mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-22 19:31:27 +00:00
Make an effort to withdraw from the high-circuitous stuff of working around the reset sequence.
This commit is contained in:
parent
367ad8079a
commit
866787c5d3
@ -741,10 +741,10 @@
|
||||
@end
|
||||
@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({
|
||||
0x83fc, divisor // DIVS #divisor, D1
|
||||
});
|
||||
}, sp);
|
||||
auto state = self.machine->get_processor_state();
|
||||
state.registers.data[1] = d1;
|
||||
state.registers.status |= ConditionCode::AllConditions;
|
||||
@ -753,6 +753,10 @@
|
||||
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 {
|
||||
[self performDIVS:divisor d1:0x4768f231];
|
||||
|
||||
@ -871,7 +875,7 @@
|
||||
|
||||
- (void)testDIVS_12 {
|
||||
// DIVS.W #$af32, D1
|
||||
[self performDIVS:0xaf32 d1:0xe1d44];
|
||||
[self performDIVS:0xaf32 d1:0xe1d44 sp:0];
|
||||
|
||||
const auto state = self.machine->get_processor_state();
|
||||
XCTAssertEqual(state.registers.data[1], 0x39dcffd4);
|
||||
@ -882,8 +886,7 @@
|
||||
- (void)testDIVSException {
|
||||
// DIVS.W #0, D1
|
||||
const uint32_t initial_sp = 0x5000;
|
||||
self.machine->set_initial_stack_pointer(initial_sp);
|
||||
[self performDIVS:0x0 d1:0x1fffffff];
|
||||
[self performDIVS:0x0 d1:0x1fffffff sp:initial_sp];
|
||||
|
||||
// Check register state.registers.
|
||||
const auto state = self.machine->get_processor_state();
|
||||
@ -1440,8 +1443,7 @@
|
||||
- (void)testSUBb_PreDec {
|
||||
self.machine->set_program({
|
||||
0x9427 // SUB.b -(A7), D2
|
||||
});
|
||||
self.machine->set_initial_stack_pointer(0x2002);
|
||||
}, 0x2002);
|
||||
auto state = self.machine->get_processor_state();
|
||||
state.registers.data[2] = 0x9c40;
|
||||
*self.machine->ram_at(0x2000) = 0x2710;
|
||||
|
@ -155,8 +155,7 @@
|
||||
- (void)testANDb_PostInc_A7 {
|
||||
_machine->set_program({
|
||||
0xc61f // AND.B (A7)+, D3
|
||||
});
|
||||
_machine->set_initial_stack_pointer(0x3000);
|
||||
}, 0x3000);
|
||||
auto state = _machine->get_processor_state();
|
||||
state.registers.data[3] = 0x54fff856;
|
||||
*_machine->ram_at(0x3000) = 0x0053;
|
||||
@ -1088,8 +1087,7 @@
|
||||
- (void)testANDISR_supervisor {
|
||||
_machine->set_program({
|
||||
0x027c, 0x0700 // ANDI.W #$700, SR
|
||||
});
|
||||
_machine->set_initial_stack_pointer(300);
|
||||
}, 300);
|
||||
|
||||
_machine->run_for_instructions(1);
|
||||
|
||||
@ -1214,8 +1212,7 @@
|
||||
- (void)testEORISR_supervisor {
|
||||
_machine->set_program({
|
||||
0x0a7c, 0x0700 // EORI.W #$700, SR
|
||||
});
|
||||
_machine->set_initial_stack_pointer(300);
|
||||
}, 300);
|
||||
|
||||
_machine->run_for_instructions(1);
|
||||
|
||||
@ -1432,8 +1429,7 @@
|
||||
- (void)testORISR_supervisor {
|
||||
_machine->set_program({
|
||||
0x007c, 0x0700 // ORI.W #$700, SR
|
||||
});
|
||||
_machine->set_initial_stack_pointer(300);
|
||||
}, 300);
|
||||
|
||||
_machine->run_for_instructions(1);
|
||||
|
||||
|
@ -108,8 +108,7 @@
|
||||
- (void)testBSRw {
|
||||
_machine->set_program({
|
||||
0x6100, 0x0006 // BSR.w $1008
|
||||
});
|
||||
_machine->set_initial_stack_pointer(0x3000);
|
||||
}, 0x3000);
|
||||
|
||||
_machine->run_for_instructions(1);
|
||||
|
||||
@ -126,8 +125,7 @@
|
||||
- (void)testBSRb {
|
||||
_machine->set_program({
|
||||
0x6106 // BSR.b $1008
|
||||
});
|
||||
_machine->set_initial_stack_pointer(0x3000);
|
||||
}, 0x3000);
|
||||
|
||||
_machine->run_for_instructions(1);
|
||||
|
||||
@ -146,13 +144,12 @@
|
||||
- (void)performCHKd1:(uint32_t)d1 d2:(uint32_t)d2 {
|
||||
_machine->set_program({
|
||||
0x4581 // CHK D1, D2
|
||||
});
|
||||
}, 0);
|
||||
auto state = _machine->get_processor_state();
|
||||
state.registers.data[1] = d1;
|
||||
state.registers.data[2] = d2;
|
||||
state.registers.status |= ConditionCode::AllConditions;
|
||||
|
||||
_machine->set_initial_stack_pointer(0);
|
||||
_machine->set_processor_state(state);
|
||||
_machine->run_for_instructions(1);
|
||||
|
||||
@ -414,8 +411,7 @@
|
||||
- (void)testJSR_PC {
|
||||
_machine->set_program({
|
||||
0x4eba, 0x000a // JSR (+a)PC ; JSR to $100c
|
||||
});
|
||||
_machine->set_initial_stack_pointer(0x2000);
|
||||
}, 0x2000);
|
||||
|
||||
_machine->run_for_instructions(1);
|
||||
|
||||
@ -430,8 +426,7 @@
|
||||
- (void)testJSR_XXXl {
|
||||
_machine->set_program({
|
||||
0x4eb9, 0x0000, 0x1008 // JSR ($1008).l
|
||||
});
|
||||
_machine->set_initial_stack_pointer(0x2000);
|
||||
}, 0x2000);
|
||||
|
||||
_machine->run_for_instructions(1);
|
||||
|
||||
@ -458,8 +453,7 @@
|
||||
- (void)testRTR {
|
||||
_machine->set_program({
|
||||
0x4e77 // RTR
|
||||
});
|
||||
_machine->set_initial_stack_pointer(0x2000);
|
||||
}, 0x2000);
|
||||
*_machine->ram_at(0x2000) = 0x7fff;
|
||||
*_machine->ram_at(0x2002) = 0;
|
||||
*_machine->ram_at(0x2004) = 0xc;
|
||||
@ -478,8 +472,7 @@
|
||||
- (void)testRTS {
|
||||
_machine->set_program({
|
||||
0x4e75 // RTS
|
||||
});
|
||||
_machine->set_initial_stack_pointer(0x2000);
|
||||
}, 0x2000);
|
||||
*_machine->ram_at(0x2000) = 0x0000;
|
||||
*_machine->ram_at(0x2002) = 0x000c;
|
||||
|
||||
@ -521,8 +514,7 @@
|
||||
- (void)testTRAPV_taken {
|
||||
_machine->set_program({
|
||||
0x4e76 // TRAPV
|
||||
});
|
||||
_machine->set_initial_stack_pointer(0x206);
|
||||
}, 0x206);
|
||||
|
||||
auto state = _machine->get_processor_state();
|
||||
state.registers.status = 0x702;
|
||||
|
@ -292,10 +292,9 @@
|
||||
- (void)testLINKA1_5 {
|
||||
_machine->set_program({
|
||||
0x4e51, 0x0005 // LINK a1, #5
|
||||
});
|
||||
}, 0x22222222);
|
||||
auto state = _machine->get_processor_state();
|
||||
state.registers.address[1] = 0x11111111;
|
||||
_machine->set_initial_stack_pointer(0x22222222);
|
||||
|
||||
_machine->set_processor_state(state);
|
||||
_machine->run_for_instructions(1);
|
||||
@ -311,8 +310,7 @@
|
||||
- (void)testLINKA7_5 {
|
||||
_machine->set_program({
|
||||
0x4e57, 0x0005 // LINK a7, #5
|
||||
});
|
||||
_machine->set_initial_stack_pointer(0x22222222);
|
||||
}, 0x22222222);
|
||||
|
||||
_machine->run_for_instructions(1);
|
||||
|
||||
@ -326,10 +324,9 @@
|
||||
- (void)testLINKA1_8000 {
|
||||
_machine->set_program({
|
||||
0x4e51, 0x8000 // LINK a1, #$8000
|
||||
});
|
||||
}, 0x22222222);
|
||||
auto state = _machine->get_processor_state();
|
||||
state.registers.address[1] = 0x11111111;
|
||||
_machine->set_initial_stack_pointer(0x22222222);
|
||||
|
||||
_machine->set_processor_state(state);
|
||||
_machine->run_for_instructions(1);
|
||||
@ -395,14 +392,13 @@
|
||||
- (void)testMOVEMl_fromEverything {
|
||||
_machine->set_program({
|
||||
0x48e4, 0xffff // MOVEM.L D0-D7/A0-A7, -(A4)
|
||||
});
|
||||
}, 0xffffffff);
|
||||
auto state = _machine->get_processor_state();
|
||||
for(int c = 0; c < 8; ++c)
|
||||
state.registers.data[c] = (c+1) * 0x11111111;
|
||||
for(int c = 0; c < 7; ++c)
|
||||
state.registers.address[c] = ((c < 4) ? (c + 9) : (c + 8)) * 0x11111111;
|
||||
state.registers.address[4] = 0x4000;
|
||||
_machine->set_initial_stack_pointer(0xffffffff);
|
||||
|
||||
_machine->set_processor_state(state);
|
||||
_machine->run_for_instructions(1);
|
||||
@ -995,10 +991,9 @@
|
||||
- (void)testPEA_A1 {
|
||||
_machine->set_program({
|
||||
0x4851 // PEA (A1)
|
||||
});
|
||||
}, 0x1996);
|
||||
auto state = _machine->get_processor_state();
|
||||
state.registers.address[1] = 0x3000ffff;
|
||||
_machine->set_initial_stack_pointer(0x1996);
|
||||
|
||||
_machine->set_processor_state(state);
|
||||
_machine->run_for_instructions(1);
|
||||
@ -1014,8 +1009,7 @@
|
||||
- (void)testPEA_A7 {
|
||||
_machine->set_program({
|
||||
0x4857 // PEA (A7)
|
||||
});
|
||||
_machine->set_initial_stack_pointer(0x1012);
|
||||
}, 0x1012);
|
||||
|
||||
_machine->run_for_instructions(1);
|
||||
|
||||
@ -1029,8 +1023,7 @@
|
||||
- (void)testPEA_4A7 {
|
||||
_machine->set_program({
|
||||
0x486f, 0x0004 // PEA 4(A7)
|
||||
});
|
||||
_machine->set_initial_stack_pointer(0x1012);
|
||||
}, 0x1012);
|
||||
|
||||
_machine->run_for_instructions(1);
|
||||
|
||||
@ -1044,8 +1037,7 @@
|
||||
- (void)testPEA_XXXw {
|
||||
_machine->set_program({
|
||||
0x4878, 0x3000 // PEA ($3000).w
|
||||
});
|
||||
_machine->set_initial_stack_pointer(0x1996);
|
||||
}, 0x1996);
|
||||
|
||||
_machine->run_for_instructions(1);
|
||||
|
||||
@ -1059,8 +1051,7 @@
|
||||
- (void)testPEA_XXXl {
|
||||
_machine->set_program({
|
||||
0x4879, 0x1234, 0x5678 // PEA ($12345678)
|
||||
});
|
||||
_machine->set_initial_stack_pointer(0x1996);
|
||||
}, 0x1996);
|
||||
|
||||
_machine->run_for_instructions(1);
|
||||
|
||||
@ -1235,8 +1226,7 @@
|
||||
- (void)testUNLINK_A7 {
|
||||
_machine->set_program({
|
||||
0x4e5f // UNLNK A7
|
||||
});
|
||||
_machine->set_initial_stack_pointer(0x3000);
|
||||
}, 0x3000);
|
||||
*_machine->ram_at(0x3000) = 0x0000;
|
||||
*_machine->ram_at(0x3002) = 0x4000;
|
||||
|
||||
|
@ -148,8 +148,7 @@ class CPU::MC68000::ProcessorStorageTests {
|
||||
0x82C0, // DIVU; location 0x404
|
||||
|
||||
/* Next instruction would be at 0x406 */
|
||||
});
|
||||
_machine->set_initial_stack_pointer(0x1000);
|
||||
}, 0x1000);
|
||||
|
||||
_machine->run_for_instructions(4);
|
||||
|
||||
|
@ -23,77 +23,48 @@ using namespace InstructionSet::M68k;
|
||||
*/
|
||||
class RAM68000: public CPU::MC68000Mk2::BusHandler {
|
||||
public:
|
||||
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);
|
||||
}
|
||||
RAM68000() : m68000_(*this) {}
|
||||
|
||||
uint32_t initial_pc() const {
|
||||
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));
|
||||
|
||||
// Add a NOP suffix, to avoid corrupting flags should the attempt to
|
||||
// run for a certain number of instructions overrun.
|
||||
ram_[(0x1000 >> 1) + program.size()] = 0x4e71;
|
||||
}
|
||||
|
||||
void set_initial_stack_pointer(uint32_t sp) {
|
||||
ram_[0] = sp >> 16;
|
||||
ram_[1] = sp & 0xffff;
|
||||
// Ensure the condition codes start unset and set the initial program counter
|
||||
// and supervisor stack pointer.
|
||||
auto state = get_processor_state();
|
||||
state.registers.status &= ~ConditionCode::AllConditions;
|
||||
state.registers.program_counter = initial_pc();
|
||||
state.registers.supervisor_stack_pointer = stack_pointer;
|
||||
set_processor_state(state);
|
||||
}
|
||||
|
||||
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_;
|
||||
if(!instructions_remaining_) {
|
||||
captured_state_ = m68000_.get_state();
|
||||
throw StopException();
|
||||
}
|
||||
}
|
||||
|
||||
void run_for_instructions(int count) {
|
||||
instructions_remaining_ = count + (has_run_ ? 0 : 1);
|
||||
finish_reset_if_needed();
|
||||
instructions_remaining_ = count;
|
||||
if(!instructions_remaining_) return;
|
||||
|
||||
while(instructions_remaining_) {
|
||||
run_for(HalfCycles(2));
|
||||
}
|
||||
try {
|
||||
while(true) {
|
||||
run_for(HalfCycles(2000));
|
||||
}
|
||||
} catch (const StopException &) {}
|
||||
}
|
||||
|
||||
void run_for(HalfCycles cycles) {
|
||||
finish_reset_if_needed();
|
||||
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) {
|
||||
return &ram_[(address >> 1) % ram_.size()];
|
||||
}
|
||||
@ -133,12 +104,11 @@ class RAM68000: public CPU::MC68000Mk2::BusHandler {
|
||||
}
|
||||
|
||||
CPU::MC68000Mk2::State get_processor_state() {
|
||||
return captured_state_;
|
||||
return m68000_.get_state();
|
||||
}
|
||||
|
||||
void set_processor_state(const CPU::MC68000Mk2::State &state) {
|
||||
initial_state_ = captured_state_ = state;
|
||||
m68000_.set_state(state);
|
||||
m68000_.decode_from_state(state.registers);
|
||||
}
|
||||
|
||||
auto &processor() {
|
||||
@ -154,12 +124,12 @@ class RAM68000: public CPU::MC68000Mk2::BusHandler {
|
||||
}
|
||||
|
||||
private:
|
||||
struct StopException {};
|
||||
|
||||
CPU::MC68000Mk2::Processor<RAM68000, true, true, true> m68000_;
|
||||
std::array<uint16_t, 256*1024> ram_{};
|
||||
int instructions_remaining_;
|
||||
HalfCycles duration_;
|
||||
bool has_run_ = false;
|
||||
CPU::MC68000Mk2::State captured_state_, initial_state_;
|
||||
};
|
||||
|
||||
#endif /* TestRunner68000_h */
|
||||
|
Loading…
x
Reference in New Issue
Block a user