Busy píše:
_dworkin píše:
Kód:
jr nz, $+18 ; 2:7/12 2dup 0x45352515 D<> if
Kam skoci to $+18 ? 18 je uz dost velka hodnota, uz to zacina byt neintuitivne a nachylne na chyby (clovek medzi tym nieco doplni a zabudne zmenit tu 18-ku). Podla mna, preto pouzivame asembler, aby sme taketo skoky nemuseli prepocitavat rucne. Navrhujem pozivat labely...
(vnutri makra samozrejme lokalne labely, ktore dnes uz vie kazdy poriadny asembler)
Tohle si nastesti pocita samo makro a skace samozrejme VZDY JEN UVNITR SEBE, a hranice slova je v kodu krasne videt podle zmeny komentaru. Musely by za sebou byt 2 stejna slova, aby to mohlo mast, a to se u techle slov nestava a i tak je tam ten uvodni radek se sumou taktu a bajtu.
Pokud si to budu rucne editovat, tak uz to chce mozna znat zakladni principy jak je to delane. Asi bych mohl pridat aspon komentar do popisu, kdyz uz ne label.
Ja ty lokalni labely v pasmu proste neumim..., proto pouzivam tenhle zapis. A snazim se udelat ten kod prelozitelny vsude. Predpokladam ze by to vyzadovalo neustele pridavani 2 radku, ktere by slova obalovala.
Jinak to makro si to pocita presne na konec sebe, ale da se to upravit pres parametry, protoze...
...to makro dela jen tu zakladni, shodnou cast a pak ji obalujeme dodatecnym kodem. Hezky je to asi videt na prikladu double EQ a double NE.
DEQ volam vnitrne takto ( jinak "dnl" je znacka pro komentar do konce radku, nic z toho nebude ve vysledku, zadne mezery, ani ten konec radku, zadne rozbalovnai maker atd.)
Kód:
dnl Prvne nadefinuji makra, ktera pouzije makro generujici kod jako globalni promenne.
dnl Neni to uplne ciste, ale prehlednejsi, puvodne to byly primo parametry.
dnl Mimochodem to nesmi obsahovat zadne carky, jinak mam problem a musim je pravdepodobne opakovane obalovat do {}.
dnl Tu carku co vidite je zrusena makrem format.
dnl
define({_TMP_INFO},{2dup $1 D= if})dnl
define({_TMP_STACK_INFO},{ _TMP_INFO ( d1 -- d1 ) format({0x%08X},eval($1)) == DEHL})dnl
dnl
dnl Pak volam to makro generujici kod
dnl 1 parametr $1 se doplni na cislo na ktere to porovnavam
dnl 2 parametr je pocet dodatecnych bajtu co ma pricist k tomu prvnimu radku kde je sumace
dnl 3 parametr je pocet dodatecnych taktu co ma pricist k tomu prvnimu radku kde je sumace
dnl 4 parametr je pocet dodatecnych bajtu co ma pricist k relativnim skokum
dnl 5 parametr je pocet dodatecnych taktu co ma pricist k relativnim skokum u tomu prvnimu radku kde je sumace, zadavam zaporne cislo
dnl
____DEQ_MAKE_BEST_CODE($1,3,10,0,0){}dnl
dnl Ted uz jen zadam makro, ktere se nahradi za vygenerovany kod
_TMP_BEST_CODE
dnl Ted to obalim zespoda
; -----------------------
jp nz, else{}IF_COUNT ; 3:10 _TMP_INFO
Bez komentaru to vypada takto
Kód:
define({_TMP_INFO},{2dup $1 D= if})dnl
define({_TMP_STACK_INFO},{ _TMP_INFO ( d1 -- d1 ) format({0x%08X},eval($1)) == DEHL})dnl
____DEQ_MAKE_BEST_CODE($1,3,10,0,0){}dnl
_TMP_BEST_CODE
; -----------------------
jp nz, else{}IF_COUNT ; 3:10 _TMP_INFO
A vysledek vypada takto
Kód:
;[21:75/33,51,69,75] 2dup 0x45352515 D= if ( d1 -- d1 ) 0x45352515 == DEHL
ld A, 0x15 ; 2:7 2dup 0x45352515 D= if
cp L ; 1:4 2dup 0x45352515 D= if x[1] = 0x15
jr nz, $+15 ; 2:7/12 2dup 0x45352515 D= if
ld A, 0x25 ; 2:7 2dup 0x45352515 D= if
cp H ; 1:4 2dup 0x45352515 D= if x[2] = 0x25
jr nz, $+10 ; 2:7/12 2dup 0x45352515 D= if
ld A, 0x35 ; 2:7 2dup 0x45352515 D= if
cp E ; 1:4 2dup 0x45352515 D= if x[3] = 0x35
jr nz, $+5 ; 2:7/12 2dup 0x45352515 D= if
ld A, 0x45 ; 2:7 2dup 0x45352515 D= if
xor D ; 1:4 2dup 0x45352515 D= if x[4] = 0x45
; -----------------------
jp nz, else101 ; 3:10 2dup 0x45352515 D= if
;[21:75]
Tohle by jeste stalo za komentar, protoze u tehle varianty chci nahradit relativni skoky primo skoky absolutnimy na "else101", aspon ten prvni skok, nebo to nastavit podle prepinace. Kod bude delsi a u TRUE varianty vzdy pomalejsi, ale u skoku rychlejsi. Uplne nejlepsi by bylo relativne skakat primo na "else101", a kdyz by to bylo mimo rozsah tak na to JP jako meziskok. Ale to je spis vlhky sen, o tom jsem nikdy neslysel, ze by to nejaky prekladac umel. Mit 2 parametry pro relativni skok.
DNE volam pres s bajty +3 a takty -10, protoze chci aby to skocilo az za JP, nepotrebuji zadny meziskok, vim ze skaci kousek dolu.
Kód:
define({_TMP_INFO},{2dup $1 D<> if})dnl
define({_TMP_STACK_INFO},{ _TMP_INFO ( d1 -- d1 ) format({0x%08X},eval($1)) <> DEHL})dnl
____DEQ_MAKE_BEST_CODE($1,3,10,3,-10){}dnl
_TMP_BEST_CODE
; .......................
jp z, else{}IF_COUNT ; 3:10 _TMP_INFO
; -----------------------
Vysledek vypada takto:
Kód:
;[21:75/23,41,59,75] 2dup 0x45352515 D<> if ( d1 -- d1 ) 0x45352515 <> DEHL
ld A, 0x15 ; 2:7 2dup 0x45352515 D<> if
cp L ; 1:4 2dup 0x45352515 D<> if x[1] = 0x15
jr nz, $+18 ; 2:7/12 2dup 0x45352515 D<> if
ld A, 0x25 ; 2:7 2dup 0x45352515 D<> if
cp H ; 1:4 2dup 0x45352515 D<> if x[2] = 0x25
jr nz, $+13 ; 2:7/12 2dup 0x45352515 D<> if
ld A, 0x35 ; 2:7 2dup 0x45352515 D<> if
cp E ; 1:4 2dup 0x45352515 D<> if x[3] = 0x35
jr nz, $+8 ; 2:7/12 2dup 0x45352515 D<> if
ld A, 0x45 ; 2:7 2dup 0x45352515 D<> if
xor D ; 1:4 2dup 0x45352515 D<> if x[4] = 0x45
; .......................
jp z, else101 ; 3:10 2dup 0x45352515 D<> if
; -----------------------
;[21:75]
Jeste jedna informace k tomu generovanemu kodu je, ze pokud je nulovy priznak nastaven, tak vzdy je zaroven akumulator nulovy. Nikdy neni posledni instrukce CP, jen kdyz neni vysledek nula.
A v realite to dnes vypada ve skutecnosti takto pro slovo _2DUP_PUSHDOT_DEQ_IF.
Kód:
dnl
dnl 2dup D. D= if
dnl ( d -- d )
define({_2DUP_PUSHDOT_DEQ_IF},{dnl
__{}define({IF_COUNT}, incr(IF_COUNT))dnl
__{}pushdef({ELSE_STACK}, IF_COUNT)dnl
__{}pushdef({THEN_STACK}, IF_COUNT)dnl
__{}define({_TMP_INFO},{2dup $1 D= if})dnl
__{}define({_TMP_STACK_INFO},{ _TMP_INFO ( d1 -- d1 ) format({0x%08X},eval($1)) == DEHL})dnl
__{}ifelse($1,{},{
__{}__{} .error {$0}(): Missing parameter!},
__{}$#,{1},{dnl
__{}__{}ifelse(index({$1},{(}),{0},{
__{}__{}__{} ;[19:108] _TMP_INFO ( d1 -- d1 ) (addr) == DEHL
__{}__{}__{} push HL ; 1:11 _TMP_INFO
__{}__{}__{} xor A ; 1:4 _TMP_INFO
__{}__{}__{} ld BC, format({%-11s},$1); 4:20 _TMP_INFO lo16($1)
__{}__{}__{} sbc HL, BC ; 2:15 _TMP_INFO lo16(d1)-BC
__{}__{}__{} jp nz, $+7 ; 2:7/12 _TMP_INFO
__{}__{}__{} ld HL,format({%-12s},($1+2)); 3:16 _TMP_INFO hi16($1)
__{}__{}__{} sbc HL, DE ; 2:15 _TMP_INFO HL-hi16(d1)
__{}__{}__{} pop HL ; 1:10 _TMP_INFO
__{}__{}__{} jp nz, else{}IF_COUNT ; 3:10 _TMP_INFO},
__{}__{}eval($1),{},{
__{}__{}__{} .error {$0}($@): M4 does not know $1 parameter value!},
__{}__{}{dnl
__{}__{}__{}____DEQ_MAKE_BEST_CODE($1,3,10,0,0){}dnl
__{}__{}__{}ifelse(eval((_TMP_BEST_B<=18) || ifelse(_TYP_DOUBLE,{small},{0},{1})),{1},{
__{}__{}__{}__{}_TMP_BEST_CODE
__{}__{}__{}__{} jp nz, else{}IF_COUNT ; 3:10 _TMP_INFO},
__{}__{}__{}{
__{}__{}__{}__{} ;[18:92/72,92] _TMP_INFO ( d1 -- d1 ) format({0x%08X},eval($1)) --> default version
__{}__{}__{}__{} push HL ; 1:11 _TMP_INFO
__{}__{}__{}__{} xor A ; 1:4 _TMP_INFO
__{}__{}__{}__{} ld BC, format({0x%04X},eval(($1) & 0xFFFF)) ; 3:10 _TMP_INFO lo16
__{}__{}__{}__{} sbc HL, BC ; 2:15 _TMP_INFO lo16(d1)-BC
__{}__{}__{}__{} jr nz, $+7 ; 2:7/12 _TMP_INFO
__{}__{}__{}__{} ld HL, format({0x%04X},eval((($1)>>16) & 0xFFFF)) ; 3:10 _TMP_INFO hi16
__{}__{}__{}__{} sbc HL, DE ; 2:15 _TMP_INFO HL-hi16(d1)
__{}__{}__{}__{} pop HL ; 1:10 _TMP_INFO
__{}__{}__{}__{} jp nz, else{}IF_COUNT ; 3:10 _TMP_INFO})})},
__{}{
__{}__{} .error {$0}($@): $# parameters found in macro!})}){}dnl
dnl
Nastesti tohle nikdo nevidi a tohle neni jeste hrozne. .)
Tady bych vypichl tu cast kde M4 nema zadne vetveni jen strukturu ifelse.
Ktera je definovana tak ze se porovnavaji na shodnost 2 retezce a pokud jsou shodne tak se provede prvni vetev, jinak druha.
Pred tu druhou vetev lze zase vlozit znovu 3 retezce, kdy prvni 2 jsou zase na porovnani a posledni jako prvni vetev. Je to oddelene carkami.
Kód:
ifelse(porovnavany_retezec_1,porovnavany_retezec_2,pokud jsou shodne tohle se zobrazi/vykona,
pokud nejsou tohle se zobrazi)
ifelse(porovnavany_retezec_1,porovnavany_retezec_2,pokud jsou shodne tohle se zobrazi/vykona,
porovnavany_retezec_3,porovnavany_retezec_4,pokud jsou shodne tohle se zobrazi/vykona,
porovnavany_retezec_4,porovnavany_retezec_5,pokud jsou shodne tohle se zobrazi/vykona,
pokud nejsou tohle se zobrazi)
Bezne pouziti je s pomoci makra eval, ktere se snazi text interpetovat jako cisla a vraci vysledek, napriklad 1 kdyz je to pouzito na porovnani a vysledek je TRUE, nebo 0 kdyz FALSE. Obaluji $1 do zavorek protoze vstupem je retezec, klidne "5+10", a pro korektni vysledky je potreba to prvne secist.
Kód:
ifelse(eval(($1) & 0xFFFF),{0},{2 spodni bajty jsou nulove},
eval(($1) & 0xFF),{0},{Spodni bajt je nulovy},
eval((($1)>>8) & 0xFF),{0},{Druhy bajt je nulovy},
{Ani jeden ze dvou spodnich bajtu neni nulovy}){}dnl
Tak a ten vtip je v tom ze eval neumi porovnat retezce, to umi jen ifelse a ja potrebuji zjistit zda makro _TYP_DOUBLE neni "small". No tak tam vlozim navic dalsi ifelse, ktere to zjisti a vraci 1 nebo 0 podle vysledku.
Kód:
ifelse(_TYP_DOUBLE,{small},{0},{1})
To uz jsem fakt uplne mimo tema...
PS: __ je makro ktere nedela nic define({__},{}), jen mi umoznuje udelat odsazeni jinak nez pomoci {}.