Compare commits

...

2 Commits

Author SHA1 Message Date
dschmenk 82a1632bfd Quick updates 2024-03-09 16:12:05 -08:00
David Schmenk db424e9fc7 Add single stepping to lib6502 adn complete Apple 1+CFFA emulation 2024-03-09 15:13:07 -08:00
6 changed files with 132 additions and 22 deletions

View File

@ -28,6 +28,10 @@
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <termios.h>
#include "config.h"
#include "lib6502.h"
@ -37,6 +41,8 @@
typedef uint8_t byte;
typedef uint16_t word;
struct termios org_tio;
void pfail(const char *msg)
{
fflush(stdout);
@ -83,21 +89,61 @@ int load(M6502 *mpu, word address, const char *path)
return 1;
}
//
// CFFA1 zero page addresses.
//
#define CFFADest 0x00
#define CFFAFileName 0x02
#define CFFAOldName 0x04
#define CFFAFileType 0x06
#define CFFAAuxType 0x07
#define CFFAFileSize 0x09
#define CFFAEntryPtr 0x0B
int cffa1(M6502 *mpu, word address, byte data)
{
char *fileptr, filename[64];
int addr;
struct stat sbuf;
switch (mpu->registers->x)
{
case 0x7A: /* perform keyboard scan */
mpu->registers->x= 0x00;
case 0x02: /* quit */
exit(0);
break;
case 0x14: /* find dir entry */
addr = mpu->memory[CFFAFileName] | (mpu->memory[CFFAFileName + 1] << 8);
memset(filename, 0, 64);
strncpy(filename, (char *)(mpu->memory + addr + 1), mpu->memory[addr]);
strcat(filename, "#FE1000");
if (!(stat(filename, &sbuf)))
{
/* DirEntry @ $9100 */
mpu->memory[CFFAEntryPtr] = 0x00;
mpu->memory[CFFAEntryPtr + 1] = 0x91;
mpu->memory[0x9115] = sbuf.st_size;
mpu->memory[0x9116] = sbuf.st_size >> 8;
mpu->registers->a = 0;
}
else
mpu->registers->a = -1;
break;
case 0x22: /* load file */
addr = mpu->memory[CFFAFileName] | (mpu->memory[CFFAFileName + 1] << 8);
memset(filename, 0, 64);
strncpy(filename, (char *)(mpu->memory + addr + 1), mpu->memory[addr]);
strcat(filename, "#FE1000");
addr = mpu->memory[CFFADest] | (mpu->memory[CFFADest + 1] << 8);
mpu->registers->a = load(mpu, addr, filename) - 1;
break;
default:
{
char state[64];
fprintf(stderr, "Unimplemented CFFA function: %02X\n", mpu->registers->x);
M6502_dump(mpu, state);
fflush(stdout);
fprintf(stderr, "\nCFFA1 %s\n", state);
fail("ABORT");
pfail("ABORT");
}
break;
}
@ -105,18 +151,38 @@ int cffa1(M6502 *mpu, word address, byte data)
}
int bye(M6502 *mpu, word addr, byte data) { exit(0); return 0; }
int cout(M6502 *mpu, word addr, byte data) { putchar(mpu->registers->a); fflush(stdout); rts; }
int cout(M6502 *mpu, word addr, byte data) { if (mpu->registers->a == 0x8D) putchar('\n'); putchar(mpu->registers->a & 0x7F); fflush(stdout); rts; }
int rd6820kbdctl(M6502 *mpu, word addr, byte data) { return 0x80; }
unsigned keypending = 0;
unsigned char keypressed(void)
{
unsigned char cin;
if (read(STDIN_FILENO, &cin, 1) > 0)
keypending = cin | 0x80;
return keypending & 0x80;
}
unsigned char keyin(void)
{
unsigned char cin;
if (!keypending)
keypressed();
cin = keypending;
keypending = 0;
return cin;
}
int rd6820kbdctl(M6502 *mpu, word addr, byte data) { return keypressed(); }
int rd6820vidctl(M6502 *mpu, word addr, byte data) { return 0x00; }
int rd6820kbd(M6502 *mpu, word addr, byte data) { return getchar(); }
int wr6820vid(M6502 *mpu, word addr, byte data) { putchar(data); fflush(stdout); return 0; }
int rd6820kbd(M6502 *mpu, word addr, byte data) { return keyin(); }
int rd6820vid(M6502 *mpu, word addr, byte data) { return 0x80; }
int wr6820vid(M6502 *mpu, word addr, byte data) { if (data == 0x8D) putchar('\n'); putchar(data & 0x7F); fflush(stdout); return 0; }
int setTraps(M6502 *mpu)
{
/* Apple 1 memory-mapped IO */
M6502_setCallback(mpu, read, 0xD010, rd6820kbd);
M6502_setCallback(mpu, read, 0xD011, rd6820kbdctl);
M6502_setCallback(mpu, read, 0xD012, rd6820vid);
M6502_setCallback(mpu, write, 0xD012, wr6820vid);
M6502_setCallback(mpu, read, 0xD013, rd6820vidctl);
/* CFFA1 and ROM calls */
@ -126,18 +192,53 @@ int setTraps(M6502 *mpu)
return 0;
}
void resetInput(void)
{
tcsetattr(STDIN_FILENO, TCSANOW, &org_tio);
}
void setRawInput(void)
{
struct termios termio;
// Save input settings.
tcgetattr(STDIN_FILENO, &termio); /* save current port settings */
memcpy(&org_tio, &termio, sizeof(struct termios));
termio.c_cflag = /*BAUDRATE | CRTSCTS |*/ CS8 | CLOCAL | CREAD;
termio.c_iflag = IGNPAR;
termio.c_oflag = 0;
termio.c_lflag = 0; /* set input mode (non-canonical, no echo,...) */
termio.c_cc[VTIME] = 0; /* inter-character timer unused */
termio.c_cc[VMIN] = 0; /* non-blocking read */
tcsetattr(STDIN_FILENO, TCSANOW, &termio);
atexit(resetInput);
}
int main(int argc, char **argv)
{
char *interpfile = "A1PLASMA";
char *interpfile = "A1PLASMA#060280";
char *program= argv[0];
M6502 *mpu = M6502_new(0, 0, 0);
if (argc == 2)
interpfile = argv[1];
while (++argv, --argc > 0)
{
if (!strcmp(*argv, "-t")) mpu->flags |= M6502_SingleStep;
else
if (argv[0][0] != '-') interpfile = *argv;
else fprintf(stderr, "Usage: %s [-t] [interpreter file]", program);
}
if (!load(mpu, 0x280, interpfile))
pfail(interpfile);
setRawInput();
setTraps(mpu);
M6502_reset(mpu);
M6502_run(mpu);
mpu->registers->pc = 0x0280;
while (M6502_run(mpu))
{
char state[64];
char insn[64];
M6502_dump(mpu, state);
M6502_disassemble(mpu, mpu->registers->pc, insn);
printf("%s : %s\n", state, insn);
}
M6502_delete(mpu);
return 0;
}

