OldComp.cz
https://oldcomp.cz/

Assembler
https://oldcomp.cz/viewtopic.php?f=40&t=421
Stránka 47

Autor:  _dworkin [ 27.08.2013, 18:41 ]
Předmět příspěvku:  Re: Assembler

Busy píše:
A na dnes jeden maly trik so skokom doprostred instrukcie ;)

Dajme tomu ze mame vyriesit takyto problem:
Kód:
IF a=ttt THEN a=uuu
ELSE IF a=vvv THEN a=www
Ako prve nas napadne jednoduchy priamociary sposob:
Kód:
      cp TTT      ; Ak A nie je TTT
      jr nz,NEXT   ; tak pokracuj
      ld a,UUU   ; Ak ano tak A=UUU
      jr END      ; Skok na koniec
NEXT:   cp VVV      ; Ak A nie je VVV
      jr nz,END   ; tak skok na koniec
      ld a,WWW   ; A=WWW
END:
Lenze toto ma az 14 bajtov. Neslo by to trosku zoptimalizovat ?
Samozrejme slo, inak by som sa nepytal ;) Najprv si to trosku preusporiadame:
Kód:
      cp TTT
      jr z,SETTT
      cp VVV
      jr nz,END
      ld a,WWW
      jr END      ; Skok o 2 bajty dalej
SETTT:   ld a,UUU   ; LD A,UUU ma 2 bajty
END
Vsimnite si ten skok ktory skace o dva bajty dopredu - obskakuje instrukciu LD A,UUU. Pre tento skok sme pouzili dvojbajtovu instrukciu nepodmieneny relativny jump. Lenze, ono existuje aj jednobajtovy nepodmieneny jump o dva bajty ! :bulb: Neverite ? Tak sa pozrite:
Kód:
      cp TTT
      jr z,SETTT
      cp VVV
      jr nz,END
      ld a,WWW
      db #21      ; Kod instrukcie LD HL,dvojbajtovy_operand
SETTT:   ld a,UUU   ; Instrukcia alebo operand pre LD HL,...
END:
Tento jednobajtovy jump je dokonca o dva takty rychlejsi, nez ten dvojbajtovy relativny ! :thumbup: A vdaka nemu je nasa rutinka o bajt kratsia :clap: Akurat jedinou jeho nevyhodou je, ze nam nezachova obsah registra HL :shrug: Nuz ale pokial HL na tomto mieste zrovna nepotrebujeme, tak to predsa nevadi :neener:

To reseni vlastne neni zavisle na tribajtove instrukci LD HL,nn ( $21, lo, hi ). Stejne dobre poslouzi i LD BC,nn ( $01, lo, hi ) nebo LD DE, nn ( $11, lo, hi ). Takze lze obetovat libovolnou z tech tri. Dalsi tribajtove jsou ruzne skoky nebo call a ty se nedaji pouzit. Ale jde udelat i toto
Kód:
      cp TTT
      jr z,SETTT
      cp VVV
      jr nz,END
      ld h,WWW
      defb $dd      ; "Prefix" instrukcie LD ixh,n, popripade $FD pro iyh,
SETTT:   ld h,UUU   ;
END:

Misto akumulatoru (ve skutecnosti tam teda jde dat cokoliv co zabita 2 bajty) se nastavuje pouze "h"a obetuje se IXH nebo IYH. Obdobne $2E nn = ld l,n a $DD $2E nn je ld ixl,n nebo $FD 2E nn je ld iyl, n.
A cele to jde pak prevest na 16 bit kdy misto osmibitoveho "h/l" nebo cast "ix/iy", muzeme nastavovat ld hl,nn a to maskovat za ld ix/iy,nn
Kód:
Instrukce   Čas (T-cykly)   Délka   Kód (dekadicky)     Kód (hexa)
LD HL,NN        10              3       33, xx, xx          21, xx, xx
LD IX,NN        14              4       221, 33, xx, xx     DD, 21, xx, xx
LD IY,NN        14              4       253, 33, xx, xx     FD, 21, xx, xx
-----
LD HL,(NN)      16              3       42, xx, xx          2A, xx, xx
LD IX,(NN)      20              4       221, 42, xx, xx     DD, 2A, xx, xx
LD IY,(NN)      20              4       253, 42, xx, xx     FD, 2A, xx, xx
-----
LD H,N          7               2       38, xx              26, xx
LD HX,N         11              3       221, 38, xx         DD, 26, xx
LD HY,N         11              3       253, 38, xx         FD, 26, xx
-----
LD L,N          7               2       46, xx              2E, xx
LD LX,N         11              3       221, 46, xx         DD, 2E, xx
LD LY,N         11              3       253, 46, xx         FD, 2E, xx

