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

Subversion Repositories tinyvliw8

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

Compare with Previous | Blame | View Log

/**
 * \file   main.c
 * \author Oliver Stecklina <stecklina@ihp-microelectronics.com>
 * \date   20.10.2013
 * 
 * \brief  IHPvliw8 assembler main program file.
 *
 * <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 <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
 
#include "config.h"
 
#define _VARNAME_LEN   8
#define _LABEL_LEN     8
 
typedef struct _label_s {
	char             name[_LABEL_LEN];
	unsigned short   addr;
 
	struct _label_s *next;
} _label_t;
 
typedef struct _var_s {
	char           name[_VARNAME_LEN];
	unsigned char  value;
	unsigned char  addr;
 
	struct _var_s *next;
} _var_t;
 
typedef enum _section_e {
	_section_data = 0,
	_section_code
} _section_t;
 
static char         *_infile     = NULL;
static char         *_outfile    = "out";
 
static _var_t       *_var   = NULL;
static _label_t     *_label = NULL;
 
static unsigned short _code_addr = 0x0000;
 
static int _parse_args(int argc, char *argv[])
{
	int err, i;
 
	err = 0;
	for (i = 1; 0 == err && i < argc; i++) {
		if ('-' != *argv[i]) {
			if ((i + 1) == argc) {
				_infile = argv[i];
				break;
			}
 
			fprintf(stderr, "\tERROR! bad option <%s>\n", argv[i]);
			err = -EINVAL;
 
			break;
		}
 
		switch (*(argv[i] + 1)) {
		case 'o':
			if ((i + 1) < argc) {
				i++;
				_outfile = argv[i];
 
				break;
			}
 
			fprintf(stderr, "\tERROR! option <%s> requires an argument\n",
			        argv[i]);
			err = -EINVAL;
 
			break;
		case 'h':
			printf("%s [option] <input>\n", argv[0]);
			printf("\t-o <file>    output filename (default: out.bin)\n");
			printf("\t-h           useful help\n");
 
			exit(0);
		}
	}
 
	if (0 == err && NULL == _infile) {
		fprintf(stderr, "\tERROR! no input file given\n");
		err = -EINVAL;
	}
 
	return err;
}
 
static int _shrink_line(char *line, unsigned int size)
{
	unsigned int s, i;
	int len;
 
	len = 0;
	s = 0;
 
	for (i = 0; i < size; i++) {
		int out;
 
		out = 0;
 
		switch (line[i]) {
		case '\0':
			out = 1;
			break;
		case '/':                 /* comment */
			out = 1;
 
			if (0 == len)
				break;
 
			line[len] = '\n';
			len++;
			line[len] = '\0';
 
			break;
		case ';':                 /* line finished */
			line[len] = '\n';
			len++;
 
			line[len] = '\0';
 
			out = 1;
			break;
		case '|':                /* instruction delimiter - jmp #0x08 | ld R0, #0x01 */
		case ',':                /* operand delimiter     - add r1, r3 */
			switch (s) {
			case 1:              /* leading blank, kick it */
				line[len - 1] = line[i];
				break;
			case 0:
				line[len] = line[i];
				len++;
 
				break;
			}
 
			s = 2;
 
			break;
		case ' ':
		case '\t':
			if (0 < i) {
				if (0 == s) {
					line[len] = ' ';
					len++;
				}
			}
 
			if (0 == s)
				s = 1;
 
			break;
		case '\r':
		case '\n':
			break;
		default:
			if (len != (int) i)
				line[len] = line[i];
 
			len++;
			s = 0;
		}
 
		if (0 != out)
			break;
	}
 
	return len;
}
 
typedef struct _token_s {
	struct {
		unsigned char num;
		char **data;
	} inst[2];
} _token_t;
 
