diff --git a/Analyser/Static/Acorn/SWIIndex.cpp b/Analyser/Static/Acorn/SWIIndex.cpp new file mode 100644 index 000000000..a61178b76 --- /dev/null +++ b/Analyser/Static/Acorn/SWIIndex.cpp @@ -0,0 +1,230 @@ +// +// SWIIndex.cpp +// Clock Signal +// +// Created by Thomas Harte on 05/05/2024. +// Copyright © 2024 Thomas Harte. All rights reserved. +// + +#include "SWIIndex.hpp" + +using namespace Analyser::Static::Acorn; + +const SWIDescription &Analyser::Static::Acorn::describe_swi(uint32_t comment) { + static SWIDescription none; + + (void)comment; + return none; +} + + +// 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(instruction == 0xe8fd7fff) { +// printf("At %08x [%d]; after last PC %08x and %zu ago was %08x\n", +// address, +// instr_count, +// pc_history[(pc_history_ptr - 2 + pc_history.size()) % pc_history.size()], +// pc_history.size(), +// pc_history[pc_history_ptr]); +// } +// last_r9 = executor_.registers()[9]; + +// log |= address == 0x038031c4; +// log |= instr_count == 53552731 - 30; +// 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().count = swi_count++; + 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("[%d] Failed swi ", back.count); + 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(); + }*/ diff --git a/Analyser/Static/Acorn/SWIIndex.hpp b/Analyser/Static/Acorn/SWIIndex.hpp new file mode 100644 index 000000000..524d6a16e --- /dev/null +++ b/Analyser/Static/Acorn/SWIIndex.hpp @@ -0,0 +1,24 @@ +// +// SWIIndex.hpp +// Clock Signal +// +// Created by Thomas Harte on 05/05/2024. +// Copyright © 2024 Thomas Harte. All rights reserved. +// + +#ifndef SWIIndex_hpp +#define SWIIndex_hpp + +#include + +namespace Analyser::Static::Acorn { + +struct SWIDescription { + +}; + +const SWIDescription &describe_swi(uint32_t comment); + +} + +#endif /* SWIIndex_hpp */ diff --git a/Machines/Acorn/Archimedes/Archimedes.cpp b/Machines/Acorn/Archimedes/Archimedes.cpp index 5c1300779..58a538d65 100644 --- a/Machines/Acorn/Archimedes/Archimedes.cpp +++ b/Machines/Acorn/Archimedes/Archimedes.cpp @@ -36,287 +36,6 @@ namespace Archimedes { -#ifndef NDEBUG -namespace { -Log::Logger logger; -} - -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(instruction == 0xe8fd7fff) { -// printf("At %08x [%d]; after last PC %08x and %zu ago was %08x\n", -// address, -// instr_count, -// pc_history[(pc_history_ptr - 2 + pc_history.size()) % pc_history.size()], -// pc_history.size(), -// pc_history[pc_history_ptr]); -// } -// last_r9 = executor_.registers()[9]; - -// log |= address == 0x038031c4; -// log |= instr_count == 53552731 - 30; -// 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().count = swi_count++; - 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("[%d] Failed swi ", back.count); - 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; - uint32_t swi_count = 0; - - struct SWICall { - uint32_t count; - 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::AudioProducer, @@ -328,7 +47,9 @@ class ConcreteMachine: public Activity::Source { private: - // TODO: pick a sensible clock rate; this is just code for '24 MIPS, please'. + Log::Logger logger; + + // This fictitious clock rate just means '24 MIPS, please'; it's divided elsewhere. static constexpr int ClockRate = 24'000'000; // Runs for 24 cycles, distributing calls to the various ticking subsystems @@ -504,7 +225,6 @@ class ConcreteMachine: void tick_cpu() { const uint32_t instruction = advance_pipeline(executor_.pc() + 8); - debugger_.notify(executor_.pc(), instruction, executor_); InstructionSet::ARM::execute(instruction, executor_); } @@ -622,9 +342,6 @@ class ConcreteMachine: SWISubversion latched_subversion_; } pipeline_; - - // MARK: - Yucky, temporary junk. - HackyDebugger debugger_; }; } diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 4309b3eb1..c535f85e5 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -971,6 +971,8 @@ 4BB505862B9634F30031C43C /* Archimedes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB505842B9634F30031C43C /* Archimedes.cpp */; }; 4BB505872B9634F30031C43C /* Archimedes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB505842B9634F30031C43C /* Archimedes.cpp */; }; 4BB505892B9C0E6F0031C43C /* Messy ARM in Resources */ = {isa = PBXBuildFile; fileRef = 4BB505882B9C0E6F0031C43C /* Messy ARM */; }; + 4BB508672BE816E8000ACC9F /* SWIIndex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB508652BE816E8000ACC9F /* SWIIndex.cpp */; }; + 4BB508682BE816E8000ACC9F /* SWIIndex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB508652BE816E8000ACC9F /* SWIIndex.cpp */; }; 4BB697CB1D4B6D3E00248BDF /* TimedEventLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697C91D4B6D3E00248BDF /* TimedEventLoop.cpp */; }; 4BB697CE1D4BA44400248BDF /* CommodoreGCR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697CC1D4BA44400248BDF /* CommodoreGCR.cpp */; }; 4BB73EA21B587A5100552FC2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB73EA11B587A5100552FC2 /* AppDelegate.swift */; }; @@ -2122,6 +2124,8 @@ 4BB505842B9634F30031C43C /* Archimedes.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Archimedes.cpp; sourceTree = ""; }; 4BB505852B9634F30031C43C /* Archimedes.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Archimedes.hpp; sourceTree = ""; }; 4BB505882B9C0E6F0031C43C /* Messy ARM */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "Messy ARM"; sourceTree = ""; }; + 4BB508652BE816E8000ACC9F /* SWIIndex.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SWIIndex.cpp; sourceTree = ""; }; + 4BB508662BE816E8000ACC9F /* SWIIndex.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SWIIndex.hpp; sourceTree = ""; }; 4BB5B995281B1D3E00522DA9 /* RegisterSizes.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = RegisterSizes.hpp; sourceTree = ""; }; 4BB5B996281B1E3F00522DA9 /* Perform.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Perform.hpp; sourceTree = ""; }; 4BB5B997281B1F7B00522DA9 /* Status.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Status.hpp; sourceTree = ""; }; @@ -3685,6 +3689,8 @@ 4B8944ED201967B4007DE474 /* StaticAnalyser.hpp */, 4B8944EF201967B4007DE474 /* Tape.hpp */, 4BE32313205327D7006EF799 /* Target.hpp */, + 4BB508652BE816E8000ACC9F /* SWIIndex.cpp */, + 4BB508662BE816E8000ACC9F /* SWIIndex.hpp */, ); path = Acorn; sourceTree = ""; @@ -5927,6 +5933,7 @@ 4B055AED1FAE9BA20060FFFF /* Z80Storage.cpp in Sources */, 4B1B88BC202E2EC100B67DFF /* MultiKeyboardMachine.cpp in Sources */, 4BC890D4230F86020025A55A /* DirectAccessDevice.cpp in Sources */, + 4BB508682BE816E8000ACC9F /* SWIIndex.cpp in Sources */, 4B2E86C925D892EF0024F1E9 /* DAT.cpp in Sources */, 4B6AAEAE230E40250078E864 /* Target.cpp in Sources */, 4BF437EF209D0F7E008CBD6B /* SegmentParser.cpp in Sources */, @@ -6293,6 +6300,7 @@ 4BDB61EB2032806E0048AF91 /* CSAtari2600.mm in Sources */, 4BFDD78C1F7F2DB4008579B9 /* ImplicitSectors.cpp in Sources */, 4B894526201967B4007DE474 /* StaticAnalyser.cpp in Sources */, + 4BB508672BE816E8000ACC9F /* SWIIndex.cpp in Sources */, 4BEE0A6F1D72496600532C7B /* Cartridge.cpp in Sources */, 4B051CB62680158600CA44E8 /* EXDos.cpp in Sources */, 4BB505782B962DDF0031C43C /* SoundGenerator.cpp in Sources */,