-
Notifications
You must be signed in to change notification settings - Fork 10
Home
The documentation for this project is at an early stage, so please bear with me. If you have any specific questions, please do ask them in the thread over on Stardot.
Logic analyzers are widely available, yet they are seldom the tool of choice when it comes to debugging 6502-based computer systems. There are a number of reasons for this:
-
To follow what the 6502 is doing, it's typically necessary to monitor the data bus (8 signals), the address bus (16 signals) plus a set of miscellaneous control lines (7 signals). This means a 32-channel logic analyzer must be used. These are out of the price range of many hobbyists, and time consuming to hook up.
-
It can be quite involved to work backwards from the values of the externally visible bus signals to piece together the instruction stream being executed.
-
Often the point of interest (a system malfunction), can be buried in many millions of correctly executed instructions, and conventional logic analyzers interfaces become unwieldy with this amount of data.
This project enables a cheap (<£10) 16-channel USB logic analyzer to be used as an effective diagnostic tool for 6502-based computer systems, overcoming each of the above issues:
-
Minimally just Phi2 (the system clock) and D7..D0 (the data bus) need to be connected. Adding just a couple more control lines (Sync, RnW) can improve the results in certain cases, but these are optional.
-
The values on the data bus are used to reconstruct the full 6502 machine state, including the internal processor registers, the external memory state, and the stream of instructions being executed.
-
Configurable triggers allow the user to set the conditions required for decoding to commence.
The motivation for this project came from the author's experiences trying to use a variety of "classic" HP logic analyzers to fix broken 1980's vintage Acorn microcomputers.
The HP 1650A is quite limited by modern standards, and only has a capture depth of 1024 samples. Optional software, called by HP an Inverse Assembler, does allow some understanding of the instruction stream. But the user interface is very poor.
The HP 16702B is a much more capable device (being based on a 150MHz PA-RISC Processor and running HP-UX internally). Yet the Inverse Assembler also extremely difficult to use effectively.
I then stumbled across Sigrok, an Open-Source signal analysis software suite that works with many different USB logic analyzers. It allows custom protocol decoders to be developed in python, and ships with one for the Z80.
Inspired by this, I started work on the 6502 Protocol Decoder for Sigrok. At the same time, I started blogging my experiences in a series of posts on stardot: Open Source Logic Analyzer Experiments
It quickly became apparent that Sigrok and it's python protocol decoders were painfully slow for this type of application. Decoding 1-seconds worth of 6502 bus data was taking 1-2 minutes (on my 2009 vintage Linux workstation).
Hence the current version of this tool is a standalone C program, which runs ~100x faster then the python code in Sigrok.
I've written up the adventures as a set of posts over on stardot, entitled Open Source Logic Analyzer Experiments:
- Part 1: An Introduction to Sigrok and Logic Sniffer
- Part 2: Probing the 6502 with Sigrok
- Part 3: Writing a 6502 Protocol Decoder
- Part 4: Synchronous capture, triggers and sigrok-cli
- Part 5: Using an uber-cheap FX2LP development board
- Part 6: Simplifying capture on the Beeb Model B
- Part 7: Using Sigrok-cli / FX2 Logic Analyzer / 6502 Decoder on Windows
$ decode6502 -h -s --sync= <data.bin >data.txt
results in:
???? : : RESET !! A=?? X=?? Y=?? SP=?? N=? V=? D=? I=1 Z=? C=?
D9CD : A9 40 : LDA #40 A=40 X=?? Y=?? SP=?? N=0 V=? D=? I=1 Z=0 C=?
D9CF : 8D 00 0D : STA 0D00 A=40 X=?? Y=?? SP=?? N=0 V=? D=? I=1 Z=0 C=?
D9D2 : 78 : SEI A=40 X=?? Y=?? SP=?? N=0 V=? D=? I=1 Z=0 C=?
D9D3 : D8 : CLD A=40 X=?? Y=?? SP=?? N=0 V=? D=0 I=1 Z=0 C=?
D9D4 : A2 FF : LDX #FF A=40 X=FF Y=?? SP=?? N=1 V=? D=0 I=1 Z=0 C=?
D9D6 : 9A : TXS A=40 X=FF Y=?? SP=FF N=1 V=? D=0 I=1 Z=0 C=?
D9D7 : AD 4E FE : LDA FE4E A=80 X=FF Y=?? SP=FF N=1 V=? D=0 I=1 Z=0 C=?
D9DA : 0A : ASL A A=00 X=FF Y=?? SP=FF N=0 V=? D=0 I=1 Z=1 C=1
D9DB : 48 : PHA A=00 X=FF Y=?? SP=FE N=0 V=? D=0 I=1 Z=1 C=1
D9DC : F0 09 : BEQ D9E7 A=00 X=FF Y=?? SP=FE N=0 V=? D=0 I=1 Z=1 C=1
D9E7 : A2 04 : LDX #04 A=00 X=04 Y=?? SP=FE N=0 V=? D=0 I=1 Z=0 C=1
D9E9 : 86 01 : STX 01 A=00 X=04 Y=?? SP=FE N=0 V=? D=0 I=1 Z=0 C=1
D9EB : 85 00 : STA 00 A=00 X=04 Y=?? SP=FE N=0 V=? D=0 I=1 Z=0 C=1
D9ED : A8 : TAY A=00 X=04 Y=00 SP=FE N=0 V=? D=0 I=1 Z=1 C=1
D9EE : 91 00 : STA (00),Y A=00 X=04 Y=00 SP=FE N=0 V=? D=0 I=1 Z=1 C=1
D9F0 : C5 01 : CMP 01 A=00 X=04 Y=00 SP=FE N=1 V=? D=0 I=1 Z=0 C=0
D9F2 : F0 09 : BEQ D9FD A=00 X=04 Y=00 SP=FE N=1 V=? D=0 I=1 Z=0 C=0
D9F4 : C8 : INY A=00 X=04 Y=01 SP=FE N=0 V=? D=0 I=1 Z=0 C=0
D9F5 : D0 F7 : BNE D9EE A=00 X=04 Y=01 SP=FE N=0 V=? D=0 I=1 Z=0 C=0
There are a growing number of command line options. For now, please refer to the built-in help.
dmb@quadhog:~/atom/6502Decoder$ ./decode6502 --help
Usage: decode6502 [OPTION...] [FILENAME]
Decoder for 6502/65C02/65C816 logic analyzer capture files.
FILENAME must be a binary capture file containing:
- 16 bit samples (of the data bus and control signals), or
- 8-bit samples (of the data bus), if the --byte option is present.
If FILENAME is omitted, stdin is read instead.
The default sample bit assignments for the 6502/65C02 signals are:
- data: bit 0 (assumes 8 consecutive bits)
- rnw: bit 8
- sync: bit 9
- rdy: bit 10
- rst: bit 14
- phi2: bit 15
The default sample bit assignments for the 65C816 signals are:
- data: bit 0 (assumes 8 consecutive bits)
- rnw: bit 8
- vpa: bit 9
- rdy: bit 10
- vda: bit 11
- e: bit 12
- rst: bit 14
- phi2: bit 15
To specify that an input is unconnected, include the option with an empty
BITNUM. e.g. --sync=
If phi2 is not connected the capture file should contain one sample per
falling edge of phi2.
If rdy is not connected a value of '1' is assumed.
If sync (or vda/vpa) is not connected a heuristic based decoder is used.
This works well, but can take several instructions to lock onto the
instruction stream. Use of sync (or vda/vpa) is recommended.
If RST is not connected, an alternative is to specify the reset vector:
- D9CD (D9 is the high byte, CD is the low byte)
- A9D9CD (optionally, also specify the first opcode, LDA # in this case)
If --debug=1 is specified, each instruction is preceeded by it's sample
values.
The --mem= option controls the memory access logging and modelling. The value
is three hex nibbles: WRM, where W controls write logging, R controls read
logging, and M controls modelling.
Each of the three nibbles has the same semantics:
- bit 3 applies to stack accesses
- bit 2 applies to data accesses
- bit 1 applies to pointer accesses
- bit 0 applies to instruction accesses
Examples:
--mem=00F models (and verifies) all accesses, but with minimal extra logging
--mem=F0F would additional log all writes
General options:
-b, --byte Enable byte-wide sample mode
--bbctube BBC tube protocol decoding
-c, --cpu=CPU Sets CPU type (6502, 65c02, r65c02, 65c816)
-d, --debug=LEVEL Sets the debug level (0 or 1)
-m, --machine=MACHINE Enable machine (beeb,elk,master) defaults
--mem[=HEX] Memory modelling (see above)
-p, --profile[=PARAMS] Profile code execution
--skip[=HEX] Skip the first n samples
-t, --trigger=ADDRESS Trigger on address
--vecrst[=HEX] Reset vector, optionally preceeded by the first
opcode (e.g. A9D9CD)
Output options:
-a, --address Show address of instruction
-f, --bbcfwa Show BBC floating-point work areas
-h, --hex Show hex bytes of instruction
-i, --instruction Show instruction disassembly
-q, --quiet Set all the output options to off
-r, --showromno Show BBC rom no for address 8000..BFFF
-s, --state Show register/flag state
-y, --cycles Show number of bus cycles
Signal defintion options:
--data=BITNUM Bit number for data (default 0)
--e[=BITNUM] Bit number for e (default 12) (65C816)
--phi2[=BITNUM] Bit number for phi2 (default 15)
--rdy[=BITNUM] Bit number for rdy (default 10)
--rnw[=BITNUM] Bit number for rnw (default 8)
--rst[=BITNUM] Bit number for rst (default 14)
--sync[=BITNUM] Bit number for sync (default 9) (6502/65C02)
--vda[=BITNUM] Bit number for vda (default 11) (65C816)
--vpa[=BITNUM] Bit number for vpa (default 9) (65C816)
Additional 6502/65C02 options:
--sp[=HEX] Initial value of the Stack Pointer register
-u, --undocumented Enable undocumented opcodes
Additional 65C816 options:
--db[=HEX] Initial value of the Data Bank register
--dp[=HEX] Initial value of the Direct Page register
--emul[=HEX] Initial value of the E flag
--ms[=HEX] Initial value of the M flag
--pb[=HEX] Initial value of the Program Bank register
--sp[=HEX] Initial value of the Stack Pointer register
--xs[=HEX] Initial value of the X flag
-?, --help Give this help list
--usage Give a short usage message
-V, --version Print program version
Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.