diff --git a/asminc/c128.inc b/asminc/c128.inc index 1fb8b397c..aac8678bf 100644 --- a/asminc/c128.inc +++ b/asminc/c128.inc @@ -6,6 +6,7 @@ ; --------------------------------------------------------------------------- ; Zero page, Commodore stuff +TXTPTR := $3D ; Pointer into BASIC source code TIME := $A0 ; 60HZ clock FNAM_LEN := $B7 ; Length of filename SECADR := $B9 ; Secondary address diff --git a/asminc/c64.inc b/asminc/c64.inc index f5dbcf549..f450fcc0b 100644 --- a/asminc/c64.inc +++ b/asminc/c64.inc @@ -6,6 +6,7 @@ ; --------------------------------------------------------------------------- ; Zero page, Commodore stuff +TXTPTR := $7A ; Pointer into BASIC source code TIME := $A0 ; 60 HZ clock FNAM_LEN := $B7 ; Length of filename SECADR := $B9 ; Secondary address diff --git a/asminc/cbm510.inc b/asminc/cbm510.inc index 827c507fc..dfeee1d4e 100644 --- a/asminc/cbm510.inc +++ b/asminc/cbm510.inc @@ -3,14 +3,17 @@ ; ; Taken from a kernal disassembly done by myself in 2000/2001. ; -; Ullrich von Bassewitz, 13.09.2001 +; 2001-09-13, Ullrich von Bassewitz +; 2013-08-26, Greg King ;----------------------------------------------------------------------------- ; Zeropage stuff -ExecReg = $00 -IndReg = $01 +ExecReg := $00 ; Controls execution memory bank +IndReg := $01 ; Controls indirect indexed load-store bank + +TXTPTR := $85 ; Far pointer into BASIC source code ; --------------------------------------------------------------------------- ; Screen size @@ -21,7 +24,7 @@ YSIZE = 25 ;----------------------------------------------------------------------------- ; I/O Definitions -; I/O $d800: VIC +; I/O $d800: VIC-II VIC_SPR0_X = $00 VIC_SPR0_Y = $01 @@ -75,7 +78,6 @@ VIC_BG_COLOR2 = $23 VIC_BG_COLOR3 = $24 - ; I/O $da00: SID 6581 SID_S1Lo = $00 @@ -112,7 +114,7 @@ SID_Noise = $1B SID_Read3 = $1C -; I/O $db00: CIA 6526 Inter Process Communication +; I/O $db00: CIA 6526, Inter Process Communication ; I/O $dc00: CIA 6526 .struct CIA @@ -176,7 +178,13 @@ SID_Read3 = $1C .endstruct -; Out video memory address +;----------------------------------------------------------------------------- +; Our video memory address -COLOR_RAM = $D400 ; System bank +COLOR_RAM := $D400 ; System bank + +;----------------------------------------------------------------------------- + +BASIC_BUF := $FB5E ; Bank 0 location of command-line +BASIC_BUF_LEN = 162 ; Maximum length of command-line diff --git a/asminc/cbm610.inc b/asminc/cbm610.inc index 94256eeb1..f442f5da8 100644 --- a/asminc/cbm610.inc +++ b/asminc/cbm610.inc @@ -1,16 +1,19 @@ ; -; Zeropage and I/O definitions for the CBM 610 +; Zero page variables and I/O definitions for the CBM 610 ; ; Taken from a kernal disassembly done by myself in 1987. ; -; Ullrich von Bassewitz, 28.09.1998 +; 1998-09-28, Ullrich von Bassewitz +; 2013-08-26, Greg King ; --------------------------------------------------------------------------- ; Zeropage stuff -ExecReg = $00 -IndReg = $01 +ExecReg := $00 ; Controls execution memory bank +IndReg := $01 ; Controls indirect indexed load-store bank + +TXTPTR := $85 ; Far pointer into BASIC source code ; --------------------------------------------------------------------------- ; Screen size @@ -29,7 +32,8 @@ YSIZE = 25 DATA .byte .endstruct -; I/O $db00: CIA 6526 Inter Process Communication + +; I/O $db00: CIA 6526, Inter Process Communication ; ; IPCcia = $db00 @@ -68,7 +72,6 @@ YSIZE = 25 ; cia = $dc00 - ; I/O $dd00: ACIA 6551 ; ; acia = $dd00 @@ -108,3 +111,7 @@ YSIZE = 25 ; tpi2 = $df00 +;----------------------------------------------------------------------------- + +BASIC_BUF := $FA5E ; Bank 1 location of command-line +BASIC_BUF_LEN = 162 ; Maximum length of command-line diff --git a/asminc/pet.inc b/asminc/pet.inc index a3dadf48d..1ebf391f9 100644 --- a/asminc/pet.inc +++ b/asminc/pet.inc @@ -7,6 +7,7 @@ ; Zero page, Commodore stuff MEMSIZE := $34 ; Size of memory installed +TXTPTR := $77 ; Pointer into BASIC source code TIME := $8D ; 60HZ clock KEY_COUNT := $9E ; Number of keys in input buffer RVS := $9F ; Reverse flag @@ -24,6 +25,9 @@ SCR_LINELEN := $D5 ; Screen line length CURS_Y := $D8 ; Cursor row FNADR := $DA ; Pointer to file name +BASIC_BUF := $200 ; Location of command-line +BASIC_BUF_LEN = 81 ; Maximum length of command-line + KEY_BUF := $26F ; Keyboard buffer ;---------------------------------------------------------------------------- diff --git a/asminc/plus4.inc b/asminc/plus4.inc index 014c18e60..17e250508 100644 --- a/asminc/plus4.inc +++ b/asminc/plus4.inc @@ -7,6 +7,7 @@ ; Zero page, Commodore stuff TMPPTR := $22 ; Temporary ptr used by BASIC +TXTPTR := $3B ; Pointer into BASIC source code TIME := $A3 ; 60HZ clock FNAM_LEN := $AB ; Length of filename LFN := $AC ; Logical file number diff --git a/asminc/vic20.inc b/asminc/vic20.inc index 6780d067d..c42db4258 100644 --- a/asminc/vic20.inc +++ b/asminc/vic20.inc @@ -6,6 +6,7 @@ ; --------------------------------------------------------------------------- ; Zero page, Commodore stuff +TXTPTR := $7A ; Pointer into BASIC source code TIME := $A0 ; 60HZ clock FNAM_LEN := $B7 ; Length of filename SECADR := $B9 ; Secondary address diff --git a/libsrc/cbm/exec.c b/libsrc/cbm/exec.c new file mode 100644 index 000000000..dec2e0080 --- /dev/null +++ b/libsrc/cbm/exec.c @@ -0,0 +1,99 @@ +/* +** Program-chaining function for Commodore platforms. +** +** 2013-08-24, Greg King +** +** This function exploits the program-chaining feature in CBM BASIC's ROM. +** It puts the desired program's name and unit number into a LOAD statement. +** Then, it points BASIC to that statement, so that the ROM will run that +** statement after this program quits. The ROM will load the next program, +** and will execute it (because the LOAD will be seen in a running program). +*/ + +#include +#include +#include +#include +#include +#include +#if defined(__CBM610__) +# include +#elif defined(__CBM510__) +# include +#endif + + +#pragma data-name(push, "LOWCODE") +static struct line { + const char end_of_line; + const struct line *const next; + const unsigned line_num; + const char load_token, quotes[2], add_token, quote; + char name[21]; + const char comma; + char unit[3]; +} basic = { + '\0', &basic + 1, /* high byte must be non-zero */ + 0, 0x93, + + /* This string operation copies the name to high BASIC RAM. + ** So, it won't be overwritten when the next program is loaded. + */ + "\"\"", 0xaa, '\"', + "\" ", /* format: "123:1234567890123456\"" */ + ',', "01" +}; +#pragma data-name(pop) + +/* These values are platform-specific. */ +extern const struct line *txtptr; +#pragma zpsym("txtptr") +extern char basbuf[]; /* BASIC's input buffer */ +extern void basbuf_len[]; +#pragma zpsym("basbuf_len") + + +int __fastcall__ exec (const char* progname, const char* cmdline) +{ + static int fd; + static unsigned char dv, n = 0; + + /* Exclude devices that can't load files. */ + dv = getcurrentdevice (); + if (dv < 8 && dv != 1 || dv > 30) { + return _mappederrno (9); /* illegal device number */ + } + utoa (dv, basic.unit, 10); + + /* Don't try to run a program that can't be found. */ + fd = open (progname, O_RDONLY); + if (fd < 0) { + return fd; + } + close (fd); + + do { + if ((basic.name[n] = progname[n]) == '\0') { + break; + } + } while (++n < 20); /* truncate long names */ + basic.name[n] = '\"'; + + /* Build the next program's argument list. */ + basbuf[0] = 0x8f; /* REM token */ + basbuf[1] = '\0'; + if (cmdline != NULL) { + strncat (basbuf, cmdline, (size_t)basbuf_len - 2); + } + +#if defined(__CBM510__) || defined(__CBM610__) + pokewsys ((unsigned)&txtptr, (unsigned)&basic); +#else + txtptr = &basic; +#endif + + /* (The return code, in ST, will be destroyed by LOAD. + ** So, don't bother to set it here.) + */ + exit (__AX__); +} diff --git a/libsrc/cbm/execvars.s b/libsrc/cbm/execvars.s new file mode 100644 index 000000000..02eabc12e --- /dev/null +++ b/libsrc/cbm/execvars.s @@ -0,0 +1,28 @@ +; +; Platform-specific variables for the exec program-chaining function +; + +.if .defined (__C128__) + .include "c128.inc" +.elseif .defined (__C16__) + .include "c16.inc" +.elseif .defined (__C64__) + .include "c64.inc" +.elseif .defined (__CBM510__) + .include "cbm510.inc" +.elseif .defined (__CBM610__) + .include "cbm610.inc" +.elseif .defined (__PET__) + .include "pet.inc" +.elseif .defined (__PLUS4__) + .include "plus4.inc" +.else + .include "vic20.inc" +.endif + + .export _txtptr:zp, _basbuf, _basbuf_len:zp + +_txtptr := TXTPTR + +_basbuf := BASIC_BUF +_basbuf_len = BASIC_BUF_LEN diff --git a/libsrc/pet/mainargs.s b/libsrc/pet/mainargs.s index 9a63f50c2..0d5b18987 100644 --- a/libsrc/pet/mainargs.s +++ b/libsrc/pet/mainargs.s @@ -13,7 +13,6 @@ MAXARGS = 10 ; Maximum number of arguments allowed REM = $8f ; BASIC token-code NAME_LEN = 16 ; maximum length of command-name -BASIC_BUF= $200 ;--------------------------------------------------------------------------- diff --git a/testcode/lib/arg-test.c b/testcode/lib/arg-test.c index c752acaeb..5c28faec0 100644 --- a/testcode/lib/arg-test.c +++ b/testcode/lib/arg-test.c @@ -9,6 +9,9 @@ int main (int argc, char* argv[]) for (I = 0; I < argc; ++I) { printf ("argv[%2d]: \"%s\"\n", I, argv[I]); } + + printf ("\n"); + getchar (); return EXIT_SUCCESS; } diff --git a/testcode/lib/exec-test1.c b/testcode/lib/exec-test1.c new file mode 100644 index 000000000..e2548fb0a --- /dev/null +++ b/testcode/lib/exec-test1.c @@ -0,0 +1,24 @@ +/* +** These programs test CC65's exec() program-chaining function. +** exec-test1 runs exec-test2 -- that tests the loading and starting of another +** program. Then, exec-test2 runs arg-test -- that tests command-line argument +** passing. +** +** 2013-08-24, Greg King +*/ + +#include +#include +#include +#include + +int main (void) { + clrscr (); + cprintf ("\nExec-test #1 -- launching #2...\r\n"); + + exec ("exec-test2", ""); + + cprintf ("\nFailed to find #2:\r\n %s.\r\n", _stroserror (_oserror)); + cgetc (); + return _oserror; +} diff --git a/testcode/lib/exec-test2.c b/testcode/lib/exec-test2.c new file mode 100644 index 000000000..e6c844a8e --- /dev/null +++ b/testcode/lib/exec-test2.c @@ -0,0 +1,23 @@ +/* +** These programs test CC65's exec() program-chaining function. +** exec-test1 runs exec-test2 -- that tests the loading and starting of another +** program. Then, exec-test2 runs arg-test -- that tests command-line argument +** passing. +** +** 2013-08-24, Greg King +*/ + +#include +#include +#include +#include + +int main (void) { + cprintf ("\nExec-test #2 -- launching arg-test...\r\n\n"); + + exec ("arg-test", "arg1 arg2 \"\" arg4"); + + cprintf ("\nFailed to find arg-test:\r\n %s.\r\n", _stroserror (_oserror)); + cgetc (); + return _oserror; +}