📄 ps2_io.asm
字号:
;========================================================================
; FILE: ps2_io.asm
;
; This file contains the code that sends/receives data via the
; D- and D+ output pins, in ps2 format
;REVISION_HISTORY:
;
;8/25/98 Added a 50 usec delay prior to sending commands.
;Some PC's did not like it without this delay.
;
;
;========================================================================
;
;defines for the 4 combinations of clock and data
CLKH_DATAH: equ DPH_DMH
CLKL_DATAH: equ DPL_DMH
CLKH_DATAL: equ DPH_DML
CLKL_DATAL: equ DPL_DML
;========================================================================
; FUNCTION: ps2_send
;
; Sends a byte
;
;
; Returns:
; C= 0 if transmission was successful
; C= 1 if not
;
;========================================================================
ps2_send:
push A ;save our data byte
push X ;save X register
mov X,A ;save data byte momentarily in X
iord USB_STATUS_CONTROL_REG ;get clock/data pair
and A,(PS2_CLOCK_BIT + PS2_DATA_BIT) ;mask off other bits in port
cmp A,(PS2_CLOCK_BIT + PS2_DATA_BIT) ;if both are not high,
jz .l1
SETC
jmp .exit ;exit this routine with carry set
.l1:
DELAY 50
call send_0 ;clock out start bit
jc .exit ;if a problem, quit now
mov A,1
mov [ps2_temp0],A ;keep track of parity
mov A,X ;get back our data byte
mov X,8 ;count 8 bits
.l2:
asr A ;shift bit to send into carry
jc .one ;if carry is zero
call send_0 ;send a zero
jc .exit ;problem, quit now
jmp .next ;
.one: ;else
call send_1 ; send a 1
jc .exit ; problem, quit now
inc [ps2_temp0] ; keep track of parity
.next: ;
dec X ;decrement counter
jz .parity ;if at zero do parity
jnc .l2 ;if -1, exit
.stopbit:
call send_1 ;clock out stop bit
CLEARC
jmp .exit
.parity:
mov A,[ps2_temp0] ;now send parity too
jmp .l2
.exit:
mov A,CLKH_DATAH ;make sure PS2 bus is left idle
iowr USB_STATUS_CONTROL_REG
pop X
pop A
ret ;return
;========================================================================
; FUNCTION: send_0,send_1
;
; Sends bit out the ps2 port
;
;
; Returns:
; C= 0 if transmission was successful
; C= 1 if not
;
;========================================================================
;
;the following state table defines the next state for the clock-data pair
;to clock out a given bit.
;
XPAGEOFF
drive_table:
db 0,0,0,CLKH_DATAL,0,CLKL_DATAL,CLKH_DATAH,CLKL_DATAH
XPAGEON
send_1:
push A
mov A,CLKH_DATAH ;start with clock high, data high
jmp clock
send_0:
push A
mov A,CLKH_DATAL ;start with clock high, data low
clock:
push A
iord USB_STATUS_CONTROL_REG ;read clock
and A,PS2_CLOCK_BIT
pop A
jnz .l2
SETC
pop A ;should be high
ret
.l2:
iowr USB_STATUS_CONTROL_REG ;set up register
DELAY 5
index drive_table ;wait 5 us
iowr USB_STATUS_CONTROL_REG ;write it out
DELAY 35 ;delay as per spec
index drive_table ;deassert clock
iowr USB_STATUS_CONTROL_REG
DELAY 30 ;wait as per spec
CLEARC
pop A
ret
;========================================================================
; FUNCTION: getbit
;
; Receives a bit
;
;
; Returns:
; C = state of bit clocked in
;
;========================================================================
getbit:
push A ;push A
iord USB_STATUS_CONTROL_REG ;if inhibit, get out now
and A,PS2_CLOCK_BIT
jz .error
mov A,CLKL_DATAH ;start with clock low, data high
iowr USB_STATUS_CONTROL_REG
DELAY 35 ;wait 35 usec
mov A,CLKH_DATAH ;raise clock line
iowr USB_STATUS_CONTROL_REG ;
DELAY 5 ;wait 5 usec
iord USB_STATUS_CONTROL_REG ;read the data line
DELAY 30 ;wait 25 usec
and a, PS2_DATA_BIT ;mask off all but data bit
jz .low ;if data bit high,
SETC ;set the carry
.low:
pop A ;pop acc and rotate carry into msb
rrc A
CLEARC ;clear carry indicating success
ret ;return
.error:
pop A
SETC
ret
;========================================================================
; FUNCTION: ps2_receive
;
; Receives a byte
;
;
; Returns:
; C= 0 if reception was successful
; C= 1 if not
;
;========================================================================
ps2_receive:
push X ;save X, we'll wipe it out
mov X,18 ;do the following 18 times:
.wait: ;
DELAY 7 ;kill time for 7 us
iord USB_STATUS_CONTROL_REG ;get port 3 data
and A,PS2_DATA_BIT ;make sure data bit low
jnz .exitearly ;out now if not
dec X ;wait again
jnz .wait ;
;above loop consumes approx 180 us.
.start:
; DELAY 5 ;wait prior to anything
mov X,8 ;count 9 bits (8 data, 1 parity)
mov A,0 ;clear parity count
mov [ps2_temp0],A
.l1:
call getbit
jc .inhibit ;if not inhibiting
cmp A,80h ;see if msbit = 1
jc .next ;yup,
inc [ps2_temp0] ;increment parity count
.next:
dec X ;decrement counter
jc .done ;if at -1, done
jnz .l1
push A ;else save partial result
jmp .l1
.inhibit: ;we were inhibited in
dec X ;the middle of getting stuff,
jc .done ;adjust stack appropriately
push A
.done:
;arrive here with data byte on the stack and the received parity bit in the msb
;of the accumulator. the calculated parity bit is in the lsb of ps2_temp0.
;if we arrived here due to host inhibit, both parity and data byte are
;garbage but that's ok -- we'll abort out of this routine anyway.
mov A,[ps2_temp0] ;
and A,1
mov X,A
;X should be 1 if ok
call getbit ;get stop bit
jc .error ;if no problem getting it
rlc a
jc .ack ;if it's not a 1
mov X,0 ;X= 0 indicates an error
.badstop: ;
call getbit ;keep looking for it
jc .error
rlc a
jnc .badstop
.ack:
;arrive here with x = 0 if no errors
call send_0 ;send a 0 to ack the transaction
mov A,X
cmp A,0
jz .error
.exit:
mov A,CLKH_DATAH ;make sure PS2 bus is left idle
iowr USB_STATUS_CONTROL_REG
jmp .return
.error:
mov A,CLKH_DATAH ;make sure PS2 bus is left idle
iowr USB_STATUS_CONTROL_REG
SETC ;set carry indicating a problem
.return:
pop A ;pop result into ACC
pop X ;restore X
ret
.exitearly:
SETC
pop X
ret
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -