                          - SEPTIC'S DEMOSKOLA -

                                 Lektion 7
                                 ¯¯¯¯¯¯¯¯¯
                        Skriven av Vicious / Septic

                                 24 Jul 93



                                 Inledning
                                 ¯¯¯¯¯¯¯¯¯
Stora välanimerade bobs, höga sinusscrollers och snabba fyllda vectorer har
en sak gemensamt. De använder den kraftfulla saken i Amigan som kallas
BLITTER. I den här lektionen ska vi äntligen börja rota lite i blitterns
möjligheter och lära oss hur den ska hanteras.


                                   Teori
                                   ¯¯¯¯¯
I första hand ska vi tänka på blittern som en kopierare. Processorn är dess
arbetsgivare, och har inte processorn sagt till den att jobba så ligger den
bara i ett hörn och latar sig.
  Men, blittern är inte någon latmask, utan väldigt effektiv. Så fort
processorn talat om för den vad den ska kopiera så sätter den igång med
rasande fart. Under tiden kan processorn utföra beräkningar och annat smått
och gott medan den väntar på att blittern ska bli klar.
  Blittern kan användas till att kopiera helt vanligt från källa till
destination, men den kan också kombinera olika källor för att uppnå
intressanta resultat, inte minst inom grafikbehandling. Ett exempel är ju
bobs, som jag kommer att ta upp nästa gång.


                                 Register
                                 ¯¯¯¯¯¯¯¯
Innan vi börjar ge blittern order med processorn är det viktigt att kolla
om den är klar. Annars kan det hända att kopieringen den just för
tillfället håller på med går åt skogen.
  Att titta om den är klar kan man på ett enkelt sätt göra genom att testa
bit #14 (BBUSY) i DMACONR ($dff002). Om den är satt så vet man att blittern
håller på för fullt och har inte tid med en ny kopiering än.
  När man så har kollat om den är färdig och fått klartecken så kan man
börja initialisera de olika registren som blittern använder.
  Till att börja med brukar jag specificera hurdan kopiering jag ska göra
och det gör man i BLTCON0 ($dff040) och BLTCON1 ($dff042). De bägge
registren ser ut som följer (ej i line draw mode):

   BIT#   BLTCON0   BLTCON1
   ----   -------   -------
    15    ASH3      BSH3
    14    ASH2      BSH2
    13    ASH1      BSH1
    12    ASH0      BSH0
    11    USEA       x
    10    USEB       x
    09    USEC       x
    08    USED       x
    07    LF7        x
    06    LF6        x
    05    LF5        x
    04    LF4       EFE
    03    LF3       IFE
    02    LF2       FCI
    01    LF1       DESC
    00    LF0       LINE

ASH0-3 - Anger skiftvärde för källa A.
BSH0-3 - Anger skiftvärde för källa B.
USEA-D - Talar om vilka blitter kanaler man vill använda.
LF7-0  - Logisk minterm funktion.
EFE    - Fyll exklusivt.
IFE    - Fyll inklusivt.
FCI    - Fill Carry Input
DESC   - Descending mode (Kopiera nerifrån och upp istället för tvärtom).
LINE   - Slår på line mode.

Fyllbitarna och linemode biten ska jag ta upp i senare lektioner. Just nu
ska vi koncentrera oss på BLTCON0 och enbart nollställa BLTCON1.
  De som inte är helt bakom flötet - eh, ursäkta - har väl vid det här
laget (om ni läst ordentligt) märkt att blittern har 4 (fyra) kanaler. De
tre första, A, B och C är källkanaler och den sista, som har beteckningen
D, är en destinationskanal.
  Vi ska den här gången bara använda oss utav källa A och destination D,
eftersom vår kopiering är av enkel typ. Alltså väljer vi bara bit #11 och
bit #8 (USEA och USED).
  Du kanske undrar vad skiftningen är till för? Jo, blittern jobbar alltid
