mirror of
https://github.com/RevCurtisP/C02.git
synced 2024-11-25 06:31:25 +00:00
Added File Command Processor to run6502 emulator
This commit is contained in:
parent
e9d5c04f87
commit
17e487d4a5
148
lib6502/dirent.c
Normal file
148
lib6502/dirent.c
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
|
||||
Implementation of POSIX directory browsing functions and types for Win32.
|
||||
|
||||
Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
|
||||
History: Created March 1997. Updated June 2003 and July 2012.
|
||||
Rights: See end of file.
|
||||
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <io.h> /* _findfirst and _findnext set errno iff they return -1 */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */
|
||||
|
||||
struct DIR
|
||||
{
|
||||
handle_type handle; /* -1 for failed rewind */
|
||||
struct _finddata_t info;
|
||||
struct dirent result; /* d_name null iff first time */
|
||||
char *name; /* null-terminated char string */
|
||||
};
|
||||
|
||||
DIR *opendir(const char *name)
|
||||
{
|
||||
DIR *dir = 0;
|
||||
|
||||
if(name && name[0])
|
||||
{
|
||||
size_t base_length = strlen(name);
|
||||
const char *all = /* search pattern must end with suitable wildcard */
|
||||
strchr("/\\", name[base_length - 1]) ? "*" : "/*";
|
||||
|
||||
if((dir = (DIR *) malloc(sizeof *dir)) != 0 &&
|
||||
(dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0)
|
||||
{
|
||||
strcat(strcpy(dir->name, name), all);
|
||||
|
||||
if((dir->handle =
|
||||
(handle_type) _findfirst(dir->name, &dir->info)) != -1)
|
||||
{
|
||||
dir->result.d_name = 0;
|
||||
}
|
||||
else /* rollback */
|
||||
{
|
||||
free(dir->name);
|
||||
free(dir);
|
||||
dir = 0;
|
||||
}
|
||||
}
|
||||
else /* rollback */
|
||||
{
|
||||
free(dir);
|
||||
dir = 0;
|
||||
errno = ENOMEM;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EINVAL;
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
int closedir(DIR *dir)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
if(dir)
|
||||
{
|
||||
if(dir->handle != -1)
|
||||
{
|
||||
result = _findclose(dir->handle);
|
||||
}
|
||||
|
||||
free(dir->name);
|
||||
free(dir);
|
||||
}
|
||||
|
||||
if(result == -1) /* map all errors to EBADF */
|
||||
{
|
||||
errno = EBADF;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct dirent *readdir(DIR *dir)
|
||||
{
|
||||
struct dirent *result = 0;
|
||||
|
||||
if(dir && dir->handle != -1)
|
||||
{
|
||||
if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1)
|
||||
{
|
||||
result = &dir->result;
|
||||
result->d_name = dir->info.name;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EBADF;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void rewinddir(DIR *dir)
|
||||
{
|
||||
if(dir && dir->handle != -1)
|
||||
{
|
||||
_findclose(dir->handle);
|
||||
dir->handle = (handle_type) _findfirst(dir->name, &dir->info);
|
||||
dir->result.d_name = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EBADF;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
Copyright Kevlin Henney, 1997, 2003, 2012. All rights reserved.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose is hereby granted without fee, provided
|
||||
that this copyright and permissions notice appear in all copies and
|
||||
derivatives.
|
||||
|
||||
This software is supplied "as is" without express or implied warranty.
|
||||
|
||||
But that said, if there are any problems please get in touch.
|
||||
|
||||
*/
|
50
lib6502/dirent.h
Normal file
50
lib6502/dirent.h
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef DIRENT_INCLUDED
|
||||
#define DIRENT_INCLUDED
|
||||
|
||||
/*
|
||||
|
||||
Declaration of POSIX directory browsing functions and types for Win32.
|
||||
|
||||
Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
|
||||
History: Created March 1997. Updated June 2003.
|
||||
Rights: See end of file.
|
||||
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef struct DIR DIR;
|
||||
|
||||
struct dirent
|
||||
{
|
||||
char *d_name;
|
||||
};
|
||||
|
||||
DIR *opendir(const char *);
|
||||
int closedir(DIR *);
|
||||
struct dirent *readdir(DIR *);
|
||||
void rewinddir(DIR *);
|
||||
|
||||
/*
|
||||
|
||||
Copyright Kevlin Henney, 1997, 2003. All rights reserved.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose is hereby granted without fee, provided
|
||||
that this copyright and permissions notice appear in all copies and
|
||||
derivatives.
|
||||
|
||||
This software is supplied "as is" without express or implied warranty.
|
||||
|
||||
But that said, if there are any problems please get in touch.
|
||||
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -25,12 +25,16 @@
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <direct.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "lib6502.h"
|
||||
|
||||
#define VERSION PACKAGE_NAME " " PACKAGE_VERSION " " PACKAGE_COPYRIGHT
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
typedef uint8_t byte;
|
||||
typedef uint16_t word;
|
||||
|
||||
@ -38,6 +42,24 @@ static char *program= 0;
|
||||
|
||||
static byte bank[0x10][0x4000];
|
||||
|
||||
/* I/O Blocks for File I/O */
|
||||
#define MAXIOB 15
|
||||
#define STRLEN 128
|
||||
struct iocb
|
||||
{
|
||||
int opened; //Flag: file opened
|
||||
char type; //Channel Type: 'F', 'D'
|
||||
char mode; //File Mode: 'R', 'W'
|
||||
FILE *fp; //File Pointer
|
||||
DIR *dp; //Directory Pointer
|
||||
int errnum; //Last Error Number
|
||||
char name[STRLEN]; //File/Directory Name
|
||||
};
|
||||
|
||||
static struct iocb iocbs[MAXIOB];
|
||||
static char filename[STRLEN]; //File name for open
|
||||
static char filebuff[256]; //File I/O Buffer
|
||||
static word fileaddr; //File Read/Write Address
|
||||
|
||||
void fail(const char *fmt, ...)
|
||||
{
|
||||
@ -247,11 +269,13 @@ static void usage(int status)
|
||||
fprintf(stream, "usage: %s [option ...]\n", program);
|
||||
fprintf(stream, " %s [option ...] -B [image ...]\n", program);
|
||||
fprintf(stream, " -B -- minimal Acorn 'BBC Model B' compatibility\n");
|
||||
fprintf(stream, " -d addr last -- dump memory between addr and last\n");
|
||||
fprintf(stream, " -d addr last -- disassemble memory between addr and last\n");
|
||||
fprintf(stream, " -F addr -- emulate fileio at addr\n");
|
||||
fprintf(stream, " -G addr -- emulate getchar(3) at addr\n");
|
||||
fprintf(stream, " -h -- help (print this message)\n");
|
||||
fprintf(stream, " -I addr -- set IRQ vector\n");
|
||||
fprintf(stream, " -l addr file -- load file at addr\n");
|
||||
fprintf(stream, " -m addr last -- dump memory between addr and last\n");
|
||||
fprintf(stream, " -M addr -- emulate memory-mapped stdio at addr\n");
|
||||
fprintf(stream, " -N addr -- set NMI vector\n");
|
||||
fprintf(stream, " -P addr -- emulate putchar(3) at addr\n");
|
||||
@ -317,7 +341,7 @@ static int save(M6502 *mpu, word address, unsigned length, const char *path)
|
||||
{
|
||||
FILE *file= 0;
|
||||
int count= 0;
|
||||
if (!(file= fopen(path, "w")))
|
||||
if (!(file= fopen(path, "wb")))
|
||||
return 0;
|
||||
while ((count= fwrite(mpu->memory + address, 1, length, file)))
|
||||
{
|
||||
@ -325,7 +349,7 @@ static int save(M6502 *mpu, word address, unsigned length, const char *path)
|
||||
length -= count;
|
||||
}
|
||||
fclose(file);
|
||||
return 1;
|
||||
return address;
|
||||
}
|
||||
|
||||
|
||||
@ -334,18 +358,19 @@ static int load(M6502 *mpu, word address, const char *path)
|
||||
FILE *file= 0;
|
||||
int count= 0;
|
||||
size_t max= 0x10000 - address;
|
||||
if (!(file= fopen(path, "r")))
|
||||
if (!(file= fopen(path, "rb")))
|
||||
return 0;
|
||||
if (DEBUG) fprintf(stderr, "loading %s\nstart address %04x\n", path, address);
|
||||
while ((count= fread(mpu->memory + address, 1, max, file)) > 0)
|
||||
{
|
||||
address += count;
|
||||
max -= count;
|
||||
}
|
||||
{
|
||||
address += count;
|
||||
max -= count;
|
||||
}
|
||||
fclose(file);
|
||||
return 1;
|
||||
if (DEBUG) fprintf(stderr, "end address %04x\n", address);
|
||||
return address;
|
||||
}
|
||||
|
||||
|
||||
static int doLoadInterpreter(int argc, char **argv, M6502 *mpu)
|
||||
{
|
||||
if (argc < 3) usage(1);
|
||||
@ -386,6 +411,349 @@ doVEC(RST);
|
||||
|
||||
#undef doVEC
|
||||
|
||||
int setiocb(int chan, int opened, char type, char mode, FILE *fp, DIR *dp, char *name) {
|
||||
iocbs[chan].opened = opened;
|
||||
iocbs[chan].type = type;
|
||||
iocbs[chan].mode = mode;
|
||||
iocbs[chan].fp = fp;
|
||||
iocbs[chan].dp = dp;
|
||||
iocbs[chan].errnum = 0;
|
||||
strcpy(iocbs[chan].name, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void initiocb(int chan) {
|
||||
setiocb(chan, 0, ' ', ' ', NULL, NULL, "");
|
||||
}
|
||||
|
||||
void initiocbs(void)
|
||||
{
|
||||
filename[0] = 0; //Set filename to ""
|
||||
for (int chan=0; chan<=MAXIOB; chan++)
|
||||
initiocb(chan);
|
||||
}
|
||||
|
||||
/* Set Error Number and Error Message */
|
||||
static int seterror(int chan) {
|
||||
int errnum = errno;
|
||||
if (DEBUG) fprintf(stderr, "setting channel %d error to %d\n", chan, errnum);
|
||||
iocbs[chan].errnum = errnum;
|
||||
return errnum;
|
||||
}
|
||||
|
||||
/* Set File Name */
|
||||
static int setname(M6502 *mpu, word addr, char *name) {
|
||||
int i;
|
||||
for (i=0; i<STRLEN; i++) {
|
||||
char c = mpu->memory[addr + i & 0xFFFF];
|
||||
if (c) name[i] = c;
|
||||
else break;
|
||||
}
|
||||
name[i] = 0; //Terminate String
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Find Unused IOCB */
|
||||
static int uniocb(void) {
|
||||
int chan;
|
||||
for (chan=1; chan<=MAXIOB; chan++) {
|
||||
if (iocbs[chan].opened == 0) break;
|
||||
if (chan > MAXIOB) {chan = -24; break;}
|
||||
}
|
||||
return chan;
|
||||
}
|
||||
|
||||
/* Validate Channel */
|
||||
static int valchan(int chan, char valtype) {
|
||||
int errnum = 0; //Error (none)
|
||||
if (DEBUG) fprintf(stderr, "validating channel %d\n", chan);
|
||||
if (chan > MAXIOB) errnum = 44; //Channel number out of range
|
||||
else if (iocbs[chan].opened == 0) errnum = 9; //Bad file descriptor
|
||||
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
|
||||
}
|
||||
}
|
||||
return errnum;
|
||||
}
|
||||
|
||||
/* Write Buffer to Memory */
|
||||
static int writemem(M6502 *mpu, char* buffer, int count) {
|
||||
int i;
|
||||
for (i = 0; i<count; i++)
|
||||
mpu->memory[fileaddr+i] = buffer[i];
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Write String to Memory */
|
||||
static int writestr(M6502 *mpu, char* buffer, int count) {
|
||||
int i;
|
||||
if (DEBUG) fprintf(stderr, "writing '%s' to address %04x\n", buffer, fileaddr);
|
||||
for (i = 0; i<count; i++) {
|
||||
char c = buffer[i];
|
||||
if (c == 0) break;
|
||||
mpu->memory[fileaddr+i] = c;
|
||||
}
|
||||
mpu->memory[fileaddr+i] = 0; //Terminate String
|
||||
if (DEBUG) fprintf(stderr, "wrote %d characters\n", i);
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Emulate fileio at addr */
|
||||
static int fTrap(M6502 *mpu, word addr, byte data) {
|
||||
const char modes[2][3] = {"r", "w"};
|
||||
int chan, e, i;
|
||||
char c, mode[3];
|
||||
char *name;
|
||||
struct 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);
|
||||
switch (a) { //File I/O Command
|
||||
case 'A': //Set filebuffer address - Y.X = address
|
||||
fileaddr = yx;
|
||||
if (DEBUG) fprintf(stdout, "file address set to %04x\n", fileaddr);
|
||||
break;
|
||||
case 'B': //Close Directory - Y = channel
|
||||
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);
|
||||
else initiocb(chan);
|
||||
break;
|
||||
case 'C': //Close file - Y = channel
|
||||
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);
|
||||
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); break;}
|
||||
if (DEBUG) fprintf(stderr, "directory opened on channel %d\n", chan);
|
||||
y = setiocb(chan, -1, 'D', ' ', NULL, dp, filename); //Setup IOCB
|
||||
if (y == 0) x = chan;
|
||||
break;
|
||||
case 'E': //EOF - Y = channel
|
||||
chan = y;
|
||||
y = valchan(chan, 'F'); 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);
|
||||
break;
|
||||
case 'G': //Get character - Y = channel
|
||||
chan = y;
|
||||
x = 0; //Character read (none)
|
||||
y = valchan(chan, 'F'); if (y) break;
|
||||
c = fgetc(iocbs[chan].fp);
|
||||
if (feof(iocbs[chan].fp)) {y = 255; break;}
|
||||
if (c == EOF) {y = seterror(chan); 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;
|
||||
char *s = fgets(filebuff, STRLEN, iocbs[chan].fp);
|
||||
if (s == NULL) {y = seterror(chan); break;}
|
||||
if (DEBUG) fprintf(stderr, "read string '%s'\n", filebuff);
|
||||
writestr(mpu, filebuff, STRLEN);
|
||||
break;
|
||||
case 'I': //Init File System
|
||||
initiocbs(); //Initialize I/O Control Blocks
|
||||
break;
|
||||
case 'J': //Read Directory Entry
|
||||
chan = y;
|
||||
x = 0; //Return Value (Read Failed)
|
||||
y = valchan(chan, 'D'); if (y) break;
|
||||
if (p & 1) {
|
||||
if (DEBUG) fprintf(stdout, "retrieving directory name\n");
|
||||
x = writestr(mpu, iocbs[chan].name, STRLEN);
|
||||
} 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);
|
||||
}
|
||||
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); else y=0;
|
||||
break;
|
||||
case 'L': //Load file
|
||||
a = 0; //Error (none)
|
||||
if (DEBUG) fprintf(stderr, "loading file at %04h\n", fileaddr);
|
||||
e = load(mpu, fileaddr, filename);
|
||||
if (!e) {a = seterror(0); 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); 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);
|
||||
break;
|
||||
case 'O': //Open file - Y = mode
|
||||
strcpy(mode, modes[y>>7]);
|
||||
x = 0; //File channel (none)
|
||||
y = 0; //Error code (none)
|
||||
chan = uniocb(); if (chan <0) {y = -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); break;}
|
||||
if (DEBUG) fprintf(stderr, "file opened on channel %d\n", chan);
|
||||
y = setiocb(chan, -1, 'F', mode[0], 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;
|
||||
e = fputc(c, iocbs[chan].fp);
|
||||
if (e == EOF) {y = seterror(chan); break;}
|
||||
a = e & 0xFF;
|
||||
break;
|
||||
case 'Q': //Put String - Y = channel
|
||||
chan = y;
|
||||
x = 0; //Number of characters written
|
||||
y = valchan(chan, 'F'); if (y) break;
|
||||
for (i = 0; i<128; i++) {
|
||||
c = mpu->memory[fileaddr+i];
|
||||
if (c) filebuff[i] = c;
|
||||
else break;
|
||||
}
|
||||
filebuff[i] = 0;
|
||||
if (DEBUG) fprintf(stderr, "writing string '%s'\n", filebuff);
|
||||
if (p & 1) strcat(filebuff, "\n");
|
||||
e = fputs(filebuff, iocbs[chan].fp);
|
||||
if (e == EOF) {y = seterror(chan); break;}
|
||||
break;
|
||||
case 'R': //Read bytes - Y = channel, X=Number of Bytes
|
||||
chan = y;
|
||||
y = valchan(chan, 'F'); if (y) break;
|
||||
if (DEBUG) fprintf(stderr, "reading %d bytes\n", x);
|
||||
e = fread(filebuff, x, 1, iocbs[chan].fp);
|
||||
if (e != 1) {y = seterror(chan); break;}
|
||||
writemem(mpu, filebuff, x);
|
||||
break;
|
||||
case 'S': //Save file Y,X = end address
|
||||
a = 0; //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); 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);
|
||||
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);}
|
||||
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); else y=0;
|
||||
} else {
|
||||
x = _getdrive();
|
||||
if (x) y=0; else y=seterror(0);
|
||||
if (DEBUG) fprintf(stderr, "current drive is %c\n", x+'@');
|
||||
}
|
||||
break;
|
||||
case 'W': //Write bytes - Y = channel, X=Number of Bytes
|
||||
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); 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);
|
||||
} else {
|
||||
if (DEBUG) fprintf(stderr, "creating directory '%s'\n", filename);
|
||||
x = _mkdir(filename);
|
||||
}
|
||||
if (x) y=seterror(0); else y=0;
|
||||
break;
|
||||
case 'Y': //Get Last Error, Y=chan
|
||||
chan = y;
|
||||
y = 0; //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);
|
||||
x = iocbs[chan].errnum;
|
||||
char *msg = strerror(x);
|
||||
if (DEBUG) fprintf(stderr, "retrieved error %d, '%s'\n", x, msg);
|
||||
writestr(mpu, msg, STRLEN);
|
||||
break;
|
||||
default:
|
||||
y = 22; //Error - invalid argument
|
||||
}
|
||||
mpu->registers->a = a;
|
||||
mpu->registers->x = x;
|
||||
mpu->registers->y = y;
|
||||
rts;
|
||||
}
|
||||
|
||||
static int doFtrap(int argc, char **argv, M6502 *mpu)
|
||||
{
|
||||
unsigned addr;
|
||||
if (argc < 2) usage(1);
|
||||
addr= htol(argv[1]);
|
||||
M6502_setCallback(mpu, call, addr, fTrap);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Emulate getchar(3) at addr */
|
||||
static int gTrap(M6502 *mpu, word addr, byte data) { mpu->registers->a= getchar(); rts; }
|
||||
@ -462,6 +830,22 @@ static int doDisassemble(int argc, char **argv, M6502 *mpu)
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int doDump(int argc, char **argv, M6502 *mpu)
|
||||
{
|
||||
unsigned addr= 0, last= 0, i= 0;
|
||||
if (argc < 3) usage(1);
|
||||
addr= htol(argv[1]);
|
||||
last= ('+' == *argv[2]) ? addr + htol(1 + argv[2]) : htol(argv[2]);
|
||||
while (addr < last)
|
||||
{
|
||||
printf("%04x ", addr);
|
||||
for (i=0; i<16; i++)
|
||||
if (addr + i < 0x10000) printf("%02x ", mpu->memory[addr + i]);
|
||||
printf("\n");
|
||||
addr += 16;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
@ -482,11 +866,13 @@ int main(int argc, char **argv)
|
||||
int n= 0;
|
||||
if (!strcmp(*argv, "-B")) bTraps= 1;
|
||||
else if (!strcmp(*argv, "-d")) n= doDisassemble(argc, argv, mpu);
|
||||
else if (!strcmp(*argv, "-F")) n= doFtrap(argc, argv, mpu);
|
||||
else if (!strcmp(*argv, "-G")) n= doGtrap(argc, argv, mpu);
|
||||
else if (!strcmp(*argv, "-h")) n= doHelp(argc, argv, mpu);
|
||||
else if (!strcmp(*argv, "-i")) n= doLoadInterpreter(argc, argv, mpu);
|
||||
else if (!strcmp(*argv, "-I")) n= doIRQ(argc, argv, mpu);
|
||||
else if (!strcmp(*argv, "-l")) n= doLoad(argc, argv, mpu);
|
||||
else if (!strcmp(*argv, "-m")) n= doDump(argc, argv, mpu);
|
||||
else if (!strcmp(*argv, "-M")) n= doMtrap(argc, argv, mpu);
|
||||
else if (!strcmp(*argv, "-N")) n= doNMI(argc, argv, mpu);
|
||||
else if (!strcmp(*argv, "-P")) n= doPtrap(argc, argv, mpu);
|
||||
@ -516,6 +902,8 @@ int main(int argc, char **argv)
|
||||
if (bTraps)
|
||||
doBtraps(0, 0, mpu);
|
||||
|
||||
initiocbs(); //Initialize fileio blocks
|
||||
|
||||
M6502_reset(mpu);
|
||||
M6502_run(mpu);
|
||||
M6502_delete(mpu);
|
||||
|
1
lib6502/tcc6502.bat
Normal file
1
lib6502/tcc6502.bat
Normal file
@ -0,0 +1 @@
|
||||
tcc -o run6502.exe -I . dirent.c lib6502.c run6502.c
|
Loading…
Reference in New Issue
Block a user