;************************************************************
;* PROGRAM Subroutine					   **
;							   **
; TMS320F2XX Flash Utilities.				   **
;							   **
; Filename: PRG24_X1.ASM				   **
; Changes: Re-written to include latest flash algorithms.  **
;							   **
;		 DSP Applications			   **
;		 Texas Instruments Inc. 		   **
;							   **
;   03 Nov 97 - Optimised code to strip out approx 30	   **
;		words to enable this algorithm to share    **
;		256 words in B0 together with the F240	   **
;		Serial Boot loader Comms kernel +	   **
;		sequencer s/w.				   **
; 11/30/1999						   **
;Changes20b: Changed conditional branch on line 194 near   **
;            row-done label from GEQ to GT, to prevent     **
;            skipping of last address on sections that end **
;            with a mult of 32d address (020h,040h,etc.)   **
;							   **
; Called by : c2xx_bpx.asm or flash application programs.  **
;							   **
; !!CAUTION - INITIALIZE DP BEFORE CALLING THIS ROUTINE!!  **
;							   **
; Function  : This routine programs all or part of the	   **
;	      flash as specified by the variables:	   **
;	       PRG_paddr - Destination start address.	    *
;	       PRG_length - Source buffer length.	    *
;	       PRG_bufaddr - Source buffer start address.   *
;							    *
; The algorithm used is "row-horizontal" which means that   *
; an entire flash row (32 words) are programed in parallel. *
; This method provides better uniformity of programming     *
; levels between adjacent bits then if each address were    *
; programed independently. The algorithm also uses a 3-read *
; check for VER0 margin (i.e. The flash location is read    *
; three times and the first two values are discarded.) This *
; provides low-freq read-back margin on programed bits. For *
; example, if the flash is programmed using a CLKOUT period *
; of 50ns, the flash can be reliably readback over the	    *
; CLKOUT period range of 50ns to 150ns (6.67Mhz-20Mhz).     *
; The programming pulse-width is 100us, and a maximum of    *
; 150 pulses are applied per row.			    *
;							    *
; The following variables are used for temp storage:	    *
;	 AR0  - Used for comparisons.			    *
;	 AR1  - Used for pgm pulse count.		    *
;	 AR2  - Used for row banz loop. 		    *
;	 AR3  - Used for buffer addr index.		    *
;	 AR4  - Used for flash address. 		    *
;	 AR6  - Parameter passed to Delay.		    *
;	SPAD1 - Flash program and STOP commands.	    *
;	SPAD2 - Flash program + EXE command.		    *
;     FL_ADRS - Used for flash address. 		    *
;     FL_DATA - Used for flash data.			    *
;	 B2_0 - Used for row-done flag. 		    *
;	 B2_1 - Used for row start address.		    *
;	 B2_2 - Used for row length-1.			    *
;	 B2_3 - Used for buffer/row start addr. 	    *
;	 B2_4 - Used for destination end addr.		   **
;	 DLY10	- Used for Delay repeat counter (DAF)
;	 DLY100 - Used for Delay repeat counter (DAF)
;	 DUMMY - Dummy variable
;************************************************************

	.include "svar2x.h"

MAX_PGM .set    150        ;Only allow 150 pulses per row.
VER0    .set    010h       ;VER0 command.
WR_CMND .set    4          ;Write command.
WR_EXE  .set    045h       ;Write EXEBIN command.
STOP    .set    0          ;Reset command.

	.def	PROGRAM

;	.ref	PRG_bufaddr,PRG_length,PRG_paddr
;	.ref	PROTECT
;	.ref	DELAY,REGS,ARRAY

	.sect ".alg"

;GPGMJ:  SPLK	 #0,IMR 	;MASK ALL INTERRUPTS  - (DAF)
;	SETC	INTM		;GLOBALLY MASK ALL INTERRUPTS
;	CALL	PROGRAM 	;Program flash.