bara med hela WORDS, vilket alltså är var sextonde pixel (titta tillbaka på
lektionen om bitplan om du inte minns!) och att flytta ett objekt på enbart
jämna sextonpixels koordinater i X-led skulle inte vara så snyggt. Det är
här skiftningen kommer in. Man skiftar helt enkelt datan upp till femton
steg inom det wordet man kopierat till och vips, så kan man låta ett
grafisk objekt glida fram en pixel i taget.
  Man kan dock använda skiftningen till annat också. Nämligen när man
scrollar en text! Programexemplet för den här gången använder skiftnings-
tekniken för att kunna scrolla texten fyra pixlar åt gången.
  Bitarna 7 till 0 (LF7-0) i BLTCON0 anger den logiska mintermen, vilken är
en mycket kraftfull liten sak som talar om för blittern hur de tre källorna
ska kombineras för att nå en speciell effekt. Dess komplexitet gör den
också ganska svår att förstå, så få inte kronisk hjärnblödning nu om ni
inte fattar min förklaring.
  Man kan alltså kombinera de tre källorna A, B och C på upp till 256 olika
sätt med den här funktionsgeneratorn. Varje enskild bit i det man kopierar
kommer att testas och påverkas olika, beroende på hurdan minterm man valt.
  Man kan åskådliggöra det med en sanningstabell (som de gjort i Hardware
Manualen, där små bokstäver betyder NOT):

   A   B   C   D   BLTCON0 bit   MINTERM
   -   -   -   -   -----------   -------
   0   0   0   ?        0          abc (=not A and not B and not C)
   0   0   1   ?        1          abC (=not A and not B and C)
   0   1   0   ?        2          aBc etc etc...
   0   1   1   ?        3          aBC
   1   0   0   ?        4          Abc
   1   0   1   ?        5          AbC
   1   1   0   ?        6          ABc
   1   1   1   ?        7          ABC

Sedan läser man bara i tabellen beroende på hur man vill kombinera
källorna. Om vi till exempel vill sätta alla bitar i destionationen när A
eller B är 1, tittar vi i tabellen och ser efter på vilka bitpositioner som
A är 1, vilket är på position 4 till 7, och sedan på vilka positioner som B
är 1, och det är ju position 2 och 3 samt 6 och 7.
  Sedan tittar vi bara på vilka bitar vi satt, nämligen 2 till och med 7
och ser att vi fått talet %11111100, vilket är $FC hexadecimalt.
  Vi ser nu också vilken enkel typ av kopiering vi ska använda till
scrolltexten, eftersom vi bara ska flytta från A till D utan krusiduller.
Vi sätter bara alla bitar som har A-biten satt, nämligen bit 4-7, och får
talet %11110000, som är $F0 i hex.
  Men, tyvärr är det inte så här enkelt bara. För när man ska konstruera
svårare operationer (nästa gång ska vi kika på hur man gör BOBS) krävs även
lite logiska ekvationer.
  Ett exempel:

   D=Ac + B

Bokstäver som sitter ihop läses som AND och ett plus anger OR. Små
bokstäver har NOT framför sig. Uttrycket ovan utläses alltså som "A and not
C or B". Detta betyder att D-biten bara sätts när A är satt och C är 0
eller när B är 1.
  Att räkna ut siffror för det här är både jobbigt och svårt, så därför har
jag inkluderat variabler i slutet av programexemplet som gör användningen
av minterms mycket enklare. Vi skall dock inte titta mer på dem förrän i
nästa avsnitt.

Sådär, det var lite om BLTCON! Efter att vi talat om för den ivrige
kopieraren hur han ska kopiera, måste vi ange varifrån han ska hämta data
och var det ska hamna.
  Källa A har sin pekare i BLTPTA ($dff050) och destinationen D BLTPTD
($dff054). Bägge adresserna kan skrivas in som longwords men tänk på att
det måste vara inom CHIP mem.

