OpenCores
URL https://opencores.org/ocsvn/tinyvliw8/tinyvliw8/trunk

Subversion Repositories tinyvliw8

[/] [tinyvliw8/] [trunk/] [tools/] [asm/] [src/] [asm.c] - Rev 6

Compare with Previous | Blame | View Log

/**
 * \file   asm.c
 * \author Oliver Stecklina <stecklina@ihp-microelectronics.com>
 * \date   12.12.2015
 * 
 * \brief  main program file of the tinyVLIW8 assembler
 *
 * <p>
 *    Copyright (C) 2015 IHP GmbH, Frankfurt (Oder), Germany
 *
 * This code is free software. It is licensed under the EUPL, Version 1.1
 * or - as soon they will be approved by the European Commission - subsequent
 * versions of the EUPL (the "License").
 * You may redistribute this code and/or modify it under the terms of this
 * License.
 * You may not use this work except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 * http://joinup.ec.europa.eu/software/page/eupl/licence-eupl
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * </p>
 */
 
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
 
#include "instr.h"
#include "list.h"
 
static unsigned int _linenum;
static unsigned int _instr_addr;
 
extern FILE *yyin;
extern int yyparse();
 
static list_t _label = {&_label, &_label};
static list_t _instr = {&_instr, &_instr};
 
void instr_irq(unsigned char num)
{
	_instr_addr = 0x07fc + num;
}
 
void instr_add(const instr_t *instr, const unsigned char num)
{
	instr_vliw_t *ninstr;
 
	ninstr = malloc(sizeof(instr_vliw_t));
	if (NULL != ninstr) {
		unsigned int i;
 
		ninstr->addr = _instr_addr;
 
		ninstr->num = num;
		for (i = 0; i < num; i++) {
			memcpy((char *) &ninstr->instr[i], (char *) &instr[i], sizeof(instr_t));
 
			/* copy source list */
			ninstr->instr[i].source.next->prev = &ninstr->instr[i].source;
			ninstr->instr[i].source.prev->next = &ninstr->instr[i].source;
		}
 
		list_add_last(&_instr, &ninstr->list);
	}
 
	_instr_addr++;
}
 
void instr_label(const char *name)
{
	instr_label_t *n;
 
	n = malloc(sizeof(instr_label_t) + strlen(name) + 1);
	if (n) {
		LIST_INIT(&n->list);
		n->offset = _instr_addr;
 
		snprintf(n->name, 64, "%s", name);
 
		list_add(&_label, &n->list);
	}
 
	return;
}
 
void instr_add_source(list_t *head, instr_operand_type_t type, const void *data)
{
	instr_operand_t *op;
 
	op = (instr_operand_t *) malloc(sizeof(instr_operand_t));
	if (NULL != op) {
		op->type = type;
		switch (type) {
		  case instr_operand_type_reg:
		  case instr_operand_type_const:
			op->value = *((int *) data);
			break;
		  case instr_operand_type_label:
		  	op->label = malloc(strlen((char *) data) + 1);
			if (NULL != op->label) {
				sprintf(op->label, "%s", (char *) data);
			}
 
			break;
		}
 
		list_add(head, &op->list);
	}
}
 
void instr_source_flag(list_t *source, unsigned char flag)
{
	if (source->prev != source) {
		instr_operand_t *op = LIST_ENTRY(source->prev, instr_operand_t, list);
 
		op->flags |= flag;
	}
}
 
void instr_add_dest(instr_operand_t *op, const unsigned char num)
{
	op->type = instr_operand_type_reg;
	op->value = num;
}
 
static unsigned int _get_symbol(const char *name)
{
	return 0x00;
}
 
static unsigned int _get_label(const char *name)
{
	if (NULL != name) {
		list_t *h;
 
		for (h = _label.next; h != &_label; h = h->next) {
			instr_label_t *l;
 
			l = LIST_ENTRY(h, instr_label_t, list);
 
			if (0 == strcmp(l->name, name))
				return l->offset;
		}
	}
 
	return 0x00;
}
 
