;**** A P P L I C A T I O N   N O T E   A V R 9 1 0 ************************
;*
;* Title	: AVR ISP
;* Version	: 1.5
;* Last updated	: 97.08.26
;* Target	: AT90S1200
;*
;* DESCRIPTION
;*	The firmware on all programmers now support a unified protocol for 
;*	program and data memory programming. The host computer do not need
;*	to know if the programmer operates in serial or parallel mode.
;*
;*	The following commands are supported. All commands start with a
;*	single letter. The programmer returns 13d (carriage return) or the
;*	data read after the command is finished.
;*
;*                                     +-------------+------------+------+
;*  Commands                           | Host writes | Host reads |      |
;*  --------                           +-----+-------+------+-----+      |
;*                                     | ID  | data  | data |     | Note |
;* +-----------------------------------+-----+-------+------+-----+------+
;* | Enter programming mode            | 'P' |       |      | 13d |   1  |
;* | Set address                       | 'A' | ah al |      | 13d |   2  |
;* | Write program memory, low byte    | 'c' |    dd |      | 13d |   3  |
;* | Write program memory, high byte   | 'C' |    dd |      | 13d |   3  |
;* | Read program memory               | 'R' |       |dd(dd)|     |   4  |
;* | Write data memory                 | 'D' |    dd |      | 13d |      |
;* | Read data memory                  | 'd' |       |   dd |     |      |
;* | Chip erase                        | 'e' |       |      | 13d |      |
;* | Write lock bits                   | 'l' |    dd |      | 13d |      |
;* | Write fuse bits                   | 'f' |    dd |      | 13d |  11  |
;* | Read fuse and lock bits           | 'F' |       |   dd |     |  11  |
;* | Leave programming mode            | 'L' |       |      | 13d |   5  |
;* | Select device type                | 'T' |    dd |      | 13d |   6  |
;* | Read signature bytes              | 's' |       | 3*dd |     |      |
;* | Return supported device codes     | 't' |       | n*dd | 00d |   7  |
;* | Return software identifier        | 'S' |       | s[7] |     |   8  |
;* | Return sofware version            | 'V' |       |dd dd |     |   9  |
;* | Return hardware version           | 'v' |       |dd dd |     |   9  |
;* | Return programmer type            | 'p' |       |   dd |     |  10  |
;* | Set LED                           | 'x' |    dd |      | 13d |  12  |
;* | Clear LED                         | 'y' |    dd |      | 13d |  12  |
;* +-----------------------------------+-----+-------+------+-----+------+
;*
;* NOTE 1
;*	The Enter programming mode command MUST be sent one time prior to
;*	the other commands, with the exception of the 't', 'S', 'V', 'v'
;*	and 'T' commands. The 'T' command must be sent before this command
;*	(see note 6).
;*
;*	For programmers supporting both parallel and serial programming
;*	mode this command enters parallel programming mode. For programmers
;*	supporting only serial programming mode, this command enters serial
;*	programming mode.
;*
;* NOTE 2
;*	The ah and al are the high and low order bytes of the address. For
;*	parallel programmers this command issues the Load Address Low/High
;*	Byte command. For serial programmers the address byte is stored for
;*	use by the Read/Write commands.
;*
;* NOTE 3
;*	For parallel programmers this command issues the Program Flash
;*	command. For serial programmers this command iussues the Write
;*	Program Memory Command. For devices with byte-wide program memories
;*	only the low byte command should be used.
;*
;* NOTE 4
;*	The contents of the program memory at the address given by the 'A'
;*	command are written to the serial port in binary form. For byte
;*	wide memories one byte is written. For 16 bit memories two bytes
;*	are written,MSB first.
;*
;* NOTE 5
;*	This command must be executed after the programming is finished.
;*
;* NOTE 6
;*	The select device type command must be sent before the enter
;*	programming command
;*
;* NOTE 7
;*	The supported device codes are returned in binary form terminated
;*	by 0x00.
;*
;* NOTE 8
;*	This return a 7 character ASCII string identifying the programmer.
;*	For the development board it is "AVR DEV", for the parallel
;*	programmer it is "AVR PPR" and for the in-curcuit programmer it is
;*	"AVR ICP".
;*
;* NOTE 9
;*	The software/hardware version are returned as two ASCII numbers.
;*
;* NOTE 10
;*	This command should be used to identify the programmer type. The
;*	return value is 'S' for serial (or SPI) programmers or 'P' for
;*	parallel programmers.
;*
;* NOTE 11
;*	The write fuse bits command are available only on parallel
;*	programmers and only for AVR devices (device code < 0x80). The host
;*	should use the return programmer type command to determine the
;*	programmer type, do not use the  "AVR PPR" idenifier because other
;*	programmers may be available in the future.
;*
;* NOTE 12
;*	Currently only the AVR development board has LEDs. The other boards
;*	must implement this commands as NOPs.
;*
;* HISTORY
;*	V1.5	97.08.21 (MWL)	Modified / Bugfix / Major cleanup
;*	...	...		(no records)
;*	V?.?	97.03.15 (OS)	Created
;*		
;***************************************************************************

