20. Říjen 2017 - 03:13

Autor Téma: Assembler z80  (Přečteno 19264 krát)

mop

  • Plný člen
  • ***
  • Příspěvků: 125
    • Zobrazit profil
Re: Assembler z80
« Odpověď #30 kdy: 6. Srpen 2010 - 00:13 »
Měl bych k tomu příkladu pár poznámek:

1. Ty dva znaky na konci tam máš proto, že po vykonání podprogramu TEXTOUT program normálně pokračuje tím, co následuje za instrukcí call TEXTOUT, a tedy vlastně znovu vykonává ten TEXTOUT. Řešení: instrukci ret, kterou máš teď úplně na konci, přesuň za call TEXTOUT, protože tady má správně ten program končit.

2. Chápu správně, že data defb 10,1 mají za cíl nastavit modrý inkoust? Pokud ano, tak tam má být buď defb 16,1 nebo hexadecimálně defb #10,1. Takhle to nedává smysl, a proto jsou tam ty otazníky na začátku.

3. Ty instrukce and a bit se obě zabývají nejvyšším bitem toho kterého bajtu, a podle tohoto bitu mají zřejmě za cíl poznat, kdy jsme dospěli na konec dat. Je to trochu zvláštní způsob, ale použít se dá. Musí se ale k poslednímu bajtu textových dat přičíst 128 (tedy dvojkově 10000000), čímž se jeho nejvyšší bit nastaví na 1. V tomhle případě tedy znak "m" nahradíme jeho hodnotou (109) zvýšenou o 128, což je 237.

Zkus to testnout:

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

zxretrosoft

  • Plný člen
  • ***
  • Příspěvků: 227
    • Zobrazit profil
    • zxretrosoft
Re: Assembler z80
« Odpověď #31 kdy: 6. Srpen 2010 - 01:07 »
Díky!  ;) Už to začínám postupně chápat, s tím posledním znakem je to trochu neelegantní, ale budiž, dá se to akceptovat. Ještě se ale nemůžu dopracovat smyslu té první instrukce defb 22,15,10. Co přesně ta instrukce na tomhle místě dělá? Myslel jsem si, že určuje polohu textu, vypadá to ale, že je to komplikovanější...

Např. změním na defb 21,15,10 a zasekne se to. Změním na defb 1,15,10 a text je nahoře zleva, ale před ním jsou 3 otazníky. Zdá se, že tomuhle ještě nemůžu přijít na kloub  ::)

P.S. Nešlo by to i bez těch instrukcí and a bit ? případně bez toho zvláštního psaní posledního znaku?  ::)
Jedna stará textovka vydá za desítky dnešních nadutých her.

KaiN

  • Starší člen
  • ****
  • Příspěvků: 419
    • Zobrazit profil
Re: Assembler z80
« Odpověď #32 kdy: 6. Srpen 2010 - 08:20 »
mop: No já bych řekl, že ten příklad byl poněkud zmršen při úpravách. Původní ideou autora podle mě bylo, že ten příkaz ret, co je na konci toho textu, ve skutečnosti není příkaz, ale indikátor konce textu. Jeho kód je totiž "201", čili má nastaven nejvyšší bit na 1, což tisknutelné znaky nemají. A jinak souhlas, určitě tam nemůže být "10,1", ale "16,1" tj. INK 1.

mop

  • Plný člen
  • ***
  • Příspěvků: 125
    • Zobrazit profil
Re: Assembler z80
« Odpověď #33 kdy: 6. Srpen 2010 - 10:40 »
Např. změním na defb 21,15,10 a zasekne se to. Změním na defb 1,15,10 a text je nahoře zleva, ale před ním jsou 3 otazníky. Zdá se, že tomuhle ještě nemůžu přijít na kloub  ::)
Nesmíš měnit ten bajt 22, ten právě určuje, že chceme použít fuknkci AT. Měň až ty dvě číla za ním, což jsou ty souřadnice.

mop

  • Plný člen
  • ***
  • Příspěvků: 125
    • Zobrazit profil
Re: Assembler z80
« Odpověď #34 kdy: 6. Srpen 2010 - 11:04 »
P.S. Nešlo by to i bez těch instrukcí and a bit ? případně bez toho zvláštního psaní posledního znaku?  ::)

