Diskuze o textových hrách

Assembler z80

Lisiak4

  • Host
Ahoj,

Vše co napíšu může být blbost, nejsem v pozici, kdy můžu radit. Ja se jen tak ze zajímavosti trochu koukal na assembler procesoru MHB8080A co je kopie Intelu 8080A a Z80 je vylepšená 8080ka viz info z wikipedie. Zilog Z80 je osmibitový mikroprocesor, který vyráběla firma Zilog od roku 1976. Jednalo se o funkční zdokonalení procesoru Intel 8080. Struktura registrů i instrukční sada vycházely z architektury procesoru Intel 8080 a až na drobnosti byly zpětně kompatibilní. V tabulce instrukci pro 8080ku se píše:

A - akumulátor
B - register B alebo registrový pár BC
C - register C
D - register D alebo registrový pár DE
E - register E
H - register H alebo registrový pár HL
L - register L

Tím narážím na to, že se tváří, jakoby A jak ty píšeš registr, zde se píše Akumulátor nebylo to samé jako B,C,D,E,H,L
Podprogram v pameti RAM pro počítač PMD používa Akumulátor na vyťištení znaku. Nevím, jestli tuhle funkci múže dělat i register B,C .... proto je tam možna to přesouvání, ale jsou to jen domněnky. Snažím se jen pomoci, jak tomu jako absolutní amatér koukajíci do toho asi 5 dní rozumím já. Další můj postřeh (možná mylnej) je ten, že v Assemblery se používa dle mě jen hexadecimálni soustava. Tím narážím na to, že například číslo 22 by sme neměli chápat jako 22 ale po přepočítání z hexadecimální soustavy nám to dá číslo 34. Jak říkam, vše co jsem napsal může být úplně špatně. Jsou to názory někoho, kdo do toho vůbec nevidi, jen jsem se snažil aspoň nejak pomoci. Vyzkoušel si v Assembleru pomoci nějakeho podprogramu něco jednoduchýho, aby Ti to fungovalo? Například vypsáni jednoho znaku? A pak nejakýho textu? Tohle se mi zdá být nejak složité na začátek :). V návodu na PMD je pár ukázek na využívání podprogramu assembleru na PMD, podprogram pro psani znaku i textu. Neni něco takového v návodu pro ZX?


zxretrosoft

  • Plný člen
  • ***
    • Příspěvků: 235
    • Zobrazit profil
    • zxretrosoft
Naopak, díky moc, tohle přesně potřebuju - člověka to hned nakopne k přemýšlení!  ;)

Pokud jde o ten akumulátor, mám za to, že akumulátor je zkrátka druh registru. Ano, stejně jako u PMD se registr A používá k vytištění znaku.
Hexadecimální soustava se používá v Prometheovi tak, že před číslo se dá znak #. Pokud je tedy číslo 22 uvedeno bez toho znaku, je to opravdu 22 v desítkové soustavě, muselo by být uvedeno jako #22.

Ta knížka je docela dobrá (asi nejlepší co mám k dispozici), ale taky mi připadá, že příklady na začátek jsou příliš složité a (viděno mýma očima laika) naprosto neprůhledné. Takové to šachování s registrama by chtělo nějak objasnit. Pokud mi někdo napíše, že nastavení barvy papíru je: ld a,c ... atd., pak musím vědět, proč zrovna obsah C přesouvá do A, k čemu je to dobré a proč se zrovna jako programátor musím rozhodnout, že obsah C přesunu do A. To přece není samo sebou - to musí mít nějaký důvod  :) Proto je spousta těch příkladů, které tento důvod neuvádějí, dost k ničemu, neboť je člověk (skoro jako vždy) odkázán na vlastní experimentování.

No, ale abych se vrátil k věci...

Znak jsem se pokusil vytisknout zjednodušeným algoritmem:

Kód: [Vybrat]
ent $
ld a,2
call #1601
ld a,"x"
rst 16
ret

