It would be nice if I could reduce parts count by emulating the 82C51A UART (or MC6850) using the AT90USB1286. Since the INT[7..0] interrupt pins are selectable between level or +/- edge sensitive and the pin-change interrupts will respond to ANY change of state, I will stick with the INT[7..0] pins. I want to trigger when the UART chip select goes high at which time the AVR will drop the WAIT line low to extend the read or write cycle while it services the request.
The AT90USB1286 data sheet states: “Interrupt Response Time: The interrupt execution response for all the enabled AVR interrupts is five clock cycles minimum. After five clock cycles the program vector address for the actual interrupt handling routine is executed. During these five clock cycle period, the Program Counter is pushed onto the Stack. The vector is normally a jump to the interrupt routine, and this jump takes three clock cycles. If an interrupt occurs during execution of a multi-cycle instruction, this instruction is completed before the interrupt is served. If an interrupt occurs when the MCU is in sleep mode, the interrupt execution response time is increased by five clock cycles. This increase comes in addition to the start-up time from the selected sleep mode.”
Doing some calculations, seems that at best, there will be a 5+3 cycle latency period just to set the program pointer to the first instruction of the ISR, then another 2 clock cycles to execute the instruction to drop the WAIT line pin, which makes 10 clock cycles. At 16MHz, the AVR’s clock period is 62.5nS, hence the AVR’s minimum interrupt latency will be 10 * 62.5nS or 625nS. That means that it will be at least 625nS before I can drop the Z80’s WAIT line to extend the RD/WR cycle. That won’t work since the Z80 datasheet says that the WAIT setup time must be at least 50nS before the falling edge of the clock after MREQ or IORQ goes active low and the hold time after the falling edge of the clock must be at least 10nS. With an 8MHz Z80 clock, the period is 125nS, so the AVR must be able to respond within in 75nS or less (125nS – 50nS = 75nS). Still, I would like to code up an ISR and perform some testing to see just what Z80 clock speed I can obtain a response.
My little test board is using an ATmega328P, not the AT90USB1286. The Interrupt Response Time is 1 cycle faster on the ATmega328P than the AT90USB1286. For simplicity, I have the RAM2 select connected to the INT0 pin of the ATmega328P and the WAIT pin is being driven by port bit B1. The functional code is below.
;============================================================= main: ;initialize TIMR0 to divide the CPU clock and output it on OC0A to be ; used as the system clock for the Z80. ; At this point, the I/O ports have already be initialized and ; the Z80 reset pin is being held low. cli ;clear global IRQ's CLRB PORTD,Z80WS ;insure Z80WS pin low GoSub Delay100mS ;delay for 100mS ;Now apply the clock signal CLRB PRR,PRTIM0,temp ;enable TIM0 in PRR ldi temp,$7 ;divider rate for 1MHz STORE OCR0A,temp tst temp ;is clock 8MHz brne main1a ;no, branch main1: SETB PORTD,Z80WS ;enable Z80WS wait-states main1a: ldi temp,( 1<0<2< STORE TCCR0A,temp ldi temp,( 0<1< STORE TCCR0B,temp ;Apply a system reset GoSub Delay100mS ;wait for 100mS SETB PORTB,Z80RST ;unleash the Z80 beast! ;setup for INT0 ldi temp,(2<<ISC00) ;set for falling edge trigger on INT0 STORE EICRA,temp SETB EIFR,INTF0 ;clear any pending INT0 interrupts SETB EIMSK,INT0 ;enable INT0 interrupts Main1z: nop rjmp Main1z ;============================================================= ; Routine to test servicing Z80 port select response. We want ; to stay in the ISR to block any other interrupts from being ; serviced until this routine is finished. ;============================================================= INT0_int: SETB DDRB,Z80WAIT ;set Z80WAIT pin to output SKBC UART_I,PORTB ;skip next if UART interrupted us rjmp INT0_int_out ;false trigger, return to caller ; dummy processing to simulate operation push temp GoSub Delay5uS ;delay a little pop temp INT0_int_out: CLRB DDRB,Z80WAIT ;set Z80WAIT pin to output reti ;return to caller ; ;=============================================================
Using the logic analyzer, I can clearly see that the interrupt latency is too great to be of any use at 1.5MHz to 8MHz Z80 clock speed. It does function correctly at 1MHz though but 1MHz is below the 2.5MHz clock speed rating of the Z80 when it was first released in 1976.
With the logic analyzer, I measured a interrupt response latency of 880nS at 1MHz Z80 clock speed. That’s 14 clock cycles on average, which is 4 cycles more than I had calculated but the AVR datasheet states there is a minimum of 5 clock cycles just to respond to a hardware interrupt, so the empiracle data correlates to the theoretical data.
If I use a simple “tight loop” structure to monitor the INTF0 flag in the EIFR register, there is still a 200 to 250nS response latency, so using the AVR to respond to a UART or DISK request in software is not possible.
Main1z: ; for polling the INTF0 flag sbic EIFR,INTF0 ;skip next if INTF0 is set rjmp Main1z ;continuously loop sbi DDRB,Z80WAIT ;set Z80WAIT pin to output call ServiceRoutine ;service the I/O request rjmp Main1z ;continue looping
AVR’s interrupt response latency. Z80 clock is 1MHz
Since I need to use the AVR for the SD memory “disk emulation”, I have to figure out a way to be able to make this method work. When the GAL22V10D SPLD’s come in, I will concentrate on the wait-state generator again as the only solution I see to proper operation is a hybrid software wait-state generation with hardware augmentation to buy the AVR time to take control of the WAIT line.
Next up, 1st attempt at a programmable wait-state generator.