Finishing Program Flow Operations

This commit is contained in:
Melefo
2020-02-24 19:06:35 +01:00
parent 92d8e97fa5
commit e9a7b9e8d7
7 changed files with 278 additions and 41 deletions

View File

@@ -74,7 +74,7 @@ add_executable(unit_tests
sources/APU/Instructions/Stack.cpp sources/APU/Instructions/Stack.cpp
sources/APU/Instructions/Subroutine.cpp sources/APU/Instructions/Subroutine.cpp
sources/APU/Instructions/ProgramFlow.cpp sources/APU/Instructions/ProgramFlow.cpp
) sources/APU/Operand.cpp)
# include criterion & coverage # include criterion & coverage
target_link_libraries(unit_tests criterion -lgcov) target_link_libraries(unit_tests criterion -lgcov)
@@ -160,7 +160,7 @@ add_executable(ComSquare
sources/APU/Instructions/Stack.cpp sources/APU/Instructions/Stack.cpp
sources/APU/Instructions/Subroutine.cpp sources/APU/Instructions/Subroutine.cpp
sources/APU/Instructions/ProgramFlow.cpp sources/APU/Instructions/ProgramFlow.cpp
) sources/APU/Operand.cpp)
target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED) target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED)

View File

@@ -166,6 +166,8 @@ namespace ComSquare::APU
return this->TCALL(0); return this->TCALL(0);
case 0x02: case 0x02:
return this->SET1(this->_getDirectAddr(), 0); return this->SET1(this->_getDirectAddr(), 0);
case 0x03:
return this->BBS(this->_getDirectAddr(), 0);
case 0x0A: case 0x0A:
return this->OR1(this->_getAbsoluteBit()); return this->OR1(this->_getAbsoluteBit());
case 0x0D: case 0x0D:
@@ -180,16 +182,24 @@ namespace ComSquare::APU
return this->TCALL(1); return this->TCALL(1);
case 0x12: case 0x12:
return this->CLR1(this->_getDirectAddr(), 0); return this->CLR1(this->_getDirectAddr(), 0);
case 0x13:
return this->BBC(this->_getDirectAddr(), 0);
case 0x1F:
return this->JMP(this->_getAbsoluteAddrByX(), true);
case 0x20: case 0x20:
return this->CLRP(); return this->CLRP();
case 0x21: case 0x21:
return this->TCALL(2); return this->TCALL(2);
case 0x22: case 0x22:
return this->SET1(this->_getDirectAddr(), 1); return this->SET1(this->_getDirectAddr(), 1);
case 0x23:
return this->BBS(this->_getDirectAddr(), 1);
case 0x2A: case 0x2A:
return this->OR1(this->_getAbsoluteBit(), true); return this->OR1(this->_getAbsoluteBit(), true);
case 0x2D: case 0x2D:
return this->PUSH(this->_internalRegisters.a); return this->PUSH(this->_internalRegisters.a);
case 0x2E:
return this->CBNE(this->_getDirectValue());
case 0x2F: case 0x2F:
return this->BRA(); return this->BRA();
case 0x30: case 0x30:
@@ -198,6 +208,8 @@ namespace ComSquare::APU
return this->TCALL(3); return this->TCALL(3);
case 0x32: case 0x32:
return this->CLR1(this->_getDirectAddr(), 1); return this->CLR1(this->_getDirectAddr(), 1);
case 0x33:
return this->BBC(this->_getDirectAddr(), 1);
case 0x3F: case 0x3F:
return this->CALL(this->_getAbsoluteAddr()); return this->CALL(this->_getAbsoluteAddr());
case 0x40: case 0x40:
@@ -206,6 +218,8 @@ namespace ComSquare::APU
return this->TCALL(4); return this->TCALL(4);
case 0x42: case 0x42:
return this->SET1(this->_getDirectAddr(), 2); return this->SET1(this->_getDirectAddr(), 2);
case 0x43:
return this->BBS(this->_getDirectAddr(), 2);
case 0x4A: case 0x4A:
return this->AND1(this->_getAbsoluteBit()); return this->AND1(this->_getAbsoluteBit());
case 0x4D: case 0x4D:
@@ -220,16 +234,24 @@ namespace ComSquare::APU
return this->TCALL(5); return this->TCALL(5);
case 0x52: case 0x52:
return this->CLR1(this->_getDirectAddr(), 2); return this->CLR1(this->_getDirectAddr(), 2);
case 0x53:
return this->BBC(this->_getDirectAddr(), 2);
case 0x5F:
return this->JMP(this->_getAbsoluteAddr());
case 0x60: case 0x60:
return this->CLRC(); return this->CLRC();
case 0x61: case 0x61:
return this->TCALL(6); return this->TCALL(6);
case 0x62: case 0x62:
return this->SET1(this->_getDirectAddr(), 3); return this->SET1(this->_getDirectAddr(), 3);
case 0x63:
return this->BBS(this->_getDirectAddr(), 3);
case 0x6A: case 0x6A:
return this->AND1(this->_getAbsoluteBit(), true); return this->AND1(this->_getAbsoluteBit(), true);
case 0x6D: case 0x6D:
return this->PUSH(this->_internalRegisters.y); return this->PUSH(this->_internalRegisters.y);
case 0x6E:
return this->DBNZ(true);
case 0x6F: case 0x6F:
return this->RET(); return this->RET();
case 0x70: case 0x70:
@@ -238,6 +260,8 @@ namespace ComSquare::APU
return this->TCALL(7); return this->TCALL(7);
case 0x72: case 0x72:
return this->CLR1(this->_getDirectAddr(), 3); return this->CLR1(this->_getDirectAddr(), 3);
case 0x73:
return this->BBC(this->_getDirectAddr(), 3);
case 0x7F: case 0x7F:
return this->RETI(); return this->RETI();
case 0x80: case 0x80:
@@ -246,6 +270,8 @@ namespace ComSquare::APU
return this->TCALL(8); return this->TCALL(8);
case 0x82: case 0x82:
return this->SET1(this->_getDirectAddr(), 4); return this->SET1(this->_getDirectAddr(), 4);
case 0x83:
return this->BBS(this->_getDirectAddr(), 4);
case 0x8A: case 0x8A:
return this->EOR1(this->_getAbsoluteBit()); return this->EOR1(this->_getAbsoluteBit());
case 0x8E: case 0x8E:
@@ -256,12 +282,16 @@ namespace ComSquare::APU
return this->TCALL(9); return this->TCALL(9);
case 0x92: case 0x92:
return this->CLR1(this->_getDirectAddr(), 4); return this->CLR1(this->_getDirectAddr(), 4);
case 0x93:
return this->BBC(this->_getDirectAddr(), 4);
case 0xA0: case 0xA0:
return this->EI(); return this->EI();
case 0xA1: case 0xA1:
return this->TCALL(10); return this->TCALL(10);
case 0xA2: case 0xA2:
return this->SET1(this->_getDirectAddr(), 5); return this->SET1(this->_getDirectAddr(), 5);
case 0xA3:
return this->BBS(this->_getDirectAddr(), 5);
case 0xAA: case 0xAA:
return this->MOV1(this->_getAbsoluteBit(), true); return this->MOV1(this->_getAbsoluteBit(), true);
case 0xAE: case 0xAE:
@@ -272,12 +302,16 @@ namespace ComSquare::APU
return this->TCALL(11); return this->TCALL(11);
case 0xB2: case 0xB2:
return this->CLR1(this->_getDirectAddr(), 5); return this->CLR1(this->_getDirectAddr(), 5);
case 0xB3:
return this->BBC(this->_getDirectAddr(), 5);
case 0xC0: case 0xC0:
return this->DI(); return this->DI();
case 0xC1: case 0xC1:
return this->TCALL(12); return this->TCALL(12);
case 0xC2: case 0xC2:
return this->SET1(this->_getDirectAddr(), 6); return this->SET1(this->_getDirectAddr(), 6);
case 0xC3:
return this->BBS(this->_getDirectAddr(), 6);
case 0xCA: case 0xCA:
return this->MOV1(this->_getAbsoluteBit()); return this->MOV1(this->_getAbsoluteBit());
case 0xCE: case 0xCE:
@@ -288,10 +322,16 @@ namespace ComSquare::APU
return this->TCALL(13); return this->TCALL(13);
case 0xD2: case 0xD2:
return this->CLR1(this->_getDirectAddr(), 6); return this->CLR1(this->_getDirectAddr(), 6);
case 0xD3:
return this->BBC(this->_getDirectAddr(), 6);
case 0xDE:
return this->CBNE(this->_getDirectAddrByX(), true);
case 0xE1: case 0xE1:
return this->TCALL(14); return this->TCALL(14);
case 0xE2: case 0xE2:
return this->SET1(this->_getDirectAddr(), 7); return this->SET1(this->_getDirectAddr(), 7);
case 0xE3:
return this->BBS(this->_getDirectAddr(), 7);
case 0xEE: case 0xEE:
return this->POP(this->_internalRegisters.y); return this->POP(this->_internalRegisters.y);
case 0xF0: case 0xF0:
@@ -300,12 +340,16 @@ namespace ComSquare::APU
return this->TCALL(15); return this->TCALL(15);
case 0xF2: case 0xF2:
return this->CLR1(this->_getDirectAddr(), 7); return this->CLR1(this->_getDirectAddr(), 7);
case 0xF3:
return this->BBC(this->_getDirectAddr(), 7);
case 0xEA: case 0xEA:
return this->NOT1(this->_getAbsoluteBit()); return this->NOT1(this->_getAbsoluteBit());
case 0xED: case 0xED:
return this->NOTC(); return this->NOTC();
case 0xEF: case 0xEF:
return this->SLEEP(); return this->SLEEP();
case 0xFE:
return this->DBNZ();
case 0xFF: case 0xFF:
return this->STOP(); return this->STOP();
default: default:
@@ -324,35 +368,6 @@ namespace ComSquare::APU
this->_paddingCycles = total - cycles; this->_paddingCycles = total - cycles;
} }
uint24_t APU::_getDirectAddr()
{
uint24_t addr = this->_internalRead(this->_internalRegisters.pc++);
if (this->_internalRegisters.p)
addr += 0x100;
return addr;
}
uint24_t APU::_getAbsoluteAddr()
{
uint24_t addr1 = this->_internalRead(this->_internalRegisters.pc++);
uint24_t addr2 = this->_internalRead(this->_internalRegisters.pc++);
return (addr2 << 8u) | addr1;
}
std::pair<uint24_t, uint24_t> APU::_getAbsoluteBit()
{
uint24_t addr1 = this->_internalRead(this->_internalRegisters.pc++);
uint24_t addr2 = this->_internalRead(this->_internalRegisters.pc++);
uint24_t operandA = (addr2 << 8u) | addr1;
uint24_t operandB = operandA >> 13u;
operandA = operandA & 0x1FFFu;
return std::make_pair(operandA, operandB);
}
MemoryMap::MemoryMap() : MemoryMap::MemoryMap() :
Page0(0x00F0), Page0(0x00F0),
Page1(0x0100), Page1(0x0100),

