OldComp.cz

Komunitní diskuzní fórum pro fanoušky historických počítačů


Právě je 28.03.2024, 21:13

Všechny časy jsou v UTC + 1 hodina [ Letní čas ]




Odeslat nové téma Odpovědět na téma  [ Příspěvků: 585 ]  Přejít na stránku Předchozí  1 ... 8, 9, 10, 11, 12, 13, 14 ... 39  Další
Autor Zpráva
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 07.12.2021, 14:01 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Kdyz me nikdo neporadil jak je to s temi retezci v ZX ROM tak jsem si to nasel sam. Na netu jsem to hledal ve vpisu ZX ROM a nenasel tak jsem spustil FUSE a pres Memory Browser si nasel adresu kde jsou ulozeny ty jmena tokenu. Nasel jsem si nejaky pekny co zacina na hezke adrese a dal do FUSE breakpoint pro cteni z konkretni adresy "br read 0x00C0". Pak stacilo jen napsat v basicu ten token a uz jsem mel podezrelou adresu ROM. Ukazalo se ale ze je to pro me ucely nevhodne, protoze ROM s tim provadi jeste nejake dodatecne kejkle nez udela RET.
Kód:
The table is searched and the correct entry printed.

0C14 PO-TABLE
    CALL 0C41,PO-SEARCH         Locate the required entry.
    JR C,0C22,PO-EACH           Print the message/token.
    LD A,+20                    A 'space' will be printed
    BIT 0,(FLAGS)               before the message/token
    CALL Z,0C3B,PO-SAVE         if required.
   
The characters of the message/token are printed in turn.

0C22 PO-EACH
    LD A,(DE)                   Collect a code.
    AND +7F                     Cancel any 'inverted bit'.
    CALL 0C3B,PO-SAVE           Print the character.
    LD A,(DE)                   Collect the code again.
    INC DE                      Advance the pointer.
    ADD A,A                     The 'inverted bit' goes to
    JR NC,0C22,PO-EACH          the carry flag and signals
                                the end of the message/token;
                                otherwise jump back.
                               
Now consider whether a 'trailing space' is required.

    POP DE                      For messages - D holds +00;
                                for tokens - D holds +00 - +5A.
    CP +48                      Jump forward if the last
    JR Z,0C35,PO-TRSP           character was a '$'.
    CP +82                      Return if the last character
    RET C                       was any other before 'A'.
0C35 PO-TR-SP
    LD A,D                      Examine the value in D and
    CP +03                      return if it indicates a
    RET C                       message, RND, INKEY$ or PI.
    LD A,+20                    All other cases will require
                                a 'trailing space'.

THE 'PO-SAVE' SUBROUTINE

This subroutine allows for characters to be printed 'recursively'. The appropriate registers are saved whilst 'PRINT-OUT' is called.

0C3B PO-SAVE
    PUSH DE                     Save the DE register pair.
    EXX                         Save HL & BC.
    RST 0010,PRINT-A-1          Print the single character.
    EXX                         Restore HL & BC.
    POP DE                      Restore DE.
    RET                         Finished.
Takze jsem prevzal jen tu jednu cast, protoze me nenapadlo jak to napsat lepe. Horsi boj byl s makrem M4. Protoze potrebuji vyhodnotit zda text konci uvozovkami a tak vytahnout posledni znak a ten oddelit a pricist k nemu 0x80.

