mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-29 20:31:46 +00:00
Formally decode bank/offset/type.
This commit is contained in:
parent
fa0a9aa611
commit
ae684edbe1
@ -113,87 +113,110 @@ struct InputOutputController {
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr uint32_t AddressMask = 0x1f'ffff;
|
||||
/// Decomposes an Archimedes bus address into bank, offset and type.
|
||||
struct Address {
|
||||
constexpr Address(uint32_t bus_address) noexcept {
|
||||
bank = (bus_address >> 16) & 0b111;
|
||||
type = Type((bus_address >> 19) & 0b11);
|
||||
offset = bus_address & 0b1111100;
|
||||
}
|
||||
|
||||
/// A value from 0 to 7 indicating the device being addressed.
|
||||
uint32_t bank;
|
||||
/// A seven-bit value which is a multiple of 4, indicating the address within the bank.
|
||||
uint32_t offset;
|
||||
/// Access type.
|
||||
enum class Type {
|
||||
Sync = 0b00,
|
||||
Fast = 0b01,
|
||||
Medium = 0b10,
|
||||
Slow = 0b11
|
||||
} type;
|
||||
};
|
||||
|
||||
bool read(uint32_t address, uint8_t &value) {
|
||||
const auto target = address & AddressMask;
|
||||
const Address target(address);
|
||||
value = 0xff;
|
||||
switch(target) {
|
||||
|
||||
switch(target.bank) {
|
||||
default:
|
||||
logger.error().append("Unrecognised IOC read from %08x", address);
|
||||
logger.error().append("Unrecognised IOC read from %08x i.e. bank %d / type %d", address, target.bank, target.type);
|
||||
break;
|
||||
|
||||
case 0x3200000 & AddressMask:
|
||||
value = control_ | 0xc0;
|
||||
value &= ~(i2c_.clock() ? 2 : 0);
|
||||
value &= ~(i2c_.data() ? 1 : 0);
|
||||
// logger.error().append("IOC control read: C:%d D:%d", !(value & 2), !(value & 1));
|
||||
return true;
|
||||
// Bank 0: internal registers.
|
||||
case 0:
|
||||
switch(target.offset) {
|
||||
default:
|
||||
logger.error().append("Unrecognised IOC bank 0 read; offset %02x", target.offset);
|
||||
break;
|
||||
|
||||
case 0x3200004 & AddressMask:
|
||||
value = serial_.input(IOCParty);
|
||||
irq_b_.clear(IRQB::KeyboardReceiveFull);
|
||||
observer_.update_interrupts();
|
||||
// logger.error().append("IOC keyboard receive: %02x", value);
|
||||
return true;
|
||||
case 0x00:
|
||||
value = control_ | 0xc0;
|
||||
value &= ~(i2c_.clock() ? 2 : 0);
|
||||
value &= ~(i2c_.data() ? 1 : 0);
|
||||
// logger.error().append("IOC control read: C:%d D:%d", !(value & 2), !(value & 1));
|
||||
break;
|
||||
|
||||
// IRQ A.
|
||||
case 0x3200010 & AddressMask:
|
||||
value = irq_a_.status;
|
||||
// logger.error().append("IRQ A status is %02x", value);
|
||||
return true;
|
||||
case 0x3200014 & AddressMask:
|
||||
value = irq_a_.request();
|
||||
// logger.error().append("IRQ A request is %02x", value);
|
||||
return true;
|
||||
case 0x3200018 & AddressMask:
|
||||
value = irq_a_.mask;
|
||||
// logger.error().append("IRQ A mask is %02x", value);
|
||||
return true;
|
||||
case 0x04:
|
||||
value = serial_.input(IOCParty);
|
||||
irq_b_.clear(IRQB::KeyboardReceiveFull);
|
||||
observer_.update_interrupts();
|
||||
// logger.error().append("IOC keyboard receive: %02x", value);
|
||||
break;
|
||||
|
||||
// IRQ B.
|
||||
case 0x3200020 & AddressMask:
|
||||
value = irq_b_.status;
|
||||
// logger.error().append("IRQ B status is %02x", value);
|
||||
return true;
|
||||
case 0x3200024 & AddressMask:
|
||||
value = irq_b_.request();
|
||||
// logger.error().append("IRQ B request is %02x", value);
|
||||
return true;
|
||||
case 0x3200028 & AddressMask:
|
||||
value = irq_b_.mask;
|
||||
// logger.error().append("IRQ B mask is %02x", value);
|
||||
return true;
|
||||
// IRQ A.
|
||||
case 0x10:
|
||||
value = irq_a_.status;
|
||||
// logger.error().append("IRQ A status is %02x", value);
|
||||
break;
|
||||
case 0x14:
|
||||
value = irq_a_.request();
|
||||
// logger.error().append("IRQ A request is %02x", value);
|
||||
break;
|
||||
case 0x18:
|
||||
value = irq_a_.mask;
|
||||
// logger.error().append("IRQ A mask is %02x", value);
|
||||
break;
|
||||
|
||||
// FIQ.
|
||||
case 0x3200030 & AddressMask:
|
||||
value = fiq_.status;
|
||||
logger.error().append("FIQ status is %02x", value);
|
||||
return true;
|
||||
case 0x3200034 & AddressMask:
|
||||
value = fiq_.request();
|
||||
logger.error().append("FIQ request is %02x", value);
|
||||
return true;
|
||||
case 0x3200038 & AddressMask:
|
||||
value = fiq_.mask;
|
||||
logger.error().append("FIQ mask is %02x", value);
|
||||
return true;
|
||||
// IRQ B.
|
||||
case 0x20:
|
||||
value = irq_b_.status;
|
||||
// logger.error().append("IRQ B status is %02x", value);
|
||||
break;
|
||||
case 0x24:
|
||||
value = irq_b_.request();
|
||||
// logger.error().append("IRQ B request is %02x", value);
|
||||
break;
|
||||
case 0x28:
|
||||
value = irq_b_.mask;
|
||||
// logger.error().append("IRQ B mask is %02x", value);
|
||||
break;
|
||||
|
||||
// Counters.
|
||||
case 0x3200040 & AddressMask:
|
||||
case 0x3200050 & AddressMask:
|
||||
case 0x3200060 & AddressMask:
|
||||
case 0x3200070 & AddressMask:
|
||||
value = counters_[(target >> 4) - 0x4].output & 0xff;
|
||||
// logger.error().append("%02x: Counter %d low is %02x", target, (target >> 4) - 0x4, value);
|
||||
return true;
|
||||
// FIQ.
|
||||
case 0x30:
|
||||
value = fiq_.status;
|
||||
logger.error().append("FIQ status is %02x", value);
|
||||
break;
|
||||
case 0x34:
|
||||
value = fiq_.request();
|
||||
logger.error().append("FIQ request is %02x", value);
|
||||
break;
|
||||
case 0x38:
|
||||
value = fiq_.mask;
|
||||
logger.error().append("FIQ mask is %02x", value);
|
||||
break;
|
||||
|
||||
case 0x3200044 & AddressMask:
|
||||
case 0x3200054 & AddressMask:
|
||||
case 0x3200064 & AddressMask:
|
||||
case 0x3200074 & AddressMask:
|
||||
value = counters_[(target >> 4) - 0x4].output >> 8;
|
||||
// logger.error().append("%02x: Counter %d high is %02x", target, (target >> 4) - 0x4, value);
|
||||
// Counters.
|
||||
case 0x40: case 0x50: case 0x60: case 0x70:
|
||||
value = counters_[(target.offset >> 4) - 0x4].output & 0xff;
|
||||
// logger.error().append("%02x: Counter %d low is %02x", target, (target >> 4) - 0x4, value);
|
||||
break;
|
||||
|
||||
case 0x44: case 0x54: case 0x64: case 0x74:
|
||||
value = counters_[(target.offset >> 4) - 0x4].output >> 8;
|
||||
// logger.error().append("%02x: Counter %d high is %02x", target, (target >> 4) - 0x4, value);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -201,113 +224,109 @@ struct InputOutputController {
|
||||
}
|
||||
|
||||
bool write(uint32_t address, uint8_t value) {
|
||||
const auto target = address & AddressMask;
|
||||
switch(target) {
|
||||
const Address target(address);
|
||||
switch(target.bank) {
|
||||
default:
|
||||
logger.error().append("Unrecognised IOC write of %02x at %08x", value, address);
|
||||
logger.error().append("Unrecognised IOC write of %02x to %08x i.e. bank %d / type %d", value, address, target.bank, target.type);
|
||||
break;
|
||||
|
||||
case 0x320'0000 & AddressMask:
|
||||
// TODO: does the rest of the control register relate to anything?
|
||||
control_ = value;
|
||||
i2c_.set_clock_data(!(value & 2), !(value & 1));
|
||||
return true;
|
||||
// Bank 0: internal registers.
|
||||
case 0:
|
||||
switch(target.offset) {
|
||||
default:
|
||||
logger.error().append("Unrecognised IOC bank 0 write; %02x to offset %02x", value, target.offset);
|
||||
break;
|
||||
|
||||
case 0x320'0004 & AddressMask:
|
||||
serial_.output(IOCParty, value);
|
||||
irq_b_.clear(IRQB::KeyboardTransmitEmpty);
|
||||
observer_.update_interrupts();
|
||||
return true;
|
||||
case 0x00:
|
||||
// TODO: does the rest of the control register relate to anything?
|
||||
control_ = value;
|
||||
i2c_.set_clock_data(!(value & 2), !(value & 1));
|
||||
break;
|
||||
|
||||
case 0x320'0014 & AddressMask:
|
||||
// b2: clear IF.
|
||||
// b3: clear IR.
|
||||
// b4: clear POR.
|
||||
// b5: clear TM[0].
|
||||
// b6: clear TM[1].
|
||||
irq_a_.clear(value & 0x7c);
|
||||
observer_.update_interrupts();
|
||||
return true;
|
||||
case 0x04:
|
||||
serial_.output(IOCParty, value);
|
||||
irq_b_.clear(IRQB::KeyboardTransmitEmpty);
|
||||
observer_.update_interrupts();
|
||||
break;
|
||||
|
||||
// Interrupts.
|
||||
case 0x320'0018 & AddressMask: irq_a_.mask = value; return true;
|
||||
case 0x320'0028 & AddressMask: irq_b_.mask = value; return true;
|
||||
case 0x320'0038 & AddressMask: fiq_.mask = value; return true;
|
||||
case 0x14:
|
||||
// b2: clear IF.
|
||||
// b3: clear IR.
|
||||
// b4: clear POR.
|
||||
// b5: clear TM[0].
|
||||
// b6: clear TM[1].
|
||||
irq_a_.clear(value & 0x7c);
|
||||
observer_.update_interrupts();
|
||||
break;
|
||||
|
||||
// Counters.
|
||||
case 0x320'0040 & AddressMask:
|
||||
case 0x320'0050 & AddressMask:
|
||||
case 0x320'0060 & AddressMask:
|
||||
case 0x320'0070 & AddressMask:
|
||||
counters_[(target >> 4) - 0x4].reload = uint16_t(
|
||||
(counters_[(target >> 4) - 0x4].reload & 0xff00) | value
|
||||
);
|
||||
return true;
|
||||
// Interrupts.
|
||||
case 0x18: irq_a_.mask = value; break;
|
||||
case 0x28: irq_b_.mask = value; break;
|
||||
case 0x38: fiq_.mask = value; break;
|
||||
|
||||
case 0x320'0044 & AddressMask:
|
||||
case 0x320'0054 & AddressMask:
|
||||
case 0x320'0064 & AddressMask:
|
||||
case 0x320'0074 & AddressMask:
|
||||
counters_[(target >> 4) - 0x4].reload = uint16_t(
|
||||
(counters_[(target >> 4) - 0x4].reload & 0x00ff) | (value << 8)
|
||||
);
|
||||
return true;
|
||||
// Counters.
|
||||
case 0x40: case 0x50: case 0x60: case 0x70:
|
||||
counters_[(target.offset >> 4) - 0x4].reload = uint16_t(
|
||||
(counters_[(target.offset >> 4) - 0x4].reload & 0xff00) | value
|
||||
);
|
||||
break;
|
||||
|
||||
case 0x320'0048 & AddressMask:
|
||||
case 0x320'0058 & AddressMask:
|
||||
case 0x320'0068 & AddressMask:
|
||||
case 0x320'0078 & AddressMask:
|
||||
counters_[(target >> 4) - 0x4].value = counters_[(target >> 4) - 0x4].reload;
|
||||
return true;
|
||||
case 0x44: case 0x54: case 0x64: case 0x74:
|
||||
counters_[(target.offset >> 4) - 0x4].reload = uint16_t(
|
||||
(counters_[(target.offset >> 4) - 0x4].reload & 0x00ff) | (value << 8)
|
||||
);
|
||||
break;
|
||||
|
||||
case 0x320'004c & AddressMask:
|
||||
case 0x320'005c & AddressMask:
|
||||
case 0x320'006c & AddressMask:
|
||||
case 0x320'007c & AddressMask:
|
||||
counters_[(target >> 4) - 0x4].output = counters_[(target >> 4) - 0x4].value;
|
||||
return true;
|
||||
case 0x48: case 0x58: case 0x68: case 0x78:
|
||||
counters_[(target.offset >> 4) - 0x4].value = counters_[(target.offset >> 4) - 0x4].reload;
|
||||
break;
|
||||
|
||||
case 0x327'0000 & AddressMask:
|
||||
logger.error().append("TODO: exteded external podule space");
|
||||
return true;
|
||||
|
||||
case 0x331'0000 & AddressMask:
|
||||
logger.error().append("TODO: 1772 / disk write");
|
||||
return true;
|
||||
|
||||
case 0x335'0000 & AddressMask:
|
||||
logger.error().append("TODO: LS374 / printer data write");
|
||||
return true;
|
||||
|
||||
case 0x335'0018 & AddressMask:
|
||||
logger.error().append("TODO: latch B write: %02x", value);
|
||||
return true;
|
||||
|
||||
case 0x335'0040 & AddressMask:
|
||||
logger.error().append("TODO: latch A write: %02x", value);
|
||||
return true;
|
||||
|
||||
case 0x335'0048 & AddressMask:
|
||||
logger.error().append("TODO: latch C write: %02x", value);
|
||||
return true;
|
||||
|
||||
case 0x336'0000 & AddressMask:
|
||||
logger.error().append("TODO: podule interrupt request");
|
||||
return true;
|
||||
|
||||
case 0x336'0004 & AddressMask:
|
||||
logger.error().append("TODO: podule interrupt mask");
|
||||
return true;
|
||||
|
||||
case 0x33a'0000 & AddressMask:
|
||||
logger.error().append("TODO: 6854 / econet write");
|
||||
return true;
|
||||
|
||||
case 0x33b'0000 & AddressMask:
|
||||
logger.error().append("TODO: 6551 / serial line write");
|
||||
return true;
|
||||
case 0x4c: case 0x5c: case 0x6c: case 0x7c:
|
||||
counters_[(target.offset >> 4) - 0x4].output = counters_[(target.offset >> 4) - 0x4].value;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// case 0x327'0000 & AddressMask: // Bank 7
|
||||
// logger.error().append("TODO: exteded external podule space");
|
||||
// return true;
|
||||
//
|
||||
// case 0x331'0000 & AddressMask:
|
||||
// logger.error().append("TODO: 1772 / disk write");
|
||||
// return true;
|
||||
//
|
||||
// case 0x335'0000 & AddressMask:
|
||||
// logger.error().append("TODO: LS374 / printer data write");
|
||||
// return true;
|
||||
//
|
||||
// case 0x335'0018 & AddressMask:
|
||||
// logger.error().append("TODO: latch B write: %02x", value);
|
||||
// return true;
|
||||
//
|
||||
// case 0x335'0040 & AddressMask:
|
||||
// logger.error().append("TODO: latch A write: %02x", value);
|
||||
// return true;
|
||||
//
|
||||
// case 0x335'0048 & AddressMask:
|
||||
// logger.error().append("TODO: latch C write: %02x", value);
|
||||
// return true;
|
||||
//
|
||||
// case 0x336'0000 & AddressMask:
|
||||
// logger.error().append("TODO: podule interrupt request");
|
||||
// return true;
|
||||
//
|
||||
// case 0x336'0004 & AddressMask:
|
||||
// logger.error().append("TODO: podule interrupt mask");
|
||||
// return true;
|
||||
//
|
||||
// case 0x33a'0000 & AddressMask:
|
||||
// logger.error().append("TODO: 6854 / econet write");
|
||||
// return true;
|
||||
//
|
||||
// case 0x33b'0000 & AddressMask:
|
||||
// logger.error().append("TODO: 6551 / serial line write");
|
||||
// return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user