;--------------------------------------------------------------------------------------------------
; Filename         : CLR_ALG.ASM 	  
; Last Modified    : 25 May 2001.
; Version          : 1.0
; Originator       : Texas Instruments, DSP Digital Control Systems Group.
;--------------------------------------------------------------------------------------------------
; Description:
;
; This file contains the implementation of the core algorithm for clearing the LF240x Flash. This
; algorithm is generic to any sector, and performs the pre-erase conditioning for the flash module
; on these parts.
;--------------------------------------------------------------------------------------------------
;--------------------------------------------------------------------------------------------------
; Revision History
; 
; Ver 1.0 (25 May 2001)
; 
;           Comments: Derived from previous source code. Several modifications in place for 
;           enhanced embeddability.
;--------------------------------------------------------------------------------------------------
;--------------------------------------------------------------------------------------------------

             .def  CLEAR_FLASH
            
;--------------------------------------------------------------------------------------------------
; Symbols imported by this file
;--------------------------------------------------------------------------------------------------
            .include "..\include\var.h"
            .include "..\include\rundefs.h"

;--------------------------------------------------------------------------------------------------
; Program sections generated by this file:
; All code in this algorithm implementation is assembled into the named  section 'ALG_Text". 
; Any relocation sensitive code is placed in the named
; section 'CSPL_text'.
;--------------------------------------------------------------------------------------------------
            .sect     "CLR_text"

;--------------------------------------------------------------------------------------------------
; Define macros to set the Flash Mode.
; ACCESS_REGS gives access to the Flash Registers in the Pgm Mem Space and ACCESS_ARRAY  gives 
; access to the Flash ARRAY in Pgm Mem Space.
;--------------------------------------------------------------------------------------------------
ACCESS_REGS        .macro    
                OUT    07fh,0ff0fh        
                .endm

ACCESS_ARRAY    .macro    
                IN    07fh,0ff0fh
                .endm

;--------------------------------------------------------------------------------------------------
; Define Short DELAY loop macro. 
;  This will be used to generate a short delay upto 256 cycles.
;--------------------------------------------------------------------------------------------------
SDELAY          .macro  COUNT
                RPT     COUNT
                NOP
                .endm
;--------------------------------------------------------------------------------------------------
; CLEAR_FLASH:
;
; This function is the user level interface to the  implementation of the clear algorithm for 
; pre-erase conditioning of the TMS320LF2407 flash array.
; This function is desginated as a LEVEL_1 subroutine.
;--------------------------------------------------------------------------------------------------
CLEAR_FLASH:                                    ;Call label for asm client applications.
_clearFlash:                                    ;Call label for C client applications.
    
        .label  ClearAlgoStartMain


        LDP     #flashAlgoVars.ADDR             ;Set the DP to the flash algo vars.

SECTOR_0:
        LACC    flashAlgoVars.SECTOR_CMD        ;Get the sector processing command.
        AND     #000Fh                          ;Mask out unwanted bits.

        BCND    NO_SECTORS,EQ                   ;If no sectors are set, then goto
                                                ;error reporting routine.

        SFR                                     ;Get Bit 0.
        SACL    flashAlgoVars.SECTOR_CMD        ;Store the rest of the command back.
;--------------------------------------------------------------------------------------------------
        BCND    SECTOR_1,NC                     ;If bit 0 is set, clear sector 0.

        SPLK    #0000h,flashAlgoVars.FL_SECST   ;Set up first addr of sector 0.
        SPLK    #0FFFh,flashAlgoVars.FL_SECEND  ;Set up last  addr of sector 0.
        SPLK    #0001h,flashAlgoVars.SECTOR_KEY ;Pass the sector enable key.
        CALL    CLEAR_SECTOR                    ;Call clear_sector to clear sector 0.
;--------------------------------------------------------------------------------------------------
SECTOR_1:
        LACC    flashAlgoVars.SECTOR_CMD        ;Get the sector processing command.
        SFR                                     ;Mask out unwanted bits.
        SACL    flashAlgoVars.SECTOR_CMD        ;Store the rest of the command back.
        BCND    SECTOR_2,NC                     ;If bit 1 is set, clear sector 1.

        SPLK     #1000h,flashAlgoVars.FL_SECST  ;Set up first addr of sector 1.
        SPLK    #3FFFh,flashAlgoVars.FL_SECEND  ;Set up last  addr of sector 1.
        SPLK    #0002h,flashAlgoVars.SECTOR_KEY ;Pass the sector enable key.
        CALL    CLEAR_SECTOR                    ;Call clear_sector to clear
                                                ; Sector 1 if requested
