...

6502 Assembly Cursus Deel 1

Basic was natuurlijk dé taal om de computer te leren bedienen. Voor velen is het daarbij gebleven en dat is natuurlijk geen probleem. Maar wie er wat meer tijd en moeite voor nam, kon zich de taal der computers meester maken. Ik heb het hier natuurlijk over Machinetaal. Omdat Machinetaal voor velen (inclusief mijzelf) een te grote stap was, gebruikte je het tweede beste; Assmebleertaal of verkort Assembly. Het lijkt misschien erg moeilijk, maar iedereen kan het. Iedereen die het programmeren begrijpt en zijn of haar mouwen op  wil stropen. De kennis was voor mij ook weer helemaal weggezakt en ik ben de boeken in gedoken naar fragmenten die in mijn ogen het beste uitleg boden. Deze stukken heb ik vertaald naar het Nederlands en ik hoop dat er mensen door geïnspireerd raken en met Assembly aan de slag gaan! Deze Assembly introductie behandelt de basis vaardigheden van deze interessante en uitdagende taal.  In het eerste deel van deze cursus, wil ik graag de basis kennis verversen of (nog mooier) vernieuwen! Ik behandel in dit deel de verschillen tussen BASIC, Assembly en Machinetaal. Ook zal ik de onderliggende hardware-componenten kort bespreken en het geheugen van de C64 de revu laten passeren. Omdat ik ergens moet beginnen, en de C64 de meest verkochte computer is, zal de focus van deze cursus op deze computer liggen. Veel van de behandelde onderdelen zijn echter voor meerdere computers uitwisselbaar. Bij het leren van Assembly is het hebben van een gedegen BASIC (of andere programmeerkennis een pré). Ik haal vaak BASIC programma's aan om bepaalde zaken te vergelijken.

19 februari 2024

...

6502 Assembly Cursus Deel 2

De Registers Vorige keer hebben we een korte inleiding gehad op de hardware-laag van de Computer. We grijpen heel even kort terug naar Deel 1, hoe zat het ook alweer? We hebben de verschillen tussen de verschillende formaten Hexadecimaal, Decimaal en Binair behandeld en de manier van omrekenen uitgelegd. Handig om te weten, niet vereist omdat we hiervoor rekenmachines hebben. Ook hebben we het over de Address-, Data en Memorybus gehad. De Addressbus dient als communicatie tussen processor en de chips. De Databus handelt de lees- en schrijfopdrachten van en naar de chips af. De Memorybus bestaat uit ROM (Alleen lezen), RAM (Lezen en Schrijven) en IA (Koppelingen naar buitenwereld).  De verschillende registers binnen de processor zijn kort besproken. Ook hebben we ter afsluiting laten zien hoe deze registers werken en hoe je er informatie in kunt stoppen of uit kunt halen. We hebben hiervoor een klein assembleerprogramma gebruikt. Nu we de basis behandeld hebben van de binnenste werking van de Commodore, ga ik verder met het beschrijven van de registers. We hebben er zes te gaan in dit deel.

24 februari 2024

...

6502 Assembly Cursus Deel 3

