| 1 | /* gri_sys.c: GRI-909 simulator interface\r |
| 2 | \r |
| 3 | Copyright (c) 2001-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 | 14-Jan-08 RMS Added GRI-99 support\r |
| 27 | 18-Oct-02 RMS Fixed bug in symbolic decode (found by Hans Pufal)\r |
| 28 | */\r |
| 29 | \r |
| 30 | #include "gri_defs.h"\r |
| 31 | #include <ctype.h>\r |
| 32 | \r |
| 33 | extern DEVICE cpu_dev;\r |
| 34 | extern UNIT cpu_unit;\r |
| 35 | extern DEVICE tti_dev, tto_dev;\r |
| 36 | extern DEVICE hsr_dev, hsp_dev;\r |
| 37 | extern DEVICE rtc_dev;\r |
| 38 | extern REG cpu_reg[];\r |
| 39 | extern uint16 M[];\r |
| 40 | extern int32 sim_switches;\r |
| 41 | \r |
| 42 | void fprint_addr (FILE *of, uint32 val, uint32 mod, uint32 dst);\r |
| 43 | \r |
| 44 | /* SCP data structures and interface routines\r |
| 45 | \r |
| 46 | sim_name simulator name string\r |
| 47 | sim_PC pointer to saved PC register descriptor\r |
| 48 | sim_emax maximum number of words for examine/deposit\r |
| 49 | sim_devices array of pointers to simulated devices\r |
| 50 | sim_stop_messages array of pointers to stop messages\r |
| 51 | sim_load binary loader\r |
| 52 | */\r |
| 53 | \r |
| 54 | char sim_name[] = "GRI-909";\r |
| 55 | \r |
| 56 | REG *sim_PC = &cpu_reg[0];\r |
| 57 | \r |
| 58 | int32 sim_emax = 2;\r |
| 59 | \r |
| 60 | DEVICE *sim_devices[] = {\r |
| 61 | &cpu_dev,\r |
| 62 | &tti_dev,\r |
| 63 | &tto_dev,\r |
| 64 | &hsr_dev,\r |
| 65 | &hsp_dev,\r |
| 66 | &rtc_dev,\r |
| 67 | NULL\r |
| 68 | };\r |
| 69 | \r |
| 70 | const char *sim_stop_messages[] = {\r |
| 71 | "Unknown error",\r |
| 72 | "Unimplemented unit",\r |
| 73 | "HALT instruction",\r |
| 74 | "Breakpoint",\r |
| 75 | "Invalid interrupt request"\r |
| 76 | };\r |
| 77 | \r |
| 78 | /* Binary loader\r |
| 79 | \r |
| 80 | Bootstrap loader format consists of blocks separated by zeroes. Each\r |
| 81 | word in the block has three frames: a control frame (ignored) and two\r |
| 82 | data frames. The user must specify the load address. Switch -c means\r |
| 83 | continue and load all blocks until end of tape.\r |
| 84 | */\r |
| 85 | \r |
| 86 | t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)\r |
| 87 | {\r |
| 88 | int32 c;\r |
| 89 | uint32 org;\r |
| 90 | t_stat r;\r |
| 91 | char gbuf[CBUFSIZE];\r |
| 92 | \r |
| 93 | if (*cptr != 0) { /* more input? */\r |
| 94 | cptr = get_glyph (cptr, gbuf, 0); /* get origin */\r |
| 95 | org = get_uint (gbuf, 8, AMASK, &r);\r |
| 96 | if (r != SCPE_OK) return r;\r |
| 97 | if (*cptr != 0) return SCPE_ARG; /* no more */\r |
| 98 | }\r |
| 99 | else org = 0200; /* default 200 */\r |
| 100 | \r |
| 101 | for (;;) { /* until EOF */\r |
| 102 | while ((c = getc (fileref)) == 0) ; /* skip starting 0's */\r |
| 103 | if (c == EOF) break; /* EOF? done */\r |
| 104 | for ( ; c != 0; ) { /* loop until ctl = 0 */\r |
| 105 | /* ign ctrl frame */\r |
| 106 | if ((c = getc (fileref)) == EOF) /* get high byte */\r |
| 107 | return SCPE_FMT; /* EOF is error */\r |
| 108 | if (!MEM_ADDR_OK (org)) return SCPE_NXM;\r |
| 109 | M[org] = ((c & 0377) << 8); /* store high */\r |
| 110 | if ((c = getc (fileref)) == EOF) /* get low byte */\r |
| 111 | return SCPE_FMT; /* EOF is error */\r |
| 112 | M[org] = M[org] | (c & 0377); /* store low */\r |
| 113 | org = org + 1; /* incr origin */\r |
| 114 | if ((c = getc (fileref)) == EOF) /* get ctrl frame */\r |
| 115 | return SCPE_OK; /* EOF is ok */\r |
| 116 | } /* end block for */\r |
| 117 | if (!(sim_switches & SWMASK ('C'))) return SCPE_OK;\r |
| 118 | } /* end tape for */\r |
| 119 | return SCPE_OK;\r |
| 120 | }\r |
| 121 | \r |
| 122 | /* Symbol tables */\r |
| 123 | \r |
| 124 | #define F_V_FL 16 /* class flag */\r |
| 125 | #define F_M_FL 017\r |
| 126 | #define F_V_FO 000 /* function out */\r |
| 127 | #define F_V_FOI 001 /* FO, impl reg */\r |
| 128 | #define F_V_SF 002 /* skip function */\r |
| 129 | #define F_V_SFI 003 /* SF, impl reg */\r |
| 130 | #define F_V_RR 004 /* reg reg */\r |
| 131 | #define F_V_ZR 005 /* zero reg */\r |
| 132 | #define F_V_RS 006 /* reg self */\r |
| 133 | #define F_V_JC 010 /* jump cond */\r |
| 134 | #define F_V_JU 011 /* jump uncond */\r |
| 135 | #define F_V_RM 012 /* reg mem */\r |
| 136 | #define F_V_ZM 013 /* zero mem */\r |
| 137 | #define F_V_MR 014 /* mem reg */\r |
| 138 | #define F_V_MS 015 /* mem self */\r |
| 139 | #define F_2WD 010 /* 2 words */\r |
| 140 | \r |
| 141 | #define F_FO (F_V_FO << F_V_FL)\r |
| 142 | #define F_FOI (F_V_FOI << F_V_FL)\r |
| 143 | #define F_SF (F_V_SF << F_V_FL)\r |
| 144 | #define F_SFI (F_V_SFI << F_V_FL)\r |
| 145 | #define F_RR (F_V_RR << F_V_FL)\r |
| 146 | #define F_ZR (F_V_ZR << F_V_FL)\r |
| 147 | #define F_RS (F_V_RS << F_V_FL)\r |
| 148 | #define F_JC (F_V_JC << F_V_FL)\r |
| 149 | #define F_JU (F_V_JU << F_V_FL)\r |
| 150 | #define F_RM (F_V_RM << F_V_FL)\r |
| 151 | #define F_ZM (F_V_ZM << F_V_FL)\r |
| 152 | #define F_MR (F_V_MR << F_V_FL)\r |
| 153 | #define F_MS (F_V_MS << F_V_FL)\r |
| 154 | \r |
| 155 | struct fnc_op {\r |
| 156 | uint32 inst; /* instr prot */\r |
| 157 | uint32 imask; /* instr mask */\r |
| 158 | uint32 oper; /* operator */\r |
| 159 | uint32 omask; /* oper mask */\r |
| 160 | };\r |
| 161 | \r |
| 162 | static const int32 masks[] = {\r |
| 163 | 0176000, 0176077, 0000077, 0176077,\r |
| 164 | 0000300, 0176300, 0000300, 0177777,\r |
| 165 | 0000077, 0177777, 0000377, 0176377,\r |
| 166 | 0176300, 0176377\r |
| 167 | };\r |
| 168 | \r |
| 169 | /* Instruction mnemonics\r |
| 170 | \r |
| 171 | Order is critical, as some instructions are more precise versions of\r |
| 172 | others. For example, JU must precede JC, otherwise, JU will be decoded\r |
| 173 | as JC 0,ETZ,dst. There are some ambiguities, eg, what is 02-xxxx-06?\r |
| 174 | Priority is as follows:\r |
| 175 | \r |
| 176 | FO (02-xxxx-rr)\r |
| 177 | SF (rr-xxxx-02)\r |
| 178 | MR (06-xxxx-rr)\r |
| 179 | RM (rr-xxxx-06)\r |
| 180 | JC (rr-xxxx-03)\r |
| 181 | RR \r |
| 182 | */\r |
| 183 | \r |
| 184 | static const char *opcode[] = {\r |
| 185 | "FOM", "FOA", "FOI", "FO", /* FOx before FO */\r |
| 186 | "SFM", "SFA", "SFI", "SF", /* SFx before SF */\r |
| 187 | "ZM", "ZMD", "ZMI", "ZMID", /* ZM before RM */\r |
| 188 | "MS", "MSD", "MSI", "MSID",\r |
| 189 | "RM", "RMD", "RMI", "RMID",\r |
| 190 | "MR", "MRD", "MRI", "MRID",\r |
| 191 | "JO", "JOD", "JN", "JND", /* JU before JC */\r |
| 192 | "JU", "JUD", "JC", "JCD",\r |
| 193 | "ZR", "ZRC", "RR", "RRC", /* ZR before RR */\r |
| 194 | "RS", "RSC",\r |
| 195 | NULL\r |
| 196 | };\r |
| 197 | \r |
| 198 | static const uint32 opc_val[] = {\r |
| 199 | 0004000+F_FOI, 0004013+F_FOI, 0004004+F_FOI, 0004000+F_FO,\r |
| 200 | 0000002+F_SFI, 0026002+F_SFI, 0010002+F_SFI, 0000002+F_SF,\r |
| 201 | 0000006+F_ZM, 0000106+F_ZM, 0000206+F_ZM, 0000306+F_ZM,\r |
| 202 | 0014006+F_MS, 0014106+F_MS, 0014206+F_MS, 0014306+F_MS,\r |
| 203 | 0000006+F_RM, 0000106+F_RM, 0000206+F_RM, 0000306+F_RM,\r |
| 204 | 0014000+F_MR, 0014100+F_MR, 0014200+F_MR, 0014300+F_MR,\r |
| 205 | 0037003+F_JU, 0037103+F_JU, 0037203+F_JU, 0037303+F_JU,\r |
| 206 | 0000403+F_JU, 0000503+F_JU, 0000003+F_JC, 0000103+F_JC,\r |
| 207 | 0000000+F_ZR, 0000200+F_ZR, 0000000+F_RR, 0000200+F_RR,\r |
| 208 | 0000000+F_RS, 0000200+F_RS\r |
| 209 | };\r |
| 210 | \r |
| 211 | /* Unit mnemonics. All 64 units are decoded, most just to octal integers */\r |
| 212 | \r |
| 213 | static const char *unsrc[64] = {\r |
| 214 | "0", "IR", "2", "TRP", "ISR", "MA", "MB", "SC", /* 00 - 07 */\r |
| 215 | "SWR", "AX", "AY", "AO", "14", "15", "16", "MSR", /* 10 - 17 */\r |
| 216 | "20", "21", "XR", "ATRP", "BSW", "BPK", "BCPA", "BCPB",/* 20 - 27 */\r |
| 217 | "GR1", "GR2", "GR3", "GR4", "GR5", "GR6", "36", "37", /* 30 - 37 */\r |
| 218 | "40", "41", "42", "43", "44", "45", "46", "47",\r |
| 219 | "50", "51", "52", "53", "54", "CDR", "56", "CADR",\r |
| 220 | "60", "61", "62", "63", "64", "65", "DWC", "DCA",\r |
| 221 | "DISK", "LPR", "72", "73", "CAS", "RTC", "HSR", "TTI" /* 70 - 77 */\r |
| 222 | };\r |
| 223 | \r |
| 224 | static const char *undst[64] = {\r |
| 225 | "0", "IR", "2", "TRP", "ISR", "5", "MB", "SC", /* 00 - 07 */\r |
| 226 | "SWR", "AX", "AY", "13", "EAO", "15", "16", "MSR", /* 10 - 17 */\r |
| 227 | "20", "21", "XR", "ATRP", "BSW", "BPK", "BCPA", "BCPB",/* 20 - 27 */\r |
| 228 | "GR1", "GR2", "GR3", "GR4", "GR5", "GR6", "36", "37", /* 30 - 37 */\r |
| 229 | "40", "41", "42", "43", "44", "45", "46", "47",\r |
| 230 | "50", "51", "52", "53", "54", "CDR", "56", "CADR",\r |
| 231 | "60", "61", "62", "63", "64", "65", "DWC", "DCA",\r |
| 232 | "DISK", "LPR", "72", "73", "CAS", "RTC", "HSP", "TTO" /* 70 - 77 */\r |
| 233 | };\r |
| 234 | \r |
| 235 | /* Operators */\r |
| 236 | \r |
| 237 | static const char *opname[4] = {\r |
| 238 | NULL, "P1", "L1", "R1"\r |
| 239 | };\r |
| 240 | \r |
| 241 | /* Conditions */\r |
| 242 | \r |
| 243 | static const char *cdname[8] = {\r |
| 244 | "NEVER", "ALWAYS", "ETZ", "NEZ", "LTZ", "GEZ", "LEZ", "GTZ"\r |
| 245 | };\r |
| 246 | \r |
| 247 | /* Function out/sense function */\r |
| 248 | \r |
| 249 | static const char *fname[] = {\r |
| 250 | "NOT", /* any SF */\r |
| 251 | "POK", "LNK", "BOV", /* SFM */\r |
| 252 | "SOV", "AOV", /* SFA */\r |
| 253 | "IRDY", "ORDY", /* any SF */\r |
| 254 | "CLL", "STL", "CML", "HLT", /* FOM */\r |
| 255 | "ICF", "ICO", /* FOI */\r |
| 256 | "ADD", "AND", "XOR", "OR", /* FOA */\r |
| 257 | "INP", "IRDY", "ORDY", "STRT", /* any FO */\r |
| 258 | NULL\r |
| 259 | };\r |
| 260 | \r |
| 261 | static const struct fnc_op fop[] = {\r |
| 262 | { 0000002, 0000077, 001, 001 }, /* NOT */\r |
| 263 | { 0000002, 0176077, 010, 010 }, /* POK */\r |
| 264 | { 0000002, 0176077, 004, 004 }, /* LNK */\r |
| 265 | { 0000002, 0176077, 002, 002 }, /* BOV */\r |
| 266 | { 0026002, 0176077, 004, 004 }, /* SOV */\r |
| 267 | { 0026002, 0176077, 002, 002 }, /* AOV */\r |
| 268 | { 0000002, 0000077, 010, 010 }, /* IRDY */\r |
| 269 | { 0000002, 0000077, 002, 002 }, /* ORDY */\r |
| 270 | { 0004000, 0176077, 001, 003 }, /* CLL */\r |
| 271 | { 0004000, 0176077, 002, 003 }, /* STL */\r |
| 272 | { 0004000, 0176077, 003, 003 }, /* CML */\r |
| 273 | { 0004000, 0176077, 004, 004 }, /* HLT */\r |
| 274 | { 0004004, 0176077, 001, 001 }, /* ICF */\r |
| 275 | { 0004004, 0176077, 002, 002 }, /* ICO */\r |
| 276 | { 0004013, 0176077, 000, 014 }, /* ADD */\r |
| 277 | { 0004013, 0176077, 004, 014 }, /* AND */\r |
| 278 | { 0004013, 0176077, 010, 014 }, /* XOR */\r |
| 279 | { 0004013, 0176077, 014, 014 }, /* OR */\r |
| 280 | { 0004000, 0176000, 011, 011 }, /* INP */\r |
| 281 | { 0004000, 0176000, 010, 010 }, /* IRDY */\r |
| 282 | { 0004000, 0176000, 002, 002 }, /* ORDY */\r |
| 283 | { 0004000, 0176000, 001, 001 } /* STRT */\r |
| 284 | };\r |
| 285 | \r |
| 286 | /* Print opcode field for FO, SF */\r |
| 287 | \r |
| 288 | void fprint_op (FILE *of, uint32 inst, uint32 op)\r |
| 289 | {\r |
| 290 | int32 i, nfirst;\r |
| 291 | \r |
| 292 | for (i = nfirst = 0; fname[i] != NULL; i++) {\r |
| 293 | if (((inst & fop[i].imask) == fop[i].inst) &&\r |
| 294 | ((op & fop[i].omask) == fop[i].oper)) {\r |
| 295 | op = op & ~fop[i].omask;\r |
| 296 | if (nfirst) fputc (' ', of);\r |
| 297 | nfirst = 1;\r |
| 298 | fprintf (of, "%s", fname[i]);\r |
| 299 | }\r |
| 300 | }\r |
| 301 | if (op) fprintf (of, " %o", op);\r |
| 302 | return;\r |
| 303 | }\r |
| 304 | \r |
| 305 | /* Print address field with potential indexing */\r |
| 306 | \r |
| 307 | void fprint_addr (FILE *of, uint32 val, uint32 mode, uint32 dst)\r |
| 308 | {\r |
| 309 | if ((val & INDEX) &&\r |
| 310 | ((dst == U_SC) || (mode != MEM_IMM)))\r |
| 311 | fprintf (of, "#%o", val & AMASK);\r |
| 312 | else fprintf (of, "%o", val);\r |
| 313 | return;\r |
| 314 | }\r |
| 315 | \r |
| 316 | /* Symbolic decode\r |
| 317 | \r |
| 318 | Inputs:\r |
| 319 | *of = output stream\r |
| 320 | addr = current PC\r |
| 321 | *val = pointer to data\r |
| 322 | *uptr = pointer to unit \r |
| 323 | sw = switches\r |
| 324 | Outputs:\r |
| 325 | return = status code\r |
| 326 | */\r |
| 327 | \r |
| 328 | #define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)\r |
| 329 | \r |
| 330 | t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,\r |
| 331 | UNIT *uptr, int32 sw)\r |
| 332 | {\r |
| 333 | int32 i, j;\r |
| 334 | uint32 inst, src, dst, op, bop;\r |
| 335 | \r |
| 336 | inst = val[0];\r |
| 337 | if (sw & SWMASK ('A')) { /* ASCII? */\r |
| 338 | if (inst > 0377) return SCPE_ARG;\r |
| 339 | fprintf (of, FMTASC (inst & 0177));\r |
| 340 | return SCPE_OK;\r |
| 341 | }\r |
| 342 | if (sw & SWMASK ('C')) { /* characters? */\r |
| 343 | fprintf (of, FMTASC ((inst >> 8) & 0177));\r |
| 344 | fprintf (of, FMTASC (inst & 0177));\r |
| 345 | return SCPE_OK;\r |
| 346 | }\r |
| 347 | if (!(sw & SWMASK ('M'))) return SCPE_ARG;\r |
| 348 | \r |
| 349 | /* Instruction decode */\r |
| 350 | \r |
| 351 | inst = val[0];\r |
| 352 | src = I_GETSRC (inst); /* get fields */\r |
| 353 | op = I_GETOP (inst);\r |
| 354 | dst = I_GETDST (inst);\r |
| 355 | bop = op >> 2; /* bus op */\r |
| 356 | for (i = 0; opcode[i] != NULL; i++) { /* loop thru ops */\r |
| 357 | j = (opc_val[i] >> F_V_FL) & F_M_FL; /* get class */\r |
| 358 | if ((opc_val[i] & DMASK) == (inst & masks[j])) { /* match? */\r |
| 359 | \r |
| 360 | switch (j) { /* case on class */\r |
| 361 | \r |
| 362 | case F_V_FO: /* func out */\r |
| 363 | fprintf (of, "%s ", opcode[i]);\r |
| 364 | fprint_op (of, inst, op);\r |
| 365 | fprintf (of, ",%s", undst[dst]);\r |
| 366 | break;\r |
| 367 | \r |
| 368 | case F_V_FOI: /* func out impl */\r |
| 369 | fprintf (of, "%s ", opcode[i]);\r |
| 370 | fprint_op (of, inst, op);\r |
| 371 | break;\r |
| 372 | \r |
| 373 | case F_V_SF: /* skip func */\r |
| 374 | fprintf (of, "%s %s,", opcode[i], unsrc[src]);\r |
| 375 | fprint_op (of, inst, op);\r |
| 376 | break;\r |
| 377 | \r |
| 378 | case F_V_SFI: /* skip func impl */\r |
| 379 | fprintf (of, "%s ", opcode[i]);\r |
| 380 | fprint_op (of, inst, op);\r |
| 381 | break;\r |
| 382 | \r |
| 383 | case F_V_RR: /* reg reg */\r |
| 384 | if (strcmp (unsrc[src], undst[dst]) == 0) {\r |
| 385 | if (bop) fprintf (of, "%s %s,%s", opcode[i + 2],\r |
| 386 | unsrc[src], opname[bop]);\r |
| 387 | else fprintf (of, "%s %s", opcode[i + 2], unsrc[src]);\r |
| 388 | }\r |
| 389 | else {\r |
| 390 | if (bop) fprintf (of, "%s %s,%s,%s", opcode[i],\r |
| 391 | unsrc[src], opname[bop], undst[dst]);\r |
| 392 | else fprintf (of, "%s %s,%s", opcode[i],\r |
| 393 | unsrc[src], undst[dst]);\r |
| 394 | }\r |
| 395 | break;\r |
| 396 | \r |
| 397 | case F_V_ZR: /* zero reg */\r |
| 398 | if (bop) fprintf (of, "%s %s,%s", opcode[i],\r |
| 399 | opname[bop], undst[dst]);\r |
| 400 | else fprintf (of, "%s %s", opcode[i], undst[dst]);\r |
| 401 | break;\r |
| 402 | \r |
| 403 | case F_V_JC: /* jump cond */\r |
| 404 | fprintf (of, "%s %s,%s,",\r |
| 405 | opcode[i], unsrc[src], cdname[op >> 1]);\r |
| 406 | fprint_addr (of, val[1], 0, U_SC);\r |
| 407 | break;\r |
| 408 | \r |
| 409 | case F_V_JU: /* jump uncond */\r |
| 410 | fprintf (of, "%s ", opcode[i]);\r |
| 411 | fprint_addr (of, val[1], 0, U_SC);\r |
| 412 | break;\r |
| 413 | \r |
| 414 | case F_V_RM: /* reg mem */\r |
| 415 | if (bop) fprintf (of, "%s %s,%s,",\r |
| 416 | opcode[i], unsrc[src], opname[bop]);\r |
| 417 | else fprintf (of, "%s %s,", opcode[i], unsrc[src]);\r |
| 418 | fprint_addr (of, val[1], op & MEM_MOD, dst);\r |
| 419 | break;\r |
| 420 | \r |
| 421 | case F_V_ZM: /* zero mem */\r |
| 422 | if (bop) fprintf (of, "%s %s,", opcode[i], opname[bop]);\r |
| 423 | else fprintf (of, "%s ", opcode[i]);\r |
| 424 | fprint_addr (of, val[1], op & MEM_MOD, dst);\r |
| 425 | break;\r |
| 426 | \r |
| 427 | case F_V_MR: /* mem reg */\r |
| 428 | fprintf (of, "%s ", opcode[i]);\r |
| 429 | fprint_addr (of, val[1], op & MEM_MOD, dst);\r |
| 430 | if (bop) fprintf (of, ",%s,%s", opname[bop], undst[dst]);\r |
| 431 | else fprintf (of, ",%s", undst[dst]);\r |
| 432 | break;\r |
| 433 | \r |
| 434 | case F_V_MS: /* mem self */\r |
| 435 | fprintf (of, "%s ", opcode[i]);\r |
| 436 | fprint_addr (of, val[1], op & MEM_MOD, dst);\r |
| 437 | if (bop) fprintf (of, ",%s", opname[bop]);\r |
| 438 | break;\r |
| 439 | } /* end case */\r |
| 440 | \r |
| 441 | return (j >= F_2WD)? -1: SCPE_OK;\r |
| 442 | } /* end if */\r |
| 443 | } /* end for */\r |
| 444 | return SCPE_ARG;\r |
| 445 | }\r |
| 446 | \r |
| 447 | /* Field parse routines\r |
| 448 | \r |
| 449 | get_fnc get function field\r |
| 450 | get_ma get memory address\r |
| 451 | get_sd get source or dest\r |
| 452 | get_op get optional bus operator\r |
| 453 | */\r |
| 454 | \r |
| 455 | char *get_fnc (char *cptr, t_value *val)\r |
| 456 | {\r |
| 457 | char gbuf[CBUFSIZE];\r |
| 458 | int32 i;\r |
| 459 | t_value d;\r |
| 460 | t_stat r;\r |
| 461 | uint32 inst = val[0];\r |
| 462 | uint32 fncv = 0, fncm = 0;\r |
| 463 | \r |
| 464 | while (*cptr) {\r |
| 465 | cptr = get_glyph (cptr, gbuf, 0); /* get glyph */\r |
| 466 | d = get_uint (gbuf, 8, 017, &r); /* octal? */\r |
| 467 | if (r == SCPE_OK) { /* ok? */\r |
| 468 | if (d & fncm) return NULL; /* already filled? */\r |
| 469 | fncv = fncv | d; /* save */\r |
| 470 | fncm = fncm | d; /* field filled */\r |
| 471 | }\r |
| 472 | else { /* symbol? */\r |
| 473 | for (i = 0; fname[i] != NULL; i++) { /* search table */\r |
| 474 | if ((strcmp (gbuf, fname[i]) == 0) && /* match for inst? */\r |
| 475 | ((inst & fop[i].imask) == fop[i].inst)) {\r |
| 476 | if (fop[i].oper & fncm) return NULL; /* already filled? */\r |
| 477 | fncm = fncm | fop[i].omask;\r |
| 478 | fncv = fncv | fop[i].oper;\r |
| 479 | break;\r |
| 480 | }\r |
| 481 | }\r |
| 482 | if (fname[i] == NULL) return NULL;\r |
| 483 | } /* end else */\r |
| 484 | } /* end while */\r |
| 485 | val[0] = val[0] | (fncv << I_V_OP); /* store fnc */\r |
| 486 | return cptr;\r |
| 487 | }\r |
| 488 | \r |
| 489 | char *get_ma (char *cptr, t_value *val, char term)\r |
| 490 | {\r |
| 491 | char gbuf[CBUFSIZE];\r |
| 492 | t_value d;\r |
| 493 | t_stat r;\r |
| 494 | \r |
| 495 | cptr = get_glyph (cptr, gbuf, term); /* get glyph */\r |
| 496 | if (gbuf[0] == '#') /* indexed? */\r |
| 497 | d = get_uint (gbuf + 1, 8, AMASK, &r) | INDEX; /* [0, 77777] */\r |
| 498 | else d = get_uint (gbuf, 8, DMASK, &r); /* [0,177777] */\r |
| 499 | if (r != SCPE_OK) return NULL;\r |
| 500 | val[1] = d; /* second wd */\r |
| 501 | return cptr;\r |
| 502 | }\r |
| 503 | \r |
| 504 | char *get_sd (char *cptr, t_value *val, char term, t_bool src)\r |
| 505 | {\r |
| 506 | char gbuf[CBUFSIZE];\r |
| 507 | int32 d;\r |
| 508 | t_stat r;\r |
| 509 | \r |
| 510 | cptr = get_glyph (cptr, gbuf, term); /* get glyph */\r |
| 511 | for (d = 0; d < 64; d++) { /* symbol match? */\r |
| 512 | if ((strcmp (gbuf, unsrc[d]) == 0) ||\r |
| 513 | (strcmp (gbuf, undst[d]) == 0)) break;\r |
| 514 | }\r |
| 515 | if (d >= 64) { /* no, [0,63]? */\r |
| 516 | d = get_uint (gbuf, 8, 077, &r);\r |
| 517 | if (r != SCPE_OK) return NULL;\r |
| 518 | }\r |
| 519 | val[0] = val[0] | (d << (src? I_V_SRC: I_V_DST)); /* or to inst */\r |
| 520 | return cptr;\r |
| 521 | }\r |
| 522 | \r |
| 523 | char *get_op (char *cptr, t_value *val, char term)\r |
| 524 | {\r |
| 525 | char gbuf[CBUFSIZE], *tptr;\r |
| 526 | int32 i;\r |
| 527 | \r |
| 528 | tptr = get_glyph (cptr, gbuf, term); /* get glyph */\r |
| 529 | for (i = 1; i < 4; i++) { /* symbol match? */\r |
| 530 | if (strcmp (gbuf, opname[i]) == 0) {\r |
| 531 | val[0] = val[0] | (i << (I_V_OP + 2)); /* or to inst */\r |
| 532 | return tptr;\r |
| 533 | }\r |
| 534 | }\r |
| 535 | return cptr; /* original ptr */\r |
| 536 | }\r |
| 537 | \r |
| 538 | /* Symbolic input\r |
| 539 | \r |
| 540 | Inputs:\r |
| 541 | *cptr = pointer to input string\r |
| 542 | addr = current PC\r |
| 543 | *uptr = pointer to unit\r |
| 544 | *val = pointer to output values\r |
| 545 | sw = switches\r |
| 546 | Outputs:\r |
| 547 | status = error status\r |
| 548 | */\r |
| 549 | \r |
| 550 | t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)\r |
| 551 | {\r |
| 552 | int32 i, j, k;\r |
| 553 | char *tptr, gbuf[CBUFSIZE];\r |
| 554 | \r |
| 555 | while (isspace (*cptr)) cptr++; /* absorb spaces */\r |
| 556 | if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */\r |
| 557 | if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */\r |
| 558 | val[0] = (t_value) cptr[0] & 0177;\r |
| 559 | return SCPE_OK;\r |
| 560 | }\r |
| 561 | if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* char string? */\r |
| 562 | if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */\r |
| 563 | val[0] = (((t_value) cptr[0] & 0177) << 8) |\r |
| 564 | ((t_value) cptr[1] & 0177);\r |
| 565 | return SCPE_OK;\r |
| 566 | }\r |
| 567 | \r |
| 568 | /* Instruction parse */\r |
| 569 | \r |
| 570 | cptr = get_glyph (cptr, gbuf, 0); /* get opcode */\r |
| 571 | for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;\r |
| 572 | if (opcode[i] == NULL) return SCPE_ARG;\r |
| 573 | val[0] = opc_val[i] & DMASK; /* get value */\r |
| 574 | j = (opc_val[i] >> F_V_FL) & F_M_FL; /* get class */\r |
| 575 | \r |
| 576 | switch (j) { /* case on class */\r |
| 577 | \r |
| 578 | case F_V_FO: /* func out */\r |
| 579 | tptr = strchr (cptr, ','); /* find dst */\r |
| 580 | if (!tptr) return SCPE_ARG; /* none? */\r |
| 581 | *tptr = 0; /* split fields */\r |
| 582 | cptr = get_fnc (cptr, val); /* fo # */\r |
| 583 | if (!cptr) return SCPE_ARG;\r |
| 584 | cptr = get_sd (tptr + 1, val, 0, FALSE); /* dst */\r |
| 585 | break;\r |
| 586 | \r |
| 587 | case F_V_FOI: /* func out impl */\r |
| 588 | cptr = get_fnc (cptr, val); /* fo # */\r |
| 589 | break;\r |
| 590 | \r |
| 591 | case F_V_SF: /* skip func */\r |
| 592 | cptr = get_sd (cptr, val, ',', TRUE); /* src */\r |
| 593 | if (!cptr) return SCPE_ARG;\r |
| 594 | \r |
| 595 | case F_V_SFI: /* skip func impl */\r |
| 596 | cptr = get_fnc (cptr, val); /* fo # */\r |
| 597 | break;\r |
| 598 | \r |
| 599 | case F_V_RR: /* reg-reg */\r |
| 600 | cptr = get_sd (cptr, val, ',', TRUE); /* src */\r |
| 601 | if (!cptr) return SCPE_ARG;\r |
| 602 | cptr = get_op (cptr, val, ','); /* op */\r |
| 603 | if (!cptr) return SCPE_ARG;\r |
| 604 | cptr = get_sd (cptr, val, 0, FALSE); /* dst */\r |
| 605 | break;\r |
| 606 | \r |
| 607 | case F_V_ZR: /* zero-reg */\r |
| 608 | cptr = get_op (cptr, val, ','); /* op */\r |
| 609 | if (!cptr) return SCPE_ARG;\r |
| 610 | cptr = get_sd (cptr, val, 0, FALSE); /* dst */\r |
| 611 | break;\r |
| 612 | \r |
| 613 | case F_V_RS: /* reg self */\r |
| 614 | cptr = get_sd (cptr, val, ',', TRUE); /* src */\r |
| 615 | if (!cptr) return SCPE_ARG;\r |
| 616 | val[0] = val[0] | I_GETSRC (val[0]); /* duplicate */\r |
| 617 | cptr = get_op (cptr, val, 0); /* op */\r |
| 618 | break;\r |
| 619 | \r |
| 620 | case F_V_JC: /* jump cond */\r |
| 621 | cptr = get_sd (cptr, val, ',', TRUE); /* src */\r |
| 622 | if (!cptr) return SCPE_ARG;\r |
| 623 | cptr = get_glyph (cptr, gbuf, ','); /* cond */\r |
| 624 | for (k = 0; k < 8; k++) { /* symbol? */\r |
| 625 | if (strcmp (gbuf, cdname[k]) == 0) break;\r |
| 626 | }\r |
| 627 | if (k >= 8) return SCPE_ARG;\r |
| 628 | val[0] = val[0] | (k << (I_V_OP + 1)); /* or to inst */\r |
| 629 | \r |
| 630 | case F_V_JU: /* jump uncond */\r |
| 631 | cptr = get_ma (cptr, val, 0); /* addr */\r |
| 632 | break;\r |
| 633 | \r |
| 634 | case F_V_RM: /* reg mem */\r |
| 635 | cptr = get_sd (cptr, val, ',', TRUE); /* src */\r |
| 636 | if (!cptr) return SCPE_ARG;\r |
| 637 | case F_V_ZM: /* zero mem */\r |
| 638 | cptr = get_op (cptr, val, ','); /* op */\r |
| 639 | if (!cptr) return SCPE_ARG;\r |
| 640 | cptr = get_ma (cptr, val, 0); /* addr */\r |
| 641 | break;\r |
| 642 | \r |
| 643 | case F_V_MR: /* mem reg */\r |
| 644 | cptr = get_ma (cptr, val, ','); /* addr */\r |
| 645 | if (!cptr) return SCPE_ARG;\r |
| 646 | cptr = get_op (cptr, val, ','); /* op */\r |
| 647 | if (!cptr) return SCPE_ARG;\r |
| 648 | cptr = get_sd (cptr, val, 0, FALSE); /* dst */\r |
| 649 | break;\r |
| 650 | \r |
| 651 | case F_V_MS: /* mem self */\r |
| 652 | cptr = get_ma (cptr, val, ','); /* addr */\r |
| 653 | if (!cptr) return SCPE_ARG;\r |
| 654 | cptr = get_op (cptr, val, 0); /* op */\r |
| 655 | break;\r |
| 656 | } /* end case */\r |
| 657 | \r |
| 658 | if (!cptr || (*cptr != 0)) return SCPE_ARG; /* junk at end? */\r |
| 659 | return (j >= F_2WD)? -1: SCPE_OK;\r |
| 660 | }\r |