A jeste jsou tribajtove instrukce u kterych si neprepiseme zadny registr, ale pamet. Nejlepsi je asi nejrychlejsi "ld (nn),a" oproti "ld (nn),hl". Problem je jen v tom ze ta adresa musi ukazovat nekam kde to nevadi. A vyssi bajt je zrovna ten druhy kam cpeme nejakou hodnotu.
Jde to i otocit na "ld a,(nn)" pak si prepisujeme akumulator a nastavovat muzeme "b,c,d,e,h,l"
Na vic jsem zatim neprisel. .)

Autor:  _dworkin [ 27.08.2013, 19:23 ]
Předmět příspěvku:  Re: Assembler

Kód:
IF a=ttt THEN a=uuu
ELSE IF a=vvv THEN a=www

Nejlepsi reseni je stejne si vhodne zvolit data.
Idealni pripad
Kód:
IF a=ttt THEN a=ttt
ELSE IF a=vvv THEN a=vvv

Se da prepsat do Z80 bez jedine chyby .)
Horsi pripady
Kód:
IF a=ttt THEN a=ttt+ccc
ELSE IF a=vvv THEN a=vvv+ccc

Kód:
IF a=ttt THEN a=ttt | xxx
ELSE IF a=vvv THEN a=vvv | xxx

A pokud se ttt vhodne zvoli jako nula tak toho jde udelat hodne misto skoku jen vzorcem.
Kód:
Prakticky prevod
if a = 0 then dec b
else if a =1 then inc b
else b je nedefinovano

add a,a
dec a
add a,b
ld b,a

Autor:  pavero [ 28.12.2013, 19:09 ]
Předmět příspěvku:  Re: Assembler

Jak se dá v assembleru číst obsah paměťi nikoliv po bajtech, ale po skupině bitů? Řekněme čtení po pěti bitech.

1. krok - horních pět bitů z prvního bajtu.
2. krok - dolní tři bity z prvního bajtu a horní dva bity z druheho bajtu.
3. krok - dalších pět bitů z druhého bajtu.
Atd.

Nějaká speciální instrukce, ktera by na toto šla nasadit, asi neexistuje, co?

Autor:  pavero [ 28.12.2013, 19:13 ]
Předmět příspěvku:  Re: Assembler

Když o tom tak premýšlím, asi mnohem snazší bude varianta po sesti bitech. (8 kroků vs. 3)

Autor:  Busy [ 28.12.2013, 19:51 ]
Předmět příspěvku:  Re: Assembler

Instrukcie vzdy citaju z pameti cely bajt, dokonca aj ked potrebujes jediny bit. Pokial mas v pameti data usporiadane tak ze nejaky udaj nezabera celych 8 bitov, robi sa to aj tak vzdy tak, ze nacitas cely bajt (alebo cele slovo) a potrebne bity si z toho "vysekas".

Cisto prakticka otazka: Naco to potrebujes ? Skus trosku popisat kontext problemu.

Autor:  pavero [ 28.12.2013, 21:47 ]
Předmět příspěvku:  Re: Assembler

Busy píše:
Instrukcie vzdy citaju z pameti cely bajt, dokonca aj ked potrebujes jediny bit. Pokial mas v pameti data usporiadane tak ze nejaky udaj nezabera celych 8 bitov, robi sa to aj tak vzdy tak, ze nacitas cely bajt (alebo cele slovo) a potrebne bity si z toho "vysekas".

Cisto prakticka otazka: Naco to potrebujes ? Skus trosku popisat kontext problemu.


Tak obecně to lze využít na čtení dat v takovémto formátu uložené. Asi klasický příklad jsou texty, kde používám pouze abecedu, tedy mi stačí jen 32 kombinací. Například Dizzy používá něco obdobného, byť tam je to ještě trochu komplikovanější.

Sám to chci použít ve své hře na uložení textů, u kterých nechci, aby byly snadno odhalitelné v hexaeditoru. Vím, že na to by mi dobře posloužila třeba i instrukce cpl, popřípadě nějaké rotace. Zároveň bych tím ale ušetřil i paměť. Asi jako vhodný kompromis použiji 6-bitů na znak, kdy každé tři znaky se vejdou do dvou bajtů, takže čtecí rutinka bude jednoduchá a krátká.