View File

@@ -161,10 +161,16 @@ namespace ComSquare::APU
//! @brief Keep the number of excess cycles executed to pad the next update //! @brief Keep the number of excess cycles executed to pad the next update
unsigned int _paddingCycles = 0; unsigned int _paddingCycles = 0;
//! @brief Get value of the Pointer Counter
uint8_t _getDirectValue();
//! @brief Get direct page offset //! @brief Get direct page offset
uint24_t _getDirectAddr(); uint24_t _getDirectAddr();
//! @brief Get direct page offset and add to it the X Index Flag
uint24_t _getDirectAddrByX();
//! @brief Get absolute direct page offset //! @brief Get absolute direct page offset
uint24_t _getAbsoluteAddr(); uint24_t _getAbsoluteAddr();
//! @brief Get absolute direct page offset nd add to it the X Index Flag
uint24_t _getAbsoluteAddrByX();
//! @brief Get absolute offset and separate its bits //! @brief Get absolute offset and separate its bits
std::pair<uint24_t, uint24_t> _getAbsoluteBit(); std::pair<uint24_t, uint24_t> _getAbsoluteBit();
@@ -235,22 +241,32 @@ namespace ComSquare::APU
//! @brief Branch Always, go to the specified location from the next instruction. //! @brief Branch Always, go to the specified location from the next instruction.
int BRA(); int BRA();
//! @brief Branch if Zero Flag is set //! @brief Branch if Zero Flag is set.
int BEQ(); int BEQ();
//! @brief Branch if Zero Flag is clear //! @brief Branch if Zero Flag is clear.
int BNE(); int BNE();
//! @brief Branch if Carry Flag is set //! @brief Branch if Carry Flag is set.
int BCS(); int BCS();
//! @brief Branch if Carry Flag is clear //! @brief Branch if Carry Flag is clear.
int BCC(); int BCC();
//! @brief Branch if Overflow Flag is set //! @brief Branch if Overflow Flag is set.
int BVS(); int BVS();
//! @brief Branch if Overflow Flag is set //! @brief Branch if Overflow Flag is set.
int BVC(); int BVC();
//! @brief Branch if Negative Flag is set //! @brief Branch if Negative Flag is set.
int BMI(); int BMI();
//! @brief Branch if Negative Flag is clear //! @brief Branch if Negative Flag is clear.
int BPL(); int BPL();
//! @brief Branch if the specified is set in the address, go to the specified location from the next instruction.
int BBS(uint24_t addr, uint8_t bit);
//! @brief Branch if the specified is clear in the address, go to the specified location from the next instruction.
int BBC(uint24_t addr, uint8_t bit);
//! @brief Branch if the value at the specified address is not equal to the Accumulator Flag.
int CBNE(uint24_t addr, bool by_x = false);
//! @brief Decrement a value then branch to the specified location if the value is not zero.
int DBNZ(bool direct_addr = false);
//! @brief Jump to the specified location.
int JMP(uint24_t addr, bool by_x = false);
public: public:
explicit APU(std::shared_ptr<MemoryMap> &map); explicit APU(std::shared_ptr<MemoryMap> &map);
APU(const APU &) = default; APU(const APU &) = default;

