;======================================
; PlayStation Pad <-> MSX     Ver 1.00
;                   2000/03/22   TOMO
;======================================

;Pin	I/O	Signal
;--------------------------
;PD0	O	LED
;PD1	-	 -
;PD2	I	/ACK
;PD3	I	DAT
;PD4	O	CMD
;PD5	O	/SEL
;PD6	O	CLK
;
;PB0	I	1/2Vcc (AIN0)
;PB1	I	OUTPUT (AIN1)
;PB2	O	Down
;PB3	O	Left
;PB4	O	Right
;PB5	I/O	TrigA
;PB6	O	Up
;PB7	I/O	TrigB



.include "include\2313def.inc"


.def	REGSAV	= r15		;SREGの一時退避場所 (割り込み用)
.def	ACKCNT	= r14		;ACK が入ったらインクリメント
.def	PS_KEY1	= r13		;PS-Pad から得たキーデータ(1バイト目)
.def	PS_KEY2	= r12		;PS-Pad から得たキーデータ(2バイト目)
.def	SHTSPD	= r11		;連射速度
.def	BEEPSW	= r10		;BEEP音スイッチ (00h:OFF)
.def	LRFLAG	= r09

.def	TEMP	= r25
.def	TEMP1	= r24
.def	TEMP2	= r23

.def	RS_TMP1	= r24
.def	RS_TMP2	= r23

.def	PS_TMP1	= r24
.def	PS_TMP2	= r23
.def	PS_ERR	= r22		;PS-Pad エラーコード
.def	MSXKEY	= r21		;MSX ジョイスティックポート値
.def	SHTFLG	= r20		;連射用マスク (00h:離)
.def	SHTCNT	= r19		;連射用カウンタ
.def	EEADR	= r18		;EEPROM アドレス
.def	EEDAT	= r17		;EEPROM データ

.equ	P_UP		= 6	;PBx (to MSX)
.equ	P_DOWN		= 2
.equ	P_LEFT		= 3
.equ	P_RIGHT		= 4
.equ	P_TRIGA		= 5
.equ	P_TRIGB		= 7
.equ	P_OUT		= 1

.equ	P_LED		= 0	;PDx (to PS-Pad,LED,BUZZ)
.equ	P_DAT		= 3
.equ	P_ACK		= 2
.equ	P_CMD		= 4
.equ	P_SEL		= 5
.equ	P_CLK		= 6

.equ	PS_TIMEOUT	= 0xff	;タイムアウト

.equ	RAMTOP		= 0x060
.equ	EE_CONFIG	= 0x060
.equ	EE_CNFSIZ	= 8
.equ	EE_KEYTBL	= EE_CONFIG + 0
.equ	EE_SHTSPD	= EE_CONFIG + 4
.equ	EE_BEEPSW	= EE_CONFIG + 5

.macro	LED_ON
	cbi	PORTD,P_LED
.endmacro

.macro	LED_OFF
	sbi	PORTD,P_LED
.endmacro


	.cseg

	.org	0x000
	rjmp	RESET

	.org	INT0addr
	rjmp	PS_ACK_INT

	.org	ACIaddr
	rjmp	MSX_OUTPUT_INT

	.org	0x020
;		 0123456789ABCDEF
;	.db	'PS-MSX I/F V1.00'	;Sign Code


;================================================
;= Main routine
;================================================

RESET:
	ldi	TEMP,low(RAMEND)
	out	SPL,TEMP
;	ldi	TEMP,high(RAMEND)	;AT90S2313では指定不可
;	out	SPH,TEMP
;	clr	TEMP
;	out	EEARH,TEMP

	ldi	XL,low(EE_CONFIG)
	ldi	XH,high(EE_CONFIG)
	ldi	TEMP,RAMEND-0x060
	clr	r0
	st	X+,r0
	dec	TEMP
	brne	PC-2

	rcall	ps_init
	rcall	msx_init
	rcall	st_init
;	rcall	kc_init
	sei

	LED_OFF
	rcall	load_config_table	;コンフィグデータ読み出し・設定

main_loop:
	ldi	TEMP2,60		;コンフィグモード移行時間
ec_lop:	rcall	get_ps_key		;PS-Pad からキーデータ取得
	sbrc	PS_KEY1,PS_START	;START+SELECT が押されているか？
	rjmp	ec_skip
	sbrc	PS_KEY1,PS_SELECT
	rjmp	ec_skip
	dec	TEMP2
	brne	ec_lop			;一定時間押されたら次に進む
	rcall	enter_config_mode
