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.
This commit is contained in:
Greg King 2015-09-28 11:27:39 -04:00
parent 067956b808
commit 6217f8fa3a
6 changed files with 63 additions and 27 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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__);

View File

@ -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