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

; Ideen für ein MSP430-Architektur Forth. Entstanden am 18. Februar 2010
; Fertig im August 2011 und seitdem noch weiterentwickelt.

; 16 bit Implementation, zwischen Subroutine Threading und Native Code, Konstantenfaltung, Opcodierungen
; Unterstützt bei Bedarf Unicode (utf8).

; Keine Registeroptimierungen, TOS im Stack.
; Register werden mit Ausnahme von SR vor jeder Benutzung gesichert !
; Achte darauf, dass auf Stacks ZUERST Platz reserviert wird.
; Es kann jederzeit ein Interrupt dazwischenkommen.
; Deshalb gibt es auch keine "ungesicherten, temporären Register" - obwohl sie viel Platz sparen helfen würden.

; Registerkarte:

; r0    PC
; r1    SP
; r2    SR
; r3    CG

; r4    Datenstackzeiger
; r5    Schleifenindex
; r6    Schleifenlimit
; r7    Freier Arbeitsregister, der nicht gesichert wird, außer beim Interrupteinsprung.
; r8  frei
; r9  frei

; r10   Schwer umkämpft ! Arbeitsregister, die immer gesichert werden.
; r11    ''
; r12    ''
; r13    ''
; r14    ''
; r15    ''

; Dictionary-Aufbau:
;  ---------------------------------
;  1 Byte Flags (immediate, inline und einige andere),
;  1 Byte Namenslänge
;  ---------------------------------
;  Namen. Falls das eine ungerade Byteanzahl ist, eine Null zum Auffüllen,
;         die aber in der Namenslängenzählung nicht enthalten is.
;  ---------------------------------
;  Link. 2 Bytes. Zeigt auf die Flags des vorherigen oder nächsten Wortes.
;  ---------------------------------
;  Danach geht sogleich der Maschinencode los.
;  Immer enthalten, immer ausführbar.
;  Routine + ret -- oder ein call/Sprung, der nie zurückkehrt.
;  ---------------------------------
;  Optional: Datenfeld. Dahinein gibt es aber keinen Link.
;            Wenn es benutzt wird, muss der ret-Opcode gesucht werden.


; Flagkarte: (hex)
;
;   FF  Unsichtbar
;
;   00  Sichtbar
;   10  Immediate
;   20  Inline
;   30  Immediate&Inline zugleich: Immediate, Compile-Only
;   40  Faltbar oder Opcodierbar
;   80  Belegt Ram (automatisch 0-Faltbar)
;
;   Im Detail:
;
;     Faltbar/Opcodierbar:
;     40  0-Faltbar
;     41  1-Faltbar
;     .   ...
;     47  7-Faltbar
;
;     "48" ist die Basis für die Opcodierfälle:
;     49  Opcodierbar Rechenlogik (auch in Kombination mit Inline: 69) --> Werden als 2-Faltbar angenommen.
;     4A  Opcodierbar Speicherschreiben
;     4B  Opcodierbar Speicherlesen
;     4C  Opcodierbar Spezialfall
;

; Flags im Dictionary und ihre Bedeutung:

Flag_invisible  equ 0FFh ; Ungesetzt = Ungebrannt im Flash.
Flag_visible   equ  0b
Flag_immediate  equ  10000b
Flag_inline     equ 100000b

Flag_visible_immediate equ Flag_visible|Flag_immediate
Flag_visible_inline    equ Flag_visible|Flag_inline

Flag_immediate_compileonly equ Flag_visible|Flag_immediate|Flag_inline ; Immediate und Inline wiedersprechen sich. Kann daher die Kombination separat benutzen.

Flag_foldable     equ 1000000b ; Zur Probe für die Faltbar-Flags
Flag_opcodierbar equ    1000b ; Zur Probe für die Opcodier-Optimierungen, wenn Faltbar gesetzt.

; Flag_foldable ist eigentlich ein Optimierbarkeits-Flag. Je nachdem, Faltung oder Opcodierung.

Flag_foldable_0 equ Flag_foldable|0
Flag_foldable_1 equ Flag_foldable|1
Flag_foldable_2 equ Flag_foldable|2
Flag_foldable_3 equ Flag_foldable|3
Flag_foldable_4 equ Flag_foldable|4
Flag_foldable_5 equ Flag_foldable|5
Flag_foldable_6 equ Flag_foldable|6
Flag_foldable_7 equ Flag_foldable|7