ec_skip:
	rcall	change_shot_speed
	inc	SHTCNT			;連射処理
	mov	TEMP,SHTCNT
	mov	TEMP1,SHTSPD
ec_lp0:	tst	TEMP1
	breq	ec_jp0
	ror	TEMP
	dec	TEMP1
	rjmp	ec_lp0
ec_jp0:	clr	SHTFLG
	sbrc	TEMP,0
	ser	SHTFLG

	rcall	set_msx_key
	rcall	msx_outport

;	rcall	debug
	rjmp	main_loop



	;1VSYNC (1/60sec)待ち
sync_wait:
	ldi	TEMP,16
	rcall	wait1m
	ret


wait100u:
	push	TEMP
	clr	TEMP		;wait 102.4us
	nop		;1
	dec	TEMP	;1
	brne	PC-2	;2
	pop	TEMP
	dec	TEMP
	brne	wait100u
	ret


wait1m:
	push	TEMP
	ldi	TEMP,10
	rcall	wait100u
	pop	TEMP
	dec	TEMP
	brne	wait1m
	ret


wait100m:
	push	TEMP
	ldi	TEMP,100
	rcall	wait1m
	pop	TEMP
	dec	TEMP
	brne	wait100m
	ret


;================================================
;= LED routines
;================================================

st_init:
	in	TEMP,PORTD
	cbr	TEMP,(1<<P_LED)
	out	PORTD,TEMP

	in	TEMP,DDRD
	sbr	TEMP,(1<<P_LED)
	out	DDRD,TEMP
	ret


;================================================
;= Key Customize routines
;================================================

.equ	PS_SELECT	= 0	;PS_KEY1
.equ	PS_START	= 3
.equ	PS_UP		= 4
.equ	PS_RIGHT	= 5
.equ	PS_DOWN		= 6
.equ	PS_LEFT		= 7
.equ	PS_L2		= 0	;PS_KEY2
.equ	PS_R2		= 1
.equ	PS_L1		= 2
.equ	PS_R1		= 3
.equ	PS_TRIANGLE	= 4
.equ	PS_CIRCLE	= 5
.equ	PS_CROSS	= 6
.equ	PS_SQUARE	= 7


;kc_init:
;	clr	SHTFLG
;	clr	MSXKEY
;	ret


;	MSXキーデータを設定
set_msx_key:
	clr	MSXKEY

	ldi	XL,low(EE_KEYTBL)
	ldi	XH,high(EE_KEYTBL)
	sbrs	PS_KEY2,4		;Triangle
	rcall	set_key_sub
	adiw	XL,1
	sbrs	PS_KEY2,5		;Circle
	rcall	set_key_sub
	adiw	XL,1
	sbrs	PS_KEY2,6		;Cross
	rcall	set_key_sub
	adiw	XL,1
	sbrs	PS_KEY2,7		;Square
	rcall	set_key_sub

	sbrs	PS_KEY1,PS_UP		;Up
	sbr	MSXKEY,(1<<P_UP)
	sbrs	PS_KEY1,PS_DOWN		;Down
	sbr	MSXKEY,(1<<P_DOWN)
	sbrs	PS_KEY1,PS_LEFT		;Left
	sbr	MSXKEY,(1<<P_LEFT)
	sbrs	PS_KEY1,PS_RIGHT	;Right
	sbr	MSXKEY,(1<<P_RIGHT)
	ret

set_key_sub:
	ld	TEMP,X
	tst	SHTFLG
	breq	kskjp0			;00hなら連射OFF
	mov	TEMP2,TEMP
	ror	TEMP2
	ror	TEMP2
	or	TEMP,TEMP2
kskjp0:	sbrc	TEMP,0
	sbr	MSXKEY,(1<<P_TRIGA)
	sbrc	TEMP,1
	sbr	MSXKEY,(1<<P_TRIGB)
	ret


;	EEPROM からコンフィグデータを読み出し・設定
load_config_table:
	ldi	EEADR,0x00
	ldi	XL,low(EE_CONFIG)
	ldi	XH,high(EE_CONFIG)
	ldi	TEMP,EE_CNFSIZ
	rcall	ee_read_block

	ldi	XL,low(EE_SHTSPD)
	ldi	XH,high(EE_SHTSPD)
	ld	SHTSPD,X

	ldi	XL,low(EE_BEEPSW)
	ldi	XH,high(EE_BEEPSW)
	ld	BEEPSW,X
	ret


