
;------------------------------------------------------------------------------
; Title       : wc2.asm
; Description : WonderCommand-II
; Author      : KAWAMOTO "nanashino" Yasuhisa
; Email       : nanashi@yk.rim.or.jp
; Date        : 12/10/2000
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; History     : 12/10/2000  Idle Mode対応
;                           transmit内でtmpを使用していたのを修正
;               08/07/2000  初期バージョン
;------------------------------------------------------------------------------

.include "2323def.inc"

;-- Defined constant --
.equ	N = 52			; 13us@4.0MHz and R=1
.equ	R = 1			; 1/1
.equ	BAUD_9600 = 8
.equ	BAUD_2400 = 32
.equ	BUFF_SIZE = 32

;-- Global register --
.def	t_tmp		= r16	; Scratch register(in interrupt handler)
.def	t_sr		= r1	; SREG storage(in interrupt handler)
.def	t_reld		= r2	; Reload register(in interrupt handler)
.def	rsv_wc		= r17	; Serial receive wait counter
.def	rsv_bc		= r18	; Serial receive bit counter
.def	rsv_bf		= r19	; Serial receive buffer
.def	trn_bit		= r3	; IR tramsmit bit register
.def	trn_wv		= r4	; IR tramsmit modulation wave
.def	trn_wc		= r20	; IR tramsmit wait counter
.def	trn_bc		= r21	; IR tramsmit bit counter
.def	trn_1c		= r22	; IR tramsmit '1' counter
.def	trn_bf		= r23	; IR tramsmit buffer
.def	str		= r24	; Status register
.def	bfc		= r25	; Buffer counter
.def	tmp		= r26	; Scratch register
; r28-r29 is Y-Register used as write pointer
; r30-r31 is Z-Register used as read pointer

;-- Bit position in Status register --
.equ	TDBF		= 7	; IR tramsmit data buffer full
.equ	RBSY		= 0	; Serial receive busy

	.dseg
	.org $60
;-- Buffer area --
bf_start:	
	.byte BUFF_SIZE
bf_end:

	.cseg
;-- Reset and interrupt vector --
	.org $0000
	rjmp	reset		; Reset handler
	.org INT0addr
	rjmp	ext_int0	; External interrupt handler
	.org OVF0addr
	rjmp	tim_ovf0	; Timer0 overflow handler

;-- External interrupt handler --
ext_int0:
	in	t_sr,SREG		; Store SREG
	sbr	str,(1<<RBSY)		; Set RBSY
	out	TCNT0,t_reld		; Set reload value
	ldi	t_tmp,(1<<TOV0)		; Clear T/C0 overflow flag
	out	TIFR,t_tmp
	ldi	t_tmp,(1<<TOIE0)	; Enable T/C0 overflow interrupt
	out	TIMSK,t_tmp
	ldi	t_tmp,R			; Start timer and set clock source
	out	TCCR0,t_tmp
	ldi	t_tmp,0			; Disable INT0
	out	GIMSK,t_tmp
	out	SREG,t_sr		; Restore SREG
	reti

;-- IR transmit(in tim_ovf0) --
transmit:
	com	trn_wv
	mov	t_tmp,trn_wv
	or	t_tmp,trn_bit
	andi	t_tmp,0b00000101
	out	PORTB,t_tmp

	dec	trn_wc
	brne	trn_exit
	ldi	trn_wc,BAUD_2400

	cpi	trn_bc,0
	brne	trn_00
	sbrc	str,TDBF		; Check set TDBF
	inc	trn_bc
	rjmp	trn_exit
trn_00:
	cpi	trn_bc,1		; Start bit
	brne	trn_01
	clr	trn_bit
	inc	trn_bc
	rjmp	trn_exit
trn_01:
	cpi	trn_bc,10		; Parity bit(odd parity)
	brne	trn_02
	clr	t_tmp
	sbrs	trn_1c,0
	ser	t_tmp
	mov	trn_bit,t_tmp
	inc	trn_bc
	rjmp	trn_exit
trn_02:
	cpi	trn_bc,11		; Stop bit
	brne	trn_03
	ser	t_tmp
	mov	trn_bit,t_tmp
	inc	trn_bc
	ldi	trn_1c,0
	ldi	trn_bc,0
	cbr	str,(1<<TDBF)		; Clear TDBF
	rjmp	trn_exit
trn_03:
	clr	t_tmp			; Data bit
	ror	trn_bf
	brcc	trn_04
	ser	t_tmp
	inc	trn_1c
trn_04:
	mov	trn_bit,t_tmp
	inc	trn_bc
trn_exit:
	ret

;-- Serial receive(in tim_ovf0) --
receive:
	dec	rsv_wc
	brne	rsv_exit

	cpi	rsv_bc,0		; Check signal
	brne	rsv_01
	sbic	PINB,1
	rjmp	rsv_00
	ldi	rsv_wc,BAUD_9600/8	; 1/8bit
	rjmp	rsv_exit
rsv_00:
	inc	rsv_bc
	ldi	rsv_wc,BAUD_9600/2	; Set wait 1/2bit
	rjmp	rsv_exit
