Electronics Tinkerer
Projects 'N Stuff

EMMA-2

Last Update: 2023-07-09

Background

Since I built the original HackBrick Pro (an Apple-1 replica) in spring 2015, I have designed about six more 6502-based systems. All of these systems have been fairly resource limited, normally using 32k RAM and an 8k EEPROM with some miscellaneous I/O ICs scattered around. Most of these systems were built on breadboards, and thus fairly short-lived. In the back of my mind, however, I have been pushing around the idea of building a 65816 (originally 6502) based system that had a memory management system, a lot more than 32k ram, capability of running multiple process threads, hardware interrupt vector remapping, DMA, HDD support, graphics, ... In May, 2021 I decided to take a week off from using my (modern) computer which usually I spent a good chunk of each day staring at. During the week of no computer, I ran out of things to do (such as organizing the stacks of paper from the semester which had just finished), so I figured that I would work a bit on that "GUI" computer. I already had the datasheets printed for all the common ICs that I was planning on using, so I set to work drawing up schematic sheet for each section that I thought would be useful. At the end of the week, I started the process of transferring the hand-drawn schematics to KiCad so I could do the PCB layout for the system. Throughout the transfer (and routing process), I tried to fix any bugs that were present so that the "REV A" boards could be the only revision needed (with the potential for a few bodge wires, but nothing substantial). By mid August, I was confident that the main logic board was in a state that I could order it, so I whipped up a basic I/O card over the last few days of summer break and ordered everything needed to assemble the system.

System Architecture

The system is centered around the 65816 CPU that WDC sells. The CPU is a 8/16-bit upgrade to the 6502, meaning that code that runs on the 6502 will run on the 65816. This makes porting old subroutines to the new system significantly easier.

MMU and VM

The CPU also adds an upper 8 address lines (for 24 total address lines) which are called the "bank." These banks provided an easy way to create a memory management unit (MMU) for setting up a virtual memory (VM) system. Each bank is 64k in size and allows a single bank to be allocated for most threads. In addition to the bank address bits, the MMU also takes in 7 bits from the "HWPID" register so that each process can have fully isolated memory from all other processes. To determine which banks of physical ram to map to the virtual bank addresses provided by the CPU, there is two 32k ram ICs that make up the page table and the permissions table. The permissions stored in the table are fed into some logic to generate an ABORT signal to the CPU to prevent the currently executing instruction from modifying any data that it was operating on.

Interrupts

Onboard, there is an interrupt controller which allows for 8 potential interrupt sources and allows for masking of interrupts based on priority. The design is based off this one: Prioritised Interrupts - 6502.org The output from the interrupt controller is fed into the CPU's IRQ (maskable interrupt) input. The NMI (nonmaskable interrupt) input to the CPU is fed from the IRQ line on a 65C22 VIA which is intended to be used as a jiffy timer since the VIA contains a 16 bit timer that can run in free running "auto reload" mode. The remaining hardware pertaining to interrupts (not including reset) would be the COP vector trap/remapping circuit. The 65816 adds the COP (COProcessor) instruction which is intended to be trapped by some sort of coprocessor in the system, such as an FPU, like on old x86-based systems. As far as I can tell, there are no 65816 coprocessors available, so there is a small state machine onboard that detects when the CPU executes the COP instruction, latches the signature byte, and waits for the CPU to access the COP software interrupt vector. At this point, the circuit remaps the vector address read by the CPU to an index in a lookup table in the main ROM area (actually RAM when the MMU is enabled), allowing direct access to the correct vector without the need for software to find the COP's signature. The intent of this circuit was to provide a simple interface to create system calls. For example, you could run 'COP 0' to call a routine that prints a string to a buffer or 'COP 24' to fork the current process.

I/O Cards

