NEWS, EDITORIALS, REFERENCE
C64 KERNAL ROM: Making Sense
The KERNAL is the heart of the Commodore 8-Bit computer family. Although each machine's KERNAL is slightly different, there is also substantial overlap in code and design.
The C64's KERNAL provides a standard jump table with 39 routines from $FF81 and $FFF3. The order of the entries in the jump table is stable, but not particularly logically organized. Most websites and books, including the C64 Programmers Reference Guide, list the routines in alphabetical order, or in the order in which they appear in the jump table. This makes it easy to find the details of any routine, if you already know which routine you want to use, but it can often lead to confusion trying to understand the relationship between the routines. Especially because many of them have similar sounding names, and in some cases similar functionality.
To improve clarity, and facilitate understanding of how the KERNAL should be used, I have grouped the routines into 7 conceptual KERNAL modules, shown in the table below.
C64 OS provides includable assembly headers which define labels for the KERNAL routines in each module. C64 OS itself is an extension of the KERNAL, and relies on the KERNAL for many tasks. For example, C64 OS's File module adds a thin abstraction layer over the KERNAL's file table and logical file numbering system. A C64 OS application that makes use of C64 OS File References can extract the logical file number from the file and use it to make manual KERNAL calls. The relationship of the KERNAL ROM to C64 OS, including a compatibility table, is discussed at the end of this post.
KERNAL Modules
Module | Routines | Include |
---|---|---|
File | 6 | ker_file.s |
I/O | 8 | ker_io.s |
IEC | 9 | ker_iec.s |
Memory | 6 | ker_mem.s |
Keyboard | 3 | ker_key.s |
Screen | 4 | ker_scr.s |
Time | 3 | ker_tim.s |
I have never seen the routines grouped as these 7 modules before, but to me, they most logically and thematically fall into these groupings, which helps to understand how to use them.
File (6 Routines)
Among other things, the KERNAL recognizes 6 device types. Two of those device types, the Keyboard and Screen, it implements directly. And it provides implementations of the communications protocols with the other devices which may or may not be connected to the computer.
Each device is referenced by a unique device number, from 0 to 30. Device types are recognized by their fixed address or the address range they fall within. Some devices also support a secondary address, which is used to send it low-level commands.
Devices Table
Device | I/O | Device Number | Secondary Address |
---|---|---|---|
Keyboard | Input | 0 | — |
Datasette | Both | 1 | 0, 1, 2 |
RS232 | Both | 2 | — |
Screen | Both | 3 | — |
Printers | Output | 4, 5 | 0, 7 |
Plotters | Output | 6, 7 | — |
Disk Drives | Both | 8... 30 | 0, 1, 2... 14, 15 |
The KERNAL provides a thin abstraction layer to reference devices, and in some cases subdivisions of a device. The abstract entity is called a logical file. Commodore may have been influenced by Unix, which treats everything—including devices—as files. On some devices, such as a Datasette or Disk Drive, logical files can also be associated with actual files, which are named collections of data stored on physical media.
The 4 main File routines allow you to open and close logical files by associating them with an underlying physical device, and optionally with a secondary address on that device. Each logical file is assigned a unique file number from 1 to 127. The KERNAL supports opening up to 10 logical files simultaneously.
There are 2 additional File routines that allow you to load and save data to and from Datasette or Disk Drive, to and from memory. Attempting to load or save to or from any other device type results in an Illegal Device Number error.
Routine | Description | Routine | Description | |
---|---|---|---|---|
SETLFS | Set logical file number, device number and secondary address | OPEN | Open logical file | |
SETNAM | Set filename or command string | CLOSE | Close logical file | |
LOAD | Load data from disk/tape into memory, or Verify data on disk/tape with memory |
SAVE | Save memory to disk/tape |
File Routines
Description | Set logical file number, device number and secondary address |
---|---|
Jump addr | $FFBA |
Vector addr | — |
Real code | $FE00 |
Stack use | 2 |
Entry | A → logical file number X → device number Y → secondary address |
Use | A/X/Y |
Return | — |
Description | Set filename or command string |
---|---|
Jump addr | $FFBD |
Vector addr | — |
Real code | $FDF9 |
Stack use | 0 |
Entry | A → string length X/Y → pointer to string |
Use | A/X/Y |
Return | — |
Description | Load or Verify data |
---|---|
Setup | SETLFS, SETNAM |
Jump addr | $FFD5 |
Vector addr | $0330 |
Real code | $F49E |
Stack use | 0 |
Entry | A → load=0, verify=1 If secondary address = 0, X/Y → pointer to start address |
Use | A/X/Y |
Return | X/Y ← pointer to last byte loaded C ← error=1 If error, A ← error number |
Description | Open logical file |
---|---|
Setup | SETLFS, SETNAM |
Jump addr | $FFC0 |
Vector addr | $031A |
Real code | $F34A |
Stack use | 0 |
Entry | — |
Use | A/X/Y |
Return | C ← error=1 If error, A ← error number |
Description | Close logical file |
---|---|
Jump addr | $FFC3 |
Vector addr | $031C |
Real code | $F291 |
Stack use | 0 |
Entry | A → logical file number |
Use | A/X/Y |
Return | — |
Description | Save memory to disk/tape |
---|---|
Setup | SETLFS, SETNAM |
Jump addr | $FFD8 |
Vector addr | $0332 |
Real code | $F5DD |
Stack use | 0 |
Entry | A → ZP pointer to start address X/Y → End address |
Use | A/X/Y |
Return | C ← error=1 If error, A ← error number |
I/O (8 Routines)
The KERNAL operates on a general design principle; data is streamed from the system's input channel to the output channel. Opened logical files (see File Module) are assigned to the input and output channels. Attempting to assign an input-only device to the output channel or vice versa results in an error. (See Devices Table)
The default configuration assigns the keyboard as the input device and the screen as the output device. This is why, when a C64 is turned on, typing on the keyboard results in characters appearing on the screen.
The 8 routines in the I/O KERNAL module assign logical files to channels, read and write bytes to and from the channels, check for channel status messages and restore default channel assignments.
Routine | Description | Routine | Description | |
---|---|---|---|---|
CHKIN | Assign the current input channel | CHRIN | Read byte from input channel | |
CHKOUT | Assign the current output channel | CHROUT | Write byte to output channel | |
CLRCHN | Restore default I/O channels | CLALL | Close all files, restore default I/O channels | |
READST | Read I/O status byte | IOINIT | Initialize CIA & IRQ |
Status Values
Hex | Bit | Serial I/O | Tape I/O |
---|---|---|---|
$80 | 7 | Device Not Present | — |
$40 | 6 | EOI status | End of file |
$20 | 5 | — | Checksum error |
$10 | 4 | Verify error | Unrecoverable read error |
$08 | 3 | — | Long block |
$04 | 2 | — | Short block |
$02 | 1 | Read timeout | — |
$01 | 0 | Write timeout | — |
I/O Routines
Description | Assign the current input channel |
---|---|
Setup | OPEN |
Jump addr | $FFC6 |
Vector addr | $031E |
Real code | $F20E |
Stack use | 0 |
Entry | X → logical file number |
Use | — |
Return | — |
Description | Assign the current output channel |
---|---|
Setup | OPEN |
Jump addr | $FFC9 |
Vector addr | $0320 |
Real code | $F250 |
Stack use | 0 |
Entry | X → logical file number |
Use | — |
Return | — |
Description | Restore default I/O channels |
---|---|
Jump addr | $FFCC |
Vector addr | $0322 |
Real code | $F333 |
Stack use | 9 |
Entry | — |
Use | A/X |
Return | — |
Description | Read I/O status byte |
---|---|
Jump addr | $FFB7 |
Vector addr | — |
Real code | $FE07 |
Stack use | 2 |
Entry | — |
Use | A |
Return | A ← status byte |
Description | Read byte from input channel |
---|---|
Setup | CHKIN (optional) |
Jump addr | $FFCF |
Vector addr | $0324 |
Real code | $F147 |
Stack use | 0 |
Entry | — |
Use | A/Y |
Return | A ← byte read |
Description | Write byte to output channel |
---|---|
Setup | CHKOUT (optional) |
Jump addr | $FFD2 |
Vector addr | $0326 |
Real code | $F1CA |
Stack use | 0 |
Entry | A → byte to write |
Use | — |
Return | C ← error=1 ST ← error number |
Description | Close all files, restore default I/O channels |
---|---|
Jump addr | $FFE7 |
Vector addr | $032C |
Real code | $F32F |
Stack use | 11 |
Entry | — |
Use | A/X |
Return | — |
Description | Initialize CIA & IRQ |
---|---|
Jump addr | $FF84 |
Vector addr | — |
Real code | $FDA3 |
Stack use | 0 |
Entry | — |
Use | A/X/Y |
Return | — |
IEC (9 Routines)
A major part of the KERNAL is dedicated to IEC serial bus communications. The IEC bus is a variant of IEEE-488, used by Commodore, which you can read about here. The bus allows multiple devices to be chained together to one C64, in a master/slave arrangement. The C64 is the master, which tells individual slave devices when to talk and when to listen.
All device numbers from 4 to 30 are assigned to the IEC serial bus, although this can be overridden by use of the vectors specified for routines in the File and I/O KERNAL modules.
Each device must have its unique device number manually configured. In addition to the device number, the IEC protocol can send a secondary address and command string, the meaning and use of which are device specific. The 9 IEC KERNAL routines implement this protocol by timed manipulation of CIA 2. It is rarely necessary to use any of these calls directly, as they are abstracted and called automatically by higher-level routines in the File and I/O KERNAL modules.
For maximum device compatibility, direct use of these routines should be avoided, unless the device type is detected and determined to actually reside on the physical IEC bus.
Routine | Description | Routine | Description | |
---|---|---|---|---|
TALK | Command an IEC device to talk | LISTEN | Command an IEC device to listen | |
TALKSA | Specify the talking device's secondary address | SECOND | Specify the listening device's secondary address | |
UNTLK | Command IEC devices to stop talking | UNLSN | Command IEC devices to stop listening | |
ACPTR | Read one byte from talking device | CIOUT | Write one byte to listening device | |
SETTMO | Toggle IEC BUS timeout |
IEC Routines
Description | Command an IEC device to talk |
---|---|
Jump addr | $FFB4 |
Vector addr | — |
Real code | $ED09 |
Stack use | 0 |
Entry | A → device number |
Use | A |
Return | — |
Description | Send secondary address after talk |
---|---|
Setup | TALK |
Jump addr | $FF96 |
Vector addr | — |
Real code | $EDC7 |
Stack use | 0 |
Entry | A → secondary address |
Use | A |
Return | — |
Description | Command IEC devices to stop talking |
---|---|
Jump addr | $FFAB |
Vector addr | — |
Real code | $EDEF |
Stack use | 0 |
Entry | — |
Use | A |
Return | — |
Description | Read one byte from talking device |
---|---|
Setup | TALKSA |
Jump addr | $FFA5 |
Vector addr | — |
Real code | $EE13 |
Stack use | 13 |
Entry | — |
Use | A |
Return | A ← byte C ← error=1 ST ← error number |
Description | Command an IEC device to listen |
---|---|
Jump addr | $FFB1 |
Vector addr | — |
Real code | $ED0C |
Stack use | 0 |
Entry | A → device number |
Use | A |
Return | — |
Description | Specify the listening device's secondary address |
---|---|
Setup | LISTEN |
Jump addr | $FF93 |
Vector addr | — |
Real code | $EDB9 |
Stack use | 0 |
Entry | A → secondary address |
Use | A |
Return | — |
Description | Command IEC devices to stop listening |
---|---|
Jump addr | $FFAE |
Vector addr | — |
Real code | $EDFE |
Stack use | 0 |
Entry | — |
Use | A |
Return | — |
Description | Write one byte to listening device |
---|---|
Setup | SECOND |
Jump addr | $FFA8 |
Vector addr | — |
Real code | $EDDD |
Stack use | 0 |
Entry | A → byte |
Use | — |
Return | C ← error=1 ST ← error number |
Description | Toggle IEC BUS timeout |
---|---|
Jump addr | $FFA2 |
Vector addr | — |
Real code | $FE21 |
Stack use | 0 |
Entry | A bit7 → enable=0 A bit7 → disable=1 |
Use | A |
Return | A |
MEMORY (6 Routines)
The memory map differs between the various Commodore 8-Bit computers. They have different amounts of ram and their I/O chips reside at different places. Additionally, BASIC is by default configured to use as much free memory as is available.
These 6 Memory routines allow you to reliably locate where the I/O chips are mapped, test and determine the quantity of RAM available, configure how much and in what range of that RAM BASIC should use. It also helps you to configure the KERNAL's ram vectors, by backing them up, replacing them with a custom table, and restoring them to defaults.
Routine | Description | Routine | Description | |
---|---|---|---|---|
MEMTOP | Read/set top of BASIC memory | VECTOR | Read/set I/O vectors | |
MEMBOT | Read/set bottom of BASIC memory | RESTOR | Restore default I/O vectors | |
RAMTAS | RAM test and search memory end | IOBASE | Read the base address of I/O chips |
Memory Routines
Description | Read/set top of BASIC memory |
---|---|
Jump addr | $FF99 |
Vector addr | — |
Real code | $FE25 |
Stack use | 2 |
Entry | C → read memtop=1 C → set memtop=0 If set memtop X/Y → pointer to memory top |
Use | X/Y |
Return | If read memtop X/Y ← pointer to memory top |
Description | Read/set bottom of BASIC memory |
---|---|
Jump addr | $FF9C |
Vector addr | — |
Real code | $FE34 |
Stack use | 0 |
Entry | C → read membot=1 C → set membot=0 If set membot X/Y → pointer to memory bottom |
Use | X/Y |
Return | If read membot X/Y ← pointer to memory bottom |
Description | RAM test and search memory end |
---|---|
Jump addr | $FF87 |
Vector addr | — |
Real code | $FD50 |
Stack use | 0 |
Entry | — |
Use | A/X/Y |
Return | Sets pointer to tape buffer Sets the screen memory page Sets pointers to start and end of memory |
Description | Read/set I/O vectors |
---|---|
Jump addr | $FF8D |
Vector addr | — |
Real code | $FD1A |
Stack use | 2 |
Entry | C → memory table to vectors=0 C → vectors to memory table=1 X/Y → pointer to memory table |
Use | A/Y |
Return | — |
Description | Restore default I/O vectors |
---|---|
Jump addr | $FF8A |
Vector addr | — |
Real code | $FD15 |
Stack use | 2 |
Entry | — |
Use | — |
Return | Vector table is restored from ROM |
Description | Read the base address of I/O chips |
---|---|
Jump addr | $FFF3 |
Vector addr | — |
Real code | $E500 |
Stack use | 2 |
Entry | — |
Use | X/Y |
Return | X/Y ← Pointer to CIA 1 ($DC00) |
KEYBOARD (3 Routines)
A C64 has a built-in keyboard, however it is just a matrix of switches connected to Ports A and B of CIA 1. (See How the C64 Keyboard Works.) The KERNAL implements all of the software routines necessary to make the keyboard a device. The matrix scanning routine is part of the KERNAL's IRQ interrupt service routine, which converts key presses into PETSCII characters and stores them in the 10-byte keyboard buffer ($0277–$0280).
RS-232 shares some properties in common with the keyboard. Namely, there is no custom RS-232 hardware, there is only CIA 2 which is connected to the user port. All RS-232 behavior is implemented by software routines provided by the KERNAL and the NMI interrupt service routine. Similarly to the keyboard buffer, the KERNAL puts incoming RS-232 bytes into a buffer in memory. The location of the RS-232 buffer, though, can be configured.
There are two routines for reading a byte from the input channel, GETIN and CHRIN. These routines have different behavior and different error conditions depending on the input device. GETIN has unique behavior only for the keyboard (Device 0) and RS-232 (Device 2). For all other devices, GETIN is merely an alias to CHRIN. Therefore, I have chosen to categorize GETIN in the keyboard KERNAL module, even though it can also be used with RS-232, or even with the other devices.
When GETIN is used with the keyboard as the input device, it returns the next character waiting in the keyboard buffer. If the buffer is empty, it returns 0 (ASCII NULL). It works the same way for RS-232, returning the next byte in the RS-232 buffer, or 0 if the buffer is empty. Using CHRIN with the keyboard enters a special routine that is used primarily by BASIC for getting data for INPUT statements. When BASIC calls CHRIN to input from the keyboard, the keyboard buffer is continuously output to the screen until return is pressed. This allows the user to populate an entire line buffer (80 characters) before the data is processed.
Routine | Description | Routine | Description | |
---|---|---|---|---|
GETIN | Read a byte from the input channel | SCNKEY | Scan the keyboard matrix | |
STOP | Check the stop key |
Keyboard Routines
Description | Read a byte from the input channel |
---|---|
Jump addr | $FFE4 |
Vector addr | $032A |
Real code | $F13E |
Stack use | 0 |
Entry | — |
Use | A/X/Y |
Return | If Keyboard or RS-232 A ← next byte in buffer or 0 if buffer is empty. If any other device, see CHRIN. |
Description | Check the stop key |
---|---|
Jump addr | $FFE1 |
Vector addr | $0328 |
Real code | $F6ED |
Stack use | 0 |
Entry | — |
Use | A (X if STOP is used) |
Return | Z ← stop pressed=1 Z ← stop not pressed=0 Closes open channels by calling CLRCHN. |
Description | Scan the keyboard matrix |
---|---|
Jump addr | $FF9F |
Vector addr | — |
Real code | $EA87 |
Stack use | 0 |
Entry | — |
Use | A/X/Y |
Return | — |
SCREEN (4 Routines)
Just as the keyboard is transformed into a device by routines in the KERNAL, so is the screen. The VIC-II chip, when in character mode, merely renders whatever screencodes are in the 1000 bytes of screen memory, with the 1000 bytes of color data in color memory.
A non-trivial amount of code in the KERNAL is devoted to implementing the screen editor. The screen editor consists of a table of 80-column logical lines which are drawn and moved through screen memory. Positioning of the cursor, inserting new characters in a line, manipulating color memory, PETSCII control codes, and insertion, quotation and reverse modes, are all part of the screen editor.
The screen editor maintains a positional cursor, which allows the screen to be abstracted into a generic I/O device. Reading a byte from the screen finds the screencode at the position of the cursor, and converts and returns its PETSCII equivalent, then advances the cursor. Writing to the screen as a device works similarly. Writing a PETSCII character converts the character to a screencode, and will reverse it if reverse mode is on, and then outputs the character to screen memory at the position of the cursor, then advances the cursor.
The 4 SCREEN routines are used to initialize the screen, reads its dimensions (which vary depending on the Commodore 8-Bit computer), read and move the cursor, and enable or disable the messages (two different types) that the KERNAL prints to the screen as user feedback.
Routine | Description | Routine | Description | |
---|---|---|---|---|
CINT | Initialize the screen | PLOT | Read/set cursor position | |
SCREEN | Read screen dimensions in cols/rows | SETMSG | Configure output of KERNAL messages |
Screen Routines
Description | Initialize the screen |
---|---|
Jump addr | $FF81 |
Vector addr | — |
Real code | $FF5B |
Stack use | 0 |
Entry | — |
Use | A/X/Y |
Return | Initializes VIC-II registers Clears the screen Initializes screen line table Initializes main interrupt timer |
Description | Read screen dimensions in cols/rows |
---|---|
Jump addr | $FFED |
Vector addr | — |
Real code | $E505 |
Stack use | 2 |
Entry | — |
Use | X/Y |
Return | X ← Columns (40) Y ← Rows (25) |
Description | Read/set cursor position |
---|---|
Jump addr | $FFF0 |
Vector addr | — |
Real code | $E50A |
Stack use | 2 |
Entry | C → Set=0 C → Get=1 X → Row Y → Column |
Use | X/Y |
Return | X ← Row Y ← Column |
Description | Configure output of KERNAL messages |
---|---|
Jump addr | $FF90 |
Vector addr | — |
Real code | $FE18 |
Stack use | 0 |
Entry | A → bit7=1 error messages on A → bit6=1 control messages on |
Use | A |
Return | — |
TIME (3 Routines)
The KERNAL keeps track of time using a 3-byte Jiffy Clock. A Jiffy is a short unit of time, in computing normally the length of time between two ticks of the system timer interrupt, or in electronics the cycle period of the AC mains. On an NTSC C64 (not sure about PAL), CIA 1 is configured to produce an interrupt every 1/60th of a second, which corresponds closely with the screen refresh rate and the cycle period of North American AC power. On every interrupt, the Jiffy Clock is ticked up. When it reaches the equivalent of 24 hours worth of jiffies, it is reset to zero.
There is a bug in the timer which, even if left to run under perfect conditions, would lose one Jiffy (1/60th of a second) per 24 hour period. In practice, this is completely irrelevant because the Jiffy Clock stops ticking entirely any time the IRQ is temporarily masked. Despite this general unreliability as a realtime clock, the Jiffy Clock is useful in a variety of small ways.
The 3 TIME routines allow you to read and set the Jiffy Clock. And, if you reimplement the IRQ interrupt service routine, calling UDTIM in your ISR will tick the Jiffy Clock. The STOP routine, in the Keyboard KERNAL module, does not scan the keyboard. It checks a stop key flag. This flag is set by the UDTIM routine. If UDTIM is not being regularly called, therefore, STOP will not work as expected.
Routine | Description | Routine | Description | |
---|---|---|---|---|
SETTIM | Set the Jiffy Clock | RDTIM | Read the Jiffy Clock | |
UDTIM | Tick the Jiffy Clock up |
Time Routines
Description | Set the Jiffy Clock |
---|---|
Jump addr | $FFDB |
Vector addr | — |
Real code | $F6E4 |
Stack use | 2 |
Entry | A → Most Significant Byte X → Middle Significant Byte Y → Least Significant Byte |
Use | A/X/Y |
Return | — |
Description | Tick the Jiffy Clock up |
---|---|
Jump addr | $FFEA |
Vector addr | — |
Real code | $F69B |
Stack use | 0 |
Entry | — |
Use | A/X |
Return | — |
Description | Read the Jiffy Clock |
---|---|
Jump addr | $FFDE |
Vector addr | — |
Real code | $F6DD |
Stack use | 2 |
Entry | — |
Use | A/X/Y |
Return * | A ← Least Significant Byte X ← Middle Significant Byte Y ← Most Significant Byte |
* NOTE: The Jiffy Clock is stored in three zero page addresses: $A0, $A1 and $A2. RDTIM loads the accumulator from $A2, the X register from $A1, and the Y register from $A0. Usually multi-byte numbers are stored little endian on the C64. However, the Jiffy Clock is stored big endian.
The C64 Programmer's Reference Guide erroneously states that RDTIM puts the most significant byte in the accumulator.
The KERNAL and C64 OS
The C64's KERNAL ROM is used by C64 OS. The default state expects the KERNAL to be patched in. However you are free to patch it out at any time, and are not required mask IRQs when you do so. In fact, it would detrimental to mask IRQs unless you absolutely have to. C64 OS will automatically patch the KERNAL back in during the IRQ service routine, and restore its state upon returning to your code. However, if you patch the KERNAL out, you are required to patch it back in before returning to or calling system code, as the rest of the system expects it to be patched in.
Despite using the KERNAL, parts of it are irrelevant under C64 OS, and parts of it have been superseded by newer implementations in the C64 OS KERNAL.
FILE
The FILE module is used pretty much as normal. The C64 OS File module provides a thin wrapper around most of these calls. When using LOAD, you have to be careful that the data loaded in will not overwrite memory that is already allocated. If you do use LOAD carefully, you must also use the C64 OS Memory routine PGMARK to mark as allocated the pages of memory that were loaded into.
I/O
The I/O module is used almost the same in C64 OS. It is unsafe to use CLALL, however, as you cannot be sure that a Utility, or the System itself, does not have a file open. If you call CLALL, all files will be closed but their corresponding C64 OS file references will be left marked as open, with invalid Logical File Numbers assigned to them.
You should also never call IOINIT, as this would change the configuration of the CIA and IRQ handler and likely crash the system. C64 OS provides a clean way to quit back to BASIC.
IEC
The IEC routines interact explicitly with the IEC bus. For maximum compatibility with other drive types, these routines should be avoided. For example, the IDE64 programming documentation states that you must not use any of these routines. For C64 OS, I would follow that practice. C64 OS routines never call these routines, prefering to call FILE and I/O routines instead.
There is, however, a way to use these routines safely. C64 OS maintains a detected drives table, containing device numbers corresponding with detected physical drive types (1541, 1571, 1581, CMD HD, CMD RamLink, CMD FD, IDE64, SD2IEC, etc.) If you consult that table, and determine that the drive is on the IEC bus, it's reasonably safe and compatible to use these IEC specific routines.
MEMORY
This part of the KERNAL is more or less irrelevant. MEMTOP and MEMBOT are specifically for configuring what BASIC can use. RAMTAS is called as part of starting up and resetting a C64. IOBASE only made sense for maintaining BASIC program compatibility between different Commodore 8-Bit computers. IOBASE on a C64 hasn't changed in 35 years, and isn't going to change any time soon. RESTOR should not be used, as C64 OS overrides some of the KERNAL's vectors. Restoring these to their defaults will cause problems. If you are careful and know what you're doing, you can use VECTOR, although it is recommended to use VECTOR to backup the current VECTOR table first, before using it to replace them with your own.
The KERNAL ROM's memory module is mostly irrelevant, not because memory management has become less important, but because C64 OS provides a Memory module that is significantly more sophisticated, which entirely supersedes these KERNAL routines.
KEYBOARD
The KERNAL ROM has only very basic support for input devices. It does not provide input drivers for anything on the two built-in controller ports. It does not provide input for joysticks or mice, and its keyboard input system is limited only to populating the keyboard buffer with PETSCII values. If two keyboard combinations resolve to the same PETSCII value (Control M and RETURN both resolve to $0D), there is no way to distinguish the two.
C64 OS completely replaces SCNKEY with a new keyboard matrix scanner, and divides the results into two types of events: Key Commands, and Printable Key Events. Printable Key Events are buffered in the same 10-key keyboard buffer used by the KERNAL, and can be retrieved with GETIN. However, this call removes the character from the buffer. C64 OS provides routines to allow you to read the current event in the buffer, without removing it. This is used to allow the event to propagate through different levels of the OS, before being removed at the end of the current iteration of the main event loop. C64 OS also provides mouse input, and will likely provide joystick input drivers as well.
STOP can be used as normal. If it interrupts one of C64 OS's FREAD or FWRITE routines, a C64 OS exception will be thrown.
SCREEN
The KERNAL's screen editor is not used by C64 OS. If the Screen device is set as the current input or output device, it will be used as a pipe to read or write data from or to a Toolkit widget that is in keyboard focus. Selecting the Screen as the output device, while a Toolkit text area is in focus, and then repeatedly calling CHROUT will insert characters into the text area.
CINT should never be used. SCREEN can be used, although it is not terribly useful. C64 OS provides SCREEN_COLS and SCREEN_ROWS constants. PLOT should never be used, as it manipulates screen editor variables in workspace memory that are used for other purposes by C64 OS. SETMSG is used by the C64 OS Booter to disable KERNAL messages, and it should not be used to turn messages back on.
TIME
C64 OS uses the same Jiffy Clock as the KERNAL ROM. Therefore, it is safe to call RDTIM and SETTIM. However, C64 OS calls UDTIM inside a larger context, which includes updating other variables. You should avoid calling UDTIM manually.
C64 OS also provides a Timers module. You can read more here about how timers work in C64 OS. The Timers module mostly obviates the need to manually use the Jiffy Clock for common timer functions.
KERNAL Compatibility in C64 OS
FILE Module | |||
---|---|---|---|
Routine | Compatible | Deprecated | Do Not Use |
SETLFS | ✓ | ||
SETNAM | ✓ | ||
OPEN | ✓ | ||
CLOSE | ✓ | ||
LOAD | ✓ | ||
SAVE | ✓ |
I/O Module | |||
---|---|---|---|
Routine | Compatible | Deprecated | Do Not Use |
CHKIN | ✓ | ||
CHKOUT | ✓ | ||
CHRIN | ✓ | ||
CHROUT | ✓ | ||
CLRCHN | ✓ | ||
READST | ✓ | ||
CLALL | ✓ | ||
IOINIT | ✓ |
IEC Module | |||
---|---|---|---|
Routine | Compatible | Deprecated | Do Not Use |
TALK | ✓ | ||
TALKSA | ✓ | ||
UNTLK | ✓ | ||
ACPTR | ✓ | ||
LISTEN | ✓ | ||
SECOND | ✓ | ||
UNLSN | ✓ | ||
CIOUT | ✓ | ||
SETTMO | ✓ |
MEMORY Module | |||
---|---|---|---|
Routine | Compatible | Deprecated | Do Not Use |
MEMTOP | ✓ | ||
MEMBOT | ✓ | ||
RAMTAS | ✓ | ||
VECTOR | ✓ | ||
RESTOR | ✓ | ||
IOBASE | ✓ |
KEYBOARD Module | |||
---|---|---|---|
Routine | Compatible | Deprecated | Do Not Use |
GETIN | ✓ | ||
STOP | ✓ | ||
SCNKEY | ✓ |
SCREEN Module | |||
---|---|---|---|
Routine | Compatible | Deprecated | Do Not Use |
CINT | ✓ | ||
SCREEN | ✓ | ||
PLOT | ✓ | ||
SETMSG | ✓ |
TIME Module | |||
---|---|---|---|
Routine | Compatible | Deprecated | Do Not Use |
SETTIM | ✓ | ||
RDTIM | ✓ | ||
UDTIM | ✓ |
Statistics
- Compatible: 16 of 39 (41%)
- Deprecated: 12 of 39 (31%)
- Do Not Use: 11 of 39 (28%)
Do you like what you see?
You've just read one of my high-quality, long-form, weblog posts, for free! First, thank you for your interest, it makes producing this content feel worthwhile. I love to hear your input and feedback in the forums below. And I do my best to answer every question.
I'm creating C64 OS and documenting my progress along the way, to give something to you and contribute to the Commodore community. Please consider purchasing one of the items I am currently offering or making a small donation, to help me continue to bring you updates, in-depth technical discussions and programming reference. Your generous support is greatly appreciated.
Greg Naçu — C64OS.com