Tenhle kód vytiskne znak "x" nahoru na obrazovku. Většina věcí v kódu se dělá automaticky: ent $ je startovací instrukce; ld a,2 se napsat musí pokaždý - do registru A musí přijít kanál 2, což supluje basicovský PRINT; call #1601 - o tom se zase nemusí přemýšlet, zkrátka zavolání podprogramu v ROM na adrese #1601=5633, aby se otevřel kanál a zobrazilo se to, co je obsahem A. Teď ale do toho registru A něco dáme a vystikneme pomocí rst 16, tedy ld a,"x" a rst 16. Nakonec jsem dal příkaz ret - nějak moc nevím sice proč, ale bez toho ret se to provede, ale nezůstane na obrazovce, takže je to asi věčná smyčka, která nám umožňuje vidět ten znak na obrazovce(?).

To je prosté vytištění jednoho znaku. Jednu věc na tom programu však nechápu - pokaždé, když se spustí, se vytištěný znak posune o 1 místo doprava, dojede-li na konec obrazovky, jede na další řádce zase zleva. Ačkoli není určená pozice, kvůli něčemu se to posouvá. A i kdybych věděl kvůli čemu, tak proč nezůstává "x" i na předchozím místě? Není zde ani CLS, a obsah registrů se v programu nikde nenuloval...?! Ale asi jsem vedle  :-\

Složitější případ jsem si vymyslel, když jsem chtěl umístit znak někam konkrétně na obrazovku (tedy jako v Basicu pomocí PRINT AT nebo LOCATE ... PRINT ap.).

K tomu by měl být funkční tehle kód:

Kód: [Vybrat]
ent$
ld a,2
call #1601
ld a,22
rst 16
ld a,14
rst 16
ld a,2
rst 16
ld a,"x"
rst 16
ret

Přibylo tu akorát na začátku ld a,22 - což by měl být podle knihy kód pro funkci AT, kde se nejprve zadává řádek a potom sloupec. Nevím ale pořád, proč za každým příkazem musím dělat rst 16 ? Když to vynechám, napíší se třeba před znak otazníky... Tím tedy docílím toho, že na řádek 2 a sloupec 16 dostanu znak "x".

Ještě si s tím zkusím pohrát, ale to je zatím všechno, co jsem z toho dostal - a ačkoli už se mi daří vytisknout znak, dokonce přesně ho lokalizovat a časem mu dát i jiné atributy, mám pocit, že je to všechno moc komplikované na to, že je to vlastně pořád to samé co v Basicu, akorát složitějším způsobem... Možná je to ale tím, že jsem úplně na začátku  ::)
Jedna stará textovka vydá za desítky dnešních nadutých her.


zxretrosoft

  • Plný člen
  • ***
    • Příspěvků: 235
    • Zobrazit profil
    • zxretrosoft
Tak myslím, že ta knížka Assembler a ZX Spectrum vypadá sice dobře, ale je pro daleko pokročilejší programátory. Snaží se sice hodně věcí objasnit od základu, ale příklady, které uvádí, jsou strašně komplikované a laik se v nich musí ztratit (mluvím za sebe, ale chtěl bych vidět, kdo by tohle na poprvé pochopil).

Když si vzpomenu na to, jak byly dělány ukázky v Basicu v každém časopise, tak přesně tak by měly být ukázky i z assembleru. To znamená: PRINT "x" udělá x na obrazovce, PRINT AT 1,1;"x" udělá na souřadnicích 1,1 x na obrazovce... Nikoliv: Tenhle program udělá x na obrazovce v šachovnici 8x8 podbarvené každý znak jinou barvou a to od 1 do 8 s barvou písma 1 do 8 invertovanou vůči barvě podkladu. Takový příklad je strašně složitý a když si představím, že bych ho udělal v Basicu, pak by to bylo taky dost složitý pro toho, kdo nikdy Basic neviděl.

To, co se udělalo tím příkladem s tiskem znaku, odpovídá přesně tomuto Basicovskému programu (v syntaktice ZX):

Kód: [Vybrat]
10 FOR i=0 to 7
20 PAPER i
30 FOR j=0 to 7
40 INK j
50 PRINT AT i,j;"@"
60 NEXT j
70 NEXT i

Posuďte sami, že to pro začátečníka není samozřejmé ani v tom Basicu - jsou to 2 cykly v sobě, změna barev i podkladu, představa jak to bude na obrazovce vyžaduje už určitý cvik...  :-\

