The Incredible KIMplement
The Incredible KIMplement is a KIM-1 emulator for the Commodore 64 (yes,
this is not a joke -- see the screenshot to the right).
It is a true, partial emulation of the original
KIM-1 hardware featuring:
In the future, more hardware support will be added to the KIMplement to make it as comprehensive an emulator of the KIM-1 as possible within the constraints of the host system.
Only a stock Commodore 64 or compatible emulator is required. Simply LOAD and RUN the program to start. After the title screen, the emulated KIM will auto-reset, the LEDs will appear, and the time machine will transport you to the year 1975!
If you're an impatient little so-and-so, you can jump
to the goodies, but I recommend reading the below first (especially if
you have only used version 0.1, which had some significant differences).
The KIM-1 has six seven-segment LEDs, displayed at the top of the screen as the rightmost six LEDs of seven (the seventh LED on the far left is the KIMplement mode indicator). In the rudimentary KIM monitor, the address is displayed on the four left digits in hexadecimal, and its current contents on the rightmost two.
The KIM-1 also has a small hexadecimal keypad along with several special keys: AD to set the current address, DA to enter data, + to advance one byte, PC to see the last program counter, GO to start execution from the current address, ST to trigger an NMI (stop execution), and RS to send a reset to the machine (the contents of memory are not altered).
On startup, KIMplement displays a 'P' for 'keyPad' in the mode indicator (leftmost LED) indicating that the keyboard sends the emulated KIM presses on the keypad. Keys 0-9 and A-F send the appropriate hex digit. + sends the plus sign key. R (for 'addRess') sends an AD keypress, G sends a GO keypress, and T (for 'daTa') sends a DA keypress. The keys to send ST and RS are special and will be discussed presently.
KIMplement can also emulate a TTY connected to the emulated KIM-1 (there's a screenshot of this to the right); this emulation is modeled on an old-school ASR-33 teletype. The TTY emulation mode is triggered by pressing RUBOUT, which is mapped to the INST/DEL key. Press the INST/DEL key firmly and hold it briefly, as there is a race condition in the KIM-1 ROM accentuated by the slower system speed. The mode indicator will change to 'b' for 'keyBoard' indicating TTY mode. In this mode, KIM types out the current address and contents to the console and waits for input. There is no punch tape reader function, although you can try to save to punched tape (the data stream is simply echoed to the console). Use the same keys indicated in the KIM-1 User Manual for sending TTY commands. Special ASR-33 keys and control sequences are mostly supported; here are the ones in this version:
If the TTY isn't responding to commands, the race condition probably got triggered. Press INST/DEL, repeatedly if needed, until the TTY responds. Remember to press it firmly. This symptom is a lot less frequent now than in previous versions because the CPU emulation is faster, but still possible to trigger.
You may freely switch between keyPad and keyBoard modes at any time (many programs will only take input from the keypad, for example). To silently enter keyBoard mode from keyPad without sending RUBOUT, press SHIFT (the screen will turn white) and release it. Note that since SHIFT is obviously an active TTY key, to shift back to keyPad mode, hold down SHIFT and press the Commodore key (the screen will turn cyan), and then release both keys. The mode indicator will always show what type of input method KIMplement is facilitating, but note that this will not change where the KIM monitor or the currently running program is expecting input from -- if you were in keyPad mode, you must return to keyPad mode to get the monitor to respond to your commands, for example. Similarly, programs hardcoded to accept information from the emulated TTY must be in keyBoard mode, such as TinyBASIC. Remember that to get the KIM monitor to acknowledge the TTY, you must press rubout (INST/DEL) to switch the KIM-1 to TTY mode as described above, and to once again get the KIM monitor to accept keypad input, the emulated KIM must be reset (see the entry on the RS key below).
To stop the currently executing program on a KIM-1, an NMI (Non-Maskable Interrupt) is sent by pressing the ST key on the keypad. In keyPad mode, the CTRL key is mapped to ST; press CTRL (the screen will turn purple) and release it. Since CTRL is also an active key in TTY mode, hold down CTRL and press the Commodore key (the screen will turn purple), and then release both keys, to trigger NMI in keyBoard mode. The emulator will automatically switch to keyPad mode on an NMI. For the ST key to properly operate on a KIM, as well as in the KIMplement, the NMI vector at locations $17fa-b must have bytes $00 and $1c in them respectively. To enter this in keyPad mode, use the following sequence:
[AD] 1 7 F A [DA] 0 0 [+] 1 C [+]
In keyBoard mode, use the following sequence:
1 7 F A [space] 0 0 . 1 C .
If this vector is not set, the emulated KIM-1 may crash or lock up in an endless loop on NMI! If that happens, you will need to reset the KIM with the Commodore key; see below.
During operation, the emulated CPU may return error or information conditions to the KIM emulator. When a CPU condition occurs, the border will flash and the emulator will report the condition and the current emulated 6502 state. BRK is handled "transparently" since many KIM applications use it as a software interrupt; it will flash the border white-and-black, then automatically trigger the IRQ, load up the stack, set the emulated B-flag and continue execution through the 6502's IRQ vector as usual. However, nothing is printed on the screen otherwise to avoid interference with normal operations. The other messages are fatal errors and the emulator will force you to non-destructively reset the emulated CPU (illegal instruction, memory fault, consistency error [bug in the CPU emulation! ack!], etc.). This will restart the KIM, but memory should remain intact (assuming the errant program hasn't trashed it). Do note that for BRK instructions to properly function, the vector at $17fe should be properly set (or set to $1c00, as in the example above for $17fa). If you get an endless loop of BRKs, you will need to reset the machine (see below).
The main menu, along with the reset command, is accessed with the Commodore key in both keyPad and keyBoard modes. Press the Commodore key (the screen will turn red) and release it; the emulator will pause, display the current state of the emulated CPU, and present options. From here, you can:
The SST mode is important and deserves additional explanation. When SST mode is activated, for any code that is not in ROM (at locations $1800-$1fff), an NMI is triggered immediately after each instruction executes, thus allowing single stepping through code (press GO or type 'g' depending on keyPad/keyBoard mode to keep stepping). Because SST mode uses NMIs to single-step, the NMI vector must be set at $17fa-b as described above, or the emulated CPU may crash! The emulator automatically switches back to keyPad mode on each step.
To load or save files, type 'L' or 'S' respectively from the main menu. To load a file from disk, the file should be stored as a regular .prg file on the default disk drive. KIMplement prefers that such files have (and files saved will have) an apparent starting address of 16384 ($4000) plus the starting address in the emulated KIM's addressing space; this is because the KIM-1's RAM is stored at this location in the C64, with the addressing space extending in the C64 from $4000-$7fff. However, since there are many raw binaries without a starting address, KIMplement will also allow you to specify a starting address for those types of files. To indicate that there is a valid starting address on the file, after pressing L, press K to indicate that this is a KIMplement-style .prg file. Otherwise, press B to indicate it is a raw binary and the KIMplement will ask you where you want to load it. Note that KIMplement rigidly enforces its addressing range and will refuse to load a program that doesn't have a valid starting address in this 16K block, and if the loaded file extends outside of this range KIMplement will force you to cold start the emulator from scratch to protect itself, potentially losing your work! To cancel a load, simply enter a blank filename. On a successful load, KIMplement will report the starting and ending addresses (inclusive) of any memory locations changed as a verification measure.
You will note that since the ROMs lie between $1800 and $1fff (real locations $5800 and $5fff), you can overwrite them with your own ROMs. This should be considered a feature, and is useful and even supported, but there are important emulator-specific limitations you should read first.
To save a file from disk, enter the desired filename, and then the starting
and ending addresses (inclusive; do not enter ending address + 1) in
hexadecimal. Give the addresses relative to KIM RAM; KIMplement will save
the file to disk with the proper
starting address and return the DOS error code, if any. Enter a blank
entry at any time to cancel the save operation.
Technical and compatibility notes
The Incredible KIMplement emulates enough of the hardware to get the KIM-1
ROMs functional, and many applications as well. Its major disadvantage
is its relatively poor execution time (relative to a native 6502).
KIMplement uses a KIM-4-style memory map for its expanded RAM emulation, with two changes: first, RAM exists in *every* location between $0000 and $1700, whereas a real KIM with most 4K low-RAM expansion boards typically only had RAM up to $1400. This is done for efficiency reasons rather than special-casing this little-used section of addressing space, but if you want your programs to be guaranteed to work on as wide a range of configurations as possible, don't take that block of RAM between $1400 and $1700 for granted. Second, above $4000, the unmapped addressing range is hardwired to return $ff on purpose; this forces an immediate illegal instruction exception if the program counter gets into this range, greatly facilitating debugging. KIMplement correctly mirrors $17f8-$17ff to $fff8-$ffff, just like a real KIM-4.
There are certain elements of the KIM hardware that KIMplement does not presently emulate. In particular, the RIOT emulation is incomplete; besides only kludgy support for terminal and keypad lines, the most important deficiency is interval timer support. A full-speed and completely cycle-accurate software emulation will never be possible on the stock ~1MHz Commodore 64 because the timers also offer a mode where every single pulse of the KIM's own 1MHz clock is counted by the timer -- impossible because the instructions merely to do the counting, let alone the 64's own IRQs and housekeeping and the rest of the emulator itself, require much more time than a single clock cycle. I am considering adding a feature where the right number of ticks are counted, but in groups based on the 60Hz Timer A IRQ, or possibly even using the 64's CIAs to count 64's own clock pulses at its similar clock speed as long as this does not greatly impact performance -- since the sorts of applications needing this support typically use it for real time triggering, it's important that the interval timers themselves run in real time, not by counting slower "emulated clock ticks." However, I haven't implemented either scheme yet and in any case either option might still not be accurate enough for certain applications. (The rest of the RIOT feature set is not so constrained and I will gradually add more accurate I/O sensing and similar features into future versions.)
A related problem is that several segments of the KIM-1 ROM were written assuming that the CPU ran at a fixed 1.000MHz -- a real trick when the 64's own 6510 is itself running at approximately that same speed as we explained above. There is no way the stock C64 can keep up with this, so for these problematic areas of ROM, the emulator actually traps calls to these routines and replaces them with native kernel-level code. In particular, the routines to flash the LEDs, read the keypad, send characters to the TTY and receive characters from the TTY have been replaced with native-mode traps, and certain startup routines are also diverted.
Because this requires the emulator to trap the emulated 6502 at certain locations in ROM, this also means that these locations must be valid for arbitrary entry. Currently, the following routines (referenced by symbol name in the KIM-1 disassembly as it appears in the User Manual) must remain at their documented entry points:
As previously mentioned, you can replace the built-in ROMs with your own ROMs, but because of the emulator's current architecture your custom ROMs must obey all of the entry point constraints noted above (both to enable compatibility with KIM-1 application programs, and to make sure that ROM traps do not fail or the emulator may trap routines falsely or (worse) place the PC at the wrong instruction). Be careful with the length of your code as well: if the length of your ROM file(s) cause them to expand into KIM RAM above $2000 (real C64 location $6000), then they may not properly be write-protected because the emulator does not know they are supposed to be "ROM," and if you really go overboard and cause them to expand beyond $3fff (real C64 location $7fff), then you will corrupt the emulator, be forced to coldstart, and lose your work! To replace 6530-002, your code should be 1K in length and have a starting address of $5800 (assembled with * = $1800); to replace 6530-003 (the master ROM), your code should be 1K at length, must have valid NMI, IRQ and RESET vectors in the last six bytes!, and have a starting address of $5c00 (assembled with * = $1c00).
Unfortunately, the emulator cannot do this sort of trapping for arbitrary programs in general. Programs that depend on the interval timer may not work at all (although some programs used the LSB at $1704 as a cheap source of 'random' numbers, and in this version this shameless practise is supported [weakly] by simply copying the LSB of the C64's jiffy clock there on each emulated instruction execution). Programs that use a delay loop based on a certain number of processor cycles will run on the KIMplement, but the delay loop will be considerably longer in real time. (This is the reverse of compatibility problems with the CMD SCPU, where a program that assumed the speed of the 64 was fixed ran too fast instead.) For such programs, the delay loop will have to be recalibrated, or the program rewritten to wait for a keypress or some other external signal. Eventually these routines might be rewritten for the interval timers when this support is added.
One other note is that SCANDS, the KIM-1 ROM routine that flashes the
KIM data/address LEDs and refreshes them, depends on the LEDs having
some kind of afterimage to make a smooth display which the sprites
obviously don't have. The ROM SCANDS operates by turning all the LEDs off after
briefly lighting the display, which when in a loop at the speed
this emulator runs at, causes noticible flickering. Instead, the
emulated SCANDS trap (enabled by default) leaves the LEDs on after
setting up the display for a smoother-looking appearance,
extinguishing them only when direct access is made to
the LEDs, or when a program is started. Usually this works, but if the
program depends on the LEDs being extinguished immediately afterwards,
the display may not function correctly. For these programs, go into the
toggle menu and
enable ROM SCANDS to use the old version, but have your headache medicine
handy when you see what happens to the LEDs.
To-do list, and known bugs
Here's what's new:
By the way, these programs have not been modified in any way other than to add a starting address, and will work on a real KIM (with the starting address removed) too. You should load them as "K"IMplement format, not as raw binaries.
This version is virgin and needs a bit of setup to get running. Here's how:
What this is doing is setting the internal jump table to reference the TTY (using the KIM routines at $1ea0 and $1e5a), using Tiny BASIC's TTY break routine to act as break during execution, and setting the backspace key to ASCII 8. (You can't use RUBOUT; it has a special meaning to Tiny BASIC. Get used to hitting CRSR LEFT or RIGHT.)
Remember to ALWAYS USE CRSR LEFT or RIGHT to backspace in Tiny BASIC. RUBOUT will appear to work, but Tiny BASIC will complain, and when you list the program you will see that it was intercepted by Tiny BASIC. If you want to use some other character, substitute its ASCII code for 08 above, but KIMplement only knows to move the carriage back for BS and RUBOUT codes. Once you have Tiny BASIC customized the way you want it, you might save a copy to save typing later.
Break is triggered during program execution with any activity on the TTY (except, of course, in INPUT statements). I like to hold down CRSR RIGHT until the execution stops, and then release it, as this seems to disturb the terminal the least.
To return to KIM, you can type print usr(7168) or just reset it. If you use the usr() escape, remember that this leaves you in keyBoard mode, so tap RUBOUT again to get the KIM's attention. To warm-return to Tiny BASIC without disturbing your program, start execution at $2003, not $2000.
Please remember that Tiny BASIC is no speed demon even on a real KIM, and doubly so on KIMplement, due to the fact it itself is written in an interpreted middle level-language. However, this makes it considerably more compact, thus the rationale for doing it that way. It is certainly much smaller than Microsoft BASIC, which doesn't even fit into KIMplement.
Thank-yous go out to: Phil Lange (who did a lot of banging on version 0.1 and offered many suggestions and requests for 0.2), Neil H. F. Meyer, Jr., Cameron Bean, Jim Butterfield, Ruud Baltissen, Peter Jennings and Tom Pittman; apologies to Wendy Carlos and, of course, Chuck Peddle.
The KIM-1 system ROMs appear for educational purposes only, as their contents are no longer considered reasonably available under the fair use/obsolescence criterion 3 of the United States Digital Millenium Copyright Act (reference: http://www.copyright.gov/1201/ and http://www.arstechnica.com/archive/news/1067440261.html). If the authorized owner of the copyrights on these ROMs would like to assert their objection and their proof of copyright on paper, please E-mail me at the address above for contact information. This currently only applies to USA domestic users of the KIMplement; other copyright or fair use laws may apply to international users depending on your home country or region.