;**** includes ****

.include "1200def.inc"

;***************************************************************************
;*
;* CONSTANTS
;*	device codes
;*
;* DESCRIPTION
;*	The following device codes must be used by the host computer. Note
;*	that the device codes are arbitrary selected, they do not have any
;*	thing in common with the signature bytes stored in the device.
;*
;*	The following devices are supported (make a new table for each
;*	software release):
;*
;*	SW_MAJOR=1, SW_MINOR=5
;*
;*	AT90S1200 rev. C (abbreviated S1200C)
;*	AT90S1200 rev. D (abbreviated S1200D)
;*	AT90S8515 rev. A (abbreviated S8515A)
;*	AT89S8252 (abbreviated S8252)
;*
;***************************************************************************

.equ	S1200C	= 0x12
.equ	S1200D	= 0x13
.equ	S8515A	= 0x38
.equ	S8252	= 0x86

;**** Revision Codes ****

.equ	SW_MAJOR = 1		; Major SW revision number
.equ	SW_MINOR = 5		; Minor SW revision number
.equ	HW_MAJOR = 1		; Major HW revision number
.equ	HW_MINOR = 0		; Minor HW revision number


;***************************************************************************
;*
;* MACROS
;*	Program Macros
;*
;* DESCRIPTION
;*	Change the following four macros if the RESET pin to the
;*	target moves and/or if the SCK/MISO/MOSO moves.
;*
;***************************************************************************

.macro	set_reset
	sbi	portb,4
.endm

.macro	clr_reset
	cbi	portb,4
.endm

.macro	ddrd_init
	nop
;	sbi	ddrd,3
.endm

.macro	ddrb_init
	ldi	temp1,0xdf
	out	ddrb,temp1	; PB5 is input, the rest is output
.endm

.macro	pulse_sck
	sbi	portb,SCK
	ldi	temp2,6
m0:	dec	temp2
	brne	m0
	cbi	portb,SCK
	ldi	temp2,3
m1:	dec	temp2
	brne	m1
.endm


;*****************
;* SPI Constants *
;*****************

.equ	MOSI	= 6		; Bit number on PORTB
.equ	MISO	= 5		; Bit number on PORTB
.equ	SCK	= 7		; Bit number on PORTB


;******************
;* UART Constants *
;******************

;**** Constant declarations Data Rate ****

;.equ	N = 95			; 115200 BAUD when R=1 and XTAL=11.059MHz
;.equ	N = 31			; 57600 BAUD when R=2 and XTAL=11.059MHz
;.equ	N = 43			; 38400 BAUD when R=2 and XTAL=11.059MHz
.equ	N = 33			; 19200 BAUD when R=2 and XTAL=4.00MHz
;.equ	N = 102			; 38400 BAUD when R=1 and XTAL=4.00MHz
.equ	R = 2

;**** UART transmit pin in PORTD ****

.equ	TXPIN = 1
.equ	RXPIN = 0		

;**** Bit positions in UART Status Register ****

.equ	TXC = 0			; Transmit
.equ	RXC = 1			; Receive


;*****************************
;* Global Register Variables *
;*****************************

.def	device	= r16		; Device code
.def	temp1	= r17
.def	temp2	= r18
.def	s_data	= r19		; SPI data
.def	u_data	= r20		; UART data
.def	addrl	= r21		; Low order byte of address
.def	addrh	= r22		; High order byte of address
.def	bit_cnt	= r23		; Bit count used by UART routine
.def	u_stat	= r24		; Status byte used by UART routine
.def	cmd	= r25		; Serial programming command
.def	count	= r26		; Time out variable for "enter programming mode"
;.def	debug1	= r27

