Magic Disk 64

home to index to html: MD9109-KURSE-CIA_TEIL_3.html
Kommen wir nun zu dem  Programm  selbst.
Hier ist der kommentierte Source-Code:  
****************************************
start   sei           IRQs sperren      
        ldx #<(irq)   IRQ-Vektor        
        ldy #>(irq)    auf neue         
        stx $0314      IRQ-Routine      
        sty $0315      verbiegen.       
        ldx #<(nmi)   NMI-Vektor        
        ldy #>(nmi)    auf neue         
        stx $0318      NMI-Routine      
        sty $0319      verbiegen.       
        ldx #$83      Timer A und B als 
        stx cia1+13  Interruptquelle für
        stx cia2+13   beide CIAs setzen 
        lda #00       Timer B von       
        sta cia1+6     CIA1             
        sta cia1+7     und              
        sta cia2+6     CIA2 mit dem Wert
        sta cia2+7     0 initialisieren.
        ldy #$90      Timer A von CIA2  
        sta cia2+4     initialisieren   
        sty cia2+5     ($9000=27 IRQs/s)
        lda #$21      Trigger=CNT und "T
                       mer Start"       
        sta cia1+15    in Control-Regist
        sta cia2+15    für Timer B von  
                       CIA1 und CIA2.   
        lda #$81      Timer A von CIA2  
        sta cia2+14    mit SysTakt als  
                       Trigger starten  
        lda #00       Bildschirm-       
        sta 53280      farben           
        lda #11        setzen           
        sta 53281      und              
        lda #<(text)   Begrüßungs-      
        ldy #>(text)   Text             
        jsr strout     ausgeben.        
        lda #01       Sprite 0          
        sta vic+39    als               
        sta vic+21    Maus-             
        lda #150      pfeil             
        sta vic       ini-              
        sta vic+1     tiali-            
        lda #41       sieren.           
        sta 2040                        
        cli          IRQs freigeben     
        rts          und ENDE.          
****************************************
nmi     pha          Alle               
        txa           Prozessorregister 
        pha           erstmal           
        tya           auf Stapel        
        pha           retten.           
        cli           IRQs freigeben.   
        lda $dd01    Datenport sporadis 
        eor #$ff     laden und invertie 
        sta mem      merken.            
        lda cia2+13  ICR von CIA2 holen 
        and #$02     Bit 1 isolieren    
        beq buttons  Wenn =0, dann war  
                      Timer A der NMI-  
                      Auslöser,   also  
                      Knopfabfrage.     
        lda mem      Sonst H-Bewegung.. 
        and #$08     Bit für HQ-Signal  
                       aus Datenport iso
                       lieren           
        beq moveleft  Wenn 0 war ->links
        bne moveright Wenn 1 war ->rechs
buttons lda mem      Aus Datenport die  
        and #$30     Bits 4 und 5 (Mau  
                     knöpfe) isolieren  
        beq bye      Wenn =0, dann war  
                     ner gedrückt.      
        and #$20    Sonst Bit5 isolier  
        beq leftone Wenn =0, war der    
                       linke gedrückt   
        lda #42     Spritepointer       
        ldx #01      und Timerwert lad  
l8      sta 2040     und setzen.        
        stx cia1+6   (Timerwert in BEI  
        stx cia2+6   CIAs!)             
        jmp bye      NMI beenden.       
leftone lda #41     Spritepointer und   
        ldx #00     Timerwert für link  
        jmp l8      Taste setzen        
****************************************
irq    lda cia1+13  ICR von CIA1 laden  
       and #$02     Bit 1 isolieren     
       bne ok       Wenn =1, dann wars  
                     ein Maus-IRQ       
       jmp sysirq   Sonst auf SysIRQ    
                     springen           
ok     cli          IRQs freigeben      
       lda $dd01    Datenport laden und 
       eor #$ff      invertieren.       
       and #$04     Bit für VQ-Signal   
                     isolieren          
       beq moveup   Wenn 0 war -> hoch  
       bne movedown Wenn 1 war -> runter
