#include #include #include #include #include #include "emul.h" // in sync with glue.asm #define RAMSTART 0x900 #define STDIO_PORT 0x00 // This binary is also used for automated tests and those tests, when // failing, send a non-zero value to RET_PORT to indicate failure #define RET_PORT 0x01 // Port for block reads. Write 2 bytes, MSB first, on that port and then // read 1024 bytes from the DATA port. #define BLK_PORT 0x03 #define BLKDATA_PORT 0x04 static FILE *fp; static int retcode = 0; static uint8_t iord_stdio() { int c; if (fp != NULL) { c = getc(fp); } else { c = getch(); } if (c == EOF) { c = 4; // ASCII EOT } return (uint8_t)c; } static void iowr_stdio(uint8_t val) { if (fp != NULL) { putchar(val); } else { if (val >= 0x20 || val == '\n') { echochar(val); } } } static void iowr_ret(uint8_t val) { retcode = val; } int run() { Machine *m = emul_init(); if (m == NULL) { return 1; } m->ramstart = RAMSTART; m->iord[STDIO_PORT] = iord_stdio; m->iowr[STDIO_PORT] = iowr_stdio; m->iowr[RET_PORT] = iowr_ret; // Run! while (emul_step()); emul_deinit(); return retcode; } int main(int argc, char *argv[]) { if (argc == 2) { fp = fopen(argv[1], "r"); if (fp == NULL) { fprintf(stderr, "Can't open %s\n", argv[1]); return 1; } int ret = run(); fclose(fp); return ret; } else if (argc == 1) { fp = NULL; initscr(); cbreak(); noecho(); nl(); clear(); scrollok(stdscr, 1); int ret = run(); nocbreak(); echo(); endwin(); printf("\nDone!\n"); emul_printdebug(); return ret; } else { fprintf(stderr, "Usage: ./forth [filename]\n"); return 1; } }