diff --git a/include/bus.hh b/include/bus.hh index 6d74f77..a0b93c7 100644 --- a/include/bus.hh +++ b/include/bus.hh @@ -5,10 +5,20 @@ #include #include #include -#include #include namespace matar { +enum CpuAccess { + Sequential, + NonSequential +}; + +enum CpuAccessWidth { + Word, + Halfword, + Byte +}; + class Bus { private: struct Private { @@ -23,20 +33,57 @@ class Bus { static std::shared_ptr init(std::array&&, std::vector&&); - uint8_t read_byte(uint32_t, bool = true); - void write_byte(uint32_t, uint8_t, bool = true); + uint8_t read_byte(uint32_t address, CpuAccess access) { + add_cpu_cycles(address, access); + return read_byte(address); + }; + void write_byte(uint32_t address, uint8_t byte, CpuAccess access) { + add_cpu_cycles(address, access); + write_byte(address, byte); + }; - uint16_t read_halfword(uint32_t, bool = true); - void write_halfword(uint32_t, uint16_t, bool = true); + uint16_t read_halfword(uint32_t address, CpuAccess access) { + add_cpu_cycles(address, access); + return read_halfword(address); + } + void write_halfword(uint32_t address, uint16_t halfword, CpuAccess access) { + add_cpu_cycles(address, access); + write_halfword(address, halfword); + } + + uint32_t read_word(uint32_t address, CpuAccess access) { + add_cpu_cycles(address, access); + return read_word(address); + } + void write_word(uint32_t address, uint32_t word, CpuAccess access) { + add_cpu_cycles(address, access); + write_word(address, word); + } + + uint8_t read_byte(uint32_t address); + void write_byte(uint32_t address, uint8_t byte); + + uint16_t read_halfword(uint32_t address); + void write_halfword(uint32_t address, uint16_t halfword); + + uint32_t read_word(uint32_t address); + void write_word(uint32_t address, uint32_t word); - uint32_t read_word(uint32_t, bool = true); - void write_word(uint32_t, uint32_t, bool = true); // not sure what else to do? - inline void internal_cycle() { cycles++; } - - inline uint32_t get_cycles() { return cycles; } + void internal_cycle() { cycles++; } + uint32_t get_cycles() { return cycles; } private: + template + void add_cpu_cycles(uint32_t address, CpuAccess access) { + auto cc = cycle_map[address >> 24 & 0xF]; + if constexpr (W == CpuAccessWidth::Word) { + cycles += (access == CpuAccess::Sequential ? cc.s32 : cc.n32); + } else { + cycles += (access == CpuAccess::Sequential ? cc.s16 : cc.n16); + } + } + template std::optional> read(uint32_t) const; diff --git a/include/cpu/cpu.hh b/include/cpu/cpu.hh index 2a25ecf..88f8673 100644 --- a/include/cpu/cpu.hh +++ b/include/cpu/cpu.hh @@ -24,12 +24,17 @@ class Cpu { void step(); void chg_mode(const Mode to); - inline bool is_halted() { return halted; } - inline void resume() { halted = false; } - +#ifdef GDB_DEBUG + bool breakpoint_reached() { + if (breakpoints.contains(pc - 2 * (cpsr.state() == State::Arm + ? arm::INSTRUCTION_SIZE + : thumb::INSTRUCTION_SIZE))) { + return true; + } + return false; + } +#endif private: - bool halted = false; - friend void arm::Instruction::exec(Cpu& cpu); friend void thumb::Instruction::exec(Cpu& cpu); @@ -79,32 +84,19 @@ class Cpu { Psr und; } spsr_banked = {}; // banked saved program status registers - inline void internal_cycle() { bus->internal_cycle(); } + void internal_cycle() { bus->internal_cycle(); } // whether read is going to be sequential or not - bool sequential = true; + CpuAccess next_access = CpuAccess::Sequential; // raw instructions in the pipeline std::array opcodes = {}; - inline void advance_pc_arm() { pc += arm::INSTRUCTION_SIZE; }; - inline void advance_pc_thumb() { pc += thumb::INSTRUCTION_SIZE; } + void advance_pc_arm() { pc += arm::INSTRUCTION_SIZE; }; + void advance_pc_thumb() { pc += thumb::INSTRUCTION_SIZE; } bool is_flushed = false; - inline void flush_pipeline() { - if (cpsr.state() == State::Arm) { - opcodes[0] = bus->read_word(pc, false); - advance_pc_arm(); - opcodes[1] = bus->read_word(pc); - advance_pc_arm(); - } else { - opcodes[0] = bus->read_halfword(pc, false); - advance_pc_thumb(); - opcodes[1] = bus->read_halfword(pc); - advance_pc_thumb(); - } - sequential = true; - }; + void flush_pipeline(); #ifdef GDB_DEBUG friend class GdbRsp; diff --git a/src/bus.cc b/src/bus.cc index ce6213d..9afcb97 100644 --- a/src/bus.cc +++ b/src/bus.cc @@ -1,4 +1,5 @@ #include "bus.hh" +#include "io/io.hh" #include "util/crypto.hh" #include "util/log.hh" @@ -141,10 +142,7 @@ Bus::write(uint32_t address) { } uint8_t -Bus::read_byte(uint32_t address, bool sequential) { - auto cc = cycle_map[address >> 24 & 0xF]; - cycles += sequential ? cc.s16 : cc.n16; - +Bus::read_byte(uint32_t address) { if (address >= IO_START && address <= IO_END) return io->read_byte(address); @@ -153,10 +151,7 @@ Bus::read_byte(uint32_t address, bool sequential) { } void -Bus::write_byte(uint32_t address, uint8_t byte, bool sequential) { - auto cc = cycle_map[address >> 24 & 0xF]; - cycles += sequential ? cc.s16 : cc.n16; - +Bus::write_byte(uint32_t address, uint8_t byte) { if (address >= IO_START && address <= IO_END) { io->write_byte(address, byte); return; @@ -169,13 +164,10 @@ Bus::write_byte(uint32_t address, uint8_t byte, bool sequential) { } uint16_t -Bus::read_halfword(uint32_t address, bool sequential) { +Bus::read_halfword(uint32_t address) { if (address & 0b01) glogger.warn("Reading a non aligned halfword address"); - auto cc = cycle_map[address >> 24 & 0xF]; - cycles += sequential ? cc.s16 : cc.n16; - if (address >= IO_START && address <= IO_END) return io->read_halfword(address); @@ -185,13 +177,10 @@ Bus::read_halfword(uint32_t address, bool sequential) { } void -Bus::write_halfword(uint32_t address, uint16_t halfword, bool sequential) { +Bus::write_halfword(uint32_t address, uint16_t halfword) { if (address & 0b01) glogger.warn("Writing to a non aligned halfword address"); - auto cc = cycle_map[address >> 24 & 0xF]; - cycles += sequential ? cc.s16 : cc.n16; - if (address >= IO_START && address <= IO_END) { io->write_halfword(address, halfword); return; @@ -207,13 +196,10 @@ Bus::write_halfword(uint32_t address, uint16_t halfword, bool sequential) { } uint32_t -Bus::read_word(uint32_t address, bool sequential) { +Bus::read_word(uint32_t address) { if (address & 0b11) glogger.warn("Reading a non aligned word address"); - auto cc = cycle_map[address >> 24 & 0xF]; - cycles += sequential ? cc.s32 : cc.n32; - if (address >= IO_START && address <= IO_END) return io->read_word(address); @@ -225,13 +211,10 @@ Bus::read_word(uint32_t address, bool sequential) { } void -Bus::write_word(uint32_t address, uint32_t word, bool sequential) { +Bus::write_word(uint32_t address, uint32_t word) { if (address & 0b11) glogger.warn("Writing to a non aligned word address"); - auto cc = cycle_map[address >> 24 & 0xF]; - cycles += sequential ? cc.s32 : cc.n32; - if (address >= IO_START && address <= IO_END) { io->write_word(address, word); return; diff --git a/src/cpu/arm/exec.cc b/src/cpu/arm/exec.cc index 914683c..71f419c 100644 --- a/src/cpu/arm/exec.cc +++ b/src/cpu/arm/exec.cc @@ -203,17 +203,21 @@ Instruction::exec(Cpu& cpu) { pc_error(data.rd); if (data.byte) { - cpu.gpr[data.rd] = cpu.bus->read_byte(cpu.gpr[data.rn], false); - cpu.bus->write_byte( - cpu.gpr[data.rn], cpu.gpr[data.rm] & 0xFF, true); + cpu.gpr[data.rd] = cpu.bus->read_byte(cpu.gpr[data.rn], + CpuAccess::NonSequential); + cpu.bus->write_byte(cpu.gpr[data.rn], + cpu.gpr[data.rm] & 0xFF, + CpuAccess::Sequential); } else { - cpu.gpr[data.rd] = cpu.bus->read_word(cpu.gpr[data.rn], false); - cpu.bus->write_word(cpu.gpr[data.rn], cpu.gpr[data.rm], true); + cpu.gpr[data.rd] = cpu.bus->read_word(cpu.gpr[data.rn], + CpuAccess::NonSequential); + cpu.bus->write_word( + cpu.gpr[data.rn], cpu.gpr[data.rm], CpuAccess::Sequential); } cpu.internal_cycle(); // last write address is unrelated to next - cpu.sequential = false; + cpu.next_access = CpuAccess::NonSequential; }, [&cpu, pc_warn, pc_error](SingleDataTransfer& data) { /* @@ -273,10 +277,12 @@ Instruction::exec(Cpu& cpu) { if (data.load) { // byte if (data.byte) - cpu.gpr[data.rd] = cpu.bus->read_byte(address, false); + cpu.gpr[data.rd] = + cpu.bus->read_byte(address, CpuAccess::NonSequential); // word else - cpu.gpr[data.rd] = cpu.bus->read_word(address, false); + cpu.gpr[data.rd] = + cpu.bus->read_word(address, CpuAccess::NonSequential); // N + S if (data.rd == cpu.PC_INDEX) @@ -292,11 +298,13 @@ Instruction::exec(Cpu& cpu) { // byte if (data.byte) - cpu.bus->write_byte( - address, cpu.gpr[data.rd] & 0xFF, false); + cpu.bus->write_byte(address, + cpu.gpr[data.rd] & 0xFF, + CpuAccess::NonSequential); // word else - cpu.bus->write_word(address, cpu.gpr[data.rd], false); + cpu.bus->write_word( + address, cpu.gpr[data.rd], CpuAccess::NonSequential); } if (!data.pre) @@ -306,7 +314,7 @@ Instruction::exec(Cpu& cpu) { cpu.gpr[data.rn] = address; // last read/write is unrelated, this will be overwriten if flushed - cpu.sequential = false; + cpu.next_access = CpuAccess::NonSequential; }, [&cpu, pc_warn, pc_error](HalfwordTransfer& data) { /* @@ -324,7 +332,6 @@ Instruction::exec(Cpu& cpu) { N -> write at target Total = 2N */ - uint32_t address = cpu.gpr[data.rn]; uint32_t offset = 0; @@ -359,8 +366,8 @@ Instruction::exec(Cpu& cpu) { if (data.sign) { // halfword if (data.half) { - cpu.gpr[data.rd] = - cpu.bus->read_halfword(address, false); + cpu.gpr[data.rd] = cpu.bus->read_halfword( + address, CpuAccess::NonSequential); // sign extend the halfword cpu.gpr[data.rd] = @@ -368,7 +375,8 @@ Instruction::exec(Cpu& cpu) { // byte } else { - cpu.gpr[data.rd] = cpu.bus->read_byte(address, false); + cpu.gpr[data.rd] = + cpu.bus->read_byte(address, CpuAccess::NonSequential); // sign extend the byte cpu.gpr[data.rd] = @@ -376,7 +384,8 @@ Instruction::exec(Cpu& cpu) { } // unsigned halfword } else if (data.half) { - cpu.gpr[data.rd] = cpu.bus->read_halfword(address, false); + cpu.gpr[data.rd] = + cpu.bus->read_halfword(address, CpuAccess::NonSequential); } // I @@ -393,7 +402,8 @@ Instruction::exec(Cpu& cpu) { // halfword if (data.half) - cpu.bus->write_halfword(address, cpu.gpr[data.rd], false); + cpu.bus->write_halfword( + address, cpu.gpr[data.rd], CpuAccess::NonSequential); } if (!data.pre) @@ -403,7 +413,7 @@ Instruction::exec(Cpu& cpu) { cpu.gpr[data.rn] = address; // last read/write is unrelated, this will be overwriten if flushed - cpu.sequential = false; + cpu.next_access = CpuAccess::NonSequential; }, [&cpu, pc_error](BlockDataTransfer& data) { /* @@ -429,7 +439,7 @@ Instruction::exec(Cpu& cpu) { uint32_t address = cpu.gpr[data.rn]; Mode mode = cpu.cpsr.mode(); int8_t i = 0; - bool sequential = false; + CpuAccess access = CpuAccess::NonSequential; pc_error(data.rn); @@ -466,19 +476,17 @@ Instruction::exec(Cpu& cpu) { if (data.up) { for (i = 0; i < cpu.GPR_COUNT; i++) { if (get_bit(data.regs, i)) { - cpu.gpr[i] = - cpu.bus->read_word(address, sequential); + cpu.gpr[i] = cpu.bus->read_word(address, access); address += alignment; - sequential = true; + access = CpuAccess::Sequential; } } } else { for (i = cpu.GPR_COUNT - 1; i >= 0; i--) { if (get_bit(data.regs, i)) { - cpu.gpr[i] = - cpu.bus->read_word(address, sequential); + cpu.gpr[i] = cpu.bus->read_word(address, access); address -= alignment; - sequential = true; + access = CpuAccess::Sequential; } } } @@ -489,19 +497,17 @@ Instruction::exec(Cpu& cpu) { if (data.up) { for (i = 0; i < cpu.GPR_COUNT; i++) { if (get_bit(data.regs, i)) { - cpu.bus->write_word( - address, cpu.gpr[i], sequential); + cpu.bus->write_word(address, cpu.gpr[i], access); address += alignment; - sequential = true; + access = CpuAccess::Sequential; } } } else { for (i = cpu.GPR_COUNT - 1; i >= 0; i--) { if (get_bit(data.regs, i)) { - cpu.bus->write_word( - address, cpu.gpr[i], sequential); + cpu.bus->write_word(address, cpu.gpr[i], access); address -= alignment; - sequential = true; + access = CpuAccess::Sequential; } } } @@ -518,7 +524,7 @@ Instruction::exec(Cpu& cpu) { cpu.chg_mode(mode); // last read/write is unrelated, this will be overwriten if flushed - cpu.sequential = false; + cpu.next_access = CpuAccess::NonSequential; }, [&cpu, pc_error](PsrTransfer& data) { /* diff --git a/src/cpu/cpu.cc b/src/cpu/cpu.cc index 22620b8..c2b0187 100644 --- a/src/cpu/cpu.cc +++ b/src/cpu/cpu.cc @@ -132,7 +132,7 @@ Cpu::step() { arm::Instruction instruction(opcodes[0]); opcodes[0] = opcodes[1]; - opcodes[1] = bus->read_word(pc, sequential); + opcodes[1] = bus->read_word(pc, next_access); #ifdef DISASSEMBLER glogger.info("0x{:08X} : {}", @@ -151,7 +151,7 @@ Cpu::step() { thumb::Instruction instruction(opcodes[0]); opcodes[0] = opcodes[1]; - opcodes[1] = bus->read_halfword(pc, sequential); + opcodes[1] = bus->read_halfword(pc, next_access); #ifdef DISASSEMBLER glogger.info("0x{:08X} : {}", @@ -168,4 +168,24 @@ Cpu::step() { advance_pc_thumb(); } } + +void +Cpu::flush_pipeline() { + // halfword align + rst_bit(pc, 0); + if (cpsr.state() == State::Arm) { + // word align + rst_bit(pc, 1); + opcodes[0] = bus->read_word(pc, CpuAccess::NonSequential); + advance_pc_arm(); + opcodes[1] = bus->read_word(pc, CpuAccess::Sequential); + advance_pc_arm(); + } else { + opcodes[0] = bus->read_halfword(pc, CpuAccess::NonSequential); + advance_pc_thumb(); + opcodes[1] = bus->read_halfword(pc, CpuAccess::Sequential); + advance_pc_thumb(); + } + next_access = CpuAccess::Sequential; +}; } diff --git a/src/cpu/thumb/exec.cc b/src/cpu/thumb/exec.cc index f26186e..4763d7b 100644 --- a/src/cpu/thumb/exec.cc +++ b/src/cpu/thumb/exec.cc @@ -257,12 +257,13 @@ Instruction::exec(Cpu& cpu) { rst_bit(pc, 0); rst_bit(pc, 1); - cpu.gpr[data.rd] = cpu.bus->read_word(pc + data.word, false); + cpu.gpr[data.rd] = + cpu.bus->read_word(pc + data.word, CpuAccess::NonSequential); cpu.internal_cycle(); // last read is unrelated - cpu.sequential = false; + cpu.next_access = CpuAccess::NonSequential; }, [&cpu](LoadStoreRegisterOffset& data) { /* @@ -284,22 +285,26 @@ Instruction::exec(Cpu& cpu) { if (data.load) { if (data.byte) { - cpu.gpr[data.rd] = cpu.bus->read_byte(address, false); + cpu.gpr[data.rd] = + cpu.bus->read_byte(address, CpuAccess::NonSequential); } else { - cpu.gpr[data.rd] = cpu.bus->read_word(address, false); + cpu.gpr[data.rd] = + cpu.bus->read_word(address, CpuAccess::NonSequential); } cpu.internal_cycle(); } else { if (data.byte) { - cpu.bus->write_byte( - address, cpu.gpr[data.rd] & 0xFF, false); + cpu.bus->write_byte(address, + cpu.gpr[data.rd] & 0xFF, + CpuAccess::NonSequential); } else { - cpu.bus->write_word(address, cpu.gpr[data.rd], false); + cpu.bus->write_word( + address, cpu.gpr[data.rd], CpuAccess::NonSequential); } } // last read/write is unrelated - cpu.sequential = false; + cpu.next_access = CpuAccess::NonSequential; }, [&cpu](LoadStoreSignExtendedHalfword& data) { // Same cycles as above @@ -308,26 +313,28 @@ Instruction::exec(Cpu& cpu) { switch (data.s << 1 | data.h) { case 0b00: - cpu.bus->write_halfword( - address, cpu.gpr[data.rd] & 0xFFFF, false); + cpu.bus->write_halfword(address, + cpu.gpr[data.rd] & 0xFFFF, + CpuAccess::NonSequential); break; case 0b01: - cpu.gpr[data.rd] = cpu.bus->read_halfword(address, false); + cpu.gpr[data.rd] = + cpu.bus->read_halfword(address, CpuAccess::NonSequential); cpu.internal_cycle(); break; case 0b10: // sign extend and load the byte - cpu.gpr[data.rd] = - (static_cast(cpu.bus->read_byte(address, false)) - << 24) >> - 24; + cpu.gpr[data.rd] = (static_cast(cpu.bus->read_byte( + address, CpuAccess::NonSequential)) + << 24) >> + 24; cpu.internal_cycle(); break; case 0b11: // sign extend the halfword cpu.gpr[data.rd] = - (static_cast( - cpu.bus->read_halfword(address, false)) + (static_cast(cpu.bus->read_halfword( + address, CpuAccess::NonSequential)) << 16) >> 16; cpu.internal_cycle(); @@ -339,7 +346,7 @@ Instruction::exec(Cpu& cpu) { } // last read/write is unrelated - cpu.sequential = false; + cpu.next_access = CpuAccess::NonSequential; }, [&cpu](LoadStoreImmediateOffset& data) { // Same cycles as above @@ -348,22 +355,26 @@ Instruction::exec(Cpu& cpu) { if (data.load) { if (data.byte) { - cpu.gpr[data.rd] = cpu.bus->read_byte(address, false); + cpu.gpr[data.rd] = + cpu.bus->read_byte(address, CpuAccess::NonSequential); } else { - cpu.gpr[data.rd] = cpu.bus->read_word(address, false); + cpu.gpr[data.rd] = + cpu.bus->read_word(address, CpuAccess::NonSequential); } cpu.internal_cycle(); } else { if (data.byte) { - cpu.bus->write_byte( - address, cpu.gpr[data.rd] & 0xFF, false); + cpu.bus->write_byte(address, + cpu.gpr[data.rd] & 0xFF, + CpuAccess::NonSequential); } else { - cpu.bus->write_word(address, cpu.gpr[data.rd], false); + cpu.bus->write_word( + address, cpu.gpr[data.rd], CpuAccess::NonSequential); } } // last read/write is unrelated - cpu.sequential = false; + cpu.next_access = CpuAccess::NonSequential; }, [&cpu](LoadStoreHalfword& data) { // Same cycles as above @@ -371,14 +382,16 @@ Instruction::exec(Cpu& cpu) { uint32_t address = cpu.gpr[data.rb] + data.offset; if (data.load) { - cpu.gpr[data.rd] = cpu.bus->read_halfword(address); + cpu.gpr[data.rd] = + cpu.bus->read_halfword(address, CpuAccess::NonSequential); cpu.internal_cycle(); } else { - cpu.bus->write_halfword(address, cpu.gpr[data.rd] & 0xFFFF); + cpu.bus->write_halfword( + address, cpu.gpr[data.rd] & 0xFFFF, CpuAccess::NonSequential); } // last read/write is unrelated - cpu.sequential = false; + cpu.next_access = CpuAccess::NonSequential; }, [&cpu](SpRelativeLoad& data) { // Same cycles as above @@ -386,14 +399,16 @@ Instruction::exec(Cpu& cpu) { uint32_t address = cpu.sp + data.word; if (data.load) { - cpu.gpr[data.rd] = cpu.bus->read_word(address); + cpu.gpr[data.rd] = + cpu.bus->read_word(address, CpuAccess::Sequential); cpu.internal_cycle(); } else { - cpu.bus->write_word(address, cpu.gpr[data.rd]); + cpu.bus->write_word( + address, cpu.gpr[data.rd], CpuAccess::Sequential); } // last read/write is unrelated - cpu.sequential = false; + cpu.next_access = CpuAccess::NonSequential; }, [&cpu](LoadAddress& data) { // 1S cycle in step() @@ -430,19 +445,19 @@ Instruction::exec(Cpu& cpu) { Total = 2N + (n-1)S */ static constexpr uint8_t alignment = 4; - bool sequential = false; + CpuAccess access = CpuAccess::NonSequential; if (data.load) { for (uint8_t i = 0; i < 8; i++) { if (get_bit(data.regs, i)) { - cpu.gpr[i] = cpu.bus->read_word(cpu.sp, sequential); + cpu.gpr[i] = cpu.bus->read_word(cpu.sp, access); cpu.sp += alignment; - sequential = true; + access = CpuAccess::Sequential; } } if (data.pclr) { - cpu.pc = cpu.bus->read_word(cpu.sp); + cpu.pc = cpu.bus->read_word(cpu.sp, access); cpu.sp += alignment; cpu.is_flushed = true; } @@ -452,20 +467,21 @@ Instruction::exec(Cpu& cpu) { } else { if (data.pclr) { cpu.sp -= alignment; - cpu.bus->write_word(cpu.sp, cpu.lr); + cpu.bus->write_word(cpu.sp, cpu.lr, access); + access = CpuAccess::Sequential; } for (int8_t i = 7; i >= 0; i--) { if (get_bit(data.regs, i)) { cpu.sp -= alignment; - cpu.bus->write_word(cpu.sp, cpu.gpr[i], sequential); - sequential = true; + cpu.bus->write_word(cpu.sp, cpu.gpr[i], access); + access = CpuAccess::Sequential; } } } // last read/write is unrelated - cpu.sequential = false; + cpu.next_access = CpuAccess::NonSequential; }, [&cpu](MultipleLoad& data) { /* @@ -487,23 +503,23 @@ Instruction::exec(Cpu& cpu) { static constexpr uint8_t alignment = 4; - uint32_t rb = cpu.gpr[data.rb]; - bool sequential = false; + uint32_t rb = cpu.gpr[data.rb]; + CpuAccess access = CpuAccess::NonSequential; if (data.load) { for (uint8_t i = 0; i < 8; i++) { if (get_bit(data.regs, i)) { - cpu.gpr[i] = cpu.bus->read_word(rb, sequential); + cpu.gpr[i] = cpu.bus->read_word(rb, access); rb += alignment; - sequential = true; + access = CpuAccess::Sequential; } } } else { for (uint8_t i = 0; i < 8; i++) { if (get_bit(data.regs, i)) { - cpu.bus->write_word(rb, cpu.gpr[i], sequential); + cpu.bus->write_word(rb, cpu.gpr[i], access); rb += alignment; - sequential = true; + access = CpuAccess::Sequential; } } } @@ -511,7 +527,7 @@ Instruction::exec(Cpu& cpu) { cpu.gpr[data.rb] = rb; // last read/write is unrelated - cpu.sequential = false; + cpu.next_access = CpuAccess::NonSequential; }, [&cpu](ConditionalBranch& data) { /* diff --git a/src/gdb_rsp.cc b/src/gdb_rsp.cc index 81a35e6..6bb11eb 100644 --- a/src/gdb_rsp.cc +++ b/src/gdb_rsp.cc @@ -91,54 +91,59 @@ GdbRsp::step(std::string msg) { cmd_halted(); break; case '$': { - if (msg.starts_with("$qSupported")) { - acknowledge(); - cmd_supported(msg); - } else if (msg.starts_with("$qAttached")) { - acknowledge(); - cmd_attached(); - } else { - acknowledge(); - switch (msg[1]) { - case '?': - cmd_halted(); + acknowledge(); + switch (msg[1]) { + case '?': + cmd_halted(); + break; + case 'g': + cmd_read_registers(); + break; + case 'G': + cmd_write_registers(msg); + break; + case 'p': + cmd_read_register(msg); + break; + case 'P': + cmd_write_register(msg); + break; + case 'm': + cmd_read_memory(msg); + break; + case 'M': + cmd_write_memory(msg); + break; + case 'z': + cmd_rm_breakpoint(msg); + break; + case 'Z': + cmd_add_breakpoint(msg); + break; + case 'c': + cmd_continue(); + break; + case 'D': + cmd_detach(); + break; + case 'Q': + if (msg == "$QStartNoAckMode") + ack_mode = true; + send_ok(); + break; + case 'q': + if (msg.starts_with("$qSupported")) { + cmd_supported(msg); break; - case 'g': - cmd_read_registers(); + } else if (msg == "$qAttached") { + cmd_attached(); break; - case 'G': - cmd_write_registers(msg); - break; - case 'p': - cmd_read_register(msg); - break; - case 'P': - cmd_write_register(msg); - break; - case 'm': - cmd_read_memory(msg); - break; - case 'M': - cmd_write_memory(msg); - break; - case 'z': - cmd_rm_breakpoint(msg); - break; - case 'Z': - cmd_add_breakpoint(msg); - break; - case 'c': - cmd_continue(); - break; - case 'D': - cmd_detach(); - break; - default: - gdb_log("unknown command"); - send_empty(); - } + } + [[fallthrough]]; + default: + gdb_log("unknown command"); + send_empty(); } - break; } default: @@ -150,7 +155,7 @@ std::string GdbRsp::receive() { std::string msg = server.receive(1); char ch = msg[0]; - int checksum = 0; + uint checksum = 0; if (ch == '$') { while ((ch = server.receive(1)[0]) != '#') { @@ -179,7 +184,8 @@ GdbRsp::make_packet(std::string raw) { void GdbRsp::acknowledge() { - server.send("+"); + if (ack_mode) + server.send("+"); } void @@ -214,6 +220,9 @@ GdbRsp::cmd_supported(std::string msg) { if (msg.find("hwbreak+;") != std::string::npos) response += "hwbreak+;"; + // no acknowledgement mode + response += "QStartNoAckMode+"; + gdb_log("sending response for qSupported"); server.send(make_packet(response)); } @@ -327,7 +336,6 @@ GdbRsp::cmd_write_register(std::string msg) { void GdbRsp::cmd_read_memory(std::string msg) { std::string response; - bool sequential = false; static std::regex rgx("\\$m([0-9A-Fa-f]+),([0-9A-Fa-f]+)"); std::smatch sm; @@ -351,20 +359,15 @@ GdbRsp::cmd_read_memory(std::string msg) { } for (uint i = 0; i < length; i++) { - response += - std::format("{:02x}", cpu->bus->read_byte(address + i), sequential); - sequential = true; + response += std::format("{:02x}", cpu->bus->read_byte(address + i)); } - cpu->sequential = false; gdb_log("sending memory values values"); server.send(make_packet(response)); } void GdbRsp::cmd_write_memory(std::string msg) { - bool sequential = false; - static std::regex rgx("\\$M([0-9A-Fa-f]+),([0-9A-Fa-f]+):([0-9A-Fa-f]+)"); std::smatch sm; regex_match(msg, sm, rgx); @@ -382,15 +385,10 @@ GdbRsp::cmd_write_memory(std::string msg) { std::string values = sm[3].str(); for (uint i = 0, j = 0; i < length && j < values.size(); i++, j += 2) { - cpu->bus->write_byte(address + i, - std::stoul(values.substr(j, 2), nullptr, 16) & - 0xFF, - sequential); - glogger.warn("hi {:02x}", cpu->bus->read_byte(address + i)); - sequential = true; + cpu->bus->write_byte( + address + i, std::stoul(values.substr(j, 2), nullptr, 16) & 0xFF); } - cpu->sequential = false; gdb_log("register values written"); send_ok(); } catch (const std::exception& e) { diff --git a/src/gdb_rsp.hh b/src/gdb_rsp.hh index 7ed33e6..7becf25 100644 --- a/src/gdb_rsp.hh +++ b/src/gdb_rsp.hh @@ -21,6 +21,8 @@ class GdbRsp { net::TcpServer server; std::string receive(); std::string make_packet(std::string raw); + + bool ack_mode = true; void acknowledge(); void send_empty(); void send_ok(); diff --git a/tests/bus.cc b/tests/bus.cc index 055afa2..d0f7d4b 100644 --- a/tests/bus.cc +++ b/tests/bus.cc @@ -26,18 +26,12 @@ TEST_CASE("bios", TAG) { auto bus = Bus::init(std::move(bios), std::vector(Header::HEADER_SIZE)); - uint32_t cycles = bus->get_cycles(); - CHECK(bus->read_byte(0) == 0xAC); CHECK(bus->read_byte(0x3FFF) == 0x48); CHECK(bus->read_byte(0x2A56) == 0x10); - - CHECK(bus->get_cycles() == cycles + 3); } TEST_CASE_METHOD(BusFixture, "board wram", TAG) { - uint32_t cycles = bus->get_cycles(); - bus->write_byte(0x2000000, 0xAC); CHECK(bus->read_byte(0x2000000) == 0xAC); @@ -46,25 +40,9 @@ TEST_CASE_METHOD(BusFixture, "board wram", TAG) { bus->write_byte(0x2022A56, 0x10); CHECK(bus->read_byte(0x2022A56) == 0x10); - - CHECK(bus->get_cycles() == cycles + 2 * 9); - cycles = bus->get_cycles(); - - bus->write_halfword(0x2022A56, 0x1009); - CHECK(bus->read_halfword(0x2022A56) == 0x1009); - - CHECK(bus->get_cycles() == cycles + 2 * 3); - cycles = bus->get_cycles(); - - bus->write_word(0x2022A56, 0x10FF9903); - CHECK(bus->read_word(0x2022A56) == 0x10FF9903); - - CHECK(bus->get_cycles() == cycles + 2 * 6); } TEST_CASE_METHOD(BusFixture, "chip wram", TAG) { - uint32_t cycles = bus->get_cycles(); - bus->write_byte(0x3000000, 0xAC); CHECK(bus->read_byte(0x3000000) == 0xAC); @@ -73,25 +51,9 @@ TEST_CASE_METHOD(BusFixture, "chip wram", TAG) { bus->write_byte(0x3002A56, 0x10); CHECK(bus->read_byte(0x3002A56) == 0x10); - - CHECK(bus->get_cycles() == cycles + 2 * 3); - cycles = bus->get_cycles(); - - bus->write_halfword(0x3002A56, 0xF0F0); - CHECK(bus->read_halfword(0x3002A56) == 0xF0F0); - - CHECK(bus->get_cycles() == cycles + 2); - cycles = bus->get_cycles(); - - bus->write_word(0x3002A56, 0xF9399010); - CHECK(bus->read_word(0x3002A56) == 0xF9399010); - - CHECK(bus->get_cycles() == cycles + 2); } TEST_CASE_METHOD(BusFixture, "palette ram", TAG) { - uint32_t cycles = bus->get_cycles(); - bus->write_byte(0x5000000, 0xAC); CHECK(bus->read_byte(0x5000000) == 0xAC); @@ -100,25 +62,9 @@ TEST_CASE_METHOD(BusFixture, "palette ram", TAG) { bus->write_byte(0x5000156, 0x10); CHECK(bus->read_byte(0x5000156) == 0x10); - - CHECK(bus->get_cycles() == cycles + 2 * 3); - cycles = bus->get_cycles(); - - bus->write_halfword(0x5000156, 0xEEE1); - CHECK(bus->read_halfword(0x5000156) == 0xEEE1); - - CHECK(bus->get_cycles() == cycles + 2); - cycles = bus->get_cycles(); - - bus->write_word(0x5000156, 0x938566E0); - CHECK(bus->read_word(0x5000156) == 0x938566E0); - - CHECK(bus->get_cycles() == cycles + 2 * 2); } TEST_CASE_METHOD(BusFixture, "video ram", TAG) { - uint32_t cycles = bus->get_cycles(); - bus->write_byte(0x6000000, 0xAC); CHECK(bus->read_byte(0x6000000) == 0xAC); @@ -127,25 +73,9 @@ TEST_CASE_METHOD(BusFixture, "video ram", TAG) { bus->write_byte(0x6012A56, 0x10); CHECK(bus->read_byte(0x6012A56) == 0x10); - - CHECK(bus->get_cycles() == cycles + 2 * 3); - cycles = bus->get_cycles(); - - bus->write_halfword(0x6012A56, 0xB100); - CHECK(bus->read_halfword(0x6012A56) == 0xB100); - - CHECK(bus->get_cycles() == cycles + 2); - cycles = bus->get_cycles(); - - bus->write_word(0x6012A56, 0x9322093E); - CHECK(bus->read_word(0x6012A56) == 0x9322093E); - - CHECK(bus->get_cycles() == cycles + 2 * 2); } TEST_CASE_METHOD(BusFixture, "oam obj ram", TAG) { - uint32_t cycles = bus->get_cycles(); - bus->write_byte(0x7000000, 0xAC); CHECK(bus->read_byte(0x7000000) == 0xAC); @@ -154,20 +84,6 @@ TEST_CASE_METHOD(BusFixture, "oam obj ram", TAG) { bus->write_byte(0x7000156, 0x10); CHECK(bus->read_byte(0x7000156) == 0x10); - - CHECK(bus->get_cycles() == cycles + 2 * 3); - cycles = bus->get_cycles(); - - bus->write_halfword(0x7000156, 0x946C); - CHECK(bus->read_halfword(0x7000156) == 0x946C); - - CHECK(bus->get_cycles() == cycles + 2); - cycles = bus->get_cycles(); - - bus->write_word(0x7000156, 0x93C5D1E0); - CHECK(bus->read_word(0x7000156) == 0x93C5D1E0); - - CHECK(bus->get_cycles() == cycles + 2); } TEST_CASE("rom", TAG) {