view lwasm/os9.c @ 238:a9a14e6b4bc8

Fixed os9 module CRC calculation
author lost
date Sat, 15 Aug 2009 05:26:02 +0000
parents a58f49a77441
children
line wrap: on
line source

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


This file implements the various pseudo operations related to OS9 target
*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lwasm.h"
#include "instab.h"
#include "expr.h"
#include "util.h"

OPFUNC(pseudo_os9)
{
	int r, rval;
	
	if (as -> outformat != OUTPUT_OS9)
	{
		register_error(as, l, 1, "os9 directive only valid for OS9 target");
		return;
	}
	
	// fetch immediate value
	r = lwasm_expr_result2(as, l, p, 0, &rval, 0);
	if (r != 0)
		rval = 0;
	if (r == 1 && as -> passnum == 2)
		register_error(as, l, 2, "Illegal external or intersegment reference");

	// SWI2; FCB ...
	lwasm_emit(as, l, 0x10);
	lwasm_emit(as, l, 0x3f);
	lwasm_emit(as, l, rval);
}

OPFUNC(pseudo_mod)
{
	int modvals[6];
	int r, v, i;
	
	if (as -> outformat != OUTPUT_OS9)
	{
		register_error(as, l, 1, "mod directive only valid for OS9 target");
		return;
	}
	
	if (as -> inmod)
	{
		register_error(as, l, 1, "Already in a module!");
		return;
	}

	// parse 6 expressions...
	for (i = 0; i < 5; i++)
	{
		r = lwasm_expr_result2(as, l, p, 0, &v, -1);
		if (r < 0)
			return;
		if (r > 0)
		{
			register_error(as, l, 2, "Illegal external or inter-segment reference (only 1 per FDB line)");
			v = 0;
		}
		else
		{
			modvals[i] = v;
		}
		if (**p != ',')
		{
			register_error(as, l, 1, "Bad operand");
			return;
		}
		(*p)++;
	}
	r = lwasm_expr_result2(as, l, p, 0, &v, -1);
	if (r < 0)
		return;
	if (r > 0)
	{
		register_error(as, l, 2, "Illegal external or inter-segment reference (only 1 per FDB line)");
		v = 0;
	}
	else
	{
		modvals[5] = v;
	}

	l -> inmod = 1;
	
	// we have an implicit ORG 0 with "mod"
	l -> codeaddr = 0;
	l -> addrset = 1;
	as -> addr = 0;

	// init crc
	as -> crc[0] = 0xff;
	as -> crc[1] = 0xff;
	as -> crc[2] = 0xff;
	as -> inmod = 1;

	// sync bytes
	lwasm_emit(as, l, 0x87);
	lwasm_emit(as, l, 0xcd);
	
	// mod length
	lwasm_emit(as, l, modvals[0] >> 8);
	lwasm_emit(as, l, modvals[0] & 0xff);
	
	// name offset
	lwasm_emit(as, l, modvals[1] >> 8);
	lwasm_emit(as, l, modvals[1] & 0xff);
	
	// type
	lwasm_emit(as, l, modvals[2]);
	
	// flags/rev
	lwasm_emit(as, l, modvals[3]);
	
	// header check
	lwasm_emit(as, l, ~(0x87 ^ 0xCD ^ (modvals[0] >> 8) ^ (modvals[0] & 0xff)
		^ (modvals[1] >> 8) ^ (modvals[1] & 0xff)
		^ modvals[2] ^ modvals[3]));

	// module type specific output
	// note that these are handled the same for all so
	// there need not be any special casing
	
	// exec offset or fmgr name offset
	lwasm_emit(as, l, modvals[4] >> 8);
	lwasm_emit(as, l, modvals[4] & 0xff);
	
	// data size or drvr name offset
	lwasm_emit(as, l, modvals[5] >> 8);
	lwasm_emit(as, l, modvals[5] & 0xff);
}

OPFUNC(pseudo_emod)
{
	unsigned char tcrc[3];
	
	if (as -> outformat != OUTPUT_OS9)
	{
		register_error(as, l, 1, "emod directive only valid for OS9 target");
		return;
	}
	
	if (!(as -> inmod))
	{
		register_error(as, l, 1, "not in a module!");
		return;
	}
	
	// don't mess with CRC!
	tcrc[0] = as -> crc[0] ^ 0xff;
	tcrc[1] = as -> crc[1] ^ 0xff;
	tcrc[2] = as -> crc[2] ^ 0xff;
	lwasm_emit(as, l, tcrc[0]);
	lwasm_emit(as, l, tcrc[1]);
	lwasm_emit(as, l, tcrc[2]);
	as -> inmod = 0;
}