static _token_t *_tokenize(char *line)
{
	_token_t *t;
 
	t = (_token_t *) malloc(sizeof(_token_t));
	if (t) {
		unsigned char inst;
 
		memset((char *) t, 0x00, sizeof(_token_t));
 
		inst = 0;
		t->inst[inst].num = 1;
 
		t->inst[inst].data = (char **) malloc(sizeof(char*) * (t->inst[inst].num + 1));
		if (NULL != t->inst[inst].data) {
			unsigned char state;
			int i;
 
			t->inst[inst].data[0] = line;
			t->inst[inst].data[1] = NULL;
 
			i = 0;
			state = 0;
			while ('\0' != line[i]) {
				unsigned char add;
 
				add = 0;
				switch (line[i]) {
				case ' ':
					if (0 == state) {
						add = 1;
						state = 1;
				}
 
					break;
				case ',':
					add = 1;
					break;
				case '|':
					inst++;
 
					add = 1;
					state = 0;
 
					break;
				}
 
				if (0 != add && '\0' != line[i + 1]) {
					line[i] = '\0';
					t->inst[inst].data = (char **) realloc(t->inst[inst].data, sizeof(char*) * (t->inst[inst].num + 2));
					if (NULL != t->inst[inst].data) {
						i++;
 
						t->inst[inst].data[t->inst[inst].num] = &line[i];
						t->inst[inst].data[t->inst[inst].num + 1] = NULL;
 
						t->inst[inst].num++;
					} else {
						/* error, no more memory, cleaning up */
						if (0 < inst)
							free(t->inst[0].data);
 
						free(t);
						t = NULL;
 
						break;
					}
				}
 
				i++;
			}
		}
	}
 
	return t;
}
 
static int _add_data_item(char *line)
{
	_token_t *tok;
	int err;
 
	tok = _tokenize(line);
	if (NULL != tok) {
		if (NULL != tok->inst[0].data[0] && NULL != tok->inst[0].data[1]) {
			int namelen;
			unsigned char addr;
			long value;
 
			namelen = strlen(tok->inst[0].data[0]);
			if (_VARNAME_LEN < namelen) {
				err = -ENAMETOOLONG;
				goto out;
			}
 
			addr = 0x00;
			if (NULL != _var) {
				if (CONFIG_DATA_ADDR_MAX == _var->addr) {
					err = -ENOSPC;
					goto out;
				}
 
		   		addr = _var->addr + 1;
			}
 
			value = strtol(tok->inst[0].data[1], NULL, 0);
			if (0 <= value && 256 > value) {
				_var_t *nv;
 
				nv = (_var_t *) malloc(sizeof(_var_t));
				if (NULL != nv) {
					memset((char *) nv, 0, sizeof(_var_t));
 
					memcpy(&nv->name[0], tok->inst[0].data[0], namelen);
 
					nv->addr = addr;
					nv->value = 0xff & value;
 
					nv->next = _var;
					_var = nv;
 
					err = 0;
				}
			} else
				err = -ERANGE;
		} else
			err = -EINVAL;
 
out:
		if (NULL != tok->inst[0].data)
			free(tok->inst[0].data);
		if (NULL != tok->inst[1].data)
			free(tok->inst[1].data);
 
		free(tok);
	} else
		err = -ENOMEM;
 
	return err;
}
 
typedef enum _opcode_e {
	_opcode_ld = 0,
	_opcode_ldi,
	_opcode_st,
	_opcode_sti,
	_opcode_jmp,
	_opcode_jc,
	_opcode_jz,
	_opcode_jnz,
	_opcode_add,
	_opcode_addi,
	_opcode_shl,
	_opcode_shli,
	_opcode_shr,
	_opcode_shri,
	_opcode_or,
	_opcode_nor,
	_opcode_and,
	_opcode_nand,
	_opcode_xor,
	_opcode_xnor,
	_opcode_unknown
} _opcode_t;
 
static _opcode_t _opcode_get(char *token)
{
	unsigned int i;
 
	for (i = 0; '\0' != token[i]; i++)
		token[i] = tolower(token[i]);
 
	if (0 == strcmp("ldi", token))
		return _opcode_ldi;
	if (0 == strcmp("ld", token))
		return _opcode_ld;
	if (0 == strcmp("sti", token))
		return _opcode_sti;
	if (0 == strcmp("st", token))
		return _opcode_st;
 
	if (0 == strcmp("jmp", token))
		return _opcode_jmp;
	if (0 == strcmp("jc", token))
		return _opcode_jc;
	if (0 == strcmp("jz", token))
		return _opcode_jz;
	if (0 == strcmp("jnz", token))
		return _opcode_jnz;
 
	if (0 == strcmp("addi", token))
		return _opcode_addi;
	if (0 == strcmp("add", token))
		return _opcode_add;
	if (0 == strcmp("shli", token))
		return _opcode_shli;
	if (0 == strcmp("shl", token))
		return _opcode_shl;
	if (0 == strcmp("shri", token))
		return _opcode_shri;
	if (0 == strcmp("shr", token))
		return _opcode_shr;
	if (0 == strcmp("nor", token))
		return _opcode_nor;
	if (0 == strcmp("or", token))
		return _opcode_or;
	if (0 == strcmp("nand", token))
		return _opcode_nand;
	if (0 == strcmp("and", token))
		return _opcode_and;
	if (0 == strcmp("xnor", token))
		return _opcode_xnor;
	if (0 == strcmp("xor", token))
		return _opcode_xor;
 
	return _opcode_unknown;
}
 
