| 1 | /* vax_syscm.c: PDP-11 compatibility mode symbolic decode and parse\r |
| 2 | \r |
| 3 | Copyright (c) 1993-2006, 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 | 12-Nov-06 RMS Fixed operand order in EIS instructions (found by W.F.J. Mueller)\r |
| 27 | 27-Sep-05 RMS Fixed warnings compiling with 64b addresses\r |
| 28 | 15-Sep-04 RMS Cloned from pdp11_sys.c\r |
| 29 | */\r |
| 30 | \r |
| 31 | #include "vax_defs.h"\r |
| 32 | #include <ctype.h>\r |
| 33 | \r |
| 34 | extern UNIT cpu_unit;\r |
| 35 | \r |
| 36 | /* Symbol tables */\r |
| 37 | /* Warning: for literals, the class number MUST equal the field width!! */\r |
| 38 | \r |
| 39 | #define I_V_CL 18 /* class bits */\r |
| 40 | #define I_M_CL 017 /* class mask */\r |
| 41 | #define I_V_NPN 0 /* no operands */\r |
| 42 | #define I_V_REG 1 /* reg */\r |
| 43 | #define I_V_SOP 2 /* operand */\r |
| 44 | #define I_V_3B 3 /* 3b literal */\r |
| 45 | #define I_V_RSOP 4 /* reg, operand */\r |
| 46 | #define I_V_BR 5 /* cond branch */\r |
| 47 | #define I_V_6B 6 /* 6b literal */\r |
| 48 | #define I_V_SOB 7 /* reg, disp */\r |
| 49 | #define I_V_8B 8 /* 8b literal */\r |
| 50 | #define I_V_DOP 9 /* double operand */\r |
| 51 | #define I_V_CCC 10 /* CC clear */\r |
| 52 | #define I_V_CCS 11 /* CC set */\r |
| 53 | #define I_V_SOPR 12 /* operand, reg */\r |
| 54 | #define I_NPN (I_V_NPN << I_V_CL)\r |
| 55 | #define I_REG (I_V_REG << I_V_CL)\r |
| 56 | #define I_SOP (I_V_SOP << I_V_CL)\r |
| 57 | #define I_3B (I_V_3B << I_V_CL)\r |
| 58 | #define I_6B (I_V_6B << I_V_CL)\r |
| 59 | #define I_BR (I_V_BR << I_V_CL)\r |
| 60 | #define I_8B (I_V_8B << I_V_CL)\r |
| 61 | #define I_RSOP (I_V_RSOP << I_V_CL)\r |
| 62 | #define I_SOB (I_V_SOB << I_V_CL)\r |
| 63 | #define I_DOP (I_V_DOP << I_V_CL)\r |
| 64 | #define I_CCC (I_V_CCC << I_V_CL)\r |
| 65 | #define I_CCS (I_V_CCS << I_V_CL)\r |
| 66 | #define I_SOPR (I_V_SOPR << I_V_CL)\r |
| 67 | \r |
| 68 | static const int32 masks[] = {\r |
| 69 | 0177777, 0177770, 0177700, 0177770,\r |
| 70 | 0177000, 0177400, 0177700, 0177000,\r |
| 71 | 0177400, 0170000, 0177777, 0177777,\r |
| 72 | 0177000\r |
| 73 | };\r |
| 74 | \r |
| 75 | static const char *opcode[] = {\r |
| 76 | "HALT","WAIT","RTI","BPT",\r |
| 77 | "IOT","RESET","RTT","MFPT",\r |
| 78 | "JMP","RTS","SPL",\r |
| 79 | "NOP","CLC","CLV","CLV CLC",\r |
| 80 | "CLZ","CLZ CLC","CLZ CLV","CLZ CLV CLC",\r |
| 81 | "CLN","CLN CLC","CLN CLV","CLN CLV CLC",\r |
| 82 | "CLN CLZ","CLN CLZ CLC","CLN CLZ CLC","CCC",\r |
| 83 | "NOP","SEC","SEV","SEV SEC",\r |
| 84 | "SEZ","SEZ SEC","SEZ SEV","SEZ SEV SEC",\r |
| 85 | "SEN","SEN SEC","SEN SEV","SEN SEV SEC",\r |
| 86 | "SEN SEZ","SEN SEZ SEC","SEN SEZ SEC","SCC",\r |
| 87 | "SWAB","BR","BNE","BEQ",\r |
| 88 | "BGE","BLT","BGT","BLE",\r |
| 89 | "JSR",\r |
| 90 | "CLR","COM","INC","DEC",\r |
| 91 | "NEG","ADC","SBC","TST",\r |
| 92 | "ROR","ROL","ASR","ASL",\r |
| 93 | "MARK","MFPI","MTPI","SXT",\r |
| 94 | "CSM", "TSTSET","WRTLCK",\r |
| 95 | "MOV","CMP","BIT","BIC",\r |
| 96 | "BIS","ADD",\r |
| 97 | "MUL","DIV","ASH","ASHC",\r |
| 98 | "XOR",\r |
| 99 | "FADD","FSUB","FMUL","FDIV",\r |
| 100 | "L2DR",\r |
| 101 | "MOVC","MOVRC","MOVTC",\r |
| 102 | "LOCC","SKPC","SCANC","SPANC",\r |
| 103 | "CMPC","MATC",\r |
| 104 | "ADDN","SUBN","CMPN","CVTNL",\r |
| 105 | "CVTPN","CVTNP","ASHN","CVTLN",\r |
| 106 | "L3DR",\r |
| 107 | "ADDP","SUBP","CMPP","CVTPL",\r |
| 108 | "MULP","DIVP","ASHP","CVTLP",\r |
| 109 | "MOVCI","MOVRCI","MOVTCI",\r |
| 110 | "LOCCI","SKPCI","SCANCI","SPANCI",\r |
| 111 | "CMPCI","MATCI",\r |
| 112 | "ADDNI","SUBNI","CMPNI","CVTNLI",\r |
| 113 | "CVTPNI","CVTNPI","ASHNI","CVTLNI",\r |
| 114 | "ADDPI","SUBPI","CMPPI","CVTPLI",\r |
| 115 | "MULPI","DIVPI","ASHPI","CVTLPI",\r |
| 116 | "SOB",\r |
| 117 | "BPL","BMI","BHI","BLOS",\r |
| 118 | "BVC","BVS","BCC","BCS",\r |
| 119 | "BHIS","BLO", /* encode only */\r |
| 120 | "EMT","TRAP",\r |
| 121 | "CLRB","COMB","INCB","DECB",\r |
| 122 | "NEGB","ADCB","SBCB","TSTB",\r |
| 123 | "RORB","ROLB","ASRB","ASLB",\r |
| 124 | "MTPS","MFPD","MTPD","MFPS",\r |
| 125 | "MOVB","CMPB","BITB","BICB",\r |
| 126 | "BISB","SUB",\r |
| 127 | NULL\r |
| 128 | };\r |
| 129 | \r |
| 130 | static const int32 opc_val[] = {\r |
| 131 | 0000000+I_NPN, 0000001+I_NPN, 0000002+I_NPN, 0000003+I_NPN,\r |
| 132 | 0000004+I_NPN, 0000005+I_NPN, 0000006+I_NPN, 0000007+I_NPN,\r |
| 133 | 0000100+I_SOP, 0000200+I_REG, 0000230+I_3B,\r |
| 134 | 0000240+I_CCC, 0000241+I_CCC, 0000242+I_CCC, 0000243+I_NPN, \r |
| 135 | 0000244+I_CCC, 0000245+I_NPN, 0000246+I_NPN, 0000247+I_NPN, \r |
| 136 | 0000250+I_CCC, 0000251+I_NPN, 0000252+I_NPN, 0000253+I_NPN, \r |
| 137 | 0000254+I_NPN, 0000255+I_NPN, 0000256+I_NPN, 0000257+I_CCC, \r |
| 138 | 0000260+I_CCS, 0000261+I_CCS, 0000262+I_CCS, 0000263+I_NPN, \r |
| 139 | 0000264+I_CCS, 0000265+I_NPN, 0000266+I_NPN, 0000267+I_NPN, \r |
| 140 | 0000270+I_CCS, 0000271+I_NPN, 0000272+I_NPN, 0000273+I_NPN, \r |
| 141 | 0000274+I_NPN, 0000275+I_NPN, 0000276+I_NPN, 0000277+I_CCS, \r |
| 142 | 0000300+I_SOP, 0000400+I_BR, 0001000+I_BR, 0001400+I_BR,\r |
| 143 | 0002000+I_BR, 0002400+I_BR, 0003000+I_BR, 0003400+I_BR,\r |
| 144 | 0004000+I_RSOP,\r |
| 145 | 0005000+I_SOP, 0005100+I_SOP, 0005200+I_SOP, 0005300+I_SOP,\r |
| 146 | 0005400+I_SOP, 0005500+I_SOP, 0005600+I_SOP, 0005700+I_SOP,\r |
| 147 | 0006000+I_SOP, 0006100+I_SOP, 0006200+I_SOP, 0006300+I_SOP,\r |
| 148 | 0006400+I_6B, 0006500+I_SOP, 0006600+I_SOP, 0006700+I_SOP,\r |
| 149 | 0007000+I_SOP, 0007200+I_SOP, 0007300+I_SOP,\r |
| 150 | 0010000+I_DOP, 0020000+I_DOP, 0030000+I_DOP, 0040000+I_DOP,\r |
| 151 | 0050000+I_DOP, 0060000+I_DOP,\r |
| 152 | 0070000+I_SOPR, 0071000+I_SOPR, 0072000+I_SOPR, 0073000+I_SOPR,\r |
| 153 | 0074000+I_RSOP,\r |
| 154 | 0075000+I_REG, 0075010+I_REG, 0075020+I_REG, 0075030+I_REG,\r |
| 155 | 0076020+I_REG,\r |
| 156 | 0076030+I_NPN, 0076031+I_NPN, 0076032+I_NPN,\r |
| 157 | 0076040+I_NPN, 0076041+I_NPN, 0076042+I_NPN, 0076043+I_NPN,\r |
| 158 | 0076044+I_NPN, 0076045+I_NPN, \r |
| 159 | 0076050+I_NPN, 0076051+I_NPN, 0076052+I_NPN, 0076053+I_NPN,\r |
| 160 | 0076054+I_NPN, 0076055+I_NPN, 0076056+I_NPN, 0076057+I_NPN,\r |
| 161 | 0076060+I_REG,\r |
| 162 | 0076070+I_NPN, 0076071+I_NPN, 0076072+I_NPN, 0076073+I_NPN,\r |
| 163 | 0076074+I_NPN, 0076075+I_NPN, 0076076+I_NPN, 0076077+I_NPN,\r |
| 164 | 0076130+I_NPN, 0076131+I_NPN, 0076132+I_NPN,\r |
| 165 | 0076140+I_NPN, 0076141+I_NPN, 0076142+I_NPN, 0076143+I_NPN,\r |
| 166 | 0076144+I_NPN, 0076145+I_NPN, \r |
| 167 | 0076150+I_NPN, 0076151+I_NPN, 0076152+I_NPN, 0076153+I_NPN,\r |
| 168 | 0076154+I_NPN, 0076155+I_NPN, 0076156+I_NPN, 0076157+I_NPN,\r |
| 169 | 0076170+I_NPN, 0076171+I_NPN, 0076172+I_NPN, 0076173+I_NPN,\r |
| 170 | 0076174+I_NPN, 0076175+I_NPN, 0076176+I_NPN, 0076177+I_NPN,\r |
| 171 | 0077000+I_SOB,\r |
| 172 | 0100000+I_BR, 0100400+I_BR, 0101000+I_BR, 0101400+I_BR,\r |
| 173 | 0102000+I_BR, 0102400+I_BR, 0103000+I_BR, 0103400+I_BR,\r |
| 174 | 0103000+I_BR, 0103400+I_BR,\r |
| 175 | 0104000+I_8B, 0104400+I_8B,\r |
| 176 | 0105000+I_SOP, 0105100+I_SOP, 0105200+I_SOP, 0105300+I_SOP,\r |
| 177 | 0105400+I_SOP, 0105500+I_SOP, 0105600+I_SOP, 0105700+I_SOP,\r |
| 178 | 0106000+I_SOP, 0106100+I_SOP, 0106200+I_SOP, 0106300+I_SOP,\r |
| 179 | 0106400+I_SOP, 0106500+I_SOP, 0106600+I_SOP, 0106700+I_SOP,\r |
| 180 | 0110000+I_DOP, 0120000+I_DOP, 0130000+I_DOP, 0140000+I_DOP,\r |
| 181 | 0150000+I_DOP, 0160000+I_DOP,\r |
| 182 | -1\r |
| 183 | };\r |
| 184 | \r |
| 185 | static const char *rname [] = {\r |
| 186 | "R0", "R1", "R2", "R3", "R4", "R5", "SP", "PC"\r |
| 187 | };\r |
| 188 | \r |
| 189 | static const char r50_to_asc[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789";\r |
| 190 | \r |
| 191 | /* Specifier decode\r |
| 192 | \r |
| 193 | Inputs:\r |
| 194 | *of = output stream\r |
| 195 | addr = current PC\r |
| 196 | spec = specifier\r |
| 197 | nval = next word\r |
| 198 | flag = TRUE if decoding for CPU\r |
| 199 | iflag = TRUE if decoding integer instruction\r |
| 200 | Outputs:\r |
| 201 | count = -number of extra words retired\r |
| 202 | */\r |
| 203 | \r |
| 204 | int32 fprint_spec (FILE *of, t_addr addr, int32 spec, int32 nval)\r |
| 205 | {\r |
| 206 | int32 reg, mode;\r |
| 207 | static const int32 rgwd[8] = { 0, 0, 0, 0, 0, 0, -1, -1 };\r |
| 208 | static const int32 pcwd[8] = { 0, 0, -1, -1, 0, 0, -1, -1 };\r |
| 209 | \r |
| 210 | reg = spec & 07;\r |
| 211 | mode = ((spec >> 3) & 07);\r |
| 212 | switch (mode) {\r |
| 213 | \r |
| 214 | case 0:\r |
| 215 | fprintf (of, "%s", rname[reg]);\r |
| 216 | break;\r |
| 217 | \r |
| 218 | case 1:\r |
| 219 | fprintf (of, "(%s)", rname[reg]);\r |
| 220 | break;\r |
| 221 | \r |
| 222 | case 2:\r |
| 223 | if (reg != 7) fprintf (of, "(%s)+", rname[reg]);\r |
| 224 | else fprintf (of, "#%-X", nval);\r |
| 225 | break;\r |
| 226 | \r |
| 227 | case 3:\r |
| 228 | if (reg != 7) fprintf (of, "@(%s)+", rname[reg]);\r |
| 229 | else fprintf (of, "@#%-X", nval);\r |
| 230 | break;\r |
| 231 | \r |
| 232 | case 4:\r |
| 233 | fprintf (of, "-(%s)", rname[reg]);\r |
| 234 | break;\r |
| 235 | \r |
| 236 | case 5:\r |
| 237 | fprintf (of, "@-(%s)", rname[reg]);\r |
| 238 | break;\r |
| 239 | \r |
| 240 | case 6:\r |
| 241 | if (reg != 7) fprintf (of, "%-X(%s)", nval, rname[reg]);\r |
| 242 | else fprintf (of, "%-X", (nval + addr + 4) & 0177777);\r |
| 243 | break;\r |
| 244 | \r |
| 245 | case 7:\r |
| 246 | if (reg != 7) fprintf (of, "@%-X(%s)", nval, rname[reg]);\r |
| 247 | else fprintf (of, "@%-X", (nval + addr + 4) & 0177777);\r |
| 248 | break;\r |
| 249 | } /* end case */\r |
| 250 | \r |
| 251 | return ((reg == 07)? pcwd[mode]: rgwd[mode]);\r |
| 252 | }\r |
| 253 | \r |
| 254 | /* Symbolic decode\r |
| 255 | \r |
| 256 | Inputs:\r |
| 257 | *of = output stream\r |
| 258 | addr = current PC\r |
| 259 | *val = values to decode\r |
| 260 | *uptr = pointer to unit\r |
| 261 | sw = switches\r |
| 262 | Outputs:\r |
| 263 | return = if >= 0, error code\r |
| 264 | if < 0, number of extra words retired\r |
| 265 | */\r |
| 266 | \r |
| 267 | t_stat fprint_sym_cm (FILE *of, t_addr addr, t_value *bytes, int32 sw)\r |
| 268 | {\r |
| 269 | int32 i, j, c1, c2, c3, inst, srcm, srcr, dstm, dstr;\r |
| 270 | int32 l8b, brdisp, wd1;\r |
| 271 | uint32 val[3];\r |
| 272 | \r |
| 273 | for (i = j = 0; i < 3; i++, j = j + 2)\r |
| 274 | val[i] = (int32) (bytes[j] | (bytes[j + 1] << 8));\r |
| 275 | \r |
| 276 | if (sw & SWMASK ('R')) { /* radix 50? */\r |
| 277 | if (val[0] > 0174777) return SCPE_ARG; /* max value */\r |
| 278 | c3 = val[0] % 050;\r |
| 279 | c2 = (val[0] / 050) % 050;\r |
| 280 | c1 = val[0] / (050 * 050);\r |
| 281 | fprintf (of, "%c%c%c", r50_to_asc[c1],\r |
| 282 | r50_to_asc[c2], r50_to_asc[c3]);\r |
| 283 | return -1;\r |
| 284 | }\r |
| 285 | if (!(sw & SWMASK ('P')) || (addr & 1) || (addr > WMASK))\r |
| 286 | return SCPE_ARG;\r |
| 287 | \r |
| 288 | inst = val[0]; /* inst */\r |
| 289 | wd1 = 0;\r |
| 290 | for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */\r |
| 291 | j = (opc_val[i] >> I_V_CL) & I_M_CL; /* get class */\r |
| 292 | if ((opc_val[i] & 0177777) == (inst & masks[j])) { /* match? */\r |
| 293 | srcm = (inst >> 6) & 077; /* opr fields */\r |
| 294 | srcr = srcm & 07;\r |
| 295 | dstm = inst & 077;\r |
| 296 | dstr = dstm & 07;\r |
| 297 | l8b = inst & 0377;\r |
| 298 | switch (j) { /* case on class */\r |
| 299 | \r |
| 300 | case I_V_NPN: case I_V_CCC: case I_V_CCS: /* no operands */\r |
| 301 | fprintf (of, "%s", opcode[i]);\r |
| 302 | break;\r |
| 303 | \r |
| 304 | case I_V_REG: /* reg */\r |
| 305 | fprintf (of, "%s %-s", opcode[i], rname[dstr]);\r |
| 306 | break;\r |
| 307 | \r |
| 308 | case I_V_SOP: /* sop */\r |
| 309 | fprintf (of, "%s ", opcode[i]);\r |
| 310 | wd1 = fprint_spec (of, addr, dstm, val[1]);\r |
| 311 | break;\r |
| 312 | \r |
| 313 | case I_V_3B: /* 3b */\r |
| 314 | fprintf (of, "%s %-X", opcode[i], dstr);\r |
| 315 | break;\r |
| 316 | \r |
| 317 | case I_V_6B: /* 6b */\r |
| 318 | fprintf (of, "%s %-X", opcode[i], dstm);\r |
| 319 | break;\r |
| 320 | \r |
| 321 | case I_V_BR: /* cond branch */\r |
| 322 | fprintf (of, "%s ", opcode[i]);\r |
| 323 | brdisp = (l8b + l8b + ((l8b & 0200)? 0177002: 2)) & 0177777;\r |
| 324 | fprintf (of, "%-X", (addr + brdisp) & 0177777);\r |
| 325 | break;\r |
| 326 | \r |
| 327 | case I_V_8B: /* 8b */\r |
| 328 | fprintf (of, "%s %-X", opcode[i], l8b);\r |
| 329 | break;\r |
| 330 | \r |
| 331 | case I_V_SOB: /* sob */\r |
| 332 | fprintf (of, "%s %s,", opcode[i], rname[srcr]);\r |
| 333 | brdisp = (dstm * 2) - 2;\r |
| 334 | fprintf (of, "%-X", (addr - brdisp) & 0177777);\r |
| 335 | break;\r |
| 336 | \r |
| 337 | case I_V_RSOP: /* rsop */\r |
| 338 | fprintf (of, "%s %s,", opcode[i], rname[srcr]);\r |
| 339 | wd1 = fprint_spec (of, addr, dstm, val[1]);\r |
| 340 | break;\r |
| 341 | \r |
| 342 | case I_V_SOPR: /* sopr */\r |
| 343 | fprintf (of, "%s ", opcode[i]);\r |
| 344 | wd1 = fprint_spec (of, addr, dstm, val[1]);\r |
| 345 | fprintf (of, ",%s", rname[srcr]);\r |
| 346 | break;\r |
| 347 | \r |
| 348 | case I_V_DOP: /* dop */\r |
| 349 | fprintf (of, "%s ", opcode[i]);\r |
| 350 | wd1 = fprint_spec (of, addr, srcm, val[1]);\r |
| 351 | fprintf (of, ",");\r |
| 352 | wd1 += fprint_spec (of, addr - wd1 - wd1, dstm,\r |
| 353 | val[1 - wd1]);\r |
| 354 | break;\r |
| 355 | } /* end case */\r |
| 356 | \r |
| 357 | return ((wd1 * 2) - 1);\r |
| 358 | } /* end if */\r |
| 359 | } /* end for */\r |
| 360 | return SCPE_ARG; /* no match */\r |
| 361 | }\r |
| 362 | \r |
| 363 | #define A_PND 100 /* # seen */\r |
| 364 | #define A_MIN 040 /* -( seen */\r |
| 365 | #define A_PAR 020 /* (Rn) seen */\r |
| 366 | #define A_REG 010 /* Rn seen */\r |
| 367 | #define A_PLS 004 /* + seen */\r |
| 368 | #define A_NUM 002 /* number seen */\r |
| 369 | #define A_REL 001 /* relative addr seen */\r |
| 370 | \r |
| 371 | /* Register number\r |
| 372 | \r |
| 373 | Inputs:\r |
| 374 | *cptr = pointer to input string\r |
| 375 | mchar = character to match after register name\r |
| 376 | Outputs:\r |
| 377 | rnum = 0..7 if a legitimate register\r |
| 378 | < 0 if error\r |
| 379 | */\r |
| 380 | \r |
| 381 | int32 get_reg (char *cptr, char mchar)\r |
| 382 | {\r |
| 383 | int32 i;\r |
| 384 | \r |
| 385 | if (*(cptr + 2) != mchar) return -1;\r |
| 386 | for (i = 0; i < 8; i++) {\r |
| 387 | if (strncmp (cptr, rname[i], 2) == 0) return i;\r |
| 388 | }\r |
| 389 | return -1;\r |
| 390 | }\r |
| 391 | \r |
| 392 | /* Number or memory address\r |
| 393 | \r |
| 394 | Inputs:\r |
| 395 | *cptr = pointer to input string\r |
| 396 | *dptr = pointer to output displacement\r |
| 397 | *pflag = pointer to accumulating flags\r |
| 398 | Outputs:\r |
| 399 | cptr = pointer to next character in input string\r |
| 400 | NULL if parsing error\r |
| 401 | \r |
| 402 | Flags: 0 (no result), A_NUM (number), A_REL (relative)\r |
| 403 | */\r |
| 404 | \r |
| 405 | char *get_addr (char *cptr, int32 *dptr, int32 *pflag)\r |
| 406 | {\r |
| 407 | int32 val, minus;\r |
| 408 | char *tptr;\r |
| 409 | \r |
| 410 | minus = 0;\r |
| 411 | \r |
| 412 | if (*cptr == '.') { /* relative? */\r |
| 413 | *pflag = *pflag | A_REL;\r |
| 414 | cptr++;\r |
| 415 | }\r |
| 416 | if (*cptr == '+') { /* +? */\r |
| 417 | *pflag = *pflag | A_NUM;\r |
| 418 | cptr++;\r |
| 419 | }\r |
| 420 | if (*cptr == '-') { /* -? */\r |
| 421 | *pflag = *pflag | A_NUM;\r |
| 422 | minus = 1;\r |
| 423 | cptr++;\r |
| 424 | }\r |
| 425 | errno = 0;\r |
| 426 | val = strtoul (cptr, &tptr, 16);\r |
| 427 | if (cptr == tptr) { /* no number? */\r |
| 428 | if (*pflag == (A_REL + A_NUM)) return NULL; /* .+, .-? */\r |
| 429 | *dptr = 0;\r |
| 430 | return cptr;\r |
| 431 | }\r |
| 432 | if (errno || (*pflag == A_REL)) return NULL; /* .n? */\r |
| 433 | *dptr = (minus? -val: val) & 0177777;\r |
| 434 | *pflag = *pflag | A_NUM;\r |
| 435 | return tptr;\r |
| 436 | }\r |
| 437 | \r |
| 438 | /* Specifier decode\r |
| 439 | \r |
| 440 | Inputs:\r |
| 441 | *cptr = pointer to input string\r |
| 442 | addr = current PC\r |
| 443 | n1 = 0 if no extra word used\r |
| 444 | -1 if extra word used in prior decode\r |
| 445 | *sptr = pointer to output specifier\r |
| 446 | *dptr = pointer to output displacement\r |
| 447 | Outputs:\r |
| 448 | status = = -1 extra word decoded\r |
| 449 | = 0 ok\r |
| 450 | = +1 error\r |
| 451 | */\r |
| 452 | \r |
| 453 | t_stat get_spec (char *cptr, int32 addr, int32 n1, int32 *sptr, int32 *dptr)\r |
| 454 | {\r |
| 455 | int32 reg, indir, pflag, disp;\r |
| 456 | \r |
| 457 | indir = 0; /* no indirect */\r |
| 458 | pflag = 0;\r |
| 459 | \r |
| 460 | if (*cptr == '@') { /* indirect? */\r |
| 461 | indir = 010;\r |
| 462 | cptr++;\r |
| 463 | }\r |
| 464 | if (*cptr == '#') { /* literal? */\r |
| 465 | pflag = pflag | A_PND;\r |
| 466 | cptr++;\r |
| 467 | }\r |
| 468 | if (strncmp (cptr, "-(", 2) == 0) { /* autodecrement? */\r |
| 469 | pflag = pflag | A_MIN;\r |
| 470 | cptr++;\r |
| 471 | }\r |
| 472 | else if ((cptr = get_addr (cptr, &disp, &pflag)) == NULL) return 1;\r |
| 473 | if (*cptr == '(') { /* register index? */\r |
| 474 | pflag = pflag | A_PAR;\r |
| 475 | if ((reg = get_reg (cptr + 1, ')')) < 0) return 1;\r |
| 476 | cptr = cptr + 4;\r |
| 477 | if (*cptr == '+') { /* autoincrement? */\r |
| 478 | pflag = pflag | A_PLS;\r |
| 479 | cptr++;\r |
| 480 | }\r |
| 481 | }\r |
| 482 | else if ((reg = get_reg (cptr, 0)) >= 0) {\r |
| 483 | pflag = pflag | A_REG;\r |
| 484 | cptr = cptr + 2;\r |
| 485 | }\r |
| 486 | if (*cptr != 0) return 1; /* all done? */\r |
| 487 | \r |
| 488 | switch (pflag) { /* case on syntax */\r |
| 489 | \r |
| 490 | case A_REG: /* Rn, @Rn */\r |
| 491 | *sptr = indir + reg;\r |
| 492 | return 0;\r |
| 493 | \r |
| 494 | case A_PAR: /* (Rn), @(Rn) */\r |
| 495 | if (indir) { /* @(Rn) = @0(Rn) */\r |
| 496 | *sptr = 070 + reg;\r |
| 497 | *dptr = 0;\r |
| 498 | return -1;\r |
| 499 | }\r |
| 500 | else *sptr = 010 + reg;\r |
| 501 | return 0;\r |
| 502 | \r |
| 503 | case A_PAR+A_PLS: /* (Rn)+, @(Rn)+ */\r |
| 504 | *sptr = 020 + indir + reg;\r |
| 505 | return 0;\r |
| 506 | \r |
| 507 | case A_MIN+A_PAR: /* -(Rn), @-(Rn) */\r |
| 508 | *sptr = 040 + indir + reg;\r |
| 509 | return 0;\r |
| 510 | \r |
| 511 | case A_NUM+A_PAR: /* d(Rn), @d(Rn) */\r |
| 512 | *sptr = 060 + indir + reg;\r |
| 513 | *dptr = disp;\r |
| 514 | return -1;\r |
| 515 | \r |
| 516 | case A_PND+A_REL: case A_PND+A_REL+A_NUM: /* #.+n, @#.+n */\r |
| 517 | disp = (disp + addr) & 0177777; /* fall through */\r |
| 518 | case A_PND+A_NUM: /* #n, @#n */\r |
| 519 | *sptr = 027 + indir;\r |
| 520 | *dptr = disp;\r |
| 521 | return -1;\r |
| 522 | \r |
| 523 | case A_REL: case A_REL+A_NUM: /* .+n, @.+n */\r |
| 524 | *sptr = 067 + indir;\r |
| 525 | *dptr = (disp - 4 + (2 * n1)) & 0177777;\r |
| 526 | return -1;\r |
| 527 | \r |
| 528 | case A_NUM: /* n, @n */\r |
| 529 | *sptr = 067 + indir;\r |
| 530 | *dptr = (disp - addr - 4 + (2 * n1)) & 0177777;\r |
| 531 | return -1;\r |
| 532 | \r |
| 533 | default:\r |
| 534 | return 1;\r |
| 535 | } /* end case */\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 = > 0 error code\r |
| 548 | <= 0 -number of extra words\r |
| 549 | */\r |
| 550 | \r |
| 551 | t_stat parse_sym_cm (char *cptr, t_addr addr, t_value *bytes, int32 sw)\r |
| 552 | {\r |
| 553 | int32 d, i, j, reg, spec, n1, n2, disp, pflag;\r |
| 554 | int32 val[3];\r |
| 555 | int32 ad32 = (int32) addr;\r |
| 556 | t_stat r;\r |
| 557 | char *tptr, gbuf[CBUFSIZE];\r |
| 558 | \r |
| 559 | if (sw & SWMASK ('R')) return SCPE_ARG; /* radix 50 */\r |
| 560 | if (!(sw & SWMASK ('P')) || (ad32 & 1) || (ad32 > WMASK))\r |
| 561 | return SCPE_ARG;\r |
| 562 | \r |
| 563 | cptr = get_glyph (cptr, gbuf, 0); /* get opcode */\r |
| 564 | n1 = n2 = pflag = 0;\r |
| 565 | for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;\r |
| 566 | if (opcode[i] == NULL) return SCPE_ARG;\r |
| 567 | val[0] = opc_val[i] & 0177777; /* get value */\r |
| 568 | j = (opc_val[i] >> I_V_CL) & I_M_CL; /* get class */\r |
| 569 | \r |
| 570 | switch (j) { /* case on class */\r |
| 571 | \r |
| 572 | case I_V_NPN: /* no operand */\r |
| 573 | break;\r |
| 574 | \r |
| 575 | case I_V_REG: /* register */\r |
| 576 | cptr = get_glyph (cptr, gbuf, 0); /* get glyph */\r |
| 577 | if ((reg = get_reg (gbuf, 0)) < 0) return SCPE_ARG;\r |
| 578 | val[0] = val[0] | reg;\r |
| 579 | break;\r |
| 580 | \r |
| 581 | case I_V_3B: case I_V_6B: case I_V_8B: /* xb literal */\r |
| 582 | cptr = get_glyph (cptr, gbuf, 0); /* get literal */\r |
| 583 | d = (int32) get_uint (gbuf, 16, (1 << j) - 1, &r);\r |
| 584 | if (r != SCPE_OK) return SCPE_ARG;\r |
| 585 | val[0] = val[0] | d; /* put in place */\r |
| 586 | break;\r |
| 587 | \r |
| 588 | case I_V_BR: /* cond br */\r |
| 589 | cptr = get_glyph (cptr, gbuf, 0); /* get address */\r |
| 590 | tptr = get_addr (gbuf, &disp, &pflag); /* parse */\r |
| 591 | if ((tptr == NULL) || (*tptr != 0)) return SCPE_ARG;\r |
| 592 | if ((pflag & A_REL) == 0)\r |
| 593 | disp = (disp - ad32) & 0177777;\r |
| 594 | if ((disp & 1) || (disp > 0400) && (disp < 0177402)) return SCPE_ARG;\r |
| 595 | val[0] = val[0] | (((disp - 2) >> 1) & 0377);\r |
| 596 | break;\r |
| 597 | \r |
| 598 | case I_V_SOB: /* sob */\r |
| 599 | cptr = get_glyph (cptr, gbuf, ','); /* get glyph */\r |
| 600 | if ((reg = get_reg (gbuf, 0)) < 0) return SCPE_ARG;\r |
| 601 | val[0] = val[0] | (reg << 6);\r |
| 602 | cptr = get_glyph (cptr, gbuf, 0); /* get address */\r |
| 603 | tptr = get_addr (gbuf, &disp, &pflag); /* parse */\r |
| 604 | if ((tptr == NULL) || (*tptr != 0)) return SCPE_ARG;\r |
| 605 | if ((pflag & A_REL) == 0)\r |
| 606 | disp = (disp - ad32) & 0177777;\r |
| 607 | if ((disp & 1) || ((disp > 2) && (disp < 0177604))) return SCPE_ARG;\r |
| 608 | val[0] = val[0] | (((2 - disp) >> 1) & 077);\r |
| 609 | break;\r |
| 610 | \r |
| 611 | case I_V_RSOP: /* reg, sop */\r |
| 612 | cptr = get_glyph (cptr, gbuf, ','); /* get glyph */\r |
| 613 | if ((reg = get_reg (gbuf, 0)) < 0) return SCPE_ARG;\r |
| 614 | val[0] = val[0] | (reg << 6); /* fall through */\r |
| 615 | case I_V_SOP: /* sop */\r |
| 616 | cptr = get_glyph (cptr, gbuf, 0); /* get glyph */\r |
| 617 | if ((n1 = get_spec (gbuf, ad32, 0, &spec, &val[1])) > 0)\r |
| 618 | return SCPE_ARG;\r |
| 619 | val[0] = val[0] | spec;\r |
| 620 | break;\r |
| 621 | \r |
| 622 | case I_V_SOPR: /* dop, reg */\r |
| 623 | cptr = get_glyph (cptr, gbuf, ','); /* get glyph */\r |
| 624 | if ((n1 = get_spec (gbuf, ad32, 0, &spec, &val[1])) > 0)\r |
| 625 | return SCPE_ARG;\r |
| 626 | val[0] = val[0] | spec;\r |
| 627 | cptr = get_glyph (cptr, gbuf, 0); /* get glyph */\r |
| 628 | if ((reg = get_reg (gbuf, 0)) < 0) return SCPE_ARG;\r |
| 629 | val[0] = val[0] | (reg << 6);\r |
| 630 | break;\r |
| 631 | \r |
| 632 | case I_V_DOP: /* double op */\r |
| 633 | cptr = get_glyph (cptr, gbuf, ','); /* get glyph */\r |
| 634 | if ((n1 = get_spec (gbuf, ad32, 0, &spec, &val[1])) > 0)\r |
| 635 | return SCPE_ARG;\r |
| 636 | val[0] = val[0] | (spec << 6);\r |
| 637 | cptr = get_glyph (cptr, gbuf, 0); /* get glyph */\r |
| 638 | if ((n2 = get_spec (gbuf, ad32, n1, &spec, &val[1 - n1])) > 0)\r |
| 639 | return SCPE_ARG;\r |
| 640 | val[0] = val[0] | spec;\r |
| 641 | break;\r |
| 642 | \r |
| 643 | case I_V_CCC: case I_V_CCS: /* cond code oper */\r |
| 644 | for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;\r |
| 645 | cptr = get_glyph (cptr, gbuf, 0)) {\r |
| 646 | for (i = 0; (opcode[i] != NULL) &&\r |
| 647 | (strcmp (opcode[i], gbuf) != 0) ; i++) ;\r |
| 648 | if ((((opc_val[i] >> I_V_CL) & I_M_CL) != j) ||\r |
| 649 | (opcode[i] == NULL)) return SCPE_ARG;\r |
| 650 | val[0] = val[0] | (opc_val[i] & 0177777);\r |
| 651 | }\r |
| 652 | break;\r |
| 653 | \r |
| 654 | default:\r |
| 655 | return SCPE_ARG;\r |
| 656 | }\r |
| 657 | \r |
| 658 | if (*cptr != 0) return SCPE_ARG; /* junk at end? */\r |
| 659 | for (i = j = 0; i < 3; i++, j = j + 2) {\r |
| 660 | bytes[j] = val[i] & BMASK;\r |
| 661 | bytes[j + 1] = (val[i] >> 8) & BMASK;\r |
| 662 | }\r |
| 663 | return ((2 * (n1 + n2)) - 1);\r |
| 664 | }\r |