diff --git a/RTX2001A/CREDITS b/RTX2001A/CREDITS new file mode 100644 index 000000000..9232fcaf8 --- /dev/null +++ b/RTX2001A/CREDITS @@ -0,0 +1,4 @@ +This project would not be possible without the original development at Harris Semiconductor +of +o The RTX2000 simulator by Phil Koopman Jr. 9/x/90 +o The APPFORTH, RTX2001A hex images by Rick VanNorman Fri 06-01-1990 \ No newline at end of file diff --git a/RTX2001A/makefile b/RTX2001A/makefile new file mode 100644 index 000000000..5f002d5b6 --- /dev/null +++ b/RTX2001A/makefile @@ -0,0 +1,155 @@ +# RTX-2001A +RTX2001AD = ${SIMHD}/RTX2001A/ +RTX2001AD_SRC = ${RTX2001AD}src/ + +RTX2001A_SRC = \ + ${RTX2001AD_SRC}rtx2001a_registers.h \ + ${RTX2001AD_SRC}rtx2001a_defs.h \ + ${RTX2001AD_SRC}rtx2001a_debug.h \ + ${RTX2001AD_SRC}rtx2001a_cpu.c \ + ${RTX2001AD_SRC}rtx2001a_sys.c \ + ${RTX2001AD_SRC}rtx2001a_decode.c \ + ${RTX2001AD_SRC}rtx2001a_decode.h \ + ${RTX2001AD_SRC}rtx2001a_execute.c \ + ${RTX2001AD_SRC}rtx2001a_execute.h \ + ${RTX2001AD_SRC}rtx2001a_ab.c \ + ${RTX2001AD_SRC}rtx2001a_ab.h \ + ${RTX2001AD_SRC}rtx2001a_mb.c \ + ${RTX2001AD_SRC}rtx2001a_mb.h \ + ${RTX2001AD_SRC}rtx2001a_psb.c \ + ${RTX2001AD_SRC}rtx2001a_psb.h \ + ${RTX2001AD_SRC}rtx2001a_rsb.c \ + ${RTX2001AD_SRC}rtx2001a_rsb.h + +# rtx2001a lib +RTX2001A_LIB = rtx2001a.a + +${RTX2001AD}${RTX2001A_LIB} : ${SIM} ${RTX2001A_SRC} + ${GCC} -c -fPIC ${CC_STD} -U__STRICT_ANSI__ ${CFLAGS_G} \ + ${CFLAGS_O} ${CFLAGS_GIT} ${CFLAGS_I} \ + -DSIM_COMPILER="${COMPILER_NAME}" -DSIM_VERSION_MODE="${SIM_VERSION_MODE}" \ + -DSIM_BUILD_TOOL=simh-makefile ${OS_CCDEFS} ${ROMS_OPT} ${SIM} ${RTX2001A_SRC} + ar vrcs ${RTX2001AD}${RTX2001A_LIB} rtx2001a_*.o sim_*.o + +# rtx2001a +rtx2001a : ${BIN}rtx2001a${EXE} + +# ${STUB_OPT} +${BIN}rtx2001a${EXE} : ${SIMH_LIB} ${RTX2001AD}${RTX2001A_LIB} + ${MKDIRBIN} + ${CC} scp.o ${SIMH_LIB} ${RTX2001AD}${RTX2001A_LIB} ${CC_OUTSPEC} ${LDFLAGS} + +# tests +OS_CCDEFS_TEST = ${OS_CCDEFS} +OS_CCDEFS_TEST += -Wall +OS_CCDEFS_TEST += -Wextra +OS_CCDEFS_TEST += -Wpointer-arith +OS_CCDEFS_TEST += -Wcast-align +OS_CCDEFS_TEST += -Wwrite-strings +OS_CCDEFS_TEST += -Wswitch-default +OS_CCDEFS_TEST += -Wunreachable-code +OS_CCDEFS_TEST += -Winit-self +OS_CCDEFS_TEST += -Wmissing-field-initializers +OS_CCDEFS_TEST += -Wno-unknown-pragmas +OS_CCDEFS_TEST += -Wstrict-prototypes +OS_CCDEFS_TEST += -Wundef +OS_CCDEFS_TEST += -Wold-style-definition + +UNITYD_SRC=../Unity/src/ + +RTX2001AD_TEST = ${RTX2001AD}test/ + +RTX2001A_TEST_MB_SRC = \ + ${RTX2001AD_TEST}test_mb.c \ + ${RTX2001AD_TEST}test_mb_long_store_fetch.c \ + ${RTX2001AD_TEST}test_mb_byte_store_fetch.c \ + ${RTX2001AD_TEST}test_mb_store_fetch.c \ + ${RTX2001AD_TEST}scp_stub.c \ + $(UNITYD_SRC)unity.c + +RTX2001A_TEST_AB_SRC = \ + ${RTX2001AD_TEST}test_ab.c \ + ${RTX2001AD_TEST}test_ab_gstore.c \ + ${RTX2001AD_TEST}test_ab_gfetch.c \ + ${RTX2001AD_TEST}scp_stub.c \ + $(UNITYD_SRC)unity.c + +RTX2001A_TEST_PSB_SRC = \ + ${RTX2001AD_TEST}test_psb.c \ + ${RTX2001AD_TEST}scp_stub.c \ + $(UNITYD_SRC)unity.c + +RTX2001A_TEST_RSB_SRC = \ + ${RTX2001AD_TEST}test_rsb.c \ + ${RTX2001AD_TEST}scp_stub.c \ + $(UNITYD_SRC)unity.c + +RTX2001A_TEST_DECODE_SRC = \ + ${RTX2001AD_TEST}test_decode.c \ + ${RTX2001AD_TEST}scp_stub.c \ + $(UNITYD_SRC)unity.c + +RTX2001A_TEST_EXECUTE_SRC = \ + ${RTX2001AD_TEST}test_execute.c \ + ${RTX2001AD_TEST}scp_stub.c \ + $(UNITYD_SRC)unity.c + +rtx2001a_test : \ + ${BIN}test_mb${EXE} \ + ${BIN}test_ab${EXE} \ + ${BIN}test_psb${EXE} \ + ${BIN}test_rsb${EXE} \ + ${BIN}test_decode${EXE} \ + ${BIN}test_execute${EXE} + +${BIN}test_mb${EXE} : ${RTX2001AD}${RTX2001A_LIB} ${RTX2001A_TEST_MB_SRC} ${RTX2001A_SRC} + ${MKDIRBIN} + ${CC} -I${UNITYD_SRC} -I${RTX2001AD_SRC} \ + ${RTX2001A_TEST_MB_SRC} \ + ${LDFLAGS} \ + ${RTX2001AD}${RTX2001A_LIB} \ + ${CC_OUTSPEC} + +${BIN}test_ab${EXE} : ${RTX2001AD}${RTX2001A_LIB} ${RTX2001A_TEST_AB_SRC} ${RTX2001A_SRC} + ${MKDIRBIN} + ${CC} -I${UNITYD_SRC} -I${RTX2001AD_SRC} \ + ${RTX2001A_TEST_AB_SRC} \ + ${LDFLAGS} \ + ${RTX2001AD}${RTX2001A_LIB} \ + ${CC_OUTSPEC} + +${BIN}test_psb${EXE} : ${RTX2001AD}${RTX2001A_LIB} ${RTX2001A_TEST_PSB_SRC} ${RTX2001A_SRC} + ${MKDIRBIN} + ${CC} -I${UNITYD_SRC} -I${RTX2001AD_SRC} \ + ${RTX2001A_TEST_PSB_SRC} \ + ${LDFLAGS} \ + ${RTX2001AD}${RTX2001A_LIB} \ + ${CC_OUTSPEC} + +${BIN}test_rsb${EXE} : ${RTX2001AD}${RTX2001A_LIB} ${RTX2001A_TEST_RSB_SRC} ${RTX2001A_SRC} + ${MKDIRBIN} + ${CC} -I${UNITYD_SRC} -I${RTX2001AD_SRC} \ + ${RTX2001A_TEST_RSB_SRC} \ + ${LDFLAGS} \ + ${RTX2001AD}${RTX2001A_LIB} \ + ${CC_OUTSPEC} + +${BIN}test_decode${EXE} : ${RTX2001AD}${RTX2001A_LIB} ${RTX2001A_TEST_DECODE_SRC} ${RTX2001A_SRC} + ${MKDIRBIN} + ${CC} -I${UNITYD_SRC} -I${RTX2001AD_SRC} \ + ${RTX2001A_TEST_DECODE_SRC} \ + ${LDFLAGS} \ + ${RTX2001AD}${RTX2001A_LIB} \ + ${CC_OUTSPEC} + +${BIN}test_execute${EXE} : ${RTX2001AD}${RTX2001A_LIB} ${RTX2001A_TEST_EXECUTE_SRC} ${RTX2001A_SRC} + ${MKDIRBIN} + ${CC} -I${UNITYD_SRC} -I${RTX2001AD_SRC} \ + ${RTX2001A_TEST_EXECUTE_SRC} \ + ${LDFLAGS} \ + ${RTX2001AD}${RTX2001A_LIB} \ + ${CC_OUTSPEC} + +# clean +rtx2001a_clean: + ${RM} -rf ${BIN} ${SIMH}/*.o ${RTX2001AD}$(RTX2001A_LIB) diff --git a/RTX2001A/rtx2001a.doc b/RTX2001A/rtx2001a.doc new file mode 100644 index 000000000..d8784e5fa Binary files /dev/null and b/RTX2001A/rtx2001a.doc differ diff --git a/RTX2001A/rtx2001a.ini b/RTX2001A/rtx2001a.ini new file mode 100644 index 000000000..c69e5ec1c --- /dev/null +++ b/RTX2001A/rtx2001a.ini @@ -0,0 +1,23 @@ + +# use for rtx2001a +# set log -n /tmp/rtx2001a.log +# set debug -PF /tmp/rtx2001a.log +set nolog +set debug -f stdout +set CPU NODEBUG=CPU;MEBR;MEBW;ASBR;ASBW;PSBR;PSBW;RSBR;RSBW +if exist "%SIM_BIN_NAME%/appforth.hex" load %SIM_BIN_NAME%/appforth.hex +if exist "appforth.hex" load appforth.hex +# set break -s -p +# set CPU DEBUG=CPU;MEBR;MEBW;ASBR;ASBW;PSBR;PSBW;RSBR;RSBW +# set CPU deb=CPU;ASBR;ASBW; +# +# boot routine +# +dep ir 0x175D +dep pc 2 +step +# +# verify boot state +# +ex state +set on \ No newline at end of file diff --git a/RTX2001A/rtx2001a_ab.c b/RTX2001A/rtx2001a_ab.c new file mode 100644 index 000000000..02ecb00f8 --- /dev/null +++ b/RTX2001A/rtx2001a_ab.c @@ -0,0 +1,554 @@ +/* rtx2001a_ab.c: RTX2001A CPU simulator + + Copyright (c) 2022, Systasis Computer Systems, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + SYSTASIS COMPUTER SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Systasis Computer Systems shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Systasis Computer Systems. + + 9-Sep-22 SYS ASIC bus routines +*/ + +#include "rtx2001a_ab.h" +#include "rtx2001a_execute.h" + +RTX_WORD hostmode = FALSE; /* when true, in process of talking to the host */ + +// https://embedjournal.com/implementing-circular-buffer-embedded-c/ +typedef struct +{ + t_value *const buffer; + int head; + int tail; + const int maxlen; +} circ_bbuf_t; + +t_value _kbbuf[255] = {'\0'}; +circ_bbuf_t kbbuf = {_kbbuf, 0, 0, 254}; + +int circ_bbuf_push(circ_bbuf_t *c, t_value data) +{ + int next; + + next = c->head + 1; // next is where head will point to after this write. + if (next >= c->maxlen) + next = 0; + + if (next == c->tail) // if the head + 1 == tail, circular buffer is full + return -1; + + c->buffer[c->head] = data; // Load data and then move + c->head = next; // head to next data offset. + return 0; // return success to indicate successful push. +} + +int circ_bbuf_pop(circ_bbuf_t *c, t_value *data) +{ + int next; + + if (c->head == c->tail) // if the head == tail, we don't have any data + return -1; + + next = c->tail + 1; // next is where tail will point to after this read. + if (next >= c->maxlen) + next = 0; + + *data = c->buffer[c->tail]; // Read data and then move + c->tail = next; // tail to next offset. + return 0; // return success to indicate successful push. +} + +// t_stat poll_kbd(t_value *data) +// { +// int status; +// unsigned char buf[1]; + +// status = read(0, buf, 1); +// *data = '\0'; +// if (status != 1) +// return SCPE_OK; +// if (sim_brk_char && (buf[0] == sim_brk_char)) +// return SCPE_BREAK; +// if (sim_int_char && (buf[0] == sim_int_char)) +// return SCPE_STOP; +// *data = buf[0]; +// return SCPE_OK; +// } + +/* implementation note: gfetch is always invoked before TEST_EXIT */ +t_stat gfetch(t_addr offset, t_value *data) +{ + switch (offset) + { + + case 0x19: // RCV + { + // if (hostmode) /* invoke fsm for serving host mode */ + // { + // return (host_read()); + // } + // *data = getchar() & D16_MASK; + /* printf("\n(%d) = '%c'", temp, temp); */ + // handle + if (0 == circ_bbuf_pop(&kbbuf, data)) + { + return SCPE_OK; + } + *data = 0; + t_stat status = sim_poll_kbd(); + switch (status) + { + case SCPE_OK: // no char + case SCPE_LOST: // Error + return status; + default: + *data = status & ~SCPE_KFLAG; + } + + return SCPE_OK; + } + + case 0x1A: // RCV? + { + t_stat status = sim_poll_kbd(); + *data = 0; + switch (status) + { + case SCPE_OK: // no char + case SCPE_LOST: // Error + return status; + default: + circ_bbuf_push(&kbbuf, status & ~SCPE_KFLAG); + } + *data = 0xFF; + return SCPE_OK; + } + + // return bit=0: Pushes the contents of I into TOP (with no pop of the Return Stack) + // return bit=1: Pushes the contents of I into TOP then performs a subroutine return + case I: + *data = asic_file[I]; + sim_debug(DBG_ASB_R, &cpu_dev, sim_is_running ? "I=0x%X\n" : "I=0x%X", asic_file[I]); + return SCPE_OK; + + // return bit=0: Pushes the contents of I into TOP, popping the Return Stack + // return bit=1: Pushes the contents of I into TOP without popping the Return Stack, then executes the Subroutine Return + case I_ASIC: + *data = asic_file[I]; + sim_debug(DBG_ASB_R, &cpu_dev, "I=0x%X\n", asic_file[I]); + if (!EXIT) + { + rs_pop(); + } + return SCPE_OK; + + // Pushes the contents of I shifted left by one bit, into TOP (the Return Stack is not popped) + case I_ALU: + *data = (asic_file[I] << 1) & D16_UMAX; + sim_debug(DBG_ASB_R, &cpu_dev, sim_is_running ? "I=0x%X\n" : " ", *data); + return SCPE_OK; + + case _CR: + *data = cr.pr & 0xFFEF; // Force SID to zero + + if (sim_is_running) + sim_debug_bits_hdr(DBG_ASB_R, &cpu_dev, "CR", cr_bits, cr.pr, *data, 1); + return SCPE_OK; + + case MD: + *data = asic_file[MD] & D16_UMAX; + if (sim_is_running) + sim_debug(DBG_ASB_R, &cpu_dev, "MD=0x%X\n", asic_file[MD]); + return SCPE_OK; + + case SQ: + { + RTX_WORD sq = asic_file[MD] << 1; + *data = sq | asic_file[SR]; + sim_debug(DBG_ASB_R, &cpu_dev, "SQ=0x%X SR=0x%X\n", sq, asic_file[SR]); + return SCPE_OK; + } + + case SR: + { + *data = asic_file[SR]; + sim_debug(DBG_ASB_R, &cpu_dev, "SR=0x%X\n", asic_file[SR]); + return SCPE_OK; + } + + case PC: + *data = asic_file[PC]; + sim_debug(DBG_ASB_R, &cpu_dev, "PC=0x%X\n", asic_file[PC]); + return SCPE_OK; + + case _IMR: + *data = imr.pr; + sim_debug_bits_hdr(DBG_ASB_R, &cpu_dev, "IMR", imr_bits, imr.pr, *data, 1); + return SCPE_OK; + + case _SPR: + *data = (((spr.fields.rsp) << 8) & 0xFF00) | (((spr.fields.psp) + 1) & 0x00FF); + sim_debug_bits_hdr(DBG_ASB_R, &cpu_dev, "SPR", spr_bits, spr.pr, *data, 1); + return SCPE_OK; + + case _SUR: + *data = sur.pr; + sim_debug_bits_hdr(DBG_ASB_R, &cpu_dev, "SUR", sur_bits, sur.pr, *data, 1); + return SCPE_OK; + + case _IVR: + { + IMR _imr; + IVR _ivr; + + _ivr.fields.ivb = ibc.fields.ivb; // Interrupt Vector Base, MA10 - MA15 + sim_debug_bits_hdr(DBG_ASB_R, &cpu_dev, "IBCR", ibc_bits, ibc.pr, ibc.pr, 1); + + _imr.pr = imr.pr; + sim_debug_bits_hdr(DBG_ASB_R, &cpu_dev, "IMR", imr_bits, imr.pr, imr.pr, 1); + + for (uint32 pri = 15; pri > 0; pri--) + { + if (_imr.pr & 1) + { + _ivr.fields.vec = pri; + break; + } + _imr.pr = _imr.pr >> 1; + } + *data = _ivr.pr; + sim_debug_bits_hdr(DBG_ASB_R, &cpu_dev, "IVR", ivr_bits, ivr.pr, *data, 1); + return SCPE_OK; + } + + // SVR is write-only + + case _IPR: + *data = ipr.pr; + sim_debug_bits_hdr(DBG_ASB_R, &cpu_dev, "IPR", ipr_bits, ipr.pr, *data, 1); + return SCPE_OK; + + case _DPR: + *data = dpr.pr; + sim_debug_bits_hdr(DBG_ASB_R, &cpu_dev, "DPR", pr_bits, dpr.pr, *data, 1); + return SCPE_OK; + + case _UPR: + *data = upr.pr; + sim_debug_bits_hdr(DBG_ASB_R, &cpu_dev, "UPR", pr_bits, upr.pr, *data, 1); + return SCPE_OK; + + case _CPR: + *data = cpr.pr; + sim_debug_bits_hdr(DBG_ASB_R, &cpu_dev, "CPR", pr_bits, cpr.pr, *data, 1); + return SCPE_OK; + + case _IBC: + *data = ibc.pr; + sim_debug_bits_hdr(DBG_ASB_R, &cpu_dev, "IBC", ibc_bits, ibc.pr, *data, 1); + return SCPE_OK; + + case _UBR: + ubr.fields.page = ipr.fields.pr; + sim_debug_bits_hdr(DBG_ASB_R, &cpu_dev, "IPR", ipr_bits, ipr.pr, ipr.pr, 1); + + *data = ubr.pr; + sim_debug_bits_hdr(DBG_ASB_R, &cpu_dev, "UBR", ubr_bits, ubr.pr, ubr.pr, 1); + return SCPE_OK; + + case TC0: + *data = asic_file[TC0]; + sim_debug(DBG_ASB_R, &cpu_dev, "TC0=0x%X\n", *data); + return SCPE_OK; + + case TC1: + *data = asic_file[TC1]; + sim_debug(DBG_ASB_R, &cpu_dev, "TC1=0x%X\n", *data); + return SCPE_OK; + + case TC2: + *data = asic_file[TC2]; + sim_debug(DBG_ASB_R, &cpu_dev, "TC2=0x%X\n", *data); + return SCPE_OK; + + case RX: + *data = asic_file[RX]; + sim_debug(DBG_ASB_R, &cpu_dev, "RX=0x%X\n", *data); + return SCPE_OK; + + case RH: + *data = asic_file[RH]; + sim_debug(DBG_ASB_R, &cpu_dev, "RH=0x%X\n", *data); + return SCPE_OK; + + default: + if (offset >= 0x18 && offset <= 0x1F) + { + *data = gdata[offset]; + sim_debug(DBG_ASB_R, &cpu_dev, "GA=0x%X GD=0x%X\n", offset, *data); + return SCPE_OK; + } + } + + return SCPE_NXM; +} + +t_stat gstore(t_addr offset, t_value data) +{ + /* implementation note: gstore is always invoked after TEST_EXIT */ + + switch (offset) + { + case I: + if (EXIT) + { + // Performs a Subroutine Return, then pushes the contents of TOP into I + rs_push(cpr.pr, data); + } + else + { + // Pops the contents of TOP into I (with no push of the Return Stack) + set_IPR(cpr.pr); + asic_file[I] = data & D16_UMAX; + sim_debug(DBG_ASB_W, &cpu_dev, "I=0x%X\n", asic_file[I]); + } + return SCPE_OK; + + case I_ASIC: + rs_push(cpr.pr, data); + return SCPE_OK; + + case I_ALU: + rs_push(cpr.pr, data); + STREAM = TRUE; + return SCPE_OK; + + case _CR: + { + CR ocr; + ocr.pr = cr.pr; + + cr.pr = data & 0xC01F; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "CR", cr_bits, ocr.pr, cr.pr, 1); + return SCPE_OK; + } + + // Pop the Paramter Stack item into the MD Register, replacing its previous contents + case MD: + asic_file[MD] = data & 0xFFFF; + sim_debug(DBG_ASB_W, &cpu_dev, "MD=0x%X\n", asic_file[MD]); + return SCPE_OK; + + case SQ: + asic_file[MD] = data << 8; + sim_debug(DBG_ASB_W, &cpu_dev, "SQ=0x%X\n", asic_file[MD]); + return SCPE_OK; + + case SR: + asic_file[SR] = data; + sim_debug(DBG_ASB_W, &cpu_dev, "SR=0x%X\n", asic_file[SR]); + return SCPE_OK; + + case PC: + // push value onto RS, then perform exit + if (EXIT) + { + asic_file[PC] = data & D16_MASK; + sim_debug(DBG_ASB_W, &cpu_dev, "PC=0x%X\n", asic_file[PC]); + } + // perform a subroutine call + else + { + rs_push(cpr.pr, asic_file[PC]); + asic_file[PC] = data & D16_MASK; + sim_debug(DBG_ASB_W, &cpu_dev, "PC=0x%X\n", asic_file[PC]); + } + return SCPE_OK; + + case _IMR: + { + IMR oimr; + oimr.pr = imr.pr; + + imr.pr = data & 0x3FFE; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "IMR", imr_bits, oimr.pr, imr.pr, 1); + return SCPE_OK; + } + + case _SPR: + { + SPR ospr; + ospr.pr = spr.pr; + + spr.fields.rsp = (data >> 8) & 0x7F; + spr.fields.psp = data & 0x7F; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "SPR", spr_bits, ospr.pr, spr.pr, 1); + return SCPE_OK; + } + + case _SUR: + { + SUR osur; + osur.pr = sur.pr; + + sur.pr = data & 0xFBFB; // Bits 2 & 10 MBZ + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "SUR", sur_bits, osur.pr, sur.pr, 1); + return SCPE_OK; + } + + case _SVR: + { + SVR osvr; + osvr.pr = svr.pr; + + svr.pr = 0; + RVL = (data >> 8) & 0x3F; + PVL = data & 0x3F; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "SVR", svr_bits, osvr.pr, svr.pr, 1); + return SCPE_OK; + } + + case _IPR: + { + IPR oipr; + oipr.pr = ipr.pr; + + ipr.pr = data & 0x1F; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "IPR", ipr_bits, oipr.pr, ipr.pr, 1); + return SCPE_OK; + } + + case _DPR: + { + DPR odpr; + odpr.pr = dpr.pr; + + dpr.pr = data & 0x0F; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "DPR", pr_bits, odpr.pr, dpr.pr, 1); + return SCPE_OK; + } + + case _UPR: + { + UPR oupr; + oupr.pr = upr.pr; + + upr.pr = data & 0x0F; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "UPR", pr_bits, oupr.pr, upr.pr, 1); + return SCPE_OK; + } + + case _CPR: + { + CPR ocpr; + ocpr.pr = cpr.pr; + + cpr.pr = data & 0x0F; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "CPR", pr_bits, ocpr.pr, cpr.pr, 1); + return SCPE_OK; + } + + case _IBC: + { + IBC oibcr; + oibcr.pr = ibc.pr; + + ibc.pr = data & 0xFFBF; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "IBC", ibc_bits, oibcr.pr, ibc.pr, 1); + return SCPE_OK; + } + + case _UBR: + { + UBR oubr; + oubr.pr = ubr.pr; + + ubr.fields.adr = data & 0x3FF; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "UBR", ubr_bits, oubr.pr, ubr.pr, 1); + return SCPE_OK; + } + + case TP0: + asic_file[TP0] = data & D16_MASK; + sim_debug(DBG_ASB_W, &cpu_dev, "TP0=0x%X\n", asic_file[TP0]); + return SCPE_OK; + /* timer side effect? */ + + case TP1: + asic_file[TP1] = data & D16_MASK; + sim_debug(DBG_ASB_W, &cpu_dev, "TP1=0x%X\n", asic_file[TP1]); + return SCPE_OK; + + case TP2: + asic_file[TP2] = data & D16_MASK; + sim_debug(DBG_ASB_W, &cpu_dev, "TP2=0x%X\n", asic_file[TP2]); + return SCPE_OK; + + case RX: + asic_file[RX] = data & D16_MASK; + sim_debug(DBG_ASB_W, &cpu_dev, "RX=0x%X\n", asic_file[RX]); + return SCPE_OK; + + case RH: + asic_file[RH] = data & D16_MASK; + sim_debug(DBG_ASB_W, &cpu_dev, "RH=0x%X\n", asic_file[RH]); + return SCPE_OK; + + case 0x19: // XMT + { + if (hostmode) + { /* invoke fsm for serving host mode */ + return host_write(data); + } + if (data) + { + putchar(data); + // @TODO: SIMH virtual console write + return SCPE_OK; + } + else + { + hostmode = -1; + } + } + + default: + /* off-chip gstores */ + if (offset >= 0x18 && offset <= 0x1F) + { + gdata[offset] = data & D16_MASK; + sim_debug(DBG_ASB_W, &cpu_dev, "GA=0x%X GD=0x%X\n", offset, gdata[offset]); + return SCPE_OK; + } + } + + return SCPE_NXM; +} + +t_stat host_write(t_value data) +{ + if (data == 0xFF) + { + return SCPE_EXIT; + } + hostmode = FALSE; + + return SCPE_OK; +} \ No newline at end of file diff --git a/RTX2001A/rtx2001a_ab.h b/RTX2001A/rtx2001a_ab.h new file mode 100644 index 000000000..c21937e61 --- /dev/null +++ b/RTX2001A/rtx2001a_ab.h @@ -0,0 +1,73 @@ +/* rtx2001a_ab.h: RTX2001A CPU simulator + + Copyright (c) 2022, Systasis Computer Systems, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + SYSTASIS COMPUTER SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Systasis Computer Systems shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Systasis Computer Systems. + + 19-Sep-22 SYS ASIC bus routines +*/ +#ifndef RTX2001A_AB_H_ +#define RTX2001A_AB_H_ 0 + +#include "rtx2001a_registers.h" +#include "rtx2001a_defs.h" +#include "rtx2001a_debug.h" +#include "rtx2001a_rsb.h" + +#define GDATA_SIZE 0x20 + +extern RTX_WORD gdata[GDATA_SIZE]; +extern RTX_WORD hostmode; + +/* extract the 5-bit short-lit/g-bus/user value */ +#define SHORT_LIT (IR & 0x1F) + +#define INC_PC \ + { \ + asic_file[PC] = (asic_file[PC] + 2) & D16_UMAX; \ + sim_debug(DBG_ASB_W, &cpu_dev, "PC=0x%X\n", asic_file[PC]); \ + } + +#define set_IPR(page) \ + { \ + ipr.fields.pr = page; \ + sim_debug_bits_hdr(DBG_ASB_R, &cpu_dev, "IBC", ibc_bits, ibc.pr, ibc.pr, 1); \ + if (DPRSEL) \ + { \ + ipr.pr |= 0x10; \ + } \ + sim_debug(DBG_ASB_W, &cpu_dev, "IPR=%d\n", ipr.fields.pr); \ + } + +#define set_DPRSEL(value) \ + { \ + IBC oibc; \ + oibc.pr = ibc.pr; \ + ibc.fields.dprsel = (value) ? 1 : 0; \ + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "IBC", ibc_bits, oibc.pr, ibc.pr, 1); \ + } + +extern t_stat gstore(t_addr, t_value); +extern t_stat gfetch(t_addr, t_value *); +extern t_stat host_write(t_value); + +#endif \ No newline at end of file diff --git a/RTX2001A/rtx2001a_cpu.c b/RTX2001A/rtx2001a_cpu.c new file mode 100644 index 000000000..d77d6dc3e --- /dev/null +++ b/RTX2001A/rtx2001a_cpu.c @@ -0,0 +1,368 @@ +/* rtx2001a_cpu.c: RTX2001A CPU simulator + + Copyright (c) 2022, Systasis Computer Systems, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + SYSTASIS COMPUTER SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Systasis Computer Systems shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Systasis Computer Systems. + + 12-Aug-22 SYS New simulator. + + simh registered callbacks +*/ + +#include "setjmp.h" +#include "rtx2001a_debug.h" +#include "rtx2001a_defs.h" +#include "rtx2001a_ab.h" +#include "rtx2001a_mb.h" +#include "rtx2001a_psb.h" +#include "rtx2001a_rsb.h" +#include "rtx2001a_registers.h" +#include "rtx2001a_execute.h" +#include "rtx2001a_decode.h" + +/* Function declaration. */ +t_stat cpu_ex(t_value *vptr, t_addr ea, UNIT *uptr, int32 sw); +t_stat cpu_dep(t_value val, t_addr ea, UNIT *uptr, int32 sw); +t_stat cpu_reset(DEVICE *dptr); + +UNIT cpu_unit = {UDATA(NULL, UNIT_FIX + UNIT_BINK, RAM_SIZE)}; + +MTAB cpu_mod[] = { + {0}}; + +DEVICE cpu_dev = { // RTX2001A device structure + "CPU", /* name */ + &cpu_unit, /* units */ + &cpu_reg[0], /* registers */ + &cpu_mod[0], /* modifiers */ + 0, /* #units */ + 16, /* address radix */ + 16, /* address width */ + 1, /* addr increment */ + 16, /* data radix */ + 16, /* data width */ + &cpu_ex, /* examine routine */ + &cpu_dep, /* deposit routine */ + &cpu_reset, /* reset routine */ + NULL, /* boot routine */ + NULL, /* attach routine */ + NULL, /* detach routine */ + NULL, /* context */ + DEV_DEBUG, /* enable device debug */ + /* debug control */ + SWMASK('E') | DBG_ASB_W | DBG_ASB_R | DBG_PSB_W | DBG_PSB_R | DBG_MEB_W | DBG_MEB_R | DBG_RSB_W | DBG_RSB_R, + &cpu_deb[0], /* debug flags */ + NULL, NULL, NULL, NULL, NULL, NULL}; + +/** + * 3.8 Other Data Structures, simh.doc, pg 33 + * contains the maximum number of words needed to hold the largest instruction or data item in the VM. + * Examine and deposit will process up to sim_emax words. + * "The number of words in the val array is given by global variable sim_emax.", simh.doc, pg 35 + */ +int32 sim_emax = 1; + +RTX_WORD TOP = 0; +RTX_WORD NEXT = 0; +RTX_WORD IR = 0; +RTX_WORD clocks = 0; +REG *sim_PC = &cpu_reg[7]; +/* +** second cycle context +*/ +t_value second_cycle = 0; +t_value stream_mode = 0; +t_value STREAM = 0; +RTX_WORD temp_ir = 0; +// RTX_WORD temp_pc = 0; + +RTX_WORD ps[PS_MAX + 1] = {0}; + +RTX_WORD asic_file[ASIC_MAX] = {0}; + +RTX_WORD gdata[GDATA_SIZE] = {0}; + +ReturnStack rs[RS_MAX + 1] = {0}; + +jmp_buf save_env; // abort handler +jmp_buf trap_env; // trap/breakpoint handler + +t_value rtx2001a_pc_value(void) +{ + return (t_value)asic_file[PC]; +} + +/* +** See SSEM/ssem_cpu.c +*/ +t_stat sim_instr(void) +{ + t_stat reason = 0; + + sim_cancel_step(); /* defang SCP step. See SSEM */ + + /* Abort handling + + If an abort occurs in memory management or memory access, the lower + level routine executes a longjmp to this area OUTSIDE the main + simulation loop. + + All variables used in setjmp processing, or assumed to be valid + after setjmp, must be volatile or global. + */ + int32 abortval = setjmp(save_env); /* set abort hdlr */ + if (0 != abortval) + { + return abortval; + } + + /* Main instruction fetch/decode loop */ + do + { + + if (sim_interval <= 0) + { /* check clock queue */ +#if !UNIX_PLATFORM + if ((reason = sim_poll_kbd()) == SCPE_STOP) + { /* poll on platforms without reliable signalling */ + break; + } +#endif + /* + ** process timer interrupt. See pg. 14 + ** maybe needed outside of sim_interval check + */ + // if (sim_is_active()) + // { + if (SCPE_OK != (reason = sim_process_event())) + break; + // } + } + + if (sim_brk_summ && /* breakpoint? */ + sim_brk_test(asic_file[PC], SWMASK('E'))) + { + reason = STOP_IBKPT; /* stop simulation */ + break; + } + + /* + ** RTX 2000 and RTX 2001A Extended Cycle Operation + ** See pg. 67, PgmrsRefMnl + */ + + reason = setjmp(trap_env); /* set break hdlr */ + if (0 == reason) + { + if (!STREAM && second_cycle) + { + if (SCPE_OK != (reason = execute(temp_ir))) + { + return (reason); + } + } + else + { + if (SCPE_OK != (reason = execute(IR))) + { + return (reason); + } + } + + if (stream_mode) + { + if (0 == asic_file[I]) + { + STREAM = 0; + stream_mode = 0; + rs_pop(); + if (!second_cycle) + { + _long_fetch(cpr.fields.pr, asic_file[PC], &IR); + temp_ir = IR; // Save context. Could be a two cycle instruction + INC_PC; + } + } + else + { + asic_file[I] = (asic_file[I] - 1) & D16_MASK; + } + } + else + { + if (STREAM) + { /* enter streamed mode for following instruction */ + stream_mode = TRUE; + } + if (!second_cycle) + { + _long_fetch(cpr.fields.pr, asic_file[PC], &IR); + temp_ir = IR; // Save context. Could be a two cycle instruction + INC_PC; + } + } + + sim_interval -= (sim_interval <= 0) ? 0 : 1; + + if (sim_step && (--sim_step <= 0)) + { + reason = SCPE_STOP; + break; + } + } + + } while (reason == 0); /* loop until halted */ + + return reason; +} + +t_stat cpu_boot(t_value unit_num, DEVICE *dptr) +{ + _long_fetch(cpr.fields.pr, 0, &IR); + INC_PC; + return SCPE_OK; +} + +t_stat cpu_ex(t_value *vptr, t_addr ea, UNIT *uptr, t_svalue sw) +{ + t_value m = sw & SWMASK('M'); + if (vptr == NULL) + return SCPE_ARG; + if (ea >= RAM_SIZE) + return SCPE_NXM; + byte_fetch(ea, vptr); + if (m) + { + RTX_WORD temp = 0; + _long_fetch(cpr.fields.pr, ea, &temp); + print_instruction(temp, cpr.pr, ea); + } + return SCPE_OK; +} + +t_stat cpu_dep(t_value val, t_addr ea, UNIT *uptr, t_svalue sw) +{ + if (ea >= RAM_SIZE) + return SCPE_NXM; + byte_store(ea, val); + return SCPE_OK; +} + +t_stat cpu_reset(DEVICE *dptr) +{ + // init debug support + // sim_brk_types = DBG_ASB; // SWMASK('E'); //| DBG_ASB | DBG_PSB | DBG_MEB | DBG_RSB; + sim_brk_dflt = SWMASK('E'); + sim_vm_step_unit = "cycle"; + sim_brk_type_desc = cpu_breakpoints; + sim_brk_types = SWMASK('E') | DBG_ASB_W | DBG_ASB_R | DBG_PSB_W | DBG_PSB_R | DBG_MEB_W | DBG_MEB_R | DBG_RSB_W | DBG_RSB_R; + sim_vm_pc_value = &rtx2001a_pc_value; + if (bad_insn == dispatch_vector_1[OP_0BRANCH]) + { + init_dispatch_vectors(); + } + + // init machine + memset(ram, 0xA5A5, RAM_SIZE * sizeof(RTX_WORD)); + memset(ps, 0xA5A5, PS_MAX + 1); + memset(rs, 0xA5A5, RS_MAX + 1); + memset(asic_file, 0, ASIC_MAX * sizeof(RTX_WORD)); + memset(gdata, 0xA5A5, GDATA_SIZE * sizeof(RTX_WORD)); + IR = 0; + clocks = 0; + second_cycle = 0; + STREAM = 0; + + // Initialize ASIC bus + REG *rptr = NULL; + for (rptr = dptr->registers; (rptr != NULL) && (rptr->name != NULL); rptr++) + { + if (0 == strcmp(rptr->name, "I")) + { + asic_file[I] = asic_file[I_ASIC] = asic_file[I_ALU] = D16_UMAX; + } + else if (0 == strcmp(rptr->name, "IR")) + { + // written by INC_PC + } + else if (0 == strcmp(rptr->name, "CR")) + { + // Boot=1; Interrupts disabled; Byte Order=0 (BE) + cr.pr = 0; + BOOT = SID = 1; + } + else if (0 == strcmp(rptr->name, "MD")) + { + asic_file[MD] = D16_UMAX; + } + else if (0 == strcmp(rptr->name, "IMR")) + { + imr.pr = 0; + } + else if (0 == strcmp(rptr->name, "SPR")) + { + TOP = IR = spr.pr = 0; + NEXT = 0xFFFF; + } + else if (0 == strcmp(rptr->name, "SUR")) + { + // Consider 0x0707 See rtx2000_simulator/STATE.C:58 + sur.pr = 0; + // psf: 1, pss: 1, rsf: 1, rss: 1 + PSF = RSF = PSS = RSS = 1; + } + else if (0 == strcmp(rptr->name, "SVR")) + { + svr.pr = 0; + PVL = RVL = 0x3F; + } + else if (0 == strcmp(rptr->name, "IVR")) + { + ivr.pr = 0x200; + } + else if (0 == strcmp(rptr->name, "IPR")) + { + ipr.pr = 0; + } + else if (0 == strcmp(rptr->name, "DPR")) + { + dpr.pr = 0; + } + else if (0 == strcmp(rptr->name, "UPR")) + { + upr.pr = 0; + } + else if (0 == strcmp(rptr->name, "CPR")) + { + cpr.pr = 0; + } + else if (0 == strcmp(rptr->name, "IBC")) + { + ibc.pr = 0; + } + else if (0 == strcmp(rptr->name, "UBR")) + { + ubr.pr = 0; + } + } + return SCPE_OK; +} diff --git a/RTX2001A/rtx2001a_debug.h b/RTX2001A/rtx2001a_debug.h new file mode 100644 index 000000000..1442301de --- /dev/null +++ b/RTX2001A/rtx2001a_debug.h @@ -0,0 +1,90 @@ +/* rtx2001a_debug.h: RTX2001A CPU simulator + + Copyright (c) 2022, Systasis Computer Systems, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + SYSTASIS COMPUTER SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Systasis Computer Systems shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Systasis Computer Systems. + + 6-Sep-22 SYS Initial version +*/ +#ifndef RTX2001A_DEBUG_H_ +#define RTX2001A_DEBUG_H_ 0 + +#include "rtx2001a_defs.h" + +/* Debug */ +#define DBG_CPU SWMASK('E') +#define DBG_PSB_R SWMASK('Y') // parameter stack bus read +#define DBG_PSB_W SWMASK('X') // parameter stack bus write +#define DBG_RSB_R SWMASK('V') // return stack bus read +#define DBG_RSB_W SWMASK('U') // return stack bus write +#define DBG_MEB_R SWMASK('S') // memory bus read +#define DBG_MEB_W SWMASK('R') // memory bus write +#define DBG_ASB_R SWMASK('P') // ASIC bus read +#define DBG_ASB_W SWMASK('O') // ASIC bus write + +#define STOP_HALT 1 +#define STOP_IBKPT 2 +#define STOP_ACCESS 3 + +static BRKTYPTAB cpu_breakpoints[] = { + BRKTYPE('E', "CPU breakpoint"), + {DBG_PSB_R, "Read from parameter stack bus"}, + {DBG_PSB_W, "Write to parameter stack bus"}, + {DBG_RSB_R, "Read from return stack bus"}, + {DBG_RSB_W, "Write to return stack bus"}, + {DBG_MEB_R, "Read from memory bus"}, + {DBG_MEB_W, "Write to memory bus"}, + {DBG_ASB_R, "Read from ASIC bus"}, + {DBG_ASB_W, "Write to ASIC bus"}, + {0}}; + +static DEBTAB cpu_deb[] = { + {"CPU", DBG_CPU, "CPU"}, + {"MEBR", DBG_MEB_R, "Read from Memory bus"}, + {"MEBW", DBG_MEB_W, "Write to Memory bus"}, + {"ASBR", DBG_ASB_R, "Read from ASIC bus"}, + {"ASBW", DBG_ASB_W, "Write to ASIC bus"}, + {"PSBR", DBG_PSB_R, "Read from Parameter Stack bus"}, + {"PSBW", DBG_PSB_W, "Write to Parameter Stack bus"}, + {"RSBR", DBG_RSB_R, "Read from Return Stack bus"}, + {"RSBW", DBG_RSB_W, "Write to Return Stack bus"}, + {0}}; + +#define DEBUG_SET(s, b) \ + { \ + struct \ + { \ + RTX_WORD o; \ + } o; \ + o.o = s; \ + s = (value & D16_MASK); \ + *val = s; \ + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, (&cpu_reg[++cell])->name, b, o.o, *val, 1); \ + } + +// #define DEBUG_LOG(mask, verb, name, value) \ +// if (sim_brk_summ & mask) \ +// { \ +// sim_debug(verb, &cpu_dev, "%s: 0x%X\n", (char *)name, value); \ +// } + +#endif \ No newline at end of file diff --git a/RTX2001A/rtx2001a_decode.c b/RTX2001A/rtx2001a_decode.c new file mode 100644 index 000000000..3bd8a01db --- /dev/null +++ b/RTX2001A/rtx2001a_decode.c @@ -0,0 +1,638 @@ +/* rtx2001a_decode.c: RTX2001A simulator definitions + + Copyright (c) 2022, Systasis Computer Systems, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + SYSTASIS COMPUTER SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Systasis Computer Systems shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Systasis Computer Systems. + + 10-Oct-22 SYS New simulator. + + Instruction decoding + + See SIMM2000/DECODE.C + */ +#include "rtx2001a_registers.h" +#include "rtx2001a_defs.h" +#include "rtx2001a_debug.h" +#include "rtx2001a_decode.h" + +/** + * Driver for instruction operation cracking. + * Input: 16-bit RTX instruction + * Output: enum for operation to be performed (exclusive of alu/shift op). + */ +t_stat decode(t_value instruction, machine_op *opcode) +{ + if (instruction & 0x8000) + { /* non-call instructions */ + switch (instruction & 0xF000) /* 3 bits of top 4 */ + { + case 0x8000: /* Branch */ + case 0x9000: /* Branch */ + return (decode_branch(instruction, opcode)); + + case 0xA000: /* ALU */ + if (instruction & 0x0010) + { + return (decode_step_math(instruction, opcode)); + } + return (decode_alu(instruction, opcode)); + + case 0xB000: /* G@/G! or short_lit */ + if (instruction & 0x0040) + { + return (decode_short_lit(instruction, opcode)); + } + return (decode_gbus(instruction, opcode)); + + case 0xC000: /* U@/U! */ + return (decode_user(instruction, opcode)); + + case 0xD000: /* long literal */ + return (decode_long_lit(instruction, opcode)); + + case 0xE000: /* word memory access*/ + case 0xF000: /* byte memory access*/ + return (decode_memory(instruction, opcode)); + } + } + else + { /* call instruction */ + *opcode = OP_CALL; + return SCPE_OK; + } + return STOP_UNK; // Defensive, no test +} + +/** Decode given that the instruction is known to be ALU class, + * returning an enum corresponding to the instruction type + * + * 1010 xxxx xxx0 xxxx + */ +t_stat decode_alu(t_value instruction, machine_op *opcode) +{ + switch (instruction & 0x00C0) + { + case 0x0000: // 1010 xxxx 00x0 xxxx + if ((instruction & 0x0E00) == 0x0000) + { + *opcode = OP_SHIFT; // 1010 000x 00x0 xxxx + return SCPE_OK; + } + if ((instruction & 0x0E00) == 0x0E00) + { + *opcode = OP_DROP_DUP; // 1010 111x 00x0 xxxx + return SCPE_OK; + } + *opcode = OP_UNDER_ALU; // 1010 cccc 00x0 xxxx + return SCPE_OK; + + case 0x0040: // 1010 xxxx 01x0 xxxx + if ((instruction & 0x0E00) == 0x0000) + { + *opcode = OP_NIP; // 1010 000x 01x0 xxxx + return SCPE_OK; + } + + if ((instruction & 0x0E00) == 0x0E00) + { + *opcode = OP_DROP; // 1010 111x 01x0 xxxx + return SCPE_OK; + } + + *opcode = OP_ALU; // 1010 cccc 01x0 xxxx + return SCPE_OK; + + case 0x0080: // 1010 xxxx 10x0 xxxx + if ((instruction & 0x0E00) == 0x0000) + { + *opcode = OP_NIP_DUP; // 1010 000x 10x0 xxxx + return SCPE_OK; + } + + if ((instruction & 0x0E00) == 0x0E00) + { + *opcode = OP_SWAP; // 1010 111x 10x0 xxxx + return SCPE_OK; + } + + *opcode = OP_TUCK_ALU; // 1010 cccc 10x0 xxxx + return SCPE_OK; + + case 0x00C0: // 1010 xxxx 11x0 xxxx + if ((instruction & 0x0E00) == 0x0000) + { + *opcode = OP_DUP; // 1010 000x 11x0 xxxx + return SCPE_OK; + } + + if ((instruction & 0x0E00) == 0x0E00) + { + *opcode = OP_OVER; // 1010 111x 11x0 xxxx + return SCPE_OK; + } + + *opcode = OP_DDUP_ALU; // 1010 cccc 11x0 xxxx + return SCPE_OK; + } + return STOP_UNK; // defensive bug check, not tested +} + +/** + * Decode given that the instruction is known to be BRANCH class, + * returning an enum corresponding to the instruction type + * + * 100x xbba aaaa aaaa + */ +t_stat decode_branch(t_value instruction, machine_op *opcode) +{ + *opcode = (machine_op)NIL; + switch (instruction & 0xF800) // which type of branch instruction + { + case 0x8000: + *opcode = OP_QDUP_0BRANCH; + return SCPE_OK; + case 0x8800: + *opcode = OP_0BRANCH; + return SCPE_OK; + case 0x9000: + *opcode = OP_BRANCH; + return SCPE_OK; + case 0x9800: + *opcode = OP_NEXT; + return SCPE_OK; + } + return STOP_UNK; // defensive bug check, not tested +} + +/** + * Decode given that the instruction is known to be SHORT LIT class, + * returning an enum corresponding to the instruction type + * + * 1011 xxxx x1xx xxxx --- short_lit + */ +t_stat decode_short_lit(t_value instruction, machine_op *opcode) +{ + switch (instruction & 0x00C0) + { + case 0x0040: // 1011 xxxx 01xx xxxx + if ((instruction & 0x0E00) == 0x0000) + { + *opcode = OP_RESERVED; // 1011 000x 01xx xxxx + return SCPE_OK; + } + if ((instruction & 0x0E00) == 0x0E00) + { + *opcode = OP_SHORT_LIT; // 1011 111x 01xd dddd + return SCPE_OK; + } + *opcode = OP_SHORT_LIT_OVER_ALU; // 1011 cccc 01xd dddd + return SCPE_OK; + + case 0x00C0: // 1011 xxxx 11xx xxxx + if ((instruction & 0x0E00) == 0x0000) + { + *opcode = OP_RESERVED; // 1011 000x 11xx xxxx + return SCPE_OK; + } + if ((instruction & 0x0E00) == 0x0E00) + { + *opcode = OP_DROP_SHORT_LIT; // 1011 111x 11xd dddd + return SCPE_OK; + } + *opcode = OP_SHORT_LIT_SWAP_ALU; // 1011 cccc 11xd dddd + return SCPE_OK; + } + return STOP_UNK; // defensive bug check, not tested +} + +/** + * Decode given that the instruction is known to be GBUS class, + * returning an enum corresponding to the instruction type + * + * 1011 xxxx xxxx xxxx + */ +t_stat decode_gbus(t_value instruction, machine_op *opcode) +{ + int result = 0; + + if ((instruction & 0xFF40) == 0xB000) + { + decode_special(instruction, opcode); + if (OP_RESERVED != *opcode) + { + return SCPE_OK; + } + } + + // Prevent operations on certain ASIC addresses + int middle_flag = ((instruction & 0x001F) > 0x07 && (instruction & 0x001F) < 0x18) ? TRUE : FALSE; + *opcode = OP_RESERVED; + + switch (instruction & 0x00C0) + { // case 0x0040 is a short lit instruction + case 0x0000: /* 1011 xxxx 00xx xxxx */ + if ((instruction & 0x0E00) == 0x0000) + { + *opcode = middle_flag ? OP_RESERVED : OP_GFETCH_DROP; /* 1011 000x 00xg gggg */ + return SCPE_OK; + } + + if ((instruction & 0x0E00) == 0x0E00) + { + *opcode = OP_GFETCH; /* 1011 111x 00xg gggg */ + return SCPE_OK; + } + + *opcode = middle_flag ? OP_RESERVED : OP_GFETCH_OVER_ALU; /* 1011 cccc 00xg gggg */ + return SCPE_OK; + + case 0x0080: /* 1011 xxxx 10xx xxxx */ + if ((instruction & 0x0E00) == 0x0000) + { + *opcode = middle_flag ? OP_RESERVED : OP_DUP_GSTORE; /* 1011 000x 10xg gggg */ + return SCPE_OK; + } + + if ((instruction & 0x0E00) == 0x0E00) + { + *opcode = OP_GSTORE; /* 1011 111x 10xg gggg */ + return SCPE_OK; + } + + // Allow ALU operations + *opcode = (middle_flag && ((instruction & 0x1F) != 0x11) && ((instruction & 0x1F) != 0x09)) ? OP_RESERVED : OP_GFETCH_SWAP_ALU; /* 1011 cccc 10xg gggg */ + return SCPE_OK; + } + ABORT(STOP_UNK); +} + +/** + * Decode given that the instruction is known to be LONG LITERAL class, + * returning an enum corresponding to the instruction type + * + * 1101 xxxx xxxx xxxx --- long literal + */ +t_stat decode_long_lit(t_value instruction, machine_op *opcode) +{ + if (instruction & 0x001F) + { // See DECODE.C:294 wrong bit pattern for $D01F + *opcode = OP_RESERVED; // 1101 xxxx xxx1 yyyy + return SCPE_OK; + } + + switch (instruction & 0x00C0) + { + case 0x0000: // 1101 xxxx 00xx xxxx + if ((instruction & 0x0E00) == 0x0000) + { + *opcode = OP_LIT_SWAP; /* 1101 000x 00xx xxxx */ + return SCPE_OK; + } + if ((instruction & 0x0E00) == 0x0E00) + { + *opcode = OP_LIT; /* 1101 111x 00xx xxxx */ + return SCPE_OK; + } + *opcode = OP_LIT_OVER_ALU; /* 1101 cccc 00xx xxxx */ + return SCPE_OK; + + case 0x0080: /* 1101 xxxx 10xx xxxx */ + if ((instruction & 0x0E00) == 0x0000) + { + *opcode = OP_RESERVED; /* 1101 000x 10xx xxxx */ + return SCPE_OK; + } + if ((instruction & 0x0E00) == 0x0E00) + { + *opcode = OP_DROP_LIT; /* 1101 111x 10xx xxxx */ + return SCPE_OK; + } + *opcode = OP_LIT_SWAP_ALU; /* 1101 cccc 10xx xxxx */ + return SCPE_OK; + } + *opcode = OP_RESERVED; /* 1101 xxxx x1xx xxxx */ + return SCPE_OK; +} + +/** + * Check for "special" instructions given that the instruction + * is known to be GBUS class, returning an enum corresponding + * to the instruction type if found, otherwise returning 0. + */ +t_stat decode_special(t_value instruction, machine_op *opcode) +{ + switch (instruction & 0xFFDF) + { + case 0xB00D: + *opcode = OP_SELECT_CPR; + return SCPE_OK; + case 0xB010: + *opcode = OP_CLEAR_SOFTINT; + return SCPE_OK; + case 0xB08D: + *opcode = OP_SELECT_DPR; + return SCPE_OK; + case 0xB090: + *opcode = OP_SET_SOFTINT; + return SCPE_OK; + case 0xB016: + *opcode = OP_DEC_RX; + return SCPE_OK; + case 0xB096: + *opcode = OP_INC_RX; + return SCPE_OK; + } + *opcode = OP_RESERVED; + return SCPE_OK; +} + +/** + * Decode given that the instruction is known to be MEMORY class, + * returning an enum corresponding to the instruction type + * + * 111x xxxx xxxx xxxx --- memory access + */ +t_stat decode_memory(t_value instruction, machine_op *opcode) +{ + switch (instruction & 0x01C0) + { + case 0x0000: // 111x xxx0 00xx xxxx + case 0x0100: // 111x xxx1 00xx xxxx + if (instruction & 0x001F) + { + *opcode = OP_RESERVED; // low 5 bits not 0 + return SCPE_OK; + } + + if ((instruction & 0x0E00) == 0x0000) + { + *opcode = OP_FETCH_SWAP; // 111x 000x 00xx xxxx + return SCPE_OK; + } + + if ((instruction & 0x0E00) == 0x0E00) + { + *opcode = OP_FETCH; // 111x 111x 00xx xxxx + return SCPE_OK; + } + + *opcode = OP_FETCH_OVER_ALU; // 111x cccc 00xx xxxx + return SCPE_OK; + + case 0x0040: // 111x xxx0 01xx xxxx + if ((instruction & 0x0E00) == 0x0000) + { + if (instruction & 0x001F) + { + *opcode = OP_RESERVED; // low 5 bits not 0 + return SCPE_OK; + } + *opcode = OP_NIP_DUP_FETCH_SWAP; // 111x 0000 01xx xxxx + return SCPE_OK; + } + + if ((instruction & 0x0E00) == 0x0E00) + { + *opcode = OP_NIP_FETCH_LIT; // 111x 1110 01xd dddd + return SCPE_OK; + } + + // NIP DUP @ SWAP d SWAP ALU + *opcode = OP_NIP_FETCH_WITH_ALU; // 111x aaa0 01xx xxxx + return SCPE_OK; + + case 0x0140: // 111x xxx1 01xx xxxx + + if ((instruction & 0x0E00) == 0x0000) + { + if (instruction & 0x001F) + { + *opcode = OP_RESERVED; // low 5 bits not 0 + return SCPE_OK; + } + *opcode = OP_DUP_FETCH_SWAP; // 111x 0001 01xx xxxx + return SCPE_OK; + } + + if ((instruction & 0x0E00) == 0x0E00) + { + *opcode = OP_FETCH_LIT; // 111x 1111 01xd dddd + return SCPE_OK; + } + + // DUP @ SWAP d SWAP ALU + *opcode = OP_FETCH_WITH_ALU; // 111x aaa1 01xx xxxx + return SCPE_OK; + + case 0x0080: // 111x xxx0 10xx xxxx + case 0x0180: // 111x xxx1 10xx xxxx + if (instruction & 0x001F) + { + *opcode = OP_RESERVED; // low 5 bits not 0 + return SCPE_OK; + } + + if ((instruction & 0x0E00) == 0x0000) + { + *opcode = OP_UNDER_STORE; // 111x 000x 10xx xxxx + return SCPE_OK; + } + + if ((instruction & 0x0E00) == 0x0E00) + { + *opcode = OP_STORE; // 111x 111x 10xx xxxx + return SCPE_OK; + } + + *opcode = OP_FETCH_SWAP_ALU; // 111x cccc 10xx xxxx + return SCPE_OK; + + case 0x00C0: // 111x xxx0 11xx xxxx + if ((instruction & 0x0E00) == 0x0000) + { + if (instruction & 0x001F) + { + *opcode = OP_RESERVED; // low 5 bits not 0 + return SCPE_OK; + } + *opcode = OP_DDUP_STORE; // 111x 0000 11xx xxxx + return SCPE_OK; + } + + if ((instruction & 0x0E00) == 0x0E00) + { + *opcode = OP_UNDER_STORE_LIT; // 111x 1110 11xd dddd + return SCPE_OK; + } + + // DDUP ! d SWAP alu + *opcode = OP_DDUP_STORE_WITH_ALU; // 111x aaa0 11xx xxxx + return SCPE_OK; + + case 0x01C0: // 111x xxx1 11xx xxxx + if ((instruction & 0x0E00) == 0x0000) + { + if (instruction & 0x001F) + { + *opcode = OP_RESERVED; // low 5 bits not 0 + return SCPE_OK; + } + *opcode = OP_TUCK_STORE; // 111x 0001 11xx xxxx + return SCPE_OK; + } + + if ((instruction & 0x0E00) == 0x0E00) + { + *opcode = OP_STORE_LIT; // 111x 1111 11xd dddd + return SCPE_OK; + } + + // TUCK ! d SWAP alu + *opcode = OP_TUCK_STORE_WITH_ALU; // 111x aaa1 11xx xxxx + return SCPE_OK; + } + + return STOP_HALT; // Defensive, no test case +} + +/** + * Decode given that the instruction is known to be USER MEMORY class, + * returning an enum corresponding to the instruction type + * + * 1100 xxxx x0xx xxxx --- U@/U! + */ +t_stat decode_user(t_value instruction, machine_op *opcode) +{ + switch (instruction & 0x00C0) + { + case 0x0000: // 1100 xxxx 00xx xxxx + if ((instruction & 0x0E00) == 0x0000) + { + *opcode = OP_UFETCH_SWAP; // 1100 000x 00xu uuuu + return SCPE_OK; + } + + if ((instruction & 0x0E00) == 0x0E00) + { + *opcode = OP_UFETCH; // 1100 111x 00xu uuuu + return SCPE_OK; + } + + *opcode = OP_UFETCH_OVER_ALU; // 1100 cccc 00xu uuuu + return SCPE_OK; + + case 0x0080: // 1100 xxxx 10xx xxxx + if ((instruction & 0x0E00) == 0x0000) + { + *opcode = OP_DUP_USTORE; // 1100 000x 10xu uuuu + return SCPE_OK; + } + + if ((instruction & 0x0E00) == 0x0E00) + { + *opcode = OP_USTORE; // 1100 111x 10xu uuuu + return SCPE_OK; + } + + *opcode = OP_UFETCH_SWAP_ALU; // 1100 cccc 10xu uuuu + return SCPE_OK; + } + return STOP_HALT; +} + +/** + * Decode given that the instruction is known to be STEP MATH class, + * returning an enum corresponding to the instruction type + */ +t_stat decode_step_math(t_value instruction, machine_op *opcode) +{ + *opcode = OP_RESERVED_STEP_MATH; + switch (instruction & 0xFFDF) + { // recognize only fully supported/documented step math operations + case 0xA012: + *opcode = OP_TWO_STAR_TICK; // 2*' + break; + case 0xA096: + *opcode = OP_RTR; // RTR + break; + case 0xA09E: + *opcode = OP_RDR; // RDR + break; + case 0xA196: + *opcode = OP_R_TICK; // R' + break; + case 0xA412: + *opcode = OP_BUSLASH_TICK; // BU/' + break; + case 0xA418: + *opcode = OP_USLASH_ONE_TICK_TICK; // U/1'' + break; + case 0xA41A: + *opcode = OP_USLASH_ONE_TICK; // U/1' + break; + case 0xA458: + *opcode = OP_USLASH_TICK_TICK; // U/'' + break; + case 0xA45A: + *opcode = OP_USLASH_TICK; // U/' + break; + case 0xA494: + *opcode = OP_BUSTAR_TICK_TICK; // BU*'' + break; + case 0xA49C: + *opcode = OP_USTAR_TICK_TICK; // U*'' + break; + case 0xA49D: + *opcode = OP_STAR_TICK_TICK; // *'' + break; + case 0xA512: + *opcode = OP_BS_ONE_TICK; // BS1' + break; + case 0xA51A: + *opcode = OP_S_ONE_TICK; // S1' + break; + case 0xA552: + *opcode = OP_BS_TICK; // BS' + break; + case 0xA558: + *opcode = OP_S_TICK_TICK; // S'' + break; + case 0xA55A: + *opcode = OP_S_TICK; // S' + break; + case 0xA894: + *opcode = OP_BUSTAR_TICK; // BU*' + break; + case 0xA89C: + *opcode = OP_USTAR_TICK; // U*' + break; + case 0xA89D: + *opcode = OP_STAR_TICK; // *' + break; + case 0xAADE: + *opcode = OP_C_TICK; // C' + break; + default: + return STOP_INVOPCOD; + } + return SCPE_OK; +} diff --git a/RTX2001A/rtx2001a_decode.h b/RTX2001A/rtx2001a_decode.h new file mode 100644 index 000000000..1dd6cf837 --- /dev/null +++ b/RTX2001A/rtx2001a_decode.h @@ -0,0 +1,166 @@ +/* rtx2001a_decode.h: RTX2001A simulator definitions + + Copyright (c) 2022, Systasis Computer Systems, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + SYSTASIS COMPUTER SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Systasis Computer Systems shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Systasis Computer Systems. + + 10-Oct-22 SYS New simulator. + + See SIMM2000/DECODE.H + + This file contains the enum definition for result of instruction cracking operations, and prototypes for the decoding subroutine. + */ +#ifndef RTX2001A_DECODE_H_ +#define RTX2001A_DECODE_H_ 0 + +#include "rtx2001a_defs.h" + +#define NIL 0 + +typedef enum machine_op +{ + OP_CALL, + OP_0BRANCH, + OP_ALU, + OP_ASIC_STREAM_MAC, + OP_BRANCH, + OP_BS_ONE_TICK, + OP_BS_TICK, + OP_BUSLASH_TICK, + OP_BUSTAR_TICK, + OP_BUSTAR_TICK_TICK, + OP_CLEAR_ACC, + OP_CLEAR_SOFTINT, + OP_C_TICK, + OP_DDUP_ALU, + OP_DDUP_STORE, + OP_DDUP_STORE_WITH_ALU, + OP_DEC_RX, + OP_DROP, + OP_DROP_DUP, + OP_DROP_LIT, + OP_DROP_SHORT_LIT, + OP_DSLL, + OP_DSRA, + OP_DSRL, + OP_DUP, + OP_DUP_FETCH_SWAP, + OP_DUP_GSTORE, + OP_DUP_USTORE, + OP_FETCH, + OP_FETCH_LIT, + OP_FETCH_OVER_ALU, + OP_FETCH_SWAP, + OP_FETCH_SWAP_ALU, + OP_FETCH_WITH_ALU, + OP_GFETCH, + OP_GFETCH_DROP, + OP_GFETCH_OVER_ALU, + OP_GFETCH_SWAP_ALU, + OP_GSTORE, + OP_INC_RX, + OP_LIT, + OP_LIT_OVER_ALU, + OP_LIT_SWAP, + OP_LIT_SWAP_ALU, + OP_MAC, + OP_MIXED_MAC, + OP_MIXED_MULT, + OP_MULT, + OP_MULT_SUB, + OP_NEXT, + OP_NIP, + OP_NIP_DUP, + OP_NIP_DUP_FETCH_SWAP, + OP_NIP_FETCH_LIT, + OP_NIP_FETCH_WITH_ALU, + OP_NORMALIZE, + OP_OVER, + OP_QDUP_0BRANCH, + OP_RDR, + OP_RESERVED, + OP_RESERVED_STEP_MATH, + OP_RTR, + OP_R_TICK, + OP_SELECT_CPR, + OP_SELECT_DPR, + OP_SET_SOFTINT, + OP_SHIFT, + OP_SHIFT_MAC_RIGHT, + OP_SHORT_LIT, + OP_SHORT_LIT_OVER_ALU, + OP_SHORT_LIT_SWAP_ALU, + OP_STAR_TICK, + OP_STAR_TICK_TICK, + OP_STORE, + OP_STORE_LIT, + OP_STREAM_MAC, + OP_SWAP, + OP_S_ONE_TICK, + OP_S_TICK, + OP_S_TICK_TICK, + OP_TUCK_ALU, + OP_TUCK_STORE, + OP_TUCK_STORE_WITH_ALU, + OP_TWO_STAR_TICK, + OP_UFETCH, + OP_UFETCH_OVER_ALU, + OP_UFETCH_SWAP, + OP_UFETCH_SWAP_ALU, + OP_UMAC, + OP_UMULT, + OP_UNDER_ALU, + OP_UNDER_STORE, + OP_UNDER_STORE_LIT, + OP_USLASH_ONE_TICK, + OP_USLASH_ONE_TICK_TICK, + OP_USLASH_TICK, + OP_USLASH_TICK_TICK, + OP_USTAR_TICK, + OP_USTAR_TICK_TICK, + OP_USTORE, + OP_ZERO_EQUAL, + DUMMY_LAST /* put here as a bounds check for initialization */ +} machine_op; + +/* Driver for instruction operation cracking. + * Input: 16-bit RTX instruction + * Output: enum for operation to be performed (exclusive of alu/shift op). + */ +t_stat decode(t_value instruction, machine_op *opcode); +t_stat decode_branch(t_value instruction, machine_op *opcode); +t_stat decode_step_math(t_value instruction, machine_op *opcode); +t_stat decode_alu(t_value instruction, machine_op *opcode); +t_stat decode_short_lit(t_value instruction, machine_op *opcode); +t_stat decode_gbus(t_value instruction, machine_op *opcode); +t_stat decode_user(t_value instruction, machine_op *opcode); +t_stat decode_long_lit(t_value instruction, machine_op *opcode); +t_stat decode_memory(t_value instruction, machine_op *opcode); +t_stat decode_special(t_value instruction, machine_op *opcode); + +/* Compute branch target address + * Input: instruction = 16-bit RTX instruction + * address = 16-bit RTX address + * Output: 16-bit RTX branch target address + */ +extern t_addr target_addr(t_value instruction, t_addr address); +#endif \ No newline at end of file diff --git a/RTX2001A/rtx2001a_defs.h b/RTX2001A/rtx2001a_defs.h new file mode 100644 index 000000000..766e47c81 --- /dev/null +++ b/RTX2001A/rtx2001a_defs.h @@ -0,0 +1,152 @@ +/* rtx2001a_defs.h: RTX2001A simulator definitions + + Copyright (c) 2022, Systasis Computer Systems, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + SYSTASIS COMPUTER SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Systasis Computer Systems shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Systasis Computer Systems. + + 12-Aug-22 SYS New simulator. +*/ + +#ifndef RTX2001A_DEFS_H_ +#define RTX2001A_DEFS_H_ 0 + +#include "setjmp.h" + +#include "sim_defs.h" + +/* Architectural constants. +** +** See hp3000_defs.h:356 +*/ +typedef uint32 RTX_WORD; /* RTX2001A 16-bit data word representation */ + +#define R_MASK 0177777u /* 16-bit register mask */ + +#define D4_WIDTH 4 /* 4-bit data bit width */ +#define D4_MASK 0017u /* 4-bit data mask */ + +#define D6_WIDTH 6 /* 6-bit data bit width */ +#define D6_MASK 077u /* 6-bit data mask */ + +#define D8_WIDTH 8 /* 8-bit data bit width */ +#define D8_MASK 0377u /* 8-bit data mask */ +#define D8_UMAX 0377u /* 8-bit unsigned maximum value */ +#define D8_SMAX 0177u /* 8-bit signed maximum value */ +#define D8_SMIN 0200u /* 8-bit signed minimum value */ +#define D8_SIGN 0200u /* 8-bit sign */ + +#define D16_WIDTH 16 /* 16-bit data bit width */ +#define D16_MASK 0177777u /* 16-bit data mask */ +#define D16_UMAX 0177777u /* 16-bit unsigned maximum value */ +#define D16_SMAX 0077777u /* 16-bit signed maximum value */ +#define D16_SMIN 0100000u /* 16-bit signed minimum value */ +#define D16_SIGN 0100000u /* 16-bit sign */ + +#define D32_WIDTH 32 /* 32-bit data bit width */ +#define D32_MASK 037777777777u /* 32-bit data mask */ +#define D32_UMAX 037777777777u /* 32-bit unsigned maximum value */ +#define D32_SMAX 017777777777u /* 32-bit signed maximum value */ +#define D32_SMIN 020000000000u /* 32-bit signed minimum value */ +#define D32_SIGN 020000000000u /* 32-bit sign */ + +#define D48_WIDTH 48 /* 48-bit data bit width */ +#define D48_MASK 07777777777777777uL /* 48-bit data mask */ +#define D48_UMAX 07777777777777777uL /* 48-bit unsigned maximum value */ +#define D48_SMAX 03777777777777777uL /* 48-bit signed maximum value */ +#define D48_SMIN 04000000000000000uL /* 48-bit signed minimum value */ +#define D48_SIGN 04000000000000000uL /* 48-bit sign */ + +#define D64_WIDTH 64 /* 64-bit data bit width */ +#define D64_MASK 01777777777777777777777uL /* 64-bit data mask */ +#define D64_UMAX 01777777777777777777777uL /* 64-bit unsigned maximum value */ +#define D64_SMAX 00777777777777777777777uL /* 64-bit signed maximum value */ +#define D64_SMIN 01000000000000000000000uL /* 64-bit signed minimum value */ +#define D64_SIGN 01000000000000000000000uL /* 64-bit sign */ + +#define S16_OVFL_MASK ((uint32)D16_UMAX << D16_WIDTH | \ + D16_SIGN) /* 16-bit signed overflow mask */ + +#define S32_OVFL_MASK ((t_uint64)D32_UMAX << D32_WIDTH | \ + D32_SIGN) /* 32-bit signed overflow mask */ + +/* Portable conversions. +** +** See hp3000_defs.h:555 +*/ +#define SEXT8(x) (int32)((x)&D8_SIGN ? (x) | ~D8_MASK : (x)) +#define SEXT16(x) (int32)((x)&D16_SIGN ? (x) | ~D16_MASK : (x)) + +#define NEG8(x) ((~(x) + 1) & D8_MASK) +#define NEG16(x) ((~(x) + 1) & D16_MASK) +#define NEG32(x) ((~(x) + 1) & D32_MASK) + +#define INT16(u) ((u) > D16_SMAX ? (-(int16)(D16_UMAX - (u)) - 1) : (int16)(u)) +#define INT32(u) ((u) > D32_SMAX ? (-(int32)(D32_UMAX - (u)) - 1) : (int32)(u)) + +/* Half-byte accessors */ + +#define UPPER_HALF(b) ((b) >> D4_WIDTH & D4_MASK) +#define LOWER_HALF(b) ((b)&D4_MASK) + +/* Byte accessors. +** +** See hp3000_defs.h:601 +*/ +typedef enum +{ + upper, /* upper byte selected */ + lower /* lower byte selected */ +} BYTE_SELECTOR; + +#define UPPER_BYTE(w) (uint8)((w) >> D8_WIDTH & D8_MASK) +#define LOWER_BYTE(w) (uint8)((w)&D8_MASK) +#define TO_WORD(u, l) (RTX_WORD)(((u)&D8_MASK) << D8_WIDTH | (l)&D8_MASK) + +#define REPLACE_UPPER(w, b) ((w)&D8_MASK | ((b)&D8_MASK) << D8_WIDTH) +#define REPLACE_LOWER(w, b) ((w)&D8_MASK << D8_WIDTH | (b)&D8_MASK) + +/* Double-word accessors */ + +#define UPPER_WORD(d) (RTX_WORD)((d) >> D16_WIDTH & D16_MASK) +#define LOWER_WORD(d) (RTX_WORD)((d)&D16_MASK) + +#define TO_DWORD(u, l) ((RTX_WORD)(u) << D16_WIDTH | (l)) + +extern t_bool build_dev_tab(void); +extern DEVICE cpu_dev; +extern int32 sim_emax; // contains the maximum number of words needed to hold the largest instruction or data item in the VM. Examine and deposit will process up to sim_emax words. +extern t_stat cpu_reset(DEVICE *); +extern t_stat do_cmd_label(int32 flag, CONST char *fcptr, CONST char *label); +extern t_stat cpu_boot(t_value unit_num, DEVICE *dptr); +extern jmp_buf save_env; +extern jmp_buf trap_env; // breakpoint handler + +#define STOP_UNK 0 // Unknown Error +#define STOP_HALT 1 // HALT +#define STOP_IBKPT 2 // breakpoint +#define STOP_INVOPCOD 3 // invalid instruction +#define STOP_ILLASICADDR 4 // Illegal ASIC bus address + +#define ABORT(val) longjmp(save_env, (val)) +#define TRAP(val) longjmp(trap_env, (val)) + +#endif /* RTX2001A_DEFS_H_ */ diff --git a/RTX2001A/rtx2001a_execute.c b/RTX2001A/rtx2001a_execute.c new file mode 100644 index 000000000..85fdc126c --- /dev/null +++ b/RTX2001A/rtx2001a_execute.c @@ -0,0 +1,1537 @@ +/* rtx2001a_execute.h: RTX2001A simulator definitions + + Copyright (c) 2022, Systasis Computer Systems, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + SYSTASIS COMPUTER SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Systasis Computer Systems shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Systasis Computer Systems. + + 10-Oct-22 SYS Initial version. + + See RTX2000/EXECUTE.C + + Instruction execution +*/ +#include "rtx2001a_defs.h" +#include "rtx2001a_debug.h" +#include "rtx2001a_ab.h" +#include "rtx2001a_psb.h" +#include "rtx2001a_mb.h" +#include "rtx2001a_registers.h" +#include "rtx2001a_execute.h" +#include "rtx2001a_decode.h" + +/* disassembler constants for alu functions */ +char *alu_names[] = { + /* 0 */ "", /* 1 */ "not ", + /* 2 */ "and ", /* 3 */ "nor ", + /* 4 */ "swap- ", /* 5 */ "swap-c ", + /* 6 */ "or ", /* 7 */ "nand ", + /* 8 */ "+ ", /* 9 */ "+c ", + /* a */ "xor ", /* b */ "xnor ", + /* c */ "- ", /* d */ "-c ", + /* e */ "", /* f */ "not "}; + +char *swap_alu_names[] = { + /* 0 */ "", /* 1 */ "not ", + /* 2 */ "and ", /* 3 */ "nor ", + /* 4 */ "- ", /* 5 */ "-c ", + /* 6 */ "or ", /* 7 */ "nand ", + /* 8 */ "+ ", /* 9 */ "+c ", + /* a */ "xor ", /* b */ "xnor ", + /* c */ "swap- ", /* d */ "swap-c ", + /* e */ "", /* f */ "not "}; + +/* disassembler constants for shifter functions */ +char *shift_names[] = { + /* 0 */ "", /* 1 */ "0< ", + /* 2 */ "2* ", /* 3 */ "2*c ", + /* 4 */ "cU2/ ", /* 5 */ "c2/ ", + /* 6 */ "U2/ ", /* 7 */ "2/ ", + /* 8 */ "N2* ", /* 9 */ "N2*c ", + /* A */ "D2* ", /* B */ "D2*c ", + /* C */ "cUD2/ ", /* D */ "cD2/ ", + /* E */ "UD2/ ", /* F */ "D2/ "}; + +/* disassembler constants for memory size specifiers */ +char *memory_names[] = { + /* 0 */ "", /* 1 */ "C"}; + +void bad_insn() +{ + sim_printf("%s PC=0x%X IR=0x%X\n", sim_stop_messages[STOP_INVOPCOD], asic_file[PC], IR); + // print_instruction(IR, cpr.pr, asic_file[PC]); + ABORT(STOP_IBKPT); + // longjmp(bkpt_env, STOP_IBKPT); +} + +void do_exit() +{ + cpr.pr = ipr.pr & 0x0F; + sim_debug(DBG_ASB_W, &cpu_dev, "CPR=0x%X\n", cpr.pr); + set_DPRSEL(ipr.pr & 0x10); + asic_file[PC] = asic_file[I]; + sim_debug(DBG_ASB_W, &cpu_dev, "PC=0x%X\n", asic_file[PC]); + rs_pop(); +} + +void do_call() +{ + sim_debug(DBG_ASB_R, &cpu_dev, "PC=0x%04X\n", asic_file[PC]); + rs_push(cpr.pr, asic_file[PC]); + asic_file[PC] = (IR << 1) & D16_UMAX; + sim_debug(DBG_ASB_W, &cpu_dev, "PC=0x%04X\n", asic_file[PC]); + CLOCKS(1); +} + +void do_qdup_0branch() +{ + if (!TOP) + { + sim_debug(DBG_ASB_R, &cpu_dev, "PC=0x%X\n", asic_file[PC]); + asic_file[PC] = target_addr(IR, asic_file[PC]); + sim_debug(DBG_ASB_W, &cpu_dev, "PC=0x%X\n", asic_file[PC]); + ps_pop(); + } + CLOCKS(1); +} + +/* void do_0branch() +{ + sim_debug(DBG_ASB_R, &cpu_dev, "PC=0x%X IR=0x%X\n", asic_file[PC], IR); + asic_file[PC] = target_addr(IR, asic_file[PC]); + sim_debug(DBG_ASB_W, &cpu_dev, "PC=0x%X\n", asic_file[PC]); + + if (!TOP) + { + ps_pop(); + } + CLOCKS(1); +} +*/ +void do_0branch() +{ + if (0 == TOP) + { + sim_debug(DBG_ASB_R, &cpu_dev, "PC=0x%X IR=0x%X\n", asic_file[PC], IR); + asic_file[PC] = target_addr(IR, asic_file[PC]); + sim_debug(DBG_ASB_W, &cpu_dev, "PC=0x%X\n", asic_file[PC]); + } + + ps_pop(); + CLOCKS(1); +} + +/* +** Support routines +*/ +t_stat shift() +{ + /* compute shift function */ + switch (IR & 0x000F) + { + case 0x0000: // nop + break; + + case 0x0001: // 0< + TOP = (TOP & 0x8000) ? 0xFFFF : 0x0000; + break; + + case 0x0002: // 2* + { + CR ocr; + ocr.pr = cr.pr; + CY = (TOP & 0x8000) ? 1 : 0; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "CR", cr_bits, ocr.pr, cr.pr, 0); + TOP = (TOP << 1) & 0xFFFE; + } + break; + + case 0x0003: /* 2*c */ + { + CR ocr; + ocr.pr = cr.pr; + t_value temp = (TOP << 1) & 0xFFFE; + if (CY) + { + temp = temp | 1; + } + CY = (TOP & 0x8000) ? 1 : 0; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "CR", cr_bits, ocr.pr, cr.pr, 0); + TOP = temp; + } + break; + + case 0x0004: // cU2/ + { + CR ocr; + ocr.pr = cr.pr; + TOP = (TOP >> 1) & 0x7FFF; + if (0 != CY) + { + TOP = TOP | 0x8000; + } + CY = 0; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "CR", cr_bits, ocr.pr, cr.pr, 0); + } + break; + + case 0x0005: // c2/ + { + CR ocr; + ocr.pr = cr.pr; + t_value temp = (TOP >> 1) & 0x7FFF; + if (CY) + { + temp = temp | 0x8000; + } + CY = (TOP & 1) ? 1 : 0; + TOP = temp; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "CR", cr_bits, ocr.pr, cr.pr, 0); + } + break; + + case 0x0006: // U2/ + { + CR ocr; + ocr.pr = cr.pr; + TOP = (TOP >> 1) & 0x7FFF; + CY = 1; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "CR", cr_bits, ocr.pr, cr.pr, 0); + } + break; + + case 0x0007: // 2/ + { + CR ocr; + ocr.pr = cr.pr; + t_value temp = (TOP >> 1) & 0x7FFF; + if (TOP & 0x8000) + { + temp |= 0x8000; + } + CY = (TOP & 0x8000) ? 1 : 0; + TOP = temp; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "CR", cr_bits, ocr.pr, cr.pr, 0); + } + break; + + case 0x0008: // N2* + NEXT = (NEXT << 1) & 0xFFFE; + break; + + case 0x0009: // N2*c + NEXT = (NEXT << 1) & 0xFFFE; + if (CY) + { + NEXT |= 1; + } + sim_debug_bits_hdr(DBG_ASB_R, &cpu_dev, "CR", cr_bits, cr.pr, cr.pr, 0); + break; + + case 0x000A: // D2* + { + CR ocr; + ocr.pr = cr.pr; + CY = (TOP & 0x8000) ? 1 : 0; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "CR", cr_bits, ocr.pr, cr.pr, 1); + TOP = (TOP << 1) & 0xFFFE; + if (NEXT & 0x8000) + TOP |= 1; + NEXT = (NEXT << 1) & 0xFFFE; + } + break; + + case 0x000B: // D2*c + { + CR ocr; + ocr.pr = cr.pr; + t_value temp = (NEXT & 0x8000) ? 1 : 0; + t_value tempa = (TOP & 0x8000) ? 1 : 0; + NEXT = (NEXT << 1) & 0xFFFE; + if (CY) + { + NEXT |= 1; + } + TOP = (TOP << 1) & 0xFFFE; + if (temp) + TOP |= 1; + CY = tempa; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "CR", cr_bits, ocr.pr, cr.pr, 0); + } + break; + + case 0x000C: // cUD2/ + { + CR ocr; + ocr.pr = cr.pr; + t_value temp = (TOP & 0x0001) ? 1 : 0; + TOP = (TOP >> 1) & 0x7FFF; + if (CY) + TOP |= 0x8000; + NEXT = (NEXT >> 1) & 0x7FFF; + if (temp) + NEXT |= 0x8000; + CY = 1; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "CR", cr_bits, ocr.pr, cr.pr, 0); + } + break; + + case 0x000D: // cD2/ + { + CR ocr; + ocr.pr = cr.pr; + t_value temp = (TOP & 0x0001) ? 1 : 0; + t_value tempa = (NEXT & 0x0001) ? 1 : 0; + TOP = (TOP >> 1) & 0x7FFF; + if (CY) + TOP |= 0x8000; + NEXT = (NEXT >> 1) & 0x7FFF; + if (temp) + NEXT |= 0x8000; + CY = tempa; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "CR", cr_bits, ocr.pr, cr.pr, 0); + } + break; + + case 0x000E: // UD2/ + { + CR ocr; + ocr.pr = cr.pr; + t_value temp = (TOP & 0x0001) ? 1 : 0; + TOP = (TOP >> 1) & 0x7FFF; + NEXT = (NEXT >> 1) & 0x7FFF; + if (temp) + NEXT |= 0x8000; + CY = 1; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "CR", cr_bits, ocr.pr, cr.pr, 0); + } + break; + + case 0x000F: // D2/ + { + CR ocr; + ocr.pr = cr.pr; + t_value temp = (TOP & 0x8000) ? 1 : 0; + t_value tempa = (TOP & 0x0001) ? 1 : 0; + TOP = (TOP >> 1) & 0x7FFF; + TOP |= temp; + CY = temp; + NEXT = (NEXT >> 1) & 0x7FFF; + if (tempa) + { + NEXT |= 0x8000; + } + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "CR", cr_bits, ocr.pr, cr.pr, 0); + } + break; + + default: + return STOP_UNK; // Defensive, no test + } + + sim_debug(DBG_ASB_W, &cpu_dev, " TOP=0x%X NEXT=0x%X\n", TOP, NEXT); + return SCPE_OK; +} + +void do_alu() +{ + t_stat result = alu(TOP, NEXT, &NEXT); + if (SCPE_OK != result) + { + ABORT(result); + } + + ps_pop(); + invert(); + + if (SCPE_OK != (result = shift())) + { + ABORT(result); + } + + TEST_EXIT; + CLOCKS(1); + sim_debug(DBG_ASB_W, &cpu_dev, " TOP=0x%X NEXT=0x%X\n", TOP, NEXT); +} + +void do_asic_stream_mac() +{ + bad_insn(); + TEST_EXIT; + CLOCKS(1); +} + +void do_branch() +{ + sim_debug(DBG_ASB_R, &cpu_dev, "PC=0x%X IR=0x%X\n", asic_file[PC], IR); + asic_file[PC] = target_addr(IR, asic_file[PC]); + sim_debug(DBG_ASB_W, &cpu_dev, "PC=0x%X\n", asic_file[PC]); + CLOCKS(1); +} + +void do_drop() +{ + ps_pop(); + invert(); + t_stat result = shift(); + if (SCPE_OK != result) + ABORT(result); + TEST_EXIT; + CLOCKS(1); +} + +void do_dup() +{ + ps_push(TOP); + invert(); + t_stat result = shift(); + if (SCPE_OK != result) + ABORT(result); + TEST_EXIT; + CLOCKS(1); +} + +void do_ddup_alu() +{ + t_stat result = SCPE_LOST; + ps_push(NEXT); + if (SCPE_OK != (result = alu(NEXT, TOP, &TOP))) + { + ABORT(result); + } + invert(); + shift(); + TEST_EXIT; + CLOCKS(1); +} + +void do_ddup_store_with_alu() +{ + t_stat result = SCPE_LOST; + store(TOP, NEXT); + if (SCPE_OK != (result = alu(TOP, SHORT_LIT, &TOP))) + { + ABORT(result); + } + + TEST_EXIT; + CLOCKS(1); + second_cycle = TRUE; +} + +void do_ddup_store_with_alu_2() +{ + CLOCKS(1); +} + +void do_fetch_2() /* SWAP {inv} */ +{ + int temp = TOP; + TOP = NEXT; + NEXT = temp; + invert(); + CLOCKS(1); +} + +/** + ** @ swap + */ +void fetch_swap() +{ + RTX_WORD temp = NEXT; + fetch(TOP, &NEXT); + TOP = temp; + TEST_EXIT; + CLOCKS(1); + second_cycle = TRUE; +} + +void do_fetch_swap_alu_2() /* alu */ +{ + t_stat result = SCPE_LOST; + if (SCPE_OK != (result = alu(TOP, NEXT, &NEXT))) + { + ABORT(result); + } + + ps_pop(); + CLOCKS(1); +} + +void do_gfetch() +{ + CLOCKS(1); + t_value temp = 0; + t_stat result = gfetch(SHORT_LIT, &temp); + if (SCPE_OK != result) + ABORT(result); + ps_push(temp); + invert(); + TEST_EXIT; +} + +/** + * TODO: ??? what happens for short_lit = 16, short_lit = 17??? + */ +void do_gfetch_drop() +{ + t_stat result = SCPE_LOST; + t_value value; + // See EXECUTE.C:559 Does not write TOP + if (SCPE_OK != (result = gfetch(SHORT_LIT, &value))) + { + ABORT(result); + } + invert(); + TEST_EXIT; + CLOCKS(1); +} + +void do_fetch_over_alu_2() /* TUCK alu */ +{ + t_stat result = SCPE_LOST; + t_value temp = TOP; + if (SCPE_OK != (result = alu(TOP, NEXT, &TOP))) + { + ABORT(result); + } + NEXT = temp; + CLOCKS(1); +} + +void do_fetch_swap_2() +{ + invert(); + CLOCKS(1); +} + +void do_gfetch_swap_alu() +{ /* ??? what happens for short_lit = 16, short_lit = 17??? */ + t_value temp; + t_stat result = gfetch(SHORT_LIT, &temp); + if (SCPE_OK != result) + ABORT(result); + result = alu(TOP, temp, &TOP); + if (SCPE_OK != result) + ABORT(result); + TEST_EXIT; + CLOCKS(1); +} + +void do_fetch_with_alu() +{ + t_stat result = SCPE_LOST; + ps_push(TOP); + fetch(TOP, &NEXT); + if (SCPE_OK != (result = alu(TOP, SHORT_LIT, &TOP))) + { + ABORT(result); + } + + TEST_EXIT; + CLOCKS(1); + second_cycle = TRUE; +} + +void do_fetch_with_alu_2() +{ + CLOCKS(1); +} + +void do_gstore() +{ + if (SHORT_LIT != 7) + TEST_EXIT; /* important that TEST_EXIT come before gstore! */ + + t_stat result = gstore(SHORT_LIT, TOP); + if (SCPE_OK != result) + ABORT(result); + if (SHORT_LIT != 9) + ps_pop(); + invert(); + CLOCKS(1); +} + +void do_lit_2() /* swap {inv} */ +{ + t_value temp; + temp = NEXT; + NEXT = TOP; + TOP = temp; + invert(); + CLOCKS(1); +} + +void do_lit_swap_alu_2() +{ + t_stat result = alu(TOP, NEXT, &NEXT); + if (SCPE_OK != result) + { + ABORT(result); + } + + ps_pop(); + CLOCKS(1); +} + +void do_next() +{ + if (0 != asic_file[I]) + { /* loop */ + asic_file[PC] = target_addr(IR, asic_file[PC]); + asic_file[I] = (asic_file[I] - 1) & D16_UMAX; + sim_debug(DBG_ASB_W, &cpu_dev, "I=0x%X PC=0x%X\n", asic_file[I], asic_file[PC]); + } + else + { /* fall through */ + rs_pop(); + } + CLOCKS(1); +} + +void do_nip() +{ + NEXT = TOP; + ps_pop(); + invert(); + shift(); + TEST_EXIT; + CLOCKS(1); +} + +void do_over() +{ + ps_push(NEXT); + invert(); + t_stat result = shift(); + if (SCPE_OK != result) + ABORT(result); + TEST_EXIT; + CLOCKS(1); +} + +void do_shift() +{ + t_stat result; + invert(); + if (SCPE_OK != (result = shift())) + { + ABORT(result); + } + TEST_EXIT; + CLOCKS(1); +} + +void do_short_lit_swap_alu() +{ + t_stat result; + if (SCPE_OK != (result = alu(TOP, SHORT_LIT, &TOP))) + { + ABORT(result); + } + TEST_EXIT; + CLOCKS(1); + sim_debug(DBG_ASB_W, &cpu_dev, " TOP=0x%X NEXT=0x%X\n", TOP, NEXT); +} + +void do_store() +{ + store(TOP, NEXT); + ps_pop(); + TEST_EXIT; + CLOCKS(1); + second_cycle = TRUE; +} + +void do_store_2() +{ + ps_pop(); + invert(); + CLOCKS(1); +} + +void do_store_lit() +{ + store(TOP, NEXT); + ps_pop(); + TOP = SHORT_LIT; + TEST_EXIT; + CLOCKS(1); + second_cycle = TRUE; +} + +void do_store_lit_2() +{ + CLOCKS(1); +} + +void do_swap() +{ + t_value temp = TOP; + t_stat result; + TOP = NEXT; + NEXT = temp; + invert(); + + if (SCPE_OK != (result = shift())) + { + ABORT(result); + } + + TEST_EXIT; + CLOCKS(1); +} + +void do_tuck_alu() +{ + t_value temp = NEXT; + NEXT = TOP; + t_stat result = alu(TOP, temp, &TOP); + if (SCPE_OK != result) + ABORT(result); + result = shift(); + if (SCPE_OK != result) + ABORT(result); + TEST_EXIT; + CLOCKS(1); +} + +void do_tuck_store_with_alu() +{ + store(TOP, NEXT); + NEXT = TOP; + ps_pop(); + t_stat result = alu(TOP, SHORT_LIT, &TOP); + if (SCPE_OK != result) + ABORT(result); + TEST_EXIT; + CLOCKS(1); + second_cycle = TRUE; +} + +void do_tuck_store_with_alu_2() +{ + CLOCKS(1); +} + +/** + * D swap + */ +void D_swap() +{ + ps_push(TOP); + _long_fetch(cpr.fields.pr, asic_file[PC], &NEXT); + INC_PC; + TEST_EXIT; + CLOCKS(1); + second_cycle = TRUE; +} + +void do_short_lit() +{ + ps_push(SHORT_LIT); + invert(); + TEST_EXIT; + CLOCKS(1); +} + +void do_uslash_one_tick() +{ + /* really sleazy definition to make things work for now ???? */ + /* undoes the preceeding d2* */ + NEXT = (NEXT >> 1) & 0x7FFF; + if (TOP & 1) + NEXT = NEXT | 0x8000; + TOP = (TOP >> 1) & 0x7FFF; + if (CY) + TOP = TOP | 0x8000; +} + +void do_uslash_tick() +{ + /* really sleazy definition to make things work for now ???? */ + /* do nothing -- save the division up for the end! */ + TEST_EXIT; + CLOCKS(1); +} + +void do_uslash_tick_tick() +{ + /* really sleazy definition to make things work for now ???? */ + /* do all the division at once */ + t_uint64 dividend; + RTX_WORD divisor, quotient, remainder; + dividend = ((t_uint64)TOP << 16) & 0xFFFF0000; + dividend = dividend | (t_uint64)(NEXT & 0xFFFF); + divisor = asic_file[MD]; + quotient = dividend / divisor; + dividend = dividend - ((t_uint64)quotient * (t_uint64)divisor); + remainder = dividend; + TOP = remainder; + NEXT = quotient; + TEST_EXIT; + CLOCKS(1); +} + +/** + * ??? the below definitions might speed things up, from Mitch Bradley + * ??? the below definitions might speed things up, from Mitch Bradley + * #define CARRY(a,b) ((unsigned)a >= (unsigned)(-b)) + * #define BORROW(a,b) ((unsigned)a < (unsigned)b) + * 16-bit versions that promote to longs + */ +RTX_WORD CARRY(RTX_WORD a, RTX_WORD b, RTX_WORD c) +{ + t_value sum, temp; /* sum=a+b+c */ + /* the additions below use high 16 bits of the long to catch carries */ + temp = a; + sum = temp & 0xFFFF; + temp = b; + sum = sum + (temp & 0xFFFF); + temp = c; + sum = sum + (temp & 0xFFFF); + if (sum & 0x10000) + return (1); + return (0); +} + +/** + * All ALU operations are performed between the contents of the TOP Register + * and another operand which is determined by the instruction. + * The results of the operation are loaded into TOP. The ALU function to be performed + * is encoded as a field in the instruction and is shown in the opcode formats + * as either "cccc" or "aaa". + * + * See Table 7.3, Prgmrs Ref Man + */ +t_stat alu(t_value opa, t_value opb, t_value *result) +{ + switch (IR & 0x0F00) + { + case 0x0200: // T AND Y + *result = (opa & opb) & D16_MASK; + return SCPE_OK; + case 0x0300: // T NOR Y + *result = (~(opa | opb)) & D16_MASK; + return SCPE_OK; + case 0x0400: // T - Y + CY = BORROW(opa, opb, 1); + *result = (opa - opb) & D16_MASK; + return SCPE_OK; + case 0x0500: // T - Y with borrow + CY = BORROW(opa, opb, CY); + *result = (opa + ~opb + CY) & D16_MASK; + return SCPE_OK; + case 0x0600: // T OR Y + *result = (opa | opb) & D16_MASK; + return SCPE_OK; + case 0x0700: // T NAND Y + *result = (~(opa & opb)) & D16_MASK; + return SCPE_OK; + case 0x0800: // T + Y + CY = CARRY(opa, opb, 0); + *result = (opa + opb) & D16_MASK; + return SCPE_OK; + case 0x0900: // T + Y with carry + CY = CARRY(opa, opb, CY); + *result = (opa + opb + CY) & D16_MASK; + return SCPE_OK; + case 0x0A00: // T XOR Y + *result = (opa ^ opb) & D16_MASK; + return SCPE_OK; + case 0x0B00: // T XNOR Y + *result = (~(opa ^ opb)) & D16_MASK; + return SCPE_OK; + case 0x0C00: // Y - T + CY = BORROW(opb, opa, 1); + *result = (opb - opa) & D16_MASK; + return SCPE_OK; + case 0x0D00: // Y - T with borrow + CY = BORROW(opb, opa, CY); + *result = (opb + ~opa + CY) & D16_MASK; + return SCPE_OK; + } + return STOP_UNK; // Defensive, no test +} + +/* Compute branch target address + * Input: instruction = 16-bit RTX instruction + * address = 16-bit RTX address + * Output: 16-bit RTX branch target address + */ +t_addr target_addr(RTX_WORD instruction, t_addr address) +{ + /** + * The RTX Branch Instruction treats each Code Memory page as 64 "blocks" of 512 words each. + * Bits 15-10 of the Program Counter determine the block number; + * Bits 9-0 determine the word offset within the block. + */ + t_addr next_addr = ((address + 1) & 0xFC00) | ((instruction << 1) & 0x03FE); + sim_debug(DBG_CPU, &cpu_dev, "NEXT_ADDR=0x%X BK=%d\n", next_addr, instruction & 0x0600); + + // See TABLE 7.2: BLOCK BRANCHING ASSIGNMENTS, Pgmrs Ref Man + switch (instruction & 0x0600) + { + case 0x0000: /* same memory block */ + return (next_addr); + case 0x0200: /* next memory block */ + return (next_addr + 0x0400) & D16_UMAX; + case 0x0400: /* memory block 0 */ + return (next_addr & 0x03FE); + case 0x0600: /* previous memory block */ + return (next_addr - 0x0400) & D16_UMAX; + } + sim_debug(DBG_CPU, &cpu_dev, "case statement error in target_addr, IR=0x%X, addr=0x%X", instruction, address); + return 0; +} +/* dispatch table for 1st clock cycle */ +void (*dispatch_vector_1[NUMBER_OF_ROUTINES])() = + { + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, /* 16 */ + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, /* 32 */ + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, /* 48 */ + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, /* 64 */ + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, /* 80 */ + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, /* 96 */ + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, /* 112 */ + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn /* 128 */ +}; + +/* dispatch table for 2nd clock cycle of 2-cycle instructions */ +void (*dispatch_vector_2[NUMBER_OF_ROUTINES])() = + { + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, /* 16 */ + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, /* 32 */ + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, /* 48 */ + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, /* 64 */ + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, /* 80 */ + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, /* 96 */ + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, /* 112 */ + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn, + bad_insn, bad_insn, bad_insn, bad_insn /* 128 */ +}; + +t_stat execute(t_value instruction) +{ + machine_op opcode = (machine_op)NIL; + t_stat status; + if (SCPE_OK == (status = decode(instruction, &opcode))) + { + print_instruction(instruction, cpr.pr, asic_file[PC]); + if (!STREAM && second_cycle) + { + dispatch_vector_2[opcode](); + second_cycle = 0; + } + else + { + dispatch_vector_1[opcode](); + } + } + return status; +} + +void dump_header(char *dest, t_value offset) +{ + t_value temp = 0; + t_value _sim_is_running = sim_is_running; + sim_is_running = 0; + byte_fetch(((IR << 1) & D16_MASK) - offset, &temp); + sim_is_running = _sim_is_running; + if (temp > 32 && temp < 128) + { + *dest = temp; + } +} + +/** + * print a disassembled instruction + */ +void print_instruction(t_value instruction, t_value page, t_addr address) +{ + +#define PREFIX \ + ((second_cycle && !STREAM) ? "2nd " : "") + + machine_op opr = (machine_op)NIL; + if (SCPE_OK != decode(instruction, &opr)) + { + return; + } + switch (opr) + { + case OP_0BRANCH: + sim_debug(DBG_CPU, &cpu_dev, "0BRANCH TOP=0x%X 0x%X\n", TOP, target_addr(instruction, address)); + break; + + case OP_ALU: + sim_debug(DBG_CPU, &cpu_dev, "%s%s\n", ALU, SHIFT); + break; + + case OP_ASIC_STREAM_MAC: + sim_debug(DBG_CPU, &cpu_dev, "Asic Stream Mac\n"); + break; + + case OP_BRANCH: + sim_debug(DBG_CPU, &cpu_dev, "BRANCH %d:0x%X\n", page, target_addr(instruction, address)); + break; + + case OP_BS_ONE_TICK: + sim_debug(DBG_CPU, &cpu_dev, "BS1'\n"); + break; + + case OP_BS_TICK: + sim_debug(DBG_CPU, &cpu_dev, "BS'\n"); + break; + + case OP_BUSLASH_TICK: + sim_debug(DBG_CPU, &cpu_dev, "BU/'\n"); + break; + + case OP_BUSTAR_TICK: + sim_debug(DBG_CPU, &cpu_dev, "BU*'\n"); + break; + + case OP_BUSTAR_TICK_TICK: + sim_debug(DBG_CPU, &cpu_dev, "BU*''\n"); + break; + + case OP_CALL: + { + char buffer[64]; + memset(buffer, '\0', sizeof(buffer)); + sprintf(buffer, "CALL %d:0x%X ", page, ((instruction << 1) & D16_MASK)); + t_value i = strlen(buffer); + for (int j = 9; j > 0; j--, i++) + { + dump_header(&buffer[i], j); + } + sim_debug(DBG_CPU, &cpu_dev, "%s\n", buffer); + } + break; + + case OP_DDUP_STORE: + sim_debug(DBG_CPU, &cpu_dev, "%sDDUP %s!\n", PREFIX, MEM); + break; + + case OP_DDUP_STORE_WITH_ALU: + sim_debug(DBG_CPU, &cpu_dev, "%sDDUP %s! 0x%X %s\n", PREFIX, MEM, SHORT_LIT, SWAP_ALU3); + break; + + case OP_DROP: + sim_debug(DBG_CPU, &cpu_dev, "DROP %s%s\n", INVERT, SHIFT); + break; + + case OP_DROP_LIT: + { + t_value value; + _long_fetch(page, address, &value); + sim_debug(DBG_CPU, &cpu_dev, "%sDROP LIT %d %s\n", PREFIX, value, INVERT); + } + break; + + case OP_DDUP_ALU: + sim_debug(DBG_CPU, &cpu_dev, "DDUP %s%s\n", ALU, SHIFT); + break; + + case OP_DUP: + sim_debug(DBG_CPU, &cpu_dev, "DUP %s%s\n", INVERT, SHIFT); + break; + + case OP_DUP_FETCH_SWAP: + sim_debug(DBG_CPU, &cpu_dev, "%sDUP %s@ SWAP\n", PREFIX, MEM); + break; + + case OP_DUP_USTORE: + sim_debug(DBG_CPU, &cpu_dev, "%sDUP %X U! %s\n", PREFIX, SHORT_LIT, INVERT); + break; + + case OP_GFETCH_DROP: + sim_debug(DBG_CPU, &cpu_dev, "0x%X G@ DROP %s ", SHORT_LIT, INVERT); + if (SHORT_LIT == 1) + sim_debug(DBG_CPU, &cpu_dev, "(R> DROP)\n"); + else + sim_debug(DBG_CPU, &cpu_dev, "\n"); + break; + + case OP_FETCH: + sim_debug(DBG_CPU, &cpu_dev, "%s%s@ %s\n", PREFIX, MEM, INVERT); + break; + + case OP_FETCH_LIT: + sim_debug(DBG_CPU, &cpu_dev, "%s%s@ 0x%X\n", PREFIX, MEM, SHORT_LIT); + break; + + case OP_FETCH_SWAP: + sim_debug(DBG_CPU, &cpu_dev, "%s%s@ SWAP %s\n", PREFIX, MEM, INVERT); + break; + + case OP_FETCH_OVER_ALU: + sim_debug(DBG_CPU, &cpu_dev, "%s%s@ OVER %s\n", PREFIX, MEM, ALU); + break; + + case OP_FETCH_SWAP_ALU: + sim_debug(DBG_CPU, &cpu_dev, "%s%s@ %s\n", PREFIX, MEM, SWAP_ALU); + break; + + case OP_FETCH_WITH_ALU: + sim_debug(DBG_CPU, &cpu_dev, "%s0x%X %s@_%s\n", PREFIX, SHORT_LIT, MEM, ALU3); + break; + + case OP_GFETCH: + sim_debug(DBG_CPU, &cpu_dev, "0x%X G@ %s ", SHORT_LIT, INVERT); + if (SHORT_LIT == 1) + { + sim_debug(DBG_CPU, &cpu_dev, "(R>)\n"); + } + else + { + sim_debug(DBG_CPU, &cpu_dev, "\n"); + }; + break; + + case OP_QDUP_0BRANCH: + sim_debug(DBG_CPU, &cpu_dev, "?DUP 0BRANCH %d:0x%X\n", page, target_addr(instruction, address)); + break; + + case OP_GFETCH_SWAP_ALU: + sim_debug(DBG_CPU, &cpu_dev, "0x%X G@ %s\n", SHORT_LIT, SWAP_ALU); + break; + + case OP_GSTORE: + sim_debug(DBG_CPU, &cpu_dev, "0x%X G! %s ", SHORT_LIT, INVERT); + if (SHORT_LIT == 0) + { + sim_debug(DBG_CPU, &cpu_dev, "(R> DROP >R)\n"); + } + else if (SHORT_LIT == 1) + { + sim_debug(DBG_CPU, &cpu_dev, "(>R)\n"); + } + else if (SHORT_LIT == 7 && (instruction & 0x0020)) + { + sim_debug(DBG_CPU, &cpu_dev, "(>R;)\n"); + } + else + { + sim_debug(DBG_CPU, &cpu_dev, "\n"); + } + break; + + case OP_LIT: + { + if (STREAM | !second_cycle) + { + t_value value; + t_bool _sim_is_running = sim_is_running; + sim_is_running = 0; // turn off debug for a moment + _long_fetch(page, address, &value); + sim_is_running = _sim_is_running; + sim_debug(DBG_CPU, &cpu_dev, "LIT 0x%X %s\n", value, INVERT); + } + else + { + sim_debug(DBG_CPU, &cpu_dev, "%sLIT\n", PREFIX); + } + } + break; + + case OP_LIT_OVER_ALU: + { + t_value value; + _long_fetch(page, address, &value); + sim_debug(DBG_CPU, &cpu_dev, "%sLIT 0x%X OVER %s\n", PREFIX, value, ALU); + } + break; + + case OP_LIT_SWAP: + { + t_value value; + _long_fetch(page, address, &value); + sim_debug(DBG_CPU, &cpu_dev, "%sLIT %d SWAP %s\n", PREFIX, value, INVERT); + } + break; + + case OP_LIT_SWAP_ALU: + { + t_value value; + t_bool _sim_is_running = sim_is_running; + sim_is_running = 0; // turn off debug for a moment + _long_fetch(page, address, &value); + sim_is_running = _sim_is_running; + sim_debug(DBG_CPU, &cpu_dev, "%sLIT %d %s\n", PREFIX, value, SWAP_ALU); + } + break; + + case OP_NEXT: + sim_debug(DBG_CPU, &cpu_dev, "NEXT %d:0x%X ", page, target_addr(instruction, address)); + break; + + case OP_NIP: + sim_debug(DBG_CPU, &cpu_dev, "NIP %s%s\n", INVERT, SHIFT); + break; + + case OP_NIP_DUP_FETCH_SWAP: + sim_debug(DBG_CPU, &cpu_dev, "%sNIP DUP %s@ SWAP\n", PREFIX, MEM); + break; + + case OP_NIP_FETCH_LIT: + sim_debug(DBG_CPU, &cpu_dev, "%sNIP %s@ 0x%X\n", PREFIX, MEM, SHORT_LIT); + break; + + case OP_NIP_FETCH_WITH_ALU: + sim_debug(DBG_CPU, &cpu_dev, "%sNIP 0x%X %s@_%s\n", PREFIX, SHORT_LIT, MEM, ALU3); + break; + + case OP_OVER: + sim_debug(DBG_CPU, &cpu_dev, "OVER %s%s\n", INVERT, SHIFT); + break; + + case OP_SHIFT: + if ((instruction & 0x0FFF) == 0) + { + sim_debug(DBG_CPU, &cpu_dev, "NOP\n"); + } + else + { + sim_debug(DBG_CPU, &cpu_dev, "%s%s\n", INVERT, SHIFT); + } + break; + + case OP_SHORT_LIT: + sim_debug(DBG_CPU, &cpu_dev, "0x%X %s\n", SHORT_LIT, INVERT); + break; + + case OP_SHORT_LIT_SWAP_ALU: + sim_debug(DBG_CPU, &cpu_dev, "0x%X %s\n", SHORT_LIT, SWAP_ALU); + break; + + case OP_STORE: + sim_debug(DBG_CPU, &cpu_dev, "%s%s! %s\n", PREFIX, MEM, INVERT); + break; + + case OP_STORE_LIT: + sim_debug(DBG_CPU, &cpu_dev, "%s%s! 0x%X\n", PREFIX, MEM, SHORT_LIT); + break; + + case OP_SWAP: + sim_debug(DBG_CPU, &cpu_dev, "SWAP %s%s\n", INVERT, SHIFT); + break; + + case OP_TUCK_ALU: + sim_debug(DBG_CPU, &cpu_dev, "TUCK %s%s\n", ALU, SHIFT); + break; + + case OP_TUCK_STORE: + sim_debug(DBG_CPU, &cpu_dev, "%sTUCK %s!\n", PREFIX, MEM); + break; + + case OP_TUCK_STORE_WITH_ALU: + sim_debug(DBG_CPU, &cpu_dev, "%sTUCK %s! 0x%X %s\n", PREFIX, MEM, SHORT_LIT, ALU3); + break; + + case OP_UFETCH: + sim_debug(DBG_CPU, &cpu_dev, "%s0x%X U@ %s\n", PREFIX, SHORT_LIT, INVERT); + break; + + case OP_UFETCH_OVER_ALU: + sim_debug(DBG_CPU, &cpu_dev, "%s0x%X U@ OVER %s\n", PREFIX, SHORT_LIT, ALU); + break; + + case OP_UFETCH_SWAP: + sim_debug(DBG_CPU, &cpu_dev, "%s0x%X U@ SWAP %s\n", PREFIX, SHORT_LIT, INVERT); + break; + + case OP_UFETCH_SWAP_ALU: + sim_debug(DBG_CPU, &cpu_dev, "%s0x%X U@ %s", PREFIX, SHORT_LIT, SWAP_ALU); + break; + + case OP_UNDER_STORE: + sim_debug(DBG_CPU, &cpu_dev, "%sUNDER %s! %s\n", PREFIX, MEM, INVERT); + break; + + case OP_UNDER_STORE_LIT: + sim_debug(DBG_CPU, &cpu_dev, "%sUNDER %s! 0x%X\n", PREFIX, MEM, SHORT_LIT); + break; + + case OP_USLASH_ONE_TICK: + sim_debug(DBG_CPU, &cpu_dev, "U/1'\n"); + break; + + case OP_USLASH_TICK: + sim_debug(DBG_CPU, &cpu_dev, "U/'\n"); + break; + + case OP_USLASH_TICK_TICK: + sim_debug(DBG_CPU, &cpu_dev, "U/''\n"); + break; + + default: + bad_insn(); + } +} + +void init_dispatch_vectors() +{ +#if DUMMY_LAST >= NUMBER_OF_ROUTINES +#error : Increase NUMBER_OF_ROUTINES array initialization !! +#endif + dispatch_vector_1[OP_CALL] = do_call; + dispatch_vector_1[OP_0BRANCH] = do_0branch; + dispatch_vector_1[OP_ALU] = do_alu; +#if 0 + dispatch_vector_1[OP_ASIC_STREAM_MAC] = do_asic_stream_mac; +#endif + dispatch_vector_1[OP_BRANCH] = do_branch; +#if 0 + dispatch_vector_1[OP_BS_ONE_TICK] = do_bs_one_tick; + dispatch_vector_1[OP_BS_TICK] = do_bs_tick; + dispatch_vector_1[OP_BUSLASH_TICK] = do_buslash_tick; + dispatch_vector_1[OP_BUSTAR_TICK] = do_bustar_tick; + dispatch_vector_1[OP_BUSTAR_TICK_TICK] = do_bustar_tick_tick; + dispatch_vector_1[OP_CLEAR_ACC] = do_clear_acc; + dispatch_vector_1[OP_CLEAR_SOFTINT] = do_clear_softint; + dispatch_vector_1[OP_C_TICK] = do_c_tick; +#endif + dispatch_vector_1[OP_DDUP_ALU] = do_ddup_alu; +#if 0 + dispatch_vector_1[OP_DDUP_STORE] = do_ddup_store; +#endif + dispatch_vector_1[OP_DDUP_STORE_WITH_ALU] = do_ddup_store_with_alu; +#if 0 + dispatch_vector_1[OP_DEC_RX] = do_dec_rx; +#endif + dispatch_vector_1[OP_DROP] = do_drop; +#if 0 + dispatch_vector_1[OP_DROP_DUP] = do_drop_dup; + dispatch_vector_1[OP_DROP_LIT] = do_drop_lit; + dispatch_vector_1[OP_DROP_SHORT_LIT] = do_drop_short_lit; + dispatch_vector_1[OP_DSLL] = do_dsll; + dispatch_vector_1[OP_DSRA] = do_dsra; + dispatch_vector_1[OP_DSRL] = do_dsrl; +#endif + dispatch_vector_1[OP_DUP] = do_dup; +#if 0 + dispatch_vector_1[OP_DUP_FETCH_SWAP] = do_dup_fetch_swap; + dispatch_vector_1[OP_DUP_GSTORE] = do_dup_gstore; + dispatch_vector_1[OP_DUP_USTORE] = do_dup_ustore; +#endif + dispatch_vector_1[OP_FETCH] = do_fetch; +#if 0 + dispatch_vector_1[OP_FETCH_LIT] = do_fetch_lit; +#endif + dispatch_vector_1[OP_FETCH_OVER_ALU] = do_fetch_over_alu; +#if 0 + dispatch_vector_1[OP_FETCH_SWAP] = do_fetch_swap; +#endif + dispatch_vector_1[OP_FETCH_SWAP_ALU] = do_fetch_swap_alu; + dispatch_vector_1[OP_FETCH_WITH_ALU] = do_fetch_with_alu; + dispatch_vector_1[OP_GFETCH] = do_gfetch; + dispatch_vector_1[OP_GFETCH_DROP] = do_gfetch_drop; +#if 0 + dispatch_vector_1[OP_GFETCH_OVER_ALU] = do_gfetch_over_alu; +#endif + dispatch_vector_1[OP_GFETCH_SWAP_ALU] = do_gfetch_swap_alu; + dispatch_vector_1[OP_GSTORE] = do_gstore; +#if 0 + dispatch_vector_1[OP_INC_RX] = do_inc_rx; +#endif + dispatch_vector_1[OP_LIT] = do_lit; +#if 0 + dispatch_vector_1[OP_LIT_OVER_ALU] = do_lit_over_alu; + dispatch_vector_1[OP_LIT_SWAP] = do_lit_swap; +#endif + dispatch_vector_1[OP_LIT_SWAP_ALU] = do_lit_swap_alu; +#if 0 + dispatch_vector_1[OP_MAC] = do_mac; + dispatch_vector_1[OP_MIXED_MAC] = do_mixed_mac; + dispatch_vector_1[OP_MIXED_MULT] = do_mixed_mult; + dispatch_vector_1[OP_MULT] = do_mult; + dispatch_vector_1[OP_MULT_SUB] = do_mult_sub; +#endif + dispatch_vector_1[OP_NEXT] = do_next; + dispatch_vector_1[OP_NIP] = do_nip; +#if 0 + dispatch_vector_1[OP_NIP_DUP] = do_nip_dup; + dispatch_vector_1[OP_NIP_DUP_FETCH_SWAP] = do_nip_dup_fetch_swap; + dispatch_vector_1[OP_NIP_FETCH_LIT] = do_nip_fetch_lit; + dispatch_vector_1[OP_NIP_FETCH_WITH_ALU] = do_nip_fetch_with_alu; + dispatch_vector_1[OP_NORMALIZE] = do_normalize; +#endif + dispatch_vector_1[OP_OVER] = do_over; + dispatch_vector_1[OP_QDUP_0BRANCH] = do_qdup_0branch; +#if 0 + dispatch_vector_1[OP_RDR] = do_rdr; + dispatch_vector_1[OP_RESERVED] = do_reserved; + dispatch_vector_1[OP_RESERVED_STEP_MATH] = do_reserved_step_math; + dispatch_vector_1[OP_RTR] = do_rtr; + dispatch_vector_1[OP_R_TICK] = do_r_tick; + dispatch_vector_1[OP_SELECT_CPR] = do_select_cpr; + dispatch_vector_1[OP_SELECT_DPR] = do_select_dpr; + dispatch_vector_1[OP_SET_SOFTINT] = do_set_softint; +#endif + dispatch_vector_1[OP_SHIFT] = do_shift; +#if 0 + dispatch_vector_1[OP_SHIFT_MAC_RIGHT] = do_shift_mac_right; +#endif + dispatch_vector_1[OP_SHORT_LIT] = do_short_lit; +#if 0 + dispatch_vector_1[OP_SHORT_LIT_OVER_ALU] = do_short_lit_over_alu; +#endif + dispatch_vector_1[OP_SHORT_LIT_SWAP_ALU] = do_short_lit_swap_alu; +#if 0 + dispatch_vector_1[OP_STAR_TICK] = do_star_tick; + dispatch_vector_1[OP_STAR_TICK_TICK] = do_star_tick_tick; +#endif + dispatch_vector_1[OP_STORE] = do_store; + dispatch_vector_1[OP_STORE_LIT] = do_store_lit; +#if 0 + dispatch_vector_1[OP_STREAM_MAC] = do_stream_mac; +#endif + dispatch_vector_1[OP_SWAP] = do_swap; + dispatch_vector_1[OP_SWAP] = do_swap; +#if 0 + dispatch_vector_1[OP_S_ONE_TICK] = do_s_one_tick; + dispatch_vector_1[OP_S_TICK] = do_s_tick; + dispatch_vector_1[OP_S_TICK_TICK] = do_s_tick_tick; +#endif + dispatch_vector_1[OP_TUCK_ALU] = do_tuck_alu; +#if 0 + dispatch_vector_1[OP_TUCK_STORE] = do_tuck_store; +#endif + dispatch_vector_1[OP_TUCK_STORE_WITH_ALU] = do_tuck_store_with_alu; +#if 0 + dispatch_vector_1[OP_TWO_STAR_TICK] = do_two_star_tick; + dispatch_vector_1[OP_UFETCH] = do_ufetch; + dispatch_vector_1[OP_UFETCH_OVER_ALU] = do_ufetch_over_alu; + dispatch_vector_1[OP_UFETCH_SWAP] = do_ufetch_swap; + dispatch_vector_1[OP_UFETCH_SWAP_ALU] = do_ufetch_swap_alu; + dispatch_vector_1[OP_UMAC] = do_umac; + dispatch_vector_1[OP_UMULT] = do_umult; + dispatch_vector_1[OP_UNDER_ALU] = do_under_alu; + dispatch_vector_1[OP_UNDER_STORE] = do_under_store; + dispatch_vector_1[OP_UNDER_STORE_LIT] = do_under_store_lit; +#endif + dispatch_vector_1[OP_USLASH_ONE_TICK] = do_uslash_one_tick; +#if 0 + dispatch_vector_1[OP_USLASH_ONE_TICK_TICK] = do_uslash_one_tick_tick; +#endif + dispatch_vector_1[OP_USLASH_TICK] = do_uslash_tick; + dispatch_vector_1[OP_USLASH_TICK_TICK] = do_uslash_tick_tick; +#if 0 + dispatch_vector_1[OP_USTAR_TICK] = do_ustar_tick; + dispatch_vector_1[OP_USTAR_TICK_TICK] = do_ustar_tick_tick; + dispatch_vector_1[OP_USTORE] = do_ustore; + dispatch_vector_1[OP_ZERO_EQUAL] = do_zero_equal; +#endif + +/* ---------------- second clock routines */ +#if 0 + dispatch_vector_2[OP_DDUP_STORE] = do_ddup_store_2; +#endif + dispatch_vector_2[OP_DDUP_STORE_WITH_ALU] = do_ddup_store_with_alu_2; +#if 0 + dispatch_vector_2[OP_DROP_LIT] = do_drop_lit_2; + dispatch_vector_2[OP_DUP_FETCH_SWAP] = do_dup_fetch_swap_2; + dispatch_vector_2[OP_DUP_USTORE] = do_dup_ustore_2; +#endif + dispatch_vector_2[OP_FETCH] = do_fetch_2; +#if 0 + dispatch_vector_2[OP_FETCH_LIT] = do_fetch_lit_2; +#endif + dispatch_vector_2[OP_FETCH_OVER_ALU] = do_fetch_over_alu_2; + dispatch_vector_2[OP_FETCH_SWAP] = do_fetch_swap_2; + dispatch_vector_2[OP_FETCH_SWAP_ALU] = do_fetch_swap_alu_2; + dispatch_vector_2[OP_FETCH_WITH_ALU] = do_fetch_with_alu_2; + dispatch_vector_2[OP_LIT] = do_lit_2; +#if 0 + dispatch_vector_2[OP_LIT_OVER_ALU] = do_lit_over_alu_2; + dispatch_vector_2[OP_LIT_SWAP] = do_lit_swap_2; +#endif + dispatch_vector_2[OP_LIT_SWAP_ALU] = do_lit_swap_alu_2; +#if 0 + dispatch_vector_2[OP_NIP_DUP_FETCH_SWAP] = do_nip_dup_fetch_swap_2; + dispatch_vector_2[OP_NIP_FETCH_LIT] = do_nip_fetch_lit_2; + dispatch_vector_2[OP_NIP_FETCH_WITH_ALU] = do_nip_fetch_with_alu_2; +#endif + dispatch_vector_2[OP_STORE] = do_store_2; + dispatch_vector_2[OP_STORE_LIT] = do_store_lit_2; +#if 0 + dispatch_vector_2[OP_TUCK_STORE] = do_tuck_store_2; +#endif + dispatch_vector_2[OP_TUCK_STORE_WITH_ALU] = do_tuck_store_with_alu_2; +#if 0 + dispatch_vector_2[OP_UFETCH] = do_ufetch_2; + dispatch_vector_2[OP_UFETCH_OVER_ALU] = do_ufetch_over_alu_2; + dispatch_vector_2[OP_UFETCH_SWAP] = do_ufetch_swap_2; + dispatch_vector_2[OP_UFETCH_SWAP_ALU] = do_ufetch_swap_alu_2; + dispatch_vector_2[OP_UNDER_STORE] = do_under_store_2; + dispatch_vector_2[OP_UNDER_STORE_LIT] = do_under_store_lit_2; + dispatch_vector_2[OP_USTORE] = do_ustore_2; +#endif +} diff --git a/RTX2001A/rtx2001a_execute.h b/RTX2001A/rtx2001a_execute.h new file mode 100644 index 000000000..d46aa6fcc --- /dev/null +++ b/RTX2001A/rtx2001a_execute.h @@ -0,0 +1,116 @@ +/* rtx2001a_execute.h: RTX2001A simulator definitions + + Copyright (c) 2022, Systasis Computer Systems, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + SYSTASIS COMPUTER SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Systasis Computer Systems shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Systasis Computer Systems. + + 10-Oct-22 SYS New simulator. + + See RTX2000/EXECUTE.H + + Instruction execution +*/ + +#ifndef RTX2001A_EXECUTE_H_ +#define RTX2001A_EXECUTE_H_ 0 + +#include "rtx2001a_defs.h" +#include "rtx2001a_decode.h" + +/** + * Note: you *MUST* change the initialization statement for these arrays + * if NUMBER_OF_ROUTINES is changed !!!!! + */ +#define NUMBER_OF_ROUTINES 128 +extern void (*dispatch_vector_1[NUMBER_OF_ROUTINES])(); +extern void (*dispatch_vector_2[NUMBER_OF_ROUTINES])(); + +extern void init_dispatch_vectors(); // Function dispatch vector + +extern t_stat execute(t_value instruction); +extern void print_instruction(t_value instruction, t_value page, t_addr address); +extern t_stat alu(t_value opa, t_value opb, t_value *result); +extern t_stat shift(void); + +extern void do_0branch(); +extern void do_call(); +extern void do_exit(); +#define do_fetch fetch_swap +extern void do_fetch_2(); +#define do_fetch_over_alu fetch_swap +extern void do_fetch_over_alu_2(); +extern void do_fetch_swap_2(); +#define do_fetch_swap_alu fetch_swap +extern void do_fetch_swap_alu_2(); +#define do_lit D_swap +#define do_lit_swap_alu D_swap +extern void do_list_2(); +extern void do_qdup_0branch(); +extern void do_store_lit_2(); +extern void bad_insn(void); +extern void D_swap(); + +extern RTX_WORD clocks; +extern t_value STREAM; +extern t_value stream_mode; +extern t_value second_cycle; + +#define CLOCKS(arg) clocks += arg + +#define EXIT (IR & 0x0020) + +#define TEST_EXIT \ + { \ + if (EXIT) \ + do_exit(); \ + } + +// #define CARRY(a, b) (((uint16_t)a >= (uint16_t)(-b)) ? 1 : 0) +// #define BORROW(a, b) (((uint16_t)a < (uint16_t)b) ? 1 : 0) +#define BORROW(a, b, c) CARRY(a, ~b, c) + +#define invert() \ + { \ + if (IR & 0x0100) \ + TOP = (~TOP) & D16_UMAX; \ + } + +/* MACROS FOR SIMPLIFIED PRINTING */ + +/* print out a shift operation */ +#define SHIFT (shift_names[instruction & 0xF]) + +/* print out the invert operation */ +#define INVERT (alu_names[(instruction >> 8) & 0x1]) + +/* print out an alu operation */ +#define ALU (alu_names[(instruction >> 8) & 0xF]) +#define SWAP_ALU (swap_alu_names[(instruction >> 8) & 0xF]) + +/* print out a 3-bit alu operation */ +#define ALU3 (alu_names[(instruction >> 8) & 0xE]) +#define SWAP_ALU3 (swap_alu_names[(instruction >> 8) & 0xE]) + +/* extract the bit that determines word vs. byte */ +#define MEM (memory_names[(instruction >> 12) & 0x1]) + +#endif diff --git a/RTX2001A/rtx2001a_mb.c b/RTX2001A/rtx2001a_mb.c new file mode 100644 index 000000000..352afe257 --- /dev/null +++ b/RTX2001A/rtx2001a_mb.c @@ -0,0 +1,225 @@ +/* rtx2001a_mb.c: RTX2001A CPU simulator + + Copyright (c) 2022, Systasis Computer Systems, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + SYSTASIS COMPUTER SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Systasis Computer Systems shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Systasis Computer Systems. + + 6-Sep-22 SYS From RTX_2000 simulator by Phil Koopman Jr. + + Memory Bus support +*/ +#include "rtx2001a_defs.h" +#include "rtx2001a_debug.h" +#include "rtx2001a_registers.h" +#include "rtx2001a_mb.h" + +RTX_WORD ram[RAM_SIZE] = {0}; + +void _read(t_addr addr, t_value *value) +{ + *value = ram[addr] & D16_MASK; + if (sim_is_running) + { + sim_debug(DBG_MEB_R, &cpu_dev, "0x%X 0x%X\n", addr, *value); + if ((sim_brk_summ & DBG_MEB_R) && sim_brk_test(addr, DBG_MEB_R)) + { + sim_messagef(STOP_IBKPT, "%s", sim_brk_message()); + TRAP(STOP_IBKPT); + } + } +} + +void _write(t_addr addr, t_value value) +{ + ram[addr] = value; + sim_debug(DBG_MEB_W, &cpu_dev, "0x%X 0x%X\n", addr, value); +} + +// See rtx2000_simulator/STATE.C:208 +void _long_fetch(t_addr seg, t_addr address, t_value *value) +{ + t_addr addr = 0; + LEA(seg, address, addr); + if ((addr >= 0) && (addr < RAM_BYTES)) + { + _read(addr >> 1, value); + return; + } + + sim_debug(DBG_MEB_R, &cpu_dev, "nxm: PC=0x%X seg:addr=%d:0x%X addr=0x%X\n", asic_file[PC], seg, address, addr); + ABORT(SCPE_NXM); +} + +// See rtx2000_simulator/STATE.C:195 +void _long_store(t_addr seg, t_addr address, t_value data) +{ + t_addr addr = 0; + LEA(seg, address, addr); + if ((addr >= 0) && (addr < RAM_BYTES)) + { + _write(addr >> 1, data & D16_MASK); + return; + } + + sim_debug(DBG_MEB_W, &cpu_dev, "nxm: PC=0x%X seg:addr=%d:0x%X addr=0x%X\n", asic_file[PC], seg, address, addr); + ABORT(SCPE_NXM); +} + +// See rtx2000_simulator/STATE.C:234 +void byte_fetch(t_addr address, t_value *value) +{ + t_value temp = 0; + dp_fetch(address, &temp); + if ((address & 1) ^ BO) + { + *value = (temp & D16_MASK) & 0x00FF; + } + else + { + *value = ((temp & D16_MASK) >> 8) & 0x00FF; + } +} + +// See rtx2000_simulator/STATE.C:225 +void byte_store(t_addr address, t_value data) +{ + uint32 temp = 0; + union + { + struct + { + uint8 a; + uint8 b; + uint16 mbz; + }; + RTX_WORD c; + } value; + value.mbz = 0; + + // Watch out for doubled wait states!!! + dp_fetch(address, &temp); + + if ((address & 1) ^ BO) + { + value.a = data & 0x00FF; + value.b = temp >> 8; + } + else + { + value.a = temp & 0x00FF; + value.b = data & 0x00FF; + // RTX_WORD value = ((data << 8) & 0xFF00) | (temp & 0xFF); + // dp_store(address, value); + } + dp_store(address, value.c); +} + +/* + * See rtx2000_simulator/STATE.C:240 + * Classes 14 and 15: Data Memory Access + * The instruction formats are identical for both word and byte access. + * The "s" bit (bit 12) of the instruction dictates the size of the operand + * (s =0 for 16-bit word, s = 1 for 8-bit byte). + */ +void fetch(t_addr address, t_value *value) +{ + uint32 tempa = 0; + uint32 tempb = 0; + + // if ((sim_brk_summ & DBG_MEB_R) && sim_brk_test(address, DBG_MEB_R)) + // { + // // longjmp(bkpt_env, STOP_IBKPT); + // printf("!\n"); + // } + if (IR & 0x1000) + { + byte_fetch(address, value); + } + else if ((address & 1) ^ BO) + { + dp_fetch(address, &tempa); + tempb = (tempa >> 8) & 0xFF; + tempa = (tempa << 8) & 0xFF00; + *value = tempa | tempb; + } + else + { + dp_fetch(address, &tempa); + *value = tempa & D16_MASK; + } +} + +/* + * See rtx2000_simulator/STATE.C:255 + * Classes 14 and 15: Data Memory Access + * The instruction formats are identical for both word and byte access. + * The "s" bit (bit 12) of the instruction dictates the size of the operand + * (s =0 for 16-bit word, s = 1 for 8-bit byte). + */ +void store(t_addr address, t_value data) +{ + uint32 tempa = 0; + uint32 tempb = 0; + + if ((sim_brk_summ & DBG_MEB_W) && sim_brk_test(address, DBG_MEB_W)) + { + // longjmp(bkpt_env, STOP_IBKPT); + printf("!\n"); + } + + if (IR & 0x1000) + { + byte_store(address, (data & D16_MASK)); + } + else + { + if ((address & 1) ^ BO) + { + tempb = (data >> 8) & 0xFF; + tempa = (data << 8) & 0xFF00; + dp_store(address, (tempa | tempb)); + } + else + { + dp_store(address, (data & D16_MASK)); + } + } +} + +void ustore(t_addr offset, t_value data) +{ + // See RTX 2001A Datasheet; Fig 13, pg 10 + // uint32 addr = (ubr.ubr & 0xFFFE) | ((offset << 1) & 0x003E); + t_addr addr = ubr.fields.page | ((offset << 1) & 0x003E); + sim_debug(DBG_ASB_R, &cpu_dev, "data=0x%X UBR=0x%X offset=0x%X addr=0x%X\n", data, ubr.pr, offset, addr); + // sim_debug(DBG_ASB_R, &cpu_dev, "PC=0x%X UPR=0x%X addr=0x%X\n", asic_file[PC], upr.pr, addr); + _write(addr, data); +} + +void ufetch(t_addr offset, t_value *data) +{ + // See RTX 2001A Datasheet; Fig 13, pg 10 + t_addr addr = ubr.fields.page | ((offset << 1) & 0x003E); + // sim_debug(DBG_ASB_R, &cpu_dev, "PC=0x%X UPR=0x%X addr=0x%X\n", asic_file[PC], upr.pr, addr); + _read(addr, data); + sim_debug(DBG_ASB_R, &cpu_dev, "data=0x%X UBR=0x%X offset=0x%X addr=0x%X\n", *data, ubr.pr, offset, addr); +} diff --git a/RTX2001A/rtx2001a_mb.h b/RTX2001A/rtx2001a_mb.h new file mode 100644 index 000000000..f8fcef3d3 --- /dev/null +++ b/RTX2001A/rtx2001a_mb.h @@ -0,0 +1,78 @@ +/* rtx2001a_mb.h: RTX2001A CPU simulator + + Copyright (c) 2022, Systasis Computer Systems, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + SYSTASIS COMPUTER SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Systasis Computer Systems shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Systasis Computer Systems. + + 6-Sep-22 SYS From RTX_2000 simulator by Phil Koopman Jr. + + Memory Bus support +*/ +#ifndef RTX2001A_MB_H_ +#define RTX2001A_MB_H_ 0 + +// #include "rtx2001a_defs.h" +#include "rtx2001a_debug.h" +#include "rtx2001a_registers.h" + +// See rtx2000_simulator/STATE.H:208 +#define RAM_SIZE 0x10000 /* in words */ +#define RAM_BYTES 0x100000 +#define RAM_ORG 0x0000 + +// extract the in-line 16-bit lit +#define LIT _long_fetch(page, address, value) + +extern RTX_WORD ram[RAM_SIZE]; + +extern void _read(t_addr, t_value *); +extern void _write(t_addr, t_value); +extern void _long_fetch(t_addr, t_addr, t_value *); +extern void _long_store(t_addr, t_addr, t_value); +extern void byte_fetch(t_addr, t_value *); +extern void byte_store(t_addr, t_value); +extern void fetch(t_addr, t_value *); +extern void store(t_addr, t_value); +extern void ufetch(t_addr, t_value *); +extern void ustore(t_addr, t_value); + +#define DATA_PAGE (DPRSEL ? DPR : CPR) /* correct page for access */ + +#define SEGADDR(prefix) \ + sim_is_running ? prefix "seg:addr=%d:0x%X addr=0x%X\n" : "" + +#define LEA(seg, address, addr) \ + addr = ((seg) ? (((seg << 16) & 0xF0000) | (address & D16_MASK)) : (address & D16_MASK)) - RAM_ORG; + +#define long_fetch(segment, address, value) _long_fetch(segment, address, value) + +#define long_store(segment, address, data) _long_store(segment, address, data) + +#define dp_store(address, data) _long_store(dpr.pr, address, data) + +#define dp_fetch(address, value) _long_fetch(dpr.pr, address, value) + +#define cp_store(address, data) _long_store(cpr.pr, address, data) + +#define cp_fetch(address, value) _long_fetch(cpr.pr, address, value) + +#endif \ No newline at end of file diff --git a/RTX2001A/rtx2001a_psb.c b/RTX2001A/rtx2001a_psb.c new file mode 100644 index 000000000..a6f134ec9 --- /dev/null +++ b/RTX2001A/rtx2001a_psb.c @@ -0,0 +1,68 @@ +/* rtx2001a_psb.c: RTX2001A CPU simulator + + Copyright (c) 2022, Systasis Computer Systems, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + SYSTASIS COMPUTER SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Systasis Computer Systems shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Systasis Computer Systems. + + 9-Oct-22 SYS Initial version + + Parameter Stack Bus support +*/ +#include "rtx2001a_defs.h" +#include "rtx2001a_debug.h" +#include "rtx2001a_registers.h" +#include "rtx2001a_psb.h" +#include "rtx2001a_execute.h" + +/** + ** parameter stack pop + */ +void ps_pop() +{ + SPR ospr; + ospr.pr = spr.pr; + + TOP = NEXT; + NEXT = ps[(spr.fields.psp)]; + sim_debug_bits_hdr(DBG_ASB_R, &cpu_dev, "SPR", spr_bits, spr.pr, spr.pr, 1); + sim_debug(DBG_PSB_R, &cpu_dev, "PS[%d]=0x%X\n", spr.fields.psp, ps[spr.fields.psp] & D16_MASK); + + (spr.fields.psp) = (--(spr.fields.psp)) & STACK_MASK; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "SPR", spr_bits, ospr.pr, spr.pr, 1); +} + +/** + ** parameter stack push + */ +void ps_push(t_value data) +{ + SPR ospr; + ospr.pr = spr.pr; + sim_debug_bits_hdr(DBG_ASB_R, &cpu_dev, "SPR", spr_bits, spr.pr, spr.pr, 1); + (spr.fields.psp) = (++(spr.fields.psp)) & STACK_MASK; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "SPR", spr_bits, ospr.pr, spr.pr, 1); + + ps[(spr.fields.psp)] = NEXT; + NEXT = TOP; + TOP = data; + sim_debug(DBG_PSB_W, &cpu_dev, "PS[%d]=0x%X\n", spr.fields.psp, ps[spr.fields.psp] & D16_MASK); +} \ No newline at end of file diff --git a/RTX2001A/rtx2001a_psb.h b/RTX2001A/rtx2001a_psb.h new file mode 100644 index 000000000..f6262554f --- /dev/null +++ b/RTX2001A/rtx2001a_psb.h @@ -0,0 +1,47 @@ +/* rtx2001a_psb.h: RTX2001A CPU simulator + + Copyright (c) 2022, Systasis Computer Systems, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + SYSTASIS COMPUTER SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Systasis Computer Systems shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Systasis Computer Systems. + + 6-Sep-22 SYS Initial version + + Parameter Stack Bus +*/ +#ifndef RTX2001A_PSB_H_ +#define RTX2001A_PSB_H_ 0 + +#include "rtx2001a_registers.h" + +/* +** +** Stacks on the RTX 2000 and RTX 2010 are each 256 elements deep; +** stacks on the RTX 2001A are 64 elements deep. See SIM2000/STATE.H:38 +*/ +#define PS_MAX 0x40 + +#define PS_MAX 0x40 +extern RTX_WORD ps[PS_MAX + 1]; + +extern void ps_push(t_value); +extern void ps_pop(); +#endif \ No newline at end of file diff --git a/RTX2001A/rtx2001a_registers.h b/RTX2001A/rtx2001a_registers.h new file mode 100644 index 000000000..ffda7c19f --- /dev/null +++ b/RTX2001A/rtx2001a_registers.h @@ -0,0 +1,517 @@ +/* rtx2001a_registers.h: RTX2001A CPU simulator + + Copyright (c) 2022, Systasis Computer Systems, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + SYSTASIS COMPUTER SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Systasis Computer Systems shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Systasis Computer Systems. + + 6-Sep-22 SYS Initial version +*/ + +/* +Stack Related Registers, Internal Processor Registers, and Status/Control Registers, Holding/Counter Scratchpad registers + +The reset states for the RTX 2001A are shown in RTX2001A DataSheet, Table 4 + +R-W Indicates that the register can be either read from or written to +R Indicates a read-only register +W Indicates a write-only register +R/W Indicates that the first register is read-only and the second register is write-only +* Indicates that individual bits in the register may be read-only or write-only and that the bit map for that register should be consulted +N Indicates that the register cannot be read from or written to + +REGISTER ASIC ADDR INITIALIZATION VALUES R W COMMENTS +======== ========= ===================== === ============================================================== +TOP 0000 0000 0000 0000 R-W Holds the top element of the Parameter Stack +NEXT 1111 1111 1111 1111 R-W Holds the second element of the Parameter Stack +IR 0000 0000 0000 0000 N Latch containing the instruction currently being executed +I 01H, 02H, 03H 1111 1111 1111 1111 R-W 16 bits of the 21-bit top element of the Return Stack and + holds the count during streamed and loop instructions + See Table 11, pg 22 +CR 03H 0100 0000 0000 1000 * Interrupts disabled, BOOT=1, Byte Order=0 + See Fig 3, pg 7 +MD 04H 1111 1111 1111 1111 R-W Holds the divisor during Step Divide operations +SR 06H 0000 0000 0000 0000 R-W Holds the intermediate values used during Step Square Root operations +PC 07H 0000 0000 0000 0000 R-W Holds the address of the next instruction to be fetched from Main Memory +IMR 08H 0000 0000 0000 0000 R-W Holds enabled maskable interrupt assignments + See Fig 6, pg 8 +SPR 09H 0000 0000 0000 0000 R-W Holds the stack pointer value for each stack + See Fig 7, pg 9; Fig 6.4, pg 90 +SUR 0AH 0000 0111 0000 0111 R-W Holds holds the underflow limit values for the + Parameter and Return Stacks + See Fig 9, pg 9 +SVR 0BH 1111 1111 1111 1111 W Holds holds the overflow limit values for the + Parameter and Return Stacks + Each stack overflow limit set for max. stack size + See Fig 8, pg 9 +IVR 0BH 0000 0010 0000 0000 R Holds the current Interrupt Vector value + .. See Figure 4, pg. 8 and Table 7, pg. 15 +IPR 0CH 0000 0000 0000 0000 R-W Initialized for Code Page 0 +DPR 0DH 0000 0000 0000 0000 R-W Initialized for Data Page 0 +UPR 0EH 0000 0000 0000 0000 R-W Initialized for User Page 0 +CPR 0FH 0000 0000 0000 0000 R-W Initialized for Code Page 0 +IBC 10H 0000 0000 0000 0000 * Holds the Interrupt Vector base address and + processor configuration information + Interrupt Base=O, Counters on internal clocks, + no rounding, use CPR for data accesses + See Fig 5, pg 8 +UBR 11H 0000 0000 0000 0000 R-W User Base address set to 0 +TC0/TP0 13H 0000 0000 0000 0000 R/W Timer/Counter Registers: +TC1/TP1 14H R/W Hold the current count value for each of the three Timer/Counters +TC2/TP2 15H R/W All Timer/Counters set to timeout after 65536 counts + Timer Preload Registers: + Hold the initial 16-bit count values written to each timer +RX 16H 0000 0000 0000 0000 R-W Scratchpad register for data storage +RH 17H 0000 0000 0000 0000 R-W Scratchpad register for data storage and + a counting register which automatically + increments or decrements RX by one when + read or written by specialized instructions + (see Table 12, pg 22) +*/ + +#ifndef RTX2001A_REGISTERS_H_ +#define RTX2001A_REGISTERS_H_ 0 + +#include "rtx2001a_defs.h" +#include "rtx2001a_psb.h" +#include "rtx2001a_rsb.h" +#include "rtx2001a_debug.h" + +/* +** CPU Stack Registers +*/ +extern RTX_WORD TOP; // Top Register +extern RTX_WORD NEXT; // Next Register + +/* +** Instruction Register Latch +*/ +extern RTX_WORD IR; + +/* +** ASIC Bus Registers +*/ +static enum { + I = 0, // Index Register, no latch + I_ASIC = 1, // Index Register, ASIC bus latch + I_ALU = 2, // Index Register, ALU latch + _CR = 3, // Configuration Register + MD = 4, // Doubleword Multiply/Divide Register + SQ = 5, // "pseudo-register" for step math operation + SR = 6, // Square Root Register + PC = 7, // Program Counter Register + _IMR = 8, // Interrupt Mask Register + _SPR = 9, // Stack Pointer Register + _SUR = 0xA, // Stack Underflow Register + _SVR = 0xB, // Stack Overflow Register, write-only + _IVR = 0xB, // Interrupt Vector Register, read-only + _IPR = 0xC, // Index Page Register + _DPR = 0xD, // Data Page Register + _UPR = 0xE, // User Page Register + _CPR = 0xF, // Code Page Register + _IBC = 0x10, // Interrupt Base/Control Register + _UBR = 0x11, // User Base Address Register + TC0 = 0x13, // Timer Counter Register 0, read-only + TP0 = 0x13, // Timer Preload Register 0, write-only + TC1 = 0x14, // Timer Counter Register 1, read-only + TP1 = 0x14, // Timer Preload Register 1, write-only + TC2 = 0x15, // Timer Counter Register 2, read-only + TP2 = 0x15, // Timer Preload Register 2, write-only + RX = 0x16, // Scratchpad/Counting register + RH = 0x17, // Scratchpad register + RSP = 0x21, // Return stack pointer + PSP = 0x22, // Parameter stack pointer + RS = 0x23, // Parameter stack + PS = 0x24, // Return stack + ASIC_MAX = 0x25, +} ASIC_FILE; +extern RTX_WORD asic_file[ASIC_MAX]; + +/** + * Configuration Register + */ +struct ConfigurationRegisterFields +{ + RTX_WORD cy : 1; // 0: R/W Carry + RTX_WORD ccy : 1; // 1: R/W Complex Carry + RTX_WORD bo : 1; // 2: Byte Order 0=BE (Intel), 1=LE (Motorola) + RTX_WORD boot : 1; // 3: Select Boot ROM + RTX_WORD sid : 1; // 4: Set Interrupt Disable 0=Enabled, 1=Disabled + RTX_WORD mbz0 : 9; // 5-13 MBZ + RTX_WORD rid : 1; // 14: Read Interrupt Disable + RTX_WORD il : 1; // 15: Interrupt Latch +}; + +static union ConfigurationRegister +{ + struct ConfigurationRegisterFields fields; + RTX_WORD pr; +} cr; +typedef union ConfigurationRegister CR; +#define CY (cr.fields.cy) +#define CCY (cr.fields.ccy) +#define BO (cr.fields.bo) +#define BOOT (cr.fields.boot) +#define SID (cr.fields.sid) +#define RID (cr.fields.rid) +#define IL (cr.fields.il) + +static BITFIELD cr_bits[] = { // Fig 3, pg 7 + BIT(CY), // 0: R/W Carry + BIT(CCY), // 1: R/W Complex Carry + BIT(BO), // 2: Byte Order 0=BE, 1=LE + BIT(BOOT), // 3: Select Boot ROM + BIT(SID), // 4: Set Interrupt Disable 0=Enabled, 1=Disabled + BITNCF(9), // 5-13 MBZ + BIT(RID), // 14: Read Interrupt Disable + BIT(IL), // 15: Interrupt latch + ENDBITS}; + +/* +** Interrupt Mask Register +*/ +struct InterruptMaskRegisterFields +{ + RTX_WORD mbz : 1; // 0: Always reads as O. + RTX_WORD ei1 : 1; // 1: External Input Pin 1 + RTX_WORD psu : 1; // 2: Parameter Stack Underflow + RTX_WORD rsu : 1; // 3: Return Stack Underflow + RTX_WORD psv : 1; // 4: Parameter Stack Overflow + RTX_WORD rsv : 1; // 5: Return Stack overflow + RTX_WORD ei2 : 1; // 6: External Input Pin 2 + RTX_WORD t0 : 1; // 7: Timer / Counter 0 Interrupt + RTX_WORD t1 : 1; // 8: Timer / Counter 1 Interrupt + RTX_WORD t2 : 1; // 9: Timer / Counter 2 Interrupt + RTX_WORD ei3 : 1; // 10: External Input Pin 3 + RTX_WORD ei4 : 1; // 11: External Input Pin 4 + RTX_WORD ei5 : 1; // 12: External Input Pin 5 + RTX_WORD swi : 1; // 13: Software Interrupt + RTX_WORD mbz1 : 2; // 14-15: Always reads as O. +}; + +static BITFIELD imr_bits[] = { // Table 4.7, pg 51 + BITNC, // 0: Always reads as O. + BIT(EI1), // 1: External Input Pin 1 + BIT(PSU), // 2: Parameter Stack Underflow + BIT(RSU), // 3: Return Stack Underflow + BIT(PSV), // 4: Parameter Stack Overflow + BIT(RSV), // 5: Return Stack overflow + BIT(EI2), // 6: External Input Pin 2 + BIT(T0), // 7: Timer / Counter 0 Interrupt + BIT(T1), // 8: Timer / Counter 1 Interrupt + BIT(T2), // 9: Timer / Counter 2 Interrupt + BIT(EI3), // 10: External Input Pin 3 + BIT(EI4), // 11: External Input Pin 4 + BIT(EI5), // 12: External Input Pin 5 + BIT(SWI), // 13: Software Interrupt + BITNCF(2), // 14-15: Always reads as O. + ENDBITS}; + +static union InterruptMaskRegister +{ + struct InterruptMaskRegisterFields fields; + RTX_WORD pr; +} imr; +typedef union InterruptMaskRegister IMR; + +/** + * Stack Pointer Register + * + * RTX2001A has 64 words in each stack + */ +struct StackPointerRegisterFields +{ + RTX_WORD psp : 6; + RTX_WORD mbz0 : 2; + RTX_WORD rsp : 6; + RTX_WORD mbz1 : 2; +}; + +static union StackPointerRegister +{ + struct StackPointerRegisterFields fields; + RTX_WORD pr; +} spr; +typedef union StackPointerRegister SPR; +#define STACK_MASK 0x3F /* mask for stack pointer wrapping */ +// define RSP (spr.fields.rsp) +// define PSP (spr.fields.psp) + +static BITFIELD spr_bits[] = { // Fig 7, pg 9 + BITF(PSP, 6), // 0-5: Parameter Stack Pointer. + BITNCF(2), // + BITF(RSP, 6), // 8-13: Return Stack Pointer. + BITNCF(2), + ENDBITS}; + +/** + * Stack Underflow Register + */ +struct StackUnderflowRegisterFields +{ + RTX_WORD psf : 1; // 0: Parameter Stack Start Flag + RTX_WORD pss : 1; // 1: Parameter Substacks, 0: two 32 word stacks, 1: one 64 word stack + RTX_WORD mbz0 : 1; // 2: Reserved + RTX_WORD psu : 5; // 3-7: Parameter Stack Underflow Limit, 0 - 31 words from stack bottom + RTX_WORD rsf : 1; // 8: Return Stack Start Flag + RTX_WORD rss : 1; // 9: Return Substacks, 0: two 32 word stacks, 1: one 64 word stack + RTX_WORD mbz1 : 1; // 10: Reserved + RTX_WORD rsu : 5; // 11-15: Return Stack Underflow Limit, 0 - 31 words from stack bottom +}; + +static union StackUnderflowRegister +{ + struct StackUnderflowRegisterFields fields; + RTX_WORD pr; +} sur; +typedef union StackUnderflowRegister SUR; +#define PSF (sur.fields.psf) +#define PSS (sur.fields.pss) +#define PSU (sur.fields.psu) +#define RSF (sur.fields.rsf) +#define RSS (sur.fields.rss) +#define RSU (sur.fields.rsu) + +static BITFIELD sur_bits[] = { // Fig 6.8, pg 93 + BIT(PSF), // 0: Parameter Stack Start Flag + BIT(PS), // 1: Parameter Substacks, 0: two 32 word stacks, 1: one 64 word stack + BITNC, // 2: Reserved + BITF(PSU, 5), // 3-7: Parameter Stack Underflow Limit, 0 - 31 words from stack bottom + BIT(RSF), // 8: Return Stack Start Flag + BIT(RS), // 9: Return Substacks, 0: two 32 word stacks, 1: one 64 word stack + BITNC, // 10: Reserved + BITF(RSU, 5), // 11-15: Return Stack Underflow Limit, 0 - 31 words from stack bottom + ENDBITS}; + +/** + * Interrupt Vector Register + */ +struct InterruptVectorRegisterFields +{ + RTX_WORD mbz : 5; // 0-4: Reserved + RTX_WORD ivb : 5; // 5-9: Interrupt Vector Base + RTX_WORD vec : 5; // 10-15: Vector +}; + +static union InterruptVectorRegister +{ + struct InterruptVectorRegisterFields fields; + RTX_WORD pr; +} ivr; +typedef union InterruptVectorRegister IVR; + +static BITFIELD ivr_bits[] = { + BITNCF(5), // 0-4: Reserved + BITF(IVB, 5), // 5-9: Interrupt Vector Base + BITF(VEC, 5), // 10-15: Vector + ENDBITS}; + +/** + * Stack Overflow Register + */ +struct StackOverflowRegisterFields +{ + RTX_WORD pvl : 6; // 0-5: Parameter Stack Overflow Limit, 0 - 31 words from stack bottom + RTX_WORD mbz0 : 2; // 6-7: Reserved + RTX_WORD rvl : 6; // 8-13: Return Stack Overflow Limit, 0 - 31 words from stack bottom + RTX_WORD mbz1 : 2; // 14-15: Reserved +}; + +static union StackOverflowRegister +{ + struct StackOverflowRegisterFields fields; + RTX_WORD pr; +} svr; +typedef union StackOverflowRegister SVR; +#define PVL (svr.fields.pvl) +#define RVL (svr.fields.rvl) + +static BITFIELD svr_bits[] = { // Fig 9, pg 8 + BITF(PVL, 6), // 0-5: Parameter Stack Overflow Limit, 0 - 31 words from stack bottom + BITNCF(2), // 6-7: Reserved + BITF(RVL, 6), // 8-13: Return Stack Overflow Limit, 0 - 31 words from stack bottom + BITNCF(2), // 14-15: Reserved + ENDBITS}; + +/** + * Index Page Register + */ +struct IndexPageRegisterFields +{ + RTX_WORD pr : 5; // 0-4: 5 most significant bits of the top element of the Return Stack (I) or current page address + RTX_WORD mbz1 : 11; // 5-15: Reserved +}; + +static BITFIELD ipr_bits[] = { // Fig 10, pg 9 + BITF(IPR, 5), // 0-4: 5 most significant bits of the top element of the Return Stack or current page address + BITNCF(11), // 5-15: Reserved + ENDBITS}; + +static union IndexPageRegister +{ + struct IndexPageRegisterFields fields; + RTX_WORD pr; +} ipr; +typedef union IndexPageRegister IPR; + +/** + * Data/User/Code Page Registers + */ +struct PageRegisterFields +{ + RTX_WORD pr : 4; // 0-3: 4 most significant bits of the top element of the Return Stack (I) or current page address + RTX_WORD mbz1 : 12; // 4-15: Reserved +}; + +static BITFIELD pr_bits[] = { // Fig 10, pg 9 + BITF(PR, 4), // 0-3: 4 most significant bits of the top element of the Return Stack or current page address + BITNCF(12), // 4-15: Reserved + ENDBITS}; + +static union DataPageRegister +{ + struct PageRegisterFields fields; + RTX_WORD pr; +} dpr; +typedef union DataPageRegister DPR; + +/** + * User Page & Base Address Registers + */ +static union UserPageRegister +{ + struct PageRegisterFields fields; + RTX_WORD pr; +} upr; +typedef union UserPageRegister UPR; + +static union CodePageRegister +{ + struct PageRegisterFields fields; + RTX_WORD pr; +} cpr; +typedef union CodePageRegister CPR; + +/** + * Interrupt Base/Control Register + */ +struct InterruptBaseControlRegisterFields +{ + RTX_WORD sef : 1; // 0: RO Stack Error flag + RTX_WORD psu : 1; // 1: RO Parameter Stack Underflow flag + RTX_WORD rsu : 1; // 2: RO Return Stack Underflow flag + RTX_WORD psv : 1; // 3: RO Parameter Stack Overflow flag + RTX_WORD rsv : 1; // 4: RO Return Stack Overflow flag + RTX_WORD dprsel : 1; // 5: RW Data Page Register, 0=CPR, 1=DPR + RTX_WORD mbz : 1; // 6: Reserved + RTX_WORD cycext : 1; // 7: RW Enable Extended Cycle Length + RTX_WORD tc : 2; // 8-9 RW Select Timer/Counter Input Signals + RTX_WORD ivb : 5; // 10-15 RW Interrupt Vector Base, MA10 - MA15 +}; + +static union InterruptBaseControlRegister +{ + struct InterruptBaseControlRegisterFields fields; + RTX_WORD pr; +} ibc; +typedef union InterruptBaseControlRegister IBC; + +#define SEF (ibc.fields.sef) +#define IBC_PSU (ibc.fields.psu) +#define IBC_RSU (ibc.fields.rsu) +#define IBC_PSV (ibc.fields.psv) +#define IBC_RSV (ibc.fields.rsv) +#define DPRSEL (ibc.fields.dprsel) +#define CYCEXT (ibc.fields.cycext) +#define TC (ibc.fields.tc) +#define IVB (ibc.fields.ivb) + +static BITFIELD ibc_bits[] = { // Fig 5, pg 7 + BIT(SEF), // 0: RO Stack Error flag + BIT(PSU), // 1: RO Parameter Stack Underflow flag + BIT(RSU), // 2: RO Return Stack Underflow flag + BIT(PSV), // 3: RO Parameter Stack Overflow flag + BIT(RSV), // 4: RO Return Stack Overflow flag + BIT(DPRSEL), // 5: RW Data Page Register, 0=CPR, 1=DPR + BITNC, // 6: Reserved + BIT(CYCEXT), // 7: RW Enable Extended Cycle Length + BITF(TC, 2), // 8-9 RW Select Timer/Counter Input Signals + BITF(IVB, 5), // 10-15 RW Interrupt Vector Base, MA10 - MA15 + ENDBITS}; + +struct UserBaseAddressRegisterFields +{ + RTX_WORD mbz : 1; // 0: Reserved + RTX_WORD page : 5; // 1-5: User Memory address page + RTX_WORD adr : 10; // 6-15: User Memory address +}; + +static union UserBaseAddressRegister +{ + struct UserBaseAddressRegisterFields fields; + RTX_WORD pr; +} ubr; +typedef union UserBaseAddressRegister UBR; + +static BITFIELD ubr_bits[] = { // Fig 13, pg 10 + BITNC, // 0: Reserved + BITF(PAGE, 5), // 1-5: User Memory Address Page + BITF(ADR, 10), // 6-15: User Memory Address + ENDBITS}; + +static REG cpu_reg[] = { + {HRDATAD(TOP, TOP, 16, "Parameter Stack top element"), REG_RO}, + {HRDATAD(NEXT, NEXT, 16, "Parameter Stack second element"), REG_RO}, + {HRDATAD(IR, IR, 16, "Instruction Register"), REG_HIDDEN}, + {HRDATAD(I, asic_file[I], 16, "Index Register"), REG_DEPOSIT | 1 << REG_V_UF}, + {HRDATADF(CR, cr.pr, 16, "Configuration Register", cr_bits), REG_DEPOSIT | (3 << REG_V_UF)}, + // 5 + {HRDATAD(MD, asic_file[MD], 16, "Multiply/Divide Register"), REG_DEPOSIT | (4 << REG_V_UF)}, + {HRDATAD(SR, asic_file[SR], 16, "Square Root Register"), REG_DEPOSIT | (6 << REG_V_UF)}, + {HRDATAD(PC, asic_file[PC], 16, "Program Counter Register"), REG_DEPOSIT | (7 << REG_V_UF)}, + {HRDATADF(IMR, imr.pr, 16, "Interrupt Mask Register", imr_bits), REG_DEPOSIT | (8 << REG_V_UF)}, + {HRDATADF(SPR, spr.pr, 16, "Stack Pointer Register", spr_bits), REG_RO | (9 << REG_V_UF)}, + // 10 + {HRDATADF(SUR, sur.pr, 16, "Stack Underflow Register", sur_bits), REG_DEPOSIT | (0xA << REG_V_UF)}, + {HRDATADF(SVR, svr.pr, 16, "Stack Overflow Register", svr_bits), REG_DEPOSIT | (0xB << REG_V_UF)}, + {HRDATADF(IVR, ivr.pr, 16, "Interrupt Vector Register", ivr_bits), REG_RO | (0xB << REG_V_UF)}, + {HRDATADF(IPR, ipr.pr, 16, "Index Page Register", pr_bits), REG_DEPOSIT | (0xC << REG_V_UF)}, + {HRDATADF(DPR, dpr.pr, 16, "Data Page Register", pr_bits), REG_DEPOSIT | (0xD << REG_V_UF)}, + // 15 + {HRDATADF(UPR, upr.pr, 16, "User Page Register", pr_bits), REG_DEPOSIT | (0xE << REG_V_UF)}, + {HRDATADF(CPR, cpr.pr, 16, "Code Page Register", pr_bits), REG_DEPOSIT | (0xE << REG_V_UF)}, + {HRDATADF(IBC, ibc.pr, 16, "Interrupt Base/Control Register", ibc_bits), REG_DEPOSIT | (0x10 << REG_V_UF)}, + {HRDATADF(UBR, ubr.pr, 16, "User Base Address Register", ubr_bits), REG_DEPOSIT | (0x11 << REG_V_UF)}, + {HRDATAD(TC0, asic_file[TC0], 16, "Timer Counter 0 Register"), REG_RO | (0x13 << REG_V_UF)}, + // 20 + {HRDATAD(TP0, asic_file[TP0], 16, "Timer Preload 0 Register"), REG_DEPOSIT | (0x14 << REG_V_UF)}, + {HRDATAD(TC1, asic_file[TC1], 16, "Timer Counter 1 Register"), REG_RO | (0x15 << REG_V_UF)}, + {HRDATAD(TP1, asic_file[TP1], 16, "Timer Preload 1 Register"), REG_DEPOSIT | (0x16 << REG_V_UF)}, + {HRDATAD(TC2, asic_file[TC2], 16, "Timer Counter 2 Register"), REG_RO | (0x17 << REG_V_UF)}, + {HRDATAD(TP2, asic_file[TP2], 16, "Timer Preload 2 Register"), REG_DEPOSIT | (0x18 << REG_V_UF)}, + {HRDATAD(RX, asic_file[RX], 16, "Scratchpad/Counting register"), REG_DEPOSIT | (0x19 << REG_V_UF)}, + {HRDATAD(RH, asic_file[RH], 16, "Scratchpad register"), REG_DEPOSIT | (0x20 << REG_V_UF)}, + {HRDATAD(RSP, spr.pr, 16, "Return Stack Pointer"), REG_DEPOSIT | (0x21 << REG_V_UF)}, + {HRDATAD(PSP, spr.pr, 16, "Parameter Stack Pointer"), REG_DEPOSIT | (0x22 << REG_V_UF)}, + {HRDATAD(RS, rs, 16, "Return Stack"), REG_RO | (0x23 << REG_V_UF)}, + {HRDATAD(PS, ps, 16, "Parameter Stack"), REG_RO | (0x24 << REG_V_UF)}, + {NULL}}; + +#endif \ No newline at end of file diff --git a/RTX2001A/rtx2001a_rsb.c b/RTX2001A/rtx2001a_rsb.c new file mode 100644 index 000000000..94de5ad76 --- /dev/null +++ b/RTX2001A/rtx2001a_rsb.c @@ -0,0 +1,82 @@ +/* rtx2001a_rsb.c: RTX2001A CPU simulator + + Copyright (c) 2022, Systasis Computer Systems, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + SYSTASIS COMPUTER SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Systasis Computer Systems shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Systasis Computer Systems. + + 9-Oct-22 SYS Initial version + + Parameter Stack Bus support +*/ +#include "rtx2001a_defs.h" +#include "rtx2001a_debug.h" +#include "rtx2001a_registers.h" +#include "rtx2001a_rsb.h" +#include "rtx2001a_ab.h" + +/** +** return stack push with 2 inputs +** @TODO: Implement stack over/under flow +*/ +void rs_push(t_addr page, t_value data) +{ + SPR ospr; + ospr.pr = spr.pr; + + (spr.fields.rsp) = (++(spr.fields.rsp)) & STACK_MASK; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "SPR", spr_bits, ospr.pr, spr.pr, 1); + + rs[(spr.fields.rsp)].fields.ipr = ipr.fields.pr; + rs[(spr.fields.rsp)].fields.i = asic_file[I]; + + sim_debug(DBG_RSB_W, &cpu_dev, "RS[%d]=%d:0x%04X\n", spr.fields.rsp, ipr.fields.pr, asic_file[I]); + + asic_file[I] = data; + sim_debug(DBG_ASB_W, &cpu_dev, "I=0x%04X\n", asic_file[I]); + set_IPR(page); + // IDK why this is here. See STATE.C:145 + // if (DPRSEL) + // { + // IPR oipr; + // oipr.pr = ipr.pr; + // ipr.pr &= 0x10; + // sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "IPR", ipr_bits, oipr.pr, ipr.pr, 1); + // } +} + +/* return stack pop, return element popped */ +void rs_pop() +{ + ReturnStack orsp; + SPR ospr; + orsp.pr = rs[(spr.fields.rsp)].pr; + ospr.pr = spr.pr; + + /* don't use set_IPR; bit 4 comes from RS */ + sim_debug(DBG_RSB_R, &cpu_dev, "RS[%d]=%d:0x%04X\n", spr.fields.rsp, rs[spr.fields.rsp].fields.ipr, rs[spr.fields.rsp].fields.i); + ipr.fields.pr = rs[(spr.fields.rsp)].fields.ipr; + asic_file[I] = rs[(spr.fields.rsp)].fields.i; + sim_debug(DBG_ASB_W, &cpu_dev, "IPR=%d I=0x%04X\n", ipr.fields.pr, asic_file[I]); + + (spr.fields.rsp) = (--(spr.fields.rsp)) & STACK_MASK; + sim_debug_bits_hdr(DBG_ASB_W, &cpu_dev, "SPR", spr_bits, ospr.pr, spr.pr, 1); +} diff --git a/RTX2001A/rtx2001a_rsb.h b/RTX2001A/rtx2001a_rsb.h new file mode 100644 index 000000000..f652e8644 --- /dev/null +++ b/RTX2001A/rtx2001a_rsb.h @@ -0,0 +1,66 @@ +/* rtx2001a_rsb.h: RTX2001A CPU simulator + + Copyright (c) 2022, Systasis Computer Systems, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + SYSTASIS COMPUTER SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Systasis Computer Systems shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Systasis Computer Systems. + + 6-Sep-22 SYS Initial version. See also SIM2000/STATE.H:109 + + Return Stack Bus + +*/ +#ifndef RTX2001A_RSB_H_ +#define RTX2001A_RSB_H_ 0 + +#include "rtx2001a_defs.h" + +/* +** +** Stacks on the RTX 2000 and RTX 2010 are each 256 elements deep; +** stacks on the RTX 2001A are 64 elements deep. See SIM2000/STATE.H:38 +*/ +struct ReturnStackFields +{ + RTX_WORD ipr : 6; // 0-5: Current value of IPR + RTX_WORD i : 16; // 6-21: Current value of I +}; + +union Return_Stack +{ + struct ReturnStackFields fields; + RTX_WORD pr; +}; + +typedef union Return_Stack ReturnStack; + +static BITFIELD rs_bits[] = { // Fig 11, pg 10 + BITF(IPR, 6), // 0-5: Current value of IPR + BITF(I, 16), // 6-21: Current value of I + ENDBITS}; + +#define RS_MAX 0x40 + +extern ReturnStack rs[RS_MAX + 1]; + +extern void rs_push(t_addr, t_value); +extern void rs_pop(); +#endif \ No newline at end of file diff --git a/RTX2001A/rtx2001a_sys.c b/RTX2001A/rtx2001a_sys.c new file mode 100644 index 000000000..d7d9788a3 --- /dev/null +++ b/RTX2001A/rtx2001a_sys.c @@ -0,0 +1,337 @@ +/* rtx2001a_sys.c: RTX2001A simulator interface + + Copyright (c) 2022, Systasis Computer Systems, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + SYSTASIS COMPUTER SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Systasis Computer Systems shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Systasis Computer Systems. + + 12-Aug-22 SYS New simulator. +*/ + +#include "rtx2001a_defs.h" +#include "rtx2001a_registers.h" +#include "rtx2001a_psb.h" +#include "rtx2001a_rsb.h" +#include "rtx2001a_debug.h" +#include "rtx2001a_mb.h" + +char sim_name[] = "RTX2001A"; + +DEVICE *sim_devices[] = { + &cpu_dev, + NULL}; + +const char *sim_stop_messages[SCPE_BASE] = { + "Unknown error", + "HALT instruction", + "Breakpoint", + "Invalid opcode", +}; + +t_bool build_dev_tab(void) +{ + return SCPE_OK; +} +/** + * These cases are differentiated by the presence of special flags in the switch parameter. + * For a simulation stop, the “M” switch and the SIM_SW_STOP switch are passed. + * For examining registers, the SIM_SW_REG switch is passed. + * The user-defined flags and register radix are passed in the addr parameter. + * Register radix is taken from the radix specified in the register definition, or overridden by –d, -o, or –x switches in the command. + * For examining memory and the EVAL command, no special switch flags are passed. + */ +t_stat fprint_sym(FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) +{ + t_value cell = (addr & REG_UFMASK) >> 16; + + if (sw & SIM_SW_REG) + { + BITFIELD *bits = NULL; + t_value value = *val; + switch (cell) + { + case _CR: + bits = sim_is_running ? cr_bits : NULL; + break; + case _SUR: + bits = sim_is_running ? sur_bits : NULL; + break; + case _IVR: // _SVR + bits = sim_is_running ? (svr.pr == value ? svr_bits : ivr_bits) : NULL; + break; + case _IPR: + case _DPR: + case _UPR: + case _CPR: + bits = sim_is_running ? pr_bits : NULL; + break; + case _IBC: + bits = sim_is_running ? ibc_bits : NULL; + break; + case _UBR: + bits = sim_is_running ? ubr_bits : NULL; + break; + case RSP: + value = spr.fields.rsp; + break; + + case RS: + { + fprintf(of, "RSP=%d ", spr.fields.rsp); + if (0 == spr.fields.rsp) + { + fprintf(of, "empty "); + return SCPE_OK; + } + + fprintf(of, "%d:0x%04X ", ipr.fields.pr, asic_file[I]); + + ReturnStack *ptr = &rs[spr.fields.rsp]; + while (ptr != &rs[1]) + { + fprintf(of, "%d:0x%04X ", ptr->fields.ipr, ptr->fields.i); + ptr--; + } + return SCPE_OK; + break; + } + + case PS: + { + fprintf(of, "PSP=%d ", spr.fields.psp); + if (0 == spr.fields.psp) + { + fprintf(of, "empty "); + return SCPE_OK; + } + + fprintf(of, "0x%X ", TOP); + if (1 == spr.fields.psp) + return SCPE_OK; + + fprintf(of, "0x%X ", NEXT); + + RTX_WORD *ptr = &ps[spr.fields.psp]; + while (ptr != &ps[2]) + { + printf("0x%X ", *ptr & D16_MASK); + ptr--; + } + + return SCPE_OK; + } + + case PSP: + value = spr.fields.psp; + break; + } + + fprintf(of, sim_is_running ? "0x%X\n" : "0x%X", value); + if (bits) + { + sim_debug_bits(DBG_ASB_R, &cpu_dev, bits, value, value, 1); + } + else + { + if (sim_is_running) + fprintf(of, "0x%X", value); + } + } + else + { + fprintf(of, "0x%X", *val); + } + + return SCPE_OK; +} + +t_stat parse_sym(CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +{ + RTX_WORD value = strtoul(cptr, NULL, 16); + if (sw & SIM_SW_REG) + { + RTX_WORD cell = (addr & REG_UFMASK) >> 16; + char name[] = ""; + switch (cell) + { + case _CR: + DEBUG_SET(cr.pr, cr_bits); + break; + case _SUR: + DEBUG_SET(sur.pr, sur_bits); + break; + case _SVR: + DEBUG_SET(svr.pr, svr_bits); + break; + case _IPR: + DEBUG_SET(ipr.pr, pr_bits); + break; + case _DPR: + DEBUG_SET(dpr.pr, pr_bits); + break; + case _UPR: + DEBUG_SET(upr.pr, pr_bits); + break; + case _CPR: + DEBUG_SET(cpr.pr, pr_bits); + break; + case _IBC: + DEBUG_SET(ibc.pr, ibc_bits); + break; + case _UBR: + DEBUG_SET(ubr.pr, ubr_bits); + break; + case PSP: + spr.fields.psp = (value & D16_MASK); + *val = spr.pr; + sim_debug(DBG_ASB_W, &cpu_dev, "%s: 0x%X\n", (&cpu_reg[_SPR])->name, *val); + break; + case RSP: + spr.fields.rsp = (value & D16_MASK); + *val = spr.pr; + sim_debug(DBG_ASB_W, &cpu_dev, "%s: 0x%X\n", (&cpu_reg[_SPR])->name, *val); + break; + default: + { + *val = (value & D16_MASK); + sim_debug(DBG_ASB_W, &cpu_dev, "%s: 0x%X\n", (&cpu_reg[cell])->name, *val); + } + } + } + else + { + *val = (value & D16_MASK); + } + return SCPE_OK; +} + +void byte_to_int(char *byte, int *value) +{ + if (*byte >= '0' && *byte <= '9') + { + *value = (*byte - (int)'0') << 4; + } + if (*byte >= 'A' && *byte <= 'F') + { + *value = (*byte + 10 - (int)'A') << 4; + } + if (*byte >= 'a' && *byte <= 'f') + { + *value = (*byte + 10 - (int)'a') << 4; + } + byte += 1; + if (*byte >= '0' && *byte <= '9') + { + *value |= (*byte - (int)'0'); + } + if (*byte >= 'A' && *byte <= 'F') + { + *value |= (*byte + 10 - (int)'A'); + } + if (*byte >= 'a' && *byte <= 'f') + { + *value |= (*byte + 10 - (int)'a'); + } +} + +void word_to_int(char *word, int *value) +{ + int hi = 0; + int lo = 0; + byte_to_int(word, &hi); + word += 2; + byte_to_int(word, &lo); + *value = hi << 8 | lo; +} + +/* +If flag = 0, load data from binary file fptr. +If flag = 1, dump data to binary file fptr. +For either command, buf contains any VM-specific arguments, and fnam contains the file name. +*/ +t_stat sim_load(FILE *fptr, const char *buf, const char *fnam, t_bool flag) +{ + struct + { + char leader; + char len[2]; + } header; + + struct + { + char address[4]; + char type[2]; + char body[255]; + } cargo; + + int len; + int address; + int bytesRead = fread(&header, sizeof(header), 1, fptr); + while (!feof(fptr)) + { + if (':' != header.leader) + { + sim_messagef(SCPE_INCOMP, "input file not in proper .HEX format, "); + return SCPE_INCOMP; + } + + byte_to_int(header.len, &len); + + if (0 == len) + { + break; + } + + memset(cargo.address, '\0', sizeof(cargo.address)); + memset(cargo.type, '\0', sizeof(cargo.type)); + memset(cargo.body, '\0', sizeof(cargo.body)); + bytesRead = fread(&cargo, (len * 2) + 10, 1, fptr); + if (feof(fptr)) + { + sim_messagef(SCPE_INCOMP, "unexpected EOF, "); + return SCPE_INCOMP; + } + + word_to_int(cargo.address, &address); + int value; + for (int i = 0; i < len * 2; i++) + { + byte_to_int(&cargo.body[i], &value); + byte_store(address, value); + sim_printf("dep 0x%X %c", address, cargo.body[i]); + byte_to_int(&cargo.body[++i], &value); + byte_store(++address, value); + sim_printf("%c\n", cargo.body[i]); + } + + header.leader = '\0'; + memset(header.len, '\0', sizeof(header.len)); + bytesRead = fread(&header, sizeof(header), 1, fptr); + } + + if (':' != header.leader) + { + sim_messagef(SCPE_INCOMP, "input file not in proper .HEX format, "); + return SCPE_INCOMP; + } + + return SCPE_OK; +} \ No newline at end of file diff --git a/doc/~$mh_doc.doc b/doc/~$mh_doc.doc new file mode 100644 index 000000000..1215360c5 Binary files /dev/null and b/doc/~$mh_doc.doc differ diff --git a/doc/~$simh.doc b/doc/~$simh.doc new file mode 100644 index 000000000..1215360c5 Binary files /dev/null and b/doc/~$simh.doc differ diff --git a/makefile b/makefile index f26bc1180..6cdac8f6d 100644 --- a/makefile +++ b/makefile @@ -2944,5 +2944,21 @@ frontpaneltest : ${BIN}frontpaneltest${EXE} ${BIN}frontpaneltest${EXE} : frontpanel/FrontPanelTest.c sim_sock.c sim_frontpanel.c #cmake:ignore-target ${MKDIRBIN} - ${CC} frontpanel/FrontPanelTest.c sim_sock.c sim_frontpanel.c ${CC_OUTSPEC} ${LDFLAGS} ${OS_CURSES_DEFS} + ${CC} frontpanel/FrontPanelTest.c sim_sock.c sim_frontpanel.c ${CC_OUTSPEC} ${LDFLAGS} ${OS_CURSES_DEFS} + +# rtx2001a +RTX2001AD = ${SIMHD}/RTX2001A/ +RTX2001AD_SRC = ${RTX2001AD} +# RTX2001AD_TEST = ${RTX2001AD}/test +RTX2001A_SRC = \ + ${RTX2001AD_SRC}rtx2001a_cpu.c ${RTX2001AD_SRC}rtx2001a_sys.c ${RTX2001AD_SRC}rtx2001a_decode.c \ + ${RTX2001AD_SRC}rtx2001a_execute.c ${RTX2001AD_SRC}rtx2001a_ab.c ${RTX2001AD_SRC}rtx2001a_mb.c \ + ${RTX2001AD_SRC}rtx2001a_psb.c ${RTX2001AD_SRC}rtx2001a_rsb.c + +rtx2001a : ${BIN}rtx2001a${EXE} + +${BIN}rtx2001a${EXE} : ${SIM} ${RTX2001A_SRC} + ${MKDIRBIN} + ${CC} ${SIM} ${RTX2001A_SRC} ${CC_OUTSPEC} ${LDFLAGS} + $@ $(call find_test,${RTX2001AD},rtx2001a) ${TEST_ARG}