Die Textseiten des Buchs in vorformatiertem ASCII, zum Teil auch schon in echter HTML-Darstellung.

Hauptkategorie: 8-Bitter
Erstellt: 16 Februar 2014
Zugriffe: 1750




                                   D I E    P I A
                                   --------------

            Die  PIA wird im Atari hauptsächlich als  Peripheriebaustein
            für  die  Joystickeingänge verwendet.  Zudem steuern  einige
            Ausgänge der PIA die MMU des Atari 600/800XL.  Bei den alten
            Atari-Geräten werden diese Ausgänge für den 3.  und 4.  Joy-
            stickanschluß  verwendet.  Ansonsten übernehmen weitere  An-
            schlüsse der PIA die Steuerung des seriellen Ports.


            Die  PIA ist im Gegensatz zu Bausteinen wie dem  ANTIC  oder
            dem   GTIA  kein  Spezialbaustein,  sondern  ein   Standard-
            peripheriebaustein  (6520  oder 6820) der  65XX- bzw.  68XX-
            Reihe.

            Sie  verfügt  über zwei unabhängige 8-bit breite Ports  (mit
            den Leitungen PA0-7 und PB0-7), bei denen sich jedes einzel-
            ne Bit über sogenannte Datenrichtungsregister als  Ein- oder
            Ausgang  programmieren läßt.  Für jeden der Ports sind  zwei
            Kontrollein- bzw.  -ausgänge  vorhanden (CA1,  CA2,  CB1 und
            CB2).  Die beiden "Hälften" der PIA beeinflußen sich  grund-
            sätzlich nicht und sind, abgesehen von kleinen Unterschieden
            in  den elektrischen Eigenschaften der Ports (die jedoch nur
            für Schaltungsentwickler wichtig sind) und Unterschieden  in
            der Behandlung von CA2/CB2,  identisch. Über die Kontrollka-
            näle  ist  es möglich,  Interrupts der CPU  auszulösen.  Die
            Kontrollkanäle  sind ursprünglich für das sogenannte  "Hand-
            shaking",  das heißt für die Synchronisation der  Datenüber-
            tragung der PIA-Ports gedacht. Da sie aber universell ausge-
            legt  sind,  konnten  sie von Atari auch für  andere  Zwecke
            verwendet  werden.  Die  Ports  der PIA werden nur  für  die
            Joysticks und die MMU,  die kein Handshaking benötigen,  be-
            nutzt.




            Es folgt eine Tabelle der Belegung der PIA-Portleitungen:
            (Die  Angaben von PIN-Nummern beziehen sich jeweils auf  die
            Steckverbinder und nicht auf die PIA-PINs)

            PORT A :

            PA0      Joystick-Port 1,  vorwärts     (PIN 1)
            PA1      Joystick-Port 1,  rückwärts    (PIN 2)
            PA2      Joystick-Port 1,  links        (PIN 3)
            PA3      Joystick-Port 1,  rechts       (PIN 4)
            PA4      Joystick-Port 2,  vorwärts     (PIN 1)
            PA5      Joystick-Port 2,  rückwärts    (PIN 2)
            PA6      Joystick-Port 2,  links        (PIN 3)
            PA7      Joystick-Port 2,  rechts       (PIN 4)

            CA1      SIO-Anschluß "Proceed"         (PIN 9)
            CA2      SIO-Anschluß "Motor-Kontrolle" (PIN 8)

            PORT B :

            PB0      MMU  (ROM/RAM, RAM im Betriebssystem-Bereich)
            PB1      MMU  (BasEn, Basic einschalten)
            PB2-6    nicht verwendet
            PB7      MMU  (TEST, Selbsttestprogramm einblenden)

            CB1      SIO-Anschluß "Interrupt" (PIN 13)
            CB2      SIO-Anschluß "Kommando" (PIN 7)


            Bei  den alten Atari-Geräten ist Port B mit Joystick 3 und 4
            wie Port A mit Joystick 1 und 2 belegt.


            Die  PIA  belegt im System mindestens 4 Bytes.  Daß  sie  im
            Atari  erheblich mehr belegt,  liegt an der  unvollständigen
            Adressdekodierung.  Jede PIA-Hälfte hat also zwei  Adressen.
            Diese  nennen sich PORTA,  PORTACNTL,  PORTB und  PORTBCNTL.
            PORTACNTL  und  PORTBCNTL steuern die  Funktionen  der  PIA.
            Außerdem wird durch sie entschieden,  ob man in die Adressen
            PORTA  und  PORTB zu übertragende Daten schreibt  oder  über
            diese Adressen die Datenrichtungsregister programmiert.

            Jedes Bit in einem der Datenrichtungsregister  repräsentiert
            ein Bit des jeweiligen Ports.  Ist das entsprechende Bit des
            Datenrichtungsregisters  "0",  so fungiert das Bit des Ports

            als  Eingang.  Dementsprechend dient das selbe Bit als  Aus-
            gang,  wenn das dazugehörige Bit des Datenrichtungsregisters
            high ist.


            Es  folgt die Beschreibung der Funktion der  einzelnen  Bits
            von Register PORTACNTL:

            Bit 0 und 1    CA1 Steuerung
            Bit 2          wenn  "0"  dann wird über Adresse  PORTA  das
                           Datenrichtungsregister A angesprochen
            Bit 3 bis 5    CA2 Steuerung
            Bit 6          IRQA1
                           beim Lesen des Registers PORTACNTL ist dieses
                           Bit "1", wenn zuvor die Interruptbedingung an
                           CA2 vorlag. Beim Lesen des Portregisters wird
                           dieses Bit auf "0" zurückgesetzt.
            Bit 7          IRQA2
                           wie Bit 6,  aber anstelle von CA2 wird dieses
                           Bit von CA1 gesteuert.


            Die   Steuerung  von  CA1  erfolgt,   wie  aus  der  Tabelle
            ersichtlich, durch Bit 0 und Bit 1 von PORTACNTL:


            Bit 1 Bit 0    Beschreibung

             0     0       Bei  der fallenden Flanke von CA1 wird Bit  7
                           des PORTACNTL "1". Der Interruptausgang A der
                           PIA bleibt auf logisch "1".
             0     1       Bei  der fallenden Flanke von CA1 wird Bit  7
                           des PORTACNTL "1". Der Interruptausgang A der
                           PIA  geht  auf logisch "0" und fordert  somit
                           einen IRQ von der CPU.
             1     0       Bei der steigenden Flanke von CA1 wird Bit  7
                           des PORTACNTL "1". Der Interruptausgang A der
                           PIA bleibt auf logisch "1".
             1     1       Bei  der steigenden Flanke von CA1 wird Bit 7
                           des PORTACNTL "1". der Interruptausgang A der
                           PIA  geht auf logisch "0" und  fordert  somit

                           einen IRQ von der CPU.
            CA2 Steuerung:

            Ist  Bit  5 des PORTACNTL low,  so dient CA2  ebenfalls  als
            Interrupteingang. Dabei gilt die gleiche Tabelle wie für die
            Steuerung von CA1. Statt Bit 0 und Bit 1 kontrollieren Bit 3
            und  4 des PORTACNTL-Registers die Funktion.  In die Tabelle
            ist statt Bit 7 des PORTACNTL, Bit 6 einzusetzen.
            Ist Bit 5 des PORTACNTL high,  so dient CA2 als Ausgang.  Es
            gilt dabei folgende Tabelle:


            Bit 4 Bit 3    Beschreibung

             0     0       CA2  wird bei der ersten negativen Flanke des
                           Systemtaktes  nach  einer  Leseoperation  von
                           PORTA  low und wieder high,  wenn Bit  7  des
                           PORTACNTL durch CA1 gesetzt wird.
             0     1       CA2 wird bei der ersten negativen Flanke  des
                           Systemtaktes  nach  einer  Leseoperation  von
                           PORTA low und bei der ersten negativen Flanke
                           des Systemtaktes, bei der die PIA nicht ange-
                           sprochen wird, wieder high.
             1     0       CA2  bleibt low  solange  dieses  Bitmuster
                           anliegt.
             1     1       CA2  bleibt high solange  dieses  Bitmuster
                           anliegt.



            Die  Steuerung  des Port B ist im Aufbau  gleich   der   des
            Port A.  Alle Tabellen mit Ausnahme der letzten können über-
            nommen  werden.  Jedoch muß PORTBCNTL anstelle von PORTACNTL
            betrachtet werden.  Statt IRQA muß es IRQB heißen, statt CA1
            und CA2 entsprechend CB1 und CB2 und statt des Zugriffs  auf
            das  Datenrichtungsregister A steuert Bit 2 den Zugriff  auf
            das Datenrichtungsregister B.  Interrupts,  die von CB1 bzw.
            CB2  ausgehen,  werden der CPU über Interruptausgang B über-
            mittelt.


            Wenn  Bit 5 des PORTBCNTL high ist,  dient CB2 als  Ausgang.
            Dabei gilt folgende Tabelle:


            Bit 4 Bit 3    Beschreibung

             0     0       CB2  wird bei der ersten positiven Flanke des
                           Systemtaktes nach einer Schreiboperation  auf
                           PORTB  low.  Wird  Bit 7 von außen durch  CB1
                           gesetzt, wird CB2 wieder high.
             0     1       CB2 wird bei der ersten positiven Flanke  des
                           Systemtaktes  nach einer Schreiboperation auf
                           PORTB low, und bei der ersten positiven Flan-
                           ke  des Systemtaktes,  bei der die PIA  nicht
                           angesprochen wird, wieder high.
             1     0       CB2   bleibt  low, solange  dieses  Bitmuster
                           anliegt.
             1     1       CB2  bleibt  high, solange  dieses  Bitmuster
                           anliegt.



            Auf den ersten Blick erscheinen die  Steuerungsmöglichkeiten
            der PIA sicherlich unübersichtlich.  Bei Überlegungen sollte
            man jedoch beachten, daß Port A ursprünglich als Eingang und
            Port B als Ausgang gedacht war. Bei genauerem Betrachten der
            Steuermöglichkeiten wird der Sinn der diversen Möglichkeiten
            der  Kontrollkanäle CA1,  CA2,  CB1 und  CB2  deutlich.  Sie
            ermöglichen  eine Verbindung einer PIA mit anderen  Periphe-
            riebausteinen,  bei  der  jeweils die CPU ein Signal  erhält
            (Interrupt),  wenn die ausgegebenen Daten vom Empfänger ver-
            arbeitet sind oder neue Daten zum Einlesen durch den Prozes-
            sor zur Verfügung stehen.  Die Interrupts lassen sich  zudem
            abschalten.  Die  CPU kann trotzdem abfragen,  ob die Unter-
            brechungsbedingung erfüllt ist. Sie kann auch beim Auftreten
            eines Interrupts die Herkunft des selben durch Abfragen  von
            Bit  6  und  7 von PORTACNTL  bzw.  PORTBCNTL  lokalisieren.
            Außerdem  lassen  sich die Kontrollkanäle direkt  vom  Peri-
            pheriegerät beeinflußen,  dies geschieht natürlich erheblich
            schneller als eine Steuerung der Kontrollkanäle von der  CPU

            aus.  Damit  läßt sich die  Datenübertragungsrate  erheblich
            erhöhen.  Mit  diesen Möglichkeiten der PIA läßt  sich,  wie
            schon erwähnt,  ein automatischer "Handshake" zwischen Peri-
            pheriegerät und Hauptgerät aufbauen.


            Im  Atari-System  wird die PIA  nicht  zur  Datenübertragung
            benutzt.  Bei  der Programmierung der PIA ist darauf zu ach-
            ten, andere PIA-Anwendungen nicht zu beeinflussen. Bei Fehl-
            programmierungen  der PIA ist es zum Beispiel  möglich,  daß
            der serielle Port gestört wird, da die Steuerung des seriel-
            len  Ports über die PIA erfolgt.  Eine weitere Gefahr stellt
            die  MMU dar.  Bei falscher Programmierung der PIA wird  der
            Rechner umweigerlich durch die falsche MMU-Steuerung abstür-
            zen. Auch hier ist besondere Vorsicht geboten.



            Die PIA-Register befinden sich an folgenden Adressen:

            PORTA          54016     $d300
            PORTB          54017     $d301
            PORTACNTL      54018     $d302
            PORTBCNTL      54019     $d303


            Wer die PIA bereits aus anderen Mikrocomputersystemen kennt,
            wird  sich  über die Reihenfolge der  PIA-Register  wundern.
            Die normale "Reihenfolge" der Register ist bekanntlich

                 PORTA     PORTACNTL     PORTB     PORTBCNTL

            Bei den Atari-Geräten existiert jedoch die oben beschriebene
            Reihenfolge,  da die beiden Adressleitungen für die Register
            der PIA vertauscht sind.



            Um die Stellung der Joysticks festzustellen,  muß der Inhalt
            der Register PORTA und PORTB gelesen werden.  Die Auswertung
            der  Register  ist  jedoch gerade für  Anfänger  nicht  ganz

            einfach.  Daher erstellt das Betriebssystem während der Ver-
            tikalsynchronisation Speicherstellen,  die die Stellung  der
            Joysticks  repräsentieren  (diese  Register  sind  letztlich
            Schattenregister der Register PORTA und PORTB) :

            Joystick1      632       $278
            Joystick2      633       $279
            (Joystick3)    634       $27A      nur bei Atari 400/800 !
            (Joystick4)    635       $27B      nur bei Atari 400/800 !


            Diese  Speicherstellen enthalten die Stellung der  Joysticks
            nach folgendem Muster:
                                               10        6
                                          11        15        7
                                               9         5
Hauptkategorie: 8-Bitter
Erstellt: 16 Februar 2014
Zugriffe: 1909


                                 D E R    P O K E Y
                                 ------------------


















            1) ALLGEMEINES

            2) TONERZEUGUNG

            3) TASTATURABFRAGE

            4) PADDLESTEUERUNG

            5) SERIELLE EIN-/AUSGABE

            Der POTentiometer and KEYboard-Controller-Chip ist der drit-
            te  Spezialbaustein im Atari 600XL/800XL.  Er übernimmt  zum
            Einen fast die gesamte Tonsteuerung, zweitens ist er für die
            Kommunikation  mit extern anzuschließenden Geräten zuständig
            und als letztes übernimmt er das Einlesen der Paddle-Kanäle.

            Als  Verbindung  zur CPU stehen ihm  die  8  Datenleitungen,
            Takt- Schreib-/Leseleitung,  eine Interrupt- und vier Adreß-
            leitungen  zur Verfügung.  Über  eine  Hardware-Resetleitung
            verfügt der POKEY nicht.

            Mit  seinen vier Adreßleitungen können im POKEY 16 verschie-
            dene  Daten- beziehungsweise  Steuer-Register   angesprochen
            werden.

            Diese  16  Register  teilen sich hauptsächlich in  9  Tonre-
            gister,  4 Übertragungsregister,  ein nicht belegtes und ein
            Interruptverarbeitungsregister auf.







            ********************
            *                  *
            *                  *
            *   TONERZEUGUNG   *
            *   ------------   *
            *                  *
            ********************


            Der  POKEY besitzt die Möglichkeit,  maximal vier  Tonkanäle
            gleichzeitig oder in Kombination miteinander zu verwalten.

            Jeder  Ton,  den wir hören können,  setzt sich aus  mehreren
            Komponenten  zusammen.  Da ist zum Einen  die  Tonhöhe,  die
            technisch  als  Frequenz bezeichnet wird und in  Hz  (Hertz,
            nach dem bekannten Physiker Heinrich Hertz) gemessen wird.

            Ein Hz ist nun eine komplette Schwingung pro Sekunde,  wobei
            'komplett' bedeutet,  daß bei immer wiederkehrenden Schwing-
            ungsbildern  man sich einen beliebigen Punkt der  Schwingung
            sucht  und  dann  so lange wartet,  bis genau  dieser  Punkt
            wieder erreicht wird. Der Bereich zwischen den beiden gefun-
            denen  Punkten ist dann eine komplette Schwingung.  Hat  man
            nun  1000 Schwingungen pro Sekunde,  so besitzt  das  Signal
            eine Frequenz von 1000Hz, oder auch 1kHz.

            Je größer die Frequenz des Signals ist, umso höher empfinden
            wir den Ton, beziehungsweise das Geräusch.

            Eine  weiteres  Charakteristikum  einer Schwingung  ist  die
            Schwingungsform.  Als  Extrema  wären hier  z.B.  die  reine
            Sinus-Schwingung oder, als Gegenstück dazu, die reine Recht-
            eck-Schwingung zu nennen.  Dies sind jedoch Sonderfälle, die
            sich zwar heutzutage mit elektronischen Mitteln recht sicher
            und  gut herstellen lassen,  die jedoch wegen  ihrer  Ausge-
            prägtheit im Klang derart 'nervend' sind,  daß sie sich kaum
            jemand  länger anhören kann.  Wer das nicht  glaubt,  sollte
            sich  einmal den 440Hz-Normton (Kammerton a) am Telefon fünf
            Minuten lang anhören.

            Alle  Geräusche und Töne,  die wir heutzutage um uns  haben,
            sind Mischformen unterschiedlichster Signalformen.  Aus  der
            jeweiligen  Signalzusammensetzung können wir,  in Verbindung
            mit den sogenannten Hüllkurven, unterschiedliche Signalquel-
            len recht sicher voneinander unterscheiden.  So dürfte  eine
            Verwechselung  zwischen  einem  Waldhorn und  einem  Klavier
            einigermaßen selten vorkommen.

            Die  Hüllkurve beschreibt nun,  wie sich die Lautstärke  des
            jeweiligen Tones im Verhältnis zur Zeit verändert.  Da  gibt
            es z.B. Signale, die sehr schnell laut sind, um dann langsam
            und  gleichmäßig abzuklingen (Klavier),  die Violine dagegen
            erreicht wesentlich langsamer Ihr Lautstärkemaximum.

            Als  letzte wesentliche Eigenschaft jedes Tones  verarbeiten
            wir mehr oder weniger unbewußt den Frequenzbereich,  in  dem
            sich das Signalgemisch ungefähr befindet.  Es hört sich ein-
            fach anders an, wenn man Musik direkt aus der HiFi-Stereoan-

            lage  hört,  als wenn man dies über das Telefon  tut.  Nicht
            unbedingt  wegen eventueller Störungen und  Knack-Geräusche,
            sondern  wegen  des enorm eingeschränkten übertragenen  Fre-
            quenzbereichs.  Der  ist von der Post so bestimmt,  daß  die
            übertragenen  Töne hauptsächlich die  Tonhöhen  durchlassen,
            die zur Übermittlung von Sprache wesentlich sind.

            Im POKEY sind nun vier Register enthalten, die nichts weiter
            tun,  als  ein vorgegebenes Taktsignal  mit bestimmter  Fre-
            quenz  durch einen bestimmten,  ebenfalls vorzugebenden Wert
            zu teilen.  Dadurch entsteht dann eben ein niedrigerer  Ton.
            Da das jedoch zu primitiv wäre, und sich damit nach dem oben
            gesagten keine vernünftigen Klänge erzeugen ließen,  gibt es
            nun  noch  weitere Möglichkeiten.  Als erstes kann man  z.B.
            zwei solcher Zähler aneinanderhängen,  das heißt  also,  den
            Ausgang  des  einen Zählers mit dem Eingang des  zweiten  zu
            verbinden.  So  kann Zähler 2 an Zähler 1 angehängt  werden,
            genauso  wie Zähler 4 an Zähler 3.  Dieses Anhängen hat fol-
            genden Zweck:

            Durch die Größe der einzelnen Zählregister von 8 Bit  ergibt
            sich ein mögliches Teilerverhältnis im Bereich von 1 bis 256
            (intern wird auf den Registerwert eine %1 addiert). Hängt man
            nun  zwei  Zähler aneinander,  so erhält man  ein  mögliches
            Verhältnis  von 1 bis 65536,  da ja nun 16 Bit zur Verfügung
            stehen.

            Es gibt somit die Möglichkeit,  vier 8bit-Kanäle oder  einen
            16bit-Kanal  und zwei 8bit-Kanäle oder,  als  letztes,  zwei
            16bit-Kanäle zu betreiben. Alles dies wird über entsprechen-
            de Satusbits festgelegt.

            Die  eigentlichen  Teilerverhältniswerte werden in die  ent-
            sprechenden Register AUDIFREQ1 bis AUDIFREQ4 geschrieben.

            Als  Takt  kann für jedes der Register  ein  64kHz-,  15kHz-
            oder,  und das gilt nur für Kanal 1 und 3, ein  1,77MHz-Takt
            gewählt werden.  Je höher der Takt gewählt wird, desto höher
            ist bei gleichem Teilerverhältnis das Ausgangssignal.

            Aus der Kombination der Takteingangsfrequenzen und der  Tei-
            lerverhältnisse  lassen sich nun sämtliche  Frequenzbereiche
            von 0 bis 1,77/2 MHz= 887kHz  erreichen.  Die letzte Teilung
            durch  den Faktor zwei ist immer gegeben und hat den  Zweck,
            immer nur symmetrische Signale auszugeben. Hat man ein Digi-
            talsignal als letztes durch den Faktor zwei geteilt,  so ist
            dieses  Signal genauso lange 'an' wie 'aus',  also  zeitlich
            symmetrisch. Diese Bedingung ist wesentlich, denn ein unsym-
            metrisches  Signal  hört sich völlig anders an als ein  sym-
            metrisches,  so  daß sich bei Veränderung  von  Teilerwerten
            nicht  nur die Frequenz,  sondern auch die  Signalform,  und
            somit  der  Klang  ändern würde,  wenn nicht zum Schluß  das
            Signal immer in ein symmetrisches abgeändert würde.

            Neben  der  Frequenz läßt sich auch noch die  Art  und  Form
            eventueller  Verzerrung  einstellen.  Dazu wird das  normale
            Ausgangssignal,  das  von den Zählregistern geliefert  wird,
            logisch verknüpft mit zyklisch auftretenden 'Störungen'.

            Diese  Störungen werden über sogenannte Schieberegister  er-
            zeugt,  die wie eine lange Röhre funktionieren.  Schiebt man
            in das eine Ende der Röhre Signale hinein,  kommt irgendwann
            einmal am anderen Ende eben dieses Signal heraus.  Nimmt man
            dieses  Signal dann wieder,  um es am vorderen  Ende  wieder
            hineinzutun, hat man einen Zyklus, der endlos weitergeht. Um
            nun  nicht einen völlig 'langweiligen',  einmaligen Rhythmus
            herauszubekommen,  wendet man noch einen weiteren Trick  an:
            Die  Röhre wird an einigen Stellen 'angebohrt',  und die  an
            der  Stelle anliegenden Signale zusammen mit dem  End-Signal
            auf den Röhreneingang gelegt. Dadurch ist immer noch sicher-
            gestellt,  daß  es sich bei dem ganzen Vorgang um einen zyk-
            lischen  handelt,  aber dessen Wiederholrate ist  wesentlich
            geringer.

            Es sind nun im POKEY drei dieser rückgekoppelten  Schiebere-
            gister, die als Polynom-Zähler bezeichnet werden, vorhanden.
            Es gibt einen 4 Bit langen,  einen mit 5 Bit und einen,  der
            umschaltbar entweder 17 oder 9 Bit Länge aufweist.

            Die  Frequenz wurde,  wie schon erwähnt,  durch die Werte in
            den Frequenzregistern AUDIFREQ1 bis AUDIFREQ4 festgelegt.

            Die Verzerrung und die 16 stufige Lautstärke werden hingegen
            über  die Kontrollregister AUDICNTL1 bis AUDICNTL4  program-
            miert. Die einzelnen Bits dieser Kontrollregister bedeuten:


                      Bit            Bedeutung
                      -------------------------------------------------
                       0             Diese vier Bit sind
                       1             zuständig für die Lautstärke.
                       2             Es sind Werte zwischen $00 und
                       3             $0f möglich (%0000 bis %1111).

                       4             VOLUME_ONLY

                       5             Diese drei Bit werden zur
                       6             Auswahl einer der sechs Verzer-
                       7             rungsmöglichkeiten benutzt (s.Tab).




            Tabelle für die Wertigkeiten der Bits 5,6 und 7 der Register
            AUDICNTLn:



            Bit  7    6    5         Signalmischung
            -----------------------------------------------------------

                 0    0    0         Das vom Zählregister stammende Sig-
                                     nal wird zuerst mit dem  5bit-Poly-
                                     nom,  dann  mit  dem  17bit-Polynom
                                     verknüpft,  bevor es auf die letzte
                                     Teilerstufe  durch den Faktor  zwei
                                     geschickt wird.

                 0    x    1         Es  findet nur eine Verknüpfung mit
                                     dem  5bit-Polynom  statt  vor   der
                                     letzten Division.

            Bit  7    6    5         Signalmischung (Fortsetzung)
            -----------------------------------------------------------
                 0    1    0         Das vom Zählregister stammende Sig-
                                     nal  wird zuerst mit dem 5bit-Poly-
                                     nom,   dann  mit  dem  4bit-Polynom
                                     verknüpft,  bevor es auf die letzte
                                     Teilerstufe  durch den Faktor  zwei
                                     geschickt wird.

                 1    0    0         Die  Ausgangsfrequenz wird mit  dem
                                     Signal des 17bit-Polynoms verknüpft
                                     und  dieses Signal auf  die  letzte
                                     Teilerstufe geschickt.

                 1    x    1         Diese 2 Kombinationen ergeben einen
                                     reinen  Ton,  da keinerlei Verknüp-
                                     fung des Ausgangssignals mit  einem
                                     der Polynome geschieht, sondern nur
                                     die letzte Justage-Division.

                 1    1    0         Es erfolgt nur eine Verknüpfung der
                                     Ausgangsfrequenz  mit dem vier  bit
                                     breiten  Polynom.  Danach wird  das
                                     Ergebnis,  genau  wie alle anderen,
                                     noch  einmal  durch den  Wert  zwei
                                     geteilt.

            Das  'x'  in der Tabelle bedeutet,  daß hier  '0'  oder  '1'
            stehen darf.

            Das  VOLUME_ONLY-Bit  aus jedem der vier  AUDICNTLn-Register
            schaltet  die gesamte interne Zähl-,  Verzerrungs- und  Ver-
            knüpfungsmaschinerie aus und bestimmt,  daß als Ausgangssig-
            nal  genau die der Lautstärke entsprechende Spannung  ausge-
            sendet  werden soll.  Ist also VOLUME_ONLY gesetzt  und  die
            Lautstärke auf 16 (volle Lautstärke), so wird die im Fernse-
            her/Monitor  befindliche  Lautsprechermembran  so  weit  wie
            möglich aus ihrer Ruheposition herausgelenkt. Setzt man dann
            die Lautstärke wieder auf Null zurück,  so fällt die Membran
            ebenfalls wieder in ihre Ruheposition zurück, es ergibt sich
            ein Knacken im Lautsprecher.

            Die   Aufgabe dieser Zusatzeinrichtung ist natürlich  nicht,
            nur ein Knackgeräusch zu erzeugen. Mit dieser Methode unter-
            liegt der Programmierer annähernd keiner Beschränkung bezüg-
            lich Signalform und Frequenz,  da jede einzelne Membranbewe-
            gung  des  Lautsprechers programmiert werden  kann.  Es  ist
            jedoch  bei allzu schnellen Amplitudenänderungen (Amplitude=
            Höhe des Ausschlags bei einer Schwingung) darauf zu  achten,
            daß  zwar  der Atari diese Signale herausgeben  kann,  harte
            Kurven  jedoch durch die dann folgende  Modulation/Demodula-
            tion im Fernseher erheblich abgerundet werden.  Dies  dürfte
            jedoch im Normalfall keine Einschränkung darstellen,  da ein
            Fernseher heutzutage oft schon HiFi-Qualitäten besitzt.

            Im  Großen und Ganzen jedoch kann gesagt werden,  daß zumin-
            dest  mit entsprechendem Softwareaufwand der Atari ohne  Zu-
            satzgeräte alle gewünschten Akustikeffekte erzeugen kann.

            Man  denke da z.B.  an Softwarepakete,  die schon die  alten
            400/800 ohne zusätzliche Hardware haben sprechen lassen. Die
            Sprache war sogar mittelmäßig verständlich.

            Neben  diesen vier,  auf jeden Kanal einzeln  bezogenen  Re-
            gistern  existiert noch ein weiteres,  für die  Tonerzeugung
            wesentliches Register: AUDIOCOM.

            Diese Adresse beinhaltet die folgenden 8 Steuerbits:


                      BIT       Erläuterung
                      -------------------------------------------------

                       0        Schaltet  den  Haupttakt  für  die  vier
                                Frequenzregister  von  64kHz  auf  15kHz
                                zurück, wenn es gesetzt wird.

                       1        Ist  dieses  Bit gesetzt,  wird  in  den
                                Ausgang  von  Kanal 2 ein  Hochtonfilter
                                eingesetzt,  dessen  Characteristik  von
                                Kanal 4 bestimmt wird.

                      BIT       Erläuterung (Fortsetzung)
                      -------------------------------------------------


                       2        In den Ausgang von Kanal 1 wird ein  von
                                Kanal 2 gesteuertes Hochtonfilter einge-
                                fügt.

                       3        Durch Setzen dieses Bits wird Kanal 4 an
                                Kanal  3  angehängt,  so daß ein  16bit-
                                Register entsteht.

                       4        Ist dieses Bit gesetzt,  wird Kanal 2 an
                                Kanal 1 gehängt.

                       5        Dieses  Bit  bewirkt,  daß Kanal  3  mit
                                einer  Grundfrequenz von  ca.  1,77  MHz
                                betrieben wird.

                       6        Das gleiche wie bei Bit 5 für Kanal 1.

                       7        Beim  Setzen dieses Bits wird das 17bit-
                                Polynom in ein 9bit langes Polynom  ver-
                                wandelt.




            Als  allgemeine Berechnungsgrundlage für das Verhältnis  von
            Ein- zu Ausgangsfrequenz kann die Gleichung

            Ausgangsfrequenz = Eingangsfrequenz / 2 ( AUDIFREQn + Off)

            verwendet werden,  wobei Off den Wert 4 erhält, wenn es sich
            bei dem Teiler um einen 8bit-Teiler handelt.  Ist es dagegen
            ein  16bit-Teiler,  muß  Off aus technischen Gründen  mit  7
            angesetzt werden.

            Neben  den Tonerzeugungsaufgaben besitzen diese Zähler  noch
            eine weitere Aufgabe.

            Wenn  einer  der Zähler 1,  2 oder 4 auf Null  zurückgezählt
            hat, wird automatisch vom POKEY ein Interrupt ausgelöst. Die
            Zähler können also genauso gut als Timerbausteine fungieren.

            Um alle Frequenzregister auf die Werte zu setzen,  die  Pro-
            grammiert  wurden  (vor  allem  sinnvoll  beim  Betrieb  als
            Timer!),  wird  einfach  irgend ein Wert in  Adresse  STIMER
            geschrieben.

            Als  'Abfallprodukt' der Polynomzähler entsteht in  Register
            RANDOM eine 8bit-Zufallszahl, die dort entsprechend ausgele-
            sen werden kann.  Sie besteht aus den höchsten 8 Bit des 17-
            /9-bit Polynomzählers.

            Abschließend  zu diesem Thema folgt noch eine  Tabelle,  aus
            der die Teilerverhältnisse der Frequenzregister bei bestimm-
            ten Notenwerten hervorgehen.  Dazu sind folgende Werte  vor-
            auszusetzen:

            AUDIOCOM  = $00      ; also nichts 'Besonderes'

            AUDICNTLn = $Ax      ; x ist die Lautstärke von 0..15

            Mit den genannten Daten,  die nur ein Beispiel sein  sollen,
            ergeben sich die auf der umseitig gedruckten Tabelle folgen-
            de Werte für AUDIOFREQn:

            Es  lassen sich aber auch praktisch alle anderen  Frequenzen
            und somit Notenwerte mit dem Atari erreichen. Dies wird auch
            in  Vergleichen  zwischen den einzelnen  Mikrocomputern  oft
            falsch  dargestellt.  Der Atari verfügt nicht nur über 3 1/2
            Oktaven Frequenzumfang.  Die höchsten erzeugbaren Frequenzen
            liegen weit über der höchsten wahrnehmbaren  Frequenz.  Auch
            die tiefste erzeugbare Frequenz ist nicht mehr hörbar.

            Note           AUDIFREQn Hexadezimal    Dezimal
            -----------------------------------------------------------

            C (tiefes)               $f3            243
            Cis oder Des             $e6            230
            D                        $d9            217
            Dis oder Es              $cc            204
            E                        $c1            193
            F                        $b6            182
            Fis oder Ges             $ad            173
            G                        $a2            162
            Gis oder As              $99            153
            A                        $90            144
            Ais oder B               $88            136
            H                        $80            128
            c (mittleres)            $79            121
            cis oder des             $72            114
            d                        $6c            108
            dis oder es              $66            102
            e                        $60             96
            f                        $5b             91
            fis oder ges             $55             85
            g                        $51             81
            gis oder as              $4c             76
            a                        $48             72
            ais oder b               $44             68
            h                        $40             64
            c'                       $3c             60
            cis' oder des'           $39             57
            d'                       $35             53
            dis' oder es'            $32             50
            e'                       $2f             47
            f'                       $2d             45
            fis' oder ges'           $2a             42
            g'                       $28             40
            gis' oder as'            $25             37
            a'                       $23             35
            ais' oder b'             $21             33
            h'                       $1f             31
            c''                      $1d             29

            ***********************
            *                     *
            *                     *
            *   TASTATURABFRAGE   *
            *   ---------------   *
            *                     *
            ***********************


            Wird  irgend  eine Taste auf der  Tastatur  des  600XL/800XL
            gedrückt,  die  nicht eine der seitlich montierten  Spezial-
            tasten  oder SHIFT oder CONTROL ist,  wird ein Interrupt vom
            POKEY ausgelöst,  der dem Betriebssystem Mitteilung von  dem
            Tastendruck  machen soll.  Von der entsprechenden Interrupt-
            routine wird dann der Tastaturkode aus Register KBCODE  aus-
            gelesen  und für die weitere Verarbeitung im Vertical  Blank
            Interrupt gesichert.

            Eine  Ausnahme hiervon stellt die BREAK-Taste dar:  Wird sie
            gedrückt,  so  erfährt das Bertiebssystem davon  durch  eine
            andere  Statusmeldung  des  POKEY  und  reagiert  dann  ent-
            sprechend durch die Break-Routine darauf.

            Ist es jedoch eine der normalen Tasten, wird das Drücken vom
            POKEY  dadurch bemerkt,  daß er ständig eine Matrix  abfragt
            (pollt), in deren Kreuzungspunkte die einzelnen Tastenschal-
            ter liegen.  Ist nun ein solcher Taster geschlossen, bemerkt
            der  POKEY  dies und erkennt an  seinen  Registern,  welcher
            Schnittpunkt, also welcher Schalter das ist.

            Darüberhinaus besitzt er zwei Signalleitungen,  die ihm mit-
            teilen,  wenn  die  SHIFT- oder CONTROL-Taste gedrückt  ist.
            Alleine  das Drücken dieser beiden Tasten löst  noch  keinen
            Interrupt aus,  verändert jedoch bei einem richtigen Tasten-
            druck dessen Kode.

            Es  sind  maximal 64 Tasten im System erlaubt.  Sie  belegen
            somit die Kodes 0 bis 63 ($00 bis $3f).  Ist die SHIFT-Taste
            gedrückt,  verschiebt sich der generierte Kode um  64,  also
            auf den Bereich 64 bis 127 ($40 bis $7f).

            Im  Falle  der gedrückten CONTROL-Taste würde sich der  Kode
            dann  nochmal um 64 verschieben,  also um insgesamt 128  auf
            den Bereich von 128 bis 191 ($80 bis $bf). Werden SHIFT- und
            CONTROL-Taste gleichzeitig gedrückt,  hat die  CONTROL-Taste
            Vorrang,  so  daß  also insgesamt 192 Tastenkodes  entstehen
            können.

            Um  nun diesen Matrix-Nummern einen sinnvollen  ATASCII-Kode
            zuweisen zu können,  wird eine Tabelle benutzt.  Der  Anfang
            der Tabelle liegt ab (KEYDEFPTR),  also im Initialisierungs-
            zustand  ab Adresse KEYDEF.  Die 192 Byte große Tabelle  be-
            sitzt die folgenden Einträge,  bei denen nur diejenige Funk-
            tion  eingetragen  ist,  die sich ohne SHIFT- oder  CONTROL-
            Taste ergibt:



                    0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
                    ----------------------------------------------

            $00:    L  J  ; /1//2/ K  +  *  O     P  U /C/ I  -  =

            $10:    V     C /3//4/ B  X  Z  4     3  6 /E/ 5  2  1

            $20:    , /S/ .  N     M  / /A/ R     E  Y /T/ T  W  Q

            $30:    9     0  7 /B/ 8    F  H  D    /P/ G  S  A



            /C/ ist die RETURN-Taste
            /S/ ist die Leertaste
            /A/ ist die ATARI-Logo-Taste
            /E/ ist die ESCape-Taste
            /T/ ist die TABulator-Taste
            /B/ ist die BackSpace-Taste
            /P/ ist die CAPS-Taste
            /1/ bis /4/ sind die zwar nicht hardwaremäßig,  aber dennoch
                softwaremäßig vorhandenen Funktionstasten des 1200XL  F1
                bis F4.


            Ob  die SHIFT-Taste gedrückt ist,  besagt Bit 3 von  SKSTAT.
            Ist das Bit Null, ist die SHIFT-Taste gedrückt.

            Eine  genauere  Beschreibung  des Registers  SKSTAT  erfolgt
            noch später.





            ***********************
            *                     *
            *                     *
            *   PADDLESTEUERUNG   *
            *   ---------------   *
            *                     *
            ***********************


            Paddles sind Eingabegeräte,  die nicht nur digitale  Signale
            liefern wie z.B.  Joysticks, sondern die einen analogen Wert
            liefern,  in diesem speziellen Fall handelt es sich um einen
            Widerstandswert.

            Da der Atari bekanntlich nur digitale Signale richtig verar-
            beiten kann,  stellt sich für ihn,  genauer:  Für den POKEY,
            das Problem, aus diesem Widerstandswert eine Zahl zu machen.

            Diesen  Vorgang  nennt man schlichtweg  Analog/Digital-Wand-
            lung,  was  sich englischsprachig abgekürzt A/D-C  schreibt,
            wobei das 'C' für Converting steht.

            Dieser  gesamte Komplex der Analog/Digital-Wandlung und  der
            artverwandten  Digital/Analog-Wandlung  ist  bis  heute  die
            große Schwachstelle an jedem Computersystem.  Nicht, daß die
            Techniker nicht wüßten, nach welchem Verfahren man die Wand-
            lung vornehmen soll.  Da gibt es einige wenige, die sich als
            sinnvoll  in den letzten Jahren herauskristallisiert  haben.

            Dagegen  ist es wesentlich schwieriger,  einen Kompromiß  zu
            finden  aus mittlerer Wandlungsgeschwindigkeit und  Genauig-
            keit des Systems.

            Es ist für einen elektronischen Schaltkreis relativ einfach,
            festzustellen,  ob  er größer oder kleiner/gleich einer Ver-
            gleichsspannung ist.  Es gibt jedoch schon Justierungsaufga-
            ben,  wenn derselbe Baustein feststellen soll,  ob sich  die
            Eingangsspannung innerhalb eines bestimmten Bereichs,  eines
            sogenannten Fensters, befindet.

            Soll der Baustein nun herausfinden, in welchem der z.B. 4096
            Fenster  sich der Eingangsspannungswert befindet,  dann  ist
            das eine langwierige und schwierige Angelegenheit.

            Der  POKEY  ist  nun ein  Baustein,  der  gleichzeitig  acht
            solcher  Kanäle überwacht und ausmißt.  Damit er das  einige
            Male  pro  Sekunde tun kann,  betrachtet er nicht  allzuviel
            mögliche Fenster, sondern nur 228 Stück. Die einzelnen Werte
            der POT-Eingänge (POT steht für Potentiometer, ein veränder-
            barer  elektrischer  Widerstand)  können aus  den  Registern
            POT0 bis POT7 ausgelesen werden.

            Es ist zu beachten,  daß der 600XL/800XL nur insgesamt  vier
            der acht möglichen Kanäle benutzen kann, da er nur über zwei
            Joystickbuchsen verfügt.

            Beim  Vergleich  der Adressenliste für den POKEY fällt  auf,
            daß die Adressen AUDI....n und POTn gleich sind.  Das berei-
            tet auch keinerlei Probleme,  da die AUDI....n-Werte nur  zu
            schreiben und die POTn-Werte nur zu lesen sind.

            Die  eigentliche  Meßprozedur läßt sich über  zwei  mögliche
            Register  starten.  Das eine Register ist SKCNTL,  in dessen
            Bit 2 festgelegt wird,  ob es sich um eine normale oder eine
            sogenannte Schnellmessung handelt.  Ist es eine  Schnellmes-
            sung, so ist sie allerdings recht ungenau.

            Das  andere  Register nennt sich POTGO und wird einfach  mit
            irgendwelchen Daten beschrieben, um eine Messung zu initiie-
            ren.

            Jeder  Kanal besitzt ein Bit in dem  Statusregister  ALLPOT,
            das Auskunft darüber gibt, ob der Kanalwert des entsprechen-
            den  Kanals 'fertig' ist oder nicht.  Ist das  entsprechende
            Bit  gesetzt,  so gilt der Wert nicht,  die Messung ist noch
            nicht fertig.






            *****************************
            *                           *
            *                           *
            *   SERIELLE EIN-/AUSGABE   *
            *   ---------------------   *
            *                           *
            *****************************



            Unter   serieller  Ein-/Ausgabe  versteht  man  das   Senden
            und/oder Empfangen von Daten über hauptsächlich eine einzige
            Datenleitung.  Die serielle Ein-/Ausgabe steht im  Gegensatz
            zur  parallelen Ein-/Ausgabe,  bei der z.B.  komplette Bytes
            auf  nebeneinander verlaufenden elektrischen Leitungen  oder
            anderen Informationsstrecken gesendet oder empfangen  werden
            können.  Solch  eine parallele Übertragungsstrecke ist  z.B.
            der  vielleicht  von Druckern her bekannte  Centronics-Stan-
            dard.

            Steht zur Datenübertragung nur eine einzige Datenleitung zur
            Verfügung,  so muß man sich überlegen, wie die Daten darüber
            zu transportieren sind.

            Will  man  nur  senden oder nur  empfangen,  ist  schon  ein
            Problem gelöst. Soll jedoch sowohl empfangen als auch gesen-
            det  werden  können,  stellt sich die Frage,  ob man  diesen
            Datentransport  nur  über eine Leitung  laufen  läßt  (Halb-
            Duplex),  oder  ob  dafür zwei Leitungen installiert  werden
            (Voll-Duplex).

            Wird das Halb-Duplex-Übertragungsverfahren gewählt,  hat man
            das Problem,  erkennen zu müssen,  ob und welches der  ange-
            schlossenen Geräte gerade senden will.

            Bei Verwendung des Voll-Duplex-Übertragungsverfahrens treten
            an Stelle der oben beschriebenen Übertragungsprobleme höhere
            Leitungskosten auf.

            Da  die Leitungskosten jedoch bei solch kurzen  Verbindungen
            wie  denen des Atari-Systems vernachlässigbar gering sind im
            Gegensatz zu dem Halb-Duplex-Umschaltaufwand,  hat sich  die
            Firma  Atari  für  das für den  Programmierer  und  Anwender
            wesentlich angenehmere Zwei-Leitungsverfahren entschieden.

            Ist  vom  Entwickler diese Frage  entschieden,  stellt  sich
            gleich die nächste: Synchrone oder asynchrone Übertragung?

            Da es sich beim Atari jedoch im Prinzip um selten auftreten-
            de  Übertragungsprozesse handelt,  wird man hier gleich  auf
            die asynchrone Übertragungsweise zurückgreifen.

            Unter  asynchroner Übertragung verstehen wir ein  Verfahren,
            bei dem der Empfänger ständig darauf wartet,  daß einmal ein
            Zeichen übertragen wird.  Anfang und Ende eines solchen Zei-
            chens sind durch ein,  dem Zeichen  vorangehendes,  Startbit
            sowie  durch  ein,  eineinhalb oder zwei Stopbits,  die  dem
            Zeichen folgen müssen, gekennzeichnet.

            Richtig,  das  ist  kein Druckfehler:  Im Gegensatz  zu  der
            Auffassung,  daß  ein Bit die kleinste darstellbare Informa-
            tionseinheit sei,  gibt es nun bei der Datenübertragung auch
            halbe Bits.  Wie dies zustandekommt,  wird leicht klar, wenn
            man sich etwas näher ansieht, wie die Zeichen mit den Start-
            und Stopbits durch die Leitung kommen.

            Bei diesem Übertragungsverfahren wird davon ausgegangen, daß
            immer nur genau ein Zeichen gesendet wird, das in Start- und
            Stopbits  'eingepackt'  ist und außerdem  vom  Programmierer
            sowohl  beim  Empfänger  als auch beim  Sender  die  gleiche
            Übertragungsgeschwindigkeit eingestellt ist. Diese Geschwin-
            digkeit ist das Her(t)z jeder seriellen Übertragung. Während

            bei  einer parallelen Strecke eine Leitung sagt "Hallo  Emp-
            fänger, jetzt kommt ein Byte!" und der Empfänger nach Erken-
            nen  des  Zeichens die Meldung  bringt  "Hallo  Sender,  das
            Zeichen wurde gelesen und verarbeitet", gibt sich hier diese
            Möglichkeit  nicht,  so daß man davon ausgehen muß,  daß der
            Empfänger genau dann ein Bit zu lesen versucht,  wenn es der
            Sender zur Verfügung stellt.


            Genau  diesen  Effekt erreicht man  durch  den  kurzzeitigen
            Gleichlauf  von Sender und Empfänger,  wenn man beiden  mit-
            teilt,  daß  jedes Bit eine ganz bestimmte Zeit anliegt.  Da
            dieser Gleichlauf nur immer ein Zeichen lang existieren  muß
            (denn dann kommt eine neue Synchronisation durch das nächste
            Startbit!), ist das technisch recht einfach lösbar.

            Im  Laufe  der  letzten 30 Jahre haben sich  ganz  bestimmte
            Übertragungsgeschwindigkeiten  durchgesetzt.   Von  Grundge-
            schwindigkeiten  ausgehend,  hat man es durch immer  bessere
            Technik  immer  wieder geschafft,  die  Übertragungsrate  zu
            verdoppeln.  So  existieren  heute die  folgenden  allgemein
            verwendeten Übertragungsraten


                       45,45   Bit/Sekunde (nur in den USA)
                       50      Bit/s     z.B. bei BTX
                      100         "
                      150         "
                      300         "
                      600         "
                    1.200         "      z.B. bei BTX
                    2.400         "
                    4.800         "
                    9.600         "
                   19.200         "
                   38.400         "


            Höhere  Übertragungsraten sind bei seriellen  Schnittstellen
            sehr selten, da es dabei technische Probleme gibt.

            Hat  man es nun also geschafft,  den Sender  beziehungsweise
            Empfänger auf eine bestimmte Übertragungsrate  einzustellen,
            so ist bekannt,  wie lang ein Bit auf der Übrtragungsleitung
            anliegt:

            Ist z.B.  die Übertragungsrate auf 19.200 Bit/s eingestellt,
            ist  jedes Bit 1/19.200 Sekunden,  also ca.  52  millionstel
            Sekunden  lang.  Das ist nicht sehr viel,  aber dem Computer
            genügt es.

            Um nun ein Stopbit zu senden,  wird einfach die Sendeleitung
            für die Dauer eines Bits in den Ruhezustand versetzt. Dieser
            Ruhezustand  kann jedoch auch länger dauern,  z.B.  die 1,5-
            fache Dauer eines Bits; also 1,5 Stopbit!

            Nach dieser etwas technischen Einleitung dürfte eine  Zeich-
            nung von zwei zu übertragenden Zeichen ganz hilfreich sein:

            Es  sollen die Bytes $53 und $8a übertragen werden mit einem
            Startbit und einem Stopbit:

            $53 = %0101 0011
            $8a = %1000 1010

            f   = Leitung im Ruhezustand (SPACE, frei)
            S   = Startbit, immer MARK
            s   = Stopbit, immer SPACE


            -----    --  --    -------- --  --      --  --  ------ SPACE
                 ----  --  ----           --  ------  --  --       MARK

            ffff S 0 1 0 1 0 0 1 1 s ffff S 1 0 0 0 1 0 1 0 s ffff


            Die  Bereiche ffff können beliebig lang sein bei  der  asyn-
            chronen Datenübertragung (daher der Name:  Asynchron,  nicht
            zeitlich festgelegt).

            Nachdem  alle diese Dinge entschieden sind,  ist man nun  in
            der Lage,  einzelne Zeichen (Bytes) zu übertragen,  und zwar
            sowohl zu senden, als auch zu empfangen.

            Um  nun  jedoch eine richtige Datenübertragung  zustande  zu
            bekommen,  ist  es weiterhin noch notwendig,  sich ein soge-
            nanntes Protokoll zu überlegen,  nach dem die einzelnen  Ge-
            räte an der seriellen Leitung angesprochen werden sollen und
            anhand dessen dann komplette Datenblöcke (durch zum Beispiel
            NEWLINE  abgeschlossene  Zeilen oder  Blöcke  fester  Länge)
            gehandhabt werden können.

            Bei Atari sind fast alle an der seriellen Leitung  hängenden
            Geräte  intelligent,  das heißt,  daß sie einen eigenen Kon-
            trollbaustein besitzen,  der die Kommunikation mit dem Host-
            system, also dem Atari 600XL/800XL übernimmt.

            Das einzige nicht intelligente Gerät ist der Cassettenrecor-
            der.  Er wird vom Benutzer ein- und ausgeschaltet,  wenn der
            Computer dies durch Huptöne empfiehlt.

            Andere  Geräte,  wie zum Beispiel der Drucker oder die  ver-
            schiedenen Diskettenstationen lauschen ständig die am  seri-
            ellen  Bus  liegenden Informationen sowie die eine  Leitung,
            genannt KOMMANDO:L,  ab.  Liegt KOMMANDO:L auf dem logischen
            Pegel Null,  bedeutet dies, daß jetzt ein Gerät angesprochen
            werden soll.  Dann sendet das Hostsystem die  Geräteart-Ken-
            nung  und die Gerätenummer sowie die Blocknummer bei Disket-
            tenstationen zusammen mit dem Kommando über den Bus,  um das
            richtige  Gerät  'aufzuwecken'.  Ist das  adressierte  Gerät
            vorhanden  und bereit für die Berabeitung dieses  Kommandos,
            so  wird es sich zurückmelden mit einer Acknowledge-Meldung:
            Es  sendet  ein  'A' und eine  kurze  Statusinformation  mit
            Checksumme. Ist das Gerät beziehungsweise das Kommando dage-
            gen nicht in Ordnung,  wird ein 'N' (=Negative  Acknowledge)
            zurückgesendet.

            Ist das Gerät bereit, beginnt der eigentliche Datentransfer,
            bei  dem  die  zu schreibenden oder zu lesenden  Zeichen  im
            Block gesendet werden,  wobei die KOMMANDO:L-Leitung  wieder
            auf Eins gesetzt wird.

            Sind  alle  Zeichen übertragen,  oder glaubt  zumindest  der
            Sender,  alle  Zeichen übertragen zu haben,  sendet er unter
            Umständen  noch eine Prüfsumme.  Ist das Peripheriegerät zum
            Beispiel  eine Diskettenstation mit dem  Befehl,  einen  be-
            stimmten  Block zu schreiben,  so beginnt es mit der eigent-
            lichen Arbeit (dem Schreiben des Blockes), nachdem es die zu
            schreibenden Daten vom Hostsystem erhalten hat.  Stellt sich
            nun jedoch heraus,  daß der zu schreibende Block defekt ist,
            sendet die Diskettenstation ein 'E' als Error-Meldung an das
            Hostsystem zurück.  Geht die Operation im ganzen gut, sendet
            das Gerät ein 'C' für 'Completed' zurück.

            Das  Hostsystem wartet während der gesamten Zeit der  Verar-
            beitung  auf  eine positive oder  negative  Rückmeldung  des
            Gerätes. Erscheint sie nach einigen (im Normalfall 7) Sekun-
            den  immer  noch nicht,  wird die Operation  vom  Hostsystem
            dadurch abgebrochen, daß ein Timeout eintritt.

            In  diesem Fall wiederholt das Betriebssystem die  Operation
            so  oft,  wie es der Wert in CRETRY vorgibt  (im  Normalfall
            noch 1 mal).

            Es ist dann Aufgabe des Hauptprogramms, sicherzustellen, daß
            eine  eventuelle  Fehlermeldung über die Statusregister  des
            CIO oder SIO richtig interpretiert wird.

            Viel einfacher ist dies alles beim Cassettenrecorder.

            Dabei werden die Daten einfach nur nach einer kurzen  Warte-
            zeit  gesendet und davon ausgegangen,  daß sie schon richtig
            ankommen werden.  Beim Lesen wird allerdings eine eigentlich
            sehr sinnvolle,  leider nur sehr ungenaue Kontrolle  vollzo-
            gen: Die Lesegeschwindigkeit stellt sich automatisch auf die
            empfangene Datenrate ein.  Dies wird dadurch realisiert, daß
            jeder  Block auf der Cassette mit zwei ganz bestimmten  Byte
            beginnen muß.  Sie haben beide den Wert $aa, was binär %1010
            1010  darstellt und sich an sich sehr gut für die Synchroni-
            sation eignet.

            Wer das Cassettenformat einmal verbessern will, kann auspro-
            bieren,  ob die Übertragung sicherer wird, wenn nicht diese,

            sondern zwei andere Byte verwendet werden: %1100 1100. Damit
            müßten  sich mit entsprechender Softwareänderung  wesentlich
            genauere Meßergebnisse herstellen lassen.

            Außerdem  gibt es bei der Cassette noch einem  weiteren  we-
            sentlichen  Unterschied  im Übertragungsverfahren  zu  allen
            anderen  bislang  bekannten Geräten:  Der  Cassettenrecorder
            'versteht' keine reinen Digitalsignale,  sondern er benötigt
            zum korrekten Arbeiten zwei unterschiedliche Töne.  Ein tie-
            ferer  Ton aus Tonkanal 2 stellt die logische Null  dar  und
            ein  höherer  Ton aus Tonkanal 1 stellt demzufolge  die  lo-
            gische  1  dar.  Diese Töne haben gegenüber Logikpegeln  den
            Vorteil,  daß sie direkt auf dem Magnetband gespeichert wer-
            den können.  Bei Pegeln (die sich theoretisch auch speichern
            lassen)  gibt es bei Cassettenrecordern  dieser  Preisklasse
            und  derart geringen Übertragungsraten erhebliche technische
            Schwierigkeiten. Nicht umsonst sind die echten Computerband-
            maschinen  immer noch recht große,  teure  Schränke,  können
            dagegen  jedoch auch in der Übertragungsrate leicht mit  den
            heutigen Atari-Diskettensystemen konkurrieren.


            Der POKEY hat nun bei alledem eine ganze Reihe von Aufgaben:

            Erstens übernimmt er die Erzeugung der Sende beziehungsweise
            Lesetakte.  Ist der POKEY der Erzeuger der  Taktsignale,  so
            gibt er sie über die Leitung CLOCK OUT aus.

            Der  Sendetakt kann durch die Taktrate in Kanal 2,  Kanal  4
            oder  durch  einen externen Takt über die Leitung  CLOCK  IN
            bestimmt werden.

            Für den Lesetakt gilt das gleiche wie für den Sendetakt. Die
            Sendedaten  wechseln  jeweils bei der steigenden Flanke  des
            Taktsignals,  wohingegen  die  Lesedaten bei  der  fallenden
            Flanke  gelesen werden.  Dies soll sicherstellen,  daß  beim
            Lesen ein halber Takt gewartet wird,  um dem Signal Zeit zum
            Einschwingen zu geben.

            Als Zweites hält der POKEY die zu sendenden Daten im  SEROUT
            und  die gerade empfangenen Daten im SERIN Register für  die
            weitere Verarbeitung fest.

            Wird in das SEROUT-Register ein Wert geschrieben, so wird er
            sofort  in das parallel/seriell-Wandlungsregister  geschrie-
            ben,  wenn  dieses  frei ist.  Danach gibt der  POKEY  einen
            Interrupt, in dem er ankündigt, daß das SEROUT-Register leer
            sei,  und  der  POKEY damit bereit sei,  ein  neues  Zeichen
            anzunehmen,  obwohl  der Baustein selbst noch mit dem Senden
            des alten Datums beschäftigt ist.

            Wird  kein  neuer Wert in das  SEROUT-Register  geschrieben,
            erfolgt nach dem Entleeren des parallel/seriell-Wandlungsre-
            gisters ein weiterer Interrupt, der angibt, daß die Übertra-
            gung des letzten Zeichens beendet sei.

            Beim  Lesen  gibt der POKEY einen  Interrupt,  wenn  er  ein
            komplettes Zeichen gelesen hat. Das Zeichen übergibt er dann
            im SERIN-Register und setzt jedoch noch einige Statusbits im
            SKSTAT-Register.  Es  kann zum Beispiel passieren,  daß  der
            Computer  nicht  rechtzeitig  die in SERIN  stehenden  Daten
            liest,  und  der POKEY ein neues Byte empfängt,  nach  SERIN
            schreibt  und somit die alte  Information  überschreibt.  In
            diesem Fall ist das Bit 6 'serieller Überlauf' gesetzt.

            Stimmt  dagegen  etwas mit den Start/Stopbits  des  Zeichens
            nicht,  so  wird das 'Framing-Fehler'-Bit Nummer 7  gesetzt.
            Dieser  Framing- (Rahmen-) Fehler kann auftreten,  wenn  zum
            Beispiel  ein BREAK-Zeichen über die serielle  Schnittstelle
            gesendet  wird.  Dies ist kein eigentliches Zeichen, sondern
            ein  Synchronisations- und  Resetmechanismus,  bei  dem  die
            Sendeleitung für ungefähr eine viertel Sekunde auf LOW (also
            aktiv,  MARK)  gezogen wird.  Dabei wird der POKEY natürlich
            ein Zeichen $00 erkennen,  danach jedoch die beiden Stopbits
            vermissen.

            Will man genau wissen,  welchen Pegel die Sende/Empfangslei-
            tung besitzt, so kann man Bit 4 von SKSTAT testen.

            Dieses  Bit ist eine Hardwarekopie des  Eingangssignals  und
            bietet  neben dieser (noch nicht programmierten) Möglichkeit
            der BREAK-Erkennung diejenige,  die Übertragungsgeschwindig-
            keit festzustellen,  ohne direkt die  seriell/parallel-Wand-
            lung des POKEY initialisieren zu müssen.

            Ist einmal ein Fehler aufgetreten, so wird das entsprechende
            Bit  dadurch  zurückgesetzt,  daß  ein  beliebiger  Wert  in
            SKRESET geschrieben wird.

            Die einzelnen Bits des SKSTAT haben die folgende Bedeutung:

            Bit       Bedeutung
            ------------------------------------------------------------
            7    MSB  Framing-Fehler bei der seriellen Übertragung

            6         Overrun-Fehler  bei der seriellen Übertragung.  Es
                      wurde wenigstens ein Zeichen verloren.

            5         Overrun-Fehler bei der Tastatureingabe.  Es  wurde
                      wenigstens ein Tastendruck verloren.

            4         Dies  ist die direkte Hardwarekopie des  seriellen
                      Eingangs.  Dieses  Bit wird nur für  Spezialanwen-
                      dungen wie Synchronisation abgefragt.

            3         Die SHIFT-Taste auf der Tastatur ist gedrückt.

            2         Die letzte Taste ist immer noch gedrückt

            1         Das  Schieberegister der parallel/seriell-Wandlung
                      arbeitet immer noch,  das heißt, die Datenübertra-
                      gung ist noch nicht abgeschlossen. Dieses Bit sagt
                      zwar  nichts darüber aus,  ob nicht  ein  weiteres
                      Datenbyte  in das SEROUT-Register geschrieben wer-
                      den darf,  aber wenn man keine genauen Informatio-
                      nen über den Status der seriellen Ausgabe hat,  so
                      sollte  man unbedingt das Einswerden  dieses  Bits
                      abwarten.

            0    LSB  Dieses Bit ist nicht benutzt und ist immer auf 1.

            MSB = Most Significant Bit = höchstwertiges Bit
            LSB = Least Significant Bit = geringstwertiges Bit

            Die  Bits  in SKSTAT sind im Ruhezustand immer auf Eins  und
            besitzen die angegebene Aussage, wenn sie auf Null gehen.


            Das  Register  SKCNTL beschreibt neben  den  Übertragungsge-
            schwindigkeiten noch die folgenden Funktionen:

            Bit       Bedeutung
            ------------------------------------------------------------

            7   MSB   Abbrechen  der  seriellen Ausgabe und  Senden  von
                      SPACE  bei  Eins.  Dient  zum  Initialisieren  der
                      Sendeleitungen  und  Senden  von  mehr  als  einem
                      Stopbit.

            6         Die drei Bit dienen der Festlegung
            5         der Übertragungsgeschwindigkeiten
            4         des Senders und Empfängers.

            3         Wird  dieses  Bit auf Eins  gesetzt,  erfolgt  die
                      Ausgabe der Bits im Zweitonverfahren.

            2         Durch das Setzten dieses Bits wird der Schnellgang
                      der  Paddlesteuerung  eingeschaltet.  Die  Messung
                      erfolgt   dann  nicht  wie  üblich  innerhalb  von
                      maximal  20ms,  sondern in der Zeit von  nur  zwei
                      Bildzeilen (ca. 128us).

            1         Dieses   Bit  wird  für  die  Tastaturverarbeitung
                      intern benutzt.

            0    LSB  Sind  Bit  1 und Bit 0 auf Null,  so  erfolgt  ein
                      Software-Reset des POKEY.


            Das SKCNTL hat ein Schattenregister SKCNTL@.

            Die Kombinationsmöglichkeiten der drei Bits 4,  5 und 6  des
            SKCNTL lassen sechs technisch mögliche Zustände zu:

            Bit  7    6    5    Bedeutung
            ------------------------------------------------------------

                 0    0    0    Alle  Takte werden von  außen  bestimmt.
                                Die internen Takte gehen auf Null.

                 0    0    1    Die  Senderate wird durch einen externen
                                Takt bestimmt, die Eingangsrate wird von
                                Kanal 4 (oder dem  16bit-Zähler,  beste-
                                hend aus Kanal 3 und Kanal 4) geliefert.
                                Es erfolgt asynchrones  Lesen der Daten.

                 0    1    0    Sowohl die Sende- als auch die Empfangs-
                                frequenzen  werden  von Kanal 4  festge-
                                legt.

                 0    1    1    Nicht nutzbar,  da der Ausgangstakt sich
                                beim  Lesen eines  Zeichens  verschieben
                                würde  (Synchronisation asynchroner  Da-
                                ten).

                 1    0    0    Die Senderate liegt bei diesem Verfahren
                                durch  die  Programmierung des Kanals  4
                                fest,  die Eingangsrate wird durch einen
                                externen Takt bestimmt.

                 1    0    1    Auch diese Taktform ist nicht nutzbar.

                 1    1    0    Hier bestimmt Kanal 2 die Senderate  und
                                Kanal 4 die Empfangssrate.  Der Takt von
                                Kanal  4 liegt an der externen  Taktaus-
                                gangsleitung an.

                 1    1    1    Die  Ausgangsrate wird wie bei 110 durch
                                Kanal 2 bestimmt, die diesmal asynchrone
                                Leserate  durch Kanal  4.  Der  Taktein-
                                /Ausgang  ist  nicht benutzt  und  liegt
                                offen.

            Die  Verfahren 110 und 111 sind zwar die komplexesten,  aber
            sie  beinhalten eine Einschränkung:  Da  zur  Taktbestimmung
            Kanal 2 benutzt werden muß,  kann hier keine Zweitonübertra-
            gung stattfinden!


            Als letztes Register des POKEY ist das Interruptregister  zu
            besprechen.

            Auch  dieses  Register ist in zwei Teile  aufgespalten:  Ein
            Leseregister IRQSTAT und das Schreibregister IRQEN.

            Gibt  der POKEY einen der unten beschriebenen Interrupts  an
            die CPU,  so prüft deren Interrupthandler über IRQSTAT, wel-
            che  der Interruptquellen es genau war und verzweigt zu  den
            entsprechenden Routinen.

            Sind alle Bits in IRQSTAT auf Eins,  so ist der POKEY  nicht
            die Unterbrechungsquelle.

            Bit       Bedeutung (IRQSTAT)
            ------------------------------------------------------------

            7    MSB  Unterbrechung aufgrund BREAK-Tastendruck

            6         Irgend eine andere Taste ist gedrückt

            5         Der serielle Eingang hat Daten gelesen und sie  in
                      SERIN bereitgestellt

            4         Das letzte in SEROUT eingetragene Zeichen wurde in
                      das   POKEY-interne  parallel/seriell-Wandlungsre-
                      gister übertragen und es kann das nächste  Zeichen
                      nach SEROUT transportiert werden.

            3         Das  parallel/seriell-Wandlungsregister des  POKEY
                      ist  leer  und in das SEROUT-Register  wurde  auch
                      kein  neuer Wert eingetragen.  Die Übertragung ist
                      somit für den POKEY beendet.

            Bit       Bedeutung (IRQSTAT)      (Fortsetzung)
            ------------------------------------------------------------

            2         Unterbrechung durch Nullwerden von Timer 4

            1         Unterbrechung durch Nullwerden von Timer 2

            0    LSB  Unterbrechung durch Nullwerden von Timer 1



            Sämtliche  Interrupts  können einzeln erlaubt oder  disabled
            werden. Eine Unterbrechung durch ein bestimmtes Ereignis ist
            dann erlaubt, wenn das zu dem Interrupt gehörige Bit gesetzt
            (auf  1)  ist.  Ein in IRQSTAT auf Null stehendes  Bit  wird
            wieder  auf 1 gesetzt,  wenn das Pendant in IRQEN  ebenfalls
            zumindest kurzzeitig auf Null gesetzt wird.

            Die  Zuordnung  der  Bits zu den  Interruptquellen  ist  bei
            IRQSTAT und IRQEN gleich:


            Bit       Bedeutung (IRQEN)
            ------------------------------------------------------------

            7    MSB  Unterbrechung aufgrund BREAK-Tastendruck erlaubt

            6         Beliebiger Tasteninterrupt erlaubt

            5         Serielle Eingangsunterbrechung erlaubt

            4         SEROUT-Interrupt enabled

            3         Übertragungsendunterbrechung gestattet

            2         Unterbrechung durch Nullwerden von Timer 4 erlaubt

            1         Unterbrechung durch Nullwerden von Timer 2 erlaubt

            0    LSB  Unterbrechung durch Nullwerden von Timer 1 erlaubt

            Zu  beachten  ist auch hier das Schattenregister für  IRQEN,
            IRQEN@. Wird ein Interrupt neu erlaubt oder verboten, so ist
            dies  sowohl  im Schatten- als auch im  Hardwareregister  zu
            tun.  Ist die Abschaltung nicht so eilig,  kann sie also  im
            nächsten Vertical Blank Interrupt geschehen;  so muß nur das
            Schattenregister korrigiert werden.

            Die Korrektur erfolgt durch 'EinODERn' beziehungsweise 'Her-
            aus-UNDen' des oder der jeweiligen Bits.
            *** ATARI INTERN                                   POKEY ***
Hauptkategorie: 8-Bitter
Erstellt: 28 November 2011
Zugriffe: 2196

Es erstaunt nicht weiter, daß beim Atari 600XL/800XL neben der allgemein guten Konzeption auch die Hardware einen recht aufgeräumten und durchdachten Eindruck macht, wobei klar sein dürfte, daß in dieser Preisklasse nicht jedem alles recht gemacht werden kann.

Einen Großteil der Strukturierung der Baugruppen wird im 600XL/800XL, wie schon in den alten 400/800-er Modellen, von den hochintegrierten Spezialbausteinen ANTIC, POKEY und GTIA, in Verbindung mit den Standardbausteinen CPU und PIA übernommen.

Als Speicher werden in den beiden neuen Geräten ein 16KByte großes ROM für das Betriebssystem und ein 8KByte großes ROM für das eingebaute BASIC verwendet.

Der einzige große Unterschied zwischen 600XL und 800XL ist bekanntlich, daß der 800XL einen auf 64KByte erweiterten RAM-Bereich besitzt. Diese Erweiterung besteht nicht aus weiteren eingesteckten Bausteinen, sondern aus einer etwas anderen Konzeption.

Während der 600XL für seine 16KByte RAM zwei Bausteine verwendet, die jeweils 16.384 4bit-Worte enthalten, ist der 800XL mit 8 wesentlich gebräuchlicheren und damit preiswerteren Bausteinen ausgerüstet, die jeweils 65.536 1bitWorte enthalten.

Schon alleine bei der Stromversorgung bemerkt man, daß die Atari-Computer keine 'Wird schon funktionieren'-Ware sind.

Die vom extern geregelten Netzteil kommende Spannung wird gleich zu Beginn nach dem Hauptschalter in drei Pfade aufgeteilt, die alle gegeneinander durch Induktivitäten und Block-Kondensatoren entkoppelt sind.

Ein Pfad ist hauptsächlich für die hochintegrierten Bausteine und die direkt daran hängenden Pufferbausteine zuständig, der zweite Pfad führt zu den restlichen Logikbausteinen und den RAMs und der dritte Stromversorgungsteil ist ausschließlich für den HF-Modulator vorgesehen. Es ist auch der induktiv am besten entkoppelte Zweig, was Sörungen sowohl der Digitalsignale durch die Hochfrequenz als auch umgekehrt verhindern soll.

Das Herz des Computers ist dessen Taktgenerator. Dieser hier erzeugt eine quarzgenaue 3.546894 MHz-Schwingung, die direkt für die Farbtakterzeugung herangezogen wird.

Die Hälfte dieser Grundfrequenz (1.773477MHz) wird als Arbeitstakt für die CPU benutzt und steuert damit zeitlich alle nicht direkt zur Farbansteuerung gehörenden Funktionen.

Ein von der CPU geliefertes Taktsignal wird benutzt, um über eine sogenannte Spannungs-Verdopplerschaltung eine Referenzspannung für CADJ des GTIA zu erzeugen. Dies ist bei diesen Geräten notwendig, da beim alten 400/800 eine Versorgungsspannung von 12V existierte, die aufgrund der modernen RAMBausteine hier keine Verwendung mehr fände.

Um das System in einen geordneten Zustand bringen zu können, benötigt es einen Reset-Impuls. Dieser wird automatisch beim Einschalten durch ein RC-Glied erzeugt. Der dabei gegen Masse liegende Kondensator kann über eine externe Leitung entladen werden; diese externe Leitung führt zur RESET-Taste der Konsole. Es werden von diesem Signal die Bausteine ANTIC, PIA und CPU zurückgesetzt. Die anderen Bausteine benötigen dieses Signal nicht, sie werden softwaremäßig initialisiert.

Die CPU steuert über ihre Adreß-, Daten- und Kontrollbusleitungen die anderen hochintegrierten Schaltkreise an. Sie läßt sich jedoch auch über die vom ANTIC stammende HALTLeitung anhalten, so daß sie ihre Leitungen auf einen hochohmigen Pegel setzt. Das hat zur Folge, daß die Busleitungen jetzt frei sind, damit zum Beispiel der ANTIC seinen direkten Speicherzugriff (DMA) machen kann.

Sämtliche Speicher (also RAM wie ROM) werden über einen weiteren, weniger hoch integrierten Baustein angesteuert.

Dieses IC ist ein programmierbarer Logikbaustein (PAL) und erfüllt unter anderem die Aufgaben einer Speicher-DekodierLogik, die sonst mit diversen Standard-Dekodern hätte aufgebaut werden müssen. Da sie jedoch nicht nur Dekodier-, sonden auch Speicherblock-Verschiebeaufgaben besitzt, wäre die Bezeichnung 'Memory-Decoder' ihr nicht gerecht geworden.

Da dieses IC in gewissem Rahmen auch eine Verwaltungslogik beinhaltet, ist der Ausdruck Memory-Management-Unit (MMU) wohl der bestgeeignete.

Bevor die einzelnen Ein- und Ausgänge diskutiert werden sollen, noch eine kleine Bemerkung zur Syntax der Leitungsbezeichner: Hinter jedem Signal steht hinter einem Doppelpunkt der Pegel, bei dem das Signal aktiv ist. Ist also zum Beispiel Signal XYZ bei Low-Pegel aktiv, so heißt das Signal XYZ:L, sonst XYZ:H.

Als Eingänge besitzt die MMU zum Beispiel die fünf obersten Adressbit und die vom ANTIC stammende REFresh-Information, die besagt, daß es sich bei dem folgenden Speicherzugriff um einen Refresh-Zyklus handelt (die verwendeten RAM-Bausteine müssen in bestimmten Zeitabständen angesprochen werden, sonst verlieren sie ihre Inhalte. Siehe allgemeine Datenblätter dynamischer RAMs).

Mit diesen Grundinformationen ist die MMU schon in der Lage, den gesamten 64KByte-Speicherbereich in 32 2Kbyte große Blöcke aufzuteilen. Die Blöcke würden prinzipiell gehen von

Block 0   $0000 bis $07ff
Block 1   $0800 bis $0fff
Block 2   $1000 bis $17ff
  .         .         .
  .         .         .
  .         .         .
Block 30  $f000 bis $f7ff
Block 31  $f800 bis $ffff

Die MMU faßt jedoch größere Blockgruppen jeweils zu Einheiten zusammen.

So ist zum Beispiel der Bereich von $0000 bis $4fff (die untersten 16KByte) immer eine Einheit, die sowohl beim 600XL als auch beim 800XL aus RAM besteht. Dann kommt ein Block, der besondere Beachtung verdient, um dann von $5800 bis $7fff wieder einen normalen RAM-Speicherbereich anzusprechen, egal, ob dort physikalische RAM-Bausteine liegen oder nicht.

Der Block Nummer 10 ($5000 bis $57ff) hat, wie gesagt, einen speziellen Status. Der Bereich ist normalerweise für den Einsatz von RAM vorgesehen, es läßt sich jedoch auch in diesem Block abschalten. Dazu führt von PIA-PORT B7 eine Leitung zum MAP-Eingang der MMU. Ist dieser Eingang auf 1, so bleibt wie gewohnt das RAM eingeschaltet. Geht er jedoch auf Null, so wird RAM-Block 10 abgeschaltet und der hinter den I/O-Bausteinen in Block 26 ($d000 bis $d7ff) versteckt liegende ROM-Bereich wird hier hinuntergespiegelt. Es handelt sich bei diesen 2KByte Programm um die SelbsttestRoutine, die eingeschaltet wird, wenn beim Einschalten des Computers die OPTION-Taste gedrückt wird und keine Diskette angeschlossen ist.

Aber noch zwei andere Umschalteleitungen führen von Port B zur MMU: PORT B0 führt direkt zu ROM:H/RAM:L an der MMU und bewirkt dort, daß beim Nullwerden der Leitung das im Bereich $c000 bis $cfff und $d800 bis $ffff liegende BetriebssystemROM ab- und das eventuell dahinter liegende RAM eingeschaltet wird. Bei Benutzung dieser Adressen ist unbedingt darauf zu achten, daß das System abstürzt, wenn kein RAM an dieser Stelle vorhanden ist oder kein vernünftiges System darin steht.

Um sicherzustellen, daß beim Kaltstart immer das ROM aktiviert ist, geht man davon aus, daß solch ein PIA-Pin nach einem RESET-Impuls automatisch als Eingang programmiert wird. Es muß dann nur noch der nun offene Eingang über einen Pull-up-Widerstand hochgezogen werden und schon ist das ROM eingeschaltet.

Die dritte und letzte Verbindung zwischen MMU und PIA wird durch PORT B1 festgelegt, dessen Signal direkt an BasE:L geht. Ist diese Leitung auf Null, so ist der 8 KByte große Bereich $a000 bis $bfff mit dem internen BASIC-ROM belegt, ansonsten ist dieser Bereich frei für anderes.

Dieses 'andere' ist im Normalfall RAM, das an diese Stelle eingeblendet werden kann unter der Voraussetzung, daß es sich um einen 800XL oder 600XL mit 64KByte-Karte handelt.

Die MMU hat jedoch noch zwei weitere Eingangsleitungen, mit denen sie Speicherbereiche umschalten kann; sie dienen der hardwaremäßigen Verarbeitung von Cartridges, also Steckmodulen.

Liegt ein Steckmodul im Speicherbereich von $a000 bis $bfff (zum Beispiel das alte BASIC-Modul, das jetzt eingebaut ist oder der Atari-Assembler oder Spiele wie STARRAIDER u.ä.), so wird dies der MMU über die Leitung EN5:H mitgeteilt, liegt das ROM-Modul (auch) im Bereich $8000 bis $9fff, so wird (auch) die Leitung EN4:H auf High gesetzt. Dadurch 'weiß' die MMU entsprechend, daß sie das dahinterliegende RAM nicht aktivieren darf.

Als letzte Eingangsleitung ist noch die MPD:L Leitung zu nennen. Sie ist eine externe Schaltleitung und bewirkt, daß aus dem Betriebssystembereich der auf die I/O-Gruppen folgende Bereich $d800 bis $dfff (Mathematikroutinen-ROM, deshalb auch Math-Pack-Disable-Leitung) abgeschaltet wird. Dies wird für spätere Hardwareergänzungen verwendet.

Neben diesen ganzen Eingangsleitungen verfügt die MMU selbstverständlich auch über Ausgangsleitungen, die alle als Selektierungsleitungen dienen.

Ist EN4:H oder EN5:H High, so wird beim Ansprechen des entsprechenden Adressbereichs (also $8000 bis $9fff respektive $a000 bis $bfff) die Leitung SEL4:L beziehungsweise SEL5:L auf Null gezogen, um das entsprechende ROM-Modul zu aktivieren.

Das Betriebssystem-ROM wird durch die Leitung OS:L nach folgenden Kriterien selektiert:

MPD:L     ROM:H/RAM:L    Adressbereich       Ausgang OS:L
------------------------------------------------------------
  H           H          $c000 bis $cfff          L
  H           H          $d800 bis $ffff          L
  x           L          generell inaktiv         H
  L           H          $c000 bis $cfff          L
  L           H          $d800 bis $dfff          H
  L           H          $e000 bis $ffff          L

Die Leitung I/O:L bewirkt beim Ansprechen des Bereichs $d000 bis $d7ff, daß der Memory-map-I/O angesprochen wird. Memory- map heißt hier, daß für die Ein-/Ausgabebausteine kein sepa- rater Adreßraum zur Verfügung gestellt wird, sondern ein Teilbereich des Speicherraums dafür abgezweigt wird.

RAM-Speicher kann dort, wo es notwendig ist, über die Lei- tung CasInh:L von der MMU abgeschaltet werden. Diese Aus- gangsleitung bewirkt bei entsprechender Decodierung beim RAM, daß das sogenannte Column Address Strobe, was die letztendliche Selektion einer dynamischen Speicherstelle bewirkt, unterdrückt wird. Dies wird deshalb auf diesem Wege vollzogen, weil sichergestellt werden muß, daß trotz aller Deselektion immer noch der Refresh zu den RAM-Bausteinen durchkommt.

Um von der MMU gleich zu den RAM-Bausteinen weiterzugehen, bedarf es auf elektronischem Weg einiger Timing-Glieder.

Allgemein kann man sagen, daß die Ansteuerung dynamischer Speicher nur wegen der genau einzuhaltenden zeitlichen Folge der von den Speicherbausteinen verlangten Signale extrem kompliziert ist.

Beim 600XL/800XL werden diese Zeitprobleme nun durch spezi- elle Zeitglieder gelöst, die eingehende Signale um wenig- stens 25, höchstes ca. 260 milliardstel Sekunden verzögern.

Auf die gesamte Decoderlogik wirken zwei Selektionssignale: Zum einen das CasInh:L von der MMU, zum anderen ein extern anzulegendes ExtSel:L, das beim Nullwerden das Ansteuern des internen RAMs verhindert.

Neben der Speicherverwaltung gibt es noch zwei andere große Schaltungsbereiche innerhalb des Atari. Der eine wäre die Erzeugung der Farb-, Bild- und Tonsignale, zu denen nichts weiter besonderes zu sagen ist, da sie aus Standard-Hardware bestehen, wie zum Beispiel einem Digital-Analogwandler für die Luminanzwerte des GTIA oder einen 3-stufigen HF-Verstär- ker für das komplette FBAS-Signal. Außerdem ist es von Atari nicht vorgesehen, daß in diesen Schaltungsteil von externer Hardware eingegriffen wird.

Der zweite Bereich ist die Ein-/Ausgabe:

So existieren Multiplexer/Demultiplexer für die Tastaturan- steuerung, Analog- und Digitaleingänge von POKEY und PORT A für Paddle und Joystick sowie zwei Systembusverbinder.

Die Analog- und Digitaleingänge sind über Pull-up- Widerstände und gegen Masse gelegte Kondensatoren entstört.

Im Gegensatz zu den alten 400/800-er Modellen ist zu beachten, daß die Ein-/Ausgänge der PIA nicht mehr durch Serienwiderstände gegen Überlast gesichert sind. Das hat den Nachteil, daß die Ausgänge nun beim Experimentieren leicht zerstört werden können, demgegenüber widerum den Vorteil, keine Probleme mehr zu bekommen, wenn der Ausgang mit normalen Lasten in seinem Grenzbereich betrieben werden soll.

Die Joysickeingänge und Paddle-Leitungen werden über 9- polige D-SUB-Miniaturbuchsen herausgeführt, deren Anschlußbild aus der folgenden Tabelle zu entnehmen ist:

Pin Nummer     Anschluß geht intern zu      Wird benutzt für
                   Joy1 / Joy2
------------------------------------------------------------
     1         PORT A0  /  A4               Vorwärts  (Joy)
     2         PORT A1  /  A5               Rückwärts (Joy)
     3         PORT A2  /  A6               N. links  (JOY), linker Auslöser beim Paddle
     4         PORT A3  /  A7               N. rechts (Joy), rechter Auslöser beim Paddle
     5         POKEY P1 / P3                linker Potentiometerwert Paddle
     6         GTIA  T0 / T1                Trigger (Feuerknopf) vom Joystick oder Lightpeneingang
     7         Ub   +5V / +5V               Betriebsspannung normal belastbar
     8              GND / GND               Signalmasse
     9         POKEY P0 / P2                recht. Potentiometerwert Paddle

 

An dem hinten am Gerät installierten CPU-Bus liegen wesentlich mehr Signale an. Neben allen 16 Adress- und 8 Datenbits liegt an mehreren Stellen des Verbinders eine Masseverbindung und für die +5V-Versorgung sind ebenfalls zwei Leitungen vorgesehen.

Die Leitung ExtSel:L sperrt im aktiven Zustand das intern vorhandene RAM und wird hauptsächlich bei Anstecken einer RAM-Karte an den 600XL benötigt.

RESET:L ist das nichtsynchronisierte Ausgangssignal, mit dem die internen Bausteine zurückgesetzt werden.

IRQ:L ist ein Eingang, der am CPU-Pin IRQ anliegt. Es ist darauf zu achten, daß alle anderen unterbrechenden Geräte wie der POKEY und die PIA ebenfalls ihre Open-Drain-Ausgänge auf dieser Leitung zu liegen haben, und daß dieser Eingang durch einen 3kOhm-Widerstand intern bereits 'gepullt' wird.

LR:H/W:L ist ein gelatchtes, gepuffertes Signal, das dem CPU-R/W entspricht. Das Latchen geschieht zeitabhängig von o2 zum gleichen Zeitpunkt, an dem die Verknüpfung aus CasInh:L und ExtSel:L gelatcht wird und kann direkt zur Ansteuerung von Speicherbausteinen verwendet werden.

RDY:L ist verbunden mit dem gleichnamigen CPU-Pin, aber es ist zu beachten, daß der ANTIC über seine ebenfalls gleichnamige Open-Drain-Leitung immer Zugriff auf die CPU haben muß. Bei Verwendung dieser Leitung gilt also die gleiche Vorsicht wie bei der IRQ:L-Leitung.

CasInh:L ist, wie schon bei der MMU besprochen, Ausgangssignal zum Disablen externer dynamischer RAMs. Es kann auch für statische Baugruppen verwendet werden, erfordert dann jedoch leichte vorherige Umwandlungsarbeit.

CAS:L ist das reine Timing-Signal, wann der Column-Address-Strobe beim dynamischen Speicher zu erfolgen hat, wenn nicht CasInh:L oder ExtSel:L aktiv sind.

Für RAS:L gilt ähnliches wie für CAS:L, nur daß dieses Signal auch beim Refresh-Zyklus generiert wird und nicht von CasInh:L abhängig ist.

Ref:L ist die Hardwarekopie des entsprechenden Ausgangs beim ANTIC und findet nur dann Verwendung, wenn aus den RAS/CAS- Signalen Informationen über den momentanen Busstatus gezogen werden sollen. Dies wäre zum Beispiel notwendig, wenn über RAS:L und CAS:L Baugruppen angesprochen werden sollen, die keinen Refresh benötigen. In wieweit dies sinnvoll ist und nicht einfach benötigte Signale aus dem restlichen CPU- Timing entnommen werden, bleibt dem jeweiligen Entwickler überlassen; wichtig werden diese Signale, wenn von außen auf das System zugegriffen werden soll.

MPD:L ist der über Pull-Up inaktiv gehaltene MMU-Eingang zum Disablen des Mathematikroutinen-ROMs im Bereich $d800 bis $dfff und wird bislang noch von keiner (im Handel bekannten) Hardware verwendet.

Das letzte auf dem Bus verwendbare Signal ist Audio In, über das Signale in den vom Rechner generierten Sound eingemischt werden können. Der Eingang ist über einen 4u7F-Kondensator gleichspannungsentkoppelt, kann jedoch auch unter bestimmten Voraussetzungen wie nochmaliger Verstärkung etc. als Ausgang verwendet werden. Dabei wäre dann mit einem Ausgangsspannungspegel von maximal 200mV zu rechnen.

Als Gesamtübersicht über diesen Verbinder läßt sich sagen, daß er alle Erweiterungsmöglichkeiten nach außen hin offen läßt, wobei er es unmöglich macht, etwas an der internen Hardwarestruktur zu ändern, was nicht von Atari direkt geplant war. Als weiterer wichtiger Punkt dürfte herausgekommen sein, daß es sich bei dieser Schnittstelle nicht etwa um eine Centronics-kompatible handelt, wie es leider immer wieder von unwissenden Verkäufern erzählt wird.

Allgemein sind die Signale, die nach außen geführt werden, nicht gepuffert. Es ist also davon auszugehen, daß die Daten- und Adressleitungen jeweils eine LS-TTL-Last vertragen, die anderen Signale wie RESET:L, CAS:L und andere vertragen nicht mehr als 5 weitere LS-TTL-Lasten. Es ist gerade bei CAS:L und RAS:L zu beachten, daß dynamische Speicher extrem hohe Eingangskapazitäten besitzen, die das Fan-out der Signalquellen erheblich schwächen.

ANSCHLUSSPLÄNE UND SPEICHERAUFTEILUNG

Speicheraufteilung

Speicherplan des Atari

Anschlussplan der 6502C CPU

6502C CPU

Anschlussbelegung des ANTIC

Anschlussbelegung des ANTIC

Anschlussbelegung des GTIA

Anschlussbelegung des GTIA

Anschlussbelegung des POKEY

Anschlussbelegung des POKEY

Anschlussbelegung der PIA

Anschlussbelegung der PIA

Anschlussplan der Memory Management Unit (MMU)

Anschlussplan der MMU

Anschlussplan der seriellen Schnittstelle

Anschlussplan der seriellen Schnittstelle

Anschlussplan des Joystick-Ports

Anschlussplan des Joystick-Ports

Anschlussplan des Cartridge-Slots

Anschlussplan des Cartridge-Slots

Hauptkategorie: 8-Bitter
Erstellt: 27 November 2011
Zugriffe: 1942

"Computer können uns nicht einen einzigen Hintergedanken abnehmen" sagte einmal eine bedeutende amerikanische Firma in ihrer Werbung - und hat damit völlig Recht. Aber was können sie dann?

Die meisten Besitzer von Mikrocoputern wenden ihre Geräte auf die unterschiedlichsten Arten und Weisen an. Der größte Teil spielt ganz einfach damit oder, genauer, mit der darauf laufenden Software. Ein weiterer Teil benutzt den ATARI zum Programmieren oder zur Text- und Datenverarbeitung und ein, wenn auch nur kleiner, Teil benutzt ihn zur Realisierung von Steuerungsaufgaben.

Computer können lediglich das, was man ihnen beigebracht hat. Jede Regel für eine Entscheidung, bzw. jede Regel nach der andere Regeln aufgestellt werden sollen, den gesamten Arbeitsablauf, sowie das gesamte Wissen, das zur Lösung notwendig ist, muß man dem Computer in einer für ihn verständlichen Sprache mitteilen. Wenn man sich überlegt, was dies bedeutet, so kommt man zu dem Schluß, daß Computer an sich "ziemlich doof" sind.

Wissenschaftler, die sich mit der INTELLIGENZ verschiedener Lebewesen und auch des Mikrocomputers befaßt haben, kamen zu dem Schluß, daß die Intelligenz eines Mikrocomputers nur knapp über der eines Regenwurms angeordnet ist. Die hohe Leistungsfähigkeit der Mikrocomputer stammt allein von ihrer hohen Verarbeitungsgeschwindigkeit. Es kursieren über Computer allgemein verschiedene Sprüche, die den Sachverhalt auf humorvolle Weise wiedergeben. Ein bekannter Satz lautet zum Beispiel: "Computer sind doof, dafür aber wenigstens fleißig". Oft redet man auch davon, daß der "Computer ein Produkt menschlicher Faulheit ist".

Mikroprozessor. Personal Computer. Hobbycomputer. Mikrocomputer. Arbeitsspeicher. ROM. Peripherie. Minirechner. Einplatinencomputer. Entwicklungssystem. OEM - Computer - alles das sind Ausdrücke, mit denen man in der heutigen Zeit im Zusammenhang mit Computern zu tun hat - mit denen man zum

Beispiel beim Kauf eines Systems "vollgepumpt" wird von Verkäufern, die manchmal (oder meist ?) selber nicht wissen, was sie erzählen. Um mehr von Computern zu verstehen, muß man zuerst die Struktur, das Grundprinzip von Computern, kennen.

Ein Computer besteht aus Speicher, Zentraleinheit und Ein/Ausgabe - Systemen, und kennt nur zwei Zustände. Das war schon immer so, und wird es bleiben - könnte man meinen! Aber nein, was die meisten nicht wissen: Es exisieren zwei Arten von Rechnern, der ANALOG- und der DIGITAL-Rechner. Der Analogrechner sei hier aber nur der Vollständigkeit halber erwähnt.

Uns wird hier nur der Digitalrechner beschäftigen. Die Sache mit den zwei Zuständen stimmt allerdings: Er ist entweder defekt oder in Ordnung. Ansonsten weiß zwar der Zuhörer, was mit den zwei Zuständen gemeint ist, aber richtig ist diese Aussage dennoch nicht. Ein "Von Neumann - Rechner", wie wir ihn in Form des ATARI zu Hause zu stehen haben, kennt zwar effektiv nur endlich viele Zustände, aber es sind doch immerhin noch eine ganze Menge! Doch dazu kommen wir später. Erst einmal wollen wir die Sache mit den zwei Zuständen endgültig klarstellen:

Das Zahlensystem, mit dem Digitalrechner arbeiten, kennt nur zwei Zustände.

Was heißt das? Unser Zahlensystem, nach dem wir dem Bäcker die Brötchen bezahlen, kennt zehn Zustände. Sie werden durch die zehn Ziffernsymbole 0,1,2,3,4,5,6,7,8,9 gekennzeichnet. Daraus lassen sich dann Kombinationen dieser Ziffern erstellen, die Zahlen genannt werden. Als Beispiel die Zahl 1234, eintausendzweihundertvierunddreißig (eigentlich ..dreißigundvier, aber das sind Eigenheiten der deutschen Sprache, genauso wie elf, zwölf usw.). Unter dieser Zahl kann man sich ab der 2. Schulklasse etwas vorstellen, man kann sogar damit arbeiten (rechnen):

"1234 und 17 macht ( 4 und 7 macht 1, 1 im Sinn, 3 und 1 und 1 im Sinn macht 5, und 2 und 1 bleiben) 1251."

So rechnet man. Später, nach einiger Übung, geht das schneller, das Prinzip bleibt aber. Nur: WARUM rechnet man so? Oder anders gefragt: Rechnet man immer so? Die Antwort auf diese Frage lautet: Nein.

Zum Beispiel: Wieviele Stunden liegen zwischen 18:00 und 03:00 Uhr?

Normalerweise würde man 3,00 - 18,00 rechnen und somit -15:00 herausbekommen. Es sind aber 9:00 Stunden - WARUM ?

Wer mitgelesen hat, hat das Problem erkannt: Die Zeit läuft nicht nach dem Dezimalsystem mit 10 Ziffern, sondern nach dem Duodezimalsystem mit (eigentlich) 12 Ziffern. Denn eigentlich müßte man folgende Rechnung aufstellen:
Der Tag endet bei 24:00. 24:00 + 3:00 = 27:00 , 27:00 - 18:00 = 09:00.

Wir sehen also, die Sache mit den Zahlensystemen ist reichlich konfus; speziell bei der Zeit, weil diese auf Grund der zehn benutzten Ziffern bei einem 12er-System die Vollendung des Zahlenchaos bedeutet. Aber wir wollen nicht vergessen, daß die Engländer lange im 12er-System gerechnet haben, und gestorben sind sie daran nicht.

Weshalb sollte nun ein Computer mehr als zwei Ziffern kennen?

Sollten wir Mathematiker unter uns haben, so sei gesagt, daß sich genau berechnen läßt, mit welcher Anzahl von Ziffern die Effektivität des Zahlensystems am höchsten ist. Schlaue Leute haben sich die Mühe des Nachrechnens gemacht und kamen auf das Ergebnis, daß bei Verwendung von ca. 2,7 Ziffern die Effektivität am höchsten sei. Bloß- was soll die 0,7. Ziffer

darstellen? Normalerweise würde man den (mathematisch richtigen) Unsinn auf 3,0 erhöhen; man hätte dann die Ziffern 0,1 und 2 zur Verfügung, was sich heute technisch in Computern realisieren ließe (und auch teilweise in komplexen Zählersystemen angewandt wird), aber man darf nicht vergessen, daß es den Computer schon eine Weile gibt; damals war noch nicht einmal an den Transistor oder den konsequenten Einsatz von Röhren zu denken (mechanische Rechenwerke seien hier nicht betrachtet!).

Im Jahre 1939 bauten die Bell- Ingenieure ihren ersten Relais-Computer Model I.

Relais - wer kennt das nicht, das Gebilde aus einer Spule und einem Anker mit Schaltkontakten? Fließt Strom durch die Spule, bewegt sich der Anker und öffnet bzw. schließt die Kontakte. H A L T !!! Da war es schon:"... öffnet oder schließt die Kontakte" - das sind genau zwei klar definierte Zustände, die sich abfragen und generieren lassen! Also, wenn drei Zustände (das Optimum) schlecht zu erreichen sind, dann nehmen wir halt zwei. Dieser Gedanke hat uns prinzipiell den ATARI beschert!

Die zwei Zustände können auf verschiedene Arten auftreten: Zum Beispiel Relais angezogen und Relais abgefallen, Licht an und Licht aus, Taste gedrückt und Taste nicht gedrückt, Zusatzgerät vorhanden und Zusatzgerät nicht vorhanden, Spannung auf "HIGH-Pegel" und Spannung auf "LOW-Pegel", es fließt Strom, und es fließt kein Strom. Diese Gegenüberstellung läßt sich fast beliebig fortsetzen.

Von Bits und Bytes

Wir haben die Entstehungsgeschichte des Systems mit den zwei Ziffern kennengelernt; jetzt wollen wir damit rechnen.

Im Englischen heißt die Ziffer DIGIT. Hat man nur zwei Ziffern zur Verfügung, nennt sie der Engländer BINARY DIGIT, also binäre (zweiwertige) Ziffer, abgekürzt

B I T

Wir haben also jede Menge Bits - aber was damit anfangen? Was machen wir mit unseren zehn Ziffern? Wir 'hängen' sie nebeneinander und geben ihnen die ihnen zugehörigen Wertigkeiten:

1234     ist eine Zahl, hier sei sie aus dem Zehnersystem.
Das heißt, es sind       1  *  1000
                      +  2  *   100
                      +  3  *    10
                      +  4  *     1
Nun wollen wir es noch einmal anders formulieren:
Jetzt sind es            1  *   10
                      +  2  *   10
                      +  3  *   10
                      +  4  *   10

Das ist logisch, denn 10 ** 3 (andere Formulierung für 10 ) = 1000, 10**2 = 100, 10**1 = 10 und schließlich: 10**0 = 1 . Daß 10**0 = 1 ist, sollten wir uns besonders merken, denn es gilt allgemein:

Für JEDES "a" aus der Menge der reellen Zahlen gilt:

a ** 0 = 1

Diesen Satz benötigen wir später wieder, also: Merken!

So, und nun setzen wir einfach mehrere BInary DigiTs aneinander:

1101 0111

(der Lesbarkeit halber in zwei Vierergruppen aufgeteilt). Das ergibt dann, ebenfalls von links nach rechts aufgeschlüsselt:

               1  *  2**7 = 1 * 128 = 128
            +  1  *  2**6 = 1 *  64 =  64
            +  0  *  2**5 = 0 *  32 =   0
            +  1  *  2**4 = 1 *  16 =  16
            +  0  *  2**3 = 0 *   8 =   0
            +  1  *  2**2 = 1 *   4 =   4
            +  1  *  2**1 = 1 *   2 =   2
            +  1  *  2**0 = 1 *   1 =   1
            __________________________
                                      215

Jetzt haben wir unsere Zahlen, deren Ziffern (Bits) nur zwei Zustände kennen. Die Aufteilung der Zahlen in Gruppen zu mehreren Ziffern (hier Vierergruppen) ergibt sich auch bei unserem Dezimalsystem, denn wie schreibt der Kaufmann die Million? 1.000.000,

Hier haben wir die Aufteilung der Zahl in Dreiergruppen, hervorgerufen durch den Dezimalpunkt (im Deutschen - im Englischen sind Dezimalpunkt und - Komma in der Bedeutung genau vertauscht, also nicht durch englische Literatur irritieren lassen!). Die Aufteilung der Binärzahlen kann auch in Dreiergruppen oder sonstwie erfolgen, durchgesetzt bei den informatorischen Wissenschaften haben sich jedoch nur Dreier- und Vierergruppen.

Die Zahl 1101 0111 liest sich natürlich etwas langatmig: "einseinsnulleinsnulleinseinseins" - das wäre sehr umständlich. Was ist also zu tun? Man überläßt dem Computer die Fieselarbeit mit den Nullen und Einsen, als gebildeter Informatiker jedoch unterhält man sich 'Hex', d.h., Hexadezimal (Genaugenommen müßte man von "Sedezimal" reden, doch dieser Begriff ist nur selten anzutreffen.). Was bedeutet das?

Wir hatten unsere Zahl in zwei Vier-Bit-Gruppen eingeteilt, und wie man leicht ausprobieren kann, hat man bei vier Stellen und jeweils zwei Möglichkeiten pro Stelle insgesamt SECHZEHN Kombinationsmöglichkeiten. Diese wären

0000, 0001, 0010, 0011, 0100, 0101, 0110, 0111, 1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111 .

Jetzt wollen wir diesen sechzehn Kombinationsmöglichkeiten einmal Namen geben:

 0000     soll heißen :  0  und bedeutet dezimal  0
 0001                    1                        1
 0010                    2                        2
 0011                    3                        3
 0100                    4                        4
 0101                    5                        5
 0110                    6                        6
 0111                    7                        7
 1000                    8                        8
 1001                    9                        9
 1010                    A                       10
 1011                    B                       11
 1100                    C                       12
 1101                    D                       13
 1110                    E                       14
 1111                    F                       15

Auf unsere Zahl bezogen können wir nun sagen:

1101 0111 heißt in Hexadezimalform : D 7 .

Wir haben es hier also mit der Zahl D7 zu tun. Aber wie erhält man nun aus D7 eine Dezimalzahl?

Ganz einfach, wir wandeln die Zahl D7 wieder in 1101 0111 um und berechnen nach der oben gezeigten Methode die Dezimalzahl 215. Gibt es auch noch einen anderen, vielleicht einfacheren Weg, diese, und vor allem größere Hex-Zahlen umzuwandeln? Sicherlich gibt es den, und der aufmerksame Leser kennt oder ahnt ihn zumindest schon: Wir haben es hier ganz offensichtlich mit zwei Ziffern aus dem Hexadezimalsystem zu tun, können also sagen:

      D7  =    D  *  16**1  =  13 * 16**1 = 13 * 16 =   208
             + 7  *  16**0  =   7 * 16**0 =  7 *  1 =     7
            ------------------------------------------------
                                                        215

Wir kennen nun die Umrechnungsart von binär oder hexadezimal nach dezimal; und wie verhält es sich umgekehrt? Hier gibt es mehrere Methoden. Als erstes könnte man die Dezimalzahl in eine binäre und die dann, durch einfache Aufteilung in Vierergruppen von rechts nach links, in eine Hexzahl wandeln. Da dazu jedoch eine ganze Reihe von Divisionen notwendig ist, empfiehlt sich diese Art nur dann, wenn man nur seinen Kopf zum Rechnen hat.

Wir nehmen uns wieder die dezimale 215:

215 / 2 = 107      Rest 1
107 / 2 =  53      Rest 1
 53 / 2 =  26      Rest 1
 26 / 2 =  13      Rest 0
 13 / 2 =   6      Rest 1
  6 / 2 =   3      Rest 0
  3 / 2 =   1      Rest 1
  1 / 2 =   0      Rest 1

Unsere Binärzahl besteht aus den Restziffern, von UNTEN NACH OBEN gelesen!

Aber wie gesagt, die Methode läßt sich auch am Montagmorgen im Kopf ausführen, die nun folgende geht wesentlich schneller, erfordert aber Rechenarbeit, speziell bei großen Zahlen:

            215,00 / 16 = 13,44 (Dez)  = D (Hex)
              0,44 * 16 =  7,04   "    = 7   "

Also: durch die größte Potenz von 16, die kleiner ist als die zu wandelnde Zahl teilen, und dann den jeweiligen Rest so oft mit 16 muliplizieren, wie die Potenz betrug, durch die wir zu Beginn geteilt hatten.

Aber das sollten wir besser noch einmal an einem etwas größeren Beispiel ausprobieren:

Die Zahl 60413 (Dez) wollen wir wandeln. Die nächstkleinere 16er-Potenz ist 16**3 = 4096 (denn 16**4 = 65536, also viel größer!).

0).  60413  / 4096 = 14,7493  ==: 14 (Dez)   = E (Hex)
1).  0,7493 *   16 = 11,9888  ==: 11   "     = B   "
2).  0,9888 *   16 = 15,8208  ==: 15   "     = F   "
3).  0,8208 *   16 = 13,1328  ==: 13   "     = D   "

Hier hören wir auf, denn unsere Sechzehnerpotenz betrug 3 (zur Erinnerung, wir hatten als Erstes durch 16**3 = 4096 geteilt!), und wir haben danach 3 Mal mit 16 multipliziert.

Unsere Hexadezimalzahl steht nun deutlich da: EBFD. Zur Überprüfung machen wir die Probe:

Es gilt, die Hexzahl EBFD in eine Dezimalzahl zu wandeln:

EBFD  =     E * 16**3 = 14 * 16**3 = 14 * 4096 =   57344
          + B * 16**2 = 11 * 16**2 = 11 *  256 =    2816
          + F * 16**1 = 15 * 16**1 = 15 *   16 =     240
          + D * 16**0 = 13 * 16**0 = 16 *    1 =      13
         -----------------------------------------------

Die Probe zeigt also das gleiche Ergebnis.

Wenn man das mehrfach übt, und sich einige Übungsaufgaben stellt, beherrscht man diese Umrechnungsarten recht schnell. Wer dazu allerdings keine Lust verspürt, kann sich ein geeignetes Programm schreiben...

Denn diese Umrechnungen von Dez nach Hex und umgekehrt werden uns auf dem Atari noch eine ganze Weile nachlaufen, denn das Atari-BASIC versteht nur Dezimalzahlen!!! Wer allerdings wissen will warum, der möge die Götter fragen, denn eines wissen wir inzwischen genau: Der Computer mag wählen zwischen binärer oder hexadezimaler Darstellung, Dezimal rechnet er auf gar keinen Fall!

Wir bezeichnen in unserem Buch übrigens die Hexadezimalzahlen mit einem "$". Die "d7" hieße also "$d7".

Die Bits haben wir nun kennengelernt, jetzt beschäftigen wir uns mit den

Bytes

Dieser Ausdruck, ist schnell erklärt. Wir haben vorhin 8 Bits, aufgeteilt in zwei Vierergruppen, genannt NIBBLEs (sprich: Nibbel), betrachtet. Warum denn gerade acht, warum nicht sieben oder neun? Nun, da wir uns geeinigt hatten, Vierergruppen zu verwenden, ist es schon nicht unpraktisch, diese Vierergruppen jeweils "voll" zu machen. Außerdem "holt" sich der ATARI immer 8 Bits auf einmal zum Arbeiten; warum sollten wir nun auch wieder anders "denken" als unser großer Bruder? In der Computerbranche hat sich für diese 8 gleichzeitigen (parallelen) Bits der Name BYTE eingebürgert. Er bedeutet BINARY TERZ also binäre Dreiergruppe. Diese Bezeichnung wurde von einer großen Firma in den USA geprägt. Sie erklärte ihren Programmierern nicht das Hexadezimalsondern das Oktalsystem, bei dem immer drei Bits zusammengefaßt werden.

Wir merken uns: Ursprünglich bedeutete "BYTE" im Oktalsystem die Zusammenfassung von drei Bits.

Jetzt hingegen gilt: 1 Byte besteht aus 8 Bits (Hexadezimalsystem).

Die HARDWARE eines Mikrocomputers

Im vorigen Kapitel hatten wir gesagt, woraus ein Computer besteht:

  • Speicher
  • Zentraleinheit
  • Ein-/Ausgabeleitungen

Diese drei Komponenten findet man aber nicht in nur drei Bausteinen, es befinden sich erheblich mehr ICs (Integrated Circuit, integrierter Schaltkreis) im Atari. Der schaltungstechnische Aufwand ist nur damit zu begründen, daß es noch keinen Baustein gibt, der den ganzen, im ATARI zur Verfügung stehenden Speicherplatz z.B. ausfüllt; bei der Zentraleinheit und den I/O (INPUT/OUTPUT) - Leitungen verhält es sich genauso. Man muß nämlich bedenken, daß alle im ATARI eingebauten Bausteine auch allgemein anwendbar sind, und somit zur Ein- und Ausgabe mehrere "Interfacebausteine" gehören.

Der Speicher

Wir wollen hier prinzipiell zwei Arten des Speichers unterscheiden :

1) den Schreib / Lesespeicher

und

2) den Nur - Lesepeicher. (ROM bzw. Read Only Memory)

Den Schreib / Lesespeicher nennt man auch Neudeutsch "RAM" (sprich: Ramm), was "Random Access Memory" bedeutet, oder "Speicher mit wahlfreiem Zugriff". Mit Zugriff wird hier nicht der Zugriff auf eine bestimmte Adresse gemeint; der ist für RAM wie ROM gleich. Es soll hier vielmehr eine Unterscheidung getroffen werden, ob es sich um einen Schreib- oder Lesezugriff handelt. Diese Speicherart kann man sich vorstellen als eine Kommode mit mehreren Schubladen.

Nehmen wir an, unsere Kommode hätte sechs Schubladen mit zwei Reihen zu je drei Stück. Dann können wir die sechs Schubladen auf zwei Arten bezeichnen:

1)       ---------------------------------------------------
          I               I               I               I
          I       0       I       1       I       2       I
          I               I               I               I
          -------------------------------------------------
          I               I               I               I
          I       3       I       4       I       5       I
          I               I               I               I
         ---------------------------------------------------


Damit hätten wir die Schubladen 0 ... 5, die wir nun eindeutig unterscheiden können. Es gibt auch noch eine andere Methode:

2)       ---------------------------------------------------
          I               I               I               I
       0  I       0       I      1        I       2       I
          I               I               I               I
          -------------------------------------------------
          I               I               I               I
       1  I       0       I      1        I       2       I
          I               I               I               I
         ---------------------------------------------------
*** ATARI INTERN         Das Prinzip eines Mikrocomuters ***


Hiermit erhalten wir die Namen    (0,0), (0,1), (0,2),
                                  (1,0), (1,1), (1,2) .

Auch hiermit lassen sich alle Schubladen eindeutig bezeichnen.

 

Wir wollen uns für die Zukunft diese beiden Arten der Numerierung merken: Die erste nennt man LINEARE ANORDNUNG, die zweite versehen wir mit dem Begriff MATRIXFÖRMIGE ANORDNUNG.

Hardwaremäßig gesehen, arbeiten Speicher ab einer bestimmten Größe matrixförmig; aber softwaremäßig werden die Speicherstellen linear angesprochen (verwirrender Weise auch wenn man Matritzen programmiert - aber damit kämen wir vom Thema ab).

Wir haben also in unserem Falle sechs Schubladen, die wir unterscheiden können. Nun wollen wir sie aber auch benutzen. Wir öffnen Schublade Null und sehen nach, was darin ist :

NICHTS

Warum? Wir haben ja noch nichts hineingetan. Aber ist Nichts denn wirklich NICHTS ? Die Frage ist ein bißchen philosophisch, deshalb wollen wir einmal ein wenig vom Thema abschweifen, um drei äußerst wesentliche informationstechnische Begriffe zu klären, mit deren Hilfe sich die oben gestellte Frage (für unsere Zwecke!!!) leicht lösen läßt.

Der Informatiker unterscheidet drei Merkmale einer Information:

  1. Die syntaktischen,
  2. die semantischen und
  3. die pragmatischen Aspekte einer gegebenen Information.

Was bedeuten diese Fremdworte?

Unter "SYNTAX" versteht man den prinzipiellen Aufbau einer Information.

Nehmen wir ein beliebiges Wort: zum Beispiel "MANN". Würden wir zwar MANN meinen, aber MAN schreiben, verstünde uns keiner. Also halten wir uns an die Regeln (Syntaxregeln!) der deutschen Sprache und schreiben "MANN".

Als anderes Beispiel sei hier die Verkehrsampel gewählt: Die Syntax der sog. "Wechsellichtanlage" lautet:

rot
rot + gelb
grün
gelb

Würden Rot und Grün zusammen erscheinen, wüßte niemand etwas mit dieser Information anzufangen - sie wäre SYNTAKTISCH FALSCH.

Unter SEMANTIK versteht man den Informationsgehalt, den sich der Entsender der Information gedacht hat oder, anders formuliert, das, was normalerweise bei Eintreffen der Information daraufhin passieren sollte.

Der semantische Aspekt der roten Ampel wäre: "HALT".

Die dritte Betrachtung einer Information, die PRAGMATIK bezeichnet das, was den Nutzer der Information zu deren Nutzung treibt, oder wie er eine Information für sich speziell verwendet. Sieht man z.B. eine gelbe Ampel, denkt man sich "Stoff, dann schaff' ich sie noch", oder "hat sowieso keinen Zweck mehr, Gas weg".

Mit diesen Definitionen läßt sich die an sich philosophisch nicht zu lösende Frage informationstechnisch relativ leicht beantworten. "Wir sehen in der soeben geöffneten Schublade nichts"; soweit waren wir schon.

NICHTS, WAS WIR SINNVOLL VERWERTEN KÖNNEN

Nach unseren drei Punkten aufgeschlüsselt:

  1. Die Syntax der Information stimmt; irgendetwas ist sicherlich in der Schublade, und wenn es ein Vakuum (luftleerer Raum) ist.
  2. Die Semantik ist auch klar, wir haben noch nichts hineingepackt, also können wir auch nichts herausholen.
  3. Pragmatisch betrachtet ist die Schublade für uns leer (obwohl etwas, nämlich NICHTS darin ist!), wir können also irgendetwas hineintun. Tun wir es, und nehmen wir oder ein anderer nicht wieder etwas heraus, werden wir es immer wieder nach Öffnen der Schublade finden.

Jetzt formulieren wir den eben beschriebenen Vorgang technisch :

Wir nennen die Nummern, mit denen wir die Schubladen bezeichnet haben, Adressen

In jede Schublade passen GENAU acht Bits hinein (also weder mehr noch weniger, eben: genau acht!).

Jetzt öffnen wir eine Schublade, nehmen wir als Beispiel die Nummer 3. Diesen Vorgang des Öffnens der Schubladen wollen wir in Zukunft adressieren nennen,

das Hineinsehen soll Lesen , das Hineinlegen soll Schreiben, die Schublade selber soll Speicherplatz heißen.

Das sind zwar eine ganze Menge Namen auf einmal, aber mit der Zeit werden wir lernen, richtig damit umzugehen.

Also, wir ADRESSIEREN SPEICHERPLATZ 3, und LESEN ihn aus. Was steht darin? Nichts ist die Antwort, denn wir haben ja noch nichts hineingeschrieben.

Wie wir im vorigen Kapitel erfahren haben, können nur Nullen und Einsen in dem Speicherplatz stehen, denn wir haben ja nur zwei Ziffern, und außerdem hatten wir eben gesagt, daß nichts nicht unbedingt nichts sein muß. Es könnte also sein, daß z.B. die Zahl 0110 1100 (6c Hex, $6c) darin enthalten ist - wieso auch nicht?!?

Technisch läßt sich das so erklären, daß durch interne Unebenheiten der in den Bauteilen enthaltenen Leiterbahnen beliebige Bitkombinationen nach dem Einschalten enthalten sind. Und diese Bitkombinationen können also alle 256 Möglichkeiten der Kombination von acht Nullen und Einsen sein, nämlich 0000 0000 bis 1111 1111 (es gibt zwei Möglichkeiten, entweder man glaubt uns, daß es 256 Kombinationen sind, oder man berechnet die Anzahl - letzteres wäre eine gute Übung zum vorherigen Kapitel!).

Nehmen wir also an, wir hätten einen Computer vor uns, bei dem nach dem Einschalten in Speicherplatz 3 die Hexzahl $6C steht.

Diese können wir natürlich jederzeit wieder lesen, denn sie steht ja drin. Nur, der pragmatische Teil dieser Information ist für uns als Benutzer unwesentlich größer als Null, denn es ist eine reine ZUFALLSINFORMATION !!!

Also wollen wir etwas Vernünftiges hineinschreiben. Dazu wählen wir unsere Hexzahl aus dem vorigen Kapitel, die "$d7". Wir haben unseren Speicherplatz Nummer 3 immer noch adressiert, und SCHREIBEN nun die Zahl $d7 hinein.

Was geschieht?

Die Zufallszahl $6c räumt den Speicherplatz 3 und es wird die $d7 GESPEICHERT. Wenn wir nun später wieder auf Speicherplatz Nummer 3 zugreifen, werden wir immer wieder die Zahl $d7 lesen, bis wir eine neue Zahl in die Speicherstelle schreiben oder den Rechner ausschalten.

Im ersten Fall wird selbstverständlich die $d7 von der neuen Zahl ÜBERSCHRIEBEN im zweiten Fall erhalten wir wieder unsere Zufallsinformation.

Gibt es denn keine Möglichkeit, eine einmal eingespeicherte Information auch nach dem Abschalten zu erhalten oder vor dem Überschreiben zu sichern?

Nur durch schaltungstechnische Eingriffe in den Computer; das RAM ist eben ein Schreib / Lesespeicher. Wollen wir einen Speicher haben, der zwar (für uns verwertbare) Informationen hergibt, sie aber nicht überschreiben kann, müssen wir Nur - Lesespeicher verwenden. Um die Informationen im RAM beim ausgeschalteten Rechner zu schützen, müßte man die RAMs auch nach dem Abschalten aller anderen Teile des Rechners weiter mit Strom versorgen. Zu diesem Zweck gibt es auch RAMs die nur sehr wenig Strom verbrauchen. Im Atari wurden jedoch "normale" RAMs verwendet.

Die Nur-Lesespeicher werden ROM (Read Only Memory) genannt. Es gibt viele unterschiedlich Arten von ROMs, die sich in der Bezeichnung immer nur durch Buchstaben vor dem "ROM" unterscheiden, z.B. EPROM, EEROM, EAROM, PROM, IPROM. In der Bezeichnung der Hersteller "heißt" ein bestimmtes EPROM aber zum Beispiel "2716".

Alle haben aber eines gemeinsam: Der Computer kann die in ihnen enthaltene Information nicht OHNE HILFSMITTEL ändern, bei einigen Bausteinen wird die Information sogar gleich bei der Entwicklung des Types hineingegeben, sodaß sie von uns niemals mehr änderbar ist (außer natürlich durch Zerstörung des Bausteines).

Die Zentraleinheit

Die Zentraleinheit übernimmt die gesamte Verwaltung des Computers. Sie adressiert den zur Verfügung stehenden Speicher, behandelt Daten in dem Speicher und verwaltet bzw. dirigiert die I/O - Leitungen. Sie ist also das Kernstück eines jeden Computers. Ist sie defekt, läuft der ganze Rechner nicht mehr.

Allgemein besteht sie aus einigen internen Speicherplätzen, sogenannten Registern, die im Gegensatz zum übrigen Speicher den Vorteil haben, daß sie wesentlich schneller von der Zentraleinheit angesprochen werden können.

Außerdem sind in der CPU (Central Processing Unit, Zentrale Prozesseinheit) noch eine komplexe Logik zum Rechnen, Treiber zum Ansteuern der Speicher und I/O - Leitungen sowie einige interne, nicht direkt adressierbare Zwischenspeicher enthalten.

Nach außen hin liefert die CPU Adressensignale zum Ansteuern der weiteren Baugruppen, Datenleitungen zum Transport (Lesen oder Schreiben) von Daten sowie einige Kontrollsignale, die den Status der CPU angeben, so z.B. eine Schreib/Leseleitung, die angibt, ob Daten gesendet oder gelesen werden sollen.

In unserem ATARI haben wir es mit der 6502 - CPU ( lies: fünfundsechzignullzwo zehpehuh ), bzw. der 6502C - CPU zu tun. Sie besitzt u.a. 8 Datenleitungen, mit denen sie die jeweils 8 Bit vom oder zum Speicher transportieren kann.

Weiterhin liefert sie 16 Adressensignale, mit denen man Speicher oder I/O - Leitungen ansprechen kann. 16 Leitungen also, wieviele Speicherplätze sind das denn? Wer im vorigen Kapitel aufgepaßt hat, hat die Antwort schnell parat: es sind genau 2**16 Speicherstellen oder I/O - Adressen.

Hier sei noch folgende Konvention der Techniker erwähnt :

Im Gegensatz zum "normalen" Kilo, das einem Faktor von l000 entspricht (man denke z.B. an das Kilogramm: 1kg = 1000g), spricht der Informatiker von dem Kilo als 1024.

Also : 1 KBit = 1024 Bit

Die "krumme" Zahl 1024 läßt sich leicht begründen: 1024 = 2**10. Wenn man also von einem Kilobyte spricht, meint man 1024 Byte. 16 KByte sind 16384 Bytes und 64 KByte sind 65536 Bytes. DAS IST KEIN DRUCKFEHLER!

Genau bei 64 Kilo stimmt die Daumenregel Anzahl mal tausend nicht mehr! Also nicht verwirren lassen, z.T. zum Verkauf angebotene Computer mit 65 KByte gibt es nicht! Leider wird selbst in Elektronikzeitschriften gelegentlich von 65 KByte gesprochen.

Wer bis hierhin alles verstanden hat, ist auch sicherlich in der Lage zu erklären, weshalb es keinen Computer geben KANN der GENAU 65 KByte adressiert.

Die Begründung ist einfach: 16 Adressleitungen adressieren 64 KByte RAM, 17 Adressleitungen dagegen schon 128 KByte. Wieviele Adressleitungen bräuchte man also für 65 KByte Adressraum ?

Die 64 KByte Adressraum der CPU werden nun aufgeteilt in RAM, ROM und

Input- / Output - Leitungen

Unter diesem Begriff versteht man nicht bloß eine Anordnung von Leitungen, über die Daten transportiert werden, sondern insbesondere die zu deren Ansteuerung notwendige Elektronik, die aus den Computer-Bits elektromechanische, elektronische, optische oder akustische Signale erzeugt, und somit die vom Computer gegebenen Informationen hörbar, sichtbar oder für ein beliebiges Medium speicherbar macht. Diese Wandler werden gemeinhin als "INTERFACES" oder "CONTROLLER" bezeichnet.

Unter einem INTERFACE versteht man eine Baugruppe, die die von einem beliebigen Geber gesendeten Signale so umwandelt und weitersendet, daß ein ebenfalls daran angeschlossener Empfänger sie erkennen, kontrollieren und verarbeiten kann.

Ein CONTROLLER "bewacht" das ihm schutzbefohlene Peripheriegerät (Peripherie = griech. Umfeld, Umfeld, also das, was "drumrum" ist wie z.B. Drucker, Floppy o.ä.) und versorgt es mit Befehlen und Daten, beziehungsweise holt Daten von ihm ab.

Selbstverständlich gehört zu der jeweiligen Elektronik auch immer eine Software, der TREIBER, der das sogenannte PROTOKOLL, das den Ablauf der Datenübertragung regelt, festlegt. Er reagiert zum Beispiel auf eine Datenanfrage, einen Fehler in einer Übertragung oder ähnliches mehr. Einige Protokolle sind standardisiert, oder ihre Standardisierung ist in Vorbereitung. Zuständig hierfür sind Institutionen wie die ISO (International Standardisation Organisation) oder CCITT, das französische Gegenstück.

LOW und HIGH

Uns interessiert jetzt die Frage, wie sich der Computer mit dem Speicher und den peripheren Geräten unterhalten kann, denn selbst bei Aufschrauben des Computers sind nirgends Nullen oder Einsen zu finden (Schlaumeier aufgemerkt, wer meint, die 6502 - CPU enthalte eine Null, hat irgendetwas nicht richtig verstanden...). Auch die am Anfang beschriebenen Relais, die offen oder geschlossen gewesen sein konnten, sind nicht im ATARI zu finden; wo steckt dann die Information?

Sie wird in Form von elektrischen Spannungen übertragen, die im Interesse der einzelnen Computerfirmen standardisiert sind. Es gibt dafür allerdings mehrere unterschiedliche Arten elektronischer Baugruppenstandards, aber uns interessiert hier nur einer:

Der TTL - Standard

Alle Bausteine auf TTL - Basis (Transistor - Transistor Logik) arbeiten mit einer Versorgungsspannung von +5 Volt, sofern sie nicht für den Interfacebetrieb an höheren Spannungen entwickelt wurden. Die Versorgungsspannung ist die Spannung, die einen Baustein zum "Leben" erweckt, ohne die sich "nichts tut".

Ein anderes Herstellungsverfahren als das der TTL - Logik, das uns die MOS (Metal Oxyd Semiconductor, Metalloxyd Halbleiter) - Bausteine "schenkte", lieferte uns auch die 6502 - CPU sowie alle höher integrierten Bausteine, wie z.B. die Speicher.

Unter höherer Integration verstehen wir, daß auf gleichem Platz (Quadratmillimeter) mehr Bauteile untergebracht sind und solche Bausteine wie Speicher oder CPUs "verbraten" immense Mengen von Bauteilen. Wollte man z.B. die CPU mit einzelnen Transistoren aufbauen, bräuchte man schon einen kompletten mittleren Wohnzimmerschrank inclusive Kühlanlage! Der ist aber, wie gesagt, nicht (mehr) notwendig.

Betrieben werden unsere Bausteine also mit einer Versorgungsspannung von +5 Volt gegen Massepotential (entspricht meist dem Erdpotential). Jetzt können wir zwei unterscheidbare Zustände definieren:

  1. Der LOW (niedrigere) - Zustand soll der negativeren und
  2. der HIGH (höhere) - Zustand soll der positiveren Spannung entsprechen.

Warum so kompliziert, warum nicht einfach LOW=Masse und HIGH=+5V? Diese komplizierte Ausdrucksweise ist notwendig, da in (nicht TTL-) Baugruppen Versorgungsspannungen von z.B. -5V existieren können. Hier wäre dann eine neue Definition notwendig, die man mit der komplizierten Beschreibung oben aber ebenfalls abgedeckt hat. Bei TTL-Bausteinen sind die Potentiale der Pegel folgendermaßen definiert :

  • HIGH - Potential liegt zwischen +2,4 Volt und +5,0 Volt
  • LOW - Potential liegt zwischen 0 Volt und +0,8Volt

Was liegt aber zwischen +0,8 und 2,4 Volt Eingangsspannung?

Bitte nicht lachen: Das weiß der Baustein, der diese Eingangsspannung empfängt, selbst nicht!

Im Allgemeinen fangen ICs bei unklaren Eingangspegeln an zu schwingen, das heißt, sie erkennen in schnellem Wechsel am Eingang abwechselnd LOW und HIGH.

Im übrigen gilt diese Definition oben von Low und High nicht immer; wir sprechen hier von POSITIVER LOGIK. Bei der negativen Logik ist alles genau umgekehrt, aber darauf wollen wir jetzt nicht weiter eingehen.

Jetzt wissen wir, wie der Computer seine Daten haben möchte: in Form von Spannungen. Spannungen kann man nicht sehen, nur ihre Auswirkungen (z.B. Blitze!) . Man kann aber auch Geräte benutzen, die uns das Vorhandensein oder Fehlen von Spannungen anzeigen. Da wären als einfachste Geräte die Logikprüfstifte zu nennen.

Sie bestehen aus einem kugelschreibergroßen Gehäuse, in dem sich zwei oder mehr Lampen befinden; je nachdem, welche der Lampen leuchtet, liegt die eine oder die andere Spannung an. Dies ist das billigste Meßinstrument in der Digitaltechnik, nur leider arbeitet unser ATARI so schnell, daß wir in den meisten Fällen beide Lämpchen leuchten sehen würden, da sich die Pegel an den ICs 50000 Mal so schnell ändern wie wir sehen können! Also ist dieses Meßinstrument für uns meist zwecklos.

Als nächstes gibt es das sogenannte Vielfachmeßinstrument. Es kann mit einem Zeiger oder einer Digitalanzeige versehen sein - man benötigt es zwar manchmal zum Reparieren von Computern, aber prinzipiell ist auch dieses Instrument für die Anzeige "nicht-statischer" Spannungen und Ströme in einem Mikrocomputer zu langsam.

Das Gerät, mit dem man sich an den Computer "heranwagen" darf, ist das Oszilloskop (manchmal auch "Oszi" oder "Oskar" genannt) mit einer Minimalfrequenz von 40MHz (Megahertz).

Eine derartig hohe Frequenz (der Atari arbeitet mit 1,77 MHz) wird benötigt, da wir digitale Signale messen wollen. Um diese richtig zu sehen, brauchen wir eine wesentlich höhere Frequenz als die des zu messenden Signals, denn Rechteckschwingungen bestehen aus beliebig vielen ungeradzahligen Harmonischen, und je mehr man davon sieht, umso besser werden die Signale auf dem Oszischirm gezeigt.

Diese kleine Ausschweifung in das (riesige) Feld der Meßtechnik sei als WARNUNG hier eingebaut.

"Niemals mit ungeeigneten Meßinstrumenten versuchen, etwas zu reparieren! Das kann nur "schief" gehen."

Es gibt zwar für jeden Techniker einmal die Situation, daß er ein Gerät reparieren muß, ohne die geeigneten Meßgeräte dabei zu haben, aber :

"Ein guter Techniker weiß, wann er aufhören muß zu improvisieren !"

Diesen Spruch sollte sich jeder über's Bett nageln, der an seinem ATARI herumschraubt, ohne GENAU zu wissen, was er macht. Damit wollen wir die kurze Einführung das "Prinzip eines Mikrocomputers" beenden.

Hauptkategorie: 8-Bitter
Erstellt: 20 November 2011
Zugriffe: 2265

Das Betriebssystem eines Computers kann, unabhängig von Größe, Art, Alter und Aufbau des Rechners, als die Schnittstelle zwischen der Hardware, also der Elektronik, und der Anwendersoftware, also zum Beispiel Programmiersprachen, Text- und Datenverarbeitungsprogrammen und anderer Software bezeichnet werden. Es ist unter anderem dafür verantwortlich, dem Anwender (beziehungsweise Programmierer) definierte Softwarehilfsmittel zur Verfügung zu stellen, mit denen er zum Beispiel ein einzelnes Zeichen auf den Bildschirm oder ein anderes Peripheriegerät bringen oder von ihm holen kann. (Peripherie = griech. Umfeld, also alles 'Drumherum'. In der Computerbranche Ausdruck für Ein-/Ausgabegeräte wie zum Beispiel Terminals oder Drucker).

Außerdem ist das Betriebssystem diejenige Software, die das System nach dem ersten Einschalten in einen Grundzustand bringt. Diesen Vorgang nennt man allgemein Power-Up, was aussagen soll, daß hier die Versorgungsspannung das erste Mal seit dem letzten Ausschalten angelegt wird. Der dabei von dem Computersystem durchlaufene Zyklus wird als PowerUp-Reset bezeichnet.

Während dieses Power-Up-Resets werden sämtliche vom Betriebssystem benötigten Speicherstellen sowie die Ein-/Ausgabebausteine initialisiert.

Gerade auf diesen letzten Punkt, die Ein-/Ausgabebausteine, wird bei heutigen Betriebssystemen gesteigerte Aufmerksamkeit gerichtet. So war es noch vor wenigen Jahren üblich, jeden Datentransfer zum Beispiel vom Speicher auf einen Magnetträger wie eine Floppy-Disk, direkt von der CPU aus zu gestalten und somit Rechenzeit damit zu 'verbraten'. Heute gibt es genügend sogenannte Controller, die nach kurzem Anstoßen durch die CPU den Datentransfer und die Gerätekontrolle alleine übernehmen, so daß das eigentliche System nach Möglichkeit nicht weiter behindert wird.

So kann ein Controller damit beschäftigt sein, auf Anforderung eines zweiten, anderen Controllers, ein (das nächste) Datenelement aus dem Speicher auszulesen und eben dieses Datum an den zweiten Controller zu übergeben.

Dieser zweite Controller könnte dann die Aufgabe haben, dieses Zeichen nach ganz bestimmter Vorgehensweise auf die Floppy-Disk zu schreiben und diesen Vorgang auf Korrektheit hin zu überprüfen.

Solche Vorgehensweisen werden im allgemeinen DMA-Prozesse genannt, was Direkt-Memory-Access, direkter Speicherzugriff ohne die Benutzung der CPU bedeutet.

Der DMA hat den schon oben erwähnten Vorteil, daß bei gut ausgeführtem DMA-Konzept die eigentliche Rechenzeit nicht weiter beeinflußt wird, hat jedoch die Nachteile, daß die Controller aufgrund der beinhalteten Intelligenz nicht eben billig sind. Außerdem ist ein System, bei dem alle Aufgaben von nur einem Baustein bearbeitet werden, wesentlich leichter zu überwachen als eines, bei dem sich diverse, parallel arbeitende, 'Intelligenzbestien' gegenseitig beeinflussen und Fehler 'zuschieben'. Es gilt also leider auch in diesem Computerbereich der Satz, daß "viele Köche den Brei verderben".

Es gibt jedoch noch eine dritte Möglichkeit, ein System aufzubauen. Dabei werden, ähnlich dem DMA-Konzept, Intelligenzen 'verteilt'. Es existieren also auch intelligente Geräte, wie zum Beispiel eine Diskettenstation. Der Unterschied zum DMA-Betrieb besteht jedoch darin, daß die Diskette nicht direkt im Speicher des Hauptsystems 'herumfummelt', sondern nur über eine sogenannte Interruptleitung dem Hauptoder auch Hostsystem mitteilt, daß es neue Daten braucht oder abgeben will. Es ist dann alleinige Aufgabe des Hostsystems, herauszufinden, von wem und auf welche Weise der Interrupt behandelt werden soll.

Im Normalfall wird solch ein Interrupt zuerst die CPU von der Meldung unterrichten. Dies geschieht dadurch, daß die CPU das eigentlich gerade bearbeitete Programm unterbricht, um einen sogenannten Interrupt-Handler aufzurufen. In diesem Interrupt-Handler, der meist Teil des Betriebssystems ist, stehen dann die, beim Auftreten eben dieser Bedingung auszuführenden, Kommandos. Damit wird dann entweder ein Baustein programmiert, der die beim unterbrechenden Gerät anliegenden

Daten einliest und verarbeitet (beziehungsweise an ein anforderndes Gerät übergibt) oder die CPU übernimmt selbst die Datenverarbeitung, um danach zu dem unterbrochenen Benutzerprogramm zurückzukehren.

Bei annähernd allen Geräten die es heutzutage verdienen, Computer genannt zu werden, treffen Sie Mischformen der drei oben angegebenen Konzepte an. Das gilt sowohl für den Hobbycomputermarkt als auch für die wesentlich teureren Bürogeräte.

Jeder Entwickler hat seine ganz perönlichen Einstellungen zu bestimmten Systemkonzepten, Vorlieben und Abneigungen zu einzelnen Bausteinen (oder Bausteinherstellern!), so daß man nicht von 'dem Computerkonzept' sprechen kann und dies wohl auch nie können wird.

Wie nach diesen einleitenden Erklärungen nicht anders zu erwarten, ist also auch das Atari 600XL/800XL-System eine Mischform aller drei Konzepte.

Als Bespiel für das reine CPU-Konzept kann die Tastaturabfrage dienen. Der Tastenkode wird zwar über einen Baustein (POKEY) eingelesen, dieser dient aber lediglich in diesem Falle als Pufferbaustein. Die eigentliche Dekodierarbeit, welcher Tastenkode zu welchem ATASCII-Zeichen gehört, wird von der CPU selbst übernommen.

Das DMA-Konzept ist, wie den entsprechenden Kapiteln zu entnehmen, in technisch ausgesprochen gut ausgereifter Weise beim ANTIC und GTIA enthalten. Der ANTIC versorgt unter anderem als intelligenter DMA-Controller den GTIA mit Daten.

Aber auch die dritte Systemart ist vorhanden: Die Atari 400/800- und 600XL/800XL Modelle verfügen über ein hohes Maß an Interrupts, von denen ein nicht unerheblicher Teil für die Datenübermittlung von oder zu peripheren Geräten über die serielle Schnittstelle und den POKEY-Baustein verwendet wird.

Dabei kann man grundsätzlich sagen, daß das System für einen Computer dieser Preisklasse über ein erstaunliches Niveau verfügt. Nicht unbedingt wegen der grundlegenden Konzeption; man findet sie in ähnlicher Form sicher auch bei Konkurrenzprodukten. Es sind jedoch zwei andere, für den reinen Benutzer nicht unmittelbar zu entdeckende Vorteile, die nur dann auffallen, wenn sie nicht vorhanden sind:

Zum einen ist das Gesamtsystem abgerundet und die einzelnen Komponenten jeweils sauber aufeinander abgestimmt. Dies und anderes stellt sicher, daß das System nach Möglichkeit jeden erdenklichen Fehler beim gleichzeiten Ausführen unterschiedlicher Aktivitäten 'abfängt' und korrigiert. Es gibt genug Computer, die pfiffige Grundelemente beinhalten. Kommt jedoch solch ein Element einmal ein wenig 'aus dem Tritt', gibt es keine Kontrollstuktur, die den Fehler auffängt.

Ein konkretes Beispiel hierzu wäre in den seriellen Schnittstellenroutinen zu finden. Vielleicht ist Ihnen schon einmal aufgefallen, daß der Atari beim Lesen oder Schreiben von/auf Diskette manchmal 'einschläft', also einige Sekunden lang nichts tut, um danach, wie von Geisterhand, völlig korrekt weiterzuarbeiten. Dieser Effekt tritt besonders häufig dann auf, wenn man Diskettenstationen fremder Hersteller verwendet.

Die Ursache des Fehlers ist in der Art der Kommunikation zwischen Computer und Diskettenstation zu suchen. Der Atari wartet nach dem Senden eines Kommandos auf eine Antwort des angesprochenen Gerätes. Kommt die Antwort jedoch etwas zu schnell für den Atari, weil dieser zum Beispiel gerade mit der Bearbeitung von Interrupts beschäftigt war, wertet er diese Antwort als fehlerhaft und wartet auf eine korrekte Meldung. Diese kann natürlich nicht kommen, weil die Diskettenstation der berechtigten Ansicht ist, schon geantwortet zu haben und vielleicht sogar nun selbst auf Daten wartet.

Dieser Konflikt, bei dem also zwei aufeinander wartende Geräte sich gegenseitig blockieren, wird Deadlock genannt und ist eine bei Betriebssystemtechnikern gefürchtete Erscheinung immer komplexer werdender Programme und führt bei

manchen Hobbycomputern zum 'Absturz', da der Konflikt nicht erkannt wird. Nicht jedoch beim 'Nobel-Betriebssystem' von Atari: Hier sorgt ein sogenannter Timeout dafür, daß die Übertragung weitergeht. Die CPU bekommt hierdurch mitgeteilt, daß die Übertragung offensichtlich 'hängt' und versucht sie ein zweites Mal.

Der zweite Vorteil des Atari-Betriebssystems gegenüber denen anderer Hersteller ist schlichtweg der, daß darin Ordnung herrscht.

Das bedeutet, daß das ganze System in kleine, überschaubare Routinen aufgeteilt ist, von denen normalerweise ganz klar definiert werden kann, was sie als Ausgabe bei welcher Eingabe liefern. Es ist, in den hier im Buch beschriebenen 12 KByte, mit einer Ausnahme davon abgesehen worden, 'Spaghetti-Kode' zu schreiben, also endlose Routinen, in denen alles und nichts getan wird. Die eine Ausnahme läßt sich ebenfalls begründen; es handelt sich dabei um eine Interruptroutine und dort wollte Atari einfach Bearbeitungszeit sparen.

Mit wenigen Ausnahmen kann man sagen, daß dieses Betriebssystem nicht von irgendwelchen Hackern geschrieben wurde, sondern von Ingenieuren, die Ihre Arbeit hervorragend verstehen.

So sind zum Beispiel die Ein-Ausgaberoutinen nicht für jeden Baustein anders, sondern es gibt sogenannte Input-OutputControl-Blocks (IOCBs), die die Art des Gerätes, das Kommando und alle damit verbundenen Werte definieren. Die Ausgabe findet nun dadurch statt, daß an die Ausgaberoutine nur noch die Nummer des IOCB übergeben zu werden braucht, und schon 'weiß' der Computer, wie er welches Gerät zu behandeln hat und welche Ein- bzw. Ausgabeoperation ausgeführt werden soll.

Diese Ordnung ist auch Grundlage dafür, daß Atari nicht schon zu Laufzeiten der alten 400/800-Serie diverse Betriebssysteme hervorbrachte, die dann nicht zueinander gepaßt hätten.

Atari hat zwar eine neue Version herausgebracht, in der einige Fehler verbessert wurden, es muß jedoch klar gesagt werden, daß Software, die für den 400/800 geschrieben wurde, voll auf den neuen Systemen lauffähig ist, wenn nur die, den autorisierten Händlern und Softwareproduzenten bekannten und von denen vielfach publizierten, Originaleinsprungadressen verwendet wurden.

Es dürfte auf der Hand liegen, daß ein Pogramm, in dem 'raffiniert getrickst' worden ist, natürlich an eine bestimmte Betriebssystemversion gebunden ist. Ein vernünftig, also ingenieurmäßig, arbeitender Programmierer hat dagegen beim Systemwechsel bei Atari keinerlei Probleme.

Dazu trägt auch noch bei, daß bei Atari dieses Betriebssystem wirklich nur eben das Betriebssystem ist, und nicht zum Beispiel Verquickungen mit einer eingebauten Programmiersprache, wie etwa BASIC, programmiert sind. Da kann es in anderen Systemen zum Beispiel vorkommen, daß in einem BASICInterpreter Routinen für Peripherieschnittstellen definiert sind. Wird also das BASIC abgeschaltet, darf man sich diese Schnittstelle neu programmieren.

Alle diese Mankos sind hier beim Atari 600XL/800XL weitestgehend vermieden worden. Zwar ist im Rechner ein MathematikROM fest eingebaut, es wird jedoch nicht (wirklich!) vom Betriebssystem benutzt.

Die Einschränkung 'wirklich' muß gemacht werden, da in der normalen Systemkonfiguration bei bestimmten Ein-/Ausgabeoperationen plötzlich bestimmte Stellen in diesem ROM angesprochen, beziehungsweise direkt angesprungen werden. Das heißt jedoch nicht, daß dort gerechnet werden soll, sondern daß dieses ROM einmal von irgendwelcher Periherie abgeschaltet und der dann freigewordene Platz mit neuem Programmspeicher belegt werden soll. In diesem Adreßbereich könnten dann zusätzliche Treiberprogramme liegen.

Welcher Art diese Peripherie sein soll, läßt sich nur erahnen, da uns außer der 64 KByte-RAM-Karte beim 600er keine

Geräte bekannt sind, die auf dem hinten anliegenden Systembus angeschlossen würden. Nur in diesem Fall nämlich könnte das Peripheriegerät den im Mathematik-ROM liegenden Adreßbereich füllen.

Ganz allgemein kann aus der Verbindung dieses Betriebssystems mit der Kenntnis über die Bus-Signale und der Tastaturdekodierung gesagt werden, daß es eigentlich gar kein Atari 600XL/800XL-Betriebssystem gibt. Es handelt sich in jedem Fall um ein modifiziertes Betriebssystem von dem leider bei uns (noch ?) nicht ausgelieferten 1200XL !

Dies ist daran zu erkennen, daß das Betriebssystem des 600XL/800XL Tastenabfragen nach Funktionstaste 1 bis 3 enthält, diese Tasten jedoch nicht bei diesem Gerät vorgesehen sind. Der 1200XL dagegen besitzt vier Funktionstasten F1 bis F4. An diesen und wenigen anderen Details bleibt es dem Fachmann nicht unentdeckt, daß dieses Betriebssystem eigentlich kein 600XL/800XL-Programmpaket ist.

Im Unterschied zum alten 400/800-Betriebssystem sind einige Dinge erstaunlich und, um nach so viel positivem auch einmal negative Kritik anzubringen, merkwürdig.

So sind in dem System Routinen enthalten, die den völlig gleichen praktischen Wert haben wie die entsprechenden des alten 400/800-Betriebssystem, aber völlig anders aufgebaut sind und dabei nicht unbedingt besser, schneller oder einfacher. Auch sind einfach komplette Programmblöcke um nur wenige Byte verschoben worden, obwohl sie dort leicht hätten stehenbleiben können. Dies alles ist jedoch nur für diejenigen Programmierer ärgerlich, die sich nicht an die von der Firma Atari vorgegebenen Schnittstellen gehalten haben.

Es bleibt die Frage, ob der offensichtlich von Atari gewünschte 'Erziehungseffekt' überhaupt von den angesprochenen Personenkreisen bemerkt wird; wir glauben es (leider) nicht, da schon Mittel und Wege gefunden wurden, dem 600XL/800XL erfolgreich vorzutäuschen, er sei ein 400/800.

 

RESET UND INTERRUPTS

Beim Kaltstart, auch Power-Up-Reset genannt, werden sämtliche für den Betrieb benötigten Register und Hardwarebausteine des Atari initialisiert. Hierbei werden ebenfalls die Interrupts eingerichtet, die das System nach dem Kaltstart am Laufen halten.

Es gibt eine ganze Reihe unterschiedlicher Interruptsquellen im Atari 600XL/800XL. Als erste und wichtigste wäre der 50 Hz-Vertical-Blank-Interrupt zu nennen. Er gilt in diesem System als das Zeitnormal oder, anders formuliert, es wird nach ihm die (systeminterne) Uhr gestellt.

Beim Auftreten eines solchen Interrupts, der nur signalisieren soll, daß im Moment keine Bildinformationen gesendet werden, weil der Elektronenstrahl der Monitorbildröhre gerade von unten rechts nach oben links zurückwandert, werden nahezu alle im Hintergrund laufenden Prozesse bearbeitet, die nicht selbst eine Hardware-Unterbrechung auslösen können. Dazu gehören als wichtigste Prozesse die Verarbeitung der Schattenregister und der Timer.

Die Schattenregister haben, bei vom System zyklisch zu schreibenden Registern, die Aufgabe, die zu schreibenden Informationen zu sichern. Es hat bei vielen Registern keinen Sinn, vom Benutzerprogramm aus, einen Wert direkt in eben dieses Hardware-Register zu schreiben, da der entsprechende Baustein nach kurzer Zeit um ein Auffrischen der Information bittet. Ohne ein Schattenregister wüßte dann das System nicht, welchen Wert es übergeben soll. Hat man jedoch die gewünschte Information in ein Schattenregister, also eine ganz normale Speicherstelle geschrieben, kann das Betriebssystem im Vertical Blank Interrupt den Inhalt dieser RAMZelle jedesmal auslesen und ihn in das Hardwareregister übertragen.

Die Verwendung von Schatten-Leseregistern hat meist eine andere Bewandtnis: Viele Meß- und Statusregister erkennen das Auslesen des gemessenen Wertes gleichzeitig als Rücksetzbefehl an, beginnen also mit einer neuen Messung oder löschen einfach nur bestimmte Informationen, wie zum Beispiel Fehlererkennungsbits.

Ist man nun gerade dabei, einen Wert auszumessen, und liest den bis dahin gemessenen Wert, ohne zu wissen, ob die Messung eigentlich abgeschlossen ist, würde in den meisten Fällen ein Fehlergebnis entstehen. Hat man im Gegensatz dazu eine einfache Speicherstelle, bei der man davon ausgeht, daß das Betriebssystem diese schon richtig beschreiben wird, ergeben sich diese Probleme nicht.

Ein weiterer Effekt der Schatten-Leseregister ist der, daß Meßergebnisse gezielt verändert werden können. So können von einem Statusregister nacheinander bestimmte Bits abgefragt werden. Sind sie gesetzt, wird ein dazugehöriger Handler aufgerufen. Bearbeitet dieser Handler nun nicht nur das eine Statusbit, sondern auch gleich noch einige andere, so kann dieser Handler nach der Behandlung die 'fertigen' Bits in der RAM-Zelle zurücksetzen, was ihm im Hardwarestatusregister nicht möglich gewesen wäre.

Die Timer haben die Aufgabe, zeitabhängige Vorgänge innerhalb des Systems zu koordinieren.

Es existieren zwei strikt voneinander zu trennende Arten von Timern: Die eine Sorte sind die Hardwarezähler, die im POKEY enthalten sind. Ist einer der Zähler 1, 2 oder 4 durch die angelegten Takte auf den Wert Null zurückgefallen, kann vom POKEY ein Interrupt ausgelöst werden. Auf diese Art Timer wollen wir hier nicht weiter eingehen, da ihre Funktionsweise eingehend im Kapitel POKEY erläutert ist.

An dieser Stelle interessieren eigentlich nur die fünf anderen Softwaretimer TIMCOUNT1 bis TIMCOUNT5.

Das sind jeweils 16bit-Werte, die vom Benutzer auf, in den gegebenen 16bit-Rahmen, beliebige Werte zu setzen sind und die dann selbsttätig bei jedem Vertical Blank Interrupt decrementiert werden.

Wird nach dem Verringern festgestellt, daß TIMCOUNT1 oder TIMCOUNT2 den Wert Null erreicht hat, wird indirekt über den entsprechenden Sprungvektor TIMER1VKT oder TIMER2VKT die vom Anwender zu programmierende Timer-Interruptroutine angesprungen. Diese Routinen sind immer mit einem normalen RTS bei 'aufgeräumtem' Stack zu beenden. Das heißt, daß nicht noch irgendwelche lokalen Werte auf dem Stack liegen dürfen, wenn zurückgesprungen werden soll.

Hat dagegen einer der Timer TIMCOUNT3, TIMCOUNT4 oder TIMCOUNT5 den Wert Null erreicht, so wird keine Routine angesprungen, sondern jeweils nur das entsprechde 8bit-Flag TIMER3SIG, TIMER4SIG oder TIMER5SIG vom Wert $00 auf $ff gesetzt. Das Anwenderprogramm mag dann die Veränderung dieser Werte selbst bemerken. Es ist auch nicht immer unbedingt sinnvoll, für jeden Timer-Event, also jeden Zeitpunkt, an dem eine bestimmte Operation ausgeführt werden soll, eine automatisch aufzurufende Prozedur zu schreiben, da es sein kann, daß der entsprechende Timer mehrfach herunterzählen soll, bis das gewünschte Ergebnis vorliegt.

Als weitere Operation wird im Vertical Blank Interrupt die sogenannte 'verzögerte' (deferred) Vertical Blank InterruptRoutine aufgerufen. Da diese Routine im Normalfall nach einem Kaltstart nicht existiert, weist ihr Pointer VBLKDVKT auf die Interrupt-Ausgangsroutine EXITVBL. Diese Routine EXITVBL ist auch dann anzuspringen (nicht aufzurufen!), wenn eine solche verzögerte Unterbrechungsroutine existiert und beendet werden soll. EXITVBL stellt sicher, daß das ursprünglich unterbrochene Programm seine alten Registerwerte wiedererhält.

Wichtig zu erwähnen wäre, daß TIMCOUNT1 bei jedem Vertical Blank Interrupt bearbeitet wird, die restlichen Timer dagegen nur dann, wenn das Flag CRITICIO gelöscht ist. Dieses Flag soll verhindern, daß im vollen Betrieb bei sehr schnell folgenden Interrupts, also zum Beispiel beim Lesen von Floppy, der Rechner mit 'Kleinkram' wie Timerverarbeitung aufgehalten wird, und somit eventuell einen Interrupt nicht mehr rechtzeitig bearbeiten kann. Timer 1 wird deshalb immer benutzt, weil er die Aufgabe übertragen bekommen hat, eine mögliche Timeout-Situation zu erkennen. Dies kann er natürlich nur dann tun, wenn er regelmäßig bearbeitet wird.

Neben diesen regelmäßigen Unterbrechungen gibt es auch eine ganze Reihe asynchroner Interrupts, also solche, über deren zeitliches Auftreten nichts genaues gesagt werden kann. Dazu gehören zum Beispiel die Unterbrechungen der seriellen Übertragungsstrecke, die vom POKEY gesammelt und gewandelt werden. Diese und andere Interrupts besitzen ihre Vektoren ab der Adresse VPRECEDE.

Jede dort abgelegt Interruptroutine muß mit den Instruktionen

PLA
RTI

enden, um sauber zum unterbrochenen Progamm zurückzukehren.

 

Ein-/Ausgabe über Kontrollblöcke

Beim Atari-Computer soll die gesamte Ein- beziehungsweise Ausgabe über sogenannte Kontrollblöcke ablaufen.

Das heißt, es gibt nicht für jedes anzusprechende Gerät eine eigene Adresse, die sich der Benutzer merken muß, sondern es gibt eine Adresse, die den Großteil des Input und Output übernimmt. Dazu wird die Beschreibung des Ein-/Asgabegerätes in einem Input-Output-Control-Block abgelegt. Dort stehen der Name des Gerätes, die Bus-Nummer, Pufferadressen und Pufferlängen sowie Statusinformationen:

IOCB - Eintrag      Bedeutung
------------------------------------------------------------

IOCBCHID            IOCB-Channel-Identifikationsnummer.  Sie
                    ist  der Offset des Eintrages  innerhalb
                    der Tabelle ab HATABS.  Vorgegeben  sind
                    schon die Einträge

                    $00 =    'P'       Printer, Drucker
                    $03 =    'C'       Cassette
                    $06 =    'E'       Editor
                    $09 =    'S'       Screen, Bildschirm
                    $0c =    'K'       Keyboard, Tastatur
                             'D'       Diskettenstation
                             'M'       Modem

                    Die beiden letzten Einträge stehen nicht
                    initiell in HATABS.  Die Diskette nicht,
                    weil  sie nicht direkt über CIO  sondern
                    über eigene Disk-Operationen läuft,  und
                    das  Modem  deshalb nicht,  weil es  von
                    Atari  kein in Deutschland  zugelassenes
                    gibt. Die einzige Möglichkeit dazu wäre,
                    über die Interfacebox zu arbeiten.

IOCBDSKN            Laufwerknummer.  Die  Diskette  ist  das
                    einzige  am Atari anzuschließende  Peri-
                    pheriegerät,  von  deren  Sorte  mehrere
                    gleichzeitig  am  Bus  anliegen  können.
                    Deshalb  reicht die Information 'D'  bei
                    der Datenübertragung nicht aus und  wird

                    um  diese Laufwerknummer erweitert.  Die
                    Laufwerknummer  kann theoretisch  von  1
                    bis 9 laufen,  es gibt jedoch nur Atari-
                    Stationen,  die  die Nummern 1 bis 4 er-
                    kennen.

IOCBCMD             An  dieser  Adresse wird  dem  zentralen
                    Ein-/Ausgabeprogrammpaket  CIO das  Kom-
                    mando übergeben,  was mit den Daten  und
                    dem angemeldetetn Gerät passieren soll.

                    Es stehen die folgenden, für alle Geräte
                    geltenden, Kommandos zur Verfügung:

                    Befehlskode    Bedeutung
                    ----------------------------------------

                         $03       OPEN
                                   Stellt fest, ob das ange-
                                   kündigte  Gerät überhaupt
                                   am Bus anliegt.

                         $05       GET RECORD
                                   Lies  den nächsten  Block
                                   von dem angemeldeten  Ge-
                                   rät, wenn es ein lesbares
                                   Gerät  ist,  sonst  melde
                                   Fehler.

                         $07       GET CHARACTER(s)
                                   Lies das nächste Zeichen,
                                   beziehungsweise die näch-
                                   sten   Zeichen, bis   zum
                                   NEWLINE von dem  angemel-
                                   deten Gerät,  wenn es ein
                                   lesbares Gerät ist, sonst
                                   melde Fehler.

                         $09       PUT RECORD
                                   Schreibe  den übergebenen
                                   Block  an den  geöffneten
                                   Datenkanal

                         $0b       PUT CHARACTER(s)
                                   Schreibe   das    nächste
                                   Zeichen,  beziehungsweise
                                   alle  folgenden  Zeichen,
                                   bis zum nächsten  NEWLINE
                                   an den geöffneten Kanal.

                         $0c       CLOSE
                                   Schließe den entsprechen-
                                   den   offenen  Kanal  und
                                   schreibe  eventuell  noch
                                   im Puffer vorhandene  Da-
                                   ten  vorher über den noch
                                   offenen Kanal.

                         $0d       STATUS
                                   Lies  die   Statusmeldung
                                   des   angesprochenen  Ge-
                                   rätes.

                         $0e       SPECIAL
                                   Rufe    gerätespezifische
                                   Spezialroutine auf.

                         Weiterhin existieren einige  Spezi-
                         alkommandos,  die  jedoch  nur  bei
                         jeweils einem Gerät gelten:

                         $11       DRAW LINE
                                   Zeichnet  eine Linie  von
                                   einem  Punkt zum  anderen
                                   in   dem   programmierten
                                   Grafikmodus.

                         $12       DRAW LINE WITH RIGHT FILL
                                   Wie  $11,  nur daß rechts
                                   von  der  Linie  bis   zu
                                   einer   eventuell  rechts
                                   davon befindlichen weite-
                                   ren  Linie der  Schirmin-
                                   halt ausgefüllt wird.

                         Die beiden letzten Kommandos galten
                         einsichtiger  Weise  nur  für   den
                         Bildschirm,   wobei  die  folgenden
                         Spezialkommandos  nur für den  Dis-
                         kettenzugriff gelten:

                         $20       RENAME DISK-FILE

                         $21       DELETE DISK-FILE

                         $22       FORMATIERE DISKETTE

                         $23       LOCK DISK-FILE
                                   Danach ist das angegebene
                                   File  nur noch zum  Lesen
                                   zu öffnen.

                         $24       UNLOCK LOCKED FILE

                         $25       POINT
                                   Dieses Kommando 'positio-
                                   niert' den   Schreib-/Le-
                                   sekopf   der  Floppy-Disk
                                   logisch auf den angegebe-
                                   nen Sektor und das  ange-
                                   gebene Byte.

                         $26       NOTE
                                   Analog  zu POINT  liefert
                                   dieses  Kommando die Aus-
                                   sage darüber, wo sich die
                                   Diskettenstation   gerade
                                   logisch befindet.



IOCBSTAT            In  diesem  Byte wird von  CIOMAIN  eine
                    Meldung  zurückgeliefert,   an  der  das
                    aufrufende Modul erkennen kann,  wie die
                    CIO-Routine   das  Kommando   bearbeiten
                    konnte.  Es sind, abhängig von dem Gerät
                    und  dem  Kommando,  insgesamt  folgende
                    Statusmeldungen möglich:


                         $01       SUCCESS
                                   Die   Operation   verlief
                                   erfolgreich.

                         $80       BREAK_ABORT
                                   Währen  der  Kommandoaus-
                                   führung  wurde die BREAK-
                                   Taste gedrückt.

                         $81       PREVIOUS_OPEN
                                   Das Gerät (beziehungswei-
                                   se eigentlich sein Kanal)
                                   wurde schon einmal geöff-
                                   net und ist seitdem nicht
                                   wieder  abgemeldet   (ge-
                                   schlossen) worden.

                         $82       NON_EXISTANT_DEVICE
                                   Dieses   Gerät   ist   in
                                   HATABS nicht bekannt.

                         $83       WRITE_ONLY
                                   Es  wurde  versucht,  von
                                   einem   Nur-Schreib-Kanal
                                   (zum Beispiel Drucker) zu
                                   lesen.

                         $84       INVALID_CMD
                                   Das  übergebene  Kommando
                                   ist nicht existent.

                         $85       NOT_OPEN
                                   Das zu beschreibende oder
                                   zu   lesende  Gerät  oder
                                   File  ist noch nicht  ge-
                                   öffnet.

                         $86       BAD_IOCBNR
                                   Die übergebene  IOCB-Num-
                                   mer,  die  ein Vielfaches
                                   von  16  sein  muß,   ist
                                   entweder  zu  groß   oder
                                   nicht durch 16 teilbar.

                         $87       READ_ONLY
                                   Es  wurde  versucht,  ein
                                   Nur-Lese-Gerät oder -File
                                   zu beschreiben.

                         $88       EOF_ERROR
                                   Es  wurde versucht,  mehr
                                   aus einem File zu  lesen,
                                   als darin enthalten ist.

                         $89       TRUNCATED
                                   Bei   einem  Zeilen-Lese-
                                   Kommando wurde eine Zeile
                                   empfangen, die länger war
                                   als  der  zur   Verfügung
                                   stehende   Puffer.    Die
                                   letzten Zeichen der Zeile
                                   sind  nicht  gespeichert,
                                   das  letzte  Zeichen  des
                                   Puffers ist NEWLINE.

                         $8a       TIMEOUT
                                   Das  Gerät hat sich nicht
                                   wieder gemeldet,  nachdem
                                   es  mit  der  Bearbeitung
                                   des  Kommandos   begonnen
                                   hat.

                         $8b       DEVICE_NACK
                                   Dieser  negative Acknowe-
                                   ledge (negative  Rückmel-
                                   dung)  zeigt an,  daß of-
                                   fensichtlich  das   anzu-
                                   sprechende   Gerät  nicht
                                   bereit (vorhanden,  ange-
                                   schlossen,  eingeschaltet
                                   o.ä.) ist.

                         $8c       FRAMING_ERROR
                                   Dieser  Kode   erscheint,
                                   wenn der POKEY beim Lesen
                                   eines    Zeichens   fest-
                                   stellt,  daß das anzuhän-
                                   gende Stop-Bit nicht kam,
                                   sondern  gleich  mit  der
                                   Übertragung eines  weite-
                                   ren   Zeichens   begonnen
                                   wurde.    Dieser   Fehler
                                   tritt vor allem dann auf,
                                   wenn   der   Sender   und
                                   Empfänger   zu  ungleiche
                                   Übertragungsraten  besit-
                                   zen.  Eine sinnvolle  In-
                                   terpretation  dieses Feh-
                                   lers kann jedoch auch die
                                   BREAK-Kondition sein.

                         $8d       CURSOR_OVERRANGE
                                   Der Cursor wird außerhalb
                                   des ihm zustehenden Bild-
                                   bereichs  gesetzt.  Tritt
                                   zum Beispiel bei falschen
                                   DRAWTO-Berechnungen auf.

                         $8e       SIO-OVERRUN
                                   Dieser POKEY-Fehler zeigt
                                   an, daß ein neues Zeichen
                                   eingelesen  wurde,  bevor
                                   das alte vom System gele-

                                   sen worden ist. Damit ist
                                   das  alte Zeichen  verlo-
                                   ren.

                         $8f       SIO-CHECKSUM_ERROR
                                   Die empfangene  Prüfsumme
                                   stimmte   nicht  mit  dem
                                   berechneten Wert überein.

                         $90       DEVICE_ERROR
                                   Das Gerät konnte die Ope-
                                   ration  nicht  vernünftig
                                   ausführen.

                         $91       BAD_SCREEN_MODE
                                   Dieser   Modus  ist   den
                                   bildschirmverarbeitenden
                                   Routinen unbekannt.

                         $92       FUNCTION_NOT_IMPLEMENTED
                                   Die  verlangte  Operation
                                   ist zwar nicht  verboten,
                                   aber dennoch nicht vorge-
                                   sehen.

                         $93       INSUFFICIENT_SCREENMEMORY
                                   Der zur Verfügung stehen-
                                   de  Speicher reicht nicht
                                   aus,  um den  geforderten
                                   Bildschirmmodus zu initi-
                                   alisieren.  Dies kann zum
                                   Beispiel passieren,  wenn
                                   in   einer  16KB-Maschine
                                   DOS  geladen   ist,   ein
                                   BASIC-Programm  läuft und
                                   eine   hohe   Grafikstufe
                                   gewählt werden soll.

Allgemein  zu  den Fehlermeldungen ist zu  sagen,  daß  ihre
Kodes  bei entsprechender Abfrage das Negativ-Flag  der  CPU
setzen.

IOCBBUFA            Hier  wird die Anfangsadresse des (meist
                    vom  Benutzer zur Verfügung zu  stellen-
                    den) Datenpuffers festgehalten. Der Wert
                    ist  unverändert  nach  Ausführung   des
                    Kommandos,  unabhängig  von Erfolg  oder
                    Mißerfolg der Operation.

IOCBPUTB            Hier   steht  die  Anfangsadresse-1  der
                    Routine, die an das definierte Gerät ein
                    Zeichen überträgt.  Der Vektor zeigt bei
                    Nur-Lese-Geräten  auf die  entsprechende
                    Fehlerbehandlungsroutine.

IOCBBUFL            Dies  ist die Angabe der Länge  des  bei
                    IOCBBUFA beginnenden Puffers.

IOCBAUXn            Die  vier folgenden Byte sind Hilfsregi-
                    ster,   von  denen  jedoch  das   erste,
                    IOCBAUX1,  zeitweilig  für die  CIO-Pro-
                    grammierung  verwendet wird.  Dabei sind
                    folgende Werte erlaubt:

                         $01       APPEND
                                   Dieser  Kode erlaubt  das
                                   anhängende  Schreiben  an
                                   eine   bestehende   Datei
                                   beziehungsweise das Lesen
                                   vom Bildschirm.

                         $02       DIRECTORY
                                   Der folgende  OPEN-Befehl
                                   veranlaßt  einen  Zugriff
                                   auf  die Disketten-Direc-
                                   tory.

                         $04       OPEN_FOR_INPUT
                                   Dieses   Kommando    kann
                                   theoretisch   bei   jedem
                                   Gerät  angewandt  werden,
                                   es sind jedoch physikali-
                                   sche  Einschränkungen  zu

                                   beachten   (zum  Beispiel
                                   Drucker).

                         $08       OPEN_FOR_OUTPUT
                                   Es  gilt das gleiche  wie
                                   für OPEN_FOR_INPUT gesag-
                                   te.

                         $12       OPEN_FOR_OUTPUT & INPUT
                                   Wie OPEN_FOR_INPUT.

                         $10       OPEN_FOR_MIXED_MODE
                                   Dieser  Zusatz  ist   nur
                                   beim   Editor  und   beim
                                   Screen erlaubt.

                         $20       OPEN_WITHOUT_CLEAR_SCREEN
                                   Ebenfalls  nur für Editor
                                   und Screen erlaubt.


Um  nun ein Kommando an die CIO-Routinen zu übergeben,  wird
im  X-Register die Nummer des IOCBs * 16,  und im  Accu  das
unter  Umständen zu sendende Zeichen an JUMPTAB+$06  überge-
ben.

Die Diskettenverarbeitung läuft nicht über die CIO-Routinen,
da  dort  etwas  andere Bedingungen vorliegen  als  bei  den
übrigen  Geräten.  Sie läuft über den Disc-Control-Block  ab
Adresse DSKDEVICE.

An  diese  und die folgenden Adressen werden folgende  Werte
übergeben:

DSKDEVICE           Bus-Kennummer  der  Diskette  Nummer  1.
                    Dieser  Wert ist Referenz für die  übri-
                    gen, nachfolgenden Geräte.

DSKUNIT             Hier  steht die eigentliche  Nummer  des
                    anzusprechenden Laufwerks.

DSKCMD              Es stehen die Kommandos

                    '!'  $21       FORMAT_DISKETTE
                    'P'  $50       PUT_SECTOR_WITHOUT_VERIFY
                    'R'  $52       GET_SECTOR
                    'S'  $53       STATUS_REQUEST
                    'W'  $57       PUT_SECTOR_WITH_VERIFY

                    zur Verfügung.

DSKSTATUS           Hier  steht  nach der Bearbeitung  eines
                    Kommandos der Status der Operation.

DSKBUFFER           Anfangsadresse des Datenpuffers.

DSKTIMOUT           Anzahl  der  Sekunden bis  zur  Timeout-
                    Meldung.

DSKBYTCNT           Länge  des  bei  DSKBUFFER   beginnenden
                    Puffers.

DSKAUX1
DSKAUX2             Hilfsbyte.  Hier  steht bei den  meisten
                    Kommandos  die  zu   lesende/schreibende
                    Blocknummer.

Die  Diskettenverarbeitung  wird nicht über  den  CIO-Vektor
angesprungen,  sondern über JUMPTAB+$09, also das SIO-Inter-
face.

******************************
*                            *
*                            *
*   BETRIEBSSYSTEMROUTINEN   *
*   ----------------------   *
*                            *
******************************




Im   Folgenden  werden  die  einzelnen  Unterprogramme   des
Betriebssystems   erläutert.   Sie  sind  nach  ihrer   Lage
(Adresse) im ROM geordnet.  Die vier Zahlenangaben  bedeuten
von  links  nach  rechts  (die Adreßangabe  kann  sich  beim
400/800 auf ungefähr gleichartige Routinen beziehen):


Adr. beim 600XL/800XL    Adr. beim 400/800   Name
 Hex       Dez            Hex       Dez
------------------------------------------------------------

$c000     49152          $xxxx     xxxxx     CHECKSR0
$c001     49153          $xxxx     xxxxx

     Diese Adresse enthält die Prüfsumme über alle Bytes aus
     den Speicherbereichen
                             $c002 .. $cfff
                             $5000 .. $57ff
                             $d800 .. $dfff

     Auf diesen Wert wird von CHECKROM1 zugegriffen.


$c00c     49164          $e6d5     59093     NMIENABLE

     Es  wird  der  NMI enabled und der Wert  von  TRIG3  in
     GINTLK  gesichert.  Beim 400/800 hat diese Routine  zu-
     sätzlich die Aufgabe, die Portbausteine zu initialisie-
     ren.

$c018     49176          $e7b4     59316     NMIFIRST

     Jeder  NMI spingt indirekt über NMIVKT an diese Stelle.
     Hier wird getestet,  ob es sich um eine ANTIC-Programm-
     Unterbrechung handelt.  Wenn es eine ist, dann wird die
     ANTIC-Programm-Unterbrechung indirekt über DLIVKT ange-
     sprungen.  Ist  es keine  ANTIC-Programm-Unterbrechung,
     wird  nach dem Pushen des ACCU  der  RESET-Tastenstatus
     überprüft. Ist die RESET-Taste gedrückt, wird der Warm-
     startvektor  (JUMPTAB  + $24) angesprungen.  Ist  keine
     dieser  Abfragen erfolgreich,  so wird nach dem  Retten
     der  Register X und Y auf dem Stack  indirekt  VBLKIVKT
     aufgerufen.


$c02c     49196          $e6f3     59123     JMPIRQVKT

     Jeder INT und jede BREAK-Operation laufen indirekt über
     INTVKT  zu dieser Adresse.  Hier wird im Gegensatz  zum
     400/800  das  DECIMAL-Flag gelöscht,  was  gerade  beim
     Erstellen  von  Interruptroutinen gerne vergessen  wird
     und sonst beim 400/800 zu Fehlern führte.  Da beim INT-
     Zyklus  der 6202-CPU automatisch das  Processor-Status-
     Word  auf dem Stack abgelegt wird,  hat das D-Flag nach
     einem RTI wieder den ursprünglichen Wert.

     Nach Löschen des Flags wird die jeweilige Interruptrou-
     tine indirekt über VIMMEDIRQ angesprungen.


$c030     49200          $e70b     59147     SINRDYIRQ

     Diese  Routine übernimmt,  angestoßen von einem  Inter-
     rupt,  die Kontrolle der seriellen und noch nicht  exi-
     stenter  I/O-Einheiten.  Dabei  wird wie  beim  400/800
     getestet, ob ein Zeichen über den seriellen Port einge-
     geben worden ist.  In diesem Fall müßte Bit 5 vom IRQST
     beziehungsweise IRQST@ gesetzt sein und wird die Einle-
     seroutine indirekt über VSERIELIN angesprungen.

     Weiterhin wird geprüft,  ob die Verknüpfung  (NEUIOMASK
     AND  NEUIOPORT) einen Wert ungleich 0 ergibt,  also ein
     an dieser Stelle angeschlossenes Gerät einen  Interrupt
     erzeugt hat. Ist dies der Fall, so wird dessen Treiber-
     routine indirekt über NEUIOINIV angesprungen.

     Ist auch diese Abfrage erfolglos,  so wird, ähnlich wie
     beim 400/800,  der IRQSTATUS dahingehend abgefragt,  ob
     ein  Interrupt des POKEY anliegt,  der dem System  mit-
     teilt,  daß  das serielle Ausgaberegister zur  Aufnahme
     eines neuen Datenbytes bereit ist, oder sogar die Über-
     tragung  des letzten Zeichens beendet  ist.  Die  erste
     Bedingung wird durch Bit 4,  die zweite durch Bit 3 des
     Statusbytes  signalisiert.  Ist Bit 4 gesetzt,  so wird
     ein  indirekter Ansprung zu der in VSERREADY  stehenden
     Adresse vorgenommen,  bei Bit 3 ein Ansprung zu der  in
     VSERCLOSE stehenden Adresse. Da diese und die folgenden
     Abfragen  in einer Schleife  vorgenommen  werden,  wird
     der   jeweilig  gefundene  Vektor  (also  zum  Beispiel
     VSERREADY)  nach NEUIOPTR geladen und von  dieser,  nun
     festen  Adresse  aus der eigentliche  Treiber  indirekt
     angesprungen.

     Ist bis hierhin keine Interruptquelle gefunden, so kann
     es  unter  anderem auch der  TIMER1,  TIMER2  oder  der
     TIMER4 des POKEY gewesen sein, der den Interrupt auslö-
     ste.  Ist  eines dieser Geräte aktiv gefunden,  so wird
     der jeweilige Treiber (VTIMER1,  VTIMER2, VTIMER4) nach
     der oben beschriebenen Methode aufgerufen.

     Ist  es  auch kein Timerinterrupt,  kann es  noch  eine
     Tastenanforderung gewesen sein. Hierbei werden schon an
     dieser  Stelle zwei Möglichkeiten  unterschieden:  Jede
     normale Taste führt auf den Vektor VKEYBOARD,  die  er-
     wähnte  Ausnahme ist die BREAK-Taste.  Ist sie gedrückt
     und KBDISABLE auf 0 (also enabled),  wird indirekt nach
     VBREAKKEY  gesprungen.  Nur wenn bis hier keine  Inter-
     ruptquelle gefunden wurde, werden die IRQ- Bits des PIA
     abgefragt.  Ist Bit 7 von PORTACNTL=1, so wird VPRECEDE
     aufgerufen, bei Bit 7 von PORTBCNTL=1 VINTERRUPT.

     Hier kann nur noch ein softwaremäßiger BREAK  anliegen,
     der  im PSW der CPU signalisiert wird.  Ist das BRK-Bit
     gesetzt,  so wird die ab (VBREAK) liegende Routine auf-
     gerufen.

     Findet der Prozessor bis hier keine  geeignete,  aktive
     Interruptquelle, dann handelt es sich bei dieser Unter-
     brechungsanforderung  um einen technischen "Irrtum" und
     die Routine kehrt zum unterbrochenen Programm zurück.


$c092     49298          $e785     59269     BRKEVENT

     Diese Routine wird angesprungen,  wenn die  BREAK-Taste
     gedrückt    wird   und   das   Keyboard   enabled   ist
     (KEYDISABLE=0).  Es werden hier der  Attract-Mode,  das
     STARTSTOP-Flag,  CURSORINH  und  IRQST mit  IRQST@  ge-
     löscht. Damit ist das System unter normalen Bedingungen
     wieder arbeitsfähig.

     Der Vektor VBREAKKEY zeigt auf BRKEVENT.


$c0cf     49359          $xxxx     xxxxx     MASKTAB

     Diese Tabelle wird benutzt, um einzelne Bits ausblenden
     zu können. Sie enthält in aufsteigender Reihenfolge die
     Werte

     $80, $40, $04, $02, $01, $08, $10, $20 .


$c0d7     49367          $xxxx     xxxxx     VECTAB

     Diese  Tabelle steht in direkter Verbindung mit MASKTAB
     bei der Verarbeitung der einzelnen Interruptquellen  in
     SINRDYIRQ.  Sie gibt zu der jeweiligen Maske den Offset
     des Ansprungvektors zu $200. Sie enthält in aufsteigen-
     der Rehenfolge die Werte

     $36, $08, $14, $12, $10, $0e, $0c, $0a .

     Bespiel:  Es  soll Bit 1 (also das 2.  Bit!!!) getestet
     werden.

     Also wird ein Offsetregister (X) mit 3 geladen und  das
     entsprechende  Statusbyte mit MASKTAB,X  maskiert.  Ist
     das Ergebnis gleich Null, so ist der Interrupt gefunden
     und es muß die Treiberadresse geholt werden. Da X immer
     noch  den  Wert 3 hat,  wird einfach nach NEUIOPTR  der
     Wert  von $200,(VECTAB,X) geladen.  (VECTAB,X)  liefert
     den  Wert $12,  also wird der Vector aus der  absoluten
     Adresse  $212=$200+$12 geholt.  Genau das  gleiche  ge-
     schieht  mit  NEUIOPTR+1  und  $201,(VECTAB,X).  Danach
     enthält  NEUIOPTR  den Pointer des Handlers des  unter-
     brechenden Gerätes.


$c0df     49375          $xxxx     xxxxx     WAITFRRES

     Dieser  Programmteil  sperrt  sämtlich  Interrupts  und
     initiiert  eine Warteschleife (65536 *  Nichtstun),  um
     danach RESET anzuspringen.


$c0f0     49392          $e7d1     59345     SYSTEMVBL

     Diese  Interruptroutine wird bei jedem  Vertical-Blank-
     Interrupt  aufgerufen  und führt eine  große  Zahl  von
     Systemkontrollen und Justierungen durch.

     So  wird als erstes die Atari-Uhr TIMER  incrementiert.
     Diese  Uhr ist eigentlich keine im üblichen Sinn,  son-
     dern  sie  zählt  lediglich  in  3  Byte  (also  TIMER,
     TIMER+1,  TIMER+2) alle ankommenden Vertical Blank  Un-
     terbrechungen.  Da  bei unserem Fersehsystem alle  20ms
     (Milli-Sekunden:  1000ms=1s)  ein sogenanntes  Halbbild
     fertig  sein  muß,  damit der Elektronenstrahl  in  der
     Bildröhre  zur  linken oberen Ecke  zurücktransportiert
     werden kann, muß natürlich auch der Atari dafür sorgen,
     daß  er  zur selben Zeit  die  neuen  Bildinformationen
     generiert.  Unter  anderem hierfür wird der  Atari also
     alle 20ms unterbrochen,  damit er die SYSTEMVBL-Routine

     ausführen kann.

     Dieses  feste Zeitintervall kann nun auch für eine  Uhr
     benutzt  werden,  mit dem kleinen Unterschied,  daß sie
     nicht Sekunden, sondern 1/50 Sekunden angibt. Dabei ist
     TIMER+2   der  niedrigste  (also  schnellste)   Zähler,
     TIMER+1  ist  der  mittlere und TIMER  zählt  dann  die
     Überläufe  von TIMER+1.  Damit ergibt sich auch  gleich
     eine leichte Umrechnung von TIMER in die normale Zeit:

     UHR = INT(((TIMER+2)+256*((TIMER+1)+256*(TIMER))) / 50)

     UHR  enthält  dann die Anzahl der Sekunden  ab  System-
     start.

     Bei  jedem Incrementieren von TIMER+1 wird auch  ATRACT
     erhöht. Dieses Register hat die Aufgabe, die Farben und
     Helligkeiten des Bildschirms zu verringern,  wenn  eine
     bestimmte  Zeit  lang  kein Zeichen über  die  Tastatur
     eingegeben  wurde.  Hat  ATRACT den Wert  128  erreicht
     (also  nach  einem Zeitraum von  128*256/50/60  =  10,9
     Minuten),  so  werden  Farbe und Helligkeit  verändert.
     Dies geschieht dadurch,  daß ATRACTMSK von $fe auf  $f6
     zurückgesetzt  wird  und  COLREGSH  mit  dem  Wert  von
     TIMER+1  geladen wird.  Diese Änderungen haben  Einfluß
     auf  die folgende Reinitialisierung der Farbe und  Hel-
     ligkeit  von Vorder- und Hintergrund.  Es gilt beim Be-
     schreiben  der Farb- und Luminanzregister folgende  An-
     wendungsregel von ATRACTMSK und COLREGSH:

neue_Farbe+LUM = (alte_Farbe+LUM eor COLREGSH) and ATRACTMSK

     Durch den Zusammenhang von TIMER+1 und COLREGSH entste-
     hen  die  sich  selbsttätig ändernden  Farben  auf  dem
     Schirm im Attract-Mode.

     Weiterhin  werden an dieser Stelle die Schattenregister
     aufgefrischt,  beziehungsweise neue Werte der Schatten-
     register in die Hardwareregister übertragen.

     Im Einzelnen sind dies an dieser Stelle der Routine:

     von            nach           Erklärung
     -------------------------------------------------------

     LPENV          LPENV@         Lightpen vertikal
     LPENH          LPENH@         Lightpen horizontal
     DLPTR@         DLPTR          Display List Pointer
     DMACNTL@       DMACNTL        DMA Control-Register
     GTIACNTL@      GTIACNTL       Monitor Control-Register

     FINESCROL wird,  wenn es ungleich Null  ist,  decremen-
     tiert  und  der  Wert  ((8-FINESCROL)  modulo  8)  nach
     VSCROL  geschrieben,  um stetiges,  weiches Scrollen zu
     ermöglichen.

     Nun  wird CONSOLE mit 8 geladen,  um das  Auslesen  des
     Registers  und somit das Erkennen eventuell  gedrückter
     Sondertasten wie SELECT oder ähnlicher zu ermöglichen.

     Dann wird die oben unter ATRACT erwähnte Reinitialisie-
     rung  der Farb- und Luminanzregister  durchgeführt.  Es
     wird  der  Bereich COLPM0@ ..  COLBAK@  in den  Bereich
     COLPM0  ..  COLBAK kopiert,  wobei jeder Wert nach  der
     oben angegebenen Gleichung modifiziert wird.

     Dann  werden  CHARBASE mit CHARBASE@ und  CHARCNTL  mit
     CHARCNTL@ beschrieben. Der erste Wert liefert dem ANTIC
     die Highbyte-Adresse des gerade gültigen Zeichengenera-
     tors,  von denen der Atari 600XL/800XL gleich zwei ein-
     gebaut  hat,  die  jedoch auch über dieses Register  um
     andere erweitert werden können.  CHARBASE definiert, ob
     die Zeichen normal oder gedreht dargstellt werden  sol-
     len.

     Als  nächstes folgt ein Block zum Testen und Modifizie-
     ren der weiteren im System enthaltenen Timer  TIMCOUNT2
     bis TIMCOUNT5.

     Diese 5 Timer sind jeweils 16-Bit Zähler, die alle 20ms
     über  die  Routine DECTIMER decrementiert  werden.  Den
     Timern TIMCOUNT0 und TIMCOUNT1 sind die  Sprungvektoren
     TIMER1VKT sowie TIMER2VKT zugeordnet,  die angesprungen
     werden,  wenn  nach dem Decrementieren die Zähler  Null
     sind.  Für die drei übrigen Zähler TIMCOUNT3, TIMCOUNT4
     und TIMCOUNT5 werden beim Erreichen von Null die jewei-
     ligen Flags TIMER3SIG bis TIMER5SIG gesetzt.

     Der zeitliche Ablauf ist so,  daß zuerst TIMCOUNT1  de-
     crementiert und, bei Bedarf, TIMER1VKT aufgerufen wird.
     Dann erfolgen die weiter unten beschrieben Abfragen nur
     noch  dann,  wenn CRITICIO an dieser Programmstelle den
     Wert Null hat, also gelöscht ist.

     Ist dies der Fall, wird TIMCOUNT2  decrementiert.  Beim
     Erreichen  von  Null wird, über JMPTIMER2  und indirekt
     über TIMER2VKT, die entsprechende Routine aufgerufen.

     Danach werden die Timer 3 bis 5 behandelt.

     Als  weiterer  Block wird die Tastatur  behandelt.  Sie
     bietet  über einige Register dem  Anwender  vielseitige
     Möglichkeiten zum Blockieren, Kodeändern oder Maskieren
     einzelner Tasten.

     Die  eigentliche  Leseroutine testet  zuerst,  ob  eine
     Taste gedrückt ist. Wenn keine gedrückt ist, prüft sie,
     ob der Delay-Zähler KEYDELAY Null ist. Ist er es nicht,
     wird er decrementiert,  ansonsten wird mit der Bearbei-
     tung der Joysticks fortgefahren.

     Die  Variable KEYDELAY verhindert,  daß man zu  schnell
     eingeben  kann (Tastenentprellung),  da der Rechner nur
     eine  neue Tasteneingabe akzeptiert,  wenn  vorher  die
     letzte Taste sozusagen 'abgeklungen' ist.  Sie wird mit
     dem Wert 3 initialisiert.

     Wenn  eine neue Taste gedrückt wird,  beginnt  der, mit
     KREPDELY   (Standardwert   40)  initialisierte,  Zähler
     SRTIMER rückwärts zu zählen,  wenn diese  entsprechende
     Taste  gedrückt bleibt.  Hat er bei einem Interrupt den
     Wert  Null  erreicht  und ist diese  Taste  immer  noch
     gedrückt und KBDISBLE=0,  d.h.  enabled, so beginnt ein
     Autorepeat  der Tastatur.  Um die  Geschwindigkeit  des
     Autorepeat festlegen zu können,  wird ebenfalls SRTIMER
     benutzt.  So  lange,  wie  diese  eine  Taste  gedrückt
     bleibt,  wird  SRTIMER mit dem Wert von KEYREP  geladen
     und  bei  jedem Vertical-Blank-Interrupt rückwärts  ge-
     zählt zu Null.  Ist er Null,  so wird der vom POKEY zur
     Verfügung gestellte Tastencode in Matrixform aus  Regi-
     ster  KBCODE, beziehungsweise  seinem  Schattenregister
     KBCODE@ ausgelesen.

     KEYREP  gibt  somit die Repeat-Geschwindigkeit  an  und
     wird mit 5 initialisiert,  während die in KREPDELY lie-
     gende Initialisierung von SRTIMER die Zeit angibt,  bis
     die Repeatfunktion überhaupt einsetzt.

     Da dieses Betriebssystem,  wie oben schon erwähnt,  ei-
     gentlich das 1200XL - Betriebssystem ist,  geschehen an
     dieser  Stelle nun einige für den 600XL/800XL unsinnige
     Dinge:

     Es  wird der gelesene Tastencode auf  einige  bestimmte
     Sonderzeichen  hin überprüft.  Der 1200XL  verfügt  zum
     Beispiel über vier freiprogrammierbare Funktionstasten,
     F1  bis F4.  Merkwürdigerweise überprüft der Atari hier
     den Tastaturkode auf CNTL & F1,  CNTL & F2,  CNTL & F4,
     CNTL  & 1  sowie einen offensichtlich in der Matrix der
     Tastatur  nicht  existenten Kode  im  Normalmodus,  mit
     Shift und Control. Entspricht der gelesene Tastaturkode
     keinem der zwölf Werte,  so wird dieser Kode in KBCODE@
     abgelegt, sonst nicht. Interessant und kein Druckfehler
     ist, daß CNTL & F3 an dieser Stelle nicht geprüft wird.

     Nach  der Tastaturabfrage überprüft der Atari die  Joy-
     stickports.

     Diese Routine beginnt bei $c201,  und kann angesprungen
     werden,  wenn  die vorhergehenden Abfragen  alle  nicht
     benötigt  werden sollten.  Es ist jedoch darauf zu ach-
     ten,  daß der normale Vertical Blank Interrupt in diese
     Routinenteile hineinläuft. Das eben gesagte gilt ebenso
     für die Triggerprüfung wie für den Paddle-Check.

     Da  der 600XL/800XL im Gegensatz zum 400/800  nur  noch
     über zwei Joystickports verfügt, einige wenige Software
     jedoch  auf Port 3 und/oder Port 4 zugreift,  hat  sich
     Atari aus Kompatibilitätsgründen dazu entschlossen, die
     fehlenden Ports zu simulieren.

     Es  werden  zuerst die oberen 4 Bit des PORT A des  PIA
     gelesen  und  gleichzeitig als Wert für  JOYSTICK1  und
     JOYSTICK3  verwertet;  beim 400/800 wurde der Wert  für
     JOYSTICK3 aus PORT B 'gezogen'. Danach werden die unte-
     ren  vier Bit von PORT A nach JOYSTICK0  und  JOYSTICK2
     transportiert.

     Nun  werden  (ab $c219) die Triggereingänge  überprüft.
     Auch hier werden die Daten von Port 1 und Port 2  eben-
     falls für jeweils Port 3 und Port 4 in der Form verwer-
     tet, daß sie aus TRIGGER0 und TRIGGER1 gelesen und nach
     TRIGGER0@ und TRIGGER2@, beziehungsweise TRIGGER1@  und
     TRIGGER3@ geschrieben werden.

     Ähnliches  gilt für das bei $c22b beginnende Lesen  der
     Paddle-Eingänge.  Die POKEY-Register PADDLE0 .. PADDLE3
     werden nach PADDLE0@ ..  PADDLE3@, beziehungsweise nach
     PADDLE4@  ..  PADDLE7@ kopiert und  die  Paddle-Trigger
     gelesen. Dabei gilt folgende Zuordnung:


     Aus  JOYSTICK0     bit  2  ==:    PTRIG0, PTRIG4
          JOYSTICK0     bit  3  ==:    PTRIG1, PTRIG5
          JOYSTICK1     bit  2  ==:    PTRIG2, PTRIG6
          JOYSTICK1     bit  3  ==:    PTRIG3, PTRIG7

     An  dieser  Stelle ist die erste  Vertikal-Blank-Unter-
     brechungsroutine  abgeschlossen und es folgt ein  indi-
     rekter Sprung über VBLKDVKT zur sogenannten  'verzöger-
     ten' V-Blankroutine.  Sie ist vom Benutzer frei zu ver-
     wenden.  Es  ist  allgemein bei der  Verwendung  dieses
     Vektors  darauf  zu achten,  daß  die  Interruptroutine
     nicht  zu lang wird,  da sonst der eigentliche  Rechen-
     prozeß  (zum Beispiel BASIC) unter Umständen nicht mehr
     zum Zug kommt.


$c25d     49757          $e8ef     59631     JMPTIMER1

     Es wird ein indirekter Sprung mit VTIMER1 durchgeführt.


$c260     49760          $e8f2     59634     JMPTIMER2

     Es wird ein indirekter Sprung mit VTIMER2 durchgeführt.


$c263     49763          $e8f5     59637     DECTIMER


     Die  Routine DECTIMER decrementiert  einen  angegebenen
     Timer,  wenn  er  nicht Null ist.  Ist der  betreffende
     Timer  entweder vor dem Decrement Null  oder  hinterher
     ungleich Null, so liefert DECTIMER im Accu den Wert $ff
     zurück,  sonst  den Wert $00.  Durch das Laden kann das
     aufrufende Programm den Wert des Zero-Flags  verwerten.
     Ist Z=1, so ist der Timer gerade eben zu Null geworden,
     sonst ist Z=0.

     DECTIMER  erwartet  die Nummer des zu behandelnden  Ti-
     mers,  multipliziert mit 2,  im X-Register beim Aufruf;
     also zum Beispiel in X den Wert $06 für TIMCOUNT3.


$c280     49792          $e912     59666     SETVBLVKT

     Diese Routine wird allgemein verwendet,  um  Interrupt-

     vektoren oder Timerwerte zu initialisieren. Dazu müssen
     an SETVBLVKT folgende Werte übergeben werden:


Wert                                   Übergeben in Register
------------------------------------------------------------

     High-Byte der zu speichernden Adresse
      beziehungsweise des zu speichernden Wertes        X

     Low -Byte der zu speichernden Adresse
      beziehungsweise des zu speichernden Wertes        Y

     Registernummer                                     A



Vektornummer kann sein:       0    ==:  VIMMEDIRQ
                              1    ==:  TIMCOUNT1
                              2    ==:  TIMCOUNT2
                              3    ==:  TIMCOUNT3
                              4    ==:  TIMCOUNT4
                              5    ==:  TIMCOUNT5
                              6    ==:  VBLKIVKT
                              7    ==:  VBLKDVKT

     Die Verktornummer kann auch größer als 7 (oder unsigned
     7  bit) werden,  dann ist jedoch darauf zu achten,  daß
     die  Routine  nur 16bit-Worte und die  nur  ab  geraden
     Adressen ablegen kann.

     Vor  dem  Modifizieren der Vektoren wird  ein  Vertical
     Blank  Interrupt abgewartet,  damit die Vektoren  nicht
     gerade 'halb geändert' sind, wenn ein Interrupt auf sie
     zugreifen will.


$c298     49816          $e93e     59710     EXITVBL

     Diese Routine macht nichts weiter,  als Y-Register,  X-
     Register  und  Accu in dieser Reihenfolge vom Stack  zu

     holen  und  mit RTI diesen  (beliebigen)  Interrupt  zu
     beenden.


$c29e     49822          f11b      61723     RESETWARM

     RESETWARM  kann direkt oder über JUMPTAB+$24 aufgerufen
     werden.  Zu Beginn der Warmstartroutine wird  getestet,
     ob  nicht vielleicht doch gravierende Einflüsse auf das
     System eingewirkt haben, die einen Kaltstart mit Initi-
     alisierung sämtlicher Register nötig machen würden.  Zu
     diesen Einflüssen gehört zum Beispiel das  Herausziehen
     oder  Wiedereinstecken  eines  ROM-Moduls in  den  ROM-
     Schacht.  Da beim 600XL/800XL im Gegensatz zum  400/800
     nicht  mehr  automatisch das Gerät beim Wechseln  eines
     ROM-Moduls ausgeschaltet wird,  ist hier also solch ein
     Test notwendig.

     Dazu wird der Inhalt von TRIGGER3 des POKEY gelesen und
     mit  dem  Inhalt des für  diesen  Zweck  eingerichteten
     ROMFLAG   verglichen.   Welchen  Zweck  das  Lesen  des
     TRIGGER3 hat, verrät uns ein Blick in das offene Gerät:
     Die  Leitung,  die beim Einstecken des ROM-Modules  das
     eventuell  an gleicher Stelle liegende RAM  abschaltet,
     ist mit eben dieser Triggerleitung verbunden, die wegen
     Weglassens der Joystickports 3 und 4 frei geworden ist.
     Wenn nun seit dem letzten Reset entweder ein ROM einge-
     steckt oder entfernt worden ist,  stimmen TRIGGER3  und
     ROMFLAG  nicht  überein  und der Atari  forciert  einen
     RESETCOLD-Aufruf.

     Sind  TRIGGER3 und ROMFLAG noch identisch,  so kann  es
     zum Beispiel sein,  daß zwar wirklich ein ROM-Modul  im
     Schacht steckt,  es jedoch ein anderes als beim letzten
     Reset ist.  Für diesen Fall werden die letzten Adressen
     des  ROMs getestet,  genauer:  Durch Aufruf von NEWCART
     wird  die Checksumme von $bff0 bis $c0ef  gebildet  und
     mit der Checksumme des letzten Aufrufs verglichen.  Ist
     die Checksumme nicht in Ordnung,  so wird ein Kaltstart
     durchgeführt.

     Es  gibt  noch  eine dritte Möglichkeit,  bei  der  ein
     Warmstart zu einem Kaltstart werden kann:  Durch Setzen
     von COLDSTART auf einen Wert ungleich Null, wird dieses
     erreicht.

     Hat keine der genannten Quellen bis hierhin einen Kalt-
     start forciert,  wird RESET+$02 mit einem Accu-Wert von
     $ff aufgerufen,  das heißt,  die eigentliche Warmstart-
     prozedur durchgeführt.


$c2b8     49848          $f125     61733     RESETCOLD

     Zu  dieser  Routine kann direkt oder  über  JUMPTAB+$27
     gesprungen werden. Der Weg über JUMPTAB ist sinnvoller,
     da  dann  Programmkompatibilität zu  der  400/800-Serie
     besteht.

     Zu  Beginn  des Kaltstarts wird,  analog zu  RESETWARM,
     geprüft,  ob es sich wirklich um einen solchen handelt,
     oder  aber seit dem letzten Kalt- oder Warmstart  keine
     gravierenden Einflüsse auf das System eingewirkt haben,
     so daß der Rechner mit einem Warmstart auskommen  könn-
     te.

     Dazu  wird als erstes geprüft,  ob drei  Adressen,  die
     beim Kaltstart auf ganz bestimmte Werte gesetzt werden,
     diese  immer noch enthalten.  Die Adressen und ihre In-
     halte sind:

     POWUPBYT1      muß für Warmstart enhalten    $5c
     POWUPBYT2      muß für Warmstart enhalten    $93
     POWUPBYT3      muß für Warmstart enhalten    $25

     Was  diese Werte bedeuten,  ist recht unklar,  es  wird
     jedoch davon ausgegangen,  daß ein neu  eingeschalteter
     Speicherbaustein  (RAM) bestimmt nicht diese drei Werte
     an eben diesen Adressen enthalten  kann.  Normalerweise
     sind  dynamische Speicherzellen nach dem Power-up bank-
     weise entweder $00 oder $FF, bedingt durch ihren physi-
     kalischen Aufbau.

     Wenn eine dieser drei Adressen nicht den  Warmstartwert
     enthält,  wird WARMFLAG mit $00 geladen, was der danach
     aufgerufenen  Routine  RESET mitteilt,  daß es sich  um
     einen Kaltstart handelt.

     Sind die drei Adressen in Ordnung,  wird RESETWARM auf-
     gerufen.


$c2d6     49878          $f126     61734     RESET
$c2d8

     In diesem Programmteil werden,  je nachdem,  ob es sich
     um einen Kalt- oder Warmstart handelt,  mehr oder weni-
     ger Register und Bausteine initialisiert.  Die  eigent-
     liche  Entscheidung darüber,  ob es sich um einen Warm-
     oder Kaltstart handelt, wird nicht mehr hier getroffen,
     sondern  in RESETWARM beziehungsweise  RESETCOLD.  Wird
     RESET  aufgerufen,  wird das WARMFLAG auf $00  gesetzt,
     was der weiteren Routine einen Kaltstart  signalisiert.
     Wird RESET+$02 aufgerufen, so wird in WARMFLAG der Wert
     des übergebenen Accus abgelegt.  Ist dieser Wert = $ff,
     so signalisiert WARMFLAG einen Warmstart.

     Danach  beginnen  die  Resetoperationen.   Zuerst  wird
     DOSVKT  auf den Wert TESTROMEN gesetzt.  Wird beim Ein-
     schalten der Maschine oder einem anderen Kaltstart  die
     OPTION-Taste  gedrückt,  wird  das im  600XL/800XL  be-
     findliche BASIC ausgeschaltet. Ist keine Diskette ange-
     schlossen  oder antwortet sie nur nicht  richtig,  wird
     der  Atari nach einiger Zeit versuchen,   etwas anderes
     sinnvolles  zu  tun als zu booten.  Da er  jedoch  kein
     BASIC zur Verfügung hat und beim 600XL/800XL kein Moni-
     tor mehr besteht (der 400/800 ging in einen Echo-Modus,
     wenn er weder ROM noch Bootgerät fand),  wird er diesen
     DOSVKT anspringen,  um nicht abzustürzen.  Über  diesen
     Vektor  wird er dann bei TESTROMEN das eingebaute Test-
     ROM einschalten und anspringen.

     Bevor  er jedoch dies alles tun kann,  hat er noch eine
     ganze Reihe anderer Dinge zu tun.

     Zuerst  wird über CARTGO getestet,  ob im  Schacht  ein
     ROM-Modul steckt. Ist dies der Fall, und ist dieses ROM
     ausführbar (siehe CARTGO), so kehrt diese Routine nicht
     zurück, sondern springt das ROM indirekt über $bffe an.

     Als  nächstes wird über NEWCART die Checksumme über die
     letzten  Bytes  des eventuellen ROMs  gebildet  und  in
     ROMFLAG abgelegt.

     Weiter  wird dort geprüft,  ob das BASIC  einzuschalten
     ist und die Ports werden initialisiert.

     Danach  beginnt  der Atari mit dem RAM-Test,  falls  es
     sich um einen Kaltstart handelt.  Dabei werden die ent-
     sprechenden Variablen von SYSINIT gesetzt.

     Ist  dies  geschehen,  oder handelt es  sich  um  einen
     Warmstart,  werden die Variablenbereiche $200  ..  $3ed
     und  $00  ..   $7f  mit  $00  initialisiert.  Nun  wird
     X64KBFLAG  auf den Wert gesetzt,  den Bit 1 von PORT  B
     besitzt  und die Variablen POWUPBYT1,  -2 und -3 werden
     mit den Werten $5c,  $93 und $25 geladen. Weiter werden
     der rechte und linke Rand des Textfensters in RIGMARGIN
     und LFTMARGIN eingestellt auf die Werte 39  beziehungs-
     weise 2.

     Als  nächstes kommt eine Eigenschaft des 600XL/800XL  -
     Betriebssystems  zu  Tage,  über die der 400/800  nicht
     verfügt.  In  den  USA ist bekanntermaßen  ein  anderes
     Farbsystem verfügbar als bei uns.  Abgesehen von unter-
     schiedlicher Bildqualität ist die Signalzusammensetzung
     und  die Bildfrequenz nicht mit 50Hz (Hertz,  1Hz  =  1
     komplette  Schwingung  pro Sekunde),  sondern mit  60Hz
     vorgegeben.  Da jedoch aus dieser Freuenz über den Ver-
     tical Blank Interrupt ein Zeitnormal gezogen wird,  ist
     dieser  Unterschied wichtig zu beachten.  Bei den alten
     Systemen wurde das so gehandhabt,  daß einfach  überall
     die Zeitkonstanten verändert wurden,  die auf den Zeit-
     takt  zurückgriffen.  Da aber den Entwicklern der neuen
     Geräte  aufgegangen ist,  daß 'Old-Germany'  inzwischen
     auch  über  einen recht großen  Computermarkt  verfügt,

     haben sie die Zeitkonstanten parametrisiert, das heißt,
     die  Zeitkonstanten  sind  alle über  Tabellen  zu  er-
     reichen.

     Um  nun jedoch zu unterscheiden,  ob es sich bei diesem
     Gerät um unser PAL- oder das NTSC-System handelt,  wird
     ein Register des GTIA gelesen,  und zwar NTSCPAL.  Sind
     die Bits 1 bis 3 dieses Registers alle Null, so handelt
     es sich um einen PAL-Baustein, sonst um einen NTSC-Typ.
     Je  nach Farbsystem werden nun die  folgenden  Register
     unterschiedlich geladen:

     Register  NTSC           PAL       Erklärung
------------------------------------------------------------

     NTSCPAL@  $00            $01       Flag  zur  weiteren
                                        Verwendung

     KEYRPDELY $30            $28       Initialisierungswert
                                        für   SRTIMER,  wenn
                                        Taste  neu  gedrückt
                                        worden ist

     KEYREP    $06            $05       Initialisierungswert
                                        für  SRTIMER,   wenn
                                        Taste  gedrückt  ist
                                        und  SRTIMER  wenig-
                                        stens  einmal  abge-
                                        laufen ist.

     Um die gesamte Interrupt-, Timer- und Vektormaschinerie
     zum Laufen zu bringen werden die Adressen $200 ..  $225
     (DLIVKT bis VBLKDVKT) initialisiert mit den Werten, die
     ab  Adresse  INIT200 stehen.  Direkt danach werden  die
     Handlervektoren ab HATABS mit den vorgegebenen Adressen
     ab INIT31A initialisiert.

     Aus  den Speichertestroutinen ist noch ein Flag zu ver-
     arbeiten: Als Hilfsregister wurde Adresse $0001 mit dem
     Wert $00 oder einem anderen für das Ergebnis des  Spei-
     chertests verwendet.

     Ist das Ergebnis nicht Null, so wird über GOMEMTEST das
     Test-ROM eingeschaltet,  die Variablen CHARCNTL mit $02
     und  CHARBASE@ mit $e0 (für Zeichengenerator ab  $e000)
     initialisiert und direkt der Speichertest aufgerufen.

     Hat $0001 den Wert Null, wird IOCB0 bestückt. Es werden
     das  Kommando OPEN,  die  Namenspufferadresse  OPENSCST
     sowie das IOCBAUX1 mit READ + WRITE (s. Erklärung IOCB-
     Verwendung) progammiert.  In Worten heißt das also, daß
     IOCB0 für einen Schreib/Lese-Open für den Screen-Editor
     vorbereitet  wird.  Dann  wird versucht,  über  CIOMAIN
     diesen Open auszuführen.  Da es dabei eigentlich  keine
     Probleme geben dürfte,  wird bei einem eventuellen Feh-
     ler  unmittelbar ohne zweiten Versuch RESETCOLD  ausge-
     führt.

     Ist bis hierhin alles glatt gegangen,  wird geprüft, ob
     von  Kassette gebootet werden soll (Drücken der  START-
     Taste), oder eine bootbare Diskette existiert. Wenn ja,
     wird über BOOT geladen,  sonst wird,  falls TMPRAMSIZ =
     $01  ist  und bit 2 von Adresse $bffd (im ROM)  gesetzt
     ist, indirekt über COLDCART das ROM angesprungen.

     Ist  auch dieses nicht der Fall,  wird  der  inzwischen
     eventuell  geänderte Vektor DOSVKT indirekt als Sprung-
     vektor benutzt.


$c3bd     50109          $xxxx     xxxxx     GOMEMTEST

     Hier  wird Bit 0 von PORT B auf 0 gesetzt.  Damit  wird
     das  im  Bereich von $5000 bis  $57ff  befindliche  RAM
     ausgeschaltet und das im Bereich $d000 bis $d7ff hinter
     den  I/O-Bausteinen  versteckt liegende  Test-ROM  wird
     über  die Memory Management Unit (MMU) auf den  Bereich
     $5000  bis $57ff kopiert.  Dieses scheinbar  schwierige
     Kopieren  wird einfach dadurch erreicht,  daß  die  MMU
     unter  diesen Bedingungen bei einer Adresse %y101  xxxx
     xxxx  xxxx (x=egal) das y-Bit auf 1 setzt.  Mit anderen
     Worten  addiert die MMU im Falle des Ansprechens  einer
     Adresse $5xxx den Wert $8000 und erhält $dxxx.

     Hier  sitzt nun also das Test-ROM,  das (wenigstens)  2
     Einsprünge   enthält:    Die   Adressen   TESTROM   und
     TESTROM+$03. Über TESTROM gelangt man in das Menue, das
     man  auch  beim Kaltstart mit  gedrückter  OPTION-Taste
     erhält. TESTROM+$03 geht direkt zum Memory-Test.

     Nach  dem Umschalten wird nun also einfach  TESTROM+$03
     angesprungen.


$c431     50225          $xxxx     xxxxx     COLDCARTC

     Es wird ein indirekter Sprung nach (COLDCART) unternom-
     men.


$c434     50228          $xxxx     xxxxx     DOSVKTC


     Es  wird ein indirekter Sprung nach (DOSVKT)  unternom-
     men.


$c437     50231          $xxxx     xxxxx     INITCARTC


     Es wird ein indirekter Sprung nach (INITCART) unternom-
     men.


$c43a     50234          $xxxx     xxxxx     CLCUNDRTS

     Wie der Name der Routine schon vermuten läßt, wird hier
     nur  das  Carry-Flag  gelöscht und  Return  ausgeführt.
     Diese  (scheinbar unsinnige) Routine kann  leicht  auch
     von  Anwenderprogrammen  zum Signalisieren von  OK-Mel-
     dungen bei Prozedurausgängen benutzt werden.

$c43c     50236          $f0e3     61667     INIT31A

     Diese Tabelle enthält die Werte, mit denen die Handler-
     Ansprungtabelle ab HATABS initialisiert wird.


$c44b     50251          $f10d     61709     DERRMSG

     Hier liegt die Meldung "BOOT ERROR (CR)"


$c459     50265          $e480     58496     INIT200

     An dieser Stelle liegen die Daten, die von RESET in die
     Interrupt- und   Timervektoren, beziehungsweise   Timer
     selbst, geladen werden.


$c47f     50303          $xxxx     xxxxx     CARTGO

     Diese  Routine testet,  ob ein Cartridge gesteckt  ist.
     Wenn  diese  Bedingung erfüllt ist und die  im  ROM  an
     Adresse  $bffc  und $bffd stehende Adresse größer  oder
     gleich dem Wert $8000 ist, wobei es eine $x000 - Adres-
     se  sein muß,  so wird ein Sprung indirekt  über  $bffe
     ausgeführt.

     Wenn dies nicht der Fall ist, werden über IOPORTINI die
     verschiedenen Ports initialisiert und geprüft,  was mit
     Bit  1 von PORT B zu geschehen hat.  Dieses Bit ist ein
     Ausgang  und  gibt an,  ob das eingebaute  BASIC  aktiv
     werden  kann oder nicht.  Das BASIC ist  eingeschaltet,
     wenn  Bit 1 des PORT B den Wert Null  hat.  Es  bekommt
     diesen  Wert,  wenn X64KBFLAG Null ist und die  OPTION-
     Taste  nicht gedrückt ist.  Letzteres erfährt man  über
     Bit  2  von CONSOLE:  Ist das Bit gesetzt,  so ist  die
     Taste  nicht gedrückt und umgekehrt.  Nach  Setzen, be-
     ziehungsweise  Rücksetzen, dieses Bits ist die  Routine
     beendet.  Da  sie jedoch keine  eigenständige  Prozedur
     ist, läuft sie in die  nächstfolgende  Speichertestrou-

     tine  GETRAMHI hinein und kehrt von dort aus zum Aufru-
     fer zurück.


$c4b7     50359          $f258     62040     GETRAMHI

     Diese Routine liefert in Register TMPRAMSIZ die  Anzahl
     der, dem  Benutzer zur Verfügung stehenden, vollen 256-
     Byte-Blöcke an RAM (Programmspeicher).  Dabei wird, bei
     Adresse $2800 mit dem Test beginnend,  jedes erste Byte
     eines  solchen Blockes gelesen und das  Einerkomplement
     dieses  Wertes an eben diese Stelle  zurückgeschrieben.
     Stimmt  danach der Speicherzelleninhalt nicht  mit  dem
     'gemerkten' Einerkomplement überein, so handelt es sich
     hierbei  offensichtlich nicht um eine RAM-Zelle und das
     Programm terminiert.  Stimmen die beiden Werte überein,
     wird  der  Originalwert  wieder  zurückgeschrieben  und
     wieder gelesen.

     Ließ sich die Speicherstelle wieder umprogrammieren, so
     handelt  es sich hierbei mit ziemlicher  Sicherheit  um
     eine  RAM-Zelle,  ansonsten wird das Programm ebenfalls
     abgebrochen.  Da zum Testen die Adressen  TMPRAMSIZ-$01
     und TMPRAMSIZ als Pointer auf die zu testende Speicher-
     stelle dienen, liefert also TMPRAMSIZ als High-Wert des
     Pointers das High-Byte der ersten nicht-RAM-Adresse und
     somit die Anzahl der zur Verfügung stehenden, darunter-
     liegenden Blöcke.


$c4d7     50391          $xxxx     xxxxx     NEWCART

     Hier  wird die Checksumme über alle Bytes von $bff0 bis
     $c0ef gebildet und mit CARTCKSUM verglichen.  Sind  die
     beiden Werte gleich,  kehrt die CPU mit gesetztem Zero-
     Flag zurück,  ansonsten wird der neue Wert in CARTCKSUM
     abgelegt und das Zero-Flag vor dem Rücksprung gelöscht.

$c4e8     50406          $f281     62081     IOPORTINI

     In diesem Programmteil werden alle bekannten  I/O-Ports
     und  Bausteine  initialisiert.  Genauer werden die  Be-
     reiche

     $d000 ... $d0ff               (GTIA)
     $d200 ... $d2ff               (POKEY)
     $d300                         (PORT)
     $d302 ... $d3ff               (PORT)
     $d400 ... $d4ff               (ANTIC)

     gesamt auf $00 gesetzt.  Danach wird PORT B auf Ausgang
     geschaltet  und  alle Bits dieses Ports auf 1  gesetzt.
     Danach werden die Statusworte von PORT A und B gelesen,
     um eventuell anliegende Interrupts zu löschen.

     Sind die Ports initialisiert,  wird der POKEY  dahinge-
     hend  gesetzt,  daß er seine Sende- und  Empfängertakte
     von Audiokanal 4 erhält.  Weiter werden die Audiokanal-
     register AUDCNTL3 und -4 auf den Wert $a0 und AUDIOCNTL
     auf  den Wert $28 gesetzt.  Abschließend wird ein $ff -
     Byte an das serielle Senderegister geschickt.


$c543     50499          $f294     62100     SYSINIT

     Diese von RESET aufgerufene Prozedur hat die hauptsäch-
     liche Aufgabe,  sämtliche I/O-Bausteine zu initialisie-
     ren.  Dazu setzt sie als erstes nach Löschen des BREAK-
     Enable-Bits   in  IRQST@  den  BRKEYVKT  auf   BRKEVENT
     ($c092). Danach wird RAMSIZE mit dem Wert von TMPRAMSIZ
     geladen und MEMTOP ebenfalls entsprechend  gesetzt,  um
     danach  die Untergrenze des Benutzer-RAMs in MEMLO  mit
     dem Wert $700 festzulegen.

     Danach  werden  in dieser Reihenfolge die  Initialisie-
     rungsroutinen des Editors,  des Screens, des Keyboards,
     des  Printers und der Kassette über die  entsprechenden
     Vektoren ab EDITORVKT aufgerufen.

     Hiernach  fehlen noch die ersten Aufrufe  von  CIOINIT,
     SIOINIT,  und  NMIENABLE  um die Interruptstruktur  des
     Systems  komplett  zu  nutzen  sowie  ein  Aufruf   von
     DISKINIT.

     Kehrt  die  CPU nach diesen Routinen  zurück,  so  wird
     NEUIOINIV   auf  NEUIOREQ  ($c97c)  gesetzt  und   über
     NEUINITC endlich NEUINIT aufgerufen.

     Nach diesen Hardwarebearbeitungen wird vor dem Rückkeh-
     ren aus der Routine noch STARTTST auf $01 gesetzt, wenn
     die START-Taste gedrückt ist,  ansonst wird STARTTST zu
     $00. Dieser Wert wird später von BOOT benutzt.


$c599     50585          $f2cf     62159     BOOT

     Zu Beginn dieser Boot-Routine wird geprüft,  ob es sich
     um einen Boot-Ansprung bei einem Warmstart handelt. Ist
     dies  der Fall (WARMFLAG ungleich $00) und außerdem ein
     vernünftiges Disk Operating System geladen (DOSAKTIV  =
     1), so wird ein indirekter Sprung nach (DOSINITV) voll-
     zogen.

     Ist  es zwar ein Warmstart,  aber ist kein DOS geladen,
     so  wird einfach die  Bootroutinenbearbeitung  abgebro-
     chen.

     Der  letzte  Fall  ist der eigentlich  interessante  in
     dieser Prozedur:

     Zuerst wird versucht, von der Diskettenstation Nummer 1
     eine  Statusmeldung zu erhalten.  Dies  geschieht  nach
     Setzen des STATUSCMDs in DSKCMD, Setzen der Nummer 1 in
     DSKUNIT  und  Aufruf von DISKINTERF  über  JUMPTAB+$03.
     Kehrt  diese Routine mit gelöschtem Negativ-Bit in  der
     CPU  zurück,  so war der Status in Ordnung und es  kann
     von  Diskette gebootet werden.  Wenn nicht,  kehrt BOOT
     mit gesetztem Negativ-Bit zurück.

     Ist  die Statusabfrage positiv verlaufen,  wird  Sektor
     Nummer 1 ab Adresse $0400 geladen. Dazu wird die Block-
     nummer $0001 nach DSKAUX1 (Low-Byte)und DSKAUX2  (High-
     Byte)  geladen sowie der Wert $0400 nach DSKBUFFER,  um
     danach den Block mit GETSECTOR zu lesen. GETSECTOR kann
     sowohl  von  Kassette als auch von Diskette  lesen  und
     liefert  im  Falle eines falsch  oder  nicht  gelesenen
     Blockes einen negativen Wert zurück.

     In diesem Fall wird die Meldung "BOOT ERROR" ausgegeben
     und  beim  Laden von Cassette das  Booten  abgebrochen,
     ansonst ein erneuter Leseversuch gestartet.

     Vor der Beschreibung der weiteren Vorgänge empfiehlt es
     sich, zwei artverwandte Begriffe zu klären:

     Ein  SEKTOR ist ein auf der Diskette eingetragener Satz
     von Daten.  Beim Atari existieren pro Diskette 40  kon-
     zentrische Spuren,  die jeweils 18 Sektoren mit jeweils
     128  Byte Daten enthalten.  Die Tracks werden innerhalb
     der Floppy-Disk-Station von $00 bis $27 durchnumeriert,
     die  Sektoren auf jedem Sektor verwirrender  Weise  von
     $01 bis $12.  Warum die unterschiedliche Zählweise ein-
     geführt worden ist,  ist unklar, sie wurde jedoch nicht
     von  Atari festgelegt,  sondern von dem Hersteller  des
     Floppy-Disk-Controllers innerhalb der Diskettenstation.


     Im  Gegensatz  zum physikalischen Sektor ist ein  BLOCK
     eine logische Zusammenfassung von Daten. Sie kann theo-
     retisch beliebig viele Datenbytes enthalten.  Der  Ein-
     fachheit  halber  enthält ein Block beim  Atari  ebenso
     viele Datenbytes wie ein Sektor,  er wird nur nicht pro
     Track  gezählt,  sondern durchgehend von $01 bis $02d0.
     Für  den Atari-Anwender ist normalerweise nur  die  Be-
     trachtung  der Blöcke von Interesse,  da die Disketten-
     station selbst eigene Intelligenz besitzt und somit dem
     Benutzer keine Gelegenheit gibt,  an die Unterscheidung
     von Sektoren und Tracks heranzukommen.  Trotzdem sollte
     der  Zusammenhang  einmal geklärt werden,  da  bei  der
     Benutzung von Erweiterungen an den Atari (CP/M-Systemen

     zum Beispiel) diese Trennung einmal interessant  werden
     kann.  Spätestens  bei der Verwendung von Diskettensta-
     tionen  mit doppelter Schreibdichte enthält  ein  Block
     nur  halb  so viele Daten wie ein Sektor,  so  daß  das
     Betriebssystem  hier  einige Daten-"Schaufelarbeit"  zu
     erledigen hat. Aber dazu später mehr.

     Ist der erste Block richtig gelesen,  werden die ersten
     vier Byte nach DSKFLAG, DSKSECCNT und DSKLDADR kopiert.
     Sie  geben die Sektorlänge,  die Anzahl der zu lesenden
     Blöcke und die Startadresse, ab der die gelesenen Daten
     abgelegt  werden sollen,  an.  Die nächsten  zwei  Byte
     geben  die Startadresse des Bootfiles an und werden  in
     DOSINITV abgelegt.


$c5c9     50633          $f301     62209     BLOCK1


     (Dieses  Label steht hier deshalb recht verloren inmit-
     ten  der Routine, weil, von CASBOOT aus, hier hineinge-
     sprungen wird!)

     Danach wird der gesamte gelesene Block ab der angegebe-
     nen Bootadresse abgelegt,  DSKSECCNT decrementiert und,
     falls  noch ein Block zu lesen ist,  dieser an den  je-
     weils folgenden Adressen abgelegt. Tritt ein Lesefehler
     auf,  so wird beim Booten von Cassette sofort die Bear-
     beitung abgebrochen,  beim Diskettenboot wird versucht,
     das gesamte Bootfile ein weiteres Mal einzulesen.

     Sind alle Blöcke richtig eingelesen und wurde von  Cas-
     sette  gebootet,  so  wird noch  ein  END_OF_FILE-Block
     eingelesen, der jedoch nicht weiter verwendet wird.

     Ansonst  wird  über  BLOAD der Anfang  der  Bootroutine
     aufgerufen.  Dieser  Anfang liegt im sechsten Byte  des
     ersten gelesenen Blocks.

     Bei einem Diskettenprogramm kann hier getestet  werden,
     ob wirklich alles richtig geladen worden ist.

     Wenn alles in Ordnung ist, muß dieser Test mit gelösch-
     tem  Carry-Flag zurückkehren,  damit nicht noch  einmal
     versucht wird, zu booten.

     Ist   das  Booten  erfolgreich  verlaufen,   wird  über
     DOSINITC das Diskettenbetriebssystem initialisiert  und
     danach DOSAKTIV auf 1 gesetzt.


$c637     50743          $f36c     62316     BLOAD

     Es  wird der Wert von DSKLDADR+6 nach RAMTSTPTR geladen
     und  danach indirekt über RAMTSTPTR die gebootete  Rou-
     tine angesprungen.


$c649     50761          $f37e     62334     DOSINITC

     Es wird ein indirekter Sprung über DOSINITV ausgeführt.


$c64c     50764          $f381     62337     DSKRDERR

     die  CPU-Register X  und Y  werden  mit  der  Low-, be-
     ziehungsweise High-Adresse der Fehlermeldung DERR gela-
     den.  Dieser  Programmteil kehrt nicht alleine  zurück,
     sondern läuft in die folgende Routine hinein.


$c650     50768          $f385     62341     PUTLINE

     Diese  Routine erwartet im X-Register der CPU den  Low-
     und im Y-Register den High-Wert der Adresse, ab der ein
     auszudruckender  Text im Speicher steht.  Die Textzeile
     muß  mit dem Atari-spezifischen NEWLINE($9b) enden  und
     darf  nicht länger als 255 Zeichen  sein.  Die  Routine
     zerstört  eventuelle Daten in IOCB0,  da es diesen  be-
     nutzt  (normale Screen-Bearbeitung).  Außerdem darf sie
     bei Betriebssystemänderungen nur zusammen mit  DSKRDERR
     verschoben werden (s. dort)!

$c667     50791          $f39d     62365     GETBLOCK

     Beim Booten von Cassette oder Diskette wird diese  Rou-
     tine  für jeden Block einmal aufgerufen.  Wird von Cas-
     sette gelesen, so hat CASSTART einen Wert ungleich Null
     und  es wird über JUMPTAB+$2a die  Prozedur  CASREADBLK
     aufgerufen.

     Handelt es sich um ein Disketten-Lesen,  so wird DSKCMD
     mit  dem  Wert READCMD ($52)  geladen,  DSKUNIT  auf  1
     gesetzt und über JUMPTAB+$03 die SIO-Routine DISKINTERF
     aufgerufen.


$c67c     50812          $f3b2               CASBOOT

     Wenn  WARMFLAG  auf  Warmstart  steht  und  Bit  1  von
     DOSAKTIV  Eins  ist, wird  über  CASINITC  die  Routine
     CASINIT  aufgerufen;  anderenfalls wird im Falle  eines
     Warmstarts zum aufrufenden Programm zurückgekehrt.

     Handelt  es sich dagegen um einen Kaltstart,  kann  ge-
     bootet  werden,  wenn STARTTST mit einem Wert  ungleich
     Null  signalisiert,  daß beim Eintreffen des Kaltstarts
     (also  zum Beispiel beim Einschalten des  Gerätes)  die
     START-Taste gedrückt war.

     Ist  oder war sie es nicht,  kehrt CASBOOT zum Aufrufer
     zurück.

     Ansonst  wird  ein OPEN auf  die  Cassette  ausgeführt,
     wobei  der Timeout auf 'lang' gestellt wird.  Dazu exi-
     stiert  das Register GAPTYPE.  Wird GAPTYPE  auf  einen
     Wert zwischen Null und 127 gesetzt,  wird das Lesen von
     Cassette nach recht kurzer Zeit unterbrochen, wenn kein
     neuer Block zu lesen ist.  Bei einem größeren Wert (als
     signed-Wert: negativ!) wird wesentlich länger gewartet.
     Dies hat den Sinn,  den Anfang eines Files auf Cassette
     abzuwarten.

     Der  eigentliche OPEN wird mit auf 1 gesetztem CASSTART
     über JUMPTAB+$2d und CASOPENIN ausgeführt, wobei danach
     gleich  BLOCK1 aufgerufen wird.  Ist der Block  richtig
     gelesen,  so  wird von BLOCK1 DOSAKTIV mit dem  Wert  2
     zurückkehren.  Ist dies der Fall,  wird als letztes der
     Inhalt von DOSINITV nach CASINITV geladen.


$c6ae     50862          $f3e1     62433     CASINITC

     Es wird ein indirekter Sprung über CASINITV ausgeführt.


$c6b1     50865          $edea     60906     DISKINIT

     DSKTIMOUT  wird mit $a0 initialisiert und die Sektoren-
     länge  der  Diskette in DSKSECLEN auf $0080  (also  128
     Byte/Sektor) gesetzt.  Hier beginnt die unter BOOT  be-
     schriebene  Unterscheidung  zwischen Block  und  Sektor
     interessant zu werden!



$c6c1     50881          $edf0     60912     DISKINTERF

     Diese Prozedur erledigt sämtlich Initialisierungsaufga-
     ben  zum Lesen oder Schreiben eines Sektors von Disket-
     te, beziehungsweise deren Formatierung oder einfach nur
     zum Lesen des Status' der Diskettenstation. Dazu werden
     die Variablen DSKDEVICE, DSKSTATUS, beim Status-Komman-
     do  DSKBUFFER,  DSKTIMOUT sowie DSKBYTCNT mit den  ent-
     sprechenden  Werten initialisert.  Diese Werte  richten
     sich nach der Art des Kommandos.  Als solche stehen dem
     Anwender folgende zu Verfügung:

     Name           Code in DSKCMD      Erklärung
     --------------------------------------------

     GET SECTOR       $52  ('R')
          Liest   Sektor   Nummer  DSKAUX1  mit  der   Länge
          DSKBYTCNT  von Diskette Nummer DSKDEVICE  ein  und
          schreibt ihn ab DSKBUFFER in den Speicher.

     PUT SECTOR      $50  ('P')
          Schreibt  Sektor  Nummer  DSKAUX1  mit  der  Länge
          DSKBYTCNT  auf  Diskette Nummer DSKDEVICE mit  dem
          Speicherinhalt ab DSKBUFFER voll. Im Gegensatz zum
          400/800 kann der 600XL/800XL dieses Kommando  auch
          über  das hier beschriebene Diskinterface  verwer-
          ten.  Bei den alten Geräten mußte 'getrickst' wer-
          den, um das Kommando anwenden zu können.

     WRITE SECTOR    $57  ('W')
          Dieses Kommando führt zuerst die gleichen Operati-
          onen  durch wie PUT SECTOR,  vollzieht jedoch nach
          dem  Schreiben  noch ein Verify  des  betreffenden
          Sektors.

     STATUS REQUEST   $53  ('S')
          Hier  wird eine formatierte Statusangabe  von  der
          Diskette erwartet.  Dieses Kommando setzt sich den
          Wert  von DSKBUFFER selbst auf DEVICSTAT,  es  muß
          (und kann) also kein Pufferbereich für die Status-
          meldung übergeben werden.

          Das  Kommando liefert,  abgesehen von der  Message
          DISK_READ_OK,   vier   Byte   in   DEVICSTAT   bis
          DEVICSTAT+3 zurück:

          DEVICSTAT      Kommandostatus
          Bit  0         ist  gesetzt nach einem  ungültigen
                         Kommando.
          Bit  1         ist  gesetzt nach dem  Lesen  eines
                         defekten Sektors
          Bit  2         ist  gesetzt nach einem erfolglosen
                         Schreibversuch über PUT SECTOR.

          Bit  3         gibt  im gesetzten Zustand an,  daß
                         die Diskette schreibgeschützt ist.
          Bit  4         schließlich  ist gesetzt,  wenn das
                         Laufwerk prinzipiell  eingeschaltet
                         ist  und sich nach dem  Status-Kom-
                         mando zurückgemeldet hat.

          DEVICSTAT+1    Hardwarestatus
                         Dieses  Byte ist eine von der  Dis-
                         kette  gesandte Kopie  des  Status-
                         bytes  des FD1771  Floppy-Disc-Con-
                         trollers,  der die gesamte Schreib-
                         Leseverarbeitung innerhalb der Dis-
                         kettenstation übernimmt. Obwohl der
                         1771  als recht veralteter FDC  ei-
                         nige  wesentlich anders  gestaltete
                         Hardwareeigenschaften  besitzt  als
                         die  neuen  Prozessoren,  sind  die
                         Statusworte  bei den jeweiligen Ty-
                         pen  gleich geblieben,  so  daß  es
                         auch  bei Verwendung eines  anderen
                         FDC  dieser Intelligenzstufe  keine
                         Schwierigkeiten  bei der  Interpre-
                         tation  dieses Bytes aus Disketten-
                         stationen anderer Hersteller  geben
                         dürfte.  Nur  bei reinen Selbstbau-
                         projekten,  die FDCs verwenden, die
                         wesentlich  mehr Parameter zum  Ar-
                         beiten  benötigen  als die  1771  /
                         1797- Typen,  kann es hier  Schwie-
                         rigkeiten geben.

          DEVICSTAT+2    Timeout-Wert
                         Dieser  Wert gibt an,  nach wieviel
                         Sekunden   eine   Timeout-Kondition
                         erkannt werden soll (s.  allgemeine
                         Beschreibung des SIO).

          DEVICSTAT+3    dieses Byte ist noch ungenutzt.

     FORMAT  DISK       $21    ('!')
          Dieses  Kommando  erwartet als Parameter  nur  den
          Kommandocode, die DSKUNIT sowie einen freien Spei-
          cherbereich von 128 Byte ab DSKBUFFER.  Bei diesem
          Kommando wird der Timeout erheblich höher gesetzt,
          da  das  Formatieren  einer  Diskette  bekanntlich
          länger als 7 Sekunden dauert.

          Ist die Formatierung beendet, werden an den Benut-
          zer Informationen über den Zustand seiner Diskette
          zurückgeliefert. In DSKBYTCNT steht die Anzahl der
          defekten, also nach dem Formatieren nicht einwand-
          frei zu lesenden Sektoren, und ab DSKBUFFER stehen
          die Nummern der fehlerhaften Sektoren,  falls vor-
          handen. Als letzter Eintrag in diesem Puffer steht
          $ffff.

          Diese Eigenschaft des Atari, halbdefekte Disketten
          trotzdem weiter zu benutzen, also nur die defekten
          Sektoren kenntlich zu machen und den Rest zu bear-
          beiten, ist bei der Verwendung von Disketten durch
          den  starken  Preisverfall in den  letzten  Jahren
          völlig aus der Mode gekommen. Das soll keine nega-
          tive Kritik an dieser Methode sein; eher im Gegen-
          teil,  denn die Tatsache,  daß Atari hier nicht an
          Progammidee gespart hat,  ehrt sie und erleichtert
          außerdem  den softwaremäßigen Anschluß einer Hard-
          disk.  Wenn  bei einem solchen Medium  einmal  ein
          Sektor (von bei einer 10MegaByte-Platte ca 82.000)
          defekt  ist,  wird nicht gleich die gesamte Platte
          weggeworfen,  sondern  nur dieser eine Sektor  ge-
          kennzeichnet.

     Die  von  DISKINTERF  zu  initialisierenden  Werte  für
     DSKTIMOUT  und DSKBYTCNT werden der Routine jeweils  in
     DSKTIMCON  beziehungsweise  DSKSECLEN  übergeben.   Die
     Pufferadresse DSKBUFFER,  das Kommando DSKCMD sowie die
     Sektornummer (für Schreiben und Lesen) in DSKAUX1 (Low)
     und DSKAUX2 (High) müssen vor dem Aufruf von DISKINTERF
     in die Register eingetragen werden.

     Als  allgemeiner  Rückgabewert  ist im  Y-Register  ein
     Statuswort enthalten,  das im Fehlerfalle negativ  ist.
     Das N-Flag der CPU ist bei der Rückkehr aus der Routine
     entsprechend dem Ergebnis gesetzt.


$c748     51016               $ee6d 61037    PUTADRESS

     DSKBUFFER wird nach BUFFERADR kopiert.


$c753     51027               $xxxx xxxxx    LOADER

     Diese Routine wird in Verbindung mit weiteren Lade- und
     Verwaltungsroutinen nicht für den momentanen Gerätepark
     der Firma Atari verwendet,  sondern bietet dem Anwender
     die Möglichkeit, sich selbst Erweiterungen zu der Hand-
     lertabelle  HATABS  zu fertigen und diese neuen  Geräte
     ebenfalls über IOCBs zu betreiben.  Bekanntermaßen sind
     die zeichenorientierten Devices  Editor,  Screen,  Key-
     board,  Lineprinter  sowie Cassette am leichtesten über
     HATABS anzusprechen,  es ist jedoch kein weiterer Platz
     in  dieser  Tabelle vorhanden  für  eventuelle  weitere
     Geräte. Dieser Makel der alten 400/800-Serie wurde hier
     mit  Hilfe von Routinen wie zum Beispiel  LINK,  UNLINK
     und  anderen abgeholfen.  Der Leser möge entschuldigen,
     wenn wir aufgrund fehlender, zu diesen Ports gehörender
     Hardware keinerlei Schwächen oder eventuelle  Laufzeit-
     fehler dieser Routinen hier feststellen können.

     Zu  Beginn dieser Routine werden RUNADR,  HIUSED  sowie
     ZHIUSED gelöscht.

     Danch werden über GETBYTEA zwei Byte gelesen, wobei das
     erste  Byte  in HIBYTELD und das zweite Byte in  SECLEN
     abgelegt wird. Generell gilt für diese Routine, daß sie
     mit  gesetztem Carry und einem Y-Wert von  $9c  zurück-
     kehrt,  wenn  GETBYTEA über das Carryflag einen  Fehler
     meldet.

     Wenn HIBYTELD ungleich $0b ist, wird die Routine aufge-

     rufen,  deren Adresse bei NEUVEKTOR + 2*HIBYTELD steht.
     Ist nach dieser Routine RECLEN gleich LCOUNT, so werden
     wieder  zwei Byte nach HIBYTELD und SECLEN geladen  und
     das  Spiel geht von vorne los.  Ansonsten wird nur noch
     ein  Zeichen  über GETBYTEA gelesen und  indirekt  über
     RUNADR die dort angegebene Routine  aufgerufen,  danach
     LCOUNT incrementiert und, wenn ungleich Null, zurückge-
     sprungen  zu der Stelle,  an der RECLEN mit LCOUNT ver-
     glichen wurde.  Ist LCOUNT hier jedoch Null,  so termi-
     niert die Routine.

     War HIBYTELD gleich $0b,  so wird GETBYTEA zweimal auf-
     gerufen  und  die beiden gelesenen Zeichen  als  RUNADR
     beziehungsweise RUNADR+1 - Inhalte abgelegt,  also  die
     komplette  Runadresse definiert.  Ist RECLEN an  dieser
     Stelle  gleich Null,  so wird die RUNADR gleich  wieder
     gelöscht,  ist RECLEN = $01,  bleibt die RUNADR ungeän-
     dert  und  in den übrigen Fällen wird zu dem  Wert  von
     RUNADR der von LODADRESS addiert.  In jedem Fall  kehrt
     jedoch  die Routine mit gelöschtem Carry-Flag und einem
     Y-Wert =$01 zurück zu dem aufrufenden Programm.


$c7dd     51165          $xxxx xxxxx         GETBYTEAC

     Es   wird  ein  indirekter  Sprung   über   (LODGBYTEA)
     ausgeführt.


$c7e0     51168          $xxxx xxxxx         RUNADRC

     Es wird ein indirekter Sprung über (RUNADR) ausgeführt.



$c7e3     51171          $xxxx xxxxx         PUTCHAR

     Dieses  Unterprogramm benötigt zwei Parameter:  ein In-
     formationsbyte im Accu sowie eines in LCOUNT.

     Hat  LCOUNT  den Wert 0,  so wird das Byte im  Accu  in

     NEWLDTMP1 und NEWADRLOD abgelegt, bei einem LCOUNT-Wert
     von  1 in NEWLDTMP1+1 sowie NEWADRLOD+1.  Im  letzteren
     Fall  werden noch einige Berechnungen  ausgeführt,  die
     sich im einzelnen nach dem Wert von HIBYTELD richten:

     HIBYTEL        Ausgeführte 16-Bit-Berechnung

     $00
     oder
     $0a            NEWADRLOD := NEWLDTMP1 + LODADRESS

     sonst          NEWADRLOD := NEWLDTMP1 + LODZLOADA

     Danach  wird  ein 16bit großes  Hilfsregister  auf  dem
     Stack eingerichtet, das den Wert

                    HIUSEDLOD + RECLEN - 2

     enthält. Die danach ablaufenden Vergleiche richten sich
     wieder nach dem Wert von HIBYTELD:

     HIBYTELD       16bit-Vergleich   Oper. wenn erfolgreich

     $00
     oder
     $0a            HILF  = HIUSEDLOD   HIUSEDLOD := HILF

     sonst          HILF  = LODZHIUSE   LODZHIUSE := HILF


     Ist  Hilf  allgemein größer als MEMTOP,  so  kehrt  die
     Routine mit einem Y-Wert von $9D und gesetztem Negativ-
     Flag in der CPU zu der vorletzten Routine in der Proze-
     durhierarchie,  also nicht zu dem eigentlichen Aufrufer
     zurück.

     Hat LCOUNT weder den Wert 0 noch 1, so wird einfach das
     im  Accu  übergebene  Byte in einer durch  den  Pointer
     LOADERTMP  spezifizierten Adresse  abgelegt.  LOADERTMP
     wird berechnet durch LOADERTMP := NEWADRLOD + LCOUNT-2.
$c87b     51323          $xxxx xxxxx         ADD28E


     Es  wird folgende Rechnung mit dem im Accu  übergebenen
     Wert durchgeführt:

     LOADERTMP := NEWADRLOD + Accu

     (LOADERTMP) := (LOADERTMP) + LODADRESS  *** 16bit-Oper.


     Die  nachstehende  Grafik soll dies  etwas  veranschau-
     lichen:


          NEWADRLOD H     NEWADRLOD L

      +                      ACCU

          ---------------------------

          LOADERTMP H     LOADERTMP L





                                                  größer

               BYTE H := BYTE H + LODADRESS H

               BYTE L := BYTE L + LODADRESS L

                                                  kleiner



$c8a0     51360          $xxxx xxxxx         ADD28EWRD

     Hat  HIBYTELD einen Wert größer oder gleich 4,  so wird
     der  Wert  von X gleich dem  Low-Byte  von  LOADADRESS,
     sonst  gleich dem Low-Byte von LODZLOADA.  Im Accu wird
     ein Byte übergeben, das folgendermaßen verwendet wird:



     LOADERTMP := NEWADRLOD + Accu

     (LOADERTMP)  :=  (LOADERTMP) + X    ***  8bit-Operation


          NEWADRLOD H     NEWADRLOD L

      +                      ACCU

          ---------------------------

          LOADERTMP H     LOADERTMP L





                                                  größer

                         BYTE := BYTE + X

                                                  kleiner



$c8c3     51395          $xxxx xxxxx         ADD28EGET

     Wieder wird im Accu ein Byte übergeben,  das den Offset
     auf  eine  Adresse darstellt.  Hat LCOUNT  beim  Aufruf
     dieser  Routine einen geradzahligen Wert,  so wird  die
     erste Berechnung ausgeführt, ansonsten die zweite.


     LOADERTMP := NEWADRLOD + Accu     *** bei LCOUNT gerade

     HIBYTELD := (LOADERTMP)              *** 8bit-Operation

          NEWADRLOD H     NEWADRLOD L

      +                      ACCU

          ---------------------------

          LOADERTMP H     LOADERTMP L


                                                  größer

       HIBYTELD := BYTE              BYTE

                                                  kleiner


                     *** bei LCOUNT ungerade

     HILF := LODADRESS + Accu + 256 * HIBYTELD


     (LOADERTMP) := HILF H               ***  8bit-Operation


     LODADRESS H     LODADRESS L

 +     HIBYTELD         ACCU

     ---------------------------

        HILF H         HILF L


                                                  größer

       BYTE := HILF H                BYTE

                                                  kleiner

$c8f2     51442          $xxxx xxxxx         NEUVEKTOR

Diese   Tabelle  beinhaltet  Ansprungpunkte  für   indirekte
Aufrufe aus LOADER. Die Ansprungvektoren sind im Einzelnen:

          PUTCHAR
          PUTCHAR
          ADD28EWRD
          ADD28EWRD
          ADD28EWRD
          ADD28EWRD
          ADD28E
          ADD28E


$c90a     51466          $xxxx xxxxx         SWITCHROM

     Diese  Routine schaltet das TestROM ein und startet  es
     über JUMPTAB+$33 direkt in $5000 .  Das Einschalten des
     ROMs  geschieht über Rücksezten der PORT B7  - Leitung.
     Für die ordentliche Rückkehr ins Betriebssystem wird an
     dieser  Stelle gleich COLDSTART auf den Wert $ff  (also
     Kaltstart) gesetzt.


$c91a     51482          $xxxx xxxxx         NEUINIT

     *** ACHTUNG *** Diese Routine darf unter keinen Umstän-
     den  während eines Programmablaufs  aufgerufen  werden;
     sie  führt auf jeden Fall zum unkontrollierten  Absturz
     der Maschine!

     Sie  ist vorgesehen für das Austesten später zu entwik-
     kelnder Hardware und ruft unter bestimmten, im normalen
     Betrieb  leicht  zu erreichenden  Bedingungen  Routinen
     auf,  die  im  Bereich des Mathe-ROMs  abgelegt  werden
     sollen.  Da  aber im Moment an dieser Stelle eben  noch
     das Mathe-ROM liegt,  springt die Routine hier 'in  die
     Wüste'.

     Trotzdem sei hier kurz die eigentlich gewünschte  Funk-
     tion erläutert:

     Es werden,  beginnend mit bit 0, nacheinander sämtliche
     Bits in der Adresse NEUPORT gesetzt und nachgesehen, ob
     in  $d803 der Wert $80 und in $d80b der Wert $91 steht.
     Ist dies der Fall,  wird die Routine ab $d819  aufgeru-
     fen, wo später wahrscheinlich einmal für das Gerät, das
     sich eben gemeldet hat, ein IOCB und eine Handlereintra
     gung  eingerichtet  werden sollen.  Ist die Routine  ab
     $d819  beendet  oder ist eines der beiden  Bytes  nicht
     richtig gesetzt, wird die gleiche Abfrage mit dem näch-
     sten Bit durchgeführt.

     Zum Abschluß wird NEUPORT auf Null gesetzt.


$c941     51521          $e959               SIOINTERF

     Diese  Routine bildet den Einsprungpunkt für  die  SIO-
     Bearbeitung über Vektor JUMPTAB+$09.

     Für uns ist im Moment eigentlich nur von Interesse, daß
     zuerst CRITICIO eingeschaltet wird, um von hier aus die
     Routine SIO aufzurufen und nach Beendigung der Bearbei-
     tung  das  Y-Register  mit dem Wert  von  DSKSTATUS  zu
     laden, nachdem CRITICIO wieder gelöscht wurde.

     Für  den Fall,  daß beim Eintritt in diese Routine  das
     Register  NEUVORHDN nicht Null ist,  werden  allerdings
     noch  einige weitere Operationen  durchgeführt.  Zuerst
     wird  das als Parameter an GETLOWEST zu übergebende  X-
     Register  mit  $08  geladen und  GETLOWEST  aufgerufen.
     Kehrt die Routine mit gelöschtem Zero-Flag  zurück,  so
     wird  X  für die weitere Verwendung gerettet und  $d805
     aufgerufen (Mathe-ROM!).  Ist das Carry-Flag als Status
     aus $d805 gelöscht, wird die eben beschriebene Prozedur
     mit decrementiertem X-Register  wiederholt,  ansonsten,
     oder wenn GETLOWEST mit Z=1 zurückkommt,  wird SIO auf-
     gerufen und weiter verfahren wie ohne diesen Exkurs.

$c97c     51580          $xxxx xxxxx         NEUIOREQ

     Dieser Programmteil wird angesprochen,  falls von einem
     zukünftigen I/O-Device ein Interrupt kommen sollte. Für
     diesen  Fall wird der Wert von NEUIODREQ auf dem  Stack
     gerettet,  um  die Nummer der Position des  niedrigsten
     gesetzten  Bits  des im Accu übergebenen Bytes  nun  in
     NEUIODREQ und gleichfalls in NEUPORT abzulegen.  Danach
     wird  kurzerhand die (noch) im Mathe-ROM liegende  Rou-
     tine  $d808  aufgerufen,  um nach deren Beendigung  die
     alten  Werte in NEUPORT und NEUIODREQ  wiederherzustel-
     len.  Danach wird,  wie beim I/O-Interrupt üblich,  das
     gerettete  X- und  A- Register gepopt und mit  RTI  zum
     unterbrochenen Programm zurückgekehrt.



$c99f     51615          $xxxx xxxxx         NEUDEVC1

     Es  wird  Y  mit dem Wert  $01  geladen  und  CHECKNEWP
     aufgerufen.


$c9a4     51620          $xxxx xxxxx         NEUDEVC3

     Es  wird  Y  mit  dem Wert $03  geladen  und  CHECKNEWP
     aufgerufen.


$c9a9     51625          $xxxx xxxxx         NEUDEVC5

     Es  wird  Y  mit dem Wert  $05  geladen  und  CHECKNEWP
     aufgerufen.


$c9ae     51630          $xxxx xxxxx         NEUDEVC7

     Es  wird  Y  mit  dem Wert $07  geladen  und  CHECKNEWP
     aufgerufen.

$c9b3     51635          $xxxx xxxxx         NEUDEVC9

     Es  wird  Y  mit dem Wert  $09  geladen  und  CHECKNEWP
     aufgerufen.


$c9b8     51640          $xxxx xxxxx         NEUDEVCB

     Es  wird  Y  mit  dem Wert $0b  geladen  und  CHECKNEWP
     aufgerufen.


$c9bd     51645          $xxxx xxxxx         GETLOWEST

     Diese  Routine erwartet in X einen Wert zwischen 1  und
     8.  Je nach der Größe dieser Zahl wird mit dem 2**(8-X)
     ten Bit des Wertes von NEUVORHDN begonnen zu testen, ob
     es 1 ist. Mit anderen Worten wird mit dem niederwertig-
     sten Bit begonnen, wenn X den Wert 8 hat und bricht die
     Routine ab, wenn X den Wert 0 hat. Wurde ein beliebiges
     Bit in NEUVORHDN gefunden,  das den Wert 1 hat, so wird
     in  NEUIODREQ und NEUPORT genau nur dieses Bit gesetzt.
     Beim   Anschluß   entsprechender   Hardware   an    den
     600XL/800XL  hat  diese Routine dann den  pragmatischen
     Wert, für jedes, in NEUVORHDN gesetzte Bit einmal einen
     Request an das Peripheriegerät zu senden. Diese Routine
     wird von SIOINTERF aufgerufen,  wenn NEUVORHDN ungleich
     Null ist, ansonsten wird sie von CHECKNEWP benutzt.


$c9d8     51672          $xxxx xxxxx         NEUPORTERR

     Auch diese Routine findet bei dem momentanen  Hardware-
     angebot  keine Verwendung.  Sie erhält in Y einen Wert,
     der  als Offset verwendet wird.  Nachdem der  Wert  von
     $d80d+Y  und  der  von $d80e+Y auf dem  Stack  abgelegt
     wurden,  wird  der Accu mit dem Wert von Adresse  $024c
     und  das  X-Register  mit dem  von  $024d  geladen,  um
     danach in Y den Immediatwert $92 zurückzugeben.

$c9ea     51690          $xxxx xxxxx         CHECKNEWP

     An diese Routine werden zwei Werte übergeben:  einer im
     Accu  und  ein zweiter in X.  Sie werden in  $024c  und
     $024d  abgelegt und der momentane Zustand von  CRITICIO
     gesichert,  um  dieses  Flag danach auf den Wert  1  zu
     setzen.

     Anschließend wird in einer Schleife GETLOWEST mit einem
     X-Wert von $08 aufgerufen. Kehrt GETLOWEST mit gelösch-
     tem Zero-Flag zurück,  so wird NEUPORTERR aufgerufen  .
     Kehrt  diese Routine wiedrum mit  gesetztem  Carry-Flag
     zurück,  wird  der Wert im Accu nach $024c geladen (was
     unsinnig  erscheint,  da NEUPORTERR diesen Wert  gerade
     erst geladen hat!?!).

     Kehrt GETLOWEST mit gesetztem Z-Flag zurück,  das heißt
     ist kein weiterer I/O-Port vorhanden, so wird Y mit $82
     geladen.

     Unabhängig  davon,  welchen Wert bis hierhin  GETLOWEST
     geliefert   hat,   werden  NEUIODREQ  und  gleichzeitig
     NEUPORT auf Null gesetzt.  Danach wird in CRITICIO  der
     Anfangswert  zurückgeladen,  der Accu mit dem Wert  aus
     $024c  geladen,  der  Wert in Y nach $024d  gelegt  und
     entsprechend  dieses Wertes die CPU-Flags  gesetzt  und
     zum Aufrufer zurückgekehrt.

     Ist  das  Carry-Flag nach der Bearbeitung des  Treibers
     Null, wird einfach die Schleife ein weiteres Mal durch-
     laufen,  diesmal  jedoch mit (von GETLOWEST)  decremen-
     tierten X-Wert.


$ca2f     51759          $xxxx xxxxx         BITMASK

     Sie  wird zum Ausblenden von Bits benötigt und  enthält
     die Werte $80, $40, $20, $10, $08, $04, $02, $01 .

$ca37     51767          $xxxx xxxxx         PREPLINK

     Diese Prozedur ist zuständig für das Öffnen eines IOCB-
     Kanals,  der für die neue,  spätere Hardware zur Verfü-
     gung  gestellt wird.  Sie ruft INITLOAD,  LINK+$06  und
     DEVS2PL3+$17  auf  und  springt  dann  mitten  in   die
     CIOMAIN-Routine,  um  das  OPEN-Statement  zu  beenden.
     Tritt während dieser ganzen Bearbeitung ein Fehler auf,
     so  wird ebenfalls mitten in CIOMAIN  gesprungen,  aber
     diesmal mit einem Y-Wert von $82,  der CIOMAIN signali-
     sieren  soll,  daß  das angeforderte Device nicht  exi-
     stiert.


$ca65     51813          $xxxx xxxxx         TABELLEN


$cb64     52068          $xxxx xxxxx         CHECKFF

     Diese  Routine bildet die Checksumme (mit Carry!)  über
     das  Byte,  auf das ZCHAIN zeigt und die  17  folgenden
     Byte. Hat die Checksumme den Wert $ff, so kehrt CHECKFF
     mit  gesetztem  Zero-Flag zurück,  sonst ist  das  Flag
     gelöscht.  Diese  Routine testet also den Inhalt  eines
     Handlereintrages,  der über LINK beziehungsweise UNLINK
     verwaltet wird.


$cb73     52083          $xxxx xxxxx         FREI0

     Ab  hier  bis $cbff sind 141 freie Byte,  die für  Pro-
     grammerweiterungen verwendet werden  können.  Aufpassen
     beim Systemstart mit der Checksummenbildung!  Am besten
     läßt  man einfach einmal die Checksummenroutinen durch-
     laufen und notiert die berechneten Werte für jeden  der
     Blöcke (s. CHECKROM1 und CHECKROM2).


$cc00     52224          $xxxx xxxxx         INTERCHAR

     An dieser Stelle beginnt der zweite interne Zeichensatz

     von  Atari.  Er wird eingeschaltet durch das Setzen von
     $CC  in CHARBASE@ und ermöglicht dann die  Verarbeitung
     von  Sonderzeichen wie 'äöü#' und vielen  anderen,  an-
     stelle der Grafiksymbole.


$d000     53248          $d000     53248     IO-Baugruppen


$e000     57344          $e000     57344     STANDCHAR

     Dies ist der Standard-Zeichensatz, der durch das Setzen
     von $e0 in CHARBASE@ eingeschaltet wird.  Er beinhaltet
     Grafiksymbole.


$e400     58368          $e400     58368     EDITORVKT

$e410     58384          $e410     58384     SCREENVKT

$e420     58400          $e420     58400     KBVKT

$e430     58416          $e430     58416     LPTVKT

$e440     58432          $e440     58432     HANDLERTB

     Diese  Adressen  bilden eine  Handlertabelle,  die  für
     jedes Device folgende Einträge enthält:

     OPEN      - Routinenadresse
     CLOSE     - Routinenadresse
     GET       - Routinenadresse
     PUT       - Routinenadresse
     STATUS    - Routinenadresse
     SPECIAL   - Routinenadresse
     einen     Sprungbefehl zur jeweiligen POWERON - Initia-
               lisierung
     ein       Hilfsbyte

Device    OPEN CLOS GET  PUT  STAT SPEC JMP  POWR HILF

EDITOR    ef93 f22d f249 f2af f21d f22c  4c  ef6e  00

SCREEN    ef8d f22d f17f f1a3 f21d f9ae  4c  ef6e  00

KB        f21d f21d f2fc f22c f21d f22c  4c  ef6e  00

LPT       fec1 ff01 fec0 feca fea2 fec0  4c  fe99  00

CASS      fce5 fdce fd79 fdb3 fdcb fce4  4c  fcdb  00


     Die  Tabelle  enthält  jeweils  die  entsprechende  An-
     sprungadresse in hexadezimaler Form.



$e450     58368          $e450     58448     JUMPTAB

     Diese Sprungtabelle ist die einzige  Möglichkeit,  Pro-
     gramme  zu  entwerfen,  die sowohl auf dem 400/800  als
     auch auf dem 600XL/800XL laufen können.  Sie beinhaltet
     alle  wesentlichen Einsprungpunkte  von  Routinen,  die
     nicht  über indirekte Vektoren laufen können oder  sol-
     len.  In  diesem Buch finden Sie einige Referenzen  auf
     eben diese Tabelle, wobei alle Ansprünge der Übersicht-
     lichkeit  halber  auf JUMPTAB+$xx und nicht direkt  auf
     die Sprungadresse bezogen sind.

     Jeder Tabelleneintrag enthält genau einen Sprungbefehl.


$e450     58368          $e450     58368     JUMPTAB+$00

     Sprung zu DISKINIT


$e453     58371          $e453     58371     JUMPTAB+$03

     Sprung zu DISKINTERF

$e456     58374          $e456     58374     JUMPTAB+$06

     Sprung zu CIOMAIN


$e459     58377          $e459     58377     JUMPTAB+$09

     Sprung zu SIOINTERF


$e45c     58380          $e45c     58380     JUMPTAB+$0c

     Sprung zu SETVBLVKT


$e45f     58383          $e45f     58383     JUMPTAB+$0f

     Sprung zu SYSTEMVBL


$e462     58386          $e462     58386     JUMPTAB+$12

     Sprung zu EXITVBL


$e465     58389          $e465     58389     JUMPTAB+$15

     Sprung zu SIOINIT


$e468     58392          $e468     58392     JUMPTAB+$18

     Sprung zu SENDENABL


$e46b     58395          $e46b     58395     JUMPTAB+$1b

     Sprung zu NMIENABLE

$e46e     58398          $e46e     58398     JUMPTAB+$1e

     Sprung zu CIOINIT


$e471     58401          $xxxx xxxxx         JUMPTAB+$21

     Sprung zu TESTROMEN


$e474     58404          $e474     58404     JUMPTAB+$24

     Sprung zu RESETWARM


$e477     58407          $e477     58407     JUMPTAB+$27

     Sprung zu RESETCOLD


$e47a     58410          $e47a     58410     JUMPTAB+$2a

     Sprung zu CASREADBL


$e47d     58413          $e47d     58413     JUMPTAB+$2d

     Sprung zu CASOPENIN


$e480     58416          $xxxx xxxxx         JUMPTAB+$30

     Sprung zu TESTROMEN

     Dies  ist kein Druckfehler,  der Ansprung wird tatsäch-
     lich  zweimal vorgenommen.  Der erste Ansprung ist  ei-
     gentlich ein Auffangen eines Fehlsprunges,  da dort bei
     der  400/800-Serie ein Sprung nach Label SIGNON  stand,
     bei dem die Message "ATARI COMPUTER - MEMO PAD"  ausge-
     druckt  worden  ist und dann in eine Echo-Funktion  ge-
     sprungen  wurde.  Diese  Funktion wurde bei  dem  neuen

     600XL/800XL durch das Memory-TestROM ersetzt,  das  nun
     von hier aus angesprungen wird.

     Damit  diese  'Auffüll'-Funktion  theoretisch  von  der
     eigentlichen  TestROM-Einschaltfunktion  getrennt  ist,
     wurden  hier  diese beiden,  vielleicht nur  im  Moment
     gleichen Sprungvektoren eingesetzt.


$e483     58419          $xxxx xxxxx         JUMPTAB+$33

     Sprung zu TESTSTART

     Dieser  Ansprung ist natürlich nur dann sinnvoll,  wenn
     auch das TestROM eingeschaltet,  oder aber sein  Inhalt
     in das RAM ab Adresse $5000 kopiert worden ist.


$e486     58422          $xxxx xxxxx         JUMPTAB+$36

     Sprung zu NEUDEVICE


$e489     58425          $xxxx xxxxx         JUMPTAB+$39

     Sprung zu UNLINK


$e48c     58428          $xxxx xxxxx         JUMPTAB+$3c

     Sprung zu LINK


$e48f     58431          $xxxx xxxxx         CALLTAB

     Hier  liegen  6  Adressen in  einer  Tabelle,  die  auf
     NEUDEVC1  bis NEUDEVCB zeigen,  respektive auf das Byte
     direkt  vor diesen Adressen.  Dies hat den  Zweck,  mit
     Hilfe  dieser Tabellenwerte die entsprechenden  Device-
     Routinen mit RTS aufrufen zu können.

     Es dürfte allgemein bekannt sein, daß die 6502-CPU beim
     Rücksprung  aus  einer  Prozedur auf  dem  Stack  einen
     16bit-Wert  als Adresse verlangt,  der auf  das  letzte
     abgearbeitete  Byte der aufrufenden Routine  zeigt,  um
     dann die danach stehenden Befehle abzuarbeiten.  Diesen
     Effekt  kann  man nun ausnutzen,  um über eine  Tabelle
     indirekt Routinen aufrufen zu können.  Dazu muß einfach
     die  aufzurufende Adresse-1 auf dem Stack abgelegt  und
     ein RTS (ReTurn from Subroutine) ausgeführt werden.


$e49b     58523          $xxxx xxxxx         NEUINITC

     Es folgt ein direkter Sprung zu NEUINIT.


$e49e     58526          $xxxx xxxxx         FREI1

     Ab  hier sind 35 Byte Programmspeicher noch  nicht  be-
     legt.  Beim  benutzerseitigen  Belegen des Platzes  ist
     darauf zu achten, daß die ROM-Checksummen (s. CHECKROM1
     und CHECKROM2) korrigiert werden!


$e4c0     58560          $xxxx xxxxx         RTS

     Hier  steht ein völlig vereinsamtes RTS.  Es  wird  von
     verschiedenen Routinen benutzt.


$e4c1     58561          $e4a6     58543     CIOINIT

     Diese  Routine löscht alle IOCBs dadurch,  daß sie  die
     Devicenamen  CHANNELID ($0340,  $0350 ...) auf $ff legt
     und  die  PUTBYTE-Zeiger  ($0346+7,  $356+7,  ...)  auf
     CIONOTOPN als Fehlermeldung legt.


$e4dc     58588          $e4c1     58561     CIONOTOPN

     Wird versucht, Ausgaben über ein nichtexistentes Device

     zu  senden,  so wird diese  Routine  angesprungen.  Sie
     liefert in Y einen Wert $85 zurück, der der aufrufenden
     Schicht gleichzeitig mit dem gesetzten Negativ-Flag des
     CPU-Statusbytes  einen  DEVICE_NOT_OPEN-Error  signali-
     siert.


$e4ef     58591          $e4c4     58565     CIOMAIN

     Diese  Hauptausgaberoutine erwartet zwei Eingabeparame-
     ter:

     Erstens ein zu sendendes Character im Accu und zweitens
     die  IOCB-Nummer  * 16 des Kanals,  an den das  Zeichen
     geschickt werden soll.  Der Multiplikator 16 kommt  da-
     durch zustande, daß jedes IOCB 16 Byte belegt.

     Zuerst  werden  das  übergebene Zeichen und  die  IOCB-
     Nummer in IOCBCHARZ respektive in IOCBNUMZ abgelegt, um
     danach  die IOCB-Nummer zu überprüfen,  ob sie  erstens
     nicht zu groß ist (da nur 8 IOCBs zur Verfügung  stehen
     ist $70 die größte erlaubte Nummer),  und zweitens,  ob
     sie überhaupt durch 16 teilbar ist. Ist eine der beiden
     Bedingungen  nicht erfüllt,  so wird in Y der BAD_IOCB-
     Error durch den Wert $86 signalisiert.

     Generell  kann zu den CIO-Routinen gesagt  werden,  daß
     sie mit gesetztem Negativ-Flag zurückkehren,  wenn  ein
     Fehler  eingetreten ist.  Der Fehlercode kann  dann  am
     Wert von Y erkannt werden.

     Danach  wird der ab IOCBx liegende Block nach IOCBCHIDZ
     kopiert, also an die ausführbare Zero-Page-Stelle.

     Hier  werden nun wieder einige Abfragen bezüglich  noch
     nicht verwendeter Konstrukte getätigt. Ist als Channel-
     Id IOCBCHIDZ der Wert $7f angegeben und IOCBCMDZ  nicht
     $0c (POWER_ON_INIT)  und HNDLRLOAD Null, so wird ebenso
     ein  INVALID_CODE-Error signalisiert,  als ob  IOCBCMDZ
     kleiner als 3 (OPEN) wäre.  Ist HNDLERLOAD nicht  Null,
     wird  PREPLINK aufgerufen und ein eventuell  gemeldeter

     Fehler  nach  'oben' durchgereicht.  Tritt kein  Fehler
     auf, wird mit der Kommandobearbeitung fortgefahren.

     Ist  schon zu Beginn IOCBCMDZ gleich $0c,  wird  sofort
     zum CLOSE - Kommando gesprungen.

     Sonst  wird  von  hier aus je  nach  Kommando  entweder
     CLOSE, CIOSTATSP, CIOREAD oder CIOWRITE aufgerufen.

     Hat  HNDLRLOAD einen Wert ungleich Null,  wird die Rou-
     tine SPECHANDL aufgerufen,  sonst DEVS2PL3. Kehrt diese
     Routine mit Carry = 1 zurück, wird trotzdem noch einmal
     HNDLRLOAD  angesprungen,   sonst  wird  DEVICSTAT   und
     DEVICSTAT+1 gelöscht und COMENT aufgerufen.


$e57c     58748          $e533     58675     CIOCLOSE

     Hier  wird, je  nach an CIO übergebenem  Parameter, der
     entsrechende IOCB auf FREI gesetzt und der dazugehörige
     CLOSE-Treiber aus der Tabelle berechnet und  angesprun-
     gen.


$e597     58775          $e54e     58702     CIOSTATSP

     Hier  wird,  ebenso wie in CIOCLOSE,  der entsprechende
     Treiber für STATUS respektive SPECIAL-Kommando aufgeru-
     fen,  wenn  das angesprochene  Device  existiert.  Wenn
     nicht,  wird  es nach Möglichkeit eingerichtet und dann
     der dazugehörige Handlerteil angesprungen.


$e5b2     58802          $e569     58729     CIOREAD

     Zu Beginn wird getestet, ob dieser IOCB eventuell lese-
     geschützt ist. Dies ist der Fall, wenn in IOCBAUX1Z das
     Bit 2 nicht gesetzt ist.  In diesem Fall würde  CIOREAD
     mit einem WRITE_ONLY-Error zurückkehren. Lesegeschützte
     Geräte sind zum Beispiel Drucker.

     Handelt  es sich um ein lesbares Gerät,  wird die  noch
     zur  Verfügung  stehende Pufferlänge in  IOCBBUFLZ  (16
     Bit)  auf Null verglichen.  Ist es Null,  wird nur  ein
     Character  über den entsprechenden  Handler  eingelesen
     und zum Aufrufer zurückgekehrt.

     Ist die Länge des Puffers dagegen ungleich  Null,  gibt
     es drei Möglichkeiten, das Lesen abzubrechen:

     Die erste Abbruchbedingung sieht die Leseroutine,  wenn
     sie  einen  Lesefehler bemerkt,  also  der  aufgerufene
     Handler  sein  Carry-Flag setzt,  bevor er  zu  CIOREAD
     zrückkehrt.

     Als  zweites kann der IOCB ein blockorientiertes  Gerät
     sein (zum Beispiel Floppy).  Dann wird das Lesen  been-
     det,  wenn  die Pufferlänge nach dem Lesen des  letzten
     Zeichens Null wurde.

     Die dritte Möglichkeit ergibt sich bei zeilenorientier-
     ten Geräten, wie Druckers sie darstellen. Dabei wird so
     lange gelesen, bis ein NEWLINE ($9b) gefunden wird. Hat
     bis  dahin der Puffer gereicht,  ist alles in  Ordnung,
     ansonsten  sind alle Zeichen,  die nach Füllen des Puf-
     fers kamen,  ignoriert worden,  und das letzte  Zeichen
     des  Puffers wurde mit dem NEWLINE  überschrieben.  Hat
     man zum Beispiel einen Puffer mit 5 Byte Länge und eine
     Zeile gelesen,  die eine Länge von 8 Zeichen hatte,  so
     bekommt man im Puffer übergeben:


     1.CHR   2.CHR   3.CHR   4.CHR   NL

     Außerdem   wird  in  diesem  Fall  im  Y-Register   der
     TRUNCATET_CODE übergeben.

     Allgemein kann gesagt werden,  daß jeder Block,  gleich
     welchen  Formats,  nach  dem vom Handler aus  richtigen
     Lesen mit einem NEWLINE-Character endet.  Dies war beim
     400/800 nicht immer sichergestellt.

     Die  Entscheidung,  ob es sich um ein block- oder  zei-
     chenorientiertes  Gerät  handelt,  wird von Bit  1  von
     IOCBCMDZ gefällt.  Ist es Null,  handelt es sich um ein
     zeilenorientiertes Device.

     Als  letzte Operation wird in IOCBBUFLZ  die  korrekte,
     endgültige Pufferlänge übergeben.


$e61e     58910          $e5c9     58825    CIOWRITE

     Auch  beim  Schreiben über einen IOCB wird  zuerst  ge-
     prüft, ob der Zugriff überhaupt gestattet ist. Dazu muß
     in IOCBAUX1 das 4. Bit gesetzt sein.

     Ist das Schreiben erlaubt, so wird kontrolliert, ob die
     Pufferlänge Null ist. Ist dies der Fall, so wird ledig-
     lich  ein  einziges Zeichen übertragen.  Dies ist  kein
     Progammierfehler,  sondern eine äußerst sinnvolle  Ein-
     richtung,  über die schon der alte 400/800 verfügte: Da
     der Pufferlängenzähler von CIOxxxx verändert wird,  ist
     es sinnvoll,  davon auszugehen,  daß beim Aufruf dieser
     Routine  wenigstens ein Zeichen übertragen werden soll,
     und nicht wegen dieses einen Zeichens von der  darüber-
     liegenden  Schicht  der Pufferzähler gesetzt zu  werden
     braucht.  Die  eigentliche Übertragung läuft  über  den
     PUT-Handlerteil des Gerätes.

     Ist die Pufferlänge größer als Null,  so wird das näch-
     ste  Zeichen aus dem Puffer gelesen und übertragen,  um
     danach über INCBFP und DECBUFL den Pufferpointer zu in-
     beziehungsweise den Pufferlängenzähler zu  decrementie-
     ren.  Ist beim Schreiben des Zeichens ein Fehler aufge-
     treten,  wird  dies  entsprechend über  das  Y-Register
     mitgeteilt.

     Handelt es sich bei dem Gerät um ein zeilenorientiertes
     Gerät,  so wird so lange in CIOWRITE verharrt,  bis das
     letzte  übertragene Zeichen ein NEWLINE ($9b) war,  an-
     sonsten  so lange,  bis der Puffer leer  ist.  Ist  bei
     einem  zeilenorientierten  Gerät das letzte  im  Puffer

     befindliche Zeichen nicht NEWLINE, so wird dieses auto-
     matisch 'hinterhergeschoben'.


$e670     58992          $e4c4     58564     CIORETURN

     Diese  Abschlußroutine für alle CIO-Kommandos hat  zwei
     Einsprungpunkte: CIORETURN und CIORETURN+$02 .

     CIORETURN hat als einzige zusätzliche Aufgabe das Able-
     gen des an die Routine übergebenen Y-Wertes (Status der
     Operation) in IOCBSTATZ zu tun gegenüber CIORETURN+$02.

     Dort  wird dann die von Benutzer programmierte  Puffer-
     adresse  wieder in IOCBBUFAZ eingetragen,  um dann  den
     kompletten Zero-Page-IOCB wieder in den Userbereich  zu
     übertragen,  damit  der  nächste Programmteil den  IOCB
     benutzen kann.  Man darf nicht vergessen,  daß die CIO-
     Routinen  nicht in den von Benutzer zu programmierenden
     Bereichen $0340 ...  $03bf arbeiten,  sondern sich  den
     gerade aktiven Bereich von oben herunterkopieren, damit
     sie  wesentlich  schneller und effektiver in der  Zero-
     Page  arbeiten können (vergleiche hierzu  entsprechende
     Literatur  über Programmiermethoden bei der  6502-CPU).
     Nach dem Kopieren wird HNDLRLOAD auf Null  gesetzt,  um
     dann  im  Accu  das letzte gelesene  oder  geschriebene
     Zeichen,  in  X der IOCB-Index und in Y der Status  der
     letzten IOCB-Operation zurückgegeben werden.  Durch das
     letzte  Laden des Y-Registers ist das Negativ-Flag  des
     Prozessor-Status-Wortes signifikant.


$e695     59029          $e63d     58941     COMPENTRY

     Der  Kanaloffset IOCBCHIDZ wird geprüft.  Ist er größer
     als 33,  so gilt die ID als falsch und COMPENTRY  kehrt
     mit einem DEVICE_NOT_OPEN-Error zurück.

     Ansonsten  liegt  bei HATABS+Y der Anfang  des  3-Byte-
     Eintrages  in HATABS.  Das erste Byte enthält den Namen
     des Gerätes, das zweite und dritte einen Zeiger auf den

     Beginn des Handlerkonstruktes,  wie es zum Beispiel  in
     HANDLERTB  für  die initiell schon  vorhandenen  Geräte
     gezeigt ist.  Dieses Handlerkonstrukt beinhaltet Adres-
     sen zum Betrieb der CIO-Routinen.

     Diese  Anfangsadresse wird nun in IOCBAUX2 und -3 abge-
     legt. Danach wird der Offset des Handlers innerhalb des
     Handlerkonstruktes festgestellt,  der sich aus dem Kom-
     mando  und  CMDTAB  ergibt.  Sodann  wird  der  Pointer
     IOCBAUX2  und IOCBAUX3 so umgelegt,  daß er direkt  auf
     den Anfang der Handlerroutine zeigt.

     Diese  ganzen  Vorgänge lassen sich am  einfachsten  an
     einem Bild erklären:

                                  leer
                                   ' '

                                  leer
                                   ' '

                                  leer
                                   ' '

                                  leer
                                   ' '

                                  leer
                                   ' '

                                  leer
                                   ' '

                               Keyboardtab
                                   'K'

                                Screentab
                                   'S'

                                Editortab
                                   'E'

                                 Castab
                                   'C'

                               Printertab
       Y-Register                  'P'      HATABS
       hat zum Beispiel
       den Wert $06




     Also  wird  erst  in IOCBAUX2 -3 ein  Pointer  auf  den
     Eintrag  'Editortab'  abgelegt  und  danach   Editortab
     selbst.

$e6bb     59067          $e633     58931     DECBUFL

     Hier erfolgt ein 16bit- Decrement auf den Pufferlängen-
     wert  in IOCBBUFLZ .  Das Zero-Flag wird gesetzt,  wenn
     nach dem Decrement der Zähler Null ist.


$e6c8     59080          $xxxx xxxxx         DECBFP

     Der  Pufferzeiger in IOCBBUFAZ wird  decrementiert.  Es
     kann  keine Aussage über Flags getroffen  werden,  dies
     ist jedoch genau wie bei INCBFP auch nicht sinnvoll, da
     alle  Programmentscheidungen nicht über den  Pufferzei-
     ger,   sondern  ausschließlich  den  Pufferlängenzähler
     erfolgen.


$e6d1     59089          $e670     58992     INCBFP

     IOCBBUFAZ wird 16bitweise um Eins erhöht.


$e6d8     59096          $e677     58999     SUBBFL

     Hier  wird  die effektive  Pufferlänge  berechnet.  Bei
     zeilenorientierten  Geräten ist bekanntermaßen die  zu-
     rückgelieferte Datenmenge unbekannt. Sie kann zum einen
     dadurch bestimmt werden, daß innerhalb des Puffers nach
     einem  NEWLINE-Character ($9b) gesucht  wird,  anderer-
     seits stellt diese Routine hier die Anzahl der  überge-
     benen  Zeichen in IOCBBUFLZ als Rückgabewert zur Verfü-
     gung. Sie berechnet dazu einfach IOCBBUFLZ := IOCBBUFLx
     - IOCBBUFLZ  ,  wobei x die Nummer des  über  IOCBCHIDZ
     spezifizierten Gerätes ist.


$e6ea     59114          $e689     59017     GOHANDLER

     Diese Routine ruft über CIOJUMP zu dem vorher berechne-
     ten  Devicehandler.  Dazu wird erst das Y-Register  mit
     dem  Wert  FUNCTION_NOT_IMPLEMENTED ($92)  geladen,  um

     sicherzustellen,  daß eine Fehlermeldung erfolgt,  wenn
     der danach aufgerufene Handler vielleicht initiell  nur
     auf ein RTS führt. Nach Rückkehr aus der Handlerroutine
     wird  je  nach  überliefertem Y-Wert  das  Negativ-Flag
     gesetzt.  Das  Carry-Flag ist ebenfalls immer auf  Eins
     gesetzt.


$e6f4     59124          $e693     59027     CIOJUMP

     Hier  wird  genau  das  Verfahren  angewendet,  das  in
     CALLTAB beschrieben ist.  Es wird die  Anfangsadresse-1
     des  Handlerunterprogramms  auf dem Stack abgelegt  und
     danach der Handler indirekt über RTS angesprungen.  Die
     Tatsache,  daß es sich bei den dafür benötigten  Tabel-
     lenwerten  um  die Anfangsadressen-1 handelt,  ist  bei
     Erstellung  neuer Handlervektorentabelle von  äußerster
     Wichtigkeit. Leicht kann ein Handler dadurch funktions-
     untüchtig  werden,  daß die falsche  Adresse  angegeben
     worden ist.  Es ist auch zu bedenken, daß die ebenfalls
     bei jedem Deviceeintrag enthaltene Sprungadresse zu der
     Power-up  Initialisierung direkt auf die  entsprechende
     Routine zeigen muß, da der Power-up nicht indirekt über
     diese CIOJUMP-Funktion, sondern über den direkt vor der
     Adresse stehenden JMP-Opcode aufgerufen wird.  Das Kon-
     zept ist nicht unbedingt leicht verständlich, aber nach
     einiger  Gewöhnungszeit  lassen sich auch  dort  Fehler
     leicht erkennen.


$e6ff     59135          $e6b8     59064     DEVS2PL3

     Dieses  Unterprogramm bestimmt den Wert von  IOCBDSKNZ,
     also die aktuell zu benutzende Diskettenstationsnummer.
     Dazu wird die Nummer gelesen,  die in dem Folgebyte auf
     (IOCBBUFAZ)  steht.  Liegt  sie  zwischen $31  und  $39
     (ASCII-Wert für die Ziffersymbole '1' ..  '9'), so wird
     der zugehörige Wert $00  ..  $09 in IOCBDSKNZ eingetra-
     gen, ansonsten ist der Defaultwert Eins.

$e712     59154          $e69e     59038     DEVICSRCH

     Es wird das bei (IOCBBUFAZ) liegende Zeichen als  Gerä-
     tename  interpretiert und in der Tabelle ab HATABS  ge-
     sucht.  Wird ein übereinstimmender Eintrag gefunden, so
     wird der Offset des Eintrags mit dem richtigen Namen zu
     HATABS  in  IOCBCHIDZ  notiert und das  Carry-Flag  ge-
     löscht. Wird in keinem der HATABS-Einträge der gesuchte
     Name  gefunden,  signalisiert ein gesetztes  Carry-Flag
     der aufrufenden Schicht einen Fehler.


$e72d     59181          $e6c9     59081     COMTAB

     Diese  Tabelle  bildet eine Referenz  für  jedes  IOCB-
     Kommando  auf einen Vektor-Eintrag in der Handlerrouti-
     nentabelle ab HATABS.

     Es führen die Kommandos       Auf den Vektor ab Byte

          3    OPEN                0

         4,5   GET_RECORD          4
         6,7   GET_CHARACTER       4

         8,9   PUT_RECORD          6
        10,11  PUT_CHARACTER       6

         12    CLOSE               2

         13    STATUS_REQUEST      8

         14    SPECIAL            10



$e739     59193          $xxxx xxxxx         LINKSOMETH

     Auch  dieser  Programmteil ist für  spätere  Verwendung
     weiterer  Peripherieeinheiten  vorgesehen,   bei  denen
     unter Umständen der in HATABS stehende Bereich zu klein

     wird.  Es ist nicht zu vergessen,  daß bei HATABS  noch
     Platz  freigehalten wurde für den Betrieb von maximal 6
     weiteren Geräten.

     Alle  diese LINK- und UNLINK-Routinen gehen davon  aus,
     daß ab der Adresse STARTTST eine 19 Byte große Struktur
     steht.  Interessant ist dabei, daß von einer Kassetten-
     benutzung offensichtlich bei Benutzung dieser Konstruk-
     te  ganz  abgesehen werden soll.  Dies  ist  auch  ganz
     einsichtig,  da  die beiden an diesen Stellen stehenden
     Adressen  nur zum Booten über Cassette benutzt  werden.
     Geht man nun davon aus, daß dieser immense Softwareauf-
     wand  nur dafür getrieben wird,  exclusive Hardware  an
     den Atari anzuhängen,  dürfte klar sein,  daß die dafür
     vorgesehene Software nicht über Cassette gebootet wird.
     Als entsprechend exclusive Hardware war zum Beispiel in
     Mundpropaganda  ein CP/M-Subsystem angekündigt  worden;
     gesehen haben wir es bis heute leider noch nicht.

     Zu  Beginn der Routine wird getestet,  ob das  WARMFLAG
     gesetzt  ist.  Ist dies der Fall,  wird ZCHAIN auf  den
     Direktwert  STARTTST gesetzt und eine  Kontrollschleife
     begonnen.

     Bevor  jedoch  diese Schleife und  ihre  Ausgangspunkte
     besprochen  werden  können,  sollte ein  wenig  Theorie
     betrieben  werden  bezüglich  der  Verwendung  linearer
     Listen beim Atari 600XL/800XL.

     Unter einer einfach verketteten linearen Liste versteht
     man  ein Gebilde,  bei dem jedes Element einen  Verweis
     auf das nächste hat.  Dies ist zum Beispiel oftmals bei
     BASIC-Programmtexten der Fall.  Es werden in einer Pro-
     grammzeile  die Zeilennummer,  die Adresse der  logisch
     hierauf  folgenden  Zeile und danach  die  eigentlichen
     Daten abgelegt.  Hat man nun einen Zeiger auf die erste
     Zeile,  findet  man  über diese die  zweite,  dann  die
     dritte usw..  Das Verfahren ist vielleicht nicht  unbe-
     dingt das schnellste, es hat jedoch in Punkto Verarbei-
     tung  einige wesentliche Vorteile.  So muß zum Beispiel
     beim Einschieben einer neuen Zeile der gesamte, logisch

     dahinter  stehende  Text nicht nach  hinten  verschoben
     werden,  sondern es wird lediglich ein Zeiger so  umge-
     legt,  deß er auf das neue Element zeigt und der Zeiger
     des neuen Elements auf das Element, auf das der Vorgän-
     ger zuletzt zeigte.  Damit liegt die neue Zeile logisch
     mitten  im  Text,  wo sie jedoch physikalisch (also  im
     Speicher) liegt, ist völlig egal.


     1) Es existiert eine lineare Liste, aus der ausschnitt-
     weise  zwei  Elemente gezeigt  werden.  Genau  zwischen
     diese beiden Elemente soll ein weiteres eingefügt  wer-
     den:


          Element n                Element n+1



          neues Element



     2) Dazu wird zuerst der Zeiger von Element n kopiert in
     den Zeiger für das neue Element:


          Element n                Element n+1



          neues Element



     3)  Nun wird der überflüssig gewordene Zeiger von  Ele-
     ment n so umgelegt,  daß er auf das neue Element zeigt.
     Von  da ab ist das neue Element in der  linearen  Liste
     enthalten.



          Element n                Element n+1



          neues Element



     Diese  Form der Verkettung heißt deshalb 'einfach  ver-
     kettet',  weil  immer nur ein Zeiger (oder  neudeutsch:
     Link, Verweis) auf den Nachfolger (häufig als successor
     bezeichnet)  existiert,  nicht jedoch ein Link auf  den
     Vorgänger,  der  in  der  englischsprachigen  Literatur
     Predecessor  genannt wird.  Solch eine Verkettung  wäre
     dann  unter  dem Begriff 'doppelt verkettete Liste'  in
     der Informatik bekannt.

     Sicher  dürfte  klar sein,  daß man nicht  einfach  ein
     solches Element aus der Liste löschen kann  beziehungs-
     weise,  daß  ein  genaues  Protokoll für  das  Einfügen
     (Linken) eines neuen Elements beziehungsweise das  Ent-
     fernen  (Unlinken)  eines bestehenden  Elementes  einer
     verketteten  Liste  eingehalten werden muß.  Würde  zum
     Beispiel in unserem obigen Beispiel erst Schritt 3  und
     dann Schritt 2 gemacht,  wären alle Elemente ab Element
     n+1 unrettbar verloren:

     Die Ausgangsposition bleibt wie gehabt.



          Element n                Element n+1



          neues Element

     2) Dann wird der Zeiger von Element n zum neuen Element
     umgebogen:



          Element n                Element n+1



          neues Element



     Schon  haben  wir den Effekt,  daß nun der  Zeiger  des
     neuen  Elements  nicht auf eine sinnvolle Stelle  zeigt
     und  auch  nicht  mehr auf das  Element  n+1  umgebogen
     werden kann,  denn wo hätte vorher notiert werden  sol-
     len,  wo Element n+1 steht?  Die Adresse stand explizit
     im   Link  des  n.   Elements  und  wurde   schlichtweg
     'vermurkst'.

     Beim Unlink sind die Probleme etwas anderer Natur:

     Nehmen wir an,  wir hätten eine lineare Liste,  von der
     wir  drei  irgendwo in der Mitte liegende Elemente  be-
     trachten:


        Element n        Element n+1        Element n+2



     Soll nun Element n+1 entfernt werden, so wird lediglich
     der Pointer von Element n so umgelegt, daß er denselben
     Wert hat wie der von Element n+1 und schon ist  Element
     n+1 'umgangen':


        Element n        Element n+1        Element n+2

     Das Problem hierbei ist,  sich zu merken,  welche Spei-
     cherbereiche  nun  noch von  aktuellen  Listenelementen
     gefüllt  sind  und welche im Gegensatz  dazu  angefüllt
     sind  mit  nicht mehr referenzierten  Elementen.  Diese
     Berechnungen anzustellen ist relativ zeitaufwendig  und
     wird  deshalb  beim Atari weitmöglichst  umgangen.  Bei
     anderen  Systemen (zum Beispiel dem für  Atari  erhält-
     lichen MicroSoft-Basic) ist die gesamte Stringverarbei-
     tung auf dynamischer Speicherverwaltung aufgebaut.  Der
     Ausdruck  dynamisch  besagt,  daß nicht ein  konstanter
     Speicherraum belegt wird, sondern immer nur gerade das,
     was  benötigt wird.  Bei Verwendung sehr  vieler,  sehr
     kleiner  Strings passiert es dann ab und  an,  daß  man
     glaubt,  der Rechner 'stehe',  obwohl er dann nach zwei
     bis  drei  Minuten weiterrechnet.  Dann war er  in  der
     sogenannten  Garbage-Collect-Routine,  die den  String-
     Müll aufsammeln sollte.

     Ergänzend sollte noch erwähnt werden, was mit dem Poin-
     ter  des letzten Elementes geschieht.  Dieser zeigt nun
     nicht  wirr  'in die Luft',  sondern er  bekommt  einen
     definierten  Wert zugewiesen,  der allgemein NIL  (Aus-
     sprache wie bei dem Fluß) genannt wird.  Er ist wie bei
     Atari in dem meisten Fällen gleich Null, es gibt jedoch
     auch andere Computerkonzepte,  die kaum noch etwas  mit
     unseren  Nullen  und Einsen zu tun haben,  so  daß  man
     ruhig die Bezeichnung NIL verwenden sollte.

     Nach  diesem kurzen Exkurs über dynamische Datenverwal-
     tung zurück zu unserer gerade begonnenen Schleife.  Bei
     diesen hier verwendeten Elementen sitzt der Link  eines
     jeden  Elements in Byte Nummer 18 und 19,  bezogen  auf
     die  Startadresse des jeweiligen Elementes.

     Zeigt  zum Beispiel ZCHAIN auf ein beliebiges  Element,
     so  verstehen wir unter dem Konstrukt ZCHAIN.LINK  eben
     den Link des Elementes, auf das ZCHAIN zeigt.

ZCHAIN         Byte  0
               Byte  1
                 .
                 .
                 .
               Byte 18       diese beiden Bytes sind in die-
               Byte 19       sem Fall ZCHAIN.LINK


     Die   Schleife  terminiert  (Ausdruck  bei   Schleifen,
     Funktionen  und Prozeduren,  wenn sie durch interne Er-
     eignisse beendet werden) zum Beispiel, wenn ZCHAIN.LINK
     den Wert NIL liefert,  es sich also bei dem behandelten
     Element um das letzte der Liste handelt.

     Ansonsten  wird  das  nächste  Element  geprüft.   Dies
     geschieht einfach durch Zuweisung:

     ZCHAIN := ZCHAIN.LINK

     Dadurch  zeigt  nun ZCHAIN auf  das  Folgeelement.  Bei
     diesem wird nun geprüft, ob die Quersumme alle Einträge
     vom 0.  bis zum 17.  Byte gleich $ff ist (CHECKFF). Ist
     sie es nicht, terminiert die Schleife ebenfalls.

     Ansonsten wird das Carry-Flag gesetzt (über  CALLVKTC1)
     und,  ebenfalls darüber, CALLVKT angesprungen, was wie-
     derum veranlaßt, daß ein Befehlsbyte angesprungen wird,
     das  an Byte 12 der durch ZCHIAN bezeichneten  Struktur
     steht. Bitte erinnern Sie sich, daß die Handlertabellen
     ab  EDITORVKT  ebenfalls ab Byte 12 einen  Sprungbefehl
     auf  die  Initialisierungsroutine  des   entsprechenden
     Handlers hatte.  Somit dürfte die Funktion und der Auf-
     bau der hier beim 600XL/800XL neu eingeführten Struktu-
     ren  klar sein:  Sie sind funktional identisch mit  den
     Handlertabellen ab EDITORVKT und vom Aufbau unterschei-
     den sie sich lediglich durch die noch weiter benötigten
     Parameter zur Listenverwaltung.

     Kehrt  dieser Initialisierungshandler nun mit gesetztem
     Carry-Flag  zurück,  so terminiert die  Schleife  eben-

     falls,  ansonsten  wird der oben beschriebene  NIL-Test
     bezüglich des Folgelinks nun auf das neue Element bezo-
     gen.

     War  zu  Beginn der Routine  WARMSTART  gelöscht,  wird
     CHAINLINK  auf NIL gesetzt und mit der  Initialisierung
     der IOCBs weiter unten im Programm begonnen.



$e76e     59246          $xxxx     xxxxx

     Nach Aufruf von DCBINIT,  bei dem IOCB 0 mit Daten für
     ein  Drive mit der Nummer 1 initialisiert wird,  findet
     ein Aufruf von SIOINTERF über JUMPTAB+$09 statt.

     Kehrt das SIO-interface mit negativem Status zurück, so
     gilt  dies als Fehler ähnlich den CIO-Routinen und die-
     ser Fehler wird sofort 'nach oben' durchgereicht.

     War die Übertragung in Ordnung,  wird CHAINTP1 mit  der
     Summe aus MEMLO und dem Devicestatus DEVICSTAT geladen.

     Ist   nach   diesen  Operationen  MEMTOP  kleiner   als
     CHAINTP1,  werden  DSKAUX1 und DSKAUX2 mit $4e  geladen
     und  DCBINIT  aufgerufen.  Danach wird zum  Beginn  der
     Routine zurückgesprungen.

     Ist MEMTOP größer oder gleich CHAINTP1,  wird der  Wert
     von CHAINTMP gerettet,  um danach CHAINTMP mit MEMLO zu
     laden.  Hiernach  wird INITLOAD mit dem geretteten Low-
     Byte aus CHAINTMP im Accu aufgerufen.

     Kehrt diese Routine mit gesetztem Negativ-Flag  zurück,
     wird  LINK aufgerufen.  Im anderen Fall wird,  abhängig
     vom Carry-Flag,  bei gelöschtem Carry komplett neu  mit
     dieser Routine begonnen, sonst wird dort weitergemacht,
     wo  DCBINIT  mit $4e in DSKAUX1 und DSKAUX2  aufgerufen
     wird.

     Der einzige Ausgangspunkt aus dieser Schleife ist  also
     der negative Rückgabewert aus dem SIO-Interface.


$e7be     59326          $xxxx xxxxx         DCBINIT

     Es  werden die Daten aus TABSIOINI in den Disk-Control-
     Block ab DSKUNIT geladen,  der im Accu übergebene  Wert
     nach  DSKAUX1  und der in Y übergebene Wert in  DSKAUX2
     abgelegt,  um  danach SIOINTERF über die  Sprungtabelle
     bei JUMPTAB+$09 anzuspringen.


$e7d4     59348          $xxxx xxxxx         TABSIOINI

     Hier  stehen die Initialisierungswerte für den DCB  (s.
     DCBINIT). Sie lauten im einzelnen:

     DSKDEVICE           $4f       ist zu ignorieren

     DSKUNIT             $01       Laufwerk 1

     DSKCMD              $40       SIO-CMD GET_DATA

     DSKSTAT             $40       ist zu ignorieren

     DSKBUFFER           $02ea     ist   DEVICSTAT,     also
                                   normaler    Ablagebereich
                                   für Status

     DSKTIMOUT           $001e     entspricht  30   Sekunden
                                   Wartezeit bis Timeout

     DSKBYTCNT           $0004     Die     Statusinformation
                                   besteht aus vier Byte


$e7de     59358          $xxxx xxxxx         INITLOAD

     An  diese  Routine wird im Accu ein Wert für  CHAINTP1H
     übergeben,  der als erstes dort auch abgelegt wird. Der

     Low-Teil  CHAINTP1L  wird auf Null und  TEMP3  auf  $ff
     gesetzt.  Ist  Bit  0 von CHAINTMP Eins,  ist also  der
     Vektor  CHAINTMP ungerade,  so wird CHAINTMP  incremen-
     tiert.  Damit ist sichergestellt,  daß nach dieser Rou-
     tine CHAINTMP auf eine gerade Adresse zeigt.

     Dann   wird  LODADRESS  mit  dem  Wert  von   CHAINTMP,
     LODGBYTEA mit der Adresse INCLOAD und LODZLOADA mit dem
     Wert $80 geladen, um danach LOADER aufzurufen.


$e816     59414          $xxxx xxxxx         INCLOAD

     Nach Incrementieren von TEMP3 wird, falls  das Ergebnis
     nicht Null ist, der Accu mit dem Byte ($037d + Wert von
     TEMP3) geladen sowie das Carry-Flag gelöscht.

     Ist TEMP3 nach dem Decrement Null,  so wird es auf  $80
     gesetzt und DCBXINIT aufgerufen, was den DCB mit Werten
     für ein NOTE_SECTOR-Kommando lädt und das SIO-Interface
     aufruft.  Ist der Note-Vorgang positiv verlaufen,  wird
     ebenfalls  der  Accu  mit dem Byte ($037d  +  Wert  von
     TEMP3) geladen und das Carry gelöscht.


$e833     59443          $xxxx xxxxx         DCBXINIT

     Hier  wird,  analog zu DCBINIT,  der Disk-Control-Block
     mit  vorgefertigen Werten aus SIOTAB geladen  und  über
     JUMPTAB+$09 das SIOINTERF aufgerufen.


$e851     59473          $xxxx xxxxx         SIOTAB

     Hier  stehen die Initialisierungswerte für den DCB  für
     das NOTE-Kommando (s.  DCBXINIT). Sie lauten im einzel-
     nen:

     DSKDEVICE           $00       ist zu ignorieren

     DSKUNIT             $01       Laufwerk 1


     DSKCMD              $26       NOTE_SECTOR

     DSKSTAT             $40       ist zu ignorieren

     DSKBUFFER           $03fd     Hier  beginnt ein   sonst
                                   nicht   vom  OS  belegter
                                   RAM-Bereich.

     DSKTIMOUT           $001e     entspricht   30  Sekunden
                                   Wartezeit bis Timeout

     DSKBYTCNT           $0080     Es werden 128 Byte  gele-
                                   sen.


$e85d     59485          $xxxx xxxxx         SEARCHLIS

     In  A und Y wird der High- beziehungsweise der Low-Teil
     einer Listenelementadresse übergeben,  nach der hierbei
     ab Adresse STARTTST gesucht werden soll.  Als Rückgabe-
     werte sind ebenfalls der Accu,  das X-Register und  das
     Carry-Flag zu beachten.  Diese drei Rückgabemechanismen
     haben  folgende Bedeutung:  das Carry-Flag gibt darüber
     Auskunft,  ob der gesuchte Vektor gefunden wurde und ob
     A und X relevante Werte enthalten.

     Damit gib es nur zwei Möglichkeiten:

     1) Carry = 0 : Der  gesuchte Vektor wurde gefunden  und
                    in  A  (High-Byte) und X (Low-Byte)  zu-
                    rückgegeben. ZCHAIN zeigt auf die Struk-
                    tur,  deren  Link gleich  dem  gesuchten
                    Pointer ist.

     2) Carry = 1 : Entweder  hatte  ein Link den  Wert  NIL
                    oder bei einer der untersuchten Struktu-
                    ren  fand  sich eine,  deren  Checksumme
                    nicht  den  Wert $ff hatte  (Aufruf  von
                    CHECKFF!).

     Im  ersten Fall gibt sich zum Beispiel folgendes  Bild,
     wenn nach LINK(n+1) gesucht wurde:


     $03f9  Element1   Element2    Element n    Element n+1
            LINK(2)    LINK(3)     LINK(n+1)


     ZCHAIN


$e894     59540          $xxxx xxxxx         CALLVKTC1

     Es  wird mit gesetztem Carry-Flag mitten in  die  LINK-
     Routine  gesprungen,  um  als erstes über  CALLVKT  den
     Power-up-Handler anzuspringen.


$e898     59544          $xxxx xxxxx         LINK

     Diese Routine reiht ein neues  Strukturelement,  dessen
     Anfangsadresse  im  Accu (High-Wert) und  Y  (Low-Wert)
     übergeben wird,  an das Ende der bestehenden Liste ein.
     Dazu wird als erstes das letzte Element der bestehenden
     Liste  gesucht  (Aufruf  von SEARCHLIS mit  A=Y=0)  und
     dieser NIL-Wert so abgeändert,  daß dieser Link nun auf
     das neue Element zeigt (s.  LINKSOMETH!).  Danach  wird
     der  Link des neuen Elements auf NIL gesetzt und direkt
     an das 12. Byte der neuen Struktur gesprungen, was  zur
     Folge  hat,  daß  ein dort stehender  Sprungbefehl  die
     Programmkontrolle  an die Power-up-Routine des  neu  zu
     installierenden  Devices übergibt.  Kehrt diese Routine
     mit  gesetztem  Carry zurück,  so wird  dieses  Element
     gleich wieder entfernt (Aufruf von UNLINK mit den alten
     Accu- beziehungsweise  Y-Werten) und zum  Aufrufer  zu-
     rückgekehrt.

     Ist dies nicht der Fall, wird geprüft, ob die aufrufen-
     de  Routine ein gesetztes oder ein gelöschtes Carry-Bit
     übergeben hat.  War es gelöscht,  so werden das 16. und
     das  17. Byte der neuen Struktur gelöscht  (MINTLK  und

     GINTLK). Danach wird, unabhängig des übergebenen Carry-
     Flags, MEMLO auf einen neuen Wert gesetzt:

     MEMLO := MEMLO + ZCHAIN.MINTLK (16bit-Operation).

     Somit kann von der aufrufenden Routine bestimmt werden,
     ob  nach  Einhängen des neuen Elements MEMLO  verändert
     werden  soll oder nicht.  Ist das Carry  gesetzt,  wird
     MEMLO  verändert,  sonst nicht.  Das hat speziell  dann
     Sinn, wenn ganz zu Systembeginn diese Routinen aufgeru-
     fen werden und sich dann alle Programme wie DOS,  BASIC
     und ähnliche,  nach dem neuen, verschobenen MEMLO rich-
     ten (MEMLO gibt die niedrigste,  von dem Betriebssystem
     nicht mehr benötigte Adresse in RAM an).

     Danach wird die Checksumme der neuen Struktur berechnet
     (CHECKFF)  und  das Ergebnis im Byte  15  der  Struktur
     abgelegt.  Das  Byte 15 war auch schon zum Beispiel bei
     EDITORVKT  ein Hilfsbyte - jetzt hat es  eine  Funktion
     übernommen.

     Es  ist  an dieser Stelle  erwähnenswert,  daß  CHECKFF
     neben der Z-Flag-Aussage noch im Accu die Differenz der
     Checksumme  zum Wert $ff zurückgibt.  Dieser Wert  kann
     nun eingesetzt werden, damit bei weiteren Überprüfungen
     die Checksumme richtig ist.


$e900     59648          $xxxx xxxxx         CALLVKT

     Es wird an das Byte 12 der Struktur gesprungen, auf die
     ZCHAIN zeigt:


                                        Höhere Adressen
                              19
                              18
                              17
                              16
                 Checkfill    15
                 High-Byte    14

                 Low-Byte     13
                 JMP ($4c)    12
                              11
                              10
                              09
                              08
                              07
                              06
                 Handler-     05
                 adressen     04
                              03
                              02
                              01
     ZCHAIN                   00        Niedrigere Adressen




$e912     59666          $xxxx xxxxx         SETBVBLVKC

     Diese  Adresse  beinhaltet lediglich einen Sprung  nach
     SETVBLVKT.


$e915     59669          $xxxx xxxxx         UNLINK

     Über  SERACHLIS  wird das in Accu und  Y  spezifizierte
     Listenelement  in  der linearen Liste ab  STARTTST  ge-
     sucht.  Wird es nicht gefunden,  kehrt die Routine  mit
     gesetztem Carry-Flag zurück.

     Das  gefundene  Element wird  entweder  gelöscht,  wenn
     COLDSTART  gesetzt,  also ungleich Null ist,  oder wenn
     erstens  das  Byte  16 und das Byte 17  Null  sind  und
     zweitens  die Quersumme über die Struktur den Wert  $ff
     liefert (CHECKFF).  In eben diesen Fällen wird das Ele-
     ment auf die Art entfernt,  die in LINKSOMETH eingehend
     beschrieben wird.

     War das Element zu löschen,  kehrt UNLINK mit  gelösch-
     tem, sonst mit gesetztem Carry-Flag zurück.

$e959     59737          $xxxx xxxxx         JMPSIOINT

     Es erfolgt ein direkter Sprung zum SIOINTERFace.


$e95c     $59740         $e944     59716     SIOINIT

     Diese Routine ist zuständig für die Initialisierung des
     POKEY. Es werden der Cassettenrecordermotor und der Ton
     abgeschaltet.  Weiterhin  wird die  NOT_COMMAND-Leitung
     des seriellen Busses auf High (inaktiv) gelegt.


$e971     59761          $e959     59737     SIO

     Diese Prozedur übernimmt sämtliche Koordinierungsaufga-
     ben zur Steuerung des seriellen Busses.

     Zuerst wird,  um Fehlinterpretationen von Interrupts zu
     vermeiden,   CRITICIO   auf  Eins  gesetzt  und   unter
     DSKDEVICE  nachgesehen,  ob es sich bei dem angegebenen
     Gerät um die Cassette handelt.  Ist dies der Fall, wird
     zu  CASENTER,  dem  Cassettenbearbeitungsprogramm,  ge-
     sprungen.  Diese  Unterscheidung ist an  dieser  Stelle
     wesentlich,  da  alle anderen Geräte außer der Cassette
     einen internen Kontroller besitzen, der ihnen 'Intelli-
     genz' verschafft.

     Haben  wir  es mit solch einem intelligenten  Gerät  zu
     tun,  wird CASFLAG auf Null gesetzt,  um nach  Rückkehr
     aus  der  Lese- beziehungsweise Schreibroutine  richtig
     reagieren  zu können.  Danach werden DRETRY und  CRETRY
     mit $01 beziehungsweise $0d initialisiert und die Über-
     tragungsgeschwindigkeit  auf  ca.   19.200  Bit/Sekunde
     festgelegt.  Letztere Festlegung erfolgt über das  Pro-
     grammieren der Audiofrequenzkanäle 3 und 4, die mit $28
     beziehungsweise $00 geladen werden.

     Danach  werden die Geräte-Identifikation,  die sich aus
     der Geräteart und der Gerätenummer-1 zusammensetzt, das
     Kommando  sowie  das  erste und  das  zweite  Hilfsbyte

     DSKAUX1 und DSKAUX2 in die entsprechenden Variablen  ab
     CMDDEVIC  geladen,  um  danach DSKBUFPTR  auf  CMDDEVIC
     zeigen zu lassen,  damit die danach aufgerufene Komman-
     doroutine  weiß,  an welcher Stelle sie das zu bearbei-
     tende Kommando findet.  BUFENDPTR zeigt auf die  Stelle
     direkt hinter CMDAUX2.

     Sind  diese Vorbereitungen erledigt,  wird über PORT  B
     die KOMMANDO auf Low gelegt, um allen Geräten zu sagen:
     "ACHTUNG,  es  kommt  eine neue  Geräteadresse!".  Eben
     dieses Senden wird von der Routine SENDINIT übernommen.
     Hat  das angesprochene Gerät einen defekten Status  zu-
     rückgemeldet  oder  sich gar ein völlig  anderes  Gerät
     gemeldet, so wird ein Fehlercode in ERRFLAG zurückgege-
     ben, der nicht Null ist. In diesem Fall, oder wenn in Y
     notiert  wurde,  daß das Gerät ein  NEGTIV_ACKNOWELEDGE
     dadurch signalisierte,  daß es Y auf Null setzte,  wird
     CRETRY  decrementiert und,  falls  nicht  Null,  erneut
     versucht,  das Gerät anzusprechen.  Gelingt dies nicht,
     findet  eine  Fehlermeldung  an  das  aufrufende  Modul
     statt.

     Hat  sich  jedoch das Gerät ordentlich  zurückgemeldet,
     wird  DSKSTATUS ausgelesen und überprüft,  ob es  einen
     positiven Wert aufweist. Ist dies der Fall, so wird vor
     dem  ersten  Senden oder Lesen eines  Datensatzes  noch
     gewartet,  bis das Device sein vorhergehendes  Kommando
     völlig  abgearbeitet hat,  oder ein Timeout-Fehler auf-
     tritt.  Danach wird ein Kommando-Datensatz an das Gerät
     gesendet. Der Disk-Control-Block muß die entsprechenden
     Parameter für das Senden beinhalten.

     Nach dem ordentlichen Abarbeiten dieses Kommandos zeigt
     DSKSTATUS an,  ob eventuell noch Daten von dem Gerät zu
     lesen sind.  Ist dies der Fall, werden sie über RECEIVE
     eingelesen.

     Treten  während  der gesamten Bearbeitung keine  Fehler
     auf,  so wird in DSKSTATUS eine $01 zurückgegeben,  an-
     sonsten der Fehlercode.  Fehlercodes sind immer negativ
     und das N-Flag ist bei Rückkehr aus SIO gesetzt.

     Auf SIO zeigt JUMPVKT+$09.


$ea37     59959          $ea1a     59930     WAIT

     Dieses Modul wird nach dem Absetzen eines Kommandos  an
     ein intelligentes Gerät benutzt, um auf die Rückmeldung
     zu warten.

     Diese Rückmeldung kann zum Beispiel sein, daß das Gerät
     das Kommando nicht ausführen kann (zum Beispiel Schrei-
     ben  auf  schreibgeschützte  Diskette) oder  aber  eine
     Positiv-Meldung,  die  hier durch die  COMPLETE-Message
     dargestellt wird.

     Kommt  eine  negative Rückmeldung oder  kommt  bis  zum
     Timeout  keine Rückmeldung,  so wird das Y-Regster  mit
     $00  geladen und in ERRORFLAG der entsprechende  Fehler
     zum aufrufenden Modul zurückgemeldet.


$ea88     60040          $ea6b     60011     SEND

     Nach Aufruf von SENDENABL wird die allgemein interrupt-
     gesteuerte  Ausgabe dadurch angestoßen,  daß das  erste
     Byte  aus  dem  durch DSKBUFPTR spezifizierten  in  das
     Ausgaberegister SEROUT des POKEY geschrieben wird.  Ist
     dieses  Zeichen übertragen,  wird ein Interrupt  ausge-
     löst.

     Weiter  wird  in dieser Routine nichts  getan,  als  in
     IRQSTS abzufragen,  ob die BREAK-Taste gedrückt  wurde.
     Ist dies der Fall, wird die Übertragung abgebrochen.

     Ansonst wird gewartet, bis vom Interrupthandler irgend-
     wann  einmal XMITEND auf einen Wert ungleich  Null  ge-
     setzt wird,  da dies das Zeichen für "Übertragung been-
     det" ist.

     Zum  Abschluß  wird noch der Transmitter  über  SENDDIS
     disabled.

$eaad     60077          $ea90     60048     ISRODN

     Diese "Interrupt Service Routine if Output Data Needed"
     wird aufgerufen,  wenn der POKEY siganlisiert, er hätte
     das  letzte Zeichen vom Ausgaberegister SEROUT in  sein
     internes Parallel/Seriell-Wandlungsregister übertragen.
     Dann wird DSKBUFPTR incrementiert und kontrolliert,  ob
     dieser  Zeiger  sein durch BUFENDPTR  angezeigtes  Ende
     erreicht hat.  Ist dies der Fall, so wird das Checksum-
     menbyte  übertragen,  soweit dies noch nicht  geschehen
     und das Flag CHKSUMSND gesetzt ist.

     Sind noch Zeichen zu übertragen,  wird das nächste Zei-
     chen aus (DSKBUFPTR) genommen und an SEROUT übergeben.


$eaec     60140          $ead1     60113     ISRXD

     Signalisiert der POKEY bei einem Interrupt,  daß er mit
     der  Übertragung des  im  Parallel/Seriell-Wandlungsre-
     gister  enthalten  gewesenen Byte fertig und noch  kein
     neues  Byte in das SEROUT-Register  geschrieben  worden
     sei, wird diese Routine aufgerufen.

     Ist hier die Checksumme schon gesendet worden,  wird in
     XMITEND mit einem Wert ungleich Null signalisiert,  daß
     die serielle Ausgabe komplett beendet sei. XMITEND wird
     nach  Beendigung der Interrupt-Routine von  SEND  abge-
     fragt.


$eafd     60157          $eae2     60130     RECEIVE

     Handelt es sich bei dem Lesekommando um eines über  die
     Cassette,   wird  das  Checksummenregister  DSKCHECKSUM
     gelöscht, sonst nicht. Danach werden sowohl bei Casset-
     te,  als  auch bei jedem intelligenten Gerät die  Flags
     BUFFULL  und  RECEIVEND gelöscht.  Nach dem Aufruf  von
     RECEIVEN,  in dem das eigentliche Empfangen erst ermög-
     licht wird,  wird in einer Schleife abgefragt,  ob

     1)   die  BREAK-Taste gedrückt ist.  Dann wird der  Da-
          tenempfang abgebrochen,

     2)   die  Timeout-Bedingung über das TIMEFLAG  signali-
          siert wird (dies wäre der Fall,  wenn TIMEFLAG den
          Wert Null hätte)

     oder

     3) RECEIVEND einen Wert ungleich Null hätte.

     In jedem der drei Fälle würde das Lesen beendet,  wobei
     in   den  ersten  zweien  dem  aufrufenden  Modul  über
     DSKSTATUS ein Fehler durchgereicht würde.


$eb2c     60204          $eb11     60177     ISRSIR

     Diese "Interrupt Service Routine at Serial Input Ready"
     wird angesprungen,  wenn der POKEY bei einem  Interrupt
     über  seine  Flags die Meinung kundtut,  er  hätte  ein
     Zeichen empfangen und es sei in SERIN abzuholen.

     In diesem Fall wird der POKEY-Status aus SKSTAT gelesen
     und  eventuelle Fehlerbits durch Schreiben in SKSTATRES
     gelöscht.  Danach wird getestet,  ob das angeblich  be-
     reitliegende Zeichen richtig gelesen wurde, oder ob ein
     Framing- oder  Overrun-Error aufgetreten ist.  In jedem
     der  beiden  Fehlerfälle setzt  die  Routine  DSKSTATUS
     entsprechend.

     Ist  das Zeichen als richtig übertragen  eingezeichnet,
     wird  über BUFFULL geprüft,  ob alle einzulesenden Zei-
     chen  eingetroffen sind.  Ist dies der Fall,  ist  also
     BUFFULL nicht Null,  wird das Zeichen,  das jetzt  noch
     anliegt,  als  Checksumme  interpretiert und  nach  dem
     Lesen des Zeichens geprüft,  ob sie mit der berechneten
     Checksumme  übereinstimmt.  Ist die Prüfsumme nicht  in
     Ordnung, wird in DSKSTATUS ein Checksummenfehler signa-
     lisiert.  Unabhängig  davon  wird über das  Setzen  von
     RECEIVEND signalisiert, daß RECEIVE terminieren kann.

     Ist  BUFFUL  Null,  wird das Zeichen  gelesen,  zu  der
     Checksumme  addiert  und in den Puffer  ab  (DSKBUFPTR)
     geschrieben.  Danach  wird DSKBUFPTR incrementiert  und
     geprüft,  ob  BUFENDPTR erreicht wurde.  Ist  DSKBUFPTR
     weiterhin kleiner als BUFENDPTR, wird die Interruptrou-
     tine ohne weitere Flagänderungen verlassen.

     Bei  Gleichheit  der  beiden Pointer ist das  Ende  der
     eigentlichen  Datenübertragung gekommen.  Es  kann  nun
     noch unter Umständen eine Checksumme zu empfangen sein.
     Ist dies der Fall, also ist NOCHKSUM Null, wird BUFFULL
     für  den  nächsten  Interrupt auf $ff gesetzt  und  die
     Unterbrechungsroutine verlassen.

     Ist  laut NOCHKSUM keine Prüfsumme mehr von dem  Sender
     zu erwarten,  wird NOCHKSUM für den nächsten Aufruf von
     RECEIVE  gelöscht  und vor dem  Verlassen  der  Routine
     RECEIVEND   auf   $ff  (Receive  vollständig   beendet)
     gesetzt.


$eb87     60295          $eb6e     60270     LOADPTR

     Es werden zwei Berechnungen durchgeführt:

     DSKBUFPTR := DSKBUFFER

     BUFENDPTR := DSKBUFFER + DSKBYTCNT

     Das  heißt  nichts anderes,  als daß die  für  den  SIO
     benötigeten  Bufferanfangs- und Enddaten aus dem DCB in
     den SIO-Control-Block übertragen werden.


$eb9d     60317          $eb84     60292     CASENTER

     Dieser Punkt wird angesprungen,  wenn es sich um  einen
     Cassetten-I/O handelt. Dazu wird als erstes unterschie-
     den,  ob  es  sich um einen  Lese- oder  Schreibzugriff
     handelt,  da  beim Lesen die Eingabegeschwindigkeit ge-
     messen wird, beim Schreiben dagegen festliegt.

     Handelt es sich also um einen Schreibzugriff,  wird der
     POKEY  in seinen Asynchron-Ausgabezählern 3 und  4  auf
     600  Bit/Sekunde programmiert.  Dann wird Über  LOADPTR
     der  SIO-Kontrollblock  initialisiert und mit SEND  der
     Block  gesendet.  CASENTER ist ebenfalls zuständig  für
     das Ein- und Ausschalten des Cassettenmotors.

     Handelt  es  sich dagegen um  einen  Lesezugriff,  wird
     CASFLAG  gesetzt und,  ebenfalls nach Setzen  der  SIO-
     Pufferpointer über LOADPTR,  für diesen Block die Lese-
     geschwindigkeit  festgehalten durch Aufruf der Prozedur
     BEGINREAD.  Außerdem wird Timer1 so initialisiert,  daß
     er als Timeout-Interruptgeber fungiert.

     Nach  einem RECEIVE-Aufruf,  in dem der Block  entweder
     richtig  gelesen wird oder aber die Flags  entsprechend
     gesetzt werden,  wird der Cassettenmotor  abgeschaltet,
     wenn  dies  gewünscht wurde (nur nach  Übertragung  des
     letzten  End  Of File-Blocks) und zum Aufrufer  zurück-
     gekehrt.


$ec11     60433          $ebf0     60400     TIMER1INT

     Hier wird hingesprungen, wenn bei einem Vertikal-Blank-
     Interrupt  der TIMCOUNT1 auf Null gegangen  ist.  Diese
     Routine  wird  benutzt,  um einen  Timeout  ('endloses'
     Warten  auf ein Gerät,  das nicht antwortet oder  nicht
     antworten  kann) zu erkennen und die 'hängende'  Opera-
     tion  mit den entsprechenden  Fehlermeldungen  abzubre-
     chen. Dazu wird einfach eine Null in TIMEFLAG geladen.

     Damit  TIMER1  diese Routine finden kann,  wird in  der
     Prozedur  SETTIM1V  die  Adresse  von  TIMER1INT   nach
     TIMER1VKT geladen.


$ec17     60439          $ebf6     60406     SENDENABL

     Hier  wird  in SKCNTL und seinem  Schattenregister  ein
     Senden über die serielle Schnittstelle initiiert.  Wei-

     terhin  wird bei Cassettenbenutzung für das dabei  ver-
     wendete  Zweitonverfahren Tonregister 2 mit der niedri-
     gen  Frequenz und Tonregister 1 mit der hohen  Frequenz
     geladen.  Dann werden in IQREN@ eventuelle alte  Inter-
     rupts  gelöscht und der Output_Data_Interrupt  enabled.
     Danach  wird mitten in die RECEIVEN-Routine gesprungen,
     wo  die restlichen POKEY-Register für  die  Übertragung
     initialisiert werden.


$ec40     60480          $ec1f     60447     RECEIVEN

     Hier  wird,  analog zu SENDENABL,  der POKEY auf  asyn-
     chrone  Datenübertragung eingestellt und der  Receiver-
     Interrupt in IRQEN erlaubt.

     Außerdem wird SKSTATRES beschrieben, um eventuelle alte
     Fehlermeldungen zu löschen.

     Hiernach  steht der Einsprungpunkt für  SENDENABL,  bei
     dem Taktkanal 3 mit 1,77MHz und Kanal 4 mit dem Ausgang
     von Kanal 3 versorgt wird.

     Dann   werden   die   entsprechenden   Kontrollregister
     AUDICNTL1  bis  AUDICNTL4  entsprechend  dem  Wert  von
     IOSOUNDEN so gesetzt,  daß der "Übertragungs-Sound" nur
     bei gesetztem IOSOUNDEN durchkommt.

     Falls   keine  Cassettenoperationen  gewünscht  werden,
     werden die Tonkanäle 1 und 2 blockiert.  Sie werden nur
     für das Zweitonverfahren der Cassette benötigt.


$ec84     60548          $ec63     60515     SENDDIS

     Es werden die Bits 3,  4 und 5 von IRQEN@ gelöscht, was
     jegliches Lesen und Schreiben über Interrupt  unterbin-
     det.  Weiter werden die 4 Tonkontrollregister AUDICNTLx
     gelöscht.

$ec9a     60570          $ec79     60537     SETTIMOUT

     Diese  Routine liefert das Produkt aus dem Low-Wert von
     DSKTIMOUT und der Konstanten 32.

     Sie liefert den High-Teil des Resultates im  X-Register
     und den Low-Teil im Y-Register zurück.


$eca9     60585          $ec88     60552     INTTAB

     Hier  liegen die drei Interruptvektoren ISRSIR,  ISRODN
     sowie ISRXD.


$ecaf     60591          $ec8e     60558     SENDINIT

     Nach kurzem Delay,  das den I/O-Baugruppen  Gelegenheit
     geben soll,  sich einzuschwingen,  wird SEND aufgerufen
     und danach WAIT.

     Nach  Rückkehr  von  WAIT wird der Y-Wert in  den  Accu
     kopiert,  um die Flags zu setzen.  Ist ein Timeout pas-
     siert oder konnte das Gerät die Operation nicht ordent-
     lich durchführen, ist das Zero-Flag gesetzt.


$ecc8     60616          $eca7     60583     COMPUTE

     Diese  Routine  berechnet den Wert für  die  POKEY-Fre-
     quenzregister 3 und 4 beim Cassettenbetrieb.  Sie  ruft
     dabei  ADJUST  auf und wird selbst  ausschließlich  von
     BEGINREAD angestoßen.



$ed2e     60718          $ed08     60680     ADJUST

     Dieses  Unterprogramm wird zur Justage der  POKEY-Werte
     benutzt.  Bei  Verwendung  eines 50Hz-Gerätes wird  der
     Wert  des Accus um $20 erhöht,  falls er den  Wert  124

     noch  nicht erreicht hat.  Ist der Accu größer als $7b,
     wird der Wert $7c abgezogen.

     Bei  der NTSC-Version erfolgt die Erhöhung nur  um  den
     Wert $07.


$ed3d     60733          $ed14     60692     BEGINREAD

     Dieser  Programmteil stellt den POKEY auf die hier  ge-
     messene  Datenübertragungsgeschwindigkeit der  Cassette
     ein.  Dazu  muß  vorausgesetzt werden,  daß die  beiden
     ersten  Byte  eines von Cassette  zu  lesenden  Blockes
     immer  den Wert $aa haben.  Dieser Hexadezimalwert ent-
     spricht der Binärzahl %10101010, die sich recht gut zur
     Synchronisation eignet.

     Ist die Synchronisation beendet,  werden zwei $55- Byte
     im Datenpuffer abgelegt und die Checksumme  dahingehend
     initialisiert,  daß  sie mit den beiden $55-Bytes über-
     einstimmt.  Während der gesamten Routine können  sowohl
     Timeout- als  auch BREAK-Tasten-Unterbrechungen auftre-
     ten.  Sie  würden  durch geeignete  Statusmeldungen  in
     DSKSTATUS an das aufrufende Modul zurückgegeben und der
     Cassettenmotor abgeschaltet werden.


$ede2     60898          $edbd     60861     SETTIM1V

     Diese  Routine setzt über JUMPTAB+$0c den  Sprungvektor
     für   Timer1   (TIMER1VKT)  auf  TIMOUTINT   und   über
     JUMPTAB+$0c den TIMER1 selbst (TIMCOUNT1) auf den in  X
     (HIGH) und Y (LOW) übergebenen Wert.


$edf9     60921          $edd2     60882     POKTAB

     Umrechnungstabelle für COMPUTE.


$ee11     60945          $xxxx xxxxx         Tabellen

$eeb1     61105          $xxxx xxxxx         ADJTAB

     In  ADJTAB steht der Zeitwert für ADJUST bei der  NTSC-
     Version,  in ADJTAB+1 der für die bei uns benutzte PAL-
     Version.


$eebc     61116          $xxxx xxxxx         NEWDEVICE

     Diese  Routine sucht ab Adresse HATABS nach einem Gerät
     mit dem in X übergebenen Namen.  Findet es diesen  Ein-
     trag,  so  kehrt  die Routine mit gesetztem  Carry-Flag
     zurück,  wobei das X-Register auf die Handleradrese des
     gefundenen Eintrags zeigt (also hinter den Namen!)  und
     das Y-Register den Eingangszustand aufweist.

     Wird  das gesuchte Gerät nicht gefunden,  überprüft die
     Routine noch einmal alle Einträge,  ob sie einen leeren
     Eintrag findet.  Ist dies der Fall, wird der übergebene
     Accu-Wert als HIGH-Teil der Adresse und das  Y-Register
     als  LOW-Teil der Handlertabellenadresse  interpretiert
     und  zusammen mit dem in X übergebenen Namen als  neuer
     HATABS-Eintrag registriert.

     In  diesem Fall wird das Carry-Bit gelöscht.  Ist  kein
     weiterer Name frei, wird das Y-Register auf $ff und das
     Carry-Flag auf Eins gesetzt.


$eef9     61177          $xxxx xxxxx         SPECHANDL

     Dieser SPECial HANDLer ruft DCBINIT mit folgenden Para-
     metern auf:

     Accu      Ein Zeichen von Adresse (IOCBBUFAZ)

     Y         Wert von IOCBDSKNZ, also die Laufwerknummer

     Kehrt DCBINIT mit negativem Rückgabewert zurück, wird Y
     mit  NON_EXISTANT_DEVICE  geladen und die  Routine  ist
     beendet.

     Anderenfalls werden folgende Register geladen:

     Register                 geladener Wert
     ---------------------------------------
     IOCBCHIDZ                $7f                    ( 8bit)
     IOCBPUTBZ                Adr. von PUTBYTE1 - 1  (16bit)
     IOCBSPARE+IOCBCHIDZ      Zeich. v. (IOCBBUFAZ)  ( 8bit)
     IOCBSPARE+IOCBCHIDZ+1    CHAINTMP               ( 8bit)
     Y                        $01


$ef26     61222          $xxxx xxxxx         PUTBYTE1

     Gleich  bei Eintritt in diese Routine werden drei  mög-
     liche Fehlerquellen überprüft:

     1)   Die unteren vier Bit des Accu können ungleich Null
          sein.  Dann wird Y mit INVALID_IOCB-NUMBER geladen
          und die Bearbeitung abgebrochen.

     2)   Den gleichen Returnwert erhält Y,  wenn der Inhalt
          des X-Registers größer oder gleich $80 ist.

     3)   Hat   STARTTST   den   Wert   Null,    wird    ein
          NON_EXISTANT_DEVICE im Y-Register zurückgemeldet.


     Liegt  keiner der drei Fälle vor,  wird der X-Wert  als
     IOCBNUMZ verwendet und der durch IOCBCHIDZ spezifizier-
     te IOCB in den für IOCBs reservierten Zero-Page-Bereich
     kopiert,  um mit diesen neuen Werten PREPLINK  aufzuru-
     fen.  Kehrt  diese  Routine mit negativem Wert  zurück,
     wird ebenfalls die PUTBYTE-Routine mit einem Y-Wert von
     FUNCTION_NOT_IMPLEMENTED_IN_HANDLER abgebrochen.


     Im anderen Fall wird der Inhalt von IOCBPUTBZ (16  Bit)
     aus  dem  Stack  abgelegt und durch RTS  dieser  Vektor
     angesprungen.

$ef65     61285          $xxxx xxxxx         FREI1

     Hier liegen sechs unbenutzte und mit Null initialisier-
     te frei zu benutzende Programmspreicherbyte.  Bitte bei
     Belegung auf die korrekte Checksummenberechnung  achten
     (CHECKROM1 u.a.!).


$ef6b     61291          $xxxx xxxxx         CASMOTOFFC

     Ein direkter Sprung zu CASMOTOFF.


$ef6e     61294          $f3e4               POWERONA

     Hier wird LASTCH gelöscht (auf $ff gesetzt), RAMTOP auf
     den Wert aus RAMSIZE,  SHIFTLOCK auf $40 (nur Großbuch-
     staben),  KEYDEFPTR  auf KEYDEF und FKTDEFPTR auf FKDEF
     gesetzt.


$ef8e     61326          $xxxx xxxxx         INITSOME

     An  dieser Stelle wird im Zuge eines  Kalt- oder  Warm-
     starts  ein großer Teil der im System verwendeten Vari-
     ablen   initialisiert.   Dazu  gehören   zum   Beispiel
     CHARBASE,  CHARSTPTR,  DMACNTL@,  CHARCNTL,  MONSTATUS,
     IRQST@,  IRQST,  CURSORINH, TEXTINDEX, ADDRESS, TABMAP,
     Diese E-Mail-Adresse ist vor Spambots geschützt! Zur Anzeige muss JavaScript eingeschaltet sein!@, TEXTSTART und andere.


$f180     61824          $f593     62867     GETCH

     Diese  Routine  liest  ein Zeichen ab  der  angegebenen
     Cursorposition und übergibt es im Accu. Die Cursorposi-
     tion wird dabei incrementiert.


$f18f     61839          $f18f     61839     GETPLT

     GETPLT  ist eine von GETCH benutzte Prozedur und  liest

     das bei ADRESS liegende Zeichen ein und wandelt es  vom
     internen Bildschirmcode zurück in den ATASCII-Code.


$f1a4     61860          $f5bd     62909     OUTCH

     Das  im  Accu übergebene Zeichen wird auf  CLEAR_SCREEN
     ($7d)  und NEWLINE ($9b) überprüft  und  gegebenenfalls
     die entsprechenden Routinen aufgerufen,  ansonsten wird
     die Zeichenverwaltung von OUTPLT übernommen,  bevor der
     Cursor incrementiert wird.


$f1ca     61898          $f5e0     62944     OUTPLT

     Wenn des Bildschimausgabeflag STARTSTOP nicht Null ist,
     läuft  der Atari hier in einer Endlosschleife so lange,
     bis es wieder gelöscht wird.

     Danach  wird  das  im Accu übergebene  Zeichen  an  der
     Cursorposition abgelegt.

     In   dieser Routine ist OUTCH2 ($f1e9) häufig auch  von
     anderen Modulen benutzter Einsprungpunkt.


$f20b     61963          $f621     63009     RETURM

     RETURn from Monitor sorgt dafür,  daß bei eingeschalte-
     tem  Grafikmodus kein Cursor zu sehen ist und  versorgt
     bei erfolgreich verlaufenen I/O DSKSTATUS mit dem  Wert
     SUCCESS.

     An  dieser Stelle sollte nicht ganz unerwähnt  bleiben,
     daß  hier  mitten in der Routine (kurz  vor  dem  Ende)
     umständlich  um das folgende Label herumgesprungen wer-
     den  muß.  Wir halten das für dieses recht  aufgeräumte
     Betriebssystem für den Ausrutscher für die  Leute,  die
     nicht gerne Perfektes kaufen.

     Somit  endet die Routine RETURM bei Adresse  $f22d  und

     nicht schon vor dem folgenden Sprung.

     Ebenfalls nicht unwesentlich ist, daß die Adresse $f21e
     von  SWAP  als Einsprungpunkt benutz wird.  Es ist  die
     Stelle,  an der der aufrufenden Schicht die Erfolgsmel-
     dung signalisiert wird.  Diese Adresse ist beim 400/800
     $f634.


$f223     61987          $xxxx xxxxx         TESTROMEN

     Dies  ist lediglich ein direkter Sprung  zu  SWITCHROM.
     Bitte  vor  eventuellen Änderungen vorstehenden  Absatz
     lesen!


$f22e     61998          $xxxx xxxxx         SCROLFINE

     Ist Bit 7 von FINESCROL Null, wird die Routinenbearbei-
     tung abgebrochen,  sonst werden der Display-List-Inter-
     rupt  abgeschaltet,  FINESCROL auf Null und der  ANTIC-
     Programmvektor auf $c0ce,  also MASKTAB-1 gesetzt bevor
     in die Routine INITSOME gesprungen wird.


$f24a     62026          $f63e     63038     EGETCH

     Diese Routine wird benutzt,  um eine komplette logische
     Zeile (also über max. 120 Zeichen) einzugeben und edie-
     ren zu können.  Als Rückgabewert wird im Accu das erste
     Zeichen der Zeile übergeben, falls nicht BREAK gedrückt
     wurde.  War dies der Fall,  so wird im Accu ein NEWLINE
     ($9b)  übergeben und das Y-Register enthält als  Status
     den Wert $80.

     War  die Eingabe in Ordnung,  ist also nicht BREAK  ge-
     drückt  worden,  hat  Y den Wert $01.  Da  beim  ersten
     Aufruf  nur  das erste Zeichen der  eingegebenen  Zeile
     übergeben werden kann, muß nun für jedes weitere einge-
     gebene  Zeichen EGETCH erneut aufgerufen werden.  Dabei
     wird dann automatisch immer das nächste Zeichen zurück-

     geliefert.  Das  Ende  einer logischen Zeile  wird  dem
     aufrufenden Modul ebenfallsn mit dem NEWLINE-Kode  mit-
     geteilt.


$f2ad     62125          $f6a1     63137     JSRIND

     Es  erfolgt  von  hier  aus ein  indirekter  Sprung  zu
     (ADDRESS).


$f2b0     62128          $f6a4     63140     EOUTCH

     Es wird das im Accu übergebene Zeichen an der Cursorpo-
     sition abgelegt. Steuerzeichen werden verarbeitet.


$F2f8     62200          $f6dd     63197     KGETC2

     Dies ist kein Einsprungpunkt,  das Label wird lediglich
     von der folgenden KGETCH-Routine benötigt.


$f302     62210          $f6e2     63202     KBGETCHAR

     Hier wird ein Zeichen von der Tastatur gelesen und  auf
     verschiedene Sonderzeichen hin überprüft.  Eines dieser
     Sonderzeichen  wäre zum Beispiel das mit dem  Tastatur-
     code $89. Dieses leider im 600XL/800XL nicht verfügbare
     Sonderzeichen  würde  den  Tastaturklick  toggeln,  das
     heißt, einschalten, wenn er ausgeschaltet war und umge-
     keht.  Weiterhin  behandelt die Routine aber auch  beim
     600XL/800XL  zu verwendende Sonderzeichen wie zum  Bei-
     spiel CONTROL-1 zum Anhalten und Weiterlaufenlassen der
     Bildschirmausgabe.


$f3e0     62432          $f779     63353     ESCAPE

     Das  ESCAPEFLG wird auf $80 gesetzt.  Es wird benötigt,
     um  Cursorbefehle als Sonderzeichen auf dem  Bildschirm

     darstellen zu können.


$f3e6     62438          $f77f     63359     CURSORUP

     Der  Cursor  wird um eine physikalisch Zeile nach  oben
     transportiert beziehungsweise am oberen  Bildschirmrand
     auf die unterste Zeile zurückgesetzt (sogenanntes wrap-
     around).


$f3f3     62451          $f78c     63372     CURSORDWN

     Der  Cursor wird eine Zeile nach unten  beziehungsweise
     von der letzten Zeile aus wieder in die oberste zurück-
     gesetzt.


$f400     62464          $f799     63385     CURSORLFT

     Der  Cursor  wird eine Position nach  links  geschoben.
     Befindet  er sich zu Beginn am Anfang einer  Zeile,  so
     erfolgt ein Zeilen-wrap-around.



$f411     62481          $f7aa     63402     CURSORRIG

     Der Cursor wird eine Spalte nach links weitergeschoben.
     Befindet  er  sich am äußersten Rand  des  Bildschirms,
     wird er auf die erste Spalte derselben Zeile gesetzt.



$f420     62496          $f7b9     63417     CLEARSCRN

     Der Bildschirm wird zusammen mit der LOGIGMAP gelöscht.

     Danach wird die CURSORHOM-Funktion ausgeführt.

$fe40     62528          $f7d6     63446     CURSORHOM

     Der Cursor wird in die linke obere Ecke (Home-Position)
     gesetzt. Der Bildschirminhalt bleibt unverändert.


$f450     62544          $f7e6     63462     CURSORBS

     Es wird die BACK-SPACE-Funktion ausgeführt,  d.h.,  das
     direkt  links vom Cursor stehende Zeichen wird gelöscht
     und der Cursor steht nun auf dessen Platz.

     Steht  der Cursor zu Beginn der Routine am  Anfang  der
     Zeile, wird das Kommando ignoriert.


$f47a     62586          $f810     63504     CURSORTAB

     Es  wird in BITMASK nach der nächsten Tabulatorposition
     gesucht und diese angesprungen.

     Ist  keine weitere Tabulatorposition in der Zeile  ver-
     fügbar,  wird an den Anfang der nächsten Zeile gesprun-
     gen.



$f495     62613          $f82d     63533     CURSOSTAB

     Die  Spalte,  an der der Cursor bei Aufruf der  Routine
     steht, wird Tabulatorposition durch Setzen des entspre-
     chenden Bits in BITMASK.



$f49a     62618          $f832     63538     CURSOCTAB

     Eine eventuell an der Cursorspalte existente Tabulator-
     position wird gelöscht.

$f49f     62623          $f837     63543     INSCHAR

     An  der Cursorposition wird nach Möglichkeit ein  Leer-
     zeichen eingeschoben (Insert).


$f4d5     62677          $f86d     63597     DELCHAR

     Das Zeichen,  das logisch rechts vom Cursor steht, wird
     gelöscht  und  alle weiteren Zeichen  werden  'herange-
     rückt' (Delete).


$f50c     62732          $f8a5     63653     INSLINE

     An  der  Cursorposition wird eine neue  logische  Zeile
     eingefügt.


$f520     62752          $f8d4     63700     DELLINE

     Die durch die Cursorposition bezeichnete logische Zeile
     wird gelöscht. Alle anschließenden Zeilen rücken auf.


$f556     62806          $f90a     63754     BELL

     Es  wird 32 mal KEYCLICK aufgerufen.  Das ergibt  einen
     ca. 0,25s langen Ton.


$f55f     62815          $xxxx xxxxx         BOTTOMLIN

     Diese  Routine positioniert den Cursor in die  unterste
     Bildschirmzeile und erste Spalte.  Diese Position  wird
     von  manchen  Terminals als Home-Position  angesprungen
     und ist immer dann sinnvoll einzusetzen, wenn man nicht
     genau weiß,  wo man eigentlich auf dem Schirm steht und
     was für Informationen auf ihm stehen.

$f565     62821          $f917     63767     DBDDEC

     ADDRESS wird zweifach decrementiert und  überprüft,  ob
     das  Register  dann immer noch in den ihm  vorgegebenen
     Grenzen liegt oder ein SCREEN_ERROR aufgetreten ist.


$f5ac     62892          $f947     63815     CONVERT

     Die durch Spalten- und Zeilennummer spezifizierte  Cur-
     soradresse  wird in die effektive Speicheradresse umge-
     rechnet.


     $f60a     62986          $f9d4     63956     INCRSB

     Nach einem Incrementieren der Cursorposition wird über-
     prüft,  ob der Cursor am Ende einer Zeile oder ab Bild-
     schirmende steht.

     Sollte dies der Fall sein, wird automatisch ein Scroll-
     Vorgang ausgelöst.


$f6ae     63150          $fa7a     64122     SUBEND

     Je  nach Wert von X ($00 oder $02) wird  ENDPOINTR  von
     PLOTROWAC oder von PLOTCOLAC abgezogen.


$f6bc     63164          $fa88     64136     ERANGE

     ERANGE ist der Einsprungpunkt für den Editor. Hier wird
     getestet,  ob der Editor geöffnet ist und bei negativem
     Ergebnis ein Öffnen vollzogen.

     Danach  wird überprüft,  ob der Cursor innerhalb seiner
     normalen  Grenzen  liegt.   Tut  er  dies  nicht,  wird
     CURSORHOM aufgerufen und ein CURSOR_OVERRUN-Error  sig-
     nalisiert und die letzte Returnadresse vom Stack genom-
     men.  Damit  gelangt  der  Fehler also  direkt  zu  dem

     CIOMAIN aufrufenden Modul.


$f715     63253          $xxxx xxxxx         JMPF21E

     Es  folgt  ein  direkter Sprung mitten in  die  RETURM-
     Routine. Dieser Ansprung wird von SWAP benutzt.


$f718     63256          $fae4     64228     OFFCURSOR

     Das Zeichen,  an dem der Cursor im Moment  steht,  wird
     wieder  in den Bildschirm geschrieben - der Cursor also
     abgeschaltet.


     Alle jetzt folgenden Routinen mit Namen BITxxx beziehen
     sich auf Tabulatorenverarbeitung:


$f723     63267          $faeb     64235     BITCON

     Die  Maske  ab MASKTAB+Offset im Accu wird  in  BITMASK
     abgelegt  und in X 1/8 des im Accu übergebenen  Offsets
     zurückgegeben.



$f732     63282          $fafa     64250     BITROL

     LOGICMAP  bis  LOGICMAP+2 wird um ein  Bit  nach  links
     geschoben.  Das  höchste Bit aus LOGICMAP wird im Carry
     zurückgegeben.



$f73c     63292          $fb04     64260     BITPUT

     Setze durch Accu spezifiziertes Bit in TABMAP.

$f74a     63306          $fb12     64274     BITCLR

     Löscht das durch den Accu spezifizierte Bit in TABMAP.


$f758     63320          $fb20     64288     LOGGET

     Lädt  Accu mit CURSROW + 120 und läuft in  die  nächste
     Routine hinein:


$f75d     63325          $fb25     64293     BITGET

     Gibt  ein gesetztes Carry-Flag zurück,  wenn das  durch
     den Accu spezifizierte Bit gesetzt ist.


$f76a     63338          $fb32     64306     INATAC

     Das  im Accu übergebene Bildschirmkode-Zeichen wird  in
     ein  ATASCII-Zeichen gewandelt,  wenn es sich nicht  um
     ein Grafiksymbol handelt.


$f78e     63374          $fb4e     64334     LINEINSERT

     Hier  erfolgt  das hardwareabhängige Verschieben  einer
     physikalischen Zeile.  Es werden die Register  ADDRESS,
     MLTTMP sowie SAVEADR benutzt.


$f7c2     63426          $fb7b     64379     EXTEND

     Diese  Routine  verlängert eine logische Zeile um  eine
     weitere physikalische.


$f7e2     63458          $fb9b     64411     CLEARLINE

     Diese  Routine erledigt das  hardwareabhängige  Löschen
     (nicht: Entfernen!) einer physikalischen Zeile.

$f7f7     63479          $xxxx xxxxx         DOSCROLL

     Diese  Routine  erledigt das 'feine' Scrolling auf  dem
     Bildschirm sowie einen Teil der Grafikverarbeitung.


$f8b1     63665          $fc00     64512     DOBUFC

     Diese Routine berechnet die Pufferlänge der  momentanen
     logischen  Zeile,  wobei die letzten Leerzeichen  igno-
     riert werden.


$f90c     63756          $fc5c     64604     STRBEG

     BUFSTR wird auf den Anfang der durch die Cursorposition
     bestimmten Zeile gesetzt.


$f918     63768          $fc68     64616     DELTIA

     Diese Routine hat die Aufgabe, eine physikalische Zeile
     dann zu löschen, wenn sie leer und letzte physikalische
     einer logischen Zeile ist.


$f93c     63804          $fc8d     64653     TESTCNTL

     Diese Prozedur durchsucht die Kontrollzeichentabelle ab
     CONTROLS.  Ist  das Zeichen gefunden,  hat X den Offset
     auf den gefundenen Tabelleneintrag bezüglich  CONTROLS.
     Außerdem ist im Erfolgsfall das Zero-Flag gesetzt.


$f94c     63820          $fc9d     64669     PHACRS

     CURSROW,  CURSCOL  und GRAPHEMUL werden ab TEMPROW nach
     unten  abgelegt.


$f957     63831          $fca8     64680     PLACRS


     Die  von  PHACRS ab TEMPROW nach unten  hin  geretteten
     Cursorpositionen werden wieder geladen.


$f962     63842          $fcb3     64691     SWAP

     Es  werden  die Variablen CURSROW  bis  OLDGRADR+1  mit
     TEXTROW  bis TEXTGRAD+1 vertauscht und SWAPFLAG  inver-
     tiert.  Diese Vertauschung muß vorgenommen werden, wenn
     von Text nach Grafik innerhalb eines Bildschirmes umge-
     schaltet werden soll oder umgekehrt.


$f983     63875          $fcd8     64728     KEYCLICK

     An  dieser  Stelle  wird das Klicken der  Tastatur  ge-
     neriert.


$f997     63895          $fce4     64740     COLCR

     CURSCOL  wird Null,  wenn SWAÜFLAG Null  und  GRAPHEMUL
     ungleich Null ist.  Ansonsten wird CURSCOL auf den Wert
     von LFTMARGIN gesetzt.


$f9a6     63910          $fcf3     64755     PUTMSC

     Der Wert von SCRNSTART wird nach ADDRESS geladen.


$f9af     63919          $fcfc     64764     DRAWTO

     Es  wird,  je  nach Kommando in IOCBCMDZ entweder  eine
     Linie  gezogen  (DRAW)  oder  ein  Bereich   ausgefüllt
     (FILL).

     Die  Linie würde gezogen von OLDGRROW,  OLDGRCOL zu der
     in CURSROW und CURSCOL angegebenen Adresse.

$fb04     64260          $fe45     65093     TABELLEN





$fb0d     64269          $fec6     65222     CONTROLS

     Diese Tabelle beinhaltet alle benutzbaren Steuerzeichen
     und dahinter die entsprechende Handleradresse.


$fb11     64273          $xxxx xxxxx         FKDEF

     Hier  stehen  für jede (beim 600XL/800XL  nicht  einge-
     baute)  Funktionstaste F1..F4 16 Byte zu  ihrer  Bedeu-
     tungsdefinition zur Verfügung.


$fb51     64337          $xxxx xxxxx         KEYDEF

     Hier stehen alle 192 möglichen Tastenkodes,  respektive
     ihre Bedeutungen.



$fc1a     64538          $ffbe     65470     CPIRQQ

     Hier   liegt  der  Keyboard-Interrupt.   Es  wird   das
     STARTSTOP-Flag  bei Drücken von CONTROL-1  modifiziert,
     das  ATRACT-Register wird gelöscht und SRTIMER auf  den
     vorgewählten Delaywert KEYRPDELY gesetzt.



$fcd6     64726          $xxxx xxxxx         FREI2

     Es stehen hier 2 mit $00 initialisierte Bytes.

$fcd8     64728          $xxxx xxxxx         KEYCLICKC

     Von  hier wird ein direkter Sprung zur KEYCLICK-Routine
     gestartet.


$fcdb     64731          $ef41     61249     INIT

     In dieser kurzen Routine wird der POKEY auf 600 Bit/Se-
     kunde Datenübetragungsrate eingestellt.


$fce6     64742          $ef4c     61260     CASOPEN


     Hier  wird der Cassettenrecorder für die  Ausgabe  oder
     Eingabe vorbereitet. Es wird ein Fehler zurückgemeldet,
     wenn das Gerät schon geöffnet ist.

     Tritt  hier  kein  Fehler auf,  wird je  nach  Kommando
     (Schreiben  oder  Lesen) BEEPWAIT für einen  oder  zwei
     Töne aufgerufen,  was wiederum  einen,  beziehungsweise
     zwei  Kommandotöne zur Cassettenbedienung erzeugt.  Da-
     nach wird nach Drücken einer Taste der Motor  hardware-
     mäßig  eingeschaltet  und kurze Zeit gewartet,  bis  er
     richtig läuft. Beim Schreiben wird gleich ein 20 Sekun-
     den  langer  Startton an die Cassette gesendet  und  es
     werden allgemein die Pufferpointer und Pufferlängenzei-
     ger gesetzt.



$fd7a     64890          $efd6     61398     CASRDBYTE

     Es  wird ein Byte von Cassette gelesen.  Ist der Puffer
     leer,  aber  das File noch nicht zu Ende,  so wird  ein
     neuer Datenblock eingelesen. Das Datum wird bei richti-
     gem  Lesen im Accu zurückgegeben und in Y  ergibt  sich
     der Status der Operation.

$fd8d     64909          $efe9     61417     CASREADBL

     Es  wird ein kompletter Block von Cassette gelesen  und
     kontrolliert,  ob es der letzte Block war. Ist dies der
     Fall,  wird weiter kontrolliert, wie viele Byte noch in
     diesem  Block  enthalten  sind.   Die  Anzahl  wird  in
     CASBUFLIM zurückgegeben.

     War   das   File  schon   komplett   gelesen,   erfolgt
     END_OF_FILE-Errormessage.


$fdb4     64948          $f010     61456     CASPUTBYT

     Das  im  Accu  übergebene  Zeichen wird  im  Puffer  ab
     CASDATA bis CASDATA+$7f abgelegt.  Ist der Puffer  voll
     (CASBUFPTR  zeigt in den Puffer hinein auf die  nächste
     freie Stelle),  wird er automatisch geschrieben und neu
     initialisiert.



$fdcc     64972          $f028     61480     STATUS

     Hier  wird lediglich eine Erfolgsmeldung (SUCCESS) in Y
     signalisiert.



$fdcf     64975          $f02b     61483     CASCLOSE

     Es  wird die Cassettenbearbeitung  abgeschlossen.  Beim
     Lesen ist dies recht einfach, beim Schreiben muß jedoch
     darauf geachtet werden,  daß die letzten im Puffer vor-
     handenen  Bytes ebenfalls auf die Cassette  geschrieben
     werden.  Zusätzlich muß nach dem letzten Block noch ein
     End_Of_Text-Block geschrieben werden.  Erst danach darf
     der Cassettenmotor abgeschaltet werden.

$fdfc     65020          $f058     61528     BEEPWAIT

     Im Accu wird an diese Routine die Anzahl der  Piep-Töne
     übergeben,  die  ausgesendet werden sollen.  Jeder  der
     Töne  ist ca.  0,25s lang,  danach folgt eine Pause von
     ca.  0,1s. Nach dem letzten Ton wird KBGETCHAR aufgeru-
     fen,  also  auf die Eingabe eines  beliebigen  Zeichens
     gewartet.


$fe3f     65087          $f095     61589     SIOSYSBUF

     Hier  wird  der  SIO-Puffer ab DSKDEVICE für  die  Cas-
     settenoperationen Read beziehungsweise Write  vorberei-
     tet.  Zum  Beispiel wird der Cassettenpuffer auf  $03fd
     gelegt  und  die Anzahl der zu erwartenden  beziehungs-
     weise zu schreibenden Zeichen auf 131.  Dann wird  über
     JUMPTAB+$09 das SIOINTERFace aufgerufen.

     Der  jeweilige  Kommandokode ist im Accu zu  übergeben.
     Wird SIOSYSBUF mit einem Write-Kommando aufgerufen, ist
     die  Routine höchstwahrscheinlich von WSIOSB  angespro-
     chen worden.


$fe7c     65148          $f0d2     61650    WSIOSB

     Dies ist die Vorbereitungsroutine für das Schreiben auf
     Cassette.  Im  Accu  wird der Typ des  zu  schreibenden
     Blockes übergeben. Dabei bedeutet

     $fc            Dieser Block besteht aus 128 Datenbyte

     $fa            Dieser  Datenblock  enthält weniger  als
                    128 signifikante Byte. Die genaue Anzahl
                    steht  in  Byte  128  des  Blockes.  Das
                    heißt,  es werden zwar 128 Byte gelesen,
                    aber nur maximal 127 verwendet.

     $fe            Es   handelt  sich  hierbei   um   einen
                    END_OF_FILE-Block,  bei  dem alle Daten-

                    byte initiell Null sind.

     Es muß an diese Routine kein Kommando übergeben werden.
     Sie wird nur im Scheib-Fall aufgerufen.


$fe8d     65165          $xxxx xxxxx         TABELLE

     Sie enthält die Wertepaare

               $04  $03
               $80  $c0
               $02  $01
               $40  $e0
               $1e  $19
               $0a  $08



$fe99     65177          $ee78     61048     PHINIT

     Der  Wert für den Timeout beim Printer  (PTIMOUT)  wird
     auf 30 gesetzt.


$fe9f     65183          $ee7e     61054     PHSTLO

     Hier  liegt  für die indirekte Benutzung der  Adreßwert
     $02ea (DEVICSTAT).



$fea1     65185          $ee80     61056     PHCHLO

     Hier  liegt für die indirekte Benutzung  der  Adreßwert
     $03c0 (PRINTBUF).


$fea3     65187          $ee81     61057     PHSTAT

     Es wird versucht,  den Drucker anzusprechen.  Wenn dies

     nicht  gelingt,  wird ein gesetztes Negativ-Flag in der
     CPU zurückgeliefert.


$fec2     65218          $ee9f     61087     PHOPEN

     Nach einem Aufruf von PHSTAT wird die Printerpufferlän-
     ge  auf 0 gesetzt (PRTBUFPTR).  Der Status  aus  PHSTAT
     liegt noch im Y-Register, die Flags sind nicht signifi-
     kant.


$fecb     65212          $eea7     61095     PHWRITE

     Der  Printerpuffer PRINTBUF wird successive gefüllt bis
     zu  einem  NEWLINE-Zeichen.  Ist dann der  Puffer  noch
     nicht voll (128 Zeichen),  wird er mit Leerzeichen auf-
     gefüllt.

     Ist  der  Puffer voll,  wird er  über  JUMPTAB+$09  und
     SIOINTERF auf den Drucker geschickt.



$ff02     65282          $eedc     61148     PHCLOSE

     Nach  einem  Aufruf  von PRMODE wird  geprüft,  ob  der
     PRINTBUF leer ist und wenn nicht,  wird er über PHWRITE
     geleert.  PHWRITE wird nicht am eigentlichen Einsprung-
     punkt aufgerufen.



$ff0f     65295          $eee6     61158     SETDBC

     In  X und Y werden der  Low- beziehungsweise  High-Teil
     der  Pufferadresse aus PHCHLO übergeben,  um damit  und
     mit  weiteren  intern  zu holenden Werten die  SIO  für
     einen Druck-Befehl zu initialisieren.

$ff3f     65343          $ef1a     61210     PHPUT

     Der Wert aus PRTTIME wird nach PTIMOUT übertragen.


$ff46     65350          $ef1a     61210     PRMODE

     Je nach Printmode (Normal, Doppelte_Breite oder Schmal-
     druck) werden DSKCMD und DSKAUX1 initialisiert.


$ff6e     65390          $xxxx xxxxx         CHECKROM1

     Es  wird die Checksumme über die folgenden  Speicherbe-
     reiche berechnet:

               $c002  ...  $cfff   (c000,1  nicht,  weil sie
                                   selbst  eine   Checksumme
                                   darstellen   und  deshalb
                                   nicht mitberechnet werden
                                   können!

               $5000  ...  $57ff   (TestROM)

               $d800  ...  $dfff   (Mathe-ROM)

     Ist  diese in CHECKSUM (LOW) und CHECKSUM+1 (HIGH)  be-
     rechnete  Prüfsumme identisch mit den in  CHECKSR0  be-
     ziehungsweise  CHECKSR1 programmierten Werten,  erfolgt
     positive Meldung durch gelöschtes Carry-Flag, sonst ist
     das Carry-Flag gesetzt. Die Routine kann natürlich auch
     zum  Berechnen  der Werte bei  neu  programmierten  Be-
     triebssystemteilen  verwendet werden.  Die Werte stehen
     nach  der  Berechnung  ja immer noch  in  CHECKSUM  zur
     Verfügung!


     Diese und die nächste Funktion benutzen GETCHECKS.

$ff8d     65421          $xxxx xxxxx         CHECKROM2

     Diese  Funktion liefert als Wert ein gelöschtes  Carry-
     Flag,  wenn  die  in  GETCHECKS  für  die  ROM- (RAM-?)
     Bereiche

          $e000 ... $fff7       ($fff8, $fff9 ist Prüfsumme)
          $fffa ... $ffff

     berechnete Prüfsumme mit den Werten in CHECKSUM2  (Low)
     und CHECKSUM2+1 (High) übereinstimmt, ansonsten ist der
     Funktionswert im Carry-Flag Eins.


$ffa4     65444          $xxxx xxxxx         GETCHECKS

     Bei Aufruf dieser Routine erwartet diese im  X-Register
     einen  Wert,  aus dem sie den Speicherbereich  erkennen
     kann,  dessen  Checksumme  sie zu dem Wert in  CHECKSUM
     (Low)  und CHECKSUM+1 (High) addieren  kann,  wobei  es
     egal ist, ob dieser Speicherbereich RAM oder ROM selek-
     tiert.  Es  stehen folgende Werte für X zur  Verfügung,
     die  dann über CHKSUMTAB die entsprechenden Speicherbe-
     reiche spezifizieren:

     Eingabeparameter in X         geprüfter Speicherbereich
     -------------------------------------------------------

        $00                        $c002 ... $cfff
        $04                        $5000 ... $57ff
        $08                        $d800 ... $dfff
        $0c                        $e000 ... $fff7
        $10                        $fffa ... $ffff


     Die  Routine  kehrt als Seiteneffekt mit einem  um  den
     Wert 4 erhöhten X-Register zurück.  Das erleichtert das
     mehrfache Aufrufen dieser Funktion zum Testen  mehrerer
     Speicherbereiche.

$ffd2     65490          $xxxx xxxxx         CHKSUMTAB

     Hier  stehen die Anfangs- und um eins erhöhten Endwerte
     für  den Prüfsummentest GETCHECKS.  Es sind  demzufolge
     die Werte

               $c002     $d000
               $5000     $5800
               $d800     $e000
               $e000     $fff8
               $fffa     $0000

     enthalten.


$fff8     65528          $xxxx xxxxx         CHECKSUM2

     Hier und im folgenden Byte steht die Prüfsumme über die
     momentan  implementierten  Betriebssystemteile  in  den
     Speicherbereichen

               $e000 ... $fff7
               $fffa ... $ffff

     Die beiden Prüfsummenbytes $fff8 und $fff9 sind selbst-
     verständlich  nicht enthalten.  Dies wäre zwar  rechne-
     risch  möglich,  würde jedoch den Nachteil in sich bür-
     gen,  daß die Funktion GETCHECKS nicht mehr als Seiten-
     effekt bei Neuimplementierungen von  Betriebssystemtei-
     len die neue, korrigierte Prüfsumme liefern würde.



$fffa     65530          $fffa     65530     NMIVKT

     Dieser  Vektor ist der vom Mikroprogramm der  R6502-CPU
     festgelegte  Vektor für die Routine des Nichtmaskierba-
     ren Interrupts. Er zeigt auf die Adresse PNMI.


$fffc     65532          $fffc     65532     RESETVKT

     Dieser Vektor ist der vom Mikroprogramm der CPU festge-
     legte  Vektor für die Routine  des  Hardware-Reset.  Er
     zeigt auf die Adresse RESETCOLD.


$fffe     65534          $fffe     65534     INTVKT

     Dieser Vektor ist der vom Mikroprogramm der CPU festge-
     legte  Vektor für die Routine des  maskierbaren  Inter-
     rupt. Er zeigt auf die Adresse JMPIRQVKT.

Hauptkategorie: 8-Bitter
Erstellt: 19 November 2011
Zugriffe: 2137

Der Speicherplan beschreibt die Funktionen der relevanten RAM-Adressen. Da es sich beim 6502-Prozessor um einen handelt, der keine separaten Ein-Ausgabe-Befehle kennt (I/O-Operations), sind Geräte ebenfalls in den 64KB-Adressraum der CPU eingeblendet. Aus diesem Grund sind auch die I/O-Geräte hier mit aufgeführt.

HILFSWORT

0

$0

Diese zwei Byte werden von der Reset-Routine beim Speichertest verwendet.

1

$1


CASINITV

2

$2

Wurde von Cassette gebootet, und war das Booten erfolgreich, erfolgt ein Sprung an die hier stehende Adresse.

3

$3


RAMTSTPTR

4

$4

Auch dieser Pointer wird nur für den Speichergrößentest verwendet.

5

$5


TMPRAMSIZ
Wird in Verbindung mit Adresse 5 ($5) benutzt, um das Ergebnis des RAM-Tests festzuhalten.

6

$6


TESTDATA
Hier steht das Datenbyte, das vor Beginn des Speichertests an der gerade zu testenden Stelle stand.

7

$7


WARMFLAG
Steht hier ein Wert ungleich Null, erfolgt im Normalfall beim Drücken der RESET-Taste nur ein Warmstart.

8

$8


DOSAKTIV
Hat dieses Byte den Wert Eins, so erfolgt beim Warmstart ein Sprung zur DOS-Initialisierungsroutine in DOSINIT.

9

$9


DOSVKT

10

$a

Hier liegt die Startadresse der DOS- oder anderen Boot-Software.

11

$b


DOSINIT

12

$c

Sprungadresse zur Initialisierungsroutine des DOS.

13

$d


BASMEMTOP

14

$e

Hier steht die höchste, vom Benutzerprogramm zu verwendende Speicheradresse. Darüber liegt in den meisten Fällen der Bildschirmbereich.

15

$f


IRQEN@
Durch Setzen der jeweiligen Bits können hier die Interruptquellen vom POKEY gesteuert werden. Ist ein Bit gesetzt, so ist die entsprechende Quelle aktiv.

16

$10


IRQST@
Ist eines der Bits dieses Schattenregisters auf Null, so ist die zugehörige Interruptquelle im POKEY aktiv geworden und es ist der entsprechende Handler aufzurufen.

17

$11


CLOCK

18

$12


19

$13

Dieser Drei-Byte-Wert wird alle 1/50 Sekunde incrementiert, wobei 20 ($14) das niederwertigste Byte ist.

20

$14


BUFFERADR

21

$15

Diese Adresse dient den SIO-Routinen als Hilfszeiger bei Diskettenoperationen.

22

$16


IOCBCMD
Sie dient als Hilfsspeicher bei CIO-Operationen.

23

$17


DISKFORM

24

$18

Dies ist ebenfalls ein Hilfszeiger für die Diskettenoperationen.

25

$19


DISKUTIL

26

$1a

Für diesen Pointer gilt ähnliches wie für DISKFORM.

27

$1b


ABUFPTR0

28

$1c

ABUFPTR1

29

$1d

ABUFPTR2

30

$1e

ABUFPTR3
Dies sind Hilfszeiger für rein internen Gebrauch.

31

$1f


IOCBCHIDZ
In diesem Byte liegt das Erkennungssymbol des anzusprechenden Gerätes an der seriellen Schnittstelle.

32

$20


IOCBDSKNZ
Bei der Diskettenverarbeitung reicht die Identifikation 'Diskette' in IOCBCHIDZ nicht aus, so daß noch eine Laufwerksnummer übergeben werden muß. Dies geschieht hierdurch.

33

$21


IOCBCMDZ
Hier liegt das gerade in Arbeit befindliche oder gerade fertig gewordene CIO-Kommando.

34

$22


IOCBSTATZ
An dieser Adresse legt die CIO-Routine ihre Statusmeldungen ab.

35

$23


IOCBBUFAZ

36

$24

Hier liegt die Anfangsadresse des Datenpuffers bei CIO-Operationen.

37

$25


IOCBPUTBZ

38

$26

Startadresse-1 der PUT_ONE_BYTE-Routine des entsprechenden Gerätes.

39

$27


IOCBBUFLZ

40

$28

Pufferlänge ab IOCBBUFAZ

41

$29


IOCBAUX1

42

$2a

IOCBAUX2

43

$2b

IOCBAUX3

44

$2c

IOCBAUX4
Hilfsinformationen für die CIOKommandobearbeitung.

45

$2d


IOCBNUMZ
Nummer des zu benutzenden IOCBs, multipliziert mit 16.

46

$2e


IOCBCHARZ
Hilfsregister zur Aufnahme des zu übertragenden Zeichens bei CIO-SchreibOperationen ohne Datenpuffer.

47

$2f


Die folgenden Register sind ausschließlich für den internen Gebrauch bestimmt. Sie dürfen nur benutzt werden, wenn die sie benutzenden Routinen verändert werden, da sonst nichts über den Zustand sowohl der benutzenden Routinen als auch der Variablen selbst ausgesagt werden kann.

DSKSTAT
Statusrückmeldung aus Disketten- oder Cassettenverarbeitung.

48

$30


DSKCHKSUM
Prüfsummenregister für serielle Übertragung.

49

$31


DSKBUFPTR

50

$32

Pufferanfang für Cassetten oder Diskettenoperation.

51

$33


BUFENDPTR

52

$34

Zeigt auf das Ende des Disk-Puffers BUFENDPTR.

53

$35


LOADERTMP

54

$36

Hilfsregister für den internen Gebrauch des Loaders.

55

$37


BUFFULL
Ist dieses Flag ungleich Null, so ist der CIO- beziehungsweise SIO-Puffer voll.

56

$38


RECEIVEND
Ist dieses Flag nicht Null, so bedeutet es, daß die CIO-Routine ihren Empfang beendet hat.

57

$39


XMITEND
Dieses Flag gibt darüber Auskunft, ob die interruptgesteuerte Senderoutine ihre Aufgabe schon beendet hat.

58

$3a


CHKSUMSND
Wenn gesetzt, ist die Checksumme bereits gesendet.

59

$3b


NOCHKSUM
Bei einem Wert ungleich Null wird keine Checksumme gesendet.

60

$3c


CASBUFPTR
Bytezähler für die Cassettenübertragung. Liegt wertmäßig zwischen Null und CASBUFLIM.

61

$3d


GAPTYPE
$00: Normale Gaplänge zwischen den einzelnen Blöcken auf einer Cassette.
$80: Extrem langer Gap am Anfang der Cassettenübertragung.

62

$3e


CASEOF
Ist dieses Byte gesetzt, so hat die Leseroutine der Cassette einen END_OF_FILE-Record gefunden.

63

$3f


BEEPCOUNT
Hier steht der Parameter für die BEEPWAITRoutine. Er enthält die Anzahl der abzugebenden Huptöne als Erkennung für irgendwelche externen Operationen (z.B. zwei Huptöne: Schalte PLAY und RECORD ein).

64

$40


IOSOUNDEN
Wenn dieses Byte Null ist, wird die Tonausgabe der seriellen Ein-/Ausgabe unterdrückt.

65

$41


CRITICIO
Dieses Bit wird dann gesetzt, wenn eine hohe, schnelle Folge von Interrupts erwartet wird (z.B. bei seriellem I/O). Sie bewirkt, daß die Vertical-Blank-Unterbrechungsroutine nur zu einem sehr geringen Teil bearbeitet wird, um somit Zeit zu sparen. Als Seiteneffekt ergibt sich zum Beispiel, daß aufgrund der fehlenden Zählerergebnisse der Autorepeat der Tastatur unwirksam ist.

66

$42


FILEMNGMT

67

$43


bis

bis

Interne Pointer für Diskettensteuerung.

73

$49


ZCHAIN

74

$4a

Pointer für die Verarbeitung der linearen Liste der IOCBs.

75

$4b


MONSTATUS
Dieser Status wird von der Monitorverarbeitung benötigt.

76

$4c


ATTRACT
Ist dieses Byte niedriger als 128 = $80, so erfolgt normale Bildschirmausgabe. Erreicht es den Wert 128, wird es auf 254 gesetzt und bwirkt das Einschalten des sogenannten Attract-Modes.

77

$4d


ATRACTMSK
$fe: Normale Bildschirmhelligkeit $f6: verringerte Helligkeit
ATRACTMASK ist abhängig von ATTRACT.

78

$4e


COLREGSH
Dieses Register gehört ebenso wie ATRACTMSK zur Verarbeitung des Attract-Modes. Es erfolgt ein logische Verknüpfung der Farb- und Luminanzregister des ANTIC.

79

$4f


MONTEMP

80

$50

Hilfsbyte für Bildverarbeitung.

81

$51


LFTMARGIN
Wert des linken Randes bei Textdarstellung.

82

$52


GIGMARGIN
Wert des rechten Randes bei Textdarstellung.

83

$53


CURSROW
Dies ist die momentane Cursorreihe bei Grafikverarbeitung in dem Bereich von 0 bis 191.

84

$54


CORSCOL

85

$55

Cursorspalte bei Grafikverarbeitung in den Bereichen von 0 bis 319.

86

$56


GRAPHEMUL
Dieser Wert legt fest, in welchem GrafikModus die folgenden Ausgaben stattfinden. Es wird benötigt, um von höheren Programmiersprachen aus leicht mehrere Grafikarten mischen zu können.

87

$57


SCRNSTART

88

$58

Adresse des ersten Bildschirmbytes.

89

$59


OLDGRROW

90

$5a

OLDGRCOL

91

$5b


92

$5c

OLDGRCHR

93

$5d

OLDGRADR

94

$5e

Diese Adressen beinhalten alle Daten, die zwischengespeichert werden müssen, wenn zwischen Grafik- und Textverarbeitung während eines Programms umgeschaltet werden soll. Auch diese Adressen sind nur für interne Zwecke bestimmt!

95

$5f


FKTDEFPTR

96

$60

Hier steht die Anfangsadresse der 8 Byte langen Tabelle zur Festlegung der Funktionstastenkodes beim 1200XL.

97

$61


PALNTSC
0: PAL-Fernsehsystem 1: NTSC

98

$62


AKTCHRNUM
Diese Variable enthält die aktive Cursorposition innerhalb einer logischen Zeile.

99

$63


ADDRESS

100

$64


101

$65

MLTTMP

102

$66


103

$67

SAVEADR

104

$68

Recht häufig intern benutzte Zwischenspeicher für vielfältige Aufgaben.

105

$69


RAMTOP
Dieses Register hält die Anzahl der im Computer insgesamt zur Verfügung stehenden RAMPages.

106

$6a


AKTBUFLEN
Hier steht die momentane Größe der aktuellen logischen Zeile.

107

$6b


BUFSTR

108

$6c

GETCHARACTER-Pointer des Editors.

109

$6d


BITMASK
Register für die Verwaltung logischer Zeilen.

110

$6e


SHFAMT
Ebenfalls für GETCHAR benötigtes Hilfsregister.

111

$6f


PLOTROWAC

112

$70


113

$71

PLOTCOLAC

114

$72


115

$73

ENDPOINTR

116

$74


117

$75

DELTAROW

118

$76

DELTACOL

119

$77

Diese Register werden zusammen mit den zwei weiter hinten stehenden Registern ROWINC und COLINC zur Berechnung von Grafik benutzt (z.B. DRAWTO).

120

$78


KEYDEFPTR

121

$79

Dieser Pointer zeigt auf die Tabelle zur Wandlung von Tastaturkode nach ATASCII.

122

$7a


SWAPFLAG
Ungleich Null zeigt dieses Flag an, daß der Bildschirmvariablenbereich auf Grafik eingestellt ist, Null signalisiert, daß die Variablen für den Bildschirmbereich Referenzen auf Texte darstellen.

123

$7b


HOLDCHAR

124

$7c

INSDATA

125

$7d

COUNTER

126

$7e

Ebenfalls alles interne Hilfsvariable für die Verwaltung des Bildschirms.

127

$7f


LOWMEM

128

$80

Dieser Zeiger weist auf die unterste Adresse, die nicht mehr für Betriebssystemzwecke verwendet wird.

129

$81


CHECKSUM

139

$8b

In diesen zwei Byte wird die Prüfsumme über Speicherbereiche gebildet. Da diese Checksumme nur bei der Initialisierungsphase benötigt wird, kann der Wert nach dem Kaltstart zerstört werden.

140

$8c


DLIVKT

512

$200

Vektor für die ANTIC-Programm- Unterbrechung. Wenn eine ANTIC-Programm-Unterbrechung ausgelöst wird, wird ein Unterbrechungsprogramm, dessen Adresse in diesen beiden Speicherstellen steht, ausgeführt.

513

$201


VPRECEDE

514

$202

Ansprungvektor für von PORT A ausgelösten Interrupt, der eine SERIAL-BUS-PROCEED-Unterbrechung darstellt.

515

$203


VINTERRUP

516

$204

Der Interrupt von PORT B signalisiert eine Unterbrechungsanforderung für die serielle Übertragungsunterbrechung. Die letzten beiden Interruptvektoren werden normalerweise vom System ignoriert, da die angeschlossenen Geräte keine Interrupts erzeugen. Die Leitungen sind für spätere Erweiterungen eingeplant.

517

$205


VBREAK

518

$206

Die hier stehende Einsprungadresse wird verwendet, wenn die CPU eine BRK-Instruktion ausführt.

519

$207


VKEYBOARD

520

$208

Vektor für den Fall, daß eine normale Taste gedrückt wurde.

521

$209


VSERIELIN

522

$20a

Es liegt ein Zeichen im SERIN-Register von der seriellen Schnittstelle an.

523

$20b


VSERREADY

524

$20c

Das SEROUT-Register ist bereit, ein weiteres Zeichen aufzunehmen.

525

$20d


VSERCLOSE

526

$20e

Das parallel/seriell-Wandlungsregister ist leer und die Übertragung wird vom POKEY aus beendet.

527

$20f


VTIMER1

528

$210

Signalisiert der POKEY, daß sein Zählerregister 1 auf Null gegangen ist, wird dieser Vektor angesprungen.

529

$211


VTIMER2

530

$212

Hier wird hingesprungen, wenn der POKEY im Interrupt signalisiert, daß sein Kanal 2 auf Null heruntergezählt hat.

531

$213


VTIMER4

532

$214

Erkennt die Interruptroutine beim POKEY, daß Timer 4 auf Null gezählt hat und ist der entsprechende Interrupt zugelassen, so wird dieser Vektor angesprungen.

533

$215


VIMMEDIRQ

534

$216

Hier steht die Adresse des eigentlichen Interrupthandlers, der erst die Verteilung auf die einzelnen Interruptquellen vornimmt.

535

$217


TIMCOUNT1

536

$218

Software-Timer 1. Der Wert wird bei jedem Vertical-Blank-Interrupt decrementiert. Ist er danach Null, so wird die bei (TIMER1VKT) stehende Routine ausgeführt.

537

$219


TIMCOUNT2

538

$21a

Dies ist ein ähnlicher Softwaretimer wie TIMCOUNT1, nur mit der Einschränkung, daß das Zählen dieses und der folgenden drei Zähler unterbleibt, wenn CRITICIO gesetzt ist.
Wird TIMCOUNT2 Null, so wird die bei (TIMER2VKT) stehende Routine ausgeführt.

539

$21b


TIMCOUNT3

540

$21c

Für diesen Zähler gilt das gleiche wie für TIMCOUNT2, nur daß kein Vektor beim Nullwerden angesprungen wird, sondern lediglich Flag TIMER3SIG gesetzt wird.

541

$21d


TIMCOUNT4

542

$21e


543

$21f

TIMCOUNT5

544

$220

Es gilt das gleiche wie für TIMCOUNT3. Beim Nullwerden des entsprechenden Zählers werden analog dazu die Flags TIMER4SIG respektive TIMER5SIG gesetzt.

545

$221


VBLKIVKT

546

$222

Dieser Vertical-Blank-Immediate-Vektor wird beim Strahlrücklaufinterrupt immer als erste Unterbrechungsroutine angesprungen.

547

$223


VBLKDVKT

548

$224

Dieser Vertical-Blank-Deferred-Vektor wird von der bei VBLKIVKT stehenden Routine aus angesprungen, wenn CRITICIO gelöscht ist. Die Routine existiert im Normalfall nicht und ist frei vom Benutzer programmierbar.

549

$225


TIMER1VKT

550

$226

Ansprungvektor für die User-Routine, die ausgeführt werden soll, wenn TIMCOUNT1 auf Null gegangen ist.

551

$227


TIMER2VKT

552

$228

Ansprungvektor für die Behandlungsroutine bei Nullwerden des TIMCOUNT2.

553

$229


TIMER3SIG
Dieses Flag ist Null, wenn TIMCOUNT3 nicht Null ist, sonst $ff.

554

$22a


SRTIMER
Wesentlicher, intern benutzter Timer für die Tasaturentprellung, Warten bis zum ersten Autorepeat und danach Bestimmen der Autorepeat-Rate.

555

$22b


TIMER4SIG
Dieses Flag ist Null, wenn TIMCOUNT4 nicht Null ist, sonst $ff.

556

$22c


IANTEMP
Temporäres Hilfsregister.

557

$22d


TIMER5SIG
Dieses Flag ist Null, wenn TIMCOUNT5 nicht Null ist, sonst $ff.

558

$22e


DMACNTL@
Schattenregister von DMACNTL. DMACNTL schaltet die einzelnen Arten des DMA ein.

559

$22f


DLPTR@

560

$230

Schattenregister des Zeigers auf das ANTICProgramm. Der Anfang des ANTIC-Programms muß in dieser Speicherstelle stehen, wenn mit dem Betriebssystem gearbeitet wird.

561

$231


SKCNTL@
Steuerung der seriellen Übertragung, des Ablesens der Tastatur und des Ablesens der POT-Eingänge.

562

$232


LCOUNT
Bytezähler für Loader-Routinen.

563

$233


LPENH@
Schattenregister, Horizontalposition des Lightpens.

564

$234


LPENV@
Schattenregister, Vertikalposition des Lightpens.

565

$235


VBREAKKEY

566

$236

Dies ist der Vektor für die BREAK-TastenVerarbeitung. Nicht verwechseln mit VBREAK, der die BRK-Instruktion der CPU behandelt!

567

$237


NEUIOINIV

568

$238

Vektor zur Initialisierungsroutine noch nicht existenter Hardware. Siehe dazu die Betriebssystembeschreibung!

569

$239


CMDDEVIV

570

$23a

CMDCMD

571

$23b

CMDAUX1

572

$23c

CMDAUX2

573

$23d

CMDAUX3

574

$23e

ERRORFLAG
Interne Hilfsvariablen für die Serielldatenverarbeitung.

575

$23f


DSKFLAG

576

$240

DSKSECCNT

577

$241

DSKLDADR

578

$242

Interne Hilfsvariablen für die reine Diskettenverarbeitung.

579

$243


COLDSTART
Wird dieses Flag vom Benutzerprogramm auf einen Wert ungleich Null gesetzt, so erfolgt beim Einsprung in die Warmstartroutine ein Kaltstart.

580

$244


DSKTIMCON
Kontrollregister für die Diskettenverarbeitung. Ein Wert ungleich Null besagt, daß ein Timeout aufgetreten ist.

582

$246


NEUVORHDN
Flag nur für den internen Gebrauch. Ist zu setzen, wenn externe Geräte am Parallelbus angeschlossen sind. Wird von der dazu mitgelieferten Boot-Software benutzt. Muß im Normalfall Null sein, da sonst das System abstürzen kann!

583

$247


NEUIODREQ
Auch dieses Flag wird vom Kaltstartprogramm für die Verwaltung der noch zu entwickelnden Hardware benutzt. Es enthält die Adresse des gerade angeprochenen Devices.

584

$248


NEUIOMASK

585

$249

NEULDTMP1

586

$24a

Diese Adressen werden ebenfalls nur dann sinnvoll benutzt, wenn Zusatzhardware am Parallelbus anliegt. Sie dürfen deshalb trotzdem nicht für neue Software verwendet werden.

587

$24b


CHARSTPTR
Ein-Byte-Pointer für interne Monitorverarbeitung.

619

$26b


FINESCROL
Temporäres Flag für die Verarbeitung des feinen Scrollings, wobei nicht gleich eine komplette Zeile verschoben wird, sondern die Zeile Punktweise nach oben gesetzt wird.

620

$26c


KBDISABLE
Besitzt dieses Flag einen Wert ungleich Null, sind Eingaben von der Tastatur nicht mehr möglich.

621

$26d


FINESCRFL
Wie FINESCROL für die Bildverschiebung verantwortlich.

622

$26e


GTIACNTL@
Schattenregister für Steuerung des GTIA und Priorität der Spieler und Geschosse.

623

$26f


PADDL0@

624

$270

PADDL1@

625

$271

PADDL2@

626

$272

PADDL3@

627

$273

PADDL4@

628

$274

PADDL5@

629

$275

PADDL6@

630

$276

PADDL7@
Schattenregister, enthalten die Werte der Paddle-Eingänge. Beim Atari 600XL und 800XL sind nur die Paddle-Eingänge 0 bis 3 benutzt, die Nummern 4 bis 7 werden von 0 bis 3 kopiert.

631

$277


JOYSTICK0

632

$278

JOYSTICK1

633

$279

JOYSTICK2

634

$27a

JOYSTICK3
Diese Register enthalten die Stellung der Joysticks (soweit angeschlossen). Bei den neuen Atari-Modellen sind jedoch nur noch zwei Joysticks vorhanden ("0" und "1"), die beiden anderen werden kopiert.

635

$27b


PTRIG0@

636

$27c

PTRIG1@

637

$27d

PTRIG2@

638

$27e

PTRIG3@

639

$27f

PTRIG4@

640

$280

PTRIG5@

641

$281

PTRIG6@

642

$282

PTRIG7@
Auslösetasten der Paddles ("0" meldet Taste gedrückt, "1" meldet Taste nicht gedrückt). Da bei den neuen Atari-Geräten nur noch 4 Paddles anzuschließen sind, werden bei diesen nur PADDLE0 bis PADDLE3 sinnvoll verwendet, die anderen werden kopiert.

643

$283


TRIG0@

644

$284

TRIG1@

645

$285

TRIG2@

646

$286

TRIG3@
Auslösetasten der Joysticks beziehungsweise Schattenregister der GTIA-Register für die Triggereingänge ("0" meldet Taste gedrückt, "1" meldet Taste nicht gedrückt). Bei den neuen Atari-Geräten sind nur TRIG0 und TRIG1 mit Joystick-Ports verbunden, die anderen zwei Werte sind Kopien der ersten beiden.

647

$287


HIBYTELD
Zwischenregister für den LOADER.

648

$288


WRITEMODE
Flag für die Cassettenverarbeitung. Es zeigt an, ob die momentane Operation ein Schreiben ($80) oder Lesen ($00) beinhaltet. Nur für internen Gebrauch.

649

$289


CASBUFLIM

650

$28a

Wert des Pufferendes für Cassettenoperationen.

651

$28b


NEUIOPTR

652

$28c

Pointer auf die Startadresse der I/O-Verarbeitung der neuen Hardwarezusätze am parallelen Bus.

653

$28d


NEWADRLOD

654

$28e

Ladeadresse für I/O mit der neuen Zusatzhardware.

655

$28f


TEXTROW

656

$290

TEXTCOL

657

$291


658

$292

TEXTINDEX

659

$293

TEXTMSC

660

$294


661

$295

TEXTOLD

662

$296


663

$297

TEXTGRAD
Variablen zur Verarbeitung von Text/Grafikgemischten Bildschirminhalten.

666

$29a


CRETRY
Dies ist die Maximalzahl der Wiederholungen des Versuches, ein Kommando auf einem sich zurückmeldenen Gerät abzusetzen. Der Wert steht auf 1, so daß eine Wiederholung stattfindet. Mehr ist hierbei auch nicht sinnvoll, denn es ist davon auszugehen, daß ein Gerät, das sich ordentlich zurückmeldet, im Normalfall auch in der Lage ist, ein richtiges Kommando auszuführen. Gelingt dies nicht, sind das Kommando oder aber Voraussetzungen für die richtige Ausführung nicht in Ordnung.

667

$29c


SUBTEMP

668

$29e

HOLD2
Hilfsvariablen für interne Verwendung.

669

$29f


DISPLYMSK

670

$2a0

TEMPLBT

671

$2a1

ESCAPEFLAG
Weitere Variablen zur reinen Textverarbeitung mit Screen oder Editor.

672

$2a2


TABMAP

673

$2a3


bis

bis

Tabelle, in der jedes einzelne Bit eine Cursorposition innerhalb einer logischen Zeile auf dem Bildschirm darstellt. Ist ein Bit gesetzt, so gilt diese Position als Tabulator-Haltestelle.

689

$2b1


LOGICMASK

690

$2b2


bis

bis

Tabelle für die Zusammenhänge von logischer und physikalischer Zeile auf dem momentan angezeigten Bildschirm. Wird intern benötigt, um beim Löschen einer Zeile immer eine komplette logische Zeile löschen zu können.

693

$2b5


XORKEYMSK
Diese Variable wird verwendet, um die Funktionalität von Tastengruppen der Tastatur abändern zu können.
Jedes gesetzte Bit in diesem Byte gibt an, daß das entsprechende, vom POKEY gelieferte Datenbit aus dem Tastaturkode invertiert werden soll. So können ganze Tastaturreihen in andere umgewandelt werden. Es muß im Einzelnen herausgefunden werden, in wieweit diese Funktion gewinnbringend eingesetzt werden kann. Es ist jedoch zu beachten, daß diese Invertierung der jeweiligen Bits mit dem Tastaturkode geschieht, also bevor der gelesene Wert in einen ATASCII-Wert umgewandelt wird.

694

$2b6


DRETRY
Hier steht die Anzahl, mit der der Versuch wiederholt wird, ein spezifiziertes Gerät anzusprechen. Der Wert ist im Normalbetrieb auf 13 Wiederholungen eingestellt.

701

$2bd


SHIFTLOCK
Dieses Label gibt Auskunft darüber, ob irgendwelche Sonderbedingungen bei der Eingabe zu beachten sind:
$00: Kleinbuchstaben aktiv (Schreibmaschinenmodus)
$40: Nur Großbuchstaben (Normalmodus)
$80: CONTROL-Taste gedrückt.

702

$2be


NUMNXTLIN
Dieses Register beinhaltet die Anzahl der auf dem Bildschirm verarbeiteten Textzeilen.
Das Register kann die Werte 24, 4 oder 0 annehmen, andere werden vom Betriebssystem ignoriert.

703

$2bf


COLPM0@

704

$2c0

COLPM1@

705

$2c1

COLPM2@

706

$2c2

COLPM3@
Schattenregister der Farbregister für die Spieler beziehungsweise Geschosse.

707

$2c3


COLPF0@

708

$2c4

COLPF1@

709

$2c5

COLPF2@

710

$2c6

COLPF3@

711

$2c7

COLBAK@
Schattenregister der Farbregister für die Spielfeldfarben beziehungsweise des Hintergrundes.

712

$2c8


RUNADRLOD

713

$2c9


714

$2ca

HIUSEDLOD

715

$2cb


716

$2cc

LODZHIUSE

717

$2cd


718

$2ce

LODGBYTEA

719

$2cf


720

$2d0

LODADRESS

721

$2d1


722

$2d2

LODZLOADA

723

$2d3

Diese Variablen werden für interne Verwaltungsaufgaben beim Programmladen der später einmal am hinteren parallelen Bus anzuschließenden Hardware verwendet.

724

$2d4


DSKSECLEN

725

$2d5

Dieser Wert kann normalerweise $0080 oder $0100 sein, je nach Diskettenformat.

726

$2d6


ACMISR

727

$2d7

Findet interne Verwendung.

728

$2d8


KEYRPDELY
Dieser Wert bestimmt die Zeit zwischen dem Drücken einer Taste und dem ersten Zeichen des Autorepeat. Standardwert ist 40.

729

$2d9


KEYREP
Im Gegensatz zu KEYRPDELY bestimmt dieser Wert bei einsetzendem Autorepeat die Wiederholrate nach dem ersten Auto-Zeichen. Standardwert ist 5.

730

$2da


CLICKDISA
Wenn ungleich Null, ist der Tastaturklick abgeschaltet.

731

$2db


HELPFLAG
Dieses Register ist beim 600XL/800XL 'Entwicklungsschrott', da es angibt, ob die in diesen Geräten nicht eingebaute HELP-Taste gedrückt ist. Darf trotzdem nicht verwendet werden, da unter Umständen Schreibzugriffe darauf programmiert sind.

732

$2dc


DMASAVE
Statusinformation des Direkten Speicherzugriffs. Hat für normalen Benutzer keinen Nutzen, darf aber nicht anderweitig benutzt werden.

733

$2dd


PRTBUFPTR
Gibt Bytenummer innerhalb des Printerpuffers an.

734

$2de


PRTBUFSIZ
Ist maximale Printerpuffergröße in Byte.

735

$2df


RAMSIZE
Anzahl der zur Verfügung stehenden RAM-Pages des Systems.

740

$2e4


MEMTOP

741

$2e5

Dies ist ein Zeiger auf die Obergrenze des vom Benutzer verwendbaren Speicherraumes. Darüber liegt im Normalfall der Bildschirm.

742

$2e6


MEMLO

743

$2e7

Dies ist der Zeiger auf die Untergrenze des vom Benutzer frei zu verfügenden Speicherraumes. Er liegt normalerweise direkt über den Betriebssystemvariablen, respektive dem DOS, eventuell noch mit DUP.

744

$2e8


HNDLRLOAD

745

$2e9

DEVICSTAT

746

$2ea


747

$2eb

CHAINTMP

748

$2ec

Hilfsvariablen für den internen Gebrauch bei der Verwaltung linearer Listen und darüber laufender Ladevorgänge mit noch nicht existenter Hardware.

749

$2ed


CASSPEED

750

$2ee

Zeitwerte für die Senderate über Cassette.

751

$2ef


CURSORINH
Auf einem Wert ungleich Null, verhindert diese Variable die Anzeige des Cursors.

752

$2f0


KEYDELAY
Dieser Wert, der standardmäßig auf 3 eingestellt ist, bestimmt die Zeit zwischen dem Loslassen einer Taste und dem Drücken einer neuen Taste, so daß deren Kode übernommen wird. Bei extrem schnellen 'Tippern' (und 'Tipperinnen') sollte dieser Wert verkleiner werden. Das verhindert Ärger mit fehlenden Zeichen beim Programmieren.

753

$2f1


CHARCNTL@
Schattenregister, steuert das Aussehen der Zeichen in mehreren Schrift-Modi des ANTIC.

755

$2f3


CHARBASE@
Schattenregister, enthält Basisadresse des Zeichengenerators (oberes Byte)

756

$2f4


NEWGRROW

757

$2f5

NEWGRCOL

758

$2f6

Hier werden die Werte für einen DRAWTO-Befehl vor dessen Aufruf festgelegt.

759

$2f7


ROWINC

760

$2f8

COLINC

761

$2f9

Diese Variablen werden zum Berechnen der Bahnen eines DRAWTO benutzt.

762

$2fa


ATASCICHR
Letztes eingegebenes Zeichen im ATASCII-Kode. Fast ausschließlich für interne Zwecke benutzt.

763

$2fb


KBCODE@
Schattenregister, enthält den Tastaturcode, das heißt, welche Taste gedrückt wurde.

764

$2fc


FILEDAT
Für die interne Benutzung des Grafiksystems reserviert.

765

$2fd


DISPLYFLG
Ist dieses Flag ungleich Null, so wird das folgende Zeichen, wenn es ein Kontrollzeichen ist, nicht ausgeführt, sondern der entsprechende ATASCII-Kode ausgegeben.

766

$2fe


STARTSTOP
Ist dieses Byte gleich $ff, so storniert die Bildschirmausgabe, bei $00 geht sie weiter. das Flag wird durch Drücken von CONTROL & '1' verändert. Wichtig ist, daß bei der momentanen Betriebssystemimplementierung das System 'steht', wenn es auf das Nullwerden von STARTSTOP wartet. Nur wesentliche Interrupts werden durchgelassen, die eigentliche Rechenarbeit wird jedoch ebenfalls mit dem Output angehalten.

767

$2ff


Im Folgenden werden die wesentlichen vom Disk-Handler benutzten Variablen beschrieben. Sie sind größtenteils bei Diskettenverarbeitung selbst zu belegen, es sei denn, die Programmierung erfolgt in einer höheren Sprache, wie zum Beispiel BASIC oder PASCAL.

DSKDEVICE
Allgemeiner Erkennungskode für die Disketten($30) beziehungsweise Cassettenstation ($60).

768

$300


DSKUNIT
Bei Diskettenverarbeitung die Nummer der anzusprechenden Diskettenstation.
Erlaubt sind hier Werte im Bereich von $01 bis $09, wobei bei der heutigen Hardware nur $01 bis $04 sinnvoll, weil kaufbar sind.

769

$301


DSKCMD
Auszuführendes Kommando. Siehe dazu ZeropageIOCBs ab IOCBCHIDZ.

770

$302


DSKSTATUS
Zurückgemeldeter Status der Operation. Siehe dazu ebenfalls IOCBSTATZ.

771

$303


DSKBUFFER

772

$304

Anfangsadresse des Datenpuffers.

773

$305


DSKTIMOUT

774

$306

Anzahl der Sekunden bis zur TimeoutFehlermeldung.

775

$307


DSKBYTCNT

776

$308

Anzahl der im Puffer ab DSKBUFFER zur Verfügung stehenden Bytes.

777

$309


DSKAUX1

778

$30a

DSKAUX2 Hilfsinformationen für die Diskettenverarbeitung. Bei OPEN-Befehlen stehen hier besondere Merkmale (z.B. Nur-Lese-Zugriff).
Bei Schreib- beziehungsweise Leseoperationen steht hier in DSKAUX1 und -2 die Blocknummer von $01 bis MAXBLOCK.

779

$30b


INTERVTI1

780

$30c

Intervalltimer 1, bildet mit INTERVTI2 eine Einheit.

781

$30d


OPTIONJMP
Diese Adresse ist offiziell von Atari als belegt gekennzeichnet, ist jedoch nirgendwo im Betriebssystem verwendet. Sie soll für spätere Hardware irgendeine Vorentscheidung treffen. Es empfiehlt sich im Hinblick auf spätere Softwarekompatibilität, diese Variable nicht zu verwenden.

782

$30e


CASFLAG
Ist dieses Flag nicht Null, handelt es sich um eine Cassettenoperation. Nur für internen Gebrauch.

783

$30f


INTERVTI2

784

$310

INTERVTI1 und -2 werden benutzt, um die Lesegeschwindigkeit bei Cassettenoperationen zu bestimmen.

785

$311


CHAINTP1

786

$312

Hilfspointer für lineare-Listenverwaltung.

787

$313


PTIMOUT
Timeoutwert für Druckbefehle.

788

$314


TIMEFLAG
Timeoutwert für die Lesegeschwindigkeitsbestimmung.

791

$317


STACKSAVE
Hilfsregister für das Retten des Stackpointers bei SIO-Operationen.

792

$318


TEMPSTAT
Register für kurzzeitiges Zwischenspeichern von SIO-Statusinformationen.

793

$319


HATABS

794

$31a


bis

bis

Tabelle für die Zuordnung von Geräten zu deren Handlern. Jeder Tabelleneintrag besteht aus drei Byte: Dem Namen (1) und der Handlertabellenstartadresse (2). Es sind die Geräte Cassette, Editor, Screen, Drucker und Keyboard vorgegeben. Ein Eintrag ist dann leer, wenn sein Name Null ist.

831

$33f


IOCB0

832

$340


bis

bis

Ab dieser Adresse stehen 8 IOCB-Einträge zur Verfügung, von denen Eintrag 0 bereits vom System für die Editorverarbeitung verwendet
wird. Die einzelnen Einträge bitte aus der Zeropage-IOCB-Beschreibung ersehen, die ab IOCBCHIDZ steht. Bei Verwendung eines dieser IOCBs wird davor der Inhalt aus diesen Registern in die Zeropage kopiert, um sie danach wieder zurückzutransportieren.

847

$34f

IOCB1

848

$350


bis

bis


863

$35f

IOCB2

864

$360


bis

bis


879

$36f

IOCB3

880

$370


bis

bis


895

$37f

IOCB4

896

$380


bis

bis


911

$38f

IOCB5

912

$390


bis

bis


927

$39f

IOCB6

928

$3a0


bis

bis


943

$3af

IOCB7

944

$3b0


bis

bis


959

$3bf


PRINTBUF

960

$3c0


bis

bis

Hier liegt der Printerpuffer für die Ausgabe an den Drucker über die serielle Schnittstelle.

999

$3e7


SUPERFLAG
Hilfsinformation für Editor.

1000

$3e8


STARTTST
Dieses Flag liefert einen Wert ungleich Null, wenn beim Kaltstart die START-Taste gedrückt war.

1001

$3e9


CASSTART
Flag, ob gerade von Cassette gebootet wird und ob die dort gelesene Init-Adresse angesprungen werden soll.

1002

$3ea


CARTCKSUM

1003

$3eb

Checksumme des Cartridge mit dem Anfang des ROMs bei $C000.

1004

$3ec


ACMVAR

1005

$3ed


bis

bis

Hilfsvariablen für interne Zwecke.

1015

$3f7


X64KBFLAG
Flag, ob die obersten 16KByte RAM oder ROM sind.

1016

$3f8


MINTLK
Hilfsregister, nicht benutzen.

1017

$3f9


TRIG3@
Dies ist eine Kopie des Registers TRIG3, das normalerweise nur durch einen Eingang beeinflußt wird. Wird ein ROM-Modul eingesteckt ($01) oder entfernt ($00), so ändert sich der Wert von TRIG3. Wird zur Feststellung benutzt, ob es sich um einen Kalt- oder Warmstart handelt.

1018

$3fa


CHAINLINK

1019

$3fb

Pointer zur Verarbeitung linearer Listen, wenn sie eingesetzt werden; also nur bei Verwendung spezieller, noch nicht auf dem Markt befindlicher Hardware.

1020

$3fc


CASBUFFER

1021

$3fd


bis

bis

Pufferbereich für die Cassettendatenübertragung, wobei die drei ersten Byte nur für die Synchronisation und Feststellung der Datentypen und -menge gelten. Der eigentliche Datenpuffer beginnt ab Adresse 1024 ($400) und geht bis zum Ende von CASBUFFER.

1151

$47f

An dieser Stelle sind die Variablen des Betriebssystems beendet. Sicherlich werden noch diverse andere Speicherstellen in der Zeropage und im Bereich über $0480 benutzt. Da diese Benutzung jedoch auf BASIC, DOS oder andere Software beschränkt ist, wird an dieser Stelle nicht weiter darauf eingegangen.


GTIA - Adressbereich

Im Weiteren folgen die Hardwareadressen von GTIA, POKEY, PIA und ANTIC:

HPOSP0 (W)

53248

$d000

HPOSP1 (W)

53249

$d001

HPOSP2 (W)

53250

$d002

HPOSP3 (W)

53251

$d003

HPOSM0 (W)

53252

$d004

HPOSM1 (W)

53253

$d005

HPOSM2 (W)

53254

$d006

HPOSM3 (W)
Horizontalpositionen der Spieler (HPOSPn) beziehungsweise der Geschosse (HPOSMn).

53255

$d007


KOLM0PF (R)

53248

$d000

KOLM1PF (R)

53249

$d001

KOLM2PF (R)

53250

$d002

KOLM3PF (R)
Kollisionsregister für Zusammenstöße zwischen den Geschossen und dem Spielfeld.

53251

$d003


KOLP0PF (R)

53252

$d004

KOLP1PF (R)

53253

$d005

KOLP2PF (R)

53254

$d006

KOLP3PF (R)
Kollisionsregister für Zusammenstöße zwischen den Spielern und dem Spielfeld.

53255

$d007


SIZEP0 (W)

53256

$d008

SIZEP1 (W)

53257

$d009

SIZEP2 (W)

53258

$d00a

SIZEP3 (W)

53259

$d00b

SIZEM (W)
Größen der Spieler (SIZEPn) und der Geschosse (SIZEM).

53260

$d00c


KOLM0PL (R)

53256

$d008

KOLM1PL (R)

53257

$d009

KOLM2PL (R)

53258

$d00a

KOLM3PL (R)
Kollisionsregister für Zusammenstöße zwischen Geschossen und Spielern.

53259

$d00b


GRAFP0 (W)

53261

$d00d

GRAFP1 (W)

53262

$d00e

GRAFP2 (W)

53263

$d00f

GRAFP3 (W)

53264

$d010

GRAFM (W)
Grafikregister der Spieler (GRAFPn) beziehungsweise der Geschosse (GRAFM).

53265

$d011


KOLP0PL (R)

53260

$d00c

KOLP1PL (R)

53261

$d00d

KOLP2PL (R)

53262

$d00e

KOLP3PL (R)
Kollisionsregister für Zusammenstöße zwischen Spielern.

53263

$d00f


TRIG0 (R)

53264

$d010

TRIG1 (R)

53265

$d011

TRIG2 (R)

53266

$d012

TRIG3 (R)
Register zum Abfragen der Triggereingänge des GTIA (Schattenregister dazu ab 644 beziehungsweise $284).

53267

$d013


COLPM0 (W)

53266

$d012

COLPM1 (W)

53267

$d013

COLPM2 (W)

53268

$d014

COLPM3 (W)
Farben der Spieler beziehungsweise der Geschosse (Schattenregister dazu ab 704 beziehungsweise $2c0).

53269

$d015


COLPF0 (W)

53270

$d016

COLPF1 (W)

53271

$d017

COLPF2 (W)

53272

$d018

COLPF3 (W)

53273

$d019

COLBAK (W)
Farben des Spielfeldes (COLPFn) und des Hintergrundes (COLBAK), Schattenregister dazu ab 708 beziehungsweise $2c4.

53274

$d01a


GTIACNTL (W)
Steuert den GTIA, bestimmt Prioritätsfolge zwischen Bildelementen und steuert Darstellung der Spieler und Geschosse.

53275

$d01b


VDELAY (W)
Ermöglicht es, Spieler und Geschosse um einzelne Bildzeilen zu verschieben, wenn zweizeilige Auflösung der Player-Missile-Grafik gewählt wurde.

53276

$d01c


PMCNTL (W)
Schaltet Spieler und Geschosse ein; ermöglicht es, den Status der Triggereingänge festzuhalten.

53277

$d01d


HITCLR (W)
Wenn in dieses Register irgendein Wert geschrieben wird (wenn diese Adresse im Schreibzugriff angesprochen wird), werden alle Kollisionsregister gelöscht.

53278

$d01e


CONSOL (W/R)
Dieses Register wird verwendet, um den Status der Konsolentaster ("START", "SELECT" und "OPTION") abzufragen.

53279

$d01f


NEUPORT-Adressbereich

NEUPORT
Dieses Register dient der I/O-Erweiterung. Siehe Betriebssystembeschreibung!

53759

$d1ff


POKEY-Adressbereich

AUDIFREQ1 (W)

53760

$d200

AUDIFREQ2 (W)

53761

$d201

AUDIFREQ3 (W)

53762

$d202

AUDIFREQ4 (W)
Diese Register bestimmen die Frequenz der Tongeneratoren.

53763

$d203


AUDICNTL1 (W)

53764

$d204

AUDICNTL2 (W)

53765

$d205

AUDICNTL3 (W)

53766

$d206

AUDICNTL4 (W)
Diese Register steuern die einzelnen Tongeneratoren. Mit diesen Registern bestimmt man jeweils für einen Tongenerator die Lautstärke, Verzerrungen beziehungsweise den VOLUME_ONLY-Modus.

53767

$d207


POT0 (R)

53760

$d200

POT1 (R)

53761

$d201

POT2 (R)

53762

$d202

POT3 (R)

53763

$d203

POT4 (R)

53764

$d204

POT5 (R)

53765

$d205

POT6 (R)

53766

$d206

POT7 (R)
Diese Register enthalten den Wert der POTEingänge des POKEY. Bei den neuen AtariGeräten werden nur noch die POT-Eingänge 0 bis 3 verwendet, da auch nur noch zwei Joystick-Ports zur Verfügung stehen. Die vier verbleibenden Register beinhalten Kopien der ersten vier.

53767

$d207


AUDICOM (W)
Dieses Register steuert die Tonerzeugung im Atari. Mit diesem Register werden vor allem die Grundfrequenzen für die vier Tonkanäle eingestellt und Hochtonfilter ein- beziehungsweise ausgeschaltet.

53768

$d208


POTSTAT (R)
Mit diesem Register läßt sich bestimmen, ob für einen bestimmten POT-Eingang die AnalogDigital-Wandlung bereits abgeschlossen ist. Wenn ein Bit von POTSTAT '0' ist, bedeutet dies, daß der Wert des dazugehörigen POTEingang gültig ist. Die Bits sind folgendermaßen zugeordnet:

53768

$d208

	Bit 0 :        POT-Eingang 0
	Bit 1 :        POT-Eingang 1
	Bit 2 :        POT-Eingang 2
	  .              .
	  .              .
	Bit 7 :        POT-Eingang 7

STIMER (W)
Durch Ansprechen dieser Adresse in einem Schreibzugriff werden die Audio-FrequenzTeiler auf ihre "AUDIFREQ"-Werte zurückgesetzt.

53769

$d209


KBCODE (R)
Dieses Register enthält den Tastaturcode, das heißt, der Benutzer kann hier abfragen, welche Taste gedrückt ist (Schattenregister bei 764 beziehungsweise $2fc).

53769

$d209


SKSTATRES (W)
Durch Eintragen irgendeines Wertes in dieses Register werden die Bits 7,6 und 5 von SKSTAT gelöscht.

53770

$d20a


RANDOM (R)
Dieses Register enthält eine "quasi"-zufällige Zahl (8 Bit), die aus einem 17- beziehungsweise 9-Bit-Polynom-Zähler stammt.

53770

$d20a


POTGO (W)
Durch Eintragen irgendeines Wertes in dieses Register wird der Ablesevorgang der POTEingänge gestartet.

53771

$d20b


SEROUT (W)
Ausgaberegister der seriellen Schnittstelle.

53773

$d20d


SERIN (R)
Eingaberegister der seriellen Schnittstelle.

53773

$d20d


IRQEN (W)
Die Bits in diesem Register schalten die einzelnen Arten zur Auslösung eines IRQ ein beziehungsweise aus.

53774

$d20e


IRQSTAT (R)
Nach dem Auftreten eines IRQ kann man durch Abfragen dieses Registers die Herkunft der Unterbrechungsanforderung bestimmen.

53774

$d20e


SKCNTL (W)
Durch dieses Register lassen sich die einzelnen Betriebsmodi der seriellen Schnittstelle, der POT-Wert-Wandlung und der Tastatur-Abfrage wählen (Schattenregister bei 562 beziehungsweise $262).

53775

$d20f


SKSTAT (R)
Dieses Register enthält Angaben zum Status der seriellen Schnittstelle sowie der Tastatur. Die Bit 7,6 und 5 werden mit SKSTATRES (53770 beziehungsweise $d20a) zurückgesetzt.

53775

$d20f


PIA-Adressbereich

PORTA (R/W)
Übertragungsregister "A" der PIA.

54016

$d300


PORTB (R/W)
Übertragungsregister "B" der PIA.

54017

$d301


PORTACNTL
Steuer- und Statusregister für den PIA-Port "A".

54018

$d302


PORTBCNTL
Steuer- und Statusregister für den PIA-Port "B".

54019

$d303


ANTIC-Adressbereich

DMACNTL (W)
Mit diesem Register kann man den DMA des ANTIC steuern (Schattenregister bei 559 beziehungsweise $22f).

54272

$d400


CHARCNTL (W)
Mit diesem Register kann man das Aussehen der Zeichen in mehreren ANTIC-Modi beeinflußen (Schattenregister bei 755 beziehungsweise $2f3).

54273

$d401


DLPTRL

54274

$d402

DLPTRH
In diesen beiden Registern steht die 16-BitAdresse des ANTIC-Programms (Schattenregister bei 560/561 beziehungsweise $230/$231). Dies ist also der Zeiger auf das ANTIC-Programm.

54275

$d403


HSCROL (W)
Mit diesem Register bestimmt man, um wieviele Farbtakte ein bestimmter Teil des Bildes nach rechts verschoben werden soll. Zu verschiebende Zeilen müssen im ANTIC-Programm gekennzeichnet werden.

54276

$d404


VSCROL (W)
Mit diesem Register bestimmt man, um wieviele Bildzeilen ein bestimmter Teil des Bildes nach oben geschoben werden soll. Die zu verschiebenden Zeilen müssen im ANTIC-Programm gekennzeichnet werden.

54277

$d405


PMBASE (W)
In dieses Register bringt man die oberen acht Bits der Basisadresse des Speicherfeldes für die Player-Missile-Grafik.

54279

$d407


CHARBASE (W)
In dieses Register müssen die oberen 8 Bits der Basisadresse des Zeichengenerators gebracht werden (Schattenregister bei 756 beziehungsweise $2f4).

54281

$d409


WAITHSYNC (W)
Durch Ansprechen dieses Registers wird die CPU bis zum Beginn der nächsten Horizontalsynchronisation angehalten.

54282

$d40a


VCOUNT (R)
Dieses Register enthält die Nummer der Bildzeile, die gerade erzeugt wird, geteilt durch zwei.

54283

$d40b


LPENH (R)
Dieses Register enthält die Horizontalposition des Lightpens (Schattenregister bei 564 beziehungsweise $234).

54284

$d40c


LPENV (R)
Dieses Register enthält die Vertikalposition (Nummer der Bildzeile geteilt durch zwei) des Lightpens (Schattenregister bei 565 beziehungsweise $235).

54285

$d40d


NMIEN (W)
Mit diesem Register werden die Unterbrechungen bei der Vertikalsynchronisation und bei ANTIC-Programm-Unterbrechungen ein- beziehungsweise ausgeschaltet.

54286

$d40e


NMIST (R)
Nach dem Auftreten eines NMI kann man durch Abfragen dieses Registers die Herkunft der Unterbrechungsanforderung bestimmen.

54287

$d40f


NMIRES (W)
Durch Eintragen irgendeines Wertes in dieses Register wird NMIST wieder gelöscht.

54287

$d40f


CPU-Hardwarevektoren

NMIVKT

65530

$fffa

Nach einem NMI springt die CPU zu der Adresse, die sich in NMIVKT befindet (das niederwertige Byte steht an erster Stelle).

65531

$fffb


RESETVKT

65532

$fffc

Nach einem RESET springt die CPU zu der Adresse, die sich in RESETVKT befindet (das niederwertige Byte steht an erster Stelle).

65533

$fffd


IRQVKT

65534

$fffe

Nach einem IRQ springt die CPU zu der Speicherstelle, die sich in IRQVKT befindet (das niederwertige Byte steht an erster Stelle).

65535

$ffff

Hauptkategorie: 8-Bitter
Erstellt: 14 November 2011
Zugriffe: 4114

Der GTIA

Der GTIA ist ein weiterer Spezialbaustein des Atari. Der Begriff ist eine Abkürzung für "Graphic Television Interface Adaptor". Der GTIA ist Hauptverbindungsglied zwischen ANTIC und dem Fernseher.

Die vorrangige Aufgabe des GTIA ist es also, die vom ANTIC übergebenen Daten in ein Fernsehbild umzusetzen. Der GTIA verfügt dazu über Farbregister. In jedes dieser Register wird jeweils eine bestimmte Farbe mit einer bestimmten Helligkeit eingetragen. Wenn der ANTIC ein Bild erstellt, gibt er nicht selbst die Farbe an, sondern wählt nur ein Farbregister des GTIA aus. Dies ist die normale Art der Bilddarstellung, es ist aber auch möglich, den GTIA dazu zu bringen, die vom ANTIC übergebenen Daten anders zu interpretieren.

Eine weitere Aufgabe des GTIA ist die Erzeugung von beweglichen Objekten auf dem Bildschirm, sogenannten "PLAYERn" und "MISSILEs" (Spielern und Geschossen). Diese Form der Darstellung wird daher auch als Player-Missile-Grafik bezeichnet. Es ist möglich, gleichzeitig vier Spieler und vier Geschosse darzustellen. Unter Umständen ist aber auch eine höhere Anzahl zu erreichen. Der GTIA unterstützt bei der Player-Missile-Grafik jeweils nur eine Bildzeile. Das heißt, daß für jede Zeile dem GTIA neue Daten über die Form der Spieler und Geschosse mitgeteilt werden müssen. Wie schon im Kapitel über den ANTIC beschrieben, ist dies auch automatisch durch den DMA möglich.

Für die Player-Missile-Grafik stehen im GTIA Register zur Verfügung. So sind wie für die Spielfelddaten, die der ANTIC übergibt, auch für die Player-Missile-Grafik Farbregister vorhanden. Außerdem gibt es Register für die Horizontalposition der Spieler und Geschosse und deren Aussehen (das heißt, wie ein Spieler bzw. ein Geschoß in EINER Zeile aussieht). Die Register, in denen das Aussehen der Spieler und Geschosse gespeichert wird, heißen Spieler- bzw. Geschoßgrafikregister. Oft werden diese Register in der Literatur auch als "Umrißregister" bezeichnet. Diese Bezeichnung halten wir jedoch für mißverständlich. Auch die horizontale

Größe der Spieler und Geschosse ist in Registern gespeichert und somit programmierbar.

Da das Bild vom ANTIC und die Daten der Spieler- und Geschoßgrafikregister im GTIA gemischt werden, kommt es bei Objekten und Bildteilen, die die gleiche Bildposition belegen zur Frage, was dargestellt werden soll, also: Was im Vorder- und was im Hintergrund liegen soll. Dies läßt sich mit einem Register steuern, das festlegt, welche Objekte bzw. welche Bildschirmfarben an welcher Stelle in einer "Prioritätsliste" stehen.

Besonders bei Spielen ist es auch interssant, ob Spieler oder Geschosse mit Spielern, Geschossen oder Bildschirmteilen zusammengestoßen sind. Auch dies wird dem Benutzer vom GTIA in Registern angezeigt. Durch diese Funktion wird der CPU erheblich Rechenzeit erspart, da sie nicht selbst anhand der Positionangaben ausrechnen muß, ob es "Zusammenstöße" gab.

Zusätzlich zu den beschriebenen Funktionen, ist der GTIA auch für die sogenannten Triggerleitungen zuständig. Die Triggerleitungen sind die Leitungen, die mit den "JoystickFeuertasten" verbunden sind. Der Status dieser Triggerleitungen wird über GTIA Register abgefragt. Bei den alten Atari-Geräten sind alle vier Triggereingänge des GTIA benutzt, da ja auch vier Joystickports zur Verfügung stehen. Bei den neuen Atari-Modellen sind zwei Triggereingänge mit Joystickports und ein Triggereingang mit einer Freigabe für den Cartridge-Steckplatz verbunden. Der vierte Triggereingang ist unbenutzt.

Auch die Zusatztasten der Tastatur, die sogenannten Konsolentaster, sind mit dem GTIA verbunden. Das bedeutet, daß die Tasten "START", "SELECT" und "OPTION" über den GTIA abgefragt werden.

Das "Klicken", das ertönt, wenn man eine Taste betätigt, wird ebenfalls vom GTIA erzeugt. Bei den alten Atari-Geräten

wird es über einen eingebauten Lautsprecher wiedergegeben. Dieser Lautsprecher wurde bei den neuen Modellen eingespart. Das "Klicken" wird jetzt direkt in das Tonsignal, das sonst vom POKEY über den Modulator zum Fernseher übertragen wird, gemischt.

Viele Adressen sind mit zwei Registern des GTIA belegt. Jeweils ein Register ist dann für eine Funktion zuständig, die nur ein Schreiben in das Register erfordert und ein anderes ist für eine Funktion zuständig, die nur ein Lesen des Registers erfordert. So können beide Register die gleiche Adresse haben und sich trotzdem nicht gegenseitig stören. Zum Beispiel liegen die Register, die die Horizontalposition der Spieler festlegen, mit denen, die eine Überprüfung, ob Kollisionen zwischen den Geschossen und dem Spielfeld vorliegen, ermöglichen, auf den gleichen Adressen.

Auch für viele der GTIA-Register stellt das Betriebssystem Schattenregister zur Verfügung. Jeweils während der Vertikalsynchronisation werden die Register- und Schattenregisterinhalte aktualisiert (bzw. aufeinander angeglichen). Dies ist zum Beispiel zu beachten, wenn man die Farben des Spielfeldes ändern möchte. Wenn man die neuen Informationen in die Register im GTIA schreibt, die ein Schattenregister haben, so werden sie bei der nächsten Vertikalsynchronisation überschrieben, tauchen also maximal eine Fünfzigstelsekunde auf dem Bildschirm auf. Um die neue Farbe dauerhaft auf den Bildschirm zu bringen, muß man in das Schattenregister schreiben, da das Betriebssystem von dort aus die Daten liest, die es in das GTIA-Register schreibt. Eine weitere Fehlerquelle liegt oft in der Tatsache, daß die Schattenregisterinhalte erst nach spätestens einer Fünfzigstelsekunde richtig sind. Unter Umständen tritt also der Fall ein, daß ein GTIA-Register und ein Schattenregister zusammen eine unmögliche Aussage machen. Dies führt zu Fehlern in Programmen. Der Benutzer sollte die Informationen also nur aus GTIA- oder nur aus Schattenregistern lesen.


Darstellung der Bilddaten des ANTIC

Wie schon erwähnt, überträgt der ANTIC Daten, die dem GTIA miteilen, welche Farbregister er jeweils abbilden soll. Im Kapitel über den ANTIC war auch schon bei der Beschreibung der diversen Grafikmodi angegeben, welches Bitmuster in den Bilddaten stehen muß, um die Farbe und Helligkeit eines bestimmten Farbregisters auf den Bildschirm zu bringen. Bei Grafikmodi, die eine Auflösung von zwei Bildpunkten pro Farbtakt haben, können benachbarte Punkte nur unterschiedliche Helligkeiten aufweisen, nicht jedoch unterschiedliche Farben. Pro Farbtakt kann nur eine Farbe dargestellt werden.

Alle Farbregister im GTIA sind gleichartig aufgebaut:

Bit 0 unbenutzt
Bit 1-3 Helligkeit
Bit 4-7 Farbe

Die Helligkeit läßt sich also in acht Stufen einstellen (da für sie 3 Bits zur Verfügung stehen). Dabei gilt folgende Tabelle:

Bit 3 Bit 2 Bit 1 Helligkeit
0 0 0 Helligkeit 0,  minimal (schwarz)
0 0 1 Helligkeit 1
0 1 0 Helligkeit 2
0 1 1 Helligkeit 3
1 0 0 Helligkeit 4
1 0 1 Helligkeit 5
1 1 0 Helligkeit 6
1 1 1 Helligkeit 7, maximal (weiß)

Es stehen 16 verschiedene Grundfarben zur Verfügung. Allerdings hängt es sehr vom Fernseher ab, wie welche Farbe "wirkt". Bei schlecht eingestellten Fernsehern können auch statt weißen Punkten dicht beieinander liegende andersfarbige Punkte erscheinen. Einen derartigen Fehler, der meist an einer schlechten "Konvergenzeinstellung" des Fernsehers liegt, sollte man vom Fachmann beseitigen lassen.



Für die Wahl der Farben gilt folgende Tabelle:

Bit 7 Bit 6 Bit 5 Bit 4 Farbe
0 0 0 0 Grau
0 0 0 1 Gold
0 0 1 0 Orange
0 0 1 1 Rot-Orange
0 1 0 0 Rosa
0 1 0 1 Purpur
0 1 1 0 Violett
0 1 1 1 Blau1
1 0 0 0 Blau2
1 0 0 1 Hellblau
1 0 1 0 Türkis
1 0 1 1 Blaugrün
1 1 0 0 Grün
1 1 0 1 Gelbgrün
1 1 1 0 Grün-Orange
1 1 1 1 Hellorange

Für die Spielfeldfarben gibt es vier Register, die mit COLPF0, COLPF1, COLPF2 und COLPF3 bezeichnet werden. Die Abkürzung "COLPF" hat sich in der Literatur eingebürgert, sie steht für "COLOR OF PLAYFIELD", was man mit "SPIELFELDFARBE" übersetzen kann. Außerdem gibt es noch ein Farbregister COLBAK, was für "COLOR OF BACKGROUND" (Hintergrundfarbe) steht. Die Farbe dieses Registers erscheint in jedem Fall überall dort, wo sich kein anderes Bildteil befindet, also im Wesentlichen in der Bildumrandung. Bei einigen Grafikmodi wird dieses Register auch als normale Bildschirmfarbe angesprochen (z.B. beim ANTIC-Modus "8" oder "A"). Für alle diese Register erzeugt das Betriebssystem Schattenregister.

Die Register und Schattenregister befinden sich an folgenden Speicherstellen im Atari-System:

Register
Schattenregister
COLPF0 53270 $d016
COLPF0@ 708 $2c4
COLPF1 53271 $d017
COLPF1@ 709 $2c5
COLPF2 53272 $d018
COLPF2@ 710 $2c6
COLPF3 53173 $d019
COLPF3@ 711 $2c7







COLBAK 53174 $d01a
COLBAK@ 712 $2c8

Wie schon am Anfang des Kapitels erwähnt, ist es möglich, den GTIA dazu zu bringen, die Bilddaten, die er vom ANTIC erhält, auf andere Art als normal darzustellen. Auch das BASIC enthält Grafikbetriebsarten ("Grafikgänge"), die nicht zu den sonst üblichen Darstellungen des ANTIC passen. Gemeint sind die Modi, die man durch "GRAPHICS 9", "GRAPHICS 10" oder "GRAPHICS 11" erhält.

Ursprünglich hat Atari seine Anlagen mit einem Chip namens "CTIA" ausgeliefert. Dieser Chip ist besonders für das Amerikanische Farbsystem (NTSC-Norm) konzipiert. Als klar wurde, daß Atari in Europa nicht nur ein paar Rechner verkaufen würde, wurden die weiteren Geräte mit dem GTIA-Chip ausgerüstet. Der GTIA ist besonders für europäische Farbsysteme ausgelegt. Fast alle Atari-Systeme in Europa enthalten den GTIA (in jedem Fall alle neuen Geräte, aber auch die meisten Atari 400 und 800). Die neuesten Geräte in den USA enthalten inzwischen ebenfalls einen weiterentwickelten Chip anstelle des alten CTIA.

Zwischen GTIA und CTIA gibt es einen wesentlichen Unterschied. Bei der Grafik mit CTIA und ANTIC werden nur die Grafikregister, die auch mit dem "SETCOLOR"-Befehl erreicht werden können, verwendet. Ohne Player-Missile-Grafik bleiben also Farbregister unbenutzt. Der GTIA-Chip kann dagegen alle neun Farbregister auch ohne Benutzung der Player-MissileGrafik ansprechen, ermöglicht dem Benutzer also eine bessere Ausnutzung des Atari-Systems.

Da bei den "neuen" Systemen nur statt des CTIAs der GTIA verwendet wurde, nicht jedoch auch ein anderer ANTIC, muß zwangsläufig der GTIA allein für die neuen Modi ("GRAPHICS 9, 10 oder 11) "zuständig" sein. Tatsächlich betreibt man den ANTIC in diesen Modi auch normal, zum Beispiel in einem Schriftmodus oder auch einem Modus für hochauflösende Grafik, der GTIA stellt die Informationen des ANTIC lediglich anders dar.

Der neue GTIA ist zum CTIA kompatibel, das heißt, daß alle Programme, die auf dem CTIA laufen, auch für den GTIA geeignet sind. Der umgekehrte "Weg" ist aber nur möglich, wenn nur CTIA-Möglichkeiten ausgenutzt worden sind.

Der GTIA interpretiert die Bilddaten des ANTIC anders als in der gewohnten Weise. Er faßt die Daten zu jeweils vier Bit breiten Nibbles zusammen. Diese Nibbles steuern dann, welche Farben auf den Bildschirm gelangen. Es muß allerdings beachtet werden, daß es bei Verwendung der horizontalen Feinverschiebung oft unerwünschte Ergebnisse gibt, wenn diese Möglichkeiten des GTIA ausgenutzt wedrden.

Die unterschiedlichen Betriebsarten werden über die Bits 6 und 7 des Registers GTIACNTL gewählt. Die Bits 0-5 des GTIACNTL werden für die Player-Missile-Grafik verwendet. Bei der Programmierung ist also darauf zu achten, daß es nicht zu Konflikten mit der Player-Missile-Grafik kommt. Auch für GTIACNTL gibt es ein Schattenregister (GTIACNTL@). Die Register befinden sich an folgenden Stellen:

GTIACNTL 53275 $d01b
GTIACNTL@ 623 $26f



Die möglichen Kombinationen von Bit 6 und Bit 7 führen zu folgenden Funktionen:

Bit7 Bit6 Beschreibung
0 0 Diese Bitkombination liegt beim CTIA immer vor. Wenn Programme von einem Atari mit GTIA auf einem Atari mit CTIA (der in Europa selten ist !) laufen sollen, muß diese Bitkombination vorliegen. Bei dieser Kombination arbeitet der Atari wie gewohnt.
0 1 Jetzt interpretiert der GTIA die erwähnten Nibbles als Helligkeitstufen. Dabei nimmt er die Farbe, die in Register COLBAK bzw. COLBAK@ steht und als Helligkeit die Bitkombination des jeweiligen Nibbles. Wenn der ANTIC beispielsweise den ANTICModus "F" (BASIC: "Graphics 8") benutzt, faßt der GTIA je 4 Bildpunkte zu einem eine Bildzeile hohen Streifen zusammen, der die Farbe aus COLBAK hat. Die Bitkombination der normalerweise erscheinenden vier Punkte bestimmt die Helligkeit des Streifens. Dieses Beispiel entspricht dem "BASIC-Gang 9".
1 0 Jetzt interpretiert der GTIA die Nibbles als Nummer eines Farbregisters. Da der GTIA aber nur über neun Farbregister verfügt, ist die Zahl der gleichzeitig darstellbaren Farben auf neun beschränkt. Wenn der ANTIC beispielsweise den Modus "F" benutzt, faßt der GTIA je vier Bildpunkte zu einem eine Bildzeile hohen Streifen zusammen. Das von dem jeweiligen Nibble (der Bitkombination der normalerweise erscheinenden vier Punkte) angewählte Farbregister bestimmt, aus welchem Farbregister Farbe und Helligkeit des Streifens stammen. Dieses Beispiel entspricht dem "BASIC-Gang 10".
1 1 Jetzt interpretiert der GTIA die Nibbles als Farbstufen. Dabei nimmt er die Helligkeit, die in Register COLBAK bzw. COLBAK@ steht. Die Farbe wird durch die Bitkombination des Nibbles gewählt. Dabei gilt die normale Farbtabelle. Wenn der ANTIC beispielsweise den Modus "F" benutzt, faßt der GTIA je vier Bildpunkte zu einem eine Bildzeile hohen Streifen zusammen. Dieser Streifen hat dann die Helligkeit aus Register COLBAK und die Farbe, die durch die Bitkombination, der normalerweise erscheinenden, vier Bildpunkte bestimmt wird. Dieses Beispiel entspricht dem "BASIC-Gang 11".

Durch diese Möglichkeiten des GTIA erhöht sich die Zahl der gleichzeitig auf dem Bildschirm darstellbaren Farben erheblich. Auch die Auflösung ist im Verhältnis zu der Anzahl der gleichzeitig darstellbaren Farben sehr hoch. Gerade Darstellungen für die Statistik oder Spiele lassen sich oft so aufbauen, daß es nicht weiter stört, daß der Bildschirm aus kurzen, einzeiligen Linien besteht.

Natürlich kann man praktisch jedes Bild, das vom ANTIC erzeugt wird, in der beschriebenen Art vom GTIA darstellen lassen. Gerade mit den Schriftmodi des ANTIC lassen sich sehr farbreiche Bilder erzeugen, die im Speicher nur wenig Raum verbrauchen, sich daher also schnell von der CPU verändern lassen. Dazu ist es aber notwendig, sich einen eigenen Zeichensatz zu definieren.

Eine weitere Möglichkeit, interessante Effekte zu erzielen und mehr Farben als üblich auf den Bildschirm zu bringen, ist der Wechsel von Farbregisterinhalten während einer ANTIC-Programm-Unterbrechung. Während der Unterbrechung trägt man in die Farbregister neue Werte ein. Auf diese Art kann man mehr Farben gleichzeitig auf dem Bildschirm darstellen, als Farbregister vorhanden sind. Auch die Betriebsart der GTIA läßt sich während einer ANTIC-Programm-Unterbrechung variieren.

Mit dem Basic-Befehl "SETCOLOR R,F,H" schreibt man in die Schattenfarbregister bestimmte Werte, die die Farbe und Helligkeit codiert enthalten (die "Codierung" wurde bereits beschrieben). Für die möglichen "R" im Befehl wird jeweils ein Schattenfarbregister angesprochen:

für R = 0: COLPF0@
für R = 1: COLPF1@
für R = 2: COLPF2@
für R = 3: COLPF3@
für R = 4: COLBAK@

Statt "SETCOLOR R,F,H" läßt sich auch

POKE (Adresse des Schattenfarbregisters), F * 16 + H

eingeben. Mit diesem Befehl ist auch die Wahl der Farbe der Farbregister für die Player-Missile-Grafik möglich, dies läßt sich mit dem "SETCOLOR"-Befehl nicht machen.


Die PLAYER-MISSILE-Grafik

Zu den wichtigsten Elementen bei Spielen gehören natürlich bewegliche Objekte. Bei herkömmlichen Systemen ist der Bildschirm ein einfacher Bereich des Speichers, der auf eine bestimmte Art auf den Monitor "projiziert" wird.

Ein auf dem Bildschirm zusammenhängendes Feld, das einen Spieler oder ein Geschoß darstellen soll, liegt im Speicher meist nicht direkt hintereinander. Zwischen den Informationen, die zu einem Spieler gehören, befinden sich Bytes, die zu den Bildteilen, die von einem Teil des Spielers in einer Zeile bis zum gleichen Spieler in der nächsten Zeile folgen, gehören. Dies muß bei jeder Operation mit einem Spieler beachtet werden. Die CPU muß also, wenn sie zum Beispiel das Aussehen eines Spielers ändern will, nur jedes soundsovielte Byte ändern. Dies bringt einen erheblichen Rechenaufwand mit sich.

Womöglich liegt ein Spieler auch noch halb in einem oder mehreren anderen Bytes, dann muß die CPU auch noch einzelne, zum Spieler gehörige und nicht zum Spieler gehörige Bits trennen. Dies bringt weiteren Rechenaufwand.

Zudem überdeckt jeder Spieler Bildteile oder wird von Bildteilen überdeckt. Jedes überdeckte Bildteil oder jeder überdeckte Spieler müssen nach dem Weiterbewegen natürlich wiederhergestellt werden. Also muß bei jedem Bildüberschreiben für einen Spieler zwischengespeichert werden, was gerade verdeckt wird.

Der gesamte Rechenaufwand läßt sich dadurch verringern, daß man die Spieler immer mehrere Punkte weit bewegt. Allerdings wirkt die Bewegung dann nicht mehr flüssig, sondern ruckend. Eine Lösung bringt die Einführung von Spielern und Geschossen, die nicht mehr per Software, sondern per Hardware eingeblendet werden. Auch Trefferkontrollen lassen sich hardwaremäßig leichter durchführen als per Software.

Bei den Atari-Geräten übernimmt dies die sogenannte PlayerMissile-Grafik. Wenn auch der Aufwand nicht auf Null absinkt und der Atari sicher auch nicht das einfachste Konzept für bewegliche Objekte hat, sollte man sich immer vor Augen halten, welche Operationen der CPU man einspart. Außerdem ist die Player-Missile-Grafik von Atari extrem flexibel.

Mit der Player-Missile-Grafik ist es möglich, bis zu vier Spieler und vier Geschosse in jedes beliebige Bild des ANTIC einzublenden. Diese Zahl läßt sich jedoch erhöhen, man kann auch mehrere Objekte mit einem Spieler oder einem Geschoß darstellen. Innerhalb von einer Zeile lassen sich jedoch nie mehr als vier Geschosse und vier Spieler darstellen.

Wenn zwei Objekte gemeinsam einen Spieler oder ein Geschoß "benutzen" sollen, können entweder ohne DMA, je nachdem welche Zeile des Bildes gerade aufgebaut wird, die Daten des einen oder des anderen Objekts in das Grafikregister geschrieben werden. Es ist aber auch mit DMA möglich, zwei Objekte durch einen Spieler darzustellen. Man muß lediglich in einer Bildzeile eine ANTIC-Programm-Unterbrechung auslösen und in der Unterbrechungsroutine das Register PMBASE (das Register ist im ANTIC-Kapitel beschrieben) auf die Basisadresse eines anderen Speicherfeldes legen.

Die Player-Missile-Grafik wird über das Register PMCNTL ein- und ausgeschaltet. Das Register PMCNTL befindet sich bei Adresse 53277 bzw. $d01d. Die einzelnen Bits des Registers haben folgende Funktionen:

Bit 0: Wenn dieses Bit auf "1" steht, ist die Übertragung der Grafikregister der Geschosse auf den Bildschirm eingeschaltet. Somit werden die Geschosse mit diesem Bit eingeschaltet.

Bit 1: Wenn dieses Bit auf "1" ist, ist die Übertragung der Grafikregister der Spieler auf den Bildschirm eingeschaltet. Somit werden die Spieler mit diesem Bit eingeschaltet.

Bit 2: Wenn dieses Bit auf "1" ist, können die Triggereingänge nur auf "0" gesetzt werden, das Loslassen einer Joystick-Feuertaste wird dadurch nicht mehr registriert. Damit ist das Speichern eines Tastendruckes auf eine der "Joystick-Feuertasten" möglich.

Die Farben der Spieler werden wie die Farben des Spielfeldes in Farbregistern gespeichert. Dabei haben immer ein Spieler und ein Geschoß gemeinsam ein Farbregister. Die Register sind in ihrer Funktion mit den anderen Farbregistern identisch. Die Register befinden sich an folgenden Adressen im Atari:

COLPM0 53266 $d012 Spieler/Geschoß 0
COLPM0@ 704 $2c0 (Schattenregister)

COLPM1 53267 $d013 Spieler/Geschoß 1
COLPM1@ 705 $2c1 (Schattenregister)

COLPM2 53268 $d014 Spieler/Geschoß 2
COLPM2@ 706 $2c2 (Schattenregister)

COLPM3 53269 $d015 Spieler/Geschoß 3
COLPM3@ 707 $2c3 (Schattenregister)

Die Form der Spieler wird in sogenannten Spieler- und Geschoßgrafikregistern abgelegt. Der GTIA unterstützt aber nur jeweils eine Bildzeile. Das heißt, daß nach jeder Zeile, sofern sich das Bild des Spielers zu dieser Zeile hin ändern soll, neue Daten in die Spieler- und Geschoßgrafikregister gebracht werden müssen. Dies läßt sich sowohl aus einem Assemblerprogramm heraus ausführen, als auch durch die ANTIC-DMA erledigen. Über die Benutzung der ANTIC-DMA gibt das Kapitel über den ANTIC Auskunft.

Für jeden Spieler ist ein Grafikregister vorhanden:

GRAFP0 53261 $d00d
GRAFP1 53262 $d00e
GRAFP2 53263 $d00f
GRAFP3 53264 $d010

Für die Geschosse ist ein gemeinsames Grafikregister vorhanden, in das die Daten aller Geschosse geschrieben werden:

GRAFPM 53265 $d011

Zu jedem Geschoss gehören zwei Bits in diesem Register:

Bit 0-1 Geschoß 1
Bit 2-3 Geschoß 2
Bit 4-5 Geschoß 3
Bit 6-7 Geschoß 4

Die Programmierung des Geschoßregisters ist etwas komplizierter als die Programmierung der Spielergrafikregister, da hier die einzelnen Bits der Geschosse zu einem Byte zusammengefügt werden müssen. Auch die DMA erleichtert diese Arbeit nicht. Aber trotzdem lassen sich Spiele auch mit dieser Form der Player-Missile-Grafik leichter programmieren, als völlig ohne Hardwarehilfe für bewegliche Objekte.

Die horizontale Position der Geschosse und Spieler wird ebenfalls in Register geschrieben. Der Registerinhalt besagt jeweils, beim wievielten Farbtakt einer Bildzeile angefangen wird, den Inhalt des Grafikregister (also das Objekt) auf den Bildschirm zu bringen.

Zu beachten ist aber, daß der linke Spielfeldrand je nach der Anzahl der Farbtakte pro Bildzeile, die man im ANTIC einstellen kann, bei verschiedenen Farbtakten liegt. Die Farbtakte vor dem eigentlichen Bild gehören zum Bildrand, der die Farbe aus COLBAK hat. Die ersten Farbtakte liegen normalerweise außerhalb des Fernseherbildes. Um Objekte unsichtbar zu machen, kann man sie ohne weiteres in diesen Bildbereich bewegen, man muß das Horizontalregister des Spielers nur auf Null setzen.

Für jeden Spieler und jedes Geschoß ist ein Horizontalregister vorhanden:

HPOSP0 53248 $d000 (Spieler 0)
HPOSP1 53249 $d001 (Spieler 1)
HPOSP2 53250 $d002 (Spieler 2)
HPOSP3 53251 $d003 (Spieler 3)

HPOSM0 53252 $d004 (Geschoß 0)
HPOSM1 53253 $d005 (Geschoß 1)
HPOSM2 53254 $d006 (Geschoß 2)
HPOSM3 53255 $d007 (Geschoß 3)

Außerdem gibt es ein weiteres Register, um die vertikale Position von Spielern und Geschossen zu beeinflussen: VDELAY 53276 $d01c

VDELAY wird benutzt, wenn man zweizeilige Auflösung gewählt hat, aber ein Objekt trotzdem in eine bestimmte Zeile bringen möchte. Durch eine "1" in einem Bit wird bewirkt, daß das entsprechende Objekt um eine Zeile nach unten gerückt wird. Das Register ist folgendermaßen belegt:

Bit 0 Geschoß 0
Bit 1 Geschoß 1
Bit 2 Geschoß 2
Bit 3 Geschoß 3

Bit 4 Spieler 0
Bit 5 Spieler 1
Bit 6 Spieler 2
Bit 7 Spieler 3

Die horizontale Größe der Objekte wird ebenfalls in Registern gespeichert. Die horizontale Größe ist die Anzahl der Farbtakte, die ein Objekt in einer Zeile einnimmt. Für jeden Spieler gibt es ein derartiges Register:

SIZEP0 53256 $d008 (Spieler 0)
SIZEP1 53257 $d009 (Spieler 1)
SIZEP2 53258 $d00a (Spieler 2)
SIZEP3 53259 $d00b (Spieler 3)

Die horizontale Größe wird durch Bit 0 und Bit 1 der Register bestimmt (die anderen Bits sind unbenutzt):

Bit1Bit0 Größe
0
0
Normalgröße, jedes Bit ist einen Farbtakt breit (ein Spieler ist also 8 Farbtakte breit).
0
1
Doppelte Größe, jedes Bit ist zwei Farbtakte breit (ein Spieler ist also 16 Farbtakte breit).
1
0
Normalgröße, jedes Bit ist einen Farbtakt breit (ein Spieler ist also 8 Farbtakte breit).
1
1
Vierfache Größe, jedes Bit ist vier Farbtakte breit (ein Spieler ist also 32 Farbtakte breit).


Die Größen der Geschosse werden dagegen in dem Register

SIZEM 53260 $d00c

gespeichert.

Je zwei Bits des Registers bestimmen die Größe eines Geschosses:

Bit 0-1 Geschoß 0
Bit 2-3 Geschoß 1
Bit 4-5 Geschoß 2
Bit 6-7 Geschoß 3

Die möglichen Bitkombinationen bewirken folgendes:

0
0
Normalgröße, jedes Bit ist einen Farbtakt breit (das Geschoß ist also zwei Farbtakte breit).
0
1
Doppelte Größe, jedes Bit ist zwei Farbtakte breit (das Geschoß ist also vier Farbtakte breit).
1
0
Normalgröße, jedes Bit ist einen Farbtakt breit (das Geschoß ist also zwei Farbtakte breit).
1
1
Vierfache Größe, jedes Bit ist vier Farbtakte breit (das Geschoß ist also acht Farbtakte breit).

Wenn Teile des Bildschirms die gleiche Bildschirmposition haben wie Spieler oder Geschosse, stellt sich die Frage, was im Vordergrund und was im Hintergrund dargestellt wird. Dies läßt sich durch das Register GTIACNTL (bzw. GTIACNTL@) bestimmen. Dieses Register ist aber auch noch für weitere Fuktionen zuständig. So bestimmen Bit 6 und 7 die GTIA-Betriebsart. Die ersten 4 Bits dienen der Prioritätskontrolle. Durch Setzen eines der 4 Bits wählt man eine Prioritätsfolge zwischen den Spielfeldfarben und den Spielern und Geschossen:

(Die Priorität FÄLLT von links nach rechts !)

Bit 0: P0, P1, P2, P3, PF0, PF1, PF2, PF3/P5, BAK

Bit 1: P0, P1, PF0, PF1, PF2, PF3/P5, P2, P3, BAK

Bit 2: PF0, PF1, PF2, PF3/P5, P0, P1, P2, P3, BAK

Bit 3: PF0, PF1, P0, P1, P2, P3, PF2, PF3/P5, BAK

Wenn mehr als eins der 4 Bits gesetzt ist, so sind die Prioritäten nicht eindeutig festgelegt. Es kommt zu Prioritätskonflikten zwischen den einzelnen Bildobjekten. Die "Überlappungszone" zwischen derartigen, in einem Prioritätskonflikt stehenden Objekten erscheint schwarz. Wenn man zum Beispiel Bit 0 und Bit 2 von GTIACNTL setzt, so wird P0 schwarz erscheinen, wenn er über PF1 gerät. Das gleiche geschieht auch mit P1, P2 und P3 wenn sie über PF1, PF2 und PF3/P5 geraten.

In den ANTIC-Modi mit einer Farbe und 40 Zeichen pro Zeile wird die Leuchtstärke eines Zeichens ohne Rücksicht auf die Priorität von PF1 bestimmt. Wenn ein Spieler oder ein Geschoß mit höherer Priorität ein derartiges Zeichen überdeckt, so wird die Farbe dieser Zone von der Spielerfarbe bestimmt.

Die beiden verbleibenden Bits von GTIACNTL haben folgende Funktionen:

Bit 4: Wenn dieses Bit gesetzt ist, haben alle Geschosse die Farbe, die in COLPF3 steht (Farbe von PF3). Dadurch können die Geschosse auch zu einem fünften Spieler (P5) zusammengefaßt werden.

Bit 5: Das Setzen dieses Bits ermöglicht es, auch mehrfarbige Spieler abzubilden. Dabei werden Spieler 0 und Spieler 1 sowie Spieler 2 und Spieler 3, sofern sie sich überlappen, miteinander verknüpft. Die Priorität gilt dann nur noch bedingt. Es können die Farben beider Spieler erscheinen. Je nachdem, welches Bit welches Spielers gesetzt ist, erscheint eine von drei Farben (zwei Farben der Spieler und die Farbe unter den Spielern) auf dem Bildschirm .

Besonders bei Spielen ist es interessant, festzustellen ob es "Zusammenstöße" zwischen Spielern und Geschossen mit anderen Spielern, Geschossen und Bildteilen gab. Der GTIA besitzt insgesamt 16 Register, die ein Programm abfragen kann, um derartige Kollisionen zu erkennen.

Für jedes Geschoß gibt es ein Register, das Kollisionen zwischen dem jeweiligen Geschoß und den Spielfeldfarben speichert:

KOLM0PF 53248 $d000
KOLM1PF 53249 $d001
KOLM2PF 53250 $d002
KOLP3PF 53251 $d003

Ein Bit dieser Register signalisiert dadurch, daß es auf "1" steht, daß es eine Kollision zwischen dem Geschoß, dem das Register zugeordnet ist und der jeweiligen Spielfeldfarbe gab:

Bit 0 : Kollision mit PF0
Bit 1 : Kollision mit PF1
Bit 2 : Kollision mit PF2
Bit 3 : Kollision mit PF3
Bit 4-7 : unbenutzt (stehen auf "0")

Es gibt auch für jeden Spieler ein Register, das einen Zusammenstoß zwischen dem jeweiligen Spieler und einer Spielfeldfarbe signalisiert:

KOLP0PF 53252 $d004
KOLP1PF 53253 $d005
KOLP2PF 53254 $d006
KOLP3PF 53255 $d007

Ein Bit dieser Register signalisiert daurch, daß es auf "1" steht, daß eine Kollision zwischen dem Spieler, dem das Register zugeordnet ist und der jeweiligen Bildschirmfarbe stattgefunden hat:

Bit 0 : Kollision mit PF0
Bit 1 : Kollision mit PF1
Bit 2 : Kollision mit PF2
Bit 3 : Kollision mit PF3
Bit 4-7 : unbenutzt (stehen auf "0")

Desweiteren gibt es für jedes Geschoß ein Register, das signalisiert, ob es Kollisionen des jeweiligen Geschosses mit einem Spieler gab:

KOLM0P 53256 $d008
KOLM1P 53257 $d009
KOLM2P 53258 $d00a
KOLM3P 53259 $d00b

Ein Bit dieser Register signalisiert dadurch, daß es auf "1" steht, daß eine Kollision des Geschosses, dem das jeweilige Register zugeordnet ist, mit dem jeweiligen Spieler stattgefunden hat:

Bit 0 : Kollision mit Spieler 0 (P0)
Bit 1 : Kollision mit Spieler 1 (P1)
Bit 2 : Kollision mit Spieler 2 (P2)
Bit 3 : Kollision mit Spieler 3 (P3)
Bit 4-7 : unbenutzt (stehen auf "0")

"Last but not least" gibt es für jeden Spieler ein Register, dessen Bits Zusammenstöße mit anderen Spielern signalisieren:

KOLP0P 53260 $d00c
KOLP1P 53261 $d00d
KOLP2P 53262 $d00e
KOLP3P 53263 $d00f

Ein Bit dieser Register signalisiert, daß ein Zusammenstoß zwischen dem Spieler, dem das Register zugeordnet ist und einem anderen Spieler stattgefunden hat. Das "eigene" Bit im jeweiligen Register steht immer auf "0".

Bit 0 : Kollision mit Spieler 0 (P0)
Bit 1 : Kollision mit Spieler 1 (P1)
Bit 2 : Kollision mit Spieler 2 (P2)
Bit 3 : Kollision mit Spieler 3 (P3)
Bit 4-7 : unbenutzt (stehen immer auf "0")

Eine Kollision wird in dem Moment markiert, in dem die Position, an der die Kollision stattfindet, auf dem Bildschirm abgebildet wird. Direkt nach dem Einschreiben in die Positionsregister hat zwar genaugenommen die Kollision schon stattgefunden, durch die interne Struktur des GTIA ist es aber zu diesem Zeitpunkt noch nicht möglich, die Kollision zu bemerken.

Die Bits in den Kollisionsregistern bleiben so lange gesetzt, bis in ein "Löschregister" irgendein Wert geschrieben wird. Die einzelnen Bits dieses Registers haben keine weitere Funktion. Es ist also wirklich völlig egal, welcher Wert in das Register

HITCLR 53278 $d01e

geschrieben wird.

Die Kollision ist also unter Umständen auch noch in dem Moment gespeichert, in dem die Objekte sich bereits wieder an anderen Stellen befinden. Auf diese Art kann man die Bewegungen der Objekte auch in Unterbrechungsroutinen ausführen, die Abfrage aber erst später im Hauptprogramm machen.


Wie benutzt man die Player-Missile-Grafik nun konkret?

Zuerst muß man sich entscheiden, ob man die Objekte durch den DMA des ANTICs darstellen läßt oder direkt aus einem Assemblerprogramm in die Grafikregister des GTIA schreibt. Gewöhnlich wird man den DMA benutzen, da man ansonsten sehr genau darauf achten muß, welche Zeile gerade abgebildet wird. Der Aufand, der entsteht, wenn man ohne DMA mit der Player-Missile-Grafik arbeitet, ist nur sehr selten zu rechtfertigen.

Sofern man die Player-Missile-Grafik mit dem DMA benutzt, muß man sich einen freien Speicherbereich im Atari suchen. Gewöhnlich liegt ganz "oben" im freien Arbeitsspeicher der Bildschirmspeicher. Direkt darunter wird man gewöhnlich das ANTIC-Programm ansiedeln. Es empfiehlt sich, unter dem ANTIC-Programm das Speicherfeld für den Player-Missile-DMA unterzubringen. Falls man weitere Speicherfelder für die Player-Missile-Grafik anlegt, sollte der Speicher weiter von oben nach unten gefüllt werden. Die Adresse des Speicherfeldes für den Player-Missile-DMA muß dem ANTIC über das Register PMBASE mitgeteilt werden. Bei der Wahl der Speicherbereiche der Player-Missile-DMA ist jedoch zu beachten, daß, wie schon erwähnt, immer an einer 1K-Byte bzw. 2K-Byte Grenze beginnen müssen.

Die horizontale Spielerbewegung läßt sich direkt durch ein Verändern der Positionsregister im GTIA erreichen. Um eine vertikale Spielerbewegung zu bewirken, muß man die Bytes des Spielers oder die einzelnen Bits des Geschosses durch das Speicherfeld für den Player-Missile-DMA bewegen. Dafür sollte man sich jeweils Unterprogramme schaffen. Die Unterprogramme dafür sind jedoch relativ einfach, da der Speicherbereich für einen Spieler oder ein Geschoß nie mehr als 256 Bytes hat, also nie größer ist, als der größte mit einem Prozessorregister (Register A,X oder Y) darstellbare Wert. Die 16 Bit Operationen, die ohne Player-Missile-Grafik nötig wären, entfallen also weitestgehend.

Jetzt sollte der Speicherbereich für die Player-MissileGrafik gelöscht werden. Außerdem müssen die Horizontalpositionen und Größen der Spieler, sowie der Grad der vertikalen Auflösung im ANTIC bzw. GTIA festgelegt werden. Die Spielerfarben werden in die Register COLPM0@ bis COLPM3@ (Schattenregister von COLPM0 bis COLPM3) eingetragen.

Ganz zuletzt sollte man den Player-Missile-DMA (mit Register DMACNTL) und die Player-Missile-Grafik (mit Register PMCNTL) einschalten; so treten keine Störungen auf dem Bildschirm während der Initialisierung auf.


Die Triggereingänge und die Konsolentaster

Die Triggereingänge des GTIA sind bei den alten AtariModellen mit den vier Joystickeingängen verbunden. Über die Triggereingänge fragt man so zum Beispiel die "Feuertasten" der Joysticks ab. Da die neuen Atari-Modelle nur noch zwei Joystick-Ports besitzen, wurde einer der freien Triggereingänge zur Abfrage der Freigabe für ein ROM-Modul verwendet. Der vierte Triggereingang ist unbenutzt.

Für jeden Triggereingang steht ein Register zur Verfügung, das jeweils im niedrigsten Bit (Bit 0) den Status des Eingangs angiebt. Eine "1" in einem dieser Bits zeigt zum Beispiel einen nicht gedrückten Taster an den Joysticks an, eine "0" einen gedrückten Taster. Wie schon erwähnt, läßt sich das Zurückschalten auf "1" durch das Setzen von Bit 2 des Registers PMCNTL unterdrücken. Wenn eine "0" in einem der Triggereingangsregister steht, bleibt sie gespeichert, bis das Bit 2 von PMCNTL wieder gelöscht wird. Die Bits 1 bis 7 der Register stehen immer auf "0". Für jedes der Register steht ein Schattenregister zur Verfügung.

Die Register und Schattenregister befinden sich an folgenden Adressen:

TRIG0 53264 $d010 JOYSTICK 1
TRIG0@ 644 $284

TRIG1 53265 $d011 JOYSTICK 2
TRIG1@ 645 $285

TRIG2 53266 $d012 Freigabe Cartridge ROM
TRIG2@ 646 $286 (Joystick 3)

TRIG3 53267 $d013 unbenutzt
TRIG3@ 647 $287 (Joystick 4)
(in Klammern: Atari 400/800)

Die Konsolentaster "START", "SELECT" und "OPTION" werden ebenfalls über den GTIA abgefragt. Dafür steht das Register CONSOL zur Verfügung:

CONSOL 53279 $d01f

Die Konsolentaster sind den Bits des Registers folgendermaßen zugeordnet:

Bit 0 : START
Bit 1 : SELECT
Bit 2 : OPTION

Eine "0" in einem der Bits signalisiert, daß die betreffende Taste gedrückt ist. Durch Einschreiben einer "1" in ein oder mehrere Bits wird die Eingabe durch den oder die betreffenden Taster gesperrt.

Bit 3 des CONSOL-Registers steuert das "Klicken" der Tastatur. Das Betriebssystem schreibt während des Vertikal-Leertaktes eine 1 in dieses Bit. Durch das Einschreiben einer "0" in dieses Bit löst man das "Klicken" aus. Das Bit sollte aber nur kurzzeitig auf "0" stehengelassen werden, insbesondere wenn man die Vertikal-Leertakt-Unterbrechungsroutine des Betriebssystems abschaltet.

Vor dem Lesen der Taster sollte man $08 in das Register CONSOL schreiben, um sicherzugehen, daß kein Taster gesperrt ist.

Das Aussehen der Farben ist bei NTSC- und PAL-System leider nicht identisch. Wenn man auf einem PAL-System ein Spiel schreibt, kann es unter Umständen nötig sein, die Farben zu ändern, bevor man das Programm auf einem NTSC-System laufen läßt. Die Änderungen können aber auch gleich im Programm berücksichtigt werden. Im Register

NTSCPAL 53268 $d014

wird dann im Programmablauf abgefragt, ob ein PAL- oder ein NTSC-Gerät vorliegt. Bei einem PAL-Gerät sind die Bits 1-3 "0", bei einem NTSC-Gerät "1".

Außerdem ist beim NTSC-System normalerweise nicht die gleiche Anzahl von Bildzeilen auf dem Bildschirm vorhanden, wie beim PAL-System.

Hauptkategorie: 8-Bitter
Erstellt: 13 November 2011
Zugriffe: 2073

Ich verwende das HTerm-Programm zur Kommunikation mit alten Maschinen. Dabei kann ich die empfangenen Daten leider nicht direkt als ASCII speichern, weil das HTerm dabei die CR+LFs rausschmeißt.

Wenn ich die Daten aber als Hex-Ausgabe (alle Bytes als zwei Ascii-Ziffern, alles in einer Zeile) abspeichere, sind die CR+LFs drin.

Also habe ich ein kleines Perl-PGM gehackt, das zwei Parameter fest erwartet und einen dritten Parm optional verarbeiten kann:

konvert.pl []

Die beiden ersten Parms dürften klar sein. Mit dem dritten Parm schalte ich einen anfangs benötigten Debug-Modus ein.

Und hier ist noch das Script (bitte nicht wundern, ich habe seit 10 Jahren kein Perl mehr angefasst. Man kann das sicher auch in einer einzigen Zeile schreiben...):

 


 

 

use strict;

# printf ("Programmname = %s\n", $0);
# printf ("Parm1 = %s\n", @ARGV[0]);
# printf ("Parm2 = %s\n", @ARGV[1]);

my ($from, $to, $rmax) = @ARGV ;
printf ("from = %s, to = %s, maximale Zeichenzahl: %d\n", $from, $to, $rmax);

local (*FROM, *TO) ;

open(FROM, "$from") or die "Could not open $from for reading: $!\n" ;
open(TO, ">$to") or die "Could not open $to for writing: $!\n" ;

while (defined (my $line = )) { 
	# printf ("Vorher: Zeilenlänge = %d\n", length ($line));
	syswrite (TO, rupf ($line));
}
close(FROM) ;
close(TO) ;

sub rupf {
	my $line = shift;
	my $max = length ($line);

	$max = $rmax if ($rmax > 0);
	my @buffer;
	
	printf ("Zeilenlänge = %d\n", $max);
	($max % 2 == 0) or die "Oops, die Stringlänge ist ungerade. Das kann nicht sein!";

	for (my $i = 0; $i %s 2==>%s\t", $str1, $str2) if ($rmax > 0);
		printf ("Wert1 ==> %2x,  Wert2==>%2x, Gesamt = %2x\n", wert ($str1), wert ($str2), ord (chr (16 * wert ($str1) + wert ($str2)))) if ($rmax > 0);
		push (@buffer, chr (16 * wert ($str1) + wert ($str2)));
	}
	my $b2 = join ('', @buffer);

	$b2 =~ tr/\{\[\}\]\~\^\|/äÄüÜßÖö/;
	$b2 =~ s/\014//g;
	$b2 =~ s/\n//g;
	return $b2;
}


sub wert {
	my $s = shift;

	my $erg = ord ($s) - ord ('0');
	if ($erg > 9) { $erg -= 7; }
	return $erg;
}


Hauptkategorie: 8-Bitter
Erstellt: 13 November 2011
Zugriffe: 1440
          *** ATARI INTERN                                  Inhalt ***


                      I N H A L T S V E R Z E I C H N I S
                      -----------------------------------


                                                                 SEITE
          Einleitung                                              5

          Das Prinzip eines Mikrocomputers                        9
               (allgemeines)
               von Bits und Bytes                                 14
               die Hardware eines Mikrocomputers                  21
               Low und High                                       31


          Das Konzept des Atari                                   35

          Die Hardware des Atari                                  51
               (allgemeines)
               Speicheraufteilung und Anschlußpläne               62

          Der ANTIC                                               73
               (allgemeines)
               die Kontroll- und Lightpenregister                 77
               der DMA für die Player-Missile-Grafik              82
               der Befehlssatz des ANTIC und das
                 ANTIC-Programm                                   87
               die Bildgrafik                                     95
               die Schriftgrafik                                  101
               Scrolling                                          112

Der GTIA 125 (allgemeines) Darstellung der ANTIC-Bilddaten 129 die Player-Missile-Grafik 135 die Triggereingänge und die Konsolentaster 149 Der POKEY 153 (allgemeines) Tonerzeugung 154 Tastaturabfrage 162 Paddlesteuerung 166 serielle Ein-/Ausgabe 168 Die PIA 183 Das Betriebssystem des Atari 191 (allgemeines) Reset und Interrupts 199 Ein-/Ausgabe über Kontrollblöcke 202 die Betriebssystemroutinen 214 Der Speicherplan des Atari 321 Das Register der Labels 373 Das Inhaltsregister 381