static unsigned char _get_reg(char *token)
{
	if ('r' == tolower(*token))
		return (*(token + 1) - '0');
 
	return 0xff;
}
 
typedef enum _ldst_vtype_e {
	_ldst_vtype_addr = 0,
	_ldst_vtype_reg
} _ldst_vtype_t;
 
typedef struct _ldst_op_s {
	_opcode_t       opcode;
	unsigned char   reg;
 
	_ldst_vtype_t   vtype;
	union {
		unsigned char reg;
		unsigned char addr;
		unsigned char raw;
	} vt;
} _ldst_op_t;
 
typedef struct _alu_op_s {
	_opcode_t       opcode;
	unsigned char   reg;
 
	struct {
		unsigned char prefix;
		unsigned char type;
		union {
			unsigned char reg;
			unsigned char value;
		} data;
	} op[2];
} _alu_op_t;
 
typedef struct _jmp_op_s {
	_opcode_t       opcode;
	unsigned short  addr;
 
	_label_t       *label;
} _jmp_op_t;
 
typedef enum _op_type_e {
	_op_type_ldst = 0,
	_op_type_alu,
	_op_type_jmp
} _op_type_t;
 
typedef struct _op_s {
	unsigned short addr;
 
	_op_type_t     opt[2];
	union {
		_ldst_op_t *ldst;
		_alu_op_t  *alu;
		_jmp_op_t  *jmp;
		void       *raw;
	} op[2];
 
	struct _op_s  *next;
} _op_t;
 
static _op_t *_op = NULL;
 
static _label_t *_label_get_by_name(const char *name)
{
	_label_t *v;
 
	for (v = _label; v != NULL; v = v->next) {
		if (0 == strcmp(v->name, name))
			break;
	}
 
	return v;
}
 
static int _add_label(char *label, unsigned short addr)
{
	int err;
 
	err = strlen(label);
	if (_LABEL_LEN > err) {
		_label_t *l;
 
		l = _label_get_by_name(label);
		if (NULL != l) {
			if (0xffff != l->addr) {
				fprintf(stderr, "label %s defined twice\n", label);
				return -EBUSY;
			}
 
			l->addr = addr;
			return 0;
		}
 
		l = (_label_t *) malloc(sizeof(_label_t));
		if (NULL != l) {
			memset((char *) l, 0x00, sizeof(_label_t));
 
			memcpy(&l->name[0], label, err);
			l->addr = addr;
 
			l->next = _label;
			_label = l;
 
			err = 0;
		} else
			err = -ENOMEM;
	} else
		err = -ENAMETOOLONG;
 
	return err;
}
 
static _var_t *_get_var_by_name(const char *name)
{
	_var_t *v;
 
	for (v = _var; v != NULL; v = v->next) {
		if (0 == strcmp(v->name, name))
			break;
	}
 
	return v;
}
 
