Newer
Older
emul / emul_inst_exec.c
#include "emul_inst_exec.h"
#include "emul_io_std.h"
#include <string.h>

// exit message
static char faild_message();
#define EXIT_MESSAGE_LENGTH 128
void emul_inst_exec_get_faild_message(char *msg);

// propaty
static RUNMODE RunMode;

void emul_inst_exec_set_runmode(RUNMODE mode) {
    RunMode = mode;
}
RUNMODE emul_inst_exec_get_runmode() {
    return RunMode;
}

// プロトタイプ
exitcode_t emul_inst_exec_pseudo(char token[LOAD_TOKEN_MAX]);
// load label
void emul_inst_exec_load_label() {
    static int start_pc = -1;
    char token[LOAD_TOKEN_MAX];
    int ps_id;
    // 開始地点を記憶
    if (start_pc == -1) start_pc = emul_reg_get(Spc);
    // トークンを取得
    if ( emul_inst_dec_get_token(token) == 0 ) {
        emul_out_std_err("Non exist next token\n");
        emul_out_std_err("Loading Label Finish!\n");
        // 次のトークンが見つからない場合終了, pcのアドレスを読み込み開始時点の状態に戻す
	// bug
	emul_inst_dec_reset_pc(start_pc);
	start_pc = -1;
        return ;
    }
    emul_out_std_debug("[label] load token: %s\n", token);
    // 疑似コードを取得
    ps_id = emul_inst_dec_get_pseudo(token);
    // 疑似コードがLABELなら
    if ( ps_id == LABEL ) {
        // 疑似コードを実行
        emul_inst_exec_pseudo(token);
    }
    // 読み込めるトークンがなくなるまで実行
    emul_inst_exec_load_label();
}

void emul_inst_exec_init() {
    emul_std_init();
    emul_reg_init();
    emul_inst_dec_init();
}
void emul_inst_exec_end() {
    emul_std_end();
}

int emul_inst_exec_load(char *filename) {
    int current_pc = emul_reg_get(Spc);
    emul_out_std_debug("emul_inst_exec_load...");
    // プログラムカウンタを更新する
    emul_inst_dec_update_pc();
    // ロードできないなら終了
    if ( emul_inst_dec_load(filename) == 0 ) return 0;
    emul_inst_dec_reset_pc(current_pc);
    // できたらラベルも読み込み
    emul_inst_exec_load_label();
    emul_out_std_debug("[Finish]\n");
    return 1;
}

int emul_inst_exec_loadline(char *line) {
    // ロードできないなら終了
    if ( emul_inst_dec_loadline(line) == 0 ) return 0;
    // できたらラベルも読み込み
    //emul_inst_exec_load_label();
    return 1;
}

/* オペコード解読処理群 - START */
void emul_inst_exec_add(int r0, int r1, int r2) {
    emul_out_std_debug("       : add r0[%d], r1[%d], r2[%d];\n", emul_reg_get(r0), emul_reg_get(r1), emul_reg_get(r2));
    emul_reg_set(r0, emul_reg_get(r1) + emul_reg_get(r2));
    emul_out_std_debug("Execute: add r0[%d], r1[%d], r2[%d];\n", emul_reg_get(r0), emul_reg_get(r1), emul_reg_get(r2));
}

void emul_inst_exec_addi(int r0, int r1, int im) {
    emul_out_std_debug("       : addi r0[%d], r1[%d], im[%d];\n", emul_reg_get(r0), emul_reg_get(r1), im);
    emul_reg_set(r0, emul_reg_get(r1) + im);
    emul_out_std_debug("Execute: addi r0[%d], r1[%d], im[%d];\n", emul_reg_get(r0), emul_reg_get(r1), im);
}

void emul_inst_exec_sub(int r0, int r1, int r2) {
    emul_out_std_debug("       : sub r0[%d], r1[%d], r2[%d];\n", emul_reg_get(r0), emul_reg_get(r1), emul_reg_get(r2));
    emul_reg_set(r0, emul_reg_get(r1) - emul_reg_get(r2));
    emul_out_std_debug("Execute: sub r0[%d], r1[%d], r2[%d];\n", emul_reg_get(r0), emul_reg_get(r1), emul_reg_get(r2));
}

