Dodelal jsem ty testy klaves.
Mel jsem k tomu jeste dve vyhrady. Jedna byla, co se stane kdyz nekdo bude chtit cist treba dvojici klaves najednou a mel jsem pocit, ze to nebude spravne fungovat.
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(__TESTKEY_P) TESTKEY'
push DE ; 1:11 0xDF01 testkey ( -- bool ) true == press "P"
ex DE, HL ; 1:4 0xDF01 testkey
ld A, 0xDF ; 2:7 0xDF01 testkey
in A,(0xFE) ; 2:11 0xDF01 testkey
rrca ; 1:4 0xDF01 testkey
ccf ; 1:4 0xDF01 testkey
sbc HL, HL ; 2:15 0xDF01 testkey
; seconds: 0 ;[10:56]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(__TESTKEY_O) TESTKEY'
push DE ; 1:11 0xDF02 testkey ( -- bool ) true == press "O"
ex DE, HL ; 1:4 0xDF02 testkey
ld A, 0xDF ; 2:7 0xDF02 testkey
in A,(0xFE) ; 2:11 0xDF02 testkey
rrca ; 1:4 0xDF02 testkey
rrca ; 1:4 0xDF02 testkey
ccf ; 1:4 0xDF02 testkey
sbc HL, HL ; 2:15 0xDF02 testkey
; seconds: 1 ;[11:60]
O a P dohromady:
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(0xFE03) TESTKEY'
push DE ; 1:11 0xFE03 testkey ( -- bool ) true == press "???"
ex DE, HL ; 1:4 0xFE03 testkey
ld A, 0xFE ; 2:7 0xFE03 testkey
in A,(0xFE) ; 2:11 0xFE03 testkey
and 0x03 ; 2:7 0xFE03 testkey
sub 0x01 ; 2:7 0xFE03 testkey
sbc HL, HL ; 2:15 0xFE03 testkey
; seconds: 0 ;[12:62]
Ale diky tomu ze bitove je TRUE nula to funguje pekne, po "and maska" je nula jen v pripade, ze vsechny klavesy jsou stiskle. Kdyby to bylo naopak tak jeste musim udelat "cp maska" nebo jeste lepe "sub maska" a pak odcitat tu jednicku kvuli carry.
Druhy problem jsem mel ze jsem sice udelal ty kombinace s IF, WHILE a UNTIL jak pro TESTKEY tak s PUSH_TESTKEY, ale...
Co kdyz to nekdo bude chtit znegovat, neco jako
IF NOT PRESS("Q") THEN...
Tak se to najednou bude chovat neoptimalizovane. Bude se to prekladat samostatne jako slovo za slovem a to jen kvuli tomu, ze chci u jedne instrukce skoku otocit priznak...
Hledal jsem jak se dela ve Forthu NOT, protoze jsem sklerotik a nic jsem nenasel. Nasel jsem teda INVERSE co otaci vsechny bity a funguje pro spravne udelany TRUE jako 0xFFFF a FALSE jako 0x0000, ale ne kdyz to true bude jako cokoliv od nuly.
A pak jsem to nasel misto slova NOT se pouzije za podminkou slovo 0=, ktere dela presne co chci.
Stejne jako <>0 dostane libovolnou hodnotu do 0xFFFF a 0x0000, tak 0= to navic otoci jako NOT (zneguje, ale pozor NEGATE je ve Forthu aritmeticke otoceni znamenka).
Takze jsem udelal dalsich 7 slov pro:
TESTKEY_0EQ
TESTKEY_0EQ_IF
TESTKEY_0EQ_WHILE
TESTKEY_0EQ_UNTIL
PUSH_TESTKEY_0EQ_IF
PUSH_TESTKEY_0EQ_WHILE
PUSH_TESTKEY_0EQ_UNTIL
Pak jsem mel pocit, ze mam zase problem s temi kombinacemi klaves, zvlast u TESTKEY_0EQ.
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'TESTKEY _0EQ'
ld A, H ; 1:4 testkey 0= ( mask -- bool )
in A,(0xFE) ; 2:11 testkey 0=
and L ; 1:4 testkey 0=
add A, 0xFF ; 2:7 testkey 0=
sbc HL, HL ; 2:15 testkey 0=
; seconds: 0 ;[ 8:41]
Ale i po testech to vypada dobre.
Jen v pripade ze je vse zmackle tam po vymaskovani bude nula a pri pricteni 0xFF zadne carry nebude a vysledek bude FALSE.
Dnes jsem pridal pomocne masky pro Sinclair1 a Sinclair2 a Cursor joysticky.
Kdyz jsem se dival na ten Kempston tak je to jiny port a vysledek je navic TRUE je jednickovy bit. Krasne vynulovany nahore.
Nez delat 5 novych slov, tak to radsi udelam slova co ctou a zapisuji na port.
Forth standart asi na to nic nema...
Tak jsem premyslel nad nazvem a napadlo me jen: FETCHPORT a STOREPORT
To jsem nakonec otocil, protoze parametr je port, takze to vypada nejak takto: "port port@".
Studoval jsem zas manual pro zapis na port a pokud se nepletu tak u "out (port),a" je neco jako "ld (256*a+port),a" mysleno ne jako adresa ale sbernice.
Description
The operand n is placed on the bottom half (A0 through A7) of the address bus to select
the I/O device at one of 256 possible ports. The contents of the Accumulator (Register A)
also appear on the top half (A8 through A15) of the address bus at this time. Then the byte
contained in the Accumulator is placed on the data bus and written to the selected peripheral device. Coz je fakt divne mit to A vyuzito 2x. Pouzil jsem teda jinou variantu "out (c),e"
Description
The contents of Register C are placed on the bottom half (A0 through A7) of the address
bus to select the I/O device at one of 256 possible ports. The contents of Register B are
placed on the top half (A8 through A15) of the address bus at this time. Then the byte contained in register r is placed on the data bus and written to the selected peripheral device.
Register r identifies any of the CPU registers shown in the following table, which also
shows the corresponding three-bit r field for each that appears in the assembled object
code.Kód:
dnl # ( port -- char )
define({PORTFETCH},{dnl
__{}__ADD_TOKEN({__TOKEN_PORTFETCH},{port@},$@){}dnl
}){}dnl
dnl
define({__ASM_TOKEN_PORTFETCH},{dnl
__{}define({__INFO},__COMPILE_INFO)
__{} ld B, H ; 1:4 __INFO ( port -- char )
__{} ld C, L ; 1:4 __INFO
__{} in L,(C) ; 2:12 __INFO
__{} ld H, 0x00 ; 2:7 __INFO}){}dnl
dnl
dnl
dnl
dnl # ( char port -- )
define({PORTSTORE},{dnl
__{}__ADD_TOKEN({__TOKEN_PORTSTORE},{port!},$@){}dnl
}){}dnl
dnl
define({__ASM_TOKEN_PORTSTORE},{dnl
__{}define({__INFO},__COMPILE_INFO)
__{} ld B, H ; 1:4 __INFO ( char port -- )
__{} ld C, L ; 1:4 __INFO
__{} out (C),E ; 2:12 __INFO
__{} pop HL ; 1:10 __INFO
__{} pop DE ; 1:10 __INFO}){}dnl
dnl
dnl
dnl
dnl # ( char port -- char port )
define({_2DUP_PORTSTORE},{dnl
__{}__ADD_TOKEN({__TOKEN_2DUP_PORTSTORE},{2dup port!},$@){}dnl
}){}dnl
dnl
define({__ASM_TOKEN_2DUP_PORTSTORE},{dnl
__{}define({__INFO},__COMPILE_INFO)
__{} ld B, H ; 1:4 __INFO ( char port -- char port )
__{} ld C, L ; 1:4 __INFO
__{} out (C),E ; 2:12 __INFO}){}dnl
dnl
dnl
dnl
dnl # ( char port -- port )
define({TUCK_PORTSTORE},{dnl
__{}__ADD_TOKEN({__TOKEN_TUCK_PORTSTORE},{tuck port!},$@){}dnl
}){}dnl
dnl
define({__ASM_TOKEN_TUCK_PORTSTORE},{dnl
__{}define({__INFO},__COMPILE_INFO)
__{} ld B, H ; 1:4 __INFO ( char port -- port )
__{} ld C, L ; 1:4 __INFO
__{} out (C),E ; 2:12 __INFO
__{} pop DE ; 1:10 __INFO}){}dnl