View File

@ -584,7 +584,7 @@ enum {
tick(ticks); \
fflush(stdout); \
fprintf(stderr, "\nundefined instruction %02X\n", memory[PC-1]); \
return;
return 0;
#define phR(ticks, adrmode, R) \
fetch(); \
@ -744,7 +744,7 @@ static void oops(void)
}
void M6502_run(M6502 *mpu)
int M6502_run(M6502 *mpu)
{
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
@ -768,9 +768,10 @@ void M6502_run(M6502 *mpu)
register void **itabp= &itab[0];
register void *tpc;
# define begin() fetch(); next()
//# define begin() fetch(); next()
# define begin() goto *(itabp[memory[PC++]])
# define fetch() tpc= itabp[memory[PC++]]
# define next() goto *tpc
# define next() if (STEP) { PC--; externalise(); return 1; } goto *tpc
# define dispatch(num, name, mode, cycles) _##num: name(cycles, mode) oops(); next()
# define end()
@ -778,7 +779,7 @@ void M6502_run(M6502 *mpu)
# define begin() for (;;) switch (memory[PC++]) {
# define fetch()
# define next() break
# define next() if (STEP) { externalise(); return 1; } break
# define dispatch(num, name, mode, cycles) case 0x##num: name(cycles, mode); next()
# define end() }
@ -790,8 +791,9 @@ void M6502_run(M6502 *mpu)
byte A, X, Y, P, S;
M6502_Callback *readCallback= mpu->callbacks->read;
M6502_Callback *writeCallback= mpu->callbacks->write;
unsigned int STEP;
# define internalise() A= mpu->registers->a; X= mpu->registers->x; Y= mpu->registers->y; P= mpu->registers->p; S= mpu->registers->s; PC= mpu->registers->pc
# define internalise() STEP=mpu->flags&M6502_SingleStep; A= mpu->registers->a; X= mpu->registers->x; Y= mpu->registers->y; P= mpu->registers->p; S= mpu->registers->s; PC= mpu->registers->pc
# define externalise() mpu->registers->a= A; mpu->registers->x= X; mpu->registers->y= Y; mpu->registers->p= P; mpu->registers->s= S; mpu->registers->pc= PC
internalise();
@ -809,6 +811,7 @@ void M6502_run(M6502 *mpu)
# undef end
(void)oops;
return 0;
}

View File

@ -48,14 +48,15 @@ struct _M6502
enum {
M6502_RegistersAllocated = 1 << 0,
M6502_MemoryAllocated = 1 << 1,
M6502_CallbacksAllocated = 1 << 2
M6502_CallbacksAllocated = 1 << 2,
M6502_SingleStep = 1 << 3
};
extern M6502 *M6502_new(M6502_Registers *registers, M6502_Memory memory, M6502_Callbacks *callbacks);
extern void M6502_reset(M6502 *mpu);
extern void M6502_nmi(M6502 *mpu);
extern void M6502_irq(M6502 *mpu);
extern void M6502_run(M6502 *mpu);
extern int M6502_run(M6502 *mpu);
extern int M6502_disassemble(M6502 *mpu, uint16_t addr, char buffer[64]);
extern void M6502_dump(M6502 *mpu, char buffer[64]);
extern void M6502_delete(M6502 *mpu);

View File

@ -1,3 +1,6 @@
include "inc/cmdsys.plh"
puts("a"); putln
puts("bb"); putln
puts("ccc"); putln
puts("Hello, world.\n")
done

View File

@ -1,5 +1,5 @@
const RELADDR = $1000
const inbuff = $200
const inbuff = $01FF
const freemem = $0006
//
// System flags: memory allocator screen holes.

View File

@ -1098,7 +1098,9 @@ JUMP INY
JMP FETCHOP
A1CMD !SOURCE "vmsrc/apple/a1cmd.a"
SEGEND = *
VMINIT LDY #$10 ; INSTALL PAGE 0 FETCHOP ROUTINE
VMINIT LDX #$FE ; INIT STACK LEAVING ROOM FOR INBUFF SIZE
TXS
LDY #$10 ; INSTALL PAGE 0 FETCHOP ROUTINE
- LDA PAGE0-1,Y
STA DROP-1,Y
DEY