void emul_inst_exec_slt(int r0, int r1, int r2) {
    emul_out_std_debug("       : slt r0[%d], r1[%d], r2[%d];\n", emul_reg_get(r0), emul_reg_get(r1), emul_reg_get(r2));
    if (emul_reg_get(r1) < emul_reg_get(r2)) emul_reg_set(r0, 1);
    else emul_reg_set(r0, 0);
    emul_out_std_debug("Execute: slt r0[%d], r1[%d], r2[%d];\n", emul_reg_get(r0), emul_reg_get(r1), emul_reg_get(r2));
}

void emul_inst_exec_slti(int r0, int r1, int im) {
    emul_out_std_debug("       : slti r0[%d], r1[%d], im[%d];\n", emul_reg_get(r0), emul_reg_get(r1), im);
    if (emul_reg_get(r1) < im) emul_reg_set(r0, 1);
    else emul_reg_set(r0, 0);
    emul_out_std_debug("Execute: slti r0[%d], r1[%d], im[%d];\n", emul_reg_get(r0), emul_reg_get(r1), im);
}

void emul_inst_exec_seq(int r0, int r1, int r2) {
    emul_out_std_debug("       : seq r0[%d], r1[%d], r2[%d];\n", emul_reg_get(r0), emul_reg_get(r1), emul_reg_get(r2));
    if (emul_reg_get(r1) == emul_reg_get(r2)) emul_reg_set(r0, 1);
    else emul_reg_set(r0, 0);
    emul_out_std_debug("Execute: seq r0[%d], r1[%d], r2[%d];\n", emul_reg_get(r0), emul_reg_get(r1), emul_reg_get(r2));
}

void emul_inst_exec_sge(int r0, int r1, int r2) {
    emul_out_std_debug("       : sge r0[%d], r1[%d], r2[%d];\n", emul_reg_get(r0), emul_reg_get(r1), emul_reg_get(r2));
    if (emul_reg_get(r1) >= emul_reg_get(r2)) emul_reg_set(r0, 1);
    else emul_reg_set(r0, 0);
    emul_out_std_debug("Execute: sge r0[%d], r1[%d], r2[%d];\n", emul_reg_get(r0), emul_reg_get(r1), emul_reg_get(r2));
}

void emul_inst_exec_sgt(int r0, int r1, int r2) {
    emul_out_std_debug("       : sgt r0[%d], r1[%d], r2[%d];\n", emul_reg_get(r0), emul_reg_get(r1), emul_reg_get(r2));
    if (emul_reg_get(r1) >= emul_reg_get(r2)) emul_reg_set(r0, 1);
    else emul_reg_set(r0, 0);
    emul_out_std_debug("Execute: sgt r0[%d], r1[%d], r2[%d];\n", emul_reg_get(r0), emul_reg_get(r1), emul_reg_get(r2));
}

void emul_inst_exec_sle(int r0, int r1, int r2) {
    emul_out_std_debug("       : sle r0[%d], r1[%d], r2[%d];\n", emul_reg_get(r0), emul_reg_get(r1), emul_reg_get(r2));
    if (emul_reg_get(r1) <= emul_reg_get(r2)) emul_reg_set(r0, 1);
    else emul_reg_set(r0, 0);
    emul_out_std_debug("Execute: sle r0[%d], r1[%d], r2[%d];\n", emul_reg_get(r0), emul_reg_get(r1), emul_reg_get(r2));
}

void emul_inst_exec_sne(int r0, int r1, int r2) {
    emul_out_std_debug("       : sne r0[%d], r1[%d], r2[%d];\n", emul_reg_get(r0), emul_reg_get(r1), emul_reg_get(r2));
    if (emul_reg_get(r1) != emul_reg_get(r2)) emul_reg_set(r0, 1);
    else emul_reg_set(r0, 0);
    emul_out_std_debug("Execute: sne r0[%d], r1[%d], r2[%d];\n", emul_reg_get(r0), emul_reg_get(r1), emul_reg_get(r2));
}

void emul_inst_exec_j(char *label) {
    int getted_address;
    emul_out_std_debug("       : j label[%s];\n", label);
    getted_address = emul_label_resolve(label);
    emul_reg_set( Spc, getted_address );
    emul_out_std_debug("Execute: j label[%s];\n", label);
}

