;
;    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/>.
;

; Speicherzugriffe aller Art

;------------------------------------------------------------------------------
  Kapitelbirne_flash "--- Speicher ---"  
;------------------------------------------------------------------------------ 


  ifdef 0 ; Wurde nur für stringvergleich gebraucht - jetzt überflüssig !
;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar, "speichervergleich"
  flagdolmetscher
speichervergleich: ; ( Adresse Adresse Länge -- ) Carry-Flag: Ergebnis.
;------------------------------------------------------------------------------
  push r10
  push r11
  push r12
  
  popda r10 ; Länge vom Datenstack holen (Achtung: in Byte!)
  popda r11 ; Adresse des einen Teils
  popda r12 ; Adresse des anderen Teils
  
- cmp #0, r10 ; Wenn die Länge null ist, sind wir fertig.
  je ++
  
  cmp.b @r11+, @r12 ; Byteweise durchlaufen ! Wichtig, falls Strings ohne Ausrichtung verglichen werden.
  ; Wenn ungleich, rausspringen. Wie ist der Carry-Flag, wenn es ungleich ist ?
  jne +
  
 ; inc r11 ; Adresse erhöhen - das macht das Plus bereits ;-)
  inc r12 ; Adresse erhöhen
  dec r10 ; Noch zu vergleichende Länge um eins erniedrigen
  jmp -   ; Weitervergleichen.
  
+ clrc
  jmp ++
  
+ setc ; Carry setzen, identisch !  
+ pop r12
  pop r11
  pop r10
  ret
  endif



  ;ifdef spezialstrings ; Wurde nur für string, gebraucht - jetzt überflüssig !
;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar, "cmove"
;cmove: ; ( Quelladdr Zieladdr Byteanzahl -- )
       ; Kopiert einen Datensatz an eine neue Stelle.
       ; Fänge vorne an, kann also zum Schieben nach hinten benutzt werden.
;------------------------------------------------------------------------------
  push r10
  push r11
  push r12
  
  popda r12 ; Count
  popda r11 ; Zieladresse
  popda r10 ; Quelladresse
  
  tst r12   ; Prüfe, ob die Anzahl der zu kopierenden Bytes Null ist.
  je +      ; Wenn ja, bin ich fertig.
  
  ; Mindestens ein Byte ist noch zu kopieren.
- mov.b @r10, @r11 ; Von der Quelladresse an die Zieladresse kopieren
  inc r10  ; Quelladresse erhöhen
  inc r11  ;  Zieladresse erhöhen
  dec r12  ; Zahl der noch zu kopierenden Bytes erniedrigen
  jnz -    ; Sind noch welche übrig ?
  
+ pop r12
  pop r11
  pop r10
  ret  
  ;endif

;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar, "cbit@" ; Testet Bit(s) ( Maske addr -- Flag )

  push r10
  popda r10 ; Adresse holen
  bit.b @r4, @r10 ; Bits prüfen

  jmp + ; Der Teil ist genauso wir in bit@.

;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar, "bit@" ; Testet Bit(s) ( Maske addr -- Flag )

  push r10
  popda r10 ; Adresse holen
  bit @r4, @r10 ; Bits prüfen

+ clr @r4
  jnc +
  mov #-1, @r4  
+
  pop r10
  ret

;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar|Flag_opcodierbar_speicherschreiben, "cxor!" ; Wechselt Bits ( n addr -- )

  push r10
  popda r10 ; Adresse holen
  xor.b @r4, @r10 ; Bits setzen
  drop
  pop r10
  ret
  .word 0e0f2h ; Opcode ! xor.b #Konstante, &Adresse. Für die Wirkung xor.b @r4+, &Adresse muss ich e4f2 benutzen.

;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar|Flag_opcodierbar_speicherschreiben, "xor!" ; Wechselt Bits ( n addr -- )

  push r10
  popda r10 ; Adresse holen
  xor @r4+, @r10 ; Bits setzen
  pop r10
  ret
  .word 0e0b2h ; Opcode ! xor #Konstante, &Adresse. Für die Wirkung xor @r4+, &Adresse muss ich e4b2 benutzen.

;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar|Flag_opcodierbar_speicherschreiben, "cbic!" ; Löscht Bits ( n addr -- )

  push r10
  popda r10 ; Adresse holen
  bic.b @r4, @r10 ; Bits setzen
  drop
  pop r10
  ret
  .word 0c0f2h ; Opcode ! bic.b #Konstante, &Adresse. Für die Wirkung bic.b @r4+, &Adresse muss ich c4f2 benutzen.

;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar|Flag_opcodierbar_speicherschreiben, "bic!" ; Löscht Bits ( n addr -- )

  push r10
  popda r10 ; Adresse holen
  bic @r4+, @r10 ; Bits setzen
  pop r10
  ret
  .word 0c0b2h ; Opcode ! bic #Konstante, &Adresse. Für die Wirkung bic @r4+, &Adresse muss ich c4b2 benutzen.

