⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main_asm.txt

📁 PS/2 设备接口用于许多现代的鼠标和键盘它是由IBM 开发并且最初出现在IBM 技术参考手册里但 是当我知道的时候这篇文件就已经很多年没有印刷了因此关于这个内容现在没有官方的出版物我 无法访问I
💻 TXT
📖 第 1 页 / 共 2 页
字号:
;*******************************************************************************
; Title:	Keyboardswitch-deluxe
; Author: 	Anders Runeson, arune@users.sf.net
; 		Andreas Fritiofson, 
; Version:	
; Date:		2003/06/xx - 2004/xx/xx
; 
; Target:	AT90Sxxxx (All AVR Devices)
;
; DESCRIPTION
; 
; 
; The timing is adapted for 4 MHz xtal
;
; Usage: 
; 
; 
;*******************************************************************************
;todo:
;
;funktion: blinka led d堥n pc bootas
;
;spara saker i eeprom
;

.include "2313def.inc"

;Hardware:
.equ	KBD_CK	=PB7		;PD5
.equ	KBD_DATA	=PB6		;PD4


.equ	PCc_CK	=PB4		;PB5
.equ	PCc_DATA	=PB5		;PB4
.equ	PCb_CK	=PB2		;PB3
.equ	PCb_DATA	=PB3		;PB2
.equ	PCa_CK	=PB0		;PB1
.equ	PCa_DATA	=PB1		;PB0

.equ	MOUSEc_E	=PD3
.equ	MOUSEb_E	=PD4
.equ	MOUSEa_E	=PD5

;debug
.equ	Uart_TxD	=PD1		;o_Data to UART is PD1
.equ	Uart_RxD	=PD0		;i_Data from UART is PD0

;.equ	LED		=PD2

; Status flags
.equ	VALID		=0	; There's new valid data in RxByte
.equ	ERROR		=1	; There was an error during last reception
.equ	BREAK		=2	; Last byte received was a break (F0)
.equ	EXTENDED	=3	; Last byte received was "extended" (E0)
.equ	KB_CAPS	=4	; Use Caps as function-key, flag indicates if Caps is being pressed

;Define regs used
.def	parity_cnt		=R4
.def	temp2			=R8
.def	temp3			=R9
.def	blkcnt1		=R10
.def	blkcnt2		=R11
.def	blkcnt3		=R12
.def	ledstatus		=R13
.def	bootingcomp		=R14

.def	temp			=R17
.def	Status		=R18
.def	bitcnt		=R20
.def	TxByte		=R21	;kan anv䮤a samma reg ifall det krisar sig (kanske inte, kolla processdata)
.def	RxByte		=R22
.def	LoopPC		=R23
.def	CurrentPC		=R24
.def	ConnectedPCs	=R25
;for PCa: LoopPC=0b00000001, PCb: LoopPC=0b00000100, PCc: LoopPC=0b00010000, PCd: LoopPC=0b01000000
;same with CurrentPC

;***** Other 
;This is what avr responds when pc asks for ID (0xF2)
.equ	KBD_ID0		=0xAB
.equ	KBD_ID1		=0x83

.equ	KBD_ACK		=0xFA
.equ	KBD_BAT_SUCCESS	=0xAA
.equ	KBD_ECHO		=0xEE

.equ	KBD_TMDelay 	=0b01		;Typematic repeat delay (0b00=250ms, 0b01=500ms, 0b10=750ms, 0b11=1000ms)
.equ	KBD_TMRate	 	=0b00100	;Typematic repeat rate
					;0b00000=30.0cps -> 0b11111=2.0cps
					;30.0, 26.7, 24.0, 21.8, 20.0, 18.5, 17.1, 16.0 , 15.0, 13.3, 12.0, 10.9, 10.0, 9.2, 8.6, 8.0, 7.5, 6.7, 6.0, 5.5, 5.0, 4.6, 4.3, 4.0, 3.7, 3.3, 3.0, 2.7, 2.5, 2.3, 2.1, 2.0

