#include "sys/alt_stdio.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "system.h"
#include "hex_out.h"
#include "sys_register.h"
#include "sys_memory.h"
#include "input_int.h"
#include "inst_decoder.h"

#include "altera_avalon_lcd_16207.h"
#include "altera_avalon_lcd_16207_regs.h"


#define LCD_BASE 0x4030

#define ledrs (volatile int *) 0x00050a0
#define lcd_on (volatile char *) 0x4010
#define lcd_blon (volatile char *) 0x4020

#define T_MS10 12500 //(10ms)

void wait(unsigned int s) {
	volatile i;
	for (i = 0; i < T_MS10*s; i++);
}

void init() {
	FILE *flcd;
	char msg[] = "test";
	*lcd_on = 1;
	*lcd_blon = 1;
	usleep(2000);

	flcd = fopen(LCD_16207_0_NAME, "w");
	if (flcd) {
		fwrite(msg, strlen(msg), 1, flcd);
		fclose(flcd);
	}
	//
	registers_init();
	memory_init();
	clear_block(HEX0_3); clear_block(HEX4_5); clear_block(HEX6_7);
	print_block("he", 2, HEX6_7);
	print_block("lo", 2, HEX4_5);
	print_block("you1", 4, HEX0_3);
	wait(200);
	clear_block(HEX0_3); clear_block(HEX4_5); clear_block(HEX6_7);
}

char stack[5];

void store_value(){
	char buf[5];
	unsigned int memi = global_registers[Ssw_memi];
	memory_store(memi, Ssw_data);
	sprintf(buf, "%02x", (unsigned char)memi);
	print_block(buf, 2, HEX6_7);
	print_block("--", 2, HEX4_5);
	sprintf(buf, "%04d", global_registers[Ssw_data]);
	print_block(buf, 4, HEX0_3);
}
void store_inst(){
	char inst;
	char mem_index;
	char reg_index;
	struct InstRec inst_rec;

	// 必要な情報の取得
	inst = global_registers[Ssw_inst];
	mem_index = global_registers[Ssw_memi];
	reg_index = global_registers[Ssw_regi];
	inst_rec.inst = (unsigned int)inst;
	inst_rec.memi = (unsigned int)mem_index;
	inst_rec.regi = (unsigned int)reg_index;

	// ストア処理
	inst_memory_store((unsigned int)global_registers[Spc], inst_rec);
	global_registers[Spc]++;

	{
		char buf[5];
		sprintf(buf, "%04d", inst_rec.inst);
		print_block(buf, 4, HEX0_3);
		sprintf(buf, "%02x", global_registers[Spc]);
		print_block(buf, 2, HEX4_5);
	}
}
void run_proc() {
	volatile struct InstRec inst_rec;

	//print_block(" go ", 4, HEX0_3);

	global_registers[Spc] = 0;
	print_block("pc", 2, HEX6_7);
	do {
		// pc表示
		{
			char buf[5];
			sprintf(buf, "%02x", global_registers[Spc]);
			print_block(buf, 2, HEX4_5);
		}
		// 命令フェッチ
		inst_rec = inst_fetch();
		// 命令デコード実行
		inst_decode(inst_rec);
		if ( global_registers[Ssw_run] ) wait(100);
	}while( inst_rec.inst != INST_END );

	//print_block(" end", 4, HEX0_3);
}

void print_change_memory(unsigned int current_memory) {
	char buf[5];
	sprintf(buf, "g %2d", current_memory);
	print_block(buf, 4, HEX0_3);
	print_block("an", 2, HEX4_5);
	print_block("ch", 2, HEX6_7);
	wait(200);
	clear_block(HEX0_3); clear_block(HEX4_5); clear_block(HEX6_7);
}

int main()
{
	init();
	while(1) {
		// interrupt
		in_int();

		// event
		if (PUSH_EVENT == PUSH_VALSTR) {
			// 値のストア
			store_value();
		}
		if (PUSH_EVENT == PUSH_INSSTR) {
			// 命令のストア
			store_inst();
		}
		if (PUSH_EVENT == PUSH_RUN) {
			if (global_current_memory != (unsigned int)global_registers[Ssw_psel]) {
				global_current_memory = (unsigned int)global_registers[Ssw_psel];
				print_change_memory(global_current_memory);
			}
			else {
				// プログラム実行
				run_proc();
			}
		}
	}
	return 0;
}