Precis som med bitplan, kan blittern addera ett modulo värde efter varje
rad den kopierat. Detta gör det enklare om man kopierar data som är mindre
än skärmen är bred. Man kan då tex flytta en bob som bara är 32 pixlar bred
på en 320-skärm och inte behöva krångla med att kopiera en rad i taget och
sen addera ett breddvärde för att spara tid, utan kan initiera blittern
till att sköta det helt automagiskt.
  Modulovärdet för källa A finns i BLTAMOD ($dff064) och för destination D
i BLTDMOD ($dff066).

Det finns också ett maskregister i blittern, som möjliggör logisk AND i
början och i slutet på en kopierad rad. Man kan på så sätt rensa bort
pixlar man inte vill ha med i ett objekt som inte riktigt fyller upp ett
helt jämnt word. Tills vidare låter vi de registren vara $ffff, eftersom vi
inte vill maska bort något än. (Mer om dess användning nästa gång, så håll
er till tåls...)

Nu är det bara att sätta igång blittern! Och hur gör man det då? Jo, det
gör man genom att ange kopieringens storlek! Så fort blittern fått tag i
storleken på datafältet den ska kopiera så sätter den igång, så därför ska
man ALLTID ge storleken sist, efter det att man satt alla andra blitter-
register till rätt värden.
  Blittern tar emot storleken som bredd i words och höjd i antal rader.
Registret man ska skriva in allt detta i är BLTSIZE ($dff058).
  Bitarna i BLTSIZE ligger så att höjden anges i bit 6 till 15 och bredden
i bit 0 till 5. Enkelt sett är det bara att multiplicera höjden med 64 för
att tvinga upp den i bitarna 6 och uppåt, och sen addera bredden.
  Ett block på 128*32 pixlar får alltså storleken (32*64)+(128/16)=2056
($808). Höjden 32 multipliceras alltså med 64, och sen lägger man till
bredden i words, vilket ju är 128 pixlar dividerat med 16 = 8 words.

Sådär ja! Det var en liten flukt på vad man kan göra enbart inom enkel
kopiering med blittern. Nu kan vi kasta oss vidare på programexemplet.


                              Programexemplet
                              ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Scrolltexter kan tyckas enormt tråkiga eftersom de verkar ha funnits sen
urminnes tider (ja, åtminstone sen 64:an började sitt triumftåg världen
över) men de visar på ett bra sätt hur "fyrkantig" kopiering går till.
  Vad man gör när man scrollar är helt enkelt att kopiera en hel fyrkantig
area, där texten finns, till en ny position i X-led, några pixlar åt
vänster (eller höger :-) om ni sett mitt Slipstro...) I mitt program
scrollar jag, på en 384*32 skärm, en 32*32 font med lite poetisk text.
Skärmen är 384 pixlar bred för att undvika fula kanter där scrollen bara
huggs av, och för att dölja att våra nya bokstäver ploppar ut på skärmen
istället för att glida in lugnt och mjukt. Att den är 32 hög bara, är helt
enkelt för att det inte behövdes mer, när fonten inte vara högre än 32.
  Jag har dessutom lagt till en liten spegeleffekt på scrollen, som är 16
pixlar extra, men denna har inget med den riktiga skärmen (som ju bara är
32 hög) att göra, utan är bara en uppochnervänd kopia som åstadkommits med
negativ modulo.
  Men, i alla fall så kanske det är bäst att jag går igenom programmet steg
för steg som jag brukar.
  Först och främst har vi den gamla hederliga startupen (hmmm?! den har
hängt med sen lektion 1 och ingen har protesterat, men funkar den verkligen
på A1200?!?!?) som vi studerat tidigare och inte behöver mala vidare på.
Sen kommer DMA-sättningen, och här kan ni se att jag slagit på blitter-DMAn
och även BLITTER NASTY-biten, som ger blittern full prioritet över
processorn, så att blittern får mer tid och kopieringen går fortare. Ett
optimalt sätt (som jag sett att Hannibal/Lemon. använder) borde egentligen
vara att endast slå på BLITTER NASTY när man väntar på att blittern ska bli
färdig, men jag har inte orkat göra det här.
  Efter det sätter vi copperlistan och sen kommer mainrutinen. Här ser vi
