                          - SEPTIC'S DEMOSKOLA -

                                 Lektion 9
                                 
                        Skriven av Vicious / Septic

                                 21 Okt 93



                                 Inledning
                                 
Efter ett kort uppehll kr vi nu igng med ytterligare ngra assembler-
lektioner. Den hr gngen tnkte jag ta upp en ganska vlknd sak som
brukar frekomma i alla demos med lite stil, nmligen trackladdning!


                                   Teori
                                   
Nr man sparar en fil i exempelvis Deluxe Paint tnker man inte mycket p
vad som egentligen hnder. Filen bara sparas p disken s att man kan ladda
den terigen nr man behver den. Vad som egentligen hnder r att AmigaDos
kollar om det finns ngon ledig plats p disken och sen sparar ner vr fil
sektor fr sektor p disken, plus att den uppdaterar en fillista s att den
kan hitta filen nsta gng vi ska ladda in den.
  Detta sker s att sga osynligt fr oss genom AmigaDos, och vi behver
egentligen inte bry oss s mycket om det.
  Som coder kanske man dock tycker AmigaDos r ganska jobbigt. Man mste
coda mycket systemvnligt om man ska kunna anvnda AmigaDos i sitt demo,
och ladda del fr del frn en diskett, och att coda systemvnligt ska vi ju
undvika :-) fr det blir ju mycket jobbigare...
  Anvnder man AmigaDos filsystem r ju ocks nackdelen att alla kan kika
p filerna man har p disketten. P en trackladdad diskett r detta mycket
svrare, speciellt fr "hackers" som inte kan trackloading.
  Allts fr man skippa AmigaDos filsystem och helt enkelt spara sina filer
fr hand, och likas ladda dem fr hand.
  I en egen trackloader sparar man sina filer p disken direkt p
sektorerna, och sen fr man hlla reda p var man sparade sin fil s att
man kan ladda den igen.
  Jag kanske skulle nmna det att en diskett r uppbyggd av 80 cylindrar.
Varje cylinder har ett track p ovansidan och ett p undersidan, allts 160
tracks totalt. Varje track r uppbyggt av 11 sektorer, och varje sektor r
512 bytes. En diskett har allts plats fr 160 tracks multiplicerat med 11
sektorer multiplicerat med 512 bytes (160*11*512)=901120 bytes!
  Frsta tv sektorerna innehller alltid ett bootblock. Bootblocket r det
som ska starta upp disken (om den r bootbar, givetvis) och drfr mste vi
ocks ta och kika p hur man konstruerar en loader i bootblocket.

Det finns tv typer av trackladdning. DOS och HARDWARE. DOS r den enkla
metoden. HARDWARE r den svra, men som anvnds mest idag eftersom den
anses vara coolare. Jag tnkte g igenom bda metoderna eftersom de bda
har frdelar och nackdelar.


                                 Register
                                 
Fr dos-trackloading behver man inte anvnda ngra register alls (det r
just drfr som det heter DOS-trackloading) utan endast en biblioteks-
funktion som laddar frn disken.
  Dremot behver man anvnda lite nya saker vid HW-trackloading
(HW=HardWare) som jag frklara nu...
  Frst och frmst ska vi kika p Amigans timers. En timer r en rknare
som endast har till uppgift att rkna frn ett visst specificerat tal ner
till noll. En sn hjrndd uppgift, kanske ni tycker, men dessa timers r
mycket anvndbara nr man mste vnta en viss tidsperiod som r KORTARE n
en frame, dvs 1/50:dels sekund. Tidigare har vi ju anvnt oss av
skrmstrlen fr att vnta en viss tidsperiod, nmligen en frame, men nr
man trackladdar behver man ibland vnta endast ngra millisekunder, och d
kommer en timer vl till pass.
  Nu mste jag ocks ppeka - fr det finns vl alltid nn som protesterar
och sger att det blir fr jobbigt att anvnda timers - att man ska ABSOLUT
inte vnta en viss tidsperiod med hjlp av loop-kommandot DBF!!! Detta
kanske verkar smidigt, och fungerar bra p din egen dator, men s
filosoferade alla coders fr tv-tre r sen och lngre tillbaka. Det r
ocks drfr som inga av deras demos fungerar p A1200 idag, t.ex, fr
deras trackloaders vntar med DBF-loopar som gr mycket fortare p 1200:an.
  Okej, som jag sa s finns det flera timers. Nr systemet r igng s
anvnds de blandannat till att skaka hand med tangentbordet vid vissa
tidpunkter, exec task switching och interrupts.
  Nr vi trackladdar har vi dock slngt ut systemet, s d spelar det ingen