View File

@@ -8,7 +8,7 @@ namespace ComSquare::APU
{ {
int APU::BRA() int APU::BRA()
{ {
int8_t offset = this->_internalRead(this->_internalRegisters.pc++); int8_t offset = this->_getDirectValue();
this->_internalRegisters.pc += offset; this->_internalRegisters.pc += offset;
return 4; return 4;
@@ -77,4 +77,61 @@ namespace ComSquare::APU
this->BRA(); this->BRA();
return 4; return 4;
} }
int APU::BBS(uint24_t addr, uint8_t bit)
{
uint8_t data = this->_internalRead(addr);
if (!(data & (1u << bit)))
return 5;
this->BRA();
return 7;
}
int APU::BBC(uint24_t addr, uint8_t bit)
{
uint8_t data = this->_internalRead(addr);
if (data & (1u << bit))
return 5;
this->BRA();
return 7;
}
int APU::CBNE(uint24_t addr, bool by_x)
{
uint8_t data = this->_internalRead(addr);
if (this->_internalRegisters.a == data)
return 5 + by_x;
this->BRA();
return 7 + by_x;
}
int APU::DBNZ(bool direct_addr)
{
uint8_t data;
if (direct_addr) {
uint24_t addr = this->_getDirectAddr();
data = this->_internalRead(addr);
this->_internalWrite(addr, --data);
}
else
data = --this->_internalRegisters.y;
if (!data)
return 4 + direct_addr;
this->BRA();
return 6 + direct_addr;
}
int APU::JMP(uint24_t addr, bool by_x)
{
this->_internalRegisters.pc = addr;
if (by_x)
return 6;
else
return 3;
}
} }

