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

Subversion Repositories igor

[/] [igor/] [trunk/] [simulator/] [instructions.c] - Rev 4

Compare with Previous | Blame | View Log

 
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
 
#include "regs.h"
#include "types.h"
#include "object.h"
#include "memory.h"
#include "microcode.h"
#include "machine.h"
#include "instructions.h"
#include "debug.h"
#include "bits.h"
#include "profiler.h"
 
typedef void (instr_f)(instr_t);
 
typedef struct {
	int format;
	instr_f *func;
	char *name;
} instr_spec_t;
 
instr_spec_t instructions[64];
 
int print_instructions = 0;
 
const char *
register_string(instr_reg_t r)
{
	struct di_const *c;
	static int regnum;
	int curreg;
	static char regs[12][128];
 
	c = debug_get1_filter(r.addr, "reg");
 
	if (c == NULL) {
		snprintf(regs[regnum], 128, "r%03X[%d]", r.addr, r.pointer);
	} else {
		snprintf(regs[regnum], 128, "%%%s(r%03X)[%d]", c->name, r.addr,
		    r.pointer);
	}
	curreg = regnum;
 
	regnum = (regnum+1)%12;
 
	return regs[curreg];
}
 
int
instr_reg(instr_reg_t r)
{
	if (r.pointer)
		return object_get_datum(reg_get(r.addr));
	return r.addr;
}
 
reg_t
instr_get_reg(instr_reg_t r)
{
	return reg_get(instr_reg(r));
}
 
void
instr_set_reg(instr_reg_t r, reg_t val)
{
	reg_set(instr_reg(r), val);
}
 
instr_reg_t
decode_instruction_reg(uint32_t r)
{
	instr_reg_t reg;
	reg.pointer = (r>>10) & 1;
	reg.addr = r & 0x3FF;
	return reg;
}
 
void
decode_instruction_imm(instr_t *instr)
{
	switch (instr->op) {
	case INS_LOAD:
	case INS_STORE:
		instr->disp = sign_extend(bitfield(instr->imm, 0, 17), 18);
		break;
	case INS_SET_FLAG:
	case INS_GET_FLAG:
		instr->fmask = bitfield(instr->imm, 0, 8);
		instr->fnr = bitfield(instr->imm, 9, 11);
		instr->fimm = bitfield(instr->imm, 12, 12);
		break;
	case INS_SET_TYPE_IMM:
	case INS_CMP_TYPE_IMM:
		instr->immval = bitfield(instr->imm, 0, 4);
		break;
	case INS_SET_DATUM_IMM:
	case INS_CMP_DATUM_IMM:
		instr->immval = sign_extend(instr->imm, 18);
		break;
	case INS_SET_GC_IMM:
	case INS_CMP_GC_IMM:
		instr->immval = bitfield(instr->imm, 0, 1);
		break;
	}
}
 
instr_t
decode_instruction(uint64_t raw_instr)
{
	instr_t instr = { };
 
	instr.op = bitfield(raw_instr, 42, 47);
	instr_spec_t instr_spec = instructions[instr.op];
 
	if (instr_spec.format < 0 || instr_spec.format > 3)
		errx(1, "Unknown instruction format: %d", instr_spec.format);
 
	if (instr_spec.format == OP_BR) {
		instr.r1 = decode_instruction_reg(bitfield(raw_instr, 29, 39));
		instr.flag_mask = bitfield(raw_instr, 21, 28);
		instr.flag_values = bitfield(raw_instr, 13, 20);
		instr.addr = sign_extend(bitfield(raw_instr, 0, 12), 13);
		return instr;
	}
 
	switch (instr_spec.format) {
	case OP_2R: instr.r2 = decode_instruction_reg(bitfield(raw_instr, 18, 28));
	case OP_1R: instr.r1 = decode_instruction_reg(bitfield(raw_instr, 29, 39));
	}
 
	instr.imm = bitfield(raw_instr, 0, 17);
	decode_instruction_imm(&instr);
 
	return instr;
}
 
char* instruction_type(int index)
{
	return instructions[index].name;
}
 
void
print_instruction(reg_t addr)
{
	print_instruction_to_file(stdout, addr);
}
 
