#include #include #include #include #include #include #include #include #include #include #define LOGERR(fmt,args...) fprintf(stderr, "\nERROR: " fmt "\n", ## args); static int verbose = 0, done = 0; typedef enum { LM8_SMALL = 0, LM8_MEDIUM = 1, LM8_LARGE = 2, } LM8_MODEL; typedef uint8_t (*lm8_read_cb) (void *context, int sp, uint32_t address); typedef void (*lm8_write_cb) (void *context, int sp, uint32_t address, uint8_t value); typedef struct _st_lm8_cpu lm8_cpu_t; struct _st_lm8_cpu { uint16_t pc; int pc_limit; uint8_t *prom; uint16_t call_stack[32]; int call_stack_idx; int call_stack_size; int reg16; uint8_t reg[32]; LM8_MODEL model; lm8_read_cb read_cb; lm8_write_cb write_cb; void *context; int sp_size; uint8_t *sp; int CF, CFs, ZF, ZFs, IE; uint8_t IP, IM; }; void lm8_close (lm8_cpu_t *cpu) { if (cpu->prom) free (cpu->prom); if (cpu->sp) free (cpu->sp); free (cpu); return; } lm8_cpu_t *lm8_new ( LM8_MODEL model, int call_stack_size, int reg16, lm8_read_cb read_cb, lm8_write_cb write_cb, void *context, const char *prom_file, int sp_size, const char *sp_file ) { lm8_cpu_t *cpu; if (!(cpu = (lm8_cpu_t *) malloc (sizeof (lm8_cpu_t)))) return NULL; memset (cpu, 0, sizeof (lm8_cpu_t)); cpu->call_stack_size = call_stack_size; cpu->model = model; cpu->read_cb = read_cb; cpu->write_cb = write_cb; cpu->context = context; cpu->sp_size = sp_size; cpu->reg16 = reg16; cpu->pc = 1; // reset vector if (verbose) { printf ("\nLM8 CPU (%s) %d regs, %d call depth:\n", (model == LM8_SMALL) ? "small" : (model == LM8_MEDIUM) ? "medium" : "large", reg16 ? 16 : 32, call_stack_size); } do { struct stat stinfo; if (stat (prom_file, &stinfo)) { LOGERR ("Unable to stat PROM file '%s' - %s", prom_file, strerror (errno)); break; } if (stinfo.st_size % 3) { LOGERR("PROM file size %u not divisible by 3", (unsigned int) stinfo.st_size); break; } cpu->pc_limit = stinfo.st_size / 3; if (!(cpu->prom = (uint8_t *) malloc (stinfo.st_size))) break; int fd; if ((fd = open (prom_file, O_RDONLY)) < 0) { LOGERR("Unable to open PROM file '%s' - %s", prom_file, strerror (errno)); break; } if (read (fd, cpu->prom, stinfo.st_size) != stinfo.st_size) { LOGERR("Unable to read PROM file '%s' - %s", prom_file, strerror (errno)); close (fd); break; } close (fd); if (verbose) { printf (" - PROM file loaded from '%s' - %d instructions\n", prom_file, cpu->pc_limit); } if (!(cpu->sp = (uint8_t *) malloc (sp_size))) break; if (verbose) printf (" - Scrach pad %d bytes\n", sp_size); if (sp_file) { if (stat (sp_file, &stinfo)) { LOGERR ("Unable to stat PROM file '%s' - %s", sp_file, strerror (errno)); break; } if (stinfo.st_size > sp_size) { LOGERR ("SP file size %u exceeds limit %d", (unsigned int) stinfo.st_size, sp_size); break; } int fd; if ((fd = open (sp_file, O_RDONLY)) < 0) { LOGERR("Unable to open SP file '%s' - %s", sp_file, strerror (errno)); break; } if (read (fd, cpu->sp, stinfo.st_size) != stinfo.st_size) { LOGERR("Unable to read SP file '%s' - %s", sp_file, strerror (errno)); close (fd); break; } close (fd); if (verbose) printf (" - Preloaded scratch pad %u bytes\n", (unsigned int) stinfo.st_size); } return cpu; } while (0); lm8_close (cpu); return NULL; } static void printf_rdrb (uint32_t raw) { printf ("r%d,r%d", (raw >> 8) & 0x1f, (raw >> 3) & 0x1f); } static void printf_rdC (uint32_t raw, int limited) { int val = raw & 0xff; if (limited) val = val >> 3; if (val > 15) printf ("r%d,%d\t// 0x%x", (raw >> 8) & 0x1f, val, val); else printf ("r%d,%d", (raw >> 8) & 0x1f, val); } static void printf_label (uint32_t raw, int pc) { int sign = (raw >> 11) & 1; raw &= 0x7ff; if (sign) pc -= (~raw + 1) & 0x7ff; else pc += raw; printf ("%d", pc); } static void printf_instruction (uint16_t pc, uint32_t raw) { int op = raw >> 13; printf ("PC fetch: [0x%04x] %08d: %06x ", pc * 3, pc, raw); switch (op) { case 0: printf ("sub "); printf_rdrb (raw); break; case 1: printf ("subi "); printf_rdC (raw, 0); break; case 2: printf ("subc "); printf_rdrb (raw); break; case 3: printf ("subci "); printf_rdC (raw, 0); break; case 4: printf ("add "); printf_rdrb (raw); break; case 5: printf ("addi "); printf_rdC (raw, 0); break; case 6: printf ("addc "); printf_rdrb (raw); break; case 7: printf ("addci "); printf_rdC (raw, 0); break; case 8: if (((raw >> 3) & 0x3ff) == 0) printf ("nop"); else { printf ("mov "); printf_rdrb (raw); } break; case 9: printf ("movi "); printf_rdC (raw, 0); break; case 10: printf ("and "); printf_rdrb (raw); break; case 11: printf ("andi "); printf_rdC (raw, 0); break; case 12: printf ("or "); printf_rdrb (raw); break; case 13: printf ("ori "); printf_rdC (raw, 0); break; case 14: printf ("xor "); printf_rdrb (raw); break; case 15: printf ("xori "); printf_rdC (raw, 0); break; case 16: printf ("cmp "); printf_rdrb (raw); break; case 17: printf ("cmpi "); printf_rdC (raw, 0); break; case 18: printf ("test "); printf_rdrb (raw); break; case 19: printf ("testi "); printf_rdC (raw, 0); break; case 20: switch (raw & 0x3) { case 0: printf ("ror "); break; case 1: printf ("rol "); break; case 2: printf ("rorc "); break; case 3: printf ("rolc "); break; } printf_rdrb (raw); break; case 22: switch (raw & 0x07) { case 0: printf ("clrc"); break; case 1: printf ("setc"); break; case 2: printf ("clrz"); break; case 3: printf ("setz"); break; case 4: printf ("clri"); break; case 5: printf ("seti"); break; case 6: switch ((raw >> 3) & 0x1f) { case 0: printf ("rcsr r%d,ip", (raw >> 8) & 0x1f); break; case 1: printf ("rcsr r%d,im", (raw >> 8) & 0x1f); break; case 2: printf ("rcsr r%d,ie", (raw >> 8) & 0x1f); break; default: printf ("UNKNOWN "); break; } break; case 7: switch ((raw >> 8) & 0x1f) { case 0: printf ("wcsr ip,r%d", (raw >> 3) & 0x1f); break; case 1: printf ("wcsr im,r%d", (raw >> 3) & 0x1f); break; case 2: printf ("wcsr ie,r%d", (raw >> 3) & 0x1f); break; default: printf ("UNKNOWN "); break; } break; } break; case 23: switch (raw & 0x07) { case 0: printf ("export "); printf_rdC (raw, 1); break; case 1: printf ("import "); printf_rdC (raw, 1); break; case 2: printf ("exporti "); printf_rdrb (raw); break; case 3: printf ("importi "); printf_rdrb (raw); break; case 4: printf ("ssp "); printf_rdC (raw, 1); break; case 5: printf ("lsp "); printf_rdC (raw, 1); break; case 6: printf ("sspi "); printf_rdrb (raw); break; case 7: printf ("lspi "); printf_rdrb (raw); break; } break; case 24: if ((raw >> 12) & 0x01) printf ("bnz "); else printf ("bz "); printf_label(raw, pc); break; case 25: if ((raw >> 12) & 0x01) printf ("bnc "); else printf ("bc "); printf_label(raw, pc); break; case 26: if ((raw >> 12) & 0x01) printf ("callnz "); else printf ("callz "); printf_label(raw, pc); break; case 27: if ((raw >> 12) & 0x01) printf ("callnc "); else printf ("callc "); printf_label(raw, pc); break; case 28: if ((raw >> 12) & 0x01) printf ("ret"); else { printf ("call "); printf_label(raw, pc); } break; case 29: if ((raw >> 12) & 0x01) { printf ("b "); printf_label(raw, pc); } else printf ("iret"); break; default: printf ("UNKNOWN 0x%03x", raw); break; } printf ("\n"); return; } static int _branch (lm8_cpu_t *cpu, uint32_t raw) { int sign = (raw >> 11) & 1; raw &= 0x7ff; cpu->pc--; if (sign) cpu->pc -= (~raw + 1) & 0x7ff; else cpu->pc += raw; return 0; } static int _pushcs (lm8_cpu_t *cpu, int br, uint32_t raw) { if (cpu->call_stack_idx == cpu->call_stack_size) { LOGERR("Cannot PUSH call stack (@%d)", cpu->call_stack_size); return 1; } cpu->call_stack[cpu->call_stack_idx] = cpu->pc; cpu->call_stack_idx++; if (br) return _branch (cpu, raw); return 0; } static int _popcs (lm8_cpu_t *cpu) { if (!cpu->call_stack_idx) { LOGERR("Cannot POP call stack (zero)"); return 1; } cpu->call_stack_idx--; cpu->pc = cpu->call_stack[cpu->call_stack_idx]; return 0; } static uint8_t _dec_rdC (int reg16, uint32_t raw, int limited, int *rd) { int val = raw & 0xff; if (limited) val = val >> 3; if (reg16) *rd = (raw >> 8) & 0x0f; else *rd = (raw >> 8) & 0x1f; return val; } static int _dec_rdrb (int reg16, uint32_t raw, int *rd) { if (reg16) { *rd = (raw >> 8) & 0x0f; return (raw >> 3) & 0x0f; } *rd = (raw >> 8) & 0x1f; return (raw >> 3) & 0x1f; } static int _io_write (lm8_cpu_t *cpu, int sp, int page, uint8_t port, int rd) { uint32_t address = port; if (page && (cpu->model != LM8_SMALL)) { address |= (cpu->reg[13] << 8); if (cpu->model == LM8_LARGE) address |= (cpu->reg[15] << 24) | (cpu->reg[14] << 16); } if (sp && (address < cpu->sp_size)) cpu->sp[address] = cpu->reg[rd]; else cpu->write_cb (cpu->context, sp, address, cpu->reg[rd]); return 0; } static int _io_read (lm8_cpu_t *cpu, int sp, int page, uint8_t port, int rd) { uint32_t address = port; if (page && (cpu->model != LM8_SMALL)) { address |= (cpu->reg[13] << 8); if (cpu->model == LM8_LARGE) address |= (cpu->reg[15] << 24) | (cpu->reg[14] << 16); } if (sp && (address < cpu->sp_size)) cpu->reg[rd] = cpu->sp[address]; else cpu->reg[rd] = cpu->read_cb (cpu->context, sp, address); return 0; } int lm8_step (lm8_cpu_t *cpu) { int rd, rb; uint8_t C; uint16_t aluc; if (cpu->IE && (cpu->IP & cpu->IM)) { // Interrupt pending if (verbose) printf ("Interrupt Vector Taken P/M=%02x/%02x\n", cpu->IP, cpu->IM); cpu->CFs = cpu->CF; cpu->ZFs = cpu->ZF; if (_pushcs (cpu, 0, 0)) return 1; cpu->pc = 0; } // Fetch next instruction if (cpu->pc >= cpu->pc_limit) { LOGERR ("PC %u >= PC limit %u", cpu->pc, cpu->pc_limit); return 1; } uint32_t raw; raw = (cpu->prom[(cpu->pc * 3) + 0] << 16) | (cpu->prom[(cpu->pc * 3) + 1] << 8) | cpu->prom[(cpu->pc * 3) + 2]; if (verbose) printf_instruction (cpu->pc, raw); cpu->pc++; int op = raw >> 13; switch (op) { case 0: // 'sub' rb = _dec_rdrb (cpu->reg16, raw, &rd); aluc = cpu->reg[rd] - cpu->reg[rb]; cpu->reg[rd] = aluc & 0xff; cpu->CF = (aluc & 0x100) ? 1 : 0; cpu->ZF = (aluc & 0x0ff) ? 0 : 1; return 0; case 1: // 'subi' C = _dec_rdC (cpu->reg16, raw, 0, &rd); aluc = cpu->reg[rd] - C; cpu->reg[rd] = aluc & 0xff; cpu->CF = (aluc & 0x100) ? 1 : 0; cpu->ZF = (aluc & 0x0ff) ? 0 : 1; return 0; case 2: // 'subc' rb = _dec_rdrb (cpu->reg16, raw, &rd); aluc = cpu->reg[rd] - cpu->reg[rb] - cpu->CF; cpu->reg[rd] = aluc & 0xff; cpu->CF = (aluc & 0x100) ? 1 : 0; cpu->ZF = (aluc & 0x0ff) ? 0 : 1; return 0; case 3: // 'subci' C = _dec_rdC (cpu->reg16, raw, 0, &rd); aluc = cpu->reg[rd] - C - cpu->CF; cpu->reg[rd] = aluc & 0xff; cpu->CF = (aluc & 0x100) ? 1 : 0; cpu->ZF = (aluc & 0x0ff) ? 0 : 1; return 0; case 4: // 'add' rb = _dec_rdrb (cpu->reg16, raw, &rd); aluc = cpu->reg[rd] + cpu->reg[rb]; cpu->reg[rd] = aluc & 0xff; cpu->CF = (aluc & 0x100) ? 1 : 0; cpu->ZF = (aluc & 0x0ff) ? 0 : 1; return 0; case 5: // 'addi' C = _dec_rdC (cpu->reg16, raw, 0, &rd); aluc = cpu->reg[rd] + C; cpu->reg[rd] = aluc & 0xff; cpu->CF = (aluc & 0x100) ? 1 : 0; cpu->ZF = (aluc & 0x0ff) ? 0 : 1; return 0; case 6: // 'addc' rb = _dec_rdrb (cpu->reg16, raw, &rd); aluc = cpu->reg[rd] + cpu->reg[rb] + cpu->CF; cpu->reg[rd] = aluc & 0xff; cpu->CF = (aluc & 0x100) ? 1 : 0; cpu->ZF = (aluc & 0x0ff) ? 0 : 1; return 0; case 7: // 'addci' C = _dec_rdC (cpu->reg16, raw, 0, &rd); aluc = cpu->reg[rd] + C + cpu->CF; cpu->reg[rd] = aluc & 0xff; cpu->CF = (aluc & 0x100) ? 1 : 0; cpu->ZF = (aluc & 0x0ff) ? 0 : 1; return 0; case 8: // 'mov' / 'nop' rb = _dec_rdrb (cpu->reg16, raw, &rd); cpu->reg[rd] = cpu->reg[rb]; return 0; case 9: // 'movi' C = _dec_rdC (cpu->reg16, raw, 0, &rd); cpu->reg[rd] = C; return 0; case 10: // 'and' rb = _dec_rdrb (cpu->reg16, raw, &rd); cpu->reg[rd] &= cpu->reg[rb]; cpu->ZF = cpu->reg[rd] ? 0 : 1; return 0; case 11: // 'andi' C = _dec_rdC (cpu->reg16, raw, 0, &rd); cpu->reg[rd] &= C; cpu->ZF = cpu->reg[rd] ? 0 : 1; return 0; case 12: // 'or' rb = _dec_rdrb (cpu->reg16, raw, &rd); cpu->reg[rd] |= cpu->reg[rb]; cpu->ZF = cpu->reg[rd] ? 0 : 1; return 0; case 13: // 'ori' C = _dec_rdC (cpu->reg16, raw, 0, &rd); cpu->reg[rd] |= C; cpu->ZF = cpu->reg[rd] ? 0 : 1; return 0; case 14: // 'xor' rb = _dec_rdrb (cpu->reg16, raw, &rd); cpu->reg[rd] ^= cpu->reg[rb]; cpu->ZF = cpu->reg[rd] ? 0 : 1; return 0; case 15: // 'xori' C = _dec_rdC (cpu->reg16, raw, 0, &rd); cpu->reg[rd] ^= C; cpu->ZF = cpu->reg[rd] ? 0 : 1; return 0; case 16: // 'cmp' rb = _dec_rdrb (cpu->reg16, raw, &rd); aluc = cpu->reg[rd] - cpu->reg[rb]; cpu->CF = (aluc & 0x100) ? 1 : 0; cpu->ZF = (aluc & 0x0ff) ? 0 : 1; return 0; case 17: // 'cmpi' C = _dec_rdC (cpu->reg16, raw, 0, &rd); aluc = cpu->reg[rd] - C; cpu->CF = (aluc & 0x100) ? 1 : 0; cpu->ZF = (aluc & 0x0ff) ? 0 : 1; return 0; case 18: // 'test' rb = _dec_rdrb (cpu->reg16, raw, &rd); cpu->ZF = (cpu->reg[rd] & cpu->reg[rb]) ? 0 : 1; return 0; case 19: // 'testi' C = _dec_rdC (cpu->reg16, raw, 0, &rd); cpu->ZF = (cpu->reg[rd] & C) ? 0 : 1; return 0; case 20: rb = _dec_rdrb (cpu->reg16, raw, &rd); switch (raw & 0x3) { case 0: // 'ror' cpu->reg[rd] = (cpu->reg[rb] << 7) | (cpu->reg[rb] >> 1); cpu->ZF = cpu->reg[rd] ? 0 : 1; return 0; case 1: // 'rol' cpu->reg[rd] = (cpu->reg[rb] << 1) | (cpu->reg[rb] >> 7); cpu->ZF = cpu->reg[rd] ? 0 : 1; return 0; case 2: // 'rorc' C = (cpu->CF << 7) | (cpu->reg[rb] >> 1); cpu->CF = cpu->reg[rb] & 0x1; cpu->reg[rd] = C; cpu->ZF = cpu->reg[rd] ? 0 : 1; return 0; case 3: // 'rolc' C = (cpu->reg[rb] << 1) | cpu->CF; cpu->CF = cpu->reg[rb] >> 7; cpu->reg[rd] = C; cpu->ZF = cpu->reg[rd] ? 0 : 1; return 0; } break; case 22: switch (raw & 0x07) { case 0: // 'clrc' cpu->CF = 0; return 0; case 1: // 'setc' cpu->CF = 1; return 0; case 2: // 'clrz' cpu->ZF = 0; return 0; case 3: // 'setz' cpu->ZF = 1; return 0; case 4: // 'clri' cpu->IE = 0; return 0; case 5: // 'seti' cpu->IE = 1; return 0; case 6: // 'rcsr' switch ((raw >> 3) & 0x1f) { case 0: _dec_rdrb (cpu->reg16, raw, &rd); cpu->reg[rd] = cpu->IP; return 0; case 1: _dec_rdrb (cpu->reg16, raw, &rd); cpu->reg[rd] = cpu->IM; return 0; case 2: _dec_rdrb (cpu->reg16, raw, &rd); cpu->reg[rd] = cpu->IE; return 0; default: break; } break; case 7: // 'wcsr' switch ((raw >> 8) & 0x1f) { case 0: _dec_rdrb (cpu->reg16, raw, &rd); cpu->IP = cpu->reg[rd]; return 0; case 1: _dec_rdrb (cpu->reg16, raw, &rd); cpu->IM = cpu->reg[rd]; return 0; case 2: _dec_rdrb (cpu->reg16, raw, &rd); cpu->IE = cpu->reg[rd] ? 1 : 0; return 0; default: break; } break; } break; case 23: switch (raw & 0x03) { case 0: // 'export' / 'ssp' C = _dec_rdC (cpu->reg16, raw, 1, &rd); return _io_write (cpu, raw & 0x04, 0, C, rd); case 1: // 'import' / 'lsp' C = _dec_rdC (cpu->reg16, raw, 1, &rd); return _io_read (cpu, raw & 0x04, 0, C, rd); case 2: // 'exporti' / 'sspi' rb = _dec_rdrb (cpu->reg16, raw, &rd); return _io_write (cpu, raw & 0x04, 1, cpu->reg[rb], rd); case 3: // 'importi' / 'lspi' rb = _dec_rdrb (cpu->reg16, raw, &rd); return _io_read (cpu, raw & 0x04, 1, cpu->reg[rb], rd); } break; case 24: // 'bnz' / 'bz' if ((raw >> 12) & 0x01) { if (cpu->ZF) return 0; } else if (!cpu->ZF) return 0; return _branch (cpu, raw); case 25: // 'bnc' / 'bc' if ((raw >> 12) & 0x01) { if (cpu->CF) return 0; } else if (!cpu->CF) return 0; return _branch (cpu, raw); case 26: // 'callnz' / 'callz' if ((raw >> 12) & 0x01) { if (cpu->ZF) return 0; } else if (!cpu->ZF) return 0; return _pushcs (cpu, 1, raw); case 27: // 'callnc' / 'callc' if ((raw >> 12) & 0x01) { if (cpu->CF) return 0; } else if (!cpu->CF) return 0; return _pushcs (cpu, 1, raw); case 28: // 'ret' / 'call' if ((raw >> 12) & 0x01) return _popcs (cpu); return _pushcs (cpu, 1, raw); case 29: // 'b' / 'iret' if ((raw >> 12) & 0x01) return _branch (cpu, raw); cpu->CF = cpu->CFs; cpu->ZF = cpu->ZFs; cpu->IE = 1; return _popcs (cpu); default: break; } LOGERR ("UNKNOWN OP CODE (%d)0x%06x", op, raw); return 2; } #define UART_IRQ 0 typedef struct _st_lm8_uart { #define UART_FIFO_SIZE_LOG2 4 // 16 bytes uint8_t fifo[1 << UART_FIFO_SIZE_LOG2]; // incoming only int rd, wr, count; uint8_t ier; } lm8_uart_t; static lm8_uart_t console; static void console_init (void) { memset (&console, 0, sizeof (console)); console.ier = 0x00; } static uint8_t console_read (int offset) { uint8_t value; switch (offset) { case 0x00: // RHR if (!console.count) return 0x00; value = console.fifo[console.rd]; console.rd = console.rd & ~(sizeof (console.fifo) - 1); console.count--; return value; case 0x01: // IER return console.ier; case 0x02: // IIR if ((console.ier & 0x01) && console.count) return 0x04; else if (console.ier & 0x02) return 0x02; else return 0x01; case 0x03: // LCR return 0x03; // always N81 case 0x05: // LSR value = (1 << 6) | // Both THR & TSR empty (1 << 5) | // THR empty (0 << 4) | // Break interrupt flag (0 << 3) | // Framing error (0 << 2) | // Parity error (0 << 1); // Overrun error if (console.count) value |= 1; // Receiver ready return value; default: break; } return 0; } static void console_write (int offset, uint8_t value) { switch (offset) { case 0x00: // THR write (2, &value, 1); break; case 0x01: // IER console.ier = value & 0x03; break; } return; } static uint8_t _wb_read (void *context, int sp, uint32_t address) { if (!sp) address |= 0x80000000; if ((address & 0xfffffff8) == 0x80000000) { return console_read (address & 0x07); } switch (address) { default: break; } LOGERR("WB READ @ %08x\n", address); exit (1); } static void _wb_write (void *context, int sp, uint32_t address, uint8_t value) { if (!sp) address |= 0x80000000; if ((address & 0xfffffff8) == 0x80000000) { return console_write (address & 0x07, value); } switch (address) { default: break; } LOGERR("WB WRITE @ %08x = %02x\n", address, value); exit (1); } static void handle_sigint (int sig) { (void) sig; done = 1; return; } int main (int argc, char *argv[]) { const char *prom_file = NULL, *sp_file = NULL; struct termios stdin_parms, old_state; argc--; argv++; while (argc) { if (!strcmp (argv[0], "-v") || !strcmp (argv[0], "--verbose")) { verbose++; } else if (!prom_file) { prom_file = argv[0]; } else if (!sp_file) { sp_file = argv[0]; } else { } argc--; argv++; } signal (SIGINT, handle_sigint); lm8_cpu_t *cpu; cpu = lm8_new (LM8_MEDIUM, 16, 1, _wb_read, _wb_write, NULL, prom_file, 1024, sp_file); if (!cpu) return -1; memset (&stdin_parms, 0, sizeof (struct termios)); tcgetattr (0, &stdin_parms); old_state = stdin_parms; stdin_parms.c_iflag &= ~(BRKINT | ICRNL | IXON); stdin_parms.c_lflag &= ~(ICANON | ECHO | FLUSHO); tcsetattr (0, TCSANOW, &stdin_parms); fcntl (0, F_SETFL, O_NONBLOCK); console_init (); while (!done) { if (lm8_step (cpu)) break; if ((console.count < sizeof (console.fifo)) && (read (0, &console.fifo[console.wr], 1) == 1)) { console.wr = (console.wr + 1) & ~(sizeof(console.fifo) - 1); console.count++; } if ( (console.ier & 0x02) || ((console.ier & 0x01) && console.count)) cpu->IP |= (1 << UART_IRQ); } lm8_close (cpu); tcsetattr (0, TCSANOW, &old_state); printf ("\n"); return 0; }