************************************************
* PROGRAM: This routine programs all or part of*
* the flash as specified by the variables:     *
*   PRG_paddr - Destination start address.     *
*  PRG_length - Source buffer length.          *
* PRG_bufaddr - Buffer start address.          *
*                                              *
* The following variables are used for temp    *
* storage:                                     *
*        AR0  - Used for comparisons.          *
*        AR1  - Used for pgm pulse count.      *
*        AR2  - Used for row banz loop.        *
*        AR3  - Used for buffer addr index.    *
*     FL_ADRS - Used for flash address.        *
*     FL_DATA - Used for flash data.           *
*        B2_0 - Used for row-done flag.        *
*        B2_1 - Used for row start address.    *
*        B2_2 - Used for row length-1.         *
*        B2_3 - Used for buffer/row start addr.*
*        B2_4 - Used for destination end addr. *
************************************************
PROGRAM
        LACL    PRG_paddr               ;Get destination start address.
        SACL    FL_ADRS                 ;Save as current address.

        ADD     PRG_length              ;Determine destination end addr.
        SUB     #1                      ;
        SACL    B2_4                    ;Save destination end addr.
        LACL    PRG_paddr               ;Get destination start addr.

        LAR     AR3,PRG_bufaddr         ;Get buffer start address.
********Begin a new row.*
NEWROW
        SACL    B2_1                    ;Save row start address.
        SAR     AR3,B2_3                ;Save buffer/row start address.
        LAR     AR1,#0                  ;Init pulse count to zero.
        SPLK    #31,B2_2                ;Init row length-1 to 31.
        AND     #001Fh                  ;Is start addr on row boundary?
        CC      ADJ_ROW,NEQ             ;If not then adjust row length.
        LACL    B2_1                    ;Get row start address.
        OR      #001Fh                  ;Get row end address.
        SUB     B2_4                    ;Is end address on row boundary?
        CC      ADJ_ROW,GT              ;If not then adjust row length.
********Same row, next pulse.*
SAMEROW
        SPLK    #1,B2_0                 ;Set row done flag = 1(True).
        LACL    B2_1                    ;Get row start address.
        SACL    FL_ADRS                 ;Save as current address.
        LAR     AR3,B2_3                ;Get buffer/row start addr. 
        LAR     AR2,B2_2                ;Init row index.
********Repeat the following code 32 times or until end of row.*
********First do low-byte.*

LOBYTE	SPLK	#0FFh, BYTE_MASK	;Prepare mask for low byte
	CALL	PRG_BYTE
HIBYTE	SPLK	#0FF00h, BYTE_MASK	;Prepare mask for Hi byte
	CALL	PRG_BYTE

;LOBYTE
;	CALL	SET_MODULE,AR4		;Determine which flash module.
;	CALL	SET_RD_VER0		;Read word at VER0 level.
;	MAR	*,AR3			;ARP -> buffer addr index.
;	LACL	*			;Get word to program.
;	XOR	FL_DATA 		;Xor with read-back value.
;	AND	#0FFh			;Mask off hi-byte mask.
;	BCND	HIBYTE,EQ		;If zero then done.
;	XOR	#0FFFFh 		;else, mask off good bits.
;	SACL	FL_DATA 		;New data.
;	CALL	EXE_PGM 		;PGM Pulse.
;	SPLK	#0,B2_0 		;Set row done flag = 0(False).
********Now do hi-byte.*
;HIBYTE
;	CALL	SET_RD_VER0		;Read word at VER0 level.
;	MAR	*,AR3			;ARP -> buffer addr index.
;	LACL	*			;Get word to program.
;	XOR	FL_DATA 		;Xor with read-back value.
;	AND	#0FF00h 		;Mask off lo-byte mask.
;	BCND	NEXTWORD,EQ		;If zero then done.
;	XOR	#0FFFFh 		;else, mask off good bits.
;	SACL	FL_DATA 		;New data.
;	CALL	EXE_PGM 		;PGM Pulse.
;	SPLK	#0,B2_0 		;Set row done flag = 0(False).
********************

NEXTWORD
        LACL    FL_ADRS                 ;Load address for next word.
        ADD     #1                      ;Increment address.
        SACL    FL_ADRS                 ;Save as current address.
        MAR     *, AR3                  ;ARP -> buffer addr index.
        MAR     *+,AR2                  ;Inc, and ARP -> row index.
        BANZ    LOBYTE                  ;Do next word,and dec AR2.