.equ	MOUSEPORTMASK	=0b00111000	;which ports on PD have a mouse_enable connected
						;TODO; flytta om dessa, klart?
.equ	NUMLOCKLED		=0x02
.equ	SCROLLOCKLED	=0x01
.equ	CAPSLOCKLED		=0x04

;.equ	CONNECTED_PCs	=0b00001100	;1 PCs 0b00000011, 2 PCs 0b00001111, 3 PCs 0b00111111, 4 PCs 0b11111111

;#############################################################
;#              RESET                                        #
;#############################################################
.ORG	0x00
		rjmp	RESET				;Reset Handler
;.ORG	OVF1addr
;		rjmp	OVFL_TIM1			;Timer1 Overflow handler

RESET:
		cli					;Disable interrupts
;#############################################################
;#              INIT                                         #
;#############################################################

		;INIT STACKPOINTER
		ldi 	temp,low(RAMEND)
		out 	SPL,temp

		;INIT PORT D
		;set inputs/outputs (1 = output)
		ldi	temp,(1<<MOUSEa_E)|(1<<MOUSEb_E)|(1<<MOUSEc_E)	;|(1<<LED)
		out	DDRD,temp
		
		;set PORT-status (1 = pullup for inputs)
		ldi	temp,(0<<MOUSEa_E)|(0<<MOUSEb_E)|(0<<MOUSEc_E)	;|(1<<LED)
		out	PORTD,temp
		
		;INIT PORT B
		;set inputs/outputs (1 = output)
		ldi	temp,(0<<KBD_CK)|(0<<KBD_DATA)|(0<<PCa_CK)|(0<<PCa_DATA)|(0<<PCb_CK)|(0<<PCb_DATA)|(0<<PCc_CK)|(0<<PCc_DATA)	;|(0<<PCd_CK)|(0<<PCd_DATA)
		out	DDRB,temp
		;set PORT-status (1 = pullup for inputs)
		ldi	temp,(0<<KBD_CK)|(0<<KBD_DATA)|(0<<PCa_CK)|(0<<PCa_DATA)|(0<<PCb_CK)|(0<<PCb_DATA)|(0<<PCc_CK)|(0<<PCc_DATA)	;|(0<<PCd_CK)|(0<<PCd_DATA)
		out	PORTB, temp

		;INIT UART
;		ldi	temp,(1<<TXEN)	;|(1<<RXEN)	;0b00011000
;		out	UCR,temp
		
;		ldi	temp,12			;25=9600, 12=19200, 
;		out	UBRR,temp
		
		;INIT TIMER1 - 16bit
		;start timer1
		;timer1 is used as watchdog timeout (not exacly, but almost), so that the program doesnt get stuck 
		;in routines checking ports (loops)
		ldi	temp,0b00000001		;no prescaler, running timer on CK
		out	TCCR1B,temp
		
		;INIT EXT-INTERRUPT 
		
		
		;INIT KEYBOARD
		;almost all commands from the pc is ignored (see process_to_keyb)
		;below there are some commands sent to keyb manually, like reset and set typematic rate/delay

		;Send keyboard reset
		ldi	TxByte,0xFF
		rcall	avr_to_keyb
		rcall	delay100us
		rcall	Wait_keyb_byte			;catch ack
		rcall	delay100us
		rcall	Wait_keyb_byte			;catch BAT_SUCCESS
		rcall	delay100us
		;send command typematic rate/delay to keyboard
		ldi	TxByte,0xF3		
		rcall	avr_to_keyb
		rcall	delay100us
		rcall	Wait_keyb_byte			;catch ack
		rcall	delay100us
		;send argument to command "typematic rate/delay"
		ldi	TxByte,(KBD_TMDelay<<5)|(KBD_TMRate<<0)
		rcall	avr_to_keyb
		rcall	delay100us
		rcall	Wait_keyb_byte			;catch ack
		rcall	delay100us
		
		
		ldi	LoopPC,0b00000001
		ldi	CurrentPC,0b00000001		;IMPORTANT INSTRUCTION!
		clr	ConnectedPCs			;let routines check which pcs are "on"
		sbi	PORTD,MOUSEa_E			;choose a mouse at reset
		clr	Status
		sei
	