Určitě šlo, já bych na konec těch dat dal normálně bajt o hodnotě 13, což je taková tradiční hodnota pro end-of-line neboli koncový znak jakéhokoliv řetězce.

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

Tedy hodnotu hned po uložení do A testujeme na koncový znak 13. Při rovnosti bez dalších cavyků ukončujeme podprogram. Jinak vypisujeme znak, zvyšujeme ukazatel HL a jdeme na začátek cyklu.

KaiN

  • Starší člen
  • ****
  • Příspěvků: 419
    • Zobrazit profil
Re: Assembler z80
« Odpověď #35 kdy: 6. Srpen 2010 - 11:25 »
Tak to já bych tam spíš dal tradiční bajt o hodnotě 0.  ;) 13 se mu může přece hodit, když bude chtít přejít v rámci odstavce na nový řádek, aniž by se musel plácat s mezerama.

mop

  • Plný člen
  • ***
  • Příspěvků: 125
    • Zobrazit profil
Re: Assembler z80
« Odpověď #36 kdy: 6. Srpen 2010 - 11:39 »
Máš pravdu, lepší bude nula, nebo prostě jakákoliv hodnota, která se nevyužívá k nějakému jinému účelu.

zxretrosoft

  • Plný člen
  • ***
  • Příspěvků: 227
    • Zobrazit profil
    • zxretrosoft
Re: Assembler z80
« Odpověď #37 kdy: 6. Srpen 2010 - 12:59 »
Klucí, díky!  ;) S tou nulou to nefunguje, s defb 13 jo. Takhle to opravdu vypadá elegantněji, přece jen už mi to dává nějaký smysl. Teď ještě přijít na ten zbytek, tj. INPUT a podmínka za tím  :)
Jdu to ještě studovat  ::) p.s. vzhledem k tomu, že v knize Assembler a ZX Spectrum na téma vstup a vyhodnocení textu je stručný příkládek na pouhých 9 stránek  :P
« Poslední změna: 6. Srpen 2010 - 13:17 od amigainspired »
Jedna stará textovka vydá za desítky dnešních nadutých her.

mop

  • Plný člen
  • ***
  • Příspěvků: 125
    • Zobrazit profil
Re: Assembler z80
« Odpověď #38 kdy: 6. Srpen 2010 - 14:21 »
To je divný, že ti to nešlo s tou nulou. Změnil jsi to na obou místech? (u instrukce CP a na konci u DEFB)

zxretrosoft

  • Plný člen
  • ***
  • Příspěvků: 227
    • Zobrazit profil
    • zxretrosoft
Re: Assembler z80
« Odpověď #39 kdy: 6. Srpen 2010 - 14:29 »
To je divný, že ti to nešlo s tou nulou. Změnil jsi to na obou místech? (u instrukce CP a na konci u DEFB)

Ano, jasně s tou nulou to jde - nezměnil jsem to u té první instrukce. Když se to změní u obou, tak to jde v pohodě  ;)
Jedna stará textovka vydá za desítky dnešních nadutých her.

zxretrosoft

  • Plný člen
  • ***
  • Příspěvků: 227
    • Zobrazit profil
    • zxretrosoft
Re: Assembler z80
« Odpověď #40 kdy: 11. Srpen 2010 - 10:32 »
Zkoumal jsem teď nějaký čas různé prográmky v assembleru různých autorů, některé se mi podařilo rozbalit bez problémů, a zjistil jsem, že porozumět assembleru je skvělé, ale 90% autorů využívá hojně hotové podprogramy - prováděcí podprogramy, příkazové podprogramy, aritmetické podprogramy atd.

Kompletní výpis ZX ROM lze najít např. tady: http://softhouse.speccy.cz/documents/download/ZX_ROM.pdf

To mě bohužel zklamalo. Je to opravdu často zplácané z těchto rutinek, autoři si osvojí jen to, kde ušetřit čas (kroky), tam použijí zase jiný ("poctivější") způsob a pak se vrátí zase do podprogramů. Rychlost je pořád lepší než v Basicu. U většiny věcí se to tak nepozná, skutečný assembler se vším všudy je jen tam, kde už autoři zápasí s RAM či s každým krokem kvůli rychlosti...