********Reached end of row. Check if row done. *
        BIT     B2_0,15                 ;Get row_done flag.
        BCND    ROW_DONE,TC             ;If 1 then row is done.
        MAR     *,AR1                   ;Else, row is not done, so
        MAR     *+                      ;inc row pulse count.
        LAR     AR0,#MAX_PGM            ;Check if passed allowable max.
        CMPR    2                       ;If AR1>MAX_PGM then
        BCND    EXIT,TC                 ;fail, don't continue.
        B       SAMEROW                 ;else, go to beginning
                                        ;of same row.
********If row done then check if Array done. *
ROW_DONE
        LACL    FL_ADRS                 ;Check if end of array.
        SUB     B2_4                    ;Subtract end addr.
        BCND    DONE, GT                ;If >0 then done.
********Else, goto next row. *
        LACL    FL_ADRS
        B       NEWROW                  ;Start new row.
;DONE					;(DAF)
;	RET

;FINISHED

DONE	CALL	 ARRAY			 ;ACCES FLASH IN ARRAY MODE.
;DONE	IN	DUMMY, F24X_ACCS   ;Set Array mode (DAF)
        RET

;-------------------------------------------------
;Programs Hi or Lo byte depending on the BYTE_MASK
;-------------------------------------------------
PRG_BYTE:
	CALL	SET_RD_VER0		;Read word at VER0 level.
	MAR	*,AR3			;ARP -> buffer addr index.
	LACL	*			;Get word to program.
	XOR	FL_DATA 		;Xor with read-back value.
	AND	BYTE_MASK		;Mask off appropriate byte
	BCND	PB_END,EQ		;If zero then done.
	XOR	#0FFFFh 		;else, mask off good bits.
	SACL	FL_DATA 		;New data.
	CALL	EXE_PGM 		;PGM Pulse.
	SPLK	#0,B2_0 		;Set row done flag = 0(False).
PB_END	RET


************************************************
* ADJ_ROW: This routine is used to adjust the  *
* row length, if the start or end address of   *
* code being programed does not fall on a row  *
* boundary. The row length is passed in the    *
* B2_2 variable, and the adjustment value to   *
* be subtracted is passed in the accumulator.  *
************************************************
ADJ_ROW
        CMPL                            ;Take ones complement.
        ADD     #1                      ;Take twos complement.
        ADD     B2_2                    ;Add row length.
        SACL    B2_2                    ;Save new row length.
        RET

;***********************************************
; SET_MODULE: This routine is used to point to *
; the appropriate flash array control register.*
; The variable FL_ST is returned with the      *
; correct register address.		       *
; The following temporary resources are used:  *
;	 AR0  - Used for comparisons.	       *
;	 AR4  - Used for flash address.        *
;***********************************************
;SET_MODULE	(DAF)
;	LAR	AR4,FL_ADRS	;AR4 = current address.
;	SPLK	#0,FL_ST	;FL_ST	= FLASH0 CTRL REGS
;	LAR	AR0,#4000H	;AR0 = compare value.
;	CMPR	1		;If AR4 < AR0 then
;				;FL_ADRS < 4000H; SET TC
;	BCND	FL0,TC		;Address is in FL0.
;				;Else address is in FL1.
;	SPLK	#04000h,FL_ST	;FL_ST = FLASH1 CTRL REGS
;FL0	 RET



************************************************************
* THIS SECTION PROGRAMS THE VALUE STORED IN FL_DATA INTO   *
* THE FLASH ADDRESS DEFINED BY FL_ADRS.                    *
*							   *
* The following resources are used for temporary storage:  *
*        AR6  - Parameter passed to Delay.                 *
*       SPAD1 - Flash program and STOP commands.           *
*       SPAD2 - Flash program + EXE command.               *
************************************************************
EXE_PGM 			;			   *
*							   *
;	IN	DUMMY, F24X_ACCS   ;Set Array mode
	CALL	ARRAY		;ACCESS ARRAY (DAF)	   *


* LOAD WADRS AND WDATA					  **
        LACL    FL_ADRS         ;ACC => PROGRAM ADRS       *
        TBLW    FL_DATA         ;LOAD WADRS AND WDATA      *


;	OUT	DUMMY, F24X_ACCS   ;Set Reg mode
	CALL	REGS		;ACCESS FLASH REGS (DAF)   *
