view src/insn_misc.c @ 8:f1df096aa76f 1.1

Tagged 1.1 bugfix release
author lost
date Sun, 04 Jan 2009 05:46:07 +0000
parents 34568fab6058
children f736579569b4
line wrap: on
line source

/*
insn_misc.c
Copyright © 2008 William Astle

This file is part of LWASM.

LWASM is free software: 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 MERCHANTABILITY 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. If not, see <http://www.gnu.org/licenses/>.

Contains code for parsing miscelaneous addressing modes
*/

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "lwasm.h"
#include "instab.h"

extern void insn_gen_aux(asmstate_t *as, sourceline_t *cl, char **optr, int *b1, int *b2, int *b3, int *op);

void insn_inh(asmstate_t *as, sourceline_t *cl, char **optr)
{
	cl -> addrmode = OPER_INH;
	emitop(instab[cl -> opcode].ops[0]);
}

void insn_rtor(asmstate_t *as, sourceline_t *cl, char **optr)
{
	int r0, r1;
	static const char *regs = "D X Y U S PCW V A B CCDP0 0 E F ";
	
	cl -> addrmode = OPER_RTOR;
	emitop(instab[cl -> opcode].ops[0]);
	// register to register (r0,r1)
	// registers are in order:
	// D,X,Y,U,S,PC,W,V
	// A,B,CC,DP,0,0,E,F
	r0 = lookupreg(regs, optr);
	if (r0 < 0 || *(*optr)++ != ',')
	{
		errorp1(ERR_BADOPER);
		r0 = r1 = 0;
	}
	else
	{
		r1 = lookupreg(regs, optr);
		if (r1 < 0)
		{
			errorp1(ERR_BADOPER);
			r0=r1=0;
		}
	}
	emit((r0 << 4) | r1);
}

void insn_rlist(asmstate_t *as, sourceline_t *cl, char **optr)
{
	int rb = 0;
	int rn;
	static const char *regs = "CCA B DPX Y U PCD S ";

	emitop(instab[cl -> opcode].ops[0]);
	cl -> addrmode = OPER_RLIST;
	while (**optr && !isspace(**optr))
	{
		rn = lookupreg(regs, optr);
		if (rn < 0)
		{
			printf("Bad reg (%s)\n", *optr);
			errorp1(ERR_BADOPER);
			emit(0);
			return;
		}
		if (**optr && **optr != ',' && !isspace(**optr))
		{
			printf("Bad char (%c)\n", **optr);
			errorp1(ERR_BADOPER);
			emit(0);
			return;
		}
		if (**optr == ',')
			(*optr)++;
		if (rn == 8)
			rn = 6;
		else if (rn == 9)
			rn = 0x40;
		else
			rn = 1 << rn;
		rb |= rn;
	}
	emit(rb);
}

// for aim, oim, eim, tim
void insn_logicmem(asmstate_t *as, sourceline_t *cl, char **optr)
{
	int rval, v1;
	int b1, b2, b3, op;
	
	if (**optr == '#')
		(*optr)++;
	
	rval = eval_expr(as, cl, optr, &v1);
	if (rval < 0)
		return;
	
	if (v1 < -128 || v1 > 255)
	{
		errorp2(ERR_OVERFLOW);
		v1 = 0;
	}
	
	if (**optr != ',' && **optr != ';')
	{
		errorp1(ERR_BADOPER);
		return;
	}
	
	(*optr)++;

	// now we have a general addressing mode - call for it
	insn_gen_aux(as, cl, optr, &b1, &b2, &b3, &op);
	
	emitop(op);
	emit(v1 & 0xff);
	if (b1 != -1)
	{
		emit(b1);
	}
	if (b2 != -1)
	{
		emit(b2);
	}
	if (b3 != -1)
	{
		emit(b3);
	}
}

