view src/insn_gen.c @ 19:925105ccf22f

small reworking of command arguments
author lost
date Fri, 02 Jan 2009 00:41:58 +0000
parents 34568fab6058
children 74a3fef7c8d0
line wrap: on
line source

/*
insn_gen.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 general addressing modes (IMM+DIR+EXT+IND)
*/

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

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

void insn_gen_aux(asmstate_t *as, sourceline_t *cl, char **optr, int *b1, int *b2, int *b3, int *op)
{
	*b1 = *b2 = *b3 = -1;
	char *optr2;
	int v1, tv, rval;
	
	optr2 = *optr;
	while (*optr2 && !isspace(*optr2) && *optr2 != ',') optr2++
		;
	if (*optr2 != ',' && **optr != '[')
	{
		// not indexed
		if (**optr == '<')
		{
			(*optr)++;
			rval = eval_expr(as, cl, optr, &v1);
			v1 = v1 & 0xffff;
			tv = v1 - ((cl -> dpval) << 8);
			if (tv < 0 || tv > 0xff)
			{
				errorp2(ERR_OVERFLOW);
			}
			v1 = v1 & 0xff;
			goto ins_gen_dir;
		}
		else if (**optr == '>')
		{
			// extended mode
			(*optr)++;
			rval = eval_expr(as, cl, optr, &v1);
			goto ins_gen_ext;
		}
		else
		{
			// eval expr and see how big it is
			rval = eval_expr(as, cl, optr, &v1);
			v1 = v1 & 0xFFFF;
			
			if (cl -> undef && as -> passnum == 1)
			{
				cl -> p1f16 = 1;
				goto ins_gen_ext;
			}
			
			tv = v1 - (cl -> dpval << 8);

			if (tv < 0 || tv > 0xff || cl -> p1f16)
				goto ins_gen_ext;
			else
			{
				v1 = v1 & 0xff;
				goto ins_gen_dir;
			}
		}
		return;
	}	

	*op = instab[cl -> opcode].ops[1];
	insn_indexed_aux(as, cl, optr, b1, b2, b3);
	return;

ins_gen_dir:
	*op = instab[cl -> opcode].ops[0];
//	cl -> code_operlen = 1;
	cl -> addrmode = OPER_DIR;
	if ((v1 & 0xFFFF) > 0xff)
		errorp2(ERR_OVERFLOW);
	*b1 = (v1);
	return;

ins_gen_ext:
	*op = instab[cl -> opcode].ops[2];
//	cl -> code_operlen = 2;
	cl -> addrmode = OPER_EXT;
	*b1 = (v1 >> 8);
	*b2 = (v1 & 0xff);
	return;
}

void insn_gen(asmstate_t *as, sourceline_t *cl, char **optr)
{
	int rval;
	int v1;
	int b1, b2, b3, op;
		
	if (**optr == '#')
	{
		// immediate mode has perterbations on instruction size
		(*optr)++;
		emitop(instab[cl -> opcode].ops[3]);
		rval = eval_expr(as, cl, optr, &v1);

		switch (instab[cl -> opcode].instype)
		{
		case INSTYPE_GEN8:
		case INSTYPE_IMM8:
			cl -> addrmode = OPER_IMM8;
//			cl -> code_operlen = 1;
			emit(v1 & 0xff);
			if (v1 < -128 || v1 > 255)
				errorp2(ERR_OVERFLOW);
			return;
			
		case INSTYPE_GEN:
			cl -> addrmode = OPER_IMM16;
//			cl -> code_operlen = 2;
			emit(v1 >> 8);
			emit(v1 & 0xff);
			return;
			
		case INSTYPE_GEN32:
			cl -> addrmode = OPER_IMM32;
//			cl -> code_operlen = 4;
			emit(v1 >> 24);
			emit((v1 >> 16) & 0xff);
			emit((v1 >> 8) & 0xff);
			emit(v1 & 0xff);
			return;
			
		default:
			errorp1(ERR_BADOPER);
			return;
		
		}

		return;
	}
	if (instab[cl -> opcode].instype == INSTYPE_IMM8)
	{
		errorp1(ERR_BADOPER);
		return;
	}

	insn_gen_aux(as, cl, optr, &b1, &b2, &b3, &op);
	emitop(op);
	if (b1 != -1)
		emit(b1);
	if (b2 != -1)
		emit(b2);
	if (b3 != -1)
		emit(b3);
}