void
print_instruction_to_file(FILE *f, reg_t addr)
{
	instr_t instr = decode_instruction(microcode_fetch_instr(addr));
	instr_spec_t instr_spec = instructions[instr.op];
	struct di_const *c;
	int i;
 
	c = debug_get1_filter(addr, "label");
	if (c != NULL)
		fprintf(f, "%s:", c->name);
 
	fprintf(f, "0x%04X ", addr);
 
	switch (instr_spec.format) {
	case OP_BR:
		//fprintf(f, "address: 0x%X\n", instr.addr);
		fprintf(f, FORMAT_IBR, instr_spec.name,
			register_string(instr.r1),
			instr.flag_mask, instr.flag_values,
			instr.addr);
		break;
	case OP_2R:
		fprintf(f, FORMAT_I2R, instr_spec.name,
			register_string(instr.r1),
			register_string(instr.r2),
			instr.imm);
		break;
	case OP_1R:
		fprintf(f, FORMAT_I1R, instr_spec.name,
			register_string(instr.r1),
			instr.imm);
		break;
	case OP_0R:
		fprintf(f, FORMAT_I0R, instr_spec.name,
			instr.imm);
		break;
	default:
		errx(1, "Unknown instruction format: %d", instr_spec.format);
	}
 
	switch (instr.op) {
	case INS_BRANCH:
	case INS_BRANCH_REG:
		fprintf(f, " [");
		for (i = 0; i < 8; i++) {
			if ((instr.flag_mask >> i) & 1)
				fprintf(f, " %s%c", ((instr.flag_values>>i)&1) ? "" : "!",
					status_flags[i]);
		}
		fprintf(f, "]");
		c = debug_get1_filter(instr.addr, "label");
		if (c != NULL)
			fprintf(f, " label: %s", c->name);
		fputs("\n", f);
		break;
	case INS_SET_TYPE_IMM:
		c = debug_get1_filter(instr.immval, "type");
		fprintf(f, " %s\n", c ? c->name : "unresolved");
		break;
	default:
		fputs("\n", f);
#if 0 // XXX: Pass file here as well
		if (instr.imm > 1)
			debug_show(instr.imm);
#endif
		break;
	}
}
 
 
 
void
i_nop(instr_t ins)
{
	// is this implementation correct?
}
 
void
i_halt(instr_t ins)
{
	machine_shutdown();
}
 
void
i_alu(instr_t ins)
{
	reg_t v1, v2;
	int a, b, res;
 
	v1 = instr_get_reg(ins.r1);
	v2 = instr_get_reg(ins.r2);
 
	//instr_spec_t instr_spec = instructions[ins.op];
 
	if (OBJECT_TYPE(v1) != OBJECT_TYPE(v2)) {
		// TODO set type error flag
		//warnx("ALU operation on two objects of different types");
		/*
		errx(1, "(%s) Can't operate on two objects of different types",
		     instr_spec.name);
		*/
	}
	if (OBJECT_TYPE(v1) != TYPE_INT) {
		//warnx("ALU operation on non-integer values");
		/*
		errx(1, "(%s) Can't operate on non-integer values",
		     instr_spec.name);
		*/
	}
 
	a = object_get_datum_signed(v1);
	b = object_get_datum_signed(v2);
 
	//printf("alu, a=%d, b=%d\n", a, b);
 
	switch (ins.op) {
	case INS_ADD:
		res = a+b;
		break;
	case INS_SUB:
		res = a-b;
		break;
	case INS_MUL:
		res = a*b;
		break;
	case INS_DIV:
		res = a/b;
		break;
	case INS_MOD:
		res = a%b;
		break;
	case INS_AND:
		res = a&b;
		break;
	case INS_OR:
		res = a|b;
		break;
	case INS_XOR:
		res = a^b;
		break;
	case INS_NOT:
		res = ~b;
		break;
	case INS_SHIFT_L:
		res = a << b;
		break;
	case INS_SHIFT_R:
		res = a >> b;
		break;
	default:
		errx(1, "this is not an ALU opcode: %d", ins.op);
	}
 
	//printf("alu, res=%d 0x%X\n", res, res);
	instr_set_reg(ins.r1, object_set_datum(v1, res));
	set_status_flag(ST_N, res<0);
	set_status_flag(ST_Z, res==0);
	set_status_flag(ST_O, res<-(1<<25) || res>=(1<<25));
}
 
 
void
i_load(instr_t ins)
{
	uint32_t addr = OBJECT_DATUM(instr_get_reg(ins.r2))+ins.disp;
	instr_set_reg(ins.r1, memory_get(addr));
}
 
void
i_store(instr_t ins)
{
	uint32_t addr = OBJECT_DATUM(instr_get_reg(ins.r2))+ins.disp;
	reg_t val = instr_get_reg(ins.r1);
 
	if (print_instructions) {
		printf("\tStoring (at 0x%07X): ", addr);
		object_dump(val);
	}
	memory_set(addr, val);
}
 
 
 