****************************************
   Hier nun noch einige Erläuterungen:  
1)Wie Sie sehen, müssen wir bei NMIs den
  Prozessorregister  "von Hand"  auf den
  Stapel retten. Bei NMIs geschieht dies
  nicht durch eine Routine im  Betriebs-
  system,  so  wie  es  bei den IRQs der
  Fall war.                             
2)Nachdem  eine  der  beiden  Interrupt-
  routinen  aufgerufen  wurde,   wird so
  früh wie möglich das  IRQ-Flag  wieder
  gelöscht und die IRQs zugelassen.  Das
  ist deshalb so wichtig, weil die  IRQs
  beim Auftreten eines Interrupts   (sei
  das ein  IRQ  oder ein NMI)   gesperrt
  werde.Befindet sich nun aber der Rech-
  ner gerade in einem NMI,   während die
  Maus der Vertikalen bewegt wird,    so
  wird kein IRQ ausgelöst,   weil dieser
  ja noch gesperrt ist. Um das doch noch
  zu ermöglichen müssen wir den  IRQ ex-
  plizit freigeben.                     
  Bei  NMIs brauchen wir darauf nicht zu
  achten,  weil NMIs ja nicht maskierbar
  sind.Das heißt,daß ein NMI immer einen
  NMI unterbrechen kann!                
3)Denken  Sie  bitte  nach wie vor daran
  daß die  Daten  der  Datenports inver-
  tiert in den CIA-Registern stehen. Wir
  müssen  sie  beim Lesen deshalb gleich
  nochmal invertieren.Das ist gerade bei
  der  Maustastenabfrage   sehr wichtig,
  weshalb der  Datenport  in  jedem Fall
  erst einmal invertiert wird,bevor eine
  Entscheidung getroffen wird, woher der
  NMI überhaupt kam.                    
  Bei der Vertikalabfrage, hätte ich den
  Datenport nicht  unbedingt invertieren
  müssen. Da hier lediglich nur ein eim-
  ziges Bit abgefragt wird,hätte ich die
  Branchbefehle zu den Bewegungsroutinen
  ebenso vertauschen k nnen.   Der Voll-
  ständigkeit halber wird hier der  Wert
  jedoch ebenfalls invertiert.          
4)Sicher  hat  Sie die merkwürdige Maus-
  button abfrage etwas verwirrt.Ich habe
  hier noch eine kleine Funktion  einge-
  baut die durch die Art unserer Abfrage
  ganz einfach zu  programmieren  wurde.
  Zunächst einmal  wird  durch den Druck
  auf einen der  Mausknöpfe   der Sprit-
  pointer zwischen den Spriteblöcken  00
  und 42 hin- und hergeschaltet.    Dies
  nur,  um  Ihnen  die Mausbuttonabfrage
  optisch zu signalisieren.   Zusätzlich
  wird,    je nach dem welchen Knopf sie
  noch drücken,  ein anderer Wert in die
  Timer-Register geschrieben.Drücken Sie
  die linke Taste,so ist das der Wert 0,
  wie wir es für die  Abfrage  ja  schon
  vereinbart hatten.  Drücken Sie jedoch
  die rechte Maustaste, so wird der Wert
  1 in die Timer geladen.   Durch diesen
  kleinen, aber effektiven  Trick können
  wir die Mausauflösung halbieren.   Da-
  durch,  daß nun 2 Impulse von der Maus
  kommen müssen,  bis ein Interrupt auf-
  tritt müssen Sie die Maus doppelt wait
  über den Tisch bewegen,   um den Maus-
  pfeil  eine  bestimmte  Strecke weg zu
  bewegen.Das kann oftmals kanz nützlich
  sein, z.B.wenn man genau zeichnen muß.
  Wenn Sie  brigens den Wert 2 die Timer
  schreiben, so verkleinet sich die Auf-
  lösung um ein Drittel und so fort...  