;#############################################################
;#              MAIN                                         #
;#############################################################
;***** Program Execution Starts Here **************************************

	;debug
	;ldi	TxByte, 0x1C
	;rcall	avr_to_pc
	;ldi	TxByte,0xEE
	;rcall	avr_to_keyb

Start:	
	;debug
	;sbi	PORTD,LED
	
	;reset timer
	clr	temp
	out	TCNT1h,temp
	out	TCNT1l,temp

	;debug (uart-rx is not connected!)
	;sbic	USR,RXC
	;rcall	uart_reciev
	
	;check if pc specified by LoopPC is active/on/ok
	rcall	check_connected_pc
	
	lsl	LoopPC
	rol	LoopPC
	cpi	LoopPC,0b01000000
	brne	skipKBports
	ldi	LoopPC,0b00000001
	;brne	skip_carry_rol
	;rol	LoopPC
	;skip_carry_rol:
	skipKBports:
	mov	temp,LoopPC
	and	temp,ConnectedPCs		;check if pc is "connected"
	breq	Start				;if not connected goto start and check if connected, then goto next computer
	
	;debug
	;mov	temp,LoopPC
	;rcall	uartsend
	
	check_ports:
	rcall	pc_to_avr		; Read from pc if it tries to send
	sbrc	Status, VALID	; If new data is available, process it
	rcall	process_to_keyb	; and send it to the keyboard if neccessary
	rcall	keyb_to_avr		; Read from keyboard if it tries to send
	sbrc	Status, VALID	; If new data is available, process it and
	rcall	process_to_pc	; send it to the current pc if neccessary
		
rjmp	Start



check_connected_pc:
;check all pcs clock- and data-line, if they are idle then set bit in ConnectedPCs
;f?ara hur denna rutinen fungerar
;	push	LoopPC
;	ldi	LoopPC,0b00000001
;	ccp_do:
	rcall	read_pc_data		;if not idle, jump/quit routine
	breq	ccp_skip_setb
	rcall	read_pc_ck			;if not idle, jump/quit routine
	breq	ccp_skip_setb
	
	;both lines is idle, this is the key to being considered connected after being disconnected, 
	;if any of the ports is not idle there can be an error, both line idle => secure to consider connected 
	;(at least if idle for some ms)
	
	mov	temp,ConnectedPCs
	and	temp,LoopPC				;if connected
	brne	ccp_skip_setb			;return
	
	;else:
	
	or	ConnectedPCs,LoopPC		;consider connected


	ccp_skip_setb:	
ret



Delay_halfbit:
	ldi	temp, (36*4-9)/3	; Delay half a bit or around 36 ?s at 4 MHz and 3 cycles per loop
	Delay_halfbit_inner:
	dec	temp
	brne	Delay_halfbit_inner
ret

delay100us:
	ldi	temp,(100*4-9)/3	; Delay 100 ?s at 4 MHz and 3 cycles per loop
	delay100us1:
	dec 	temp
	brne	delay100us1
ret

delay5us:
	ldi	temp,(5*4-9)/3		; Delay 5 ?s at 4 MHz and 3 cycles per loop
	delay5us1:
	dec 	temp
	brne	delay5us1
ret