Op dit punt heb je als het goed is een aardig idee wat registers zijn en welke de Commodore 64 kent. Vorige keer hebben we ze allemaal behandeld en tevens de daarbij behorende assembly commando's genoemd. Tot zover de theorie. Om de werking van deze commando's (ook wel OPCODES genoemd) te kunnen zien, moeten we nu echt programmaregels gaan invoeren. Om programma's in Assembly te schrijven hebben we een Assembler nodig. Er zijn er een aantal, maar wij gebruiken de Merlin64 Assembler. In de archieven van Arnold is deze terug te vinden via de link: arnold.c64.org/pub/uNls/c64apps/ compiler/Merlin_Assembler.zip In deel drie zullen we de Merlin Assembler zelf behandelen, een basis die je zult moeten beheersen voor het verdere verloop van de cursus. Maar ook deze magie zal de jouwe kunnen zijn met een beetje oefenen en geduld... Merlin is een erg fijne Assembler voor de Commodore 64. Het werkt alleen met een diskdrive en niet met een tapedrive. We zullen de Assembler beetje bij beetje behandelen, omdat het anders meer een manual gaat lijken. De commando's die we het hardst nodig hebben behandelen we het eerste. Om Merlin64 te starten laadt je de Assembler via:                    LOAD "MERLIN*",8 Na het laden start je Merlin64 via het RUN commando. Het kan even duren. Als de Assembler gestart is, sta je automatisch in de zogenaamde "Executive Mode". Deze herken je aan het "%" teken en betekent dat je onderstaand scherm ziet:   Het is een goed idee om een eigen werkdiskette te hebben voor al je experimenten, dus gaan we deze eerst maken. Doe een lege diskette in de drive en kies "X". Je zult een nieuwe prompt zien: "%Command:". Kies hier een "I" en na het drukken op ENTER zal de diskette direct snel geformatteerd worden. Met het commando "C" kun je de inhoud van een diskette opvragen.   Het invoeren van een nieuw programma Voor nu hoeven we niets meer te doen in de "Executive Mode" dus kiezen we "E" waarmee we in de Editor komen (herkenbaar aan de ":") , de prompt verandert in "Editor:". We zijn nu in de "Command Mode" gekomen. Om nu daadwerkelijk programma's te kunnen schrijven kiezen we "A" (Add). Anders dan in BASIC, heeft Merlin64 vier velden, net zoals de meeste Assemblers: LABEL, OPCODE, OPERAND, COMMENT. Met elke druk op de SPATIEBALK spring je naar het volgende veld, met ENTER ga je naar de volgende regel. De OPCODE en OPERAND velden zijn de belangrijkste. Als we sprongen gaan maken in onze programma's zal het LABEL veld onmisbaar blijken. Om te beginnen, gaan we onderstaand regels invoeren met de OPCODE en OPERAND velden: LN# LABEL OPCODE OPERAND COMMENT1 JSR $E5442 RTS Stap 1: Kies (als dit nog niet gedaan is) de "A" om regels in te kunnen voerenStap 2: Druk op de SPATIEBALK om het LABEL veld leeg te laten en naar het OPCODE veld te springen. Vul hier "JSR" in.Stap 3: Druk op de SPATIEBALK om naar het OPERAND veld te springen en vul hier "$E544" in. Op dit adres staat de clear-­‐screen instructie.Stap 4: Druk op ENTER om naar de volgende regel (2) te gaan.Stap 5: Druk op de SPATIEBALK om naar het OPCODE veld te gaan en vul daar "RTS" in.Stap 6: Druk tweemaal op ENTER. De eerste maal om naar de volgende regel te springen en de tweede maal om een uit de "Add Mode" te gaan en terug in de "Command Mode" te komen. Gefeliciteerd! Je hebt je eerste Assembly programma geschreven. Deze staat ingevoerd in de editor maar om het uit te kunnen voeren moet je het assembleren. Dit doe je met behulp van het commando "ASM" en op ENTER te drukken. Er zal een vraag op het scherm komen "Update source (Y/N)?", welke je met "N" mag beantwoorden. Het resultaat zal gelijk moeten zijn aan de schermafdruk hiernaast -­‐ en dat is goed. Nog een mijlpaal, want je hebt zojuist je eerste, zelfgemaakte programma, geassembleerd. Een belangrijk gegeven is dat dit programma op geheugenplaats $8000 begint, zoals het scherm laat zien. Hier staat dus de zogenaamde objectcode (geassembleerd programma) staat. De decimale waarde van $8000 is 32768. Deze waarde hebben we nodig om ons programma vanuit BASIC te kunnen starten met het commando: SYS 32768. Het programma is gemaakt, geassembleerd en klaar voor opslag. Net als BASIC zullen programma's verloren gaan na het uitzeKen van de computer. Om dit programma op onze vers aangemaakte werkdiskeKe op te slaan drukken we nu eerst op "Q" om de "Command Mode" te verlaten en terug te keren in de "Executive Mode". Tik bij de % prompt nu de "S" om het programma op te slaan. Als het goed is zit je werkdiskette in de drive (mooi moment om dit even te checken). Geef als naam "clear" op, want dat is precies wat het programma zal doen als we het draaien -­‐ het scherm schoonmaken. Je ziet "Saving clear.s" staan en na het opslaan zal dit bestand op de diskette bijgeschreven zijn. Wat je nu opgeslagen hebt is niet iets wat je direct kunt starten, je hebt een zogenaamd "sourcefile" opgeslagen. In dit bestand (dat altijd eindigt op ".s") staan de regels die je in de Editor hebt ingevoerd. De geassembleerde code (objectcode) is niet opgeslagen. Om de geassembleerde code op te slaan, druk je op de letter "O" en zal automatisch de naam van je sourcefile verschijnen, omdat je deze hiervoor opgeslagen hebt en Merlin64 ervan uitgaat dat je hiervan de objectcode zal willen opslaan. Je hebt nu dus je source­‐ en objectcode opgeslagen op je werkdiskette. Als je via het "C" commando de inhoud van de diskette bekijkt, vind je dus de "clear.s" en "clear.o" bestanden. In het scherm is nog wat gebeurd. Als het goed is staat in het scherm een nieuwe regel met het adres van de objectcode, direct onder het adres van de sourcecode. Altijd handig om om te weten. Laten we uit de "Executive Mode" gaan via "Q" waarna het scherm schoongemaakt wordt en Merlin64 ons nog herinnert dat we via SYS 52000 weer terug in de Assembler kunnen komen. Toen we via het "ASM" commando ons programma assembleerde, werd dit voor ons op adres $8000 gezet, waarmee we het via SYS 32768 kunnen starten. Als alles goed gegaan is, zal het scherm schoongemaakt worden zodra je het sys commando invoert en op ENTER drukt. En zo heb je dus je eerste programma in een Assembler ingevoerd, geassembleerd, opgeslagen en vanuit BASIC gestart! Tijd voor koffie.   Het bewerken van het bronbestand Tik na de koffie SYS 52000 om weer terug in de Assembler te komen. Als de computer in de tussentijd niet uitgezet is en er geen andere programma's geladen zijn kun je nu via de "E" toets in de editor komen. (Is dit wel het geval, dan kun je het bronbestand vanuit de "Executive Mode" laden -­‐ hierover later meer). Vanuit het Editor menu of "Command Mode" heb je nu de beschikking over de volgende keuzes: L Geeft een Listing vna je broncode A Voeg regels toe op de eerstvolgende regel I# Voeg regels toe op het opgegeven nummer # D# Verwijder regel nummer # E# Bewerk regel nummer # PORT# Selekteert de printer als output poort # PRTR# Stuurt de listing naar printer met als output poort # F Zoek naar een stuk tekst in de listing C Verander tekst M Verplaats regels broncode R Verplaats regels in een bereik naar een andere selectie NEW Verwijderd de brondcode uit het geheugen   L(ist) Dit commando geeW de listing van het bronbestand weer. Als je later langere programma's gaat schrijven is het handig als je een listing kunt onderbreken (of je moet razend snel leren lezen). Als je op de SPATIEBALK drukt tijdens de listing, kun je het scrollen onderbreken en vervolgens (met dezelfde toets) regel voor regel door de listing lopen. Met RETURN hervat het scrollen weer op de normale snelheid. A(dd) Toen we onze eerste regels in gingen voeren, drukte we hiervoor op de "A" toets. We werden automatosch op regel 1 gezet. Als je broncode in het geheugen staat, brengt deze toets na naar de eerstvolgende beschikbare vrije regel (in het geval van het "clear" programma dus regel 3). I(nsert) Dit commando gebruiken we om een regel tussen te voegen. Met twee regels in het geheugen kunnen we via het commando "I1" een regel tussenvoegen. Voeg bijvoorbeeld eens "ORG $C000" toe. Druk daarna tweemaal op RETURN om terug op de prompt te komen en met "L" zou de listing er dan als volgt uit moeten zien: 1 ORG $C000 2 JSR $E544 3 RTS De ORG instructie wordt zogenaamde "Pseudo code" genoemd. Dit betekent dat deze opdracht niet geassembleerd wordt (d.m.v. ASM), maar het vertelt de assembler waar je programma moet beginnen. Doe je dit niet, dan zet Merlin64 je programma standaard op $8000. Let er wel op dat de ORG instructie de eerste regel van je programma is! Naarmate je meer gaat programmeren zul je merken dat je de I(nsert) functie erg vaak zult gebruiken. D(elete)# Dit is een gemakkelijk commando om te gebruiken. Je voert een "D" in, direct gevolgd door het regelnummer dat je wilt verwijderen en drukt op RETURN. "D1" verwijdert dus de eerste regel. Je kunt ook meerdere regels tegelijk verwijderen. "D1,2" verwijdert regel 1 tot en met regel 2. Hiermee verwijder je dus een bereik. E(dit)# Om een regel te bewerken gebruik je het "E" commando gevolgd door het betreffende regelnummer. Wil je bijvoorbeeld de eerste regel bewerken, voer je "E1" in gevolgd door RETURN. Druk nu op de SPATIEBALK om naar de instructie te springen en de cursustoetsen om één karakter te verspringen. Met RETURN kom je terug in de "Command Mode". In Edit mode heb je een aantal CTRL commando's ter beschikking die de moeite waard zijn om te leren: CTRL + I Voeg één karakter in CTRL+D Verwijder één karakter CTRL + D Verwijder één karakter CTRL + F Zoek een karakter CTRL + O Lijkt op CTRL + I maar deze voegt een control karakter in CTRL + P Zet een regel met sterretjes op het scherm. Druk je eerst op de spatiebalk dan krijg je sterretjes aan elke kant van de regel CTRL + B Springt naar het begin van een regel CTRL + N Springt naar het begin van een regel CTRL + R Herstelt de huidige regel naar zijn originele staat CTRL + A Schoont de huidige regel vanaf de cursor naar rechts STOP/RUN Verlaat EDIT MODE zonder de regel te veranderen   PORT# / PRTR# Als je een printer aangesloten hebt, kun je de uitvoer van je programma niet naar het scherm maar naar de printer sturen met het PORT commando of de listing afdrukken via het PRTR commando. F(ind) Als je een uitgebreid programma geschreven hebt, is het vaak handig om bepaalde zoekopdrachten uit te voeren. Met bijvoorbeeld F"JSR" krijg je alle regels te zien van het programma waarin het JSR commando voorkomt. Met F5,9"JSR" worden alle regels tussen 5 en 9 getoond waarin het JSR commando staat. C(hange) Dit is de Assembleer-­versie van de Zoek‐en‐Vervang opdracht. Stel je wilt alle JMP commando's van je programma vervangen door JSR commando's, dan kun je dit doen met het commando C"JMP"JSR". Let erop dat je slechts gebruik maakt van drie (!) aanhalingstekens. Nadat je op RETURN gedrukt hebt, zal Merlin64 je vragen of je alle (A) of sommige (S) veranderingen wil doorvoeren. Bij de laatste optie zul je elke aanpassing afzonderlijk moeten goedkeuren. COPY Het zal in de toekomst voorkomen dat je bepaalde regels van je programma weer wilt gebruiken. Om te voorkomen dat je deze regels opnieuw in moet tikken, kun je het COPY commando gebruiken. Met COPY 1 TO 2 zal de eerste regel voor de tweede gekopieerd worden. Als de regel waarnaar je kopieert reeds bestaat, zal deze een regel zakken en wordt de gekopieerde regel tussengevoegd. Omgekeerd kan natuurlijk ook: COPY 3 TO 1 zal ervoor zorgen dat regel 3 naar regel 1 gekopieerd wordt. (Waardoor regel drie zal veranderen in regel 4 vanwege de ingevoegde regel op 1). Dit commando werkt echter ook met een opgegeven bereik. COPY 10,20 TO 33 zal ervoor zorgen dat de regels van 10 t/m 20 gekopieerd worden vanaf regel 33. MOVE Het broertje van COPY is MOVE, met het verschil dat dit commando de regels daadwerkelijk verplaatst en niet kopieert. De werking van het MOVE commando is verder identiek aan dat van COPY. Met MOVE 5 TO 3 zal regel 5 verplaatst worden naar de derde positie, waardoor regels vier en hoger een regel naar beneden zakken. R(eplace)# Het replace commando roept de opgegeven regel op en zet je vervolgens in de insertmodus (gelijk aan CTRL+I) zodat je de regel kunt overschrijven. NEW Wist het huide bronbestand. Let op: De geassembleerde code blijven bestaan in het geheugen. Tenslotte zijn er nog wat algemeen geldende regels. Zoals bijvoorbeeld de regel dat alle commando's in hoofdletters geschreven moeten worden. Met behulp van de F7 toets is het mogelijk om te schakelen tussen hoofdletters en kleine letters. Maar een nog niet genoemd belangrijk commando is het omrekenen van decimale naar hexadecimale nummers (en vice versa) vanuit de "Command Mode". Omrekenen van Hexadecimaal naar Decimaal doe je door het hexadecimale getal op de ":" prompt in te Fkken en op RETURN te drukken. :$C000 <RETURN> 49152 = -16384 Je kunt een programma op $C000 dus starten met SYS49152 of SYS16384. Om van Decimaal naar Hexadecimaal om te rekenen doe je het omgekeerde: :1234 <RETURN> $04D2 Het is verstandig om veel met bovenstaande commando's te experimenteren, want je zult ze vaak nodig hebben tijdens het programmeren! Zeker als we de volgende keer verder gaan met deel 4 van deze cursus!