;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar|Flag_opcodierbar_speicherschreiben, "cbis!" ; Setzt Bits ( n addr -- )  

  push r10
  popda r10 ; Adresse holen
  bis.b @r4, @r10 ; Bits setzen
  drop
  pop r10
  ret
  .word 0d0f2h ; Opcode ! bis.b #Konstante, &Adresse. Für die Wirkung bis.b @r4+, &Adresse muss ich d4f2 benutzen.

;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar|Flag_opcodierbar_speicherschreiben, "bis!" ; Setzt Bits ( n addr -- )

  push r10
  popda r10 ; Adresse holen
  bis @r4+, @r10 ; Bits setzen
  pop r10
  ret
  .word 0d0b2h ; Opcode ! bis #Konstante, &Adresse. Für die Wirkung bis @r4+, &Adresse muss ich d4b2 benutzen.



;------------------------------------------------------------------------------
setze_faltbarflag: ; Markiert Wort als 0-Faltbar.
;------------------------------------------------------------------------------
  push r10
  mov #Flag_faltbar, r10
  br #flagsetzer

;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar, "2constant" ; Legt eine Konstante an
zweiconstant: ; ( Zahl -- ) : constant create swap literal, literal, ret, smudge ; 
;------------------------------------------------------------------------------
  call #create
  swap
  call #literalkomma
  call #literalkomma
  call #retkomma
  call #setze_faltbarflag
  br #smudge

;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar, "constant" ; Legt eine Konstante an
constant: ; ( Zahl -- ) : constant create literal, ret, smudge ; 
;------------------------------------------------------------------------------
  call #create
  call #literalkomma
  call #retkomma
  call #setze_faltbarflag
  br #smudge
   
; Variable im Flash:
; pushda #Adresse ret Initialisierungswert

; Variable im Ram:
; pushda #Adresse ret Wert

; Nur mit dem kleinen Unterschied, dass die Adresse bei der Flash-Variablen irgendwo im Ram liegt
; und der Initialisierungswert dahin kopiert wird.

; Somit ist das Anlegen der Variablen selbst eigentlich in beiden Fällen identisch.

; Um Ram-Speicher zu bekommen, markiere das Wort als Flag_ramallot|Größe in Words.
; und dekrementiere den VariablenPointer entsprechend. Prüfe, ob noch genug Speicher da ist.

;  cmp #nRamAnfang+2, &VariablenPointer
;  jlo ; Fehler !


  ifdef doppeltzahleneinbinden
;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar, "2variable" ; Legt eine initialisierte Variable an
;variable: ; ( ZahlL ZahlH -- ) 
;------------------------------------------------------------------------------  
  ifdef flashdictionaryeinbinden

  call #create

  ifdef flashdictionaryeinbinden
    cmp #nBacklinkgrenze, &DictionaryPointer ;tst &WritetoFlash
    jlo zweivariable_fuer_ram                   ;jz variable_fuer_ram

    ifdef ramverwaltungeinbinden
    ; Eine echte Flash-Variable entsteht so, dass Platz im Ram angefordert wird.
    ; Prüfe hier, ob genug Ram da ist !?
    mov #Flag_ramallot|2, &FlashFlags ; Mache dies NUR beim Schreiben in Flash.
    sub #4, &VariablenPointer
    push r10
      mov &VariablenPointer, r10 ; Lege den Startwert der Variablen bereit !      
      mov @r4, @r10
      mov 2(r4), 2(r10)
      pushda r10 ; &VariablenPointer ; Die Adresse, die Flash-Variablen benutzen und die ins Ram zeigt.  
    pop r10
    jmp zweivariable_weitermachen
    else ; ramverwaltungeinbinden
      writeln "Im Flash können keine Variablen definiert werden !"
      br #quit    
    endif
  endif ; flashdictionaryeinbinden

zweivariable_fuer_ram:
    pushda &DictionaryPointer ; Dies ist die Adresse, die für Ram-Variablen benutzt wird.
    add #10, @r4 ; Zeiger auf die Zahl in der Speicherstelle, die genau 10 Bytes später kommt.
zweivariable_weitermachen:
  call #literalkomma
  call #retkomma
  call #komma ; Zahl bzw. Initialisierungswert einfügen.
  call #komma
  call #setze_faltbarflag ; Das führt dazu, dass Variablen Ramallot & Faltbarkeit gesetzt haben.
  br #smudge              ; macht nichts, da das Ramallot-Flag zuerst geprüft wird.

  else ; flashdictionaryeinbinden
    ; Könnte ich 2variable in der nur-Ram-Variante nicht auch einfach mit call #variable br #komma erledigen :-) ?  
    call #variable
    br #komma      ; Noch einen Wert hinten dranhängen :-) Kein Problem !
  endif ; flashdictionaryeinbinden

  endif ; doppeltzahleneinbinden