static _jmp_op_t *_jmp_gen_item(_opcode_t opcode, char *value)
{
	_jmp_op_t *op;
	int err;
 
	if (NULL == value)
		return NULL;
 
	op = (_jmp_op_t *) malloc(sizeof(_jmp_op_t));
	if (NULL == op)
		return NULL;
 
	memset((char *) op, 0x00, sizeof(_jmp_op_t));
 
	op->opcode = opcode;
	err = 0;
 
	switch (*value) {
	_label_t *label;
	long v;
 
	case '$':
		label = _label_get_by_name(&value[1]);
		if (NULL != label) {
			op->addr = label->addr;
			op->label = label;
		} else {
			op->addr = 0xffff;
 
			err = _add_label(&value[1], 0xffff);
			if (0 == err) {
				op->label = _label_get_by_name(&value[1]);
				if (NULL == op->label) {
					fprintf(stderr, "error while adding virtual label <%s>\n",
					        &value[1]);
				}
			} else
				fprintf(stderr, "add virtual label <%s> failed, error %d\n",
				        &value[1], err);
		}
 
		break;
	case '-':
		v = strtol(value + 1, NULL, 0);
		if (0 > v || CONFIG_CODE_SIZE <= v) {
			err = -ERANGE;
			break;
		}
 
		if (v > _code_addr) {
			err = -EINVAL;
			break;
		}
 
		op->addr = _code_addr - v;
		break;
	case '+':
		v = strtol(value + 1, NULL, 0);
		if (0 > v || CONFIG_CODE_SIZE <= v) {
			err = -ERANGE;
			break;
		}
 
		if (CONFIG_CODE_SIZE <= (v + _code_addr)) {
			err = -EINVAL;
			break;
		}
 
		op->addr = _code_addr + v;
		break;
	case '#':
		v = strtol(value + 1, NULL, 0);
		if (0 <= v && CONFIG_CODE_SIZE > v) {
			op->addr = v;
		} else
			err = -ERANGE;
 
		break;
	default:
		fprintf(stderr, "syntax error at label\n");
		err = -EINVAL;
	}
 
	if (0 != err) {
		free(op);
		op = NULL;
	}
 
	return op;
}
 
static _ldst_op_t *_ldst_gen_item(_opcode_t opcode, char *reg_str, char *value)
{
	unsigned char reg;
	_ldst_op_t *op;
	int err;
 
	if (NULL == reg_str || NULL == value)
		return NULL;
 
	reg = _get_reg(reg_str);
	if (CONFIG_MAX_REG_NUM < reg)
		return NULL;
 
	op = (_ldst_op_t *) malloc(sizeof(_ldst_op_t));
	if (NULL == op)
		return NULL;
 
	memset((char *) op, 0x00, sizeof(_ldst_op_t));
 
	op->opcode = opcode;
	op->reg = reg;
 
	err = 0;
	switch (*value) {
	_var_t *var;
	long v;
 
	case '@':
		op->vtype = _ldst_vtype_reg;
 
		reg = _get_reg(&value[1]);
		if (CONFIG_MAX_REG_NUM >= reg) {
			op->vt.reg = reg;
		} else
			err = -EINVAL;
 
		break;
	case '%':
		op->vtype = _ldst_vtype_addr;
 
		var = _get_var_by_name(&value[1]);
		if (var) {
			op->vt.addr = var->addr;
		} else {
			fprintf(stderr, "undefined variable %s\n", &value[1]);
			err = -EINVAL;
		}
 
		break;
	case '#':
		op->vtype = _ldst_vtype_addr;
 
		v = strtol(value + 1, NULL, 0);
		if (0 <= v && 0xff >= v) {
			op->vt.addr = 0xff & v;
		} else
			err = -ERANGE;
 
		break;
	default:
		err = -EINVAL;
	}
 
	if (0 != err) {
		free(op);
		op = NULL;
	}
 
	return op;
}
 
