Add WriteLong to Memory, CPU
This commit is contained in:
@@ -806,6 +806,7 @@ void CPU::ExecuteInstruction(uint8_t opcode) {
|
||||
case 0x20: // JSR Absolute
|
||||
{
|
||||
operand = Absolute(AccessType::Control);
|
||||
PB = (operand >> 16);
|
||||
JSR(operand);
|
||||
break;
|
||||
}
|
||||
@@ -904,7 +905,7 @@ void CPU::ExecuteInstruction(uint8_t opcode) {
|
||||
case 0xBD: // LDA Absolute Indexed, X
|
||||
{
|
||||
operand = AbsoluteIndexedX();
|
||||
LDA(operand);
|
||||
LDA(operand, false, false, true);
|
||||
break;
|
||||
}
|
||||
case 0xBF: // LDA Absolute Long Indexed, X
|
||||
@@ -1321,9 +1322,11 @@ void CPU::ExecuteInstruction(uint8_t opcode) {
|
||||
STA(operand);
|
||||
break;
|
||||
case 0x97: // STA DP Indirect Long Indexed, Y
|
||||
{
|
||||
operand = DirectPageIndirectLongIndexedY();
|
||||
STA(operand);
|
||||
break;
|
||||
}
|
||||
case 0x99: // STA Absolute Indexed, Y
|
||||
operand = AbsoluteIndexedY();
|
||||
STA(operand);
|
||||
@@ -1510,7 +1513,8 @@ void CPU::LogInstructions(uint16_t PC, uint8_t opcode, uint16_t operand,
|
||||
<< "$" << std::uppercase << std::setw(2) << std::setfill('0')
|
||||
<< static_cast<int>(PB) << ":" << std::hex << PC;
|
||||
std::cout << " \033[1;32m"
|
||||
<< ": 0x" << std::hex << static_cast<int>(opcode) << " ";
|
||||
<< ": 0x" << std::hex << std::uppercase << std::setw(2)
|
||||
<< std::setfill('0') << static_cast<int>(opcode) << " ";
|
||||
std::cout << " \033[1;35m" << opcode_to_mnemonic.at(opcode) << " "
|
||||
<< "\033[0m";
|
||||
|
||||
@@ -1526,7 +1530,53 @@ void CPU::LogInstructions(uint16_t PC, uint8_t opcode, uint16_t operand,
|
||||
std::cout << std::hex << std::setw(4) << std::setfill('0')
|
||||
<< static_cast<int>(operand);
|
||||
}
|
||||
|
||||
bool x_indexing, y_indexing;
|
||||
auto x_indexed_instruction_opcodes = {0x15, 0x16, 0x17, 0x55, 0x56,
|
||||
0x57, 0xD5, 0xD6, 0xD7, 0xF5,
|
||||
0xF6, 0xF7, 0xBD};
|
||||
auto y_indexed_instruction_opcodes = {0x19, 0x97, 0x1D, 0x59, 0x5D, 0x99,
|
||||
0x9D, 0xB9, 0xD9, 0xDD, 0xF9, 0xFD};
|
||||
if (std::find(x_indexed_instruction_opcodes.begin(),
|
||||
x_indexed_instruction_opcodes.end(),
|
||||
opcode) != x_indexed_instruction_opcodes.end()) {
|
||||
x_indexing = true;
|
||||
} else {
|
||||
x_indexing = false;
|
||||
}
|
||||
if (std::find(y_indexed_instruction_opcodes.begin(),
|
||||
y_indexed_instruction_opcodes.end(),
|
||||
opcode) != y_indexed_instruction_opcodes.end()) {
|
||||
y_indexing = true;
|
||||
} else {
|
||||
y_indexing = false;
|
||||
}
|
||||
|
||||
if (x_indexing) {
|
||||
std::cout << ", X";
|
||||
}
|
||||
|
||||
if (y_indexing) {
|
||||
std::cout << ", Y";
|
||||
}
|
||||
}
|
||||
|
||||
// Log the registers and flags.
|
||||
std::cout << std::right;
|
||||
std::cout << "\033[1;33m"
|
||||
<< " A:" << std::hex << std::setw(2) << std::setfill('0')
|
||||
<< static_cast<int>(A);
|
||||
std::cout << " X:" << std::hex << std::setw(2) << std::setfill('0')
|
||||
<< static_cast<int>(X);
|
||||
std::cout << " Y:" << std::hex << std::setw(2) << std::setfill('0')
|
||||
<< static_cast<int>(Y);
|
||||
std::cout << " S:" << std::hex << std::setw(2) << std::setfill('0')
|
||||
<< static_cast<int>(status);
|
||||
std::cout << " DB:" << std::hex << std::setw(2) << std::setfill('0')
|
||||
<< static_cast<int>(DB);
|
||||
std::cout << " D:" << std::hex << std::setw(2) << std::setfill('0')
|
||||
<< static_cast<int>(D);
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -1548,7 +1598,6 @@ uint8_t CPU::GetInstructionLength(uint8_t opcode) {
|
||||
case 0xFC: // JSR Absolute Indexed Indirect
|
||||
case 0xDC: // JMP Absolute Indirect Long
|
||||
case 0x6B: // RTL
|
||||
|
||||
case 0x82: // BRL Relative Long
|
||||
PC = next_pc_;
|
||||
return 0;
|
||||
@@ -1559,7 +1608,7 @@ uint8_t CPU::GetInstructionLength(uint8_t opcode) {
|
||||
|
||||
case 0x60: // RTS
|
||||
PC = last_call_frame_;
|
||||
return 0;
|
||||
return 3;
|
||||
|
||||
// Branch Instructions (BCC, BCS, BNE, BEQ, etc.)
|
||||
case 0x90: // BCC near
|
||||
|
||||
@@ -160,7 +160,7 @@ class CPU : public Memory, public Loggable, public core::ExperimentFlags {
|
||||
// Low: First operand byte
|
||||
//
|
||||
// LDA addr
|
||||
uint16_t Absolute(AccessType access_type = AccessType::Data);
|
||||
uint32_t Absolute(AccessType access_type = AccessType::Data);
|
||||
|
||||
// Effective Address:
|
||||
// The Data Bank Register is concatened with the 16-bit operand
|
||||
@@ -342,6 +342,9 @@ class CPU : public Memory, public Loggable, public core::ExperimentFlags {
|
||||
void WriteWord(uint32_t address, uint16_t value) override {
|
||||
memory.WriteWord(address, value);
|
||||
}
|
||||
void WriteLong(uint32_t address, uint32_t value) {
|
||||
memory.WriteLong(address, value);
|
||||
}
|
||||
|
||||
uint8_t FetchByte() {
|
||||
uint32_t address = (PB << 16) | PC + 1;
|
||||
@@ -498,7 +501,8 @@ class CPU : public Memory, public Loggable, public core::ExperimentFlags {
|
||||
void JSL(uint32_t address);
|
||||
|
||||
// LDA: Load accumulator
|
||||
void LDA(uint16_t address, bool immediate = false, bool direct_page = false);
|
||||
void LDA(uint16_t address, bool immediate = false, bool direct_page = false,
|
||||
bool data_bank = false);
|
||||
|
||||
// LDX: Load X register
|
||||
void LDX(uint16_t address, bool immediate = false);
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace yaze {
|
||||
namespace app {
|
||||
namespace emu {
|
||||
|
||||
uint16_t CPU::Absolute(CPU::AccessType access_type) {
|
||||
uint32_t CPU::Absolute(CPU::AccessType access_type) {
|
||||
auto operand = FetchWord();
|
||||
uint32_t bank =
|
||||
(access_type == CPU::AccessType::Data) ? (DB << 16) : (PB << 16);
|
||||
|
||||
@@ -361,7 +361,7 @@ void CPU::JSL(uint32_t address) {
|
||||
next_pc_ = address; // Set program counter to the new address
|
||||
}
|
||||
|
||||
void CPU::LDA(uint16_t address, bool isImmediate, bool direct_page) {
|
||||
void CPU::LDA(uint16_t address, bool isImmediate, bool direct_page, bool data_bank) {
|
||||
uint8_t bank = PB;
|
||||
if (direct_page) {
|
||||
bank = 0;
|
||||
@@ -628,7 +628,9 @@ void CPU::RTL() {
|
||||
PB = memory.PopByte();
|
||||
}
|
||||
|
||||
void CPU::RTS() { last_call_frame_ = memory.PopWord(); }
|
||||
void CPU::RTS() {
|
||||
last_call_frame_ = memory.PopWord();
|
||||
}
|
||||
|
||||
void CPU::SBC(uint32_t value, bool isImmediate) {
|
||||
uint16_t operand;
|
||||
|
||||
@@ -117,6 +117,7 @@ class Memory {
|
||||
|
||||
virtual void WriteByte(uint32_t address, uint8_t value) = 0;
|
||||
virtual void WriteWord(uint32_t address, uint16_t value) = 0;
|
||||
virtual void WriteLong(uint32_t address, uint32_t value) = 0;
|
||||
|
||||
virtual void PushByte(uint8_t value) = 0;
|
||||
virtual uint8_t PopByte() = 0;
|
||||
@@ -263,6 +264,12 @@ class MemoryImpl : public Memory, public Loggable {
|
||||
memory_.at(mapped_address) = value & 0xFF;
|
||||
memory_.at(mapped_address + 1) = (value >> 8) & 0xFF;
|
||||
}
|
||||
void WriteLong(uint32_t address, uint32_t value) override {
|
||||
uint32_t mapped_address = GetMappedAddress(address);
|
||||
memory_.at(mapped_address) = value & 0xFF;
|
||||
memory_.at(mapped_address + 1) = (value >> 8) & 0xFF;
|
||||
memory_.at(mapped_address + 2) = (value >> 16) & 0xFF;
|
||||
}
|
||||
|
||||
// Stack operations
|
||||
void PushByte(uint8_t value) override {
|
||||
@@ -347,11 +354,11 @@ class MemoryImpl : public Memory, public Loggable {
|
||||
}
|
||||
|
||||
if (bank <= 0x3F) {
|
||||
if (offset <= 0x1FFF) {
|
||||
if (address <= 0x1FFF) {
|
||||
return (0x7E << 16) + offset; // Shadow RAM
|
||||
} else if (offset <= 0x5FFF) {
|
||||
} else if (address <= 0x5FFF) {
|
||||
return (bank << 16) + (offset - 0x2000) + 0x2000; // Hardware Registers
|
||||
} else if (offset <= 0x7FFF) {
|
||||
} else if (address <= 0x7FFF) {
|
||||
return offset - 0x6000 + 0x6000; // Expansion RAM
|
||||
} else {
|
||||
// Return lorom mapping
|
||||
|
||||
@@ -34,6 +34,7 @@ class MockMemory : public Memory {
|
||||
|
||||
MOCK_METHOD2(WriteByte, void(uint32_t address, uint8_t value));
|
||||
MOCK_METHOD2(WriteWord, void(uint32_t address, uint16_t value));
|
||||
MOCK_METHOD2(WriteLong, void(uint32_t address, uint32_t value));
|
||||
|
||||
MOCK_METHOD1(PushByte, void(uint8_t value));
|
||||
MOCK_METHOD0(PopByte, uint8_t());
|
||||
@@ -173,8 +174,9 @@ class MockMemory : public Memory {
|
||||
return value;
|
||||
});
|
||||
ON_CALL(*this, SP()).WillByDefault([this]() { return SP_; });
|
||||
ON_CALL(*this, SetSP(::testing::_))
|
||||
.WillByDefault([this](uint16_t value) { SP_ = value; });
|
||||
ON_CALL(*this, SetSP(::testing::_)).WillByDefault([this](uint16_t value) {
|
||||
SP_ = value;
|
||||
});
|
||||
ON_CALL(*this, ClearMemory()).WillByDefault([this]() {
|
||||
memory_.resize(64000, 0x00);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user