mirror of
https://github.com/RevCurtisP/C02.git
synced 2024-11-27 19:49:41 +00:00
Multiple modifications to run6502.c and file6502.c
This commit is contained in:
parent
eee6661a01
commit
60ac041bb1
@ -13,12 +13,16 @@
|
||||
#include <io.h> /* _findfirst and _findnext set errno iff they return -1 */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define EPOCH 116444736000000000 //January 1, 1970 as MS file time
|
||||
#define RATIO 10000000 //Conversion Factor - Hundreds of Nanoseconds
|
||||
|
||||
typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */
|
||||
|
||||
struct DIR
|
||||
@ -103,6 +107,9 @@ struct dirent *readdir(DIR *dir)
|
||||
if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1)
|
||||
{
|
||||
result = &dir->result;
|
||||
result->d_attr = dir->info.attrib;
|
||||
result->d_size = dir->info.size;
|
||||
result->d_time = localtime(&dir->info.time_write);
|
||||
result->d_name = dir->info.name;
|
||||
}
|
||||
}
|
||||
|
@ -17,10 +17,14 @@ extern "C"
|
||||
#endif
|
||||
|
||||
typedef struct DIR DIR;
|
||||
typedef struct tm tm;
|
||||
|
||||
struct dirent
|
||||
{
|
||||
char *d_name;
|
||||
int d_attr; //Attributes
|
||||
unsigned d_size; //Size in Bytes
|
||||
struct tm *d_time; //Timestamp
|
||||
char *d_name; //Filename
|
||||
};
|
||||
|
||||
DIR *opendir(const char *);
|
||||
|
41
lib6502/error.h
Normal file
41
lib6502/error.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* Subset of Standard Unix/Posiz Error Codes */
|
||||
|
||||
#define ENOERROR 0 /* No Error */
|
||||
#define EPERM 1 /* Operation not permitted */
|
||||
#define ENOENT 2 /* No such file or directory */
|
||||
#define ESRCH 3 /* No such process */
|
||||
#define EINTR 4 /* Interrupted system call */
|
||||
#define EIO 5 /* Input/output error */
|
||||
#define ENXIO 6 /* No such device or address */
|
||||
#define E2BIG 7 /* Argument list too long */
|
||||
#define ENOEXEC 8 /* Exec format error */
|
||||
#define EBADF 9 /* Bad file descriptor */
|
||||
#define ECHILD 10 /* No child processes */
|
||||
#define EDEADLK 11 /* Resource deadlock avoided */
|
||||
#define ENOMEM 12 /* Cannot allocate memory */
|
||||
#define EACCES 13 /* Permission denied */
|
||||
#define EFAULT 14 /* Bad address */
|
||||
#define ENOTBLK 15 /* Block device required */
|
||||
#define EBUSY 16 /* Device busy */
|
||||
#define EEXIST 17 /* File exists */
|
||||
#define EXDEV 18 /* Cross-device link */
|
||||
#define ENOTDEV 19 /* Operation not supported by device */
|
||||
#define ENOTDIR 20 /* Not a directory */
|
||||
#define EISDIR 21 /* Is a directory */
|
||||
#define EINVAL 22 /* Invalid argument */
|
||||
#define ENFILE 23 /* Too many open files in system */
|
||||
#define EMFILE 24 /* Too many open files */
|
||||
#define ENOTTY 25 /* Inappropriate ioctl for device */
|
||||
#define ETXTBSY 26 /* Text file busy */
|
||||
#define EFBIG 27 /* File too large */
|
||||
#define ENOSPC 28 /* No space left on device */
|
||||
#define ESPIPE 29 /* Illegal seek */
|
||||
#define EROFS 30 /* Read-only file system */
|
||||
#define EMLINK 31 /* Too many links */
|
||||
#define EPIPE 32 /* Broken pipe */
|
||||
#define EDOM 33 /* Numerical argument out of domain */
|
||||
#define ERANGE 34 /* Result too large */
|
||||
#define EAGAIN 35 /* Resource temporarily unavailable */
|
||||
#define EALREADY 37 /* Operation already in progress */
|
||||
#define EBADFD 77 /* File descriptor in bad state */
|
||||
#define EEOF 255 /* End of File */
|
@ -5,10 +5,11 @@
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <direct.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "error.h"
|
||||
#include "lib6502.h"
|
||||
#include "file6502.h"
|
||||
|
||||
@ -18,23 +19,37 @@ typedef uint16_t word;
|
||||
|
||||
int debug;
|
||||
|
||||
#define STRLEN 128
|
||||
#define STRSIZ STRLEN+1
|
||||
|
||||
/* DOS File Attributes */
|
||||
#define _A_ARCH 0x20 //Archive. Set whenever the file is changed, and cleared by the BACKUP command.
|
||||
#define _A_HIDDEN 0x02 //Hidden file. Not normally seen with the DIR command, unless the /AH option is used.
|
||||
#define _A_RDONLY 0x01 //Read-only. File cannot be opened for writing.
|
||||
#define _A_SUBDIR 0x10 //Subdirectory.
|
||||
#define _A_SYSTEM 0x04 //System file. Not normally seen with the DIR command, unless the /AS option is used.
|
||||
|
||||
/* I/O Blocks for File I/O */
|
||||
#define MAXIOB 15
|
||||
#define STRLEN 128
|
||||
#define TDIR 'D'
|
||||
#define TFILE 'F'
|
||||
|
||||
typedef struct dirent dirent;
|
||||
|
||||
struct iocb
|
||||
{
|
||||
int opened; //Flag: file opened
|
||||
char type; //Channel Type: 'F', 'D'
|
||||
char type; //Channel Type: TFILE, TDIR
|
||||
char mode; //File Mode: 'R', 'W'
|
||||
int recsize; //Record Size (0=None)
|
||||
FILE *fp; //File Pointer
|
||||
DIR *dp; //Directory Pointer
|
||||
int errnum; //Last Error Number
|
||||
char name[STRLEN]; //File/Directory Name
|
||||
char name[STRSIZ]; //File/Directory Name
|
||||
};
|
||||
|
||||
static struct iocb iocbs[MAXIOB];
|
||||
static char filename[STRLEN]; //File name for open
|
||||
static char filename[STRSIZ]; //File name for open
|
||||
static char filebuff[256]; //File I/O Buffer
|
||||
static word fileaddr; //File Read/Write Address
|
||||
static word fileindx; //File Record Size/Number
|
||||
@ -91,6 +106,7 @@ int setiocb(int chan, int opened, char type, char mode, int recsize, FILE *fp, D
|
||||
|
||||
void initiocb(int chan) {
|
||||
setiocb(chan, 0, ' ', ' ', 0, NULL, NULL, "");
|
||||
if (debug) fprintf(stderr, "cleared iocb for channel %d\n", chan);
|
||||
}
|
||||
|
||||
void initiocbs(void)
|
||||
@ -121,6 +137,54 @@ static int setname(M6502 *mpu, word addr, char *name) {
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Normalize Drive ID */
|
||||
static char driveid(char drive) {
|
||||
char id;
|
||||
if (debug) fprintf(stderr, "normalizing drive $%02x\n", drive);
|
||||
if (drive == 0 || strchr(" 0@", drive)) id = 0; //Default Drive
|
||||
else id = toupper(drive);
|
||||
if (debug) fprintf(stderr, "returning driveid $%02x\n", id);
|
||||
return id;
|
||||
}
|
||||
|
||||
/* Convert Drive ID to Drive Number *
|
||||
* Args: driveid - Drive ID (A-Z) *
|
||||
* Returns: Drive Number (1-126, *
|
||||
* 0 for Default, or -errno */
|
||||
static int driveno(char drvid) {
|
||||
int id = driveid(drvid);
|
||||
if (debug) fprintf(stderr, "converting drive id %02x\n", drvid);
|
||||
if (id == 0 ) return 0;
|
||||
if (id >='A' && id <='Z') return id - '@';
|
||||
return -seterror(0, ENXIO); //No such device or address
|
||||
}
|
||||
|
||||
/* Change Current Drive *
|
||||
* Args: drivno - drive number (1-26) *
|
||||
* Returns: Error (0=None) */
|
||||
static int chgdrive(char drvno) {
|
||||
if (debug) fprintf(stderr, "changing default drive to %d: ", drvno);
|
||||
int r = _chdrive(drvno);
|
||||
if (r) r = seterror(0, errno);
|
||||
else if (debug) fprintf(stderr, "default drvno changed\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Build File Spec */
|
||||
static int setspec(char *spec, char driveid, char* name, char* dflt) {
|
||||
if (debug) fprintf(stderr, "building filespec for drive $%02x, name \"%s\"\n", driveid, name);
|
||||
spec[0] = 0; //Set filespec to ""
|
||||
int drive = driveno(driveid); if (drive < 0) return seterror(0, -drive);
|
||||
for (int i = 0; i<STRLEN; i++) if (name[i] == '/') name[i] = '\\'; //Convert Slashes
|
||||
if (strlen(name) == 0) {
|
||||
strcpy(name, dflt);
|
||||
if (debug) fprintf(stderr, "name changed to \"%s\"\n", name);
|
||||
}
|
||||
if (drive) {sprintf(spec, "%c:", drive); strncat(spec, name, STRLEN);}
|
||||
else strncpy(spec, name, STRLEN);
|
||||
return ENOERROR;
|
||||
}
|
||||
|
||||
/* Find Unused IOCB */
|
||||
static int uniocb(void) {
|
||||
int chan;
|
||||
@ -140,9 +204,9 @@ static int valchan(int chan, char valtype) {
|
||||
else if (iocbs[chan].type != valtype) {
|
||||
if (debug) fprintf(stderr, "invalid channel type '%c'\n", iocbs[chan].type);
|
||||
switch (iocbs[chan].type) {
|
||||
case 'D': errnum = 21; //Is a directory
|
||||
case 'F': errnum = 20; //Not a directory
|
||||
default: errnum = 77; //File descriptor in bad state
|
||||
case TDIR: errnum = EISDIR; //Is a directory
|
||||
case TFILE: errnum = ENOTDIR; //Not a directory
|
||||
default: errnum = EBADFD; //File descriptor in bad state
|
||||
}
|
||||
}
|
||||
return errnum;
|
||||
@ -151,8 +215,10 @@ static int valchan(int chan, char valtype) {
|
||||
/* Write Buffer to Memory */
|
||||
static int writemem(M6502 *mpu, char* buffer, int count) {
|
||||
int i;
|
||||
if (debug) fprintf(stderr, "writing to address %04x\n", fileaddr);
|
||||
for (i = 0; i<count; i++)
|
||||
mpu->memory[fileaddr+i] = buffer[i];
|
||||
if (debug) fprintf(stderr, "wrote %d bytes\n", i);
|
||||
return i;
|
||||
}
|
||||
|
||||
@ -170,81 +236,139 @@ static int writestr(M6502 *mpu, char* buffer, int count) {
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Convert tm struct to readable time */
|
||||
void strtm(char *s, tm *time) {
|
||||
sprintf(s, "%d-%02d-%02d %02d:%02d:%02d",
|
||||
time->tm_year+1900, time->tm_mon, time->tm_mday,
|
||||
time->tm_hour, time->tm_min, time->tm_sec);
|
||||
}
|
||||
|
||||
int copystring(char *b, char *s, int ofs) {
|
||||
if (debug) fprintf(stderr, "copying string \"$s\" to buffer at offset %d\n", s, ofs);
|
||||
for (int i = 0; i < STRLEN; i++) {
|
||||
if (s[i]) b[ofs++] = s[i]; else break;
|
||||
}
|
||||
b[ofs++] = 0;
|
||||
return ofs;
|
||||
}
|
||||
|
||||
int copytime(char *b, tm *t, int ofs) {
|
||||
char s[STRLEN]; strtm(s, t);
|
||||
t->tm_mon = t->tm_mon + 1; //Adjust Zero-based Month
|
||||
if (debug) fprintf(stderr, "copying timestamp %s to buffer at offset %d\n", s, ofs);
|
||||
b[ofs++] = t->tm_year; b[ofs++] = t->tm_mon; b[ofs++] = t->tm_mday;
|
||||
b[ofs++] = t->tm_hour; b[ofs++] = t->tm_min; b[ofs++] = t->tm_sec;
|
||||
return ofs;
|
||||
}
|
||||
|
||||
int copyword(char *b, word w, int ofs) {
|
||||
if (debug) fprintf(stderr, "copying word %04x to buffer at offset %d\n", w, ofs);
|
||||
b[ofs++] = w & 0xFF; b[ofs++] = w >> 8;
|
||||
return ofs;
|
||||
}
|
||||
|
||||
int copyattrs(char *b, int attr, int ofs) {
|
||||
b[ofs++] = (attr & _A_ARCH) ? 0xFF : 00;
|
||||
b[ofs++] = (attr & _A_HIDDEN) ? 0xFF : 00;
|
||||
b[ofs++] = (attr & _A_RDONLY) ? 0xFF : 00;
|
||||
b[ofs++] = (attr & _A_SUBDIR) ? 0xFF : 00;
|
||||
b[ofs++] = (attr & _A_SYSTEM) ? 0xFF : 00;
|
||||
return ofs;
|
||||
}
|
||||
|
||||
/* Copy dirent to character array matching run6502.h02 *
|
||||
* struct dirent { *
|
||||
* struct {char arch, hidden, system, rdonly, subdir, system} attr *
|
||||
* struct {char year, month, day, hour, minute, second;} time; *
|
||||
* int size, char name[128];} */
|
||||
int setentry(char *buffer, dirent *de) {
|
||||
int offset = 0;
|
||||
char ts[STRSIZ]; strtm(ts, de->d_time);
|
||||
if (debug) fprintf(stderr, "copying entry \"%s\", attr=$%02x, size=%d, time=%s\n",
|
||||
de->d_name, de->d_attr, de->d_size, ts);
|
||||
offset = copyattrs(buffer, de->d_attr, offset);
|
||||
offset = copytime(buffer, de->d_time, offset);
|
||||
offset = copyword(buffer, de->d_size, offset);
|
||||
offset = copystring(buffer, de->d_name, offset);
|
||||
return offset;
|
||||
}
|
||||
|
||||
/* Emulate fileio at addr */
|
||||
extern int filecmd(M6502 *mpu, word addr, byte data) {
|
||||
const char modes[8][4] = {"r", "rb", "w", "wb", "a", "ab", "r+", "rb+"};
|
||||
const char modes[8][4] = {"r", "rb", "w", "wb", "a", "ab", "a+", "ab+"};
|
||||
const char ddesc[2][9] = {"creating", "removing"};
|
||||
const char fdesc[2][10] = {"file", "directory"};
|
||||
const char qdesc[2][7] = {"string", "line"};
|
||||
int chan, e, i;
|
||||
char c, m, n, mode[4];
|
||||
char *name;
|
||||
struct dirent *de;
|
||||
char c, d, m, n, t, mode[4];
|
||||
char *buffer;
|
||||
char filespec[STRSIZ], newspec[STRSIZ] ;
|
||||
struct tm time;
|
||||
dirent *de;
|
||||
byte a = mpu->registers->a;
|
||||
byte x = mpu->registers->x;
|
||||
byte y = mpu->registers->y;
|
||||
byte p = mpu->registers->p;
|
||||
word yx = y << 8 | x;
|
||||
char drive = y & 0x1f;
|
||||
if (debug) fprintf(stderr, "executing '%c' with options %02x,%02x,%02x\n", a, y, x, p);
|
||||
if (debug) fprintf(stderr, "executing file command '%c' with options %02x,%02x,%02x\n", a, y, x, p);
|
||||
switch (a) { //File I/O Command
|
||||
case 'A': //Set filebuffer address - Y.X = address
|
||||
if (p & 1) {
|
||||
fileindx = yx;
|
||||
if (debug) fprintf(stderr, "file index set to %04x\n", fileaddr);
|
||||
if (debug) fprintf(stderr, "file index set to %04x\n", fileindx);
|
||||
} else {
|
||||
fileaddr = yx;
|
||||
if (debug) fprintf(stderr, "file address set to %04x\n", fileaddr);
|
||||
}
|
||||
break;
|
||||
case 'B': //Close Directory - Y = channel
|
||||
//case 'B': //Unused
|
||||
case 'C': //Close Channel - Y = channel, CC = File, CS = Directory
|
||||
chan = y;
|
||||
if (debug) fprintf(stderr, "closing directory channel %d\n", chan);
|
||||
y = valchan(chan, 'D'); if (y) break;
|
||||
if (closedir(iocbs[chan].dp)) y = seterror(chan, errno);
|
||||
else initiocb(chan);
|
||||
m = p & 1; t = (m) ? TDIR : TFILE;
|
||||
if (debug) fprintf(stderr, "closing %s channel %d\n", fdesc[m], chan);
|
||||
y = valchan(chan, t); if (y) break;
|
||||
if (m) e = closedir(iocbs[chan].dp); else e = fclose(iocbs[chan].fp);
|
||||
if (e) y = seterror(chan, errno); else initiocb(chan);
|
||||
if (debug) fprintf(stderr, "channel closed\n");
|
||||
break;
|
||||
case 'C': //Close file - Y = channel
|
||||
case 'D': //Read Directory - Y = Channel, CC = Entry, CS = Header
|
||||
chan = y;
|
||||
if (debug) fprintf(stderr, "closing file channel %d\n", chan);
|
||||
y = valchan(chan, 'F'); if (y) break;
|
||||
if (fclose(iocbs[chan].fp)) y = seterror(chan, errno);
|
||||
else initiocb(chan);
|
||||
break;
|
||||
case 'D': //Open Directory - Y,X = Directory Name
|
||||
x = 0; //File channel (none)
|
||||
y = 0; //Error code (none)
|
||||
chan = uniocb(); if (chan <0) {y = -chan; break;}
|
||||
setname(mpu, yx, filename);
|
||||
if (strlen(filename) == 0) strcpy(filename, ".");
|
||||
if (debug) fprintf(stderr, "opening directory '%s'\n", filename, mode);
|
||||
DIR *dp = opendir(filename);
|
||||
if (dp == NULL) { y = seterror(0, errno); break;}
|
||||
if (debug) fprintf(stderr, "directory opened on channel %d\n", chan);
|
||||
y = setiocb(chan, -1, 'D', ' ', 0, NULL, dp, filename); //Setup IOCB
|
||||
if (y == 0) x = chan;
|
||||
x = 0; //Return Value (Read Failed)
|
||||
y = valchan(chan, TDIR); if (y) break;
|
||||
if (p & 1) {
|
||||
if (debug) fprintf(stderr, "retrieving directory name\n");
|
||||
x = writestr(mpu, iocbs[chan].name, STRLEN);
|
||||
} else {
|
||||
if (debug) fprintf(stderr, "reading directory entry\n");
|
||||
de = readdir(iocbs[chan].dp);
|
||||
if (de) {x = setentry(filebuff, de); writemem(mpu, filebuff, x);}
|
||||
else if (errno != 2) y = seterror(chan, errno);
|
||||
}
|
||||
break;
|
||||
case 'E': //EOF - Y = channel
|
||||
chan = y;
|
||||
y = valchan(chan, 'F'); if (y) break;
|
||||
y = valchan(chan, TFILE); if (y) break;
|
||||
y = feof(iocbs[chan].fp);
|
||||
break;
|
||||
case 'F': //Flush File - Y = Channel
|
||||
chan = y;
|
||||
y = valchan(chan, 'F'); if (y) break;
|
||||
if (fflush(iocbs[chan].fp)) y = seterror(chan, errno);
|
||||
y = valchan(chan, TFILE); if (y) break;
|
||||
x = fflush(iocbs[chan].fp);
|
||||
if (x) y = seterror(chan, errno);
|
||||
break;
|
||||
case 'G': //Get character - Y = channel
|
||||
case 'G': //Get Character - Y = channel
|
||||
chan = y;
|
||||
x = 0; //Character read (none)
|
||||
y = valchan(chan, 'F'); if (y) break;
|
||||
y = valchan(chan, TFILE); if (y) break;
|
||||
c = fgetc(iocbs[chan].fp);
|
||||
if (feof(iocbs[chan].fp)) {y = 255; break;}
|
||||
if (feof(iocbs[chan].fp)) {y = EOF; break;}
|
||||
if (c == EOF) {y = seterror(chan, errno); break;}
|
||||
x = c & 0xFF;
|
||||
break;
|
||||
case 'H': //Get String - Y = channel
|
||||
chan = y;
|
||||
x = 0; //Number of Characters read
|
||||
y = valchan(chan, 'F'); if (y) break;
|
||||
y = valchan(chan, TFILE); if (y) break;
|
||||
char *s = fgets(filebuff, STRLEN, iocbs[chan].fp);
|
||||
if (s == NULL) {y = seterror(chan, errno); break;}
|
||||
if (debug) fprintf(stderr, "read string '%s'\n", filebuff);
|
||||
@ -254,74 +378,100 @@ extern int filecmd(M6502 *mpu, word addr, byte data) {
|
||||
case 'I': //Init File System
|
||||
initiocbs(); //Initialize I/O Control Blocks
|
||||
break;
|
||||
case 'J': //Read Directory Entry
|
||||
case 'J': //Get/Put Word - Y = Channel, Carry Set = Put, Clear = Get
|
||||
chan = y;
|
||||
x = 0; //Return Value (Read Failed)
|
||||
y = valchan(chan, 'D'); if (y) break;
|
||||
a = valchan(chan, TFILE); if (y) break;
|
||||
if (p & 1) {
|
||||
if (debug) fprintf(stdout, "retrieving directory name\n");
|
||||
x = writestr(mpu, iocbs[chan].name, STRLEN);
|
||||
y = fileaddr >> 8; x = fileaddr & 0xFF;
|
||||
e = fputc(x, iocbs[chan].fp);
|
||||
if (e == EOF) {a = seterror(chan, errno); break;}
|
||||
e = fputc(y, iocbs[chan].fp);
|
||||
if (e == EOF) {a = seterror(chan, errno); break;}
|
||||
} else {
|
||||
if (debug) fprintf(stdout, "reading directory entry\n");
|
||||
de = readdir(iocbs[chan].dp);
|
||||
if (de) {
|
||||
if (debug) fprintf(stdout, "read entry '%s'\n", de->d_name);
|
||||
x = writestr(mpu, de->d_name, STRLEN);
|
||||
}
|
||||
else if (errno != 2) y = seterror(chan, errno);
|
||||
c = fgetc(iocbs[chan].fp);
|
||||
if (feof(iocbs[chan].fp)) {a = EOF; break;}
|
||||
if (c == EOF) {a = seterror(chan, errno); break;}
|
||||
x = c & 0xFF;
|
||||
c = fgetc(iocbs[chan].fp);
|
||||
if (feof(iocbs[chan].fp)) {a = EOF; break;}
|
||||
if (c == EOF) {a = seterror(chan, errno); break;}
|
||||
y = c & 0xFF;
|
||||
}
|
||||
break;
|
||||
case 'K': //REMOVE - Delete File - Y,X = Filename
|
||||
setname(mpu, yx, filename);
|
||||
if (debug) fprintf(stderr, "removing file '%s'\n", filename);
|
||||
x = remove(filename);
|
||||
if (x) y=seterror(0, errno); else y=0;
|
||||
d = driveid(y);
|
||||
y = setspec(filespec, d, filename, "."); if (y) break;
|
||||
if (debug) fprintf(stderr, "removing file '%s'\n", filespec);
|
||||
e = remove(filespec);
|
||||
if (e) y=seterror(0, errno);
|
||||
break;
|
||||
case 'L': //Load file
|
||||
a = 0; //Error (none)
|
||||
//ALLOW SPECIFYING DRIVE ID
|
||||
a = ENOERROR; //Error (none)
|
||||
if (debug) fprintf(stderr, "loading file at %04h\n", fileaddr);
|
||||
e = load(mpu, fileaddr, filename);
|
||||
if (!e) {a = seterror(0, errno); break;}
|
||||
y = e >> 8; x = e & 0xff;
|
||||
break;
|
||||
case 'M': //MOVE - Rename File - Y,X = Filename
|
||||
setname(mpu, yx, filebuff);
|
||||
if (debug) fprintf(stderr, "renaming file '%s' to '%s'\n", filename, filebuff);
|
||||
x = rename(filename, filebuff);
|
||||
if (x) y=seterror(0, errno); else y=0;
|
||||
case 'M': //MOVE - Rename File - Y = Drive ID
|
||||
d = driveid(y); //Not Implemented Yet
|
||||
y = setspec(filespec, d, filename, "."); if (y) break;
|
||||
y = setspec(newspec, d, filebuff, "."); if (y) break;
|
||||
if (debug) fprintf(stderr, "renaming file \"%s\" to \"%s\"\n", filename, filebuff);
|
||||
e = rename(filespec, newspec);
|
||||
if (e) y=seterror(0, errno); else y=0;
|
||||
break;
|
||||
case 'N': //Set filename - Y,X = string address
|
||||
x = setname(mpu, yx, filename); //Set filename and Return Length
|
||||
if (debug) fprintf(stderr, "filename set to '%s'\n", filename);
|
||||
case 'N': //Set Name - Y,X = string address, CC = filename, CS = filebuff
|
||||
m = p & 1;
|
||||
if (m) {
|
||||
x = setname(mpu, yx, filebuff); //Set filebuff and Return Length
|
||||
if (debug) fprintf(stderr, "filebuff set to \"%s\"\n", filename);
|
||||
} else {
|
||||
x = setname(mpu, yx, filename); //Set filename and Return Length
|
||||
if (debug) fprintf(stderr, "filename set to \"%s\"\n", filename);
|
||||
}
|
||||
break;
|
||||
case 'O': //Open file - Y = Drive#, X = Mode (Bits 7,6 = RWA, Bit 5 = Binary)
|
||||
m = x >> 5 & 7; //Get Mode Index
|
||||
x = 0; //File channel (none)
|
||||
y = 0; //Error code (none)
|
||||
strcpy(mode, modes[m]); //Set Mode from Mode Index
|
||||
chan = uniocb(); if (chan <0) {y = seterror(0, -chan); break;}
|
||||
if (debug) fprintf(stderr, "opening file '%s' with mode '%s'\n", filename, mode);
|
||||
FILE *fp = fopen(filename, mode);
|
||||
if (fp == NULL) { y = seterror(0, errno); break;}
|
||||
if (debug) fprintf(stderr, "file opened on channel %d\n", chan);
|
||||
i = (m == 3) ? fileindx : 0; //Set Records Size if Mode RECORD
|
||||
y = setiocb(chan, -1, 'F', mode[0], i, fp, NULL, filename); //Setup IOCB
|
||||
if (y == 0) x = chan;
|
||||
case 'O': //Open file/directory - Y = Drive#, X = Mode, CC = File, CS = Directory
|
||||
if (p & 1) {
|
||||
x = 0; //File channel (none)
|
||||
d = driveid(y); //Normalize Drive ID
|
||||
y = setspec(filespec, d, filename, "."); if (y) {seterror(0, y); break;}
|
||||
chan = uniocb(); if (chan <0) {y = -chan; break;}
|
||||
if (debug) fprintf(stderr, "opening directory '%s'\n", filespec, mode);
|
||||
DIR *dp = opendir(filespec);
|
||||
if (dp == NULL) { y = seterror(0, errno); break;}
|
||||
if (debug) fprintf(stderr, "directory opened on channel %d\n", chan);
|
||||
y = setiocb(chan, -1, TDIR, ' ', 0, NULL, dp, filespec); //Setup IOCB
|
||||
if (y == 0) x = chan;
|
||||
} else {
|
||||
m = x >> 5 & 7; //Get Mode Index
|
||||
x = 0; //File channel (none)
|
||||
y = ENOERROR; //Error code (none)
|
||||
strcpy(mode, modes[m]); //Set Mode from Mode Index
|
||||
chan = uniocb(); if (chan <0) {y = seterror(0, -chan); break;}
|
||||
if (debug) fprintf(stderr, "opening file '%s' with mode '%s'\n", filename, mode);
|
||||
FILE *fp = fopen(filename, mode);
|
||||
if (fp == NULL) { y = seterror(0, errno); break;}
|
||||
if (debug) fprintf(stderr, "file opened on channel %d\n", chan);
|
||||
i = (m > 5) ? fileindx : 0; //Set Records Size if Mode RECORD
|
||||
y = setiocb(chan, -1, TFILE, mode[0], i, fp, NULL, filename); //Setup IOCB
|
||||
if (y == 0) x = chan;
|
||||
}
|
||||
break;
|
||||
case 'P': //Put character - Y = channel; X = character
|
||||
chan = y;
|
||||
c = x;
|
||||
if (debug) fprintf(stderr, "writing '%c' to channel %d\n", c, chan);
|
||||
a = 0; //Character written (none)
|
||||
y = valchan(chan, 'F'); if (y) break;
|
||||
x = 0xFF; //Character written (Error)
|
||||
y = valchan(chan, TFILE); if (y) break;
|
||||
e = fputc(c, iocbs[chan].fp);
|
||||
if (e == EOF) {y = seterror(chan, errno); break;}
|
||||
a = e & 0xFF;
|
||||
x = e & 0xFF;
|
||||
break;
|
||||
case 'Q': //Put String - Y = channel
|
||||
case 'Q': //Put String - Y = channel, Carry Set = putline
|
||||
chan = y;
|
||||
x = 0; //Number of characters written
|
||||
y = valchan(chan, 'F'); if (y) break;
|
||||
y = valchan(chan, TFILE); if (y) break;
|
||||
for (i = 0; i<128; i++) {
|
||||
c = mpu->memory[fileaddr+i];
|
||||
if (c) filebuff[i] = c;
|
||||
@ -338,7 +488,7 @@ extern int filecmd(M6502 *mpu, word addr, byte data) {
|
||||
m = p & 1; //Set Mode: 0 = fread, 1 = fgetr
|
||||
chan = y;
|
||||
if (m) {
|
||||
a = valchan(chan, 'F'); if (a) break;
|
||||
a = valchan(chan, TFILE); if (a) break;
|
||||
if (debug) fprintf(stderr, "selecting record #%d\n", fileindx);
|
||||
n = iocbs[chan].recsize;
|
||||
i = fileindx * n;
|
||||
@ -346,7 +496,7 @@ extern int filecmd(M6502 *mpu, word addr, byte data) {
|
||||
e = fseek(iocbs[chan].fp, i, SEEK_SET);
|
||||
if (e) {a = seterror(chan, errno); break;}
|
||||
} else {
|
||||
y = valchan(chan, 'F'); if (y) break;
|
||||
y = valchan(chan, TFILE); if (y) break;
|
||||
n = x;
|
||||
}
|
||||
if (debug) fprintf(stderr, "reading %d bytes\n", n);
|
||||
@ -361,69 +511,83 @@ extern int filecmd(M6502 *mpu, word addr, byte data) {
|
||||
}
|
||||
break;
|
||||
case 'S': //Save file Y,X = end address
|
||||
a = 0; //Error (none)
|
||||
//CHANGE INPUT PARAMETER TO DRIVE ID
|
||||
a = ENOERROR; //Error (none)
|
||||
if (debug) fprintf(stderr, "saving file from %04x to %04x\n", fileaddr, yx);
|
||||
e = save(mpu, fileaddr, yx-fileaddr-1, filename);
|
||||
if (!e) {a = seterror(0, errno); break;}
|
||||
y = e >> 8; x = e & 0xff;
|
||||
break;
|
||||
case 'T': //Get Current Directory - YX = String Address
|
||||
x = 0; //Directory Name Length
|
||||
y = 0; //Error (None)
|
||||
if (debug) fprintf(stderr, "getting current working directory\n");
|
||||
if (_getcwd(filename, STRLEN)) {
|
||||
if (debug) fprintf(stderr, "cwd: %s\n", filename);
|
||||
for (i = 0; i<STRLEN; i++) {
|
||||
c = filename[i];
|
||||
if (c == 0) break;
|
||||
mpu->memory[yx+i] = c;
|
||||
}
|
||||
mpu->memory[yx+i] = 0;
|
||||
x = i;
|
||||
}
|
||||
else y = seterror(0, errno);
|
||||
break;
|
||||
case 'U': //Change Directory - YX = Directory Name
|
||||
x = 0; //Result (Success)
|
||||
y = 0; //Error (None)
|
||||
setname(mpu, yx, filename); //Set filename to Directory Name
|
||||
if (debug) fprintf(stderr, "changing directory to '%s'\n", filename);
|
||||
if (_chdir(filename)) {x = 0xFF; y = seterror(0, errno);}
|
||||
//case 'T': //Unused
|
||||
case 'U': //Get/Set Current Directory - Y = Drive/Disk ID, CC=Get. CS=Set
|
||||
if (p & 1) { //Change Directory
|
||||
d = driveid(y);
|
||||
y = setspec(filespec, d, filename, "."); if (y) break;
|
||||
if (debug) fprintf(stderr, "changing directory to \"%s\"\n", filespec);
|
||||
if (_chdir(filespec)) {y = seterror(0, errno);}
|
||||
} else { //Get Directory
|
||||
x = 0; filename[0] = 0; //Clear filename, Set Length to 0
|
||||
d = driveno(y); if (d < 0) {y=seterror(0, -d); break;}
|
||||
e = _getdrive(); if (e == 0) {y=seterror(0, errno); break;}
|
||||
if (d && e != d ) {y = chgdrive(d); if (y) break;}
|
||||
if (debug) fprintf(stderr, "getting current working directory for drive %d\n", d);
|
||||
if (_getcwd(filename, STRLEN) == NULL) y = seterror(0, errno);
|
||||
else {
|
||||
if (debug) fprintf(stderr, "current working directory ie \"%s\"\n", filename);
|
||||
x = writestr(mpu, filename, STRLEN);
|
||||
}
|
||||
if (d && e != d ) {e = chgdrive(e); if (e) seterror(0, errno);}
|
||||
}
|
||||
break;
|
||||
case 'V': //Get or Set Current Drive, Y=Drive, Carry=Get/Set
|
||||
if (p & 1) {
|
||||
if (debug) fprintf(stderr, "changing drive to %c\n", y+'@');
|
||||
x = _chdrive(y);
|
||||
if (x) y=seterror(0, errno); else y=0;
|
||||
x = _chdrive(y); if (x) y=seterror(0, errno); else y=0;
|
||||
} else {
|
||||
x = _getdrive();
|
||||
if (x) y=0; else y=seterror(0, errno);
|
||||
x = _getdrive(); if (x) y=0; else y=seterror(0, errno);
|
||||
if (debug) fprintf(stderr, "current drive is %c\n", x+'@');
|
||||
}
|
||||
break;
|
||||
case 'W': //Write bytes - Y = channel, X=Number of Bytes
|
||||
case 'W': //Write bytes - Y = channel, X = Number of Bytes
|
||||
m = p & 1; //Set Mode: 0 = fread, 1 = fgetr
|
||||
chan = y;
|
||||
y = valchan(chan, 'F'); if (y) break;
|
||||
for (i = 0; i<x; i++)
|
||||
filebuff[i] = mpu->memory[fileaddr+i];
|
||||
if (debug) fprintf(stderr, "writing %d bytes\n", x);
|
||||
e = fwrite(filebuff, x, 1, iocbs[chan].fp);
|
||||
if (e != 1) {y = seterror(chan, errno); break;}
|
||||
break;
|
||||
case 'X': //Make/Remove Directory - YX = Directory Name
|
||||
setname(mpu, yx, filename);
|
||||
if (p & 1) {
|
||||
if (debug) fprintf(stderr, "removing directory '%s'\n", filename);
|
||||
x = _rmdir(filename);
|
||||
if (m) {
|
||||
a = valchan(chan, TFILE); if (a) break;
|
||||
if (debug) fprintf(stderr, "selecting record #%d\n", fileindx);
|
||||
n = iocbs[chan].recsize;
|
||||
i = fileindx * n;
|
||||
if (debug) fprintf(stderr, "setting position to %d\n", i);
|
||||
e = fseek(iocbs[chan].fp, i, SEEK_SET);
|
||||
if (e) {a = seterror(chan, errno); break;}
|
||||
i = ftell(iocbs[chan].fp);
|
||||
if (debug) fprintf(stderr, "position set to %d\n", i);
|
||||
} else {
|
||||
if (debug) fprintf(stderr, "creating directory '%s'\n", filename);
|
||||
x = _mkdir(filename);
|
||||
y = valchan(chan, TFILE); if (y) break;
|
||||
n = x;
|
||||
}
|
||||
if (x) y=seterror(0, errno); else y=0;
|
||||
for (i = 0; i<n; i++)
|
||||
filebuff[i] = mpu->memory[fileaddr+i];
|
||||
if (debug) fprintf(stderr, "writing %d bytes\n", n);
|
||||
e = fwrite(filebuff, n, 1, iocbs[chan].fp);
|
||||
if (debug) fprintf(stderr, "fwrite() returned %d\n", e);
|
||||
if (e == 0) {e = seterror(chan, errno); if (m) a = e; else y = e; break; }
|
||||
if (m) {
|
||||
fileindx++; y = fileindx >> 8; x = fileindx & 0xff;
|
||||
if (debug) fprintf(stderr, "returning record #%d\n", fileindx);
|
||||
}
|
||||
break;
|
||||
case 'X': //Make/Remove Directory - Y = Drive ID, CC = RMDIR, CS = MKDIR
|
||||
d = driveid(y);
|
||||
m = p & 1;
|
||||
y = setspec(filespec, d, filename, "."); if (y) break;
|
||||
if (debug) fprintf(stderr, "%s directory '%s'\n", ddesc[m], filespec);
|
||||
if (m) e = _rmdir(filespec);
|
||||
else e = _mkdir(filespec);
|
||||
if (e) y=seterror(0, errno);
|
||||
break;
|
||||
case 'Y': //Get Last Error: Y=chan
|
||||
chan = y;
|
||||
y = 0; //Set Error to None
|
||||
y = ENOERROR; //Set Error to None
|
||||
x = 0xFF; //Set Result to Invalid
|
||||
if (chan > MAXIOB) {y = 44; break;}
|
||||
if (debug) fprintf(stderr, "getting last error for channel %d\n", chan);
|
||||
@ -434,26 +598,66 @@ extern int filecmd(M6502 *mpu, word addr, byte data) {
|
||||
break;
|
||||
case 'Z': //File Position: Y=chan, fileaddr = position, Carry = seek/tell
|
||||
chan = y;
|
||||
y = valchan(chan, 'F'); if (y) break;
|
||||
y = valchan(chan, TFILE); if (y) break;
|
||||
if (p & 1) {
|
||||
e = ftell(iocbs[chan].fp);
|
||||
if (e < 0) {a = seterror(chan, errno);}
|
||||
else {
|
||||
if (debug) fprintf(stderr, "returning position %d\n", e);
|
||||
a = 0; y = e >> 8; x = e & 0xff;
|
||||
a = ENOERROR;
|
||||
}
|
||||
y = e >> 8; x = e & 0xff;
|
||||
} else {
|
||||
if (fileindx == 0xFFFF) {i = 0; m = SEEK_END;}
|
||||
else {i = fileindx, m = SEEK_SET;}
|
||||
if (debug) fprintf(stderr, "seeking position %d\n", i);
|
||||
x = fseek(iocbs[chan].fp, i, m);
|
||||
if (x) y = seterror(chan, errno);
|
||||
e = fseek(iocbs[chan].fp, i, m);
|
||||
if (e) y = seterror(chan, errno);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
y = 22; //Error - invalid argument
|
||||
}
|
||||
if (debug) fprintf(stderr, "returning values %02x, %02x, %02x\n", a, y, x);
|
||||
if (debug) fprintf(stderr, "returning values %02x, %02x, %02x, %02x\n", a, y, x, p);
|
||||
mpu->registers->a = a;
|
||||
mpu->registers->x = x;
|
||||
mpu->registers->y = y;
|
||||
}
|
||||
|
||||
/* Emulate system command dispatch at addr */
|
||||
extern int syscmd(M6502 *mpu, word addr, byte data) {
|
||||
struct tm time;
|
||||
dirent *de;
|
||||
byte a = mpu->registers->a;
|
||||
byte x = mpu->registers->x;
|
||||
byte y = mpu->registers->y;
|
||||
byte p = mpu->registers->p;
|
||||
word yx = y << 8 | x;
|
||||
if (debug) fprintf(stderr, "executing system command '%c' with options %02x,%02x,%02x\n", a, y, x, p);
|
||||
switch(a) {
|
||||
case 'C': //Get System Clock
|
||||
if (debug) fprintf(stderr, "reading system clock\n");
|
||||
clock_t clk = clock(); //Get System Clock
|
||||
if (debug) fprintf(stderr, "system clock = %d ticks\n", clk);
|
||||
int i = (clk / 50) & 0xFFFFFF; //Convert to 24-bit integer, 50 ticks per second
|
||||
a = i >> 16; y = i >> 8; x = i; //with resolution of 50 ticks per second
|
||||
if (debug) fprintf(stderr, "returning $%02x%02x%02x (%d)\n", a, y, x, clk);
|
||||
break;
|
||||
case 'T': //Get/Set Date and Time - YX = tm address; CC = Get, CS = Set
|
||||
if (p & 1) {
|
||||
y = 0xFF; //Return Error - Not Implemented
|
||||
} else {
|
||||
fileaddr = yx; //Set Struct Address
|
||||
_getsystime(&time);
|
||||
x = copytime(filebuff, &time, 0); //Convert time struct
|
||||
writemem(mpu, filebuff, x); //Write to Memory
|
||||
y = 0; //Return Error = None
|
||||
}
|
||||
break;
|
||||
default:
|
||||
y = 22; //Error - invalid argument
|
||||
}
|
||||
if (debug) fprintf(stderr, "returning values %02x, %02x, %02x, %02x\n", a, y, x, p);
|
||||
mpu->registers->a = a;
|
||||
mpu->registers->x = x;
|
||||
mpu->registers->y = y;
|
||||
|
@ -6,4 +6,93 @@ typedef uint8_t byte;
|
||||
typedef uint16_t word;
|
||||
|
||||
extern void setdebug(int dbg);
|
||||
|
||||
|
||||
/**********************************************************************************************
|
||||
* Process File Command *
|
||||
* Command passed in A and parameters in X, Y, and Carry *
|
||||
* 16-Bit values are passed with the MSB in Y and the LSB in X *
|
||||
* Results returned in A, X, and Y *
|
||||
* Unless otherwise specified, A contains the Command Code *
|
||||
* Status of 0 indicates success, any other value indicates failure *
|
||||
* For FOPEN only bits 5-7 of the File Mode are significant; bits 0-4 are ignored *
|
||||
* Bits 6-7 are the access mode: %00=Read, %01=Write, %10=Append, %11=Records *
|
||||
* Bit 5 is the access type: 0=text, 1=binary *
|
||||
* *
|
||||
* A=Command Description Parameters Returns *
|
||||
* A SETADDR Set File Buffer Address Y,X=Address Y,X=Address *
|
||||
* C FCLOSR Close File (Carry Clear) Y=Channel Y=Error *
|
||||
* CLOSEDIR Close Directory (Carry Set) Y=Channel Y=Error *
|
||||
* D READDIR Read Dir Entry (Carry Clear) Y=Channel X=Name Length, Y=Error *
|
||||
* SETADDR Struct Address *
|
||||
* READHDR Read Dir Header (Carry Set) Y=Channel X=Name Length, Y=Error *
|
||||
* SETADDR Struct Address *
|
||||
* E FEOF Check for End of File Y=Channel Y=EOF Indicator *
|
||||
* F FFLUSH Flush File to Disk Y=Channel X=Status, Y=Error *
|
||||
* G FGETC Read Character from File Y=Channel X=Character, Y=Error *
|
||||
* H FGETS Read String from File Y=Channel X=String Legth, Y=Error *
|
||||
* SETADDR Array Address *
|
||||
* I FSINIT Initialize File System *
|
||||
* G FGETW Read Integer (Carry Clear) Y=Channel Y.X=Integer, A=Error *
|
||||
* FPUTW Write Integer (Carry Set) Y=Channel Y=Error *
|
||||
* SETADDR Struct Address *
|
||||
* K REMOVE Remove File from Disk Y=Drive Y=Error *
|
||||
* SETNAME Filename *
|
||||
* L FLOAD Load File into Memory Y,X=End Address, A=Error *
|
||||
* SETNAME File Name *
|
||||
* SETADDR Start Address *
|
||||
* M RENAME Change Name of File on Disk Y=Drive Y=Error *
|
||||
* SETNAME Old Name *
|
||||
* SETBUFF New Name *
|
||||
* N SETNAME Set Filename (Carry Clear) YX=Name YX=Name *
|
||||
* SETBUFF Set File Buffer (Carry Set) YX=String YX=String *
|
||||
* O FOPEN Open File (Carry Clear) Y=Drive, X=Mode X=Channel, Y=Error *
|
||||
* SETNAME File Name *
|
||||
* SETINDEX Record Length (MRECRD) *
|
||||
* OPENDIR Open Directory (Carry Set) Y=Drive X=Channel, Y=Error *
|
||||
* SETNAME Directory Name *
|
||||
* P FPUTC Write Character to File Y=Channel, X=Char E=Status, Y=Error *
|
||||
* Q FPUTS Write String (Carry Clear) Y=Channel X=String Length, Y=Error *
|
||||
* SETADDR String Address *
|
||||
* FPUTLN Write Line (Carry Set) Y=Channel X=String Length, Y=Error *
|
||||
* SETADDR String Address *
|
||||
* R FREAD Read Bytes (Carry Clear) Y=Channel, X=Count X=Count, Y=Error *
|
||||
* SETADDR Array Address *
|
||||
* FGETR Read Record (Carry Set) Y=Channel A=Error, YX=Next Index *
|
||||
* SETADDR Struct *
|
||||
* SETINDEX Record Address *
|
||||
* S FSAVE Save File to Disk Y,X=End Address Y=Error *
|
||||
* SETNAME File Name *
|
||||
* SETADDR Start Address *
|
||||
* U GETCWD Get Current Dir (Carry Clear) Y=Drive ID X=Name Length, Y=Error *
|
||||
* SETADDR String Buffer *
|
||||
* U CHDIR Change Directory (Carry Set) Y=Drive ID Y=Error *
|
||||
* SETNAME Directory Name *
|
||||
* V GETDRIVE Get Current Drive (Carry Clear) X=Drive ID, Y=Error *
|
||||
* CHDRIVE Set Current Drive (Carry Set) Y=Drive ID Y=Error *
|
||||
* W FWRITE Write Bytes (Carry Clear) Y=Channel, X=Count X=Count, Y=Error *
|
||||
* X MKDIR Create Directory (Carry Clear) Y=Drive ID Y=Error *
|
||||
* SETNAME Directory Name *
|
||||
* RMDIR Remove Directory (Carry Set) Y=Drive ID Y=Error *
|
||||
* SETNAME Directory Name *
|
||||
* Y FERROR Get Last Error on Channel Y=Channel X=Channel Error, Y = Error *
|
||||
* SETADDR Array Address *
|
||||
* Z FSEEK Move to Position (Carry Clear) Y=Channel X=Status, Y=Error *
|
||||
* SETINDEX Position *
|
||||
* FTELL Get File Position (Carry Clear) Y=Channel A=Error, YX=Position *
|
||||
**********************************************************************************************/
|
||||
extern int filecmd(M6502 *mpu, word addr, byte data);
|
||||
|
||||
/**********************************************************************************************
|
||||
* Process System Command *
|
||||
* Command passed in A and parameters in X, Y, and Carry *
|
||||
* 16-Bit values are passed with the MSB in Y and the LSB in X *
|
||||
* Results returned in A, X, and Y *
|
||||
* Unless otherwise specified, A contains the Command Code *
|
||||
* *
|
||||
* A=Command Description Parameters Returns *
|
||||
* C CLOCK Get System Clock A,Y,X=Clock (Seconds/50) *
|
||||
* T GETTM Get Date/Time (Carry Clear) Y,X = tm Address *
|
||||
* SETTM Set Date/Time Time (Carry Set Y,X = tm Address Y=Error * *
|
||||
**********************************************************************************************/
|
||||
extern int syscmd(M6502 *mpu, word addr, byte data);
|
||||
|
@ -583,7 +583,7 @@ enum {
|
||||
fetch(); \
|
||||
tick(ticks); \
|
||||
fflush(stdout); \
|
||||
fprintf(stderr, "\nundefined instruction %02X\n", memory[PC-1]); \
|
||||
fprintf(stderr, "\nundefined instruction %02X at address %04x\n", memory[PC-1], PC-1); \
|
||||
return;
|
||||
|
||||
#define phR(ticks, adrmode, R) \
|
||||
|
@ -259,6 +259,7 @@ static void usage(int status)
|
||||
fprintf(stream, " -N addr -- set NMI vector\n");
|
||||
fprintf(stream, " -P addr -- emulate putchar(3) at addr\n");
|
||||
fprintf(stream, " -R addr -- set RST vector\n");
|
||||
fprintf(stream, " -S addr -- emulate system commands at addr\n");
|
||||
fprintf(stream, " -s addr last file -- save memory from addr to last in file\n");
|
||||
fprintf(stream, " -v -- print version number then exit\n");
|
||||
fprintf(stream, " -X addr -- terminate emulation if PC reaches addr\n");
|
||||
@ -407,6 +408,18 @@ static int doFtrap(int argc, char **argv, M6502 *mpu)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int STrap(M6502 *mpu, word addr, byte data) {
|
||||
syscmd(mpu, addr, data);
|
||||
rts;
|
||||
}
|
||||
static int doStrap(int argc, char **argv, M6502 *mpu)
|
||||
{
|
||||
unsigned addr;
|
||||
if (argc < 2) usage(1);
|
||||
addr= htol(argv[1]);
|
||||
M6502_setCallback(mpu, call, addr, STrap);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Emulate getchar(3) at addr */
|
||||
static int gTrap(M6502 *mpu, word addr, byte data) { mpu->registers->a= getchar(); rts; }
|
||||
@ -532,6 +545,7 @@ int main(int argc, char **argv)
|
||||
else if (!strcmp(*argv, "-N")) n= doNMI(argc, argv, mpu);
|
||||
else if (!strcmp(*argv, "-P")) n= doPtrap(argc, argv, mpu);
|
||||
else if (!strcmp(*argv, "-R")) n= doRST(argc, argv, mpu);
|
||||
else if (!strcmp(*argv, "-S")) n= doStrap(argc, argv, mpu);
|
||||
else if (!strcmp(*argv, "-s")) n= doSave(argc, argv, mpu);
|
||||
else if (!strcmp(*argv, "-v")) n= doVersion(argc, argv, mpu);
|
||||
else if (!strcmp(*argv, "-X")) n= doXtrap(argc, argv, mpu);
|
||||
|
Loading…
Reference in New Issue
Block a user