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

Attempt to wire up timer interrupts.

This commit is contained in:
Thomas Harte 2024-03-12 11:34:31 -04:00
parent 6efc41ded7
commit c6b91559e1
3 changed files with 78 additions and 23 deletions

View File

@ -20,6 +20,11 @@ namespace InstructionSet::ARM {
/// memory. No hooks are currently provided for applying realistic timing.
template <Model model, typename MemoryT>
struct Executor {
template <typename... Args>
Executor(Args &&...args) : bus(std::forward<Args...>(args)...) {}
/// @returns @c true if @c condition implies an appropriate perform call should be made for this instruction,
/// @c false otherwise.
bool should_schedule(Condition condition) {
return registers_.test(condition);
}

View File

@ -170,6 +170,29 @@ struct Registers {
set_pc(uint32_t(type));
}
/// Applies an exception of @c type and returns @c true if: (i) it is IRQ or FIQ; (ii) the processor is currently accepting such interrupts.
/// Otherwise returns @c false.
template <Exception type>
bool interrupt() {
switch(type) {
case Exception::IRQ:
if(interrupt_flags_ & ConditionCode::IRQDisable) {
return false;
}
break;
case Exception::FIQ:
if(interrupt_flags_ & ConditionCode::FIQDisable) {
return false;
}
break;
default: return false;
}
exception<type>();
}
// MARK: - Condition tests.
/// @returns @c true if @c condition tests as true; @c false otherwise.

View File

@ -164,7 +164,19 @@ namespace IRQA {
static constexpr uint8_t SetAlways = 0x80;
}
namespace InterruptRequests {
static constexpr int IRQ = 0x01;
static constexpr int FIQ = 0x02;
};
struct Interrupts {
int interrupt_mask() const {
return
((irq_a_.request() | irq_b_.request()) ? InterruptRequests::IRQ : 0) |
(fiq_.request() ? InterruptRequests::FIQ : 0);
}
bool tick_timers() {
bool did_change_interrupts = false;
@ -180,8 +192,8 @@ struct Interrupts {
counters_[c].value = counters_[c].reload;
switch(c) {
case 0: did_change_interrupts |= irq_a_.apply(0x20); break;
case 1: did_change_interrupts |= irq_a_.apply(0x40); break;
case 0: did_change_interrupts |= irq_a_.apply(IRQA::Timer0); break;
case 1: did_change_interrupts |= irq_a_.apply(IRQA::Timer1); break;
default: break;
}
// TODO: events for timers 2 and 3. Also remove some branchyness.
@ -191,7 +203,7 @@ struct Interrupts {
return did_change_interrupts;
}
bool read(uint32_t address, uint8_t &value) {
bool read(uint32_t address, uint8_t &value) const {
const auto target = address & 0x7f;
logger.error().append("IO controller read from %08x", address);
switch(target) {
@ -240,12 +252,12 @@ struct Interrupts {
return true;
case 0x14:
logger.error().append("TODO: IRQ clear write %02x", value);
// b2: clear IF.
// b3: clear IR.
// b4: clear POR.
// b5: clear TM[0].
// b6: clear TM[1].
irq_a_.clear(value & 0x7c);
return true;
// Interrupts.
@ -292,6 +304,9 @@ private:
status |= value;
return status & mask;
}
void clear(uint8_t bits) {
status &= ~bits;
}
};
Interrupt irq_a_, irq_b_, fiq_;
@ -304,7 +319,14 @@ private:
};
/// Primarily models the MEMC.
template <typename IOCWriteDelegateT>
struct Memory {
Memory(IOCWriteDelegateT &ioc_write_delegate) : ioc_write_delegate_(ioc_write_delegate) {}
int interrupt_mask() const {
return ioc_.interrupt_mask();
}
void set_rom(const std::vector<uint8_t> &rom) {
std::copy(
rom.begin(),
@ -321,10 +343,6 @@ struct Memory {
return false;
}
if(address == 0x02000078 || address == 0x02400078) {
printf("%08x: %08x\n", address, source);
}
switch (write_zones_[(address >> 21) & 31]) {
case Zone::DMAAndMEMC:
if((address & 0b1110'0000'0000'0000'0000) == 0b1110'0000'0000'0000'0000) {
@ -365,6 +383,7 @@ struct Memory {
case Zone::IOControllers:
ioc_.write(address, source);
ioc_write_delegate_.did_write_ioc();
return true;
case Zone::VideoController:
@ -470,6 +489,7 @@ struct Memory {
std::array<uint8_t, 2*1024*1024> rom_;
Interrupts ioc_;
Video vidc_;
IOCWriteDelegateT &ioc_write_delegate_;
template <typename IntT>
IntT &physical_ram(uint32_t address) {
@ -692,7 +712,7 @@ class ConcreteMachine:
ConcreteMachine(
const Analyser::Static::Target &target,
const ROMMachine::ROMFetcher &rom_fetcher
) {
) : executor_(*this) {
set_clock_rate(ClockRate);
constexpr ROM::Name risc_os = ROM::Name::AcornRISCOS319;
@ -706,8 +726,11 @@ class ConcreteMachine:
insert_media(target.media);
}
private:
void did_write_ioc() {
test_interrupts();
}
private:
// MARK: - ScanProducer.
void set_scan_target(Outputs::Display::ScanTarget *scan_target) override {
(void)scan_target;
@ -716,15 +739,9 @@ class ConcreteMachine:
return Outputs::Display::ScanStatus();
}
std::set<uint32_t> all;
// MARK: - TimedMachine.
void run_for(Cycles cycles) override {
static uint32_t last_pc = 0;
// static uint32_t last_link = 0;
// static uint32_t last_r0 = 0;
// static uint32_t last_r1 = 0;
// static uint32_t last_r10 = 0;
auto instructions = cycles.as<int>();
@ -748,11 +765,9 @@ class ConcreteMachine:
static bool log = false;
all.insert(instruction);
if(executor_.pc() == 0x03802b40) {
printf("");
}
// if(executor_.pc() == 0x03802b40) {
// printf("");
// }
// log |= (executor_.pc() > 0x02000000 && executor_.pc() < 0x02000078);
// log |= executor_.pc() == 0x03801980;
// log |= (executor_.pc() > 0x03801000);
@ -814,12 +829,24 @@ class ConcreteMachine:
timer_divider_ = TimerTarget;
if(executor_.bus.tick_timers()) {
logger.error().append("TODO: Interrupts (or maybe in the main loop?)");
test_interrupts();
}
}
}
}
void test_interrupts() {
using Exception = InstructionSet::ARM::Registers::Exception;
const int requests = executor_.bus.interrupt_mask();
if((requests & InterruptRequests::FIQ) && executor_.registers().interrupt<Exception::FIQ>()) {
return;
}
if(requests & InterruptRequests::IRQ) {
executor_.registers().interrupt<Exception::IRQ>();
}
}
// MARK: - MediaTarget
bool insert_media(const Analyser::Static::Media &) override {
// int c = 0;
@ -834,7 +861,7 @@ class ConcreteMachine:
// MARK: - ARM execution
static constexpr auto arm_model = InstructionSet::ARM::Model::ARMv2;
InstructionSet::ARM::Executor<arm_model, Memory> executor_;
InstructionSet::ARM::Executor<arm_model, Memory<ConcreteMachine>> executor_;
};
}