; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;                 Build this with the "Project" menu using
;                       "Console Assemble and Link"
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; 28.01.14 KKS: Anpassung an neues Konzept:
;  - Simulator verwendet 2M Flash (ab $0.0000) und 1M RAM (ab $2000.0000)
;  - Beim Lesen externer Files auch andere Speicheraufteilungen
; 13.04.14 KKS: Color@ und Color! ergänzt
; 03.05.15 KKS: Erweiterungen im Timer: SYSTICK, GetTime, GetDate
;               (invert, (d2* und (d2/ durch l/r/ashift ersetzt
; 10.05.15 KKS: Debug verbessert - Nur dann werden Register gespeichert
; 13.05.15 KKS: +, -, L/R/ASHIFT verwendet W als Überlauf
; 13.06.15 KKS: Flash/RAM getrennt:
;               -p           Kein Flash verwendet
;               +paaaa.ssss  Flash mit Anfangsadresse a und Größe s
;               +vaaaa.ssss  RAM (Default 1M ab 0)
;               +h           Harward (Default)
;               -h           Kein Harward = Neumann (RAM wie ROM behandelt)
;               +a           Align (4 bei @, 2 bei w@)
;               -a           kein Align
; 03.07.15 KKS: Fehlerkorrektur im Nest
; 03.07.15 KKS: Fehlerkorrektur im Nest
; 17.07.15 KKS: Flash-Befehle
; 01.08.15 KKS: Alle direkten Flash-Schreibbefehle deaktiviert
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««« 

    .486                                    ; create 32 bit code
    .model flat, stdcall                    ; 32 bit memory model
    option casemap :none                    ; case sensitive
 
    WIN32_LEAN_AND_MEAN equ 1
    include \masm32\include\windows.inc     ; always first
    include \masm32\macros\macros.asm       ; MASM support macros

  ; ------------------------------------------------
  ; include files that have MASM format prototypes 
  ; for function calls
  ; ------------------------------------------------
    include \masm32\include\masm32.inc
    include \masm32\include\gdi32.inc
    include \masm32\include\user32.inc
    include \masm32\include\kernel32.inc
    include \masm32\include\msvcrt.inc
    include \masm32\include\shlwapi.inc     ; für extrahieren des Filenamens

  ; ------------------------------------------------
  ; Library files that have definitions for function
  ; exports and tested reliable prebuilt code.
  ; ------------------------------------------------
    includelib \masm32\lib\masm32.lib
    includelib \masm32\lib\gdi32.lib
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib
    includelib \masm32\lib\msvcrt.lib
    includelib \masm32\lib\shlwapi.lib

  ; ------------------------------------------------
  ; Konstanten
  ; ------------------------------------------------
;    INVALID_FILE_SIZE equ -2
;    INVALID_SET_FILE_POINTER equ -3
   
  ; ------------------------------------------------
  ; Nicht initialisierte Daten
  ; ------------------------------------------------
    .data

  ; Console-Handling
    hStdOut          dd      0          ; Ausgabe-Handle
    dummy            dd      0,0        ; temporäre Daten
    topleft          dd      0,0        ; Position oben links immer 0 für Löschen
    debugaddr        dd      0          ; Debug-Adresse
    debug            db      0          ; Ende bei 1, Debug bei 2, 4 für Singlestep, 8 für Breakpoint
    D_END            equ     1
    D_TRACE          equ     2
    D_STEP           equ     4
    D_BREAKPOINT     equ     8
    D_ALL            equ     15
    cbuf             db 15 dup (0)      ; Für Debug-Ausgabe


  ; CONSOLE_SCREEN_BUFFER_INFO
    dwSize           dw      0,0        ; X/Y
    dwCursor         dw      0,0        ; X/Y
    wAttributes      dw      0          ; Flag
    srWindow         dw      0,0,0,0    ; Links,Oben,Rechts,Unten
    dwMaximum        dw      0,0

    fpc              dd      0          ; FORTH-Programmzeiger
    fsp              dd      0          ; FORTH-Stackpointer
    frp              dd      0          ; FORTH-Returnstackpointer
    fip              dd      0          ; FORTH-Instruction-Pointer wenn indirect
    fw               dd      0          ; FORTH-Working-Register
    
  ; Informationen zu genutzten Speicher
    pvflag           dd      0          ; Bit 0=1: RAM reserviert; Bit 1=1: Flash reserviert
                                        ; Bit 2=1: ROM nutzen; Bit 3=1: Harward; Bit 4=1: Align
    PV_RAM           equ     1
    PV_ROM           equ     2
    PV_TOROM         equ     4
    PV_HARWARD       equ     8
    PV_ALIGN         equ     16

    prgptr           dd      0          ; Pointer auf Programm
    prgoff           dd      0          ; Anfangsadresse Programm
    prgsize          dd      0          ; Reservierter Speicher für Flash
    varptr           dd      0          ; Pointer auf Variable
    varoff           dd      0          ; Anfangsadresse Variable
    varsize          dd      0          ; Reservierter Speicher für Variable


  ; Zusatz, für Abfrage der Eingabezeile
    CommandLine      dd      0		; Zeiger auf Eingaben
    lpArg            dd      0		; Pointer auf erstes Argument
    hFile            dd      0		; Filehandle
    br               dd      0		; Gelesene Bytes
    flen             dd      0          ; Filelänge

  ; Zusatz für Filebefehle unter Windows
    fsizehigh        dd      0          ; High-Wert für Fileposition und Größe

  ; Zusatz für Baudratenänderungen an serieller Schnittstelle
    hSerialPort      dd      0          ; handle for serial port
    Baudrate         dd      0          ; baud rate for serial port
    SerialFlag       dd      0          ; flag for serial port
    SerialSettings   DCB {0}            ; settings for serial port
    SerialTimeOuts   COMMTIMEOUTS {0}   ; timeout settings for serial port

  ; Systemtimer-Variable
    systime          SYSTEMTIME <>      ; Jahr ... Millisekunden
     
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Hauptprogramm
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .code                       ; Tell MASM where the code starts

start:                          ; The CODE entry point to the program
;   int 3                      ; für WinDbg

; CTRL+C abschalten
    invoke  GetStdHandle,STD_INPUT_HANDLE
    invoke  SetConsoleMode,eax, 0

; Output-Handle für PAGE ... merken
    invoke  GetStdHandle,STD_OUTPUT_HANDLE
    mov     [hStdOut],eax

; FORTH initialisieren
;    print  chr$("FORTH-System initialisiert",13,10)
    call    mcFInit             ; Register und Speicher initialisieren

; Wenn Debugger aktiv, zuerst Anzeige
    test    debug,D_ALL
    jnz     mcF0
mcFLoop:
    call    mcFStep
; Prüfen, ob evtl. Breakpoint aktiv
mcF0:
    test    debug,D_BREAKPOINT
    jz      mcF1
    mov     eax,fpc             ; PC
    cmp     eax,debugaddr       ; mit Debug-Adresse vergleichen
    jnz     mcF1
    mov     debug,D_TRACE+D_STEP ; Singlestep-Debug
; Ausgabe des nächsten Befehls
mcF1:
    test    debug,D_TRACE       ; Debug-Ausgabe ?
    jz      mcF2
    call    mcFTrace
mcF2:
    test    debug,D_END         ; Ende ?
    jnz     mcFEnd
    test    debug,D_STEP        ; Singlestep ?
    jz      mcFLoop
; Option für Debugger: ESC, Enter, S, U
    call    key
    cmp     al,01bh             ; ESC: Ende
    jz      mcFEnd
    cmp     al,00dh             ; CR: Ohne Debug weiter
    jnz     mcF3
    mov     debug,0
    jmp     mcFLoop
mcF3:
    cmp     al,073h             ; S: Ohne Debuggen bis nächste Adresse
    jnz     mcF4
    mov     eax,fpc
    add     eax,5
    mov     debugaddr,eax
    mov     debug,D_BREAKPOINT
    jmp     mcFLoop
mcF4:
    cmp     al,075h             ; U: weiter bis Exit
    jnz     mcFLoop
    mov     eax,frp             ; EAX: RStack
    call    getvarptr
    mov     eax,[eax]
    mov     debugaddr,eax
    mov     al,D_BREAKPOINT
    mov     debug,al
    jmp     mcFLoop
mcFEnd:
;   int 3                       ; !!! Debug : Test ob immer aufgerufen

;    print  chr$("FORTH-System beendet",13,10)
    test    pvflag,PV_ROM       ; Ist getrenntes Flash verfügbar
    jz      mcFEnd2
    free    prgptr              ; Flash freigeben
mcFEnd2:
    free    varptr              ; RAM freigeben
;    invoke  wait_key
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

; Tabelle für Befehle  
ALIGN 4
mcFStep_Table:
    dd      mcFStep_00      ; Befehl $00: CALL
    dd      mcFStep_01      ; Befehl $01: BRANCH 
    dd      mcFStep_02      ; Befehl $02: 0BRANCH
    dd      mcFStep_03      ; Befehl $03: NBRANCH
    dd      mcFStep_04      ; Befehl $04: LIT
    dd      mcFStep_05      ; Befehl $05: EXIT
    dd      mcFStep_06      ; Befehl $06: EXECUTE
    dd      mcFStep_07      ; Befehl $07: SP@
    dd      mcFStep_08      ; Befehl $08: SP!
    dd      mcFStep_09      ; Befehl $09: DROP
    dd      mcFStep_0A      ; Befehl $0A: DUP
    dd      mcFStep_0B      ; Befehl $0B: OVER
    dd      mcFStep_0C      ; Befehl $0C: SWAP
    dd      mcFStep_0D      ; Befehl $0D: RP@
    dd      mcFStep_0E      ; Befehl $0E: RP!
    dd      mcFStep_0F      ; Befehl $0F: >R
    dd      mcFStep_10      ; Befehl $10: R>
    dd      mcFStep_11      ; Befehl $11: R@
    dd      mcFStep_12      ; Befehl $12: RDROP
    dd      mcFStep_13      ; Befehl $13: AND
    dd      mcFStep_14      ; Befehl $14: OR
    dd      mcFStep_15      ; Befehl $15: XOR
    dd      mcFStep_16      ; Befehl $16: +C
    dd      mcFStep_17      ; Befehl $17: -C
    dd      mcFStep_18      ; Befehl $18: LSHIFT
    dd      mcFStep_19      ; Befehl $19: RSHIFT
    dd      mcFStep_1a      ; Befehl $1A: ASHIFT
    dd      mcFStep_1B      ; Befehl $1B: UM*
    dd      mcFStep_1C      ; Befehl $1C: UM/MOD
    dd      mcFStep_1D      ; Befehl $1D: 0<
    dd      mcFStep_1E      ; Befehl $1E: U<
    dd      mcFStep_1F      ; Befehl $1F: <
    dd      mcFStep_20      ; Befehl $20: c@
    dd      mcFStep_21      ; Befehl $21: c!
    dd      mcFStep_22      ; Befehl $22: W@
    dd      mcFStep_23      ; Befehl $23: W!
    dd      mcFStep_24      ; Befehl $24: @
    dd      mcFStep_25      ; Befehl $25: !
    dd      mcFStep_26      ; Befehl $26: C@P
    dd      mcFStep_27      ; Befehl $27: C!P
    dd      mcFStep_28      ; Befehl $28: W@P
    dd      mcFStep_29      ; Befehl $29: W!P
    dd      mcFStep_2A      ; Befehl $2A: @P
    dd      mcFStep_2B      ; Befehl $2B: !P
    dd      mcFStep_2C      ; Befehl $2C: C@IO
    dd      mcFStep_2D      ; Befehl $2D: C!IO
    dd      mcFStep_2E      ; Befehl $2E: W@IO
    dd      mcFStep_2F      ; Befehl $2F: W!IO
    dd      mcFStep_30      ; Befehl $30: @IO
    dd      mcFStep_31      ; Befehl $31: !IO
    dd      mcFStep_32      ; Befehl $32: C@X
    dd      mcFStep_33      ; Befehl $33: C!X
    dd      mcFStep_34      ; Befehl $34: W@X
    dd      mcFStep_35      ; Befehl $35: W!X
    dd      mcFStep_36      ; Befehl $36: @X
    dd      mcFStep_37      ; Befehl $37: !X
    dd      mcFStep_38      ; Befehl $38: FIP@
    dd      mcFStep_39      ; Befehl $39: FIP!
    dd      mcFStep_3A      ; Befehl $3A: FW@
    dd      mcFStep_3B      ; Befehl $3B: FW!
    dd      mcFStep_3C      ; Befehl $3C: NEST
    dd      mcFStep_3D      ; Befehl $3D: >CODE
    dd      mcFStep_3E      ; Befehl $3E: SYSCALL
    dd      mcFStep_3F      ; Befehl $3F: NOP
CFZ_MAX	equ 64

mcFStep_Table_00xx:
    dd      mcFStep_0000    ; Befehl $0000: BYE
    dd      mcFStep_0001    ; Befehl $0001: DEBUG
    dd      mcFStep_0002    ; Befehl $0002: GETPAR
    dd      mcFStep_0003    ; Befehl $0003: IRQOFF
    dd      mcFStep_0004    ; Befehl $0004: IRQON
    dd      mcFStep_0005    ; Befehl $0005: IRQSET
    dd      mcFStep_0006    ; Befehl $0006: V
CFS_MAX	equ 7

mcFStep_Table_01xx:
    dd      mcFStep_0100    ; Befehl $0100: XINIT
    dd      mcFStep_0101    ; Befehl $0101: XALLOC
    dd      mcFStep_0102    ; Befehl $0102: XRELLOC
    dd      mcFStep_0103    ; Befehl $0103: XFREE
    dd      mcFStep_0104    ; Befehl $0104: >X
    dd      mcFStep_0105    ; Befehl $0105: P>X
    dd      mcFStep_0106    ; Befehl $0106: S>X
    dd      mcFStep_0107    ; Befehl $0107: R>X
    dd      mcFStep_0108    ; Befehl $0108: FLASH-SE
    dd      mcFStep_0109    ; Befehl $0109: FLASH-SW
    dd      mcFStep_010A    ; Befehl $010A: FLASH-E
    dd      mcFStep_010B    ; Befehl $010B: FLASH-W
CFX_MAX equ 12

mcFStep_Table_02xx:
    dd      mcFStep_0200    ; Befehl $0200: CINIT
    dd      mcFStep_0201    ; Befehl $0201: SYSTICK
    dd      mcFStep_0202    ; Befehl $0202: TIME@
    dd      mcFStep_0203    ; Befehl $0203: TIME!
    dd      mcFStep_0204    ; Befehl $0204: DATE@
    dd      mcFStep_0205    ; Befehl $0205: DATE!
    dd      mcFStep_0206    ; Befehl $0206: WAITMS
CFC_MAX	equ 7

mcFStep_Table_03xx:
    dd      mcFStep_0300    ; Befehl $0300: TINIT
    dd      mcFStep_0301    ; Befehl $0301: KEY
    dd      mcFStep_0302    ; Befehl $0302: EMIT
    dd      mcFStep_0303    ; Befehl $0303: KEY?
    dd      mcFStep_0304    ; Befehl $0304: EMIT?
    dd      mcFStep_0305    ; Befehl $0305: EXPECT
    dd      mcFStep_0306    ; Befehl $0306: PAGE
    dd      mcFStep_0307    ; Befehl $0307: ATXYMAX
    dd      mcFStep_0308    ; Befehl $0308: ATXY?
    dd      mcFStep_0309    ; Befehl $0309: ATXY
    dd      mcFStep_030A    ; Befehl $030A: COLOR@
    dd      mcFStep_030B    ; Befehl $030B: COLOR!
    dd      mcFStep_030C    ; Befehl $030C: AT@
    dd      mcFStep_030D    ; Befehl $030D: AT!
CFT_MAX	equ 14

mcFStep_Table_04xx:
    dd      mcFStep_0400    ; Befehl $0400: FINIT
    dd      mcFStep_0401    ; Befehl $0401: FCREATE
    dd      mcFStep_0402    ; Befehl $0402: FRENAME
    dd      mcFStep_0403    ; Befehl $0403: FDELETE
    dd      mcFStep_0404    ; Befehl $0404: FOPEN
    dd      mcFStep_0405    ; Befehl $0405: FCLOSE
    dd      mcFStep_0406    ; Befehl $0406: FSIZE@
    dd      mcFStep_0407    ; Befehl $0407: FSIZE!
    dd      mcFStep_0408    ; Befehl $0408: FPOS@
    dd      mcFStep_0409    ; Befehl $0409: FPOS!
    dd      mcFStep_040A    ; Befehl $040A: FREAD
    dd      mcFStep_040B    ; Befehl $040B: FWRITE
    dd      mcFStep_040C    ; Befehl $040C: FFIRST
    dd      mcFStep_040D    ; Befehl $040D: FNEXT
    dd      mcFStep_040E    ; Befehl $040E: FDIR@
    dd      mcFStep_040F    ; Befehl $040F: FDIR!
    dd      mcFStep_0410    ; Befehl $0410: FDRV@
    dd      mcFStep_0411    ; Befehl $0411: FDRV!
    dd      mcFStep_0412    ; Befehl $0412: FFREE
    dd      mcFStep_0413    ; Befehl $0413: FPAR@	
    dd      mcFStep_0414    ; Befehl $0414: FPAR!	
    dd      mcFStep_0415    ; Befehl $0415: FCOPY	
CFF_MAX	equ 22

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Zusatz zur Verwendung des richtigen Speicher
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Programmpointer: EAX enthält Adresse => Pointer für PRG/VAR in EAX
getprgptr:
    test    pvflag,PV_HARWARD        ; Harward ?
    jnz     getprgptr1
    sub     eax,prgoff              ; Neumann: - Offset Programm
    cmp     eax,prgsize             ; Test, ob innerhalb Programm
    jb      getprgptr2              ; ja: nur Programmpointer addieren
    add     eax,prgoff              ; nein:    + Offset Programm
    sub     eax,varoff              ;          - Offset Variable
    cmp     eax,varsize             ; !!! Test, ob innerhalb Variable
    jnb     getprgptrerror          ; !!! nein: Fehler
    add     eax,varptr              ;          + Pointer Variable
    ret
getprgptr1:
    sub     eax,prgoff              ; Harward: - Offset Programm
    cmp     eax,prgsize             ; !!! Test, ob innerhalb Programm
    jnb     getprgptrerror          ; !!! nein: Fehler
getprgptr2:
    add     eax,prgptr              ;          + Pointer Programm
    ret
getprgptrerror:                     ; !!!
    push    eax                     ; !!!
    print   chr$(13,10,"GETPRGPTR - Error") ; !!!
    pop     eax                     ; !!!
    call    regdump                 ; !!!
    call    ptrdump                 ; !!!
    invoke  wait_key                ; !!!
    jmp     mcFEnd                  ; !!!

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; FORTH-Adresse aus Programm-Pointer
getprgaddr:
    test    pvflag,8                ; Harward ?
    jnz     getprgaddr1
    sub     eax,prgptr              ; Neumann: - Pointer Programm
    cmp     eax,prgsize             ; Test ob im Bereich (+1, für Call)
    jbe     getprgaddr2             ; ja: nur Programmoffset addieren
    add     eax,prgptr              ; nein:    + Pointer Programm
    sub     eax,varptr              ;          - Pointer Variable
    add     eax,varoff              ;          + Offset Variable 
    ret
getprgaddr1:
    sub     eax,prgptr              ; Harward: - Pointer Program
getprgaddr2:
    add     eax,prgoff              ;          + Offset Programm
    ret

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; VariablenAdresse: EAX enthält Adresse => Pointer für Variable in EAX
getvarptr:
    test    pvflag,8                ; Harward ?
    jnz     getvarptr1
    sub     eax,varoff              ; Neumann: - Offset Variable
    cmp     eax,varsize             ; Test, ob innerhalb Variable
    jb      getvarptr2              ; ja: nur Variablenpointer addieren
    add     eax,varoff              ; nein:    + Offset Variable
    sub     eax,prgoff              ;          - Offset Programm
    cmp     eax,prgsize             ; !!! Test, ob innerhalb Programm
    jnb     getvarptrerror          ; !!! nein: Fehler
    add     eax,prgptr              ;          + Pointer Program
    ret
getvarptr1:
    sub     eax,varoff              ; Neumann: - Offset Variable
    cmp     eax,varsize             ; !!! Test, ob innerhalb Variable
    jnb     getvarptrerror          ; !!! nein: Fehler
getvarptr2:
    add     eax,varptr              ;          + Pointer Variable
    ret
getvarptrerror:                     ; !!!
    push    eax                     ; !!!
    print   chr$(13,10,"GETVARPTR - Error") ; !!!
    pop     eax                     ; !!!
    call    regdump                 ; !!!
    call    ptrdump                 ; !!!
    invoke  wait_key                ; !!!
    jmp     mcFEnd                  ; !!!

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Variablenpointer: EAX enthält Adresse => Pointer für Variable in EAX
getvaraddr:
    test    pvflag,8                ; Harward ?
    jnz     getvaraddr1
    sub     eax,varptr              ; Neumann: - Pointer Variable
    cmp     eax,varsize             ; Test ob im Bereich (+1, für Call)
    jbe     getvaraddr2             ; ja: nur Variablenoffset addieren
    add     eax,varptr              ; nein:    + Pointer Variable
    sub     eax,prgptr              ;          - Pointer Programm
    add     eax,prgoff              ;          + Offset Programm 
    ret
getvaraddr1:
    sub     eax,varptr              ; Neumann: - Pointer Variable
getvaraddr2:
    add     eax,varoff              ;          + Offset Variable
    ret

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Ein Befehl im mcFORTH
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; ESI => PC+FPRG; EBX => SP+FPRG; EDX => RP+FPRG
mcFStep:
; Register laden
    mov     eax,fpc                 ; ESI: FPC + PRG-Pointer
    call    getprgptr
    mov     esi,eax
    mov     eax,fsp                 ; EBX: SP + VAR-Pointer
    call    getvarptr
    mov     ebx,eax
    mov     eax,frp                 ; EDX: RP + FPRG
    call    getvarptr
    mov     edx,eax
; Befehl ausführen
mcFStep1:
    xor     eax,eax                 ; EAX auf 0
    lodsb                           ; Opcode holen
;    call    regdump                 ; !!! Debug
    cmp     al,CFZ_MAX              ; gültig ?
    jnb     mcFIllegal              ; Nein: Fehler
    sal     eax,2
    add     eax,offset mcFStep_Table ; + Tabellenanfang
mcFStepEx:
    call    dword ptr [eax]
    test    debug,D_ALL             ; Ohne Debugger sofort weiter
    jz      mcFStep1                ; schneller, da keine Register zu retten sind
; Register wieder speichern
mcFStep2:
    mov     eax,edx                 ; EDX: FRP (im RAM)
    call    getvaraddr
    mov     frp,eax
    mov     eax,ebx                 ; EBX: FSP (im RAM)
    call    getvaraddr
    mov     fsp,eax
    mov     eax,esi                 ; ESI: FPC (im Programm)
    call    getprgaddr
    mov     fpc,eax
    ret
mcFIllegal_SysCall:
    sub     ebx,4
    mov     [ebx],ecx               ; SysCall# speichern
mcFIllegal:
    dec     esi
    call    mcFStep2
    print   chr$(13,10,13,10)       ; !!!
    call    regdump                 ; !!!
    call    ptrdump                 ; !!!
    call    mcFTrace
    print   chr$(13,10,13,10,"Illegal Opcode !!!",13,10)  ; !!!
    invoke  wait_key                ; !!!
    or      debug,D_END
    jmp     mcFEnd                  ; !!!
; ------------------------------------------------
; Befehl $3E: SYSCALL (# auf dem Stack)
mcFStep_3E:
    mov     ecx,[ebx]       ; Wert holen
    add     ebx,4           ; und vom Stack nehmen
    mov     eax,ecx
    sar     eax,8           ; High-Byte
    cmp     eax,0           ; Systembefehle ?
    jnz     mcFStep_01xx
    cmp     cl,CFS_MAX
    jnb     mcFIllegal_SysCall
    mov     al,cl           ; nur Lowbyte
    sal     eax,2
    add     eax,offset mcFStep_Table_00xx ; + Tabellenanfang
    jmp     dword ptr [eax]
mcFStep_01xx:
    cmp     eax,1           ; Speicherbefehle ?
    jnz     mcFStep_02xx
    cmp     cl,CFX_MAX
    jnb     mcFIllegal_SysCall
    mov     al,cl           ; nur Lowbyte
    sal     eax,2
    add     eax,offset mcFStep_Table_01xx ; + Tabellenanfang
    jmp     dword ptr [eax]
mcFStep_02xx:
    cmp     eax,2           ; Timerbefehle ?
    jnz     mcFStep_03xx
    cmp     cl,CFC_MAX
    jnb     mcFIllegal_SysCall
    mov     al,cl           ; nur Lowbyte
    sal     eax,2
    add     eax,offset mcFStep_Table_02xx ; + Tabellenanfang
    jmp     dword ptr [eax]
mcFStep_03xx:
    cmp     eax,3           ; Terminalbefehle ?
    jnz     mcFStep_04xx
    cmp     cl,CFT_MAX
    jnb     mcFIllegal_SysCall
    mov     al,cl           ; nur Lowbyte
    sal     eax,2
    add     eax,offset mcFStep_Table_03xx ; + Tabellenanfang
    jmp     dword ptr [eax]
mcFStep_04xx:
    cmp     eax,4           ; Filebefehle ?
    jnz     mcFIllegal_SysCall
    cmp     cl,CFF_MAX
    jnb     mcFIllegal_SysCall
    mov     al,cl           ; nur Lowbyte
    sal     eax,2
    add     eax,offset mcFStep_Table_04xx ; + Tabellenanfang
    jmp     dword ptr [eax]
; ------------------------------------------------
; Befehl $00: CALL
mcFStep_00:
    lodsd                   ; Offset nach EBX
    mov     ecx,eax
    mov     eax,esi         ; Programmadresse ermitteln
    call    getprgaddr
    sub     edx,4           ; und zum Returnstack
    mov     [edx],eax
    add     eax,ecx         ; PC + Offset
    call    getprgptr       ; Pointer ermitteln
    mov     esi,eax         ; und wieder nach FPC/ESI
    ret
; ------------------------------------------------
; Befehl $01: BRANCH
mcFStep_01:
    lodsd                   ; Offset holen
    add     esi,eax         ; + Adresse
    ret
; ------------------------------------------------
; Befehl $02: 0BRANCH
mcFStep_02:
    mov     ecx,[ebx]       ; Flag vom Stack zu CX
    add     ebx,4           ; drop
    lodsd                   ; Offset holen
    and     ecx,ecx         ; Flag = 0?
    jnz     mcFStep_02a     ; Nein: Offset ignorieren
    add     esi,eax         ; Offset zu PC addieren
mcFStep_02a:
    ret
; ------------------------------------------------
; Befehl $03: NBRANCH
mcFStep_03:
    mov     eax,[edx]       ; Zähler holen
    and     eax,eax         ; 0 ?
    jz      mcFStep_03a     ; Ja: Ende
    dec     eax             ; Zähler - 1
    mov     [edx],eax
    lodsd                   ; Offset holen
    add     esi,eax         ; + Adresse
    ret
mcFStep_03a:
    add     edx,4           ; RP + 4: Zähler entfernen
    add     esi,4           ; Offset überspringen
    ret
; ------------------------------------------------
; Befehl $04: LIT
mcFStep_04:
    lodsd                   ; Literal zu EAX
    sub     ebx,4           ; und zum Stack
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $05: EXIT
mcFStep_05:
    mov     eax,[edx]       ; Rücksprungadresse
    add     edx,4           ; vom Stack holen
    call    getprgptr       ; und Pointer ermitteln
    mov     esi,eax
    ret
; ------------------------------------------------
; Befehl $06: EXECUTE
mcFStep_06:
    mov     eax,esi         ; Programmadresse ermitteln
    call    getprgaddr
    sub     edx,4           ; und zum Returnstack
    mov     [edx],eax
    mov     eax,[ebx]       ; neue Adresse holen
    add     ebx,4
    call    getprgptr       ; Pointer ermitteln
    mov     esi,eax         ; und wieder nach FPC/ESI
    ret
; ------------------------------------------------
; Befehl $07: SP@
mcFStep_07:
    mov     eax,ebx         ; Stackpointer holen
    call    getvaraddr      ; und in Adresse umrechnen
    sub     ebx,4
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $08: SP!
mcFStep_08:
    mov     eax,[ebx]       ; Stackpointer holen
    add     ebx,4
    test    pvflag,PV_ALIGN
    jz      mcFStep_08a
    test    eax,3           ; untere 2 Bits müssen 0 sein
    jnz     mcFNotAligned
mcFStep_08a:
    call    getvarptr       ; und in Pointer umrechnen
    mov     ebx,eax
    ret
mcFNotAligned:
    sub     ebx,4
    mov     [ebx],eax               ; Adresse speichern
    dec     esi
    call    mcFStep2
    print   chr$(13,10,13,10)       ; !!!
    call    regdump                 ; !!!
    call    ptrdump                 ; !!!
    call    mcFTrace
    print   chr$(13,10,13,10,"Address not Aligned",13,10) ; !!!
    invoke  wait_key                ; !!!
    or      debug,D_END
    jmp     mcFEnd                  ; !!!
; ------------------------------------------------
; Befehl $09: DROP
mcFStep_09:
    add     ebx,4
    ret
; ------------------------------------------------
; Befehl $0A: DUP
mcFStep_0A:
    mov     eax,[ebx]       ; Wert holen
    sub     ebx,4
    mov     [ebx],eax       ; und speichern
    ret
; ------------------------------------------------
; Befehl $0B: OVER
mcFStep_0B:
    mov     eax,[4+ebx]     ; Wert holen
    sub     ebx,4
    mov     [ebx],eax       ; und speichern
    ret
; ------------------------------------------------
; Befehl $0C: SWAP
mcFStep_0C:
    mov     eax,[ebx]       ; 1. Wert holen
    mov     ecx,[4+ebx]     ; 2. Wert holen
    mov     [ebx],ecx       ; 2. Wert speichern
    mov     [4+ebx],eax     ; 1. Wert speichern
    ret
; ------------------------------------------------
; Befehl $0D: RP@
mcFStep_0D:
    mov     eax,edx         ; RP lesen
    call    getvaraddr      ; und in Adresse umrechnen
    sub     ebx,4           ; push
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0E: RP!
mcFStep_0E:
    mov     eax,[ebx]       ; RP holen
    add     ebx,4           ; pop
    test    pvflag,PV_ALIGN
    jz      mcFStep_0Ea
    test    eax,3           ; untere 2 Bits müssen 0 sein
    jnz     mcFNotAligned
mcFStep_0Ea:
    call    getvarptr       ; und in Pointer umrechnen
    mov     edx,eax         ; und übernehmen
    ret
; ------------------------------------------------
; Befehl $0F: >R
mcFStep_0F:
    mov     eax,[ebx]
    add     ebx,4
    sub     edx,4
    mov     [edx],eax
    ret
; ------------------------------------------------
; Befehl $10: R>
mcFStep_10:
    mov     eax,[edx]
    add     edx,4
    sub     ebx,4
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $11: R@
mcFStep_11:
    mov     eax,[edx]
    sub     ebx,4
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $12: RDROP
mcFStep_12:
    add     edx,4
    ret
; ------------------------------------------------
; Befehl $13: AND
mcFStep_13:
    mov     eax,[ebx]       ; Wert 1 holen
    add     ebx,4           ; drop
    and     [ebx],eax       ; AND Wert 2
    ret
; ------------------------------------------------
; Befehl $14: OR
mcFStep_14:
    mov     eax,[ebx]       ; Wert 1 holen
    add     ebx,4           ; drop
    or      [ebx],eax       ; OR Wert 2
    ret
; ------------------------------------------------
; Befehl $15: XOR
mcFStep_15:
    mov     eax,[ebx]       ; Wert 1 holen
    add     ebx,4           ; drop
    xor     [ebx],eax       ; XOR Wert 2
    ret
; ------------------------------------------------
; Befehl $16: +C
mcFStep_16:
    mov     eax,[ebx]       ; Wert 1 holen
    add     ebx,4           ; drop
    add     [ebx],eax       ; Addieren (setzt Carry)
    mov     eax,0           ; Flag = 0
    jnc     mcFStep_16a     ; Bei Carry: 1 ablegen
    inc     eax
mcFStep_16a:
    mov     fw,eax
    ret
; ------------------------------------------------
; Befehl $17: -C
mcFStep_17:
    mov     eax,[ebx]       ; Wert 1 holen
    add     ebx,4           ; drop
    sub     [ebx],eax       ; Subtrahieren (setzt Carry)
    mov     eax,0           ; Flag = 0
    jnc     mcFStep_17a     ; Bei Carry: 1
    inc     eax
mcFStep_17a:
    mov     fw,eax
    ret
; ------------------------------------------------
; Befehl $18: LSHIFT
mcFStep_18:
    mov     ecx,[ebx]       ; Zähler in CL
    add     ebx,4
    mov     eax,[ebx]
    shl     eax,cl          ; Shift Links
    mov     [ebx],eax
    mov     eax,0
    rcl     eax,1    
    mov     fw,eax
    ret
; ------------------------------------------------
; Befehl $19: RSHIFT
mcFStep_19:
    mov     ecx,[ebx]       ; Zähler in CL
    add     ebx,4
    mov     eax,[ebx]
    shr     eax,cl          ; Shift Rechts
    mov     [ebx],eax
    mov     eax,0
    rcr     eax,1    
    mov     fw,eax
    ret
; ------------------------------------------------
; Befehl $1A: ASHIFT
mcFStep_1a:
    mov     ecx,[ebx]       ; Zähler in CL
    add     ebx,4
    mov     eax,[ebx]
    sar     eax,cl          ; Shift Rechts (MSB bleibt)
    mov     [ebx],eax
    mov     eax,0
    rcr     eax,1    
    mov     fw,eax
    ret
; ------------------------------------------------
; Befehl $1B: UM*
mcFStep_1B:
    mov     ecx,edx         ; Returnstackzeiger nach ECX
    mov     eax,[ebx+4]     ; Wert holen
    mov     edx,[ebx]       ; Wert holen
    mul     edx             ; Multiplizieren
    mov     [ebx+4],eax     ; Low
    mov     [ebx],edx       ; High
    mov     edx,ecx         ; Returnstackzeiger zurück
    ret
; ------------------------------------------------
; Befehl $1C: UM/MOD
mcFStep_1C:
    mov     ecx,[ebx]       ; Divisor holen
    add     ebx,4           ; Divisor entfernen
    cmp     ecx,0
    jz      mcFStep_1Cb     ; /0 => -1 -1 
    push    edx             ; Returnstackzeiger sichern
    mov     edx,[ebx]       ; High holen
    mov     eax,[ebx+4]     ; low holen
    cmp     edx,ecx
    jae     mcFStep_1Ca     ; Überlauf => -1 -1
    div     ecx             ; Dividieren
    mov     [ebx+4],edx     ; Rest
    mov     [ebx],eax       ; Divident
    pop     edx             ; Returnstackzeiger restaurieren
    ret
mcFStep_1Ca:
    pop     edx             ; Returnstackzeiger restaurieren
mcFStep_1Cb:
    mov     eax,-1
    mov     [ebx+4],eax     ; Rest = -1
    mov     [ebx],eax       ; Divident = -1
    ret
; ------------------------------------------------
; Befehl $1D: 0<
mcFStep_1D:
    mov     eax,[ebx]       ; Wert holen
    sal     eax,1           ; MSB zu Carry
    mov     eax,0           ; Flag = 0
    jnc     mcFStep_1da     ; Bei Carry: -1
    dec     eax
mcFStep_1da:
    mov     [ebx],eax       ; Nur Flag lassen
    ret
; ------------------------------------------------
; Befehl $1E: U<
mcFStep_1E:
    mov     eax,[ebx]       ; Wert 1 holen
    add     ebx,4           ; drop
    sub     [ebx],eax       ; Subtrahieren (setzt Carry)
    mov     eax,0           ; Flag = 0
    jnb     mcFStep_1ea     ; wenn kleiner
    dec     eax
mcFStep_1ea:
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $1F: <
mcFStep_1F:
    mov     eax,[ebx]       ; Wert 1 holen
    add     ebx,4           ; drop
    sub     [ebx],eax       ; Subtrahieren (setzt Carry)
    mov     eax,0           ; Flag = 0
    jnl     mcFStep_1fa     ; wenn kleiner (mit Vorzeichen)
    dec     eax
mcFStep_1fa:
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $20: C@
mcFStep_20:
    mov     eax,[ebx]       ; Adresse holen
    call    getvarptr
    xor     ecx,ecx
    mov     cl,[eax]        ; Wert holen
    mov     [ebx],ecx       ; und zum Stack
    ret
; ------------------------------------------------
; Befehl $21: C!
mcFStep_21:
    mov     eax,[ebx]       ; Adresse holen
    add     ebx,4
    call    getvarptr       ; in Pointer umrechnen
    mov     ecx,[ebx]       ; Wert holen
    add     ebx,4           ; drop
    mov     [eax],cl
    ret
; ------------------------------------------------
; Befehl $22: W@
mcFStep_22:
    mov     eax,[ebx]       ; Adresse holen
    add     ebx,4
    test    pvflag,PV_ALIGN
    jz      mcFStep_22a
    test    eax,1           ; untere Bit muss 0 sein
    jnz     mcFNotAligned
mcFStep_22a:
    call    getvarptr       ; in Pointer umrechnen
    xor     ecx,ecx         ; CX = 0
    mov     cx,[eax]        ; Wert holen (16bit)
    sub     ebx,4
    mov     [ebx],ecx       ; und zum Stack
    ret
; ------------------------------------------------
; Befehl $23: w!
mcFStep_23:
    mov     eax,[ebx]       ; Adresse holen
    add     ebx,4           ; drop
    test    pvflag,PV_ALIGN
    jz      mcFStep_23a
    test    eax,3           ; untere 2 Bits müssen 0 sein
    jnz     mcFNotAligned
mcFStep_23a:
    call    getvarptr       ; in Pointer umrechnen
    mov     ecx,[ebx]       ; Wert holen
    add     ebx,4           ; drop
    mov     [eax],cx        ; Wert im RAM speichern
    ret
; ------------------------------------------------
; Befehl $24: @
mcFStep_24:
    mov     eax,[ebx]       ; Adresse holen
    add     ebx,4
    test    pvflag,PV_ALIGN
    jz      mcFStep_24a
    test    eax,3           ; untere 2 Bits müssen 0 sein
    jnz     mcFNotAligned
mcFStep_24a:
    call    getvarptr       ; in Pointer umrechnen
    mov     eax,[eax]       ; Wert holen
    sub     ebx,4
    mov     [ebx],eax       ; und zum Stack
    ret
; ------------------------------------------------
; Befehl $25: !
mcFStep_25:
    mov     eax,[ebx]       ; Adresse holen
    add     ebx,4           ; drop
    test    pvflag,PV_ALIGN
    jz      mcFStep_25a
    test    eax,3           ; untere 2 Bits müssen 0 sein
    jnz     mcFNotAligned
mcFStep_25a:
    call    getvarptr       ; in Pointer umrechnen
    mov     ecx,[ebx]       ; Wert holen
    add     ebx,4           ; drop
    mov     [eax],ecx
    ret
; ------------------------------------------------
; Befehl $26: C@P
mcFStep_26:
    mov     eax,[ebx]       ; Adresse holen
    call    getprgptr       ; in Pointer umrechnen
    xor     ecx,ecx
    mov     cl,[eax]        ; Wert holen
    mov     [ebx],ecx       ; und zum Stack
    ret
; ------------------------------------------------
; Befehl $27: c!p
mcFStep_27:
    jmp     mcFIllegal
; aktuell nicht verwendet
    mov     eax,[ebx]       ; Adresse holen
    add     ebx,4           ; drop
    call    getprgptr       ; in Pointer umrechnen
    mov     cl,[eax]        ; Wert holen
    cmp     cl,-1           ; ist $FF ?
    jnz     mcFNotErased
    mov     ecx,[ebx]       ; Wert holen
    add     ebx,4           ; drop
    mov     [eax],cl
    ret
mcFNotErased:
    sub     ebx,4           ; Adresse lassen
    dec     esi
    call    mcFStep2
    print   chr$(13,10,13,10)       ; !!!
    call    regdump                 ; !!!
    call    ptrdump                 ; !!!
    call    mcFTrace
    print   chr$(13,10,13,10,"Flash not Erased",13,10) ; !!!
    invoke  wait_key                ; !!!
    or      debug,D_END
    jmp     mcFEnd                  ; !!!
; ------------------------------------------------
; Befehl $28: W@P
mcFStep_28:
    mov     eax,[ebx]       ; Adresse holen
    add     ebx,4
    test    pvflag,PV_ALIGN
    jz      mcFStep_28a
    test    eax,1           ; untere Bit muss 0 sein
    jnz     mcFNotAligned
mcFStep_28a:
    call    getprgptr       ; in Pointer umrechnen
    xor     ecx,ecx         ; ECX = 0
    mov     cx,[eax]        ; Wert holen (16bit)
    sub     ebx,4
    mov     [ebx],ecx       ; und zum Stack
    ret
; ------------------------------------------------
; Befehl $29: W!P
mcFStep_29:
    jmp     mcFIllegal
; aktuell nicht verwendet
    mov     eax,[ebx]       ; Adresse holen
    add     ebx,4           ; drop
    test    pvflag,PV_ALIGN
    jz      mcFStep_29a
    test    eax,1           ; untere Bit muss 0 sein
    jnz     mcFNotAligned
mcFStep_29a:
    call    getprgptr       ; in Pointer umrechnen
    mov     cx,[eax]        ; Wert holen
    cmp     cx,-1           ; ist $FFFF ?
    jnz     mcFNotErased
    mov     ecx,[ebx]       ; Wert holen
    add     ebx,4           ; drop
    mov     [eax],cx
    ret
; ------------------------------------------------
; Befehl $2A: @P
mcFStep_2A:
    mov     eax,[ebx]       ; Adresse holen
    add     ebx,4
    test    pvflag,PV_ALIGN
    jz      mcFStep_2Aa
    test    eax,3           ; untere 2 Bits müssen 0 sein
    jnz     mcFNotAligned
mcFStep_2Aa:
    call    getprgptr       ; in Pointer umrechnen
    mov     eax,[eax]       ; Wert holen
    sub     ebx,4
    mov     [ebx],eax       ; und zum Stack
    ret
; ------------------------------------------------
; Befehl $2B: !P
mcFStep_2B:
    jmp     mcFIllegal
; aktuell nicht verwendet
    mov     eax,[ebx]       ; Adresse holen
    add     ebx,4           ; drop
    test    pvflag,PV_ALIGN
    jz      mcFStep_2Ba
    test    eax,3           ; untere 2 Bits müssen 0 sein
    jnz     mcFNotAligned
mcFStep_2Ba:
    call    getprgptr       ; in Pointer umrechnen
    mov     ecx,[eax]       ; Wert holen
    cmp     cx,-1           ; ist $FFFFFFFF ?
    jnz     mcFNotErased
    mov     ecx,[ebx]       ; Wert holen
    add     ebx,4           ; drop
    mov     [eax],ecx
    ret
; ------------------------------------------------
; Befehl $2C: C@IO
mcFStep_2C:
; Befehl $2D: C!IO
mcFStep_2D:
; Befehl $2E: W@IO
mcFStep_2E:
; Befehl $2F: W!IO
mcFStep_2F:
; Befehl $30: @IO
mcFStep_30:
; Befehl $31: !IO
mcFStep_31:
    jmp     mcFIllegal
; ------------------------------------------------
; Befehl $32: C@X
mcFStep_32:
    add     ebx,4               ; High ignorieren
    mov     eax,[ebx]
    xor     ecx,ecx
    mov     cl,[eax]
    mov     [ebx],ecx
    ret
; ------------------------------------------------
; Befehl $33: C!X
mcFStep_33:
    mov     eax,[ebx+4]
    mov     ecx,[ebx+8]
    add     ebx,12
    mov     [eax],cl
    ret
; ------------------------------------------------
; Befehl $34: W@X
mcFStep_34:
    add     ebx,4               ; High ignorieren
    mov     eax,[ebx]
    add     ebx,4
    test    pvflag,PV_ALIGN
    jz      mcFStep_34a
    test    eax,1           ; untere Bit muss 0 sein
    jnz     mcFNotAligned
mcFStep_34a:
    xor     ecx,ecx
    mov     cx,[eax]
    sub     ebx,4
    mov     [ebx],ecx
    ret
; ------------------------------------------------
; Befehl $35: W!X
mcFStep_35:
    add     ebx,4
    mov     eax,[ebx]
    add     ebx,4
    test    pvflag,PV_ALIGN
    jz      mcFStep_35a
    test    eax,1           ; untere Bit muss 0 sein
    jnz     mcFNotAligned
mcFStep_35a:
    mov     ecx,[ebx]
    add     ebx,4
    mov     [eax],cx
    ret
; ------------------------------------------------
; Befehl $36: @X
mcFStep_36:
    add     ebx,4               ; High ignorieren
    mov     eax,[ebx]
    add     ebx,4
    test    pvflag,PV_ALIGN
    jz      mcFStep_36a
    test    eax,3           ; untere 2 Bits müssen 0 sein
    jnz     mcFNotAligned
mcFStep_36a:
    mov     eax,[eax]
    sub     ebx,4
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $37: !X
mcFStep_37:
    add     ebx,4
    mov     eax,[ebx]
    add     ebx,4
    test    pvflag,PV_ALIGN
    jz      mcFStep_37a
    test    eax,3           ; untere 2 Bits müssen 0 sein
    jnz     mcFNotAligned
mcFStep_37a:
    mov     ecx,[ebx]
    add     ebx,4
    mov     [eax],ecx
    ret
; ------------------------------------------------
; Befehl $38: FIP@
mcFStep_38:
    mov     eax,fip
    sub     ebx,4
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $39: FIP!
mcFStep_39:
    mov     eax,[ebx]
    add     ebx,4
    mov     fip,eax
    ret
; ------------------------------------------------
; Befehl $3A: FW@
mcFStep_3A:
    mov     eax,fw
    sub     ebx,4
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $3B: FW!
mcFStep_3B:
    mov     eax,[ebx]
    add     ebx,4
    mov     fw,eax
    ret
; ------------------------------------------------
; Befehl $3C: NEST
mcFStep_3C:
    mov     eax,fip                 ; EAX: FIP
    add     fip,4                   ; FIP zeigt auf nächsten Befehl
    call    getprgptr               ; => Speicheradresse
    mov     eax,[eax]               ; CFA holen
    mov     fw,eax                  ; W speichern
    add     fw,4                    ; FW zeigt auf PFA
    call    getprgptr               ; => Speicheradresse
    mov     eax,[eax]               ; CFA auslesen
    call    getprgptr               ; => IP zeigt auf Codeadresse
    mov     esi,eax
    ret
; ------------------------------------------------
; Befehl $3D: >CODE
mcFStep_3D:
    jmp     mcFIllegal
; ------------------------------------------------
; Befehl $3F: NOP
mcFStep_3F:
    ret
; ================================================
; Befehl $0000: BYE
mcFStep_0000:
    or      debug,D_END
    pop     eax
    ret
; ------------------------------------------------
; Befehl $0001: DEBUG
mcFStep_0001:
    mov     eax,[ebx]           ; Wert nach Debug
    mov     debug,al
    add     ebx,4
    mov     eax,[ebx]
    mov     debugaddr,eax       ; Debugaddresse merken
    mov     eax,0               ; OK = 0 zurück
    mov     [ebx],eax		; überschreibt Wert
    ret
; ------------------------------------------------
; Befehl $0002: GETPAR (aktuell Befehlszeilenadresse)
mcFStep_0002:
    mov     eax,lpArg		; Zeilenargument holen
    sub     ebx,4
    mov     [ebx],eax           ; und speichern
    mov     eax,0               ; OK = 0 zurück
    mov     lpArg,eax           ; keine weitere Zeilen
    sub     ebx,4
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0003: IRQOFF
mcFStep_0003:
    jmp     mcFIllegal_SysCall
; ------------------------------------------------
; Befehl $0004: IRQON
mcFStep_0004:
    jmp     mcFIllegal_SysCall
; ------------------------------------------------
; Befehl $0005: IRQSET
mcFStep_0005:
    jmp     mcFIllegal_SysCall
; ------------------------------------------------
; Befehl $0006: V
mcFStep_0006:
    jmp     mcFIllegal_SysCall
; ================================================
; Befehl $0100: XINIT
mcFStep_0100:
    mov     eax,0		; nur 0 zurück
    mov     [ebx],eax		; überschreibt Wert
    ret                         ; nichts zu tun
; ------------------------------------------------
; Befehl $0101: XALLOC
mcFStep_0101:
    ; High-Byte wird ignoriert
    ; mov     eax,[ebx]
    ; sal     eax,16
    mov     eax,[ebx+4]
    push    ebx
    push    edx
    push    esi
    mov     eax,alloc(eax)      ; Speicher reservieren
    pop     esi
    pop     edx
    pop     ebx
    and     eax,eax             ; OK ?
    jnz     mcFStep_0101a       ; Ja
    add     ebx,4               ; drop
    mov     eax,07F07h          ; Fehler: MAlloc
    mov     [ebx],eax
    ret
mcFStep_0101a:
    mov     [ebx+4],eax         ; Low = Adresse
    mov     eax,0
    mov     [ebx],eax           ; High = 0
    sub     ebx,4
    mov     [ebx],eax           ; OK
    ret
; ------------------------------------------------
; Befehl $0102: FRELLOC
mcFStep_0102:
    jmp     mcFIllegal_SysCall
; ------------------------------------------------
; Befehl $0103: XFREE
mcFStep_0103:
    mov     eax,[ebx+4]         ; Adresse
    add     ebx,4               ; High ignorieren
    push    ebx
    push    edx
    push    esi
    free    eax                 ; Speicher freigeben
    pop     esi
    pop     edx
    pop     ebx
    mov     eax,0
    mov     [ebx],eax           ; ok
    ret
; ------------------------------------------------
; Befehl $0105: P>X
mcFStep_0105:
    mov     eax,[ebx]           ; Offset
    call    getprgptr           ; => Pointer
    mov     [ebx],eax           ; speichern
    sub     ebx,4
    xor     eax,eax             ; High = 0
    mov     [ebx],eax		
    sub     ebx,4		; ok
    mov     [ebx],eax
    ret  
; ------------------------------------------------
; Befehl $0104: >X
mcFStep_0104:
; Befehl $0106: S>X
mcFStep_0106:
; Befehl $0107: R>X
mcFStep_0107:
    mov     eax,[ebx]           ; Offset
    call    getvarptr           ; => Pointer
    mov     [ebx],eax           ; speichern
    sub     ebx,4
    xor     eax,eax             ; High = 0
    mov     [ebx],eax		
    sub     ebx,4		; ok
    mov     [ebx],eax
    ret  
; ------------------------------------------------
; Befehl $0108: FLASH-SE
mcFStep_0108:
    mov     ecx,[ebx]           ;   Größe
    mov     eax,[ebx+4]         ; + Anfangsadresse
    add     ecx,eax             ; = Endadresse+1
    and     eax,0ffffff00h      ; auf 256 Bytes abrunden
    sub     ecx,eax             ; Größe
    add     ecx,0ffh            ; auf nächsten Sektor
    and     ecx,0ffffff00h      ; (=256 Byte) aufrunden
    mov     [ebx],ecx           ; und speichern
    mov     [ebx+4],eax         ; Adresse speichern
    mov     eax,0		; kein Fehler
    sub     ebx,4               
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0109: FLASH-SW
mcFStep_0109:
    mov     ecx,[ebx]           ;   Größe
    mov     eax,[ebx+4]         ; + Anfangsadresse
    add     ecx,eax             ; = Endadresse+1
    and     eax,0fffffff0h      ; auf 16 Bytes abrunden
    sub     ecx,eax             ; Größe
    add     ecx,0fh             ; auf nächste Page      
    and     ecx,0fffffff0h      ; (=16 Byte) aufrunden
    mov     [ebx],ecx           ; und speichern
    mov     [ebx+4],eax         ; Adresse speichern
    mov     eax,0		; kein Fehler
    sub     ebx,4               
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $010A: FLASH-E
mcFStep_010A:
    mov     ecx,[ebx]           ; Größe
    test    ecx,-1              ; 0 ?
    jz      mcFStep_010Aa      
    mov     eax,[ebx+4]         ; Anfangsadresse
    call    getprgptr           ; Auf Pointer umrechnen
    mov     edi,eax
    mov     al,-1
@@:
    stosb                       ; Flash löschen
    loopd   @b                  ; Zähler-1 bis 0
mcFStep_010Aa: 
    add     ebx,4               ; Stack korrigierten (Platz für OK)
    mov     eax,0		; kein Fehler
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $010B: FLASH-W
mcFStep_010B:
    mov     ecx,[ebx]           ; Größe
    test    ecx,-1              ; Ende ?
    jz      mcFStep_010Ba
    mov     eax,[ebx+4]         ; Flash-Adresse
    call    getprgptr
    mov     edi,eax
    mov     eax,[ebx+8]         ; RAM-Adresse
    call    getvarptr
    push    esi                 ; ESI speichern
    mov     esi,eax
@@:
    lodsb                       ; aus RAM
    stosb                       ; zum Flash
    loopd   @b
    pop     esi                 ; ESI wieder holen
mcFStep_010Ba: 
    add     ebx,8               ; Stack korrigierten (Platz für OK)
    mov     eax,0		; kein Fehler
    mov     [ebx],eax
    ret
; ================================================
; Befehl $0200: CINIT
mcFStep_0200:
    mov     eax,0		; nur 0 zurück
    mov     [ebx],eax		; überschreibt Wert
    ret                         ; nichts zu tun
; ------------------------------------------------
; Befehl $0201: SYSTICK
mcFStep_0201:
    push    ebx
    push    edx
    push    esi
    invoke  GetTickCount        ; Systemticker holen
    pop     esi
    pop     edx
    pop     ebx
    sub     ebx,4
    mov     [ebx],eax           ; Ticker in ms
    mov     eax,1000
    sub     ebx,4
    mov     [ebx],eax           ; Frequenz 1000Hz
    mov     eax,0               ; OK = 0 zurück
    sub     ebx,4
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0202: TIME@
mcFStep_0202:
    push    ebx
    push    edx
    push    esi
    invoke  GetLocalTime,addr systime
    pop     esi
    pop     edx
    pop     ebx
    movzx   eax,systime.wMilliseconds
    sub     ebx,4
    mov     [ebx],eax           ; ms
    movzx   eax,systime.wSecond
    sub     ebx,4
    mov     [ebx],eax           ; sec
    movzx   eax,systime.wMinute
    sub     ebx,4
    mov     [ebx],eax           ; min
    movzx   eax,systime.wHour
    sub     ebx,4
    mov     [ebx],eax           ; h
    mov     eax,0               ; OK = 0 zurück
    sub     ebx,4
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0203: TIME!
mcFStep_0203:
    jmp     mcFIllegal_SysCall
; ------------------------------------------------
; Befehl $0204: DATE@
mcFStep_0204:
    push    ebx
    push    edx
    push    esi
    invoke  GetLocalTime,addr systime
    pop     esi
    pop     edx
    pop     ebx
    movzx   eax,systime.wDay
    sub     ebx,4
    mov     [ebx],eax           ; Tag
    movzx   eax,systime.wMonth
    sub     ebx,4
    mov     [ebx],eax           ; Monat
    movzx   eax,systime.wYear
    sub     ebx,4
    mov     [ebx],eax           ; Jahr
    mov     eax,0               ; OK = 0 zurück
    sub     ebx,4
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0205: DATE!
mcFStep_0205:
    jmp     mcFIllegal_SysCall
; ================================================
; Befehl $0206: WAITMS
mcFStep_0206:
    mov     eax,[ebx]           ; Zeit holen
    call    waitms              ; Warten
    mov     eax,0               ; OK = 0 zurück
    mov     [ebx],eax
    ret
; ================================================
; Befehl $0300: TINIT
mcFStep_0300:
    mov     eax,0		; nur 0 zurück
    mov     [ebx],eax		; überschreibt Wert
    ret
; ------------------------------------------------
; Befehl $0301: KEY
mcFStep_0301:
    call    key                 ; Zeichen holen
    sub     ebx,4
    mov     [ebx],eax           ; und speichern
    mov     eax,0               ; OK = 0 zurück
    sub     ebx,4
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0302: EMIT
mcFStep_0302:
    mov     eax,[ebx]           ; Zeichen holen
    call    emit                ; Zeichen ausgeben
    mov     eax,0               ; OK = 0 zurück
    mov     [ebx],eax
    ret
; -----	-------------------------------------------
; Befehl $0303: KEY?
mcFStep_0303:
    call    keyq
    sub     ebx,4
    mov     [ebx],eax
    mov     eax,0               ; OK = 0 zurück
    sub     ebx,4
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0304: EMIT?
mcFStep_0304:
    call    emitq
    sub     ebx,4
    mov     [ebx],eax
    sub     ebx,4
    mov     eax,0               ; OK = 0 zurück
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0305: ACCEPT
mcFStep_0305:
    jmp     mcFIllegal_SysCall
; ------------------------------------------------
; Befehl $0306: PAGE
mcFStep_0306:
    push    ebx
    push    edx
    push    esi
;    invoke  GetStdHandle,STD_OUTPUT_HANDLE
;    mov     [hStdOut],eax
    invoke  GetConsoleScreenBufferInfo,[hStdOut],addr dwSize
    .if eax ; if eax is non-zero
        ; fill the entire screen with spaces
        xor eax,eax
        mov ax,dwSize
        xor ecx,ecx
        mov cx,dwSize+2
        mul ecx ; calculate size of console  
        invoke FillConsoleOutputCharacter,[hStdOut],VK_SPACE,eax,topleft,addr dummy
        invoke SetConsoleCursorPosition,[hStdOut],dword ptr topleft
    .endif
    pop     esi
    pop     edx
    pop     ebx

; Test: Adresse von dwSize liefern
;    sub     ebx,4
;    mov     eax,offset dwSize
;    mov     [ebx],eax 
; Ende Test

    mov     eax,0               ; OK = 0 zurück
    sub     ebx,4
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0307: ATXYMAX
mcFStep_0307:
    push    ebx
    push    edx
    push    esi
;    invoke  GetStdHandle,STD_OUTPUT_HANDLE
;    mov     [hStdOut],eax
    invoke  GetConsoleScreenBufferInfo,[hStdOut],offset dwSize
    pop     esi
    pop     edx
    pop     ebx
    and     eax,0ffffh
    mov     ax,dwMaximum        ; Breite maximal
    sub     ebx,4
    mov     [ebx],eax
    mov     ax,dwMaximum+2      ; Höhe maximal
    sub     ebx,4
    mov     [ebx],eax
    mov     eax,0               ; OK = 0 zurück
    sub     ebx,4
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0308: ATXY?
mcFStep_0308:
    push    ebx
    push    edx
    push    esi
;    invoke  GetStdHandle,STD_OUTPUT_HANDLE
;    mov     [hStdOut],eax
    invoke  GetConsoleScreenBufferInfo,[hStdOut],addr dwSize
    pop     esi
    pop     edx
    pop     ebx
    mov     ax,dwCursor
    and     eax,0ffffh
    sub     ebx,4
    mov     [ebx],eax
    mov     ax,dwCursor+2
    and     eax,0ffffh
    sub     ebx,4
    mov     [ebx],eax
    mov     eax,0               ; OK = 0 zurück
    sub     ebx,4
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0309: ATXY
mcFStep_0309:
    mov     eax,[ebx]
    add     ebx,4
    mov     dwCursor+2,ax
    mov     eax,[ebx]
    add     ebx,4
    mov     dwCursor,ax   
    push    ebx
    push    edx
    push    esi
;    invoke  GetStdHandle,STD_OUTPUT_HANDLE
;    mov     [hStdOut],eax
    invoke  SetConsoleCursorPosition,[hStdOut],dword ptr dwCursor
    pop     esi
    pop     edx
    pop     ebx
    mov     eax,0               ; OK = 0 zurück
    sub     ebx,4
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $030A: COLOR@
mcFStep_030A:
    push    ebx
    push    edx
    push    esi
    invoke GetConsoleScreenBufferInfo,[hStdOut],addr dwSize
    pop     esi
    pop     edx
    pop     ebx
    mov     eax,0
    mov     ax,wAttributes
    sub     ebx,4
    mov     [ebx],eax
    mov     eax,0               ; OK = 0 zurück
    sub     ebx,4
    mov     [ebx],eax
    ret  
; Befehl $030B: COLOR!
mcFStep_030B:
    push    ebx
    push    edx
    push    esi
    mov     eax,[ebx]
    mov     wAttributes,ax
    invoke SetConsoleTextAttribute,[hStdOut],dword ptr wAttributes
    pop     esi
    pop     edx
    pop     ebx
    mov     eax,0               ; OK = 0 zurück
    mov     [ebx],eax
    ret  
; Befehl $030C: AT@
mcFStep_030C:
; Befehl $030D: AT!
mcFStep_030D:
    jmp     mcFIllegal_SysCall
; ================================================
; Befehl $0400: FINIT
mcFStep_0400:
    mov     eax,0		; nur 0 zurück
    mov     [ebx],eax		; überschreibt Wert
    ret
; ------------------------------------------------
; Befehl $0401: FCREATE
mcFStep_0401:
    add     ebx,4           ; Länge ignorieren
    mov     eax,[ebx]       ; Stringadresse
    call    getvarptr       ; im Variablenbereich
    push    ebx
    push    edx
    push    esi
    invoke CreateFileA,eax,  GENERIC_WRITE OR GENERIC_READ,
                            NULL,
                            NULL,CREATE_ALWAYS,
                            FILE_ATTRIBUTE_NORMAL,
                            NULL
    .IF eax==INVALID_HANDLE_VALUE
        invoke GetLastError
        pop     esi
        pop     edx
        pop     ebx
        mov     [ebx],eax
        ret
    .ENDIF
    pop     esi
    pop     edx
    pop     ebx
    sub     ebx,4
    mov     [4+ebx],eax
    mov	    eax,0
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0402: RENAME
mcFStep_0402:
    jmp     mcFIllegal_SysCall
; ------------------------------------------------
; Befehl $0403: FDELETE
mcFStep_0403:
    add     ebx,4           ; Länge ignorieren
    mov     eax,[ebx]       ; Stringadresse
    call    getvarptr       ; im Variablenbereich
    push    ebx
    push    edx
    push    esi
    invoke  DeleteFileA, eax
    .IF eax==0
        invoke GetLastError
        pop     esi
        pop     edx
        pop     ebx
        mov     [ebx],eax
        ret
    .ENDIF
    pop     esi
    pop     edx
    pop     ebx
    mov	    eax,0
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0404: FOPEN
mcFStep_0404:
    mov     ecx,[ebx]       ; Flag holen
    add     ebx,8           ; Länge ignorieren
    mov     eax,[ebx]       ; Filename
    call    getvarptr       ; im Variablenbereich
    push    ebx
    push    edx
    push    esi
    invoke CreateFileA,eax, ecx,
                            FILE_SHARE_READ,
                            NULL,OPEN_EXISTING,
                            FILE_ATTRIBUTE_NORMAL,
                            NULL
    .IF eax==INVALID_HANDLE_VALUE
        invoke  GetLastError
        pop     esi
        pop     edx
        pop     ebx
        mov     [ebx],eax
        ret
    .ENDIF
    pop     esi
    pop     edx
    pop     ebx
    mov     [ebx],eax
    mov     eax,0
    sub     ebx,4
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0405: FCLOSE
mcFStep_0405:
    mov     eax,[ebx]
    push    ebx
    push    edx
    push    esi
    invoke  CloseHandle,eax
    .IF eax==0
        invoke GetLastError
    .ELSE
        mov     eax,0
    .ENDIF
    pop     esi
    pop     edx
    pop     ebx
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0406: FSIZE@
mcFStep_0406:
    mov     eax,[ebx]       ; Handle
    push    ebx
    push    edx
    push    esi
    invoke  GetFileSize,eax,NULL
    .IF     eax==INVALID_FILE_SIZE
        invoke GetLastError
        pop     esi
        pop     edx
        pop     ebx
        mov     [ebx],eax
        ret
    .ENDIF
    pop     esi
    pop     edx
    pop     ebx
    mov     [ebx],eax       ; Länge Low
    mov     eax,0           ; Länge High = 0
    sub     ebx,4
    mov     [ebx],eax
    sub     ebx,4           ; kein Fehler
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0407: FSIZE!
mcFStep_0407:
    jmp     mcFIllegal_SysCall
; Befehl $0408: FPOS@
mcFStep_0408:
    mov     eax,[ebx]       ; Handle
    add     ebx,4
    mov     ecx,1           ; Richtung 1=rel
    add     ebx,4
    push    ebx
    mov     ebx,0           ; Position = 0
    push    edx
    push    esi
    invoke  SetFilePointer,eax,ebx,NULL,ecx
    .IF     eax == INVALID_SET_FILE_POINTER
        invoke GetLastError
        pop     esi
        pop     edx
        pop     ebx
        mov     [ebx],eax
        ret
    .ENDIF
    pop     esi
    pop     edx
    pop     ebx
    mov     [ebx],eax         ; Low-Wort Offset
    xor     eax,eax
    sub     ebx,4             ; High-Wort Offset ist 0
    mov     [ebx],eax
    mov     eax,0             ; OK
    sub     ebx,4
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0409: FPOS!
mcFStep_0409:
    mov     eax,[ebx]       ; Handle
    add     ebx,4
    mov     ecx,[ebx]       ; Richtung
    add     ebx,8           ; High-Wort Offset nicht genutzt
    push    ebx
    mov     ebx,[ebx]       ; Position
    push    edx
    push    esi
    invoke  SetFilePointer,eax,ebx,NULL,ecx
    .IF     eax == INVALID_SET_FILE_POINTER
        invoke GetLastError
        pop     esi
        pop     edx
        pop     ebx
        mov     [ebx],eax
        ret
    .ENDIF
    pop     esi
    pop     edx
    pop     ebx
    mov     eax,0           ; OK
    mov     [ebx],eax       ; statt Handle
    ret
; ------------------------------------------------
; Befehl $040A: FREAD
mcFStep_040A:
    mov     eax,[ebx]       ; File-ID
    add     ebx,4
    mov     ecx,[ebx]       ; Länge
    add     ebx,8
    mov     edi,[ebx]       ; Adresse (absolut - nur Low-Word)    
    push    ebx
    push    edx
    push    esi
    invoke  ReadFile,eax,edi,ecx,ebx,NULL ;Handle, Ptr, Länge, &Gelesen, Overlapped
    .IF     eax == 0
        invoke GetLastError
        pop     esi
        pop     edx
        pop     ebx
        mov     [ebx],eax
        ret
    .ENDIF
    pop     esi
    pop     edx
    pop     ebx
    xor     eax,eax          ; kein Fehler - Länge schon auf dem Stack
    sub     ebx,4
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $040B: FWRITE
mcFStep_040B:
    mov     eax,[ebx]       ; File-ID
    add     ebx,4
    mov     ecx,[ebx]       ; Länge
    add     ebx,8
    mov     edi,[ebx]       ; Adresse (absolut)    
    push    ebx
    push    edx
    push    esi
    invoke  WriteFile,eax,edi,ecx,ebx,NULL ;Handle, Ptr, Länge, &Länge, Overlapped
    .IF     eax == 0
        invoke GetLastError
        pop     esi
        pop     edx
        pop     ebx
        mov     [ebx],eax
        ret
    .ENDIF
    pop     esi
    pop     edx
    pop     ebx
    xor     eax,eax          ; kein Fehler
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $040C: FFIRST
mcFStep_040C:
; Befehl $040D: FNEXT
mcFStep_040D:
; Befehl $040E: FDIR@
mcFStep_040E:
; Befehl $040F: FDIR!
mcFStep_040F:
; Befehl $0410: FDRV@
mcFStep_0410:
; Befehl $0411: FDRV!
mcFStep_0411:
; Befehl $0412: FFREE
mcFStep_0412:
    jmp     mcFIllegal_SysCall
; ------------------------------------------------
; Befehl $0413: FPAR@
mcFStep_0413:
    ; Windows-Routine aufrufen
    mov     eax,[ebx]
    mov     hSerialPort,eax ; Port

    push    esi
    push    edx
    push    ebx
    mov     SerialSettings.DCBlength, SIZEOF DCB     ; configure the Settings variable
    invoke  GetCommState, hSerialPort, ADDR SerialSettings   ; fill it with the current settings
    pop     ebx
    pop     edx
    pop     esi

    ; Daten auslesen
    mov     eax, SerialSettings.fbits                ; Flag holen
    mov     [ebx],eax                                ; und ablegen
    sub     ebx,4
    mov     eax, SerialSettings.BaudRate             ; Baudrate holen
    mov     [ebx],eax                                ; und ablegen
    sub     ebx,4
    mov     eax,0                                    ; OK = 0 zurück
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0414: FPAR!
mcFStep_0414:
    mov     eax,[ebx]
    mov     hSerialPort,eax ; Port
    add     ebx,4
    mov     eax,[ebx]
    mov     Baudrate,eax    ; Baudrate
    add     ebx,4
    mov     eax,[ebx]
    mov     SerialFlag,eax  ; Flag
    add     ebx,4

    ; Register retten
    push    esi
    push    edx
    push    ebx

    ; Baudrate umstellen
    mov     SerialSettings.DCBlength, SIZEOF DCB     ; configure the Settings variable
    invoke  GetCommState, hSerialPort, ADDR SerialSettings   ; fill it with the current settings
    mov     eax,Baudrate
    mov     SerialSettings.BaudRate, eax             ; Baud Rate
    mov     SerialSettings.ByteSize, 8               ; Data Bits: 8
    mov     SerialSettings.Parity, NOPARITY          ; Parity: None
    mov     SerialSettings.StopBits, ONESTOPBIT      ; Stop Bits: 1
    mov     eax,SerialFlag
    mov     SerialSettings.fbits, eax                ; folgende Flags kodiert
;    and     [SerialSettings.fbits], 0FFFFCFCFh       ; RTS - DTR - Binary   
;    or      [SerialSettings.fbits], 000001011h       ; Enable - Enable - Enable
; mov     SerialSettings.fbits, BITRECORD<\
; TRUE,  \   ; fBinary:1
; FALSE, \   ; fParity:1
; FALSE, \   ; fOutxCtsFlow:1
; FALSE, \   ; fOutxDsrFlow:1
; DTR_CONTROL_DISABLE, \   ; fDtrControl:2
; FALSE, \   ; fDsrSensitivity:1
; TRUE,  \   ; fTXContinueOnXoff:1
; FALSE, \   ; fOutX:1
; FALSE, \   ; fInX:1
; TRUE,  \   ; fErrorChar:1
; FALSE, \   ; fNull:1
; RTS_CONTROL_DISABLE, \   ; fRtsControl:2
; FALSE, \   ; fAbortOnError:1
; NULL>  ; fDummy2:17
    invoke  SetCommState, hSerialPort, ADDR SerialSettings   ; Apply the new settinsg

  ; Set the Time-outs to occur immedietly with everything in the buffer
    invoke GetCommTimeouts, hSerialPort, ADDR SerialTimeOuts
    mov SerialTimeOuts.ReadIntervalTimeout, MAXDWORD
    mov SerialTimeOuts.ReadTotalTimeoutMultiplier, 0
    mov SerialTimeOuts.ReadTotalTimeoutConstant, 0
    mov SerialTimeOuts.WriteTotalTimeoutMultiplier, 0
    mov SerialTimeOuts.WriteTotalTimeoutConstant, 0
    invoke SetCommTimeouts, hSerialPort, ADDR SerialTimeOuts

    ; Register wieder herstellen
    pop     ebx
    pop     edx
    pop     esi

    sub     ebx,4
    mov     eax,0                                    ; OK = 0 zurück
    mov     [ebx],eax
    ret
; ------------------------------------------------
; Befehl $0415: FCOPY
mcFStep_0415:
    mov     edi,[ebx]       ; Flag holen (0=neu anlegen)
    add     ebx,4
    mov     eax,[ebx]       ; neues File
    call    getvarptr       ; im Variablenbereich
    mov     ecx,eax
    add     ebx,4
    mov     eax,[ebx]       ; altes File
    call    getvarptr       ; im Variablenbereich
    push    ebx
    push    edx
    push    esi
    invoke CopyFile,eax,ecx,edi
    .IF     eax == 0
        invoke GetLastError
        pop     esi
        pop     edx
        pop     ebx
        mov     [ebx],eax
        ret
    .ENDIF
    pop     esi
    pop     edx
    pop     ebx
    xor     eax,eax          ; kein Fehler
    mov     [ebx],eax
    ret
; ------------------------------------------------

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Tracer-Ausgaben für das FORTH-System
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
mcFOp_Table:
    db 64
    db "CALL    ", 0
    db "BRANCH  ", 0
    db "0BRANCH ", 0
    db "NBRANCH ", 0
    db "LIT     ", 0
    db "EXIT    ", 0
    db "EXECUTE ", 0
    db "SP@     ", 0
    db "SP!     ", 0
    db "DROP    ", 0
    db "DUP     ", 0
    db "OVER    ", 0
    db "SWAP    ", 0
    db "RP@     ", 0
    db "RP!     ", 0
    db ">R      ", 0
    db "R>      ", 0
    db "R@      ", 0
    db "RDROP   ", 0
    db "AND     ", 0
    db "OR      ", 0
    db "XOR     ", 0
    db "+W      ", 0
    db "-W      ", 0
    db "LSHIFT  ", 0
    db "RSHIFT  ", 0
    db "ASHIFT  ", 0
    db "UM*     ", 0
    db "UM/MOD  ", 0
    db "0<      ", 0
    db "U<      ", 0
    db "<       ", 0
    db "C@      ", 0
    db "C!      ", 0
    db "W@      ", 0
    db "W!      ", 0
    db "@       ", 0
    db "!       ", 0
    db "C@P     ", 0
    db "C!P     ", 0
    db "W@P     ", 0
    db "W!P     ", 0
    db "@P      ", 0
    db "!P      ", 0
    db "C@IO    ", 0
    db "C!IO    ", 0
    db "W@IO    ", 0
    db "W!IO    ", 0
    db "@IO     ", 0
    db "!IO     ", 0
    db "C@X     ", 0
    db "C!X     ", 0
    db "W@X     ", 0
    db "W!X     ", 0
    db "@X      ", 0
    db "!X      ", 0
    db "FIP@    ", 0
    db "FIP!    ", 0
    db "FW@     ", 0
    db "FW!     ", 0
    db "NEST    ", 0
    db ">CODE   ", 0
    db "SYSCALL ", 0
    db "NOP     ", 0
mcFOp_Table_00xx:
    db 7
    db "BYE     ", 0
    db "DEBUG   ", 0
    db "GETPAR  ", 0
    db "IRQOFF  ", 0
    db "IRQON   ", 0
    db "IRQSET  ", 0
    db "V       ", 0
mcFOp_Table_01xx:
    db 12
    db "XINIT   ", 0
    db "XALLOC  ", 0
    db "XRELOC  ", 0
    db "XFREE   ", 0
    db ">X      ", 0
    db "P>X     ", 0
    db "S>X     ", 0
    db "R>X     ", 0
    db "FLASH-SE", 0
    db "FLASH-SW", 0
    db "FLASH-E ", 0
    db "FLASH-W ", 0
mcFOp_Table_02xx:
    db 7
    db "CINIT   ", 0
    db "SYSTICK ", 0
    db "TIME@   ", 0
    db "TIME!   ", 0
    db "DATE@   ", 0
    db "DATE!   ", 0
    db "WAITMS  ", 0
mcFOp_Table_03xx:
    db 14
    db "TINIT   ", 0
    db "KEY     ", 0
    db "EMIT    ", 0
    db "KEY?    ", 0
    db "EMIT?   ", 0
    db "ACCEPT  ", 0
    db "PAGE    ", 0
    db "ATMAX   ", 0
    db "ATXY?   ", 0
    db "ATXY    ", 0
    db "COLOR@  ", 0
    db "COLOR!  ", 0
    db "AT@     ", 0
    db "AT!     ", 0
mcFOp_Table_04xx:
    db 22	
    db "FINIT   ", 0
    db "FCREATE ", 0
    db "FRENAME ", 0
    db "FDELETE ", 0
    db "FOPEN   ", 0
    db "FCLOSE  ", 0
    db "FSIZE@  ", 0
    db "FSIZE!  ", 0
    db "FPOS@   ", 0
    db "FPOS!   ", 0
    db "FREAD   ", 0
    db "FWRITE  ", 0
    db "FFIRST  ", 0
    db "FNEXT   ", 0
    db "FDIR@   ", 0
    db "FDIR!   ", 0
    db "FDRV@   ", 0
    db "FDRV!   ", 0
    db "FFREE   ", 0
    db "FPAR@   ", 0
    db "FPAR!   ", 0
    db "FCOPY   ", 0
; ------------------------------------------------
mcFTrace:
    print   chr$(13,10)
    call    mcFTraceStacks   
    print   chr$(13,10)
    print   chr$("IP=")      ; IP ausgeben
    mov     eax,fip
    call    hex_eax
    print   chr$(" W=")      ; W ausgeben
    mov     eax,fw
    call    hex_eax
    print   chr$(" PC=")      ; PC ausgeben
    mov     eax,fpc
    call    hex_eax
    print   chr$(32)
    mov     eax,fpc          ; Programmpointer
    call    getprgptr
    mov     esi,eax
    mov     al,[esi]         ; Opcode ausgeben
    call    hex_al
    print   chr$(32)
    xor     eax,eax          ; EAX = 0
    lodsb                    ; Opcode holen (SI+1)
    push    eax
    cmp     al,005h
    jb      mcFTrace2
    print   chr$("         ") ; Leerzeichen statt Opcode
    jmp     mcFTrace3
mcFTrace2:
    mov     eax,[esi]        ; Adresse/Wert ausgeben
    call    hex_eax
    print   chr$(32)
mcFTrace3:
    pop     eax
    cmp     al,03Eh          ; bei $3E SYSCALL ausgeben
    jz      mcFTrace_SysCall
    mov     ebx,mcFOp_Table
    jmp     mcFTrace_OpC
mcFTrace_SysCall:
    mov     eax,fsp
    call    getvarptr
    mov     ebx,eax
    mov     eax,[ebx]
    mov     ecx,eax
    sar     ecx,8
    and     eax,0FFh
    cmp     ecx,00h
    jnz     mcFTrace_SysCall_01xx
    mov     ebx, mcFOp_Table_00xx
    jmp     mcFTrace_OpC
mcFTrace_SysCall_01xx:
    cmp     ecx,01h
    jnz     mcFTrace_SysCall_02xx
    mov     ebx, mcFOp_Table_01xx
    jmp     mcFTrace_OpC
mcFTrace_SysCall_02xx:
    cmp     ecx,02h
    jnz     mcFTrace_SysCall_03xx
    mov     ebx, mcFOp_Table_02xx
    jmp     mcFTrace_OpC
mcFTrace_SysCall_03xx:
    cmp     ecx,03h
    jnz     mcFTrace_SysCall_04xx
    mov     ebx, mcFOp_Table_03xx
    jmp     mcFTrace_OpC
mcFTrace_SysCall_04xx:
    cmp     ecx,04h
    jnz     mcFTrace_SysCall_05xx
    mov     ebx, mcFOp_Table_04xx
    jmp     mcFTrace_OpC
mcFTrace_SysCall_05xx:
; SysCall Nummer unbekannt 
    mov     al,0FFh
    mov     ebx, mcFOp_Table
mcFTrace_OpC:
    cmp     al,[ebx]         ; mit max. Anzahl vergleichen
    jb      mcFTrace_Mnx
    print   chr$("???????? ") ; Opcode unbekannt
    ret
mcFTrace_Mnx:
    inc     ebx
    add     ebx,eax
    sal     eax,3
    add     ebx,eax
    print   ebx
    print   chr$(32)         ; danach Leerzeichen
    ret
; Ende der MNemonics-Ausgabe
mcFTraceStacks:
;    call    ptrdump          ; !!! Debug: Pointer ausgeben
;    call    regdump          ; !!! Debug: Register anzeigen
    print   chr$(13,10,"S=")        ; SP mit 3 Einträgen ausgeben
    mov     eax,dword ptr [fsp]
    call    hex_eax
    print   chr$(":")
    mov     eax,dword ptr [fsp]
    call    getvarptr
    mov     esi,eax

    lodsd
    call    hex_eax
    print   chr$("|")
    lodsd
    call    hex_eax
    print   chr$("|")
    lodsd
    call    hex_eax
    print   chr$("  R=")            ; RP mit 3 Einträgen ausgeben
    mov     eax,dword ptr [frp]
    call    hex_eax
    print   chr$(":")
    mov     eax,dword ptr [frp]
    call    getvarptr
    mov     esi,eax
    lodsd
    call    hex_eax
    print   chr$("|")
    lodsd
    call    hex_eax
    print   chr$("|")
    lodsd
    call    hex_eax
;    print   chr$("  IP=")          ; IP ausgeben
;    mov     eax,dword ptr [fip]
;    call    hex_ax
;    print   chr$("  W=")           ; W ausgeben
;    mov     eax,dword ptr [fw]
;    call    hex_ax
    print   chr$(32)
    ret
;
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Initialisierung des mcF
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
mcFInit:
; Initialisierung der Parameter
    mov     pvflag,PV_TOROM+PV_HARWARD ; ROM/RAM, Harward, kein Align
    mov     prgptr,0                    ; noch kein Flash reserviert
    mov     prgoff,0                    ; Anfang 0
    mov     prgsize,0200000h            ; Größe 2MByte
    mov     varptr,0                    ; noch kein RAM reserviert
    mov     varoff,020000000h           ; Anfang $2000.0000
    mov     varsize,0100000h            ; Größe 1MByte

; Command Line holen
; wenn File gefunden, dann an Stelle des FORTH-Kern laden

    invoke GetCommandLine
    mov CommandLine, eax

    invoke PathGetArgs,CommandLine
    mov lpArg, eax
    mov esi,eax

; Ausgabe der Befehlszeile ( !!! Debug)
;    push eax
;    push esi
;    mov  esi,eax
;    lodsb
;    mov  esi,lpArg
;    call dump_si
;    print chr$(13,10)
;    call dump_si
;    print chr$(13,10)
;    mov  eax,lpArg
;    print eax		; Ausgabe des Strings
;    print chr$(13,10)
;    pop esi
;    pop eax
; Ende der Ausgabe der Befehlszeile

; Eingabezeile auf Parameter testen
; Leerzeichen überspringen
mcFInit_s1:
    lodsb
    cmp al, 0
    jz mcFInite     ; jump if no arg
    cmp al, 32      ; 
    je mcFInit_s1   ; Skip Space
; Test, ob Parameter: + gefolgt von p v h oder a
    cmp al, 02bh    ; Test auf +
    jnz mcFInit_m1  ; nein: - ? 
    call upcchar    ; in Großbuchstabe
    cmp al,0
    jz mcFInite     ; Ende der Eingabezeile
    cmp al,041h     ; +a: Align-Bit setzen
    jnz mcFInit_p1
    or pvflag,PV_ALIGN  ; Bit 4=1 in PVFLAG setzen
    jmp  mcFInit_s1 ; und nach nächsten Parameter suchen
mcFInit_p1:
    cmp al,048h     ; +h: Harward-Bit setzen
    jne mcFInit_p2
    or pvflag,PV_HARWARD     ; Bit 3=1 in PVFLAG setzen
    jmp mcFInit_s1  ; und nach nächsten Parameter suchen
mcFInit_p2:
    cmp al,050h     ; +paaaaaaaa.ssssssss ?
    jne mcFInit_p3
    call gethex     ; Adresse holen
    mov  prgoff,ebx
    lodsb
    cmp  al,0
    je mcFInite     ; Ende der Zeile hier nicht erwartet
    cmp  al,02eh    ; . erwartet
    jne mcFInite
    call gethex     ; Länge holen
    mov  prgsize,ebx
    or pvflag,PV_TOROM     ; Bit 2=1 in PVFLAG setzen
    jmp mcFInit_s1  ; und nach nächsten Parameter suchen
mcFInit_p3:
    cmp al,056h     ; +vaaaaaaaa.ssssssss ?
    jne mcFInit_s2x
    call gethex     ; Adresse holen
    mov  varoff,ebx
    lodsb
    cmp  al,0
    je mcFInite     ; Ende der Zeile hier nicht erwartet
    cmp  al,02eh    ; . erwartet
    jne mcFInite
    call gethex     ; Länge holen
    mov  varsize,ebx
    jmp mcFInit_s1  ; und nach nächsten Parameter suchen

; Test, ob Parameter: - gefolgt von p oder h oder a
; Abfrage auf -
mcFInit_m1:
    cmp al, 02dh    ; Test auf -
    jnz mcFInit_s2x ; nein: Filename ? 
    call upcchar    ; in Großbuchstabe
    cmp al,0
    jz mcFInite     ; Ende der Eingabezeile
    cmp al,041h     ; -a: Align-Bit löschen
    jnz mcFInit_m2
    and pvflag,NOT(PV_ALIGN)  ; Bit 4=1 in PVFLAG löschen
    jmp  mcFInit_s1 ; und nach nächsten Parameter suchen
mcFInit_m2:
    cmp al,048h     ; -h: Harward-Bit löschen
    jnz mcFInit_m3
    and pvflag,NOT(PV_HARWARD)  ; Bit 3=1 in PVFLAG löschen
    jmp  mcFInit_s1 ; und nach nächsten Parameter suchen
mcFInit_m3:
    cmp al,050h     ; -p: kein ROM
    jnz mcFInit_s2
    mov prgoff,0    ; Anfang 0
    mov prgsize,0   ; Größe 0
    and pvflag,NOT(PV_TOROM)  ; Bit 2=1 in PVFLAG löschen
    jmp  mcFInit_s1 ; und nach nächsten Parameter suchen

; Filename ermitteln, Rest der Zeile als ucF-Kommando
; Space überspringen
mcFInit_s2:
    lodsb
    cmp al, 0
    je mcFInite     ; jump if no arg
mcFInit_s2x:
    cmp al, 32      ; 
    je mcFInit_s2   ; Skip Space

    cmp al,05ch     ; Test auf \ für Singlestep-Debug
    jne @f
    mov  byte ptr [debug],D_STEP+D_TRACE ; Singlestep
    lodsb
    jmp mcFInit0
@@: cmp al, 02fh    ; Test auf / für Debug
    jne mcFInit0
    mov  byte ptr [debug],D_TRACE ; mit 1 überschreiben
    lodsb
mcFInit0:
    mov ah, 34      ; Default: Filename in " eingeschlossen
    cmp al, ah      ; ist ersten Zeichen " ? 
    je  @F  
    mov ah,32       ; Ende ist Space oder 0
    sub esi,1       ; Anfang war schon letztes Zeichen      
@@:   
    mov lpArg,esi   ; Anfang als neues Argument merken
mcFInit1:
    lodsb           ; Nächstes Zeichen holen
    cmp al, 0
    je  @F         ; weitere Zeichen ?
    cmp al, ah      ; " oder SPACE ?
    jne mcFInit1    ; dann lesen wiederholen
    sub  esi,1      ; zum letzten Zeichen zurück
    mov  byte ptr [esi],0 ; mit 0 überschreiben
    add  esi,2      ; zum letzten Zeichen zurück
@@:
    sub  esi,1      ; zum letzten Zeichen zurück
    push esi        ; Anfang des Zeilenrest
; File öffnen
    invoke exist,lpArg
    .if eax == 1

        invoke CreateFile,lpArg,
                          GENERIC_READ,
                          FILE_SHARE_READ,
                          NULL,OPEN_EXISTING,
                      FILE_ATTRIBUTE_NORMAL,
                      NULL

        mov hFile, eax
;        call    hex_eax
;        print chr$(" Filehandle",13,10)
        
;        print chr$("$")
        invoke GetFileSize,hFile,NULL
        mov flen, eax
;        call    hex_eax
;        print chr$(" Bytes Maximum",13,10)
;        print chr$("Nach ")
;        mov eax,prgptr
;        call    hex_eax
;        print chr$(13,10)

; Speicher anlegen und Programm nach RAM oder ROM laden
; ROM/RAM-Version - zwei getrennte Speicher reserviert
; RAM anlegen
mcFInit2:
        mov	eax,varsize             ; RAM reservieren
        add     eax,12                  ; +12 Bytes für Tracer
        mov     varptr, alloc(eax)
        or      pvflag,PV_RAM           ; Bit 0 für RAM setzen
; RAM mit $FF belegen
    	push    ds
    	pop     es
    	mov     edi,varptr
    	mov     ecx,varsize
        add     eax,12                  ; +12 Byte für Tracer
    	mov     al,0ffh
@@:
	stosb
    	loopd   @b
; evtl. Flash anlegen
        test    pvflag,PV_TOROM         ; evtl. Flash anlegen ?
        jz      mcFInit3                ; nein
        mov     eax,prgsize             ; Flash reservieren
        mov     prgptr, alloc(eax)
        or      pvflag,PV_ROM           ; Bit 1 für ROM setzen
; Flash mit $FF belegen
    	push    ds
    	pop     es
    	mov     edi,prgptr
    	mov     ecx,prgsize
    	mov     al,0ffh
@@:
    	stosb
        loopd   @b
        jmp     mcFInit4
; Wenn kein getrennter Speicher und Neumann-Architektur: ROM=RAM
mcFInit3:
        test    pvflag,PV_TOROM+PV_HARWARD  ; Test, das Bit 2 (P) und 3 (H) auf 0
        jnz     mcFInit4                ; nicht 0: ROM bleibt getrennt
        mov     eax,varptr              ; ansonsten RAM ist auch ROM
        mov     prgptr,eax
        mov     eax,varoff
        mov     prgoff,eax
        mov     eax,varsize
        mov     prgsize,eax
; Image ins ROM (bzw. RAM) laden
mcFInit4:
        invoke ReadFile,hFile,prgptr,prgsize,ADDR br,NULL
        invoke CloseHandle,hFile

;        print chr$("$")
;        mov     eax,br
;        call    hex_eax       
;        print chr$(" Bytes Programm:",13,10)
;        mov esi, prgptr
;        call dump_si

mcFInit5:
        pop 	esi
        mov 	lpArg,esi		; Befehlszeile ist Rest
; Register initialisieren
     	mov     eax,prgoff              ; PC auf Programmanfang
        mov     fpc,eax
        mov     eax,varoff              ; RP auf Variablenende
        add     eax,varsize
        mov     frp,eax
        sub     eax,100h                ; SP $100 Bytes darunter
        mov     fsp,eax
        mov     eax,0                   ; IP auf 0
        mov     fip,eax
        mov     eax,0                   ; W auf 0
        mov     fw,eax
        add     varsize,12              ; +12 Byte für Stackanzeige
        ret
; =========================================================================
mcFInite:
    .endif
    pop esi

; Abbruch wegen fehlendem File
    print  chr$("Missing ucF Image File Name",13,10)
    invoke  wait_key
    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Unterprogramme für FORTH
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; ------------------------------------------------
; Key? (Flag in EAX bzw. AX bzw. AL)
; ------------------------------------------------
keyq:
    push    ebx
    push    edx
    push    esi
    call	crt__kbhit
    test    eax,eax
    jz      keyq1
    mov     eax,-1
keyq1:
    pop     esi
    pop     edx
    pop     ebx
    ret     

; ------------------------------------------------
; Key (Zeichen in EAX bzw. AL)
; ------------------------------------------------
key:
    push    ebx
    push    edx
    push    esi
    invoke  crt__getch,eax
; Option für Debugger: ESC schaltet Debugger an
;    cmp     ax,01bh
;    jnz     key1
;    or      debug,D_END
key1:
;    cmp     ax,4
;    jnz     key2
;    call    mcFTrace
;    print   chr$(13,10)
;    mov     eax,7
key2:
    pop     esi
    pop     edx
    pop     ebx
    ret     

; ------------------------------------------------
; Emit? (Flag in EAX bzw. AX bzw. AL)
; ------------------------------------------------
emitq:
    mov     eax,-1
    ret

; ------------------------------------------------
; Emit (Zeichen in AL)
; ------------------------------------------------
emit:
    push    ebx
    push    edx
    push    esi
;    invoke crt__putch, eax
    mov     cbuf, al
    mov     cbuf+1, 0
    print   offset cbuf 

    pop     esi
    pop     edx
    pop     ebx
    ret     
; ------------------------------------------------
; Wait (Zeit in EAX)
; ------------------------------------------------
waitms:
    push    ebx
    push    edx
    push    esi
    invoke  Sleep,eax
    pop     esi
    pop     edx
    pop     ebx
    ret     

; ------------------------------------------------
; Debug-Ausgabe:
; ------------------------------------------------
; REGDUMP: Alle Register ausgeben
regdump:
    push    eax
    push    ebx
    push    ecx
    push    edx
    push    edi
    push    esi
    push    esi
    push    edi
    push    edx
    push    ecx
    push    ebx
    push    eax
    print   chr$(13,10,"EAX:")
    pop     eax
    call    hex_eax
    print   chr$(" EBX:")
    pop     eax
    call    hex_eax
    print   chr$(" ECX:")
    pop     eax
    call    hex_eax
    print   chr$(" EDX:")
    pop     eax
    call    hex_eax
    print   chr$(" EDI:")
    pop     eax
    call    hex_eax
    print   chr$(" ESI:")
    pop     eax
    call    hex_eax
    print   chr$(13,10)
    pop     esi
    pop     edi
    pop     edx
    pop     ecx
    pop     ebx
    pop     eax
    ret
; ------------------------------------------------
; PTRDUMP: Alle Pointer und Flags ausgeben
ptrdump:
    push    eax
    push    ebx
    push    ecx
    push    edx
    push    edi
    push    esi
    print   chr$(13,10,"Flag:")
    mov     eax,pvflag
    call    hex_eax
    print   chr$(13,10," PRGPTR:")
    mov     eax,prgptr
    call    hex_eax
    print   chr$(" PRGOFF:")
    mov     eax,prgoff
    call    hex_eax
    print   chr$(" PRGSIZE:")
    mov     eax,prgsize
    call    hex_eax
    print   chr$(13,10," VARPTR:")
    mov     eax,varptr
    call    hex_eax
    print   chr$(" VAROFF:")
    mov     eax,varoff
    call    hex_eax
    print   chr$(" VARSIZE:")
    mov     eax,varsize
    call    hex_eax
    pop     esi
    pop     edi
    pop     edx
    pop     ecx
    pop     ebx
    pop     eax
    ret
    ret
; ------------------------------------------------
; Dump: 16 Byte ab EAX ausgeben
dump_si:
    mov     eax,esi
    call    hex_eax
    mov     ecx,16
dump_si1:
    push    ecx
    print   chr$(32)
    lodsb
    call    hex_al
    pop     ecx
    loop    dump_si1
    ret
; ------------------------------------------------
; Register EAX ausgeben
; 2 Hex-Zeichen ab CBUF ablegen (von hinten nach vorne)
hex_al:
    push    ecx
    push    ebx
    mov     ecx,2
    jmp     hex_eax0
; ------------------------------------------------
; Register AX ausgeben
; 4 Hex-Zeichen ab CBUF ablegen (von hinten nach vorne)
hex_ax:
    push    ecx
    push    ebx
    mov     ecx,4
    jmp     hex_eax0
; ------------------------------------------------
; 8 Hex-Zeichen ab CBUF ablegen (von hinten nach vorne)
hex_eax:
    push    ecx
    push    ebx
    mov     ecx,8
hex_eax0:
    mov     ebx,offset cbuf
    add     ebx,ecx 
    and     byte ptr [ebx],0
hex_eax1:  
    dec     ebx
    push    eax
; Nibble in ASCII umwandeln und speichern
    and     al,00fh
    or      al,030h
    cmp     al,03ah
    jb      hex_eax2
    add     al,007h
hex_eax2:
    mov     [ebx],al
; Nächstes Zeichen
    pop     eax
    shr     eax,4
    dec     ecx
    jnz     hex_eax1
; Ausgabe    
    print   offset cbuf 
    pop     ebx
    pop     ecx
    ret
; ------------------------------------------------
; Hex-Adresse lesen (ESI zeigt auf String)
gethex:
    mov     ebx,0       ; Anfangswert 0
gethex1:
    call    upcchar     ; nächstes Zeichen in Großschrift
    cmp     al,030h     ; $30..$39 ?
    jb      gethexe     ; <$30 nicht ausgewertet
    sub     al,030h     ; -$30
    cmp     al,00ah     ; <$3A ist Zahl 0..9
    jb      gethexadd   ; EBX*10+al
    sub     al,007h     ; -$07 ("A" ist 10)
    cmp     al,10
    jb      gethexe     ; unter "A" nicht erlaubt
    cmp     al,16
    ja      gethexe     ; über "F" nicht erlaubt
gethexadd:
    shl     ebx,4       ; EBX * $10
    add     bl,al       ; Hex-Wert übernehmen (+AL)
    jmp     gethex1     ; nächstes Zeichen
gethexe:
    sub     esi,1
    ret
; ------------------------------------------------
; Nächstes Zeichen von ESI als Großbuchstabe
upcchar:
    lodsb
    cmp     al,061h
    jb      upcchar1
    cmp     al,07ah
    jnbe    upcchar1
    sub     al,020h
upcchar1:
    ret
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

; Image in einem eigenen File (aktuell: immer externes File erwartet)
;   include  PRG32.ASM                  ; automatisch generiertes Image   
;   db 65536-mcfsize dup (255)          ; bis 64K auffüllen


end start                       ; Tell MASM where the program ends
