********* Welcome to Project 64! The goal of Project 64 is to preserve Commodore 64 related documents in electronic text format that might otherwise cease to exist with the rapid advancement of computer technology and declining interest in 8- bit computers on the part of the general population. Extensive efforts were made to preserve the contents of the original document. However, certain portions, such as diagrams, program listings, and indexes may have been either altered or sacrificed due to the limitations of plain vanilla text. Diagrams may have been eliminated where ASCII-art was not feasible. Program listings may be missing display codes where substitutions were not possible. Tables of contents and indexes may have been changed from page number references to section number references. Please accept our apologies for these limitations, alterations, and possible omissions. Document names are limited to the 8.3 file convention of DOS. The first characters of the file name are an abbreviation of the original document name. The version number of the etext follows next. After that a letter may appear to indicate the particular source of the document. Finally, the document is given a .TXT extension. The author(s) of the original document and members of Project 64 make no representations about the accuracy or suitability of this material for any purpose. This etext is provided "as-is". Please refer to the warantee of the original document, if any, that may included in this etext. No other warantees, express or implied, are made to you as to the etext or any medium it may be on. Neither the author(s) nor the members of Project 64 will assume liability for damages either from the direct or indirect use of this etext or from the distribution of or modification to this etext. Therefore if you read this document or use the information herein you do so at your own risk. ********* The Project 64 etext of the ~Mapping The Commodore 64 book~, typed by David Holz , formatted to 71 columns and somewhat proofed by Cris Berneburg . MAPC6410.TXT, May 1998, etext #352# Note from the tired typist: WHEW! This is a LOT of text. And, yes, this whole darned 11,000-line thing was completely hand-typed. As for the content, I tried to get everything exactly word-for-word. However, many typos are bound to be lurking in these pages. Thus I give permission for anybody to edit and repost this file without having to contact me. I also made some minor changes, which include throwing out page numbers and delimitation, filling up to 79 columns wide, listing out some ordinary-formatted text into somewhat formatted tables, and correcting some typos and errors in the original text. The book bears Sheldon Leemon's name and was published by Compute! Publications, (c) 1984. Again (like the Project 64 header should read), this copy is meant for reference only, and to preserve its contents from being eternally lost. No monetary or other damages to Compute! Publications or Sheldon Leemon are meant by the creation and transfer of this electronic book, and the intellectual ownership of the contents of this text by the above parties is hereby acknowledged. No profit is to be made from the transfer of this electronic copy! I claim no responsibility for anything that anybody does with the text herein, as do the original author and publisher. Without further ado, here's one of the best C64 references around! Enjoy! White Flame (aka David Holz) http://www.geocities.com/ResearchTriangle/Lab/1767 ********* MAPPING THE Commodore 64 :::::::::::: ::Contents:: :::::::::::: Foreword Acknowledgments Introduction Chapter 1. Page 0 Chapter 2. Page 1 Chapter 3. Pages 2 and 3 BASIC and Kernal Working Storage Chapter 4. 1K to 40K Screen, Memory, Sprite Pointers, and BASIC Program Text Chapter 5. 8K BASIC ROM and 4K Free RAM Chapter 6. VIC-II, SID, I/O Devices, Color RAM, and Character ROM Chapter 7. 8K Operating System Kernal ROM Appendix A. A Beginner's Guide to Typing In Programs Appendix B. How to Type In Programs Appendix C. Screen Location Table Appendix D. Screen Color Memory Table Appendix E. Screen Color Codes Appendix F. ASCII Codes [*** OMITTED ***] [widely available elsewhere; not suitable for textual formatting] Appendix G. Screen Codes [*** OMITTED ***] [widely available elsewhere; not suitable for textual formatting] Appendix H. Commodore 64 Keycodes Index (By Memory Location) :::::::::::: ::Foreword:: :::::::::::: This is a memory map of the Commodore 64 personal computer. But it's much more than that. It's a reference book which every programmer who uses the 64 will find invaluable. What is a memory map? It's a list of the memory locations in a computer. But Mapping the Commodore 64 is a memory amp that goes much further. It explains the purpose of each location and shows you how to change the contents of many of them. You can make the computer do what you want it to. If you're a BASIC programmer, you'll find easy-to-understand explanations of how to use the advanced features of the Commodore 64, and how to include these features in your own programs. If you're already using machine language to write your own programs, you'll use this guide over and over again, referring to specific memory locations and routines. You'll have the most complete guide to the Commodore 64's memory available. As with all COMPUTE! books, the explanations are clear and easy to understand. Beginning and advanced programmers alike will find Mapping the Commodore 64 a valuable resource. :::::::::::::::::::: ::Acknowledgements:: :::::::::::::::::::: I would like to thank Russ Davies, author of Mapping the VIC, for his generosity in sharing the results of his research. Without his help, and that of Dan Heeb, author of the The Commodore 64 and VIC Tool Kit, this book would have been much less complete. Of all the published sources of information about the 64, I have found the Commodore 64 Programmer's Reference Guide to be the most valuable for technical information. That Commodore has come out with such a thorough reference work so quickly after the introduction of the machine is much to their credit. Because of the similarities between the 64 and previous Commodore computers, I have also relied heavily on ooks that deal with the PET/CBM. Of particular interest are Programming the PET/CBM by Raeto West, which should be subtitled "Everything You Ever Wanted to Know about Commodore Computers," and the PET/CBM Personal Computer Guide, Third Edition, Osborne/ McGraw-Hill. These important reference works contain more information of real benefit to the 64 owner than most books which deal specifically with the 64. Finally, I would like to thank my wife Lenore. Although her contribution to this book was nontechnical in nature, it was as important as any other. :::::::::::::::: ::Introduction:: :::::::::::::::: To many computer users, the concept of a memory map may be an unfamiliar one. Simply stated, it is a guide to your computer's internal hardware and software. A memory map can help you use the PEEK and POKE instructions to extend your BASIC programming powers. If you plan to do machine language programming, it is necessary that you be able to find your way around the system. Many computer owners think of a program as something they buy at a store and feed into the computer so that it will let them play games, or do word processing, or keep financial records. But this type of applications software is by no means the only kind. It is important to remember that a computer cannot do anything without some kind of program. When the computer displays the READY prompt, or blinks the cursor, or displays the letters that you type, it can only do so by executing a program. In the examples shown above, it is the master control program, the Operating System (OS), which is being executed. When you give the computer a command such as LOAD, the BASIC interpreter program translates the English-like request to the language of numbers which the computer understands. The Operating System and BASIC interpreter programs are contained in permanent Read Only Memory (ROM), and are available as soon as you turn the power on. Without them, your computer would be a rather expensive paperweight. This permanent software co-exists inside your computer with the applications program that you load. Since the system software performs many of the same functions as the applications program (such as reading information from the keyboard and displaying it on the screen), it is often possible for the applications program to make use of certain parts of the Operating System. This not only makes the task of the programmer easier, but in come cases it allows him or her to do things that otherwise would not be possible. The Commodore 64 also has hardware support chips which enable the graphics display, sound synthesis, and communications with external devices. Since these chips are addressed like memory, they occupy space in our map. Control over these chips, and the graphics, sound, and I/O functions they make possible, can only be accomplished by manipulation of the memory addresses which correspond to these devices. Therefore, a guide to these addresses is necessary in order to take advantage of the graphics, music, and communications power that they offer. The purpose of this book is to describe the memory locations used by the system, and to show, wherever possible, how to utilize them in your own programs. The book should clear up some of the mystery surrounding the way your computer works. How to Use This Book The Commodore 64 and communicate with 64K or 65536 (64*1024) bytes of memory. Each of these bytes of memory can store a number from 0 to 255. The computer can read (and sometimes write) information from any of these 65536 locations by using its address, a number from 0 to 65535. Bits and Bytes Each byte is make up of eight binary digits called bits. These bits are the computer's smallest unit of information. They can contain only the number one or the number zero, but when combined, they can be used to form any number needed. To see how that is possible, let's look at a single bit. A single bit can only be a one or a zero. But if two bits are combined the number increases. 00,01,10,11 That makes four possible combinations. And if a third bit is added: 000,001,010,011,100,101,110,111 When eight bits are put together, the number of combinations increases to 256. These eight bits are called a byte and can be used to represent the numbers from 0 to 255. This system of numbering is known as binary (or base two). It works much like the decimal (base ten) system. In the base ten numbering system, the rightmost digit is known as the one's place, and holds a number from 0 to 9. The next place to the left is known as then ten's place, and also holds a number from 0 to 9, which represents the number of times the one's place has been used in counting (the number of tens). In the binary system, there is a one's place, then a two's place, a four's place, etc. The bits are counted from right to left, starting with Bit 0. Here are the values of each bit: Bit 0 = 1 Bit 1 = 2 Bit 2 = 4 Bit 3 = 8 Bit 4 = 16 Bit 5 = 32 Bit 6 = 64 Bit 7 = 128 If all the bits are added together (128+64+32+16+4+2+1), they total 255, which is the maximum value of one byte. What if you need to count higher than 255? Use two bytes. By using a second bytere to count the number of 255's, 65536 combinations are possible (256*256). This is the same number as the bytes of memory in the Commodore 64. Therefore, any byte can be addressed by a number using a maximum of two bytes. When discussing large, even units of memory, the second byte, the number of 256's, is often used alone. These units are known as pages. Page 0 starts at location zero (0*256), Page 1 starts at location 256 (1*256), etc. You may see thn terms low-byte, high-byte order or LSB (Least Significant Byte), MSB (Most Significant Byte) order, mentioned later in this book. That refers to the way in which the Commodore 64 usually deals with a two-byte address. The byte of the address that represents the number of 256's (MSB) is usually stored higher in memory than the part that stores the leftover value from 0 to 255 (LSB). Therefore, to find the address, you must add the LSB to 256*MSB. Hexadecimal One other numbering system that is used in speaking about computers is the hexadecimal (base 16) system. Each hexadecimal digit can count a number from 0 to 15. Since the highest numeric digit is 9, the alphabet must be used: A=10, B=11, and so on up to F=15. With just two digits, 256 combinations are possible (16*16). That means that each byte can be represented by just two hexadecimal digits, each of which stands for four bits of memory. These four- bit units are smaller than a byte, so they are known as nybbles. Since programmers often find that hexadecimal numbers are easier to use than binary or decimal numbers, many numbers in this book are given in both decimal and hexadecimal format. A dollar sign ($) has been placed in front of each hexadecimal number. AND, OR, and EOR Certain functions on the 64 (particularly those using the sound and graphics chips) are controlled by a single bit. You will often see references to setting Bit 6 to a value of one, or setting Bit 3 to a value of zero. This can be done by adding or subtracting the bit value for that particular bit from the value of the whole byte. Adding or subtracting the bit value will work only if you know the status of that bit already. If Bit 4 is off, and you add 16 (the bit value of Bit 4) to the byte, it will turn Bit 4 on. But if it were on already, adding 16 would turn Bit 4 off, and another bit on. This is where logical (sometimes called Boolean) functions come in handy. Two functions, OR and AND, are available in BASIC, and a third, EOR, can be used in machine language programming for bit manipulation. AND is usually used to zero out (or mask) unwanted bits. When you AND a number with another, a 1 will appear in the resulting number only of identical bits in the ANDed numbers had been set to 1. For example, if you wanted to turn of Bit 4 in the number 154, you could AND it with 239 (which is the maximum bit combination minus the bit value to be masked; 255-16): 10011010 = 154 AND 11101111 = 239 -------- = 10001010 = 138 By using the AND function, nothing would be harmed if we tried to turn off a bit that wasn't on. You can always turn a bit off by using the formula BYTEVALUE AND (255-BITVALUE). Remember, there must be a 1 in the same bit of both numbers in order for the same bit in the result to have a 1. The opposite function, turning a bit on, is performed by the OR statement. The OR function puts a 1 in the bit of the resulting number if there was a 1 in the same bit in either of the two numbers. For example, to turn Bit 4 back on in the number 138, we would use the statement 138 OR 16 (the bit value for the bit we want to turn on): 10001010 = 138 OR 00010000 = 16 -------- = 10011010 = 154 Again, no harm would be done if the bit was already on. A bit can always be turned on with the formula BYTEVALUE OR BITVALUE. The third operation, EOR, can be done only in machine language. It is used to reverse the value of a bit. If the bit of the second number holds a 1, it will reverse the value of the corresponding bit in the first number. Therefore, to switch all of the bits, you can EOR a number by 255: 10011010 = 154 EOR 11111111 = 255 -------- = 01100101 = 101 Notice that this produces the complement of the original number (256 minus the number). Anytime you with to flip a bit from 0 to 1, or 1 to 0, you can EOR it with the value of that bit. The Format of Entries The entries in this book are organized at the most general level by large blocks 9the 256 page 0 locations, for example, or the 8192 locations in the BASIC ROM). At the beginning of these blocks, you will often find an explanation that will give you an idea of how the lcoations in that section are related. Usually, this overview will make it easier to understand the more detailed explanations of the individual locations in that block. Within these larger blocks, you will sometimes see a few locations grouped under the heading Location Range. This grouping is done where the locations are so interrelated that it would be meaningless to try to explain one without explaining them all. Finally comes the entries for individual locations. These give the address, first in decimal, then in hexadecimal, and sometimes a label. This label is merely a mnemonic device, used in machine language programming, for easier reference to a particular memory location. Although Commodore has not released the source code for their Operating System or BASIC, they have published some of these labels in the Commodore 64 Programmer's Reference Guide. Other labels used here are taken from Jim Butterfield's PET memory maps, which have enjoyed a wide circulation among Commodore users. Their use here should help 64 owners adapt information about the PET to their own machines. The mnemonic label for an entry is followed by a one-line description of the location. Often, a more detailed explanation will appear under that, ranging from a couple of sentences to several pages. Occasionally, program samples will accompany these explanations. Sometimes the single-line descriptions will identify a location as a flag, a vector, or a pointer. A flag is just a number that the program uses to store the outcome of a previous operation. A pointer of vector is usually a two-byte location that holds a significant address. Generally, the term pointer is used when the address points to the start of some data, and vector is used when the address points to the start of a machine language program. However, sometimes these terms will be used interchangeably, with the meaning clear from the context. ::::::::::::: ::Chapter 1:: :: :: :: Page 0 :: ::::::::::::: Memory locations 0-255 ($0-$FF) have a special significance in 6502 machine language programming (the 6510 microprocessor in the Commodore 64 shares the same instruction set as the 6502). Since these addresses cn be expressed using just one byte, instructions which access data stored in these locations are shorter and execute more quickly than do instructions which operate on addresses in higher memory, which requires two bytes. Because of this relatively fast execution time, most 6502 software makes heavy use of zero-page locations. The 64 is no exception, and uses this area for many important system variables and pointers. In addition, locations 0 and 1 have special Input/Output functions on the 6510. In the case of the 64, this on-chip I/O port is used to select the possible combinations of ROM, as we will se below, and to control cassette I/O. Location Range: 0-143 ($0-$8F) BASIC Working Storage This portion of zero page is used by BASIC only. Therefore, a program written entirely in machine language that does not interact with BASIC can freely use this area. 0 $0 D6510 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. 1 $1 R6510 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 int he 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. 2 $2 Unused 3-4 $3-$4 ADRAY1 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 ($311) for an explanation of how to use this routine in connection with the USR command. 5-6 $5-$6 ADRAY2 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 ($311). 7 $7 CHARAC 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 ($200), 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. 8 $8 ENDCHR 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. 9 $9 TRMPOS 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. 10 $A VERCK 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). 11 $B COUNT Index into the Text Input Buffer/Number of Array Subscripts The routines that convert the text in the input buffer at 512 ($200) 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. 12 $C DIMFLG 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. 13 $D VALTYP 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. 14 $E INTFLG 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. 15 $F GARBFL 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, $200) into a linked program line of BASIC keyword tokens. 16 $10 SUBFLG 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. 17 $11 INPFLG 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. 18 $12 TANSGN 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. 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. 19 $13 CHANNL 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 ($200), the keyboard buffer. 20-21 $14-$15 LINNUM 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. 22 $16 TEMPPT 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. 23-24 $17-$18 LASTPT 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. 25-33 $19-$21 TEMPST 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. 34-37 $22-$25 INDEX Miscellaneous Temporary Pointers and Save Area This area is used by many BASIC routines to hold temporary pointers and calculation results. 38-42 $26-$2A RESHO 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. 43-44 $2B-$2C TXTTAB 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 ($801). 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 ($401). 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 ($801), it will not recognize its presence because it expects a BASIC program to start at 1025 ($401). 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). 2. 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 ($801), 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. 3. 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. 4. 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. 45-46 $2D-$2E VARTAB 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. 47-48 $2F-$30 ARYTAB 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). 49-50 $31-$32 STREND 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). 51-52 $33-$34 FREETOP 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). 53-54 $35-$36 FRESPC 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. 55-56 $37-$38 MEMSIZ 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. 2. 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. 57-58 $39-$3A CURLIN 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 ($308), 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. 59-60 $3B-$3C OLDLIN Previous BASIC Line Number When program execution ends, the last line number executed is stored here, and restored to location 57 ($39) by CONT. 61-62 $3D-$3E OLDTXT 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. 63-64 $3F-$40 DATLIN 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. 65-66 $41-$42 DATPTR 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$ 67-68 $43-$44 INPPTR 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 ($200). 69-70 $45-$46 VARNAM 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. 71-72 $47-$48 VARPNT 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. 73-74 $49-$4A FORPNT 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 ($100). 75-76 $4B-$4C OPPTR 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. 77 $4D OPMASK 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. 78-79 $4E-$4F DEFPNT 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. 80-82 $50-$52 DSCPNT 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. 83 $53 FOUR6 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. 84-86 $54-$56 JMPER 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). 87-96 $57-$60 BASIC Numeric Work Area This is a very busy work area, used by many routines. 97-102 $61-$66 FAC1 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: 97 $61 FACEXP 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. 98-101 $62-$65 FACHO 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. 102 $66 FACSGN Floating Point Accumulator #1: Sign A value of 0 here indicates a positive number, while a value of 255 ($FF) indicates a negative number. 103 $67 SGNFLG 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. 104 $68 BITS 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. 105-110 $69-$6E FAC2 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. 105 $69 ARGEXP Floating Point Accumulator #2: Exponent 106-109 $6A-$6D ARGHO Floating Point Accumulator #2: Mantissa 110 $6E ARGSGN Floating Point Accumulator #2: Sign 111 $6F ARISGN 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. 112 $70 FACOV 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. 113-114 $71-$72 FBUFPT 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). 115-138 $73-$8A CHRGET 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 ($200-$250) ; 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 ($300-$30B) for more details. 139-143 $8B-$8F RNDX 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. Location Range: 144-255 ($90-$FF) Kernal Work Storage Area This is the zero-page storage area for the Kernal. The user should take into account what effect changing a location here will have on the operation of the Kernal functions before making any such changes. At power-on, this range of locations is first filled with zeros, and then initialized from values stored in ROM as needed. 144 $90 STATUS 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: Cassette: Bit 2 (Bit Value of 4) = Short Block Bit 3 (Bit Value of 8) = Long Block Bit 4 (Bit Value of 16) = Unrecoverable error (Read), mismatch Bit 5 (Bit Value of 32) = Checksum error Bit 6 (Bit Value of 64) = End of file Serial Devices: Bit 0 (Bit Value of 1) = Time out (Write) Bit 1 (Bit Value of 2) = Time out (Read) Bit 6 (Bit Value of 64) = EOI (End or Identify) Bit 7 (Bit Value of 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 ($297). 145 $91 STKEY 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. 146 $92 SVXT 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. 147 $93 VERCK 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. 148 $94 C3PO 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. 149 $95 BSOUR 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. 150 $96 SYNO Cassette Block Synchronization Number 151 $97 XSAV Temporary .X Register Save Area This .X register save area is used by the routines that get and put an ASCII character. 152 $98 LDTND 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 ($259-$277) 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. 153 $99 DFLTN 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. 154 $9A DFLTO 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. 155 $9B PRTY Tape Character Parity This location is used to help detect when bits of information have been lost during transmission of tape data. 156 $9C DPSW 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. 157 $9D MSGFLG 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. 158 $9E PTR1 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). 159 $9F PTR2 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. 160-162 $A0-$A2 TIME 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. 163-164 $A3-$A4 Temporary Data Storage Area These locations are used temporarily by the tape and serial I/O routines. 165 $A5 CNTDN Cassette Synchronization Character Countdown Used to count down the number of synchronization characters that are sent before the actual data in a tape block. 166 $A6 BUFPNT 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. 167 $A7 INBIT 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. 168 $A8 BITCI 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. 169 $A9 RINONE 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. 170 $AA RIDATA 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 pointer 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. 171 $AB RIPRTY 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. 172-173 $AC-$AD SAL 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. 174-175 $AE-$AF EAL 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. 176-177 $B0-$B1 CMP0 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. 178-179 $B2-$B3 TAPE1 Pointer: Start of Tape Buffer On power-on, this pointer is set to the address of the cassette buffer (828, $33C). This pointer must contain an address greater than or equal to 512 ($200), or an ILLEGAL DEVICE NUMBER error will be sent when tape I/O is tried. 180 $B4 BITTS 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. 181 $B5 NXTBIT 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. 182 $B6 RODATA 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). 183 $B7 FNLEN 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 ($293-$296), and determine baud rate, word length, and parity. 184 $B8 LA 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. 185 $B9 SA 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. 186 $BA FA 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 187-188 $BB-$BC FNADR 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 ($293-$296), where they are used to control such parameters as baud rate, parity, and word length. 189 $BD ROPRTY 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. 190 $BE FSBLK 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. 191 $BF MYCH Tape Input Byte Buffer This is used by the tape routines as a work area in which incoming characters area assembled. 192 $C0 CAS1 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. 193-194 $C1-$C2 STAL 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. 197 $C5 LSTX 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). 198 $C6 NDX Number of Characters in Keyboard Buffer (Queue) The value here indicates the number of charracters waiting in the keyboard buffer at 631 ($277). The maximum number of characters in the keyboard buffer at any one time is determined by the value in location 649 ($289), 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 ($277), the keyboard buffer. 199 $C7 RVS 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. 200 $C8 INDX 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. 201-202 $C9-$CA LXSP 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). 203 $CB SFDX 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 34 = J 1 = RETURN 35 = 0 2 = CRSR RIGHT 36 = M 3 = F7 37 = K 4 = F1 38 = O 5 = F3 39 = N 6 = F5 40 = + 7 = CRSR DOWN 41 = P 8 = 3 42 = L 9 = W 43 = - 10 = A 44 = . 11 = 4 45 = : 12 = Z 46 = @ 13 = S 47 = , 14 = E 48 = LIRA (BRITISH POUND SIGN) 15 = NOT USED 49 = * (WOULD BE LEFT SHIFT) 50 = ; 16 = 5 51 = CLR/HOME 17 = R 52 = NOT USED 18 = D (WOULD BE RIGHT SHIFT) 19 = 6 53 = = 20 = C 54 = UP ARROW 21 = F (EXPONENTATION SIGN) 22 = T 55 = / 23 = X 56 = 1 24 = 7 57 = LEFT ARROW 25 = Y 58 = NOT USED 26 = G (WOULD BE CTRL) 27 = 8 59 = 2 28 = B 60 = SPACE BAR 29 = H 61 = NOT USED 30 = U (WOULD BE COMMODORE LOGO) 31 = V 62 = Q 32 = 9 63 = RUN/STOP 33 = I 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. 204 $CC BLNSW 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. 205 $CD BLNCT 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. 206 $CE GDBLN 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. 207 $CF BLNON 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. 208 $D0 CRSW 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). 209-210 $D1-$D2 PNT 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. 211 $D3 PNTR 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). 212 $D4 QTSW 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 213 $D5 LNMX 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. 214 $D6 TBLX 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 ($30C-$30F). 215 $D7 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. 216 $D8 INSRT 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. 217-242 $D9-$F2 LDTB1 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 ($288) 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. 243-244 $F3-$F4 USER 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. 245-246 $F5-$F6 KEYTAB 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. 247-248 $F7-$F8 RIBUF 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. 249-250 $F9-$FA ROBUF 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 251-254 $FB-$FE FREEZP 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. 255 $FF BASZPT 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.. ::::::::::::: ::Chapter 2:: :: :: :: Page 1 :: ::::::::::::: 256-511 $100-$1FF 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 ($1FF), and subsequent entries are built downward toward 256 ($100). 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: 256-266 $100-$10A Work Area for Floating Point to String Conversions Used in the conversion of numbers to the equivalent ASCII digits, and in scanning strings. 256-318 $100-$13E BAD 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. 319-511 $13F-$1FF 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. :::::::::::::::::::::::: :: Chapter 3 :: :: :: :: Pages 2 and 3 :: :: :: ::BASIC and the Kernal:: :: Working Storage :: :::::::::::::::::::::::: This area is used to store important information for the Operating System and BASIC. It contains vectors to certain BASIC routines as well as Operating System Kernal routines. Registers for RS-232 serial I/O are located here. Buffer space is allocated in this area for tape I/O, BASIC text input, and the keyboard queue. In addition, there are a number of Operating System variables and pointers here which the programmer can utilize. 512-600 $200-$258 BUF 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. Location Range: 601-630 ($259-$276) 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 ($259), the device number of the I/O device is put into the table at 611 ($263), and its secondary address is put into the table at 621 ($26D). 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. 601-610 $259-$262 LAT Kernal Table of Active Logical File Numbers 611-620 $263-$26C FAT Kernal Table of Device Numbers for Each Logical File 621-630 $26D-$276 SAT Kernal Table of Secondary Addresses for Each Logical File 631-640 $277-$280 KEYD 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 ($289)). 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 641-642 $281-282 MEMSTR 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 ($800). 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. 643-644 $283-284 MEMSIZ 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 ($400) 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. 645 $285 TIMOUT 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). 646 $286 COLOR 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 647 $287 GDCOL 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 ($286), 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. 648 $288 HIBASE 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 ($400), 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 649 $289 XMAX Maximum Keyboard Buffer Size The value here indicates the maximum number of characters that the keyboard buffer at 631 ($277) 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 ($281-$284) to be overwritten, but no real harm should result. 650 $28A RPTFLAG 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. 651 $28B KOUNT 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 ($28C) 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 ($28A) 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. 652 $28C DELAY 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 ($28B) 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. 653 $28D SHFLAG 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 ($291) 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. 654 $28E LSTSHF 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. 655-656 $28F-$290 KEYLOG 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 ($28D), 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 657 $291 MODE 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. 658 $292 AUTODN 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). Location Range: 659-663 ($293-$297) 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 ($293-$296), although the last two, which specify a nonstandard baud rate, are not used because that feature is not implemented. 659 $293 M51CTR 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 0 (bit value of 0) = 1 STOP Bit 1 (bit value of 128) = 0 STOP Bits Bits 6-5: WORD LENGTH 00 (bit value of 0) = 8 DATA Bits 01 (bit value of 32) = 7 DATA Bits 10 (bit value of 64) = 6 DATA Bits 11 (bit value of 96) = 5 DATA Bits Bit 4: Unused Bits 3-0: BAUD RATE 0000 (bit value of 0) = Nonstandard (User-Defined) Rate (Not Implemented) 0001 (bit value of 1) = 50 Baud 0010 (bit value of 2) = 75 Baud 0011 (bit value of 3) = 110 Baud 0100 (bit value of 4) = 134.5 Baud 0101 (bit value of 5) = 150 Baud 0110 (bit value of 6) = 300 Baud 0111 (bit value of 7) = 600 Baud 1000 (bit value of 8) = 1200 Baud 1001 (bit value of 9) = 1800 Baud 1010 (bit value of 10) = 2400 Baud 1011 (bit value of 11) = 3600 Baud (Not Implemented on the Commodore 64) 1100 (bit value of 12) = 4800 Baud (Not Implemented on the Commodore 64) 1101 (bit value of 13) = 7200 Baud (Not Implemented on the Commodore 64) 1110 (bit value of 14) = 9600 Baud (Not Implemented on the Commodore 64) 1111 (bit value of 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. 660 $294 M51CDR 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 XX0 (bit value of 0,64,128, or 192) = No Parity Generated or Received 001 (bit value of 32) = Odd Parity Transmitted and Received 011 (bit value of 96) = Even Parity Transmitted and Received 101 (bit value of 160) = Mark Parity Transmitted and Received 111 (bit value of 224) = Space Parity Transmitted and Received Bit 4: Duplex 0 (bit value of 0) = Full Duplex 1 (bit value of 16) = Half Duplex Bits 3-1: Unused Bit 0: Handshake Protocol 0 (bit value of 0) = 3 Line 1 (bit value of 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. 661-662 $295-$296 M51AJB 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 ($293) 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. 663 $297 $RSSTAT 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 7: 1 (bit value of 128) = Break Detected Bit 6: 1 (bit value of 64) = DTR (Data Set Ready) Signal Missing Bit 5: Unused Bit 4: 1 (bit value of 16) = CTS (Clear to Send) Signal Missing Bit 3: 1 (bit value of 8) = Receiver Buffer Empty Bit 2: 1 (bit value of 4) = Receiver Buffer Overrun Bit 1: 1 (bit value of 2) = Framing Error Bit 0: 1 (bit value of 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. 664 $298 BITNUM 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 ($293). 665-666 $299-$29A BAUDOF 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 ($293) 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). Location Range: 667-670 ($29B-$29E) 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. 667 $29B RIDBE 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. 668 $29C RIDBS 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. 669 $29D RODBS 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. 670 $29E RODBE 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. 671-672 $29F-$2A0 IRQTMP 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 ($314-$315) 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. 673 $2A1 ENABL 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 4: 1 (bit value of 16) = System is Waiting for Receiver Edge Bit 1: 1 (bit value of 2) = System is Receiving Data Bit 0: 1 (bit value of 1) = System is Transmitting Data 674 $2A2 Indicator of CIA #1 Control Register B Activity During Cassette I/O 675 $2A3 Save Area for CIA #1 Interrupt Control Register During Cassette Read 676 $2A4 Save Area for CIA #1 Control Register A During Cassette Read 677 $2A5 Temporary Index to the Next 40-Column Line for Screen Scrolling 678 $2A6 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. 679-767 $2A7-$2FF 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. Location Range: 768-779 ($300-$30B) 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 ($300). The indirect vector at 768 ($300) points to 42042 ($A43A), which is the instruction immediately following JMP ($300). 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 ($306), 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) 768-769 $300-$301 IERROR Vector to the Print BASIC Error Message Routine This vector points to the address of the ERROR routine at 58251 ($E38B). 770-771 $302-$303 IMAIN 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. 772-773 $304-$305 ICRNCH 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). 774-775 $306-$307 IQPLOP 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). 776-777 $308-$309 IGONE 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. 778-779 $30A-$30B IEVAL 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. Location Range: 780-783 ($30C-$30F) 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 int he .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. 780 $30C SAREG Storage Area for .A Register (Accumulator) 781 $30D SXREG Storage Area for .X Index Register 782 $30E SYREG Storage Area for .Y Index Register 783 $30F SPREG Storage Area for .P (Status) Register The Status (.P) register has seven different flags. Their bit assignments are as follows: Bit 7 (bit value of 128) = Negative Bit 6 (bit value of 64) = Overflow Bit 5 (bit value of 32) = Not Used Bit 4 (bit value of 16) = BREAK Bit 3 (bit value of 8) = Decimal Bit 2 (bit value of 4) = Interrupt Disable Bit 1 (bit value of 2) = Zero Bit 0 (bit value of 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. 784 $310 USRPOK 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. 785-786 $311-$312 USRADD 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 ($0005) instruction. The floating point result will be left in FAC1. 787 $313 Unused 788-789 $314-$315 CINV Vector to IRQ Interrupt Routine This vector points to the address of the routine that is executed when an IRQ interrupt occurs (normally 59953 ($FA31)). 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. 790-791 $316-$317 CBINV 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. 792-793 $318-$319 NMINV 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. Location Range: 794-813 ($31A-$32D) 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. 794-795 $31A-$31B IOPEN Vector to Kernal OPEN Routine (Currently at 62282 ($F34A)) 796-797 $31C-$31D ICLOSE Vector to Kernal CLOSE Routine (Currently at 62097 ($F291)) 798-799 $31E-$31F ICHKIN Vector to Kernal CHKIN Routine (Currently at 61966 ($F20E)) 800-801 $320-$321 ICKOUT Vector to Kernal CKOUT Routine (Currently at 62032 ($F250)) 802-803 $322-$323 ICLRCH Vector to Kernal CLRCHN Routine (Currently at 62259 ($F333)) 804-805 $324-$325 IBASIN Vector to Kernal CHRIN Routine (Currently at 61783 ($F157)) 806-807 $326-$327 IBSOUT Vector to Kernal CHROUT Routine (Currently at 61898 ($F1CA)) 808-809 $328-$329 ISTOP 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. 810-811 $32A-$32B IGETIN Vector to Kernal GETIN Routine (Currently at 61758 ($F13E)) 812-813 $32C-$32D ICLALL Vector to Kernal CLALL Routine (Currently at 62255 ($F32F)) 814-815 $32E-$32F USRCMD 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. 816-817 $330-$331 ILOAD Vector to Kernal LOAD Routine (Currently at 62622 ($F49E)) 818-819 $332-$333 ISAVE Vector: Kernal SAVE Routine (Currently at 62941 ($F5DD)) 820-827 $334-$33B Unused Eight free bytes for user vectors or other data. 828-1019 $33C-$3FB TBUFFER 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 ($340-$37F) can be used as sprite data block number 13, and locations 896-959 ($380-$3BF) 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 ($33C)) 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. 1020-1023 $3FC-$3FF Unused Four more free bytes. :::::::::::::::::::::::: :: Chapter 4 :: :: :: :: 1K to 40K :: :: :: :: Screen Memory, :: ::Sprite Pointers, and:: :: BASIC Program Text :: :::::::::::::::::::::::: 1024-2047 $400-$7FF VICSCN Video Screen Memory Area This is the default location of the video screen memory area, which contains the video matrix and the sprite data pointers. Keep in mind, however, that the video screen memory area can be relocated to start on any even 1K boundary. Its location at any given moment is getermined by the VIC-II chip memory control register at 53272 ($D018), and the VIC-II memory bank select bits on CIA #2 Data Port A (56576, $DD00). 1024-2023 $400-$7E7 Video Matrix: 25 Lines by 40 Columns The video matrix is where thext screen characters are stored in RAM. Normally, the VIC-II chip will treat each byte of memory here as a screen display code and will display the text character that corresponds to that byte of code. The first byte of memory here will be displayed in the top-left corner of the screen, and subsequent bytes will be displayed in the columns to the right and the rows below that character. It is possible to make text or graphics characters appear on the screen by POKEing their screen codes directly into this area of RAM. For example, the letter A has a screen code value of 1. Therefore, POKE 1024,1 should make the letter A appear in the top-left corner of the screen. However, you should be aware that the most current version of the Operating System initializes the color RAM which is used for the foreground color of text characters to the same value as the background color every time that the screen is cleared. The result is that although the POKE will put a blue A on the screen, you won't be able to see it because it is the same color blue as the background. This can be remedied by POKEing a different value into color RAM (which starts at 55296 ($D800)). A POKE 1024,1:POKE 1024+54272,1 will put a white A in the upper-left corner of the screen. The loop FOR I=0 TO 255:POKE 1024+I,I:POKE 1024+54272+I,1:NEXT will display all of the characters in white at the top of the screen. Another solution to the color RAM problem is to fool the Operating System into initializing the color RAM for you. If you change the background color to the desired foreground color before you clear the screen, color RAM will be set to that color. Then, all you have to do is change the background color back to what it was. This example will show how it's done: 10 POKE 53281,2:REM BACKGROUND IS RED 20 PRINT CHR$(147):REM CLEAR SCREEN 30 POKE 53281,1:REM BACKGROUND IS WHITE 40 POKE 1024,1:REM RED "A" APPEARS IN TOP LEFT CORNER 2040-2047 $7F8-$7FF Sprite Shape Data Pointers The last eight bytes of the video matrix (whether it is here at the default location, or has been relocated elsewhere) are used as pointers to the data blocks used to define the sprite shapes. Each sprite is 3 bytes wide (24 bits) by 21 lines high. It therefore requires 63 bytes for its shape definition, but it actually uses 64 bytes in order to arrive at an even 256 shape blocks in the 16K area of RAM which the VIC-II chip addresses. Each pointer holds the current data block being used to define the shape of one sprite. The block numver used to define the shape of Sprite 0 is held in location 2040 ($7F8), the Sprite 1 shape block is designated by location 2041 ($7F9), etc. The value in the pointer times 64 equals the starting location of the sprite shape data table. For example, a value of 11 in location 2040 indicates that the shape data for Sprite 0 starts at address 704 (11*64), and continues for 63 more bytes to 767. For additional information on sprite graphics, see the entries for individual VIC-II chip sprite graphics locations, and the summary at the beginning of the VIC-II chip section, at 53248 ($D000). 2048-40959 $800-$9FFF BASIC Program Text This is the area where the actual BASIC program text is stored. The text of a BASIC program consists of linked lines of program tokens. Each line contains the following: 1. A two-byte pointer to the address of the next program line (in standard low-byte, high-byte order). After the last program line, a link pointer consisting of two zeros marks the end of the program. 2. A two-byte line number (also in low-byte, high-byte order). 3. The program commands. Each keyword is stored as a one-byte character whose value is equal to or greater than 128. Print, for example, is stored as the number 151. Other elements of the BASIC command, such as the variable names, string literals ("HELLO"), and numbers, are stored using their ASCII equivalents. 4. A 0 character, which acts as a line terminator. In order for BASIC to work correctly, the first character of the BASIC text area must be 0. A quick review of the BASIC pointers starting at 43 ($2B) reveals that the layout of the BASIC program area (going from lower memory addresses to higher) is as follows: BASIC Program Text Non-Array Variables and String Descriptors Array Variables Free Area (Reported by FRE(0)) String Text Area (Strings build from top of memory down into free area) BASIC ROM It is interesting to note that the NEW command does not zero out the text area but rather replaces the first link address in the BASIC program with two zeros, indicating the end of the program. Therefore, you can recover a program from a NEW by replacing the first link adress, finding the address of the two zeros that actually mark the end of the program, and setting the pointers at 45, 47, and 49 (which all point to the end of a BASIC program before the program is RUN) to the byte following these zeros. 4096-8191 $1000-$1FFF Character ROM Image for VIC-II Chip When Using Memory Bank 0 (Default) Though the VIC-II chip shares memory with the 6510 processor chip, it does not always see that memory in exactly the same way as the main microprocessor. Although the 6510 accesses RAM at these locations, when the VIC-II is banked to use the first 16K of RAM (which is the default condition), it sees the character ROM here (the 6510 cannot access this ROM unless it is switched into its memory at 49152 ($C000)). This solves the riddle of how the VIC-II chip can use the character ROM at 49152 ($C000) for character shape data and RAM at 1024 ($400), when it can only address memory within a 16K range. It also means that the RAM at 4096-8191 cannot be used for screen display memory or user-defined character dot data, and sprite data blocks 64-127 are not accessible. You can verify this by turning on bitmap graphics with the screen memory set to display addresses from 0 to 8192. You will see that the bottom portion of the screen shows all of the text character shapes stored in the ROM. For more information on the format of text character data storage, see the description of the Character ROM at 49152 ($C000). 32768 $8000 Autostart ROM Cartridge An 8K or 16K autostart ROM cartridge designed to use this as a starting memory address may be plugged into the Expansion Port on the back. If the cartridge ROM at locations 32772-32776 ($8004-$8008) contains the numbers 195, 194, 205, 56, 48 ($C3, $C2, $CD, $38, $30) when the computer powers up, it will start the program pointed to by the vector at locations 32768-32769 ($8000-$8001), and will use 32770-32771 ($8002-$8003) for a warm start vector when the RESTORE key is pressed. These characters are PETASCII for the inverse letters CBM, followed by the digits 80. An autostart cartridge may also be addressed at 40960 ($A000), where it would replace BASIC, or at 61440 ($F000), where it would replace the Kernal. It is possible to have a 16K cartridge sitting at 32768 ($8000), such as Simon's BASIC, which can be turned on and off so that the BASIC ROM underneath can also be used. Finally, it is even possible to have bank-selected cartridges, which turn banks of memory in the cartidge on and off alternately, so that a 32K program could fit into only 16K of addressing space. 36864-40959 $9000-$9FFF Character ROM Image for VIC-II Chip When Using Memory Bank 2 When the VIC-II chip is set up to use the third 16K block of memory for graphics (as would be the case when the 64 is set up to emulate the PET, which has its text screen memory at 32768 ($8000), it sees the character generator ROM at this address (see entry at 4096 ($1000) above for more details). It should be noted that the character ROM is available only when the VIC-II chip is using banks 0 or 2. When using one of the other two banks, the user must supply all of the character shape data in a RAM table. :::::::::::::: ::Chapter 5 :: :: :: :: 8K BASIC :: ::ROM and 4K:: :: Free RAM :: :::::::::::::: Locations 40960 to 49152 ($A000 to $BFFF) are used by the BASIC ROM when it is selected (which is the default condition). BASIC is the 64's main program, which is always run if there is no autostart cartridge inserted at power-up time. When the 64 tells you READY, that's BASIC talking. The BASIC interpreter that comes with the 64 is, aside from being located in a different memory space, almost identical to the Microsoft BASIC interpreter found on the VIC-20. Both of these interpreters are slightly modified versions of PET BASIC 2.0, also known as PET BASIC 3.0 or Upgrade BASIC, because it was an upgraded version of the BASIC found on the original PET. This is a somewhat mixed blessing, because while PET BASIC was, in its day, quote an advanced language for use with an eight-bit microprocessor, it lacks several of the features (such as error trapping) which are now standard on most home computers. And, of course, it makes no provision whatever for easy use of the many graphics and sound capabilities made available by the new dedicated video and sound support chips. On the other hand, its faithfulness to the original Commodore BASIC allows a large body of software to be translated for the 64 with little change (in most cases, the PET Emulator program from Commodore will allow you to run PET programs with no changes). Programming aids and tricks developed for the PET and VIC will, for the most part, carry over quite nicely to the 64. Although there is no official source code listing of the ROM available from Commodore, this version of BASIC has been around long enough that it has been thoroughly disassembled, dissected, and documented by PET users. The labels used here correspond to those used by Jim Butterfield in his PET memory maps, which are well-known among PET BASIC users. They should, therefore, provide some assistance in locating equivalent routines on the two machines. A good description of the workings of PET BASIC can be found in Programming the PET/CBM by Raeto West. It is beyond the scope of this book to detail the inner workings of each routine in the BASIC interpreter. However, the following summary of routines and their functions should aid the user who is interested in calling BASIC routines from his or her own program, or in modifying the BASIC. Please keep in mind that the entry and exit points listed for routines that perform a particular function are to be used as guideposts, and not absolutes. In fact, BASIC enters many of these routines from slightly different places to accomplish different tasks. Some subroutines are called by so many commands that it is hard to say which they belong to. You will even find that some whole commands are part of other commands. Where it is important for you to know the details of a particular routine, you will need to obtain a disassembly of that section and look at the machine language program itself. It should be noted that when BASIC is not neede,d it can be switched out and the RAM underneath can be accessed by the VIC-II chip and used for screen graphics. See location 56576 ($DD00) for more information. 40960-40961 $A000-$A001 Cold Start Vector This vector points to the address of the routine used to initialize BASIC. After the Operating System finishes its power-on activities, it enters the BASIC program through this vector. The most visible effect of the BASIC initialization routine is that the screen is cleared, and the words: **** COMMODORE 64 BASIC V2 **** are printed along with the BYTES FREE message. For details of the steps taken during the initialization of BASIC, see the entry for 58260 ($E394), the current cold start entry point. 40962-40963 $A002-$A003 Warm Start Vector The warm start vector points to the address of the routines used to reset BASIC after the STOP/RESTORE key combination is pressed. This is the same address to which the BRK instruction is vectored. When BASIC is entered through this vector, the program in memory is not disturbed. For more information, see the entry for 58235 ($E37B), the current warm start entry point. 40964-40971 $A004-$A00B ASCII Text characters CBMBASIC The ASCII characters for the letters CBMBASIC are located here. Possibly an identifier, this text is not referenced elsewhere in the program. 40972041941 $A00C-$A051 STMDSP Statement Dispatch Vector Table This table contains two-byte vectors, each of which points to an address which is one byte before the address of one of the routines that perform a BASIC statement. The statements are in token number order. When it comes time to execute a statement, the NEWSTT routine at 42926 ($A7AE) places this address-1 on the stack and jumps to the CHRGET routine. The RTS instruction at the end of that routine causes the statement address to be pulled off the stack, incremented, and placed in the Program Counter, just as if it were the actual return address. This table is handy for locating the address of the routine that performs a BASIC statement, so that the routine can be disassembled and examined. To aid in this purpose, the table is reproduced below with the actual target address, and not in the address-1 format used by BASIC. Token # Statement Routine Address 128 $80 END 43057 $A831 129 $81 FOR 42818 $A742 130 $82 NEXT 44318 $AD1E 131 $83 DATA 43256 $A8F8 132 $84 INPUT# 43941 $ABA5 133 $85 INPUT 43967 $ABBF 134 $86 DIM 45185 $B081 135 $87 READ 44038 $AC06 136 $88 LET 43429 $A9A5 137 $89 GOTO 43168 $A8A0 138 $8A RUN 43121 $A871 139 $8B IF 43304 $A928 140 $8C RESTORE 43037 $A81D 141 $8D GOSUB 43139 $A883 142 $8E RETURN 43218 $A8D2 143 $8F REM 43323 $A93B 144 $90 STOP 43055 $A82F 145 $91 ON 43339 $A94B 146 $92 WAIT 47149 $B82D 147 $93 LOAD 57704 $E168 148 $94 SAVE 57686 $E156 149 $95 VERIFY 57701 $E165 150 $96 DEF 46003 $B3B3 151 $97 POKE 47140 $B824 152 $98 PRINT# 43648 $AA80 153 $99 PRINT 43680 $AAA0 154 $9A CONT 43095 $A857 155 $9B LIST 42652 $A69C 156 $9C CLR 42590 $A65E 157 $9D CMD 43654 $AA86 158 $9E SYS 57642 $E12A 159 $9F OPEN 57790 $E1BE 160 $A0 CLOSE 57799 $E1C7 161 $A1 GET 43899 $AB7B 162 $A2 NEW 42562 $A642 41042-41087 $A052-$A07F FUNDSP TABLE Function Dispatch Vector Table This table contains two-byte vectors, each of which points to the address of one of the routines that performs a BASIC function. A function is distinguished by a following argument, in parentheses. The expression in the parentheses is first evaluated by the routines which begin at 44446 ($AD9E). Then this table is used to find the address of the function that corresponds to the token number of the function to be executed. The substance of this table, which can be used for locating the addresses of these routines, is reproduced below. Note that the address for the USR function is 784 ($310), which is the address of the JMP instruction which precedes the user-supplied vector. Token # Function Routine Address 180 $B4 SGN 48185 $BC39 181 $B5 INT 48332 $BCCC 182 $B6 ABS 48216 $BC58 183 $B7 USR 784 $0310 184 $B8 FRE 45949 $B37D 185 $B9 POS 45982 $B39E 186 $BA SQR 49009 $BF71 187 $BB RND 57495 $E097 188 $BC LOG 45794 $B9EA 189 $BD EXP 49133 $BFED 180 $BE COS 57956 $E264 191 $BF SIN 57963 $E26B 192 $C0 TAN 58036 $E2B4 193 $C1 ATN 58126 $E30E 194 $C2 PEEK 47117 $B80D 195 $C3 LEN 46972 $B77C 196 $C4 STR$ 46181 $B465 197 $C5 VAL 47021 $B7AD 198 $C6 ASC 46987 $B78B 199 $C7 CHR$ 46828 $B6EC 200 $C8 LEFT$ 46848 $B700 201 $C9 RIGHT$ 46892 $B72C 202 $CA MID$ 46903 $B737 41088-41117 $A080-$A09D OPTAB Operator Dispatch Vector Table This table contains two-byte vectors, each of which points to an address which is one byte before the address of one of the routines that perform a BASIC math operation. For the reasoning behind the one-byte offset to the true address, see the entry for location 40972 ($A00C). In addition, each entry has a one-byte number which indicates the degree of precedence that operation takes. Operations with a higher degree of precedence are performed before operations of a lower degree (for example, in the expression A=3+4*6, the 4*6 operation is performed first, and 3 is added to the total). The order in which they are performed is: 1. Expressions in parentheses 2. Exponentation (raising to a power, using the up-arrow symbol) 3. Negation of an expression (-5, -A) 4. Multiplication and division 5. Addition and subtraction 6. Relation tests (=, <>, <, >, <=, >= all have the same precedence) 7. NOT (logical operation) 8. AND (logical operation) 9. OR (logical operation) The substance of this table, which can be used to locate the addresses of the math routines, is given below. Note that less that, equal, and greater than operators all use the same routines, though they have different token numbers. Token # Operator Routine Address 170 $AA + (ADD) 47210 $B86A 171 $AB - (SUBTRACT) 47187 $B853 172 $AC * (MULTIPLY) 47659 $BA2B 173 $AD / (DIVIDE) 47890 $BB12 174 $AE ^ (EXPONENTIATE) 49019 $BF7B 175 $AF AND (LOGICAL AND) 45033 $AFE9 176 $B0 OR (LOGICAL OR) 45030 $AFE6 177 $B1 > (GREATER THAN) 49076 $BFB4 178 $B2 = (EQUAL TO) 44756 $AED4 179 $B3 < (LESS THAN) 45078 $B016 41118-41373 $A09E-$A19D RESLST List of Keywords This table contains a complete list of the reserved BASIC keywords (those combinations of ASCII text characters that cause BASIC to do something). The ASCII text characters of these words are stored in token number order. Bit #7 of the last letter of each word is set to indicate the end of the word (the last letter has 128 added to its true ASCII value). When the BASIC program text is stored, this list of words is used to reduce any keywords to a single-byte value called a token. The command PRINT, for example, is not stored in a program as five ASCII bytes, but rather as the single token 153 ($99). When the BASIC program is listed, this table is used to convert these tokens back to ASCII text. The entries in this table consist of the following: 1. The statements found in STMDSP at 40972 ($A00C), in the token number order indicated (token numbers 128-162). 2. Some miscellaneous keywords which never begin a BASIC statement: Token # Keyword 162 $A3 TAB( 164 $A4 TO 165 $A5 FN 166 $A6 SPC( 167 $A7 THEN 168 $A8 NOT 169 $A9 STEP 3. The math operators found in OPTAB at 41088 ($A080), in the token number order indicated (token numbers 170-179). 4. The functions found in FUNDSP at 41042 ($A052), in the token number order indicated (token numbers 182-202). 5. The word GO (token number 203 ($CB)). This word was added to the table to make the statement GO TO legal, to afford some compatibility with the very first PET BASIC, which allowed spaces within keywords. 41374-41767 $A19E-$A327 ERRTAB ASCII Text of BASIC Error Messages This table contains the ASCII text of all of the BASIC error messages. As in the keyword table, Bit 7 of the last letter of each message is set to indicate the end of the message. Although we've all seen some of them at one time or another, it's somewhat daunting to see the whole list at once. The possible errors you can make include: 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 FILENAME 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 Message number 30, BREAK, is located in the Miscellaneous Messages table below. 41768-41828 $A328-$A364 Error Message Vector Table This table contains the two-byte address of the first letter of each of the 30 error messages. 41829-41865 $A365-$A389 Miscellaneous Messages The text of some of the other messages that BASIC can give you is stored here. This text includes cursor movement characters, and each message ends with a 0 character. The messages are: 1) Carriage return, OK, carriage return 2) Space, space, ERROR 3) Space, IN, space 4) Carriage return, linefeed, READY., carraige return, linefeed 5) Carriage return, linefeed, BREAK 41866-41911 $A38A-$A3B7 FNDFOR Find FOR on Stack This routine searches the stack for the blocks of data entries which are stored by each FOR command. For more information on the data that FOR places on the stack, see location 256 ($100). 41912 $A3B8 BLTU Open a Space in Memory for a New Program Line or Variable When a new nonarray variable is being created, or when a BASIC program line is being added or replaced, this routine is used to make room for the addition. It first checks to see if space is available, and then moves the program text and/or variables to make room. 41979-41991 $A3FB-$A407 GETSTK Check for Space on Stack Before undertaking an operation that requires stack space, this routine is used to check if there is enough room on the stack. If there is not, an OUT OF MEMORY error is issued. 41992-42036 $A408-$A434 REASON Check for Space in Memory This is the subroutine that checks to see if there is enough space in free memory for proposed additions such as new lines of program text. If not, it calls for garbage collection, and if this still does not produce enough space, an OUT OF MEMORY error is issued. 42037-42088 $A435-$A468 OMERR OUT OF MEMORY Error Handler This routine just sets the error message code, and falls through to the general error handler. 42039-42088 $A437-$A468 ERROR General Error Handler The error number is passed to this routine in the .X register, and it displays the appropriate error message. Since this routine is vectored through RAM at 768 ($300), you can divert this vector to the address of your own routine, which would allow error trapping, or the addition of new commands. 42089-42099 $A474-$A47F READY Print READY This routine displays the word READY, sets the Kernal message flag to show that direct mode is operative, and falls through to the main BASIC loop. 42112-42139 $A480-$A49B MAIN Main Loop, Receives Input and Executes Immediately or Stores as Program Line This is the main BASIC program loop. It jumps through the RAM vector at 770 ($302), so this routine can be diverted. The routine gets a line of input from the keyboard, and checks for a line number. If there is a line number, the program branches to the routine that stores a line of program text. If there is no line number, it branches to the routine that executes statements. 42140 $A49C MAIN1 Add or Replace a Line of Program Text This routine calls subroutines to get the line number, tokenize keywords, and then looks for a line with the same line number. If it finds a line with the same number, the routine deletes that line by moving all higher program text and variables down to where it started. The new line is then added. Since the CLR routine is called, the value of all current program variables is lost. 42291 $A533 LINKPRG Relink Lines of Tokenized Program Text Each line of program text starts with a pointer to the address of the next line (link address). This routine scans each line to the end (which is marked with a 0), and calculates the new link address by adding the offset to the address of the current statement. 42336 $A560 INLIN Input a Line to Buffer from Keyboard This subroutine calls the Kernal CHRIN routine (61783, $F157) to obtain a line of input from the current input device (usually the keyboard). It stores the characters in the BASIC text input buffer at 512 ($200) until a carriage return or 89 characters have been received. The keyboard device will never return more than 80 characters before a carriage return, but other devices can output a longer line. An error will occur if the line goes over 80 characters. 42361 $A579 CRUNCH Tokenize Line in Input Buffer When a line of program text has been input into the BASIC text buffer at 512 ($200), this routine goes through the line and changes any keywords or their abbreviations, which do not appear in quotes, into their corresponding token. This command is vectored through RAM at 772 ($304), so it can be diverted in order to add new commands. 42515 $A613 FINDLN Search for Line Number This routine searches through the program text, trying to match the two-byte integer line number that is stored in 20-21 ($14-$15). If it is found, 95-96 ($5F-$60) will be set as a pointer to the address of the link field for that line, and the Carry flag will be set. If it is not found, the Carry flag will be cleared. 42562 $A642 SCRTCH Perform NEW The NEW command stores two zeros in the link address of the first program line to indicate the end of program, and sets the end of program pointer at 45-46 ($2D-$2E) to point to the byte past those zeros. It continues through to the CLR command code. 42590 $A65E CLEAR Perform CLR The CLR command closes all I/O files with the Kernal CLALL routine (62255, $F32F). It eliminates string variables by copying the end of memory pointer at 55-56 ($37-$38) to the bottom of strings pointer at 51-52 ($33-$34). It also copies the pointer to the end of BASIC program text at 49-50 ($31-$31) to the pointer to the start of nonarray variables at 45-46 ($2D-$2E) and the start of array variables at 47-48 ($2F-$30). This makes these variables unusable (although the contents of these areas are not actually erased). RESTORE is called to set the data pointer back to the beginning, and the stack is cleared. 42638 $A68E RUNC Reset Pointer to Current Text Character to the Beginning of Program Text This routine resets the CHRGET pointer TXTPTR (122-123, $7A-$7B) so that the next byte of text that the interpreter will read comes from the beginning of program text. 52652 $A69C LIST Perform LIST This routine saves the range of lines to be printed in pointers at 95-96 ($5F- $60) and 20-21 ($14-$15), and then prints them out, translating any tokens back to their ASCII equivalent. 42775 $A717 QPLOP Print BASIC Tokens as ASCII Characters This is the part of the LIST routine that chagnes one-byte program tokens back to their ASCII text characters. The routine is vectored through RAM at 774 ($306), so it is possible to list out new command words that you have added by changing this vector to detour through your own routine. 42818 $A742 FOR Perform FOR FOR is performed mostly by saving the needed information for the NEXT part of the command on the stack (see the entry for 256 ($100) for details). This includes the TO termination value, so if the upper limit is a variable, the current value of the variable will be stored, and you cannot end the loop early by decreasing the value of the TO variable within the loop (although you can end it early by increasing the value of the FOR variable within the loop). Also, since the TO expression is evaluated only once, at the time FOR is performed, a statement such as FOR I=1 TO I+100 is valid. The terminating value is not checked until NEXT is executed, so the loop statements always execute at least once. The variable used by FOR must be a nonarray floating point variable. Reusing the same FOR variable in a loop that is still active will cause the previous FOR loop and all intervening loops to be cancelled. 42926 $A7AE NEWSTT Set Up Next Statement for Execution This routine tests for the STOP key, updates the pointer to the current line number, and positions the text pointer to read the beginning of the statement. 42980 $A7E4 GONE Read and Execute the Next Statement This is the routine which gets the next token and executes the statement. It is vectored through RAM at 776 ($308) to allow the addition and execution of new statement tokens. Since a statement must always start with a token or an implied LET statement, this routine checks to see if the first character is a valid token. If it is, the address is placed on the stack, so that a call to CHRGET will return to the address of the code that executes the statement (see the table of statement tokens at 40972 ($A00C)). An invalid token will cause a SYNTAX ERROR. A character whose ASCII value is less that 128 will cause LET to be executed. 43037 $A81D RESTOR Perform RESTORE The RESTORE command simply resetes the DATA pointer at 65-66 ($41-$42) from the start of BASIC pointer at 43-44 ($2B-$2V). 43052 $A82C Test STOP Key for Break in Program The Kernal STOP routine is called from here, and if the key is pressed, the STOP (63213, $F6ED) command, below, is executed. 43055 $A831 END Perform END The current line number and text pointers are preserved for a possible CONT command, and the READY prompt is printed. If a STOP key break occured, the BREAK message is printed first. 43095 $A857 CONT Perform CONT The CONT statement is performed by moving the saved pointers back to the current statement and current text character pointers. If the saved pointers cannot be retrieved, the CAN'T CONTINUE error statement is printed. 43121 $A871 RUN Perform RUN RUN is executed by calling the Kernal SETMSG (65048, $FE18) routine to set the message flag for RUN mode and performing a CLR to start the program. If a line followed RUN, a GOTO is executed after the CLR. 43139 $A883 GOSUB Perform GOSUB This statement pushes the pointers to the current text character and current line onto the stack, along with a constant 141 ($8D) which identifies the block as saved GOSUB information to be used by RETURN. The GOTO is called. 43168 $A8A0 GOTO Perform GOTO This statement scans BASIC for the target line number (the scan starts with the current line if the target line number is higher, otherwise it starts with the first line). When the line is found, the pointers to the current statement and text character are changed, so that the target statement will be executed next. 43218 $A8D2 RETURN Perform RETURN The RETURN statement finds the saved GOSUB data on the stack, and uses it to restore the pointers to the current line and current character. This will cause execution to continue where it left off when GOSUB was executed. 43256 $A8F8 DATA Perform DATA DATA uses the next subroutine to find the offset to the next statement, and adds the offset to the current pointers so that the next statement will be executed. If effect, it skips the statement, much like REM. 43270 $A906 DATAN Search Program Text for the End of the Current BASIC Statement This routine starts at the current byte of program text and searches until it finds a zero character (line delimiter) or a colon character that is not in quotes (statement delimiter). 43304 $A928 IF Perform IF IF uses the FRMEVL routine at 44446 ($AD9E) to reduce the expression which follows to a single term. If the expression evaluates to 0 (false), the routine falls through to REM. If it is not 0, GOTO or the statement following THEN is executed. 43323 $A93B REM Perform REM The REM statement is executed by skipping all program text until the beginning of the next statement. It is actually a part of the IF statement, which continues for a few bytes after the REM part. 43339 $A94B ONGOTO Perform ON GOTO or ON GOSUB ON is performed by converting the argument to an integer, and then skipping a number between commas each time that the integer is decremented until the argument reaches 0. If a GOTO or GOSUB is the next token, the current number between commas is used to execute one of those statements. If the numbers between commas are used up before the argument reaches 0, the statement has no effect, and the next statement is executed. 43371 $A96B LINGET Convert an ASCII Decimal Number to a Two-Byte Binary Line Nmumber This subroutine is used by several statements to read a decimal number, convert it to a two-byte integer line number (in low-byte, high-byte format), and check that it is in the correct range of 0-63999. 43429 $A9A5 LET Perform LET The LET command causes variables to be created and initialized, or to have a new value assigned. It handles all types of array or nonarray variables: strings, floating point, integers, ST, TI, and TI$. The routine is composed of several subroutines that evaluate the variable, evaluate the assigned expression, check that the assigned value is suitable for a variable of that type, and then assign a value to the existing variable, or create a new variable. 43648 $AA80 PRINTN Perform PRINT# The PRINT# statement calls CMD and then closes the output channel with the Kernal CLRCHN routine (62259, $F333). 43654 $AA86 CMD Perform CMD This routine calls the Kernal CHKOUT routine (62032, $F250), and calls PRINT to send any included text to the device. Unlike PRINT# it leaves the output channel open, so that output continues to go to that device. 43680 $AAA0 PRINT Perform PRINT The PRINT routine has many segments, which are required for the various options which can be added to it: TAB, SPC, comman, semicolon, variables, PI, ST, TI, and TI$. Eventually, all output is converted to strings, and the Kernal CHROUT routine is called to print each character. 43806 $AB1E STROUT Print Message from a String Whose Address Is in the .Y and .A Registers This part of the PRINT routine outputs a string whose address is in the Accumulator (low byte) and .Y register (high byte), and which ends in a zero byte. 43853 $AB4D DOAGIN Error Message Formatting Routines for GET, INPUT, and READ 43899 $AB7B GET Perform GET and GET# The GET routine first makes sure that the program is not in direct mode. It opens an input channel using the Kernal CHKIN routine (61966, $F20E) if a number sign was added to make GET#. Then it calls the common I/O routines in READ to get a single character, and causes the input channel to be closed if one was opened. 43941 $ABA5 INPUTN Perform INPUT# This routine opens an input channel with the Kernal CHKIN routine, calls INPUT, and then closes the channel with a CHKOUT routine (62032, $F250). Extra data is discarded without an EXTRA IGNORED message, and a FILE DATA ERROR message is issued when the data type is not suitable for the type of variable used. 43967 $ABBF INPUT Perform INPUT The INPUT routine checks to make sure that direct mode is not active, prints prompts, receives a line of input from the device, and jumps to the common code in READ that assigns the input to the variables which were named. 44038 $AC06 READ Perform READ This routine includes the READ command and common code for GET and INPUT. The READ command locates the next piece of DATA, reads the text, and converts it to the appropriate type of data to be assigned to a numeric or string variable. 44284 $ACFC EXIGNT ASCII Text for Input Error Messages The text stored here is ?EXTRA IGNORED and ?REDO FROM START, each followed by a carriage return and a zero byte. 44318 $AD1E NEXT Perform NEXT NEXT is executed by finding the appropriate FOR data on the stack, adding the STEP value to the FOR variable, and comparing the result to the TO value. If the loop is done, the stack entries for that FOR command are removed from the stack. If the loop hasn't reached its limit, the pointers to the current statement and text character are updated from the FOR stack entry, which causes execution to continue with the statement after the FOR statement. 44426 $AD8A FRMNUM Evaluate a Numeric Expression and/or Check for Data Type Mismatch This routine can be called from different entry points to check the current data against the desired data type (string or numeric) to see if they match. If they don't, a TYPE MISMATCH error will result. 44446 $AD9E FRMEVAL Evaluate Expression This is the beginning point of a very powerful group of subroutines which are used extensively by BASIC. The main purpose of these routines is to read in the ASCII text of BASIC expressions, separate the operators and terms of the expression, check them for errors, combine the individual terms by performing the indicated operations, and obtain a single value which the BASIC program can use. This can be a very complex task, and expressions an be of the string or numeric type, and can contain any type of variable, as well as constants. At the end, the flag which shows whether the resulting value is string or numeric at 13 ($D) is set, and if the value is numeric, the flag at 14 ($E) is set as well, to show if it is an integer or floating point numer. 44675 $AE83 EVAL Convert a Single Numeric Term from ASCII Text to a Floating Point Number This routine reduces a single arithmetic term which is part of an expression from ASCII text to its floating point equivalent. If the term is a constant, the routine sets the data type flag to number, sets the text pointer to the first ASCII numeric character, and jumps to the routine which converts the ASCII string to a floating point number. If the term is a variable, the variable value is retrieved. If it is the PI character, the value of PI is moved into the Floating Point Accumulator. This routine is vectored through RAM at 778 ($30A). 44712 $AEA8 PIVAL PI Expressed as a Five-Byte Floating Point Number The value of PI is stored here as a five-byte floating point number. 44785 $AEF1 PARCHK Evaluate Expression Within Parentheses This routine evaluates an expression within parentheses by calling the syntax checking routines that look for opening and closing parentheses, and then calling FRMEVL (4446, $AD9E) for each level of parentheses. 44791 $AEF7 CHKCLS Check for and Skip Closing Parentheses 44794 $AEFA CHKOPN Check for and Skip Opening Parentheses 44799 $AEFF CHKCOM Check for and Skip Comma This syntax checking device is the same in substance as the two checking routines above. It is used when the next character should be a comma. If it is not, a SYNTAX ERROR retults. If it is, the character is skipped and the next character is read. Any character can be checked for and skipped this way by loading the character into the Accumulator and entering this routine from SYNCHR at 44799 ($AEFF). 44808 $AF08 SNERR Print Syntax Error Message 44843 $AF2B ISVAR Get the Value of a Variable 44967 $AFA7 ISFUN Dispatch and Evaluate a Function If a BASIC function (like ASC("A")) is part of an expression, this routine will use the function dispatch table at 42242 ($A502) to set up the address of th proper function routine, and then branch to that routine. 45030 $AFE6 OROP Perform OR The OR routine sets the .Y register as a flag, and falls through to the AND routine, which also performs OR. 45033 $AFE9 ANDOP Perform AND The AND routine changes the parameters to two-byte integer values, and performs the appropriate logical operation (AND or OR). A result of 0 signifies false, while a result of -1 signifies true. 45078 $B016 DORE1 Perform Comparisons This routine does the greater than (>), less than (<), and equal (=) comparisons for foating point numbers and strings. The result in the Floating Point Accumulator will be 0 if the comparison is false, and -1 if it is true. 45185 $B018 DIM Perform DIM This command calls the next routine to create an array for every variable dimensioned (since a statement can take the form DIM A(12), B(13), C(14)...). If the array element is referenced before a DIM statement (for example, A(3)=4), the array will be dimensioned to 10 (as if DIM A(10) were executed). Remember, DIMensioning an array to 10 really creates 11 elements (10). The 0 element should always be considered in calculating the size to DIMension your array. 45195 $B08B PTRGET Search for a Variable and Set It Up If It Is Not Found This routine attempts to locate a variable by searching for its name in the variable area. If an existing variable of that name cannot be found, one is created with the NOTFNS routine below. 45331 $B113 Check If .A Register Holds Alphabetic ASCII Character This is part of the check for a valid variable name (it must start with an alphabetic character). 45341 $B11D NOTFNS Create a New BASIC Variable This routine makes space for a seven-byte descriptor by moving the variable storage area seven bytes higher in memory, and then creates the descriptor. 45445 $B185 FINPTR Return the Address of the Variable That Was Found or Created This routine stores the address of the variable that was found or created by the preceding routines in a pointer at 71-72 ($47-$48). 45460 $B194 ARYGET Allocate Space for Array Descriptors This routine allocates five bytes plus two bytes for every dimension specified for the array descriptor. 45477 $B1A5 N32768 The Constant -32768 in Five-Byte Floating Point Format This constant is used for range checking in the conversion of a floating point number to a signed integer (the minimum inter value is -32768). 45482 $B1AA Convert a Floating Point Number to a Signed Integer in .A and .Y Registers This subroutine calls AYINT, below, which checks to make sure that the number in the Floating Point Accumulator is between 32767 and -32768, and converts it to a 16-bit signed integer in 100-101 ($64-$65), high byte first. It leaves the high byte of the integer in the Accumulator, and the low byte in the .Y register. Although this routine does not appear to be referenced anywhere in BASIC, the vector at locations 3-4 points to its address. Presumably, it is provided for the benefit of the user who wishes to pass parameters in a USR call, or the like. 45490 $B1B2 INTIDX Input and Convert a Floating Point Subscript to a Positive Integer This routine converts a floating point subscript value to an integer, making sure first that it is positive. 45503 $B1BF AYINT Convert a Floating Point Number to a Signed Integer This subroutine first checks to make sure that the number in the Floating Point Accumulator is between 32767 and -32768. If it is not, an ILLEGAL QUANTITY error results. If it is, the routine converts it to a 16-bit signed integer with the high byte in location 100 ($64), and the low byte in location 101 ($65). 45521 $B1D1 ISARY Find Array Element or Create New Array in RAM This routine searches for an array. If it is found, the subscript value is checked to see if it is valid, and pointers to the array and element of the array are set. If it is not found, the array is created, and the pointers set. 45637 $B245 BSERR Print BAD SUBSCRIPT Error Message 45640 $B248 FCERR Print ILLEGAL QUANTITY Error Message 45900 $B34C UMULT Compute the Size of a Multidimensional Array This routine calculates the size of a multidimensional array by multiplying the dimensions. 45949 $B37D FRE Perform FRE The FRE function calls the garbage collection routine at 46374 ($B526) to get rid of unused string text, and calculates the difference between the bottom of string text and the top of array storage. It then drops through to the follow routine, which assumes that the free memory value is a 16-bit signed integer, and converts it to floating point accordingly. Of course, while the free memory space on the PET might have always been 32767 or less (the maximum value of a signed integer), sich is definitely not the case on the 64. Because conversion is from a signed integer, any memory value over 32767 will be regarded as negative (the high bit is treated as a sign bit). Therefore, for these higher values you must add twice the bit value of the high bit (65536) in order to come up with the correct value. The expression FRE(0)-6556*(FRE(0)<0) will always return the correct amount of free memory. 45969 $B391 GIVAYF Convert 16-Bit Signed Integer to Floating Point This routine treats the value in the Accumulator as the high byte of a 16-bit signed integer, and the value in the .Y register as the low byte, and converts the signed integer into a floating point number in the Floating Point Accumulator. The address of this routine is pointed to by the RAM vector at 5-6, and the routine can be used to return an argument from the USR call in the Floating Point Accumulator. 45982 $B39E POS Perform POS The POS command calls the Kernal PLOT routine (58634, $E50A) to get the position of the cursor on the logical line. What it really does is an equivalent of PEEK(211). Remember, since we are dealing with a logical line, this number can be over 39. The statement "THIS SENTENCE IS LONGER THAN ONE PHYSICAL LINE";POS(X) will return a value of 48 for the POS(X). 45990 $B3A6 ERRDIR Check If the Program is Running in Direct Mode, and If So Issue an Error This routine is called by statements that prohibit execution in direct mode. It checks a flag that is set when a line without a linenumber is entered, and causes an ILLEGAL DIRECT error if the flag is set. 46003 $B3B3 DEF Perform DEF DEF performs some syntax checking, and pushes five bytes onto the stack: the first byte of the function statement, a two-byte pointer to the dependent variable (the X in FN(X)), and the address of the first character of the definition itself, where it resides in the program text. The DEF statement must fit on one line, but functions can be extended by nesting them (having one function call another). 46049 $B3E1 GETFNM Check DEF and FN Syntax This routine checks to make sure that FN follow SEG, and that the dependent variable has a valid floating point variable name. It calls the routine to find or create a variable to get the pointer to its address. 46068 $B3F4 FNDOER Perform FN The FN evaluation is done by evaluating the FN argument (for example, FN(A+B*C/D)) and then getting the rest of the expression from the text of the function definition statement. The function variable descriptor area is used as a work area, and the dependent variable is not disturbed (so that if the definition used FN(X), the value of X will not be changed by the function call). 46181 $B465 STRD Perform STR$ STR$ first checks to make sure that the parameter is a number, and then calls the routines that convert floating point to ASCII and crate the pointers to a string constant. 46215 $B487 STRLIT Scan and Set Up Pointers to a String in Memory This routine calculates the length of the string, and calls the routine that allocates space in memory. It then saves the string, or creates a pointer to its location in the BASIC text input buffer at 512 ($200). 46324 $B4F4 GETSPA Allocate Space in Memory for String The amount of space needed for a string is passed to this routine, and the routine checks if there is that amount of space available in free memory. If not, it does a garbage collection and tries again. 46374 $B526 GARBAG String Garbage Collection Whenever a string is changed in any way, the revised version of the text is added to the bottom of the string text area, leaving the old version higher up in memory, wasting space. In order to reclaim that space, the descriptor for every string whose text is in the string text area (rather than in the program text area) must be searched to find the valid text that is highest in memory. If that string is not as high as it could be, it is moved up to replace any string that is no longer valid. Then all of the string descriptors must be searched again to find the next highest string and move it up. This continues until every string that is un use has been covered. After all have been moved up, the pointer to the bottom of string text at 51-52 ($33-$34) is changed to show the new bottom location. If there are more than a few strings whose text is in the string text storage area, rather than in the body of the program, scanning every string as many times as there are strings can take an awful lot of time. The computer may seem as if it had died (the STOP key is not even checked during the procedure). The collection will take about as long whether there is any spare space or not; the full collection will be done even if it is done immediately after the last collection. Although the increased memory capacity of the 64 helps to forestall the need for garbage collection, a large program with many string arrays may still experience lengthy collection delays. 46525 $B5BD Check for Most Eligible String to Collect This part of the garbage collection routine checks to see if the current string is the highest in memory. 46598 $B606 Collect a String This part of the garbage collection routine moves the string to high memory and updates the descriptor to point to its new location. 46653 $B63D CAT Concatenate Two Strings This routine is used to add the text of one string onto the end of another (A$+B$). Error checking is done to see if the length of the combined string is within range, the allocation routine is called to allocate space, and the new string is built at the bottom of the string text area. 46714 $B67A MOVINS Move a String in Memory This is the routine which is used to move a string to the bottom of the string text area for the above routine. It is generally used as a utility routine to move strings. 46755 $B6A3 FRESTR Discard a Temporary String This routine calls the following routine which clears an entry from the temporary descriptor stack. If the descriptor was on the stack, it exits after setting pointers to the string and its length. If it wasn't on the temporary stack and is at the bottom of string text storage, the pointer to the bottom is moved up to deallocate the string. 46811 $B6DB FRETMS Remove an Entry from the String Descriptor Stack If the descriptor of a currently valid string is the same as one of the entries on the temporary string descriptor stack, the stack entry is removed. 46828 $B6EC CHRD Perform CHR$ The CHR$ routine creates a descriptor on the temporary string stack for the one-byte string whose value is specified in the command, and sets a pointer to that string. 46848 $B700 LEFTD Perform LEFT$ LEFT$ creates a temporary string descriptor for a new string which contains the number of characters from the left side of the string that is specified in the command. 46892 $B72C RIGHTD Perform RIGHT$ RIGHT$ manipulates its parameters so that the tail end of LEFT$ can be used to create a temporary string descriptor for a new string. This new string contains the number of characters from the right side of the string that is specified in the command. 46903 $B737 MIDD Perform MID$ MID$ manipulates its parameters so that the tail end of LEFT$ can be used to create a temporary string descriptor for a new string. This new string contains the number of characters from the position in the middle of the string that is specified in the command. 46945 $B761 PREAM Pull String Function Parameters from Stack for LEFT$, RIGHT$, and MID$ This routine is used to obtain the first two parameters for all three of these commands. 46972 $B77C LEN Perform LEN The LEN function is performed by obtaining the string length from the descriptor and converting it to a floating point number. 46987 $B78B ASC Perform ASC This routine gets the first character of the string in the .Y register (if it's not a null string). Then it calls the part of POS that converts a one- byte integer in .Y to a floating point number. 47003 $B79B GETBYTC Input a Parameter Whose Value Is Between 0 and 255 This routine reads numeric ASCII program text, converts it to an integer, checks that it is in the range 0-255, and stores it in the .X register. This routine can be useful for reading parameters from a USR statement or new commands. 47021 $B7AD VAL Perform VAL The VAL routine obtains the string pointer, and reads the string one character at a time until an invalid character is found (ASCII numbers, sign character, a single decimal point, exponent, and spaces are all valid). Then the string is changed to floating point. If no valid characters are found, a 0 is returned. 47083 $B7EB GETNUM Get a 16-Bit Address Parameter and an 8-Bit Parameter (for POKE and WAIT) This routine gets the next numeric parameter from the current place in program text. The routine evaluates it, checks that it is a positive integer within the range 0-65535, and changes it from floating point to a two-byte integer in 20-21 ($14-$15). It checks for and skips a comma, then gets a one-byte integer parameter in the .X register. The routine is used to get the parameters for POKE an WAIT. 47095 $B7F7 GETADR Convert a Floating Point Number to an Unsigned Two-Byte Integer This routine checks the number in the Floating Point Accumulator to make sure that it is a positive number less than 65536, and then calls the subroutine which conerts floatin point to integer. It is used to get address parameters, for commands such as PEEK. 47117 $B80D PEEK Perform PEEK PEEK reads the address parameter and converts it to a pointer. Then it gets the byte pointed to into the .Y register, and calls the part of POS that converts a single integer in .Y to a floating point number. 47140 $B824 POKE Perform POKE POKE gets a pointer to the address parameter, and stores the next parameter there. 47149 $B82D FUWAIT Perform WAIT WAIT gets an address parameter and an integer parameter to use as a mask. WAIT then looks for an optional parameter to use as a pattern for the exclusive OR. Then, the address location is read, its value is exclusive ORed with the optional pattern value (or 0 if there is none). This value is ANDed with the mask value. The command loops continuously until the result is not- zero. The purpose of this command is to allow the program to watch a location which can be changed by the system or by outside hardware (such as the software clock or keycode value locations). The AND function lets you check if a bit changes from 0 to 1, while the EOR function allows you to check if a bit changes from 1 to 0. For more information, see the article "All About the Wait Instruction," by Louis Sander and Doug Ferguson, in COMPUTE!'s First Book of Commodore 64. 47177 $B849 FADDH Add .5 to Contents of Floating Point Accumulator #1 47184 $B850 FSUB Subtract FAC1 from a Number in Memory This routine is used to subtract the Floating Point Accumulator from a number in memory. It moves the number in memory into FAC2, and falls through to the next routine. 47187 $B853 FSUBT BASIC's Subtraction Operation This routine subtracts the contents of FAC2 from FAC1 by complementing its sign and adding. 47207 $B867 FADD Add FAC1 to a Number in Memory This routine is used to add the contents of the Floating Point Accumulator (FAC1) to a number in memory, by moving that number into FAC2, and falling through to the next routine. 47210 $B86A FADDT Perform BASIC's Addition Operation This routine adds the contents of FAC1 and FAC2 and stores the results in FAC1. 47271 $B8A7 FADD4 Make the Result Negative If a Borrow Was Done 47358 $B8FE NORMAL Normalize Floating Point Accumulator #1 47431 $B947 NEGFAC Replace FAC1 with Its 2's Complement 47486 $B97E OVERR Print Overflow Error Message 47491 $B983 MULSHF SHIFT Routine 47548 $B9BC FONE Floating Point Constant with a Value of 1 This five-byte floating point representation of the number 1 is stored here for use by the floating point routines. It is also used as the default STEP value for the FOR statement. 47553 $B9C1 LOGCN2 Table of Floating Point Constants for the LOG Function This table of eight numeric constants in five-byte floating point representation is used by the LOG function. 47594 $B9EA LOG Perform LOG to Base E The LOG to the base e of the number in FAC1 is performed here, and the result left in FAC1. 47656 $BA28 FMULT Multiply FAC1 with FAC2 This routine multiplies the contents of FAC1 by the contents of FAC2 and stores the result in FAC1 47705 $BA59 MLTPLY Multiply a Byte Subroutine This subroutine is used to repetitively add a mantissa byte of FAC2 to FAC1 the number of times specified in the .A register. 47756 $BA8C CONUPK Move a Floating Point Number from Memory into FAC2 This subroutine loads FAC2 from the four-byte number (three mantissa and one sign) pointed to by the .A and .Y registers. 47799 $BAB7 MULDIV Add Exponent of FAC1 to Exponent of FAC2 47828 $BAD4 MLDVEX Handle Underflow or Overflow 47842 $BAE2 MUL10 Multiply FAC1 by 10 This subroutine is called to help convert a floating point number to a series of ASCII numerals. 47865 $BAF9 TENC The Constant 10 in Five-Byte Floating Format 47870 $BAFE DIV10 Divide FAC1 by 10 47887 $BB0F FDIV Divide a Number in Memory by FAC1 This number in memory is stored to FAC2, and this routine falls through to the next. 47890 $BB12 FDIVT Divide FAC2 by FAC1 This routine is used to divide the contents of FAC2 by the contents of FAC1, with the result being stored in FAC1. A check for division by 0 is made before dividing. 48034 $BBA2 MOVFM Move a Floating Point Number from Memory to FAC1 This routine loads FAC1 with the five-byte floating point number pointed to by the address stored in the Accumulator (low byte) and the .Y register (high byte). 48071 $BBC7 MOV2F Move a Floating Point Number from FAC1 to Memory This routine is used to move a number from the Floating Point Accumulator (FAC1) to memory at either 92-96 ($5C-$60) or 87-91 ($57-$5B), depending on the entry point to the routine. 48124 $BBFC MOVFA Move a Floating Point Number from FAC2 to FAC1 48140 $BC0C MOVAF Round and Move a Floating Point Number from FAC1 to FAC2 48143 $BC0F MOVEF Copy FAC1 to FAC2 Without Rounding 48155 $BC1B ROUND Round Accumulator #1 by Adjusting the Rounding Byte If doubling the rounding byte at location 112 ($70) makes it greater than 128, the value of FAC1 is increased by 1. 48171 $BC2B SIGN Put the Sign of Accumulator #1 into .A Register On exit from this routine the Accumulator will hold a 0 if FAC1 is 0, a 1 if it is positive, and a value of 255 ($FF) if it is negative. 48185 $BC39 SGN Perform SGN The SGN routine calls the above routine to put the sign of FAC1 into .A, and then converts that value into a floating point number in FAC1. 48216 $BC58 ABS Perform ABS The FAC1 sign byte at 102 ($66) is shifted right by this command, so that the top bit is a 0 (positive). 48219 $BC5B FCOMP Compare FAC1 to Memory On entry to this routine, .A and .Y point to a five-byte floating point number to be compared to FAC1. After the comparison, .A holds 0 if the two are equal, a 1 if the value of FAC1 is greater than that in the memory location, and 255 ($FF) if the value of FAC1 is less than that in the memory location. 48283 $BC9B QINT Convert FAC1 into Integer Within FAC1 This routine converts the value in FAC1 into a four-byte signed integer in 98- 101 ($62-$65), with the most significant byte first. 48332 $BCCC INT Perform INT This routine removes the fractional part of a floating point number by calling the routine above to change it to an integer, and then changing the integer back to floating point format. 48371 $BCF3 FIN Convert an ASCII String to a Floating Point Number FAC1 This routine is called by VAL to evaluate and convert an ASCII string to a floating point number. 48510 $BD7E FINLOG Add Signed Integer to FAC1 This routine is used to add an ASCII digit that has been converted to a signed integer to FAC1. 48563 $BDB3 NO999 This table of three floating point constants holds the values 99,999,999.5, 999,999,999.5 and 1,000,000,000. These values are used in converting strings to floating point numbers. 48576 $BDC0 INPRT Print IN Followed by a Line Number 48589 $BDCD LINPRT Output a Number in ASCII Decimal Digits This routine is used to output the line number for the routine above. It converts thenumber whose high byte is in .A and whose low byte is in .X to a floating point number. It also calls the routine below, which converts the floating point number to an ASCII string. 48605 $BDDD FOUT Convert Contents of FAC1 to ASCII String This routine converts a floating point number to a string of ASCII digits, and sets a pointer to the string in .A and .Y. 48913 $BF11 FHALF The Constant Value 1/2 in Five-Byte Floating Point Notation This constant is used for rounding and SQR. 48924 $BF1C FOUTBL Powers of Minus Ten Constants Table This table contains the powers of -10 expressed as four-byte floating point numbers (that is, -1; +10; -100; +1000; -10,000; +100,000; -1,000,000; +10,000,000; and -100,000,000). 48954 $BF3A FDCEND Table of Constants for TI$ Conversion This table contains the floating point representation of the powers of -60 multiplied by 1 or 10. These constants are used for converting TI$ to ASCII. 48978 $BF52 Unused area This unused area is filled with byts of 170 ($AA). 49009 $BF71 SQR Perform SQR This routine moves the contents of FAC1 to FAC2, moves the constant 0.5 to FAC1, and falls through to the exponentation routine. 49019 $BF7B FPWRT Performs Exponentation (Power Calculation Called for by UPARROW) This routine raises the value in FAC2 to the power in FAC1 and leaves the result in FAC1. 49076 $BFB4 NEGOP Perform NOT and > This negates the Floating Point Accumulator by exclusive ORing the sign byte with a constant of 255 ($FF). Zero is left unchanged. The results of this command follow rom the formula NOT X=-(X+1). Therefore, if you NOT a tatement that is true (-1), you get 0 (false). 49087 $BFBF EXPCON Table of Constants for EXP and LOG in Five-Byte Floating Point Format These tables are used to calculate 2 to the N power. 49133 $BFED EXP Perform EXP This routine calculates the natural logarithm e (2.718281828...) raised to the power in FAC1. The result is left in FAC1. This routine is split between the BASIC ROM wich ends at 49151 ($BFFF) and the Kernal ROM which begins at 57344 ($E000). Therefore, a JMP $E000 instruction is tacked on to the end, which makes the BASIC routines in the 64 Kernal ROM three bytes higher in memory than the corresponding VIC-20 routines. 49152-53247 $C000-$CFFF 4K Free RAM Locations 49152 to 53247 ($C000 to $CFFF) are free RAM. Since this area is not contiguous with the BASIC program text RAM area, it is not available for BASIC program or variable storage (it is not counted in the FRE(0) total). This area is fully available for any other use, however, sudh as storing machine language subroutines for use with BASIC, alternate I/O drivers for parallel or IEEE devices, character graphics or sprite data, etc. This large free area is such a tempting spot for system additions that many such applications may be competing for the same RAM space. For example, the Universal Wedge DOS Support program that adds easy access to the disk communications channel is usually loaded at 52224 ($CC00). Programs that use that part of RAM will therefore overwrite the DOS support program, with the result that they may not run correctly, or even at all. Likewise, Simon's BASIC, the extended language which Commodore has released on cartridge, uses several locations in this range. Be aware of this potential problem when you buy hardware additions that use this spot to hook into the system. :::::::::::::::::::: :: Chapter 6 :: :: :: ::VIC-II, SID, I/O:: :: Devices, Color :: :: RAM, and :: :: Character ROM :: :::::::::::::::::::: 53248-57343 $D000-$DFFF This 4K block of memory is used for several key functions. Normally, the 6510 microprocessor addresses the two Complex Interface Adapter (CIA) Input/Output chips here, along with the VIC-II video controller chip, the Sound Interface Device (SID) music synthesizer, and the Color RAM. Alternatively, the 6510 can address the character ROM here (though normally only the VIC-II chip has access to it). Finally, there is also 4K of RAM here, although to use it may require banking it in only when necessary, as the I/O devices are needed for such niceties as reading he keyboard, and updating the screen display. It will appear from the map of the I/O devices below that many of the locations are not accounted for. That is beause these devices tie up more addressing space than they actually use. Each of them uses only a few addresses, mostly on the bit level. The missing addresses either consist of images of the hardware registers, or cannot be addressed in this configuration. In addition, some address space is left open for the use of future hardware devices which might be plugged into the expansion port, like the CP/M card. As mentioned above, memory usage by these I/O devices is to intensive that to work with them often requires that you turn individual bits on and off. Here is a quick reminder of how to manipulate bits. The bit values for each bit are: Bit 0 = 1 Bit 1 = 2 Bit 2 = 4 Bit 3 = 8 Bit 4 = 16 Bit 5 = 32 Bit 6 = 64 Bit 7 = 128 To set a bit to 1 from BASIC, POKE address, PEEK(address) OR Bitvalue. To reset a bit to 0 from BASIC, POKE address, PEEK(address) AND 255-Bitvalue. 53248-53294 $D000-$D02E VIC-II Chip Registers The Video Interface Controller (VIC-II chip) is a specially designed processor that is in charge of the 64's video display. It is this chip which makes possible the 64's wide range of graphics capabilities. The VIC-II chip's ability to address memory is independent of the 6510 microprocessor. It can address only 16K at a time, and any of the four blocks of 16K can be chosen for video memory. The system default is for it to use the first 16K. All of the video display memory, character dot data, and sprite shapes must be stored within the chosen 16K block. Locations 53248-53294 ($D000-$D02E) are registers which allow the user to communicate with the VIC-II chip. Although for the most part they can be written to and read like ordinary memory locations, their contents directly control the video display. Since many of these locations work in close conjunction with others, a general overview of some of the different graphics systems on the 64 is in order. The most familiar type of graphics display is the ordinary text that appears when you turn the machine on. The area of RAM which is displayed on the screen is determined by the Video Matrix Base Address Nybble of the VIC-II Memory Control Register (53272, $D018). The address of the dot-data which is used to assign a shape to each text character based on an 8 by 8 matrix of lit or unlit dots is determined by the other half of the Memory Control Register at 53272 ($D018). More information on how the data is used to represent the character shapes may be found at the alternate entry for 49152 ($C000), the Character Generator ROM. Text character graphics may employ one of the two sets of text and graphics characters in the Character Generator ROM, or the user may substitute a completely different set of graphics or text characters in RAM. Normally, the text graphics screen uses a background color which is common to all text characters, and that value is stored in Background Color Register 0 (53281, $D021). The color of the frame around the screen is determined by the Border Color Register at 53280 ($D020). The color of each character is determined by one nybble of the Color RAM which starts at 55296 ($D800). There are, however, two variations which alter this scheme somewhat. The first is called multicolor text mode, and is set by Bit 4 of 53270 ($D016). Instead of each bit selecting either the foreground or the background color for each dot in the character, bit-pairs are used to select one of four colors for each double-width dot. This results in the horizontal resolution being cut to four dots across per character, but allows two extra colors to be introduced from Background Color Registers 1 and 2 (53282-53283, $D022-$D023). The other text mode is called Extended Background Color Mode. In this mode, the foreground color is always selected by the Color RAM. The background color depends on the actual screen code of the character. In this mode, only the first 64 character shapes are available, but each can have one of four different background colors. The background color for each character is determined by its screen code as follows: 1. If the screen code is from 0-63 (this includes the normal alphanumerics), the value in Background Color Register 0 (53281, $D021) will determine the background color, as is usual. 2. Characters with codes 64-255 will have the same shape as the corresponding character in the group with codes 0-63. 3. For characters with codes 64-127 (SHIFTed characters), the background colors are deterined by the value in Background Color Register 1 (53282, $D022). 4. The value in Background Color Register 2 (53283, $D023) is used for characters with codes 128-191 (reversed alphanumerics). 5. For characters with codes 192-255, the value in Background Color Register 3 (53284, $D024) is used to determine the background color. In place of the normal text mode, a bitmap graphics mode is also abailable by setting Bit 5 of location 53265 ($D011). In this mode, each bit of data determines whether one dot on the screen will be set to either the background color or foreground color. Within an 8 by 8 dot area, the foreground and background colors may be individually selected. The bitmap area is 320 dots wide and 200 dots high. The area which contains the graphics data, the bitmap, is determined by the Character Dot Data Base Address in the lower nybble of the VIC-II Memory Control Register (53272, $D018). The Video Matrix Base Address in the upper nybble, which normally determines which area of memory will be displayed, instead determines where the color memory for each 8 by 8 ground of dots will be located. The Color RAM is not used for high-resolution bitmap graphics. But multicolor mode is also available for bitmap graphics, and it uses the Color RAM to determine the foreground color of each dot. As with multicolor text mode, the horizontal resolution is but in half (to 160 dots across), so that in addition to the foreground and background colors, each dot can be one of two other colors as well. This mode gets the value for the two extra colors from the two nybbles of each byte of bitmap color memory, the location of which is determined by the Video Matrix Base Address. Multicolor text mode offers four colors, three of which will be common to all characters, and one of which can be selected individually. Multicolor bitmap mode offers a choice of four colors, three of which can be individually selected within an 8 by 8 dot area. The 64 also contains an entirely separate graphics system, whose character shapes, colors, and positions are derived and displayed without any reference to the Video Matrix and Character Dot-Data addresses. Best of all, these characters may be moved quickly and easily to any position on the screen, greatly facilitating games and animated graphics of all types. This system is known as sprite graphics. Sprite graphics takes its name from the graphics characters it displays, each of which is called a sprite. There are eight sprites, known as Sprites 0-7. Each sprite character is 24 dots wide by 21 dots high. This is about eight times as large as a regular text character, which is only 8 dots wide by 8 dots high. A sprite takes its shape from 63 bytes of data in one of the 256 data blocks, each 64 bytes long, that can fit into the 16K space which the VIC-II chip can address. The block currently assigned to any given sprite is determined by the Sprite Data Pointers, which are located at the last eight bytes of the screen memory area (the default locations are 2040-2047, $7F8-$7FF). The first Sprite Data Pointer determines the data block used for the shape of Sprite 0, the second for the shape of Sprite 1, etc. The number in the pointer times 64 equals the address of the first byte of the data block within the VIC-II addressing range. For example, using the default values for VIC-II addressing area and screen memory, a value of 11 in location 2040 ($7F8) would mean that the shape of Sprite0 is determined by the data in the 63-byte block starting at location 704 (11*64). It should be noted that it is possible for more than one sprite to take its shape data from the same block, so that only 64 bytes of data are required to create eight sprites, each having the same shape. The dot patterns of each sprite correspond to the bit patterns of the sprite shape data. Each byte of shape data in memory consists of a number from 0 to 255. This number can be represented by eight binary digits of 0 or 1. Each binary digit has a bit value that is two times greater than the last. If the digit in the zero bit place is a 1, it has a value of 1 (we count bit places from 0 to 7). A 1 in the first bit place has a value of 2, the second bit has a value of 4, the third has a value of 8, the fourth has a vlue of 16, the fifth a value of 32, the sixth a value of 64, and the seventh a value of 128. By making all of the possible combinations of 0's and 1's in all eight bit places, and adding the bit values of every bit place that contains a 1, we can represent every number from 0 to 255 as a series of 1's and 0's. If you think of every 0 as a dot having the same color as the background, and every 1 as a dot which is the color of the sprite, you can see how a series of bytes could be used to represent the sprite shape. Since each line of the sprite is 24 dots wide, it takes 3 bytes of memory (24 bits) per line to portray its shape. Let's take a look at a couple of sample sprite lines. 00000000 01111110 00000000 = 0, 126, 0 As you can see, the first and last bytes are all 0's, so nothing will be displayed there. The middle byte has six 1's, so it will be displayed as a line six dots long. By adding the values of these dix bits (64+32+16+8+4+2), we get a byte value of 126. Let's try another line. 00011111 11111111 11111000 = 21, 255, 248 The first byte has five bits set to 1, having values of 16, 8, 4, 2, and 1, for a total of 31. The second byte has all bits set to 1, so it has the maximum value of 255. The third byte also has five bits set to 1, having values of 128, 64, 32, 16, and 8, for a total of 248. The result is that this line of sprite data will display a line that is 18 dots long. We can put these two kinds of lines together to show how a large cross might be drawn using bytes of sprite data. 000000000000000000000000 = 0, 0, 0 000000000000000000000000 = 0, 0, 0 000000000111111000000000 = 0, 126, 0 000000000111111000000000 = 0, 126, 0 000000000111111000000000 = 0, 126, 0 000000000111111000000000 = 0, 126, 0 000000000111111000000000 = 0, 126, 0 000000000111111000000000 = 0, 126, 0 000000000111111000000000 = 0, 126, 0 000111111111111111111000 = 21, 255, 248 000111111111111111111000 = 21, 255, 248 000111111111111111111000 = 21, 255, 248 000000000111111000000000 = 0, 126, 0 000000000111111000000000 = 0, 126, 0 000000000111111000000000 = 0, 126, 0 000000000111111000000000 = 0, 126, 0 000000000111111000000000 = 0, 126, 0 000000000111111000000000 = 0, 126, 0 000000000111111000000000 = 0, 126, 0 000000000000000000000000 = 0, 0, 0 000000000000000000000000 = 0,0,0 The 63 numbers, displayed three per line opposite the bit patters they represent, are the values that would have to be put in the sprite shape data area in order to display this cross using sprite graphics. Even after the sprite shape data has been placed in memory, and the Sprite Data Pointer has been set to display that block of data bytes as the sprite shape, there are still several steps that must be taken in order to display the sprite on the screen. The proper bit of the Sprite Display Enable Register at 53269 ($D015) must be set to 1 in order to turn on the sprite display. A horizontal and vertical screen position must be selected for the sprite by means of the horizontal and vertical position registers (53248-53264, $D000-$D010). Finally, the color value of the sprite should be placed in the appropriate Sprite Color Register (53287-53294, $D027-$D02E). Once you have the sprite on the screen, animation is fairly simple to achieve. Moving the sprite is as easy as changing the values in the sprite position registers. Changing the sprite shape can be accomplished by merely changing the Sprite Data Pointer to point to another block of shape data in memory. There are also some optional sprite graphics features available which enhance its flexibility. Sprite expand registers allow you to make each sprite twice as wide as normal, twice as tall, or both. Collision detection registers let you know when a sprite shape overlaps a regular text character or bitmap dot, or if two sprites are touching. If a sprite is positioned in the same place on the screen as a text character or bitmap dot, a Priority Register allows you to choose whether the sprite or the normal graphics will by displayed. This enables three- dimensional effects by letting you choose whether the sprite goes in front of or behind other objects on the screen. Finally, any sprite may be selected for multicolor display, using the register at location 53276 ($D01C). In this mode, as in multicolor text and bitmap modes, pairs of bits are used to determine the color of each double- width dot. The possible color values which may be selected are those of Background Color Register 0, the Sprite Color Register, or the two color values in the Sprite Multicolor Registers at 53285-53286 ($D025-$D026). Location Range: 53248-53264 ($D000-$D010) Sprite Horizontal and Vertical Position Registers These locations determine the horizontal and vertical position at which each sprite will be displayed on the screen. Each sprite has its own horizontal and vertical position register. In addition, all of the sprites share a common register which is used to extend the range of horizontal positions. Vertical positions for each sprite range from 0 to 255, and these indicate the vertical position of the top line of the sprite's 21-line length. Since there are only 200 visible scan lines in the screen display, some of these vertical positions will result in the sprite being partially or wholly offscreen. The visible viewing area starts at line 50 and extends to line 249. Therefore, any sprite whose vertical psition is 29 ($1D) or less will be completely above the visible picture. At vertical position 30 ($1E), the bottom line of the sprite display becomes visible at the top of the screen. At position 230 ($E6), the bottom line of the sprite is lost from view off the bottom of the screen, and at vertical position 250 ($FA), the entire sprite disappears from view off the bottom edge of the screen. Horizontal positioning is somewhat trickier, because the visible display area is 320 dots wide, and one eight-bit register can hold only 256 position values. Therefore, an additional register is needed to hold the ninth bit of each sprite's horizontal position. Each sprite is assigned a single bit in the Most Significant Bit of Horizontal Position register (MSB register) at 53264 ($D010). If that bit is set to 1, the value 256 is added to the horizontal position. This extends the range of possible horizontal positions to 511. In order to set a sprite's horizontal position, you must make sure that both the values in the horizontal position register and the MSB Register are correct. For example, if you wish to set the horizontal position of Sprite 5 to a value of 30, you must place a value of 30 in the Sprite 5 Horizontal Position Register (POKE 53258,30 will do it from BASIC), and you must also clear Bit 5 of the MSB Register (POKE 53264,PEEK(53264)AND(255-16)). If you forget the MSB register, and Bit 5 is set to 1, you will end up with position 286 instead of 30. The horizontal position value indicates the position of the leftmost dot of the sprite's 24-dot width. The visible display is restricted to the 320 dot positions between positions 24 and 344. At position 0 the whole sprite is past the left edge of the visible screen. At position 1 the righmost dot enters the display area, and at position 24 ($18) the entire sprite is displayed on screen. At position 321 ($141) the rightmost dot goes past the right edge of the visible display area, and a position 355 ($158) the whole sprite has moved out of sight, off the right edge of the screen. These registers are all intialized to 0 at power-up. 53248 $D000 SP0X Sprite 0 Horizontal Position 53249 $D001 SP0Y Sprite 0 Vertical Position 53250 $D002 SP1X Sprite 1 Horizontal Position 53251 $D003 SP1Y Sprite 1 Vertical Position 53252 $D004 SP2X Sprite 2 Horizontal Position 53253 $D005 SP2Y Sprite 2 Vertical Position 53254 $D006 SP3X Sprite 3 Horizontal Position 53255 $D007 SP3Y Sprite 3 Vertical Position 53256 $D008 SP4X Sprite 4 Horizontal Position 53257 $D009 SP4Y Sprite 4 Vertical Position 53258 $D00A SP5X Sprite 5 Horizontal Position 53259 $D00B SP5Y Sprite 5 Vertical Position 53260 $D00C SP6X Sprite 6 Horizontal Position 53261 $D00D SP6Y Sprite 6 Vertical Position 53262 $D00E SP7X Sprite 7 Horizontal Position 53263 $D00F SP7Y Sprite 7 Vertical Position 53264 $D010 MSIGX Most Significant Bits of Sprites 0-7 Horizontal Position Bit 0: Most significant bit of Sprite 0 horizontal position Bit 1: Most significant bit of Sprite 1 horizontal position Bit 2: Most significant bit of Sprite 2 horizontal position Bit 3: Most significant bit of Sprite 3 horizontal position Bit 4: Most significant bit of Sprite 4 horizontal position Bit 5: Most significant bit of Sprite 5 horizontal position Bit 6: Most significant bit of Sprite 6 horizontal position Bit 7: Most significant bit of Sprite 7 horizontal position Setting one of these bites to 1 adds 256 to the horizontal position of the corresponding sprite. Resetting one of these bits to 0 restricts the horizontal position of the corresponding sprite to a value of 255 or less 53265 $D011 SCROLY Vertical Fine Scrolling and Control Register Bits 0-2: Fine scroll display vertically by X scan lines (0-7) Bit 3: Select a 24-row or 25-row text display (1=25 rows, 0=24 rows) Bit 4: Blank the entire screen to the same color as the background (0=blank) Bit 5: Enable bitmap graphics mode (1=enable) Bit 6: Enable extended color text mode (1=enable) Bit 7: High bit (Bit 8) of raster compare register at 53266 ($D012) This is one of the two important multifunction control registers on the VIC-II chip. Its defaule value is 155, which sets the high bit of the raster compare to 1, selects a 25-row display, disables the blanking feature, and uses a vertical scrolling offset of three scan lines. Bits 0-2. These bits control vertical fine scrolling of the screen display. This feature allows you to move the entire text display smoothly up and down, enabling the display area to act as a window, scrolling over a larger text or character graphics display. Since each row of text is eight scan lines high, if you simply move each line of text up one row, the characters travel an appreciable distance each time they move, which gives the motion a jerky quality. This is called coarse scrolling, and you can see an example of it when LISTing a program that is too long to fit on the screen all at one time. By placing a number from 1 to 7 into these three bits, you can move the whole screen display down by from 1 to 7 dot spaces. Stepping through the values 1 to 7 allows you to smoothly make the transition from having a character appear in one row on the screen to having it appear in the next row. To demonstrate this, type in the following sample program, LIST it, and RUN. 10 FOR I= 1 TO 50:FOR J=0 TO 7 20 POKE 53265, (PEEK(53265)AND248) OR J:NEXTJ,I 30 FOR I= 1 TO 50:FOR J=7 TO 0 STEP-1 40 POKE 53265, (PEEK(53265)AND248) OR J:NEXTJ,I As you can see, after the display has moved seven dot positions up or down, it starts over at its original position. In order to continue the scroll, you must do a coarse scroll every time the value of the scroll bits goes from 7 to 0, or from 0 to 7. This is accomplished by moving the display data for each line by 40 bytes in either direction, overwriting the data for the last line, and introducing a line of data at the opposite end of screen memory to replace it. Obviously, ony a machine language program can move all of these lines quickly enough to maintain the effect of smooth motion. The following BASIC program, however, will give you an iea of what vertical fine scrolling is like: 10 POKE 53281,0:PRINTCHR$(5);CHR$(147) 20 FORI=1 TO 27: 30 PRINTTAB(15)CHR$(145)" ":POKE 53265,PEEK(53265)AND248 40 WAIT53265,128:PRINTTAB(15)"I'M FALLING" 50 FOR J=1 TO 7 60 POKE53265,(PEEK(53265)AND248)+J 70 FORK=1TO50 80 NEXT K,J,I:RUN Bit 3. This bit register allows you to select either the normal 25-line text display (by setting the bit to 1), or a shortened 24-row display (by resetting that bit to 0). This shortened display is created by extending the border to overlap the top or bottom row. The characters in these rows are still there; they are just covered up. The shortened display is designed to aid vertical fine scrolling. It covers up the line into which new screen data is introduced, so that the viewer does not see the new data being moved into place. However, unlink the register at 53270 ($D016) which shortens the screen by one character space on either side to aid horizontal scrolling in either direction, this register can blank only one vertical line at a time. In order to compensate, it blanks the top line when the three scroll bits in this register are set to 0, and shifts the blanking one scan line at a time as the value of thee bits increases. Thus the bottom line is totally blanked when these bits are set to 7. Bit 4. Bit 4 of this register controls the screen blanking feature. When this bit is set to 0, no data can be displayed on the screen. Instead, the whole screen will be filled with the color of the frame (which is controlled by th eBorder Color Register at 53280 ($D020)). Screen blanking is useful because of the way in which the VIC-II chip interacts with the 6510 microprocessor. Since the VIC-II and the 6510 both have to address the same memory, they must share the system data bus. Sharing the data bus means that they must take turns whenever they want to address memory. The VIC-II chip was designed so that it fetches most of the data it needs during the part of the cycle in which the 6510 is not using the data bus. But certain operations, such as reading the 40 screen codes needed for each line of text from video mmeory, or fetching sprite data, require that the VIC-II chip get data at a faster rate than is possible just by using the off half of the 6510 cycle. Thus, the VIC-II chip must delay the 6510 for a short amount of time while it is using the data bus to gather display information for text or bitmap graphics, and must delay it a little more if sprites are also enabled. When you set the screen blanking bit to 0, these delays are eliminated, and the 6510 processor is allowed to run at its full speed. This speeds up any processing task a little. To demonstrate this, run the following short program. As you will see, leaving the screen on makes the processor run about 7 percent slower than when you turn it off. If you perform the same timing test on the VIC-20, you will find that it runs at the same speed with its screen on as the 64 does with its screen off. And the same test on a PET will run substantially slower. 10 PRINT CHR$(147);TAB(13);"TIMING TEST":PRINT:TI$="000000":GOTO 30 20 FOR I=1 TO 10000:NEXT I:RETURN 30 GOSUB 20:DISPLAY=TI 40 POKE 53265,11:TI$="000000" 50 GOSUB 20:NOSCREEN=TI:POKE 53265,27 60 PRINT "THE LOOP TOOK";DISPLAY;" JIFFIES" 70 PRINT "WITH NO SCREEN BLANKING":PRINT 80 PRINT "THE LOOP TOOK";NOSCREEN;" JIFFIES" 90 PRINT "WITH SCREEN BLANKING":PRINT 100 PRINT "SCREEN BLANKING MAKE THE PROCESSOR" 110 PRINT "GO";DISPLAY/NOSCREEN*100-100;"PERCENT FASTER" The above explanation accounts for the screen being turned off during tape read and write operations. The timing of these operations is rather critical, and would be affected by even the relatively small delay caused by the video chip. It also explains why the 64 has difficulty loading programs from an unmodified 1540 Disk Drive, since the 1540 was set up to transfer data from the VIC-20, which does not have to contend with these slight delays. If you turn off the 64 display with a POKE 53265,PEEEK(53265) AND 239, you will be able to load programs correctly from an old 1540 drive. The new 1541 drive transfers data at a slightly slower rate in the default setting, and can be set from software to transfer it at the higher rate for the VIC-20. Bit 5. Setting Bit 5 of this register to 1 enables the bitmap graphics mode. In this mode, the screen area is broken down into 64,000 separate dots of light, 320 dots across by 200 dots high. Each dot corresponds to one bit of display memory. If the bit is set to 1, the dot will be displayed in the foreground color. If the bit is reset to 0, it will be displayed in the background color. This allows the display of high-resolution graphics images for games, charts, and graphs, etc. Bitmapping is a common technique for implementing high-resolution graphics on a microcomputer. There are some features of the Commodore system which are unusual, however. Most systems display screen memory sequentially; that is, the first byte controls the display of the first eight dots in the upper-left corner of the screen, the second byte controls the eight dots to the right of that, etc. In the Commodore system, display memory is laid out more along the lines of how character graphics dot-data is arranged. The first byte controls the row of eight dots in the top-left corner of the screen, but the next byte controls the eight dots below that, and so on until the ninth byte. The ninth byte controls the eight dots directly to the right of those controlled by the first byte of display memory. It is exactly the same as if the screen were filled with 1000 programmable characters, with display memory taking the place of the character dot-data. The 64's bitmap graphics mode also resembles character graphics in that the foreground color of the dots is set by a color map (although it does not use the Color RAM for this purpose). Four bits of each byte of this color memory control the foreground color of one of these eight-byte groups of display memory (which form an 8 by 8 grid of 64 dots). Unlike character graphics, however, the other four bits control the background color that will be seen in the eight-byte display group where a bit has a value of 0. Setting up a bitmap graphics screen is somewhat more complicated than just setting this register bit to 1. You must first choose a location for the display memory area, and for the color memory area. The display memory area will be 8192 bytes long (8000 of which are actually used for the display) and can occupy only the first or the second half of the 16K space which the VIC-II chip can address. Each byte of bitmap graphics color memory uses four bits for the background color as well as four bits for the foreground color. Therefore, the Color RAM nybbles at 55296 ($D800), which are wired for four bits only, cannot be used. Another RAM location must therefore be found for color memory. This color memory area will take up 1K (1000 bytes of which are actually used to control the foreground and background colors of the dots), and must be in the opposite half of VIC-II memory as the display data. Since bitmap graphics require so much memory for the display, you may want to select a different 16K bank for VIC-II memory (see the discussion of things to consider in selecting a VIC-II memory bank at location 56576 ($DD00)). To keep things simple, however, let's assume that you have selected to use the default bank of VIC-II memory, which is the first 16K. You would have to select locations 8192-16383 ($2000-$3FFF) for screen memory, because the VIC-II chip sees an image of the character ROM in the first half of the 16K block (at locations 4096-8192 ($1000-$1FFF)). Color memory could be placed at the default location of text display memory, at 1024-2047 ($400-$7FF). Placement of bitmap display and color memory is controlled by the VIC Memory Control Register at 53272 ($D018). When in bitmap mode, the lower four bits of this register, which normally control the base address of character dot-data, now control the location of the 8K bitmap. Only Bit 3 is significant. If it is set to 1, the graphics display memory will be in the second 8K of VIC-II memory (in this case, starting at 8192 ($2000)). If that bit contains a 0, the first 8K will be used for the bitmap. The upper four bits of this register, which normally control the location of the Video Display Matrix, are used in bitmap mode to establish the location of the color map within the VIC-II address space. These four bits can hold a number from 0 to 15, which indicates on which 1K boundary the color map begins. For example, if color memory began at 1024 (1K), the value of these four bits would be 0001. Once the bitmap mode has been selected, and the screen and color memory areas set up, you must establish a method for turning each individual dot on and off. The conventional method for identifying each dot is to assign it to a horizontal (X) position coordinate and a vertical (Y) coordinate. Horizontal position values will range from 0 to 319, where dot 0 is at the extreme left-hand side of the screen, and dot 319 at the extreme right. Vertical positions will range from 0 to 199, where dot 0 is on the top line, and dot 199 is on the bottom line. Because of the unusual layout of bitmap screen data on the 64, it is fairly easy to transfer text characters to a bitmap screen, but it is somewhat awkward finding the bit which affects the screen dot having a given X-Y coordinate. First, you must find the byte BY in which the bit resides, and then you must POKE a vlue into that byte which turns the desired bit on or off. Given that the horizontal position of the dot is stored in the variable X, its vertical position is in the variable Y, and the base address of the bitmap area is in the variable BASE, you can find the desired byte with the formula: BY=BASE+40*(Y AND 256)+(Y AND 7)+(X AND 504) To turn on the desired dot, POKE BY, PEEK(BY) OR (2^(NOTX AND 7) To turn the dot off, POKE BY, PEEK(BY) AND (255-2^(NOTX AND 7)) The exponentation function takes a lot of time. To speed things up, an array can be created, each of whose elements corresponds to a power of two. FOR I=0 TO 7:BIT(I)=2^1:NEXT After this is done, the expression 2^(I) can be replaced by BI(I). The following sample program illustrates the bit-graphics concepts explained above, and serves as a summary of that information. 10 FOR I=0 TO 7:BI(I)=2^I:NEXT: REM SET UP ARRAY OF POWERS OF 2 (BIT VALUE) 20 BASE=2*4096:POKE53272,PEEK(53272)OR8:REM PUT BIT MAP AT 8192 30 POKE53265,PEEK(53265)OR32:REM ENTER BIT MAP MODE 40 A$="":FOR I=1 TO 37:A$=A$+"C":NEXT:PRINT CHR$(19); 50 FOR I=1 TO 27:PRINTA$;:NEXT:POKE2023,PEEK(2022): REM SET COLOR MAP 60 A$="":FOR I=1 TO 27:A$=A$+"@":NEXT:FOR I=32 TO 63 STEP 2 70 POKE648,I:PRINT CHR$(19);A$;A$;A$;A$:NEXT:POKE648,4:REM CLEAR HI-RES SCREEN 80 FORY=0TO199STEP.5:REM FROM THE TOP OF THE SCREEN TO THE BOTTOM 90 X=INT(160+40*SIN(Y/10)): REM SINE WAVE SHAPE 100 BY=BASE+40*(Y AND 248)+(Y AND 7)+(X AND 504): REM FIND HI-RES BYTE 110 POKEBY,PEEK(BY)OR(BI(NOT X AND 7)):NEXT Y:REM POKE IN BIT VALUE 120 GOTO 120: REM LET IT STAY ON SCREEN As you can see, using BASIC to draw in bit-graphics mode is somewhat slow and tedious. Machine language is much more suiable for bit-graphics plotting. For a program that lets you replace some BASIC ommands with high-res drawing commands, see the article "Hi-Res Graphics Made Simple," by Paul F. Schatz, in COMPUTE!'s First Book of Commodore 64 Sound and Graphics. There is a slightly lower resolution bitmap graphics mode available which offers up to four colors per 8 by 8 dot matrix. To enable this mode, you must set the multicolor bit (Bit 4 of 53270 ($D016)) while in bitmap graphics mode. For more information on this mode, see the entry for the multicolor enable bit. Bit 6. This bit of this register enables extended background color mode. This mode lets you select the background color of each text character, as well as its foreground color. It is able to increase the number of background colors displayed, by reducing the number of characters that can be shown on the screen. Normally, 256 character shapes can be displayed on the screen. You can use them either by using the PRINT statement or by POKEing a display code from 0 to 255 into screen memory. If the POKEing method is used, you must also POKE a color code from 0 to 15 into color memory (for example, if you POKE 1024,1, and POKE 55296,1, a white A appears in the top-left corner of the screen). The background color of the screen is determined by Background Color Register 0, and you can change this color by POKEing a new value to that register, which is located at 53281 ($D021). For example, POKE 53281,0 creates a black background. When extended background color mode is activated, however, only the first 64 shapes found in the table of the screen display codes can be displayed on the screen. This group includes the letters of the alphabet, numerals, and punctuation marks. If you try to print on the screen a character having a higher display code, the shape displayed will be from the first group of 64, but that character's background will no longer be determined by the register at 53281 ($D021). Instead, it will be determined by one of the other background color registers. When in extended background color mode, characters having display codes 64- 127 will take their background color from register 1, and location 53282 ($D022). These characters include various SHIFTed characters. Those with codes 128-191 will have their background colors determined by register 2, at 53283 ($D023). These include the reversed numbers, letters, and punctuation marks. Finally, characters with codes 192-255 will use register 4, at 53284 ($D024). These are the reversed graphics characters. Let's try an experiment to see just how this works. First, we will put the codes for four different letters in screen memory: FOR I=0 TO 3:POKE 1230+(I*8),I*64+I:POKE 55502+(I*8),1:NEXT Four white letters should appear on the screen, an A, a shifted A, a reversed A, and a reversed, shifted A, all on a blue background. Next, we will put colors in the other background color registers: POKE 53282,0:POKE53283,2:POKE53284,5 This sets the registers to black, red, and green, respectively. Finally, we will activate extended color mode by setting Bit 6 of the VIC-II register at location 53265 to a 1. The BASIC statement that turns this mode on is: POKE 53265,PEEK(53265) OR 64 Notice that two things happened. First, all of the letters took on the same shape, that of the letter A. Second, each took on the background color of a different color register. To get things back to normal, turn off extended color mode with this statement: POKE 53265,PEEK(53265) AND 191 Extended color mode can be a very useful enhancement for your text displays. It allows the creation of windows. These windows, because of their different background colors, make different bodies of text stand out as visually distinct from one another. For example, a text adventure program could have one window to display the player's current location, one to show an inventory of possessions, and one to accept commands for the next move. In this mode the background color of these windows can be changed instantly, just by POKEing a new value to the color register. This technique lends itself to some dramatic effects. A window can be flashed to draw attention to a particular message at certain times. And varying the foreground color can make either the window or the message vanish and reappear later. There are, however, a couple of problems involved in using these windows. The character shape that you want to use might not have a screen code of less than 64. In that case, the only solution is to define your own character set, with the shape you want in one of the first 64 characters. Another problem is that characters within a PRINT statement in your program listing are not always going to look the same on the screen. Having to figure out what letter to print to get the number 4 with a certain background color can be very inconvenient. The easiest solution to this problem is to have a subroutine to the translation for you. Since letters will appear normally in window 1, and window 3 characters are simply window 1 characters reversed, you will only have problems with characters in windows 2 and 4. To conver these characters, put your message in A$, and use the following subroutine: 500 B$="":FOR I=1 TO LEN(A$):B=ASC(MID$(A$,I,1)) 510 B=B+32:IF B<96 THEN B=B+96 520 B$=B$+CHR$(B):NEXT I:RETURN This subroutine converts each letter to its ASCII equivalent, adds the proper offset, and converts it back to part of the new string, B$. When the conversion is complete, B$ will hold the characters necessary to PRINT that message in window 2. For window 4, PRINT CHR$(18);B$;CHR$(146). This will turn reverse video on before printing the string, and turn it off afterwards. A practical demonstration of the technique for setting up windows is given in the sample program below. The program sets up three windows, and shows them flashing, appearing and disappearing. 5 DIM RO$(25):RO$(0)=CHR$(19):FOR I=1 TO 24:RO$(I)=RO$(I-1)+CHR$(17):NEXT 10 POKE 53265,PEEK(53265) OR 64 20 POKE 53280,0:POKE 53281,0:POKE 53282,1:POKE 53283,2:POKE 53284,13 25 OP$=CHR$(160):FOR I=1 TO 4:OP$=OP$:NEXTI:PRINTCHR$(147);RO$(3); 30 FOR I=1 TO10:PRINTTAB(1);CHR$(18);" ";TAB(23);OP$:NEXT 40 PRINT CHR$(146):PRINT:PRINT:FOR I=1 TO 4:PRINTOP$;OP$;OP$;OP$;OP$;:NEXTI 50 PRINT RO$(5);CHR$(5);CHR$(18);TAB(2);"A RED WINDOW" 60 PRINT CHR$(18);TAB(2);"COULD BE USED" 70 PRINT CHR$(18);TAB(2);"FOR ERROR" 80 PRINT CHR$(18);TAB(2);"MESSAGES" 100 A$="A GREEN WINDOW":GOSUB 300:PRINT RO$(5);CHR$(144);CHR$(18);TAB(24);B$ 110 A$="COULD BE USED":GOSUB 300:PRINTTAB(24);CHR$(18);B$ 120 A$="TO GIVE":GOSUB 300:PRINTTAB(24);CHR$(18);B$ 130 A$="INSTRUCTIONS":GOSUB 300:PRINTTAB(24);CHR$(18);B 140 PRINT CHR$(31);RO$(19); 150 A$=" WHILE THE MAIN WINDOW COULD BE USED":GOSUB 300:PRINT B$ 160 A$=" FOR ACCEPTING COMMANDS.":GOSUB 300:PRINT B$ 170 FOR I=1 TO 5000:NEXT I:POKE 53284,0 180 FOR I=1 TO 5:FOR J=1 TO 300:NEXT J:POKE 53282,15 190 FOR J=1 TO 300:NEXT J:POKE 53282,1 200 NEXT I:POKE 53283,-2*(PEEK(53283)=240):POKE 53284,-13*(PEEK(53284)=240) 210 GOTO 180 300 B$="":FOR I=1TOLEN(A$):B=ASC(MID$(A$,I,1)) 310 B=B+32:IFB<96THENB=B+96 320 B$=B$+CHR$(B):NEXTI:RETURN Bit 7. Bit 7 of this register is the high-order bit (Bit 8) of the Raster Compare register at 53266 ($D012). Even though it is located here, it functions as part of that register (see the description below for more information on the Raster Compare register). Machine language programmers should note that its position here at Bit 7 allows testing this bit with the Negative flag. Since scan lines above number 256 are all off the screen, this provides an easy way to delay changing the graphics display until the scan is in the vertical blanking interval and the display is no longer being drawn: LOOP LDA $D011 BPL LOOP Sprites should always be moved when the raster is scanning off-screen, because if they are moved while they are being scanned, their shapes will waver slightly. The BASIC equivalent of the program fragment above is the statement WAIT 53265,128, but BASIC is usually not fast enough to execute the next statement while still in the blanking interval. 53266 $D012 RASTER Read Current Raster Scan Line/Write Line to Compare for Raster IRQ The Raster Compare register has two different functions, depending on whether you are reading from it or writing to it. When this register is read, it tells which screen line the electron beam is currently scanning. There are 262 horizontal lines which make up the American (NTSC) standard display screen (312 lines in the European or PAL standard screen). Every one of these lines is scanned and updated 60 times per second. Only 200 of these lines (numbers 50-249) are part of the visible display. It is sometimes helpful to know just what line is being scanned, because changing screen graphics on a particular line while that line is being scanned may cause a slight disruption on the screen. By reading this register, it is possible for a machine language program to wait until the scan is off the bottom of the screen before changing the graphics display. It is even possible for a machine language program to read this register, and change the screen display when a certain scan line is reached. The program below uses this technique to change the background color in midscreen, in order to show all 256 combinations of foreground and background text colors at once. 40 FOR I=49152 TO 49188:READ A:POKE I,A:NEXT:POKE 53280,11 50 PRINT CHR$(147):FOR I=1024 TO I+1000:POKE I,160:POKE I+54272,11:NEXT I 60 FOR I=0 TO 15:FOR J=0 TO 15 70 P=1196+(48*I)+J:POKE P,J+I:POKE P+54272,J:NEXT J,I 80 PRINT TAB(15)CHR$(5)"COLOR CHART":FOR I=1 TO 19:PRINT:NEXT 85 PRINT "THIS CHART SHOWS ALL COMBINATIONS OF " 86 PRINT "FOREGROUND AND BACKGROUND COLORS. " 87 PRINT "FOREGROUND INCREASES FROM LEFT TO RIGHT" 88 PRINT "BACKGROUND INCREASES FROM TOP TO BOTTOM" 90 SYS 12*4096 100 DATA 169,90,133,251,169,0,141,33,208,162,15,120,173,17,208,48 105 DATA 251,173,18,208 110 DATA 197,251,208,249,238,33,208,24,105,8,133,251,202,16,233,48,219 Writing to this register designates the comparison value for the Raster Compare Interrupt. When that interrupt is enabled, a maskable interrupt request will be issued every time the electron beam scan reaches the scan line whose number was written here. This is a much more flexible technique for changing the display in midscreen than reading this register as the sample program above does. That technique requires that the program continuously watch the Raster Register, while the interrupt method will call the program when the time is right to act. For more information on raster interrupts, see the entry for the Interrupt Mask Register (53274, $D01A). It is very important to remember that this register requires nine bits, and that this location only holds eight of those bits (the ninth is Bit 7 of 53265 ($D011)). If you forget to read or write to the ninth bit, your results could be in error by a factor of 256. For example, some early programs written to demonstrate the raster interrupt took for granted that the ninth bit of this register would be set to 0 on power-up. When a later version of the Kernal changed this initial value to a 1, their interrupt routines, which were supposed to set the raster interrupt to occur at scan line number 150, ended up setting it for line number 406 instead. Since the scan line numbers do not go up that high, no interrupt request was ever issued and the program did not work. Location Range: 53267-53268 ($D013-$D014) Light Pen Registers A light pen is an input device that can be plugged into joystick Control Port #1. It is shaped like a pen and has a light-sensitive device at its tip that causes the trigger switch of the joystick port to close at the moment the electron beam that updates the screen display strikes it. The VIC-II chip keeps track of where the beam is when that happens, and records the corresponding horizontal and vertical screen coordinates in the registers at these locations. A program can read the position at which the light pen is held up to the screen. The values in these registers are updated once every screen frame (60 times per second). Once the switch is closed and a value written to these registers, the registers are latched, and subsequent switch closings during the same screen frame will not be recorded. A given light pen may not be entirely accurate (and the operator may not have a steady hand). It is probably wise to average the positions returned from a number of samplings, particularly when using a machine language driver. 53267 $D013 LPENX Light Pen Horizontal Position This location holds the horizontal position of the light pen. Since there are only eight bits available (which give a range of 256 values) for 320 possible horizontal screen positions, the value here is accurate only to every second dot position. The number here will range from 0 to 160 and must be multiplied by 2 in order to get a close approximation of the actual horizontal dot position of the light pen. 53268 $D014 LPENY Light Pen Vertical Position This location holds the vertical position of the light pen. Since there are only 200 visible scan lines on the screen, the value in this register corresponds exactly to the current raster scan line. 53269 $D015 SPENA Sprite Enable Register Bit 0: Enable Sprite 0 (1=sprite is on, 0=sprite is off) Bit 1: Enable Sprite 1 (1=sprite is on, 0=sprite is off) Bit 2: Enable Sprite 2 (1=sprite is on, 0=sprite is off) Bit 3: Enable Sprite 3 (1=sprite is on, 0=sprite is off) Bit 4: Enable Sprite 4 (1=sprite is on, 0=sprite is off) Bit 5: Enable Sprite 5 (1=sprite is on, 0=sprite is off) Bit 6: Enable Sprite 6 (1=sprite is on, 0=sprite is off) Bit 7: Enable Sprite 7 (1=sprite is on, 0=sprite is off) In order for any sprite to be displayed, the corresponding bit in this register must be set to 1 (the default for this location is 0). Of course, just setting this bit along will not guarantee that a sprite will be shown on the screen. The Sprite Data Pointer must indicate a data area that holds some values other than 0. The Sprite Color Register must also contain a value other than that of the background color. In addition, the Sprite Horizontal and Vertical Position Registers must be set for positions that lie within the visible screen range in order for a sprite to appear on screen. 53270 $D016 SCROLX Horizontal Fine Scrolling and Control Register Bits 0-2: Fine scroll display horizontally by X dot positions (0-7) Bit 3: Select a 38-column or 40-column text display (1=40 columns, 0=38 columns) Bit 4: Enable multicolor text or multicolor bitmap mode (1=multicolor on, 0=multicolor off) Bit 5: Video chip reset (0=normal operations, 1=video completely off) Bits 6-7: Unused This is one of the two important multifunction control registers on the VIC-II chip. On power-up, it is set to a default value of 8, which means that the VIC chip Reset line is set for a normal display, Multicolor Mode is disabled, a 40-column text display is selected, and no horizontal fine-scroll offset is used. Bits 0-2. The first three bits of this chip control vertical fine scrolling of the screen display. This feature allows you to smoothly move the entire text display back and forth, enabling the display area to act as a window, scrolling over a larger text or character graphics display. Since each text character is eight dots wide, moving each character over one whole character position (known as coarse scrolling) is a relatively big jump, and the motion looks jerky. By placing a number from 1 to 7 into these three bits, you can move the whole screen display from one to seven dot spaces to the right. Stepping through values 1 to 7 allows you to smoothly make the transition from having a character appear at one screen column to having it appear at the next one over. To demonstrate this, type in the following program, LIST, and RUN it. 10 FOR I=1 TO 50:FOR J=0 TO 7 20 POKE 53270,(PEEK(53270)AND248) OR J:NEXT J,I 30 FOR I=1 TO 50:FOR J=7 TO 0 STEP-1 40 POKE 53270,(PEEK(53270)AND248) OR J:NEXT J,I As you can see, after the display has moved over seven dots, it starts over at its original position. In order to continue with the scroll, you must do a coarse scroll every time the value of the scroll bits goes from 7 to 0, or from 0 to 7. This is accomplished by moving each byte of display data on each line over one position, overwriting the last character, and introducing a new byte of data on the opposite end of the screen line to replace it. Obviously, only a machine language program can move all of these bytes quickly enough to maintain the effect of smooth motion. The following BASIC program, however, will give you an idea of what the combination of fine and coarse scrolling looks like. 10 POKE 53281,0:PRINT CHR$(5);CHR$(147):FOR I=1 TO 5:PRINT CHR$(17):NEXT 20 FOR I=1 TO 30 30 PRINT TAB(I-1)"{UP}{10 SPACES}{UP}" 40 WAIT53265,128:POKE53270,PEEK(53270)AND248:PRINTTAB(I)"AWAY WE GO" 50 FOR J=1 TO 7 60 POKE 53270,(PEEK(53270)AND248)+J 70 FORK=1TO30-I 80 NEXT K,J,I:RUN Changing the value of the three horizontal scroll bits will affect the entire screen display. If you wish to scroll only a portion of the screen, you will have to use raster interrupts (see 53274 ($D01A) below) to establish a scroll zone, change the value of these scroll bits only when that zone is being displayed, and change it back to 0 afterward. Bit 3. Bit 3 of this register allows you to cover up the first and last columns of the screen display with the border. Since the viewers cannot see the characters there, they will not be able to see you insert a new character on the end of the line when you do coarse scrolling (see explanation of Bits 0-2 above). Setting this bit to 1 enables the normal 40-column display, while resetting it to 0 changes the display to 38 columns. This is a purely cosmetic aid, and it is not necessary to change the screen to the smaller size to use the scrolling feature. Bit 4. This bit selects multicolor graphics. The effect of setting this bit to 1 depends on whether or not the bitmap graphics mode is also enabled. If you are not in bitmap mode, and you select multicolor text character mode by setting this bit to 1, characters with a color nybble whose value is less than 8 are displyed normally. There will be one background color and one foreground color. But each dot of a character with a color nybble whose value is over 7 can have any one of four different colors. The two colors in the Background Control Registers 1 and 2 (53282-3, $D022-3) are available in addition to the colors supplied by the Color RAM. The price of these extra colors is a reduction in horizontal resolution. Instead of each bit controlling one dot, in multicolor mode a pair of bits control the color of a larger dot. A pattern of 11 will light it with the color from the lower three bits of color RAM. Patterns of 01 and 10 will select the colors from Background Color Registers 1 and 2, respectively, for the double-width dot. You can see the effect that setting this bit has by typing in the following BASIC command line: POKE 53270,PEEK(53280)OR16:PRINT CHR$(149)"THIS IS MULTICOLOR MODE" It is obvious from this example that the normal set of text characters was not made to be used in multicolor mode. In order to take advantage of this mode, you will need to design custom four-color characters. For more information, see the alternate entry for 53248 ($D000), the Character Generator ROM. If the multicolor and bitmap enable bits are both set to 1, the result is a multicolor bitmap mode. As in multicolor text mode, pairs of graphics data bits are used to set each dot in a 4 by 8 matrix to one of four colors. This results in a reduction of the horizontal resolution to 160 double-wide dots across. But while text multicolor mode allows only one of the four colors to be set individually for each 4 by 8 dot area, bitmap multicolor mode allows up to three different colors to be individually selected in each 4 by 8 dot area. The source of the dot color for each bit-pair combination is shown below: 00 Background Color Register 0 (53281, $D021) 01 Upper four bits of Video Matrix 10 Lower four bits of Video Matrix 11 Color RAM nybble (area starts at 55296 ($D800)) The fact that bit-pairs are used in this mode changes the strategy for plotting somewhat. In order to find the byte BY in which the desired bit-pair resides, you must multiply the horizontal position X, which has a value of 0- 159, by 2, and then use the same formula as for hi-res bitmap mode. Given that the horizontal position (0-159) of the dot is stored in the variable X, its vertical position is in the variable Y, and the base address of the bitmap area ia in the variable BASE, you can find the desired byte with the formula: BY=BASE+(Y AND 248)*40+(Y AND 7)+(2*X AND 504) Setting the desired bit-pair will depend on what color you chose. First, you must set up an array of bit masks. CA(0)=1:CA(1)=4:CA(2)=16:CA(3)=64 To turn on the desired dot, select a color CO from 0 to 3 (representing the color selected by the corresponding bit pattern) and execute the following statement: BI=(NOT X AND 3):POKE BY,PEEK(BY) AND (NOT 3*CA(BI)) OR (CO*CA(BI)) The following program will demonstrate this technique: 10 CA(0)=1:CA(1)=4:CA(2)=16:CA(3)=64:REM ARRAY FOR BIT PAIRS 20 BASE=2*4096:POKE53272,PEEK(53272)OR8:REM PUT BIT MAP AT 8192 30 POKE53265,PEEK(53265)OR32:POKE53270,PEEK(53270)OR16:REM MULTI-COLOR BIT MAP 40 A$="":FOR I=1 TO 37:A$=A$+"C":NEXT:PRINT CHR$(19); 50 FOR I=1 TO 27:PRINT A$;:NEXT:POKE 2023,PEEK(2022): REM SET COLOR MAP 60 A$="":FOR I=1 TO 128:A$=A$+"@":NEXT:FOR I=32 TO 63 STEP 2 70 POKE648,I:PRINTCHR$(19);A$;A$;A$;A$:NEXT:POKE648,4:REM CLR HI-RES SCREEN 80 FOR CO=1TO3:FOR Y=0TO199STEP.5:REM FROM THE TOP OF THE SCREEN TO THE BOTTOM 90 X=INT(10*CO+15*SIN(CO*45+Y/10)): REM SINE WAVE SHAPE 100 BY=BASE+40*(Y AND 248)+(Y AND 7)+(X*2 AND 504): REM FIND HI-RES BYTE 110 BI=(NOT X AND 3):POKE BY,PEEK(BY) AND (NOT 3*CA(BI)) OR(CO*CA(BI)) 120 NEXT Y,CO 130 GOTO 130: REM LET IT STAY ON SCREEN Bit 5: Bit 5 controls the VIC-II chip Reset line. Setting this bit to 1 will completely stop the video chip from operating. On older 64s, the screen will go black. It should always be set to 0 to insure normal operation of the chip. Bits 6 and 7. These bits are not used. 53271 $D017 YXPAND Sprite Vertical Expansion Register Bit 0: Expand Sprite 0 vertically (1=double height, 0=normal height) Bit 1: Expand Sprite 1 vertically (1=double height, 0=normal height) Bit 2: Expand Sprite 2 vertically (1=double height, 0=normal height) Bit 3: Expand Sprite 3 vertically (1=double height, 0=normal height) Bit 4: Expand Sprite 4 vertically (1=double height, 0=normal height) Bit 5: Expand Sprite 5 vertically (1=double height, 0=normal height) Bit 6: Expand Sprite 6 vertically (1=double height, 0=normal height) Bit 7: Expand Sprite 7 vertically (1=double height, 0=normal height) This register can be used to double the height of any sprite. When the bit in this register that corresponds to a particular sprite is set to 1, each dot of the 24 by 21 sprite dot matrix will become two raster scan lines high instead of one. 53272 $D018 VMCSB VIC-II Chip Memory Control Register Bit 0: Unused Bits 1-3: Text character dot-data base address within VIC-II address space Bits 4-7: Video matrix base address within VIC-II address space This register affects virtually all graphics operations. It determines the vase address of two very important data areas, the Video Matrix, and the Character Dot-Data area. Bits 1-3. These bits are used to set the location of the Character Dot-Data area. This area is where the data is stored (for more information on character shape data, see the alternate entry for location 53248 ($D000), the Character Generator ROM). Bits 1-3 can represent any even number from 0 to 14. That numer stands for the even 1K offset of the character data area from the beginning of VIC-II memory. For example, if these bits are all set to 0, it means that the character memory occupies the first 2K of VIC-II memory. If they equal 2, the data area starts 2*1K (2*1024) or 2048 bytes from the beginning of VIC memory. The default value of this nybble is 4. This sets the address of the Character Dot-Data area to 4096 ($1000), which is the starting address of where the VIC-II chip addresses the Character ROM. The normal character set which contains uppercase and graphics occupies the first 2K of that ROM. The alternate character set which contains both upper- and lowercase letters use the second 2K. Therefore, to shift to the alternate character set, you must change the value of this nybble to 6, with a POKE 53272,PEEK(53272)OR2. To change it back, POKE 53272,PEEK(53272)AND253. In bitmap mode, the lower nybble controls the location of the bitmap screen data. Since this data area can start only at an offset of 0 or 8K from the beginning of VIC-II memory, only Bit 3 of the Memory Control Register is significant in bitmap mode. If Bit 3 holds a 0, the offset is 0, and if it holds a 1, the offset is 8192 (8K). Bits 4-7. This nybble determines the starting address of the Video Matrix area. This is the 1024-byte area of memory which contains the screen codes for the text characters that are displayed on the screen. In addition, the last eight bytes of this area are used as pointers which designate which 64- byte block of VIC-II memory will be used as shape data for each sprite. These four bits can represent numbers from 0 to 15. These numbers stand for the offset (in 1K increments) from the beginning of VIC-II memory to the Video Matrix. For example, the default bit pattern is 0001. This indicates that the Video Matrix is offset by 1K from the beginning of VIC-II memory, the normal starting place for screen memory. Remember, though, the bit value of this number will be 16 times what the bit pattern indicates, because we are dealing with Bits 4-7. Therefore, the 0001 in the upper nybble has a value of 16. Using this register, we can move the start of screen memory to any 1K boundary within the 16K VIC-II memory area. Just changing this register, however, is not enough if you want to use the BASIC line editor. The editor looks to location 648 ($288) to determine where to print screen characters. If you just change the location of the Video Matrix without changing the value in 648, BASIC will continue to print characters in the memory area starting at 1024, even though that area is no longer being displayed. The result is that you will not be able to see anything that you type in on the keyboard. To fix this, you must POKE 648 with the page number of the starting address of screen memory (page number=location/256). Remember, the actual starting address of screen memory depends not only on the offset from the beginning of VIC-II memory in the register, but also on which bank of 16K is used for VIC-II memory. For example, if the screen area starts 1024 bytes from the beginning of VIC- II memory, and the video chip is using Bank 2 (32768-49151), the actual starting address of screen memory is 32768+1024=33792 ($8400). For examples of how to change the video memory area, and of how to relocate the screen, see the entro for 56576 ($DD00). 53273 $D019 VICIRQ VIC Interrupt Flag Register Bit 0: Flag: Is the Raster Compare a possible source of an IRQ? (1=yes) Bit 1: Flag: Is a collision between a sprite and the normal graphics display a possible source of an IRQ? (1=yes) Bit 2: Flag: Is a collision between two sprites a possible source of an IRQ? (1=yes) Bit 3: Flag: Is the light pen trigger a possible source of an IRQ? (1=yes) Bits 4-6: Not used Bit 7: Flag: Is there any VIC-II chip IRQ source which could cause an IRQ? (1=yes) The VIC-II chip is capable of generating a maskable request (IRQ) when certain conditions relating to the video display are fulfilled. Briefly, the conditions that can cause a VIC-II chip IRQ are: 1. The line number of the current screen line being scanned by the raster is the same as the line number value written to the Raster Register (53266, $D012). 2. A sprite is positioned at the same location where normal graphics data are being displayed. 3. Two sprites are positioned so that they are touching. 4. The light sensor on the light pen has been struck by the raster beam, causing the fire button switch on joystick Control Port #1 to close (pressing the joystick fire button can have the same effect). When one of these conditions is met, the corresponding bit in this status register is set to 1 and latched. That means that as long as the corresponding enable bit in the VIC IRQ Mask register is set to 1, and IRQ requested will be generated, and any subsequent fulfillment of the same condition will be ignored until the latch is cleared. This allows you to preserve multiple interrupt requests if more than one of the interrupt conditions is met at a time. In order to keep an IRQ source from generating another request after it has been serviced, and to enable subsequent interrupt conditions to be detected, the interrupt service routine must write a 1 to the corresponding bit. This will clear the latch for that bit. The default value written to this register is 15, which clears all interrupts. There is only 1 IRQ vector that points to the address of the routine that will be executed when an IRQ interrupt occurs. The same routine will therefore be executed regardless of the source of the interrupt. This status register provides a method for that routine to check what the source of the IRQ was, so that the routine can take appropriate action. First, the routine can check Bit 7. Anytime that any of the other bits in the status register is set to 1, Bit 7 will also be set. Therefore, if that bit holds a 1, you know that the VIC-II chip requested an IRQ (the two CIA chips which are the other sources of IRQ interrupts can be checked in a similar manner). Once it has been determined that the VIC chip is responsible for the IRQ, the individual bits can be tested to see which of the IRQ conditions have been met. For more information, and a sample VIC IRQ program, see the following entry. 53274 $D01A IRQMASK IRQ Mask Register Bit 0: Enable Raster Compare IRQ (1=interrupt enabled) Bit 1: Enable IRQ to occure when sprite collides with display of normal graphics data (1=interrupt enabled) Bit 2: Enable IRQ to occur when two sprites collide (1=interrupt enabled) Bit 3: Enable light pen to trigger an IRQ (1=interrupt enabled) Bits 4-7: Not used This register is used to enable an IRQ request to occur when one of the VIC-II chip interrupt conditions is met. In order to understand what that means, and how these interrupts can extend the range of options available to a programmer, you must first understand what an interrupt is. An interrupt is a signal given to the microprocessor (the brains of the computer) that tells it to stop executing its machine language program (for example, BASIC), and to work on another program for a short time, perhaps only a fraction of a second. After finishing the interrupt program, the computer goes back to executing the main program, just as if there had never been a detour. Bit 0. This bit enables the Raster Compare IRQ. The conditions for this IRQ are met when the raster scan reaches the video line indicated by the value written to the Raster Register at 53266 ($D012) and Bit 7 of 53265 ($D011). Again, an explanation of the terminology is in order. In the normal TV display, a beam of electrons (raster) scans the screen, starting in the top-left corner, and moving in a straight line to the right, lighting up appropriate parts of the screen line on the way. When it comes to the right edge, the beam moves down a line, and starts again from the left. There are 262 such line that are scanned by the 64 display, 200 of which form the visible screen area. This scan updates the complete screen display 60 times every second. The VIC-II chip keeps track of which line is being scanned, and stores the scan number in the Raster Register at 53266 and 53265 ($D012 and $D011). The Raster Register has two functions. When read, it tells what line is presently being scanned. But when written to, it designates a particular scan line as the place where a raster interrupt will occur. At the exact moment that the raster beam line number equals the number written to the register, Bit 0 of the status register will be set to 1, showing that the conditions for a Raster Compare Interrupt have been fulfulled. If the raster interrupt is enabled then, simultaneously, the interrupt program will be executed. This allows the user to reset any of the VIC-II registers at any point in the display, and thus change character sets, background color, or graphics mode for only a part of the screen display. The interrupt routine will first check if the desired condition is the source of the interrupt (see above entry) and then make the changes to the screen display. Once you have written this interrupt routine, you must take the following steps to install it. 1. Set the interrupt disable flag in the status register with an SEI instruction. This will disable all interrupts and prevent th system from crashing while you are changing the interrupt vectors. 2. Enable the raster interrupt. This is done by setting Bit 0 of the VIC- II chip interrupt enable register at location 53274 ($D01A) to 1. 3. Indicate the scan line on which you want the interrupt to occur by writing to the raster registers. Don't forget that this is a nine-bit value, and you must set both the low byte (in location 53266 ($D012)) and the high bit (in the register at 53265 ($D011)) in order to insure that the interrupt will start at the scan line you want it to, and not 256 lines earlier or later. 4. Let the computer know where the machine language routine that you want the interrupt to execute starts. This is done by placing the address in the interrupt vector at locations 788-789 ($314-$315). This address is split into two parts, a low byte and a high byte, with the low byte stored at 788. To calculate the two values for a given address AD, you may use the formula HIBYTE=INT(AD/156) and LOWBYTE=AD-(HIBYTE*256). The value LOWBYTE would go into location 788, and the value HIBYTE would go into location 789. 5. Reenable interrupts with a CLI instruction, which clears the interrupt disable flag on the status register. When the computer is first turned on, the interrupt vector is set to point to the normal hardware timer interrupt routine, the one that advances the jiffy clock and reads the keyboard. Since this interrupt routine uses the same vector as the raster interrupt routine, it is best to turn off the hardware timer interrupt by putting a value of 127 in location 56333 ($DC0D). If you want the keyboard and jiffy clock to function normally while your interrupt is enabled, you must preserve the contents of locations 788 and 789 before you change them to point to your new routine. Then you must have your interrupt routine jump to the old interrupt routine exactly once per screen refresh (every 1/60 second). Another thing that you should keep in mind is that at least two raster interrupts are required if you want to change only a part of the screen. Not only must the interrupt routine change the display, but it must also set up another raster interrput that will change it back. The sample program below uses a raster-scan interrupt to divide the display into three sections. The first 80 scan lines are in high-resolution bitmap mode, the next 40 are regular text, and the last 80 are in multicolor bitmap mode. The screen will split this way as soon as a SYS to the routine that turns on the interrupt occurs. The display will stay split even after the program ends. Only if you hit the STOP and RESTORE keys together will the display return to normal. The interrupt uses a table of values that are POKEd into four key locations during each of the three interrupts, as well as values to determine at what scan lines the interrupt will occur. The locations affected are Control Register 1 (53265, $D011), Control Register 2 (53270, $D016), the Memory Control Register (53272, $D018), and Background Color 0 (53281, $D021). The data for the interrupt routine is contained in lines 49152-49276. Each of these line numbers corresponds to the locations where the first data byte in the statement is POKEd into memory. If you look at lines 49264-49276 of the BASIC program, you will see REMark statements that explain which VIC-II registers are affected by the DATA statements in each line. The number in these DATA startements appear in the reverse order in which they are put into the VIC register. For example, line 49273 holds the data that will go into Control Register 2. The last number, 8, is the one that will be placed into Control Register 2 while the top part of the screen is displayed. The first number, 24, is placed into Control Register 2 during the bottom part of the screen display, and changes that portion of the display to multicolor mode. The only tricky part in determining which data byte affects which interrupt comes in line 49264, which holds the data that determines the scan line at which each interrupt will occur. Each DATA statement entry reflects the scan line at which the next interrupt will occur. The first item in line 49264 is 49. Even though this is the entry for the third interrupt, the next to be generates is the first interrupt, which occurs at the top of the screen. Likewise, the last data item of 129 is used during the first interrupt to start the next interrupt at scan line 129. Try experimenting with these values to see what results you come up with. For example, if you change the number 170 to 210, you will increase the text area by five lines (40 scan lines). By changing the values in the data tables, you can alter the effect of each interrupt. Change the 20 in line 49276 to 22, and you will get lowercase text in the middle of the screen. Change the first 8 in line 49273 to 24, and you'll get multicolor text in the center window. Each of these table items may be used exactly like you would use the corresponding register, in order to change background color, to obtain text or bitmap graphics, regular or multicolor modes, screen blanking or extended background color mode. It is even possible to change the table values during a program, by POKEing the new value into the memory location where those table values are stored. In that way, you can, for example, change the background color of any of the screen parts while the program is running. 5 FOR I=0 TO 7:BI(I)=2^I:NEXT 10 FOR I=49152 TO 49278:READ A:POKE I,A:NEXT:SYS12*4096 20 PRINT CHR$(147):FOR I=0 TO 8:PRINT:NEXT 30 PRINT"THE TOP AREA IS HIGH-RES BIT MAP MODE" 40 PRINT:PRINT"THE MIDDLE AREA IS ORDINARY TEXT " 50 PRINT:PRINT"THE BOTTOM AREA IS MULTI-COLOR BIT MAP" 60 FORG=1384 TO 1423:POKE G,6:NEXT 70 FORG=1024 TO 1383:POKEG,114:POKE G+640,234:NEXT 80 A$="":FOR I=1 TO 128:A$=A$+"@":NEXT:FOR I=32 TO 63 STEP 2 90 POKE 648,I:PRINT CHR$(19)CHR$(153);A$;A$;A$;A$:NEXT:POKE 648,4 100 BASE=2*4096:BK=49267 110 H=40:C=0:FORX=0TO319:GOSUB150:NEXT 120 H=160:C=0:FORX=0TO319STEP2:GOSUB150:NEXT:C=40 125 FORX=1TO319STEP2:GOSUB150:NEXT 130 C=80:FOR X=0 TO 319 STEP2:W=0:GOSUB150:W=1:GOSUB150:NEXT 140 GOTO 140 150 Y=INT(H+20*SIN(X/10+C)):BY=BASE+40*(Y AND 248)+(Y AND 7)+(X AND 504) 160 POKE BY,PEEK(BY) OR (BI(ABS(7-(XAND7)-W))):RETURN 49152 DATA 120, 169, 127, 141, 13, 220 49158 DATA 169, 1, 141, 26, 208, 169 49164 DATA 3, 133, 251, 173, 112, 192 49170 DATA 141, 18, 208, 169, 24, 141 49176 DATA 17, 208, 173, 20, 3, 141 49182 DATA 110, 192, 173, 21, 3, 141 49188 DATA 111, 192, 169, 50, 141, 20 49194 DATA 3, 169, 192, 141, 21, 3 49200 DATA 88, 96, 173, 25, 208, 141 49206 DATA 25, 208, 41, 1, 240, 43 49212 DATA 190, 251, 16, 4, 169, 2 49218 DATA 133, 251, 166, 251, 189, 115 49224 DATA 192, 141, 33, 208, 189, 118 49230 DATA 192, 141, 17, 208, 189, 121 49236 DATA 192, 141, 22, 208, 189, 124 49242 DATA 192, 141, 24, 208, 189, 112 49248 DATA 192, 141, 18, 208, 138, 240 49254 DATA 6, 104, 168, 104, 170, 104 49260 DATA 64, 76, 49, 234 49264 DATA 49, 170, 129 :REM SCAN LINES 49267 DATA 0, 6, 0:REM BACKGROUND COLOR 49270 DATA 59, 27,59:REM CONTROL REG. 1 49273 DATA 24, 8, 8:REM CONTROL REG. 2 49276 DATA 24, 20, 24:REM MEMORY CONTROLRUN Besides enabling the creation of mixed graphics-modes screens, the Raster Compare Interrupt is also useful for creating scrolling zones, so that some parts of the screen can be fine-scrolled while the rest remains stationary. Bit 1 enables the light pen interrupt. This interrupt can occur when the light of the raster beam strikes the light-sensitive device in the pen's tip, causing it to close the fire button switch on joystick Controller Port #1. The light pen interrupt affords a method of signaling to a program that the pen is being held to the screen, and that its position can be read. Some light pens provide a push-button switch which grounds one of the other lines on the joystick port. This switch can be pressed by the user as an additional signal that the pen is properly positioned. Its location can then be read in the light pen position registers (53267-8, $D013-4). Bit 2 enables the sprite-foreground collision interrupt. This interrupt can occur if one of the srpte character's dots is touching one of the dots from the foreground display of either text character or bitmap graphics. Bit 3 enables the sprite-sprite collision interrupt, which can occur if one of the sprite character's dots is touching one of the dots of another sprite character. These two interrupts are useful for games, where such collisions often require that some action be taken immediately. Once the interrupt signals that a collision has occurred, the interrupt routine can check the Sprite- Foreground Collision Register at 53279 ($D01F), or the Sprite-Sprite Collision Register at 53278 ($D01E), to see which sprite or sprites are involved in the collision. See the entry for those locations for more details on collisions. 53275 $D01B SPBGPR Sprite to Foreground Display Priority Register Bit 0: Select display priority of Sprite 0 to foreground (0=sprite appears in front of foreground) Bit 1: Select display priority of Sprite 1 to foreground (0=sprite appears in front of foreground) Bit 2: Select display priority of Sprite 2 to foreground (0=sprite appears in front of foreground) Bit 3: Select display priority of Sprite 3 to foreground (0=sprite appears in front of foreground) Bit 4: Select display priority of Sprite 4 to foreground (0=sprite appears in front of foreground) Bit 5: Select display priority of Sprite 5 to foreground (0=sprite appears in front of foreground) Bit 6: Select display priority of Sprite 6 to foreground (0=sprite appears in front of foreground) Bit 7: Select display priority of Sprite 7 to foreground (0=sprite appears in front of foreground) If a sprite is positioned to appear at a spot on the screen that is already occupied by text or bitmap graphics, a conflict arises. The contents of this register determines which one will be displayed in such a situation. If the bit that corresponds to a particular sprite is set to 0, the sprite will be displayed in front of the foreground graphics data. If that bit is set to 1, the foreground data will be displayed in front of the sprite. The default value that this register is set to at power-on is 0, so all sprites start out with priority over foreground graphics. Note that for the purpose of priority, the 01 bit-pair of multicolor graphics modes is considered to display a background color, and therefore will be shown behind sprite graphics even if the foreground graphics data takes priority. Also, between the sprites themselves there is a fixed priority. Each sprite has priority over all higher-number sprites, so that Sprite 0 is displayed in front of all the others. The use of priority can aid in creating three-dimensional effects, by allowing some objects on the screen to pass in front of or behind other objects. 53276 $D01C SPMC Sprite Multicolor Registers Bit 0: Select multicolor mode for Sprite 0 (1=multicolor, 0=hi-res) Bit 1: Select multicolor mode for Sprite 1 (1=multicolor, 0=hi-res) Bit 2: Select multicolor mode for Sprite 2 (1=multicolor, 0=hi-res) Bit 3: Select multicolor mode for Sprite 3 (1=multicolor, 0=hi-res) Bit 4: Select multicolor mode for Sprite 4 (1=multicolor, 0=hi-res) Bit 5: Select multicolor mode for Sprite 5 (1=multicolor, 0=hi-res) Bit 6: Select multicolor mode for Sprite 6 (1=multicolor, 0=hi-res) Bit 7: Select multicolor mode for Sprite 7 (1=multicolor, 0=hi-res) Sprite multicolor mode is very similar to text and bitmap multicolor modes (see Bit 4 of 53270, $D016). Normally, the color of each dot of the sprite is controlled by a single bit of sprite shape data. When thi mode is enabled for a sprite, by setting the corresponding bit of this register to 1, the bits of sprite shape data are grouped together in pairs, with each pair of bits controlling a double-wide dot of the sprite display. By sacrificing some of the horizontal resolution (the sprite, although the same size, is now only 12 dots wide), you gain the use of two additional colors. The four possible combinations of these bit-pairs display dot colors from the following sources: 00 Background Color Register 0 (transparent) 01 Sprite Multicolor Register 0 (53285, $D025) 10 Sprite Color Registers (53287-94, $D027-E) 11 Sprite Multicolor Register 1 (53286, $D026) Like multicolor text characters, multicolor sprites all share two color registers. While each sprite can display three foreground colors, only one of these colors in unique to that sprite. The number of unique colors may be increated by combining more than one sprite into a single character. 53277 $D01D XXPAND Sprite Horizontal Expansion Register Bit 0: Expand Sprite 0 horizontally (1=double-width sprite, 0=normal width) Bit 1: Expand Sprite 1 horizontally (1=double-width sprite, 0=normal width) Bit 2: Expand Sprite 2 horizontally (1=double-width sprite, 0=normal width) Bit 3: Expand Sprite 3 horizontally (1=double-width sprite, 0=normal width) Bit 4: Expand Sprite 4 horizontally (1=double-width sprite, 0=normal width) Bit 5: Expand Sprite 5 horizontally (1=double-width sprite, 0=normal width) Bit 6: Expand Sprite 6 horizontally (1=double-width sprite, 0=normal width) Bit 7: Expand Sprite 7 horizontally (1=double-width sprite, 0=normal width) This register can be used to double the width of any sprite. Setting any bit of this register to 1 will cause each dot of the corresponding sprite shape to be displayed twice as wide as normal, so that without changing its horizontal resolution, the sprite takes up twice as much space. The horizontal expansion feature can be used alone, or in combination with the vertical expansion register at 53271 ($D017). Location Range: 53278-53279 ($D01E-$D01F) Sprite Collision Detection Registers While Bit 2 of the VIC IRQ Register at 53273 ($D019) is set to 1 anytime two sprites overlap, and Bit 1 is set to 1, when a sprite shape is touching the foreground text or bit-graphics display, these registers specify which sprites were involved in the collision. Every bit that is set to 1 indicates that the corresponding sprite was involved in the collision. Reading these registers clears them so that they can detect the next collision. Therefore, if you plan to make multiple tests on the values stored here, it may be necessary to copy it to a RAM variable for further reference. Note that while these registers tell you what sprites were involved in a collision, they do not necessarily tell you what objects have collided with each other. It is quite possible to have three sprites lined up in a row, where Sprite A is on the left, Sprite B is in the middle, touching Sprite A, and Sprite C is on the right, touching Sprite B but not touching Sprite A. The Sprite-Sprite Collision register would show that all three are involved. The only way to make absolutely certain which collided with which is to check the position of each sprite, and calculate for each sprite display line if a sprite of that size would touch either of the others. As you can imagine, this is no easy task. There are a few simple rules concerning what does or does not cause a collision. Though the sprite character consists of 504 dots in a 24 by 21 matrix, does which represent data bits that are equal to 0 (or multicolor bit- pairs equal to 00), and therefore always displayed in the background color, do not count when it comes to collision. A collision can occur only if a dot which represents a sprite shape data bit of 1 touches another dot of nonzero graphics data. Consider the case of two invisible sprites. The first sprite is enabled, its color set to contrast the background, and it is positioned on the screen, but its shape data bytes are all 0. This sprite can never be involved in a collision, because it displays no nonzero data. The second sprite is enabled, positioned on the screen, and its shape pointer set for a data read that is filled with bytes having a value of 255. Even if that sprite's color is set to the same value as the background color, making the sprite invisible, it can still be involved in collisions. The only exception to this rule is the 01 bit-pair of multicolor graphics data. This bit-pair is considered part of the background, and the dot it displays can never be involved in a collision. The other rule to remember about collisions is that they can occur in areas that are covered by the screen border. Collision between sprites can occur when the sprites are offscreen, and collisions between sprites and foreground display data can occur when that data is in an area that is covered by the border due to the reduction of the display to 38 columns or 24 rows. 53278 $D01E SPSPCL Sprite to Sprite Collision Register Bit 0: Did Sprite 0 collide with another sprite? (1=yes) Bit 1: Did Sprite 1 collide with another sprite? (1=yes) Bit 2: Did Sprite 2 collide with another sprite? (1=yes) Bit 3: Did Sprite 3 collide with another sprite? (1=yes) Bit 4: Did Sprite 4 collide with another sprite? (1=yes) Bit 5: Did Sprite 5 collide with another sprite? (1=yes) Bit 6: Did Sprite 6 collide with another sprite? (1=yes) Bit 7: Did Sprite 7 collide with another sprite? (1=yes) 53279 $D01F SPBGCL Sprite to Foreground Collision Register Bit 0: Did Sprite 0 collide with the foreground display? (1=yes) Bit 1: Did Sprite 1 collide with the foreground display? (1=yes) Bit 2: Did Sprite 2 collide with the foreground display? (1=yes) Bit 3: Did Sprite 3 collide with the foreground display? (1=yes) Bit 4: Did Sprite 4 collide with the foreground display? (1=yes) Bit 5: Did Sprite 5 collide with the foreground display? (1=yes) Bit 6: Did Sprite 6 collide with the foreground display? (1=yes) Bit 7: Did Sprite 7 collide with the foreground display? (1=yes) Location Range: 53280-53294 ($D020-$D02E) VIC-II Color Register Although these color registers are used for various purposes, all of them have one thing in common. Like the Color RAM Nybbles, only the lower four bits are connected. Therefore, when reading these registers, you must mask out the upper four bits (that is, BORDERCOLOR=PEEK(53280)AND15) in order to get a true reading. 53280 $D020 EXTCOL Border Color Register The color value here determines the color of the border or frame around the central display area. The entire screen is set to this color when the blanking feature of Bit 4 of 53265 ($D011) is enabled. The default color value is 14 (light blue). 53281 $D021 BGCOL0 Background Color 0 This register sets the background color for all text modes, sprite graphics, and multicolor bitmap graphics. The default color value is 6 (blue). 53282 $D022 BGCOL1 Background Color 1 This register sets the color for the 01 bit-pair of multicolor character graphics, and the background color for characters having screen codes 64-127 in extended background color text mode. The default color value is 1 (white). 53283 $D023 BGCOL2 Background Color 2 This register sets the color for the 10 bit-pair of multicolor character graphics, and the background color for characters habing screen codes 128-191 in extended background color text mode. The default color value is 2 (red). 53285 $D024 BGCOL3 Background Color 3 This register sets the background color for characters having screen codes between 192 and 255 in extended background color text mode. The default color value is 3 (cyan). 53285 $D025 SPMC0 Sprite Multicolor Register 0 This register sets the color that is displayed by the 01 bit-pair in multicolor sprite graphics. The default color value is 4 (purple). 53286 $D026 SPMC1 Sprite Multicolor Register 1 This register sets the color that is displayed by the 11 bit-pair in multicolor sprite graphics. The default color value is 0 (black). Location Range: 53287-53294 ($D027-$D02E) Sprite Color Registers These registers are used to set the color to be displayed by bits of hi-res sprite data having a value of 1, and by bit-pairs of multicolor sprite data having a value of 10. The color of each sprite is determined by its own individual color register. 53287 $D027 SP0COL Sprite 0 Color Register (the default color value is 1, white) 53288 $D028 SP1COL Sprite 1 Color Register (the default color value is 2, red) 53289 $D029 SP2COL Sprite 2 Color Register (the default color value is 3, cyan) 53290 $D01A SP3COL Sprite 3 Color Register (the default color value is 4, purple) 53291 $D01B SP4COL Sprite 4 Color Register (the default color value is 5, green) 53292 $D01C SP5COL Sprite 5 Color Register (the default color value is 6, blue) 53293 $D01D SP6COL Sprite 6 Color Register (the default color value is 7, yellow) 53294 $D01E SP7COL Sprite 7 Color Register (the default color value is 12, medium gray) Location Range: 53295-53311 ($D02F-$D03F) Not Connected The VIC-II chip has only 47 registers for 64 bytes of possible address space. Therefore, the remaining 17 addresses do not access any memory. When read, they will always give a value of 255 ($FF). This value will not change after writing to them. Location Range: 53312-54271 ($D040-$D3FF) VIC-II Register Images Since the VIC-II requires only enough addressing lines to handle 64 locations (the minimum possible for its 47 registers), none of the higher bits are decoded when addressing this 1K area. The result is that every 64 byte area in this 1K block is a mirror of every other. POKE53281+64,1 has the same effect as POKE53281,1 or POKE53281+10*64,1; they all turn the screen background to white. For the sake of clarity in your programs it is advisable to use the base address of the chip. 54272-54300 $D400-$D41C Sound Interface Device (SID) Registers Mmeory locations 54272-54300 ($D400-$D41C) are used to address the 6581 Sound Interface Device (SID). SID is a custom music synthesizer and sound effects generator chip that gives the 64 its impressive musical capabilities. It provides three separate music channels, or voices, as they are called. Each voice has 16-bit frequency resolution, waveform control, envelope shaping, oscillator synchronization, and ring modulation. In addition, programmable high-pass, low-pass, and band-pass filters can be set and enabled or disabled for each sound channel. Since quite a few of these locations must be used in concert to produce sound, a brief summary of the interplay between some of these registers may be helpful. Often the first step is to select an overall volume level using the Volume Register. Then, the desired frequency or pitch of the note is chosen by writing to each of the two bytes which make up the 16-bit Frequency Register. An ADSR envelope setting must be chosen by writing values to the Attack/ Decay and Sustain/Release Register. These determine the rate of the rise and fall of the volume of the note from zero volume to peak volume and back again. These rates have a great influence on the character of the sound. Finally, the waveform must be selected, and the note started (or the oscillator gated, as we say). This is done by writing certain bits to the Control Register. The waveform control lets you select one of four different waveforms, each of which has varying harmonic content that affects the tone quality of the sound. By writing a 1 to the gate bit, you start the Attack/ Delay/Sustain cycle. Afer rising to a peak and declining to the Sustain volume, the volume will continue at the same level until you write a 0 to the gate bit. Then, the Release cycle will start. Make sure that you keep the same waveform bit set to 1 while you write the 0 to the gate bit, so that the Release cycle starts. Otherwise, the sound will stop entirely, as it also will if the Volume Register or the Frequency Register is set to 0. It should be noted that except for the last four SID chip registers, these addresses are write-only. That means that their values cannot be determined by PEEKing these locations. Location Range: 54272-54273 ($D400-$D401) Voice 1 Frequency Control Together, these two locations control the frequency or pitch of the musical output of voice 1. Some frequency must be selected in order for voice 1 to be heard. This frequency may be changed in the middle of a note to achieve special effects. The 16-bit range of the Frequency Control Register covers over eight full octaves, and allows you to vary the pitch from 0 (very low) to about 4000 Hz (very high), in 65536 steps. The exact frequency of the output can be determined by the equation FREQUENCY=(REGISTER VALUE*CLOCK/16777216)Hz where CLOCK equals the system clock frequency, 1022730 for American (NTSC) systems, 985250 for European (PAL), and REGISTER VALUE is the combined value of these frequency registers. That combined value equals the value of the low byte plus 256 times the value of the high byte. Using the American (NTSC) clock value, the equation works out to FREQUENCY=REGISTER VALUE*.060959458 Hz 54272 $D400 FRELO1 Voice 1 Frequency Control (low byte) 54273 $D401 FREHI1 Voice 1 Frequency Control (high byte) Location Range: 54274-54275 ($D402-$D403) Voice 1 Pulse Waveform Width Control As you will see below under the description of the Control Register at 54276 ($D404), you can select one of four different waveforms for the output of each voice. If the pulse waveform is selected, these registers must be set to establish the pulse width. The pulse width has a 12-bit resolution, being made up of the value in the first register and the value in the lower nybble of the second register. The pulse width determines the duty cycle, or proportion of the time that the rectangular wave will stay at the high part of the cycle. The following formula shows the relationship between the value in the Pulse Width Register and the proportion of time that the wave stays at the high part of the cycle: PULSE WIDTH=(REGISTER VALUE/40.95)% The possible range of the register values (0-4095) covers the range of the duty cycles from 0 to 100 percent in 4096 steps. Changing the pulse width will vastly change the sound created with the pulse waveform. 54274 $D402 PWLO1 Voice 1 Pulse Waveform Width (low byte) 54275 $D403 PWHI1 Voice 1 Pulse Waveform Width (high nybble) 54276 $D404 VCREG1 Voice 1 Control Register Bit 0: Gate Bit: 1=Start attack/decay/sustain, 0=Start release Bit 1: Sync Bit: 1=Synchronize Oscillator with Oscillator 3 frequency Bit 2: Ring Modulation: 1=Ring modulate Oscillators 1 and 3 Bit 3: Test Bit: 1=Disable Oscillator 1 Bit 4: Select triangle waveform Bit 5: Select sawtooth waveform Bit 6: Select pulse waveform Bit 7: Select random noise waveform Bit 0. Bit 0 is used to gate the sound. Setting this bit to a 1 while selecting one of the four waveforms will start the attack/decay/sustain part of the cycle. Setting this bit back to 0 (while keeping the same waveform setting) anytime after a note has started playing will begin the release cycle of the note. Of course, in order for the gate bit to have an effect, the frequency and attack/decay/sustain/release (ADSR) registers must be set, as well as the pulse width, if necessary, and the volume control set to a nonzero value. Bit 1. This bit is used to synchronize the fundamental frequency of Oscillator 1 with the fundamental frequency of Oscillator 3, allowing you to create a wide range of complex harmonic structures from voice 1. Synchronization occurs when this bit is set to 1. Oscillator 3 must be set to some frequency other than zero, but no other voice 3 parameters will affect the output from voice 1. Bit 2. When Bit 2 is set to 1, the triangle waveform output of voice 1 is replaced with a ring modulated combination of Oscillators 1 and 3. This ring modulation produces nonharmonic overtone structures that are useful for creating bell or gong effects. Bit 3. Bit 3 is the test bit. When set to 1, it disables the output of the oscillator. This can be useful in generating very complex waveforms (even speech synthesis) under software control. Bit 4. When set to 1, Bit 4 selects the triangle waveform output of Oscillator 1. Bit 0 must also be set for the note to be sounded. Bit 5. This bit selects the sawtooth waveform when set to 1. Bit 0 must also be set for the sound to begin. Bit 6. Bit 6 chooses the pulse waveform when set to 1. The harmonic content of sound produced using this waveform may be varied using the Pulse Width Registers. Bit 0 must be set to begin the sound. Bit 7. When Bit 7 is set to 1, the noise output waveform for Oscillator 1 is set. This creates a random sound output whose waveform varies with a frequency proportionate to that of Oscillator 1. It can be used to imitate the sound of explosions, drums, and other unpitched noises. One of the four waveforms must be chosed in order to create a sound. Setting more than one of these bits will result in a logical ANDing of the waveforms. Particularly, the combination of the noise waveform and another is not recommended. Location Range: 54277-54278 ($D405-$D406) Voice 1 Envelop (ADSR) Control When a note is played on a musical instrument, the volume does not suddenly rise to a peak and then cut off to zero. Rather, the volume builds to a peak, levels off to an intermediate value, and then fades away. This creates what is known as a volume envelope. The first phase of the envelope, in which the volume builds to a peak, is known as the attack phase. The second, in which it declines to an intermediate level, is called the decay phase. The third, in which the intermediate leve of volume is held, is known as the sustain period. The final interval, in which the sound fades away, is called the release part of the cycle. The SID chip allows the volume envelope of each voice to be controlled, so that specific instruments may be imitated, or new sounds created. This is done via the attack/decay and sustain/release registers. Each register devotes four bits (which can store a number from 0 to 15) to each phase of the cycle. When a note is gated by writing a 1 to a waveform bit and to Bit 0 of the Control Register, the attack cycle begins. The volume of the sound builds to a peak over the period of time specified by the high nybble of the attack/decay register. Once it has reached the peak volume, it falls to the intermediate level during the period indicated by the low nybble of the attack/decay register (this is the decay phase). The volume of this intermediate or sustain level is selected by placing a value in the high nybble of the sustain/release register. This volume level is held until a 0 is written to the gate bit of the control register (while leaving the waveform bit set). When that happens, the release phase begins, and the volume of the sound begins to taper off during the period indicated by the low nybble of the sustain/release register. You may notice the volume of the sound does not quite get to 0 at the end of the release cycle, and you may need to turn off the sound to get rid of the residual noise. You can do this either by setting the waveform bit back to 0, changing the frequency to 0, or setting the volume to 0. 54277 $D405 ATDCY1 Voice 1 Attack/Decay Register Bits 0-3: Select decay cycle duration (0-15) Bits 4-7: Select attack cycle duration (0-15) Bits 4-7 control the duration of the attack cycle. This is the period of time over which the volume will rise from 0 to its peak amplitude. There are 16 durations which may be selected. The way in which the number placed here corresponds to the elapsed time of this cycle is as follows: 0 = 2 milliseconds 8 = 100 milliseconds 1 = 8 milliseconds 9 = 250 milliseconds 2 = 16 milliseconds 10 = 500 milliseconds 3 = 24 milliseconds 11 = 800 milliseconds 4 = 38 milliseconds 12 = 1 second 5 = 56 milliseconds 13 = 3 seconds 6 = 68 milliseconds 14 = 5 seconds 7 = 80 milliseconds 15 = 8 seconds Bits 0-3 control the length of the decay phase, in which the volume of the note declines from the peak reached in the attack phase to the sustain level. The number selected corresponds to the length of this phase as shown below: 0 = 6 milliseconds 8 = 300 milliseconds 1 = 24 milliseconds 9 = 750 milliseconds 2 = 48 milliseconds 10 = 1.5 seconds 3 = 72 milliseconds 11 = 2.4 seconds 4 = 114 milliseconds 12 = 3 seconds 5 = 168 milliseconds 13 = 9 seconds 6 = 204 milliseconds 14 = 15 seconds 7 = 240 milliseconds 15 = 24 seconds Since the two functions share one register, you must multiply the attack value by 16 and add it to the decay value in order to come up with the number to be placed in the register: REGISTER VALUE=(ATTACK*16)+DECAY 54278 $D406 SUREL1 Voice 1 Sustain/Release Control Register Bits 0-3: Select release cycle duration (0-15) Bits 4-7: Select sustain volume level (0-15) Bits 4-7 select the volume level at which the note is sustained. Following the decay cycle, the volume of the output of voice 1 will remain at the selected sustain level as long as the gate bit of the Control Register is set to 1. The sustain values range from 0, which chooses no volume, to 15, which sets the output of voice 1 equal to the peak volume achieved during the attack cycle. Bits 0-3 determine the length of the release cycle. This phase, in which the volume fades from the sustain level to near zero volume, begins when the gate bit of the Control Register is set to 0 (while leaving the waveform setting that was previously chosen). The duration of this decline in volume corresponds to the number (0-15) selected in the same way as for the decay value: 0 = 6 milliseconds 8 = 300 milliseconds 1 = 24 milliseconds 9 = 750 milliseconds 2 = 48 milliseconds 10 = 1.5 seconds 3 = 72 milliseconds 11 = 2.4 seconds 4 = 114 milliseconds 12 = 3 seconds 5 = 168 milliseconds 13 = 9 seconds 6 = 204 milliseconds 14 = 15 seconds 7 = 240 milliseconds 15 = 24 seconds Location Range: 54279-54292 ($D407-$D414) Voice 2 and Voice 3 Controls The various control registers for these two voices correspond almost exactly to those of voice 1. The one exception is that the sync and ring-modulation bits of voice 2 operate on Oscillators 1 and 2, while the same bits of the Control Register for voice 3 uses Oscillators 2 and 3. 54279 $D407 FRELO2 Voice 2 Frequency Control (low byte) 54280 $D408 FREHI2 Voice 2 Frequency Control (high byte) 54281 $D409 PWLO2 Voice 2 Pulse Waveform Width (low byte) 54282 $D40A PWHI2 Voice 2 Pulse Waveform Width (high nybble) 54283 $D40B VCREG2 Voice 2 Control Register Bit 0: Gate Bit: 1=Start attack/decay/sustain, 0=Start release Bit 1: Sync Bit: 1=Synchronize oscillator with Oscillator 1 frequency Bit 2: Ring Modulation: 1=Ring modulate Oscillators 2 and 1 Bit 3: Test Bit: 1=Disable Oscillator 2 Bit 4: Select triangle waveform Bit 5: Select sawtooth waveform Bit 6: Select pulse waveform Bit 7: Select noise waveform 54284 $D40C ATDCY2 Voice 2 Attack/Decay Register Bits 0-3: Select decay cycle duration (0-15) Bits 4-7: Select attack cycle duration (0-15) 54285 $D40D SUREL2 Voice 2 Sustain/Release Control Register Bits 0-3: Select release cycle duration (0-15) Bits 4-7: Select sustain volume level (0-15) 54286 $D40E FRELO3 Voice 3 Frequency Control (low byte) 54287 $D40F FREHI3 Voice 3 Frequency Control (high byte) 54288 $D410 PWLO3 Voice 3 Pulse Waveform Width (low byte) 54289 $D411 PWHI3 Voice 3 Pulse Waveform Width (high nybble) 54290 $D412 VCREG3 Voice 3 Control Register Bit 0: Gate Bit: 1=Start attack/decay/sustain, 0=Start release Bit 1: Sync Bit: 1=Synchronize oscillator with Oscillator 2 frequency Bit 2: Ring Modulation: 1=Ring modulate Oscillators 3 and 2 Bit 3: Test Bit: 1=Disable Oscillator 3 Bit 4: Select triangle waveform Bit 5: Select sawtooth waveform Bit 6: Select pulse waveform Bit 7: Select noise waveform 54291 $D413 ATDCY3 Voice 3 Attack/Decay Register Bits 0-3: Select decay cycle duration (0-15) Bits 4-7: Select attack cycle duration (0-15) 54292 $D414 SUREL3 Voice 3 Sustain/Release Control Register Bits 0-3: Select release cycle duration (0-15) Bits 4-7: Select sustain volume level (0-15) Location Range: 54293-54296 ($D415-$D418) Filter Controls In addition to the controls detailed above for each voice, the SID chip also provides a filtering capability which allows you to attenuate (make quieter) certain ranges of frequencies. Any one or all three voices can be filtered, and there is even a provision for filtering an external signal that is input through pin 5 of the monitor jack. A low-pass filter is available, which suppresses the volume of those frequency components that are above a designated cutoff level. The high-pass filter reduces the volume of frequency components that are below a certain level. The band-pass filter reduces the volume of frequency components on both sides of the chosen frequency, thereby enhancing that frequency. Finally, the high-pass and low-pass filters can be combined to form a notch reject filter, which reduces the folume of the frequency components nearest the selected frequency. These various filters can dramatically change the quality of the sound produced. The first two registers are used to select the filter cutoff frequency. This is the frequency above or below which any sounds will be made quieter. The further away from this level any frequency components are, the more their output volume will be suppresed (high- and low-pass filters reduce the volume of those components by 12 dB per octave away from the center frequency, while the band-pass filter attenuates them by 6 dB per octave). The cutoff frequency has an 11-bit range (which corresponds to the numbers 0 to 2047). This is made up of a high-byte and three low bits. Therefore, to compute the frequency represented by the value in these registers, you must multiply the value in the high byte by 8, and add the value of the low three bits. The range of cutoff freqnencies represented by these 2048 values stretches from 30 Hz to about 12,000 Hz. The exact frequency may be calculated with the formula: FREQUENCY=(REGISTER VALUE*5.8)+30Hz An additional element in filtering is the resonance control. This allows you to peak the volume of the frequency elements nearest the cutoff frequency. 54293 $D415 CUTLO Bits 0-2: Low portion of filter cutoff frequency Bits 5-7: Unused 54294 $D416 CUTHI Filter Cutoff Frequency (high byte) 54295 $D417 RESON Filter Resonance Control Register Bit 0: Filter the output of voice 1? 1=yes Bit 1: Filter the output of voice 2? 1=yes Bit 2: Filter the output of voice 3? 1=yes Bit 3: Filter the output from the external input? 1=yes Bits 4-7: Select filter resonance 0-15 Bits 0-3 are used to control which of the voices will be altered by the filters. If one of these bits is set to 1, the corresponding voice will be processed through the filter, and its harmonic content will be changed accordingly. If the bit is set to 0, the voice will pass directly to the audio output. Note that there is also a provision for processing an external audio signal which is brought through pin 5 of the Audio/Video Port. Bits 4-7 control the resonance of the filter. By placing a number from 0 to 15 in these four bits, you may peak the volume of those frequencies nearest the cutoff. This creates an even sharper filtering effect. A setting of 0 causes no resonance, while a setting of 15 gives maximum resonance. 54296 $D418 SIGVOL Volume and Filter Select Register Bits 0-3: Select output volume (0-15) Bit 4: Select low-pass filter, 1=low-pass on Bit 5: Select band-pass filter, 1=band-pass on Bit 6: Select high-pass filter, 1=high-pass on Bit 7: Disconnect output of voice 4, 1=voice 3 off Bits 0-3 control the volume of all outputs. The possible volume levels range from 0 (no volume) to 15 (maximum volume). Some level of volume must be set here before any sound can be heard. Bits 4-6 control the selection of the low-pass, band-pass, or high-pass filter. A 1 in any of these bits turns the corresponding filter on. These filters can be combined, although only one cutoff frequency can be chosen. In order for the filter to have any effect, at least one of the voices must be routed through it using the Filter Resonance Control Register at 54295 ($D417). When Bit 7 is set to 1, it disconnects the output of voice 3. This allows you to use the output of the oscillator for modulating the frequency of the other voices, or for generating random number, without any undesired audio output. Location Range: 54297-54298 ($D419-$D41A) Game Paddle Inputs These registers allow you to read the game paddles that plug into joystick Controller Ports 1 and 2. Each paddle uses a variable resistor (also known as a potentiometer or pot), whose resistance is controlled by turning a knob. The varying resistance is used to vary the voltage to two pins of the SID chip between 0 and +5 volts. Analog-to-digital (A/D) converters in the chip interpret these voltage levels as binary values and store the values in these registers. These registers return a number from 0 (minumum resistance) to 255 (maximum resistance) for each paddle in either of the ports, depending on the position of the paddle knob. Since these registers will read the paddle values for only one controller port, there is a switching mechanism which allows you to select which of the two ports to read. By writing a bit-pair of 01 (bit value of 64) to the last two bits of CIA #1 Data Port A (56320, $DC00), you select the paddles on joystick Controller Port 1. By writing a bit-pair of 10 (bit value of 128), you select the paddles on Controller Port 2. If you look at the description of Data Port A (56320, $DC00), however, you will notice that it is also used in the keyboard scanning process. By writing to this port, you determine which keyboard column will be read. Since the IRQ interrupt keyboard scan routine and the routine that checks for the STOP key are putting values into this location 60 times per second, you cannot reliable select the pair of paddles you wish to read from BASIC without first turning off the keyboard IRQ. This can be done with a POKE 56333,127. You can then read the paddles with the statements A=PEEK(54297) and B=PEEK(54298). The IRQ can be restored after a paddle read with a POKE 56333,129. It may, however, be easier and more accurate in the long run to use a machine language paddle read subroutine such as that presented on page 347 of the Commodore 64 Programmer's Reference Guide. The paddle fire buttons are read as Bits 2 and 3 of the Data Ports A (56320, $DC00) and B (56321, $DC01). On Port A, if Bit 2 is set to 0, button 1 is pushed, and if Bit 3 is set to 0, button 2 is pushed. On Port B, if Bit 2 is set to 0, button 3 is pushed, and if Bit 3 is set to 0, button 4 is pushed. The BASIC statements to test these buttons, thereore, are: PB(1)=(PEEK(56321)AND4)/4 PB(2)=(PEEK(56321)AND8)/8 PB(3)=(PEEK(56320)AND4)/4 PB(4)=(PEEK(56320)AND8)/8 If a 0 is returned by the PEEK statement, the button is pushed, and if a 1 is returned, it is not. 54297 $D419 POTX Read Game Paddle 1 (or 3) Position 54298 $D41A POTY Read Game Paddle 2 (or 4) Position 54299 $D41B RANDOM Read Oscillator 3/Random Number Generator This register lets you read the upper eight bits of the waveform output of Oscillator 3. The kinds of numbers generated by this output depend on the type of waveform selected. If the sawtooth waveform is chosen, the output read by this register will be a series of numbers which start at 0 and increase by 1 to a maximum of 255, at which time they start over at 0. When the triangle waveform is chosen, they increase from 0 to 255, at which time they decrease to 0 again. The rate at which these numbers change is determined by the frequency of Oscillator 3. If the pulse waveform is selected, the output here will be either 255 or 0. Finally, selecting the noise waveform will produce a random series of numbers between 0 and 255. This allows you to use the register as a random number generator for games. There are many other uses for reading Oscillator 3, however, particularly for modulation of the other voices through machine language software. For example, the output of this register could be added to the frequency of another voice. If the triangle waveform were selected for this purpose, it would cause the frequency of the other voice to rise and fall, at the frequency of Oscillator 3 (perhaps for vibrato effects). This output can also be combined with the Filter Frequency or Pulse Width Registers to vary the values in these registers quickly over a short period of time. Normally, when using Oscillator 3 for modulation, the audio output of voice 3 should be turned off by setting Bit 7 of the Volume and Filter Select Register at 54296 ($d418) to 1. It is not necessary to gate Bit 0 of Control Register 3 to use the oscillator, however, as its output is not affected by the ADSR envelope cycle. 54300 $D41C ENV3 Envelope Generator 3 Output This register allows you to read the output of the voice 3 Envelope generator, in much the same way that the preceding register lets you read the output of Oscillator 3. This output can also be added to another oscillator's Frequency Control Registers, Pulse Width Registers, or the Filter Frequency Control Register. In order to produce any output from this register, however, the gate bit in Control Register 3 must be set to 1. Just as in the production of sound, setting the gate bit to 1 starts the attack/decay/sustain cycle, and setting it back to 0 starts the release cycle. Location Range: 54301-54303 ($D41D-$D41F) Not Connected The SID chip has been provided with enough addresses for 32 different registers, but as it has only 29, the remaining three addresses are not used. Reading them will always return a value of 255 ($FF), and writing to them will have no effect. Location Range: 54304-55295 ($D420-$D7FF) SID Register Images Since the SID chip requires enough addressing lines for only 32 locations (the minimum possible for its 29 registers), none of the higher bits are decoded when addressing the 1K area that has been assigned to it. The result is that every 32-byte area in this 1K block is a mirror of every other. For the sake of clarity in your programs, it is advisable not to use these addresses at all. 55296-56319 $D800-$DBFF Color RAM The normal Commodore 64 text graphics system uses a screen RAM area to keep track of the character shapes that are to be displayed. But since each character can be displayed in any of 16 foreground colors, there must also be a parallel area which keeps track of the foreground color. This 1024-byte area is used for that purpose (actually, since there are only 1000 screen positions, only 1000 byte actually affect screen color). These 1000 bytes each control the foreground color of one character, with the first byte controlling the foreground color of the character in the upper- left corner, and subsequent bytes controlling the characters to the right and below that character. Because only four bits are needed to represent the 16 colors available, only the low four bits of each Color RAM location are connected (this is why they are sometimes referred to as Color RAM Nybbles). Writing to the high bits will not affect them, and these four bits will usually return a random value when read (a small number of 64s return a constant value). Therefore, in order to read Color RAM correctly, you must mask out the top bits by using the logical AND function. In BASIC, you can read the first byte of Color RAM with the statement CR=PEEK(55296)AND15. This will always return a color value between 0 and 15. These color values correspond to the following colors: 0 = BLACK 1 = WHITE 2 = RED 3 = CYAN (LIGHT BLUE-GREEN) 4 = PURPLE 5 = GREEN 6 = BLUE 7 = YELLOW 8 = ORANGE 9 = BROWN 10 = LIGHT RED 11 = DARK GRAY 12 = MEDIUM GRAY 13 = LIGHT GREEN 14 = LIGHT BLUE 15 = LIGHT GRAY Color mapping affords a convenient method of changing the color of the text display without changing the letters. By POKEing the appropriate section of Color RAM, you can change the color of a whole section of text on the screen without affecting the content of the text. You can even use this method to make letters disappear by changing their foreground colors to match the background (or by changing the background to match the foreground), and later make them reappear by changing them back, or by changing the background to a contrasting color. An interesting example program which changes Color RAM quickly in BASIC can be found under the entry for 648 ($288). A change in the Operating System causes newer 64s to set all of the Color RAM locations to the same value as the current background color whenever the screen is cleared. Therefore, POKEing character codes to the Screen RAM area will not appear to have any effect, because the letters will be the same color as the background. This can easily be turned to your advantage, however, because it means that all you have to do to set all of Color RAM to a particular value is to set the background color to that value (using the register at 53281 ($D021)), clear the screen, and return the background color in the desired value. The various garphics modes use this area differently than does the regular text mode. In high-resolution bitmap mode, this area is not used at all, but in multicolor bitmap mode it is used to determine the color of the 11 bit-pair for a given 8 by 8 dot area. In multicolor text mode, only the lowest three bits are used, so only colors 0-7 may be selected. The fourth bit is used to determine whether a character will be displayed in regular text or multicolor text. Characters with a color value over 7 are displayed as multicolor characters, with the color of the 11 bit-pair determined by the color value minus 8. Characters with a color value under 8 are displayed normally. It should be noted that unlike the Screen RAM area, which can be moved to any RAM location, the Color RAM area is fixed, and will function normally regardless of where screen memory is located. 56320-56335 $DC00-$DC0F Complex Interface Adapter (CIA) #1 Registers Locations 56320-56335 ($DC00-$DC0F) are used to communicate with the Complex Interface Adapter chip #1 (CIA #1). This chip is a successor to the earlier VIA and PIA devices used on the VIC-20 and PET. This chip functions the same way as the VIA and PIA: It allows the 6510 microprocessor to communicate with peripheral input and output devices. The specific devices that CIA #1 reads data from and sends data to are the joystick controllers, the paddle fire buttons, and the keyboard. In addition to its two data ports, CIA #1 has two timers, each of which can count an interval from a millionth of a second to a fifteenth of a second. Or the timers can be hooked together to count much longer intervals. CIA #1 has an interrupt line which is connected to the 6510 IRQ line. These two timers can be used to generate interrupts at specified intervals (such as the 1/60 second interrupt used for keyboard scanning, or the more complexly timed interrupts that drive the tape read and write routines). As you will see below, the CIA chip has a host of other features to aid in Input/Output functions. Location Range: 56320-56321 ($DC00-$DC01) CIA #1 Data Ports A and B These registers are where the actual communication with outside devices takes place. Bits of data written to these registers can be sent to external devices, while bits of data that those devices send can be read here. The keyboard is so necessary to the computer's operation that you may have a hard time thinking of it as a peripheral device. Nonetheless, it cannot be directly read by the 6510 microprocessor. Instead, the keys are connected in a matrix of eight rows by eight columns to CIA #1 Ports A and B. The layout of this matrix is shown below. WRITE TO PORT A READ PORT B (56321, $DC01) 56320/$DC00 Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 Bit 7 STOP Q C= SPACE 2 CTRL <- 1 Bit 6 / ^ = RSHIFT HOME ; * LIRA Bit 5 , @ : . - L P + Bit 4 N O K M 0 J I 9 Bit 3 V U H B 8 G Y 7 Bit 2 X T F C 6 D R 5 Bit 1 LSHIFT E S Z 4 A W 3 Bit 0 CRSR DN F5 F3 F1 F7 CRSR RT RETURN DELETE As you can see, there are two keys which do not appear in the matrix. The SHIFT LOCK key is not read as a separate key, but rather is a mechanical device which holds the left SHIFT key switch in a closed position. The RESTORE key is not read like the other keys either. It is directly connected to the NMI interrupt line of the 6510 microprocessor, and causes an NMI interrupt to occur whenever it is pressed (not just when it is pressed with the STOP key). In order to read the individual keys in the matrix, you must first set Port A for all outputs (255, $FF), and Port B for all inputs (0), using the Data Direction Registers. Note that this is the default condition. Next, you must write a 0 in the bit of Data Port A that corresponds to the column that you wish to read, and a 1 to the bits that correspond to columns you wish to ignore. You will then be able to read Data Port B to see which keys in that column are being pushed. A 0 in any bit position signifies that the key in the corresponding row of the selected column is being pressed, while a 1 indicates that the key is not being pressed. A value of 255 ($FF) means that no keys in that column are being pressed. Fortunately for us all, an interrupt routine causes the keyboard to be read, and the results are made available to the Operating System automatically every 1/60 second. And even when the normal interrupt routine cannot be used, you can use the Kernal SCNKEY routine at 65439 ($FF9F) to read the keyboard. These same data ports are also used to read the joystick controllers. Although common sense might lead you to believe that you could read the joystick that is plugged into the port marked Controller Port 1 from Data Port A, and the second joystick from Data Port B, there is nothing common about the Commodore 64. Controller Port 1 is read from Data Port B, and Controller Port 2 is read from CIA #1 Data Port A. Joysticks consist of five switches, one each for up, down, right, and left directions, and another for the fire button. The switches are read like the key switches--if the switch is pressed, the corresponding bit will read 0, and if it is not pressed, the bit will be set to 1. From BASIC, you can PEEK the ports and use the AND and NOT operators to mask the unused bits and inverse the logic for easier comprehension. For example, to read the joystick in Controller Port 1, you could use the statement: S1=NOT PEEK(56321)AND15 The meaning of the possible numbers returned are: 0 = none pressed 1 = up 2 = down 4 = left 5 = up left 6 = down left 8 = right 9 = up right 10 = down right The same technique can be used for joystick 2, by substituting 56320 as the number to PEEK. By the way, the 3 and 7 aren't listed because they represent impossible combinations like up-down. To read the fire buttons, you can PEEK the appropriate port and use the AND operator to mask all but bit 4: T1=(PEEK(56321)AND16)/16 The above will return a 0 if the button is pressed, and a 1 if it is not. Substitute location 56320 as the location to PEEK for Trigger Button 2. Since CIA #1 Data Port B is used for reading the keyboard as well as joystick 1, some confusion can result. The routine that checks the keyboard has no way of telling whether a particular bit was set to 0 by a keypress or one of the joystick switches. For example, if you plug the joystick into Controller Port 1 and push the stick to the right, the routine will interpret this as the 2 key being pressed, because both set the same bit to 0. Likewise, when you read the joystick, it will register as being pushed to the right if the 2 key is being pressed. The problem of mistaking the keyboard for the joystick can be solved by turning off the keyscan momentarily when reading the stick with a POKE 56333, 127:POKE 56320,255, and restoring it after the read with a POKE 56333,129. Sometimes you can use the simpler solution of clearing the keyboard buffer after reading the joystick, with a POKE 198,0. The problem of mistaking the joystick for a keypress is much more difficult--there is no real way to turn off the joystick. Many commercially available games just use Controller Port 2 to avoid the conflict. So, if you can't beat them, sit back and press your joystick to the left in order to slow down a program listing (the keyscan routine thinks that it is the CTRL key). As if all of the above were not enough, Port A is also used to control which set of paddles is read by the SID chip, and to read the paddle fire buttons. Since there are two paddles per joystick Controller Port, and only two SID registers for reading paddle positions, there has to be a method for switching the paddle read from joystick Port 1 to joystick Port 2. When Bit 7 of Port A is set to 1 and Bit 6 is cleared to 0, the SID registers will read the paddles on Port 1. When Bit 7 is set to 0 and Bit 6 is set to 1, the paddles on Port 2 are read by the SID chip registers. Note that this also conflicts with the keyscan routine, which is constantly writing different values to CIA #1 Data Port A in order to select the keyboard column to read (most of the time, the value for the last column is written to this port, which coincides with the selection of paddles on joystick Port 1). Therefore, in order to get an accurate reading, you must turn off the keyscan IRQ and select which joystick port you want to read. See POTX at 54297 ($D419), which is the SID register where the paddles are read, for the exact technique. Although the SID chip is used to read the paddle settings, the fire buttons are read at CIA #1 Data Ports A and B. The fire buttons for the paddles plugged into Controller Port 1 are read at Data Port B (56321, $DC01), while those for the paddles plugged into Controller Port 2 are read from Data Port A (56320, $DC00). The fire buttons are read at Bit 2 and Bit 3 of each port (the same as the joystick left and joystick right switches), and as usual, the bit will read 0 if the corresponding button is pushed, and 1 if it is not. Although only two of the rout paddle values can be read at any one time, you can always read all four paddle buttons. See the game paddle input description at 54297 ($D419) for the BASIC statements used to read these buttons. Finally, Data Port B can also be used as an output by either Timer A or B. It is possible to set a mode in which the timers do not cause an interrupt when they run down (see the descriptions of Control Registers A and B at 56334-5 ($DC0E-F)). Instead, they cause the output on Bit 6 or 7 of Data Port B to change. Timer A can be set either to pulse the output of Bit 6 for one machine cycle, or to toggle that bit from 1 to 0 or 0 to 1. Timer B can use Bit 7 of this register for the same purpose. 56320 $DC00 CIAPRA Data Port Register A Bit 0: Select to read keyboard column 0 Read joystick 2 up direction Bit 1: Select to read keyboard column 1 Read joystick 2 down direction Bit 2: Select to read keyboard column 2 Read joystick 2 left direction Read paddle 1 fire button Bit 3: Select to read keyboard column 3 Read joystick 2 right direction Read paddle 2 fire button Bit 4: Select to read keyboard column 4 Read joystick 2 fire button Bit 5: Select to read keyboard column 5 Bit 6: Select to read keyboard column 6 Select to read paddles on Port A or B Bit 7: Select to read keyboard column 7 Select to read paddles on Port A or B 56321 $DC01 CIAPRB Data Port Register B Bit 0: Read keyboard row 0 Read joystick 1 up direction Bit 1: Read keyboard row 1 Read joystick 1 down direction Bit 2: Read keyboard row 2 Read joystick 1 left direction Read paddle 1 fire button Bit 3: Read keyboard row 3 Read joystick 1 right direction Read paddle 2 fire button Bit 4: Read keyboard row 4 Read joystick 1 fire button Bit 5: Read keyboard row 5 Bit 6: Read keyboard row 6 Toggle or pulse data output for Timer A Bit 7: Read keyboard row 7 Toggle or pulse data output for Timer B Location Range: 56322-56323 ($DC02-$DC03) CIA #1 Data Direction Registers A and B These Data Direction Registers control the direction of data flow over Data Ports A and B. Each bit controls the direction of the data on the corresponding bit of the port. If teh bit of the Direction Register is set to a 1, the corresponding Data Port bit will be used for data output. If the bit is set to a 0, the corresponding Data Port bit will be used for data input. For example, Bit 7 of Data Direction Register A controls Bit 7 of Data Port A, and if that direction bit is set to 0, Bit 7 of Data Port A will be used for data input. If the direction bit is set to 1, however, data Bit 7 on Port A will be used for data output. The default setting for Data Direction Register A is 255 (all outputs), and for Data Direction Register B it is 0 (all inputs). This corresponds to the setting used when reading the keyboard (the keyboard column number is written to Data Port A, and the row number is then read in Data Port B). 56322 $DC02 CIDDRA Data Direction Register A Bit 0: Select Bit 0 of Data Port A for input or output (0=input, 1=output) Bit 1: Select Bit 1 of Data Port A for input or output (0=input, 1=output) Bit 2: Select Bit 2 of Data Port A for input or output (0=input, 1=output) Bit 3: Select Bit 3 of Data Port A for input or output (0=input, 1=output) Bit 4: Select Bit 4 of Data Port A for input or output (0=input, 1=output) Bit 5: Select Bit 5 of Data Port A for input or output (0=input, 1=output) Bit 6: Select Bit 6 of Data Port A for input or output (0=input, 1=output) Bit 7: Select Bit 7 of Data Port A for input or output (0=input, 1=output) 56323 $DC03 CIDDRB Data Direction Register B Bit 0: Select Bit 0 of Data Port B for input or output (0=input, 1=output) Bit 1: Select Bit 1 of Data Port B for input or output (0=input, 1=output) Bit 2: Select Bit 2 of Data Port B for input or output (0=input, 1=output) Bit 3: Select Bit 3 of Data Port B for input or output (0=input, 1=output) Bit 4: Select Bit 4 of Data Port B for input or output (0=input, 1=output) Bit 5: Select Bit 5 of Data Port B for input or output (0=input, 1=output) Bit 6: Select Bit 6 of Data Port B for input or output (0=input, 1=output) Bit 7: Select Bit 7 of Data Port B for input or output (0=input, 1=output) Location Range: 56324-56327 ($DC04-$DC07) Timers A and B Low and High Bytes These four timer registers (two for each timer) have different functions depending on whether you are reading from them or writing to them. When you read from these registers, you get the present value of the Timer Counter (which counts down from its initial value to 0). When you write data to these registers, it is stored in the Timer Latch, and from there it can be used to load the Timer Counter using the Force Load bit of Control Register A or B (see 56334-5 ($DC0E-F) below). These interval timers can hold a 16-bit number from 0 to 65535, in normal 6510 low-byte, high-byte format (VALUE=LOW BYTE+256*HIGH BYTE). Once the Timer Counter is set to an initial value, and the timer is started, the timer will count down one number every microprocessor clock cycle. Since the clock speed of the 64 (using the American NTSC television standard) is 1,022,730 cycles per second, every count takes approximately a millionth of a second. The formula for calculating the amount of time it will take for the timer to count down from its latch value to 0 is: TIME=LATCH VALUE/CLOCK SPEED where LATCH VALUE is the value written to the low and high timer registers (LATCH VALUE=TIMER LOW+256*TIMER HIGH), and CLOCK SPEED is 1,022,370 cycles per second for American (NTSC) standard television monitors, or 985,250 for European (PAL) monitors. When Timer Counter A or B gets to 0, it will set Bit 0 or 1 in the Interrupt Control Register at 56333 ($DC0D). If the timer interrupt has been enabled (see 56333 ($DC0D)), an IRQ will take place, and the high bit of the Interrupt Control Register will be set to 1. Alternately, if the Port B output bit is set, the timer will write data to Bit 6 or 7 of Port B. After the timer gets to 0, it will reload the Timer Latch Value, and either stop or count down again, depending on whether it is in one-shot or continuous mode (determined by Bit 3 of the Control Register). Although usually a timer will be used to count the microprocessor cycles, Timer A can count either the microprocessor clock cycles or external pulses on the CTN line, which is connected to pin 4 of the User Port. Timer B is even more versatile. In addition to these two sources, Timer B can count the number of times that Timer A goes to 0. By setting Timer A to count the microprocessor clock, and setting Timer B to count the number of times that Timer A zeros, you effectively link the two timers into one 32-bit timer that can count up to 70 minutes with accuracy within 1/15 second. In the 64, CIA #1 Timer A is used to generate the interrupt which drives the routine for reading the keyboard and updating the software clock. Both Timers A and B are also used for the timing of the routines that read and write tape data. Normally, Timer A is set for continuous operation, and latched with a value of 149 in the low byte and 66 in the high byte, for a total Latch Value of 17045. This means that it is set to count to 0 every 17045/1022730 seconds, or approximately 1/60 second. For tape reads and writes, the tape routines take over the IRQ vectors. Even though the tape write routines use the on-chip I/O port at location 1 for the actual data output to the cassette, reading and writing to the cassette uses both CIA #1 Timer A and Timer B for timing the I/O routines. 56324 $DC04 TIMALO Timer A (low byte) 56325 $DC05 TIMAHI Timer A (high byte) 56326 $DC06 TIMBLO Timer B (low byte) 56327 $DC07 TIMBHI Timer B (high byte) Location Range: 56328-56331 ($DC08-$DC0B) Time of Day Clock (TOD) In addition to the two general-purpose timers, the 6526 CIA chip has a special-purpose Time of Day Clock, which keeps time in a format that humans can understand a little more easily than microseconds. This Time of Day Clock even has an alarm, which can cause an interrupt at a specific time. It is organized in four registers, one each for hours, minutes, seconds, and tenths of seconds. Each register reads out in Binary Coded Decimal (BCD) format, for easier conversion to ASCII digits. A BCD byte is divided into two nybbles, each of which represents a single digit in base 10. Even though a four-bit nybble can hold a number from 0 to 15, only the base 10 digits of 0-9 are used. Therefore, 10 0'clock would be represented by a byte in the hours register with the nybbles 0001 and 0000, which stand for the digits 1 and 0. The binary value of this byte would be 16 (16 times the high nybble plus the low nybble). Each of the other registers operates in the same manner. In addition, Bit 7 of the hours register is used as an AM/PM flag. If that bit is set to 1, it indicates PM, and if it is set to 0, the time is AM. The Time of Day Clock Registers can be used for two purposes, depending on whether you are reading them or writing to them. If you are reading them, you will always be reading the time. There is a latching feature associated with reading the hours register in order to solve the problem of the time changing while you are reading the registers. For example, if you were reading the hours register just as the time was changing from 10:59 to 11:00, it is possible that you would read the 10 in the hours register, and by the time you read the minutes register it would have changed from 59 to 00. Therefore, you would read 10:00 instead of either 10:59 or 11:00. To prevent this kind of mistake, the Time of Day Clock Registers stop updating as soon as you read the hours register, and do not start again until you read the tenths of seconds register. Of course, the clock continues to keep time internally even though it does not update the registers. If you want to read only minutes, or seconds or tenths of seconds, there is no problem, and no latching will occur. But anytime you read hours, you must follow it by reading tenths of seconds, even if you don't care about them, or else the registers will not continue to update. Writing to these registers either sets the time or the alarm, depending on the setting of Bit 7 of Control Register B (56335, $DC0F). If that bit is set to 1, writing to the Time of Day registers sets the alarm. If the bit is set to 0, writing to the Time of Day registers sets the Time of Day clock. In either case, as with reading the registers, there is a latch function. This function stops the clock from updating when you write to the hours register. The clock will not start again until you write to the tenths of seconds registers. The only apparent use of the Time of Day Clock by the 64's Operating System is in the BASIC RND statement. There, the seconds and tenths of seconds registers are read and their values used as part of the seed value for the RND(0) command. Nonetheless, this clock can be an invaluable resource for the 64 user. It will keep time more accurately than the software clock maintained at locations 60-162 ($A0-$A2) by the Timer A interrupt routine. And unlike that software clock, the Time of Day Clock will not be disturbed when I/O operations disrupt the Timer A IRQ, or when the IRQ vector is diverted elsewhere. Not even a cold start RESET will disrupt the time. For game timers, just set the time for 00:00:00:0 and it will keep track of elapsed time in hours, minutes, seconds and tenths of seconds format. The following digital clock program, written in BASIC, will demonstrate the use of these timers: 10 PRINT CHR$(147):GOSUB 200 20 H=PEEK(56331):POKE 1238,(H AND 16)/16+48:POKE 1239,(H AND 15)+48 30 M=PEEK(56330):POKE 1241,(M AND 240)/16+48:POKE 1242,(M AND 15)+48 40 S=PEEK(56329):POKE 1244,(S AND 240)/16+48:POKE 1245,(S AND 15)+48 50 T=PEEK(56328)AND15:POKE 1247,T+48:GOTO 20 200 INPUT"WHAT IS THE HOUR";H$:IF H$="" THEN 200 210 H=0:IF LEN(H$)>1 THEN H=16 220 HH=VAL(RIGHT$(H$,1)):H=H+HH:POKE56331,H 230 INPUT "WHAT IS THE MINUTE";M$:IF M$=""THEN 200 240 M=0:IF LEN(M$)>1 THEN M=16*VAL(LEFT$(M$,1)) 250 MM=VAL(RIGHT$(M$,1)):M=M+MM:POKE56330,M 260 INPUT "WHAT IS THE SECOND";S$:IF S$=""THEN 200 270 S=0:IF LEN(S$)>1 THEN S=16*VAL(LEFT$(S$,1)) 280 SS=VAL(RIGHT$(S$,1)):S=S+SS:POKE56329,S:POKE56328,0 290 POKE 53281,1:PRINT CHR$(147):POKE 53281,6 300 POKE 1240,58:POKE 1243,58:POKE 1246,58:GOTO 20 56328 $DC08 TODTEN Time of Day Clock Tenths of Seconds Bits 0-3: Time of Day tenths of second digit (BCD) Bits 4-7: Unused 56329 $DC09 TODSEC Time of Day Clock Seconds Bits 0-3: Second digit of Time of Day seconds (BCD) Bits 4-6: First digit of Time of Day seconds (BCD) Bit 7: Unused 56330 $DC0A TODMIN Time of Day Clock Minutes Bits 0-3: Second digit of Time of Day minutes (BCD) Bits 4-6: First digit of Time of Day minutes (BCD) Bit 7: Unused 56331 $DC0B TODHRS Time of Day Clock Hours Bits 0-3: Second digit of Time of Day hours (BCD) Bit 4: First digit of Time of Day hours (BCD) Bits 5-6: Unused Bit 7: AM/PM Flag (1=PM, 0=AM) 56332 $DC0C CIASDR Serial Data Port The CIA chip has an on-chip serial port, which allows you to send or receive a byte of data one bit at a time, with the most significant bit (Bit 7) being transferred first. Control Register A at 56334 ($DC0E) allows you to choose input or output modes. In input mode, a bit of data is read from the SP line (pin 5 of the User Port) whenever a signal on the CNT line (pin 4) appears to let you know that it is time for a read. After eight bits are received this way, the data is placed in the Serial Port Register, and an interrupt is generated to let you know that the register should be read. In output mode, you write data to the Serial Port Register, and it is sent out over the SP line (pin 5 of the User Port), using Timer A for the baud rate generator. Whenever a byte of data is written to this register, transmission will start as long as Timer A is running and in continuous mode. Data is sent at half the Timer A rage, and an output will appear on the CNT line (pin 4 of the User Port) whenever a bit is sent. After all eight bits have been sent, an interrupt is generated to indicate that it is time to load the next byte to send into the Serial Register. The Serial Data Register is not used by the 64, which does all of its serial I/O through the regular data ports. 56333 $DC0D CIAICR Interrupt Control Register Bit 0: Read / did Timer A count down to 0? (1=yes) Write/ enable or disable Timer A interrupt (1=enable, 0=disable) Bit 1: Read / did Timer B count down to 0? (1=yes) Write/ enable or disable Timer B interrupt (1=enable, 0=disable) Bit 2: Read / did Time of Day Clock reach the alarm time? (1=yes) Write/ enable or disable TOD clock alarm interrupt (1=enable, 0=disable) Bit 3: Read / did the serial shift register finish a byte? (1=yes) Write/ enable or disable serial shift register interrupt (1=enable, 0=disable) Bit 4: Read / was a signal sent on the flag line? (1=yes) Write/ enable or disable FLAG line interrupt (1=enable, 0=disable) Bit 5: Not used Bit 6: Not used Bit 7: Read / did any CIA #1 source cause an interrupt? (1=yes) Write/ set or clear bits of this register (1=bits written with 1 will be set, 0=bits written with 1 will be cleared) This register is used to control the five interrupt sources on the 6526 CIA chip. These sources are Timer A, Timer B, the Time of Day Clock, the Serial Register, and the FLAG line. Timers A and B cause an interrupt when they count down to 0. The Time of Day Clock generates an interrupt when it reaches the ALARM time. The Serial Shift Register interrupts when it compiles eight bits of input or output. An external signal pulling the CIA hardware line called FLAG low will also cause an interrupt (on CIA #1, this FLAG line is connected to the Cassette Read line of the Cassette Port). Even if the condition for a particular interrupt is satisfied, the interrupt must still be enabled for an IRQ actually to occur. This is done by writing to the Interrupt Control Register. What happens when you write to this register depends on the way that you set Bit 7. If you set it to 0, any other bit that was written to with a 1 will be cleared, and the corresponding interrupt will be disabled. If you set Bit 7 to 1, any bit written to with a 1 will be set, and the corresponding interrupt will be enabled. In either case, the interrupt enable flags for those bits written to with a 0 will not be affected. For example, in order to disable all interrupts from BASIC, you could POKE 56333, 127. This sets Bit 7 to 0, which clears all of the other bits, since they are all written with 1's. Don't try this from BASIC immediate mode, as it will turn off Timer A which causes the IRQ for reading the keyboard, so that it will in effect turn off the keyboard. To turn on the Timer A interrupt, a program could POKE 56333,129. Bit 7 is set to 1 and so is Bit 0, so the interrupt which corresponds to Bit 0 (Timer A) is enabled. When you read this register, you can tell if any of the conditions for a CIA Interrupt were satisfied because the corresponding bit will be set to a 1. For example, if Timer A counts down to 0, Bit 0 of this register will be set to 1. If, in addition, the mask bit that corresponds to that interrupt source is set to 1, and an interrupt occurs, Bit 7 will also be set. This allows a multi-interrupt system to read one bit and see if the source of a particular interrupt was CIA #1. You should note, however, that reading this register clears it, so you should preserve its contents in RAM if you want to test more than one bit. 56334 $DC0E CIACRA Control Register A Bit 0: Start Timer A (1=start, 0=stop) Bit 1: Select Timer A output on Port B (1=Timer A output appears on Bit 6 of Port B) Bit 2: Port B output mode (1=toggle Bit 6, 0=pulse Bit 6 for one cycle) Bit 3: Timer A run mode (1=one-shot, 0=continuous) Bit 4: Force latched value to be loaded to Timer A counter (1=force load strobe) Bit 5: Timer A input mode (1=count microprocessor cycles, 0=count signals on CNT line at pin 4 of User Port) Bit 6: Serial Port (56332, $DC0C) mode (1=output, 0=input) Bit 7: Time of Day Clock frequency (1=50 Hz required on TOD pin, 0=60 Hz) Bits 0-3. This nybble controls Timer A. Bit 0 is set to 1 to start the timer counting down, and set to 0 to stop it. Bit 3 sets the timer for one-shot or continuous mode. In one-shot mode, the timer counts down to 0, sets the counter value back to the latch value, and then sets Bit 0 back to 0 to stop the timer. In continuous mode, it reloads the latch value and starts all over again. Bits 1 and 2 allow you to send a signal on Bit 6 of Data Port B when the timer counts. Setting Bit 1 to 1 forces this output (which overrides the Data Direction Register B Bit 6, and the normal Data Port B value). Bit 2 allows you to choose the form this output to Bit 6 of Data Port B will take. Setting Bit 2 to a value of 1 will cause Bit 6 to toggle to the opposite value when the timer runs down (a value of 1 will change to 0, and a value of 0 will change to 1). Setting Bit 2 to a value of 0 will cause a single pulse of a one machine-cycle duration (about a millionth of a second) to occur. Bit 4. This bit is used to load the Timer A counter with the value that was previously written to the Timer Low and High Byte Registers. Writing a 1 to this bit will force the load (although there is no data stored here, and the bit has no significance on a read). Bit 5. Bit 5 is used to control just what it is Timer A is counting. If this bit is set to 1, it counts the microprocessor machine cycles (which occur at the rate of 1,022,730 cycles per second). If the bit is set to 0, the timer counts pulses on the CNT line, which is connected to pin 4 of the User Port. This allows you to use the CIA as a frequency counter or an event counter, or to measure pulse width or delay times of external signals. Bit 6. Whether the Serial Port Register is currently inputting or outputting data (see the entry for that register at 56332 ($DC0C) for more information) is controlled by this bit. Bit 7. This bit allows you to select from software whether the Time of Day Clock will use a 50 Hz or 60 Hz signal on the TOD pin in order to keep accurate time (the 64 uses a 60 Hz signal on that pin). 56335 $DC0F CIACRB Control Register B Bit 0: Start Timer B (1=start, 0=stop) Bit 1: Select Timer B output on Port B (1=Timer B output appears on Bit 7 of Port B) Bit 2: Port B output mode (1=toggle Bit 7, 0=pulse Bit 7 for one cycle) Bit 3: Timer B run mode (1=one-shot, 0=continuous) Bit 4: Force latched value to be loaded to Timer B counter (1=force load strobe) Bits 5-6: Timer B input mode 00 = Timer B counts microprocessor cycles 01 = Count signals on CNT line at pin 4 of User Port 10 = Count each time that Timer A counts down to 0 11 = Count Timer A 0's when CNT pulses are also present Bit 7: Select Time of Day write (0=writing to TOD registers sets alarm, 1=writing to TOD registers sets clock) Bits 0-3. This nybble performs the same functions for Timer B that Bits 0-3 of Control Register A perform for Timer A, except that Timer B output on Data Port B appears at Bit 7, and not Bit 6. Bits 5 and 6. These two bits are used to select what Timer B counts. If both bits are set to 0, Timer B counts the microprocessor machine cycles (which occur at the rate of 1,022,730 cycles per second). If Bit 6 is set to 0 and Bit 5 is set to 1, Timer B counts pulses on the CNT line, which is connected to pin 4 of the User Port. If Bit 6 is set to 1 and Bit 5 is set to 0, Timer B counts Timer A underflow pulses, which is to say that it counts the number of times that Timer A counts down to 0. This is used to link the two numbers into one 32-bit timer that can count up to 70 minutes with accuracy to within 1/15 second. Finally, if both bits are set to 1, Timer B counts the number of times that Timer A counts down to 0 and there is a signal on the CNT line (pin 4 of the User Port). Bit 7. Bit 7 controls what happens when you write to the Time of Day registers. If this bit is set to 1, writing to the TOD registers sets the ALARM time. If this bit is cleared to 0, writing to the TOD registers sets the TOD clock. Location Range: 56336-56575 ($DC10-$DCFF) CIA #1 Register Images Since the CIA chip requires only enough addressing lines to handle 16 registers, none of the higher bits are decoded when addressing the 256-byte area that has been assigned to it. The result is that every 16-byte area in this 256-byte block is a mirror of every other. Even so, for the sake of clarity in your programs it is advisable to use the base address of the chip, and not use the higher addresses to communicate with the chip. 56576-56591 $DD00-$DD0F Complex Interface Adapter (CIA) #2 Registers Locations 56576-56591 ($DD00-$DD0F) are used to address the Complex Interface Adapter chip #2 (CIA #2). Since the chip itself is identical to CIA #1, which is addressed at 56320 ($DC00), the discussion here will be limited to the use which the 64 makes of this particular chip. For more general information on the chip registers, please see the corresponding entries for CIA #1. One of the significant differences between CIA chips #1 and #1 is the use to which Data Ports A and B are put. The peripheral input and output devices that CIA #2 controls are those on the Serial Bus (such as the 1541 Disk Drive and 1525 printer), the RS-232 device (which is used for telecommunications), and the User Port, an eight-bit parallel port that can be turned to whatever purpose the user desires. In addition, Data Port A has the important task of selecting the 16K bank ofmemory that will be used by the VIC-II chip for graphics. Another significant difference between CIA chips #1 and #2 is that the interrupt line of CIA #1 is wired to the 6510 IRQ line, while that of CIA #2 is wired to the NMI line. This means that interrupts from this chip cannot be masked by setting the Interrupt disable flag (SEI). They can be disabled from CIA's Mask Register, though. Be sure to use the NMI vector when setting up routines to be driven by interrupts generated by this chip. Location Range: 56576-56577 ($DD00-$DD01) CIA #2 Data Ports A and B These registers are where the communication with the Serial Bus, RS-232 device, and User Port take place. The Serial Bus is like the IEEE bus which is used by the PET, in that it allows more than one device to be connected to the port at a time, in a daisychain arrangement. Since each byte of data is sent one bit at a time, however, the Serial Bus is at least eight times slower than the IEEE. It is presently used to control the 1541 Disk Drive and 1525 printer, and other devices (such as printer interface for Centronics- type parallel pritners and stringy floppy wafer tape storage units) can be placed on this bus. Data Port A is used for communication with the Serial Bus. Bits 5 and 7 are used for Serial Bus Data Output and Input, respectively, and Bits 4 and 6 are used for the Serial Bus Clock Pulse Output and Input. Bit 3 of Data Port A is used to send the ATN signal on the Serial Bus. The 64 has built-in software to handle RS-232 communications through a modem or other device plugged in the RS-232/User Port. The RS-232 device uses Bit 2 of Data Port A for data output (it is the only line from Port A that is connected to the RS-232/User Port jack). It also makes heavy use of Port B, using Bit 7 for the Data Set Ready (DSR) signal, Bit 6 for the Clear to Send (CTS), Bit 4 for the Carrier Detect (DCD), Bit 3 for the Ring Indicator (RI), Bit 2 for Data Terminal Ready (DTR), Bit 1 for Request to Send (RTS), and Bit 0 for data input. See locations 659-660 ($293-$294) for more details on the RS-232 device. All of the data lines which the RS-232 device uses are also available to the user as part of the User Port. All of the Port B data lines, and Bit 2 of Port A, are brought out to the User Port connector on the back of the 64. These data bits are utilized in the normal way: The port connections are made to TTL-level input or output devices, and the direction of data is determined by the Data Direction Registers. In addition, the User Port has pins connected to the two CIA Serial Ports (whose eight-bit shift registers are well-suited for serial-to-parallel and parallel-to-serial conversion),and the two CNT lines which aid in the operation of the Serial Ports. The CNT lines can also be used in conjunction with the CIA Timers, and allow them to be used as frequency counters, event counters, interval timers, etc. The advanced features of the CIA chip make almost any type of interfacing application possible, and in the near future we will probably see many interesting applications for the User Port on the 64. A pin description of tthe User Port connector is provided below: User RS-232 Port CIA DB-25 Pin Line Pin Description 1 Ground 2 +5 Volts (100 milliamps maximum) 3 RESET (grounding this pin causes a cold start) 4 CNT1 CIA #1 Serial Port and Timer Counter 5 SP1 CIA #1 Serial Data Port 6 CNT2 CIA #2 Serial Port and Timer Counter 7 SP2 CIA #2 Serial Data Port 8 PC2 CIA #2 handshaking line 9 Connected to the ATN line of the Serial Bus 10 9 Volts AC (+ phase, 50 milliamps maximum) 11 9 volts AC (- phase, 50 milliamps maximum) 12 Ground A 1 Ground B FLAG2 CIA #2 handshaking line C PB0 3 Port B Bit 0--RS-232 Received Data (SIN) D PB1 4 Port B Bit 1--RS-232 Request to Send (RTS) E PB2 20 Port B Bit 2--RS-232 Data Terminal Ready (DTR) F PB3 22 Port B Bit 3--RS-232 Ring Indicator (RI) H PB4 8 Port B Bit 4--RS-232 Carrier Detect (DCD) J PB5 Port B Bit 5 K PB6 5 Port B Bit 6--RS-232 Clear to Send (CTS) L PB7 6 Port B Bit 7--RS-232 Data Set Ready (DSR) M PA2 2 Port A Bit 2--RS-232 Transmitted Data (Sout) N 7 Ground One of the handshaking lines on the above chart, PC2, was not covered in the discussion of CIA #1, because that line of CIA #1 is not connected to anything. The CIA #2 PC line is accessible from the User Port, however. This line will go low for one cycle following a read or write of Port B on CIA #2. This signal lets external devices know when data has been read or written. Bits 0 and 1 of CIA #2 Port A have an extremely important function. As mentioned in the section on the VIC-II chip (53248, $D000), the video chip can address only 16K of memory at a time, and all graphics data must be stored in that 16K block in order to be displayed. Within this area, sprite graphics data may be placed in any of 256 groups of 64 bytes each. Character data can be stored in any of eight 2K blocks. Text screen memory may be in any of 16 1K areas, and bitmap screen memory may be in either of two 8K sections. When you turn the power on, the VIC-II uses the bottom 16K of memory for graphics. Unfortunately, this block of memory is also used extensively for other important purposes. Though some means of eliminating these conflicts are discussed above, in many situations you will want to change from the default 16K bank at the low end of memory. Bits 0 and 1 select the current 16K bank for video memory from the four possible choices using the following bit patterns: 00 (bit value of 0) Bank 3 (49152-65535, $C000-$FFFF) 01 (bit value of 1) Bank 2 (32768-49151, $8000-$BFFF) 10 (bit value of 2) Bank 1 (16384-32767, $4000-$7FFF) 11 (bit value of 3) Bank 0 (0-16383, $0-$3FFF) The technique for making this change from BASIC is discussed below. But before we go ahead and start changing banks, let's briefly review the contents of these areas, and the considerations for using them for graphics. Block 0. This is normally used for system variables and BASIC program text. Locations 1024-2047 ($400-$7FF) are reserved for the default position of screen memory. There is an addition limitation on memory usage of this block, as the VIC-II sees the character generator ROM at 4096-8191 ($1000-$1FFF), making this portion of memory unavailable for other graphics data. Generally, there is little free space here for graphics display data. Locations 679-767 ($2A7- $2FF) are unused, and could hold one sprite shape (number 11) or data for 11 characters. The area from 820-1023 ($334-$3FF), which includes the cassette I/O buffer, is available for graphics memory, and is large enough to hold three sprite shapes (numbers 13, 14, and 15), or data for 25 characters (numbers 103-127). But getting enough memory for bitmap graphics requires that you either reserve memory after the end of BASIC text by lowering the end of BASIC pointer at 56 ($38), or raise the start of BASIC pointer at 44 ($2C). See the entries for these pointers for more details. Block 1. Block 1 is normally used for BASIC program storage. When using this bank, the VIC-II does not have access to the character generator ROM. Providing that you lower the top of memory so that BASIC programs do not interfere, this area is wide open for sprite shapes, character graphics, and bitmap graphics. The drawbacks to useing this bank are the unavailability of the character ROM and the limitation on BASIC program space (as little as 14K). The absence of the character ROM is a relatively minor nuisance, because you can always switch in the ROM and copy any or all of the characters to RAM (see the entries for location 1 and the alternate entry for 53248 ($D000), the Character ROM, for details). This block may be a good alternate choice to avoid potential conflicts with other applications that use higher memory. Block 2. The third block (Block 2) consists of 8K of RAM, half of which is seen by the VIC-II chip as character ROM, and the 8K BASIC interpreter ROM. The BASIC ROM area is available for graphics. This is possible because of the 64's special addressing. The VIC-II chip reads only from RAM, and thus sees the RAM underneath the BASIC ROM, even if the 6510 has ROM switched in. The 6510, on the other hand, always writes to RAM, even when dealing with memory it reads as ROM. Whatever is written to the RAM underlying the BASIC ROM is displayed normally by the VIC-II chip. This opens up an extra 8K are for sprites and character data under the BASIC ROM. You should keep in mind that while you can write to this area, you cannot read it from BASIC. This may not be a serious problem when it comes to character sets and sprite data, but it's more of a drawback if you want to use this RAM for screen memory. For example, the Operating System has to read the text screen to move the cursor properly, and if it reads the ROM value instead of the RAM screen data, it gets hopelessly confused, making it impossible to type in any commands. Likewise, you would not be able to read the high-resolution screen if it were placed here, without some machine language trickery. With locations 36863-40959 ousted by the character ROM, only 4K of true RAM remains for use as screen memory, not enough for a complete high-resolution screen. Therefore, this block is not recommended for use in bitmap mode if your program needs to check the screen. Otherwise, this is a good place for graphics memory, particularly if you need to emulate the screen configuration of the PET. Block 3. Normally Block 3 contains 4K of RAM that is completely unused by the system, 4K if I/O registers, and the 8K Operating System Kernal ROM. It is very convenient to use when you need a lot of memory space for both graphics and a BASIC program. Although the character ROM is not available, it can be copied to RAM. The area under the Kernal ROM can be used as explained above. One possible conflict that you should be aware of is that the current version of the DOS support program is written to reside at 52224 ($CC00). It would be safest to avoid using 52224-53247 for graphics if you plan to use DOS support. Changing banks. Once you have selected a bank of 16K to use, the procedure for making the change from BASIC is as follows: 1. Set the Data Direction Register if necessary. In order to use Bits 0 and 1 of Port A to change banks, these bits must be set as outputs in Data Direction Register A. Since this is the default condition on powering-up, this step normally will not be needed. 2. Select a bank. Banks 0-3 can be chosen by entering the following lines: POKE 56578,PEEK(56578) OR 3: REM SET FOR OUTPUT IF NOT ALREADY POKE 56576,(PEEK(56576) AND 252) OR (3-BANK): REM BANK IS BANK #, MUST BE 0-3 3. Set the VIC-II register for character memory. As explained at the entry for location 53272 ($D018), the formula for this is: POKE 53272,(PEEK(53272) AND 240) OR TK: REM TK IS 2 KBYTE OFFSET FROM BEGINNING OF BLOCK 4. Set the VIC-II register for display memory. As explained at the entry for location 53272 ($D018), the formula for this is: POKE 53272,(PEEK(53272) AND 15) OR K*16: REM K IS KBYTE OFFSET FROM BEGINNING OF BLOCK Since steps 3 and 4 operate on the same register, you could combine these steps and just POKE 53272,(16*K+TK). 5. Set the Operating System pointer for display memory at 648 ($288). Even though you have just told the VIC-II chip where to display memory for the screen, the Operating System does not yet know where to write its text characters. Let it know with this statement: POKE 648,AD/256: REM AD IS THE ACTUAL ADDRESS OF SCREEN MEMORY After you make this change, you must watch out for the STOP/RESTORE key combination. The BRK initialization changes the screen display default to location 1024 in Bank 0, but not the Operating System pointer at 648 ($288). As a result, what you are typing will not be displayed on the screen. The computer will lock up until you turn the power off and back on again. The simplest way to avoid this problem is to disable the RESTORE key entirely (see the entries for 792 ($318) and 808 ($328) for more information). Below is a sample program which switches to Bank 3. It includes a machine language transfer routine to move the ROM character set to RAM, and a short interrupt routine to correct the RESTORE key problem. After the switch is made, a loop isused to POKE characters into the new screen memory area. Next, the character data is slowly erased, to show that the character set is now in RAM. Then, a loop is used to read the locations of the character set, and write to the same locations. This demonstrates that the 6510 reads the Kernal ROM when you PEEK those locations, but POKEs to the RAM which is being displayed. Finally, the machine language move is used again to show how quickly the set is restored. 20 FOR I=1 TO 33:READ A:POKE 49152+I,A:NEXT: REM SET UP ML ROUTINE 30 GOSUB 200: REM ML COPY OF ROM CHARACTER SET TO RAM 40 POKE 56576,PEEK(56576) AND 252: REM STEP 1, ENABLE BANK 3 50 POKE 53272,44: REM STEPS 2-3, POINT VIC-II TO SCREEN AND CHARACTER MEMORY 60 REM SCREEN OFFSET IS 2*16, CHARACTER OFFSET IS 12 70 POKE 648,200: REM STEP 4, POINT OS TO SCREEN AT 51200 (200*256) 80 PRINT CHR$(147): REM CLEAR SCREEN 90 FOR I=53236 TO 53245:READ A:POKE I,A:NEXT: REM NEW INTERRUPT ROUTINE 100 POKE 53246,PEEK(792):POKE 53247,PEK(793): REM SAVE OLD NMI VECTOR 110 POKE 792,244:POKE 793,207: REM ROUTE THE INTERRUPT THROUGH THE NEW ROUTINE 120 FOR I=0 TO 255:POKE 51400+I,I:POKE 55496+I,1:NEXT 125 REM POKE CHARACTERS TO SCREEN 130 FOR J=1 TO 8:FOR I=61439+J TO I+2048 STEP 8 140 POKE I,0:NEXT I,J: REM ERASE CHARACTER SET 150 FOR I=61440 TO I+2048:POKE I,PEEK(I):NEXT: REM POKE ROM TO RAM 160 GOSUB 200:END: REM RESTORE CHARACTER SET 200 POKE 56334,PEEK(56334) AND 254: REM DISABLE INTERRUPTS 210 POKE 1,PEEK(1) AND 251:REM SWITCH CHARACTER ROM INTO 6510 MEMORY 220 SYS 49152: REM COPY ROM CHARACTER SET TO RAM AT 61440 230 POKE 1,PEEK(1) OR 4: REM SWITCH CHARACTER ROM OUT OF 6510 MEMORY 240 POKE 56334,PEEK(56334)OR 1: REM ENABLE INTERRUPTS 250 RETURN 300 REM DATA FOR ML PROGRAM TO COPY CHARACTER SET TO RAM 310 DATA169,0,133,251,133,253,169,208,133,252,169,240,133,254,162,16 320 DATA160,0,177,251,145,253,136,208,249,230,252,230,254,202,208,240,96 330 REM NEXT IS ML PROGRAM TO MAKE THE RESTORE KEY RESET OS POINTER TO SCREEN 340 DATA 72,169,4,141,136,02,104,108,254,207 See also the sample program showing how to configure your 64 like a PET at location 43 ($2B). 56576 $DD00 CI2PRA Data Port Register A Bits 0-1: Select the 16K VIC-II chip memory bank (11=bank 0, 00=bank 3) Bit 2: RS-232 data output (Sout)/Pin M of User Port Bit 3: Serial bus ATN signal output Bit 4: Serial bus clock pulse output Bit 5: Serial bus data output Bit 6: Serial bus clock pulse input Bit 7: Serial bus data input 56577 $DD01 CI2PRB Data Port B Bit 0: RS-232 data input (SIN)/ Pin C of User Port Bit 1: RS-232 request to send (RTS)/ Pin D of User Port Bit 2: RS-232 data terminal ready (DTR)/ Pin E of User Port Bit 3: RS-232 ring indicator (RI)/ Pin F of User Port Bit 4: RS-232 carrier detect (DCD)/ Pin H of User Port Bit 5: Pin J of User Port Bit 6: RS-232 clear to send (CTS)/ Pin K of User Port Toggle or pulse data output for Timer A Bit 7: RS-232 data set ready (DSR)/ Pin L of User Port Toggle or pulse data output for Timer B Location Range: 56578-56579 ($DD02-$DD03) CIA #2 Data Direction Registers A and B These Data Direction registers control the direction of data flow over Data Ports A and B. For more details on the operation of these registers, see the entry for the CIA #1 Data Direction Registers at 56322 ($DC02). The default setting for Data Direction Register A is 63 (all bits except 6 and 7 are outputs), and for Data Direction Register B the default setting is 0 (all inputs). Bits 1 and 2 of Port B are changed to output when the RS-232 device is opened. 56578 $DD02 C2DDRA Data Direction Register A Bit 0: Select Bit 0 of data Port A for input or output (0=input, 1=output) Bit 1: Select Bit 1 of data Port A for input or output (0=input, 1=output) Bit 2: Select Bit 2 of data Port A for input or output (0=input, 1=output) Bit 3: Select Bit 3 of data Port A for input or output (0=input, 1=output) Bit 4: Select Bit 4 of data Port A for input or output (0=input, 1=output) Bit 5: Select Bit 5 of data Port A for input or output (0=input, 1=output) Bit 6: Select Bit 6 of data Port A for input or output (0=input, 1=output) Bit 7: Select Bit 7 of data Port A for input or output (0=input, 1=output) 56579 $DD03 C2DDRB Data Direction Register B Bit 0: Select Bit 0 of data Port B for input or output (0=input, 1=output) Bit 1: Select Bit 1 of data Port B for input or output (0=input, 1=output) Bit 2: Select Bit 2 of data Port B for input or output (0=input, 1=output) Bit 3: Select Bit 3 of data Port B for input or output (0=input, 1=output) Bit 4: Select Bit 4 of data Port B for input or output (0=input, 1=output) Bit 5: Select Bit 5 of data Port B for input or output (0=input, 1=output) Bit 6: Select Bit 6 of data Port B for input or output (0=input, 1=output) Bit 7: Select Bit 7 of data Port B for input or output (0=input, 1=output) Location Range: 56580-56583 ($DD04-$DD07) Timer A and B Low and High Bytes These four timer registers are used to control Timers A and B. For details on the operation of these timers, see the entry for Location Range 56324-56327 ($DC04-$DC07). The 64 Operating System uses the CIA #2 Timers A and B mostly for timing RS-232 send and receive operations. Serial Bus timing uses CIA #1 Timer B. 56580 $DD04 TI2ALO Timer A (low byte) 56581 $DD05 TI2AHI Timer A (high byte) 56582 $DD06 TI2BLO Timer B (low byte) 56583 $DD07 TI2BHI Timer B (high byte) Location Range: 56584-56587 ($DD08-$DD0B) Time of Day Clock In addition to the two general purpose timers, the 6526 CIA chip has a special purpose Time of Day Clock, which keeps time in a format that humans can understand a little more easily than microseconds. For more information about this clock, see the entry for Location Range 56328-56331 ($DC08-$DC0B). The 64's Operating system does not make use of these registers. 56584 $DD08 TO2TEN Time of Day Clock Tenths of Seconds Bits 0-3: Time of Day tenths of second digit (BCD) Bits 4-7: Unused 56585 $DD09 TO2SEC Time of Day Clock Seconds Bits 0-3: Second digit of Time of Day seconds (BCD) Bits 4-6: First digit of Time of Day seconds (BCD) Bit 7: Unused 56586 $DD0A TO2MIN Time of Day Clock Minutes Bits 0-3: Second digit of Time of Day minutes (BCD) Bits 4-6: First digit of Time of Day minutes (BCD) Bit 7: Unused 56587 $DD0B TO2HRS Time of Day Clock Hours Bits 0-3: Second digit of Time of Day hours (BCD) Bit 4: First digit of Time of Day hours (BCD) Bits 5-6: Unused Bit 7: AM/PM flag (1=PM, 0=AM) 56588 $DD0C CI2SDR Serial Data Port The CIA chip has an on-chip serial port, which allows you to send or receive a byte of data one bit at a time, with the most significant bit (Bit 7) being transferred first. For more information about its use, see the entry for location 56332 ($DC0C). The 64's Operating System does not use this facility. 56589 $DD0D CI2ICR Interrupt Control Register Bit 0: Read / did Timer A count down to 0? (1=yes) Write/ enable or disable Timer A interrupt (1=enable, 0=disable) Bit 1: Read / did Timer B count down to 0? (1=yes) Write/ enable or disable Timer B interrupt (1=enable, 0=disable) Bit 2: Read / did Time of Day Clock reach the alarm time? (1=yes) Write/ enable or disable TOD clock alarm interrupt (1=enable, 0=disable) Bit 3: Read / did the serial shift register finish a byte? (1=yes) Write/ enable or disable serial shift register interrupt (1=enable, 0=disable) Bit 4: Read / was a signal sent on the FLAG line? (1=yes) Write/ enable or disable FLAG line interrupt (1=enable, 0=disable) Bit 5: Not used Bit 6: Not used Bit 7: Read / did any CIA #2 source cause an interrupt? (1=yes) Write/ set or clear bits of this register (1=bits written with 1 will be set, 0=bits written with 1 will be cleared) This register is used to control the five interrupt sources on the 6526 CIA chip. For details on its operation, see the entry for 56333 ($DC0D). The main difference between these two chips pertaining to this register is that on CIA #2, the FLAG line is connected to Pin B of the User Port, and thus is available to the user who wishes to take advantage of its ability to cause interrupts for handshaking purposes. Location Range: 56590-$56591 ($DD0E-$DD0F) See locations 56334 and 56334 for details 56590 $DD0E CI2CRA Control Register A Bit 0: Start Timer A (1=start, 0=stop) Bit 1: Select Timer A output on Port B (1=Timer A output appears on Bit 6 of Port B) Bit 2: Port B output mode (1=toggle Bit 6, 0=pulse Bit 6 for one cycle) Bit 3: Timer A run mode (1=one-shot, 0=continuous) Bit 4: Force latched value to be loaded to Timer A counter (1=force load strobe) Bit 5: Timer A input mode (1=count microprocessor cycles, 0=count signals on CNT line at pin 4 of User Port) Bit 6: Serial Port (56588, $DD0C) mode (1=output, 0=input) Bit 7: Time of Day Clock frequency (1=50 Hz required on TOD pin, 0=60 Hz) 56591 $DD0F CI2CRB Control Register B Bit 0: Start Timer B (1=start, 0=stop) Bit 1: Select Timer B output on Port B (1=Timer B output appears on Bit 7 of Port B) Bit 2: Port B output mode (1=toggle Bit 7, 0=pulse Bit 7 for one cycle) Bit 3: Timer B run mode (1=one shot, 0=continuous) Bit 4: Force latched value to be loaded to Timer B counter (1=force load strobe) Bits 5-6: Timer B input mode 00 = Timer B counts microprocessor cycles 01 = Count signals on CNT line at pin 4 of User Port 10 = Count each time that Timer A counts down to 0 11 = Count Timer A 0's when CNT pulses are also present Bit 7: Select Time of Day write (0=writing to TOD registers sets alarm, 1=writing to ROD registers sets clock) Location Range: 56592-56831 ($DD10-$DDFF) CIA #2 Register Images Since the CIA chip requires only enough addressing lines to handle 16 registers, none of the higher bits are decoded when addressing the 256-byte area that has been assigned to it. The result is that every 16-byte area in this 256-byte block is a mirror of every other. For the sake of clarity in your programs, it is advisable not to use these addresses. Location Range: 56832-57087 ($DE00-$DEFF) Reserved for I/O Expansion This range of locations is not used directly by the 64's internal hardware. It is, however, accessible via pin 7 of the Expansion Port. It can be used to control cartridges which are connected to this port. For example, the CP/M module uses this space to control which microprocessor is in control of the system. The Z-80 microprocessor is turned on and off by writing to 56832 ($DE00). Another cartridge which uses this space is Simon's BASIC. This 16K cartridge is addressed at memory locations 32768-49151 ($8000-$BFFF), which means that it overlaps the regular BASIC ROM at 40960-49151 ($A000-$BFFF). But since it contains additions to BASIC, it must use the BASIC ROM as well. This problem is solved by copying the cartridge at 32768-40959 ($8000-$9FFF) to RAM, and turning the cartridge on and off by writing to or reading from location 56832 ($DE00). Location Range: 57088-57343 ($DF00-$DFFF) CIA #2 Register Images This range of locations is not used directly by the 64's internal hardward, but is accessible via pin 10 of the Expansion Port. One possible use for this I/O memory that Commodore has mentioned is an inexpensive parallel disk drive (which presumable would be much faster than the current serial model). Alternate 53248-57343 ($D000-$DFFF) Character Generator ROM The character generator ROM supplies the data which is to form the shapes of the text and graphics characters that are displayed on the screen. Each character requires eight bytes of shape data, and these eight-byte sequences are arranged in order in which the characters appear in the screen code chart (see Appendix G). For example, the first eight bytes of data in the ROM hold the shape information for the commercial at sign (@), the next eight hold the shape of the letter A, etc. In all, there are 4096 bytes, representing shape data for two complete character sets of 256 characters each--1K each for uppercase/graphics, reverse uppercase/reverse graphics, lowercase/ uppercase, and reverse lowercase/reverse uppercase. The shape of each character is formed by an 8 by 8 matrix of screen dots. Whether any of the 64 dots is lit up or not is determined by the bit patterns of the character data. Each byte of the Character ROM holds a number from 0 to 255. This number can be represented by eight binary digits of 0 or 1. The leftmost bit of these eight is known as Bit 7, while the rightmost bit is called Bit 0. Each of these binary digits has a bit value that is two times greater than the last. The values of a bit set to 1 in each of the bit places are: Bit 0 1 2 3 4 5 6 7 Value 1 2 4 8 16 32 64 128 A byte whose value is 255 has every bit set to 1 (128+64+32+16+8+4+2+1=255), while a byte whose value is 0 is made up of all zero bits. Numbers in between are made up of combinations of bits set to 1 and bits set to 0. If you think of every bit that holds 0 as a dot on the screen which is the color of the screen background, and every bit that holds a 1 as a dot whose color is that of the appropriate nybble in Color RAM, you can begin to get an idea of how the byte values relate to the shape of the character. For example, if you PEEK at the first eight bytes of the character ROM (the technique is explained in the entry for location 1), you will see the numbers 60, 102, 110, 110, 96, 98, 60, 0. Breaking these data bytes down into their bit values gives us a picture that looks like the following: 00111100 0 + 0 + 32 + 16 + 8 + 4 + 0 + 0 = 60 01100110 0 + 64 + 32 + 0 + 0 + 4 + 2 + 0 = 101 01101110 0 + 64 + 32 + 0 + 8 + 4 + 2 + 0 = 110 01101110 0 + 64 + 32 + 0 + 8 + 4 + 2 + 0 = 110 01100000 0 + 64 + 32 + 0 + 0 + 0 + 0 + 0 = 96 01100010 0 + 64 + 32 + 0 + 0 + 0 + 2 + 0 = 98 00111100 0 + 0 + 32 + 16 + 8 + 4 + 0 + 0 = 60 00000000 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 = 0 If you look closely, you will recognize the shape of the commercial at sign (@) as it's displayed on your screen. The first byte of data is 60, and you can see that Bits 5, 4, 3, and 2 are set to 1. The chart above shows that the bit values for these bits are 32, 16, 8, and 4. Adding these together, you get 32+16+8+4=60. This should give you an idea of how the byte value corresponds to the patterns of lit dots. For an even more graphic display, type in the following program, which shows the shape of any of the 512 characters in the ROM, along with the number value of each byte of the shape. 10 DIM B%(7),T%(7):FOR I=0 TO 7:T%(I)=2^I:NEXT 20 POKE 53281,2:PRINT CHR$(147):POKE 53281,1:POKE 53280,0:POKE 646,11 30 POKE 214,20:PRINT:INPUT" CHARACTER NUMBER (0-511)";C$ 40 C=VAL(C$):GOSUB 80:FOR I=0 TO 7 50 POKE 214,6+I:PRINT:PRINT TAB(23);B%(I);CHR$(20);" " 60 FOR J=7 TO 0 STEP-1:POKE 1319+(7-J)+I*40,32-128*((B%(I)ANDT%(J))=T%(J)) 70 NEXT J,I:POKE 214,20:PRINT:PRINT TAB(27)" ":GOTO 30 80 POKE 56333,127:POKE 1,51:FOR I=0 TO 7 90 B%(I)=PEEK(53248+C*8+I):NEXT:POKE 1,55:POKE 56333,129:RETURN If you have read about the VIC-II video chip, you know that it can address only 16K of memory at a time, and that all display data such as screen memory, character shape data, and sprite shape data must be stored within that 16K block. Since it would be very inconvenient for the VIC-II chip to be able to access the character data only at the 16K block which includes adresses 53248-57343 ($D000-$DFFF), the 64 uses an addressing trick that makes the VIC-II chip see an image of the Character ROM at 4096-8191 ($1000-$1FFF) and at 36864-40959 ($9000-$9FFF). It is not available in the other two blocks. To generate characters in these blocks, you must supply your own user-defined character set, or copy the ROM data to RAM. A machine language routine for doing this is included in a sample program at the entry for 56576 ($DD00). As indicated above, you are by no means limited to useing the character data furnished by the ROM. The availability of user-defined characters greatly extends the graphics power of the 64. It allows you to create special text characters, like math or chemistry symbols and foreign language alphabets. You can also develop special graphics characters as a substitute for plotting points in bitmap graphics. You can achieve the same resolution using a custom character as in high-resolution bitmap mode, but with less memory. Once you have defined the character, it is much faster to print it to the screen than in would be to plot out all of the individual points. To employ user-defined characters, you must first pick a spot to put the shape data. This requires choosing a bank of 16K for video chip memory (see the entry under Bits 0-1 of 56576 ($DD00) for the considerations involved), and setting the pointer to the 2K area of character memory in 53272 ($D018). It is then up to you to supply the shape data for the characters. You can use part of the ROM character set by reading the ROM and transferring the data to your character shape area (see the entry for location 1 for a method of reading the ROM). Your original characters may be created by darkening squares on an 8 by 8 grid, converting all darkened squares to their bit values, and then adding the bit values for each of the eight bytes. Or, you may use one of the many character graphics editor programs that are available commercially to generate the data interactively by drawing on the screen. One graphics mode, multicolor text mode, almost requires that you define your own character set in order to use it effectively. Multicolor mode is enabled by Bit 4 of location 53270 ($D016). Instead of using each bit to control whether an individual dot will be foreground color (1) or background color (0), that mode breaks down each byte of shape data in four bit-pairs. These bit pairs control whether a dot will be the color in Background Color Register #0 (00), the color in Background Color Register #1 (01), the color in Background Color Register #2 (10), or the color in the appropriate nybble of Color RAM (11). Since each pair of bits controls one dot, each character is only four dots across. To make up for this, each dot is twice as wide as a normal high-resolution dot. :::::::::::::::: :: Chapter 7 :: :: :: ::8K Operating:: :: System :: :: Kernal ROM :: :::::::::::::::: As with the section on the BASIC ROM, this section is not meant to be a complete explanation of the Kernal ROM, but rather a guidepost for further exploration. Where the exact instructions the Kernal ROM routines use are important to your programming, it will be necessary for you to obtain a disassembly listing of those routines and look at the code itself. Keep in mind that there is 8K of RAM underlying the Kernal ROM that can be used by turning off interrupts and switching out the Kernal ROM temporarily. Even without switching out the Kernal ROM, this RAM may be read by the VIC-II chip if it is banked to use the top 16K of memory, and may be used for graphics data. The Kernal and BASIC ROMs may be copied to RAM, and the RAM versions modified to change existing features or add new ones. There are some differences between the version of the Kernal found on the first few Commodore 64s and those found on the majority of newer models. Those differences are discussed in the entries for the sections on later Kernal additions (patches) at 58541-58623 ($E4AD-$E4FF) an 65371-67407 ($FF5B-$FF7F). The most obvious change causes the Color RAM at 55296 ($D800) to be initialized to the background color when the screen is cleared on newer models, instead of white as on the original models. Other changes allow the new Kernal software to be used by either U.S. or European 64s. Keep in mind that the Kernal is always subject to change, and that the following discussion, while accurate at the time written (mid-1983), may not pertain to later models. If future changes are like past ones, however, they are likely to be minor ones. The first place to look for these changes would be in the patch sections identified above. 57344 $E000 Continuation of EXP Routine This routine is split, with part on the BASIC ROM and the other part here. Since the two ROMs do not occupy contiguous memory as on most Commodore machines, the BASIC ROM ends with a JMP $E000 instruction. Thus, while the BASIC interpreter on the 64 is for the most part the same as on the VIC, the addresses for routines in this ROM are displaced by three bytes from their location on the VIC. 57411 $E043 POLY1 Function Series Evaluation Subroutine 1 This routine is used to evaluate more comples expressions, and calls the following routine to do the intermediate evaluation. 57433 $E059 POLY2 Function Series Evaluation Subroutine 2 This is the main series evaluation routine, which evaluates expressions by using a table of the various values that must be operated on in sequence to obtain the proper result. 57485 $E08D RMULC Multiplicative Constant for RND A five-byte floating point number which is multiplied by the seed value as part of the process of obtaining the next value for RND> 57490 $E092 RADDC Additive Constant for RND The five-byte floating point number stored here is added to the seed as part of the process of obtaining the value for RND. 57495 $E097 RND Perform RND This routine comes up with a random number in one of three ways, depending on the argument X of RND(X). If the argument is positive, the next RND value is obtained by multiplying the seed value in location 139 ($8B) by one of the constants above, adding the other constant, and scrambling the resulting bytes. This produces the next number in a sequence. So many numbers can be produced in this way before the sequence begins to repear that it can be considered random. If the argument is negative, the argument itself is scrambled, and made the new seed. This allows creation of a sequence that can be duplicated. If the argument is 0, four bytes of the Floating Point Accumulator are loaded from the low and high byte of Timer A, and the tenths of second and second Time of Day Clock registers, all on CIA #1. This provides a somewhat random value determined by the setting of those timers at the moment that the command is executed, which becomes the new seed value. The RND(1) command should then be used to generate further random numbers. The RND(0) implementation on the 64 has serious problems which make it unusable for generating a series of random numbers when used by itself. First of all, the Time of Day Clock on CIA #1 (see 56328-56331 ($DC08-$DC0B)) does not start running until you write to the tenth of second register. The Operating System never starts this clock, and therefore the two registers used as part of the floating point RND(0) value always have a value of 0. Even if the clock was started, however, these registers keep time in Binary Coded Decimal (BCD) format, which means that they do not produce a full range of numbers from 0 to 255. In addition, the Timer A high register output ranges only from 0 to 66, which also imits the range of the final floating point value so that certain numbers are never chosen. 57593 $E0F9 Call Kernal I/O Routines This section is used when BASIC wants to call the Kernal I/O routines CHROUT, CHRIN, CHKOUT, CHKIN, and GETIN. It handles any errors that result from the call, and creates a 512-byte buffer space at the top of BASIC and executes a CLR if the RS-232 device is opened. 57642 $E12A SYS Perform SYS Before executing the machine language subroutine (JSR) at the address indicated, the .A, .X, .Y, and .P registers are loaded from the storage area at 780-783 ($30C-$30F). After the return from subroutine (RTS), the new values of those registers are stored back at 780-783 ($30C-$30F). 57686 $E156 SAVE Perform SAVE This routine sets the range of addresses to be saved from the start of BASIC program text and end of BASIC program text pointers at 43 ($2B) and 45 ($2D), and calls the Kernal SAVE routine. This means that any area of memory can be saved by altering these two pointers to point to the starting and ending address of the desired area, and then changing them back. 57701 $E165 VERIFY Perform VERIFY This routine sets the load/verify flag at 10 ($A), and falls through to the LOAD routine. 57704 $E168 LOAD Perform LOAD This routine sets the load address to the start of BASIC (from pointer at 43 ($2B)), and calls the Kerneal LOAD routine. If the load is successful, it relinks the BASIC program so that the links agree with the address to which it is loaded, and it resets the end of BASIC pointer to reflect the new end of program text. If the LOAD was done while a program was running, the pointers are reset so that the program starts executing all over again from the beginning. A CLR is not performed, so that the variables build so far are retained, and their values are still accessible. The pointer to the variable area is not changed, but if the new program is longer than the one that loaded it, the variable table will be partially overwritten. This will cause errors when the overwritten variables are referenced. Likewise, strings whose text was referenced at its location within the original program listing will be incorrect. Since a LOAD from a program causes the program execution to continue at the first line, when loading a machine language routine or data file with a nonrelocating load (for example, LOAD"FILE",8,1) from a program, you should read a flag and GOTO the line after the LOAD if you don't want the program to keep rerunning indefinitely: 10 IF FLAG=1 THEN GOTO 30 20 FLAG=1:LOAD"FILE",8,1 30 REM PROGRAM CONTINUES HERE 57790 $E1BE OPEN Perform OPEN The BASIC OPEN statement calls the Kernal OPEN routine. 57799 $E1C7 CLOSE Perform CLOSE The BASIC CLOSE statement calls the Kernal CLOSE routine. 57812 $E1D4 Set Parameters for LOAD, VERIFY, and SAVE This routine is used in common by LOAD, SAVE, and VERIFY for setting the filename, the logical file, device number, and secondary address, all of which must be done prior to these operations. 57856 $E200 Skip Comma and Get Integer in .X This subroutine is used to skip the comma between parameters and get the following integer value in the .X register. 57862 $E206 Fetch Current Character and Check for End of Line This subroutine gets the current character, and if it is 0 (end of line), it pulls its own return address off the stack and returns. This terminates both its own execution and that of the subroutine which called it. 57870 $E20E Check for Comma This subroutine checks for a comma, moves the text pointer past it if found, and returns an error if it is not found. 57881 $E219 Set Parameters for OPEN and CLOSE This routine is used in common by OPEN and CLOSE for setting the filename, the logical file, device number, and secondary address, all of which must be done prior to these operations. 57956 $E264 COS Perform COS COS is executed by adding PI/2 to the contents of FAC1 and dropping through to SIN. 57960 $E268 SIN Perform SIN This routine evaluates the SIN of the number in FAC1 (which represents the angle in radians), and leaves the result there. 58036 $E2B4 TAN Perform TAN This routine evaluates the tangent of the number in FAC1 (which represents the angle in radians) by dividing its sine by its cosine. Location Range: 58080-58125 ($E2E0-$E30D) Table of Constants for Evaluation of SIN, COS, and TAN 58080 $E2E0 PI2 The Five-Byte Floating Point Representation of the Constant PI/2 58085 $E2E5 TWOPI The Five-Byte Floating Point Representation of the Constant 2*PI 58090 $E2EA FR4 The Five-Byte Floating Point Representation of the Constant 1/4 58095 $E2EF SINCON Table of Constants for Evaluation of SIN, COS, and TAN This table starts with a counter byte of 5, indicating that there are six entries in the table. This is followed by the six floating point constants of five bytes each. 58126 $E30E ATN Perform ATN The arc tangent of the number in FAC1 (which represents the angle in radians) is evaluated using the 12-term series of operations from the constant table which follows. The answer is left in FAC1. 58174 $E33E ATNCON Table of Constants for ATN Evaluation The table begins with a count byte of 11, which is followed by 12 constants in five-byte floating point representation. 58235 $E37B Warm Start BASIC This is the entry point into BASIC from the BRK routine at 65126 ($FE66), which is executed when the STOP and RESTORE keys are both pressed. It first executes the Kernal CLRCHN routine which closes all files. It then sets the default devices, resets the stack and BASIC program pointers, and jumps through the vector at 768 ($300) to the next routine to print the READY prompt and enter the main BASIC loop. 58251 $E38B Error Message Handler This routine to print error messages is pointed to by the vector at 768 ($300). Using the .X register as an index, it either prints an error message from the table at 41363 ($A193) or the READY prompt, and continues through the vector at 770 ($302) to the main BASIC loop. 58260 $E394 Cold Start BASIC This initialization routine is executed at the time of power-up. The RAM vectors to important BASIC routines are set up starting at 768 ($300), the interpreter is initialized, the start-up messages are printed, and the main loop entered through the end of the warm start routine. 58274 $E3A2 INITAT Text of the CHRGET Routine Which Runs at 115 ($73) The text of the CHRGET routine is stored here, and moved to Page 0 by the BASIC initialization routine. When creating a wedge in CHRGET, it is possible to execute all or part of this code in place of the RAM version. 59298 $E3BA Initial RND Seed Value At power-up time, this five-byte floating point constant is transferred to 139 ($8B), where it functions as the starting RND seed number. Thus, if RND is not initialized with a negative or zero argument, it will always return the same sequence of numbers. 58303 $E3BF INIT Initialize BASIC This routine is called by the cold start routine to initialize all of the BASIC zero-page locations which have a fixed value. This includes copying the CHRGET routine from the ROM location above, to 115 ($73). 58402 $E422 Print BASIC Start-Up Messages This routine prints the start-up message "**** COMMODORE 64 BASIC V2 ****", calculates the amount of free memory, and prints the BYTES FREE message. 58439 $E447 Table of Vectors to Important BASIC Routines This table contains the vectors which point to the addresses of some important BASIC routines. The contents of this table are moved to the RAM table at 768 ($300). 58451 $E453 Copy BASIC Vectors to RAM The cold start routine calls this subroutine to copy the table of vectors to important BASIC routines to RAM, starting at location 768 ($300). 58464 $E460 WORDS Power-Up Messages The ASCII text of the start-up messages "**** COMMODORE 64 BASIC V2 ****" and "BYTES FREE" is stored here. Location Range: 58551-58623 ($E4B7-E4FF) Patches Added to Later Kernal Versions This area contains code that was not found in the original version of the Kernal. These additions were made to fix some bugs and to increase Kernal compatibility between U.S. and European 64s. 58541 $E4AD Patch for BASIC Call of CHKOUT This patch was made to preserve the .A register if there was no error returned from BASIC's call of the Kernal CHKOUT routine. Apparently, the first version could cause a malfunction of the CMD and PRINT# commands. 58551 $E4B7 35 Unused Bytes (all have the value of 170 ($AA) Locaiton Range: 58586-65535 ($E4DA-$FFFF) Kernal I/O Routines After the conclusion of BASIC comes the part of this ROM which can be considered the Kernal proper. This part contains all of the vectored routines found in the jump table starting at 65409 ($FF81). 58586 $E4DA Clear Color RAM to the Color in Background Color Register 0 This routine is a patch added to the more recent versions of the Kernal. It is called by the routine which clears a screen line (59903, $E9FF), and it places the color value in Background Color Register 0 (53281, $D021) into the current byte of Color RAM pointed to by USER (243, $F3). In the original version of the Kernal, the routine that cleared a screen line set the corresponding Color RAM to a value of 1, which gives text characters a white foreground color. This was changed when the white color was found to sometimes cause light flashes during screen scrolling. It was that white foreground color, however, that enabled the user to POKE the screen code for a character into screen RAM, and make that character appear on the screen in a color that contrasted the blue background. This change to the Operating System causes colors POKEd to screen RAM to be the same color as the background, and thus they are invisible. This is a fairly serious problem, because the technique of POKEing characters to screen RAM has long been a staple of Commodore graphics programming. Fortunately, the problem has an easy colution. Since the Color RAM will be set to whatevere color is in Background Color Register 0, what you have to do to initialize Color RAM to the color you desire is change the background color to the desired foreground color, clear the screen, and then change the background color back again: C=PEEK(53281):POKE 53281,HUE:PRINT CHR$(147):POKE 53281,C 58592 $E4E0 Pause after Finding a File on Cassette This routine is a patch to the routine which finds a file on cassette. After the file is found, the message FILETITLE FOUND appears on the screen. On the original versions of the Kernal, the user would then have to hit the Commodore key to continue the load. On the newer versions, this patch causes a slight pause after the tape file is round, during which time a keypress is looked for. If a key is pressed, the loading process continues immediately. If it is not, the load continues by itself after the end of the pause. 58604 $E4EC Baud Rate Table for European (PAL) Standard Monitors This table of prescaler values was added to later Kernal versions to allow the same Kernal software to be used with either U.S. or European 64s. It contains the values which are required to obtain interrupts at the proper frequency for the standard RS-232 baud rates, and corresponds exactly in format to the table of values for the U.S. (NTSC) monitor format at 65218 ($FEC2). Separate tables are required because the prescaler values are derived from dividing the system clock rate by the baud rate, and PAL machines operate with a slightly slower clock frequency. 58624 $E500 IOBASE Store Base Address of Memory-Mapped I/O Devices in .X and .Y Registers This is one of the documented Kernal routines for which there is a vector in the jump table at 65523 ($FFF3). When called, this routine sets the .X register to the low byte of the base address of the memory-mapped I/O devices, and puts the high byte in the .Y register. This allows a user to set up a zero-page pointer to the device, and to load and store indirectly through that pointer. A program which uses this method, rather than directly accessing such devices could be made to function without change on future Commodore models, even though the I/O chips may be addressed at different locations. This of course assumes that the CIA or a similar chip will be used. This routine is of limited value for creating software that is compatible with both the VIC-20 and the 64 because of the differences in the VIA I/O chip that the VIC uses. The current version of this routine loads the .X register with a 0, and the .Y register with 220 ($DC), thus pointing to CIA #1, which is at 56320 ($DC00). 58629 $E505 SCREEN Store Number of Screen Rows and Columns in .Y and .X This is a documented Kernal routine which is vectored in the jump table at 65517 ($FFED), and is provided to allow for program compatibility between computers. When called, this subroutine returns the number of screen columns in the .X register, and the number of screen rows in .Y. Thus, a program can detect the screen format of the machine on which it is running, and make sure that text output is formatted accordingly. The present version of this routine loads the .X register with 40 ($28) and the .Y register with 25 ($19). 58634 $E50A PLOT Read/Set Location of the Cursor The jump table entry for this documented Kernal is at 65520 ($FFF0). The routine allows the user to read or set the position of the cursor. If the carry flag is set with the SEC instruction before calling this subroutine, cursor column (X position) will be returned in the .X register, and the cursor row (Y position) will be returned in the .Y register. If the carry flag is cleared with a CLC instruction before entering this routine, and the .Y and .X registers are loaded with the desired row and column positions respectively, this routine will set the cursor position accordingly. The current read routine loads .X and .Y from locations 214 ($D6) and 211 ($D3) respectively. The cursor set routine stores .X and .Y in these locations, and calls the routine that sets the screen pointers at 58732 ($E56C). The user can access this routine from BASIC by loading the .X, .Y, and .P register values desired to the save area starting at 780 ($30C). 58648 $E518 Initialize Screen and Keyboard This is the original CINT Kernal routine, to which additions were made in later versions of the Kernal. After calling the routine at 58784 ($E5A0) to set up default I/O values, this routine initializes the cursor blink flags, the keyboard decode vector, the key repeat delay and frequency counters, the current color code, and maximum keyboard buffer size. It then falls through to the next routine. 58692 $E544 Initialize the Screen Line Link Table and Clear the Screen This routine initializes the screen line link table at 217 ($D9), clears the screen, and clears the Color RAM to the background color. It falls through to the next routine. 58726 $E566 Home the Cursor This routine sets PNTR (211, $D3) and TBLX (214, $D6) to 0, and falls through to the next routine. 58732 $E56C Set Pointer to Current Screen Line This routine sets the pointer PNT (209, $D1) to the address of the first byte of the current logical line. In figuring this address, it takes into account the status of the screen line link table, which can indicate that two physical lines should be joined as one logical line. 58784 $E5A0 Set Default I/O Devices and Set Default Values for VIC-II Chip Registers This routine sets the keyboard and screen as the current input and output devices. It then writes the default values found in the table at 60601 ($ECB9) to the VIC-II chip. 58804 $E5B4 LP2 Get a Character from the Keyboard Buffer This routine transfers the first character from the keybard buffer to the .A register, bumps the rest of the characters one place up in line, and decrements the pointer, showing how many characters are waiting in the buffer. 58826 $E5CA Wait for a Carriage Return from the Keyboard This subroutine is called by the portion of the CHKIN routine that handles keyboard input. It turns the cursor on, gets characters, and echoes them to the screen until a carriage return has been entered. It also looks for the shifted RUN/STOP key, and forces the output of the commands LOAD and RUN if it finds it. 58930 $E632 Input a Character from Screen or Keyboard This routine is the portion of the Kernal CHRIN routine that handles input from the keyboard and screen devices. CHRIN gets one byte at a time from the current screen position, or inputs a whole line from the keyboard and returns it one byte at a time. 59012 $E684 Test for Quote Marks This subroutine checks if the current character is a quotation mark, and if it is, toggles the quote switch at 212 ($D4). 59025 $E691 Add a Character to the Screen This is part of the routine that outputs a character to the screen. It puts printable characters into screen memory. 59048 $E6A8 Return from Outputting a Character to the Screen This is the common exit point for the screen portion of the CHROUT routine. 59062 $E6B6 Advance the Cursor This routine advances the cursor, and provides for such things as scrolling at the end of the screen, and inserting a blank line in order to add another physical line to the current logical line. 59137 $E701 Move Cursor Back over a 40-Column Line Boundary 59158 $E716 Output to the Screen This is the main entry point for the part of CHROUT that handles output to the screen device. It takes an ASCII character number, and tests if the character is printable. If it is, it prints it (taking into consideration the reverse flag, if any inserts are left, etc.). If it is a nonprinting character, the routine performs the appropriate cursor movement, color change, screen clearing, or whatever else might be indicated. 59516 $E87C Move Cursor to Next Line This subroutine moves the cursor down to the next line if possible, or scrolls the screen if the cursor is on the last line. 59537 $E891 Output a Carriage Return A carriage return is performed by clearing insert mode, reverse video, and quote mode, and moving the cursor to the next line. 59553 $E8A1 If at the Beginning of a Screen Line, Move Cursor to Previous Line 59571 $E8B3 If at the End of a Screen Line, Move Cursor to the Next Line 59595 $E8CB Check for a Color Change This routine is used by the screen CHROUT routine to check if the character to be printed is one that causes the current foreground color to change (such as the CTRL-1 combination). 59601 $E8D1 PETASCII Color Code Equivalent Table This table gives the PETASCII values of the color change characters for each of the 16 possible colors. These values are: 144 ($90) Change to color 0 (black) 5 ($05) Change to color 0 (white) 28 ($1C) Change to color 0 (red) 159 ($9F) Change to color 0 (cyan) 156 ($9C) Change to color 0 (purple) 30 ($1E) Change to color 0 (green) 31 ($1F) Change to color 0 (blue) 158 ($9E) Change to color 0 (yellow) 129 ($81) Change to color 0 (orange) 149 ($95) Change to color 0 (brown) 150 ($96) Change to color 0 (light red) 151 ($97) Change to color 0 (dark gray) 152 ($98) Change to color 0 (medium gray) 153 ($99) Change to color 0 (light green) 154 ($9A) Change to color 0 (light blue) 155 ($9B) Change to color 0 (light gray) 59626 $E8EA Scroll Screen This subroutine moves all of the screen lines up, so that a blank line is created at the bottom of the screen and the top screen line is lost. If the top logical line is two physical lines long, all lines are moved up two lines. Holding down the CTRL key will cause a brief pause after the scroll. 59749 $E965 Insert a Blank Line on the Screen This subroutine is used when INSERTing to add a blank physical line to a logical line. 59848 $E9C8 Move Screen Line This subroutine is used by the scroll routine to move one screen line (and its associated Color RAM) up a line. 59872 $E9E0 Set Temporary Color Pointer for Scrolling This subrouting sets up a pointer in 17-175 ($AE-$AF) to the Color RAM address that corresponds to the temporary screen line address in 172-173 ($AC-$AD). 59888 $E9F0 Set Pointer to Screen Address of Start of Line This subroutine puts the address of the first byte of the screen line designated by the .X register into locations 209-210 ($D1-$D2). 59903 $E9FF Clear Screen Line This subroutine writes space characters to an entire line of screen memory, and clears the corresponding line of color memory to color in Background Color Register 0 (53281, $D021). 59923 $EA13 Set Cursor Blink Timing and Color Memory Address for Print to Screen This subroutine sets the cursor blink countdown and sets the pointer to Color RAM. It then falls through to the next routine. 59932 $EA1C Store to Screen This routine stores the character in the .A register to the screen address pointed to by 209 ($D1), and stores the color in the .X register to the address pointed to by 243 ($F3). 59940 $EA24 Synchronize Color RAM Pointer to Screen Line Pointer This subroutine sets the pointer at 243 ($F3) to the address of the beginning of the line of Color RAM which corresponds to the current line of screen RAM (whose pointer is at 209 ($D1)). 59953 $EA31 IRQ Interrupt Entry This is the entry point to the standard IRQ interrupt handler. Timer A of CIA #1 is set at power-on to cause an IRQ interrupt to occur every 1/60 second. When the interrupt occurs, program flow is transferred here via the CINV vector at 788 ($314). This routine updates the software clock at 160-162 ($A0-$A2), handles the cursor flash, and maintains the tape interlock which keeps the cassette motor on if a button is pushed and the interlock flag is on. Finally, it calls the keyboard scan routine, which checks the keyboard and puts any character it finds into the keyboard buffer. 60039 $EA87 SCNKEY Read the Keyboard This subroutine is called by the IRQ interrupt handler above to read the keyboard device which is connected to CIA #1 (see entry for 56320 ($DC00) for details on how to read the keyboard). It is the Kernal routine SCNKEY which can be entered from the jump table at 65439 ($FF9F). This routine returns the keycode of the key currently being pressed in 203 ($CB), sets the shift/control flag if appropriate, and jumps through the vector at 655 ($28F) to the routine that sets up the proper table to translate the keycode to PETASCII. It concludes with the next routine, which places the PETASCII value of the character in the keyboard buffer. 60128 $EAE0 Decode the Keystroke and Place its ASCII Value in the Keyboard Buffer This is the continuation of the IRQ keyscan routine. It decodes the keycode with the proper PETASCII table, and compares it with the last keystroke. If if is the same, it checks to see if it is okay to repeat the character without waiting for the key to be let up. If the character should be printed, it is moved to the end of the keyboard buffer at 631 ($277). 60232 $Eb48 Set Up the Proper Keyboard Decode Table This routine is pointed to by the vector at 655 ($28F). Its function is to read the shift/control flag at 653 ($28D), and set the value of the decode table pointer at 245 ($F5) accordingly. First it checks if the SHIFT/Commodore logo combination was pressed, and if the toggle enable at 657 (291) will allow a change, the character set will be changed to lowercase/uppercase or uppercase/graphics by changing the VIC Memory Control Register at 53272 ($D018), and no character will be printed. Next it sets the decode table pointer. There are 64 keys, and each can have four different PETASCII values, depending on whether the key is pressed by itself, or in combination with the SHIFT, CTRL, or Commodore logo keys. Therefore, there are four tables of 64 entries each to translate the keycode to PETASCII: the standard table, the SHIFT table, the Commodore logo table, and the CONTROL table. The routine will set up the pointer for the appropriate table, depending on whether the SHIFT, CTRL, or logo key was pressed. The CTRL key takes precedence, so that if another of these keys is pressed along with the CTRL key, the CONTROL table is used. 60281 $EB79 Keyboard Decode Table Vectors This table contains the two-byte addresses of the four keyboard decode tables in low-byte, high-byte format. 60289 $EB81 Standard Keyboard Matrix Decode Table This table contains the 64 PETASCII values for the standard keyboard, one for each key which is struck by itself. The table is in keycode order (see the keycode table in Appendix H for the correspondence of keycode to key). A 65th byte with the value of 255 ($FF) marks the end of the table (this corresponds to a keypress value of 64, no key pressed). 60354 $EBC2 SHIFTed Keyboard Matrix Decode Table This table contains the 64 PETASCII values for the shifted keyboard, one for each key which is struck while the SHIFT key is pressed. The table is in keycode order (see the keycode table in Appendix H for the correspondence of keycode to key). A 65th byte with the value of 255 ($FF) marks the end of the table (this corresponds to a keypress value of 64, no key pressed). 60419 $EC03 Commodore Logo Keyboard Matrix Decode Table This table contains the 64 PETASCII values for the logo keyboard, one for each key which is struck while the Commodore logo key is pressed. The table is in keycode order (see the keycode table in Appendix H for the correspondence of keycode to key). A 65th byte with the value of 255 ($FF) marks the end of the table (this corresponds to a keypress value of 64, no key pressed). 60484 $EC44 Set Lowercase/Uppercase or Uppercase/Graphics Character Set The part of the Kernal CHROUT routine that outputs to the screen uses this subroutine to check for the special nonprinting characters that switch the character set (CHR$(14) and CHR$(142)). If one of these is the character to be printed, this routine makes the switch by setting the location 53272 ($D018) accordingly. 60510 $EC5E Set Flag to Enable or Disable Switching Character Sets This subroutine is also used to check for special characters to print. In this case, it checks for the characters that enable or disable the SHIFT/logo combination from toggling the character set currently in use (CHR$(8) and CHR$(9)). If one of these is to be printed, the flag at 657 ($291) is changed. 60536 $EC78 Control Keyboard Matrix Decode Table This table contains the 64 PETASCII values for the Control keyboard, one for each key which is struck while the CTRL key is pressed. The table is in keycode order (see the keycode table in Appendix H for the correspondence of keycode to key). A 65th byte with the value of 255 ($FF) marks the end of the table (this corresponds to a keypress value of 64, no key pressed). The only keys generally struck in combination with the CTRL key are the ones that change the colors on the top row of the keyboard, but this doesn't necessarily mean that the other CTRL key combinations don't do anything. On the contrary, looking at the values in this table, you can see that any of the first 32 values in the PETASCII table can be produced by some combination of the CTRL key and another key. CTRL-@ produces a CHR$(0). CTRL-A through CTRL-Z produce CHR$(1) through CHR$(26). Ctrl-: is the same as CHR$(27), CTRL-Lira (that's the slashed-L British pound sign) produces CHR$(28), CTRL-; equals CHR$(29), CTRL-up arrow produces CHR$(30), and CTRL-= produces CHR$(31). Any of these combinations produce the same effect as the CHR$(X) statement. For examble, CTRL-; moves the cursor over to the right, CTRL-N switches to lowercase, CTRL-R turns on reverse video, and CTRL-E changes the printing to white. 60601 $ECB9 Video Chip Register Default Table This table contains the default values that are stored in the 47 VIC-II chip registers. It is interesting to note that this table appears to be incomplete. While Sprite Color Registers 0-6 are initialized to values of 1-7, Sprite Color Register 7 is initialized to 76--the ASCII value of the letter L which begins on the next table. 60647 $ECE7 Text for Keyboard Buffer When SHIFT/RUN is Pressed When the SHIFT and RUN keys are pressed, the ASCII text stored here is forced into the keyboard buffer. That text is LOAD, carriage return, RUN, carriage return. 60656 $ECF0 Low Byte Table of Screen Line Addresses This table holds the low byte of the screen address for lines 0-24. The high byte is derived from combining a value from the screen line link table at 217 ($D9) with the pointer to screen memory at 648 ($288). 60681 $ED09 TALK Send TALK to a Device on the Serial Bus This is a documented Kernal routine whose entry in the jump table is 65460 ($FFB4). When called, it ORs the device number in the Accumulator with the TALK code (64, $40) and sends it on the serial bus. This commands the device to TALK. 60684 $ED0C LISTEN This is a documented Kernal routine whose entry in the jump table is 65457 ($FFB1). When called, it ORs the device number in the Accumulator with the LISTEN code (32, $20) and sends it on the serial bus. This commands the device to LISTEN. 60689 $ED11 Send Command Code to a Device on the Serial Bus This subroutine is used in common by many Kernal routines to send the command code in the Accumulator to a device on the serial bus. 60736 $ED40 Send a Byte on the Serial Bus This subroutine is used in common by several Kernal routines to send the byte in the serial bus character buffer at 149 ($95) on the serial bus. 60848 $EDB0 Time-Out Error on Serial Bus This subroutine handles the case when the device does not respond by setting the DEVICE NOT PRESENT error code and exiting. 60857 $EDB9 SECOND Send a Secondary Address to a Device on the Serial Bus after LISTEN This is a documented Kernal routine that can be entered from the jump table at 65427 ($FF93). It sends a secondary address from the Accumulator to the device on the serial bus that has just been commanded to LISTEN. This is usually done to give the device more particular instructions on how the I/O is to be carried out before information is sent. 60871 $EDC7 TKSA Send a Secondary Address to a Device on the Serial Bus after TALK This is a documented Kernal routine that can be entered from the jump table at 65430 ($FF96). It sends a secondary address from the Accumulator to the device on the serial bus that has just been commanded to TALK. This is usually done to give the device more particular instructions on how the I/O is to be carried out before information is sent. 60893 $EDDD CIOUT Send a Byte to an I/O Device over the Serial Bus This is a documented Kernal routine which can be entered from the jump table at 65448 ($FFA8). Its purpose is to send a byte of data over the serial bus. In order for the data to be received, the serial device must have first been commanded to LISTEN and been given a secondary address if necessary. This routine always buffers the current character, and defers sending it until the next byte is buffered. When the UNLISTEN command is sent, the last byte will be sent with an End or Identify (EOI). 60911 $EDEF UNTLK Send UNTALK to a Device on the Serial Bus This is a documented Kernal routine whose entry in the jump table is 65451 ($FFAB). When called, it sends the UNTALK code (95, $5F) on the serial bus. This commands any TALKer on the bus to stop sending data. 60926 $EDFE UNLSN Send UNLISTED to a Device on the Serial Bus This is a documented Kernal routine whose entry in the jump table is 65454 ($FFAE). It sends the UNLISTEN code (63, $3F) on the serial bus. This commands any LISTENers to get off the serial bus, and frees up the bus for other users. 60947 $EE13 ACPTR Receive a Byte of Data from a Device on the Serial Bus This is a documented Kernal routine whose entry point in the jump table is 65445 ($FFA5). When called, it will get a byte of data from the current TALKer on the serial bus and store it in the Accumulator. In order to receive the data, the device must have previously been sent a command to TALK and a secondary address if it needs one. 61061 $EE85 Set the Serial Clock Line Low (Active) This subroutine clears the serial bus clock pulse output bit (Bit 4 of CIA #2 Data Port A at 56576 ($DD00)). 61070 $EE8E Set the Serial Clock Line High (Inactive) This subroutine sets the serial bus clock pulse output bit to 1 (Bit 4 of CIA #2 Data Port A at 56576 ($DD00)). 61079 $EE97 Set Serial Bus Data Output Line Low This subroutine clears the serial bus data output to 0 (Bit 5 of CIA #2 Data Port A at 56576 ($DD00)). 61097 $EEA9 Get Serial Bus Data Input Bit and Clock Pulse Input Bit This subroutine reads the serial bus data input bit and clock pulse input bit (Bits 7 and 6 of CIA #2 Data Port A at 56576 ($DD00)), and returns the data bit in the Carry flag and the clock bit in the Negative flag. 61107 $EEB3 Perform a One-Millisecond Delay 61115 $EEBB Send Next RS-232 Bit (NMI) This subroutine is called by the NMI interrupt handler routine to send the next bit of data to the RS-232 device. 61230 $EF2E Handle RS-232 Errors This subroutine sets the appropriate error bits in the status register at 663 ($297). 61258 $#F4A Set the Word Length For the Current RS-232 Character This routine takes the number of data bits to send per RS-232 character from the control register and puts it into the .X register for use by the RS-232 routines. 61273 $EF59 Receive Next RS-232 Bit (NMI) This routine is called by the NMI interrupt handler routine to receive the next bit of data from the RS-232 device. 61310 $EF7E Setup to Receive a New Byte from RS-232 61328 $EF90 Test If Start Bit Received from RS-232 61335 $EF97 Put a Byte of Received Data into RS-232 Receive Buffer This routine checks for a Receive Buffer Overrun, stores the byte just received in the RS-232 receive buffer, and checks for Parity Error, Framing Error, or Break Detected Error. It then sets up to receive the next byte. 61409 $EFE1 CHKOUT for the RS-232 device The Kernal CHKOUT routine calls this subroutine to define the RS-232 device's logical file as an output channel. Before this can be done, the logical file must first be OPENed. 61460 $F014 CHROUT for the RS-232 Device The Kernal CHROUT routine calls this subroutine to output a character to the RS-232 device. After the logical file has been OPENed and set for output using CHKOUT, the CHROUT routine is used to actually send a byte of data. 61517 $F04D CHKIN for the RS-232 Device The Kernal CHKIN routine calls this subroutine to define the RS-232 device's logical file as an input channel. A prerequisite for this is that the logical file first be OPENed. 61574 $F086 GETIN for the RS-232 Device The Kernal GETIN routine calls this subroutine to remove the next byte of data from the RS-232 receive buffer and return it in the Accumulator. The routine checks for the Receive Buffer Empty Error. It is also called by the Kernal CHRIN routine, which essentially does the same thing as GETIN for the RS-232 device. 61604 $F0A4 Stop CIA #2 RS-232 NMIs for Serial/Cassette Routines This subroutine turns off the NMIs that drive the RS-232 routines before any I/O is done using the serial bus or cassette device. Such interrupts could throw off the timing of those I/O routines, and interfere with the transmission of data. 61629 $F0BD Kernal Control Messages The ASCII text of the Kernal I/O control messages is stored here. The last byte of every message has Bit 7 set to 1 (ASCII value + 128). The messages are: I/O ERROR SEARCHING FOR PRESS PLAY ON TAPE PRESS RECORD & PLAY ON TAPE LOADING SAVING VERIFYING FOUND OK 61739 $F12B Print Kernal Error Message if in Direct Mode This routine first checks location 157 ($9D) to see if the messages are enabled. If they are, it prints the message indexed by the .Y register. 61758 $F13E GETIN Get One Byte from the Input Device This is a documented Kernal routine whose jump table entry point is at 65508 ($FFE4). The routine jumps through a RAM vector at 810 ($32A). Its function is to get a character from the current input device (whose device number is stored at 153 ($99)). In practive, it operates identically to the CHRIN routine below for all devices except for the keyboard. If the keyboard is the current input device, this routine gets one character from the keyboard buffer at 631 ($277). It depends on the IRQ interrupt routine to rad the keyboard and put characters into the buffer. 61783 $F157 CHRIN Input a Character from the Current Device This is a documented Kernal routine whose jump table entry point is at 65487 ($FFCF). The routine jumps through a RAM vector at 804 ($324). Its function is to get a character from the current input device (whose device number is stored at 153 ($99)). This device must first have been OPENed and then designated as the input channel by the CHKIN routine. When this routine is called, the next byte of data available from this device is returned in the Accumulator. The only exception is the routine for the keyboard device (which is the default input device). It the keyboard is the current input device, this routine blinks the cursor, fetches characters from the keyboard buffer, and echoes them to the screen until a carriage return is encountered. When a carriage return is round, the routine sets a flag to indicate the length of the last logical line before the return character, and reads the first character of this logical line from the screen. Subsequent calls to this routine will cause the next character in the line to be read from the screen and returned in the Accumulator, until the carriage return character is returned to indicate the end of the line. Any call after this character is received will start the whole process over again. Note that only the last logical line before the carriage return is used. Any time you type in more than 80 characters, a new logical line is started. This routine will ignore any characters on the old logical line, and process only the most recent 80-character group. 61898 $F1CA CHROUT Output a Byte This is a documented Kernal routine whose jump table entry point is at 65490 ($FFD2). The routine jumps through a RAM vector at 806 ($326). It is probably one of the best known and most used Kernal routines, because it sends the character in the Accumulator to the current output device. Unless a device has been OPENed and designated as the current output channel using the CHKOUT routine, the character is printed to the screen, which is the default output device. If the cassette is the current device, outputting a byte will only add it to the buffer. No actual transmission of data will occur until the 192-byte buffer is full. 61966 $F20E CHKIN Designate a Logical File As the Current Input Channel This is a documented Kernal routine which can be entered from the jump table at 65478 ($FFC6). The routine jumps through a RAM vector at 798 ($31E). If you wish to get data from any device other than the keyboard, this routine must be called after OPENing the device, before you can get a data byte with the CHRIN or GETIN routine. When called, the routine will designate the logical file whose file number is in the .X register as the current file, its device as the current device, and its secondary address as the current secondary address. If the device on the channel is a serial device, which requires a TALK command and sometimes a secondary address, this routine will send them over the serial bus. 62032 $F250 CHKOUT Designate a Logical File As the Current Output Channel This is a documented Kernal routine which can be entered from the jump table at 65481 ($FFC9). The routine jumps through a RAM vector at 800 ($320). If you wish to output data to any device other than the screen, this routine must be called after OPENing the device, and before you output a data byte with the CHROUT routine. When called, the routine will designate the logical file whose file number is in the .X register as the current file, its device as the current device, and its secondary address as the current secondary address. If the device on the channel uses the serial bus, and therefore requires a LISTEN command and possibly a secondary address, this information will be sent on the bus. 62097 $F291 CLOSE Close a Logical I/O File CLOSE is a documented Kernal routine which can be entered via the jump table at 65475 ($FFC3). The routine jumps through a RAM vector at 796 ($31C). It is used to close a logical file after all I/O operations involving that file have been completed. This is accomplished by loading the Accumulator with the logical file number of the file to be closed, and calling this routine. Closing an RS-232 file will de-allocate space at the top of memory for the receiving and trasmit buffers. Closing a cassette file that was opened for writing will force the last block to be written to cassette, even if it is not a full 192 bytes. Closing a serial bus device will send an UNLISTEN command on the bus. Remember, it is necessary to properly CLOSE a cassette or disk data file in order to retrieve the file later. For all types of files, CLOSE removes the file's entry from the tables of logical files, device, and secondary address at 601, 611, and 621 ($259, $263, $26D), and moves all higher entries in the table down one space. 62223 $F30F Find the File in the Logical File Table This subroutine is used by many Kernal routines to find the position of the logical file in the logical file table at 601 ($259). 62239 $F31F Set Current Logical File, Current Device, and Current Seconday Address This subroutine is used to update the Kernal variables at 184-186 ($B8-$BA) which holds the current logical file number, current device number, and current secondary address number. 62255 $F32F CLALL Close All Logical I/O Files CLALL is a documented Kernal routine whose entry point in the jump table is 65511 ($FFE7). The routine jumps through a RAM vector at 812 ($32C). It closes all open files, by resetting the index into open files at 152 ($98) to zero. It then falls through to the next routine, which restores the default I/O devices. 62259 $F333 CLRCHN Restore Current Input and Output Devices to the Default Devices This is a documented Kernal Routine which can be entered at location 65484 ($FFCC) in the jump table. The routine jumps through a RAM vector at 802 ($322). It sets the current input device to the keyboard, and the current output device to the screen. Also, if the current input device was formerly a serial device, the routine sends it an UNTALK command on the serial bus, and if a serial device was formerly the current output device, the routine sends it an UNLISTEN command. 62282 $F34A OPEN Open a Logical I/O File OPEN is a documented Kernal I/O routine. It can be entered from the jump table at 65472 ($FFC0). The routine jumps through a RAM vector at 794 ($31A). This routine assigns a logical file to a device, so that it can be used for Input/Output operations. In order to specify the logical file number, the device number, and the secondary address if any, the SETLFS routine must first be called. Likewise, in order to designate the filename, the SETNAM routine must be used first. After these two routines are called, OPEN is then called. 62622 $F49E LOAD Load RAM from a Device This is a documented Kernal routine, whose entry in the jump table appears at 65493 ($FFD5). The routine jumps through a RAM vector at 816 ($330). LOAD is used to transfer data froma device directly to RAM. It can also be used to verify RAM, comparing its contents to those of a disk or tape file. To choose between these operations you must set the Accumulator with a 0 for LOAD, or a 1 for VERIFY. Since the LOAD routine performs an OPEN, it must be preceded by a call to the SETLFS routine to specify the logical file number, device number, and secondary address, and a call to the SETNAM routine to specify the filename (a LOAD from tape can be performed without a filename being specified). Then the .X and .Y registers should be set with the starting address for the load, and the LOAD routine called. If the secondary address specified was a 1, this starting address will be ignored, and the header information will be used to supply the load address. If the secondary address was a 0, the address supplied by the call will be used. In either case, upon return from the subroutine, the .X and .Y registers will contain the address of the highest RAM location that was loaded. 62885 $F5A5 Print SEARCHING Message if in Direct Mode 62930 $F5D2 Print LOADING or VERIFYING 62941 $F5DD SAVE Save RAM to a Device This is a documented Kernal routine, whose entry in the jump table appears at 65496 ($FFD8). The routine jumps through a RAM vector at 818 ($332). SAVE is used to transfer data directly from RAM to an I/O device. Since the SAVE routine performs an OPEN, it must be preceded by a call to the SETLFS routine to specify the logical file number, device number, and secondary address, and a call to the SETNAM routine to specify the filename (although a SAVE to the cassette can be performed without giving a filename). A Page 0 pointer to the starting address of the area to be saved should be set up, with the low byte of the address first. The accumulator should be loaded with the Page 0 offset of that pointer, then the .X and .Y registers should be set with the ending address for the save, and the SAVE routine called. 63119 $F68F If in Direct Mode, Print SAVING and Filename 63131 $F69B UDTIM Update the Software Clock and Check for the STOP Key UDTIM is a documented Kernal routine which can be entered through the jump table at 65514 ($FFEA). It is normally called by the IRQ interrupt handler once every sixtieth of a second. It adds one to the value in the three-byte software jiffy clock at 160-162 ($A0-$A2), and sets the clock back to zero when it reaches the 24 hour point. In addition, it scans the keyboard row in which the STOP key is located, and stores the current value of that key in location 145 ($91). This variable is used by the STOP routine which checks for the STOP key. 63197 $F6DD RDTIM Read the Time From the Software Clock into the .A, .X, and .Y Registers This is a documented Kernal routine whose entry point in the jump table is 65502 ($FFDE). It reads the software clock (which counts sixtieths of a second) into the internal registers. The .Y register contains the most significant byte (from location 160 ($A0)), the .X register contains the middle byte (from location 161 ($A1)), and the Accumulator contains the least significant byte (from location 162 ($A2)). 63204 $F6E4 SETTIM Set the Software Clock from the .A, .X, and .Y Registers This documented Kernal routine can be entered from location 65499 ($FFDB). It performs the reverse operation from RDTIM, storing the value in the .Y register into location 160 ($A0), the .X register into 161 ($A1), and the Accumulator into 162 ($A2). Interrupts are first disabled, to make sure that the clock will not be updated while being set. 63213 $F6ED STOP Test STOP Key STOP is a documented Kernal routine which can be entered from the jump table at location 65505 ($FFE1). It is vectored through RAM at 808 ($328). The routine checks to see if the STOP key was pressed during the last UDTIM call. If it was, the Zero flag is set to 1, the CLRCHN routine is called to set the input and output devices back to the keyboard and screen, and the keyboard queue is emptied. 63227 $F6FB Set Kernal I/O Error Messages This subroutine is used to handle I/O errors from Kernal I?O routines. It calls CLRCHN to restore default I/O devices. If Bit 6 of the flag at 157 ($9D) is set, it prints I/O ERROR followed by the error number, and then sets the Carry flag to indicate an error, with the error number in the Accumulator. The Kernal error messages are not used by BASIC, but may be used by machine language monitors and other applications. 63276 $F72C Get Next Tape File Header from Cassette This routine reads in tape blocks until it finds a file header block. It then prints out the FOUND message along with the first 16 characters of the filename. 63338 $F76A Write Tape File Header Block 63440 $F7D0 Put Pointer to Tape Buffer in .X and .Y Registers 63447 $F7D7 Set I/O Area Start and End Pointers to Tape Buffer Start and End Address 63466 $F7EA Search Tape for a Filename 63511 $F817 Test Cassette Buttons and Handle Messages for Tape Read This routine tests the sense switch, and if no buttons are depressed it prints the PRESS PLAY ON TAPE message, and loops until a cassette button is pressed, or until the STOP key is pressed. If a button is pressed, it prints the message OK. Since the message printing routine is entered after the test for direct mode, these messages cannot be superseded by changing the flag at 157 ($9D). You could have them harmlessly printed to ROM, however, by changing the value of HIBASE at 648 ($288) temporarily to 160, and then back to 4. 63534 $F82E Check Cassette Switch This subroutine is used to check if a button on the recorder has been pressed. 63544 $F838 Test Cassette Buttons and Handle Messages for Tape Write This routine tests the sense switch, and if no buttons are depressed it prints the PRESS PLAY & RECORD message, and loops until a cassette button is pressed, or until the STOP key is pressed. If a button is pressed, it prints the message OK. These messages cannot be supressed by changing the flag at 157 ($9D). See the entry for 63511 ($F817) for more information. 63553 $F841 Start Reading a Block of Data from the Cassette This subroutine tests the cassette switch and initializes various flags for reading a block of data from cassette. 63588 $F864 Start Writing a Block of Data to the Cassette This subroutine tests the cassette switch and initializes various flags for writing a block of data to cassette. 63605 $F875 Common Code for Reading a Data Block from Tape and Writing a Block to Tape This routine sets the actual reading or writing of a block of data. It sets CIA #1 Timer B to call the IRQ which drives the actual reading or writing routine, saves the old IRQ vector, and sets the new IRQ vector to the read or write routine. It also blanks the screen so that the video chip's memory addressing (which normally takes away some of the 6510 microprocessor's addressing time) will not interfere with the timing of the routines. 63696 $F8D0 Test the STOP Key during Cassette I/O Operations This subroutine is used to test the STOP key during tape I/O oeprations, and to stop I/O if it is pressed. 63714 $F8E2 Adjust CIA #1 Timer A for Tape Bit Timing 63788 $F92C Read Tape Data (IRQ) This is the IRQ handler routine that is used for reading data from the cassette. At the end of the read, the IRQ vector is restored to the normal IRQ routine. 64096 $FA60 Receive and Store the Next Character from Cassette This is the part of the cassette read IRQ routine that actually gets the next byte of data from the cassette. 64398 $FB8E Move the Tape SAVE/LOAD Address into the Pointer at 172 64407 $FB97 Reset Counters for Reading or Writing a New Byte of Cassette Data 64422 $FBA6 Toggle the Tape Data Output Line This routine sets the CIA #1 Timer B, and toggles the Tape Data Output line on the 6510 on-chip I/O port (Bit 3 of location 1). 64456 $FBC8 Write Data to Cassette--Part 2 (IRQ) This IRQ handler routine is one part of the write data to cassette routine 64618 $FC6A Write Data fo Cassette--Part 1 (IRQ) This IRQ handler routine is the other part of the write data to cassette routine. 64659 $FC93 Restores the Default IRQ Routine At the end of the tape I/O operations, this subroutine is used to turn the screen back on and stop the cassette motor. It then resets the CIA #1 Timer A to generate an interrupt every sixtieth of a second, and restores the IRQ vector to point to the normal interrupt routine that updates the software clock and scans the keyboard. 64696 $FCB8 Terminate Cassette I/O This routine calls the subroutine above and returns from the interrupt. 64714 $FCCA Turn Off the Tape Motor 64721 $FCD1 Check the Tape Read/Write Pointer This routine compares the current tape read/write address with the ending read/write address. 64731 $FCDB Advance the Tape Read/Write Pointer This routine is used to move the pointer to the current read/write address up a byte. 64738 $FCE2 Power-On Reset Routine This is the RESET routine which is pointed to by the 6510 hardware RESET vector at 65532 ($FFFC). This routine is automatically executed when the computer is first turned on. First, it sets the Interrupt disable flag, sets the stack pointer, and clears the Decimal mode flag. Next, it tests for an autostart cartridge. If one is found, the routine immediately jumps through the cartridge cold start vector at 32768 ($8000). If no cartridge is found, the Kernal initialization routines IOINIT, RAMTAS, RESTOR, and CINT are called, the Interrupt disable flag is cleared, and the BASIC program is entered through the cold start vector at 40960 ($A000). 64770 $FD02 Check for an Autostart Cartridge This routine tests for an autostart cartridge by comparing the characters at location 32772-6 ($8004-8) to the text below. The Zero flag will be set if they match, and cleared if they don't. 64784 $FD10 Text for Autostart Cartridge Check The characters stored here must be the fifth through the ninth characters in the cartridge in order for it to be started on power-up. These characters are the PETASCII values for CBM, each with the high bit set (+128), and the characters "80". 64789 $FD15 RESTOR Restore RAM Vectors for Default I/O Routines This documented Kernal routine can be entered through the jump table at 65418 ($FF8A). It sets the values for the 16 RAM vectors to the interrupt and important Kernal I/O routines in the table that starts at 788 ($314) to the standard values held in the ROM table at 64816 ($FD30). 64794 $FD1A VECTOR Set the RAM Vector Table from the Table Pointed to by .X and .Y This documented Kernal routine can be entered through the jump table at 65421 ($FF8D). It is used to read or change the values for the 16 RAM vectors to the interrupt and important Kernal I/O routines in the table that starts at 788 ($314). If the Carry flag is set when the routine is called, the current value of the 16 vectors will be stored at a table whose address is pointed to by the values in the .X and .Y registers. If the Carry flag is cleared, the RAM vectors will be loaded from the table whose address is pointed to by the .X and .Y registers. Since this routine can change the vectors for the IRQ and NMI interrupts, you might expect that the Interrupt disable flag would be set at its beginning. Such is not the case, however, and therefore it would be wise to execute an SEI before calling it and a CLI afterwards (as the power-on RESET routine does) just to be safe. 64816 $FD30 Table of RAM Vectors to the Default I/O Routines This table contains the 16 RAM I/O vectors that are moved to 788-819 ($314-$333). 64848 $FD50 RAMTAS Perform RAM Test and Set Pointers to the Top and Bottom of RAM This documented Kernal routine, which can be entered through location 65415 ($FF87) of the jump table, performs a number of initialization tasks. First, it clears Pages 0, 2, and 3 of memory to zeros. Next, it sets the tape buffer pointer to address 828 ($33C), and performs a nondestructive test of RAM from 1024 ($400) up. When it reaches a non-RAM address (presumably the BASIC ROM at 40960 ($A000)), that address is placed in the top of memory pointer at 643-4 ($283-4). The bottom of memory pointer at 641-2 ($281-2) is set to point to address 2048 ($800), which is the beginning of BASIC program text. Finally, the pointer to screen memory at 648 ($288) is set to 4, which lets the Operating System know that screen memory starts at 1024 ($400). 64923 $FD9B Table of IRQ Vectors This table holds the vectors to the four IRQ routines which the system uses. The first points to Part 1 of the cassette write routine at 64618 ($FC6A), the second to Part 2 of the cassette write routine at 64461 ($FBCD), the third to the standard scan keyboard IRQ at 59953 ($EA31), and the last to the cassette read routine at 63788 ($F92C). 64931 $FDA3 IOINIT Initialize CIA I/O Devices This documented Kernal routine, which can be entered through the jump table at 65412 ($FF84), intializes the Complex Interface Adapter (CIA) devices, and turns the volume of the SID chip off. As part of this initialization, it sets CIA #1 Timer A to cause an IRQ interrupt every sixtieth of a second. 65017 $FDF9 SETNAM Set Filename Parameters This is a documented Kernal routine, which can be entered through the jump table at location 65469 ($FFBD). It puts the value in the Accumulator into the location which stores the number of characters in the filename, and sets the pointer to the address of the ASCII text of the filename from the .X and .Y registers. This sets up the filename for the OPEN, LOAD, or SAVE routine. 65024 $FE00 SETLFS Set Logical File Number, Device Number, and Secondary Address This is a documented Kernal routine, which can be entered through the jump table at location 65466 ($FFBA). It stores the value in the Accumulator in the location which holds the current logical file number, the value in the .X register is put in the location that holds the current device number, and the value in the .Y register is stored in the location that holds the current secondary address. If no secondary address is used, the .Y register should be set to 255 ($FF). It is necessary to set the values of the current file number, device number, and secondary address before you OPEN a file, or LOAD or SAVE. 65031 $FE07 READST Read the I/O Status Word This is a documented Kernal routine, which can be entered through the jump table at location 65463 ($FFB7). Whenever an I/O error occurs, a bit of the Status Word is set to indicate what the problem was. The routine allows you to read the status word (it is returned in the Accumulator). If the device was the RS-232, its status register is read and cleared to zero. For the meanings of the various status codes, see the entry for location 144 ($90) or 663 ($297) for the RS-232 device. 65048 $FE18 SETMSG Set the Message Control Flag This documented Kernal routine can be entered through its jump table vector at 65424 ($FF90). The routine controls the printing of error messages and control messages by the Kernal. It Bit 6 is seto to 1 (bit value of 64), Kernal control messages can be printed. These messages include SEARCHING FOR, LOADING, and the like. If Bit 6 is cleared to 0, these messages will not be printed (BASIC will clear this bit when a program is running so that the messages do not appear when I/O is performed from a program). Setting Bit 6 will not suppress the PRESS PLAY ON TAPE or PRESS PLAY & RECORD messages, however. If Bit 7 is set to 1 (bit value of 128), Kernal error messages can be printed. If Bit 7 is set to 0, those error messages (for example, I/O ERROR #nn) will be suppressed. Note that BASIC has its own set of error messages (such as FILE NOT FOUND ERROR) which it uses in preference to the Kernal's message. 65057 $E21 SETTMO Set Time-Out Flag for IEEE Bus This documented Kernal routine can be entered fromthe jump table at 65442 ($FFA2). The routine sets the time-out flag for the IEEE bus. When timeouts are enabled, the Commodore will wait for a device for 64 milliseconds, and if it does not receive a response to its signal it will issue a time-out error. Loading the Accumulator with a value less than 128 and calling this routine will enable time-outs, while using a value over 128 will disable time-outs. This routine is for use only with the Commodore IEEE add-on card, which at the time of this writing was not yet available. 65061 $FE25 MEMTOP Read/Set Top of RAM Pointer This is a documented Kernal routine, which can be entered through the jump table at location 65433 ($FF99). It can be used to either read or set the top of RAM pointer. If called with the Carry flag set, the address in the pointer will be loaded into the .X and .Y registers. If called with the Carry flag cleared, the pointer will be changed to the address found in the .X and .Y registers. 65076 $FE34 MEMBOT Read/Set Bottom of RAM Pointer This is a documented Kernal routine, which can be entered through the jump table at location 65436 ($FF9C). It can be used to either read or set the bottom of RAM pointer. If called with the Carry flag set, the address in the pointer willbe loaded into the .X and .Y registers. If called with the Carry flag cleared, the pointer will be changed to the address found in the .X and .Y registers. 65091 $FE43 NMI Interrupt Entry Point This routine is the NMI interrupt handler entry, which is pointed to by the hardware NMI vector at 65530 ($FFFA). Any time an NMI interrupt occurs, the Interrupt disable flag will be set, and the routine will jump through the RAM vector at 792 ($318), which ordinarily points to the continuation of this routine. The standard handler first checks to see if the NMI was caused by the RS-232 device. If not, the RESTORE key is assumed. The routine checks for a cartridge, and if one is found it exits through the cartridge warm start vector at 32770 ($8002). If not, the STOP key is checked, and if it is being pressed, the BRK routine is executed. If the RS-232 device was the cause of the NMI, the cartridge and STOP key checks are bypassed, and the routine skips to the end, where it checks whether it is time to send or receive a data bit via the RS-232 device. 65126 $FE66 BRK, Warm Start Routine This routine is executed when the STOP/RESTORE combination of keypresses occurs. In addition, it is the default target address of the BRK instruction vector. This routine calls the Kernal intialization routines RESTOR, IOINIT, and part of CINT. It then exits through the BASIC warm start vector at 40962 ($A002). 65138 $FE72 NMI RS-232 Handler This is the part of the NMI handler that checks if it is time to receive or send a bit on the RS-232 channel, and takes the appropriate action if it is indeed the time. 65218 $FEC2 RS-232 Baud Rate Tables for U.S. Television Standard (NTSC) This table contains the ten prescaler values for the ten standard baud rates implemented by the RS-232 Control Register at 659 ($293). The table starts with the two values needed for the lowest baud rate (50 baud) and finishes with the entries for the highest baud rate, 2400 baud. The RS-232 routines are handled by NMI interrupts which are caused by the timers on CIA #2. Since the RS-232 device could both receive and send a bit in a single cycle, the time between interrupts should be a little less than half of the clock frequency divided by the baud rate. The exact formula used is: ((CLOCK/BAUD)/2)-100 where CLOCK is the processor clock speed and BAUD is the baud rate. The clock frequency for machines using the U.S. television standard (NTSC) is 1,022,730 cycles per second, while the frequency for the European (PAL) standard is 985,250 cycles per second. For this reason, separate baud rate tables were added for European machines at 58604 ($E4EC). 65238 $FED6 RS-232 Receive the Next Bit (NMI) The NMI handler calls this subroutine to input the next bit on the RS-232 bus. It then calls the next subroutine to reload the timer that causes the interrupts. 65306 $FF1A Load the Timer with Prescaler Values from the Baud Rate Lookup Table 65352 $FF48 Main IRQ/BRK Interrupt Entry Point The 6510 hardware IRQ/BRK vector at 65534 ($FFFE) points to this address. Anytime the BRK instruction is encountered or an IRQ interrupt occurs, this routine will be executed. The routine first saves the .A, .X, and .Y registers on the stack, and then tests the BRK bit of the status register (.P) to see if a BRK was executed. If it was, the routine exits through the RAM BRK vector at 790 ($316), where it will usually be directed to the BRK routine at 65126 ($FE66). If not, the routine exits through the RAM IRQ vector at 788 ($314), where it will usually be directed to the handler that scans the keyboard at 59953 ($EA31). If you plan to change either of these vectors to your own routine, remember to pull the stored register values off the stack before finishing. Location Range: 65371-65407 ($FF5B-$FF7F) Patches Added to Later Kernal Versions This area contains additional code not found in the original version of the Kernal. It is used to test whether a European (PAL) or U.S. (NTSC) standard monitor is used, and to compensate so that the sixtieth of a second interrupt will be accurately timed on either system. 65371 $FF5B CINT Initialize Screen Editor and VIC-II Chip This is a documented Kernal routine whose entry in the jump table is located at 65409 ($FF81). The start of the routine appears to be a patch that was added to later versions of the Kernal. It first calls the old routine at 58648 ($E518). This initializes the VIC-II chip to the default values, sets the keyboard as the input device and the screen as the output device, initializes the cursor flash variables, builds the screen line link table, clears the screen, and homes the cursor. The new code then checks the VIC Interrupt register to see if the conditions for a Raster Compare IRQ have been fulfilled. Since the Raster Register was initialized to 311, that can only occur when using a PAL system (NTSC screens do not have that many scan lines). The PAL/NTSC register at 678 ($2A6) is set on the basis of the outcome of this test. The CIA #1 Timer A is then set to cause an IRQ interrupt every sixtieth of a second, using the prescaler figures for a PAL or NTSC system, as appropriate. 65390 $FF6E End of Routine to Set Timer for Sixtieth of a Second IRQ This appears to be a patch added to compensate for the extra length of the current version of this routine, which chooses either the PAL or NTSC prescaler values for the timer. 65408 $FF80 Kernal Version Identifier Byte This last byte before the jump table can be used to identify the version of the Kernal. The first version has a 170 ($AA) stored here, while the most current version at the time of this writing has a zero in this location. The PET 64, a one-piece version with an integrated monochrome display, has an identifier byte of 100 ($64). The Commodore 64 logo uses this byte to recognize the PET 64, and adjust its display accordingly. Location Range: 65409-65525 ($FF81-$FFF5) Kernal Jump Table The following jump table is provided by Commodore in an effort to maintain stable entry points for key I/O routines. Each three-byte table entry consists of a 6510 JMP instruction and the actual address of the routine in the ROM. Although the actual address of the routine may vary from machine to machine, or in later versions of the Kernal, these addresses will stay where they are. By jumping to the entry point provided by this table, rather than directly into the ROM, you insure your programs against changes in the Operating System. In addition, this jump table may help you write programs that will function on more than one Commodore machine. The 15 table entries from 65472-65514 ($FFC0-$FFEA) are the same for all Commodore machines, from the earliest PET on. As an additional aid, some of these routines are also vectored through the table which starts at 788 ($314). Since this table is in RAM, you can change those vectors to point to your own routines which support additional I/O devices. Programs that use the jump table entry points to the I/O routines will be able to use these I/O devices without a problem. The following table will give the entry point, routine name, RAM vector if any, its current address, and a brief summary of its function. 65409 ($FF81) CINT (65371, $FF5B) initialize screen editor and video chip 65412 ($FF84) IOINIT (64931, $FDA3) initialize I/O devices 65415 ($FF87) RAMTAS (64848, $FD50) initialize RAM, tape buffer, screen 65418 ($FF8A) RESTOR (64789, $FD15) restore default I/O vectors 65421 ($FF8D) VECTOR (64794, $FD1A) read/set I/O vector table 65424 ($FF90) SETMSG (65048, $FE18) set Kernal message control flag 65427 ($FF93) SECOND (60857, $EDB9) send secondary address after LISTEN 65430 ($FF96) TKSA (60871, $EDC7) send secondary address after TALK 65433 ($FF99) MEMTOP (65061, $FE25) read/set top of memory pointer 65436 ($FF9C) MEMBOT (65076, $FE34) read/set bottom of memory pointer 65439 ($FF9F) SCNKEY (60039, $EA87) scan the keyboard 65442 ($FFA2) SETTMO (65057, $FE21) set time-out flag for IEEE bus 65445 ($FFA5) ACPTR (60947, $FE13) input byte from serial bus 65448 ($FFA8) CIOUT (60893, $EDDD) output byte to serial bus 65451 ($FFAB) UNTLK (60911, $EDEF) command serial bus device to UNTALK 65454 ($FFAE) UNLSN (60926, $EDFE) command serial bus device to UNLISTEN 65457 ($FFB1) LISTEN (60684, $ED0C) command serial bus device to LISTEN 65460 ($FFB4) TALK (60681, $ED09) command serial bus device to TALK 65463 ($FFB7) READST (65031, $FE07) read I/O status word 65466 ($FFBA) SETLFS (65024, $FE00) set logical file parameters 65469 ($FFBD) SETNAM (65017, $FDF9) set filename parameters 65472 ($FFC0) OPEN (via 794 ($31A) to 62282, $F34A) open a logical file 65475 ($FFC3) CLOSE (via 796 ($31C) to 62097, $F291) close a logical file 65478 ($FFC6) CHKIN (via 798 ($31E) to 61966, $F20E) define an input channel 65481 ($FFC9) CHKOUT (via 800 ($320) to 62032, $F250) define an output channel 65484 ($FFCC) CLRCHN (via 802 ($322) to 62259, $F333) restore default devices 65487 ($FFCF) CHRIN (via 804 ($324) to 61783, $F157) input a character 65490 ($FFD2) CHROUT (via 806 ($326) to 61898, $F1CA) output a character 65493 ($FFD5) LOAD (via 816 ($330) to 62622, $F49E) load from device 65496 ($FFD8) SAVE (via 818 ($332) to 62941, $F5DD) save to a device 65499 ($FFDB) SETTIM (63204, $F6E4) set the software clock 65502 ($FFDE) RDTIM (63197, $F6DD) read the software clock 65505 ($FFE1) STOP (via 808 ($328) to 63213, $F6ED) check the STOP key 65508 ($FFE4) GETIN (via 810 ($32A) to 61758, $F13E) get a character 65511 ($FFE7) CLALL (via 812 ($32C) to 62255, $F32F) close all files 65514 ($FFEA) UDTIM (63131, $F69B) update the software clock 65517 ($FFED) SCREEN (58629, $E505) read number of screen rows and columns 65520 ($FFF0) PLOT (58634, $E50A) read/set position of cursor on screen 65523 ($FFF3) IOBASE (58624, $E500) read base address of I/O devices Location Range: 65530-65535 ($FFFA-$FFFF) 6510 Hardware Vectors The last six locations in memory are reserved by the 6510 processor chip for three fixed vectors. These vectors let the chip know at what address to start executing machine language program code when an NMI interrupt occurs, when the computer is turned on, or when an IRQ interrupt or BRK occurs. 65530 $FFFA Non-Maskable Interrupt Hardware Vector This vector points to the main NMI routine at 65091 ($FE43). 65532 $FFFC System Reset (RES) Hardware Vector This vector points to the power-on routine at 64738 ($FCE2). 65534 $FFFE Maskable Interrupt Request and Break Hardware Vectors This vector points to the main IRQ handler routine at 65352 ($FF48). ::::::::::::::::::: :: Appendix A :: :: :: :: A Beginner's :: ::Guide to Typing:: :: In Programs :: ::::::::::::::::::: What Is a Program? A computer cannot perform any task by itself. Like a car without gas, a computer has potential, but without a program, it isn't going anywhere. Most of the programs published in this book are written in a computer language called BASIC. BASIC is easy to learn and is built into all Commodore 64s. BASIC Programs Computers can be picky. Unlike the English language, which is full of ambiguities, BASIC usually has only one right way of stating something. Every letter, character, or number is significant. A common mistake is substituting a letter such as O for the numeral 0, a lowercase l for the numeral 1, or an uppercase B for the numeral 8. Also, you must enter all punctuation such as colons and commas just as they appears in the book. Spacing can be important. To be safe, type in the listings exactly as they appear. Braces and Special Characters The exception to this typing rule is when you see the braces, such as {DOWN}. Anything within a set of braces is a special character or characters that cannot easily by listed on a printer. When you come across such a special statement, refer to Appendix B, "How to Type In Programs." About DATA Statements Some programs contain a section or sections of DATA statements. These lines provide information needed by the program. Some DATA statements contain actual programs (called machine language); others contain graphics codes. These lines are especially sensitive to errors. If a single number in any one DATA statement is mistyped, your machine could lock up, or crash. The keyboard and STOP key may seem dead, and the screen may go blank. Don't panic--no damage is done. To regain control, you have to turn off your computer, then turn it back on. This will erase whatever program was in memory, so always SAVE a copy of your program before you RUN it. If your computer crashes, you can LOAD the program and look for your mistake. Sometimes a mistyped DATA statement will cause an error message when the program is RUN. The error message may refer to the program line that READs the data. The error is still in the DATA statements, though. Get to Know Your Machine You should familiarize yourself with your computer before attempting to type in a program. Learn the statements you use to store and retrieve your programs from tape or disk. You'll want to save a copy of your program, so that you won't have to type it in every time you want to use it. Learn to use your machine's editing functions. How do you change a line if you made a mistake? You can always retype the line, but you at least need to know how to backspace. Do you know how to enter reverse video, lowercase, and control characters? It's all explained in your computer's manuals. A Quick Review 1. Type in the program a line at a time, in order. Press RETURN at the end of each line. Use backspace or the back arrow to correct mistakes 2. Check the line you've typed against the line in the book. You can check the entire program again if you get an error when you RUN the program. ::::::::::::::: ::Appendix B :: :: :: ::How to Type:: ;:In Programs:: ::::::::::::::: To make it easy to know exactly what to type when entering one of these programs into your computer, we have established the following listing conventions. Generally, Commodore 64 program listings will contain words within braces which spell out any special characters: {DOWN} would mean to press the cursor down key. {5 SPACES} would mean to press the space bar five times. To indicate that a key should be shifted (hold down the SHIFT key while pressing the other key), the key would be unterlined in our listings. For example, _S_ would mean to type the S key while holding the SHIFT key. This would appear on your screen as a heart symbol. If you find an underlined key enclosed in braces (e.g., {10 _N_}), you should type the key as many times as indicated (in our example, you would enter ten shifted N's). If a key is enclosed in special brackets, [<>], you should hold down the Commodore key while pressing the key inside the special brackets. (The Commodore key is the key in the lower-left corner of the keyboard.) Again, if the key is preceded by a number, you should press the key as many times as necessary. Rarely, you'll see a solitary letter of the alphabet enclosed in braces. These characters can be entered by holding down the CTRL key while typing the letter in the braces. For example, {A} would indicate that you should press CTRL-A. About the quote mode: You know that you can move the cursor around the screen with the CRSR keys. Sometimes a programmer will want to move the cursor under program control. That's why you see all the {LEFT}'s, {HOME}'s, and {BLU}'s in our programs. The only way the computer can tell the difference between direct and programmed cursor control is the quote mode. Once you press the quote (the double quote, SHIFT-2), you are in the quote mode. If you type something and then try to change it by moving the cursor left, you'll only get a bunch of reverse-video lines. These are the symbols for cursor left. The only editing key that isn't programmable is the DEL key; you can still use DEL to back up and edit the line. Once you type another quote, you are out of quote mode. You also go into quote mode when you INSerT spaces into a line. In any case, the easiest way to get out of quote mode is to just press RETURN. You'll then be out of quote mode and you can cursor up to the mistyped line and fix it. Use the following table when entering cursor and color control keys: When You When You Read: Press: Read: Press: [CLR] SHIFT CLR/HOME [<1>] C= 1 [HOME] CLR/HOME [<2>] C= 2 [UP] SHIFT CRSR UP/DOWN [<3>] C= 3 [DOWN] CRSR UP/DOWN [<4>] C= 4 [LEFT] SHIFT CRSR LEFT/RIGHT [<5>] C= 5 [RIGHT] CRSR LEFT/RIGHT [<6>] C= 6 [RVS] CTRL 9 [<7>] C= 7 [OFF] CTRL 0 [<8>] C= 8 [BLK] CTRL 1 [F1] F1 [WHT] CTRL 2 [F2] SHIFT F1 [RED] CTRL 3 [F3] F3 [CYN] CTRL 4 [F4] SHIFT F3 [PUR] CTRL 5 [F5] F5 [GRN] CTRL 6 [F6] SHIFT F5 [BLU] CTRL 7 [F7] F7 [YEL] CTRL 8 [F8] SHIFT F8 :::::::::::::: ::Appendix C:: :: :: :: Screen :: :: Location :: :: Table :: :::::::::::::: Row 0 1024 oooooooooooooooooooooooooooooooooooooooo 1064 oooooooooooooooooooooooooooooooooooooooo 1104 oooooooooooooooooooooooooooooooooooooooo 1144 oooooooooooooooooooooooooooooooooooooooo 1184 oooooooooooooooooooooooooooooooooooooooo 5 1224 oooooooooooooooooooooooooooooooooooooooo 1264 oooooooooooooooooooooooooooooooooooooooo 1304 oooooooooooooooooooooooooooooooooooooooo 1344 oooooooooooooooooooooooooooooooooooooooo 1384 oooooooooooooooooooooooooooooooooooooooo 10 1424 oooooooooooooooooooooooooooooooooooooooo 1464 oooooooooooooooooooooooooooooooooooooooo 1504 oooooooooooooooooooooooooooooooooooooooo 1544 oooooooooooooooooooooooooooooooooooooooo 1584 oooooooooooooooooooooooooooooooooooooooo 15 1624 oooooooooooooooooooooooooooooooooooooooo 1664 oooooooooooooooooooooooooooooooooooooooo 1704 oooooooooooooooooooooooooooooooooooooooo 1744 oooooooooooooooooooooooooooooooooooooooo 1784 oooooooooooooooooooooooooooooooooooooooo 20 1824 oooooooooooooooooooooooooooooooooooooooo 1864 oooooooooooooooooooooooooooooooooooooooo 1904 oooooooooooooooooooooooooooooooooooooooo 1944 oooooooooooooooooooooooooooooooooooooooo 24 1984 oooooooooooooooooooooooooooooooooooooooo | | | | | | | | | 0 5 10 15 20 25 30 35 39 Column :::::::::::::::: :: Appendix D :: :: :: ::Screen Color:: ::Memory Table:: :::::::::::::::: Row 0 55296 oooooooooooooooooooooooooooooooooooooooo 55336 oooooooooooooooooooooooooooooooooooooooo 55376 oooooooooooooooooooooooooooooooooooooooo 55416 oooooooooooooooooooooooooooooooooooooooo 55456 oooooooooooooooooooooooooooooooooooooooo 5 55496 oooooooooooooooooooooooooooooooooooooooo 55536 oooooooooooooooooooooooooooooooooooooooo 55576 oooooooooooooooooooooooooooooooooooooooo 55616 oooooooooooooooooooooooooooooooooooooooo 55656 oooooooooooooooooooooooooooooooooooooooo 10 55696 oooooooooooooooooooooooooooooooooooooooo 55736 oooooooooooooooooooooooooooooooooooooooo 55776 oooooooooooooooooooooooooooooooooooooooo 55816 oooooooooooooooooooooooooooooooooooooooo 55856 oooooooooooooooooooooooooooooooooooooooo 15 55896 oooooooooooooooooooooooooooooooooooooooo 55936 oooooooooooooooooooooooooooooooooooooooo 55976 oooooooooooooooooooooooooooooooooooooooo 56016 oooooooooooooooooooooooooooooooooooooooo 56056 oooooooooooooooooooooooooooooooooooooooo 20 56096 oooooooooooooooooooooooooooooooooooooooo 56136 oooooooooooooooooooooooooooooooooooooooo 56176 oooooooooooooooooooooooooooooooooooooooo 56216 oooooooooooooooooooooooooooooooooooooooo 24 56256 oooooooooooooooooooooooooooooooooooooooo | | | | | | | | | 0 5 10 15 20 25 30 35 39 Column ::::::::::::::: ::Appendix E :: :: :: :: Screen :: ::Color Codes:: ::::::::::::::: Value to POKE for Each Color Low nybble High nybble Select multicolor Color color value color value color value Black 0 0 8 White 1 16 9 Red 2 32 10 Cyan 3 48 11 Purple 4 64 12 Green 5 80 13 Blue 6 96 14 Yellow 7 112 15 Orange 8 128 -- Brown 9 144 -- Light Red 10 160 -- Dark Gray 11 176 -- Medium Gray 12 192 -- Light Green 13 208 -- Light Blue 14 224 -- Light Gray 15 240 -- Where To POKE Color Values For Each Mode Bit or Mode * bit-pair Location Color value Regular text 0 53281 Low nybble 1 Color memory Low nybble Multicolor text 00 53281 Low nybble 01 53282 Low nybble 10 53283 Low nybble 11 Color memory Select Multicolor Extended color 00 53281 Low nybble text + 01 53282 Low nybble 10 53283 Low nybble 11 53284 Low nybble Bitmapped 0 Screen memory Low nybble ++ 1 Screen memory High nybble ++ Multicolor 00 53281 Low nybble bitmapped 01 Screen memory High nybble ++ 10 Screen memory Low nybble ++ 11 Color memory Low nybble * For all modes, the screen border color is controlled by POKEing location 53280 with the low nybble color value. + In exteded color mode, Bits 6 and 7 of each byte of screen memory serve as the bit-pair controlling background color. Because only Bits 0-5 are available for character selection, only characters with screen codes 0-63 can be used in this mode. ++ In the bitmapped modes, the high and low nybble color values are ORed together and POKEd into the same location in memory to control the colors of the corresponding cell in the bitmap. For example, to control the colors of cell 0 of the bitmap, OR the high and low nybbles and POKE the result into location 0 of screen memory. ::::::::::::::: ::Appendix F :: :: :: ::ASCII Codes:: ::::::::::::::: [*** OMITTED ***] [widely available elsewhere; not suitable for textual formatting] :::::::::::::::: :: Appendix G :: :: :: ::Screen Codes:: :::::::::::::::: [*** OMITTED ***] [widely available elsewhere; not suitable for textual formatting] ::::::::::::::: ::Appendix H :: :: :: :: Commodore :: ::64 Keycodes:: ::::::::::::::: Key Keycode Key Keycode A 10 6 19 B 28 7 24 C 20 8 27 D 18 9 32 E 14 0 35 F 21 + 40 G 26 - 43 H 29 LIRA 48 I 33 CLR/HOME 51 J 34 INST/DEL 0 K 37 LEFT ARROW 57 L 42 @ 46 M 36 * 49 N 39 ^ 54 O 38 : 45 P 41 ; 50 Q 62 = 53 R 17 RETURN 1 S 13 , 47 T 22 . 44 U 30 / 55 V 31 CRSR UP/DN 7 W 9 CRSR LF/RT 2 X 23 F1 4 Y 25 F3 5 Z 12 F5 6 1 56 F7 3 2 59 SPACE 60 3 8 RUN/STOP 63 4 11 NO KEY 5 16 PRESSED 64 The keycode is the number found at location 197 for the current key being pressed. Try this one-line program: 10 PRINT PEEK(197):GOTO 10 :::::::::::::: :: Index :: :: :: ::(by memory:: :: location):: :::::::::::::: ABS 48216 AND 45033 ASC 46987 ATN 58126 BASIC adding new commands 115,768 current line number 57 execution of statements 776,42980 expression evaluation 778, 44446, 44675 function evaluation 44967 pointer to bottom of string text 51 pointer to current data item address 65 pointer to current statement address 61 pointer to end of array storage 49 pointer to start of array storage 47 pointer to start of program text 43 pointer to start of variable storage 45 pointer to top of BASIC RAM 55 program text storage 2048 RAM vector table 768 Buffer cassette I/O buffer 178, 828 keyboard buffer 198, 631 RS-232 input buffer 247 RS-232 output buffer 249 text input buffer 512 cartridge, autostart ROM 32768 cassette data output line 01 I/O buffer 828 Kernal ROM routines 63466-64737 motor control 01, 192 switch sense 01 character generator ROM 01, 4096, 36864, 53248 charcter graphics 53248 CHAREN 01 CHRGET 115, 58274 CHR$ 46828 CIA (Complex Interface Adapter) CIA #1 56320-56335 CIA #2 56576-56591 data direction registers 56322, 56323, 56578, 56579 data ports 56320, 56321, 56576, 56577 timers 56334, 56335, 56590, 56591 clock clock speed (6510 microprocessor) 56334 software clock 160 Time of Day clock 56328, 56584 CLOSE 57799 CLR 42590 CMD 43654 cold start, BASIC 40960, 58260 color background 53281 border (frame) 53280 color codes 646 color RAM nybbles 55296 current character color 646 multicolor background registers 53282, 53283 PETASCII color change characters 59601 sprite color registers 53287-53294 sprite multicolor registers 53285, 53286 CONT 43095 COS 57956 DATA 43256 data direction register 00, 56322, 56323, 56578, 56579 data port 01, 56320, 56321, 56576, 56577 DEF 46003 DIM 45185 dynamic keyboard 198, 631 error BASIC error handler 768, 42039, 58251 error message control flag 157 I/O error status 144 RS-232 I/O error status 663 EXP 49133 expression evaluation 778, 44446, 44675 floating point addition 47207, 47210 division 47887, 47890 fixed-floating point conversion 05, 45969 floating-fixed point conversion 03, 45482, 45503 Floating Point Accumulators 97, 110 floating point-ASCII conversion 48605 multiplication 47656, 47667 subtraction 47194, 47194 FN 46068 FOR 42818 FRE 45949 garbage collection, string variable 46374 GET, GET# 43899 GOSUB 43139 GOTO 43168 graphics bitmapped graphics 53265 character graphics 53248 extended background color mode 53265 fine scrolling 53265, 43271 multicolor mode 53271 raster position 53265, 53266 screen blanking 53265 sprites SEE sprite graphics HIRAM 01 IF 43304 INT 48332 interrupt CIA hardware FLAG line 56589, 56333 CIA serial shift register 56589, 56333 CIA Time of Day clock alarm 56589, 56333 CIA Timers A and B 56589, 56333 IRQ handler 59953, 65352 IRQ vector 788, 65534 light pen IRQ 53273, 53274 NMI handler 65091 NMI vector 792, 65530 raster compare IRQ 53266, 53273, 53274 sprite-display data collision IRQ 53273, 53275 sprite-sprite collision IRQ 53273, 53275 INPUT 43967 INPUT# 43941 I/O current device number 186 current filename address 187 current filename length 183 current input device 153 current I/O channel number 19 current logical file number 184 current output device 154 current secondary address 185 device number table 611 logical file table 601 number of I/O files open 152 RS-232 status 663 secondary address table 621 status word codes 144 joystick controllers 56320, 56321 Kernal jump table 65409 RAM vector table 794 ACPTR 60947, 65445 CHKIN 798, 61966, 65478 CHKOUT 800, 62032, 65481 CHRIN 804, 61783, 65487 CHROUT 806, 61898, 65490 CINT 65371, 65409 CIOUT 60893, 65448 CLALL 812, 62255, 65511 CLOSE 796, 62097, 65475 CLRCHN 802, 62259, 65484 GETIN 810, 61758, 65508 IOBASE 58624, 65523 IOINIT 64931, 65412 LISTEN 60684, 65457 LOAD 816, 62622, 65493 MEMBOT 65076, 65436 MEMTOP 65061, 65433 OPEN 794, 62282, 65472 PLOT 58634, 65520 RAMTAS 64848, 65415 RDTIM 63197, 65502 READST 65031, 65463 RESTOR 64789, 65418 SAVE 818, 62941, 65496 SCNKEY 60039, 65439 SCREEN 58629, 65517 SECOND 60857, 65427 SETLFS 65024, 65466 SETMSG 65048, 65424 SETNAM 65017, 65469 SETTIM 63204, 65499 SETTMO 65057, 65442 STOP 808, 63213, 65505 TALK 60681, 65460 TKSA 60871, 65430 UDTIM 63131, 65514 UNLSN 60926, 65454 UNTLK 60911, 65451 VECTOR 64794, 65421 keyboard current key pressed 203 keyboard buffer 631 keycodes 203 keyboard matrix 245, 655, 56321 last key pressed 197 number of characters in buffer 198 pointer to matrix lookup table 245 reading the keyboard 56320 repeating keys 650 LEFT$ 46848 LEN 46972 LET 43429 light pen 53267, 53268 LIST 42652 LOAD 57704 LORAM 01 MID$ 46903 NEW 42562 NEXT 44318 NMI 65095 ON GOSUB, ON GOTO 43339 OPEN 57790 Operating System (OS) OS end of RAM pointer 643 OS screen memory pointer 648 OS start of RAM pointer 641 OR 45030 paddle controllers 54297, 54298 paddle fire button 56320, 56321 PAL/NTSC flag 678 PEEK 47117 POKE 47140 POS 45982 PRINT 43680 PRINT# 43648 program text area 43, 2048 program text input buffer 512 RAM BASIC pointer to end of RAM 55 RAM/ROM selection 01 OS pointer to end of RAM 643 OS pointer to start of RAM 641 random number generator 54299 READ 44038 registers, reading/setting from BASIC 780 REM 43323 RESER, power-on 64738, 65532 reset, VIC-II chip 53270 RESTORE 43037 RESTORE key, disabling 792, 808 RETURN 43218 RIGHT$ 46892 RND 139, 57495 RS-232 baud rate 659, 661, 665 baud rate tables 58604, 65218 buffers 247, 249 command register 660 connector pin assignments 56576, 56577 control register 659 duplex mode 660 handshaking protocol 660 Kernal ROM routines 57344-65535 parity 660 status register 663 stop bits 659 word length 659 RUN 43121 SAVE 57686 screen editor current character color 646 cursor color RAM position 243 cursor flash 204, 205, 207 cursor maintenance 206, 647 cursor screen position 209, 211, 214 insert mode flag 216 key repeat 650, 651, 652 quote mode flag 212 reverse character flag 199 screen line link table 217 screen RAM 1024, 648, 53272 shift flag 653, 654 Serial Bus I/O 56576, 60681-61114 Serial Data Port (CIA) 56332, 56588 SGN 48185 SID chip register 54272-54300 SEE ALSO sound SIN 57960 sound ADSR envelope control 54278-54279, 54285-54286, 54292-54293 filtering 54293-54296 frequency (pitch) control 54272-54273, 54279-54280, 54286-54287 gate bit 54276 Oscillator 3 envelope generator 54300 Oscillator 3 output 54299 pulse waveform pulse width 54274-54275, 54281-54282, 54288-54289 ring modulation 54276, 54283, 54290 synchronization (hard sync) 54276, 54283, 54290 volume control 54296 waveform control 54276, 54283, 54290 sprite graphics color registers 53287-53294 display priority 53275 enabling sprite display 53274 horizontal expansion 53277 multicolor color registers 53285-53286 multicolor sprites 53276 position registers 53248-53264 shape data pointers 2040 sprite-display data collision detection 53279 sprite-sprite collision detection 53278 vertical expansion 53271 SQR 49009 ST (I/O status word) 144 stack, 6510 microprocessor 256 STOP 43055 STOP key 145, 808 STR$ 46181 SYS 780, 57642 TAN 56083 Time of Day clock 56328-56331, 56584-56587 timers, hardware 56324-56327, 56334-56335, 56580-56583, 56590-56591 tokens, keyword 772, 774, 40972, 41042, 41088, 41118, 42364, 42772 User Port 56567-56577 USR 785 VAL 47021 variable array variable storage 47 find or create variable routine 45195 storage format 45 string text area 51 VERIFY 57701 VIC-II CHIP memory bank switching 56576 registers 53248-53294 SEE ALSO graphics, sprite graphics warm start, BASIC 40962, 58235 WAIT 47149 wedges 115 ********* End Project 64 etext Mapping The Commodore 64. *********