25 februari 2024

...

6502 Assembly Cursus Deel 4

Nu we weten wat er in de computer zit, de registers behandeld hebben en vorige keer een assembler besproken hebben, kunnen we nu aan de slag gaan om echt wat met de registers te gaan doen. Dit zal ik doen met veel voorbeelden, zodat het een en ander duidelijker wordt.  De voorbeelden die in dit deel genoemd worden kun je in de assembler invoeren en uitproberen. Zo krijg je een beter begrip van de commando's en leer je de Assembler kennen. Vorige keer hebben we de Merlin assembler besproken, maar je bent natuurlijk vrij in het gebruik van je eigen voorkeur.  De komende delen zullen de eerder besproken commando's vanzelf voorbij komen en als leidraad dienen, waar ik beetje bij beetje meer theorie en achtergrond informatie aan toe zal voegen! Zoals eerder gezegd, het hart van de 6510 is de Accumulator waar bijna alle gegevens doorheen gaan. Het is een opslagplaats van acht bits waar je een getal tot maximaal 255 in kunt stoppen. We gaan nu een aantal commando's uit het vorige deel gebruiken voor het laden en verplaatsen van data.     OPCODE OPERAND LDA #0 (Laad het decimale getal 0 in de Accumulator)STA 1024 (Zet inhoud van de Accumulator op geheugenadres 1024) STA 55296 (Zet inhoud van Accumulator op geheugenadres 55296) RTS (Keer terug vab de Subroutine naar BASIC) END Bovenstaande listing zal na het uitvoeren een zwarte "@" in de linkerbovenhoek van het scherm afdrukken, en toch, het enige wat we feitelijk gedaan hebben is het getal "0" op twee plaatsen in het geheugen geplaatst! Dit heeft te maken met wáár we de waarde plaatsen. Als deze geheugenlocatie tussen de 1024 en 2023 ligt, wordt de waarde op het scherm getoond. Met andere woorden, door een nul te stoppen op geheugenadres 1024 zal de inhoud van geheugenadres linksboven op het scherm getoond worden. De reden hiervoor heeft te maken met de manier waarop de Commodore 64 VIC chip het scherm opbouwt. Het scherm is opgebouwd uit 25 rijen van 40 vakjes (samen precies 1000), zoals hieronder weergegeven wordt. Elk vakje heeft zijn eigen geheugenadres. De eerste rij, bijvoorbeeld, begint op geheugen adres 1024 (he daar is ie) en loopt tot en met adres 1063. De allerlaatste rij eindige tenslotte op 2023, de laatste positie op het scherm helemaal rechts onderin. Nu het duidelijk is, waarom er iets op de eerste positie van het scherm getoond wordt als we iets in adres 1024 zetten, komt de volgende vraag: Waarom wordt een "@" getoond? Dat heeft dus te maken met wát we op geheugenadres 1024 zetten. Zoals eerder gezegd kan het een waarde van 0 tot 255 zijn. In een kleurenadres stelt elk van deze 256 waarden (de nul telt ook mee) een karakter voor. Je kunt dus 256 verschillende karakters op een positie op het scherm laten verschijnen, afhankelijk van welke waarde je op adres 1024 t/m 2023 zet. Op de volgende pagina staat een karaktertabel, waarbij je kunt zien welk karakter welke waarde voorstelt.  Bovenstaande tabel laat, voor de oplettende lezer, slechts 128 verschillende karakters zien (0 - 127), terwijl ik het dubbele aantal beloofd had. Dat komt doordat de waardes 128 t/m 255 de inverse versies zijn van de boven getoonde karakters. Je ziet hierboven bij de nul het karakter "@" staan. Hadden we een hoofdletter D gewild, dan hadden we de waarde "4" gebruikt en voor het cijfer acht de waarde "56". Nu weten we dus waarom de "@" in de linkerbovenhoek van het scherm getoond werd. We zette met ons programma een de waarde 0 (@) op geheugenadres 1024. Maar ik moet nog één ding vertellen over kleuren. Als je een waarde direct op het scherm zet, dien je de computer ook te vertellen welke kleur hij moet weergeven. Doe je dit niet, dan laat je de kleurbepaling van het karakter volledig aan de willekeur over, met het risico dat het karakter dezelfde kleur krijgt als de achtergrond. Elke van de 1000 video adressen heeft een bijbehorend kleurenadres, die in de tabel hieronder weergegeven wordt. Je ziet dezelfde layout als bij de video adressen. Elke vakje kan een waarde 0 t/m 15 bevatten, waarbij de waarde overeenkomt met de kleur, die je waarschijnlijk vanuit BASIC nog kent: 0 - Zwart 8 - Oranje 1 - Wit 9 - Bruin 2 - Rood 10 - Licht Rood 3 - Cyaan 11 - Donker Grijs 4 - Paars 12 - Midden Grijs 5 - Groen 13 - Licht Groen 6 - Blauw 14 - Licht Blauw 7 - Geel 15 - Licht Grijs   Dus door een waarde nul te zetten op geheugen adres 55296 krijgt het karakter dat op de eerste positie op het scherm (1024) staat de kleur die bij die opgegeven waarde (zwart) hoort. Wat we nu geleerd hebben is om een karakter, in een bepaalde kleur, op een bepaalde positie op het scherm te zetten. Met deze kennis, zou ik mijn voornaam (Addy) dus in het rood op het scherm kunnen zetten met het volgende programma: OPCODE OPERAND LDA    #1 (Laad decimale getal 1 in Accumulator, dit wordt dus de "A") LDY    #2 (Ik gebruik het Y register om de kleur rood in op te slaan) STA    1024 (Zet een A op de eerste positie van het scherm) STY    55296 (Zorg dat de A de kleur rood krijgt vanuit het Y register) LDA    #4 (Laad decimale getal 4 in de Accumulator, dit wordt dus de "D") STA    1025 (Zet een D op de tweede positie van het scherm) STY    55297 (Zorg dat de D de kleur rood krijgt vanuit het Y register) STA    1026 (Zet een D op de derde positie van het scherm) STY    55298 (Zorg dat de D de kleur rood krijgt vanuit het Y register) LDA    #25 (Laad het decimale getal 25 in de Accumulator, dit wordt de "Y") STA    1027 (Zet een Y op de tweede positie van het scherm) STY    55299 (Zorg dat de Y de kleur rood krijgt vanuit het Y register) RTS    (Keer terug uit naar de Subroutine naar, in dit geval, BASIC) END Wat opvalt, is dat ik het Y register eenmaal vul met de waarde 2 (rood) en deze steeds hergebruik. Ook laad ik de "D" maar eenmaal, en gebruik ik deze tweemaal. Als je het aandurft, doe dan hetzelfde met jouw naam. In sommige Assemblers laad je een decimale waarde met het commando LDAIM (LaaD Accumulator IMmediately) gevolgd door het cijfer zonder "#".  Je snapt dat het bovenstaande voorbeeld wel een heel omslachtige manier is om een woordje op het scherm te krijgen en natuurlijk gaan we dit later makkelijker doen. Het gaat er nu enkel om dat je begrijpt hoe je het LDA en STA commando's gebruikt. We hadden hier de commando's LDA, LDX of LDY door elkaar heen kunnen gebruiken, omdat we geen rekenkundige bewerkingen uit hoefde te voeren (zoals optellen e.d). Daar gebruik je normaliter de Accumulator voor en de X/Y registers gebruik je voor het verplaatsen van data. Maar je ziet, het maakt voor de laad commando's in dit geval niets uit. Tevens hebben we in dit deel gezien dat je adressen kunt voorzien van een waarde, die direct iets uitvoert (in dit geval op het scherm). De kleuren manipuleer je door in de kleuren adressen 55296 t/m 56295 een waarde van 0 t/m 15 te laden. De positie van het scherm kun je vullen door een waarde van 0 t/m 255 te laden op adressen 1025 t/m 2023. Volgende keer gaan we wat berekeningen doen, waardoor we nog leukere voorbeelden kunnen aanhalen. Maar omdat je door verschillende karakters naar het scherm te sturen gelijk het resultaat ziet, zullen in de komende delen voorbeelden als deze steeds weer terugkomen om andere commando's te demonstreren. Ik daag daarom iedereen uit om met behulp van de voorbeelden uit dit deel te gaan experimenteren om karakters op het scherm te toveren in willekeurige kleuren.  Wat opvalt, is dat ik het Y register eenmaal vul met de waarde 2 (rood) en deze steeds hergebruik. Ook laad ik de "D" maar eenmaal, en gebruik ik deze tweemaal. Als je het aandurft, doe dan hetzelfde met jouw naam. In sommige Assemblers laad je een decimale waarde met het commando LDAIM (LaaD Accumulator IMmediately) gevolgd door het cijfer zonder "#".  Je snapt dat het bovenstaande voorbeeld wel een heel omslachtige manier is om een woordje op het scherm te krijgen en natuurlijk gaan we dit later makkelijker doen. Het gaat er nu enkel om dat je begrijpt hoe je het LDA en STA commando's gebruikt. We hadden hier de commando's LDA, LDX of LDY door elkaar heen kunnen gebruiken, omdat we geen rekenkundige bewerkingen uit hoefde te voeren (zoals optellen e.d). Daar gebruik je normaliter de Accumulator voor en de X/Y registers gebruik je voor het verplaatsen van data. Maar je ziet, het maakt voor de laad commando's in dit geval niets uit. Tevens hebben we in dit deel gezien dat je adressen kunt voorzien van een waarde, die direct iets uitvoert (in dit geval op het scherm). De kleuren manipuleer je door in de kleuren adressen 55296 t/m 56295 een waarde van 0 t/m 15 te laden. De positie van het scherm kun je vullen door een waarde van 0 t/m 255 te laden op adressen 1025 t/m 2023. Volgende keer gaan we wat berekeningen doen, waardoor we nog leukere voorbeelden kunnen aanhalen. Maar omdat je door verschillende karakters naar het scherm te sturen gelijk het resultaat ziet, zullen in de komende delen voorbeelden als deze steeds weer terugkomen om andere commando's te demonstreren. Ik daag daarom iedereen uit om met behulp van de voorbeelden uit dit deel te gaan experimenteren om karakters op het scherm te toveren in willekeurige kleuren. 