5)Achten Sie bitte auch auf die Abfragen
  in den Interruptroutinen, von  welchen
  Quelle der Interrupt kam.  Im ICR sind
  dann n mlich die  entsprechenden  Bits
  die auch beim Einstellen der Interrup-
  quellen benutzt werden gesetzt.So kön-
  nen wir also unterscheiden, von wo ein
  Interrupt kam.                        
6)Die Routinen MOVELEFT, MOVERIGHT,MOVE-
  UP und MOVEDOWN sind Routinen die  den
  Mauspfeil  bewegen  und  sollen   hier
  nicht näher erläutert werden. Sie kön-
  nen  Sie  sich  aber  gerne im Source-
  Listing  "AM GA-MAUS3.SRC"  auf dieser
  MD anschauen                          
7)Das Label  ENDIRQ enthüllt die Adresse
  $EA7E. Ab dieser Adresse stehen im Be-
  triebssystem  die  Befehle,  mit denen
  jeder Interrupt  (auch NMIs)   beendet
  werden.Es werden einfach die Prozesor-
  register  wieder  vom  Stapel  geholt.
  Um unsere eigenen  Interrupts  zu  be-
  enden springe ich also der Einfachheit
  halber gleich diese Adresse an.       
Natürlich brauchen  Sie  zum Betrieb der
neuen  Mausabfrage  einen neuen Adapter-
stecker.  Damit das nicht allzu umständ-
lich wird,  habe  ich  die Belegungen im
Großen  und  Ganzen  so gelassen wie sie
beim  erst  Adapterstecker  waren.   Sie
müssen lediglich zwei Leitungen umlöten:
* Das  V-Signal  (Pin 1 an der  Joyport-
  buchse) kommt jetzt an CNT1 (=Pin 4 am
  Userport - vorher Pin C).             
* Das  H-Signal  (Pin 2 an der  Joyport-
  buchse) kommt jetzt an CNT2 (=Pin 6 am
  Userport - vorher Pin D).             
 Schließen Sie den neuen Stecker nun bei
abgeschaltetem 64er am Userport an,  und
stecken Sie eine  AMIGA-Maus  am anderen
Ende ein.  Jetzt können Sie das Programm
"AMIGA-MAUS3"von dieser MD laden und mit
RUN starten. Wie Sie sehen, können Sie  
nun  auch  weiterhin Eingaben machen, da
der Cursor weiterhin blinkt.  Denken Sie
nun daran, daß es bei Diskettenzugriffen
Probleme geben wird,     da die NMIs den
Datenverkehr stören(sollten Sie noch aus
dem ersten Teilen dieses Kurses wissen).
In solchen Fällen ist es ratsam die  Ab-
frage doch abzuschalten  (z.B. indem man
die Timer einfach anhält,   oder sie als
Interruptquellen sperrt).               
 Zum  Schluß  möchte ich Ihnen noch eine
