/*
 * inst_decoder.c
 *
 *  Created on: 2016/11/25
 *      Author: takayun
 */

#include "inst_decoder.h"
#include "sys_memory.h"
#include "sys_register.h"
#include "hex_out.h"
#include "sys_prog.h"
#include <stdio.h>
#include <unistd.h>

struct InstRec inst_fetch(){
	struct InstRec rec = inst_memory_load((unsigned int)global_registers[Spc]);
	inc_pc();
	return rec;
}

void inst_decode(struct InstRec inst_rec){
	switch(inst_rec.inst) {
	case INST_END:
		break;
	case INST_JUMP:
		inst_jump(inst_rec.regi, inst_rec.memi);
		break;
	case INST_OUTPUT:
		inst_output(inst_rec.regi, inst_rec.memi);
		break;
	case INST_LOAD:
		inst_load(inst_rec.regi, inst_rec.memi);
		break;
	case INST_STORE:
		inst_store(inst_rec.regi, inst_rec.memi);
		break;
	case INST_DELAY:
		inst_delay(inst_rec.regi, inst_rec.memi);
		break;
	case INST_ADD:
		inst_add(inst_rec.regi, inst_rec.memi);
		break;
	case INST_SUB:
		inst_sub(inst_rec.regi, inst_rec.memi);
		break;
	case INST_COMP:
		inst_comp(inst_rec.regi, inst_rec.memi);
		break;
	case INST_JEQ:
		inst_jeq(inst_rec.regi, inst_rec.memi);
		break;
	case INST_JNE:
		inst_jne(inst_rec.regi, inst_rec.memi);
		break;
	case INST_JIEQ:
		inst_jieq(inst_rec.regi, inst_rec.memi);
		break;
	case INST_JINE:
		inst_jine(inst_rec.regi, inst_rec.memi);
		break;
	}
}

void inst_jump(enum Register reg, unsigned char memory_index){
	set_pc(global_registers[reg]+memory_index);
}
void inst_output(enum Register reg, unsigned char memory_index){
	//メモリの値を7セグに表示
	char buf[5];
	memory_load(memory_index, Sseg);
	sprintf(buf, "%04d", global_registers[Sseg]);
	print_block(buf, 4, HEX0_3);
}
void inst_load(enum Register reg, unsigned char memory_index){
	memory_load(memory_index, reg);
}
void inst_store(enum Register reg, unsigned char memory_index){
	memory_store(memory_index, reg);
}
void inst_delay(enum Register reg, unsigned char memory_index){
	//レジスタの値*10ms待つ
	usleep((int)global_registers[reg]*10000);
}
void inst_add(enum Register reg, unsigned char memory_index){
	global_registers[Sacc]+=global_registers[reg];
}
void inst_sub(enum Register reg, unsigned char memory_index){
	global_registers[Sacc]-=global_registers[reg];
}
void inst_comp(enum Register reg, unsigned char memory_index){
	if(global_registers[Sacc]==global_registers[reg]){
		global_registers[Sflg]=0;
	} else if(global_registers[Sacc] > global_registers[reg]){
		global_registers[Sflg]=-1;
	}else{
		global_registers[Sflg]=1;
	}
}
void inst_jeq(enum Register reg, unsigned char memory_index){
	if(global_registers[Sflg]==global_registers[reg]){
		inc_pc();
	}
}
void inst_jne(enum Register reg, unsigned char memory_index){
	if(global_registers[Sflg]!=global_registers[reg]){
		inc_pc();
	}
}
void inst_jieq(char im, unsigned char memory_index){
	if(global_registers[Sflg]==im){
		inc_pc();
	}
}
void inst_jine(char im, unsigned char memory_index){
	if(global_registers[Sflg]!=im){
		inc_pc();
	}
}

