1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-10-01 13:58:20 +00:00

Imports third-party tests for ABCD, and thereby fixes ABCD.

This commit is contained in:
Thomas Harte 2019-06-19 18:13:06 -04:00
parent 8182b0363f
commit 8dace34e63
3 changed files with 148 additions and 27 deletions

View File

@ -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

View File

@ -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

View File

@ -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"));
}