;*********************
;* Interrupt Vectors *
;*********************

.CSEG
	rjmp	RESET		; Reset Handle
	reti			; IRQ0 Handle (not used)
	rjmp	TIM0_OVF	; Timer0 Overflow Handle
	reti			; Analog Comparator Handle (not used)


;***************************************************************************
;*
;* INTERRUPT
;*	TIM0_OVF - Timer/Counter0 Overflow Interrupt
;*
;***************************************************************************

TIM0_OVF:
	in	r0,SREG		; store SREG
	ldi	temp1,(256-N+8)
	out	TCNT0,temp1	; reset T/C0 to one bit lenght
	inc	bit_cnt		; increment bit counter
	sbrs	u_stat,TXC	; if (transmit complete flag clear)
	rjmp	transmit	;    goto transmit

to_0:	sec			; set carry
	sbis	PIND,RXPIN	; if (RxD == LOW)
	clc			;	clear carry
	ror	u_data		; shift carry into u_data

	cpi	bit_cnt,8	; if (bit_cnt == 8)
	brne	to_1		; {
	clr	temp1		;    disable T/C0 Overflow Interrupt
	out	TIMSK,temp1
	sbr	u_stat,1<<RXC	;    set receive complete
to_1:				; }
	out	SREG,r0	        ; restore SREG
	reti			; exit

transmit:
	cpi	bit_cnt,1	; if (bit_cnt == 1)	\\ start bit
	brne	to_2		; {
	cbi	PORTD,TXPIN	;	generate start bit
	rjmp	to_1		;	exit
to_2:				; }
	cpi	bit_cnt,10	; if (bit_cnt == 10)	\\ stop bit
	brne	to_3		; {
	sbi	PORTD,TXPIN	;	generate stop bit
	clr	temp1		;	disable TC0 overflow interrupt
	out	TIMSK,temp1
	sbr	u_stat,1<<TXC	;	set transmit complete bit
	rjmp	to_1		;	exit
to_3:				; }
	sbrc	u_data,0	; if (LSB set)
	sbi	PORTD,TXPIN	;	PD3 = HIGH
	sbrs	u_data,0	; if (LSB clear)
	cbi	PORTD,TXPIN	;	PD3 = LOW
	lsr	u_data		; shift left u_data
	rjmp	to_1		; exit


;***************************************************************************
;*
;* FUNCTION
;*	u_init
;*
;* DESCRIPTION
;*	Initialize UART.
;*
;***************************************************************************

u_init:	ldi	u_stat,1<<TXC	; set TXC
	ldi	temp1,R		; set clock rate
	out	TCCR0,temp1
	sbi	DDRD,TXPIN	; initialize UART pins
	cbi	DDRD,RXPIN
	ret


;***************************************************************************
;*
;* FUNCTION
;*	putc
;*
;* DESCRIPTION
;*	Send a character on the UART Tx line.
;*
;***************************************************************************

putc:	clr	u_stat		; clear UART status flags
	clr	bit_cnt		; clear bit counter
	ldi	temp1,1<<TOV0	; enable T/C0 overflow interrupt
	out	TIMSK,temp1
putc0:	sbrs	u_stat,TXC	; while (!(u_stat & TXC)); // Wait for TXC
	rjmp	putc0
	ret


;***************************************************************************
;*
;* FUNCTION
;*	getc
;*
;* DESCRIPTION
;*	Wait for start bit and receive a character on the UART Rx line.
;*
;***************************************************************************

getc:	sbis	PIND,RXPIN
	rjmp	getc
getc0:	sbic	PIND,RXPIN
	rjmp	getc0
	ldi	temp1,(256-(N+N/2)+8+12);
	out	TCNT0,temp1 	; preset T/C0 to 1.5 bit lengths
	ldi	temp1,1<<TOIE0
	out	TIFR,temp1	; clear T/C0 overflow flag
	out	TIMSK,temp1	; enable T/C0 overflow Interrupt
	clr	bit_cnt		; clear bit counter
getc1:	sbrs	u_stat,RXC	; wait for Receive Complete
	rjmp	getc1
	cbr	u_stat,1<<RXC	; clear RXC
	ret


;***************************************************************************
;*
;* FUNCTION
;*	delay
;*
;* DESCRIPTION
;*	 Make a small delay.
;*
;***************************************************************************