;	コンフィグデータを EEPROM へ保存
save_config_table:
	ldi	XL,low(EE_SHTSPD)
	ldi	XH,high(EE_SHTSPD)
	st	X,SHTSPD

	ldi	XL,low(EE_BEEPSW)
	ldi	XH,high(EE_BEEPSW)
	st	X,BEEPSW

	ldi	EEADR,0x00
	ldi	XL,low(EE_CONFIG)
	ldi	XH,high(EE_CONFIG)
	ldi	TEMP,EE_CNFSIZ
	rcall	ee_write_block
	ret


;	連射速度を変更
change_shot_speed:
	mov	TEMP,LRFLAG
	eor	TEMP,PS_KEY2
	andi	TEMP,(1<<PS_L1)+(1<<PS_L2)+(1<<PS_R1)+(1<<PS_R2)
	brne	PC+2
	ret
	mov	LRFLAG,PS_KEY2
	sbrs	PS_KEY2,PS_L1
	rjmp	css_up
	sbrs	PS_KEY2,PS_L2
	rjmp	css_up
	sbrs	PS_KEY2,PS_R1
	rjmp	css_down
	sbrs	PS_KEY2,PS_R2
	rjmp	css_down
	ret

css_up:
	inc	SHTSPD
	rjmp	css_set_speed
css_down:
	dec	SHTSPD
css_set_speed:
	mov	TEMP,SHTSPD
	andi	TEMP,3
	mov	SHTSPD,TEMP
	mov	EEDAT,TEMP
	ldi	EEADR,EE_SHTSPD-EE_CONFIG
	rcall	ee_write
	ret


;	EEPROM・SRAM のコンフィグデータを初期状態へ戻す
config_reset:
	ldi	ZL,low(kc_default*2)
	ldi	ZH,high(kc_default*2)
	ldi	XL,low(EE_CONFIG)
	ldi	XH,high(EE_CONFIG)
	ldi	TEMP,EE_CNFSIZ
cr_lp0:	lpm
	st	X+,r0
	adiw	ZL,1
	dec	TEMP
	brne	cr_lp0
save_config:
	ldi	XL,low(EE_CONFIG)
	ldi	XH,high(EE_CONFIG)
	ldi	EEADR,0x000
	ldi	TEMP,EE_CNFSIZ
	rcall	ee_write_block
	rcall	load_config_table
	LED_OFF
	ret


;	コンフィグモード
enter_config_mode:
	LED_ON

	clr	TEMP
	ldi	XL,low(EE_KEYTBL)	;キーテーブルをクリア
	ldi	XH,high(EE_KEYTBL)
	st	X+,TEMP
	st	X+,TEMP
	st	X+,TEMP
	st	X+,TEMP
ecmlp0:
	rcall	get_ps_key
	sbrs	PS_KEY1,PS_START	;START,SELECT が離されるまで待つ
	rjmp	ecmlp0
	sbrs	PS_KEY1,PS_SELECT
	rjmp	ecmlp0
ecmlp1:
	rcall	get_ps_key

	sbrs	PS_KEY1,PS_START	;START : コンフィグモード終了
	rjmp	save_config

	sbrs	PS_KEY1,PS_SELECT	;SELECT : コンフィグリセット
	rjmp	config_reset

	ldi	ZL,low(trgtbl*2)
	ldi	ZH,high(trgtbl*2)
	sbrs	PS_KEY1,PS_UP
	rjmp	ecmjp0
	adiw	ZL,1
	sbrs	PS_KEY1,PS_DOWN
	rjmp	ecmjp0
	adiw	ZL,1
	sbrs	PS_KEY1,PS_LEFT
	rjmp	ecmjp0
	adiw	ZL,1
	sbrs	PS_KEY1,PS_RIGHT
	rjmp	ecmjp0
	adiw	ZL,1
ecmjp0:	lpm
	ldi	ZL,low(EE_KEYTBL)
	ldi	ZH,low(EE_KEYTBL)
	sbrs	PS_KEY2,PS_TRIANGLE
	rjmp	ecmjp1
	adiw	ZL,1
	sbrs	PS_KEY2,PS_CIRCLE
	rjmp	ecmjp1
	adiw	ZL,1
	sbrs	PS_KEY2,PS_CROSS
	rjmp	ecmjp1
	adiw	ZL,1
	sbrc	PS_KEY2,PS_SQUARE
	rjmp	ecmlp1
ecmjp1:	ld	TEMP,Z
	or	TEMP,r0
	st	Z,TEMP
	rjmp	ecmlp1


trgtbl:	.db	0b0100,0b1000	;RA,RB
	.db	0b0001,0b0010	; A, B
	.db	0b0000,0b0000	;dummy


;================================================
;= MSX Joystick-Port interface routines
;================================================

