mirror of
https://github.com/dschmenk/PLASMA.git
synced 2025-02-10 10:30:58 +00:00
Add single stepping to lib6502 adn complete Apple 1+CFFA emulation
This commit is contained in:
parent
8344f18612
commit
db424e9fc7
@ -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,139 @@
|
||||
typedef uint8_t byte;
|
||||
typedef uint16_t word;
|
||||
|
||||
int keycode_to_a2code[128] =
|
||||
{
|
||||
-1, // KEY_RESERVED
|
||||
0x35, // KEY_ESC
|
||||
0x12, // KEY_1
|
||||
0x13, // KEY_2
|
||||
0x14, // KEY_3
|
||||
0x15, // KEY_4
|
||||
0x17, // KEY_5
|
||||
0x16, // KEY_6
|
||||
0x1A, // KEY_7
|
||||
0x1C, // KEY_8
|
||||
0x19, // KEY_9
|
||||
0x1D, // KEY_0
|
||||
0x1B, // KEY_MINUS
|
||||
0x18, // KEY_EQUAL
|
||||
0x3B, // KEY_BACKSPACE0
|
||||
0x30, // KEY_TAB
|
||||
0x0C, // KEY_Q
|
||||
0x0D, // KEY_W
|
||||
0x0E, // KEY_E
|
||||
0x0F, // KEY_R
|
||||
0x11, // KEY_T
|
||||
0x10, // KEY_Y
|
||||
0x20, // KEY_U
|
||||
0x22, // KEY_I
|
||||
0x1F, // KEY_O
|
||||
0x23, // KEY_P
|
||||
0x21, // KEY_LEFTBRACE
|
||||
0x1E, // KEY_RIGHTBRACE
|
||||
0x24, // KEY_ENTER
|
||||
0x36, // KEY_LEFTCTRL
|
||||
0x00, // KEY_A
|
||||
0x01, // KEY_S
|
||||
0x02, // KEY_D
|
||||
0x03, // KEY_F
|
||||
0x05, // KEY_G
|
||||
0x04, // KEY_H
|
||||
0x26, // KEY_J
|
||||
0x28, // KEY_K
|
||||
0x25, // KEY_L
|
||||
0x29, // KEY_SEMICOLON
|
||||
0x27, // KEY_APOSTROPHE
|
||||
0x32, // KEY_GRAVE
|
||||
0x38, // KEY_LEFTSHIFT
|
||||
0x2A, // KEY_BACKSLASH
|
||||
0x06, // KEY_Z
|
||||
0x07, // KEY_X
|
||||
0x08, // KEY_C
|
||||
0x09, // KEY_V
|
||||
0x0B, // KEY_B
|
||||
0x2D, // KEY_N
|
||||
0x2E, // KEY_M
|
||||
0x2B, // KEY_COMMA
|
||||
0x2F, // KEY_DOT
|
||||
0x2C, // KEY_SLASH
|
||||
0x38, // KEY_RIGHTSHIFT
|
||||
0x43, // KEY_KPASTERISK
|
||||
0x37, // KEY_LEFTALT
|
||||
0x31, // KEY_SPACE
|
||||
0x39, // KEY_CAPSLOCK
|
||||
0x7A, // KEY_F1
|
||||
0x78, // KEY_F2
|
||||
0x63, // KEY_F3
|
||||
0x76, // KEY_F4
|
||||
0x60, // KEY_F5
|
||||
0x61, // KEY_F6
|
||||
0x62, // KEY_F7
|
||||
0x64, // KEY_F8
|
||||
0x65, // KEY_F9
|
||||
0x6D, // KEY_F10
|
||||
0x47, // KEY_NUMLOCK
|
||||
0x37, // KEY_SCROLLLOCK
|
||||
0x59, // KEY_KP7
|
||||
0x5B, // KEY_KP8
|
||||
0x5C, // KEY_KP9
|
||||
0x4E, // KEY_KPMINUS
|
||||
0x56, // KEY_KP4
|
||||
0x57, // KEY_KP5
|
||||
0x58, // KEY_KP6
|
||||
0x45, // KEY_KPPLUS
|
||||
0x53, // KEY_KP1
|
||||
0x54, // KEY_KP2
|
||||
0x55, // KEY_KP3
|
||||
0x52, // KEY_KP0
|
||||
0x41, // KEY_KPDOT
|
||||
-1,
|
||||
-1, // KEY_ZENKAKUHANKAKU
|
||||
-1, // KEY_102ND
|
||||
0x67, // KEY_F11
|
||||
0x6F, // KEY_F12
|
||||
-1, // KEY_RO
|
||||
-1, // KEY_KATAKANA
|
||||
-1, // KEY_HIRAGANA
|
||||
-1, // KEY_HENKAN
|
||||
-1, // KEY_KATAKANAHIRAGANA
|
||||
-1, // KEY_MUHENKAN
|
||||
-1, // KEY_KPJPCOMMA
|
||||
0x4C, // KEY_KPENTER
|
||||
0x36, // KEY_RIGHTCTRL
|
||||
0x4B, // KEY_KPSLASH
|
||||
0x7F, // KEY_SYSRQ
|
||||
0x37, // KEY_RIGHTALT
|
||||
0x6E, // KEY_LINEFEED
|
||||
0x73, // KEY_HOME
|
||||
0x3E, // KEY_UP
|
||||
0x74, // KEY_PAGEUP
|
||||
0x3B, // KEY_LEFT
|
||||
0x3C, // KEY_RIGHT
|
||||
0x77, // KEY_END
|
||||
0x3D, // KEY_DOWN
|
||||
0x79, // KEY_PAGEDOWN
|
||||
0x72, // KEY_INSERT
|
||||
0x33, // KEY_DELETE
|
||||
-1, // KEY_MACRO
|
||||
-1, // KEY_MUTE
|
||||
-1, // KEY_VOLUMEDOWN
|
||||
-1, // KEY_VOLUMEUP
|
||||
0x7F, // KEY_POWER /* SC System Power Down */
|
||||
0x51, // KEY_KPEQUAL
|
||||
0x4E, // KEY_KPPLUSMINUS
|
||||
-1, // KEY_PAUSE
|
||||
-1, // KEY_SCALE /* AL Compiz Scale (Expose) */
|
||||
0x2B, // KEY_KPCOMMA
|
||||
-1, // KEY_HANGEUL
|
||||
-1, // KEY_HANJA
|
||||
-1, // KEY_YEN
|
||||
0x3A, // KEY_LEFTMETA
|
||||
0x3A, // KEY_RIGHTMETA
|
||||
-1 // KEY_COMPOSE
|
||||
};
|
||||
struct termios org_tio;
|
||||
|
||||
void pfail(const char *msg)
|
||||
{
|
||||
fflush(stdout);
|
||||
@ -83,21 +220,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 +282,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 +323,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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -1,5 +1,5 @@
|
||||
const RELADDR = $1000
|
||||
const inbuff = $200
|
||||
const inbuff = $01FF
|
||||
const freemem = $0006
|
||||
//
|
||||
// System flags: memory allocator screen holes.
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user