;***************************************************************************
;*
;* Title	: AVR ISP (Auto adr inc, 115200bps)
;* Version	: 3.2
;* Last updated	: Dec 09 2002 
;* Target	: AT90S2313
;* File		: avr910_31.asm
;* Author(s)	: Dreadatour@mail.ru
;*
;* 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  |
;* | Report autoincrement address      | 'a' |       |      | 'Y' |      |
;* | 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  |
;* | Issue Page Write                  | 'm' |       |      | 13d |      |
;* | 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  |
;* | Universial command                | ':' |  3*dd |   dd | 13d |      |
;* | New universal command             | '.' |  4*dd |   dd | 13d |      |
;* | Special test command              | 'Z' |  2*dd |   dd |     |      |
;* +-----------------------------------+-----+-------+------+-----+------+
;*
;* 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 ISP".
;*
;* 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.
;*
;* NOTE 13
;*      Devices using Page Mode Programming write one page of flash memory
;*      before issuing a Page Mode Write Pulse.
;*
;* HISTORY
;* V3.1	 05.03.09 (dred)	Добавил нормальную работу со светодиодами,
;*				индицирующими работу девайса
;* V3.0	 02.01.23 (wubble)	Ported from 1200 to 2313.
;*				Serial IO modified to use hardware UART.
;*				Added support for multiple new devices.
;*				Used data polling to short write process.
;*				Added LED support to indicate R/W process.
;* V2.2	 00.03.10 (pkastnes)	Added support for multiple new devices.
;* V2.1	 98.10.26 (mlund)	New date marking.
;*				Removed support for AT90S1200C.
;*				Added support for AT90S4433A.
;* V2.0	 98.01.06 (mlund)	ATmega103 support.
;* V1.7	 97.11.06 (mlund)	Universial command (':') implemented.
;*				Releases all pins when not in 
;*				programming mode.
;* V1.6e 97.11.04 (mlund)	mega103 rev D support
;* V1.6c 97.10.30 (mlund)	Auto incrementing / SPI sync
;*				also works for mega103.
;* V1.6	 97.09.09 (hskar)	Created Page Mode Version (mega103)
;* V1.5	 97.08.21 (mlund)	Modified / Bugfix / Major cleanup
;* ...	 ...			(no records)
;* V?.?	 97.03.15 (OS)		Created
;* 
;*		
;* Device Support List: see table "Devices" at the end of this file.
 
;***************************************************************************

;**** includes ****

.include "2313def.inc"

;***************************************************************************
;*
;* CONSTANTES
;*
;***************************************************************************

;**** Constant declarations Data Rate ****

.equ	XTAL 		= 11059		;XTAL frequency, KHz
.equ	BAUD 		= 115200		;Data rate, bauds

.equ	N 			= ((XTAL*10000)/(16*BAUD)-5)/10

;***************************************************************************
;*
;* PORTS
;*	Ports Definitions
;*
;* DESCRIPTION
;*	Change the following definitions if the RESET pin to the
;*	target moves and/or if the SCK/MISO/MISO/LED moves.
;*
;***************************************************************************

.equ	MISO		= PB0		; MISO  pin of the target (input)
.equ	SCK		= PB1		; SCK   pin of the target (output)
.equ	RESET		= PB2		; RESET pin of the target (output)
.equ	LED		= PB3		; LED output, active low  (output)
.equ	MOSI		= PB4		; MOSI  pin of the target (output)
.equ	RXD		= PD0		; UART RXD line
.equ	TXD		= PD1		; UART TXD line

.equ	WriteLed	= PD4
.equ	ReadLed		= PD2

;***************************************************************************
;*
;* MACROS
;*	Program Macros
;*
;* DESCRIPTION
;*	Change the following macros if the RESET pin to the
;*	target moves and/or if the SCK/MISO/MISO/LED moves.
;*
;***************************************************************************

.macro	init_ports		;init ports
	ser		temp2
	out		PORTD,	temp2
	out		PORTB,	temp2
.endm

.macro	catch_ports		;catch ports
	ldi		temp2,	(1<<TXD) | (1<<WriteLed) | (1<<ReadLed)
	out		DDRD,	temp2
	ldi		temp2,	(1<<RESET) | (1<<MOSI) | (1<<SCK) | (1<<LED)
	out		DDRB,	temp2
.endm

