mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-20 14:29:11 +00:00
Begin foray into disassembly.
This commit is contained in:
parent
9d858bc61b
commit
2ad6bb099b
119
InstructionSets/ARM/Disassembler.hpp
Normal file
119
InstructionSets/ARM/Disassembler.hpp
Normal file
@ -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 <string>
|
||||
#include <sstream>
|
||||
|
||||
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 <Model model>
|
||||
struct Disassembler {
|
||||
Instruction last() {
|
||||
return instruction_;
|
||||
}
|
||||
|
||||
bool should_schedule(Condition condition) {
|
||||
instruction_.condition = condition;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <Flags> void perform(DataProcessing) {}
|
||||
template <Flags> void perform(Multiply) {}
|
||||
template <Flags> void perform(SingleDataTransfer) {}
|
||||
template <Flags> void perform(BlockDataTransfer) {}
|
||||
template <Flags> void perform(Branch) {}
|
||||
template <Flags> void perform(CoprocessorRegisterTransfer) {}
|
||||
template <Flags> void perform(CoprocessorDataOperation) {}
|
||||
template <Flags> void perform(CoprocessorDataTransfer) {}
|
||||
|
||||
void software_interrupt() {
|
||||
instruction_.operation = Instruction::Operation::SWI;
|
||||
}
|
||||
void unknown() {
|
||||
instruction_.operation = Instruction::Operation::Undefined;
|
||||
}
|
||||
|
||||
private:
|
||||
Instruction instruction_;
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -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<uint32_t, 10> 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<int>();
|
||||
|
||||
@ -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<arm_model> disassembler;
|
||||
InstructionSet::ARM::dispatch<arm_model>(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;
|
||||
|
||||
|
@ -1807,6 +1807,7 @@
|
||||
4BA91E1C216D85BA00F79557 /* MasterSystemVDPTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MasterSystemVDPTests.mm; sourceTree = "<group>"; };
|
||||
4BA9C3CF1D8164A9002DDB61 /* MediaTarget.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MediaTarget.hpp; sourceTree = "<group>"; };
|
||||
4BAA167B21582B1D008A3276 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = "<group>"; };
|
||||
4BAB1E522BA9D9950002C9B9 /* Disassembler.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Disassembler.hpp; sourceTree = "<group>"; };
|
||||
4BAB62AC1D3272D200DF5BA0 /* Disk.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Disk.hpp; sourceTree = "<group>"; };
|
||||
4BAB62AE1D32730D00DF5BA0 /* Storage.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Storage.hpp; sourceTree = "<group>"; };
|
||||
4BAF2B4C2004580C00480230 /* DMK.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DMK.cpp; sourceTree = "<group>"; };
|
||||
@ -2776,6 +2777,7 @@
|
||||
4B2005482B92697500420C5C /* Executor.hpp */,
|
||||
4B2005402B804AA300420C5C /* OperationMapper.hpp */,
|
||||
4B2005462B8BD7A500420C5C /* Registers.hpp */,
|
||||
4BAB1E522BA9D9950002C9B9 /* Disassembler.hpp */,
|
||||
);
|
||||
path = ARM;
|
||||
sourceTree = "<group>";
|
||||
|
@ -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;
|
||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user