The Incredible KIMplement v0.3
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:
0.3 is a significant update, so even if you're a long-time KIMplement user, please read the below to ensure you're current on all the new features. 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.
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:
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:
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
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 $fb. This opcode is only supported as a replacement for JSR instructions (i.e., opcode $20). On a real KIM using an NMOS CPU, $fb would be interpreted as the undocumented ISC instruction, 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:
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
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)
This program is pre-crunched with pucrunch. It will take a few seconds to decompress and depack itself.
Here's the changelog:
By the way, except where otherwise stated, 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, or BACKSPACE in your terminal program if you're redirecting the TTY to the user port.)
Remember to ALWAYS USE CRSR LEFT or RIGHT (i.e., true backspace, ASCII code 8) 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). On the Commodore I like to hold down CRSR RIGHT until the execution stops, and then release it, as this seems to disturb the terminal the least.
If you redirect the output to the user port, you will notice apparently spurious characters which are politely ignored by the Commodore 64's console routines. These are Tiny BASIC's pad characters; setting $2011 to 0 will mostly, but not completely, make them into nulls. Pressing RUBOUT once is sufficient to interrupt program execution.
Saving and loading programs are done through the KIM monitor. To return to the KIM monitor, you can type print usr(7168) or just reset the emulated KIM. If you use the usr() escape, KIMplement will stay in keyBoard mode, including if the TTY is redirected. To save your program, save from $2900 to the value at location $0024 (e.g., if $0024 was $23 and $0025 was $29, then save from $2900 to $2923). To load your program, cold start Tiny BASIC first, then load your program and set $0024 accordingly. (Alternatively, save from $0020 to $00b8 to capture the status of your program, and load that as well.) To warm start 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.
To start FOCAL, switch to keyBoard mode with RUBOUT and start the interpreter with 2000 [space] g. It will (character by character) display an error code and an asterisk prompt. The border flashes on errors or system messages due to this program's use of the BRK instruction as a software interrupt.
When you type initially, the terminal will "stutter." Turn off FOCAL's local echo by typing s fech(1) and press RETURN (this will turn into ss ffeecchh((11)) on screen; if you press RUBOUT, you'll see pound signs serving as backslashes). Note that FOCAL "forgets" to keep your echo setting on errors and you may have to type this again after a BRK has occurred. FOCAL also treats the backarrow as delete, so try to avoid using it. However, once you've turned off local echo, RUBOUT (INST/DEL) works as you would expect.
As well as a functional if somewhat baroque programming language, FOCAL can serve as a simple calculator (type t and an expression) out to a configurable number of decimal places. It is also notable for its "floating point" module-line number format, derived from its ancestor JOSS, as demonstrated at right with the sample program running in the KIMplement computing square roots using Newton's method. Aresco FOCAL-65 adds several utility functions which you can read about in the manual. This version of FOCAL-65 is limited to single character variables (you will get an error using more than one), and exponentiation truncates any decimal portion, though negative numbers are supported if the unary minus is in parentheses, e.g. t 34.67^(-12) from the manual. For example, t 5^0.5 returns 1, the same as t 5^0, but does not throw an error.
Don't forget erase all to clear the program area, and write to display the interpreter version and any program in memory.
To exit back to the KIM monitor, just reset it (i.e., press the Commodore key twice). A program in memory will be left intact, so you can also halt a program this way: if you call $2000 again after resetting the machine but with FOCAL still in memory, if a program had been running, FOCAL will display where its execution halted.
FOCAL programs start at the immediate end of the interpreter. To save a program, return to the KIM monitor and save the entire range from the value in $002f to the value in $0042. When loading it, ensure that $0042 is set to its ending address, and simply call $2000 again to resume.
FOCAL is even slower than Tiny BASIC due in large part to its heavy floating point usage, but this is also a nice stress test for the emulator and shows that the 6502 was certainly capable of high precision math.
If you are using FOCAL on the console TTY as opposed to over the user port, FOCAL's speed also means that it may not respond immediately to keyboard input (ASK prompts are particularly slow: it may take a second or two to process each character). KIMplement feeds it characters from the C64 Kernal's keyboard buffer and marks the terminal "not idle" so that the main loop will eventually fetch all the keys, but the buffer overflows after 10 characters, so don't type too far ahead! On the other hand, if you are connected over the user port, your typing is fully buffered (up to 256 characters) and responsiveness seems about the same as any other 300 baud connection. In that sense FOCAL actually works rather well in that environment.
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.