Az első assembly programunk

Eljött végre a pillanat, amit mindenki annyira várt! Rendhagyó módon mi most nem egy HELLO WORLD-el kezdünk, hanem valami sokkal látványosabbal. Ami mellesleg egyszerűbb is, emellett segít megalapozni a továbbiakat.

Izzítsuk be az emut, tehénkedjünk az Action Replay menüjében az F7-re, és írjuk be az alábbi parancsot:

006-poke.jpg

Az enter leütése után valami csoda történik, és a kék keret világoszöldre vált. Miféle gonosz mágia lehet ez? És mi a fene az a POKE?

A POKE működése pofonegyszerű, a megadott memóriacímre beírja a megadott számot. Esetünkben a cím az 53280, a beírt érték pedig a 13.

Honnan jönnek ezek a számok és mit jelentek?

Gépünkben van egy grafikus chip, a VIC-II, ami egyszerűsége ellenére eléggé nagyszerű, és viszonylag könnyen vezérelhető. Gondolom már sejtitek, hogy ezzel a POKE-al valamiféle utasítást adtunk neki az előbb.

Ez a chip is rendelkezik regiszterekkel, amiken keresztül a működését lehet befolyásolni. Elég sok van neki, szám szerint 46 darab. Ezek a regiszterek csúnya szóval élve, "be vannak fűzve" a C64 memóriájába, vagyis egy adott memóriacím írásával/olvasásával, egy adott regisztert tudjuk piszkálni.

Ez a 46 regiszter a memóriában az 53248 és 53294 közötti memóriaterület. A fent "megpókolt" 53280 az bizony pont a keret színéért felelős regiszter, amibe benyomtuk a 13-as számot, ami a világoszöldet jelenti.

Don't panic!

Nem kell beszarni, ez a sok hülye szám elsőre ijesztő lehet, de természetesen, mint minden rendes programozónak, nekünk is vannak referenciáink. A regiszterek listája, és a színek számkódjai is mind megtalálhatóak a VIC-II Wikipédia oldalán. Meg még persze 1000 más helyen a neten :)

A későbbiekben természetesen elkezdünk majd használni mindenféle emberközelibb fejlesztőeszközöket, és egyebeket, amik majd megkönnyítik a dolgunkat, de szeretném az alapoknál kezdeni, hogy lehetőleg mindenki értse is azt, amit csinál. :)

Aki megnézte a linkelt Wiki oldalt, annak feltűnhetett, hogy sehol sincs 53280, viszont a 32. regiszternél vagyis "border color"-nál egy D020 áll.

006-d020.jpg

Nem megyek most bele a kettes (bináris), és tizenhatos (hexadecimális) számrendszer mélységeibe, akit érdekel, talál rengeteg infót róla a neten. Elégedjünk meg most annyival, hogy a BASIC a jól ismert 10-es számrendszert használja, mi viszont a 16-ost fogjuk majd javarészt. Aki szeretné, kipróbálhatja ezen az átváltó oldalon, hogy a D020 hexadecimális szám, az biza 53280 a 10-es számrendszerben. A későbbiekben a hexadecimális számokat dollárjellel fogjuk jelölni, vagyis $D020.

Ha már eddig eljutottunk, jöjjön egy kis játék, állítsuk át a belső kék rész színét is, mondjuk sötétzöldre. A wiki oldalon kikereshetjük a "Background color 0" regiszter címét, ami $D021, valamint a sötétzöld számkódját, ami 5.

Mivel még BASIC-nél tartunk, a 10-es számrendszerbeli megfelelő az 53281, az 5 meg értelemszerűen 5.

006-poke2.jpg

Hoppáhoppá, vezéreljük a grafikus chipet! Hát nem nagyszerű? Természetesen ennél jóval menőbb dolgokra is képes a masina, de ne rohanjunk annyira előre.

Próbáljuk ki a következő BASIC programot. (Én most kireseteltem a gépet Alt+F9-el, azért kék minden)

006-border.jpg

Jelenleg már megfelelő tudással rendelkezik mindenki, hogy magától rájöjjön, hogy itt mi bizony gyorsan változtatjuk majd a keret színét a világoszöld (13), és a világoskék (14) között. A RUN beírása után mindenki egy standard villogásra számít majd...

