OldComp.cz

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


Právě je 28.03.2024, 22:32

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 ... 29, 30, 31, 32, 33, 34, 35 ... 39  Další
Autor Zpráva
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 03.06.2023, 19:58 
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
_dworkin píše:
Kód:
    xor   A             ; 1:4       0x1F port@ 0xFF-4 cor 1c+ zf   ( -- ) set zf: port(0x1F) and 0xFF-4
    in    A,(0x1F)      ; 2:11      0x1F port@ 0xFF-4 cor 1c+ zf
    or    0xFB          ; 2:7       0x1F port@ 0xFF-4 cor 1c+ zf
    inc   A             ; 1:4       0x1F port@ 0xFF-4 cor 1c+ zf
Pri Kempstone (a mnohych dalsich periferiach) mozes kludne vyhodit to XOR A pretoze tieto periferie dekoduju iba nizsi bajt adresy (a aj to obvykle nie vsetky bity) a na vyssom bajte nezalezi. Takze je uplne jedno, ako je A nastavene pred IN (0x1F).


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 04.06.2023, 00:41 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Busy píše:
_dworkin píše:
Kód:
    xor   A             ; 1:4       0x1F port@ 0xFF-4 cor 1c+ zf   ( -- ) set zf: port(0x1F) and 0xFF-4
    in    A,(0x1F)      ; 2:11      0x1F port@ 0xFF-4 cor 1c+ zf
    or    0xFB          ; 2:7       0x1F port@ 0xFF-4 cor 1c+ zf
    inc   A             ; 1:4       0x1F port@ 0xFF-4 cor 1c+ zf
Pri Kempstone (a mnohych dalsich periferiach) mozes kludne vyhodit to XOR A pretoze tieto periferie dekoduju iba nizsi bajt adresy (a aj to obvykle nie vsetky bity) a na vyssom bajte nezalezi. Takze je uplne jedno, ako je A nastavene pred IN (0x1F).


No, to bude trosku problematicke jak to udelat... aby to podporovalo oboji a bylo to snadno pochopitelne pro uzivatele.
Jedine dalsi slovo, ale jak to nazvat...
PORT8FETCH? _8BITPORTFETCH? Jako ze je to jen 8 bitu adresy...
Jeste by slo udelat KEMPSTONTEST, ale to se me moc nechce i kdyz by to bylo asi nejsnazsi, jen jednoucelove.

Zatim jsem si hral se PORTSTORE a pridal spoustu kombinaci, ale u PORTSTORE to asi plati taky s tim hornim bajtem u vic zarizeni? Ke vsemu jak jsem premyslel o te rychlosti zapisu tak to napriklad u instrukci jako je OTIR (a INIR) prestava davat smysl. Proste to zarizeni musi byt tak rychle aby to zvladlo.
Ale nejak me nenapada jak se to jednoduse pouziva a pro co. Protoze pokud je to neco sloziteho tak to bude vyzadovat nejakou inicializaci, komunikacni protokol pro nejake overeni ze je vse ok atd.
Takze to jde asi pouzit pro hrani nejakeho "wawu" na beeperu. Ale to bude dost kratky sampl... Ke vsemu bude 7 bitu z 8 vata... .))) Takze OTIR nedava moc smysl. Mozna nejake udelatko pro externi pamet? Ale jak se to vyhne kolizi s ostatnimi zarizenimi? To pak nemuze pouzit primo ten port pro spodni bajt adresy ale zas nejaky protokol. Neco jako prvni zapis nastavi segment, druhy ofset a pak nejakym jinym cislem portu (vlastne staci jedno cislo portu (spodnich 8 bitu) a rozlisovat 3 nebo minimalne 2 rozdilne hodnoty horniho bajtu "cisla portu"? Jaka je terminilogie? Cislo portu je 0..255? Nebo 0..x?) se to uklada a automaticky inckrementuje/snizuje kam se to uklada. Pak uz jde pouzit OTIR.

Nebo pro sitove/zaznamove zarizeni. No a pak uz me nic nenapada. Protoze neco jako AY asi bude ovladane pomaleji zmenou nejakych registru.

Hmm... mozna kazeta? Ale tam by se asi mela resit rychlost zapisu aby pak odpovidala rychlosti cteni. .))) Hmm.. a cteni taky nejde asi udelat pres INIR protoze ta rychlost by musela uplne presne stejna na instrukci jako Z80 pro celou delku cteni, nebo toho useku co cte INIR. Takze tam se to musi taky resit nejak jinak (bez blokove instrukce) a neustale sesynchronizovavat.

Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PORTSTORE'
    ld    B, H          ; 1:4       port!   ( char port -- )
    ld    C, L          ; 1:4       port!
    out  (C),E          ; 2:12      port!
    pop  HL             ; 1:10      port!
    pop  DE             ; 1:10      port!
; seconds: 0           ;[ 6:40]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(0x1234) PORTSTORE'
    ld   BC, 0x1234     ; 3:10      0x1234 port!   ( char -- )   port(0x1234) = char
    out  (C),L          ; 2:12      0x1234 port!
    ex   DE, HL         ; 1:4       0x1234 port!
    pop  DE             ; 1:10      0x1234 port!
; seconds: 0           ;[ 7:36]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'DUP PUSH(0x1234) PORTSTORE'
    ld   BC, 0x1234     ; 3:10      dup 0x1234 port!   ( char -- char )   port(0x1234) = char
    out  (C),L          ; 2:12      dup 0x1234 port!
; seconds: 1           ;[ 5:22]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'OVER PUSH(0x1234) PORTSTORE'
    ld   BC, 0x1234     ; 3:10      over 0x1234 port!   ( char x -- char x )   port(0x1234) = char
    out  (C),E          ; 2:12      over 0x1234 port!
; seconds: 0           ;[ 5:22]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(0x1234) _2DUP PORTSTORE'
    push DE             ; 1:11      0x1234 2dup port!   ( char -- char 0x1234 )   port(0x1234) = char
    ex   DE, HL         ; 1:4       0x1234 2dup port!
    ld   HL, 0x1234     ; 3:10      0x1234 2dup port!
    ld    C, L          ; 1:4       0x1234 2dup port!
    ld    B, H          ; 1:4       0x1234 2dup port!
    out  (C),E          ; 2:12      0x1234 2dup port!
; seconds: 0           ;[ 9:45]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(0x33) PUSH(0x1234) PORTSTORE'
    ld   BC, 0x1234     ; 3:10      0x33 0x1234 port!   ( -- )   port(0x1234) = 0x33
    ld    A, 0x33       ; 2:7       0x33 0x1234 port!
    out  (C),A          ; 2:12      0x33 0x1234 port!
; seconds: 0           ;[ 7:29]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh '_2DUP PORTSTORE'
    ld    C, L          ; 1:4       2dup port!   ( char x -- char x )   port(x) = char
    ld    B, H          ; 1:4       2dup port!
    out  (C),E          ; 2:12      2dup port!
; seconds: 0           ;[ 4:20]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'TUCK PORTSTORE'
    ld    B, H          ; 1:4       tuck port!   ( char port -- port )
    ld    C, L          ; 1:4       tuck port!
    out  (C),E          ; 2:12      tuck port!
    pop  DE             ; 1:10      tuck port!
; seconds: 0           ;[ 5:30]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$

A tady jsem se trochu vykaslal na "FORTH syntaxi" a pridal jakoby slovo "BC" co ma jakoby do TOS zkopirovat BC register. A tim si uvolnil ruce pro opakovane pouziti zapisu na stejny port. Ale bez pravidel pro tokeny, takze to jde volat jen jako spojene slovo primo.
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'BC_PORTSTORE'
    out  (C),L          ; 2:12      bc port!
    ex   DE, HL         ; 1:4       bc port!
    pop  DE             ; 1:11      bc port!
; seconds: 0           ;[ 4:27]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'DUP_BC_CPORTSTORE'
    out  (C),L          ; 2:12      dup bc cport!   ( char -- char )   port(BC) = char
; seconds: 1           ;[ 2:12]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'DUP_BC_HPORTSTORE'
    out  (C),H          ; 2:12      dup bc hport!   ( x -- x )   port(BC) = hi(x)
; seconds: 1           ;[ 2:12]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'OVER_BC_CPORTSTORE'
    out  (C),E          ; 2:12      over bc cport!   ( char x -- char x )   port(BC) = char
; seconds: 0           ;[ 2:12]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'OVER_BC_HPORTSTORE'
    out  (C),D          ; 2:12      over bc hport!   ( x2 x1 -- x2 x1 )   port(BC) = hi(x2)
; seconds: 0           ;[ 2:12]

Tim jsem obesel problem ze kdyz to bude opakovane nacitat z TOSu tak to bude problematicke kvuli tomu ze DROP je:
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'DROP'
    ex   DE, HL         ; 1:4       drop
    pop  DE             ; 1:10      drop   ( a -- )
; seconds: 0           ;[ 2:14]

Oproti efektivnimu NIP
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'NIP'
    pop  DE             ; 1:10      nip   ( b a -- a )
; seconds: 0           ;[ 1:10]

_________________
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.06.2023, 13:09 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Nakonec jsem precejenom vytvoril slovo TESTKEMPSTON ( mask -- bool ) a pro nej 6 promennych a fci co je prevadi na popisek. Obdobnou fci jsem udelal i pro promenne u TESTKEY, protoze to zkracuje kod generujici slova.

Kód:
define({__TESTKEMPSTON_RIGHT},0xFFFE){}dnl
define({__TESTKEMPSTON_LEFT}, 0xFFFD){}dnl
define({__TESTKEMPSTON_DOWN}, 0xFFFB){}dnl
define({__TESTKEMPSTON_UP},   0xFFF7){}dnl
define({__TESTKEMPSTON_FIRE}, 0xFFEF){}dnl
define({__TESTKEMPSTON_FIRE2},0xFFDF){}dnl
dnl
dnl
dnl
define({__TESTKEMPSTON_NAME},{dnl
__{}ifelse(dnl
__{}__HEX_L($1),__HEX_L(__TESTKEMPSTON_RIGHT),{{"right"}},
__{}__HEX_L($1),__HEX_L(__TESTKEMPSTON_LEFT), {{"left"}},
__{}__HEX_L($1),__HEX_L(__TESTKEMPSTON_DOWN), {{"down"}},
__{}__HEX_L($1),__HEX_L(__TESTKEMPSTON_UP),   {{"up"}},
__{}__HEX_L($1),__HEX_L(__TESTKEMPSTON_FIRE), {{"fire"}},
__{}__HEX_L($1),__HEX_L(__TESTKEMPSTON_FIRE2),{{"fire2"}},
__{}__HEX_L($1),0xBF,                         {{"6th bit"}},
__{}__HEX_L($1),0x7F,                         {{"7th bit"}},
__{}{{"???"}}){}dnl
}){}dnl