void emul_inst_exec_jal(char *label) {
    emul_out_std_debug("        : jal label[%s] $pc=%d;\n", label, emul_reg_get(Spc) );
    emul_reg_set( Sra, emul_reg_get(Spc) );
    emul_reg_set( Spc, emul_label_resolve(label) );
    emul_out_std_debug("Execute : jal label[%s] $ra=%d;\n", label, emul_reg_get(Sra) );
}

void emul_inst_exec_jalr(int r0, int r1) {
    emul_out_std_debug("        : jalr r0[%d] r1[%d];\n", emul_reg_get(r0), emul_reg_get(r1));
    emul_reg_set( r1, emul_reg_get(Spc) );
    emul_reg_set( Spc, emul_reg_get(r0) );
    emul_out_std_debug("Execute : jalr r0[%d] r1[%d];\n", emul_reg_get(r0), emul_reg_get(r1));
}
void emul_inst_exec_jr(int r0) {
    emul_out_std_debug("        : jr r0[%d];\n", emul_reg_get(r0));
    emul_reg_set( Spc, emul_reg_get(r0) );
    emul_out_std_debug("Execute : jr r0[%d];\n", emul_reg_get(r0));
}

void emul_inst_exec_beq(int r0, int r1, char *label) {
    emul_out_std_debug("       : beq r0[%d] r1[%d] label[%d];\n", emul_reg_get(r0), emul_reg_get(r1), label);
    if (emul_reg_get(r0) == emul_reg_get(r1)) {
        emul_reg_set( Spc, emul_label_resolve(label) );
    }
    emul_out_std_debug("Execute: beq r0[%d] r1[%d] label[%d];\n", emul_reg_get(r0), emul_reg_get(r1), label);
}

void emul_inst_exec_bne(int r0, int r1, char *label) {
    int getted_address = -1;
    emul_out_std_debug("       : bne r0[%d] r1[%d] label[%s]>>PC(%d);\n", emul_reg_get(r0), emul_reg_get(r1), label, getted_address);
    if (emul_reg_get(r0) != emul_reg_get(r1)) {
        getted_address = emul_label_resolve(label);
        emul_reg_set( Spc, getted_address );
    } else {
        getted_address = -1;
    }
    emul_out_std_debug("Execute: bne r0[%d] r1[%d] label[%s]>>PC(%d);\n", emul_reg_get(r0), emul_reg_get(r1), label, getted_address);
}

void emul_inst_exec_lw(int r0, int address, int r1) {
    emul_out_std_debug("       : lw r0[%d] address[%d] offset[%d];\n", emul_reg_get(r0), address, emul_reg_get(r1));
    emul_reg_set(r0, emul_mem_get_word(address+emul_reg_get(r1)));
    emul_out_std_debug("Execute: lw r0[%d] address[%d] offset[%d];\n", emul_reg_get(r0), address, emul_reg_get(r1));
}

void emul_inst_exec_sw(int r0, int address, int r1) {
    emul_out_std_debug("       : sw r0[%d] address[%d] offset[%d];\n", emul_reg_get(r0), address, emul_reg_get(r1));
    emul_mem_set_word(address+emul_reg_get(r1), emul_reg_get(r0));
    emul_out_std_debug("Execute: sw r0[%d] address[%d] offset[%d];\n", emul_reg_get(r0), address, emul_reg_get(r1));
}
/* オペコード解読処理群 - END */


/* 疑似コード解読処理群 - START */

/* :DUMP <OPTION>
 * OPTION:
 *   LAST: 最後に実行した命令を表示
 *   NONE: デバックなし(通常モード)へ切り替え
 *   DEBUG<NUM>: デバックあり
 *     NUM: デバックレベル[0-2] (0はデバックなし)
 * OUTPUT:
 *   LAST_CMD [OPTION] */
void emul_inst_exec_pseudo_dump(const char *option) {
    if ( strcmp(option, "NONE") == 0 ) emul_std_debug(0);
    if ( strcmp(option, "none") == 0 ) emul_std_debug(0);
    if ( strcmp(option, "DEBUG0") == 0 ) emul_std_debug(0);
    if ( strcmp(option, "debug0") == 0 ) emul_std_debug(0);
    if ( strcmp(option, "DEBUG1") == 0 ) emul_std_debug(1);
    if ( strcmp(option, "debug1") == 0 ) emul_std_debug(1);
    if ( strcmp(option, "DEBUG2") == 0 ) emul_std_debug(2);
    if ( strcmp(option, "debug2") == 0 ) emul_std_debug(2);
    emul_out_std_debug("PseudoExec: DUMP option[%s];\n", option);
}