delay:	ldi	temp2,0xff
dl:	dec	temp2
	brne	dl
	dec	temp1
	brne	delay
	ret


;***************************************************************************
;*
;* FUNCTION
;*	wrser
;*
;* DESCRIPTION
;*	 Write a byte to the SPI.
;*
;***************************************************************************

wrser:	ldi	temp1,8
wrs0:	rol	s_data
	brcc	wrs1
	sbi	portb,MOSI
	rjmp	wrs2
wrs1:	cbi	portb,MOSI
wrs2:	pulse_sck
	dec	temp1
	brne	wrs0
	ret


;***************************************************************************
;*
;* FUNCTION
;*	rdser
;*
;* DESCRIPTION
;*	 Read a byte from the SPI.
;*
;***************************************************************************

rdser:	ldi	temp1,8
	ldi	s_data,0
rd0:	lsl	s_data
	sbic	pinb,MISO
	ori	s_data,1
	pulse_sck
	dec	temp1
	brne	rd0
	ret


;***************************************************************************
;*
;* FUNCTION
;*	spiinit (Enter programming mode)
;*
;* DESCRIPTION
;*	Initialize SPI interface on AVR or 'AT89 device.
;*
;***************************************************************************

spiinit:ddrd_init		; initialize port D
	ddrb_init		; initialize port B
	cbi	portb,SCK	; clear SCK
	cpi	device,S8252	; if (device != S8252)
	breq	s89		; {
	set_reset		;	set RESET = 1
	ldi	temp1,0xff	;	delay(0xff);
	rcall	delay
	clr_reset		;	set RESET = 0
	rjmp	s0		; }
				; else
s89:				; {
	clr_reset		; 	set RESET = 0
	ldi	temp1,0xff	;	delay(0xff);
	rcall	delay
	set_reset		;	set RESET = 1
s0:				; }
	ldi	temp1,0xff	; delay(0xff);
	rcall	delay

	ldi	s_data,0xac	; wrser(0xac);		// SPI write (byte 1)
	rcall	wrser
	ldi	s_data,0x53	; wrser(0x53);		// SPI write (byte 2)
	rcall	wrser

	cpi	device,S8515A	; if (device == S8515A)	// SPI Synchronization (fix!)
	brne	s2		; {
	ldi	count,32	;	count = 32;
s1:				;	do {
	rcall	rdser		;		if (rdser == 0x53)	// SPI read (byte 3)
	cpi	s_data,0x53
	breq	s3		;			break;
	ldi	s_data,0x00	;		wrser(0x00);		// SPI write (byte 4)
	rcall	wrser
	pulse_sck		;		pulse SCK
	ldi	s_data,0xac	;		wrser(0xac);		// SPI write (byte 1)
	rcall	wrser
	ldi	s_data,0x53	;		wrser(0x53);		// SPI write (byte 2)
	rcall	wrser
	dec	count		;	} while(--count);
	brne	s1
	rjmp	s3		; }
				; else
s2:				; {
	ldi	s_data,0x00	;	wrser(0x00);		// SPI write (byte 3)
	rcall	wrser
s3:				; }
	cpi	device,S8252	; if (device != S8252)
	breq	s4		; {
	ldi	s_data,0x00	;	wrser(0x00);	// SPI write (byte 4)
	rcall	wrser
s4:				; }
	ldi	temp1,0x10	; delay(0x10);
	rcall	delay
	ret



;***************************************************************************
;*
;* FUNCTION
;*	show_id
;*
;* DESCRIPTION
;*	Show our ID ("AVR ISP") on the serial line.
;*
;***************************************************************************

show_id:ldi	u_data,0x41		; 'A'
	rcall	putc
	ldi	u_data,0x56		; 'V'
	rcall	putc
	ldi	u_data,0x52		; 'R'
	rcall	putc
	ldi	u_data,0x20		; ' '
	rcall	putc
	ldi	u_data,0x49		; 'I'
	rcall	putc
	ldi	u_data,0x53		; 'S'
	rcall	putc
	ldi	u_data,0x50		; 'P'
	rcall	putc
	ret


;***************************************************************************
;*
;* RESET
;*
;* DESCRIPTION
;*	Initialization
;*
;***************************************************************************

