PC keyboard and mouse interface (via SX28) to the Play Station 1

By: Simon Armstrong

My psxkeys project [...] illustrates a device that has interfaces to mouse, keyboard and PSOne controller port using SX28.

There is also in there the startings of a SmartMedia card reader.

The mouse (clk0 dat0) and keyboard (clk1 dat1) use standard ibm ps2 connectors.

B0 clk0
B1 clk1
B2 dat0
B2 dat1 (mouse and keyboard share the dataline)

The psx controller connection is a 5 wire circuit, the timing is critical, (code is also availbe for 10mhz pic16f84 also)

A0 psx-dat
A1 psx-cmd
A2 psx-ack
A3 psx-clk
A4 psx-sel

For the sx-entry competitioon, hmm, i'd have to break open my prototype but I'm thinking it's on a parallax 50mhz crystal.

Ideally the circuit would run on 4 mhz cystal due to expense.

SmartMedia pins
-----------------

B3 sm-ale
B4 sm-cle
B5 sm-write
B6 sm-read
B7 sm-busy

; psx connector
; -------------
; 1 dat
; 2 cmd
; 3 7v
; 4 gnd
; 5 3v
; 6 sel
; 7 clk
; 8 NC
; 9 ack

The easiest way to test the circuit is with a mouse and standard playstation boot screen (nocd), the psx code can be tested separately and will cause a mouse cursor to appear on the memory card manager page of the Playstation.

A planned LAN connector will allow $100 PSOne to perform network operation in local home network including a beta internet suite from the designer.

ToDo ( contribs to simon@acid.co.nz ):

Source

; psxkeys.src
; version for scenix sx28ac50
; porta psx dedicated
; portb user port
; portc data bus
; 50mhzturbo=20x


		DEVICE		SX28L,TURBO,STACKX_OPTIONX
		ID		'PSXKEYS'


		reset		cold_start


; global port regs


rb_dir		equ		$08
rb_dat		equ		$09
ra_dat		equ		$0a


timer		equ		$0b
timer2		equ		$0c
timer3		equ		$0d


; watchdog waits


wdreturn	MACRO
		test		timer
		snz
		retw		$fc
		ENDM


wdwaithi	MACRO			;port,bit 100*256*9=230K=~1/160 sec
		mov		timer,#100
		clr		timer2
:loop		dec		timer2		;1
		snz				;2
		dec		timer
		snz				;2
		retw		$fc
		sb		\1		;1
		jmp		:loop		;3
		ENDM


wdwaitlo	MACRO		;port,bit
		mov		timer,#100
		clr		timer2
:loop		dec		timer2
		snz
		dec		timer
		snz
		retw		$fc
		snb		\1
		jmp		:loop
		ENDM


; busy waits


ifwne		MACRO		;imm,label
		xor		w,#\1
		sz
		jmp		\2
		ENDM


ifweq		MACRO		;imm,label
		xor		w,#\1
		snz
		jmp		\2
		ENDM


bin		MACRO		;pin
		setb		rb_dir.\1
		mov		!rb,rb_dir
		ENDM


bout		MACRO		;pin
		clrb		rb_dir.\1
		mov		!rb,rb_dir
		ENDM


bsethi		MACRO
		setb		rb_dat.\1
		mov		rb,rb_dat
		ENDM


bsetlo		MACRO
		clrb		rb_dat.\1
		mov		rb,rb_dat
		ENDM


; =====================================================================
; register set
; =====================================================================


		org	$10


pcount		ds	1
padout		ds	1
padin		ds	1
parity		ds	1
kout		ds	1
kin		ds	1
mout		ds	1
min		ds	1
count		ds	1
dins		ds	1
key		ds	1
flags		ds	1
mousex		ds	1
mousey		ds	1
mouseb		ds	1


; =====================================================================
; object code starts here
; =====================================================================


		org		0


;port b


clk0		equ		0
clk1		equ		1
dat0		equ		2
dat1		equ		2
ale		equ		3
cle		equ		4
write		equ		5
read		equ		6
busy		equ		7


LEVEL		equ		$0d
PULLUP		equ		$0e
DIR		equ		$0f


; initialise user port 		default output=0 dir=input pullups=on


cold_start	clr		ra
		mov		w,#$60
		mov		rb_dat,w
		mov		rb,w
		mode		LEVEL
		mov		!ra,#$0f	;TTL inputs
		mov		!rb,#$ff	;TTL inputs
		mode		PULLUP
		mov		!ra,#$f0
		mov		!rb,#$f8
		mode		DIR
		mov		!ra,#$0f	;port a=inputs
		mov		w,#$84		;dat,rb inputs
		mov		rb_dir,w
		mov		!rb,w
		clr		dins


