diff --git a/M6532/inc/M6532.h b/M6532/inc/M6532.h index 26c8c59..ea57564 100644 --- a/M6532/inc/M6532.h +++ b/M6532/inc/M6532.h @@ -3,6 +3,8 @@ #include #include +#include +#include /* PIA 6532 combined timer, IO and 128 bytes RAM @@ -190,16 +192,16 @@ namespace EightBit { put into an OFF-STATE during Reset. Interrupt capability is disabled with the RES signal. The RES signal must be held low for at least one clock period when reset is required. */ - PinLevel& RES() { return m_res; } + DECLARE_PIN_INPUT(RES) - /* + /* _ Read/Write (R/W) The R/W signal is supplied by the microprocessor array and is used to control the transfer of data to and from the microprocessor array and the 6532. A high on the R/W pin allows the processor to read (with proper addressing) the data supplied by the 6532. A low on the R/W pin allows a write (with proper addressing) to the 6532. */ - PinLevel& RW() { return m_rw; } + DECLARE_PIN_INPUT(RW) /* ___ Interrupt Request (IRQ) @@ -207,7 +209,7 @@ namespace EightBit { an interrupt from the 6532. An external pull-up device is required. The IRQ pin may be activated by a transition on PA7 or timeout of the interval timer. */ - PinLevel& IRQ() { return m_irq; } + DECLARE_PIN_OUTPUT(IRQ) /* Data Bus (D0-D7) @@ -215,7 +217,7 @@ namespace EightBit { allow transfer of data to and from the microprocessor array. The output buffers remain in the off state except when a Read operation occurs and are capable of driving one standard TTL load and 130 pf. */ - uint8_t& data() { return m_data; } + auto& DATA() { return m_data; } /* Peripheral Data Ports @@ -236,28 +238,32 @@ namespace EightBit { /* Address Lines (A0-A6) - There are 7 address pins. In addition to these 7, there is 9 RAM SELECT pin. These pins, A0-A6 and RAM + There are 7 address pins. In addition to these 7, there is a RAM SELECT pin. These pins, A0-A6 and RAM SELECT, are always used as addressing pins. There are two additional pins which are used as CHIP SELECTS. They are pins CS1 and CS2. */ uint8_t& address() { return m_address; } // RAM SELECT, active low - PinLevel& RS() { return m_rs; } + DECLARE_PIN_INPUT(RS) // CHIP SELECT 1, active high - PinLevel& CS1() { return m_cs1; } + DECLARE_PIN_INPUT(CS1) // CHIP SELECT 2, active low - PinLevel& CS2() { return m_cs2; } + DECLARE_PIN_INPUT(CS2) - void tick(); + bool activated() { return powered() && selected(); } + bool selected() { return raised(CS1()) && lowered(CS2()); } - virtual void initialise() final; + Signal Accessing; + Signal Accessed; + + private: + void step(); void reset(); - private: enum EdgeDetect { Positive, Negative }; enum TimerIncrement { One = 1, Eight = 8, SixtyFour = 64, OneThousandAndTwentyFour = 1024 }; @@ -268,8 +274,6 @@ namespace EightBit { auto& IF() { return m_interruptFlags; } - bool selected() { return raised(CS1()) && lowered(CS2()); } - uint8_t m_address; uint8_t m_data; @@ -281,13 +285,6 @@ namespace EightBit { uint8_t m_drb; uint8_t m_ddrb; - PinLevel m_res; - PinLevel m_rw; - PinLevel m_irq; - PinLevel m_rs; - PinLevel m_cs1; - PinLevel m_cs2; - Ram m_ram = 0x80; bool m_allowTimerInterrupts; diff --git a/M6532/src/M6532.cpp b/M6532/src/M6532.cpp index 42e3dd3..35d5aef 100644 --- a/M6532/src/M6532.cpp +++ b/M6532/src/M6532.cpp @@ -4,98 +4,123 @@ #include EightBit::M6532::M6532() noexcept { + Ticked.connect([this](EightBit::EventArgs&) { + step(); + }); } -void EightBit::M6532::tick() { +DEFINE_PIN_LEVEL_CHANGERS(RES, M6532); +DEFINE_PIN_LEVEL_CHANGERS(RW, M6532); +DEFINE_PIN_LEVEL_CHANGERS(IRQ, M6532); +DEFINE_PIN_LEVEL_CHANGERS(RS, M6532); +DEFINE_PIN_LEVEL_CHANGERS(CS1, M6532); +DEFINE_PIN_LEVEL_CHANGERS(CS2, M6532); - if (selected()) { +void EightBit::M6532::step() { - // Process interrupts + resetCycles(); - if (--m_currentIncrement == 0) { - m_currentIncrement = m_timerIncrement; - --m_timerInterval; - } - if (m_allowPA7Interrupts && (PA() & 0x80)) - IF() &= 0x40; + if (!activated()) + return; - if (m_allowTimerInterrupts && (m_timerInterval == 0)) - IF() &= 0x80; + Accessing.fire(EventArgs::empty()); - const auto read = raised(RW()); - const auto write = lowered(RW()); - assert(read == !write); + if (lowered(RES())) { + reset(); + raise(RES()); + return; + } - const auto ram = lowered(RS()); - if (ram) { + if (--m_currentIncrement == 0) { + m_currentIncrement = m_timerIncrement; + --m_timerInterval; + } - auto& cell = RAM().reference(address() & 0x7f); - read ? data() = cell : cell = data(); + const bool interruptPA7 = m_allowPA7Interrupts && (PA() & Bit7); + if (interruptPA7) + setFlag(IF(), Bit6); + + const bool interruptTimer = m_allowTimerInterrupts && (m_timerInterval == 0); + if (interruptTimer) + setFlag(IF(), Bit7); + + interruptPA7 || interruptTimer ? lower(IRQ()) : raise(IRQ()); + + const auto read = raised(RW()); + const auto write = lowered(RW()); + assert(read == !write); + + const auto ram = lowered(RS()); + if (ram) { + + auto& cell = RAM().reference(address() & 0x7f); + read ? DATA() = cell : cell = DATA(); + + } else { + + const auto a0 = address() & 0b00001; + const auto a1 = address() & 0b00010; + const auto a2 = address() & 0b00100; + const auto a3 = address() & 0b01000; + const auto a4 = address() & 0b10000; + + const auto portControls = a2 == 0; + const auto otherControls = a2 == 1; + + if (portControls) { + + switch (a0 | a1) { + case 0b00: + // R/W output reg A + break; + case 0b01: + read ? DATA() = DDRA() : DDRA() = DATA(); + break; + case 0b10: + // R/W output reg B + break; + case 0b11: + read ? DATA() = DDRB() : DDRB() = DATA(); + break; + } } else { - const auto a0 = address() & 0b00001; - const auto a1 = address() & 0b00010; - const auto a2 = address() & 0b00100; - const auto a3 = address() & 0b01000; - const auto a4 = address() & 0b10000; + if (read && !a4 && a2) { + m_allowPA7Interrupts = !a1; + m_edgeDetection = a0 ? Positive : Negative; + } - const auto portControls = a2 == 0; - const auto otherControls = a2 == 1; + if (read && a2 && a0) { + DATA() = IF(); + clearFlag(IF(), Bit6); + } - if (portControls) { + m_allowTimerInterrupts = !!a3; - switch (a0 | a1) { + if (write && a4) { + m_timerInterval = DATA(); + switch (a1 | a0) { case 0b00: - // R/W output reg A + m_timerIncrement = One; break; case 0b01: - read ? data() = DDRA() : DDRA() = data(); + m_timerIncrement = Eight; break; case 0b10: - // R/W output reg B + m_timerIncrement = SixtyFour; break; case 0b11: - read ? data() = DDRB() : DDRB() = data(); + m_timerIncrement = OneThousandAndTwentyFour; break; } - - } else { - - if (read && !a4 && a2) { - m_allowPA7Interrupts = !a1; - m_edgeDetection = a0 ? Positive : Negative; - } - - if (read && a2 && a0) - data() = IF() & (0x80 & 0x40); - - m_allowTimerInterrupts = !!a3; - - if (write && a4) { - m_timerInterval = data(); - switch (a1 | a0) { - case 0b00: - m_timerIncrement = One; - break; - case 0b01: - m_timerIncrement = Eight; - break; - case 0b10: - m_timerIncrement = SixtyFour; - break; - case 0b11: - m_timerIncrement = OneThousandAndTwentyFour; - break; - } - m_currentIncrement = m_timerIncrement; - } + m_currentIncrement = m_timerIncrement; + clearFlag(IF(), Bit7); } } } -} -void EightBit::M6532::initialise() { + Accessed.fire(EventArgs::empty()); } void EightBit::M6532::reset() {