RESET:	clr	temp1
	out	GIMSK,temp1	; disable external interrupt
	ser	temp1		; Initialize
	out	PORTD,temp1
	set_reset		; set RESET=1
	out	DDRB,temp1
	out	PORTB,temp1
	rcall	u_init		; Initialize UART
	sei			; Enable interrupts


;***************************************************************************
;*
;* PROGRAM
;*	waitcmd -> main
;*
;* DESCRIPTION
;*	Wait for and execute commands.
;*
;***************************************************************************

waitcmd:rcall	getc		; while (getc() == ESC) {};
	cpi	u_data,0x1b
	breq	waitcmd

;**** Device Type ****

	cpi	u_data,0x54     ; 'T' Device type
	brne	w0
	rcall	getc		; getc();	// dummy
	mov	device,u_data	; putc(device);
	rjmp	put_ret

;**** Return Software Identifier ****

w0:	cpi	u_data,0x53	; 'S' Return software identifier
	brne	w1
	rcall	show_id		; show_id();
	rjmp	waitcmd

;**** Return Software Version ****

w1:	cpi	u_data,0x56	;'V' Return software version
	brne	w2
	ldi	u_data,0x30+SW_MAJOR ; putc(0x30+SW_MAJOR);
	rcall	putc
	ldi	u_data,0x30+SW_MINOR ; putc(0x30+SW_MINOR);
	rcall	putc
	rjmp	waitcmd

;**** Return Hardware Version ****

w2:	cpi	u_data,0x76	;'v' Return hardware version
	brne	w3
	ldi	u_data,0x30+HW_MAJOR ; putc(0x30+HW_MAJOR);
	rcall	putc
	ldi	u_data,0x30+HW_MINOR ; putc(0x30+HW_MINOR);
	rcall	putc
	rjmp	waitcmd

;**** Show Supported Devices ****

w3:	cpi	u_data,0x74	; 't' Show supported devices
	brne	w4
	ldi	u_data,S1200C	; putc(S1200C);
	rcall	putc
	ldi	u_data,S1200D	; putc(S1200D);
	rcall	putc
	ldi	u_data,S8515A	; putc(S8515A);
	rcall	putc
	ldi	u_data,S8252	; putc(S8252);
	rcall	putc
	ldi	u_data,0x00	; putc(0x00);	// end of device list
	rcall	putc
	rjmp	waitcmd

;**** Return Programmer Type ****

w4:	cpi	u_data,0x70     ; 'p' Return programmer type
	brne	w5
	ldi	u_data,0x53     ; putc('S');	// serial programmer
	rcall	putc
	rjmp	waitcmd

;**** Set LED ****

w5:	cpi	u_data,0x78	; 'x' Set LED (ignored)
	brne	w6
	rjmp	put_ret

;**** Clear LED ****

w6:	cpi	u_data,0x79     ; 'y' Clear LED (ignored)
	brne	w7
	rjmp	put_ret

;**** Enter Programming Mode ****

; We require that the device code be selected before any of the other commands

w7:	cpi	device,S1200C	; if ((device != S1200C) &&
	breq	w72
	cpi	device,S1200D	;     (device != S1200D) &&
	breq	w72
	cpi	device,S8515A	;     (device != S8515A) &&
	breq	w72
	cpi	device,S8252	;     (device != S8252))
	breq	w72
	rjmp	put_err		;	goto put_err();

w72:	cpi	u_data,0x50	; 'P' Enter programming mode
	brne	w8
	rcall	spiinit		; spiinit();
	rjmp	put_ret

;**** Wait Program Memory ****

;* USAGE
;*	wait_pm(byte cmd, byte c_data);
;*
;*	cmd :		0x28 - wait for high byte written
;*			0x20 - wait for low byte written
;*	u_data :	current data written

;wait_pm:			; do
;				; {
;	mov	s_data,cmd	;	wrser(cmd);		// SPI write (byte 1)
;	rcall	wrser
;	mov	s_data,addrh	;	wrser(addrh);		// SPI write (byte 2)
;	rcall	wrser
;	mov	s_data,addrl	;	wrser(addrl);		// SPI write (byte 3)
;	rcall	wrser
;	rcall	rdser		;	s_data = rdser();	// SPI read (byte 4)
				; }
;	cp	s_data,u_data	; while(s_data != u_data);
;	brne	wait_pm
;	ret

;**** Write Program Memory, High Byte ****

