mirror of
https://github.com/cc65/cc65.git
synced 2024-12-23 04:30:10 +00:00
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:
parent
067956b808
commit
6217f8fa3a
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,40 +32,44 @@
|
||||
/* 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, '\"',
|
||||
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 void basbuf_len[];
|
||||
@ -75,22 +79,27 @@ 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);
|
||||
|
||||
/* 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 fd;
|
||||
return -1;
|
||||
}
|
||||
close (fd);
|
||||
}
|
||||
|
||||
n = 0;
|
||||
do {
|
||||
if ((basic.name[n] = progname[n]) == '\0') {
|
||||
break;
|
||||
@ -98,20 +107,34 @@ int __fastcall__ exec (const char* progname, const char* cmdline)
|
||||
} 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__);
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user