view src/insn_gen.c @ 67:d5fe306f1ab1

Fixed numerous bugs in macro handling
author lost
date Mon, 05 Jan 2009 05:40:33 +0000
parents 31d8e85706e7
children a338d496350e
line wrap: on
line source

/*
insn_gen.c, Copyright © 2009 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 <stdlib.h>

#include "lwasm.h"
#include "instab.h"
#include "expr.h"

extern void insn_indexed_aux(asmstate_t *as, lwasm_line_t *l, const char **p, int *b1, int *b2, int *b3);

// "extra" is required due to the way OIM, EIM, TIM, and AIM work
void insn_gen_aux(asmstate_t *as, lwasm_line_t *l, char **optr, int opnum, int extra)
{
	int b1 = -1, b2 = -1, b3 = -1;

	const char *optr2;
	int v1, tv, rval;
	lwasm_expr_stack_t *s;
	int f8 = 0;
	int f16 = 0;
	int isdp = 0;
		
	optr2 = *optr;
	while (*optr2 && !isspace(*optr2) && *optr2 != ',') optr2++
		/* do nothing */ ;

	if (*optr2 != ',' && **optr != '[')
	{
		// not indexed
		if (l -> fsize == 1)
			f8 = 1;
		else if (l -> fsize == 2)
			f16 = 1;

		if (**optr == '<')
		{
			(*optr)++;
			f8 = 1;
		}
		else if (**optr == '>')
		{
			(*optr)++;
			f16 = 1;
		}
		s = lwasm_evaluate_expr(as, l, *optr, NULL);
		if (!s)
		{
			register_error(as, l, 1, "Bad expression");
			return;
		}
		if (!lwasm_expr_is_constant(s) && as -> passnum == 1)
		{
			f16 = 1;
			l -> fsize = 2;
			register_error(as, l, 2, "Incomplete reference");
		}
		v1 = lwasm_expr_get_value(s);
		lwasm_expr_stack_free(s);

		if (((v1 >> 8) & 0xff) == (as -> dpval & 0xff))
			isdp = 1;
		
		if (f8 || (!f16 && isdp))
		{
			v1 = v1 & 0xffff;
			tv = v1 - ((as -> dpval) << 8);
			if (tv < 0 || tv > 0xff)
			{
				register_error(as, l, 2, "Byte overflow");
			}
			v1 = v1 & 0xff;
			lwasm_emitop(as, l, instab[opnum].ops[0]);
			if (extra != -1)
				lwasm_emit(as, l, extra);
			lwasm_emit(as, l, v1 & 0xff);
			return;
		}
		else
		{
			// everything else is 16 bit....
			lwasm_emitop(as, l, instab[opnum].ops[2]);
			if (extra != -1)
				lwasm_emit(as, l, extra);
			lwasm_emit(as, l, v1 >> 8);
			lwasm_emit(as, l, v1 & 0xff);
			return;
		}
	}	

	lwasm_emitop(as, l, instab[opnum].ops[1]);
	if (extra != -1)
		lwasm_emit(as, l, extra);
	insn_indexed_aux(as, l, (const char **)optr, &b1, &b2, &b3);
	if (b1 != -1)
		lwasm_emit(as, l, b1);
	if (b2 != -1)
		lwasm_emit(as, l, b2);
	if (b3 != -1)
		lwasm_emit(as, l, b3);
	return;
}

// the various insn_gen? functions have an immediate mode of ? bits
OPFUNC(insn_gen0)
{
	if (**p == '#')
	{
		register_error(as, l, 1, "Immediate mode not allowed");
		return;
	}
	
	// handle non-immediate
	insn_gen_aux(as, l, p, opnum, -1);
}

OPFUNC(insn_gen8)
{
	int rval;
	
	if (**p == '#')
	{
		lwasm_emitop(as, l, instab[opnum].ops[3]);
		(*p)++;
		if (lwasm_expr_result(as, l, p, EXPR_PASS2CONST | EXPR_BYTE, &rval) < 0)
			rval = 0;
		lwasm_emit(as, l, rval & 0xff);
		return;
	}
	
	insn_gen_aux(as, l, p, opnum, -1);
}

OPFUNC(insn_gen16)
{
	lwasm_expr_stack_t *s;
	int rval;
	
	if (**p == '#')
	{
		lwasm_emitop(as, l, instab[opnum].ops[3]);
		(*p)++;
		s = lwasm_evaluate_expr(as, l, *p, NULL);
		if (!s)
		{
			register_error(as, l, 1, "Bad expression");
			rval = 0;
		}
		else
		{
			if (!lwasm_expr_is_constant(s))
				register_error(as, l, 2, "Incomplete reference");
			rval = lwasm_expr_get_value(s);
			lwasm_expr_stack_free(s);
		}
		lwasm_emit(as, l, (rval >> 8) & 0xff);
		lwasm_emit(as, l, rval & 0xff);
		return;
	}
	
	insn_gen_aux(as, l, p, opnum, -1);
}

OPFUNC(insn_gen32)
{
	lwasm_expr_stack_t *s;
	int rval;
	
	if (**p == '#')
	{
		lwasm_emitop(as, l, instab[opnum].ops[3]);
		(*p)++;
		s = lwasm_evaluate_expr(as, l, *p, NULL);
		if (!s)
		{
			register_error(as, l, 1, "Bad expression");
			rval = 0;
		}
		else
		{
			if (!lwasm_expr_is_constant(s))
				register_error(as, l, 2, "Incomplete reference");
			rval = lwasm_expr_get_value(s);
			lwasm_expr_stack_free(s);
		}
		lwasm_emit(as, l, (rval >> 24) & 0xff);
		lwasm_emit(as, l, (rval >> 16) & 0xff);
		lwasm_emit(as, l, (rval >> 8) & 0xff);
		lwasm_emit(as, l, rval & 0xff);
		return;
	}
	
	insn_gen_aux(as, l, p, opnum, -1);
}

OPFUNC(insn_imm8)
{
	lwasm_expr_stack_t *s;
	int rval;
	
	if (**p == '#')
	{
		lwasm_emitop(as, l, instab[opnum].ops[0]);
		(*p)++;
		s = lwasm_evaluate_expr(as, l, *p, NULL);
		if (!s)
		{
			register_error(as, l, 1, "Bad expression");
			rval = 0;
		}
		else
		{
			if (!lwasm_expr_is_constant(s))
				register_error(as, l, 2, "Incomplete reference");
			rval = lwasm_expr_get_value(s);
			lwasm_expr_stack_free(s);
		}
		if (rval < -128 || rval > 255)
			register_error(as, l, 2, "Byte overflow");
		lwasm_emit(as, l, rval & 0xff);
		return;
	}

	register_error(as, l, 1, "Bad operand");	
}