Can now boot the last test programs from floppy, and runs INSTRUCTION-C and PAGING-C without errors.
358 lines
14 KiB
C
358 lines
14 KiB
C
/*
|
|
* Copyright (c) 2023 Anders Magnusson.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "sim_defs.h"
|
|
|
|
#include "nd100_defs.h"
|
|
|
|
char sim_name[] = "ND100";
|
|
|
|
extern REG cpu_reg[];
|
|
REG *sim_PC = &cpu_reg[8];
|
|
int32 sim_emax = 1;
|
|
|
|
DEVICE *sim_devices[] = {
|
|
&cpu_dev,
|
|
&mm_dev,
|
|
&tti_dev,
|
|
&tto_dev,
|
|
&floppy_dev,
|
|
&clk_dev,
|
|
NULL
|
|
};
|
|
|
|
const char *sim_stop_messages[SCPE_BASE] = {
|
|
"Unknown error",
|
|
"Unhandled IOX address",
|
|
"Unknown instruction",
|
|
"Checksum error",
|
|
"Simulator breakpoint",
|
|
"Wait at level 0",
|
|
"manual end",
|
|
};
|
|
|
|
static int mlp;
|
|
|
|
static int
|
|
gb(FILE *f)
|
|
{
|
|
int w;
|
|
|
|
if (f == NULL)
|
|
return prdmem(mlp++, PM_CPU);
|
|
w = getc(f) & 0377;
|
|
return w;
|
|
}
|
|
|
|
static int
|
|
gw(FILE *f)
|
|
{
|
|
int c = gb(f);
|
|
return (c << 8) | gb(f);
|
|
}
|
|
|
|
|
|
/*
|
|
* Bootable (BPUN) tape format.
|
|
* Disks can use it as well with a max of 64 words data. In this case
|
|
* the bytes are stored in the LSB of the words from beginning of disk.
|
|
* 1kw block should be read at address 0 in memory.
|
|
*
|
|
* A bootable tape consists of nine segments, named A-I.
|
|
*
|
|
* A - Any chars not including '!'
|
|
* B - (optional) octal number terminated by CR (LF ignored).
|
|
* C - (optional) octal number terminated by '!'.
|
|
* D - A '!' delimeter
|
|
* E - Block start address (in memory), two byte, MSB first.
|
|
* F - Word count in G section, two byte, MSB first.
|
|
* G - Words as counted in F section.
|
|
* H - Checksum of G section, one word.
|
|
* I - Action code. If non-zero, start at address in B, otherwise nothing.
|
|
*/
|
|
|
|
t_stat
|
|
sim_load(FILE *f, CONST char *buf, CONST char *fnam, t_bool flag)
|
|
{
|
|
int B, C, E, F, H, I;
|
|
int w, i, rv;
|
|
uint16 s;
|
|
|
|
rv = SCPE_OK;
|
|
if (sim_switches & SWMASK('D')) { /* read file from disk */
|
|
mlp = 0;
|
|
for (i = 0; i < 1024; i++) {
|
|
/* images have MSB first */
|
|
s = (getc(f) & 0377) << 8;
|
|
s |= getc(f) & 0377;
|
|
pwrmem(i, s, PM_CPU);
|
|
}
|
|
f = NULL;
|
|
}
|
|
|
|
/* read B/C section */
|
|
for (B = C = 0;(w = gb(f) & 0177) != '!'; ) {
|
|
switch (w) {
|
|
case '\n':
|
|
continue;
|
|
case '\r':
|
|
B = C, C = 0;
|
|
break;
|
|
case '0': case '1': case '2': case '3':
|
|
case '4': case '5': case '6': case '7':
|
|
C = (C << 3) | (w - '0');
|
|
break;
|
|
default:
|
|
B = C = 0;
|
|
}
|
|
}
|
|
printf("B address %06o\n", B);
|
|
printf("C address %06o\n", C);
|
|
regP = B;
|
|
printf("Load address %06o\n", E = gw(f));
|
|
printf("Word count %06o\n", F = gw(f));
|
|
for (i = s = 0; i < F; i++) {
|
|
pwrmem(E+i, gw(f), PM_CPU);
|
|
s += prdmem(E+i, PM_CPU);
|
|
}
|
|
printf("Checksum %06o\n", H = gw(f));
|
|
if (H != s)
|
|
rv = STOP_CKSUM;
|
|
printf("Execute %06o\n", I = gw(f));
|
|
printf("Words read %06o\n", i);
|
|
ald = 0300; /* from tape reader */
|
|
return rv;
|
|
}
|
|
|
|
static char *nd_mem[] = {
|
|
"stz", "sta", "stt", "stx", "std", "ldd", "stf", "ldf",
|
|
"min", "lda", "ldt", "ldx", "add", "sub", "and", "ora",
|
|
"fad", "fsb", "fmu", "fdv", "mpy", "jmp", "cjp", "jpl",
|
|
"skp", "rop", "mis", "sht", "N/A", "iox", "arg", "bop"
|
|
};
|
|
|
|
static char *jptab[] =
|
|
{ "jap", "jan", "jaz", "jaf", "jpc", "jnc", "jxz", "jxn" };
|
|
|
|
static char *argtab[] =
|
|
{ "sab", "saa", "sat", "sax", "aab", "aaa", "aat", "aax" };
|
|
|
|
static char *boptab[] = {
|
|
"bset zro", "bset one", "bset bcm", "bset bac",
|
|
"bskp zro", "bskp one", "bskp bcm", "bskp bac",
|
|
"bstc", "bsta", "bldc", "blda", "banc", "band", "borc", "bora",
|
|
};
|
|
|
|
static char *dactab[] = { "", "d", "p", "b", "l", "a", "t", "x" };
|
|
|
|
static char *skptab[] = {
|
|
"eql", "geq", "gre", "mgre", "ueq", "lss", "lst", "mlst"
|
|
};
|
|
|
|
static char *tratab[] = {
|
|
"pans", "sts", "opr", "pgs", "pvl", "iic", "pid", "pie",
|
|
"csr", "actl", "ald", "pes", "pcs14", "pea", "err16", "err17"
|
|
};
|
|
|
|
static char *trrtab[] = {
|
|
"panc", "sts", "lmp", "pcr", "err04", "iie", "pid", "pie",
|
|
"cclr", "lcil", "ucil", "err13", "err14", "eccr", "err16", "err17"
|
|
};
|
|
|
|
static char *mitab[] = {
|
|
"ldatx", "ldxtx", "lddtx", "ldbtx", "statx", "stztx", "stdtx", "ERR"
|
|
};
|
|
|
|
t_stat
|
|
fprint_sym(FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw)
|
|
{
|
|
int ins, op, off;
|
|
|
|
if (!(sw & SWMASK ('M')))
|
|
return SCPE_ARG;
|
|
|
|
op = val[0];
|
|
ins = op & ND_MEMMSK;
|
|
off = SEXT8(op);
|
|
|
|
#define R(x) ((x) & 0177777)
|
|
fprintf(of, "%06o\t", op);
|
|
if (ins < ND_CJP || ins == ND_JPL) {
|
|
/* MEMORY REFERENCE INSTRUCTIONS */
|
|
fprintf(of, "%s ", nd_mem[ins >> ND_MEMSH]);
|
|
switch ((op >> 8) & 07) {
|
|
case 0:
|
|
fprintf(of, "0%o", R(off + addr));
|
|
break;
|
|
case 1:
|
|
fprintf(of, "B+0%o", R(off));
|
|
break;
|
|
case 2:
|
|
fprintf(of, "(0%o)", R(off + addr));
|
|
break;
|
|
case 3:
|
|
fprintf(of, "(B+0%o)", R(off));
|
|
break;
|
|
case 4:
|
|
fprintf(of, "0%o+X", R(off));
|
|
break;
|
|
case 5:
|
|
fprintf(of, "B+0%o+X", R(off));
|
|
break;
|
|
case 6:
|
|
fprintf(of, "(0%o)+X", R(off + addr));
|
|
break;
|
|
case 7:
|
|
fprintf(of, "(B+0%o)+X", R(off));
|
|
break;
|
|
}
|
|
#undef R
|
|
} else if (ins == ND_CJP) {
|
|
fprintf(of, "%s 0%o", jptab[(op & ND_CJPMSK) >> ND_CJPSH],
|
|
off + addr);
|
|
} else if (ins == ND_IOX) {
|
|
fprintf(of, "iox 0%04o", op & ND_IOXMSK);
|
|
} else if (ins == ND_ARG) {
|
|
fprintf(of, "%s 0%o", argtab[(op & ND_CJPMSK) >> ND_CJPSH],
|
|
off & 0177777);
|
|
} else if (ins == ND_SHT) {
|
|
fprintf(of, "s%c%c ", (op & 0600) == 0600 ? 'a' : 'h',
|
|
(op & 0200) ? 'd' : (op & 0400) ? 'a' : 't');
|
|
if (op & 03000)
|
|
fprintf(of, "%s ", (op & 01000) == 01000 ? "rot " :
|
|
(op & 02000) == 02000 ? "zin" : "lin");
|
|
fprintf(of, "%d", op & 040 ? 32 - (op & 037) : (op & 037));
|
|
} else if (ins == ND_BOP) {
|
|
fprintf(of, "%s ", boptab[(op & ND_BOPMSK) >> ND_BOPSH]);
|
|
fprintf(of, "%d d%s", (op & 0170) >> 3, dactab[op & 7]);
|
|
} else if (ins == ND_MIS) {
|
|
if ((op & 0177400) == 0151000)
|
|
fprintf(of, "wait 0%o", op & 0377);
|
|
else if (op == ND_MIS_SEX)
|
|
fprintf(of, "sex");
|
|
else if (op == ND_MIS_REX)
|
|
fprintf(of, "rex");
|
|
else if (op == ND_MIS_IOF)
|
|
fprintf(of, "iof");
|
|
else if (op == ND_MIS_ION)
|
|
fprintf(of, "ion");
|
|
else if (op == ND_MIS_POF)
|
|
fprintf(of, "pof");
|
|
else if (op == ND_MIS_PON)
|
|
fprintf(of, "pon");
|
|
else if (op == ND_MIS_PIOF)
|
|
fprintf(of, "piof");
|
|
else if (op == ND_MIS_PION)
|
|
fprintf(of, "pion");
|
|
else if (op == ND_MIS_IOXT)
|
|
fprintf(of, "ioxt");
|
|
else if ((op & ND_MIS_TRMSK) == ND_MIS_TRA)
|
|
fprintf(of, "tra %s", tratab[op & 017]);
|
|
else if ((op & ND_MIS_TRMSK) == ND_MIS_TRR)
|
|
fprintf(of, "trr %s", trrtab[op & 017]);
|
|
else if ((op & ND_MIS_TRMSK) == ND_MIS_MCL)
|
|
fprintf(of, "mcl 0%o", op & 077);
|
|
else if ((op & ND_MIS_TRMSK) == ND_MIS_MST)
|
|
fprintf(of, "mst 0%o", op & 077);
|
|
else if ((op & 0177600) == 0153600)
|
|
fprintf(of, "irr 0%02o d%s",
|
|
(op >> 3) & 017, dactab[op & 07]);
|
|
else if ((op & 0177600) == 0153400)
|
|
fprintf(of, "irw 0%02o d%s",
|
|
(op >> 3) & 017, dactab[op & 07]);
|
|
else if ((op & ND_MONMSK) == ND_MON)
|
|
fprintf(of, "mon 0%o", op & 0377);
|
|
else if ((op & ND_MONMSK) == ND_MIS_NLZ)
|
|
fprintf(of, "nlz 0%o", op & 0377);
|
|
else if ((op & ND_MIS_RBMSK) == ND_MIS_LRB)
|
|
fprintf(of, "lrb");
|
|
else if ((op & ND_MIS_RBMSK) == ND_MIS_SRB)
|
|
fprintf(of, "srb");
|
|
else
|
|
fprintf(of, "MISSING2: 0%06o", op);
|
|
} else if (ins == ND_ROP) {
|
|
switch (op & ND_ROPMSK) {
|
|
case 0146000: fprintf(of, "radd"); break;
|
|
case 0146600: fprintf(of, "rsub"); break;
|
|
case 0144400: fprintf(of, "rand"); break;
|
|
case 0145400: fprintf(of, "rora"); break;
|
|
case 0145000: fprintf(of, "rexo"); break;
|
|
case 0144000: fprintf(of, "swap"); break;
|
|
case 0146100: fprintf(of, "copy"); break;
|
|
case 0146500: fprintf(of, "rinc"); break;
|
|
default:
|
|
if ((op & 0177770) == 0146400) {
|
|
fprintf(of, "rinc %s", dactab[op & 07]);
|
|
op = 0;
|
|
} else
|
|
fprintf(of, "%07o", op & ND_ROPMSK);
|
|
break;
|
|
}
|
|
if (op)
|
|
fprintf(of, " s%s to d%s",
|
|
dactab[(op & 070) >> 3], dactab[op & 07]);
|
|
} else if (ins == ND_SKP) {
|
|
if (op & 0300) {
|
|
if (op == ND_SKP_BFILL)
|
|
fprintf(of, "bfill");
|
|
else if (op == ND_SKP_MOVB)
|
|
fprintf(of, "movb");
|
|
else if (op == ND_SKP_MOVBF)
|
|
fprintf(of, "movbf");
|
|
else if (op == ND_SKP_IDENT10)
|
|
fprintf(of, "ident 10");
|
|
else if (op == ND_SKP_IDENT11)
|
|
fprintf(of, "ident 11");
|
|
else if (op == ND_SKP_IDENT12)
|
|
fprintf(of, "ident 12");
|
|
else if (op == ND_SKP_IDENT13)
|
|
fprintf(of, "ident 13");
|
|
else if (op == ND_SKP_LBYT)
|
|
fprintf(of, "lbyt");
|
|
else if (op == ND_SKP_SBYT)
|
|
fprintf(of, "sbyt");
|
|
else if ((op & 0177707) == ND_SKP_EXR)
|
|
fprintf(of, "exr %s", dactab[(op & 070) >> 3]);
|
|
else if ((op & 0177700) == ND_SKP_LDATX)
|
|
fprintf(of, "%s", mitab[op & 07]);
|
|
else if ((op & 0177700) == ND_SKP_RMPY)
|
|
fprintf(of, "rmpy %s %s",
|
|
dactab[(op & 070) >> 3], dactab[op & 07]);
|
|
else
|
|
fprintf(of, "MISSING4: 0%06o", op);
|
|
} else
|
|
fprintf(of, "skp d%s %s s%s", dactab[op & 07],
|
|
skptab[(op >> 8) & 07], dactab[(op & 070) >> 3]);
|
|
} else
|
|
fprintf(of, "MISSING: 0%06o", op);
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat
|
|
parse_sym(CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
|
|
{
|
|
return SCPE_ARG;
|
|
}
|