Line 2... |
Line 2... |
//
|
//
|
// Filename: zparser.cpp
|
// Filename: zparser.cpp
|
//
|
//
|
// Project: Zip CPU -- a small, lightweight, RISC CPU core
|
// Project: Zip CPU -- a small, lightweight, RISC CPU core
|
//
|
//
|
// Purpose:
|
// Purpose: This file is really mis-named. At one time it was going to
|
|
// be the parser for the Zip Assembler, zasm. Since then, I
|
|
// discovered Flex and Bison and have written a parser using
|
|
// those tools. The true parser may therefore be found in zasm.y.
|
|
// This file, however, still contains some very valuable tools.
|
|
// In particular, all of the routines used to build instructions
|
|
// from the appropriate fields are kept in this file. For example,
|
|
// op_noop() returns the instruction code for a NOOP instruction.
|
//
|
//
|
// Creator: Dan Gisselquist, Ph.D.
|
// Creator: Dan Gisselquist, Ph.D.
|
// Gisselquist Tecnology, LLC
|
// Gisselquist Tecnology, LLC
|
//
|
//
|
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
Line 43... |
Line 50... |
#include "zparser.h"
|
#include "zparser.h"
|
#include "zopcodes.h"
|
#include "zopcodes.h"
|
|
|
typedef ZPARSER::ZIPI ZIPI; // A Zip Instruction (i.e. uint32)
|
typedef ZPARSER::ZIPI ZIPI; // A Zip Instruction (i.e. uint32)
|
|
|
bool ZPARSER::iscomment(const char *line) const {
|
|
const char *sp = line;
|
|
do {
|
|
if (*sp == '\0')
|
|
return true;
|
|
else if (*sp == ';')
|
|
return true;
|
|
else if (*sp == '#')
|
|
return true;
|
|
else if (*sp == '\n')
|
|
return true;
|
|
else if (*sp == '\r')
|
|
return true;
|
|
else if ((*sp == '/')&&(sp[1] == '/'))
|
|
return true;
|
|
else if (!isspace(*sp))
|
|
return false;
|
|
} while(*sp++);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ZPARSER::islabel(const char *line) const {
|
|
const char *sp = line;
|
|
if (isspace(*line))
|
|
return false;
|
|
if (!isalpha(*line))
|
|
return false;
|
|
while((isalpha(*sp))||(isdigit(*sp))||(*sp=='_'))
|
|
sp++;
|
|
if (*sp != ':')
|
|
return false;
|
|
sp++;
|
|
return iscomment(sp);
|
|
}
|
|
|
|
bool ZPARSER::parse_op(const char *line, ZPARSER::ZIPA pc,
|
|
ZPARSER::ZIPI &ins, const unsigned lineno) const {
|
|
const char *sp = line;
|
|
char cpy[128], *cp = cpy, *point, *dollar, *plus, *comma, *paren,
|
|
*opc, *opb, *opa;
|
|
ZPARSER::ZIPREG ra = ZPARSER::ZIP_Rnone, rb = ZPARSER::ZIP_Rnone;
|
|
ZIPCOND cnd = ZIPC_ALWAYS;
|
|
ZIPIMM imm = 0;
|
|
bool valid = true;
|
|
|
|
if (!isspace(*sp))
|
|
return false;
|
|
|
|
while(isspace(*sp))
|
|
sp++;
|
|
// Remove comments from our local copy
|
|
for(unsigned int i=0; i<sizeof(cpy); i++) {
|
|
if (*sp == '\0')
|
|
break;
|
|
else if (*sp == ';')
|
|
break;
|
|
else if (*sp == '#')
|
|
break;
|
|
else if (*sp == '\n')
|
|
break;
|
|
else if (*sp == '\r')
|
|
break;
|
|
else if ((*sp == '/')&&(sp[1] == '/'))
|
|
break;
|
|
*cp++ = *sp++;
|
|
} if (cp-cpy >= (int)sizeof(cpy))
|
|
return false;
|
|
*cp = '\0';
|
|
point = strchr(cpy, '.');
|
|
comma = strchr(cpy, ',');
|
|
plus = strchr(cpy, '+');
|
|
dollar= strchr(cpy, '$');
|
|
paren = strchr(cpy, '(');
|
|
if (point) *point++ = '\0';
|
|
if (comma) *comma++ = '\0';
|
|
if (plus) *plus++ = '\0';
|
|
if (dollar) *dollar++ = '\0';
|
|
// if (paren) *paren++ = '\0';
|
|
cp = cpy;
|
|
while(isalpha(*cp))
|
|
cp++;
|
|
opc = cpy;
|
|
if ((*cp == '\0')&&(point == NULL))
|
|
cp[1] = '\0';
|
|
*cp = '\0';
|
|
|
|
if ((point)&&(strncasecmp("DAT",point,3)!=0)) {
|
|
cp = point;
|
|
while(isalpha(*cp))
|
|
cp++;
|
|
if (*cp == '\0')
|
|
cp[1] = '\0';
|
|
*cp = '\0';
|
|
|
|
for(int i=1; i<8; i++) {
|
|
if (strcasecmp(&zop_ccstr[i][1], point)==0) {
|
|
cnd = (ZIPCOND)i;
|
|
break;
|
|
}
|
|
} if (cnd == ZIPC_ALWAYS) {
|
|
printf("ERR: Unrecognized condition, %s\n", point);
|
|
valid = false;
|
|
}
|
|
}
|
|
|
|
cp++;
|
|
while(isspace(*cp))
|
|
cp++;
|
|
opb = cp;
|
|
opa = comma;
|
|
|
|
if (paren) {
|
|
opb = paren+1;
|
|
if ((comma)&&(opb > comma))
|
|
opa = cp;
|
|
} else if (plus)
|
|
opb = plus;
|
|
|
|
if (dollar) {
|
|
// Figure out the base
|
|
{
|
|
char *ip = dollar, mxd = 0;
|
|
if ((*ip == '0')&&(toupper(ip[1])=='X'))
|
|
imm = strtoul(dollar, NULL, 16);
|
|
else {
|
|
bool neg = false;
|
|
if (*ip == '-') {
|
|
neg = true;
|
|
ip++;
|
|
dollar++;
|
|
}
|
|
while(isdigit(*ip)||((toupper(*ip)>='A')&&(toupper(*ip)<='F'))) {
|
|
if (isalpha(*ip))
|
|
mxd = (*ip-'a')+10;
|
|
else
|
|
mxd = (*ip-'0');
|
|
ip++;
|
|
}
|
|
|
|
if ((mxd <= 1)&&(*ip=='d'))
|
|
imm = strtoul(dollar, NULL, 2);
|
|
else if ((mxd <= 7)&&((*dollar == '0')||(toupper(*ip)=='O')))
|
|
imm = strtoul(dollar, NULL, 8);
|
|
else if ((mxd <= 15)&&(toupper(*ip)=='H'))
|
|
imm = strtoul(dollar, NULL, 16);
|
|
else if ((toupper(*ip)=='D')||(*ip == '+')||(isspace(*ip))||(*ip == '(')||(*ip == '\0'))
|
|
imm = atoi(dollar);
|
|
else {
|
|
printf("Cannot parse immediate, %s\n", dollar);
|
|
printf("Assuming you meant %d\n", atoi(dollar));
|
|
imm = atoi(dollar);
|
|
}
|
|
|
|
if (neg)
|
|
imm = -imm;
|
|
}
|
|
}
|
|
} else
|
|
imm = 0;
|
|
|
|
if (*opb) for(int i=31; i>=0; i--) {
|
|
// printf("%s Checking for match to opB: \'%s\' to %s", opc, opb, zop_regstr[i]);
|
|
if (NULL != strcasestr(opb, zop_regstr[i])) {
|
|
// printf(" --- Match\n");
|
|
rb = (ZIPREG)i;
|
|
break;
|
|
} // else printf(" -- nope\n");
|
|
} if (opa) for(int i=31; i>=0; i--) {
|
|
// printf("%s Checking for match to opA: ,%s to %s", opc, opa, zop_regstr[i]);
|
|
if (NULL != strcasestr(opa, zop_regstr[i])) {
|
|
ra = (ZIPREG)i;
|
|
// printf(" --- Match\n");
|
|
break;
|
|
} // else printf(" -- nope\n");
|
|
}
|
|
|
|
if (strcasecmp("MOV",opc)!=0) {
|
|
// Only move instructions can reference user regs
|
|
if ((ra != ZIP_Rnone)&&(ra >= ZIP_uR0))
|
|
valid = false;
|
|
if ((rb != ZIP_Rnone)&&(rb >= ZIP_uR0))
|
|
valid = false;
|
|
if (!valid)
|
|
printf("ERR: Only Mov can specify user regs\n");
|
|
}
|
|
|
|
if ((!*opc)&&(strncasecmp("DAT",point,3)==0)) {
|
|
ins = imm;
|
|
valid = true;
|
|
} else if (strcasecmp("CMP",opc)==0) {
|
|
if (rb != ZIP_Rnone)
|
|
ins = op_cmp(cnd, imm, rb, ra);
|
|
else ins = op_cmp(cnd, imm, ra);
|
|
} else if (strcasecmp("TST",opc)==0) {
|
|
if (rb != ZIP_Rnone)
|
|
ins = op_tst(cnd, imm, rb, ra);
|
|
else if (!dollar)
|
|
ins = op_tst(cnd, ra);
|
|
else
|
|
ins = op_tst(cnd, imm, ra);
|
|
} else if (strcasecmp("MOV",opc)==0) {
|
|
if ((rb != ZIP_Rnone)&&(ra != ZIP_Rnone))
|
|
ins = op_mov(cnd, imm, rb, ra);
|
|
else { printf("ERR MOV, ra = %d, rb = %d, imm = %d, cnd = %d\nLine was: %s", (int)ra, (int)rb, (int)imm, (int)cnd, line); valid = false; }
|
|
} else if (strcasecmp("LDI",opc)==0) {
|
|
if ((rb == ZIP_Rnone)&&(cnd == ZIPC_ALWAYS))
|
|
ins = op_ldi(imm, ra);
|
|
else valid = false;
|
|
} else if (strcasecmp("trap",opc)==0) {
|
|
if ((rb == ZIP_Rnone)&&(rb == ZIP_Rnone))
|
|
ins = op_trap(cnd, imm);
|
|
else
|
|
valid = false;
|
|
} else if (strcasecmp("CLR",opc)==0) {
|
|
if ((ra == ZIP_Rnone)&&(!dollar)&&(cnd == ZIPC_ALWAYS))
|
|
ins = op_clr(rb); // Good
|
|
else valid = false;
|
|
} else if ((strcasecmp("NOOP",opc)==0)||(strcasecmp("NOP",opc)==0)) {
|
|
if ((rb == ZIP_Rnone)&&(ra == ZIP_Rnone)&&(!dollar)&&(cnd == ZIPC_ALWAYS))
|
|
ins = op_noop();
|
|
else { printf("ERR: NOP, ra=%d, rb=%d, dollar = %s\n",
|
|
(int)ra, (int)rb, (dollar)?"true":"false"); valid = false; }
|
|
} else if ((strcasecmp("BREAK",opc)==0)||(strcasecmp("BRK",opc)==0)) {
|
|
if ((rb == ZIP_Rnone)&&(ra == ZIP_Rnone)&&(!dollar)&&(cnd == ZIPC_ALWAYS))
|
|
ins = op_break();
|
|
else { printf("ERR: BRK, ra=%d, rb=%d, dollar = %s\n",
|
|
(int)ra, (int)rb, (dollar)?"true":"false"); valid = false; }
|
|
} else if ((strcasecmp("LDIHI",opc)==0)||(strcasecmp("LODIHI",opc)==0)) {
|
|
if ((dollar)&&(ra != ZIP_Rnone))
|
|
ins = op_ldihi(cnd, imm, ra);
|
|
else valid = false;
|
|
} else if ((strcasecmp("LDILO",opc)==0)||(strcasecmp("LODILO",opc)==0)){
|
|
if ((dollar)&&(ra != ZIP_Rnone))
|
|
ins = op_ldilo(cnd, imm, ra);
|
|
else valid = false;
|
|
} else if ((strcasecmp("LOD",opc)==0)||(strcasecmp("LOAD",opc)==0)) {
|
|
if (rb != ZIP_Rnone)
|
|
ins = op_lod(cnd,imm,rb,ra);
|
|
else ins = op_lod(cnd,imm,ra);
|
|
} else if ((strcasecmp("STO",opc)==0)||(strcasecmp("STOR",opc)==0)) {
|
|
// printf("STO: Imm = %d, RA = %d, RB = %d\n", imm, ra, rb);
|
|
if (rb != ZIP_Rnone)
|
|
ins = op_sto(cnd,ra,imm,rb);
|
|
else ins = op_sto(cnd,ra,imm);
|
|
} else if (strcasecmp("SUB",opc)==0) {
|
|
if (rb != ZIP_Rnone)
|
|
ins = op_sub(cnd,imm,rb,ra);
|
|
else ins = op_sub(cnd,imm,ra);
|
|
} else if (strcasecmp("AND",opc)==0) {
|
|
if (rb != ZIP_Rnone)
|
|
ins = op_and(cnd,imm,rb,ra);
|
|
else ins = op_and(cnd,imm,ra);
|
|
} else if (strcasecmp("ADD",opc)==0) {
|
|
if (rb != ZIP_Rnone)
|
|
ins = op_add(cnd,imm,rb,ra);
|
|
else ins = op_add(cnd,imm,ra);
|
|
} else if (strcasecmp("OR",opc)==0) {
|
|
if (rb != ZIP_Rnone)
|
|
ins = op_or(cnd,imm,rb,ra);
|
|
else ins = op_or(cnd,imm,ra);
|
|
} else if (strcasecmp("XOR",opc)==0) {
|
|
if (rb != ZIP_Rnone)
|
|
ins = op_xor(cnd,imm,rb,ra);
|
|
else ins = op_xor(cnd,imm,ra);
|
|
} else if ((strcasecmp("LSL",opc)==0)||(strcasecmp("ASL",opc)==0)) {
|
|
if (rb != ZIP_Rnone)
|
|
ins = op_lsl(cnd,imm,rb,ra);
|
|
else ins = op_lsl(cnd,imm,ra);
|
|
} else if (strcasecmp("ASR",opc)==0) {
|
|
if (rb != ZIP_Rnone)
|
|
ins = op_asr(cnd,imm,rb,ra);
|
|
else ins = op_asr(cnd,imm,ra);
|
|
} else if (strcasecmp("LSR",opc)==0) {
|
|
if (rb != ZIP_Rnone)
|
|
ins = op_lsr(cnd,imm,rb,ra);
|
|
else ins = op_lsr(cnd,imm,ra);
|
|
} else if (strcasecmp("BR",opc)==0) {
|
|
if ((dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone))
|
|
valid = false;
|
|
else ins = op_bra(cnd, imm);
|
|
} else if (strcasecmp("BRA",opc)==0) {
|
|
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS))
|
|
valid = false;
|
|
else ins = op_bra(imm);
|
|
} else if (strcasecmp("BRZ",opc)==0) {
|
|
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS))
|
|
valid = false;
|
|
else ins = op_brz(imm);
|
|
} else if ((strcasecmp("BRNZ",opc)==0)||(strcasecmp("BNZ",opc)==0)) {
|
|
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS))
|
|
valid = false;
|
|
else ins = op_bnz(imm);
|
|
} else if ((strcasecmp("BRGE",opc)==0)||(strcasecmp("BGE",opc)==0)) {
|
|
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS))
|
|
valid = false;
|
|
else ins = op_bge(imm);
|
|
} else if ((strcasecmp("BRGT",opc)==0)||(strcasecmp("BGT",opc)==0)) {
|
|
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS))
|
|
valid = false;
|
|
else ins = op_bgt(imm);
|
|
} else if (strcasecmp("BRZ",opc)==0) {
|
|
} else if ((strcasecmp("BRLT",opc)==0)||(strcasecmp("BLT",opc)==0)) {
|
|
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS))
|
|
valid = false;
|
|
else ins = op_blt(imm);
|
|
} else if ((strcasecmp("BRC",opc)==0)||(strcasecmp("BC",opc)==0)) {
|
|
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS))
|
|
valid = false;
|
|
else ins = op_brc(imm);
|
|
} else if ((strcasecmp("BRV",opc)==0)||(strcasecmp("BV",opc)==0)) {
|
|
if ((!dollar)||(ra != ZIP_Rnone)||(rb != ZIP_Rnone)||(cnd != ZIPC_ALWAYS))
|
|
valid = false;
|
|
else ins = op_brv(imm);
|
|
} else if (strcasecmp("CLRF",opc)==0) {
|
|
if ((ra == ZIP_Rnone)&&(!dollar)&&(imm==0))
|
|
ins = op_clrf(cnd, rb);
|
|
else valid = false;
|
|
} else if((strcasecmp("HALT",opc)==0)||(strcasecmp("WAIT",opc)==0)) {
|
|
if ((rb == ZIP_Rnone)&&(ra==ZIP_Rnone)&&(!opa)&&(!dollar))
|
|
ins = op_halt(cnd);
|
|
else valid = false;
|
|
} else if (strcasecmp("BUSY",opc)==0) {
|
|
if ((rb == ZIP_Rnone)&&(ra==ZIP_Rnone)&&(!opa)&&(!dollar))
|
|
ins = op_busy(cnd);
|
|
else valid = false;
|
|
} else if (strcasecmp("RTU",opc)==0) {
|
|
if ((rb == ZIP_Rnone)&&(ra==ZIP_Rnone)&&(imm==0)&&(!opa)&&(!dollar))
|
|
ins = op_rtu(cnd);
|
|
else { printf("ERRR,RTU, ra=%d,rb=%d,imm=%08x,comma=%s,dollar=%s\n",
|
|
(int)ra, (int)rb, imm, (opa)?"true":"false",
|
|
(dollar)?"true":"false");
|
|
valid = false;
|
|
}
|
|
} else if (strcasecmp("JMP",opc)==0) {
|
|
if ((rb != ZIP_Rnone)&&(!opa))
|
|
ins = op_not(cnd, rb);
|
|
else valid = false;
|
|
} else if (strcasecmp("NOT",opc)==0) {
|
|
if ((rb != ZIP_Rnone)&&(ra==ZIP_Rnone)&&(!opa)&&(!dollar))
|
|
ins = op_not(cnd, rb);
|
|
else valid = false;
|
|
} else valid = false;
|
|
|
|
return valid;
|
|
}
|
|
|
|
bool ZPARSER::parse(const char *line, ZPARSER::ZIPA &pc, ZPARSER::ZIPI &instruction, const unsigned int lineno) {
|
|
bool v = parse_op(line, pc, instruction, lineno);
|
|
pc = pc + 1;
|
|
return v;
|
|
}
|
|
|
|
#define IMMOP(OP,CND,IMM,A) (((OP&0x0f)<<28)|((A&0x0f)<<24)|((CND&0x07)<<21) \
|
#define IMMOP(OP,CND,IMM,A) (((OP&0x0f)<<28)|((A&0x0f)<<24)|((CND&0x07)<<21) \
|
| (IMM & 0x0fffff))
|
| (IMM & 0x0fffff))
|
|
|
#define DBLREGOP(OP,CND,IMM,B,A) (((OP&0x0f)<<28)|((A&0x0f)<<24) \
|
#define DBLREGOP(OP,CND,IMM,B,A) (((OP&0x0f)<<28)|((A&0x0f)<<24) \
|
|((CND&0x07)<<21)|(1<<20)|((B&0x0f)<<16) \
|
|((CND&0x07)<<21)|(1<<20)|((B&0x0f)<<16) \
|
Line 437... |
Line 91... |
return in;
|
return in;
|
}
|
}
|
|
|
ZIPI ZPARSER::op_trap(ZIPCOND cnd, ZIPIMM imm) const {
|
ZIPI ZPARSER::op_trap(ZIPCOND cnd, ZIPIMM imm) const {
|
ZIPI in;
|
ZIPI in;
|
in = ((0x4f)<<24)|((cnd&0x07)<<21)|(1<<20)|((0x0e)<<16);
|
if (cnd != ZIPC_ALWAYS)
|
in |= (imm & 0x0ffff);
|
return op_ldilo(cnd, imm, ZIP_CC);
|
|
else
|
|
return op_ldi(imm, ZIP_CC);
|
|
// in = ((0x4f)<<24)|((cnd&0x07)<<21)|(1<<20)|((0x0e)<<16);
|
|
// in |= (imm & 0x0ffff);
|
return in;
|
return in;
|
}
|
}
|
|
|
ZIPI ZPARSER::op_noop(void) const {
|
ZIPI ZPARSER::op_noop(void) const {
|
return 0x4e000000;
|
return 0x4e000000;
|