There are 6 I/O card slots available for the user to plug in whatever I/O devices they can come up with. (For example: I/O, sound, video, networking, DMA, disk controller) Each slot is given a specific IRQ priority but the address that each is selected at is user-selectable via the pads on board. This allows each card to be placed in the range $4800-$7fff in $0400-byte increments. Additionally, there is a "sound card" select signal that maps to a 16k block ($0000-$3fff) and a "gpu card" select that maps to a 32k ($8000-$ffff) block. All I/O cards are accessible via bank $ff when the system is in a privileged mode. When the system is in HWPID $00, the I/O at $4000-$7fff is addressable directly in bank $00 to decrease program size and increase access speed. **General IO Card** The motherboard itself does not contain any form of IO and as such, to have the computer do anything useful, this card is needed. It provides two RS232 serial ports via the 16750 UARTs and two 20-pin parallel ports via the 65C22 VIAs. Since each of these perpherial ICs has a interrupt request line, there is an interrupt controller (the same design as the one on the motherboard) which feeds the card slot's interrupt request pin. There are jumpers onboard the card to select the priorities of each of the devices. Additionally, there is some "perfboard" area in case I need to add another IO device to the card. **DISK and RTC Card** The newest card is the IDE harddisk and RTC card. This allows the system to interface to a 'proper' storage device and have a form of time keeping while the system is off. The disk interface is a bit more complicated than most IDE interfaces for 8-bit computers since I wanted some "hardware acceleration" for accessing sectors on disk. The IDE disk has several registers that can be read or written to from the CPU. These registers are mapped into their own IO memory region. Much like a UART, the IDE disk has a data write and data read register (like the THR/RHR on a 16550). The hardware address mapping circuitry mirrors these data registers across a full 512-byte memory range. This means that the CPU can make use of the MVN/MVP block copy instructions to rapidly copy data to/from the disk (1/7 the CPU's clock rate). Additionally, this could be used to simplify a DMA interface, whenever I get around to designing that system. As for the RTC, the chip has its own IO memory range. Backup power is supplied via a few-farad supercap that is slowly charged through a resistor-diode circuit when the system has power. There is also a 32K ram socket on the card since the RTC has a backup supply output for keeping the contents of external memories. Unfortunately, the quiescent current, even in sleep, for the RAM I have is so high that the capacitor only lasts about a hour before the memory loses state. As such, the ram is current not populated. The plan was to use the RAM to store boot configuration parameters (such as whether to default to booting off disk or going straight into the BIOS monitor.) The RAM could either be replaced with a form of non-volatile storage or the capacitor could potentially be upgraded to a small secondary lithium cell with a charge controller.

Privilege Modes

The system supports two privilege levels: Privileged and Unprivileged.

Documentation

There is some documentation available for the system: REV A Main logic board schematic REV A IO Card schematic REV A Disk and RTC Card schematic General "User Guide" overview of system

Pictures

Main logic board, top view Current patches to the logic board. There's a few jumpers running around. Most of them are rather long since they had to find an unused gate somewhere. IO Card, plugged into the main logic board Back side of IO card, showing the logic board and small switching PSU Current full assembly. The disk drive card is at the top, followed by the IO card. There's plenty of ribbon cables for the IO. The disk also requires 12 volts, so another switching regulator was added along with the black-sheathed cable.

PWQ (Potentially Wondered Questions)

Q: Why discreet logic ICs and not an FPGA? This makes the board so large, lowers the max clock speed, and increases the cost of the overall system.

A: Two reasons for the discrete logic:

Q: Is there an EMMA-1?

A: Yes there is! It is a 65C02 based system that has 6 card slots, like the EMMA-2. The main board only contains a power-on-reset monitor, the CPU, and some bus transceivers. The system was planned to be as flexible as physically possible so I could use it as a general purpose workbench computer. I think that it was this lack of definition of the system that allowed me to never create any cards for it (save for a resistor NOP generator with an onboard oscillator, which showed that I could get the 6502 to execute NOPs at up to 32 MHz before I ran out of frequencies to try). I've added a page about EMMA-1 here: EMMA-1 Project Page

Q: What does EMMA stand for/mean?

A: The Electronic Machine for Multiple Applications. Originally created for use in the very general-purpose EMMA-1, I kept the name for the new machine since the system still has expandability to pretty much whatever hardware I would want to put into it.

Q: What does the debugging process look like?

A: This is a bit of a tough question. Ideally, there would be no issues with the hardware and only software would need to be debugged. Unfortunately, since none of the hardware was simulated or in any way tested (aside from *thinking* about it) before ordering and building up the boards, there is bound to be a few bugs. The first thing I always do after building up a board is to make sure that the voltages on the board are what I expect. (e.g., VCC is 5V at all points, GND is 0V at all points). From there, I usually write a simple program that is the bare minimum to get some form of IO operational so that the system can tell me its state. In this case, that consisted of writing to one of the 8-bit ports on a VIA on the IO card. I connected a few LEDs to the port and the program simply increments the output register's value at key points in program execution. Whatever number the leds stopped at is approximately the point where there is an issue. (And to further complicate things, all the original code for EMMA-2 was written using HEIPA, an assembler I created, but did not really test, meaning there's another variable to have to simultaneously debug). Anyway, my main friend in the hardware debugging process was, believe it or not, just a simple logic probe. This is a device that changes its beep sound based on what the probed signal is doing. No fancy logic analyzers required. There was one time when I cracked out the two-channel oscillscope to check something but it pretty much just confirmed the logic probe results. Here are a few common faults that I look for in 65xx systems:

Updates

2022-01-28:

2022-01-26:

2022-01-22:

2022-01-20:

2022-01-19:

2022-01-06:

2022-01-05:

2022-11-13:

2021-11-12:

2021-09-21:

2021-09-19:

2021-09-05:

2021-09-03:

2021-09-01:

2021-08-31:

2021-08-28:

2021-08-26:

2021-08-24:

2021-08-23:

2021-08-20:

2021-08-15:

That's all!
© 2021-2024 — Electronics Tinkerer — All rights reserved.
Top | Home | Privacy | Terms of Service