/* :MEMCAT <ADDRESS>
 * OUTPUT:
 *   ADDRESS = <0xVALUE(8bit)> */
void emul_inst_exec_pseudo_memcat(int address) {
    emul_out_std("0x%02X\n", emul_mem_get(address));
    emul_out_std_debug("PseudoExec: MEMCAT address[%d];\n", address);
}

/* :MEMCATW <ADDRESS>
 * OUTPUT:
 *   ADDRESS = <0xVALUE(32bit)> */
void emul_inst_exec_pseudo_memcatw(int address) {
    emul_out_std("0x%08X\n", emul_mem_get(address));
    emul_out_std_debug("PseudoExec: MEMCATW address[%d];\n", address);
}

/* :REGCAT <REGISTER>
 * OUTPUT:
 *   ADDRESS = <0xVALUE(32bit)> */
void emul_inst_exec_pseudo_regcat(int reg) {
    emul_out_std("0x%08X\n", emul_reg_get(reg));
    emul_out_std_debug("PseudoExec: REGCAT address[%d];\n", reg);
}

/* :LABEL <LABELNAME>
 * INPUT:
 *   LABELNAME = <ラベル名>*/
void emul_inst_exec_pseudo_label(const char *labelname, int address) {
    emul_label_add(labelname, address);
    emul_out_std_debug("PseudoExec: LABEL labelname[%s] address[%d];\n", labelname, address);
}

/* :RUN
* SUMMARY:
*   現在の状態から逐次実行に切り替える */
void emul_inst_exec_pseudo_run() {
    emul_inst_exec_set_runmode(Run);
}

/* :STEP
* SUMMARY:
*   現在の状態からステップ実行に切り替える */
void emul_inst_exec_pseudo_step() {
    emul_inst_exec_set_runmode(Step);
}

/* :INPUT <REGISTER>
* SUMMARY:
*   キーボート入力を待機し,結果をレジスタへ格納する */
void emul_inst_exec_pseudo_input(int reg) {
    int c;
    emul_out_std_debug("wait to be inputed...\n");
    while ( (c = getchar()) == '\n' );
    emul_reg_set(reg, c);
}

/* :OUTPUT <REGISTER>
*   レジスタの値をASCII文字として画面に出力する,改行はない*/
void emul_inst_exec_pseudo_output(int reg) {
    emul_out_std("%d", (char)emul_reg_get(reg));
}

/* :CRLF
*   画面へ改行コードを送信する,改行コードについて決まりはない */
void emul_inst_exec_pseudo_crlf() {
    emul_out_std("\n");
}

/* :EXEC
*   ファイルからプログラムを読み込み実行する */
void emul_inst_exec_pseudo_exec(char *filename) {
    emul_inst_exec_load(filename);
}

/* :Exit 
 *   プログラムを正常終了 */
void emul_inst_exec_pseudo_exit() {
    emul_inst_exec_set_runmode(Exit);
}

/* 疑似コード解読処理群 - END */


/* Execute pseudocode
 * RETURN:
 *   succsess: 1
 *   failed  : 0 */