.macro	release_ports		;release ports
	ldi		temp2,	(1<<TXD) | (1<<WriteLed) | (1<<ReadLed)
	out		DDRD,	temp2
	ldi		temp2,	(1<<RESET) | (1<<LED)
	out		DDRB,	temp2
.endm

.macro	pas_RESET		;set RESET passive
	tst	device
	brmi	m2		; S89 device
	sbi	portb,RESET
	rjmp	m3
m2:	cbi	portb,RESET
m3:		
.endm

.macro	act_RESET		;set RESET active
	tst	device
	brmi	m4		; S89 device
	cbi	portb,RESET
	rjmp	m5
m4:	sbi	portb,RESET
m5:		
.endm

.macro	set_LED			;set LED
	sbi	portb,LED
.endm

.macro	clr_LED			;clear LED
	cbi	portb,LED
.endm

.macro	sbic_MISO		;skip if MISO cleared
	sbic	pinb,MISO
.endm

.macro	set_MOSI		;set MOSI
	sbi	portb,MOSI
.endm

.macro	clr_MOSI		;clear MOSI
	cbi	portb,MOSI
.endm

.macro	clr_SCK			;clear SCK
	cbi	portb,SCK	
.endm

.macro	pulse_SCK		;pulse SCK
	sbi	portb,SCK
	ldi	temp2,(XTAL/1500+1)		
m0:	dec	temp2
	brne	m0
	cbi	portb,SCK
	ldi	temp2,(XTAL/3000+1)
m1:	dec	temp2
	brne	m1
.endm

.macro	table			;load Z pointer
	ldi	ZL,low (@0*2)
	ldi	ZH,high(@0*2)
.endm

;***************************************************************************
;*
;* Global Register Variables
;*
;***************************************************************************

;r0 used with lpm instruction

.def	cmd1		= r1	; Universal commands params
.def	cmd2		= r2	; ..
.def	cmd3		= r3	; ..
.def	pol_al		= r4	; Polling address low
.def	pol_ah		= r5	; Polling address high

.def	temp1		= r16	; Temporary register 1
.def	temp2		= r17	; Temporary register 2
.def	temp3		= r18	; Temporary register 3
.def	s_data		= r19	; SPI data
.def	u_data		= r20	; UART data
.def	device		= r21	; Device code
.def	param1		= r22	; Param to read signature 
.def	rd_s_data	= r23	; Read data on SPI
.def	pol_cmd		= r24	; Polling command
.def	p_data		= r25	; Polling data

.def	addrl		= r28	; (YL) Low order byte of address
.def	addrh		= r29	; (YH) High order byte of address

;r30,r31 used as Z register

;***************************************************************************
;*
;* Interrupt Vectors
;*
;***************************************************************************

.CSEG
	rjmp	INIT		; Reset Handle

;***************************************************************************
;*
;* FUNCTION
;*	u_init
;*
;* DESCRIPTION
;*	Initialize UART.
;*
;***************************************************************************

u_init:	
	ldi	temp1,N		; set baud rate
	out	UBRR,temp1
	ldi	temp1,(1<<TXEN)|(1<<RXEN) ; initialize UART for TX and RX
	out	UCR,temp1
	ret

;***************************************************************************
;*
;* FUNCTION
;*	getc
;*
;* DESCRIPTION
;*	Wait for start bit and receive a character on the UART Rx line.
;*
;***************************************************************************

getc:
	sbis	USR,RXC		; wait until a character has been received
	rjmp	getc
	in	u_data,UDR	; Read byte from the UART
	ret

;***************************************************************************
;*
;* FUNCTION
;*	putc
;*
;* DESCRIPTION
;*	Send a character on the UART Tx line.
;*
;***************************************************************************

putc:
	sbis	USR,UDRE	; test for TX register empty
	rjmp	putc		; loop until TX empty
	out	UDR,u_data	; send the byte
	ret

;***************************************************************************
;*
;* FUNCTION
;*	put_string
;*
;* DESCRIPTION
;*	Send Z - pointed null-terminated string on the UART Tx line.
;*
;***************************************************************************
	
put_string:
	lpm
	tst	r0
	breq	ps_ret		; check for end of string (0x00)
	mov	u_data,r0
	rcall	putc		; putc(char)
	adiw	ZL,1		; next char
	rjmp	put_string
