From 6217f8fa3ae57bfcb29abb6ea2b4d118384d3e06 Mon Sep 17 00:00:00 2001 From: Greg King Date: Mon, 28 Sep 2015 11:27:39 -0400 Subject: [PATCH] Made the Commodore version of exec() work in programs that are so big that they load into all of BASIC RAM. The function won't cause an "out of memory" error. --- asminc/c64.inc | 2 ++ asminc/pet.inc | 1 + asminc/plus4.inc | 2 ++ asminc/vic20.inc | 2 ++ libsrc/cbm/exec.c | 69 ++++++++++++++++++++++++++++--------------- libsrc/cbm/execvars.s | 14 ++++++--- 6 files changed, 63 insertions(+), 27 deletions(-) diff --git a/asminc/c64.inc b/asminc/c64.inc index f450fcc0b..5815bebf9 100644 --- a/asminc/c64.inc +++ b/asminc/c64.inc @@ -6,6 +6,8 @@ ; --------------------------------------------------------------------------- ; Zero page, Commodore stuff +VARTAB := $2D ; Pointer to start of BASIC variables +MEMSIZE := $37 ; Pointer to highest BASIC RAM location (+1) TXTPTR := $7A ; Pointer into BASIC source code TIME := $A0 ; 60 HZ clock FNAM_LEN := $B7 ; Length of filename diff --git a/asminc/pet.inc b/asminc/pet.inc index 1ebf391f9..a745a89c8 100644 --- a/asminc/pet.inc +++ b/asminc/pet.inc @@ -6,6 +6,7 @@ ; --------------------------------------------------------------------------- ; Zero page, Commodore stuff +VARTAB := $2A ; Pointer to start of BASIC variables MEMSIZE := $34 ; Size of memory installed TXTPTR := $77 ; Pointer into BASIC source code TIME := $8D ; 60HZ clock diff --git a/asminc/plus4.inc b/asminc/plus4.inc index 17e250508..69b2298a3 100644 --- a/asminc/plus4.inc +++ b/asminc/plus4.inc @@ -7,6 +7,8 @@ ; Zero page, Commodore stuff TMPPTR := $22 ; Temporary ptr used by BASIC +VARTAB := $2D ; Pointer to start of BASIC variables +MEMSIZE := $37 ; Pointer to highest BASIC RAM location (+1) TXTPTR := $3B ; Pointer into BASIC source code TIME := $A3 ; 60HZ clock FNAM_LEN := $AB ; Length of filename diff --git a/asminc/vic20.inc b/asminc/vic20.inc index c42db4258..12424dc11 100644 --- a/asminc/vic20.inc +++ b/asminc/vic20.inc @@ -6,6 +6,8 @@ ; --------------------------------------------------------------------------- ; Zero page, Commodore stuff +VARTAB := $2D ; Pointer to start of BASIC variables +MEMSIZE := $37 ; Pointer to highest BASIC RAM location (+1) TXTPTR := $7A ; Pointer into BASIC source code TIME := $A0 ; 60HZ clock FNAM_LEN := $B7 ; Length of filename diff --git a/libsrc/cbm/exec.c b/libsrc/cbm/exec.c index 36c3afe00..b9c1bdc96 100644 --- a/libsrc/cbm/exec.c +++ b/libsrc/cbm/exec.c @@ -1,7 +1,7 @@ /* ** Program-chaining function for Commodore platforms. ** -** 2013-09-04, Greg King +** 2015-09-27, Greg King ** ** This function exploits the program-chaining feature in CBM BASIC's ROM. ** @@ -32,42 +32,46 @@ /* The struct below is a line of BASIC code. It sits in the LOWCODE segment ** to make sure that it won't be hidden by a ROM when BASIC is re-enabled. ** The line is: -** 0 LOAD""+"" ,01 +** 0 CLR:LOAD""+"" ,01 ** After this function has written into the line, it might look like this: -** 0 LOAD""+"program name" ,08 +** 0 CLR:LOAD""+"program name" ,08 ** ** When BASIC's LOAD command asks the Kernal to load a file, it gives the ** Kernal a pointer to a file-name string. CC65's CBM programs use that ** pointer to give a copy of the program's name to main()'s argv[0] parameter. -** But, when BASIC uses a string literal that's in a program, it points +** But, when BASIC uses a string literal that is in a program, it points ** directly to that literal -- in the models that don't use banked RAM ** (Pet/CBM, VIC-20, and 64). The literal is overwritten by the next program -** that's loaded. So, argv[0] would point to machine code. String operations +** that is loaded. So, argv[0] would point to machine code. String operations ** create a new result string -- even when that operation changes nothing. The ** result is put in the string space at the top of BASIC's memory. So, the ""+ ** in this BASIC line guarantees that argv[0] will get a name from a safe place. */ #pragma data-name(push, "LOWCODE") static struct line { - const char end_of_line; - const struct line *const next; + const char end_of_line; /* fake previous line */ + const struct line* const next; const unsigned line_num; - const char load_token, quotes[2], add_token, quote; + const char CLR_token, colon, LOAD_token, quotes[2], add_token, quote; char name[21]; const char comma; char unit[3]; } basic = { - '\0', &basic + 1, /* high byte of link must be non-zero */ - 0, 0x93, "\"\"", 0xaa, '\"', - "\" ", /* format: "123:1234567890123456\"" */ + '\0', &basic + 1, /* high byte of link must be non-zero */ + 0, 0x9C, ':', 0x93, "\"\"", 0xAA, '\"', + "\" ", /* format: "123:1234567890123456\"" */ ',', "01" }; #pragma data-name(pop) /* These values are platform-specific. */ -extern const struct line *txtptr; +extern const void* vartab; /* points to BASIC program variables */ +#pragma zpsym("vartab") +extern const void* memsize; /* points to top of BASIC RAM */ +#pragma zpsym("memsize") +extern const struct line* txtptr; /* points to BASIC code */ #pragma zpsym("txtptr") -extern char basbuf[]; /* BASIC's input buffer */ +extern char basbuf[]; /* BASIC's input buffer */ extern void basbuf_len[]; #pragma zpsym("basbuf_len") @@ -75,43 +79,62 @@ extern void basbuf_len[]; int __fastcall__ exec (const char* progname, const char* cmdline) { static int fd; - static unsigned char dv, n = 0; + static unsigned char dv, n; /* Exclude devices that can't load files. */ + /* (Use hand optimization, to make smaller code.) */ dv = getcurrentdevice (); - if (dv < 8 && dv != 1 || dv > 30) { + if (dv < 8 && __AX__ != 1 || __AX__ > 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; + /* Tape files can be openned only once; skip this test for the Datasette. */ + if (dv != 1) { + /* Don't try to run a program that can't be found. */ + fd = open (progname, O_RDONLY); + if (fd < 0) { + return -1; + } + close (fd); } - close (fd); + n = 0; do { if ((basic.name[n] = progname[n]) == '\0') { break; } - } while (++n < 20); /* truncate long names */ + } while (++n < 20); /* truncate long names */ basic.name[n] = '\"'; +/* This next part isn't needed by machines that put +** BASIC source and variables in different RAM banks. +*/ +#if !defined(__CBM510__) && !defined(__CBM610__) && !defined(__C128__) + /* cc65 program loads might extend beyond the end of the RAM that is allowed + ** for BASIC. Then, the LOAD statement would complain that it is "out of + ** memory". Some pointers that say where to put BASIC program variables + ** must be changed, so that we do not get that error. One pointer is + ** changed here; a BASIC CLR statement changes the others. + */ + vartab = (char*)memsize - 256; +#endif + /* Build the next program's argument list. */ - basbuf[0] = 0x8f; /* REM token */ + basbuf[0] = 0x8F; /* REM token */ basbuf[1] = '\0'; if (cmdline != NULL) { strncat (basbuf, cmdline, (size_t)basbuf_len - 2); } + /* Tell the ROM where to find that BASIC program. */ #if defined(__CBM510__) || defined(__CBM610__) pokewsys ((unsigned)&txtptr, (unsigned)&basic); #else txtptr = &basic; #endif - /* (The return code, in ST, will be destroyed by LOAD. + /* (The return code, in ST [status], 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 index 02eabc12e..68f8a5d64 100644 --- a/libsrc/cbm/execvars.s +++ b/libsrc/cbm/execvars.s @@ -20,9 +20,15 @@ .include "vic20.inc" .endif - .export _txtptr:zp, _basbuf, _basbuf_len:zp +; exec() is written in C. +; Provide the spellings that the C compiler wants to use. -_txtptr := TXTPTR +.ifdef VARTAB +.exportzp _vartab := VARTAB +.exportzp _memsize := MEMSIZE +.endif -_basbuf := BASIC_BUF -_basbuf_len = BASIC_BUF_LEN +.exportzp _txtptr := TXTPTR + +.export _basbuf := BASIC_BUF +.exportzp _basbuf_len = BASIC_BUF_LEN