exitcode_t emul_inst_exec_pseudo(char token[LOAD_TOKEN_MAX]) {
    char label[LABEL_NAME_LENGTH_MAX];
    char temp[LOAD_TOKEN_MAX];
    // execute pseudocode.
    int ps_id;

    // 疑似コードIDを取得
    ps_id = emul_inst_dec_get_pseudo(token);

    // 例外処理:疑似コードが見つからない
    if ( ps_id == PSEUDO_DECODE_ERROR ) {
        return Failed;
    }

    switch( ps_id ) {
    case DUMP:
        emul_inst_dec_get_token(temp);
        emul_inst_exec_pseudo_dump(temp);
        break;
    case MEMCAT:
        emul_inst_exec_pseudo_memcat(
	        emul_inst_dec_get_next_immediate()
        );
        break;
    case MEMCATW:
        emul_inst_exec_pseudo_memcatw(
            emul_inst_dec_get_next_immediate()
        );
        break;
    case REGCAT:
        emul_inst_exec_pseudo_regcat(
            emul_inst_dec_get_next_operand()
        );
        break;
    case LABEL:
        emul_inst_dec_get_token(label);
        emul_inst_exec_pseudo_label(
            label,
            emul_reg_get(Spc)
        );
        break;
    case RUN:
        emul_inst_exec_pseudo_run();
        break;
    case STEP:
        emul_inst_exec_pseudo_step();
        break;
    case INPUT:
        emul_inst_exec_pseudo_input(
            emul_inst_dec_get_next_operand()
        );
        break;
    case OUTPUT:
        emul_inst_exec_pseudo_output(
            emul_inst_dec_get_next_operand()
        );
        break;
    case CRLF:
        emul_inst_exec_pseudo_crlf();
        break;
    case EXEC:
        emul_inst_dec_get_token(label);
        emul_inst_exec_pseudo_exec(
            label
        );
        break;
    case EXIT:
        emul_inst_exec_pseudo_exit();
        break;
	default:
	    emul_out_std_debug("[疑似コード]まだ実装してないので待って!\n");
    }

    return Success;
}

/* Execute Step
 * RETURN:
 *   succsess: 1
 *   failed  : 0 */
