C64 Memory Map

by Michael Steil. [github.com/mist64/c64ref, rev 2667951, 2024-07-06]

This allows you to view different commentaries side-by-side. You can enable/disable individual columns:

Mapping the Commodore 64Reference from Mapping the Commodore 64 by Sheldon Leemon, ISBN 0-942386-23-X.
64'er [German]German-language reference from Memory Map mit Wandervorschlägen by Dr. H. Hauck, in 64'er Sonderheft 1986/07.
64 intern [German]German-language reference from Das neue Commodore-64-intern-Buch by Data Becker, ISBN 3890113079.
Joe Forster/STAReference by Joe Forster/STA, with awsm's changes applied.
Microsoft/Commodore SourceComments from the original M6502 BASIC source by Microsoft and the original C64 KERNAL source by Commodore
Programmer's Reference GuideReference from Commodore 64 Programmer's Reference Guide.
64mapReference as found in "Commodore_64_Memory_Maps.txt" by anonymous.
Jim ButterfieldReference by Jim Butterfield in COMPUTE! #29 (October 1982).


Address Symbol Decimal Mapping the Commodore 64 64'er [German] 64 intern [German] Joe Forster/STA Microsoft/Commodore Source Programmer's Reference Guide 64map Jim Butterfield
$0000 D6510 0
6510 On-Chip I/O DATA Direction Register
  • Bit 0: Direction of Bit 0 I/O on port at next address. Default = 1 (output)
  • Bit 1: Direction of Bit 1 I/O on port at next address. Default = 1 (output)
  • Bit 2: Direction of Bit 2 I/O on port at next address. Default = 1 (output)
  • Bit 3: Direction of Bit 3 I/O on port at next address. Default = 1 (output)
  • Bit 4: Direction of Bit 4 I/O on port at next address. Default = 0 (input)
  • Bit 5: Direction of Bit 5 I/O on port at next address. Default = 1 (output)
  • Bit 6: Direction of Bit 6 I/O on port at next address. Not used.
  • Bit 7: Direction of Bit 7 I/O on port at next address. Not used.

This location is the first of a number of hardware registers that we will discuss. Although they can be written to and/or read like RAM, they are connected to hardware devices, and their contents affect the operation of the devices.

Each bit of this Data Direction Register determines whether the contents of the corresponding bit on the Internal I/O Port (see location 1) can be written to by peripheral devices. If the bit is set to 0, it indicates the direction of data flow as Input, which means that the corresponding bit of the I/O port will be affected by peripheral defices. If the bit is set to 1, it indicates Output. On the 64, only Bits 0-5 are significant. On power-up, this register is set to 239 ($EF), which indicates that all bits, except for Bit 4 (which senses the cassette switch), are set up for Output.

Datenrichtungsregister für Ein-/Ausgabe-Port des 6510-Mikroprozessors  
Datenrichtungsregister für Prozessor- Port

Bit 0 - 6; 0= Eingang 1= Ausgang

Processor port data direction register

Bits:

  • Bit #x: 0 = Bit #x in processor port can only be read; 1 = Bit #x in processor port can be read and written.

Default: $2F, %00101111.

6510 data direction register   6510 On-Chip Data-Direction Register   6510 On-chip Data Direction Register.   Chip directional register  
$0001 R6510 1
6510 On-Chip I/O Port
  • Bit 0: LORAM signal. Selects ROM or RAM at 40960 ($A000). 1=BASIC, 0=RAM
  • Bit 1: HIRAM signal. Selects ROM or RAM at 57344 ($E000). 1=Kernal, 0=RAM
  • Bit 2: CHAREN signal. Selects character ROM or I/O devices. 1=I/O, 0=ROM
  • Bit 3: Cassette Data Output line.
  • Bit 4: Cassette Switch Sense. Reads 0 if a button is pressed, 1 if not.
  • Bit 5: Cassette Motor Switch Control. A 1 turns the motor on, 0 turns it off.
  • Bits 6-7: Not connected--no function presently defined.

The chief function of this register is to determine which blocks of RAM and ROM the 6510 microprocessor will address. The Commodore 64 comes with 64K RAM, even though it normally does not use all of that RAM at once. In addition, it has an 8K BASIC Interpreter ROM, an 8K Operating System Kernal ROM, a 4K Character Generator ROM, a Sound Interface Device (SID), a 6566 Video Interface Controller (VIC-II), and two 6526 Complex Interface adapter chips.

To address all of these at once would require 88K, 24K past the addressing limit of the 6510 microprocessor. In order to allocate address space, the I/O Port is used to affect the addressing lines, and thus determine which segments of RAM and ROM will be addressed at any one time.

Bit 0. This bit controls the LORAM signal. A 0 in this bit position switches the BASIC ROM out, and replaces it with RAM at addresses 40960-49151 ($A000-$BFFF). The default value of this bit is 1.

Bit 1. Bit 1 controls the HIRAM signal. A 0 in this bit position switches the Kernal ROM out, and replaces it with RAM at 57344-65535 ($E000-$FFFF). As the BASIC interpreter uses the Kernal, it is also switched out and replaced by RAM. The default value of this bit is 1.

The system allows a wide range of combinations of RAM and ROM to be utilized. Of course, the BASIC programmer will have little need, in the ordinary course of events, to switch out the BASIC ROM and the Kernal. To do so would just hang the system up. But one way to make use of this feature is to move the contents of ROM to the corresponding RAM addresses. That way, you can easily modify and customize the BASIC interpreter and OS Kernal routines, which are ordinarily fixed in ROM. For examples, to move BASIC into RAM, just type:

FOR I=40960 TO 49151:POKE I,PEEK(I):NEXT

Though it appears that such a program would not do anything, it in fact copies bytes from ROM to RAM. This is because any data which is written to a ROM location is stored in the RAM which resides at the same address. So while you are PEEKing ROM, you are POKEing RAM. To switch to your RAM copy of BASIC, type in:

POKE 1,PEEK(1) AND 254.

Now you are ready to make modifications. Examples of simple modifications include changing the text which the interpreter prints, such as the READY prompt, the power-up message, or the keyword table.

An example of the latter would be POKE 41122,69. This changes the FOR keyword to FER, so that BASIC would respond normally to a FER-NEXT loop, but fail to recognize FOR as syntactically correct.

On the more practical side, you could change the prompt that INPUT issues to a colon, rather than a question mark:

POKE 43846,58

You are not limited to just cosmetic changes of text. Jim Butterfield has given an example in COMPUTE! magazine of changing the interpreter so that it assigns a null string the ASCII value 0. In the ROM version, the command PRINT ASC("") will return ?ILLEGAL QUANTITY ERROR. This is inconvenient when INPUTting a string, because if the user presses RETURN and you try to check the ASCII value of the string that has been entered, you will get this error. By entering POKE 46991,5, this is changed so that PRINT ASC("") now responds with a zero.

For the more serious machine language programmer, it is quite feasible to add new commands or modify existing ones by diverting the vectors which are discussed in the section covering the BASIC interpreter ROM. For a good example of this technique, see the article "Hi-Res Graphics Made Simple" by Paul Schatz in COMPUTE!'s First Book of Commodore 64 Sound and Graphics. The program example there inserts new graphics commands into a RAM version of BASIC. When you want to switch back to the ROM BASIC, enter POKE 1,PEEK(1) OR 1.

For machine language applications, it would be possible to replace the ROM programs with an entirely different operating system, or an application that has its own screen editing and I/O functions included. Such an application would first have to be loaded from disk into RAM. A language other than BASIC could be loaded, and could then just switch out the BASIC ROM, while still using the OS Kernal.

Or a spreadsheet application that contained its own I/O routines could switch out all ROMs and have the use of all of RAM that is not actually needed for the program itself, for data. It should be remembered, however, that before switching the Kernal out, it is necessary to disable interrupts, as the vectors for these interrupts are contained in the Kernal.

Bit 2. This bit controls the CHAREN signal. A 0 in this position switches the character generator ROM in, so that it can be read by the 6510 at addresses 53248-57343 ($D000-$DFFF). Normally, this bit is set to 1, so that while the VIC-II chip has access to the character generator ROM for purposes of creating the screen display, the user cannot PEEK into it. Since this ROM is switched into the system in the same location as the I/O devices (SID chip, VIC-II chip, and 6526 CIA's), o I/O can occur when this ROM is switched in.

The ability to switch in the character generator ROM is very useful to the programmer who wishes to expirement with user-defined characters. Modified character graphics is one of the more powerful graphics tools available, but often the user will not want to redefine a whole character set at one time. By reading the character ROM and duplicating its contents in RAM, the user can replace only a few characters in the set. The method for reading this ROM into RAM from BASIC is as follows:

10 POKE 56333,127:POKE1,PEEK(1) AND 251:FOR I=0 TO 2048
20 POKE BASE+I,PEEK(53248+I):NEXT:POKE 1,PEEK(1) OR 4:POKE 56333,129

The first POKE is necessary to turn off the system timer interrupt. Since the I/O devices are addressed in the same space as the character ROM, switching that ROM in switches all I/O out, making it necessary to turn off any interrupts which use these devices.

The second POKE is the one which switches in the character ROM. The program loop then reads this ROM memory into RAM, starting with the address BASE. Note that this address should start on an even 2K boundary (an address evenly divisible by 2048) within the block of memory presently being addresses by the VIC-II chip (for more information on where to put user-defined character sets, and how to use them, see the section on the VIC-II chip, under location 53272 ($D018), the section on the character ROM at 49152 ($C000), and the section on banking VIC-II memory at 56576 ($DD00)). After reading the contents of ROM into RAM, the next POKEs switch out the character ROM and restore the interrupt.

It should be noted that while Bits 0-2 of this register allow software control of some signals that determine the memory configuration that is used by the Commodore 64 at any given time, they are not the only determining factor. Signals can also be generated by means of plug-in expansion cartridges which are connected to the expansion port, and these can change the memory map.

Two lines located on the exapansion port are called GAME and EXROM. When used in conjunction with the software-controlled lines noted above, these two hardware lines can enable cartridge ROM to replace various segments of ROM and/or RAM.

Possible configurations include 8K of cartridge ROM to be switched in at $8000-$9FFF, for a BASIC enhancement program; an 8K cartridge ROM at $A000-$BFFF, replacing BASIC, or at $E000-$FFFF, replacing the Kernal, or a 16k cartridge at $8000-$C000.

When cartridge ROM is selected to replace the Kernal, a Max emulator mode is entered, which mimics the specification of the ill-fated Max Machine, a game machine which Commodore never produced for sale in the U.S. In this mode, only the first 6K of RAM are used, there is no access to the character ROM, and graphics data such as charactger dot-data is mapped down from 57344 ($E000) to 8192 ($2000). Further hardware information may be obtained from the Commodore 64 Programmer's Reference Guide.

Bits 3-5 of this register have functions connected with the Datasette recorder. These are as follows:

Bit 3. This is the Cassette Data Output line. This line is connected to the Cassette Data Write line on the cassette port, and is used to send the data which is written to tape.

Bit 4. This bit is the Cassette Switch Sense line. This bit enables a program to tell whether or not one of the buttons that moves the recorder is pressed down. If the switch on the recorder is down, this bit will have a value of 1. Remember that Bit 4 of the data direction register at location 0 must contain a 0 for this bit to properly reflect the status of the switch.

Bit 5. Bit 5 is the Cassette Motor Control. Setting this bit to zero allows the motor to turn when you press one of the buttons on the recorder, while setting it to one disables it from turning.

Most of the time, the setting of this bit will be controlled by the interrupt routine that is used to read the keyboard every sixtieth of a second. If none of the buttons on the recorder is pressed, that interrupt routine shuts the motor off and sets the interlock at location 192 ($C0) to zero. When a button is pressed, if the interlock location is zero, Bit 5 of this register is set to zero to turn the motor on.

When the interlock location contains a zero, the keyscan routine will not let you control the setting of this bit of the register (and the interlock is always set to zero when no buttons are pressed). In order for you to gain control of the motor, you must POKE a nonzero value into 192 after a button on the recorder has been pressed. You can then shut off the motor and turn it back on as you please, by manipulating this bit, so long as a button stays pressed.

Datenregister für Ein-/Ausgabe-Port des 6510-Mikroprozessors

Im Gegensatz zum Mikroprozessor des VC 20 hat der des C 64 sechs Ein-/Ausgabe- Leitungen, die einzeln programmierbar sind und so eine direkte Verbindung zwischen dem Mikroprozessor und der Außenwelt herstellen. Warum nur sechs Leitungen und nicht wie üblich acht? Auf dem Chip selbst könnten acht Bit verkraftet werden, aber es stehen nur sechs Anschlußbeine zur Verfügung.

Um trotzdem flexibel zu bleiben, ist dieses Tor zum Prozessor - zutreffend auch »Port« genannt - in beiden Richtungen begehbar. Jede einzelne der sechs Leitungen kann vom Programmierer auf »Eingang« oder auf »Ausgang« geschaltet werden. Dazu dient das Datenrichtungsregister in der Speicherzelle 0.

Datenrichtungsreglster in Zelle 0

Wenn zum Beispiel in das Bit 4 der Zelle 0 eine 0 hineingePOKEt wird, ist die Leitung Nummer 4 des Ports auf »Eingang« geschaltet. Es gilt für alle 6 Bit (Nummer 0 bis 5):

  • Bit auf 0 = Eingang
  • Bit auf 1 = Ausgang

Beim Einschalten schreibt das Betriebssystem in dieses Register die Dualzahl ..101111 (dezimal=47). Das heißt also, daß nur die Leitung Nummer 4 als Eingang verwendet wird, alle anderen aber als Ausgang. Warum das so ist, sehen wir gleich. Vorher will ich aber noch erwähnen, daß im C 64 von dieser Flexibilität des Mikroprozessor-Ports kein Gebrauch gemacht wird. Ich habe das ganze Betriebssystem durchgesehen, aber das einzige Mal, wo die Speicherzelle 0 angesprochen wird, ist eben bei der Einschaltroutine.

Das heißt aber nicht, daß Sie, lieber Hobby-Programmierer, darauf verzichten müssen. Ich kann mir vorstellen, daß besonders Ausgefuchste unter Ihnen durch POKEn eines anderen Bitmusters in die Speicherzelle 0 vielseitige Befehle erzeugen und einsetzen können.

Das wird besonders deutlich, wenn Sie jetzt sehen, mit welchen Teilen des Computers diese sechs Leitungen verbunden sind.

Datenregister in Speicherzelle 1

Mit diesem Register steuert der Mikroprozessor (und damit natürlich das Betriebssystem) die Auswahl von Speicherblöcken und den Betrieb mit dem Kassettenrecorder. Dem Programmierer steht diese Möglichkeit über POKEn auch zur Verfügung.

Bit 0

schaltet den Speicherbereich 40960 bis 49151 ($A000 bis $BFFF) zwischen dem Basic-Übersetzer (Interpreter) im ROM und freiem RAM um (Normalzustand = 1).

Bit 1

schaltet den Speicherbereich 57344 bis 65535 ($E000 bis $FFFF) zwischen dem Betriebssystem (Kernel) im ROM und freiem RAM um (Normalzustand = 1).

Bit 2

schaltet den Speicherbereich 53248 bis 57343 ($D000 bis $DFFF) zwischen Zeichen-ROM und Ein-/Ausgabe-ROM um (Normalzustand = 1).

Bit 3

sendet serielle Daten zum Kassettenrecorder (Normalzustand = 0).

Bit 4

prüft, ob eine der Tasten des Recorders gedrückt ist, welche den Motor einschalten (Normalzustand = 1).

Bit 5

schaltet den Motor des Recorders ein und aus (Normalzustand = 1).

Die RAM-ROM-Umschaltung

Sie wissen, daß Ihr C 64 deswegen so heißt, weil er 64 KByte Speicherplätze hat. Nur stimmt das nicht! Er hat nämlich 88 KByte und müßte eigentlich C 88 heißen.

Da mit den 16 Bit der High-/Low-Byte-Methode (siehe Texteinschub Nr. 2) nur 64 KByte adressierbar sind, müssen die restlichen 22 KByte bei Bedarf eingeschoben werden - und das machen die oben erwähnten Bit 0 bis 2 des Datenregisters.

In Bild 1 sehen Sie die drei oben erwähnten Speicherblöcke, die sowohl mit RAM als auch mit ROM belegt sind, einer davon gleich doppelt. Ich habe ihnen folgende Namen gegeben:

  • 40960 bis 49151 ($A000 bis $BFFF) = BLOCK A
  • 53248 bis 57343 ($D000 bis $DFFF) = BLOCK D
  • 57344 bis 65535 ($E000 bis $FFFF) = BLOCK E

Tabelle 2 gibt Ihnen die Übersicht über die gemeinsame Wirkung der Bit 0, 1 und 2 des Datenregisters auf den jeweiligen Inhalt der Speicherblöcke.

Der Vollständigkeit halber muß ich hier noch erwähnen, daß neben den drei ersten Bits der Speicherzelle 1 noch zwei weitere Signale die RAM/ROM- Umschaltung beeinflussen. Es sind das die Leitungen auf Pin 8 und 9 des Erweiterungssteckers (GAME und EXROM), welche durch Spiel- und Programmodule benutzt werden. Eine genaue Beschreibung der dadurch erzeugten sinnvollen Speicherkombinationen finden Sie in dem Buch »64 Intern« von Data Becker ab Seite 14. Zwei Anwendungsbeispiele dieser Umschaltung finden Sie im Texteinschub Nr. 3 »Manipuliertes Basic«.

Betrieb des Kassettenrecorders

Bit 3, 4 und 5 regeln, wie schon gesagt, den Betrieb des Kassettenrecorders.

Zu Bit 3 ist oben schon das Notwendige gesagt.

Bit 4 ist im Normalzustand auf 1, »normal« heißt hier, solange keine der Motor- Tasten der Datasette (PLAY, REWIND, FAST FORWARD) gedrückt ist. Zur Probe:

10 X=PEEK(1)

funktioniert das alles nur, wenn - wie im »Normalfall« - das Bit 4 des Datenrichtungsregisters (Speicherzelle 0) auf 0 (Eingang) steht.

Bit 5 schaltet den Motor der Datasette ein und aus. Es bietet sich an, damit per Programm die Datasette zu schalten - wenn so etwas nützlich ist. Leider ist dieses Bit etwas schwieriger zu handhaben, da es in der Interrupt-Routine des Betriebssystems eine Rolle spielt.

Die Tasten der Datasette werden nämlich 60mal in der Sekunde abgefragt. Wenn keine Taste gedrückt ist, setzt das Betriebssystem sowohl das sogenannte »Interlock«-Register in Speicherzelle 192 auf 0 als auch Bit 5 der Zelle 1 auf 1, wodurch der Motor ausgeschaltet wird beziehungsweise bleibt. Da kann man nicht dagegen an. Wir haben nur eine Chance, wenn eine Taste bereits gedrückt ist und der Kassettenmotor schon läuft.

Dann nämlich können wir zuerst das Interlock-Register mit einem Wert größer als 0 lahmlegen:

POKE 192,255

Jetzt läßt sich der Motor der Datasette mit Bit 5 steuern: POKE 1,39 beziehungsweise POKE 1,PEEK(1) OR 32 schaltet den Motor aus,

POKE 1,7 beziehungsweise POKE 1,PEEK(1) AND 31 schaltet den Motor ein.

Das Interlock-Register in Speicherzelle 192 werde ich später noch einmal erwähnen, da es seine Funktion auch beim VC 20 ausübt, allerdings mit anderen Ein-/Ausgangs-Ports. Das ist alles, was zur Speicherzelle 1 zu sagen ist.

Ab Speicherzelle 3 bis zur Speicherzelle 672 gelten alleAngaben sowohl für den C 64 als auch für den VC 20, zumindest was die Bedeutung der Zellen betrifft. Ihr Inhalt kann entsprechend der verschiedenen Adressen der Betriebssysteme voneinander abweichen. Wie üblich werde ich natürlich jeweils darauf aufmerksam machen.

Prozessorport

Im Prozessorport kann man angeben, welche Speicherbereiche ein- oder ausgeschaltet werden.

Bitbeschreibung:

Bit 0 1 = BASIC-ROM, 0= RAM
Bit 1 1 = KERNAL-ROM, 0= RAM
Bit 2 1 = I/O 0= Zeichensatz
Bit 3 Datenausgabe von Datasette
Bit 4 0 = Taste bei Datasette gedrückt
1 = nicht gedrückt
Bit 5 1 = Motor an, 0= Motor aus

Die Bits 6 und 7 sind unbenutzt und immer 0

Processor port

Bits:

  • Bits #0-#2: Configuration for memory areas $A000-$BFFF, $D000-$DFFF and $E000-$FFFF. Values:
  • %x00: RAM visible in all three areas.
    • %x01: RAM visible at $A000-$BFFF and $E000-$FFFF.
    • %x10: RAM visible at $A000-$BFFF; KERNAL ROM visible at $E000-$FFFF.
    • %x11: BASIC ROM visible at $A000-$BFFF; KERNAL ROM visible at $E000-$FFFF.
    • %0xx: Character ROM visible at $D000-$DFFF. (Except for the value %000, see above.)
    • %1xx: I/O area visible at $D000-$DFFF. (Except for the value %100, see above.)
  • Bit #3: Datasette output signal level.
  • Bit #4: Datasette button status; 0 = One or more of PLAY, RECORD, F.FWD or REW pressed; 1 = No button is pressed.
  • Bit #5: Datasette motor control; 0 = On; 1 = Off.

Default: $37, %00110111.

6510 data register   6510 On-Chip 8-Bit Input/Output Register   6510 On-chip 8-bit Input/Output Register.   Chip I/O; memory & tape control  
$0002 2 Unused   unbenutzt   unbenutzt   Unused       Unused   Unused. Free for user programs.      
$0003-$0004 ADRAY1 3-4
Vector: Routine to Convert a Number from Floating Point to Signed Integer

This vector points to the address of the BASIC routine which converts a floating point number to an integer. In the current Kernal version, the address that it points to is 45482 ($B1AA). Disassembly of the ROMs indicates that BASIC does not use this vector. However, it may be of real assistance to the programmer who wishes to use data that is stored in floating point format. The parameter that is passed by the USR command is available only in that format, for example.

Since it is extremely difficult to decipher and use a floating point number, the simplest way to deal with such data is to use the conversion routines that are built into BASIC to change it into a two-byte signed integer. This could be accomplished by jumping directly into the BASIC ROM, if you know the location of the routine. Therefore, if the address changes in future versions of the 64 or future Commodore computers, you won't have to modify your program to make it work with them.

See the entry for the USR vector at 785 ($0311) for an explanation of how to use this routine in connection with the USR command.

Vektor auf die Routine zur Umwandlung einer Gleitkommazahl in eine ganze Zahl mit Vorzeichen

In diesen beiden Speicherzellen steht also ein Vektor. Was das ist, wird im Texteinschub Nr. 4 näher erläutert. Beim VC 20 deutet dieser Vektor auf die Adresse 63674 ($D1AA), beim C 64 auf 45482 ($B1AA). Sie können das mit

PRINT PEEK (3)+256*PEEK (4)

leicht nachprüfen. Ab diesen Adressen beginnt im Basic-Übersetzer (Interpreter) ein Programm, welches - natürlich in Maschinensprache - eine Gleitkommazahl in eine ganze Zahl umwandelt.

Diejenigen Leser, die mit Gleitkommazahlen nicht so vertraut sind, möchte ich auf den Texteinschub Nr. 6 verweisen. Er ist nur eine kleine Einführung. Eine detaillierte Beschreibung finden Sie im Assemblerkurs (Teil 8) von Heimo Ponnath (Ausgabe 4/85) beziehungsweise im 64er-Sonderheft 8/85, ab Seite 42.

Dieses Umwandlungsprogramm steht nicht nur den Maschinen, sondern auch den Basic-Programmierern zur Verfügung, allerdings nur über den USR-Befehl und da auch nur, wenn der »Floating Point Accumulator« #1 (FAC1) in den besagten Adressen 97 bis 102 mitbenutzt wird. Ich verschiebe daher alle weiteren Details auf unsere Ankunft bei diesen Speicherzellen.

Vektor für Umwandlung von Fließkomma nach Fest

Von diesen Adressen aus beginnt der Interpreter, eine Gleitkommazahl in eine ganze Zahl umzuwandeln. Der Vektor deutet auf die Adresse $B1AA.

Unused.

Default: $B1AA, execution address of routine converting floating point to integer.

Store here the addr of the routine to turn the FAC into a two byte signed integer in [Y,A]   Jump Vector: Convert Floating-Integer   Jump Vector: Convert FAC to Integer in (A/Y) ($B1AA).   Float-Fixed vector  
$0005-$0006 ADRAY2 5-6
Vector: Routine to Convert a Number from Integer to Floating Point

This vector points to the address of the BASIC routine which converts an integer to a floating point number. This routine is currently located at 45969 ($B391). BASIC does not appear to reference this location. It is available for use by the programmer who needs to make such a conversion for a machine language program that interacts with BASIC. For an explanation of how to use this routine in connection with the USR command, see the entry for the USR vector at 785 ($0311).

Vektor auf die Routine zur Umwandlung einer ganzen Zahl in eine Gleitkommazahl

Dieses Programm ist die Umkehrung der oberen Routine. Sie beginnt beim VC 20 ab Speicherzelle 54161 ($D391), beim C 64 ab 45969 ($B391). Da hier prinzipiell dasselbe gilt wie oben, möchte ich nur kurz den Vorteil beleuchten, den derartige Vektoren haben. Eigentlich könnten wir direkt auf die im Vektor enthaltenen Adressen springen - wenn wir sie kennen.

Ein Sprung auf die Adresse des Vektors erlaubt uns jedoch immer die völlige Ignoranz seines Inhalts - und Commodore erlaubt die Änderung der Adressen im Basic-Übersetzer, wie es ja beim C 64 gegenüber dem VC 20 auch gemacht worden ist, ohne daß vorhandene Programme umgeschrieben werden müssen.

Vektor für Umwandlung von Fest nach Fließkomma

Diese Routine verwandelt eine ganze Zahl in eine Fließkommazahl. Der Zeiger steht auf $B391.

Unused.

Default: $B391, execution address of routine converting integer to floating point.

Store here the addr of the routine to convert [Y,A] to a floating point number in the FAC.   Jump Vector: Convert Integer--Floating   Jump Vector: Convert Integer in (A/Y) to Floating point in (FAC); ($B391).   Fixed-Float vector  
$0007-$0008 7-8                         Temporary Integer during OR/AND.      
$0007 CHARAC 7
Search Character for Scanning BASIC Text Input

This location and the next are used heavily by the BASIC routines that scan the text that comes into the buffer at 512 ($0200), in order to detect significant characters such as quotes, comma, the colon which separates BASIC statements, and end-of-line. The ASCII values of such special characters are usually stored here.

This location is also used as a work area by other BASIC routines that do not involve scanning text.

Suchzeichen zur Prüfung von Texteingaben in Basic

Diese Speicherzelle wird viel von denjenigen Basic-Routinen als Zwischenspeicher benutzt, die den direkt eingegebenen Text absuchen, um Steuerzeichen (Gänsefüße, Kommata, Doppelpunkte und die Zeilenbeendigung durch die RETURN-Taste) rechtzeitig zu erkennen. Normalerweise wird in der Zelle 7 der ASCII-Wert dieser Zeichen abgelegt. Die Speicherzelle 7 wird aber auch von anderen Basic-Routinen benutzt. Sie ist daher für den Programmierer praktisch nicht zu verwerten.

Suchzeichen

Die Speicherzelle $07 wird oft von BASIC-Programmen als Suchzeiger für Texteingaben verwendet.

Byte being searched for during various operations.
Current digit of number being input.
 
A delimiting character.   Search Character   Search Character/Temporary Integer during INT.   Search character  
INTEGR             Low byte of first integer operand during AND and OR.
Low byte of integer-format FAC during INT().
 
A one-byte integer from "QINT".              
$0008 ENDCHR 8
Search Character for Statement Termination or Quote

Like location 7, this location is used as a work byte during the tokenization of a BASIC statement. Most of the time, its value is 0 or 34.

Suchzeichen speziell für Befehlsende und Gänsefüße

Wie Speicherzelle 7 dient auch die Zelle 8 als Zwischenspeicher für Basic- Texteingabe und zwar während der Umwandlung von Basic-Befehlen in den vom Computer verwendeten Befehlscode (Tokens). Die Speicherzelle 8 ist in Basic nicht verwertbar.

Hochkomma-Flag

Während der Umwandlung von BASIC-Befehlen in Tokens wird die Speicherzelle $08 als Zwischenspeicher für BASIC-Texteingaben verwendet.

Byte being search for during various operations.
Current byte of BASIC line during tokenization.
High byte of first integer operand during AND and OR.
 
The other delimiting character.   Flag: Scan for Quote at End of String   Flag: Scan for Quote at end of String.   Scan-quotes flag  
$0009 TRMPOS 9
Column position of the Cursor before the Last TAB or SPC

TRMPOS is used by TAB and SPC. The cursor column position prior to the TAB or SPC is moved here from 211 ($D3), and is used to calculate where the cursor ends up after one of these functions is invoked. Note that the value contained here shows the position of the cursor on a logical line. Since one logical line can be up to two physical lines long, the value stored here can range from 0 to 79.

Spaltenposition des Cursors vor dem letzten TAB- oder SPC-Befehl

Speicherzelle 9 wird von den Basic-Befehlen TAB und SPC verwendet. Vor ihrer Ausführung wird die Nummer der Spalte, in der sich der Cursor befindet, aus der Speicherzelle 211 ($D3) nach 9 gebracht, von wo sie geholt wird, um die Position des Cursors nach der Ausführung von TAB und SPC auszurechnen.

Diese komplizierte Erklärung können wir durch Ausprobieren deutlicher machen. Dazu PRINTen wir 16mal den Buchstaben X hintereinander (Semikolon!), allerdings mit SPC (2) jeweils um 2 Spalten versetzt.

10 FOR I=0 TO 15
20 PRINT SPC (2) "X";
30 PRINT PEEK (9);
40 NEXT I

Nach jedem X wird durch Zeile 30 die »alte« Cursor-Spaltenposition ausgedruckt und zwar in derselben Zeile, ausgelöst durch das Semikolon. Dadurch erhöht sich laufend die in Speicherzelle 9 stehende Positionsangabe des Cursors. Wir erhalten folgenden Ausdruck:

..X.0...X.6...X.12...X.19...X.26...X.33...X.40...X.47.
..X.54...X.61...X.68...X.75...X.82...X.1...X.7...X.13

Sie können die Positionsnummer nachrechnen. Berücksichtigen Sie aber dabei, daß bei PRINT vor und nach jeder Zahl eine Stelle frei bleibt, die erste für das Vorzeichen, die zweite wegen des Abstandes.

Wichtig ist außerdem, daß die maximal mögliche Spaltenzahl nicht die Bildschirmspaltenzahl, sondern die »logische« Spaltenzahl ist, also 88 beim VC 20 und 80 beim C 64.

Wir können die Cursorposition in Adresse 9 auch abfragen und ein Programm damit steuern. Fügen Sie einfach in das obige Programm die folgende Zeile 35 ein:

35 IF PEEK (9)=33 THEN PRINT "END": END

Sobald Position 33 erreicht ist, bleibt das Programm stehen.

Speicher für Spalte beim TAB-Befehl

Nach der Ausführung von TAB oder SPC wird die Cursorposition in der Speicherzelle 9 zwischengespeichert.

Current column number during SPC() and TAB().   Position of terminal carriage.   Screen Column From Last TAB   Screen Column for last TAB.   TAB column save  
$000A VERCK 10
Flag: LOAD or VERIFY

BASIC uses one Kernal routine to perform either the LOAD or VERIFY function, depending on whether the Accumulator (.A) is set to 0 or 1 upon entry to the routine. BASIC sets the value of VERCK to 0 for a LOAD, or 1 for a VERIFY. Its contents are passed to the Kernal LOAD routine, which in turn stores it in location 147 ($93).

Flagge für LOAD oder VERIFY

In Zelle 10 steht eine 0, wenn geladen wird und eine 1 bei einem VERIFY. Warum das so ist, will ich kurz erläutern:

Die Basic-Routinen für LOAD beziehungsweise für VERIFY sind völlig identisch. Was das Betriebssystem hinterher daraus machen muß, ist natürlich unterschiedlich. Das Basic erspart sich eine doppelte Routine, zeigt aber mit der Flagge in Speicherzelle 10 den Unterschied an.

Erwähnenswert ist noch, daß das Betriebssystem in einer Art Nationalismus seine eigene Flagge aufzieht: Den Unterschied zwischen LOAD und VERIFY speichert es seinerseits in Zelle 147 ($93) ab. Soweit ich es sehen kann, sind Inhalt und Bedeutung beider Speicherzellen völlig identisch.

Ich habe für Sie zwar kein Kochrezept zur Anwendung der LOAD-VERIFY-Flagge in einem Programm vorrätig, möchte Sie aber trotzdem ein bißchen zum Spielen anregen. Um meine Erklärung nachzuvollziehen, tippen Sie bitte direkt LOAD ein.

Den Ladevorgang brechen Sie mit der STOP-Taste ab und fragen dann den Inhalt der Zelle 10 ab mit

PRINT PEEK (10)

Wir erhalten eine 0.

Wiederholen Sie bitte diesen Vorgang, aber mit VERIFY. Wir erhalten jetzt eine 1 - Quod erat demonstrandum.

Wir können auch in die Zelle 10 hineinPOKEn. Die »Wachablösung« zwischen Basic und Betriebssystem unter Hissen der Flagge in Zelle 10 findet beim VC 20 in der Speicherzelle 57705, beim C 64 in 57708 statt. Bevor wir diese Maschinenroutine mit SYS 57705 (SYS 57708) starten, geben wir mit dem Inhalt der Speicherzelle 10 an, ob es ein LOAD oder ein VERIFY sein soll.

Legen Sie ein Band mit Programm in die Datasette. Um ein LOAD zu erzeugen, geben wir direkt ein:

POKE 10,0:SYS 57705
(POKE 10,0:SYS 57708)

Entsprechend der Anweisung auf dem Bildschirm drücken Sie PLAY, und das Auffinden des ersten Programms wird mit LOAD gemeldet. Machen Sie das Ganze noch einmal, diesmal aber POKEn Sie bitte eine 1 in die Zelle 10. Jetzt meldet das Betriebssystem das Auffinden des Programms mit VERIFY.

Wie gesagt, vielleicht fällt Ihnen eine Anwendung dafür ein.

0= LOAD, 1= Verify, Flag des Interpreters

Weil die Routine von LOAD und VERIFY identisch ist, wird ein Flag benötigt, um zu unterscheiden, ob ein LOAD oder ein VERIFY-Vorgang ausgeführt worden ist.

LOAD/VERIFY switch

Values:

  • $00: LOAD.
  • $01-$FF: VERIFY.
    Flag: 0 = Load, 1 = Verify   Flag: 0 = Load, 1 = Verify.   0 = LOAD, 1 = VERIFY  
$000B COUNT 11
Index into the Text Input Buffer/Number of Array Subscripts

The routines that convert the text in the input buffer at 512 ($0200) into lines of executable program tokes, and the routines that link these program lines together, use this location as an index into the input buffer area. When the job of converting text to tokens is finished, the value in this location is equal to the length of the tokenized line.

The routines which build an array or locate an element in an array use this location to calculate the number of DIMensions called for and the amount of storage required for a newly created array, or the number of subscripts specified when referencing an array element.

Flagge für den Eingabepuffer/Anzahl der Dimensionen von Zahlenfeldern (Arrays)

Alle Buchstaben und Zeichen, die mit der Tastatur direkt eingetippt werden, kommen in einen Eingabe-Pufferspeicher.

Er beginnt ab Speicherzelle 512 ($0200). Sobald die RETURN-Taste gedrückt wird, wandelt eine Routine des Basic-Übersetzers den Text in Codezahlen (Tokens) um. Diese Routine und eine andere, welche die Zeilen eines Programms aneinanderhängt, verwenden die Zelle 11 als Zwischenspeicher.

Sobald die Textumwandlung beendet ist, steht in Zelle 11 eine Zahl, die die Länge der Token-Zeile angibt.

Die Zelle 11 wird außerdem noch von den Basic-Routinen benutzt, die ein Feld (Array) aufbauen oder ein bestimmtes Element in einem Array suchen. Was ein Feld oder Array ist, finden Sie in den Commodore-Handbüchern gut beschrieben. Außerdem gehe ich bei der Behandlung der Speicherzellen 47 bis 50 näher darauf ein.

Diese Routinen also verwenden die Speicherzelle 11, um die Anzahl der verlangten DIMensionen und den für ein neu aufgebautes Feld nötigen Speicherbedarf zu berechnen.

Zeiger im Eingabepuffer, Anzahl der Dimensionen

Die Speicherzelle $0B wird dazu verwendet, die Anzahl der Dimensionen zu berechnen. Außerdem wird noch die Länge der Tokenzeile hier angegeben.

Current token during tokenization.
Length of BASIC line during insertion of line.
AND/OR switch; $00 = AND; $FF = OR.
Number of dimensions during array operations.
 
A general counter.   Input Buffer Pointer / No. of Subscripts   Input Buffer Pointer/Number of Subscripts.   Input buffer pointer/# subscrpt  
$000C DIMFLG 12
Flags for the Routines That Locate or Build an Array

This location is used as a flag by the routines that build an array or reference an existing array. It is used to determine whether a variable is in an array, whether the array has already been DIMensioned, and whether a new array should assume the default dimensions.

Flagge für Basic-Routinen, die ein Feld (Array) suchen beziehungsweise aufbauen

Diese Speicherzelle wird von den Basic-Routinen als Zwischenspeicher benutzt, die feststellen, ob eine Variable ein Feld (Array) ist, ob das Feld bereits DIMensioniert worden ist, oder ob ein neues Feld die unDIMensionierte Zahl von 11 Elementen hat.

Flag für DIM

Diese Speicherzelle wird benutzt, um festzustellen, ob die Variable ein Array oder schon eine dimensionierte Variable ist.

Switch for array operations

Values:

  • $00: Operation was not called by DIM.
  • $40-$7F: Operation was called by DIM.

In getting a pointer to a variable it is important to remember whether it is being done for "dim" or not.

DIMFLG and VALTYP must be consecutive locations.

Flag: Default Array DiMension   Flag: Default Array dimension.   Default DIM flag  
$000D VALTYP 13
Flag: Type of Data (String or Numeric)

This flag is used internally to indicate whether data being operated upon is string or numeric. A value of 255 ($FF) in this location indicates string data, while a 0 indicates numeric data. This determination is made every time a variable is located or created.

Flagge zur Bestimmung des Datentyps (Zeichenkette/String oder Zahl)

Diese Flagge zeigt den Routinen des Basic-Übersetzers an, ob es sich bei den zur Verarbeitung anstehenden Daten um einen String oder um Zahlenwerte handelt. Zeigt die Flagge 255 ($FF), ist es ein String. Bei 0 handelt es sich um Zahlen. Diese Bestimmung erfolgt jedesmal, wenn eine Variable definiert oder gesucht wird. Diese Flagge kann leider nicht durch ein Basic-Programm abgefragt werden.

Typflag $00= numerisch, $FF= String

Das Flag zeigt dem BASIC-Interpreter an, ob es sich um Zahlenwerte oder um einen String handelt.

Current expression type

Values:

  • $00: Numerical.
  • $FF: String.
The type indicator.

0=numeric 1=string.

Data Type: $FF = String, $00 = Numeric   Data type Flag: $00 = Numeric, $FF = String.   Type : FF = string, 00 = numeric  
$000E INTFLG 14
Flat: Type of Numeric Data (Integer or Floating Point)

If data which BASIC is using is determined to be numeric, it is further classified here as either a floating point number or as an integer. A 128 ($80) in this location identifies the number as an integer, and a 0 indicates a floating point number.

Flagge zur Bestimmung des Zahlentyps (Ganze Zahl oder Gleitkommazahl)

Sobald durch die Flagge in der vorherigen Zelle 13 eine Zahl signalisiert wird, steht hier die Zahl 128 ($80), wenn es sich um eine ganze Zahl handelt, während eine 0 die Zahl als Gleitkommazahl identifiziert.

Damit wollen wir ein bißchen experimentieren. Zeile 10 definiert eine Gleitkommazahl, Zeile 20 druckt sie und die Flagge aus Zelle 14 aus.

10 A=13.41
20 PRINT A,PEEK (14)

Wir erhalten dieZahl 13.41 und als Flagge eine 0.

30 B=INT (A)
40 PRINT B,PEEK (14)

INT bildet die ganze Zahl von 13.41. Also müßte die Flagge in Zelle 14 auf 128 stehen. Weit gefehlt! Da intern auch die 13 als Gleitkommazahl berechnet wird, erhalten wir immer noch eine 0.

50 B%=A
60 PRINT B%,PEEK (14)

Erst die Definition der Variablen B als ganze Zahl (mit %) ergibt die Flagge 128.

70 D=16*B%
80 PRINT D,PEEK (14)

Die Multiplikation einer ganzen Zahl mit der Ganzzahl-Variablen B% fällt in dieselbe Kategorie wie Zeile 30 oben, da die Verarbeitung als Gleitkommazahl erfolgt. Also erhalten wir zu Recht eine 0. Erst wenn D als ganze Zahl (Zeile 90) ausgewiesen wird, steht die Flagge wieder auf 128:

90 D%=16*B%
100 PRINT D%, PEEK (14)
$80= Integer, $00= Real

Wenn eine Gleitkommazahl auftritt, steht in der Speicherzelle $00, bei einer ganzen Zahl eine $80.

Current numerical expression type

Bits:

  • Bit #7: 0 = Floating point; 1 = Integer.
Tells if integer.   Data Type: $80 = Integer, $00 = Floating   Data type Flag: $00 = Floating point, $80 = Integer.   Type : 80 = integer, 00 = floating point  
$000F GARBFL 15
Flag for LIST, Garbage Collection, and Program Tokenization

The LIST routine uses this byte as a flag to let it know when it has come to a character string in quotes. It will then print the string, rather than search it for BASIC keyword tokens.

The garbage collection routine uses this location as a flag to indicate that garbage collection has already been tried before adding a new string. If there is still not enough memory, an OUT OF MEMORY message will result.

This location is also used as a work byte for the process of converting a line of text in the BASIC input buffer (512, $0200) into a linked program line of BASIC keyword tokens.

Flagge bei LIST, Garbage Collection und Textumwandlung

Die Routine des LIST-Befehls muß unterscheiden zwischen Basic-Befehlen und normalem Text. Wenn eine Zeichenkette durch ein »Gänsefüßchen« identifiziert worden ist, wird die Flagge gesetzt, und der Text wird ausgedruckt.

Unter »Garbage Collection« (Müllabfuhr) wird die Routine des Betriebssystems verstanden, welche zu bestimmten Anlässen im Variablenspeicher alle nicht mehr benötigten Strings entfernt, um Platz zu schaffen. Dabei wird eine Flagge in Zelle 15 gesetzt, die anzeigt, daß eine Müllabfuhr bereits stattgefunden hat. Wenn bei der Speicherung eines neuen Strings zu wenig Speicherplatz vorhanden ist, wird bei der Flagge nachgesehen, ob gerade vorher schon durch die Müllabfuhr (Garbage Collection) der Speicher entrümpelt worden ist. Falls das der Fall ist, wird OUT OF MEMORY angezeigt, falls nicht, wird eine Müllabfuhr durchgeführt.

Schließlich wird Zelle 15 auch bei der Umwandlung von Basic-Befehlen in internen Codezahlen (Tokens) eingesetzt.

Hochkommaflag bei LIST

Durch diese Speicherzelle wird beim LIST-Befehl durch ein Hochkomma erkannt, ob eine Textkette folgt. Zusätzlich wird in dieser Speicherzelle markiert, ob eine Garbage Collection durchgeführt werden muß oder nicht.

Garbage collection indicator during memory allocation for string variable; $00-$7F = There was no garbage collection yet; $80 = Garbage collection already took place.   Whether to do garbage collection.   Flag: DATA scan/LIST quote/Garbage Coll   Flag: DATA scan/List Quote/Garbage collection.   DATA scan/LIST quote/memry flag  
DORES             Quotation mode switch during tokenization; Bit #6: 0 = Normal mode; 1 = Quotation mode.
Quotation mode switch during LIST; $01 = Normal mode; $FE = Quotation mode.
 
Whether can or can't crunch res'd words.

Turned on when "data" being scanned by crunch so unquoted strings won't be crunched.

           
$0010 SUBFLG 16
Flag: Subscript Reference to an Array or User-Defined Function Call (FN)

This flag is used by the PTRGET routine which finds or creates a variable, at the time it checks whether the name of a variable is valid. If an opening parenthesis is found, this flag is set to indicate that the variable in question is either an array variable or a user-defined function.

You should note that it is perfectly legal for a user-defined function (FN) to have the same name as a floating point variable. Moreover, it is also legal to redefine a function. Using a FN name in an already defined function results in the new definition of the function.

Flagge zur Anzeige eines Variablen-Feldes oder einer selbstdefinierten Funktion

Im Basic-Übersetzer gibt es eine Routine, die den Speicher absucht, ob es eine Variable mit bestimmten Namen bereits gibt. Wenn diese mit einer Klammer beginnt, wird die Flagge in Zelle 16 gesetzt, um anzuzeigen, daß es sich um eine Array-Variable oder um eine mit DEF FN selbstdefinierte Funktion handelt.

Flag für FN

Hier wird angezeigt, ob es sich um eine Array-Variable oder um eine mit DEF FN definierte Variable handelt.

Switch during fetch of variable name

Values:

  • $00: Integer variables are accepted.
  • $01-$FF: Integer variables are not accepted.
Flag whether sub'd variable allowed.

"FOR" and user-defined function pointer fetching turn this on before calling "PTRGET" so arrays won't be detected. "STKINI" and "PTRGET" clear it. Also disallows integers there.

Flag: Subscript Ref / User Function Call   Flag: Subscript reference/User Function call.   Subscript/FNx flag  
$0011 INPFLG 17
Flag: Is Data Input to GET, READ or INPUT?

Since the keywords GET, INPUT, and READ perform similar functions, BASIC executes some of the same instructions for all three. There are also many areas of difference, however, and this flag indicates which of the three keywords is currently being executed, so that BASIC will know whether or not to execute the instructions which relate to the areas in which the commands differ (152 ($98)=READ, 64 ($40)=GET, 0=INPUT).

As a result, INPUT will show the ? prompt, will echo characters back to the screen, and will wait for a whole line of text ended by a carriage return. GET gives no prompt and accepts one character without waiting. The colon character and the comma are valid data for GET, but are treated as delimiters between data by INPUT and READ.

As each command has its own error messages, this flag is used to determine the appropriate message to issue in case of an error.

Flagge für INPUT, GET oder READ

Die Basic-Routinen für INPUT, GET und READ sind zum großen Teil identisch. Um Speicherplatz zu sparen, verwendet der Basic-Übersetzer die identischen Teile nur einmal. Um in die nichtidentischen Teile verzweigen zu können, wird in Zelle 17 angezeigt, um welchen der drei Befehle es sich gerade handelt. Die Flagge steht auf 0 für INPUT, auf 64 ($40) für GET und auf 152 ($98) für READ.

Mit dem folgenden kleinen Programm können wir das leicht nachprüfen.

10 DATA 3
20 READ A
30 PRINT PEEK (17)
40 INPUT B
50 PRINT PEEK (17)
60 GET C$:IF C$= " "THEN 60
70 PRINT PEEK (17)

Zeile 10 und 20, 40 sowie 60 sind Anwendungen der drei zur Debatte stehenden Basic-Befehle. Nach der Durchführung jedes Befehls wird in den Zeilen 30, 50 und 70 die jeweilige Flagge ausgelesen.

Nach RUN erhalten wir als Resultat der Zeile 20 die Zahl 152, als Resultat von Zeile 30 die INPUT-Aufforderung mit Fragezeichen. Geben Sie irgendeine Zahl und RETURN ein. Wir erhalten so die 0. Die GET-Schleife in Zeile 40 wartet auf einen Tastendruck, dann erhalten wir 64.

$00= INPUT, $40= GET, $98= READ

Diese Speicherzelle gibt an, in welche Routine der BASIC-Interpreter verzweigen soll.

GET/INPUT/READ switch

Values:

  • $00: INPUT.
  • $40: GET.
  • $98: READ.
Flags whether we are doing "INPUT" or "READ".   Flag: $00 = INPUT, $40 = GET, $98 = READ   Input Flag: $00 = INPUT, $40 = GET, $98 = READ.   0 = INPUT; $40 = GET; $98 = READ  
$0012 TANSGN 18
Flag: Sign of the Result of the TAN or SIN Function

This location is used to determine whether the sign of the value returned by the functions SIN or TAN is positive or negative.

Flagge für Vorzeichen bei SIN, COS und TAN

Die Routinen des Basic-Übersetzers (Interpreter), welche die drei trigonometrischen Funktionen SIN, COS und TAN berechnen, verwenden die Speicherzelle 18 zur Bestimmung des Vorzeichens.

Zur Erinnerung: Die trigonometrischen Funktionen haben in den vier »Quadranten« des Kreises (0-90, 90-180, 180-270, 270-360 Grad) nicht unbedingt dieselben Vorzeichen. Die Vorzeichen ändern sich allerdings nur an den Grenzen der Quadranten, wie in Bild 2 zu sehen ist. Die Flagge in Zelle 18 gibt das Vorzeichen nicht direkt an, sondern auf Umwegen. Die Darstellung ist in der folgenden Tabelle zusammengefaßt.

Dabei bedeutet »gleich«: 0-0-0-0 oder 255-255-255 »Wechsel«: 0-255-0-255 Da die Erklärung mit »gleich« beziehungsweise »Wechsel« nicht gerade einleuchtend ist, schlage ich vor, daß Sie sich das Ganze mit dem folgenden kleinen Programm selbst anschauen, welches für viele Werte des Winkels im Bogenmaß - und in kleinen Schritten - den Wert der Flagge, daneben den Winkel I und den Wert der Funktion mit Vorzeichen ausdruckt.

10 FOR I=0 TO 10 STEP 0.01
20 PRINT PEEK(18);INT (I*100)/100;SIN(I):NEXT

Diese etwas umständliche Art, den Wert von I auszudrucken, vermeidet Rundungsfehler und begrenzt den Ausdruck auf zwei Dezimalstellen. Wenn Sie die Winkelwerte von I in Graden ausgedruckt haben wollen, können Sie eine ändere Zeile 20 verwenden, welche die Umrechnungsformel vom Bogenmaß in Grade verwendet: Winkel in Grad = Winkel im Bogenmaß * 180/π

20 PRINT PEEK(18);INT(I*180/π);SIN(I):NEXT

Statt SIN können Sie genauso gut COS und TAN einsetzen.

In Bild 2 sind nicht nur die Kurven und die Bereiche der Vorzeichen, sondern auch die Winkelbereiche sowohl im Bogenmaß als auch in Graden dargestellt.

Vorzeichen bei ATN

Die Speicherzelle $12 wird von den trigonometrischen Funktionen zur Bestimmung des Vorzeichens verwendet. Zusätzlich dient die Speicherzelle $12 als Vergleichsoperator für Vergleichsoperationen.

Sign during SIN() and TAN()

Values:

  • $00: Positive.
  • $FF: Negative.
Used in determining sign of tangent.   Flag TAN sign / Comparison Result   Flag: TAN sign/Comparative result.   ATN sign/Comparison eval flag  
DOMASK

Additionally, the string and numeric comparison routines use this location to indicate the outcome of the comparison. For a comparison of variable A to variable B, the value here will be 1 if A is greater than B, 2 if A equals B, and 4 if a is less than B. If more than one comparison operator was used to compare the two variables (e.g., >= or <=), the value here will be a combination of the above values.

Flagge bei Vergleich

Die Speicherzelle 18 wird auch noch von anderen Routinen des Basic-Interpreters beansprucht und zwar von allen, die einen Vergleich wie <, >, >= und so weiter durchführen. Entsprechend der Art des Vergleichs steht dann in der Zelle 18 eine Ziffer von 0 bis 6.

Das folgende Programm macht das deutlich.

10 A=2
20 FOR I=1 TO 3
30 IF I=A  THEN PRINT I; PEEK(18); "="
40 IF I<>A THEN PRINT I; PEEK(18); "><"
50 IF I>A  THEN PRINT I; PEEK(18); ">"
60 IF I<A  THEN PRINT I; PEEK(18); "<"
70 IF I>=A THEN PRINT I; PEEK(18); ">="
80 IF I<=A THEN PRINT I; PEEK(18); "<="
90 IF I<A OR I=A THEN PRINT I; PEEK(18); "< OR ="
100 NEXT I

Kurz zur Erklärung dieser Zeilen: In der FOR..NEXT-Schleife wird die Variable I mit der Konstanten A=2 verglichen. In den Zeilen 30 bis 90 werden alle möglichen Vergleichsoperatoren durchgeprüft. Jeder der zutrifft, druckt den Wert von I, den Wert der dann in Zelle 18 stehenden Flagge und schließlich den Vergleichsoperator aus. Aus dem Resultat dieses Programms läßt sich folgende Tabelle zusammenstellen:

Vergleich Flagge in 18
< OR = 0
> OR = 0
> 1
= 2
>= 3
< 4
<> 5
<= 6

Sie sehen, die Flagge für die kombinierten Vergleichsoperatoren entspricht der Summe ihrer Einzelwerte. Nur die Verknüpfung über OR nicht, denn die ergibt 0.

        Mask in use by relation operations.              
$0013 CHANNL 19
Current I/O Channel (CMD Logical File) Number

Whenever BASIC inputs or outputs data, it looks here to determine which I/O device is currently active for the purpose of prompting or output control. It uses location 184 ($B8) for purposes of deciding what device actually to put input from or output to.

When the default input device (number 0, the keyboard) or output device (number 3, the display screen) is used, the value here will be a zero, and the format of prompting and output will be the standard screen output format.

When another device is used, the logical file number (CMD channel number) will be placed here. This lets the system now that it may have to make some subtle changes in the way it performs the I/O operation. For example, if TAB is used with the PRINT command, cursor right characters are used if the device PRINTed to is the screen. Otherwise, spaces are output when the number here is other than zero (the assumption being that you can't tab a printer like you can the screen).

Likewise, the ? prompt for INPUT is suppressed if the file number here is nonzero, as is the EXTRA IGNORED message, and input of a carriage return by itself is ignored, rather than being treated as a null string (""). Therefore, by OPENing the screen as a device, and issuing the CMD statement, you can force the suppression of the ? prompt, and the other effects above.

CMD places the new output file number here, and calls the Kernal to open the device for output, leaving it LISTENing for output (such as the READY prompt, which is diverted to the new device).

Many routines reset this location and UNLISTEN the device, defeating the CMD and once again sending the output to the screen. If an error message has to be displayed, for example, this location will be reset and the message will be displayed on the screen. GET, GET#, INPUT, INPUT#, and PRINT# all will reset this location after the I/O is completed, effectively redirecting output back to the screen. PRINT and LIST are the only I/O operations that will not undo the CMD.

This location can also be used to fool BASIC into thinking that data it is reading from the tape is actually being entered into the keyboard in immediate mode.

For a look at a technique that uses a different approach to accomplish the same thing for disk or tape users, see location 512 ($0200), the keyboard buffer.

Flagge zur Kennzeichnung des laufenden Ein-/Ausgabegerätes

Immer dann, wenn von Basic Daten ein- oder ausgegeben werden, schaut die entsprechende Routine des Übersetzers in Zelle 19 nach, um welches Peripheriegerät es sich handelt. Zur Debatte stehen Tastatur, Datasette, RS232- User-Port, Bildschirm, Drucker und Floppy-Laufwerk.

Die Flagge ihrerseits ist ausschlaggebend für die feinen Unterschiede, wie zum Beispiel das Fragezeichen, bei Eingabe von der Tastatur (INPUT) oder die Anweisung »Press Play on Tape« bei Eingabe von der Datasette.

Beim Einschalten des Rechners setzt die Initialisierungsroutine des Betriebssystems, die beim VC 20 ab Adresse 58276 ($E3A4), beim C 64 ab 58303 ($E3BF) beginnt, die Flagge in Zelle 19auf 0. Die Null bedeutet Eingabe über Tastatur und Ausgabe über Bildschirm.

Wenn Sie einen Disassembler haben, drucken Sie doch einmal das Assemblerlisting aus. Sie werden in Adresse 58324/58325 ($E3D4/$E3D5), beim C 64 in 58354/58355 ($E3F2/$E3F3) den Befehl finden, der eine Null nach Zelle 19 ($13) bringt.

Immer dann, wenn ein Programm nicht Tastatur und Bildschirm, sondern eines der oben genannten anderen Peripheriegeräte anspricht (indem mit OPEN.... eine Datei = Logical File eröffnet wird), wird in Zelle 19 die Nummer der gerade bearbeiteten Datei eingetragen, mit den bereits beschriebenen Konsequenzen.

Ich will hier nicht weiter darauf eingehen, da wir den Inhalt von Zelle 19 selbst nicht auslesen können. Er wird nämlich immer gleich wieder auf Null gesetzt.

Wir können ihn aber durch POKE verändern. Durch POKE 19,1 gaukeln wir dem Rechner vor, daß Ein- und Ausgabe über »externe« Geräte läuft, selbst wenn nur die Tastatur und der Bildschirm betrieben werden.

Wenn zum Beispiel der Rechner der Meinung ist, daß ein INPUT von der Datasette kommt, druckt er kein Fragezeichen aus; auch kein EXTRA IGNORED als Fehlermeldung bei zu zahlreicher Eingabe und das alleinige Drücken der RETURN- Taste ignoriert er auch, im Gegensatz zum »normalen« INPUT Probieren Sie es aus:

10 INPUT "TEST"; A$
20 PRINT A$

In diesem Normalfall erscheint nach RUN darunter die Aufforderung TEST?

Eine Eingabe, zum Beispiel XX, erscheint mit einem Abstand daneben, und nach RETURN wird XX an den Anfang der nächsten Zeile gedruckt. Alle falschen Eingaben werden mit den üblichen Fehlermeldungen quittiert.

Jetzt fügen wir ein:

5 POKE 19,1

Nach RUN erscheint wieder die Aufforderung TEST, aber ohne Fragezeichen. Die Eingabe XX wird ohne Abstand daneben gesetzt und nach RETURN mit einem Abstand in derselben Zeile weitergeschrieben.

Das Drücken der RETURN-Taste setzt den Cursor nicht wie üblich in die nächste Zeile, sondern schiebt ihn in derselben Zeile weiter.

Diesen zusätzlichen Effekt muß man beachten, da er sehr störend für den Verlauf eines Programms sein kann.

Man kann ihn natürlich auch nutzbringend einsetzen, hat er doch die Eigenschaft eines automatischen »Cursor UP«. Eine pfiffige Anwendung dieser Art wurde von Brad Templeton für den PET erfunden und ist von Jim Butterfield für eine MERGE- Routine mit dem Namen »Magic Merge« veröffentlicht worden.

Da diese Routine aber primär auf der Eigenschaft der Speicherzelle 153 basiert, werde ich sie dann erläutern, sobald wir bei der Zelle 153 angelangt sind.

Zurück zur Flagge in Zelle 19.

Umgekehrt können wir POKE 19,0 leider nicht nutzen, da die betroffenen Befehle GET, GET#, INPUT, INPUT# und PRINT # die Flagge sofort auf den richtigen Wert setzen. Nur PRINT und LIST tun das nicht, wie wir bei dem PRINT-Befehl oben ja gesehen haben.

aktives I/O-Gerät $00= Direkteingabe

Die Speicherzelle $13 wird als Zeiger für die Peripheriegeräte wie Tastatur, Datasette, RS232, User-Port, Bildschirm, Drucker und Floppy verwendet.

Current I/O device number.

Default: $00, keyboard for input and screen for output.

Holds channel number.   Flag: INPUT Prompt   File number of current Input Device.   Current I/O prompt flag  
$0014-$0015 LINNUM 20-21
Integer Line Number Value

The target line number for GOTO, LIST, ON, and GOSUB is stored here in low- byte, high-byte integer format, as is the number of a BASIC line that is to be added or replaced.

LIST saves the highest line number to list (or 65535 ($FFFF) if program is to be listed to the end) at this location.

GOTO tests the target line number to see if it is greater than the line number currently being executed. If it is greater, GOTO starts its search for the target line at the current line number. If it is not greater, GOTO must search for the target line from the first line of the program. It is interesting to note that the test is of the most significant byte only. Therefore, INT(TARGETLINE/256) must be greater than INT(CURRENTLINE/256) in order for the search to start with the current line, instead of at the beginning of the program.

PEEK, POKE, WAIT, and SYS use this location as a pointer to the address which is the subject of the command.

Zeilennummer für LIST, GOTO, GOSUB und ON, Zeiger der Adresse bei PEEK, POKE, SYS und WAIT

In diesen Speicherzellen wird die Zeilennummer der Sprungbefehle GOTO, ON..GOTO und GOSUB sowie die Zeilenangabe beim LIST-Befehl gespeichert. Da die Werte bis maximal 65535 gehen können, braucht der Computer 2 Byte zur High-/Low-Byte- Darstellung.

Die GOTO-Routine (im VC 20 ab 51360 = $C8A0, im C 64 ab 43168 = $A8A0) vergleicht die Zahl in 20 und 21 mit der laufenden Zeilenzahl. Wenn sie kleiner ist, wird ab der ersten Zeile des Programms gesucht. Ist sie aber größer, dann beginnt die Suche ab der laufenden Zeilenzahl. Die Suche geht solange, bis die in 20 und 21 angegebene Zeilenzahl gefunden ist. Dann fährt das Programm mit dieser Zeile fort.

LIST speichert in 20 und 21 die höchste auszulistende Zeilennummer ab, falls keine Angabe beim LISTen gegeben worden ist, den Wert 65535 ($FFFF).

Die Befehle PEEK, POKE, SYS und WAIT verwenden diese Speicherzellen zur Angabe der Adressen, die dem Befehl immer folgen müssen.

Leider können wir die Speicherzellen 20 und 21 mit Basic-Programmen nicht bearbeiten; ihr Inhalt wird immer gleich auf 20 zurückgesetzt.

Integer-Adresse z.B. Zeilennummer

In dieser Speicherzelle werden die Zeilennummern von den Befehlen wie ON..GOTO, GOTO, GOSUB, ON..GOSUB und der Zeilenausgabe beim LIST-Befehl gespeichert.

Line number during GOSUB, GOTO and RUN.
Second line number during LIST.
 
Location to store line number before BUF so that "BLTUC" can store it all away at once.

A comma (preload or from ROM) used by input statement since the data pointer always starts on a comma or terminator.

Temp: Integer Value   Temporary: Integer value.   Integer value  
POKER             Memory address during PEEK, POKE, SYS and WAIT.  
Set up location used by POKE.

Temporary for input and read code

           
$0016 TEMPPT 22
Pointer to the Next Available Space in the Temporary String Stack

This location points to the next available slot in the temporary string descriptor stack located at 25-33 ($19-$21). Since that stack has room for three descriptors of three bytes each, this location will point to 25 ($19) if the stack is empty, to 28 ($1C) if there is one entry, to 31 ($1F) if there are two entries, and to 34 ($22) if the stack is full.

If BASIC needs to add an entry to the temporary string descriptor stack, and this location holds a 34, indicating that the stack is full, the FORMULA TOO COMPLEX error message is issued. Otherwise, the entry is added, and three is added to this pointer.

Zeiger auf den nächsten freien Speicherplatz im »Temporary String Descriptor Stack«

Dieser Zeiger bezieht sich in seiner Wirkung auf die übernächsten Speicherzellen 25 bis 33 ($19 bis $21).

Diese werden als Stapelspeicher (Stack) für Angaben über vorläufige Zeichenketten - auf englisch »Temporary String Descriptor« - verwendet.

Die Speicherzelle 22 ($16) ihrerseits enthält einen Zeiger auf den jeweils nächsten verfügbaren Platz in diesem Speicher ab Zelle 25. Da er eine Kapazität von 3 * 3 Byte hat, zeigt der Zeiger auf die Zelle 25 ($19), wenn er leer ist. Bei einem Eintrag zeigt er auf 28 ($1C), bei zwei Einträgen auf 31 ($1F) und schließlich auf 34 ($22), wenn der Speicher voll ist.

Eine Zeichenkette ist dann »vorläufig«, wenn sie noch nicht einer Stringvariablen zugeordnet worden ist, zum Beispiel »Mahlzeit« in dem Basic- Befehl

PRINT "MAHLZEIT".

Beim Einschalten setzt das Betriebssystem mit der Einschaltroutine ab Adresse 58303 ($E3BF) im C 64, beim VC 20 ab 58276 ($E3A4) den Zeigerauf 25. Die Stringverwaltungsroutine ab 46215 ($B487) im C 64 beziehungsweise ab 54407 ($D487) im VC 20 fragt bei String-Eingaben die Flagge ab. Nach jeder Eintragung in den Speicher ab Zelle 25 wird der Zeiger um 3 weitergesetzt.

Sie können die Leerflagge 25 mit

PRINT PEEK (22)

leicht nachprüfen.

Die anderen Eintragungen können nicht nachgeprüft werden, weil sie sofort auf 25 zurückgesetzt werden.

Wir können sie aber durch POKE beeinflussen; ob das sinnvoll ist, ist eine andere Frage.

10 POKE 22,34
20 PRINT "MAHLZEIT"

Die Zahl 34 in Zelle 22 sagt dem Programm, daß der Speicher ab Zelle 25 voll ist. Wir bekommen statt der MAHLZEIT eine Fehlermeldung serviert.

Mit einem POKE-Befehl, der als Argument die für den vorgesehenen Zweck ungültige Zahl 35 verwendet:

POKE 22,35

erreichen wir allerdings zwei interessante »Dreckeffekte«. Zum einen unterdrückt der Befehl die Ausgabe des READY, zum anderen aber bewirkt er, daß bei LIST ein Listing ohne Zeilennummern ausgedruckt wird, sowohl auf dem Bildschirm als auch mit dem Drucker.

Das billigste editierfähige Textverarbeitungssystem

Die Idee dazu habe ich von Mike Apsey’s Hinweis in »Commodore User« Juli 1984. Mit Zeilennummern versehen, läßt sich jeder beliebige Text schreiben, verbessern, verschieben, abspeichern, aber nicht RUNen!!

Der POKE-Befehl von oben (POKE 22,35) gefolgt von einem CMD und LIST, druckt dann alles brav als reinen Text aus. Die maximale Zeilenlänge entspricht der Zeilenlänge des jeweiligen Computers.

Probieren Sie es aus:

10 DER COMPUTER BIETET IN DER
20 DATENFERNÜBERTRAGUNG
30 UNGEAHNTE MÖGLICHKEITEN.
40 ABER DIE GEFAHR
50 USW. USW.
60:

Jede Zeile wird mit der RETURN-Taste abgeschlossen. Damit auch alles gedruckt wird, muß - zumindest bei meinem Drucker (1526) - eine »Leerzeile« folgen (Zeile 60). Mit

POKE 22,35:OPEN 1,4:CMD 1:LIST

wird der Text ohne Zeilennummern ausgedruckt. Sie können ihn vorher nach Belieben verändern.

Wie gesagt, nur nicht mit RUN starten, denn das bringt unweigerlich eine Fehlermeldung.

Zeiger auf Stringstack

Die Speicherzelle $16 zeigt auf den nächsten freien Speicherplatz im Stringstack.

Pointer to next expression in string stack

Values: $19; $1C; $1F; $22.

Default: $19.

Pointer at first free temp descriptor.

Initialized to point to TEMPST.

Pointer Temporary String   Pointer: Temporary String Stack.   Pointer : temporary strg stack  
$0017-$0018 LASTPT 23-24
Pointer to the Address of the Last String in the Temporary String Stack

This pointer indicates the last slot used in the temporary string descriptor stack. Therefore, the value stored at 23 ($17) should be 3 less than that stored at 22 ($16), while 24 ($18) will contain a 0.

Zeiger auf die Adresse der letzten Zeichenkette im »Temporary String Stack«

Der Inhalt dieser 2 Byte zeigt auf den zuletzt benutzten Speicherplatz Innerhalb der Adresse 22 bis 33. Das heißt, daß der Wert in 23 ($17) immer um 3 kleiner ist als der in 22 ($16), während der Wert in 24 ($18) eine Null ist.

Zeiger auf zuletzt verwendeten String

Der Inhalt dieser beiden Bytes zeigt auf den zuletzt verwendeten Speicherplatz.

Pointer to previous expression in string stack.   Pointer to last-used string temporary.   Last Temp String Address   Last temporary String Address.   Last temp string vector  
$0019-$0021 TEMPST 25-33
Descriptor Stack for Temporary Strings

The temporary string descriptor stack contains information about temporary strings which hve not yet been assigned to a string variable. An examples of such a temporary string is the literal string "HELLO" in the statement PRINT "HELLO".

Each three-byte descriptor in this stack contains the length of the string, and its starting and ending locations, expresses as displacements within the BASIC storage area.

Stapelspeicher für Angaben über vorläufige Zeichenketten

Das ist also der Speicherbereich, von dem in den beiden vorigen Abschnitten dauernd die Rede war. Ich gebe zu, »Descriptor Stack for Temporary Strings« drückt die Sache präziser aus als der deutsche Text.

Die Bedeutung eines »vorläufigen« Strings habe ich oben in der Beschreibung der Speicherzelle 22 erklärt.

Was ein Stapelspeicher (Stack) ist, entnehmen Sie bitte dem Texteinschub 6. Jeder der 3 Byte langen Angaben im Stack von 22 bis 33 enthält die Länge sowie die Anfangs- und Endadressen eines vorläufigen Strings, ausgedruckt als Verschiebung im Basic-Speicherbereich.

Stringstack

Die Angaben im Stringstack enthalten die Stringlänge sowie die Anfangs- und Endadressen des vorherigen Strings.

String stack, temporary area for processing string expressions (9 bytes, 3 entries).   Storage for NUMTMP temp descriptors.   Stack for Temporary Strings   Stack for temporary Strings.   Stack for temporary strings  
$0022-$0025 INDEX 34-37
Miscellaneous Temporary Pointers and Save Area

This area is used by many BASIC routines to hold temporary pointers and calculation results.

Verschiedene Zwischenspeicher

Diese vier Speicherzellen werden vom Basic-Übersetzer (Interpreter) für verschiedene Zwischenergebnisse und Flaggen benutzt, die aber dem Programmierer nichts nutzen.

Zeiger für diverse Zwecke

Diese Speicherzellen benutzt der Interpreter, um verschiedene Zwischenergebnisse zu speichern.

Temporary area for various operations (4 bytes).   Indexes.   Utility Pointer Area   Utility Pointer Area.   Utility pointer area  
$0022-$0023 INDEX1 34-35                     First Utility Pointer.   First Utility Pointer.      
$0024-$0025 INDEX2 36-37                     Second Utility Pointer.   Secong Utility Pointer.      
$0026-$002A RES 38-42
Floating Point Multiplication Work Area

This location is used by BASIC multiplication and division routines. It is also used by the routines which compute the size of the area required to store an array which is being created.

Arbeitsspeicher für arithmetische Operationen

Diese Speicherzellen werden von den Basic-Routinen bei der Multiplikation und Division als »Notizblatt« verwendet. Auch die Routinen, welche die erforderliche Speichergröße beim Definieren eines Zahlenfeldes (Array) ausrechnen, benutzen diesen Bereich.

Register für Funktionsauswertung und Arithmetik

Diese Speicherzellen werden vom BASIC-Interpreter auch zum Speichern von Zwischenergebnissen bei der Multiplikation und Division benutzt.

Auxiliary arithmetical register for division and multiplication (4 bytes).       Floating-Point Product of Multiply   Floating point product of Multiply and Divide.   Product area for multiplication  
$0026 RESHO 38                 Result of multiplier and divider.              
$0027 RESMOH 39                 One more byte.              
$0028 RESMO 40                                
ADDEND                 Temporary used by "UMULT".              
$0029 RESLO 41                                
$002B-$002C TXTTAB 43-44
Pointer to the Start of BASIC Program Text

This two-byte pointer lets BASIC know where program text is stored. Ordinarily, such text is located beginning at 2049 ($0801). Using this pointer, it is possible to change the program text area. Typical reasons for doing this include:

  1. Conforming the memory configuration to that of other Commodore computers. On 32K PET and CBM computers, for example, screen memory starts at 32768 ($8000), and BASIC text begins at 1025 ($0401). You can emulate this configuration with the 64 with the following short program:
    10 POKE 55,0:POKE 56,128: CLR: REM LOWER TOP OF MEMORY TO 32768
    20 POKE 56576,PEEK(56576) AND 253: REM ENABLE BANK 2
    30 POKE 53272,4: REM TEXT DISPLAY MEMORY NOW STARTS AT 32768
    40 POKE 648,128:REM OPERATING SYSTEM PRINTS TO SCREEN AT 32768 (128*256)
    50 POKE 44,4:POKE 1024,0: REM MOVE START OF BASIC TO 1025 (4*256+1)
    60 POKE 792,193: REM DISABLE RESTORE KEY
    70 PRINT CHR$(147);"NOW CONFIGURED LIKE PET":NEW
    80 REM ALSO SEE ENTRIES FOR LOCATION 55, 56576, AND 648
    

Such reconfiguring can be helpful in transferring programs from the 64 to the PET, or vice versa. Since the 64 automatically relocates BASIC program text, it can load and list PET programs even though the program file indicates a loading addresss that is different from the 64 start of BASIC. The PET does not have this automatic relocation feature, however, and it loads all BASIC programs at the two-byte address indicated at the beginning of the disk or tape file.

So if the PET loads a 64 program at its normal starting address of 2049 ($0801), it will not recognize its presence because it expects a BASIC program to start at 1025 ($0401). Therefore, if you want to let a PET and 64 share a program, you must either reconfigure the 64 to start BASIC where the PET does, or reconfigure the PET to start BASIC where the 64 does (with a POKE 41,8:POKE 2048,0).

  1. Raising the lowest location used for BASIC text in order to create a safe area in low memory. For example, if you wish to use the high-resolution graphics mode, you may want to put the start of screen memory at 8192 ($2000). The high-resolution moe requires 8K of memory, and you cannot use the lowest 8K for this purpose because it is already being used for the zero-page assignments.

Since BASIC program text normally starts at 2048 ($0801), this means that you only have 6k for program text before your program runs over into screen memory. One way around this is by moving the start of basic to 16385 ($4001) by typing in direct entry mode:

POKE 44,64: POKE 64*256,0:NEW

Other uses might include setting aside a storage area for sprite shape data, or user-defined character sets.

  1. Keeping two or more programs in memory simultaneously. By changing this pointer, you can keep more than one BASIC program in memory at one time, and switch back and forth betwenn them. Examples of this application can be found in COMPUTE!'s First Book of PET/CBM, pages 66 and 163.

This technique has a number of offshoots that are perhaps of more practical use.

a) You can store two programs in memory simultaneously for the purpose of appending one to the other. This technique requires that the line numbers of the two programs do not overlap. (See Programming the PET/CBM by Raeto Collin West, pages 41-42, for a discussion of this technique).

b) You can have two programs in memory at once and use the concept in (2) above to allow an easier way to create a safe area in low memory. The first program is just onw line that sets the start of BASIC pointer to the address of the second program which is located higher in memory, and then runs that second program.

  1. Since this address is used as the address of the first byte to SAVE, you can save any section of memory by changing this pointer to indicate the starting address, and the pointer 45-46 ($2D-$2D) to indicate the address of the byte after the last byte that you wish to save.
Zeiger auf den Anfang der Basic-Programme im Speicher

Dieser Zeiger, in der Low-/High-Byte-Darstellung, gibt dem Basic-Übersetzer an, ab welcher Speicherzelle das Basic-Programm beginnt. Normalerweise ist diese Adresse fest vorgegeben. Beim C 64 zum Beispiel zeigt der Zeiger auf 2049 ($0801). Beim VC 20 ist die Lage schon schwieriger, denn der Speicherbeginn hängt davon ab, welche Speichererweiterung eingesetzt ist. Die folgende Tabelle 3 gibt darüber Auskunft.

Tabelle 3: Beginn des Programmspeichers

C 64 2049 ($0801)
VC 20 (GV) 4097 ($1001)
VC 20 (+3 K) 1025 ($0401)
VC 20 (+ 8 K) 4609 ($1201)

Mit dem Befehl

PRINT PEEK (43) + PEEK (44)*256

läßt sich der jeweilige Beginn des Programmspeichers leicht feststellen. Mit einem POKE-Befehl kann der Programmierer diese Anfangsadresse verändern. Wozu das gut ist, fragen Sie?

Anwendung #1:

Nun, wenn Sie zum Beispiel ein Maschinenprogramm mit einem Basic-Programm gemeinsam betreiben wollen, brauchen Sie einen Speicherbereich für das Maschinenprogramm, der vom Basic-Programm nicht belegt wird. Wir sprechen vom »Schützen des Maschinenprogramms vor dem Überschreiben durch das Basic«. Der Speicherbereich eines Maschinenprogramms ist immer bekannt. Nach seinem letzten Speicherplatz kann das Basic-Programm beginnen.

Die Verschiebung der Anfangsadresse erfolgt in vier Schritten:

  1. Schritt: In den Speicherplatz vor dem neuen Basic-Bereich muß eine Null gePOKEt werden. Die Null dient zum Abgrenzen.
  2. Schritt: Die Adresse der ersten Speicherzelle wird in die Low-/High-Byte- Darstellung umgerechnet. Ich verweise dazu auf die Erklärung dieses Vorgangs im Texteinschub Nr. 1.
  3. Schritt: Das Low-Byte wird in die Speicherzelle 43, das High-Byte in die Zelle 44 gePOKEt.
  4. Schritt: Die Operation muß unbedingt mit dem Befehl NEW abgeschlossen werden, um sicherzustellen, daß auch alle anderen Zeiger auf ihren Anfangszustand gesetzt werden.

Im folgenden kleinen Programm wird angenommen, daß der Speicher bis zur Adresse 6000 ($1388) durch ein Maschinenprogramm belegt ist. Das Basic-Programm kann daher ab 5002 ($138A) anfangen, denn in 5001 muß ja eine Null stehen. Die Adresse 5002 teilt sich auf in ein High-Byte von INT (5002/256) = 19 und ein Low-Byte von 5002-(19*256) = 138.

10 POKE 5001,0
20 POKE 43,138
30 POKE 44,19
40 NEW

Der Effekt einer solchen »Verbiegung« des Zeigers in 43 und 44 wird im Texteinschub Nr. 7 »Der sichtbare Basic-Speicher« demonstriert.

Neben der oben erwähnten Anwendung der Zeigerverbiegung gibt es noch andere Möglichkeiten:

Anwendung #2:

Christoph Sauer hat in seinem Kurs »Der gläserne VC 20« in Ausgabe 10/84 auf Seite 158 gezeigt, wie man mehrere Programme gleichzeitig im Speicher unterbringen und zwischen ihnen umschalten kann.

Anwendung #3:

Man kann zwei oder mehrere unabhängige Programme genau hintereinander in den Speicher bringen, um sie aneinander zu hängen, was dem im Commodore-Basic fehlenden Befehl MERGE entspricht. Dabei dürfen die Zeilennummern sich allerdings nicht überschneiden.

Anwendung #4:

Durch Hinaufschieben des Basic-Bereichs kann Platz geschaffen werden für selbstdefinierte Zeichen oder hochauflösende Grafik.

Die Speicherzellen-Paare von 45, 46 bis 55, 56 ($37 bis $38) zeigen auf weitere für Basic-Programme wichtige Speicherbereiche, die deswegen gemeinsam betrachtet werden sollten. Bild 5 stellt den Zusammenhang grafisch dar. In diesem Bereich werden alle Variablen eines Programms gespeichert. Zur Erinnerung:

Wir unterscheiden zwischen »normalen« Variablen (numerische und String- Variable) und Feld-Variablen (Arrays). Dabei ist wichtig zu wissen, daß ein Basic-Programm während des Eintippens oder Einladens von Disk beziehungsweise Kassette in den 1. Block kommt. Während des Programmlaufs werden alle normalen Variablen in den 2. Block geschrieben, alle Felder (Arrays) in den 3. Block und schließlich der Text der Zeichenketten (Strings) sozusagen rückwärts vom Ende des Arbeitsspeichers in den 4 . Block. Je nach Größe des Programms und nach Anzahl der Variablen wandern die Blockgrenzen nach oben beziehungsweise die von Block 4 nach unten. Wenn sie sich treffen beziehungsweise überschneiden, gibt es »OUT OF MEMORY«.

Diese Blockbewegung ist in Bild 5 durch die Pfeile dargestellt.

Zeiger auf BASIC-Programm Anfang

Der Anfangsbereich des BASIC ist in Low- und Highbyte angegeben. Man kann durch die beiden Bytes den BASIC-Start abfragen oder verändern.

Pointer to beginning of BASIC area.

Default: $0801, 2049.

Pointer to beginning of text.

Doesn't change after being setup by "INIT".

Pointer: Start of BASIC Text   Pointer: Start of BASIC Text Area ($0801).   Pointer : Start-of-Basic  
$002D-$002E VARTAB 45-46
Pointer to the Start of the BASIC Variable Storage Area

This location points to the address which marks the end of the BASIC program text area, and the beginning of the variable storage area. All nonarray variables are stored here, as are string descriptors (for the address of the area where the actual text of strings is stored, see location 51 ($33)).

Seven bytes of memory are allocated for each variable. The first two bytes are used for the variable name, which consists of the ASCII value of the first two letters of the variable name. If the variable name is a single letter, the second byte will contain a zero.

The seventh bit of one or both of these bytes can be set (which would add 128 to the ASCII value of the letter). This indicates the variable type. If neither byte has the seventh bit set, the variable is the regular floating point type. If only the first byte has its seventh bit set, the variable is a string. If only the second byte has its seventh bit set, the variable is a defined function (FN). If both bytes have the seventh bit set, the variable is an integer.

The use of the other five bytes depends on the type of variable. A floating point variable will use the five bytes to store the value of the variable in floating point format. An integer will have its value stored in the third and fourth bytes, high byte first, and the other three will be unused.

A string variable will use the third byte for its length, and the fourth and fifth bytes for a pointer to the address of the string text, leaving the last two bytes unused. Note that the acrual string text that is pointed to is located either in the part of the BASIC program where the string is first assigned a value, or in the string text storage area pointed to by location 51 ($33).

A function definition will use the third and fourth bytes for a pointer to the address in the BASIC program text where the function definition starts. It uses the fifth and sixth bytes for a pointer to the dependent variable (the X of FN A(X)). The final byte is not used.

Knowing something about how variables are created can help your BASIC programming. For example, you can see that nonarray integer variables take up no less space than floating point variables, and since most BASIC commands convert the integers to floating point, they do not offer a speed advantage either, and in many cases will actually slow the program down. As will be seen below, however, integer arrays can save a considerable amount of space.

Variables are stored in the order in which they are created. Likewise, when BASIC goes looking for a variable, it starts its search at the beginning of this area. If commonly used variables are defined at the end of the program, and are thus at the back of this area, it will take longer to find them. It may help program execution speed to define the variables that will be used most frequently right at the beginning of the program.

Also, remember that once created, variables do not go away during program execution. Even if they are never used again, they still take up space in the variable storage area, and they slow down the routine that is used to search for variables that are referenced.

Another point to consider about the order in which to define variables is that arrays are created in a separate area of memory which starts at the end of the nonarray variable area. Therefore, every time a nonarray variable is created, all of the arrays must be moved seven bytes higher in memory in order to make room for the new variable. Therefore, it may help performance to avoid defining nonarray variables after defining arrays.

This pointer will be reset to one byte past the end of the BASIC program text whenever you execute the statements CLR, NEW, RUN, or LOAD. Adding or modifying a BASIC statement will have the same effect, because the higher numbered BASIC statements have to be moved up into memory to make room for the new statements, and can therefore overwrite the variable storage area. This means that if you wish to check the value of a variable after stopping a program, you can only do so before modifying the program.

The exception to the above is when the LOAD command is issued from a program. The purpose of not resetting this pointer in such a case is to allow the chaining of programs by having one program load and then run the next (that is also why a LOAD issued from a program causes a RUN from the beginning of the program). This allows the second program to share variables with the first. There are problems with this, however. Some string variable descriptors and function definitions have their pointers set to areas within the program text. When this text is replaced by a load, these pointers are no longer valid, which will lead to errors if the FN or string value is referenced. And if the second program text area is larger than that of the first, the second program will overwrite some of the first program's variables, and their values will be lost.

The ability to chain short programs is a holdover from the days of the 8K PET, for which this BASIC was written, but with the vastly increased memory of the 64, program chaining should not be necessary.

You should also note that SAVE uses this pointer as the address of the byte after the last byte to SAVE.

Zeiger auf die Anfangsadresse des Speicherbereichs für Variable

Dieser Zeiger, in der Low/High-Byte-Darstellung, gibt dem Basic-Interpreter an, ab welcher Speicherzelle die Variablen eines Basic-Programms gespeichert sind. Da die Variablen direkt an das Basic-Programm anschließen, zeigt dieser Zeiger natürlich gleichzeitig auf das Ende des Basic-Programms.

Es muß betont werden, daß es sich nur um den Bereich der »normalen« Variablen handelt, also nicht um Felder (Arrays). Anders als der Zeiger in 43 und 44, der auf fest definierte Speicherzellen zeigt, liegt derZeiger für den Variablen- Beginn nicht fest. Je nach Länge des Programms wandert er nach oben.

Sobald ein Programm eingetippt oder aus einem externen Speicher (Diskette, Kassette) eingelesen ist, wird der Zeiger in 45 und 46 durch RUN auf ein Byte hinter das Programmende gesetzt und alle Variablen werden in der Reihenfolge ihres Auftretens gespeichert. Da normalerweise die Länge eines Basic-Programms während des Ablaufs konstant bleibt, werden die Variablen in ihrer Position auch nicht gestört.

Das bedeutet, daß sie sowohl vom Programm als auch vom Programmierer nach einer Unterbrechung abgefragt werden können. Nur wenn das Programm modifiziert wird, wandert der Zeiger zusammen mit den Variablen entsprechend weiter.

Denselben Effekt wie das oben erwähnte RUN haben übrigens auch die Befehle NEW, CLR und LOAD. Eine Ausnahme bildet das LOAD innerhalb eines Programms, welches den Zeiger nicht zurücksetzt. Dadurch wird ein Aneinanderhängen von mehreren Programmen samt Variablen-Weiterverwendung unter bestimmten Voraussetzungen ermöglicht.

Die Bearbeitung der Variablen durch das Basic-Programm und die daraus resultierenden Kochrezepte für den Programmierer sind im Texteinschub Nr. 8 »Normale Variable in BASIC« separat erläutert.

Die verschiedenen Typen der Variablen und ihre Darstellung im Speicher finden Sie im 64’er, Ausgabe 10/84, Seite 157 und noch ausführlicher in Ausgabe 11/84, Seite 124, dargestellt und erklärt.

Für diejenigen Leser, welche kein Monitor- beziehungsweise Disassembler- Programm haben oder benutzen können, ist im Texteinschub Nr. 9 »Darstellung der normalen Variablen im Speicher« eine kleine Anleitung gegeben, wie sie die Variablendarstellung mittels Basic anschauen können.

Zeiger auf BASIC-Programmende

Dieser Zeiger teilt dem Interpreter das BASIC-Ende mit, damit die Variablen hinter dem Programm abgelegt werden können.

Pointer to beginning of variable area.

(End of program plus 1.)

Pointer to start of simple variable space.

Updated whenever the size of the program changes, set to [TXTTAB] by "SCRATCH" ("NEW").

Pointer: Start of BASIC Variables   Pointer: Start of BASIC Variables.   Pointer : Start-of-Variables  
$002F-$0030 ARYTAB 47-48
Pointer to the Start of the BASIC Array Storage Area

This location points to the address of the end of nonarray variable storage, and the beginning of array variable storage. The format for array storage is as follows:

The first two bytes hold the array name. The format and high-bit patterns are the same as for nonarray variables (see 45 ($2D) above), except that there is no equivalent to the function definition.

Next comes a two-byte offset to the start of the next array, low byte first. Then there is a one-byte value for the number of array dimensions (e.g., 2 for a two-dimensional array like A(x,y)). That byte is followed by pairs of bytes which hold the value of each array dimension+1 (DIMensioning an array always makes space for 0, so A(0) can be used).

Finally come the values of the variables themselves. The format for these values is the same as with nonarray values, but each value only takes up the space required; that is, floating point variables use five bytes each, integers two bytes, and string descriptors three bytes each.

Remember that as with nonarray string, the actual string text is stored elsewhere, in the area which starts at the location pointed to in 51-52 ($33-$34).

Zeiger auf die Anfangsadresse des Speicherbereichs für Felder (Arrays)

Dieser Zeiger, in der Low-/High-Byte-Darstellung, gibt dem Basic-Übersetzer (Interpreter) an, ab welcher Speicherzelle die Felder (Arrays) eines Basic- Programms gespeichert sind. Was Felder sind und wozu sie gebraucht werden, ist im Texteinschub Nr. 10 kurz erläutert. Da die Felder direkt nach den normalen Variablen gespeichert werden, zeigt dieser Zeiger natürlich gleichzeitig auf das Ende des Speichers für normale Variablen.

Durch POKEn einer Adresse in die Speicherzellen 47 und 48 kann der Speicherbereich am Anfang eines Programms beinahe beliebig verschoben werden. Beinahe deswegen, weil die Verschiebung im Zusammenhang mit den anderen Bereichen (siehe Bild 5) einen Sinn haben muß. Im übrigen gilt für diesen Zeiger dasselbe, was schon für den Zeiger in 45 und 46 gesagt worden ist. Die Darstellung der Feld-Variablen selbst kann mit der Methode angesehen werden, die im Texteinschub Nr. 11 erklärt ist.

Wie aus den Erklärungen hervorgeht, wird bei Feldern mit Zeichenketten (Strings) in dem von Zeiger 47 und 48 bezeichneten Speicherbereich nur die Definition beziehungsweise die Dimensionierung gespeichert. Die eigentlichen Zeichenketten stehen wie bei den normalen Variablen im vierten Block, vorn Speicherende rückwärts angeordnet.

Zeiger auf Start der Arrays

Das LOW- und HIGH-Byte der Adressen geben dem BASIC-Interpreter die Information, ab welcher Speicherzelle die Arrays eines BASIC-Programms gespeichert sind.

Pointer to beginning of array variable area.  
Pointer to beginning of array table.

Incremented by 6 whenever a new simple variable is found, and set to [VARTAB] by "CLEARC".

Pointer: Start of BASIC Arrays   Pointer: Start of BASIC Arrays.   Pointer : Start-of-Arrays  
$0031-$0032 STREND 49-50
Pointer to End of the BASIC Array Storage Area (+1), and the Start of Free RAM

This location points to the address of the end of BASIC array storage space and the start of free RAM. Since string text starts at the top of memory and builds downwards, this location can also be thought of as the last possible address of the string storage area. Defining new variables pushes this pointer upward, toward the last string text.

If a string for which space is being allocated would cross over this boundary into the array storage area, garbage collection is performed, and if there still is not enough room, an OUT OF MEMORY error occurs. FRE performs garbage collection, and returns the difference between the addresses pointed to here and the address of the end of string text storage pointed to by location 51 ($33).

Zeiger auf die Endadresse (+1) des Speicherbereichs für Felder (Arrays)

Der Inhalt dieser Speicherzellen zeigt auf die Adresse, wo der Speicherbereich für Felder auf· hört. Wie aus Bild 5 hervorgeht, werden die Zeichenketten vorn Ende des verfügbaren RAM· Speichers rückwärts gespeichert. Man kann also auch sagen, daß der Zeiger in 49 und 50 die letzte mögliche Adresse für Zeichenketten angibt. Wenn in einem Programm neue Variablen definiert werden, rutscht diese Adresse weiter nach oben und nähert sich dem Ende der Zeichenketten, die durch den Zeiger in 51 und 52 angegeben wird.

Wenn sich die Speicherbereiche der Felder und Zeichenketten berühren, bleibt der Computer stehen und führt die »Garbage Collection« (Müllabfuhr) durch - ein Prozeß, in dem nicht mehr gebrauchte Zeichenketten entfernt und der Zeichenketten-Speicher reduziert wird. Ist danach immer noch kein Platz, wird OUT OF MEMORY gegeben.

Der Befehl FRE löst immer eine solche Garbage Collection aus und gibt dann die Differenz zwischen den Adressen in den Zeigern 49 und 50 und 51 und 52 als verbleibenden, noch verfügbaren, Speicherbereich aus.

Zeiger auf Ende der Datenfelder

Diese beiden Speicherzellen zeigen auf das Ende der Arrays. Zu beachten ist, daß die Zeichenketten rückwärts gespeichert werden.

Pointer to end of array variable area.  
End of storage in use.

Increased whenever a new array or simple variable is encountered. set to [VARTAB] by "CLEARC".

Pointer End of BASIC Arrays (+1)   Pointer: End of BASIC Arrays + 1.   Pointer : End-of-Arrays  
$0033-$0034 FRETOP 51-52
Pointer to the Bottom of the String Text Storage Area

This pointer marks the current end of the string text area, and the top of free RAM (strings are built from the top of memory downward). Additional string texts are added, to the area below the address pointed to here. After they are added, this pointer is lowered to point below the newly added string text. The garbage collection routine (which is also called by FRE) readjusts this pointer upward.

While the power-on/reset routines set this pointer to the top of RAM, the CLR command sets this pointer to the end of BASIC memory, as indicated in location 55 ($37). This allows the user to set aside an area of BASIC memory that will not be disturbed by the program, as detailed at location 55 ($37).

Zeiger auf die untere Grenze des Speicherbereichs für den Text der Zeichenketten-Variablen

Der Inhalt dieser Speicherzellen zeigt in Low-/High-Byte-Darstellung auf das jeweilige untere Ende (siehe Bild 5) des Textspeichers von Zeichenketten. Er bezeichnet aber zugleich auch das obere Ende des frei verfügbaren RAM-Bereichs. Das entsteht dadurch, daß der Text der Zeichenketten vom Ende des RAM-Bereichs nach unten gespeichert wird. In Bild 5 ist das durch den Pfeil dargestellt.

Beim Einschalten des Computers und nach einem RESET wird dieser Zeiger auf das oberste Ende des RAM-Bereichs gesetzt. Beim C 64 ist das 40960 ($A000). Beim VC 20 hängt es von den eingesetzten Speichererweiterungen ab, ohne Erweiterung ist die Adresse 7680 ($1E00).

Der Befehl CLR setzt den Zeiger auf die Adresse, welche durch den Zeiger in den Speicherzellen 55 und 56 als das Ende des Basic-Speichers angegeben wird. Wozu das dient, erkläre ich Ihnen bei der Beschreibung dieses Zeigers weiter unten.

Zeiger auf Stringgrenze

Der Inhalt dieser Speicherzellen zeigt auf das Ende des Textspeichers, der aber noch zugleich das obere Ende des frei verfügbaren RAM-Bereichs anzeigt.

Pointer to beginning of string variable area.

(Grows downwards from end of BASIC area.)

Top of string free space.   Pointer: Bottom of String Storage   Pointer: Bottom of String space.   Pointer : String-storage(moving down)  
$0035-$0036 FRESPC 53-54
Temporary Pointer for Strings

This is used as a temporary pointer to the most current string added by the routines which build strings or move them in memory.

Zeiger auf die Adresse der zuletzt eingegebenen Zeichenkette

In diesen Speicherplätzen steht die Adresse (im vierten Block, siehe Bild 5) der Zeichenkette, die als letzte von Routinen (Programme, Direkteingabe) zur String-Manipulation abgespeichert worden ist. Mit dem folgenden kleinen Programm können Sie das genau sehen:

10 PRINT PEEK(53)+256*PEEK(54),
20 PRINT PEEK(51)+256*PEEK(52)
30 INPUT A$
40 GOTO 10

Zeile 10 druckt uns zuerst (links) den Zeiger auf die zuletzt eingegebene Zeichenkette aus, Zeile 20 rechts daneben den Zeiger auf die untere Speichergrenze der Zeichenketten. Zeile 30 fordert zur Eingabe einer Zeichenkette auf.

Wenn Sie bei frisch eingeschaltetem Computer das Programm starten, sehen Sie eine 0 (=vorher noch kein String eingeben) und daneben die Adresse dezimal 40960 (C 64) beziehungsweise dezimal 7680 (VC 20 ohne Erweiterung). Wenn Sie auf das Fragezeichen des INPUT hin zum Beispiel ein A eintippen, erhalten Sie links den vorigen Wert von rechts und rechts jetzt eine um 1 kleinere Zahl. Eine weitere Eingabe von zum Beispiel XXXXX schiebt die alte rechte Zahl nach links und die neue wird um die Anzahl der Zeichen, also 5, verringert.

Hilfszeiger für Strings

In diesen Zellen wird die Adresse der Zeichenkette verzeichnet, die als letzte von Routinen zur Stringmanipulation abgespeichert worden ist.

Pointer to memory allocated for current string variable.   Pointer to new string.   Utility String Pointer   Utility String Pointer.   Utility string pointer  
$0037-$0038 MEMSIZ 55-56
Pointer to the Highest Address Used by BASIC

The power-on/reset routine tests each byte of RAM until it comes to the BASIC ROM, and sets this pointer to the adress of the highest byte of consecutive RAM found (40959, $9FFF).

There are two circumstances under which this pointer may be changed after power-up to reflect an address lower than the actual top of consecutive RAM:

  1. Users may wish to lower this pointer themselves, in order to set aside an area of free RAM that will not be disturbed by BASIC. For example, to set aside a 1K area at the top of BASIC, start your program with the line:
    POKE 56,PEEK(56)-4:CLR
    

The CLR is necessary to insure that the string text will start below your safe area.

You may wish to store machine language programs, sprites, or alternate character sets in such an area. For the latter two applications, however, keep in mind the 16K addressing range limitation of the VIC-II chip. If you do not assign the VIC-II to a bank other than the default memory bank of 0-16383 ($0-$3FFF), you must lower the top of memory below 16383 ($3FFF) if you wish your sprite or character data area to be within its addressing range.

  1. Then the RS-232 device (number 2) is opened, this pointer and the pointer to the end of user RAM at 643 are lowered by 512 bytes in order to create two 256-byte buffers, one for input and the other for output.

Since the contents of these buffers will overwrite any variables at the top of memory, a CLR command is issued at the time device 2 is opened. Therefore, the RS-232 device should be opened before defining any variables, and before setting aside a safe area for machine language programs or other uses, as described above.

Zeiger auf das Ende des für Basic-Programme verfügbaren Speichers

Dieser Zeiger, in der Low-/High-Byte-Darstellung, gibt dem Basic-Übersetzer an, welches die höchste von Basic verwendbare Speicheradresse ist. Wie aus Bild 5 ersichtlich, ist diese Adresse zugleich der Anfang der als Variable abgespeicherten Zeichenkette (Strings).

Normalerweise ist diese Adresse fest vorgegeben. Die folgende Tabelle 4 gibt darüber Auskunft:

Tabelle 4: Ende des Programmspeichers

Adresse Zeiger in 55 56
C 64 40960 0160
VC 20 (Grundv.) 7680 030
VC 20 (+3 KByte) 7680 030
VC 20 (+8 KByte) 16384 064
VC 20 (+16 KByte) 24576 096
VC 20 (+24 KByte) 32768 0128

Beim Einschalten des Computers überprüft das Betriebssystem den gesamten RAM- Speicher, bis es zur ersten ROM-Speicherzelle kommt, setzt den Zeiger in 55 und 56 auf diese Adresse und druckt den bekannten Kopf mit der verfügbaren Speicherangabe auf den Bildschirm.

Normalerweise wird dieser Zeiger nicht geändert.

Es gibt aber zwei Gelegenheiten, bei denen eine Änderung dieses Zeigers sinnvoll beziehungsweise notwendig ist.

Anwendung 1:

Es kommt oft vor, daß der gesamte Speicher nicht ausschließlich für Basic benötigt wird, sondern daß ein freier Speicherbereich geschaffen wird, um zum Beispiel Maschinenprogramme, selbst definierte Zeichen oder hochaufgelöste Grafik unterzubringen, die aber nicht vom Basic-Programm überschrieben werden können.

Bei der Besprechung der Zeiger in 43 und 44 haben wir das auch schon gemacht, allerdings durch »Hochschieben« des Speicheranfangs. Mit dem Zeiger in 55 und 56 erreichen wir denselben Effekt, diesmal durch »Herunterdrücken« des Speicherendes. Gegenüber den vier Schritten beim Hochschieben ist das Herunterdrücken einfacher. Mit dem Befehl:

POKE 56,PEEK(56)-1:CLR

schieben wir das Speicherende um 256 Byte nach unten, egal für welchen Computer und welche Speichererweiterung. Mit -2 verschiebt sich das Ende um 512, mit-4 um 1024 Byte (also 1 KByte) nach unten. Wenn Sie eine feinere Verschiebung als Vielfache von 256 benötigen, kommen Sie mit dem High-Byte in 56 allein nicht aus, sondern Sie müssen auch einen entsprechenden Wert in 55 hineinPOKEn.

Der Befehl CLR ist notwendig, denn er setzt den Zeiger der Zellen 51 und 52 (siehe dort), das heißt das untere Ende des Speicherbereichs für Zeichenketten auf dieselbe Adresse wie Zeiger 55 und 56. Dadurch wird erzwungen, daß die Zeichenkette sozusagen als Ausgangslage unterhalb des heruntergedrückten Speicherendes abgelegt wird.

Anwendung 2:

Über den User-Port (Steckerleiste an der Rückseite, neben dem Datasetten- Anschluß) können VC 20 und C 64 mit anderen Geräten verbunden werden. Der Datentransfer über diese Verbindung - sie heißt RS232-Schnittstelle - muß allerdings programmiert werden. Diese RS232-Schnittstelle hat die Gerätenummer 2 (so wie der Drucker Nummer 4 und das Diskettengerät die Nummer 8 hat).

Wenn nun ein Gerät Nummer 2 mit einem OPEN-Befehl angewählt wird, wird automatisch der Zeiger in 55 und 56 und der Zeiger in 643 um 512 Byte heruntergedrückt, um je einen Eingangs- und Ausgangspufferspeicher zu erzeugen. Da der Inhalt dieser Pufferspeicher alle Variable in diesen 512 Byte überschreiben würde, wird auch der CLR-Befehl automatisch gegeben.

Es gilt daher als Vorschrift, daß bei RS232-Verbindungen zuerst der Datenkanal durch OPEN eröffnet werden muß, bevor Variable, Felder und Zeichenketten definiert werden.

Zeiger auf BASIC-RAM-Ende

Dieser Zeiger gibt dem Interpreter an, welches die höchste von BASIC verwendbare Speicheradresse ist.

Pointer to end of BASIC area.

Default: $A000, 40960.

Highest location in memory.   Pointer: Highest Address Used by BASIC   Pointer: Highest Address available to BASIC ($A000).   Pointer : Limit-of-memory  
$0039-$003A CURLIN 57-58
Current BASIC Line Number

This location contains the line number of the BASIC statement which is currently being executed, in LSB/MSB format. A value of 255 ($FF) in location 58 ($3A), which translates to a line number of 65280 or above (well over the 63999 limit for a program line), means that BASIC is currently in immediate mode, rather than RUN mode.

BASIC keywords that are illegal in direct mode check 58 ($3A) to determine whether or not this is the current mode.

When in RUN mode, this location is updated as each new BASIC line is fetched for execution. Therefore, a TRACE function could be added by diverting the vector at 776 ($0308), which points to the routine that executes the next token, to a user-written routine which prints the line number indicated by this location before jumping to the token execution routine. (LISTing the line itself would be somewhat harder, because LIST uses many Page 0 locations that would have to be preserved and restored afterwards.)

This line number is used by BREAK and error messages to show where program execution stopped. The value here is copied to 59 ($3B) by STOP, END, and the stop-key BREAK, and copied back by CONT.

Nummer der laufenden Basic-Programmzeile

Diese Speicherzellen enthalten die Zeilennummer in Low-/High-Byte-Darstellung derjenigen Basic-Anweisung, welche gerade ausgeführt wird.

Ein kurzes Programm macht das deutlich:

10 PRINT "ZEILE 10", PEEK(57)+256*PEEK(58)
20 A=3:PRINT A,PEEK(57)+256*PEEK(58)
30 B=5:PRINT B,PEEK(57)+256*PEEK(58)
40 PRINT A*B,PEEK(57)+256*PEEK(58)

In jeder Zeile wird zuerst etwas gePRINTet, nämlich Text, Variable und ein Rechenresultat. Durch das Komma getrennt wird in der 2. Bildschirmhälfte (VC 20) beziehungsweise Bildschirmviertel (C 64) der Inhalt der Speicherzellen 57 und 58 ausgedruckt. Das Resultat zeigt in der Tat die jeweilige Zeilennummer an.

Die Basic-Befehle GOTO, GOSUB-RETURN, FOR-NEXT, END, STOP, CONT und die Betätigung der STOP-Taste während eines Programmlaufes verwenden alle den Inhalt dieser Speicherzellen, um entweder zu der laufenden Zeile zurückzufinden oder um die Unterbrechung mit BREAK IN... anzuzeigen. Auch die meisten Fehlermeldungen verwenden diese Zellen.

In vielen Basic-Erweiterungen und Programmierhilfen wird ein Befehl TRACE oder STEP angeboten, welcher ein schrittweises Abarbeiten eines Programms bei gleichzeitiger Anzeige der gerade aktiven Zeilennummer erlaubt. Dieses TRACE verwendet natürlich auch den Inhalt der Zellen 57 und 58.

Schließlich sei noch erwähnt, daß im direkten Modus, also bei direkt eingetippten Aktionen des Computers ohne Programmzeilen, in der Zelle 58 immer die Zahl 255 steht. Diejenigen Basic-Befehle, welche im direkten Modus nicht erlaubt sind (INPUT, GET, DEF), prüfen in Zelle 58, ob sie im direkten Modus oder während eines Programmlaufes aufgetreten sind.

augenblickliche BASIC-Zeilennummer

In diesen Speicherzellen wird die Zeilennummer verzeichnet, welche gerade ausgeführt wird.

Current BASIC line number

Values:

  • $00-$F9FF, 0-63999: Line number.
  • $FF00-$FFFF: Direct mode, no BASIC program is being executed.
Current line #.

Set to 0,255 for direct statements.

Current BASIC Line Number   Current BASIC Line number.   Current Basic line number  
$003B-$003C OLDLIN 59-60
Previous BASIC Line Number

When program execution ends, the last line number executed is stored here, and restored to location 57 ($39) by CONT.

Zeilennummer der letzten Programmunterbrechung

Immer dann, wenn ein Programmablauf durch die Befehle END oder STOP oder aber mit der STOP-Taste abgebrochen wird, wird die Nummer der gerade ausgeführten Programmzeile nach 59 und 60 gebracht und bleibt dort solange, bis eine neue Unterbrechung erfolgt.

Das läßt sich am besten mit der STOP-Taste und nachfolgendem CONT zeigen. Nehmen Sie bitte dazu das kleine Demo-Programm der Zellen 57 und 58 und ändern Sie alle PEEK-Adressen in 59 und 60 um. Fügen Sie außerdem noch eine Zeile 50 hinzu:

50 GOTO 10

Den dadurch erzeugten kontinuierlichen Laufdes Programms bremsen Sie dann mit der STOP-Taste und lassen ihn danach mit CONT weiterlaufen.

Auf der rechten Seite erscheint jetzt die Zeilennummer, bei der das Programm vorher unterbrochen worden ist.

Zeilennummer für CONT

Falls eine Unterbrechung des Programmablaufs durch den Befehl STOP oder über die STOP-Taste erfolgt, wird in den Speicheradressen $3B-$3C die Zeilennummer gespeichert, die gerade abgearbeitet wurde.

Current BASIC line number for CONT.  
Old line number

Set up by ^C,"STOP" or "END" in a program.

Previous BASIC Line Number   Previous BASIC Line number.   Previous Basic line number  
$003D-$003E OLDTXT 61-62
Pointer to the Address of the Current BASIC Statement

This location contains the address (not the line number) of the text of the BASIC statement that is being executed. The value of TXTPTR (122, $7A), the pointer tot he address of the BASIC text character currently being scanned, is stored here each time a new BASIC line begins execution.

END, STOP, and the STOP-key BREAK save the value of TXTPTR here, and CONT restores this value to TXTPTR. CONT will not continue if 62 ($3E) has been changed to a zero by a LOAD, a modification to the program text, or by error routines.

Zeiger auf die Adresse, ab weicher der Text der laufenden Basic-Zeile gespeichert ist.

Die Abarbeitung der einzelnen Basic-Zeilen während eines Programmlaufs wird von einem kleinen Maschinencode-Programm, welches in den Speicherzellen 115 bis 138 steht (wir kommen noch dahin), gesteuert. In den Zellen 122 und 123 enthält es die Adresse des letzten Bytes des gerade ausgeführten Basic-Befehls.

Sobald eine neue Basic-Zeile verarbeitet wird, holt das Betriebssystem diese Adresse aus 122 und 123 und speichert sie in den hier zur Diskussion stehenden Speicherzellen 61 und 62 ab, wie üblich als Low-/High-Byte.

Dasselbe geschieht bei jedem Befehl END, STOP, bei Fehlern mit dem Befehl INPUT und durch das Drücken der STOP-Taste. Der Befehl CONT hingegen schaut in 61 und 62 nach und bringt die darin befindliche Adresse zurück in die Speicherzellen 122 und 123 zur Fortsetzung des Programms. Wenn aber in Zelle 62 inzwischen eine 0 steht - und das geschieht bei einem LOAD-Befehl, durch Programm-Abbruch mit Fehlermeldung und durch Eingabe neuer Basic-Zeilen beziehungsweise deren Veränderungen mit abschließender RETURN-Taste - dann wird der CONT-Befehl nicht ausgeführt.

Zur besseren Erklärung dieser in 61 und 62 als Zeiger stehenden Adresse einer Basic-Zeile möchte ich Sie an den Texteinschub Nr. 7 erinnern, in dem ich den Basic-Programmspeicher »sichtbar« gemacht habe, um die Wirkung der Verschiebung des Zeigers in den Zellen 43 und 44 zu demonstrieren.

Wir nehmen dazu bitte noch einmal das kleine Demo-Programm für die Adressen 57 und 58 oben her und ersetzen die PEEK-Werte durch 61 und 62. Das Ausdrucken des Inhalts von 61 und 62 legen wir aber an den Anfang jeder Zeile. Das Programm sieht dann so aus:

10 PRINT PEEK(61)+256*PEEK(62),"ZEILE 10"
20 PRINT PEEK(61)+256*PEEK(62),:A=3:PRINT A
30 PRINT PEEK(61)+256*PEEK(62),:B=5:PRINT B
40 PRINT PEEK(61)+256*PEEK(62),A*B

Nach RUN erhalten wir jetzt auf der linken Seite Zahlen, die den jeweiligen Basic-Speicher angeben, ab dem diese Zeile gespeichert ist. Wenn Sie ab diesen Adressen mit der gerade erwähnten Methode aus Texteinschub Nr. 7 nachschauen, finden Sie genau die Zeilen des kleinen Demo-Programms wieder.

Zur Anwendung dieses Zeigers kann ich wenig sagen. Ihn durch POKE zu verändern, geht in Basic nicht, weil das Betriebssystem die richtigen Werte immer neu eingibt. Man kann ihn allerdings abfragen, wenn man sich für die Speicheradressen der Basic-Zeilen interessiert. Die einzige Anwendung dafür kenne ich von S. Leemon, welche bei den Adressen 65 und 66 eingesetzt wird.

Zeiger auf nächstes Statement für CONT

Sobald eine neue BASIC-Zeile verarbeitet wird, holt sich das Betriebssystem die aktuelle Zeilennummer und speichert diese dann in $3D-$3E als LOW- und HIGH-Byte ab.

Pointer to next BASIC instruction for CONT

Values:

  • $00-$FF: CONT'ing is not possible.
  • $0100-$FFFF: Pointer to next BASIC instruction.
Old text pointer.

Points at statement to be exec'd next.

Pointer: BASIC Statement for CONT   Pointer: BASIC Statement for CONT.   Pointer : Basic statement for CONT  
$003F-$0040 DATLIN 63-64
Current DATA Line Number

This location holds the line number of the current DATA statement being READ. It should be noted that this information is not used to determine where the next DATA item is read from (that is the job of the pointer at 65-66 ($41-$42) below). But if an error concerning the DATA occurs, this number will be moved to 57 ($39), so that the error message will show that the error occurred in the line that contains the DATA statement, rather than in the line that contains the READ statement.

Zellennummer eines gerade laufenden DATA-Befehls

Diese Speicherzellen enthalten die Nummer der Basic-Zeile, in der gerade ein DATA-Befehl mit READ gelesen wird. Sobald in einer DATA-Zeile ein Fehler gefunden wird, kommt diese Zeilennummer aus 63 und 64 in die Speicherzellen 57 und 58, um in der Fehlermeldung die fehlerhafte DATA-Zeile und nicht die laufende READ-Zeile anzuzeigen. Auf diese Weise werden Syntax-Fehler in einer DATA-Zeile angezeigt. Um andere Fehler, wie zum Beispiel ein fehlendes Komma zwischen zwei DATA-Angaben anzuzeigen, können die Speicherzellen 63 und 64 eingesetzt werden.

In dem folgenden Programm wird in Zeile 20 geprüft, ob die DATA-Angaben größer als 255 sind. Da bei einem fehlenden Komma die beiden Zahlen als eine Zahl gelesen werden, wird dieser Fall erkannt und mit einem F versehen die Nummer der DATA-Zeile ausgedruckt, in der das Komma fehlt.

10 FOR X=1 TO 10:READ A:PRINTA
20 IF A>255 THEN PRINT "F" PEEK(63) + 256*PEEK(64)
30 NEXT X
40 DATA 10,20,30
50 DATA 40,50,60
60 DATA 70,80,90,100

Sie können jetzt in den DATA-Zeilen Kommafehler einbauen, die vom Programm angezeigt werden. Ein anderer häufiger Fehler, nämlich ein Komma am Ende einer DATA-Zeile, kann damit leider nicht erkannt werden. Aber vielleicht fällt Ihnen eine Prüfformel dazu ein.

augenblickliche Zeilennummer für DATA

Diese beiden Speicherzellen enthalten die Zeilennummer einer DATA-Zeile, die gerade vom READ-Befehl ausgelesen wird.

BASIC line number of current DATA item for READ.   Data line # -- remember for errors.   Current DATA Line Number   Current DATA Line number.   Current DATA line number  
$0041-$0042 DATPTR 65-66
Pointer to the Address of the Current DATA Item

This location points to the address (not the line number) within the BASIC program text area where DATA is currently being READ. RESTORE sets this pointer back to the address indicated by the start of BASIC pointer at location 43 ($2B).

The sample program below shows how the order in which DATA statements are READ can be changed using this pointer. The current address of the statement before the DATA statement is stored in a variable, and then used to change this pointer.

10 A1=PEEK(61):A2=PEEK(62)
20 DATA THIS DATA WILL BE USED SECOND
30 B1=PEEK(61):B2=PEEK(62)
40 DATA THIS DATA WILL BE USED FIRST
50 C1=PEEK(61):C2=PEEK(62)
60 DATA THIS DATA WILL BE USED THIRD
70 POKE 65,B1:POKE 66,B2:READ A$:PRINT A$
80 POKE 65,A1:POKE 66,A2:READ A$:PRINT A$
90 POKE 65,C1:POKE 66,C2:READ A$:PRINT A$
Zeiger auf die Adresse, ab der die laufende DATA-Angabe gespeichert ist

Diese Speicherzellen enthalten in der Low-/High-Byte-Darstellung die Adresse im Basic-Programmspeicher, ab welcher der READ-Befehl nach der nächsten DATA-Zeile sucht.

Zu Beginn eines Programms steht in 65 und 66 als Adresse der Beginn des Basic- Speichers, also derselbe Wert wie in den Speicherzellen 43 und 44. Der Befehl RESTORE setzt den Zeiger immer auf diesen Anfangswert zurück. Ein Demo-Programm zeigt uns das an (die Kommata sind wichtig für das Format der Darstellung auf dem Bildschirm!):

10 PRINT, PEEK(65)+256*PEEK(66)
20 FOR X=1 TO 10:READ A
30 PRINT A,PEEK(65)+256*PEEK(66)
40 NEXT X
50 DATA 10,20,30,40,50,60, 70,80,90,100
60 RESTORE
70 PRINT,PEEK(65)+256*PEEK(66)

Durch Verändern dieses Zeigers in 65 und 66 kann die Reihenfolge, mit der DATA- Angaben gelesen werden, verändert werden, allerdings nur zeilenweise.

Wir brauchen dazu die oben beschriebenen Speicherzellen 61 und 62, deren jeweiligen Inhalt wir ja mit PEEK abfragen können. Wenn wir das vor jeder DATA- Zeile machen und diesen Wert einer Variablen zuweisen, haben wir die Adresse gespeichert, hinter welcher die DATA-Zeile kommt. Durch POKEn dieser Adressen in die Speicherzellen 65 und 66 vor einem READ-Befehl, wird diesem READ die nächste DATA-Zeile vorgegeben und wir können so die Reihenfolge der DATA-Zeilen ändern.

10 A1=PEEK(61)+PEEK(62)*256
20 DATA DAS IST DIE 1. ZEILE
30 A2=PEEK(61)+PEEK(62)*256
40 DATA DAS IST DIE 2.ZEILE
50 A3=PEEK(61)+PEEK(62)*256
60 DATA DAS IST DIE 3.ZEILE
70 POKE 65,A3 AND 255:POKE 66,A3/256:READ A$:PRINT A$
80 POKE 65,A1 AND 255:POKE 66,A1/256:READ A$:PRINT A$
90 POKE 65,A2 AND 255:POKE 66,A2/256:READ A$:PRINT A$

Mit den Zeilen 70 bis 90 werden für jede DATA-Zeile eigene READ-Anweisungen gegeben. Welche DATA-Zeile gelesen werden soll, wird durch die Variablen Ax und Bx (x=1,2,3) bestimmt, mit denen der Zeiger in 65 und 66 »verbogen« wird. Auf ein Detail will ich hier hinweisen:

Die Adresse 61 und 62 darf nicht mit zwei Befehlen, sondern muß mit einem Befehl ausgelesen werden, da bei einem möglichen Page-Wechsel zwischen den zwei Befehlen der Zeiger nicht verbogen, sondern abgeknickt wird.

Was passiert in der ersten Zeile des Demo-Programms?

10 A1=PEEK(61):B1=PEEK(62)

Mit »A1=PEEK(61)« wird der Variablen A1 der Wert des Low-Bytes des Zeigers 61 und 62 zugewiesen. Dieser zeigt am Anfang einer Zeile auf das Null-Byte vor der Linkadresse (hier 2048), so daß A1 den Wert (2048 AND 255)=0 erhält. Mit »B1=PEEK(62)« wird der Variablen B1 der Wert des High-Bytes des Zeigers 61 und 62 zugewiesen. Dieser zeigt aber inzwischen auf das Trennzeichen (»:«) zwischen den beiden Befehlen (hier 2061), so daß B1 den Wert (INT(2061/256)) = 8 erhält. Als Zeiger auf das aktuelle DATA-Element erhalten wir die erwartete Adresse (A1 + B1 * 256) = 2048.

Was aber, wenn Zeilenanfang und Trennzeichen nicht in derselben Page liegen? Dazu setzen Sie bitte den Basic-Anfang um eine Stelle zurück:

POKE43,0:POKE 2047,0:NEW

Die Zeiger auf den Zeilenanfang und das Trennzeichen werden dadurch ja ebenfalls verändert, so daß A1 jetzt den Wert (2047 AND 255)=255 und B1 den Wert (INT(2060/256))=8 erhält. Als Zeiger auf das aktuelle DATA-Element erhalten wir nun die völlig unbrauchbare Adresse (A1+B1 * 256)=2303.

Zeiger für nächstes DATA-Element

Hier ist die Adresse aufgeführt, ab welcher der READ-Befehl nach der nächsten DATA-Zeile sucht.

Pointer to next DATA item for READ.  
Pointer to data.

Initialized to point at the zero in front of [TXTTAB] by "RESTORE" which is called by "CLEARC". updated by execution of a "READ".

Pointer: Current DATA Item Address   Pointer: Used by READ - current DATA Item Address.   Current DATA address  
$0043-$0044 INPPTR 67-68
Pointer in the Source of GET, READ, or INPUT Information

READ, INPUT and GET all use this as a pointer to the address of the source of incoming data, such as DATA statements, or the text input buffer at 512 ($0200).

Zeiger auf die Adresse, aus welcher die Befehle INPUT, GET und READ die Zeichen/Zahlen holen

INPUT und GET verlangen Angaben, die per Tastatur eingegeben werden. Tastatur- Eingaben im direkten Modus, also wenn kein Programm läuft, werden im Eingabe- Pufferspeicher des Editors (der Teil des Betriebssystems, welcher für die Zeilendarstellung auf dem Bildschirm verantwortlich ist) ab Speicherzelle 512 bis 600 zwischengespeichert.

Der Zeiger in 67 und 68 zeigt auf die jeweilige Adresse in diesem Eingabe- Pufferspeicher. Bei READ ist 67 und 68 identisch mit 65 und 66. Der Inhalt dieser Speicherzellen kann mit PEEK ausgelesen werden.

Zeiger auf Herkunft der Eingabe

Der Zeiger zeigt auf die jeweilige Adresse in diesem Eingabepufferspeicher.

Pointer to input result during GET, INPUT and READ.   This remembers where input is coming from.   Vector: INPUT Routine   Pointer: Temporary storage of Pointer during INPUT Routine.   Input vector  
$0045-$0046 VARNAM 69-70
Current BASIC Variable Name

The current variable name being searched for is stored here, in the same two- byte format as in the variable value storage area located at the address pointed to by 45 ($2D). See that location for an explanation of the format.

Name der gerade aufgerufenen Basic-Variablen

Wenn beim Ablauf eines Programms eine Variable auftaucht, muß ihr derzeitiger Wert im Variablen-Speicher gesucht werden. Während dieses Suchvorgangs wird der Name der Variablen in 69 und 70 zwischengespeichert. Die Form der Zwischenspeicherung ist dieselbe 2-Byte-Darstellung wie im Variablenspeicher, beschrieben bei der Behandlung der Speicherzellen 45 und 46.

Variablenname

Falls während des Ablaufs eines Programms eine Variable auftaucht, wird deren Name hier zwischengespeichert.

Name and type of current variable

Bits:

  • $45 bits #0-#6: First character of variable name.
  • $46 bits #0-#6: Second character of variable name; $00 = Variable name consists of only one character.
  • $45 bit #7 and $46 bit #7:
    • %00: Floating-point variable.
    • %01: String variable.
    • %10: FN function, created with DEF FN.
    • %11: Integer variable.
Variable's name is stored here.   Current BASIC Variable Name   Name of Variable being sought in Variable Table.   Current variable name  
$0047-$0048 VARPNT 71-72
Pointer to the Current BASIC Variable Value

This location points to the address of the descriptor of the current BASIC variable (see location 45 ($2D) for the format of a variable descriptor). Specifically, it points to the byte just after the two-character variable name.

During a FN call, this location does not point to the dependent variable (the A of FN A), so that a real variable of the same name will not have its value changed by the call.

Zeiger auf die Adresse des Wertes der gerade aufgerufenen Basic-Variablen

Ähnlich wie bei 69 und 70 wird hier während des Anrufes einer Variablen durch ein Programm ein Wert zwischengespeichert, diesmal aber nicht der Name der Variablen, sondern der 2-Byte-Wert, welcher direkt hinter dem Variablennamen steht. Nähere Einzelheiten sind im Text der Speicherzellen 45 und 46 beschrieben.

Davon ausgenommen sind selbstdefinierte Funktionen. Wie im Texteinschub Nr. 12 »Darstellung der Variablen einer selbstdefinierten Funktion« gezeigt ist, erscheinen diese ebenfalls im Variablenspeicher in einer Darstellung, welche den normalen Variablen sehr ähnlich ist.

Damit nun eine normale oder Feld-Variable denselben Namen haben kann wie eine Funktion, wird die oben genannte Zwischenspeicherung in 69 und 70 bei Funktionen unterdrückt.

Variablenadresse

In diesen Speicherzellen wird der Zeiger auf den Variablenwert abgelegt.

Pointer to value of current variable or FN function.   Pointer to variable in memory.   Pointer: Current BASIC Variable Data   Pointer: to value of (VARNAM) if Integer, to descriptor if String.   Current variable address  
$0047 FDECPT 71                 Pointer into power of tens of "FOUT".              
$0049-$004A FORPNT 73-74
Temporary Pointer to the Index Variable Used by FOR

The address of the BASIC variable which is the subject of a FOR/NEXT loop is first stored here, but is then pushed onto the stack. That leaves this location free to be used as a work area by such statements as INPUT, GET, READ, LIST, WAIT, CLOSE, LOAD, SAVE, RETURN, and GOSUB.

For a description of the stack entries made by FOR, see location 256 ($0100).

Zwischenspeicher für Variable einer FOR-NEXT-Schleife und für diverse Basic- Befehle

Die Adresse einer Schleifenvariablen wird zuerst hier gespeichert, bevor sie auf den Stapelspeicher ab Speicherzelle 256 ($0100) gebracht wird. Die Funktion und Arbeitsweise des Stapelspeichers werden wir bei diesen Adressen behandeln. Etliche Basic-Befehle, wie LIST, WAIT, GET, INPUT, OPEN, CLOSE und andere, verwenden die Speicherzellen 73 und 74 für Zwischenspeicherungen. Diese Adressen sind für den Basic-Programmierer daher nicht verwendbar.

Zeiger auf Variablenelement

Die Adresse einer Schleifenvariable wird zunächst hier gespeichert, bevor sie in den Stack gebracht wird.

Pointer to value of current variable during LET.   A variable's pointer for "FOR" loops and "LET" statements.   Pointer: Index Variable for FOR/NEXT   Pointer: Index Variable for FOR/NEXT loop.   Variable pointer for FOR/NEXT  
$0049 ANDMSK 73             Value of second parameter during WAIT.
Logical number during CLOSE and CLOSE Device number of LOAD, SAVE and VERIFY.
 
               
LSTPNT                 Pntr to list string.              
ANDMSK                 The mask used by WAIT for ANDing.              
$004A EORMSK 74             Value of third parameter during WAIT.
Device number during OPEN.
 
The mask for EORing in wait.              
$004B-$0060 75-96                     Temp Pointer / Data Area          
$004B-$004C OPPTR 75-76
Math Operator Table Displacement

This location is used during the evaluation of mathematical expressions to hold the displacement of the current math operator in an operator table. It is also used as a save area for the pointer to the address of program text which is currently being read.

Zwischenspeicher für Zeiger bei READ und mathematischen Operationen

Während der Auswertung eines mathematischen Ausdrucks durch die Routine FRMEVL des Basic-Übersetzers, wird der Platz des betroffenen mathematischen Operators in einer Tabelle, hier in 75 und 76, zwischengespeichert. Dieser Platz wird dabei als Abstand zum Beginn der Tabelle dargestellt. Außerdem verwendet der READ-Befehl diese Adressen als Zwischenspeicher für einen Programmzeiger. Die Speicherzeilen 75 und 76 sind in Basic nicht verwendbar.

        Pointer to current op's entry in "OPTAB".              
VARTXT        
Zwischenspeicher für Programmzeiger

Diese Speicherzellen dienen als Zwischenspeicher für mathematische Operationen. Außerdem werden die Speicherzellen auch noch vom READ-Befehl als Zwischenspeicher verwendet.

Temporary area for saving original pointer to current BASIC instruction during GET, INPUT and READ.       Temporary storage for TXTPTR during READ, INPUT and GET.   Temporary storage for TXTPTR during READ, INPUT and GET.   Y-save; op-save; Basic pointer save  
$004B VARTXT 75                 Pointer into list of variables.              
$004D OPMASK 77
Mask for Comparison Operation

The expression evaluation routine creates a mask here which lets it know whether the current comparieson operation is a less-than (1), equals (2), or greater-than (4) comparison.

Hilfsspeicher für Vergleichs-Operationen

Die bei 75 und 76 schon erwähnte Auswertungs-Routine FRMEVL erzeugt in der Speicherzelle 77 einen Wert, der angibt, ob es sich bei einer Vergleichsoperation um den Fall »kleiner als« (<), »gleich wie« (=) oder »größer als« (>) handelt. Diese Speicherzelle ist nur im Maschinencode erreichbar.

Maske für Vergleichsoperationen

Dieser Zeiger wird von mathematischen Routinen als Vergleichsoperator verwendet, daß heißt um festzustellen, ob ein Wert kleiner, gleich oder größer ist.

Comparison operator indicator

Bits:

  • Bit #1: 1 = ">" (greater than) is present in expression.
  • Bit #2: 1 = "=" (equal to) is present in expression.
  • Bit #3: 1 = "<" (less than) is present in expression.
Mask created by current operator.   Mask used during FRMEVL.   Mask used during FRMEVL.   Comparison symbol accumulator  
$004E-$0053 78-83                             Misc work area, pointer, etc  
$004E-$0052 TEMPF3 78-82                 A third FAC temporary (4 bytes).   Temporary storage for FLPT value.   Temporary storage for FLPT value.      
$004E-$004F DEFPNT 78-79
Pointer to the Current FN Descriptor

During function definition (DEF FN) this location is used as a pointer to the descriptor that is created. During function execution (FN) it points to the FN descriptor in which the evaluation results should be saved.

Zeiger auf Adresse, ab welcher der Wert der Variablen einer selbstdefinierten Funktion gespeichert ist

Basic erlaubt es bekanntlich, mit dem Befehl DEF selbst erfundene Funktionen zu definieren, welche die Form FN gefolgt von einem Variablennamen haben, zum Beispiel

DEF FNAA(X).

Im Texteinschub Nr. 12 »Darstellung von Variablen selbstdefinierter Funktionen« wird gezeigt beziehungsweise sichtbar gemacht, wie derartige Funktionen und ihre Variablen gespeichert werden. Während der Definition einer Funktion steht in 78 und 79 die Adresse, ab welcher die Funktion und der Wert ihrer Variablen gespeichert ist. Der Inhalt dieser Adressen ist identisch mit den Zeichen hinter dem Namen der Funktion (1. Gruppe im nebenstehenden Beispiel).

Nach der Ausführung der Funktion steht in 78 und 79 allerdings die Adresse, ab weiche der Zahlenwert der Funktion selbst gespeichert ist. Er ist identisch mit den Zeichen der 2. Gruppe.

Diesen Zusammenhang können Sie überprüfen, indem Sie im Programm des Texteinschubes folgende Zeilen hinzufügen:

25 PRINT PEEK(78)+256*PEEK(79)
35 PRINT PEEK(78)+256*PEEK(79)

Nach RUN erhalten Sie zwei Adressen, die Sie mit direkter Eingabe abfragen:

FOR I=0 TO 4:PRINT PEEK (1.Adresse+I);:NEXT I:
FOR J=0 TO 4:PRINT PEEK (2.Adresse+J);:NEXT J

Sie werden sehen, daß der Inhalt der beiden Adressen genau den Werten der Zeichen 3 bis 7 der beiden Gruppen entspricht, allerdings im Bildschirmcode.

Zeiger für FN

In $4E-$4F ist die Adresse angegeben, wo die Variablen und ihr Wert abgelegt sind.

Pointer to current FN function.   Pointer used in function definition.              
$004E GRBPNT 78                 Another used in garbage collection.              
$0050-$0052 DSCPNT 80-82
Temporary Pointer to the Current String Descriptor

The string assignment and handling routines use the first two bytes as a temporary pointer to the current string descriptor, and the third to hold the value of the string length.

Zeiger auf einen provisorischen Speicherplatz einer Zeichenkette, die gerade bearbeitet wird

Die Teilprogramme (von Programmierern »Routinen« genannt) des Basic-Übersetzers im ROM des Computers, welche Zeichenketten (Strings) behandeln, verwenden die ersten beiden Bytes dieser drei Speicherzellen, nämlich 80 und 81, um in Low-/ High-Byte-Darstellung diejenige Speicheradresse anzugeben, ab der die Zeichenkette im Programmspeicher zu finden ist.

Das dritte Byte (82) enthält die Länge der Zeichenkette. Wegen der provisorischen Natur dieses Zeigers ist er für Basic-Programme nicht geeignet.

Stringdescriptor   Pointer to current string variable during memory allocation.   Pointer to a string descriptor.              
$0053 FOUR6 83
Constant for Garbage Collection

The constant contained here lets the garbage collection routines know whether a three- or seven-byte string descriptor is being collected.

Flagge für die Garbage Collection

In dieser Speicherzelle steht während der sogenannten Garbage Collection (Müllabfuhr) eine Zahl, die angibt, ob die Variable der zur Überprüfung anstehenden Zeichenkette eine Länge von 3 oder 7 Byte hat.

Der Vorgang der Garbage Collection ist von B. Schneider, 64’er-Ausgabe 1/85, ausführlich beschrieben worden. Angaben über die Bedeutung der Variablen einer Zeichenkette finden Sie in den Texteinschüben Nr. 9 und Nr. 11.

Schrittweite für Garbage Collection  
Step size of garbage collection

Values: $03; $07.

Variable constant used by garb collect.   Length of String Variable during Garbage collection.   Length of String Variable during Garbege collection.      
$0054-$0056 JMPER 84-86
Jump to Function Instruction

The first byte is the 6502 JMP instruction ($4C), followed by the address of the required function taken from the table at 41042 ($A052).

Sprungbefehl auf die Adressen der Basic-Funktionen

Jede Basic-Funktion, wie zum Beispiel SGN, INT, ABS, USR und so weiter, wird durch ein spezielles Teilprogramm (Routine) des Basic-Übersetzers ausgeführt. Die Anfangsadresse jeder dieser Routinen sind in einer Tabelle im ROM fest eingespeichert. Im VC 20 steht diese Tabelle von 49234 bis 49279 ($C052 bis $C07F), im C 64 von 41042 bis 41087 ($A052 bis $A07F).

In der Speicherzelle 84 steht der Sprungbefehl JMP in Maschinencode, dargestellt durch die Zahl 75 ($4C). In den beiden anderen Zellen 85 und 86 steht dann in Low-/High-Byte-Darstellung die jeweilige Adresse in der Tabelle, welche der vom Programm gerade gebrauchten Basic-Funktion entspricht. Dieser gesamte Befehl JMP plus Adresse entspricht in Basic der GOSUB-Zeilennummer.

Ein Beispiel soll das verdeutlichen. Geben Sie direkt ein:

PRINT PEEK(84) ;PEEK(85); PEEK(86)

Wir erhalten

  • beim C 64: 76 13 184
  • beim VC 20: 76 13 216

Die erste Zahl ist genauso wie oben beschrieben. Die beiden anderen Zahlen ergeben zusammen die Adresse 47117 ($B80D) beziehungsweise 55309 ($D80D). Wenn Sie ein Buch mit ROM-Listing haben, werden Sie unter dieser Adresse die Routine für die Funktion »PEEK« finden. Das ist natürlich nicht erstaunlich, haben wir doch gerade vorher als letzten Befehl genau diese Funktion eingegeben.

Leider ist das auch die einzige Funktion, die ich Ihnen vorführen kann, denn zum Vorführen muß ich eben immer PEEKen, so daß beim besten Willen immer nur die oben angegebenen Zahlen erscheinen können.

    JMP ABS machine instruction, jump to current BASIC function.       Jump Vector used in Function Evaluation- JMP followed by Address ($4C,$LB,$MB).   Jump Vector used in Function Evaluation - JMP followed by Address ($4C,$LB,$MB).   Jump vector for functions  
$0054 84        
Konstante $4C JMP für Funktionen

Hier ist die Konstante für JMP ($4C) festgelegt.

                   
$0055-$0056 85-86        
Sprungvektor für Funktionen

In $55-$56 werden die Sprungvektoren für die Funktionen angegeben.

Execution address of current BASIC function.                  
$0055 SIZE 85                                
$0056 OLDOV 86                 The old overflow.              
$0057-$0060 87-96
BASIC Numeric Work Area

This is a very busy work area, used by many routines.

Arbeitsspeicher für diverse Arithmetik-Routinen des Basic-Übersetzers

Diese zehn Speicherplätze werden von verschiedenen Teilprogrammen (Routinen), besonders bei arithmetischen Operationen, als Zwischenspeicher verschiedener Werte, Flaggen und Zeiger benutzt.

                    Misc numeric work area  
$0057-$005B TEMPF1 87-91        
Register für Arithmetik, Akku #3

Die Register werden für die Zwischenspeicherung von Polynomauswertungen (TAN) benÖtigt.

Arithmetic register #3 (5 bytes).       Temporary storage for FLPT value.   Temporary storage for FLPT value.      
$0058 HIGHDS 88                 Destination of highest element in BLT.              
$005A HIGHTR 90                 Source of highest element to move.              
$005C-$0060 TEMPF2 92-96        
Register für Arithmetik, Akku #4

siehe oben

Arithmetic register #4 (5 bytes).       Temporary storage for FLPT value.   Temporary storage for FLPT value.      
$005D LOWDS 93                 Location of last byte transferred into.              
$005F LOWTR 95                 Last thing to move in BLT.              
$0058 ARYPNT 88                 A pointer used in array building.              
$005F GRBTOP 95                 A pointer used in garbage collection.              
$005D DECCNT 93                 Number of places before decimal point.              
$005E TENEXP 94                 Has a DPT been input?              
$005F DPTFLG 95                 Base ten exponent.              
$0060 EXPSGN 96                 Sign of base ten exponent.              
$0061-$0066 FAC 97-102
Floating Point Accumulator #1

The Floating Point Accumulator is central to the execution of any BASIC mathematical operation. It is used in the conversion of integers to floating point numbers, strings to floating point numbers, and vice versa. The results of most evaluations are stored in this location.

The internal format of floating point numbers is not particularly easy to understand (or explain). Generally speaking, the number is broken into the normalized mantissa, which represents a number between 1 and 1.99999..., and an exponent value, which represents a power of 2. Multiplying the mantissa by 2 raised to the value of the exponent gives you the value of the floating point number.

Fortunately, the BASIC interpreter contains many routines for the manipulation and conversion of floating point number, and these routines can be called by the user. See the entries for locations 3 and 5

Floating Point Accumulator #1 can be further divided into the following locations:

Gleitkomma-Akkumulator Nr.1

»Akkumulator« heißt seit der Zeit der mechanischen Rechenmaschinen eine Speicherzelle, welche bei Rechenoperationen dadurch im Mittelpunkt steht, daß laufend Daten in sie hineingeschrieben beziehungsweise aus ihr herausgelesen werden.

Normalerweise trägt diesen Namen das zentrale Rechenregister des Mikroprozessors. Leser des Assembler-Kurses kennen diesen Akkumulator inzwischen zur Genüge.

Die Speicherzellen 97 bis 102 werden deswegen ebenfalls Akkumulator genannt, weil sie bei der Verarbeitung von Gleitkommazahlen eine ähnliche zentrale Rolle spielen.

Zelle 97 enthält den Exponenten. Die Zellen 98 bis 101 enthalten die Mantisse.

Zelle 102 enthält das Vorzeichen der Gleitkommazahl. Eine 0 bedeutet ein positives, die Zahl 255 ein negatives Vorzeichen.

Mit dem Gleitkomma-Akkumulator Nr. 1 sind zwei weitere Speicherzellen eng verbunden, nämlich 104 ($68) und 112 ($70).

Ganz zum Schluß ist noch erwähnenswert, daß nach der Umwandlung einer Gleitkommazahl in eine ganze Zahl diese als Low-/High-Byte in den beiden Speicherzellen 98 und 99 steht, was für Maschinenprogramme vielleicht recht nützlich sein kann.

Fließkommaakku #1, FAC

Diese Register werden für die Berechnung von Fließkommazahlen verwendet.

FAC, arithmetic register #1 (5 bytes).   The floating accumulator       Main Floating point Accumulator.      
$0061 FACEXP 97
Floating Point Accumulator #1: Exponent

This exponent represents the closest power of two to the number, with 129 added to take care of the sign problem for negative exponents. An exponent of 128 is used for the value 0; an exponent of 129 represents 2 to the 0 power, or 1; an exponent of 130 represents 2 to the first power, or 2; 131 is 2 squared, or 4; 132 is 2 cubed, or 8; and so on.

                Floating-Point Accumulator #1: Exponent   FAC Exponent.   Accum#l : Exponent  
DSCTMP                 This is where temp descs are built.              
$0062-$0065 FACHO 98-101
Floating Point Accumulator #1: Mantissa

The most significant digit can be assumed to be a 1 (remember that the range of the mantissa is from 1 to 1.99999...) when a floating point number is stored to a variable. The first bit is used for the sign of the number, and the other 31 bits of the four-byte mantissa hold the other significant digits.

The first two bytes (98-99, $62-$63) of this location will hold the signed integer result of a floating point to integer conversion, in high-byte, low- byte order.

                Floating Accum. #1: Mantissa   FAC Mantissa.   Accum#l : Mantissa  
$0062 FACHO 98                 Most significant byte of mantissa.              
$0063 FACMOH 99                 One more.              
$0064 FACMO 100                 Middle order of mantissa.              
INDICE                 Indice is set up here by "QINT".              
$0065 FACLO 101                 Least sig byte of mantissa.              
$0066 FACSGN 102
Floating Point Accumulator #1: Sign

A value of 0 here indicates a positive number, while a value of 255 ($FF) indicates a negative number.

   
Vorzeichen von FAC

Der Zeiger gibt an, ob der Wert, der im FAC steht, positiv oder negativ ist.

Sign of FAC

Bits:

  • Bit #7: 0 = Positive; 1 = Negative.
Sign of FAC (0 or -1) when unpacked.   Floating Accum. #1: Sign   FAC Sign.   Accum#l : Sign  
$0067 SGNFLG 103
Number of Terms in a Series Evaluation

This location is used by mathematical formula evaluation routines. It indicates the number of separate evaluations that must be done to resolve a complex expression down to a single term.

Zwischenspeicher beziehungsweise Zählregister

Diese Adresse wird von zwei Routinen verwendet. Der Basic-Übersetzer benutzt sie als Vorzeichenspeicher bei der Umwandlung von Zahlen aus dem ASCII-Format in Gleitkommazahlen. Das Betriebssystem verwendet diese Adresse als Zähler der Abarbeitungsschritte bei der Berechnung eines Polynoms der Form y=a0+a1x+a2x^2+a3*x^3+...

Zähler für Polynomauswertung

Diese Speicherzelle dient als Zähler für die Polynomauswertung.

Number of degrees during polynomial evaluation.   Sign of FAC is preserved bere by "FIN".   Pointer: Series Evaluation Constant   Pointer: Series Evaluation Constant.   Series evaluation constant pointer  
DEGREE                 A count used by polynomials.              
$0068 BITS 104
Floating Point Accumulator #1: Overflow Digit

This location contains the overflow byte. The overflow byte is used in an intermediate step of conversion from an integer or text string to a floating point number.

Überlauf-Speicher des Gleitkomma-Akkumulators Nr. 1

Wenn eine Zahl so groß wird, daß sie mit den zur Verfügung stehenden Stellen nicht mehr dargestellt werden kann, sprechen wir von einem »Überlauf«.

Bei Gleitkommazahlen liegt diese Überlaufgrenze bei 1,70141183 * 10^38.

Während einer mathematischen Berechnung kann es intern im Computer vorkommen, daß ein Überlauf eintritt, der aber am Ende der Operation wieder verschwinden würde. Der Akkumulator Nr. 1 benutzt in einem derartigen Fall die Speicherzelle 104, um die verfügbare Stellenzahl um 8 Bit zu vergrößern. Für endgültige Resultate steht diese Erweiterung natürlich nicht zur Verfügung.

Dieser Vorgang tritt besonders häufig bei der Umwandlung von ganzen Zahlen oder Zeichenketten in Gleitkommazahlen auf.

Rundungsbyte für FAC

Hier wird angegeben, ob der Wert, der im FAC steht, auf- oder abgerundet werden soll.

Temporary area for various operations.   Something for "SHIFTR" to use.   Floating Accum. #1: Overflow Digit   Bit Overflow Area during normalisation Routine.   Accum#l hi-order (over flow)  
$0069-$006E ARG 105-110
Floating Point Accumulator #2

A second Floating Point Accumulator, used in conjunction with Floating Point Accumulator #1 in the evaluation of products, sums, differences--in short, any operation requiring more than one value. The format of this accumulator is the same as FAC1.

Gleitkomma-Akkumulator Nr. 2

Spätestens jetzt verstehen Sie, warum der Akkumulator der Speicherzellen 97 bis 102 die Nr. 1 hat. Es gibt hier noch einen zweiten Gleitkomma-Akkumulator, der ein identischer Zwilling ist. Zwei Akkumulatoren sind immer dann notwendig, wenn mathematische Operationen ablaufen, welche mehr als einen Operanden verarbeiten, wie zum Beispiel Multiplikation, Division und so weiter.

Aufgrund der Identität der beiden Akkumulatoren kann ich mir eine weitere Beschreibung ersparen.

Fließkommaakku#2, ARG

Diese Register werden für die Berechnung von Fließkommazahlen verwendet.

ARG, arithmetic register #2 (5 bytes).   The floating argument (unpacked)       Auxiliary Floating point Accumulator.   Accum#2 : Exponent, etc.  
$0069 ARGEXP 105 Floating Point Accumulator #2: Exponent                   Floating-Point Accumulator #2: Exponent   AFAC Exponent.      
$006A-$006D 106-109 Floating Point Accumulator #2: Mantissa                   Floating Accum. #2: Mantissa   AFAC Mantissa.      
$006A ARGHO 106                                
$006B ARGMOH 107                                
$006C ARGMO 108                                
$006D ARGLO 109                                
$006E ARGSGN 110 Floating Point Accumulator #2: Sign      
Vorzeichen von ARG

Hier wird angegeben, ob der Wert, der im ARG steht, positiv oder negativ ist.

Sign of ARG

Bits:

  • Bit #7: 0 = Positive; 1 = Negative.
    Floating Accum. #2: Sign   AFAC Sign.      
$006F-$0070 STRNG1 111-112             Pointer to first string expression during string comparison.                  
$006F ARISGN 111
Result of a Signed Comparison of Accumulator #1 to Accumulator #2

Used to indicate whether the two Floating Point Accumulators have like or unlike signs. A 0 indicates like signs, a 255 ($FF) indicates unlike signs.

Flagge für Vorzeichenvergleich der Gleitkomma-Akkumulatoren Nr. 1 und Nr. 2

Wenn die Zahl in beiden Akkumulatoren gleiche Vorzeichen hat, steht in Speicherzelle 111 eine 0, bei verschiedenen Vorzeichen eine 255.

Vergleichsbyte der Vorzeichen von FAC und ARG

Diese Speicherzelle gibt dem Interpreter an, ob die Vorzeichen der beiden Akkus übereinstimmen.

    A sign reflecting the result.   Sign Comparison Result: Accum. # 1 vs #2   Sign of result of Arithmetic Evaluation.   Sign comparison, Acc#l vs #2  
$006F-$0070 STRNG1 111-112                 Pointer to a string or descriptor.              
$0070 FACOV 112
Low Order Mantissa Byte of Floating Point Accumulator #1 (For Rounding)

If the mantissa of the floating point number has more significant figures than can be held in four bytes, the least significant figures are placed here. They are used to extend the accuracy of intermediate mathematical operations and to round to the final figure.

Rundungsspeicher des Gleitkomma-Akkumulators Nr. 1

Es kann vorkommen, daß die Mantisse einer Gleitkommazahl mehr Stellen hat, als mit den vier Mantissen-Bytes des Akkumulators Nr. 1 (Zelle 97 bis 102) dargestellt werden können. In diesem Fall werden die hintersten, das heißt die unwichtigsten Stellen hinter dem Komma in der Zelle 112 abgelegt. Von dort werden sie geholt, um die Genauigkeit von mathematischen Operationen zu erhöhen und auch um Endresultate abrunden zu können.

FAC-Rundungsbyte       Overflow byte of the FAC.   Floating Accum. #1. Low-Order (Rounding)   FAC low-order rounding.   Accum#l lo-order (rounding)  
$0071-$0072 FBUFPT 113-114
Series Evaluation Pointer

This location points to the address of a temporary table of values built in the free RAM area for the evaluation of formulas. It is also used for such various purposes as a TI$ work area, string setup pointer, and work space for the evaluation of the size of an array.

Although this is labeled a pointer to the tape buffer in the Programmer's Reference Guide, disassembly of the BASIC ROM reveals no reference to this location for that purpose (see 178 ($B2) for pointer to tape buffer).

Zwischenspeicher für verschiedene Routinen

Diese Speicherzellen werden von sehr vielen Routinen des Übersetzers und des Betriebssystems, wie zum Beispiel Zeichenkettenverarbeitung, interne Uhr (TI$), Bestimmung der Größe von Feldern (Arrays) und etlichen anderen verwendet.

Zeiger für Polynomauswertung

Hier ist in LOW- und HIGH-Byte angegeben, was ausgewertet werden sol 1.

    Pointer into FBUFFR used by FOUT.   Pointer: Cassette Buffer   Pointer: Used during CRUNCH/ASCII conversion.   Cassette buff len/Series pointer  
STRNG2             Temporary area for saving original pointer to current BASIC instruction during VAL().                  
POLYPT             Pointer to current item of polynomial table during polynomial evaluation.                  
CURTOL             Auxiliary pointer during array operations.                  
BUFPTR                 Pointer to buf used by "CRUNCH".              
STRNG2                 Pointer to string or desc.              
POLYPT                 Pointer into polynomial coefficients.              
CURTOL                 Absolute linear index is formed here.              
$0073-$008A CHRGET 115-138
Subroutine: Get Next BASIC Text Character

This is actually a machine language subroutine, which at the time of a BASIC cold start (such as when the power is turned on) is copied from MOVCHG (58274, $E3A2) in the ROM to this zero page location.

CHRGET is a crucial routine which BASIC uses to read text characters, such as the text of the BASIC program which is being interpreted. It is placed on zero page to make the routine run faster. Since it keeps track of the address of the character being read within the routine itself, the routine must be in RAM in order to update that pointer. The pointer to the address of the byte currently being read is really the operand of a LDA instruction. When entered from CHRGET, the routine increments the pointer by modifying the operand at TXTPTR (122, $7A), thus allowing the next character to be read.

Entry at CHRGOT (121, $79) allows the current character to be read again. The CHRGET routine skips spaces, sets the various flags or the status register (.P) to indicate whether the character read was a digit, statement terminator, or other type of character, and returns with the retrieved character in the Accumulator (.A).

Since CHRGET is used to read every BASIC statement before it is executed, and since it is in RAM, and therefore changeable, it makes a handy place to intercept BASIC to add new features and commands (and in the older PET line, it was the only way to add such features). Diversion of the CHRGET routine for this purpose is generally referred to as a wedge.

Since a wedge can greatly slow down execution speed, mose of the time it is set up so that it performs its preprocessing functions only when in direct or immediate mode. The most well-known example of such a wedge is the "Universal DOS Support" program that allows easier communication with the disk drive command channel.

As this is such a central routine, a disassembly listing is given below to provide a better understanding of how it works.

115 $73   CHRGET  INC TXTPTR   ; increment low byte of TXTPTR
117 $75           BNE CHRGOT   ; if low byte isn't 0, skip next
119 $77           INC TXTPTR+1 ; increment high byte of TXTPTR
121 $79   CHRGOT  LDA          ; load byte from where TXTPTR points
                               ; entry here does not update TXTPTR,
                               ; allowing you to readl the old byte again
122 $7A   TXTPTR  $0207        ; pointer is really the LDA operand
                               ; TXTPTR+1 points to 512-580 ($0200-$0250)
                               ; when reading from the input buffer
                               ; in direct mode
124 $7C   POINTB  CMP #$3A     ; carry flag set if > ASCII numeral 9
126 $7E           BCS EXIT     ; character is not a numeral--exit
128 $80           CMP #$20     ; if it is an ASCI space...
130 $82           BEQ CHRGET   ; ignore it and get next character
132 $84           SEC          ; prepare to subtract
133 $85           SBC #$30     ; ASCII 0-9 are between 48-57 ($30-$39)
135 $87           SEC          ; prepare to subtract again
136 $88           SBC #$D0     ; if < ASCII 0 (57, $39) then carry is set
138 $8A   EXIT    RTS          ; carry is clear only for numeral on return

The Accumulator (.A register) holds the character that was read on exit from the routine. Status register (.P) bits which can be tested for on exit are:

  • Carry Clear if the character was an ASCII digit 0-9.
  • Carry Set, otherwise.
  • Zero Set only if the character was a statement terminator 0 or an ASCII colon, 58 ($3A).
  • Zero Clear, otherwise.

One wedge insertion technique is to change CHRGET's INC $7A to a JMP WEDGE, have your wedge update TXTPTR itself, and then JSR CHRGOT. Another is to change the CMP #$3A at location 124 ($7C), which I have labeled POINTB, to a JMP WEDGE, do your wedge processing, and then exit through the ROM version of POINTB, which is located at 48283 ($E3AB). For more detailed information about wedges, see Programming the PET/CBM, Raeto Collin West, pages 365-68.

While the wedge is a good, quick technique for adding new commands, a much more elegant method exists for accomplishing this task on the VIC-20 and 64 withouth slowing BASIC down to the extent that the wedge does. See the entries for the BASIC RAM vector area at 768-779 ($0300-$030B) for more details.

Teilprogramm »Nächstes Zeichen eines Basic-Textes holen« (CHRGET-Routine)

Die Problematik der Übersetzung von Basic-Befehlen und Anweisungen besteht darin, daß die Übersetzungsschritte durch entsprechende Programmteile des Basic-Übersetzers im Computer fest vorprogrammiert sein müssen, was bedeutet, daß diese Programme natürlich im - nicht veränderbaren - ROM stehen.

Auf der anderen Seite verlangt aber der Übersetzungsvorgang, daß gewisse Teile dieser Programme sich laufend verändern. Als Beispiel soll der Zeiger herhalten, der angibt, in welcher Speicherzelle das nächste zu bearbeitende Zeichen steht. Dieser Zeiger und die zusammengehörigen Programmschritte dürfen natürlich nicht im ROM stehen, denn da sind sie ja nicht änderbar.

Dieser Konflikt wird dadurch gelöst, daß dieses »variable« Teilprogramm des Übersetzers zwar im ROM steht (im C 64 ab 58274 oder $E3A2, im VC 20 ab 58247 oder $E387), von wo es aber direkt nach dem Einschalten des Computers in das RAM, und zwar in die Speicherzellen 115 bis 138, umgeladen wird.

Dieses Teilprogramm, welches die Zeichen zur Übersetzung herbeiholt und deswegen »Character-Get« oder kurz CHARGET-Routine genannt wird, ist wegen seiner Veränderbarkeit natürlich ein beliebtes Objekt aller möglichen Manipulationen. Es ist deshalb im Assembler-Kurs, Teil 5, im 64’er, Ausgabe 1/85, im Detail beschrieben worden, allerdings mit Schwerpunkt auf Assembler- Maschinensprache.

Für Basic-Programmierer möchte ich hier deshalb eine kurze Beschreibung der CHARGET-Routine einfügen.

Die Routine beginnt mit einem Sprung auf den oben schon erwähnten Zeiger in Adresse 122 und 123, welcher seinerseits auf die Adresse zeigt, in welcher das nächste zu übersetzende Zeichen steht. Das Zeichen wird entsprechend dem Hinweis des Zeigers geholt, in den Akkumulator des Mikroprozessors geladen und dort verschiedenen Prüfungen unterzogen. Ist das Zeichen ein Gänsefuß, erkennt das Programm, wie es das nächste Zeichen interpretieren und behandeln muß. Ein Doppelpunkt leitet einen neuen Befehl ein, eine Leerstelle wird unterdrückt und so weiter.

Mit dem Befehl

PRINT PEEK(122)+256*PEEK(123)

können wir innerhalb eines Programms ausdrucken, wohin der Zeiger nach dem letzten Basic-Zeichen deutet. Eine Überprüfung mit den Methoden, die ich bei der Besprechung der Speicherzellen 43 bis 56 genannt habe, zeigt Ihnen den Zusammenhang.

Normalerweise wird der Zeiger in 122 und 123 nach jedem Zeichen um 1 erhöht, da ja die Zeichen einer Basic-Zeile hintereinander im Speicher stehen. Ein GOTO- oder GOSUB-Befehl kann diese Folge natürlich unterbrechen, ebenso wie eine willkürliche Änderung durch einen Eingriff von außen.

Ein derartiger Eingriff, auch »wedge« (Keil) genannt, öffnet natürlich Tür und Tor für Programmiertricks, insbesondere für Einbau von neuen, selbsterfundenen Befehlen. Man kann entweder den allerersten Sprungbefehl auf den Zeiger so umlenken, daß er auf ein eigenes Maschinenprogramm springt, oder man kann den Zeiger selbst »verbiegen«, so daß er auf eine andere Adresse und damit auf ein anderes Zeichen zeigt. Es gibt dafür viele Möglichkeiten, die aber alle nur in Maschinencode funktionieren. Theoretisch können wir natürlich den Inhalt des Zeigers in 122 und 123 durch POKE verändern. Aber was dann? Jeder nachfolgende Basic-Befehl löst natürlich wieder die normale Übersetzungsroutine aus und unser schöner POKE ist für die Katz.

Wie ein Wedge in Maschinensprache gemacht wird, hat Christoph Sauer im VC 20- Kurs - 64’er, Ausgabe 9/84 beschrieben. Allerdings ist das Beispiel für Anfänger nicht verständlich, was mich zu der Überzeugung bringt, daß die CHARGET-Routine und ihre Anwendung einen eigenen Aufsatz wert wäre.

CHRGET-Routine

Diese Routine holt ein Zeichen aus dem BASIC-Text.

CHRGET. Machine code routine to read next byte from BASIC program or direct command (24 bytes).  
RAM code.

This code gets changed throughout execution. It is made to be fast this way. Also, [X] and [Y] are not disturbed.

"CHRGET" using [TXTPTR] as the current text pntr, fetches a new character into ACCA after incrementing [TXTPTR] and sets condition codes according to what's in ACCA.

  • not C = numeric ("0" thru "9")
  • Z = ":" or end-of-line (a null)

[ACCA] = new char.

[TXTPTR]=[TXTPTR]+1

The following exists in ROM if ROM exists and is loaded down here by init. Otherwise it is just loaded into this RAM like all the rest of RAM is loaded.

Subroutine: Get Next Byte of BASIC Text  
Subroutine: Get next Byte of BASIC Text.
,0073  INC $7A
,0075  BNE $79
,0077  INC $7B
,0079  LDA $0801
,007C  CMP #$3A
,007E  BCS $8A
,0080  CMP #$20
,0082  BEQ $73
,0084  SEC
,0085  SBC #$30
,0087  SEC
,0088  SBC #$D0
,008A  RTS
CHRGET subroutine; get Basic char  
$0079 CHRGOT 121            
CHRGOT. Read current byte from BASIC program or direct command.

Pointer to current byte in BASIC program or direct command.

    Entry to Get Same Byte of Text Again   Entry to Get same Byte again.      
$007A-$007B TXTPTR 122-123        
Programmzeiger

In diesen Speicherzellen wird in LOW- und HIGH-Byte die Anfangsadresse des als nächstes auszuführenden Befehls im BASIC-RAM angegeben.

        Pointer: Current Byte of BASIC Text   Pointer: Current Byte of BASIC Text.   Basic pointer (within subrtn)  
$008B-$008F RNDX 139-143
RND Function Seed Value

This location holds the five-byte floating point value returned by the RND function. It is initially set to a seed value copied from ROM (the five bytes are 128, 79, 199, 82, 88--$80, $4F, $C7, $52, $58).

When the function RND(X) is called, the numeric value of X does not affect the number returned, but its sign does. If X is equal to 0, RND generates a seed value from chip-level hardware timers. If X is a positive number, RND(X) will return the next number in an arithmetic sequence. This sequence continues for such a long time without repeating itself, and gives such an even distribution of numbers, that it can be considered random. If X is negative, the seed value is changed to a number that corresponds to a scrambled floating point representation of the number X itself.

Given a particular seed value, the same pseudorandom series of numbers will always be returned. This can be handy for debugging purposes, but not where you wish to have truly random numbers.

The traditional Commodore method of selecting a random seed is by using the expression RND(-TI), mostly because RND(0) didn't function correctly on early PETs. While the RND(0) form doesn't really work right on the 64 either (see location 57495 ($E097)), the expression RND(-RND(0)) may produce a more random seed value.

Wert der RND-Funktion als Gleitkommazahl

Mit dem Befehl RND(X) kann bekanntlich eine Zufallszahl erzeugt werden. Was das bedeutet und wie »zufällig« diese Zahlen sind, können Sie dem Texteinschub Nr. 13 »Wie zufällig sind Zufallszahlen?« entnehmen.

Beim Einschalten des Computers werden die Zahlen 128, 79, 199, 82 und 88 in diese Speicherzellen geschrieben. Mit der folgenden Zeile können Sie das gleich nach dem Einschalten des Computers leicht überprüfen.

FOR X=139 TO 143:PRINT PEEK(X):NEXT

Nach den Manipulationen des RND-Befehls wird das Resultat wieder in die Zellen 139 bis 143 als neuer Ausgangswert (seed) für den nächsten RND-Befehl gebracht.

Diese fünf Zahlen stellen eine Gleitkommazahl dar. Ihre Form entspricht dabei der Aufteilung, wie sie auch im Gleitkomma-Akkumulator (97 bis 101) verwendet wird.

Eine Abfrage dieser Zahlen aus den Zellen 139 bis 143 ist natürlich möglich, aber nicht ergiebig, weil das Resultat von RND(X) direkt als Zahl verfügbar ist, während die 5 Byte erst in eine brauchbare Zahl umgerechnet werden müßten. Eine Änderung durch POKEn neuer Werte in diese Speicherzellen geht leider nicht.

letzter RND-Wert

In diesen Registern wird der letzte RND-Wert im Fließkommaformat abgelegt.

Previous result of RND().       Floating RND Function Seed Value   Floating RND Function Seed Value.   RND seed value  
$0090 STATUS 144
Kernal I/O Status Word (ST)

The Kernal routines which open I/O channels or perform input/output functions check and update this location. The value here is almost always the same as that returned to BASIC by use of the reserved variable ST. Note that BASIC syntax will not allow an assignment such as ST=4. A table of status codes for cassette and serial devices follows below:

Bit Bit Value Cassette
2 4 Short Block
3 8 Long Block
4 16 Unrecoverable error (Read), mismatch
5 32 Checksum error
6 64 End of file
Bit Bit Value Serial Devices
0 1 Time out (Write)
1 2 Time out (Read)
6 64 EOI (End or Identify)
7 128 Device not present

Probably the most useful bit to test is Bit 6 (end of file). When using the GET statement to read in individual bytes from a file, the statement IF ST AND 64 will be true if you have got to the end of the file.

For status codes for the RS-232 device, see the entry for location 663 ($0297).

Statusvariable ST

Diese Adresse enthält ein Byte, welches mit der Statusvariablen ST von Basic identisch ist. Diese reservierte Variable ist im Texteinschub Nr. 14 »ST-atus« näher beschrieben.

Alle Routinen des Betriebssystems, die mit Ein- und Ausgabe zu tun haben, benutzen diese Speicherzelle zum Abspeichern und Abfragen des Status der Ein-/ Ausgabeoperationen.

Genauer gesagt, alle Ein-/Ausgabeoperationen, die mit der Datasette und mit dem Floppy-Gerät beziehungsweise dem Drucker zu tun haben, benutzen die Adresse 144. Im Fachjargon sprechen wir vom Kassetten-Port und vom seriellen Port.

Der dritte Anschluß des Computers, nämlich der RS232 oder User-Port, benutzt für den Status die Speicherzelle 663.

Jedes Bit der Zelle 144 hat eine eigene Bedeutung wie folgt.

Bit Wert Kassette
2 4 Kurzer Block
3 8 Langer Block
4 16 Lesefehler (nicht korrigierbar)
5 32 Prüfsummenfehler
6 64 File-Ende
7 128 Band-Ende
Bit Wert Floppy/Drucker
0 1 Fehler beim Schreiben
1 2 Fehler beim Lesen
6 64 Daten-Ende
7 128 »Device Not Present«-Fehler

Alle nicht aufgeführten Bits sind nicht benutzt.

Diese Speicherzelle beziehungsweise die Statusvariable ST kann recht nützlich sein. Einige Kochrezepte dafür werden im Texteinschub Nr. 14 behandelt.

Statuswort ST

In dieser Speicherzelle, die auch mit der BASIC-Variable ST identisch ist, sind die Fehlermeldungen der Datasette und der Floppy verzeichnet:

Bit Datasette
0 Unbenutzt
1 Unbenutzt
2 Kurzer Block
3 Langer Block
4 Lesefehler
5 Prüfsummenfehler
6 File-Ende
7 Band-Ende
Bit Floppy
0 Fehler beim Schreiben
1 Fehler beim Lesen
2 Unbenutzt
3 Unbenutzt
4 Unbenutzt
5 Unbenutzt
6 Daten-Ende
7 DEVICE NOT PRESENT ERROR
Value of ST variable, device status for serial bus and datasette input/output

Serial bus bits:

  • Bit #0: Transfer direction during which the timeout occured; 0 = Input; 1 = Output.
  • Bit #1: 1 = Timeout occurred.
  • Bit #4: 1 = VERIFY error occurred (only during VERIFY), the file read from the device did not match that in the memory.
  • Bit #6: 1 = End of file has been reached.
  • Bit #7: 1 = Device is not present.

Datasette bits:

  • Bit #2: 1 = Block is too short (shorter than 192 bytes).
  • Bit #3: 1 = Block is too long (longer than 192 bytes).
  • Bit #4: 1 = Not all bytes read with error during pass 1 could be corrected during pass 2, or a VERIFY error occurred, the file read from the device did not match that in the memory.
  • Bit #5: 1 = Checksum error occurred.
  • Bit #6: 1 = End of file has been reached (only during reading data files).
I/O operation status byte   Kernal I/O Status Word: ST   Kernal I/O Status Word ST.   Status word ST  
$0091 STKEY 145
Flag: Was STOP Key Pressed?

This location is updated every 1/60 second during the execution of the IRQ routine that reads the keyboard and updates the jiffy clock.

The value of the last row of the keyboard matrix is placed here. That row contains the STOP key, and although this location is used primarily to detect when that key has been pressed, it can also detect when any of the other keys in that row of the matrix have been pressed.

In reading the keyboard matrix, a bit set to 1 means that no key has been pressed, while a bit reset to 0 indicates that a key is pressed. Therefore, the following values indicate the keystrokes detailed below:

255 $FF no key pressed
254 $FE 1 key pressed
253 $FD (left arrow) key pressed
251 $FB CTRL key pressed
247 $F7 2 key pressed
239 $EF space bar pressed
223 $DF Commodore logo key pressed
191 $BF Q key pressed
127 $7F STOP key pressed

VIC owners will notice that the 64's keyboard matrix is very different from the VIC's. One of the advantages of this difference is that you can test for the STOP key by following a read of this location with a BPL instruction, which will cause a branch to occur anytime that the STOP key is pressed.

Zwischenspeicher für Abfrage der STOP-Taste

In den Bildern 13 und 14 ist dargestellt, wie die Tasten des VC 20 und des C 64 miteinander über eine Matrix verbunden sind.

60mal in der Sekunde unterbricht der Computer seine Arbeit, merkt sich, wo er gerade ist und fragt dann unter anderem, ob die STOP-Taste gedrückt worden ist. Dadurch wird erreicht, daß die STOP-Taste jederzeit Priorität hat.

Die Abfrage geht so vonstatten, daß das Betriebssystem über das im Bild 13 und 14 gezeigte Spaltenregister 56320 (beim VC 20: 37152) diejenige Tastenspalte anwählt, in welcher sich die STOP-Taste befindet. Aus Bild 13 und 14 sehen wir, daß dies die Spalte mit der Codenummer 127 beziehungsweise 247 ist. Ist in dieser Spalte eine Taste gedrückt, wird an ihrer Stelle eine Null in das Auslese-Register 56321 (VC 20: 37153) geschrieben. Die dadurch entstandene Dualzahl wird in die Speicherzelle 145 gebracht.

Es ist sicher verständlich, daß auf diese Weise nicht nur die STOP-Taste, sondern alle Tasten der Spalte 127 (247) abgefragt werden können. Ein kleines Demonstrationsprogramm kann das beweisen:

10 PRINT PEEK (656321);PEEK (145)
20 GOTO 10

Beim VC 20 ist statt 56321 natürlich 37153 einzusetzen.

Das Zahlenband kann durch die Tasten der genannten Spalte - und nur durch diese - beeinflußt werden.

Flag für STOP-Taste

In dieser Speicherzelle wird vermerkt, ob die Stoptaste gedrückt worden ist oder nicht.

Stop key indicator

Values:

  • $7F: Stop key is pressed.
  • $FF: Stop key is not pressed.
STOP key flag   Flag: STOP key / RVS key   Flag: $7F = STOP key.   Keyswitch PIA : STOP and RVS flags  
$0092 SVXT 146
Timing Constant for Tape Reads

This location is used as an adjustable timing constant for tape reads, which can be changed to allow for the slight speed variation between tapes.

Zeltkonstante beim Lesen vom Band

Die Speicherzelle enthält eine vom Betriebssystem einstellbare Zahl, welche die kleinen Unterschiede in der Aufnahmegeschwindigkeit ausgleicht, die bei verschiedenen Datasetten vorkommen können.

Diese Zeitkonstante steht im Zusammenhang mit der Zahl, die in den Speicherzellen 176 und 177 steht.

Eine Veränderung der Konstante in Basic ist nicht möglich.

Zeitkonstante für Band

Dieses Register hat die Aufgabe, kleine Unterschiede bei der Aufnahmegeschwindigkeit auszugleichen.

Unknown. (Timing constant during datasette input.)   Cassette: temp used to adjust software servo   Timing Constant for Tape   Timing Constant for Tape.   Timing constant for tape  
$0093 VERCK 147
Flag for Load Routine: 0=LOAD, 1=VERIFY

The same Kernal routine can perform either a LOAD or VERIFY, depending on the value stored in the Accumulator (.A) on entry to the routine. This location is used to determine which operation to perform.

Flagge für LOAD oder VERIFY

Diese Flagge dient dem Betriebssystem, um zu unterscheiden, ob eine LOAD- Operation nur LOADen oder aber VERIFYen soll.

Sie ist identisch mit der Flagge des Basic-Übersetzers in Speicherzelle 10. Genauere Hinweise bitte ich der Beschreibung von Zelle 10 zu entnehmen.

Flag für LOAD $00, oder für VERIFY $01

Dieses Flag dient dem Betriebssystem dazu, um zu unterscheiden, ob eine LOAD oder eine VERIFY Operation erfolgt.

LOAD/VERIFY switch

Values:

  • $00: LOAD.
  • $01-$FF: VERIFY.
Cassette: verify or load flag (Z - loading)   Flag: 0 = Load, 1 = Verify   Flag: 0 = Load, 1 = Verify.   Load = 0, Verify = l  
$0094 C3P0 148
Flag: Serial Bus--Output Character Was Buffered

This location is used by the serial output routines to indicate that a character has been placed in the output buffer and is waiting to be sent.

Flagge für Floppy/Drucker-Ausgang

Das Betriebssystem benutzt diese Speicherzelle, um anzuzeigen, daß ein Zeichen im Ausgabepuffer steht, welches zum Floppy-Gerät oder zum Drucker geleitet werden soll. Diese Flagge setzt alle am seriellen Port angeschlossenen Geräte in den Zustand »Listen«, das heißt bereit zu sein, Daten aufzunehmen.

Flag bei IEC-Ausgabe

Diese Adresse setzt bei Floppy und Drucker den "LISTEN" Zustand.

Serial bus output cache status

Bits:

  • Bit #7: 1 = Output cache dirty, must transfer cache contents upon next output to serial bus.
IEEE buffered char flag   Flag: Serial Bus-Output Char. Buffered   Flag: Serial Bus - Output Character buffered.   Serial output : deferred char flag  
$0095 BSOUR 149
Buffered Character for Serial Bus

This is the character waiting to be sent. A 255 ($FF) indicates that no character is waiting for serial output.

Zeichen im Ausgabepuffer

In dieser Speicherzelle wird das Zeichen abgelegt, welches als nächstes über den Serial-Port zum Floppy-Gerät oder zum Drucker transportiert wird, sobald die Flagge in 148 die Bereitschaft anzeigt.

Ausgabepuffer für IEC-Bus

Hier wird das Zeichen abgelegt, welches über den seriellen Port zur Floppy oder zum Drucker geschickt werden soll, sobald die Adresse $94 Bereitschaft zeigt.

Serial bus output cache, previous byte to be sent to serial bus.   Char buffer for IEEE   Buffered Character for Serial Bus   Buffered Character for Serial Bus.   Serial deferred character  
$0096 SYNO 150 Cassette Block Synchronization Number  
Arbeitsspeicher für die Band-Leseroutine

Diese Speicherzelle wird zur Zwischenspeicherung von Daten beim Lesen einer Kassette benutzt.

Flag für EOT vom Band empfangen

In $96 werden die Daten zwischengespeichert, die vom Band gelesen werden.

Unknown. (End of tape indicator during datasette input/output.)   Cassette: flags if we have block SYNC (16 zero dipoles)   Cassette Sync No.   Cassette Sync. number.   Tape EOT received  
$0097 XSAV 151
Temporary .X Register Save Area

This .X register save area is used by the routines that get and put an ASCII character.

Zwischenspeicher des X-Registers

Maschinen-Programmierer kennen das X-Register des Mikroprozessors. Beim Lesen eines Zeichens von der Datasette wird der Inhalt des X-Registers in dieser Adresse zwischengespeichert.

Zwischenspeicher für Register

Beim Lesen von Band wird hier das X-Register zwischengespeichert.

Temporary area for saving original value of Y register during input from RS232.
Temporary area for saving original value of X register during input from datasette.
 
Temp for BASIN   Temp Data Area   Temporary storage of X Register during CHRIN.
Temporary storage of Y Register during RS232 fetch.
 
Register save  
$0098 LDTND 152
Number of Open I/O Files/Index to the End of File Tables

The number of currently open I/O files is stored here. The maximum number that can be open at one time is ten. The number stored here is used as the index to the end of the tables that hold the file numbers, device numbers, and secondary address numbers (see locations 601-631 ($0259-$0277) for more information about these tables).

CLOSE decreases this number and removes entries from the tables referred to above, while OPEN increases it and adds the appropriate information to the end of the tables. The Kernal routine CLALL closes all files by setting this number to 0, which effectively empties the table.

Anzahl der offenen Files

Ein File, oder auf Deutsch gesagt, eine Datei, wird mit dem Befehl OPEN eröffnet. Nach OPEN folgt die Nummer der Datei; sie ist beliebig wählbar bis maximal 255. Als zweites folgt die Nummer des Gerätes, mit dem die Verbindung hergestellt werden soll.

Es ist erlaubt, mehrere Dateien gleichzeitig geöffnet zu halten, vorausgesetzt die Nummern der Dateien sind verschieden.

In Speicherzelle 152 wird festgehalten, wieviel Dateien gleichzeitig geöffnet sind. Dieses kleine Programm zeigt es uns deutlich:

10 FOR K=10 TO 22
20 PRINT PEEK (152),K
30 OPEN K,0
40 NEXT K

Mit der FOR...NEXT-Schleife der Zeilen 10 und 40 eröffnen wir 13 Dateien hintereinander, und zwar - wie Zeile 30 uns deutlich macht - mit der Tastatur. Die Tastatur hat die Nummer 0, der Drucker die Nummer 4, das Floppy-Gerät die Nummer 8 und die Datasette die Nummer 1. Ich habe die Tastatur gewählt, obwohl es keinen Sinn ergibt, weil sie die vielen Eröffnungen ohne zu unterbrechen akzeptiert.

Nach RUN sehen wir links untereinander den Inhalt von 152, also die Anzahl der eröffneten Dateien. Rechts steht jeweils die Nummer der eröffne-

In der 10. Zeile sehen wir jetzt die 10 als Inhalt von 152 und als neue Dateinummer (Schleifenvariable K) wieder die 10. Das Programm bleibt aber stehen und meldet FILE OPEN. Es hat recht, denn die Datei 10 ist bereits als erste eröffnet, aber nicht wieder geschlossen worden.

Das Betriebssystem macht das so, daß jede der Dateinummern in eine Tabelle geschrieben wird, die in den Speicherzellen 601 bis 610 stehen. Bei jedem OPEN- Befehl wird dort nachgeschaut, ob die Filenummer existiert. Wenn ja, wird die Fehlermeldung FILE OPEN ERROR ausgegeben. Bei jedem CLOSE-Befehl wird die entsprechende Nummer aus der Tabelle gelöscht.

Wir können aber auch eine 0 in die Speicherzelle 152 POKEn, wodurch dem Betriebssystem vorgegaukelt wird, daß keine Datei eröffnet ist. Schieben Sie im Programm einfach die Zeile ein:

45 POKE 152,0

und das Programm läuft ewig weiter.

Die Speicherzelle 152 ist also der Wächter über die Anzahl der eröffneten Dateien. Steht sie auf 0, dann wird eine Neueröffnung am Anfang der Tabelle ab 601 eingetragen. Die Tabelle ihrerseits ist der Wächter über Exklusivität der Dateinummern. Ich zeige Ihnen das noch genauer, wenn wir zu 601 kommen.

Sie werden vielleicht fragen, warum ich das so ausführlich beschreibe. Nun, in einem Programm kann es sicher sehr nützlich sein, dieZelle 152 mit PEEK nach der Datei-Lage abzufragen und entsprechend Maßnahmen zu treffen, ehe die Fehlermeldung das Programm abbricht.

Mit POKE 152,0 aber müssen Sie aufpassen. Es ersetzt nämlich nicht (!!) den CLOSE-Befehl. Probieren Sie es aus: Um das kleine Programm oben per Drucker auszudrucken, brauchen wir:

OPEN 1,4: CMD 1: LIST

Wenn Sie jetzt die Zeile 152 auf 0 POKEn und dann LIST eintippen, wird trotzdem wieder auf dem Drucker gelistet und nicht auf dem Bildschirm. Die vorgeschriebene Schließmethode mit

PRINT #1:CLOSE1

geht jetzt aber auch nicht mehr, denn das Betriebssystem ist ja im Glauben, daß keine Datei eröffnet ist - schöner Schlamassel!

Erst eine Neueröffnung bringt alles wieder in die Reihe. Also Vorsicht mit der Anwendung der Speicherzelle 152. Eine Möglichkeit, alle Dateien auf einen Schlag zu schließen, gibt es aber doch.

SYS 65511 besorgt das sowohl beim C 64 als auch beim VC 20.

Anzahl der offenen Files

In dieser Speicherzelle wird festgehalten, wie viele Files gleichzeitig geöffnet sind.

Number of files currently open

Values: $00-$0A, 0-10.

Index to logical file   No. of Open Files / Index to File Table   Number of Open Files/Index to File Table.   How many open files  
$0099 DFLTN 153
Default Input Device (Set to 0 for Keyboard)

The default value of this location is 0, which designates the keyboard as the current input device. That value can be changed by the Kernal routine CHKIN (61966, $F20E), which uses this location to store the device number of the device whose file it defines as an input channel.

BASIC calls CHKIN whenever the command INPUT# or GET# is executed, but clears the channel after the input operation has been completed.

Nummer des Eingabe-Gerätes

Das Betriebssystem verwendet diese Speicherzelle, um festzuhalten, welches Gerät zur Eingabe verwendet werden soll.

Die Nummern sind wie folgt festgelegt:

0 Tastatur
1 Datasette
2 RS232 (User-)Port
3 Bildschirm
4,5 Drucker
8-11 Floppy-Laufwerke

Nach dem Einschalten oder nach RESET des Computers steht in 153 eine 0 (Tastatur). Nach jedem Einsatz eines anderen Gerätes wird diese Speicherzelle wieder auf 0 gesetzt, so daß wir immer die Tastatur zur Verfügung haben.

Für Maschinenprogrammierer ist diese Adresse sicherlich wertvoll. Die Routine, welche die Eingabegeräte festlegt, sobald der Befehl INPUT# beziehungsweise GET# ausgeführt wird, heißt CHKIN und beginnt beim C 64 ab Adresse 61966 ($F20E), beim VC 20 ab 62151 ($F2C7).

Für Basic-Programmierer habe ich in der Literatur nur eine Anwendung gefunden, und die wurde bereits bei der Besprechung der Speicherzelle 19 angekündigt.

Es ist dies eine MERGE-Routine. Leider funktioniert dieses Verfahren nicht bei dem 1541-Floppy-Laufwerk. Erfunden wurde die Routine von Brad Templeton und ist von Jim Butterfield unter dem Namen »Magic Merge« für den VC 20/

C 64 adaptiert worden. Ich gebe zu, in der Zwischenzeit sind noch andere, vielleicht auch kürzere MERGE-Routinen veröffentlicht worden. Aber diese hier verwendet gleich drei interessante Ingredienzen, nämlich die Speicherzellen 19 und 153 und außerdem die sogenannte »Dynamische Tastenabfrage«. Wer die letztere nicht kennt, sollte sich zum Verständnis den Texteinschub Nr. 15 gleichen Namens ansehen.

Ein MERGE (deutsch: zusammenführen, verschmelzen) besteht darin, ein auf Band gespeichertes Programm zu einem im Computer stehenden anderen Programm so dazuzuladen, daß dieses nicht überschrieben, sondern ergänzt wird. Wichtig ist dabei, daß das Programm vom Band höhere Zeilennummern hat als das Programm im Computer. Außerdem muß das Programm auf dem Band als Datei gespeichert sein. Das wird so erreicht:

  1. Programm eintippen
  2. Direkt eingeben:

    OPEN 1,1,1, "Name*: CMD1:LIST

  3. Erst wenn READY kommt, direkt eingeben PRINT #1:CLOSE1

Damit ist das Programm auf dem Band gespeichert. Nun kommt der eigentliche MERGE-Vorgang.

  1. Es steht ein Programm im Computer
  2. Band mit dem Programm »Name« einlegen
  3. Direkt eingeben:

    POKE 19,1:OPEN 1

  4. Sobald READY erscheint, Bildschirm löschen (SHIFT-CLR).

  5. Dreimal Cursor-Down
  6. Direkt eingeben:

    PRINT CHR$(19):POKE 198,1:POKE 631,13:POKE 153,1

  7. Das Band beendet den Ladevorgang mit einer Fehlermeldung, die wir ignorieren.

  8. Nach CLOSE 1 sind beide Programme zusammengefügt.

Wie gesagt, Schritt 6 verwendet Zeile 19 (bitte dort nachlesen), Schritte 8 und 9 sind die »Dynamische Tastenabfrage«, und Schritt 9 verwendet zusätzlich die hier zur Diskussion stehende Speicherzelle 153, um die Datasette als Eingabegerät zu definieren.

aktives Eingabegerät

In dieser Speicherzelle wird festgehalten, welches Gerät zur Eingabe verwendet werden soll. Die Nummern sind folgendermaßen festgelegt:

0 Tastatur
1 Datasette
2 RS232 und User-Port
3 Bildschirm
4-5 Drucker
8-11 Laufwerke
Current input device number.

Default: $00, keyboard.

Default input device #   Default Input Device (0)   Default Input Device (0).   Input device, normally 0  
$009A DFLTO 154
Default Output (CMD) Device (Set to 3 for the Screen)

The default value of this location is 3, which designates the screen as the current output device. That value can be changed by the Kernal routine CHKOUT (62032, $F250), which uses this location to store the device number of the device whose file it defines as an output channel.

BASIC calls CHKOUT whenever the command PRINT# or CMD is executed, but clears the channel after the PRINT# operation has been completed.

Nummer des Ausgabe-Gerätes

Diese Speicherzelle entspricht der Zelle 153, nur steht hier die Nummer des Gerätes, über das die Ausgabe läuft.

Nach dem Einschalten und nach Ausgabeoperationen wird der Wert immer auf 3 gesetzt. Das ist entsprechend der oben genannten Zuordnung der Bildschirm.

Für Maschinenprogrammierer sei erwähnt, daß Basic bei den Befehlen PRINT# oder CMD die Routine CHKOUT einsetzt, welche die Adresse 154 belegt. Sie steht im C 64 ab Adresse 62032 ($F250), im VC 20 ab 62217 ($F309).

aktives Ausgabegerät

Diese Speicherzelle ist mit der vorherigen zu vergleichen, nur steht hier die Nummer des Geräts, über das die Ausgabe erfolgt.

Current output device number.

Default: $03, screen.

Default output device #   Default Output (CMD) Device (3)   Default Output Device (3).   Output CMD device, normally 3  
$009B PRTY 155
Tape Character Parity

This location is used to help detect when bits of information have been lost during transmission of tape data.

Fehlerkontrolle bei Bandoperationen

Die Commodore-Datasette ist deswegen so zuverlässig, weil sie mehrere Methoden zur Fehlererkennung beziehungsweise Korrektur von Lese- und Schreibfehlern verwendet.

Eine der Methoden ist die sogenannte Parity-Prüfung. Sie ist nichts anderes als eine Quersummenbildung der einzelnen Stellen jedes Bytes, deren Resultat überprüft wird.

Die Speicherzelle 155 wird bei dieser Parity-Prüfung eingesetzt.

Parität für Band

Über diese Speicherzelle findet eine Parity-Prüfung (Quersummenbildung) statt. Dies dient dazu, um Lese- und Schreibfehler zu vermeiden.

Unknown. (Parity bit during datasette input/output.)   Cassette: holds current calculated parity bit   Tape Character Parity   Parity of Byte Output to Tape.   Tape character parity  
$009C DPSW 156
Flag: Tape Byte Received

This location is used as a flag to indicate whether a complete byte of tape data has been received, or whether it has only been partially received.

Flagge für korrektes Byte vom Band

In dieser Speicherzelle wird zwischengespeichert, ob das vom Band gelesene Byte die Prüfungen bestanden hat, also richtig ist oder nicht.

Flag für Byte empfangen

Hier wird festgelegt, ob das gelesene Byte die Quersumme richtig gebildet hat oder nicht.

Unknown. (Byte ready indicator during datasette input/output.)   Cassette: if NZ then expecting LL/L combination that ends a byte   Flag: Tape Byte-Received   Flag: Byte received from Tape.   Byte-received flag  
$009D MSGFLG 157
Flag: Kernal Message Control

This flag is set by the Kernal routine SETMSG (65048, $FE18), and it controls whether or not Kernal error messages or control messages will be displayed.

A value of 192 ($C0) here means that both Kernal error and control messages will be displayed. This will never normally occur when using BASIC, which prefers its own plain text error messages over the Kernal's perfunctory I/O ERROR (number). The Kernal error messages might be used, however, when you are SAVEing or LOADing with a machine language monitor.

A 128 ($80) means that control messages only will be displayed. Such will be the case when you are in the BASIC direct or immediate mode. These messages include SEARCHING, SAVING, FOUND, etc.

A value of 64 means that Kernal error messages only are on. A 0 here suppresses the display of all Kernal messages. This is the value placed here when BASIC enters the program or RUN mode.

Flagge für Meldungen

Man muß zwischen zwei Arten von Meldungen unterscheiden:

Meldungen des Betriebssystems Meldungen des Basic-Übersetzers Die Meldungen des Betriebssystems kennen wir als Angaben zum Ablauf, wie SEARCHING FOR, FOUND, PRESS PLAY ON TAPE und so weiter. Normalerweise nicht bekannt ist die Meldung I/O ERROR #, wobei nach dem Zeichen # Zahlen von 0 bis 29 stehen können. Diese Zahlen beziehen sich auf Meldungen des Übersetzers (Interpreter), die ausschließlich Fehlermeldungen sind. Das mag verwirrend klingen, klärt sich aber sofort. Die Flagge in 157 kann vier Werte annehmen: 0,64,128 und 192.

  1. Der Wert 0 unterdrückt alle Meldungen des Betriebssystems. Dieser Modus tritt nach RUN beim Ablauf eines Programms ein.
  2. Der Wert 64 läßt nur Fehlermeldungen des Betriebssystems zu. Dieser Modus ist normalerweise nicht vorgesehen, kann aber künstlich erzeugt werden.
  3. Der Wert 128 unterdrückt die Fehlermeldung des Betriebssystems. Dieser Modus entspricht dem Normalfall.
  4. Der Wert 192 läßt alle Meldungen zu. Auch dieser Modus ist nur künstlich herzustellen.

Das folgende Beispiel macht das deutlich. Geben Sie direkt ein:

POKE 157,0:LOAD"$",9

Wir versuchen, vom Gerät mit der Nummer 9, das ist eine zweite Floppy, die Directory zu laden. Wir erhalten entsprechend Punkt 1 nur die Meldung des Übersetzers

?DEVICE NOT PRESENT

Verändern wir den POKE-Befehl für Punkt 2:

POKE 157,64:LOAD"$",9

Wir erhalten jetzt

I/O ERROR #5
?DEVICE NOT PRESENT

POKE 157,128:LOAD"$",9

ergibt die Meldung

SEARCHING FOR $
?DEVICE NOT PRESENT

Schließlich nehmen wir noch den letzten Fall:

POKE 157,192: LOAD"$",9

Jetzt erhalten wir alles:

SEARCHING FOR $
I/O ERROR #5
?DEVICE NOT PRESENT

Da die Fehlermeldung des Betriebssystems und die zugehörigen Nummern in keinem Handbuch erwähnt sind, habe ich sie interessehalber in der folgenden Tabelle zusammengefaßt.

# MELDUNG (ERROR)
1 TOO MANY FILES
2 FILE OPEN
3 FILE NOT OPEN
4 FILE NOT FOUND
5 DEVICE NOT PRESENT
6 NOT INPUT FILE
7 NOT OUTPUT FILE
8 MISSING FILE NAME
9 ILLEGAL DEVICE NUMBER
10 NEXT WITHOUT FOR
11 SYNTAX
12 RETURN WITHOUT GOSUB
13 OUT OF DATA
14 ILLEGAL QUANTITY
15 OVERFLOW
16 OUT OF MEMORY
17 UNDEF'D STATEMENT
18 BAD SUBSCRIPT
19 REDIM'D ARRAY
20 DIVISION BY ZERO
21 ILLEGAL DIRECT
22 TYPE MISMATCH
23 STRING TOO LONG
24 FILE DATA
25 FORMULA TOO COMPLEX
26 CAN'T CONTINUE
27 UNDEF'D FUNCTION
28 VERIFY
29 LOAD
Flag für Direktmodus $80, Programm $00

In dieser Speicherzelle wird angegeben, welche Fehlermeldungen zugelassen werden und welche nicht. $00 unterdrückt alle Fehlermeldungen, $80 kommt dem normalen Eingabemodus gleich und $C0 läßt alle Fehlermeldungen zu. Diese Zustände können alle künstlich erzeugt werden.

System error display switch

Bits:

  • Bit #6: 0 = Suppress I/O error messages; 1 = Display them.
  • Bit #7: 0 = Suppress system messages; 1 = Display them.
OS message flag   Flag: $80 = Direct Mode, $00 = Program   Flag: $00 = Program mode: Suppress Error Messages, $40 = Kernal Error Messages only, $80 = Direct mode: Full Error Messages.   Direct = $80/RUN = 0 output control  
$009E-$009F 158-159    
Zwischenspeicher bei Kassettenoperationen

Diese beiden Speicherzellen werden von Routinen des Betriebssystems verwendet, welche bei Kassettenoperationen die Zeichen überprüfen, ob sie richtig sind, und welche bei aufgetretenen Fehlern Korrekturen durchführen.

                       
$009E PTR1 158
Tape Pass 1 Error Log Index

This location is used in setting up an error log of bytes in which transmission parity errors occur the first time that the block is received (each tape block is sent twice to minimize data loss from transmission error).

   
Bandpass 1 Checksumme

Diese Speicherzelle wird zur Überprüfung von Bytes bei Kassettenoperationen benutzt.

Error counter during LOAD from datasette.

Values: $00-$3E, 0-62.

Cassette: count of read locations in error (pointer into bad, max 61)   Tape Pass 1 Error Log   Tape Error log pass 1.   Tp Pass 1 error log/char buffer  
T1             Block header type during datasette input/output.
Length of file name during datasette input/output.
Byte to be put into output buffer during RS232 and datasette output.
 
Temporary 1       Index to Cassette File name/Header ID for Tape write.      
$009F PTR2 159
Tape Pass 2 Error Log Correction Index

This location is used in correcting bytes of tape data which were transmitted incorrectly on the first pass.

   
Bandpass 2 Fehlerkorrektur

Hier werden die Fehler korrigiert, die bei Kassettenoperationen aufgetreten sind.

Error correction counter during LOAD from datasette.

Values: $00-$3E, 0-62.

Cassette: count of re-read locations (pointer into bad, during re-read)   Tape Pass 2 Error Log   Tape Error log pass 2.   Tp Pass 2 err log corrected  
T2             Auxiliary counter for writing file name into datasette buffer.
Auxiliary counter for comparing requested file name with file name read from datasette during datasette input.
 
Temporary 2              
$00A0-$00A2 TIME 160-162
Software Jiffy Clock

These three locations are updated 60 times a second, and serve as a software clock which counts the number of jiffies (sixtieths of a second) that have elapsed since the computer was turned on.

The value of location 162 ($A2) is increased every jiffy (0.1667 second), 161 ($A1) is updated every 256 jiffies (4.2267 seconds), and 160 ($A0) changes every 65536 jiffies (or every 18.2044 minutes). After 24 hours, these locations are set back to 0.

The jiffy clock is used by the BASIC reserved variables TI and TI$. These are not ordinary variables that are stored in the RAM variable area, but are functions that call the Kernal routines RDTIM (63197, $F6DD), and SETTIM (63204, $F6E4). Assigning the value of TI or TI$ to another variable reads these locations, while assigning a given value to TI$ alters these locations.

To illustrate the relationship between these locations and TI$, try the following program. The program sets the jiffy clock to 23 hours, 50 minutes. After the program has been running for one minute, all these locations will be reset to 0.

100 TI$="235900"
110 PRINT TI$,PEEK(160),PEEK(161),PEEK(162)
120 GOTO 110

Since updating is done by the IRQ interrupt that reads the keyboard, anything which affects the operation of that interrupt routine will also interfere with this clock. A typical example is tape I/O operations, which steal the IRQ vector for their own use, and restore it afterwards. Obviously, user routines which redirect the IRQ and do not send it back to the normal routine will upset software clock operation as well.

Interne Uhr für TI und TI$

Das Basic der Commodore-Computer kennt neben der Variablen ST (siehe Speicherzelle 144) noch zwei weitere »reservierte« Variable, nämlich TI und TI$. Beide bieten eine interne Uhr, welche aus dem Inhalt der Speicherzellen 160 bis 162 abgeleitet wird. Diese drei Zellen funktionieren wie der Kilometerzähler eines Autos, halt nur mit drei Stellen.

Die hinterste Stelle ist die Zelle 162. Ihr Inhalt wird beim Einschalten des Computers auf 0 gesetzt, dann aber 60mal in der Sekunde um 1 erhöht. Das erfolgt durch die automatische Interrupt-Routine, welche auch die STOP-Taste abfragt und noch andere Hausaufgaben 60mal in der Sekunde ausführt. Da i60 = 0,01667 ist, zählt also dle Zelle 162 in 0,01667 Sekunden um 1 weiter. Sie kann wie alle Speicherzellen maximal nur die Zahl 255 enthalten, danach kommt wieder eine 0. Das heißt aber, daß sie nach 256 * 0,01667 = 4,267 Sekunden einmal durchgelaufen ist.

Nach jedem Durchlauf wird die davorliegende Speicherzelle 161 um 1 erhöht. Sie zählt also in 4,267 Sekunden um 1 weiter und ist nach 256 * 4.067 = 1 092,26 Sekunden oder besser nach 18,2044 Minuten einmal durchgelaufen. Nach dem Kilometerzähler-Prinzip wird nach jedem Durchlauf von 161 der Inhalt der davorliegenden Zelle 160 um 1 erhöht.

Die Zelle 160 zählt also in 18,2044 Minuten um 1 weiter und ist nach 256 * 18, 2044 = 4660,34 Minuten, das sind 77.67 Stunden, einmal durchgelaufen.

Diese Stundenzahl wird allerdings niemals erreicht, da das Betriebssystem nach Erreichen des Wertes für 24 Stunden alle drei Zellen wieder auf 0 zurücksetzt. Wir werden das gleich nachprüfen.

Zuerst aber wollen wir uns den dreizelligen Zähler anschauen:

10 PRINT PEEK(160);PEEK(161);PEEK(162)
20 GOTO 10

Nach RUN sehen wir den Inhalt der drei Zellen sich entsprechend der oben angegebenen Zeiten verändern. Die Zahlen sind nicht vorherbestimmbar, denn der Zähler ist ja nach dem Einschalten des Computers schon losgelaufen. Er kann aber auf 0 gesetzt werden durch Einfügen der Zeile 5:

5 POKE 160,0:POKE 161,0: POKE 162,0

Jetzt beginnt der Zähler immer ab 0. Ich habe gerade gesagt, daß der Zähler auf 0 gesetzt wird, wenn er 24 Stunden lang gelaufen ist. Der Inhalt in den drei Speicherzellen, der 24 Stunden entspricht, ist nach der oben angegebenen Umrechnungsart 79-26-0. Diesen Wert, oder besser noch ein Wert kurz davor, in die Zellen 160 bis 162 gePOKEt, zeigt uns den Nullsetzvorgang. Ersetzen Sie bitte die obige Zeile 5 durch eine neue Zeile:

5 POKE 160,79:POKE 161,25:POKE 162,0

Nach vier Sekunden Laufzeit schalten alle drei Zellen in der Tat auf 0 zurück.

Die Umsetzung der Zahlen aus 160 bis 162 in die Variablen TI und TI$ sowie deren Wirkungsweise entnehmen Sie bitte dem Texteinschub Nr. 16 »Die eingebaute Uhr«.

Abschließend muß eines noch warnend erwähnt werden. Alle Operationen, welche den Interrupt-Vektor verwenden beziehungsweise verändern, stören oder verzögern die normale Interrupt-Routine, die ja den Zähler weiterstellt. So zählt der Zähler nicht gleichmäßig und die daraus abgeleitete Uhr geht nicht mehr richtig. Ein Beispiel dafür sind alle Ein- und Ausgaben über die Datasette, welche über einen Interrupt laufen.

Time

In diesen Speicherzellen wird die Uhrzeit über die Interruptroutine erhöht.

Value of TI variable, time of day, increased by 1 every 1/60 second (on PAL machines)

Values: $0000-$4F19FF, 0-518399 (on PAL machines).

24 hour clock in 1/60th seconds   Real-Time Jiffy Clock (approx) 1/60 Sec   Real-time jiffy Clock (Updated by IRQ Interrupt approx. every 1/60 of Second); Update Routine: UDTIMK ($F69B).   Jiffy Clock HML  
$00A3-$00A4 163-164
Temporary Data Storage Area

These locations are used temporarily by the tape and serial I/O routines.

Zwischenspeicher

Diese beiden Speicherzellen werden von den Ein- und Ausgabe-Routinen des Betriebssystems für Kassetten, Floppy-Laufwerk und Drucker als Zwischenspeicher für alle möglichen Werte benutzt.

            Temp Data Area          
$00A3 R2D2 163        
Bitzähler für serielle Ausgabe

Dieses Register wird als Zwischenspeicher von Ein-/Ausgaberoutinen benutzt.

EOI switch during serial bus output

Bits:

  • Bit #7: 0 = Send byte right after handshake; 1 = Do EOI delay first.

Bit counter during datasette output.

Serial bus usage       Bit Counter Tape Read or Write/Serial Bus EOI (End Of Input) Flag.   Serial bit count/EOI flag  
PCNTR                 Cassette: counts down from 8-0 for data then to ff for parity              
$00A4 FIRT 164        
Zähler für Band

siehe oben

Byte buffer during serial bus input.
Parity during datasette input/output.
 
        Pulse Counter Tape Read or Write/Serial Bus shift Counter.   Cycle count  
BSOUR1                 Temp used by serial routine              
FIRT                 Cassette: used to indicate which half of dipole we're in              
$00A5 CNTDN 165
Cassette Synchronization Character Countdown

Used to count down the number of synchronization characters that are sent before the actual data in a tape block.

Bit-Zähler für Kassetten-Synchronisierung

Beim Abspeichern eines Programms auf ein Band werden vor den eigentlichen Daten mehrere Bits zusätzlich gespeichert, die beim Einlesen dieses Bandes zur Synchronisierung dienen, das heißt zum Übereinstimmen der Geschwindigkeit der Datenübertragung.

Die Speicherzelle 165 wird als Zähler dieses Synchron-Bits verwendet.

Zähler für Band schreiben

Diese Speicherzelle wird als Zähler des Synchron-Bits verwendet.

Bit counter during serial bus input/output.
Counter for sync mark during datasette output.
 
    Cassette Sync Countdown   Tape Synchronising count down.   Countdown, tape write/bit count  
COUNT                 Temp used by serial routine              
CNTDN                 Cassette sync countdown              
$00A6 BUFPT 166
Count of Characters in Tape I/O Buffer

This location is used to count the number of bytes that have been read in or written to the tape buffer. Since on a tape write, no data is sent until the 192 byte buffer is full, you can force output of the buffer with the statement POKE 166,191.

Zahler der bearbeiteten Bytes im Kassetten-Puffer

Diese Speicherzelle wird als Zähler benutzt, welcher angibt, wieviele Bytes gerade in den Kassetten-Puffer eingeschrieben oder aus ihm ausgelesen worden sind. Der Kassetten-Puffer besteht aus den Speicherzellen 828 bis 1 019 und kann somit 191 Byte aufnehmen, was zugleich die höchste Zahl ist, welche sinnvollerweise in der Zelle 166 stehen kann.

Nähere Erklärungen und ein paar Experimente mit Zelle 166 finden Sie in dem Texteinschub 17 »Experimente mit dem Kassetten-Puffer«.

Die meisten der nächsten 20 Speicherzellen werden bei Operationen mit der RS232-Schnittstelle, die über den User-Port den Computer mit anderen Geräten verbindet, eingesetzt. Da die Programmierung der RS232-Schnittstelle noch andere Speicherzellen benötigt, die später an der Reihe sind, gehe ich auf die RS232-Schnittstelle erst bei der Behandlung der Speicherzelle 659 bis 673 näher ein.

Zeiger in Bandpuffer

Dieses Register wird als Zähler benutzt, welcher angibt, wie viele Bytes aus dem Bandpuffer gelesen oder in den Bandpuffer geschrieben worden sind.

Offset of current byte in datasette buffer.   Cassette buffer pointer   Pointer: Tape I/O Buffer   Pointer: Tape I/O buffer.   Tape buffer pointer  
$00A7-$00AB 167-171        
Arbeitsspeicher für Ein-/Ausgabe

Diese Register werden häufig von Kassettenoperationen und der RS-232 Schnittstelle als Zwischenspeicher benutzt.

                   
$00A7 INBIT 167
RS-232 Input Bits/Cassette Temporary Storage Area

This location is used to temporarily store each bit of serial data that is received, as well as for miscellaneous tasks by tape I/O.

Zwischenspeicher für Kassetten-Operationen und für Eingabe über die RS232-Schnittsteile

Diese Speicherzelle wird verwendet, um jedes Bit, welches von einem RS232-Kanal über den User-Port eingelesen wird, zwischenzuspeichern.

Außerdem verwenden mehrere Kassetten-Routinen diese Adresse als Zwischenspeicher.

    Bit buffer during RS232 input.   RS-232 rcvr input bit storage   RS-232 Input Bits / Cassette Temp   RS232 temporary for received Bit/Tape temporary.   Tp Wrt ldr count/Rd pass/inbit  
SHCNL                 Cassette: holds FSBLK, used to direct routines, because of exit case              
$00A8 BITCI 168
RS-232 Input Bit Count/Cassete Temporary Storage

This location is used to count the number of bits of serial data that has been received. This is necessary so that the serial routines will know when a full word has been received. It is also used as an error flag during tape loads.

Bitzähler für RS232-Eingabe und bei Band-Ein-/Ausgabe

Die Speicherzelle 168 wird als Zähler verwendet, der dies mal nicht die Bytes, sondern die Anzahl der Bits zählt, die sowohl über den User-Port als auch über den Kassetten-Port geleitet werden. Das dient dem Betriebssystem dazu, zu wissen, wann ein volles Wort abgearbeitet worden ist.

    Bit counter during RS232 input.   RS-232 rcvr bit count in   RS-232 Input Bit Count / Cassette Temp   RS232 Input Bit count/Tape temporary.   Tp Wrt new byte/Rd error/inbit cnt  
RER                 Cassette: flags errors (if Z then no error)              
$00A9 RINONE 169
RS-232 Flag: Check for Start Bit

This flag is used when checking for a start bit. A 144 ($90) here indicates that no start bit was received, while a 0 means that a start bit was received.

RS232-Flagge für Startbit-Prüfung

Ein RS232-Datentransfer prüft, ob ein Start-Bit empfangen worden ist. Im positiven Fall steht in Zelle 169 die Zahl 144, im negativen Fall eine 0.

   
Stop bit switch during RS232 input

Values:

  • $00: Data bit.
  • $01-$FF: Stop bit.
RS-232 rcvr flag for start bit check   RS-232 Flag: Check for Start Bit   RS232 Flag: Start Bit check/Tape temporary.   Wrt start bit/Rd bit err/stbit  
REZ                 Cassette: counts zeros (if Z then correct # of dipoles)              
$00AA RIDATA 170
RS-232 Input Byte Buffer/Cassette Temporary Storage

Serial routines use this area to reassemble the bits received into a byte that will be stored in the receiving buffer pointed to by 247 ($F7). Tape routines use this as a flag to help determine whether a received character should be treated as data or as a synchronization character.

RS232-Eingabe- und Zwischenspeicher für Kassetten-Routinen

Bei der Speicherzelle 165 haben wir gesehen, daß ein Band Synchronisationsbits enthält. Die Speicherzelle 170 wird dabei als Flagge benutzt, die angibt, ob ein gelesenes Zeichen Synchronisierungs-Bits oder ein Datenwort darstellt.

Die RS232-Routinen verwenden Zelle 17 0 dagegen als Speicher, in welchem die eingelesenen Bits zu einem Byte zusammengefaßt werden, bevor sie im Eingabepuffer am oberen Ende des Programmspeichers abgelegt werden (siehe auch Speicherzellen 55/56).

    Byte buffer during RS232 input.   RS-232 rcvr byte buffer   RS-232 Input Byte Buffer/Cassette Temp   RS232 Input Byte Buffer/Tape temporary.   Tp Scan; Cnt; Ld; End/byte assy  
RDFLG                
Cassette: holds function mode

MI - waiting for block SYNC VS - in data block reading data NE - waiting for byte SYNC

           
$00AB RIPRTY 171
RS-232 Input Parity/Cassete Leader Counter

This location is used to help detect if data was lost during RS-232 transmission, or if a tape leader is completed.

Quersummenprüfung und Zähler für Band-Header bei RS232- und Kassetten-Operationen

Diese Speicherzelle wird vom Betriebssystem benutzt, um festzustellen, ob während einer RS232-Datenübertragung Bits verloren gingen. Da derartige Prüfungen mit Parity-Bits (Quersummenprüfung) des öfteren erwähnt werden, gebe ich eine kurze Beschreibung des Prüfprinzips im Texteinschub 18 »Fehlererkennung mit Parity-Bits«.

Zusätzlich wird in 171 die Länge des Band-Vorspanns bei seiner Erzeugung gezählt.

    Parity during RS232 input.
Computed block checksum during datasette input.
 
RS-232 rcvr parity storage   RS-232 Input Parity / Cassette Short Cnt   RS232 Input parity/Tape temporary.   Wr lead length/Rd checksum/parity  
SHCNH                 Cassette: short cnt; left over from debugging              
$00AC-$00AD 172-173
Pointer to the Starting Address of a Load/Screen Scrolling

The pointer to the start of the RAM area to be SAVEd or LOADed at 193 ($C1) is copied here. This pointer is used as a working version, to be increased as the data is received or transmitted. At the end of the operation, the initial value is restored here. Screen management routines temporarily use this as a work pointer.

Zeiger auf die Anfangsadresse für Ein-/Ausgabe, Zwischenspeicher für den Bildschirmeditor

In den Speicherzellen 193 und 194 steht ein Zeiger, der auf die Adresse im Programmspeicher zeigt, wo das Programm beginnt beziehungsweise beginnen soll, welches abgespeichert beziehungsweise geladen werden soll.

Dieser Zeiger wird am Anfang einer Lade- oder Abspeicher-Operation in die Zellen 172 und 173 gebracht, wo er während der Operation laufend erhöht wird, bis das Ende des Programms erreicht ist; dann wird er wieder auf seinen ursprünglichen Wert gesetzt.

Der Zeiger dient außerdem noch dem Bildschirmeditor als Zwischenspeicher während des Scrollens (Hochschieben) des Bildschirms und beim Einfügen zusätzlicher Zeilen.

Dieser Zeiger kann sehr nützlich sein, um Programme entweder schon beim SAVEn oder aber erst beim LOADen gezielt auf andere als ursprünglich verwendete Speicherbereiche zu bringen. Dazu sind aber noch einige andere Zellen notwendig, bis hin zu dem schon erwähnten Zeiger in 193 und 194.

Zeiger für Bandpuffer und Scrolling

Diese Speicherzellen dienen in erster Linie als Zeiger auf die Adresse, ab welcher ein Programm geladen oder gespeichert werden soll. Zweitens dienen sie auch als Zwischenspeicher während des Scrollings des Video-RAM und beim Einfügen zusätzlicher Zeilen.

Start address for SAVE to serial bus.
Pointer to current byte during SAVE to serial bus or datasette.
Pointer to line in screen memory to be scrolled during scrolling the screen.
 
    Pointer: Tape Buffer/ Screen Scrolling   Pointer: Tape Buffer/Screen scrolling.   Pointer : tape bufr, scrolling  
$00AC SAL 172                 Cassette: indirect to data storage area              
$00AD SAH 173                                
$00AE-$00AF 174-175
Pointer to Ending Address of Load (End of Program)

This location is set by the Kernal routine SAVE to point to the ending address for SAVE, LOAD, or VERIFY.

Zeiger auf die Endadresse für Ein-/Ausgabe, Zwischenspeicher für den Bildschirmeditor

Dieser Zeiger ist der Zwilling zu 172 und 173, nur zeigt er seinerseits auf die letzte Adresse des zu bewegenden Programms.

Zeiger auf Programmende bei LOAD/SAVE

Ähnlich wie $AC-$AD funktionieren diese beiden Speicherzellen. Sie Zeigen immer auf das Byte, das gerade gelesen oder gespeichert wurde.

Load address read from input file and pointer to current byte during LOAD/VERIFY from serial bus.
End address after LOAD/VERIFY from serial bus or datasette.
End address for SAVE to serial bus or datasette.
Pointer to line in Color RAM to be scrolled during scrolling the screen.
 
    Tape End Addresses/End of Program   Tape End Address/End of Program.   Tape end adds/End of program  
$00AE EAL 174                                
$00AF EAH 175                                
$00B0-$00B1 176-177
Tape Timing

Location 176 ($B0) is used to determine the value of the adjustable timing constant at 146 ($92). Location 199 is also used in the timing of tape reads.

Zeitkonstante

Der Wert in dieser Speicherzelle wird verwendet, um die Zeitkonstante zum Lesen vom Band in der Zelle 146 einzustellen.

Zeitkonstante beim Lesen von Band

Der Wert in den Speicherzellen wird benutzt, um die Zeitkonstante beim Lesen von Band einzustellen.

Unknown.       Tape Timing Constants   Tape timing Constants.   Tape timing constants  
$00B0 CMP0 176                 Cassette: software servo (+/- adjust to time calcs)              
$00B1 TEMP 177                 Cassette: used to hold dipole time during type calculations              
$00B2-$00B3 TAPE1 178-179
Pointer: Start of Tape Buffer

On power-on, this pointer is set to the address of the cassette buffer (828, $033C). This pointer must contain an address greater than or equal to 512 ($0200), or an ILLEGAL DEVICE NUMBER error will be sent when tape I/O is tried.

Zeiger auf den Kassetten-Puffer

Beim Einschalten des Computers werden diese Speicherzellen in Low-/High-Byte- Darstellung auf die Anfangsadresse des Kassetten-Puffers gesetzt. Beim VC 20 und C 64 ist dies die Adresse 828 ($033C).

Durch Verbiegen dieses Zeigers kann der Kassettenpuffer auf beliebige Plätze des Speichers, aber nicht unterhalb der Adresse 512 verschoben werden. Das kann durchaus sinnvoll sein, um im Kassettenpuffer abgelegte Maschinenprogramme vor Überschreiben durch Kassettenoperationen zu schützen.

Zeiger auf Bandpuffer

Diese beiden Speicherzellen zeigen auf den Bandpuffer ($033C)

Pointer to datasette buffer.

Default: $033C, 828.

Address of tape buffer #1y.   Pointer: Start of Tape Buffer   Pointer: Start Address of Tape Buffer ($033C).   Pntr : start of tape buffer  
$00B4 BITTS 180
RS-232 Output Bit Count/Cassette Temporary Storage

RS-232 routines use this to count the number of bits transmitted, and for parity and stop bit manipulation. Tape load routines use this location to flag when they are ready to receive data bytes.

RS232-Bit-Zähler und -Zwischenspeicher für Kassetten-Operationen

Die RS232-Routinen verwenden die Speicherzelle 180, um die Zahl der übertragenen Bits zu zählen, außerdem für Parity-Berechnung (siehe Texteinschub 18) und Stop-Bit-Bearbeitung.

Die Lade-Routinen für Kassettenbetrieb benutzen diese Zelle als Flagge, die angibt, ob der Computer bereit ist, Daten zu übernehmen.

Bitzähler für Band

Hier wird die Anzahl der übertragenden Bits gezählt.

Bit counter and stop bit switch during RS232 output

Bits:

  • Bits #0-#6: Bit count.
  • Bit #7: 0 = Data bit; 1 = Stop bit.

Bit counter during datasette input/output.

RS-232 trns bit count   RS-232 Out Bit Count / Cassette Temp   RS232 Write bit count/Tape Read timing Flag.   l = Tp timer enabled; bit count  
SNSW1                 Cassette: flags if we have byte SYNC (a longlong)              
$00B5 NXTBIT 181
RS-232 Next Bit to Send/Tape EOT Flag

This location is used by the RS-232 routines to hold the next bit to be sent, and by the tape routines to indicate what part of a block the read routine is currently reading.

RS232-Anzeige für nächstes Bit, Flagge für End-of-Tape

Bei RS232-Operationen enthält die Zelle 181 das jeweils nächste Bit, welches übertragen werden soll. Bandoperationen entnehmen dieser Speicherzelle, welcher Block gerade gelesen wird.

nächstes Bit für RS-232

Diese Speicherzelle enthält immer das nächste Bit, das bei RS-232 Operationen übertragen werden soll.

Bit buffer (in bit #2) during RS232 output.   RS-232 trns next bit to be sent   RS-232 Next Bit to Send/ Tape EOT Flag   RS232 Next Bit to send/Tape Read - End of Tape.   Tp EOT/RS232 next bit to send  
DIFF                 Cassette: used to preserve SYNO (outside of bit routines)              
$00B6 RODATA 182
RS-232 Output Byte Buffer

RS-232 routines use this area to disassemble each byte to be sent from the transmission buffer pointed to by 249 ($F9).

Ausgabe-Zwischenspeicher für RS232 und Kassette

Bei Ausgabe von Daten über die RS232-Schnittstelle wird jedes Byte in seine Einzelteile zerlegt, bevor es über den Ausgabepuffer seriell übertragen wird. DerAusgabepufferwird im obersten Teil des Programmspeichers angelegt (siehe auch Speicherzellen 55 und 56); die genaue Anfangsadresse steht in Speicherzelle 248. Auch die Ausgabe von Daten auf die Kassette verwendet Zelle 182 als Ausgabe-Zwischenspeicher.

Puffer für auszugebendes Byte

Dieses Register wird als Ausgabezwischenspeicher benutzt.

Byte buffer during RS232 output.   RS-232 trns byte buffer   RS-232 Out Byte Buffer   RS232 Output Byte Buffer/Tape Read Error Flag.   Read character error/outbyte buf  
PRP                 Cassette: has combined error values from bit routines              
$00B7 FNLEN 183
Length of Current Filename

This location holds the number of characters in the current filename. Disk filenames may have from 1 to 16 characters, while tape filenames range from 0 to 187 characters in length.

If the tape name is longer than 16 characters, the excess will be truncated by the SEARCHING and FOUND messages, but will still be present on the tape. This means that machine language programs meant to run in the cassette buffer may be saved as tape filenames.

A disk file is always referred to be a name, whether full or generic (containing the wildcard characters * or ?). This location will always be greater than 0 if the current file is a disk file. Tape LOAD, SAVE, and VERIFY operations do not require that a name be specified, and this location can therefore contain a 0. If this is the case, the contents of the pointer to the filename at 187 will be irrelevant.

An RS-232 OPEN command may specify a filename of up to four characters. These characters are copied to locations 659-662 ($0293-$0296), and determine baud rate, word length, and parity.

Länge des derzeitigen File-Namens

Die LOAD-, SAVE- und VERIFY-Befehle für Disketten verlangen die Angabe eines Programm- oder Dateinamens, auf Computerdeutsch »File-Name«. Nähere Angaben dazu finden Sie im Texteinschub Nr. 19 »Files - Geräte - Namen - Nummern«.

Auch der OPEN-Befehl kann einen File-Namen haben. Bei Kassettenoperationen kann der File-Name weggelassen werden.

In der Speicherzelle 183 steht während und nach der Verwendung eines der oben genannten Befehle eine Zahl, die angibt, aus wie vielen Zeichen der File-Name besteht.

Bei Disketten sind File-Namen möglich, die aus maximal 16 Zeichen bestehen.

Bei Kassetten dagegen sind Namenslängen von maximal 187 Zeichen erlaubt. Allerdings werden vom Computer auf dem Bildschirm nur 16 Zeichen ausgedruckt (siehe dazu den Texteinschub 20 »Tape-Header«).

Für die Längenangabe in Zelle 183 gilt dabei nur die Anzahl derjenigen Zeichen, die zwischen den Gänsefüßchen stehen.

Diese Zahl kann nach einer Ein-/Ausgabeoperation, auch nach einer ungültigen oder abgebrochenen, durch PEEK (183) ausgelesen werden.

Ein File-Name wird übrigens auch bei einem OPEN-Befehi der RS232-Schnittstelle angegeben. Dieser Name, der bis zu vier Zeichen lang sein kann, wird in die Speicherzellen 659 bis 662 übertragen und gibt dort die Übertragungsrate, Wortlänge und Parity-Prüfung an.

Länge des Filenamens

In dieser Speicherzelle wird angegeben, aus wie vielen Zeichen der Filename besteht.

Length of file name or disk command; first parameter of LOAD, SAVE and VERIFY or fourth parameter of OPEN

Values:

  • $00: No parameter.
  • $01-$FF: Parameter length.
Length current file n str   Length of Current File Name   Number of Characters in Filename.   # characters in file name  
$00B8 LA 184
Current Logical File Number

This location holds the logical file number of the device currently being used. A maximum of five disk files, and ten files in total, may be open at any one time.

File numbers range from 1 to 255 (a 0 is used to indicate system defaults). When printing to a device with a file number greater than 127, an ASCII linefeed character will be sent following each carriage return, which is useful for devices like serial printers that require linefeeds in addition to carriage returns.

The BASIC OPEN command calls the Kernal OPEN routine, which sets the value of this location. In the BASIC statement OPEN 4,8,15, the logical file number corresponds to the first parameter 4.

Nummer der derzeitigen Datei (File)

Hinter jedem OPEN-Befehl steht eine Zahl, die der durch diesen Befehl angefangenen Datei zugeordnet wird. Diese Datei- oder File-Nummer gilt als Referenz für alle anderen Ein- und Ausgabebefehle derselben Datei. Nähere Angaben dazu können Sie dem Texteinschub Nr. 19 »Files - Geräte - Namen - Nummern« entnehmen.

Ein OPEN-Befehl ruft die entsprechende Routine des Betriebssystems auf, welche die File-Nummer in die Speicherzelle 184 schreibt. Von dort kann sie mit PEEK(184) ausgelesen werden. Geben Sie die folgende Zeile direkt ein:

A=30:OPEN A,3:PRINT PEEK(184):CLOSE A

Um verschiedene File-Nummern auszuprobieren, definieren wir sie als Variable A. Nach dem »A« des OPEN-Befehls steht die Zahl 3. Damit wird der Bildschirm angewählt (siehe »Sekundär-Adresse« im schon erwähnten Texteinschub). Das Anwählen des Bildschirms vermeidet eine störende Meldung des Betriebssystems.

Mit RETURN nach der obenstehenden Zeile wird der jeweilige Wert von A als Inhalt der Zelle 184 ausgedruckt.

logische Filenummer

In dieser Speicherzelle wird die logische Filenummer verzeichnet.

Logical number of current file.   Current file logical addr   Current Logical File Number   Current File - Logical File number.   Current logical file  
$00B9 SA 185
Current Secondary Address

This location holds the secondary address of the device currently being used. The range of valid secondary address numbers is 0 through 31 for serial devices, and 0 through 127 for other devices.

Secondary device numbers mean something different to each device that they are used with. The keyboard and screen devices ignore the secondary address completely. But any device which can have more than one file open at the same time, such as the disk drive, distinguishes between these files by using the secondary address when opening a disk file. Secondary address numbers 0, 1, and 15-31 have a special significance to the disk drive, and therefore device numbers 2-14 only should be used as secondary addresses when opening a disk file.

OPENing a disk file with a secondary address of 15 enables the user to communicate with the Disk Operating System through that channel. A LOAD command which specifies a secondary address of 0 (for example, LOAD "AT BASIC",8,0) results in the program being loaded not to the address specified on the file as the starting address, but rather to the address pointed to by the start of BASIC pointer (43, $2B).

A LOAD with a secondary address of 1 (for example, LOAD "HERE",8,1) results in the contents of the file being loaded to the address specified in the file. A disk file that has been LOADed using a secondary address of 1 can be successfully SAVEd in the same manner (SAVE "DOS 5.1",8,1).

LOADs and SAVEs that do not specify a secondary address will default to a secondary address of 0.

When OPENing a Datasette recorder file, a secondary address of 0 signifies that the file will be read, while a secondary address of 1 signifies that the file will be written to. A value of 2 can be added to indicate that an End of Tape marker should be written as well. This marker tells the Datasette not to search past it for any more files on the tape, though more files can be written to the tape if desired.

As with the disk drive, the LOAD and SAVE commands use secondary addresses of 0 and 1 respectively to indicate whether the operation should be relocating or nonrelocating.

When the 1515 or 1525 Printer is opened with a secondary address of 7, the uppercase/lowercase character set is used. If it is openend with a secondary address of 0, or without a secondary address, the uppercase/graphics character set will be used.

Derzeitige Sekundär-Adresse

Die Sekundär-Adresse steht als dritte Angabe hinter den Ein- und Ausgabe- Befehlen LOAD, SAVE, VERIFY und OPEN. Sie hat bei den verschiedenen Peripheriegeräten spezielle Funktionen. Diese Funktionen sind im Texteinschub 19 näher erläutert.

Der jeweilige Wert der Sekundär-Adresse steht in der Speicherzelle 185, allerdings um 96 erhöht. Für Sekundär-Adressen stehen, über die Standardwerte der einzelnen Peripheriegeräte hinaus, die Zahlen von 0 bis 31 zur Verfügung. Ab 32 fängt in Zelle 185 wieder der Zyklus ab 0 an. Das können wir uns anschauen. Ich wähle zur Eröffnung einer Datei wieder den Bildschirm als »nicht-störendes« Empfangsgerät.

A=15:0PEN 1,3,A:PRINT PEEK(185)-96:CLOSE 1

Durch Verändern des Wertes von A können Sie alle Möglichkeiten durchspielen.

Sekundäradresse

Hier steht die jeweilige Sekundäradresse.

Secondary address of current file.   Current file 2nd addr   Current Secondary Address   Current File - Secondary Address.   Current secndy address  
$00BA FA 186
Current Device Number

This location holds the number of the device that is currently being used. Device number assignments are as follows:

0 Keyboard
1 Datasette Recorder
2 RS-232/User Port
3 Screen
4-5 Printer
8-11 Disk
Derzeitige Geräte-Nummer

Jedes an den Computer anschließbare Gerät hat eine eigene Nummer, die zusammen mit den Ein-/Ausgabe-Befehlen LOAD, SAVE, VERIFY und OPEN angegeben werden muß. Wird keine Nummer angegeben, nimmt der Computer automatisch an, daß die Datasette gemeint ist.

Alle von Commodore vorgegebenen Geräte-Nummern sind in der folgenden Tabelle 5 aufgelistet.

Geräte-Nummer angesprochenes Gerät
0 Tastatur
1 Datasette
2 RS232- (User-Port) Schnittstelle
3 Bildschirm
4 Drucker (normal)
5 Drucker (zusätzlich)
8 Disketten-Laufwerk Nr. 0
9 Disketten-Laufwerk Nr. 1
10, 11 weitere Disketten-Laufwerke

Tabelle 5. Von Commodore vorgegebene Geräte-Nummern

Die normale Geräte-Nummer eines Druckers ist 4, die eines Disketten-Laufwerks 8. Die zusätzlichen Nummern müssen gesondert am betreffenden Gerät eingestellt werden.

Nach der Ausführung eines der oben genannten Befehle steht die entsprechende Geräte-Nummer in der Speicherzelle 186, aus der sie mit PEEK(186) ausgelesen werden kann.

Gerätenummer

Entsprechend ist auch in dieser Speicherzelle die Gerätenummer zu finden.

Device number of current file.   Current file primary addr   Current Device Number   Current File - First Address (Device number).
OPEN LA,FA,SA; OPEN 1,8,15,"I0":CLOSE 1
 
Current device  
$00BB-$00BC FNADR 187-188
Pointer: Current Filename

This location holds a pointer to the address of the current filename. If an operation which OPENs a tape file does not specify a filename, this pointer is not used.

When a disk filename contains a shifted space character, the remainder of the name will appear outside the quotes in the directory, and may be used for comments. For example, if you SAVE "ML[shifted space]SYS828", the directory entry will read "ML"SYS 828. You may reference the program either by the portion of the name that appears within quotes, or by the full name, including the shifted space. A program appearing later in the directory as "ML"SYS 900 would not be found just by reference to "ML", however.

A filename of up to four characters may be used when opening the RS-232 device. These four characters will be copied to 659-662 ($0293-$0296), where they are used to control such parameters as baud rate, parity, and word length.

Zeiger auf Adresse des derzeitigen File-Namens

Die Bedeutung eines Programm- oder Dateinamens - normalerweise kurz »File-Name« genannt - ist im Texteinschub Nr. 19 »File - Geräte - Namen - Nummern« näher beschrieben. In den Speicherzellen 187 und 188 steht in der Low-/High-Byte- Darstellung ein Zeiger auf diejenige Adresse im Programm-Speicher, wo dieser Name gespeichert ist.

Eine Ausnahme ist hier der OPEN-Befehl der RS232-Schnittstelle. Ihr File-Name wird in die Speicherzellen 659 bis 662 gebracht, wo er verschiedene Parameter dieser Schnittstelle steuert.

Zeiger auf Filenamen

In diesen Speicherzellen steht ein Zeiger, der in LOW- und HIGH-Byte- Darstellung auf den Filenamen zeigt.

Pointer to current file name or disk command; first parameter of LOAD, SAVE and VERIFY or fourth parameter of OPEN.   Addr current file name str   Pointer: Current File Name   Pointer: Current File name Address.   Pointer to file name  
$00BD ROPRTY 189
RS-232 Output Parity/Cassette Temporary Storage

This location is used by the RS-232 routines as an output parity work byte, and by the tape as temporary storage for the current character being read or sent.

Zwischenspeicher für RS232-Parity-Prüfung und für Kassettenoperationen

Die RS232-Routinen benutzen diese Speicherzellen als Zwischenspeicher für ein Prüf-Byte (Parity-Prüfung) bei der Ausgabe. Die Parity-Prüfung habe ich kurz im Texteinschub Nr. 18 erklärt.

Auch die Kassetten-Routinen bedienen sich dieser Speicherzelle. Sie verwenden sie als Zwischenspeicher für das gerade gesendete oder empfangene Zeichen.

Arbeitsspeicher serielle Ein-/Ausgabe

Hier wird von den RS-232-Routinen ein Prüfbyte abgelegt (Parity-Prüfung).

Parity during RS232 output.
Byte buffer during datasette input/output.
 
RS-232 trns parity buffer   RS-232 Out Parity / Cassette Temp   RS232 Output Parity/Tape Byte to be Input or Output.   Wr shift word/Rd input char  
OCHAR                                
$00BE FSBLK 190
Cassette Read/Write Block Count

Used by the tape routines to count the number of copies of a data block remaining to be read or written.

Blockzähler für Kassetten-Ein-/Ausgabe

Das Betriebssystem des Computers schreibt bei SAVE ein Programm zweimal auf das Band der Datasette. Beim LOAD-Befehl wird der erste Block in den Arbeitsspeicher des Computers geladen; der zweite - identische - Block wird dann mit dem ersten Block Byte für Byte verglichen, um Datenfehler auf dem nicht immer ganz zuverlässigen Bandmaterial zu erkennen.

In derSpeicherzelle 190 wird dem Betriebssystem angezeigt, wie viele Blockteile bei diesem Prozeß noch gelesen oder gespeichert werden müssen. Vom Basic- Programm aus ist diese Speicherzelle nicht zugänglich.

Passzähler für Band

In dieser Speicherzelle ist angegeben, wie viele Blockteile von Band gelesen oder auf Band geschrieben werden sollen.

Block counter during datasette input/output.   Cassette: indicate which block we're looking at (0 to exit)   Cassette Read / Write Block Count   Tape Input/Output Block count.   # blocks remaining to Wr/Rd  
$00BF MYCH 191
Tape Input Byte Buffer

This is used by the tape routines as a work area in which incoming characters area assembled.

Zwischenspeicher für LOAD-Operationen vom Band

Diese Speicherzelle wird beim Laden eines Programms vom Band dazu benutzt, um Zeichen aus einzelnen Bits zusammenzusetzen.

Puffer für serielle Ausgabe

Beim Laden eines Programms von Band wird diese Speicherzelle dazu benutzt, um die einzelnen Bits zu einem Byte zusammenzusetzen.

Unknown.   Cassette: holds input byte being built   Serial Word Buffer   Serial Word Buffer.   Serial word buffer  
$00C0 CAS1 192
Tape Motor Interlock

This location is maintained by the IRQ interrupt routine that scans the keyboard. Whenever a button is pressed on the recorder, this location is checked. If it contains a 0, the motor is turned on by setting Bit 5 of location 1 to 0. When the button is let up, the tape motor is turned off, and this location is set to 0.

Since the interrupt routine is executed 60 times per second, you will not be able to keep the motor bit set to keep the motor on if no buttons are pushed. Likewise, if you try to turn the motor off when a button is pressed and this location is set to 0, the interrupt routine will turn it back on.

To control the motor via software, you must set this location to a nonzero value after one of the buttons on the recorder has been pressed.

Motorsperre der Datasette

Die Tasten der Datasette werden 60mal in der Sekunde von der »Interrupt- Routine« des Betriebssystem überprüft, ob eine von ihnen gedrückt worden ist. Die Speicherzelle 192 spielt dabei eine entscheidende Rolle, beim C 64 allerdings in einer anderen Weise als beim VC 20. Wie sie diese Rolle beim C 64 spielt, ist im Zusammenhang mit der Speicherstelle 1 ganz am Anfang dieses Kurses beschrieben worden. Ich habe dabei in zwei Beispielen gezeigt, wie durch Abfrage des vierten Bits von Adresse 1 geprüft werden kann, ob eine Taste der Datasette gedrückt ist und wie der Motor durch Setzen und Löschen des Bit 5 der Zelle 1 ein- und ausgeschaltet werden kann. Vorausgesetzt, der Inhalt der Speicherzelle 192 ist ungleich Null und eine Taste der Datasette ist gedrückt.

Nun will ich, wie versprochen, denselben Vorgang für den VC 20 beschreiben.

Wie Sie sich vielleicht noch erinnern, wird die Speicherzelle 1 beim VC 20 nicht für die Steuerung der Ein- und Ausgänge des Mikroprozessors verwendet. Diese Rolle wird beim VC 20 durch zwei Register des »Versatile Interface Adapter« (VIA 6522-A) ausgefüllt.

Für die Abfrage der Datasetten-Tasten ist das sechste Bit des VIA-Registers 37151 zuständig. Bei gedrückter Taste steht es auf 1, sonst auf 0. Ein kleines Programm zeigt es Ihnen:

10 X = PEEK(37151)
20 PRINT X
30 IF X = 62 THEN 50
40 GOTO 10
50 PRINT"TASTE GEDRÜCKT"

Wenn keine Taste gedrückt ist, läuft ein Zahlenband mit 126 ab. Die entsprechende Darstellung als Dualzahl lautet 1111 1110. Bei einer gedrückten Taste steht in 37151 die Zahl 62, als Dualzahl 0011 1110. Wichtig, wie gesagt ist nur das zweithöchste Bit.

Mit der Abfrage der Zeile 30 springt beim Drücken einer Taste das Programm auf die Zeile 50 und druckt den Text aus.

Den Motor der Datasette können wir mit Hilfe des Registers 37184 schalten. Wie beim C 64 gilt auch jetzt, daß dazu die hier angesprochene Speicherzelle 192, auch Interlock-Register genannt, eine Zahl größer als 0 enthält und daß außerdem eine Taste der Datasette gedrückt ist. Drücken Sie auf PLAY und geben Sie direkt ein:

POKE 192,255
POKE 37148,251: DER MOTOR BLEIBT STEHEN.
POKE 37148,252: DER MOTOR LÄUFT LOS.

Bestimmend sind hier Bit 2, 3 und 4.

Zum Ausschalten muß lediglich Bit 2 auf 1 stehen, zum Einschalten die drei Bits auf 110. Jede Zahl, die als Dualzahl diese Bedingungen erfüllt, kann dafür hergenommen werden. Um unabhängig von den anderen Bits des Registers 37148 zu bleiben, die ja auch ganz bestimmte andere Funktionen haben, empfiehlt es sich, über Boole’sche Verknüpfungen nur die wichtigen drei Bits zu verändern. Die beiden POKE-Befehle sehen dann so aus:

Ausschalten:

POKE 37148,PEEK(37148) OR 2

Einschalten:

POKE 37148,PEEK(37148) AND 12
Flag für Bandmotor

Der Motor der Datasette kann nur eingeschaltet werden, wenn die Speicherzelle ungleich Null ist.

Datasette motor switch

Values:

  • $00: No button was pressed, motor has been switched off. If a button is pressed on the datasette, must switch motor on.
  • $01-$FF: Motor is on.
Cassette manual/controlled switch   Tape Motor Interlock   Tape Motor Switch.   Tape motor interlock  
$00C1-$00C2 STAL 193-194
I/O Start Address

This location points to the beginning address of the area in RAM which is currently being LOADed or SAVEd. For tape I/O, it will point to the cassette buffer, and the rest of the data is LOADed or SAVEd directly to or from RAM. This location points to the beginning address of the area of RAM to be used for the blocks of data that come after the initial header.

Anfangsadresse für Ein-/Ausgabe-Operationen

In diesen Speicherzellen steht in Low-/High-Byte-Darstellung die Adresse, ab der ein Programm gerade geladen oder gespeichert wird. Diese Adresse wird übrigens von hier auch in die Speicherzellen 172 und 173gebracht, die wir schon früher besprochen haben.

Bei LOAD und SAVE auf Band steht hier die Anfangsadresse des Bandpuffers (828). Im Bandpuffer steht allerdings nur der sogenannte Bandvorspann (auf englisch »Tape Header«), während der Hauptteil des Programms im Programmspeicher ab einer Adresse steht, auf die der Zeiger in den Speicherzellen 195 und 196 hinweist.

Startadresse für Ein-/Ausgabe

In diesen Registern ist in LOW- und HIGH-Byte-Darstellung angegeben, ab welcher Adresse ein Programm geladen oder gespeichert wird.

Start address during SAVE to serial bus, LOAD and VERIFY from datasette and SAVE to datasette.
Pointer to current byte during memory test.
 
    I/O Start Address   Start Address for LOAD and Cassette Write.   I/O start address  
$00C1 TMP0 193                                
STAL                                
$00C2 STAH 194                                
$00C3-$00C4 MEMUSS 195-196    
Zeiger auf den Anfang des Programms hinter dem Tape Header

Bei jedem LOAD- und SAVE-Befehl für Kassetten wird der Vorspann (Tape Header), in dem Programmtyp, Anfangs- und Endadresse aufgezeichnet sind, im Kassettenpuffer ab Adresse 828 gespeichert. Der eigentliche Teil des Programms steht dann im Programmspeicher.

In den Speicherzellen 195 und 196 steht in der Low-/High-Byte-Darstellung diese Adresse, ab der das Programm beginnt. Ich habe für alle diejenigen, die mit der Datasette arbeiten, im Texteinschub Nr. 20 »Tape-Header« die Zusammenhänge mit einem Beispiel dargestellt.

Endadresse für Ein-/Ausgabe

Hier steht in LOU- und HIGH-Byte der Zeiger auf den Tape-Header im Bandpuffer.

Start address for a secondary address of 0 for LOAD and VERIFY from serial bus or datasette.
Pointer to ROM table of default vectors during initialization of I/O vectors.
 
Cassette load temps (2 bytes)   Tape Load Temps   Pointer: Type 3 Tape LOAD and general use.   Kernel setup pointer  
TMP2                                
$00C5 LSTX 197
Matrix Coordinate of Last Key Pressed, 64=None Pressed

During every normal IRQ interrput this location is set with the value of the last keypress, to be used in keyboard debouncing. The Operating System can check if the current keypress is the same as the last one, and will not repeat the character if it is.

The value returned here is based on the keyboard matrix values as set forth in the explanation of location 56320 ($DC00). The values returned for each key pressed are shown at the entry for location 203 ($CB).

Tasten-Code der zuletzt gedrückten Taste

Bei der Behandlung der Speicherzelle 145 habe ich Ihnen mit Wort und Bild beschrieben, wie die Tasten des Computers abgefragt werden. Die dabei für jede Taste entstehende Dualzahl wird in eine Dezimalzahl (0 bis 63) umgewandelt und zuerst in die Speicherzellen 203 beziehungsweise 653 gebracht. Zur Umwandlung und Abfrage der Zellen 203 und 653 bringe ich bei diesen Speicherzellen mehr Details. Nach der Prüfung, welche Taste gedrückt worden ist, wird die Codezahl von 203 in die Speicherzelle 197 gebracht und dort »aufgehoben«. Diese vermeintliche Verdoppelung wird vom Betriebssystem dafür gebraucht, um zu erkennen, ob die nächste gedrückte Taste mit der vorhergehenden identisch ist. Ist sie identisch, dann entscheidet der Inhalt der Speicherzelle 650, ob das Zeichen dieser Taste mehrfach ausgedruckt wird. In 650 steht die sogenannte Wiederholfunktion. Aber ich will nicht vorgreifen. Die Codezahlen der einzelnen Tasten werde ich bei der Besprechung der Zelle 203 auflisten.

Nummer der gedrückten Taste

Hier wird die Nummer der gedrückten Taste gespeichert (64= keine Taste).

Matrix code of key previously pressed

Values:

  • $00-$3F: Keyboard matrix code.
  • $40: No key was pressed at the time of previous check.
Key scan index   Current Key Pressed: CHR$(n) 0 = No Key   Matrix value of last Key pressed; No Key = $40.   Last key pressed  
$00C6 NDX 198
Number of Characters in Keyboard Buffer (Queue)

The value here indicates the number of charracters waiting in the keyboard buffer at 631 ($0277). The maximum number of characters in the keyboard buffer at any one time is determined by the value in location 649 ($0289), which defaults to 10.

If INPUT or GET is executed while there are already characters in the buffer, those characters will be read as part of the data stream. You can prevent this by POKEing a 0 to this location before those operations, which will always cause any character in the buffer to be ignored. This technique can be handy when using the joystick in Controller Port #1, which sometimes causes fake keypresses to be registered, placing unwanted characters in the keyboard buffer.

Not only is this location handy for taking unwanted characters out of the keyboard buffer, but it can also be used to put desired characters into the buffer, and thus to program the keyboard buffer. This technique (dynamic keyboard) allows you to simulate keyboard input in direct mode from a program.

The dynamic keyboard technique is an extremely useful one, as it enables you to add, delete, or modify program lines while the program is running. The basic scheme is to POKE the PETASCII character values that you wish to be printed (including cursor control characters and carriage returns) into the buffer. Then, when an END statement is executed, the characters in the buffer will be printed, and entered by the carriage return.

This technique can help with the problem of trying to use data separation and terminator characters with INPUT statements. If you try to INPUT a string that has a comma or colon, the INPUT will read only up to that character and issue an EXTRA IGNORED error message. You can avoid this by entering the input string in quotes, but this places on the user the burder of remembering the quote marks. One solution is to use the statements:

POKE 198,3:POKE 631,34: POKE 632,34: POKE 633,20

before the input. This will force two quote marks and a delete into the buffer. The first quote mark allows the comma or colon to be INPUT, the second is used to get the editor out of quote mode, and the delete removes that second quote.

For more specific information and programming examples, see the description of location 631 ($0277), the keyboard buffer.

Anzahl der Zeichen im Tastaturpuffer

Die Funktion des Tastaturpuffers, zu dem wir bei den Speicherzellen 631 und 640 noch kommen werden, habe ich bereits in diesem Kurs, und zwar im Texteinschub Nr. 15 »Dynamische Tastenabfrage« erklärt. Dabei habe ich damals schon sozusagen im Vorgriff die Zelle 198 verwendet.

In dieser Speicherzelle steht die jeweilige Anzahl der Zeichen, die im Tastaturpuffer gespeichert sind und darauf warten, weiterverarbeitet zu werden.

Das folgende kleine Programm zeigt es.

10 GET A$
20 PRINT PEEK (198);A$
30 FOR J=1 3000:NEXT J
40 GOTO 10

Der GET-Befehl holt ein Zeichen aus dem Tastaturpuffer - sofern eines dort zu finden ist. Die Zeile 20 druckt die Anzahl derZeichen im Pufferaus, daneben das erste dieser Zeichen. Dann folgt eine Warteschleife, die uns erlaubt, ganz schnell ein paarTasten zu drücken. Danach springt das Programm an den Anfang zurück und arbeitet diese eingegebenen Zeichen ab. Es ist dabei deutlich zu sehen, wie durch den GET-Befehl bereits ein Zeichen aus dem Puffer genommen und dadurch der Inhalt der Zelle 198 sofort um 1 reduziert wird.

Der Inhalt der Speicherzelle 198 kann mit POKE auch verändert werden.

Eine sinnvolle Anwendung dieser Beeinflussung erlaubt der nicht gerade sehr populäre WAIT-Befehl.

Ersetzen Sie bitte im obigen Programm die Warteschleife der Zeile 30 durch:

30 POKE 198,0: WAIT 198,1

Zuerst wird dem Computer vorgegaukelt, daß der Tastaturpuffer leer sei. Durch den WAIT-Befehl wartet das Programm danach so iange, bis ein Zeichen im Tastaturpuffer erscheint und springt erst dann auf die nächste Zeile 40.

Wenn Sie nach dem WAIT-Befehl statt der 1 eine 2 eingeben, wartet diese Zeile entsprechend auf zwei Tasteneingaben. Allerdings wird in der Zeile 20 dann nur jedes zweite Zeichen ausgedruckt.

Anzahl der gedrückten Tasten

Hier steht die jeweilige Anzahl der Zeichen, die im Tastaturpuffer gespeichert sind.

Length of keyboard buffer

Values:

  • $00, 0: Buffer is empty.
  • $01-$0A, 1-10: Buffer length.
Index to keyboard q   No. of Chars. in Keyboard Buffer (Queue)   Number of Characters in Keyboard Buffer queue.   # chars in keybd buffer  
$00C7 RVS 199
Flag: Print Reverse Characters? 0=No

When the [CTRL][RVS-ON] characters are printer (CHR$(18)), this flag is set to 18 ($12), and the print routines will add 128 ($80) to the screen code of each character which is printed, so that the caracter will appear on the screen with its colors reversed.

POKEing this location directly with a nonzero number will achieve the same results. You should remember, however, that the contents of this location are returned to 0 not only upon entry of a [CTRL][RVS-OFF] character (CHR$(146)), but also at every carriage return. When this happens, characters printed thereafter appear with the normal comination of colors.

Flagge für reverse Darstellung der Zeichen

Normalerweise steht in dieser Speicherzelle eine 0, was mit PRINT PEEK(199) leicht nach geprüft werden kann.

Sobald in der Zelle 199 eine andere Zahl als 0 steht, werden alle Zeichen in der reversen Darstellung gedruckt. Das Betriebssystem des Computers erhöht nämlich in diesem Fall den jeweiligen Bildschirmcode der Zeichen um 128. Ein Blick in eine Tabelle der Biidschirmcodes bestätigt, daß die Codes aller reversen Zeichen um genau 128 höher sind als die der normalen Zeichen.

Den reversen Modus können wir bekanntlich direkt mit der Kombination der CTRL- und der RVS-ON-Taste oder aber mit PRINT CHR$(18) herstellen. Wenn Sie aber versuchen sollten, das direkt einzugeben, um dann wieder mit PRINT PEEK(199) nachzuschauen, was jetzt in der Speicherzelle 199 steht, dann werden Sie Schiffbruch erleiden. Das Betriebssystem setzt den Inhalt der Zelle 199 nach einem »Wagenrücklauf«, hervorgerufen zum Beispiel durch die RETURN-Taste oder nach einem PRINT-Befehl, der nicht mit einem Komma oder Semikolon abgeschlossen ist, sogleich auf 0 zurück. Natürlich erfolgt das auch durch Drücken der CTRL- und RVS-OFF-Taste.

Wir vermeiden die Rücksetzung durch einen Einzeiler:

PRINT CHR$(18) "AAA" PEEK(199)

Wir erhalten drei reverse As und als Inhalt der Zelle 199auch die Zahl 18. Dasselbe Ergebnis erhalten wir durch POKEn einer Zahl größer als 0 in die Zelle 199:

POKE 199,4: PRINT"XX" PEEK(199)

Das Ergebnis beweist, daß diese Adresse sehr nützlich sein kann, zumal ihre Abfrage beziehungsweise Beeinflussung auch innerhalb eines Programms erfolgen kann.

Flag für RVS-Modus

Diese Speicherzelle gibt an, ob die auszugebenden Zeichen revers oder normal dargestellt werden sollen (0= normal, 1= revers).

Reverse mode switch

Values:

  • $00: Normal mode.
  • $12: Reverse mode.
RVS field on flag   Flag: Reverse Chars. - 1=Yes, 0=No Used   Flag: Reverse On/Off; On = $01, Off = $00.   Screen reverse flag  
$00C8 INDX 200
Pointer: End of Logical Line for Input

This pointer indicates the column number of the last nonblank character on the logical line that is to be input. Since a logical line can be up to 80 characters long, this number can range from 0-79.

Zeiger auf das Ende der eingegebenen logischen Zelle

Eine echte Zeile faßt beim C 64 maximal 40 Zeichen, beim VC 20 nur 22.

Eine Zeile mit Anweisungen darf beim C 64 insgesamt 80 Zeichen, beim VC 20 sogar 88 Zeichen enthalten. Diese »verlängerte« Programmzeile nennt man »logische Zeile«.

Der Zeiger in Speicherzelle 200 gibt dem Betriebssystem an, auf welcher Position das letzte Zeichen einer eingegebenen logischen Zeile sitzt. Löschen Sie den Bildschirm und geben Sie direkt irgendwo auf dem Bildschirm den Befehl ein:

PRINT PEEK(200)

Sie erhalten die Zahl der Spalte des letzten Zeichens dieses Direkt-Befehls.

Zeilenende für Eingabe

Dieses Register enthält die Position des letzen Zeichens in einer Zeile.

Length of line minus 1 during screen input. Values: $27, 39; $4F, 79.       Pointer: End of Logical Line for INPUT   Pointer: End of Line for Input (Used to suppress trailing spaces).   End-of-line for input pointer  
$00C9-$00CA 201-202
Cursor X,Y Position at Start of Input

These locations keep track of the logical line that the cursor is on, and its column position on that logical line (in line, column format).

Each logical line may contain one or two 40-column physical lines. Thus there may be as many as 25 logical lines, or as few as 13 at any one time. Therefore, the logical line number might be anywhere from 1-25. Depending on the length of the logical line, the cursor column may be from 1-40 or 1-80.

For a more detailed exaplanation of logical lines, see the description of the screen line link talbe, 217 ($D9).

Zeiger auf Zeilen- und Spaltenposition des letzten Zeichens einer Zeile

Diese beiden Speicherzellen werden bei GET und INPUT verwendet, um die Zeile und Spalte des letzten Zeichens einer eingegebenen Zeile festzustellen. Die Spalten (in Zelle 201 angegeben) zählen von 1 bis 40 (1 bis 22 beim VC 20). Die Zeilen (in Zelle 202 enthalten) zählen dagegen in Paaren von 0 bis 12, identisch mit der bei Zelle 200 erläuterten »logischen« Zweierzeile. Da dies nicht ganz einsichtig ist, gebe ich einen Bildschirmausschnitt wieder (Bild 20), der den Sachverhalt verdeutlichen soll.

Der erste Direktbefehl steht in der zweiten Zeile, das letzte Zeichen in der Spalte 30. Der zweite Befehl steht in der ersten Sechserzeile. Das heißt also, daß die Zeilenangabe dieselbe ist, egal, um welchen Teil der logischen Zeile es sich handelt. Das können Sie leicht nachprüfen, indem Sie den ersten Direktbefehl eine Zeile höher schreiben. Das Resultat ist dasselbe.

Die Unterscheidung, um welche der beiden Zeilenteile es sich handelt, wird in den Speicherzellen 217 bis 242 getroffen.

Beim VC 20 sieht der Bildschirmausdruck etwas anders aus (Bild 21), auch die Befehlseingabe habe ich der Zeilenlänge wegen verändert. Interessant ist beim VC 20 allerdings, daß.dort trotz der Länge der logischen Zeile auch nur Zeilenpaare verwendet werden, deren Länge natürlich auf 22 Spalten reduziert ist.

            Cursor X-Y Pos. at Start of INPUT   Cursor X/Y (Line/Column) position at start of Input.   Input cursor log (row, column)  
$00C9 LSXP 201        
Cursorzeile für Eingabe

Diese Speicherzelle dient dazu, um die Zeile des letzten eingegebenen Zeichens festzustellen.

Cursor row during screen input. Values: $00-$18, 0-24.   X pos at start              
$00CA LSTP 202        
Cursorspalte für Eingabe

Diese Speicherzelle dient dazu, um die Spalte des letzten eingegebenen Zeichens festzustellen.

Cursor column during screen input. Values: $00-$27, 0-39.                  
$00CB SFDX 203
Matrix Coordinate of Current Key Pressed

The keyscan interrupt routine uses this location to indicate which key is currently being pressed. The value here is then used as an index into the appropriate keyboard table to determine which character to print when a key is struck.

The correspondence between the key pressed and the number stored here is as follows:

0 INST/DEL
1 RETURN
2 CRSR RIGHT
3 F7
4 F1
5 F3
6 F5
7 CRSR DOWN
8 3
9 W
10 A
11 4
12 Z
13 S
14 E
15 NOT USED (WOULD BE LEFT SHIFT)
16 5
17 R
18 D
19 6
20 C
21 F
22 T
23 X
24 7
25 Y
26 G
27 8
28 B
29 H
30 U
31 V
32 9
33 I
34 J
35 0
36 M
37 K
38 O
39 N
40 +
41 P
42 L
43 -
44 .
45 :
46 @
47 ,
48 LIRA (BRITISH POUND SIGN)
49 *
50 ;
51 CLR/HOME
52 NOT USED (WOULD BE RIGHT SHIFT)
53 =
54 UP ARROW (EXPONENTATION SIGN)
55 /
56 1
57 LEFT ARROW
58 NOT USED (WOULD BE CTRL)
59 2
60 SPACE BAR
61 NOT USED (WOULD BE COMMODORE LOGO)
62 Q
63 RUN/STOP
64 NO KEY PRESSED

The RESTORE key is not accounted for, because it is not part of the normal keyboard matrix. Instead, it is connected directly to the microprocessor NMI line, and causes an NMI interrupt whenever it is pressed.

Tastencode der gerade gedrückten Taste

Bei der Speicherzelle 145 habe ich beschrieben, wie die Tasten des Computers abgefragt werden. Die dabei für jede der 64 Tasten (mit Ausnahme der RESTORE- und der SHIFT-LOCK-Tasten) entstehende Dualzahl wird in eine Dezimalzahl (0 bis 63) umgewandelt und in der Speicherzelle 203 gespeichert, einige auch in der Zelle 653. Diese Zahl steht auch in Speicherzelle 197, um sie mit der vorher gedrückten Taste vergleichen zu können.

Die Codezahlen jeder Taste lassen sich mit folgendem Programm abfragen:

10 PRINT PEEK (203)
20 GOTO 10

Nach RUN sehen wir ein laufendes Zahlenband, zuerst mit der Zahl 64. Das ist die Codezahl für »keine Taste gedrückt«. Die X-Taste ergibt 23 (26 beim VC 20), die W-Taste ergibt 9. Auch die Funktionstasten haben ihren Tastencode. F1 ergibt 4 (39 beim VC 20) und so weiter.

Nur die Steuertasten CTRL, SHIFT, und C= (Commodore-Taste) zeigen keine Reaktion. Deren Tastencode steht nämlich in Speicherzelle 653. Den Grund für diesen Separatismus erfahren Sie bei der Besprechung dieser Zelle. Hier ist nur interessant, daß nicht nur jede einzelne dieser drei Tasten einen eigenen Code hat, sondern auch alle machbaren Kombinationen von gleichzeitig gedrückten Steuertasten. Um das zu sehen, ändern Sie bitte die Zeile 10 so ab:

10 PRINT PEEK (203), PEEK(653)

Tabelle 9 gibt Ihnen die volle Übersicht. Wenn Sie sich die Mühe machen, die Zahlenreihen der Zelle 203 auf Vollständigkeit zu prüfen, dann werden Sie feststellen, daß vier Zahlen fehlen. Es sind die Werte, die eigentlich den vier Steuertasten CTRL, C=, rechte und linke SHIFT-Taste zugewiesen sind. Aber wie gesagt, sie werden gleich nach 653 umgeleitet, wobei allerdings kein Unterschied mehr zwischen der linken und rechten SHIFT-Taste gemacht wird.

Einige Anwendungsbeispiele der Tastencodes sowie der Kombinationen der drei

Steuertasten finden Sie im Texteinschub Nr. 21 »Abfrage der Tastencodes«. Wie schon erwähnt, haben die RESTORE-Taste und die SHIFT-LOCK-Taste keinen eigenen Code.

Die RESTORE-Taste ist überhaupt nicht an die Tastatur-Matrix angeschlossen, sondern ist direkt mit der RESTORE-Leitung des Computers verbunden. Dort löst sie einen sogenannten NMI-Interrupt aus. Die SHIFT-LOCK-Taste ist lediglich eine mechanische Verriegelung der SHIFT-Taste.

gedrückte Taste

Hier steht der jeweilige Code der gedrückten Taste. (64= keine Taste).

Matrix code of key currently being pressed

Values:

  • $00-$3F: Keyboard matrix code.
  • $40: No key is currently pressed.
SHIFT mode on print   Flag: Print Shifted Chars.   Flag: Print shifted Characters.   Which key : 64 if no key  
$00CC BLNSW 204
Cursor Blink Enable: 0=Flash Cursor

When this flag is set to a nonzero value, it indicates to the routine that normally flashes the cursor not to do so. The cursor blink is turned off when there are characters in the keyboard buffer, or when the program is running.

You can use this location to turn the cursor on during a program (for a series of GET operations, for example, to show the user that input is expected) by using the statement POKE 204,0.

Schalter für Cursor blinken

Ein Wert größer 0 in dieser Speicherzelle schaltet das Blinken des Cursors ab. Diese Abschaltung erfolgt durch das Betriebssystem immer dann, wenn sich Zeichen im Tastaturpuffer befinden und wenn ein Programm ausgeführt wird.

Im folgenden Beispiel einer Eingabe mit dem GET-Befehl, bei dem bekannterweise der Cursor nicht blinkt, wird demonstriert, daß durch POKE 204,0 der Cursor trotzdem blinkt. Das kann für selbstgeschriebene Eingabe-Routinen interessant sein.

10 PRINT"JA/NEIN?";
20 POKE 204,0
30 GET A$: IF A$=""THEN 30
40 PRINT A$

Umgekehrt kann man durch POKE 204,1 das Blinken des Cursors abschalten. Es bleibt dabei allerdings dem Zufall überlassen, ob er in der Einoder Aus-Phase abgeschaltet wird. Wenn Sie Pech haben, dann bleibt der Cursor bewegungslos stehen.

Flag für Cursor

Der Cursor wird ausgeschaltet, wenn in dieser Speicherzelle ein größerer Wert als Null steht.

Cursor visibility switch

Values:

  • $00: Cursor is on.
  • $01-$FF: Cursor is off.
Cursor blink enab   Cursor Blink enable: 0 = Flash Cursor   Flag: Cursor blink; $00 = Enabled, $01 = Disabled.   0 = flash cursor  
$00CD BLNCT 205
Timer: Countdown to Blink Cursor

The interrupt routine that blinks the cursor uses this location to tell when it's time for a blink. First the number 20 is put here, and every jiffy (1/60 second) the value here is decreased by one, until it reaches zero. Then the cursor is blinked, the number 20 is put back here, and the cycle starts all over again. Thus, under normal circumstances, the cursor blinks three times per second.

Zähler für Blinkfrequenz des Cursors

Das Blinken des Cursors besorgt die Interrupt-Routine. 60mal in jeder Sekunde unterbricht sie den normalen Programmablauf. Während dieser Zeit führt sie mehrere »Haushalt«-Arbeiten durch. So wird hier die Tastatur abgefragt und das Cursorblinken gesteuert.

Dazu wird die Zahl 20 in die Speicherzelle 205 geschrieben und bei jeder Unterbrechung dann um 1 reduziert. Wenn die Zahl in 205 den Wert 0 erreicht hat, wird der Cursor eingeschaltet. Nach Adam Riese erfolgt das also 60/20 = 3mal pro Sekunde. Im Texteinschub Nr. 22 »Cursor-Spiele oder der INPUT-Befehl einmal etwas anders« wird mit diesem Zähler für die Blinkfrequenz experimentiert.

Zähler für Cursor blinken

Diese Speicherzelle dient als Zähler für die Cursor-Blinkphase. Wenn der Wert 20 in dieser Speicherzelle abgezählt ist, wird der Cursor eingeschaltet.

Delay counter for changing cursor phase

Values:

  • $00, 0: Must change cursor phase.
  • $01-$14, 1-20: Delay.
Count to toggle cur   Timer: Countdown to Toggle Cursor   Timer: Count down for Cursor blink toggle.   Cursor timing countdown  
$00CE GDBLN 206
Character Under Cursor

The cursor is formed by printing the inverse of the character that occupies the cursor position. If that characters is the letter A, for example, the flashing cursor merely alternates between printing an A and a reverse-A. This location keeps track of the normal screen code of the character that is located at the cursor position, so that it may be restored when the cursor moves on.

Bildschirmcode des Zeichens unter dem Cursor

Im Prinzip ist der Cursor nichts anderes als das wiederholte Drucken eines Zeichens in reverser Form, das gerade unter dem Cursor steht. Normalerweise ist dies das Leerzeichen, deshalb sehen wir meistens das ausgefüllte Viereck. Fahren Sie aber mit dem Cursor auf einen Buchstaben, dann erscheint dieser wechselweise normal und revers. In Speicherzelle 206 steht jeweils der Bildschirmcode des Zeichens unter dem Cursor. Geben Sie die folgende Anweisung direkt ein, fahren aber noch vor dem Drücken der RETURN-Taste mit dem Cursor zurück auf eines der Zeichen, zum Beispiel auf ein P:

PRINT PEEK(206)

Nach RETURN erscheint die Zahl 16. Das ist also der Bildschirmcode des Zeichens, auf dem der Cursor saß, als die RETURN-Taste gedrückt wurde. Sie können das mit allen anderen Zeichen dieser Zeile wiederholen.

Ich kann mir vorstellen, daß eine derartige Abfrage in einem Programm, welches mit dem Bildschirm arbeitet, sinnvoll sein kann. Die Speicherzelle 206 wird allerdings nach jedem Blinken auf den neuesten Stand gebracht.

Zeichen unter dem Cursor

Hier ist jeweils der Bildschirmcode eines Zeichens angegeben, das sich gerade unter dem Cursor befindet.

Screen code of character under cursor.   Char before cursor   Character Under Cursor   Character under Cursor while Cursor Inverted.   Character under cursor  
$00CF BLNON 207
Flag: Was Last Curson Blink on or off?

This location keeps track of whether, during the current cursor blink, the character under the cursor was reversed, or was restored to normal. This location will contain a 0 if the character is reversed, and a 1 if the character is restored to its nonreversed status.

Flagge für Blinkzustand des Cursors

In dieser Speicherzelle wird festgehalten, in welcher der beiden Blink-Phasen - normal oder revers - der Cursor sich gerade befindet. Eine 0 bedeutet reverses Zeichen, eine 1 bedeutet ein normales Zeichen.

Die Abfrage innerhalb eines Basic-Programms funktioniert nicht. Denn die Interrupt-Routine steuert den Phasenwechsel.

Flag für Cursor

In diesem Register wird festgehalten, in welcher Blink-Phase sich der Cursor gerade befindet.

Cursor phase switch

Values:

  • $00: Cursor off phase, original character visible.
  • $01: Cursor on phase, reverse character visible.
On/off blink flag   Flag: Last Cursor Blink On/Off   Flag: Cursor Status; $00 = Off, $01 = On.   Cursor in blink phase  
$00D0 CRSW 208
Flag: Input from Keyboard or Screen

This flag is used by the Kernal CHRIN (61783, $F157) routine to indicate whether input is available from the screen (3), or whether a new line should be obtained from the keyboard (0).

Flagge für Eingabe von Tastatur oder Bildschirm

Diese Speicherzelle wird von einer Routine des Betriebssystems verwendet, die das jeweils nächste Zeichen in den Arbeitsspeicher holt. Für sie ist wichtig zu wissen, von welchem Eingabegerät dieses Zeichen geholt werden soll.

Wenn in der Zelle 208 eine 0 steht, wird damit die Tastatur als Eingabegerät bestimmt. Das ist der Normalfall, mit dem wir per Tastendruck Zeichen auf den Bildschirm tippen. Sobald aber statt einem Zeichen die RETURN-Taste gedrückt wird, ändert sich der Inhalt der Speicherzelle 208. Die oben genannte Routine überträgt nämlich jetzt den Inhalt der Zelle 213, in welcher die Länge der derzeitigen logischen Zeile steht, nach 208. Dann holt sie das nächste Zeichen, allerdings nicht von der Tastatur, sondern vom Bildschirm, und zwar das erste Zeichen der gerade abgeschlossenen logischen Zeile. Auf diese Weise gelangen die Anweisungen einer Zeile in den Arbeitsspeicher, wo sie im Direkt-Modus sofort ausgeführt, im Programm-Modus aber gespeichert und erst nach RUN ausgeführt werden.

Den Unterschied zwischen »logischer« und »echter« Zeile habe ich in dem Texteinschub Nr. 23 näher beschrieben.

Flag für Eingabe von Tastatur oder Bildschirm

Hier wird die Länge der zu übertragenden Zeichen gespeichert.

End of line switch during screen input

Values:

  • $00: Return character reached, end of line.
  • $01-$FF: Still reading characters from line.
INPUT vs GET flag   Flag: INPUT or GET from Keyboard   Flag: Input from Screen = $03, or Keyboard = $00.   Input from screen/from keyboard  
$00D1-$00D2 PNT 209-210
Pointer to the Address of the Current Screen Line

This location points to the address in screen RAM of the first column of the logical line upon which the cursor is currently positioned.

Zeiger auf den Anfang der Bildschirmzeile, auf welcher der Cursor gerade steht

Dieser Zeiger in Low-/High-Byte-Darstellung zeigt auf die Adresse im Bildschirmspeicher, in welcher diejenige Zeile beginnt, auf der der Cursor gerade steht. Das läßt sich leicht nachprüfen durch folgende Programmzeile:

10 PRINT CHR$(147) PEEK(209) PEEK(210)

Nach RUN wird erst der Bildschirm gelöscht, der Cursor in die HOME-Position gebracht und dann der Inhalt der beiden Zellen ausgedruckt. Da dies alles in der ersten Zeile passiert, sehen wir als Resultat eine 0 und eine 4. Die beiden Zahlen ergeben zusammen die Adresse, in der die erste Zeile des Bildschirmspeichers beginnt. Erweitern Sie die Zeile 10 um ein Komma und die Low-/High-Byte-Berechnung:

10 PRINT CHR$(147) PEEK(209) PEEK(210), PEEK(209)+256*PEEK(210)

Jetzt sehen wir als Resultat:

0 4 1024

Beim VC 20 erscheinen die der verwendeten Speichererweiterung entsprechenden Zahlen. Wir können durch einen TAB-Befehl den zweiten Teil der PRINT-Anweisung in die nächste Zeile schieben und sehen, was dann herauskommt:

20 PRINT PEEK(209) PEEK (210),TAB(50) PEEK(209)+ 256*PEEK(210)

Das Resultat ist jetzt:

0      4       1024
40     4       1104

Einen entsprechenden Zeiger für die Adresse der dazugehörigen Zeile im Farbspeicher werden wir in den Speicherzellen 243 und 244 antreffen. Durch POKEn können wir die Cursorposition leider nicht beeinflussen, aber Abfragen geht, wenn es uns interessiert.

Zeiger auf Start der Bildschirmzeile

In diesen Speicherzellen wird in LOW- und HIGH-Byte-Darstellung angezeigt, wo sich im Video-RAM die Zeile befindet, auf der der Cursor gerade steht.

Pointer to current line in screen memory.   Pointer to row   Pointer: Current Screen Line Address   Pointer: Current Screen Line Address.   Pointer to screen line  
$00D3 PNTR 211
Cursor Column on Current Line

The number contained here is the cursor column position within the logical line pointed to by 209 ($D1). Since a logical line can contain up to two physical lines, this value may be from 0 to 79 (the number here is the value returned by the POS function).

Position des Cursors innerhalb einer logischen Zeile

Den Inhalt der Speicherzelle 211 könnte man auch die Spaltenposition des Cursors nennen, wenn es sich nicht um die Position in der logischen Zeile handelte (siehe Texteinschub Nr. 23). Beim C 64 sind daher die Werte von 0 bis 79, beim VC 20 von 0 bis 87 möglich.

Diese Speicherzelle zusammen mit Zelle 214 wird von den Befehlen POS, TAB, SPC und vom Komma innerhalb einer PRINT-Anweisung verwendet, um den Cursor zu positionieren. Das können wir auch. Um den Cursor auf Platz 5 in der Bildschirmzeile 18 zu bringen, geben wir folgende Programmzeile ein:

10 POKE 214,17: PRINT: POKE 211,5:PRINT"C64"

Aus innerbetrieblichen Gründen muß der Wert, den wir als Zeile erzielen wollen, um 1 verringert in die Zelle 214 gePOKEt werden. Mit der Zahl 17 wird also der Cursor zuerst auf die Zeile 18 gebracht, dann in Spalte 5, ab der dann das Wort »C 64« gedruckt wird. Auf diese Weise erhalten wir einen Befehl, der in anderen Basic-Formen unter dem Namen PRINT AT sehr verbreitet ist, der bei den kleinen Commodore-Computern aber fehlt.

Der Vorgang dabei besteht darin, daß die Inhalte von 211 und 214 in das X- Register beziehungsweise in das Y-Register des Mikroprozessors gebracht werden. Von dort können die Werte dann von einer Routine des Betriebssystems abgerufen werden. Das klingt alles sehr nach Maschinensprache. Aber wir haben Glück, denn sowohl die beiden Register als auch die besagte Routine sind von Basic aus ansprechbar. Das X-Register steht in Speicherzelle 781, das Y-Register in Speicherzelle 782, die Routine beginnt sowohl beim C 64 als auch beim VC 20 ab der Adresse 68634, wo wir sie mit dem SYS-Befehl starten können.

Für unser Beispiel sieht das dann so aus:

10 POKE 781,18:POKE 782,5: SYS 58634:PRINT"C 64"

Wir erhalten dasselbe Ergebnis, nur mit dem Unterschied, daß die Zeile jetzt wirklich die Zeile 18 ist. Mit dieser Methode ist jetzt auch die Zeile 0 erreichbar.

Die Speicherzellen 781 und 782 bieten natürlich noch andere Anwendungen, auf die wir noch kommen werden.

Cursorspalte

Hier wird die Spaltenposition des Cursors festgehalten.

Current cursor column. Values: $00-$27, 0-39.   Pointer to column   Cursor Column on Current Line   Cursor Column on current Line, including Wrap-round Line, if any.   Position of cursor on above line  
$00D4 QTSW 212
Flag: Editor in Quote Mode? 0=No

A nonzero value in this location indicates that the editor is in quote mode. Quote mode is toggled every time that you type in a quotation mark on a given line--the first quote mark turns it on, the second turns it off, the third turns it back on, etc.

If the editor is in this mode when a cursor control character or other nonprinting character is entered, a printed equivalent will appear on the screen instead of the cursor movement or other control operation taking place. Instead, that action is deferred until the string is sent to the string by a PRINT statement, at which time the cursor movement or other control operation will take place.

The exception to this rule is the DELETE key, which will function normally within quote mode. The only way to print a character which is equivalent to the DELETE key is by entering insert mode (see loctaion 216 ($D8)). Quote mode may be exited by printing a closing quote, or by hitting the RETURN or SHIFT-RETURN keys.

Sometimes, it would be handy to be able to escape from quote mode or insert mode without skipping to a new line. The machine language program below hooks into the keyscan interrupt routine, and allows you to escape quote mode by changing this flag to 0 when you press the f1 key:

10 FOR I=850 TO I+41:READ A:POKE I,A:NEXT
20 PRINTCHR$(147)"PRESS F1 KEY TO ESCAPE QUOTE MODE"
30 PRINT"TO RESTART AFTER RESTORE ONLY, SYS 850":SYS850:NEW
40 DATA  173 , 143 , 2 , 141 , 46 , 3 , 173 , 144 , 2 , 141
50 DATA 47 , 3 , 120 , 169 , 107 , 141 , 143 , 2 , 169 , 3
60 DATA 141 , 144 , 2 , 88 , 96 , 165 , 203 , 201 , 4 , 208
70 DATA 8 , 169 , 0 , 133 , 212 , 133 , 216 , 133 , 199 , 108 , 46 , 3
Flagge für Gänsefuß-Modus

Steht in dieser Speicherzelle eine 0, dann befindet sich der Computer im Gänsefuß-Modus, andere Zahlen bedeuten den Normal-Modus.

Selbst Anfängern ist der Gänsefuß-Modus sehr rasch geläufig, bietet er doch die Möglichkeit, Zeichen mit der PRINT-Anweisung auszudrucken. Genauso bekannt sind aber auch die Tücken der Gänsefüße. Die Cursor-Tasten reagieren nicht wie gewohnt. Auch die Farbumschaltung und andere Steuertasten zeigen nicht die übliche Wirkung, sondern drucken - allzu oft unerwartet - ein reverses Zeichen auf den Bildschirm.

Eingeschaltet wird der Gänsefuß-Modus durch Drücken der geSHIFTeten 2-Taste oder der geSHIFTeten INST/DEL-Taste. Abgeschaltet wird er nach jedem 2., 4., 6., also nach jeder geradzahligen Wiederholung der Gänsefuß-Taste innerhalb einer Zeile. Abgeschaltet wird er auch durch die RETURN-Taste. Das spezielle Verhalten der Steuertasten zwischen Gänsefüßen läßt sich für faszinierende Effekte ausnutzen.

Leider läßt sich der Inhalt der Speicherzelle 212 und damit der Status des Gänsefuß-Modus von Basic aus nicht beeinflussen. Doch in Maschinensprache unter Verwendung der Interrupt-Routine geht es, und einige Vorschläge zum Abschalten des Gänsefuß-Modus per Tastendruck sind schon veröffentlicht worden.

Flag für Hochkommamodus

Falls in dieser Speicherzelle eine Null steht, dann befindet sich der Computer im Normalmodus. Andere Werte bewirken den Hochkommamodus.

Quotation mode switch

Values:

  • $00: Normal mode.
  • $01: Quotation mode.
Quote switch   Flag: Editor in Quote Mode, $00 = NO   Flag: Editor in Quote Mode; $00 = Not.   0 = direct cursor, else programmed  
$00D5 LNMX 213
Maximum Length of Physical Screen Line

The line editor uses this location when the end of a line has been reached to determine whether another physical line can be added to the current logical line, or if a new logical line must be started.

Länge der Bildschirmzeile

Im Texteinschub 23 »Logische und echte Zeilen« ist der Unterschied zwischen den beiden Zeilentypen beschrieben.

Der Inhalt dieser Speicherzelle entscheidet, wann eine neue logische Zeile begonnen werden muß oder ob die laufende logische Zeile um eine weitere echte Zeile erweitert werden kann. Der Bildschirm-Editor verwendet diese Speicherzelle, um komplette logische Zeilen nach oben zu verschieben. Einige andere Routinen benutzen den Wert der Zelle bei der Rückwärtsüberprüfung einer Zeile, bei der die Endposition der Zeile bekannt sein muß. Schließlich bezieht noch die bereits behandelte Speicherzelle 200 Ihren Wert von der Zelle 213.

Länge der Bildschirmzeile

Der Inhalt dieser Speicherzelle entscheidet, ob eine neue Zeile angefangen werden muß oder nicht.

Length of current screen line minus 1. Values: $27, 39; $4F, 79.   40/80 max positon   Physical Screen Line Length   Current logical Line length: 39 or 79.   Current screen line length  
$00D6 TBLX 214
Current Cursor Physical Line Number

This location contains the current physical screen line position of the cursor (0-24). It can be used in a fashion to move the cursor vertically, by POKEing the target screen line (1-25) minus 1 here, followed by a PRINT command. For example,

POKE 214,9:PRINT:PRINT "WE'RE ON LINE ELEVEN"

prints the message on line 11. The first PRINT statement allows the system to update the other screen editor variables so that they will also show the new line. The cursor can also be set or read using the Kernal PLOT routine (58634, $E50A) as explained in the entry from locations 780-783 ($030C-$030F).

Nummer der echten Zelle, auf der sich der Cursor gerade befindet

Diese Speicherzelle ist zusammen mit der Speicherzelle 211 beschrieben.

Cursorzeile

Hier wird die Zeilenposition des Cursors festgehalten.

Current cursor row. Values: $00-$18, 0-24.       Current Cursor Physical Line Number   Current Screen Line number of Cursor.   Row where curosr lives  
$00D7 DATA 215
Temporary Storage Area for ASCII Value of Last Character Printed

The ASCII value of the last character printed to the screen is held here temporarily.

Zwischenspeicher für den ASCII-Codewert der zuletzt gedrückten Taste

Bei der Tastaturabfrage werden die Tastencodes (siehe Speicherzelle 203) in ASCII-Codewerte umgewandelt und in den Tastaturpuffer gebracht. Die Speicherzelle 215 dient dabei als Zwischenspeicher. Kassettenoperationen speichern hier auch Prüfsummen ab.

Speicher für ASCII-Tasten-Code

Bevor ein Zeichen in den Tastaturpuffer gebracht wird, wird es vorher hier zwischengespeichert.

PETSCII code of character during screen input/output.
Bit buffer during datasette input.
Block checksum during datasette output.
 
Cassette: holds most recent dipole bit value   Temp Data Area   Screen value of current Input Character/Last Character Output.   Last inkey/checksum/buffer  
$00D8 INSRT 216
Flag: Insert Mode (Any Number Greater Than 0 Is the Number of Inserts)

When the INST key is pressed, the screen editor shifts the line to the right, allocates another physical line to the logical line if necessary (and possible), updates the screen line length in 213 ($D5), and adjusts the screen line link table at 217 ($D9). This location is used to keep track of the number of spaces that has been opened up in this way.

Until the spaces that have been opened up are filled, the editor acts as if in quote mode (see location 212 ($D4), the quote mode flag). This means that cursor control characters that are normally nonprinting will leave a printed equivalent on the screen when entered, instead of having their normal effect on cursor movement, etc. The only difference between insert and quote mode is that the DELETE key will leave a printed equivalent in insert mode, while the INST key will insert spaces as normal.

Flagge für INSERT-Modus

Immer wenn die geSHIFTete INST/DEL-Taste gedrückt wird, um in einer Zeile Platz für ein einzufügendes Zeichen zu schaffen, wird der Inhalt der Speicherzelle 216 um 1 erhöht. Dann wird die Zeile ab dem Freiplatz nach rechts verschoben, der Inhalt der Speicherzelle 213 erhöht und schließlich der entsprechende Wert der Link-Tabelle für Bildschirmzeilen ab Speicherzelle 217 bis 242 verändert.

Bei jedem Tippen eines Zeichens in den freigewordenen Platz wird der Inhalt von 216 wieder um 1 reduziert, bis mit der 0 das Ende des INSERT-Modus angezeigt wird.

Anzahl der Inserts

Hier wird die Anzahl der Inserts festgelegt.

Number of insertions

Values:

  • $00: No insertions made, normal mode, control codes change screen layout or behavior.
  • $01-$FF: Number of insertions, when inputting this many character next, those must be turned into control codes, similarly to quotation mode.
Insert mode flag   Flag: Insert Mode, >0 = # INSTs   Count of number of inserts outstanding.   # of INSERTs outstanding  
$00D9-$00F2 LDTB1 217-242
Screen Line Link Table/Editor Temporary Storage

This table contains 25 entries, one for each row of the screen display. Each entry has two functions. Bits 0-3 indicate on which of the four pages of screen memory the first byte of memory for that row is located. This is used in calculating the pointer to the starting address of a screen line at 209 ($D1).

While earlier PETs used one table for the low bytes of screen rows and another for the high bytes, this is not possible on the 64, where screen memory is not fixed in any one spot. Therefore, the Operating System uses a table of low bytes at 60656 ($ECF0), but calculates the high byte by adding the value of the starting page of screen memory held in 648 ($0288) to the displacement page held here.

The other function of this table is to establish the makeup of logical lines on the screen. While each screen line is only 40 characters long, BASIC allows the entry of program lines that contain up to 80 characters. Therefore, some method must be used to determine which pairs of physical lines are linked into a longer logical line, so that this longer logical line may be edited as a unit.

The high bit of each byte here is used as a flag by the screen editor. That bit is set (leaving the value of the byte over 128 ($80)) when a line is the first or only physical line in a logical line. The high bit is reset to 0 only when a line is the second half of a logical line.

Link-Tabellen der Bildschirm-Zeilen

Diese 26 Speicherzellen enthalten Angaben für jede Zeile des Bildschirms. Jedes dieser Bytes hat zwei Funktionen.

Die ersten 4 Bit, also Bit 0 bis 3, geben an, in welchem Speicherblock, man sagt auch »page« dazu, das erste Byte der betreffenden Bildschirmzeile sich befindet. Diese Angabe wird zur Berechnung des Zeigers in der Speicherzelle 209 (siehe dort) verwendet. Sie ist in dieser Form notwendig, da der Bildschirmspeicher beim C 64 überall in den Arbeitsspeicher gelegt werden kann. Um die Position eines Zeichens oder besser gesagt eines Bytes davon im Bildschirmspeicher genau positionieren zu können, braucht das Betriebssystem noch die genaue Lage innerhalb des Speicherblocks. Das Low-Byte dieser Zahl steht in einer Tabelle ab Speicherzelle 60656 (60952 beim VC 20). Das High-Byte wird berechnet, und zwar durch Addition des Wertes der Speicherzelle 648 mit dem Wert der ersten 4 Bit in Tabelle 217 bis 242. Der Wert in Zelle 648 gibt die Anfangsadresse des Bildschirmspeichers an.

Der zweite Teil jedes Bytes in der Tabelle 217 bis 242 hat eine andere Funktion. Wie im Texteinschub 23 beschrieben ist, kann eine logische Zeile aus ein oder zwei (beim VC 20 sogar bis zu 4) echten Zeilen bestehen. Das Betriebssystem braucht daher eine Angabe, welche echten Zeilen zu einer logischen Zeile verbunden sind. Dieses Verbinden heißt auf englisch »link«, daher heißt der Speicherbereich 217 bis 242 »Link-Tabelle«. Diese oberen 4 Bit zeigen mit irgendeinem Wert über 0 an, daß die betreffende echte Zeile die erste oder einzige einer logischen Zeile ist. Sind die 4 Bit alle 0, dann ist sie eine 2., 3. und 4. Zeile der logischen Zeile.

MSB der Bildschirmzeilenanfänge

Alle 25 Speicherzellen enthalten Informationen über die Zeilen des Bildschirms.

High byte of pointers to each line in screen memory (25 bytes)

Values:

  • $00-$7F: Pointer high byte.
  • $80-$FF: No pointer, line is an extension of previous line on screen.
Line flags+endspace   Screen Line Link Table / Editor Temps   Screen Line link Table/Editor temporaries.
High Byte of Line Screen Memory Location.
 
Screen line link table  
$00F3-$00F4 USER 243-244
Pointer to the Address of the Current Screen Color RAM Location

This poitner is synchronized with the pointer to the address of the first byte of screen RAM for the current line kept in location 209 ($D1). It holds the address of the first byte of color RAM for the corresponding screen line.

Zeiger auf Position des Cursors im Farbspeicher

Jedem Platz im Bildschirmspeicher, in dem der Codewert für ein Zeichen steht, entspricht ein Platz im Farbspeicher, in dem der Codewert für die Farbe dieses Zeichens steht.

Das heißt, daß den Bildschirm-Werten der Speicherzellen 209 bis 210 die Farbspeicher-Werte der Zellen 243 bis 244 entsprechen. Dieser Zeiger bestimmt also in der Low-/High-Byte-Darstellung die Adresse im Farbspeicher, ab der die echte Zeile beginnt, auf welcher der Cursor gerade steht.

Zeiger in Farb-RAM

Diese Speicherzellen zeigen auf die Stelle im Farb-RAM, an der der Cursor auf der Zeile steht.

Pointer to current line in Color RAM.   Screen editor color IP   Pointer: Current Screen Color RAM loc.   Pointer: Current Colour RAM Location.   Screen color pointer  
$00F5-$00F6 KEYTAB 245-246
Vector: Keyboard Decode Table

KEYTAB points to the address of the keyboard matrix lookup table currently being used. Although there are only 64 keys on the keyboard matrix, each key can be used to print up to four different characters, depending on whether it is struck by itself or in combination with the SHIFT, CTRL, or Commodore logo keys.

The tables pointed to y this address hold the ASCII value of each of the 64 keys for one of these possible combinations of keypresses. When it comes time to print the character, the table that is used determines which character is printed.

The addresses of the four tables are:

60289 $EB81 default uppercase/graphics characters (unshifted)
60354 $EBC2 shifted characters
60419 $EC03 Commodore logo key characters
60536 $EC78 CTRL characters

The concept of the keyboard matrix tables should not be confused with changing the character sets from uppercase/graphics to upper/lowercase. The former involves determining what character is to be placed into screen memory, while the latter involves determining which character data table is to be used to decode the screen memory into individual dots for the display of characters on the screen. That character base is determined by location 53272 ($D018) of the VIC-II chip.

Vektor auf die Decodiertabelle für ASCII-Codewerte der Tasten

Bei der Diskussion der Speicherzelle 145 habe ich Ihnen gezeigt, wie das Drücken einer der 64 Tasten entschlüsselt wird.

Ein entschlüsselter Wert wird in Speicherzelle 145 zwischengespeichert und gelangt dann als Tastencode in die Speicherzelle 203. Bei der Besprechung der Zelle 203 wurden die Codewerte aufgelistet. Ich habe auch darauf hingewiesen, daß die Codes der drei Steuertasten SHIFT, CTRL und COMMODORE (C=) separat in der Zelle 653 stehen.

Diese Tastencodes sind sehr nützlich und vom Basic aus gut verwendbar. Im Verkehr mit anderen Geräten sind sie aber nicht einsetzbar, da sie keiner internationalen Norm entsprechen.

Eine derartige Norm bietet der sogenannte ASCII-Code. Deshalb rechnet, wo notwendig, das Betriebssystem die Tastencodes in den ASCII-Code um.

Dazu stehen im Speicher des Betriebssystems vier Tabellen (Bild 22), die die ASCII-Codewerte enthalten (in Klammern für den VC 20).

Die Umrechnung der Tastencodes in ASCII-Code ist sehr einfach. Der Tastencode wird lediglich zu der Anfangsadresse der entsprechenden Tabelle hinzugezählt. Die Summe ergibt die Adresse in derTabelle, in der der ASCII-Code für das gedrückte Zeichen steht.

Als Beispiel nehmen wir das normale »G«, sein Tastencode ist 26 (VC 20:19). Zur Anfangsadresse der normalen Tabelle 60289 (60510) dazugezählt, ergibt das 60315 (60529). Schauen wir in dieser Speicherzelle nach:

PRINT PEEK(60315): REM BEIM C 64
PRINT PEEK(60529): REM BEIM VC 20

In beiden Fällen erhalten wir die Zahl 71. Ein Blick in die ASCII-Tabelle des Handbuchs bestätigt die Richtigkeit.

Der Vektor in den vorliegenden Speicherzellen 245/246 zeigt auf den Anfang der vier Tabellen, und zwar in Abhängigkeit davon, ob und welche der drei Steuertasten zusammen mit einer anderen Taste gedrückt worden ist. Auch das kann ich Ihnen zeigen mit einer Programmzeile, welche ein Zahlenband erzeugt, dessen Zahl durch die Steuertasten verändert wird. Sie werden sehen, es sind die Anfangsadressen der vier Tabellen.

10 PRINT PEEK(245)+256*PEEK(246):GOTO 10
Zeiger auf Tastatur-Dekodiertabelle

Diese Speicherzellen zeigen auf die Tastatur-Dekodiertabelle.

Pointer to current conversion table during conversion from keyboard matrix codes to PETSCII codes.   Keyscan table indirect   Vector Keyboard Decode Table   Vector: Current Keyboard decoding Table.
($EB81)
 
Keyboard pointer  
$00F7-$00F8 RIBUF 247-248
Pointer: RS-232 Input Buffer

When device number 2 (the RS-232 channel) is opened, two buffers of 256 bytes each are created at the top of memory. This location points to the address of the one which is used to store characters as they are received. A BASIC program should always OPEN device 2 before assigning any variables to avoid the consequences of overwriting variables which were previously located at the top of memory, as BASIC executes a CLR after opening this device.

Zeiger auf den Anfang des RS232-Eingabe-Puffers

Immer wenn ein Kanal mit der Geräte-Nummer 2 (User-Port) eröffnet wird, werden am oberen Ende des Arbeitsspeichers zwei Pufferspeicher mit je 256 Byte reserviert (siehe auch die Beschreibung der Speicherzellen 55 bis 56).

Der Zeiger, der in Low-/High-Byte-Darstellung in 247 und 248 steht, zeigt auf die Anfangsadresse desjenigen Pufferspeichers, der die ankommenden Zeichen aufnimmt.

Ein Programm, das den User-Port benutzen will, sollte übrigens immer zuerst die Gerätenummer 2 eröffnen, bevor irgendwelche Variable definiert werden. Dadurch wird vermieden, daß die Puffer-Reservierung eventuelle Variablenwerte überschreibt, die bereits in diesen 512 Byte angesiedelt worden sind.

Zeiger auf RS-232 Eingabepuffer

Diese Register zeigen auf die Anfangsadresse des Eingabepuffers.

Pointer to RS232 input buffer

Values:

  • $00-$FF: No buffer defined, a new buffer must be allocated upon RS232 input.
  • $0100-$FFFF: Buffer pointer.
RS-232 input buffer pointer   RS-232 Input Buffer Pointer   RS232 Input Buffer Pointer.   RS-232 Rev pntr  
$00F9-$00FA ROBUF 249-250
Pointer: RS-232 Output Buffer

This location points to the address of the 256-byte output buffer which is used for transmitting data to RS-232 devices (device number 2)l

Zeiger auf den Anfang des RS232-Ausgabe-Puffers

Dieser Zeiger ist der Zwilling zu dem in den Zellen 247/248 stehenden Zeiger, diesmal aber für den Ausgabe-Puffer.

Zeiger auf RS-232 Ausgabepuffer

Diese Register zeigen auf die Anfangsadresse des Ausgabepuffers.

Pointer to RS232 output buffer

Values:

  • $00-$FF: No buffer defined, a new buffer must be allocated upon RS232 output.
  • $0100-$FFFF: Buffer pointer.
RS-232 output buffer pointer   RS-232 Output Buffer Pointer   RS232 Output Buffer Pointer.   RS-232 Tx pntr  
$00FB-$00FE FREKZP 251-254
Four Free Bytes of Zero Page for User Programs

These locations were specifically set aside for user-written ML routines that require zero-page addressing. While other zero-page locations can be used on a noninterference basis, it is guaranteed that BASIC will not alter these locations.

Vier freie Byte für Anwenderprogramme

Diese 4 Byte sind frei, und da sie von Basic nicht gestört beziehungsweise verändert werden, eignen sie sich in idealer Weise für Flaggen, Register oder andere Zwischenspeicher.

unbenutzt   Unused (4 bytes).   Free KERNAL zero page 9/24/80   Free 0-Page Space for User Programs   Free Zero Page space for User Programs.      
$00FF-$010A BASZPT 255-266
BASIC Temporary Data for Floating Point to ASCII Conversion

This location is used for temporary storage in the process of converting floating point numbers to ASCII characters.

Arbeitsspeicher für Umwandlung von Gleitkomma-Zahlen in ASCII-Werte, auch FAC (Fließkomma-Akku) genannt

Diese 12 Byte werden von einer Routine des Betriebssystems verwendet, um Werte zwischenzuspeichern, die bei der Umwandlung von Gleitkomma-Zahlen in ASCII- Werte oder in Werte der Funktion TI$ anfallen. Eine andere Routine verwendet den Bereich, um Zeichenketten (Strings) zu untersuchen.

Puffer für Umwandlung Fließkomma nach ASCII

Diese Register werden für die Zwischenspeicherung von Fließkommazahlen benutzt.

Buffer for conversion from floating point to string (12 bytes.)   Location ($FF) used by BASIC   Floating to String Work Area   Assembly Area for Floating point to ASCII conversion.   Floating to ASCII work area  
$0100-$01FF 256-511
Microprocessor Stack Area

Locations 256-511 are reserved for the 6510 microprocessor hardware stack. The organization of this temporary storage area has often been compared to that of a push-down stack of trays at a cafeteria. The first number placed on the stack goes to the bottom, and subsequent entries are placed on top of it. Then you pull a number off the stack, you come up with the last number that was pushed on (such a stack is called a Last In, First Out, or LIFO stack).

The stack is controlled by one of the microprocessor registers called the Stack Pointer, which keeps track of the last stack location used. The first number placed on the stack goes to location 511 ($01FF), and subsequent entries are built downward toward 256 ($0100). If more than 256 numbers are pushed onto the stack, the Stack Pointer will start counting from 0 again, and an overflow error will result. Likewise, if you try to pull more items off the stack than have been pushed on, an underflow error will result. Most often, such errors will cause the system to go haywire, and nothing will operate until you turn the power off and on again.

The stack is used by the system to keep track of the return addresses of machine language subroutines and interrupt calls and to save the contents of internal registers. The stack can also be used by the programmer for temporary storage. BASIC and the Kernal make heavy use of the stack.

Microsoft BASIC uses part of the stack for a temporary work area. Therefore, the stack may be broken down into the following subregions:

        Processor stack. Also used for storing data related to FOR and GOSUB.       Micro-Processor System Stack Area   6510 Hardware Stack Area.   Processor stack area  
$0100-$013E BAD 256-318
Tape Input Error Log

Each tape block is saved twice consecutively, in order to minimize loss of data from transmission errors. These 62 bytes serve as indices of which bytes in the tape block were not received corectly during the first transmission, so that corrections might be made on the second pass.

Arbeitsspeicher für Fehler bei der Eingabe vom Band

Alle Daten, die auf Band gespeichert werden, stehen dort doppelt in zwei identischen Blöcken hintereinander. Beim Laden in den Computer werden beide Blöcke miteinander verglichen, um Fehler zu finden und, wo möglich, sie zu korrigieren.

In diesem Bereich, der übrigens auch bei der Speicherzelle 256 anfängt, aber 63 Byte in Anspruch nimmt, werden beim Laden Angaben gespeichert, aus denen das Betriebssystem erkennen kann, welche Bytes fehlerhaft sind.

Speicher für Korrektur bei Bandeingabe

Beim Laden von Band werden hier die Daten zwischengespeichert, aus denen das Betriebssystem erkennen kann, welche Bytes fehlerhaft sind.

    Cassette: storage space for bad read locations (bottom of stack)   Tape Input Error Log   Tape Input Error log.   Tape error log  
$0100-$013D BAD 256-317             Pointers to bytes read with error during datasette input (62 bytes, 31 entries).                  
$013F-$01FF 319-511

This area is exclusively for the microprocessor stack. Some BASIC commands, such as FOR-NEXT loops require many stack entries at a time. Therefore, BASIC frequently checks the stack before pushing entries on, and returns an OUT OF MEMORY error if an operation would result in less than 62 bytes of available stack memory.

Each FOR statement causes 18 bytes to be pushed onto the stack, which come off in the following order:

First comes a one-byte constant of 129 ($81). Next is a two-byte pointer to the address of the subject variable (the X of FOR X=1 to 10). This is followed by the five-byte floating point representation of the TO value. Finally comes the two-byte line number of the line to which the program returns after a NEXT, and the two-byte address of the next character to read in that line after the FOR statement.

Each GOSUB call places five bytes on the stack. The first byte to come off is a one-byte constant of 141 ($8D). The next two bytes contain the line number of the statement to which the program will RETURN after the subroutine ends. And the final two bytes are a pointer to the address of the BASIC program text for that statement in which the program RETURNs.

DEF also leaves a five-byte entry on the stack. It is the same as that described for GOSUB, except that instead of a constant byte of 141, the first number is a dummy byte, whose value has no significance.

Stapelspeicher (Stack) des Mikroprozessors

Die Funktionsweise eines Stapelspeichers, auf englisch »stack«, ist im Texteinschub Nr. 24 erklärt.

Der Stapelspeicher hat prinzipiell die Aufgabe, bei allen Sprüngen oder Unterbrechungen innerhalb eines normalen Programmablaufs alle Adressen und Daten so zu speichern, daß am Ende der Unterbrechung das Programm wieder fortgesetzt werden kann.

Derartige Unterbrechungen und Sprünge treten in Basic bei den Befehlen GOSUB- RETURN und FOR-NEXT auf, genauso wie bei vielen Routinen des Betriebssystems. In Maschinensprache gibt es dafür sogar eigene Befehle. Heimo Ponnath hat sie alle in seinem Assemblerkurs (Folge 7 und 8 im 64’er, Ausgabe 2/85 und 3/85) sehr ausführlich beschrieben.

Da uns hier Basic mehr interessiert, gebe ich Ihnen nur kurz an, was im Stapel gespeichert wird, da der Stapelspeicher nur in Maschinensprache manipuliert werden kann.

Jeder FOR-TO-NEXT-Befehl belegt 18 Byte im Stapelspeicher.

Im ersten Byte steht als Kennung dieZahl 129. Byte 2 und 3 enthalten in Low/ High-Byte-Darstellung einen Zeiger auf die Adresse, in der die durch das FOR definierte Schleifen-Variable (zum Beispiel K in FOR K=0 TO 3) gespeichert ist. Die nächsten 5 Byte sind für den Gleitkommawert von STEP reserviert, das Byte danach für das Vorzeichen von STEP. Danach folgt der Gleitkommawert von TO mit 5 Byte und in zwei weiteren Byte die Nummer derjenigen Zeile, auf die nach dem NEXT zurückgesprungen wird. In den letzten beiden Bytes schließlich steht ein Zeiger auf der Adresse, in der das nächste Zeichen steht, welches nach Beendigung der FOR-TO-NEXT-Schleife gelesen werden muß.

Ein GOSUB-Befehl belegt 5 Byte im Stapelspeicher. Byte 1 enthält die Kennzahl 141. Ihr folgen zwei Byte für die Nummer der Zeile, auf die nach RETURN zurückgesprungen wird. Die letzten beiden Byte enthalten wieder einen Zeiger auf die Adresse, in der das nächste Zeichen steht, mit dem nach RETURN das Programm fortgesetzt wird.

Der Basic-Befehl DEF zur freien Definition von Funktionen belegt ebenfalls 5 Byte im Stapelspeicher. Ihre Verteilung ist dieselbe wie von GOSUB, mit dem einzigen Unterschied, daß statt der ersten Kennzahl irgendein anderer Wert verwendet wird, der aber keine Bedeutung hat.

Wenn so viele FOR...NEXT-Schleifen oder GOSUB-Sprünge gleichzeitig im Programm vorkommen, daß der Stapelspeicher voll wird, steigt das Programm mit OUT OF MEMORY aus.

Prozessorstack

Der Stack ist generell ein Zwischenspeicher, in dem der Programmierer Daten ablegen kann. Außerdem wird er vom Prozessor dazu benutzt, bei einem Interrupt oder einem Unterprogrammaufruf die Adresse, von der aus verzweigt wurde, zwischenzuspeichern. Dies geschieht in der Reihenfolge HIGH- und LOW-Byte. Die Daten werden im Stack von der Adresse $01FF zur Adresse $0100 hin abgelegt. Bei einem BREAK wird zusätzlich der Prozessorstatus im Stack abgelegt.

            BASIC Stack Area.      
$0200-$0258 BUF 512-600
BASIC Line Editor Input Buffer

When you are in the BASIC immediate mode, and type in a line of characters, those characters are stored here. BASIC then scans the string of characters, converts the text to tokenized BASIC program format, and either stores it or executes the line, depending on whether or not it started with a line number.

This same area is also used to store data which is received via the INPUT and GET commands. This explains why these commands are illegal in immediate mode--they must use the same buffer space that is required by the immediate mode statement itself.

It is interesting to note that this buffer is 89 bytes long. The screen editor will allow a maximum of only 80 characters in a program line, with one extra byte required for a 0 character, marking the end of the line. This presumable is a carry over from the VIC, which allows a line length of up to 88 characters. The last eight bytes of this buffer are therefore normally not used, and can be considered free space for the programmer to use as he or she sees fit.

Eingabespeicher von Basic

Wenn Sie Zeichen, zum Beispiel einen Befehl oder eine Programmzeile, eingeben und mit der RETURN-Taste abschließen, werden diese Zeichen in diesen Speicherbereich von 512 bis 600 gebracht. Seine Länge von 89 Byte entspricht der Länge einer logischen Zeile des VC 20 (88 Zeichen) plus einer Abschluß- Null. Die logische Zeilenlänge des C 64 von 80 Zeichen füllt den Speicherbereich nicht ganz aus, aber das Betriebssystem des C 64 ist gegenüber dem des VC 20 nicht geändert worden.

Nach RETURN sucht der Computer diesen Eingabespeicher nach Gänsefüßen, Komma und nach der Zahl für Zellenende ab. Dann wandelt der Computer die gespeicherten Zeichen in für ihn lesbare Zahlen (Token und ASCII-Werte) um und fügt am Anhang die Zeilennummer und die Anschluß-Adresse (Link) der nächsten Zeile, am Ende die Abschluß-Null hinzu. Wenn eine Zeilennummer vorhanden ist, kommt alles in den Programmspeicher. Fehlt sie jedoch, dann wird die ganze Anweisung sofort ausgeführt (Direktmodus).

Eine detaillierte Beschreibung dieses Eingabe- und Umwandlungsvorganges gab Christoph Sauer im 3. Teil seines Kurses »Der gläserne VC 20« im 64’er, Ausgabe 11/84 ab Seite 126.

Dieser Speicherbereich wird auch von den Befehlen INPUT und GET benutzt, um die Eingabedaten aufzunehmen. Das erklärt übrigens, warum diese beiden Befehle nur innerhalb einer Programmzeile und nicht im Direktmodus verwendet werden können. Sie verwenden ja denselben Speicherplatz, der vom Direkt-(Eingabe-)Modus verwendet wird.

Es erklärt außerdem, warum eine von INPUT geforderte Eingabe maximal 88 Zeichen lang sein darf.

BASIC-Eingabepuffer

Nach der Eingabe eines Befehls oder einer Programmzeile werden diese Daten in diesen Bereich zwischengespeichert, um dann wieder weiterverarbeitet zu werden.

Input buffer, storage area for data read from screen (89 bytes).  
BASIC/MONITOR buffer

Type-in stored here. Direct statements execute out of here. Remember "INPUT" smashes buf. Must be on page zero or assignment of string values in direct statements won't copy into string space -- which it must. N.B.: Two nonzero bytes must precede "BUFLNM".

System INPUT Buffer   BASIC Input Buffer (Input Line from Screen).   Basic input buffer  
$0259-$0276 601-630
Tables for File Numbers, Device Numbers, and Secondary Addresses

All three of the tables here have room for ten one-byte entries, each of which represents an active Input/Output file. When an I/O file is opened, its logical file number is put into the table at 601 ($0259), the device number of the I/O device is put into the table at 611 ($0263), and its secondary address is put into the table at 621 ($026D).

The entry for any particular I/O file will occupy the same position in each of the three tables. That is, if logical file number 2 is the third entry in the file number table, its secondary address will be the third entry in the secondary address table, and its corresponding device number will occupy the third spot in the device number table.

Every time a device is OPENed, its information is added as the last entry in each table, and the value at location 152 ($98) is increased by one, indicating that there is one more active I/O file. When a device is CLOSEd, the value at location 152 is decreased by one, and all entries that occupy a position in the tables that is higher than that of the closed device are moved down one position, thus eliminating the entry for that device. The Kernal CLALL routine (62255, $F32F) simply zeros location 152, which has the effect of emptying these tables.

Tabellen für File-Nummern, Geräte-Nummern und Sekundär-Adressen von eröffneten Dateien

Bei der Besprechung der Speicherzelle 152 habe ich diesen Speicherbereich bereits erwähnt. Ich habe damals gesagt und gezeigt, daß die Zelle 152 über die Anzahl der eröffneten Dateien (Files) Buch führt, die Tabellen in 601 bis 630 dagegen darüber, welche File-Nummern, Geräte-Nummern und Sekundär-Adressen jeder eröffneten Datei zugeordnet sind. Wer sich nochmals über diese Begriffe orientieren will, den verweise ich auf die Beschreibung im Texteinschub Nr. 19.

Der Speicherbereich von 601 bis 630 ist in drei Blöcke unterteilt.

601 bis 610 Tabelle der File-Nummern
611 bis 620 Tabelle der Geräte-Nummern
621 bis 630 Tabelle der Sekundär-Adressen

In jeder Tabelle können also maximal 10 Byte stehen. Sie haben folgende Zusammensetzung:

Die drei Angaben über eine eröffnete Datei stehen in den Tabellen jeweils am gleichen Platz. Wenn also die Datei Nummer 5 als dritte Datei eröffnet worden ist, steht eine 5 in Zelle 603, ihre Gerätenummer in Zelle 613, die Sekundär- Adresse entsprechend in Zelle 623.

Immer wenn eine neue Datei eröffnet wird, kommen diese Angaben auf die nächsten Plätze der Tabellen, und der Inhalt der Speicherzelle 152 wird um 1 erhöht. Wird dagegen eine Datei geschlossen, dann rücken alle Angaben dahinter um eine Stelle zurück.

In diesen Tabellen kann nachgesehen werden, mit welchen Parametern Dateien eröffnet worden sind. Eine sehr interessante Anwendung, die Eintragung in den Tabellen durch POKE zu verändern, wurde von Rügheimer und Spanik veröffentlicht, welche ich hier zitieren möchte.

Eine Änderung der Filenummern in Tabelle 601 bis 610 ist nicht empfehlenswert, um Verwechslungen zu vermeiden.

Mit dem folgenden kleinen Programm, welches bei einer eröffneten Datei die Geräte-Nummer in Tabelle 611 bls 620 ändert, kann zwischen einem Drucker mit Geräte-Nummer 4 und einem Plotter mit Geräte-Nummer 6 umgeschaltet werden.

10 OPEN 4,4,0
20 POKE 611,6: PRINT#4,"PLOTTER"
30 POKE 611,4: PRINT#4,"DRUCKER"

Ähnliches ist mit den Sekundär-Adressen möglich. Dabei muß man allerdings wissen, daß die Sekundär-Adressen nicht so wie sie sind in der Tabelle 621 bis 630 gespeichert werden, sondern mit »OR 96« verknüpft. Dasselbe müssen wir auch machen:

10 OPEN 3,4,0
20 POKE 621,0 OR 96: PRINT#3,"GRAFIKMODUS"
30 POKE 621,7 OR 96: PRINT#3,"TEXTMODUS"

Mit dieser Methode können Sie sich das öffnen und Schließen vieler Dateien ersparen.

                       
$0259-$0262 LAT 601-610 Kernal Table of Active Logical File Numbers      
Tabelle der logischen Filenummern

In dieser Tabelle werden die logischen Filenummern der Reihe nach, von 1-10, eingetragen. Beim Schließen einer Datei werden diese Einträge wieder entfernt.

Logical numbers assigned to files (10 bytes, 10 entries).   Logical file numbers   KERNAL Table: Active Logical File No's.   Kernal Table: Active logical File numbers.   Logical file table  
$0263-$026C FAT 611-620 Kernal Table of Device Numbers for Each Logical File      
Tabelle der Gerätenummern

Diese Tabelle entspricht $0259-$0262, nur mit dem Unterschied, daß hier die Geräteadressen vermerkt werden.

Device numbers assigned to files (10 bytes, 10 entries).   Primary device numbers   KERNAL Table: Device No. for Each File   Kernal Table: Active File First Addresses (Device numbers).   Device # table  
$026D-$0276 SAT 621-630 Kernal Table of Secondary Addresses for Each Logical File      
Tabelle der Sekundäradressen

Diese Tabelle entspricht $0259-$0262, nur mit dem Unterschied, daß hier die Sekundäradressen vermerkt werden.

Secondary addresses assigned to files (10 bytes, 10 entries).   Secondary addresses   KERNAL Table: Second Address Each File   Kernal Table: Active File Secondary Addresses.   Sec Adds table  
$0277-$0280 KEYD 631-640
Keyboard Buffer (Queue)

This buffer, sometimes also referred to as the keyboard queue, holds the ASCII values of the characters entered from the keyboard. The interrupt routine which scans the keyboard deposits a character here each time a key is pressed. When BASIC sees that there are characters waiting, it removes and prints them, one by one, in the order in which they were entered.

This kind of a buffer is known as FIFO, for First In, First Out. The buffer will hold up to ten characters, allowing you to type faster than the computer prints characters, without losing characters. The maximum number of characters this buffer can hold at one time is ten (as determined by the value at 649 ($0289)). Characters entered after the buffer is full will be ignored.

The commands GET and INPUT retrieve characters from this buffer. If one of these is executed while there are already characters waiting in the buffer, those characters will be fetched as if they were part of the data being input. To prevent this from happening, you can clear the buffer by POKEing a 0 into location 198 ($C6), which holds the number of characters that are waiting in the buffer.

One of the most interesting and useful techniques for programming Commodore computers is to have a program simulate direct entry of commands from the keyboard. This dynamic keyboard trick is achieved by first POKEing PETASCII characters, usually cursor movement characters and carriage returns, into the buffer, and setting location 198 ($C6) to show how many characters are waiting in the buffer.

Next, you clear the screen, and PRINT the statements that you wish to have executed on the screen, carefully positioning them so that the first statement to be entered is on the fourth line of the screen.

You then home the cursor and execute an END statement. This causes the keyboard buffer to be read, and the carriage returns to be executed, thus entering the printed lines as if they had been typed in immediate or direct mode. The program can be continued by including a GOTO statement in the last line entered.

Many interesting effects can be achieved using this method. Examples of a few of these are included below. For example, program lines can be added, modified, or deleted, while the program is running. The following example shows how this is done:

10 REM THIS LINE WILL BE DELETED
20 REM A NEW LINE 30 WILL BE CREATED
40 PRINT CHR$(147):PRINT:PRINT
50 PRINT "80 LIST":PRINT"30 REM THIS LINE WASN'T HERE BEFORE"
60 PRINT "10":PRINT "GOTO 80"CHR$(19)
70 FOR I=631 TO 634:POKE I,13:NEXT:POKE 198,4:END
80 REM THIS LINE WILL BE REPLACED

You can use this technique to enter numbered DATA statements automatically, using values in memory. These statements become a permanent part of the program.

Another interesting application is taking ASCII program lines from a tape data file, or sequential disk file, and having them entered automatically. This can be used for merging programs, or for transferring programs between computers with a modem and a terminal program. To create the ASCII program file, you use CMD to direct a LISTing to the desired device as follows:

  • For tape: OPEN 1,1,1,"ASCII":CMD 1:LIST
  • After the listing has ended: PRINT #1:CLOSE 1

  • For disk: OPEN 8,8,8,"ASCII,S,W":CMD 8:LIST

  • After the listing has ended: PRINT #8:CLOSE 8

This file can then be uploaded using a modem and appropriate terminal software, entered by itself or merged with another program by using the following program. Be sure to save this program before you run it, because it will erase itself when it is done.

60000 OPEN 1,8,8,"ASCII"
60010 POKE 152,1:B=0:GOSUB 60170
60020 GET #1,A$:IF A$=""THEN60020
60030 IF ST AND 64 THEN 60120
60040 IF A$=CHR$(13)AND B=0THEN60020
60050 PRINT A$;:B=1:IF A$=CHR$(34)THEN POKE 212,0
60060 IF A$<>CHR$(13) THEN 60020
60070 PRINT CHR$(5);"GOTO 60010";CHR$(5):PRINT:PRINT:POKE 198,0
60080 PRINT "RETURN=KEEP LINE    S=SKIP LINE":B=0
60090 GET A$:IF A$=""THEN 60090
60100 IF A$="S" THEN 60010
60110 GOTO 60180
60120 PRINT "END OF FILE--HIT RETURN TO FINISH MERGE"
60130 IF PEEK(197)<>1THEN60130
60140 A=60000
60150 GOSUB 60170:FOR I=A TO A+60 STEP10:PRINTI:NEXT
60160 PRINT "A="I":GOTO 60150":GOTO 60180
60170 PRINT CHR$(147):PRINT:PRINT:RETURN
60180 FOR I=631TO640:POKEI,13:NEXT:POKE198,10:PRINTCHR$(19);:END

If you wish to merge additional programs at the same time, when it indicates that the file has ended, press the STOP key rather than RETURN, enter the name of the new file in line 60000, and RUN 60000

Tastaturpuffer

Bei der Behandlung der Speicherzelle 203 habe ich die Codezahlen beschrieben, die beim Drücken einer der 64 Tasten erzeugt werden. Bei den Speicherzellen 245 und 246 haben wir gesehen, wie aus diesen Tastencodes der ASCII-Code für die verschiedenen Zeichen einer Taste umgerechnet wird.

Hier nun im Tastaturpuffer landen diese umgerechneten ASCII-Werte. Wenn Sie den Kurs schon länger verfolgen, ist Ihnen das auch nicht neu, denn ich habe die Wirkungsweise des Tastaturpuffers bei der »Dynamischen Tastenabfrage« (Texteinschub Nr. 15) sozusagen im Vorgriff, ausführlich erklärt.

Zur Erinnerung sei gesagt, daß im Tastaturpuffer alle Zeichen zwischengespeichert werden, die während eines Programmlaufes eingegeben und nicht sofort vom Betriebssystem verarbeitet werden können. Sobald der Computer sich im Eingabe-Modus befindet — nach Programmende oder bei INPUT- und GET- Befehlen, werden die Zeichen in der Reihenfolge ihrer Eingabe herausgeholt und verwendet.

Der Tastaturpuffer ist 10 Byte lang. In Speicherzelle 198 steht, wieviele Zeichen sich im Puffer befinden.

Als Ergänzung zu den Beispielen der dynamischen Tastenabfrage zeige ich Ihnen im Texteinschub Nr. 25 »Programme, die sich selbst verändern« noch ein paar andere Anwendungen.

Tastaturpuffer

Hier werden die Tastencodes zwischengespeichert, die nicht sofort vom Betriebssystem weiterverarbeitet werden können.

Keyboard buffer (10 bytes, 10 entries).   IRQ keyboard buffer   Keyboard Buffer Queue (FIFO)   Keyboard Buffer Queue (FIFO).   Keybd buffer  
$0281-$0282 MEMSTR 641-642
Pointer: O.S. Start of Memory

When the power is first turned on, or a cold start RESET is performed, the Kernal routine RAMTAS (64848, $FD50) sets this location to point to address 2048 ($0800). This indicates that this is the starting address of user RAM. BASIC uses this location to set its own start of memory pointer at location 43 ($2B), and thereafter uses only its own pointer.

The Kernal routine MEMBOT (65076, $FE34) may be used to read or set this pointer, or these locations may be directly PEEKed or POKEd from BASIC.

Zeiger auf den Anfang des Programmspeichers

Wenn der Computer eingeschaltet wird oder wenn mit einer Reset-Taste beziehungsweise mit SYS 58260 (VC 20: SYS 58232) ein Kaltstart ausgelöst wird, setzt das Betriebssystem diesen Zeiger auf die Adresse des ersten freien RAM- Speicherplatzes.

Beim C 64 ist dies die Adresse 2048. Beim VC 20 hängt sie von der Speichererweiterung ab; ohne Erweiterung ist es 4096, mit einer 3-KByte- Erweiterung dagegen 1024, mit 8 KByte oder mehr ist die Adresse 4608.

Dieser Zeiger wird vom Basic-Übersetzer in die Speicherzelle 43 übernommen und nur von dort weiterverwendet.

Start des BASIC-RAM

Nach einem Reset oder einem Kaltstart wird dieser Zeiger auf den nächsten freien Speicherplatz gesetzt.

Pointer to beginning of BASIC area after memory test.

Default: $0800, 2048.

Start of memory   Pointer: Bottom of Memory for O.S.   Pointer: Bottom of Memory for Operating System ($0800).   Start of Basic Memory  
$0283-$0284 MEMSIZ 643-644
Pointer: O.S. End of Memory

When the power is first turned on, or a cold start RESET is performed, the Kernal routine RAMTAS (64848, $FD50) performs a nondestructive test of RAM from 1024 ($0400) up, stopping when the test fails, indicating the presence of ROM. This will normally occur at 40960 ($A000), the location of the BASIC ROM. The top of user RAM pointer is then set to point to that first ROM location.

After BASIC has been started, the system will alter this location only when an RS-232 channel (device number 2) is OPENed or CLOSEd. As 512 bytes of memory are required for the RS-232 transmission and reception buffers, this pointer, as well as the end of BASIC pointer at 55 ($37), is lowered to create room for those buffers when the device is opened. CLOSing the device resets these pointers.

The Kernal routine MEMTOP (65061, $FE25) may be used to read or set this pointer.

Zeiger auf das Ende des Programmspeichers

Dieser Zeiger ist der Zwilling zu dem anderen Zeiger in 641 und 642. Er wird vom Betriebssystem auf die Adresse gesetzt, welche beim Kaltstart beziehungsweise der dabei durchgeführten Prüfung des Speichers den letzten verfügbaren RAM-Speicherplatz angibt. Beim C 64 ist diese Adresse normalerweise 40960 ($A000), beim VC 20 ohne Erweiterung 7680.

Dieser Zeiger wird vom Basic-Übersetzer in die Speicherzelle 55 übernommen.

Ende des BASIC-RAM

Dieser Zeiger wird nach einem Reset oder einem Kaltstart auf den letzten verfügbaren freien RAM-Speicherplatz gesetzt.

Pointer to end of BASIC area after memory test.

Default: $A000, 40960.

Top of memory   Pointer: Top of Memory for O.S.   Pointer: Top of Memory for Operating System ($A000).   Top of Basic Memory  
$0285 TIMOUT 645
Flag: Kernal Variable for IEEE Time-Out

This location is used only with the external IEEE interface card (which was not yet available from Commodore at the time of writing). For more information, see the entry for the Kernal SETTMO routine at 65057 ($FE21).

Flagge für Ein- und Ausschalten der IEEE-488-Karte

Diese Speicherzelle ist etwas mysteriös. Sie kommt im ganzen Betriebssystem nur ein einziges Mal zum Einsatz, und zwar als Flagge beim Betrieb der sogenannten IEEE-488-Interface-Karte. Wenn diese Flagge gesetzt ist, wartet der Computer 64 Millisekunden lang, ob er von einem angeschlossenen Gerät angesprochen wird. Wenn kein Signal kommt, gibt er ein Fehlersignal aus.

Zahlen in der Zelle 645, die kleiner als 128 sind, bedeuten Flagge gesetzt, größer als 128 löschen sie die Flagge.

Timeout-Flag für seriellen IEC-Bus

Alle Zähler in dieser Speicherzelle, die größer als 128 sind, bedeuten, daß ein Gerät angeschlossen ist. Die kleineren Werte bedeuten das Gegenteil.

Unused. (Serial bus timeout.)   IEEE timeout flag   Flag: Kernal Variable for IEEE Timeout   Serial IEEE Bus timeout defeat Flag.   Serial bus timeout flag  
$0286 COLOR 646
Current Foreground Color for Text

The process of PRINTing a character to the screen consists of both placing the screen code value for the character in screen memory and placing a foreground color value in the corresponding location in color RAM. Whenever a character is PRINTed, the Operating System fetches the value to be put in color RAM from this location.

The foreground color may be changed in a number of ways. Pressing the CTRL or Commodore logo key and numbers 1-8 at the same time will change the value stored here, and thus the color being printed. PRINTing the PETASCII equivalent character with the CHR$ command will have the same effect. But probably the easiest method is to POKE the color value directly to this location. The table below lists the possible colors that may be produced, and shows how to produce them using all three methods.

POKE

COLOR # COLOR CHR$ KEYS TO PRESS
0 Black 144 CTRL-1
1 White 5 CTRL-2
2 Red 28 CTRL-3
3 Cyan 159 CTRL-4
4 Purple 156 CTRL-5
5 Green 30 CTRL-6
6 Blue 31 CTRL-7
7 Yellow 158 CTRL-8
8 Orange 129 Logo-1
9 Brown 149 Logo-2
10 Lt Red 150 Logo-3
11 Dark Gray 151 Logo-4
12 Med Gray 152 Logo-5
13 Lt Green 153 Logo-6
14 Lt Blue 154 Logo-7
15 Lt Gray 155 Logo-8
Aktuelle Farbe der Zeichen (Vordergrundfarbe)

Um ein bestimmtes Zeichen auf den Bildschirm zu drucken, muß vom Betriebssystem erstens der Bildschirmcode des Zeichens in den Bildschirmspeicher und zweitens der Codewert der gewünschten Farbe in den Farbspeicher gebracht werden.

In der Speicherzelle 646 steht immer der Codewert derjenigen Farbe, die gerade eingestellt ist. Immer wenn ein PRINT-Befehl gegeben wird, holt das Betriebssystem den Farbwert aus der Zelle 646 und bringt ihn in den Farbspeicher, und zwar an den entsprechenden Platz, wo gerade gePRINTet werden soll. Der Codewert in der Zelle 646 kann auf drei Arten eingestellt werden:

  • Drücken der CTRL-Taste gleichzeitig mit einer der Farbtasten 1 bis 8. Beim C 64 kommen noch weitere acht Farben dazu durch Drücken der Commodore-Taste anstelle der CTRL-Taste.
  • PRINT-Befehl gefolgt vom ASCII-Codewert der Farbe Innerhalb von Gänsefüßen.
  • POKEn der Farbcodes 0 bis 7 (beim C 64 0 bis 15) direkt in die Speicherzelle.

Innerhalb eines Programms Ist das POKEn in Zelle 646 wohl die eleganteste Methode (Tabelle 10).

Als Beispiel möge dieses kleine Programm dienen:

10 FOR X=0 TO 7
20 POKE 646,X
30 PRINT "A";
40 NEXT X
50 GOTO 10

Wer mehr über Vordergrund- und Hintergrundfarben erfahren will, der lese den Texteinschub Nr. 26 »Bunte Zeichen und bunter Hintergrund«.

augenblickliche Farbe

Hier wird die augenblickliche Zeichenfarbe festgelegt:

0 schwarz
1 weiß
2 rot
3 lila
4 purpur
5 grün
6 blau
7 gelb
8 orange
9 braun
10 hellrot
11 dunkelgrau
12 mittelgrau
13 hellgrün
14 hellblau
15 hellgrau
Current color, cursor color

Values: $00-$0F, 0-15.

Active color nybble   Current Character Color Code   Current Character Colour code.   Current color code  
$0287 GDCOL 647
Color of Character under Cursor

This location is used to keep track of the original color code of the character stored at the present cursor location. Since the blinking cursor uses the current foreground color at 646 ($0286), the original value must be stored here so that if the cursor moves on without changing that character, its color code can be restored to its original value.

Zeichenfarbe unter dem Cursor

Das Blinken des Cursors wird dadurch erzeugt, daß das Zeichen auf der Stelle des Bildschirms, auf der er gerade steht (meistens ist es eine Leerstelle), dauernd von »normal« auf »revers« (oder »invertiert«) und zurück geschaltet wird. Die reverse Darstellung benutzt dabei die Farbe des Zeichens.

Genauso, wie sich der Computer in der Speicherzelle 206 das Zeichen merkt, mit dem er gerade blinkt, um beim Weiterwandern dieses Zeichen in seiner »normalen« Form auf dem Bildschirm zurückzulassen, merkt er sich die Farbe dieses Zeichens in der Speicherzelle 647.

Farbe unter dem Cursor

In dieser Speicherzelle merkt sich das Betriebssystem, welche Farbe gerade unter dem Cursor steht.

Color of character under cursor

Values: $00-$0F, 0-15.

Original color before cursor   Background Color Under Cursor   Background Colour under Cursor.   Color under cursor  
$0288 HIBASE 648
Top Page of Screen Memory

This location contains the value used by the Operating System routines that print to the screen as the base address for screen RAM. The top of screen memory can be found by multiplying this location by 256. The default value for screen RAM is set on power-up to location 1024 ($0400), and this location therefore usually contains a 4.

Screen display memory on the Commodore 64 can be moved to start on any 1K boundary (location evenly divisible by 1024). This is done by manipulating the VIC-II chip memory bank select at location 56576 ($DD00).

It is important to note, however, that while any area may be displayed, the Operating System will look here to find out where it should PRINT characters. Therefore, if you change the screen location by altering the contents of one of the two addresses listed above, the Operating System will still not know where to PRINT characters unless you also change this address as well. The result will be that characters entered from the keyboard or PRINTed will not appear on the screen.

Examples of how to properly relocate the screen can be found at the entries for location 53272 ($D018) and 43 ($2B).

Since the PRINT command in essence just POKEs a lot of values to screen and color memory, by changing this pointer you can print a string of characters to memory locations other than screen RAM. For example, you could PRINT a sprite shape to memory without having to READ a lot of DATA statements. The program below PRINTs different sprite shapes into the sprite data area:

10 SP=53248:POKESP,170:POKESP+1,125:POKESP+21,1:POKE 2040,13:PRINT CHR$(147)
20 A$="THIS TEXT WILL BE PRINTED TO THE SPRITE SHAPE DATA AREA AND DISPLAYED"
30 GOSUB 100
40 A$="THIS IS SOME DIFFERENT TEXT TO BE PRINTED TO THE SPRITE SHAPE AREA"
50 GOSUB 100
60 COUNT=COUNT+1:IF COUNT<15 THEN 20
70 END
100 POKE 648,3:PRINT CHR$(19);CHR$(17);SPC$(24);A$;:POKE 648,4:RETURN

Since PRINTing also changes color memory, you can change the pointer to print the characters harmlessly to ROM, while changing a lot of screen RAM at one time, as the following program demonstrates:

10 D$=CHR(94):FOR I=1 TO 4:D$=D$+D$:NEXT
20 PRINT CHR$(147);:FOR I=1 TO 7:PRINT TAB(10) D$:NEXT:PRINT:PRINT:PRINT:PRINT
30 PRINT TAB(9);CHR$(5);"HIT ANY KEY TO STOP"
40 DIM C(15):FOR I=0TO14:READ A:C(I)=A:NEXT:DATA2,8,7,5,6,4,1,2,8,7,5,6,4,1,2
50 POKE 53281,0:POKE 648,212:FOR J=0 TO 6:PRINT CHR$(19);
60 FOR I=J TO J+6:POKE 646,C(I):PRINT TAB(10) D$:NEXT I,J
70 GET A$:IF A$="" THEN 50
80 POKE 648,4:POKE 646,1
Beginn des Bildschirmspeichers

In dieser Speicherzelle steht eine Zahl, die als High-Byte dem Betriebssystem angibt, ab welcher Speicherzelle der Bildschirmspeicher beginnt.

Nach einem Kaltstart (nach dem Einschalten oder nach dem Drücken der RESET-Taste) steht hier eine 4, das ergibt als Anfangsadresse 1024 (= 4256). Beim VC 20 ohne Erweiterung steht dort eine 30. Daraus folgt, daß die Anfangsadresse bei 7680 (= 30256) liegt.

Der Bildschirmspeicher hat keinen absolut festen Platz. Innerhalb gewisser Grenzen kann er durch Verändern des Inhalts der Speicherzelle 53272 (36869 beim VC 20) verschoben werden. Die Methode dazu ist im Texteinschub näher beschrieben. Wichtig dabei ist, daß nach dem Verschieben der Inhalt der Speicherzelle 648 entsprechend geändert wird, damit auch das Betriebssystem die Verschiebung berücksichtigt.

Umgekehrt kann aber dem Betriebssystem durch Ändern der Zahl in der Speicherzelle 648 mitgeteilt werden, daß es Zeichen in einen Speicherbereich bringen soll, der außerhalb des »offiziellen«, durch die Speicherzelle 53272 (36869) festgelegten Bildschirmspeichers liegt.

Zwei Beispiele sollen das verdeutlichen. Der PRINT-Befehl macht letztlich nichts anderes, als viele Zahlen in den Bildschirm- und den Farbspeicher zu POKEn. Wenn nun der Zeiger in Zelle 648 verschoben wird, kann man mit einem

PRINT-Befehl eine beliebige Zeichenkette außerhalb des Bildschirmspeichers speichern. Auf die gleiche Weise kann man beim C 64 Sprites mit einem PRINT- Befehl speichern, ohne mit READ viele lästige DATA-Zeilen lesen zu müssen.

HIGH-Byte Video-RAM

Dieses HIGH-Byte gibt dem Betriebssystem an, ab welcher Adresse das Video-RAM zu finden ist.

High byte of pointer to screen memory for screen input/output.

Default: $04, $0400, 1024.

Base location of screen (top)   Top of Screen Memory (Page)   High Byte of Screen Memory Address ($04).   Screen memory page  
$0289 XMAX 649
Maximum Keyboard Buffer Size

The value here indicates the maximum number of characters that the keyboard buffer at 631 ($0277) may hold at any one time. Anytime that the current buffer length in location 198 ($C6) matches the value here, further keypresses will be ignored.

Although the maximum size of the keyboard buffer is usually 10 characters, it may be possible to extend it up to 15 characters by changing the number here. This could cause the Operating System pointers to the bottom and top of memory at 641-644 ($0281-$0284) to be overwritten, but no real harm should result.

Maximale Länge des Tastaturpuffers

Der Tastaturpuffer belegt, wie schon besprochen, die Speicherzellen 631 bis 640. Er kann darin maximal 10 Zeichen Zwischenspeichern.

Der Inhalt der Speicherzelle 649 legt fest, wieviele Zellen des Tastaturpuffers verwendet werden sollen, eine Zahl also, die normalerweise zwischen 0 und 10 liegen sollte. Die 10 ist übrigens der Wert, welcher nach dem Einschalten vom Betriebssystem in die Zelle 649 gebracht wird.

Diese Zahl wird immer mit dem Inhalt der Speicherzelle 198 verglichen, der die aktuelle Anzahl der Zeichen im Tastaturpuffer angibt. Ist die Differenz der beiden Zahlen gleich Null, dann können keine weiteren Zeichen eingegeben werden.

Es ist naheliegend, daß durch Verändern der Zahl in Zelle 649 die Länge des Tastaturpuffers verändert werden kann. Der eine Extremfall ist 0:

POKE 649,0 schaltet die Tastatur aus. Nichts geht mehr.

Das kann bei Programmen oder Spielen, die durch falsches oder zeitlich unpassendes Drücken von Tasten gestört werden, recht nützlich sein. Einschalten kann man dann die Tastatur nur mit RUN/STOP und RESTORE.

Auch eine Erhöhung der Zahl in 649 über 10 hinaus ist möglich. Die Zeichen werden halt nur über die dafür reservierten Speicherzellen 631 bis 640 hinaus in Zellen geschrieben, die eigentlich eine andere Funktion haben. Bis zur Speicherzelle 645 geht das normalerweise ohne Probleme, da die betroffenen »fremden« Adressen nur direkt nach dem Einschalten des Computers gebraucht werden.

Probieren Sie es aus, indem Sie zuerst eine Zeitschleife laufen lassen und in dieser Zeit etwa 20 Tasten drücken. Am Ende der Zeitschleife wird der Inhalt des Tastaturpuffers ausgedruckt, und Sie sehen in der Tat 15 der eingegebenen Zeichen:

POKE 649,15
FOR X=0 TO 10000:NEXT X
QWERTYUIOPASDFGHJKL

Auf dem Bildschirm erscheinen die Zeichen Q bis G.

Wenn Sie die Zahl in 649 noch weiter erhöhen, dringen Sie in die Zellen 646 und 647 ein und diese bestimmen bekanntlich die Zeichenfarbe. Wenn Sie aber eine unbeabsichtigte und unkontrollierbare Farbänderung nicht stört, können Sie den Tastaturpuffer auf 17 Zeichen vergrößern. Ab 18 Zeichen stürzt der Computer ab.

Länge des Tastaturpuffers

Dieses Register gibt an, wie viele Speicherzellen des Tastaturpuffers belegt werden sollen.

Maximum length of keyboard buffer

Values:

  • $00, 0: No buffer.
  • $01-$0F, 1-15: Buffer size.
    Size of Keyboard Buffer   Maximum number of Bytes in Keyboard Buffer ($0A).   Max size of keybd buffer  
$028A RPTFLA 650
Flag: Which Keys Will Repeat?

The flag at this location is used to determine whether to continue printing a character as long as its key is held down, or whether to wait until the key is let up before allowing it to be printed again. The default value here is 0, which allows only the cursor movement keys, insert/delete key, and the space bar to repeat.

POKEing this location with 128 ($80) will make all keys repeating, while a value of 64 ($40) will disable all keys from repeating.

Flagge für Tastenwiederholung

Normalerweise steht in dieser Speicherzelle eine 0. Das bedeutet, daß die Funktion der Cursor-Tasten, der Leertaste und der INST/DEL-Taste wiederholt wird, solange die entsprechende Taste gedrückt wird.

Durch Verändern der Zahl in der Speicherzelle 650 kann diese Wiederholfunktion sowohl auf alle Tasten ausgedehnt als auch für alle Tasten gesperrt werden.

POKE 650,0

ist der Normalzustand, Wiederholfunktion für Cursor-, Leer- und INST/DEL-Taste

POKE 650,64

schaltet Wiederholfunktion für alle Tasten aus.

POKE 650,128

erweitert Wiederholfunktion auf alle Tasten.

                       
RPTFLG        
Flag für Repeatfunktion für alle Tasten

In dieser Speicherzelle wird dem Betriebssystem angegeben, welche Tasten eine Repeat-Funktion haben und welche nicht:

0 nur Cursor-, Insert/Delete- und Leertaste
64 keine Taste
128 alle Tasten
Keyboard repeat switch

Bits:

  • Bits #6-#7:
    • %00 = Only cursor up/down, cursor left/right, Insert/Delete and Space repeat
    • %01 = No key repeats
    • %1x = All keys repeat.
Key repeat flag   Flag: REPEAT Key Used, $80 = Repeat   Flag: Repeat keys; $00 = Cursors, INST/DEL & Space repeat, $40 no Keys repeat, $80 all Keys repeat ($00).   Repeat all keys  
$028B KOUNT 651
Counter for Timing the Delay Between Key Repeats

This location is used as a delay counter to determine how long to wait while a key is being held down until the next repeat printing of that key.

The value here starts at 6. If location 652 ($028C) contains a 0, the value in this location is counted down once every 1/60 second, so long as the same key is held down. When this counter gets to 0, and if the repeat flag at 650 ($028A) allows that key to repeat, its ASCII equivalent will once again be placed in the keyboard buffer. A value of 4 is then placed in location 651, allowing subsequent repeats to occur at a rate of 15 per second.

Zähler für Wiederholgeschwindigkeit der Tasten

Das Betriebssystem verwendet diese Speicherzelle als Zähler, der die Geschwindigkeit bestimmt, mit der eine Taste wiederholt wird, wenn sie länger gedrückt wird. Voraussetzung ist die durch Zelle 650 festgelegte Wiederholbarkeit der Taste. Am Anfang steht in der Zelle 651 die Zahl 6. Sobald eine wiederholbare Taste gedrückt wird, zählt das Betriebssystem diese Zahl alle 0,0167 Sekunden (60mal in der Sekunde) um 1 zurück, bis die Zahl 1 erreicht ist. Dann erst wird das Zeichen der gedrückten Taste wieder auf den Bildschirm gedruckt oder ihre Funktion wiederholt.

Bei jedem folgenden Lauf steht in Zelle 651 die Zahl 4. Entsprechend verkürzt sich der Zählvorgang.

Am schnellsten würde die Wiederholung natürlich mit dem Wert 1 in der Speicherzelle 651 sein. Von Basic aus mit POKE 651,1 geht das leider nicht.

Im Texteinschub Nr. 27 »Turbo-Tasten« wird ein Maschinenprogramm beschrieben, welches dies kann.

Zähler für Repeatgeschwindigkeit

Diese Speicherzelle dient als Zähler, die die Repeat-Geschwindigkeit festlegt.

Delay counter during repeat sequence, for delaying between successive repeats

Values:

  • $00, 0: Must repeat key.
  • $01-$04, 1-4: Delay repetition.
    Repeat Speed Counter   Repeat Key: Speed Counter ($04).   Repeat speed counter  
$028C DELAY 652
Counter for Timing the Delay Until the First Key Repeat Begins

This location is used as a delay counter to determine how long a key must be held down before the entry of that key should be repeated.

The initial value of 16 is counted down every 1/60 second, as long as the same key remains pressed. When the value gets to 0, location 651 ($028B) is counted down from 6, and the key is repeated when the value there reaches 0. Thus a total of 22/60, or approximately 1/3, second will elapse before the first repeat of a key. The value here will be held to 0 after the first repeat, so that subsequent keystroke repititions occur much more quickly.

Zähler für die Ansprechzeit der Wiederholfunktion von Tasten

Diese Speicherzelle wird vom Betriebssystem als Zähler verwendet, der festlegt, wie lange eine wiederholbare Taste gedrückt sein muß, bis die Wiederholfunktion einsetzt.

Am Anfang steht in der Zelle 652 die Zahl 16. Diese Zahl wird alle 0,0167 Sekunden um 1 reduziert, bis die Zahl 0 erreicht ist. Dann wird das Zeichen der Taste auf den Bildschirm gebracht oder ihre Funktion wiederholt. Anschließend wird die Zahl 4 in die Speicherzelle 651 geschrieben (siehe dort), während die Zelle 652 so lange auf 0 stehen bleibt, bis eine andere Taste gedrückt wird. Wie diese anfängliche Verzögerung reduziert werden kann, steht im Texteinschub Nr. 27 »Turbo-Tasten«.

Zähler für Repeatverzögerung

Hier wird angegeben, wie lange eine Taste gedrückt sein muß, bis die Repeat-Funktion einsetzt.

Repeat sequence delay counter, for delaying before first repetition

Values:

  • $00, 0: Must start repeat sequence.
  • $01-$10, 1-16: Delay repeat sequence.
    Repeat Delay Counter   Repeat Key: First repeat delay Counter ($10).   Repeat delay counter  
$028D SHFLAG 653
Flag: SHIFT/CTRL/Logo Keypress

This flag signals which of the SHIFT, CTRL, or Commodore logo keys are currently being pressed, if any.

A value of 1 signifies that one of the SHIFT keys is being pressed, a 2 shows that the Commodore logo key is down, and 4 means that the CTRL key is being pressed. If more than one key is held down, these values will be added; for example, a 3 indicates that SHIFT and logo are both held down.

The value here is used by the Operating System when determining how to convert a keypress into a PETASCII character. There are four different tables used to translate one of the 64 keys on the keyboard matrix into a PETASCII character, and the combination of special SHIFT keys determines which of these tables will be used (see the entry for location 245 ($F5) for more details on the keyboard tables).

Pressing the SHIFT and Commodore logo keys at the same time will toggle the character set that is presently being used between the uppercase/graphics set, and the lowercase/uppercase set (provided that the flag at 657 ($0291) has not been set to disable this switch).

This changes the appearance of all of the characters on the screen at once. It has nothing whatever to do with the keyboard shift tables, however, and should not be confused with the printing of SHIFTed characters, which affects only one character at a time. Rather, it is the result of the value of the character dot data table base address in 53272 ($D018) being changed. The came result may be obtained by POKEing that address directly.

Tastencode der SHIFT-, CTRL- und Commodore-Taste

In der Speicherzelle 203 stehen die Codes aller Tasten, die gedrückt werden, außer die der drei Steuertasten SHIFT, CTRL und Commodore (oft auch CBM-, Logo- oder C=-Taste genannt). Diese drei Ausnahmen haben ihr eigenes Code-Register, eben 653.

Der Grund dafür liegt in der Bedeutung der drei Tasten. Sie können ja bekanntlich verschiedene Zeichensätze einschalten:

  • SHIFT schaltet das Zeichen vorne rechts auf einerTaste ein
  • C= schaltet das Zeichen vorne links auf einer Taste ein
  • CTRL schaltet die Farben vorn auf den Zahlentasten ein
  • SHIFT + C= schaltet von dem normalen Zeichensatz auf die Groß-/ Kleinschreibung um.

Ich habe diese Zusammenhänge auch bei der Behandlung der Speicherzellen 245 und 246 erwähnt.

Die Codezahlen selbst sind auch in der Tabelle 9 enthalten. Der Vollständigkeit halber sind sie hier noch einmal angegeben:

SHIFT 1
C= 2
CTRL 4
SHIFT und C= 3
SHIFT und CTRL 5
C= und CTRL 6
SHIFT und C= und CTRL 7

Mit dem folgenden kleinen Programm und mit ein wenig Fingerfertigkeit können Sie diese Codewerte nachvollziehen:

10 PRINT PEEK(653)
20 GOTO 10

Eine interessante Anwendung habe ich im Texteinschub Nr. 21 »Abfrage der Tastencodes oder 476 Funktionstasten« gegeben.

Flag für SHIFT, Commodore und CTRL

In diesem Register stehen die Tastencodes der Steuertasten:

1 SHIFT
2 Commodore
3 SHIFT und Commodore
4 CTRL
5 SHIFT und CTRL
6 Commodore und CTRL
7 SHIFT, Commodore und CTRL
Shift key indicator

Bits:

  • Bit #0: 1 = One or more of left Shift, right Shift or Shift Lock is currently being pressed or locked.
  • Bit #1: 1 = Commodore is currently being pressed.
  • Bit #2: 1 = Control is currently being pressed.
SHIFT flag byte   Flag: Keyboard SHIFT Key/CTRL Key/C= Key   Flag: Shift Keys: Bit 1 = Shift, Bit 2 = CBM, Bit 3 = CTRL; ($00 = None, $01 = Shift, etc.).   Keyboard Shift/Control flag  
$028E LSTSHF 654
Last Pattern of SHIFT/CTRL/Logo Keypress

This location is used in combination with the one above to debounce the special SHIFT keys. This will keep the SHIFT/logo combination from changing character sets back and forth during a single pressing of both keys.

Tastencode der zuletzt gedrückten SHIFT-, CTRL-oder C=-Taste

Diese Speicherzelle wird zusammen mit der Zelle 653 verwendet, um zu verhindern, daß ein schlechter Tastendruck als mehrfaches Drücken derselben Taste gedeutet wird. Im Fachdeutsch nennt man das »Entprellen« einer Taste oder eines Kontaktes. Die Funktion ist vergleichbar mit der der Zelle 197 gegenüber der Zelle 203 für alle anderen Tasten.

SHIFT-Flag

Hier steht die zuletzt gedrückte Steuertaste.

Previous value of shift key indicator

Bits:

  • Bit #0: 1 = One or more of left Shift, right Shift or Shift Lock was pressed or locked at the time of previous check.
  • Bit #1: 1 = Commodore was pressed at the time of previous check.
  • Bit #2: 1 = Control was pressed at the time of previous check.
Last SHIFT pattern   Last Keyboard Shift Pattern   Last Shift Key used for debouncing.   Last shift pattern  
$028F-$0290 KEYLOG 655-656
Vector to Keyboard Table Setup Routine

This location points to the address of the Operating System routine which actually determines which keyboard matrix lookup table will be used.

The routine looks at the value of the SHIFT flag at 653 ($028D), and based on what value it finds there, stores the address of the correct table to use at location 245 ($F5).

The interrupt driven keyboard-scanning routine jumps through this RAM vector to get to the table setup routine. Therefore, it is possible to alter the address contained in this vector, and direct the keyscan routine to your own routine, which can check the keypress and SHIFT combination, and act before a character is printed.

Since this routine comes after the keypress, but before it is printed, this is a very good place to have your preprocessor routine check for a particular keypress. An excellent example of such a program is the "VICword" program by Mark Niggemann, COMPUTE!'s Second Book of VIC. This program adds a machine language routine that checks if the SHIFT or Commodore logo key is pressed while not in quote mode. If it finds one of these keypresses, it substitutes an entire BASIC keyword for the letter (A-Z) of the key that was pressed. An adaptation of that program for the 64 appears below.

100 IF PEEK(PEEK(56)*256)<>120THENPOKE56,PEEK(56)-1:CLR
110 HI=PEEK(56):BASE=HI*256
120 PRINTCHR$(147)"READING DATA"
130 FOR AD=0 TO 211:READ BY
140 POKE BASE+AD,BY:NEXT AD
150 :
200 REM RELOCATION ADJUSTMENTS
210 POKE BASE+26,HI:POKE BASE+81,HI
220 POKE BASE+123,HI:POKE BASE+133,HI
230 :
240 PRINT CHR$(147) TAB(15)"***64WORD***":PRINT
250 PRINT"TO TOGGLE THE PROGRAM ON/OFF:":PRINT:PRINT:PRINT "SYS";BASE;
260 PRINT CHR$(145);CHR$(145);
270 DATA 120,173,143,2,201,32
280 DATA 208,12,169,220,141,143
290 DATA 2,169,72,141,144,2
300 DATA 88,96,169,32,141,143
310 DATA 2,169,0,141,144,2
320 DATA 88,96,165,212,208,117
330 DATA 173,141,2,201,3,176
340 DATA 110,201,0,240,106,169
350 DATA 194,133,245,169,235,133
360 DATA 246,165,215,201,193,144
370 DATA 95,201,219,176,91,56
380 DATA 233,193,174,141,2,224
390 DATA 2,208,3,24,105,26
400 DATA 170,189,159,0,162,0
410 DATA 134,198,170,160,158,132
420 DATA 34,160,160,132,35,160
430 DATA 0,10,240,16,202,16
440 DATA 12,230,34,208,2,230
450 DATA 35,177,34,16,246,48
460 DATA 241,200,177,34,48,17
470 DATA 8,142,211,0,230,198
480 DATA 166,198,157,119,2,174
490 DATA 211,0,40,208,234,230
500 DATA 198,166,198,41,127,157
510 DATA 199,2,230,198,169,20
520 DATA 141,119,2,76,72,235
530 DATA 76,224,234
550 REM TOKENS FOR SHIFT KEY
570 DATA 153,175,199,135,161,129
580 DATA 141,164,133,137,134,147
590 DATA 202,181,159,151,163,201
600 DATA 196,139,192,149,150,155
610 DATA 191,138
630 REM TOKENS FOR COMMODORE KEY
650 DATA 152,165,198,131,128,130
660 DATA 142,169,132,145,140,148
670 DATA 195,187,160,194,166,200
680 DATA 197,167,186,157,165,184
690 DATA 190,158,0

Commodore 64word: Keys into BASIC Commands

Key SHIFT Commodore
A PRINT PRINT#
B AND OR
C CHR$ ASC
D READ DATA
E GET END
F FOR NEXT
G GOSUB RETURN
H TO STEP
I INPUT INPUT#
J GOTO ON
K DIM RESTORE
L LOAD SAVE
M MID$ LEN
N INT RND
O OPEN CLOSE
P POKE PEEK
Q TAB( SPC(
R RIGHT$ LEFT$
S STR$ VAL
T IF THEN
U TAN SQR
V VERIFY CMD
W DEF FN
X LIST FRE
Y SIN COS
Z RUN SYS
Vektor auf die Routine der Tastencode-Tabellen

Das Betriebssystem hat eine Routine ab Adresse 60232 (60380 beim VC 20), auf die der Vektor in 655 und 656 zeigt. Sie liest den Codewert derSHIFT-, CTRL- und C=-Taste in der Speicherzelle 653 aus und verändert entsprechend den Vektor der Zellen 245 und 246, so daß er auf die richtige Codetabelle zeigt. Es gibt Anwenderprogramme, die diesen Vektor so verbiegen, daß die Decodierung der Tasten umgangen und durch eine andere, selbstgebaute Routine ersetzt wird. So kann zum Beispiel das Drücken einer bestimmten Taste umgemünzt werden in Ausdrucken von Basic-Befehlen auf dem Bildschirm.

Zeiger für Tastatur-Dekodierung

Hier steht ein Zeiger, der auf die Betriebssystemroutine für die Tastatur- Dekodierung zeigt.

Execution address of routine that, based on the status of shift keys, sets the pointer at memory address $F5-$F6 to the appropriate conversion table for converting keyboard matrix codes to PETSCII codes.

Default: $EB48.

Indirect for keyboard table setup   Vector: Keyboard Table Setup   Vector: Routine to determine Keyboard table to use based on Shift Key Pattern ($EB48).   Keyboard table setup pointer  
$0291 MODE 657
Flag: Enable or Disable Changing Character Sets with SHIFT/Logo Keypress

This flag is used to enable or disable the feature which lets you switch between the uppercase/graphics and upper/lowercase character sets by pressing the SHIFT and Commodore logo keys simultaneously.

This flag affects only this special SHIFT key function, and does not affect the printing of SHIFTed characters. POKEing a value of 128 ($80) here will disable this feature, while POKEing a value of 0 will enable it once more. The same effect can be achieved by PRINTing CHR$(8) or CTRL-H to disable the switching of character sets, and CHR$(9) or CTRL-I to enable it. See entries for locations 53272 ($D018) and 49152 ($C000) for more information on switching character sets.

Flagge für Verriegelung der Zeichensatz-Umschaltung

Durch gleichzeitiges Drücken der SHIFT- und der Commodore-Taste wird bekanntlich der Zeichensatz 1 (Großbuchstaben und Grafik-Zeichen) umgeschaltet auf den Zeichensatz 2 (Groß- und Kleinbuchstaben), ein zweites Drücken der beiden Tasten schaltet den Zeichensatz zurück.

Diese Umschaltung wird verriegelt, wenn in der Speicherzelle 657 eine 128 steht. Eine 0 läßt die Umschaltung zu.

Dieser Effekt kann auf zwei, beim C 64 sogar auf drei Arten erzielt werden:

  • Umschaltung des Zeichensatzes zulassen

    POKE 657,0 PRINT CHR$(9) CTRL und I (nur C 64)

  • Umschaltung des Zeichensatzes verriegeln

    POKE 657,128 PRINT CHR$(8) CTRL und H (nur C 64)

Flag für SHIFT/Commodore gesperrt

Falls in der Speicherzelle eine 128 steht, wird eine Umschaltung mit SHIFT/Commodore verriegelt. Bei einer 0 wird die Umschaltung zugelassen.

Commodore-Shift switch

Bits:

  • Bit #7: 0 = Commodore-Shift is disabled; 1 = Commodore-Shift is enabled, the key combination will toggle between the uppercase/graphics and lowercase/uppercase character set.
0-PET mode, 1-cattacanna   Flag: $00=Disable SHIFT Keys, $80=Enable   Flag: Upper/Lower Case change: $00 = Disabled, $80 = Enabled ($00).   Keyboard shift mode  
$0292 AUTODN 658
Flag: Screen Scrolling Enabled

This location is used to determine whether moving the cursor past the fortieth column of a logical line will cause another physical line to be added to the logical line.

A value of 0 enables the screen to scroll the following lines down in order to add that line; any nonzero value will disable the scroll. This flag is set to disable the scroll temporarily when there are characters waiting in the keyboard buffer (these may include cursor movement characters that would eliminate the need for a scroll).

Flagge für Scrollen

Die Flagge in dieser Speicherzelle legt fest, ob eine weitere echte Zeile zu einer logischen Zeile hinzugefügt wird, sobald der Cursor über das 40ste Zeichen der Zeile (22ste Zeichen beim VC 20) hinausläuft.

Steht in 658 eine 0, dann werden alle Zeilen hochgeschoben (man nennt das »scrollen«), um der neuen Zeile Platz zu machen.

Wenn in der Zeile irgendein Wert größer als Null steht, unterbleibt dieses Scrollen. Die Flagge wird immer dann auf den höheren Wert gesetzt, wenn Zeichen im Tastaturpuffer (631 bis 640) stehen und darauf warten, am Ende des Programms ausgedruckt beziehungsweise ausgeführt zu werden. Diese Verriegelung wird deshalb eingesetzt, weil im Tastaturpuffer Zeichen wie zum Beispiel Cursor- Bewegungen stehen können.

Von Basic aus kann diese Speicherzelle nicht beeinflußt werden.

Flag für Scrollen

Wenn in dieser Speicherzelle eine 0 steht, setzt der Scroll-Vorgang ein. Bei einem größeren Wert setzt dieser Vorgang nicht ein.

Scroll direction switch during scrolling the screen

Values:

  • $00: Insertion of line before current line, current line and all lines below it must be scrolled 1 line downwards.
  • $01-$FF: Bottom of screen reached, complete screen must be scrolled 1 line upwards.
Auto scroll down flag(=0 on,<>0 off)   Flag: Auto Scroll Down, 0 = ON   Flag: Auto scroll down: $00 = Disabled ($00).   0 = scroll enable  
$0293-$0297 659-663
RS-232 Pseudo 6551 Registers

For serial Input/Output via the RS-232 port, the internal software of the Commodore 64 emulates the operation of a 6551 UART chip (that's Universal Asynchronous Receiver/Transmitter, for you acronym buffs), also known as an ACIA (Asynchronous Communications Interface Adapter).

These RAM locations are used to mimic the functions of that chip's hardware command, control, and status registers. Although RAM locations are allocated for mimicking the 6551's ability to use either an on-board baud rate generator or an external clock crystal, this function is not implemented by the internal software.

Provisions have been made for the user to communicate with these registers through the RS-232 OPEN command. When device 2 is opened, a filename of up to four characters may be appended. These four characters are copied to locations 659-662 ($0293-$0296), although the last two, which specify a nonstandard baud rate, are not used because that feature is not implemented.

                           
$0293 M51CTR 659
RS-232: Mock 6551 Control Register

This location is used to control the RS-232 serial I/O baud rate (speed at which data is transmitted and received), the word length (number of bits per data character), and the number of stop bits used to mark the end of a transmitted character. It uses the same format as that of the 6551 UART control register to set these parameters, although, as you will see, some of the 6551 configurations are not implemented by the software that emulates the UART device. For example, the standard baud rates which are higher than 2400 baud are not implemented, presumably because the software cannot keep up at higher rates. The meanings of the various bit patterns are as follows:

Bit 7: STOP Bits

Bit Value
0 0 1 STOP Bit
1 128 0 STOP Bits

Bits 6-5: WORD LENGTH

Bit Value
00 0 8 DATA Bits
01 32 7 DATA Bits
10 64 6 DATA Bits
11 96 5 DATA Bits

Bit 4: Unused

Bits 3-0: BAUD RATE

Bit Value
0000 0 Nonstandard (User-Defined Rate (Not Implemented)
0001 1 50 Baud
0010 2 75 Baud
0011 3 110 Baud
0100 4 134.5 Baud
0101 5 150 Baud
0110 6 300 Baud
0111 7 600 Baud
1000 8 1200 Baud
1001 9 1800 Baud
1010 10 2400 Baud
1011 11 3600 Baud (Not Implemented on the Commodore 64)
1100 12 4800 Baud (Not Implemented on the Commodore 64)
1101 13 7200 Baud (Not Implemented on the Commodore 64)
1110 14 9600 Baud (Not Implemented on the Commodore 64)
1111 15 19200 Baud (Not Implemented on the Commodore 64)

This register is the only one which must be set when opening RS-232 device (number 2). The first character of the filename will be stored here. For example, the statement OPEN 2,2,0,CHR$(6+32) will set the value of this location to 38. As you can see from the above chart, this sets up the RS-232 device for a data transfer rate of 300 baud, using seven data bits per character and one stop bit.

RS232-Steuerregister

Jeder OPEN-Befehl, mit dem bekanntlich eine Datei (File) eröffnet wird, kann neben File-Nummer und Geräte-Nummer auch einen File-Namen haben. Der File-Namen einer RS232-Schnittstelle hat maximal nur vierZeichen. Das erste Zeichen wird in diese Speicherzelle 659 gebracht und steuert dort Übertragungsgeschwindigkeit, die Wortlänge und die Anzahl der Stopp-Bits. Die nähere Bedeutung dieser Fachwörter können Sie dem Texteinschub Nr. 29 »Die Elemente der RS232-Schnittstelle« entnehmen. Tabelle 11 zeigt die Bedeutung jedes einzelnen Bits dieser Speicherzelle.

Die praktische Anwendung dieser Bit-Werte innerhalb eines OPEN-Befehls ist ausführlich im Texteinschub Nr. 30 »Die Programmierung der RS232-Schnittstelle« beschrieben.

RS-232 Kontrollwert

Hier wird die Übertragungsgeschwindigkeit der RS-232 Schnittstelle festgelegt: Bits 0-3 steuern die Übertragungsgeschwindigkeit:

Bitmuster Wert Baudrate
0000 0 50 Baud
0001 1 50 Baud
0010 2 75 Baud
0011 3 110 Baud
0100 4 134.5 Baud
0101 5 150 Baud
0110 6 300 Baud
0111 7 600 Baud
1000 8 1200 Baud
1001 9 1800 Baud
1010 10 2400 Baud

Bit 4 nicht belegt Die Bits 5 und 6 steuern die Länge der Übertragung:

Bitmuster Wert Länge
00 0 8-Bit
01 32 7-Bit
10 64 6-Bit
11 96 5-Bit

Bit 7 gibt die Anzahl der STOP-Bits an:

Bitmuster Wert Anzahl
0 0 1-STOP-Bit
1 128 2-STOP-Bits
RS232 control register

Bits:

  • Bits #0-#3: Baud rate, transfer speed. Values:
    • %0000: User specified.
    • %0001: 50 bit/s.
    • %0010: 75 bit/s.
    • %0011: 110 bit/s.
    • %0100: 150 bit/s.
    • %0101: 300 bit/s.
    • %0110: 600 bit/s.
    • %0111: 1200 bit/s.
    • %1000: 2400 bit/s.
    • %1001: 1800 bit/s.
    • %1010: 2400 bit/s.
    • %1011: 3600 bit/s.
    • %1100: 4800 bit/s.
    • %1101: 7200 bit/s.
    • %1110: 9600 bit/s.
    • %1111: 19200 bit/s.
  • Bits #5-#6: Byte size, number of data bits per byte; %00 = 8; %01 = 7, %10 = 6; %11 = 5.
  • Bit #7: Number of stop bits; 0 = 1 stop bit; 1 = 2 stop bits.
6551 control register   RS-232: 6551 Control Register Image   RS232 Pseudo 6551 control Register Image.   RS-232 control reg  
$0294 M51CDR 660
RS-232: Mock 6551 Command Register

This location performs the same function as the 6551 UART chip's command register, which specifies type of parity, duplex mode, and handshaking protocol.

The type of parity used determines how the 64 will check that RS-232 data is received correctly.

The duplex mode can be either full duplex (the 64 will be able to transmit at the same time it is receiving) or half duplex (it will take turns sending and receiving).

The handshaking protocol has to do with the manner in which the sending device lets the receiver know that it is ready to send data, and the receiver lets the sender know that it has gotten the data correctly. The meanings of the bit patterns in this register are as follows:

Bits 7-5: Parity

Bit Value
XX0 0, 64, 128, or 192 No Parity Generated or Received
001 32 Odd Parity Transmitted and Received
011 96 Even Parity Transmitted and Received
101 160 Mark Parity Transmitted and Received
111 224 Space Parity Transmitted and Received

Bit 4: Duplex

Bit Value
0 0 Full Duplex
1 16 Half Duplex

Bits 3-1: Unused

Bit 0: Handshake Protocol

Bit Value
0 0 3 Line
1 1 X Line

This register can be set at the user's option when opening RS-232 device (number 2). The second character of the filename will be stored here. For example, the statement

OPEN 2,2,0,CHR$(6+32)+CHR$(32+16)

will set the value of this location to 48, which is the value of the second character in the filename portion of the statement. As you can see from the above chart, this configures the RS-232 device for half duplex data transfer using odd parity and three-line handshaking.

RS232-Befehlsregister

In diese Speicherzelle wird, ähnlich wie bei der Zelle 659, das zweite Zeichen des File-Namens gebracht. Die einzelnen Bits steuern das Handshake-Protokoll (3-/X-Leitung), den Duplex-Modus (Halb-/Voll-Duplex) und die Parity-Prüfung (keine, gerade, ungerade). Die nähere Bedeutung dieser Fachwörter können Sie dem Texteinschub Nr. 11 »Die Elemente der RS232-Schnittstelle« entnehmen. Tabelle 12 zeigt die Bedeutungjedes einzelnen Bits dieser Speicherzelle.

Wenn Sie sich für die praktische Anwendung dieser Bit-Werte innerhalb eines OPEN-Befehls interessieren, dann verweise ich an dieser Stelle auf den Texteinschub Nr. 30 »Die Programmierung der RS232-Schnittstelle«.

RS-232 Befehlswort

Die einzelnen Bits steuern das 'Handshake'-Protokol1.

RS232 command register

Bits:

  • Bit #0: Synchronization type; 0 = 3 lines; 1 = X lines.
  • Bit #4: Transmission type; 0 = Duplex; 1 = Half duplex.
  • Bits #5-#7: Parity mode. Values:
    • %xx0: No parity check, bit #7 does not exist.
    • %001: Odd parity.
    • %011: Even parity.
    • %101: No parity check, bit #7 is always 1.
    • %111: No parity check, bit #7 is always 0.
6551 command register   RS-232: 6551 Command Register Image   RS232 Pseudo 6551 command Register Image.   RS-232 command reg  
$0295-$0296 M51AJB 661-662
RS-232: Nonstandard Bit Timing

These locations are provided for storing a nonstandard user-defined baud rate, to be used when the low nybble of the control register at 659 ($0293) is set to 0. They were presumable provided to conform to the nodel of the 6551 UART device, which allows a nonstandard baud rate to be generated from an external reference crystal. However, the software emulation of that feature is not provided in the current version of the Kernal, and thus these locations are currently nonfunctional.

Nonetheless, Commodore has specified that if the nonstandard baud rate feature is implemented, the value placed here should equal the system clock frequency divided by the baud rate divided by 2 minus 100, stored in low byte, high byte order. The system clock frequency for American television monitors (NTSC standard) is 1.02273 MHz, and for European monitors (PAL standard) .98525 MHz.

RS232 frei wählbare Übertragungsgeschwindigkeit

Es war ursprünglich vorgesehen, durch entsprechendeWahl des dritten und vierten Zeichens im File-Namen beliebige Übertragungsgeschwindigkeiten einzustellen. Die jeweiligen Werte sollten die Speicherzellen 661 und 662 enthalten. Diese Möglichkeit wurde aber nicht eingebaut. Der Grund dafür dürfte wohl der sein, daß die wählbaren Übertragungsgeschwindigkeiten aller Geräte auf bestimmte Werte normiert sind.

Bit-Timing

Die Möglichkeit, eine freiwählbare Übertragungsgeschwindigkeit einzustellen, wurde vorgesehen, aber nicht eingebaut.

Default value of RS232 output timer, based on baud rate

(Must be filled with actual value before RS232 input/output if baud rate is "user specified" in RS232 control register, memory address $0293.)

Non standard (bittime/2-100)   RS-232 Non-Standard BPS (Time/2-100) USA   RS232 Non-standard Bits/Second.   Bit timing  
$0297 RSSTAT 663
RS-232: Mock 6551 Status Register

The contents of this register indicate the error status of RS-232 data transmission. That status can be determined by PEEKing this location directly, by referencing the BASIC reserved variable ST, or by using the Kernal READST (65031, $FE07) routine.

Note that if you use ST or Kernal, this location will be set to 0 after it is read. Therefore, if you need to test more than one bit, make sure that each test preserves the original value, because you won't be able to read it again. The meaning of each bit value is specified below:

Bit Value
7 128 1 = Break Detected
6 64 1 = DTR (Data Set Ready) Signal Missing
5 Unused
4 16 1 = CTS (Clear to Send) Signal Missing
3 8 1 = Receiver Buffer Empty
2 4 1 = Receiver Buffer Overrun
1 2 1 = Framing Error
0 1 1 = Parity Error

The user is responsible for checking these errors and taking appropriate action. If, for example, you find that Bit 0 or 1 is set when you are sending, indicating a framing or parity error, you should resend the last byte. If Bit 2 is set, the GET#2 command is not being executed quickly enough to empty the buffer (BASIC should be able to keep up at 300 baud, but not higher). If Bit 7 is set, you will want to stop sending, and execute a GET#2 to see what is being sent.

RS232-Statusregister

Genauso wie in der Speicherzelle 144 der Status aller Ein- und Ausgabe- Operationen angezeigt wird, werden alle Fehler der RS232-Schnittstelle in der Speicherzelle 663 angezeigt. Die Bedeutung der einzelnen Bits, wenn sie auf 1 gesetzt sind, zeigt Tabelle 14.

Der Status wird nicht automatisch angezeigt, sondern muß vom Programm abgefragt werden. Abfragen können Sie sowohl durch PEEKen der Speicherzelle 663 als auch durch Aufrufen der Statusvariablen ST. Die Variable ST, die normalerweise den Inhalt der Zelle 144 wiedergibt, schaltet nach dem Eröffnen eines RS232-Kanals durch OPEN 1,2 auf die Speicherzelle 663 um. Jedoch ist Vorsicht geboten, da durch Aufruf von ST der Inhalt von 663 gelöscht wird.

Es ist ratsam, den Wert von ST erst einer anderen Variablen zuzuordnen, wenn sie mehrfach verwendet werden soll.

Falls das Status-Register einen Fehler anzeigt, muß das Programm entsprechende Konsequenzen ziehen. Wenn zum Beispiel Bit 0 oder Bit 1 gesetzt sind, ist es angebracht, das letzte Daten-Byte noch einmal zu übertragen. Wenn Bit 2 gesetzt ist, heißt dies, daß der GET #-Befehl den Eingabepufferspeicher nicht schnell genug entleert. Falls die Übertragungsgeschwindigkeit von 300 Bit/s, die maximal mit einem Basic-Programm erreichbar ist, nicht ausreicht, muß entweder der Sender langsamer eingestellt werden, oder Sie schreiben das Programm in Maschinensprache.

RS-232 Status

Hier werden die Fehlermeldungen der RS-232 Schnittstelle angezeigt:

Bit Wert Bedeutung
0 1 Fehler bei Parity-Prüfung
1 2 Fehler in der Bitfolge
2 4 Überlauf des Eingabepuffers
3 8 Eingabepuffer ist leer
4 16 das CTS-Signal fehlt
5 32 nicht belegt
6 64 Das DSR-Signal fehlt
7 128 Die Übertragung ist unterbrochen
Value of ST variable, device status for RS232 input/output

Bits:

  • Bit #0: 1 = Parity error occurred.
  • Bit #1: 1 = Frame error, a stop bit with the value of 0, occurred.
  • Bit #2: 1 = Input buffer underflow occurred, too much data has arrived but it has not been read from the buffer in time.
  • Bit #3: 1 = Input buffer is empty, nothing to read.
  • Bit #4: 0 = Sender is Clear To Send; 1 = Sender is not ready to send data to receiver.
  • Bit #6: 0 = Receiver reports Data Set Ready; 1 = Receiver is not ready to receive data.
  • Bit #7: 1 = Carrier loss, a stop bit and a data byte both with the value of 0, detected.
RS-232 status register   RS-232: 6551 Status Register Image   RS232 Pseudo 6551 Status Register Image.   RS-232 status  
$0298 BITNUM 664
RS-232: Number of Bits Left to be Sent/Received

This location is used to determine how many zero bits must be added to the data character to pad its length out to the word length specified in 659 ($0293).

RS232 - Anzahl der zu übertragenden Bits

Diese Speicherzelle wird verwendet, um festzustellen, mit wievielen Nullen das zu übertragende Zeichen aufgefüllt werden muß, um die in Speicherzelle 659 (Bit 5 und 6) ausgewählte Wortlänge herzustellen (s. Speicherzellen 168 und 180).

Anzahl der Datenbits für RS-232

Diese Speicherzelle wird verwendet, um die Wortlänge festzustellen.

RS232 byte size, number of data bits per data byte, default value for bit counters.   Number of bits to send (fast response)   RS-232 Number of Bits Left to Send   RS232 Number of Bits left to send.   # bits to send  
$0299-$029A BAUDOF 665-666
Time Required to Send a Bit

This location holds the prescaler value used by CIA #2 timers A and B.

These timers cause an NMI interrupt to drive the RS-232 receive and transmit routines CLOCK/PRESCALER times per second each, where CLOCK is the system 02 frequency of 1,022,730 Hz (985,250 if you are using the European PAL television standard rather than the American NTSC standard), and PRESCALER is the value stored at 56580-1 ($DD04-5) and 56582-3 ($DD06-7), in low-byte, high-byte order. You can use the following formula to figure the correct prescaler value for a particular RS-232 baud rate:

PRESCALER=((CLOCK/BAUDRATE)/2)-100

The American (NTSC standard) prescaler values for the standard RS-232 baud rates which the control register at 659 ($0293) makes available are stored in a table at 65218 ($FEC2), starting with the two-byte value used for 50 baud. The European (PAL standard) version of that table is located at 58604 ($E4EC).

RS232 - Zeit, die zum Übertragen eines Bits gebraucht wird

Sobald ein RS232-Kanal eröffnet worden ist, berechnet das Betriebssystem einen Wert, der die Zeitdauer eines Bits festlegt. Da die Übertragungsrate in Speicherzelle 659 einstellbar ist, hängt diese Bit-Dauer von der gewählten Übertragungsgeschwindigkeit ab. Die Bit-Dauer errechnet sich aus der Systemfrequenz (985,25 kHz) geteilt durch die Übertragungsgeschwindigkeit. Dieser Wert steht in Low-/High-Byte-Darstellung in diesen beiden Speicherzellen, von wo aus er vom Betriebssystem abgerufen wird.

RS-232 Baud-Rate

Die Übertragungsrate errechnet sich aus der Systemfrequenz (985.25) KHz dividiert duch die Baudrate. Dieser Wert steht in LOW- und HIGH-Byte-Darstellung in den beiden Speicherzellen. Er wird vom Betriebssystem abgerufen.

Default value of RS232 input timer, based on baud rate

(Calculated automatically from default value of RS232 output timer, at memory address $0295-$0296.)

Baud rate full bit time (created by open)   RS-232 Baud Rate: Full Bit Time (us)   RS232 Baud Rate; Full Bit time microseconds.   RS-232 speed/code  
$029B-$029E 667-670
Byte Indices to the Beginning and End of Receive and Transmit Buffers

The two 256-byte First In, First Out (FIFO) buffers for RS-232 data reception and transmission are dynamic wraparound buffers. This means that the starting point and the ending point of the buffer can change over time, and either point can be anywhere withing the buffer. If, for example, the starting point is at byte 100, the buffer will fill towards byte 255, at which point it will wrap around to byte 0 again. To maintain this system, the following four locations are used as indices to the starting and the ending point of each buffer.

                           
$029B RIDBE 667
RS-232: Index to End of Receive Buffer

This index points to the ending byte within the 256-byte RS-232 receive buffer, and is used to add data to that buffer.

RS232-Index auf das Ende des Eingabepufferspeichers

Dieser Index wird verwendet, um Daten in den Eingabepufferspeicher zu schreiben. Wenn man ihn nämlich zum Inhalt der Speicherzelle 247/248 addiert, erhält man die Adresse des zuletzt in den Eingabepufferspeicher eingegebenen Bytes.

Zeiger für empfangenes Byte RS-232

Wenn man den Inhalt der Speicherzelle mit dem Wert in $F7-$F8 addiert, erhält man die Adresse des zuletzt im Eingabepuffer eingegebenen Bytes.

Offset of byte received in RS232 input buffer.   Input buffer index to end   RS-232 Index to End of Input Buffer   RS232 Index to End of Input Buffer.   RS232 receive pointer  
$029C RIDBS 668
RS-232: Index to Start of Receive Buffer

This index points to the starting byte within the 256-byte RS-232 receive buffer, and is used to remove data from that buffer.

RS232-Index auf den Anfang des Eingabepufferspeichers

Dieser Index wird verwendet, um Daten aus dem Eingabepufferspeicher auszulesen. Wenn man ihn nämlich zum Inhalt der Speicherzelle 247 und 248 addiert, erhält man die Adresse des ersten in den Eingabepufferspeicher eingegebenen Bytes.

Zeiger auf Input von RS-232

Wenn man den Inhalt der Speicherzelle mit dem Wert in $F7-$F8 addiert, erhält man die Adresse des ersten im Eingabepuffer eingegebenen Bytes.

Offset of current byte in RS232 input buffer.   Input buffer pointer to start   RS-232 Start of Input Buffer (Page)   RS232 Pointer: High Byte of Address of Input Buffer.   RS232 input pointer  
$029D RODBS 669
RS-232: Index to Start of Transmit Buffer

This index points to the starting byte within the 256-byte RS-232 transmit buffer, and is used to remove data from that buffer.

RS232-Index auf den Anfang des Ausgabepufferspeichers

Dieser Index wird verwendet, um Daten aus dem Ausgabepufferspeicher auszulesen. Wenn man ihn nämlich zum Inhalt der Speicherzelle 249 und 250 addiert, erhält man die Adresse des ersten in den Ausgabepufferspeicher eingegebenen Bytes.

Zeiger auf zu Übertragendes Byte RS-232

Wenn man den Inhalt der Speicherzelle mit dem Wert in $F9-$FA addiert, erhält man die Adresse des ersten im Ausgabepuffer eingegebenen Bytes.

Offset of byte to send in RS232 output buffer.   Output buffer index to start   RS-232 Start of Output Buffer (Page)   RS232 Pointer: High Byte of Address of Output Buffer.   RS232 transmit pointer  
$029E RODBE 670
RS-232: Index to End of Transmit Buffer

This index points to the ending byte within the 256-byte RS-232 transmit buffer, and is used to add data to that buffer.

RS232-Index auf das Ende des Ausgabepufferspeichers

Dieser Index wird verwendet, um Daten in den Ausgabepufferspeicher zu schreiben. Wenn man ihn nämlich zum Inhalt der Speicherzelle 249 und 250 addiert, erhält man die Adresse des zuletzt in den Ausgabepufferspeicher eingegebenen Bytes.

Zeiger auf Ausgabe auf RS-232

Wenn man den Inhalt der Speicherzelle mit dem Wert in $F9-$FA addiert, erhält man die Adresse des zuletzt im Ausgabepuffer eingegebenen Bytes.

Offset of current byte in RS232 output buffer.   Output buffer index to end   RS-232 Index to End of Output Buffer   RS232 Index to End of Output Buffer.   RS232 output pointer  
$029F-$02A0 IRQTMP 671-672
Save Area for IRQ Vector During Cassette I/O

The routines that read and write tape data are driven by an IRQ interrupt. In order to hook one of these routines into the interrupt, the RAM IRQ vector at 788-789 ($0314-$0315) must be changed to point to the address at which it starts. Before that change is made, the old IRQ vector address is saved at these locations, so that after the tape I/O is finished, the interrupt that is used for scanning the keyboard, checking the stop key, and updating the clock can be restored.

You will note that all of the above functions will be suspended during tape I/O.

Zwischenspeicher für den IRQ-Vektor während Kassetten-Ein-/Ausgabe

Die Routinen des Betriebssystems, die Daten auf, beziehungsweise von Kassette ein- und ausgeben, werden durch die Interrupt-Routine gesteuert. Diese Routine unterbricht normalerweise 60mal in der Sekunde alle Aktivitäten des Computers, um diverse »Hausaufgaben« (Uhr weiterschalten, STOP-Taste abfragen und so weiter) auszuführen. Bei Kassetten-Ein-/Ausgaben ist diese Interrupt-Routine jedoch abgeschaltet. Dies wird dadurch erreicht, daß der Vektor in Speicherzelle 788 und 789, der auf die Anfangsadresse der Interrupt-Routine zeigt, auf eine Adresse der Kassetten-Routine gesetzt wird. Um nach der Kassettenoperation weitermachen zu können, wird der »alte« Interrupt-Vektor in dieser Speicherzelle 671 und 672 gespeichert.

Speicher für IRQ während Bandbetrieb

Bei Kassettenoperationen wird hier in LOW- und HIGH-Byte-Darstellung der Vektor für die Interruptroutine gespeichert.

Temporary area for saving pointer to original interrupt service routine during datasette input output

Values:

  • $00-$FF: No datasette input/output took place yet or original pointer has been already restored.
  • $0100-$FFFF: Original pointer, datasette input/output currently in progress.
Holds irq during tape ops   Holds IRQ Vector During Tape I/O   Temporary store for IRQ Vector during Tape operations.   IRQ save during tape I/O  
$02A1 ENABL 673
RS-232 Interrupts Enabled

This location holds the active NMI interrupt flag byte from CIA #2 Interrupt Control Register (56589, $DD0D). The bit values for this flag are as follows:

Bit Value
4 16 1 = System is Waiting for Receiver Edge
1 2 1 = System is Receiving Data
0 1 1 = System is Transmitting Data
bei C 64: Flagge für RS232-Interrupt bei VC 20: frei verfügbar

Diese Speicherzelle enthält den Wert des Interrupt-Steuerregisters 56589, das die RS232-Schnittstelle steuert. Die Bedeutung der einzelnen Bits, wenn sie auf 1 gesetzt sind, zeigt Tabelle 15. Diese Flagge kann zu Steuerzwecken abgefragt werden. Um beispielsweise ein Programm warten zu lassen, bis der Ausgabepufferspeicher geleert ist, gibt man die Anweisung

100 IF (PEEK(673) AND 1) THEN 100

die das Programm so lange aufhält, bis die Übertragung abgeschlossen und Bit O der Flagge gelöscht ist.

Die folgenden 4 Speicherzellen, nämlich 674 bis 678, werden nur vom C 64 benutzt. Beim VC 20 sind sie nicht belegt und können frei verwendet werden.

CIA 2 NMI-Flag

Diese Speicherzelle erhält den Wert des Interruptsteuerregisters, das die RS-232 Schnittstelle steuert.

Temporary area for saving original value of CIA#2 interrupt control register, at memory address $DD0D, during RS232 input/output.   RS-232 enables (replaces ier)   RS-232 Enables   RS232 Enables.   CIA 2 (NMI) Interrupt Control  
$02A2 CASTON 674 Indicator of CIA #1 Control Register B Activity During Cassette I/O  
Indikator für das Steuerregister A des CIA #1

Mit CIA werden die beiden »Complex Interface Adapter« des C 64 bezeichnet. Das sind integrierte Schaltkreise, die Ein- und Ausgabeoperationen steuern. Jeder der beiden CIAs hat mehrere Register. Das Steuerregister A (Adresse 56334 beziehungsweise $DC0E) beeinflußt die Zählregister des CIA, die ihrerseits die Ein- und Ausgabe von Daten auf beziehungsweise von Kassetten steuern. Das Betriebssystem speichert zu diesem Zweck geeignete Bitmuster in der Speicherzelle 674 ab, die von da in das Steuerregister transferiert werden.

CIA 1 Timer A

Bei Bandroutinen wird hier das HIGH-Byte von Timer A zwischengespeichert.

Temporary area for saving original value of CIA#1 timer #1 control register, at memory address $DC0E, during datasette input/output.   TOD sense during cassettes   TOD Sense During Cassette I/O   TOD sense during Tape I/O.   CIA 1 Timer A control log  
$02A3-$02A4 675-676             Unknown.                  
$02A3 KIKA26 675 Save Area for CIA #1 Interrupt Control Register During Cassette Read  
Speicher für das Interrupt- Steuerregister B des CIA #1

Ein weiteres Register (Adresse 56333 beziehungsweise $DC0D) ist für die Unterbrechungen (Interrupt) des Computers bei Ein- und Ausgaben zuständig.

In der Speicherzelle 675 werden Werte dieses Interruptregisters beim Lesen von der Kassette zwischengespeichert.

CIA 1 Interruptflag

Bei Bandroutinen wird in dieser Speicherzelle festgelegt, welche IRQs freigegeben sind und welche nicht.

    Cassette: holds old D1ICR after clear on read   Temp Storage For Cassette Read   Temporary storage during Tape READ.   CIA 1 Interrupt Log  
$02A4 STUPID 676 Save Area for CIA #1 Control Register A During Cassette Read  
Zusatzspeicher für Steuerregister B des CIA #1

Derselbe Wert, der bei der Vorbereitung des Lesevorganges von der Kassette in die Speicherzelle 674 kommt, gelangt auch nach 676, von wo er zu einem späteren Zeitpunkt beim Lesen zu Vergleichszwecken herangezogen wird.

CIA 1 Flag für Timer A

Hier wird bei Bandroutinen angegeben, ob Timer A läuft oder nicht. Wenn hier eine $00 steht, ist der Timer freigegeben, andernfalls ist er gesperrt.

    Cassette: hold indicator (NZ - no T1IRQ yet) for T1IRQ   Temp D1 IRQ Indicator For Cassette Read   Temporary D1IRQ Indicator during Tape READ.   CIA 1 Timer A enabled flag  
$02A5 LINTMP 677 Temporary Index to the Next 40-Column Line for Screen Scrolling  
Zwischenspeicher für das Link-Byte während des Bildschirm-Scrollens

Das Betriebssystem enthält eine Routine, welche den Bildschirminhalt hochschiebt (scrollt), sobald eine leere Zeile eingeschoben wird. Das bedeutet, daß jedesmal die Angaben in den Link-Tabellen der Speicherzellen 217 bis 241 geändert werden müssen. In der Speicherzelle 677 wird nun das Link-Byte zwischengespeichert, während der obere Teil des Bildschirms hochgeschoben wird. Beim VC 20 gibt es diese Funktion übrigens auch. Sie wird durch die Speicherzelle 242 ausgefüllt.

Bildschirmzeile   Number of line currently being scrolled during scrolling the screen.   Temporary for line index   Temp For Line Index   Temporary for Line Index.   Screen row marker  
$02A6 PALNTS 678
PAL/NTSC Flag

At power-on, a test is performed to see if the monitor uses the NTSC (North American) or PAL (European) television standard.

This test is accomplished by setting a raster interrupt for scan line 311, and testing if the interrupt occurs. Since NTSC monitors have only 262 raster scan lines per screen, the interrupt will occur only if a PAL monitor is used. The results of that test are stored here, with a 0 indicating an NTSC system in use, and one signifying a PAL system.

This information is used by the routines which set the prescaler values for the system IRQ timer, so that the IRQ occurs every 1/60 second. Since the PAL system 02 clock runs a bit slower than the NTSC version, this prescaler value must be adjusted accordingly.

Flagge für PAL oder NTSC

Im Gegensatz zum VC 20, der entweder fest auf die deutsche Fernsehnorm PAL oder aber auf die amerikanische Norm NTSC eingestellt ist, kann der C 64 beide Normen verkraften. Diese beiden Normen beziehen sich unter anderem auf die Anzahl der Zeilen und auf die Abtast-Geschwindigkeit des Lichtstrahls im Fernsehgerät oder im Monitor. Das Betriebssystem des C 64 überprüft gleich beim Einschalten, ob eine Rasterzeile 311 im angeschlossenen Sichtgerät vorhanden ist. Ist sie nicht vorhanden, muß alles auf die NTSC-Norm eingestellt werden, da diese nur 262 Rasterzeilen hat und mit einer internen Taktfrequenz von 14,3 MHz läuft. Ist eine Rasterzeile 311 vorhanden, wird auf PAL-Norm eingestellt mit einer Taktfrequenz von 17,7 MHz. Das Resultat dieses Tests wird in der Speicherzelle 678 gespeichert: als 0 für NTSC und 1 für PAL.

Flag für PAL- (1) o. NTSC-Version (0)

Hier steht ein Wert, der angibt, ob es sich um eine PAL- oder eine NTSC- Version handelt.

PAL/NTSC switch, for selecting RS232 baud rate from the proper table

Values:

  • $00: NTSC.
  • $01: PAL.
PAL vs NTSC flag 0=NTSC 1=PAL   PAL/NTSC Flag, 0= NTSC, 1 = PAL   Flag: TV Standard: $00 = NTSC, $01 = PAL.      
$02A7-$02FF 679-767
Unused

The programmer may use this area for machine language subroutines, or for graphics data storage.

If the VIC-II ship is using the bottom 16K for graphics and memory (the default setting when the system is turned on), this is one of the few free areas available for storing sprite or character data. Locaitons 704-767 could be used for sprite data block number 11, without interfering with BASIC program text or variables.

nicht belegt

Diese 89 Byte sind frei und können für alle möglichen Programme und Anwendungen verwendet werden. Beim VC 20 stehen sogar 95 Byte zur Verfügung, da der freie Bereich ja schon ab Speicherzelle 673 beginnt. Dieser Speicherbereich hat den Vorteil, daß er - wie der Kassettenpuffer ja auch - von Basic nicht gestört wird. Er kann also für kleinere Maschinenprogramme oder auch für Sprite-Blöcke verwendet werden. Gegenüber dem Kassettenpuffer hat dieser Bereich den Vorteil, daß er durch Kassettenoperationen nicht gestört wird.

    Unused (89 bytes).       Unused   Unused.      
$0300-$030B 768-779
BASIC Indirect Vector Table

Several important BASIC routines are vectored through RAM. This means that the first instruction executed by the routine is an indirect jump to a location pointed to by one of the vectors in this table.

On power up, the system sets these vectors to point to the next instruction past the original JuMP instruction. The routine then continues with that instruction as if the jump never took place. For example, the BASIC error message routine starts at 42039 ($A437) with the instruction JMP ($0300). The indirect vector at 768 ($0300) points to 42042 ($A43A), which is the instruction immediately following JMP ($0300).

Although this may seem like a fancy way of accomplishing nothing, using these indirect vectors serves two important purposes. First, it allows you to use these important BASIC routines without knowing their addresses in the BASIC ROM.

For example, the routine to LIST the ASCII text of the single-byte BASIC program token that is currently in the Accumulator (.A) is located at one address in the VIC, and another in the 64. On future Commodore computers it may be found at still another location. Yet as long as the routine is vectored in RAM at 774 ($0306), the statement QP=PEEK(774)+256*PEEK(775) would find the address of that routine on any of the machines. Thus, entering such routines through RAM vectors rather than a direct jump into the ROMs helps to keep your programs compatible with different machines.

The other important effect of having these vectors in RAM is that you can alter them. In that way, you can redirect these important BASIC routines to execute your own preprocessing routines first.

If you wanted to add commands to BASIC, for example, how would you go about it? First, you would need to change the BASIC routines that convert ASCII program text to tokenized program format, so that when a line of program text was entered, the new keyword would be stored as a token.

Next, you would need to change the routine that executes tokens, so that when the interpreter comes to your new keyword token, it will take the proper action.

You would also have to change the routine that converts tokens back to ASCII text, so that your program would LIST the token out correctly. And you might want to alter the routine that prints error messages, to add new messages for your keyword.

As you will see, vectors to all of these routines can be found in the following indirect vector table. Changing these vectors is a much more elegant and efficient solution than the old wedge technique discussed at location 115 ($73)

Die nächsten 12 Speicherzellen enthalten 6 Vektoren, deren Bedeutung bei der Übersetzung von Basic-Programmen im Texteinschub Nr. 31 »Indirekte Sprung- Vektoren« näher erklärt wird.

                       
$0300-$0301 IERROR 768-769
Vector to the Print BASIC Error Message Routine

This vector points to the address of the ERROR routine at 58251 ($E38B).

Vektor auf die Ausgabe von Fehler-Meldungen (ERROR)

Dieser Vektor zeigt auf die Anfangsadresse der Basic-Routine, welche für die leidigen Fehlermeldungen zuständig ist. Beim C 64 zeigt der Vektor auf 58251 ($E38B), beim VC 20 auf 50234 ($C438).

Diese Routine verwendet eine Tabelle im Basic-Übersetzer, in der alle Fehlermeldungen gespeichert sind. Sie liegt im Speicherbereich 41374 bis 41767 (beim VC 20 49566 bis 49959). Die Routine verwendet den Inhalt des X-Registers (siehe Speicherzelle 781), um die entsprechende Fehlermeldung ganz einfach durch Abzählen der Reihenfolge aus der Tabelle auszulesen und auf dem Bildschirm anzuzeigen.

Ein Verbiegen dieses Vektors ist für zwei Anwendungsfälle sinnvoll. Man kann die Fehlermeldung abschalten, um zu prüfen, ob ein bestimmtes Peripherie-Gerät, zum Beispiel das Floppylaufwerk, angeschlossen beziehungsweise eingeschaltet ist. Die Fehlermeldung ist abschaltbar mit POKE 768,61. Wieder eingeschaltet wird sie mit POKE 768,139. Ein Anwendungsbeispiel habe ich bereits im Texteinschub Nr. 14 »ST-atus« gebracht.

Die zweite Anwendung einer Verbiegung zielt auf eine Übersetzung der Fehlermeldungen. Wem der vorgegebene englische - und manchmal nicht gerade einleuchtende - Text der Fehlermeldungen nicht gefällt, kann den Vektor auf einen Speicherbereich legen, in dem er seine speziellen deutschen Fehlermeldungen speichert. Eine genaue Kenntnis der Fehlermeldungsroutine ist dazu allerdings erforderlich.

(Die nächsten 12 Speicherzellen enthalten 6 Vektoren, deren Bedeutung bei der Übersetzung von Basic-Programmen im Texteinschub Nr. 31 »Indirekte Sprung- Vektoren« näher erklärt wird.)

$E38B Vektor für BASIC-Warmstart  
Execution address of warm reset, displaying optional BASIC error message and entering BASIC idle loop.

Default: $E38B.

indirect ERROR (output error in .X)   Vector: Print BASIC Error Message   Vector: Indirect entry to BASIC Error Message, (X) points to Message ($E38B).   Error message link  
$0302-$0303 IMAIN 770-771
Vector to the Main BASIC Program Loop

This vector points to the address of the main BASIC program loop at 42115 ($A483). This is the routine that is operating when you are in the direct mode (READY). It executes statements, or stores them as program lines.

Vektor auf die Hauptroutine zur Ausführung von Basic-Befehlen

Dieser Vektor zeigt auf die Adresse 42115 ($A483), beim VC 20 auf 50307 ($C483). Die dort beginnende Routine steuert den Direkt-Modus, indem sie entweder direkt eingegebene Befehle ausführt oder mit Zeilennummer eingegebene Anweisungen speichert.

$A483 Vektor für Eingabe einer Zeile  
Execution address of BASIC idle loop.

Default: $A483.

indirect MAIN (system direct loop)   Vector: BASIC Warm Start   Vector: Indirect entry to BASIC Input Line and Decode ($A483).   Basic warm start link  
$0304-$0305 ICRNCH 772-773
Vector to the Routine That Crunches the ASCII Text of Keywords into Tokens

This vector points to the address of the CRUNCH routine at 42364 ($A57C).

Vektor auf die Basic-Routine, die ASCII-Text in Token umwandelt

Dieser Vektor zeigt auf 42364 ($A57C), beim VC 20 auf 50556 ($C57C). Dort beginnt eine Routine, die nach dem Drücken der RETURN-Taste alle Anweisungen der damit eingegebenen Zeile absucht und Text beziehungsweise Wörter, die nicht zwischen Gänsefüßen stehen, als Basic-Befehle interpretiert und sie dann in sogenannte »Token« umwandelt. Token sind Codezahlen, die im Computer anstelle von Textbefehlen verwendet werden. Sie sind im Texteinschub Nr. 32 »Die Kurzschrift von Basic« näher beschrieben.

Dieser Vektor kann verbogen werden, um zusätzliche Basic-Befehle zu erfinden und in das Betriebssystem einzubauen.

$A57C Vektor für Umwandlung in Interpretercode  
Execution address of BASIC line tokenizater routine.

Default: $A57C.

indirect CRUNCH (tokenization routine)   Vector: Tokenize BASIC Text   Vector: Indirect entry to BASIC Tokenise Routine ($A57C).   Crunch Basic tokens link  
$0306-$0307 IQPLOP 774-775
Vector to the Routine That Lists BASIC Program Token as ASCII Text

This vector points to the address of the QPLOP routine at 42778 ($A71A).

Vektor auf die Basic-Routine, die Token in ASCII-Werte zurückwandelt (LIST)

Dieser Vektor zeigt auf die Adresse 42778 ($A71A), beim VC 20 auf 50970 ($C71A). Dort beginnt eine Routine, die Token wieder in LISTbaren Text umwandelt. Sie steht nicht allein, sondern wird als Unterprogramm von der LIST- Routine verwendet.

Falls ein Programmierer spezielle zusätzliche Basic-Befehle erfunden hat, kann er durch Verbiegen dieses Vektors seine eigenen Token lesbar ausLISTen.

Man kann auch durch eine entsprechende Verbiegung erreichen, daß die LIST- Routine nicht angesprungen werden kann, was gleichbedeutend ist mit einer LIST- Sperre. Das ist aber wohl nur sinnvoll bei einem Autostart-Programm.

Besser finde ich da ein kleines Programm, das J. Pellechi in der Zeitschrift RUN, Ausgabe 6/85 (Seite 10), angegeben hat:

10 FOR J=679 TO 688
20 READ K
30 POKE J,K
40 NEXT J
50 POKE 774,167:POKE 775,2
60 NEW
70 DATA 72,173,141
80 DATA 2,208,251,104
90 DATA 76,26,167

Beim VC 20 ist nur die Zeile 90 verschieden:

90 DATA 76,26,199

In den freien Speicherbereich ab Speicherzelle 679 wird ein kleines Maschinenprogramm gePOKEt, das in den DATA-Zeilen 70 bis 90 steht. In Zeile 50 steht der für unser Beispiel entscheidende Befehl: Der Vektor in 774 und 775 wird nach der Adresse 679 verbogen. Dadurch springt die LIST-Routine immer zuerst auf die Adresse 679, in der sie das kleine Maschinenprogramm findet.

Disassembliert schaut das so aus:

02A7 48 PHA
02A8 AD 8D 02  LDA 028D
02AB D0 FB     BNE 02A8
02AD 68 PLA
02AE 4C 1A A7  JMP A71A

Zuerst wird der Akkumulator mit dem Inhalt der Speicherzelle 653 ($028D) geladen. Dort steht bekanntlich eine Zahl von 1 bis 7, je nachdem, ob die SHIFT-, CTRL- oder Commodore-Taste gedrückt ist. Ist dies der Fall, springt das Programm auf die Adresse 680 zurück und bildet so eine Dauerschleife, bis die Taste wieder losgelassen wird. Erst dann geht es weiter mit der ursprünglichen Zieladresse des Vektors in 774 und 775, nämlich $A71A (42778) beziehungsweise $C71A (50970) beim VC 20.

Auf diese Weise können Sie das LISTen eines Programms mit einer der drei genannten Tasten anhalten.

$A71A Vektor für Umwandlung in Klartext (LIST)  
Execution address of BASIC token decoder routine.

Default: $A71A.

indirect LIST (char list)   Vector: BASIC Text LIST   Vector: Indirect entry to BASIC LIST Routine ($A71A).   Print tokens link  
$0308-$0309 IGONE 776-777
Vector to the Routine That Executes the Next BASIC Program Token

This vector points to the address of the GONE routine at 42980 ($A7E4) that executes the next program token.

Vektor auf die Basic-Routine, die den nächsten Befehl liest und ausführt

Dieser Vektor zeigt auf die Adresse 42980 ($A7E4), beim VC 20 auf 51172 ($C7E4). Diese Routine prüft das nächste Token, ob es gültig ist. Wenn der ASCII-Wert des Token kleiner als 128 ist, wird er als Zeichen einerVariablen angesehen, und das System springt auf die LET-Routine. Das erklärt, warum zur Definition einer Variablen der LET-Befehl auch weggelassen werden kann.

Durch Verbiegen dieses Vektors kann zum Beispiel eine Trace-Routine gebaut werden, welche zuerst die Nummer der Zeile ausdruckt, die gerade ausgeführt wird, bevor sie auf die ursprüngliche Zieladresse des Vektors zurückkehrt.

$A7E4 Vektor für BASIC-Befehlsadresse holen  
Execution address of BASIC instruction executor routine.

Default: $A7E4.

indirect GONE (char dispatch)   Vector: BASIC Char. Dispatch   Vector: Indirect entry to BASIC Character dispatch Routine ($A7E4).   Start new Basic code link  
$030A-$030B IEVAL 778-779
Vector to the Routine That Evaluates a Single-Term Arithmetic Expression

This vector points to the address of the EVAL routinea t 44678 ($AE86) which, among other things, is used to evaluate BASIC functions such as INT and ABS.

Vektor auf die Basic-Routine, die einen numerischen Ausdruck in eine Gleitkommazahl umwandelt

Dieser Vektor zeigt auf 44675 ($AE83), beim VC 20 auf 52867 ($CE83). Hier beginnt eine Routine, die einen einzelnen numerischen Wert, wenn er Teil eines Ausdrucks ist, von seinem ASCII-Wert in eine Gleitkomma-Zahl umwandelt.

Ist der Ausdruck eine Konstante, wird diese Umwandlung durchgeführt.

Ist der Ausdruck eine Variable, wird ihr Zahlenwert aus dem Variablenspeicher geholt.

Ist der Ausdruck die Zahl »pi«, wird der Zahlenwert für »pi« in den Gleitkomma-Akkumulator gebracht.

$AE86 Vektor für Ausdruck auswerten  
Execution address of routine reading next item of BASIC expression.

Default: $AE86.

indirect EVAL (symbol evaluation)   Vector: BASIC Token Evaluation   Vector: Indirect entry to BASIC Token evaluation ($AE86).   Get arithmetic element link  
$030C-$030F 780-783
Register Storage Area

The BASIC SYS command uses this area to store 6510 internal registers--the Accumulator (.A), the .X and .Y index registers, and the status register, .P.

Before every SYS command, each of the registers is loaded with the value found in the corresponding storage address. After the ML program finished executing, and returns to BASIC with an RTS instruction, the new value of each register is stored in the appropriate storage address. This is only true of SYS, not of the similar USR command.

This feature allows you to place the necessary preentry values into the registers from BASIC before you SYS to a Kernal or BASIC ML routine. It also enables you to examine the resulting effect of the routine on the registers, and to preserve the condition of the registers on exit for subsequent SYS calls.

An extremely practical application comes immediately to mind. Although the 64's BASIC 2 has many commands for formatting printed characters on the monitor screen (for example, TAB, SPC, PRINT A$,B), there is none to adjust the vertical cursor position.

There is a Kernal routine, PLOT (58634, $E50A), which will allow you to position the cursor anywhere on the screen. In order to use it, you must first clear the carry flag (set it to 0), and then place the desired horizontal column number in the .Y register and the vertical row number in the .X register before entering the routine with a SYS 65520. Using the register storage area, we can print the work HELLO at row 10, column 5 with the following BASIC line:

POKE 781,10:POKE 782,5:POKE 783,0:SYS 65520:PRINT "HELLO"

You can also use these locations to help you take advantage of Kernal routines that return information in the register. For example, the SCREEN routine (58629,$E505) returns the number of screen rows in the .Y register, and the number of columns in the .X register. Using this routine, a BASIC program could be written to run on machines with different screen formats (for example, the 64 and the VIC-20). Just PEEK(781) after a SYS 65517 to see how many screen columns the computer display has.

Speicher für Register

Der SYS-Befehl holt aus den nächsten vier Speicherzellen alle notwendigen Parameter, die für ein mit SYS zu startendes Maschinenprogramm notwendig sind. Er speichert sie in die vier Register des Mikroprozessors 6510 (beim VC 20 heißt er 6502). Es sind dies:

  • der Akkumulator
  • das X-Register
  • das Y-Register
  • das P-(Status-)Register

Die Bedeutung der Register ist im Assembler-Kurs erklärt worden.

Normalerweise funktioniert der SYS-Befehl nur, wenn vorher schon alle Parameter des aufgerufenen Maschinenprogramms richtig vorhanden sind, was meistens nicht der Fall ist.

So können Sie zum Beispiel mit Aufrufen der Load-Routine durch SYS 62622 nichts ausrichten, weil die für LOAD erforderlichen Parameter, nämlich Gerätenummer, File-Namen, Anfangs- und Endadresse, nicht festgelegt sind.

Wie dies mit Hilfe der vier folgenden Register-Speicherzellen erreichbar ist, hat Rolf Zweifel schon in der Ausgabe 7/84, Seite 131 erklärt. Weil das aber schon lange her ist und weil es hier so schön in den Kurs paßt, wiederhole ich dieses Thema im Texteinschub Nr. 33 »Der vorbereitete SYS-Befehl«.

                       
$030C SAREG 780 Storage Area for .A Register (Accumulator)   Speicher für den Akkumulator   Akku für SYS-Befehl   Default value of register A for SYS.
Value of register A after SYS.
 
.A reg   Storage for 6502 .A Register   Storage for 6510 Accumulator during SYS.   SYS A-reg save  
$030D SXREG 781 Storage Area for .X Index Register   Speicher für das X-Register   X-REG für SYS-Befehl   Default value of register X for SYS.
Value of register X after SYS.
 
.X reg   Storage for 5502 .X Register   Storage for 6510 X-Register during SYS.   SYS X-reg save  
$030E SYREG 782 Storage Area for .Y Index Register   Speicher für das Y-Register   Y-REG für SYS-Befehl   Default value of register Y for SYS.
Value of register Y after SYS.
 
.Y reg   Storage for 6502 .Y Register   Storage for 6510 Y-Register during SYS.   SYS Y-reg save  
$030F SPREG 783
Storage Area for .P (Status) Register

The Status (.P) register has seven different flags. Their bit assignments are as follows:

Bit Value
7 128 Negative
6 64 Overflow
5 32 Not Used
4 16 BREAK
3 8 Decimal
2 4 Interrupt Disable
1 2 Zero
0 1 Carry

If you wish to clear any flag before a SYS, it is safe to clear them all with a POKE 783,0. The reverse is not true, however, as you must watch out for the Interrupt disable flag.

A 1 in this flag bit is equal to an SEI instruction, which turns off all IRQ interrupts (like the one that reads the keyboard, for example). Turning off the keyboard could make the computer very difficult to operate! To set all flags except for Interrupt disable to 1, POKE 783,247.

Speicher für das Statusregister   tatus-Register für SYS-Befehl   Default value of status register for SYS.
Value of status register after SYS.
 
.P reg   Storage for 6502 .SP Register   Storage for 6510 Status Register during SYS.   SYS status reg save  
$0310-$0312 USRPOK 784-786    
Sprungbefehl und wählbare Sprungadresse des USR-Befehls

Mit dem Basic-Befehl USR wird bekanntlich ein Maschinenprogramm gestartet. Diese drei Speicherzellen werden bei der Abwicklung von USR verwendet. In ihnen muß der Anwender des USR-Befehls die Zieladresse in Low-/High-Byte-Darstellung angeben, ab der das Maschinenprogramm im Speicher steht.

Dieser Vorgang ist bereits behandelt worden bei den Speicherzellen 0 bis 2 des VC 20, die ja genau den Speicherzellen 784 bis 786 des C 64 entsprechen.

Speziell für den C 64 ist der USR-Befehl noch einmal behandelt, und zwar im Texteinschub Nr. 34 »Das Mauerblümchen USR«.

(Diese drei Speicherzellen 784 bis 786 sind beim VC 20 nicht belegt. Beim C 64 entsprechen sie den Adressen 0 bis 2 des VC 20.)

    JMP ABS machine instruction, jump to USR() function.   user function dispatch           USR function jump ($B248)  
$0310 784
Jump Instruction for User Function ($4C)

The value here (67, $4C) is first part of the 6510 machine language JuMP instruction for the USR command.

                USR Function Jump Instr (4C)   USR Function JMP Instruction ($4C).      
$0311-$0312 USRADD 785-786
Address of USR Routine (Low Byte First)

These locations contain the target address of the USR command. They are initialized by the Operating System to point to the BASIC error message handler routine, so that if you try to execute a USR call without changing these values, you wil receive an ILLEGAL QUANTITY error message.

In order to successfully execute a USR call, you must first POKE in the target address in low-byte, high-byte order. You can calculate these two values for any address with the formula:

HI=INT(AD/256):LO=AD-(HI*256)

For example, if the USR routine started at 49152 ($C000), you would POKE 786, INT(49152/256):POKE 785,49152-(PEEK(786)*256 before executing the USR command.

What makes the USR command different from SYS is that you can pass a parameter into the machine language routine by placing it in parenthesis after the USR keyword, and you can pass a parameter back to a variable by assigning its value to the USR function.

In other words, the statement X=USR(50) will first put the number 50 in floating point format into the Floating Point Accumulator (FAC1) at 97-102 ($61-$66). Then, the machine language program designated by the address at this vector will be executed. Finally, the variable X will be assigned the floating point value which ends up in FAC1 after the user-written routine is finished.

Since floating point representation is difficult to work with, it is handy to change these floating point parameters into integers before working with them. Fortunately, there are vectored routines which will do the conversions for you. The routine vectored at locations 3-4 converts the number in FAC1 to a two-byte signed integer, with the low byte in the .Y register (and location 101 ($65)) and the high byte in the Accumulator (.A). Remember, that number is converted to a signed integer in the range between 32767 and -32768, with Bit 7 of the high byte used to indicate the sign.

To pass a value back through the USR function, you need to place the number into FAC1. To conert a signed integer to floating point format, place the high byte into the Accumulator (.A), the low byte into the .Y register, and jump through the vector at locations 5-6 with a JMP ($05) instruction. The floating point result will be left in FAC1.

    $B248 USR-Vektor   Execution address of USR() function.       USR Address Low Byte / High Byte   USR Address ($LB,$MB).      
$0313 787 Unused  
beim C 64 und VC 20 nicht belegt

Während dieses freie Byte des C 64 nicht viel nutzt, haben VC 20-Besitzer immerhin vier aufeinanderfolgende freie Byte für eigene Vektoren und andere zwischenzuspeichernde Werte zur Verfügung, die nie in Gefahr geraten, von einem Basic-Programm überschrieben zu werden.

    Unused.       Unused   Unused.      
$0314-$0315 CINV 788-789
Vector to IRQ Interrupt Routine

This vector points to the address of the routine that is executed when an IRQ interrupt occurs (normally 59953 ($EA31)).

At power on, the CIA #1 Timer B is set to cause an IRQ interrupt to occur every 1/60 second. This vector is set to point to the routine which updates the software clock and STOP key check, blinks the cursor, maintains the tape interlock, and reads the keyboard. By changing this vector, the user can add or substitute a machine language routine that will likewise execute every 1/60 second. The user who is writing IRQ interrupt routines should consider the following:

  1. It is possible for an IRQ interrupt to occur while you are changing this vector, which would cause an error from which no recovery could be made. Therefore, you must disable all IRQ interrupts before changing the contents of this location, and reenable them afterwards, by using the 6510 SEI and CLI instructions, or by using the Kernal VECTOR routine (64794, $FD1A) to set this vector.

  2. There is some code in ROM that is executed before the interrupt routine is directed through this vector. This code checks whether the source of the interrupt was an IRQ or BRK instruction. If first preserves the contents of all the registers by pushing them onto the stack in the following sequence: PHA, TXA, PHA, TYA, PHA. It is up to the user to restore the stack at the end of his routine, either by exiting through the normal IRQ, or with the sequence: PLA, TAY, PLA, TAX, PLA, RTI.

  3. There is only one IRQ vector, but there are many sources for IRQ interrupts (two CIA chips, and several VIC chip IRQs). If you plan to enable IRQs from more than one source, the IRQ routine here must determine the source, and continue the routine in the appropriate place for an IRQ from that source.

In the same vein, if you replace the normal IRQ routine with your own, you should be aware that the keyboard's scanning and clock update will not occur unless you call the old interrupt routine once every 1/60 second. It is suggested that if you plan to use that routine, you save the old vector address in some other location. In that way, you can JuMP to the keyboard interrupt routine through this alternate vector, rather than assuming that the ROM address will never change and that it is safe to jump into the ROM directly.

Vektor auf die IRQ-Interrupt-Routine des Betriebssystems

Dieser Vektor zeigt auf die Adresse 59953 ($EA31) - beim VC 20 auf 60095 ($EABF). Ab hier beginnt die Routine des Betriebssystems, die den IRQ-Interrupt ausführt. Die Bedeutung der verschiedenen Interrupts (Unterbrechungen), ihre Auslöser und Abläufe sind als Übersicht im Texteinschub Nr. 35 »Dem Computer ins Wort fallen« dargestellt.

Die IRQ-Routine wird vom Timer A des Ein-/Ausgabe-Bausteins CIA #1 - beim VC 20 vom Timer 1 des Ein-/Ausgabe-Bausteins VIA #2 - ausgelöst, und zwar periodisch 60mal in jeder Sekunde. In der Programmpause werden die im Texteinschub beschriebenen »Haushaltsarbeiten« durchgeführt.

Dieser Vektor eignet sich hervorragend für eigene Programmierzwecke, da er durch das Verbiegen auf eine andere Adresse seine gleichmäßige und hochfrequente Wiederkehr nicht verliert. Mit seiner Hilfe können also eigene Maschinenprogramme 60mal in der Sekunde in ein Programm eingeschoben werden - eine Methode, die deswegen den englischen Namen »Wedge« = Keil, erhalten hat. Zwei Vorbedingungen sind allerdings dabei zu erfüllen.

  1. Da ein IRQ mit Sicherheit während des Verbiegens auftritt, muß er vorher abgeschaltet werden. Den Schlüssel dazu bietet die Speicherzelle 56334, die mit 0 gePOKEt den Interrupt abschaltet und mit POKE 56334,1 ihn wieder zuläßt. Beim VC 20 ist dies POKE 37116,127 beziehungsweise POKE 37116,192. Aber Vorsicht!! Da während eines IRQ-Interrupts auch die Tastatur abgefragt wird, kann das Abschalten nur innerhalb eines Programms erfolgen - während der Abschaltung ist die Tastatur tot.
  2. Am Ende eines »Wedge« muß der Sprung auf die alte IRQ-Adresse erfolgen, die ursprünglich in den Speicherzellen 788 bis 789 stand, damit - etwas verspätet zwar - die normalen Haushaltsarbeiten des IRQ nachgeholt werden können. Bei längeren Wedges wird daher die interne Uhr TI und TI$ etwas nachgehen.

Ich habe lange nach einem Beispiel gesucht. Ich kenne viele: Abfrage der Joysticks, Lautstärke von Tönen mit Funktionstasten steuern, von Basic unabhängige Laufschrift, um ein paar zu nennen. Aber alle haben einen ziemlich langen Maschinensprache-Teil. Ich bringe daher hier das kürzeste Beispiel, das ich kenne. Es stammt von Rügheimer und Spanik.

Das Programm verändert dauernd die Farbe des Bildschirmrahmens:

10 FOR K=679 TO 699
20 READ A
30 POKE K,A:NEXT
40 DATA 166,162,224,0,224,128,240
50 DATA 3,76,49,234,174,32,208
60 DATA 202,142,32,208,76,175,02
70 POKE 56334,0
80 POKE 788,167:POKE 789,2
90 POKE 56334,1

Dieses Programm gilt nur für den C 64; für den VC 20 müßte es entsprechend umgeschrieben werden.

Die Zeilen 10 bis 30 lesen das Maschinenprogramm, das in den DATA-Zeilen 40 bis 60 steht, in die Speicherzellen 679 bis 699. Diese stehen, wie wir das letzte Mal gesehen haben, zur freien Verfügung - und sind daher ideal geeignet, ein kleines Maschinenprogramm ungestört aufzunehmen.

In Zeile 70 wird der IRQ-Interrupt unterbrochen. Jetzt kommt der wichtige Teil: Zeile 80 verbiegt den IRQ-Vektor zur Speicherzelle 176 + 256 * 2 = 679. Zeile 90 schaltet schließlich den IRQ-Interrupt wieder ein.

Jetzt passiert also folgendes: Jedesmal, wenn der Timer A den Haushalt-IRQ auslöst, springt der Computer zuerst einmal auf das Maschinenprogramm ab Speicherzelle 679 und schaltet die Rahmenfarbe um. Dann erst springt der letzte Befehl des Maschinenprogramms auf die ursprüngliche IRQ-Adresse 59953 ($EA31), von der aus das Betriebssystem weitermacht, als sei nichts geschehen.

Für Kenner gebe ich noch das Assembler-Listing des Maschinenprogramms an:

,02A7 A6 A2     LDX A2
,02A9 E0 00     CPX #00
,02AB E0 80     CPX #80
,02AD F0 03     BEQ 02B2
,02AF 4C 31 EA  JMP EA31
,02B2 AE 20 D0  LDX D020
,02B5 CA        DEX
,02B6 8E 20 D0  STX D020
,02B9 4C Af 02  JMP 02AF

Es gibt noch eine kleine, erwähnenswerte Anwendung. Wenn der Vektor nicht auf den Anfang der IRQ-Routine bei 59953, sondern auf 59956 - also drei Stellen weiter - zeigt, übergeht die IRQ-Routine den Teil, welcher die STOP-Taste abfragt und die TI/TI$-Uhr weiterschaltet, wodurch effektiv die STOP-Taste ausgeschaltet wird. Das geht ganz schnell mit POKE 788,52. Mit POKE 788,49 wird das wieder rückgängig gemacht. Beim VC 20 sind es die Werte POKE 788,194 oder POKE 788,191.

$EA31 IRQ-Vektor  
Execution address of interrupt service routine.

Default: $EA31.

IRQ RAM vector   Vector: Hardware Interrupt   Vector: Hardware IRQ Interrupt Address ($EA31).   Hardware interrupt vector ($EA31)  
$0316-$0317 CBINV 790-791
Vector: BRK Instruction Interrupt

This vector points to the address of the routine which will be executed anytime that a 6510 BRK instruction (00) is encountered.

The default value points to a routine that calls several of the Kernal initialization routines such as RESTOR, IOINIT and part of CINT, and then jumps through the BASIC warm start vector at 40962. This is the same routine that is used when the STOP and RESTORE keys are pressed simultaneously, and is currently located at 65126 ($FE66).

A machine language monitor program will usually change this vector to point to the monitor warm start address, so that break points may be set that will return control to the monitor for debugging purposes.

Vektor auf die BREAK-Interrupt-Routine des Betriebssystems

Diese Routine ist im Texteinschub Nr. 35 nicht erwähnt, weil sie ein Teil der NMI-Routine ist. Dieser Vektor zeigt auf die Adresse 65126 ($FE66) - beim VC 20 auf 65234 ($FED2). Die da beginnende Routine des Betriebssystems wird aufgerufen, wenn der Maschinenbefehl BRK ausgeführt wird. Er führt letztlich zu einem Warmstart, das heißt der Bildschirm wird gelöscht und der Cursor meldet sich mit READY. Diese Routine wird auch durch das gleichzeitige Drücken der STOP- und der RESTORE-Taste angestoßen.

$FE66 BRK-Vektor  
Execution address of BRK service routine.

Default: $FE66.

BRK instr RAM vector   Vector: BRK Instr. Interrupt   Vector: BRK Instruction Interrupt Address ($FE66).   Break interrupt vector ($FE66)  
$0318-$0319 NMINV 792-793
Vector: Non-Maskable Interrupt

This vector points to the address of the routine that will be executed when a Non-Maskable Interrupt (NMI) occurs (currently at 65095 ($FE47)).

There are two possible sources for an NMI interrupt. The first is the RESTORE key, which is connected directly to the 6510 NMI line. The second is CIA #2, the interrupt line of which is connected to the 6510 NMI line.

When an NMI interrupt occurs, a ROM routine sets the Interrupt disable flag, and then jumps through this RAM vector. The default vector points to an interrupt routine which checks to see what the cause of the NMI was.

If the cause was CIA #2, the routine checks to see if one of the RS-232 routines should be called. If the source was the RESTORE key, it checks for a cartridge, and if present, the cartridge is entered at the warm start entry point. If there is no cartridge, the STOP key is tested. If the STOP key was pressed at the same time as the RESTORE key, several of the Kernal initialization routines such as RESTOR, IOINIT and part of CINT are executed, and BASIC is entered through its warm start vector at 40962. If the STOP key was not pressed simultaneously with the RESTORE, the interrupt will end without letting the user know that anything happened at all when the RESTORE key was pressed.

Since this vector controls the outcome of pressing the RESTORE key, it can be used to disable the STOP/RESTORE sequence. A simple way to do this is to change this vector to point to the RTI instruction. A simple POKE 792,193 will accomplish this. To set the vector back, POKE 792,71. Note that this will cut out all NMIs, including those required for RS-232 I/O.

Vektor auf die NMI-Routine des Betriebssystems.

Der NMI-Interrupt ist im Texteinschub Nr. 35 »Dem Computer ins Wort fallen« näher beschrieben. Der Vektor zeigt auf den Beginn dieser Routine ab Speicherzelle 65095 ($FE47) - beim VC 20 ab 65197 ($FEAD).

Sobald ein NMI-Interrupt auftritt, wird zuerst durch Setzen der Interrupt- Abschalt-Flagge (Interrupt Disable Flag) jede Unterbrechung durch den IRQ- Interrupt unterbunden. Dann wird geprüft, wer den NMI-Interrupt ausgelöst hat, und zwar in der Reihenfolge: RS232-Schnittstelle, RESTORE-Taste; eingestecktes Modul und schließlich die STOP-Taste. Die letztere dient zum Sichem der RESTORE-Taste. Nur wenn beide gemeinsam gedrückt werden, kommt die NMI- Unterbrechung durch die RESTORE-Taste zur Auswirkung.

Da die RESTORE-Taste fast als erste abgefragt wird, kann sie und ihre Kombination mit der STOP-Taste durch Verbiegen des Vektors in Speicherzelle 792 bis 793 abgeschaltet werden. Beim C 64 geht das mit POKE 792,193 - Wieder eingeschaltet wird mit POKE 792,71. Beim VC 20 geht das mit POKE 792,91 beziehungsweise POKE 792,173 - Natürlich können Spezialisten durch Verbiegen des Vektors auf andere Adressen ihre eigenen NMI-Routinen bauen.

$FE47 NMI-Vektor  
Execution address of non-maskable interrupt service routine.

Default: $FE47.

NMI RAM vector   Vector: Non-Maskable Interrupt   Vector: Hardware NMI Interrupt Address ($FE47).   NMI interrupt vector ($FE47)  
$031A-$032D 794-813
Kernal Indirect Vectors

There are 39 Kernal routines for which there are vectors in the jump table located at the top of the ROM (65409, $FF81). For ten of these routines, the jump table entry contains a machine language instruction to jump to the address pointed to by the RAM vector in this table. The addresses in this table are initialized to point to the corresponding routines in the Kernal ROM. Since these addresses are in RAM, however, any entry in this table may be changed. This enables the user to add to these routines, or to replace them completely.

You will notice, for example, that many of these routines involve Input/ Output functions. By changing the vectors to these routines, it is possible to support new I/O devices, such as an IEEE disk drive used through an adapter.

The user should be cautioned that since some of these routines are interrupt-driven, it is dangerous to change these vectors without first turning off all interrupts. For a safe method of changing all of these vectors at one time, along with the interrupt vectors above, see the entry for the Kernal VECTOR routine at 64794 ($FD1A).

More specific information about the individual routines can be found in the descriptions given for their ROM locations.

           
Indirects for code

Conforms to KERNAL spec 8/19/80

           
$031A-$031B IOPEN 794-795 Vector to Kernal OPEN Routine (Currently at 62282 ($F34A))  
Vektor auf die OPEN-Routine des Betriebssystems

Die Routine beginnt ab Adresse 62282 ($F34A) - beim VC 20 ab 62474 ($FEAD). Diese Routine prüft, ob eine Datei (File) eröffnet werden kann. Das geht immer dann, wenn die File-Nummer nicht 0 ist und wenn weniger als 10 andere Dateien bereits eröffnet sind. Für die serielle Schnittstelle (Geräte-Nummer 4, 5, 8 bis 11) wird an das angewählte Gerät zuerst der Befehl »Listen« gegeben und dann die Sekundär-Adresse des OPEN-Befehls.

Beim Bandgerät (Geräte-Nummer 1) prüft die Routine den Tape Header einer sequentiellen Datei beziehungsweise schreibt einen Tape Header auf das Band.

Bei Anwahl der RS232-Schnittstelle (Geräte-Nummer 2) aktiviert die Routine einige Leitungen und reserviert je einen Ein- und Ausgabe-Pufferspeicheram oberen Ende des Basic-Programmspeichers.

$F34A OPEN-Vektor  
Execution address of OPEN, routine opening files.

Default: $F34A.

    KERNAL OPEN Routine Vector   Vector: Indirect entry to Kernal OPEN Routine ($F34A).   OPEN vector ($F34A)  
$031C-$031D ICLOSE 796-797 Vector to Kernal CLOSE Routine (Currently at 62097 ($F291))  
Vektor auf die CLOSE-Routine des Betriebssystems

Dieser Vektor zeigt auf die Adresse 62097 ($F291) - beim VC 20 auf 62282 ($F34A). Ab hier beginnt eine Routine, die beim CLOSE-Befehl zuerst prüft, ob die Datei-Nummer in der Tabelle der eröffneten Datei enthalten ist. Dann holt sie die dazugehörige Geräte-Nummer und Sekundär-Adresse und schließt den Kanal und die Datei.

$F291 CLOSE-Vektor  
Execution address of CLOSE, routine closing files.

Default: $F291.

    KERNAL CLOSE Routine Vector   Vector: Indirect entry to Kernal CLOSE Routine ($F291).   CLOSE vector ($F291)  
$031E-$031F ICHKIN 798-799 Vector to Kernal CHKIN Routine (Currently at 61966 ($F20E))  
Vektor auf die CHKIN-Routine des Betriebssystems

Diese Routine beginnt ab Adresse 61966 ($F20E) - beim VC 20 ab 62161 ($F2C7). Sie eröffnet einen Datenkanal zur Übernahme von Daten von dem Gerät, das durch den OPEN-Befehl angegeben worden ist.

$F20E CHKIN-Vektor  
Execution address of CHKIN, routine defining file as default input.

Default: $F20E.

    KERNAL CHKIN Routine   Vector: Indirect entry to Kernal CHKIN Routine ($F20E).   Set - input vector ($F20E)  
$0320-$0321 ICKOUT 800-801 Vector to Kernal CKOUT Routine (Currently at 62032 ($F250))  
Vektor auf die CKOUT-Routine des Betriebssystems

Dieser Vektor zeigt auf die Adresse 62032 ($F250) - beim VC 20 auf 62217 ($F309). Dort beginnt die Routine, welche einen Datenkanal zur Abgabe von Daten an das im OPEN-Befehl angegebene Gerät aufmacht.

$F250 CKOUT-Vektor  
Execution address of CHKOUT, routine defining file as default output.

Default: $F250.

    KERNAL CHKOUT Routine   Vector: Indirect entry to Kernal CHKOUT Routine ($F250).   Set - output vector ($F250)  
$0322-$0323 ICLRCH 802-803 Vector to Kernal CLRCHN Routine (Currently at 62259 ($F333))  
Vektor auf die CLRCHN-Routine des Betriebssystems

Der Name dieser Routine ist die Abkürzung für »clear channel«. Diese Routine, die ab Adresse 62259 ($F333) - beim VC 20 ab 62461 ($F3F3) - beginnt, setzt alle Kanäle in den Einschaltzustand zurück. Das heißt, das Eingabegerät ist die Tastatur, das Ausgabegerät ist der Bildschirm.

$F333 CLRCH-Vektor  
Execution address of CLRCHN, routine initializating input/output.

Default: $F333.

    KERNAL CLRCHN Routine Vector   Vector: Indirect entry to Kernal CLRCHN Routine ($F333).   Restore I/0 vector ($F333)  
$0324-$0325 IBASIN 804-805 Vector to Kernal CHRIN Routine (Currently at 61783 ($F157))  
Vektor auf die CHRIN-Routine des Betriebssystems

Dieser Vektor zeigt auf die Adresse 61783 ($F157) - beim VC 20 auf 61966 ($F20E). Die hier beginnende Routine, deren Abkürzung »Character Input« bedeutet, holt das jeweils nächste Byte vom Eingabepuffer des angewählten Gerätes, sofern ein solcher eingerichtet ist (zum Beispiel Kassettenpuffer, RS232-Puffer).

Bei Eingabe von der Tastatur holt diese Routine so lange Bytes aus dem Tastaturpuffer und zeigt sie auf dem Bildschirm an, bis das Zeichen für ein ungeSHIFTetes RETURN auftritt. Erst dann gibt die Routine das erste Zeichen der logischen Zeile auf dem Bildschirm an den Basic-Übersetzer weiter.

$F157 INPUT-Vektor  
Execution address of CHRIN, data input routine, except for keyboard and RS232 input.

Default: $F157.

    KERNAL CHRIN Routine   Vector: Indirect entry to Kernal CHRIN Routine ($F157).   INPUT vector ($F157)  
$0326-$0327 IBSOUT 806-807 Vector to Kernal CHROUT Routine (Currently at 61898 ($F1CA))  
Vektor auf die CHROUT-Routine des Betriebssystems

Die CHROUT-Routine entspricht der CHRIN-Routine in der anderen Richtung. Sie bedeutet »Character Output« und transferiert ein Byte, das im Akkumulator steht, in den Puffer des angewählten Ausgabegerätes. Sie beginnt ab Adresse 62898 ($F1CA), - beim VC 20 ab 62074 ($F27A).

$F1CA OUTPUT-Vektor  
Execution address of CHROUT, general purpose data output routine.

Default: $F1CA.

    KERNAL CHROUT Routine   Vector: Indirect entry to Kernal CHROUT Routine ($F1CA).   Output vector ($F1CA)  
$0328-$0329 ISTOP 808-809
Vector to Kernal STOP Routine (Currently at 63213 ($F6ED))

This vector points to the address of the routine that tests the STOP key. The STOP key can be disabled by changing this with a POKE 808,239. This will not disable the STOP/RESTORE combination, however. To disable both STOP and STOP/ RESTORE, POKE 808,234 (POKEing 234 here will cause the LIST command not to function properly). To bring things back to normal in either case, POKE 808, 237.

Vektor auf die STOP-Routine des Betriebssystems

Der Vektor zeigt auf die Adresse 63213 ($F6ED) - beim VC 20 auf 63344 ($F770). Die dort beginnende Routine prüft, ob die STOP-Taste gedrückt ist. Durch Verbiegen dieses Vektors kann die STOP-Taste abgeschaltet werden. Beim C 64 geht dies mit POKE 808,239; wieder eingeschaltet wird die STOP-Taste mit POKE 808,237. Beim VC 20 sind die Werte POKE 808,100 beziehungsweise POKE 808,112.

$F6ED STOP-Vektor  
Execution address of STOP, routine checking the status of Stop key indicator, at memory address $91.

Default: $F6ED.

    KERNAL STOP Routine Vector   Vector: Indirect entry to Kernal STOP Routine ($F6ED).   Test-STOP vector ($F6ED)  
$032A-$032B IGETIN 810-811 Vector to Kernal GETIN Routine (Currently at 61758 ($F13E))  
Vektor auf die GETIN-Routine des Betriebssystems

Diese Routine ist fast identisch mit der CHRiN-Routine (siehe Speicherzellen 804 bis 805). Sie holt genauso Zeichen von angewählten Geräten in die Eingabepuffer. Der einzige und damit wichtigste Unterschied liegt in der Behandlung der Tastatur-Eingabe. Im Gegensatz zu CHRIN holt sie ein Byte aus dem Tastaturpuffer sofort in den Akkumulator. Der Vektor zeigt auf den Anfang der Routine ab Speicherzelle 61785 ($F13E) - beim VC 20 ab 61941 ($F1F5).

$F13E GET-Vektor  
Execution address of GETIN, general purpose data input routine.

Default: $F13E.

    KERNAL GETIN Routine   Vector: Indirect entry to Kernal GETIN Routine ($F13E).   GET vector ($F13E)  
$032C-$032D ICLALL 812-813 Vector to Kernal CLALL Routine (Currently at 62255 ($F32F))  
Vektor auf die CLALL-Routine des Betriebssystems

CLALL ist die Abkürzung für Close ALL (Channels and Files). Diese Routine, die ab Adresse 62255 ($F32F) - beim VC 20 ab 62447 ($F3EF) - beginnt, setzt die Speicherzelle 152 auf 0 und schließt so zwangsläufig alle Dateien und Kanäle.

$F32F CLALL-Vektor  
Execution address of CLALL, routine initializing input/output and clearing all file assignment tables.

Default: $F32F.

    KERNAL CLALL Routine Vector   Vector: Indirect entry to Kernal CLALL Routine ($F32F).   Abort I/o vector ($F32F)  
$032E-$032F USRCMD 814-815
Vector to User-Defined Command (Currently Points to BRK at 65126 ($FE66))

This appears to be a holdover from PET days, when the built-in machine language monitor would JuMP through the USRCMD vector when it encountered a command that it did not understand, allowing the user to add new commands to the monitor.

Although this vector is initialized to point to the routine called by STOP/ RESTORE and the BRK interrupt, and is updated by the Kernal VECTOR routine (64794, $FD1A), it does not seem to have the function of aiding in the addition of new commands.

Freier Vektor

Nach dem Einschalten zeigt dieser Vektor auf die BREAK-Routine, genauso wie der Vektor in Speicherzelle 790 und 791. Er ist ein Überbleibsel aus dem PET- Betriebssystem, das aber beim VC 20 und C 64 keine Rolle spielt. Hier können also eigene Vektoren definiert und eingesetzt werden.

$FE66 Warmstart-Vektor  
Unused.

Default: $FE66.

    User-Defined Vector   User Defined Vector ($FE66).   Warm start vector ($FE66)  
$0330-$0331 ILOAD 816-817 Vector to Kernal LOAD Routine (Currently at 62622 ($F49E))  
Vektor auf die LOAD-Routine des Betriebssystems

Dieser Vektor zeigt auf die Adresse 62622 ($F49E) - beim VC 20 auf 62793 ($F549). Die dort beginnende Routine transferiert Daten von einem Eingabegerät direkt in den RAM-Speicher. Sie kann auch zum VERIFYen durch Vergleich der geladen mit den gespeicherten Daten verwendet werden.

$F4A5 LOAD-Vektor  
Execution address of LOAD, routine loading files.

Default: $F4A5.

    KERNAL LOAD Routine   Vector: Indirect entry to Kernal LOAD Routine ($F4A5).   LOAD link ($F4A5)  
$0332-$0333 ISAVE 818-819 Vector: Kernal SAVE Routine (Currently at 62941 ($F5DD))  
Vektor auf die SAVE-Routine des Betriebssystems

Diese Routine ist das Gegenstück zur LOAD-Routine. Sie beginnt ab Adresse 62941 ($F5DD) - beim VC 20 ab 63103 ($F685).

$F5ED SAVE-Vektor  
Execution address of SAVE, routine saving files.

Default: $F5ED.

savesp   KERNAL SAVE Routine Vector   Vector: Indirect entry to Kernal SAVE Routine ($F5ED).   SAVE link ($F5ED)  
$0334-$033B 820-827
Unused

Eight free bytes for user vectors or other data.

Freier Speicherbereich

Diese 8 Byte stehen zur freien Verfügung.

    Unused (8 bytes).       Unused   Unused.      
$033C-$03FB TBUFFR 828-1019
Cassette I/O Buffer

This 192-byte buffer area is used to temporarily hold data that is read from or written to the tape device (device number 1).

When not being used for tape I/O, the cassette buffer has long been a favorite place for Commodore programmers to place short machine language routines (although the 64 has 4K of unused RAM above the BASIC ROM at 49152 ($C000) that would probably better serve the purpose).

Of more practical interest to the 64 programmer is the possible use of this area for VIC-II chip graphics memory (for example, sprite shape data or text character dot data). If the VIC-II chip is banked to the lowest 16K of memory (as is the default selection), there is very little memory space which can be used for such things as sprite shape data without conflict. If the tape is not in use, locations 832-895 ($0340-$037F) can be used as sprite data block number 13, and locations 896-959 ($0380-$03BF) can be used as sprite data block number 14.

The types of tape blocks that can be stored here are program header blocks, data header blocks, and data storage blocks.

The first byte of any kind of block (which is stored at location 828 ($033C)) identifies the block type. Header blocks follow this identifier byte with the two-byte starting RAM address of the tape data, the two-byte ending RAM address, and the filename, padded with blanks so that the total length of the name portion equals 187 bytes. Data storage blocks have 191 bytes of data following the identifier byte. The meanings of the various identifier blocks are as follows:

A value of 1 signifies that the block is the header for a relocatable program file, while a value of 3 indicates that the block is the header for a nonrelocatable program file.

A relocatable file is created when a program is SAVEd with a secondary address of 0 (or any even number), while a nonrelocatable program file is created if the secondary SAVE address is 1 (or any odd number). The difference between the two types of files is that a nonrelocatable program will always load at the address specified in the header. A relocatable program will load at the current start of BASIC address unless the LOAD statement uses a secondary address of 1, in which case it will also be loaded at the addrss specified in the header.

You should note that a program file uses the cassette buffer only to store the header block. Actual program data is transferred directly to or from RAM, without first being buffered.

An identifier value of 4 means that the block is a data file header. Such a header block is stored in the cassette buffer whenever a BASIC program OPENs a tape data file for reading or writing. Subsequent data blocks start with an identifier byte of 2. These blocks contain the actual data byte written by the PRINT #1 command, and read by the GET #1 and INPUT #1 commands. Unlike the body of a program file, these blocks are temporarily stored in the cassette byffer when being written or read.

An identifier byte of 5 indicates that this block is the logical end of the tape. This signals the Kernal not to search past this point, even if there are additional tape blocks physically present on the tape.

Kassettenpuffer

Diese 192 Byte beherbergen den Kassettenpuffer. Der Name kennzeichnet diesen Speicherbereich als Zwischenspeicher für Ein- und Ausgabe-Operationen von und auf Band.

Dabei unterscheiden sich die normalen LOAD-, SAVE- und VERIFY-Befehle von den Datei-Befehlen INPUT#, GET# und PRINT#.

Bei LOAD, SAVE und VERIFY steht im Kassettenpuffer lediglich der Vorspann, der auf englisch »Tape Header« heißt. Die Funktion und Zusammensetzung des Tape Headers habe ich schon bei den Speicherzellen 183 bis 187 und im Texteinschub Nr. 20 »Tape Header« detailliert beschrieben. Die eigentlichen Daten berühren den Kassettenpuffer nicht, sondern werden direkt von und in den RAM-Speicher transferiert.

Bei GET#, INPUT# und PRINT# werden nicht nur der Tape Header, sondern auch alle Daten im Kassettenpuffer zwischengespeichert. Dieser blockweise Transport ist an den charakteristischen Unterbrechungen des Datasettenmotors leicht zu erkennen.

Der Kassettenpuffer kann durch Verbiegen der Zeiger in Speicherzelle 178 und 179 auf beliebige Plätze des Speichers, aber nicht unterhalb 512, geschoben werden. Normalerweise gibt das keinen Sinn, es sei denn, der Speicherbereich 828 bis 1019 wurde mit einem eigenen Maschinenprogramm belegt, und durch das Verschieben des Kassettenpuffers in höhere Regionen möchte man das Maschinenprogramm vor der Zerstörung durch ungeplante Datasetten-Operationen schützen.

Die Kenntnis der Inhalte der Speicherzellen des Kassettenpuffers kann man ausnutzen, um die ärgerlichen LOAD ERROR-Probleme zu lösen. Die Methode dazu ist im Texteinschub Nr. 36 »Reparatur von LOAD ERROR« beschrieben.

Ist die Datasette nicht angeschlossen, oder wird sie nicht eingesetzt, kann der Speicherbereich des Kassettenpuffers als freier Speicher benutzt werden.

Bandpuffer   Datasette buffer (192 bytes).   cassette data b   Tape I/O Buffer   Tape I/O Buffer.   Cassette buffer  
$03FC-$03FF 1020-1023
Unused

Four more free bytes.

Freie Speicherplätze

Auch diese 4 Byte stehen zur freien Verfügung.

    Unused (4 bytes).       Unused   Unused.