mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +00:00
Begins a basic get/set state API, allowing some actual unit tests, implying an ABCD fix.
This commit is contained in:
parent
53b3d9cf9d
commit
0d7bbdad54
@ -64,6 +64,14 @@ class RAM68000: public CPU::MC68000::BusHandler {
|
||||
return HalfCycles(0);
|
||||
}
|
||||
|
||||
CPU::MC68000::Processor<RAM68000, true>::State get_processor_state() {
|
||||
return m68000_.get_state();
|
||||
}
|
||||
|
||||
void set_processor_state(const CPU::MC68000::Processor<RAM68000, true>::State &state) {
|
||||
m68000_.set_state(state);
|
||||
}
|
||||
|
||||
private:
|
||||
CPU::MC68000::Processor<RAM68000, true> m68000_;
|
||||
std::vector<uint16_t> ram_;
|
||||
@ -85,10 +93,24 @@ class RAM68000: public CPU::MC68000::BusHandler {
|
||||
}
|
||||
|
||||
- (void)testABCD {
|
||||
_machine->set_program({
|
||||
0xc100 // ABCD D0, D0
|
||||
});
|
||||
_machine->run_for(HalfCycles(400));
|
||||
for(int d = 0; d < 100; ++d) {
|
||||
_machine.reset(new RAM68000());
|
||||
_machine->set_program({
|
||||
0xc100 // ABCD D0, D0
|
||||
});
|
||||
|
||||
auto state = _machine->get_processor_state();
|
||||
const uint8_t bcd_d = ((d / 10) * 16) + (d % 10);
|
||||
state.data[0] = bcd_d;
|
||||
_machine->set_processor_state(state);
|
||||
|
||||
_machine->run_for(Cycles(40 + 6));
|
||||
|
||||
state = _machine->get_processor_state();
|
||||
const uint8_t double_d = (d * 2) % 100;
|
||||
const uint8_t bcd_double_d = ((double_d / 10) * 16) + (double_d % 10);
|
||||
XCTAssert(state.data[0] == bcd_double_d, "%02x + %02x = %02x; should equal %02x", bcd_d, bcd_d, state.data[0], bcd_double_d);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testSBCD {
|
||||
|
@ -157,12 +157,28 @@ class BusHandler {
|
||||
class ProcessorBase: public ProcessorStorage {
|
||||
};
|
||||
|
||||
struct ProcessorState {
|
||||
uint32_t data[8];
|
||||
uint32_t address[7];
|
||||
uint32_t user_stack_pointer, supervisor_stack_pointer;
|
||||
uint32_t program_counter;
|
||||
uint16_t status;
|
||||
|
||||
// TODO: More state needed to indicate current instruction, the processor's
|
||||
// progress through it, and anything it has fetched so far.
|
||||
// uint16_t current_instruction;
|
||||
};
|
||||
|
||||
template <class T, bool dtack_is_implicit> class Processor: public ProcessorBase {
|
||||
public:
|
||||
Processor(T &bus_handler) : ProcessorBase(), bus_handler_(bus_handler) {}
|
||||
|
||||
void run_for(HalfCycles duration);
|
||||
|
||||
using State = ProcessorState;
|
||||
State get_state();
|
||||
void set_state(const State &);
|
||||
|
||||
private:
|
||||
T &bus_handler_;
|
||||
};
|
||||
|
@ -93,7 +93,7 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
||||
int result = (destination & 0xf) + (source & 0xf) + (extend_flag_ ? 1 : 0);
|
||||
if(result > 0x9) result += 0x06;
|
||||
result += (destination & 0xf0) + (source & 0xf0);
|
||||
if(result > 0x90) result += 0x60;
|
||||
if((result&0xff0) > 0x90) result += 0x60;
|
||||
|
||||
// Set all flags essentially as if this were normal addition.
|
||||
zero_flag_ |= result & 0xff;
|
||||
@ -114,7 +114,7 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
||||
int result = (destination & 0xf) - (source & 0xf) - (extend_flag_ ? 1 : 0);
|
||||
if(result > 0x9) result -= 0x06;
|
||||
result += (destination & 0xf0) - (source & 0xf0);
|
||||
if(result > 0x90) result -= 0x60;
|
||||
if((result&0xff0) > 0x90) result -= 0x60;
|
||||
|
||||
// Set all flags essentially as if this were normal subtraction.
|
||||
zero_flag_ |= result & 0xff;
|
||||
@ -176,3 +176,26 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, bool dtack_is_implicit> ProcessorState Processor<T, dtack_is_implicit>::get_state() {
|
||||
write_back_stack_pointer();
|
||||
|
||||
State state;
|
||||
memcpy(state.data, data_, sizeof(state.data));
|
||||
memcpy(state.address, address_, sizeof(state.address));
|
||||
state.user_stack_pointer = stack_pointers_[0].full;
|
||||
state.supervisor_stack_pointer = stack_pointers_[1].full;
|
||||
|
||||
// TODO: status word.
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>::set_state(const ProcessorState &state) {
|
||||
memcpy(data_, state.data, sizeof(state.data));
|
||||
memcpy(address_, state.address, sizeof(state.address));
|
||||
stack_pointers_[0].full = state.user_stack_pointer;
|
||||
stack_pointers_[1].full = state.supervisor_stack_pointer;
|
||||
|
||||
// TODO: update address[7], once there's a status word to discern the mode this processor should now be in.
|
||||
}
|
||||
|
@ -388,7 +388,7 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() {
|
||||
ProcessorStorageConstructor constructor(*this);
|
||||
|
||||
// Create the exception programs.
|
||||
const size_t reset_offset = constructor.assemble_program("n- n- n- n- n- nn nF nf nV nv np np");
|
||||
const size_t reset_offset = constructor.assemble_program("n n n n n nn nF nf nV nv np np");
|
||||
|
||||
// Install operations.
|
||||
constructor.install_instructions();
|
||||
@ -401,3 +401,16 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() {
|
||||
effective_address_ = 0;
|
||||
is_supervisor_ = 1;
|
||||
}
|
||||
|
||||
void CPU::MC68000::ProcessorStorage::write_back_stack_pointer() {
|
||||
stack_pointers_[is_supervisor_] = address_[7];
|
||||
}
|
||||
|
||||
void CPU::MC68000::ProcessorStorage::set_is_supervisor(bool is_supervisor) {
|
||||
const int new_is_supervisor = is_supervisor ? 1 : 0;
|
||||
if(new_is_supervisor != is_supervisor_) {
|
||||
stack_pointers_[is_supervisor_] = address_[7];
|
||||
is_supervisor_ = new_is_supervisor;
|
||||
address_[7] = stack_pointers_[is_supervisor_];
|
||||
}
|
||||
}
|
||||
|
@ -141,6 +141,12 @@ class ProcessorStorage {
|
||||
MicroOp *active_micro_op_ = nullptr;
|
||||
BusStep *active_step_ = nullptr;
|
||||
|
||||
/// Copies address_[7] to the proper stack pointer based on current mode.
|
||||
void write_back_stack_pointer();
|
||||
|
||||
/// Sets or clears the supervisor flag, ensuring the stack pointer is properly updated.
|
||||
void set_is_supervisor(bool);
|
||||
|
||||
private:
|
||||
friend class ProcessorStorageConstructor;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user