;	OUTPUT 検出処理 (割込)
;	[E] none
;	[R] none
;	[M] none
MSX_OUTPUT_INT:
	in	REGSAV,SREG

	out	SREG,REGSAV
	reti


;	MSX Joystick-Port インターフェースルーチン初期化
;	[E] none
;	[R] none
;	[M] TEMP
msx_init:
	;Stick,Trigger,OUTPUT = Input(O.D.)/Low
	in	TEMP,PORTB
	cbr	TEMP,(1<<P_UP)+(1<<P_DOWN)+(1<<P_LEFT)+(1<<P_RIGHT)+(1<<P_TRIGA)+(1<<P_TRIGB)+(1<<P_OUT)+(1<<0)
	out	PORTB,TEMP

	in	TEMP,DDRB
	cbr	TEMP,(1<<P_UP)+(1<<P_DOWN)+(1<<P_LEFT)+(1<<P_RIGHT)+(1<<P_TRIGA)+(1<<P_TRIGB)+(1<<P_OUT)+(1<<0)
	out	DDRB,TEMP

	in	TEMP,ACSR
	cbr	TEMP,(1<<ACIS0)+(1<<ACIS1)	;両エッジ割り込み
	sbr	TEMP,(1<<ACIE)			;コンパレータ割り込み許可
	out	ACSR,TEMP
	ret


;	MSX Joystick-Port にキーデータ出力
;	[E] none
;	[R] none
;	[M] TEMP
msx_outport:
	in	TEMP,DDRB
	cbr	TEMP,(1<<P_UP)+(1<<P_DOWN)+(1<<P_LEFT)+(1<<P_RIGHT)+(1<<P_TRIGA)+(1<<P_TRIGB)
	or	TEMP,MSXKEY
	out	DDRB,TEMP
	ret


;================================================
;= PS-Pad interface routines
;================================================

;	PS-Pad キーデータを取得
;	[E] none
;	[R] none
;	[M] none
get_ps_key:
	push	TEMP
	push	PS_TMP1
	push	PS_TMP2

	rcall	sync_wait

	cbi	DDRD,P_CLK	;CLK = "H"
	sbi	DDRD,P_SEL	;SEL = "L"

	ldi	PS_TMP1,5	;パッドによっては必要
	rcall	clock_wait
	dec	PS_TMP1
	brne	PC-2
gps_lop:
	ldi	TEMP,0x01
	rcall	ps_comm
	rcall	ps_ack_wait

	ldi	TEMP,0x42
	rcall	ps_comm
	rcall	ps_ack_wait

	ldi	TEMP,0x00
	rcall	ps_comm
	rcall	ps_ack_wait

	ldi	TEMP,0x00
	rcall	ps_comm
	rcall	ps_ack_wait
	mov	PS_KEY1,TEMP

	ldi	TEMP,0x00
	rcall	ps_comm
;	rcall	ps_ack_wait
	mov	PS_KEY2,TEMP

	cbi	DDRD,P_SEL	;SEL = "H"

	pop	PS_TMP2
	pop	PS_TMP1
	pop	TEMP
	ret


;	ACK 検出処理 (割込)
;	[E] none
;	[R] none
;	[M] none
PS_ACK_INT:
	in	REGSAV,SREG
	inc	ACKCNT
	out	SREG,REGSAV
	reti


;	PS-Pad インターフェースルーチン初期化
;	[E] none
;	[R] none
;	[M] TEMP
ps_init:
	;DAT,ACK = Input(Pull-up)
	;CMD,CLK,SEL = "H"
	in	TEMP,PORTD
	sbr	TEMP,(1<<P_DAT)+(1<<P_ACK)
	cbr	TEMP,(1<<P_CMD)+(1<<P_CLK)+(1<<P_SEL)+(1<<P_LED)
	out	PORTD,TEMP

	in	TEMP,DDRD
	cbr	TEMP,(1<<P_DAT)+(1<<P_ACK)+(1<<P_CMD)+(1<<P_CLK)+(1<<P_SEL)
	sbr	TEMP,(1<<P_LED)
	out	DDRD,TEMP

	in	TEMP,MCUCR	;INT0 立下りエッジ
	cbr	TEMP,(1<<ISC00)
	sbr	TEMP,(1<<ISC01)
	out	MCUCR,TEMP

	in	TEMP,GIMSK	;INT0 割り込み許可
	sbr	TEMP,(1<<INT0)
	out	GIMSK,TEMP

	clr	ACKCNT
	clr	PS_ERR
	ret


