Add StackPointer to memory, PHA, PLA, PHP, PLP
This commit is contained in:
@@ -65,60 +65,6 @@ uint8_t CPU::FetchByteDirectPage(uint8_t operand) {
|
||||
return fetchedByte;
|
||||
}
|
||||
|
||||
uint16_t CPU::DirectPageIndexedIndirectX() {
|
||||
uint8_t dp = FetchByte();
|
||||
return memory.ReadWord((dp + X) & 0xFF);
|
||||
}
|
||||
|
||||
uint16_t CPU::StackRelative() {
|
||||
uint8_t sr = FetchByte();
|
||||
return SP + sr;
|
||||
}
|
||||
|
||||
uint16_t CPU::DirectPage() { return FetchByte(); }
|
||||
|
||||
uint16_t CPU::DirectPageIndirectLong() {
|
||||
uint8_t dp = FetchByte();
|
||||
return memory.ReadWordLong(dp);
|
||||
}
|
||||
|
||||
uint16_t CPU::Immediate() { return PC++; }
|
||||
|
||||
uint16_t CPU::Absolute() { return FetchWord(); }
|
||||
|
||||
uint16_t CPU::AbsoluteLong() { return FetchLong(); }
|
||||
|
||||
uint16_t CPU::DirectPageIndirectIndexedY() {
|
||||
uint8_t dp = FetchByte();
|
||||
return memory.ReadWord(dp) + Y;
|
||||
}
|
||||
|
||||
uint16_t CPU::DirectPageIndirect() {
|
||||
uint8_t dp = FetchByte();
|
||||
return memory.ReadWord(dp);
|
||||
}
|
||||
|
||||
uint16_t CPU::StackRelativeIndirectIndexedY() {
|
||||
uint8_t sr = FetchByte();
|
||||
return memory.ReadWord(SP + sr) + Y;
|
||||
}
|
||||
|
||||
uint16_t CPU::DirectPageIndexedX() {
|
||||
uint8_t dp = FetchByte();
|
||||
return (dp + X) & 0xFF;
|
||||
}
|
||||
|
||||
uint16_t CPU::DirectPageIndirectLongIndexedY() {
|
||||
uint8_t dp = FetchByte();
|
||||
return memory.ReadWordLong(dp) + Y;
|
||||
}
|
||||
|
||||
uint16_t CPU::AbsoluteIndexedY() { return FetchWord() + Y; }
|
||||
|
||||
uint16_t CPU::AbsoluteIndexedX() { return FetchWord() + X; }
|
||||
|
||||
uint16_t CPU::AbsoluteLongIndexedX() { return FetchLong() + X; }
|
||||
|
||||
void CPU::ExecuteInstruction(uint8_t opcode) {
|
||||
// uint8_t opcode = FetchByte();
|
||||
uint8_t operand = -1;
|
||||
|
||||
@@ -11,101 +11,21 @@ namespace yaze {
|
||||
namespace app {
|
||||
namespace emu {
|
||||
|
||||
// ADC: Add with carry
|
||||
// AND: Logical AND
|
||||
// ASL: Arithmetic shift left
|
||||
// BCC: Branch if carry clear
|
||||
// BCS: Branch if carry set
|
||||
// BEQ: Branch if equal (zero set)
|
||||
// BIT: Bit test
|
||||
// BMI: Branch if minus (negative set)
|
||||
// BNE: Branch if not equal (zero clear)
|
||||
// BPL: Branch if plus (negative clear)
|
||||
// BRA: Branch always
|
||||
// BRK: Break
|
||||
// BRL: Branch always long
|
||||
// BVC: Branch if overflow clear
|
||||
// BVS: Branch if overflow set
|
||||
// CLC: Clear carry
|
||||
// CLD: Clear decimal
|
||||
// CLI: Clear interrupt disable
|
||||
// CLV: Clear overflow
|
||||
// CMP: Compare
|
||||
// COP: Coprocessor
|
||||
// CPX: Compare X register
|
||||
// CPY: Compare Y register
|
||||
// DEC: Decrement
|
||||
// DEX: Decrement X register
|
||||
// DEY: Decrement Y register
|
||||
// EOR: Exclusive OR
|
||||
// INC: Increment
|
||||
// INX: Increment X register
|
||||
// INY: Increment Y register
|
||||
// JMP: Jump
|
||||
// JML: Jump long
|
||||
// JSR: Jump to subroutine
|
||||
// JSL: Jump to subroutine long
|
||||
// LDA: Load accumulator
|
||||
// LDX: Load X register
|
||||
// LDY: Load Y register
|
||||
// LSR: Logical shift right
|
||||
// MVN: Move negative
|
||||
// MVP: Move positive
|
||||
// NOP: No operation
|
||||
// ORA: Logical OR
|
||||
// PEA: Push effective address
|
||||
// PEI: Push effective indirect address
|
||||
// PER: Push effective PC-relative address
|
||||
// PHA: Push accumulator
|
||||
// PHB: Push data bank register
|
||||
// PHD: Push direct page register
|
||||
// PHK: Push program bank register
|
||||
// PHP: Push processor status register
|
||||
// PHX: Push X register
|
||||
// PHY: Push Y register
|
||||
// PLA: Pull accumulator
|
||||
// PLB: Pull data bank register
|
||||
// PLD: Pull direct page register
|
||||
// PLP: Pull processor status register
|
||||
// PLX: Pull X register
|
||||
// PLY: Pull Y register
|
||||
// ROL: Rotate left
|
||||
// ROR: Rotate right
|
||||
// RTI: Return from interrupt
|
||||
// RTL: Return from subroutine long
|
||||
// RTS: Return from subroutine
|
||||
// SBC: Subtract with carry
|
||||
// STA: Store accumulator
|
||||
// STP: Stop the clock
|
||||
// STX: Store X register
|
||||
// STY: Store Y register
|
||||
// STZ: Store zero
|
||||
// TDC: Transfer direct page register to accumulator
|
||||
// TRB: Test and reset bits
|
||||
// TSB: Test and set bits
|
||||
// WAI: Wait for interrupt
|
||||
// XBA: Exchange B and A accumulator
|
||||
// XCE: Exchange carry and emulation
|
||||
|
||||
class CPU : public Memory {
|
||||
private:
|
||||
Memory& memory;
|
||||
|
||||
public:
|
||||
explicit CPU(Memory& mem) : memory(mem) {}
|
||||
|
||||
void Init() {}
|
||||
void Init() { memory.ClearMemory(); }
|
||||
|
||||
uint8_t ReadByte(uint16_t address) const override;
|
||||
uint16_t ReadWord(uint16_t address) const override;
|
||||
uint32_t ReadWordLong(uint16_t address) const override;
|
||||
|
||||
void WriteByte(uint32_t address, uint8_t value) override;
|
||||
void WriteWord(uint32_t address, uint16_t value) override;
|
||||
|
||||
void SetMemory(const std::vector<uint8_t>& data) override {
|
||||
memory.SetMemory(data);
|
||||
}
|
||||
int16_t SP() const override { return memory.SP(); }
|
||||
void SetSP(int16_t value) override { memory.SetSP(value); }
|
||||
|
||||
uint8_t FetchByte();
|
||||
uint16_t FetchWord();
|
||||
@@ -115,37 +35,217 @@ class CPU : public Memory {
|
||||
|
||||
uint8_t FetchByteDirectPage(uint8_t operand);
|
||||
|
||||
uint16_t DirectPageIndexedIndirectX();
|
||||
uint16_t StackRelative();
|
||||
uint16_t DirectPage();
|
||||
uint16_t DirectPageIndirectLong();
|
||||
uint16_t Immediate();
|
||||
uint16_t Absolute();
|
||||
uint16_t AbsoluteLong();
|
||||
uint16_t DirectPageIndirectIndexedY();
|
||||
uint16_t DirectPageIndirect();
|
||||
uint16_t StackRelativeIndirectIndexedY();
|
||||
uint16_t DirectPageIndexedX();
|
||||
uint16_t DirectPageIndirectLongIndexedY();
|
||||
uint16_t AbsoluteIndexedY();
|
||||
uint16_t AbsoluteIndexedX();
|
||||
uint16_t AbsoluteLongIndexedX();
|
||||
|
||||
void ExecuteInstruction(uint8_t opcode);
|
||||
|
||||
void loadROM(const std::vector<uint8_t>& rom) {
|
||||
// if (rom.size() > memory.size()) {
|
||||
// std::cerr << "ROM too large" << std::endl;
|
||||
// return;
|
||||
// }
|
||||
// std::copy(rom.begin(), rom.end(), memory.begin());
|
||||
// ==========================================================================
|
||||
// Addressing Modes
|
||||
|
||||
// Effective Address:
|
||||
// Bank: Data Bank Register if locating data
|
||||
// Program Bank Register if transferring control
|
||||
// High: Second operand byte
|
||||
// Low: First operand byte
|
||||
//
|
||||
// LDA addr
|
||||
uint16_t Absolute() { return FetchWord(); }
|
||||
|
||||
// Effective Address:
|
||||
// The Data Bank Register is concatened with the 16-bit operand
|
||||
// the 24-bit result is added to the X Index Register
|
||||
// based on the emulation mode (16:X=0, 8:X=1)
|
||||
//
|
||||
// LDA addr, X
|
||||
uint16_t AbsoluteIndexedX() { return FetchWord() + X; }
|
||||
|
||||
// Effective Address:
|
||||
// The Data Bank Register is concatened with the 16-bit operand
|
||||
// the 24-bit result is added to the Y Index Register
|
||||
// based on the emulation mode (16:Y=0, 8:Y=1)
|
||||
//
|
||||
// LDA addr, Y
|
||||
uint16_t AbsoluteIndexedY() { return FetchWord() + Y; }
|
||||
|
||||
// Test Me :)
|
||||
// Effective Address:
|
||||
// Bank: Program Bank Register (PBR)
|
||||
// High/low: The Indirect Address
|
||||
// Indirect Address: Located in the Program Bank at the sum of
|
||||
// the operand double byte and X based on the
|
||||
// emulation mode
|
||||
// JMP (addr, X)
|
||||
uint16_t AbsoluteIndexedIndirect() {
|
||||
uint16_t address = FetchWord() + X;
|
||||
return memory.ReadWord(address);
|
||||
}
|
||||
|
||||
// Effective Address:
|
||||
// Bank: Program Bank Register (PBR)
|
||||
// High/low: The Indirect Address
|
||||
// Indirect Address: Located in Bank Zero, at the operand double byte
|
||||
//
|
||||
// JMP (addr)
|
||||
uint16_t AbsoluteIndirect() {
|
||||
uint16_t address = FetchWord();
|
||||
return memory.ReadWord(address);
|
||||
}
|
||||
|
||||
// Effective Address:
|
||||
// Bank/High/Low: The 24-bit Indirect Address
|
||||
// Indirect Address: Located in Bank Zero, at the operand double byte
|
||||
//
|
||||
// JMP [addr]
|
||||
uint32_t AbsoluteIndirectLong() {
|
||||
uint16_t address = FetchWord();
|
||||
return memory.ReadWordLong(address);
|
||||
}
|
||||
|
||||
// Effective Address:
|
||||
// Bank: Third operand byte
|
||||
// High: Second operand byte
|
||||
// Low: First operand byte
|
||||
//
|
||||
// LDA long
|
||||
uint16_t AbsoluteLong() { return FetchLong(); }
|
||||
|
||||
// Effective Address:
|
||||
// The 24-bit operand is added to X based on the emulation mode
|
||||
//
|
||||
// LDA long, X
|
||||
uint16_t AbsoluteLongIndexedX() { return FetchLong() + X; }
|
||||
|
||||
// Source Effective Address:
|
||||
// Bank: Second operand byte
|
||||
// High/Low: The 16-bit value in X, if X is 8-bit high byte is 0
|
||||
//
|
||||
// Destination Effective Address:
|
||||
// Bank: First operand byte
|
||||
// High/Low: The 16-bit value in Y, if Y is 8-bit high byte is 0
|
||||
//
|
||||
// Length:
|
||||
// The number of bytes to be moved: 16-bit value in Acculumator C plus 1.
|
||||
//
|
||||
// MVN src, dst
|
||||
void BlockMove(uint16_t source, uint16_t dest, uint16_t length) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
memory.WriteByte(dest + i, memory.ReadByte(source + i));
|
||||
}
|
||||
}
|
||||
|
||||
// Effective Address:
|
||||
// Bank: Zero
|
||||
// High/low: Direct Page Register plus operand byte
|
||||
//
|
||||
// LDA dp
|
||||
uint16_t DirectPage() { return FetchByte(); }
|
||||
|
||||
// Effective Address:
|
||||
// Bank: Zero
|
||||
// High/low: Direct Page Register plus operand byte plus X
|
||||
// based on the emulation mode
|
||||
//
|
||||
// LDA dp, X
|
||||
uint16_t DirectPageIndexedX() {
|
||||
uint8_t dp = FetchByte();
|
||||
return (dp + X) & 0xFF;
|
||||
}
|
||||
|
||||
// Effective Address:
|
||||
// Bank: Zero
|
||||
// High/low: Direct Page Register plus operand byte plus Y
|
||||
// based on the emulation mode
|
||||
// LDA dp, Y
|
||||
uint16_t DirectPageIndexedY() {
|
||||
uint8_t dp = FetchByte();
|
||||
return (dp + Y) & 0xFF;
|
||||
}
|
||||
|
||||
// Effective Address:
|
||||
// Bank: Data bank register
|
||||
// High/low: The indirect address
|
||||
// Indirect Address: Located in the direct page at the sum of the direct page
|
||||
// register, the operand byte, and X based on the emulation mode in bank zero.
|
||||
//
|
||||
// LDA (dp, X)
|
||||
uint16_t DirectPageIndexedIndirectX() {
|
||||
uint8_t dp = FetchByte();
|
||||
return memory.ReadWord((dp + X) & 0xFF);
|
||||
}
|
||||
|
||||
// Effective Address:
|
||||
// Bank: Data bank register
|
||||
// High/low: The 16-bit indirect address
|
||||
// Indirect Address: The operand byte plus the direct page register in bank
|
||||
// zero.
|
||||
//
|
||||
// LDA (dp)
|
||||
uint16_t DirectPageIndirect() {
|
||||
uint8_t dp = FetchByte();
|
||||
return memory.ReadWord(dp);
|
||||
}
|
||||
|
||||
// Effective Address:
|
||||
// Bank/High/Low: The 24-bit indirect address
|
||||
// Indirect address: The operand byte plus the direct page
|
||||
// register in bank zero.
|
||||
//
|
||||
// LDA [dp]
|
||||
uint16_t DirectPageIndirectLong() {
|
||||
uint8_t dp = FetchByte();
|
||||
return memory.ReadWordLong(dp);
|
||||
}
|
||||
|
||||
// Effective Address:
|
||||
// Found by concatenating the data bank to the double-byte
|
||||
// indirect address, then adding Y based on the emulation mode.
|
||||
//
|
||||
// Indirect Address: Located in the Direct Page at the sum of the direct page
|
||||
// register and the operand byte, in bank zero.
|
||||
//
|
||||
// LDA (dp), Y
|
||||
uint16_t DirectPageIndirectIndexedY() {
|
||||
uint8_t dp = FetchByte();
|
||||
return memory.ReadWord(dp) + Y;
|
||||
}
|
||||
|
||||
// Effective Address:
|
||||
// Found by adding to the triple-byte indirect address Y based on the
|
||||
// emulation mode. Indrect Address: Located in the Direct Page at the sum
|
||||
// of the direct page register and the operand byte in bank zero.
|
||||
// Indirect Address:
|
||||
// Located in the Direct Page at the sum of the direct page register and
|
||||
// the operand byte in bank zero.
|
||||
//
|
||||
// LDA (dp), Y
|
||||
uint16_t DirectPageIndirectLongIndexedY() {
|
||||
uint8_t dp = FetchByte();
|
||||
return memory.ReadWordLong(dp) + Y;
|
||||
}
|
||||
|
||||
// 8-bit data: Data Operand Byte
|
||||
// 16-bit data 65816 native mode m or x = 0
|
||||
// Data High: Second Operand Byte
|
||||
// Data Low: First Operand Byte
|
||||
//
|
||||
// LDA #const
|
||||
uint16_t Immediate() { return PC++; }
|
||||
|
||||
uint16_t StackRelative() {
|
||||
uint8_t sr = FetchByte();
|
||||
return SP() + sr;
|
||||
}
|
||||
|
||||
uint16_t StackRelativeIndirectIndexedY() {
|
||||
uint8_t sr = FetchByte();
|
||||
return memory.ReadWord(SP() + sr) + Y;
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// Registers
|
||||
uint8_t A = 0; // Accumulator
|
||||
uint8_t X = 0; // X index register
|
||||
uint8_t Y = 0; // Y index register
|
||||
uint8_t SP = 0; // Stack Pointer
|
||||
|
||||
uint8_t A = 0; // Accumulator
|
||||
uint8_t X = 0; // X index register
|
||||
uint8_t Y = 0; // Y index register
|
||||
// uint8_t SP = 0; // Stack Pointer
|
||||
uint16_t DB = 0; // Data Bank register
|
||||
uint16_t D = 0; // Direct Page register
|
||||
uint16_t PB = 0; // Program Bank register
|
||||
@@ -165,8 +265,8 @@ class CPU : public Memory {
|
||||
// B #$10 00010000 Break (emulation mode only)
|
||||
|
||||
// Setting flags in the status register
|
||||
int GetAccumulatorSize() { return status & 0x20; }
|
||||
int GetIndexSize() { return status & 0x10; }
|
||||
int GetAccumulatorSize() const { return status & 0x20; }
|
||||
int GetIndexSize() const { return status & 0x10; }
|
||||
|
||||
// Set individual flags
|
||||
void SetNegativeFlag(bool set) { SetFlag(0x80, set); }
|
||||
@@ -186,7 +286,84 @@ class CPU : public Memory {
|
||||
bool GetZeroFlag() const { return GetFlag(0x02); }
|
||||
bool GetCarryFlag() const { return GetFlag(0x01); }
|
||||
|
||||
// ==========================================================================
|
||||
// Instructions
|
||||
|
||||
// Left to implement
|
||||
// * = in progress
|
||||
|
||||
// ADC: Add with carry *
|
||||
// AND: Logical AND *
|
||||
// ASL: Arithmetic shift left
|
||||
// BCC: Branch if carry clear *
|
||||
// BCS: Branch if carry set *
|
||||
// BEQ: Branch if equal (zero set) *
|
||||
// BIT: Bit test
|
||||
// BMI: Branch if minus (negative set)
|
||||
// BNE: Branch if not equal (zero clear)
|
||||
// BPL: Branch if plus (negative clear)
|
||||
// BRA: Branch always
|
||||
// BRK: Break
|
||||
// BRL: Branch always long
|
||||
// BVC: Branch if overflow clear
|
||||
// BVS: Branch if overflow set
|
||||
// CMP: Compare
|
||||
// COP: Coprocessor
|
||||
// CPX: Compare X register
|
||||
// CPY: Compare Y register
|
||||
// DEC: Decrement
|
||||
// DEX: Decrement X register
|
||||
// DEY: Decrement Y register
|
||||
// EOR: Exclusive OR
|
||||
// INC: Increment
|
||||
// INX: Increment X register
|
||||
// INY: Increment Y register
|
||||
// JMP: Jump
|
||||
// JML: Jump long
|
||||
// JSR: Jump to subroutine
|
||||
// JSL: Jump to subroutine long
|
||||
// LDA: Load accumulator
|
||||
// LDX: Load X register
|
||||
// LDY: Load Y register
|
||||
// LSR: Logical shift right
|
||||
// MVN: Move negative
|
||||
// MVP: Move positive
|
||||
// NOP: No operation
|
||||
// ORA: Logical OR
|
||||
// PEA: Push effective address
|
||||
// PEI: Push effective indirect address
|
||||
// PER: Push effective PC-relative address
|
||||
// PHA: Push accumulator
|
||||
// PHB: Push data bank register
|
||||
// PHD: Push direct page register
|
||||
// PHK: Push program bank register
|
||||
// PHP: Push processor status register
|
||||
// PHX: Push X register
|
||||
// PHY: Push Y register
|
||||
// PLA: Pull accumulator
|
||||
// PLB: Pull data bank register
|
||||
// PLD: Pull direct page register
|
||||
// PLP: Pull processor status register
|
||||
// PLX: Pull X register
|
||||
// PLY: Pull Y register
|
||||
// ROL: Rotate left
|
||||
// ROR: Rotate right
|
||||
// RTI: Return from interrupt
|
||||
// RTL: Return from subroutine long
|
||||
// RTS: Return from subroutine
|
||||
// SBC: Subtract with carry
|
||||
// STA: Store accumulator
|
||||
// STP: Stop the clock
|
||||
// STX: Store X register
|
||||
// STY: Store Y register
|
||||
// STZ: Store zero
|
||||
// TDC: Transfer direct page register to accumulator
|
||||
// TRB: Test and reset bits
|
||||
// TSB: Test and set bits
|
||||
// WAI: Wait for interrupt
|
||||
// XBA: Exchange B and A accumulator
|
||||
// XCE: Exchange carry and emulation
|
||||
|
||||
void ADC(uint8_t operand);
|
||||
void AND(uint16_t address);
|
||||
|
||||
@@ -223,6 +400,18 @@ class CPU : public Memory {
|
||||
|
||||
void CLV() { status &= ~0x40; }
|
||||
|
||||
void PHA() { memory.PushByte(A); }
|
||||
|
||||
void PLA() {
|
||||
A = memory.PopByte();
|
||||
SetNegativeFlag((A & 0x80) != 0);
|
||||
SetZeroFlag(A == 0);
|
||||
}
|
||||
|
||||
void PHP() { memory.PushByte(status); }
|
||||
|
||||
void PLP() { status = memory.PopByte(); }
|
||||
|
||||
void SEI() { status |= 0x04; }
|
||||
|
||||
void SED() { status |= 0x08; }
|
||||
@@ -251,7 +440,7 @@ class CPU : public Memory {
|
||||
SetNegativeFlag(A & 0x80);
|
||||
}
|
||||
|
||||
void TCS() { SP = A; }
|
||||
void TCS() { memory.SetSP(A); }
|
||||
|
||||
void TAX() {
|
||||
X = A;
|
||||
@@ -290,15 +479,15 @@ class CPU : public Memory {
|
||||
}
|
||||
|
||||
void TSX() {
|
||||
X = SP;
|
||||
X = SP();
|
||||
SetZeroFlag(X == 0);
|
||||
SetNegativeFlag(X & 0x80);
|
||||
}
|
||||
|
||||
void TXS() { SP = X; }
|
||||
void TXS() { memory.SetSP(X); }
|
||||
|
||||
void TSC() {
|
||||
A = SP;
|
||||
A = SP();
|
||||
SetZeroFlag(A == 0);
|
||||
SetNegativeFlag(A & 0x80);
|
||||
}
|
||||
@@ -328,14 +517,19 @@ class CPU : public Memory {
|
||||
// Helper function to get the value of a specific flag bit
|
||||
bool GetFlag(uint8_t mask) const { return (status & mask) != 0; }
|
||||
|
||||
// Appease the C++ Gods...
|
||||
void PushByte(uint8_t value) override { memory.PushByte(value); }
|
||||
void PushWord(uint16_t value) override { memory.PushWord(value); }
|
||||
uint8_t PopByte() override { return memory.PopByte(); }
|
||||
uint16_t PopWord() override { return memory.PopWord(); }
|
||||
void ClearMemory() override { memory.ClearMemory(); }
|
||||
void LoadData(const std::vector<uint8_t>& data) override {
|
||||
memory.LoadData(data);
|
||||
}
|
||||
|
||||
// Appease the C++ Gods...
|
||||
uint8_t operator[](int i) const override { return 0; }
|
||||
uint8_t at(int i) const override { return 0; }
|
||||
|
||||
Memory& memory;
|
||||
};
|
||||
|
||||
} // namespace emu
|
||||
|
||||
@@ -34,6 +34,13 @@ class Memory {
|
||||
virtual void WriteByte(uint32_t address, uint8_t value) = 0;
|
||||
virtual void WriteWord(uint32_t address, uint16_t value) = 0;
|
||||
|
||||
virtual void PushByte(uint8_t value) = 0;
|
||||
virtual uint8_t PopByte() = 0;
|
||||
virtual void PushWord(uint16_t value) = 0;
|
||||
virtual uint16_t PopWord() = 0;
|
||||
virtual int16_t SP() const = 0;
|
||||
virtual void SetSP(int16_t value) = 0;
|
||||
|
||||
virtual void SetMemory(const std::vector<uint8_t>& data) = 0;
|
||||
virtual void ClearMemory() = 0;
|
||||
virtual void LoadData(const std::vector<uint8_t>& data) = 0;
|
||||
@@ -65,6 +72,7 @@ class MemoryImpl : public Memory {
|
||||
(static_cast<uint32_t>(memory_.at(mapped_address + 1)) << 8) |
|
||||
(static_cast<uint32_t>(memory_.at(mapped_address + 2)) << 16);
|
||||
}
|
||||
|
||||
void WriteByte(uint32_t address, uint8_t value) override {
|
||||
uint32_t mapped_address = GetMappedAddress(address);
|
||||
memory_.at(mapped_address) = value;
|
||||
@@ -75,19 +83,47 @@ class MemoryImpl : public Memory {
|
||||
memory_.at(mapped_address + 1) = (value >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
// Stack operations
|
||||
void PushByte(uint8_t value) override {
|
||||
if (SP_ > 0x0100) {
|
||||
memory_.at(SP_--) = value;
|
||||
} else {
|
||||
// Handle stack underflow
|
||||
std::cout << "Stack underflow!" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t PopByte() override {
|
||||
if (SP_ < 0x1FF) {
|
||||
return memory_.at(++SP_);
|
||||
} else {
|
||||
// Handle stack overflow
|
||||
std::cout << "Stack overflow!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void PushWord(uint16_t value) override {
|
||||
PushByte(value >> 8);
|
||||
PushByte(value & 0xFF);
|
||||
}
|
||||
|
||||
uint16_t PopWord() override {
|
||||
uint8_t low = PopByte();
|
||||
uint8_t high = PopByte();
|
||||
return (static_cast<uint16_t>(high) << 8) | low;
|
||||
}
|
||||
|
||||
int16_t SP() const override { return SP_; }
|
||||
void SetSP(int16_t value) override { SP_ = value; }
|
||||
|
||||
void SetMemory(const std::vector<uint8_t>& data) override { memory_ = data; }
|
||||
|
||||
void ClearMemory() override { memory_.resize(64000, 0x00); }
|
||||
|
||||
void LoadData(const std::vector<uint8_t>& data) override {
|
||||
std::copy(data.begin(), data.end(), memory_.begin());
|
||||
}
|
||||
|
||||
uint8_t at(int i) const override { return memory_[i]; }
|
||||
auto size() const { return memory_.size(); }
|
||||
auto begin() const { return memory_.begin(); }
|
||||
auto end() const { return memory_.end(); }
|
||||
|
||||
uint8_t operator[](int i) const override {
|
||||
if (i > memory_.size()) {
|
||||
std::cout << i << " out of bounds \n";
|
||||
@@ -96,6 +132,10 @@ class MemoryImpl : public Memory {
|
||||
return memory_[i];
|
||||
}
|
||||
|
||||
auto size() const { return memory_.size(); }
|
||||
auto begin() const { return memory_.begin(); }
|
||||
auto end() const { return memory_.end(); }
|
||||
|
||||
private:
|
||||
uint32_t GetMappedAddress(uint32_t address) const {
|
||||
uint32_t bank = address >> 16;
|
||||
@@ -135,6 +175,9 @@ class MemoryImpl : public Memory {
|
||||
|
||||
// Memory (64KB)
|
||||
std::vector<uint8_t> memory_;
|
||||
|
||||
// Stack Pointer
|
||||
uint16_t SP_ = 0x01FF;
|
||||
};
|
||||
|
||||
} // namespace emu
|
||||
|
||||
@@ -45,7 +45,7 @@ absl::Status LoadCgx(uint8_t bpp, std::string_view filename,
|
||||
std::vector<uint8_t>& cgx_data,
|
||||
std::vector<uint8_t>& cgx_loaded,
|
||||
std::vector<uint8_t>& cgx_header) {
|
||||
std::ifstream file(filename, std::ios::binary);
|
||||
std::ifstream file(filename.data(), std::ios::binary);
|
||||
if (!file.is_open()) {
|
||||
return absl::NotFoundError("CGX file not found.");
|
||||
}
|
||||
@@ -68,7 +68,7 @@ absl::Status LoadCgx(uint8_t bpp, std::string_view filename,
|
||||
|
||||
absl::Status LoadScr(std::string_view filename, uint8_t input_value,
|
||||
std::vector<uint8_t>& map_data) {
|
||||
std::ifstream file(filename, std::ios::binary);
|
||||
std::ifstream file(filename.data(), std::ios::binary);
|
||||
if (!file.is_open()) {
|
||||
return absl::NotFoundError("SCR/PNL/MAP file not found.");
|
||||
}
|
||||
@@ -157,9 +157,9 @@ absl::Status DrawScrWithCgx(uint8_t bpp, std::vector<uint8_t>& map_data,
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
std::vector<SDL_Color> DecodeColFile(const std::string& filename) {
|
||||
std::vector<SDL_Color> DecodeColFile(const std::string_view filename) {
|
||||
std::vector<SDL_Color> decoded_col;
|
||||
std::ifstream file(filename, std::ios::binary | std::ios::ate);
|
||||
std::ifstream file(filename.data(), std::ios::binary | std::ios::ate);
|
||||
|
||||
if (!file.is_open()) {
|
||||
return decoded_col; // Return an empty vector if the file couldn't be
|
||||
|
||||
@@ -63,7 +63,7 @@ absl::Status DrawScrWithCgx(uint8_t bpp, std::vector<uint8_t>& map_bitmap_data,
|
||||
std::vector<uint8_t>& map_data,
|
||||
std::vector<uint8_t>& cgx_loaded);
|
||||
|
||||
std::vector<SDL_Color> DecodeColFile(const std::string& filename);
|
||||
std::vector<SDL_Color> DecodeColFile(const std::string_view filename);
|
||||
|
||||
absl::Status DecodeObjFile(
|
||||
std::string_view filename, std::vector<uint8_t>& obj_data,
|
||||
|
||||
Reference in New Issue
Block a user