Skip to content

Commit

Permalink
feature #5: utility for setting efl flags based on instruction output
Browse files Browse the repository at this point in the history
  • Loading branch information
laudominik committed Sep 17, 2023
1 parent 9d64fa6 commit ee2fcef
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 1 deletion.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@
x86 emulator, the main idea is to implement instructions all instructions from [here](resources/AKO.pdf) + interrupts

## Resources
### Instruction reference
[felixcloutier.com](https://www.felixcloutier.com/)
### Flags
[parity flag](https://en.wikipedia.org/wiki/Parity_flag)
[carry and overflow flag](https://teaching.idallen.com/dat2343/10f/notes/040_overflow.txt)
52 changes: 51 additions & 1 deletion src/basicComponents/Flags.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include <utility/Widths.h>

struct Flags {
public:
struct Flag{
Expand All @@ -14,5 +16,53 @@ struct Flags {
bool val_{false};
};

Flag CF, PF, ZF, SF, TF, IF, DF, OF;
Flag CF, PF, ZF, SF, TF, IF, DF, OF, AF;

template<typename WIDTH_T>
void setAddFlags(WIDTH_T arg1, WIDTH_T arg2, bool omitCarry = false){
WIDTH_T result = arg1 + arg2;
ZF.set(isZero(result));
SF.set(isSign(result));
PF.set(isParity(result & 0xFF));
OF.set(isOverflow(arg1, arg2, result));
if(!omitCarry){
CF.set(isCarry(arg1, result));
}
AF.set(isAuxCarry(arg1, arg2));
}

private:
template<typename WIDTH_T>
bool isOverflow(WIDTH_T arg1, WIDTH_T arg2, WIDTH_T result){
return
(isSign(result) && !isSign(arg1) && !isSign(arg2)) ||
(!isSign(result) && isSign(arg1) && isSign(arg2));
}
// aux carry is only for 4 lowest bits
bool isAuxCarry(Byte arg1, Byte arg2){
auto arg1lo = arg1 & 0x0F;
auto arg2lo = arg2 & 0x0F;
return (arg1lo + arg2lo) >> 4;
}
template<typename WIDTH_T>
bool isCarry(WIDTH_T arg1, WIDTH_T result){
return (arg1 > result);
}
template<typename WIDTH_T>
bool isZero(WIDTH_T after){
return after == 0;
}
template<typename WIDTH_T>
bool isSign(WIDTH_T after){
return (1 << (sizeof(WIDTH_T) * 8u - 1)) & after;
}

// parity is only checked for LSB
bool isParity(Byte after){
uint8_t counter = 0;
for(auto i = 0u; i < sizeof(Byte) * 8; i++){
counter += (after >> i) & 1;
}
return counter % 2 == 0;
}
};
86 changes: 86 additions & 0 deletions test/status.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,95 @@
#include <gtest/gtest.h>

#include <basicComponents/Flags.h>
#include <utility/Widths.h>

TEST(StatusTest, testStatus){
Flags efl;
efl.CF.set(true);
EXPECT_TRUE(efl.CF.get());
}

TEST(StatusTest, testZero){
Flags efl;
efl.setAddFlags<Byte>(0, 0);
EXPECT_TRUE(efl.ZF.get());
efl.setAddFlags<Byte>(0, 1);
EXPECT_FALSE(efl.ZF.get());
}

TEST(StatusTest, testSign){
Flags efl;
efl.setAddFlags<Byte>(0, 0x80);
EXPECT_TRUE(efl.SF.get());
efl.setAddFlags<Byte>(0, 0);
EXPECT_FALSE(efl.SF.get());
efl.setAddFlags<Word>(0, 0x8000);
EXPECT_TRUE(efl.SF.get());
efl.setAddFlags<Word>(0, 0);
EXPECT_FALSE(efl.SF.get());
efl.setAddFlags<Dword>(0, 0x80000000);
EXPECT_TRUE(efl.SF.get());
efl.setAddFlags<Dword>(0, 0);
EXPECT_FALSE(efl.SF.get());
}

TEST(StatusTest, testParity){
Flags efl;
efl.setAddFlags<Byte>(0, 0);
EXPECT_TRUE(efl.PF.get());
efl.setAddFlags<Byte>(0, 0b11010101);
EXPECT_FALSE(efl.PF.get());
efl.setAddFlags<Word>(0, 0b111010101);
EXPECT_FALSE(efl.PF.get());
efl.setAddFlags<Word>(0, 0b111011101);
EXPECT_TRUE(efl.PF.get());
efl.setAddFlags<Word>(0, 0b11011101);
EXPECT_TRUE(efl.PF.get());
}

TEST(StatusTest, testOverflow){
Flags efl;
efl.setAddFlags<Byte>(0b01000000, 0b01000000);
EXPECT_TRUE(efl.OF.get());
efl.setAddFlags<Byte>(0, 0, 0);
EXPECT_FALSE(efl.OF.get());
efl.setAddFlags<Word>(0x8000, 0x8000);
EXPECT_TRUE(efl.OF.get());
efl.setAddFlags<Word>(0x80, 0x8000);
EXPECT_FALSE(efl.OF.get());
}

TEST(StatusTest, testCarry){
Flags efl;
efl.setAddFlags<Byte>(0b10000000, 0b10000000);
EXPECT_TRUE(efl.CF.get());
efl.setAddFlags<Byte>(0x80, 0);
EXPECT_FALSE(efl.CF.get());
efl.setAddFlags<Dword>(0x80000000, 0x80000000);
EXPECT_TRUE(efl.CF.get());
}

TEST(StatusTest, testAuxCarry){
Flags efl;
efl.setAddFlags<Byte>(0b1000, 0b1000);
EXPECT_TRUE(efl.AF.get());
efl.setAddFlags<Byte>(0b0000, 0b1000);
EXPECT_FALSE(efl.AF.get());
efl.setAddFlags<Byte>(0b10000, 0b1000);
EXPECT_FALSE(efl.AF.get());
efl.setAddFlags<Byte>(0b0000, 0b1000);
EXPECT_FALSE(efl.AF.get());
efl.setAddFlags<Byte>(0b11000, 0b1000);
EXPECT_TRUE(efl.AF.get());
}

TEST(StatusTest, testOmitCarry){
Flags efl;
efl.setAddFlags<Byte>(0b10000000, 0b10000000, true);
EXPECT_FALSE(efl.CF.get());
efl.setAddFlags<Byte>(0x80, 0);
EXPECT_FALSE(efl.CF.get());
efl.setAddFlags<Dword>(0x80000000, 0x80000000, true);
EXPECT_FALSE(efl.CF.get());
}

0 comments on commit ee2fcef

Please sign in to comment.