roll om vi roffar t oss en timer och anvnder den fr att tajma vr
trackloader.
  En timer kan fungera p lite olika stt. Den kan t.ex rkna ner till
noll, generera ett interrupt och sen stta sitt ursprungsvrde igen och
pnytt rkna ner till noll. Eller s kan den rkna ner en gng och sen
stanna, och det r den metoden vi ska anvnda.
  I min trackloader har jag valt att anvnda CIAB Timer A. Vi ska kika p
hur enkelt den r uppbyggd.
  Frst och frmst har vi ett kontrollregister, CIAB Control Register A
($BFDE00). Det ser ut s hr:

BIT   NAMN          FUNKTION
---   ----          --------
 0    START         1=Starta Timer A, 0=Stoppa Timer A
                    (Den hr biten nollstlls automatiskt nr timern ntt
                     noll i One-Shot mode)
 1    PBON          1=Timer A output till PB6, 0=PB6 normal
 2    OUTMODE       1=Toggle, 0=Pulse
 3    RUNMODE       1=One-Shot mode, 0=Continuos mode
 4    LOAD          1=Force load (Strobe bit, tvingar timern att brja om
                    rkningen)
 5    INMODE        1=Timer A rknar Positive CNT transitions
                    0=Timer A rknar 02 pulser
 6    SPMODE        1=Seriell port blir output, 0=Seriell port blir input
 7    UNUSED        Ej anvnd.

Sen mste man ocks fra in vilket vrde Timern ska rkna ner ifrn. Det
fr man in i CIAB Timer A lo byte ($BFD400) och hi byte ($BFD500). Sen r
det bara att testa bit 0 i kontroll-registret fr att se nr timern r
frdig.
  Jag tnker inte g in nrmare p hur dessa timers funkar. Det str
frklarat utfrligt i Hrdvarumanualen s fixa den om ni r intresserade.

Att gra en HW-trackloader r verkligen ett mandomsprov fr en coder. Hr
mste man skta diskdriven p allra lgsta niv, dvs flytta ls/skriv
huvudet manuellt, byta disksida beroende p vilket track man lser p, lsa
in data frn disketten med hjlp av ngra hrdvaruregister och sedan decoda
datan till formatet vi sparade i.
  Till att brja med har vi ngra register som styr lshuvudet och det r
CIAAPRA ($BFE001) och CIAAPRB ($BFD100). CIAAPRA knner vi blandannat igen
fr att man lser av musknappen dr, men det finns ngra bitar som r
intressanta vid HW-trackloading. Hr kommer de intressanta bitarna:

BIT   NAMN          FUNKTION
---   ----          --------
 2    DSKCHANGE     Blir 0 nr en disk tas ur driven.
 3    DSKPROT       Disken r skrivskyddad=0.
 4    DSKTRACK0     r noll nr lshuvudet befinner sig p track 0.
 5    DSKREADY      Disk ready. Blir noll nr drivemotorn roterar med full
                    hastighet och driven r klar att ta emot kommandon.

I CIAAPRB har vi bara intressanta bitar! Se hr:

BIT   NAMN          FUNKTION
---   ----          --------
 0    DSKSTEP       Flyttar ls/skrivhuvudet p diskdriven. Signalen mste
                    ges som en snabb puls, 1, sen 0 i minst 3 millisekunder
                    och sen 1 igen. (Nr man byter riktning mste man vnta
                    i minst 18 millisekunder innan man fortstter.)
 1    DSKDIREC      Specificera riktningen som drivehuvudet skall ka. En
                    nolla anger riktningen int, mot centrum p disken, en
                    etta anger utt.
 2    DSKSIDE       Anger vilken sida p disketten vi ska lsa. En nolla
                    betyder ovansidan, och en etta r undersidan. Alla
                    jmna tracks ligger p undersidan och de udda p
                    ovansidan. (Mste vara stabil i minst 100 mikrosekunder
                    innan man skriver till disketten.)
 3    DSKSEL0       Vlj drive 0.
 4    DSKSEL1       Drive 1.
 5    DSKSEL2       Drive 2.
 6    DSKSEL3       Drive 3.
 7    DSKMOTOR      Disk motor kontroll. Anvnds fr att sl p disk motorn
                    p den drive man valt. Det gr till s att man frst
                    stter diskdrive, sen rensar DSKMOTOR biten, vntar
                    kort och sen rensar diskdrive-biten p den drive man
                    valt.

Dr har vi allt vi behver fr att styra diskdrivens ls och skrivhuvud.
Det var vl inte s farligt?
  Nu kan vi kika vidare p hrdvaruregistren som har hand om ls och
