65C02 Computer Interactive Diagnostic Tool
This is an interactive diagnostic tool for 65C02 based hobby computers including the Ben Eater 6502 computer. The code runs on an Arduino Mega (or similar) platform, and can be interacted with using a standard serial terminal or the Arduino Serial Monitor.
Features
This tool allows you to do the following:
- Temporarily disable the 65C02 processor in place, allowing this tool (or something else) to use the address and data buses
- Reprogram the EEPROM without removing it from the circuit
- Monitor the address and data buses in real time AND decode/disassemble the instructions (at clock speeds up to 10 kHz)
- Reset the 65C02
- Generate a clock signal at a configurable frequency from 1 Hz all the way up to 4 MHz
- Measure the frequency of an external clock running at <100 kHz
- Read any RAM or ROM value at any address while the 65C02 is executing code
- Write to any RAM address or I/O device register while the 65C02 is executing code
- Enable or Disable AT28C256 EEPROM Software Data Protection
Getting Started
The tool connects to 30-35 different digital signals on the 65C02 and supporting hardware:
- 1 pin for the System Clock (φ2)
- 16 pins for the Address Bus (A0-A15)
- 8 pins for the Data Bus (D0-D7)
- 1 pin for the R/W signal
- 4 pins for the control signals RDY, SYNC, BE and RESET
- 2 pins for the WE and OE pins of the PROM (required when programming the EEPROM in place only)
- 3 pins for IRQ, NMI, and SO (optional, not currently used by this tool)
- A common ground connection is also required
NOTE: If you're using this tool with the Ben Eater 6502 computer. You need to replace the jumpers connecting RDY, NMI, and BE on the 65C02 to +5V with 1k Ω or larger pull-up resistors instead. You also need to replace the jumpers connecting WE and OE on the EEPROM to +5V and GND respectivly with 1k Ω resistors as well.
Once running you can interact with the tool using the Arduino serial monitor, or any other serial terminal connected to the Arduino. The tool uses a simple command line style interface, enter a command at the >
prompt followed by CR or LF. All commands are case insensitive. Entering "Help" will give a list of available commands.
Default Arduino pin mapping
This is the "out-of-the-box" pin mapping. You can however change these to anything by altering the constants at the start of the .ino file. The clock (φ2) pin has special requirements but all other pins may be connected to any digital I/O pin on the Arduino. Note that only 34 of the 65C02's 40 pins are connected.
Name | 65C02 Pin | Arduino Mega Pin | Notes |
---|---|---|---|
RDY | 2 | 23 | 1 |
IRQ | 4 | 25 | 1,3 |
NMI | 6 | 27 | 1,3 |
SYNC | 7 | 29 | |
A0 | 9 | 31 | |
A1 | 10 | 33 | |
A2 | 11 | 35 | |
A3 | 12 | 37 | |
A4 | 13 | 39 | |
A5 | 14 | 41 | |
A6 | 15 | 43 | |
A7 | 16 | 45 | |
A8 | 17 | 47 | |
A9 | 18 | 49 | |
A10 | 19 | 51 | |
A11 | 20 | 53 | |
VSS | 21 | GND | |
A12 | 22 | 52 | |
A13 | 23 | 50 | |
A14 | 24 | 48 | |
A15 | 25 | 46 | |
D7 | 26 | 44 | |
D6 | 27 | 42 | |
D5 | 28 | 40 | |
D4 | 29 | 38 | |
D3 | 30 | 36 | |
D2 | 31 | 34 | |
D1 | 32 | 32 | |
D0 | 33 | 30 | |
R/W | 34 | 28 | |
BE | 36 | 26 | 1 |
φ2 | 37 | 02 | 2 |
SO | 38 | 24 | 1,3 |
RESET | 40 | 22 | 1 |
-
This is an input (to the 65C02), it should be pulled high with a 1+ kΩ resistor to ensure the signal is valid when the Arduino isn't driving the pin, or is disconnected. Do NOT tie these pins directly to +5V while using this tool.
-
φ2 is the system clock, it can be driven externally by a crystal, or 555 timer circuit, or generated by the Arduino. This must be on an Arduino pin that is connected to both an interrupt, and a PWM timer. On an Arduino Mega it must be on Arduino pin 2 or 3 because those are the only two pins that support both interrupts and PWM timers.
-
This pin is not used by the tool at this time and can be left disconnected.
In addition, to use the EEPROM programmer you must connect two additional Arduino pins to the EEPROM.
Name | 28C256 Pin | Arduino Mega Pin | Notes |
---|---|---|---|
OE | 22 | 15 | 1 |
WE | 27 | 14 | 1 |
- This is an input (to the 28C256), it should be pulled high or low with a 1+ kΩ resistor to ensure the signal is valid when the Arduino isn't driving the pin, or is disconnected. Do NOT tie these pins directly to +5V or GND while using this tool.
Commands
Help Command
You can get a list of available commands at any time with the Help
command.
> help
Available Commands:
help
reset
disableProcessor
enableProcessor
measureClock
startClock
stopClock
peek
poke
monitor
readProm
writeProm
lockProm
unlockProm
Enable or Disable the 65C02 processor
The tool can temporarily halt the 65C02 execution at any time by pulling both the RDY and BE signals low.
DisableProcessor
will disable the 65C02 and disconnect it from the ADDRESS, DATA, and RW buses.
EnableProcessor
will re-enable the 65C02 after a call to DisableProcessor.
If DisableProcessor was called more than once, EnableProcessor must also be called the same number of times before the processor will be enabled.
Read a single byte from any address
The PEEK
command will read any memory address on the next clock cycle. The 65C02 processor will be temporarily disabled during the read so as not to interfere.
The address can be specified in decimal, in hexadecimal by prefixing the value with '0x', or in octal by prefixing the value with '0'.
The memory address read will be printed in hexadecimal, decimal, and (if it's a printable character) in ASCII.
EXAMPLE
> peek 0x1234
200 OK - 0x1234: 0x21 (33) '!'
Write a single byte to any address
The POKE
command will write a single byte to any memory address on the next clock cycle. The 65C02 processor will be temporarily disabled during the write so as not to interfere.
Both the address and the data value can be specified in decimal, in hexadecimal by prefixing the value with '0x', or in octal by prefixing the value with '0'.
EXAMPLE
> poke 0x1234 33
200 OK
> peek 0x1234
200 OK - 0x1234: 0x21 (33) '!'
Monitor and decode the traffic on the data & address busses
The Monitor
command will begin decoding traffic on the address & data busses in real time. The SYNC pin must be connected to decode OpCodes.
The output format is as follows:
r---------- OpCode fetch signal from the SYNC pin
| r------- Address being read from / written to
| | r--- R/W signal 'r' for read, 'W' for write
| | | r- Byte(s) read/written*
| | | |
| | | | r- Decoded instruction
v v v v v
* e09e r 8d 01 c1 STA $c101
c101 W 62
- When multiple bytes are read or written to sequential addresses, they will be shown on the same line. In the above example, first $8d was read at address $e09e, then $01 was read at address $e09f, then $c1 was read at $e0a0, and finally $62 was written to address $c101.
This is an example of the decoded output starting from a reset signal.
EXAMPLE
> monitor
200 OK - Watching Bus, send any key to stop...
* ffff r 00 BRK
e010 r 30
01ff r e0
01fe r 35
01fd r e0
fffc r 00 e0
* e000 r a2 ff LDX #$ff
* e002 r 9a TXS
e003 r a9
* e003 r a9 38 LDA #$38
* e005 r 2c 00 c1 BIT $c100
c100 r 63
* e008 r 30 fb BMI $e005
* e00a r 8d 00 c1 STA $c100
c100 W 38
* e00d r 2c 02 c1 BIT $c102
c102 r 06
* e010 r 30 fb BMI $e00d
* e012 r 8d 02 c1 STA $c102
c102 W 38
Generate a clock signal from the Arduino
The StartClock
command will start generating a clock signal at the specified frequency in Hz.
EXAMPLE
> startclock 10
200 OK - Generating internal clock at 10 Hz
To stop generating a clock signal, use the StopClock
command.
EXAMPLE
> stopclock
200 OK - Clock has been stopped
Measure the frequency of an external clock
The MeasureClock
command will measure the frequency of the external clock, by counting the number of clock pulses over roughly a 2 second period and dividing by the exact time.
EXAMPLE
> measureclock
200 OK - Counted 40 clock pulses in 2000 ms for a clock frequency of 20 Hz
Reading and Writing to the EEPROM in place
The tool can write to an EEPROM without first removing it from the circuit. When using these commands, the 65C02 processor will be temporarily disabled during the reads and writes so as not to interfere with the bus. Also in this repository, is a command line tool that can be used to upload a binary image assembled on a different computer to write to the EEPROM using these commands. See the Command Line Tool section below for more information.
The WriteProm
command can write up to 64 consecutive bytes to an EEPROM in the circuit.
WriteProm
should start with a memory address, followed by up to 64 bytes in hexadecimal. The memory address can be specified in decimal, in hexadecimal by prefixing the value with '0x', or in octal by prefixing the value with '0'.
The data to be written MUST be specified in hexadecimal.
Note that while the address MUST be prefixed by 0x if you wish to specify it in hexadecimal, the data to be written must NOT be prefixed with 0x.
EXAMPLE
> writeprom 0xE000 A2FF9AA9382C00C130FB8D00C12C02C130FB8D02C1A9062C00C130FB8D00C12C
200 OK
You can read/verify the EEPROM with the ReadProm
command. ReadProm
takes two parameters. First the starting address, then the number of bytes to read from the PROM. Both the address and the number of bytes to read can be specified in decimal, in hexadecimal by prefixing the value with '0x', or in octal by prefixing the value with '0'. When reading the EEPROM, the tool will always read 16 bytes at a time, if the number of bytes to be read is not a multiple of 16 it will be rounded up to the next multiple of 16.
EXAMPLE
> readprom 0xE000 32
200 OK
e000: a2 ff 9a a9 38 2c 00 c1 30 fb 8d 00 c1 2c 02 c1
e010: 30 fb 8d 02 c1 a9 06 2c 00 c1 30 fb 8d 00 c1 2c
Unlike when using an EEPROM programmer, the EEPROM is still in the circuit and therefore any existing hardware address decoding is still applied to the CS chip select pin of the EEPROM. If you have a 28C256 EEPROM with hardware address decoding mapping it to $8000 - $FFFF, you start reading the first 32 bytes of the EEPROM with the command readprom 0x8000 32
. Where as when using an EEPROM programmer this would be address 0x0000 instead.
Enabling or Disabling the Software Data Protection (SDP) of an AT28C256 EEPROM
The Atmel AT28C256 EEPROM supports an optional software data protection (SDP) mechanism to guard against inadvertent writes. You can enable or disable the EEPROMs SDP with the lockprom and unlockprom commands. To enable SDP, simply specify the lockprom command followed by the starting address of the EEPROM to be locked. To disable SDP use the unlockprom command followed by the starting address of the EEPROM to be locked.
The address can be specified in decimal, in hexadecimal by prefixing the value with '0x', or in octal by prefixing the value with '0'. If the address is omitted, a start address of 0x8000 will be assumed.
EXAMPLES
Enable SDP for an EEPROM at addresses 0x8000-0xFFFF
> lockprom 0x8000
200 OK
Disable SDP for an EEPROM, addresses 0x8000-0xFFFF is assumed by default if not specified
> unlockprom
200 OK
Note that AT28C256 EEPROM addresses 0x2AAA and 0x5555 must be addressable within the circuit in order to enable or disable SDP. These addresses appear at 0xAAAA and 0xD555 respectively if the EEPROM mapped to 0x8000-0xFFFF withing the circuit.
Resetting the 65C02 computer
The Reset
command will pull the RESET pin on the 65C02 to ground for at least 3 clock cycles, triggering a reset of the microprocessor.
EXAMPLE
> Reset
200 OK
Use as a standalone EEPROM programmer
You can also use this tool directly as a stand-alone EEPROM programmer. To do this simply connect the WE, OE, Address and Data pins directly to the matching pins on the EEPROM, and connect the CS pin to ground to ensure the EEPROM is always selected. In this scenario be sure there are no other chips connected to the bus.
Command Line tool for uploading a binary image to the EEPROM
The eeprom-programmer\
folder contains a command line tool for uploading a binary rom image to the tool for writing to an EEPROM. The eeprom-programmer is written in C# against .NET 5 and can be built and run on any major OS including Windows, MacOS, and Linux platforms.
Prerequisites
You will need to download and install the .NET 5.0 runtime for your operating system.
Supported Formats
The command line tool accepts binary images in the following formats:
- BIN - Raw binary format
- PGM - Raw binary with 2 byte header indicating the load address
- SBIN - Raw binary with 4 byte header indicating the load address and length of the image
Usage
To use the programmer simply pass the filename as the first argument
Example
eeprom-programmer MyBinaryImage.sbin
or
dotnet eeprom-programmer.dll MyBinaryImage.sbin
The eeprom programmer accepts the following additional command line parameters
Parameter | Example | Default | Description |
---|---|---|---|
-a | -a 0x8000 | Read from image file | The address to load the image to, required when using the raw binary format |
-b | -b 9600 | 115200 | Baud rate to use when communicating with the tool |
-e | -e | no echo | When specified, any communication with the tool will be echo'd to STDOUT |
-f | -f SBIN | Guessed from file extension | The format the image file is in |
-p | -p /dev/ttyS0 | First serial port found | The serial port the tool is connected to the computer on |
--noverify | --noverify | always verify | When specified, skip the verification that the image was written to the EEPROM correctly |
-r | -r | do not reset | When specified, automatically pull the RESET pin low for at least 3 clock cycles to trigger a reset of the target computer after a successfully completed upload |
Acknowledgements
- Special thanks reddit user u/andreamazzai69 for his assistance debugging two issues in my code.