static _alu_op_t *_alu_gen_item(_opcode_t opcode, char *reg_str, char *op1, char *op2)
{
	_alu_op_t *op;
	unsigned char i, reg;
	char *operand[] = {op1, op2};
	int err;
 
	if (NULL == reg_str || NULL == op1) {
		fprintf(stderr, "parse error \n");
		return NULL;
	}
 
	reg = _get_reg(reg_str);
	if (CONFIG_MAX_REG_NUM < reg) {
		fprintf(stderr, "invalid destination register %s\n", reg_str);
		return NULL;
	}
 
	op = (_alu_op_t *) malloc(sizeof(_alu_op_t));
	if (NULL == op)
		return NULL;
 
	memset((char *) op, 0x00, sizeof(_alu_op_t));
 
	op->opcode = opcode;
	op->reg = reg;
 
	for (i = 0; i< 2; i++) {
		if (NULL == operand[i]) {
			if (0 == i) {
				err = -EINVAL;
				break;
			}
 
			/* copy operand 0 to operand 1 */
			memcpy((char *) &op->op[1], (char *) &op->op[0], sizeof(op->op[0]));
 
			/* set operand 0 to destination register */
			op->op[0].prefix = 0;
			op->op[0].type = 0;
 
			op->op[0].data.reg = op->reg;
 
			break;
		}
 
		switch (*operand[i]) {
		long v;
 
		case '-':     /* two's complement */
		case '~':     /* invert */
			op->op[i].prefix = 1;
			op->op[i].type = 0;
 
			reg = _get_reg(operand[i] + 1);
			if (CONFIG_MAX_REG_NUM >= reg) {
				op->op[i].data.reg = reg;
			} else
				err = -EINVAL;
 
			break;
		case '#':     /* constant value */
			op->op[i].prefix = 0;
			op->op[i].type = 1;
 
			v = strtol(operand[i] + 1, NULL, 0);
			if (0 <= v && 0xff >= v) {
				op->op[i].data.value = 0xff & v;
			} else
				err = -ERANGE;
 
			break;
		default:      /* register */
			op->op[i].prefix = 0;
			op->op[i].type = 0;
 
			reg = _get_reg(operand[i]);
			if (CONFIG_MAX_REG_NUM >= reg) {
				op->op[i].data.reg = reg;
			} else
				err = -EINVAL;
 
			break;
		}
	}
 
	if (0 != err) {
		fprintf(stderr, "error %d at 0x%02x %s %s %s failed\n",
		        err, opcode, reg_str, op1, op2);
 
		free(op);
		op = NULL;
	}
 
	return op;
}
 
static int _add_code_item(char *line)
{
	_token_t *tok;
	int err;
 
	for (err = 0; err < (int) strlen(line); err++)
		if ('\n' == line[err] || '\r' == line[err]) {
			line[err] = '\0';
			break;
		}
 
	if (0 < err && ':' == line[err - 1]) {
		line[err - 1] = '\0';
 
		return _add_label(line, (NULL == _op) ? 0x00 : _op->addr + 1);
	}
 
	tok = _tokenize(line);
	if (NULL != tok) {
		unsigned char inst;
		_opcode_t opcode;
		unsigned short addr;
		_op_t *op;
 
		if (NULL == tok->inst[0].data[0]) {
			err = -EINVAL;
			goto out;
		}
 
		if (CONFIG_CODE_ADDR_MAX < _code_addr) {
			err = -ENOSPC;
			goto out;
		}
 
		addr = _code_addr;
		_code_addr += 1;
 
		op = malloc(sizeof(_op_t));
		if (NULL == op) {
			err = -ENOMEM;
			goto out;
		}
 
		err = 0;
		for (inst = 0; 0 == err && inst < 2; inst++) {
			if (0 == tok->inst[inst].num)
				continue;
 
			opcode = _opcode_get(tok->inst[inst].data[0]);
 
			switch (opcode) {
			case _opcode_jmp:
			case _opcode_jz:
			case _opcode_jc:
			case _opcode_jnz:
				op->op[inst].jmp = _jmp_gen_item(opcode, tok->inst[inst].data[1]);
				op->opt[inst] = _op_type_jmp;
 
				break;
			case _opcode_ld:
			case _opcode_ldi:
			case _opcode_st:
			case _opcode_sti:
				op->op[inst].ldst = _ldst_gen_item(opcode, tok->inst[inst].data[1], tok->inst[inst].data[2]);
				op->opt[inst] = _op_type_ldst;
 
				break;
			case _opcode_add:
			case _opcode_addi:
			case _opcode_shl:
			case _opcode_shli:
			case _opcode_shr:
			case _opcode_shri:
			case _opcode_or:
			case _opcode_nor:
			case _opcode_and:
			case _opcode_nand:
			case _opcode_xor:
			case _opcode_xnor:
				if (4 == tok->inst[inst].num)
					op->op[inst].alu = _alu_gen_item(opcode, tok->inst[inst].data[1], tok->inst[inst].data[2], tok->inst[inst].data[3]);
				else
					op->op[inst].alu = _alu_gen_item(opcode, tok->inst[inst].data[1], tok->inst[inst].data[2], NULL);
 
				op->opt[inst] = _op_type_alu;
 
				break;
			default:
				op->op[inst].raw = NULL;
				err = -EINVAL;
			}
 
			if (NULL == op->op[inst].raw) {
				err = -EINVAL;
				break;
			}
 
			op->addr = addr;
		}
 
		if (NULL == op->op[1].raw) {
			op->op[1].raw = op->op[0].raw;
			op->opt[1] = op->opt[0];
		}
 
		if (0 == err) {
			op->next = _op;
			_op = op;
		} else
			free(op);
 
out:
		if (NULL != tok->inst[0].data)
			free(tok->inst[0].data);
		if (NULL != tok->inst[1].data)
			free(tok->inst[1].data);
 
		free(tok);
	} else
		err = -ENOMEM;
 
	return err;
}
 
