First Commit of my working state
[simh.git] / S3 / s3_sys.c
CommitLineData
196ba1fc
PH
1/* s3_sys.c: IBM System/3 system interface\r
2\r
3 Copyright (c) 2001-2005, Charles E. Owen\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 Charles E. Owen 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 Charles E. Owen.\r
25*/\r
26\r
27#include <ctype.h>\r
28#include "s3_defs.h"\r
29\r
30extern DEVICE cpu_dev;\r
31extern DEVICE pkb_dev;\r
32extern DEVICE cdr_dev;\r
33extern DEVICE cdp_dev;\r
34extern DEVICE stack_dev;\r
35extern DEVICE lpt_dev;\r
36extern DEVICE r1_dev;\r
37extern DEVICE f1_dev;\r
38extern DEVICE r2_dev;\r
39extern DEVICE f2_dev;\r
40extern UNIT cpu_unit;\r
41extern REG cpu_reg[];\r
42extern unsigned char M[];\r
43extern int32 saved_PC, IAR[];\r
44extern char ebcdic_to_ascii[256];\r
45char *parse_addr(char *cptr, char *gbuf, int32 *addr, int32 *addrtype);\r
46\r
47int32 printf_sym (FILE *of, char *strg, int32 addr, uint32 *val,\r
48 UNIT *uptr, int32 sw);\r
49\r
50/* SCP data structures\r
51\r
52 sim_name simulator name string\r
53 sim_PC pointer to saved PC register descriptor\r
54 sim_emax number of words needed for examine\r
55 sim_devices array of pointers to simulated devices\r
56 sim_stop_messages array of pointers to stop messages\r
57 sim_load binary loader\r
58*/\r
59\r
60char sim_name[] = "System/3";\r
61\r
62REG *sim_PC = &cpu_reg[0];\r
63\r
64int32 sim_emax = 6;\r
65\r
66DEVICE *sim_devices[] = {\r
67 &cpu_dev, \r
68 &pkb_dev,\r
69 &cdr_dev,\r
70 &cdp_dev,\r
71 &stack_dev,\r
72 &lpt_dev,\r
73 &r1_dev,\r
74 &f1_dev,\r
75 &r2_dev,\r
76 &f2_dev,\r
77 NULL\r
78};\r
79\r
80const char *sim_stop_messages[] = {\r
81 "Unknown error",\r
82 "Unknown I/O Instruction",\r
83 "HALT instruction",\r
84 "Breakpoint",\r
85 "Invalid Opcode",\r
86 "Invalid Qbyte",\r
87 "Invalid Address",\r
88 "Invalid Device Command",\r
89 "ATTN Card Reader"\r
90};\r
91\r
92/* This is the opcode master defintion table. Each possible opcode mnemonic\r
93 is defined here, with enough information to translate to and from\r
94 symbolic to binary machine code. \r
95 First field is the opcode's mnemonic\r
96 Second field is the hex of the right nybble of the binary opcode\r
97 Third field is the Q code for those with implicit Q codes\r
98 Fourth field is the symbolic format of the operands:\r
99 0 - (Q-byte),(R-byte)\r
100 1 - (Q-byte),(Address)\r
101 2 - (Address),(Address),(Qbyte)\r
102 3 - (Address),(Qbyte)\r
103 4 - (device),(modifier),(function) -- these 3 make up qbyte\r
104 5 - (device),(modifier),(function),(control)\r
105 6 - (device),(modifier),(function),(Address)\r
106 7 - (displacement) -- Q byte is implicit in opcode\r
107 8 - (address) -- Qbyte is implicit in opcode\r
108 9 - (Address),(Address) -- Qbyte is implicit in opcode\r
109 Fifth Field is the group number:\r
110 0 - Command Group (left op nybble is F)\r
111 1 - One Address Operations A (Left Nybble C, D, or E)\r
112 2 - Two Address Operations (Left Nybble 0,1,2,4,5,6,8,9, or A)\r
113 3 - One Address Operations B (left Nybble 3, 7, or B)\r
114\r
115 There is duplication in this table -- IBM defines different opcodes\r
116 that resolve to the same binary machine instruction -- e.g. JE and\r
117 JZ. On input this is no problem, on output, define the one you\r
118 want to appear first, the second will never appear on output.\r
119*/ \r
120\r
121int32 nopcode = 75;\r
122struct opdef opcode[75] = {\r
123 "HPL", 0x00,0,0,0, /* Halt Program Level */\r
124 "A", 0x06,0,1,3, /* Add to Register: A R,AADD */\r
125 "ST", 0x04,0,1,3, /* Store Register */\r
126 "L", 0x05,0,1,3, /* Load Register */\r
127 "LA", 0x02,0,1,1, /* Load Address */\r
128 "ZAZ", 0x04,0,2,2, /* Zero and Add Zoned */\r
129 "AZ", 0x06,0,2,2, /* Add Zoned Decimal */\r
130 "SZ", 0x07,0,2,2, /* Subtract Zoned Decimal */\r
131 "ALC", 0x0E,0,2,2, /* Add Logical: ALC BADD,AADD,LEN */\r
132 "SLC", 0x0F,0,2,2, /* Sub Logical: SLC BADD,AADD,LEN */\r
133 "MVC", 0x0C,0,2,2, /* Move Chars MVX BADD,AADD,LEN */\r
134 "ED", 0x0A,0,2,2, /* Edit: ED BADD,AADD,LEN */\r
135 "ITC", 0x0B,0,2,2, /* Insert Chars: ITC BADD,AADD,LEN */\r
136 "CLC", 0x0D,0,2,2, /* Compare Logical: CLC BADD,AADD,LEN */\r
137 "MVI", 0x0C,0,3,3, /* Move Immediate */\r
138 "SBN", 0x0A,0,3,3, /* Set Bits On */\r
139 "SBF", 0x0B,0,3,3, /* Set Bits Off */\r
140 "CLI", 0x0D,0,3,3, /* Compare Immediate */\r
141 "TBN", 0x08,0,3,3, /* Test Bits On */\r
142 "TBF", 0x09,0,3,3, /* Test Bits Off */\r
143 "APL", 0x01,0,4,0, /* Advance Program Level */\r
144 "SIO", 0x03,0,5,0, /* Start I/O */\r
145 "SNS", 0x00,0,6,3, /* Sense I/O */\r
146 "LIO", 0x01,0,6,3, /* Load I/O */\r
147 "TIO", 0x01,0,6,1, /* Test I/O */\r
148 "J", 0x02,0,7,0, /* Jump Unconditional */\r
149 "J", 0x02,0x87,7,0, /* Alternate J */\r
150 "JH", 0x02,132,7,0, /* Jump if High */\r
151 "JL", 0x02,130,7,0, /* Jump if Low */\r
152 "JE", 0x02,129,7,0, /* Jump if Equal */\r
153 "JNH", 0x02,4,7,0, /* Jump if Not High */\r
154 "JNL", 0x02,2,7,0, /* Jump if Not Low */\r
155 "JNE", 0x02,1,7,0, /* Jump if Not Equal */\r
156 "JOZ", 0x02,136,7,0, /* Jump if Overflow Zoned */\r
157 "JOL", 0x02,160,7,0, /* Jump if Overflow Logical */\r
158 "JNOZ", 0x02,8,7,0, /* Jump if No Overflow Zoned */\r
159 "JNOL", 0x02,32,7,0, /* Jump if No Overflow Logical */\r
160 "JT", 0x02,16,7,0, /* Jump if True */\r
161 "JF", 0x02,144,7,0, /* Jump if False */\r
162 "JP", 0x02,132,7,0, /* Jump if Plus */\r
163 "JM", 0x02,130,7,0, /* Jump if Minus */\r
164 "JZ", 0x02,129,7,0, /* Jump if Zero */\r
165 "JNP", 0x02,4,7,0, /* Jump if Not Plus */\r
166 "JNM", 0x02,2,7,0, /* Jump if Not Minus */\r
167 "JNZ", 0x02,1,7,0, /* Jump if Not Zero */\r
168 "NOPJ", 0x02,0x80,7,0, /* Never Jump - NOP */\r
169 "B", 0x00,0x00,8,1, /* Branch Unconditional */\r
170 "B", 0x00,0x87,8,1, /* Alternate B */\r
171 "BH", 0x00,0x84,8,1, /* Branch if High */\r
172 "BL", 0x00,0x82,8,1, /* Branch if Low */\r
173 "BE", 0x00,0x81,8,1, /* Branch if Equal */\r
174 "BNH", 0x00,0x04,8,1, /* Branch if Not High */\r
175 "BNL", 0x00,0x02,8,1, /* Branch if Not Low */\r
176 "BNE", 0x00,0x01,8,1, /* Branch if Not Equal */\r
177 "BOZ", 0x00,0x88,8,1, /* Branch if Overflow Zoned */\r
178 "BOL", 0x00,0xA0,8,1, /* Branch if Overflow Logical */\r
179 "BNOZ", 0x00,0x08,8,1, /* Branch if No Overflow Zoned */\r
180 "BNOL", 0x00,0x20,8,1, /* Branch if No Overflow Logical */\r
181 "BT", 0x00,0x10,8,1, /* Branch if True */\r
182 "BF", 0x00,0x90,8,1, /* Branch if False */\r
183 "BP", 0x00,0x84,8,1, /* Branch if Plus */\r
184 "BM", 0x00,0x82,8,1, /* Branch if Minus */\r
185 "BZ", 0x00,0x81,8,1, /* Branch if Zero */\r
186 "BNP", 0x00,0x04,8,1, /* Branch if Not Plus */\r
187 "BNM", 0x00,0x02,8,1, /* Branch if Not Minus */\r
188 "BNZ", 0x00,0x01,8,1, /* Branch if Not Zero */\r
189 "NOPB", 0x00,0x80,8,1, /* Never Branch - NOP */\r
190 "MZZ", 0x08,0,9,2, /* Move Zone to Zone */\r
191 "MNZ", 0x08,1,9,2, /* Move Numeric to Zone */\r
192 "MZN", 0x08,2,9,2, /* Move Zone to Numeric */\r
193 "MNN", 0x08,3,9,2, /* Move Numeric to Numeric */\r
194 "MVX", 0x08,0,2,2, /* Move Hex: MVX BADD,AADD,CODE */\r
195 "JC", 0x02,0,3,0, /* Jump on Specified Condition bits */\r
196 "BC", 0x00,0,3,1, /* Branch on Specified Condition */\r
197 "***", 0x00,0,0,0\r
198};\r
199\r
200int32 regcode[15] = { 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,\r
201 0x80, 0xC0, 0xA0, 0x90, 0x88, 0x84, 0x82, 0x81\r
202};\r
203 \r
204char regname[15][8] = { "(P2IAR)",\r
205 "(P1IAR)",\r
206 "(IAR)",\r
207 "(ARR)",\r
208 "(PSR)",\r
209 "(XR2)",\r
210 "(XR1)",\r
211 "(IAR0)",\r
212 "(IAR1)",\r
213 "(IAR2)",\r
214 "(IAR3)",\r
215 "(IAR4)",\r
216 "(IAR5)",\r
217 "(IAR6)",\r
218 "(IAR7)"\r
219}; \r
220\r
221/* This is the binary loader. The input file is considered to be\r
222 a string of literal bytes with no special format. The\r
223 load starts at the current value of the P1IAR.\r
224*/\r
225\r
226int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag)\r
227{\r
228int32 i, addr = 0, cnt = 0;\r
229\r
230if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;\r
231addr = IAR[8];\r
232while ((i = getc (fileref)) != EOF) {\r
233 M[addr] = i & 0xff;\r
234 addr++;\r
235 cnt++;\r
236} /* end while */\r
237printf ("%d Bytes loaded.\n", cnt);\r
238return (SCPE_OK);\r
239}\r
240\r
241/* Symbolic output\r
242\r
243 Inputs:\r
244 *of = output stream\r
245 addr = current PC\r
246 *val = pointer to values\r
247 *uptr = pointer to unit\r
248 sw = switches\r
249 Outputs:\r
250 status = error code\r
251*/\r
252\r
253int32 fprint_sym (FILE *of, int32 addr, uint32 *val,\r
254 UNIT *uptr, int32 sw)\r
255{\r
256 int32 r;\r
257 char strg[256];\r
258 \r
259 strcpy(strg, "");\r
260 r = printf_sym(of, strg, addr, val, uptr, sw);\r
261 if (sw & SWMASK ('A'))\r
262 strcpy(strg, "");\r
263 else\r
264 fprintf(of, "%s", strg);\r
265 return (r);\r
266}\r
267\r
268int32 printf_sym (FILE *of, char *strg, int32 addr, uint32 *val,\r
269 UNIT *uptr, int32 sw)\r
270{\r
271int32 cflag, c1, c2, group, len1, len2, inst, aaddr, baddr;\r
272int32 oplen, groupno, i, j, vpos, qbyte, da, m, n;\r
273char bld[128], bldaddr[32], boperand[32], aoperand[32];\r
274int32 blk[16], blt[16];\r
275int32 blkadd;\r
276\r
277cflag = (uptr == NULL) || (uptr == &cpu_unit);\r
278c1 = val[0] & 0xff;\r
279if (sw & SWMASK ('A')) {\r
280 for (i = 0; i < 16; i++) {\r
281 blkadd = addr + (i*16);\r
282 for (j = 0; j < 16; j++) {\r
283 blk[j] = M[blkadd+j] & 0xff;\r
284 c2 = ebcdic_to_ascii[blk[j]];\r
285 if (c2 < 040 || c2 > 0177 || blk[j] == 07) {\r
286 blt[j] = '.';\r
287 } else { \r
288 blt[j] = c2;\r
289 }\r
290 }\r
291 if (i == 0) {\r
292 fprintf(of, "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X [%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c]\n ",\r
293 blk[0], blk[1], blk[2], blk[3], blk[4], blk[5], blk[6], blk[7],\r
294 blk[8], blk[9], blk[10], blk[11], blk[12], blk[13], blk[14], blk[15],\r
295 blt[0], blt[1], blt[2], blt[3], blt[4], blt[5], blt[6], blt[7],\r
296 blt[8], blt[9], blt[10], blt[11], blt[12], blt[13], blt[14], blt[15]);\r
297 } else {\r
298 fprintf(of, "%X\t%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X [%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c]\n ",\r
299 blkadd, blk[0], blk[1], blk[2], blk[3], blk[4], blk[5], blk[6], blk[7],\r
300 blk[8], blk[9], blk[10], blk[11], blk[12], blk[13], blk[14], blk[15],\r
301 blt[0], blt[1], blt[2], blt[3], blt[4], blt[5], blt[6], blt[7],\r
302 blt[8], blt[9], blt[10], blt[11], blt[12], blt[13], blt[14], blt[15]);\r
303 } \r
304 } \r
305 return SCPE_OK; }\r
306if (sw & SWMASK ('C')) {\r
307 c2 = ebcdic_to_ascii[c1];\r
308 if (c2 < 040 || c2 > 0177) {\r
309 sprintf(strg, "<%02X>", c1 & 0xff);\r
310 } else { \r
311 sprintf (strg, "%c", c2 & 0xff);\r
312 }\r
313 return SCPE_OK; }\r
314if (!(sw & SWMASK ('M'))) return SCPE_ARG;\r
315\r
316inst = val[0] & 0x0f;\r
317len1 = (val[0] >> 6) & 3;\r
318len2 = (val[0] >> 4) & 3;\r
319group = (val[0] >> 4) & 0x0f;\r
320qbyte = val[1];\r
321\r
322/* Get total length of instruction */\r
323\r
324if (group == 0x0f) {\r
325 oplen = 3;\r
326} else {\r
327 oplen = 2; \r
328 if (len1 == 0) oplen += 2;\r
329 if (len1 == 1 || len1 == 2) oplen++;\r
330 if (len2 == 0) oplen += 2;\r
331 if (len2 == 1 || len2 == 2) oplen++;\r
332}\r
333\r
334/* Find which group it belongs to */\r
335\r
336switch (group) {\r
337 case 0x0f: \r
338 groupno = 0;\r
339 break;\r
340 case 0x0c:\r
341 case 0x0d:\r
342 case 0x0e:\r
343 groupno = 1;\r
344 break;\r
345 case 0x03:\r
346 case 0x07:\r
347 case 0x0b:\r
348 groupno = 3;\r
349 break;\r
350 default:\r
351 groupno = 2;\r
352 break;\r
353} \r
354\r
355/* find the table entry */\r
356\r
357for (i = 0; i < nopcode; i++) {\r
358 if (opcode[i].form < 7) { /* Explicit Q */\r
359 if (opcode[i].group == groupno &&\r
360 opcode[i].opmask == inst) break;\r
361 } else { /* Implicit Q */\r
362 if (opcode[i].group == groupno &&\r
363 opcode[i].opmask == inst &&\r
364 opcode[i].q == qbyte) break;\r
365 } \r
366}\r
367\r
368/* print the opcode */\r
369\r
370if (i >= nopcode) {\r
371 sprintf(strg, "%02X", val[0]);\r
372 oplen = 1;\r
373} else {\r
374 sprintf(bld, "%s ", opcode[i].op);\r
375\r
376 /* Extract the addresses into aaddr and baddr */\r
377\r
378 strcpy(aoperand, "ERROR");\r
379 strcpy(boperand, "ERROR");\r
380 vpos = 2;\r
381 aaddr = baddr = 0;\r
382 switch (len1) {\r
383 case 0:\r
384 baddr = ((val[vpos] << 8) & 0xff00) | (val[vpos + 1] & 0x00ff);\r
385 sprintf(boperand, "%04X", baddr);\r
386 vpos = 4;\r
387 break;\r
388 case 1:\r
389 baddr = val[vpos] & 255;\r
390 sprintf(boperand, "(%02X,XR1)", baddr);\r
391 vpos = 3;\r
392 break;\r
393 case 2:\r
394 baddr = val[vpos] & 255;\r
395 sprintf(boperand, "(%02X,XR2)", baddr);\r
396 vpos = 3;\r
397 break;\r
398 default:\r
399 baddr = 0;\r
400 break;\r
401 } \r
402 switch (len2) {\r
403 case 0:\r
404 aaddr = ((val[vpos] << 8) & 0xff00) | (val[vpos + 1] & 0x00ff);\r
405 if (group == 0x0C || group == 0x0D || group == 0x0E)\r
406 sprintf(boperand, "%04X", aaddr);\r
407 else\r
408 sprintf(aoperand, "%04X", aaddr);\r
409 break; \r
410 case 1:\r
411 aaddr = val[vpos] & 255;\r
412 if (group == 0x0C || group == 0x0D || group == 0x0E)\r
413 sprintf(boperand, "(%02X,XR1)", aaddr);\r
414 else\r
415 sprintf(aoperand, "(%02X,XR1)", aaddr);\r
416 break;\r
417 case 2:\r
418 aaddr = val[vpos] & 255;\r
419 if (group == 0x0C || group == 0x0D || group == 0x0E)\r
420 sprintf(boperand, "(%02X,XR2)", aaddr);\r
421 else\r
422 sprintf(aoperand, "(%02X,XR2)", aaddr);\r
423 break;\r
424 default:\r
425 aaddr = 0;\r
426 break;\r
427 } \r
428\r
429 /* Display the operands in the correct format */\r
430\r
431 da = (qbyte >> 4) & 0x0f; \r
432 m = (qbyte >> 3) & 0x01;\r
433 n = (qbyte) & 0x07;\r
434\r
435 switch (opcode[i].form) {\r
436 case 0:\r
437 sprintf(bldaddr, "%02X,%02X", qbyte, val[2]);\r
438 break;\r
439 case 1:\r
440 if (inst == 2 || inst == 4 || inst == 5 || inst == 6) {\r
441 for (i = 0; i < 16; i++) {\r
442 if (regcode[i] == qbyte)\r
443 break;\r
444 }\r
445 if (i < 16) {\r
446 sprintf(bldaddr, "%s,%s", regname[i], boperand);\r
447 } else {\r
448 sprintf(bldaddr, "%02X,%s", qbyte, boperand);\r
449 } \r
450 } else {\r
451 sprintf(bldaddr, "%02X,%s", qbyte, boperand);\r
452 }\r
453 break;\r
454 case 2:\r
455 if (inst > 9 || inst == 4 || inst == 6 || inst == 7)\r
456 qbyte++; /* special +1 for length display */\r
457 sprintf(bldaddr, "%s,%s,%d", boperand, aoperand, qbyte);\r
458 break;\r
459 case 3:\r
460 if (strcmp(opcode[i].op, "JC") == 0) {\r
461 sprintf(bldaddr, "%04X,%02X", addr+oplen+val[2], qbyte);\r
462 } else { \r
463 sprintf(bldaddr, "%s,%02X", boperand, qbyte);\r
464 } \r
465 break;\r
466 case 4: \r
467 sprintf(bldaddr, "%d,%d,%d", da, m, n);\r
468 break;\r
469 case 5:\r
470 sprintf(bldaddr, "%d,%d,%d,%02X", da, m, n, val[2]);\r
471 break;\r
472 case 6:\r
473 sprintf(bldaddr, "%d,%d,%d,%s", da, m, n, boperand);\r
474 break;\r
475 case 7:\r
476 sprintf(bldaddr, "%04X", addr+oplen+val[2]);\r
477 break;\r
478 case 8:\r
479 sprintf(bldaddr, "%s", boperand); \r
480 break;\r
481 default:\r
482 sprintf(bldaddr, "%s,%s", boperand, aoperand);\r
483 break;\r
484 } \r
485 sprintf(strg, "%s%s", bld, bldaddr);\r
486} \r
487\r
488return -(oplen - 1);\r
489}\r
490\r
491/* Symbolic input\r
492\r
493 Inputs:\r
494 *cptr = pointer to input string\r
495 addr = current PC\r
496 *uptr = pointer to unit\r
497 *val = pointer to output values\r
498 sw = switches\r
499 Outputs:\r
500 status = error status\r
501*/\r
502\r
503int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw)\r
504{\r
505int32 cflag, i = 0, j, r, oplen, addtyp, saveaddr, vptr;\r
506char gbuf[CBUFSIZE];\r
507\r
508cflag = (uptr == NULL) || (uptr == &cpu_unit);\r
509while (isspace (*cptr)) cptr++; /* absorb spaces */\r
510if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */\r
511 if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */\r
512 val[0] = (unsigned int) cptr[0];\r
513 return SCPE_OK;\r
514}\r
515if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */\r
516 if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */\r
517 val[0] = ((unsigned int) cptr[0] << 8) + (unsigned int) cptr[1];\r
518 return SCPE_OK;\r
519}\r
520\r
521/* An instruction: get opcode (all characters until null, comma, left paren,\r
522 or numeric (including spaces).\r
523*/\r
524\r
525while (1) {\r
526 if (*cptr == ',' || *cptr == '\0' || *cptr == '(' ||\r
527 isdigit(*cptr))\r
528 break;\r
529 gbuf[i] = toupper(*cptr);\r
530 cptr++;\r
531 i++;\r
532}\r
533\r
534/* kill trailing spaces if any */\r
535gbuf[i] = '\0';\r
536for (j = i - 1; gbuf[j] == ' '; j--) {\r
537 gbuf[j] = '\0';\r
538}\r
539\r
540/* find opcode in table */\r
541for (j = 0; j < nopcode; j++) {\r
542 if (strcmp(gbuf, opcode[j].op) == 0)\r
543 break;\r
544}\r
545if (j >= nopcode) /* not found */\r
546 return SCPE_ARG;\r
547\r
548oplen = 2; /* start with op & q */\r
549\r
550val[0] = opcode[j].opmask; /* store opcode right nybble */\r
551\r
552switch (opcode[j].form) { /* Get operands based on operand format */\r
553 case 0: /* Single Byte Operand */\r
554 if (*cptr == ',') cptr++;\r
555 cptr = get_glyph(cptr, gbuf, ','); /* Get Q Byte */\r
556 sscanf(gbuf, "%x", &r);\r
557 val[1] = r;\r
558 if (*cptr == ',') cptr++;\r
559 cptr = get_glyph(cptr, gbuf, 0); /* Get R Byte */\r
560 sscanf(gbuf, "%x", &r);\r
561 val[2] = r;\r
562 oplen = 3;\r
563 val[0] = 0xf0 | opcode[j].opmask;\r
564 break;\r
565 case 1:\r
566 if (*cptr == ',') cptr++;\r
567 cptr = get_glyph(cptr, gbuf, ',');\r
568 if (opcode[j].opmask == 2 ||\r
569 opcode[j].opmask == 4 ||\r
570 opcode[j].opmask == 5 ||\r
571 opcode[j].opmask == 6) {\r
572 if (isdigit(gbuf[0])) {\r
573 sscanf(gbuf, "%x", &r);\r
574 } else {\r
575 for (i = 0; i < 16; i++) {\r
576 if (strcmp(gbuf, regname[i]) == 0)\r
577 break;\r
578 }\r
579 if (i < 16) {\r
580 r = regcode[i];\r
581 } else {\r
582 return SCPE_ARG;\r
583 } \r
584 } \r
585 } else {\r
586 sscanf(gbuf, "%x", &r);\r
587 } \r
588 if (r > 255) return SCPE_ARG;\r
589 val[1] = r;\r
590 if (*cptr == ',') cptr++;\r
591 cptr = parse_addr(cptr, gbuf, &addr, &addtyp);\r
592 switch(addtyp) {\r
593 case 0: \r
594 val[2] = (addr >> 8) & 0x00ff;\r
595 val[3] = addr & 0xff;\r
596 oplen = 4;\r
597 if (opcode[j].group == 1)\r
598 val[0] = 0xC0 | opcode[j].opmask;\r
599 else\r
600 val[0] = 0x30 | opcode[j].opmask;\r
601 break;\r
602 case 1: \r
603 val[2] = addr & 0xff;\r
604 oplen = 3;\r
605 if (opcode[j].group == 1)\r
606 val[0] = 0xD0 | opcode[j].opmask;\r
607 else \r
608 val[0] = 0x70 | opcode[j].opmask;\r
609 break;\r
610 case 2:\r
611 val[2] = addr & 0xff;\r
612 oplen = 3;\r
613 if (opcode[j].group == 1)\r
614 val[0] = 0xE0 | opcode[j].opmask;\r
615 else\r
616 val[0] = 0xB0 | opcode[j].opmask;\r
617 break;\r
618 default:\r
619 return SCPE_ARG;\r
620 break;\r
621 } \r
622 break;\r
623 case 2:\r
624 oplen = 2;\r
625 cptr = parse_addr(cptr, gbuf, &addr, &addtyp);\r
626 switch(addtyp) {\r
627 case 0: \r
628 val[2] = (addr >> 8) & 0xff;\r
629 val[3] = addr & 0xff;\r
630 oplen += 2;\r
631 vptr = 4;\r
632 val[0] = 0x00 | opcode[j].opmask;\r
633 break;\r
634 case 1: \r
635 val[2] = addr & 0xff;\r
636 oplen += 1;\r
637 vptr = 3;\r
638 val[0] = 0x40 | opcode[j].opmask;\r
639 break;\r
640 case 2:\r
641 val[2] = addr & 0xff;\r
642 oplen += 1;\r
643 vptr = 3;\r
644 val[0] = 0x80 | opcode[j].opmask;\r
645 break;\r
646 default:\r
647 return SCPE_ARG;\r
648 break;\r
649 }\r
650 if (*cptr == ',') cptr++;\r
651 cptr = parse_addr(cptr, gbuf, &addr, &addtyp);\r
652 switch(addtyp) {\r
653 case 0: \r
654 val[vptr] = (addr >> 8) & 0xff;\r
655 val[vptr+1] = addr & 0xff;\r
656 oplen += 2;\r
657 break;\r
658 case 1: \r
659 val[vptr] = addr & 0xff;\r
660 oplen += 1;\r
661 val[0] = 0x10 | val[0];\r
662 break;\r
663 case 2:\r
664 val[vptr] = addr & 0xff;\r
665 oplen += 1;\r
666 val[0] = 0x20 | val[0];\r
667 break;\r
668 default:\r
669 return SCPE_ARG;\r
670 break;\r
671 } \r
672 if (*cptr == ',') cptr++;\r
673 cptr = get_glyph(cptr, gbuf, 0);\r
674 sscanf(gbuf, "%d", &r);\r
675 if (opcode[j].opmask > 9 ||\r
676 opcode[j].opmask == 4 ||\r
677 opcode[j].opmask == 6 ||\r
678 opcode[j].opmask == 7) r--; /* special: length -1 */\r
679 val[1] = r;\r
680 if (*cptr == ',') cptr++;\r
681 break;\r
682 case 3:\r
683 saveaddr = addr;\r
684 if (*cptr == ',') cptr++;\r
685 cptr = parse_addr(cptr, gbuf, &addr, &addtyp);\r
686 switch(addtyp) {\r
687 case 0:\r
688 if (opcode[j].group == 0) { /* Group 0 form 3 is JC with explicit Q */\r
689 if (*cptr == ',') cptr++;\r
690 cptr = get_glyph(cptr, gbuf, 0);\r
691 sscanf(gbuf, "%x", &r);\r
692 if ((addr - (saveaddr+3)) > 255 || (addr - (saveaddr+3)) < 1)\r
693 return SCPE_ARG;\r
694 val[2] = addr - (saveaddr+3);\r
695 val[1] = r;\r
696 val[0] = 0xf0 | opcode[j].opmask;\r
697 oplen = 3;\r
698 \r
699 } else {\r
700 val[2] = (addr >> 8) & 0x00ff;\r
701 val[3] = addr & 0xff;\r
702 oplen = 4;\r
703 if (opcode[j].group == 1)\r
704 val[0] = 0xC0 | opcode[j].opmask;\r
705 else\r
706 val[0] = 0x30 | opcode[j].opmask;\r
707 } \r
708 break;\r
709 case 1: \r
710 val[2] = addr & 0xff;\r
711 oplen = 3;\r
712 if (opcode[j].group == 1)\r
713 val[0] = 0xD0 | opcode[j].opmask;\r
714 else\r
715 val[0] = 0x70 | opcode[j].opmask;\r
716 break;\r
717 case 2:\r
718 val[2] = addr & 0xff;\r
719 oplen = 3;\r
720 if (opcode[j].group == 1)\r
721 val[0] = 0xE0 | opcode[j].opmask;\r
722 else\r
723 val[0] = 0xB0 | opcode[j].opmask;\r
724 break;\r
725 default:\r
726 return SCPE_ARG;\r
727 break;\r
728 } \r
729 if (*cptr == ',') cptr++;\r
730 cptr = get_glyph(cptr, gbuf, 0);\r
731 sscanf(gbuf, "%x", &r);\r
732 if (r > 255) return SCPE_ARG;\r
733 val[1] = r;\r
734 break;\r
735 case 4:\r
736 if (*cptr == ',') cptr++;\r
737 cptr = get_glyph(cptr, gbuf, ',');\r
738 sscanf(gbuf, "%d", &r);\r
739 if (r > 15) return SCPE_ARG;\r
740 val[1] = (r << 4) & 0xf0;\r
741 val[0] = 0xf0 | opcode[j].opmask;\r
742 if (*cptr == ',') cptr++;\r
743 cptr = get_glyph(cptr, gbuf, ',');\r
744 sscanf(gbuf, "%d", &r);\r
745 if (r > 1) return SCPE_ARG;\r
746 val[1] |= (r << 3) & 0x08;\r
747 if (*cptr == ',') cptr++;\r
748 cptr = get_glyph(cptr, gbuf, 0);\r
749 sscanf(gbuf, "%d", &r);\r
750 if (r > 7) return SCPE_ARG;\r
751 val[1] |= r & 0x07;\r
752 val[2] = 0;\r
753 oplen = 3;\r
754 break;\r
755 case 5:\r
756 if (*cptr == ',') cptr++;\r
757 cptr = get_glyph(cptr, gbuf, ',');\r
758 sscanf(gbuf, "%d", &r);\r
759 if (r > 15) return SCPE_ARG;\r
760 val[1] = (r << 4) & 0xf0;\r
761 val[0] = 0xf0 | opcode[j].opmask;\r
762 if (*cptr == ',') cptr++;\r
763 cptr = get_glyph(cptr, gbuf, ',');\r
764 sscanf(gbuf, "%d", &r);\r
765 if (r > 1) return SCPE_ARG;\r
766 val[1] |= (r << 3) & 0x08;\r
767 if (*cptr == ',') cptr++;\r
768 cptr = get_glyph(cptr, gbuf, ',');\r
769 sscanf(gbuf, "%d", &r);\r
770 if (r > 7) return SCPE_ARG;\r
771 val[1] |= r & 0x07;\r
772 if (*cptr == ',') cptr++;\r
773 cptr = get_glyph(cptr, gbuf, 0);\r
774 sscanf(gbuf, "%x", &r);\r
775 if (r > 255) return SCPE_ARG;\r
776 val[2] = r;\r
777 oplen = 3;\r
778 break;\r
779 case 6:\r
780 if (*cptr == ',') cptr++;\r
781 cptr = get_glyph(cptr, gbuf, ',');\r
782 sscanf(gbuf, "%d", &r);\r
783 if (r > 15) return SCPE_ARG;\r
784 val[1] = (r << 4) & 0xf0;\r
785 if (*cptr == ',') cptr++;\r
786 cptr = get_glyph(cptr, gbuf, ',');\r
787 sscanf(gbuf, "%d", &r);\r
788 if (r > 1) return SCPE_ARG;\r
789 val[1] |= (r << 3) & 0x08;\r
790 if (*cptr == ',') cptr++;\r
791 cptr = get_glyph(cptr, gbuf, ',');\r
792 sscanf(gbuf, "%d", &r);\r
793 if (r > 7) return SCPE_ARG;\r
794 val[1] |= r & 0x07;\r
795 if (*cptr == ',') cptr++;\r
796 cptr = parse_addr(cptr, gbuf, &addr, &addtyp);\r
797 switch(addtyp) {\r
798 case 0: \r
799 val[2] = (addr >> 8) & 0x00ff;\r
800 val[3] = addr & 0xff;\r
801 oplen = 4;\r
802 if (opcode[j].group == 1)\r
803 val[0] = 0xC0 | opcode[j].opmask;\r
804 else\r
805 val[0] = 0x30 | opcode[j].opmask;\r
806 break;\r
807 case 1: \r
808 val[2] = addr & 0xff;\r
809 oplen = 3;\r
810 if (opcode[j].group == 1)\r
811 val[0] = 0xD0 | opcode[j].opmask;\r
812 else\r
813 val[0] = 0x70 | opcode[j].opmask;\r
814 break;\r
815 case 2:\r
816 val[2] = addr & 0xff;\r
817 oplen = 3;\r
818 if (opcode[j].group == 1)\r
819 val[0] = 0xE0 | opcode[j].opmask;\r
820 else\r
821 val[0] = 0xB0 | opcode[j].opmask;\r
822 break;\r
823 default:\r
824 return SCPE_ARG;\r
825 break;\r
826 } \r
827 break;\r
828 case 7:\r
829 if (*cptr == ',') cptr++;\r
830 cptr = get_glyph(cptr, gbuf, 0);\r
831 sscanf(gbuf, "%x", &r);\r
832 if ((r - (addr+3)) > 255 || (r - (addr+3)) < 1) return SCPE_ARG;\r
833 val[2] = r - (addr+3);\r
834 val[1] = opcode[j].q;\r
835 val[0] = 0xf0 | opcode[j].opmask;\r
836 oplen = 3;\r
837 break;\r
838 \r
839 case 8:\r
840 if (*cptr == ',') cptr++;\r
841 cptr = parse_addr(cptr, gbuf, &addr, &addtyp);\r
842 switch(addtyp) {\r
843 case 0: \r
844 val[2] = (addr >> 8) & 0x00ff;\r
845 val[3] = addr & 0xff;\r
846 oplen = 4;\r
847 val[0] = 0xC0 | opcode[j].opmask;\r
848 break;\r
849 case 1: \r
850 val[2] = addr & 0xff;\r
851 oplen = 3;\r
852 val[0] = 0xD0 | opcode[j].opmask;\r
853 break;\r
854 case 2:\r
855 val[2] = addr & 0xff;\r
856 oplen = 3;\r
857 val[0] = 0xE0 | opcode[j].opmask;\r
858 break;\r
859 default:\r
860 return SCPE_ARG;\r
861 break;\r
862 } \r
863 val[1] = opcode[j].q;\r
864 break;\r
865 case 9:\r
866 oplen = 2;\r
867 val[0] = 0;\r
868 cptr = parse_addr(cptr, gbuf, &addr, &addtyp);\r
869 switch(addtyp) {\r
870 case 0: \r
871 val[2] = (addr >> 8) & 0xff;\r
872 val[3] = addr & 0xff;\r
873 oplen += 2;\r
874 vptr = 4;\r
875 val[0] = 0x00 | opcode[j].opmask;\r
876 break;\r
877 case 1: \r
878 val[2] = addr & 0xff;\r
879 oplen += 1;\r
880 vptr = 3;\r
881 val[0] = 0x40 | opcode[j].opmask;\r
882 break;\r
883 case 2:\r
884 val[2] = addr & 0xff;\r
885 oplen += 1;\r
886 vptr = 3;\r
887 val[0] = 0x80 | opcode[j].opmask;\r
888 break;\r
889 default:\r
890 return SCPE_ARG;\r
891 break;\r
892 }\r
893 if (*cptr == ',') cptr++;\r
894 cptr = parse_addr(cptr, gbuf, &addr, &addtyp);\r
895 switch(addtyp) {\r
896 case 0: \r
897 val[vptr] = (addr >> 8) & 0xff;\r
898 val[vptr+1] = addr & 0xff;\r
899 oplen += 2;\r
900 break;\r
901 case 1: \r
902 val[vptr] = addr & 0xff;\r
903 oplen += 1;\r
904 val[0] = 0x10 | val[0];\r
905 break;\r
906 case 2:\r
907 val[vptr] = addr & 0xff;\r
908 oplen += 1;\r
909 val[0] = 0x20 | val[0];\r
910 break;\r
911 default:\r
912 return SCPE_ARG;\r
913 break;\r
914 } \r
915 val[1] = opcode[j].q;\r
916 break;\r
917 default:\r
918 break;\r
919}\r
920\r
921\r
922return (-(oplen-1));\r
923}\r
924\r
925char *parse_addr(char *cptr, char *gbuf, int32 *addr, int32 *addrtype)\r
926{\r
927int32 nybble = 0;\r
928char temp[32];\r
929\r
930cptr = get_glyph(cptr, gbuf, ',');\r
931if (gbuf[0] == '(') { /* XR relative */\r
932 strcpy(temp, gbuf+1);\r
933 sscanf(temp, "%x", addr);\r
934 if (*cptr == ',') cptr++;\r
935 cptr = get_glyph(cptr, gbuf, ',');\r
936 nybble = -1;\r
937 if (strcmp(gbuf, "XR1)") == 0)\r
938 nybble = 1;\r
939 if (strcmp(gbuf, "XR2)") == 0)\r
940 nybble = 2;\r
941} else { /* Direct */\r
942 sscanf(gbuf, "%x", addr);\r
943 nybble = 0; \r
944}\r
945*addrtype = nybble;\r
946return cptr;\r
947}\r
948\r