URL
https://opencores.org/ocsvn/zipcpu/zipcpu/trunk
Subversion Repositories zipcpu
[/] [zipcpu/] [trunk/] [sw/] [zasm/] [zparser.cpp] - Rev 2
Go to most recent revision | Compare with Previous | Blame | View Log
//////////////////////////////////////////////////////////////////////////////// // // Filename: zparser.cpp // // Project: Zip CPU -- a small, lightweight, RISC CPU core // // Purpose: // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Tecnology, LLC // //////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2015, Gisselquist Technology, LLC // // This program is free software (firmware): you can redistribute it and/or // modify it under the terms of the GNU General Public License as published // by the Free Software Foundation, either version 3 of the License, or (at // your option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with this program. (It's in the $(ROOT)/doc directory, run make with no // target there if the PDF file isn't present.) If not, see // <http://www.gnu.org/licenses/> for a copy. // // License: GPL, v3, as defined and found on www.gnu.org, // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <strings.h> #include "zparser.h" #include "zopcodes.h" 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, *opc, *opb; 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; 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; } } opb = dollar; if (plus) opb = plus; } else imm = 0; if (*opb) for(int i=31; i>=0; i--) { // printf("Checking for match: \'%s\' to %s", opb, zop_regstr[i]); if (NULL != strcasestr(opb, zop_regstr[i])) { // printf(" --- Match\n"); rb = (ZIPREG)i; break; } // else printf(" -- nope\n"); } if (comma) for(int i=31; i>=0; i--) { // printf("Checking for match: ,%s to %s", comma, zop_regstr[i]); if (NULL != strcasestr(comma, 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 = strtoul(opb, NULL, 0); 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)) { if (rb != ZIP_Rnone) ins = op_sto(cnd,rb,imm,ra); else ins = op_sto(cnd,rb,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)&&(!comma)&&(!dollar)) ins = op_halt(cnd); else valid = false; } else if (strcasecmp("BUSY",opc)==0) { if ((rb == ZIP_Rnone)&&(ra==ZIP_Rnone)&&(!comma)&&(!dollar)) ins = op_busy(cnd); else valid = false; } else if (strcasecmp("RTU",opc)==0) { if ((rb == ZIP_Rnone)&&(ra==ZIP_Rnone)&&(imm==0)&&(!comma)&&(!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, (comma)?"true":"false", (dollar)?"true":"false"); valid = false; } } else if (strcasecmp("JMP",opc)==0) { if ((rb != ZIP_Rnone)&&(!comma)) ins = op_not(cnd, rb); else valid = false; } else if (strcasecmp("NOT",opc)==0) { if ((rb != ZIP_Rnone)&&(ra==ZIP_Rnone)&&(!comma)&&(!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) \ | (IMM & 0x0fffff)) #define DBLREGOP(OP,CND,IMM,B,A) (((OP&0x0f)<<28)|((A&0x0f)<<24) \ |((CND&0x07)<<21)|(1<<20)|((B&0x0f)<<16) \ | (IMM & 0x0ffff)) ZIPI ZPARSER::op_cmp(ZIPCOND cnd, ZIPIMM imm, ZIPREG b, ZIPREG a) const { return DBLREGOP(0x0, cnd, imm, b, a); } ZIPI ZPARSER::op_cmp(ZIPCOND cnd, ZIPIMM imm, ZIPREG a) const { return IMMOP(0x0, cnd, imm, a); } ZIPI ZPARSER::op_tst(ZIPCOND cnd, ZIPIMM imm, ZIPREG b, ZIPREG a) const { return DBLREGOP(0x1, cnd, imm, b, a); } ZIPI ZPARSER::op_tst(ZIPCOND cnd, ZIPIMM imm, ZIPREG a) const { return IMMOP(0x1, cnd, imm, a); } ZIPI ZPARSER::op_mov(ZIPCOND cnd, ZIPIMM imm, ZIPREG b, ZIPREG a) const { ZIPI in; in = (0x02 << 28)|((a&0x0f)<<24)|((cnd&0x07)<<21); in |= (a&0x10)<<16; in |= (b&0x0f)<<16; in |= (b&0x10)<<11; in |= imm & 0x07fff; return in; } ZIPI ZPARSER::op_ldi(ZIPIMM imm, ZIPREG a) const { ZIPI in; in = ((0x03)<<28) | ((a&0x0f)<<24) | (imm & ((1<<24)-1)); return in; } ZIPI ZPARSER::op_trap(ZIPCOND cnd, ZIPIMM imm) const { ZIPI in; in = ((0x4f)<<24)|((cnd&0x07)<<21)|(1<<20)|((0x0e)<<16); in |= (imm & 0x0ffff); return in; } ZIPI ZPARSER::op_noop(void) const { return 0x4e000000; } ZIPI ZPARSER::op_break(void) const { return 0x4e000001; } ZIPI ZPARSER::op_ldihi(ZIPCOND cnd, ZIPIMM imm, ZIPREG a) const { ZIPI in; in = ((0x4f)<<24)|((cnd&0x07)<<21)|(1<<20)|((a&0x0f)<<16); in |= (imm & 0x0ffff); return in; } ZIPI ZPARSER::op_ldilo(ZIPCOND cnd, ZIPIMM imm, ZIPREG a) const { ZIPI in; in = ((0x4f)<<24)|((cnd&0x07)<<21)|(0<<20)|((a&0x0f)<<16); in |= (imm & 0x0ffff); return in; } ZIPI ZPARSER::op_lod(ZIPCOND cnd, ZIPIMM imm, ZIPREG b, ZIPREG a) const { return DBLREGOP(0x6, cnd, imm, b, a); } ZIPI ZPARSER::op_lod(ZIPCOND cnd, ZIPIMM imm, ZIPREG a) const { return IMMOP(0x6, cnd, imm, a); } ZIPI ZPARSER::op_sto(ZIPCOND cnd, ZIPREG v, ZIPIMM imm, ZIPREG b) const { return DBLREGOP(0x7, cnd, imm, b, v); } ZIPI ZPARSER::op_sto(ZIPCOND cnd, ZIPREG v, ZIPIMM imm) const { return IMMOP(0x7, cnd, imm, v); } ZIPI ZPARSER::op_sub(ZIPCOND cnd, ZIPIMM imm, ZIPREG b, ZIPREG a) const { return DBLREGOP(0x8, cnd, imm, b, a); } ZIPI ZPARSER::op_sub(ZIPCOND cnd, ZIPIMM imm, ZIPREG a) const { return IMMOP(0x8, cnd, imm, a); } ZIPI ZPARSER::op_and(ZIPCOND cnd, ZIPIMM imm, ZIPREG b, ZIPREG a) const { return DBLREGOP(0x9, cnd, imm, b, a); } ZIPI ZPARSER::op_and(ZIPCOND cnd, ZIPIMM imm, ZIPREG a) const { return IMMOP(0x9, cnd, imm, a); } ZIPI ZPARSER::op_add(ZIPCOND cnd, ZIPIMM imm, ZIPREG b, ZIPREG a) const { return DBLREGOP(0xa, cnd, imm, b, a); } ZIPI ZPARSER::op_add(ZIPCOND cnd, ZIPIMM imm, ZIPREG a) const { return IMMOP(0xa, cnd, imm, a); } ZIPI ZPARSER::op_or(ZIPCOND cnd, ZIPIMM imm, ZIPREG b, ZIPREG a) const { return DBLREGOP(0xb, cnd, imm, b, a); } ZIPI ZPARSER::op_or(ZIPCOND cnd, ZIPIMM imm, ZIPREG a) const { return IMMOP(0xb, cnd, imm, a); } ZIPI ZPARSER::op_xor(ZIPCOND cnd, ZIPIMM imm, ZIPREG b, ZIPREG a) const { return DBLREGOP(0xc, cnd, imm, b, a); } ZIPI ZPARSER::op_xor(ZIPCOND cnd, ZIPIMM imm, ZIPREG a) const { return IMMOP(0xc, cnd, imm, a); } ZIPI ZPARSER::op_lsl(ZIPCOND cnd, ZIPIMM imm, ZIPREG b, ZIPREG a) const { return DBLREGOP(0xd, cnd, imm, b, a); } ZIPI ZPARSER::op_lsl(ZIPCOND cnd, ZIPIMM imm, ZIPREG a) const { return IMMOP(0xd, cnd, imm, a); } ZIPI ZPARSER::op_asr(ZIPCOND cnd, ZIPIMM imm, ZIPREG b, ZIPREG a) const { return DBLREGOP(0xe, cnd, imm, b, a); } ZIPI ZPARSER::op_asr(ZIPCOND cnd, ZIPIMM imm, ZIPREG a) const { return IMMOP(0xe, cnd, imm, a); } ZIPI ZPARSER::op_lsr(ZIPCOND cnd, ZIPIMM imm, ZIPREG b, ZIPREG a) const { return DBLREGOP(0xf, cnd, imm, b, a); } ZIPI ZPARSER::op_lsr(ZIPCOND cnd, ZIPIMM imm, ZIPREG a) const { return IMMOP(0xf, cnd, imm, a); }
Go to most recent revision | Compare with Previous | Blame | View Log