weitere Funktion der CIAs erklären.  Nur
mit dem  Userport  erhält  sie überhaupt
einen Sinn,  weshalb  ich  sie bis jetzt
auslassen mußte.                        
Vielleicht erinnern Sie sich noch daran,
daß das Register 12 einer  CIA das soge-
nannte  "Serial-Data-Register" ist.  Mit
diesem Register kann über die SP-Leitung
(die ja von beiden  CIAs am Userport an-
liegt) ein einfacher serieller Datenaus-
tausch mit einem anderen Rechner(im ein-
fachsten Fall ebenfalls ein 64'er statt-
finden. Das kann sehr nützlich sein wenn
man z.B. ein Spiel programmieren möchte,
bei dem zwei  Spieler  an  jeweils einem
eigenen  Rechner  gegeneinander  spielen
Wenn das Spielprogramm also  Daten  über
die Tätigkeiten und Bewegungen des ande-
ren Spielers benötigt.                  
Über das  SD-Register wird dieser Daten-
austausch stark vereinfacht und ist fast
noch unkomplzierter,   als wenn man sich
der   normal   Seriellen   Schnittstelle
(RS232) des Betriebssystems bedient.    
 Bei der Datenübertragung müssen wir un-
terscheiden, ob die SP-Leitung nun auf  
Ein oder Ausgang geschaltet ist.    Dies
wird mit Bit 6 des    Control-Registers-
Timer A (Reg.14) angegeben.Ist es auf 1,
so ist SP auf Ausgang, ist es auf 0,  so
ist SP auf Eingang geschaltet.   Je nach
Betriebsart  verhält  sich die Benutzung
von SDR wie folgt:                      
* Wenn SP Ausgang ist, so wird ein Wert,
  der in das  SDR  geschrieben  wird mit
  der halben Unterlauffrequenz von Timer
  A  in  den  entsprechenden  CIA  an SP
  "herausgesch ben". Das heißt,  daß der
  Wert Bit für Bit, bei jedem Timerunter
  lauf an SP e scheint.    Nach 8 Unter-
  läufen ist SDR wi der leer und es wird
  ein Interrupt ausgelöst.   Bit3 im ICR
  zeigt an,  daß  der  Interrupt von dem
  leeren SDR-Regist kommt.              
* Wenn SP Eingang ist, so wird mit jeder
  steigenden Flanke an  CNT der entspre-
  chende CIA der Wert,der gerade anliegt
  (0 oder 1) in ein internes  Schiebere-
  gister übernommen.    Ist dies Mal ge-
  schehen,   so wird der Wert in das SDR
  übertragen und ebenfalls ein Interrupt
  ausgelöst.Hier erkennt man ebefalls an
  Bit 3 im ICR, daß das SDR voll ist und
  ausgelesen werden kann.               
 Kombiniert man das Ganze jetzt noch mit
der Möglichkeit, daß die  CIA  bei einem
Timerunterlauf ein Signal an PB6 anlegen
kann,so kann man sehr einfach Daten aus-
tauschen. Möchten Sie z.B.Daten an einen
anderen C64 senden,   so müssen Sie sich
ein Kabel bauen,   daß die Userporte der
beiden  Rechner  miteinander  verbindet.
Dabei sollte der SP-Ausgang von Rechnern
mit dem SP-Eingang von Rechner 2 verbun-
den sein und die Leitung PB6 von Recher1
mit der Leitung CNT von Rechner2 (ob SP1
oder SP2, bzw.CNT1 oder CNT2 hängt davon
ab mit welcher  CIA  sie die Daten über-
tragen wollen).                         
Jetzt müssen Sie im Control-Register von
Timer A  (des sendenden Rechners)   noch
festlegen,  daß  das  Signal an  PB6 bei
jedem  Timerunterlauf in die jeweils an-
dere Lage gekippt werden soll.   Das ge-
schieht,  indem  Sie  die  Bits  1 und 2
dieses Registers auf 1 setzen.   Dadurch
erscheint  nämlich  ebenfalls  mit   der
halben Unterlauffrequenz von Timer A(des
sendenden Rechners)  ein  Signal  an PB6
und  läst  somit  die  Datenübernahme am
empfangenden Rechner aus!               
  Das war es dann endgültig mit dem CIA-
Kurs. Ich hoffe,  daß Sie nun einen bes-
seren Einblick in die  Funktionen dieser
beiden kleinen,  aber  extrem  mächtigen
Bausteine  innerhalb  unseres   Rechners
haben.    Wie Sie sehen lassen sich sehr
viele Probleme mit  Interrupts  leichter
lösen (wie die Mausabfrage beweist). Zu-
sätzlich  können  Sie  mit  dem Userport
vielf ltige Har wareerweiterungen leicht
und einfach bedienen.                   
  Ich freue mich also, wenn es Ihnen ein
wenig  Spaß  gemacht  hat  und  bi n für
Kritik  und  Anregungen  zu neuen Kursen
immer  zu  haben (auch ein kleiner Kurs-
autor kriegt gerne Leserpost).          
   Bis auf Weiteres also ein letztes Mal
"Servus"                                
                   Ihr Uli Basters (ub) 



Valid HTML 4.0 Transitional Valid CSS!