mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-19 08:31:11 +00:00
Imports third-party tests for ABCD, and thereby fixes ABCD.
This commit is contained in:
parent
8182b0363f
commit
8dace34e63
@ -11,6 +11,7 @@
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
|
||||
#define LOG_TRACE
|
||||
#include "68000.hpp"
|
||||
|
||||
/*!
|
||||
@ -66,17 +67,18 @@ class RAM68000: public CPU::MC68000::BusHandler {
|
||||
|
||||
case Microcycle::SelectWord | Microcycle::Read:
|
||||
cycle.value->full = ram_[word_address];
|
||||
printf("r %04x from %08x \n", cycle.value->full, *cycle.address);
|
||||
break;
|
||||
case Microcycle::SelectByte | Microcycle::Read:
|
||||
cycle.value->halves.low = ram_[word_address] >> cycle.byte_shift();
|
||||
break;
|
||||
case Microcycle::SelectWord:
|
||||
printf("w %08x of %04x\n", *cycle.address, cycle.value->full);
|
||||
ram_[word_address] = cycle.value->full;
|
||||
break;
|
||||
case Microcycle::SelectByte:
|
||||
ram_[word_address] = (cycle.value->full & cycle.byte_mask()) | (ram_[word_address] & (0xffff ^ cycle.byte_mask()));
|
||||
ram_[word_address] = uint16_t(
|
||||
(cycle.value->halves.low << cycle.byte_shift()) |
|
||||
(ram_[word_address] & cycle.untouched_byte_mask())
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -208,7 +210,7 @@ class CPU::MC68000::ProcessorStorageTests {
|
||||
_machine.reset();
|
||||
}
|
||||
|
||||
- (void)testABCD {
|
||||
- (void)testABCDLong {
|
||||
for(int d = 0; d < 100; ++d) {
|
||||
_machine.reset(new RAM68000());
|
||||
_machine->set_program({
|
||||
@ -515,4 +517,134 @@ class CPU::MC68000::ProcessorStorageTests {
|
||||
// XCTAssert(!falseInvalids.count, "%@ opcodes should be valid but aren't: %@", @(falseInvalids.count), falseInvalids.hexDump);
|
||||
}
|
||||
|
||||
// MARK: - Tests below this line were ported from those of the Portable 68k emulator;
|
||||
// that emulator does not include a licence. It reports that all tests were verified
|
||||
// against an Amiga.
|
||||
|
||||
- (void)testABCD {
|
||||
_machine->set_program({
|
||||
0xc302, // ABCD D2, D1
|
||||
});
|
||||
auto state = _machine->get_processor_state();
|
||||
state.data[1] = 0x1234567a;
|
||||
state.data[2] = 0xf745ff78;
|
||||
_machine->set_processor_state(state);
|
||||
_machine->run_for_instructions(2);
|
||||
|
||||
state = _machine->get_processor_state();
|
||||
XCTAssert(state.status & CPU::MC68000::Flag::Carry);
|
||||
XCTAssertEqual(state.data[1], 0x12345658);
|
||||
XCTAssertEqual(state.data[2], 0xf745ff78);
|
||||
}
|
||||
|
||||
- (void)testABCDZero {
|
||||
_machine->set_program({
|
||||
0xc302, // ABCD D2, D1
|
||||
});
|
||||
auto state = _machine->get_processor_state();
|
||||
state.data[1] = 0x12345600;
|
||||
state.data[2] = 0x12345600;
|
||||
state.status = CPU::MC68000::Flag::Zero;
|
||||
_machine->set_processor_state(state);
|
||||
_machine->run_for_instructions(2);
|
||||
|
||||
state = _machine->get_processor_state();
|
||||
XCTAssert(state.status & CPU::MC68000::Flag::Zero);
|
||||
XCTAssertEqual(state.data[1], 0x12345600);
|
||||
XCTAssertEqual(state.data[2], 0x12345600);
|
||||
}
|
||||
|
||||
- (void)testABCDNegative {
|
||||
_machine->set_program({
|
||||
0xc302, // ABCD D2, D1
|
||||
});
|
||||
auto state = _machine->get_processor_state();
|
||||
state.data[1] = 0x12345645;
|
||||
state.data[2] = 0x12345654;
|
||||
state.status = CPU::MC68000::Flag::Zero;
|
||||
_machine->set_processor_state(state);
|
||||
_machine->run_for_instructions(2);
|
||||
|
||||
state = _machine->get_processor_state();
|
||||
XCTAssert(state.status & CPU::MC68000::Flag::Negative);
|
||||
XCTAssertEqual(state.data[1], 0x12345699);
|
||||
XCTAssertEqual(state.data[2], 0x12345654);
|
||||
}
|
||||
|
||||
- (void)testABCDWithX {
|
||||
_machine->set_program({
|
||||
0xc302, // ABCD D2, D1
|
||||
});
|
||||
auto state = _machine->get_processor_state();
|
||||
state.data[1] = 0x12345645;
|
||||
state.data[2] = 0x12345654;
|
||||
state.status = CPU::MC68000::Flag::Extend;
|
||||
_machine->set_processor_state(state);
|
||||
_machine->run_for_instructions(2);
|
||||
|
||||
state = _machine->get_processor_state();
|
||||
XCTAssert(state.status & CPU::MC68000::Flag::Carry);
|
||||
XCTAssertEqual(state.data[1], 0x12345600);
|
||||
XCTAssertEqual(state.data[2], 0x12345654);
|
||||
}
|
||||
|
||||
- (void)testABCDOverflow {
|
||||
_machine->set_program({
|
||||
0xc302, // ABCD D2, D1
|
||||
});
|
||||
auto state = _machine->get_processor_state();
|
||||
state.data[1] = 0x1234563e;
|
||||
state.data[2] = 0x1234563e;
|
||||
state.status = CPU::MC68000::Flag::Extend;
|
||||
_machine->set_processor_state(state);
|
||||
_machine->run_for_instructions(2);
|
||||
|
||||
state = _machine->get_processor_state();
|
||||
XCTAssert(state.status & CPU::MC68000::Flag::Overflow);
|
||||
XCTAssertEqual(state.data[1], 0x12345683);
|
||||
XCTAssertEqual(state.data[2], 0x1234563e);
|
||||
}
|
||||
|
||||
- (void)testABCDPredecDifferent {
|
||||
_machine->set_program({
|
||||
0xc30a, // ABCD -(A2), -(A1)
|
||||
});
|
||||
*_machine->ram_at(0x3000) = 0xa200;
|
||||
*_machine->ram_at(0x4000) = 0x1900;
|
||||
|
||||
auto state = _machine->get_processor_state();
|
||||
state.address[1] = 0x3001;
|
||||
state.address[2] = 0x4001;
|
||||
state.status = CPU::MC68000::Flag::Extend;
|
||||
_machine->set_processor_state(state);
|
||||
_machine->run_for_instructions(2);
|
||||
|
||||
state = _machine->get_processor_state();
|
||||
XCTAssert(state.status & CPU::MC68000::Flag::Carry);
|
||||
XCTAssert(state.status & CPU::MC68000::Flag::Extend);
|
||||
XCTAssertEqual(state.address[1], 0x3000);
|
||||
XCTAssertEqual(state.address[2], 0x4000);
|
||||
XCTAssertEqual(*_machine->ram_at(0x3000), 0x2200);
|
||||
XCTAssertEqual(*_machine->ram_at(0x4000), 0x1900);
|
||||
}
|
||||
|
||||
- (void)testABCDPredecSame {
|
||||
_machine->set_program({
|
||||
0xc309, // ABCD -(A1), -(A1)
|
||||
});
|
||||
*_machine->ram_at(0x3000) = 0x19a2;
|
||||
|
||||
auto state = _machine->get_processor_state();
|
||||
state.address[1] = 0x3002;
|
||||
state.status = CPU::MC68000::Flag::Extend;
|
||||
_machine->set_processor_state(state);
|
||||
_machine->run_for_instructions(2);
|
||||
|
||||
state = _machine->get_processor_state();
|
||||
XCTAssert(state.status & CPU::MC68000::Flag::Carry);
|
||||
XCTAssert(state.status & CPU::MC68000::Flag::Extend);
|
||||
XCTAssertEqual(state.address[1], 0x3000);
|
||||
XCTAssertEqual(*_machine->ram_at(0x3000), 0x22a2);
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -53,7 +53,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
const HalfCycles remaining_duration = duration + half_cycles_left_to_run_;
|
||||
|
||||
#ifdef LOG_TRACE
|
||||
static bool should_log = false;
|
||||
static bool should_log = true;
|
||||
#endif
|
||||
|
||||
// This loop counts upwards rather than downwards because it simplifies calculation of
|
||||
@ -289,10 +289,10 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
}
|
||||
|
||||
#ifdef LOG_TRACE
|
||||
const uint32_t fetched_pc = (program_counter_.full - 4)&0xffffff;
|
||||
// const uint32_t fetched_pc = (program_counter_.full - 4)&0xffffff;
|
||||
|
||||
should_log |= fetched_pc == 0x401142;
|
||||
should_log &= fetched_pc != 0x4011AA;
|
||||
// should_log |= fetched_pc == 0x401142;
|
||||
// should_log &= fetched_pc != 0x4011AA;
|
||||
|
||||
// should_log = (fetched_pc >= 0x408D66) && (fetched_pc <= 0x408D84);
|
||||
#endif
|
||||
|
@ -808,7 +808,7 @@ struct ProcessorStorageConstructor {
|
||||
// Temporary storage for the Program fields.
|
||||
ProcessorBase::Program program;
|
||||
|
||||
// if(instruction == 0xc302) {
|
||||
// if(instruction == 0xc30a) {
|
||||
// printf("");
|
||||
// }
|
||||
|
||||
@ -1831,26 +1831,15 @@ struct ProcessorStorageConstructor {
|
||||
// Decodes the format used by ABCD and SBCD.
|
||||
case Decoder::ABCD_SBCD: {
|
||||
if(instruction & 8) {
|
||||
program.source = &storage_.source_bus_data_[0];
|
||||
program.destination = &storage_.destination_bus_data_[0];
|
||||
program.source_address = &storage_.address_[ea_register];
|
||||
program.destination_address = &storage_.address_[data_register];
|
||||
program.set_source(storage_, Ind, ea_register);
|
||||
program.set_destination(storage_, Ind, data_register);
|
||||
|
||||
const int source_dec = dec(ea_register);
|
||||
const int destination_dec = dec(data_register);
|
||||
|
||||
int first_action = source_dec | MicroOp::SourceMask | MicroOp::DestinationMask;
|
||||
if(source_dec != destination_dec) {
|
||||
first_action = source_dec | MicroOp::SourceMask;
|
||||
op(destination_dec | MicroOp::DestinationMask);
|
||||
}
|
||||
|
||||
op( first_action,
|
||||
seq("n nr nrd np nw", { a(ea_register), a(data_register), a(data_register) }, false));
|
||||
op(Action::PerformOperation);
|
||||
op(MicroOp::SourceMask | dec(ea_register), seq("n nr", { a(ea_register) }, false ));
|
||||
op(MicroOp::DestinationMask | dec(data_register), seq("nrd np", { a(data_register) }, false ));
|
||||
op(Action::PerformOperation, seq("nw", { a(data_register) }, false));
|
||||
} else {
|
||||
program.source = &storage_.data_[ea_register];
|
||||
program.destination = &storage_.data_[data_register];
|
||||
program.set_source(storage_, Dn, ea_register);
|
||||
program.set_destination(storage_, Dn, data_register);
|
||||
|
||||
op(Action::PerformOperation, seq("np n"));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user