;--------------------------------------------------------------------------------------------------


SECTOR_2:
        LACC    flashAlgoVars.SECTOR_CMD        ;Get the sector processing command.
        SFR                                     ;Mask out unwanted bits.
        SACL    flashAlgoVars.SECTOR_CMD        ;Store the rest of the command back.
        BCND    SECTOR_3,NC                     ;If bit 2 is set, clear sector 2.

        SPLK    #4000h,flashAlgoVars.FL_SECST   ;Set up first address of sector 2.
        SPLK    #6FFFh,flashAlgoVars.FL_SECEND  ;Set up last address of sector 2.
        SPLK    #0004h,flashAlgoVars.SECTOR_KEY ;Pass the sector enable key.
        CALL    CLEAR_SECTOR                    ;Call clear_sector to clear sector 2.

SECTOR_3:
        LACC    flashAlgoVars.SECTOR_CMD        ;Get the sector processing command.
        SFR                                     ;Mask out unwanted bits.
        SACL    flashAlgoVars.SECTOR_CMD        ;Store the rest of the command back.
        BCND    SECTORS_DONE,NC                 ;If bit 3 is set, clear sector 3.

        SPLK    #7000h,flashAlgoVars.FL_SECST   ;Set up first address of sector 3.
        SPLK    #7FFFh,flashAlgoVars.FL_SECEND  ;Set up last address of sector 3.
        SPLK    #0008h,flashAlgoVars.SECTOR_KEY ;Pass the sector enable key.
        CALL    CLEAR_SECTOR                    ;Call clear_sector to clear sector 3.

SECTORS_DONE:
        SPLK    #0,flashAlgoVars.ALGO_STATUS    ;No errors encountered.
        RET

NO_SECTORS:
        SPLK    #10,flashAlgoVars.ALGO_STATUS   ;No sectors specified for clear.
        RET

