diff --git a/InstructionSets/ARM/Disassembler.hpp b/InstructionSets/ARM/Disassembler.hpp index 395cd1825..6f744e426 100644 --- a/InstructionSets/ARM/Disassembler.hpp +++ b/InstructionSets/ARM/Disassembler.hpp @@ -28,6 +28,22 @@ struct Operand { switch(type) { default: return ""; case Type::Register: return std::string("r") + std::to_string(value); + case Type::RegisterList: { + std::stringstream stream; + stream << '['; + bool first = true; + for(int c = 0; c < 16; c++) { + if(value & (1 << c)) { + if(!first) stream << ", "; + first = false; + + stream << 'r' << c; + } + } + stream << ']'; + + return stream.str(); + } } } }; @@ -43,16 +59,20 @@ struct Instruction { ORR, MOV, BIC, MVN, LDR, STR, + LDM, STM, B, BL, SWI, + MRC, MCR, + Undefined, } operation = Operation::Undefined; Operand destination, operand1, operand2; bool sets_flags = false; + bool is_byte = false; std::string to_string(uint32_t address) const { std::ostringstream result; @@ -89,6 +109,11 @@ struct Instruction { case Operation::LDR: result << "ldr"; break; case Operation::STR: result << "str"; break; + case Operation::LDM: result << "ldm"; break; + case Operation::STM: result << "stm"; break; + + case Operation::MRC: result << "mrc"; break; + case Operation::MCR: result << "mcr"; break; } // Append the sets-flags modifier if applicable. @@ -118,10 +143,14 @@ struct Instruction { result << " 0x" << std::hex << ((address + 8 + operand1.value) & 0x3fffffc); } - if(operation == Operation::LDR || operation == Operation::STR) { + if( + operation == Operation::LDR || operation == Operation::STR || + operation == Operation::LDM || operation == Operation::STM + ) { + if(is_byte) result << 'b'; result << ' ' << static_cast(destination); result << ", [" << static_cast(operand1) << "]"; - // TODO: learn how ARM shifts/etc are normally represented. + // TODO: learn how ARM shifts/etc are normally presented. } return result.str(); @@ -197,7 +226,18 @@ struct Disassembler { instruction_.operand1.type = Operand::Type::Register; instruction_.operand1.value = fields.base(); } - template void perform(BlockDataTransfer) {} + template void perform(BlockDataTransfer fields) { + constexpr BlockDataTransferFlags flags(f); + instruction_.operation = + (flags.operation() == BlockDataTransferFlags::Operation::STM) ? + Instruction::Operation::STM : Instruction::Operation::LDM; + + instruction_.destination.type = Operand::Type::Register; + instruction_.destination.value = fields.base(); + + instruction_.operand1.type = Operand::Type::RegisterList; + instruction_.operand1.value = fields.register_list(); + } template void perform(Branch fields) { constexpr BranchFlags flags(f); instruction_.operation = @@ -206,7 +246,12 @@ struct Disassembler { instruction_.operand1.type = Operand::Type::Immediate; instruction_.operand1.value = fields.offset(); } - template void perform(CoprocessorRegisterTransfer) {} + template void perform(CoprocessorRegisterTransfer) { + constexpr CoprocessorRegisterTransferFlags flags(f); + instruction_.operation = + (flags.operation() == CoprocessorRegisterTransferFlags::Operation::MRC) ? + Instruction::Operation::MRC : Instruction::Operation::MCR; + } template void perform(CoprocessorDataOperation) {} template void perform(CoprocessorDataTransfer) {} diff --git a/InstructionSets/ARM/Executor.hpp b/InstructionSets/ARM/Executor.hpp index 95d49866c..40586a507 100644 --- a/InstructionSets/ARM/Executor.hpp +++ b/InstructionSets/ARM/Executor.hpp @@ -295,6 +295,18 @@ struct Executor { return; } + // Decide whether to write back — when either postindexing or else write back is requested. + constexpr bool should_write_back = !flags.pre_index() || flags.write_back_address(); + + // STR: update prior to write. +// if constexpr (should_write_back && flags.operation() == SingleDataTransferFlags::Operation::STR) { +// if(transfer.base() == 15) { +// registers_.set_pc(offsetted_address); +// } else { +// registers_[transfer.base()] = offsetted_address; +// } +// } + // "... post-indexed data transfers always write back the modified base. The only use of the [write-back address] // bit in a post-indexed data transfer is in non-user mode code, where setting the W bit forces the /TRANS pin // to go LOW for the transfer" @@ -355,8 +367,11 @@ struct Executor { } } - // If either postindexing or else with writeback, update base. - if constexpr (!flags.pre_index() || flags.write_back_address()) { + // LDR: write back after load, only if original wasn't overwritten. +// if constexpr (should_write_back && flags.operation() == SingleDataTransferFlags::Operation::LDR) { +// if(transfer.base() != transfer.destination()) { + + if constexpr (should_write_back) { // Empirically: I think writeback occurs before the access, so shouldn't overwrite on a load. if(flags.operation() == SingleDataTransferFlags::Operation::STR || transfer.base() != transfer.destination()) { if(transfer.base() == 15) { diff --git a/Machines/Acorn/Archimedes/CMOSRAM.hpp b/Machines/Acorn/Archimedes/CMOSRAM.hpp index 61117c4b2..8e89b0312 100644 --- a/Machines/Acorn/Archimedes/CMOSRAM.hpp +++ b/Machines/Acorn/Archimedes/CMOSRAM.hpp @@ -26,7 +26,7 @@ struct CMOSRAM: public I2C::Peripheral { 0x00, 0x00, 0x03, 0x14, 0x00, 0x6f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, - 0x00, 0xfe, 0x00, 0xeb, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x10, 0x50, 0x20, 0x08, 0x0a, 0x2c, + 0x01, 0xfe, 0x00, 0xeb, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x10, 0x50, 0x20, 0x08, 0x0a, 0x2c, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -43,7 +43,7 @@ struct CMOSRAM: public I2C::Peripheral { const uint8_t result = defaults[address_]; ++address_; - return result; + return 0;//result; } bool write(uint8_t value) override { diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme index 474fa352e..19b54b90e 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme +++ b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme @@ -62,7 +62,7 @@ > regs[c]; } - switch(opcode) { - case 0xe090e00f: - // adds lr, r0, pc - // The test set comes from an ARM that doesn't multiplex flags - // and the PC. - masks[15] = 0; - regs[15] &= 0x03ff'fffc; - break; - - case 0xee100f10: - case 0xee105f10: - case 0xee502110: - // MRCs; tests seem possibly to have a coprocessor? - ignore_test = true; - break; - - // TODO: - // * adds to R15: e090f00e, e090f00f; possibly to do with non-multiplexing original? - // * movs to PC: e1b0f00e; as above? - - default: break; - } - if(!test) test = std::make_unique(); auto ®isters = test->registers(); if(label == "Before:") {