; DP512 FLASH Erase/Write/Read Absolute assembly code
; This code uses only far addresses for flash E/W.
; - It means always use PPAGE and Offset addresing mode
; - In order to be able to use also nonpaged space addresable by means of 
;   short address the code must be adjusted or there is possibility
;   to use this mode but PPAGE must be set to $3F.
; - Also some error codes are not used. For example:
;   - result (written) value is not tested  - FLASHerrRANGE
;   - range of the address is not tested    - FLASHerrVALUE
;
; - Functions ReadFarWord, WriteWordFar, CopyWaitForFlashROMtoRAM
;   must be in nonpaged memory.
; - Functions FlashEraseSector, FlashWriteWord should be in nonpaged
;   memory because they are finished by RTS
;*****************************************************************

; export symbols
            XDEF Entry            ; export 'Entry' symbol
            ABSENTRY Entry        ; for absolute assembly: mark this as application entry point

; include derivative specific macros
            INCLUDE 'mc9s12dp512.inc'

ROMStart    EQU  $C000  ; absolute address to place my code/constant data


;---------------------------------
; flash error codes
;---------------------------------
FLASHblocks           EQU   4
FLASHsectorSize       EQU   1024
FlashPagesPerBlock    EQU   8

FLASHerrOK:           EQU   0     ; OK
FLASHerrRANGE:        EQU   1     ; address is out of range
FLASHerrVALUE:        EQU   2     ; Read value is not equal to written value
FLASHerrNOTAVAIL:     EQU   3     ; Desired program/erase operation is not available
FLASHerrBUSY:         EQU   4     ; Flash is busy
ERR_NOTAVAIL:         EQU   5     ; Requested value or method not available.
;---------------------------------
; variable/data section
;---------------------------------
            ORG RAMStart
CCRbackup         DS.B 1          ; stores CCR while required
FLASHreturnCode   DS.B 1          ; flash error return code
WaitForFlashInRam DS.B 30         ; allocate space for RAM function

pg                DS.B 1          ; stores address page
off               DS.W 1          ; stores address offset
farWord           DS.W 1          ; stores Word value

temp              DS.B 1
;---------------------------------
; Code section
;---------------------------------
            ORG   ROMStart
;---------------------------------
; Get CCR; disbal I-bit maskable interrupts
;---------------------------------
GetCCRdisableI:
            TPA
            STAA CCRbackup
            SEI
            RTS 
;---------------------------------
; Restore CCR after Get CCR
;---------------------------------
RestoreCCR:
            LDAA CCRbackup
            TAP;
            RTS
;---------------------------------
; Routine for Waiting for flash 
; Modifies: FLASHreturnCode
; The function must be run from RAM durin Flash E/W processing
; To copy it the function CopyWaitForFlashROMtoRAM is used
;---------------------------------
WaitForFlashinROM:
            
            MOVB #$80,FSTAT            ;command buffer empty = 0
            CLR  FLASHreturnCode       ;clear return value
 
            BRSET FSTAT,#32,WFFIR1     ;check PVIOL
            BRCLR FSTAT,#16,WFFIR2     ;check ACCERR
WFFIR1:
            MOVB  #5,FLASHreturnCode   ;ERR_NOTAVAIL
            RTS 
WFFIR2:
            BRCLR FSTAT,#64,*+0        ;wait while not CCIF
            RTS
WaitForFlashROMend:
;---------------------------------
; Copy WaitForFlashROM to RAM
;---------------------------------
CopyWaitForFlashROMtoRAM:
            PSHX
            PSHY
            PSHA
            
            LDY   #WaitForFlashInRam
            LDX   #WaitForFlashinROM
            LDAA  #30                   ; loop constant
CWFFRTR1:   
            LDAB  0,X
            STAB  0,Y
            INX
            INY
            DBNE A,CWFFRTR1
            
            PULA
            PULY
            PULX
            
            RTS
;---------------------------------
; Read Word from Far
; Parameters: pg, off, farWord
; Modifies  : farWord
;---------------------------------
ReadFarWord:
            PSHA                      ; save A register
            PSHX
            LDAA    PPAGE             ; store PPAGE
            MOVB    pg,PPAGE          ; set page register
            LDX     off               
            LDX     0,X               ; read word from flash
            STX     farWord
            STAA    PPAGE             ; restore page register
            PULX
            PULA                      ; restore A register
            RTS
;---------------------------------
; Write Word to Far
; Parameters: pg, off, farWord
; returns   : NONE
;---------------------------------
WriteWordFar:
            PSHA                      ; save A register
            PSHX
            PSHY
            LDAA    PPAGE             ; save page register
            MOVB    pg,PPAGE          ; set page register
            LDX     off               ; 
            LDY     farWord
            STY     0,X               ; write word to far flash
            STAA    PPAGE             ; restore page register
            PULY
            PULX
            PULA                      ; restore A register
            RTS
;---------------------------------
; FlashEraseSector
; Parameters: pg, off
; Modifies: FLASHreturnCode
;---------------------------------
FlashEraseSector:
            PSHD
            PSHX
            CLR FLASHreturnCode
            ; disable interrupt because of critical section
            JSR  GetCCRdisableI

            ;erase error flags in all blocks
            MOVB FCNFG,temp       ; store FCNFG
            
            LDAA FCNFG            ; get FCNFG
            LDAB #FLASHblocks     ; loop constant
FES1:   
            DECB                  ; calculate block in loop 
            ANDA  #$F0            ; mask block in FCNFG 
            ABA                   ; write block to FCNFG
            STAA  FCNFG           ; 
            MOVB  #$30,FSTAT      ; errase error flags in given block
            TSTB
            BNE   FES1


            ; calculate block
            ; FCNFG_BKSEL=(UBYTE) ((0x3F-page)/Flash_Pages_Per_Block);   
            CLRA
            LDAB  #$3F
            SUBB  pg
            LDX   #FlashPagesPerBlock
            IDIV                  ; result in B
            EXG  D,X
            LDAA  FCNFG           ; get FCNFG
            ANDA  #$F0            ; mask block in FCNFG 
            ABA                   ; 
            STAA FCNFG            ; write block to FCNFG

            ; if (FSTAT_CBEIF == 0) {restoreCCR(); return FLASHerrBUSY;} // Is command buffer full ?
            BRSET FSTAT,#128,FES2
            JSR  RestoreCCR 
            MOVB #FLASHerrBUSY,FLASHreturnCode
            BRA  FES9
FES2:       
            MOVW  #$FFFF,farWord  ;Write dummy word
            JSR  WriteWordFar
            MOVB #$40,FCMD
            JSR  WaitForFlashInRam; Wait while flash is busy
FES9:       
            MOVB temp,FCNFG       ; restore FCNFG
            JSR  RestoreCCR       ; restore CCR
            PULX
            PULD

            RTS
;---------------------------------
; FlashWriteWord
; Parameters: pg, off, farWord
; Modifies: FLASHreturnCode
;---------------------------------
FlashWriteWord:
            PSHD
            PSHX
            CLR FLASHreturnCode
            
            ; disable interrupt because of critical section
            JSR  GetCCRdisableI

            ;check alignment
            BRCLR off,#1,FWW1
            MOVB #FLASHerrNOTAVAIL,FLASHreturnCode
            BRA  FWW9
FWW1: 

            ;erase error flags in all blocks
            MOVB FCNFG,temp       ; store FCNFG
            
            LDAA FCNFG            ; get FCNFG
            LDAB #FLASHblocks     ; loop constant
FWW2:   
            DECB                  ; calculate block in loop 
            ANDA  #$F0            ; mask block in FCNFG 
            ABA                   ; write block to FCNFG
            STAA  FCNFG           ; 
            MOVB  #$30,FSTAT      ; errase error flags in given block
            TSTB
            BNE   FWW2


            ; calculate block
            ; FCNFG_BKSEL=(UBYTE) ((0x3F-page)/Flash_Pages_Per_Block);   
            CLRA
            LDAB  #$3F
            SUBB  pg
            LDX   #FlashPagesPerBlock
            IDIV                  ; result in B
            EXG  D,X
            LDAA  FCNFG           ; get FCNFG
            ANDA  #$F0            ; mask block in FCNFG 
            ABA                   ; 
            STAA FCNFG            ; write block to FCNFG

            ; if (FSTAT_CBEIF == 0) {restoreCCR(); return FLASHerrBUSY;} // Is command buffer full ?
            BRSET FSTAT,#128,FWW3
            JSR  RestoreCCR 
            MOVB #FLASHerrBUSY,FLASHreturnCode
            BRA  FES9
FWW3:       
            JSR  WriteWordFar
            MOVB #$20,FCMD
            JSR  WaitForFlashInRam; Wait while flash is busy
FWW9:       
            MOVB temp,FCNFG       ; restore FCNFG
            JSR  RestoreCCR       ; restore CCR
            PULX
            PULD

            RTS
;---------------------------------
; Main code loop
;---------------------------------
Entry:
            LDS   #RAMEnd+1           ; initialize the stack pointer

            ; copy routine which is used for Flash E/W into RAM
            JSR   CopyWaitForFlashROMtoRAM ;copy flashing routine to RAM
            
            ;init Flash CLOCK   OSCCLK=16MHz BUSCL=8MHz
            MOVB  #74,FCLKDIV
            
            ; read word by means of far address 
            MOVB  #$3F,pg             ; address
            MOVW  #$BFFE,off
            JSR   ReadFarWord         ; result is in variable farWord

            ; write word into RAM by means of far address (example) 
            MOVB  #$00,pg             ; address
            MOVW  #$0900,off
            MOVW  #$ABCD,farWord      ; data 
            JSR   WriteWordFar        ; write it


mainLoop:

            ; erase sector $208000
            MOVB #$20,pg
            MOVW #$8000,off
            JSR FlashEraseSector
            ; process FLASHreturnCode here
            
            ; write word at $208000
            MOVB #$20,pg
            MOVW #$8000,off
            MOVW #$DEAD,farWord
            JSR FlashWriteWord
            ; process FLASHreturnCode here



            ; erase flash sector $4000
            MOVB #$3F,pg
            MOVW #$4000,off
            JSR FlashEraseSector
            ; process FLASHreturnCode here
            
            ; write word at flash $4000
            MOVB #$3F,pg
            MOVW #$4000,off
            MOVW #$DEAD,farWord
            JSR FlashWriteWord
            ; process FLASHreturnCode here


            BRA   mainLoop        ; main loop
;**************************************************************
;*                 Interrupt Vectors                          *
;**************************************************************
            ORG   $FFFE
            DC.W  Entry           ; Reset Vector


















