LEKCIJA 4 – C64 ASEMBLER
C64 Asembler (C64 Assembly) – Lekcija 4
Dobrodošli u lekciju 4 male škole programiranja u asembleru za Commodore 64. Danas ćemo preći neke izuzetno važne asemblerske naredbe, a kao i obično, daćemo primere i BASIC ekvivalente.
Napomene, saveti i objašnjenja
Prilikom unosa koda u Turbo Assembleru i kompajliranja programa, kada se nađete u BASIC-u i želite da radite u njemu, preporučujemo da otkucate naredbu SYS 64738. Ovo će restartovati računar, dok će Turbo Assembler i program koji ste uneli ostati netaknuti. Razlog je taj što se prilikom startovanja Turbo Assemblera poremete neka osnovna podešavanja sistema, pa neke BASIC naredbe neće raditi ispravno (npr. PEEK) ili će se pokazati da nema dovoljno memorije ako želite da unesete BASIC program.
Da biste iz BASIC-a pokrenuli vaš mašinski program, kucajte SYS praćeno adresom početka programa u decimalnom formatu (npr. SYS 4096). Da biste se vratili u Turbo Assembler i vaš izvorni program, kucajte SYS 333 ili SYS 36864.
Vrste indeksiranja
Kao što smo već rekli u prethodnim lekcijama, ne postoje šesnaestobitni registri koji bi obuhvatili celokupnu memoriju računara i koji bi se mogli automatski povećavati ili smanjivati. To je bitno za manipulaciju svim memorijskim blokovima (0-65535 / $0-$FFFF). Zbog toga postoje preindeksirano i postindeksirano indeksiranje.
Sa ovim imamo ukupno pet vrsta indeksiranja (neposredno, nulta strana, apsolutno, preindeksirano i postindeksirano). Pokazaćemo ih pomoću naredbe LD (učitavanje vrednosti u akumulator/registar). Naravno, i druge naredbe, poput ST (smeštanje vrednosti iz registra u memorijske lokacije), mogu koristiti ova indeksiranja:
LDA #a– neposredno – direktno se unosi osmobitni broj argumentaau akumulator.LDA n– nulta strana – osmobitni broj argumentaniz memorije$0-$FF(nulte strane memorije) unosi se u akumulator.LDA n,X– nulta strana uvećana za X – osmobitni broj argumentaniz memorije0-FFuvećane za vrednost registra X unosi se u akumulator.LDA ap– apsolutno – osmobitni broj argumentaapiz memorije$0-$FFFF(celokupne memorije) unosi se u akumulator.LDA ap,X– apsolutno – osmobitni broj argumentaapiz memorije$0-$FFFFuvećane za vrednost registra X unosi se u akumulator.LDA ap,Y– apsolutno – osmobitni broj argumentaapiz memorije$0-$FFFFuvećane za vrednost registra Y unosi se u akumulator.LDA (pr,X)– preindeksirano – osmobitni broj, iz vrednosti memorije$0-$FFargumentaprza niži bajt uvećan za registar X ipr+1za viši bajt uvećan za registar X (ova dva bajta mogu sadržati vrednost celokupne memorije0-65535/$0-$FFFF), unosi se u akumulator.LDA (po),Y– postindeksirano – osmobitni broj, iz vrednosti memorije$0-$FFargumentapoza niži bajt ipo+1za viši bajt (ova dva bajta mogu sadržati vrednost celokupne memorije0-65535/$0-$FFFF) uvećane za vrednost registra Y, unosi se u akumulator.
Ova indeksiranja smo radili u prethodnim lekcijama, osim preindeksiranog i postindeksiranog, koje ćemo upoznati u današnjoj lekciji.
Matematičke operacije (sabiranje i oduzimanje)
Sabiranje (ADC)
ADC #broj/adresa – sabiranje sadržaja akumulatora sa osmobitnim brojem ili vrednosti memorijske lokacije i vrednosti C-bita (prenos prekoračenja) registra stanja procesora.
Pre sabiranja treba dati naredbu CLC koja resetuje C-bit prenos prekoračenja registra stanja procesora na nulu.
Evo kako sabiranje funkcioniše:
*= $1000 ; Krećemo kompajliranje asemblera od $1000 (4096)
LDA #$00 ; Učitavamo nulu u akumulator
STA $04 ; Stavljamo vrednost iz akumulatora u memorijsku adresu 4
LDA #$05 ; Stavimo 5 u akumulator A (prvi sabirak)
STA $02 ; Smestimo vrednost iz akumulatora u memorijsku adresu 2
LDA #$F9 ; Stavimo $F9 (249) u akumualtor A (drugi sabirak)
STA $03 ; Smestimo vrednost iz akumulatora u memorijsku adresu 3
LDA $02 ; Učitajmo vrednost iz memorijske adrese 2 u akumulator
CLC ; Obrišimo C-prenosni bit
ADC $03 ; Sabiranje: akumulator + memorijska adresa 3 + C-bit
STA $04 ; Vrednost akumulatora smeštamo u memorijsku adresu 4
RTS ; Kraj programa
Kompajliranjem i pokretanjem ovog programa, a zatim proverom sa PRINT PEEK(4), videćete vrednost 254 (5 + 249).
Primer sa prekoračenjem:
*= $1000
LDA #$00 ; Nula u akumulator
STA $04 ; Adresa 4 će biti niži bajt zbira
STA $05 ; Adresa 5 će biti viši bajt zbira
LDA #$14 ; $14 (20) u akumulator
STA $02 ; Prvi sabirak u adresi 2
LDA #$FA ; $FA (250) u akumulator
STA $03 ; Drugi sabirak u adresi 3
LDA $02 ; Učitaj vrednost iz adrese 2 u akumulator
CLC ; Obriši C-bit
ADC $03 ; Saberi sa vrednošću iz adrese 3
STA $04 ; Rezultat (niži bajt) ide u adresu 4
LDA #$00 ; Učitaj nulu u akumulator
ADC #$00 ; Saberi sa nulom i dodaj C-bit (prenos iz prethodnog sabiranja)
STA $05 ; Rezultat (viši bajt) ide u adresu 5
RTS ; Kraj programa
Nakon pokretanja, PRINT PEEK(4) + PEEK(5) * 256 će prikazati 14 + 1 * 256 = 270. BASIC ekvivalent je jednostavan: PRINT 20 + 250.
Oduzimanje (SBC)
SBC #broj/adresa – oduzimanje od sadržaja akumulatora datog osmobitnog broja ili sadržaja memorijske lokacije i vrednosti C-bita registra stanja procesora.
Pre oduzimanja treba dati naredbu SEC koja setuje C-bit prenos prekoračenja registra stanja procesora na jedinicu.
Evo kako oduzimanje funkcioniše:
*= $1000 ; Početak programa na $1000
LDA #$00 ; Nula u akumulator
STA $04 ; Adresa 4 će sadržati razliku
LDA #$F9 ; Učitavamo $F9 (249) u akumulator (umanjenik)
STA $02 ; Smestimo vrednost u adresu 2
LDA #$05 ; Stavimo 5 u akumulator (umanjilac)
STA $03 ; Smestimo vrednost u adresu 3
LDA $02 ; Učitajmo vrednost iz adrese 2 u akumulator
SEC ; Setuj C-prenosni bit
SBC $03 ; Oduzimanje: akumulator - vrednost iz adrese 3 - (1-C)
STA $04 ; Vrednost akumulatora smeštamo u adresu 4
RTS ; Kraj programa
Nakon pokretanja, PRINT PEEK(4) će prikazati 244 (249 – 5).
Primer oduzimanja šesnaestobitnih brojeva:
*= $1000
LDA #$16 ; Učitavamo niži bajt umanjioca ($16)
STA $02 ; Smestamo u adresu 2
LDA #$0A ; Učitavamo viši bajt umanjioca ($0A)
STA $03 ; Smestamo u adresu 3
LDA #$11 ; Učitavamo niži bajt umanjenika ($11)
STA $04 ; Smestamo u adresu 4
LDA #$B0 ; Učitavamo viši bajt umanjenika ($B0)
STA $05 ; Smestamo u adresu 5
SEC ; Setujemo C-bit za oduzimanje
LDA $04 ; Učitavamo niži bajt umanjenika ($11) u akumulator
SBC $02 ; Oduzimamo niži bajt umanjioca ($16)
STA $04 ; Smeštamo razliku u adresu 4
LDA $05 ; Učitavamo viši bajt umanjenika ($B0) u akumulator
SBC $03 ; Oduzimamo viši bajt umanjioca ($0A)
STA $05 ; Smeštamo razliku u adresu 5
RTS ; Kraj programa
Naredbom PRINT PEEK(4) + PEEK(5) * 256 dobićemo 251 + 165 * 256 = 42491. Ovo odgovara oduzimanju $B011 (45073) – $0A16 (2582).
Kao što ste videli, programiranje u asembleru je zahtevnije od BASIC-a, ali se isplati zbog neprikosnovene brzine izvršavanja i drastično manjeg zauzeća memorije.
Naredbe za poređenje
Naredbe za poređenje su veoma važne za stvaranje petlji i uslovnih skokova. Ove naredbe direktno utiču na N, Z i C bitove registra procesora.
CMP #broj/adresa– poređenje sadržaja akumulatora A sa brojem ili vrednosti memorijske lokacije.A = broj/sadržaj adrese-> Z-bit je setovanA > broj/sadržaj adrese-> C-bit je setovanA < broj/sadržaj adrese-> N-bit je setovan
CPX #broj/adresa– poređenje sadržaja registra X sa brojem ili vrednosti memorijske lokacije.X = broj/sadržaj adrese-> Z-bit je setovanX > broj/sadržaj adrese-> C-bit je setovanX < broj/sadržaj adrese-> N-bit je setovan
CPY #broj/adresa– poređenje sadržaja registra Y sa brojem ili vrednosti memorijske lokacije.Y = broj/sadržaj adrese-> Z-bit je setovanY > broj/sadržaj adrese-> C-bit je setovanY < broj/sadržaj adrese-> N-bit je setovan
Naredbe za uslovne skokove
Naredbe za uslovne skokove u potpunosti zavise od stanja bitova u registru procesora:
BNE adresa– skok ako je Z-bit (indikator nule) resetovan (Z=0).BEQ adresa– skok ako je Z-bit setovan (Z=1).BCC adresa– skok ako je C-bit (prenos prekoračenja) resetovan (C=0).BCS adresa– skok ako je C-bit setovan (C=1).BPL adresa– skok ako je N-bit (negativni znak) resetovan (N=0).BMI adresa– skok ako je N-bit setovan (N=1).BVC adresa– skok ako je V-bit (premašenje u rezultatu) resetovan (V=0).BVS adresa– skok ako je V-bit setovan (V=1).
Ekvivalenti BASIC naredbi:
IF A=0 THEN GOTO-> BEQIF A<>0 THEN GOTO-> BNEIF A<M THEN GOTO-> BMIIF A>=M THEN GOTO-> BPLIF X=0 THEN GOTO-> CPX, BEQIF X<>0 THEN GOTO-> CPX, BNEIF X<M THEN GOTO-> CPX, BMIIF X>=M THEN GOTO-> CPX, BPLIF Y=0 THEN GOTO-> CPY, BEQIF Y<>0 THEN GOTO-> CPY, BNEIF Y<M THEN GOTO-> CPY, BMIIF Y>=M THEN GOTO-> CPY, BPL
Primeri punjenja ekrana
Primer 1: Ispunjenje ekrana pomoću preindeksiranog indeksiranja
*= $1000 ; Pocinjemo na $1000
LDA #$00 ; Ucitavamo 0 u akumulator za nizi bajt
STA $02 ; Smestamo u memorijsku lokaciju 2
LDA #$04 ; Ucitavamo 4 u akumulator za visi bajt
STA $03 ; Smestamo u memorijsku lokaciju 3
LDX #$00 ; Ucitavamo 0 u registar X
LDA #$01 ; Ucitavamo 1 (kodna vrednost za 'a') u akumulator
OPET:
STA ($02,X) ; Stavljamo 'a' na adresu iz $02/$03 uvecanu za X
INC $02 ; Uvecavamo nizi bajt adrese za 1
BNE OPET ; Skacemo dok nizi bajt ne bude 0 (ciklus 0-255)
INC $03 ; Uvecavamo visi bajt adrese za 1
LDY $03 ; Ucitavamo vrednost viseg bajta u Y
CPY #$08 ; Poredimo Y sa 8
BNE OPET ; Vracamo se dok visi bajt ne bude 8
RTS ; Kraj programa
Primer 2: Ispunjenje ekrana pomoću postindeksiranog indeksiranja
*= $1000 ; Pocinjemo na $1000
LDA #$00 ; Ucitavamo 0 u akumulator za nizi bajt
STA $02 ; Smestamo u memorijsku lokaciju 2
LDA #$04 ; Ucitavamo 4 u akumulator za visi bajt
STA $03 ; Smestamo u memorijsku lokaciju 3
LDY #$00 ; Ucitavamo 0 u registar Y
LDA #$01 ; Ucitavamo 1 (kodna vrednost za 'a') u akumulator
OPET:
STA ($02),Y ; Stavljamo 'a' na adresu iz $02/$03 uvecanu za Y
INY ; Uvecavamo vrednost registra Y za 1
BNE OPET ; Skacemo dok Y ne bude 0 (ciklus 0-255)
INC $03 ; Uvecavamo visi bajt adrese za 1
LDX $03 ; Ucitavamo vrednost viseg bajta u X
CPX #$08 ; Poredimo X sa 8
BNE OPET ; Vracamo se dok visi bajt ne bude 8
RTS ; Kraj programa
BASIC ekvivalent (primera 1 i 2):
10 FOR I=1024 TO 2023
20 POKE I,1
30 NEXT I
Ovom BASIC programu treba najmanje 5 sekundi da ispuni ekran, što jasno pokazuje ubedljivu nadmoć mašinskog programa.
Poređenje dužina programa:
- Mašinac (primer 2):
$1000-$1019-> 25 bajta - BASIC:
$0803-$082c-> 41 bajt
Primer 3: Ispunjenje ekrana pomoću blokova ekranske memorije
Ovaj program popunjava blokove memorije direktno, ali je manje fleksibilan.
*= $1000 ; Pocetak programa
LDX #$00 ; Registar X je brojac
LDA #$01 ; Vrednost 'a' u akumulatoru
OPET1: ; Prvi blok $0400-$04FF
STA $0400,X
INX
BNE OPET1
OPET2: ; Drugi blok $0500-$05FF
STA $0500,X
INX
BNE OPET2
OPET3: ; Treci blok $0600-$06FF
STA $0600,X
INX
BNE OPET3
OPET4: ; Cetvrti blok $0700-$07FF
STA $0700,X
INX
BNE OPET4
RTS ; Kraj programa
Ovaj pristup je koristan za manji broj blokova, ali je za manipulaciju celokupnom memorijom bolje koristiti preindeksirano i postindeksirano indeksiranje.
Kao što vidite, asemblerski kompajler je daleko nadmoćniji od BASIC interpretera u brzini i efikasnosti.

