diff --git a/Analyser/Static/Acorn/SWIIndex.cpp b/Analyser/Static/Acorn/SWIIndex.cpp index a61178b76..7fc085882 100644 --- a/Analyser/Static/Acorn/SWIIndex.cpp +++ b/Analyser/Static/Acorn/SWIIndex.cpp @@ -8,60 +8,109 @@ #include "SWIIndex.hpp" +#include +#include + using namespace Analyser::Static::Acorn; -const SWIDescription &Analyser::Static::Acorn::describe_swi(uint32_t comment) { - static SWIDescription none; +SWIDescription::SWIDescription(uint32_t comment) { + chunk_offset = comment & 0b111111; + chunk_number = (comment >> 6) & 0b11111111111; + error_flag = comment & (1 << 17); + swi_group = SWIGroup((comment >> 18) & 0b11); + os_flag = (comment >> 20) & 0b1111; - (void)comment; - return none; + static std::set encountered; + + const uint32_t number = comment & uint32_t(~(1 << 17)); + switch(number) { + case 0x00: + name = "OS_WriteC"; + registers[0].type = Register::Type::Character; + break; + case 0x01: + name = "OS_WriteS"; + registers[0].type = Register::Type::FollowingString; + break; + case 0x02: + name = "OS_Write0"; + registers[0].type = Register::Type::PointerToString; + break; + case 0x03: + name = "OS_NewLine"; + break; + case 0x04: + name = "OS_ReadC"; + break; + case 0x05: + name = "OS_CLI"; + registers[0].type = Register::Type::PointerToString; + break; + case 0x06: + name = "OS_Byte"; + registers[0].type = Register::Type::ReasonCode; + registers[1].type = Register::Type::ReasonCodeDependent; + registers[2].type = Register::Type::ReasonCodeDependent; + break; + case 0x07: + name = "OS_Word"; + registers[0].type = Register::Type::ReasonCode; + registers[1].type = Register::Type::Pointer; + break; + case 0x08: + name = "OS_File"; + registers[0].type = Register::Type::ReasonCode; + break; + case 0x09: + name = "OS_Args"; + registers[0].type = Register::Type::ReasonCode; + registers[1].type = Register::Type::Pointer; + registers[2].type = Register::Type::ReasonCodeDependent; + break; + case 0x0c: + name = "OS_GBPB"; + registers[0].type = Register::Type::ReasonCode; + break; + case 0x0d: + name = "OS_Find"; + registers[0].type = Register::Type::ReasonCode; + break; + case 0x0f: + name = "OS_Control"; + registers[0].type = Register::Type::Pointer; + registers[1].type = Register::Type::Pointer; + registers[2].type = Register::Type::Pointer; + registers[3].type = Register::Type::Pointer; + break; + case 0x1d: + name = "OS_Heap"; + registers[0].type = Register::Type::ReasonCode; + registers[1].type = Register::Type::Pointer; + registers[2].type = Register::Type::Pointer; + registers[3].type = Register::Type::ReasonCodeDependent; + break; + case 0x3a: + name = "OS_ValidateAddress"; + registers[0].type = Register::Type::Pointer; + registers[1].type = Register::Type::Pointer; + break; + + case 0x400e2: + name = "Wimp_PlotIcon"; + registers[1].type = Register::Type::Pointer; + break; + + + default: + if(encountered.find(number) == encountered.end()) { + encountered.insert(number); + printf("SWI: %08x\n", number); + } + break; + } } -// 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( @@ -118,19 +167,6 @@ const SWIDescription &Analyser::Static::Acorn::describe_swi(uint32_t comment) { 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; @@ -186,45 +222,5 @@ const SWIDescription &Analyser::Static::Acorn::describe_swi(uint32_t comment) { 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 index 524d6a16e..06b865539 100644 --- a/Analyser/Static/Acorn/SWIIndex.hpp +++ b/Analyser/Static/Acorn/SWIIndex.hpp @@ -9,15 +9,44 @@ #ifndef SWIIndex_hpp #define SWIIndex_hpp +#include #include +#include namespace Analyser::Static::Acorn { -struct SWIDescription { - +enum class SWIGroup: uint8_t { + OperatingSystem = 0b00, + OperatingSystemModules = 0b01, + ThirdPartyApplications = 0b10, + UserApplications = 0b11, }; -const SWIDescription &describe_swi(uint32_t comment); +struct SWIDescription { + SWIDescription(uint32_t comment); + + uint8_t chunk_offset; + SWIGroup swi_group; + uint16_t chunk_number; + uint8_t os_flag; + bool error_flag; + + std::string name; + struct Register { + enum class Type { + Unused, + ReasonCode, + Pointer, + PointerToString, + ReasonCodeDependent, + Character, + + /// A string that appears immediately after the SWI in memory. + FollowingString, + } type = Type::Unused; + }; + std::array registers; +}; } diff --git a/Machines/Acorn/Archimedes/Archimedes.cpp b/Machines/Acorn/Archimedes/Archimedes.cpp index 58a538d65..b979d3cde 100644 --- a/Machines/Acorn/Archimedes/Archimedes.cpp +++ b/Machines/Acorn/Archimedes/Archimedes.cpp @@ -34,6 +34,8 @@ #include #include +#include "../../../Analyser/Static/Acorn/SWIIndex.hpp" + namespace Archimedes { class ConcreteMachine: @@ -149,13 +151,72 @@ class ConcreteMachine: fill_pipeline(executor_.pc()); } - bool should_swi(uint32_t) { + bool should_swi(uint32_t comment) { using Exception = InstructionSet::ARM::Registers::Exception; using SWISubversion = Pipeline::SWISubversion; switch(pipeline_.swi_subversion()) { - case Pipeline::SWISubversion::None: - return true; + case Pipeline::SWISubversion::None: { + [[maybe_unused]] Analyser::Static::Acorn::SWIDescription description(comment); + + // TODO: 400C1 to intercept create window 400C1 and positioning; then + // plot icon 400e2 to listen for icons in window. That'll give a click area. + // Probably also 400c2 which seems to be used to add icons to the icon bar. + // + // 400D4 for menus? + + const auto get_string = [&](uint32_t address, bool indirect) -> std::string { + std::string desc; + if(indirect) { + executor_.bus.read(address, address, false); + } + while(true) { + uint8_t next; + executor_.bus.read(address, next, false); + if(next < 0x20) break; + desc.push_back(static_cast(next)); + ++address; + } + return desc; + }; + + switch(comment & static_cast(~(1 << 17))) { + case 0x400d4: { + uint32_t address = executor_.registers()[1] + 28; + + printf("Menu:\n"); + while(true) { + uint32_t icon_flags; + uint32_t item_flags; + executor_.bus.read(address, item_flags, false); + executor_.bus.read(address + 8, icon_flags, false); + auto desc = get_string(address + 12, icon_flags & (1 << 8)); + printf("%s\n", desc.c_str()); + address += 24; + if(item_flags & (1 << 7)) break; + } + } break; + +// case 0x400c2: + case 0x400e2: { + // Wimp_PlotIcon; try to determine what's on-screen next. + const uint32_t address = executor_.registers()[1]; + uint32_t x1, y1, x2, y2, flags; + executor_.bus.read(address + 0, x1, false); + executor_.bus.read(address + 4, y1, false); + executor_.bus.read(address + 8, x2, false); + executor_.bus.read(address + 12, y2, false); + executor_.bus.read(address + 16, flags, false); + + std::string desc; + if(flags & 1) { + desc = get_string(address + 20, flags & (1 << 8)); + } + + printf("Wimp_PlotIcon: %d, %d -> %d, %d; flags %08x; icon data: %s\n", x1, y1, x2, y2, flags, desc.c_str()); + } break; + } + } return true; case SWISubversion::DataAbort: // executor_.set_pc(executor_.pc() - 4);