Asi bych mel brzdit, kdyz vsechen volny cas programuji. Uz je zase rano a za sebou mam dalsi probdenou noc. Je to skvela vec na zabiti casu, kdyz jen cekate na konec, ale zacina me to zmahat.
Nechce se me moc rozepisovat, ale zmen je prilis mnoho. Musel jsem nekolikrat znovu prepisovat kod, protoze se ukazalo, ze je to vhodnejsi resit jinak, s jinymi parametry, jinym poradim parametru. Ze je to prilis komplikovane a musim to rozdelit na vic podfunkci atd.
Takze je hotovo vcetne automatickeho prevodu z forthu do M4 FORTHu:
CREATE(jmeno_navesti)
PUSH_ALLOT(pocet_bajtu)
Tohle slovo musi mit parametr, protoze musim vedet jaka je skutecna hodnota kolik chcete alokovat. Pokud to bude ve smycce nebo ve funkci tak to selze. V podstate to udela "DS pocet_bajtu".
Co je dulezite, uz to umi i dealokaci! Mel jsem asi v 6 rano v nedeli, ze by to mohlo jit kdyz budu pouzivat v CREATE zasobnikovy typ definice. Takze pomoci undefine se dostanu zpet na predchozi jmeno_navesti. K tomu je jeste existuje dalsi makro ktere si pamatuje kolik bajtu pod danym slovem bylo.
Pal me doslo, ze mam ale problem kdyz zacnu znovu alokovat tak jak to zapsat...
Po rade neuspechu jsem mel napad vyzkouset co dela ve zdrojaku "ORG $-40". A dela presne co chci, minimalne pokud tam zadam nove ukazatele tak budou mit spravnou adresu.
HERE
Tohle slovo hodi na zasobnik prvni volnou adresu. V podstate ulozim do HL,posledni_jmeno_navesti+kolik_tam_je_ted_bajtu
VARIABLE(jmeno_promenne)
PUSH_VARIABLE(hodnota,jmeno_promenne)
Udelal jsem zmenu v poradi parametru, takhle je to jak to ma forth, musel jsem prepsat a zkontrolovat hodne kodu
DVARIABLE(jmeno_promenne)
PUSHDOT_DVARIABLE(32bitova_hodnota,jmeno_promenne)
Obdobne s VALUE
A automaticky prevod uz sam pozna podle jmena zda je to ukazatel a nebo chceme cist z dane adresy. Takze to zmeni na PUSH((jmeno_promenne)). U VALUE() a TO() to naopak nezazavorkuje. Takze veskere optimalizace jsou funkcni.
TO(jmeno_promenne)
Samo to uz pozna zda je to 16 bitova nebo 32 bitova hodnota.
PUSH_TO(jmeno_promenne)
PUSHDOT_TO(jmeno_promenne)
COMMA
PUSH_COMMA()
PUSHS_COMMA()
Tohle forth slovo co vypada jako carka s mezerama okolo dela to ze nacte z datoveho zasobniku hodnotu a ulozi ji na prvni volne misto v pameti.
Takze program z rossetacode
Kód:
include random.fs
: shuffle ( deck size -- )
2 swap do
dup i random cells +
over @ over @ swap
rot ! over !
cell+
-1 +loop drop ;
: .array 0 do dup @ . cell+ loop drop ;
create deck 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ,
deck 10 2dup shuffle .array
Vypada nejak takto
Kód:
include(`../M4/FIRST.M4')dnl
ORG 0x8000
INIT(60000)
CREATE(_deck) PUSHS_COMMA(1,2,3,4,5,6,7,8,9,10)
PUSH2(_deck,10) _2DUP CALL(_shuffle) CALL(_dot_array)
STOP
COLON(_shuffle)
;#( deck size -- )
PUSH_SWAP(2) DO
DUP I RANDOM _2MUL ADD
OVER FETCH OVER FETCH SWAP
ROT STORE OVER STORE
_2ADD
PUSH_ADDLOOP(-1) DROP SEMICOLON
COLON(_dot_array) PUSH(0) DO DUP_FETCH SPACE_DOT _2ADD LOOP DROP CR SEMICOLON
Uz jsem psal o tom, ze to nemuzu zapsat jen jako
Kód:
_deck: dw 1,2,3,4,5,6,7,8,9,10
Protoze pri druhem spusteni uz _deck bude obsahovat zamichane hodnoty. Takze se to musi znovu prepsat.
Po nejake dobe jsem rezignoval to udelat lepe, protoze by to nebylo podle standardu a psal neco jako
Kód:
ld HL, 1
ld (_deck),HL
ld HL, 2
ld (_deck+2),HL
...
A pak to zacalo... optimalizace... A ze jich tam je! Protoze, zname predchozi hodnotu a navic je to v HL.
To same nedelni rano, touhle ranni dobou (5:51 v Chesteru) pred usnutim me napadlo jak jsem blby. A kdysi optimalizoval slovo PUSH(5) a PUSH(10) na PUSH2(5,10) protoze me vypadne 2x ex HL, DE. A u tri hodnot to vzdal protoze to prece nejde.
Kód:
../check_word.sh 'PUSH(5) PUSH(10) PUSH2(5,10)'
push DE ; 1:11 push(5)
ex DE, HL ; 1:4 push(5)
ld HL, 5 ; 3:10 push(5)
push DE ; 1:11 push(10)
ex DE, HL ; 1:4 push(10)
ld HL, 10 ; 3:10 push(10)
push DE ; 1:11 push2(5,10)
push HL ; 1:11 push2(5,10)
ld DE, 5 ; 3:10 push2(5,10)
ld HL, 0x000A ; 3:10 push2(5,10)
;[18:92]
Ale proc by to neslo, kdyz vlastne prvne ulozim DE a HL na zasobnik, protoze budou oba prepsany a pak bud do HL nebo DE dam prvni hodnotu a taky ji hodim na zasobnik a pak druhou dam do DE a posledni do HL. Hotovo.
No... vlastne ne. Tohle je jeste vetsi slozitost nez v PUSHS_COMMA.
Mam nejake 3 hodnoty ktere znam, a dve budou lezet ve stejnem registru. Tech kombinaci je fakt hodne. Psal jsem to asi 3 dny. Vytvarel funkce, ty nadale delil atd.
Az dospel k zakladnim 2 pomocnym funkcim.
Prvni vypada takto:
__LD_REG16_16BIT({HL},co_tam_chci,{DE},0x1234,{HL},0x5678)
Prvni parametr je jmeno registru pro ktery chci generovat kod.
Druhy parametr je co tam chci mit za hodnotu
Pak nasleduji nepovinne dvojice parametru s jmenem registru a co tam lezi. Je to delane az pro 8 parametru. Pocita se jen s HL,DE,BC.
Pak me doslo, ze to nebude stacit. Protoze kdyz napriklad mam
Kód:
../check_word.sh "PUSH3(0x55FF,0x56FF,0x5600)"
push DE ; 1:11 0x55FF 0x56FF 0x5600 push3(0x55FF,0x56FF,0x5600)
push HL ; 1:11 0x55FF 0x56FF 0x5600 push3(0x55FF,0x56FF,0x5600)
ld HL, 0x55FF ; 3:10 0x55FF 0x56FF 0x5600 push3(0x55FF,0x56FF,0x5600)
push HL ; 1:11 0x55FF 0x56FF 0x5600 push3(0x55FF,0x56FF,0x5600)
ld E, L ; 1:4 0x55FF 0x56FF 0x5600 push3(0x55FF,0x56FF,0x5600) E = L = 0xFF
inc HL ; 1:6 0x55FF 0x56FF 0x5600 push3(0x55FF,0x56FF,0x5600)
ld D, H ; 1:4 0x55FF 0x56FF 0x5600 push3(0x55FF,0x56FF,0x5600) D = H = 0x56
;[ 9:57]
Tak prvni hodnotu zde je nejlepsi vlozit do HL a pak pres inc HL ziskame treti hodnotu. Ale jak do DE vlozime 0x56FF, kdyz nizsi bajt ma L pred zmenou a vyssi bajt ma H po zmene? To potrebuji rozdelit...
__LD_REG16_16BIT_BEFORE_AFTER({DE},co_tam_chci,{HL},0x1234,{HL},0x5678)
Napevno 6 parametru. Kdy se do DE snazi vecpat hodnoty z 4 parametru nebo 6 parametru a vystup je rozdelen na 2 promenne.
Pak me doslo, ze ani to nebude stacit. Ale to uz jsem ignoroval. Muze se stat, ze chceme misto
ld HL, 0x20FE
...
ld HL, 0x2100
a o bajt kratsi je to pres
ld HL, 0x20FE
...
inc L
inc HL
Takze mame hned 0x20,0x21,0xFF,0x00. Ale ten 0xFF ztratim. Pokud bych chtel mit napriklad v DE, 0xFFFF mam smulu.
Je toho mnohem, mnohem vic. Pokud napriklad nacitame do HL 0x5353 a mame HL 0x2052 tak muzeme tady vyuzit toho ze jeden z registru H nebo L udelame prvni a uz je to tak vstup pro druhy registr.
Takze ve vysledku, musim udelat vsechny kombinace pro 8 nebo 16 bit a najit tu nejlepsi.
Kód:
push DE ; 1:11 0x2222 0x3333 0x5555 push3(0x2222,0x3333,0x5555)
push HL ; 1:11 0x2222 0x3333 0x5555 push3(0x2222,0x3333,0x5555)
ld HL, 0x2222 ; 3:10 0x2222 0x3333 0x5555 push3(0x2222,0x3333,0x5555)
push HL ; 1:11 0x2222 0x3333 0x5555 push3(0x2222,0x3333,0x5555)
ld DE, 0x3333 ; 3:10 0x2222 0x3333 0x5555 push3(0x2222,0x3333,0x5555)
add HL, DE ; 1:11 0x2222 0x3333 0x5555 push3(0x2222,0x3333,0x5555) 0x5555 = 0x2222+0x3333
;[10:64]
Zpetne jsem pak upravil PUSH2 s vyuzitom novych maker a i PUSHS_COMMA.
PUSHS_COMMA me vadilo, ze kdyz zadate 1,2,3,4,5,6,7,8,9,10 tak to jde napsat lepe. Tak jsem udelal analyzu vstupu a u +1,-1,+256,-256,+0 rad jsem provedl smycku.
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh "CREATE(_deck) PUSHS_COMMA(1,2,3,4,5,6,7,8,9,10)"
push HL ; 1:11 1 , 2 , ... 10 , +1
ld HL, _deck ; 3:10 1 , 2 , ... 10 ,
ld BC, 0x0A01 ; 3:10 1 , 2 , ... 10 ,
ld (HL),C ; 1:7 1 , 2 , ... 10 ,
inc HL ; 1:6 1 , 2 , ... 10 ,
ld (HL),0x00 ; 2:10 1 , 2 , ... 10 ,
inc HL ; 1:6 1 , 2 , ... 10 ,
inc C ; 1:4 1 , 2 , ... 10 ,
djnz $-6 ; 2:8/13 1 , 2 , ... 10 ,
pop HL ; 1:10 1 , 2 , ... 10 ,
;[16:496] 1 , 2 , ... 10 ,
VARIABLE_SECTION:
_deck:
dw 1
dw 2
dw 3
dw 4
dw 5
dw 6
dw 7
dw 8
dw 9
dw 10
;[16:82]
Stale to jeste neni ono, protoze kdyz to nenajde radu a spoleha se to na pouhe optimalizace z predchoziho cisla, tak by bylo vhodne to prvne vzestupne seradit, protoze s ld (adresa+x),HL mame volnost co dame za x. To ale vyzaduje seradit n parametru v makru!
Myslim ze to jde... zkousel jsem predtim neco hackovat a nejde to, ale jde udelat z parametru retezec oddeleny treba mezerama. A kazde sude cislo bude index puvodniho parametru. A takovy retezec jde pak seradit. I bez podpory smycek. Pres zasobniky.