[laminar] Executing cfg/jobs/simh-ibmpcxt.run ++ id -u ++ id -g ++ echo simh-ibmpcxt ++ cut -f 1 -d - + docker run --rm --interactive --volume /var/cache/git:/var/cache/git --volume /var/cache/laminar:/var/cache/laminar --volume /var/lib/laminar/cfg/scripts:/var/lib/laminar/cfg/scripts --volume /var/lib/laminar/cfg/patches:/var/lib/laminar/cfg/patches --volume /var/lib/laminar/run/simh-ibmpcxt/50:/var/lib/laminar/run/simh-ibmpcxt/50 --env rev= --env JOB=simh-ibmpcxt --env COMPILER_SUITE= --security-opt apparmor=unconfined --net=host --user 998:998 --workdir /var/lib/laminar/run/simh-ibmpcxt/50 simh /bin/bash + export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/var/lib/laminar/cfg/scripts + PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/var/lib/laminar/cfg/scripts + SRC_REPO=/var/cache/git/simh ++ basename /var/cache/git/simh .git + SRC_REPO_DIR=simh ++ echo simh-ibmpcxt ++ cut -f 2- -d - + SIMULATOR=ibmpcxt + BUILD_REV= + '[' -z '' ']' + BUILD_REV=master + . /var/lib/laminar/cfg/scripts/evaluate_compiler.inc ++ : gcc-snapshot ++ case "${COMPILER_SUITE}" in ++ export CC=/usr/lib/gcc-snapshot/bin/gcc ++ CC=/usr/lib/gcc-snapshot/bin/gcc ++ export CXX=/usr/lib/gcc-snapshot/bin/g++ ++ CXX=/usr/lib/gcc-snapshot/bin/g++ ++ export CPP=/usr/lib/gcc-snapshot/bin/cpp ++ CPP=/usr/lib/gcc-snapshot/bin/cpp ++ export LD_LIBRARY_PATH=/usr/lib/gcc-snapshot/lib ++ LD_LIBRARY_PATH=/usr/lib/gcc-snapshot/lib ++ export PATH=/usr/lib/gcc-snapshot/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/var/lib/laminar/cfg/scripts ++ PATH=/usr/lib/gcc-snapshot/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/var/lib/laminar/cfg/scripts ++ hash -r + . /var/lib/laminar/cfg/scripts/evaluate_patches.inc + /usr/lib/gcc-snapshot/bin/gcc --version gcc (Debian 20230315-1) 13.0.1 20230315 (experimental) [master r13-6680-ga9ae16db8cb] Copyright (C) 2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + /usr/lib/gcc-snapshot/bin/g++ --version g++ (Debian 20230315-1) 13.0.1 20230315 (experimental) [master r13-6680-ga9ae16db8cb] Copyright (C) 2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + rm -rf simh + git clone --shared /var/cache/git/simh Cloning into 'simh'... done. Updating files: 49% (910/1826) Updating files: 50% (913/1826) Updating files: 51% (932/1826) Updating files: 52% (950/1826) Updating files: 53% (968/1826) Updating files: 54% (987/1826) Updating files: 55% (1005/1826) Updating files: 56% (1023/1826) Updating files: 57% (1041/1826) Updating files: 58% (1060/1826) Updating files: 59% (1078/1826) Updating files: 60% (1096/1826) Updating files: 61% (1114/1826) Updating files: 62% (1133/1826) Updating files: 63% (1151/1826) Updating files: 64% (1169/1826) Updating files: 65% (1187/1826) Updating files: 66% (1206/1826) Updating files: 67% (1224/1826) Updating files: 68% (1242/1826) Updating files: 69% (1260/1826) Updating files: 70% (1279/1826) Updating files: 71% (1297/1826) Updating files: 72% (1315/1826) Updating files: 73% (1333/1826) Updating files: 74% (1352/1826) Updating files: 75% (1370/1826) Updating files: 76% (1388/1826) Updating files: 77% (1407/1826) Updating files: 78% (1425/1826) Updating files: 79% (1443/1826) Updating files: 80% (1461/1826) Updating files: 81% (1480/1826) Updating files: 82% (1498/1826) Updating files: 83% (1516/1826) Updating files: 84% (1534/1826) Updating files: 85% (1553/1826) Updating files: 86% (1571/1826) Updating files: 87% (1589/1826) Updating files: 88% (1607/1826) Updating files: 89% (1626/1826) Updating files: 90% (1644/1826) Updating files: 91% (1662/1826) Updating files: 92% (1680/1826) Updating files: 93% (1699/1826) Updating files: 94% (1717/1826) Updating files: 95% (1735/1826) Updating files: 96% (1753/1826) Updating files: 97% (1772/1826) Updating files: 98% (1790/1826) Updating files: 99% (1808/1826) Updating files: 100% (1826/1826) Updating files: 100% (1826/1826), done. + pushd simh /var/lib/laminar/run/simh-ibmpcxt/50/simh /var/lib/laminar/run/simh-ibmpcxt/50 + git checkout master Already on 'master' Your branch is up to date with 'origin/master'. + apply_patches .:generic-simh .:simh-ibmpcxt + local this_arg + local this_path + local this_prefix + local this_patch + '[' 2 -gt 0 ']' + this_arg=.:generic-simh + shift ++ echo .:generic-simh ++ cut -f 1 -d : + this_path=. ++ echo .:generic-simh ++ cut -f 2 -d : /var/lib/laminar/run/simh-ibmpcxt/50/simh /var/lib/laminar/run/simh-ibmpcxt/50/simh /var/lib/laminar/run/simh-ibmpcxt/50 + this_prefix=generic-simh + pushd . + for this_patch in "/var/lib/laminar/cfg/patches/${this_prefix}--"*.patch + '[' -r '/var/lib/laminar/cfg/patches/generic-simh--*.patch' ']' + popd + '[' 1 -gt 0 ']' + this_arg=.:simh-ibmpcxt + shift /var/lib/laminar/run/simh-ibmpcxt/50/simh /var/lib/laminar/run/simh-ibmpcxt/50 ++ echo .:simh-ibmpcxt ++ cut -f 1 -d : + this_path=. ++ echo .:simh-ibmpcxt ++ cut -f 2 -d : /var/lib/laminar/run/simh-ibmpcxt/50/simh /var/lib/laminar/run/simh-ibmpcxt/50/simh /var/lib/laminar/run/simh-ibmpcxt/50 + this_prefix=simh-ibmpcxt + pushd . + for this_patch in "/var/lib/laminar/cfg/patches/${this_prefix}--"*.patch + '[' -r '/var/lib/laminar/cfg/patches/simh-ibmpcxt--*.patch' ']' + popd + '[' 0 -gt 0 ']' + git show /var/lib/laminar/run/simh-ibmpcxt/50/simh /var/lib/laminar/run/simh-ibmpcxt/50 commit b40f7efde8e67d9cc25620d863a0d527e8e4c39c Author: Anders Magnusson Date: Thu Mar 30 19:52:33 2023 +0200 ND100: Initial support for Nord-100, implements the base instruction set. Passes the test program INSTRUCTION-B. diff --git a/ND100/nd100_cpu.c b/ND100/nd100_cpu.c new file mode 100644 index 00000000..83b81eac --- /dev/null +++ b/ND100/nd100_cpu.c @@ -0,0 +1,1748 @@ +/* + * 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 + +#include "sim_defs.h" + +#include "nd100_defs.h" + +#define MAXMEMSIZE 512*1024 +#undef TIMERHACK + +#ifdef TIMERHACK +int rtc_int_enabled, rtc_dev_ready, rtccnt; +void chkrtc(void); +#endif + +typedef struct { + int ir; + int16 sts; + int16 d; + int16 p; + int16 b; + int16 l; + int16 a; + int16 t; + int16 x; +} Hist_entry ; + +#define HIST_IR_INVALID -1 +#define HIST_MIN 0 +#define HIST_MAX 1000000 + +static int32 hist_p = 0; +static int32 hist_cnt = 0; +static Hist_entry *hist = NULL; +static struct intr *ilnk[4]; /* level 10-13 */ +jmp_buf env; + +uint16 R[8], RBLK[16][8], regSTH; +int curlvl; /* current interrupt level */ +int iic, iie, iid; /* IIC/IIE/IID register */ +int pid, pie; /* PID/PIE register */ +int ald, eccr, pvl, lmp; + +#define SETC() (regSTL |= STS_C) +#define CLRC() (regSTL &= ~STS_C) +#define SETQ() (regSTL |= STS_Q) +#define CLRQ() (regSTL &= ~STS_Q) +#define SETO() (regSTL |= STS_O) +#define CLRO() (regSTL &= ~STS_O) + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_reset (DEVICE *dptr); + +t_stat hist_set(UNIT * uptr, int32 val, CONST char * cptr, void * desc); +t_stat hist_show(FILE * st, UNIT * uptr, int32 val, CONST void * desc); +static void hist_fprintf(FILE *fp, int itemNum, Hist_entry *hptr); +static void hist_save(int ir); + +static int getoff(int ir); +static int iox_check(int dev); +static int nd_trr(int reg); +static int nd_tra(int reg); +static int nd_mcl(int reg); +static int nd_mst(int reg); +static int highest_level(void); +static void intrpt14(int); +static void identrm(int); +static uint16 add3(uint16 a, uint16 d, uint16 c); +int fls(int); + + +int ins_store(int ir, int addr); +int ins_stdf(int ir, int addr); +int ins_lddf(int ir, int addr); +int ins_min(int ir, int addr); +int ins_load(int ir, int addr); +int ins_add(int ir, int addr); +int ins_andor(int ir, int addr); +void ins_dnz(int ins); +void ins_nlz(int ins); +int ins_fad(int ir, int addr); +int ins_fsb(int ir, int addr); +int ins_fmu(int ir, int addr); +int ins_fdv(int ir, int addr); +int ins_mpy(int ir, int addr); +int ins_jmpl(int ir, int addr); +int ins_cjp(int ir, int addr); +int ins_skp(int ir, int addr); +int ins_skip_ext(int IR); +int ins_rop(int ir, int addr); +int ins_mis(int IR, int addr); +int ins_sht(int IR, int addr); +int ins_na(int IR, int addr); +int ins_iox(int IR, int addr); +int ins_arg(int IR, int addr); +int ins_bop(int IR, int addr); + +#define ID(x) (((x) & ND_MEMMSK) >> ND_MEMSH) + +int (*ins_table[32])(int ir, int addr) = { + ins_store, ins_store, ins_store, ins_store, /* STZ/STA/STT/STX */ + ins_stdf, ins_lddf, ins_stdf, ins_lddf, /* STD/LDD/STF/LDF */ + ins_min, ins_load, ins_load, ins_load, /* MIN/LDA/LDT/LDX */ + ins_add, ins_add, ins_andor, ins_andor, /* ADD/SUB/ADN/ORA */ + ins_fad, ins_fsb, ins_fmu, ins_fdv, /* FAD/FSB/FMU/FDV */ + ins_mpy, ins_jmpl, ins_cjp, ins_jmpl, /* MPY/JMP/CJP/JPL */ + ins_skp, ins_rop, ins_mis, ins_sht, /* SKP/ROP/MIS/SHT */ + ins_na, ins_iox, ins_arg, ins_bop /* --/IOX/ARG/BOP */ +}; + +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) }; + +REG cpu_reg[] = { + { ORDATA(STS, R[0], 16) }, + { ORDATA(D, regD, 16) }, + { ORDATA(P, regP, 16) }, + { ORDATA(B, regB, 16) }, + { ORDATA(L, regL, 16) }, + { ORDATA(A, regA, 16) }, + { ORDATA(T, regT, 16) }, + { ORDATA(X, regX, 16) }, + { DRDATA(LVL, curlvl, 4) }, + { DRDATA(LMP, lmp, 16) }, + { DRDATA(PVL, pvl, 4) }, + { ORDATA(PID, pid, 16) }, + { ORDATA(PIE, pie, 16) }, + { ORDATA(IIC, iic, 4) }, + { ORDATA(IIE, iie, 10) }, + { NULL } +}; + +MTAB cpu_mod[] = { + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", + &hist_set, &hist_show }, + { 0 } +}; + +DEVICE cpu_dev = { + "CPU", &cpu_unit, cpu_reg, cpu_mod, + 1, 8, 16, 1, 8, 16, + &cpu_ex, &cpu_dep, &cpu_reset, + NULL, NULL, NULL +}; + +t_stat +sim_instr() +{ + int IR; + int reason; + int n, i; + int first = 1; + uint16 off; + + reason = setjmp(env); + +while (reason == 0) { + if (sim_interval <= 0) + if ((reason = sim_process_event ())) + break; + +#ifdef TIMERHACK + chkrtc(); +#endif + if ((pid & pie) > (0177777 >> (15-curlvl)) && ISION()) { + /* need to interrupt */ + pvl = curlvl; + n = highest_level(); + for (i = 0; i < 8; i++) { + RBLK[curlvl][i] = R[i]; + R[i] = RBLK[n][i]; + } + curlvl = n; + if (curlvl == 14 && iic == 1) /* mon call */ + regT = SEXT8(IR); + } + + IR = rdmem(regP); + sim_interval--; + + if (first == 0 && sim_brk_summ && sim_brk_test (regP, SWMASK ('E'))) { + reason = STOP_BP; + break; + } + first = 0; + + if (hist_cnt) + hist_save(IR); + + /* + * Execute instruction. We intercept it here before calling + * the instruction routine and just update IR. + */ + if (ISEXR(IR)) { /* Execute instruction */ + IR = R[(IR >> 3) & 07]; +#ifdef notyet + if (ISEXR(IR)) + trap... +#endif + if (hist_cnt) + hist_save(IR); + } + + if (ID(IR) < ND_CJP || ID(IR) == ND_JPL) + off = getoff(IR); + + reason = (*ins_table[ID(IR)])(IR, off); + if (reason == 0) + regP++; +} + return reason; +} + +t_stat +cpu_reset(DEVICE *dptr) +{ + sim_brk_types = sim_brk_dflt = SWMASK ('E'); + regSTH |= STS_N100; + return SCPE_OK; +} + +t_stat +cpu_ex(t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ + if (addr >= MAXMEMSIZE) + return SCPE_ARG; + *vptr = rdmem(addr); + return SCPE_OK; +} + +/* Memory deposit */ + +t_stat +cpu_dep(t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ + return SCPE_ARG; +} + +t_stat +cpu_set_size(UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + return SCPE_ARG; +} + +t_stat +cpu_boot(int32 unitno, DEVICE *dptr) +{ + return SCPE_ARG; +} + +/* + * Store register. + */ +int +ins_store(int IR, int off) +{ + int n = ((IR >> 11) & 03) + 4; + wrmem(off, n == 4 ? 0 : R[n]); + return SCPE_OK; +} + +/* + * Store double or triple reg. + */ +int +ins_stdf(int IR, int off) +{ + if (ID(IR) == ID(ND_STF) /* && 48-bit */) + wrmem(off++, regT); + wrmem(off++, regA); + wrmem(off, regD); + return SCPE_OK; +} + +/* + * Load double or triple reg. + */ +int +ins_lddf(int IR, int off) +{ + if (ID(IR) == ID(ND_LDF) /* && 48-bit */) + regT = rdmem(off++); + regA = rdmem(off++); + regD = rdmem(off); + return SCPE_OK; +} + +/* + * Load one reg. + */ +int +ins_load(int IR, int off) +{ + R[((IR&014000) >> 11) + 4] = rdmem(off); + return SCPE_OK; +} + +/* + * Increment (and skip?). + */ +int +ins_min(int IR, int off) +{ + uint16 s; + + wrmem(off, s = rdmem(off) + 1); + if (s == 0) + regP++; + return SCPE_OK; +} + +/* + * Add/sub. + */ +int +ins_add(int IR, int off) +{ + uint16 d = rdmem(off); + int n = 0; + + if (ID(IR) == ID(ND_SUB)) + n = 1, d = ~d; + regA = add3(regA, d, n); + return SCPE_OK; +} + +/* + * And/or + */ +int +ins_andor(int IR, int off) +{ + uint16 s = rdmem(off); + + regA = BIT11(IR) ? (regA | s) : (regA & s); + return SCPE_OK; +} + +/* + * Byte instructions (BFILL, MOVB, MOVBF). Requires at least ND100. + * + * Byte operands occupy fields within the memory. Operands are specified + * by two 16-bit words, known as descriptors, giving the start address + * and the field length. + * + * The start address is in register A if source, X if destination (D1) + * The rest of the descriptor is in D if source, T if destination (D2) + * + * In D2 bits + * 11-0 are the field length (in bytes). + * 12 - Ignored + * 13 - Must be 0 + * 14 - 0 = normal PT, 1 = alternate + * 15 - 0 = left byte start, 1 = right byte. + * + */ +#define BYTELN(x) ((x) & 07777) +/* + * Byte fill (BFILL). + * + * This instruction has only one operand. The destination operand is + * specified in the X and T registers. The right-most byte in the A-reg + * (bits 0-7) is filled into the destination field. + * After execution, the X-register and T-register bit 15 point to the + * end of the field (after the last byte). The T-register bits (0-11) + * equal zero. + * The instruction will always have a skip return (no error condition). + */ +static void +ins_bfill(int IR) +{ + while (regT & 07777) { + wrbyte(regX, regA, BIT15(regT)); + regT--; + regT ^= 0100000; + if (BIT15(regT) == 0) + regX++; + } + regP++; /* skip return */ +} + +/* + * Move bytes (MOVB) + * + * This instruction moves a block of bytes from the location specified for + * the source operand to the location specified for the destination operand. + * The move operation takes care of source— and destination-field overlap. + * The number of bytes moved is determined by the shortest field length of + * the operands. + * After execution, the AD and XT registers (bit 15 in D and T) point to + * the end of the field that is moved (after the last byte). D-reg. bits + * 0-11 equal zero and T-reg. bits 0-11 contain the number of bytes moved. + * The T—reg. bits 12—13 and the D-reg. bit 12 are used during the execution, + * and are left cleared. Bit 13 must be zero before execution (used as an + * interrupt mark). + * The instruction will always have a skip return (no error condition). + * + * Implementation note: Because this instruction can be interrupted (by a + * page fault for example) byte for byte must be moved, and every state + * will be stored in the registers (similar to the microcode implementation). + * The usage is: + * - BIT13(regD): all regs are setup in the middle of execution. + */ +static void +ins_movb(int IR) +{ + int i; + + if (BIT13(regD) == 0) { + /* setup for copy */ + int len = BYTELN(regD); + if (BYTELN(regT) < len) + len = BYTELN(regT); + regT = (regT & 0140000) | len; /* T is max */ + regD = (regD & 0140000); /* D is zero */ + regD |= (1 << 13); /* setup done! */ + } + + if (regX > regA) { /* copy bottom-top */ + for (i = BYTELN(regD); i < BYTELN(regT); i++, regD++) { + int8 w = rdbyte(regA, BIT15(regD)); + wrbyte(regX, w, BIT15(regT)); + regD ^= 0100000; + if (BIT15(regD) == 0) regA++; + regT ^= 0100000; + if (BIT15(regT) == 0) regX++; + } + regD &= 0140000; /* Clear setup + count bits */ + } else { /* copy top-bottom */ + + } + regP++; /* skip return */ +} + +/* + * This instruction moves a block of bytes from the location specified as + * the source operand to the location specified as the destination operand. + * The move operation always starts with the first byte (lower address). + * + * The number of bytes moved is determined by the shortest field length of + * the operands. Forbidden overlap exists when the source data to be moved, + * will be destroyed. That happens when a byte is stored in a word before + * that word is read from memory. This is reported by an error return (no skip). + * + * After successful execution, the A,D and X,T registers (bit 15 in D and T) + * point to the end of the fields that are moved (after the last byte). + * The numbers initially contained in the D- and T-registers, bits 0-11, + * are decremented by the number of bytes moved. + * + * The T—reg. bits 12—13 and the D—reg. bit 12 are used during the execution + * and are left cleared. Bit 13 must be zero before execution (used as an + * interrupt mark). The instruction will have a skip—return when + * no illegal overlap exists. + */ +static void +ins_movbf(int IR) +{ + int i; + + if (BIT13(regD) == 0) { + /* setup for copy */ + int len = BYTELN(regD); + if (BYTELN(regT) < len) + len = BYTELN(regT); + regT = (regT & 0140000) | len; /* T is max */ + regD = (regD & 0140000); /* D is zero */ + regD |= (1 << 13); /* setup done! */ + if (regX > regA && regX < (regA + (len >> 1))) + return; + } + + for (i = BYTELN(regD); i < BYTELN(regT); i++, regD++) { + int8 w = rdbyte(regA, BIT15(regD)); + wrbyte(regX, w, BIT15(regT)); + regD ^= 0100000; + if (BIT15(regD) == 0) regA++; + regT ^= 0100000; + if (BIT15(regT) == 0) regX++; + } + regD &= 0140000; /* Clear setup + count bits */ + regT &= 0140000; /* Clear setup + count bits */ + regP++; /* skip return */ +} + +/* + * Instructions with the same encoding as skip instructions. + */ +int +ins_skip_ext(int IR) +{ + uint16 d; + int16 ss, sd; + int32 shc; + int reason = 0; + + if ((IR & 0177707) == ND_SKP_CLEPT) { + intrpt14(IIE_II); + regP--; + } else if (IR == ND_SKP_MIX3) { + /* X = (A-1)*3 */ + regX = (regA-1)*3; + } else if (IR == ND_SKP_IDENT10) { + identrm(10); + } else if (IR == ND_SKP_IDENT11) { + identrm(11); + } else if (IR == ND_SKP_IDENT12) { + identrm(12); + } else if (IR == ND_SKP_IDENT13) { + identrm(13); + } else if (IR == ND_SKP_BFILL) + ins_bfill(IR); + else if (IR == ND_SKP_MOVB) + ins_movb(IR); + else if (IR == ND_SKP_MOVBF) + ins_movbf(IR); + else if (IR == ND_SKP_LBYT) { + d = rdmem(regT + (regX >> 1)); + if (regX & 1) + regA = d & 0377; + else + regA = d >> 8; + } else if (IR == ND_SKP_SBYT) { + d = regT + (regX >> 1); + if (regX & 1) + wrmem(d, (rdmem(d) & 0xff00) | (regA & 0xff)); + else + wrmem(d, (rdmem(d) & 0xff) | (regA << 8)); + } else if ((IR & 0177700) == ND_SKP_RMPY) { + ss = R[(IR & 070) >> 3]; + sd = R[IR & 07]; + shc = ss * sd; + regD = shc; + regA = shc >> 16; + } else if ((IR & 0177700) == ND_SKP_RDIV) { + ss = R[(IR & 070) >> 3]; + shc = (regA << 16) | regD; + regA = shc / ss; + regD = shc % ss; + } else if (IR == 0142700) { + /* ??? what is this? */ + intrpt14(IIE_II); + regP--; + } else + reason = STOP_UNHINS; + return reason; +} + +/* + * The instruction SRB stores the contents of the register + * block on the program level specified in the level field of + * the instruction. The specified register block is stored in + * succeeding memory locations starting at the location specified by + * the contents of the X register. + * If the current program level is specified, the stored P register points + * to the instruction following SRB. + * + * Affected: (EL), +1 +2 +3 +4 +5 +6 +7 + * P X T A D L STS B + */ +static int s2r[] = { rnP, rnX, rnT, rnA, rnD, rnL, rnSTS, rnB }; +static void +ins_srb(int IR) +{ + int i, n = (IR >> 3) & 017; + + /* Save current level (maybe used) to reg block */ + for (i = 0; i < 8; i++) + RBLK[curlvl][i] = R[i]; + RBLK[curlvl][rnP]++; /* following insn */ + + /* store requested block to memory */ + for (i = 0; i < 8; i++) + wrmem(regX+i, RBLK[n][s2r[i]]); +} + +/* + * The instruction LRB loads the contents of the register + * block on program level specified in the level field of the instruction. + * The specified register block is loaded by the contents of succeeding + * memory locations starting at the location specified by the contents + * of the X register. + * If the current program level is specified, the P register is not affected. + * Affected: All the registers on specified program level are affected. + * Note: If the current level is specified, the P register is not affected. + */ +static void +ins_lrb(int IR) +{ + int i, n = (IR >> 3) & 017; + + /* fetch from memory */ + for (i = 0; i < 8; i++) + RBLK[n][s2r[i]] = rdmem(regX+i); + RBLK[n][rnSTS] &= 0377; + + if (n == curlvl) + for (i = 0; i < 8; i++) + if (i != rnP) + R[i] = RBLK[n][i]; +} + +/* + * Miscellaneous instructions. + */ +int +ins_mis(int IR, int off) +{ + int reason = 0; + int n, i; + + if (IR == ND_MIS_SEX) + regSTH |= STS_SEXI; + else if (IR == ND_MIS_DEPO) { + if ((n = ((regA << 16) | regD)) <= MAXMEMSIZE) + PM[n] = regT; + } else if (IR == ND_MIS_EXAM) { + if ((n = ((regA << 16) | regD)) <= MAXMEMSIZE) + regT = PM[n]; + } else if (IR == ND_MIS_REX) { + regSTH &= ~STS_SEXI; + } else if (IR == ND_MIS_PON) { + regSTH |= STS_PONI; + } else if (IR == ND_MIS_POF) { + regSTH &= ~STS_PONI; + } else if (IR == ND_MIS_ION) { + regSTH |= STS_IONI; + } else if (IR == ND_MIS_IOF) { + regSTH &= ~STS_IONI; + } else if (IR == ND_MIS_PIOF) { + regSTH &= ~(STS_IONI|STS_PONI); + } else if (IR == ND_MIS_IOXT) { + reason = iox_check(regT); + } else if ((IR & ND_MIS_TRMSK) == ND_MIS_TRA) + reason = nd_tra(IR & ~ND_MIS_TRMSK); + else if ((IR & ND_MIS_TRMSK) == ND_MIS_TRR) + reason = nd_trr(IR & ~ND_MIS_TRMSK); + else if ((IR & ND_MIS_TRMSK) == ND_MIS_MST) + reason = nd_mst(IR & ~ND_MIS_TRMSK); + else if ((IR & ND_MIS_TRMSK) == ND_MIS_MCL) + reason = nd_mcl(IR & ~ND_MIS_TRMSK); + else if ((IR & ND_MIS_IRRMSK) == ND_MIS_IRR) { + n = (IR >> 3) & 017; + if (n == curlvl) + regA = R[IR & 07]; + else + regA = RBLK[n][IR & 07]; + } else if ((IR & ND_MIS_IRRMSK) == ND_MIS_IRW) { + n = (IR >> 3) & 017; + RBLK[n][IR & 07] = regA; + if (n == curlvl && (IR & 07) != rnP) + R[IR & 07] = regA; + } else if ((IR & ND_MIS_RBMSK) == ND_MIS_SRB) { + ins_srb(IR); + } else if ((IR & ND_MIS_RBMSK) == ND_MIS_LRB) { + ins_lrb(IR); + } else if ((IR & ND_MONMSK) == ND_MON) { + RBLK[14][rnT] = SEXT8(IR); + intrpt14(IIE_MC); + } else if ((IR & ND_MONMSK) == ND_WAIT) { + if (ISION() == 0) { + regP++; + reason = STOP_WAIT; + } else if (curlvl > 0) { + pid &= ~(1 << curlvl); + n = highest_level(); + if (curlvl != n) { + regP++; + for (i = 0; i < 8; i++) { + RBLK[curlvl][i] = R[i]; + R[i] = RBLK[n][i]; + } + regP--; + } + curlvl = n; + } + } else if ((IR & ND_MONMSK) == ND_MIS_NLZ) { + /* convert integer to floating point */ + ins_nlz(IR); + } else if ((IR & ND_MONMSK) == ND_MIS_DNZ) { + ins_dnz(IR); + } else + reason = STOP_UNHINS; + return reason; +} + +int +ins_sht(int IR, int off) +{ + char sht_reg[] = { rnT, rnD, rnA, 0 }; + int m, n, rs, i; + uint32 ushc; + + rs = sht_reg[(IR >> 7) & 03]; + n = BIT5(IR) ? 32 - IR & 037 : IR & 037; + m = BIT7(regSTL); + + ushc = rs ? R[rs] : (regA << 16) | regD; + if (BIT5(IR)) { /* right */ + int mm = BIT0(ushc); + for (i = 0; i < n; i++) { + m = BIT0(ushc); + ushc = ushc >> 1; + switch (IR & 03000) { + case 0: /* Arithmetic */ + ushc |= (rs ? (BIT14(ushc) << 15) : + (BIT30(ushc) << 31)); + break; + case 01000: /* ROT */ + ushc |= (rs ? (m << 15) : + (m << 31)); + break; + case 02000: /* zero end input */ + break; + case 03000: /* link end input */ + ushc |= (rs ? (mm << 15) : + (mm << 31)); + break; + } + } + } else { /* left */ + int mm = (rs ? BIT15(ushc) : BIT31(ushc)); + for (i = 0; i < n; i++) { + m = (rs ? BIT15(ushc) : BIT31(ushc)); + ushc = ushc << 1; + switch (IR & 03000) { + case 01000: /* ROT */ + ushc |= m; break; + case 0: /* Arithmetic */ + case 02000: /* zero end input */ + break; + case 03000: /* link end input */ + ushc |= mm; break; + } + } + } + regSTL = (regSTL & ~STS_M) | (m << 7); + if (rs == 0) { + regA = ushc >> 16; + regD = ushc; + } else + R[rs] = ushc; + return SCPE_OK; +} + +int +ins_na(int IR, int addr) +{ + return STOP_UNHINS; +} + +int +ins_iox(int IR, int addr) +{ + return iox_check(IR & ND_IOXMSK); +} + +int +ins_arg(int IR, int addr) +{ + int rs, n = (IR >> 8) & 03; + + rs = n ? n + 4 : 3; + R[rs] = add3(BIT10(IR) ? R[rs] : 0, SEXT8(IR), 0); + return SCPE_OK; +} + +int +ins_bop(int IR, int addr) +{ + + int rd, n, reason = 0; + + rd = IR & 7; + n = (IR >> 3) & 017; + switch ((IR >> 7) & 017) { + case 000: /* BSET zero/one */ + R[rd] &= ~(1 << n); + break; + + case 001: + R[rd] |= (1 << n); + break; + + case 002: /* BSET BCM bit = ~bit */ + R[rd] ^= (1 << n); + break; + + case 003: /* BSET BAC bit = K */ + R[rd] &= ~(1 << n); + if (regSTL & STS_K) + R[rd] |= (1 << n); + break; + + case 004: /* BSKP zero/one */ + case 005: + if (((R[rd] >> n) & 1) == BIT7(IR)) + regP++; + break; + + case 006: /* BSKP BCM K == ~bit */ + if (((regSTL & STS_K) != 0) ^ (((R[rd] >> n) & 1) != 0)) + regP++; + break; + + + case 010: /* BSTA store ~K and set K */ + R[rd] &= ~(1 << n); + if ((regSTL & STS_K) == 0) + R[rd] |= (1 << n); + regSTL |= STS_K; + break; + + case 011: /* BSTA store K and clear K */ + R[rd] &= ~(1 << n); + if (regSTL & STS_K) + R[rd] |= (1 << n); + regSTL &= ~STS_K; + break; + + case 012: /* BLDA load ~K */ + regSTL &= ~STS_K; + if (((R[rd] >> n) & 1) == 0) + regSTL |= STS_K; + break; + + case 013: /* BLDA load K */ + regSTL &= ~STS_K; + if ((R[rd] >> n) & 1) + regSTL |= STS_K; + break; + + case 014: /* BANC K = ~bit & K */ + if (regSTL & STS_K) { + if ((R[rd] >> n) & 1) + regSTL &= ~STS_K; + } + break; + + case 015: /* BAND K = bit & K */ + if (regSTL & STS_K) { + if (((R[rd] >> n) & 1) == 0) + regSTL &= ~STS_K; + } + break; + + case 016: /* BORC K = ~bit | K */ + if ((regSTL & STS_K) == 0) { + if (((R[rd] >> n) & 1) == 0) + regSTL |= STS_K; + } + break; + + case 017: /* BORA K = bit | K */ + if ((regSTL & STS_K) == 0) { + if ((R[rd] >> n) & 1) + regSTL |= STS_K; + } + break; + + default: + reason = STOP_UNHINS; + break; + } + return reason; +} + +/* + * 48-bit floating point. T has the sign and exponent, A has the most + * significant bits and D has the least. + * Exponent is biased 16384, mantissa is 0.5 <= X < 1.0. + */ +struct fp { + int s; + int e; + t_uint64 m; +}; + +static void +mkfp48(struct fp *fp, uint16 w1, uint16 w2, uint16 w3) +{ + fp->s = BIT15(w1); + fp->e = (w1 & 077777) - 16384; + fp->m = ((t_uint64)w2 << 16) + (t_uint64)w3; +} + +/* + * Description of DNZ instruction from the NORD-10 manual: + * + * Converts the floating number in the floating accumulator to a + * single precision fixed point number in the A register, using the + * scaling of the DNZ instruction as a scaling factor. + * + * When converting to integers, the scaling factor should be —16, a + * greater scaling factor will cause the fixed point number to be + * greater. After this instruction the contents of the T and D registers + * will all be zeros. + * + * If the conversion causes underflow, the T, A and D registers will all + * be set to zero. If the conversion causes overflow, the error + * indicator 2 is set to one. Overflow occurs if the resulting integer + * in absolute value is greater than 32767. + * The conversion will truncate and negative numbers are converted to + * positive numbers before conversion. The result will again be + * converted to a negative number. + */ +void +ins_dnz(int ins) +{ + int32 val = 0; /* XXX remove warnings */ + int sh; + + sh = (regT & 077777) - 16384 + SEXT8(ins); + if (sh < 0) { + val = regA; + val >>= -sh; + } else { + + } +#ifdef notyet + if (val > 32767) + z = 1; +#endif + if (regT & 0100000) + val = -val; + regT = regD = 0; + regA = (uint16)val; +} + +/* + * Description of DNZ instruction from the NORD-10 manual: + * + * Converts the number in the A register to a standard form floating + * number in the floating accumulator, using the scaling of the NLZ + * instruction as a scaling factor. For integers, the scaling factor + * should be +16, a larger scaling factor will result in a higher floating, + * point number. Because of the single precision fixed point number, + * the D register will be cleared. + */ +void +ins_nlz(int ins) +{ + int sh, s; + int val; + + s = 0; + regD = 0; + if (regA == 0) { /* zero, special case */ + regT = 0; + return; + } + + val = (int)(int16)regA; + sh = 16384 + SEXT8(ins); + if (val < 0) + val = -val, s = 0100000; + if (val > 32767) + val >>= 1, sh++; + while ((val & 0100000) == 0) { + val <<= 1; + sh--; + } + regT = sh + s; + regA = val; +} + +/* + * Multiplication of two 48-bit floating point numbers. + * + * The contents of the floating accumulator are multiplied with the + * number of the effective floating word locations with the result in + * the floating accumulator. The previous setting of the carry and overflow + * indicators are lost. + * Affected: (T), (A), (D), O, Q, TG + */ +int +ins_fmu(int IR, int addr) +{ + struct fp f1, f2; + int s3, e3; + t_uint64 m3; + + /* Fetch from memory */ + mkfp48(&f1, rdmem(addr), rdmem(addr+1), rdmem(addr+2)); + + /* From registers */ + mkfp48(&f2, regT, regA, regD); + + /* calc */ + m3 = f1.m * f2.m; + e3 = f1.e + f2.e; + s3 = f1.s ^ f2.s; + + /* normalize (if needed) */ + if ((m3 & (1ULL << 63)) == 0) { + m3 <<= 1; + e3--; + } + + /* restore regs */ + regA = (uint16)(m3 >> 48); + regD = (uint16)(m3 >> 32); + regT = (e3 + 16384) | (s3 << 15); + if (m3 == 0 || e3 < -16383) + regT = regA = regD = 0; + return SCPE_OK; +} + +/* + * Division of two 48-bit floating point numbers. + * + * The contents of the floating accumulator are divided by the number + * in the effective floating word locations. Result in floating + * accumulator. If division by zero is attempted, the error indicator 2 + * is set to one. The error indicator 2 may be sensed by a BSKP instruc- + * tion (see BOP). The previous setting of the carry and overflow + * indicators are lost. + * Affected: (T), (A), (D), Z, C, O, Q, TG + */ +int +ins_fdv(int IR, int addr) +{ + struct fp f1, f2; + int s3, e3; + t_uint64 m3; + + /* Fetch from memory */ + mkfp48(&f1, rdmem(addr), rdmem(addr+1), rdmem(addr+2)); + + /* From registers */ + mkfp48(&f2, regT, regA, regD); + f2.m <<= 32; + + /* Initial sanity */ + if (f1.m == 0) { + regSTL |= STS_Z; + regT |= 077777; + regA = regD = 0177777; + intrpt14(IIE_V); + return SCPE_OK; + } + + /* calc */ + s3 = f1.s ^ f2.s; + e3 = f2.e - f1.e; + m3 = f2.m / f1.m; + if (f2.m%f1.m) /* "guard" bit */ + m3++; + + /* normalize (if needed) */ + if (m3 >= (1ULL << 32)) { + m3 >>= 1; + e3++; + } + + /* restore regs */ + regA = (uint16)(m3 >> 16); + regD = (uint16)m3; + regT = (e3 + 16384) | (s3 << 15); + if (f2.m == 0 || e3 < -16383) + regT = regA = regD = 0; + return SCPE_OK; +} + +/* + * Add two 48-bit numbers. + * + * The contents of the effective location and the two following locations + * are added to the floating accumulator with the result in the floating + * accumulator. The previous setting of the carry and overflow indicators + * are lost. + * Affected: (T), (A), (D), C, O, Q, TG + */ +static void +add48(struct fp *f1, struct fp *f2) +{ + struct fp *ft; + t_uint64 m3; + int scale, gbit; + + /* Ensure f1 is larger */ + if (f2->e > f1->e) + ft = f1, f1 = f2, f2 = ft; + + if ((scale = f1->e - f2->e) > 31) { + m3 = f1->m; + goto done; + } + + /* get shifted out guard bit */ + gbit = scale ? (((1LL << scale)-1) & f2->m) != 0 : 0; + f2->m >>= scale; + m3 = (f1->m + f2->m) | gbit; + if (m3 > 0xffffffffLL) { + m3 >>= 1; + f1->e++; + } + +done: regT = (f1->e + 16384) | (f1->s << 15); + regA = (uint16)(m3 >> 16); + regD = (uint16)m3; +} + +/* + * Subtract two 48-bit numbers. + * The numbers are of different sign. + * + * The contents of the effective location and the two following locations + * are subtracted from the floating accumulator with the result + * in the floating accumulator. The previous setting of the carry and + * overflow indicators are lost. + * Affected: (T), (A), (D), C, O, Q, TG + */ +static void +sub48(struct fp *f1, struct fp *f2, int addr) +{ + struct fp *ft; + t_uint64 m3; + int scale, gbit; + + /* Ensure f1 is bigger */ + if (f2->e > f1->e) + ft = f1, f1 = f2, f2 = ft; + + if ((scale = f1->e - f2->e) > 31) { + m3 = f1->m; + goto done; + } + + /* get shifted out sticky bit */ + gbit = scale ? (((1LL << scale)-1) & f2->m) != 0 : 0; + f2->m >>= scale; + f2->e = f1->e; + /* check for swap of mantissa */ + if (f2->m > f1->m) + ft = f1, f1 = f2, f2 = ft; + m3 = (f1->m - f2->m) | gbit; + + if (m3 == 0) { + regT = regA = regD = 0; + return; + } + while ((m3 & 0x80000000LL) == 0){ + m3 <<= 1; + f1->e--; + } + +done: regT = (f1->e + 16384) | (f1->s << 15); + regA = (uint16)(m3 >> 16); + regD = (uint16)m3; +} + +int +ins_fad(int IR, int addr) +{ + struct fp f1, f2; + + mkfp48(&f1, rdmem(addr), rdmem(addr+1), rdmem(addr+2)); + mkfp48(&f2, regT, regA, regD); + + if (f1.s ^ f2.s) + sub48(&f1, &f2, addr); + else + add48(&f1, &f2); + return SCPE_OK; +} + +int +ins_fsb(int IR, int addr) +{ + struct fp f1, f2; + + mkfp48(&f1, rdmem(addr), rdmem(addr+1), rdmem(addr+2)); + mkfp48(&f2, regT, regA, regD); + + f1.s ^= 1; /* swap sign of right op */ + + if (f1.s ^ f2.s) + sub48(&f1, &f2, addr); + else + add48(&f1, &f2); + return SCPE_OK; +} + +/* + * Add three numbers, setting overflow and carry as needed. + */ +uint16 +add3(uint16 a, uint16 d, uint16 c) +{ + int32 res; + + CLRC(); + CLRQ(); + res = a + d + c;; + + if (res > 0177777) + SETC(); + if (((a ^ d) & 0100000) == 0) { + /* sign bits equal */ + if ((a ^ res) & 0100000) + SETQ(), SETO(); /* result sign differ */ + } + return res; +} + +/* + * Multiply A with memory. Set flags. + */ +int +ins_mpy(int IR, int off) +{ + int res = (int)(int16)regA * (int)(int16)rdmem(off); + regA = res; + regSTL &= ~STS_Q; + if (res > 32767) + regSTL |= (STS_Q|STS_O); + return SCPE_OK; +} + +/* + * Jump or jump and link. + */ +int +ins_jmpl(int IR, int off) +{ + if (BIT12(IR)) + regL = regP+1; + regP = off-1; + return SCPE_OK; +} +/* + * Conditional jump. + */ +int +ins_cjp(int IR, int off) +{ + char cjpmsk[] = { 01, 01, 02, 02, 05, 05, 02, 01 }; + int n, i; + uint16 s; + + n = (IR & ND_CJPMSK) >> ND_CJPSH; + if (cjpmsk[n] & 04) + regX++; + s = n & 04 ? regX : regA; + i = (SEXT8(IR)-1); + if (cjpmsk[n] & 01) { /* pos/neg */ + if (BIT8(IR) == BIT15(s)) + regP += i; + } else if (cjpmsk[n] & 02) { /* zero/filled */ + if (BIT8(IR) == !!s) + regP += i; + } + return SCPE_OK; +} + +int +ins_skp(int IR, int off) +{ + int c_o, shc, n, rv = SCPE_OK; + uint16 s, d; + + if (IR & 0300) { /* extended instructions */ + rv = ins_skip_ext(IR); + } else { + s = ~(IR & 070 ? R[(IR & 070) >> 3] : 0); + d = IR & 07 ? R[IR & 07] : 0; + shc = d + s + 1; + c_o = (!BIT15(s ^ d) && BIT15(d ^ shc)); + + switch ((IR >> 8) & 03) { + case 0: /* eql */ n = ((shc & 0177777) == 0); break; + case 1: /* geq */ n = !BIT15(shc); break; + case 2: /* gre */ n = ((BIT15(shc) ^ c_o) == 0); break; + case 3: /* mgre */ n = (shc > 0177777); break; + } + if (BIT10(IR)) n = !n; + if (n) regP++; + } + return rv; +} + +int +ins_rop(int IR, int off) +{ + int n, rs, rd; + uint16 s, d; + + rs = (IR & 070) >> 3; + rd = IR & 07; + s = rs ? R[rs] : 0; + d = rd ? R[rd] : 0; + if (rs == 2) s++; + if (rd == 2) d++; + if (BIT6(IR)) d = 0; /* clear dest */ + if (BIT7(IR)) s = ~s; /* complement src */ + if (BIT10(IR)) { /* add source to destination */ + n = 0; + if (BIT8(IR)) n = 1; + else if (BIT9(IR)) n = BIT6(regSTL); + d = add3(s, d, n); + } else { /* logical instructons */ + if (BIT8(IR)) { + if (BIT9(IR)) d |= s; + else d &= s; + } else { + if (BIT9(IR) == 0) { /* swap */ + if (rs) R[rs] = d; + d = s; + } else + d ^= s; + } + } + if (rd) R[rd] = d; + if (rd == 2) regP--; + return SCPE_OK; +} + +/* + * Look for some device at dev. + */ +static int +iox_check(int dev) +{ +#ifdef TIMERHACK + if ((dev & 03777) == 011) { + rtccnt = 0; + return SCPE_OK; + } + if ((dev & 03777) == 013) { + rtc_int_enabled = regA & 1; + if ((regA >> 13) & 1) + rtc_dev_ready = 0; + return SCPE_OK; + } +#else + if ((dev & 0177774) == 010) + return iox_clk(dev); +#endif + if ((dev & 0177770) == 0300) + return iox_tty(dev); + if ((dev & 0177770) == 01560) + return iox_floppy(dev); + + intrpt14(IIE_IOX); + + return SCPE_OK; + +} + +static int +getoff(int ir) +{ + int ea; + + ea = BIT8(ir) ? regB : regP; + if (BIT10(ir) & !BIT9(ir)) + ea = 0; + ea += SEXT8(ir); + if (BIT9(ir)) + ea = rdmem(ea); + if (BIT10(ir)) + ea += regX; + return ea; +} + +/* + * bit-clear value in internal reg. + */ +static int +nd_mcl(int reg) +{ + int reason = SCPE_OK; + + switch (reg) { + case IR_STS: + regSTL &= ~(regA & 0377); + break; + case 006: /* PID */ + pid &= ~regA; + break; + + case 007: /* PIE */ + pie &= ~regA; + break; + + default: + reason = STOP_UNHINS; + } + return reason; +} + +/* + * Or-set value of internal reg. + */ +static int +nd_mst(int reg) +{ + int reason = SCPE_OK; + + switch (reg) { + case IR_STS: + regSTL |= (regA & 0377); + break; + case 006: /* PID */ + pid |= regA; + break; + case 007: /* PIE */ + pie |= regA; + break; + + default: + reason = STOP_UNHINS; + } + return reason; +} + +/* + * Set value of internal reg. + */ +static int +nd_trr(int reg) +{ + int reason = SCPE_OK; + + switch (reg) { + case IR_STS: + regSTL = regA & 0377; + break; + case IR_LMP: /* lamp reg */ + lmp = regA; + break; + case IR_PCR: /* PCR (paging control register) */ + mm_wrpcr(); + break; + case 005: /* IIE */ + iie = regA & 02776; + break; + case 006: /* PID */ + pid = regA; + break; + case 007: /* PIE */ + pie = regA; + break; + case IR_ECCR: + eccr = regA; + break; + default: + reason = STOP_UNHINS; + } + return reason; +} + +/* + * Read value of internal reg. + */ +static int +nd_tra(int reg) +{ + int reason = SCPE_OK; + + switch (reg) { + case IR_STS: /* STS */ + regA = regSTL | regSTH | (curlvl << 8); + break; + case IR_PGS: /* 3 */ + regA = 0; /* XXX */ + break; + case IR_PVL: /* 4 */ + regA = pvl; + break; + case IR_IIC: /* read IIC. Clears IIC and IID */ + regA = iic; + iic = iid = 0; + pid &= ~(1 << 14); + break; + case IR_PID: /* 6 */ + regA = pid; + break; + case IR_PIE: + regA = pie; + break; + case IR_CSR: /* CCR */ + regA = 04; /* cache disabled */ + break; + case 012: /* ALD */ + regA = ald; + break; + case 013: /* PES */ + regA = 0; /* XXX */ + break; + case 014: /* read back PCR */ + mm_rdpcr(); + break; + case 015: /* */ + regA = 0; /* XXX */ + break; + default: + reason = STOP_UNHINS; + } + return reason; +} + +int +highest_level() +{ + int i, d = pid & pie; + + for (i = 15; i >= 0; i--) + if (d & (1 << i)) + return i; + return 0; +} + +/* + * Find last bit set. + */ +int +fls(int msk) +{ + int i, j; + + if (msk == 0) + return -1; + for (i = 15, j = 0100000; i >= 0; i--, j >>= 1) + if (j & msk) + return i; + return -1; +} + +int +ffs(mask) + register int mask; +{ + register int bit; + + if (mask == 0) + return(0); + for (bit = 1; !(mask & 1); bit++) + mask >>= 1; + return(bit); +} + +/* + * Post an internal interrupt for the given source. + */ +void +intrpt14(int src) +{ + iid |= src; /* set detect flipflop */ + for (iic = 0; (src & 1) == 0; iic++, src >>= 1) + ; + + if (iid & iie) /* if internal int enabled, post priority int */ + pid |= (1 << 14); +} + +void +extint(int lvl, struct intr *ip) +{ + pid |= (1 << lvl); + lvl -= 10; + if (ip->inuse) + return; + ip->inuse = 1; + ip->next = ilnk[lvl]; + ilnk[lvl] = ip; +} + +/* + * Fetch ident from interrupting device. + * If no device interrupting, post IOX error. + */ +void +identrm(int id) +{ + struct intr *ip = ilnk[id-10]; + + if (ip == 0) { + intrpt14(IIE_IOX); + } else { + regA = ip->ident; + ilnk[id-10] = ip->next; + ip->next = NULL; + ip->inuse = 0; + if (ilnk[id-10] == 0) + pid &= ~(1 << id); + } +} + +#ifdef TIMERHACK +struct intr rtc_intx = { 0, 1 }; +void +chkrtc(void) +{ + if (rtccnt++ < 5001) + return; + rtccnt = 0; + rtc_dev_ready = 1; + if (rtc_int_enabled) { + extint(13, &rtc_intx); + } +} +#endif + +static void +hist_save(int ir) +{ + Hist_entry *hist_ptr; + + if (hist == NULL || hist_cnt == 0) + return; + if (++hist_p == hist_cnt) + hist_p = 0; + hist_ptr = &hist[hist_p]; + + hist_ptr->ir = ir; + hist_ptr->sts = regSTL | regSTH | (curlvl << 8); + hist_ptr->d = R[1]; + hist_ptr->p = R[2]; + hist_ptr->b = R[3]; + hist_ptr->l = R[4]; + hist_ptr->a = R[5]; + hist_ptr->t = R[6]; + hist_ptr->x = R[7]; +} + +t_stat +hist_set(UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + int32 i, lnt; + t_stat r; + + if (cptr == NULL) { + for (i = 0 ; i < hist_cnt ; i++) + hist[i].ir = HIST_IR_INVALID; + hist_p = 0; + return SCPE_OK; + } + + lnt = (int32) get_uint(cptr, 10, HIST_MAX, &r); + if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) + return SCPE_ARG; + + hist_p = 0; + if (hist_cnt) { + free(hist); + hist_cnt = 0; + hist = NULL; + } + + if (lnt) { + hist = (Hist_entry *) calloc(lnt, sizeof(Hist_entry)); + if (hist == NULL) + return SCPE_MEM; + hist_cnt = lnt; + } + return SCPE_OK; +} + +static void +hist_fprintf(FILE *fp, int itemNum, Hist_entry *hptr) +{ + t_value val; + + if (hptr == NULL) + return; + if (itemNum == 0) + fprintf(fp, "\n\n"); + fprintf(fp, "%06o: IR=%06o STS=%06o D=%06o B=%06o " + "L=%06o A=%06o T=%06o X=%06o ", + hptr->p & 0177777, hptr->ir & 0177777, hptr->sts & 0177777, + hptr->d & 0177777, hptr->b & 0177777, hptr->l & 0177777, + hptr->a & 0177777, hptr->t & 0177777, hptr->x & 0177777); + val = hptr->ir; + fprint_sym(fp, hptr->p, &val, 0, SWMASK ('M')); + fprintf(fp, "\n"); +} + +static void +ioxprint(FILE *fp, Hist_entry *hptr, int ioaddr) +{ + fprintf(fp, "%06o: iox(%06o) %s A=%06o\n", + hptr->p, ioaddr & 0177777, ioaddr & 1 ? "out" : "in ", + hptr->a & 0177777); +} + +t_stat +hist_show(FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + int32 k, di, lnt; + CONST char *cptr = (CONST char *) desc; + t_stat r; + Hist_entry *hptr; + + if (hist_cnt == 0) + return SCPE_NOFNC; + + if (cptr) { /* number of entries specified */ + lnt = (int32)get_uint(cptr, 10, hist_cnt, &r); + if ((r != SCPE_OK) || (lnt == 0)) + return SCPE_ARG; + } else + lnt = hist_cnt; + + di = hist_p - lnt; + if (di < 0) + di = di + hist_cnt; + + for (k = 0 ; k < lnt ; ++k) { + hptr = &hist[(++di) % hist_cnt]; + if (sim_switches & SWMASK('I')) { + /* print iox instructions */ + if ((hptr->ir & ND_MEMMSK) == ND_IOX) + ioxprint(st, hptr, hptr->ir & ~ND_MEMMSK); + if (hptr->ir == ND_MIS_IOXT) + ioxprint(st, hptr, hptr->t); + } else { + if (hptr->ir != HIST_IR_INVALID) + hist_fprintf(st, k, hptr); + } + } + return SCPE_OK; +} + diff --git a/ND100/nd100_defs.h b/ND100/nd100_defs.h new file mode 100644 index 00000000..d956cb90 --- /dev/null +++ b/ND100/nd100_defs.h @@ -0,0 +1,263 @@ +/* + * 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. + */ + +/* + * masks for instruction matching. + */ +#define ND_MEMMSK 0174000 +#define ND_MEMSH 11 +#define ND_CJPMSK 0003400 +#define ND_CJPSH 8 +#define ND_IOXMSK 0003777 +#define ND_BOPSH 7 +#define ND_BOPMSK 0003600 +#define ND_ROPMSK 0177700 + + +/* mem instructions args */ +#define NDMEM_B 00400 +#define NDMEM_I 01000 +#define NDMEM_X 02000 +#define NDMEM_OMSK 0377 + +/* + * Major group of instructions (ND10 + ND100) + * All up to CJP (+JPL) uses the memory address syntax. + */ + +#define ND_STZ 0000000 +#define ND_STA 0004000 +#define ND_STT 0010000 +#define ND_STX 0014000 +#define ND_STD 0020000 +#define ND_LDD 0024000 +#define ND_STF 0030000 +#define ND_LDF 0034000 +#define ND_MIN 0040000 +#define ND_LDA 0044000 +#define ND_LDT 0050000 +#define ND_LDX 0054000 +#define ND_ADD 0060000 +#define ND_SUB 0064000 +#define ND_AND 0070000 +#define ND_ORA 0074000 +#define ND_FAD 0100000 +#define ND_FSB 0104000 +#define ND_FMU 0110000 +#define ND_FDV 0114000 +#define ND_MPY 0120000 +#define ND_JMP 0124000 +#define ND_CJP 0130000 +#define ND_JPL 0134000 +#define ND_SKP 0140000 +#define ND_ROP 0144000 +#define ND_MIS 0150000 +#define ND_SHT 0154000 +#define ND_NA 0160000 +#define ND_IOX 0164000 +#define ND_ARG 0170000 +#define ND_BOP 0174000 + +#define ND_SKP_CLEPT 0140301 +#define ND_SKP_EXR 0140600 +#define ND_SKP_BFILL 0140130 +#define ND_SKP_MOVB 0140131 +#define ND_SKP_MOVBF 0140132 +#define ND_SKP_RMPY 0141200 +#define ND_SKP_RDIV 0141600 +#define ND_SKP_LBYT 0142200 +#define ND_SKP_SBYT 0142600 +#define ND_SKP_MIX3 0143200 +#define ND_SKP_IDENT10 0143604 +#define ND_SKP_IDENT11 0143611 +#define ND_SKP_IDENT12 0143622 +#define ND_SKP_IDENT13 0143643 + +#define ISEXR(x) (((x) & 0177707) == ND_SKP_EXR) + +#define ND_MIS_TRA 0150000 +#define ND_MIS_TRR 0150100 +#define ND_MIS_MCL 0150200 +#define ND_MIS_MST 0150300 +#define ND_MIS_TRMSK 0177700 +#define ND_MIS_NLZ 0151400 +#define ND_MIS_DNZ 0152000 +#define ND_MIS_LRB 0152600 +#define ND_MIS_SRB 0152402 +#define ND_MIS_RBMSK 0177607 +#define ND_MIS_IRW 0153400 +#define ND_MIS_IRR 0153600 +#define ND_MIS_IRRMSK 0177600 + +#define ND_MON 0153000 +#define ND_WAIT 0151000 +#define ND_MONMSK 0177400 + +#define ND_MIS_IOF 0150401 +#define ND_MIS_ION 0150402 +#define ND_MIS_POF 0150404 +#define ND_MIS_PIOF 0150405 +#define ND_MIS_SEX 0150406 +#define ND_MIS_REX 0150407 +#define ND_MIS_PON 0150410 +#define ND_MIS_PION 0150412 +#define ND_MIS_IOXT 0150415 +#define ND_MIS_EXAM 0150416 +#define ND_MIS_DEPO 0150417 + +/* Internal registers */ +#define IR_STS 001 /* Status reg (as in register stack) */ +#define IR_OPR 002 /* Operator reg */ +#define IR_LMP 002 /* Display reg */ +#define IR_PGS 003 /* paging status reg */ +#define IR_PCR 003 /* paging control reg */ +#define IR_PVL 004 /* Previous level */ +#define IR_IIC 005 /* Internal interrupt code */ +#define IR_IIE 005 /* Internal interrupt enable */ +#define IR_PID 006 /* Priority interrupt detect */ +#define IR_PIE 007 /* Priority interrupt enable */ +#define IR_CSR 010 /* Cache status reg */ +#define IR_PCR14 014 /* paging control reg */ +#define IR_ECCR 015 /* Error Correction Control Register */ + +/* internal interrupt enable register */ +#define IIE_MC 0000002 /* Monitor call */ +#define IIE_PV 0000004 /* Protect Violation */ +#define IIE_PF 0000010 /* Page fault */ +#define IIE_II 0000020 /* Illegal instruction */ +#define IIE_V 0000040 /* Error indicator */ +#define IIE_PI 0000100 /* Privileged instruction */ +#define IIE_IOX 0000200 /* IOX error */ +#define IIE_PTY 0000400 /* Memory parity error */ +#define IIE_MOR 0001000 /* Memory out of range */ +#define IIE_POW 0002000 /* Power fail interrupt */ + +/* Status register bits */ +#define STS_PTM 0000001 /* page table mode */ +#define STS_TG 0000002 /* floating point rounding mode */ +#define STS_K 0000004 +#define STS_Z 0000010 +#define STS_Q 0000020 +#define STS_O 0000040 +#define STS_C 0000100 +#define STS_M 0000200 +#define STS_N100 0010000 /* Nord-100 */ +#define STS_SEXI 0020000 /* Extended addressing enabled */ +#define STS_PONI 0040000 /* Paging turned on */ +#define STS_IONI 0100000 /* interrupts turned on */ + +#define ISION() BIT15(regSTH) +#define ISPON() BIT14(regSTH) +#define ISSEX() BIT13(regSTH) + +/* paging bits */ +#define PT_WIP 0010000 +#define PT_PGU 0004000 + +/* Simulator-specific stuff */ +#define rnSTS 0 +#define rnD 1 +#define rnP 2 +#define rnB 3 +#define rnL 4 +#define rnA 5 +#define rnT 6 +#define rnX 7 +#define regSTL R[0] /* Only low 8 bits valid */ +#define regD R[1] +#define regP R[2] +#define regB R[3] +#define regL R[4] +#define regA R[5] +#define regT R[6] +#define regX R[7] + +extern uint16 PM[]; +extern uint16 R[8]; +extern uint16 regSTH; /* common for all levels */ +extern int ald; /* Automatic load descriptor - set by boot */ +extern int curlvl; + +/* + * interrupt link per device. + */ +struct intr { + struct intr *next; + short ident; + short inuse; +}; + +extern DEVICE cpu_dev; +extern DEVICE mm_dev; +extern DEVICE tti_dev; +extern DEVICE tto_dev; +extern DEVICE floppy_dev; +extern DEVICE clk_dev; + +int iox_floppy(int addr); +int iox_tty(int addr); +int iox_clk(int addr); + +#define M_PHYS 0 +#define M_PT 1 +#define M_APT 2 +#define M_FETCH 3 + +uint16 rdmem(int addr/* , int how*/); +uint8 rdbyte(int vaddr, int lr/* , int how*/); +void wrmem(int addr, int val/* , int how*/); +void wrbyte(int vaddr, int val, int lr/* , int how*/); +void mm_wrpcr(void); +void mm_rdpcr(void); + +void extint(int lvl, struct intr *intr); + +#define STOP_UNHIOX 1 +#define STOP_UNHINS 2 +#define STOP_CKSUM 3 +#define STOP_BP 4 +#define STOP_WAIT 5 + +/* Useful bit extraction macros */ +#define BIT0(x) ((x) & 1) +#define BIT1(x) (((x) >> 1) & 1) +#define BIT2(x) (((x) >> 2) & 1) +#define BIT3(x) (((x) >> 3) & 1) +#define BIT4(x) (((x) >> 4) & 1) +#define BIT5(x) (((x) >> 5) & 1) +#define BIT6(x) (((x) >> 6) & 1) +#define BIT7(x) (((x) >> 7) & 1) +#define BIT8(x) (((x) >> 8) & 1) +#define BIT9(x) (((x) >> 9) & 1) +#define BIT10(x) (((x) >> 10) & 1) +#define BIT11(x) (((x) >> 11) & 1) +#define BIT12(x) (((x) >> 12) & 1) +#define BIT13(x) (((x) >> 13) & 1) +#define BIT14(x) (((x) >> 14) & 1) +#define BIT15(x) (((x) >> 15) & 1) +#define BIT30(x) (((x) >> 30) & 1) +#define BIT31(x) (((x) >> 31) & 1) + +#define SEXT8(x) ((x & 0377) > 127 ? (int)(x & 0377) - 256 : (x & 0377)) diff --git a/ND100/nd100_floppy.c b/ND100/nd100_floppy.c new file mode 100644 index 00000000..d7339ce0 --- /dev/null +++ b/ND100/nd100_floppy.c @@ -0,0 +1,358 @@ +/* + * 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 +#include + +#include "sim_defs.h" + +#include "nd100_defs.h" + +/* + * Floppy and Streamer Controller (3112). + * ND documentation ND-11.021.1 + * + * Currently only 5 1/4" DS/DD floppies implemented (no streamer). + * + * The device uses eight IOX addresses, but the transfer commands + * are given in a command block of 12 words in memory. + */ + +t_stat floppy_svc(UNIT *uptr); +t_stat floppy_reset (DEVICE *dptr); +t_stat floppy_boot (int32 unitno, DEVICE *dptr); +t_stat floppy_attach (UNIT *uptr, CONST char *cptr); +static int floppy_excmd(void); + +#define FL_NTR 80 /* # tracks/side */ +#define FL_NSC 8 /* # sectors/track */ +#define FL_NSD 2 /* # sides */ +#define FL_NBY 1024 /* # bytes/sector */ + +#define FL_SZ (FL_NTR*FL_NTR*FL_NSD*FL_NBY) + +/* hardware status reg flags */ +#define FL_ST_IE 0000002 /* interrupt enable (RFT) */ +#define FL_ST_ACT 0000004 /* device active */ +#define FL_ST_RDY 0000010 /* device ready for transfer (RFT) */ +#define FL_ST_ERR 0000020 /* OR of errors */ +#define FL_ST_HE 0000100 /* Hard error (DMA) */ +#define FL_ST_DENS 0100000 /* Dual density ctlr */ + +/* hardware control word */ +#define FL_CW_IE 0000002 /* interrupt enable (RFT) */ +#define FL_CW_AUTO 0000004 /* Activate autoload */ +#define FL_CW_TEST 0000010 /* Test mode */ +#define FL_CW_CLR 0000020 /* Device clear */ +#define FL_CW_ENSTR 0000040 /* Enable streamer */ +#define FL_CW_FCE 0000400 /* Fetch Command and Execute */ + +static int fl_rdata; /* devno + 0, read data */ +static int fl_rstatus; /* devno + 2 (+4) read status */ +static int fl_lcw; /* devno + 3 load control word */ +static int fl_lph; /* devno + 5 load pointer high */ +static int fl_lpl; /* devno + 7 load pointer low */ + +/* + * The command block (CB) is DMAed from ND100 memory. + * Word 0-5 are the command part, 06-13 are the status part. + * + * 15 8 7 0 + * +---------------------------------------------+ + * 0 | Command word | + * +---------------------------------------------+ + * 1 | Device address bit 15-0 | + * +----------------------+----------------------+ + * 2 | Device addr bit 23-16| Memory addr bit 23-16| + * +----------------------+----------------------+ + * 3 | Memory addr bit 15-0 | + * +----------------------+----------------------+ + * 4 | Options | Word count bit 23-16 | + * +----------------------+----------------------+ + * 5 | Word count (or record count) bit 15-0 | + * +---------------------------------------------+ + * 6 | Status 1 | + * +---------------------------------------------+ + * 7 | Status 2 | + * +---------------------------------------------+ + * 10 | Empty | Last addr 23-16 | + * +---------------------------------------------+ + * 11 | last memory address 15-0 | + * +---------------------------------------------+ + * 12 | Empty | Rem. words 23-16 | + * +---------------------------------------------+ + * 13 | Remaining words 15-0 | + * +---------------------------------------------+ + * + */ + +/* CB offsets */ +#define CB_CW 000 +#define CB_DAL 001 +#define CB_DAHMAH 002 +#define CB_MAL 003 +#define CB_OPTWCH 004 +#define CB_WCL 005 +#define CB_ST1 006 +#define CB_ST2 007 +#define CB_LAH 010 +#define CB_LAL 011 +#define CB_REMWH 012 +#define CB_REMWL 013 + +/* Options word (004) */ +#define CB_OPT_WC 0100000 /* set if word count in 4/5, else record */ + +/* Command word (000) */ +#define CW_FL_RD 0000000 /* Read data */ +#define CW_FL_WR 0000001 /* Write data */ +#define CW_FL_RDFMT 0000042 /* Read format */ +#define CW_FL_CMDMSK 077 /* mask for command */ +#define CW_FL_SELSH 6 /* shift for unit */ +#define CW_FL_1K 0001400 /* 1K sectors */ +#define CW_FL_DS 0002000 /* Double sided */ +#define CW_FL_DD 0004000 /* Double density */ + +/* Status 2 */ +#define ST2_FL_BS1K 0000003 /* 1k sectors */ +#define ST2_FL_DS 0000004 /* Double sided */ +#define ST2_FL_DD 0000010 /* Double density */ +#define ST2_FL_514 0000020 /* 5 1/4" floppy */ + +/* soft data structures (for simh) */ +#define state u3 /* current unit state */ +#define U_RDY 00 /* unit idling */ +#define U_READ 01 /* unit reading */ +#define U_WRITE 02 /* unit writing */ +#define U_RDFMT 03 /* Read format */ + +#define devaddr u4 /* unit offset (in words) */ +#define wcnt u5 /* word count */ +#define memaddr u6 /* place in memory */ + +UNIT floppy_unit[] = { + { UDATA (&floppy_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, FL_SZ) }, + { UDATA (&floppy_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, FL_SZ) }, + { UDATA (&floppy_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, FL_SZ) }, + { UDATA (&floppy_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, FL_SZ) }, + { 0 } +}; + +REG floppy_reg[] = { + { ORDATA (RDATA, fl_rdata, 16) }, + { ORDATA (RSTATUS, fl_rstatus, 16) }, + { ORDATA (LCW, fl_lcw, 16) }, + { ORDATA (LPH, fl_lph, 16) }, + { ORDATA (LPL, fl_lpl, 16) }, + { NULL } +}; + +MTAB floppy_mod[] = { + { MTAB_XTD|MTAB_VUN, 0, "write enabled", "WRITEENABLED", + &set_writelock, &show_writelock, NULL, + "Write enable floppy drive" }, + { 0 } +}; + +DEVICE floppy_dev = { + "FLOPPY", floppy_unit, floppy_reg, floppy_mod, + 1, 8, 12, 1, 8, 16, + NULL, NULL, &floppy_reset, + &floppy_boot, NULL, NULL, + NULL, DEV_DISABLE +}; + +struct intr floppy0_int = { 0, 021 }; + +/* + * Floppy called via iox instruction. + */ +int +iox_floppy(int addr) +{ + int n; + int rv = 0; + + + switch (addr & 07) { + case 0: /* read data */ + regA = 0; + break; + + case 1: + break; + + case 2: + regA = fl_rstatus; + break; + + case 3: + n = regA; + if (n & FL_CW_FCE) { + rv = floppy_excmd(); + break; + } + if (n & FL_CW_IE) { /* Interrupt enable */ + if ((fl_rstatus & (FL_CW_IE|FL_ST_RDY)) == FL_ST_RDY) + extint(11, &floppy0_int); + fl_rstatus |= FL_ST_IE; + break; + } + if (n & FL_CW_CLR) { /* reset */ + break; + } + return STOP_UNHIOX; + break; + + case 5: + fl_lph = regA; + break; + + case 7: + fl_lpl = regA; + break; + + default: + rv = STOP_UNHIOX; + break; + } + + return rv; +} + +t_stat +floppy_reset(DEVICE *dptr) +{ + fl_rstatus = FL_ST_DENS | FL_ST_RDY; + return 0; +} + +t_stat +floppy_svc(UNIT *uptr) +{ + unsigned char *wp; + int i, j; + int cbaddr = fl_lpl + ((fl_lph & 0377) << 8); + int lah = 0, lal = 0; + + if ((fl_rstatus & FL_ST_ACT) == 0) + return STOP_UNHIOX; + + switch (uptr->state) { + case U_READ: + wp = malloc(uptr->wcnt * 2); + if (fseek(uptr->fileref, uptr->devaddr * 2, SEEK_SET) < 0) + goto err; + if (sim_fread(wp, uptr->wcnt, 2, uptr->fileref) < 0) + goto err; + for (i = 0, j = 0; i < uptr->wcnt; i++, j += 2) + wrmem(uptr->memaddr+i, (wp[j] << 8) | wp[j+1]); + lah = (uptr->memaddr + uptr->wcnt) >> 16; + lal = (uptr->memaddr + uptr->wcnt) & 0177777; + free(wp); + break; + + case U_RDFMT: + break; + + case U_WRITE: + default: + return STOP_UNHIOX; + } + + wrmem(cbaddr+CB_ST1, FL_ST_RDY); + wrmem(cbaddr+CB_ST2, + ST2_FL_BS1K|ST2_FL_DS|ST2_FL_DD|ST2_FL_514); + wrmem(cbaddr+CB_LAH, lah); + wrmem(cbaddr+CB_LAL, lal); + wrmem(cbaddr+CB_REMWH, 0); + wrmem(cbaddr+CB_REMWL, 0); + + fl_rstatus &= ~FL_ST_ACT; + fl_rstatus |= FL_ST_RDY; + if (fl_rstatus & FL_ST_IE) + extint(11, &floppy0_int); + + return SCPE_OK; + +err: + return STOP_UNHIOX; +} + +t_stat +floppy_boot(int32 unitno, DEVICE *dptr) +{ + printf("floppy_boot \n"); + return 1; +} + +static int +floppy_excmd(void) +{ + UNIT *unit; + int cw, u, cmd; + int cbaddr = fl_lpl + ((fl_lph & 0377) << 8); + + cw = rdmem(cbaddr+CB_CW); + u = (cw >> CW_FL_SELSH) & 03; + cmd = cw & CW_FL_CMDMSK; + + unit = &floppy_unit[u]; + if ((unit->flags & UNIT_ATT) == 0) + goto err; /* floppy not inserted */ + + /* XXX check disk size, word count etc... */ + unit->memaddr = ((rdmem(cbaddr+CB_DAHMAH) & 0377) << 16) | rdmem(cbaddr+CB_MAL); + unit->wcnt = ((rdmem(cbaddr+CB_OPTWCH) & 0377) << 16) | rdmem(cbaddr+CB_WCL); + unit->devaddr = ((rdmem(cbaddr+CB_DAHMAH) & 0177400) << 8) | + rdmem(cbaddr+CB_DAL); + + if (cmd == CW_FL_RDFMT) { + unit->state = U_RDFMT; + } else if (cmd == CW_FL_RD || cmd == CW_FL_WR) { + if (cmd == CW_FL_WR) + goto err; /* floppy write protected */ + + if ((cw & CW_FL_1K) != CW_FL_1K) + goto err; /* Require 1K sectors */ + if ((cw & (CW_FL_DS|CW_FL_DD)) != (CW_FL_DS|CW_FL_DD)) + goto err; /* Must be double sided/double density */ + + unit->state = U_READ; + } else + goto err; + + sim_activate(&floppy_unit[u], 10); + fl_rstatus &= ~FL_ST_RDY; + fl_rstatus |= FL_ST_ACT; + return SCPE_OK; + +err: + return STOP_UNHIOX; +} diff --git a/ND100/nd100_mm.c b/ND100/nd100_mm.c new file mode 100644 index 00000000..93b74fa2 --- /dev/null +++ b/ND100/nd100_mm.c @@ -0,0 +1,195 @@ +/* + * 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" + +#define MAXMEMSIZE 512*1024 + +t_stat mm_reset(DEVICE *dptr); + +uint16 PM[MAXMEMSIZE]; +uint16 PCR[16]; /* Paging control register */ +uint16 ptmap[4][64]; /* protection */ +uint16 pmmap[4][64]; /* memory mapping */ + +#define ISDIS() (mm_dev.flags & DEV_DIS) + +UNIT mm_unit = { UDATA(NULL, UNIT_FIX+UNIT_DISABLE+UNIT_BINK, 0) }; + +REG mm_reg[] = { + { BRDATA(PCR, PCR, 8, 16, 16) }, + { NULL } +}; + + +DEVICE mm_dev = { + "MM", &mm_unit, mm_reg, 0, + 1, 8, 16, 1, 8, 16, + 0, 0, &mm_reset, + NULL, NULL, NULL, + NULL, DEV_DISABLE+DEV_DIS +}; + +/* + * Read a byte. 0 in lr is left byte, 1 is right byte. + */ +uint8 +rdbyte(int vaddr, int lr/* , int how*/) +{ + uint16 val = rdmem(vaddr); + + return lr ? val & 0377 : val >> 8; +} + +/* + * Write a byte. 0 in lr is left byte, 1 is right byte. + */ +void +wrbyte(int vaddr, int val, int lr/* , int how*/) +{ + uint16 ov = rdmem(vaddr); + + val &= 0377; /* sanity */ + ov = lr ? (ov & 0177400) | val : (ov & 0377) | (val << 8); + wrmem(vaddr, ov); +} + +/* + * Access shadow memory. if: + * sexi == 0 && v >= 0177400 && (myring == 3 || pon == 0) + * or + * sexi == 1 && v >= 0177000 && (myring == 3 || pon == 0) + */ +static int +is_shadow(int vaddr) +{ + if ((PCR[curlvl] & 03) < 3 && ISPON()) + return 0; /* not valid */ + if (ISSEX()) + return 1; + return (vaddr >= 0177400); +} + +/* + * Fetch a word from the shadow mem. + */ +static int +shadowrd(int v) +{ + int pt; + int x = 0; + + if (ISSEX()) + x = v & 1, v >>= 1; + pt = (v >> 6) & 03; + v &= 077; + + if (ISSEX()) + return x ? pmmap[pt][v] : ptmap[pt][v]; + return ptmap[pt][v]|pmmap[pt][v]; +} + +/* + * Write a word to the shadow mem. + */ +static void +shadowwr(int v, int dat) +{ + int pt; + int x = 0; + + if (ISSEX()) + x = v & 1, v >>= 1; + pt = (v >> 6) & 03; + v &= 077; + + if (ISSEX()) { + if (x) + pmmap[pt][v] = dat; + else + ptmap[pt][v] = dat; + } else { + pmmap[pt][v] = dat & 0777; + ptmap[pt][v] = dat & 0177000; + } +} + + +uint16 +rdmem(int vaddr/* , int how*/) +{ + int pt; + + vaddr &= 0177777; + + if ((vaddr >= 0177000) && is_shadow(vaddr)) + return shadowrd(vaddr); + /* Mark page as read */ + if (ISPON()) { + pt = (PCR[curlvl] >> 8) & 03; + ptmap[pt][vaddr >> 10] |= PT_PGU; + } + +// if (ISPON() == 0) + return PM[vaddr]; + +} + +void +wrmem(int vaddr, int val/* , int how*/) +{ + vaddr &= 0177777; + if ((vaddr >= 0177000) && is_shadow(vaddr)) { + shadowwr(vaddr, val); + return; + } + PM[vaddr] = val; +} + +void +mm_wrpcr() +{ + if (ISDIS()) + return; + PCR[(regA >> 3) & 017] = regA & 03603; +} + +void +mm_rdpcr() +{ + if (ISDIS()) + return; + regA = PCR[(regA >> 3) & 017]; +} + + +t_stat +mm_reset(DEVICE *dptr) +{ + return 0; +} diff --git a/ND100/nd100_stddev.c b/ND100/nd100_stddev.c new file mode 100644 index 00000000..cb9e2f79 --- /dev/null +++ b/ND100/nd100_stddev.c @@ -0,0 +1,292 @@ +/* + * 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 "sim_tmxr.h" + +#include "nd100_defs.h" + +struct intr tti_int = { 0, 1 }; +struct intr tto_int = { 0, 1 }; + +MTAB ttx_mod[]; + +int tti_status, tti_ctrl; +int tto_status, tto_ctrl; + +t_stat tti_svc(UNIT *uptr); +t_stat tto_svc(UNIT *uptr); +t_stat tti_reset(DEVICE *dptr); +t_stat tto_reset(DEVICE *dptr); +t_stat tty_setpar(UNIT *uptr); + +#define TT_ICTRL_EIRDY 0000001 /* enable int on dev ready */ +#define TT_ICTRL_EIERR 0000002 /* enable int on error */ +#define TT_ICTRL_ACT 0000004 /* set device active */ + +#define TT_ISTAT_IRDY 0000001 /* device ready gives interrupt */ +#define TT_ISTAT_RDY 0000010 /* device ready for transfer */ + +#define TT_OCTRL_EIRDY 0000001 /* enable int on dev ready */ +#define TT_OCTRL_EIERR 0000002 /* enable int on error */ +#define TT_OCTRL_ACT 0000004 /* set device active */ + +#define TT_OSTAT_IRDY 0000001 /* device ready gives interrupt */ +#define TT_OSTAT_RDY 0000010 /* device ready for transfer */ + +UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }; + +REG tti_reg[] = { + { ORDATA(BUF, tti_unit.buf, 8) }, + { ORDATA(ISTATUS, tti_status, 16) }, + { ORDATA(ICTRL, tti_ctrl, 16) }, + { DRDATA (TIME, tti_unit.wait, 24), }, + { NULL } +}; + +DEVICE tti_dev = { + "TTI", &tti_unit, tti_reg, ttx_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &tti_reset, + NULL, NULL, NULL, + NULL, 0 +}; + +UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }; + +REG tto_reg[] = { + { ORDATA(OSTATUS, tto_status, 16) }, + { ORDATA(OCTRL, tto_ctrl, 16) }, + { DRDATA(POS, tto_unit.pos, T_ADDR_W), PV_LEFT }, + { DRDATA(TIME, tto_unit.wait, 24), REG_NZ + PV_LEFT }, + { NULL } +}; + +MTAB ttx_mod[] = { +#if 0 + { TT_PAR, TT_PAR_EVEN, "even parity", "EVEN", &tty_setpar }, + { TT_PAR, TT_PAR_ODD, "odd parity", "ODD", &tty_setpar }, + { TT_PAR, TT_PAR_MARK, "mark parity", "MARK", &tty_setpar }, + { TT_PAR, TT_PAR_SPACE, "no parity", "NONE", &tty_setpar }, +#endif + { 0 } +}; + +DEVICE tto_dev = { + "TTO", &tto_unit, tto_reg, ttx_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &tto_reset, + NULL, NULL, NULL, + NULL, 0 +}; + +t_stat +tti_reset(DEVICE *dptr) +{ + sim_cancel(&tti_unit); + return SCPE_OK; +} + +t_stat +tto_reset(DEVICE *dptr) +{ + sim_cancel(&tto_unit); + tto_status |= TT_OSTAT_RDY; + return SCPE_OK; +} + +t_stat +tti_svc(UNIT *uptr) +{ + int temp; + + sim_activate (&tti_unit, tti_unit.wait); + if ((temp = sim_poll_kbd()) < SCPE_KFLAG) + return temp; + + tti_unit.buf = temp & 0177; + if (tti_ctrl & TT_ICTRL_ACT) { + tti_status |= TT_ISTAT_RDY; + if (tti_ctrl & TT_ICTRL_EIRDY) + extint(12, &tti_int); + } + + return SCPE_OK; +} + +t_stat +tto_svc(UNIT *uptr) +{ + int32 c; + t_stat r; + + c = tto_unit.buf & 0177; + if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output; error? */ + sim_activate (uptr, uptr->wait); /* try again */ + return ((r == SCPE_STALL)? SCPE_OK : r);/* !stall? report */ + } + tto_status |= TT_OSTAT_RDY; + if (tto_ctrl & TT_OCTRL_EIRDY) + extint(10, &tto_int); + return SCPE_OK; +} + + +int +iox_tty(int addr) +{ + int rv = 0; + + /* + * First four addresses are input, following four are output. + */ + switch (addr & 07) { + case 0: /* read data */ + regA = tti_unit.buf; + tti_status &= ~TT_ISTAT_RDY; + break; + + case 1: /* Ignored */ + break; + + case 2: /* read input status reg */ + regA = tti_status; + break; + + case 3: /* Write control reg */ + if ((tti_ctrl & TT_ICTRL_ACT) == 0 && (regA & TT_ICTRL_ACT)) + sim_activate (&tti_unit, tti_unit.wait); + if ((regA & TT_ICTRL_ACT) == 0) + sim_cancel(&tti_unit); + tti_ctrl = regA; + if (tti_ctrl & TT_ICTRL_EIRDY) + tti_status |= TT_ISTAT_IRDY; + else + tti_status &= ~TT_ISTAT_IRDY; + break; + + case 4: /* Ignored */ + break; + + case 5: /* Write data */ + tto_unit.buf = regA & 0177; + tto_status &= ~TT_OSTAT_RDY; + sim_activate (&tto_unit, tto_unit.wait); + break; + + case 6: /* Read output status */ + regA = tto_status; + break; + + case 7: /* Write output control reg */ + tto_ctrl = regA; + if (tto_ctrl & TT_OCTRL_ACT) + tto_status |= TT_OSTAT_RDY; + else + tto_status &= ~TT_OSTAT_RDY; + if (tto_ctrl & TT_OCTRL_EIRDY) + tto_status |= TT_OSTAT_IRDY; + else + tto_status &= ~TT_OSTAT_IRDY; + break; + } + + return rv; +} + +/* + * Real-time clock. + */ +#define US_PER_CLK 20000 +#define CLK_PER_SEC 50 + +int int_enabled, dev_ready; + +struct intr rtc_int = { 0, 1 }; + +t_stat clk_svc(UNIT *uptr); + +UNIT clk_unit = { UDATA (&clk_svc, 0, 0) }; + +REG clk_reg[] = { + { FLDATA (INTENB, int_enabled, 0) }, + { FLDATA (DEVRDY, dev_ready, 0) }, + { NULL } +}; + +MTAB clk_mod[] = { + { 0 } +}; + +DEVICE clk_dev = { + "RTC", &clk_unit, clk_reg, clk_mod, + 1, 0, 0, 0, 0, 0, + NULL, NULL, NULL, + NULL, NULL, NULL, + 0, 0 +}; + +int +iox_clk(int addr) +{ + int rv = 0; + + switch (addr & 3) { + case 0: /* return 0 in A */ + regA = 0; + break; + case 1: /* Reset counter */ + sim_cancel(&clk_unit); + if (!sim_is_active(&clk_unit)) + sim_activate(&clk_unit, sim_rtc_init(US_PER_CLK)); + break; + case 2: /* read status */ + regA = (dev_ready << 3) | int_enabled; + break; + + case 3: /* set status */ + sim_cancel(&clk_unit); + if (!sim_is_active(&clk_unit)) + sim_activate(&clk_unit, sim_rtc_init(US_PER_CLK)); + int_enabled = regA & 1; + if (BIT13(regA)) + dev_ready = 0; + break; + + default: + rv = STOP_UNHIOX; + } + return rv; +} + +t_stat +clk_svc(UNIT *uptr) +{ + sim_activate(&clk_unit, sim_rtc_calb(US_PER_CLK)); + dev_ready = 1; + if (int_enabled) + extint(13, &rtc_int); + return SCPE_OK; +} diff --git a/ND100/nd100_sys.c b/ND100/nd100_sys.c new file mode 100644 index 00000000..50f58265 --- /dev/null +++ b/ND100/nd100_sys.c @@ -0,0 +1,351 @@ +/* + * 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[2]; +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", +}; + +static int mlp; + +static int +gb(FILE *f) +{ + int w; + + if (f == NULL) + return rdmem(mlp++); + 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; + wrmem(i, s); + } + 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++) { + wrmem(E+i, gw(f)); + s += rdmem(E+i); + } + 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" +}; + +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_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; +} diff --git a/Visual Studio Projects/Simh.sln b/Visual Studio Projects/Simh.sln index b3a3b940..7c472fec 100755 Binary files a/Visual Studio Projects/Simh.sln and b/Visual Studio Projects/Simh.sln differ diff --git a/Visual Studio Projects/nd100.vcproj b/Visual Studio Projects/nd100.vcproj new file mode 100644 index 00000000..16c0ba47 Binary files /dev/null and b/Visual Studio Projects/nd100.vcproj differ diff --git a/makefile b/makefile index b282f0a6..f474487f 100644 --- a/makefile +++ b/makefile @@ -1439,6 +1439,11 @@ PDP1 = ${PDP1D}/pdp1_lp.c ${PDP1D}/pdp1_cpu.c ${PDP1D}/pdp1_stddev.c \ PDP1_OPT = -I ${PDP1D} ${DISPLAY_OPT} $(PDP1_DISPLAY_OPT) +ND100D = ${SIMHD}/ND100 +ND100 = ${ND100D}/nd100_sys.c ${ND100D}/nd100_cpu.c ${ND100D}/nd100_floppy.c \ + ${ND100D}/nd100_stddev.c ${ND100D}/nd100_mm.c +ND100_OPT = -I ${ND100D} + NOVAD = ${SIMHD}/NOVA NOVA = ${NOVAD}/nova_sys.c ${NOVAD}/nova_cpu.c ${NOVAD}/nova_dkp.c \ ${NOVAD}/nova_dsk.c ${NOVAD}/nova_lp.c ${NOVAD}/nova_mta.c \ @@ -2187,7 +2192,7 @@ ALL = pdp1 pdp4 pdp7 pdp8 pdp9 pdp15 pdp11 pdp10 \ microvax2000 infoserver100 infoserver150vxt microvax3100 microvax3100e \ vaxstation3100m30 vaxstation3100m38 vaxstation3100m76 vaxstation4000m60 \ microvax3100m80 vaxstation4000vlc infoserver1000 \ - nova eclipse hp2100 hp3000 i1401 i1620 s3 altair altairz80 gri \ + nd100 nova eclipse hp2100 hp3000 i1401 i1620 s3 altair altairz80 gri \ i7094 ibm1130 id16 id32 sds lgp h316 cdc1700 \ swtp6800mp-a swtp6800mp-a2 tx-0 ssem b5500 intel-mds \ scelbi 3b2 3b2-700 i701 i704 i7010 i7070 i7080 i7090 \ @@ -2520,6 +2525,15 @@ ifneq (,$(call find_test,${VAXD},vax-diag)) $@ $(call find_test,${VAXD},vax-diag) ${TEST_ARG} endif +nd100 : ${BIN}nd100${EXE} + +${BIN}nd100${EXE} : ${ND100} ${SIM} + ${MKDIRBIN} + ${CC} ${ND100} ${SIM} ${ND100_OPT} ${CC_OUTSPEC} ${LDFLAGS} +ifneq (,$(call find_test,${ND100D},nd100)) + $@ $(call find_test,${ND100D},nd100) ${TEST_ARG} +endif + nova : ${BIN}nova${EXE} ${BIN}nova${EXE} : ${NOVA} ${SIM} + git status On branch master Your branch is up to date with 'origin/master'. nothing to commit, working tree clean + git diff ++ git rev-parse HEAD + REV_ID=b40f7efde8e67d9cc25620d863a0d527e8e4c39c + popd + hash -r /var/lib/laminar/run/simh-ibmpcxt/50 /var/lib/laminar/run/simh-ibmpcxt/50/simh /var/lib/laminar/run/simh-ibmpcxt/50 declare -x CC="/usr/lib/gcc-snapshot/bin/gcc" declare -x COMPILER_SUITE="gcc-snapshot" declare -x CPP="/usr/lib/gcc-snapshot/bin/cpp" declare -x CXX="/usr/lib/gcc-snapshot/bin/g++" declare -x HOME="/home/foo" declare -x HOSTNAME="lili" declare -x JOB="simh-ibmpcxt" declare -x LD_LIBRARY_PATH="/usr/lib/gcc-snapshot/lib" declare -x OLDPWD="/var/lib/laminar/run/simh-ibmpcxt/50" declare -x PATH="/usr/lib/gcc-snapshot/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/var/lib/laminar/cfg/scripts" declare -x PWD="/var/lib/laminar/run/simh-ibmpcxt/50/simh" declare -x SHLVL="1" declare -x rev="" + pushd simh + export + log_execute 'bld simu' make GCC=/usr/lib/gcc-snapshot/bin/gcc LTO=1 TEST_ARG=-v BIN/ibmpcxt [bld simu 2023-04-07 23:18:59] lib paths are: /lib/ /lib/x86_64-linux-gnu/ /lib32/ /libx32/ /usr/lib/ [bld simu 2023-04-07 23:18:59] include paths are: /usr/lib/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13/include /usr/local/include /usr/lib/gcc-snapshot/include /usr/include/x86_64-linux-gnu /usr/include [bld simu 2023-04-07 23:18:59] using libm: /lib/x86_64-linux-gnu/libm.so [bld simu 2023-04-07 23:18:59] using librt: /lib/x86_64-linux-gnu/librt.a [bld simu 2023-04-07 23:18:59] using libpthread: /lib/x86_64-linux-gnu/libpthread.a /usr/include/pthread.h [bld simu 2023-04-07 23:18:59] using libpcre: /lib/x86_64-linux-gnu/libpcre.so /usr/include/pcre.h [bld simu 2023-04-07 23:18:59] using semaphore: /usr/include/semaphore.h [bld simu 2023-04-07 23:18:59] using libdl: /lib/x86_64-linux-gnu/libdl.a /usr/include/dlfcn.h [bld simu 2023-04-07 23:18:59] using libedit: /usr/include/editline/readline.h [bld simu 2023-04-07 23:18:59] using libpng: /lib/x86_64-linux-gnu/libpng.so /usr/include/png.h [bld simu 2023-04-07 23:18:59] using zlib: /lib/x86_64-linux-gnu/libz.so /usr/include/zlib.h [bld simu 2023-04-07 23:18:59] using mman: /usr/include/x86_64-linux-gnu/sys/mman.h [bld simu 2023-04-07 23:18:59] *** [bld simu 2023-04-07 23:18:59] *** BIN/ibmpcxt Simulator being built with: [bld simu 2023-04-07 23:18:59] *** - compiler optimizations, with Link Time Optimization, and no debugging support. GCC Version: 13.0.1. [bld simu 2023-04-07 23:18:59] *** - Per simulator tests will be run with argument: -v. [bld simu 2023-04-07 23:18:59] *** [bld simu 2023-04-07 23:18:59] *** git commit id is b40f7efde8e67d9cc25620d863a0d527e8e4c39c. [bld simu 2023-04-07 23:18:59] *** git commit time is 2023-03-30T19:52:33+0200. [bld simu 2023-04-07 23:18:59] *** [bld simu 2023-04-07 23:19:03] #cmake:ignore-target [bld simu 2023-04-07 23:19:03] /usr/lib/gcc-snapshot/bin/gcc -std=gnu99 -U__STRICT_ANSI__ -O2 -finline-functions -fgcse-after-reload -fpredictive-commoning -fipa-cp-clone -fno-unsafe-loop-optimizations -fno-strict-overflow -flto -DSIM_GIT_COMMIT_ID=b40f7efde8e67d9cc25620d863a0d527e8e4c39c -DSIM_GIT_COMMIT_TIME=2023-03-30T19:52:33+0200 -DSIM_COMPILER="GCC Version: 13.0.1" -DSIM_BUILD_TOOL=simh-makefile -I . -Werror -D_GNU_SOURCE -DUSE_READER_THREAD -DSIM_ASYNCH_IO -DHAVE_PCRE_H -DHAVE_SEMAPHORE -DHAVE_SYS_IOCTL -DHAVE_LINUX_CDROM -DSIM_HAVE_DLOPEN=so -DHAVE_EDITLINE -DHAVE_UTIME -DHAVE_LIBPNG -DHAVE_ZLIB -DHAVE_GLOB -DHAVE_SHM_OPEN ./Intel-Systems/common/i8088.c ./Intel-Systems/ibmpcxt/ibmpcxt_sys.c ./Intel-Systems/common/i8253.c ./Intel-Systems/common/i8259.c ./Intel-Systems/common/i8255.c ./Intel-Systems/ibmpcxt/ibmpcxt.c ./Intel-Systems/common/pceprom.c ./Intel-Systems/common/pcram8.c ./Intel-Systems/common/pcbus.c ./Intel-Systems/common/i8237.c ./scp.c ./sim_console.c ./sim_fio.c ./sim_timer.c ./sim_sock.c ./sim_tmxr.c ./sim_ether.c ./sim_tape.c ./sim_disk.c ./sim_serial.c ./sim_video.c ./sim_imd.c ./sim_card.c -I ./Intel-Systems/ibmpcxt -o BIN/ibmpcxt -lm -lrt -lpthread -lpcre -ldl -ledit -ltermcap -lpng -lz [bld simu 2023-04-07 23:19:03] ./Intel-Systems/common/i8088.c:22:10: fatal error: cpu.h: No such file or directory [bld simu 2023-04-07 23:19:03] 22 | #include "cpu.h" [bld simu 2023-04-07 23:19:03] | ^~~~~~~ [bld simu 2023-04-07 23:19:03] compilation terminated. [bld simu 2023-04-07 23:19:04] ./Intel-Systems/common/i8253.c:114:15: error: 'DEBUG_xack' undeclared here (not in a function); did you mean 'DEBUG_all'? [bld simu 2023-04-07 23:19:04] 114 | { "XACK", DEBUG_xack }, [bld simu 2023-04-07 23:19:04] | ^~~~~~~~~~ [bld simu 2023-04-07 23:19:04] | DEBUG_all [bld simu 2023-04-07 23:19:04] ./Intel-Systems/common/i8253.c: In function 'i8253_cfg': [bld simu 2023-04-07 23:19:04] ./Intel-Systems/common/i8253.c:164:37: error: 'BYTEMASK' undeclared (first use in this function) [bld simu 2023-04-07 23:19:04] 164 | i8253_baseport[devnum] = base & BYTEMASK; [bld simu 2023-04-07 23:19:04] | ^~~~~~~~ [bld simu 2023-04-07 23:19:04] ./Intel-Systems/common/i8253.c:164:37: note: each undeclared identifier is reported only once for each function it appears in [bld simu 2023-04-07 23:19:04] ./Intel-Systems/common/i8253.c: In function 'i8253t0': [bld simu 2023-04-07 23:19:04] ./Intel-Systems/common/i8253.c:380:50: error: 'BYTEMASK' undeclared (first use in this function) [bld simu 2023-04-07 23:19:04] 380 | return (i8253_T1_latch[devnum] & BYTEMASK); [bld simu 2023-04-07 23:19:04] | ^~~~~~~~ [bld simu 2023-04-07 23:19:04] ./Intel-Systems/common/i8253.c: In function 'i8253t1': [bld simu 2023-04-07 23:19:04] ./Intel-Systems/common/i8253.c:437:50: error: 'BYTEMASK' undeclared (first use in this function) [bld simu 2023-04-07 23:19:04] 437 | return (i8253_T1_latch[devnum] & BYTEMASK); [bld simu 2023-04-07 23:19:04] | ^~~~~~~~ [bld simu 2023-04-07 23:19:04] ./Intel-Systems/common/i8253.c: In function 'i8253t2': [bld simu 2023-04-07 23:19:04] ./Intel-Systems/common/i8253.c:494:50: error: 'BYTEMASK' undeclared (first use in this function) [bld simu 2023-04-07 23:19:04] 494 | return (i8253_T2_latch[devnum] & BYTEMASK); [bld simu 2023-04-07 23:19:04] | ^~~~~~~~ [bld simu 2023-04-07 23:19:04] ./Intel-Systems/common/i8259.c:106:15: error: 'DEBUG_xack' undeclared here (not in a function); did you mean 'DEBUG_all'? [bld simu 2023-04-07 23:19:04] 106 | { "XACK", DEBUG_xack }, [bld simu 2023-04-07 23:19:04] | ^~~~~~~~~~ [bld simu 2023-04-07 23:19:04] | DEBUG_all [bld simu 2023-04-07 23:19:04] ./Intel-Systems/common/i8259.c: In function 'i8259_cfg': [bld simu 2023-04-07 23:19:04] ./Intel-Systems/common/i8259.c:155:37: error: 'BYTEMASK' undeclared (first use in this function) [bld simu 2023-04-07 23:19:04] 155 | i8259_baseport[devnum] = base & BYTEMASK; [bld simu 2023-04-07 23:19:04] | ^~~~~~~~ [bld simu 2023-04-07 23:19:04] ./Intel-Systems/common/i8259.c:155:37: note: each undeclared identifier is reported only once for each function it appears in [bld simu 2023-04-07 23:19:04] ./Intel-Systems/common/i8255.c:164:15: error: 'DEBUG_xack' undeclared here (not in a function); did you mean 'DEBUG_all'? [bld simu 2023-04-07 23:19:04] 164 | { "XACK", DEBUG_xack }, [bld simu 2023-04-07 23:19:04] | ^~~~~~~~~~ [bld simu 2023-04-07 23:19:04] | DEBUG_all [bld simu 2023-04-07 23:19:04] ./Intel-Systems/common/i8255.c: In function 'i8255_cfg': [bld simu 2023-04-07 23:19:04] ./Intel-Systems/common/i8255.c:206:37: error: 'BYTEMASK' undeclared (first use in this function) [bld simu 2023-04-07 23:19:04] 206 | i8255_baseport[devnum] = base & BYTEMASK; [bld simu 2023-04-07 23:19:04] | ^~~~~~~~ [bld simu 2023-04-07 23:19:04] ./Intel-Systems/common/i8255.c:206:37: note: each undeclared identifier is reported only once for each function it appears in [bld simu 2023-04-07 23:19:06] ./Intel-Systems/common/i8237.c:308:5: error: braces around scalar initializer [-Werror] [bld simu 2023-04-07 23:19:06] 308 | { 0 } [bld simu 2023-04-07 23:19:06] | ^ [bld simu 2023-04-07 23:19:06] ./Intel-Systems/common/i8237.c:308:5: note: (near initialization for 'i8237_unit.next') [bld simu 2023-04-07 23:19:06] ./Intel-Systems/common/i8237.c: In function 'i8237_rDx': [bld simu 2023-04-07 23:19:06] ./Intel-Systems/common/i8237.c:785:9: error: too many arguments to function 'i8237_reset_dev' [bld simu 2023-04-07 23:19:06] 785 | i8237_reset_dev(devnum); [bld simu 2023-04-07 23:19:06] | ^~~~~~~~~~~~~~~ [bld simu 2023-04-07 23:19:06] ./Intel-Systems/common/i8237.c:450:6: note: declared here [bld simu 2023-04-07 23:19:06] 450 | void i8237_reset_dev() [bld simu 2023-04-07 23:19:06] | ^~~~~~~~~~~~~~~ [bld simu 2023-04-07 23:19:06] cc1: all warnings being treated as errors [bld simu 2023-04-07 23:19:22] make: *** [makefile:2759: BIN/ibmpcxt] Error 1 TCLUG_BUILD_INFO;bld simu;2;23 [laminar] Executing cfg/after + export declare -x ARCHIVE="/var/lib/laminar/archive/simh-ibmpcxt/50" declare -x CONTEXT="default" declare -x HOME="/nonexistent" declare -x INVOCATION_ID="9b02437f413b4689a9f1c5e694d46bc1" declare -x JOB="simh-ibmpcxt" declare -x JOURNAL_STREAM="8:1789880356" declare -x LAMINAR_BASE_URL="http://toolchain.lug-owl.de/laminar/" declare -x LAMINAR_TITLE="toolchain.lug-owl.de" declare -x LANG="en_US.UTF-8" declare -x LANGUAGE="en_US:en" declare -x LAST_RESULT="failed" declare -x LOGNAME="laminar" declare -x OLDPWD declare -x PATH="/var/lib/laminar/cfg/scripts:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" declare -x PWD="/var/lib/laminar/run/simh-ibmpcxt/50" declare -x RESULT="failed" declare -x RUN="50" declare -x SHLVL="1" declare -x SYSTEMD_EXEC_PID="54097" declare -x USER="laminar" declare -x WORKSPACE="/var/lib/laminar/run/simh-ibmpcxt/workspace" declare -x __LAMINAR_SETENV_PIPE="9" + VERBOSE= + find . -type f -name '*.sum' -exec cp --parent '{}' /var/lib/laminar/archive/simh-ibmpcxt/50 ';' + find . -type f -name config.log -exec cp --parent '{}' /var/lib/laminar/archive/simh-ibmpcxt/50 ';' + find . -type f -name config.h -exec cp --parent '{}' /var/lib/laminar/archive/simh-ibmpcxt/50 ';' + find . -type f -name test-suite.log -exec cp --parent '{}' /var/lib/laminar/archive/simh-ibmpcxt/50 ';' + find . -type f -name SYSTEM.def -exec cp --parent '{}' /var/lib/laminar/archive/simh-ibmpcxt/50 ';' + '[' '!' -d logs ']' + find . -type f -name build-state.json -exec cp --parent '{}' /var/lib/laminar/archive/simh-ibmpcxt/50 ';' + find . -type f -name versions.json -exec cp --parent '{}' /var/lib/laminar/archive/simh-ibmpcxt/50 ';' + '[' '!' -r build.log ']' + '[' failed = success -a failed '!=' failed ']' + '[' failed = failed -a failed '!=' failed ']' + printf '\nFinal status: %s.\n' failed Final status: failed.