Ruud's Commodore Site Home  Email

Debugger




What is it?

The Debugger is a device I built to debug hardware problems I had with my Elektuur Junior and my C64. The Debugger enables you to see what the processor is doing step by step.


The story

For those who don't know the Junior, it is a 6502 based computer, quite the same as the KIM. It has been extended with lots of cards. Of course I made my own ones as well 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 idea

The 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 of the CPUs I know have an input to do 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 a lot of buffers and LEDs. But to make life easier I suggest to use an intelligent hexadecimal display. Just connect the address- and datalines 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 simply does NOT stop! This meant that if something went wrong during that specific 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 at least once could see 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 video-part. 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 also 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. My first solution was to cut the line directly to the RDY-input and connect both ends with the in- 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 expansion-connector of the C64. This worked fine enough for C64s I had to repair. A better solution is to cut the line between the DMA-input coming from the expansion-connector 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.....

With the Junior-version I 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 means that it started doing something else then you expected and didn't arrive at the chosen address at all. The reason can be faulty hardware, an error in the software or you, mis-interpreting the hard- and/or software :-).


The hardware

The SCH can be divided in six parts: The logic to step the processor
First we have to debounce the switch that triggers the stepping. This is done by IC3CB and D, two 74LS00 NAND-gates functioning as a flipflop. 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. 1
Remark: 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 delaytimes 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 clockcycle 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) meaning the 6502 can run at full speed all the time.

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 addressbus, 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 en- 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. It took me some time to find out what the display was showing. It just turned out to be 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-chip of the C64 sometimes steels some cycles from the 6510 to complete its actions.

Adjustments for the 65816
The 65816 has 24 addresslines so we need an extra 573 and two extra hexadecimal displays (or what ever you use) to display the state of addresslines 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 processors

One day I was thinking about building an interfacecard for my ZX-Spectrum. But I also needed one for my self-build 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. (OK, if the 6510 is soldered....)

Remark: such an interface only sees what the CPU does, not what the rest of the system is doing. So you won't see the errors that a faulty buffer will cause in the rest of the system....


Weird problem

Once I wrote a little ML-PRG to be used in a small stand-alone 6502 computer using some Junior-cards. The thing did simply nothing at all. So I attached my debugger and started clicking. No problems so far.
After a lot of clicking I started to use the address-discriminator. It never arrived at the set address. So I started to work towards the reset-address. To my surprise the computer even never arrived at the reset-address! At that moment I didn't know what to think about the situation but I had the idea that it could be the EPROM so I burned another one. Now the little fellow worked fine.
So my final conclusion was that my first EPROM had an accesstime of more then one micro-second for one or another reason. Just wanted to share this with you.


Schematics







Having questions or comment? You want more Info?
You can email me here.