ps_ret:	ret	

	
;***************************************************************************
;*
;* FUNCTION
;*	put_table
;*
;* DESCRIPTION
;*	Send Z - pointed table on the UART Tx line.
;*
;***************************************************************************
	
put_table:
	lpm
	tst	r0
	breq	pt_ret		; check for end of table (0x00)
	mov	u_data,r0
	rcall	putc		; putc(Byte)
	adiw	ZL,2		; skip MSB
	rjmp	put_table
pt_ret:	ret	

	
;***************************************************************************
;*
;* FUNCTION
;*	bel_table
;*
;* DESCRIPTION
;*	C=0 if device belongs to table.
;*
;***************************************************************************

bel_table:
	lpm			; read table
	tst	r0		; check for end of table
	breq	c1_ret
	cp	device,r0
	breq	c0_ret		; C=0
	adiw	ZL,2		; skip MSB
	rjmp	bel_table	
c1_ret:	sec			; C=1
c0_ret:	ret		

;***************************************************************************
;*
;* FUNCTION
;*	delay
;*
;* DESCRIPTION
;*	 Make delay 1mS (x temp1).
;*
;***************************************************************************

delay:	
	ldi	temp2,40
dl2:	ldi	temp3,(XTAL/120)
dl1:	dec	temp3
	brne	dl1
	dec	temp2
	brne	dl2
	dec	temp1
	brne	delay
	ret

;***************************************************************************
;*
;* FUNCTION
;*	rdser, wrser
;*
;* DESCRIPTION
;*	 Write and read bytes on the SPI.
;*
;***************************************************************************

rdser:	
	clr	s_data
wrser:	
	ldi	temp1,8		; load bit counter
	ldi	rd_s_data,0
wrs0:	rol	s_data
	brcc	wrs1
	set_MOSI		; MOSI = 1
	rjmp	wrs2
wrs1:	clr_MOSI		; MOSI = 0
wrs2:	lsl	rd_s_data
	sbic_MISO		; read MISO
	ori	rd_s_data,1
	pulse_SCK		; pulse SCK
	dec	temp1		; advance bit counter
	brne	wrs0		; loop
	mov	s_data,rd_s_data
	ret

;***************************************************************************
;*
;* FUNCTION
;*	shift_s_data3
;*
;* DESCRIPTION
;*	 Shift s_data 3 times left for S89 device.
;*
;***************************************************************************

shift_s_data3:
	lsl	s_data
	lsl	s_data
	lsl	s_data
	brcc	s3_ret
	cpi	device,0x87	; if (device != S53)
	brne	s3_ret	
	sbr	s_data, 4	; a13 +
s3_ret:	ret

;***************************************************************************
;***************************************************************************
;***************************************************************************
;*
;* INIT
;*
;* DESCRIPTION
;*	Initialization
;*
;***************************************************************************
;***************************************************************************
;***************************************************************************

INIT:
        ldi 	temp1,	RAMEND
        out 	SPL,	temp1	; Locate stack

        ldi		device,	0x20	; S2313 as default
        init_ports				; Initialize ports
        release_ports			; Release ports

		rcall	u_init			; Initialize UART

;***************************************************************************
;*
;* PROGRAM
;*	waitcmd -> main
;*
;* DESCRIPTION
;*	Wait for and execute commands.
;*
;***************************************************************************

waitcmd:
	rcall	getc			; while (getc() == ESC) {};
	cpi		u_data,	0x1b
	breq	waitcmd

;====== 'T' - Device Type ==================================================

	cpi	u_data,'T'	; 'T' Device type
	brne	w0
	rcall	getc
	mov	device,u_data	; get device type
	rjmp	put_ret

;====== 'S' - Return Software Identifier ===================================

w0:	
	cpi	u_data,'S'	; 'S' Return software identifier
	brne	w1
	table	ID_Str
	rcall	put_string	; put string "AVR ISP"
	rjmp	waitcmd

;====== 'V' - Return Software Version ======================================

w1:	
	cpi	u_data,'V'	;'V' Return software version
	brne	w2
	table	SW_Ver
	rcall	put_string	; put software version
	rjmp	waitcmd


;====== 'v' - Return Hardware Version ======================================

w2:	
	cpi	u_data,'v'	;'v' Return hardware version
	brne	w3
	table	HW_Ver
	rcall	put_string	; put hardware version
	rjmp	waitcmd

;====== 't' - Show Supported Devices =======================================

