;
;    Mecrisp - A native code Forth implementation for MSP430 microcontrollers
;    Copyright (C) 2011  Matthias Koch
;
;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;    (at your option) any later version.
;
;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.
;
;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.
;

;------------------------------------------------------------------------------
  Kapitelbirne_flash "--- Flash ---"  
;------------------------------------------------------------------------------  

;------------------------------------------------------------------------------
; Register & Konstanten für die Flashzugriffe !
;------------------------------------------------------------------------------

FCTL1 equ 0128h
FCTL2 equ 012Ah
FCTL3 equ 012Ch

; Schlüssel für alle Flashregister:
FWKEY equ 0A500h

;------------------------------------------------------------------------------
; Konstanten für FCTL1:
         ; 76543210
BLKWRT equ 10000000b ; Block Write Mode
WRT    equ  1000000b ; Write
                     ; Reserviert
EEIEX  equ    10000b ; Emergency Exit
EEI    equ     1000b ; Enable Erase Interrupts
MERAS  equ      100b ; Mass erase
ERASE  equ       10b ; Erase
                     ; Reserviert

;------------------------------------------------------------------------------
; Konstanten für FCTL2:
         ; 76543210
FSSEL_0 equ 00000000b ; ACLK
FSSEL_1 equ 01000000b ; MCLK
FSSEL_2 equ 10000000b ; SMCLK
FSSEL_3 equ 11000000b ; SMCLK

; In Bit 0-5 gehört der Taktteilerwert. Geteilt wird durch (Wert + 1).
FN0    equ          1b ; Teiler 2^0 = 1
FN1    equ         10b ; Teiler 2^1 = 2
FN2    equ        100b ; Teiler 2^2 = 4
FN3    equ       1000b ; Teiler 2^3 = 8
FN4    equ      10000b ; Teiler 2^4 = 16
FN5    equ     100000b ; Teiler 2^5 = 32

;------------------------------------------------------------------------------
; Konstanten für FCTL3:
         ; 76543210
FAIL  equ  10000000b ; Operation Failure
LOCKA equ   1000000b ; SegmentA and Info Lock. Writing 1 toggles state.
EMEX  equ    100000b ; Emergency Exit
LOCK  equ     10000b ; Lock. This bit unlocks flash memory for writing or erasing.
WAIT  equ      1000b ; Wait. Indicates Flash memory is being written to.
ACCVIFG equ     100b ; Access violation interrupt flag
KEYV  equ        10b ; Flash security key violation
BUSY  equ         1b ; Busy-Flag

;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar, "eraseflash" ; Vergisst den Inhalt des Dictionarys.
                                        ; Macht einen Kaltstart. Initialisiert alles neu.
;------------------------------------------------------------------------------           
  ; Wird einmal den ganzen Flash löschen. Füllt jetzt einfach das Dictionary mit $FFFF.
  writeln " "
  ;write "Flash wird gelöscht... "
  write "Flash gets erased... "
  push r10

  ; Flash zum Löschen präparieren
  ; Routine funktioniert gleichermaßen gut im echten Flash wie im Emulator.
            push sr
            dint
            mov.w   #FWKEY, &FCTL3           ; Clear LOCK bits
            mov.w   #FWKEY+ERASE,&FCTL1      ; Set Erase bit


  mov #nFlashDictionaryAnfang, r10

- cmp #0FFFFh, @r10
  je +
  mov #0FFFFh, @r10
+ incd r10
  cmp #nFlashDictionaryEnde, r10
  jne -

  ; Flash wieder schützen
            mov.w   #FWKEY, &FCTL1           ; Clear Erase bit
            mov.w   #FWKEY+LOCK,&FCTL3       ; Set LOCK bit
            pop sr
  pop r10
  ;writeln " Fertig !"
  writeln "Finished !"
  ; Muss nun die Pointer neu setzen. Und am Besten alle Initialisierungen neu machen.
  ; Ram wird ebenso gelöscht, denn die Verweise ins Flash sind gerade gelöscht worden
  br #Reset
  


  ifdef 0  ; Flash-Adress-Probe  
  cmp #nFlashDictionaryAnfang, @r4
  jhs +
  writeln "Wilder Flashzugriff unterhalb des Dictionarys !"
  br #quit

+ cmp nFlashDictionaryEnde, @r4
  jlo +
  writeln "Wilder Flashzugriff oberhalb des Dictionarys !"
  br #quit

+
  endif

;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar, "cflash!"
flashcstore: ; ( n Adresse -- ) Fügt ein Byte mitten in das Dictionary ein.
;------------------------------------------------------------------------------
  push r10 
  push r11 
  popda r10 ; Adresse
  popda r11 ; Inhalt

  cmp #kernelstartadresse, r10 ; Schützt Forth.
  jhs +

  cmp.b #0FFh, r11 ; FFFF wird nie gebrannt.
  je +

  cmp.b #0FFh, @r10 ; Es wird nur gebrannt, wenn an der Stelle im Flash $FF steht.
  jne +             ; In Kombination werden so die Schreibzyklen nie überschritten.

  ; Brennen.
            push sr
            dint
            mov.w   #FWKEY, &FCTL3           ; Clear LOCK bit
            mov.w   #FWKEY+WRT,&FCTL1        ; Set WRT bit for write operation

  mov.b r11, @r10
  ; Flash wieder schützen
            mov.w   #FWKEY, &FCTL1           ; Clear WRT bit
            mov.w   #FWKEY+LOCK,&FCTL3       ; Set LOCK bit
            pop sr
+ pop r11
  pop r10
  ret

;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar, "flash!"
flashstore: ; ( n Adresse -- ) Fügt ein Word mitten in das Dictionary ein.
;------------------------------------------------------------------------------
  push r10 
  push r11 
  popda r10 ; Adresse
  popda r11 ; Inhalt

  cmp #kernelstartadresse, r10 ; Schützt Forth.
  jhs +

  bit #1, r10 ; Wordzugriffe nur an geraden Adressen
  jc +

  cmp #0FFFFh, r11 ; FFFF wird nie gebrannt.
  je +

  cmp #0FFFFh, @r10 ; Es wird nur gebrannt, wenn an der Stelle im Flash $FFFF steht.
  jne +             ; In Kombination werden so die Schreibzyklen nie überschritten.

  ; Brennen.    
            push sr
            dint        
            mov.w   #FWKEY, &FCTL3           ; Clear LOCK bit
            mov.w   #FWKEY+WRT,&FCTL1        ; Set WRT bit for write operation
  mov r11, @r10
  ; Flash wieder schützen
            mov.w   #FWKEY, &FCTL1           ; Clear WRT bit
            mov.w   #FWKEY+LOCK,&FCTL3       ; Set LOCK bit
            pop sr

+ pop r11
  pop r10
  ret

;------------------------------------------------------------------------------
  Kapitelbirne "--- Flash ---"  
;------------------------------------------------------------------------------  