skrivning frn diskett. Vad de egentligen styr r DISK DMA, speciellt gjort
fr att lsa och skriva frn disk.
  Vi kan brja med kontrollregistret ADKCON, som str fr Audio Disk
Control, och som mycket riktigt innehller bitar fr att kontrollera ljud
och disk. Vi ska titta enbart p disk-bitarna:

BIT   NAMN          FUNKTION
---   ----          --------
15    SET/CLR       Stter eller rensar bitar som r satta. (Precis hos
                    DMACon, BPLCon osv...)
14-13 PRECOMP0-1    00 Ingen prekompensation
                    01 140 nanosekunders prekompensation
                    10 280   "     "         "      "
                    11 560   "     "         "      "
12    MFMPREC       0=GCR Precompensation (Group Coded Recording)
                    1=MFM Precompensation (Normalt)
10    WORDSYNC      En etta mjliggr synchronisering med DSKSYNC-registret
09    MSBSYNC       En etta mjliggr synchronisering av den mest
                    signifikanta biten av lst data (anvnds mest vid GCR)
08    FAST          En etta anger 2 mikrosekunder per bit cell (MFM)
                    En nolla ger 4 mikrosekunder (GCR)

Vidare har vi ett register som heter DSKLEN ($DFF024). Det anger disk DMA
datans lngd i words. Bit 15 slr dock p Disk DMA och bit 14 anger om data
ska lsas (0) eller skrivas (1), s det r allts bara bit 0-13 som anger
lngden. Det kluriga r att man mste skriva TV gnger till den hr
addressen fr att verkstlla ordern.
  I DSKPT ($DFF020) skriver man in disk-pekar-destinationen som ett
longword, allts var i minnet den MFM-kodade rawdatan ska lsas. Mste vara
till CHIP mem.
  I DSKSYNC ($DFF07E) skriver vi in diskens sync-vrde, som vanligvis
brukar vara talet $4489!
  I INTENAR ($DFF01C) finns det dessutom en interrupt bit som stts nr ett
disk block lsts. Jag anvnder det fr att kolla nr disk DMA:n r klar.
  Just det, glm fr allt i vrlden inte av att sl p DISK DMA-biten i
DMACON ocks!
  S lngt, allt vl, men nu r kruxet det att all data vi lst in r kodad
p ett speciellt stt, som kallas MFM-encoding. Dr r varje bit tv bits
istllet, som ligger p fljande stt: En 1 r alltid 01. En 0 r 10 om
fregende ocks var noll, annars r den 00.

  Sdr, det var allt man behvde fr HW-trackladdning.

Nu tnkte jag g igenom dos-trackladdning lite ltt. Eftersom libraries
inte r min starka sida kan det bli lite krystat och svrfrklarat nu, men
ni kan lsa mer om de hr biblioteksfunktionerna i Rom Kernel Reference
Manualen.
  Vi ska allts anvnda oss utav ett device som heter Trackdisk.device fr
att ladda frn disken.
  Frst mste vi skapa ett IO-Request block som vi ska anvnda oss utav fr
att ladda. Blocket ska vara 20 longwords, eller 80 bytes.
  Sedan anvnder vi AddPort och skapar en port som vi fr in i
IO-requesten. Sen ppnar vi trackdisk.device.
  Efter det kan vi skriva in ett kommando till IO-requesten p den 28:e
byten. Hr fljer en lista p kommandon:

Nummer Kommando Funktion
------ -------- --------
   2   Read     Ls frn disken
   3   Write    Skriv till disken
   4   Update   Uppdatera skriven data till disk
   5   Clear    Rensa tracks
   9   Motor    Sl p eller av diskmotorn
  10   Seek     Flytta skrivhuvudet till ett speciellt track
  11   Format   Formater tracks
  13   ChgNum   Kolla hur mnga gnger disken bytts i driven
  14   ChgState Finns nn disk i driven?
  15   ProtStat Kolla om disken r skrivskyddad

