From 799aec23a64c9f11fa2591f5e8dc7a93ee298430 Mon Sep 17 00:00:00 2001 From: Dave Plummer Date: Sat, 4 Jun 2022 13:00:48 -0700 Subject: [PATCH] Add KIM-1 Support --- asminc/kim1.inc | 28 +++++++++++++++++ cfg/kim1.cfg | 41 ++++++++++++++++++++++++ include/kim1.h | 67 ++++++++++++++++++++++++++++++++++++++++ libsrc/Makefile | 1 + libsrc/kim1/crt0.s | 47 ++++++++++++++++++++++++++++ libsrc/kim1/ctype.s | 5 +++ libsrc/kim1/read.s | 51 ++++++++++++++++++++++++++++++ libsrc/kim1/tapeio.s | 39 +++++++++++++++++++++++ libsrc/kim1/write.s | 49 +++++++++++++++++++++++++++++ samples/Makefile | 6 +++- samples/kim1/Makefile | 56 +++++++++++++++++++++++++++++++++ samples/kim1/kimHello | Bin 0 -> 2789 bytes samples/kim1/kimHello.c | 24 ++++++++++++++ src/ca65/main.c | 4 +++ src/cc65/main.c | 4 +++ src/common/target.c | 2 ++ src/common/target.h | 1 + targettest/Makefile | 1 + 18 files changed, 425 insertions(+), 1 deletion(-) create mode 100644 asminc/kim1.inc create mode 100644 cfg/kim1.cfg create mode 100644 include/kim1.h create mode 100644 libsrc/kim1/crt0.s create mode 100644 libsrc/kim1/ctype.s create mode 100644 libsrc/kim1/read.s create mode 100644 libsrc/kim1/tapeio.s create mode 100644 libsrc/kim1/write.s create mode 100644 samples/kim1/Makefile create mode 100644 samples/kim1/kimHello create mode 100644 samples/kim1/kimHello.c diff --git a/asminc/kim1.inc b/asminc/kim1.inc new file mode 100644 index 000000000..f0d1555a7 --- /dev/null +++ b/asminc/kim1.inc @@ -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 +; --------------------------------------------------------------------------- + diff --git a/cfg/kim1.cfg b/cfg/kim1.cfg new file mode 100644 index 000000000..69636065e --- /dev/null +++ b/cfg/kim1.cfg @@ -0,0 +1,41 @@ +# kim1.cfg (4k) +# +# for unexpanded Kim-1 +# +# ld65 --config kim1.cfg -o .bin .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; +} + diff --git a/include/kim1.h b/include/kim1.h new file mode 100644 index 000000000..52e690c9d --- /dev/null +++ b/include/kim1.h @@ -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 diff --git a/libsrc/Makefile b/libsrc/Makefile index 2018de801..627897d9b 100644 --- a/libsrc/Makefile +++ b/libsrc/Makefile @@ -27,6 +27,7 @@ TARGETS = apple2 \ $(CBMS) \ $(GEOS) \ gamate \ + kim1 \ lynx \ nes \ none \ diff --git a/libsrc/kim1/crt0.s b/libsrc/kim1/crt0.s new file mode 100644 index 000000000..7e7dd485b --- /dev/null +++ b/libsrc/kim1/crt0.s @@ -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 + diff --git a/libsrc/kim1/ctype.s b/libsrc/kim1/ctype.s new file mode 100644 index 000000000..1301965eb --- /dev/null +++ b/libsrc/kim1/ctype.s @@ -0,0 +1,5 @@ +; Character specification table. +; +; uses the "common" definition + + .include "ctype_common.inc" diff --git a/libsrc/kim1/read.s b/libsrc/kim1/read.s new file mode 100644 index 000000000..5566a9f27 --- /dev/null +++ b/libsrc/kim1/read.s @@ -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 diff --git a/libsrc/kim1/tapeio.s b/libsrc/kim1/tapeio.s new file mode 100644 index 000000000..4a16d6b9c --- /dev/null +++ b/libsrc/kim1/tapeio.s @@ -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 diff --git a/libsrc/kim1/write.s b/libsrc/kim1/write.s new file mode 100644 index 000000000..216f5031c --- /dev/null +++ b/libsrc/kim1/write.s @@ -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 diff --git a/samples/Makefile b/samples/Makefile index 4007e3522..cec4bed89 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -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 \ diff --git a/samples/kim1/Makefile b/samples/kim1/Makefile new file mode 100644 index 000000000..89600ad5a --- /dev/null +++ b/samples/kim1/Makefile @@ -0,0 +1,56 @@ + +# Run 'make SYS='; 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) diff --git a/samples/kim1/kimHello b/samples/kim1/kimHello new file mode 100644 index 0000000000000000000000000000000000000000..5842567557dc9f321409d269970f08832b736d86 GIT binary patch literal 2789 zcmbVOTWl2989pPwHj|K(i1^Ur@f{@6caBR^#e^evV4CFt9Pc8bVHbVBy0T$R2rJ0ktL?4Nib zo8J=YZ<8)^P!)bIYN9})f5+@!{>KkCxqxB*K%{?2S`KParRkDPJQrCHdD} z0@!q1Hct~T-8U=R>2Yzg!)n|iY!z*Y=9&Z-6I^_pQ(G)ZbVziBX1ZQ%rU7*b56R8W zzS-W9rvhdCYxE5<>*1Q5z-yyl4%@htlkG^!b8X~$(5S~j+uJQr9m%C)In)>Rzec2U&e!Iy&9tvVtJlaZjs>yGJKl==tlO% zXy-%Q-io#@kV>@SXK-OY>rI55LlFu+v5UA_}tI20RRB<@m$XfCNhAl?vz z*O?A!QC=cGD&HgK$#}2_4)wDQE^2_eqDvcKzUV$#xl8D8#8IhNJ$09aiQy$4dPkw( zl=z_otb=D4E^yChsu-eC#o(0SAX^8=PTeG7SGHipjkp+>v<0Hw1`NNKE{b^vuV5Tv znu{uT$PBp0Kg`wzgN$(7hz7RuOMb#sIwHcIJEJ=fgQ2gno@@ial?cm!4FLHT1GeOY z!%SYuxB&&ugE=eeD@s|{Dk-h8Y)Hr00-4jb#%*%)dP*BlRCH}PrS&!D$#q?;H*OI= z3-PV*Y?p7563}_lm?KQ0-4gw(1Y*cVz%Lsb_;HnHO=UC3a>z!Ia6;a4+Lw-ui%@Ig zkOUrtWm_oNnsLM9_pKo!Oem-DMU)*zQWrOa$|I>LVuZn7Le%? z!UWJnm~h)AlO{pNp$>ErstQ_C2IlG~GW5Lci}Xqo&O<{IsGxu;$pD32=9iL}+H7^u zX5Ac5j#V=pCz8c#<{VdCbOL2z2H8-l$nMUYA0*3*P;ACapa#1FSvZb6* z&s&+D?S3H(nb42wp2(RkdQ!xtyanM{j&+s}CmhL>cq0*kl&UCStRl-ccnebss!a+S zJt%Vx8nZ>ej%(7W@t(q-^TfCu$86Q5BTRGDiQ8&bDH==WUvbG;?Qd{URcR?;zsmbC z4U@d`%(pQB_~2~nBi_H)ifg6yXN{5Aw9&#vHg|I3iVDpgfT0N4Cl1P2l~9^uOCG6d z7E8FOWUmX%~9jU$gh?>da zx+muh+bHcd_U(naBAfN}TFNrF$OU;6*YpA&(j9C*FWWjl@4yFytL@Z|2d7hZsI>$1-l@(MIr=3XX6;Y7of>)5}T24^F|l z#REB0Q0p@VWjUUc3X4su;S==xk5T8bo?iq>h60VneFaoFhFh3@+LGBvk?&8ZvrTj~ zod>kj9bD`H(c&56f^khH#8d2EOPyi2k6HY?_zEwPFiratJt9;w?x)ao*&IO5cuGx$ zbhY&;LUdG#9%~=jl4I0T;p03v)~}W7XLV1SPK{t&DoyM47A_Up69>}YE)&`trCnTRNqAu{5TWMvyKOpFlOxSER-TGIo*tPY4?Xl|Zg7xp|L(5s-+PK48p!P) z%xzQ@q-1jg0|)7=2j3jn^90wGUHRPyemKbG-lw10wD}v)Zs~jO`ES3lZTpT5&pf?( z%jUjK&u;ERNDzsv7+YU**j^a5Vv)0G$Y^e JbXnmD{{hxi-7)|G literal 0 HcmV?d00001 diff --git a/samples/kim1/kimHello.c b/samples/kim1/kimHello.c new file mode 100644 index 000000000..dcbfb4e67 --- /dev/null +++ b/samples/kim1/kimHello.c @@ -0,0 +1,24 @@ +// -------------------------------------------------------------------------- +// Hello World for Kim-1 +// +// Dave Plummer based on Sym-1 sample by Wayne Parham +// +// davepl@davepl.com +// -------------------------------------------------------------------------- + +#include +#include + +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; +} diff --git a/src/ca65/main.c b/src/ca65/main.c index b1ef3a3db..4146aaf11 100644 --- a/src/ca65/main.c +++ b/src/ca65/main.c @@ -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); diff --git a/src/cc65/main.c b/src/cc65/main.c index c08616efa..f800ac43e 100644 --- a/src/cc65/main.c +++ b/src/cc65/main.c @@ -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); } diff --git a/src/common/target.c b/src/common/target.c index 4a851034a..ad62990bd 100644 --- a/src/common/target.c +++ b/src/common/target.c @@ -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 */ diff --git a/src/common/target.h b/src/common/target.h index 7087048e2..7439fa621 100644 --- a/src/common/target.h +++ b/src/common/target.h @@ -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; diff --git a/targettest/Makefile b/targettest/Makefile index 0450bfd4e..23463ccd9 100644 --- a/targettest/Makefile +++ b/targettest/Makefile @@ -742,6 +742,7 @@ TARGETS := \ creativision \ cx16 \ gamate \ + kim1 \ lunix \ lynx \ nes \