Back to the main page

New version 1.0 - full open source with bug fixes! Plus Tiny PILOT! (27 April 2024)

The Incredible KIMplement v1.0

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:

Why did I write this, instead of a (better) MESS driver, say? The KIMplement was written as a demonstration application of a software 6502 emulation I wrote for the 6502. Besides being an entertaining academic pursuit, having a software 6502 on the 6502 allows us to add features that the original didn't have, such as true virtual and protected memory models, exception processing, additional instructions, and other features needed by modern operating systems. The KIMplement shows some of this capability with its ability to trap ROM and I/O access, trap illegal instructions, and remap memory access. Plus, it was a lot of fun :-)

In the future, even 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 never used a KIM-1 before.

Using the KIMplement

A complete primer on using the KIM-1 is beyond the scope of this document and it is assumed you have some familiarity. If you don't, look at the manuals on the Links and Archives page. Nevertheless, here are the basics.

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 and after every reset, 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. By default the TTY uses the Commodore 64's screen and keyboard, but can also be redirected to a serial connection to the 64's user port at 300 baud.

The TTY emulation mode is triggered by either pressing RUBOUT, which is mapped to the INST/DEL key, or pressing SHIFT while in keyPad mode. 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. 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:

In addition, most control sequences are active, such as CTRL-G for BEL (which will ring an emulated bell). And, of course, the Commodore keyboard already has the ASR-33's backarrow (now you know where PETSCII came from). Graphic characters are ignored, as is any character code over 127. There are no shifted letters because ASCII-1963 and the ASR-33 didn't have them.

You may freely switch between keyPad and keyBoard modes at any time (many programs will only take input from the keypad, for example). To enter keyBoard mode from keyPad without sending RUBOUT, press SHIFT (the screen will turn white) and release it (this is the same as putting the jumper on pins 21-V, which may or may not trigger any change in the KIM). 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. Programs hardcoded to accept information from the emulated TTY must be in keyBoard mode, such as Tiny BASIC. Remember that to get the KIM monitor to acknowledge the TTY, you must press RUBOUT (INST/DEL) or SHIFT to switch the KIM-1 to TTY mode as described above, and you may need to warm-reset the emulated KIM if the monitor does not acknowledge the keypad (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. This is done for you automatically in 0.3 and up, but for older versions, 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 like FOCAL 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 toggle menu lists several user-configurable options for the emulator. In this version, three are supported: toggling ROM SCANDS support (see Technical and compatiblity notes), toggling the SST "Single-STep" switch (SST) (see Debugging KIM programs), and toggling whether the TTY goes to the Commodore 64's user port (see Connecting a physical terminal). Each toggle displays their value (0 for off, 1 for on). To toggle the appropriate option, press the number listed to toggle the value. When finished setting toggle switches, press T to return to the main menu. Toggle switch settings are not saved when you leave the emulator.

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 by loading 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.

Debugging KIM programs

When you pause the emulator, or whenever an exception such as an illegal instruction is triggered, the emulator will display the current status of the 6502's registers as well as the current opcode it is executing. You can pause and unpause at will to look at how the registers and program counter change.

KIMplement can also be used to help debug a KIM program using the Single-STep switch (SST) or triggering a software NMI. These features require the NMI vector at $17fa-b to be correctly set to $1c00. If you are using 0.3 or later, this is done for you by default.

The SST switch is a feature on the real KIM that KIMplement can emulate. When SST mode is activated by setting its toggle from the menu, for any program 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 to keep stepping). Registers and processor status are preserved.

KIMplement also allows you to insert software NMIs as breakpoints using the special opcode $42. This opcode is only supported as a replacement for JSR instructions (i.e., opcode $20). On a real KIM using an NMOS CPU, $42 would be interpreted as a "jam" instruction and hang the processor, so it should not be used on real hardware. In KIMplement, when this opcode is encountered, 6o6 will trigger a special exception that KIMplement turns into an NMI, exactly as if you had pressed ST at that precise point in execution. The breakpoint opcode is then automatically replaced with $20 so you can continue from that point by pressing GO. You can also turn on the SST switch to continue stepping from the breakpoint.

The KIM break routine at $1c00 saves shadow copies of the registers in RAM: $00f1 contains the status word, $00f2 the stack pointer, and $00f3-5 A, X and Y. These values are unconditionally reloaded when you press GO, even if you decide to execute from a different location, and they are not altered by the KIM's warm start reset routine. If you get weird bugs with math, look at the status word in $00f1 to see if bit 3 (NV-BDIZC, == 8) is set, as this bit means decimal mode will be enabled on execution. KIMplement clears $00f1 when the emulator first starts, but other programs may change it, and a real KIM won't guarantee anything about these locations.

Connecting a physical terminal

If the toggle redirecting the TTY to the user port is set, then a terminal or another computer connected to your Commodore's user port (such as via null modem) can control the virtual KIM. Similarly, the virtual KIM can also send data to a connected device (like a modem or teleprinter) or another computer connected to it.

The connection should be 300bps, 8 bit, no parity and one stop bit ("8N1") without hardware flow control. Connections to devices without lower case such as early TI Silent 700s and real ASR-33 or compatible units will "just work," as will a connection to another Commodore computer. If the connected device or terminal uses true ASCII, however, you will need to have the CAPS LOCK down to send upper case to the unit, just as you would with a real KIM-1. Ideally your terminal should have separate keys for RUBOUT and BACKSPACE since programs may treat them differently.

