OpenCores
URL https://opencores.org/ocsvn/zipcpu/zipcpu/trunk

Subversion Repositories zipcpu

[/] [zipcpu/] [trunk/] [sw/] [zasm/] [zparser.cpp] - Rev 5

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.