From 31979649c65e9ff8f0dcac28b2243b9162fd02a7 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 31 Mar 2024 18:15:48 -0400 Subject: [PATCH] As it continues to swell, factor out the junk. --- Machines/Acorn/Archimedes/Archimedes.cpp | 552 ++++++++++++----------- 1 file changed, 283 insertions(+), 269 deletions(-) diff --git a/Machines/Acorn/Archimedes/Archimedes.cpp b/Machines/Acorn/Archimedes/Archimedes.cpp index 416921da5..888a587b6 100644 --- a/Machines/Acorn/Archimedes/Archimedes.cpp +++ b/Machines/Acorn/Archimedes/Archimedes.cpp @@ -41,6 +41,282 @@ Log::Logger logger; namespace Archimedes { +#ifndef NDEBUG +template +struct HackyDebugger { + + void notify(uint32_t address, uint32_t instruction, Executor &executor) { + pc_history[pc_history_ptr] = address; + pc_history_ptr = (pc_history_ptr + 1) % pc_history.size(); + +// if( +// executor_.pc() > 0x038021d0 && +// last_r1 != executor_.registers()[1] +// || +// ( +// last_link != executor_.registers()[14] || +// last_r0 != executor_.registers()[0] || +// last_r10 != executor_.registers()[10] || +// last_r1 != executor_.registers()[1] +// ) +// ) { +// logger.info().append("%08x modified R14 to %08x; R0 to %08x; R10 to %08x; R1 to %08x", +// last_pc, +// executor_.registers()[14], +// executor_.registers()[0], +// executor_.registers()[10], +// executor_.registers()[1] +// ); +// logger.info().append("%08x modified R1 to %08x", +// last_pc, +// executor_.registers()[1] +// ); +// last_link = executor_.registers()[14]; +// last_r0 = executor_.registers()[0]; +// last_r10 = executor_.registers()[10]; +// last_r1 = executor_.registers()[1]; +// } + +// if(executor_.pc() == 0x03801ed8 || (executor_.registers()[9] == 0x00ff'0000 && executor_.registers()[9] != last_r9)) { +// printf("At %08x; after last PC %08x and %zu ago was %08x; r9 is %08x [%d]\n", +// executor_.pc(), +// pc_history[(pc_history_ptr - 2 + pc_history.size()) % pc_history.size()], +// pc_history.size(), +// pc_history[pc_history_ptr], +// executor_.registers()[9], +// executor_.registers()[9] != last_r9); +// } +// last_r9 = executor_.registers()[9]; + +// log |= executor_.pc() == 0x03801ebc; +// log |= instr_count == 72766815; +// log &= executor_.pc() != 0x000000a0; + +// log = (executor_.pc() == 0x038162afc) || (executor_.pc() == 0x03824b00); +// log |= instruction & ; + + // The following has the effect of logging all taken SWIs and their return codes. + if( + (instruction & 0x0f00'0000) == 0x0f00'0000 && + executor.registers().test(InstructionSet::ARM::Condition(instruction >> 28)) + ) { + if(instruction & 0x2'0000) { + swis.emplace_back(); + swis.back().opcode = instruction; + swis.back().address = executor.pc(); + swis.back().return_address = executor.registers().pc(4); + for(int c = 0; c < 10; c++) swis.back().regs[c] = executor.registers()[uint32_t(c)]; + + // Possibly capture more detail. + // + // Cf. http://productsdb.riscos.com/support/developers/prm_index/numswilist.html + uint32_t pointer = 0; + switch(instruction & 0xfd'ffff) { + case 0x41501: + swis.back().swi_name = "MessageTrans_OpenFile"; + + // R0: pointer to file descriptor; R1: pointer to filename; R2: pointer to hold file data. + // (R0 and R1 are in the RMA if R2 = 0) + pointer = executor.registers()[1]; + break; + case 0x41502: + swis.back().swi_name = "MessageTrans_Lookup"; + break; + case 0x41506: + swis.back().swi_name = "MessageTrans_ErrorLookup"; + break; + + case 0x4028a: + swis.back().swi_name = "Podule_EnumerateChunksWithInfo"; + break; + + case 0x4000a: + swis.back().swi_name = "Econet_ReadLocalStationAndNet"; + break; + case 0x4000e: + swis.back().swi_name = "Econet_SetProtection"; + break; + case 0x40015: + swis.back().swi_name = "Econet_ClaimPort"; + break; + + case 0x40541: + swis.back().swi_name = "FileCore_Create"; + break; + + case 0x80156: + case 0x8015b: + swis.back().swi_name = "PDriver_MiscOpForDriver"; + break; + + case 0x05: + swis.back().swi_name = "OS_CLI"; + pointer = executor.registers()[0]; + break; + case 0x0d: + swis.back().swi_name = "OS_Find"; + if(executor.registers()[0] >= 0x40) { + pointer = executor.registers()[1]; + } + break; + case 0x1d: + swis.back().swi_name = "OS_Heap"; + break; + case 0x1e: + swis.back().swi_name = "OS_Module"; + break; + + case 0x20: + swis.back().swi_name = "OS_Release"; + break; + case 0x21: + swis.back().swi_name = "OS_ReadUnsigned"; + break; + case 0x23: + swis.back().swi_name = "OS_ReadVarVal"; + + // R0: pointer to variable name. + pointer = executor.registers()[0]; + break; + case 0x24: + swis.back().swi_name = "OS_SetVarVal"; + + // R0: pointer to variable name. + pointer = executor.registers()[0]; + break; + case 0x26: + swis.back().swi_name = "OS_GSRead"; + break; + case 0x27: + swis.back().swi_name = "OS_GSTrans"; + pointer = executor.registers()[0]; + break; + case 0x29: + swis.back().swi_name = "OS_FSControl"; + break; + case 0x2a: + swis.back().swi_name = "OS_ChangeDynamicArea"; + break; + + case 0x4c: + swis.back().swi_name = "OS_ReleaseDeviceVector"; + break; + + case 0x43057: + swis.back().swi_name = "Territory_LowerCaseTable"; + break; + case 0x43058: + swis.back().swi_name = "Territory_UpperCaseTable"; + break; + + case 0x42fc0: + swis.back().swi_name = "Portable_Speed"; + break; + case 0x42fc1: + swis.back().swi_name = "Portable_Control"; + break; + } + + if(pointer) { + while(true) { + uint8_t next; + executor.bus.template read(pointer, next, InstructionSet::ARM::Mode::Supervisor, false); + ++pointer; + + if(next < 32) break; + swis.back().value_name.push_back(static_cast(next)); + } + } + + } + + if(executor.registers().pc_status(0) & InstructionSet::ARM::ConditionCode::Overflow) { + logger.error().append("SWI called with V set"); + } + } + if(!swis.empty() && executor.pc() == swis.back().return_address) { + // Overflow set => SWI failure. + auto &back = swis.back(); + if(executor.registers().pc_status(0) & InstructionSet::ARM::ConditionCode::Overflow) { + auto info = logger.info(); + + info.append("failed swi "); + if(back.swi_name.empty()) { + info.append("&%x", back.opcode & 0xfd'ffff); + } else { + info.append("%s", back.swi_name.c_str()); + } + + if(!back.value_name.empty()) { + info.append(" %s", back.value_name.c_str()); + } + + info.append(" @ %08x ", back.address); + for(uint32_t c = 0; c < 10; c++) { + info.append("r%d:%08x ", c, back.regs[c]); + } + } + + swis.pop_back(); + } + + if(log) { + InstructionSet::ARM::Disassembler disassembler; + InstructionSet::ARM::dispatch(instruction, disassembler); + + auto info = logger.info(); + info.append("[%d] %08x: %08x\t\t%s\t prior:[", + instr_count, + executor.pc(), + instruction, + disassembler.last().to_string(executor.pc()).c_str()); + for(uint32_t c = 0; c < 15; c++) { + info.append("r%d:%08x ", c, executor.registers()[c]); + } + info.append("]"); + } + opcodes.insert(instruction); + if(accumulate) { + int c = 0; + for(auto instr : opcodes) { + printf("0x%08x, ", instr); + ++c; + if(!(c&15)) printf("\n"); + } + accumulate = false; + } + + ++instr_count; + } + +private: + std::array pc_history; + std::size_t pc_history_ptr = 0; + uint32_t instr_count = 0; + + struct SWICall { + uint32_t opcode; + uint32_t address; + uint32_t regs[10]; + uint32_t return_address; + std::string value_name; + std::string swi_name; + }; + std::vector swis; + uint32_t last_pc = 0; +// uint32_t last_r9 = 0; + bool log = false; + bool accumulate = true; + + std::set opcodes; +}; +#else +template +struct HackyDebugger { + void notify(uint32_t, uint32_t, Executor &) {} +}; +#endif + class ConcreteMachine: public Machine, public MachineTypes::MappedKeyboardMachine, @@ -127,12 +403,6 @@ class ConcreteMachine: return; } if(requests & InterruptRequests::IRQ) { -// logger.info().append("[%d] IRQ at %08x prior:[r13:%08x r14:%08x]", -// instr_count, -// executor_.pc(), -// executor_.registers()[13], -// executor_.registers()[14]); - executor_.registers().interrupt(); } } @@ -150,10 +420,6 @@ class ConcreteMachine: return executor_.bus.video().crt().get_scaled_scan_status(); } - std::array pc_history; - std::size_t pc_history_ptr = 0; - uint32_t instr_count = 0; - // MARK: - TimedMachine. void run_for(Cycles cycles) override { macro_counter_ += cycles.as(); @@ -170,275 +436,19 @@ class ConcreteMachine: } int video_divider_ = 1; - std::set opcodes; void tick_cpu() { - struct SWICall { - uint32_t opcode; - uint32_t address; - uint32_t regs[10]; - uint32_t return_address; - std::string value_name; - std::string swi_name; - }; - static std::vector swis; - static uint32_t last_pc = 0; -// static uint32_t last_r9 = 0; - static bool log = false; - static bool accumulate = true; - -// if(executor_.pc() == 0x03801ed8 || (executor_.registers()[9] == 0x00ff'0000 && executor_.registers()[9] != last_r9)) { -// printf("At %08x; after last PC %08x and %zu ago was %08x; r9 is %08x [%d]\n", -// executor_.pc(), -// pc_history[(pc_history_ptr - 2 + pc_history.size()) % pc_history.size()], -// pc_history.size(), -// pc_history[pc_history_ptr], -// executor_.registers()[9], -// executor_.registers()[9] != last_r9); -// } -// last_r9 = executor_.registers()[9]; - uint32_t instruction; - pc_history[pc_history_ptr] = executor_.pc(); - pc_history_ptr = (pc_history_ptr + 1) % pc_history.size(); if(!executor_.bus.read(executor_.pc(), instruction, executor_.registers().mode(), false)) { - logger.info().append("Prefetch abort at %08x; last good was at %08x", executor_.pc(), last_pc); +// logger.info().append("Prefetch abort at %08x; last good was at %08x", executor_.pc(), last_pc); executor_.prefetch_abort(); // TODO: does a double abort cause a reset? executor_.bus.read(executor_.pc(), instruction, executor_.registers().mode(), false); - } else { - last_pc = executor_.pc(); } // TODO: pipeline prefetch? -// log |= executor_.pc() == 0x03801ebc; -// log |= instr_count == 72766815; -// log &= executor_.pc() != 0x000000a0; - -// log = (executor_.pc() == 0x038162afc) || (executor_.pc() == 0x03824b00); -// log |= instruction & ; - - // The following has the effect of logging all taken SWIs and their return codes. - if( - (instruction & 0x0f00'0000) == 0x0f00'0000 && - executor_.registers().test(InstructionSet::ARM::Condition(instruction >> 28)) - ) { - if(instruction & 0x2'0000) { - swis.emplace_back(); - swis.back().opcode = instruction; - swis.back().address = executor_.pc(); - swis.back().return_address = executor_.registers().pc(4); - for(int c = 0; c < 10; c++) swis.back().regs[c] = executor_.registers()[uint32_t(c)]; - - // Possibly capture more detail. - // - // Cf. http://productsdb.riscos.com/support/developers/prm_index/numswilist.html - uint32_t pointer = 0; - switch(instruction & 0xfd'ffff) { - case 0x41501: - swis.back().swi_name = "MessageTrans_OpenFile"; - - // R0: pointer to file descriptor; R1: pointer to filename; R2: pointer to hold file data. - // (R0 and R1 are in the RMA if R2 = 0) - pointer = executor_.registers()[1]; - break; - case 0x41502: - swis.back().swi_name = "MessageTrans_Lookup"; - break; - case 0x41506: - swis.back().swi_name = "MessageTrans_ErrorLookup"; - break; - - case 0x4028a: - swis.back().swi_name = "Podule_EnumerateChunksWithInfo"; - break; - - case 0x4000a: - swis.back().swi_name = "Econet_ReadLocalStationAndNet"; - break; - case 0x4000e: - swis.back().swi_name = "Econet_SetProtection"; - break; - case 0x40015: - swis.back().swi_name = "Econet_ClaimPort"; - break; - - case 0x40541: - swis.back().swi_name = "FileCore_Create"; - break; - - case 0x80156: - case 0x8015b: - swis.back().swi_name = "PDriver_MiscOpForDriver"; - break; - - case 0x05: - swis.back().swi_name = "OS_CLI"; - pointer = executor_.registers()[0]; - break; - case 0x0d: - swis.back().swi_name = "OS_Find"; - if(executor_.registers()[0] >= 0x40) { - pointer = executor_.registers()[1]; - } - break; - case 0x1d: - swis.back().swi_name = "OS_Heap"; - break; - case 0x1e: - swis.back().swi_name = "OS_Module"; - break; - - case 0x20: - swis.back().swi_name = "OS_Release"; - break; - case 0x21: - swis.back().swi_name = "OS_ReadUnsigned"; - break; - case 0x23: - swis.back().swi_name = "OS_ReadVarVal"; - - // R0: pointer to variable name. - pointer = executor_.registers()[0]; - break; - case 0x24: - swis.back().swi_name = "OS_SetVarVal"; - - // R0: pointer to variable name. - pointer = executor_.registers()[0]; - break; - case 0x26: - swis.back().swi_name = "OS_GSRead"; - break; - case 0x27: - swis.back().swi_name = "OS_GSTrans"; - pointer = executor_.registers()[0]; - break; - case 0x29: - swis.back().swi_name = "OS_FSControl"; - break; - case 0x2a: - swis.back().swi_name = "OS_ChangeDynamicArea"; - break; - - case 0x4c: - swis.back().swi_name = "OS_ReleaseDeviceVector"; - break; - - case 0x43057: - swis.back().swi_name = "Territory_LowerCaseTable"; - break; - case 0x43058: - swis.back().swi_name = "Territory_UpperCaseTable"; - break; - - case 0x42fc0: - swis.back().swi_name = "Portable_Speed"; - break; - case 0x42fc1: - swis.back().swi_name = "Portable_Control"; - break; - } - - if(pointer) { - while(true) { - uint8_t next; - executor_.bus.template read(pointer, next, InstructionSet::ARM::Mode::Supervisor, false); - ++pointer; - - if(next < 32) break; - swis.back().value_name.push_back(static_cast(next)); - } - } - - } - - if(executor_.registers().pc_status(0) & InstructionSet::ARM::ConditionCode::Overflow) { - logger.error().append("SWI called with V set"); - } - } - if(!swis.empty() && executor_.pc() == swis.back().return_address) { - // Overflow set => SWI failure. - auto &back = swis.back(); - if(executor_.registers().pc_status(0) & InstructionSet::ARM::ConditionCode::Overflow) { - auto info = logger.info(); - - info.append("failed swi "); - if(back.swi_name.empty()) { - info.append("&%x", back.opcode & 0xfd'ffff); - } else { - info.append("%s", back.swi_name.c_str()); - } - - if(!back.value_name.empty()) { - info.append(" %s", back.value_name.c_str()); - } - - info.append(" @ %08x ", back.address); - for(uint32_t c = 0; c < 10; c++) { - info.append("r%d:%08x ", c, back.regs[c]); - } - } - - swis.pop_back(); - } - - if(log) { - InstructionSet::ARM::Disassembler disassembler; - InstructionSet::ARM::dispatch(instruction, disassembler); - - auto info = logger.info(); - info.append("[%d] %08x: %08x\t\t%s\t prior:[", - instr_count, - executor_.pc(), - instruction, - disassembler.last().to_string(executor_.pc()).c_str()); - for(uint32_t c = 0; c < 15; c++) { - info.append("r%d:%08x ", c, executor_.registers()[c]); - } - info.append("]"); - } - opcodes.insert(instruction); - if(accumulate) { - int c = 0; - for(auto instr : opcodes) { - printf("0x%08x, ", instr); - ++c; - if(!(c&15)) printf("\n"); - } - accumulate = false; - } -// logger.info().append("%08x: %08x", executor_.pc(), instruction); + debugger_.notify(executor_.pc(), instruction, executor_); InstructionSet::ARM::execute(instruction, executor_); - ++instr_count; - -// if( -// executor_.pc() > 0x038021d0 && -// last_r1 != executor_.registers()[1] -// || -// ( -// last_link != executor_.registers()[14] || -// last_r0 != executor_.registers()[0] || -// last_r10 != executor_.registers()[10] || -// last_r1 != executor_.registers()[1] -// ) -// ) { -// logger.info().append("%08x modified R14 to %08x; R0 to %08x; R10 to %08x; R1 to %08x", -// last_pc, -// executor_.registers()[14], -// executor_.registers()[0], -// executor_.registers()[10], -// executor_.registers()[1] -// ); -// logger.info().append("%08x modified R1 to %08x", -// last_pc, -// executor_.registers()[1] -// ); -// last_link = executor_.registers()[14]; -// last_r0 = executor_.registers()[0]; -// last_r10 = executor_.registers()[10]; -// last_r1 = executor_.registers()[1]; -// } } void tick_timers() { executor_.bus.tick_timers(); } @@ -476,7 +486,11 @@ class ConcreteMachine: // MARK: - ARM execution static constexpr auto arm_model = InstructionSet::ARM::Model::ARMv2; - InstructionSet::ARM::Executor> executor_; + using Executor = InstructionSet::ARM::Executor>; + Executor executor_; + + // MARK: - Yucky, temporary junk. + HackyDebugger debugger_; }; }