;	ACK 検出待ち
;	[E] none
;	[R] none
;	[M] none
ps_ack_wait:
	push	TEMP
	ldi	TEMP,100	;Timeout = 100us
pw_lop:	rjmp	PC+1	;2
	rjmp	PC+1	;2
	nop		;1
	tst	ACKCNT	;1
	brne	pw_ext	;1
	dec	TEMP	;1
	brne	pw_lop	;2
	ldi	PS_ERR,PS_TIMEOUT
pw_ext:	pop	TEMP
	ret


;	PS-Pad と1バイト通信
;	[E] TEMP = 送信データ
;	[R] TEMP = 受信データ
;	[M] TEMP,S_TMP1,PS_TMP2
ps_comm:
	clr	ACKCNT
	clr	PS_ERR
	ldi	PS_TMP1,8
pc_lp0:
	ror	TEMP		;TEMP<0> -> C
	brcs	PC+2
	sbi	DDRD,P_CMD	;CMD="L"
	brcc	PC+2
	cbi	DDRD,P_CMD	;CMD="H"

	sbi	DDRD,P_CLK	;CLK = "L"
	rcall	clock_wait
	cbi	DDRD,P_CLK	;CLK = "H"
	rcall	clock_wait

	clc
	sbic	PIND,P_DAT
	sec
	ror	PS_TMP2		;C -> PS_TMP2<7>

	dec	PS_TMP1
	brne	pc_lp0
	mov	TEMP,PS_TMP2
	ret


;	wait 2us
;	wait 1.2+0.3n(us)
clock_wait:
	push	TEMP		;2
	ldi	TEMP,5		;1
	dec	TEMP		; 1
	brne	PC-1		; 2
	pop	TEMP		;2
	ret			;4+3


;================================================
;= EEPROM accessing routines
;================================================

;	EEPROM に1バイト書き込み
;	[E] EEDAT = 書き込みデータ
;	    EEADR = 書き込みアドレス
;	[R] none
;	[M] none
ee_write:
	sbic	EECR,EEWE		;書き込み完了までウエイト(念のため)
	rjmp	PC-1
	out	EEARL,EEADR
	out	EEDR,EEDAT
	sbi	EECR,EEMWE
	sbi	EECR,EEWE
	sbic	EECR,EEWE		;書き込み完了までウエイト
	rjmp	PC-1
	ret


;	EEPROM に1バイト書き込み
;	[E] EEADR = 読み込みアドレス
;	[R] EEDAT = 読み込んだデータ
;	[M] none
ee_read:
	sbic	EECR,EEWE		;書き込み完了までウエイト(念のため)
	rjmp	PC-1
	out	EEARL,EEADR
	sbi	EECR,EERE
	in	EEDAT,EEDR
	ret


;	SRAM から EEPROM に指定バイト転送
;	[E] TEMP = 転送バイト数
;	    EEADR = EEPROM アドレス
;	    Xreg  = SRAM アドレス
;	[R] none
;	[M] TEMP,EEADR,EEDAT,Xreg
ee_write_block:
	ld	EEDAT,X+
	rcall	ee_write
	inc	EEADR
	dec	TEMP
	brne	ee_write_block
	ret


;	EEPROM から SRAM に指定バイト転送
;	[E] TEMP = 転送バイト数
;	    EEADR = EEPROM アドレス
;	    Xreg  = SRAM アドレス
;	[R] none
;	[M] TEMP,EEADR,EEDAT,Xreg
ee_read_block:
	rcall	ee_read
	st	X+,EEDAT
	inc	EEADR
	dec	TEMP
	brne	ee_read_block
	ret



;================================================
;= Default config data
;================================================

;+ 0	PS-MSX トリガ対応テーブル
;	b0-b3	予約
;	b4	Trigger A (0:対応)
;	b5	Trigger B
;	b6	Trigger A (Rapid Shot)
;	b7	Trigger B (Rapid Shot)
;+ 4	連射速度
;+ 5	BEEP ON/OFF
;+ 6,7	予約

kc_default:
	.db	0b0001,0b0010		;Triangle,Circle
	.db	0b1000,0b0100		;Cross,Square
	.db	0x01,0x00		;連射速度,BEEP ON/OFF
	.db	0xff,0xff		;reserved,reserved


;================================================
;= EEPROM data area
;================================================

	.eseg
	.org	0x000

	.db	0b0001		;Triangle
	.db	0b0010		;Circle
	.db	0b1000		;Cross
	.db	0b0100		;Square
	.db	0x02		;連射速度
	.db	0x00		;BEEP ON/OFF
	.db	0xff		;reserved
	.db	0xff		;reserved


