recipes/rc2014/ps2: add "resend" requests on parity check failures

This commit is contained in:
Virgil Dupras 2019-06-30 11:17:12 -04:00
parent 0f82ebe02d
commit 2c6ab08d51

View File

@ -75,7 +75,7 @@
; - 2: awaiting parity bit ; - 2: awaiting parity bit
; - 3: awaiting stop bit ; - 3: awaiting stop bit
; it reaches 11, we know we're finished with the frame. ; it reaches 11, we know we're finished with the frame.
; R19: Register used for parity computations ; R19: Register used for parity computations and tmp value in some other places
; R20: data being sent to the 595 ; R20: data being sent to the 595
; Y: pointer to the memory location where the next scan code from ps/2 will be ; Y: pointer to the memory location where the next scan code from ps/2 will be
; written. ; written.
@ -174,14 +174,13 @@ loop:
; Process the data bit received in INT0 handler. ; Process the data bit received in INT0 handler.
processbit: processbit:
in r16, GPIOR0 ; backup GPIOR0 before we reset T in r19, GPIOR0 ; backup GPIOR0 before we reset T
andi r16, 0x1 ; only keep the first flag andi r19, 0x1 ; only keep the first flag
cbi GPIOR0, 0 cbi GPIOR0, 0
clt ; ready to receive another bit clt ; ready to receive another bit
; We've received a bit. reset timer ; We've received a bit. reset timer
ldi r19, TIMER_INITVAL rcall resetTimer
out TCNT0, r19
; Which step are we at? ; Which step are we at?
tst r18 tst r18
@ -193,7 +192,7 @@ processbit:
; step 3: stop bit ; step 3: stop bit
clr r18 ; happens in all cases clr r18 ; happens in all cases
; DATA has to be set ; DATA has to be set
tst r16 ; Was DATA set? tst r19 ; Was DATA set?
breq loop ; not set? error, don't push to buffer breq loop ; not set? error, don't push to buffer
; push r17 to the buffer ; push r17 to the buffer
st Y+, r17 st Y+, r17
@ -203,7 +202,7 @@ processbit:
processbits0: processbits0:
; step 0 - start bit ; step 0 - start bit
; DATA has to be cleared ; DATA has to be cleared
tst r16 ; Was DATA set? tst r19 ; Was DATA set?
brne loop ; Set? error. no need to do anything. keep r18 brne loop ; Set? error. no need to do anything. keep r18
; as-is. ; as-is.
; DATA is cleared. prepare r17 and r18 for step 1 ; DATA is cleared. prepare r17 and r18 for step 1
@ -216,7 +215,7 @@ processbits1:
; We're about to rotate the carry flag into r17. Let's set it first ; We're about to rotate the carry flag into r17. Let's set it first
; depending on whether DATA is set. ; depending on whether DATA is set.
clc clc
sbrc r16, 0 ; skip if DATA cleared. sbrc r19, 0 ; skip if DATA cleared.
sec sec
; Carry flag is set ; Carry flag is set
ror r17 ror r17
@ -228,21 +227,23 @@ processbits1:
rjmp loop rjmp loop
processbits2: processbits2:
; step 2 - parity bit ; step 2 - parity bit
mov r1, r16 mov r1, r19
mov r19, r17 mov r19, r17
rcall checkParity ; --> r16 rcall checkParity ; --> r16
cp r1, r16 cp r1, r16
; TODO: implement "resend requests" on parity check failure brne processbitError ; r1 != r16? wrong parity
brne processbitReset ; r1 != r16? wrong parity
inc r18 inc r18
rjmp loop rjmp loop
processbitError:
clr r18
ldi r19, 0xfe
rcall sendToPS2
rjmp loop
processbitReset: processbitReset:
clr r18 clr r18
ldi r16, TIMER_INITVAL rcall resetTimer
out TCNT0, r16
ldi r16, (1<<TOV0)
out TIFR, r16
rjmp loop rjmp loop
; send next scan code in buffer to 595, MSB. ; send next scan code in buffer to 595, MSB.
@ -293,6 +294,105 @@ sendTo595Loop:
rjmp loop rjmp loop
resetTimer:
ldi r16, TIMER_INITVAL
out TCNT0, r16
ldi r16, (1<<TOV0)
out TIFR, r16
ret
; Send the value of r19 to the PS/2 keyboard
sendToPS2:
; We don't use the general INT0 mechanism here. However, we still want
; to listen to PCINT, so we don't disable interrupts entirely, just
; INT0.
ldi r16, (1<<PCIE)
out GIMSK, r16
; First, indicate our request to send by holding both Clock low for
; 100us, then pull Data low
; lines low for 100us.
cbi PORTB, CLK
sbi DDRB, CLK
rcall resetTimer
; Wait until the timer overflows
in r16, TIFR
sbrs r16, TOV0
rjmp PC-2
; Good, 100us passed.
; Pull Data low, that's our start bit.
cbi PORTB, DATA
sbi DDRB, DATA
; Now, let's release the clock. At the next raising edge, we'll be
; expected to have set up our first bit (LSB). We set up when CLK is
; low.
cbi DDRB, CLK ; Should be starting high now.
; We will do the next loop 8 times
ldi r16, 8
; Let's remember initial r19 for parity
mov r1, r19
sendToPS2Loop:
; Wait for CLK to go low
sbic PINB, CLK
rjmp PC-1
; set up DATA
cbi PORTB, DATA
sbrc r19, 0 ; skip if LSB is clear
sbi PORTB, DATA
lsr r19
; Wait for CLK to go high
sbis PINB, CLK
rjmp PC-1
dec r16
brne sendToPS2Loop ; not zero? loop
; Data was sent, CLK is high. Let's send parity
mov r19, r1 ; recall saved value
rcall checkParity ; --> 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.
ldi r16, (1<<INT0)|(1<<PCIE)
out GIMSK, r16
ret
; Check that Y is within bounds, reset to SRAM_START if not. ; Check that Y is within bounds, reset to SRAM_START if not.
checkBoundsY: checkBoundsY:
tst YL tst YL