&&
------------------------------------------------------------------------------
           CURSUS ASSEMBLER  -  EEN SROLL-PROGRAMMA MET EXTRA'S 1
------------------------------------------------------------------------------

Dit programma gebruikt een heleboel mogelijkheden van de Amiga om een tekst op
het scherm te laten scrollen. Het programma heeft op bijna elke regel wat
kommentaar. Om die reden is het kommentaar tussen de regels kort gehouden.

;
;------ graphics.library ------
;
Text                 = -30 - 30     ; Afdrukken van teksten.
InitRastPort         = -30 -168     ; Initialiseren van de RastPoort.
SetAPen              = -30 -312     ; Kleur van de karakters zetten.
InitBitMap           = -30 -360     ; Initialiseren van de BitMap.
ScrollRaster         = -30 -366     ; Scrollen van een Raster.
;
;-------- exec.library --------
;
ExecBase             =        4     ; Pointer naar de Exec.library.
Forbid               = -30 -102     ; Zet alle interrupts uit.
Permit               = -30 -108     ; Zet alle interrupts aan.
AllocMem             = -30 -168     ; Allokeer geheugen.
FreeMem              = -30 -180     ; Geef het geheugen weer vrij.
OldOpenLibrary       = -30 -378     ; Open een library.
CloseLibrary         = -30 -384     ; Sluit een library.
&&
Als eerste moeten we de graphics.library openen en de pointer daarheen opslaan
in GFXBase.

Start:   move.l   ExecBase,a6       ; Pointer naar Exec.library.
         lea      GFXName,a1        ; Naam van de Graphics.library.
         jsr      OldOpenLibrary(a6) ; Open de graphics.library.
         move.l   d0,GFXBase        ; Sla de pointer op.
         beq.l    No_GFXBase        ; Geen library gevonden ???

Nadat de library open is kunnen we geheugen reserveren voor de bitplanes waar
de scroll op te zien is. Dat moet in CHIP-geheugen zijn.

         move.l   ExecBase,a6       ; Pointer naar de Exec.library.
         move.l   #400*300/8,d0     ; Aantal bytes reserveren voor 2 bit-
         mulu     #2,d0             ;    Planes.
         move.l   #$10002,d1        ; Het moet CHIP-MEM zijn.
         jsr      AllocMem(a6)      ; Reserveer geheugen.
         move.l   d0,bit_Adress     ; Sla het adres daarvan op.
         beq.l    No_BitMap         ; Geen geheugen gevonden ???

We hebben geheugen gereserveerd en kunnen nu de start-adressen van de twee
bitplanes bepalen. Deze slaan we op in een paar variabelen achterin het pro-
gramma.

         move.l   bit_Adress,d0     ; Geheugenadres naar d0.
         move.l   d0,d1             ; Ook naar d1.
         add.l    #400*300/8,d1     ; 1 BitPlane verder in d1.
&&
         move.w   d0,P1Lo           ; 1e Low-woord van Plane 1.
         move.w   d1,P2Lo           ; 1e Low-woord van Plane 2.
         swap     d0                ; Verwissel Hi en Lo.
         swap     d1                ; Verwissel Hi en Lo.
         move.w   d0,P1Hi           ; 2e High-woord van Plane 1.
         move.w   d1,P2Hi           ; 2e High-woord van Plane 2.

We gebruiken ook een eigen Copper-lijst om wat met kleuren te spelen. Daarvoor
moeten we ook geheugen reserveren. Dat moet op deze manier omdat we ver-
anderingen aanbrengen in deze Copper-lijst.
Later, bij de Copper-lijst, ga ik daar verder op in.

         move.l   #CopSize+2,d0     ; CopperLijst-lengte plus 2.
         move.l   #$10002,d1        ; Het moet CHIP-MEN zijn.
         jsr      AllocMem(a6)      ; Reserveer geheugen.
         move.l   d0,Cop_Adress     ; Sla het adres daarvan op.
         beq.l    No_Copper         ; Geen geheugen gevonden ???

Nu nog wat gegevens zodat we weten hoe groot het scherm is waar we op werken.
Daarvoor maken we een BitMap aan.

         move.l   GFXBase,a6        ; Pointer naar de Graphics.library.
         lea      bitMap,a0         ; Adres van de BitMap-struktuur.
         move.b   #2,d0             ; 2 BitPlanes, dus 4 kleuren.
         move.w   #400,d1           ; Breedte is 400 punten.
         move.w   #300,d2           ; Hoogte is 300 punten.
         jsr      InitBitMap(a6)    ; Initialiseer de BitMap-struktuur.
&&
Ook de start-adressen van de twee BitPlanes van de BitMap moeten we opslaan.

         move.l   bit_Adress,a0     ; Zet adres van BitMap in a0.
         move.l   a0,a1             ; Ook in a1.
         add.l    #400*300/8,a1     ; Bereken het 2e bitPlane in a1.
         move.l   a0,Plane1         ; Start Plane 1.
         move.l   a1,Plane2         ; Start Plane 2.

Als laatste krijgt het scherm nog een RastPort. We zetten de pointer naar de
BitMap in die RastPort.

         lea      RastPort,a1       ; Adres van de RastPort-struktuur.
         jsr      InitRastPort(a6)  ; Initialiseer de RastPort-struktuur.
         move.l   #bitMap,R_BitMap  ; BitMap-pointer in de RastPort zetten.