To ze je TRUE u nacteneho bitu 1 a ne 0 jako u klavesnice stale trochu boli, protoze u slov jako je PUSH_TESTKEMPSTON_ZF kde znam hodnotu masky, takze ji dokazi v dobe "kompilace" invertovat a mit kod neco jako
Kód:
    in    A,(0x1F)      ; 2:11      0xFFEF testkempston if   ( -- )  port(kempston) 0xFFEF invert and 0<> if
    and  0x10           ; 2:7       0xFFEF testkempston if   "fire"

To nemohu provest... protoze TRUE=no zf a FALSE=zf
ale pokud zjistim ze je tam testovano vic bitu a nebo neznam hodnotu masky tak to bude
Kód:
    in    A,(0x1F)      ; 2:11      testkempston 0= while(101)   ( mask -- )  port(kempston) or +1 0<> if
    or   0x??           ; 2:7       testkempston 0= while(101)
    inc   A             ; 1:4       testkempston 0= while(101)

kde vysledek bude opacny, TRUE=zf a FALSE=no zf.
Je fajn ze to jde prevest aspon na stejny priznak ale na stejnou hodnotu to udelat nejde (neumim). Na prvni reseni nejde sahnout, protoze cokoliv ho udela stejne efektivni jako druhe a XOR nejde pouzit, protoze by to selhalo pokud by nactena hodnota mela vic bitu aktivnich. To je otazka pristupu, ja to beru tak ze kdyz testuji VLEVO tak by TRUE melo byt i kdyz je to VLEVO+FIRE nebo VLEVO+NAHORU. Pokud chci testovat VLEVO+FIRE tak musim mit masku pro "VLEVO & FIRE" co odchytne zase i VLEVO+NAHORU+FIRE. Pokud bych to chtel ale jinak, tak je XOR reseni to prave.

No a kdyz sahnu na druhe reseni tak to nedokazi prevest na TRUE=no zf aniz bych to take neprodlouzil i kdyz tady jsem mel lepsi sance.

Kdyz invertuji A za bajt a 4 takty a pouziji tu masku s AND tak je to stejne dlouhe, jen je ten zero flag stale otoceny...

Ok takze zakladni varianty:
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'TESTKEMPSTON'
    in    A,(0x1F)      ; 2:11      testkempston   ( mask -- bool )  bool: port(kempston) cor +1c 0c=
    or    L             ; 1:4       testkempston
    add   A, 0x01       ; 2:7       testkempston
    sbc  HL, HL         ; 2:15      testkempston
; seconds: 0           ;[ 7:37]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'TESTKEMPSTON _0EQ'
    in    A,(0x1F)      ; 2:11      testkempston 0=   ( mask -- bool )  bool: port(kempston) cor +1c 0c<>
    or    L             ; 1:4       testkempston 0=
    sub  0xFF           ; 2:7       testkempston 0=
    sbc  HL, HL         ; 2:15      testkempston 0=
; seconds: 0           ;[ 7:37]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'TESTKEMPSTON_ZF'
    in    A,(0x1F)      ; 2:11      testkempston zf   ( mask -- )  zf: port(kempston) cor +1c 0c=
    or    L             ; 1:4       testkempston zf
    inc   A             ; 1:4       testkempston zf
    ex   DE, HL         ; 1:4       testkempston zf
    pop  DE             ; 1:10      testkempston zf
; seconds: 0           ;[ 6:33]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$

Se znalosti masky:
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(__TESTKEMPSTON_FIRE) TESTKEMPSTON'
    push DE             ; 1:11      0xFFEF testkempston   ( -- bool )  bool: port(kempston) 0xFFEF cand 0c<>
    ex   DE, HL         ; 1:4       0xFFEF testkempston
    in    A,(0x1F)      ; 2:11      0xFFEF testkempston
    and  0x10           ; 2:7       0xFFEF testkempston   "fire"
    add   A, 0xFF       ; 2:7       0xFFEF testkempston
    sbc  HL, HL         ; 2:15      0xFFEF testkempston
; seconds: 0           ;[10:55]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(__TESTKEMPSTON_FIRE & __TESTKEMPSTON_RIGHT) TESTKEMPSTON'
    push DE             ; 1:11      0xFFEF & 0xFFFE testkempston   ( -- bool )  bool: port(kempston) 0xFFEF & 0xFFFE cor +1c 0c=
    ex   DE, HL         ; 1:4       0xFFEF & 0xFFFE testkempston
    in    A,(0x1F)      ; 2:11      0xFFEF & 0xFFFE testkempston
    or   0xEE           ; 2:7       0xFFEF & 0xFFFE testkempston   "multibit test"
    inc   A             ; 1:4       0xFFEF & 0xFFFE testkempston
    sub  0x01           ; 2:7       0xFFEF & 0xFFFE testkempston
    sbc  HL, HL         ; 2:15      0xFFEF & 0xFFFE testkempston
; seconds: 1           ;[11:59]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(blabla) TESTKEMPSTON'
    push DE             ; 1:11      blabla testkempston   ( -- bool )  bool: port(kempston) blabla cor +1c 0c=
    ex   DE, HL         ; 1:4       blabla testkempston
    in    A,(0x1F)      ; 2:11      blabla testkempston
    or   blabla         ; 2:7       blabla testkempston
    inc   A             ; 1:4       blabla testkempston
    sub  0x01           ; 2:7       blabla testkempston
    sbc  HL, HL         ; 2:15      blabla testkempston
; seconds: 0           ;[11:59]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH((adresa)) TESTKEMPSTON'
    push DE             ; 1:11      (adresa) testkempston   ( -- bool )  bool: port(kempston) (adresa) cor +1c 0c=
    ex   DE, HL         ; 1:4       (adresa) testkempston
    ld   HL, (adresa)   ; 3:16      (adresa) testkempston
    in    A,(0x1F)      ; 2:11      (adresa) testkempston
    or    L             ; 1:4       (adresa) testkempston
    inc   A             ; 1:4       (adresa) testkempston
    sub  0x01           ; 2:7       (adresa) testkempston
    sbc  HL, HL         ; 2:15      (adresa) testkempston
; seconds: 0           ;[13:72]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$

v podstate to same s "NOT"
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(__TESTKEMPSTON_FIRE) TESTKEMPSTON _0EQ'
    push DE             ; 1:11      0xFFEF testkempston 0=   ( -- bool )  bool: port(kempston) 0xFFEF cand 0c=
    ex   DE, HL         ; 1:4       0xFFEF testkempston 0=
    in    A,(0x1F)      ; 2:11      0xFFEF testkempston 0=
    and  0x10           ; 2:7       0xFFEF testkempston 0=   "fire"
    sub  0x01           ; 2:7       0xFFEF testkempston 0=
    sbc  HL, HL         ; 2:15      0xFFEF testkempston 0=
; seconds: 1           ;[10:55]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(__TESTKEMPSTON_FIRE & __TESTKEMPSTON_RIGHT) TESTKEMPSTON _0EQ'
    push DE             ; 1:11      0xFFEF & 0xFFFE testkempston 0=   ( -- bool )  bool: port(kempston) 0xFFEF & 0xFFFE cor +1c 0c<>
    ex   DE, HL         ; 1:4       0xFFEF & 0xFFFE testkempston 0=
    in    A,(0x1F)      ; 2:11      0xFFEF & 0xFFFE testkempston 0=
    or   0xEE           ; 2:7       0xFFEF & 0xFFFE testkempston 0=   "multibit test"
    inc   A             ; 1:4       0xFFEF & 0xFFFE testkempston 0=
    add   A, 0xFF       ; 2:7       0xFFEF & 0xFFFE testkempston 0=
    sbc  HL, HL         ; 2:15      0xFFEF & 0xFFFE testkempston 0=
; seconds: 1           ;[11:59]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(blabla) TESTKEMPSTON _0EQ'
    push DE             ; 1:11      blabla testkempston 0=   ( -- bool )  bool: port(kempston) blabla cor +1c 0c<>
    ex   DE, HL         ; 1:4       blabla testkempston 0=
    in    A,(0x1F)      ; 2:11      blabla testkempston 0=
    or   blabla         ; 2:7       blabla testkempston 0=
    inc   A             ; 1:4       blabla testkempston 0=
    add   A, 0xFF       ; 2:7       blabla testkempston 0=
    sbc  HL, HL         ; 2:15      blabla testkempston 0=
; seconds: 1           ;[11:59]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH((adresa)) TESTKEMPSTON _0EQ'
    push DE             ; 1:11      (adresa) testkempston 0=   ( -- bool )  bool: port(kempston) (adresa) cor +1c 0c<>
    ex   DE, HL         ; 1:4       (adresa) testkempston 0=
    ld   HL, (adresa)   ; 3:16      (adresa) testkempston 0=
    in    A,(0x1F)      ; 2:11      (adresa) testkempston 0=
    or    L             ; 1:4       (adresa) testkempston 0=
    inc   A             ; 1:4       (adresa) testkempston 0=
    add   A, 0xFF       ; 2:7       (adresa) testkempston 0=
    sbc  HL, HL         ; 2:15      (adresa) testkempston 0=
; seconds: 0           ;[13:72]

A pak jeste PUSH_TESTKEMPSTON_ZF co jsem uz popisoval ze nerozlisuje pokud je testovan jediny bit, ale ukazi jak dokaze udelat malou analyzu te masky kdyz testujeme VLEVO+VPRAVO a nebo je nejvyssi bit nula coz naznacuje ze programator nepochopil ze ta maska ma byt invertovana.
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(__TESTKEMPSTON_FIRE) TESTKEMPSTON_ZF'
    in    A,(0x1F)      ; 2:11      0xFFEF testkempston zf   ( -- )  zf: port(kempston) 0xFFEF cor +1c
    or   0xEF           ; 2:7       0xFFEF testkempston zf   "fire"
    inc   A             ; 1:4       0xFFEF testkempston zf
; seconds: 0           ;[ 5:22]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(__TESTKEMPSTON_RIGHT & __TESTKEMPSTON_LEFT) TESTKEMPSTON_ZF'
  .warning Nonsence mask! Each bit that is tested must be 0 and the others 1.
    in    A,(0x1F)      ; 2:11      0xFFFE & 0xFFFD testkempston zf   ( -- )  zf: port(kempston) 0xFFFE & 0xFFFD cor +1c
    or   0xFC           ; 2:7       0xFFFE & 0xFFFD testkempston zf   "???"
    inc   A             ; 1:4       0xFFFE & 0xFFFD testkempston zf
; seconds: 1           ;[ 5:22]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(0xFC) TESTKEMPSTON_ZF'
  .warning Nonsence mask! Each bit that is tested must be 0 and the others 1.
    in    A,(0x1F)      ; 2:11      0xFC testkempston zf   ( -- )  zf: port(kempston) 0xFC cor +1c
    or   0xFC           ; 2:7       0xFC testkempston zf   "???"
    inc   A             ; 1:4       0xFC testkempston zf