Výpis ZX ROM je skutečně základní stavební kámen většiny programů v assembleru, takže asi taky něco zkusím, ať vypadám, že tomu rozumím  ;D
Jedna stará textovka vydá za desítky dnešních nadutých her.

lanex

  • Nováček
  • *
  • Příspěvků: 8
    • Zobrazit profil
Re: Assembler z80
« Odpověď #41 kdy: 20. Červen 2011 - 17:59 »
opráším další staré téma:

tvůj příklad volá standartní rutiny v ROM, které jsou určené pro použití v ZX Basicu, a jsou pro ně optimalizované. Pro volání ze strojového kodu jsou ale nevhodné, protože jim to zkrátka hrozně dlouho trvá. Pokud chceš z procesoru s kmitočtem 3,54 MHz vymačknout maximum, musíš se téměř kompletně vyhnout rutinám v ROM. Pokud se rutinám v ROM vyhnout nechceš nebo nemůžeš, neni důvod psát tvuj program v ASM, protože stejně dosáhneš podobné rychlosti jako kdybys ho psal v ZX Basicu.
>> Amiga 1200, ZX Spectrum+, Didaktik Gama, http://www.ilnx.cz <<

zxretrosoft

  • Plný člen
  • ***
  • Příspěvků: 227
    • Zobrazit profil
    • zxretrosoft
Re: Assembler z80
« Odpověď #42 kdy: 22. Červen 2011 - 22:46 »
opráším další staré téma:

tvůj příklad volá standartní rutiny v ROM, které jsou určené pro použití v ZX Basicu, a jsou pro ně optimalizované. Pro volání ze strojového kodu jsou ale nevhodné, protože jim to zkrátka hrozně dlouho trvá. Pokud chceš z procesoru s kmitočtem 3,54 MHz vymačknout maximum, musíš se téměř kompletně vyhnout rutinám v ROM. Pokud se rutinám v ROM vyhnout nechceš nebo nemůžeš, neni důvod psát tvuj program v ASM, protože stejně dosáhneš podobné rychlosti jako kdybys ho psal v ZX Basicu.

Ano, to je principiálně pravda, ovšem šlo o to, že mnoho prográmků, které jsem listoval a všemožně pročítal, mají podobný autorův "podpis". Jeho postup je totiž zpravidla tento:

  • Naučí se několik smyček, vytvářet drobné rutinky v ASM, o kterých ví, co dělají, a ty v té či oné variantě používá (max. je nějak rozšiřuje, ale jen trochu).
  • U věcí, které by se přes tyto rutinky, co "zná", daly udělat jen stěží, použije prostě rutinku z ROM.

Jen málokdy se dá mluvit o tom, že autor chápe celý program v ASM, nebo že vyráží ze Z80 maximum. Tímhle postupem skládání programu jako puzzle dosáhne většinou zajímavého výsledku, "prográmku ve strojáku", aniž by ASM naplno využíval či chápal...

To se ostatně ukazuje na mnoha fórech věnovaných ASM. Téměř všichni, co něco napsali v ASM, to nedokáží vysvětlit, jen opakují fráze typu: "No prostě dej tam ld b,a pak ld hl,0 a ret". Samozřejmě když se zeptám, proč třeba zrovna ld hl,0 , tak na to vůbec neodpoví nebo zopakují frázi, nebo ze mě udělají blbce  ::)

Je to také asi tím, že počet lidí, kteří by alespoň potenciálně mohli umět v ASM Z80, je minimum (a byl minimum už v 90. letech, natož teď), takže člověku nezbývá, než se ponořit do Bity do bytu od L. Zajíčka (či něco obdobného) a studovat to pořád dokola...  :)
Jedna stará textovka vydá za desítky dnešních nadutých her.

lanex

  • Nováček
  • *
  • Příspěvků: 8
    • Zobrazit profil
Re: Assembler z80
« Odpověď #43 kdy: 24. Červen 2011 - 22:02 »
Zřejmě jsi jen nenarazil na ty správný lidi :)

