| 1 | /* i1620_sys.c: IBM 1620 simulator interface\r |
| 2 | \r |
| 3 | Copyright (c) 2002-2005, 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 | \r |
| 27 | #include "i1620_defs.h"\r |
| 28 | #include <ctype.h>\r |
| 29 | \r |
| 30 | #define LINE_LNT 50\r |
| 31 | \r |
| 32 | extern DEVICE cpu_dev, tty_dev;\r |
| 33 | extern DEVICE ptr_dev, ptp_dev;\r |
| 34 | extern DEVICE lpt_dev;\r |
| 35 | extern DEVICE cdr_dev, cdp_dev;\r |
| 36 | extern DEVICE dp_dev;\r |
| 37 | extern UNIT cpu_unit;\r |
| 38 | extern REG cpu_reg[];\r |
| 39 | extern uint8 M[MAXMEMSIZE];\r |
| 40 | extern char cdr_to_alp[128], alp_to_cdp[256];\r |
| 41 | \r |
| 42 | /* SCP data structures and interface routines\r |
| 43 | \r |
| 44 | sim_name simulator name string\r |
| 45 | sim_PC pointer to saved PC register descriptor\r |
| 46 | sim_emax maximum number of words for examine/deposit\r |
| 47 | sim_devices array of pointers to simulated devices\r |
| 48 | sim_stop_messages array of pointers to stop messages\r |
| 49 | sim_load binary loader\r |
| 50 | */\r |
| 51 | \r |
| 52 | char sim_name[] = "IBM 1620";\r |
| 53 | \r |
| 54 | REG *sim_PC = &cpu_reg[0];\r |
| 55 | \r |
| 56 | int32 sim_emax = LINE_LNT;\r |
| 57 | \r |
| 58 | DEVICE *sim_devices[] = {\r |
| 59 | &cpu_dev,\r |
| 60 | &tty_dev,\r |
| 61 | &ptr_dev,\r |
| 62 | &ptp_dev,\r |
| 63 | &cdr_dev,\r |
| 64 | &cdp_dev,\r |
| 65 | &lpt_dev,\r |
| 66 | &dp_dev,\r |
| 67 | NULL\r |
| 68 | };\r |
| 69 | \r |
| 70 | const char *sim_stop_messages[] = {\r |
| 71 | "Unknown error",\r |
| 72 | "HALT instruction",\r |
| 73 | "Breakpoint",\r |
| 74 | "Invalid instruction",\r |
| 75 | "Invalid digit",\r |
| 76 | "Invalid character",\r |
| 77 | "Invalid indicator",\r |
| 78 | "Invalid digit in P address",\r |
| 79 | "Invalid P address",\r |
| 80 | "P address exceeds indirect address limit",\r |
| 81 | "Invalid digit in Q address",\r |
| 82 | "Invalid Q address",\r |
| 83 | "Q address exceeds indirect address limit",\r |
| 84 | "Invalid IO device",\r |
| 85 | "Invalid return register",\r |
| 86 | "Invalid IO function",\r |
| 87 | "Instruction address must be even",\r |
| 88 | "Invalid select code",\r |
| 89 | "Index instruction with no band selected",\r |
| 90 | "P address must be odd",\r |
| 91 | "DCF address must be even",\r |
| 92 | "Invalid disk drive",\r |
| 93 | "Invalid disk sector address",\r |
| 94 | "Invalid disk sector count",\r |
| 95 | "Invalid disk buffer address",\r |
| 96 | "Disk address compare error",\r |
| 97 | "Disk write check error",\r |
| 98 | "Disk cylinder overflow error",\r |
| 99 | "Disk wrong length record error",\r |
| 100 | "Invalid CCT",\r |
| 101 | "Field exceeds memory",\r |
| 102 | "Record exceeds memory",\r |
| 103 | "No card in reader",\r |
| 104 | "Overflow check",\r |
| 105 | "Exponent check",\r |
| 106 | "Write address function disabled",\r |
| 107 | "Floating point mantissa too long",\r |
| 108 | "Floating point mantissa lengths unequal",\r |
| 109 | "Floating point exponent flag missing",\r |
| 110 | "Floating point divide by zero"\r |
| 111 | };\r |
| 112 | \r |
| 113 | /* Binary loader -- load carriage control tape\r |
| 114 | \r |
| 115 | A carriage control tape consists of entries of the form\r |
| 116 | \r |
| 117 | (repeat count) column number,column number,column number,...\r |
| 118 | \r |
| 119 | The CCT entries are stored in cct[0:lnt-1], cctlnt contains the\r |
| 120 | number of entries\r |
| 121 | */\r |
| 122 | \r |
| 123 | t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)\r |
| 124 | {\r |
| 125 | int32 col, rpt, ptr, mask, cctbuf[CCT_LNT];\r |
| 126 | t_stat r;\r |
| 127 | extern int32 cct_lnt, cct_ptr, cct[CCT_LNT];\r |
| 128 | char cbuf[CBUFSIZE], gbuf[CBUFSIZE];\r |
| 129 | \r |
| 130 | if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;\r |
| 131 | ptr = 0;\r |
| 132 | for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */\r |
| 133 | mask = 0;\r |
| 134 | if (*cptr == '(') { /* repeat count? */\r |
| 135 | cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */\r |
| 136 | rpt = get_uint (gbuf, 10, CCT_LNT, &r); /* repeat count */\r |
| 137 | if (r != SCPE_OK) return SCPE_FMT;\r |
| 138 | }\r |
| 139 | else rpt = 1;\r |
| 140 | while (*cptr != 0) { /* get col no's */\r |
| 141 | cptr = get_glyph (cptr, gbuf, ','); /* get next field */\r |
| 142 | col = get_uint (gbuf, 10, 12, &r); /* column number */\r |
| 143 | if (r != SCPE_OK) return SCPE_FMT;\r |
| 144 | mask = mask | (1 << col); /* set bit */\r |
| 145 | }\r |
| 146 | for ( ; rpt > 0; rpt--) { /* store vals */\r |
| 147 | if (ptr >= CCT_LNT) return SCPE_FMT;\r |
| 148 | cctbuf[ptr++] = mask;\r |
| 149 | }\r |
| 150 | }\r |
| 151 | if (ptr == 0) return SCPE_FMT;\r |
| 152 | cct_lnt = ptr;\r |
| 153 | cct_ptr = 0;\r |
| 154 | for (rpt = 0; rpt < cct_lnt; rpt++) cct[rpt] = cctbuf[rpt];\r |
| 155 | return SCPE_OK;\r |
| 156 | }\r |
| 157 | \r |
| 158 | /* Symbol table */\r |
| 159 | \r |
| 160 | struct opc {\r |
| 161 | char *str; /* mnemonic */\r |
| 162 | uint32 opv; /* opcode & flags */\r |
| 163 | uint32 qv; /* q field */\r |
| 164 | };\r |
| 165 | \r |
| 166 | #define I_V_FL 16 /* flags */\r |
| 167 | #define I_M_QX 0x01 /* Q indexable */\r |
| 168 | #define I_M_QM 0x02 /* Q immediate */\r |
| 169 | #define I_M_QNP 0x00 /* Q no print */\r |
| 170 | #define I_M_QCP 0x04 /* Q cond print */\r |
| 171 | #define I_M_QP 0x08 /* Q print */\r |
| 172 | #define I_M_PCP 0x00 /* P cond print */\r |
| 173 | #define I_M_PP 0x10 /* P print */\r |
| 174 | #define I_GETQF(x) (((x) >> I_V_FL) & 0x03)\r |
| 175 | #define I_GETQP(x) (((x) >> I_V_FL) & 0x0C)\r |
| 176 | #define I_GETPP(x) (((x) >> I_V_FL) & 0x10)\r |
| 177 | \r |
| 178 | #define I_2 ((I_M_PP | I_M_QP | I_M_QX) << I_V_FL)\r |
| 179 | #define I_2M ((I_M_PP | I_M_QP | I_M_QM) << I_V_FL)\r |
| 180 | #define I_2X ((I_M_PP | I_M_QP | I_M_QX | I_M_QM) << I_V_FL)\r |
| 181 | #define I_2S ((I_M_PP | I_M_QP) << I_V_FL)\r |
| 182 | #define I_1 ((I_M_PP | I_M_QCP) << I_V_FL)\r |
| 183 | #define I_1E ((I_M_PP | I_M_QNP) << I_V_FL)\r |
| 184 | #define I_0 ((I_M_PCP | I_M_QCP) << I_V_FL)\r |
| 185 | #define I_0E ((I_M_PCP | I_M_QNP) << I_V_FL)\r |
| 186 | \r |
| 187 | struct opc opcode[] = {\r |
| 188 | { "RNTY", 36+I_1E, 100 }, { "RATY", 37+I_1E, 100 },\r |
| 189 | { "WNTY", 38+I_1E, 100 }, { "WATY", 39+I_1E, 100 },\r |
| 190 | { "DNTY", 35+I_1E, 100 }, { "SPTY", 34+I_0E, 101 },\r |
| 191 | { "RCTY", 34+I_0E, 102 }, { "BKTY", 34+I_0E, 103 },\r |
| 192 | { "IXTY", 34+I_0E, 104 }, { "TBTY", 34+I_0E, 108 },\r |
| 193 | { "RNPT", 36+I_1E, 300 }, { "RAPT", 37+I_1E, 300 },\r |
| 194 | { "WNPT", 38+I_1E, 200 }, { "WAPT", 39+I_1E, 200 },\r |
| 195 | { "DNPT", 35+I_1E, 200 },\r |
| 196 | { "RNCD", 36+I_1E, 500 }, { "RACD", 37+I_1E, 500 },\r |
| 197 | { "WNCD", 38+I_1E, 400 }, { "WACD", 39+I_1E, 400 },\r |
| 198 | { "DNCD", 35+I_1E, 400 },\r |
| 199 | { "PRN", 38+I_1E, 900 }, { "PRNS", 38+I_1E, 901 },\r |
| 200 | { "PRA", 39+I_1E, 900 }, { "PRAS", 39+I_1E, 901 },\r |
| 201 | { "PRD", 35+I_1E, 900 }, { "PRDS", 35+I_1E, 901 },\r |
| 202 | { "SK", 34+I_1E, 701 },\r |
| 203 | { "RDGN", 36+I_1E, 700 }, { "CDGN", 36+I_1E, 701 },\r |
| 204 | { "RDN", 36+I_1E, 702 }, { "CDN", 36+I_1E, 703 },\r |
| 205 | { "RTGN", 36+I_1E, 704 }, { "CTGN", 36+I_1E, 705 },\r |
| 206 | { "RTN", 36+I_1E, 706 }, { "CTN", 36+I_1E, 707 },\r |
| 207 | { "WDGN", 38+I_1E, 700 }, { "WDN", 38+I_1E, 702 },\r |
| 208 | { "WTGN", 38+I_1E, 704 }, { "WTN", 38+I_1E, 706 },\r |
| 209 | { "RBPT", 37+I_1E, 3300 }, { "WBPT", 39+I_1E, 3200 },\r |
| 210 | { "BC1", 46+I_1E, 100 }, { "BNC1", 47+I_1E, 100 },\r |
| 211 | { "BC2", 46+I_1E, 200 }, { "BNC2", 47+I_1E, 200 },\r |
| 212 | { "BC3", 46+I_1E, 300 }, { "BNC3", 47+I_1E, 300 },\r |
| 213 | { "BC4", 46+I_1E, 400 }, { "BNC4", 47+I_1E, 400 },\r |
| 214 | { "BLC", 46+I_1E, 900 }, { "BNLC", 47+I_1E, 900 },\r |
| 215 | { "BH", 46+I_1E, 1100 }, { "BNH", 47+I_1E, 1100 },\r |
| 216 | { "BP", 46+I_1E, 1100 }, { "BNP", 47+I_1E, 1100 },\r |
| 217 | { "BE", 46+I_1E, 1200 }, { "BNE", 47+I_1E, 1200 },\r |
| 218 | { "BZ", 46+I_1E, 1200 }, { "BNZ", 47+I_1E, 1200 },\r |
| 219 | { "BNL", 46+I_1E, 1300 }, { "BL", 47+I_1E, 1300 },\r |
| 220 | { "BNN", 46+I_1E, 1300 }, { "BN", 47+I_1E, 1300 },\r |
| 221 | { "BV", 46+I_1E, 1400 }, { "BNV", 47+I_1E, 1400 },\r |
| 222 | { "BXV", 46+I_1E, 1500 }, { "BNXV", 47+I_1E, 1500 },\r |
| 223 | { "BA", 46+I_1E, 1900 }, { "BNA", 47+I_1E, 1900 },\r |
| 224 | { "BNBS", 46+I_1E, 3000 }, { "BEBS", 47+I_1E, 3000 },\r |
| 225 | { "BBAS", 46+I_1E, 3100 }, { "BANS", 47+I_1E, 3100 },\r |
| 226 | { "BBBS", 46+I_1E, 3200 }, { "BBNS", 47+I_1E, 3200 },\r |
| 227 | { "BCH9", 46+I_1E, 3300 },\r |
| 228 | { "BCOV", 46+I_1E, 3400 },\r |
| 229 | { "BSNX", 60+I_1E, 0 }, { "BSBA", 60+I_1E, 1 },\r |
| 230 | { "BSBB", 60+I_1E, 2 },\r |
| 231 | { "BSNI", 60+I_1E, 8 }, { "BSIA", 60+I_1E, 9 },\r |
| 232 | \r |
| 233 | { "FADD", 1+I_2, 0 }, { "FSUB", 2+I_2, 0 },\r |
| 234 | { "FMUL", 3+I_2, 0 }, { "FSL", 5+I_2, 0 },\r |
| 235 | { "TFL", 6+I_2, 0 }, { "BTFL", 7+I_2, 0 },\r |
| 236 | { "FSR", 8+I_2, 0 }, { "FDIV", 9+I_2, 0 },\r |
| 237 | { "BTAM", 10+I_2M, 0 }, { "AM", 11+I_2M, 0 },\r |
| 238 | { "SM", 12+I_2M, 0 }, { "MM", 13+I_2M, 0 },\r |
| 239 | { "CM", 14+I_2M, 0 }, { "TDM", 15+I_2S, 0 },\r |
| 240 | { "TFM", 16+I_2M, 0 }, { "BTM", 17+I_2M, 0 },\r |
| 241 | { "LDM", 18+I_2M, 0 }, { "DM", 19+I_2M, 0 },\r |
| 242 | { "BTA", 20+I_2, 0 }, { "A", 21+I_2, 0 },\r |
| 243 | { "S", 22+I_2, 0 }, { "M", 23+I_2, 0 },\r |
| 244 | { "C", 24+I_2, 0 }, { "TD", 25+I_2, 0 },\r |
| 245 | { "TF", 26+I_2, 0 }, { "BT", 27+I_2, 0 },\r |
| 246 | { "LD", 28+I_2, 0 }, { "D", 29+I_2, 0 },\r |
| 247 | { "TRNM", 30+I_2, 0 }, { "TR", 31+I_2, 0 },\r |
| 248 | { "SF", 32+I_1, 0 }, { "CF", 33+I_1, 0 },\r |
| 249 | { "K", 34+I_2S, 0 }, { "DN", 35+I_2S, 0 },\r |
| 250 | { "RN", 36+I_2S, 0 }, { "RA", 37+I_2S, 0 },\r |
| 251 | { "WN", 38+I_2S, 0 }, { "WA", 39+I_2S, 0 },\r |
| 252 | { "NOP", 41+I_0, 0 }, { "BB", 42+I_0, 0 },\r |
| 253 | { "BD", 43+I_2, 0 }, { "BNF", 44+I_2, 0 },\r |
| 254 | { "BNR", 45+I_2, 0 }, { "BI", 46+I_2S, 0 },\r |
| 255 | { "BNI", 47+I_2S, 0 }, { "H", 48+I_0, 0 },\r |
| 256 | { "B", 49+I_1, 0 }, { "BNG", 55+I_2, 0 },\r |
| 257 | { "BS", 60+I_2S, 0 }, { "BX", 61+I_2, 0 },\r |
| 258 | { "BXM", 62+I_2X, 0 }, { "BCX", 63+I_2, 0 },\r |
| 259 | { "BCXM", 64+I_2X, 0 }, { "BLX", 65+I_2, 0 },\r |
| 260 | { "BLXM", 66+I_2X, 0 }, { "BSX", 67+I_2, 0 },\r |
| 261 | { "MA", 70+I_2, 0 }, { "MF", 71+I_2, 0 },\r |
| 262 | { "TNS", 72+I_2, 0 }, { "TNF", 73+I_2, 0 },\r |
| 263 | { "BBT", 90+I_2, 0 }, { "BMK", 91+I_2, 0 },\r |
| 264 | { "ORF", 92+I_2, 0 }, { "ANDF", 93+I_2, 0 },\r |
| 265 | { "CPFL", 94+I_2, 0 }, { "EORF", 95+I_2, 0 },\r |
| 266 | { "OTD", 96+I_2, 0 }, { "DTO", 97+I_2, 0 },\r |
| 267 | { NULL, 0, 0 }\r |
| 268 | };\r |
| 269 | \r |
| 270 | /* Print an address from five characters */\r |
| 271 | \r |
| 272 | void fprint_addr (FILE *of, int32 spc, t_value *dig, t_bool flg)\r |
| 273 | {\r |
| 274 | int32 i, idx;\r |
| 275 | \r |
| 276 | fputc (spc, of); /* spacer */\r |
| 277 | if (dig[ADDR_LEN - 1] & FLAG) { /* signed? */\r |
| 278 | fputc ('-', of); /* print minus */\r |
| 279 | dig[ADDR_LEN - 1] = dig[ADDR_LEN - 1] & ~FLAG;\r |
| 280 | }\r |
| 281 | for (i = 0; i < ADDR_LEN; i++) /* print digits */\r |
| 282 | fprintf (of, "%X", dig[i] & DIGIT);\r |
| 283 | if ((cpu_unit.flags & IF_IDX) && flg) { /* indexing? */\r |
| 284 | for (i = idx = 0; i < ADDR_LEN - 2; i++) { /* get index reg */\r |
| 285 | if (dig[ADDR_LEN - 2 - i] & FLAG)\r |
| 286 | idx = idx | (1 << i);\r |
| 287 | dig[ADDR_LEN - 2 - i] = dig[ADDR_LEN - 2 - i] & ~FLAG;\r |
| 288 | }\r |
| 289 | if (idx) fprintf (of, "(%d)", idx); /* print */\r |
| 290 | }\r |
| 291 | return;\r |
| 292 | }\r |
| 293 | \r |
| 294 | /* Symbolic decode\r |
| 295 | \r |
| 296 | Inputs:\r |
| 297 | *of = output stream\r |
| 298 | addr = current address\r |
| 299 | *val = values to decode\r |
| 300 | *uptr = pointer to unit\r |
| 301 | sw = switches\r |
| 302 | Outputs:\r |
| 303 | return = if >= 0, error code\r |
| 304 | if < 0, number of extra words retired\r |
| 305 | */\r |
| 306 | \r |
| 307 | #define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)\r |
| 308 | \r |
| 309 | t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,\r |
| 310 | UNIT *uptr, int32 sw)\r |
| 311 | {\r |
| 312 | int32 pmp, qmp, i, c, d, any;\r |
| 313 | uint32 op, qv, opfl;\r |
| 314 | \r |
| 315 | if (uptr == NULL) uptr = &cpu_unit;\r |
| 316 | if (sw & SWMASK ('C')) { /* character? */\r |
| 317 | if (uptr->flags & UNIT_BCD) {\r |
| 318 | if (addr & 1) return SCPE_ARG; /* must be even */\r |
| 319 | c = ((val[0] & DIGIT) << 4) | (val[1] & DIGIT);\r |
| 320 | if (alp_to_cdp[c] > 0)\r |
| 321 | fprintf (of, "%c", alp_to_cdp[c]);\r |
| 322 | else fprintf (of, "<%02x>", c);\r |
| 323 | return -1;\r |
| 324 | } \r |
| 325 | else fprintf (of, FMTASC (val[0] & 0177));\r |
| 326 | return SCPE_OK;\r |
| 327 | }\r |
| 328 | if ((uptr->flags & UNIT_BCD) == 0) return SCPE_ARG; /* CPU or disk? */\r |
| 329 | if (sw & SWMASK ('D')) { /* dump? */\r |
| 330 | for (i = d = 0; i < LINE_LNT; i++) d = d | val[i];\r |
| 331 | if (d & FLAG) { /* any flags? */\r |
| 332 | for (i = 0; i < LINE_LNT; i++) /* print flags */\r |
| 333 | fprintf (of, (val[i] & FLAG)? "_": " ");\r |
| 334 | fprintf (of, "\n\t");\r |
| 335 | }\r |
| 336 | for (i = 0; i < LINE_LNT; i++) /* print digits */\r |
| 337 | fprintf (of, "%X", val[i] & DIGIT) ;\r |
| 338 | return -(i - 1);\r |
| 339 | }\r |
| 340 | if (sw & SWMASK ('S')) { /* string? */\r |
| 341 | if (addr & 1) return SCPE_ARG; /* must be even */\r |
| 342 | for (i = 0; i < LINE_LNT; i = i + 2) {\r |
| 343 | c = ((val[i] & DIGIT) << 4) | (val[i + 1] & DIGIT);\r |
| 344 | if (alp_to_cdp[c] < 0) break;\r |
| 345 | fprintf (of, "%c", alp_to_cdp[c]);\r |
| 346 | }\r |
| 347 | if (i == 0) {\r |
| 348 | fprintf (of, "<%02X>", c);\r |
| 349 | return -1;\r |
| 350 | }\r |
| 351 | return -(i - 1);\r |
| 352 | }\r |
| 353 | if ((sw & SWMASK ('M')) == 0) return SCPE_ARG;\r |
| 354 | \r |
| 355 | if (addr & 1) return SCPE_ARG; /* must be even */\r |
| 356 | op = ((val[0] & DIGIT) * 10) + (val[1] & DIGIT); /* get opcode */\r |
| 357 | for (i = qv = pmp = qmp = 0; i < ADDR_LEN; i++) { /* test addr */\r |
| 358 | if (val[I_P + i]) pmp = 1;\r |
| 359 | if (val[I_Q + i]) qmp = 1;\r |
| 360 | qv = (qv * 10) + (val[I_Q + i] & DIGIT);\r |
| 361 | }\r |
| 362 | if ((val[0] | val[1]) & FLAG) pmp = qmp = 1; /* flags force */\r |
| 363 | for (i = 0; opcode[i].str != NULL; i++) { /* find opcode */\r |
| 364 | opfl = opcode[i].opv & 0xFF0000;\r |
| 365 | if ((op == (opcode[i].opv & 0xFF)) &&\r |
| 366 | ((qv == opcode[i].qv) ||\r |
| 367 | ((opfl != I_1E) && (opfl != I_0E)))) break;\r |
| 368 | }\r |
| 369 | if (opcode[i].str == NULL) return SCPE_ARG;\r |
| 370 | if (I_GETQP (opfl) == I_M_QNP) qmp = 0; /* Q no print? */\r |
| 371 | \r |
| 372 | fprintf (of, opcode[i].str); /* print opcode */\r |
| 373 | if (I_GETPP (opfl) == I_M_PP) /* P required? */\r |
| 374 | fprint_addr (of, ' ', &val[I_P], I_M_QX);\r |
| 375 | else if ((I_GETPP (opfl) == I_M_PCP) && (pmp || qmp)) /* P opt & needed? */\r |
| 376 | fprint_addr (of, ' ', &val[I_P], 0);\r |
| 377 | if (I_GETQP (opfl) == I_M_QP) { /* Q required? */\r |
| 378 | fprint_addr (of, ',', &val[I_Q], I_GETQF (opfl));\r |
| 379 | if (I_GETQF (opfl) & I_M_QM) /* immediate? */\r |
| 380 | val[I_Q] = val[I_Q] & ~FLAG; /* clr hi Q flag */\r |
| 381 | }\r |
| 382 | else if ((I_GETQP (opfl) == I_M_QCP) && (pmp || qmp)) /* Q opt & needed? */\r |
| 383 | fprint_addr (of, ',', &val[I_Q], 0);\r |
| 384 | for (i = any = 0; i < INST_LEN; i++) { /* print rem flags */\r |
| 385 | if (val[i] & FLAG) {\r |
| 386 | if (!any) fputc (',', of);\r |
| 387 | any = 1;\r |
| 388 | fprintf (of, "%d", i);\r |
| 389 | }\r |
| 390 | }\r |
| 391 | return -(INST_LEN - 1);\r |
| 392 | }\r |
| 393 | \r |
| 394 | /* parse_addr - get sign + address + index */\r |
| 395 | \r |
| 396 | t_stat parse_addr (char *cptr, t_value *val, int32 flg)\r |
| 397 | {\r |
| 398 | int32 i, sign = 0, addr, index;\r |
| 399 | static int32 idx_tst[ADDR_LEN] = { 0, 4, 2, 1, 0 };\r |
| 400 | char *tptr;\r |
| 401 | \r |
| 402 | if (*cptr == '+') cptr++; /* +? skip */\r |
| 403 | else if (*cptr == '-') { /* -? skip, flag */\r |
| 404 | sign = 1;\r |
| 405 | cptr++;\r |
| 406 | }\r |
| 407 | errno = 0; /* get address */\r |
| 408 | addr = strtoul (cptr, &tptr, 16);\r |
| 409 | if (errno || (cptr == tptr) || (addr > 0xFFFFF)) /* err or too big? */\r |
| 410 | return SCPE_ARG;\r |
| 411 | if ((cpu_unit.flags & IF_IDX) && (flg & I_M_QX) && /* index allowed? */\r |
| 412 | (*tptr == '(')) { /* index specified */\r |
| 413 | errno = 0;\r |
| 414 | index = strtoul (cptr = tptr + 1, &tptr, 10); /* get index */\r |
| 415 | if (errno || (cptr == tptr) || (index > 7)) /* err or too big? */\r |
| 416 | return SCPE_ARG;\r |
| 417 | if (*tptr++ != ')') return SCPE_ARG;\r |
| 418 | }\r |
| 419 | else index = 0;\r |
| 420 | if (*tptr != 0) return SCPE_ARG; /* all done? */\r |
| 421 | for (i = ADDR_LEN - 1; i >= 0; i--) { /* cvt addr to dig */\r |
| 422 | val[i] = (addr & 0xF) | ((index & idx_tst[i])? FLAG: 0);\r |
| 423 | addr = addr >> 4;\r |
| 424 | }\r |
| 425 | if (sign) val[ADDR_LEN - 1] = val[ADDR_LEN - 1] | FLAG; /* set sign */\r |
| 426 | if (flg & I_M_QM) val[0] = val[0] | FLAG; /* set immediate */\r |
| 427 | return SCPE_OK;\r |
| 428 | }\r |
| 429 | \r |
| 430 | /* Symbolic input\r |
| 431 | \r |
| 432 | Inputs:\r |
| 433 | *cptr = pointer to input string\r |
| 434 | addr = current PC\r |
| 435 | *uptr = pointer to unit\r |
| 436 | *val = pointer to output values\r |
| 437 | sw = switches\r |
| 438 | Outputs:\r |
| 439 | status = > 0 error code\r |
| 440 | <= 0 -number of extra words\r |
| 441 | */\r |
| 442 | \r |
| 443 | t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)\r |
| 444 | {\r |
| 445 | int32 i, qv, opfl, last;\r |
| 446 | char t, la, *fptr, gbuf[CBUFSIZE];\r |
| 447 | \r |
| 448 | while (isspace (*cptr)) cptr++; /* absorb spaces */\r |
| 449 | if ((sw & SWMASK ('C')) || ((*cptr == '\'') && cptr++)) { /* character? */\r |
| 450 | if ((t = *cptr & 0x7F) == 0) return SCPE_ARG; /* get char */\r |
| 451 | if (uptr->flags & UNIT_BCD) { /* BCD? */\r |
| 452 | if (addr & 1) return SCPE_ARG;\r |
| 453 | t = cdr_to_alp[t]; /* convert */\r |
| 454 | if (t < 0) return SCPE_ARG; /* invalid? */\r |
| 455 | val[0] = (t >> 4) & DIGIT; /* store */\r |
| 456 | val[1] = t & DIGIT;\r |
| 457 | return -1;\r |
| 458 | }\r |
| 459 | else val[0] = t; /* store ASCII */\r |
| 460 | return SCPE_OK;\r |
| 461 | }\r |
| 462 | \r |
| 463 | if ((uptr->flags & UNIT_BCD) == 0) return SCPE_ARG; /* CPU or disk? */\r |
| 464 | if ((sw & SWMASK ('S')) || ((*cptr == '"') && cptr++)) { /* string? */\r |
| 465 | if (addr & 1) return SCPE_ARG; /* must be even */\r |
| 466 | for (i = 0; (i < sim_emax) && (*cptr != 0); i = i + 2) {\r |
| 467 | t = *cptr++ & 0x7F; /* get character */\r |
| 468 | t = cdr_to_alp[t]; /* convert */\r |
| 469 | if (t < 0) return SCPE_ARG; /* invalid? */\r |
| 470 | val[i] = (t >> 4) & DIGIT; /* store */\r |
| 471 | val[i + 1] = t & DIGIT;\r |
| 472 | }\r |
| 473 | if (i == 0) return SCPE_ARG; /* final check */\r |
| 474 | return -(i - 1);\r |
| 475 | }\r |
| 476 | \r |
| 477 | if (addr & 1) return SCPE_ARG; /* even addr? */\r |
| 478 | cptr = get_glyph (cptr, gbuf, 0); /* get opcode */\r |
| 479 | for (i = 0; opcode[i].str != NULL; i++) { /* look it up */\r |
| 480 | if (strcmp (gbuf, opcode[i].str) == 0) break;\r |
| 481 | }\r |
| 482 | if (opcode[i].str == NULL) return SCPE_ARG; /* successful? */\r |
| 483 | opfl = opcode[i].opv & 0xFF0000; /* get flags */\r |
| 484 | val[0] = (opcode[i].opv & 0xFF) / 10; /* store opcode */\r |
| 485 | val[1] = (opcode[i].opv & 0xFF) % 10;\r |
| 486 | qv = opcode[i].qv;\r |
| 487 | for (i = ADDR_LEN - 1; i >= 0; i--) { /* set P,Q fields */\r |
| 488 | val[I_P + i] = 0;\r |
| 489 | val[I_Q + i] = qv % 10;\r |
| 490 | qv = qv /10;\r |
| 491 | }\r |
| 492 | \r |
| 493 | cptr = get_glyph (cptr, gbuf, ','); /* get P field */\r |
| 494 | if (gbuf[0]) { /* any? */\r |
| 495 | if (parse_addr (gbuf, &val[I_P], (I_GETPP (opfl)?\r |
| 496 | I_M_QX: 0))) return SCPE_ARG;\r |
| 497 | }\r |
| 498 | else if (I_GETPP (opfl) == I_M_PP) return SCPE_ARG;\r |
| 499 | \r |
| 500 | if (I_GETQP (opfl) != I_M_QNP) { /* Q field allowed? */\r |
| 501 | cptr = get_glyph (cptr, gbuf, ','); /* get Q field */\r |
| 502 | if (gbuf[0]) { /* any? */\r |
| 503 | if (parse_addr (gbuf, &val[I_Q], I_GETQF (opfl)))\r |
| 504 | return SCPE_ARG;\r |
| 505 | }\r |
| 506 | else if (I_GETQP (opfl) == I_M_QP) return SCPE_ARG;\r |
| 507 | }\r |
| 508 | \r |
| 509 | cptr = get_glyph (cptr, fptr = gbuf, ' '); /* get flag field */\r |
| 510 | last = -1; /* none yet */\r |
| 511 | while (t = *fptr++) { /* loop through */\r |
| 512 | if ((t < '0') || (t > '9')) return SCPE_ARG; /* must be digit */\r |
| 513 | t = t - '0'; /* convert */\r |
| 514 | if (t == 1) { /* ambiguous? */\r |
| 515 | la = *fptr++; /* get next */\r |
| 516 | if (la == '0') t = 10; /* 10? */\r |
| 517 | else if ((la == '1') && (*fptr == 0)) t = 11; /* 11 & end field? */\r |
| 518 | else --fptr; /* dont lookahead */\r |
| 519 | }\r |
| 520 | if (t <= last) return SCPE_ARG; /* in order? */\r |
| 521 | val[t] = val[t] | FLAG; /* set flag */\r |
| 522 | last = t; /* continue */\r |
| 523 | }\r |
| 524 | \r |
| 525 | if (*cptr != 0) return SCPE_ARG;\r |
| 526 | return -(INST_LEN - 1);\r |
| 527 | }\r |