// this function will be activated on ID stage. // it's mainly about recording forwarding data. // But it will also help branch do their forwarding // // for some instructions that don't need to fwd, // their reg_A, reg_B will be -1, // so it's impossible to have hazard detect here // // if reg_A and reg_B be -1, // the only cnd they will have hazard is // reg_EX = -1 or reg_EX = -1 // but it will fulfill the fwd cnd int hazard_check(int reg_EX, int reg_ME, int reg_A, int reg_B) { int result = 0, branch = 0; struct ins* i = CPU.pipeline[0]; int op_cur = i->opcode, func_cur = i->func; int op_ex = CPU.pipeline[1]->opcode; int op_me = CPU.pipeline[2]->opcode; int ex_cnd = ((reg_EX != -1) && (reg_EX != 0)) && (reg_EX == reg_A || reg_EX == reg_B); // make sure it is not access 0 int me_cnd = ((reg_ME != -1) && (reg_ME != 0)) && !(reg_EX == reg_ME) && (reg_ME == reg_A || reg_ME == reg_B); // make sure it is not access 0 int fwd_des = -1; //reg_A is rs, reg_B is rt //but for sll/srl/sra, reg_A is rt. //check if branch(jump) or not if(is_branch(_ID) || (op_cur == 0x00 && func_cur == _jr)) { branch = 1; fwd_des = _ID; } else fwd_des = _EX; //if they are not equals to -1, it means that it can forward now //this will happen only after stall, so the if(ex_cnd) and if(me_cnd) will not be trigger //branch/jump is ready to forward. if(branch && i->fwd_id) { //printf("do branch fowarding\n"); return 0; } //clean forwarding message after stall if(i->fwd_id || i->fwd_ex) { i->fwd_id = 0; i->fwd_ex = 0; i->fwd_to_s = -1; i->fwd_to_t = -1; } if(ex_cnd && notNOP(1)) { int load = 0; //if it is load, need to stall. It's because the data cannot be access at EX stage if(is_load(op_ex)) result = 1; else { fwd_signal(fwd_des, _EX, reg_EX, reg_A, reg_B); if(branch) result = 1; } } if(me_cnd && notNOP(2)) { // branch won't have chance to let ME-WB forward // when ID needs to compute, ME-WB might still not available // but when ME-WB is available // the data is already write back to register(first half cycle) if(!branch) fwd_signal(fwd_des, _ME, reg_ME, reg_A, reg_B); else { if(is_load(op_me)) result = 1; else if(!result) { fwd_signal(_ID, _EX, reg_ME, reg_A, reg_B); } } } return result; }
void alu_unit(int s, int t) { struct ins* i = CPU.pipeline[1]; int opc = i->opcode; short c = i->c; if(opc) { if(opc == _addi) addi(s, c); else if(opc == _halt) printf("encounter halt\n"); else if(is_load(opc) || is_store(opc)) load_store(s, c); else if(opc == _lui) lui(c); else if(opc == _andi) andi(s, c); else if(opc == _ori) ori(s, c); else if(opc == _nori) nori(s, c); else if(opc == _slti) slti(s, c); } else { int func = i->func; int shamt = i->shamt; if(func == _add) add(0, s, t); else if(func == _sub) add(1, s, t); else if(func == _and) and(0, s, t); else if(func == _or) or(0, s, t); else if(func == _xor) or(1, s, t); else if(func == _nor) or(2, s, t); else if(func == _nand) and(1, s, t); else if(func == _slt) slt(s, t); else if(func == _sll) sll(t, shamt); else if(func == _srl) sr(0, t, shamt); else if(func == _sra) sr(1, t, shamt); } }
// read a char from io buf inline char a2_io_readchar(struct a2_io* io_p){ assert(io_p); if(is_end(io_p)) return '\0'; if(is_load(io_p, 0)) _a2_io_load(io_p); return io_p->buf[io_p->seek++]; }
// match n char inline char a2_io_matchchar(struct a2_io* io_p, int n){ assert(io_p); if(_is_end(io_p, n)) return '\0'; else if (n<=0 && ((-n)<=io_p->seek) ) return io_p->buf[io_p->seek+n]; else if( n>0 && n<io_p->size){ if(is_load(io_p, n)) _a2_io_load(io_p); return io_p->buf[io_p->seek+n]; } return '\0'; }