Phase 2 of the project is to breadboard a minimal circuit and get the CPU to run in freerun mode. This also allows testing the power on and pushbutton reset circuits.
The idea of freerun is to get the CPU to execute instructions before the RAM, ROM, and other circuitry is present, by hard wiring the data lines so it continuously reads and executes an instruction. It should then walk through all memory addresses. Often this is done with a NOP (no operation) instruction. Getting the CPU to execute in freerun mode requires minimal circuitry and is a good first step towards getting the system working.
What signals are needed to freerun a 68000? We need:
- +5V power and ground
- a clock (CLK) signal
- proper timing of RESET* and HALT* signals
- data on the data lines D0 through D15 corresponding to a valid instruction
- DTACK* pulled low to acknowledge read cycles
The sequence of events in more detail is
- RESET* and HALT* need to be asserted and then deasserted to reset the CPU.
- The 68000 will do word-size reads from addresses $000000 and $000002 and store the value in the the Supervisor State Pointer (SSP) .
- The 68000 will do word-size fetches of the reset vector from addresses $000003 and $000004 and load the program counter (PC).
- Execution then starts at the reset vector address read above.
- The CPU will fetch instruction words (of varying length) and execute the instruction.
- Then it will fetch and execute the next instruction, continuously cycling through memory.
For the 68000, a NOP instruction is $4E71. We can't actually use this because the CPU will read this value as the SSP and RESET vectors, and they need to be even addresses or the CPU will take an odd address exception. If the exception vector address read is also odd, it will then halt the CPU. A convenient value that does work is all zeroes, which corresponds to the instruction ORI.B #0,D0.
Our minimal freerun circuit is basically page 2 of the schematic. In addition we need to pull the 16 data lines low through pulldown resistors to force $0000 on the data bus, and in order to complete the bus cycles we can connect the 68000 AS* output to the DTACK* input.
I built this circuit on a solderless breadboard as in the picture above.
To start, I wired up the clock oscillator. I used a 1 MHz clock oscillator rather than 8 MHz because solderless breadboards don't tend to work well at higher frequencies. I verified it was working with my oscilloscope (which also has a frequency counter).
Then I built the power on reset circuit that uses a 555 timer to generate a suitable RESET pulse on power up. I confirmed that it generated the correct pulse on power on.
Next was the reset pusbutton circuit which uses some cross-coupled NAND gates to generate a clean reset pulse when the button is pressed. This was also working.
Next I wired up the 68000 CPU with the required pullup and pulldown resistors.
A problem I noticed initially with the full circuit was that the 5 volt power supply was dropping too low in voltage. It turned out that the jumper wires and alligator clips I was using were dropping too much voltage. I wired the power supply to the protoboard directly using heavier wires and the voltage then read close to 5.00 volts at the board.
Initial testing shows that the CPU was not executing instructions and was halted, as indicated the HALT* line being asserted (low). I eventually realized that this was because I had omitted the pullup resistors on the RESET* and HALT* lines. They are driven by open collector chips which require pullups to go high. I added the resistors and the CPU started executing in freerun mode. The address lines were toggling correctly at binary rates depending on the address line.
I tried changing the clock oscillator to an 8 MHz unit, and was surprised to find that it still ran. The clock signal was a little rough but this is impressive for a breadboard.
The current draw was 215 mA at 1 MHz and 256 mA at 8 MHz.
I observed the signals on the CPU, which were as follows:
CLK 8 MHz
E 800 kHz, not 50/50 duty cycle (which is normal)
A1 1 MHz
A2 500 kHz
A3 250 kHz
A4 125 kHz
A10 1.95 kHz
A20 2 Hz
AS* 2 MHz pulses
R/W* high (indicating read cycles)
FC0 low \
FC1 high > indicating supervisor program
FC2 high /
As a test, I pulled data line D0 up. On reset the CPU should then fetch a stack pointer of $00010001 and reset vector of $00010001, causing an odd address exception, double bus fault, and drive HALT* low. This happened as expected.
The power on reset circuit is working correctly, with the CPU starting reliably on powerup. It also reset whenever the switch was pressed.
Connecting AS* to DTACK* was the method suggested in the textbook to get the bus cycles to be completed. An alternate method, which also works, is simply to ground DTACK* (trivia: One of the early manufacturers of 68000-based computers was a company called Dtack Grounded).
An alternate freerun instruction that was suggested in a magazine article I found is $2040, MOVE D0,A0. This requires pulling D6 (pin 63) and D13 (pin 56) high, and the other data lines low. This also worked.
With freerun mode working, I'm ready to move on to the next phase, building more of the circuit on a wirewrapped prototype board. I'm still waiting for my protoboards to arrive before I can start that.