static int _parse_line(char *line, _section_t *sec_ptr)
{
	int err;
 
	if ('.' == *line) {
		/* section definition */
		if ('d' == *(line + 1)) {
			*sec_ptr = _section_data;
			return 0;
		}
 
		if ('c' == *(line + 1)) {
			*sec_ptr = _section_code;
			return 0;
		}
 
		if ('i' == *(line + 1)) {
			unsigned char inum;
 
			inum = *(line + 4) - '0';
			if (CONFIG_IRQ_NUM >= inum) {
				_code_addr = CONFIG_IRQ_START + inum;
				return 0;
			} else
				return -EINVAL;
		}
 
		return -EINVAL;
	}
 
	err = 0;
	switch (*sec_ptr) {
	case _section_data:
		err = _add_data_item(line);
		break;
	case _section_code:
		err = _add_code_item(line);
		break;
	}
 
	return err;
}
 
static int _jmp_dump(unsigned char *dst, _jmp_op_t *op)
{
	int err;
 
	err = 0;
 
	switch (op->opcode) {
	case _opcode_jmp:
		dst[0] = 0xe0;
		break;
	case _opcode_jz:
		dst[0] = 0xe8;
		break;
	case _opcode_jc:
		dst[0] = 0xf0;
		break;
	case _opcode_jnz:
		dst[0] = 0xf8;
		break;
	default:
		err = -EINVAL;
	}
 
	if (0xffff == op->addr) {
		if (NULL == op->label) {
			fprintf(stderr, "error, unresolved label at %p\n", op);
			return -ENOENT;
		}
 
		op->addr = op->label->addr;
	}
 
	dst[0] |= (op->addr >> 8) & 0x07;
	dst[1] = op->addr & 0x00ff;
 
	return err;
}
 
static int _ldst_dump(unsigned char *dst, _ldst_op_t *op)
{
	int err;
 
	err = 0;
	switch (op->opcode) {
	case _opcode_ld:
		dst[0] = 0x00;
		break;
	case _opcode_ldi:
		dst[0] = 0x10;
		break;
	case _opcode_st:
		dst[0] = 0x20;
		break;
	case _opcode_sti:
		dst[0] = 0x30;
		break;
	default:
		err = -EINVAL;
	}
 
	if (_ldst_vtype_reg == op->vtype)
		dst[0] |= 0x08;
 
	dst[0] |= op->reg;
	dst[1] = op->vt.raw;
 
	return err;
}
 
static void _alu_dump_operand(unsigned char *dst, _alu_op_t *op)
{
	if (1 == op->op[1].type) {
		dst[1] = op->op[1].data.value;
		dst[0] |= 0x08;
 
		return;
	}
 
	dst[1] = ((0 != op->op[0].prefix) ? 0x08 : 0x00) | (op->op[0].data.reg & 0x07);
	dst[1] <<= 4;
	dst[1] |= ((0 != op->op[1].prefix) ? 0x08 : 0x00) | (op->op[1].data.reg & 0x07);
}
 