;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar, "variable" ; Legt eine initialisierte Variable an
variable: ; ( Zahl -- ) : variable create here 10 + literal, ret, , smudge ; Es war einmal ...
;------------------------------------------------------------------------------  
  call #create

  ifdef flashdictionaryeinbinden
    cmp #nBacklinkgrenze, &DictionaryPointer ;tst &WritetoFlash
    jlo variable_fuer_ram                   ;jz variable_fuer_ram

    ifdef ramverwaltungeinbinden
    ; Eine echte Flash-Variable entsteht so, dass Platz im Ram angefordert wird.
    ; Prüfe hier, ob genug Ram da ist !?
    mov #Flag_ramallot|1, &FlashFlags ; Mache dies NUR beim Schreiben in Flash.
    decd &VariablenPointer
    push r10
      mov &VariablenPointer, r10 ; Lege den Startwert der Variablen bereit !
      mov @r4, @r10
      pushda r10 ; &VariablenPointer ; Die Adresse, die Flash-Variablen benutzen und die ins Ram zeigt.  
    pop r10
    jmp variable_weitermachen
    else ; ramverwaltungeinbinden
      writeln "Im Flash können keine Variablen definiert werden !"
      br #quit    
    endif
  endif

variable_fuer_ram:
    pushda &DictionaryPointer ; Dies ist die Adresse, die für Ram-Variablen benutzt wird.
    add #10, @r4 ; Zeiger auf die Zahl in der Speicherstelle, die genau 10 Bytes später kommt.
variable_weitermachen:
  call #literalkomma
  call #retkomma
  call #komma ; Zahl bzw. Initialisierungswert einfügen.
  call #setze_faltbarflag ; Das führt dazu, dass Variablen Ramallot & Faltbarkeit gesetzt haben.
  br #smudge              ; macht nichts, da das Ramallot-Flag zuerst geprüft wird.


;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar|Flag_opcodierbar_speicherschreiben, "+!" ; Plus-Store ( n addr -- )

  push r10
  popda r10 ; Adresse holen
  add @r4, @r10 ; Hinzuzählen
  drop
  pop r10
  ret
  .word 50b2h ; Opcode ! add #Konstante, &Adresse. Für die Wirkung add @r4+, &Adresse muss ich 54b2 benutzen.
   
;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar, "2!" ; Store ( d addr -- )
  push r10  
    popda r10 ; Hole die Adresse    
    popda @r10  ; High-Word an Adresse
    incd r10
    popda @r10  ; Low-Word an Adresse+2 gemäß fig/ans
  pop r10
  ret
  
;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar, "2@" ; Fetch ( addr -- d )
  push r10
    mov @r4, r10  ; Hole die Adresse  
    incd r10
    mov @r10, @r4
    decd r4
    decd r10
    mov @r10, @r4
  pop r10
  ret

;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar|Flag_opcodierbar_speicherschreiben, "c!" ; c-Store ( c addr -- ) 
  push r10  ; Adresse
  push r11  ; Inhalt
    
    popda r10  ; Hole die Adresse
    popda r11  ; Hole den Byte-Inhalt    
    mov.b r11, @r10 ; Lege den gewünschten Inhalt hinein.
        
  pop r11
  pop r10
  ret      
  .word 40f2h ; Opcode ! mov.b #Konstante, &Adresse. Für die Wirkung mov.b @r4+, &Adresse muss ich 44f2 benutzen.
  
;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar|Flag_opcodierbar_speicherlesen, "c@" ; c-Fetch ( addr -- c )
  push r10
    mov @r4, r10  ; Hole die Adresse
    mov.b @r10, r10 ; Hole den Inhalt der Adresse
    mov r10, @r4  ; Lege den addressierten Inhalt auf den Stack
  pop r10
  ret       
  .word 42d4h ; Opcode ! mov.b &Adresse, 0(r4). Muss im Opcodierfall vorher noch decd r4 = $8324 einfügen.
              ;          High-Byte im Datenstack bleibt ungesetzt. Lösche ihn mit clr.b 1(r4)
  
;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar|Flag_opcodierbar_speicherschreiben, "!" ; Store ( n addr -- )
  push r10  
    popda r10  ; Hole die Adresse  
    popda @r10 ; und lege den gewünschten Inhalt hinein.  
  pop r10
  ret      
  .word 40b2h ; Opcode ! mov #Konstante, &Adresse. Für die Wirkung mov @r4+, &Adresse muss ich 44b2 benutzen.
  
;------------------------------------------------------------------------------
  Wortbirne Flag_sichtbar|Flag_opcodierbar_speicherlesen, "@" ; Fetch ( addr -- n )
  push r10
    mov @r4, r10  ; Hole die Adresse  
    mov @r10, @r4 ; Lege den addressierten Inhalt auf den Stack
  pop r10
  ret
  .word 4294h ; Opcode ! mov &Adresse, 0(r4). Muss im Opcodierfall vorher noch decd r4 = $8324 einfügen.
    
;------------------------------------------------------------------------------
  Kapitelbirne "--- Speicher ---"  
;------------------------------------------------------------------------------ 