006-border2.jpg

Érdekes módon valamiféle fura csíkozást kapunk. Ennek oka, hogy a VIC másodpercenként 50szer rajzolja ki a teljes képet, elkezdve a bal felső sarokból, és szépen soronként lefelé végigmegy. Mivel a BASIC programunk gyorsabb, mint amennyi idő kell egy ilyen teljes kép kirajzolásához, a rajzolás közben már átváltja a keretszínt, majd vissza.

A grafikus chipünk "buta", őt nem érdekli, hogy van-e értelme az adott feladatnak, csupán végrehajtja. Ha éppen a képernyő kirajzolásának a közepén váltjuk át a keret színét... Akkor bizony gondolkodás nélkül rajzolja tovább a képernyőre a képet, immár az új színnel. Aki látott már C64-et, annak ismerős lehet ez a keret villogás, csinálunk is majd belőle érdekes dolgokat ;)

Az igazán szemfülesek még azt is kiszúrhatják a képemen, hogy éppen hol tartott a VIC a kép kirajzolásával, mikor éppen átváltott a program kékről zöldre. (Jobb szélen, a kereten van egy "törés")

006-border22.jpg

 

Ha megállítjuk a programot ESC-el, akkor viszont a villogás abbamarad, és vagy kék, vagy zöld keretet kapunk, mivel az adott regiszterben lévő számérték már nem változik többé. Igy a chipünk mindig ugyanazzal a színnel rajzol majd. Másodpercenként 50-szer.

Hol van már az assembly???

Oké, rendben, jöjjön hát a lényegi rész. 

Az Action Replay-ünknek egy nagyon jó kis bővítménye, a "Gépi kódú monitor"-nak, vagy csak simán monitornak nevezett program. Ezzel megnézhetjük, és átírhatjuk direktben a memória bármilyen szegletét. Emellett van benne egy egyszerű assembler is, ami nekünk most nagyon jól jön. (Igen, van a VICE-ban is beépített monitor, de attól hülyét kapok, sry)

Írjuk hát be: MON és csapjunk az enterre: (Én már megint reseteltem, hogy átláthatóbb legyen a kép, de természetesen nem muszáj)

006-mon.jpg

Indításkor kiír mindenfélét, de mi ezzel most nem foglalkozunk.

Írjuk meg hát az első assembly programunkat, ami pontosan a fenti képernyővillogtató lesz. Először pötyögjük be, aztán rátérünk, hogy mit és hogyan csinál. (Innentől minden szám hexadecimális, akár áll előtte dollárjel, akár nem!)

Ha beírjuk, hogy "A 1000 LDA #$0D" és leenterezzük, valami láthatóan történik:

006-asm01.jpg

Hát ez átírta a sorunkat! Majd a következő sor elejére kiírta, hogy 1002:

006-asm02.jpg

Mi is történt? Az "A" (mint assemble) parancs mondja meg a monitor programnak, hogy mi most bizony assembly kódot fogunk beírni neki. Példánkban az 1000 azt a memóriacímet jelöli, ahová el szeretnénk helyezni a parancsunkat. Természetesen teljesen más címet is választhattam volna, hiszen van 64kb szabad RAMunk :)

Sejthetően az LDA #$0D pedig valamilyen assembly kód lesz...

Pontosan így van, az LDA (LoaD to A) utasítás be tud tenni egy byte-ot a processzor A regiszterébe. (Itt esetleg vissza lehet ugrani az előző postokhoz, hogy mi is az a regiszter) Jelen esetben belerakunk egy $0D (10-es számrendszerben 13 - világoszöld) értéket. A kettőskeresszttel azt mondjuk meg, hogy itt direktben megadunk egy számot. (Lesznek más jelölések is később, például a memória egy tetszőleges helyéről is beolvashatunk egy byte-ot.)

Mikor entert nyomunk, akkor viszont a monitor átszerkeszti a sort, és belekerül egy "A9 0D" a parancs elé. Ez valójában az utasítás gépi kódú megfelelője. Ugye mindenki emlékszik, a processzor csak és kizárólag számokat tud értelmezni. Az A9 valójában az "LDA #", a mögötte álló "0D" pedig az érték, amit megadtunk.

