1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-30 04:50:08 +00:00

Begins a basic get/set state API, allowing some actual unit tests, implying an ABCD fix.

This commit is contained in:
Thomas Harte 2019-03-17 21:57:00 -04:00
parent 53b3d9cf9d
commit 0d7bbdad54
5 changed files with 87 additions and 7 deletions

View File

@ -64,6 +64,14 @@ class RAM68000: public CPU::MC68000::BusHandler {
return HalfCycles(0); 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: private:
CPU::MC68000::Processor<RAM68000, true> m68000_; CPU::MC68000::Processor<RAM68000, true> m68000_;
std::vector<uint16_t> ram_; std::vector<uint16_t> ram_;
@ -85,10 +93,24 @@ class RAM68000: public CPU::MC68000::BusHandler {
} }
- (void)testABCD { - (void)testABCD {
_machine->set_program({ for(int d = 0; d < 100; ++d) {
0xc100 // ABCD D0, D0 _machine.reset(new RAM68000());
}); _machine->set_program({
_machine->run_for(HalfCycles(400)); 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 { - (void)testSBCD {

View File

@ -157,12 +157,28 @@ class BusHandler {
class ProcessorBase: public ProcessorStorage { 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 { template <class T, bool dtack_is_implicit> class Processor: public ProcessorBase {
public: public:
Processor(T &bus_handler) : ProcessorBase(), bus_handler_(bus_handler) {} Processor(T &bus_handler) : ProcessorBase(), bus_handler_(bus_handler) {}
void run_for(HalfCycles duration); void run_for(HalfCycles duration);
using State = ProcessorState;
State get_state();
void set_state(const State &);
private: private:
T &bus_handler_; T &bus_handler_;
}; };

View File

@ -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); int result = (destination & 0xf) + (source & 0xf) + (extend_flag_ ? 1 : 0);
if(result > 0x9) result += 0x06; if(result > 0x9) result += 0x06;
result += (destination & 0xf0) + (source & 0xf0); 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. // Set all flags essentially as if this were normal addition.
zero_flag_ |= result & 0xff; 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); int result = (destination & 0xf) - (source & 0xf) - (extend_flag_ ? 1 : 0);
if(result > 0x9) result -= 0x06; if(result > 0x9) result -= 0x06;
result += (destination & 0xf0) - (source & 0xf0); 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. // Set all flags essentially as if this were normal subtraction.
zero_flag_ |= result & 0xff; 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.
}

View File

@ -388,7 +388,7 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() {
ProcessorStorageConstructor constructor(*this); ProcessorStorageConstructor constructor(*this);
// Create the exception programs. // 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. // Install operations.
constructor.install_instructions(); constructor.install_instructions();
@ -401,3 +401,16 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() {
effective_address_ = 0; effective_address_ = 0;
is_supervisor_ = 1; 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_];
}
}

View File

@ -141,6 +141,12 @@ class ProcessorStorage {
MicroOp *active_micro_op_ = nullptr; MicroOp *active_micro_op_ = nullptr;
BusStep *active_step_ = 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: private:
friend class ProcessorStorageConstructor; friend class ProcessorStorageConstructor;
}; };