w8:	cpi	u_data,0x43	; 'C' Write program memory, high byte
	brne	w9
	rcall	getc
	cpi	device,S8252	; if (device == S8252)
	brne	w81		; {
	rjmp	put_err		; 	goto err();
				;	// (AT89 series have byte wide program memory !)
				; }
w81:	ldi	s_data,0x48	; wrser(0x48);		// SPI write (byte 1)
	rcall	wrser
	mov	s_data,addrh	; wrser(addrh);		// SPI write (byte 2)
	rcall	wrser
	mov	s_data,addrl	; wrser(addrl);		// SPI write (byte 3)
	rcall	wrser
	mov	s_data,u_data	; wrser(u_data);	// SPI write (byte 4)
	rcall	wrser
	ldi	temp1,0x20	; delay(0x20);		// 24585 cycles delay
	rcall	delay

;	ldi	cmd,0x28
;	sbi	PORTB,PB3	;						DEBUG!!!!!
;	rcall	wait_pm
;	cbi	PORTB,PB3	;						DEBUG!!!!!

	rjmp	put_ret		; goto reply();

;**** Write Program Memory, Low Byte ****

w9:	cpi	u_data,0x63     ; 'c' Write program memory, low byte
	brne	w10
	rcall	getc

	cpi	device,S8252	; if (device != S8252)
	breq	w989		; {
	ldi	s_data,0x40	;	wrser(0x40);	// SPI write (byte 1)
	rcall	wrser
	mov	s_data,addrh	;	s_data = addrh;
	rjmp	w91		; }
				; else
w989:				; {
	mov	s_data,addrh	;	s_data = (addrh << 3) | 0x02;
	lsl	s_data
	lsl	s_data
	lsl	s_data
	ori	s_data,0x02
w91:				; }
	rcall	wrser		; wrser(s_data);	// SPI write (byte 2)
	mov	s_data,addrl	; wrser(addrl);		// SPI write (byte 3)
	rcall	wrser
	mov	s_data,u_data	; wrset(u_data);	// SPI write (byte 4)
	rcall	wrser
	ldi	temp1,0x20	; delay(0x20);		// 24585 cycles delay
	rcall	delay

;	ldi	cmd,0x20
;	sbi	PORTB,PB3	;						DEBUG!!!!!
;	rcall	wait_pm
;	cbi	PORTB,PB3	;						DEBUG!!!!!

	rjmp	put_ret		; goto reply();

;**** Read Program Memory ****

w12:	cpi	u_data,0x52	; 'R' Read program memory
	brne	w13
	cpi	device,S8252	; if (device != S8252)
	breq	w1289		; {
	ldi	s_data,0x28	;	wrser(0x28);	// SPI write (byte 1)
	rcall	wrser
	mov	s_data,addrh	;	s_data = addrh;
	rjmp	w121		; }
				; else
w1289:				; {
	mov	s_data,addrh	;	s_data = (addrh << 3) | 0x01;
	lsl	s_data
	lsl	s_data
	lsl	s_data
	ori	s_data,0x01
w121:				; }
	rcall	wrser		; wrser(s_data);	// SPI write (byte 2)
	mov	s_data,addrl	; wrser(addrl);		// SPI write (byte 3)
	rcall	wrser
	rcall	rdser		; putc(rdser());	// Send data (byte 4)
	mov	u_data,s_data
	rcall	putc
	cpi	device,S8252	; if (device == S8252)
	brne	w122		; {
	rjmp	waitcmd		;	goto waitcmd();
				; }
				; else
w122:				; {
	ldi	s_data,0x20	;	wrser(0x20);	// SPI write (byte 1)
	rcall	wrser
	mov	s_data,addrh	;	wrser(addrh);	// SPI write (byte 2)
	rcall	wrser
	mov	s_data,addrl	;	wrser(addrl);	// SPI write (byte 3)
	rcall	wrser
	rcall	rdser		;	putc(rdser());	// Send data (byte 4)
	mov	u_data,s_data
	rcall	putc
	rjmp	waitcmd		;	goto waitcmd();
				; }

;**** Load Address ****

w10:	cpi	u_data,0x41	; 'A' Load address
	brne	w11
	rcall	getc		; addrh = getc();
	mov	addrh,u_data
	rcall	getc		; addrl = getc();
	mov	addrl,u_data
	rjmp	put_ret		; goto reply();

;**** Write Data Memory ****