w3:	
	cpi	u_data,'t'	; 't' Show supported devices
	brne	w4
	table	Dev_S
	rcall	put_table	; put supported devices codes
	table	Dev_M
	rcall	put_table	; put supported devices codes
	ldi	u_data,0x00	; putc(0x00) - end of device list
	rcall	putc
	rjmp	waitcmd

;====== 'p' - Return Programmer Type =======================================

w4:	
	cpi	u_data,'p'	; 'p' Return programmer type
	brne	w5
	ldi	u_data,'S'	; putc('S') - serial programmer
	rcall	putc
	rjmp	waitcmd

;====== 'a' - Return autoincrement address support =========================

w5:	
	cpi	u_data,'a'	; 'a' Return address auto increment
	brne	w6
	ldi	u_data,'Y'	; putc('Y') - supports autoinc
	rcall	putc
	rjmp	waitcmd

;====== 'x' - Set LED ======================================================

w6:	
	cpi	u_data,'x'	; 'x' Set LED (ignored)
	brne	w61
	rcall	getc		; get parameter
	rjmp	put_ret

;====== 'y' - Clear LED ====================================================

w61:	
	cpi	u_data,'y'	; 'y' Clear LED (ignored)
	brne	w7
	rcall	getc		; get parameter
	rjmp	put_ret

;===========================================================================

; We require that the device code be selected before any of the other commands

w7:
	table	Dev_S		; load pointer
	rcall	bel_table
	brcc	w71		; device belongs to table
	table	Dev_M	
	rcall	bel_table
	brcc	w71		; device belongs to table
	rjmp	put_err		; not match, goto put_err();

;====== 'P' - Enter Programming Mode =======================================

w71:	
	cpi	u_data,'P'	; 'P' Enter programming mode
	breq	w70
	rjmp	w8
w70:
	cbi		PORTD,	WriteLed							; зажечь светодиод "ПРОГРАММИРОВАНИЕ"
	clr_LED			; LED on
	catch_ports		; catch ports
	clr_SCK			; clear SCK
	pas_RESET		; set RESET passive
	ldi	temp1,50	; delay 50mS;
	rcall	delay
	act_RESET		; set RESET active
	ldi	temp1,50	; delay 50mS;
	rcall	delay
	ldi	s_data,0xac	
	rcall	wrser		; wrser(0xac) SPI write (byte 1)
	ldi	s_data,0x53	
	rcall	wrser		; wrser(0x53) SPI write (byte 2)

				; SPI Synchronization (fix!)
	cpi	device,0x20	; if ( (device >= 0x20) && (device <= 0x7F) )
	brlo	s2
	tst	device
	brmi	s2
				
	ldi	temp3,32	; count = 32;
s1:	rcall	rdser		;             SPI read  (byte 3)
	cpi	s_data,0x53	; if (rdser == 0x53)
	breq	s3		; break
	ldi	s_data,0x00	;		
	rcall	wrser		; wrser(0x00) SPI write (byte 4)
	pulse_SCK		; pulse SCK
	ldi	s_data,0xac		
	rcall	wrser		; wrser(0xac) SPI write (byte 1)
	ldi	s_data,0x53		
	rcall	wrser		; wrser(0x53) SPI write (byte 2)
	dec	temp3		; count-1
	brne	s1		; loop
	rjmp	s3
				; else
s2:	ldi	s_data,0x00	
	rcall	wrser		; wrser(0x00) SPI write (byte 3)
s3:	tst	device
	brmi	s4		; S89 device
	ldi	s_data,0x00	
	rcall	wrser		; wrser(0x00) SPI write (byte 4)

s4:	ldi	temp1,4		; delay 4mS;
	rcall	delay
	rjmp	put_ret

;====== 'c' - Write Program Memory, Low Byte ===============================

w8:	
	cpi	u_data,'c'	; 'c' Write program memory, low byte
	brne	w9
	rcall	getc		; get data byte
	ldi	s_data,0x40
	mov	pol_cmd,s_data	; save command for polling	
	tst	device
	brmi	w81		; S89 device
	rcall	wrser		; wrser(0x40)   SPI write (byte 1)
	mov	s_data,addrh
	rjmp	w82
w81:	mov	s_data,addrh	; s_data = (addrh << 3) | 0x02;
	rcall	shift_s_data3
	ori	s_data,0x02