; seconds: 0           ;[ 5:22]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(0xF3) TESTKEMPSTON_ZF'
  .warning Nonsence mask! Each bit that is tested must be 0 and the others 1.
    in    A,(0x1F)      ; 2:11      0xF3 testkempston zf   ( -- )  zf: port(kempston) 0xF3 cor +1c
    or   0xF3           ; 2:7       0xF3 testkempston zf   "???"
    inc   A             ; 1:4       0xF3 testkempston zf
; seconds: 0           ;[ 5:22]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(0x7F) TESTKEMPSTON_ZF'
  .warning Nonsence mask! Each bit that is tested must be 0 and the others 1.
    in    A,(0x1F)      ; 2:11      0x7F testkempston zf   ( -- )  zf: port(kempston) 0x7F cor +1c
    or   0x7F           ; 2:7       0x7F testkempston zf   "7th bit"
    inc   A             ; 1:4       0x7F testkempston zf
; seconds: 0           ;[ 5:22]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(0x7E) TESTKEMPSTON_ZF'
  .warning Nonsence mask! Each bit that is tested must be 0 and the others 1.
    in    A,(0x1F)      ; 2:11      0x7E testkempston zf   ( -- )  zf: port(kempston) 0x7E cor +1c
    or   0x7E           ; 2:7       0x7E testkempston zf   "???"
    inc   A             ; 1:4       0x7E testkempston zf
; seconds: 1           ;[ 5:22]


No a pak jsem pracoval na spojeni tech 4 zakladnich slov (TESTKEMPSTON, TESTKEMPSTON_0EQ, PUSH_TESTKEMPSTON, PUSH_TESTKEMPSTON_0EQ,) s IF WHILE a UNTIL. Nebudu ukazovat vygenerovany kod protoze tam je navic jen odskok a pripadne break label u UNTIL.

Na cely kod "BEGIN" smycek jsem hrabal a zmenil info ze to ukazuje... aha tak neco radsi ukazu, bude to snazsi:
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'BEGIN PUSH(0xFD) TESTKEMPSTON UNTIL'
begin101:               ;           begin(101)
    in    A,(0x1F)      ; 2:11      0xFD testkempston until(101)   ( -- )  port(kempston) 0xFD invert and 0<> if
    and  0x02           ; 2:7       0xFD testkempston until(101)   "left"
    jp    z, begin101   ; 3:10      0xFD testkempston until(101)
break101:               ;           0xFD testkempston until(101)
; seconds: 0           ;[ 7:28]

Pridaval jsem za ty smyckovy slova do informaci zavorku s cislem smycky, puvodne jsem tam nemel nic a nebo to mel oddelenne mezerou takze to vypadalo jako PUSH(101).

Trochu jsem se sam dostal, protoze ty hodnoty generuji AZ kdyz generuji instrukce, takze v tokenech nic neni, zadny parametr navic a celou dobu tokenu je tam jen 100. Takze jsem mel omylem puvodne neco jako
Kód:
define({UNTIL},{dnl
__{}__ADD_TOKEN({__TOKEN_UNTIL},{until(BEGIN_STACK)},$@){}dnl
}){}dnl

Ale to by pro vsechny slova melo ve vysledku (100).

Takze jsem to pridal az v __ASM_TOKEN... kde se generuji ty instrukce
Kód:
__{}define({__INFO},__COMPILE_INFO(BEGIN_STACK)){}dnl


ale to taky nefunguje... protoze si M4 mysli ze je to parametr makra/fce __COMPILE_INFO, takze se to nevypise!
Spravne je az
Kód:
__{}define({__INFO},__COMPILE_INFO{(BEGIN_STACK)}){}dnl


Hrabal jsem na to hromadne s cca 100 zmenama a musel jsem to neustale oprvovat tak snad jsem neco nerozdrbal.
U makra __ASM_BEGIN to musi byt trosku jinak protoze tam se to inkrementuje, takze to musi byt pred definici __INFO.

A ve vyseledku je to stejne cele spatne protoze mohou existovat spojena slova jako ...WHILE_NECO... a ta zavorka nebude u WHILE ale na konci. Reseni by bylo to mit jak jsem ukazoval u definice tokenu UNTIL a delat zmenu BEGIN_STACK v tomhle case a pridavat k tokenum dalsi parametr s cislem smycky. Ale nechce se me v tom drbat a neco rozhasit...

PS: Reseni ohledne toho vyssiho bajtu co se posila u IN a OUT me napadlo, ze pokud to bude zname (u PUSH) a bude to nula tak to ignorovat, protoze to bude signal ze to neni potreba. Klavesnice to vyzaduje, ale ani jeden bajt neni nulovy. Jen kdybych chtel cist vsechny radky najednou... a i pak by to slo protoze je na to specialni slovo TESTKEY a nemusim to delat pres PORTFETCH.
Existuje nejaky hardware u ktereho je ten horni bajt dulezity a zaroven muze byt nula?

PPS: Dalsi reseni je generovat vsude

if _neco_
xor a
endif
in a,(port)

a mit tak moznost to zmenit globalne. A nemuset kvuli tomu muset duplikovat vsechen kod/slova.

A nebo se na to uplne... .)

PPPS: Tohle me trosku vadi
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'BEGIN IF BREAK THEN'
begin101:               ;           begin(101)
    ld    A, H          ; 1:4       if
    or    L             ; 1:4       if
    ex   DE, HL         ; 1:4       if
    pop  DE             ; 1:10      if
    jp    z, else101    ; 3:10      if
    jp   break101       ; 3:10      break(101)
else101  EQU $          ;           then  = endif
endif101:               ;           then
; seconds: 0           ;[10:42]

Jde mi o to ze IF je delane na IF ELSE THEN, ale kdyz ELSE vetev neni a jedine co je za IF je instrukce skoku tak staci otocit priznak u skoku na ELSE a vypadne jedna instrukce. Ale tenhle pripad je celkem vyjmecny a u te ukazky nesmyslny, protoze jde nahradit WHILE
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'BEGIN WHILE'
begin101:               ;           begin(101)
    ld    A, H          ; 1:4       while(101)
    or    L             ; 1:4       while(101)
    ex   DE, HL         ; 1:4       while(101)
    pop  DE             ; 1:10      while(101)
    jp    z, break101   ; 3:10      while(101)
; seconds: 0           ;[ 7:32]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'BEGIN _0EQ WHILE'
begin101:               ;           begin(101)
                        ;[7:32]     0= while(101)   ( x -- )   0 == HL variant: zero
    ld    A, L          ; 1:4       0= while(101)
    or    H             ; 1:4       0= while(101)
    ex   DE, HL         ; 1:4       0= while(101)
    pop  DE             ; 1:10      0= while(101)
    jp   nz, break101   ; 3:10      0= while(101)
; seconds: 0           ;[ 7:32]
a dalsi odskok je jen z definovaneho slova/fce/podprogramu. A osetrit to by znamenalo to udelat ve vsech slovech s IF... Hlidat ze je tam IF_BREAK_THEN. Takze i KEMPSTON_IF_BREAK_THEN atd. A to se mi fakt nechce takze... to necham plavat. Komu to vadi muze si to delat rucne.. .)

_________________
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.06.2023, 13:38 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Jak se koukam na ten kod...
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(__TESTKEMPSTON_FIRE & __TESTKEMPSTON_RIGHT) TESTKEMPSTON'
    push DE             ; 1:11      0xFFEF & 0xFFFE testkempston   ( -- bool )  bool: port(kempston) 0xFFEF & 0xFFFE cor +1c 0c=
    ex   DE, HL         ; 1:4       0xFFEF & 0xFFFE testkempston
    in    A,(0x1F)      ; 2:11      0xFFEF & 0xFFFE testkempston
    or   0xEE           ; 2:7       0xFFEF & 0xFFFE testkempston   "multibit test"
    inc   A             ; 1:4       0xFFEF & 0xFFFE testkempston
    sub  0x01           ; 2:7       0xFFEF & 0xFFFE testkempston
    sbc  HL, HL         ; 2:15      0xFFEF & 0xFFFE testkempston
; seconds: 0           ;[11:59]

Tak jsem mel to "inc A" ostranit... misto TRUE=carry resene z 0 pres SUB 0x01 jsem to mel resit rovnou z 255 pres ADD A,0x01

PS: Pripadne pokud je to _0EQ tak to same z 255 pres SUB 0xFF.
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(__TESTKEMPSTON_FIRE & __TESTKEMPSTON_RIGHT) TESTKEMPSTON _0EQ'
    push DE             ; 1:11      0xFFEF & 0xFFFE testkempston 0=   ( -- bool )  bool: port(kempston) 0xFFEF & 0xFFFE cor +1c 0c<>
    ex   DE, HL         ; 1:4       0xFFEF & 0xFFFE testkempston 0=
    in    A,(0x1F)      ; 2:11      0xFFEF & 0xFFFE testkempston 0=
    or   0xEE           ; 2:7       0xFFEF & 0xFFFE testkempston 0=   "multibit test"
    inc   A             ; 1:4       0xFFEF & 0xFFFE testkempston 0=
    add   A, 0xFF       ; 2:7       0xFFEF & 0xFFFE testkempston 0=
    sbc  HL, HL         ; 2:15      0xFFEF & 0xFFFE testkempston 0=
; seconds: 1           ;[11:59]

Da se rici ze proste mazu INC A a prohazuji ADD za SUB.

_________________
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.06.2023, 20:21 
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
_dworkin píše:
A nebo se na to uplne... .)
To je spravny pristup ! :thumbup:
Basic tiez nema vseliake varianty pre taky a onaky OUT/IN ale proste ma jeden plny 16-bitovy IN a jeden plny 16-bitovy OUT. A s nim uz urobis vsetko co potrebujes.


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

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Potreboval jsem cekaci smycku, ale vic jak 8 bitovou a podminka byla aby "DEC" trval konstantni dobu.

Takze jsem udelal
Kód:
        ld   B, H                      ;1:4
        ld   C, L                      ;1:4
loop_HL:
; HL*24
        dec BC                         ;1:6
        ld   A, B                      ;1:4
        or   C                         ;1:4
        jp   nz, loop_HL               ;3:10


No, ale bylo to pomale a potreboval jsem to zrychlit... (zjemnit jeden krok) jenze kdyz to rozseknu na 2 smycky tak to nebude konstantni. Kazda 256. hodnota bude trosku odlisna...

Ale napadlo me tohle!
Kód:
        ld   B, H                      ;1:4
        ld   C, L                      ;1:4
        inc  B                         ;1:4
        inc  C                         ;1:4
loop_HL:
;HL*18
        nop                            ;1:4
        dec  C                         ;1:4
        jp   nz, loop_HL               ;3:10
        dec  C                         ;1:4
        dec  B                         ;1:4
        jp   nz, loop_HL               ;3:10


Jeste nikdy jsem nic takoveho nevidel... .)
Bude tam sice vznikat trosku vetsi konstantni "rezie" z puvodnich 8 taktu je to 16+18, ale konstatni zpozdeni me nevadi.

