;
;    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/>.
; 
 
 
; Messages, string printing and number output routines.
; They are taken from a very early version of my Mecrisp Forth, standalone, but they use the common forth second stack.
; Usefull for you: writeword, writebyte, write and writeln.
; Examples: writeword r11
;           writebyte &P2IN
;           writeln "Hi "
;           writeln "Matthias !"


; Die Meldungsroutinen, die "nebenbei" in Forth entwickelt worden sind, hier als eigenständige Diener.

;------------------------------------------------------------------------------
skipstring: ; ( Adresse -- Adresse ) 
                  ; Überspringt einen String.  
                  ; Takes the address of a counted string and skips it.
;------------------------------------------------------------------------------
  push r10
  push r11

  mov @r4, r10 ; Stringanfangsadresse

    mov.b @r10, r11 ; Hole das Längenbyte nach r11
    inc r10         ; Längenbyte überlesen
    add r11, r10    ; Zahl der Textzeichen hinzuaddieren
  pop r11 

  ; Füll-Null überlesen, falls ungerade Adresse...
  bit #1, r10
  adc r10

  ; Zeiger ist jetzt beim Befehl nach dem String.
  mov r10, @r4

  pop r10
  ret

;------------------------------------------------------------------------------
printcountedstring: ; ( Adresse -- ) 
                ; Prints a counted string, whose address is provided on data stack.
                ; Schreibt einen String über emit hinaus
                ; Beispiel: Moinstring:  .byte 5, "Moin", 10
                  ; So geht es !
                  ; pushda #Moinstring
                  ; call #printcountedstring
;------------------------------------------------------------------------------
        push r10
        push r11

        popda r10          ; Anfangsadresse des Strings
        mov.b @r10, r11    ; Länge des Strings holen
        inc r10            ; r10 ist Adresszeiger
        
-       cmp #0, r11        ; Wenn die Länge Null ist, sind wir fertig.
        je +
        
        decd r4
        clr @r4
        mov.b @r10+, @r4

        call #emit        
        
        dec r11           ; Länge verringern
        jnz -        
        
+       pop r11
        pop r10        
        ret

;------------------------------------------------------------------------------
printinlinestring:
  ; Returnstack: (R: Stringanfangsadresse-im-Rücksprung )
  ; Takes String address from call-return-address, prints it and skips it.
;------------------------------------------------------------------------------
  
  ; Adresse des Strings ist in der Rücksprungadresse enthalten.
  pushda @sp
  call #printcountedstring

  pushda @sp+ ; Adresse vom Returnstack auf den Datenstack legen
  call #skipstring ; Rücksprungadresse auf den Befehl nach dem String setzen.
  mov @r4+, pc ; Ret über den Datenstack


; Comfortable message printers:

write macro Text           ; Mag keine runden Klammern... Doesn't like ( and )
  call #printinlinestring
  .byte STRLEN(Text), Text
  align 2
  endm
  
writeln macro Text         ; Mag keine runden Klammern... Doesn't like ( and )
  call #printinlinestring
  .byte STRLEN(Text)+1, Text, 10
  align 2
  endm


;------------------------------------------------------------------------------
printnibble: ; ( Datennibble -- )
                ; Schreibt vier Bits als Hexadezimalziffer über die serielle Leitung hinaus
                ; Writes four data bits as HEX
;------------------------------------------------------------------------------
  push r10
 
  popda r10 ; Nibble holen
  and #0Fh, r10 ; Nur die untersten 4 Bits beachten

  ; 0 bis 9: 
  cmp #10, r10
  jhs +
  add #48, r10 ; Ab ASCII 48 beginnen die Zahlen  ; Numbers ASCII 48 and above
  jmp ++

+ ; 10 bis 15
  add #55, r10 ; Ab ASCII 65 beginnen die Großbuchstaben  ; Characters ASCII 65 and above
+ pushda r10
  call #emit

  pop r10
  ret

;------------------------------------------------------------------------------
printbyte: ; ( Datenbyte -- )
              ; Schreibt ein Byte hexadezimal über die serielle Leitung hinaus
              ; Writes byte as HEX
;------------------------------------------------------------------------------
  push r10
  mov @r4, r10 
  rra r10
  rra r10
  rra r10
  rra r10
  pushda r10
 
  call #printnibble ; High-Nibble
  call #printnibble ; Low-Nibble
  pop r10
  ret

;------------------------------------------------------------------------------
printword: ; (Datenword -- )
              ; Schreibt ein Word hexadezimal über die serielle Leitung hinaus
              ; Writes word as HEX
;------------------------------------------------------------------------------
  dup
  swpb @r4
  call #printbyte
  call #printbyte
  ret

;------------------------------------------------------------------------------  
; Makros, um diese Routinen komfortabel benutzen zu können
; Macros for comfortable use of the definitions above
;------------------------------------------------------------------------------  

writeword macro Zahl
  pushda Zahl
  call #printword
  endm  
  
writebyte macro Zahl
  decd r4
  clr @r4
  mov.b Zahl, @r4
  call #printbyte
  endm   

  ifdef 0
;------------------------------------------------------------------------------  
printboolean: ; ( -- ) Gibt das Carry-Flag aus
              ; Prints Carry Flag
;------------------------------------------------------------------------------  
  push sr
  jnc +
  write " true "
  pop sr
  ret
+ write " false "
  pop sr
  ret  

writeboolean macro
  call #writeboolean
  endm  

  endif

