What is it?The Debugger enables you to observe the behaviour of the processor step by step. I built it to debug some hardware problems I had with some of my computers.
The storyIn 1986 I got a Junior for free but it was broken. For those who don't know the Junior, it is a 6502 based computer, quite the same as the KIM. It can be extended with lots of cards. I made some of the cards myself but they did not always work well right from the start. So I decided to build a device to check the status of the bus at a given moment: the Debugger.
The ideaThe idea itself is quite simple: stop the processor (CPU) and check the levels of all the lines you are interested in. But how are we going to stop the CPU? Most CPUs I know have an input to perform this job. For the 6502 this is the RDY input (RDY = ReaDY). Make it (L) and the processor stops. (Almost) as simple like that!
The next thing is to determine the levels of all the lines you are interested in. The simplest way is to use some buffers and a lot of LEDs. But to make life easier I suggest using an intelligent hexadecimal display. Just connect the address and data lines to these displays and you have a nice hexadecimal output.
(Almost) as simple like that!My first 'almost' is a feature MOS/Rockwell implemented in their 65xx which I still don't understand: when the RDY input is negated during a write-cycle, the CPU does NOT stop! This meant that if something went wrong during that specific write cycle, I had no means to check it. Generally spoken this 'problem' caused no trouble because I could lay my hands on some 65SC02s from GTE and these CPUs have this nice feature that they do stop during a write-cycle as well :-)
But then I decided to use the debugger for my C64 too and as there is not such a thing as a "65SC10", I had to find another solution for the 'write-cycle-bug'. I only managed to solve it half. I 'froze' the data during this cycle on the displays by preventing an update of it immediately after a write-cycle. In this way I could see at least once what the CPU had written to where. But unfortunately there are occasions the 6510 performs two and even three write-cycles in a row (JSR, IRQ, NMI) and that means that some write-cycles still will be lost :-(
Another 'almost' for the C64 was the VIC chip. As you probably know this IC takes care of the videopart. This is done in such a way that the CPU and the VIC share the bus together but not simultaneously. Generally it means that the VIC controls the bus during the negative half of the clock and the CPU during the positive half. This meant that I only saw garbage on the displays of my original design. Freezing the data during the negative half of the clock solved this problem.
The third 'almost' was the accessibility of the RDY input of the 6510 in the C64. My first solution was to cut the line directly to the RDY input and connect both ends with the input and output of an AND gate. The second input of this AND gate was connected with the RDY output of my debugger. The AND gate was situated on a little print needed to convert the Junior-bus to the expansionport of the C64. This works fine enough for C64s I have to repair. A better solution is to cut the line between the DMA input coming from the expansionport and the input of the AND gate who controls the AEC input of the 6510. With a jumper I can restore the connection. In this way I don't have to solder a wire every time I want to connect the debugger. Unfortunately the line to be cut is situated between the IC and the board (at least with the models I have). This means removing the 74LS08 first so I only did this for some C64s of my own.
Clicking and clicking and clicking.....Using it with the Junior I soon discovered a serious shortcoming: the usability to handle loops and subroutines. This meant you could be clicking that little knob for hours before you reached the address where the fault appeared. So I added an address discriminator. This little device stops the processor at the chosen address. If the CPU doesn't stop, it didn't arrive at the chosen address which means that it started doing something else then you expected. The reason can be faulty hardware, an error in the software or you, misinterpreting the hardware and/or software :-).
The hardwareThe schematic can be divided in six parts:
- The logic to step the processor.
- Enabling the stepping circuitry.
- The address discriminator.
- Connecting a C64.
- Adjustments for the 65816.
- Using the debugger for other computers and/or processors.
The logic to step the processor
First we have to debounce the switch that triggers the stepping. This is done by a flipflop, made out of IC3CB and D, two 74LS00 NAND gates. The output of IC3D is (L) when step switch S1 isn't pressed. This (L) clears IC4A, a 74LS76A, and with both the J and K input (L), the levels of the outputs of IC4B remain the same.
+----+ +----+ +----+ +----+ +----+ +----+ +----+ CLK2 | | | | | | | | | | | | | +----+ +----+ +----+ +----+ +----+ +/ /+ +----+ +---------------------------------------/ /--+ IC3D | | -----------+ +------------- +---------+ Q_4B | | ---------------------+ +------------------/ /----------------- --------------------------------+ +------------ Q\_4A | | +-----------------/ /----+ A B C D E F Fig. 1Remark: with Q\ I mean the inverted Q output.
As you can see, there is a difference of one character between the edges of CLK2 and Q\_4B and between the edges of Q\_4B and Q\_4A. These differences represent the delay times of each gates. They are only about 10 ns but even this can be enough to have a significant meaning in certain situations.
So as you can see above, Q\_4A is (H) and Q_4B is (L) when the circuit is in rest.
Now assume that at point A the switch is pressed and the output of IC3D becomes (H). Point A can be situated at any place between two negative edges of CLK2. Because both the J and K inputs of IC4B are (H) now, it will toggle its Q outputs every negative edge of CLK2. In this case it means Q_4B will go (L) on the first negative edge of CLK2 at point B. It will only remain in this state during one clock cycle of CLK2 because at the next negative edge of CLK2, at point C, it will go (H) again.
RDY is indirect connected with Q_4B and will be (H) during this one cycle. The 6502 will detect this state at the end of the positive half of CLK2 at point C and then will perform one cycle. Because Q_4B is (H) again at the end of this cycle (point E), and RDY will (L) again, the CPU will stop. UNLESS one or more write-cycles are performed. These we cannot stop and will take place out of our control.
As already said, the negative edge of CLK2 at point C causes Q_4B to become (L) again. The negative edge of Q_4B causes output Q\_4A to become (L). This event means that input CL of IC4B becomes (L) as well which prevents IC4B to toggle its Q output. This means that Q-9B won't become (H) at point E as expected but will remain (L) until something else changes.
This "something else" is the release of the switch (point F). This causes the output of IC3D to become (L) again, which on its turn clears IC4A. Clearing IC4B means that Q\_4A becomes (H) and by doing so it releases its hold on IC4B. But as its J and K inputs are (L) again, IC4B won't react to any negative transaction of CLK2 anymore. The whole circuitry is in the state as before point A again.
Enabling the stepping circuitry
Of course it makes no sense in connecting the Q output of IC4B directly to the RDY input of the 6502: in this way the 6502 never can run at full speed. The simplest solution is to place an OR gate, IC5A (74LS32), in this line. The second input of this gate is connected to switch SW4 and a pull-up resistor. Opening SW4 means that the OR gate, and thus RDY as well, becomes (H) which means the 6502 can run at full speed.
The address discriminator
The next step in the evolution of the debugger was adding the address discriminator. It is made out of two 74LS688's, IC1 and IC2. The 688 is a 8-bit comparator. One side is connected to the address bus, the other one to an 8-bit dipswitch plus pull-up resistor-array. The idea is simple: the moment both 8-bit sides see the same input, pin 19 becomes (L). IC1 cascades its output to IC3.
A pull-up resistor and switch SW3 connected to pin 1 of IC1 enable you to enable or disable the discriminator.
The last step is to mix this signal with the one of the stepping circuit using an AND gate made out of IC3A and IC3B.
Connecting a C64 When I connected my debugger to a C64, I only saw rubbish. that was caused by the video chip, using the low half of CLK2 for his own business.
The solution was to freeze the data on the displays during the lower half of CLK2 using latches, 74ALS573's in this case (IC6..8). The clock input of the latches was connected to CLK2.
Even then the display vaguely displayed random data. The reason for this is that the video IC of the C64 sometimes steels some cycles from the 6510 to complete its actions.
Adjustments for the 65816
The 65816 has 24 address lines so we need an extra 573 and two extra hexadecimal displays (or what ever you use) to display the state of address lines A16..23. This 573 must be clocked by CLK1 or an inverted CLK2.
Remark: this addition is not shown in the schematic.
Using the debugger for other computers and/or processorsOne day I was thinking about building an interface for my ZX-Spectrum. But I also needed one for my self-built Micro-Professor. Two computers with each having their own bus but the SAME processor. Bingo! Why not making an interface, which can be put on top of the processor or better, between the processor and the board? We only have to look at the C64 to see the advantage of the last solution: we don't need to cut lines anymore. (That is, if the 6510 is not soldered)
Replacement of the 74LS76ALately I discovered I had only one 74LS76A in my box. Ordering new ones seemed to be a problem: my local supplier didn't even know that there was a difference between the 74LS76 and 74LS76A. And neither did his supplier. So I decided to design a replacement.
+----+ +----+ +----+ +----+ +----+ +----+ +----+ CLK2 | | | | | | | | | | | | | +----+ +----+ +----+ +----+ +----+ +/ /+ +----+ +---------------------------------------/ /--+ Step | | -----------+ +------------- +---------+ To RDY | | ---------------------+ +------------------/ /----------------- --------------------------------+ +------------ Q\_2B | | +-----------------/ /----+ A B C D E Fig. 2If the above figure looks familiar, it is a copy of Fig. 1 with the exception of the names. And again it shows Q\_2B = (H) and 'To RDY' = (L) when the circuit is in rest.
Now assume that at point A the switch is pressed and 'Step' becomes (H). Point A can be situated at any place between two negative edges of CLK2. The output of the AND gate becomes (H) and at the first falling edge of CLK2, point B, the Q output of the flipflop IC2A (= signal towards RDY) becomes (H) as well. The rising edge of this signal causes IC2B to negate it Q\ output. That on its turn causes the output of the AND gate to become (L) as well. At the next negative edge of CLK2, at point C, this (L) will be copied to the Q output and thus negating RDY.
As long as 'Step' is (H), the Q\ output of IC2B will remain (L). The moment 'Step' is released (point E), the CLR input of IC2B is negated and its Q\ output becomes (H) again. The circuit is ready for th next step.
You can email me here.