Add KIM-1 Support

This commit is contained in:
Dave Plummer 2022-06-04 13:00:48 -07:00
parent 30dc9b8d1a
commit 799aec23a6
18 changed files with 425 additions and 1 deletions

28
asminc/kim1.inc Normal file
View File

@ -0,0 +1,28 @@
; ---------------------------------------------------------------------------
;
; KIM-1 definitions
;
; ---------------------------------------------------------------------------
RAMSTART := $0200 ; Entry point
; ---------------------------------------------------------------------------
; Monitor Functions
; ---------------------------------------------------------------------------
OUTCHR := $1EA0 ; Output character
INTCHR := $1E5A ; Input character without case conversion
DUMPT := $1800 ; Dump memory to tape
LOADT := $1873 ; Load memory from tape
SAL := $17F5 ; Tape load address low
SAH := $17F6 ; Tape load address high
EAL := $17F7 ; Tape address end low
EAH := $17F8 ; Tape address end high
ID := $17F9 ; Tape Identification number
; ---------------------------------------------------------------------------
; System Memory
; ---------------------------------------------------------------------------

41
cfg/kim1.cfg Normal file
View File

@ -0,0 +1,41 @@
# kim1.cfg (4k)
#
# for unexpanded Kim-1
#
# ld65 --config kim1.cfg -o <prog>.bin <prog>.o
FEATURES {
STARTADDRESS: default = $0200;
CONDES: segment = STARTUP,
type = constructor,
label = __CONSTRUCTOR_TABLE__,
count = __CONSTRUCTOR_COUNT__;
CONDES: segment = STARTUP,
type = destructor,
label = __DESTRUCTOR_TABLE__,
count = __DESTRUCTOR_COUNT__;
}
SYMBOLS {
__STACKSIZE__: type = weak, value = $0080; # 128 byte program stack
__STARTADDRESS__: type = export, value = %S;
}
MEMORY {
ZP: file = %O, define = yes, start = $0000, size = $00EE;
CPUSTACK: file = "", define = yes, start = $0100, size = $0100;
RAM: file = %O, define = yes, start = %S, size = $1000 - %S - __STACKSIZE__;
MAINROM: file = "", define = yes, start = $E000, size = $1000;
TOP: file = "", define = yes, start = $F000, size = $1000;
}
SEGMENTS {
ZEROPAGE: load = ZP, type = zp, define = yes;
STARTUP: load = RAM, type = ro, define = yes;
CODE: load = RAM, type = ro, define = yes;
RODATA: load = RAM, type = ro, define = yes;
ONCE: load = RAM, type = ro, define = yes;
DATA: load = RAM, type = rw, define = yes;
BSS: load = RAM, type = bss, define = yes;
}

67
include/kim1.h Normal file
View File

@ -0,0 +1,67 @@
/*****************************************************************************/
/* */
/* kim1.h */
/* */
/* Kim-1 system-specific definitions */
/* */
/* */
/* */
/* (C) 2022 Dave Plummer */
/* Email: davepl@davepl.com */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef _KIM1_H
#define _KIM1_H
/* Check for errors */
#if !defined(__KIM1__)
# error This module may only be used when compiling for the Kim-1!
#endif
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/*****************************************************************************/
/* Hardware */
/*****************************************************************************/
// Todo (davepl)
//
// #include <_6530.h>
// #define RIOT3 (*(struct __6530*)0x1700) // U25
// #define RIOT2 (*(struct __6530*)0x1740) // U28
/*****************************************************************************/
/* Code */
/*****************************************************************************/
/* Read from tape */
int __fastcall__ loadt (unsigned char);
/* Write to tape */
int __fastcall__ dumpt (unsigned char, const void*, const void*);
/* End of sym1.h */
#endif

View File

@ -27,6 +27,7 @@ TARGETS = apple2 \
$(CBMS) \
$(GEOS) \
gamate \
kim1 \
lynx \
nes \
none \

47
libsrc/kim1/crt0.s Normal file
View File

@ -0,0 +1,47 @@
;
; Startup code for cc65 (kim-1 version)
;
.export _init, _exit
.export __STARTUP__ : absolute = 1 ; Mark as startup
.import _main
.import initlib, donelib, copydata, zerobss
.import __RAM_START__, __RAM_SIZE__ ; Linker generated
.import __STACKSIZE__ ; Linker generated
.include "zeropage.inc"
.include "kim1.inc"
; Place the startup code in a special segment
.segment "STARTUP"
; A little light housekeeping
_init: cld ; Clear decimal mode
; Set cc65 argument stack pointer
lda #<(__RAM_START__ + __RAM_SIZE__)
sta sp
lda #>(__RAM_START__ + __RAM_SIZE__)
sta sp+1
; Initialize memory storage
jsr zerobss ; Clear BSS segment
jsr copydata ; Initialize DATA segment
jsr initlib ; Run constructors
; Call main()
jsr _main
; Back from main (this is also the _exit entry). There may be a more elegant way to9
; return to the monitor on the Kim-1, but I don't know it!
_exit: brk

