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

Add timers that count.

This commit is contained in:
Thomas Harte 2024-03-07 11:39:26 -05:00
parent ae3cd924e8
commit d380cecdb7

View File

@ -153,41 +153,127 @@ struct Video {
struct Interrupts {
// TODO: timers, which decrement at 2Mhz.
void tick_timers() {
for(int c = 0; c < 4; c++) {
// Events happen only on a decrement to 0; a reload value of 0 effectively means 'don't count'.
if(!counters_[c].value && !counters_[c].reload) {
continue;
}
--counters_[c].value;
if(!counters_[c].value) {
counters_[c].value = counters_[c].reload;
// TODO: event triggered here.
}
}
}
bool read(uint32_t address, uint8_t &value) {
switch(address & 0x7f) {
const auto target = address & 0x7f;
switch(target) {
default: break;
case 0x10: // IRQ status A
value = irq_status_a();
case 0x00:
logger.error().append("TODO: IOC control read");
value = 0;
return true;
case 0x20: // IRQ status B
value = 0x00;
return true;
// IRQ A.
case 0x10: value = irq_a_.status; return true;
case 0x14: value = irq_a_.request(); return true;
case 0x18: value = irq_a_.mask; return true;
case 0x30: // FIQ status
value = 0x80;
// IRQ B.
case 0x20: value = irq_b_.status; return true;
case 0x24: value = irq_b_.request(); return true;
case 0x28: value = irq_b_.mask; return true;
// FIQ.
case 0x30: value = fiq_.status; return true;
case 0x34: value = fiq_.request(); return true;
case 0x38: value = fiq_.mask; return true;
// Counters.
case 0x40: case 0x50: case 0x60: case 0x70:
value = counters_[(target >> 4) - 0x4].output & 0xff;
return true;
case 0x44: case 0x54: case 0x64: case 0x74:
value = counters_[(target >> 4) - 0x4].output >> 8;
return true;
}
logger.error().append("TODO: IO controller read from %08x", address);
logger.error().append("TODO: IO controller read from %08x", address);
return false;
}
bool write(uint32_t address, uint8_t value) {
const auto target = address & 0x7f;
switch(target) {
default: break;
case 0x00:
logger.error().append("TODO: IOC control write %02x", value);
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].
return true;
// Interrupts.
case 0x18: irq_a_.mask = value; return true;
case 0x28: irq_b_.mask = value; return true;
case 0x38: fiq_.mask = value; return true;
// Counters.
case 0x40: case 0x50: case 0x60: case 0x70:
counters_[(target >> 4) - 0x4].reload = uint16_t(
(counters_[(target >> 4) - 0x4].reload & 0xff00) | value
);
return true;
case 0x44: case 0x54: case 0x64: case 0x74:
counters_[(target >> 4) - 0x4].reload = uint16_t(
(counters_[(target >> 4) - 0x4].reload & 0x00ff) | (value << 8)
);
return true;
case 0x48: case 0x58: case 0x68: case 0x78:
counters_[(target >> 4) - 0x4].value = counters_[(target >> 4) - 0x4].reload;
return true;
case 0x4c: case 0x5c: case 0x6c: case 0x7c:
counters_[(target >> 4) - 0x4].output = counters_[(target >> 4) - 0x4].value;
return true;
}
logger.error().append("TODO: IO controller write of %02x at %08x", value, address);
return false;
}
private:
uint8_t irq_status_a() const {
return irq_status_a_;
Interrupts() {
irq_a_.status = 0x80 | 0x10; // i.e. 'set always' + 'power-on'.
irq_b_.status = 0x00;
fiq_.status = 0x80; // 'set always'.
}
uint8_t irq_status_a_ = 0x80 | 0x10; // 0x80 = always; 0x10 = at power-on.
private:
struct Interrupt {
uint8_t status, mask;
uint8_t request() const {
return status & mask;
}
};
Interrupt irq_a_, irq_b_, fiq_;
struct Counter {
uint16_t value;
uint16_t reload;
uint16_t output;
};
Counter counters_[4];
};
/// Primarily models the MEMC.
@ -242,7 +328,9 @@ struct Memory {
return true;
} break;
case Zone::IOControllers: return ioc_.write(address, source);
case Zone::IOControllers:
ioc_.write(address, source);
return true;
case Zone::VideoController:
// TODO: handle byte writes correctly.
@ -305,13 +393,15 @@ struct Memory {
case Zone::IOControllers: {
if constexpr (std::is_same_v<IntT, uint8_t>) {
return ioc_.read(address, source);
ioc_.read(address, source);
return true;
} else {
// TODO: generalise this adaptation of an 8-bit device to the 32-bit bus, which probably isn't right anyway.
uint8_t value;
if(!ioc_.read(address, value)) {
return false;
}
ioc_.read(address, value);
// if(!ioc_.read(address, value)) {
// return false;
// }
source = value;
return true;
}
@ -610,10 +700,10 @@ class ConcreteMachine:
}
// TODO: pipeline prefetch?
// static bool log = false;
// if(log) {
// logger.info().append("%08x: %08x [r14:%08x]", executor_.pc(), instruction, executor_.registers()[14]);
// }
static bool log = false;
if(log) {
logger.info().append("%08x: %08x [r14:%08x]", executor_.pc(), instruction, executor_.registers()[14]);
}
InstructionSet::ARM::execute<arm_model>(instruction, executor_);
}