void
i_branch(instr_t ins)
{
	if ((ins.flag_mask & get_all_status_flags()) == ins.flag_values)
		reg_set(REG_PC, ins.addr);
}
 
 
void
i_branch_reg(instr_t ins)
{
	uint32_t addr = object_get_datum(instr_get_reg(ins.r1)) + ins.addr;
	if ((ins.flag_mask & get_all_status_flags()) == ins.flag_values)
		reg_set(REG_PC, addr);
}
 
 
void
i_set_flag(instr_t ins)
{
	printf("i_set_flag: fnr=%X, fmask=%X, fimm=%X, reg=%X\n",
	       ins.fnr, ins.fmask, ins.fimm, instr_get_reg(ins.r1));
	set_status_flag(ins.fnr,
			get_flags(ins.fmask)
			|| ins.fimm
			|| object_get_datum(instr_get_reg(ins.r1)));
}
 
void
i_clear_flag(instr_t ins)
{
	set_status_flag(ins.fnr, 0);
}
 
void
i_get_flag(instr_t ins)
{
	instr_set_reg(ins.r1, get_flags(ins.fmask));
}
 
 
void
i_get_type(instr_t ins)
{
	int type = OBJECT_TYPE(instr_get_reg(ins.r2));
	reg_t val = instr_get_reg(ins.r1);
	val = object_set_datum(val, type);
	val = object_set_type(val, TYPE_INT);
	instr_set_reg(ins.r1, val);
}
 
void
i_set_type(instr_t ins)
{
	//printf("SET-TYPE r%x <- %x\n", ins.r1, ins.imm);
	reg_t val = instr_get_reg(ins.r1);
	if (ins.op == INS_SET_TYPE_IMM) {
		val = object_set_type(val, ins.immval);
	} else {
		val = object_set_type(val, object_get_datum(instr_get_reg(ins.r2)));
	}
	instr_set_reg(ins.r1, val);
}
 
void
i_get_datum(instr_t ins)
{
	reg_t val1, val2;
 
	val1 = instr_get_reg(ins.r1);
	val2 = instr_get_reg(ins.r2);
	val1 = object_set_datum(val1, object_get_datum(val2));
	instr_set_reg(ins.r1, val1);
}
 
void
i_set_datum(instr_t ins)
{
	//printf("SET-DATUM r%x <- %x\n", ins.r1, ins.imm);
 
	reg_t val = instr_get_reg(ins.r1);
	instr_set_reg(ins.r1, object_set_datum(val, ins.immval));
}
 
void
i_get_gc(instr_t ins)
{
	reg_t val1, val2;
	val1 = instr_get_reg(ins.r1);
	val2 = instr_get_reg(ins.r2);
	val1 = object_set_datum(val1, object_get_gc(val2));
	instr_set_reg(ins.r1, val1);
}
 
void
i_set_gc(instr_t ins)
{
	reg_t val = instr_get_reg(ins.r1);
	if (ins.op == INS_SET_GC_IMM) {
		val = object_set_gc(val, ins.immval);
	} else {
		val = object_set_gc(val, object_get_datum(instr_get_reg(ins.r2)));
	}
	instr_set_reg(ins.r1, val);
}
 
void
i_cpy(instr_t ins)
{
	instr_set_reg(ins.r1, instr_get_reg(ins.r2));
}
 
 
void
i_cmp(instr_t ins)
{
	int diff = 0;
	switch (ins.op) {
	case INS_CMP_TYPE:
		diff = object_get_type(instr_get_reg(ins.r1))
			- object_get_type(instr_get_reg(ins.r2));
		break;
	case INS_CMP_TYPE_IMM:
		diff = object_get_type(instr_get_reg(ins.r1))
			- ins.immval;
		break;
	case INS_CMP_DATUM:
		diff = object_get_datum_signed(instr_get_reg(ins.r1))
			- object_get_datum_signed(instr_get_reg(ins.r2));
		break;
	case INS_CMP_DATUM_IMM:
		diff = object_get_datum_signed(instr_get_reg(ins.r1))
			- ins.immval;
		break;
	case INS_CMP_GC:
		diff = object_get_gc(instr_get_reg(ins.r1))
			- object_get_gc(instr_get_reg(ins.r2));
		break;
	case INS_CMP_GC_IMM:
		diff = object_get_gc(instr_get_reg(ins.r1))
			- ins.immval;
		break;
	case INS_CMP:
		// TODO fix
		if (object_get_type(instr_get_reg(ins.r1)) !=
		    object_get_type(instr_get_reg(ins.r2))) {
			//errx(1, "(CMP) Cannot compare two objects of different types");
			set_status_flag(ST_T, 1);
			return;
		}
		//if (object_get_type(instr_get_reg(ins.r1)) == TYPE_INT) {
		diff = object_get_datum_signed(instr_get_reg(ins.r1))
			- object_get_datum_signed(instr_get_reg(ins.r2));
		break;
	default:
		errx(1, "(i_cmp) Unknown comparison instruction %d",
		     ins.op);
	}
 
	//printf("compare, diff=%d\n", diff);
 
	set_status_flag(ST_T, 0);
	set_status_flag(ST_Z, diff==0);
	set_status_flag(ST_N, diff<0);
}
 
 
/*
void
i_check_type(instr_t ins)
{
	int reg = ins.r2;
	int type = ins.imm;
 
	set_status_flag(ST_B, OBJECT_TYPE(reg_get(reg)) == type);
}
*/
 