static void _write_jmp(unsigned char *iw, instr_opcode_t opcode, const instr_operand_t *op)
{
	unsigned int addr;
 
	iw[0] = (0x07 << 5);
 
	switch (opcode) {
	case instr_opcode_jz:
		iw[0] |= (0x01 << 3);
		break;
	case instr_opcode_jc:
		iw[0] |= (0x02 << 3);
		break;
	case instr_opcode_jnz:
		iw[0] |= (0x03 << 3);
		break;
	default:
		/* nothing to do */;
	}
 
	addr = 0;
	if (instr_operand_type_const == op->type) {
		addr = op->value;
	} else if (instr_operand_type_label == op->type) {
		addr = _get_label(op->label);
	}
 
	iw[0] |= ((addr & 0x07ff) >> 8);
	iw[1] = addr & 0x00ff;
}
 
static void _write_ldst(unsigned char *iw, instr_opcode_t opcode, const instr_operand_t *dst, const instr_operand_t *src)
{
	switch (opcode) {
	case instr_opcode_ldi:
		iw[0] = (0x01 << 4);
		break;
	case instr_opcode_st:
		iw[0] = (0x02 << 4);
		break;
	case instr_opcode_sti:
		iw[0] = (0x03 << 4);
		break;
	default:
		iw[0] = 0x00;
		break;
	}
 
	if (instr_operand_type_reg == src->type) {
		iw[0] |= (0x01 << 3);
	}
 
	iw[0] |= dst->value & 0x07;
 
	switch (src->type) {
	case instr_operand_type_reg:
		iw[0] |= (0x01 << 3);
		iw[1] = src->value & 0x07;
 
		break;
	case instr_operand_type_const:
		iw[1] = src->value;
		break;
	case instr_operand_type_label:
		iw[1] = _get_symbol(src->label);
		break;
	}
}
 
static void _write_sh(unsigned char *iw, instr_opcode_t opcode, const instr_operand_t *dst, const instr_operand_t *src)
{
	iw[0] = (0x03 << 5);
	iw[1] = 0x00;
 
	switch (opcode) {
	case instr_opcode_rlc:
		iw[1] |= (0x01 << 3);
		break;
	case instr_opcode_rrc:
		iw[1] |= (0x01 << 3);
	case instr_opcode_rra:
		iw[0] |= (0x01 << 3);
		break;
	default:
		/* nothing to do */;
	}
 
	iw[0] |= dst->value & 0x07;
	iw[1] |= src->value & 0x07;
}
 
#define _SRC_FIRST(src)  (src)->next != src ? LIST_ENTRY((src)->next, instr_operand_t, list) : NULL
 
static void _write_src(unsigned char *iw, const instr_operand_t *dst, const list_t *src_l)
{
	instr_operand_t *src = _SRC_FIRST(src_l);
 
	if (instr_operand_type_const == src->type) {
		iw[0] |= (0x01 << 3);
		iw[1] = src->value & 0x00ff;
	} else if (instr_operand_type_reg == src->type) {
		iw[1] = src->value & 0x07;
		if (0 != (src->flags & INSTR_FLAG_TILDE))
			iw[1] |= (0x01 << 3);
 
		if (src->list.next != src_l) {
			src = LIST_ENTRY(src->list.next, instr_operand_t, list);
 
			iw[1] |= (src->value & 0x07) << 4;
			if (0 != (src->flags & INSTR_FLAG_TILDE))
				iw[1] |= (0x01 << 7);
		} else {
			iw[1] |= (dst->value & 0x07) << 4;
		}
	}
}
 
static void _write_add(unsigned char *iw, unsigned char carry, const instr_operand_t *dst, const list_t *src_l)
{
	iw[0] = (0x02 << 5);
	if (0 != carry)
		iw[0] |= (0x02 << 3);
 
	iw[0] |= dst->value & 0x07;
 
	_write_src(iw, dst, src_l);
}
 
static void _write_mov(unsigned char *iw, const instr_operand_t *dst, const instr_operand_t *src)
{
	iw[0] = (0x03 << 5);
	iw[0] |= (0x02 << 3);
 
	iw[0] |= dst->value & 0x07;
 
	if (instr_operand_type_const == src->type) {
		iw[0] |= (0x01 << 3);
		iw[1] = src->value & 0x00ff;
	} else if (instr_operand_type_reg == src->type) {
		iw[1] = src->value & 0x07;
		if (0 != (src->flags & INSTR_FLAG_TILDE))
			iw[1] |= (0x01 << 3);
	}
}
 