Az assembler megkönnyíti az életünket, mert nem kell hülye számokat megjegyeznünk. Valószínűleg az A9-et holnapra mindenki elfelejti, viszont az LDA könnyebben fejben tartható.

És mivel extra jó fej, az assembly parancsunk értelmezése, és tárolása után nagyon előzékenyen kiírja nekünk a következő sor elejére az "A 1002"-t, vagyis azt memóriacímet, ahová a következő utasítást beírhatjuk.

Pötyögjük be a maradékot, és nézzük meg egyben, majd értelmezzük: (Ha valamit elgépelünk, és az assembler nem érti, egy ?-et fog kiírni. Ilyenkor nyugodtan gépeljük be újra a parancsot a következő sorba, vagy menjünk vissza a kurzorral, javítsuk, és enter. Ugye fullscreen editorunk van, pont mint BASIC-ben ;)))

006-asm03.jpg

Itt már újabb utasításokat is felfedezhetünk, és szépen látható, hogy ezek milyen módon tárolódnak a memóriában.

Az STA (STore A) kb az LDA fordítottja, az A regiszter tartalmát kiírja valahova. Esetünkben a megadott memóriacímre, ami a már ismerős $D020. Tehát a keret világoszöldre vált.

Az alatta lévő két sor ugyanezt csinálja, beteszünk A-ba egy $0E értéket, és azt kiírjuk a $D020-as címre. A keret világoskék lesz.

Az STA utasítások sorában megfigyelhető, hogy itt bizony már 3 szám keletkezett az utasítás előtt. Igen, a "8D" az STA, a "20 D0" pedig a D020, csak fordítva. A C64 a memóriacímeket mindig ilyen fordított sorrendben tárolja, ezt hívjuk alsó/felső byte alaknak, ez sokszor előkerül majd még.

Az utolsó utasítást nem lesz nehéz kikövetkeztetni, ez a JMP (JuMP), vagyis ugyanaz, mint a BASIC-ben a GOTO. Itt nem programsort, hanem memóriacímet adunk meg, hogy hová ugorjon a program. Mi visszaugrunk a legelejére, vagyis a $1000-es memóriacímre. És itt minden kezdődik elölről.

A gépi kódot, és az assembly utasításokat összevetve könnyen észrevehető, hogy vannak parancsok, amik 2 byte, míg vannak amik 3 byte hosszúak. Valójában minden utasítás csak 1 byte, a mögötte álló plusz 1 vagy 2 byte az az utasítás paraméterei. Van utasítás, aminek nincs paramétere, az értelemszerűen csak 1 byte hosszú lesz. Szerencsére ezt nem kell fejben tartanunk, az assembler tudja helyettünk is.

Az is jól látszik, hogy az assembly parancsaink mind 3 karakteresek, és általában valamilyen könnyen megjegyezhető szó rövidítései.

Futtassuk!

Ha minden tuti, a kurzor most egy "A 100D" kezdetű sorban villog, az assembler azt hiszi mi még folytatnánk a programot, és várja az utasítást. Ha itt nem adunk meg semmit, csak ráenterezünk, egy sima üres sort kapunk.

006-asm04.jpg

A programunkat futtatni a "G"-vel tudjuk (Go). Meg kell adnunk egy memóriacímet is, ami ez esetben 1000. Vagyis beírva, hogy "G 1000", a programunknak el kell indulnia.

006-asm05.jpg

Hasonló villogást kapunk, mint a BASIC program esetében, viszont itt már látszik a sebességkülönbség a BASIC és az assembly között. Mivel közvetlenül a processzort programozzuk, mindenféle közvetítő (a BASIC parancsértelmező) nélkül, kb 300-szoros sebességnövekedést értünk el.

BASIC-ben kb fél képernyőnként változott a keret színe, jelenleg pedig minden egyes sorban többször is. Ha tegyük fel, sikerülne úgy beidőzíteni a programunkat, hogy csak minden sor elején változtassa meg a keret színét, akkor érdekes effekteket érhetnénk el, mint pl a klasszikus C64-es "rasterbar"-ok.

006-rasterbar.jpg

Összefoglalva

