1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-23 21:29:11 +00:00

Make an effort to withdraw from the high-circuitous stuff of working around the reset sequence.

This commit is contained in:
Thomas Harte 2022-05-25 20:22:38 -04:00
parent 367ad8079a
commit 866787c5d3
6 changed files with 55 additions and 106 deletions

View File

@ -741,10 +741,10 @@
@end @end
@implementation M68000DIVSTests @implementation M68000DIVSTests
- (void)performDIVS:(uint16_t)divisor d1:(uint32_t)d1 { - (void)performDIVS:(uint16_t)divisor d1:(uint32_t)d1 sp:(uint32_t)sp {
self.machine->set_program({ self.machine->set_program({
0x83fc, divisor // DIVS #divisor, D1 0x83fc, divisor // DIVS #divisor, D1
}); }, sp);
auto state = self.machine->get_processor_state(); auto state = self.machine->get_processor_state();
state.registers.data[1] = d1; state.registers.data[1] = d1;
state.registers.status |= ConditionCode::AllConditions; state.registers.status |= ConditionCode::AllConditions;
@ -753,6 +753,10 @@
self.machine->run_for_instructions(1); self.machine->run_for_instructions(1);
} }
- (void)performDIVS:(uint16_t)divisor d1:(uint32_t)d1 {
[self performDIVS:divisor d1:d1];
}
- (void)performDIVSOverflowTestDivisor:(uint16_t)divisor { - (void)performDIVSOverflowTestDivisor:(uint16_t)divisor {
[self performDIVS:divisor d1:0x4768f231]; [self performDIVS:divisor d1:0x4768f231];
@ -871,7 +875,7 @@
- (void)testDIVS_12 { - (void)testDIVS_12 {
// DIVS.W #$af32, D1 // DIVS.W #$af32, D1
[self performDIVS:0xaf32 d1:0xe1d44]; [self performDIVS:0xaf32 d1:0xe1d44 sp:0];
const auto state = self.machine->get_processor_state(); const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x39dcffd4); XCTAssertEqual(state.registers.data[1], 0x39dcffd4);
@ -882,8 +886,7 @@
- (void)testDIVSException { - (void)testDIVSException {
// DIVS.W #0, D1 // DIVS.W #0, D1
const uint32_t initial_sp = 0x5000; const uint32_t initial_sp = 0x5000;
self.machine->set_initial_stack_pointer(initial_sp); [self performDIVS:0x0 d1:0x1fffffff sp:initial_sp];
[self performDIVS:0x0 d1:0x1fffffff];
// Check register state.registers. // Check register state.registers.
const auto state = self.machine->get_processor_state(); const auto state = self.machine->get_processor_state();
@ -1440,8 +1443,7 @@
- (void)testSUBb_PreDec { - (void)testSUBb_PreDec {
self.machine->set_program({ self.machine->set_program({
0x9427 // SUB.b -(A7), D2 0x9427 // SUB.b -(A7), D2
}); }, 0x2002);
self.machine->set_initial_stack_pointer(0x2002);
auto state = self.machine->get_processor_state(); auto state = self.machine->get_processor_state();
state.registers.data[2] = 0x9c40; state.registers.data[2] = 0x9c40;
*self.machine->ram_at(0x2000) = 0x2710; *self.machine->ram_at(0x2000) = 0x2710;

View File

@ -155,8 +155,7 @@
- (void)testANDb_PostInc_A7 { - (void)testANDb_PostInc_A7 {
_machine->set_program({ _machine->set_program({
0xc61f // AND.B (A7)+, D3 0xc61f // AND.B (A7)+, D3
}); }, 0x3000);
_machine->set_initial_stack_pointer(0x3000);
auto state = _machine->get_processor_state(); auto state = _machine->get_processor_state();
state.registers.data[3] = 0x54fff856; state.registers.data[3] = 0x54fff856;
*_machine->ram_at(0x3000) = 0x0053; *_machine->ram_at(0x3000) = 0x0053;
@ -1088,8 +1087,7 @@
- (void)testANDISR_supervisor { - (void)testANDISR_supervisor {
_machine->set_program({ _machine->set_program({
0x027c, 0x0700 // ANDI.W #$700, SR 0x027c, 0x0700 // ANDI.W #$700, SR
}); }, 300);
_machine->set_initial_stack_pointer(300);
_machine->run_for_instructions(1); _machine->run_for_instructions(1);
@ -1214,8 +1212,7 @@
- (void)testEORISR_supervisor { - (void)testEORISR_supervisor {
_machine->set_program({ _machine->set_program({
0x0a7c, 0x0700 // EORI.W #$700, SR 0x0a7c, 0x0700 // EORI.W #$700, SR
}); }, 300);
_machine->set_initial_stack_pointer(300);
_machine->run_for_instructions(1); _machine->run_for_instructions(1);
@ -1432,8 +1429,7 @@
- (void)testORISR_supervisor { - (void)testORISR_supervisor {
_machine->set_program({ _machine->set_program({
0x007c, 0x0700 // ORI.W #$700, SR 0x007c, 0x0700 // ORI.W #$700, SR
}); }, 300);
_machine->set_initial_stack_pointer(300);
_machine->run_for_instructions(1); _machine->run_for_instructions(1);

View File

@ -108,8 +108,7 @@
- (void)testBSRw { - (void)testBSRw {
_machine->set_program({ _machine->set_program({
0x6100, 0x0006 // BSR.w $1008 0x6100, 0x0006 // BSR.w $1008
}); }, 0x3000);
_machine->set_initial_stack_pointer(0x3000);
_machine->run_for_instructions(1); _machine->run_for_instructions(1);
@ -126,8 +125,7 @@
- (void)testBSRb { - (void)testBSRb {
_machine->set_program({ _machine->set_program({
0x6106 // BSR.b $1008 0x6106 // BSR.b $1008
}); }, 0x3000);
_machine->set_initial_stack_pointer(0x3000);
_machine->run_for_instructions(1); _machine->run_for_instructions(1);
@ -146,13 +144,12 @@
- (void)performCHKd1:(uint32_t)d1 d2:(uint32_t)d2 { - (void)performCHKd1:(uint32_t)d1 d2:(uint32_t)d2 {
_machine->set_program({ _machine->set_program({
0x4581 // CHK D1, D2 0x4581 // CHK D1, D2
}); }, 0);
auto state = _machine->get_processor_state(); auto state = _machine->get_processor_state();
state.registers.data[1] = d1; state.registers.data[1] = d1;
state.registers.data[2] = d2; state.registers.data[2] = d2;
state.registers.status |= ConditionCode::AllConditions; state.registers.status |= ConditionCode::AllConditions;
_machine->set_initial_stack_pointer(0);
_machine->set_processor_state(state); _machine->set_processor_state(state);
_machine->run_for_instructions(1); _machine->run_for_instructions(1);
@ -414,8 +411,7 @@
- (void)testJSR_PC { - (void)testJSR_PC {
_machine->set_program({ _machine->set_program({
0x4eba, 0x000a // JSR (+a)PC ; JSR to $100c 0x4eba, 0x000a // JSR (+a)PC ; JSR to $100c
}); }, 0x2000);
_machine->set_initial_stack_pointer(0x2000);
_machine->run_for_instructions(1); _machine->run_for_instructions(1);
@ -430,8 +426,7 @@
- (void)testJSR_XXXl { - (void)testJSR_XXXl {
_machine->set_program({ _machine->set_program({
0x4eb9, 0x0000, 0x1008 // JSR ($1008).l 0x4eb9, 0x0000, 0x1008 // JSR ($1008).l
}); }, 0x2000);
_machine->set_initial_stack_pointer(0x2000);
_machine->run_for_instructions(1); _machine->run_for_instructions(1);
@ -458,8 +453,7 @@
- (void)testRTR { - (void)testRTR {
_machine->set_program({ _machine->set_program({
0x4e77 // RTR 0x4e77 // RTR
}); }, 0x2000);
_machine->set_initial_stack_pointer(0x2000);
*_machine->ram_at(0x2000) = 0x7fff; *_machine->ram_at(0x2000) = 0x7fff;
*_machine->ram_at(0x2002) = 0; *_machine->ram_at(0x2002) = 0;
*_machine->ram_at(0x2004) = 0xc; *_machine->ram_at(0x2004) = 0xc;
@ -478,8 +472,7 @@
- (void)testRTS { - (void)testRTS {
_machine->set_program({ _machine->set_program({
0x4e75 // RTS 0x4e75 // RTS
}); }, 0x2000);
_machine->set_initial_stack_pointer(0x2000);
*_machine->ram_at(0x2000) = 0x0000; *_machine->ram_at(0x2000) = 0x0000;
*_machine->ram_at(0x2002) = 0x000c; *_machine->ram_at(0x2002) = 0x000c;
@ -521,8 +514,7 @@
- (void)testTRAPV_taken { - (void)testTRAPV_taken {
_machine->set_program({ _machine->set_program({
0x4e76 // TRAPV 0x4e76 // TRAPV
}); }, 0x206);
_machine->set_initial_stack_pointer(0x206);
auto state = _machine->get_processor_state(); auto state = _machine->get_processor_state();
state.registers.status = 0x702; state.registers.status = 0x702;

View File

@ -292,10 +292,9 @@
- (void)testLINKA1_5 { - (void)testLINKA1_5 {
_machine->set_program({ _machine->set_program({
0x4e51, 0x0005 // LINK a1, #5 0x4e51, 0x0005 // LINK a1, #5
}); }, 0x22222222);
auto state = _machine->get_processor_state(); auto state = _machine->get_processor_state();
state.registers.address[1] = 0x11111111; state.registers.address[1] = 0x11111111;
_machine->set_initial_stack_pointer(0x22222222);
_machine->set_processor_state(state); _machine->set_processor_state(state);
_machine->run_for_instructions(1); _machine->run_for_instructions(1);
@ -311,8 +310,7 @@
- (void)testLINKA7_5 { - (void)testLINKA7_5 {
_machine->set_program({ _machine->set_program({
0x4e57, 0x0005 // LINK a7, #5 0x4e57, 0x0005 // LINK a7, #5
}); }, 0x22222222);
_machine->set_initial_stack_pointer(0x22222222);
_machine->run_for_instructions(1); _machine->run_for_instructions(1);
@ -326,10 +324,9 @@
- (void)testLINKA1_8000 { - (void)testLINKA1_8000 {
_machine->set_program({ _machine->set_program({
0x4e51, 0x8000 // LINK a1, #$8000 0x4e51, 0x8000 // LINK a1, #$8000
}); }, 0x22222222);
auto state = _machine->get_processor_state(); auto state = _machine->get_processor_state();
state.registers.address[1] = 0x11111111; state.registers.address[1] = 0x11111111;
_machine->set_initial_stack_pointer(0x22222222);
_machine->set_processor_state(state); _machine->set_processor_state(state);
_machine->run_for_instructions(1); _machine->run_for_instructions(1);
@ -395,14 +392,13 @@
- (void)testMOVEMl_fromEverything { - (void)testMOVEMl_fromEverything {
_machine->set_program({ _machine->set_program({
0x48e4, 0xffff // MOVEM.L D0-D7/A0-A7, -(A4) 0x48e4, 0xffff // MOVEM.L D0-D7/A0-A7, -(A4)
}); }, 0xffffffff);
auto state = _machine->get_processor_state(); auto state = _machine->get_processor_state();
for(int c = 0; c < 8; ++c) for(int c = 0; c < 8; ++c)
state.registers.data[c] = (c+1) * 0x11111111; state.registers.data[c] = (c+1) * 0x11111111;
for(int c = 0; c < 7; ++c) for(int c = 0; c < 7; ++c)
state.registers.address[c] = ((c < 4) ? (c + 9) : (c + 8)) * 0x11111111; state.registers.address[c] = ((c < 4) ? (c + 9) : (c + 8)) * 0x11111111;
state.registers.address[4] = 0x4000; state.registers.address[4] = 0x4000;
_machine->set_initial_stack_pointer(0xffffffff);
_machine->set_processor_state(state); _machine->set_processor_state(state);
_machine->run_for_instructions(1); _machine->run_for_instructions(1);
@ -995,10 +991,9 @@
- (void)testPEA_A1 { - (void)testPEA_A1 {
_machine->set_program({ _machine->set_program({
0x4851 // PEA (A1) 0x4851 // PEA (A1)
}); }, 0x1996);
auto state = _machine->get_processor_state(); auto state = _machine->get_processor_state();
state.registers.address[1] = 0x3000ffff; state.registers.address[1] = 0x3000ffff;
_machine->set_initial_stack_pointer(0x1996);
_machine->set_processor_state(state); _machine->set_processor_state(state);
_machine->run_for_instructions(1); _machine->run_for_instructions(1);
@ -1014,8 +1009,7 @@
- (void)testPEA_A7 { - (void)testPEA_A7 {
_machine->set_program({ _machine->set_program({
0x4857 // PEA (A7) 0x4857 // PEA (A7)
}); }, 0x1012);
_machine->set_initial_stack_pointer(0x1012);
_machine->run_for_instructions(1); _machine->run_for_instructions(1);
@ -1029,8 +1023,7 @@
- (void)testPEA_4A7 { - (void)testPEA_4A7 {
_machine->set_program({ _machine->set_program({
0x486f, 0x0004 // PEA 4(A7) 0x486f, 0x0004 // PEA 4(A7)
}); }, 0x1012);
_machine->set_initial_stack_pointer(0x1012);
_machine->run_for_instructions(1); _machine->run_for_instructions(1);
@ -1044,8 +1037,7 @@
- (void)testPEA_XXXw { - (void)testPEA_XXXw {
_machine->set_program({ _machine->set_program({
0x4878, 0x3000 // PEA ($3000).w 0x4878, 0x3000 // PEA ($3000).w
}); }, 0x1996);
_machine->set_initial_stack_pointer(0x1996);
_machine->run_for_instructions(1); _machine->run_for_instructions(1);
@ -1059,8 +1051,7 @@
- (void)testPEA_XXXl { - (void)testPEA_XXXl {
_machine->set_program({ _machine->set_program({
0x4879, 0x1234, 0x5678 // PEA ($12345678) 0x4879, 0x1234, 0x5678 // PEA ($12345678)
}); }, 0x1996);
_machine->set_initial_stack_pointer(0x1996);
_machine->run_for_instructions(1); _machine->run_for_instructions(1);
@ -1235,8 +1226,7 @@
- (void)testUNLINK_A7 { - (void)testUNLINK_A7 {
_machine->set_program({ _machine->set_program({
0x4e5f // UNLNK A7 0x4e5f // UNLNK A7
}); }, 0x3000);
_machine->set_initial_stack_pointer(0x3000);
*_machine->ram_at(0x3000) = 0x0000; *_machine->ram_at(0x3000) = 0x0000;
*_machine->ram_at(0x3002) = 0x4000; *_machine->ram_at(0x3002) = 0x4000;

View File

@ -148,8 +148,7 @@ class CPU::MC68000::ProcessorStorageTests {
0x82C0, // DIVU; location 0x404 0x82C0, // DIVU; location 0x404
/* Next instruction would be at 0x406 */ /* Next instruction would be at 0x406 */
}); }, 0x1000);
_machine->set_initial_stack_pointer(0x1000);
_machine->run_for_instructions(4); _machine->run_for_instructions(4);

View File

@ -23,77 +23,48 @@ using namespace InstructionSet::M68k;
*/ */
class RAM68000: public CPU::MC68000Mk2::BusHandler { class RAM68000: public CPU::MC68000Mk2::BusHandler {
public: public:
RAM68000() : m68000_(*this) { RAM68000() : m68000_(*this) {}
// Setup the /RESET vector.
ram_[0] = 0;
ram_[1] = 0x206; // Supervisor stack pointer.
ram_[2] = 0;
ram_[3] = 0x1000; // Initial PC.
// Ensure the condition codes start unset.
auto state = get_processor_state();
state.registers.status &= ~ConditionCode::AllConditions;
set_processor_state(state);
}
uint32_t initial_pc() const { uint32_t initial_pc() const {
return 0x1000; return 0x1000;
} }
void set_program(const std::vector<uint16_t> &program) { void set_program(
const std::vector<uint16_t> &program,
uint32_t stack_pointer = 0x206) {
memcpy(&ram_[0x1000 >> 1], program.data(), program.size() * sizeof(uint16_t)); memcpy(&ram_[0x1000 >> 1], program.data(), program.size() * sizeof(uint16_t));
// Add a NOP suffix, to avoid corrupting flags should the attempt to // Ensure the condition codes start unset and set the initial program counter
// run for a certain number of instructions overrun. // and supervisor stack pointer.
ram_[(0x1000 >> 1) + program.size()] = 0x4e71; auto state = get_processor_state();
} state.registers.status &= ~ConditionCode::AllConditions;
state.registers.program_counter = initial_pc();
void set_initial_stack_pointer(uint32_t sp) { state.registers.supervisor_stack_pointer = stack_pointer;
ram_[0] = sp >> 16; set_processor_state(state);
ram_[1] = sp & 0xffff;
} }
void will_perform(uint32_t, uint16_t) { void will_perform(uint32_t, uint16_t) {
if(!has_run_) {
// Reapply all of initial state except the program counter and stack pointers.
// Also copy the supervisor stack pointer to the user.
const auto state = m68000_.get_state();
initial_state_.registers.program_counter = state.registers.program_counter;
initial_state_.registers.user_stack_pointer = state.registers.supervisor_stack_pointer;
initial_state_.registers.supervisor_stack_pointer = state.registers.supervisor_stack_pointer;
m68000_.set_state(initial_state_);
}
--instructions_remaining_; --instructions_remaining_;
if(!instructions_remaining_) { if(!instructions_remaining_) {
captured_state_ = m68000_.get_state(); throw StopException();
} }
} }
void run_for_instructions(int count) { void run_for_instructions(int count) {
instructions_remaining_ = count + (has_run_ ? 0 : 1); instructions_remaining_ = count;
finish_reset_if_needed(); if(!instructions_remaining_) return;
while(instructions_remaining_) { try {
run_for(HalfCycles(2)); while(true) {
run_for(HalfCycles(2000));
} }
} catch (const StopException &) {}
} }
void run_for(HalfCycles cycles) { void run_for(HalfCycles cycles) {
finish_reset_if_needed();
m68000_.run_for(cycles); m68000_.run_for(cycles);
} }
void finish_reset_if_needed() {
// If the 68000 hasn't run yet, build in the necessary
// cycles to finish the reset program, and set the stored state.
if(!has_run_) {
m68000_.run_for(HalfCycles(80));
duration_ -= HalfCycles(80);
has_run_ = true;
}
}
uint16_t *ram_at(uint32_t address) { uint16_t *ram_at(uint32_t address) {
return &ram_[(address >> 1) % ram_.size()]; return &ram_[(address >> 1) % ram_.size()];
} }
@ -133,12 +104,11 @@ class RAM68000: public CPU::MC68000Mk2::BusHandler {
} }
CPU::MC68000Mk2::State get_processor_state() { CPU::MC68000Mk2::State get_processor_state() {
return captured_state_; return m68000_.get_state();
} }
void set_processor_state(const CPU::MC68000Mk2::State &state) { void set_processor_state(const CPU::MC68000Mk2::State &state) {
initial_state_ = captured_state_ = state; m68000_.decode_from_state(state.registers);
m68000_.set_state(state);
} }
auto &processor() { auto &processor() {
@ -154,12 +124,12 @@ class RAM68000: public CPU::MC68000Mk2::BusHandler {
} }
private: private:
struct StopException {};
CPU::MC68000Mk2::Processor<RAM68000, true, true, true> m68000_; CPU::MC68000Mk2::Processor<RAM68000, true, true, true> m68000_;
std::array<uint16_t, 256*1024> ram_{}; std::array<uint16_t, 256*1024> ram_{};
int instructions_remaining_; int instructions_remaining_;
HalfCycles duration_; HalfCycles duration_;
bool has_run_ = false;
CPU::MC68000Mk2::State captured_state_, initial_state_;
}; };
#endif /* TestRunner68000_h */ #endif /* TestRunner68000_h */