INTRODUCTION
Many years ago, in 1976, MOS Technologies designed the KIM-1 microcomputer system to promote their 6502 CPU. This single-boad computer offered 2KB ROM, 1KB RAM, hex keypad, 7-segment LED display and little I/O (serial and tape interface).
Let’s build a modern 6502 based single-boad computer with a more convenient user interface – the KIM-64. It is based on the well documented 6502 CPU, VIA 6522 and C64 firmware.
Features
- USB powered 5V/200mA
- C64 BASIC V2 (unpatched)
- C64 KERNEL (patched)
- C64 keyboard
- 64KB RAM
- Monochrome analog 40 x 25 character PAL CVBS video output
- Onboard Supermon64 machine-language monitor
- Onboard SD2IEC for file storage and PC transfer
- Full screen editor with transparent video memory
- IEC serial bus support (disk drives, printers, etc.)
- PEEK & POKE access to Mega 2560 resources (Ports, Timers, UARTs, TWI, etc.)
- NMOS & CMOS compatible (65xx, 65Cxx)
- Easy memory transfer from Mega 2560 FLASH to KIM-64 RAM
- Progammable PHI0 and Interrupt Timers
Block diagram
Theory of operation
After reset of the Mega 2560 it copies the C64 firmware from Flash to RAM. Its timers for interrupt and clock PHI0 are started and finally RESET is set high to start 6502 CPU execution at vector $FFFC/$FFFD.
In addition to the address decoding the Main Logic halts the CPU when it’s accessing screen memory ($400-$7FF) or Mega I/O ($D000-$D0FF). The Mega 2560 processes the interrupt request and asserts ACK after finishing.
The Nano is the video controller which provides video timing and pixel data. Writing to screen memory interrupts the Mega 2560 and the address is latched during the write cycle. Now, the screen character byte is being copied from RAM to SRAM in the Mega 2560. During vertical sync the transfer of screen data from Mega to Nano takes place via SPI for the period of approximately 3 ms.
Thus there are three identical sets of the screen data: RAM, Mega SRAM, Nano SRAM
Note: Interrupts for Vertical sync and CPU halt state may interfere with each other, resulting in a delayed access on Mega I/O.
A falling edge on VIA 6522 CA1 input generates the interrupt for the 6502 CPU. Pin CA1 is driven by Timer 4 at 60 Hz. Both 8-bit ports of the VIA are used to scan the 8×8 keyboard matrix, in a similar manner to the C64.
For the connection of IEC devices like 1541, 1571, 1581, SD2IEC, etc. an IEC interface is realized by I/O logic, reduced to the bare minimum, in an ATF22V10 PLD.
Main Logic Write Timing diagram
Main Logic Read Timing diagram
KIM-64 Memory map
Address | KIM-64 | C64 |
---|---|---|
0000, 0001 | RAM | 6510 Processor Port |
$0002-$9FFF | RAM | RAM |
$A000-$BFFF | BASIC (RAM resident) | BASIC ROM |
$C000-$CFFF | RAM | RAM |
$D000-$D03F | RAM | VIC |
$D040-$D0FF | Mega 2560 IO | VIC |
$D100-$DBFF | Supermon64 | VIC, SID, Color RAM |
$DC00-$DCFF | VIA 6522 (Keyboard, IRQ) | CIA 6526 |
$DD00-$DDFF | IEC Interface | CIA 6526 IEC & User Port |
$DE00-$DEFF | I/O #1 | I/O #1 |
$DF00-$DFFF | I/O #2 | I/O #2 |
$E000-$FFFF | KERNEL (RAM resident) | KERNEL ROM |
Supermon64
Due to non-existend C64 VIC, SID and Color RAM the address range $D000-$DBFF became available for other purposes. The machine-language monitor Supermon64 is now occupying $D100-$DBFF. It was programmed in the 1980s by Jim Butterfield and others. Reformatted by J.B. Langston to be conform with 64tass.
To start Supermon64
- press and hold RUN/STOP and hit RESTORE
- during system RESET press and hold RUN/STOP
- SYS 53504
Supermon64 command summary
Command | Description |
---|---|
|
|
G |
|
J | jump (subroutine) |
L | load from SD card or disk |
M | memory display |
R | register display |
S | save to or disk |
X | exit to basic |
A | simple assembler |
D | disassembler |
F | fill memory |
H | hunt memory |
T | transfer memory |
C | compare memory |
@ | disk status/command |
Helpful hints
- default for LOAD/SAVE is device #8
- LOAD displays the directory from default device #8
- LOAD “”,9 displays the directory from device #9
- Tape (device #1) is not supported
- RS232 (device #2) is not supported, use Mega 2560 UART instead
- only capital/graphics character set is supported
- CBM + RUN/STOP loads first file from device #8
Main Logic ABEL design
MODULE
TITLE 'KIM-64'
"Yorck Thiele, March 2024
DEVICE 'p22V10';
"INPUTS
PHI2 pin 1; "
SYNC pin 2; "
R_W pin 3; "
ACK pin 4; "
A8 pin 5; "
A9 pin 6; "
A10 pin 7; "
A11 pin 8; "
A12 pin 9; "
A13 pin 10; "
A14 pin 11; "
A15 pin 13; "
RAM6502 pin 14; "
"OUTPUTS
LATCH_EN pin 23 istype 'reg'; "
RDY pin 22 istype 'reg'; "
!RAM_WR pin 21 istype 'com'; "
!RAM_OE pin 20 istype 'com'; "
!VIA1 pin 19 istype 'com'; "
!VIA2 pin 18 istype 'com'; "
!IO1 pin 17 istype 'com'; "
!IO2 pin 16 istype 'com'; "
X=.X.;
ADR_IN= [A15,A14,A13,A12,A11,A10,A9,A8, X,X,X,X,X,X,X,X];
VIDEO_ADR=((ADR_IN >= ^h0400) & (ADR_IN <= ^h07FF));
IO_ADR= ((ADR_IN >= ^hD000) & (ADR_IN <= ^hD0FF));"MEGA2560 INTERN I/O ACCESS
EQUATIONS
LATCH_EN.CLK=PHI2;
RDY.CLK=PHI2;
RAM_WR= !(VIA1 # VIA2 #IO1 #IO2) & !R_W & PHI2;
RAM_OE= !(VIA1 # VIA2 #IO1 #IO2) & R_W;
RAM_WR.OE=RAM6502;
RAM_OE.OE=RAM6502;
when ((VIDEO_ADR # IO_ADR) & (R_W ==0) & (ACK ==0)) # ((LATCH_EN ==0) & (ACK ==0)) then LATCH_EN := 0; else LATCH_EN := 1;
when (LATCH_EN ==0) # (IO_ADR & (R_W ==1) & (ACK ==0)) then RDY := 0; else RDY := 1;
"KIM-64 ADDRESS MAP
when (ADR_IN>= ^hDC00) & (ADR_IN<= ^hDCFF) then VIA1 = 1;
when (ADR_IN>= ^hDD00) & (ADR_IN<= ^hDDFF) then VIA2 = 1;
when (ADR_IN>= ^hDE00) & (ADR_IN<= ^hDEFF) then IO1 = 1;
when (ADR_IN>= ^hDF00) & (ADR_IN<= ^hDFFF) then IO2 = 1;
END
IEC Logic ABEL design
MODULE
TITLE 'KIM IEC IO'
"Yorck Thiele, MAY 2024
DEVICE 'p22V10';
"INPUTS (CPU6502 SIGNALS)
R_W, CS, RESET PIN 13, 8, 9;
"INPUTS (INVERTED PHI2)
PHI1 PIN 1;
"INPUTS (IEC BUS SIGNALS)
DATA_IN, CLOCK_IN PIN 3, 4;
"OUTPUTS
IEC_RESET PIN 23 ISTYPE 'com';
IEC_DATA PIN 22 ISTYPE 'reg';
IEC_CLOCK PIN 21 ISTYPE 'reg';
IEC_ATN PIN 20 ISTYPE 'reg';
D3 PIN 18 ISTYPE 'com';"IEC ATN OUT
D4 PIN 17 ISTYPE 'com';"IEC CLOCK OUT
D5 PIN 16 ISTYPE 'com';"IEC DATA OUT
D6 PIN 15 ISTYPE 'reg';"IEC CLOCK IN
D7 PIN 14 ISTYPE 'reg';"IEC DATA IN
EQUATIONS
IEC_DATA.clk=PHI1;
IEC_CLOCK.clk=PHI1;
IEC_ATN.clk=PHI1;
D6.clk=PHI1;
D7.clk=PHI1;
IEC_DATA.OE= !IEC_DATA & RESET;
IEC_CLOCK.OE= !IEC_CLOCK & RESET;
IEC_ATN.OE= !IEC_ATN & RESET;
IEC_RESET = 0;
IEC_RESET.OE = !RESET;
D7 := DATA_IN;
D7.OE = RESET & R_W & !CS;
D6 := CLOCK_IN;
D6.OE = RESET & R_W & !CS;
D5 = !IEC_DATA;
D5.OE = RESET & R_W & !CS;
D4 = !IEC_CLOCK;
D4.OE = RESET & R_W & !CS;
D3 = !IEC_ATN;
D3.OE = RESET & R_W & !CS;
when (RESET & !R_W & !CS) then IEC_DATA := !D5; else IEC_DATA := IEC_DATA # !RESET;
when (RESET & !R_W & !CS) then IEC_CLOCK := !D4; else IEC_CLOCK := IEC_CLOCK # !RESET;
when (RESET & !R_W & !CS) then IEC_ATN := !D3; else IEC_ATN := IEC_ATN # !RESET;
END