5
libsrc/kim1/ctype.s Normal file
View File

@ -0,0 +1,5 @@
; Character specification table.
;
; uses the "common" definition
.include "ctype_common.inc"

51
libsrc/kim1/read.s Normal file
View File

@ -0,0 +1,51 @@
;
; int __fastcall__ read (int fd, void* buf, unsigned count);
;
.include "kim1.inc"
.import popax, popptr1
.importzp ptr1, ptr2, ptr3
.export _read
.proc _read
sta ptr3
stx ptr3+1 ; Count in ptr3
inx
stx ptr2+1 ; Increment and store in ptr2
tax
inx
stx ptr2
jsr popptr1 ; Buffer address in ptr1
jsr popax
begin: dec ptr2
bne getch
dec ptr2+1
beq done ; If buffer full, return
getch: jsr INTCHR ; Get character using Monitor ROM call
;jsr OUTCHR ; Echo it
and #$7F ; Clear top bit
cmp #$07 ; Check for '\a'
bne chkcr ; ...if BEL character
;jsr BEEP ; Make beep sound TODO
chkcr: cmp #$0D ; Check for '\r'
bne putch ; ...if CR character
lda #$0A ; Replace with '\n'
jsr OUTCHR ; and echo it
putch: ldy #$00 ; Put char into return buffer
sta (ptr1),y
inc ptr1 ; Increment pointer
bne begin
inc ptr1+1
bne begin
done: lda ptr3
ldx ptr3+1
rts ; Return count
.endproc

39
libsrc/kim1/tapeio.s Normal file
View File

@ -0,0 +1,39 @@
;
; int __fastcall__ loadt (unsigned char id);
; int __fastcall__ dumpt (unsigned char id, void* start_addr, void* end_addr);
;
.include "kim1.inc"
.import popa, popax, return0, return1
.export _loadt, _dumpt
.segment "CODE"
.proc _loadt: near
sta ID ; Tape record ID to P1L
jsr LOADT ; Read data from tape
bcs error
jmp return0 ; Return 0 if sucessful
error: jmp return1 ; or 1 if not
.endproc
.proc _dumpt: near
sta EAL ; End address
stx EAH
jsr popax
sta SAL ; Start address
stx SAH
jsr popa
sta ID ; Tape Record ID
ldx #$00
jsr DUMPT ; Write data to tape
bcs error
jmp return0 ; Return 0 if sucessful
error: jmp return1 ; or 1 if not
.endproc

49
libsrc/kim1/write.s Normal file
View File

@ -0,0 +1,49 @@
;
; int __fastcall__ write (int fd, const void* buf, int count);
;
.include "kim1.inc"
.import popax, popptr1
.importzp ptr1, ptr2, ptr3
.export _write
.proc _write
sta ptr3
stx ptr3+1 ; Count in ptr3
inx
stx ptr2+1 ; Increment and store in ptr2
tax
inx
stx ptr2
jsr popptr1 ; Buffer address in ptr1
jsr popax
begin: dec ptr2
bne outch
dec ptr2+1
beq done
outch: ldy #0
lda (ptr1),y
jsr OUTCHR ; Send character using Monitor call
cmp #$07 ; Check for '\a'
bne chklf ; ...if BEL character
;jsr BEEP ; Make beep sound
chklf: cmp #$0A ; Check for 'n'
bne next ; ...if LF character
lda #$0D ; Add a carriage return
jsr OUTCHR
next: inc ptr1
bne begin
inc ptr1+1
jmp begin
done: lda ptr3
ldx ptr3+1
rts ; Return count
.endproc

View File

@ -154,7 +154,7 @@ endif
# Lists of subdirectories
# disasm depends on cpp
DIRLIST = tutorial geos atari2600 atari5200 apple2 gamate lynx supervision sym1 cbm
DIRLIST = tutorial geos atari2600 atari5200 apple2 gamate lynx supervision sym1 kim1 cbm
# --------------------------------------------------------------------------
# Lists of executables
@ -329,6 +329,9 @@ EXELIST_supervision = \
EXELIST_sym1 = \
notavailable
EXELIST_kim1 = \
notavailable
EXELIST_telestrat = \
ascii \
checkversion \
@ -395,6 +398,7 @@ TARGETS := \
creativision \
cx16 \
gamate \
kim1 \
lunix \
lynx \
nes \

