From: Greg King Date: Mon, 28 Sep 2015 15:27:39 +0000 (-0400) Subject: Made the Commodore version of exec() work in programs that are so big that they load... X-Git-Tag: V2.16~225^2 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=refs%2Fpull%2F214%2Fhead;p=cc65 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. --- 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 + +.exportzp _txtptr := TXTPTR -_basbuf := BASIC_BUF -_basbuf_len = BASIC_BUF_LEN +.export _basbuf := BASIC_BUF +.exportzp _basbuf_len = BASIC_BUF_LEN