| 1 | /* sds_sys.c: SDS 940 simulator interface\r |
| 2 | \r |
| 3 | Copyright (c) 2001-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 "sds_defs.h"\r |
| 28 | #include <ctype.h>\r |
| 29 | #define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)\r |
| 30 | \r |
| 31 | extern DEVICE cpu_dev;\r |
| 32 | extern DEVICE chan_dev;\r |
| 33 | extern DEVICE ptr_dev;\r |
| 34 | extern DEVICE ptp_dev;\r |
| 35 | extern DEVICE tti_dev;\r |
| 36 | extern DEVICE tto_dev;\r |
| 37 | extern DEVICE lpt_dev;\r |
| 38 | extern DEVICE rtc_dev;\r |
| 39 | extern DEVICE drm_dev;\r |
| 40 | extern DEVICE rad_dev;\r |
| 41 | extern DEVICE dsk_dev;\r |
| 42 | extern DEVICE mt_dev;\r |
| 43 | extern DEVICE mux_dev, muxl_dev;\r |
| 44 | extern UNIT cpu_unit;\r |
| 45 | extern REG cpu_reg[];\r |
| 46 | extern uint32 M[MAXMEMSIZE];\r |
| 47 | \r |
| 48 | /* SCP data structures and interface routines\r |
| 49 | \r |
| 50 | sim_name simulator name string\r |
| 51 | sim_PC pointer to saved PC register descriptor\r |
| 52 | sim_emax number of words for examine\r |
| 53 | sim_devices array of pointers to simulated devices\r |
| 54 | sim_stop_messages array of pointers to stop messages\r |
| 55 | sim_load binary loader\r |
| 56 | */\r |
| 57 | \r |
| 58 | char sim_name[] = "SDS 940";\r |
| 59 | \r |
| 60 | REG *sim_PC = &cpu_reg[0];\r |
| 61 | \r |
| 62 | int32 sim_emax = 1;\r |
| 63 | \r |
| 64 | DEVICE *sim_devices[] = {\r |
| 65 | &cpu_dev,\r |
| 66 | &chan_dev,\r |
| 67 | &ptr_dev,\r |
| 68 | &ptp_dev,\r |
| 69 | &tti_dev,\r |
| 70 | &tto_dev,\r |
| 71 | &lpt_dev,\r |
| 72 | &rtc_dev,\r |
| 73 | &drm_dev,\r |
| 74 | &rad_dev,\r |
| 75 | &dsk_dev,\r |
| 76 | &mt_dev,\r |
| 77 | &mux_dev,\r |
| 78 | &muxl_dev,\r |
| 79 | NULL\r |
| 80 | };\r |
| 81 | \r |
| 82 | const char *sim_stop_messages[] = {\r |
| 83 | "Unknown error",\r |
| 84 | "IO device not ready",\r |
| 85 | "HALT instruction",\r |
| 86 | "Breakpoint",\r |
| 87 | "Invalid IO device",\r |
| 88 | "Invalid instruction",\r |
| 89 | "Invalid I/O operation",\r |
| 90 | "Nested indirects exceed limit",\r |
| 91 | "Nested EXU's exceed limit",\r |
| 92 | "Memory management trap during interrupt",\r |
| 93 | "Memory management trap during trap",\r |
| 94 | "Trap instruction not BRM",\r |
| 95 | "RTC instruction not MIN or SKR",\r |
| 96 | "Interrupt vector zero",\r |
| 97 | "Runaway carriage control tape"\r |
| 98 | };\r |
| 99 | \r |
| 100 | /* Character conversion tables */\r |
| 101 | \r |
| 102 | const char sds_to_ascii[64] = {\r |
| 103 | '0', '1', '2', '3', '4', '5', '6', '7',\r |
| 104 | '8', '9', ' ', '=', '\'', ':', '>', '%', /* 17 = check mark */\r |
| 105 | '+', 'A', 'B', 'C', 'D', 'E', 'F', 'G',\r |
| 106 | 'H', 'I', '?', '.', ')', '[', '<', '@', /* 37 = stop code */\r |
| 107 | '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',\r |
| 108 | 'Q', 'R', '!', '$', '*', ']', ';', '^', /* 57 = triangle */\r |
| 109 | '_', '/', 'S', 'T', 'U', 'V', 'W', 'X',\r |
| 110 | 'Y', 'Z', '?', ',', '(', '~', '\\', '#' /* 72 = rec mark */\r |
| 111 | }; /* 75 = squiggle, 77 = del */\r |
| 112 | \r |
| 113 | const char ascii_to_sds[128] = {\r |
| 114 | -1, -1, -1, -1, -1, -1, -1, -1, /* 0 - 37 */\r |
| 115 | 032, 072, -1, -1, -1, 052, -1, -1,\r |
| 116 | -1, -1, -1, -1, -1, -1, -1, -1,\r |
| 117 | -1, -1, -1, -1, -1, -1, -1, -1,\r |
| 118 | 012, 052, -1, 077, 053, 017, -1, 014, /* 40 - 77 */\r |
| 119 | 074, 034, 054, 020, 073, 040, 033, 061,\r |
| 120 | 000, 001, 002, 003, 004, 005, 006, 007,\r |
| 121 | 010, 011, 015, 056, 036, 013, 016, 072,\r |
| 122 | 037, 021, 022, 023, 024, 025, 026, 027, /* 100 - 137 */\r |
| 123 | 030, 031, 041, 042, 043, 044, 045, 046,\r |
| 124 | 047, 050, 051, 062, 063, 064, 065, 066,\r |
| 125 | 067, 070, 071, 035, 076, 055, 057, 060,\r |
| 126 | 000, 021, 022, 023, 024, 025, 026, 027, /* 140 - 177 */\r |
| 127 | 030, 031, 041, 042, 043, 044, 045, 046,\r |
| 128 | 047, 050, 051, 062, 063, 064, 065, 066,\r |
| 129 | 067, 070, 071, -1, -1, -1, -1, -1\r |
| 130 | };\r |
| 131 | \r |
| 132 | const char odd_par[64] = {\r |
| 133 | 0100, 0001, 0002, 0103, 0004, 0105, 0106, 0007,\r |
| 134 | 0010, 0111, 0112, 0013, 0114, 0015, 0016, 0117,\r |
| 135 | 0020, 0121, 0122, 0023, 0124, 0025, 0026, 0127,\r |
| 136 | 0130, 0031, 0032, 0133, 0034, 0135, 0136, 0037,\r |
| 137 | 0040, 0141, 0142, 0043, 0144, 0045, 0046, 0147,\r |
| 138 | 0150, 0051, 0052, 0153, 0054, 0155, 0156, 0057,\r |
| 139 | 0160, 0061, 0062, 0163, 0064, 0165, 0166, 0067,\r |
| 140 | 0070, 0171, 0172, 0073, 0174, 0075, 0076, 0177\r |
| 141 | };\r |
| 142 | \r |
| 143 | /* Load carriage control tape\r |
| 144 | \r |
| 145 | A carriage control tape consists of entries of the form\r |
| 146 | \r |
| 147 | (repeat count) column number,column number,column number,...\r |
| 148 | \r |
| 149 | The CCT entries are stored in lpt_cct[0:lnt-1], lpt_ccl contains the\r |
| 150 | number of entries\r |
| 151 | */\r |
| 152 | \r |
| 153 | t_stat sim_load_cct (FILE *fileref)\r |
| 154 | {\r |
| 155 | int32 col, rpt, ptr, mask, cctbuf[CCT_LNT];\r |
| 156 | t_stat r;\r |
| 157 | extern int32 lpt_ccl, lpt_ccp, lpt_cct[CCT_LNT];\r |
| 158 | char *cptr, cbuf[CBUFSIZE], gbuf[CBUFSIZE];\r |
| 159 | \r |
| 160 | ptr = 0;\r |
| 161 | for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */\r |
| 162 | mask = 0;\r |
| 163 | if (*cptr == '(') { /* repeat count? */\r |
| 164 | cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */\r |
| 165 | rpt = get_uint (gbuf, 10, CCT_LNT, &r); /* repeat count */\r |
| 166 | if (r != SCPE_OK) return SCPE_FMT;\r |
| 167 | }\r |
| 168 | else rpt = 1;\r |
| 169 | while (*cptr != 0) { /* get col no's */\r |
| 170 | cptr = get_glyph (cptr, gbuf, ','); /* get next field */\r |
| 171 | col = get_uint (gbuf, 10, 7, &r); /* column number */\r |
| 172 | if (r != SCPE_OK) return SCPE_FMT;\r |
| 173 | mask = mask | (1 << col); /* set bit */\r |
| 174 | }\r |
| 175 | for ( ; rpt > 0; rpt--) { /* store vals */\r |
| 176 | if (ptr >= CCT_LNT) return SCPE_FMT;\r |
| 177 | cctbuf[ptr++] = mask;\r |
| 178 | }\r |
| 179 | }\r |
| 180 | if (ptr == 0) return SCPE_FMT;\r |
| 181 | lpt_ccl = ptr;\r |
| 182 | lpt_ccp = 0;\r |
| 183 | for (rpt = 0; rpt < lpt_ccl; rpt++) lpt_cct[rpt] = cctbuf[rpt];\r |
| 184 | return SCPE_OK;\r |
| 185 | }\r |
| 186 | \r |
| 187 | /* Load command. -l means load a line printer tape. Otherwise, load\r |
| 188 | a bootstrap paper tape.\r |
| 189 | */\r |
| 190 | \r |
| 191 | int32 get_word (FILE *fileref, int32 *ldr)\r |
| 192 | {\r |
| 193 | int32 i, c, wd;\r |
| 194 | \r |
| 195 | for (i = wd = 0; i < 4; ) {\r |
| 196 | if ((c = fgetc (fileref)) == EOF) return -1;\r |
| 197 | if ((c == 0) && (*ldr == 0)) return -1;\r |
| 198 | if (c == 0) continue;\r |
| 199 | *ldr = 0;\r |
| 200 | wd = (wd << 6) | (c & 077);\r |
| 201 | i++;\r |
| 202 | }\r |
| 203 | return wd;\r |
| 204 | }\r |
| 205 | \r |
| 206 | t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)\r |
| 207 | {\r |
| 208 | int32 i, wd, buf[8];\r |
| 209 | int32 ldr = 1;\r |
| 210 | extern int32 sim_switches;\r |
| 211 | extern uint32 P;\r |
| 212 | \r |
| 213 | if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;\r |
| 214 | if (sim_switches & SWMASK ('L')) return sim_load_cct (fileref);\r |
| 215 | for (i = 0; i < 8; i++) { /* read boot */\r |
| 216 | if ((wd = get_word (fileref, &ldr)) < 0) return SCPE_FMT;\r |
| 217 | buf[i] = wd;\r |
| 218 | }\r |
| 219 | if ((buf[0] != 023200012) || /* 2 = WIM 12,2 */\r |
| 220 | (buf[1] != 004100002) || /* 3 = BRX 2 */\r |
| 221 | (buf[2] != 007100011) || /* 4 = LDX 11 */\r |
| 222 | (buf[3] != 023200000) || /* 5 = WIM 0,2 */\r |
| 223 | (buf[4] != 004021000) || /* 6 = SKS 21000 */\r |
| 224 | (buf[5] != 004100005)) return SCPE_FMT; /* 7 = BRX 5 */\r |
| 225 | for (i = 0; i < 8; i++) M[i + 2] = buf[i]; /* copy boot */\r |
| 226 | if (I_GETOP (buf[6]) == BRU) P = buf[6] & VA_MASK;\r |
| 227 | for (i = buf[7] & VA_MASK; i <= VA_MASK; i++) { /* load data */\r |
| 228 | if ((wd = get_word (fileref, &ldr)) < 0) return SCPE_OK;\r |
| 229 | M[i] = wd;\r |
| 230 | }\r |
| 231 | return SCPE_NXM;\r |
| 232 | }\r |
| 233 | \r |
| 234 | /* Symbol tables */\r |
| 235 | \r |
| 236 | #define I_V_FL 24 /* inst class */\r |
| 237 | #define I_M_FL 017 /* class mask */\r |
| 238 | #define I_V_NPN 000 /* no operand */\r |
| 239 | #define I_V_PPO 001 /* POP */\r |
| 240 | #define I_V_IOI 002 /* IO */\r |
| 241 | #define I_V_MRF 003 /* memory reference */\r |
| 242 | #define I_V_REG 004 /* register change */\r |
| 243 | #define I_V_SHF 005 /* shift */\r |
| 244 | #define I_V_OPO 006 /* opcode only */\r |
| 245 | #define I_V_CHC 007 /* chan cmd */\r |
| 246 | #define I_V_CHT 010 /* chan test */\r |
| 247 | #define I_NPN (I_V_NPN << I_V_FL) \r |
| 248 | #define I_PPO (I_V_PPO << I_V_FL) \r |
| 249 | #define I_IOI (I_V_IOI << I_V_FL) \r |
| 250 | #define I_MRF (I_V_MRF << I_V_FL) \r |
| 251 | #define I_REG (I_V_REG << I_V_FL) \r |
| 252 | #define I_SHF (I_V_SHF << I_V_FL) \r |
| 253 | #define I_OPO (I_V_OPO << I_V_FL)\r |
| 254 | #define I_CHC (I_V_CHC << I_V_FL)\r |
| 255 | #define I_CHT (I_V_CHT << I_V_FL) \r |
| 256 | \r |
| 257 | static const int32 masks[] = {\r |
| 258 | 037777777, 010000000, 017700000,\r |
| 259 | 017740000, 017700000, 017774000,\r |
| 260 | 017700000, 017377677, 027737677\r |
| 261 | };\r |
| 262 | \r |
| 263 | static const char *opcode[] = {\r |
| 264 | "POP", "EIR", "DIR",\r |
| 265 | "ROV", "REO", "OTO", "OVT",\r |
| 266 | "IDT", "IET",\r |
| 267 | "BPT4", "BPT3", "BPT2", "BPT1",\r |
| 268 | "CLAB", "ABC", "BAC", "XAB",\r |
| 269 | "XXB", "STE", "LDE", "XEE",\r |
| 270 | "CLEAR",\r |
| 271 | \r |
| 272 | "HLT", "BRU", "EOM", "EOD",\r |
| 273 | "MIY", "BRI", "MIW", "POT",\r |
| 274 | "ETR", "MRG", "EOR",\r |
| 275 | "NOP", "EXU",\r |
| 276 | "YIM", "WIM", "PIN",\r |
| 277 | "STA", "STB", "STX",\r |
| 278 | "SKS", "BRX", "BRM",\r |
| 279 | "SKE", "BRR", "SKB", "SKN",\r |
| 280 | "SUB", "ADD", "SUC", "ADC",\r |
| 281 | "SKR", "MIN", "XMA", "ADM",\r |
| 282 | "MUL", "DIV",\r |
| 283 | "SKM", "LDX", "SKA", "SKG",\r |
| 284 | "SKD", "LDB", "LDA", "EAX",\r |
| 285 | \r |
| 286 | "BRU*", \r |
| 287 | "MIY*", "BRI*", "MIW*", "POT*",\r |
| 288 | "ETR*", "MRG*", "EOR*",\r |
| 289 | "EXU*",\r |
| 290 | "YIM*", "WIM*", "PIN*",\r |
| 291 | "STA*", "STB*", "STX*",\r |
| 292 | "BRX*", "BRM*",\r |
| 293 | "SKE*", "BRR*", "SKB*", "SKN*",\r |
| 294 | "SUB*", "ADD*", "SUC*", "ADC*",\r |
| 295 | "SKR*", "MIN*", "XMA*", "ADM*",\r |
| 296 | "MUL*", "DIV*",\r |
| 297 | "SKM*", "LDX*", "SKA*", "SKG*",\r |
| 298 | "SKD*", "LDB*", "LDA*", "EAX*",\r |
| 299 | \r |
| 300 | "RSH", "RCY", "LRSH",\r |
| 301 | "LSH", "NOD", "LCY",\r |
| 302 | "RSH*", "LSH*",\r |
| 303 | \r |
| 304 | "ALC", "DSC", "ASC", "TOP",\r |
| 305 | "CAT", "CET", "CZT", "CIT",\r |
| 306 | \r |
| 307 | "CLA", "CLB", "CAB", /* encode only */\r |
| 308 | "CBA", "CBX", "CXB",\r |
| 309 | "XPO", "CXA", "CAX",\r |
| 310 | "CNA", "CLX", NULL,\r |
| 311 | NULL\r |
| 312 | };\r |
| 313 | \r |
| 314 | static const int32 opc_val[] = {\r |
| 315 | 010000000+I_PPO, 000220002+I_NPN, 000220004+I_NPN,\r |
| 316 | 002200001+I_NPN, 002200010+I_NPN, 002200100+I_NPN, 002200101+I_NPN,\r |
| 317 | 004020002+I_NPN, 004020004+I_NPN,\r |
| 318 | 004020040+I_NPN, 004020100+I_NPN, 004020200+I_NPN, 004020400+I_NPN,\r |
| 319 | 004600003+I_NPN, 004600005+I_NPN, 004600012+I_NPN, 004600014+I_NPN,\r |
| 320 | 004600060+I_NPN, 004600122+I_NPN, 004600140+I_NPN, 004600160+I_NPN,\r |
| 321 | 024600003+I_NPN,\r |
| 322 | \r |
| 323 | 000000000+I_NPN, 000100000+I_MRF, 000200000+I_IOI, 000600000+I_IOI,\r |
| 324 | 001000000+I_MRF, 001100000+I_MRF, 001200000+I_MRF, 001300000+I_MRF,\r |
| 325 | 001400000+I_MRF, 001600000+I_MRF, 001700000+I_MRF,\r |
| 326 | 002000000+I_OPO, 002300000+I_MRF,\r |
| 327 | 003000000+I_MRF, 003200000+I_MRF, 003300000+I_MRF,\r |
| 328 | 003500000+I_MRF, 003600000+I_MRF, 003700000+I_MRF,\r |
| 329 | 004000000+I_IOI, 004100000+I_MRF, 004300000+I_MRF,\r |
| 330 | 005000000+I_MRF, 005100000+I_MRF, 005200000+I_MRF, 005300000+I_MRF,\r |
| 331 | 005400000+I_MRF, 005500000+I_MRF, 005600000+I_MRF, 005700000+I_MRF,\r |
| 332 | 006000000+I_MRF, 006100000+I_MRF, 006200000+I_MRF, 006300000+I_MRF,\r |
| 333 | 006400000+I_MRF, 006500000+I_MRF,\r |
| 334 | 007000000+I_MRF, 007100000+I_MRF, 007200000+I_MRF, 007300000+I_MRF,\r |
| 335 | 007400000+I_MRF, 007500000+I_MRF, 007600000+I_MRF, 007700000+I_MRF,\r |
| 336 | \r |
| 337 | 000140000+I_MRF,\r |
| 338 | 001040000+I_MRF, 001140000+I_MRF, 001240000+I_MRF, 001340000+I_MRF,\r |
| 339 | 001440000+I_MRF, 001640000+I_MRF, 001740000+I_MRF,\r |
| 340 | 002340000+I_MRF,\r |
| 341 | 003040000+I_MRF, 003240000+I_MRF, 003340000+I_MRF,\r |
| 342 | 003540000+I_MRF, 003640000+I_MRF, 003740000+I_MRF,\r |
| 343 | 004140000+I_MRF, 004340000+I_MRF,\r |
| 344 | 005040000+I_MRF, 005140000+I_MRF, 005240000+I_MRF, 005340000+I_MRF,\r |
| 345 | 005440000+I_MRF, 005540000+I_MRF, 005640000+I_MRF, 005740000+I_MRF,\r |
| 346 | 006040000+I_MRF, 006140000+I_MRF, 006240000+I_MRF, 006340000+I_MRF,\r |
| 347 | 006440000+I_MRF, 006540000+I_MRF,\r |
| 348 | 007040000+I_MRF, 007140000+I_MRF, 007240000+I_MRF, 007340000+I_MRF,\r |
| 349 | 007440000+I_MRF, 007540000+I_MRF, 007640000+I_MRF, 007740000+I_MRF,\r |
| 350 | \r |
| 351 | 006600000+I_SHF, 006620000+I_SHF, 006624000+I_SHF,\r |
| 352 | 006700000+I_SHF, 006710000+I_SHF, 006720000+I_SHF,\r |
| 353 | 006640000+I_MRF, 006740000+I_MRF,\r |
| 354 | \r |
| 355 | 000250000+I_CHC, 000200000+I_CHC, 000212000+I_CHC, 000214000+I_CHC,\r |
| 356 | 004014000+I_CHT, 004011000+I_CHT, 004012000+I_CHT, 004010400+I_CHT,\r |
| 357 | \r |
| 358 | 004600001+I_REG, 004600002+I_REG, 004600004+I_REG,\r |
| 359 | 004600010+I_REG, 004600020+I_REG, 004600040+I_REG,\r |
| 360 | 004600100+I_REG, 004600200+I_REG, 004600400+I_REG,\r |
| 361 | 004601000+I_REG, 024600000+I_REG, 004600000+I_REG,\r |
| 362 | -1\r |
| 363 | };\r |
| 364 | \r |
| 365 | static const char *chname[] = {\r |
| 366 | "W", "Y", "C", "D", "E", "F", "G", "H", NULL\r |
| 367 | };\r |
| 368 | \r |
| 369 | /* Register change decode\r |
| 370 | \r |
| 371 | Inputs:\r |
| 372 | *of = output stream\r |
| 373 | inst = mask bits\r |
| 374 | */\r |
| 375 | \r |
| 376 | void fprint_reg (FILE *of, int32 inst)\r |
| 377 | {\r |
| 378 | int32 i, j, sp;\r |
| 379 | \r |
| 380 | inst = inst & ~(I_M_OP << I_V_OP); /* clear opcode */\r |
| 381 | for (i = sp = 0; opc_val[i] >= 0; i++) { /* loop thru ops */\r |
| 382 | j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */\r |
| 383 | if ((j == I_V_REG) && (opc_val[i] & inst)) { /* reg class? */\r |
| 384 | inst = inst & ~opc_val[i]; /* mask bit set? */\r |
| 385 | fprintf (of, (sp? " %s": "%s"), opcode[i]);\r |
| 386 | sp = 1;\r |
| 387 | }\r |
| 388 | }\r |
| 389 | return;\r |
| 390 | }\r |
| 391 | \r |
| 392 | /* Symbolic decode\r |
| 393 | \r |
| 394 | Inputs:\r |
| 395 | *of = output stream\r |
| 396 | addr = current PC\r |
| 397 | *val = pointer to values\r |
| 398 | *uptr = pointer to unit\r |
| 399 | sw = switches\r |
| 400 | Outputs:\r |
| 401 | return = status code\r |
| 402 | */\r |
| 403 | \r |
| 404 | t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,\r |
| 405 | UNIT *uptr, int32 sw)\r |
| 406 | {\r |
| 407 | int32 i, j, ch;\r |
| 408 | int32 inst, op, tag, va, shf, nonop;\r |
| 409 | \r |
| 410 | inst = val[0]; /* get inst */\r |
| 411 | op = I_GETOP (inst); /* get fields */\r |
| 412 | tag = (inst >> 21) & 06;\r |
| 413 | va = inst & VA_MASK;\r |
| 414 | shf = inst & I_SHFMSK;\r |
| 415 | nonop = inst & 077777;\r |
| 416 | \r |
| 417 | if (sw & SWMASK ('A')) { /* ASCII? */\r |
| 418 | if (inst > 0377) return SCPE_ARG;\r |
| 419 | fprintf (of, FMTASC (inst & 0177));\r |
| 420 | return SCPE_OK;\r |
| 421 | }\r |
| 422 | if (sw & SWMASK ('C')) { /* character? */\r |
| 423 | fprintf (of, "%c", sds_to_ascii[(inst >> 18) & 077]);\r |
| 424 | fprintf (of, "%c", sds_to_ascii[(inst >> 12) & 077]);\r |
| 425 | fprintf (of, "%c", sds_to_ascii[(inst >> 6) & 077]);\r |
| 426 | fprintf (of, "%c", sds_to_ascii[inst & 077]);\r |
| 427 | return SCPE_OK;\r |
| 428 | }\r |
| 429 | if (!(sw & SWMASK ('M'))) return SCPE_ARG;\r |
| 430 | \r |
| 431 | /* Instruction decode */\r |
| 432 | \r |
| 433 | for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */\r |
| 434 | j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */\r |
| 435 | if ((opc_val[i] & DMASK) == (inst & masks[j])) { /* match? */\r |
| 436 | \r |
| 437 | switch (j) { /* case on class */\r |
| 438 | \r |
| 439 | case I_V_NPN: /* no operands */\r |
| 440 | case I_V_OPO: /* opcode only */\r |
| 441 | fprintf (of, "%s", opcode[i]); /* opcode */\r |
| 442 | break;\r |
| 443 | \r |
| 444 | case I_V_SHF: /* shift */\r |
| 445 | fprintf (of, "%s %-o", opcode[i], shf);\r |
| 446 | if (tag) fprintf (of, ",%-o", tag);\r |
| 447 | break;\r |
| 448 | \r |
| 449 | case I_V_PPO: /* pop */\r |
| 450 | fprintf (of, "POP %-o,%-o", op, nonop);\r |
| 451 | if (tag) fprintf (of, ",%-o", tag);\r |
| 452 | break;\r |
| 453 | \r |
| 454 | case I_V_IOI: /* I/O */\r |
| 455 | fprintf (of, "%s %-o", opcode[i], nonop);\r |
| 456 | if (tag) fprintf (of, ",%-o", tag);\r |
| 457 | break;\r |
| 458 | \r |
| 459 | case I_V_MRF: /* mem ref */\r |
| 460 | fprintf (of, "%s %-o", opcode[i], va);\r |
| 461 | if (tag) fprintf (of, ",%-o", tag);\r |
| 462 | break;\r |
| 463 | \r |
| 464 | case I_V_REG: /* reg change */\r |
| 465 | fprint_reg (of, inst); /* decode */\r |
| 466 | break;\r |
| 467 | \r |
| 468 | case I_V_CHC: /* chan cmd */\r |
| 469 | ch = I_GETEOCH (inst); /* get chan */\r |
| 470 | fprintf (of, "%s %s", opcode[i], chname[ch]);\r |
| 471 | break;\r |
| 472 | \r |
| 473 | case I_V_CHT: /* chan test */\r |
| 474 | ch = I_GETSKCH (inst); /* get chan */\r |
| 475 | fprintf (of, "%s %s", opcode[i], chname[ch]);\r |
| 476 | break;\r |
| 477 | } /* end case */\r |
| 478 | \r |
| 479 | return SCPE_OK;\r |
| 480 | } /* end if */\r |
| 481 | } /* end for */\r |
| 482 | return SCPE_ARG;\r |
| 483 | }\r |
| 484 | \r |
| 485 | /* Get (optional) tag\r |
| 486 | \r |
| 487 | Inputs:\r |
| 488 | *cptr = pointer to input string\r |
| 489 | *tag = pointer to tag\r |
| 490 | Outputs:\r |
| 491 | cptr = updated pointer to input string\r |
| 492 | */\r |
| 493 | \r |
| 494 | char *get_tag (char *cptr, t_value *tag)\r |
| 495 | {\r |
| 496 | char *tptr, gbuf[CBUFSIZE];\r |
| 497 | t_stat r;\r |
| 498 | \r |
| 499 | tptr = get_glyph (cptr, gbuf, 0); /* get next field */\r |
| 500 | *tag = get_uint (gbuf, 8, 07, &r) << I_V_TAG; /* parse */\r |
| 501 | if (r == SCPE_OK) return tptr; /* ok? advance */\r |
| 502 | *tag = 0;\r |
| 503 | return cptr; /* no change */\r |
| 504 | }\r |
| 505 | \r |
| 506 | /* Symbolic input\r |
| 507 | \r |
| 508 | Inputs:\r |
| 509 | *cptr = pointer to input string\r |
| 510 | addr = current PC\r |
| 511 | uptr = pointer to unit\r |
| 512 | *val = pointer to output values\r |
| 513 | sw = switches\r |
| 514 | Outputs:\r |
| 515 | status = error status\r |
| 516 | */\r |
| 517 | \r |
| 518 | t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)\r |
| 519 | {\r |
| 520 | int32 i, j, k;\r |
| 521 | t_value d, tag;\r |
| 522 | t_stat r;\r |
| 523 | char gbuf[CBUFSIZE];\r |
| 524 | \r |
| 525 | while (isspace (*cptr)) cptr++;\r |
| 526 | for (i = 1; (i < 4) && (cptr[i] != 0); i++)\r |
| 527 | if (cptr[i] == 0) for (j = i + 1; j <= 4; j++) cptr[j] = 0;\r |
| 528 | if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */\r |
| 529 | if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */\r |
| 530 | val[0] = (t_value) cptr[0] | 0200;\r |
| 531 | return SCPE_OK;\r |
| 532 | }\r |
| 533 | if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* string? */\r |
| 534 | if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */\r |
| 535 | for (i = j = 0, val[0] = 0; i < 4; i++) {\r |
| 536 | if (cptr[i] == 0) j = 1; /* latch str end */\r |
| 537 | k = ascii_to_sds[cptr[i] & 0177]; /* cvt char */\r |
| 538 | if (j || (k < 0)) k = 0; /* bad, end? spc */\r |
| 539 | val[0] = (val[0] << 6) | k;\r |
| 540 | }\r |
| 541 | return SCPE_OK;\r |
| 542 | }\r |
| 543 | \r |
| 544 | cptr = get_glyph (cptr, gbuf, 0); /* get opcode */\r |
| 545 | for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;\r |
| 546 | if (opcode[i] == NULL) return SCPE_ARG;\r |
| 547 | val[0] = opc_val[i] & DMASK; /* get value */\r |
| 548 | j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */\r |
| 549 | \r |
| 550 | switch (j) { /* case on class */\r |
| 551 | \r |
| 552 | case I_V_NPN: case I_V_OPO: /* opcode only */\r |
| 553 | break;\r |
| 554 | \r |
| 555 | case I_V_SHF: /* shift */\r |
| 556 | cptr = get_glyph (cptr, gbuf, ','); /* get next field */\r |
| 557 | d = get_uint (gbuf, 8, I_SHFMSK, &r); /* shift count */\r |
| 558 | if (r != SCPE_OK) return SCPE_ARG;\r |
| 559 | cptr = get_tag (cptr, &tag); /* get opt tag */\r |
| 560 | val[0] = val[0] | d | tag;\r |
| 561 | break;\r |
| 562 | \r |
| 563 | case I_V_PPO: /* pop */\r |
| 564 | cptr = get_glyph (cptr, gbuf, ','); /* get next field */\r |
| 565 | d = get_uint (gbuf, 8, 077, &r); /* opcode */\r |
| 566 | if (r != SCPE_OK) return SCPE_ARG;\r |
| 567 | val[0] = val[0] | d; /* fall thru */\r |
| 568 | \r |
| 569 | case I_V_IOI: /* I/O */\r |
| 570 | cptr = get_glyph (cptr, gbuf, ','); /* get next field */\r |
| 571 | d = get_uint (gbuf, 8, 077777, &r); /* 15b address */\r |
| 572 | if (r != SCPE_OK) return SCPE_ARG;\r |
| 573 | cptr = get_tag (cptr, &tag); /* get opt tag */\r |
| 574 | val[0] = val[0] | d | tag;\r |
| 575 | break;\r |
| 576 | \r |
| 577 | case I_V_MRF: /* mem ref */\r |
| 578 | cptr = get_glyph (cptr, gbuf, ','); /* get next field */\r |
| 579 | d = get_uint (gbuf, 8, VA_MASK, &r); /* virt address */\r |
| 580 | if (r != SCPE_OK) return SCPE_ARG;\r |
| 581 | cptr = get_tag (cptr, &tag); /* get opt tag */\r |
| 582 | val[0] = val[0] | d | tag;\r |
| 583 | break;\r |
| 584 | \r |
| 585 | case I_V_REG: /* register */\r |
| 586 | for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;\r |
| 587 | cptr = get_glyph (cptr, gbuf, 0)) {\r |
| 588 | for (i = 0; (opcode[i] != NULL) &&\r |
| 589 | (strcmp (opcode[i], gbuf) != 0); i++) ;\r |
| 590 | if (opcode[i] != NULL) {\r |
| 591 | k = opc_val[i] & DMASK;;\r |
| 592 | if (I_GETOP (k) != RCH) return SCPE_ARG;\r |
| 593 | val[0] = val[0] | k;\r |
| 594 | }\r |
| 595 | else {\r |
| 596 | d = get_uint (gbuf, 8, 077777, &r);\r |
| 597 | if (r != SCPE_OK) return SCPE_ARG;\r |
| 598 | else val[0] = val[0] | d;\r |
| 599 | }\r |
| 600 | }\r |
| 601 | break;\r |
| 602 | \r |
| 603 | case I_V_CHC: case I_V_CHT: /* channel */\r |
| 604 | cptr = get_glyph (cptr, gbuf, ','); /* get next field */\r |
| 605 | for (i = 0; (chname[i] != NULL) && (strcmp (chname[i], gbuf) != 0);\r |
| 606 | i++);\r |
| 607 | if (chname[i] != NULL) d = i; /* named chan */\r |
| 608 | else {\r |
| 609 | d = get_uint (gbuf, 8, NUM_CHAN - 1, &r);\r |
| 610 | if (r != SCPE_OK) return SCPE_ARG; /* numbered chan */\r |
| 611 | }\r |
| 612 | val[0] = val[0] | ((j == I_V_CHC)? I_SETEOCH (d): I_SETSKCH (d));\r |
| 613 | break;\r |
| 614 | } /* end case */\r |
| 615 | \r |
| 616 | if (*cptr != 0) return SCPE_ARG; /* junk at end? */\r |
| 617 | return SCPE_OK;\r |
| 618 | }\r |