Autor:  pavero [ 28.12.2013, 21:49 ]
Předmět příspěvku:  Re: Assembler

Opravuji, každé čtyři znaky se vejdou do tří bajtů.

Autor:  Milsa [ 28.12.2013, 21:55 ]
Předmět příspěvku:  Re: Assembler

Ja mám otázku, niekde som videl, že EXX vymení aj AF a AF' a inde, že tieto registre ostanú nedotknuté. Ako je to teda?

Autor:  pavero [ 28.12.2013, 21:59 ]
Předmět příspěvku:  Re: Assembler

Milsa píše:
Ja mám otázku, niekde som videl, že EXX vymení aj AF a AF' a inde, že tieto registre ostanú nedotknuté. Ako je to teda?


Aspoň co já mám vyzkoušené (minimálně v emulátorech), tak instrukce EXX nemění AF/AF', od toho je EX AF,AF'

Autor:  Busy [ 29.12.2013, 16:32 ]
Předmět příspěvku:  Re: Assembler

pavero píše:
Milsa píše:
Ja mám otázku, niekde som videl, že EXX vymení aj AF a AF' a inde, že tieto registre ostanú nedotknuté. Ako je to teda?

Aspoň co já mám vyzkoušené (minimálně v emulátorech), tak instrukce EXX nemění AF/AF', od toho je EX AF,AF'
Samozrejme, EXX meni iba BC,DE,HL. Pre vymenu AF treba pouzit EX AF,AF. Takze napriklad ak chcem aby hlavny program pouzival jednu sadu registrov AF BC DE HL, a rutinka v prerusni druhu sadu, tak na zaciatku aj na konci prerusovacej rutinky musim pouzit obidve tieto instrukcie:
Kód:
int:
  EXX
  EX AF,AF
  .....
  EX AF,AF
  EXX
  EI
  RET
Vzajomne poradie oboch instrukcii EXX a EX AF,AF nie je kriticke (kedze ich mnoziny posobenia su plne disjunktné), preto ja osobne vzdy pouzivam take ich poradie, ktore v zdrojaku vyzera esteticky lepsie :)

PS1: Uz som sa u ludi zoparkrat stretol s pohladom ze zalozne registre su nejake "ine" a pred navratom z programu ich treba zase "odstrankovat" aby cinnost pokracovala s hlavnymi registrami. Zaujimavy pohlad, ale nespravny. Obidve sady su absolutne rovnocenne, nie je medzi nimi ziadna "hlavna" alebo "zalozna". Je preto uuuplne jedno, ci ich nejaky program necha v skutocnosti vymenene alebo nie. Dolezite je jedine to aby pripadne potrebne hodnoty (vracane z programu) boli v spravnej registrovej banke.

PS2: Pokial je na ZX spektre nejaky strojak volany z basicu funkciou USR, v registri HL' (HL ktore prave nie je "nastrankovane") je hodnota #2758 a tato hodnota tam musi byt aj pri navrate nazad do basicu. Je preto uplne jedno, ci strojak vobec nepouzije EXX (a tym HL' nezmeni) alebo pouzije EXX lubovolny pocet (parny ci neparny) krat (a pomeni vsetky registre) ale pred navratom urobi LD HL,#2758:EXX:RET - v oboch pripadoch to bude spravne.

Autor:  Busy [ 29.12.2013, 18:00 ]
Předmět příspěvku:  Re: Assembler

pavero píše:
Tak obecně to lze využít na čtení dat v takovémto formátu uložené. Asi klasický příklad jsou texty, kde používám pouze abecedu, tedy mi stačí jen 32 kombinací. Například Dizzy používá něco obdobného, byť tam je to ještě trochu komplikovanější.

Sám to chci použít ve své hře na uložení textů, u kterých nechci, aby byly snadno odhalitelné v hexaeditoru. Vím, že na to by mi dobře posloužila třeba i instrukce cpl, popřípadě nějaké rotace. Zároveň bych tím ale ušetřil i paměť. Asi jako vhodný kompromis použiji 6-bitů na znak, kdy každé tři znaky se vejdou do dvou bajtů, takže čtecí rutinka bude jednoduchá a krátká.
Aj keby si pouzil 5 bitov na znak, rutinku to nijak neskomplikuje ;)