;debug
uart_reciev:
	in	RxByte,UDR
	;rcall	avr_to_pc
	;ldi	TxByte,0xEE
	ldi	TxByte,0xEE

	cpi	RxByte,0x02
	brne	nextcomp1
	ldi	TxByte,0xF3
	rjmp	klart
	
	nextcomp1:
	cpi	RxByte,0x03
	brne	nextcomp2
	ldi	TxByte,0x00
	rjmp	klart
	
	
	nextcomp2:
	cpi	RxByte,0x04
	brne	nextcomp3
	;ldi	TxByte,0b00000010
	ldi	TxByte,0x20
	rjmp	klart
	
	
	nextcomp3:
	
	klart:
	;ldi	TxByte,0x02
	;rcall	avr_to_keyb

	rcall	avr_to_keyb

;	in	temp,UDR
	waitloop:
	sbis	USR,UDRE
	rjmp	waitloop

	;out	UDR,temp
ret

;debug
uartsend:
	us_waitloop:
	sbis	USR,UDRE
	rjmp	us_waitloop

	out	UDR,temp
ret

.MACRO m_clear_keyb_ck
	sbi	DDRB,KBD_CK
.ENDMACRO

.MACRO m_release_keyb_ck
	cbi	DDRB,KBD_CK
.ENDMACRO

.MACRO m_clear_keyb_data
	sbi	DDRB,KBD_DATA
.ENDMACRO

.MACRO m_release_keyb_data
	cbi	DDRB,KBD_DATA
.ENDMACRO

clear_pc_data:		;(set port as output, port is already low)
	mov	temp2,LoopPC
	lsl	temp2
	in	temp3,DDRB
	or	temp3,temp2
	out	DDRB,temp3
ret

release_pc_data:		;(set port as input, pullup makes it high)
	mov	temp2,LoopPC
	lsl	temp2
	com	temp2
	in	temp3,DDRB
	and	temp3,temp2
	out	DDRB,temp3
ret

clear_pc_ck:		;(set port as output, port is already low)
	mov	temp2,LoopPC
	in	temp3,DDRB
	or	temp3,temp2
	out	DDRB,temp3
ret

release_pc_ck:		;(set port as input, pullup makes it high)
	mov	temp2,LoopPC
	com	temp2
	in	temp3,DDRB
	and	temp3,temp2
	out	DDRB,temp3
ret

read_pc_ck:
	in	temp3,PINB
	and	temp3,LoopPC
ret	;returns z=1 if PINB.x=0 (data low)

read_pc_data:
	in	temp3,PINB
	lsr	temp3
	and	temp3,LoopPC
ret	;returns z=1 if PINB.x=0 (ck low)

;#############################################################
;#              avr_to_pc                                    #
;#              Transmits the byte in TxByte to the pc       #
;#############################################################
avr_to_pc:
	cbr	Status,1<<ERROR	; Reset the error bit
	ldi	temp, 50*4/25	; Reset delay to 75 ?s at 4 MHz and 25 cycles per loop
	atp_Wait_idle:		; Check if both CLK and DATA lines are idle (high)
	rcall	read_pc_data
	breq	atp_Abort		; Bus is not idle, so abort
	rcall	read_pc_ck
	breq	atp_Abort		; Bus is not idle, so abort

	dec	temp			; Check again if not yet idle for 75 ?s
	brne	atp_Wait_idle

	ldi	bitcnt, 11		; Number of bits including start bit, 8 data bits, parity bit and stop bit
	clr	parity_cnt		; Clear the parity counter
	clc				; Clear carry to send a zero as the first bit (start bit)
	atp_Shift_data:
	brcs	atp_Output_1	; Set DATA according to the carry flag
	rcall	clear_pc_data	; Take DATA low
	rjmp	atp_Send_clock
	atp_Output_1:	
	inc	parity_cnt		; Count # of ones in the data byte
	rcall	release_pc_data	; Release DATA

	atp_Send_clock:	
	rcall	clear_pc_ck		; Take CK low
	rcall	Delay_halfbit
	rcall	release_pc_ck	; Release CK
	rcall	Delay_halfbit

	
	dec	bitcnt
	breq	atp_Send_done	; No bits left: we're done

	rcall	read_pc_ck		; If host takes clock low during transmission, abort and
	breq	atp_Abort		; exit subroutine

	cpi	bitcnt, 1
	breq	atp_Stop_bit	; One bit left: the stop bit
	cpi	bitcnt, 2
	breq	atp_Parity_bit	; Two bits left: time for the parity bit
	
	ror	TxByte		; >2 bits left: rotate next bit in data byte to carry flag
	rjmp	atp_Shift_data
	atp_Parity_bit:
	inc	parity_cnt		; Add 1 to the number of ones in the data byte (odd parity)
	ror	parity_cnt		; Set carry flag to the lsb of the parity counter+1
	rjmp	atp_Shift_data
	atp_Stop_bit:
	sec				; Set carry to send a one as the last bit (stop bit)
	rjmp	atp_Shift_data

	atp_Abort:
	rcall	release_pc_data	; Make sure we don't pull data low
	sbr	Status,1<<ERROR	; We couldn't send the byte
	rjmp	atp_very_done
	
	atp_Send_done:
	;rcall	read_pc_ck
	;breq	atp_Send_done	; Bus is not idle, so loop until it is
	
	atp_very_done:	