Zase jsem se dostal do bodu, kdy me to bud nerozbalilo makro nebo se mi parametr makra rozpadl na vice parametru, kdyz makro obsahovalo carku. Pres nekolik pokusu jsem presel na nejslibnejsi metodu s "regexp", coz je makro co zpracovava regularni vyraz. Ale porad to neslo i kdyz jsem mel treba spravny mezivysledek tak nesel predat dal jako parametr dalsiho makra. Takze jsem zacal vypisovat prubezne hodnoty, zkousel "changequote" a nic a nic a nic. Nakonec hrubou silou to vyslo. Zadne pomocne slibne promene, jen to primo napsat do parametru a v jednom miste zdvojit uvozovky {{ }}.
Kód:
dnl ." string"
dnl .( string)
dnl ( -- )
dnl print string ending with inverted most significant bit
define({PRINT_I},{dnl
__{}ifelse(dnl
__{}regexp({$*},{^\(.*\)\("[^"]"\)\s*$},{{"text","x"}}),{"text","x"},
__{}__{}{_PRINT_I(regexp({$*},{^\(.*\)\("[^"]"\)\s*$},{{\1\2 + 0x80}}))},
__{}regexp({$*},{"\s*$},{"text"}),{"text"},
__{}__{}{_PRINT_I(regexp({$*},{^\(.+\)\(.\)"\s*$},{{\1","\2"+0x80}}))},
__{}{dnl
__{}__{}_PRINT_I(regexp({$*},{^\(.+\)"\([^"]+[^" ]\)\s*$},{{\1"\2 + 0x80}})){}dnl
__{}}){}dnl
})dnl
Takhle to vypada snadno, ze to nedalo hodiny prace. Zakladni pointa kterou jsem hledal je _PRINT_I(regexp({vstupni_parametry},{regularni_vyraz},{{co_s_tim_chci_delat}}).
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth$ ./check_word.sh 'PRINT_I({"<=", 0x0d}) PRINT_I({"<=", 0x0d          })'
; vvv
; ^^^
    ld   BC, string101  ; 3:10      print_i   Address of string101 ending with inverted most significant bit
    call PRINT_STRING_I ; 3:17      print_i
    ld   BC, string101  ; 3:10      print_i   Address of string101 ending with inverted most significant bit == string102
    call PRINT_STRING_I ; 3:17      print_i
;==============================================================================
; Print string ending with inverted most significant bit
; In: BC = addr string_imsb
; Out: BC = addr last_char + 1
PRINT_STRING_I:         ;           print_string_i
    ld    A,(BC)        ; 1:7       print_string_i
    and  0x7f           ; 2:7       print_string_i
    rst  0x10           ; 1:11      print_string_i putchar with ZX 48K ROM in, this will print char in A
    ld    A,(BC)        ; 1:7       print_string_i
    add   A, A          ; 1:4       print_string_i
    inc  BC             ; 1:6       print_string_i
    jp   nc, $-10       ; 3:10      print_string_i
    ret                 ; 1:10      print_string_i

STRING_SECTION:
string101:
db "<=", 0x0d + 0x80
size101 EQU $ - string101
                       ;[23:116]
dworkin@dw-A15:~/Programovani/ZX/Forth$ ./check_word.sh 'PRINT_I({"<="}) PRINT_I({"<="          })'
; vvv
; ^^^
    ld   BC, string101  ; 3:10      print_i   Address of string101 ending with inverted most significant bit
    call PRINT_STRING_I ; 3:17      print_i
    ld   BC, string101  ; 3:10      print_i   Address of string101 ending with inverted most significant bit == string102
    call PRINT_STRING_I ; 3:17      print_i
;==============================================================================
; Print string ending with inverted most significant bit
; In: BC = addr string_imsb
; Out: BC = addr last_char + 1
PRINT_STRING_I:         ;           print_string_i
    ld    A,(BC)        ; 1:7       print_string_i
    and  0x7f           ; 2:7       print_string_i
    rst  0x10           ; 1:11      print_string_i putchar with ZX 48K ROM in, this will print char in A
    ld    A,(BC)        ; 1:7       print_string_i
    add   A, A          ; 1:4       print_string_i
    inc  BC             ; 1:6       print_string_i
    jp   nc, $-10       ; 3:10      print_string_i
    ret                 ; 1:10      print_string_i

STRING_SECTION:
string101:
db "<","="+0x80
size101 EQU $ - string101
                       ;[23:116]

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 07.12.2021, 14:07 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Pri tom jsem narazil na chybu v "push2" makru. Kde jsem zapomnel umazat pomocne informace, kdyz jsem vylepsoval makro. Protoze zakladni makro bylo:
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth$ ./check_word.sh 'PUSH(0x0102)PUSH(0x0304)'
; vvv
; ^^^
    push DE             ; 1:11      push(0x0102)
    ex   DE, HL         ; 1:4       push(0x0102)
    ld   HL, 0x0102     ; 3:10      push(0x0102)
    push DE             ; 1:11      push(0x0304)
    ex   DE, HL         ; 1:4       push(0x0304)
    ld   HL, 0x0304     ; 3:10      push(0x0304)
                       ;[10:50]
dworkin@dw-A15:~/Programovani/ZX/Forth$ ./check_word.sh 'PUSH2(0x0102,0x0304)'
; vvv
; ^^^
    push DE             ; 1:11      push2(0x0102,0x0304)
    ld   DE, 0x0102     ; 3:10      push2(0x0102,0x0304)
    push HL             ; 1:11      push2(0x0102,0x0304)
    ld   HL, 0x0304     ; 3:10      push2(0x0102,0x0304)
                       ;[ 8:42]

Coz vypada optimalne, ale neni! Protoze kdyz budete vkladat shodne hodnoty, pak nastupuji optimalizace:
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth$ ./check_word.sh 'PUSH2(0x0102,0x0102)'
; vvv
; ^^^
    push DE             ; 1:11      push2(0x0102,0x0102)
    push HL             ; 1:11      push2(0x0102,0x0102)
    ld   HL, 0x0102     ; 3:10      push2(0x0102,0x0102)
    ld    D, H          ; 1:4       push2(0x0102,0x0102)
    ld    E, L          ; 1:4       push2(0x0102,0x0102)
                       ;[ 7:40]
dworkin@dw-A15:~/Programovani/ZX/Forth$ ./check_word.sh 'PUSH2(0x0102,0x0201)'
; vvv
; ^^^
    push DE             ; 1:11      push2(0x0102,0x0201)
    push HL             ; 1:11      push2(0x0102,0x0201)
    ld   HL, 0x0201     ; 3:10      push2(0x0102,0x0201)
    ld    D, L          ; 1:4       push2(0x0102,0x0201)
    ld    E, H          ; 1:4       push2(0x0102,0x0201)
                       ;[ 7:40]

PS: Jinak pripominam pro pochopeni, mam zasobnik delany tak ze krome toho co lezi v SP, nasleduje registrovy par DE a pak HL (ktery je tak TOS = top of stack).

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 07.12.2021, 15:02 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Hmm... porad je co vylepsovat. .) Rovnou jsem pridal dalsi 4 opomenute kombinace a opravil variantu kdy mohou byt volane parametry v uvozovkach a jsou tak odkazy na skutecne hodnoty, takze je nelze takhle optimalizovat. Kdyz se totiz predhodi vestavenemu makru eval(100) nebo eval((50+50)) tak je to pro nej shodna hodnota.
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth$ ./check_word.sh 'PUSH2(0x0103,0x0303)'
; vvv
; ^^^
    push DE             ; 1:11      push2(0x0103,0x0303)
    push HL             ; 1:11      push2(0x0103,0x0303)
    ld   DE, 0x0103     ; 3:10      push2(0x0103,0x0303)
    ld    H, E          ; 1:4       push2(0x0103,0x0303)
    ld    L, E          ; 1:4       push2(0x0103,0x0303)
                       ;[ 7:40]
dworkin@dw-A15:~/Programovani/ZX/Forth$ ./check_word.sh 'PUSH2(0x0103,0x0101)'
; vvv
; ^^^
    push DE             ; 1:11      push2(0x0103,0x0101)
    push HL             ; 1:11      push2(0x0103,0x0101)
    ld   DE, 0x0103     ; 3:10      push2(0x0103,0x0101)
    ld    H, D          ; 1:4       push2(0x0103,0x0101)
    ld    L, D          ; 1:4       push2(0x0103,0x0101)
                       ;[ 7:40]
dworkin@dw-A15:~/Programovani/ZX/Forth$ ./check_word.sh 'PUSH2(0x0303,0x0103)'
; vvv
; ^^^
    push DE             ; 1:11      push2(0x0303,0x0103)
    push HL             ; 1:11      push2(0x0303,0x0103)
    ld   HL, 0x0103     ; 3:10      push2(0x0303,0x0103)
    ld    D, L          ; 1:4       push2(0x0303,0x0103)
    ld    E, L          ; 1:4       push2(0x0303,0x0103)
                       ;[ 7:40]
dworkin@dw-A15:~/Programovani/ZX/Forth$ ./check_word.sh 'PUSH2(0x0101,0x0103)'
; vvv
; ^^^
    push DE             ; 1:11      push2(0x0101,0x0103)
    push HL             ; 1:11      push2(0x0101,0x0103)
    ld   HL, 0x0103     ; 3:10      push2(0x0101,0x0103)
    ld    D, H          ; 1:4       push2(0x0101,0x0103)
    ld    E, H          ; 1:4       push2(0x0101,0x0103)
                       ;[ 7:40]

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 26.02.2022, 01:11 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Hledal jsem na rosettacode nejake male programky ve Forthu, ktere bych mohl vyzkouset zkompilovat M4 FORTHem. A protoze jsem na rosettacode jednou prispel ZX Spectrum Basicem tak jsem zvolil https://rosettacode.org/wiki/Levenshtein_distance.

Po nejakych drobnych upravach se mi to podarilo zkompilovat, ale byl jsem zdeseny, kdyz vysledek byl mnohem pomalejsi nez obycejny basic. Protoze uvedeny algoritmus pro FORTH pouziva rekurzi a tak se nevyhnu pouziti druheho emulovaneho zasobniku pro navratove adresy (=RASu). A implementace druheho zasobniku je opravdu neefektivni. Az tak neefektivni, ze prepsani algoritmu tak, aby RAS omezil nasobne zrychluje kod. Ktery ale zase nevypada jako neco co byste psali ve Forthu...

Snazil jsem se to pracne prepsat znovu podle meho vzoru v basicu. Bez rekurze, zato s tabulkou. Ale tady jsem taky narazil, protoze jsem potreboval prilis mnoho aktivnich 16 bitovych promennych a vysledek byl pro me neakceptovatelny. V registrech uchovavam TOS (prvni hodnotu na zasobniku), NOS (druhou hodnotu na zasobniku), treti si muzu nacist do BC, ale s ctvrtou a patou uz mam problem... Jo, jde to resit, ale aby to bylo efektivni...

Obecne ten algoritmus potrebuje prochazet pole, bunku po bunce. Coz je fajn, staci zvysovat pointer. Pak je potreba cist jednu bunku vlevo, jednu na predchozim radku a jednu vlevo na predchozim radku. Cele to ma byt zanorene ve dvou smyckach, kazda prochazi znak po znaku jeden retezec.

Nejsem priznivcem registru IX, protoze VZDY lze napsat kratsi a rychlejsi kod bez jeho pouziti. Pokud jsou ale vsechny registry uz obsazene tak to je asi prijatelna volba. Takze jsem IX pouzil jako index a jeho pricitaci konstanty jako relativni ukazatele na jine bunky. Retezce jsem zmenil na C-style. Teda zakoncene nulou, abych omezil dalsi promenne. A nakonec algoritmus napsal. Na zasobniku ma minimalne jen 2 adresy na aktualni znak v porovnavanych retezcich. Obcas se pridaji ty znaky, nebo hodnota bunek, ale aktivne jsou potreba v jeden okamzik stale jen 2 promenne ktere jsou na vrcholu.

Super. Ale to fungovalo jen na retezce ktere jsem zadal primo do zdrojaku. Ne na retezce nactene uzivatelem, protoze ty budou mit jinou delku a teda i ta tabulka bude mit jine rozmery a teda i bunka na dalsim radku bude mit jiny relativni offset. Ale ty jsou v instrukci asembleru Z80 konstatni.

ld E,(IX+konstanta)

A tady jsem se na tydny zasekl. Pocitat to vzdy pro nejvetsi variantu? To fakt ne.

V assembleru proste napisete sebeprepisujici kod a hotovo. Jak to ale prenest do "vyssiho" jazyka?

Problem je v tom, ze kdyz tam pokazde vygeneruji label tak ho musim prepsat PRED tim nez ho pouziji. M4 FORTH je ale jednopruchodovy. V okamziku, kdy potrebuji abych generoval kod pro prepsani konstant o nich nic nevim. Kolik jich je, jak se jmenuji atd.

Takze jsem mel predstavu ze to udelam nejak tak, ze pokazde vygeneruji label, ten nejakym makrem ulozim a na konci rozbalim v nejake funkci. A tu funkci budu volat hned na zacatku v miste kde potrebuji menit kod. Neco jako:
Kód:
PUSH(69)   ; HL = 69
call PREPIS_HODNOTU
...
lab01 EQU $+2
ld A,(IX+96)
...
lab02 EQU $+2
ld A,(IX+96)
...
PREPIS_HODNOTU:
ld  A,L
ld (lab01), A
ld (lab02), A
ret

Ale byl jsem zatim prilis linej zjistovat jak mam napsat to makro na ukladani jmen labelu a jeste me vadilo, ze musim volat funkci i kdybych to pouzil jen jednou a chci to "inline".

Takze jsem to nechal plavat a po dlouhem case mi konecne docvaklo jak jsem blbej... Spravne reseni je mit dalsi nepovinny parametr u slova co cte nebo uklada z pole (tedy tech, ktere potrebuji menit). Prvni je ten relativni offset a pripadny druhy je jmeno toho labelu. Problem se prenese na programatora a ten si to uz ohlida a muze psat neco jako:
Kód:
PUSH2_CSTORE(69,lab01)
PUSH2_CSTORE(69,lab02)
...
ARRAY_CFETCH(96,lab01)
...
ARRAY_CFETCH(96,lab02)


Tady je navrh knihovny, jaka slova to umi:
https://github.com/DW0RKiN/M4_FORTH#array
https://github.com/DW0RKiN/M4_FORTH/blob/master/M4/array.m4

Tady je ten program:
https://github.com/DW0RKiN/M4_FORTH/blob/master/Testing/levenshtein.m4
https://github.com/DW0RKiN/M4_FORTH/blob/master/Testing/levenshtein.asm

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 26.02.2022, 02:04 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Kdyz uz jsem zpracovaval retezce od uzivatele tak jsem musel prepsat slovo ACCEPT ktere pro to FORTH pouziva. Jedna vec byla spatne mazani nactene promenne. Mazal jsem ji na zacatku, nacetl, rychle zpracoval a skocil na zacatek kde se maze. Ale pocitove to nejak drhlo, i kdyz by nemelo. Protoze 50x za vterinu by se melo vykonat mnohem vice instrukci. Takze jsem to prepsal. Maze se to na zacatku jednou a pak uz jen pokazde POTE co to uspesne nacte znak. Zmenil jsem tak i slovo KEY, ktere ma nacitat znak (getchar s cekanim). Maze buffer take az a jedine po nacteni znaku. Proto jsem pridal slovo CLEARKEY, ktere maze buffer pro pripadne pouziti na zacatku programu. A jeste KEYQUESTION (key?) ktere ma vracet TRUE pokud neco v bufferu je.

No a kdyz jsem pouzival ACCEPT tak, jsem se diky tomu, ze nektere znaky nezaznamenal spletl a narazil s tim, ze nemam implementovany ani mazani predchoziho znaku. Takze pridal i to, coz uz nebylo na par instrukci, protoze se musi hlidat i podteceni retezce, udelat posun kurzoru vlevo, tisknout mezeru a zase posunout kurzor vlevo. Takze to uz trosku narostlo (cca 20 bajtu), ale nemit mazani je vetsi opruz.

Proc to pisi. Nevi nekdo zda nejde nejak efektivne pouzit INPUT $A z ROM v assembleru? Co to umi? Jak se to vola?

ACCEPT je definovane tak ze v NOS (u me reg. DE) je addresa prvniho znaku noveho retezce, v TOS (u me reg. HL) je maximalni pocet znaku a slovo vraci v TOS skutecny pocet nactenych znaku, protoze ENTER muze delku zkratit. Ma to zvladat retezce vetsi jak 255 znaku.
Kód:
ifdef({USE_ACCEPT},{ifdef({USE_CLEARKEY},,define({USE_CLEARKEY},{}))
;==============================================================================
; Read string from keyboard
; In: DE = addr_string, HL = max_length
; Out: pop stack, TOP = HL = loaded
READSTRING:
__{}ifdef({USE_ACCEPT_Z},{dnl
__{}    dec  HL             ; 1:6       readstring_z
__{}})dnl
    ld   BC, 0x0000     ; 3:10      readstring   loaded
    call CLEARBUFF      ; 3:17      readstring
READSTRING2:
    ld    A,(0x5C08)    ; 3:13      readstring   read new value of {LAST K}
    or    A             ; 1:4       readstring   is it still zero?
    jr    z, READSTRING2; 2:7/12    readstring

    call CLEARBUFF      ; 3:17      readstring
    ld  (DE),A          ; 1:7       readstring   save char

    cp  0x0C            ; 2:7       readstring   delete?
    jr   nz, READSTRING3; 2:7/12    readstring
    ld    A, B          ; 1:4       readstring
    or    C             ; 1:4       readstring
    jr    z, READSTRING2; 2:7/12    readstring   empty string?
    dec  DE             ; 1:6       readstring   addr--
    dec  BC             ; 1:6       readstring   loaded--
    inc  HL             ; 1:6       readstring   space++
    ld    A, 0x08       ; 2:7       readstring
    rst   0x10          ; 1:11      putchar with {ZX 48K ROM} in, this will print char in A
    ld    A, 0x20       ; 2:7       readstring
    rst   0x10          ; 1:11      putchar with {ZX 48K ROM} in, this will print char in A
    ld    A, 0x08       ; 2:7       readstring
    rst   0x10          ; 1:11      putchar with {ZX 48K ROM} in, this will print char in A
    jr   READSTRING2    ; 2:12      readstring
READSTRING3:

    cp  0x0D            ; 2:7       readstring   enter?
    jr    z, READSTRING4; 2:7/12    readstring

    rst   0x10          ; 1:11      putchar with {ZX 48K ROM} in, this will print char in A
    inc  DE             ; 1:6       readstring   addr++
    inc  BC             ; 1:6       readstring   loaded++
    dec  HL             ; 1:6       readstring   space--
    ld    A, H          ; 1:4       readstring
    or    L             ; 1:4       readstring
    jr   nz, READSTRING2; 2:7/12    readstring

READSTRING4:            ;           readstring   A = 0, flag: z, nc
__{}ifdef({USE_ACCEPT_Z},{dnl
__{}    xor   A             ; 1:7       readstring_z
__{}    ld  (DE),A          ; 1:7       readstring_z  set zero char
__{}})dnl
    pop  HL             ; 1:10      readstring   ret
    pop  DE             ; 1:10      readstring
    push HL             ; 1:11      readstring   ret
    ld    H, B          ; 1:4       readstring
    ld    L, C          ; 1:4       readstring
    ret                 ; 1:10      readstring}){}dnl
dnl
dnl
dnl
ifdef({USE_KEY},{ifdef({USE_CLEARKEY},,define({USE_CLEARKEY},{}))
;==============================================================================
; Read key from keyboard
; In:
; Out: push stack, TOP = HL = key
READKEY:
    ex   DE, HL         ; 1:4       readkey   ( ret . old _DE old_HL -- old_DE ret . old_HL key )
    ex  (SP),HL         ; 1:19      readkey
    push HL             ; 1:11      readkey

    ld    A,(0x5C08)    ; 3:13      readkey   read new value of {LAST K}
    or    A             ; 1:4       readkey   is it still zero?
    jr    z, $-4        ; 2:7/12    readkey
    ld    L, A          ; 1:4       readkey
    ld    H, 0x00       ; 2:7       readkey
;   ...fall down to clearbuff}){}dnl
ifdef({USE_CLEARKEY},{
;==============================================================================
; Clear key buffer
; In:
; Out: {(LAST_K)} = 0
CLEARBUFF:
    push HL             ; 1:11      clearbuff
    ld   HL, 0x5C08     ; 3:10      clearbuff   {ZX Spectrum LAST K} system variable
    ld  (HL),0x00       ; 2:10      clearbuff
    pop  HL             ; 1:10      clearbuff
    ret                 ; 1:10      clearbuff}){}dnl

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 28.02.2022, 17:52 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Jeste jsem ten vstup retezce pomoci ROM rutiny nerozlousknul. Nejsem si uz ani jisty, zda se ptam spravne na tomhle foru... .) Diky DEXi za "like", potesilo vedomi ze to nekdo cte.

Nasel jsem ale mezitim zpusob jak tisknout 16 bitovy integer pomoci ZX ROM. FORTH tiskne integer pomoci slova
Kód:
.
a unsigned pomoci
Kód:
u.
V M4 FORTH se ty slova jmenuji "DOT" a "UDOT". Pridal jsem ted slova "DOTZXROM" a "UDOTZXROM".

UDOTZXROM pouziva rutinu na ulozeni unsigned cisla v BC na zasobnik cisel s plovouci carkou a pak rutinu co tiskne cislo z toho zasobniku.

DOTZXROM je trochu slozitejsi protoze musime rici, ze to cislo je signed. Takze se ta prvni rutina musi udelat rucne. V podstate chceme dat do registru:

A nulu
E sign (0x00 nebo 0xFF podle nejvysiho bitu toho 16 bitoveho cisla)
D nizsi bajt cisla
C vyssi bajt cisla
B = 0

Pokud je cislo zaporne tak ho nemenime na kladne, jen nastavime registr E na 0xFF. A pak zavolame zbytek rutiny. Tady mam zase otazku. Ta rutina nastavuje IY. Je to nutne?

Tady je mala ukazka FORTH programu co tiskne cisla 1,2,4,8,16...
Kód:
;vvvvv
include(`../M4/FIRST.M4')dnl
;^^^^^
ORG 0x8000
INIT(0xF000)

PUSH(1)
BEGIN
    DUP UDOTZXROM
    DUP DOTZXROM
    DUP NEGATE DOTZXROM
    CR
    _2MUL
DUP_INVERT_UNTIL

STOP
A tady je videt vystup v asembleru.
Kód:
;vvvvv
;^^^^^
ORG 0x8000

;   ===  b e g i n  ===
    ld  (Stop+1), SP    ; 4:20      init   storing the original SP value when the "bye" word is used
    ld    L, 0x1A       ; 2:7       init   Upper screen
    call 0x1605         ; 3:17      init   Open channel
    ld   HL, 0xF000     ; 3:10      init   Init Return address stack
    exx                 ; 1:4       init


    push DE             ; 1:11      push(1)
    ex   DE, HL         ; 1:4       push(1)
    ld   HL, 1          ; 3:10      push(1)

begin101:               ;           begin 101
   
    push DE             ; 1:11      dup
    ld    D, H          ; 1:4       dup
    ld    E, L          ; 1:4       dup ( a -- a a )
    call PRINT_ZXROM_U16; 3:17      u.zxrom   ( u -- )
   
    push DE             ; 1:11      dup
    ld    D, H          ; 1:4       dup
    ld    E, L          ; 1:4       dup ( a -- a a )
    call PRINT_ZXROM_S16; 3:17      .zxrom   ( x -- )
   
    push DE             ; 1:11      dup
    ld    D, H          ; 1:4       dup
    ld    E, L          ; 1:4       dup ( a -- a a )
    xor   A             ; 1:4       negate
    sub   L             ; 1:4       negate
    ld    L, A          ; 1:4       negate
    sbc   A, H          ; 1:4       negate
    sub   L             ; 1:4       negate
    ld    H, A          ; 1:4       negate
    call PRINT_ZXROM_S16; 3:17      .zxrom   ( x -- )
   
    ld    A, 0x0D       ; 2:7       cr      Pollutes: AF, DE', BC'
    rst   0x10          ; 1:11      cr      with 48K ROM in, this will print char in A
   
    add  HL, HL         ; 1:11      2*

    ld    A, H          ; 1:4       dup invert until 101   ( flag -- flag )
    or    L             ; 1:4       dup invert until 101
    jp   nz, begin101   ; 3:10      dup invert until 101
break101:               ;           dup invert until 101


Stop:                   ;           stop
    ld   SP, 0x0000     ; 3:10      stop   restoring the original SP value when the "bye" word is used
    ld   HL, 0x2758     ; 3:10      stop
    exx                 ; 1:4       stop
    ret                 ; 1:10      stop
;   =====  e n d  =====

;==============================================================================
; Input: HL
; Output: Print space and unsigned decimal number in HL
; Pollutes: AF, BC, HL <- DE, DE <- (SP)
PRINT_ZXROM_U16:        ;           print_zxrom_u16
    ld    A, ' '        ; 2:7       print_zxrom_u16   putchar Pollutes: AF, DE', BC'
    rst   0x10          ; 1:11      print_zxrom_u16   putchar with ZX 48K ROM in, this will print char in A
    ; fall to print_zxrom_u16_only
;------------------------------------------------------------------------------
; Input: HL
; Output: Print unsigned decimal number in HL
; Pollutes: AF, BC, HL <- DE, DE <- (SP)
PRINT_ZXROM_U16_ONLY:   ;           print_zxrom_u16_only
    push DE             ; 1:11      print_zxrom_u16_only   ( u -- )
    ld    B, H          ; 1:4       print_zxrom_u16_only
    ld    C, L          ; 1:4       print_zxrom_u16_only
    call 0x2D2B         ; 3:17      print_zxrom_u16_only   call ZX ROM stack BC routine
    call 0x2DE3         ; 3:17      print_zxrom_u16_only   call ZX ROM print a floating-point number routine'

    pop  HL             ; 1:10      print_zxrom_u16_only
    pop  BC             ; 1:10      print_zxrom_u16_only   load ret
    pop  DE             ; 1:10      print_zxrom_u16_only
    push BC             ; 1:11      print_zxrom_u16_only   save ret
    ret                 ; 1:10      print_zxrom_u16_only
;==============================================================================
; Input: HL
; Output: Print space and signed decimal number in HL
; Pollutes: AF, BC, HL <- DE, DE <- (SP)
PRINT_ZXROM_S16:        ;           print_zxrom_s16
    ld    A, ' '        ; 2:7       print_zxrom_s16   putchar Pollutes: AF, DE', BC'
    rst   0x10          ; 1:11      print_zxrom_s16   putchar with ZX 48K ROM in, this will print char in A
    ; fall to print_zxrom_s16_only
;------------------------------------------------------------------------------
; Input: HL
; Output: Print signed decimal number in HL
; Pollutes: AF, BC, HL <- DE, DE <- (SP)
PRINT_ZXROM_S16_ONLY:   ;           print_zxrom_s16_only
    push DE             ; 1:11      print_zxrom_s16_only   ( u -- )
    ld    A, H          ; 1:4       print_zxrom_s16_only
    add   A, A          ; 1:4       print_zxrom_s16_only
    sbc   A, A          ; 1:4       print_zxrom_s16_only   sign
    ld    E, A          ; 1:4       print_zxrom_s16_only   2. byte sign
    xor   A             ; 1:4       print_zxrom_s16_only   1. byte = 0
    ld    D, L          ; 1:4       print_zxrom_s16_only   3. byte lo
    ld    C, H          ; 1:4       print_zxrom_s16_only   4. byte hi
    ld    B, A          ; 1:4       print_zxrom_s16_only   5. byte = 0
   
    ld   IY, 0x5C3A     ; 4:14      print_zxrom_s16_only   Re-initialise IY to ERR-NR.

    call 0x2AB6         ; 3:17      print_zxrom_s16_only   call ZX ROM STK store routine
    call 0x2DE3         ; 3:17      print_zxrom_s16_only   call ZX ROM print a floating-point number routine'
    pop  HL             ; 1:10      print_zxrom_s16_only
    pop  BC             ; 1:10      print_zxrom_s16_only   load ret
    pop  DE             ; 1:10      print_zxrom_s16_only
    push BC             ; 1:11      print_zxrom_s16_only   save ret
    ret                 ; 1:10      print_zxrom_u16_only
Příloha:
nasobky.png
nasobky.png [ 6.5 KiB | Zobrazeno 3217 krát ]

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 05.03.2022, 23:57 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Pri zkoumani rom ZX 48 jsem narazil na jeho kalkulacku. Vypadalo to snazsi na pouziti nez ta rutina pro cteni textu. Tak jsem si s tim hral a udel jsem si slovo pro ulozeni celociselneho cisla na zasobnik kalkulacky. Tisk toho cisla, nasobeni, deleni a prevod na integer.

Tisk vypadal ze automticky maze to cislo, tak fajn.

Nasobeni potrebuje v DE a HL adresy tech cisel a vysledek se ukladal do HL. Ok, taky zadny vetsi problem. Do DE vlozim adresu posledniho cisla na zasobniku a do HL dam adresu predchoziho. Cislo ze zasobniku smazu sam tim ze ulozim do promenne STKEND, ktera ukazuje na prvni volne misto v tom zasobniku kalkulacky, hodnotu DE.

Tak a ted deleni. To ma oproti nasobeni jednu nevyhodu. FORTH deli tak ze zadate "24 8 /" a vysledek je pak "3". ZX ROM chape ale parametry opacne, kdyz je na zasobniku "24 8" a do HL dam adresu na cislo "24" a do DE adresu na cislo "8" tak vysledek bude "0.3333 8". Kdyz registry prohodim tak na zasobniku bude "24 3". Ale ja chci videt "3 8" a osmicku umazat.

U "24 3" musim prvne prepsat "24" trojkou na "3 3" a pak snizit STKEND o 5 bajtu, coz je velikost jednoho floatu. A nebo pred volanim deleni prohodit "24 8" za "8 24" a pak s tim zachazet jako u nasobeni.

Fajn, fajn, fajn. No... ne tak uplne. Pri kontrolnim tisku se mi nesnizovala hodnota STKEND. Snazil jsem se zjistit o co jde, jestli nema rom jeste jinou promennou. Prohlizim ten kod pro deleni, atd. A nakonec zjistim ze chyba bude v te funkci co tiskne cislo. Proste jednou tisk snizuje STKEND a podruhe ne. Protoze kdyz jsem do tisku pridal odecet tak to vse fungovalo... Takze krokuji tu rutinu tisku a najednou koukam ze uklada hodnotu registru B. Co? Tu prece nikde nenastavuji...
Kód:
GEN_ENT_1   335E   LD A,B   Either transfer a single operation offset to BREG temporarily, or, when using the subroutine recursively, pass the parameter to BREG to be used as a counter.
Takze to vypda ze
Kód:
    call 0x2D2B         ; 3:17      print_zxrom_u16_only   call ZX ROM stack BC routine
    call 0x2DE3         ; 3:17      print_zxrom_u16_only   call ZX ROM print a floating-point number routine
funguje, ale jen proto ze prvni rutina 0x2D2B nastavuje nejake hodnoty spravne pro druhou rutinu. U ktere je ale nejsou uvedeny zadne vstupni dodatecne parametry. https://skoolkid.github.io/rom/asm/2DE3.html

Mimochodem ta rutina pro cteni textu bude o dost slozitejsi. Protoze tiskne navic uvozovky. Ktere muzete smazat a tim zpusobit chybu, zadruhe muzete psat
Kód:
"Tohle je vstupni" + " retezec."
a ta rutina to spoji. Stejne jako kdyz jste mozna taky kdysi psali v nejakem krouzku vypocetni techniky v programu na test zda umite zakladni matematicke operace tu matematickou operaci.
Kód:
Vypocitejte 50+150 = "50+150"
Spravne!


Neznate nejake lepsi informace nez v https://skoolkid.github.io/rom/maps/all.html. Protoze snazit se to louskat instrukci po instrukci jde fakt strasne pomalu.

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 07.03.2022, 12:38 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Docela dost dlouho me trvalo nez jsem prisel na to jak pomoci ZX ROM nacist do DE hodnotu STKEND-5 a do HL hodnotu STKEND-10.
Muj kod bez pouziti ROM byl
Kód:
ld HL,(STKEND)    ; 3:16
ld DE,-5          ; 3:10 HL = stkend - 00, DE = -5
add HL,DE         ; 1:11 HL = stkend - 05, DE = -5
ex DE,HL          ; 1:4  HL = -5         , DE = stkend - 5
add HL,DE         ; 1:11 HL = stkend - 10, DE = stkend - 5

V ROM jsem nasel jen https://skoolkid.github.io/rom/asm/35BF.html ktera nastavuje HL = STKEND-5 a DE na STKEND.
Kód:
STK_PNTRS   35BF   LD HL,($5C65)   Fetch the current value of STKEND.
            35C2   LD DE,$FFFB   Set DE to -5, two's complement.
            35C5   PUSH HL   Stack the value for STKEND.
            35C6   ADD HL,DE   Calculate STKEND-5.
            35C7   POP DE   DE now holds STKEND and HL holds STKEND-5.
            35C8   RET   
Vzhledem k tomu ze jsem potreboval snizit hodnotu STKEND o jedno cislo, teda 5 bajtu tak jsem na to sel pomoci dvojiho volani 0x35bf a mezitim snizeni STKEND.
Kód:
call 0x35bf       ; 3:17
ld (STKEND), HL   ; 3:16
call 0x35bf       ; 3:17

Jenze kdyz jsem si hral se swap tak STKEND nesnizuji, takze na to musim jit jinak. Hledal jsem v ROM vic a neuspesne. Poradne jsem se podival na tu ROM fci a krome toho CO to dela jsem si uvedomil JAK to dela. Doslo mi, ze kdyz kdyz rutinu zavolam jeste jednou o instrukci dal, takze preskocim prvni co nacita do HL hodnotu STKEND, tak to udela presne to co chci, zkopiruje HL do DE a snizi HL o 5.
Ale jak je ta rutina napsana neuveritelne neefektivne a hloupe! Myslel jsem si ze je ROM napsana docela dobre, ale tohle fakt bije do oci...
Kód:
            35C5   PUSH HL   Stack the value for STKEND.
            35C6   ADD HL,DE   Calculate STKEND-5.
            35C7   POP DE   DE now holds STKEND and HL holds STKEND-5.

oproti 2x kratsimu, 5x rychlejsimu a lepe citelnejsimu
Kód:
            35C5   EX DE,HL       
            35C6   ADD HL,DE   Calculate STKEND-5.

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 07.03.2022, 19:46 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Pri testovani jsem narazil na nekolik chyb, vcetne spatneho poradi vraceni ulozenych parametru na zasobniku pri volani funkci. Kdy jsem delal neustale swap. S tim bylo spojeno ze me VUBEC NEDOSLO, ze kdyz ulozim na zasobnik FORTHu 2 hodnoty a ty pak presunu na zasobnik kalkulacky tak prohodim zase poradi... Takze jsem opravoval rutinu deleni, ted nemusim swapovat. Hura...
Po kompilaci FORTH-->asm vypada vysledek zatim nejak takto:
Kód:
ORG 0x8000

;   ===  b e g i n  ===
    ld  (Stop+1), SP    ; 4:20      init   storing the original SP value when the "bye" word is used
    ld    L, 0x1A       ; 2:7       init   Upper screen
    call 0x1605         ; 3:17      init   Open channel
    ld   HL, 60000      ; 3:10      init   Init Return address stack
    exx                 ; 1:4       init


    ld   BC, 13         ; 3:10      push_zx48fpush(13)   ( -- )
    call _BC_ZX48FPUSH  ; 3:17      push_zx48fpush(13)

    ld   BC, 5          ; 3:10      push_zx48fpush(5)   ( -- )
    call _BC_ZX48FPUSH  ; 3:17      push_zx48fpush(5)

    call _ZX48FDIV      ; 3:17      zx48fdiv   ( -- )

    call _ZX48FDOT      ; 3:17      zx48fdot   ( -- )

Stop:                   ;           stop
    ld   SP, 0x0000     ; 3:10      stop   restoring the original SP value when the "bye" word is used
    ld   HL, 0x2758     ; 3:10      stop
    exx                 ; 1:4       stop
    ret                 ; 1:10      stop
;   =====  e n d  =====

_BC_ZX48FPUSH:
    push DE             ; 1:11      _bc_zx48fpush
    push HL             ; 1:11      _bc_zx48fpush
    call 0x2D2B         ; 3:17      _bc_zx48fpush   call ZX ROM stack BC routine
    pop  HL             ; 1:10      _bc_zx48fpush
    pop  DE             ; 1:10      _bc_zx48fpush
    ret                 ; 1:10      _bc_zx48fpush

_ZX48FDOT:
    push DE             ; 1:11      _zx48fdot
    push HL             ; 1:11      _zx48fdot
    call 0x35bf         ; 3:17      _zx48fdot   call ZX ROM stk-pntrs, DE= stkend, HL = DE-5
    push HL             ; 1:11      _zx48fdot
    call 0x2de3         ; 3:17      _zx48fdot   call ZX ROM print a floating-point number routine
    pop  HL             ; 1:10      _zx48fdot
    ld (0x5C65),HL      ; 3:16      _zx48fdot   save STKEND
    pop  HL             ; 1:10      _zx48fdot
    pop  DE             ; 1:10      _zx48fdot
    ret                 ; 1:10      _zx48fdot

_ZX48FDIV:
    push DE             ; 1:11      _zx48fdiv
    push HL             ; 1:11      _zx48fdiv
if 1
    rst 0x28            ; 1:11      Use the calculator
    db  0x05            ; 1:        calc-div
    db  0x38            ; 1:        calc-end    Pollutes: AF, BC', DE'(=DE)
else
    call 0x35bf         ; 3:17      _zx48fdiv   call ZX ROM stk-pntrs, DE= stkend, HL = DE-5
    ld (0x5C65),HL      ; 3:16      _zx48fdiv   save STKEND
    call 0x35c2         ; 3:17      _zx48fdiv   call ZX ROM            DE= HL    , HL = HL-5
    call 0x31af         ; 3:17      _zx48fdiv   call ZX ROM fdiv
endif
    pop  HL             ; 1:10      _zx48fdiv
    pop  DE             ; 1:10      _zx48fdiv
    ret                 ; 1:10      _zx48fdiv

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 08.03.2022, 23:45 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Existuje nejaky snadny zpusob jak vkladat do zdrojaku floating-point konstantu?

Umi to nejaky prekladac? Je to totiz hardwarove zavisle a ne kazdy pocitac co ma Z80 je ZX Spectrum.

Chci napriklad vlozit cisla
Kód:
NUM3:
ZX_READNUMBER(0.55443322E-32)
NUM2:
ZX_READNUMBER(12.345E4)
NUM:
ZX_READNUMBER(3E2)
a vysledek ma vypadat
Kód:
NUM3:
DB 0x15,0x66,0x4d,0x73,0xdf ; = 0.55443322E-32
NUM2:
DB 0x91,0x71,0x1d,0x00,0x00 ; = 12.345E4
NUM:
DB 0x89,0x16,0x00,0x00,0x00 ; = 3E2

Udelal jsem na to makro. Prvni problem je, ze M4 neumi nic jineho nez integer. A jeste pouze signed 32 bit. Sesmolil jsem neco, co uz umi nejake podmnoziny floating-point cisel. Muj slozity postup byl nacitat cislo znak po znaku jako integer s tim ze jsem si pamatoval pocet desetinych cisel za teckou. Ten pocet jsem odecetl od desitkoveho exponentu. Desitkovy exponent jsem zrusil tak, ze jsem pridaval nuly k nactenemu cislu. Az jsem mel pouze integer. Pak jsem vytvoril novy dvojkovy exponent 128+32. A cislo nasobil dvema az byl nejvyssi bit 32 bitoveho cisla jednickovy a exponent pri kazdem nasobeni snizil o jedna. To ale hned selze kdyz ten integer mam v retezci, ale je vic jak 32 bit. Atd. takze bych musel vytvaret fce co ctou retezce a delaji nad nimi matematicke operace.

Kdyz mi doslo ze na to jde mnohem snadneji!

M4 umi tisknout pres makro "format" pomoci C syntaxe. Hodite mu retezec, ktery obsahuje floating-point cislo a on ho vytiskne jako cislo. No a C ma parametr "%a" ktery tiskne ve formatu "-0x1.789abp+100". A z tohoto retezce uz je to mnohem snazsi. Mate krasne hotovou mantisu v hex formatu za teckou. Jedine co potrebujete je zpracovat to tak, aby to bylo 32 bit. Doplnit nuly, nebo oriznout. Udelat bitovy posun vpravo. Prvni bt nastavit podle znamenka. Minut je 1, plus je 0. A prvni bajt je cislo za "p" + 129.
Kód:
define({___},{})dnl
dnl
define({ZX_READCHAR},{dnl
___{}define({ZXTEMP_CHAR},substr(ZXTEMP_STRING,0,1)){}dnl
___{}define({ZXTEMP_STRING},substr(ZXTEMP_STRING,1)){}dnl
})dnl
dnl
dnl
define({ZX_READ_EXP},{ifelse(eval(ZXTEMP_CHAR>=0),{1},{dnl
___{}define({ZXTEMP_EXP},ZXTEMP_EXP{}ZXTEMP_CHAR){}dnl
___{}ZX_READCHAR{}dnl
___{}ZX_READ_EXP{}dnl
})}){}dnl
dnl
dnl
define({ZX_READ_MANT},{ifelse(eval({0x0}ZXTEMP_CHAR>=0),{1},{dnl
___{}define({ZXTEMP_MANTISSA},ZXTEMP_MANTISSA{}ZXTEMP_CHAR){}dnl
___{}ZX_READCHAR{}dnl
___{}ZX_READ_MANT{}dnl
})}){}dnl
dnl
dnl
dnl 12.345E7 --> 12345*10^(7-3) --> 12345*10^4 --> 123450000
dnl
dnl
define({ZX_READNUMBER},{dnl
___{}define({ZXTEMP_STRING},format({%a},$1)){}dnl
___{}ZX_READCHAR{}dnl 0 or -+
___{}define({ZXTEMP_SIGN},0){}dnl
___{}define({ZXTEMP_EXP},{}){}dnl
___{}define({ZXTEMP_MANTISSA},{0x}){}dnl
___{}ifelse(ZXTEMP_CHAR,{+},{ZX_READCHAR}){}dnl
___{}ifelse(ZXTEMP_CHAR,{-},{ZX_READCHAR{}define({ZXTEMP_SIGN},0x80)}){}dnl
___{}ZX_READCHAR{}dnl x
___{}ZX_READCHAR{}dnl 1
___{}ZX_READCHAR{}dnl .
___{}ifelse(ZXTEMP_CHAR,{.},{dnl
___{}___{}ZX_READCHAR{}dnl .
___{}___{}ZX_READ_MANT{}dnl
___{}})dnl
___{}ifelse(ZXTEMP_CHAR,{p},{dnl
___{}___{}ZX_READCHAR{}dnl
___{}___{}define({ZXTEMP_EXP},ZXTEMP_CHAR){}dnl
___{}___{}ZX_READCHAR{}dnl
___{}___{}ZX_READ_EXP{}dnl
___{}})dnl
___{}ifelse(substr(ZXTEMP_MANTISSA,2,1),{},define({ZXTEMP_MANTISSA},ZXTEMP_MANTISSA{0})){}dnl
___{}ifelse(substr(ZXTEMP_MANTISSA,3,1),{},define({ZXTEMP_MANTISSA},ZXTEMP_MANTISSA{0})){}dnl
___{}ifelse(substr(ZXTEMP_MANTISSA,4,1),{},define({ZXTEMP_MANTISSA},ZXTEMP_MANTISSA{0})){}dnl
___{}ifelse(substr(ZXTEMP_MANTISSA,5,1),{},define({ZXTEMP_MANTISSA},ZXTEMP_MANTISSA{0})){}dnl
___{}ifelse(substr(ZXTEMP_MANTISSA,6,1),{},define({ZXTEMP_MANTISSA},ZXTEMP_MANTISSA{0})){}dnl
___{}ifelse(substr(ZXTEMP_MANTISSA,7,1),{},define({ZXTEMP_MANTISSA},ZXTEMP_MANTISSA{0})){}dnl
___{}define({ZXTEMP_MANTISSA},substr(ZXTEMP_MANTISSA,0,10)){}dnl
___{}define({ZXTEMP_MANTISSA},format({0x%08x},eval((ZXTEMP_MANTISSA>>1) & 0x7FFFFFFF))){}dnl
___{}define({ZXTEMP_EXP},format({0x%02x},eval(ZXTEMP_EXP+129))){}dnl
DB ZXTEMP_EXP,format({0x%02x},eval(ZXTEMP_SIGN+((ZXTEMP_MANTISSA>>24) & 0x7F))),dnl
format({0x%02x},eval((ZXTEMP_MANTISSA>>16) & 0xFF)),dnl
format({0x%02x},eval((ZXTEMP_MANTISSA>>8) & 0xFF)),dnl
format({0x%02x},eval(ZXTEMP_MANTISSA & 0xFF)) ; = $1 = format({%a},$1)})
dnl

PS: Nahral jsme na github prvni verzi podpory ZX ROM floating point aritmetiky. Je to rozdeleno na 2 soubory. Protoze nema cenu si hrat pri pouziti ROM na rychlost, tak aspon aby to bylo co nejmensi jsou jednotliva slova vetsinou jen volani rutin, ktere jsou definovane v druhem souboru a lezi v kodu na konci.
https://github.com/DW0RKiN/M4_FORTH/blob/master/M4/zx48float.m4
https://github.com/DW0RKiN/M4_FORTH/blob/master/M4/zx48float_end.m4
Takze si to muzete sami vyzkouset i kdyz tam jeste neni vsechno, nektere komentare jako ktere registry jsou zasazene nedavaji smysl atd.

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 09.03.2022, 16:19 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Nalezena a opravena chyba v makru prevodu float na retezec znaku. Vkladalo to obcas nulu za "0x". Zkuste si s predchozim kodem vlozit napriklad cislo 20 jako 2E1. Vlozi to 16.25, protoze ta nula posune bity makra o 4 vpravo.
Kód:
define({___},{})dnl
dnl
dnl
define({ZX_READCHAR},{dnl
___{}define({ZXTEMP_CHAR},substr(ZXTEMP_STRING,0,1)){}dnl
___{}define({ZXTEMP_STRING},substr(ZXTEMP_STRING,1)){}dnl
})dnl
dnl
dnl
define({ZX_READ_MANT},{dnl
___{}define({ZX_READ_TEMP},ZXTEMP_CHAR){}dnl
___{}ifelse(ZX_READ_TEMP,{p},{define({ZX_READ_TEMP},{0})}){}dnl
___{}ifelse(len(ZXTEMP_MANTISSA),{10},{define({ZX_READ_TEMP},{})}){}dnl
___{}define({ZXTEMP_MANTISSA},ZXTEMP_MANTISSA{}ZX_READ_TEMP){}dnl
___{}ifelse(ZXTEMP_CHAR,{p},{dnl
___{}___{}ifelse(eval(len(ZXTEMP_MANTISSA)<10),{1},{ZX_READ_MANT})},
___{}{dnl
___{}___{}ZX_READCHAR{}dnl
___{}___{}ZX_READ_MANT}){}dnl
}){}dnl
dnl
dnl
define({ZX48FLOAT2ARRAY},{dnl
___{}define({ZXTEMP_STRING},format({%a},$1)){}dnl
___{}ZX_READCHAR{}dnl                               0 or -+
___{}define({ZXTEMP_SIGN},0){}dnl
___{}define({ZXTEMP_EXP},{}){}dnl
___{}define({ZXTEMP_MANTISSA},{0x}){}dnl
___{}ifelse(ZXTEMP_CHAR,{+},{ZX_READCHAR}){}dnl
___{}ifelse(ZXTEMP_CHAR,{-},{ZX_READCHAR{}define({ZXTEMP_SIGN},0x80)}){}dnl
___{}ZX_READCHAR{}dnl                               x
___{}ZX_READCHAR{}dnl                               1
___{}ifelse(ZXTEMP_CHAR,{1},{ZX_READCHAR}){}dnl     .
___{}ifelse(ZXTEMP_CHAR,{.},{ZX_READCHAR}){}dnl     ?
___{}ZX_READ_MANT{}dnl
___{}ifelse(ZXTEMP_CHAR,{p},{dnl
___{}___{}ZX_READCHAR{}dnl
___{}___{}define({ZXTEMP_EXP},ZXTEMP_STRING){}dnl
___{}})dnl
___{}define({ZXTEMP_MANTISSA},format({0x%08x},eval((ZXTEMP_MANTISSA>>1) & 0x7FFFFFFF))){}dnl
___{}define({ZXTEMP_EXP},format({0x%02x},eval(ZXTEMP_EXP+129))){}dnl
___{}ifelse(eval($1),{0},{define({ZXTEMP_EXP},{0x00})}){}dnl
DB ZXTEMP_EXP,format({0x%02x},eval(ZXTEMP_SIGN+((ZXTEMP_MANTISSA>>24) & 0x7F))),dnl
format({0x%02x},eval((ZXTEMP_MANTISSA>>16) & 0xFF)),dnl
format({0x%02x},eval((ZXTEMP_MANTISSA>>8) & 0xFF)),dnl
format({0x%02x},eval(ZXTEMP_MANTISSA & 0xFF)) ; = $1 = format({%a},$1)}){}dnl

Edit: Pridana podpora pro specialni hodnotu jako je nula! :D
Protoze nula nejde v normalizavanem tvaru napsat a vypada jako "0x0p+0" a ne jako jednicka "1.0p+0" takze to delalo paseku.

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Naposledy upravil _dworkin dne 09.03.2022, 17:38, celkově upraveno 1

Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 09.03.2022, 16:51 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Nevite nekdo jak funguje porovnani? Kdyz vlozim kod pro F<
Kód:
    rst 0x28            ; 1:11      Use the calculator
    db  0x0D            ; 1:        calc-less
    db  0x38            ; 1:        calc-end    Pollutes: AF, BC, BC', DE'(=DE)
Tak to nedela co ma dokud pred volanim nenastavim registr B na 0x0D. Pak to porovna dve cisla a smaze je a vlozi cislo 0 nebo 1.
Pokud ale zmenim B na 0x0E co ma byt pro "==" a uz nezmenim hodnotu db 0x0D tak to stejne provede porovnani na "rovna se".
Vsechno to skace na https://skoolkid.github.io/rom/asm/353B.html vcetne porovnani retezcu.

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 09.03.2022, 19:04 
Offline
Óm Nejvyšší

Registrován: 22.05.2013, 21:14
Příspěvky: 3642
Bydliště: Bratislava
Has thanked: 371 times
Been thanked: 788 times
Pokial chces vykonat operaciu ktorej kod je v registri B, potom namiesto 0x0D treba pouzit kod 0x3B.
Kód:
    rst 0x28            ; 1:11      Use the calculator
    db  0x3B            ; 1:        operace z >BREG<  ;fp-calc-2
    db  0x38            ; 1:        calc-end
V romke sa to pouziva na adrese #2755 kde je cast rutinky pre vyhodnocovanie vyrazov, ked su na zasobniku uz nacitane oba operandy a podla kodu operatora sa z tabulky nacita kod jeho zodpovedajucej operacie pre kalkulacku.


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 09.03.2022, 20:59 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Podivam se na to jestli to neni rychlejsi (jestli v ROMce to nedela kratsim kodem). Protoze velikost kodu bude stejna. Jinak jak jsem rekl me to prekvapive FUNGUJE i kdyz tam mam tu hodnotu pro "<" teda 0x0D.
Příloha:
zxfloat.png
zxfloat.png [ 3.68 KiB | Zobrazeno 2945 krát ]

Kód:
; vvv
include(`../M4/FIRST.M4')dnl
; ^^^
ORG 0x8000
INIT(60000)

ZX48FADDR CR

PUSH(NUM)  ZX48FFETCH
PUSH(NUM2) ZX48FFETCH
SCALL(Test)
ZX48FSWAP
SCALL(Test)
ZX48FDROP
ZX48FDUP
SCALL(Test)
ZX48FDROP
ZX48FDROP

ZX48FADDR
STOP


SCOLON(Test)
    ZX48FOVER ZX48FDOT ZX48FDUP ZX48FDOT ZX48FOVER ZX48FOVER
    ZX48FLE
    PRINT_Z({"f<= "})
    ZX48FDOT CR

    ZX48FOVER ZX48FDOT ZX48FDUP ZX48FDOT ZX48FOVER ZX48FOVER
    ZX48FGE
    PRINT_Z({"f>= "})
    ZX48FDOT CR

    ZX48FOVER ZX48FDOT ZX48FDUP ZX48FDOT ZX48FOVER ZX48FOVER
    ZX48FNE
    PRINT_Z({"f<> "})
    ZX48FDOT CR

    ZX48FOVER ZX48FDOT ZX48FDUP ZX48FDOT ZX48FOVER ZX48FOVER
    ZX48FGT
    PRINT_Z({"f> "})
    ZX48FDOT CR

    ZX48FOVER ZX48FDOT ZX48FDUP ZX48FDOT ZX48FOVER ZX48FOVER
    ZX48FLT
    PRINT_Z({"f< "})
    ZX48FDOT CR

    ZX48FOVER ZX48FDOT ZX48FDUP ZX48FDOT ZX48FOVER ZX48FOVER
    ZX48FEQ
    PRINT_Z({"f= "})
    ZX48FDOT CR   
SSEMICOLON

db "Tequila",0

NUM:
ZX48FLOAT2ARRAY(40.00001)
NUM2:
ZX48FLOAT2ARRAY(40)

Legenda Forth slov:
...DOT tiskne a maze cislo
...DUP kopiruje float
...OVER kopiruje nasledujici float
...SWAP prohodi floaty
...FETCH cte float z adresy
...LT <
...GT >
...EQ =
...LE <=
... GE >=
...NE <>
FADDR moje nestandardni rozsireni co tiskne aktualni hodnotu adresy float zasobniku (STKEND).


Přílohy:
zx_float.asm.zip [2.31 KiB]
99 krát

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH
Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 09.03.2022, 21:38 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Tak jsem se snazil krokovat kudy bezi jedno volani:
RST 0x28
JP 0x335B THE 'CALCULATE' SUBROUTINE
CALL 0x35BF THE 'STK-PNTRS' SUBROUTINE
RET 0x353B THE 'COMPARISON' OPERATIONS (offsets +09 to +0E, +11 to +16)
CALL 300F THE 'SUBTRACTION' OPERATION (offset +03)
CALL 346E THE 'UNARY MINUS' OPERATION (offset +1B)
CALL 34E9 THE 'TEST-ZERO'
CALL 3296 ex DE,HL + 3297 = THE 'RE-STACK' SUBROUTINE (offset +3D)
CALL 2D7F THE 'INT-FETCH' SUBROUTINE
CALL 2F9B THE 'PREPARE TO ADD' SUBROUTINE
CALL 2F9B THE 'PREPARE TO ADD' SUBROUTINE
CALL 2FBA THE 'FETCH TWO NUMBERS' SUBROUTINE
CALL 2FDD THE 'SHIFT ADDEND' SUBROUTINE
CALL 34F9 THE 'GREATER THAN ZERO' OPERATION (offset +37)
CALL 34E9 THE 'TEST-ZERO' SUBROUTINE
...tady to vzdavam. :D Proste zavolam profiler, i kdyz tam budu muset resit co s prerusenim kdyz beham v ROMce.

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
Zobrazit příspěvky za předchozí:  Seřadit podle  
Odeslat nové téma Odpovědět na téma  [ Příspěvků: 585 ]  Přejít na stránku Předchozí  1 ... 8, 9, 10, 11, 12, 13, 14 ... 39  Další

Všechny časy jsou v UTC + 1 hodina [ Letní čas ]


Kdo je online

Uživatelé procházející toto fórum: Žádní registrovaní uživatelé a 4 návštevníků


Nemůžete zakládat nová témata v tomto fóru
Nemůžete odpovídat v tomto fóru
Nemůžete upravovat své příspěvky v tomto fóru
Nemůžete mazat své příspěvky v tomto fóru
Nemůžete přikládat soubory v tomto fóru

Hledat:
Přejít na:  
Založeno na phpBB® Forum Software © phpBB Group
Český překlad – phpBB.cz