rsv_01:
	cpi	rsv_bc,1		; Check start bit
	brne	rsv_02
	sbis	PINB,1
	rjmp	rsv_err
	inc	rsv_bc
	ldi	rsv_wc,BAUD_9600	; Set wait 1bit
	rjmp	rsv_exit
rsv_02:
	cpi	rsv_bc,10		; Check stop bit
	brne	rsv_04
	sbic	PINB,1
	rjmp	rsv_err
	cpi	bfc,BUFF_SIZE		; BUFF_SIZE =< bfc
	brsh	rsv_err
	st	Y+,rsv_bf
	inc	bfc
	cpi	YL,low(bf_end)
	brlo	rsv_03			; YL < bf_end
	ldi	YL,low(bf_start)
rsv_03:
	ldi	rsv_bc,0
	ldi	rsv_wc,BAUD_9600/8	; Set wait 1/8bit
	cbr	str,(1<<RBSY)		; Clear RBSY
	rjmp	rsv_exit
rsv_04:
	sec				; Data bit
	sbic	PINB,1
	clc
	ror	rsv_bf
	inc	rsv_bc
	ldi	rsv_wc,BAUD_9600	; Set wait 1bit
	rjmp	rsv_exit
rsv_err:
	ldi	rsv_bc,0
	ldi	rsv_wc,BAUD_9600/8	; Set wait 1/8bit
rsv_exit:
	ret

;-- Timer0 overflow handler --
tim_ovf0:
	in	t_sr,SREG		; Store SREG
	out	TCNT0,t_reld		; Set reload timer
	rcall	transmit		; IR transmit
	rcall	receive			; Serial receive
	out	SREG,t_sr		; Restore SREG
	reti

;-- Init hardware --
init_hw:
	ldi	tmp,$00			; Disable WDT
	out	WDTCR,tmp

	ldi	tmp,(1<<SE)|(1<<ISC01)|(1<<ISC00) ; Sleep Enable & Clear SM, Set rising edge INT0
	out	MCUCR,tmp

	ldi	tmp,(256-N+8)		; Set reload value
	mov	t_reld,tmp

	ldi	rsv_wc,BAUD_9600/8	; Set wait 1/8bit
	ldi	rsv_bc,0

	ldi	tmp,0b11111111
	mov	trn_bit,tmp
	ldi	tmp,0b00000000
	mov	trn_wv,tmp
	ldi	trn_wc,BAUD_2400
	ldi	trn_bc,0
	ldi	trn_1c,0

	ldi	str,0b00000000

	ldi	bfc,0
	ldi	YL,low(bf_start)	; Set buffer write pointer
	ldi	YH,high(bf_start)
	ldi	ZL,low(bf_start)	; Set buffer read pointer
	ldi	ZH,high(bf_start)

	ldi	tmp,0b00000101		; PB2,PB0(output)/PB1(input)
	out	DDRB,tmp
	ldi	tmp,0b00000101
	out	PORTB,tmp

	ldi	tmp,0			; Stop timer
	out	TCCR0,tmp
	ldi	tmp,0			; Disable T/C0 overflow interrupt
	out	TIMSK,tmp
	ldi	tmp,(1<<TOV0)		; Clear T/C0 overflow flag
	out	TIFR,tmp
	out	TCNT0,t_reld		; Set reload value

	ldi	tmp,(1<<INTF0)		; Clear INT0 flag
	out	GIFR,tmp
	ldi	tmp,(1<<INT0)		; Enable INT0
	out	GIMSK,tmp
	ret

;-- Main --
reset:
	ldi	tmp,$00			; Clear EXTRF and PORF
	out	MCUSR,tmp
	ldi	tmp,RAMEND		; Set stack-pointer
	out	SPL,tmp
	rcall	init_hw			; Init hardware
	sei				; Enable interrupt
loop:
	sbrc	str,TDBF		; Check clear TDBF
	rjmp	loop
	cpi	bfc,0			; Check buffer counter
	breq	idle			; Go to Idle Mode
	ld	tmp,Z+
	dec	bfc
	cpi	ZL,low(bf_end)		; ZL < bf_end
	brlo	rp_cls_skip
	ldi	ZL,low(bf_start)
rp_cls_skip:
	mov	trn_bf,tmp
	sbr	str,(1<<TDBF)		; Set TDBF
	rjmp	loop
idle:
	sbrc	str,RBSY		; Check clear RBSY
	rjmp	loop
	ldi	tmp,0			; Stop timer
	out	TCCR0,tmp
	ldi	tmp,0			; Disable T/C0 overflow interrupt
	out	TIMSK,tmp
	ldi	tmp,(1<<TOV0)		; Clear T/C0 overflow flag
	out	TIFR,tmp
	out	TCNT0,t_reld		; Set reload value
	ldi	tmp,(1<<INTF0)		; Clear INT0 flag
	out	GIFR,tmp
	ldi	tmp,(1<<INT0)		; Enable INT0
	out	GIMSK,tmp
	sleep				; Idle Mode(SM = 0)
	rjmp	loop