static int _alu_dump(unsigned char *dst, _alu_op_t *op)
{
	int err;
 
	dst[0] = op->reg & 0x07;
	dst[1] = 0x00;
 
	err = 0;
	switch (op->opcode) {
	case _opcode_addi:
		dst[0] |= 0x10;
		/* no break */
	case _opcode_add:
		dst[0] |= 0x02 << 5;
		_alu_dump_operand(dst, op);
 
		break;
	case _opcode_shli:
	case _opcode_shri:
		dst[0] |= 0x08;
		/* no break */
	case _opcode_shr:
		dst[0] |= 0x10;
		/* no break */
	case _opcode_shl:
		dst[0] |= 0x03 << 5;
		dst[1] = op->op[0].data.reg & 0x07;
 
		break;
	case _opcode_nor:
		dst[0] |= 0x10;
		/* no break */
	case _opcode_or:
		dst[0] |= 0x05 << 5;
		_alu_dump_operand(dst, op);
 
		break;
	case _opcode_nand:
		dst[0] |= 0x10;
		/* no break */
	case _opcode_and:
		dst[0] |= 0x04 << 5;
		_alu_dump_operand(dst, op);
 
		break;
	case _opcode_xnor:
		dst[0] |= 0x10;
		/* no break */
	case _opcode_xor:
		dst[0] |= 0x06 << 5;
		_alu_dump_operand(dst, op);
 
		break;
	default:
		err = -EINVAL;
	}
 
	return err;
}
 
static int _write_code(char *name, _op_t *op)
{
	char filename[64];
	int err;
 
	err = snprintf(filename, 64, "%s.bin", name);
	if (64 <= err) {
		return -ENAMETOOLONG;
	}
 
	err = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0644);
	if (0 <= err) {
		unsigned int i, max_addr;
		_op_t *t;
		int fd;
 
		fd = err;
		err = 0;
 
		max_addr = 0;
		for (t = op; NULL != t; t = t->next) {
			if (t->addr > max_addr)
				max_addr = t->addr;
		}
 
		for (i = 0; 0 == err && i <= max_addr; i++) {
			unsigned short value[2];
			int k;
 
			for (t = op; 0 == err && NULL != t; t = t->next) {
				if (i == t->addr) {
					break;
				}
			}
 
			value[0] = value[1] = 0;
			if (NULL != t) {
				for (k = 0; 0 == err && k < 2; k++) {
					switch (t->opt[k]) {
					case _op_type_jmp:
						err = _jmp_dump((unsigned char *) &value[k], t->op[k].jmp);
						break;
					case _op_type_ldst:
						err = _ldst_dump((unsigned char *) &value[k], t->op[k].ldst);
						break;
					case _op_type_alu:
						err = _alu_dump((unsigned char *) &value[k], t->op[k].alu);
						break;
					}
 
					if (0 != err)
						break;
 
					if (t->opt[0] == t->opt[1]) {
						value[1] = value[0];
						break;
					}
				}
			}
 
			while (0 == err) {
				err = write(fd, &value[0], sizeof(value));
				if (sizeof(value) == err) {
					err = 0;
					break;
				}
 
				err = -errno;
				if (-EINTR == err)
					err = 0;
			}
		}
 
		close(fd);
	} else
		err = -errno;
 
	return err;
}
 
 
static int _parse_file(const char *filename)
{
	FILE *f;
	int err;
 
	f = fopen(filename, "r");
	if (NULL != f) {
		_section_t sec;
		int line;
		char l[80];
 
		sec = _section_code;
 
		err = 0;
		line = 0;
 
		while (0 == err && NULL != fgets(&l[0], 80, f)) {
			int len;
 
			line++;
 
			len = _shrink_line(&l[0], 80);
			if (0 > len) {
				err = len;
				fprintf(stderr, "parse error (%d) near line %d\n", err, line);
 
		   		break;
			}
 
			if (0 == len)
				continue;
 
			err = _parse_line(&l[0], &sec);
			if (0 != err) {
				fprintf(stderr, "parse error (%d) near line %d\n", err, line);
			}
		}
 
		fclose(f);
 
		if (0 == err) {
			err = _write_code(_outfile, _op);
			if (0 != err) {
				fprintf(stderr, "write data failed, error %d\n", err);
			}
		}
 
		while (NULL != _op) {
			_op_t *op;
 
			op = _op->next;
			if (_op->op[0].raw != _op->op[1].raw)
				free(_op->op[1].raw);
			free(_op->op[0].raw);
			free(_op);
 
			_op = op;
		}
 
		while (NULL != _var) {
			_var_t *t;
 
			t = _var->next;
			free(_var);
			_var = t;
		}
	} else {
		fprintf(stderr, "failed to open file %s\n", filename);
		err = -errno;
	}
 
	return err;
}
 
int main(int argc, char *argv[])
{
	int err;
 
	err = _parse_args(argc, argv);
	if (0 == err) {
		err = _parse_file(_infile);
	}
 
	return err;
}
 
 

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.