; Natürlich sind diese Fälle nicht unbedingt faltbar - aber so wird es im Bitmuster erkannt.
Flag_opcodierbar_rechenlogik       equ Flag_foldable|Flag_opcodierbar|1
Flag_opcodierbar_speicherschreiben equ Flag_foldable|Flag_opcodierbar|2
Flag_opcodierbar_speicherlesen     equ Flag_foldable|Flag_opcodierbar|3
Flag_opcodierbar_spezialfall       equ Flag_foldable|Flag_opcodierbar|4

  ifdef ramverwaltungeinbinden
Flag_ramallot equ 10000000b
Flag_variable equ Flag_ramallot|1
  endif

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; Anfang des Dictionaries !
; Zuerst Kopfdefinitionen.

  ifndef flashdictionaryeinbinden

; Normale Variante für Vorwärtslinks

Latest set 0FFFFh ; Zeiger auf das letzte definierte Wort
Neu    set 0FFFFh ; Variable für aktuellen Zeiger

Wortbirne macro Flagzustand, Name
  align 2
Neu set $ ; Aktuelle Adresse für den Link sichern
  .byte Flagzustand, STRLEN(Name), Name
  align 2
  .word Latest
Latest set Neu
          endm

  else ; flashdictionaryeinbinden

    ifdef ramverwaltungeinbinden
CoreVariablenPointer set nRamDictionaryEnde

CoreVariable macro Name ; Benutze den Mechanismus, um initialisierte Variablen zu erhalten.
CoreVariablenPointer set CoreVariablenPointer - 2
Name equ CoreVariablenPointer
             endm
    endif ; ramverwaltungeinbinden

; Im Prinzip möchte ich jedem Aufruf ein eigenes Label geben, und dies jeweils in dem nächsten erst Definieren.
; Also: Im 1. Aufruf: .word Backlink_1
;       Im 2. Aufruf kann ich Backlink_1 definieren und .word Backlink_2 einsetzen.
;       Und so weiter. Bis gang am Ende der letzte Backlink definiert wird.

Backlink_Zaehler set 0
Backlink_Label   set "\{Backlink_Zaehler}"

Wortbirne macro Flagzustand, Name
  align 2

Backlink_{Backlink_Label} equ $ ; Aktuelle Adresse für den letzten Backlink sichern.

Backlink_Zaehler set Backlink_Zaehler+1 ; Nächstes Label auswählen
Backlink_Label   set "\{Backlink_Zaehler}"  ; und zusammensetzen.

  .byte Flagzustand, STRLEN(Name), Name
  align 2
  .word Backlink_{Backlink_Label} ; Die Vorwärtsreferenz hier einfügen.

          endm

; Ganz am Ende:
; Backlink_{Backlink_Label} equ nFlashDictionaryAnfang ; Dies ist der Zeiger in das veränderliche Flash-Dictionary.

  endif ; flashdictionaryeinbinden

;------------------------------------------------------------------------------
CoreDictionaryAnfang: ; Enthält das Wörterbuch
;------------------------------------------------------------------------------

  include "terminal.asm"
  include "stackjugglers.asm"
  include "logic.asm"

  ifdef doppeltzahleneinbinden
    ifdef fixkommarechnungeneinbinden
      include "fixpoint.asm"
    endif
    include "double.asm"
  endif

  include "starslash.asm"
  include "strings.asm"
  include "calculations.asm"
  include "memory.asm"

  ifdef flashdictionaryeinbinden
    include "flash.asm"
  endif

  include "query.asm"
  include "deepinsight.asm"
  include "numberstrings.asm"
  include "interpreter.asm"
  include "compiler.asm"
  include "controlstructures.asm"

  ifdef caseeinbinden
    include "case.asm"
  endif

  include "comparisions.asm"

  ifdef analogeinbinden
    include "analog.asm"
  endif

  ; Diese Routinen haben viele Abhängigkeiten... Denke daran !

  ifdef interrupthookseinbinden
    include "interrupts.asm"
  endif

  ifdef taktlauschereinbinden
    include "ledcomm.asm"
  endif

;------------------------------------------------------------------------------

  ifdef flashdictionaryeinbinden
; Noch den Backlink in den veränderlichen Teil des Flash-Dictionarys setzen.
; Am Ende des festen Teils kommt immer der Link dahin, wo es Neues gibt.

Backlink_{Backlink_Label} equ nFlashDictionaryAnfang ; Dies ist der Zeiger in das veränderliche Flash-Dictionary.

  else ; Für die Variante, die nur RAM kennt:

CoreFadenende equ Latest
CoreDictionaryEnde equ $

  endif