The connection does not automatically start on the connected device from a KIM reset. You must either press RUBOUT (i.e., INST/DEL) or SHIFT on the Commodore itself to start the connection, just like you would using the Commodore as console, or data from a connected device will be ignored. This is to prevent a malfunctioning device from monopolizing the emulator.

When the TTY is redirected, the border will sparkle while waiting for data and flash green (for receive) or red (for transmit) when data moves back and forth. If you press the Commodore key for the menu, the connection is suspended, though data already in transit may continue to flow to and from the Commodore's serial buffers. If the emulated KIM is reset, these buffers will be immediately flushed. You can switch back and forth between the Commodore's console at will and the user port and programs will seamlessly move from one to the other. Any buffered data that arrives on the user port will be deferred until you switch back unless you reset the emulated KIM.

Although this mimics a real KIM-1's current loop connection, the connection characteristics are different. The KIM-1 has a half-duplex connection with no buffering and only sends and receives data by explicit operation; there is no interrupt or NMI for handling serial data that may arrive while the system is busy. Sending data while the KIM is transmitting generally causes garbage characters or sometimes actually incorrect behaviour. KIMplement, on the other hand, uses the Commodore 64 Kernal to send and receive serial data, which is full-duplex, buffered and triggered by NMIs. This is much more forgiving and allows the emulated KIM to seemingly interact at nearly the same speed as a real one, but also means some of the deficiencies of a real KIM are inaccurately smoothed over.

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). Even with substantial optimizations the emulated KIM's CPU runs about 30 times slower than a real one, modulo exact workload, though native code traps and good use of the Commodore 64's additional hardware still make the emulated KIM sufficiently responsive at this lower speed.

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. It is theoretically possible to use the 64's CIA timers to do something similar but these are all occupied by the Timer A 50/60Hz interrupt, RS-232 timing and the IEC serial bus, which KIMplement depends on too. In current versions of KIMplement, the 1024 microsecond timer at $1707 is implemented by using the Kernal Timer A interrupt to count down a specific number on each IRQ in real time. This value is copied to $1704, $1705 and $1706. It is not currently possible to implement any of the faster interval timer speeds without conflicting with the Kernal's use of the CIAs, and there is no support for triggering an IRQ in the emulated KIM. Despite that, this is more than enough for many programs such as Wumpus from the "First Book of KIM," which by using the interval timer and certain trapped ROM routines (see below) for its display subroutine can appear to run at nearly full wall-clock speed.

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:

In addition, location $1fd4 must contain an RTS ($60), and locations $1f16-$1f18 and locations $1f5e-$1f62 must also be identical to their contents in the original KIM ROMs (hex 49 ff 60 and hex e8 e8 a4 fc 60 respectively), as the emulator uses these sections of code to improve native compatibility.

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. A program that uses the 1024usec interval timer will usually work correctly and approximately real-time, but programs trying to use the faster timers will run much slower, and a program waiting for an IRQ may not run at all. Similarly, 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 written to use the existing interval timer facility, or the program rewritten to wait for a keypress or some other external signal.

Finally, the LED display has some important differences which are difficult to model accurately. There is no need to wait 500 microseconds after writing an LED register in KIMplement because sprite pointers naturally update the screen instantaneously at full brightness, whereas on a real KIM-1, the LED may be too dim if you don't wait long enough. (Waiting for a tick of the 1024usec interval timer should work in both places.) In a similar vein, because a real KIM's LEDs neither light fully nor extinguish instantly, programs that set the desired LED after emitting the desired segments (i.e., they write SBD after SAD) will still work on a KIM because the flash of the digit in the wrong place isn't visible. In KIMplement this will look like the display is shifting, particularly because the emulated CPU can't update the display as quickly as a real KIM would. A couple of the programs below have been corrected for this irregularity which doesn't affect a real device.

This is the underlying need for the emulator to trap SCANDS. SCANDS is the KIM-1 ROM routine that refreshes the LED display of the current address and data (or as provided). SCANDS' code completely extinguishes the segments of each digit before updating it. Because of the LEDs' slow response this is not visible on a real KIM, but it causes obvious flickering on KIMplement, again exacerbated by the slower CPU speed. Instead, the default SCANDS trap leaves the LED sprites on after setting up the display for a smooth appearance, and is also faster since the trap is native instead of emulated; it extinguishes them only when direct access is made to the LEDs or when a program is started. This works for nearly everything, but if the program depends on SCANDS' exact behaviour, the display may show persistent "on" LED segments where there should be none. For these programs, go into the toggle menu and enable ROM SCANDS to use the old version, but although current versions improve LED display by trying to better mimic the LED's persistence, still have your headache medicine handy when you see what happens to the LEDs.

To-do list, and other known bugs

Download

Updated with new binaries and demonstration programs for 1.0

Okay, now the goodies.

If you're lazy and don't want to download and run these .sdas, you can download everything together in a gzipped .d64 which can be turned into a real 1541 disk using Pasi Ojala's gunzip.c64. However, please, please, PLEASE read the instructions below anyway. kim2d64.d64.gz (22K)

Here are some sample programs ready-to-run in KIMplement. These are updated for 0.2b.

Other utilities:

Acknowledgements

Send all bug-reports, comments, and wads of cash to ckaiser@floodgap.com.

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.


Back to the main page