ERROR1: 
;--------------------------------------------------------------------------------------------------
;   IMPORTANT NOTE:
;
;   This code is executed in LEVEL_3, during a call to CLR_LOOP (which is a LEVEL_3 routine).
;   This routine is returning control to the LEVEL_0 (Caller's level). So it is performing the
;   function of a LEVEL_1 routine.
;   So, It is EXTREMELY important that this routine adjust the stack depth by the proper amount.
;   This routine must therefore remove two (2) words from the stack.
;--------------------------------------------------------------------------------------------------
        POPD    flashAlgoVars.PAD               ;Adjust stack depth 1.
        POPD    flashAlgoVars.PAD               ;Adjust stack depth 2.

        SPLK    #1,flashAlgoVars.ALGO_STATUS    ;Error encountered in CLEAR.
        RET

;--------------------------------------------------------------------------------------------------
; CLEAR_SECTOR:
;
; This function is the implementation of the clear algorithm for the pre-erase preconditioning of 
; the flash array. This function is desginated as a LEVEL_2 subroutine.
;--------------------------------------------------------------------------------------------------
CLEAR_SECTOR:
;--------------------------------------------------------------------------------------------------
; Enable the flash for programming:
; To accept programming commands the following must happen:
;   1. Place the flash in the register mode.
;   2. Copy the sector key to the SECT register.
;   3. Enable the core by setting Bit 0 of the ENAB Register
;--------------------------------------------------------------------------------------------------
ENABLE: ACCESS_REGS                               ;Put the flash in register mode.
        LACC    #SECT                             ;Enable sector.

        BLDD    #flashAlgoVars.SECTOR_KEY,flashAlgoVars.PAD
        TBLW    flashAlgoVars.PAD    

        LACC    #ENAB                             ;Enable core.
        SPLK    #0001h,flashAlgoVars.PAD          ;
        TBLW    flashAlgoVars.PAD                 ;
;--------------------------------------------------------------------------------------------------
;  Next, the following steps are performed
;  1. DATA is set to 0000h for use in the compare stage, since in clear the flash is set to all 
;     words = 0000h.
;  2. Calls the Level 2 routine CLR_LOOP to clear the sector user space.
;  3. Calls the Level 2 routine CLR_LOOP to clear the sector base space.
;     This clears out any bits in the base sector space that were not  mapped into the user space.
;  4. It then calls the Level2 routine CLR_LOOP to clear the redundant 
;     row bits, that were not mapped into the user space.
;--------------------------------------------------------------------------------------------------
        SPLK    #0000h,flashAlgoVars.DATA       ;Load 0000h for compare.
        SPLK    #0000h,flashAlgoVars.FL_CMD     ;Setup the routine to address the base space.
        SPLK    #0001H,flashAlgoVars.FAIL_CMD   ;Setup the routine to fail if any bits in 
                                                ;the user space fail to clear.
        CALL    CLR_LOOP                        ;Call the CLR_Loop routine to clear 
                                                ;the user space.

        LACC    flashAlgoVars.SECTOR_KEY        ;Get the sector key.
        AND     #0006H                          ;Mask out bits for sectors 0 and 3.
        BCND    NO_RED_CLEAR,EQ                 ;Perform NOROWRED and PRECON steps only
                                                ;for sectors 1 and 2.

        SPLK    #0080h,flashAlgoVars.FL_CMD     ;Setup the NOROWRED mode.
        SPLK    #0000H,flashAlgoVars.FAIL_CMD   ;Set up the routine to ingnore failure of
                                                ;bits to program on MX_PCNT pulses.
        CALL    CLR_LOOP                        ;Clear the base sector space (NOROWRED)

        SPLK    #0100h,flashAlgoVars.FL_CMD     ;Setup the redundancy precondition mode.
        SPLK    #0000H,flashAlgoVars.FAIL_CMD   ;Set up the routine to ingnore failure of
                                                ;bits to program on MX_PCNT pulses.
        CALL    CLR_LOOP                        ;Call the CLR_Loop routine to clear 
                                                ;the redundant bits.
NO_RED_CLEAR:
        CALL     END1
        RET

;--------------------------------------------------------------------------------------------------
;   CLR_LOOP:
;--------------------------------------------------------------------------------------------------
;   This function is desginated as a LEVEL_3 subroutine.
;--------------------------------------------------------------------------------------------------
;   This function is the implementation for the clear loop. It reads the flash one word at a 
;   time in PROGVER mode. It then compares this word to the word in DATA. In case of the this
;   algo, it is always  0000h. If then goes processes the next word if it is already zero, 
;   else it enters BITMASK to form the bitmask for applying programming pulses to the Flash array.
;--------------------------------------------------------------------------------------------------
CLR_LOOP:
        SPLK    #MX_PCNT,flashAlgoVars.PLS_CNT  ;Initialize the program pulse count. 
        BLDD    #flashAlgoVars.FL_SECST,flashAlgoVars.ADDR        
                                                ;Initialize the address counter.

PGVERON:
        LACC    #WADDR                          ;Load the WADDR Register with the address of
        CALL    SETWADDR                        ;the word to be programmed.

        LACC    flashAlgoVars.FL_CMD            
        XOR     #0004h                          ;(PROGVER Command)Program Verification Command.
        SACL    flashAlgoVars.PAD                        

        LACC    #CTRL                           ;Enter the PROGVER mode.
        TBLW    flashAlgoVars.PAD
        SDELAY  #T_pvsu                         ;Wait for T_pvsu(P)

        LACC    #PMPC                
        SPLK    #0005h,flashAlgoVars.PAD
        TBLW    flashAlgoVars.PAD               ;Activate the PGVER Mode by writing to 
                                                ;PMPC.
        SDELAY   #T_pva_e                       ;Wait T_pva(E) 
        CALL     READWORD
    
PGVEROFF:
        SPLK    #0000h,flashAlgoVars.PAD1       ;Clear out PMPC.
        CALL    CLRCMD                          ;

        SDELAY  #Tpv_h_P                        ; Wait for Program verify hold time

        SPLK    #0001h,flashAlgoVars.PAD1       ;Clear out PMPC and CTRL
        CALL    CLRCMD                          ;Since PMPC is cleared already, it is unchanged.

        SDELAY  #Tpv_h_C                        ;Hold the normal read mode.


COMPARE:
        LACC    flashAlgoVars.READ              ;Get the value of the word read out during
                                                ;Program Verify.
        OR      #0000h                          ;OR this value with 0000h
        BCND    NEXTWORD,EQ                     ;If == 0000h then this word (*ADDR) is
                                                ;programmed, process the next word.
;--------------------------------------------------------------------------------------------------
; BITMASK:
;       This section forms the bitmask to write to the WDATA register.
;       READ contains the value read during program verify above,
;       and this is used to build the mask.
;       Once the mask is built, the sub-routine PROG is called.
;--------------------------------------------------------------------------------------------------
; Notes on building the mask:
;
; ** IMPORTANT: This mask building assumes processing is always to clear the 
; **             flash, i.e. the end value in the flash is assumed to be 0000h.
; **
; 
; This works as follows:
;       1.  Get the value read out during program verify.
;        2. Any bits that are 0s should not get any more pulses.  While any bits that are 1s 
;           should get pulses.
;        3. To apply pulses bits in the WDATA register should be 0s.
;        4. XOR the read value with 0ffffh. This inverts all bits in the read value. So bits that
;           are 0s send 1s in the corresponding bits in WDATA and bits that are 1s send 0s in the
;           corresponding bits in WDATA.
;        5. This ensures that prog applied pulses to those bits read out as 1s.
;--------------------------------------------------------------------------------------------------
        LACC    flashAlgoVars.READ              ;Get the value read during program verify
        XOR     #0ffffh                         ;Acc has the bits now to be written to WDATA.
        SACL    flashAlgoVars.DATA,0            ;Store acc in flashAlgoVars.DATA
        CALL    PROG                            ;Call the PROGRAM routine, that applies the
                                                ;pulses.
;--------------------------------------------------------------------------------------------------
; PGCNT: Program Pulse Count Advance / Check:
;        1. Advance the pulse counter.
;        2. Check the pulse counter to see if this has exceeded limits.          
;        3. Error handling if (2) is true.
;--------------------------------------------------------------------------------------------------
PGCNT:  LACC    flashAlgoVars.PLS_CNT           ;Decrement the pulse counter
        SUB     #1                              ;
        SACL    flashAlgoVars.PLS_CNT           ;Pulse counter now has remaining 
                                                ;pulses allowable.
                                    
        BCND    CHK_IF_FAIL,EQ                  ;If zero then the pulse count is exceeded,
                                                ;enter error handling,
        B        PGVERON                        ;verify word programmed
;--------------------------------------------------------------------------------------------------
CHK_IF_FAIL:                                    ; If here then MAX_PCNT pulses have been 
                                                ; applied. So, check the fail command.
        LACL    flashAlgoVars.FAIL_CMD          ; Get the FAIL_CMD passed from caller.
        BCND    ERROR,NEQ                       ; If non-zero begin error handling.
        B       NEXTWORD                        ; If fail command is zero, then the 
                                                ; caller intended to allow programming
                                                ; failures. So continue the flow.
ERROR:  CALL    END1
        B       ERROR1

;--------------------------------------------------------------------------------------------------
; NEXTWORD
; This block does the following things:
;   1.  Checks if the ADDR is at the last address in the sector.
;   2.  If not, increments ADDR.
;   3.  Sets up program pulse count for programming the next word.
;--------------------------------------------------------------------------------------------------
NEXTWORD:

        LACL    flashAlgoVars.ADDR              ;ACC = (address of previous word programmed).
        SUB     flashAlgoVars.FL_SECEND         ;ACC = (prev word addr) - (last address of sector)
        BCND    NW,NEQ                          ;If there is a match end the routine,
        RET                                     ;otherwise continue with the next word.

NW      LACL    flashAlgoVars.ADDR              ;ACC = (address of previous word programmed).
        ADD     #1                              ;INCREMENT ADDR
        SACL    flashAlgoVars.ADDR              ;STORE ADDR OF NEXT WORD

        SPLK    #MX_PCNT,flashAlgoVars.PLS_CNT  ;Initialize PROGRAM PULSE COUNT 
        B       PGVERON                         ;begin prog of next word


;--------------------------------------------------------------------------------------------------
; PROG: Program subroutine.
;--------------------------------------------------------------------------------------------------
; This is a LEVEL4 subroutine.
;--------------------------------------------------------------------------------------------------
;       
;    1.     This subroutine applies programming pulses to the flash word based on
;        the bitmask built by the caller and placed in flashAlgoVars.DATA.
;
;    2.  The pulses are applied to the main array or the redundant rows depending  
;          on the status of flashAlgoVars.FL_CMD.
;        FL_CMD = 0080h (NOROWRED) programs the bits in the main array.
;        FL_CMD = 0100h (PRECON).
;--------------------------------------------------------------------------------------------------
PROG    LACC    #WDATA                          ;Load data to be prog
        TBLW    flashAlgoVars.DATA              ;Write data to the WDATA register.

        LACC    flashAlgoVars.FL_CMD            ;Get the flash command.
        XOR     #0003h                          ;Add in the bits for the PROG mode.
        SACL    flashAlgoVars.PAD

        LACC    #CTRL                           ;Init prog mode 
        TBLW    flashAlgoVars.PAD            
        SDELAY  #T_psu_p                        ;Wait T_psu(P)

        LACC    #PMPC                           ;Turn on prog voltages
        SPLK    #0005h,flashAlgoVars.PAD    
        TBLW    flashAlgoVars.PAD

PPW     SDELAY  #T_prog_e1                      ;PROG pulse width part 1
        SDELAY  #T_prog_e2                      ;PROG pulse width part 2

        SPLK    #0000h,flashAlgoVars.PAD        ;Turn off PROG Voltages.
        TBLW    flashAlgoVars.PAD

        SDELAY  #Tph_P                          ;Wait T_ph(P)     (HOLD TIME).

        SPLK    #0001h,flashAlgoVars.PAD1       ;Clear PMPC and CTRL.
        CALL    CLRCMD                          ;Since PMPC is 0s already from above,
                                                ;really the only thing affected is CTRL

        SDELAY  #Tph_A                          ;Wait in normal read mode.


        RET                                     





;--------------------------------------------------------------------------------------------------
; READWORD
; This routine performs the following operations
;    1. Reads the word at the location pointed to by flashAlgoVars.ADDR.
;    2. Stores the word in the variable READ.
;    3. Returns to the caller in Register Mode.
;    This is a LEVEL4 subroutine.
;--------------------------------------------------------------------------------------------------
READWORD:
        ACCESS_ARRAY
        LACC    flashAlgoVars.ADDR              ;Read word flash 
        TBLR    flashAlgoVars.READ              ;store word in READ (data space)
        ACCESS_REGS
        RET
;--------------------------------------------------------------------------------------------------
;    END1:                                       
;     This routine performs the following operations
;   1.  Clears the control registers PMPC,CNTL,WADDR,WDATA,ENABLE AND SECTOR)
;   2.  Returns to the caller in ARRAY Mode.
;--------------------------------------------------------------------------------------------------
END1:   SPLK    #0006h,flashAlgoVars.PAD1       ;CLEAR ALL SIX 
        CALL    CLRCMD
        ACCESS_ARRAY
        RET

;--------------------------------------------------------------------------------------------------
; CLRCMD
;--------------------------------------------------------------------------------------------------
;     This routine performs the following operations
;   1.  Places the flash in normal read mode by writing 0000 to two control 
;       registers PMPC=0000,CNTL=0000.
;   2.  Returns to the caller in Register Mode.
;--------------------------------------------------------------------------------------------------
CLRCMD: ACCESS_REGS
        SPLK    #0,flashAlgoVars.PAD
        LACC    #0
        RPT     flashAlgoVars.PAD1
        TBLW    flashAlgoVars.PAD
        RET

        .label  ClearAlgoEndMain

        .sect    "CSPL_text"
SETWADDR:
        .label  ClearAlgoStartSpl
        TBLW    flashAlgoVars.ADDR              ;Perform the write to the address register.
        RET
        .label  ClearAlgoEndSpl