_________________
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.06.2023, 18:40 
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
_dworkin píše:
Jeste nikdy jsem nic takoveho nevidel... .)
Pretoze si sa nepozeral do komentovaneho vypisu ZX ROM :poke: :lol:
Pozri sa do BEEP rutinky #3B5, pre dlzku polperiody tonu sa tam pouziva podobna cakacia slucka, tiez zalozena na dvoch osembitovych dekrementoch za sebou.

A este jedna pikoska: Tvoja povodna verzia ma rozlisenie 24T, tvoja nova ma uz (o zanedbatelny kusok lepsich) 18T, ale cakacia slucka v BEEP rutinke ma rozlisenie 4T :)


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

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Busy píše:
_dworkin píše:
Jeste nikdy jsem nic takoveho nevidel... .)
Pretoze si sa nepozeral do komentovaneho vypisu ZX ROM :poke: :lol:
Pozri sa do BEEP rutinky #3B5, pre dlzku polperiody tonu sa tam pouziva podobna cakacia slucka, tiez zalozena na dvoch osembitovych dekrementoch za sebou.

A este jedna pikoska: Tvoja povodna verzia ma rozlisenie 24T, tvoja nova ma uz (o zanedbatelny kusok lepsich) 18T, ale cakacia slucka v BEEP rutinke ma rozlisenie 4T :)


No ale rozliseni 4 takty je uz pod schopnosti smycky, takze se ten vstup musi upravit a to stoji mnohem vic rezie. Schvalne jsem udelal na prvni dobrou rutinu co ma rozdil ty 4 takty a je... fakt hnusna... .))) S tvrdym omezenim zadne RET a smeni jen AF. Ale je to prvni co me napadlo:
Kód:
; wait = hl*4 + 73 clock

    xor a            ; 1:4
    or l             ; 1:4
    rra              ; 1:4
    jp nc,$+4        ; 3:10
    or a             ; 1:4      +4 clock
   
    rra              ; 1:4
    jp nc,$+5        ; 3:10
    or a             ; 1:4      +4 clock
    nop              ; 1:4      +4 clock
   
    inc a           ; 1:4
    dec a           ; 1:4
    jr $-1          ; 2:7/12    +16 clock
                    ; lo/4 * 4*4 = lo/4 * 16 

    ld a,h          ; 1:4
    inc a           ; 1:4
    dec a           ; 1:4
    jp  z, end_hi   ; 3:10
loop_hi:
    push bc         ; 1:11
    ld   b, 75      ; 2:7
    djnz $-2        ; 2:8/13
    inc  bc         ; 1:6
    dec  bc         ; 1:6
    pop  bc         ; 1:10
                    ;[6:11+7+74*13+8+10+12=1010]
    dec a           ; 1:4
    jp nz, end_hi   ; 3:10      +1024 clock
end_hi:
                       ;[35:4*HL+77]

Netestoval jsem.
Tohle je ale dobra vyzva, jak to napsat bud nejkratsi a nebo s co nejmensi konstantni rezii.

Kdyz podelim dvema vstup a pouziji tu nejsnazsi smycku
Kód:
    srl h           ; 2:8
    rr  l           ; 2:8       hl/2
    jp nc,$+5       ; 3:10
    inc hl          ; 1:6       +6 clock
    dec hl          ; 1:6       +6 clock
loop:
    ld a,l          ; 1:4
    or h            ; 1:4
    dec hl          ; 1:6
    jp nz, loop     ; 3:10      +12 taktu
                    ;[15:HL*12+50]


Kdyz pouziji tu vylepsenou:
Kód:
    srl h           ; 2:8
    rr  l           ; 2:8       hl/2
    jp nc,$+5       ; 3:10
    ld  a,i         ; 2:9       +9 clock
    inc l           ; 1:4
    inc h           ; 1:4
loop:
    dec l           ; 1:4
    nop             ; 1:4
    jp nz, loop     ; 3:10

    dec l           ; 1:4
    dec h           ; 1:4
    jp nz, loop     ; 3:10
                    ;[21:HL*9+70]


Ale stejne je to k nicemu... .) Protoze jsem nekde cetl ze to musi byt u ZX nasobek 8. Nevim proc, asi kvuli nejakym kolizim s ULA...???

Takze...
Kód:
    inc c           ; 1:4
    inc b           ; 1:4
loop:
    dec c           ; 1:4
    jr nz, loop     ; 2:7/12    ; 16 clock (last 11 clock)

    nop             ; 1:4
    dec c           ; 1:4
    djnz   loop     ; 2:8/13    ; -5 + 4 + 4 + 13 = 16 clock
                    ;[ 9:BC*16+35]

Tohle je moc pekne.. :D
Mezi skokem a neskokem v JR je rozdil 5 taktu, takze je misto pro jeden odecet DEC C a stale zbyva jeden takt... Ale to je presne o kolik je pomalejsi DJNZ, krasne to vychazi!

Pokud to podelim dvema:
Kód:
    srl b           ; 2:8
    rr  c           ; 2:8       bc/2
    jp nc,$+5       ; 3:10
    nop             ; 1:4       +4 clock
    nop             ; 1:4       +4 clock
               
    inc c           ; 1:4
    inc b           ; 1:4
loop:
    dec c           ; 1:4
    jr nz, loop     ; 2:7/12    ; 16 clock (last 11 clock)

    nop             ; 1:4
    dec c           ; 1:4
    djnz   loop     ; 2:8/13    ; -5 + 4 + 4 + 13 = 16 clock
                    ;[18:BC*8+61]


Jen ta 61 neni delitelna 8... ale to neva protoze kdyz se to da do rutiny tak CALL + 17 a RET + 10 se rovna 61+17+10 = 88.

No a kdybych to jeste podelil dvema:
Kód:
    ld a,c          ; 1:4
    srl b           ; 2:8
    rra             ; 1:4       ba/2
    jp nc,$+4       ; 3:10
    nop             ; 1:4       +4 clock

    srl b           ; 2:8
    rra             ; 1:4       bc/2
    jp nc,$+5       ; 3:10
    nop             ; 1:4       +4 clock
    nop             ; 1:4       +4 clock
               
    srl b           ; 2:8
    rr  c           ; 2:8       bc/2
    jp nc,$+5       ; 3:10
    nop             ; 1:4       +4 clock
    nop             ; 1:4       +4 clock
               
    inc c           ; 1:4
    inc b           ; 1:4
loop:
    dec c           ; 1:4
    jr nz, loop     ; 2:7/12    ; 16 clock (last 11 clock)

    nop             ; 1:4
    dec c           ; 1:4
    djnz   loop     ; 2:8/13    ; -5 + 4 + 4 + 13 = 16 clock
                    ;[25:BC*4+83]


Tak to bude cca o 10 bajtu kratsi jak prvni reseni, ale to melo minimalni rezii 77 taktu.


No abych to nezakecal. Chtel jsem se zeptat:

1. je nekde ulozena hodnota bitu speakeru (4 bit kdyz to pocitam od nuly) co byl naposled poslan na 0xFE?

2. bubinek speakeru... spikru... ehh... radsi budu psat bzucaku je trvale vychylen na jednu stranu na ktery byla nastaven ten bit? A nebo ma nejakou trvalou polohu (0) a pri vybuzeni (1) se presouva do druhe polohy a odtam pak postupne se vrati na polohu (0)? Jde mi o to ze jsem videl v nejakem motoru opakovat posilanou 1 a i posilanou 0 na 0xFE v nejakem pevnem intervalu. Pokud by se ten speaker vracel k (0) tak by davalo smysl to opakovane posilani 1, opakovani nuly je divne... Jedine ze by mel stredovou polohu.

PS: Opravil jsem nejake drobnosti, jako ze slovo ZX_CLS ted pri aktivaci fontu 5x8 ten font nezrusi.

PPS: Pridal jsem slovo MUSIC(filename_xm), ktery prehrava 8-kanalovy xm. Pouzil jsem nahodne motor OCTODE ve variante 2k16. Trosku tapu jak to pridat k MIT licenci. Co jsem pouzil ma licenci:
https://github.com/utz82/ZX-Spectrum-1-Bit-Routines/blob/master/LICENSE

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Neither the name of utz/irrlicht project nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.


To co je cervene me prekladac preklada nesmyslne dvojznacne.

* Ani název projektu utz/irrlicht ani jeho názvy
přispěvatelé mohou být využiti k podpoře nebo propagaci produktů odvozených od
tento software bez zvláštního předchozího písemného povolení

* Název projektu utz/irrlicht ani názvy jeho
přispěvatelů nesmí být použity k podpoře nebo propagaci produktů odvozených od
tohoto softwaru bez zvláštního předchozího písemného svolení

Takze jsem to udelal tak ze jsem vytvoril novy adresar mimo M4 a do neho nakopiroval veci okolo toho motoru a vrazil tam doslovnou kopii tehle licence. Snad je to ok.

Musel jsem upravit ten cpp soubor co prevadi binarni XM soubor na textovy soubor plny DW radku. Protoze puvodni autor nepocital s tim, ze budu chtit includnou vic souboru a mlatili by se nazvy labelu. Takze jsem musel nepatrne osetrit i "obal" toho motoru na vstupu (i vystupu), aby to zvladlo vic jak jeden "loop" label a vic jak jeden pocatek dat.