Omdat we een stuk geheugen gereserveerd hebben voor de Copper-lijst moeten we
deze daar ook heen kopieeren. We doen dat in een eenvoudige lus.

Copy_Copper:
         move.l   #Copper,a0        ; Het adres van de nieuwe CopperLijst. 
         move.l   Cop_Adress,a1     ; Het gereserveerde geheugen voor de
                                    ; CopperLijst.
         move.w   #CopSize-1,d0     ; Lengte van de nieuwe CopperLijst.
CoLoop:  move.b   (a0)+,(a1)+       ; Verplaatsen.
         dbf      d0,CoLoop         ; Totdat alles gedaan is.

         move.l   #ScrollText,Text_Ptr ; De plaats van de tekst.
&&
Om alles te kunnen starten moeten we eerst de interrupts uit zetten, dan alle
pointers naar de interrupt- en Copper-vektoren veranderen en als laatste de
interrupts weer toestaan.

         move.l   ExecBase,a6       ; Adres van de Exec.library.
         jsr      Forbid(a6)        ; STOP alle Tasks.

         move.l   GFXBase,a0        ; Adres van de Graphics.library.
         move.w   #$4000,$dff09a    ; STOP de Interrupts.
         move.w   #$0080,$dff096    ; STOP de Copper.
         move.l   $6c,OldIrq        ; Sla de Interrupt-vektor op.
         move.l   #Interrupt,$6c    ; Zet de nieuwe Interrupt-vektor.
         move.l   50(a0),OldCopper  ; Sla de Copper-vektor op.
         move.l   Cop_Adress,50(a0) ; Zet de nieuwe Copper0vektor.
         move.w   #$86c0,$dff096    ; START de Copper.
         move.w   #$c000,$dff09a    ; START de Interrupts.

Alles loopt nu via interrupts. Daarom hoeft het hoofd-programma niets meer te
doen. Het programma kan wachten totdat u het programma wilt verlaten. Een
eenvoudige wachtlus op een muistoets is genoeg.

Wacht:   btst     #6,$bfe001        ; Wacht op de linker-muisknop.
         beq.s    Stop              ; Ja ???
         btst     #10,$dff016       ; Wacht op de rechter-muisknop.
         bne.s    Wacht             ; Nee ???
&&
U heeft gekozen het programma te stoppen. Nu moeten de oude vektoren weer
terug gezet worden. Weer alles met de interrupts uit natuurlijk.

Stop:    move.l   GFXBase,a0        ; Adres van de Graphics.library.
         move.w   #$4000,$dff09a    ; STOP Interrupts.
         move.w   #$0080,$dff096    ; STOP Copper.
         move.l   OldIrq,$6c        ; Herstel oude Iterrupt-vektor.
         move.l   OldCopper,50(a0)  ; Herstel oude Copper-vektor.
         move.w   #$8080,$dff096    ; START Copper.
         move.w   #$c000,$dff09a    ; START Interrupts.

         move.l   ExecBase,a6       ; Adres van de Exec.library.
         jsr      Permit(a6)        ; START alle Tasks.

Als laatste moet al het geheugen vrij gegeven worden. Eerst het geheugen van
de Copper-lijst en dan de BitMap. Daarna sluiten we alle libraries en ver-
laten het programma.

         move.l   ExecBase,a6       ; Adres van de Exec.library.
         move.l   Cop_Adress,a1     ; Adres van het eigen Copper-geheugen.
         move.l   #CopSize+2,d0     ; Het aantal bytes.
         jsr      FreeMem(a6)       ; Geef het geheugen vrij.
No_Copper:
         move.l   ExecBase,a6       ; Adres van de Exec.library.
         move.l   bit_Adress,a1     ; Adres van het BitMap-geheugen.
         move.l   #400*300/8,d0     ; Het aantal bytes per bitPlane.
         mulu     #2,d0             ; Maal 2.
&&
         jsr      FreeMem(a6)       ; Geef het geheugen vrij.
No_BitMap:
         move.l   ExecBase,a6       ; Adres van de Exec.library.
         move.l   GFXBase,a1        ; Adres van de Graphics.library.
         jsr      CloseLibrary(a6)  ; Sluit de Graphics.library.
No_GFXBase:
         clr.l    d0                ; Moet 0 zijn voor de CLI.
         rts                        ; Einde programma.......

Dit is de routine die in de interrupt uitgevoerd wordt.

Interrupt:
         move     SR,-(A7)          ; Sla de SR op.
         movem.l  a0-a6/d0-d7,-(A7) ; Sla de rest op.

         bsr.s    Scroll            ; De eigenlijke scroll-routine.

         movem.l  (A7)+,a0-a6/d0-d7 ; Herstel de rest.
         move     (A7)+,SR          ; Herstel de SR.

Omdat we de sprong naar de oude interrupt niet als sprong neer kunnen zetten
omdat die steeds anders kan zijn, kiezen we voor een wat andere oplossing.
&&
De code $4EF9 is de Assembler-instruktie voor JMP. Daar achter komt het adres
van de oude interrupt-vektor te staan. Daardoor komt er een nieuwe instruktie
die de juiste sprong uitvoerd.

         dc.w     $4ef9             ; Code voor JMP. Hier achter zetten we
OldIrq:  dc.l     0                 ;    de oude Interrupt-vektor neer.

















Verder in deel 2 van deze tekst.


- EINDE ----------------------------------------------------------------------
&&