;		call		mediaid


mainloop	clr		key
		clr		flags		;reset data in pacmet
		dec		flags
		clr		mousex
		clr		mousey
		call		@readkeys
		call		@readmouse
		call		@padsend
		jmp		@mainloop


wait		mov		timer,w
wa		mov		timer2,#12
wb		decsz		timer2		;1
		jmp		wb		;3
		decsz		timer
		jmp		wa
		retp


; =====================================================================
; smartmedia driver
; =====================================================================




mediaid		clr		w
		mov		!rc,w		;output
		bsethi		cle
		bsetlo		write
		mov		rc,#$90		;cmd=readid
		bsethi		write
		bsetlo		cle
		bsethi		ale
		bsetlo		write
		clr		rc
		bsethi		write
		bsetlo		ale
		nop
		nop
		nop
		mov		w,#$ff		;input
		mov		!rc,w
		bsetlo		read
		nop
		nop
		mov		w,rc
		mov		mousex,w
		bsethi		read
		bsetlo		read
		nop
		nop
		mov		w,rc
		mov		mousey,w
		bsethi		read
		retp


;	poke.h	memf,0x0100
;	poke.b	flashcmd,0x90	;status
;	poke.b	flashloc,0x00
;	peek.b	t0,flashdata
;	peek.b	t1,flashdata
;	peek.b	t2,flashdata
;	brk


;
; ps/2 drivers for mouse and keyboard interface
;


;dins


mouse		equ	0
keyboard	equ	1


;flags


mleft		equ	2
mright		equ	3
krelease	equ	6
kextended	equ	7


; =====================================================================
; keyboard driver (din0)
; =====================================================================


		org		$200


release		MACRO
		bin		\1
		ENDM


drive		MACRO
		bout		\1
		ENDM


; write ps2 din0


kput		mov		kout,w		;paramater in w
		release		dat0		;release data
		drive		clk0		;drive clock
		mov		w,#$64
		call		@wait		;wait 100 usecs
		drive		dat0		;drive data lo
		release		clk0		;release clock
		clr		parity
		inc		parity
		mov		count,#8
kshift		rr		kout
		snc
		inc		parity
		call		kbitout
		wdreturn
		decsz		count
		jmp		kshift
		rr		parity		;parity bit
		call		kbitout
		wdreturn
		stc
		call		kbitout
		wdreturn
		wdwaitlo	rb.clk0		;line control (must be 0)
		snb		rb.dat0
		retw		$fc
		wdwaithi	rb.clk0
		jmp		kget		;receive ack


kbitout		wdwaitlo	rb.clk0
		snc
		jmp		kset
		drive		dat0
		wdwaithi	rb.clk0
		ret
kset		release		dat0
		wdwaithi	rb.clk0
		ret


; read ps2 din0


kget		release		clk0
		release		dat0
		mov		w,#$08
		call		@wait		;wait 100 usecs
		mov		count,#$08
		wdwaitlo	rb.clk0		;start bit
		wdwaithi	rb.clk0
kbitin		wdwaitlo	rb.clk0
		clc
		snb		rb.dat0
		stc
		rr		kin
		wdwaithi	rb.clk0
		decsz		count
		jmp		kbitin
		wdwaitlo	rb.clk0		;parity check?
		wdwaithi	rb.clk0
		wdwaitlo	rb.clk0		;stop bit
		drive		clk0
		mov		w,#$32
		call		@wait		;wait 100 usecs
		mov		w,kin
		ret


readkeys	sb		dins.keyboard
		jmp		nokeyboard


getkey		call		kget
		ifweq		$fc,nokey
		mov		w,kin
		ifwne		$f0,notrelease
		clrb		flags.krelease
		jmp		getkey


notrelease	mov		w,kin
		ifwne		$e0,notextended
		clrb		flags.kextended
		jmp		getkey


notextended	mov		w,kin
		mov		key,w


nokey		drive		clk0		;inhibit
		release		dat0		
		retp


nokeyboard	call		kget		;poweron response	;start with reset?
		ifwne		$aa,keyboarderr	
		mov		w,#$ed		;set leds
		call		kput
		ifwne		$fa,keyboarderr
		mov		w,#$01
		call		kput
		ifwne		$fa,keyboarderr
		setb		dins.keyboard
		retp


keyboarderr	drive		clk0		;inhibit
		release		dat0		;release data
		clrb		dins.keyboard
		retp




