diff --git a/InstructionSets/ARM/Disassembler.hpp b/InstructionSets/ARM/Disassembler.hpp new file mode 100644 index 000000000..845edbf7f --- /dev/null +++ b/InstructionSets/ARM/Disassembler.hpp @@ -0,0 +1,119 @@ +// +// Disassembler.hpp +// Clock Signal +// +// Created by Thomas Harte on 19/03/2024. +// Copyright © 2024 Thomas Harte. All rights reserved. +// + +#pragma once + +#include "OperationMapper.hpp" + +#include +#include + +namespace InstructionSet::ARM { + +struct Operand { + enum class Type { + Immediate, Register, RegisterList, + } type = Type::Immediate; + uint32_t value = 0; + + // TODO: encode shifting + + operator std::string() const { + return ""; + } +}; + +struct Instruction { + Condition condition; + enum class Operation { + AND, EOR, SUB, RSB, + ADD, ADC, SBC, RSC, + TST, TEQ, CMP, CMN, + ORR, MOV, BIC, MVN, + + B, BL, + + SWI, + + Undefined, + } operation = Operation::Undefined; + + Operand destination, operand1, operand2; + + std::string to_string(uint32_t address) const { + std::string result; + + // Print operation. + switch(operation) { + case Operation::Undefined: return "undefined"; + case Operation::SWI: return "swi"; + + case Operation::B: result += "b"; break; + case Operation::BL: result += "bl"; break; + + case Operation::AND: result += "and"; break; + case Operation::EOR: result += "eor"; break; + case Operation::SUB: result += "sub"; break; + case Operation::RSB: result += "rsb"; break; + case Operation::ADD: result += "add"; break; + case Operation::ADC: result += "adc"; break; + case Operation::SBC: result += "sbc"; break; + case Operation::RSC: result += "rsc"; break; + case Operation::TST: result += "tst"; break; + case Operation::TEQ: result += "teq"; break; + case Operation::CMP: result += "cmp"; break; + case Operation::CMN: result += "cmn"; break; + case Operation::ORR: result += "orr"; break; + case Operation::MOV: result += "mov"; break; + case Operation::BIC: result += "bic"; break; + case Operation::MVN: result += "mvn"; break; + } + + // If this is a branch, append the target and complete. + if(operation == Operation::B || operation == Operation::BL) { + result += " "; + + } + + return result; + } +}; + +template +struct Disassembler { + Instruction last() { + return instruction_; + } + + bool should_schedule(Condition condition) { + instruction_.condition = condition; + return true; + } + + template void perform(DataProcessing) {} + template void perform(Multiply) {} + template void perform(SingleDataTransfer) {} + template void perform(BlockDataTransfer) {} + template void perform(Branch) {} + template void perform(CoprocessorRegisterTransfer) {} + template void perform(CoprocessorDataOperation) {} + template void perform(CoprocessorDataTransfer) {} + + void software_interrupt() { + instruction_.operation = Instruction::Operation::SWI; + } + void unknown() { + instruction_.operation = Instruction::Operation::Undefined; + } + +private: + Instruction instruction_; + +}; + +} diff --git a/Machines/Acorn/Archimedes/Archimedes.cpp b/Machines/Acorn/Archimedes/Archimedes.cpp index 1a1fb5e36..1b288924f 100644 --- a/Machines/Acorn/Archimedes/Archimedes.cpp +++ b/Machines/Acorn/Archimedes/Archimedes.cpp @@ -14,6 +14,7 @@ #include "../../ScanProducer.hpp" #include "../../TimedMachine.hpp" +#include "../../../InstructionSets/ARM/Disassembler.hpp" #include "../../../InstructionSets/ARM/Executor.hpp" #include "../../../Outputs/Log.hpp" #include "../../../Components/I2C/I2C.hpp" @@ -1043,9 +1044,14 @@ class ConcreteMachine: return Outputs::Display::ScanStatus(); } + std::array pc_history; + std::size_t pc_history_ptr = 0; + uint32_t instr_count = 0; + // MARK: - TimedMachine. void run_for(Cycles cycles) override { static uint32_t last_pc = 0; + static bool log = true; auto instructions = cycles.as(); @@ -1055,11 +1061,10 @@ class ConcreteMachine: timer_divider_ -= run_length; while(run_length--) { - if(executor_.pc() == 0x0207b3bc) { - printf("At %08x after last PC %08x\n", executor_.pc(), last_pc); - } - uint32_t instruction; + pc_history[pc_history_ptr] = executor_.pc(); + pc_history_ptr = (pc_history_ptr + 1) % pc_history.size(); +// pc_history.push_back(executor_.pc()); 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); executor_.prefetch_abort(); @@ -1071,13 +1076,17 @@ class ConcreteMachine: } // TODO: pipeline prefetch? - static bool log = false; +// if(executor_.pc() == 0x03803194 || !instruction || instruction == 0xe49aa000) { +// printf("At %08x; after last PC %08x and %zu ago was %08x\n", executor_.pc(), pc_history[(pc_history_ptr - 2 + pc_history.size()) % pc_history.size()], pc_history.size(), pc_history[pc_history_ptr]); +// } +// log |= executor_.registers()[12] == 0xe59ff114; // log |= (executor_.pc() > 0x02000000 && executor_.pc() < 0x02000078); - log |= executor_.pc() == 0x0207b3bc; //0x397af9c +// log |= executor_.pc() == 0x0380ff4c; //0x397af9c // log = executor_.pc() == 0x0381202c; // log |= (executor_.pc() > 0x03801000); // log &= executor_.pc() != 0x03801a0c; +// log |= instr_count == 71259670 - 50; // if(executor_.pc() == 0x02000078) { // if(!all.empty()) { @@ -1093,8 +1102,15 @@ class ConcreteMachine: // } if(log) { + InstructionSet::ARM::Disassembler disassembler; + InstructionSet::ARM::dispatch(instruction, disassembler); + auto info = logger.info(); - info.append("%08x: %08x prior:[", executor_.pc(), instruction); + 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]); } @@ -1102,6 +1118,7 @@ class ConcreteMachine: } // logger.info().append("%08x: %08x", executor_.pc(), instruction); InstructionSet::ARM::execute(instruction, executor_); + ++instr_count; // if( // executor_.pc() > 0x038021d0 && @@ -1132,6 +1149,10 @@ class ConcreteMachine: // } } + if(log) { + printf(""); + } + if(!timer_divider_) { timer_divider_ = TimerTarget; diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 4b5bfcbf4..f74c8fc91 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -1807,6 +1807,7 @@ 4BA91E1C216D85BA00F79557 /* MasterSystemVDPTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MasterSystemVDPTests.mm; sourceTree = ""; }; 4BA9C3CF1D8164A9002DDB61 /* MediaTarget.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MediaTarget.hpp; sourceTree = ""; }; 4BAA167B21582B1D008A3276 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = ""; }; + 4BAB1E522BA9D9950002C9B9 /* Disassembler.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Disassembler.hpp; sourceTree = ""; }; 4BAB62AC1D3272D200DF5BA0 /* Disk.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Disk.hpp; sourceTree = ""; }; 4BAB62AE1D32730D00DF5BA0 /* Storage.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Storage.hpp; sourceTree = ""; }; 4BAF2B4C2004580C00480230 /* DMK.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DMK.cpp; sourceTree = ""; }; @@ -2776,6 +2777,7 @@ 4B2005482B92697500420C5C /* Executor.hpp */, 4B2005402B804AA300420C5C /* OperationMapper.hpp */, 4B2005462B8BD7A500420C5C /* Registers.hpp */, + 4BAB1E522BA9D9950002C9B9 /* Disassembler.hpp */, ); path = ARM; sourceTree = ""; diff --git a/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm b/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm index 644dcd8ce..e5b9e80b6 100644 --- a/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm +++ b/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm @@ -425,9 +425,9 @@ struct MemoryLedger { continue; } -// if(instruction == 0xe1a0f001 && test_count == 1) { -// printf(""); -// } + if(instruction == 0xe79ea10a && test_count == 1) { + printf(""); + } execute(instruction, *test); NSMutableString *error = nil; diff --git a/OSBindings/Mac/Clock SignalTests/Messy ARM/test.txt.gz b/OSBindings/Mac/Clock SignalTests/Messy ARM/test.txt.gz index 55a29e720..a76b99938 100644 Binary files a/OSBindings/Mac/Clock SignalTests/Messy ARM/test.txt.gz and b/OSBindings/Mac/Clock SignalTests/Messy ARM/test.txt.gz differ