| 1 | /* hp2100_sys.c: HP 2100 simulator interface\r |
| 2 | \r |
| 3 | Copyright (c) 1993-2008, Robert M. Supnik\r |
| 4 | \r |
| 5 | Permission is hereby granted, free of charge, to any person obtaining a\r |
| 6 | copy of this software and associated documentation files (the "Software"),\r |
| 7 | to deal in the Software without restriction, including without limitation\r |
| 8 | the rights to use, copy, modify, merge, publish, distribute, sublicense,\r |
| 9 | and/or sell copies of the Software, and to permit persons to whom the\r |
| 10 | Software is furnished to do so, subject to the following conditions:\r |
| 11 | \r |
| 12 | The above copyright notice and this permission notice shall be included in\r |
| 13 | all copies or substantial portions of the Software.\r |
| 14 | \r |
| 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r |
| 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r |
| 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r |
| 18 | ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r |
| 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r |
| 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r |
| 21 | \r |
| 22 | Except as contained in this notice, the name of Robert M Supnik shall not be\r |
| 23 | used in advertising or otherwise to promote the sale, use or other dealings\r |
| 24 | in this Software without prior written authorization from Robert M Supnik.\r |
| 25 | \r |
| 26 | 24-Apr-08 JDB Changed fprint_sym to handle step with irq pending\r |
| 27 | 07-Dec-07 JDB Added BACI device\r |
| 28 | 27-Nov-07 JDB Added RTE OS/VMA/EMA mnemonics\r |
| 29 | 21-Dec-06 JDB Added "fwanxm" external for sim_load check\r |
| 30 | 19-Nov-04 JDB Added STOP_OFFLINE, STOP_PWROFF messages\r |
| 31 | 25-Sep-04 JDB Added memory protect device\r |
| 32 | Fixed display of CCA/CCB/CCE instructions\r |
| 33 | 01-Jun-04 RMS Added latent 13037 support\r |
| 34 | 19-Apr-04 RMS Recognize SFS x,C and SFC x,C\r |
| 35 | 22-Mar-02 RMS Revised for dynamically allocated memory\r |
| 36 | 14-Feb-02 RMS Added DMS instructions\r |
| 37 | 04-Feb-02 RMS Fixed bugs in alter/skip display and parsing\r |
| 38 | 01-Feb-02 RMS Added terminal multiplexor support\r |
| 39 | 16-Jan-02 RMS Added additional device support\r |
| 40 | 17-Sep-01 RMS Removed multiconsole support\r |
| 41 | 27-May-01 RMS Added multiconsole support\r |
| 42 | 14-Mar-01 RMS Revised load/dump interface (again)\r |
| 43 | 30-Oct-00 RMS Added examine to file support\r |
| 44 | 15-Oct-00 RMS Added dynamic device number support\r |
| 45 | 27-Oct-98 RMS V2.4 load interface\r |
| 46 | */\r |
| 47 | \r |
| 48 | #include "hp2100_defs.h"\r |
| 49 | #include "hp2100_cpu.h"\r |
| 50 | #include <ctype.h>\r |
| 51 | \r |
| 52 | extern DEVICE cpu_dev;\r |
| 53 | extern UNIT cpu_unit;\r |
| 54 | extern DEVICE mp_dev;\r |
| 55 | extern DEVICE dma0_dev, dma1_dev;\r |
| 56 | extern DEVICE ptr_dev, ptp_dev;\r |
| 57 | extern DEVICE tty_dev, clk_dev;\r |
| 58 | extern DEVICE lps_dev, lpt_dev;\r |
| 59 | extern DEVICE baci_dev;\r |
| 60 | extern DEVICE mtd_dev, mtc_dev;\r |
| 61 | extern DEVICE msd_dev, msc_dev;\r |
| 62 | extern DEVICE dpd_dev, dpc_dev;\r |
| 63 | extern DEVICE dqd_dev, dqc_dev;\r |
| 64 | extern DEVICE drd_dev, drc_dev;\r |
| 65 | extern DEVICE ds_dev;\r |
| 66 | extern DEVICE muxl_dev, muxu_dev, muxc_dev;\r |
| 67 | extern DEVICE ipli_dev, iplo_dev;\r |
| 68 | extern REG cpu_reg[];\r |
| 69 | extern uint16 *M;\r |
| 70 | extern uint32 fwanxm;\r |
| 71 | \r |
| 72 | /* SCP data structures and interface routines\r |
| 73 | \r |
| 74 | sim_name simulator name string\r |
| 75 | sim_PC pointer to saved PC register descriptor\r |
| 76 | sim_emax maximum number of words for examine/deposit\r |
| 77 | sim_devices array of pointers to simulated devices\r |
| 78 | sim_stop_messages array of pointers to stop messages\r |
| 79 | sim_load binary loader\r |
| 80 | */\r |
| 81 | \r |
| 82 | char sim_name[] = "HP 2100";\r |
| 83 | \r |
| 84 | char halt_msg[] = "HALT instruction xxxxxx";\r |
| 85 | \r |
| 86 | REG *sim_PC = &cpu_reg[0];\r |
| 87 | \r |
| 88 | int32 sim_emax = 3;\r |
| 89 | \r |
| 90 | DEVICE *sim_devices[] = {\r |
| 91 | &cpu_dev,\r |
| 92 | &mp_dev,\r |
| 93 | &dma0_dev,\r |
| 94 | &dma1_dev,\r |
| 95 | &ptr_dev,\r |
| 96 | &ptp_dev,\r |
| 97 | &tty_dev,\r |
| 98 | &clk_dev,\r |
| 99 | &lps_dev,\r |
| 100 | &lpt_dev,\r |
| 101 | &baci_dev,\r |
| 102 | &dpd_dev, &dpc_dev,\r |
| 103 | &dqd_dev, &dqc_dev,\r |
| 104 | &drd_dev, &drc_dev,\r |
| 105 | &ds_dev,\r |
| 106 | &mtd_dev, &mtc_dev,\r |
| 107 | &msd_dev, &msc_dev,\r |
| 108 | &muxl_dev, &muxu_dev, &muxc_dev,\r |
| 109 | &ipli_dev, &iplo_dev,\r |
| 110 | NULL\r |
| 111 | };\r |
| 112 | \r |
| 113 | const char *sim_stop_messages[] = {\r |
| 114 | "Unknown error",\r |
| 115 | "Unimplemented instruction",\r |
| 116 | "Non-existent I/O device",\r |
| 117 | halt_msg,\r |
| 118 | "Breakpoint",\r |
| 119 | "Indirect address loop",\r |
| 120 | "Indirect address interrupt (should not happen!)",\r |
| 121 | "No connection on interprocessor link",\r |
| 122 | "Device/unit offline",\r |
| 123 | "Device/unit powered off"\r |
| 124 | };\r |
| 125 | \r |
| 126 | /* Binary loader\r |
| 127 | \r |
| 128 | The binary loader consists of blocks preceded and trailed by zero frames.\r |
| 129 | A block consists of 16b words (punched big endian), as follows:\r |
| 130 | \r |
| 131 | count'xxx\r |
| 132 | origin\r |
| 133 | word 0\r |
| 134 | :\r |
| 135 | word count-1\r |
| 136 | checksum\r |
| 137 | \r |
| 138 | The checksum includes the origin but not the count.\r |
| 139 | */\r |
| 140 | \r |
| 141 | int32 fgetw (FILE *fileref)\r |
| 142 | {\r |
| 143 | int c1, c2;\r |
| 144 | \r |
| 145 | if ((c1 = fgetc (fileref)) == EOF) return -1;\r |
| 146 | if ((c2 = fgetc (fileref)) == EOF) return -1;\r |
| 147 | return ((c1 & 0377) << 8) | (c2 & 0377);\r |
| 148 | }\r |
| 149 | \r |
| 150 | t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)\r |
| 151 | {\r |
| 152 | int32 origin, csum, zerocnt, count, word, i;\r |
| 153 | \r |
| 154 | if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;\r |
| 155 | for (zerocnt = 1;; zerocnt = -10) { /* block loop */\r |
| 156 | for (;; zerocnt++) { /* skip 0's */\r |
| 157 | if ((count = fgetc (fileref)) == EOF) return SCPE_OK;\r |
| 158 | else if (count) break;\r |
| 159 | else if (zerocnt == 0) return SCPE_OK;\r |
| 160 | }\r |
| 161 | if (fgetc (fileref) == EOF) return SCPE_FMT;\r |
| 162 | if ((origin = fgetw (fileref)) < 0) return SCPE_FMT;\r |
| 163 | csum = origin; /* seed checksum */\r |
| 164 | for (i = 0; i < count; i++) { /* get data words */\r |
| 165 | if ((word = fgetw (fileref)) < 0) return SCPE_FMT;\r |
| 166 | if (MEM_ADDR_OK (origin)) M[origin] = word;\r |
| 167 | origin = origin + 1;\r |
| 168 | csum = csum + word;\r |
| 169 | }\r |
| 170 | if ((word = fgetw (fileref)) < 0) return SCPE_FMT;\r |
| 171 | if ((word ^ csum) & DMASK) return SCPE_CSUM;\r |
| 172 | }\r |
| 173 | }\r |
| 174 | \r |
| 175 | /* Symbol tables */\r |
| 176 | \r |
| 177 | #define I_V_FL 16 /* flag start */\r |
| 178 | #define I_M_FL 017 /* flag mask */\r |
| 179 | #define I_V_NPN 0 /* no operand */\r |
| 180 | #define I_V_NPC 1 /* no operand + C */\r |
| 181 | #define I_V_MRF 2 /* mem ref */\r |
| 182 | #define I_V_ASH 3 /* alter/skip, shift */\r |
| 183 | #define I_V_ESH 4 /* extended shift */\r |
| 184 | #define I_V_EMR 5 /* extended mem ref */\r |
| 185 | #define I_V_IO1 6 /* I/O + HC */\r |
| 186 | #define I_V_IO2 7 /* I/O only */\r |
| 187 | #define I_V_EGZ 010 /* ext grp, 1 op + 0 */\r |
| 188 | #define I_V_EG2 011 /* ext grp, 2 op */\r |
| 189 | #define I_V_ALT 012 /* alternate use instr */\r |
| 190 | #define I_NPN (I_V_NPN << I_V_FL)\r |
| 191 | #define I_NPC (I_V_NPC << I_V_FL)\r |
| 192 | #define I_MRF (I_V_MRF << I_V_FL)\r |
| 193 | #define I_ASH (I_V_ASH << I_V_FL)\r |
| 194 | #define I_ESH (I_V_ESH << I_V_FL)\r |
| 195 | #define I_EMR (I_V_EMR << I_V_FL)\r |
| 196 | #define I_IO1 (I_V_IO1 << I_V_FL)\r |
| 197 | #define I_IO2 (I_V_IO2 << I_V_FL)\r |
| 198 | #define I_EGZ (I_V_EGZ << I_V_FL)\r |
| 199 | #define I_EG2 (I_V_EG2 << I_V_FL)\r |
| 200 | #define I_ALT (I_V_ALT << I_V_FL)\r |
| 201 | \r |
| 202 | static const int32 masks[] = {\r |
| 203 | 0177777, 0176777, 0074000, 0170000,\r |
| 204 | 0177760, 0177777, 0176700, 0177700,\r |
| 205 | 0177777, 0177777, 0177777\r |
| 206 | };\r |
| 207 | \r |
| 208 | static const char *opcode[] = {\r |
| 209 | \r |
| 210 | /* These mnemonics are used by debug printouts, so put them first. */\r |
| 211 | \r |
| 212 | "$LIBR", "$LIBX", ".TICK", ".TNAM", /* RTE-6/VM OS firmware */\r |
| 213 | ".STIO", ".FNW", ".IRT", ".LLS", \r |
| 214 | ".SIP", ".YLD", ".CPM", ".ETEQ",\r |
| 215 | ".ENTN", "$OTST", ".ENTC", ".DSPI",\r |
| 216 | "$DCPC", "$MPV", "$DEV", "$TBG", /* alternates for dual-use */\r |
| 217 | \r |
| 218 | ".PMAP", "$LOC", "$VTST",/* --- */ /* RTE-6/VM VMA firmware */\r |
| 219 | /* --- --- --- --- */\r |
| 220 | ".IMAP", ".IMAR", ".JMAP", ".JMAR",\r |
| 221 | ".LPXR", ".LPX", ".LBPR", ".LBP",\r |
| 222 | \r |
| 223 | ".EMIO", "MMAP", "$ETST",/* --- */ /* RTE-IV EMA firmware */\r |
| 224 | /* --- --- --- --- */\r |
| 225 | /* --- --- --- --- */\r |
| 226 | /* --- --- --- */ ".EMAP",\r |
| 227 | \r |
| 228 | /* Regular mnemonics. */\r |
| 229 | \r |
| 230 | "NOP", "NOP", "AND", "JSB",\r |
| 231 | "XOR", "JMP", "IOR", "ISZ",\r |
| 232 | "ADA", "ADB" ,"CPA", "CPB",\r |
| 233 | "LDA", "LDB", "STA", "STB",\r |
| 234 | "DIAG", "ASL", "LSL", "TIMER",\r |
| 235 | "RRL", "ASR", "LSR", "RRR",\r |
| 236 | "MPY", "DIV", "DLD", "DST",\r |
| 237 | "FAD", "FSB", "FMP", "FDV",\r |
| 238 | "FIX", "FLT",\r |
| 239 | "STO", "CLO", "SOC", "SOS",\r |
| 240 | "HLT", "STF", "CLF",\r |
| 241 | "SFC", "SFS", "MIA", "MIB",\r |
| 242 | "LIA", "LIB", "OTA", "OTB",\r |
| 243 | "STC", "CLC",\r |
| 244 | "SYA", "USA", "PAA", "PBA",\r |
| 245 | "XMA",\r |
| 246 | "XLA", "XSA", "XCA", "LFA",\r |
| 247 | "RSA", "RVA",\r |
| 248 | "MBI", "MBF",\r |
| 249 | "MBW", "MWI", "MWF", "MWW",\r |
| 250 | "SYB", "USB", "PAB", "PBB",\r |
| 251 | "SSM", "JRS",\r |
| 252 | "XMM", "XMS", "XMB",\r |
| 253 | "XLB", "XSB", "XCB", "LFB",\r |
| 254 | "RSB", "RVB", "DJP", "DJS",\r |
| 255 | "SJP", "SJS", "UJP", "UJS",\r |
| 256 | "SAX", "SBX", "CAX", "CBX",\r |
| 257 | "LAX", "LBX", "STX",\r |
| 258 | "CXA", "CXB", "LDX",\r |
| 259 | "ADX", "XAX", "XBX",\r |
| 260 | "SAY", "SBY", "CAY", "CBY",\r |
| 261 | "LAY", "LBY", "STY",\r |
| 262 | "CYA", "CYB", "LDY",\r |
| 263 | "ADY", "XAY", "XBY",\r |
| 264 | "ISX", "DSX", "JLY", "LBT",\r |
| 265 | "SBT", "MBT", "CBT", "SBT",\r |
| 266 | "ISY", "DSY", "JPY", "SBS",\r |
| 267 | "CBS", "TBS", "CMW", "MVW",\r |
| 268 | NULL, /* decode only */\r |
| 269 | NULL\r |
| 270 | };\r |
| 271 | \r |
| 272 | static const int32 opc_val[] = {\r |
| 273 | 0105340+I_NPN, 0105341+I_NPN, 0105342+I_NPN, 0105343+I_NPN, /* RTE-6/VM OS */\r |
| 274 | 0105344+I_NPN, 0105345+I_NPN, 0105346+I_NPN, 0105347+I_NPN,\r |
| 275 | 0105350+I_NPN, 0105351+I_NPN, 0105352+I_NPN, 0105353+I_NPN,\r |
| 276 | 0105354+I_ALT, 0105355+I_ALT, 0105356+I_ALT, 0105357+I_ALT,\r |
| 277 | 0105354+I_NPN, 0105355+I_NPN, 0105356+I_NPN, 0105357+I_NPN, /* alternates */\r |
| 278 | \r |
| 279 | 0105240+I_ALT, 0105241+I_ALT, 0105242+I_ALT, /* --- */ /* RTE-6/VM VMA */\r |
| 280 | /* --- --- --- --- */\r |
| 281 | 0105250+I_NPN, 0105251+I_NPN, 0105252+I_NPN, 0105253+I_NPN,\r |
| 282 | 0105254+I_NPN, 0105255+I_NPN, 0105256+I_NPN, 0105257+I_ALT,\r |
| 283 | \r |
| 284 | 0105240+I_NPN, 0105241+I_NPN, 0105242+I_NPN, /* RTE-IV EMA */\r |
| 285 | /* --- --- --- --- */\r |
| 286 | /* --- --- --- --- */\r |
| 287 | /* --- --- --- */ 0105257+I_NPN,\r |
| 288 | \r |
| 289 | 0000000+I_NPN, 0002000+I_NPN, 0010000+I_MRF, 0014000+I_MRF,\r |
| 290 | 0020000+I_MRF, 0024000+I_MRF, 0030000+I_MRF, 0034000+I_MRF,\r |
| 291 | 0040000+I_MRF, 0044000+I_MRF, 0050000+I_MRF, 0054000+I_MRF,\r |
| 292 | 0060000+I_MRF, 0064000+I_MRF, 0070000+I_MRF, 0074000+I_MRF,\r |
| 293 | 0100000+I_NPN, 0100020+I_ESH, 0100040+I_ESH, 0100060+I_NPN,\r |
| 294 | 0100100+I_ESH, 0101020+I_ESH, 0101040+I_ESH, 0101100+I_ESH,\r |
| 295 | 0100200+I_EMR, 0100400+I_EMR, 0104200+I_EMR, 0104400+I_EMR,\r |
| 296 | 0105000+I_EMR, 0105020+I_EMR, 0105040+I_EMR, 0105060+I_EMR,\r |
| 297 | 0105100+I_NPN, 0105120+I_NPN,\r |
| 298 | 0102101+I_NPN, 0103101+I_NPN, 0102201+I_NPC, 0102301+I_NPC,\r |
| 299 | 0102000+I_IO1, 0102100+I_IO2, 0103100+I_IO2,\r |
| 300 | 0102200+I_IO1, 0102300+I_IO1, 0102400+I_IO1, 0106400+I_IO1,\r |
| 301 | 0102500+I_IO1, 0106500+I_IO1, 0102600+I_IO1, 0106600+I_IO1,\r |
| 302 | 0102700+I_IO1, 0106700+I_IO1,\r |
| 303 | 0101710+I_NPN, 0101711+I_NPN, 0101712+I_NPN, 0101713+I_NPN,\r |
| 304 | 0101722+I_NPN,\r |
| 305 | 0101724+I_EMR, 0101725+I_EMR, 0101726+I_EMR, 0101727+I_NPN,\r |
| 306 | 0101730+I_NPN, 0101731+I_NPN,\r |
| 307 | 0105702+I_NPN, 0105703+I_NPN,\r |
| 308 | 0105704+I_NPN, 0105705+I_NPN, 0105706+I_NPN, 0105707+I_NPN,\r |
| 309 | 0105710+I_NPN, 0105711+I_NPN, 0105712+I_NPN, 0105713+I_NPN,\r |
| 310 | 0105714+I_EMR, 0105715+I_EG2,\r |
| 311 | 0105720+I_NPN, 0105721+I_NPN, 0105722+I_NPN,\r |
| 312 | 0105724+I_EMR, 0105725+I_EMR, 0105726+I_EMR, 0105727+I_NPN,\r |
| 313 | 0105730+I_NPN, 0105731+I_NPN, 0105732+I_EMR, 0105733+I_EMR,\r |
| 314 | 0105734+I_EMR, 0105735+I_EMR, 0105736+I_EMR, 0105737+I_EMR,\r |
| 315 | 0101740+I_EMR, 0105740+I_EMR, 0101741+I_NPN, 0105741+I_NPN,\r |
| 316 | 0101742+I_EMR, 0105742+I_EMR, 0105743+I_EMR,\r |
| 317 | 0101744+I_NPN, 0105744+I_NPN, 0105745+I_EMR,\r |
| 318 | 0105746+I_EMR, 0101747+I_NPN, 0105747+I_NPN,\r |
| 319 | 0101750+I_EMR, 0105750+I_EMR, 0101751+I_NPN, 0105751+I_NPN,\r |
| 320 | 0101752+I_EMR, 0105752+I_EMR, 0105753+I_EMR,\r |
| 321 | 0101754+I_NPN, 0105754+I_NPN, 0105755+I_EMR,\r |
| 322 | 0105756+I_EMR, 0101757+I_NPN, 0105757+I_NPN,\r |
| 323 | 0105760+I_NPN, 0105761+I_NPN, 0105762+I_EMR, 0105763+I_NPN,\r |
| 324 | 0105764+I_NPN, 0105765+I_EGZ, 0105766+I_EGZ, 0105767+I_NPN,\r |
| 325 | 0105770+I_NPN, 0105771+I_NPN, 0105772+I_EMR, 0105773+I_EG2,\r |
| 326 | 0105774+I_EG2, 0105775+I_EG2, 0105776+I_EGZ, 0105777+I_EGZ,\r |
| 327 | 0000000+I_ASH, /* decode only */\r |
| 328 | -1\r |
| 329 | };\r |
| 330 | \r |
| 331 | /* Decode tables for shift and alter/skip groups */\r |
| 332 | \r |
| 333 | static const char *stab[] = {\r |
| 334 | "ALS", "ARS", "RAL", "RAR", "ALR", "ERA", "ELA", "ALF",\r |
| 335 | "BLS", "BRS", "RBL", "RBR", "BLR", "ERB", "ELB", "BLF",\r |
| 336 | "CLA", "CMA", "CCA", "CLB", "CMB", "CCB",\r |
| 337 | "SEZ", "CLE", "CLE", "CME", "CCE",\r |
| 338 | "SSA", "SSB", "SLA", "SLB",\r |
| 339 | "ALS", "ARS", "RAL", "RAR", "ALR", "ERA", "ELA", "ALF",\r |
| 340 | "BLS", "BRS", "RBL", "RBR", "BLR", "ERB", "ELB", "BLF",\r |
| 341 | "INA", "INB", "SZA", "SZB", "RSS",\r |
| 342 | NULL\r |
| 343 | };\r |
| 344 | \r |
| 345 | static const int32 mtab[] = {\r |
| 346 | 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700,\r |
| 347 | 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700,\r |
| 348 | 0007400, 0007400, 0007400, 0007400, 0007400, 0007400,\r |
| 349 | 0002040, 0002040, 0002300, 0002300, 0002300,\r |
| 350 | 0006020, 0006020, 0004010, 0004010,\r |
| 351 | 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027,\r |
| 352 | 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027,\r |
| 353 | 0006004, 0006004, 0006002, 0006002, 0002001,\r |
| 354 | 0\r |
| 355 | };\r |
| 356 | \r |
| 357 | static const int32 vtab[] = {\r |
| 358 | 0001000, 0001100, 0001200, 0001300, 0001400, 0001500, 0001600, 0001700,\r |
| 359 | 0005000, 0005100, 0005200, 0005300, 0005400, 0005500, 0005600, 0005700,\r |
| 360 | 0002400, 0003000, 0003400, 0006400, 0007000, 0007400,\r |
| 361 | 0002040, 0000040, 0002100, 0002200, 0002300,\r |
| 362 | 0002020, 0006020, 0000010, 0004010,\r |
| 363 | 0000020, 0000021, 0000022, 0000023, 0000024, 0000025, 0000026, 0000027,\r |
| 364 | 0004020, 0004021, 0004022, 0004023, 0004024, 0004025, 0004026, 0004027,\r |
| 365 | 0002004, 0006004, 0002002, 0006002, 0002001,\r |
| 366 | -1\r |
| 367 | };\r |
| 368 | \r |
| 369 | /* Symbolic decode\r |
| 370 | \r |
| 371 | Inputs:\r |
| 372 | *of = output stream\r |
| 373 | addr = current PC\r |
| 374 | *val = pointer to data\r |
| 375 | *uptr = pointer to unit\r |
| 376 | sw = switches\r |
| 377 | Outputs:\r |
| 378 | return = status code\r |
| 379 | */\r |
| 380 | \r |
| 381 | #define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)\r |
| 382 | \r |
| 383 | t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,\r |
| 384 | UNIT *uptr, int32 sw)\r |
| 385 | {\r |
| 386 | int32 cflag, cm, i, j, inst, disp;\r |
| 387 | uint32 irq;\r |
| 388 | \r |
| 389 | cflag = (uptr == NULL) || (uptr == &cpu_unit);\r |
| 390 | inst = val[0];\r |
| 391 | if (sw & SWMASK ('A')) { /* ASCII? */\r |
| 392 | if (inst > 0377) return SCPE_ARG;\r |
| 393 | fprintf (of, FMTASC (inst & 0177));\r |
| 394 | return SCPE_OK;\r |
| 395 | }\r |
| 396 | if (sw & SWMASK ('C')) { /* characters? */\r |
| 397 | fprintf (of, FMTASC ((inst >> 8) & 0177));\r |
| 398 | fprintf (of, FMTASC (inst & 0177));\r |
| 399 | return SCPE_OK;\r |
| 400 | }\r |
| 401 | if (!(sw & SWMASK ('M'))) return SCPE_ARG;\r |
| 402 | \r |
| 403 | /* If we are being called as a result of a VM stop to display the next\r |
| 404 | instruction to be executed, check to see if an interrupt is pending and not\r |
| 405 | deferred. If so, then display the interrupt source and the trap cell\r |
| 406 | instruction as the instruction to be executed, rather than the instruction at\r |
| 407 | the current PC.\r |
| 408 | */\r |
| 409 | \r |
| 410 | if (sw & SIM_SW_STOP) { /* simulator stop? */\r |
| 411 | irq = calc_int (); /* check interrupt */\r |
| 412 | \r |
| 413 | if (irq && (!ion_defer || !calc_defer())) { /* pending interrupt and not deferred? */\r |
| 414 | inst = val[0] = ReadIO (irq, SMAP); /* load trap cell instruction */\r |
| 415 | val[1] = ReadIO (irq + 1, SMAP); /* might be multi-word */\r |
| 416 | val[2] = ReadIO (irq + 2, SMAP); /* although it's unlikely */\r |
| 417 | fprintf (of, "IAK %2o: ", irq); /* report acknowledged interrupt */\r |
| 418 | }\r |
| 419 | }\r |
| 420 | \r |
| 421 | for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */\r |
| 422 | j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */\r |
| 423 | if ((opc_val[i] & DMASK) == (inst & masks[j])) { /* match? */\r |
| 424 | switch (j) { /* case on class */\r |
| 425 | \r |
| 426 | case I_V_NPN: /* no operands */\r |
| 427 | fprintf (of, "%s", opcode[i]); /* opcode */\r |
| 428 | break;\r |
| 429 | \r |
| 430 | case I_V_NPC: /* no operands + C */\r |
| 431 | fprintf (of, "%s", opcode[i]);\r |
| 432 | if (inst & I_HC) fprintf (of, " C");\r |
| 433 | break;\r |
| 434 | \r |
| 435 | case I_V_MRF: /* mem ref */\r |
| 436 | disp = inst & I_DISP; /* displacement */\r |
| 437 | fprintf (of, "%s ", opcode[i]); /* opcode */\r |
| 438 | if (inst & I_CP) { /* current page? */\r |
| 439 | if (cflag) fprintf (of, "%-o", (addr & I_PAGENO) | disp);\r |
| 440 | else fprintf (of, "C %-o", disp);\r |
| 441 | }\r |
| 442 | else fprintf (of, "%-o", disp); /* page zero */\r |
| 443 | if (inst & I_IA) fprintf (of, ",I");\r |
| 444 | break;\r |
| 445 | \r |
| 446 | case I_V_ASH: /* shift, alter-skip */\r |
| 447 | cm = FALSE;\r |
| 448 | for (i = 0; mtab[i] != 0; i++) {\r |
| 449 | if ((inst & mtab[i]) == vtab[i]) {\r |
| 450 | inst = inst & ~(vtab[i] & 01777);\r |
| 451 | if (cm) fprintf (of, ",");\r |
| 452 | cm = TRUE;\r |
| 453 | fprintf (of, "%s", stab[i]);\r |
| 454 | }\r |
| 455 | }\r |
| 456 | if (!cm) return SCPE_ARG; /* nothing decoded? */\r |
| 457 | break;\r |
| 458 | \r |
| 459 | case I_V_ESH: /* extended shift */\r |
| 460 | disp = inst & 017; /* shift count */\r |
| 461 | if (disp == 0) disp = 16;\r |
| 462 | fprintf (of, "%s %d", opcode[i], disp);\r |
| 463 | break;\r |
| 464 | \r |
| 465 | case I_V_EMR: /* extended mem ref */\r |
| 466 | fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK);\r |
| 467 | if (val[1] & I_IA) fprintf (of, ",I");\r |
| 468 | return -1; /* extra word */\r |
| 469 | \r |
| 470 | case I_V_IO1: /* IOT with H/C */\r |
| 471 | fprintf (of, "%s %-o", opcode[i], inst & I_DEVMASK);\r |
| 472 | if (inst & I_HC) fprintf (of, ",C");\r |
| 473 | break;\r |
| 474 | \r |
| 475 | case I_V_IO2: /* IOT */\r |
| 476 | fprintf (of, "%s %-o", opcode[i], inst & I_DEVMASK);\r |
| 477 | break;\r |
| 478 | \r |
| 479 | case I_V_EGZ: /* ext grp 1 op + 0 */\r |
| 480 | fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK);\r |
| 481 | if (val[1] & I_IA) fprintf (of, ",I");\r |
| 482 | return -2; /* extra words */\r |
| 483 | \r |
| 484 | case I_V_EG2: /* ext grp 2 op */\r |
| 485 | fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK);\r |
| 486 | if (val[1] & I_IA) fprintf (of, ",I");\r |
| 487 | fprintf (of, " %-o", val[2] & VAMASK);\r |
| 488 | if (val[2] & I_IA) fprintf (of, ",I");\r |
| 489 | return -2; /* extra words */\r |
| 490 | \r |
| 491 | case I_V_ALT: /* alternate use instr */\r |
| 492 | if ((inst >= 0105354) &&\r |
| 493 | (inst <= 0105357) && /* RTE-6/VM OS range? */\r |
| 494 | (addr >= 2) &&\r |
| 495 | (addr <= 077)) /* in trap cell? */\r |
| 496 | continue; /* use alternate mnemonic */\r |
| 497 | \r |
| 498 | else if ((inst >= 0105240) && /* RTE-6/VM VMA range? */\r |
| 499 | (inst <= 0105257) &&\r |
| 500 | (cpu_unit.flags & UNIT_EMA)) /* EMA enabled? */\r |
| 501 | continue; /* use EMA mnemonics */\r |
| 502 | \r |
| 503 | else\r |
| 504 | fprintf (of, "%s", opcode[i]); /* print opcode */\r |
| 505 | break;\r |
| 506 | }\r |
| 507 | \r |
| 508 | return SCPE_OK;\r |
| 509 | } /* end if */\r |
| 510 | } /* end for */\r |
| 511 | return SCPE_ARG;\r |
| 512 | }\r |
| 513 | \r |
| 514 | /* Get address with indirection\r |
| 515 | \r |
| 516 | Inputs:\r |
| 517 | *cptr = pointer to input string\r |
| 518 | Outputs:\r |
| 519 | val = address\r |
| 520 | -1 if error\r |
| 521 | */\r |
| 522 | \r |
| 523 | int32 get_addr (char *cptr)\r |
| 524 | {\r |
| 525 | int32 d;\r |
| 526 | t_stat r;\r |
| 527 | char gbuf[CBUFSIZE];\r |
| 528 | \r |
| 529 | cptr = get_glyph (cptr, gbuf, ','); /* get next field */\r |
| 530 | d = get_uint (gbuf, 8, VAMASK, &r); /* construe as addr */\r |
| 531 | if (r != SCPE_OK) return -1;\r |
| 532 | if (*cptr != 0) { /* more? */\r |
| 533 | cptr = get_glyph (cptr, gbuf, 0); /* look for indirect */\r |
| 534 | if (*cptr != 0) return -1; /* should be done */\r |
| 535 | if (strcmp (gbuf, "I")) return -1; /* I? */\r |
| 536 | d = d | I_IA;\r |
| 537 | }\r |
| 538 | return d;\r |
| 539 | }\r |
| 540 | \r |
| 541 | /* Symbolic input\r |
| 542 | \r |
| 543 | Inputs:\r |
| 544 | *iptr = pointer to input string\r |
| 545 | addr = current PC\r |
| 546 | *uptr = pointer to unit\r |
| 547 | *val = pointer to output values\r |
| 548 | sw = switches\r |
| 549 | Outputs:\r |
| 550 | status = error status\r |
| 551 | */\r |
| 552 | \r |
| 553 | t_stat parse_sym (char *iptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)\r |
| 554 | {\r |
| 555 | int32 cflag, d, i, j, k, clef, tbits;\r |
| 556 | t_stat r, ret;\r |
| 557 | char *cptr, gbuf[CBUFSIZE];\r |
| 558 | \r |
| 559 | cflag = (uptr == NULL) || (uptr == &cpu_unit);\r |
| 560 | while (isspace (*iptr)) iptr++; /* absorb spaces */\r |
| 561 | if ((sw & SWMASK ('A')) || ((*iptr == '\'') && iptr++)) { /* ASCII char? */\r |
| 562 | if (iptr[0] == 0) return SCPE_ARG; /* must have 1 char */\r |
| 563 | val[0] = (t_value) iptr[0] & 0177;\r |
| 564 | return SCPE_OK;\r |
| 565 | }\r |
| 566 | if ((sw & SWMASK ('C')) || ((*iptr == '"') && iptr++)) { /* char string? */\r |
| 567 | if (iptr[0] == 0) return SCPE_ARG; /* must have 1 char */\r |
| 568 | val[0] = (((t_value) iptr[0] & 0177) << 8) |\r |
| 569 | ((t_value) iptr[1] & 0177);\r |
| 570 | return SCPE_OK;\r |
| 571 | }\r |
| 572 | \r |
| 573 | ret = SCPE_OK;\r |
| 574 | cptr = get_glyph (iptr, gbuf, 0); /* get opcode */\r |
| 575 | for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;\r |
| 576 | if (opcode[i]) { /* found opcode? */\r |
| 577 | val[0] = opc_val[i] & DMASK; /* get value */\r |
| 578 | j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */\r |
| 579 | switch (j) { /* case on class */\r |
| 580 | \r |
| 581 | case I_V_NPN: /* no operand */\r |
| 582 | break;\r |
| 583 | \r |
| 584 | case I_V_NPC: /* no operand + C */\r |
| 585 | if (*cptr != 0) {\r |
| 586 | cptr = get_glyph (cptr, gbuf, 0);\r |
| 587 | if (strcmp (gbuf, "C")) return SCPE_ARG;\r |
| 588 | val[0] = val[0] | I_HC;\r |
| 589 | }\r |
| 590 | break;\r |
| 591 | \r |
| 592 | case I_V_MRF: /* mem ref */\r |
| 593 | cptr = get_glyph (cptr, gbuf, 0); /* get next field */\r |
| 594 | if (k = (strcmp (gbuf, "C") == 0)) { /* C specified? */\r |
| 595 | val[0] = val[0] | I_CP;\r |
| 596 | cptr = get_glyph (cptr, gbuf, 0);\r |
| 597 | }\r |
| 598 | else if (k = (strcmp (gbuf, "Z") == 0)) { /* Z specified? */\r |
| 599 | cptr = get_glyph (cptr, gbuf, ',');\r |
| 600 | }\r |
| 601 | if ((d = get_addr (gbuf)) < 0) return SCPE_ARG;\r |
| 602 | if ((d & VAMASK) <= I_DISP) val[0] = val[0] | d;\r |
| 603 | else if (cflag && !k && (((addr ^ d) & I_PAGENO) == 0))\r |
| 604 | val[0] = val[0] | (d & (I_IA | I_DISP)) | I_CP;\r |
| 605 | else return SCPE_ARG;\r |
| 606 | break;\r |
| 607 | \r |
| 608 | case I_V_ESH: /* extended shift */\r |
| 609 | cptr = get_glyph (cptr, gbuf, 0);\r |
| 610 | d = get_uint (gbuf, 10, 16, &r);\r |
| 611 | if ((r != SCPE_OK) || (d == 0)) return SCPE_ARG;\r |
| 612 | val[0] = val[0] | (d & 017);\r |
| 613 | break;\r |
| 614 | \r |
| 615 | case I_V_EMR: /* extended mem ref */\r |
| 616 | cptr = get_glyph (cptr, gbuf, 0); /* get next field */\r |
| 617 | if ((d = get_addr (gbuf)) < 0) return SCPE_ARG;\r |
| 618 | val[1] = d;\r |
| 619 | ret = -1;\r |
| 620 | break;\r |
| 621 | \r |
| 622 | case I_V_IO1: /* IOT + optional C */\r |
| 623 | cptr = get_glyph (cptr, gbuf, ','); /* get device */\r |
| 624 | d = get_uint (gbuf, 8, I_DEVMASK, &r);\r |
| 625 | if (r != SCPE_OK) return SCPE_ARG;\r |
| 626 | val[0] = val[0] | d;\r |
| 627 | if (*cptr != 0) {\r |
| 628 | cptr = get_glyph (cptr, gbuf, 0);\r |
| 629 | if (strcmp (gbuf, "C")) return SCPE_ARG;\r |
| 630 | val[0] = val[0] | I_HC;\r |
| 631 | }\r |
| 632 | break;\r |
| 633 | \r |
| 634 | case I_V_IO2: /* IOT */\r |
| 635 | cptr = get_glyph (cptr, gbuf, 0); /* get device */\r |
| 636 | d = get_uint (gbuf, 8, I_DEVMASK, &r);\r |
| 637 | if (r != SCPE_OK) return SCPE_ARG;\r |
| 638 | val[0] = val[0] | d;\r |
| 639 | break;\r |
| 640 | \r |
| 641 | case I_V_EGZ: /* ext grp 1 op + 0 */\r |
| 642 | cptr = get_glyph (cptr, gbuf, 0); /* get next field */\r |
| 643 | if ((d = get_addr (gbuf)) < 0) return SCPE_ARG;\r |
| 644 | val[1] = d;\r |
| 645 | val[2] = 0;\r |
| 646 | ret = -2;\r |
| 647 | break;\r |
| 648 | \r |
| 649 | case I_V_EG2: /* ext grp 2 op */\r |
| 650 | cptr = get_glyph (cptr, gbuf, 0); /* get next field */\r |
| 651 | if ((d = get_addr (gbuf)) < 0) return SCPE_ARG;\r |
| 652 | cptr = get_glyph (cptr, gbuf, 0); /* get next field */\r |
| 653 | if ((k = get_addr (gbuf)) < 0) return SCPE_ARG;\r |
| 654 | val[1] = d;\r |
| 655 | val[2] = k;\r |
| 656 | ret = -2;\r |
| 657 | break;\r |
| 658 | } /* end case */\r |
| 659 | \r |
| 660 | if (*cptr != 0) return SCPE_ARG; /* junk at end? */\r |
| 661 | return ret;\r |
| 662 | } /* end if opcode */\r |
| 663 | \r |
| 664 | /* Shift or alter-skip\r |
| 665 | \r |
| 666 | Each opcode is matched by a mask, specifiying the bits affected, and\r |
| 667 | the value, specifying the value. As opcodes are processed, the mask\r |
| 668 | values are used to specify which fields have already been filled in.\r |
| 669 | \r |
| 670 | The mask has two subfields, the type bits (A/B and A/S), and the field\r |
| 671 | bits. The type bits, once specified by any instruction, must be\r |
| 672 | consistent in all other instructions. The mask bits assure that no\r |
| 673 | field is filled in twice.\r |
| 674 | \r |
| 675 | Two special cases:\r |
| 676 | \r |
| 677 | 1. The dual shift field in shift requires checking how much of the\r |
| 678 | target word has been filled in before assigning the shift value.\r |
| 679 | To implement this, shifts are listed twice is the decode table.\r |
| 680 | If the current subopcode is a shift in the first part of the table\r |
| 681 | (entries 0..15), and CLE has been seen or the first shift field is\r |
| 682 | filled in, the code forces a mismatch. The glyph will match in\r |
| 683 | the second part of the table.\r |
| 684 | \r |
| 685 | 2. CLE processing must be deferred until the instruction can be\r |
| 686 | classified as shift or alter-skip, since it has two different\r |
| 687 | bit values in the two classes. To implement this, CLE seen is\r |
| 688 | recorded as a flag and processed after all other subopcodes.\r |
| 689 | */\r |
| 690 | \r |
| 691 | clef = FALSE;\r |
| 692 | tbits = 0;\r |
| 693 | val[0] = 0;\r |
| 694 | for (cptr = get_glyph (iptr, gbuf, ','); gbuf[0] != 0;\r |
| 695 | cptr = get_glyph (cptr, gbuf, ',')) { /* loop thru glyphs */\r |
| 696 | if (strcmp (gbuf, "CLE") == 0) { /* CLE? */\r |
| 697 | if (clef) return SCPE_ARG; /* already seen? */\r |
| 698 | clef = TRUE; /* set flag */\r |
| 699 | continue;\r |
| 700 | }\r |
| 701 | for (i = 0; stab[i] != NULL; i++) { /* find subopcode */\r |
| 702 | if ((strcmp (gbuf, stab[i]) == 0) &&\r |
| 703 | ((i >= 16) || (!clef && ((val[0] & 001710) == 0)))) break;\r |
| 704 | }\r |
| 705 | if (stab[i] == NULL) return SCPE_ARG;\r |
| 706 | if (tbits & mtab[i] & (I_AB | I_ASKP) & (vtab[i] ^ val[0]))\r |
| 707 | return SCPE_ARG;\r |
| 708 | if (tbits & mtab[i] & ~(I_AB | I_ASKP)) return SCPE_ARG;\r |
| 709 | tbits = tbits | mtab[i]; /* fill type+mask */\r |
| 710 | val[0] = val[0] | vtab[i]; /* fill value */\r |
| 711 | }\r |
| 712 | if (clef) { /* CLE seen? */\r |
| 713 | if (val[0] & I_ASKP) { /* alter-skip? */\r |
| 714 | if (tbits & 0100) return SCPE_ARG; /* already filled in? */\r |
| 715 | else val[0] = val[0] | 0100;\r |
| 716 | }\r |
| 717 | else val[0] = val[0] | 040; /* fill in shift */\r |
| 718 | }\r |
| 719 | return ret;\r |
| 720 | }\r |