1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-28 21:49:27 +00:00

Add a 2Mhz tick for timers.

This commit is contained in:
Thomas Harte 2024-03-07 11:12:40 -05:00
parent a0f0f73bde
commit ae3cd924e8

View File

@ -151,6 +151,38 @@ struct Video {
}; };
struct Interrupts { struct Interrupts {
// TODO: timers, which decrement at 2Mhz.
void tick_timers() {
}
bool read(uint32_t address, uint8_t &value) {
switch(address & 0x7f) {
default: break;
case 0x10: // IRQ status A
value = irq_status_a();
return true;
case 0x20: // IRQ status B
value = 0x00;
return true;
case 0x30: // FIQ status
value = 0x80;
return true;
}
logger.error().append("TODO: IO controller read from %08x", address);
return false;
}
bool write(uint32_t address, uint8_t value) {
logger.error().append("TODO: IO controller write of %02x at %08x", value, address);
return false;
}
private:
uint8_t irq_status_a() const { uint8_t irq_status_a() const {
return irq_status_a_; return irq_status_a_;
} }
@ -210,9 +242,7 @@ struct Memory {
return true; return true;
} break; } break;
case Zone::IOControllers: case Zone::IOControllers: return ioc_.write(address, source);
logger.error().append("TODO: Write to IO controllers of %08x to %08x", source, address);
break;
case Zone::VideoController: case Zone::VideoController:
// TODO: handle byte writes correctly. // TODO: handle byte writes correctly.
@ -273,24 +303,19 @@ struct Memory {
source = high_rom<IntT>(address); source = high_rom<IntT>(address);
return true; return true;
case Zone::IOControllers: case Zone::IOControllers: {
switch(address & 0x7f) { if constexpr (std::is_same_v<IntT, uint8_t>) {
default: break; return ioc_.read(address, source);
} else {
case 0x10: // IRQ status A // TODO: generalise this adaptation of an 8-bit device to the 32-bit bus, which probably isn't right anyway.
source = ioc_.irq_status_a(); uint8_t value;
return true; if(!ioc_.read(address, value)) {
return false;
case 0x20: // IRQ status B }
source = 0x00; source = value;
return true;
case 0x30: // FIQ status
source = 0x80;
return true; return true;
} }
logger.error().append("TODO: IO controller read from %08x", address); }
break;
default: default:
logger.error().append("TODO: read from %08x", address); logger.error().append("TODO: read from %08x", address);
@ -306,6 +331,10 @@ struct Memory {
update_mapping(); update_mapping();
} }
void tick_timers() {
ioc_.tick_timers();
}
private: private:
bool has_moved_rom_ = false; bool has_moved_rom_ = false;
std::array<uint8_t, 4*1024*1024> ram_{}; std::array<uint8_t, 4*1024*1024> ram_{};
@ -522,11 +551,20 @@ class ConcreteMachine:
public MachineTypes::TimedMachine, public MachineTypes::TimedMachine,
public MachineTypes::ScanProducer public MachineTypes::ScanProducer
{ {
// TODO: pick a sensible clock rate; this is just code for '20 MIPS, please'.
static constexpr int ClockRate = 20'000'000;
// Timers tick at 2Mhz, so figure out the proper divider for that.
static constexpr int TimerTarget = ClockRate / 2'000'000;
int timer_divider_ = TimerTarget;
public: public:
ConcreteMachine( ConcreteMachine(
const Analyser::Static::Target &target, const Analyser::Static::Target &target,
const ROMMachine::ROMFetcher &rom_fetcher const ROMMachine::ROMFetcher &rom_fetcher
) { ) {
set_clock_rate(ClockRate);
constexpr ROM::Name risc_os = ROM::Name::AcornRISCOS319; constexpr ROM::Name risc_os = ROM::Name::AcornRISCOS319;
ROM::Request request(risc_os); ROM::Request request(risc_os);
auto roms = rom_fetcher(request); auto roms = rom_fetcher(request);
@ -535,10 +573,6 @@ class ConcreteMachine:
} }
executor_.bus.set_rom(roms.find(risc_os)->second); executor_.bus.set_rom(roms.find(risc_os)->second);
// TODO: pick a sensible clock rate; this is just code for '20 MIPS, please'.
set_clock_rate(20'000'000);
insert_media(target.media); insert_media(target.media);
} }
@ -557,7 +591,13 @@ class ConcreteMachine:
static uint32_t last_pc = 0; static uint32_t last_pc = 0;
auto instructions = cycles.as<int>(); auto instructions = cycles.as<int>();
while(instructions--) {
while(instructions) {
auto run_length = std::min(timer_divider_, instructions);
instructions -= run_length;
timer_divider_ -= run_length;
while(run_length--) {
uint32_t instruction; uint32_t instruction;
if(!executor_.bus.read(executor_.pc(), instruction, executor_.registers().mode(), false)) { if(!executor_.bus.read(executor_.pc(), instruction, executor_.registers().mode(), false)) {
logger.info().append("Prefetch abort at %08x; last good was at %08x", executor_.pc(), last_pc); logger.info().append("Prefetch abort at %08x; last good was at %08x", executor_.pc(), last_pc);
@ -576,6 +616,14 @@ class ConcreteMachine:
// } // }
InstructionSet::ARM::execute<arm_model>(instruction, executor_); InstructionSet::ARM::execute<arm_model>(instruction, executor_);
} }
if(!timer_divider_) {
executor_.bus.tick_timers();
timer_divider_ = TimerTarget;
}
}
} }
// MARK: - MediaTarget // MARK: - MediaTarget