ret

;#############################################################
;#              pc_to_avr                                    #
;#              Receive one byte from pc to RxByte           #
;#############################################################
pc_to_avr:
	;debug
	;rcall	release_pc_ck
	
	
	cbr	Status, (1<<VALID)|(1<<ERROR)	; Reset valid and error bits
	rcall	read_pc_ck
	brne	pta_Done		; Abort if host is not requesting to send
	m_clear_keyb_ck		; Set ~CTS to keyboard to stop it from sending

	pta_Wait_ck_high:		; Clock is low, so pc is requesting attention
	;if timer overflowed, quit routine, means that this computer is not ok (disconnected or off)
	in	temp,TIFR
	sbrc	temp,TOV1
	rjmp	pta_Timeout

	rcall	read_pc_ck
	breq	pta_Wait_ck_high	; Wait until ck goes high again
	rcall	read_pc_data
	brne	pta_Done		; Abort if ck goes high w/o data=0
					; (no request_to_send, only ~clear_to_send)

	;; Otherwise start clocking in the data
	
	clr	bitcnt		; Clear the bit slot counter
	clr	parity_cnt		; Clear the parity counter

	pta_Clock_cycle:
	rcall	Delay_halfbit
	rcall	clear_pc_ck		; Take ck low
	rcall	Delay_halfbit	; Pc will set data during this time
	rcall	release_pc_ck	; Release ck

	cpi	bitcnt, 8
	brlo	pta_Data_bit	; bit 0-7: Data bits, clock them in
	breq	pta_Parity_bit	; bit 8: Parity bit, check it
	cpi	bitcnt, 10
	brlo	pta_Ack		; bit 9: Ack, send it
	breq	pta_End_ack		; bit 10: End of ack

	dec	bitcnt		; bit 11+: Pc holds data low,
	rjmp	pta_Bit_done	; keep sending clocks until it's released

	pta_Data_bit:	
	rcall	read_pc_data	; Read data bit from pc
	breq	pta_Input0		; Set carry to the data bit
	sec
	inc	parity_cnt		; Increase the parity counter if bit=1
	rjmp	pta_Shift_data
	pta_Input0:
	clc
	pta_Shift_data:
	ror	RxByte		; Shift carry into RxData, lsb first
	rjmp	pta_Bit_done

	pta_Parity_bit:
	rjmp	pta_Bit_done	; For the moment, we don't give a f**k

	pta_Ack:
	rcall	clear_pc_data	; Send ack by pulling data low during 10th bit
	rjmp	pta_Bit_done

	pta_End_ack:
	rcall	release_pc_data	; Release data again after ack sent
	;rjmp	pta_Bit_done	;(pointless)

	pta_Bit_done:
	inc	bitcnt		; Increase bit slot counter
	cpi	bitcnt, 11		; Abort reception if pc holds ck low before 11th bit

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -