****************************************************************************** * S12E128 Simple EEPROM EMULATION * 1KB of S128 Flash is used as byte-writable EEPROM. This flash sector is * written to RAM at program startup, and is wrtten to as RAM during program * execution, then the RAM block is written to Flash as part of program * shutdown. Writing of Flash is done by copying about 200B of relocatable code * to RAM and executing from there. 1KB of RAM needs to be dedicated to this task. * Flash is guaranteed for 10,000 erase-program cycles. So this * code is suitable for applications where life-time power-ups is expected to * be less than this number. Motorola Application note AN2302 addresses more * sophisticated strategies that can extend this life. * Bruce McMillan 9 October 2003 * ****************************************************************************** DEFAULT_RAM: EQU $2000 RAM_SIZE: EQU $2000 STACKTOP: EQU DEFAULT_RAM+RAM_SIZE STACK_SIZE: EQU $80 VECTORS: EQU $FF8A ; /* eeprom emulation in ram&flash */ EEPROM_EMUL_SIZE: EQU $400 EEPROM_IN_RAM: EQU DEFAULT_RAM+RAM_SIZE-EEPROM_EMUL_SIZE-STACK_SIZE ;$3B00 (available ram 0..7,040B) EEPROM_IN_FLASH EQU $38BC00 EEPROM_IN_FLASH_1 EQU $BC00 ; /* paged FLASH ROM */ DEFAULT_ROM_PAGED: EQU $308000 PAGE_30: EQU $C0000 ;0x308000 ;$C0000–$C3FFF PAGE_31: EQU $C4000 ;0x318000 ;$C4000–$C7FFF PAGE_32: EQU $C8000 ;0x328000 ;$C8000–$CBFFF PAGE_33: EQU $CC000 ;0x338000 ;$CC000–$CFFFF PAGE_34: EQU $D0000 ;0x348000 ;$D0000–$D3FFF PAGE_35: EQU $D4000 ;0x358000 ;$D4000–$D7FFF PAGE_36: EQU $D8000 ;0x368000 ;$D8000–$DBFFF PAGE_37: EQU $DC000 ;0x378000 ;$DC000–$DFFFF PAGE_38: EQU $388000 ;$E0000 ;0x388000 ;$E0000–$E3FFF ;EEPROM Emulation PAGE_39: EQU $398000 ;$E4000 ;0x398000 ;$E4000–$E7FFF PAGE_3A: EQU $3A8000 ;$E8000 ;0x3A8000 ;$E8000–$EBFFF PAGE_3B: EQU $3B8000 ;$EC000 ;0x3B8000 ;$EC000–$EFFFF PAGE_3C: EQU $3C8000 ;$F0000 ;0x3C8000 ;$F0000–$F3FFF PAGE_3D: EQU $3D8000 ;$F4000 ;0x3D8000 ;$F4000–$F7FFF P_OP1: EQU $38 ;page $38 P_OP2: EQU $39 ;page $39 P_OP3: EQU $3A ;page $3A P_OP4: EQU $3B ;page $3B P_OP5: EQU $3C ;page $3C P_OP6: EQU $3D ;page $3D ****************************************************************************** OscClk: equ 4000000 ; oscillator clock frequency. fEclock: equ 16000000 ; final E- clock frequency (PLL). RefClock: equ 4000000 ; reference clock used by the PLL. REFDVVal: equ (OscClk/ RefClock)- 1 ; value for the REFDV register. SYNRVal: equ (fEclock/ RefClock)- 1 ; value for the SYNR register. if OscClk> 12800000 FCLKDIVVal: equ (OscClk/ 200000/ 8)+ PRDIV8 ; value for the FCLKDIV register. else FCLKDIVVal: equ (OscClk/ 200000) ; value for the FCLKDIV register. endif ; FlashStart: equ $8000 ; start address of the flash window. BootBlkSize: equ 4096*4 ; Erase protected bootblock size. RAMStart: equ $2000 ; default RAM base address. StackTop: equ $4000 ; ex $ffc0; stack location after RAM is moved. RAMBoot: equ $3000 ; starting RAM address where the bootloader will be copied. SectorSize: equ 1024 ; size of a Flash Sector. 1024 For E128 chip !!!!! PPAGESize: equ 16384 ; size of the PPAGE window ($ 8000 - $BFFF). ****************************************************************************** ****************************************************************************** EEPROM_EMULATION_INIT ;JSR EEPROM_EMULATION_INIT !! must run in non-paged * ****************************************************************************** MOVB PPAGE,1,-SP MOVB #P_OP1,PPAGE ;$B8 LDY #EEPROM_IN_FLASH_1 ;source: $38:BC00 LDX #EEPROM_IN_RAM LDD #EEPROM_EMUL_SIZE/2 _EE_INIT_Loop MOVW 2,y+,2,x+ DBNE D,_EE_INIT_Loop MOVB 1,SP+,PPAGE RTS ****************************************************************************** ****************************************************************************** EEPROM_EMULATION_SAVE ;JSR EEPROM_EMULATION_SAVE !! must run in non-paged * ;executes in RAM * ****************************************************************************** sei ; clear interrupts ldaa PPAGE psha ; PPAGE gets modified, so save ldx #EEPROM_EMUL_WRITE ; point to the start of the Flash bootloader in Flash. ldy #RAMBoot ; point to the start of on- chip RAM. ldd #EE_BootLoadEnd ; calculate the size of the bootloader code. subd #EEPROM_EMUL_WRITE EE_MoveMore: movb 1,x+, 1,y+ ; move a byte of the bootloader into RAM. dbne d,EE_MoveMore ; dec byte count, move till done. jmp RAMBoot ; ----- program diverts to execute save routine in RAM, then returns here ----- EE_Continue nop pula staa PPAGE ; restore PPAGE reg cli ; enable interrupts rts ****************************************************************************** ; relocatable code.... (executes from RAM) ****************************************************************************** EEPROM_EMUL_WRITE: jsr COP_SERVICE ; ----- erase old code ----- bset FSTAT,#CBEIF+PVIOL+ACCERR ;clr any pending flags EE_WRITE_Loop clr ErrorFlag ; clear the global error flag. jsr EraseEEPROM_Emul,pcr ; Erase execution blocks ldab ErrorFlag ; error executing the command? bne EE_WRITE_Loop ; if error, re-write till watchdog timeout ; ----- load new code ----- jsr COP_SERVICE ; all preserved (~24cyc) jsr WriteEEPROM_Emul,pcr ; Get infrared download ldab ErrorFlag ; error executing the command? bne EE_WRITE_Loop ; if error, erase & try again till watchdog timeout ; ----- sucessful, return to execution from Flash ----- jmp EE_Continue ****************************************************************************** EraseEEPROM_Emul: movb #$38,PPAGE ; erase sector $38:3BC0 clr FCNFG ; set block select bits to 0. ldx #EEPROM_IN_FLASH_1 ; point to the start of the PPAGE window ldab #1 ; number of sectors to clr (EEPROM emulation is one sector) bsr EE_EraseSectors ; go erase the PPAGE window a sector at a time bne EE_SaveError ; non- zero value returned in A indiciates a sector didn't erase rts EE_SaveError: staa ErrorFlag ; put error code where pod can access it rts ; return. ; ----- Erases 'b' (accumulator) sectors beginning at address 'x' (index register) ----- EE_EraseSectors: exg b,y ; put the sector count in y EE_EraseSectLoop: ldab #ERASE ; perform a sector erase bsr EE_EraseCmd beq EE_DoEraseVerf ; if no problem with the erase command, do a verify EE_Rtn: rts ; if problem, return with an error code in a EE_DoEraseVerf: bsr EE_VerfSector bne EE_Rtn ; if problem, return with an error code in a leax SectorSize,x ; point to the next sector. dbne y,EE_EraseSectLoop ; continue to erase remaining sectors. rts ; done. return. ; ----- Erases a block or sector of Flash ----- EE_EraseCmd: std 0,x ; latch address for erase command. stab FCMD ldab #CBEIF stab FSTAT ; initiate the erase command. brclr FSTAT,#PVIOL+ACCERR,EE_EraseCmdOK ; continue if the privliage violation & Access error flags are clear. ldaa #FEraseError ; rts EE_EraseCmdOK: brclr FSTAT,#CCIF,* ; wait until the command has completed. clra rts ; ----- Verify that a sector was properly erased ----- ; ----- Must verify a word at a time because the built in verify command only works on a block (64K) EE_VerfSector: pshx ; save the base address of the sector. pshy ; save the sector count. ldy #SectorSize/2 ; we'll check 2 bytes at a time. EE_VerfSectLoop: ldd 2,x+ ; get a byte from the sector. ibeq d,EE_WordOK ldaa #FEraseError bra EE_SectRtn EE_WordOK: dbne y,EE_VerfSectLoop ; yes. dec the sector word count. clra EE_SectRtn: puly ; restore the sector count. pulx ; restore the base address of the sector. rts ; return. ************************************************************************************* WriteEEPROM_Emul ;writes EEPROM_IN_RAM to EEPROM_IN_FLASH at shutdown ************************************************************************************* movb #$38,PPAGE ; page low jsr EE_ProgFBlock,pcr ; go program the data into Flash. beq EE_PROG_REC_x ; zero condition means all went ok. ldaa #FlashPrgErr staa ErrorFlag ; put error code where pod can access it. EE_PROG_REC_x: rts ************************************************************************************** ************************************************************************************** EE_ProgFBlock: ldx #EEPROM_IN_FLASH_1 ; destination ldy #EEPROM_IN_RAM ; source ldd #EEPROM_EMUL_SIZE/2 ; get sector size $400/2 EE_ProgLoop: pshd movw 2,y+,2,x+ ; latch the address & data into the Flash program/ erase buffers. ldab #PROG ; get the program command. stab FCMD ; write it to the command register. ldab #CBEIF ; start the command by writing a 1 to CBEIF. stab FSTAT ldab FSTAT ; check to see if there was a problem executing the command. bitb #PVIOL+ACCERR ; if either the PVIOL or ACCERR bit is set, puld ; CCR unaffected bne EE_Return ; return. brclr FSTAT,#CBEIF,* ; wait here till the command buffer is empty. dbne d,EE_ProgLoop ; yes. continue until done. brclr FSTAT,#CCIF,* ; no. wait until all commands complete. ; ----- verify ----- ldx #EEPROM_IN_FLASH_1 ; destination ldy #EEPROM_IN_RAM ; source ldd #EEPROM_EMUL_SIZE/2 ; get sector size $400/2 EE_VerfLoop: pshd ldd 2,y+ ; get a word from the buffer. cpd 2,x+ ; same as the word in Flash? puld ; CCR unaffected bne EE_Return ; no. return w/ an error (!= condition). dbne d,EE_VerfLoop ; no. compare some more. EE_Return: rts ; return. ****************************************************************************** EE_BootLoadEnd EQU * ******************************************************************************