The plan is to use the AT90USB1286 (PJRC TEENSY 2.0 ++ board) as a virtual UART and “Disk Drive” (using an SD memory card). Testing the AVR’s response time to DISK and UART selects as interrupts on the INT0 input is a problem. Using INT0, it takes 14 clock cycles to respond and set the I/O pin low to assert the Z80’s WAIT line. The TEENSY 2.0 ++ runs at 16MHz, thus one cpu cycle is 62.5nS. 14 * 62.5nS = 875nS, which works fine at a 1MHz Z80 clock speed with a 1uS cycle time BUT any clock speed above that and the AVR just cannot respond fast enough.
The project goal is to be able to run the Z80 at 8MHz but also be able to run at slower speeds, say for “single-stepping” at 31.5KHz for the Z80. Any Z80 clock speed 1MHz and less is not a problem but I wish to achieve a maximum speed of 8MHz, perhaps even 10MHz, since I have Z84C0020 parts, which are rated for 20MHz. The solution is to insert wait-states for Z80 clock speeds above 1MHz. Each clock speed would need a different number of wait-states.
In calculating the needed wait-states, I came up with these:
8Mhz = 7 wait states 4MHz = 4 wait states 2Mhz = 2 wait states 1MHz >= 0 wait states
I thought of perhaps using one of the AVR’s timers as the wait-state generator. Set the OC1A pin to drop low, asserting the Z80 WAIT line, at OCR1A match, which would be adjustable based on the Z80’s clock speed. The Z80 clock could be gated by the UART or DISK chip selects into the AVR’s T1 input to feed the timer. Although, the AVR does not support eternal gating of the clock source to it’s timers, so I would need an external gating circuit to do so. It turns out that I had a few pins left on the memory decoder PLD and I am already decoding the DISK and UART chip selects, so why not use it? I went ahead and coded up the gating logic to feed into the AVR’s T1 pin. I also needed to insure the the AVR’s OC1A pin is tri-state-able so I ran it back into the PLD through a register to take advantage of the output enable logic. Upon completion, the simulator worked fine but in hardware testing with an ATmega328P (my current “functional test board”), it didn’t work so well. Using the logic analyzer, I could see that there just wasn’t enough clock cycles to reliably gate the AVR’s T1 input and increment the counter.
I knew it was a sampling issue so I enabled the AVR’s CLKOUT pin to access the AVR’s 16MHz system clock on the PB0 pin. Now that worked a little better but it still was not reliable. The AVR is capable of using it’s main system clock as the timer’s clock source, which in this case is 16MHz BUT the T1 input has edge detection logic, which must be introducing a delay and doesn’t allow enough clock cycles to pass to reliably gate the AVR timer’s T1 input and increment the timer reliably. Although I cannot seem to find anything in the AVR datasheet about T1 clock rate vs. AVR system clock ratio, I seem to recall testing it some years ago and found it to be half of the system clock. Hmmm, well that presents a problem because now I am limited to a maximum T1 clock of 8Mhz. I would prefer to over-sample and use a 4x Z80 clock but that means I have to run the Z80 at 2MHz. If I I run the Z80 at 1MHz, I don’t need to insert wait-states. It also means that to run the Z80 at 8MHz, I need to feed the AVR’s T1 pin a 32MHz clock source, which isn’t going to work either because the maximum “stated” clock speed for the AT90USB1286 running at 5 volts is 20MHz. I know it can be overclocked safely to about 24MHz but I would have to change the crystal on the TEENSY 2.0 ++ board. Also, once the OCR1A match happens, the OC1A pin is dropped low but I can’t figure out how to get it set high again. There seems to be no way to preload the level before or after a match.
Looks like I can’t use the AVR’s timer for this function after all and am back to having to use more external logic outside the AVR to do this.
Bottom line is that I need a programmable wait-state generator that I can use as a “hardware assist” for the AVR. In other words, let the hardware-assisted wait-state generator seize the WAIT line for the desired number of wait states and then having the AVR take over and seize the WAIT line assertion until it has finished its operation.
Its tough to find any circuit suggestions for wait-state generators on “the net” because the days of the Z80/8085/8088/8086/6505/68xx bus-based CPU’s and slow DRAM are pretty much over. Now, modern day CPU’s use memory controllers with built-in wait-state generators or have one built into the DSP or microcontroller. I did find exactly two different circuits for wait-state generators with jumper-selectable wait-states. They both use standard 74HC series parts. One uses the 74HC164 serial-to-parallel shift register and the other uses a 74HC165 parallel-to-serial shift register. In the designs that I found, the 74HC164/74HC165 is being used to assert the RDY line of an 8085 or 8088/8086’s clock generator, which is an 82C84. I see what they are doing with generating wait-states by shifting a high bit through each successive register but I need to change the polarity and the designs use a jumper to select which “tap” they want to use. Since my Z80 clock will be “user selectable” but controlled by the AVR, I need to also be able to select how many wait states to insert based on the user’s desired Z80 clock speed. Though, I expect it will always remain at 8MHz.
Back to the wait-state calculations; I have four clock speeds, thus 4 different wait-states durations to choose from. Seems to me that a simple 4:1 digital multiplexer should at least allow me to select which “Q tap” to use and the AVR can control the “S[1:0] lines based on the chosen Z80 clock speed. I thought I could implement all this in a PLD and I have some extra AFT16V8B’s but the 16V8 and 20V8’s types do not have PR and CL inputs available on their registers, only “D” and “\Q”, so I’ll have to see what I can do. I was thinking that the GAL16V8 was large enough to accommodate a 7-bit shift register and the WAIT line, 8 outputs total.
After about 20 minutes, I had the 4:1 MUX designed and the test vectors checked out. Time to design the shift register. I only have 8 output pins available on the ATF16V8B and since each register takes up a pin, I am only able to implement a 7-bit shift register because I still a pin to drive the Z80’s WAIT line. That gives me access to only 6 wait-states but I am testing my theory, so it’ll do for now.
I am not going to lie and say that I had all this done in 20 minutes as well because it took some time to figure it all out, like nearly a week off and on! Besides, my PLD designing is a little rusty as I have not done this type of work since the early 2000’s. I was having difficulty getting the logic equations to work out properly, as it was a little confusing determining all the Q output states that would be needed for 0, 2, 4 and 7 wait-states. I finally stepped away and back a little. I then realized that I could let the logic compiler figure more combinatorial logic out for me if I used higher level constructs for the select inputs and the Q outputs, so I turned the 7-bit register outputs into a 7-bit count value. Once I did that, I could tell the logic compiler to only assert the WAIT line if certain conditions were met, namely, the states of the select inputs (S1 and S0 for the MUX) and which Q outputs to use in determining when to assert the WAIT line by comparing to specific “count values” for each wait-state of the current S1/S0 selection.
I was still having difficulty trying to figure out how to preset the Q outputs back to “1” after the desired wait-states had been achieved. I ignored that for the time being, I tried the test vectors and they seemed to work.
Now for the actual “live test” in hardware, which turned out to be “not-so-good”. The bottom line is that this particular method does not work as there is no way to reset the internal registers after a power-up condition. With each attempted use of the wait-state generator, the state of the Q outputs at any given time is thus unknown and unreliable.
Next up, moving the wait-state generator into a GAL22V10.