void insn_tfm(asmstate_t *as, sourceline_t *cl, char **optr)
{
	static const char *reglist = "DXYUS   AB  00EF";
	int r0, r1;
	char *c;
	int tfm = 0;
			
	cl -> addrmode = OPER_TFM;
			
	c = strchr(reglist, toupper(*(*optr)++));
	if (!c)
	{
		errorp1(ERR_BADOPER);
		return;
	}
	r0 = c - reglist;
	if (**optr == '+')
	{
		(*optr)++;
		tfm = 1;
	}
	else if (**optr == '-')
	{
		(*optr)++;
		tfm = 2;
	}
	if (*(*optr)++ != ',')
	{
		errorp1(ERR_BADOPER);
		return;
	}
	c = strchr(reglist, toupper(*(*optr)++));
	if (!c)
	{
		errorp1(ERR_BADOPER);
		return;
	}
	r1 = c - reglist;

	if (**optr == '+')
	{
		(*optr)++;
		tfm |= 4;
	}
	else if (**optr == '-')
	{
		(*optr)++;
		tfm |= 8;
	}
	
	if (**optr && !isspace(**optr))
	{
		errorp1(ERR_BADOPER);
		return;
	}
			
	// valid values of tfm here are:
	// 1: r0+,r1 (2)
	// 4: r0,r1+ (3)
	// 5: r0+,r1+ (0)
	// 10: r0-,r1- (1)
	switch (tfm)
	{
	case 5: //r0+,r1+
		emitop(instab[cl -> opcode].ops[0]);
		break;
	case 10: //r0-,r1-
		emitop(instab[cl -> opcode].ops[1]);
		break;
	case 1: // r0+,r1
		emitop(instab[cl -> opcode].ops[2]);
		break;
	case 4: // r0,r1+
		emitop(instab[cl -> opcode].ops[3]);
		break;
	default:
		errorp1(ERR_BADOPER);
		return;
	}
	emit((r0 << 4) | r1);
}

void insn_bitbit(asmstate_t *as, sourceline_t *cl, char **optr)
{
	int r;
	int rval;
	int v1;
	int tv;
		
	emitop(instab[cl -> opcode].ops[0]);
	
	cl -> addrmode = OPER_BITBIT;

	r = toupper(*(*optr)++);
	if (r == 'A')
		r = 1;
	else if (r == 'B')
		r = 2;
	else if (r == 'C' && toupper(**optr) == 'C')
	{
		r = 0;
		(*optr)++;
	}
	else
	{
		errorp1(ERR_BADREG);
		return;
	}
	if (*(*optr)++ != ',')
	{
		errorp1(ERR_BADOPER);
		return;
	}
	rval = eval_expr(as, cl, optr, &v1);
	if (v1 < 0 || v1 > 7)
	{
		errorp2(ERR_OVERFLOW3);
		v1 = 0;
	}
	if (*(*optr)++ != ',')
	{
		errorp1(ERR_BADOPER);
		return;
	}
	r = (r << 6) | (v1 << 3);
	rval = eval_expr(as, cl, optr, &v1);
	if (v1 < 0 || v1 > 7)
	{
		errorp2(ERR_OVERFLOW3);
		v1 = 0;
	}
	if (*(*optr)++ != ',')
	{
		errorp1(ERR_BADOPER);
		return;
	}
	r |= v1;
	
	emit(r);
			
	// ignore base page address modifier
	if (**optr == '<')
		optr++;
			
	rval = eval_expr(as, cl, optr, &v1);
	v1 &= 0xFFFF;
	tv = v1 - ((cl -> dpval) << 8);
	if (tv > 0xFF || tv < 0)
		errorp2(ERR_OVERFLOW);
	emit(tv & 0xff);
}

void insn_rel8(asmstate_t *as, sourceline_t *cl, char **optr)
{
	int v1, rval;
	
	emitop(instab[cl -> opcode].ops[0]);
	cl -> addrmode = OPER_REL8;
	rval = eval_expr(as, cl, optr, &v1);
	v1 &= 0xFFFF;
	v1 -= cl -> addr + 2;
	if (v1 < -128 || v1 > 127)
		errorp2(ERR_OVERFLOW);
	v1 &= 0xFFFF;
	emit(v1 & 0xff);
}

void insn_rel16(asmstate_t *as, sourceline_t *cl, char **optr)
{
	int v1, rval;

	emitop(instab[cl -> opcode].ops[0]);
	cl -> addrmode = OPER_REL16;
	rval = eval_expr(as, cl, optr, &v1);
	v1 &= 0xFFFF;
	v1 -= cl -> addr + 3;
	if (instab[cl -> opcode].ops[0] > 0xff)
		v1 -= 1;
	v1 &= 0xFFFF;
	emit(v1 >> 8);
	emit(v1 & 0xff);
}