* SET-UP WRITE COMMAND WORDS				  **
        LACL    PROTECT         ;GET SEGMENT PROTECT MASK **
        OR      #WR_CMND        ;OR IN WRITE COMMAND      **
        SACL    SPAD1           ;SPAD1 = WRITE COMMAND    **
        OR      #WR_EXE         ;OR IN EXEBIN COMMAND     **
        SACL    SPAD2           ;SPAD2 = WRITE EXE COMMAND**
        LACL    FL_ST           ;ACC =>  (FLASH)           *
*							   *
* ACTIVATE WRITE BIT					  **
        TBLW    SPAD1           ;EXECUTE COMMAND          **
;	LAR	AR6,#D10	;SET DELAY (DAF)	  **
;	CALL	DELAY,*,AR6	;WAIT			  **
	RPT	DLY10		;
	NOP
* SET EXEBIN BIT					 ***
        TBLW    SPAD2           ;EXECUTE COMMAND         ***
;	LAR	AR6,#D100	;SET DELAY (DAF)	 ***
;	CALL	DELAY,*,AR6	;WAIT			 ***
	RPT	DLY100		;
	NOP
* STOP WRITE OPERATION					   *
        SPLK    #0,SPAD1        ;SHUTDOWN WRITE OPERATION  *
        TBLW    SPAD1           ;EXECUTE COMMAND           *
        TBLW    SPAD1           ;EXECUTE COMMAND           *
;	LAR	AR6,#D10	;SET DELAY (DAF)	   *
;	CALL	DELAY,*,AR6	;WAIT			   *
	RPT	DLY10		;
	NOP
	RET		;RETURN TO CALLING SEQUENCE	   *
************************************************************

***********************************************************
* ACTIVATE VER0 ON FLASH READS				  *
* LOADS FLASH WORD AT ADDR FL_ADRS TO FL_DATA.            *
* Uses SPAD1 for temporary storage of flash comands.      *
***********************************************************
SET_RD_VER0			;

	CALL	REGS		;ACCESS FLASH REGISTERS (DAF)
;	OUT	DUMMY, F24X_ACCS   ;Set Reg mode
	LACL	FL_ST		;ACC => FLASH
	SPLK	#VER0,SPAD1	;ACTIVATE VER0
	TBLW	SPAD1		;EXECUTE COMMAND
;	LAR	AR6,#D10	;SET DELAY (DAF)
;	CALL	DELAY,*,AR6	;WAIT
	RPT	DLY10		;
	NOP

	CALL	ARRAY		;ACCESS FLASH ARRAY (DAF)
;	IN	DUMMY, F24X_ACCS   ;Set Array mode

	LACL	FL_ADRS 	;POINT TO ADRS
	TBLR	FL_DATA 	;GET FLASH WORD 1x read
	TBLR	FL_DATA 	; 2x read
	TBLR	FL_DATA 	; 3x read

;	OUT	DUMMY, F24X_ACCS   ;Set Reg mode
	CALL	REGS		;ACCESS FLASH REGISTERS

	LACL	FL_ST		;ACC => FLASH
	SPLK	#STOP,SPAD1	;DEACTIVATE VER0
	TBLW	SPAD1		;EXECUTE COMMAND
;	LAR	AR6,#D10	;SET DELAY (DAF)
;	CALL	DELAY,*,AR6	;WAIT
	RPT	DLY10		;
	NOP
	CALL	ARRAY		;ACCESS FLASH ARRAY (DAF)
;	IN	DUMMY, F24X_ACCS   ;Set Array mode
	RET		;RETURN TO CALLING SEQUENCE
***********************************************************



********If here then unit failed to program. *
EXIT    SPLK    #1,ERROR        ;Update error flag.
;	B	FINISHED	;Get outa here.
	B	DONE		;Get outa here. (DAF)

ARRAY:	IN	DUMMY, F24X_ACCS

;	LDP	#0E0H
;	SPLK	#0,7018H
;	LDP	#6
	RET

REGS:	OUT	DUMMY, F24X_ACCS
;	LDP	#0E0H
;	SPLK	#0800H,7018H
;	LDP	#6
	RET


        .end

        
