KERNAL

From Wikipedia, the free encyclopedia
Jump to: navigation, search
This article is about Commodore's 8-bit OS software. It is not to be confused with kernel.

The KERNAL[1] is Commodore's name for the ROM-resident operating system core in its 8-bit home computers; from the original PET of 1977, followed by the extended but strongly related versions used in its successors; the VIC-20, Commodore 64, Plus/4, C16, and C128.

Description[edit]

The Commodore 8-bit machines' KERNAL consisted of the low-level, close-to-the-hardware OS routines roughly equivalent to the BIOS in IBM PC compatibles (in contrast to the BASIC interpreter routines, also located in ROM) as well as higher-level, device-independent I/O functionality, and was user-callable via a jump table whose central (oldest) part, for reasons of backwards compatibility,[2] remained largely identical throughout the whole 8-bit series. The KERNAL ROM occupies the last 8 KB of the 8-bit CPU's 64 KB address space ($E000-$FFFF).

The Adventure International games published for the VIC-20 on cartridge are an example of software that uses the KERNAL. Because they only use the jump table, the games can be memory dumped to disk, loaded into a 64, and run without modification.[3]

The KERNAL was initially written for the Commodore PET by John Feagans, who introduced the idea of separating the BASIC routines from the operating system. It was further developed by several people, notably Robert Russell added many of the features for the VIC-20 and the C64.

Example[edit]

A simple, yet characteristic, example of using the KERNAL is given by the following 6502 assembly language subroutine[4] (written in ca65 assembler format/syntax):

   CHROUT  = $ffd2          ; CHROUT sends a character to the current output device
   CR      = $0d            ; PETSCII code for Carriage Return 
   ;
   hello:
           ldx #0           ; start with character 0
   next:
           lda message,x    ; read character X from message
           beq done         ; we're done when we read a zero byte
           jsr CHROUT       ; call CHROUT to output char to current output device (defaults to screen)
           inx              ; next character
           bne next         ; loop back while index is not zero (max string length 255 bytes)
   done:
           rts              ; return from subroutine
   ;
   message:
           .byte "Hello, world!"
           .byte CR, 0      ; Carriage Return and zero marking end of string

This code stub employs the CHROUT routine, whose address is found at address $FFD2 (65490), to send a text string to the default output device (e.g., the display screen).

The name[edit]

The KERNAL was known as kernel[5] inside of Commodore since the PET days, but in 1980 Robert Russell misspelled the word in his notebooks forming the "word" kernal. When Commodore technical writers Neil Harris and Andy Finkel collected Russell's notes and used them as the basis for the VIC-20 programmer's manual, the misspelling followed them along and stuck.[6]

According to early Commodore myth, and reported by writer/programmer Jim Butterfield among others, the "word" KERNAL is an acronym (or maybe more likely, a backronym) standing for Keyboard Entry Read, Network, And Link, which in fact makes good sense considering its role. Berkeley Softworks later used it when naming the core routines of its GUI OS for 8-bit home computers: the GEOS KERNAL.

On device independent I/O[edit]

Surprisingly, the KERNAL implemented a device-independent I/O API not entirely dissimilar from that of Unix or Plan-9, which nobody actually exploited. Whereas one could reasonably argue that "everything is a file" in these latter systems, you could easily claim that "everything is a GPIB-device" in the former.

Due to limitations with the 6502 architecture at the time, opening an I/O channel required three system calls. The first typically set the logical filename through the SETNAM system call. The second call, SETLFS, establishes the GPIB/IEEE-488 "device" address to communicate with. Finally OPEN is called to perform the actual transaction. The application then used CHKIN and CHKOUT system calls to set the application's current input and output channels, respectively. Applications may have any number of concurrently open files (up to some system-dependent limit; e.g., the C64 allowed for ten files to be opened at once). Thereafter, CHRIN and CHROUT prove useful for actually conducting input and output, respectively. CLOSE then closes a channel.