static void _write_logic(unsigned char *iw, instr_opcode_t opcode, const instr_operand_t *dst, const list_t *src_l)
{
	iw[0] = 0x00;
 
	switch (opcode) {
	case instr_opcode_nand:
		iw[0] |= (0x02 << 3);
	case instr_opcode_and:
		iw[0] |= (0x04 << 5);
		break;
	case instr_opcode_nor:
		iw[0] |= (0x02 << 3);
	case instr_opcode_or:
		iw[0] |= (0x05 << 5);
		break;
	case instr_opcode_xnor:
		iw[0] |= (0x02 << 3);
	case instr_opcode_xor:
		iw[0] |= (0x06 << 5);
		break;
	default:
		/* nothing to do */;
	}
 
	iw[0] |= dst->value & 0x07;
 
	_write_src(iw, dst, src_l);
}
 
static void _gen_code(unsigned char *iw, const instr_t *i)
{
	switch (i->opcode) {
	case instr_opcode_ld:
	case instr_opcode_ldi:
	case instr_opcode_st:
	case instr_opcode_sti:
		_write_ldst(iw, i->opcode, &i->dest, _SRC_FIRST(&i->source));
		break;
	case instr_opcode_add:
	case instr_opcode_addi:
		_write_add(iw, i->opcode == instr_opcode_addi ? 1 : 0, &i->dest, &i->source);
		break;
	case instr_opcode_rla:
	case instr_opcode_rlc:
	case instr_opcode_rra:
	case instr_opcode_rrc:
		_write_sh(iw, i->opcode, &i->dest, _SRC_FIRST(&i->source));
		break;
	case instr_opcode_mov:
		_write_mov(iw, &i->dest, _SRC_FIRST(&i->source));
		break;
	case instr_opcode_and:
	case instr_opcode_nand:
	case instr_opcode_or:
	case instr_opcode_nor:
	case instr_opcode_xor:
	case instr_opcode_xnor:
		_write_logic(iw, i->opcode, &i->dest, &i->source);
		break;
	case instr_opcode_jmp:
	case instr_opcode_jc:
	case instr_opcode_jz:
	case instr_opcode_jnz:
		_write_jmp(iw, i->opcode, _SRC_FIRST(&i->source));
		break;
	}
}
 
void instr_out(const char *filename)
{
	list_t *head;
	int f;
 
	f = open(filename, O_WRONLY | O_CREAT | O_TRUNC
#ifdef __MINGW32__
			| O_BINARY,  S_IRUSR | S_IWUSR
#else
			, S_IRUSR | S_IWUSR | S_IRGRP
#endif
			);
 
	if (0 <= f) {
		unsigned int addr;
 
		addr = 0;
		for (head = _instr.next; head != &_instr; head = head->next) {
			instr_vliw_t *i = LIST_ENTRY(head, instr_vliw_t, list);
			unsigned char iw[4];
			int err;
 
			memset(&iw[0], 0x00, sizeof(iw));
 
			while (addr < 0x7ff && addr < i->addr) {
				err = write(f, &iw[0], 4);
				if (err != 4) {
					fprintf(stderr, "write failed\n");
					break;
				}
 
				addr++;
			}
 
			_gen_code(&iw[0], &i->instr[0]);
			_gen_code(&iw[2], &i->instr[1 < i->num ? 1 : 0]);
 
			err = write(f, &iw[0], 4);
			if (err != 4) {
				fprintf(stderr, "write failed\n");
				break;
			}
 
			addr++;
		}
 
		close(f);
	} else
		fprintf(stderr, "unable to open output\n");
}
 
int execute(int arg)
{
	return arg;
}
 
void nextline()
{
	_linenum++;
}
 
int get_linenum()
{
	return _linenum;
}
 
int main(int argc, char *argv[])
{
	_linenum = 0;
	_instr_addr = 0;
 
	if (1 < argc) {
		fprintf(stderr, "parse file %s\n", argv[1]);
		yyin = fopen(argv[1], "r");
	} else
		yyin = stdin;
 
	yyparse();
 
	instr_out("out.a");
 
	return 0;
}
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.