Připravil jsem ti malý příklad na srovnání "Vlastní rutina vs Rutina v ROM", aby se mluvilo o konkrétních hodnotách:
Napsal jsem si pro účely měření obdobný program, jako je zde uvedený první příklad v ASM (vykreslí čtverec znaků 8x8 v různých barvách za pomocí ROM), a šel jsem měřit :)

- Příklad zde uvedený na začátku, co tiskne s pomocí ROM rutiny RST 16 tento čtverec vytiskl na obazovku za 571804 taktů (159,74 ms)

- příklad který jsem si ted tady napsal v ASM, používá mnou napsaný "LnxPrint" :) , vytiskl na obrazovku tentýž čtverec za 60786 taktů (16,98 ms)

Výsledek:

Za pomocí ROM se za sekundu dá vytisknout 400,65 znaků (cca půl obrazovky za sekundu). Moje rutina zvládne za sekundu 3769,14 znaků (cca 5 obrazovek za sekundu).

ROM rutina je tedy skoro 10x pomalejší :) Ani jsem si nemyslel, že to bude až takový rozdíl :)

Přikládám i ASM:
Kód: [Vybrat]
org     50000 ;kompilovat budeme od adresy 50000

                ld c,8 ;budeme tisknout box o 8mi řádcích...
LOOP            ld b,8 ;a 8 sloupcích
LOOP2           push    bc ;uchováme si BC pro jeho obnovení - protože ho při tisknu zničíme

                dec     b ;tady pořešíme barvy. Barva na ZX je v rozsahu 0-7, ne 1-8,
                dec     c ;takže barvu popředí (ink) a pozadí (paper) snížíme o jednu
                ld      a,b ;attribbut barev na ZX je FBPPPIII (Flash-Bright-Paper-Ink)
                sla     a ;proto posuneme barvu PAPERu o 3 doleva, aby byl na správné pozici
                sla     a
                sla     a
                or      c ;a sloučíme s INK, tím dostaneme správný Attribut barvy pro videoram
                ld      (Barva),a ;uložíme do paměti pro tiskovou rutinu

                call    PrintAT ;Zavoláme "Print At regB,regC", tedy nastavíme pozici příštího znaku na obrazovce

                ld       a,64 ;budeme tisknout znak zavináče (ascii 64)
                call    LnxPrint ;a natiskneme znak

                pop     bc ;obnovíme zničené registry BC
                djnz    LOOP2 ;už je celá řádka vytištěná?
                dec      c
                jr       nz,LOOP ;už jsou všechny řádky vytištěné?
                ret ;návrat (kam? no přece tam, odkud jsme to volali :) třeba do bejziku)

; A tady je moje náhrada za RST16:

LnxPrint:       sub     32 ;v RegA máme znak co chceme tisknout. Ascii tabulka začíná od 32 znaku
;(0-31 jsou spec řídící znaky)
                ld      d,0 ;Musíme najít adresu, kde začíná ve fontu písmeno co hledáme.
                ld      e,a ;Z regA si uděláme 16tibitový reg DE, a počítáme:

                sla     e ;DE=DE*8 (v případě @ vypadne 512)
                rl      d
                sla     e
                rl      d
                sla     e
                rl      d

                ld      hl,15616 ;a příčteme adresu písma v ROM (Fontu) HL= HL+DE
                add     hl,de

                ld      de,(PrintAdr) ;do DE si vezmeme adresu do videoram, kterou nám vypočítal Print At regB,regC
                ld      b,8 ;každé písmenko má 8 linek
LnxPrint3:      ld      a,(hl) ;tak je tady všechny zkopírujeme na obrazovku
                ld      (de),a
                inc     d ;další linka na obrazovce je o 256 bajtů dále
                inc     l ;další linka je ve fontu o 1 bajt dále
                djnz    LnxPrint3

                ld      hl,(ColorAdr) ;do HL si vezmeme adresu do color-videoram, kterou nám vypočítal Print At regB,regC
                ld      a,(Barva) ;načteme si hodnotu barvy
                ld      (hl),a ;a cákneme to na to naše písmenko. Znak je na obrazovce, a i v barvě :)

                ld      hl,(PrintAdr) ;opět si načteme adresu do videoram, kterou nám vypočítal Print At regB,regC
                inc     l ;příští písmenko bude o jednu pozici vpravo
                ld      (PrintAdr),hl ;uložíme zpět do paměti
                ld      a,0 ;Zkontrolujem, zda nám pozice znaku nepřetekla do jiné třetiny obrazovky
                cp      l
                jr      nz,LnxPrint4
                ld      de,2048 ;přetekla, takže jdeme s příštím znakem do následujicí třetiny obrazovky
                add     hl,de ;k adrese tedy připočteme 2048
                ld      (PrintAdr),hl ;a uložíme do paměti

