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:
parent
a0f0f73bde
commit
ae3cd924e8
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user