mirror of
https://github.com/zoriya/ComSquare.git
synced 2025-12-21 06:35:10 +00:00
Finishing Program Flow Operations
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
59
sources/APU/Operand.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user