w82:	rcall	wrser		; wrser(addrh)  SPI write (byte 2)
	mov	s_data,addrl	
	rcall	wrser		; wrser(addrl)  SPI write (byte 3)
	mov	s_data,u_data	
	rcall	wrser		; wrser(u_data) SPI write (byte 4)
	mov	p_data,u_data	; save data for polling
	mov	pol_al,addrl	; save address for polling
	mov	pol_ah,addrh
	tst	device
	brpl	w83 
	adiw	addrl,1		; Auto increment address for S89 device
w83:	rjmp	wait_S		; write FLASH delay

;====== 'C' - Write Program Memory, High Byte ==============================

w9:	
	cpi	u_data,'C'	; 'C' Write program memory, high byte
	brne	w10
	rcall	getc		; get data byte
	tst	device
	brmi	w91		; S89 device
	ldi	s_data,0x48	
	mov	pol_cmd,s_data	; save command for polling	
	rcall	wrser		; wrser(0x48)   SPI write (byte 1)
	mov	s_data,addrh	
	rcall	wrser		; wrser(addrh)  SPI write (byte 2)
	mov	s_data,addrl	
	rcall	wrser		; wrser(addrl)  SPI write (byte 3)
	mov	s_data,u_data	; wrser(u_data) SPI write (byte 4)
	rcall	wrser
	mov	p_data,u_data	; save data for polling
	mov	pol_al,addrl	; save address for polling
	mov	pol_ah,addrh
	adiw	addrl,1		; Auto increment address
	rjmp	wait_S		; write FLASH delay
w91:	rjmp	put_err		; S89 device have byte wide program memory!	

;====== 'R' - Read Program Memory ==========================================

w10:	
	cpi	u_data,'R'	; 'R' Read program memory
	brne	w11

	cbi		PORTD,	ReadLed							; зажечь светодиод "ЧТЕНИЕ"

	tst	device
	brmi	w101		; S89 device
	ldi	s_data,0x28	
	rcall	wrser		; wrser(0x28)  SPI write (byte 1)
	mov	s_data,addrh
	rjmp	w102
w101:	mov	s_data,addrh	; s_data = (addrh << 3) | 0x01;
	rcall	shift_s_data3
	ori	s_data,0x01
w102:	rcall	wrser		; wrser(addrh) SPI write (byte 2)
	mov	s_data,addrl	
	rcall	wrser		; wrser(addrl) SPI write (byte 3)
	rcall	rdser		;              SPI read  (byte 4)
	mov	u_data,s_data
	rcall	putc		; send data

	tst	device
	brmi	w103		; S89 device
	ldi	s_data,0x20	
	rcall	wrser		; wrser(0x20)  SPI write (byte 1)
	mov	s_data,addrh	
	rcall	wrser		; wrser(addrh) SPI write (byte 2)
	mov	s_data,addrl	
	rcall	wrser		; wrser(addrl) SPI write (byte 3)
	rcall	rdser		;              SPI read  (byte 4)
	mov	u_data,s_data
	rcall	putc		; send data

w103:	adiw	addrl,1		; Auto increment address
	sbi		PORTD,	ReadLed							; зажечь светодиод "ЧТЕНИЕ"

	rjmp	waitcmd		; goto waitcmd();

;====== 'A' - Load Address =================================================

w11:	
	cpi	u_data,'A'	; 'A' Load address
	brne	w12
	rcall	getc		; addrh = getc();
	mov	addrh,u_data
	rcall	getc		; addrl = getc();
	mov	addrl,u_data
	rjmp	put_ret		; goto reply();

;====== 'D' - Write Data Memory ============================================

w12:	
	cpi	u_data,0x44	; 'D' Write data memory
	brne	w13
	rcall	getc		; get data
	tst	device
	brmi	w121		; S89 device
	ldi	s_data,0xc0
	rcall	wrser		; wrser(0xc0)   SPI write (byte 1)
	mov	s_data,addrh
	rjmp	w122
w121:	cpi	device,0x87	; if (device == S53)
	breq	w123
	mov	s_data,addrh
	rcall	shift_s_data3
	ori	s_data,0x06
w122:	rcall	wrser		; wrser(addrh)  SPI write (byte 2)
	mov	s_data,addrl
	rcall	wrser		; wrser(addrl)  SPI write (byte 3)
	mov	s_data,u_data
	rcall	wrser		; wrser(u_data) SPI write (byte 4)
	ldi	temp1,10	;delay 10mS
	rcall	delay

	adiw	addrl,1		; Auto increment address
	rjmp	put_ret