56
samples/kim1/Makefile Normal file
View File

@ -0,0 +1,56 @@
# Run 'make SYS=<target>'; or, set a SYS env.
# var. to build for another target system.
SYS ?= kim1
# Just the usual way to find out if we're
# using cmd.exe to execute make rules.
ifneq ($(shell echo),)
CMD_EXE = 1
endif
ifdef CMD_EXE
NULLDEV = nul:
DEL = -del /f
RMDIR = rmdir /s /q
else
NULLDEV = /dev/null
DEL = $(RM)
RMDIR = $(RM) -r
endif
ifdef CC65_HOME
AS = $(CC65_HOME)/bin/ca65
CC = $(CC65_HOME)/bin/cc65
CL = $(CC65_HOME)/bin/cl65
LD = $(CC65_HOME)/bin/ld65
else
AS := $(if $(wildcard ../../bin/ca65*),../../bin/ca65,ca65)
CC := $(if $(wildcard ../../bin/cc65*),../../bin/cc65,cc65)
CL := $(if $(wildcard ../../bin/cl65*),../../bin/cl65,cl65)
LD := $(if $(wildcard ../../bin/ld65*),../../bin/ld65,ld65)
endif
EXELIST_kim1 = \
kimHello.bin
ifneq ($(EXELIST_$(SYS)),)
samples: $(EXELIST_$(SYS))
else
samples: notavailable
endif
# empty target used to skip systems that will not work with any program in this dir
notavailable:
ifeq ($(MAKELEVEL),0)
@echo "info: kim1 tests not available for" $(SYS)
else
# suppress the "nothing to be done for 'samples' message
@echo > $(NULLDEV)
endif
kimHello.bin: kimHello.c
$(CL) -t kim1 -O -o kimHello.bin kimHello.c
clean:
@$(DEL) kimHello.bin 2>$(NULLDEV)

BIN
samples/kim1/kimHello Normal file

Binary file not shown.

24
samples/kim1/kimHello.c Normal file
View File

@ -0,0 +1,24 @@
// --------------------------------------------------------------------------
// Hello World for Kim-1
//
// Dave Plummer based on Sym-1 sample by Wayne Parham
//
// davepl@davepl.com
// --------------------------------------------------------------------------
#include <stdio.h>
#include <kim1.h>
int main (void)
{
char str[100];
char c = 0x00;
printf ("\nHello World!\n\n");
printf ("Type a line and press ENTER, please.\n\n");
gets( str );
printf ("\n\nThanks: %s\n\n", str);
return 0;
}

View File

@ -342,6 +342,10 @@ static void SetSys (const char* Sys)
NewSymbol ("__SYM1__", 1);
break;
case TGT_KIM1:
NewSymbol ("__KIM1__", 1);
break;
default:
AbEnd ("Invalid target name: '%s'", Sys);

View File

@ -299,6 +299,10 @@ static void SetSys (const char* Sys)
DefineNumericMacro ("__SYM1__", 1);
break;
case TGT_KIM1:
DefineNumericMacro ("__KIM1__", 1);
break;
default:
AbEnd ("Unknown target system '%s'", Sys);
}

View File

@ -163,6 +163,7 @@ static const TargetEntry TargetMap[] = {
{ "geos", TGT_GEOS_CBM },
{ "geos-apple", TGT_GEOS_APPLE },
{ "geos-cbm", TGT_GEOS_CBM },
{ "kim1", TGT_KIM1 },
{ "lunix", TGT_LUNIX },
{ "lynx", TGT_LYNX },
{ "module", TGT_MODULE },
@ -219,6 +220,7 @@ static const TargetProperties PropertyTable[TGT_COUNT] = {
{ "c65", CPU_4510, BINFMT_BINARY, CTPET },
{ "cx16", CPU_65C02, BINFMT_BINARY, CTPET },
{ "sym1", CPU_6502, BINFMT_BINARY, CTNone },
{ "kim1", CPU_6502, BINFMT_BINARY, CTNone },
};
/* Target system */

View File

@ -87,6 +87,7 @@ typedef enum {
TGT_C65,
TGT_CX16,
TGT_SYM1,
TGT_KIM1, // Added at end so as not to shift existing entries
TGT_COUNT /* Number of target systems */
} target_t;

View File

@ -742,6 +742,7 @@ TARGETS := \
creativision \
cx16 \
gamate \
kim1 \
lunix \
lynx \
nes \