att jag först använder en sync-rutin för att synka scrollen med
rasterstrålen (prova att plocka bort sync-rutinen för att se skillnaden)
och få det hela att flyta fint.
  Sen hoppar jag till scrolltext-rutinen och då ska vi ta och kika på vad
jag gör där.
  Först av allt subtraherar jag från en ScrollCounter. Detta gör jag för
att kunna veta när nya bokstäver ska skrivas ut.
  Om inte ScrollCountern är noll hoppar vi till .NoNewChar men om den
däremot ÄR noll sätter vi den till 8. Hmmm, ÅTTA? Kanske du undrar, och det
kan jag förstå. Det riktiga talet borde ju egentligen vara 32! Men, om
värdet skulle vara 32 skulle vi också få scrolla texten en pixel varje synk
bara, och det är ganska sakta. Jag scrollar nu texten 4 pixlar åt vänster
varje sync, och därför blir det bara värdet 32/4=8 i ScrollCountern. Testa
gärna att skriva in högre och lägre värden på den här raden så kommer ni
att märka att bokstäverna kommer närmare eller längre från varandra.
  Sedan hoppar jag till rutinen NewChar, och då är det lika bra att vi
kikar på den också med en gång.
  I NewChar hämtar jag först en pekare som anger var i texten vi befinner
oss, alltså vilket tecken vi nu skall putta ut på skärmen. Efter att ha
nollställt D0 (egentligen inte nödvändigt, men en säkerhetsåtgärd för
divideringen senare) hämtar jag tecknet och hoppar om det inte är noll. Är
det noll, börjar vi bara om från början på texten igen och försöker på
nytt.
  Sedan sparar jag textpekaren igen (nu pekar den på nästa bokstav som vi
ska skriva ut nästa gång) och subtraherar 32 från D0. Om ni tittat i en
ASCII-tabell någon gång (och det hoppas jag, annars ska ni göra det
omedelbums!) så har ni förhoppningsvis märkt att de första 32 bokstäverna
bara är kontrolltecken. Dessa tecken behöver inte vi i vår scrolltext, och
vi har heller inte dem representerade i vår font, så därför gör vi helt
enkelt om tabellen så att mellanslag får värdet 0 istället för 32 och
utropstecken blir 1 istället för 33 osv...Titta på fontbilden så ser du hur
tecknen är uppställda. (Å, Ä och Ö finns också med på bilden fast på ganska
galna positioner, nämligen &, % och +, så bli inte förvånad om det inte
stämmer riktigt med en ASCII-tabell!)
  Sedan - om vi går tillbaka till programmet igen - nollställer jag D1
(säkerhet igen, annars kan det bugga ur...) och dividerar D0, alltså
bokstavsnumret, med 10 eftersom det finns 10 tecken på varje rad i
fontbilden. När jag gör detta får jag ett svar som anger på vilket rad
tecknet står och en rest (i de högre 16 bitarna) som talar om på vilken
position i sidled.
  Jag flyttar de låga 16 bitarna, alltså radnumret till D1 och
multiplicerar det med en bokstavs-radhöjd i fontbilden, som är 320 pixlar
bred, vilket alltså blir 320/8 bytes=40 gånger 32 pixlar hög.
  Efter det rensar jag de låga bitarna i D0 och flyttar ner divisions-