LnxPrint4:      ld      hl,(ColorAdr) ;i adresa color-videoram se o jednu pozici posune doprava
                ld      de,1 ;naštěstí nemusíme kontrolovat třetiny, jako tomu bylo u videoram
                add     hl,de
                ld      (ColorAdr),hl ;a uložíme do paměti
                ret ;Znak vytištěn, a nová pozice připravena. Naschledanou

PrintAT:        ld      hl, 16384 ;Budeme zjištovat adresu do videoram podle X (v regB) a Y (v reg C)
                ld      de, 2048 ;videoram je rozdělena na třetiny po 2048 bajtech a proto
                ld      a,b ;budeme testovat jestli Y nezasahuje do jiné třetiny (8mej řádek a více)
LnxPrint2:      cp      8 ;8 řádků a víc?
                jr      c,LnxPrint1 ;jestli ne, jsme ve správné třetině a jdeme dál=>LnxPrint1
                add     hl,de ;ano, 8 a víc, znak se tedy nenachází v této třetině videoram (skočíme do
                sub     a,8 ;následující třetiny tak, že přičteme 2048 k videoram a snížíme pozici Y o 8)
                jr      LnxPrint2 ;a znovu otestuj, jestli není dokonce ve 3tí třetině

LnxPrint1:      sla     a ;Od ted pracujeme jen v jedné třetině obrazovky, Y není větší jak 7
                sla     a ;(páč 8 a víc by byla úplně jiná třetina obrazovky)
                sla     a ;na každé řádce je 32 znaků, 33 znak je vlastně první znak na
                sla     a ;další řádce
                sla     a ;vynásobíme tedy Y * 32
                ld      d,0 ;přeneseme do DE
                ld      e,a
                add     hl,de ;a připočteme k adrese videoram uloženou v HL
                ld      e,c ;do DE nyní vložíme X
                add     hl,de ;a také přičteme k adrese videoram v HL
                ld      (PrintAdr),hl ;tu potom uložíme do paměti.

                ld      hl,22528 ;Nyní si vypočteme adresu color-videoram
                add     hl,de ;přičteme k ní pozici X (která nám od minule zůstala v DE
                ld      e,b ;potom do DE dáme Y
                sla     e ;a vynásobíme 32x (32 protože každý 33 znak je vlastně 1 znak na další řádce)
                sla     e
                sla     e ;(tady je malej fígl pro zrychlení = číslo co násobíme není větší jak 23
                sla     e ;takže se vejde do 5ti bitů. Poslední 3 bity tedy nemůžou přetéct
                rl      d ;a tak 3 bity počítám jen 8mibitově a tedy rychleji. Potom už ale musím přejít
                sla     e ;na 16tibitové nasobení, ale jen kvuli dvoum bitum :) úplný turbo :D )
                rl      d
                add     hl,de ;a přičteme k color-videoram v HL
                ld      (ColorAdr),hl ;uložíme
                ret ;a jdeme doprdele odsud :)

PrintAdr:       defw    0 ;tady nám Print At uloží adresu do videoram, kam cpát znak
ColorAdr:       defw    0 ;tady totež, jen color.videoram
Barva:          defb    15 ;touhle barvou budeme tisknout znak
« Poslední změna: 27. Červen 2011 - 17:53 od lanex »
>> Amiga 1200, ZX Spectrum+, Didaktik Gama, http://www.ilnx.cz <<

KaiN

  • Starší člen
  • ****
  • Příspěvků: 419
    • Zobrazit profil
Re: Assembler z80
« Odpověď #44 kdy: 27. Červen 2011 - 11:21 »
Není nad komentovaný výpis programu...  ;)