| 1 | /* pdp8_sys.c: PDP-8 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-Jun-08 RMS Fixed bug in new rim loader (found by Don North)\r |
| 27 | 24-May-08 RMS Fixed signed/unsigned declaration inconsistency\r |
| 28 | 03-Sep-07 RMS Added FPP8 support\r |
| 29 | Rewrote rim and binary loaders\r |
| 30 | 15-Dec-06 RMS Added TA8E support, IOT disambiguation\r |
| 31 | 30-Oct-06 RMS Added infinite loop stop\r |
| 32 | 18-Oct-06 RMS Re-ordered device list\r |
| 33 | 17-Oct-03 RMS Added TSC8-75, TD8E support, DECtape off reel message\r |
| 34 | 25-Apr-03 RMS Revised for extended file support\r |
| 35 | 30-Dec-01 RMS Revised for new TTX\r |
| 36 | 26-Nov-01 RMS Added RL8A support\r |
| 37 | 17-Sep-01 RMS Removed multiconsole support\r |
| 38 | 16-Sep-01 RMS Added TSS/8 packed char support, added KL8A support\r |
| 39 | 27-May-01 RMS Added multiconsole support\r |
| 40 | 18-Mar-01 RMS Added DF32 support\r |
| 41 | 14-Mar-01 RMS Added extension detection of RIM binary tapes\r |
| 42 | 15-Feb-01 RMS Added DECtape support\r |
| 43 | 30-Oct-00 RMS Added support for examine to file\r |
| 44 | 27-Oct-98 RMS V2.4 load interface\r |
| 45 | 10-Apr-98 RMS Added RIM loader support\r |
| 46 | 17-Feb-97 RMS Fixed bug in handling of bin loader fields\r |
| 47 | */\r |
| 48 | \r |
| 49 | #include "pdp8_defs.h"\r |
| 50 | #include <ctype.h>\r |
| 51 | \r |
| 52 | extern DEVICE cpu_dev;\r |
| 53 | extern UNIT cpu_unit;\r |
| 54 | extern DEVICE tsc_dev;\r |
| 55 | extern DEVICE ptr_dev, ptp_dev;\r |
| 56 | extern DEVICE tti_dev, tto_dev;\r |
| 57 | extern DEVICE clk_dev, lpt_dev;\r |
| 58 | extern DEVICE rk_dev, rl_dev;\r |
| 59 | extern DEVICE rx_dev;\r |
| 60 | extern DEVICE df_dev, rf_dev;\r |
| 61 | extern DEVICE dt_dev, td_dev;\r |
| 62 | extern DEVICE mt_dev, ct_dev;\r |
| 63 | extern DEVICE ttix_dev, ttox_dev;\r |
| 64 | extern REG cpu_reg[];\r |
| 65 | extern uint16 M[];\r |
| 66 | extern int32 sim_switches;\r |
| 67 | \r |
| 68 | t_stat fprint_sym_fpp (FILE *of, t_value *val);\r |
| 69 | t_stat parse_sym_fpp (char *cptr, t_value *val);\r |
| 70 | char *parse_field (char *cptr, uint32 max, uint32 *val, uint32 c);\r |
| 71 | char *parse_fpp_xr (char *cptr, uint32 *xr, t_bool inc);\r |
| 72 | int32 test_fpp_addr (uint32 ad, uint32 max);\r |
| 73 | \r |
| 74 | /* SCP data structures and interface routines\r |
| 75 | \r |
| 76 | sim_name simulator name string\r |
| 77 | sim_PC pointer to saved PC register descriptor\r |
| 78 | sim_emax maximum number of words for examine/deposit\r |
| 79 | sim_devices array of pointers to simulated devices\r |
| 80 | sim_consoles array of pointers to consoles (if more than one)\r |
| 81 | sim_stop_messages array of pointers to stop messages\r |
| 82 | sim_load binary loader\r |
| 83 | */\r |
| 84 | \r |
| 85 | char sim_name[] = "PDP-8";\r |
| 86 | \r |
| 87 | REG *sim_PC = &cpu_reg[0];\r |
| 88 | \r |
| 89 | int32 sim_emax = 4;\r |
| 90 | \r |
| 91 | DEVICE *sim_devices[] = {\r |
| 92 | &cpu_dev,\r |
| 93 | &tsc_dev,\r |
| 94 | &clk_dev,\r |
| 95 | &ptr_dev,\r |
| 96 | &ptp_dev,\r |
| 97 | &tti_dev,\r |
| 98 | &tto_dev,\r |
| 99 | &ttix_dev,\r |
| 100 | &ttox_dev,\r |
| 101 | &lpt_dev,\r |
| 102 | &rk_dev,\r |
| 103 | &rl_dev,\r |
| 104 | &rx_dev,\r |
| 105 | &df_dev,\r |
| 106 | &rf_dev,\r |
| 107 | &dt_dev,\r |
| 108 | &td_dev,\r |
| 109 | &mt_dev,\r |
| 110 | &ct_dev,\r |
| 111 | NULL\r |
| 112 | };\r |
| 113 | \r |
| 114 | const char *sim_stop_messages[] = {\r |
| 115 | "Unknown error",\r |
| 116 | "Unimplemented instruction",\r |
| 117 | "HALT instruction",\r |
| 118 | "Breakpoint",\r |
| 119 | "Non-standard device number",\r |
| 120 | "DECtape off reel",\r |
| 121 | "Infinite loop"\r |
| 122 | };\r |
| 123 | \r |
| 124 | /* Ambiguous device list - these devices have overlapped IOT codes */\r |
| 125 | \r |
| 126 | DEVICE *amb_dev[] = {\r |
| 127 | &rl_dev,\r |
| 128 | &ct_dev,\r |
| 129 | &td_dev,\r |
| 130 | NULL\r |
| 131 | };\r |
| 132 | \r |
| 133 | #define AMB_RL (1 << 12)\r |
| 134 | #define AMB_CT (2 << 12)\r |
| 135 | #define AMB_TD (3 << 12)\r |
| 136 | \r |
| 137 | /* RIM loader format consists of alternating pairs of addresses and 12-bit\r |
| 138 | words. It can only operate in field 0 and is not checksummed.\r |
| 139 | */\r |
| 140 | \r |
| 141 | t_stat sim_load_rim (FILE *fi)\r |
| 142 | {\r |
| 143 | int32 origin, hi, lo, wd;\r |
| 144 | \r |
| 145 | origin = 0200;\r |
| 146 | do { /* skip leader */\r |
| 147 | if ((hi = getc (fi)) == EOF)\r |
| 148 | return SCPE_FMT;\r |
| 149 | } while ((hi == 0) || (hi >= 0200));\r |
| 150 | do { /* data block */\r |
| 151 | if ((lo = getc (fi)) == EOF)\r |
| 152 | return SCPE_FMT;\r |
| 153 | wd = (hi << 6) | lo;\r |
| 154 | if (wd > 07777) origin = wd & 07777;\r |
| 155 | else M[origin++ & 07777] = wd;\r |
| 156 | if ((hi = getc (fi)) == EOF)\r |
| 157 | return SCPE_FMT;\r |
| 158 | } while (hi < 0200); /* until trailer */\r |
| 159 | return SCPE_OK;\r |
| 160 | }\r |
| 161 | \r |
| 162 | /* BIN loader format consists of a string of 12-bit words (made up from\r |
| 163 | 7-bit characters) between leader and trailer (200). The last word on\r |
| 164 | tape is the checksum. A word with the "link" bit set is a new origin;\r |
| 165 | a character > 0200 indicates a change of field.\r |
| 166 | */\r |
| 167 | \r |
| 168 | int32 sim_bin_getc (FILE *fi, uint32 *newf)\r |
| 169 | {\r |
| 170 | int32 c, rubout;\r |
| 171 | \r |
| 172 | rubout = 0; /* clear toggle */\r |
| 173 | while ((c = getc (fi)) != EOF) { /* read char */\r |
| 174 | if (rubout) /* toggle set? */\r |
| 175 | rubout = 0; /* clr, skip */\r |
| 176 | else if (c == 0377) /* rubout? */\r |
| 177 | rubout = 1; /* set, skip */\r |
| 178 | else if (c > 0200) /* channel 8 set? */\r |
| 179 | *newf = (c & 070) << 9; /* change field */\r |
| 180 | else return c; /* otherwise ok */\r |
| 181 | }\r |
| 182 | return EOF;\r |
| 183 | }\r |
| 184 | \r |
| 185 | t_stat sim_load_bin (FILE *fi)\r |
| 186 | {\r |
| 187 | int32 hi, lo, wd, csum, t;\r |
| 188 | uint32 field, newf, origin;\r |
| 189 | \r |
| 190 | do { /* skip leader */\r |
| 191 | if ((hi = sim_bin_getc (fi, &newf)) == EOF)\r |
| 192 | return SCPE_FMT;\r |
| 193 | } while ((hi == 0) || (hi >= 0200));\r |
| 194 | csum = origin = field = newf = 0; /* init */\r |
| 195 | for (;;) { /* data blocks */\r |
| 196 | if ((lo = sim_bin_getc (fi, &newf)) == EOF) /* low char */\r |
| 197 | return SCPE_FMT;\r |
| 198 | wd = (hi << 6) | lo; /* form word */\r |
| 199 | t = hi; /* save for csum */\r |
| 200 | if ((hi = sim_bin_getc (fi, &newf)) == EOF) /* next char */\r |
| 201 | return SCPE_FMT;\r |
| 202 | if (hi == 0200) { /* end of tape? */\r |
| 203 | if ((csum - wd) & 07777) /* valid csum? */\r |
| 204 | return SCPE_CSUM;\r |
| 205 | return SCPE_OK;\r |
| 206 | }\r |
| 207 | csum = csum + t + lo; /* add to csum */\r |
| 208 | if (wd > 07777) /* chan 7 set? */\r |
| 209 | origin = wd & 07777; /* new origin */\r |
| 210 | else { /* no, data */\r |
| 211 | if ((field | origin) >= MEMSIZE) \r |
| 212 | return SCPE_NXM;\r |
| 213 | M[field | origin] = wd;\r |
| 214 | origin = (origin + 1) & 07777;\r |
| 215 | }\r |
| 216 | field = newf; /* update field */\r |
| 217 | }\r |
| 218 | return SCPE_IERR;\r |
| 219 | }\r |
| 220 | \r |
| 221 | /* Binary loader\r |
| 222 | Two loader formats are supported: RIM loader (-r) and BIN (-b) loader. */\r |
| 223 | \r |
| 224 | t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)\r |
| 225 | {\r |
| 226 | if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;\r |
| 227 | if ((sim_switches & SWMASK ('R')) || /* RIM format? */\r |
| 228 | (match_ext (fnam, "RIM") && !(sim_switches & SWMASK ('B'))))\r |
| 229 | return sim_load_rim (fileref);\r |
| 230 | else return sim_load_bin (fileref); /* no, BIN */\r |
| 231 | }\r |
| 232 | \r |
| 233 | /* Symbol tables */\r |
| 234 | \r |
| 235 | #define I_V_FL 18 /* flag start */\r |
| 236 | #define I_M_FL 07 /* flag mask */\r |
| 237 | #define I_V_NPN 0 /* no operand */\r |
| 238 | #define I_V_FLD 1 /* field change */\r |
| 239 | #define I_V_MRF 2 /* mem ref */\r |
| 240 | #define I_V_IOT 3 /* general IOT */\r |
| 241 | #define I_V_OP1 4 /* operate 1 */\r |
| 242 | #define I_V_OP2 5 /* operate 2 */\r |
| 243 | #define I_V_OP3 6 /* operate 3 */\r |
| 244 | #define I_V_IOA 7 /* ambiguous IOT */\r |
| 245 | #define I_NPN (I_V_NPN << I_V_FL)\r |
| 246 | #define I_FLD (I_V_FLD << I_V_FL)\r |
| 247 | #define I_MRF (I_V_MRF << I_V_FL)\r |
| 248 | #define I_IOT (I_V_IOT << I_V_FL)\r |
| 249 | #define I_OP1 (I_V_OP1 << I_V_FL)\r |
| 250 | #define I_OP2 (I_V_OP2 << I_V_FL)\r |
| 251 | #define I_OP3 (I_V_OP3 << I_V_FL)\r |
| 252 | #define I_IOA (I_V_IOA << I_V_FL)\r |
| 253 | \r |
| 254 | static const int32 masks[] = {\r |
| 255 | 07777, 07707, 07000, 07000,\r |
| 256 | 07416, 07571, 017457, 077777,\r |
| 257 | };\r |
| 258 | \r |
| 259 | /* Ambiguous device mnemonics must precede default mnemonics */\r |
| 260 | \r |
| 261 | static const char *opcode[] = {\r |
| 262 | "SKON", "ION", "IOF", "SRQ", /* std IOTs */\r |
| 263 | "GTF", "RTF", "SGT", "CAF",\r |
| 264 | "RPE", "RSF", "RRB", "RFC", "RFC RRB", /* reader/punch */\r |
| 265 | "PCE", "PSF", "PCF", "PPC", "PLS",\r |
| 266 | "KCF", "KSF", "KCC", "KRS", "KIE", "KRB", /* console */\r |
| 267 | "TLF", "TSF", "TCF", "TPC", "SPI", "TLS",\r |
| 268 | "SBE", "SPL", "CAL", /* power fail */\r |
| 269 | "CLEI", "CLDI", "CLSC", "CLLE", "CLCL", "CLSK", /* clock */\r |
| 270 | "CINT", "RDF", "RIF", "RIB", /* mem mmgt */\r |
| 271 | "RMF", "SINT", "CUF", "SUF",\r |
| 272 | "RLDC", "RLSD", "RLMA", "RLCA", /* RL - ambiguous */\r |
| 273 | "RLCB", "RLSA", "RLWC",\r |
| 274 | "RRER", "RRWC", "RRCA", "RRCB",\r |
| 275 | "RRSA", "RRSI", "RLSE",\r |
| 276 | "KCLR", "KSDR", "KSEN", "KSBF", /* CT - ambiguous */\r |
| 277 | "KLSA", "KSAF", "KGOA", "KRSB",\r |
| 278 | "SDSS", "SDST", "SDSQ", /* TD - ambiguous */\r |
| 279 | "SDLC", "SDLD", "SDRC", "SDRD",\r |
| 280 | "ADCL", "ADLM", "ADST", "ADRB", /* A/D */\r |
| 281 | "ADSK", "ADSE", "ADLE", "ADRS",\r |
| 282 | "DCMA", "DMAR", "DMAW", /* DF/RF */\r |
| 283 | "DCIM", "DSAC", "DIML", "DIMA",\r |
| 284 | "DCEA", "DEAL", "DEAC",\r |
| 285 | "DFSE", "DFSC", "DISK", "DMAC",\r |
| 286 | "DCXA", "DXAL", "DXAC",\r |
| 287 | "PSKF", "PCLF", "PSKE", /* LPT */\r |
| 288 | "PSTB", "PSIE", "PCLF PSTB", "PCIE",\r |
| 289 | "LWCR", "CWCR", "LCAR", /* MT */\r |
| 290 | "CCAR", "LCMR", "LFGR", "LDBR",\r |
| 291 | "RWCR", "CLT", "RCAR",\r |
| 292 | "RMSR", "RCMR", "RFSR", "RDBR",\r |
| 293 | "SKEF", "SKCB", "SKJD", "SKTR", "CLF",\r |
| 294 | "DSKP", "DCLR", "DLAG", /* RK */\r |
| 295 | "DLCA", "DRST", "DLDC", "DMAN",\r |
| 296 | "LCD", "XDR", "STR", /* RX */\r |
| 297 | "SER", "SDN", "INTR", "INIT",\r |
| 298 | "DTRA", "DTCA", "DTXA", "DTLA", /* DT */\r |
| 299 | "DTSF", "DTRB", "DTLB",\r |
| 300 | "ETDS", "ESKP", "ECTF", "ECDF", /* TSC75 */\r |
| 301 | "ERTB", "ESME", "ERIOT", "ETEN",\r |
| 302 | "FFST", "FPINT", "FPICL", "FPCOM", /* FPP8 */\r |
| 303 | "FPHLT", "FPST", "FPRST", "FPIST",\r |
| 304 | "FMODE", "FMRB",\r |
| 305 | "FMRP", "FMDO", "FPEP",\r |
| 306 | \r |
| 307 | "CDF", "CIF", "CIF CDF",\r |
| 308 | "AND", "TAD", "ISZ", "DCA", "JMS", "JMP", "IOT",\r |
| 309 | "NOP", "NOP2", "NOP3", "SWAB", "SWBA",\r |
| 310 | "STL", "GLK", "STA", "LAS", "CIA",\r |
| 311 | "BSW", "RAL", "RTL", "RAR", "RTR", "RAL RAR", "RTL RTR",\r |
| 312 | "SKP", "SNL", "SZL",\r |
| 313 | "SZA", "SNA", "SZA SNL", "SNA SZL",\r |
| 314 | "SMA", "SPA", "SMA SNL", "SPA SZL",\r |
| 315 | "SMA SZA", "SPA SNA", "SMA SZA SNL", "SPA SNA SZL",\r |
| 316 | "SCL", "MUY", "DVI", "NMI", "SHL", "ASR", "LSR",\r |
| 317 | "SCA", "SCA SCL", "SCA MUY", "SCA DVI",\r |
| 318 | "SCA NMI", "SCA SHL", "SCA ASR", "SCA LSR",\r |
| 319 | "ACS", "MUY", "DVI", "NMI", "SHL", "ASR", "LSR",\r |
| 320 | "SCA", "DAD", "DST", "SWBA",\r |
| 321 | "DPSZ", "DPIC", "DCIM", "SAM",\r |
| 322 | "CLA", "CLL", "CMA", "CML", "IAC", /* encode only */\r |
| 323 | "CLA", "OAS", "HLT",\r |
| 324 | "CLA", "MQA", "MQL",\r |
| 325 | NULL, NULL, NULL, NULL, /* decode only */\r |
| 326 | NULL\r |
| 327 | };\r |
| 328 | \r |
| 329 | static const int32 opc_val[] = {\r |
| 330 | 06000+I_NPN, 06001+I_NPN, 06002+I_NPN, 06003+I_NPN,\r |
| 331 | 06004+I_NPN, 06005+I_NPN, 06006+I_NPN, 06007+I_NPN,\r |
| 332 | 06010+I_NPN, 06011+I_NPN, 06012+I_NPN, 06014+I_NPN, 06016+I_NPN,\r |
| 333 | 06020+I_NPN, 06021+I_NPN, 06022+I_NPN, 06024+I_NPN, 06026+I_NPN,\r |
| 334 | 06030+I_NPN, 06031+I_NPN, 06032+I_NPN, 06034+I_NPN, 06035+I_NPN, 06036+I_NPN,\r |
| 335 | 06040+I_NPN, 06041+I_NPN, 06042+I_NPN, 06044+I_NPN, 06045+I_NPN, 06046+I_NPN,\r |
| 336 | 06101+I_NPN, 06102+I_NPN, 06103+I_NPN,\r |
| 337 | 06131+I_NPN, 06132+I_NPN, 06133+I_NPN, 06135+I_NPN, 06136+I_NPN, 06137+I_NPN,\r |
| 338 | 06204+I_NPN, 06214+I_NPN, 06224+I_NPN, 06234+I_NPN,\r |
| 339 | 06244+I_NPN, 06254+I_NPN, 06264+I_NPN, 06274+I_NPN,\r |
| 340 | 06600+I_IOA+AMB_RL, 06601+I_IOA+AMB_RL, 06602+I_IOA+AMB_RL, 06603+I_IOA+AMB_RL,\r |
| 341 | 06604+I_IOA+AMB_RL, 06605+I_IOA+AMB_RL, 06607+I_IOA+AMB_RL,\r |
| 342 | 06610+I_IOA+AMB_RL, 06611+I_IOA+AMB_RL, 06612+I_IOA+AMB_RL, 06613+I_IOA+AMB_RL,\r |
| 343 | 06614+I_IOA+AMB_RL, 06615+I_IOA+AMB_RL, 06617+I_IOA+AMB_RL,\r |
| 344 | 06700+I_IOA+AMB_CT, 06701+I_IOA+AMB_CT, 06702+I_IOA+AMB_CT, 06703+I_IOA+AMB_CT,\r |
| 345 | 06704+I_IOA+AMB_CT, 06705+I_IOA+AMB_CT, 06706+I_IOA+AMB_CT, 06707+I_IOA+AMB_CT,\r |
| 346 | 06771+I_IOA+AMB_TD, 06772+I_IOA+AMB_TD, 06773+I_IOA+AMB_TD,\r |
| 347 | 06774+I_IOA+AMB_TD, 06775+I_IOA+AMB_TD, 06776+I_IOA+AMB_TD, 06777+I_IOA+AMB_TD,\r |
| 348 | 06530+I_NPN, 06531+I_NPN, 06532+I_NPN, 06533+I_NPN, /* AD */\r |
| 349 | 06534+I_NPN, 06535+I_NPN, 06536+I_NPN, 06537+I_NPN,\r |
| 350 | 06601+I_NPN, 06603+I_NPN, 06605+I_NPN, /* DF/RF */\r |
| 351 | 06611+I_NPN, 06612+I_NPN, 06615+I_NPN, 06616+I_NPN,\r |
| 352 | 06611+I_NPN, 06615+I_NPN, 06616+I_NPN,\r |
| 353 | 06621+I_NPN, 06622+I_NPN, 06623+I_NPN, 06626+I_NPN,\r |
| 354 | 06641+I_NPN, 06643+I_NPN, 06645+I_NPN,\r |
| 355 | 06661+I_NPN, 06662+I_NPN, 06663+I_NPN, /* LPT */\r |
| 356 | 06664+I_NPN, 06665+I_NPN, 06666+I_NPN, 06667+I_NPN,\r |
| 357 | 06701+I_NPN, 06702+I_NPN, 06703+I_NPN, /* MT */\r |
| 358 | 06704+I_NPN, 06705+I_NPN, 06706+I_NPN, 06707+I_NPN,\r |
| 359 | 06711+I_NPN, 06712+I_NPN, 06713+I_NPN,\r |
| 360 | 06714+I_NPN, 06715+I_NPN, 06716+I_NPN, 06717+I_NPN,\r |
| 361 | 06721+I_NPN, 06722+I_NPN, 06723+I_NPN, 06724+I_NPN, 06725+I_NPN,\r |
| 362 | 06741+I_NPN, 06742+I_NPN, 06743+I_NPN, /* RK */\r |
| 363 | 06744+I_NPN, 06745+I_NPN, 06746+I_NPN, 06747+I_NPN,\r |
| 364 | 06751+I_NPN, 06752+I_NPN, 06753+I_NPN, /* RX */\r |
| 365 | 06754+I_NPN, 06755+I_NPN, 06756+I_NPN, 06757+I_NPN,\r |
| 366 | 06761+I_NPN, 06762+I_NPN, 06764+I_NPN, 06766+I_NPN, /* DT */\r |
| 367 | 06771+I_NPN, 06772+I_NPN, 06774+I_NPN,\r |
| 368 | 06360+I_NPN, 06361+I_NPN, 06362+I_NPN, 06363+I_NPN, /* TSC */\r |
| 369 | 06364+I_NPN, 06365+I_NPN, 06366+I_NPN, 06367+I_NPN,\r |
| 370 | 06550+I_NPN, 06551+I_NPN, 06552+I_NPN, 06553+I_NPN, /* FPP8 */\r |
| 371 | 06554+I_NPN, 06555+I_NPN, 06556+I_NPN, 06557+I_NPN,\r |
| 372 | 06561+I_NPN, 06563+I_NPN,\r |
| 373 | 06564+I_NPN, 06565+I_NPN, 06567+I_NPN,\r |
| 374 | \r |
| 375 | 06201+I_FLD, 06202+I_FLD, 06203+I_FLD,\r |
| 376 | 00000+I_MRF, 01000+I_MRF, 02000+I_MRF, 03000+I_MRF,\r |
| 377 | 04000+I_MRF, 05000+I_MRF, 06000+I_IOT,\r |
| 378 | 07000+I_NPN, 07400+I_NPN, 07401+I_NPN, 07431+I_NPN, 07447+I_NPN,\r |
| 379 | 07120+I_NPN, 07204+I_NPN, 07240+I_NPN, 07604+I_NPN, 07041+I_NPN,\r |
| 380 | 07002+I_OP1, 07004+I_OP1, 07006+I_OP1,\r |
| 381 | 07010+I_OP1, 07012+I_OP1, 07014+I_OP1, 07016+I_OP1,\r |
| 382 | 07410+I_OP2, 07420+I_OP2, 07430+I_OP2,\r |
| 383 | 07440+I_OP2, 07450+I_OP2, 07460+I_OP2, 07470+I_OP2,\r |
| 384 | 07500+I_OP2, 07510+I_OP2, 07520+I_OP2, 07530+I_OP2,\r |
| 385 | 07540+I_OP2, 07550+I_OP2, 07560+I_OP2, 07570+I_OP2,\r |
| 386 | 07403+I_OP3, 07405+I_OP3, 07407+I_OP3,\r |
| 387 | 07411+I_OP3, 07413+I_OP3, 07415+I_OP3, 07417+I_OP3,\r |
| 388 | 07441+I_OP3, 07443+I_OP3, 07445+I_OP3, 07447+I_OP3,\r |
| 389 | 07451+I_OP3, 07453+I_OP3, 07455+I_OP3, 07457+I_OP3,\r |
| 390 | 017403+I_OP3, 017405+I_OP3, 0174017+I_OP3,\r |
| 391 | 017411+I_OP3, 017413+I_OP3, 017415+I_OP3, 017417+I_OP3,\r |
| 392 | 017441+I_OP3, 017443+I_OP3, 017445+I_OP3, 017447+I_OP3,\r |
| 393 | 017451+I_OP3, 017453+I_OP3, 017455+I_OP3, 017457+I_OP3,\r |
| 394 | 07200+I_OP1, 07100+I_OP1, 07040+I_OP1, 07020+I_OP1, 07001+I_OP1,\r |
| 395 | 07600+I_OP2, 07404+I_OP2, 07402+I_OP2,\r |
| 396 | 07601+I_OP3, 07501+I_OP3, 07421+I_OP3,\r |
| 397 | 07000+I_OP1, 07400+I_OP2, 07401+I_OP3, 017401+I_OP3,\r |
| 398 | -1\r |
| 399 | };\r |
| 400 | \r |
| 401 | /* Symbol tables for FPP-8 */\r |
| 402 | \r |
| 403 | #define F_V_FL 18 /* flag start */\r |
| 404 | #define F_M_FL 017 /* flag mask */\r |
| 405 | #define F_V_NOP12 0 /* no opnd 12b */\r |
| 406 | #define F_V_NOP9 1 /* no opnd 9b */\r |
| 407 | #define F_V_AD15 2 /* 15b dir addr */\r |
| 408 | #define F_V_AD15X 3 /* 15b dir addr indx */\r |
| 409 | #define F_V_IMMX 4 /* 12b immm indx */\r |
| 410 | #define F_V_X 5 /* index */\r |
| 411 | #define F_V_MRI 6 /* mem ref ind */\r |
| 412 | #define F_V_MR1D 7 /* mem ref dir 1 word */\r |
| 413 | #define F_V_MR2D 8 /* mem ref dir 2 word */\r |
| 414 | #define F_V_LEMU 9 /* LEA/IMUL */\r |
| 415 | #define F_V_LEMUI 10 /* LEAI/IMULI */\r |
| 416 | #define F_V_LTR 11 /* LTR */\r |
| 417 | #define F_V_MRD 12 /* mem ref direct (enc) */\r |
| 418 | #define F_NOP12 (F_V_NOP12 << F_V_FL)\r |
| 419 | #define F_NOP9 (F_V_NOP9 << F_V_FL)\r |
| 420 | #define F_AD15 (F_V_AD15 << F_V_FL)\r |
| 421 | #define F_AD15X (F_V_AD15X << F_V_FL)\r |
| 422 | #define F_IMMX (F_V_IMMX << F_V_FL)\r |
| 423 | #define F_X (F_V_X << F_V_FL)\r |
| 424 | #define F_MRI (F_V_MRI << F_V_FL)\r |
| 425 | #define F_MR1D (F_V_MR1D << F_V_FL)\r |
| 426 | #define F_MR2D (F_V_MR2D << F_V_FL)\r |
| 427 | #define F_LEMU (F_V_LEMU << F_V_FL)\r |
| 428 | #define F_LEMUI (F_V_LEMUI << F_V_FL)\r |
| 429 | #define F_LTR (F_V_LTR << F_V_FL)\r |
| 430 | #define F_MRD (F_V_MRD << F_V_FL)\r |
| 431 | \r |
| 432 | static const uint32 fmasks[] = {\r |
| 433 | 07777, 07770, 07770, 07600,\r |
| 434 | 07770, 07770, 07600, 07600,\r |
| 435 | 07600, 017600, 017600, 07670,\r |
| 436 | 07777\r |
| 437 | };\r |
| 438 | \r |
| 439 | /* Memory references are encode dir / decode 1D / decode 2D / indirect */\r |
| 440 | \r |
| 441 | static const char *fopcode[] = {\r |
| 442 | "FEXIT", "FPAUSE", "FCLA", "FNEG",\r |
| 443 | "FNORM", "STARTF", "STARTD", "JAC",\r |
| 444 | "ALN", "ATX", "XTA",\r |
| 445 | "FNOP", "STARTE",\r |
| 446 | "LDX", "ADDX",\r |
| 447 | "FLDA", "FLDA", "FLDA", "FLDAI",\r |
| 448 | "JEQ", "JGE", "JLE", "JA",\r |
| 449 | "JNE", "JLT", "JGT", "JAL",\r |
| 450 | "SETX", "SETB", "JSA", "JSR",\r |
| 451 | "FADD", "FADD", "FADD", "FADDI",\r |
| 452 | "JNX",\r |
| 453 | "FSUB", "FSUB", "FSUB", "FSUBI",\r |
| 454 | "TRAP3",\r |
| 455 | "FDIV", "FDIV", "FDIV", "FDIVI",\r |
| 456 | "TRAP4",\r |
| 457 | "FMUL", "FMUL", "FMUL", "FMULI",\r |
| 458 | "LTREQ", "LTRGE", "LTRLE", "LTRA",\r |
| 459 | "LTRNE", "LTRLT", "LTRGT", "LTRAL",\r |
| 460 | "FADDM", "FADDM", "FADDM", "FADDMI",\r |
| 461 | "IMUL", "LEA",\r |
| 462 | "FSTA", "FSTA", "FSTA", "FSTAI",\r |
| 463 | "IMULI", "LEAI",\r |
| 464 | "FMULM", "FMULM", "FMULM", "FMULMI",\r |
| 465 | NULL\r |
| 466 | };\r |
| 467 | \r |
| 468 | static const int32 fop_val[] = {\r |
| 469 | 00000+F_NOP12, 00001+F_NOP12, 00002+F_NOP12, 00003+F_NOP12,\r |
| 470 | 00004+F_NOP12, 00005+F_NOP12, 00006+F_NOP12, 00007+F_NOP12,\r |
| 471 | 00010+F_X, 00020+F_X, 00030+F_X,\r |
| 472 | 00040+F_NOP9, 00050+F_NOP9,\r |
| 473 | 00100+F_IMMX, 00110+F_IMMX,\r |
| 474 | 00000+F_MRD, 00200+F_MR1D, 00400+F_MR2D, 00600+F_MRI,\r |
| 475 | 01000+F_AD15, 01010+F_AD15, 01020+F_AD15, 01030+F_AD15,\r |
| 476 | 01040+F_AD15, 01050+F_AD15, 01060+F_AD15, 01070+F_AD15,\r |
| 477 | 01100+F_AD15, 01110+F_AD15, 01120+F_AD15, 01130+F_AD15,\r |
| 478 | 01000+F_MRD, 01200+F_MR1D, 01400+F_MR2D, 01600+F_MRI,\r |
| 479 | 02000+F_AD15X,\r |
| 480 | 02000+F_MRD, 02200+F_MR1D, 02400+F_MR2D, 02600+F_MRI,\r |
| 481 | 03000+F_AD15,\r |
| 482 | 03000+F_MRD, 03200+F_MR1D, 03400+F_MR2D, 03600+F_MRI,\r |
| 483 | 04000+F_AD15,\r |
| 484 | 04000+F_MRD, 04200+F_MR1D, 04400+F_MR2D, 04600+F_MRI,\r |
| 485 | 05000+F_LTR, 05010+F_LTR, 05020+F_LTR, 05030+F_LTR,\r |
| 486 | 05040+F_LTR, 05050+F_LTR, 05060+F_LTR, 05070+F_LTR,\r |
| 487 | 05000+F_MRD, 05200+F_MR1D, 05400+F_MR2D, 05600+F_MRI,\r |
| 488 | 016000+F_LEMU, 006000+F_LEMU,\r |
| 489 | 06000+F_MRD, 06200+F_MR1D, 06400+F_MR2D, 06600+F_MRI,\r |
| 490 | 017000+F_LEMUI, 007000+F_LEMUI,\r |
| 491 | 07000+F_MRD, 07200+F_MR1D, 07400+F_MR2D, 07600+F_MRI,\r |
| 492 | -1\r |
| 493 | };\r |
| 494 | \r |
| 495 | /* Operate decode\r |
| 496 | \r |
| 497 | Inputs:\r |
| 498 | *of = output stream\r |
| 499 | inst = mask bits\r |
| 500 | class = instruction class code\r |
| 501 | sp = space needed?\r |
| 502 | Outputs:\r |
| 503 | status = space needed\r |
| 504 | */\r |
| 505 | \r |
| 506 | int32 fprint_opr (FILE *of, int32 inst, int32 class, int32 sp)\r |
| 507 | {\r |
| 508 | int32 i, j;\r |
| 509 | \r |
| 510 | for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */\r |
| 511 | j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */\r |
| 512 | if ((j == class) && (opc_val[i] & inst)) { /* same class? */\r |
| 513 | inst = inst & ~opc_val[i]; /* mask bit set? */\r |
| 514 | fprintf (of, (sp? " %s": "%s"), opcode[i]);\r |
| 515 | sp = 1;\r |
| 516 | }\r |
| 517 | }\r |
| 518 | return sp;\r |
| 519 | }\r |
| 520 | \r |
| 521 | /* Symbolic decode\r |
| 522 | \r |
| 523 | Inputs:\r |
| 524 | *of = output stream\r |
| 525 | addr = current PC\r |
| 526 | *val = pointer to data\r |
| 527 | *uptr = pointer to unit \r |
| 528 | sw = switches\r |
| 529 | Outputs:\r |
| 530 | return = status code\r |
| 531 | */\r |
| 532 | \r |
| 533 | #define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)\r |
| 534 | #define SIXTOASC(x) (((x) >= 040)? (x): (x) + 0100)\r |
| 535 | #define TSSTOASC(x) ((x) + 040)\r |
| 536 | \r |
| 537 | t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,\r |
| 538 | UNIT *uptr, int32 sw)\r |
| 539 | {\r |
| 540 | int32 cflag, i, j, sp, inst, disp, opc;\r |
| 541 | extern int32 emode;\r |
| 542 | t_stat r;\r |
| 543 | \r |
| 544 | cflag = (uptr == NULL) || (uptr == &cpu_unit);\r |
| 545 | inst = val[0];\r |
| 546 | if (sw & SWMASK ('A')) { /* ASCII? */\r |
| 547 | if (inst > 0377) return SCPE_ARG;\r |
| 548 | fprintf (of, FMTASC (inst & 0177));\r |
| 549 | return SCPE_OK;\r |
| 550 | }\r |
| 551 | if (sw & SWMASK ('C')) { /* characters? */\r |
| 552 | fprintf (of, "%c", SIXTOASC ((inst >> 6) & 077));\r |
| 553 | fprintf (of, "%c", SIXTOASC (inst & 077));\r |
| 554 | return SCPE_OK;\r |
| 555 | }\r |
| 556 | if (sw & SWMASK ('T')) { /* TSS8 packed? */\r |
| 557 | fprintf (of, "%c", TSSTOASC ((inst >> 6) & 077));\r |
| 558 | fprintf (of, "%c", TSSTOASC (inst & 077));\r |
| 559 | return SCPE_OK;\r |
| 560 | }\r |
| 561 | if ((sw & SWMASK ('F')) && /* FPP8? */\r |
| 562 | ((r = fprint_sym_fpp (of, val)) != SCPE_ARG))\r |
| 563 | return r;\r |
| 564 | if (!(sw & SWMASK ('M'))) return SCPE_ARG;\r |
| 565 | \r |
| 566 | /* Instruction decode */\r |
| 567 | \r |
| 568 | opc = (inst >> 9) & 07; /* get major opcode */\r |
| 569 | if (opc == 07) /* operate? */\r |
| 570 | inst = inst | ((emode & 1) << 12); /* include EAE mode */\r |
| 571 | if (opc == 06) { /* IOT? */\r |
| 572 | DEVICE *dptr;\r |
| 573 | DIB *dibp;\r |
| 574 | uint32 dno = (inst >> 3) & 077;\r |
| 575 | for (i = 0; (dptr = amb_dev[i]) != NULL; i++) { /* check amb devices */\r |
| 576 | if ((dptr->ctxt == NULL) || /* no DIB or */\r |
| 577 | (dptr->flags & DEV_DIS)) continue; /* disabled? skip */\r |
| 578 | dibp = (DIB *) dptr->ctxt; /* get DIB */\r |
| 579 | if ((dno >= dibp->dev) || /* IOT for this dev? */\r |
| 580 | (dno < (dibp->dev + dibp->num))) {\r |
| 581 | inst = inst | ((i + 1) << 12); /* disambiguate */\r |
| 582 | break; /* done */\r |
| 583 | }\r |
| 584 | }\r |
| 585 | }\r |
| 586 | \r |
| 587 | for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */\r |
| 588 | j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */\r |
| 589 | if ((opc_val[i] & 077777) == (inst & masks[j])) { /* match? */\r |
| 590 | \r |
| 591 | switch (j) { /* case on class */\r |
| 592 | \r |
| 593 | case I_V_NPN: case I_V_IOA: /* no operands */\r |
| 594 | fprintf (of, "%s", opcode[i]); /* opcode */\r |
| 595 | break;\r |
| 596 | \r |
| 597 | case I_V_FLD: /* field change */\r |
| 598 | fprintf (of, "%s %-o", opcode[i], (inst >> 3) & 07);\r |
| 599 | break;\r |
| 600 | \r |
| 601 | case I_V_MRF: /* mem ref */\r |
| 602 | disp = inst & 0177; /* displacement */\r |
| 603 | fprintf (of, "%s%s", opcode[i], ((inst & 00400)? " I ": " "));\r |
| 604 | if (inst & 0200) { /* current page? */\r |
| 605 | if (cflag) fprintf (of, "%-o", (addr & 07600) | disp);\r |
| 606 | else fprintf (of, "C %-o", disp);\r |
| 607 | }\r |
| 608 | else fprintf (of, "%-o", disp); /* page zero */\r |
| 609 | break;\r |
| 610 | \r |
| 611 | case I_V_IOT: /* IOT */\r |
| 612 | fprintf (of, "%s %-o", opcode[i], inst & 0777);\r |
| 613 | break;\r |
| 614 | \r |
| 615 | case I_V_OP1: /* operate group 1 */\r |
| 616 | sp = fprint_opr (of, inst & 0361, j, 0);\r |
| 617 | if (opcode[i]) fprintf (of, (sp? " %s": "%s"), opcode[i]);\r |
| 618 | break;\r |
| 619 | \r |
| 620 | case I_V_OP2: /* operate group 2 */\r |
| 621 | if (opcode[i]) fprintf (of, "%s", opcode[i]); /* skips */\r |
| 622 | fprint_opr (of, inst & 0206, j, opcode[i] != NULL);\r |
| 623 | break; \r |
| 624 | \r |
| 625 | case I_V_OP3: /* operate group 3 */\r |
| 626 | sp = fprint_opr (of, inst & 0320, j, 0);\r |
| 627 | if (opcode[i]) fprintf (of, (sp? " %s": "%s"), opcode[i]);\r |
| 628 | break;\r |
| 629 | } /* end case */\r |
| 630 | \r |
| 631 | return SCPE_OK;\r |
| 632 | } /* end if */\r |
| 633 | } /* end for */\r |
| 634 | return SCPE_ARG;\r |
| 635 | }\r |
| 636 | \r |
| 637 | /* Symbolic input\r |
| 638 | \r |
| 639 | Inputs:\r |
| 640 | *cptr = pointer to input string\r |
| 641 | addr = current PC\r |
| 642 | *uptr = pointer to unit\r |
| 643 | *val = pointer to output values\r |
| 644 | sw = switches\r |
| 645 | Outputs:\r |
| 646 | status = error status\r |
| 647 | */\r |
| 648 | \r |
| 649 | t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)\r |
| 650 | {\r |
| 651 | uint32 cflag, d, i, j, k;\r |
| 652 | t_stat r;\r |
| 653 | char gbuf[CBUFSIZE];\r |
| 654 | \r |
| 655 | cflag = (uptr == NULL) || (uptr == &cpu_unit);\r |
| 656 | while (isspace (*cptr)) cptr++; /* absorb spaces */\r |
| 657 | if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */\r |
| 658 | if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */\r |
| 659 | val[0] = (t_value) cptr[0] | 0200;\r |
| 660 | return SCPE_OK;\r |
| 661 | }\r |
| 662 | if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* sixbit string? */\r |
| 663 | if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */\r |
| 664 | val[0] = (((t_value) cptr[0] & 077) << 6) |\r |
| 665 | ((t_value) cptr[1] & 077);\r |
| 666 | return SCPE_OK;\r |
| 667 | }\r |
| 668 | if ((sw & SWMASK ('T')) || ((*cptr == '"') && cptr++)) { /* TSS8 string? */\r |
| 669 | if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */\r |
| 670 | val[0] = (((t_value) (cptr[0] - 040) & 077) << 6) |\r |
| 671 | ((t_value) (cptr[1] - 040) & 077);\r |
| 672 | return SCPE_OK;\r |
| 673 | }\r |
| 674 | if ((r = parse_sym_fpp (cptr, val)) != SCPE_ARG) /* FPP8 inst? */\r |
| 675 | return r;\r |
| 676 | \r |
| 677 | /* Instruction parse */\r |
| 678 | \r |
| 679 | cptr = get_glyph (cptr, gbuf, 0); /* get opcode */\r |
| 680 | for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;\r |
| 681 | if (opcode[i] == NULL) return SCPE_ARG;\r |
| 682 | val[0] = opc_val[i] & 07777; /* get value */\r |
| 683 | j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */\r |
| 684 | \r |
| 685 | switch (j) { /* case on class */\r |
| 686 | \r |
| 687 | case I_V_IOT: /* IOT */\r |
| 688 | if ((cptr = parse_field (cptr, 0777, &d, 0)) == NULL)\r |
| 689 | return SCPE_ARG; /* get dev+pulse */\r |
| 690 | val[0] = val[0] | d;\r |
| 691 | break;\r |
| 692 | \r |
| 693 | case I_V_FLD: /* field */\r |
| 694 | for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;\r |
| 695 | cptr = get_glyph (cptr, gbuf, 0)) {\r |
| 696 | for (i = 0; (opcode[i] != NULL) &&\r |
| 697 | (strcmp (opcode[i], gbuf) != 0) ; i++) ;\r |
| 698 | if (opcode[i] != NULL) {\r |
| 699 | k = (opc_val[i] >> I_V_FL) & I_M_FL;\r |
| 700 | if (k != j) return SCPE_ARG;\r |
| 701 | val[0] = val[0] | (opc_val[i] & 07777);\r |
| 702 | }\r |
| 703 | else {\r |
| 704 | d = get_uint (gbuf, 8, 07, &r);\r |
| 705 | if (r != SCPE_OK) return SCPE_ARG;\r |
| 706 | val[0] = val[0] | (d << 3);\r |
| 707 | break;\r |
| 708 | }\r |
| 709 | }\r |
| 710 | break;\r |
| 711 | \r |
| 712 | case I_V_MRF: /* mem ref */\r |
| 713 | cptr = get_glyph (cptr, gbuf, 0); /* get next field */\r |
| 714 | if (strcmp (gbuf, "I") == 0) { /* indirect? */\r |
| 715 | val[0] = val[0] | 0400;\r |
| 716 | cptr = get_glyph (cptr, gbuf, 0);\r |
| 717 | }\r |
| 718 | if ((k = (strcmp (gbuf, "C") == 0)) || (strcmp (gbuf, "Z") == 0)) {\r |
| 719 | if ((cptr = parse_field (cptr, 0177, &d, 0)) == NULL)\r |
| 720 | return SCPE_ARG;\r |
| 721 | val[0] = val[0] | d | (k? 0200: 0);\r |
| 722 | }\r |
| 723 | else {\r |
| 724 | d = get_uint (gbuf, 8, 07777, &r);\r |
| 725 | if (r != SCPE_OK) return SCPE_ARG;\r |
| 726 | if (d <= 0177) val[0] = val[0] | d;\r |
| 727 | else if (cflag && (((addr ^ d) & 07600) == 0))\r |
| 728 | val[0] = val[0] | (d & 0177) | 0200;\r |
| 729 | else return SCPE_ARG;\r |
| 730 | }\r |
| 731 | break;\r |
| 732 | \r |
| 733 | case I_V_OP1: case I_V_OP2: case I_V_OP3: /* operates */\r |
| 734 | case I_V_NPN: case I_V_IOA:\r |
| 735 | for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;\r |
| 736 | cptr = get_glyph (cptr, gbuf, 0)) {\r |
| 737 | for (i = 0; (opcode[i] != NULL) &&\r |
| 738 | (strcmp (opcode[i], gbuf) != 0) ; i++) ;\r |
| 739 | k = opc_val[i] & 07777;\r |
| 740 | if ((opcode[i] == NULL) || (((k ^ val[0]) & 07000) != 0))\r |
| 741 | return SCPE_ARG;\r |
| 742 | val[0] = val[0] | k;\r |
| 743 | }\r |
| 744 | break;\r |
| 745 | } /* end case */\r |
| 746 | \r |
| 747 | if (*cptr != 0) return SCPE_ARG; /* junk at end? */\r |
| 748 | return SCPE_OK;\r |
| 749 | }\r |
| 750 | \r |
| 751 | /* FPP8 instruction decode */\r |
| 752 | \r |
| 753 | t_stat fprint_sym_fpp (FILE *of, t_value *val)\r |
| 754 | {\r |
| 755 | uint32 wd1, wd2, xr4b, xr3b, ad15;\r |
| 756 | uint32 i, j;\r |
| 757 | extern uint32 fpp_bra, fpp_cmd;\r |
| 758 | \r |
| 759 | wd1 = (uint32) val[0] | ((fpp_cmd & 04000) << 1);\r |
| 760 | wd2 = (uint32) val[1];\r |
| 761 | xr4b = (wd1 >> 3) & 017;\r |
| 762 | xr3b = wd1 & 07;\r |
| 763 | ad15 = (xr3b << 12) | wd2;\r |
| 764 | \r |
| 765 | for (i = 0; fop_val[i] >= 0; i++) { /* loop thru ops */\r |
| 766 | j = (fop_val[i] >> F_V_FL) & F_M_FL; /* get class */\r |
| 767 | if ((fop_val[i] & 017777) == (wd1 & fmasks[j])) { /* match? */\r |
| 768 | \r |
| 769 | switch (j) { /* case on class */\r |
| 770 | case F_V_NOP12:\r |
| 771 | case F_V_NOP9:\r |
| 772 | case F_V_LTR: /* no operands */\r |
| 773 | fprintf (of, "%s", fopcode[i]);\r |
| 774 | break;\r |
| 775 | \r |
| 776 | case F_V_X: /* index */\r |
| 777 | fprintf (of, "%s %o", fopcode[i], xr3b);\r |
| 778 | break;\r |
| 779 | \r |
| 780 | case F_V_IMMX: /* index imm */\r |
| 781 | fprintf (of, "%s %-o,%o", fopcode[i], wd2, xr3b);\r |
| 782 | return -1; /* extra word */\r |
| 783 | \r |
| 784 | case F_V_AD15: /* 15b address */\r |
| 785 | fprintf (of, "%s %-o", fopcode[i], ad15);\r |
| 786 | return -1; /* extra word */\r |
| 787 | \r |
| 788 | case F_V_AD15X: /* 15b addr, indx */\r |
| 789 | fprintf (of, "%s %-o", fopcode[i], ad15);\r |
| 790 | if (xr4b >= 010)\r |
| 791 | fprintf (of, ",%o+", xr4b & 7);\r |
| 792 | else fprintf (of, ",%o", xr4b);\r |
| 793 | return -1; /* extra word */\r |
| 794 | \r |
| 795 | case F_V_MR1D: /* 1 word direct */\r |
| 796 | ad15 = (fpp_bra + (3 * (wd1 & 0177))) & ADDRMASK;\r |
| 797 | fprintf (of, "%s %-o", fopcode[i], ad15);\r |
| 798 | break;\r |
| 799 | \r |
| 800 | case F_V_LEMU:\r |
| 801 | case F_V_MR2D: /* 2 word direct */\r |
| 802 | fprintf (of, "%s %-o", fopcode[i], ad15);\r |
| 803 | if (xr4b >= 010)\r |
| 804 | fprintf (of, ",%o+", xr4b & 7);\r |
| 805 | else if (xr4b != 0)\r |
| 806 | fprintf (of, ",%o", xr4b);\r |
| 807 | return -1; /* extra word */\r |
| 808 | \r |
| 809 | case F_V_LEMUI:\r |
| 810 | case F_V_MRI: /* indirect */\r |
| 811 | ad15 = (fpp_bra + (3 * xr3b)) & ADDRMASK;\r |
| 812 | fprintf (of, "%s %-o", fopcode[i], ad15);\r |
| 813 | if (xr4b >= 010)\r |
| 814 | fprintf (of, ",%o+", xr4b & 7);\r |
| 815 | else if (xr4b != 0)\r |
| 816 | fprintf (of, ",%o", xr4b);\r |
| 817 | break;\r |
| 818 | \r |
| 819 | case F_V_MRD: /* encode only */\r |
| 820 | return SCPE_IERR;\r |
| 821 | }\r |
| 822 | \r |
| 823 | return SCPE_OK;\r |
| 824 | } /* end if */\r |
| 825 | } /* end for */\r |
| 826 | return SCPE_ARG;\r |
| 827 | }\r |
| 828 | \r |
| 829 | /* FPP8 instruction parse */\r |
| 830 | \r |
| 831 | t_stat parse_sym_fpp (char *cptr, t_value *val)\r |
| 832 | {\r |
| 833 | uint32 i, j, ad, xr;\r |
| 834 | int32 broff, nwd;\r |
| 835 | char gbuf[CBUFSIZE];\r |
| 836 | \r |
| 837 | cptr = get_glyph (cptr, gbuf, 0); /* get opcode */\r |
| 838 | for (i = 0; (fopcode[i] != NULL) && (strcmp (fopcode[i], gbuf) != 0) ; i++) ;\r |
| 839 | if (fopcode[i] == NULL) return SCPE_ARG;\r |
| 840 | val[0] = fop_val[i] & 07777; /* get value */\r |
| 841 | j = (fop_val[i] >> F_V_FL) & F_M_FL; /* get class */\r |
| 842 | xr = 0;\r |
| 843 | nwd = 0;\r |
| 844 | \r |
| 845 | switch (j) { /* case on class */\r |
| 846 | \r |
| 847 | case F_V_NOP12:\r |
| 848 | case F_V_NOP9:\r |
| 849 | case F_V_LTR: /* no operands */\r |
| 850 | break;\r |
| 851 | \r |
| 852 | case F_V_X: /* 3b XR */\r |
| 853 | if ((cptr = parse_field (cptr, 07, &xr, 0)) == NULL)\r |
| 854 | return SCPE_ARG;\r |
| 855 | val[0] |= xr;\r |
| 856 | break;\r |
| 857 | \r |
| 858 | case F_V_IMMX: /* 12b, XR */\r |
| 859 | if ((cptr = parse_field (cptr, 07777, &ad, ',')) == NULL)\r |
| 860 | return SCPE_ARG;\r |
| 861 | if ((*cptr == 0) ||\r |
| 862 | ((cptr = parse_fpp_xr (cptr, &xr, FALSE)) == NULL))\r |
| 863 | return SCPE_ARG;\r |
| 864 | val[0] |= xr;\r |
| 865 | val[++nwd] = ad;\r |
| 866 | break;\r |
| 867 | \r |
| 868 | case F_V_AD15: /* 15b addr */\r |
| 869 | if ((cptr = parse_field (cptr, 077777, &ad, 0)) == NULL)\r |
| 870 | return SCPE_ARG;\r |
| 871 | val[0] |= (ad >> 12) & 07;\r |
| 872 | val[++nwd] = ad & 07777;\r |
| 873 | break;\r |
| 874 | \r |
| 875 | case F_V_AD15X: /* 15b addr, idx */\r |
| 876 | if ((cptr = parse_field (cptr, 077777, &ad, ',')) == NULL)\r |
| 877 | return SCPE_ARG;\r |
| 878 | if ((*cptr == 0) ||\r |
| 879 | ((cptr = parse_fpp_xr (cptr, &xr, FALSE)) == NULL))\r |
| 880 | return SCPE_ARG;\r |
| 881 | val[0] |= ((xr << 3) | ((ad >> 12) & 07));\r |
| 882 | val[++nwd] = ad & 07777;\r |
| 883 | break;\r |
| 884 | \r |
| 885 | case F_V_LEMUI:\r |
| 886 | case F_V_MRI: /* indirect */\r |
| 887 | if ((cptr = parse_field (cptr, 077777, &ad, ',')) == NULL)\r |
| 888 | return SCPE_ARG;\r |
| 889 | if ((*cptr != 0) &&\r |
| 890 | ((cptr = parse_fpp_xr (cptr, &xr, TRUE)) == NULL))\r |
| 891 | return SCPE_ARG;\r |
| 892 | if ((broff = test_fpp_addr (ad, 07)) < 0)\r |
| 893 | return SCPE_ARG;\r |
| 894 | val[0] |= ((xr << 3) | broff);\r |
| 895 | break;\r |
| 896 | \r |
| 897 | case F_V_MRD: /* direct */\r |
| 898 | if ((cptr = parse_field (cptr, 077777, &ad, ',')) == NULL)\r |
| 899 | return SCPE_ARG;\r |
| 900 | if (((broff = test_fpp_addr (ad, 0177)) < 0) ||\r |
| 901 | (*cptr != 0)) {\r |
| 902 | if ((*cptr != 0) &&\r |
| 903 | ((cptr = parse_fpp_xr (cptr, &xr, TRUE)) == NULL))\r |
| 904 | return SCPE_ARG;\r |
| 905 | val[0] |= (00400 | (xr << 3) | ((ad >> 12) & 07));\r |
| 906 | val[++nwd] = ad & 07777;\r |
| 907 | }\r |
| 908 | else val[0] |= (00200 | broff);\r |
| 909 | break;\r |
| 910 | \r |
| 911 | case F_V_LEMU:\r |
| 912 | if ((cptr = parse_field (cptr, 077777, &ad, ',')) == NULL)\r |
| 913 | return SCPE_ARG;\r |
| 914 | if ((*cptr != 0) &&\r |
| 915 | ((cptr = parse_fpp_xr (cptr, &xr, TRUE)) == NULL))\r |
| 916 | return SCPE_ARG;\r |
| 917 | val[0] |= ((xr << 3) | ((ad >> 12) & 07));\r |
| 918 | val[++nwd] = ad & 07777;\r |
| 919 | break;\r |
| 920 | \r |
| 921 | case F_V_MR1D:\r |
| 922 | case F_V_MR2D:\r |
| 923 | return SCPE_IERR; \r |
| 924 | } /* end case */\r |
| 925 | \r |
| 926 | if (*cptr != 0) return SCPE_ARG; /* junk at end? */\r |
| 927 | return -nwd;\r |
| 928 | }\r |
| 929 | \r |
| 930 | /* Parse field */\r |
| 931 | \r |
| 932 | char *parse_field (char *cptr, uint32 max, uint32 *val, uint32 c)\r |
| 933 | {\r |
| 934 | char gbuf[CBUFSIZE];\r |
| 935 | t_stat r;\r |
| 936 | \r |
| 937 | cptr = get_glyph (cptr, gbuf, c); /* get field */\r |
| 938 | *val = get_uint (gbuf, 8, max, &r);\r |
| 939 | if (r != SCPE_OK)\r |
| 940 | return NULL;\r |
| 941 | return cptr;\r |
| 942 | }\r |
| 943 | \r |
| 944 | /* Parse index register */\r |
| 945 | \r |
| 946 | char *parse_fpp_xr (char *cptr, uint32 *xr, t_bool inc)\r |
| 947 | {\r |
| 948 | char gbuf[CBUFSIZE];\r |
| 949 | uint32 len;\r |
| 950 | t_stat r;\r |
| 951 | \r |
| 952 | cptr = get_glyph (cptr, gbuf, 0); /* get field */\r |
| 953 | len = strlen (gbuf);\r |
| 954 | if (gbuf[len - 1] == '+') {\r |
| 955 | if (!inc)\r |
| 956 | return NULL;\r |
| 957 | gbuf[len - 1] = 0;\r |
| 958 | *xr = 010;\r |
| 959 | }\r |
| 960 | else *xr = 0;\r |
| 961 | *xr += get_uint (gbuf, 8, 7, &r);\r |
| 962 | if (r != SCPE_OK)\r |
| 963 | return NULL;\r |
| 964 | return cptr;\r |
| 965 | }\r |
| 966 | \r |
| 967 | /* Test address in range of base register */\r |
| 968 | \r |
| 969 | int32 test_fpp_addr (uint32 ad, uint32 max)\r |
| 970 | {\r |
| 971 | uint32 off;\r |
| 972 | extern uint32 fpp_bra;\r |
| 973 | \r |
| 974 | off = ad - fpp_bra;\r |
| 975 | if (((off % 3) != 0) ||\r |
| 976 | (off > (max * 3)))\r |
| 977 | return -1;\r |
| 978 | return ((int32) off / 3);\r |
| 979 | }\r |