w123:	rjmp	put_err

;====== 'd' - Read Data Memory =============================================

w13:	
	cpi	u_data,0x64	; 'd' Read data memory
	brne	w14

	cbi		PORTD,	ReadLed							; зажечь светодиод "ЧТЕНИЕ"

	tst	device
	brmi	w131		; S89 device
	ldi	s_data,0xa0
	rcall	wrser		; wrser(0xa0)   SPI write (byte 1)
	mov	s_data,addrh
	rjmp	w132
w131:	cpi	device,0x87	; if (device == S53)
	breq	w133
	mov	s_data,addrh
	rcall	shift_s_data3
	ori	s_data,0x05
w132:	rcall	wrser		; wrser(addrh)  SPI write (byte 2)
	mov	s_data,addrl	
	rcall	wrser		; wrser(addrl)  SPI write (byte 3)
	rcall	rdser		;               SPI read  (byte 4)
	mov	u_data,s_data
	rcall	putc		; send data

	adiw	addrl,1		; Auto increment address
	sbi		PORTD,	ReadLed							; зажечь светодиод "ЧТЕНИЕ"

	rjmp	waitcmd		; goto waitcmd();

	sbi		PORTD,	ReadLed							; зажечь светодиод "ЧТЕНИЕ"

w133:	rjmp	put_err

;====== 'L' - Leave Programming Mode =======================================

w14:	
	cpi	u_data,'L'	; 'L' Leave programming mode
	brne	w15
	
	sbi		PORTD,	WriteLed							; погасить светодиод "ПРОГРАММИРОВАНИЕ"

	release_ports		; release ports
	pas_RESET		; set RESET passive
	set_LED			; LED off
	rjmp    put_ret

;====== 'e' - Chip Erase ===================================================

w15:	
	cpi	u_data,0x65     ; 'e' Chip erase
        brne	w16
	ldi	s_data,0xac
	rcall	wrser		; wrser(0xac) SPI write (byte 1)
	tst	device
	brmi	w151		; S89 device
	ldi	s_data,0x80
	rcall	wrser		; wrser(0x80) SPI write (byte 2)
w151:	ldi	s_data,0x04
	rcall	wrser		; wrser(0x04) SPI write (byte 3)
	ldi	s_data,0x00
	rcall	wrser		; wrser(0x00) SPI write (byte 4)
	ldi	temp1,40	;delay 40mS
	rcall	delay
	rjmp	put_ret

;====== 'l' - Write Lock Bits ==============================================

w16:	
	cpi	u_data,'l'	; 'l' Write lock bits
	brne	w17
	rcall	getc		; get data
	ldi	s_data,0xac
	rcall	wrser		; wrser(0xac)   SPI write (byte 1)
	tst	device
	brmi	w161		; S89 device
	cpi	device,0x5e	; if (device == tn26)
	breq	w163	
	mov	s_data,u_data 
	andi	s_data,0x06	; (u_data & 0x06) | 0xe0
	ori	s_data,0xe0
	rcall	wrser		; wrser(u_data) SPI write (byte 2)
	ldi	s_data,0x00
	rcall	wrser		; wrser(0x00)   SPI write (byte 3)
	rjmp	w162
w163:	ldi	s_data,0xe0	; tn26 device
	rcall	wrser		; wrser(0xe0)   SPI write (byte 2)
	ldi	s_data,0x00
	rcall	wrser		; wrser(0x00)   SPI write (byte 3)
	mov	s_data,u_data 
	ori	s_data,0xfc
	rcall	wrser		; wrser(u_data) SPI write (byte 4)
	rjmp	w164
w161:	mov	s_data,u_data 
	andi	s_data,0xe0	; S89 device
	ori	s_data,0x07
	rcall	wrser
w162:	ldi	s_data,0x00
	rcall	wrser		; wrser(0x00)   SPI write (byte 4)
w164:	ldi	temp1,10	; delay 10mS
	rcall	delay
	rjmp	put_ret

;====== 's' - Read Signature Bytes =========================================