/*
void
i_push(instr_t ins)
{
	reg_set(REG_SP, reg_get(REG_SP)-1);
	memory_set(reg_get(REG_SP), reg_get(ins.r1));
}
 
void
i_pull(instr_t ins)
{
	reg_set(ins.r1, memory_get(reg_get(REG_SP)));
	reg_set(REG_SP, reg_get(REG_SP)+1);
}
*/
 
void
instructions_init(void)
{
	REG_INSTR(NOP, OP_2R, i_nop);
	REG_INSTR(HALT, OP_2R, i_halt);
 
	REG_INSTR(ADD, OP_2R, i_alu);
	REG_INSTR(SUB, OP_2R, i_alu);
	REG_INSTR(MUL, OP_2R, i_alu);
	REG_INSTR(DIV, OP_2R, i_alu);
	REG_INSTR(AND, OP_2R, i_alu);
	REG_INSTR(OR,  OP_2R, i_alu);
	REG_INSTR(XOR, OP_2R, i_alu);
	REG_INSTR(NOT, OP_2R, i_alu);
	REG_INSTR(SHIFT_L, OP_2R, i_alu);
	REG_INSTR(MOD, OP_2R, i_alu);
	REG_INSTR(SHIFT_R, OP_2R, i_alu);
 
	REG_INSTR(LOAD, OP_2R, i_load);
	REG_INSTR(STORE, OP_2R, i_store);
 
	REG_INSTR(BRANCH, OP_BR, i_branch);
	REG_INSTR(BRANCH_REG, OP_BR, i_branch_reg);
 
	REG_INSTR(GET_FLAG, OP_1R, i_get_flag);
	REG_INSTR(CLEAR_FLAG, OP_0R, i_clear_flag);
	REG_INSTR(SET_FLAG, OP_1R, i_set_flag);
 
	REG_INSTR(GET_TYPE, OP_2R, i_get_type);
	REG_INSTR(SET_TYPE, OP_2R, i_set_type);
	REG_INSTR(SET_TYPE_IMM, OP_1R, i_set_type);
	REG_INSTR(GET_DATUM, OP_2R, i_get_datum);
	REG_INSTR(SET_DATUM_IMM, OP_1R, i_set_datum);
	REG_INSTR(GET_GC, OP_2R, i_get_gc);
	REG_INSTR(SET_GC, OP_2R, i_set_gc);
	REG_INSTR(SET_GC_IMM, OP_1R, i_set_gc);
	REG_INSTR(CPY, OP_2R, i_cpy);
 
	REG_INSTR(CMP_TYPE, OP_2R, i_cmp);
	REG_INSTR(CMP_TYPE_IMM, OP_1R, i_cmp);
	REG_INSTR(CMP_DATUM, OP_2R, i_cmp);
	REG_INSTR(CMP_DATUM_IMM, OP_1R, i_cmp);
	REG_INSTR(CMP_GC, OP_2R, i_cmp);
	REG_INSTR(CMP_GC_IMM, OP_1R, i_cmp);
	REG_INSTR(CMP, OP_2R, i_cmp);
}
 
 
void
execute_instruction(instr_t ins)
{
	//printf("Looking for opcode: %d\n", ins.op);
	instructions[ins.op].func(ins);
}
 
void
set_instruction_printing(int s)
{
	print_instructions = s;
}
 
void
do_instruction(reg_t addr)
{
	instr_t instr;
	if (print_instructions)
		print_instruction(addr);
	instr = decode_instruction(microcode_fetch_instr(addr));
	execute_instruction(instr);
	profiler_add_execution(addr, instr, get_all_status_flags());
}
 
void
do_next_instruction(void)
{
	reg_t pc;
 
	if (!machine_up())
		errx(1, "(do_next_instruction) cannot do that: machine down\n");
 
	pc = reg_get(REG_PC);
	reg_set(REG_PC, pc+1);
	do_instruction(pc);
}
 
reg_t
next_instr_addr(void)
{
	return reg_get(REG_PC);
}
 
 

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.