View File

@@ -17,7 +17,7 @@ namespace ComSquare::APU
int APU::PCALL() int APU::PCALL()
{ {
this->CALL(0xFF00u + this->_internalRead(this->_internalRegisters.pc++)); this->CALL(0xFF00u + this->_getDirectValue());
return 6; return 6;
} }

59
sources/APU/Operand.cpp Normal file
View File

@@ -0,0 +1,59 @@
//
// Created by Melefo on 24/02/2020.
//
#include "../Models/Int24.hpp"
#include "APU.hpp"
namespace ComSquare::APU
{
uint8_t APU::_getDirectValue()
{
return this->_internalRead(this->_internalRegisters.pc++);
}
uint24_t APU::_getDirectAddr()
{
uint24_t addr = this->_getDirectValue();
if (this->_internalRegisters.p)
addr += 0x100;
return addr;
}
uint24_t APU::_getDirectAddrByX()
{
uint24_t addr = this->_getDirectAddr();
addr += this->_internalRegisters.x;
return addr;
}
uint24_t APU::_getAbsoluteAddr()
{
uint24_t addr1 = this->_getDirectValue();
uint24_t addr2 = this->_getDirectValue();
return (addr2 << 8u) | addr1;
}
uint24_t APU::_getAbsoluteAddrByX()
{
uint24_t addr1 = this->_getDirectValue() + this->_internalRegisters.x;
uint24_t addr2 = this->_getDirectValue() + this->_internalRegisters.x++;
return (addr2 << 8u) | addr1;
}
std::pair<uint24_t, uint24_t> APU::_getAbsoluteBit()
{
uint24_t addr1 = _getDirectValue();
uint24_t addr2 = this->_getDirectValue();
uint24_t operandA = (addr2 << 8u) | addr1;
uint24_t operandB = operandA >> 13u;
operandA = operandA & 0x1FFFu;
return std::make_pair(operandA, operandB);
}
}

