diff --git a/Machines/Acorn/Archimedes/InputOutputController.hpp b/Machines/Acorn/Archimedes/InputOutputController.hpp index 3ebbc33f3..ac7e6e18c 100644 --- a/Machines/Acorn/Archimedes/InputOutputController.hpp +++ b/Machines/Acorn/Archimedes/InputOutputController.hpp @@ -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; }