1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-20 14:29:11 +00:00

Start making leeway on interesting SWIs.

This commit is contained in:
Thomas Harte 2024-05-06 22:40:00 -04:00
parent 02ee3a7804
commit 6d42c9aaf9
3 changed files with 194 additions and 108 deletions

View File

@ -8,60 +8,109 @@
#include "SWIIndex.hpp"
#include <cstdio>
#include <set>
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<uint32_t> 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<uint8_t>(pointer, next, InstructionSet::ARM::Mode::Supervisor, false);
++pointer;
if(next < 32) break;
swis.back().value_name.push_back(static_cast<char>(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();
}*/

View File

@ -9,15 +9,44 @@
#ifndef SWIIndex_hpp
#define SWIIndex_hpp
#include <array>
#include <cstdint>
#include <string>
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<Register, 14> registers;
};
}

View File

@ -34,6 +34,8 @@
#include <set>
#include <vector>
#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<char>(next));
++address;
}
return desc;
};
switch(comment & static_cast<uint32_t>(~(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);