View File

@@ -607,3 +607,93 @@ Test(ProgramFlow, BPL)
cr_assert_eq(result, 4); cr_assert_eq(result, 4);
cr_assert_eq(apu->_internalRead(apu->_internalRegisters.pc), 101); cr_assert_eq(apu->_internalRead(apu->_internalRegisters.pc), 101);
} }
Test(ProgramFlow, BBS)
{
auto apu = Init().second.apu;
int result = 0;
apu->_internalRegisters.pc = 0;
apu->_internalWrite(apu->_internalRegisters.pc, 23);
apu->_internalWrite(23, 0);
result = apu->BBS(apu->_getDirectAddr(), 2);
cr_assert_eq(result, 5);
apu->_internalRegisters.pc = 0;
apu->_internalWrite(apu->_internalRegisters.pc + 1, 10);
apu->_internalWrite(23, 255);
result = apu->BBS(apu->_getDirectAddr(), 2);
cr_assert_eq(result, 7);
cr_assert_eq(apu->_internalRegisters.pc, 12);
}
Test(ProgramFlow, BBC)
{
auto apu = Init().second.apu;
int result = 0;
apu->_internalRegisters.pc = 0;
apu->_internalWrite(apu->_internalRegisters.pc, 10);
apu->_internalWrite( 10, 255);
apu->_internalWrite(apu->_internalRegisters.pc + 1, 23);
result = apu->BBC(apu->_getDirectAddr(), 2);
cr_assert_eq(result, 5);
apu->_internalRegisters.pc = 0;
apu->_internalWrite( 10, 0);
result = apu->BBC(apu->_getDirectAddr(), 2);
cr_assert_eq(result, 7);
cr_assert_eq(apu->_internalRegisters.pc, 25);
}
Test(ProgramFlow, CBNE)
{
auto apu = Init().second.apu;
int result = 0;
apu->_internalRegisters.pc = 0;
apu->_internalRegisters.a = 4;
apu->_internalWrite(apu->_internalRegisters.pc, 10);
apu->_internalWrite( 10, 4);
apu->_internalWrite(apu->_internalRegisters.pc + 1, 23);
result = apu->CBNE(apu->_getDirectAddr());
cr_assert_eq(result, 5);
apu->_internalRegisters.pc = 0;
apu->_internalWrite( 10, 0);
result = apu->CBNE(apu->_getDirectAddrByX(), true);
cr_assert_eq(result, 8);
cr_assert_eq(apu->_internalRegisters.pc, 25);
}
Test(ProgramFlow, DBNZ)
{
auto apu = Init().second.apu;
int result = 0;
apu->_internalRegisters.pc = 0;
apu->_internalRegisters.y = 1;
result = apu->DBNZ();
cr_assert_eq(result, 4);
apu->_internalWrite(apu->_internalRegisters.pc, 10);
apu->_internalWrite(apu->_internalRegisters.pc + 1, 23);
apu->_internalWrite( 10, 0);
result = apu->DBNZ(true);
cr_assert_eq(result, 7);
cr_assert_eq(apu->_internalRegisters.pc, 25);
}
Test(ProgramFlow, JMP)
{
auto apu = Init().second.apu;
int result = 0;
apu->_internalRegisters.pc = 0x32;
apu->_internalWrite(0x32, 0b00001111);
apu->_internalWrite(0x33, 0b11110000);
result = apu->JMP(apu->_getAbsoluteAddr());
cr_assert_eq(result, 3);
cr_assert_eq(apu->_internalRegisters.pc, 61455);
apu->_internalRegisters.pc = 0x32;
apu->_internalRegisters.x = 0b000000001;
result = apu->JMP(apu->_getAbsoluteAddrByX(), true);
cr_assert_eq(result, 6);
cr_assert_eq(apu->_internalRegisters.pc, 61712);
}