w17:	
	cpi	u_data,'s'	; 's' Read signature bytes
	brne	w18

	cbi		PORTD,	ReadLed							; зажечь светодиод "ЧТЕНИЕ"


	tst	device
	brmi	w171		; S89 device
	ldi	param1,0x02	; param1 = 0x02
	rcall	ca17
	ldi	param1,0x01	; param1 = 0x01
	rcall	ca17
	ldi	param1,0x00	; param1 = 0x00
	rcall	ca17
	sbi		PORTD,	ReadLed							; зажечь светодиод "ЧТЕНИЕ"
	rjmp	waitcmd
	sbi		PORTD,	ReadLed							; зажечь светодиод "ЧТЕНИЕ"
w171:	rjmp	put_err

ca17:	ldi	s_data,0x30
	rcall	wrser		; wrser(0x30)   SPI write (byte 1)
	ldi	s_data,0x00
	rcall	wrser		; wrser(0x00)   SPI write (byte 2)
	mov	s_data,param1
	rcall	wrser		; wrser(param1) SPI write (byte 3)
	rcall	rdser		;               SPI read  (byte 4)
	mov	u_data,s_data
	rcall	putc		; send data
	ret

;====== 'm' - Write Program Memory Page ====================================

w18:	
	cpi	u_data,'m'	; 'm' Write Program Memory Page
	brne	w19
	ldi	s_data,0x4c	
	rcall	wrser		; wrser(0x4c)  SPI write (byte 1)
	mov	s_data,addrh
	rcall	wrser		; wrser(addrh) SPI write (byte 2)
	mov	s_data,addrl
	rcall	wrser		; wrser(addrl) SPI write (byte 3)
	ldi	s_data,0x00
	rcall	wrser		; wrser(0x00)  SPI write (byte 4)
	rjmp	wait_M		; write FLASH delay

;====== ':' - Universal Command ============================================

w19:	
	cpi	u_data,':'	; ':' Universal Command
	brne	w20
	rcall	getc		; get data1
	mov	cmd1,u_data	; cmd1 = data1
	rcall	getc		; get data2
	mov	cmd2,u_data	; cmd2 = data2
	rcall	getc		; get data3
	mov	cmd3,u_data	; cmd3 = data3
	mov	s_data,cmd1
	rcall	wrser		; wrser(cmd1)  SPI write (byte 1)
	mov	s_data,cmd2
	rcall	wrser		; wrser(cmd2)  SPI write (byte 2)
	mov	s_data,cmd3
	rcall	wrser		; wrser(cmd3)  SPI write (byte 3)
	rcall	rdser		;              SPI read  (byte 4)
	mov	u_data,s_data
	rcall	putc		; send data
	ldi	temp1,50	; delay 50mS
	rcall	delay
	rjmp	put_ret

;====== '.' - New Universal Command ========================================

w20:	
	cpi	u_data,'.'	; '.' New Universal Command
	brne	w21
	rcall	getc		; get data1
	mov	cmd1,u_data	; cmd1 = data1
	rcall	getc		; get data2
	mov	cmd2,u_data	; cmd2 = data2
	rcall	getc		; get data3
	mov	cmd3,u_data	; cmd3 = data3
	rcall	getc		; get data4
	mov	s_data,cmd1
	rcall	wrser		; wrser(cmd1)   SPI write (byte 1)
	mov	s_data,cmd2
	rcall	wrser		; wrser(cmd2)   SPI write (byte 2)
	mov	s_data,cmd3
	rcall	wrser		; wrser(cmd3)   SPI write (byte 3)
	mov	s_data,u_data
	rcall	wrser		; wrser(u_data) SPI write (byte 4)
	mov	u_data,rd_s_data
	rcall	putc		; send data
	ldi	temp1,50	; delay 50mS
	rcall	delay
	rjmp	put_ret
	
;====== Unknown Command ====================================================

w21:	rjmp	put_err

;====== Wait for FLASH write in byte mode ==================================

Wait_S:
	table	Dev_M	
	rcall	bel_table
	brcs	ws_pol		
	rjmp	put_ret		; device belongs to table Dev_M
				; Page mode requires no delay!
ws_pol:	cpi	device,0x13	; if (device == S1200D)
	breq	ws_del		; polling not used (bug!)
	andi	pol_cmd,0x0f	; write command: 0x48, 0x40
	ori	pol_cmd,0x20	; read  command: 0x28, 0x20
	
	clr	temp3		; clear polling counter
ws_cy:	tst	device
	brmi	ws_89		; S89 device
	mov	s_data,pol_cmd	
	rcall	wrser		; wrser(pol_cmd) SPI write (byte 1)
	mov	s_data,pol_ah
	rjmp	ws_90