Kod pro prehrani 3 souboru vypada nejak takto:
Kód:
;vvvv
include(`../M4/FIRST.M4')dnl
;^^^^

    org 0x8000
    define({USE_FONT_5x8})

    middle_text equ 24/2-1
    left_text equ (51-20)/2
         
    INIT(6000)
    ZX_CONSTANT

    PUSH(0x5800,3*256,ZX_BLUE) FILL
    PUSH(ZX_BLACK) ZX_BORDER

    BEGIN
        PRINT_I({ZX_INK, ZX_BLUE, ZX_PAPER, ZX_BLACK})
        PRINT_I({ZX_AT,middle_text-1,left_text," 1: octode     test "})
        PRINT_I({ZX_AT,middle_text+0,left_text," 2: octode2k15 test "})
        PRINT_I({ZX_AT,middle_text+1,left_text," 3: octode2k16 test "})
        PRINT_I({ZX_AT,middle_text+2,left_text," 4: exit ",ZX_INK, ZX_RED})

        PUSH(__TESTKEY_1) TESTKEY
    IF
        PRINT_I({ZX_AT,middle_text-1,left_text," 1: octode     test "})
        MUSIC(octode)
    ELSE
        PUSH(__TESTKEY_2) TESTKEY
    IF
        PRINT_I({ZX_AT,middle_text+0,left_text," 2: octode2k15 test "})
        MUSIC(octode2k15)
    ELSE
        PUSH(__TESTKEY_3) TESTKEY
    IF
        PRINT_I({ZX_AT,middle_text+1,left_text," 3: octode2k16 test "})
        MUSIC(octode2k16)
    ELSE
        PUSH(__TESTKEY_4) TESTKEY
    IF     
        PRINT_I({ZX_AT,middle_text+2,left_text," 4: exit ",ZX_INK, ZX_RED})
        BREAK
    THEN THEN THEN THEN
    AGAIN

    DEPTH
    PRINT_I({0x0D, "Depth: "}) DOT CR
    STOP


Příloha:
music.png
music.png [ 746 bajtů | Zobrazeno 439 krát ]


Hraje to testovaci skladby co byly na ukazku k motorum Octode od Shiru (asi kdyz je to jeho puvodni motor) a dve od Irrlicht project (asi, mozna je to skupina?)

https://soundcloud.com/irrlicht-project/octode-2k16-test

PPPS: Zkousel jsem svoje pipani, ale rekl bych ze je to dost mimo me schopnosti... i kdyz nejaky zaklad chapu, tak jsou ty implementacni detaily dost slozite.


Přílohy:
test2.tap [12.34 KiB]
17 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.06.2023, 04:36 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Jinak jsem uplne selhal v editovani XM souboru.
Kdysi davno jsem mel Impulse Tracker na 486 (AMD DX2-80 bez zvukovky), a v ubuntu jsem rad, ze to vubec jeste nejaky prehravac prehraje, ale editace...?
Takze jsem nasel primo v repozitari FastTRacker II a vzpominal...
Dokazi snadno zmenit pocet kanalu a celou skladbu snizit o oktavu...
Problem je ale v tom, ze OCTODE vyzaduje jen jeden "bubinek" a ten se pozna podle toho ze ma sampl s cislem 2. Ktery typ uderu se pouzije se rozlisuje podle toho zda je to C-5 nebo F-5 atd.
Zbytek musi byt se samplem 1 a max B-4?

No a ja umim maximalne ty samply smazat... .) a ne hromadne zmenit. Takze kdyz pouziji nereferencni XM (i neco primitivniho) tak je bud uplne bez zvuku a nebo nahodne kdyz se hraje samp cislo 1 se spravnou oktavou to kousek hraje.

_________________
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.06.2023, 08:39 
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
_dworkin píše:
jsem nekde cetl ze to musi byt u ZX nasobek 8. Nevim proc, asi kvuli nejakym kolizim s ULA...???
To plati iba za velmi specifickych okolnosti - kod musi bezat v spomalenej videoramke a musi sa jednat o originalne ZX Spektrum 16k,48k,128k a +2. Na comkolvek inom (+2A, +3, M, Kompakt, Pentagon...) to uz neplati. Pokial ale kod umiestnis do rychlej pameti, tak vsade mas zaruku ze sa to nebude zaokruhlovat na nasobok 8 T.
_dworkin píše:
1. je nekde ulozena hodnota bitu speakeru (4 bit kdyz to pocitam od nuly) co byl naposled poslan na 0xFE?
Nie je. A ani bit 3 (pouzivany pre SAVE) nie je nikde ulozeny.
_dworkin píše:
2. bubinek speakeru... spikru... ehh... radsi budu psat bzucaku je trvale vychylen na jednu stranu na ktery byla nastaven ten bit? ...
Bit 4 priamo zodpoveda trvalej polohe membrany repraciku. Ked na bit 4 portu #FE posles nulu, tak je jeho budiaci tranzistor vypnuty, cez repracik netecie (temer) ziadny prud a membrana je v kludovej strednej polohe. Ked tam posles 1 tak sa tranzistor zopne, cez repracik zacne pretekat trvaly jednosmerny prud a membrana sa trvalo vychyli do jednej krajnej polohy a zostane tak. Az ked na ten bit znovu posles 0 tak sa membrana vrati nazad do kludovej polohy. (preto sa velmi doporucuje po skonceni generovania zvuku nastavit bit 4=0 aby cez repracik netiekol trvaly prud)

Z hladiska samotneho generovania zvuku je dolezite to ze hodnoty 0 a 1 zodpovedaju dvom pevnym poloham membrany repraciku.

Pre klony ZX Spektra ktore nemaju zabudovany repracik to plati zase pre vystupny signal - 0 znamena nizke napetie na vystupe a 1 vyssie napetie. V podstate klasicky 1-bitovy D/A prevodnik :)
_dworkin píše:
PPPS: Zkousel jsem svoje pipani, ale rekl bych ze je to dost mimo me schopnosti...
Nie je tam nic zloziteho. Ak chces na vystupe urobit pulz, treba tam poslat 1 pre zaciatok pulzu a po danom case pulzu zase 0 pre koniec pulzu. A ak nejaku frekvenciu, musis "rucne" softwerovo striedat 0 a 1 s danou frekvenciou.
_dworkin píše:
i kdyz nejaky zaklad chapu, tak jsou ty implementacni detaily dost slozite.
Co konkrente je zlozite ?


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 09.06.2023, 09:12 
Offline
Radil

Registrován: 18.10.2014, 23:10
Příspěvky: 377
Has thanked: 28 times
Been thanked: 120 times
Chcel by som to ešte upresniť. Ten Octode používa PWM (Pulse Width Modulation), čo je vlastne využívanie toho, že reproduktor má síce len dve krajné polohy (stav 0 a stav 1), ale prechod od jednej polohy k druhej chvíľu trvá. Takže rýchlym striedaním 0 a 1 bude reproduktor niekde v strede (stav 0.5). No a to opakované outovanie rovnakej hodnoty môže byť sampel, alebo len forma pauzy. Výstup je digitálny, takže ten bude len 0, alebo 1.


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 09.06.2023, 09:39 
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
Tento sposob vyuziva aj stary znamy hudobny program "Wham! The music box". Pomocou rychleho striedania 0 a 1 si vytvara akusi strednu polohu, a vdaka tomu umoznuje na jednom bite hrat dva binarne obdlznikove tony naraz.

Dalej sa zvykne pouzivat pulzna modulacia, ked sa ton vytvara seriou kratkych pulzov. Tym ze su pulzy kratke a vecsinu casu je uroven v nule, tak sa da obycajnym OR-om skombinovat viacero tonov naraz bez vyraznejsej straty kvality. Takto funguju napriklad vsetky hudobne hradla od Bytepack: osemkanalovy ZX-7, stvorkanalovy ZX10, a dokonca aj sestnastkanalovy ZX16.


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

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Pokud budu v pravidelnych intevalech posilat 0 a 1 tak me bude (trosku asi v zavislosti na konkretnim 40+ let starem bzucaku) vznikat "vlna" co bude vypadat nejak takto:
Kód:
max ........==========(0)...................==========(0)...................====
           /           \                   /           \                   /                 
          /      |      \        |        /      |      \        |        /                 
     |   /   |   |   |   \   |   |   |   /   |   |   |   \   |   |   |   /   |             
        /        |        \      |      /        |        \      |      /       
       /                   \           /                   \           /       
min ==(1)...................==========(1)...................==========(1).......


Kterou budu asi slyset jako nejaky ton podobny tomuhle, jen diky orezani to nebude znit ciste?
Kód:
                ***                             ***                             ***
              *      *                        *     *                         *   
max ........==========(0)...................==========(0)...................=======
           /           \                   /           \                   /                 
          /      |      \        |        /      |      \        |        /      |           
     |   /   |   |   |   \   |   |   |   /   |   |   |   \   |   |   |   /   |   |         
        /        |        \      |      /        |        \      |      /        |
       /                   \           /                   \           /           
min ==(1)...................==========(1)...................==========(1)..........
                              *      *                        *     *               *
                                ***                             ***


Kdyz snizim frekvenci o polovinu, takze zmenim oktavu:
Kód:
                                                                 
max ........=========================(0)....................................===
           /                           \                                   /             
          /              |              \                |                /             
     |   /   |   |   |   |   |   |   |   \   |   |   |   |   |   |   |   /   |             
        /                |                \              |              /   
       /                                   \                           /   
min ==(1)...................................==========================(1)....

Tohle uz tezko budu slyset jako sinusovy ton:
Kód:
                                                                 
                       *****
                   *           * 
                *                 *
              *                     *                                         *
max ........=========================(0)....................................===
           /                           \                                   /             
          /              |              \                |                /             
     |   /   |   |   |   |   |   |   |   \   |   |   |   |   |   |   |   /   |             
        /                |                \              |              /   
       /                                   \                           /   
min ==(1)...................................==========================(1)....
                                              *                     *                           
                                                *                 *
                                                   *           * 
                                                       *****

A kdyz to jeste zpomalim na 1/50 vteriny tak uz zbude jen "lupani"...


Pokud to naopak 2x zrychlim tak uz bubinek taktak dosahne mezni polohy a uz ho budu posilat dolu:
Kód:
max ........==(0)...........==(0)...........==(0)...........==(0)...........==(0)...........==(0)...........=
           /   \           /   \           /   \           /   \           /   \           /   \           /             
          /  |  \    |    /  |  \    |    /  |  \    |    /  |  \    |    /  |  \    |    /  |  \    |    /             
     |   /   |   \   |   /   |   \   |   /   |   \   |   /   |   \   |   /   |   \   |   /   |   \   |   /             
        /    |    \  |  /    |    \  |  /    |    \  |  /    |    \  |  /    |    \  |  /    |    \  |  /   
       /           \   /           \   /           \   /           \   /           \   /           \   /     
min ==(1)...........==(1)...........==(1)...........==(1)...........==(1)...........==(1)...........==(1)....


A kdyz to jeste 2x zrychlim tak uz to bubinek nestihne:
Kód:
max ..........................................................................................................

          (0)     (0)     (0)     (0)     (0)     (0)     (0)     (0)     (0)     (0)     (0)     (0)     (0)   
          / \     / \     / \     / \     / \     / \     / \     / \     / \     / \     / \     / \     / \             
         /   \   /   \   /   \   /   \   /   \   /   \   /   \   /   \   /   \   /   \   /   \   /   \   /   \ 
        /     \ /     \ /     \ /     \ /     \ /     \ /     \ /     \ /     \ /     \ /     \ /     \ /     \ /
min ==(1).....(1).....(1).....(1).....(1).....(1).....(1).....(1).....(1).....(1).....(1).....(1).....(1).....(1)


Lepsi by bylo asi to drzet uprostred, ale bez jakekoliv zpetne vazby a s tim ze kazdy bubinek bude mit jinou "kvalitu",
a navic 40+ let k dobru toho tezkko pujde dosahnout...
Kód:
max ..........................................................................................................

          (0)     (0)     (0)     (0)     (0)     (0)     (0)     (0)     (0)     (0)     (0)     (0)     (0)   
          / \     / \     / \     / \     / \     / \     / \     / \     / \     / \     / \     / \     / \             
         /   \   /   \   /   \   /   \   /   \   /   \   /   \   /   \   /   \   /   \   /   \   /   \   /   \ 
        /     \ /     \ /     \ /     \ /     \ /     \ /     \ /     \ /     \ /     \ /     \ /     \ /     \ /
       /      (1)     (1)     (1)     (1)     (1)     (1)     (1)     (1)     (1)     (1)     (1)     (1)     (1)
min =(1).......................................................................................................


Timhle zpusobem by asi bylo mozne ztisit ton??? Nebo by to byl jiny (ale tizsi) zvuk?:
Kód:
max ........==(0)...........==(0)...........==(0)...........==(0)...........==(0)...........==(0)...........=
           /   \           /   \           /   \           /   \           /   \           /   \           /             
          /  |  \    |    /  |  \    |    /  |  \    |    /  |  \    |    /  |  \    |    /  |  \    |    /             
     |   /   |   \   |   /   |   \   |   /   |   \   |   /   |   \   |   /   |   \   |   /   |   \   |   /             
        /    |    \  |  /    |    \  |  /    |    \  |  /    |    \  |  /    |    \  |  /    |    \  |  /   
       /           \   /           \   /           \   /           \   /           \   /           \   /     
min ==(1)...........==(1)...........==(1)...........==(1)...........==(1)...........==(1)...........==(1)....

max ..........................................................................................................

            (0)             (0)             (0)             (0)             (0)             (0)             (0) 
      |     / \      |      / \      |      / \      |      / \      |      / \      |      / \      |      / \     
           /   \           /   \           /   \           /   \           /   \           /   \           /   
          /     \         /     \         /     \         /     \         /     \         /     \         /   
min =====(1).....========(1).... ========(1).....========(1).... ========(1).....========(1).... ========(1)...


Tudy asi snadna cesta nevede, a nikde jsem nevidel informaci jak dlouho cca taktu trva bubinku dosahnout z klidove minimalni polohy do maximalni.
A to se bude asi jeste lisit, kdyz uz v pohybu a ten pohyb taky nemusi byt konstantni kdyz ho budu bombardovat nejakou serii jednicek a nul.

A tohle je jen "konstantni" vlna a kdyz uderim do klaviru tak by to nevypadalo jako cirkularka, ale ten prubeh by byl uplne jiny s postupnym odeznenim.

Viz https://www.onlinepianist.com/virtual-piano


A to jeste stale resim jediny ton... natoz 2 a vice.

Pokud bych chtel nejaky obecny prubeh vlny tak musim bud nejak rychle menit 0 a 1 a nebo na to jit jeste jinak.


Tady je dost pekny clanek popisujici historii na ZX Spectru:
https://www.gamejournal.it/the-sound-of-1-bit-technical-constraint-as-a-driver-for-musical-creativity-on-the-48k-sinclair-zx-spectrum/


A uz u te casti kde Matthew Smith psal 2 tony pro Manic Miner jsem to moc nepochopil.
Krome toho ze to byl SKOLAK a psal to v roce 1983, kdy bylo tezke ziskat nejake informace a jeste na VYPUJCENY pocitac.
Nejsem si ani jisty zda je to fakt clovek (nebo ja .)).


Popisuji tam techniku co objevil co ma vydavat dva tony:

Rozebrání Smithova kódu v paměti RAM odhaluje, že jako základ rutiny titulní hudby používal impulsní vlaky.
(??? https://www.dsprelated.com/freebooks/sasp/Impulse_Trains.html)
Hudba byla uložena v paměti jako série 95 skupin, z nichž každá obsahovala tři datové bajty. Každá trojice odpovídá samostatnému rytmu (nebo subrytmu) v uspořádání a každá je zakódována jako doba trvání a dvojice hodnot výšky tónu, nebo přesněji jako hodnoty čítače, které se používají k výpočtu doby mezi postupnými impulsy pomocí techniky známé jako frekvenční dělič, nebo k dělení syntézy (Silnice 1996, str. 925).

Tato technika generuje vlnovou křivku počítáním pulsů hlavních hodin a spuštěním impulsu, když je dosaženo zvoleného dělitele (počítací hranice). Počítadlo se pak resetuje a začne znovu. To generuje periodický impulsní vlak o frekvenci, kterou lze vypočítat takto:

sample frequency
----------------
counter limit

Přeskupením rovnice lze vypočítat limit počitadla, který odpovídá dané frekvenci. V případě Manic Miner je čítač aktualizován v každém cyklu podprogramu theme-music, a tak je načasování každého hlavního taktu určeno dvěma faktory: hodinovou rychlostí procesoru Z80, který běží na 3,5 MHz, a délkou času, který procesor potřebuje k vykonání jednotlivých instrukcí stroje ve smyčce, kterou lze získat experimentálně. Smith tak dokázal sestavit frekvenční tabulku, která mapovala noty hudebního uspořádání na řadu čítačových hodnot a právě tyto hodnoty poskytují notová data pro jeho rutinu.

Smithova hudební rutina využívá dvě počítadla pro výpočet dvou současně jedoucích impulsních vlaků.

(zase Impulse Trains)
Rutina zapíše dvě hodnoty čítače uložené v datových trojicích do dvou paměťových registrů a vypočítá dobu mezi po sobě jdoucími impulsy, přičemž při přehrávání efektivně propojí oba impulsní vlaky a vytvoří dva kanály přehrávání. Pro jednotlivé melodické noty Smith zakódoval výšku tónu jako dvojici hodnot čítačů oddělených jedničkou, aby vytvořil fázovací efekt. Akordy jsou zakódovány jako dvě odlišné frekvenční hodnoty. Fázovací efekt funguje dobře, vytváří harmonicky bohatý, časově proměnlivý tón na jednotlivé noty s charakteristickým efektem zametání na rytmické frekvenci. Pokud je však efekt použit k vyvolání dvou souběžných odlišných výšek tónu, rutina zavádí stupeň nejednoznačnosti výšky tónu, který vyplývá z relativních amplitud harmonických jednotlivých tónů.

Jak je uvedeno výše, jednotlivé noty jsou kódovány jako dvojice hodnot čítačů oddělených jednou jednotkou, což má za následek vytvoření dvou binárních impulsních vláčků oddělených ve frekvenci pouze několika hertzy. Výsledkem je frekvenční spektrum, které se velmi blíží harmonické řadě, jak je znázorněno na obrázku 8.

Příloha:
obrazek8.png
obrazek8.png [ 55.4 KiB | Zobrazeno 360 krát ]

Obrázek 8: Spektrální graf dvou téměř shodných impulsních vlaků ukazuje pseudoharmonickou řadu, i když shoda mezi harmonickými tóny spodního tónu, ilustrovaná tmavými pásy, a horním tónem, ilustrovaná světlejšími pásy, klesá se zvyšující se frekvencí. Tento harmonický charakter usnadňuje identifikaci jednoznačného smyslu výšky tónu.

Když se dva impulsní vlaky prolínají v odlišných kmitočtech, toto pseudo- harmonické spektrum se rozpadá, jak ukazuje obrázek 9 níže. Tento spektrální graf ilustruje hlavní třetí interval. Stejně jako dříve, tmavé pásy odpovídají harmonické dolní tón v intervalu, a světelné pásy do harmonické horního tónu. Okamžitě je vidět, že tyto frekvenční složky nemají žádnou pravidelnou strukturu. Rozestupy mezi spektrálními složkami jsou variabilní a zahrnují řadu velmi těsně seskupených složek, což přináší nepříjemné bití do tónu. Také proto, že každá z harmonických jednotlivých tónů má stejnou velikost, jeden z klíčových zvukových podnětů, které běžně používáme k lokalizaci a identifikaci výšky tónu, základní, který je obvykle nejsilnější z těchto frekvenčních složek, není patrný. Každá frekvenční složka se tedy libovolně stává dominantní, protože ucho se soustředí do různých oblastí, což vytváří velmi vágní a nezřetelný pocit výšky tónu. Celkovým efektem je vytvořit v posluchači pocit drsného, komplexního tónu, spíše než dvou diskrétních a odlišných tónů.

Příloha:
obrazek9.png
obrazek9.png [ 60.7 KiB | Zobrazeno 360 krát ]

Obrázek 9: Spektrální graf dvou nekolísajících impulsních vlaků ukazuje složitější vztah. Existuje variabilita v rozestupech mezi komponenty a některé shlukování, což vede k bití. Jednotná velikost komponent velmi ztěžuje identifikaci diskrétních výšek.

Smithův přístup byl tedy inovativní a do jisté míry velmi účinný. Podařilo se mu přejít od implikující polyfonie na makro úrovni, manipulací s časovým uspořádáním poměrně rozsáhlých zvukových zrn, k implikující ji na mikro úrovni prokládáním impulsů, nejmenších jednotek binárního zvuku. Tím se hudba ZX Spectrum dostala na podobné území, jaké zkoumali průkopníci elektronické hudby jako Pete Samson, jehož práce s počítačovými systémy MIT TX-0 a PDP-1 zkoumala podobné metody o nějakých dvacet let dříve (Levy, 2010, s. 17-18), a navrhla směr, kterým by další vývojáři mohli pokračovat v inovacích.


_________________
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.06.2023, 20:06 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Ze stejneho zdroje:

Modulace šířky pulzu (PWM)
--------------------------

V roce 1984 se Zombie Zombie (White & Sutherland, 1984) od Quicksilvy stala první Speccy hrou, která řešila selhání dvoukanálové rutiny Manic Miner a pomocí pulzní modulace (PWM) ukotvila dva zcela nezávislé kanály laditelných čtvercových vln ze spektra. Jak již bylo zmíněno, posílání různých sekvencí jedniček a nul do beeeru umožňuje vytvořit řadu příbuzných tvarů vln, od vlaků binárních impulsů

(ehm... sekvence binarnich pulsů?)

až po pulsní vlny různého pracovního cyklu.

(ehm... asi neco jako dlouhy a kratky tyden... :D v originale je "pulse waves of varying duty cycle")

Tuto myšlenku lze posunout o krok dále návratem k myšlence setrvačnosti reproduktoru, což je představa, že kužel reproduktoru nemůže změnit svůj stav diskrétně a okamžitě. Při jízdě trvá krátký, ale konečný čas, než dosáhne maximálního posunu a musí se pohybovat všemi svými mezistavy mezi plným vypnutím a plným zapnutím. Reproduktor se chová podobným, i když ne identickým způsobem, když se vrací do klidu. Modulací šířky signálů (změnou doby, po kterou je reproduktor poháněn v poměru k době, po kterou není poháněn) může být reproduktor poháněn do mezibodů mezi vypnutím a zapnutím, čímž se simuluje účinek spojitého analogového napětí. Existuje, jak si asi umíte představit, mnoho způsobů, jak toho dosáhnout, ale nejběžnější metodou pro Spektrum bylo použití předem vypočtených vyhledávacích tabulek pro převod notových kmitočtů na hodnoty čítačů, které by mohly být uloženy v paměti a použity k syntéze pulzních vlaků podobným způsobem jako binární impulsní vlaky diskutované dříve. Pomocí této formy PWM, by mohl být reproduktor kužel k tanci ve velmi propracované způsoby vytvořit velmi složité vícehlasé skladby. Tento proces však zcela svázal CPU, což znamenalo, že efekt byl možný pouze pro titulní obrazovku a přestávky v hraní.

Zvuková rutina v Zombie Zombie generuje dva kanály zvuku bez jakékoli hlasitosti nebo timbrálního ovládání a je založena na osmém notovém kvantifikačním schématu, s delšími notami, které se skládají z více osmých tónů ve stejné výšce tónu a spouštějí se postupně. Hra obsahuje tři hlavní hudební sekvence. První z nich je triumfální, pochodové nastudování Deseti zelených lahví, které se v taktu 9 proměňuje v zneklidňující aranžmá v paralelně rozšířených čtvrtkách, odkaz na běžný hororový soundtrack osmdesátých let z nafouklé dětské písničky nebo dětské říkanky. Hra také obsahuje jednoduché, ale triumfální uspořádání Bizetova Pochodu toreadorů po dokončení hry a skladbu, která kombinuje Whiteovu dvoukanálovou rutinu s naznačenou polyfonní technikou popsanou v sekci 4, kombinující basy a jednoduchý arpeggizovaný doprovod, který vytváří sugesci tří simultánních hlasů.


Radsi sem hodim odkaz:
phpBB [video]



Poté, co založil PWM jako životaschopný přístup k tvorbě hudby na Spectrum, některé hry aplikovat techniku s různou mírou úspěchu, zatímco Melbourne House Wham! Music Box (Alexander, 1985), poměrně sofistikovaný hudební sekvencer a perkusní syntetizér poskytl uživatelům snadno použitelné grafické rozhraní, které by bylo známé uživatelům většiny digitálních audio pracovních stanic dnes. Pager Spectrumu však měl ještě co nabídnout a byl to Tim Follin, mladý programátor ze St. Helens na severozápadě Anglie, kdo si PWM opravdu oblíbil a posunul Spectrum a jeho 1-bitový hlas na zcela novou úroveň. Follin vyvinul svou zvukovou sestavu na svých nejranějších titulech Subterranean Stryker (Follin, 1985), Star Firebirds (Follin et al, 1985a) a Vectron (Follin et al, 1985b), takže v roce 1986 s Agentem X, jak jeho charakteristický zvuk, tak jeho technické provedení, které dosáhlo počtu kanálů pět, spolu s bicími, obálkováním, portamento a phasing, byly již velmi dobře vyvinuté. To se však stalo na úkor věrnosti zvuku.

Follinovy nejranější soundtracky zpětně ukazují postupný vývoj jak jeho zvukového motoru, tak jeho vznikajícího hudebního stylu. Soundtrack k jeho první hře Spectrum Subterranean Stryker je zajímavý jen do té míry, že demonstruje některé rodící se schopnosti jeho motoru. Obsahuje jednokanálovou melodickou linku, která se pohybuje stylisticky a s pramalou melodickou koherencí, což je možná programový ekvivalent kytaristy noodling na fretboardu. Pod notami je však slyšet amplitudové zahalování, což není zdaleka triviální úkol na reproduktoru, který může být pouze zapnutý nebo vypnutý, a fázovací efekt, který vytváří dynamicky se měnící zabarvení, což jsou oba rysy, které by Follin nadále rozvíjel. Pro svůj další titul, Star Firebirds, Follin představil portamento efekt, který místy vytvořil docela dramatické Emersonské výškové plachty, ale byl to Vectron, 3D hra s bludištěm inspirovaná sekvencí Space Paranoids z Disneyho Tronu (Lisberger, 1982), kde jak engine, tak Follinův hudební styl opravdu začínají prosvítat. Soundtrack ve Vectronu zvládá během přehrávání tři nezávislé hlasy a začíná fázovaným, obaleným synthem vedoucím k elektronické fanfáře, než začne rychlý bluesový riff, ne nepodobný perkusním varhanním linkám Keitha Emersona a Ricka Wakemana. Skladba pak porušuje styl, přímo odkazuje na původní partituru Wendy Carlosové z Trona, než se vrátí k sérii sekvencí v bluesovém měřítku.

Follin publikoval svou tříkanálovou hudební sestavu jako hexadecimální typový program v časopise Your Sinclair (Follin, 1987), čímž ji volně zpřístupnil pro použití v nekomerčních programech. Výpis obsahuje pouhých 167 řádků kódu a celá sestava, doplněná o data poznámek, váží něco přes 1K. Článek poznamenal, že v té době Follin pracoval na nové šestikanálové sestavě se sborem, basy, echo, portamento a plným ADSR, což jsou všechny prvky, které se objeví v jeho pozdějších soundtrackech, jak se jeho komerční engine bude dále vyvíjet.

V roce 1986, s vydáním Agenta X, Follin zvýšil počet kanálů na 5, i když to bylo na úkor určité audio věrnosti. S procesorem posunutým na hranici svých možností je hudba velmi lo-fi, což Follin uznal v rozhovoru pro Eurogamer, když poznamenal, že „Je těžké skutečně slyšet [hudbu v Agent X], myslím, že jsem procesor ve skutečnosti posunul příliš daleko!“. Follinův motor Agent X funguje tak, že využívá pět registrů Z80, sekcí RAM uvnitř hlavního procesoru, které mohou být použity k ukládání a rychlému provozu na často používaných datech, prioritních oblastí paměti, které umožňují procesoru rychlý přístup, ve smyčce, z nichž všechny odpočítávají od řady předem určených hodnot k nule. Když je každá smyčka kompletní, generuje puls, jehož šířka určuje úroveň reproduktoru. Neustále se měnící šířky pulsů ovlivňují jak hladinu, tak zabarvení, a přidávají šum v tom smyslu, že měnící se obsah harmonických tónů vnáší do zvuku nežádoucí drsnost a způsobuje problémy s laděním, jak počet kanálů stoupá.


Koukam ze tam moc o PWM neni takze:
Příloha:
Delta_PWM.png
Delta_PWM.png [ 83.86 KiB | Zobrazeno 360 krát ]


Tady je docela krasne videt cca jak se to provadi (aspon princip), s tim ze ten rust i klesani neni uplne stejne.

_________________
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.06.2023, 20:13 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
A jak jsem tvrdil ze to posila opakovane 0 je videt tady:
Kód:
;*********************************************************************************************
if (low($))!=0
    org 256*(1+(high($)))
endif
;   iiii dd, ss         ; b:tt      ...
core0:                  ;           volume 0, 0t
basec equ high($)
    ;----------------- ;[  :0]
    dw OUT_C_0x00       ; 2:12      switch sound off
   
    ld   HL,(addBuffer) ; 3:16      get ch1 accu
    pop  BC             ; 1:10      get ch1 base freq
    add  HL, BC         ; 1:11      add them up
    ld (addBuffer),HL   ; 3:16      store ch1 accu
    rl    H             ; 2:8       rotate bit 7 into volume accu
    rla                 ; 1:4       ...
   
    ld  HL,(addBuffer+2); 3:16      as above, for ch2
    pop  BC             ; 1:10
    add  HL, BC         ; 1:11
    ld  (addBuffer+2),HL; 3:16      store ch2 accu
    rl    H             ; 2:8       ...
    adc   A, 0x00       ; 2:7       ...
   
    ld  HL,(addBuffer+4); 3:16      as above for ch3
   
    ld    C, 0xFE       ; 2:7       ...
    ds 3            ;12
   
    ret   c             ; 1:5       timing, branch never taken
    ld    B, PCTRL_B    ; 2:7       B = 0x10
    ;----------------- ;[  :192]
   
    dw OUT_C_0x00       ; 2:12      switch sound off
   
    pop  BC             ; 1:10
    add  HL, BC         ; 1:11
    ld  (addBuffer+4),HL; 3:16      store ch3 accu
    rl    H             ; 2:8       ...
    adc   A, 0x00       ; 2:7       ...

;   iiii dd, ss         ; b:tt      ...
    ex   DE, HL         ; 1:4       DE is ch4 accu
    pop  BC             ; 1:10      add base freq as usual
    add  HL, BC         ; 1:11
    ex   DE, HL         ; 1:4       ...
    ld    B, D          ; 1:4       get bit 7 of ch4 accu without modifying the accu itself
    rl    B             ; 2:8       ...
    adc   A, 0x00       ; 2:7       ...
   
    exx                 ; 1:4       ...

    pop  BC             ; 1:10      get base freq ch5
    add  HL, BC         ; 1:11      HL' is ch5 accu
    ld    B, H          ; 1:4       ...
    rl    B             ; 2:8       ...
       
    ld    R, A          ; 1:9       timing
    ld   BC, PCTRL      ; 3:10      0x10fe
    ;----------------- ;[  :168]

    dw OUT_C_0x00       ; 2:12      switch sound off

    adc   A, 0x00       ; 2:7       ...
    ret   c             ; 1:5/11    timing
    ;----------------- ;[  :192]
   
    dw OUT_C_0x00       ; 2:12      switch sound off
   
    ex   DE, HL         ; 1:4       DE' is accu ch6
    pop  BC             ; 1:10
    add  HL, BC         ; 1:11
    ld    B, H          ; 1:4       ...
    rl    B             ; 2:8       ...
    adc   A, 0x00       ; 2:7       ...
    ex   DE, HL         ; 1:4       ...
   
    pop  BC             ; 1:10
    add  IX, BC         ; 2:15      IX is accu ch7
    ld    B, IXH        ; 2:8       ...
    rl    B             ; 2:8       ...
    adc   A, 0x00       ; 2:7       ...
    ret   c             ; 1:5/11    timing
   
    pop  BC             ; 1:10   
    add  IY, BC         ; 2:15      IY is accu ch8   
    ld    B, IYH        ; 2:8       ...
    rl    B             ; 2:8       ...
   
    exx                 ; 1:4       ...
    ld   BC, PCTRL      ; 3:10      0x10fe
    ;----------------- ;[  :168]
   
    dw OUT_C_0x00       ; 2:12      switch sound off
   
    ex   AF, AF'        ; 1:4
    dec   A             ; 1:4
    ex   AF, AF'        ; 1:4
    ;----------------- ;[  :192]
   
    dw OUT_C_0x00       ; 2:12      switch sound off
   
;   iiii dd, ss         ; b:tt      ...
    adc   A, 0x00       ; 2:7       ...

    ld   HL,-16         ; 3:10      point SP to beginning of pattern row again
    add  HL, SP         ; 1:11      ...
    ld   SP, HL         ; 1:6       ...
    add   A, basec      ; 2:7       calculate which core to use for next frame
    ld    H, A          ; 1:4       and put the value in HL
    xor   A             ; 1:4       also reset volume accu
    ld    L, A          ; 1:4       ...
   
    ex  (SP),HL         ; 1:19      timing
    ex  (SP),HL         ; 1:19      timing
   
    ex   AF, AF'        ; 1:4       check if timer has expired
    dec   A             ; 1:4
    jp    z,updateTimer ; 3:10      and update if necessary
    ret   z             ; 1:5/11    timing
    ex   AF, AF'        ; 1:4
   
    ex  (SP),HL         ; 1:19      timing
    ex  (SP),HL         ; 1:19      timing
    ;----------------- ;[  :168]

    dw OUT_C_0x00       ; 2:12      switch sound off
       
    ds 2                ; 2:8       timing
    jp  (HL)            ; 1:4       jump to next frame
    ;----------------- ;[  :192]


V originale je trosku jiny popisek:
Kód:
;*********************************************************************************************
IF (LOW($))!=0
   org 256*(1+(HIGH($)))
ENDIF

core0                  ;volume 0, 0t
basec equ HIGH($)

   dw OUTLO      ;12__      ;switch sound on

   ld hl,(addBuffer)   ;16      ;get ch1 accu
   pop bc         ;10      ;get ch1 base freq
   add hl,bc      ;11      ;add them up
   ld (addBuffer),hl   ;16      ;store ch1 accu
   rl h         ;8      ;rotate bit 7 into volume accu
   rla         ;4
   
   ld hl,(addBuffer+2)   ;16      ;as above, for ch2
   pop bc         ;10
   add hl,bc      ;11
   ld (addBuffer+2),hl   ;16
   rl h         ;8
   adc a,0         ;7
   
   ld hl,(addBuffer+4)   ;16      ;as above for ch3
   
   ld c,#fe      ;7
   ds 3         ;12
   
   ret c         ;5      ;timing, branch never taken
   ld b,PCTRL_B      ;7      ;B = #10
   ;------------------   ;--192
   
   dw OUTLO      ;12__      ;sound on
   
   pop bc         ;10
   add hl,bc      ;11
   ld (addBuffer+4),hl   ;16
   rl h         ;8
   adc a,0         ;7

   ex de,hl      ;4      ;DE is ch4 accu
   pop bc         ;10      ;add base freq as usual
   add hl,bc      ;11
   ex de,hl      ;4
   ld b,d         ;4      ;get bit 7 of ch4 accu without modifying the accu itself
   rl b         ;8
   adc a,0         ;7
   
   exx         ;4

   pop bc         ;10      ;get base freq ch5
   add hl,bc      ;11      ;HL' is ch5 accu
   ld b,h         ;4
   rl b         ;8
      
   ld r,a         ;9      ;timing
   ld bc,PCTRL      ;10
   dw OUTLO      ;12__168

   adc a,0         ;7
   ret c         ;5      ;timing
   ;-----------------   ;--192
   
   dw OUTLO      ;12__
   
   ex de,hl      ;4      ;DE' is accu ch6
   pop bc         ;10
   add hl,bc      ;11
   ld b,h         ;4
   rl b         ;8
   adc a,0         ;7
   ex de,hl      ;4
   
   pop bc         ;10
   add ix,bc      ;15      ;IX is accu ch7
   ld b,ixh      ;8
   rl b         ;8
   adc a,0         ;7
   ret c         ;5      ;timing
   
   pop bc         ;10   
   add iy,bc      ;15      ;IY is accu ch8   
   ld b,iyh      ;8
   rl b         ;8
   
   exx         ;4
   ld bc,PCTRL      ;10
   dw OUTLO      ;12__168
   
   ex af,af'      ;4
   dec a         ;4
   ex af,af'      ;4
   ;-----------------   ;--192
   
   dw OUTLO      ;12__
   
   adc a,0         ;7

   ld hl,-16      ;10      ;point SP to beginning of pattern row again
   add hl,sp      ;11
   ld sp,hl      ;6
   add a,basec      ;7      ;calculate which core to use for next frame
   ld h,a         ;4      ;and put the value in HL
   xor a         ;4      ;also reset volume accu
   ld l,a         ;4
   
   ex (sp),hl      ;19      ;timing
   ex (sp),hl      ;19      ;timing
   
   ex af,af'      ;4      ;check if timer has expired
   dec a         ;4
   jp z,updateTimer   ;10      ;and update if necessary
   ret z         ;5      ;timing
   ex af,af'      ;4
   
   ex (sp),hl      ;19      ;timing
   ex (sp),hl      ;19      ;timing

   dw OUTLO      ;12__168
      
   ds 2         ;8      ;timing
   jp (hl)         ;4      ;jump to next frame
   ;-----------------   ;--192

Tam zacina ze zvuk se zapina tim poslanim nuly.
To bude odvisle co tam bylo predtim...
Ja to upravil ze 0 je OFF a 1 ON.
Je to jako DW protoze PASMO neumi "in (c),0x00".
Pro "in (c),b" co ma stejne takty a tim vetsinou posila "1", ale nekdy netusim co je v B.
Je to taky jako "dw", nechal jsem to tak protoze me to KWRITE barevne zvyraznuje.
Tady posila jen same 1.
Kód:
;*********************************************************************************************
    org 256*(1+(high($)))
;   iiii dd, ss         ; b:tt      ...
core8:                  ;           vol 8 - 192t
    ;+++++++++++++++++ ;[  :0]
    dw OUT_C_B          ; 2:12      switch sound on

    ld   HL,(addBuffer) ; 3:16      get ch1 accu
    pop  BC             ; 1:10      get ch1 base freq
    add  HL, BC         ; 1:11      add them up
    ld (addBuffer),HL   ; 3:16      store ch1 accu
    rl    H             ; 2:8       rotate bit 7 into volume accu
    rla                 ; 1:4       ...
   
    ld  HL,(addBuffer+2); 3:16      as above, for ch2
    pop  BC             ; 1:10
    add  HL, BC         ; 1:11
    ld  (addBuffer+2),HL; 3:16      store ch2 accu
    rl    H             ; 2:8       rotate bit 7 into volume accu
    adc   A, 0x00       ; 2:7       ...
   
    ld  HL,(addBuffer+4); 3:16      as above for ch3
   
    ld    C, 0xFE       ; 2:7       ...
    ds 3                ; 3:12      timing   
    ret   c             ; 1:5       timing, branch never taken
   
    ld    B, PCTRL_B    ; 2:7       B = 0x10
    ;+++++++++++++++++ ;[36:192]
   
    dw OUT_C_B          ; 2:12      switch sound on
    pop  BC             ; 1:10
    add  HL, BC         ; 1:11
    ld  (addBuffer+4),HL; 3:16      store ch3 accu
    rl    H             ; 2:8       ...
    adc   A, 0x00       ; 2:7       ...

    ex   DE, HL         ; 1:4       DE is ch4 accu
    pop  BC             ; 1:10      add base freq as usual
    add  HL, BC         ; 1:11
    ex   DE, HL         ; 1:4       ...
    ld    B, D          ; 1:4       get bit 7 of ch4 accu without modifying the accu itself
    rl    B             ; 2:8       ...
    adc   A, 0x00       ; 2:7       ...
   
    exx                 ; 1:4       ...

    pop  BC             ; 1:10      get base freq ch5
    add  HL, BC         ; 1:11      HL' is ch5 accu
    ld    B, H          ; 1:4       ...
    rl    B             ; 2:8       ...
       
    ld    R, A          ; 1:9       timing
    ld   BC, PCTRL      ; 3:10      0x10fe
    ;+++++++++++++++++ ;[30:168]
    dw OUT_C_B          ; 2:12      switch sound on

    adc   A, 0x00       ; 2:7       ...
    ret   c             ; 1:5/11    timing
    ;+++++++++++++++++ ;[35:192]
   
    dw OUT_C_B          ; 2:12      switch sound on
   
    ex   DE, HL         ; 1:4       DE' is accu ch6
    pop  BC             ; 1:10
    add  HL, BC         ; 1:11
    ld    B, H          ; 1:4       ...
    rl    B             ; 2:8       ...
    adc   A, 0x00       ; 2:7       ...
    ex   DE, HL         ; 1:4       ...
   
    pop  BC             ; 1:10
    add  IX, BC         ; 2:15      IX is accu ch7
    ld    B, IXH        ; 2:8       ...
    rl    B             ; 2:8       ...
    adc   A, 0x00       ; 2:7       ...
    ret   c             ; 1:5/11    timing
   
    pop  BC             ; 1:10   
    add  IY, BC         ; 2:15      IY is accu ch8   
    ld    B, IYH        ; 2:8       ...
    rl    B             ; 2:8       ...
   
    exx                 ; 1:4       ...
    ld   BC, PCTRL      ; 3:10      0x10fe
    ;+++++++++++++++++ ;[32:168]
    dw OUT_C_B          ; 2:12      switch sound on
   
    ex   AF, AF'        ; 1:4
    dec   A             ; 1:4
    ex   AF, AF'        ; 1:4
    ;+++++++++++++++++ ;[37:192]
    dw OUT_C_B          ; 2:12      switch sound on
   
    adc   A, 0x00       ; 2:7       ...

    ld   HL,-16         ; 3:10      point SP to beginning of pattern row again
    add  HL, SP         ; 1:11      ...
    ld   SP, HL         ; 1:6       ...
    add   A, basec      ; 2:7       calculate which core to use for next frame
    ld    H, A          ; 1:4       and put the value in HL
    xor   A             ; 1:4       also reset volume accu
    ld    L, A          ; 1:4       ...
   
    ex  (SP),HL         ; 1:19      timing
    ex  (SP),HL         ; 1:19      timing
   
    ex   AF, AF'        ; 1:4       check if timer has expired
    dec   A             ; 1:4
    jp    z,updateTimer ; 3:10      and update if necessary
    ret   z             ; 1:5/11    timing
    ex   AF, AF'        ; 1:4
   
    ex  (SP),HL         ; 1:19      timing
    ex  (SP),HL         ; 1:19      timing
    ;+++++++++++++++++ ;[25:168]
    dw OUT_C_B          ; 2:12      switch sound on
       
    ds 2                ; 2:8       timing
    jp  (HL)            ; 1:4       jump to next frame
    ;. . . . . . . . . ;[30:192]

Ostatni "core" jsou v nejakem pomeru:

core0: 0-168-192 ale same nuly
core1: 0-24-192 prvni interval 0..24 je 1 a 24..192 je nula
core2: 0-48-192 1,0
core3: 0-72-192 1,0
core4: 0-96-192 1,0
core5: 0-120-192 1,0
core6 0-144-192 1,0
core7: 0-168-192 1,0 a pak se to opakuje ale uz nevim jiste zda tam je 1
core8: 0-168-192 same 1

Tak pokud to chapu tak core0 a core8 se mohlo napsat jinak, jestli opakovany zapis stejne hodnoty nema vliv.

PS: Jinak ten kod je hodne brutalni a pouziva i register R a I. To druhe me dost vadi protoze me velke I rozbaluje makro jako index smycky... Takze jsem to musel vsude obalovat do {I}.
PPS: A taky pouzival IX a IY a ja pak resil proc me to nekdy nezalamuje radek... .))) Nez jsem zjistil ze znicil ukazatel na promenne ROMky.
PPPS: A jeste ke vsemu me i po osetreni nefungovalo v basicu mereni rychlosti. Ale jen do chvile nez me doslo ze to bezi celou dobu s vyplym prerusenim,,, .)))

_________________
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 ... 29, 30, 31, 32, 33, 34, 35 ... 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 5 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