view src/insn_bitbit.c @ 101:f59c0916753d

Fixed relative branches and PCR addressing to handle constant intra-section references properly
author lost
date Fri, 23 Jan 2009 03:36:27 +0000
parents 8929e1ee99cf
children
line wrap: on
line source

/*
insn_bitbit.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/>.
*/

/*
for handling inherent mode instructions
*/

#define __insn_bitbit_c_seen__

#include <stdlib.h>

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

// these instructions cannot tolerate external references
OPFUNC(insn_bitbit)
{
	int r;
	lwasm_expr_stack_t *s;
	int v1;
	int tv;

	lwasm_emitop(as, l, instab[opnum].ops[0]);
	
	r = toupper(*(*p)++);
	if (r == 'A')
		r = 1;
	else if (r == 'B')
		r = 2;
	else if (r == 'C' && toupper(**p) == 'C')
	{
		r = 0;
		(*p)++;
	}
	else
	{
		register_error(as, l, 1, "Bad register");
		return;
	}
	if (*(*p)++ != ',')
	{
		register_error(as, l, 1, "Bad operand");
		return;
	}
	s = lwasm_evaluate_expr(as, l, *p, NULL, 0);
	if (!s)
	{
		register_error(as, l, 1, "Bad operand");
		return;
	}
	if (!lwasm_expr_is_constant(s))
	{
		register_error(as, l, 2, "Incomplete reference");
	}
	v1 = lwasm_expr_get_value(s);
	lwasm_expr_stack_free(s);
	if (v1 < 0 || v1 > 7)
	{
		register_error(as, l, 2, "Invalid bit number");
		v1 = 0;
	}
	if (*(*p)++ != ',')
	{
		register_error(as, l, 1, "Bad operand");
		return;
	}
	r = (r << 6) | (v1 << 3);

	s = lwasm_evaluate_expr(as, l, *p, NULL, 0);
	if (!s)
	{
		register_error(as, l, 1, "Bad operand");
		return;
	}
	if (!lwasm_expr_is_constant(s))
	{
		register_error(as, l, 1, "Incomplete reference");
	}
	v1 = lwasm_expr_get_value(s);
	lwasm_expr_stack_free(s);
	if (v1 < 0 || v1 > 7)
	{
		register_error(as, l, 2, "Invalid bit number");
		v1 = 0;
	}
	if (*(*p)++ != ',')
	{
		register_error(as, l, 1, "Bad operand");
		return;
	}
	r |= v1;
	
	lwasm_emit(as, l, r);
			
	// ignore base page address modifier
	if (**p == '<')
		(*p)++;
			
	s = lwasm_evaluate_expr(as, l, *p, NULL, 0);
	if (!s)
	{
		register_error(as, l, 1, "Bad operand");
		return;
	}
	if (!lwasm_expr_is_constant(s))
	{
		register_error(as, l, 1, "Incomplete reference");
	}
	v1 = lwasm_expr_get_value(s);
	lwasm_expr_stack_free(s);
	v1 &= 0xFFFF;

	tv = v1 - ((as -> dpval) << 8);
	if (tv > 0xFF || tv < 0)
	{
		register_error(as, l, 2, "Byte overflow");
	}
	lwasm_emit(as, l, tv & 0xff);
}