1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-09-29 16:55:59 +00:00

Gets as far as executing a first loop.

This commit is contained in:
Thomas Harte 2021-01-20 18:15:24 -05:00
parent e502d76371
commit e58608b25a
3 changed files with 102 additions and 26 deletions

View File

@ -118,9 +118,10 @@ template <
// }
}
void perform_all() {
// TEMPORARY (?). Execute all current instructions, unless
// and until one branches.
/*!
Executes up to the next branch.
*/
void run_to_branch() {
has_branched_ = false;
for(auto index: program_) {
const auto performer = performers_[index];

View File

@ -37,7 +37,9 @@ void Executor::set_rom(const std::vector<uint8_t> &rom) {
reset();
// TEMPORARY: just to test initial wiring.
perform_all();
for(int c = 0; c < 130; c++) {
run_to_branch();
}
}
void Executor::reset() {
@ -45,6 +47,49 @@ void Executor::reset() {
set_program_counter(uint16_t(memory_[0x1ffe] | (memory_[0x1fff] << 8)));
}
uint8_t Executor::read(uint16_t address) {
address &= 0x1fff;
switch(address) {
default: return memory_[address];
// TODO: external IO ports.
// "Port R"; sixteen four-bit ports
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
printf("TODO: Port R\n");
return 0xff;
// Ports P0P3.
case 0xe0: case 0xe1:
case 0xe2: case 0xe3:
case 0xe4: case 0xe5:
case 0xe8: case 0xe9:
printf("TODO: Ports P0P3\n");
return 0xff;
// Timers.
case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
printf("TODO: Timers\n");
return 0xff;
}
}
void Executor::write(uint16_t address, uint8_t value) {
address &= 0x1fff;
if(address < 0x60) {
memory_[address] = value;
return;
}
// TODO: all external IO ports.
}
void Executor::push(uint8_t value) {
write(s_, value);
--s_;
}
template <Operation operation, AddressingMode addressing_mode> void Executor::perform() {
// Deal with all modes that don't access memory up here;
// those that access memory will go through a slightly longer
@ -55,7 +100,7 @@ template <Operation operation, AddressingMode addressing_mode> void Executor::pe
#define next8() memory_[(program_counter_ + 1) & 0x1fff]
#define next16() (memory_[(program_counter_ + 1) & 0x1fff] | (memory_[(program_counter_ + 2) & 0x1fff] << 8))
printf("%d %d\n", int(operation), int(addressing_mode));
printf("%04x\t%d %d\n", program_counter_ & 0x1fff, int(operation), int(addressing_mode));
// Underlying assumption below: the instruction stream will never
// overlap with IO ports.
@ -78,17 +123,19 @@ template <Operation operation, AddressingMode addressing_mode> void Executor::pe
program_counter_ += 2;
return;
// case AddressingMode::Relative:
// These are all the branches...
// address = program_counter_ + size(addressing_mode) + int8_t(next8());
// return;
// Special-purpose addressing modes.
// case AddressingMode::ImmediateZeroPage:
case AddressingMode::Relative:
address = program_counter_ + 1 + size(addressing_mode) + int8_t(next8());
break;
case AddressingMode::SpecialPage: address = 0x1f00 | next8(); break;
case AddressingMode::ImmediateZeroPage:
// LDM only...
// return;
// case AddressingMode::SpecialPage: address = 0x1f00 | next8(); break;
// JSR only...
write(memory_[(program_counter_+2)&0x1fff], memory_[(program_counter_+1)&0x1fff]);
program_counter_ += 1 + size(addressing_mode);
return;
/* TODO:
@ -136,16 +183,23 @@ template <Operation operation, AddressingMode addressing_mode> void Executor::pe
// Check for a branch; those don't go through the memory accesses below.
switch(operation) {
case Operation::JMP:
case Operation::BRA: case Operation::JMP:
set_program_counter(uint16_t(address));
return;
case Operation::JSR:
// TODO: push!
case Operation::JSR: {
const auto return_address = program_counter_ - 1;
push(uint8_t(return_address >> 8));
push(uint8_t(return_address & 0xff));
set_program_counter(uint16_t(address));
return;
} return;
/* TODO: all other types of branches and calls. */
case Operation::BPL: if(!(negative_result_&0x80)) set_program_counter(uint16_t(address)); return;
case Operation::BMI: if(negative_result_&0x80) set_program_counter(uint16_t(address)); return;
case Operation::BEQ: if(!zero_result_) set_program_counter(uint16_t(address)); return;
case Operation::BNE: if(zero_result_) set_program_counter(uint16_t(address)); return;
/* TODO: all other types of branches. */
default: break;
}
@ -153,18 +207,20 @@ template <Operation operation, AddressingMode addressing_mode> void Executor::pe
assert(access_type(operation) != AccessType::None);
// TODO: full reading/writing logic here; only the first 96 bytes are RAM,
// there are also timers and IO ports to handle.
if constexpr(access_type(operation) == AccessType::Read) {
perform<operation>(&memory_[address & 0x1fff]);
uint8_t source = read(uint16_t(address));
perform<operation>(&source);
return;
}
uint8_t value = memory_[address & 0x1fff];
uint8_t value;
if constexpr(access_type(operation) == AccessType::ReadModifyWrite) {
value = read(uint16_t(address));
} else {
value = 0xff;
}
perform<operation>(&value);
memory_[address & 0x1fff] = value;
write(uint16_t(address), value);
}
template <Operation operation> void Executor::perform(uint8_t *operand [[maybe_unused]]) {
@ -201,6 +257,20 @@ template <Operation operation> void Executor::perform(uint8_t *operand [[maybe_u
case Operation::CLD: decimal_mode_ = false; break;
case Operation::SED: decimal_mode_ = true; break;
case Operation::DEX: --x_; set_nz(x_); break;
case Operation::INX: ++x_; set_nz(x_); break;
case Operation::DEY: --y_; set_nz(y_); break;
case Operation::INY: ++y_; set_nz(y_); break;
case Operation::DEC: --*operand; set_nz(*operand); break;
case Operation::INC: ++*operand; set_nz(*operand); break;
/*
Already removed from the instruction stream:
* all branches and jumps;
* LDM.
*/
default:
printf("Unimplemented operation: %d\n", int(operation));
assert(false);
@ -209,6 +279,7 @@ template <Operation operation> void Executor::perform(uint8_t *operand [[maybe_u
}
void Executor::set_program_counter(uint16_t address) {
printf("--- %04x ---\n", (address & 0x1fff) - 0x1000);
program_counter_ = address;
CachingExecutor::set_program_counter(address);
}

View File

@ -117,6 +117,10 @@ class Executor: public CachingExecutor {
uint8_t interrupt_disable_ = 0;
bool index_mode_ = false;
bool decimal_mode_ = false;
inline uint8_t read(uint16_t address);
inline void write(uint16_t address, uint8_t value);
inline void push(uint8_t value);
};
}