blob: 6f41f2ab5b7ff425442b6ffc66bf195fe9f1e3f4 [file] [log] [blame] [raw]
/*
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;
}