| /* i7070_sys.c: IBM 7070 Simulator system interface. | |
| Copyright (c) 2006-2016, Richard Cornwell | |
| 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 | |
| RICHARD CORNWELL 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. | |
| */ | |
| #include "i7070_defs.h" | |
| #include "sim_card.h" | |
| #include <ctype.h> | |
| t_stat parse_sym(CONST char *cptr, t_addr addr, UNIT * uptr, t_value * val, int32 sw); | |
| /* SCP data structures and interface routines | |
| sim_name simulator name string | |
| sim_PC pointer to saved PC register descriptor | |
| sim_emax number of words for examine | |
| sim_devices array of pointers to simulated devices | |
| sim_stop_messages array of pointers to stop messages | |
| sim_load binary loader | |
| */ | |
| char sim_name[] = "IBM 7070"; | |
| REG *sim_PC = &cpu_reg[0]; | |
| int32 sim_emax = 1; | |
| DEVICE *sim_devices[] = { | |
| &cpu_dev, | |
| &chan_dev, | |
| #ifdef NUM_DEVS_CDR | |
| &cdr_dev, | |
| #endif | |
| #ifdef NUM_DEVS_CDP | |
| &cdp_dev, | |
| #endif | |
| #ifdef NUM_DEVS_LPR | |
| &lpr_dev, | |
| #endif | |
| #ifdef NUM_DEVS_CON | |
| &con_dev, | |
| #endif | |
| #if NUM_DEVS_MT > 0 | |
| &mta_dev, | |
| #if NUM_DEVS_MT > 1 | |
| &mtb_dev, | |
| #if NUM_DEVS_MT > 2 | |
| &mtc_dev, | |
| #if NUM_DEVS_MT > 3 | |
| &mtd_dev, | |
| #endif | |
| #endif | |
| #endif | |
| #endif | |
| #if NUM_DEVS_HT > 0 | |
| &hta_dev, | |
| #if NUM_DEVS_HT > 1 | |
| &htb_dev, | |
| #endif | |
| #endif | |
| #ifdef NUM_DEVS_DSK | |
| &dsk_dev, | |
| #endif | |
| #ifdef NUM_DEVS_COM | |
| &coml_dev, | |
| &com_dev, | |
| #endif | |
| #ifdef NUM_DEVS_CHRON | |
| &chron_dev, | |
| #endif | |
| NULL | |
| }; | |
| /* Device addressing words */ | |
| #ifdef NUM_DEVS_CDR | |
| DIB cdr_dib = { CH_TYP_UREC, 1, 01, 0xF, &cdr_cmd, NULL }; | |
| #endif | |
| #ifdef NUM_DEVS_CDP | |
| DIB cdp_dib = { CH_TYP_UREC, 1, 02, 0xF, &cdp_cmd, &cdp_ini }; | |
| #endif | |
| #ifdef NUM_DEVS_LPR | |
| DIB lpr_dib = { CH_TYP_UREC, 1, 03, 0xF, &lpr_cmd, &lpr_ini }; | |
| #endif | |
| #ifdef NUM_DEVS_CON | |
| DIB con_dib = { CH_TYP_UREC, 1, 00, 0xF, &con_cmd, &con_ini }; | |
| #endif | |
| DIB mt_dib = { CH_TYP_76XX, NUM_UNITS_MT, 0000, 0000, &mt_cmd, &mt_ini }; | |
| #ifdef NUM_DEVS_CHRON | |
| DIB chron_dib = { CH_TYP_76XX, 1, 0000, 0000, &chron_cmd, NULL }; | |
| #endif | |
| #ifdef NUM_DEVS_DSK | |
| DIB dsk_dib = { CH_TYP_79XX, 0, 0, 0, &dsk_cmd, &dsk_ini }; | |
| #endif | |
| #ifdef NUM_DEVS_HT | |
| DIB ht_dib = { CH_TYP_79XX, NUM_UNITS_HT, 0, 0, &ht_cmd, NULL }; | |
| #endif | |
| #ifdef NUM_DEVS_COM | |
| DIB com_dib = { CH_TYP_79XX, 0, 0, 0, &com_cmd, NULL }; | |
| #endif | |
| /* Simulator stop codes */ | |
| const char *sim_stop_messages[] = { | |
| "Unknown error", | |
| "IO device not ready", | |
| "HALT instruction", | |
| "Breakpoint", | |
| "Unknown Opcode", | |
| "", | |
| "", | |
| "I/O Check error", | |
| "", | |
| "7750 invalid line number", | |
| "7750 invalid message", | |
| "7750 No free output buffers", | |
| "7750 No free input buffers", | |
| "Field overflow", | |
| "Sign change", | |
| "Divide error", | |
| "Alpha index word", | |
| "Error?", "Error2", 0 | |
| }; | |
| /* Simulator debug controls */ | |
| DEBTAB dev_debug[] = { | |
| {"CHANNEL", DEBUG_CHAN}, | |
| {"TRAP", DEBUG_TRAP}, | |
| {"CMD", DEBUG_CMD}, | |
| {"DATA", DEBUG_DATA}, | |
| {"DETAIL", DEBUG_DETAIL}, | |
| {"EXP", DEBUG_EXP}, | |
| {"SENSE", DEBUG_SNS}, | |
| {0, 0} | |
| }; | |
| DEBTAB crd_debug[] = { | |
| {"CHAN", DEBUG_CHAN}, | |
| {"CMD", DEBUG_CMD}, | |
| {"DATA", DEBUG_DATA}, | |
| {"DETAIL", DEBUG_DETAIL}, | |
| {"EXP", DEBUG_EXP}, | |
| {"CARD", DEBUG_CARD}, | |
| {0, 0} | |
| }; | |
| const char mem_to_ascii[64] = { | |
| ' ', '1', '2', '3', '4', '5', '6', '7', | |
| '8', '9', '0', '=', '\'', ':', '>', 's', | |
| 'b', '/', 'S', 'T', 'U', 'V', 'W', 'X', | |
| 'Y', 'Z', 'x', ',', '(', '~', '\\', '_', | |
| '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', | |
| 'Q', 'R', '!', '$', '*', ']', ';', '^', | |
| '+', 'A', 'B', 'C', 'D', 'E', 'F', 'G', | |
| 'H', 'I', '?', '.', ')', '[', '<', '|', | |
| /*Sq*/ /*RM*/ | |
| }; | |
| char mem_ascii[256] = { | |
| /* 00 */ ' ', '~', '~', '~', '~', '~', '~', '~', | |
| /* */ | |
| /* 08 */ '~', '~', '~', '~', '~', '~', '~', '~', | |
| /* . sq ? */ | |
| /* 10 */ '~', '~', '~', '~', '~', '.', '[', '?', | |
| /* \ # */ | |
| /* 18 */ '\\', '#', '|', '~', '~', '~', '~', '~', | |
| /*+/- $ * ? */ | |
| /* 20 */ '+', '~', '~', '~', '~', '$', '*', '?', | |
| /* ? +/- */ | |
| /* 28 */ '?', '-', '~', '~', '~', '~', '~', '~', | |
| /* - / , %/( ? */ | |
| /* 30 */ '-', '/', '~', '~', '~', ',', '%', '?', | |
| /* ? sm */ | |
| /* 38 */ '?', 's', '~', '~', '~', '~', '~', '~', | |
| /* =/# !/@ ? */ | |
| /* 40 */ '~', '~', '~', '~', '~', '=', '!', '?', | |
| /* ? tm */ | |
| /* 48 */ '?', 't', '~', '~', '~', '~', '~', '~', | |
| /* */ | |
| /* 50 */ '~', '~', '~', '~', '~', '~', '~', '~', | |
| /* */ | |
| /* 58 */ '~', '~', '~', '~', '~', '~', '~', '~', | |
| /* +0 A B C D E F G */ | |
| /* 60 */ '^', 'A', 'B', 'C', 'D', 'E', 'F', 'G', | |
| /* H I */ | |
| /* 68 */ 'H', 'I', '~', '~', '~', '~', '~', '~', | |
| /* -0 J K L M N O P */ | |
| /* 70 */ '_', 'J', 'K', 'L', 'M', 'N', 'O', 'P', | |
| /* Q R */ | |
| /* 78 */ 'Q', 'R', '~', '~', '~', '~', '~', '~', | |
| /* rm S T U V W X */ | |
| /* 80 */ 'r', '~', 'S', 'T', 'U', 'V', 'W', 'X', | |
| /* Y Z */ | |
| /* 88 */ 'Y', 'Z', '~', '~', '~', '~', '~', '~', | |
| /* 0 1 2 3 4 5 6 7 */ | |
| /* 90 */ '0', '1', '2', '3', '4', '5', '6', '7', | |
| /* 8 9 */ | |
| /* 98 */ '8', '9', '~', '~', '~', '~', '~', '~' | |
| }; | |
| /* Load a card image file into memory. */ | |
| t_stat | |
| sim_load(FILE * fileref, CONST char *cptr, CONST char *fnam, int flag) | |
| { | |
| /* Currently not implimented until I know format of load files */ | |
| return SCPE_NOFNC; | |
| } | |
| /* Symbol tables */ | |
| typedef struct _opcode | |
| { | |
| uint16 opbase; | |
| const char *name; | |
| uint8 type; | |
| } | |
| t_opcode; | |
| #define TYPE_A 0 /* Basic oo ii ff aaaa */ | |
| #define TYPE_S 1 /* Shift control */ | |
| #define TYPE_B 2 /* Basic oo ii xx aaaa */ | |
| #define TYPE_C 3 /* Alternate switch */ | |
| #define TYPE_D 4 /* Electronic switch */ | |
| #define TYPE_E 5 /* Extended memory */ | |
| #define TYPE_F 6 /* Branch type 2 */ | |
| #define TYPE_Z 8 /* Sign control */ | |
| #define TYPE_I 9 /* Basic oo ii II aaaa */ | |
| #define TYPE_X 10 /* No extra values */ | |
| #define TYPE_T 11 /* Tape control */ | |
| #define TYPE_U 12 /* unit record control */ | |
| #define TYPE_V 13 /* Channel IO */ | |
| #define TYPE_G 14 /* Diag SW */ | |
| #define TYPE_P1 15 /* Branch priority */ | |
| #define TYPE_P2 16 /* Set Priority latch */ | |
| #define TYPE_P3 17 /* Clear Priority latch */ | |
| #define TYPE_IQ 18 /* Inquiry instruction */ | |
| #define TYPE_TB 19 /* Binary Tape operations */ | |
| /* Opcodes */ | |
| t_opcode base_ops[] = { | |
| {OP_HB, "HB", TYPE_B}, | |
| {OP_B, "B", TYPE_B}, | |
| {OP_BLX, "BLX", TYPE_I}, | |
| {OP_CD, "CD", TYPE_A}, | |
| {OP_EXMEM, "EXMEM", TYPE_E}, | |
| {OP_DIAGC, "DIAGC", TYPE_I}, | |
| {OP_DIAGT, "DIAGT", TYPE_I}, | |
| {OP_DIAGR, "DIAGR", TYPE_I}, | |
| {OP_DIAGS, "DIAGS", TYPE_I}, | |
| {OP_BZ1, "BZ1", TYPE_B}, | |
| {OP_BV1, "BV1", TYPE_B}, | |
| {OP_ST1, "ST1", TYPE_A}, | |
| {OP_ZA1, "ZA1", TYPE_A}, | |
| {OP_A1, "A1", TYPE_A}, | |
| {OP_C1, "C1", TYPE_A}, | |
| {OP_ZAA, "ZAA", TYPE_A}, | |
| {OP_AA, "AA", TYPE_A}, | |
| {OP_AAS1, "AAS1", TYPE_A}, | |
| {OP_AS1, "AS1", TYPE_A}, | |
| {OP_BZ2, "BZ2", TYPE_B}, | |
| {OP_BV2, "BV2", TYPE_B}, | |
| {OP_ST2, "ST2", TYPE_A}, | |
| {OP_ZA2, "ZA2", TYPE_A}, | |
| {OP_A2, "A2", TYPE_A}, | |
| {OP_C2, "C2", TYPE_A}, | |
| {OP_AS2, "AS2", TYPE_A}, | |
| {OP_AAS2, "AAS2", TYPE_A}, | |
| {OP_BZ3, "BZ3", TYPE_B}, | |
| {OP_BV3, "BV3", TYPE_B}, | |
| {OP_ST3, "ST3", TYPE_A}, | |
| {OP_ZA3, "ZA3", TYPE_A}, | |
| {OP_A3, "A3", TYPE_A}, | |
| {OP_C3, "C3", TYPE_A}, | |
| {OP_AS3, "AS3", TYPE_A}, | |
| {OP_AAS3, "AAS3", TYPE_A}, | |
| {OP_BL, "BL", TYPE_B}, | |
| {OP_BFLD, "BFLD", TYPE_F}, | |
| {OP_BXN, "BXN", TYPE_I}, | |
| {OP_XL , "XL ", TYPE_I}, | |
| {OP_XZA, "XZA", TYPE_I}, | |
| {OP_XA, "XA", TYPE_I}, | |
| {OP_XSN, "XSN", TYPE_I}, | |
| {OP_BIX, "BIX", TYPE_I}, | |
| {OP_SC, "SC", TYPE_S}, | |
| {OP_INQ, "INQ", TYPE_IQ}, | |
| {OP_BSWITCH, "BSWITCH", TYPE_C}, | |
| {OP_M, "M", TYPE_A}, | |
| {OP_PC, "PC", TYPE_I}, | |
| {OP_ENA, "ENA", TYPE_I}, | |
| {OP_ENB, "ENB", TYPE_I}, | |
| {OP_PRTST, "PRTST", TYPE_P1}, | |
| {OP_BSW21, "BES", TYPE_D}, | |
| {OP_BSW22, "BES", TYPE_D}, | |
| {OP_BSW23, "BES", TYPE_D}, | |
| {OP_PR, "PR", TYPE_B}, | |
| {OP_RS, "RS", TYPE_I}, | |
| {OP_LL, "LL", TYPE_A}, | |
| {OP_LE, "LE", TYPE_A}, | |
| {OP_LEH, "LEH", TYPE_A}, | |
| {OP_UREC, "UREC", TYPE_U}, | |
| {OP_FBV, "FBV", TYPE_B}, | |
| {OP_FR, "FR", TYPE_X}, | |
| {OP_FM, "FM", TYPE_B}, | |
| {OP_FA, "FA", TYPE_B}, | |
| {OP_FZA, "FZA", TYPE_B}, | |
| {OP_FAD, "FAD", TYPE_B}, | |
| {OP_FAA, "FAA", TYPE_B}, | |
| {OP_HP, "HP", TYPE_X}, | |
| {OP_NOP, "NOP", TYPE_X}, | |
| {OP_CS, "CS", TYPE_Z}, | |
| {OP_BM1, "BM1", TYPE_B}, | |
| {OP_ZST1, "ZST1", TYPE_A}, | |
| {OP_STD1, "STD1", TYPE_A}, | |
| {OP_ZS1, "ZS1", TYPE_A}, | |
| {OP_S1, "S1", TYPE_A}, | |
| {OP_CA, "CA", TYPE_A}, | |
| {OP_ZSA, "ZSA", TYPE_A}, | |
| {OP_SA, "SA", TYPE_A}, | |
| {OP_SS1, "SS1", TYPE_A}, | |
| {OP_BM2, "BM2", TYPE_B}, | |
| {OP_ZST2, "ZST2", TYPE_A}, | |
| {OP_STD2, "STD2", TYPE_A}, | |
| {OP_ZS2, "ZS2", TYPE_A}, | |
| {OP_S2, "S2", TYPE_A}, | |
| {OP_SS2, "SS2", TYPE_A}, | |
| {OP_BM3, "BM3", TYPE_B}, | |
| {OP_ZST3, "ZST3", TYPE_A}, | |
| {OP_STD3, "STD3", TYPE_A}, | |
| {OP_ZS3, "ZS3", TYPE_A}, | |
| {OP_S3, "S3", TYPE_A}, | |
| {OP_SS3, "SS3", TYPE_A}, | |
| {OP_BH, "BH", TYPE_B}, | |
| {OP_BE, "BE", TYPE_B}, | |
| {OP_BCX, "BCX", TYPE_I}, | |
| {OP_BXM, "BXM", TYPE_I}, | |
| {OP_XU, "XU", TYPE_I}, | |
| {OP_XZS, "XZS", TYPE_I}, | |
| {OP_XS, "XS", TYPE_I}, | |
| {OP_XLIN, "XLIN", TYPE_I}, | |
| {OP_BDX, "BDX", TYPE_I}, | |
| {OP_CSC, "CSC", TYPE_S}, | |
| {OP_D, "D", TYPE_A}, | |
| {OP_ENS, "ENS", TYPE_I}, | |
| {OP_EAN, "EAN", TYPE_I}, | |
| {OP_PRION, "DCAN", TYPE_P2}, | |
| {OP_PRIOF, "DCAF", TYPE_P3}, | |
| {OP_RG, "RG", TYPE_I}, | |
| {OP_FBU, "FBU", TYPE_B}, | |
| {OP_FD, "FD", TYPE_B}, | |
| {OP_FS, "FS", TYPE_B}, | |
| {OP_FDD, "FDD", TYPE_B}, | |
| {OP_FADS, "FADS", TYPE_B}, | |
| {OP_FSA, "FSA", TYPE_B}, | |
| {OP_TRN, "TRN", TYPE_TB}, | |
| {OP_TRNP, "PTRN", TYPE_TB}, | |
| {OP_TAP1, "", TYPE_T}, | |
| {OP_TAP2, "", TYPE_T}, | |
| {OP_TAP3, "", TYPE_T}, | |
| {OP_TAP4, "", TYPE_T}, | |
| {OP_TAPP1, "P", TYPE_T}, | |
| {OP_TAPP2, "P", TYPE_T}, | |
| {OP_TAPP3, "P", TYPE_T}, | |
| {OP_TAPP4, "P", TYPE_T}, | |
| {OP_CHN1, "", TYPE_V}, | |
| {OP_CHN2, "", TYPE_V}, | |
| {OP_CHN3, "", TYPE_V}, | |
| {OP_CHN4, "", TYPE_V}, | |
| {OP_CHNP1, "P", TYPE_V}, | |
| {OP_CHNP2, "P", TYPE_V}, | |
| {OP_CHNP3, "P", TYPE_V}, | |
| {OP_CHNP4, "P", TYPE_V}, | |
| {0, NULL, 0}, | |
| }; | |
| t_opcode sub_ops[] = { | |
| {0, "SR", TYPE_S}, | |
| {1, "SRR", TYPE_S}, | |
| {2, "SL", TYPE_S}, | |
| {3, "SLC", TYPE_S}, | |
| {4, "SRS", TYPE_S}, | |
| {5, "SLS", TYPE_S}, | |
| {6, "SRS", TYPE_S}, | |
| {7, "SLS", TYPE_S}, | |
| {0, "BAS", TYPE_C}, | |
| {1, "BCB", TYPE_C}, | |
| {2, "BDCB", TYPE_C}, | |
| {0, "BES", TYPE_D}, | |
| {1, "ESN", TYPE_D}, | |
| {2, "ESF", TYPE_D}, | |
| {3, "BSN", TYPE_D}, | |
| {4, "BSF", TYPE_D}, | |
| {0x00, "BAL", TYPE_P1}, | |
| {0x01, "BUL", TYPE_P1}, | |
| {0x02, "BUL", TYPE_P1}, | |
| {0x03, "BQL", TYPE_P1}, | |
| {0x04, "BQL", TYPE_P1}, | |
| {0x10, "BTL", TYPE_P1}, | |
| {0x20, "BTL", TYPE_P1}, | |
| {0x30, "BTL", TYPE_P1}, | |
| {0x40, "BTL", TYPE_P1}, | |
| {0x80, "BDCL", TYPE_P1}, | |
| {0x90, "BDCA", TYPE_P1}, | |
| {0x01, "ULN", TYPE_P2}, | |
| {0x02, "ULN", TYPE_P2}, | |
| {0x03, "QLN", TYPE_P2}, | |
| {0x04, "QLN", TYPE_P2}, | |
| {0x10, "TLN", TYPE_P2}, | |
| {0x20, "TLN", TYPE_P2}, | |
| {0x30, "TLN", TYPE_P2}, | |
| {0x40, "TLN", TYPE_P2}, | |
| {0x80, "BDLN", TYPE_P2}, | |
| {0x90, "BDAN", TYPE_P2}, | |
| {0x01, "ULF", TYPE_P3}, | |
| {0x02, "ULF", TYPE_P3}, | |
| {0x03, "QLF", TYPE_P3}, | |
| {0x04, "QLF", TYPE_P3}, | |
| {0x10, "TLF", TYPE_P3}, | |
| {0x20, "TLF", TYPE_P3}, | |
| {0x30, "TLF", TYPE_P3}, | |
| {0x40, "TLF", TYPE_P3}, | |
| {0x80, "BDLF", TYPE_P3}, | |
| {0x90, "BDAF", TYPE_P3}, | |
| {0, "BASS", TYPE_E}, | |
| {1, "ASSN", TYPE_E}, | |
| {2, "ASSF", TYPE_E}, | |
| {0, "BFV", TYPE_F}, | |
| {1, "SMFV", TYPE_F}, | |
| {2, "HMFV", TYPE_F}, | |
| {0x30, "CSA", TYPE_Z}, | |
| {0x60, "CSM", TYPE_Z}, | |
| {0x90, "CSP", TYPE_Z}, | |
| {0x31, "MSA", TYPE_Z}, | |
| {0x61, "MSM", TYPE_Z}, | |
| {0x91, "MSP", TYPE_Z}, | |
| {2, "SMSC", TYPE_Z}, | |
| {3, "HMSC", TYPE_Z}, | |
| {4, "BSC", TYPE_Z}, | |
| {0x10, "TR", TYPE_T}, | |
| {0x20, "TRR", TYPE_T}, | |
| {0x30, "TW", TYPE_T}, | |
| {0x40, "TWR", TYPE_T}, | |
| {0x50, "TWZ", TYPE_T}, | |
| {0x60, "TWC", TYPE_T}, | |
| {0x70, "TSF", TYPE_T}, | |
| {0x80, "TSB", TYPE_T}, | |
| {0x90, "TRA", TYPE_T}, | |
| {0x00, "TSEL", TYPE_T}, | |
| {0x01, "TM", TYPE_T}, | |
| {0x02, "TRW", TYPE_T}, | |
| {0x03, "TRU", TYPE_T}, | |
| {0x04, "TRB", TYPE_T}, | |
| {0x05, "TSM", TYPE_T}, | |
| {0x06, "TSK", TYPE_T}, | |
| {0x07, "TEF", TYPE_T}, | |
| {0x08, "TSLD", TYPE_T}, | |
| {0x09, "TSHD", TYPE_T}, | |
| {0, "US", TYPE_U}, | |
| {1, "UR", TYPE_U}, | |
| {2, "UW", TYPE_U}, | |
| {3, "UWIV", TYPE_U}, | |
| {4, "TYP", TYPE_U}, | |
| {1, "DCP", TYPE_V}, | |
| {2, "DCUA", TYPE_V}, | |
| {3, "DCUR", TYPE_V}, | |
| {4, "DCPR", TYPE_V}, | |
| {6, "DCU", TYPE_V}, | |
| {0, "QR", TYPE_IQ}, | |
| {1, "QW", TYPE_IQ}, | |
| {0, NULL, 0}, | |
| }; | |
| const char *chname[11] = { | |
| "*", "1", "2", "3", "4", "A", "B", "C", "D" | |
| }; | |
| /* Print out an instruction */ | |
| void | |
| print_opcode(FILE * of, t_value val, t_opcode * tab) | |
| { | |
| uint32 MA; | |
| uint8 f1; | |
| uint8 f2; | |
| uint8 IX; | |
| uint16 op; | |
| int type; | |
| int t; | |
| MA = AMASK & val; | |
| f1 = (val >> 16) & 0xf; | |
| f2 = (val >> 20) & 0xf; | |
| IX = (val >> 24) & 0xff; | |
| op = (val >> 32) & 0xff; | |
| if ((val & SMASK) == MSIGN) | |
| op |= 0x100; | |
| while (tab->name != NULL) { | |
| if (tab->opbase == op) { | |
| switch (type = tab->type) { | |
| case TYPE_X: | |
| fputs(tab->name, of); | |
| return; | |
| case TYPE_A: | |
| fputs(tab->name, of); | |
| fputc(' ', of); | |
| fprint_val(of, MA, 16, 16, PV_RZRO); | |
| if (IX != 0) { | |
| fputs("+X", of); | |
| fprint_val(of, IX, 16, 8, 0); | |
| } | |
| if (f1 != 0 || f2 != 9) { | |
| fprintf(of, "(%d,%d)", f2, f1); | |
| } | |
| return; | |
| case TYPE_S: | |
| f1 = (MA >> 8) & 0xf; | |
| for(tab = sub_ops; tab->name != NULL; tab++) { | |
| if (tab->type == type && tab->opbase == f1) | |
| break; | |
| } | |
| if (tab->name == NULL) | |
| break; | |
| fputs(tab->name, of); | |
| if (op == OP_SC) | |
| fputc('0' + ((MA >> 12) & 0xf), of); | |
| fputc(' ', of); | |
| fprint_val(of, MA & 0xff, 16, 8, PV_RZRO); | |
| if (IX != 0) { | |
| fputs("+X", of); | |
| fprint_val(of, IX, 16, 8, 0); | |
| } | |
| return; | |
| case TYPE_B: | |
| fputs(tab->name, of); | |
| fputc(' ', of); | |
| fprint_val(of, MA, 16, 16, PV_RZRO); | |
| if (IX != 0) { | |
| fputs("+X", of); | |
| fprint_val(of, IX, 16, 8, 0); | |
| } | |
| return; | |
| case TYPE_C: | |
| for(tab = sub_ops; tab->name != NULL; tab++) { | |
| if (tab->type == type && tab->opbase == f1) | |
| break; | |
| } | |
| if (tab->name == NULL) | |
| break; | |
| fputs(tab->name, of); | |
| fprintf(of, " %d,", f2); | |
| fprint_val(of, MA, 16, 16, PV_RZRO); | |
| if (IX != 0) { | |
| fputs("+X", of); | |
| fprint_val(of, IX, 16, 8, 0); | |
| } | |
| return; | |
| case TYPE_D: /* Electronic switch */ | |
| for(tab = sub_ops; tab->name != NULL; tab++) { | |
| if (tab->type == type && tab->opbase == f2) | |
| break; | |
| } | |
| if (tab->name == NULL) | |
| break; | |
| fputs(tab->name, of); | |
| fputc(' ', of); | |
| fputc('0' + (op & 0xf), of); | |
| fputc('0' + f1, of); | |
| fputc(',', of); | |
| fprint_val(of, MA, 16, 16, PV_RZRO); | |
| if (IX != 0) { | |
| fputs("+X", of); | |
| fprint_val(of, IX, 16, 8, 0); | |
| } | |
| return; | |
| case TYPE_E: /* Extended memory */ | |
| for(tab = sub_ops; tab->name != NULL; tab++) { | |
| if (tab->type == type && tab->opbase == f1) | |
| break; | |
| } | |
| if (tab->name == NULL) | |
| break; | |
| fputs(tab->name, of); | |
| if (f1 == 0) { | |
| fputc(' ', of); | |
| fprint_val(of, MA, 16, 16, PV_RZRO); | |
| if (IX != 0) { | |
| fputs("+X", of); | |
| fprint_val(of, IX, 16, 8, 0); | |
| } | |
| } | |
| return; | |
| case TYPE_F: /* Branch type 2 */ | |
| for(tab = sub_ops; tab->name != NULL; tab++) { | |
| if (tab->type == type && tab->opbase == f2) | |
| break; | |
| } | |
| if (tab->name == NULL) | |
| break; | |
| fputs(tab->name, of); | |
| if (f2 == 0) { | |
| fputc(' ', of); | |
| fprint_val(of, MA, 16, 16, PV_RZRO); | |
| if (IX != 0) { | |
| fputs("+X", of); | |
| fprint_val(of, IX, 16, 8, 0); | |
| } | |
| } | |
| return; | |
| case TYPE_Z: /* Sign control */ | |
| f1 |= f2 << 4; | |
| for(tab = sub_ops; tab->name != NULL; tab++) { | |
| if (tab->type == type && tab->opbase == f1) | |
| break; | |
| } | |
| if (tab->name == NULL) | |
| break; | |
| fputs(tab->name, of); | |
| fputc(' ', of); | |
| fprint_val(of, MA, 16, 16, PV_RZRO); | |
| if (IX != 0) { | |
| fputs("+X", of); | |
| fprint_val(of, IX, 16, 8, 0); | |
| } | |
| return; | |
| case TYPE_TB: /* Binary Tape operation. */ | |
| fprintf(of, "%s %d,", tab->name, f2); | |
| fprint_val(of, MA, 16, 16, PV_RZRO); | |
| if (IX != 0) { | |
| fputs("+X", of); | |
| fprint_val(of, IX, 16, 8, 0); | |
| } | |
| return; | |
| case TYPE_I: /* Indexed operand */ | |
| fprintf(of, "%s %d%d,", tab->name, f2, f1); | |
| fprint_val(of, MA, 16, 16, PV_RZRO); | |
| if (IX != 0) { | |
| fputs("+X", of); | |
| fprint_val(of, IX, 16, 8, 0); | |
| } | |
| return; | |
| case TYPE_T: /* Tape Control */ | |
| f1 <<= 4; | |
| if (f1 == 0) | |
| f1 += MA & 0xf; | |
| fputs(tab->name, of); | |
| for(tab = sub_ops; tab->name != NULL; tab++) { | |
| if (tab->type == type && tab->opbase == f1) | |
| break; | |
| } | |
| if (tab->name == NULL) | |
| break; | |
| fputs(tab->name, of); | |
| fputc(' ', of); | |
| fputc('0' + (op & 0xf), of); | |
| fputc('0' + f2, of); | |
| fputc(',', of); | |
| fprint_val(of, MA, 16, 16, PV_RZRO); | |
| if (IX != 0) { | |
| fputs("+X", of); | |
| fprint_val(of, IX, 16, 8, 0); | |
| } | |
| return; | |
| case TYPE_U: /* Unit Record Control */ | |
| for(tab = sub_ops; tab->name != NULL; tab++) { | |
| if (tab->type == type && tab->opbase == f2) | |
| break; | |
| } | |
| if (tab->name == NULL) | |
| break; | |
| fputs(tab->name, of); | |
| fputc(' ', of); | |
| fputc('0' + f1, of); | |
| fputc(',', of); | |
| fprint_val(of, MA, 16, 16, PV_RZRO); | |
| if (IX != 0) { | |
| fputs("+X", of); | |
| fprint_val(of, IX, 16, 8, 0); | |
| } | |
| return; | |
| case TYPE_V: /* Channel Control */ | |
| fputs(tab->name, of); | |
| for(tab = sub_ops; tab->name != NULL; tab++) { | |
| if (tab->type == type && tab->opbase == f1) | |
| break; | |
| } | |
| if (tab->name == NULL) | |
| break; | |
| fputs(tab->name, of); | |
| fputc(' ', of); | |
| fputc('0' + (op & 0xf), of); | |
| fputc(',', of); | |
| fputc('0' + f2, of); | |
| fputc(',', of); | |
| fprint_val(of, MA, 16, 16, PV_RZRO); | |
| if (IX != 0) { | |
| fputs("+X", of); | |
| fprint_val(of, IX, 16, 8, 0); | |
| } | |
| return; | |
| case TYPE_P1: /* Priority Control */ | |
| case TYPE_P2: | |
| case TYPE_P3: | |
| if (f2 == 0) | |
| t = f1; | |
| else | |
| t = f2 << 4; | |
| for(tab = sub_ops; tab->name != NULL; tab++) { | |
| if (tab->type == type && tab->opbase == t) | |
| break; | |
| } | |
| if (tab->name == NULL) { | |
| /* Not found, decode */ | |
| for(tab = base_ops; tab->name != NULL; tab++) { | |
| if (tab->opbase == op) | |
| break; | |
| } | |
| } | |
| fputs(tab->name, of); | |
| fputc(' ', of); | |
| switch(f2) { | |
| case 4: | |
| case 3: | |
| case 2: fputc('0' + f2 - 1, of); | |
| case 1: | |
| case 8: | |
| case 9: | |
| case 0: fputc('0' + f1, of); | |
| break; | |
| } | |
| fputc(',', of); | |
| fprint_val(of, MA, 16, 16, PV_RZRO); | |
| if (IX != 0) { | |
| fputs("+X", of); | |
| fprint_val(of, IX, 16, 8, 0); | |
| } | |
| return; | |
| case TYPE_IQ: | |
| for(tab = sub_ops; tab->name != NULL; tab++) { | |
| if (tab->type == type && tab->opbase == f2) | |
| break; | |
| } | |
| if (tab->name == NULL) | |
| break; | |
| fprintf(of, "%s %d,", tab->name, f2); | |
| fprint_val(of, MA, 16, 16, PV_RZRO); | |
| if (IX != 0) { | |
| fputs("+X", of); | |
| fprint_val(of, IX, 16, 8, 0); | |
| } | |
| return; | |
| default: | |
| return; | |
| } | |
| } | |
| tab++; | |
| } | |
| fprintf(of, " %d Unknown opcode", op); | |
| } | |
| /* Symbolic decode | |
| Inputs: | |
| *of = output stream | |
| addr = current PC | |
| *val = pointer to values | |
| *uptr = pointer to unit | |
| sw = switches | |
| Outputs: | |
| return = status code | |
| */ | |
| t_stat | |
| fprint_sym(FILE * of, t_addr addr, t_value * val, UNIT * uptr, int32 sw) | |
| { | |
| t_uint64 inst = *val; | |
| /* Print value in decimal first */ | |
| fputc(' ', of); | |
| switch (inst & SMASK) { | |
| case PSIGN: fputc('+', of); break; | |
| case MSIGN: fputc('-', of); break; | |
| case ASIGN: fputc('@', of); break; | |
| default: fputc('#', of); break; | |
| } | |
| fprint_val(of, inst & DMASK, 16, 40, PV_RZRO); | |
| if (sw & SWMASK('M')) { | |
| fputs(" ", of); | |
| print_opcode(of, inst, base_ops); | |
| } | |
| if (sw & SWMASK('C')) { | |
| int i; | |
| fputs(" '", of); | |
| for (i = 4; i >= 0; i--) { | |
| int ch; | |
| ch = (int)(inst >> (8 * i)) & 0xff; | |
| fputc(mem_ascii[ch], of); | |
| } | |
| fputc('\'', of); | |
| } | |
| return SCPE_OK; | |
| } | |
| t_opcode * | |
| find_opcode(char *op, t_opcode * tab) | |
| { | |
| while (tab->name != NULL) { | |
| if (*tab->name != '\0' && strcmp(op, tab->name) == 0) | |
| return tab; | |
| tab++; | |
| } | |
| return NULL; | |
| } | |
| /* Symbolic input | |
| Inputs: | |
| *cptr = pointer to input string | |
| addr = current PC | |
| uptr = pointer to unit | |
| *val = pointer to output values | |
| sw = switches | |
| Outputs: | |
| status = error status | |
| */ | |
| t_stat | |
| parse_sym(CONST char *cptr, t_addr addr, UNIT * uptr, t_value * val, int32 sw) | |
| { | |
| int i; | |
| int idx; | |
| t_value a, opr, d; | |
| int sign; | |
| char opcode[100]; | |
| while (isspace(*cptr)) | |
| cptr++; | |
| d = 0; | |
| if (sw & SWMASK('M')) { | |
| t_opcode *op, *op2; | |
| i = 0; | |
| sign = 0; | |
| /* Grab opcode */ | |
| cptr = get_glyph(cptr, opcode, 0); | |
| op2 = 0; | |
| if((op = find_opcode(opcode, base_ops)) == 0) { | |
| if ((op2 = find_opcode(opcode, sub_ops)) != 0) { | |
| for(op = base_ops; (op->type != op2->type) && | |
| (op->name != NULL); op++); | |
| if (op->name == NULL) | |
| return STOP_UUO; | |
| } else if (opcode[0] == 'P' && | |
| (op2 = find_opcode(&opcode[1], sub_ops)) != 0) { | |
| for(op = base_ops; (op->type != op2->type) && | |
| (op->name != NULL) && op->name[0] == 'P'; op++); | |
| if (op->name == NULL) | |
| return STOP_UUO; | |
| } | |
| } | |
| if (op == 0) | |
| return STOP_UUO; | |
| d = (((t_uint64)op->opbase) << 32) & DMASK; | |
| d |= (op->opbase & 0x100)? MSIGN:PSIGN; | |
| if (op->type == TYPE_X) { | |
| *val = d; | |
| return SCPE_OK; | |
| } | |
| if (op2 != 0 && op2->opbase != 0 && op->type == TYPE_E) { | |
| d |= ((t_uint64)op2->opbase) << 24; | |
| *val = d; | |
| return SCPE_OK; | |
| } | |
| if (op2 != 0 && op2->opbase != 0 && op->type == TYPE_F) { | |
| d |= ((t_uint64)op2->opbase) << 28; | |
| *val = d; | |
| return SCPE_OK; | |
| } | |
| a = 0; | |
| idx = 0; | |
| opr = 0; | |
| while (*cptr == ' ' || *cptr == '\t') | |
| cptr++; | |
| /* Collect first argument if there is one */ | |
| while (*cptr >= '0' && *cptr <= '9') | |
| opr = (opr << 4) + (*cptr++ - '0'); | |
| /* Skip blanks */ | |
| while (*cptr == ' ' || *cptr == '\t') | |
| cptr++; | |
| /* Type A opc addr+X#(n,m) */ | |
| /* Type B opc addr+X# */ | |
| /* Type S opcA addr+X# f1 = op */ | |
| /* Type C opc addr+X#,f2 f1 = op */ | |
| /* Type D opc opf2,addr+X */ | |
| /* Type E opc *addr+X# f1 = op */ | |
| /* Type F opc *addr+X# f2 = op*/ | |
| /* Type Z opc addr+X# f1 = op */ | |
| /* Type I opc f2f1,addr+X# */ | |
| /* Type T opc opf2,addr+X# f1 = op */ | |
| /* Type U opc f1,addr+X# f2 = op */ | |
| /* Type V opc opf1,addr+X# f2 = op */ | |
| /* End of opcode, give to address */ | |
| if (*cptr == '\0' || *cptr == '(') { | |
| a = opr; | |
| opr = 0; | |
| } | |
| /* If plus, then must be address and follow by index */ | |
| if (*cptr == '+') { | |
| a = opr; | |
| opr = 0; | |
| cptr++; | |
| /* Skip blanks */ | |
| while (*cptr == ' ' || *cptr == '\t') | |
| cptr++; | |
| if (*cptr != 'x' && *cptr != 'X') | |
| return STOP_UUO; | |
| cptr++; | |
| while (*cptr >= '0' && *cptr <= '9') | |
| idx = (idx << 4) + (*cptr++ - '0'); | |
| if (idx >= 0x100) | |
| return STOP_UUO; | |
| } | |
| /* Comma, first was operand, now get address */ | |
| if (*cptr == ',') { | |
| a = 0; | |
| cptr++; | |
| /* Skip blanks */ | |
| while (*cptr == ' ' || *cptr == '\t') | |
| cptr++; | |
| /* Collect second argument if there is one */ | |
| while (*cptr >= '0' && *cptr <= '9') | |
| a = (a << 4) + (*cptr++ - '0'); | |
| /* Skip blanks */ | |
| while (*cptr == ' ' || *cptr == '\t') | |
| cptr++; | |
| if (*cptr == '+') { | |
| cptr++; | |
| /* Skip blanks */ | |
| while (*cptr == ' ' || *cptr == '\t') | |
| cptr++; | |
| if (*cptr != 'x' && *cptr != 'X') | |
| return STOP_UUO; | |
| cptr++; | |
| while (*cptr >= '0' && *cptr <= '9') | |
| idx = (idx << 4) + (*cptr++ - '0'); | |
| if (idx >= 0x100) | |
| return STOP_UUO; | |
| } | |
| } | |
| /* If we get a (, then grab field spec */ | |
| if (*cptr == '(') { | |
| if (op->type != TYPE_A) | |
| return STOP_UUO; | |
| cptr++; | |
| /* Skip blanks */ | |
| while (*cptr == ' ' || *cptr == '\t') | |
| cptr++; | |
| /* Collect second argument if there is one */ | |
| if (*cptr >= '0' && *cptr <= '9') | |
| opr = *cptr++ - '0'; | |
| else | |
| return STOP_UUO; | |
| while (*cptr == ' ' || *cptr == '\t') | |
| cptr++; | |
| if (*cptr == ',') { | |
| /* Skip blanks */ | |
| cptr++; | |
| while (*cptr == ' ' || *cptr == '\t') | |
| cptr++; | |
| /* Collect second argument if there is one */ | |
| if (*cptr >= '0' && *cptr <= '9') { | |
| opr <<= 4; | |
| opr |= *cptr++ - '0'; | |
| } else | |
| return STOP_UUO; | |
| } else if (*cptr == ')') | |
| opr |= opr << 4; | |
| /* Skip blanks */ | |
| while (*cptr == ' ' || *cptr == '\t') | |
| cptr++; | |
| if (*cptr++ != ')') | |
| return STOP_UUO; | |
| } else if (op->type == TYPE_A) | |
| opr = 0x09; | |
| /* Skip blanks */ | |
| while (*cptr == ' ' || *cptr == '\t') | |
| cptr++; | |
| if (*cptr != '\0') | |
| return STOP_UUO; | |
| d |= ((t_uint64)idx) << 24; | |
| d |= a; | |
| switch(op->type) { | |
| case TYPE_P1: | |
| case TYPE_P2: | |
| case TYPE_P3: | |
| if (op2 == NULL) | |
| d |= ((t_uint64)opr) << 16; | |
| else | |
| d |= ((t_uint64)(opr + op2->opbase)) << 16; | |
| break; | |
| case TYPE_A: | |
| d |= ((t_uint64)opr) << 16; | |
| break; | |
| case TYPE_E: | |
| case TYPE_F: | |
| case TYPE_B: | |
| break; | |
| case TYPE_S: | |
| case TYPE_D: | |
| case TYPE_V: | |
| d += ((t_uint64)opr &0xF0) << 28; | |
| d |= ((t_uint64)opr &0x0F) << 28; | |
| break; | |
| case TYPE_Z: | |
| d |= ((t_uint64)op2->opbase) << 16; | |
| break; | |
| case TYPE_TB: | |
| opr <<= 4; | |
| opr |= 1; | |
| /* Fall through */ | |
| case TYPE_I: | |
| d |= ((t_uint64)opr) << 16; | |
| break; | |
| case TYPE_T: | |
| if (op2->opbase & 0xf0) | |
| d |= ((t_uint64)op2->opbase &0xF0) << 12; | |
| else | |
| d |= op2->opbase; | |
| d |= ((t_uint64)opr & 0xF) << 16; | |
| d += ((t_uint64)opr &0xF0) << 28; | |
| break; | |
| case TYPE_U: | |
| case TYPE_C: | |
| d |= ((t_uint64)opr) << 20; | |
| d |= ((t_uint64)op2->opbase) << 16; | |
| /* Fall through */ | |
| case TYPE_IQ: | |
| d |= ((t_uint64)opr) << 20; | |
| break; | |
| } | |
| } else if (sw & SWMASK('C')) { | |
| extern uint8 bcd_mem[64]; | |
| i = 0; | |
| while (*cptr != '\0' && i < 5) { | |
| d <<= 8; | |
| if (sim_ascii_to_six[0177 & *cptr] != -1) | |
| d |= bcd_mem[(int)sim_ascii_to_six[0177 & *cptr]]; | |
| cptr++; | |
| i++; | |
| } | |
| d <<= 8 * (5 - i); | |
| d |= ASIGN; | |
| } else { | |
| switch(*cptr) { | |
| case '-': sign = -1; cptr++; break; | |
| case '@': sign = 1; cptr++; break; | |
| case '+': cptr++; | |
| /* Fall through */ | |
| default: | |
| sign = 0; | |
| } | |
| while (*cptr >= '0' && *cptr <= '9') { | |
| d <<= 4; | |
| d |= *cptr++ - '0'; | |
| } | |
| d &= DMASK; | |
| switch (sign) { | |
| case 1: d |= ASIGN; break; | |
| case 0: d |= PSIGN; break; | |
| case -1: d |= MSIGN; break; | |
| } | |
| } | |
| *val = d; | |
| return SCPE_OK; | |
| } |