Jag tnkte inte g in s noga p de olika kommandona. Vi ska bara komma
ihg att kommandot READ (#2) krver lngden i byte 36 av IO-requesten,
destinationen i byte 40 och offseten i byte 44. Lngden och offset mste
vara jmna multiplar av 512, allts mste man skriva in det som SECTOR*512.
Vill man lsa femton sektorer med brjan p sektor tre, s blir offseten
3*512 och lngden 15*512. Destinationen mste ligga i chipmem.
  Sen hoppar man bara till exec-funktionen DoIO (-456).
  Nr man konstruerar bootblock brukar man anvnda sig av en
dos-trackloader som laddar in den riktiga loadern, eftersom HW-trackloaders
brukar vara ganska stora. I bootblocket r det dock ganska smidigt med
dos-loaders, eftersom man fr en pekare till en frdefinerad IO-struktur i
A1, som man enkelt kan anvnda. Allts behver man bara skriva in lngd,
offset och destination och s laddas MAIN-loadern in.


                              Programexemplen
                              
Idag har vi flera spnnande program att kika p. Ett exempel p ett boot-
block med en dostrackloader, en vanlig dosloader och en HW-trackloader.
  Frsta programmet r en dostrackloader. Den anvnder sig utav systemets
trackload-rutiner, och drfr mste systemet vara intakt nr man kr den.
Anvnder man en sn rutin i ett demo fr man allts inte stnga av systemet
och d kan man allts inte anvnda hela minnet.
  Programmet r inte s svrt att frst. Det lser helt enkelt ett visst
antal sectorer frn en viss position p disken (mtt i sectorer) till en
adress i minnet.
  Nsta program, Lekt9b.s, r i princip samma program, fast det r omgjort
fr att lggas i ett bootblock. Nr man startar ett program frn
bootblocket fr man en IO-struktur frdig att anvndas i register A1.
Drfr behver man inte allokera en sjlv och d blir ju programmet ganska
litet och smidigt. Eftersom programmet r skrivet fr att fungera endast
frn bootblocket kan du INTE kra det p vanligt stt i assemblern, utan du
mste spara det p en disk och sen boota frn disken. Hur du ska gra str
frklarat i programmets brjan.
  Programmet gr egentligen ingen nytta. Det lser bara ngra sectorer frn
disken fr att demonstrera hur man gr, och sen gr det in i en evig loop
som bara kan brytas genom reset.

Det sista programmet r en komplett hardware trackloader. Den jobbar enbart
med tracks, inte sectorer allts, s varje lsning innebr 5632 bytes.
  Programmet r ganska utfrligt kommenterat s du kan lsa dr hur det
hela fungerar.

Nu kanske du undrar hur man ska spara sina alster p en diskett s att man
kan anvnda trackloading sen. Jo, det r ganska enkelt, fast man mste
hlla reda p lite siffror som man kanske mste skriva ner p ett papper.
Frst och frmst ska bootblocket alltid ligga p sector 0 och 1 s dr kan
vi inte spara ngot. Dremot p sector 2 och framt r allt fritt. Om vi nu
vill spara t.ex en jttebra lt dr som r 95789 bytes stor, mste vi frst
rkna fram hur mnga sectorer den tar upp. D gr vi bara s att vi
dividerar lngden med 512, allts 95789/512 och d fr vi 187.09 sectorer.
Vi kan bara arbeta med hela sectorer och vi ser att vi behver lite mer n
187 sectorer, s d fr vi allts spara 188 sectorer fr att hela filen ska
komma med.
  I AsmOne kan man sen gra fljande fr att spara filen. Skriv in ett kort
program som ser ut s hr:

   section   data,data_c
s: incbin    'lt-path/ltens-namn'

Assemblera sen detta och stoppa sen i den disk du ska spara lten p i DF0:
(disken fr inte innehlla ngra viktiga AmigaDOS-filer! Dessa kommer i s
fall att frstras!)
  Nu skriver du WS fr Write Sector och anger S som RAM PTR, eftersom det
r dr vr lt ligger i minnet. Sen skulle vi ju brja spara p sector 2,
och drfr skriver vi ocks 2 p frgan om DISK PTR. Sen skriver vi lngden
188 och sen var det klart. Nu sparas lten p sector 2 till 190 och det r
nu vi behver lite papper och penna fr att skriva upp de hr siffrorna.
Annars kanske man sparar ver lten nsta gng man ska spara en annan fil
p disken.
  Hardware Trackloadern jobbar endast med hela tracks, som sagt, och skulle
vi anvnda den i vrt demo istllet s fr vi gra lite annorlunda. Vi tar
reda p antal tracks istllet fr antal sectorer, och det gr man genom att
ta fillngden genom 11*512 (eftersom det finns 11 sectorer p varje track).
Allts 95789/5632 och det blir 17.01. Vi behver allts lite mer n 17
tracks, och d blir det givetvis 18 tracks.
  Nu anvnder vi kommandot WT (Write Tracks) istllet fr WS, och anger
alla lngder och offseter i tracks. Vi brjar allts spara p track 1
istllet fr sector 2, och lngden blir 18 istllet fr 188.
  S, nu hoppas jag ni kan gra riktigt hftiga trackmos efter det hr!

