| /* | |
| Copyright (c) 2015-2016, John Forecast | |
| Permission is hereby granted, free of charge, to any person obtaining a | |
| copy of this software and associated documentation files (the "Software"), | |
| to deal in the Software without restriction, including without limitation | |
| the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| and/or sell copies of the Software, and to permit persons to whom the | |
| Software is furnished to do so, subject to the following conditions: | |
| The above copyright notice and this permission notice shall be included in | |
| all copies or substantial portions of the Software. | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| JOHN FORECAST BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| Except as contained in this notice, the name of John Forecast shall not | |
| be used in advertising or otherwise to promote the sale, use or other dealings | |
| in this Software without prior written authorization from John Forecast. | |
| */ | |
| /* cdc1700_sym.c: symbolic assembler input for "deposit" command | |
| */ | |
| #include "cdc1700_defs.h" | |
| #include <ctype.h> | |
| extern UNIT cpu_unit; | |
| extern uint16 doADDinternal(uint16, uint16); | |
| /* | |
| * Symbol tables | |
| */ | |
| #define I_DATA 0x10000 /* Data transmission */ | |
| #define I_ARITH 0x20000 /* Arithmetic */ | |
| #define I_LOG 0x30000 /* Logical */ | |
| #define I_JUMP 0x40000 /* Jumps */ | |
| #define I_REG 0x50000 /* Register reference */ | |
| #define I_SKIP 0x60000 /* Skip */ | |
| #define I_INTER 0x70000 /* Inter-register */ | |
| #define I_SHIFT 0x80000 /* Shift */ | |
| #define I_MASK 0xF0000 | |
| #define I_DMASK 0xFFFF | |
| /* | |
| * Modifiers for I_REG addressing. | |
| */ | |
| #define I_NONE 0x000000 /* No argument expected */ | |
| #define I_REL 0x100000 /* 8-bit relative address */ | |
| #define I_ABS 0x200000 /* 8-bit absolute value */ | |
| #define I_SIGNED 0x300000 /* 8-bit signed value */ | |
| #define I_MASK2 0x300000 | |
| #define I_NOARG I_REG + I_NONE | |
| static const char *opcode[] = { | |
| "ADQ", "LDQ", "RAO", "LDA", | |
| "EOR", "AND", "SUB", "ADD", | |
| "SPA", "STA", "RTJ", "STQ", | |
| "DVI", "MUI", "JMP", "SLS", | |
| "SAZ", "SAN", "SAP", "SAM", | |
| "SQZ", "SQN", "SQP", "SQM", | |
| "SWS", "SWN", "SOV", "SNO", | |
| "SPE", "SNP", "SPF", "SNF", | |
| "INP", "OUT", "EIN", "IIN", | |
| "ECA", "DCA", "SPB", "CPB", | |
| "AAM", "AAQ", "AAB", "CLR", | |
| "TCM", "TCQ", "TCB", "TCA", | |
| "EAM", "EAQ", "EAB", "SET", | |
| "TRM", "TRQ", "TRB", "TRA", | |
| "LAM", "LAQ", "LAB", "CAM", | |
| "CAQ", "CAB", "INA", "ENA", | |
| "NOP", "ENQ", "INQ", "EXI", | |
| "QRS", "ARS", "LRS", "QLS", | |
| "ALS", "LLS", "ECA", "DCA", | |
| NULL | |
| }; | |
| static const int32 opc_val[] = { | |
| OPC_ADQ + I_ARITH, OPC_LDQ + I_DATA, OPC_RAO + I_ARITH, OPC_LDA + I_DATA, | |
| OPC_EOR + I_LOG, OPC_AND + I_LOG, OPC_SUB + I_ARITH, OPC_ADD + I_ARITH, | |
| OPC_SPA + I_DATA, OPC_STA + I_DATA, OPC_RTJ + I_JUMP, OPC_STQ + I_DATA, | |
| OPC_DVI + I_ARITH, OPC_MUI + I_ARITH, OPC_JMP + I_JUMP, OPC_SLS + I_NOARG, | |
| OPC_SAZ + I_SKIP, OPC_SAN + I_SKIP, OPC_SAP + I_SKIP, OPC_SAM + I_SKIP, | |
| OPC_SQZ + I_SKIP, OPC_SQN + I_SKIP, OPC_SQP + I_SKIP, OPC_SQM + I_SKIP, | |
| OPC_SWS + I_SKIP, OPC_SWN + I_SKIP, OPC_SOV + I_SKIP, OPC_SNO + I_SKIP, | |
| OPC_SPE + I_SKIP, OPC_SNP + I_SKIP, OPC_SPF + I_SKIP, OPC_SNF + I_SKIP, | |
| OPC_INP + I_REG + I_REL, OPC_OUT + I_REG + I_REL, OPC_EIN + I_NOARG, OPC_IIN + I_NOARG, | |
| OPC_ECA + I_NOARG, OPC_DCA + I_NOARG, OPC_SPB + I_NOARG, OPC_CPB + I_NOARG, | |
| OPC_AAM + I_INTER, OPC_AAQ + I_INTER, OPC_AAB + I_INTER, OPC_CLR + I_INTER, | |
| OPC_TCM + I_INTER, OPC_TCQ + I_INTER, OPC_TCB + I_INTER, OPC_TCA + I_INTER, | |
| OPC_EAM + I_INTER, OPC_EAQ + I_INTER, OPC_EAB + I_INTER, OPC_SET + I_INTER, | |
| OPC_TRM + I_INTER, OPC_TRQ + I_INTER, OPC_TRB + I_INTER, OPC_TRA + I_INTER, | |
| OPC_LAM + I_INTER, OPC_LAQ + I_INTER, OPC_LAB + I_INTER, OPC_CAM + I_INTER, | |
| OPC_CAQ + I_INTER, OPC_CAB + I_INTER, OPC_INA + I_REG + I_SIGNED, OPC_ENA + I_REG + I_SIGNED, | |
| OPC_NOP + I_NOARG, OPC_ENQ + I_REG + I_SIGNED, OPC_INQ + I_REG + I_SIGNED, OPC_EXI + I_REG + I_ABS, | |
| OPC_QRS + I_SHIFT, OPC_ARS + I_SHIFT, OPC_LRS + I_SHIFT, OPC_QLS + I_SHIFT, | |
| OPC_ALS + I_SHIFT, OPC_LLS + I_SHIFT, OPC_ECA + I_NOARG, OPC_DCA + I_NOARG | |
| }; | |
| /* | |
| * Register (and pseudo-register) names. | |
| */ | |
| static const char *regname[] = { | |
| "A", "Q", "M", "I", "B", | |
| NULL | |
| }; | |
| /* | |
| * Usage value for each usage type (0 means invalid). | |
| */ | |
| static uint16 instIndex[] = { | |
| 0x0000, MOD_I1, 0x0000, MOD_I2, MOD_I1 | MOD_I2 | |
| }; | |
| static uint16 instInter[] = { | |
| MOD_D_A, MOD_D_Q, MOD_D_M, 0x0000, 0x0000 | |
| }; | |
| #define NEXTSYMBOL(mchar) \ | |
| cptr = get_glyph(cptr, gbuf, mchar); \ | |
| for (j = 0; (regname[j] != NULL) && (strcmp(regname[j], gbuf) != 0); j++); \ | |
| if (regname[j] == NULL) return SCPE_ARG | |
| t_stat parse_sym(CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) | |
| { | |
| int32 cflag, i, j, l, rdx; | |
| t_bool neg, cons; | |
| t_value temp; | |
| t_stat r, sta = SCPE_OK; | |
| char gbuf[CBUFSIZE], mode; | |
| const char *cptr2; | |
| cflag = (uptr == NULL) || (uptr == &cpu_unit); | |
| while (isspace(*cptr)) | |
| cptr++; | |
| if ((sw & SWMASK('A')) || ((*cptr == '\'') && cptr++)) { | |
| /* ASCII character */ | |
| if (cptr[0] == 0) | |
| return SCPE_ARG; | |
| val[0] = (t_value)cptr[0] | 0200; | |
| return SCPE_OK; | |
| } | |
| if ((sw & SWMASK('C')) || ((*cptr == '"') && cptr++)) { | |
| /* Packed ASCII characters (2 to a word) */ | |
| if (cptr[0] == 0) | |
| val[0] = (((t_value)cptr[0] | 0200) << 8) | ((t_value)cptr[1] | 0200); | |
| return SCPE_OK; | |
| } | |
| cptr = get_glyph(cptr, gbuf, 0); | |
| l = strlen(gbuf); | |
| if ((gbuf[l - 1] == '*') || (gbuf[l - 1] == '-') || (gbuf[l - 1] == '+')) { | |
| mode = gbuf[l - 1]; | |
| gbuf[l - 1] = '\0'; | |
| } else mode = 0; | |
| for (i = 0; (opcode[i] != NULL) && (strcmp(opcode[i], gbuf) != 0); i++); | |
| if (opcode[i] == NULL) | |
| return SCPE_ARG; | |
| val[0] = opc_val[i] & I_DMASK; | |
| while (isspace(*cptr)) | |
| cptr++; | |
| cons = neg = FALSE; | |
| rdx = 10; | |
| switch (opc_val[i] & I_MASK) { | |
| case I_DATA: | |
| case I_ARITH: | |
| case I_LOG: | |
| if (*cptr == '=') { | |
| cons = TRUE; | |
| cptr++; | |
| if (*cptr == '-') { | |
| neg = TRUE; | |
| cptr++; | |
| } | |
| if (*cptr == '$') { | |
| rdx = 16; | |
| cptr++; | |
| } | |
| temp = get_uint(cptr, rdx, MAXNEG, &r); | |
| if (r != SCPE_OK) | |
| return r; | |
| if (neg) { | |
| if (temp > MAXPOS) | |
| return SCPE_ARG; | |
| temp = (~temp) & 0xFFFF; | |
| } | |
| if ((mode == '*') || (mode == '-')) | |
| return SCPE_ARG; | |
| /* | |
| * Constant addressing mode always occupies 2 words. | |
| */ | |
| val[1] = temp; | |
| return -1; | |
| } | |
| /* FALLTHROUGH */ | |
| case I_JUMP: | |
| if (*cptr == '(') { | |
| cptr++; | |
| if (*cptr == '$') { | |
| rdx = 16; | |
| cptr++; | |
| } | |
| temp = strtotv(cptr, &cptr2, rdx); | |
| if ((cptr == cptr2) || (*cptr2++ != ')')) | |
| return SCPE_ARG; | |
| cptr = (char *)cptr2; | |
| val[0] |= MOD_IN; | |
| } else { | |
| if (*cptr == '$') { | |
| rdx = 16; | |
| cptr++; | |
| } | |
| temp = strtotv(cptr, &cptr2, rdx); | |
| if (cptr == cptr2) | |
| return SCPE_ARG; | |
| cptr = (char *)cptr2; | |
| } | |
| if (mode == '*') { | |
| temp = doADDinternal(temp, ~addr); | |
| if (CANEXTEND8(temp)) | |
| temp &= 0xFF; | |
| val[0] |= MOD_RE; | |
| } | |
| if ((mode == '-') && ((temp & 0xFF00) != 0)) | |
| return SCPE_ARG; | |
| /* | |
| * Check for indexing modifier | |
| */ | |
| if (*cptr++ == ',') { | |
| NEXTSYMBOL(0); | |
| if (instIndex[j] == 0) | |
| return SCPE_ARG; | |
| val[0] |= instIndex[j]; | |
| } | |
| if (((temp & 0xFF00) != 0) || (mode == '+')) { | |
| val[1] = temp; | |
| return -1; | |
| } | |
| val[0] |= temp; | |
| return SCPE_OK; | |
| case I_REG: | |
| switch (opc_val[i] & I_MASK2) { | |
| case I_NONE: | |
| return SCPE_OK; | |
| case I_REL: | |
| case I_SIGNED: | |
| if (*cptr == '-') { | |
| neg = TRUE; | |
| cptr++; | |
| } | |
| if (*cptr == '$') { | |
| rdx = 16; | |
| cptr++; | |
| } | |
| temp = get_uint(cptr, rdx, 127, &r); | |
| if (r != SCPE_OK) | |
| return r; | |
| if (neg) | |
| temp = (~temp) & 0xFF; | |
| val[0] |= temp; | |
| return SCPE_OK; | |
| case I_ABS: | |
| if (*cptr == '$') { | |
| rdx = 16; | |
| cptr++; | |
| } | |
| temp = get_uint(cptr, rdx, 255, &r); | |
| if (r != SCPE_OK) | |
| return r; | |
| val[0] |= temp; | |
| return SCPE_OK; | |
| } | |
| break; | |
| case I_SKIP: | |
| if (*cptr == '$') { | |
| rdx = 16; | |
| cptr++; | |
| } | |
| temp = get_uint(cptr, rdx, 15, &r); | |
| if (r != SCPE_OK) | |
| return r; | |
| val[0] |= temp; | |
| return SCPE_OK; | |
| case I_INTER: | |
| if (*cptr != 0) { | |
| do { | |
| NEXTSYMBOL(','); | |
| if (instInter[j] == 0) | |
| return SCPE_ARG; | |
| val[0] |= instInter[j]; | |
| } while (*cptr != 0); | |
| } | |
| return SCPE_OK; | |
| case I_SHIFT: | |
| if (*cptr == '$') { | |
| rdx = 16; | |
| cptr++; | |
| } | |
| temp = get_uint(cptr, rdx, 31, &r); | |
| if (r != SCPE_OK) | |
| return r; | |
| val[0] |= temp; | |
| return SCPE_OK; | |
| } | |
| return SCPE_ARG; | |
| } |