w11:	cpi	u_data,0x44	; 'D' Write data memory
	brne	w12
	rcall	getc
	cpi	device,S8252
	breq	w1189

	ldi	s_data,0xc0
	rcall	wrser
	mov	s_data,addrh
	rjmp	w111

w1189:	mov	s_data,addrh
	lsl	s_data
	lsl	s_data
	lsl	s_data
	ori	s_data,0x06

w111:	rcall	wrser
	mov	s_data,addrl
	rcall	wrser
	mov	s_data,u_data
	rcall	wrser
	ldi	temp1,0x20
	rcall	delay
	rjmp	put_ret

;;**** Read Data Memory ****

w13:	cpi	u_data,0x64	; 'd' Read data memory
	brne	w14
	cpi	device,S8252	; if (device != S8252)
	breq	w1389		; {
	ldi	s_data,0xa0	;	wrser(0xA0);	// SPI write (byte 1)
	rcall	wrser
	mov	s_data,addrh	;	s_data = addrh;
	rjmp	w131		; }
				; else
w1389:				; {
	mov	s_data,addrh	;	s_data = (addrh << 3) | 0x05;
	lsl	s_data
	lsl	s_data
	lsl	s_data
	ori	s_data,0x05
w131:				; }
	rcall	wrser		; wrser(s_data);	// SPI write (byte 2)
	mov	s_data,addrl	; wrser(addrl);		// SPI write (byte 3)
	rcall	wrser
	rcall	rdser		; putc(rdser());	// Send data (byte 4)
	mov	u_data,s_data
	rcall	putc
	rjmp	waitcmd		; goto waitcmd();


;**** Leave Programming Mode ****

w14:	cpi	u_data,0x4c	; 'L' Leave programming mode
	brne	w15
	cpi	device,S8252
	breq	w141
	set_reset		; set RESET = 1
	rjmp    put_ret
w141:	clr_reset		; set RESET = 0
	rjmp	put_ret

;**** Chip Erase ****

w15:	cpi	u_data,0x65     ; 'e' Chip erase
        brne	w16
	ldi	s_data,0xac
	rcall	wrser
	cpi	device,S8252
	breq	w1589
	ldi	s_data,0x80
	rcall	wrser
w1589:	ldi	s_data,0x04
	rcall	wrser
	ldi	s_data,0x00
	rcall	wrser
	ldi	temp1,0x30
	rcall	delay
	rjmp	put_ret

;**** Write Lock Bits ****

w16:	cpi	u_data,0x6c	; 'l' Write lock bits
	brne	w17
	rcall	getc
	ldi	s_data,0xac
	rcall	wrser
	mov	s_data,u_data
	cpi	device,S8252
	breq	w1689
	andi	s_data,0x06
	ori	s_data,0xe0
	rcall	wrser
	ldi	s_data,0x00
	rcall	wrser
	rjmp	w162

w1689:	andi	s_data,0xe0
	ori	s_data,0x07
	rcall	wrser
w162:	ldi	s_data,0x00
	rcall	wrser
	ldi	temp1,0x30
	rcall	delay
	rjmp	put_ret

;**** Read Signature Bytes ****

w17:	cpi	u_data,0x73	; 's' Read signature bytes
	brne	w99
	cpi	device,S8252
	breq	put_err

	ldi	s_data,0x30
	rcall	wrser
	ldi	s_data,0x00
	rcall	wrser
	ldi	s_data,0x02
	rcall	wrser
	rcall	rdser
	mov	u_data,s_data
	rcall	putc

	ldi	s_data,0x30
	rcall	wrser
	ldi	s_data,0x00
	rcall	wrser
	ldi	s_data,0x01
	rcall	wrser
	rcall	rdser
	mov	u_data,s_data
	rcall	putc

	ldi	s_data,0x30
	rcall	wrser
	ldi	s_data,0x00
	rcall	wrser
	ldi	s_data,0x00
	rcall	wrser
	rcall	rdser
	mov	u_data,s_data
	rcall	putc
	rjmp	waitcmd

w99:	rjmp	put_err

;**** Reply Command ****

put_ret:ldi	u_data,0x0d	; putc(0x0D);	\\ send CR
	rcall	putc
	rjmp	waitcmd

;**** Command Error ****

put_err:ldi	u_data,0x3f	; putc('?');	\\ send '?'
	rcall	putc
	rjmp	waitcmd

;**** End of File ****