25 februari 2024

...

6502 Assembly Cursus Deel 5

Als je programma's schrijft, ontkom je er niet aan om zo af en toe een sprong terug of naar voren te maken. Vergelijkbaar met BASIC heeft Assembly deze natuurlijk ook.  Maar Assembly heeft ook een eigen register dat bijhoudt welke regel momenteel wordt uitgevoerd. Na dit deel zul je dus naast de reeds bekende A, Y en X registers ook kennis gemaakt hebben met het programcounter (PC) register! Er zijn maar weinig programma's die alle opdrachten van voren naar achteren afwerken zonder ergens te springen of te vertakken. In dit deel behandelen we twee technieken van verspringen. Ook het register dat die de sprongen controleert en bijhoudt laten we kort de revu passeren. Onvoorwaardelijke sprongen Een onvoorwaardelijke sprong doet precies wat zijn naam zegt; spring naar een ander deel van het programma zonder verder ergens naar te kijken. Er zijn dus geen voorwaarden aan verbonden. Sprongen zijn met name handig om bepaalde stukken code te hergebruiken. Door bijvoorbeeld een stuk muziek wat in het geheugen staat op verschillende momenten aan te kunnen roepen. Er bestaan slechts twee onvoorwaardelijke 6510 opdrachten: JMP - JuMP JSR - Jump naar SubRoutine BASIC vertaling van GOTO = JMP In BASIC kon je met behulp van het GOTO commando door je hele programma heen springen, naar voren en naar achteren. In Assembly gebruiken we hier JMP voor. We kunnen het JMP commando het beste demonstreren aan de hand van een voorbeeld (startadres is 828): OPCODE OPERAND LDAIM  #1    (Laad 1 in register A) JMP    834   (Spring naar geheugenadres 834) RTS          (Spring terug - in dit geval terug naar BASIC) STA    1024  (Zet de inhoud van A op adres 1024) STA    55296 (Zet de inhoud van A op adres 55296) JMP    833   (Spring naar geheugenadres 833) END Wat hier gebeurt is dat er direkt naar de STA 1024 gesprongen wordt, over de RTS heen. Bovenstaande voorbeeld is natuurlijk weinig zinvol, maar dient louter ter demonstratie van het JMP commando. Het zou bijvoorbeeld gebruikt kunnen worden om later een stukje coding "in te voegen". Vergeet niet dat het voor de snelheid niet uitmaakt waar je regels staan. Je kunt zonder snelheidsverlies van hot naar hen springen. Bovendien waren de editors vroeger niet zo gebruikersvriendelijk, en het was vaak makkelijker/sneller om achteraf een sprong te maken naar extra coding in plaats van coding tussen te voegen. Zoals je aan dit schema hiernaast kunt zien is dat precies wat we met het voorbeeld aantonen. Dit (stroom)schema is een grafische vertaling van het Assembly programma hierboven. Dit laat duidelijk zien hoe het verloop van de code is.  Het programma drukt overigens een witte "A" af in de linker bovenhoek, maar na Deel 4 had je dat natuurlijk al zelf gezien. Als je dus het JMP commando gebruikt, zul je precies moeten vertellen waarheen er gesprongen moet worden, er moet een adres opgegeven worden. Ook om weer terug te komen op de originele plek zul je dus een JMP commando moeten gebruiken. Het heen springen zal mischien niet zo schokkend zijn, maar hoe kom je nu weer precies terug op de regel na je originele sprong? Met andere woorden, hoe weet je dat je naar geheugenadres 833 moet springen zoals in ons voorbeeld? Adressen berekenen Alle OPCODES hebben een bepaalde grote, ze nemen precies 1 byte in beslag. De OPERAND neemt ook geheugen in beslag, alleen de bepaling daarvan is iets ingewikkelder. Dit is een kwestie van weten of opzoeken, raak dus niet in paniek. Als je een geheugenadres in een OPERAND gebruikt (zoals bij JMP en STA) kost dat 2 bytes extra omdat een geheugenadres getallen kan bevatten die groter zijn dan de 255 die in één byte passen. (1 byte = 8 bits en kan maximaal de waarde 255 bevatten weten we uit Deel 1) Ons programma begint op geheugenadres 828. Voor het gemak zullen we de geheugen adressen voor de coding zetten: ADRES OPCODE OPERAND GEBRUIKT 828   LDAIM  #1      (828 plus 1 byte voor "#1") 828 t/m 829 830   JMP    834     (830 plus 2 bytes voor het adres "834") 830 t/m 832 833   RTS            (geen operant, dus geen extra bytes) 833 t/m 833 834   STA    1024    (834 plus 2 bytes voor het adres "1024") 834 t/m 836 837   STA    55296   (837 plus 2 bytes voor het adres "55296") 837 t/m 839 840   JMP    833     (840 plus 2 bytes voor het adres "833") 840 t/m 842 END Om dus over (voorbij) RTS te springen, springen we van geheugenadres 830 naar 834. We springen hierbij dus over adres 833 waar RTS staat. Zoals eerder gezegd, gewoon opzoeken, zo zijn we allemaal begonnen. Geloof het of niet, na een tijdje wordt het tweede natuur. Ik wil bovenstaande ook nog in een Assembly Machinetaal vergelijking gieten: ADRES ASSEMBLY  MACHINETAAL 828   LDAIM #1  A9 01 830   JMP 834   4C 42 03 833   RTS       60 834   STA 1024  8D 00 04837   STA 55296 8D 00 D8840   JMP 833   4C 41 03 Als je onder het kopje Machinetaal kijkt, bevat de eerste kolom de OPCODE, de tweede en derde kolom bevat de OPERANT. In machinetaal kun je duidelijk zien dat "LDAIM #1" twee bytes in beslag neemt (adres 828 en 829) en "JMP 834" drie bytes (830, 831 en 832) in beslag neemt. Als je naar de Machinetaal listing kijkt, zie je overigens ook dat ons gehele programma 15 bytes in beslag neemt. BASIC vertaling van GOSUB...RETURN = JSR...RTS De BASIC kenners onder ons kunnen zich nog een sprong herinneren. Naast de GOTO kennen we namenlijk ook nog een GOSUB ... RETURN opdracht in BASIC. In Assembly gebruiken we hiervoor JSR...RTS. Het grote voordeel is dat je bij het terugspringen niet een adres hoeft op te geven (en berekenen), de RTS maakt gebruik van de verderop besproken programmateller om te bepalen waar naartoe teruggesprongen moet worden. We maken weer gebruik van hetzelfde voorbeeld, maar ditmaal gebruiken we JSR en RTS.  OPCODE OPERANDLDAIM  #1    (Laad 1 in register A) JSR    834   (Spring naar geheugenadres 834) RTS          (Spring terug - in dit geval terug naar BASIC) STA    1024  (Zet de inhoud van A op adres 1024) STA    55296 (Zet de inhoud van A op adres 55296) RTS          (Spring terug naar de regel na JSR 834 - in dit geval RTS) END Hieronder laten we het voorbeeeld nog even in een programma stroomschema zien. De JSR instructie biedt dus de mogelijkheid om naar kleine stukjes programma's (subroutines) te springen vanuit je hoofd programma. De RTS instructie springt telkens uit de huidige subroutine terug naar de bovenliggende programma vanwaar het werd aangeroepen. Gebruik je RTS in je hoofdprogramma, dan snapt de 6510 processor dat je terug wilt springen naar BASIC. Oplettende lezers zien trouwens ook dat ons JSR...RTS voorbeeld slechts 13 bytes groot is (2 bytes kleiner dan ons JMP voorbeeld) omdat het RTS commando geen OPERAND code nodig heeft voor een adres van twee bytes groot. De Programmateller Zoals we bij het laatste voorbeeld zagen, wist de processor zelf naar waar hij terug moest springen bij de RTS instructie. Dit betekent dus, dat de computer ergens bijhoudt op welke plek hij in een programma is. Dit is het moment waarop we de programmateller (programcounter of PC) uit de kast trekken. De PC is een 16-bits register dat het adres bevat van het volgende commando dat moet worden uitgevoerd. Iedere keer als de PC een byte uit het geheugen haalt wordt hij met 1 verhoogd. Op deze manier blijft hij altijd naar de volgende geheugenlocatie met de bijbehorende instructie wijzen. Maak je geen zorgen, een voorbeeld zal dit verhaal verduidelijken. Ons programma begon op adres 828. OPCODE    OPERAND PC voor instructie PC na instructie 828 LDAIM  #1             828                        830 830 JSR     834            830                        834 ... De PC weet dus altijd waar je bent in je programma. De methode die de PC gebruikt noemen we stapelen, waar we later bij het bespreken van het stapelgeheugen (STACKs) op terugkomen. Wat belangrijk is om voor nu te begrijpen, is (1) dat het PC register bestaat en (2) dat het dient om tijdens de uitvoering van je programma bij te houden op welke "regel" (eigenlijk adres) het programma zich bevindt.  Kort samenvattend is het duidelijk dat de nummering die je bij de BASIC programma's gebruikt geenzins overeenkomt met de nummering in Assembly. Waar je in BASIC gewoon nummers kunt verzinnen, moet je bij Assembly bewust zijn van het feit dat dit adressen zijn. Later, als we Macro's gaan gebruiken wordt dit wat makkelijker. We kennen nu twee manieren om door het programma te springen. De JMP gebruik je in feite om voorbij stukken programma te springen, terwijl je de JSR...RTS combinatie gebruikt om een tijdelijk "uitstapje" te maken met het voornemen later weer verder te gaan waar je gebleven was. Het programmateller register houdt voor ons bij welke regel er uitgevoerd gaat worden om ons wat denkwerk te besparen.

25 februari 2024

Actueel

'Meld je aan voor de nieuwsbrief' van HCC!commodore

'Abonneer je nu op de nieuwsbrief en blijf op de hoogte van onze activiteiten!'

Aanmelden