|
|
|
@ -2,8 +2,8 @@ |
|
|
|
|
|
|
|
/* Global variables */ |
|
|
|
|
|
|
|
char *progname; |
|
|
|
char **argv; |
|
|
|
char* progname; |
|
|
|
char** argv; |
|
|
|
int argc; |
|
|
|
|
|
|
|
byte cpm_drive; |
|
|
|
@ -14,6 +14,10 @@ char bindir80[CPM_MAXPATH] = ""; |
|
|
|
char libdir80[CPM_MAXPATH] = ""; |
|
|
|
char incdir80[CPM_MAXPATH] = ""; |
|
|
|
|
|
|
|
#ifndef _WIN32 |
|
|
|
struct termios tc_orig; |
|
|
|
#endif |
|
|
|
|
|
|
|
byte RAM[65536]; /* The Z80's address space */ |
|
|
|
|
|
|
|
void load_comfile(void); /* Forward declaration */ |
|
|
|
@ -21,31 +25,22 @@ void load_comfile(void); /* Forward declaration */ |
|
|
|
static int deinit_term, deinit_gsx; |
|
|
|
static void mkpath(char* fullpath, char* path, char* subdir); |
|
|
|
|
|
|
|
#ifndef _WIN32 |
|
|
|
struct termios tc_orig; |
|
|
|
|
|
|
|
void raw_init(void); |
|
|
|
void deinit_raw(void); |
|
|
|
#endif |
|
|
|
|
|
|
|
void dump_regs(FILE *fp, byte a, byte b, byte c, byte d, byte e, byte f, |
|
|
|
void dump_regs(FILE* fp, byte a, byte b, byte c, byte d, byte e, byte f, |
|
|
|
byte h, byte l, word pc, word ix, word iy) |
|
|
|
{ |
|
|
|
fprintf(fp, "\tAF=%02x%02x BC=%02x%02x DE=%02x%02x HL=%02x%02x\n" |
|
|
|
"\tIX=%04x IY=%04x PC=%04x\n", |
|
|
|
a,f,b,c,d,e,h,l,pc,ix,iy); |
|
|
|
a, f, b, c, d, e, h, l, pc, ix, iy); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char *parse_to_fcb(char *s, int afcb) |
|
|
|
char* parse_to_fcb(char* s, int afcb) |
|
|
|
{ |
|
|
|
byte *fcb = &RAM[afcb+1]; |
|
|
|
byte* fcb = &RAM[afcb + 1]; |
|
|
|
|
|
|
|
RAM[afcb] = 0; |
|
|
|
memset(fcb, ' ', 11); |
|
|
|
|
|
|
|
while (s[0]==' ') /* skip leading spaces */ |
|
|
|
while (s[0] == ' ') /* skip leading spaces */ |
|
|
|
{ |
|
|
|
s++; |
|
|
|
} |
|
|
|
@ -57,45 +52,30 @@ char *parse_to_fcb(char *s, int afcb) |
|
|
|
{ |
|
|
|
RAM[afcb] = s[0] - '@'; |
|
|
|
if (RAM[afcb] > 16) RAM[afcb] -= 0x20; |
|
|
|
s+=2; |
|
|
|
s += 2; |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (s[0] == '.') |
|
|
|
{ |
|
|
|
++s; |
|
|
|
fcb = &RAM[afcb+9]; |
|
|
|
fcb = &RAM[afcb + 9]; |
|
|
|
continue; |
|
|
|
} |
|
|
|
*fcb = *s; if (islower(*fcb)) *fcb = toupper(*fcb); |
|
|
|
++s; |
|
|
|
++fcb; |
|
|
|
if (fcb >= &RAM[afcb+12]) break; |
|
|
|
if (fcb >= &RAM[afcb + 12]) break; |
|
|
|
} |
|
|
|
return s; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Msg(char *s, ...) |
|
|
|
void ed_fe(byte* a, byte* b, byte* c, byte* d, byte* e, byte* f, |
|
|
|
byte* h, byte* l, word* pc, word* ix, word* iy) |
|
|
|
{ |
|
|
|
#ifdef DEBUG |
|
|
|
va_list ap; |
|
|
|
|
|
|
|
va_start(ap, s); |
|
|
|
fprintf(stderr, "%s trace: ", progname); |
|
|
|
vfprintf(stderr, s, ap); |
|
|
|
fflush(stderr); |
|
|
|
va_end(ap); |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void ed_fe(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, |
|
|
|
byte *h, byte *l, word *pc, word *ix, word *iy) |
|
|
|
{ |
|
|
|
switch(*a) |
|
|
|
switch (*a) |
|
|
|
{ |
|
|
|
case 0xC0: |
|
|
|
cpmbdos(a,b,c,d,e,f,h,l,pc,ix,iy); |
|
|
|
cpmbdos(a, b, c, d, e, f, h, l, pc, ix, iy); |
|
|
|
break; |
|
|
|
|
|
|
|
case 0xC1: |
|
|
|
@ -103,24 +83,23 @@ void ed_fe(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, |
|
|
|
break; |
|
|
|
|
|
|
|
case 0xC2: |
|
|
|
fprintf(stderr,"%s: Incompatible BIOS.BIN\n", progname); |
|
|
|
fprintf(stderr, "%s: Incompatible BIOS.BIN\n", progname); |
|
|
|
zxcc_term(); |
|
|
|
zxcc_exit(1); |
|
|
|
|
|
|
|
case 0xC3: |
|
|
|
cpmbios(a,b,c,d,e,f,h,l,pc,ix,iy); |
|
|
|
cpmbios(a, b, c, d, e, f, h, l, pc, ix, iy); |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
fprintf(stderr, "%s: Z80 encountered invalid trap\n", progname); |
|
|
|
dump_regs(stderr,*a,*b,*c,*d,*e,*f,*h,*l,*pc,*ix,*iy); |
|
|
|
dump_regs(stderr, *a, *b, *c, *d, *e, *f, *h, *l, *pc, *ix, *iy); |
|
|
|
zxcc_term(); |
|
|
|
zxcc_exit(1); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* load_bios() loads the minimal CP/M BIOS and BDOS. |
|
|
|
* |
|
|
|
@ -158,7 +137,7 @@ void load_bios(void) |
|
|
|
} |
|
|
|
if (!fp) |
|
|
|
{ |
|
|
|
fprintf(stderr,"%s: Cannot locate bios.bin\n", progname); |
|
|
|
fprintf(stderr, "%s: Cannot locate bios.bin\n", progname); |
|
|
|
zxcc_term(); |
|
|
|
zxcc_exit(1); |
|
|
|
} |
|
|
|
@ -166,30 +145,30 @@ void load_bios(void) |
|
|
|
if (bios_len < 1 || ferror(fp)) |
|
|
|
{ |
|
|
|
fclose(fp); |
|
|
|
fprintf(stderr,"%s: Cannot load bios.bin\n", progname); |
|
|
|
fprintf(stderr, "%s: Cannot load bios.bin\n", progname); |
|
|
|
zxcc_term(); |
|
|
|
zxcc_exit(1); |
|
|
|
} |
|
|
|
fclose(fp); |
|
|
|
|
|
|
|
Msg("Loaded %d bytes of BIOS\n", bios_len); |
|
|
|
DBGMSGV("Loaded %d bytes of BIOS\n", bios_len); |
|
|
|
} |
|
|
|
/*
|
|
|
|
* try_com() attempts to open file, file.com, file.COM, file.cpm and file.CPM |
|
|
|
* |
|
|
|
*/ |
|
|
|
|
|
|
|
FILE *try_com(char *s) |
|
|
|
FILE* try_com(char* s) |
|
|
|
{ |
|
|
|
char fname[CPM_MAXPATH + 1]; |
|
|
|
FILE *fp; |
|
|
|
FILE* fp; |
|
|
|
|
|
|
|
strcpy(fname, s); |
|
|
|
fp = fopen(s, "rb"); if (fp) return fp; |
|
|
|
sprintf(s,"%s.com", fname); fp = fopen(s, "rb"); if (fp) return fp; |
|
|
|
sprintf(s,"%s.COM", fname); fp = fopen(s, "rb"); if (fp) return fp; |
|
|
|
sprintf(s,"%s.cpm", fname); fp = fopen(s, "rb"); if (fp) return fp; |
|
|
|
sprintf(s,"%s.CPM", fname); fp = fopen(s, "rb"); if (fp) return fp; |
|
|
|
sprintf(s, "%s.com", fname); fp = fopen(s, "rb"); if (fp) return fp; |
|
|
|
sprintf(s, "%s.COM", fname); fp = fopen(s, "rb"); if (fp) return fp; |
|
|
|
sprintf(s, "%s.cpm", fname); fp = fopen(s, "rb"); if (fp) return fp; |
|
|
|
sprintf(s, "%s.CPM", fname); fp = fopen(s, "rb"); if (fp) return fp; |
|
|
|
|
|
|
|
strcpy(s, fname); |
|
|
|
return NULL; |
|
|
|
@ -205,7 +184,7 @@ void load_comfile(void) |
|
|
|
{ |
|
|
|
size_t com_len; |
|
|
|
char fname[CPM_MAXPATH + 1]; |
|
|
|
FILE *fp; |
|
|
|
FILE* fp; |
|
|
|
|
|
|
|
/* Look in current directory first */ |
|
|
|
strcpy(fname, argv[1]); |
|
|
|
@ -218,7 +197,7 @@ void load_comfile(void) |
|
|
|
} |
|
|
|
if (!fp) |
|
|
|
{ |
|
|
|
fprintf(stderr,"%s: Cannot locate %s, %s.com, %s.COM, %s.cpm _or_ %s.CPM\r\n", |
|
|
|
fprintf(stderr, "%s: Cannot locate %s, %s.com, %s.COM, %s.cpm _or_ %s.CPM\n", |
|
|
|
progname, argv[1], argv[1], argv[1], argv[1], argv[1]); |
|
|
|
zxcc_term(); |
|
|
|
zxcc_exit(1); |
|
|
|
@ -227,22 +206,22 @@ void load_comfile(void) |
|
|
|
if (com_len < 1 || ferror(fp)) |
|
|
|
{ |
|
|
|
fclose(fp); |
|
|
|
fprintf(stderr,"%s: Cannot load %s\n", progname, fname); |
|
|
|
fprintf(stderr, "%s: Cannot load %s\n", progname, fname); |
|
|
|
zxcc_term(); |
|
|
|
zxcc_exit(1); |
|
|
|
} |
|
|
|
fclose(fp); |
|
|
|
|
|
|
|
/* read() can corrupt buffer area following data read if length
|
|
|
|
* of data read is less than buffer. Clean it up. */ |
|
|
|
memset(RAM + 0x0100 + com_len, 0, 0xFD00 - com_len); |
|
|
|
|
|
|
|
Msg("Loaded %d bytes from %s\n", com_len, fname); |
|
|
|
DBGMSGV("Loaded %d bytes from %s\n", com_len, fname); |
|
|
|
} |
|
|
|
|
|
|
|
unsigned int in() { return 0; } |
|
|
|
unsigned int out() { return 0; } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* xltname: Convert a unix filepath into a CP/M compatible drive:name form. |
|
|
|
* The unix filename must be 8.3 or the CP/M code will reject it. |
|
|
|
@ -251,7 +230,7 @@ unsigned int out() { return 0; } |
|
|
|
* the result to the command line. |
|
|
|
*/ |
|
|
|
|
|
|
|
void zxcc_xltname(char *name, char *pcmd) |
|
|
|
void zxcc_xltname(char* name, char* pcmd) |
|
|
|
{ |
|
|
|
char nbuf[CPM_MAXPATH + 1]; |
|
|
|
|
|
|
|
@ -267,17 +246,16 @@ void zxcc_xltname(char *name, char *pcmd) |
|
|
|
on the endianness of the host CPU and the sizes of data types. |
|
|
|
*/ |
|
|
|
|
|
|
|
int main(int ac, char **av) |
|
|
|
int main(int ac, char** av) |
|
|
|
{ |
|
|
|
int n; |
|
|
|
char *pCmd, *str; |
|
|
|
char* pCmd, * str; |
|
|
|
char* tmpenv; |
|
|
|
|
|
|
|
|
|
|
|
argc = ac; |
|
|
|
argv = av; |
|
|
|
#ifdef __PACIFIC__ /* Pacific C doesn't support argv[0] */ |
|
|
|
progname="ZXCC"; |
|
|
|
progname = "ZXCC"; |
|
|
|
#endif |
|
|
|
progname = argv[0]; |
|
|
|
|
|
|
|
@ -289,38 +267,27 @@ int main(int ac, char **av) |
|
|
|
|
|
|
|
#ifdef DEBUG |
|
|
|
fprintf(stderr, "\n\n"); |
|
|
|
Msg("Start of execution: "); |
|
|
|
DBGMSG("Start of execution: "); |
|
|
|
for (n = 0; n < argc; n++) |
|
|
|
fprintf(stderr, " %s", argv[n]); |
|
|
|
fprintf(stderr, "\n"); |
|
|
|
#endif |
|
|
|
|
|
|
|
if (_isatty(STDIN_FILENO)) |
|
|
|
Msg("Using interactive console mode\n"); |
|
|
|
else |
|
|
|
Msg("Using standard input/ouput mode\n"); |
|
|
|
term_init(); |
|
|
|
|
|
|
|
if (sizeof(int) > 8 || sizeof(byte) != 1 || sizeof(word) != 2) |
|
|
|
{ |
|
|
|
fprintf(stderr,"%s: type lengths incorrect; edit typedefs " |
|
|
|
fprintf(stderr, "%s: type lengths incorrect; edit typedefs " |
|
|
|
"and recompile.\n", progname); |
|
|
|
zxcc_exit(1); |
|
|
|
} |
|
|
|
|
|
|
|
if (argc < 2) |
|
|
|
{ |
|
|
|
fprintf(stderr,"%s: No CP/M program name provided.\n",progname); |
|
|
|
fprintf(stderr, "%s: No CP/M program name provided.\n", progname); |
|
|
|
zxcc_exit(1); |
|
|
|
} |
|
|
|
|
|
|
|
#ifdef _WIN32 |
|
|
|
setmode(STDIN_FILENO, O_BINARY ); |
|
|
|
setmode(STDOUT_FILENO, O_BINARY ); |
|
|
|
#else |
|
|
|
if (_isatty(STDIN_FILENO)) |
|
|
|
raw_init(); |
|
|
|
#endif |
|
|
|
|
|
|
|
/* Parse arguments. An argument can be either:
|
|
|
|
|
|
|
|
* preceded by a '-', in which case it is copied in as-is, less the |
|
|
|
@ -360,15 +327,15 @@ int main(int ac, char **av) |
|
|
|
if ((tmpenv = getenv("INCDIR80"))) |
|
|
|
mkpath(incdir80, tmpenv, ""); |
|
|
|
|
|
|
|
Msg("BINDIR80=\"%s\"\n", bindir80); |
|
|
|
Msg("LIBDIR80=\"%s\"\n", libdir80); |
|
|
|
Msg("INCDIR80=\"%s\"\n", incdir80); |
|
|
|
DBGMSGV("BINDIR80=\"%s\"\n", bindir80); |
|
|
|
DBGMSGV("LIBDIR80=\"%s\"\n", libdir80); |
|
|
|
DBGMSGV("INCDIR80=\"%s\"\n", incdir80); |
|
|
|
|
|
|
|
xlt_map(0, bindir80); /* Establish the 3 fixed mappings */ |
|
|
|
xlt_map(1, libdir80); |
|
|
|
xlt_map(2, incdir80); |
|
|
|
|
|
|
|
pCmd = (char *)RAM + 0x81; |
|
|
|
pCmd = (char*)RAM + 0x81; |
|
|
|
|
|
|
|
for (n = 2; n < argc; n++) |
|
|
|
{ |
|
|
|
@ -385,7 +352,7 @@ int main(int ac, char **av) |
|
|
|
} |
|
|
|
else if (argv[n][0] == '+') |
|
|
|
{ |
|
|
|
zxcc_xltname(pCmd, argv[n]+1); |
|
|
|
zxcc_xltname(pCmd, argv[n] + 1); |
|
|
|
} |
|
|
|
else /* Translate a filename */ |
|
|
|
{ |
|
|
|
@ -401,7 +368,7 @@ int main(int ac, char **av) |
|
|
|
parse_to_fcb(str, 0x6C); |
|
|
|
|
|
|
|
// This statement is very useful when creating a client like zxc or zxas
|
|
|
|
Msg("Command tail is \"%s\"\n", pCmd); |
|
|
|
DBGMSGV("Command tail is \"%s\"\n", pCmd); |
|
|
|
|
|
|
|
load_bios(); |
|
|
|
|
|
|
|
@ -462,10 +429,6 @@ int zxcc_term(void) |
|
|
|
{ |
|
|
|
word n; |
|
|
|
|
|
|
|
#ifndef _WIN32 |
|
|
|
deinit_raw(); |
|
|
|
#endif |
|
|
|
|
|
|
|
//n = RAM[0x81]; /* Get the return code. This is Hi-Tech C */
|
|
|
|
//n = (n << 8) | RAM[0x80]; /* specific and fails with other COM files */
|
|
|
|
n = 0; |
|
|
|
@ -476,12 +439,15 @@ int zxcc_term(void) |
|
|
|
{ /* (my modified Hi-Tech C library uses this */ |
|
|
|
n = cpm_error; /* call) */ |
|
|
|
} |
|
|
|
|
|
|
|
if (n < 256 || n == 0xFFFF) |
|
|
|
{ |
|
|
|
Msg("Return code %d\n", n); |
|
|
|
DBGMSGV("Return code %d\n", n); |
|
|
|
else |
|
|
|
n = 0; |
|
|
|
|
|
|
|
term_reset(); |
|
|
|
|
|
|
|
return n; |
|
|
|
} |
|
|
|
else return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/* helper function to build full path */ |
|
|
|
@ -503,11 +469,11 @@ void raw_init(void) |
|
|
|
{ |
|
|
|
struct termios tc_raw; |
|
|
|
|
|
|
|
Msg("Enabling RAW Terminal IO\n"); |
|
|
|
DBGMSG("Enabling RAW Terminal IO\n"); |
|
|
|
|
|
|
|
if (tcgetattr(STDIN_FILENO, &tc_orig) == -1) |
|
|
|
{ |
|
|
|
Msg("Failed to enable RAW Terminal IO - tcgetattr() failed\n"); |
|
|
|
DBGMSG("Failed to enable RAW Terminal IO - tcgetattr() failed\n"); |
|
|
|
zxcc_exit(1);; |
|
|
|
} |
|
|
|
|
|
|
|
@ -527,11 +493,11 @@ void raw_init(void) |
|
|
|
|
|
|
|
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tc_raw) == -1) |
|
|
|
{ |
|
|
|
Msg("Failed to enable RAW Terminal IO - tcsetattr() failed\n"); |
|
|
|
DBGMSG("Failed to enable RAW Terminal IO - tcsetattr() failed\n"); |
|
|
|
zxcc_exit(1); |
|
|
|
} |
|
|
|
|
|
|
|
Msg("Enabled RAW Terminal IO\n"); |
|
|
|
DBGMSG("Enabled RAW Terminal IO\n"); |
|
|
|
|
|
|
|
return; |
|
|
|
} |
|
|
|
@ -540,13 +506,39 @@ void deinit_raw(void) |
|
|
|
{ |
|
|
|
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tc_orig) == -1) |
|
|
|
{ |
|
|
|
Msg("Failed to disable RAW Terminal IO - tcsetattr() failed\n"); |
|
|
|
DBGMSG("Failed to disable RAW Terminal IO - tcsetattr() failed\n"); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
Msg("Disabled RAW Terminal IO\n"); |
|
|
|
DBGMSG("Disabled RAW Terminal IO\n"); |
|
|
|
|
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
void term_init(void) |
|
|
|
{ |
|
|
|
#ifdef _WIN32 |
|
|
|
setmode(STDIN_FILENO, O_BINARY); |
|
|
|
setmode(STDOUT_FILENO, O_BINARY); |
|
|
|
#else |
|
|
|
if (_isatty(STDIN_FILENO)) |
|
|
|
raw_init(); |
|
|
|
#endif |
|
|
|
|
|
|
|
if (_isatty(STDIN_FILENO)) |
|
|
|
DBGMSG("Using interactive console mode\n"); |
|
|
|
else |
|
|
|
DBGMSG("Using standard input/output mode\n"); |
|
|
|
|
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
void term_reset(void) |
|
|
|
{ |
|
|
|
#ifndef _WIN32 |
|
|
|
if (_isatty(STDIN_FILENO)) |
|
|
|
deinit_raw(); |
|
|
|
#endif |
|
|
|
} |
|
|
|
|