/* * Copyright (c) 2018, 2022 Lars Brinkhoff * * 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, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the names of the authors shall * not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization * from the authors. */ #include #include #include "display.h" /* XY plot interface */ #include "ng.h" /* Bits in the CSR register, type Dazzle. */ #define TKRUN 004000 #define TKGO 010000 #define TKSTOP 020000 /* Number of displays. */ #define DISPLAYS 8 static void *ng_dptr; static int ng_dbit; #if defined(__cplusplus) extern "C" { #endif #define DEVICE void extern void _sim_debug_device (unsigned int dbits, DEVICE* dptr, const char* fmt, ...); #define DEBUGF(...) _sim_debug_device (ng_dbit, ng_dptr, ## __VA_ARGS__) #if defined(__cplusplus) } #endif int ng_type = 0; int ng_scale = PIX_SCALE; static uint16 status[DISPLAYS]; static int reloc = 0; static int console = 0; static int dpc[DISPLAYS]; static int x[DISPLAYS]; static int y[DISPLAYS]; static unsigned char sync_period = 0; static unsigned char time_out = 0; int32 ng_get_csr(void) { if (ng_type == TYPE_DAZZLE) { DEBUGF("[%d] Get CSR: ", 0); if (status[console] & TKRUN) DEBUGF("running\n"); else DEBUGF("stopped\n"); return status[console]; } else if (ng_type == TYPE_LOGO) { DEBUGF("Get CSR: %06o\n", status[0]); return status[0]; } return 0; } int32 ng_get_reloc(void) { return reloc & 0177777; } void ng_set_csr(uint16 d) { if (ng_type == TYPE_DAZZLE) { console = d & 0377; if (d & TKGO) { DEBUGF("[%d] Set CSR: GO\n", console); if ((status[console] & TKRUN) == 0) dpc[console] = 2*console; status[console] = TKRUN | console; } if (d & TKSTOP) { DEBUGF("[%d] Set CSR: STOP\n", console); status[console] = console; } } else if (ng_type == TYPE_LOGO) { DEBUGF("Set CSR: %06o\n", d); if ((status[0] & 1) == 0 && (d & 1)) dpc[0] = 2*0; status[0] = d; } } void ng_set_reloc(uint16 d) { reloc = d; DEBUGF("Set REL: %06o\n", d); } int ng_init(void *dev, int debug) { /* Don't change this number. */ assert (DISPLAYS == 8); ng_dptr = dev; ng_dbit = debug; memset (status, 0, sizeof status); return display_init(DIS_NG, ng_scale, ng_dptr); } static int fetch (int a, uint16 *x) { return ng_fetch (a + reloc, x); } static int store (int a, uint16 x) { return ng_store (a + reloc, x); } static void point (void) { int x1 = x[console]; int y1 = y[console]; DEBUGF("[%d] POINT %d %d\n", console, x[console], y[console]); display_point(x1 + 256, y1 + 256, DISPLAY_INT_MAX, 0); } void increment (uint16 inst) { int n = (inst >> 8) & 7; int i, mask; if (n == 0) n = 8; DEBUGF("[%d] Increment %d, direction %d, bits %o\n", console, n, (inst >> 11) & 7, inst & 0377); mask = 0200; if (ng_type == TYPE_DAZZLE) mask = 0200 >> (8 - n); for (i = 0; i < n; i++, mask >>= 1) { switch (inst & 034000) { case 000000: if (inst & mask) x[console]++; y[console]++; break; case 004000: if (inst & mask) y[console]++; x[console]++; break; case 010000: if (inst & mask) y[console]--; x[console]++; break; case 014000: if (inst & mask) x[console]++; y[console]--; break; case 020000: if (inst & mask) x[console]--; y[console]--; break; case 024000: if (inst & mask) y[console]--; x[console]--; break; case 030000: if (inst & mask) y[console]++; x[console]--; break; case 034000: if (inst & mask) x[console]--; y[console]++; break; } point (); } } void pushj (uint16 inst) { uint16 a; fetch (16 + 2*console, &a); store (16 + 2*console, a + 1); store (2*a, dpc[console]); DEBUGF("[%d] PUSHJ %06o -> %06o (%06o->%06o)\n", console, dpc[console], inst << 1, a, a+1); dpc[console] = inst << 1; } void stop (void) { DEBUGF("[%d] STOP\n", console); if (ng_type == TYPE_DAZZLE) status[console] &= ~TKRUN; else if (ng_type == TYPE_LOGO) dpc[0] = 2*0; } uint16 pop (void) { uint16 a; fetch (16 + 2*console, &a); store (16 + 2*console, a - 1); DEBUGF("[%d] POP (%06o -> %06o)\n", console, a, a - 1); return a - 1; } void popj (void) { uint16 a, x; a = pop (); fetch (2*a, &x); DEBUGF("[%d] POPJ %06o -> %06o\n", console, dpc[console], x); dpc[console] = x; } void resetx (void) { DEBUGF("[%d] RESET X\n", console); x[console] = 0; } void resety (void) { DEBUGF("[%d] RESET Y\n", console); y[console] = 0; } void delta (uint16 inst) { int delta = inst & 01777; if (inst & 01000) delta |= ~0u << 10; switch (inst & 014000) { case 000000: if (inst & 02000) resetx (); if (inst & 01000) resety (); if (inst & 00400) stop (); if (inst & 00200) pop (); if (inst & 00100) popj (); return; case 004000: y[console] += delta; break; case 010000: x[console] += delta; break; case 014000: x[console] += delta; y[console] += delta; break; } DEBUGF("[%d] DELTA %d\n", console, delta); if (inst & 02000) { point (); } } int ng_cycle(int us, int slowdown) { uint16 inst; static uint32 usec = 0; static uint32 msec = 0; uint32 new_msec; int running = 0; int saved; new_msec = (usec += us) / 1000; /* if awaiting sync, look for next frame start */ if (sync_period && (msec / sync_period != new_msec / sync_period)) sync_period = 0; /* start next frame */ msec = new_msec; if (ng_type == TYPE_LOGO) { DEBUGF("LOGO/STATUS %06o\n", status[0]); if ((status[0] & 1) == 0) goto age_ret; } else if (ng_type != TYPE_DAZZLE) return 0; if (sync_period) goto age_ret; saved = console; for (console = 0; console < 1; console++) { if (ng_type == TYPE_DAZZLE && (status[console] & TKRUN) == 0) continue; running = 1; time_out = fetch(dpc[console], &inst); DEBUGF("[%d] PC %06o, INSTR %06o\n", console, dpc[console], inst); dpc[console] += 2; switch (inst & 0160000) { case 0040000: case 0060000: increment (inst); break; case 0100000: case 0120000: pushj (inst & 037777); break; case 0140000: delta (inst); break; } } console = saved; age_ret: display_age(us, slowdown); return running || !display_is_blank(); }