exitcode_t emul_inst_exec_step()
#define COUNT_OPERAND_MAX 3
{
    char token[LOAD_TOKEN_MAX];
    int op_id, oprs[COUNT_OPERAND_MAX];
    int ps_id;
    int pc;

    int temp_op[3];
    char label[LABEL_NAME_LENGTH_MAX];

    emul_out_std_debug(">>>Start step\n");

    // トークンを取得
    if ( emul_inst_dec_get_token(token) == 0 ) {
        emul_out_std_err("Non exist next token\n");
        // 次のトークンが見つからない場合終了
        return Failed;
    }
    emul_out_std_debug("token: %s\n", token);
    // オペコードIDを取得
    op_id = emul_inst_dec_get_opecode(token);

    // 例外処理: オペコードが見つからない
    if ( op_id == OPECODE_DECODE_ERROR ) {
        emul_out_std_err("Non exist next operand\n");
        ps_id = emul_inst_dec_get_pseudo(token);
        // 例外処理:疑似コードが見つからない
        if ( ps_id == PSEUDO_DECODE_ERROR ) {
            emul_out_std_err("Non exist next pseudocode\n");
            return Continue;
        } else {
            // 疑似コードを実行
            return emul_inst_exec_pseudo(token);
        }
    }

    // オペコード実行
    switch (op_id) {
	case ADD :
	    temp_op[0] = emul_inst_dec_get_next_operand();
	    temp_op[1] = emul_inst_dec_get_next_operand();
	    temp_op[2] = emul_inst_dec_get_next_operand();
	    emul_inst_exec_add(temp_op[0], temp_op[1], temp_op[2]);
	    break;
	case ADDI:
	    temp_op[0] = emul_inst_dec_get_next_operand();
	    temp_op[1] = emul_inst_dec_get_next_operand();
	    temp_op[2] = emul_inst_dec_get_next_immediate();
	    emul_inst_exec_addi(temp_op[0], temp_op[1], temp_op[2]);
	    break;
	case SUB :
	    temp_op[0] = emul_inst_dec_get_next_operand();
	    temp_op[1] = emul_inst_dec_get_next_operand();
	    temp_op[2] = emul_inst_dec_get_next_operand();
	    emul_inst_exec_sub(temp_op[0], temp_op[1], temp_op[2]);
	    break;
	case SLT :
	    temp_op[0] = emul_inst_dec_get_next_operand();
	    temp_op[1] = emul_inst_dec_get_next_operand();
	    temp_op[2] = emul_inst_dec_get_next_operand();
        emul_inst_exec_slt(temp_op[0], temp_op[1], temp_op[2]);
	    break;
	case SLTI:
        temp_op[0] = emul_inst_dec_get_next_operand();
        temp_op[1] = emul_inst_dec_get_next_operand();
        temp_op[2] = emul_inst_dec_get_next_immediate();
        emul_inst_exec_slti(temp_op[0], temp_op[1], temp_op[2]);
	    break;
	case SEQ :
	    temp_op[0] = emul_inst_dec_get_next_operand();
	    temp_op[1] = emul_inst_dec_get_next_operand();
	    temp_op[2] = emul_inst_dec_get_next_operand();
	    emul_inst_exec_seq(temp_op[0], temp_op[1], temp_op[2]);
	    break;
	case SGE :
	    temp_op[0] = emul_inst_dec_get_next_operand();
	    temp_op[1] = emul_inst_dec_get_next_operand();
	    temp_op[2] = emul_inst_dec_get_next_operand();
	    emul_inst_exec_sge(temp_op[0], temp_op[1], temp_op[2]);
	    break;
	case SGT :
	    temp_op[0] = emul_inst_dec_get_next_operand();
	    temp_op[1] = emul_inst_dec_get_next_operand();
	    temp_op[2] = emul_inst_dec_get_next_operand();
	    emul_inst_exec_sgt(temp_op[0], temp_op[1], temp_op[2]);
	    break;
	case SLE :
	    temp_op[0] = emul_inst_dec_get_next_operand();
	    temp_op[1] = emul_inst_dec_get_next_operand();
	    temp_op[2] = emul_inst_dec_get_next_operand();
	    emul_inst_exec_sle(temp_op[0], temp_op[1], temp_op[2]);
	    break;
	case SNE :
	    temp_op[0] = emul_inst_dec_get_next_operand();
	    temp_op[1] = emul_inst_dec_get_next_operand();
	    temp_op[2] = emul_inst_dec_get_next_operand();
	    emul_inst_exec_sne(temp_op[0], temp_op[1], temp_op[2]);
	    break;
	//case B   :
	//    break;
	case BEQ :
	    temp_op[0] = emul_inst_dec_get_next_operand();
	    temp_op[1] = emul_inst_dec_get_next_operand();
	    emul_inst_dec_get_token(label);
	    emul_inst_exec_beq(temp_op[0], temp_op[1], label);
	    break;
	case BNE :
	    temp_op[0] = emul_inst_dec_get_next_operand();
	    temp_op[1] = emul_inst_dec_get_next_operand();
	    emul_inst_dec_get_token(label);
	    emul_inst_exec_bne(temp_op[0], temp_op[1], label);
	    break;
	case J   :
	    emul_inst_dec_get_token(label);
	    emul_inst_exec_j(label);
	    break;
	case JAL :
	    emul_inst_dec_get_token(label);
	    emul_inst_exec_jal(label);
	    break;
    case JALR:
	    temp_op[0] = emul_inst_dec_get_next_operand();
	    temp_op[1] = emul_inst_dec_get_next_operand();
        emul_inst_exec_jalr(temp_op[0], temp_op[1]);
        break;
    case JR  :
	    temp_op[0] = emul_inst_dec_get_next_operand();
        emul_inst_exec_jr(temp_op[0]);
        break;
	case LW  :
	    temp_op[0] = emul_inst_dec_get_next_operand();
	    temp_op[1] = emul_inst_dec_get_next_immediate();
	    temp_op[2] = emul_inst_dec_get_next_operand();
	    emul_inst_exec_lw(temp_op[0], temp_op[1], temp_op[2]);
	    break;
	case SW  :
	    temp_op[0] = emul_inst_dec_get_next_operand();
	    temp_op[1] = emul_inst_dec_get_next_immediate();
	    temp_op[2] = emul_inst_dec_get_next_operand();
	    emul_inst_exec_sw(temp_op[0], temp_op[1], temp_op[2]);
	    break;
	//case MOVE:
	    //break;
	default:
	    emul_out_std_debug("[オペコード]まだ実装してないので待って!\n");
    }
    //emul_inst_dec_get_operand(token);

    return Success;
}

/* Execute Run All
 * RETURN:
 *   succsess: 1
 *   failed  : 0 */
exitcode_t emul_inst_exec_run() {
    // step関数を終わるまで呼び出せばよい
    exitcode_t exit_code;
    emul_out_std_debug(">>>Start run\n");
    while ( (exit_code = emul_inst_exec_step()) == Success ) {
        if (RunMode == Step) {
            emul_out_std("...Wait for step, please input key enter.\n");
            getchar();
        } else if (RunMode == Exit) {
            emul_out_std_debug("Program Exit...\n");
            return Success;
        }
    }
    emul_out_std_debug("<<<Stop run\n");
    return exit_code;
}