Skip to content
David Banks edited this page May 23, 2018 · 7 revisions

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.

Overview

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:

  1. 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.

  2. It can be quite involved to work backwards from the values of externally visible bus signals to piece together then instruction stream being executed.

  3. 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:

  1. 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.

  2. 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.

  3. Configurable triggers allow the user to set the conditions required for decoding to commence.

Background

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.

Blog Posts (on Stardot)

I've written up the adventures as a set of posts over on stardot, entitled Open Source Logic Analyzer Experiments:

Example of the current decoder (taken from Part 6)

$ 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

Command Line Options

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 logic analyzer capture files.

FILENAME must be a binary capture file with 16 bit samples.

If FILENAME is omitted, stdin is read instead.

The default bit assignments for the input signals are:
 - data: bit  0 (assumes 8 consecutive bits)
 -  rnw: bit  8
 - sync: bit  9
 -  rdy: bit 10
 - phi2: bit 11
 -  rst: bit 14

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 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, is preferred.

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)


  -a, --address              Show address of instruction.
  -b, --byte                 Byte samples
  -c, --c02                  Enable 65C02 mode.
      --data=BITNUM          The start bit number for data
  -d, --debug=LEVEL          Sets debug level (0 1 or 2)
  -e, --emulate              Enable emulation, for error checking.
  -f, --bbcfwa               Show BBC floating poing work areas.
  -h, --hex                  Show hex bytes of instruction.
  -i, --instruction          Show instruction.
  -m, --machine=MACHINE      Enable machine specific behaviour
      --phi2[=BITNUM]        The bit number for phi2, blank if unconnected
  -p, --profile[=PARAMS]     Profile code execution.
  -q, --quiet                Set all the show options to off.
      --rdy[=BITNUM]         The bit number for rdy, blank if unconnected
      --rnw[=BITNUM]         The bit number for rnw
      --rst[=BITNUM]         The bit number for rst, blank if unconnected
  -r, --rockwell             Enable additional rockwell instructions.
      --sync[=BITNUM]        The bit number for sync, blank if unconnected
  -s, --state                Show register/flag state.
  -t, --trigger=ADDRESS      Trigger on address.
  -u, --undocumented         Enable undocumented 6502 opcodes (currently
                             incomplete)
      --vecrst[=HEX]         The reset vector, black if not known
  -y, --cycles               Show number of bus cycles.
  -?, --help                 Give this help list
      --usage                Give a short usage message
  -V, --version              Print program version
Clone this wiki locally