V nějakém složitějším, moderním Basicu na PC (např. FreeBasicu), byste to už těžko dešifrovali - a to je pořád ještě Basic. Odpovídal by tomu řešení (alespoň zhruba) např. takovýhle prográmek:

Kód: [Vybrat]
dim as single i,j,k
screen 20,32,,0
cls
for i=0 to 7
for j=0 to 7
k=i*15
draw string$(j*10+16,i*10+16),"@",rgb(k,k+i*j*3,110)
next j
next i


Později jsem si zkoušel třeba i "jednoduchý" prográmek pro PLOT z téže knihy:

Kód: [Vybrat]
PLOT1 ld a,b
call #22B1
ld b,a
inc b
ld a,1
PLOT1A rrca
djnz PLOT1A
xor (hl)
ld (hl),a
ret

Tenhle prográmek udělá sice bod v jakési části obrazovky, pochybuji ale, že z toho vyčte někdo kde a proč. Instrukcí call #22B1 se má "vypočítat adresa a bit pro tento bod", to je sice hezké... ale...?? První nápad s instrukcí ld a,b je mi také nejasný - proč obsah registru B přesouvat do A, abych získal Y-ovou souřadnici? Jaká je tedy její hodnota? To co bylo v B? Ale kde jsem to B nastavil? Proč to nedat vlastně rovnou do A (tj. bez použití registru B, se kterým předtím stejně vůbec nepracuji)?...

Je toho víc, co mi přijde nepochopitelné, ale možná nejsem tak chytrý, nevím, těžko říct... Asi by mi pomohlo, kdyby existovalo víc jednodušších příkladů, které by byly ekvivalentní k Basicu - různé komplikovanosti a další možnosti už by si člověk experimentováním objevil. Ale chtělo by to zkrátka:

BASIC: PRINT AT 5,6;"x" -> ASSEMBLER: ld a,b ....
BASIC: BEEP 1,1 -> ASSEMBLER: ld a,b ....
BASIC: PLOT 100,20 -> ASSEMBLER: ld a,b ....

Jsem přesvědčen, že na neskonalé možnosti assembleru by si člověk musel přijít sám, stejně jako jsme si je odvodili tehdy z Basicu.

Co si o tom myslíte? Neznáte náhodou nějakou "lepší" knížku k assembleru? Bližší tomu, co jsem nastolil?  ::)
« Poslední změna: 11. Červenec 2010 - 14:55 od amigainspired »
Jedna stará textovka vydá za desítky dnešních nadutých her.


KaiN

  • Superčlen
  • *****
    • Příspěvků: 505
    • Zobrazit profil
Ještě k tomu prvnímu příkladu, ono už to tu víceméně nějak bylo rozlousknuto, tak to jen shrnu:

Já myslím, že jediný tvůj problém je, že nemáš zmapován ten "rst 16". Parametr se předává výhradně v registru A, nejprve se předá "co" se bude dělat. Např. "22" znamená "PRINT AT x,y", následně se přes registr A předá "x" a poté i "y". Registry B a C se v prográmku používají jako počítadla. B je přitom jako počítadlo u Z80 předpokládáno, proto např. existuje instrukce DJNZ loop2, která nejprve sníží registr B a pokud je výsledek nenulový, provede skok na loop. U C je třeba nejprve samostatně snížit C (dec C) a poté samostatně vyhodnotit výsledek operace pomocí "JR NZ loop".
RET znamená obecně návrat tam, odkud byla rutina volána. Pokud ji vyvoláš přímo z BASICU, vrátí se po vykonání na následující řádek resp. příkaz.


mop

  • Plný člen
  • ***
    • Příspěvků: 158
    • Zobrazit profil
Taky si myslím, že dokud nebudeš pořádně vědět, co dělá ta instrukce RST 16, tak ti tyhle příklady žádný užitek nepřinesou. Přiznám se, že považuju za docela nešťastný tenhle přístup k výuce assembleru, kdy se jako příklad použije kód, jehož podstatná část je tvořena instrukcemi CALL nebo RST, volajícími nějaké už existující rutiny v ROM nějakého konkrétního počítače. Z takového příkladu se v konečném důsledku stejně dopodrobna nedozvíš, co ten program vlastně vykonává.

Jestli trochu vládneš anglicky, tak rozhodně doporučuju tyhle stránky, kde na to autor jde přesně opačně:

http://sgate.emt.bme.hu/patai/publications/z80guide/

Myslím, že je to výborné čtivo na úplný začátek, pro pochopení samotné filozofie strojového jazyka. Ale tím, že je to tutoriál naprosto obecný, který se nezabývá specifiky nějakého konkrétního počítače, nenajdeš v něm odpovědi na své otázky týkající se ZX Spectra (jako třeba právě otázka, co dělá ta instrukce RST 16).

Já jsem si kdysi dávno něco málo psal pro počítač Sharp, takže s věcmi specifickými pro ZX poradit neumím, ale s otázkami týkajícími se obecně strojáku Z80 se můžu pokusit pomoct. Ale nevím, jestli je to ještě aktuální, jelikož tady už dva týdny žádná diskuse neběží.


zxretrosoft

  • Plný člen
  • ***
    • Příspěvků: 235
    • Zobrazit profil
    • zxretrosoft
jj, díky za odpověď! Určitě se na ty anglické stránky mrknu!  ;)

Aktuální to je pořád, akorát na programování nemám tolik času, je to přece jen moje zábava po práci, takže si tu a tam chci něco zkusit a něco pochopit. Assembler (alespoň na Z80) bych se rád naučil, ještě se do toho vrhnu a zkusím to s jiným tutoriálem.

V téhle diskuzi jsem se chtěl vlastně jen dopátrat, jak konkrétně zacházet s obrazovkou, v tomhle případě na začátek s textem, ale i když to v reálu nějak dokážu, nemůžu říct, že to chápu - a proto jsem tu diskuzi rozpoutal. Assembler Z80 se dnes člověk učí hlavně (či spíš jenom) kvůli tomu, aby to pochopil a měl z toho radost, ne proto, aby něco zplácal bezmyšlenkovitě dohromady (viz dnešní programování v C++ apod.  ;D ).

Každopádně ještě jednou díky za ten odkaz i odpověď, v nejbližší době se na to podrobněji podívám!  8)
« Poslední změna: 28. Červenec 2010 - 10:09 od amigainspired »
Jedna stará textovka vydá za desítky dnešních nadutých her.


mop

  • Plný člen
  • ***
    • Příspěvků: 158
    • Zobrazit profil
Nedalo mi to a stáhnul jsem si v pdf 1. díl té knihy Assembler a ZX Spectrum, kde je na str. 36 vysvětleno, jak je to vlastně s tím RST 16:

Citace
... Tisk znaku je zajišťován instrukcí rst 16 (volání podprogramu na adrese 16). Znak, který má být vytisknut, je uložen v registru a. ... Program umí tisknout všechny ASCII znaky, semigrafiku, UDG, klíčová slova a zpracovávat tyto řídící kódy:
6 - print COMMA (posune na další pozici - začátek nebo polovina řádku)
8 - cursor left (posune tiskovou pozici doleva)
9 - cursor right (posune tiskovou pozici doprava)
10 - cursor down (posune tiskovou pozici dolů)
11 - cursor up (posune tiskovou pozici nahoru)
13 - ENTER (přesune tiskovou pozici na začátek dalšího řádku)
16 - ink (ovládání barvy inkoustu - pošlete kód 16 a potom číslo 0-7)
17 - paper (ovládání barvy papíru - pošlete kód 17 a potom číslo 0-7)
18 - flash (ovládání blikání - pošlete kód 18 a potom číslo 0 nebo 1)
19 - bright (ovládání jasu - pošlete kód 19 a potom číslo 0 nebo 1)
20 - inverse (ovládání inverze - pošlete kód 20 a potom číslo 0 nebo 1)
21 - over (ovládání over - pošlete kód 21 a potom číslo 0 nebo 1)
22 - at (nastavení tiskové pozice - pošlete kód 22 a potom řádek a sloupec)
23 - tab (tabulátor - pošlete kód 23 a potom číslo rozložené do dvou bytů)

To je naprosto v souladu se známým faktem, že v ASCII tabulce začínají tisknutelné znaky až od č. 32, zatímco hodnoty 0 až 31 bývají využívány pro různé užitečné úkony, jako je třeba tabulátor, enter apod. (proto tomu říkají řídicí kódy). Takže v zásadě se dá říct, že sekvence instrukcí LD A,x a RST 16 dělá totéž, co příkaz PRINT CHR$(x) v basicu. Zkus třeba do basicu naťukat tohle:

Kód: [Vybrat]
10 LET A$="AHOJ"+CHR$(13)+"SVETE"
20 LET B$="HELLO"+CHR$(22)+CHR$(5)+CHR$(20)+"WORLD"
30 PRINT A$
40 PRINT B$

Když se podíváš, co to dělá, a dáš si to dohromady tady s tím seznamem řídicích kódů, tak ti to podle mě pomůže pochopit i leccos z těch dřívějších příkladů v assembleru.


zxretrosoft

  • Plný člen
  • ***
    • Příspěvků: 235
    • Zobrazit profil
    • zxretrosoft
Děkuju za ten příklad!  ;)

O tom "vysvětlení", jak je to s tím rst 16 jsem to četl, což o to, ale přece jen proč je umístěno rst 16 po každé instrukci, která odesílá nějaký údaj?

Např.:

Kód: [Vybrat]
ld a,22 'funkce AT
rst 16 '??
ld a,14 'číslo řádku
rst 16 '??
ld a,20 'číslo sloupce
rst 16 '??

Proč vlastně pořád volám tiskový podprogram?  ::)
A vůbec - nejde to nějak jednodušeji?  :)

Jen tak si představuji, že si zkouším něco s assemblerem - třeba náhodně na nějakou lokaci na obrazovce umístit barevnou hvězdičku. To mi při tomhle způsobu programování spolkne mnoho a mnoho instrukcí rst 16::)
« Poslední změna: 28. Červenec 2010 - 19:47 od amigainspired »
Jedna stará textovka vydá za desítky dnešních nadutých her.


mop

  • Plný člen
  • ***
    • Příspěvků: 158
    • Zobrazit profil
Ona ta instrukce LD A,x právě nikam nic neposílá. Ta jen nastaví registr A na nějakou hodnotu, a basta. A pak se teprve volá podprogram pro tisk znaku, který udělá všechnu práci a který je napsán tak, že hodnotu požadovaného znaku si bere právě z registru A.

Pokud jde o ty příklady, tak tam je to takhle mechanicky za sebou jen kvůli lepší přehlednosti. V reálu budeš mít ty data uložený někde v paměti hezky za sebou a jejich tisk bude řešený nějakým cyklem, takže ta instrukce bude v kódu napsaná jen jednou, i když budeš vypisovat dlouhé řetězce, různýma barvičkama atd.


zxretrosoft

  • Plný člen
  • ***
    • Příspěvků: 235
    • Zobrazit profil
    • zxretrosoft
Aha, dobře, díky moc, ještě si s tím zkusím pohrát!...  ;)
Jedna stará textovka vydá za desítky dnešních nadutých her.


zxretrosoft

  • Plný člen
  • ***
    • Příspěvků: 235
    • Zobrazit profil
    • zxretrosoft
Ona ta instrukce LD A,x právě nikam nic neposílá. Ta jen nastaví registr A na nějakou hodnotu, a basta. A pak se teprve volá podprogram pro tisk znaku, který udělá všechnu práci a který je napsán tak, že hodnotu požadovaného znaku si bere právě z registru A.

Pokud jde o ty příklady, tak tam je to takhle mechanicky za sebou jen kvůli lepší přehlednosti. V reálu budeš mít ty data uložený někde v paměti hezky za sebou a jejich tisk bude řešený nějakým cyklem, takže ta instrukce bude v kódu napsaná jen jednou, i když budeš vypisovat dlouhé řetězce, různýma barvičkama atd.

Dobře, tak ještě mě napadlo všechno moje snažení zjednodušit a směřovat to rovnou k nějaké té textovce...  :D

V Prometheovi jdou texty vypisovat pomocí defm, jestli jsem to dobře pochopil (podle Assembler a ZX Spectrum je to teda trochu kumšt). Kdybych chtěl udělat nějaký jednoduchý skok, který je v textovkách obvyklý, např.

  • Napíše se text.
  • Bliká kurzor pro input.
  • Jestliže S, pak skok na místnost na severu - další text, jinak hláška o špatném směru.

