📄 ps2d.asm
字号:
ENDIF
.delay_done:
RET
;-----------------------------------------------------------------------------
; FUNCTION NAME: PS2D_Send
; DESCRIPTION: Send a byte of data
;
;-----------------------------------------------------------------------------
;
; ARGUMENTS: A: Contains the data to send
;
; RETURNS: A: Contains completion code
;
; SIDE EFFECTS: REGISTERS ARE VOLATILE: THE A AND X REGISTERS MAY BE MODIFIED!
;
; THEORY of OPERATION or PROCEDURE:
;
;-----------------------------------------------------------------------------
PS2D_Send:
_PS2D_Send:
.data: equ -1 ; Local stack variables
.cnt: equ -2
.parity: equ -3
PUSH X ; Build the local variable
ADD SP, 3 ;
MOV X, SP ;
MOV [X + .data], A ; Save off the data byte
MOV [X + .parity], 1 ; Start the parity at 1
MOV [X + .cnt], 8 ; Send 8 data bits
; Test for inhibit
.inhibit_wait:
M8C_ClearWDT
TST REG[PS2D_DR], PS2D_SCLK ; Inhibit?
JZ .inhibit_wait ; Continue to wait if we are inhibited
DELAY 50, 0 ; Min delay between check for inhibit
TST REG[PS2D_DR], PS2D_SCLK ; Inhibit?
JZ .inhibit_wait ; Continue to wait if we are inhibited
; Test for RTS
TST REG[PS2D_DR], PS2D_SDATA ; RTS?
JZ .rts ; Jump if RTS
; Flow here to send start bit
CALL PS2D_Send_0 ; Start bits are zero
JC .inhib ; Host has inhibited
DELAY 2, 12 ; Wait 2 uSec
; Flow or jump here to sent the data bits
.snb:
ASR [X + .data] ; rotate the next bit to the carry
JC .s1 ; and send a 1 or 0 based
.s0:
CALL PS2D_Send_0 ; Send 0
JMP .cont
.s1:
INC [X + .parity] ; Count the number of 1 bits for the parity
CALL PS2D_Send_1 ; Send 1
.cont:
JC .inhib ; Did the host inhibit us during the last bit?
DEC [X + .cnt] ; If not, send the next bit
JZ .s_parity ; When it hits zero, do the parity
JNC .snb ; It will carry after the parity bit is sent
; Flow here to send the stop bit
CALL PS2D_Send_1 ; Stop bits are 1
JMP .success
; Flow here after all 8 data bits have been clocked out
.s_parity:
MOV A, [X + .parity] ; clock out the lsb of the parity
MOV [X + .data],a ; Save the data
JMP .snb
; Jump here on a successful stop bit
.success:
MOV A, 0 ; Flow here after a successful stop bit
JMP .exit
; Jump here if we failed because we were inhibited
.inhib: ; Jump here for any failed bit
CALL PS2D_Release ; Releaes the bus
MOV A, 0x88
JMP .exit
; Jump here if we found a RTS
.rts: ; Jump here for a RTS
MOV A, 0x90 ;
; Jump or flow here to exit
.exit:
ADD SP, -3 ; Clean up the stack
POP X
RET
;-----------------------------------------------------------------------------
; FUNCTION NAME: PS2D_Send_1, PS2D_Send_0
; DESCRIPTION: Local function. Assembly interface only.
;
;-----------------------------------------------------------------------------
;
; ARGUMENTS:
;
; RETURNS:
;
; SIDE EFFECTS: REGISTERS ARE VOLATILE: THE A AND X REGISTERS MAY BE MODIFIED!
;
; THEORY of OPERATION or PROCEDURE:
;
;-----------------------------------------------------------------------------
PS2D_Send_1:
OR [Port_1_Data_SHADE], PS2D_SDATA ; Set the data bit high
JMP PS2D_Clock_Out_Bit
PS2D_Send_0:
AND [Port_1_Data_SHADE], ~PS2D_SDATA ; Set the data bit low
JMP PS2D_Clock_Out_Bit ; This jump maintains the same number
; of clock cycles for both a 1 or 0
; Jump here to clock out the bit
PS2D_Clock_Out_Bit:
MOV A, [Port_1_Data_SHADE] ; Get the shadow
MOV REG[PS2D_DR], A ; Clock High and data
DELAY 10, 12 ; Wait 10 uSec
; Clock Low ; Clock Low and the data
XOR [Port_1_Data_SHADE], PS2D_SCLK ; Clock Low
MOV A, [Port_1_Data_SHADE] ; Get the shadow
MOV REG[PS2D_DR], A ; Clock Low and data
DELAY 38, 12 ; Wait 38 uSec
; Clock High ; Finally Clock High and the data
XOR [Port_1_Data_SHADE], PS2D_SCLK ; Clock High
MOV A, [Port_1_Data_SHADE] ; Get the shadow
MOV REG[PS2D_DR], A ; Clock High and data
DELAY 22, 60 ; Wait 22 uSec
; Check for inhibit
CLEARC ; Carry clear indicates success
TST REG[PS2D_DR], PS2D_SCLK ; Inhibit?
JNZ .clock_done ; Jump if not
SETC ; Carry set indicates fail/Inhibit
.clock_done:
; Done
RET
;-----------------------------------------------------------------------------
; FUNCTION NAME: PS2D_Receive
; DESCRIPTION:
; Receive one byte from the host. Assumes PS2_HostRequestToSend has
; been called to check for a host RTS
;
;-----------------------------------------------------------------------------
;
; ARGUMENTS:
;
; RETURNS:
; A = unsigned char from PS2 Host
; X = 00h Valid data
; X msb set indicates an error
; X = 10000000 no data
; X = 1xxxxxx1 parity error
; X = 1xxxxx1x bad stop bit
; X = 1xxxx1xx invalid start bit
; X = 1xxx1xxx inhibited
;
; SIDE EFFECTS: REGISTERS ARE VOLATILE: THE A AND X REGISTERS MAY BE MODIFIED!
;
; THEORY of OPERATION or PROCEDURE:
;
;-----------------------------------------------------------------------------
PS2D_Receive:
.data: equ -1 ; Local stack variables
.cnt: equ -2 ;
.parity: equ -3 ;
.r_status: equ -4 ;
ADD SP, 4 ;
MOV X, SP ;
; Look for the start bit--180 usec total
MOV [X + .r_status], 84h ; Assume no start bit
MOV [X + .cnt], 18 ; Do 18 samples ( 18 is legacy)
DELAY 30, 0
.check_start:
DELAY 10, 48
TST REG[PS2D_DR], PS2D_SCLK ; Ensure clock is set
JZ .exit ; Jump if clock not set, invalid start
TST REG[PS2D_DR], PS2D_SDATA ; Ensure data is set cleared
JNZ .exit ; Jump if data not clear, invalid start
DEC [X + .cnt] ; Check again?
JNZ .check_start ;
; Flow here for a valid start bit from the host
MOV A, 0 ; A will get the data bit rotated into the msb
MOV [X + .parity], A ; Start the parity at 0
MOV [X + .r_status], A ; Assume good data
MOV [X + .cnt], 8 ; Receive 8 data bits
.gnb:
CALL PS2D_GetBit ; Clock in the bit
JC .inhib ; Jump if inhibited
CMP A, 0x80 ; Accumulate the parity, if needed
JC .skip_parity ;
INC [X + .parity] ; Accumulate the parity
.skip_parity:
DEC [X + .cnt] ; Finished one bit
JC .stop ; Jump if we just did the parity bit
JNZ .gnb ; Get the next bit
MOV [X + .data], A ; Save the data
JMP .gnb ; Go get the parity
.stop:
CALL PS2D_GetBit ; Get the stop bit
JC .inhib ; Jump if inhibited
RLC A ; Stop bit should be 1
JC .ack ; Jump if we got the correct stop bit
MOV [X + .r_status], 0x82 ; Flag the bad stop bit
JNC .stop ; Keep looking for stop bit
.ack:
CALL PS2D_Send_0 ; Send a zero ack
JMP .exit ; We've already logged any errors in .r_status
.inhib:
MOV [X + .r_status], 0x84 ; Return inhibit
.exit:
CALL PS2D_Release ; Releaes the bus
TST [X + .parity], 01h ; Check the parity
JNZ .parity_ok
OR [x+.r_status],81h ; Return bad status
.parity_ok:
MOV A, [X + .data] ; return the data
MOV X, [X + .r_status] ; return the validity flag
ADD SP, -4 ; Clean up the stack
RET
;-----------------------------------------------------------------------------
; FUNCTION NAME: PS2D_GetBit
;
; DESCRIPTION:
; Clock in a single bit from the PS/2 Host
;
; ARGUMENTS:
; A--Normally the previous bits clocked in
;
; RETURNS:
; A >> 1 and msb of A is set to the clocked bit
; Carry set on error (Host Inhibit)
;
; SIDE EFFECTS:
; REGISTERS ARE VOLATILE: THE A AND X REGISTERS MAY BE MODIFIED!
;
; THEORY of OPERATION OR PROCEDURE:
; TOP goes here
;
;-----------------------------------------------------------------------------
PS2D_GetBit:
PUSH A ; Save the previously clocked data
DELAY 10, 12 ; Wait 10 uSec
; Clock Low
AND [Port_1_Data_SHADE], ~PS2D_SCLK ; Clock Low
MOV A, [Port_1_Data_SHADE] ; Get the shadow
MOV REG[PS2D_DR], A ; Update
DELAY 38, 12 ; Wait 38 uSec
; Clock high
OR [Port_1_Data_SHADE], PS2D_SCLK ; Clock High
MOV A, [Port_1_Data_SHADE] ; Get the shadow
MOV REG[PS2D_DR], A ; Update
DELAY 22, 72 ; Wait 22 uSec
; Sample the data
MOV A, REG[PS2D_DR] ; Sample the data
; Extract the data
CLEARC ; Assume the clocked bit is 0
AND A, PS2D_SDATA ; Isolate the data bit
JZ .exit
SETC ; The clocked bit was 1
.exit:
; The following lines does not change C
POP A ; Restore the previously saved data
TST REG[PS2D_DR], PS2D_SCLK ; Get the port
JZ .error ; Error if inhibit
RRC A ; MSB updated with the clocked bit
CLEARC
RET
.error:
SETC ; Flag error/inhibit
RET
; End of File PS2D.asm
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -