diff --git a/EightBit.sln b/EightBit.sln index 03f8c06..fe8aee1 100644 --- a/EightBit.sln +++ b/EightBit.sln @@ -33,6 +33,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MC6850", "MC6850\src\MC6850 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unittest_MC6809", "MC6809\unittest\unittest_MC6809.vcxproj", "{9EFEA22E-E981-4342-BE17-7DD0F33F1F52}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "M6532", "M6532\src\M6532.vcxproj", "{61ACB9AF-314F-4D9E-BFF4-96BC85F38278}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -161,6 +163,14 @@ Global {9EFEA22E-E981-4342-BE17-7DD0F33F1F52}.Release|x64.Build.0 = Release|x64 {9EFEA22E-E981-4342-BE17-7DD0F33F1F52}.Release|x86.ActiveCfg = Release|Win32 {9EFEA22E-E981-4342-BE17-7DD0F33F1F52}.Release|x86.Build.0 = Release|Win32 + {61ACB9AF-314F-4D9E-BFF4-96BC85F38278}.Debug|x64.ActiveCfg = Debug|x64 + {61ACB9AF-314F-4D9E-BFF4-96BC85F38278}.Debug|x64.Build.0 = Debug|x64 + {61ACB9AF-314F-4D9E-BFF4-96BC85F38278}.Debug|x86.ActiveCfg = Debug|Win32 + {61ACB9AF-314F-4D9E-BFF4-96BC85F38278}.Debug|x86.Build.0 = Debug|Win32 + {61ACB9AF-314F-4D9E-BFF4-96BC85F38278}.Release|x64.ActiveCfg = Release|x64 + {61ACB9AF-314F-4D9E-BFF4-96BC85F38278}.Release|x64.Build.0 = Release|x64 + {61ACB9AF-314F-4D9E-BFF4-96BC85F38278}.Release|x86.ActiveCfg = Release|Win32 + {61ACB9AF-314F-4D9E-BFF4-96BC85F38278}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -180,4 +190,13 @@ Global GlobalSection(Performance) = preSolution HasPerformanceSessions = true EndGlobalSection + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection EndGlobal diff --git a/M6532/documentation/R6532_datasheet.pdf b/M6532/documentation/R6532_datasheet.pdf new file mode 100644 index 0000000..e2bae00 Binary files /dev/null and b/M6532/documentation/R6532_datasheet.pdf differ diff --git a/M6532/documentation/mos_6532_riot.pdf b/M6532/documentation/mos_6532_riot.pdf new file mode 100644 index 0000000..3abe5b9 Binary files /dev/null and b/M6532/documentation/mos_6532_riot.pdf differ diff --git a/M6532/inc/M6532.h b/M6532/inc/M6532.h new file mode 100644 index 0000000..eb1071a --- /dev/null +++ b/M6532/inc/M6532.h @@ -0,0 +1,249 @@ +#pragma once + +#include + +#include + +/* + PIA 6532 combined timer, IO and 128 bytes RAM + ============================================= + + MOS 6532 pin configuration + -------------------------- + ____________ + | |_| | + VSS -| 1 40|- A6 + | | + A5 -| 2 39|- 02 + | | + A4 -| 3 38|- CS1 + | | ___ + A3 -| 4 37|- CS2 + | | __ + A2 -| 5 36|- RS + | | + A1 -| 6 35|- R/W + | | ___ + A0 -| 7 34|- RES + | | + PA0 -| 8 33|- D0 + | | + PA1 -| 9 32|- D1 + | | + PA2 -|10 31|- D2 + | | + PA3 -|11 30|- D3 + | | + PA4 -|12 29|- D4 + | | + PA5 -|13 28|- D5 + | | + PA6 -|14 27|- D6 + | | + PA7 -|15 26|- D7 + | | ___ + PB7 -|16 25|- IRQ + | | + PB6 -|17 24|- PB0 + | | + PB5 -|18 23|- PB1 + | | + PB4 -|19 22|- PB2 + | | + Vcc -|20 21|- PB3 + |____________| + + VSS = power + A0-A6 = address + PA0-PA7 = port A + PB0-PB7 = port B + Vcc = ground + 02 = clock input + CS1 = chip select 1 + CS2 = chip select 2 (low) + RS = RAM select (low) + R/W = read/write + RES = reset (low) + D0 - D7 = data + IRQ = interrupt request (low) + + MOS 6532 Block Diagram + ====================== + ___________ _____________ + D0 <---->| | __ | DATA | + D1 <---->| DATA | ||<---->| DIRECTION | + D2 <---->| BUS | || | CONTROL | + D3 <---->| BUFFER |<---->|| | REGISTER | + D4 <---->| | || | A | + D5 <---->| | || |_____________|----- + D6 <---->| | || | + D7 <---->|___________| || _____________ | + || | OUTPUT | | + ___________ ||<---->| REGISTER A | | + CS1 ---->| | || |_____________| | + ___ | CHIP | || | | + CS2 ---->| SELECT | || V | + | R/W | || _____________ | + 02 ---->| | || | |<---- + | | || | PERIPHERAL |<----> PA7 + R/W ---->| | || | DATA |<----> PA6 + ___ | | ||<-----| BUFFER |<----> PA5 + RES ---->|___________| || | A |<----> PA4 + || | |<----> PA3 + ___________ || | |<----> PA2 + __ | 128 x 8 | || | |<----> PA1 + RS ---->| RAM |<---->|| |_____________|<----> PA0 + |___________| || + || _____________ + || | |<----> PB7 + ___________ || | PERIPHERAL |<----> PB6 + ___ | INTERRUPT | || | DATA |<----> PB5 + IRQ ---->| CONTROL |<---->||<-----| BUFFER |<----> PB4 + |___________| || | B |<----> PB3 + ^ || | |<----> PB2 + | || | |<----> PB1 + V || | |<----> PB0 + ___________ || |_____________|<---- + | INTERVAL | || | | + | TIMER |<---->|| V | + |___________| || _____________ | + ___________ || | OUTPUT | | + A0 ---->| | ||<---->| REGISTER B | | + A1 ---->| | || |_____________| | + A2 ---->| ADDRESS | || | + A3 ---->| DECODERS | || _____________ | + A4 ---->| | || | DATA |----- + A5 ---->| | || | DIRECTION | + A6 ---->|___________| ||<---->| CONTROL | + -- | REGISTER | + | B | + |_____________| +*/ + + +namespace EightBit { + class M6532 final : public Chip { + public: + M6532() noexcept; + virtual ~M6532() = default; + + /* + 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 + 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; } + + // CHIP SELECT 1, active high + PinLevel& CS1() { return m_cs1; } + + // CHIP SELECT 2, active low + PinLevel& CS2() { return m_cs2; } + + /* + Data Bus (D0-D7) + The 6532 has eight bi-directional data pins (D0-D7). These pins connect to the system's data lines and + 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; } + + /* + Peripheral Data Ports + The 6532 has 16 pins available for peripheral I/O operations. Each pin is individually software programmable + to act as either an input or an output. The 16 pins are divided into 2 8-bit ports, PA0-PA7 and PB0-PB7. + PA7 also has other uses which are discussed in later sections. The pins are set up as an input by writing a + "0" into the corresponding bit of the data direction register. A "1" into the data direction register will cause + its corresponding bit to be an output. When in the input mode, the peripheral output buffers are in the "1" + state and pull-up device acts as less than one TTL load to the peripheral data lines. On a Read operation, the + microprocessor unit reads the peripheral pin. When the peripheral device gets information from the 6532 it + receives data stored in the data register. The microprocessor will read correct information if the peripheral + lines are greater than 2.0 volts for a "1" and less than 0.8 volts for a "0" as the peripheral pins are all TTL + compatible. Pins PB0-PB7 are also capable of sourcing 3 ma at 1.5v, thus making them capable of Darlington + drive. + */ + uint8_t& PA() { return m_pa; } + uint8_t& PB() { return m_pb; } + + /* ___ + Reset (RES) + During system initialization a logic "0" on the RES input will cause a zeroing of all four I/O registers. This + in turn will cause all I/O buses to act as inputs thus protecting external components from possible damage + and erroneous data while the system is being configured under software control. The Data Bus Buffers are + 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; } + + /* + 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; } + + /* ___ + Interrupt Request (IRQ) + The IRQ pin is an interrupt pin from the interrupt control logic. The pin will be normally high with a low indicating + 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; } + + void tick(); + + virtual void initialise() final; + + void reset(); + + private: + enum EdgeDetect { Positive, Negative }; + enum TimerIncrement { One = 1, Eight = 8, SixtyFour = 64, OneThousandAndTwentyFour = 1024 }; + + auto& RAM() { return m_ram; } + + auto& DDRA() { return m_ddra; } + auto& DDRB() { return m_ddrb; } + + auto& IF() { return m_interruptFlags; } + + bool selected() { return raised(CS1()) && lowered(CS2()); } + + uint8_t m_address; + uint8_t m_data; + + uint8_t m_pa; + uint8_t m_dra; + uint8_t m_ddra; + + uint8_t m_pb; + 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; + bool m_allowPA7Interrupts; + EdgeDetect m_edgeDetection; + + TimerIncrement m_timerIncrement; + uint8_t m_currentIncrement; + uint8_t m_timerInterval; + bool m_timerInterrupt; + + uint8_t m_interruptFlags; + }; +} diff --git a/M6532/src/M6532.cpp b/M6532/src/M6532.cpp new file mode 100644 index 0000000..dfe5cd3 --- /dev/null +++ b/M6532/src/M6532.cpp @@ -0,0 +1,139 @@ +#include "stdafx.h" +#include "M6532.h" + +#include + +EightBit::M6532::M6532() noexcept { +} + + +/* +RAM—128 Bytes (1024 Bits) +The 128 x 8 Read/Write memory acts as a conventional static RAM. Data can be written into the RAM from +the microprocessor by selecting the chip (CS1 = 1, CS2 = 0) and by setting RS to a logic 0 (0.4v). Address +lines AO through A6 are then used to select the desired byte of storage. +*/ + +/* + __ + RS R/W A4 A3 A2 A1 A0 +Write RAM 0 0 - - - - - +Read RAM 0 1 - - - - - +Write DDRA 1 0 - - 0 0 1 +Read DDRA 1 1 - - 0 0 1 +Write DDRB 1 0 - - 0 1 1 +Read DDRB 1 1 - - 0 1 1 +Write Output Reg A 1 0 - - 0 0 0 +Read Output Reg A 1 1 - - 0 0 0 +Write Output Reg B 1 0 - - 0 1 0 +Read Output Reg B +Write Timer +1 1 0 1 0 ++ 1T 1 0 1 (a) 1 0 0 ++ 8T 1 0 1 (a) 1 0 1 ++ 64T t 0 1 (a) 1 1 0 ++ 1024T 1 0 1 (a) 1 1 1 +Read Timer 1 1 _ (a) 1 — 0 +Read Interrupt Flag(s) 1 1 — — 1 — 1 +Write Edge Detect Control 1 0 0 — 1 (b) (0) + +*/ + + +void EightBit::M6532::tick() { + + if (selected()) { + + // Process interrupts + + if (--m_currentIncrement == 0) { + m_currentIncrement = m_timerIncrement; + --m_timerInterval; + } + if (m_allowPA7Interrupts && (PA() & 0x80)) + IF() &= 0x40; + + if (m_allowTimerInterrupts && (m_timerInterval == 0)) + IF() &= 0x80; + + 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 { + + 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; + } + } + } + } +} + +void EightBit::M6532::initialise() { +} + +void EightBit::M6532::reset() { + PA() = m_dra = m_ddra = 0; // Zero port A registers + PB() = m_drb = m_ddrb = 0; // Zero port B registers + m_allowTimerInterrupts = m_allowPA7Interrupts = false; // Interrupts are disabled +} diff --git a/M6532/src/M6532.vcxproj b/M6532/src/M6532.vcxproj new file mode 100644 index 0000000..04a91d6 --- /dev/null +++ b/M6532/src/M6532.vcxproj @@ -0,0 +1,168 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {61ACB9AF-314F-4D9E-BFF4-96BC85F38278} + Win32Proj + M6532 + + + + StaticLibrary + true + v141 + Unicode + + + StaticLibrary + false + v141 + true + Unicode + + + StaticLibrary + true + v141 + Unicode + + + StaticLibrary + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + false + ..\inc;..\..\inc;$(IncludePath) + + + true + ..\inc;..\..\inc;$(IncludePath) + + + true + ..\inc;..\..\inc;$(IncludePath) + + + false + ..\inc;..\..\inc;$(IncludePath) + + + + Use + Level3 + true + NDEBUG;_LIB;%(PreprocessorDefinitions) + AdvancedVectorExtensions + false + stdcpp17 + true + + + Windows + true + true + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + stdcpp17 + true + + + Windows + true + + + + + Use + Level3 + Disabled + _DEBUG;_LIB;%(PreprocessorDefinitions) + stdcpp17 + true + + + Windows + true + + + + + Use + Level3 + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + AdvancedVectorExtensions + false + stdcpp17 + true + + + Windows + true + true + true + + + + + + + + + + Create + Create + Create + Create + + + + + + \ No newline at end of file diff --git a/M6532/src/M6532.vcxproj.filters b/M6532/src/M6532.vcxproj.filters new file mode 100644 index 0000000..72acbba --- /dev/null +++ b/M6532/src/M6532.vcxproj.filters @@ -0,0 +1,29 @@ +ο»Ώ + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/M6532/src/stdafx.cpp b/M6532/src/stdafx.cpp new file mode 100644 index 0000000..485139f Binary files /dev/null and b/M6532/src/stdafx.cpp differ diff --git a/M6532/src/stdafx.h b/M6532/src/stdafx.h new file mode 100644 index 0000000..bb74931 Binary files /dev/null and b/M6532/src/stdafx.h differ