Observe that no system call exists to "create" an I/O channel, for devices cannot be created or destroyed dynamically under normal circumstances. Likewise, no means exists for seeking, nor for performing "I/O control" functions such as you'd find with ioctl() in Unix. Indeed, KERNAL proves much closer to the Plan-9 philosophy here, where an application would open a special "command" channel to the indicated device to conduct such "meta" or "out-of-band" transactions. For example, to delete ("scratch") a file from a disk unit, you typically would "open" the resource called "S0:THE-FILE-TO-RMV" on device 8 or 9, channel 15. Per established convention in the Commodore 8-bit world, channel 15 represents the "command channel" for peripherals, relying on message-passing techniques to communicate both commands and results, including exceptional cases. For example, in Commodore BASIC, you might find software not unlike the following:

    70 ...
    80 REM ROTATE LOGS CURRENTLY OPENED ON LOGICAL CHANNEL #1.
    90 CLOSE #1
    100 OPEN 15,8,15,"R0:ERROR.1=0:ERROR.0"
    110 INPUT #15,A,B$,C,D
    120 CLOSE #15
    130 IF A=0 THEN GOTO 200
    140 PRINT "ERROR RENAMING LOG FILE:"
    150 PRINT "  CODE: "+A
    160 PRINT "  MSG : "+B$
    170 END
    200 REM CONTINUE PROCESSING HERE, CREATING NEW LOG FILE AS WE GO...
    210 OPEN 1,8,1,"0:ERROR.0,S,W"
    220 ...

Device numbers, per established documentation, were restricted to the range [0,16). However, this limitation came from the specific adaptation of the IEEE-488 protocol and, in effect, applied only to external peripherals. With all relevant KERNAL system calls vectored, programmers could intercept system calls to implement virtual devices with any address in the range of [32,256). Conceivably, one can load a device driver binary into memory, patch the KERNAL I/O vectors, and from that moment forward, a new (virtual) device could be addressed. So far, this capability has never been utilized, presumably for two reasons: (1) The KERNAL provides no means for dynamically allocating device IDs, and (2) the KERNAL provides no means for loading a relocatable binary image. Thus, the burden of collisions both in I/O space and in memory space falls upon the user, while platform compatibility across a wide range of machines falls upon the software author. Nonetheless, support software for these functions could easily be implemented if desired.

Logical filename formats tended to depend upon the specific device addressed. The most common device used, of course, was the floppy disk system, which used a format similar to "MD:NAME,ATTRS", where M is a flag of sorts ($ for directory listing, @ for indicating a desire to overwrite a file if it already exists, unused otherwise.), D is the (optional) physical disk unit number (0: or 1: for dual-drive systems, just 0: for single-disk units like the 1541, et al. Defaults to 0: if left unspecified.), NAME is a resource name up to 16 characters in length (most characters allowed except for certain special characters), and ATTRS were an optional comma-separated list of attributes or flags. For example, if you wanted to overwrite a program file called PRGFILE, you might see a filename like "@0:PRGFILE,P" used in conjunction with device 8 or 9. Meanwhile, a filename for the RS-232 driver (device 2) consists simply of four characters, encoded in binary format.[7]

Other devices, such as the keyboard (device 0), cassette (device 1), the display interface (device 3), and printer (device 4 and 5), required no filenames to function, either assuming reasonable defaults or simply not needing them at all.

Notes[edit]

  1. ^ Commodore 64 Programmer's Reference Guide. Commodore Business Machines, Inc., 1982, p. 268
  2. ^ The kernal jump table, used to access all the subroutines in the kernal, was an array of JMP (jump) instructions leading to the actual subroutines. This feature ensured compatibility with user-written software in the event that code within the kernal ROM needed to be relocated in a later revision.
  3. ^ Kevelson, Morton (January 1986). "Speech Synthesizers for the Commodore Computers / Part II". Ahoy!. p. 32. Retrieved 17 July 2014. 
  4. ^ Many of the KERNAL subroutines (e.g., OPEN and CLOSE) were vectored through page three in RAM, allowing a programmer to intercept the associated KERNAL calls and add to or replace the original functions.
  5. ^ The kernel is the most fundamental part of a program, typically an operating system, that resides in memory at all times and provides the basic services. It is the part of the operating system that is closest to the machine and may activate the hardware directly or interface to another software layer that drives the hardware
  6. ^ On The Edge: The Spectacular Rise and Fall of Commodore, page 202.
  7. ^ Commodore 128 Programmers Reference Guide, Commodore Business Machines, Inc., 1986, p. 382