; =====================================================================
; mouse driver (din1)
; =====================================================================


		org		$400


mput		mov		mout,w		;paramater in w
		release		dat1		;release data
		drive		clk1		;drive clock
		mov		w,#$64
		call		@wait		;wait 100 usecs
		drive		dat1		;drive data lo
		release		clk1		;release clock
		clr		parity
		inc		parity
		mov		count,#8
mshift		rr		mout
		snc
		inc		parity
		call		mbitout
		wdreturn
		decsz		count
		jmp		mshift
		rr		parity		;parity bit
		call		mbitout
		wdreturn
		stc
		call		mbitout
		wdreturn
		wdwaitlo	rb.clk1		;line control (must be 0)
		snb		rb.dat1
		retw		$fc
		wdwaithi	rb.clk1
		jmp		mget		;receive ack


mbitout		wdwaitlo	rb.clk1
		snc
		jmp		mset
		drive		dat1
		wdwaithi	rb.clk1
		ret
mset		release		dat1
		wdwaithi	rb.clk1
		ret


; read ps2 din1


mget		release		clk1
		release		dat1
		mov		w,#$08
		call		@wait		;wait 8 usecs
		mov		count,#$08
		wdwaitlo	rb.clk1		;start bit
		wdwaithi	rb.clk1
mbitin		wdwaitlo	rb.clk1
		clc
		snb		rb.dat1
		stc
		rr		min
		wdwaithi	rb.clk1
		decsz		count
		jmp		mbitin
		wdwaitlo	rb.clk1		;parity check?
		wdwaithi	rb.clk1
		wdwaitlo	rb.clk1		;stop bit
		drive		clk1
		mov		w,#$32
		call		@wait		;wait 50 usecs
		mov		w,min
		ret


readmouse	sb		dins.mouse
		jmp		nomouse
		mov		w,#$eb
		call		mput
		ifwne		$fa,mouseerr
		call		mget
		mov		mouseb,w
		call		mget
		mov		mousex,w
		call		mget
		mov		mousey,w
		snb		mouseb.0
		clrb		flags.mright
		snb		mouseb.1
		clrb		flags.mleft
		not		mousey	
		inc		mousey
		retp


nomouse		call		mget		;poweron response
		ifwne		$aa,mouseerr
		call		mget
		ifwne		$00,mouseerr	
		mov		w,#$f0		;set remote mode
		call		mput
		ifwne		$fa,mouseerr
		setb		dins.mouse
		retp


mouseerr	drive		clk1		;inhibit
		release		dat1		;release data
		clrb		dins.mouse
		retp
	
; =====================================================================
; psx pad driver (port a)
; =====================================================================


		org		$600


dat		equ		0
cmd		equ		1
ack		equ		2
clk		equ		3
sel		equ		4	;rtcc


waitsello	MACRO
:wlo		snb		rb.4		
		jmp		:wlo
		ENDM


waitselhi	MACRO
:whi		sb		rb.4		
		jmp		:whi
		ENDM


padsend		;waitselhi
		;waitsello


		mov		rtcc,#$ff
		mov		!OPTION,#$ff
		nop
wrc1		mov		w,rtcc
		sz
		jmp		wrc1


		mov		!ra,#$fe	;dat=output
		mov		w,#$ff
		call		dobyte
		decsz		padin		;if padin!=01 ps0
		jmp		ps0
		call		doack
		mov		w,#$12
		call		dobyte
		call		doack
		mov		w,#$5a
		call		dobyte
		call		doack
		mov		w,key		;keys
		call		dobyte
		call		doack
		mov		w,flags		;flags
		call		dobyte
		call		doack
		mov		w,mousex	;deltax
		call		dobyte
		call		doack
		mov		w,mousey	;deltay
		call		dobyte
ps0		clr		ra
		mov		!ra,#$ff	;float port




;		waitselhi
		retp


dobyte		mov		padout,w	;padout=w
		mov		count,#8
		mov		w,#$80		;w=1
dobit		rr		padout
		rl		ra
wl		snb		ra.clk		;wait clk lo
		jmp		wl
wh		sb		ra.clk		;wait clk hi
		jmp		wh
		clc
		rr		padin
		snb		ra.cmd
		or		padin,w
		decsz		count
		jmp		dobit
		ret


doack		mov		count,#50	;100/50mhz=2usecs
db		decsz		count
		jmp		db
		clr		ra		;drive ack (ra.2) lo
		mov		!ra,#$fa
		mov		count,#25	;100/50mhz=2usecs
da		decsz		count
		jmp		da
		mov		!ra,#$fe
		ret