ws_89:	mov	s_data,pol_ah	; s_data = (pol_ah << 3) | 0x01;
	rcall	shift_s_data3
	ori	s_data,0x01
ws_90:	rcall	wrser		; wrser(pol_ah) SPI write (byte 2)
	mov	s_data,pol_al	
	rcall	wrser		; wrser(pol_al) SPI write (byte 3)
	rcall	rdser		;               SPI read  (byte 4)
	tst	device
	brpl	ws_cb
	andi	s_data,0x80	; compare only MSB for S89 device
	andi	p_data,0x80
ws_cb:	cp	s_data,p_data
	breq	ws_ok		; s_data = p_data
	dec	temp3
	breq	put_err		; 256 polling cycles are over
	rjmp	ws_cy		; loop
	
ws_ok:	tst	temp3		; if s_data = p_data at first cycle, 
	breq	ws_del		; this is "bad" code, polling inapplicable
	rjmp	put_ret
	
ws_del:	ldi	temp1,10	; delay 10mS;
	rcall	delay
	rjmp	put_ret
			
;====== Wait for FLASH write in page mode ==================================

Wait_M:
	cpi	device,0x41
	breq	wm_del		; polling inapplicable for m103
	cpi	device,0x42
	breq	wm_del		; polling inapplicable for m603
	
	andi	pol_cmd,0x0f	; write command: 0x48, 0x40
	ori	pol_cmd,0x20	; read  command: 0x28, 0x20
	
	clr	temp3		; clear polling counter
wm_cy:	mov	s_data,pol_cmd	
	rcall	wrser		; wrser(pol_cmd) SPI write (byte 1)
	mov	s_data,pol_ah
	rcall	wrser		; wrser(pol_ah) SPI write (byte 2)
	mov	s_data,pol_al	
	rcall	wrser		; wrser(pol_al) SPI write (byte 3)
	rcall	rdser		;               SPI read  (byte 4)
	cp	s_data,p_data
	breq	wm_ok		; s_data = p_data
	dec	temp3
	breq	put_err		; 256 polling cycles are over
	rjmp	wm_cy		; loop
	
wm_ok:	tst	temp3		; if s_data = p_data at first cycle, 
	breq	wm_del		; this is "bad" code, polling inapplicable
	rjmp	put_ret
	
wm_del:	ldi	temp1,50	; delay 50mS
	rcall	delay
	rjmp	put_ret

;====== Command Error ======================================================

put_err:
	ldi	u_data,'?'	; putc('?')
	rcall	putc		; send '?'
	rjmp	waitcmd

;====== Reply Command ======================================================

put_ret:
	ldi	u_data,0x0d	; putc(0x0D)
	rcall	putc		; send CR
	rjmp	waitcmd

;***************************************************************************
;*
;* TABLE
;*	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.
;*
;***************************************************************************

Dev_S:	; byte write
	.dw	0x13	;S1200D
	.dw	0x20	;S2313A
	.dw	0x28	;S4414A
	.dw	0x30	;S4433A
	.dw	0x34	;S2333A
	.dw	0x38	;S8515A
	.dw	0x48	;S2323A
	.dw	0x4C	;S2343A
	.dw	0x51	;tn10
	.dw	0x55	;tn12
	.dw	0x56	;tn15
	.dw	0x58	;tn19
	.dw	0x68	;S8535
	.dw	0x6C	;S4434
	.dw	0x86	;S8252
	.dw	0x87	;S53
	.dw	0x00	;End of table
	
Dev_M:	; page write	
	.dw	0x3A	;m8515
	.dw	0x41	;m103
	.dw	0x42	;m603 
	.dw	0x43	;m128
	.dw	0x5E	;tn26
	.dw	0x60	;m161
	.dw	0x64	;m163
	.dw	0x65	;m83
	.dw	0x76	;m8
	.dw	0x72	;m32
	.dw	0x74	;m16
	.dw	0x00	;End of table

;***************************************************************************
;*
;* TABLE
;*	revision codes
;*
;***************************************************************************

SW_Ver:
	.db "32",0
HW_Ver:
	.db "10",0	

;***************************************************************************
;*
;* TABLE
;*	ID string "AVR ISP"
;*
;***************************************************************************

ID_Str:
	.db "AVR ISP",0

;**** End of File ****
