/* * sc.c -- sc61860 emulator * * Copyright (C) 1994 by Dai Ishijima */ #include #include "pocket.h" #define YES 1 #define NO 0 /* sc61860 registers */ static unsigned short pc, dp; static unsigned char preg, qreg, rreg, dreg; static unsigned short alu; static unsigned char cflag, zflag; static unsigned char xin = 0; static unsigned char opcode; static unsigned short ticks, ticks2; static unsigned char div500, div2; unsigned char power_on; unsigned char disp_on; #define hi(x) ((x) >> 8) #define lo(x) ((x) & 0xff) #define pair(h,l) (((h) << 8) | (l)) #define pairload(h,l,v) h=hi(v); l=lo(v) #define XTICKS 500 #define XTICK2 500 #define IRAMSIZ (0x5f+1) static unsigned char iram[IRAMSIZ]; #define ireg iram[0] #define jreg iram[1] #define areg iram[2] #define breg iram[3] #define xlreg iram[4] #define xhreg iram[5] #define ylreg iram[6] #define yhreg iram[7] #define kreg iram[8] #define lreg iram[9] #define mreg iram[10] #define nreg iram[11] #define bareg (pair(iram[3], iram[2])) #define xreg (pair(iram[5], iram[4])) #define yreg (pair(iram[7], iram[6])) #define ia iram[0x5c] #define ib iram[0x5d] #define fo iram[0x5e] #define ctrl iram[0x5f] static unsigned char iaport, ibport, foport, ctrlport; static unsigned char testport; #define PCEOF 032 /* ^Z */ #define BYTEOUT 1 #define BYTEIN 2 #define ESCAPE 0x3f #define RTN 0x37 #ifdef FREQ static unsigned int opfreq[256]; static FILE *fp; #endif #define swap(a,b) {unsigned char _swpc; _swpc=a; a=b; b=_swpc;} /*#define memr(adr) ((adr < 0x2000) ? (hi(adr)) : mainram[adr])*/ #define memr(adr) (mainram[adr]) /* * memory write */ void memw(adr, dat) int adr; int dat; { if ((0x2000 <= adr) && (adr <= 0x7fff)) { mainram[adr] = dat; } else { fprintf(stderr, "???\n"); power_on = NO; } /* if (a & 0x7000 == 0x7000) { if ((0x7000 <= adr) && (adr <= 0x703b)) { display(adr); } if ((0x7068 <= adr) && (adr <= 0x707b)) { display(adr); } if (adr == 0x703c || adr == 0x703d || adr == 0x707c) { symbol(adr); } } */} /* * operations */ /* secret */ static void mvwp() /* 35 */ { --pc ; dreg = ireg+ 1; iram[--rreg] = hi(pc); iram[--rreg] = lo(pc); pc = bareg; do { iram[preg++] = mainram[pc++]; --dreg; } while (dreg != 0); pc = pair(iram[rreg + 1], iram[rreg]) + 1; rreg += 2; } static void tsma() /* C6 */ { zflag = (iram[preg] & areg) == 0; } static void clra() /* 23 */ { areg = 0; } static void mvmp() /* 54 */ { iram[preg] = mainram[pc]; } static void ldpc() /* 56 */ { areg = mainram[pc]; } static void sz() /* D7 */ { iram[rreg - 1] = memr(dp); ++pc; zflag = YES; } static void rz() /* 72 73 76 77 */ { ++pc; zflag = NO; } /* 8bits load */ static void ldp() { areg = preg; } static void ldq() { areg = qreg; } static void ldr() { areg = rreg; } static void ldm() { areg = iram[preg]; } static void ldd() { areg = memr(dp); } static void lia() { areg = mainram[pc++]; } static void lib() { breg= mainram[pc++]; } static void lij() { jreg= mainram[pc++]; } static void lii() { ireg= mainram[pc++]; } static void lip() { preg = mainram[pc++]; } static void lp() { preg = opcode & 0x3f; } static void stp() { preg = areg; } static void stq() { qreg = areg; } static void liq() { qreg = mainram[pc++]; } static void str() { rreg = areg; } static void lidl() { dp = (dp & 0xff00) | mainram[pc++]; } static void std() { memw(dp, areg); } static void mvdm() { memw(dp, iram[preg]); } static void mvmd() { iram[preg] = memr(dp); } static void leave() { iram[rreg] = 0; } static void pop() { areg = iram[rreg++]; } static void push() { iram[--rreg] = areg; } /* 16bits load */ static void lidp() { dp = pair(mainram[pc], mainram[pc + 1]); pc += 2; } /* block load, exchange */ static void mvb() { dreg = jreg+ 1; do { iram[preg++] = iram[qreg++]; --dreg; } while (dreg != 0); } static void mvw() { dreg = ireg+ 1; do { iram[preg++] = iram[qreg++]; --dreg; } while (dreg != 0); } static void mvbd() { dreg = jreg+ 1; do { iram[preg++] = memr(dp); dp++; --dreg; } while (dreg != 0); } static void mvwd() { dreg = ireg+ 1; do { iram[preg++] = memr(dp); dp++; --dreg; } while (dreg != 0); } static void film() { dreg = ireg+ 1; do { iram[preg++] = areg; --dreg; } while (dreg != 0); } static void fild() { dreg = ireg+ 1; do { memw(dp++, areg); --dreg; } while (dreg != 0); } static void exab() { swap(areg, breg); } static void exam() { swap(areg, iram[preg]); } static void exb() { dreg = jreg+ 1; do { swap(iram[preg], iram[qreg]); preg++; qreg++; --dreg; } while (dreg != 0); } static void exw() { dreg = ireg+ 1; do { swap(iram[preg], iram[qreg]); preg++; qreg++; --dreg; } while (dreg != 0); } static void exwd() { unsigned char tmp; dreg = ireg+ 1; do { tmp = memr(dp); memw(dp, iram[preg]); iram[preg] = tmp; preg++; dp++; --dreg; } while (dreg != 0); } static void exbd() { int tmp; dreg = jreg+ 1; do { tmp = memr(dp); memw(dp, iram[preg]); iram[preg] = tmp; preg++; dp++; --dreg; } while (dreg!= 0); } static void swp() { areg = (areg << 4) | (areg >> 4); } static void chkcz() { zflag = (alu & 0x00ff) == 0; cflag = (alu & 0xff00) != 0; } /* 8bits */ static void adia() { alu = areg + mainram[pc++]; areg = alu; chkcz(); } static void adim() { alu = iram[preg] + mainram[pc++]; iram[preg] = alu; chkcz(); } static void adm() { alu = iram[preg] + areg; iram[preg] = alu; chkcz(); } static void adcm() { alu = iram[preg] + areg + cflag; iram[preg] = alu; chkcz(); } static void sbia() { alu = areg - mainram[pc++]; areg = alu; chkcz(); } static void sbim() { alu = iram[preg] - mainram[pc++]; iram[preg] = alu; chkcz(); } static void sbm() { alu = iram[preg] - areg; iram[preg] = alu; chkcz(); } static void sbcm() { alu = iram[preg] - areg - cflag; iram[preg] = alu; chkcz(); } static void inca() { qreg= 2; alu = areg + 1; areg = alu; chkcz(); } static void incb() { qreg= 3; alu = breg+ 1; breg= alu; chkcz(); } static void inci() { qreg= 0; alu = ireg+ 1; ireg= alu; chkcz(); } static void incj() { qreg= 1; alu = jreg+ 1; jreg= alu; chkcz(); } static void inck() { qreg= 8; alu = kreg + 1; kreg = alu; chkcz(); } static void incl() { qreg= 9; alu = lreg + 1; lreg = alu; chkcz(); } static void incm() { qreg= 10; alu = mreg+ 1; mreg= alu; chkcz(); } static void incn() { qreg= 11; alu = nreg + 1; nreg = alu; chkcz(); } static void incp() { ++preg; } static void deca() { qreg= 2; alu = areg - 1; areg = alu; chkcz(); } static void decb() { qreg= 3; alu = breg- 1; breg= alu; chkcz(); } static void deci() { qreg= 0; alu = ireg- 1; ireg= alu; chkcz(); } static void decj() { qreg= 1; alu = jreg- 1; jreg= alu; chkcz(); } static void deck() { qreg= 8; alu = kreg - 1; kreg = alu; chkcz(); } static void decl() { qreg= 9; alu = lreg - 1; lreg = alu; chkcz(); } static void decm() { qreg= 10; alu = mreg - 1; mreg = alu; chkcz(); } static void decn() { qreg= 11; alu = nreg - 1; nreg = alu; chkcz(); } static void decp() { --preg; } static void ania() { zflag = (areg &= mainram[pc++]) == 0; } static void anma() { zflag = (iram[preg] &= areg) == 0; } static void anim() { zflag = (iram[preg] &= mainram[pc++]) == 0; } static void anid() { iram[rreg - 1] = memr(dp); memw(dp, memr(dp) & mainram[pc++]); zflag = (memr(dp) == 0); } static void oria() { zflag = (areg |= mainram[pc++]) == 0; } static void orma() { zflag = (iram[preg] |= areg) == 0; } static void orim() { zflag = (iram[preg] |= mainram[pc++]) == 0; } static void orid() { iram[rreg - 1] = memr(dp); memw(dp, memr(dp) | mainram[pc++]); zflag = (memr(dp) == 0); } static void cpia() { alu = areg - mainram[pc++]; chkcz(); } static void cpma() { alu = iram[preg] - areg; chkcz(); } static void cpim() { alu = iram[preg] - mainram[pc++]; chkcz(); } /* 16bits */ static void adb() { unsigned long xx; xx = iram[preg] | (iram[preg + 1] << 8); xx += bareg; iram[preg] = xx; iram[++preg] = xx >> 8; zflag = (xx & 0x0000ffffL) == 0; cflag = (xx & 0xffff0000L) != 0; } static void sbb() { unsigned long xx; xx = iram[preg] | (iram[preg + 1] << 8); xx -= bareg; iram[preg] = xx; iram[++preg] = xx >> 8; zflag = (xx & 0x0000ffffL) == 0; cflag = (xx & 0xffff0000L) != 0; } /* inc/dec load/store */ static void ix() { qreg= 5; dp = xreg + 1; pairload(xhreg, xlreg, dp); } static void iy() { qreg= 7; dp = yreg + 1; pairload(yhreg, ylreg, dp); } static void dx() { qreg= 5; dp = xreg - 1; pairload(xhreg, xlreg, dp); } static void dy() { qreg= 7; dp = yreg - 1; pairload(yhreg, ylreg, dp); } static void ixl() { qreg= 5; dp = xreg + 1; areg = memr(dp); pairload(xhreg, xlreg, dp); } static void iys() { qreg= 7; memw(dp = yreg + 1, areg); pairload(yhreg, ylreg, dp); } static void dxl() { qreg= 5; dp = xreg - 1; areg = memr(dp); pairload(xhreg, xlreg, dp); } static void dys() { qreg= 7; memw(dp = yreg - 1, areg); pairload(yhreg, ylreg, dp); } /* rotate / shift */ static void sr() { alu = areg | (cflag << 8); areg = alu >> 1; cflag = alu & 1; } static void sl() { alu = (areg << 1) | cflag; areg = alu; cflag = (alu & 0x0100) != 0; } static void srw() { dreg= ireg+ 1; alu = 0; do { alu = (alu << 8) | iram[preg]; iram[preg] = alu >> 4; ++preg; --dreg; } while (dreg!= 0); } static void slw() { dreg= ireg+ 1; alu = 0; do { alu = (alu >> 8) | (iram[preg] << 8); iram[preg] = (alu >> 4); --preg; --dreg; } while (dreg!= 0); } /* bit test */ static void tsia() { zflag = (areg & mainram[pc++]) == 0; } static void tsim() { zflag = (iram[preg] & mainram[pc++]) == 0; } static void tsid() { iram[rreg - 1] = memr(dp); zflag = (memr(dp) & mainram[pc++]) == 0; } static void cup() { dreg= ireg+ 1; zflag = NO; if (xin == 0) { do { ++preg; --dreg; } while ((!xin) && (dreg!= 0xff)); if (xin == 0) { zflag = YES; } } } static void cdn() { dreg= ireg+ 1; zflag = NO; if (xin) { do { ++preg; --dreg; } while (xin && (dreg!= 0xff)); if (xin) { zflag = YES; } } } unsigned int deciadd(p, q) unsigned int p; unsigned int q; { unsigned int ans; ans = (p & 0x0f) + (q & 0x0f); if (ans > 0x09) { ans += 6; } ans += (p & 0xf0) + (q & 0xf0); if ((ans & 0xfff0) > 0x90) { ans += 0x60; } return(ans & 0x1ff); } unsigned int decisub(p, q) unsigned int p; unsigned int q; { unsigned int ans; ans = (p & 0x0f) - (q & 0x0f); if (ans > 0x09) { ans -= 0x06; } ans += (p & 0xf0) - (q & 0xf0); if ((ans & 0xfff0) > 0x90) { ans -= 0x60; } return(ans & 0x1ff); } static void adn() { dreg = ireg+ 1; alu = areg; zflag = YES; do { alu = deciadd(iram[preg], alu); iram[preg] = alu; zflag = zflag && (iram[preg] == 0); --preg; --dreg; alu >>= 8; } while (dreg != 0); cflag = (alu != 0); } static void sbn() { dreg = ireg+ 1; alu = areg; zflag = YES; do { alu = decisub(iram[preg], alu); iram[preg] = alu; zflag = zflag && (iram[preg] == 0); --preg; --dreg; alu >>= 8; } while (dreg != 0); cflag = (alu != 0); } static void adw() { dreg = ireg+ 1; alu = 0; zflag = YES; do { alu = deciadd(iram[preg], alu); alu = (alu & 0x100) | deciadd(alu & 0xff, iram[qreg]); iram[preg] = alu; zflag = zflag && (iram[preg] == 0); --preg; --qreg; --dreg; alu >>= 8; } while (dreg != 0); cflag = (alu != 0); } static void sbw() { dreg = ireg+ 1; alu = 0; zflag = YES; do { alu = decisub(iram[preg], alu); alu = (alu & 0x100) | decisub(alu & 0xff, iram[qreg]); iram[preg] = alu; zflag = zflag && (iram[preg] == 0); --preg; --qreg; --dreg; alu >>= 8; } while (dreg != 0); cflag = (alu != 0); } /* jumps */ static void jrp() { pc += mainram[pc]; } static void jrm() { pc -= mainram[pc]; } static void jrzp() { pc += (zflag) ? mainram[pc] : 1; } static void jrzm() { pc += (zflag) ? -mainram[pc] : 1; } static void jrnzp() { pc += (!zflag) ? mainram[pc] : 1; } static void jrnzm() { pc += (!zflag) ? -mainram[pc] : 1; } static void jrcp() { pc += (cflag) ? mainram[pc] : 1; } static void jrcm() { pc += (cflag) ? -mainram[pc] : 1; } static void jrncp() { pc += (!cflag) ? mainram[pc] : 1; } static void jrncm() { pc += (!cflag) ? -mainram[pc] : 1; } static void jp() { pc = (mainram[pc] << 8) | mainram[pc + 1]; } static void jpz() { pc = (zflag) ? ((mainram[pc] << 8) | mainram[pc + 1]) : pc + 2; } static void jpnz() { pc = (!zflag) ? ((mainram[pc] << 8) | mainram[pc + 1]) : pc + 2; } static void jpc() { pc = (cflag) ? ((mainram[pc] << 8) | mainram[pc + 1]) : pc + 2; } static void jpnc() { pc = (!cflag) ? ((mainram[pc] << 8) | mainram[pc + 1]) : pc + 2; } static void loop() { alu = iram[rreg]; --alu; iram[rreg] = alu; chkcz(); if (cflag) { ++pc; } else { pc -= mainram[pc]; } } static void case1() { dreg = mainram[pc++]; iram[--rreg] = mainram[pc++]; iram[--rreg] = mainram[pc++]; } static void case2() { /* zflag = NO;*/ do { if (areg == mainram[pc++]) { pc = (mainram[pc] << 8) + mainram[pc + 1]; /* zflag = YES;*/ break; } else { pc += 2; } --dreg; } while (dreg != 0); if (dreg == 0) { pc = (mainram[pc] << 8) | mainram[pc + 1]; } } static void cal() { ++pc; iram[--rreg] = hi(pc); iram[--rreg] = lo(pc); pc = ((opcode & 0x1F) << 8) | mainram[pc - 1]; } static void call() { pc += 2; iram[--rreg] = hi(pc); iram[--rreg] = lo(pc); pc = (mainram[pc - 2] << 8) | mainram[pc - 1]; } static void rtn() { pc = pair(iram[rreg + 1], iram[rreg]); rreg += 2; } static void outa() { static int cnt = 0; static int ch; if ((iaport != 0) && (ia == 0)) { ++cnt; if (cnt > 2) { if (power_on) { ch = getkey(); } else { ch = getchar(); } if (ch > 0) { keyscan(ch); } else { keyscan(0); } cnt = 0; } } qreg= 0x5c; iaport = ia; } static void outb() { qreg= 0x5d; ibport = ib; } static void outf() { qreg= 0x5e; foport = fo; } static void outc() { qreg= 0x5f; disp_on = (ctrl & 1); if (!disp_on) { busy(); } if (ctrl & 2) { ticks = ticks2 = div500 = div2 = 0; } power_on = !(ctrl & 8); } int bit(ii) int ii; { int jj; for (jj= 0; jj < 8; jj++) { if (ii & 1) { break; } ii >>= 1; } return(jj); } static void ina() { int ii, jj, kk; areg = 0; if ((iaport == 0) && (mainram[0x7e00] != 0)) { jj = bit(mainram[0x7e00]); if (jj < 7) { areg = keym[jj]; } } else { jj = bit(iaport); if (jj < 7) { areg = keym[jj + 7]; } } zflag = (areg == 0); } static void inb() { areg = 0x38; zflag = (areg == 0); } static void sc() { cflag = zflag = YES; } static void rc() { cflag = NO; zflag = YES; } static void nop() { } static void wait() { ++pc; } static void test() { testport = 0; if (div2) { testport |= 1; } if (div500) { testport |= 2; } if (kon) { testport |= 8; } zflag = (testport & mainram[pc++]) == 0; } /* undefined code */ static void undef() { fprintf(stderr, "Undefined code: %04x %02x\n", pc - 1, opcode); exit(1); } static void escape() { int code; static FILE *ofp = NULL; static FILE *ifp = NULL; int ch; code = mainram[pc++]; if (code == BYTEOUT) { if (ofp == NULL) { ofp = fopen("sc.out", "w"); } ch = areg; if (ch == '\r') { ch = '\n'; } if (ch == PCEOF) { fclose(ofp); ofp = NULL; } else { putc(ch, ofp); } } else if (code == BYTEIN) { if (ifp == NULL) { ifp = fopen("sc.inp", "r"); } if (ifp != NULL) { if ((ch = getc(ifp)) == EOF) { fclose(ifp); ifp = NULL; areg = PCEOF; iram[0x0e] |= 0x80; } else if (ch == '\n') { areg = '\r'; iram[0x0e] |= 0x40; } else { areg = ch; iram[0x0e] &= 0x3f; } } else { areg = PCEOF; iram[0x0e] |= 0x80; } /* putchar(areg);*/ cflag = NO; zflag = NO; preg = 0x0e; } else { fprintf(stderr, "escape: %04x %02x\n", pc - 1, code); } } typedef void (*op)(); static op ops[] = { /* +0 +1 +2 +3 +4 +5 +6 +7 */ lii, lij, lia, lib, ix, dx, iy, dy, /* 0 */ mvw, exw, mvb, exb, adn, sbn, adw, sbw, lidp, lidl, lip, liq, adb, sbb, undef, undef, /* 1 */ mvwd, exwd, mvbd, exbd, srw, slw, film, fild, ldp, ldq, ldr, clra, ixl, dxl, iys, dys, /* 2 */ jrnzp, jrnzm, jrncp, jrncm, jrp, jrm, undef, loop, stp, stq, str, nop, push, mvwp, undef, rtn, /* 3 */ jrzp, jrzm, jrcp, jrcm, undef, undef, undef, escape, inci, deci, inca, deca, adm, sbm, anma, orma, /* 4 */ inck, deck, incm, decm, ina, nop, wait, cup, incp, decp, std, mvdm, mvmp, mvmd, ldpc, ldd, /* 5 */ swp, ldm, sl, pop, undef, outa, undef, outf, anim, orim, tsim, cpim, ania, oria, tsia, cpia, /* 6 */ nop, case2, nop, test, undef, undef, undef, cdn, adim, sbim, rz, rz, adia, sbia, rz, rz, /* 7 */ call, jp, case1, undef, jpnz, jpnc, jpz, jpc, /* +0 +1 +2 +3 +4 +5 +6 +7 */ lp, lp, lp, lp, lp, lp, lp, lp, /* 8 */ lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, /* 9 */ lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, /* A */ lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, lp, /* B */ lp, lp, lp, lp, lp, lp, lp, lp, incj, decj, incb, decb, adcm, sbcm, tsma, cpma, /* C */ incl, decl, incn, decn, inb, nop, nop, undef, sc, rc, sr, nop, anid, orid, tsid, sz, /* D */ leave, nop, exab, exam, undef, outb, undef, outc, cal, cal, cal, cal, cal, cal, cal, cal, /* E */ cal, cal, cal, cal, cal, cal, cal, cal, cal, cal, cal, cal, cal, cal, cal, cal, /* F */ cal, cal, cal, cal, cal, cal, cal, cal, /* +0 +1 +2 +3 +4 +5 +6 +7 */ }; void tictac() { if (++ticks >= XTICKS) { div500 = !div500; if (++ticks2 >= XTICK2) { div2 = !div2; ticks2 = 0; } ticks = 0; } } int interpret() { tictac(); opcode = mainram[pc++]; #ifdef FREQ ++opfreq[opcode]; #endif (*ops[opcode])(); return(pc); } int islcd() { return(hi(dp) == 0x70); } void initsc() { pc = dp = 0; preg = qreg= 0; rreg = IRAMSIZ; cflag = zflag = NO; ticks = 0; power_on = YES; kon = 0; iaport = ibport = foport = 0; mainram[0xed34] = ESCAPE; mainram[0xed35] = BYTEOUT; mainram[0xed36] = 0x37; mainram[0xec2e] = ESCAPE; mainram[0xec2f] = BYTEIN; mainram[0xec30] = 0x37; mainram[0xeaa8] = 0xd0; mainram[0xeaa9] = 0x37; #ifdef FREQ { int i; for (i = 0; i < 256; i++) { opfreq[i] = 0; } } #endif } closesc() { #ifdef FREQ int i; fp = fopen("opfreq", "w"); for (i = 0; i < 256; i++) { fprintf(fp, "%d\n", opfreq[i]); } #endif } scstatus() { int xx; printf("PC P Q R DP "); printf("I J A B XL XH YL YH K L M N C Z\r\n"); printf("%04x %02x %02x %02x %04x ", pc, preg, qreg, rreg, dp); for (xx = 0; xx < 12; xx++) { printf("%02x ", iram[xx]); } printf(" %2x %2x", cflag, zflag); putchar('\r'); putchar('\n'); }