Dal by se tenhle proces co nejvíce zjednodušit? V zásadě na tom by mohla stát totiž každá textovka  :) Ale je to pro mě pořád proces, který neumím udělat. Možná už chci moc, ale aspoň jeden bod z toho bych rád zrealizoval co nejjednodušším způsobem, v nejlepším případě všechny 3 body  ::)

V Basicu je to samozřejmě triviální:

Kód: [Vybrat]
10 PRINT "Jsi na křižovatce. Jakým směrem půjdeš?"
20 INPUT x$
30 IF x="S" THEN GOTO 50 ELSE GOTO 40
40 PRINT "Tam se jít nedá." : GOTO 10
50 PRINT "Jsi na severní křižovatce."

Pak bych zkusil pokračovat (např. tomu dát nějakou barvu, efekty, zvuk...), ale to už je hudba budoucnosti. Zatím bude stačit zrealizovat tohle  ???
« Poslední změna: 5. Srpen 2010 - 09:09 od amigainspired »
Jedna stará textovka vydá za desítky dnešních nadutých her.


KaiN

  • Superčlen
  • *****
    • Příspěvků: 505
    • Zobrazit profil
Ajaj, takhle snad raději ne. ;) Mimochodem, řekl bych, že ti to ani nebude fungovet. Podle mě tam má být "INPUT x$". Jestli chceš mermomocí udělat textovku pro ZX, použij PAW nebo Quill (viz. WoS), když nebudeš vymýšlet nějaké komplikované příkazy, tak to s "cestinou" půjde. Sám jsem to kdysi dávno zkoušel.


zxretrosoft

  • Plný člen
  • ***
    • Příspěvků: 235
    • Zobrazit profil
    • zxretrosoft
Ajaj, takhle snad raději ne. ;) Mimochodem, řekl bych, že ti to ani nebude fungovet. Podle mě tam má být "INPUT x$". Jestli chceš mermomocí udělat textovku pro ZX, použij PAW nebo Quill (viz. WoS), když nebudeš vymýšlet nějaké komplikované příkazy, tak to s "cestinou" půjde. Sám jsem to kdysi dávno zkoušel.

Ale jooo  ;) To byl jenom příklad, fungovat to bude bezpečně, to x$ jsem změnil, je to detail, jsem totiž zvyklý na Basic, kde se už $ nedává ani za stringové proměnné. Potřebuji si jen přijít na to, jak tenhle jednoduchý proces 3 kroků bude fungovat v assembleru, pak se dá již všechno zkomplikovat, přemostit, zavést tam další a další věci a podmínky...
Jedna stará textovka vydá za desítky dnešních nadutých her.



zxretrosoft

  • Plný člen
  • ***
    • Příspěvků: 235
    • Zobrazit profil
    • zxretrosoft
Solaris104: Díky  ;) To je pěkný článek i časopis!  :)

Jinak už jsem skoro vyřešil bod č. 1, který jsem deklaroval. Říkám skoro, což je důležité, protože výstup je pořád nějak pokřivený a nemůžu to srovnat (viz příloha).

V knize je bohužel ten příklad tak nešikovně a nešťastně, že je skoro nemožné to kompletně dešifrovat.

Zjednodušil jsem to tedy na maximum, ale ještě se to musí doladit - možná bude někdo vědět jak na to  ::)

Kód: [Vybrat]
ent $
call #D6B
ld a,2
call #1601
ld hl,TEXT1
call TEXTOUT
TEXTOUT ld a,(hl)
and 127
rst 16
bit 7,(hl)
inc hl
jr z,TEXTOUT
ret
TEXT1 defb 22,15,10
defb 10,1
defm "ZX Spectrum"
ret

Některé věci jsou tam trochu komplikované, ale možná, že jsou nutné (např. and 127 v kombinaci s bit 7,(hl) inc hl a tou smyčkou). Zkoušel jsem je odstranit a ještě to zjednodušit, ale zdá se, že už to víc nejde...
S číslíčky u defb je možno si pohrát - ovlivňují pozici, barvu a jas textu.
« Poslední změna: 5. Srpen 2010 - 22:21 od amigainspired »
Jedna stará textovka vydá za desítky dnešních nadutých her.