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

View File

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

View File

@@ -161,10 +161,16 @@ namespace ComSquare::APU
//! @brief Keep the number of excess cycles executed to pad the next update
unsigned int _paddingCycles = 0;
//! @brief Get value of the Pointer Counter
uint8_t _getDirectValue();
//! @brief Get direct page offset
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
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
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.
int BRA();
//! @brief Branch if Zero Flag is set
//! @brief Branch if Zero Flag is set.
int BEQ();
//! @brief Branch if Zero Flag is clear
//! @brief Branch if Zero Flag is clear.
int BNE();
//! @brief Branch if Carry Flag is set
//! @brief Branch if Carry Flag is set.
int BCS();
//! @brief Branch if Carry Flag is clear
//! @brief Branch if Carry Flag is clear.
int BCC();
//! @brief Branch if Overflow Flag is set
//! @brief Branch if Overflow Flag is set.
int BVS();
//! @brief Branch if Overflow Flag is set
//! @brief Branch if Overflow Flag is set.
int BVC();
//! @brief Branch if Negative Flag is set
//! @brief Branch if Negative Flag is set.
int BMI();
//! @brief Branch if Negative Flag is clear
//! @brief Branch if Negative Flag is clear.
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:
explicit APU(std::shared_ptr<MemoryMap> &map);
APU(const APU &) = default;

View File

@@ -8,7 +8,7 @@ namespace ComSquare::APU
{
int APU::BRA()
{
int8_t offset = this->_internalRead(this->_internalRegisters.pc++);
int8_t offset = this->_getDirectValue();
this->_internalRegisters.pc += offset;
return 4;
@@ -77,4 +77,61 @@ namespace ComSquare::APU
this->BRA();
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()
{
this->CALL(0xFF00u + this->_internalRead(this->_internalRegisters.pc++));
this->CALL(0xFF00u + this->_getDirectValue());
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(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);
}