A processzor csak számokat ért meg. Minden szám egy parancs számára. Ezeket a számokat a memóriából olvassa ki. A számokat beírhatjuk kézzel a memóriába, vagy egy assemblerrel, ami kicsit könnyebb.

Ja igen...

Most mindenki ottmaradt egy villogó képernyővel, ami a végtelenségig ezt csinálja. Hogyan is állítsuk meg?

Az ESC+PageUp lenyomása megfelel az igazi C64 RUN/STOP + RESTORE billentyűkombinációjának. Ha megnyomjuk, az egy megszakítást (interrupt) generál. Előzőleg volt már szó arról, hogy a processzor képes megszakítások kezelésére, vagyis amikor kap egy ilyen megszakításkérelmet, akkor félbehgyja az adott program futását, és valami mást csinál. A monitorprogram ezt a megszakítást átírja saját magára, így a billentyűk lenyomásakor a programunk megszakad, és visszakerülünk a monitorba, egy üres prompttal.

006-restore.jpg

Még néhány apróság

A monitor program természetesen nem csak assembly -> gépi kód átalakítást tud, hanem fordítva is. Magyarán a memóriából kiolvasott byte-okat értelmezve, elő tudja állítani az eredetileg általunk beírt assembly kódot is.

Ezt a D (disassemble) paranccsal tudjuk elővarázsolni. Ha beírjuk, hogy "D 1000 1010", akkor kilistázza az 1000-1010 közötti memóriaterületet nekünk, olvasható formában.

006-disasm.jpg

Itt látható, hogy a programunk a JMP-nél véget ér, utána pedig már csak a memóriában található "szemét" látszik. Az "FF" például a processzor által nem értelmezhető utasítás, így kérdőjelek jelennek meg. (A 6502/6510 nem rendelkezik 255 különböző utasítással, így némely byte értelmezhetetlen, vagy hivatalosan nem dokumentált működést eredményez) 

Mivel a teljes képernyős szerkesztő mindig mindenhol működik, a kilistázott programunkat a BASIC-hez hasonlóan tudjuk módosítani is. Csak annyit kell tenni, hogy a kurzorral felmegyünk, és az LDA #$0D -t átírjuk LDA #$00 -ra, majd nyomunk egy entert. Azután a másik LDA-nál a 0E-t pedig például 01-re, majd enter.

Futtatva látható, hogy a keret most a fekete (00) és a fehér (01) színek között váltogat.

006-disasm2.jpg

A kilistázott programot, és a képernyőt "görgetni" is tudjuk, ha lemegyünk az utolsó sorba, és nyomkodjuk a lefelé nyilat. Ilyenkor a memória listázása 1010-től folytatódik. Ugyanez igaz a képernyő tetején is. Mindenki próbálja ki, elsőre kicsit fura, de szokható.

006-disasm3.jpg

Az F5 és F7 billentyűkkel a képernyőt automatikusan görgethetjük a megfelelő irányba, pause: kurzor fel, kilépés a görgetésből: kurzor le.

Elsőre ennyi, mindenki emésztgesse, játszogasson, próbálgasson. Eminenseknek szorgalmi: írjuk át a programot, hogy ne a keretet, hanem a háttérszínt váltogassa. ($D021)

Lépjünk tovább, lássuk hogyan tudunk valamit megjeleníteni a képernyőn!

Némi extra adalék: Action Replay monitor parancsok (7.pontnál)

A bejegyzés trackback címe:

https://c64assembly.blog.hu/api/trackback/id/tr3116182122

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Nincsenek hozzászólások.

C64 assembly alapok

Friss topikok

  • Heretic83: Sziasztok! Tudnátok ajánlani olyan tudástárt, ahonnan lehet tanulni bővebben az assembly programoz... (2023.07.13. 19:15) Mi az az assembly
  • tájbor1001110: Válaszolva a saját kérdésemre: Az End+o -val lehet 5 szín séma között váltogatni. (2022.09.20. 21:14) Turbo Assembler
  • tájbor1001110: Ne haragudj, aludtam rá egyet és észrevettem hogy a "*=$1000" direktívából hiányzik a '$'. (((: Bo... (2022.09.16. 08:56) Képernyőtörlés

Címkék

süti beállítások módosítása