Browse Source

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

pull/10/head
Virgil Dupras 5 years ago
parent
commit
2c6ab08d51
1 changed files with 115 additions and 15 deletions
  1. +115
    -15
      recipes/rc2014/ps2/ps2ctl.asm

+ 115
- 15
recipes/rc2014/ps2/ps2ctl.asm View File

@@ -75,7 +75,7 @@
; - 2: awaiting parity bit
; - 3: awaiting stop bit
; 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
; Y: pointer to the memory location where the next scan code from ps/2 will be
; written.
@@ -174,14 +174,13 @@ loop:

; Process the data bit received in INT0 handler.
processbit:
in r16, GPIOR0 ; backup GPIOR0 before we reset T
andi r16, 0x1 ; only keep the first flag
in r19, GPIOR0 ; backup GPIOR0 before we reset T
andi r19, 0x1 ; only keep the first flag
cbi GPIOR0, 0
clt ; ready to receive another bit

; We've received a bit. reset timer
ldi r19, TIMER_INITVAL
out TCNT0, r19
rcall resetTimer

; Which step are we at?
tst r18
@@ -193,7 +192,7 @@ processbit:
; step 3: stop bit
clr r18 ; happens in all cases
; 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
; push r17 to the buffer
st Y+, r17
@@ -203,7 +202,7 @@ processbit:
processbits0:
; step 0 - start bit
; 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
; as-is.
; 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
; depending on whether DATA is set.
clc
sbrc r16, 0 ; skip if DATA cleared.
sbrc r19, 0 ; skip if DATA cleared.
sec
; Carry flag is set
ror r17
@@ -228,21 +227,23 @@ processbits1:
rjmp loop
processbits2:
; step 2 - parity bit
mov r1, r16
mov r1, r19
mov r19, r17
rcall checkParity ; --> r16
cp r1, r16
; TODO: implement "resend requests" on parity check failure
brne processbitReset ; r1 != r16? wrong parity
brne processbitError ; r1 != r16? wrong parity
inc r18
rjmp loop

processbitError:
clr r18
ldi r19, 0xfe
rcall sendToPS2
rjmp loop

processbitReset:
clr r18
ldi r16, TIMER_INITVAL
out TCNT0, r16
ldi r16, (1<<TOV0)
out TIFR, r16
rcall resetTimer
rjmp loop

; send next scan code in buffer to 595, MSB.
@@ -293,6 +294,105 @@ sendTo595Loop:

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.
checkBoundsY:
tst YL


Loading…
Cancel
Save