.include "tn45def.inc" ; Receives keystrokes from PS/2 keyboard and send them to the '164. On the PS/2 ; side, it works the same way as the controller in the rc2014/ps2 recipe. ; However, in this case, what we have on the other side isn't a z80 bus, it's ; the one of the two controller ports of the SMS through a DB9 connector. ; The PS/2 related code is copied from rc2014/ps2 without much change. The only ; differences are that it pushes its data to a '164 instead of a '595 and that ; it synchronizes with the SMS with a SR latch, so we don't need PCINT. We can ; also afford to run at 1MHz instead of 8. ; *** Register Usage *** ; ; GPIOR0 flags: ; 0 - when set, indicates that the DATA pin was high when we received a ; bit through INT0. When we receive a bit, we set flag T to indicate ; it. ; ; R16: tmp stuff ; R17: recv buffer. Whenever we receive a bit, we push it in there. ; R18: recv step: ; - 0: idle ; - 1: receiving data ; - 2: awaiting parity bit ; - 3: awaiting stop bit ; R19: Register used for parity computations and tmp value in some other places ; R20: data being sent to the '164 ; Y: pointer to the memory location where the next scan code from ps/2 will be ; written. ; Z: pointer to the next scan code to push to the 595 ; ; *** Constants *** .equ CLK = PINB2 .equ DATA = PINB1 .equ CP = PINB3 ; SR-Latch's Q pin .equ LQ = PINB0 ; SR-Latch's R pin .equ LR = PINB4 ; init value for TCNT0 so that overflow occurs in 100us .equ TIMER_INITVAL = 0x100-100 ; *** Code *** rjmp main rjmp hdlINT0 ; Read DATA and set GPIOR0/0 if high. Then, set flag T. ; no SREG fiddling because no SREG-modifying instruction hdlINT0: sbic PINB, DATA ; DATA clear? skip next sbi GPIOR0, 0 set reti main: ldi r16, low(RAMEND) out SPL, r16 ldi r16, high(RAMEND) out SPH, r16 ; init variables clr r18 out GPIOR0, r18 ; Setup int0 ; INT0, falling edge ldi r16, (1< r16 cp r1, r16 brne processbitError ; r1 != r16? wrong parity inc r18 rjmp loop processbitError: clr r18 ldi r19, 0xfe rcall sendToPS2 rjmp loop processbitReset: clr r18 rcall resetTimer rjmp loop ; Send the value of r20 to the '164 sendTo164: sbis PINB, LQ ; LQ is set? we can send the next byte rjmp loop ; Even if we have something in the buffer, we ; can't: the SMS hasn't read our previous ; buffer yet. ; We disable any interrupt handling during this routine. Whatever it ; is, it has no meaning to us at this point in time and processing it ; might mess things up. cli sbi DDRB, DATA ld r20, Z+ rcall checkBoundsZ ldi r16, 8 sendTo164Loop: cbi PORTB, DATA sbrc r20, 7 ; if leftmost bit isn't cleared, set DATA high sbi PORTB, DATA ; toggle CP cbi PORTB, CP lsl r20 sbi PORTB, CP dec r16 brne sendTo164Loop ; not zero yet? loop ; release PS/2 cbi DDRB, DATA sei ; Reset the latch to indicate that the next number is ready sbi PORTB, LR cbi PORTB, LR rjmp loop resetTimer: ldi r16, TIMER_INITVAL out TCNT0, r16 ldi r16, (1< r16 ; Wait for CLK to go low sbic PINB, CLK rjmp PC-1 ; set parity bit cbi PORTB, DATA sbrc r16, 0 ; parity bit in r16 sbi PORTB, DATA ; Wait for CLK to go high sbis PINB, CLK rjmp PC-1 ; Wait for CLK to go low sbic PINB, CLK rjmp PC-1 ; We can now release the DATA line cbi DDRB, DATA ; Wait for DATA to go low. That's our ACK sbic PINB, DATA rjmp PC-1 ; Wait for CLK to go low sbic PINB, CLK rjmp PC-1 ; We're finished! Enable INT0, reset timer, everything back to normal! rcall resetTimer clt ; also, make sure T isn't mistakely set. sei ret ; Check that Y is within bounds, reset to SRAM_START if not. checkBoundsY: tst YL breq PC+2 ret ; not zero, nothing to do ; YL is zero. Reset Y clr YH ldi YL, low(SRAM_START) ret ; Check that Z is within bounds, reset to SRAM_START if not. checkBoundsZ: tst ZL breq PC+2 ret ; not zero, nothing to do ; ZL is zero. Reset Z clr ZH ldi ZL, low(SRAM_START) ret ; Counts the number of 1s in r19 and set r16 to 1 if there's an even number of ; 1s, 0 if they're odd. checkParity: ldi r16, 1 lsr r19 brcc PC+2 ; Carry unset? skip next inc r16 ; Carry set? We had a 1 tst r19 ; is r19 zero yet? brne checkParity+1 ; no? loop and skip first LDI andi r16, 0x1 ; Sets Z accordingly ret