mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-16 18:30:32 +00:00
Add a faulty attempt at MOVEM.
This commit is contained in:
parent
9d79e64f5c
commit
a818650027
@ -156,7 +156,7 @@ struct TestProcessor: public CPU::MC68000Mk2::BusHandler {
|
||||
|
||||
// To limit tests run to a subset of files and/or of tests, uncomment and fill in below.
|
||||
_fileSet = [NSSet setWithArray:@[
|
||||
// @"chk.json",
|
||||
@"movem.json",
|
||||
|
||||
// Below this line are passing tests.
|
||||
@"abcd_sbcd.json",
|
||||
@ -176,7 +176,7 @@ struct TestProcessor: public CPU::MC68000Mk2::BusHandler {
|
||||
@"ext.json",
|
||||
@"swap.json",
|
||||
]]; // 16/32 = 50 % done, as far as the tests go.
|
||||
// _testSet = [NSSet setWithArray:@[@"BCLR 0122"]];
|
||||
_testSet = [NSSet setWithArray:@[@"MOVEM 006f (2)"]];
|
||||
}
|
||||
|
||||
- (void)testAll {
|
||||
@ -287,7 +287,7 @@ struct TestProcessor: public CPU::MC68000Mk2::BusHandler {
|
||||
NSNumber *const value = [enumerator nextObject];
|
||||
|
||||
if(!address || !value) break;
|
||||
XCTAssertEqual(test68000->ram[address.integerValue ^ 1], value.integerValue, @"%@: Memory at location %@ inconsistent", name, address);
|
||||
// XCTAssertEqual(test68000->ram[address.integerValue ^ 1], value.integerValue, @"%@: Memory at location %@ inconsistent", name, address);
|
||||
if(test68000->ram[address.integerValue ^ 1] != value.integerValue) [_failures addObject:name];
|
||||
}
|
||||
|
||||
|
@ -143,6 +143,9 @@ enum ExecutionState: int {
|
||||
MOVEPtoR_l,
|
||||
|
||||
LogicalToSR,
|
||||
|
||||
MOVEMtoR, MOVEMtoR_l_read, MOVEMtoR_w_read, MOVEMtoR_finish,
|
||||
MOVEMtoM, MOVEMtoM_l_write, MOVEMtoM_w_write, MOVEMtoM_finish,
|
||||
};
|
||||
|
||||
// MARK: - The state machine.
|
||||
@ -640,6 +643,11 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
||||
Duplicate(ORItoSR, EORItoSR); Duplicate(ANDItoSR, EORItoSR);
|
||||
StdCASE(EORItoSR, perform_state_ = LogicalToSR);
|
||||
|
||||
StdCASE(MOVEMtoRl, perform_state_ = MOVEMtoR);
|
||||
StdCASE(MOVEMtoRw, perform_state_ = MOVEMtoR);
|
||||
StdCASE(MOVEMtoMl, perform_state_ = MOVEMtoM);
|
||||
StdCASE(MOVEMtoMw, perform_state_ = MOVEMtoM);
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
@ -1528,6 +1536,140 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
||||
Prefetch();
|
||||
MoveToState(Decode);
|
||||
|
||||
//
|
||||
// MOVEM M --> R
|
||||
//
|
||||
BeginState(MOVEMtoR):
|
||||
Prefetch(); // np
|
||||
post_ea_state_ =
|
||||
(instruction_.operation == InstructionSet::M68k::Operation::MOVEMtoRl) ?
|
||||
MOVEMtoR_l_read : MOVEMtoR_w_read;
|
||||
next_operand_ = 1;
|
||||
register_index_ = 0;
|
||||
register_delta_ = 1;
|
||||
|
||||
SetDataAddress(effective_address_[1]);
|
||||
SetupDataAccess(Microcycle::Read, Microcycle::SelectWord);
|
||||
MoveToState(CalcEffectiveAddress);
|
||||
|
||||
BeginState(MOVEMtoR_w_read):
|
||||
// If there's nothing left to read, move on.
|
||||
if(!operand_[0].w) {
|
||||
MoveToState(MOVEMtoR_finish);
|
||||
}
|
||||
|
||||
// Find the next register to read, read it and sign extend it.
|
||||
while(!(operand_[0].w & 1)) {
|
||||
operand_[0].w >>= 1;
|
||||
register_index_ += register_delta_;
|
||||
}
|
||||
Access(registers_[register_index_].low);
|
||||
registers_[register_index_].l = uint32_t(int16_t(registers_[register_index_].w));
|
||||
effective_address_[1] += 2;
|
||||
|
||||
// Drop the bottom bit.
|
||||
operand_[0].w >>= 1;
|
||||
register_index_ += register_delta_;
|
||||
MoveToState(MOVEMtoR_w_read);
|
||||
|
||||
BeginState(MOVEMtoR_l_read):
|
||||
// If there's nothing left to read, move on.
|
||||
if(!operand_[0].w) {
|
||||
MoveToState(MOVEMtoR_finish);
|
||||
}
|
||||
|
||||
// Find the next register to read, read it.
|
||||
while(!(operand_[0].w & 1)) {
|
||||
operand_[0].w >>= 1;
|
||||
register_index_ += register_delta_;
|
||||
}
|
||||
Access(registers_[register_index_].low);
|
||||
effective_address_[1] += 2;
|
||||
Access(registers_[register_index_].high);
|
||||
effective_address_[1] += 2;
|
||||
|
||||
// Drop the bottom bit.
|
||||
operand_[0].w >>= 1;
|
||||
register_index_ += register_delta_;
|
||||
MoveToState(MOVEMtoR_l_read);
|
||||
|
||||
BeginState(MOVEMtoR_finish):
|
||||
// Perform one more read, spuriously.
|
||||
Access(temporary_value_.low); // nr
|
||||
|
||||
Prefetch(); // np
|
||||
MoveToState(Decode);
|
||||
|
||||
//
|
||||
// MOVEM R --> M
|
||||
//
|
||||
BeginState(MOVEMtoM):
|
||||
Prefetch(); // np
|
||||
post_ea_state_ =
|
||||
(instruction_.operation == InstructionSet::M68k::Operation::MOVEMtoMl) ?
|
||||
MOVEMtoM_l_write : MOVEMtoM_w_write;
|
||||
next_operand_ = 1;
|
||||
|
||||
// Predecrement writes registers the other way around, but still reads the
|
||||
// mask from LSB.
|
||||
if(instruction_.mode(1) == Mode::AddressRegisterIndirectWithPredecrement) {
|
||||
register_index_ = 15;
|
||||
register_delta_ = -1;
|
||||
} else {
|
||||
register_index_ = 0;
|
||||
register_delta_ = 1;
|
||||
}
|
||||
|
||||
SetDataAddress(effective_address_[1]);
|
||||
SetupDataAccess(0, Microcycle::SelectWord);
|
||||
MoveToState(CalcEffectiveAddress);
|
||||
|
||||
BeginState(MOVEMtoM_w_write):
|
||||
// If there's nothing left to read, move on.
|
||||
if(!operand_[0].w) {
|
||||
MoveToState(MOVEMtoM_finish);
|
||||
}
|
||||
|
||||
// Find the next register to write, write it.
|
||||
while(!(operand_[0].w & 1)) {
|
||||
operand_[0].w >>= 1;
|
||||
register_index_ += register_delta_;
|
||||
}
|
||||
Access(registers_[register_index_].low);
|
||||
effective_address_[1] += register_delta_ << 1;
|
||||
|
||||
// Drop the bottom bit.
|
||||
operand_[0].w >>= 1;
|
||||
register_index_ += register_delta_;
|
||||
MoveToState(MOVEMtoM_w_write);
|
||||
|
||||
BeginState(MOVEMtoM_l_write):
|
||||
// If there's nothing left to read, move on.
|
||||
if(!operand_[0].w) {
|
||||
MoveToState(MOVEMtoM_finish);
|
||||
}
|
||||
|
||||
// Find the next register to write, write it.
|
||||
while(!(operand_[0].w & 1)) {
|
||||
operand_[0].w >>= 1;
|
||||
register_index_ += register_delta_;
|
||||
}
|
||||
|
||||
// TODO: switch word order if predecrementing.
|
||||
Access(registers_[register_index_].high);
|
||||
effective_address_[1] += register_delta_ << 1;
|
||||
Access(registers_[register_index_].low);
|
||||
effective_address_[1] += register_delta_ << 1;
|
||||
|
||||
// Drop the bottom bit.
|
||||
operand_[0].w >>= 1;
|
||||
register_index_ += register_delta_;
|
||||
MoveToState(MOVEMtoM_l_write);
|
||||
|
||||
BeginState(MOVEMtoM_finish):
|
||||
Prefetch(); // np
|
||||
MoveToState(Decode);
|
||||
|
||||
//
|
||||
// Various states TODO.
|
||||
//
|
||||
|
@ -99,6 +99,10 @@ struct ProcessorBase: public InstructionSet::M68k::NullFlowController {
|
||||
/// determine total operation cost.
|
||||
bool did_bit_op_high_ = false;
|
||||
|
||||
/// Two bits of state for MOVEM, being the curent register and what to
|
||||
/// add to it to get to the next register.
|
||||
int register_index_ = 0, register_delta_ = 0;
|
||||
|
||||
// A lookup table that aids with effective address calculation in
|
||||
// predecrement and postincrement modes; index as [size][register]
|
||||
// and note that [0][7] is 2 rather than 1.
|
||||
|
Loading…
x
Reference in New Issue
Block a user