resten dit. Efter det utför jag en aritmetisk skift åt vänster två steg,
vilket är samma sak som att multiplicera med 4 (fast skiftning går
snabbare), och det gör jag för att få korrekt tecken position i X-led.
Varje bokstav är ju 32 pixlar bred, och det är ju som bekant FYRA bytes!
Så, om tecknet hade position 2 så multiplicerar vi det med 4 och får 8, och
det betyder alltså att grafiken för bokstav nr 2 finns 8 bytes in på
fontbilden.
  Vad gör jag sen? Jo, nu har vi alla offseter vi behöver, så nu pekar jag
på var fontbilden ligger i minnet och adderar sedan så att A0 till slut
pekar på rätt bokstav, alltså den vi ska skriva ut på skärmen.
  Sen pekar jag på skärmen, 46 bytes in, eftersom vi ska skriva tecknet
långt ute till höger och så börjar jag flytta data.
  Det behövs två loopar för det hela. En som går runt 32 gånger (då vi
kopierar rad för rad i bokstavsgrafiken) och så en som går runt 4 gånger
(eftersom fonten har fyra bitplan).
  Jag flyttar grafiken med move.l för att det är precis 32 pixlar och sen
adderar jag skärmbredden (så att vi kommer till nästa rad, rakt under den
förra) till både fontbilden och den riktiga skärmen. (Fonten är 320 pixlar
bred, vilket är 40 bytes, och skärmen är 384/8=48...)
  När jag har kopierat en hel bokstav i ett bitplan går jag till nästa
bitplan. Eftersom skärmen bara är 32 pixlar hög behöver jag inte addera
något till den, men till fontbilden adderar jag dess bitplanstorlek
(40*192) minus ett teckens höjd (40*32), så hamnar jag på rätt ställe.
  Sådär, det var NewChar-rutinen. Då hoppar vi tillbaka till där vi var, i
ScrollText-rutinen.
  Här hoppar vi till själva blitter-scroll-rutinen, ScrollIt.
  I ScrollIt gör vi det som man alltid först måste göra innan man använder
blittern. Man testar om den är klar! Jag gör här en busywait (detta e
demokodning, så who carez?!).
  Sedan lägger jag in source och destination i A0 och A1. Att sourcen är
screen+2 (alltså 16 pixlar åt höger) beror på att blittern skiftar åt höger
(utom i descending mode, men det är en annan historia jag ska ta upp i en
senare lektion). Så, vad vi gör är alltså att flytta 16 pixlar åt vänster
och sen skifta åt höger för att få hastigheten 16-skiftvärde.
  Vilket skiftvärde jag har ser ni på nästa rad, där jag skriver till
BLTCON0. Det är $c000, men bara de tre högsta bitarna räknas, så det blir
$c, alltså 12. Scrollhastigheten blir således 16-12=4, och det känner vi ju
igen från ovan!
  Sedan står det också +srca!dest!a och det är minterms-förenklingarna som
jag pratade om innan, som gör det lättare att kombinera funktioner. Srca
och Dest står för USEA och USED, alltså att bara A och D ska vara påslagna,
och A:et som följer talar om för blittern att den ska kopiera allt från A
till D utan några som helst modifikationer.
  Sen nollställer jag BLTCON1 (kan egentligen göras genom att skriva ett
longword till BLTCON0, men jag ville få det hela överskådligt för de som är
nybörjare :-)) och skriver $ffffffff till BLTAxWM som är de bägge
maskregistren.
  I BLTAPT och BLTDPT skriver jag så in källa och destination och sen
skriver jag noll till båda modulo-registren.
  Nu, sist men absolut inte minst, skriver jag storleken till BLTSIZE. 32
raders höjd gånger 4 bitplan plus 8 extra rader och så 23 words bredd.

Det var allt om programmet den här gången. För att enklare följa det hela
kan ni ju printa ut den här textfilen och läsa den samtidigt som ni tittar
på programmet, eller så kan ni ladda in det i någon texteditor som klarar
av flera filer åt gången i olika fönster (typ Cygnus Ed, yeah!) som jag
själv använder.