Btw. prave takyto "5-bitovy" sposob ulozenia textu som pouzil vo svojom intre StoryTalker (video). Text nacitavam z pameti takouto rutinkou:
Kód:
getznk  ld      b,#05
        xor     a
getrot  rl      c
        jr      nz,getbit
        ld      c,(hl)
        inc     hl
        scf
        rl      c
getbit  adc     a,a
        djnz    getrot
Rutinka postupne pri kazdom zavolani nacita jednu 5-bitovu hodnotu z pameti a vrati ju v A. Funguje tak, ze si najprv do registra C nacita cely bajt z pameti, a z tohto bajtu potom narotuje 5 bitov do akumulatora. Ked sa (napr. pri dalsom zavolani) minu vsetky bity v registri C, nacita sa do C novy bajt z pameti a mozu sa vyberat dalsie bity. Rutinka sa da pouzit na vseobecny pocet bitov na jeden nacitavany znak, staci zmenit konstantu #05. Pred prvym zavolanim rutinky treba C inicializovat na hodnotu #00 alebo #80 a do HL nastavit adresu prveho bajtu kde v pameti zacina takto skomprimovany text. A potom pocas nacitavania textu po znakoch zachovat pre rutinku registre C a HL.

Autor:  pavero [ 29.12.2013, 23:04 ]
Předmět příspěvku:  Re: Assembler

Paráda Busy, to jsem ani nedoufal, že na tuto úlohu bude stačit takhle krátký a hlavně univerzální kód. :)

Za jaké situace je příznak ZERO nastaven na 1 u instrukce RL?

Autor:  Busy [ 29.12.2013, 23:33 ]
Předmět příspěvku:  Re: Assembler

pavero píše:
Za jaké situace je příznak ZERO nastaven na 1 u instrukce RL?
Pri vsetkych rotaciach po shifte #DD sa zero nastavuje podla obvyklych pravidiel - nastavi sa ak je vysledkom operacie (v tomto pripade rotacie) nulovy bajt. Napr. ak mas v C hodnotu #80, nie je nastavene carry a urobis RL C, carry sa zarotuje do nulteho bitu C a tym padom bude v nultom bite C nula. A najvyssi jednotkovy bit vypadne prec, v celom registri C budu vsetky bity nulove a nastavi sa zero.

pavero píše:
k čemu je tam dobrá ta instrukce scf, když za ní hned následuje rl c, která příznak carry přenastaví dle aktuální situace?
Avsak ak je carry pred rotaciou nastavene, potom po rotacii bude nulty bit C nastaveny na jednotku. A zero nastavene tym padom byt nemoze.

Tato moja rutinka prave podla priznaku zero testuje, ci uz vyrotovala z registra C vsetky uzitocne bity a ci ho treba znovu naplnit dalsim bajtom. Na zaciatku pri prvom zavolani rutinky (ked je C nastavene na #80) po XOR A nebude carry, a rotaciou vznikne nula, takze C sa naplni bajtom z ramky. Nasledne, hned po vyrotovani prveho najvyssieho bitu prveho znaku, sa vdaka tomu SCF dostane do nulteho bitu jednicka, a ta zabezpeci, ze nasledujucich sedem rotacii nemoze nastavit priznak zero (a register C nebude najplnany z ramky). A az tento nas jednickovy bit vypadne na druhej strane registra C von, co znamena, ze v registri C uz nie su ziadne bity nasich znakov, nastavi sa zero a rutinka podla toho vie, ze musi C znovu naplnit dalsimi datami z ramky.

Autor:  pavero [ 30.12.2013, 00:17 ]
Předmět příspěvku:  Re: Assembler

Aj, teď mi to konečně docvaklo, vykonání adc a,a vždy v tomto případě vynuluje CARRY, takže do C se pak zprava sypou samé nuly, takže rutinka ví, kdy má skočit na další byte, prostě geniální. :)

A intro StoryTalker je taky boží!

Autor:  Milsa [ 08.01.2014, 16:59 ]
Předmět příspěvku:  Re: Assembler

Kedysi sme mali na Didaktik Game spektrácky program na výuku assembleru. Nahrávalo sa to z kazety postupne po lekciách. Bolo to v češtine. Myslím, že obsahovo aj pedagogicky to bol výborný program. Nemá to niekto? Samozrejme aj s návodom ako to nahrať do emulátora.

Stránka 47 Všechny časy jsou v UTC + 1 hodina [ Letní čas ]
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/