/* run6502.c -- 6502 emulator shell -*- C -*- */ /* Copyright (c) 2005 Ian Piumarta * * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the 'Software'), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, provided that the above copyright notice(s) and this * permission notice appear in all copies of the Software and that both the * above copyright notice(s) and this permission notice appear in supporting * documentation. * * THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK. */ /* Last edited: 2005-11-02 01:18:58 by piumarta on margaux.local */ /* Apple 1 + CFFA1 support for PLASMA by resman */ #include #include #include #include #include #include #include #include #include #include "config.h" #include "lib6502.h" #define VERSION PACKAGE_NAME " " PACKAGE_VERSION " " PACKAGE_COPYRIGHT typedef uint8_t byte; typedef uint16_t word; struct termios org_tio; void pfail(const char *msg) { fflush(stdout); perror(msg); exit(1); } #define rts \ { \ word pc; \ pc = mpu->memory[++mpu->registers->s + 0x100]; \ pc |= mpu->memory[++mpu->registers->s + 0x100] << 8; \ return pc + 1; \ } int save(M6502 *mpu, word address, unsigned length, const char *path) { FILE *file; int count; if (!(file = fopen(path, "wb"))) return 0; while ((count = fwrite(mpu->memory + address, 1, length, file))) { address += count; length -= count; } fclose(file); return 1; } int load(M6502 *mpu, word address, const char *path) { FILE *file; int count; size_t max = 0x10000 - address; if (!(file = fopen(path, "rb"))) return 0; while ((count = fread(mpu->memory + address, 1, max, file)) > 0) { address += count; max -= count; } fclose(file); 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 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); pfail("ABORT"); } break; } rts; } int bye(M6502 *mpu, word addr, byte data) { exit(0); return 0; } int cout(M6502 *mpu, word addr, byte data) { if (mpu->registers->a == 0x8D) putchar('\n'); putchar(mpu->registers->a & 0x7F); fflush(stdout); rts; } int paused = 0; unsigned char keypending = 0; unsigned char keypressed(M6502 *mpu) { unsigned char cin, cext[2]; if (read(STDIN_FILENO, &cin, 1) > 0) { if (cin == 0x03) // CTRL-C { mpu->flags |= M6502_SingleStep; paused = 1; } if (cin == 0x1B) // Look for left arrow { if (read(STDIN_FILENO, cext, 2) == 2 && cext[0] == '[' && cext[1] == 'D') cin = 0x08; } keypending = cin | 0x80; } return keypending & 0x80; } unsigned char keyin(M6502 *mpu) { unsigned char cin; if (!keypending) keypressed(mpu); cin = keypending; keypending = 0; return cin; } int rd6820kbdctl(M6502 *mpu, word addr, byte data) { return keypressed(mpu); } int rd6820vidctl(M6502 *mpu, word addr, byte data) { return 0x00; } int rd6820kbd(M6502 *mpu, word addr, byte data) { return keyin(mpu); } 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 */ M6502_setCallback(mpu, call, 0x9000, bye); M6502_setCallback(mpu, call, 0x900C, cffa1); M6502_setCallback(mpu, call, 0xFFEF, cout); 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#060280"; char *program= argv[0]; M6502 *mpu = M6502_new(0, 0, 0); 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); 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\r\n", state, insn); if (paused || (keypressed(mpu) && keypending == 0x83)) { keypending = 0; while (!keypressed(mpu)); if (keypending == (0x80|'C')) paused = 0; else if (keypending == (0x80|'Q')) break; keypending = 0; } } M6502_delete(mpu); return 0; }