%d READ_OP 0b0001
%d READ_RT 0b0010

declare mul_u32 interface
{
	input a<32>, b<32>;
	output dout<64>;
	instrin con;
	instr_arg con(a, b);
}

%i "div_u32.h"
%i "bsr_s32.h"

circuit R3000A
{
	instrin run;

	output A<32>, Word<3>;
	reg_wr A_reg<32>, Word_reg<3>;
	input Din<32>;

	reg_ws reset;
	instrself reset_act;

	instrin exe_set(hA, h_data);
	input hA<12>, h_data<8>;

	mem gpr[32]<32> = {
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
	};

	mem cpr0[32]<32> = {
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10900000, 0, 0, 2,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
	};

	reg_wr pc<32>;
	reg_wr hi<32>, lo<32>;

	reg_wr opcode<32>;

	instrself read(rid, A, Word);
	sel rid<4>;
	reg_wr rid_reg<4>;
	instrout read_req;
	instrin read_ack;

	instrself write(A, Dout, Word);
	instrout write_req;
	output Dout<32>;
	reg_wr Dout_reg<32>;

	instrself stage_IF;
	reg_wr stall_mem, stall_sys;
	reg_wr delay_slot_pre, delay_slot;

	instrself stage_ID;
	reg_wr op<8>; // 6bit
	reg_wr rs<5>, rt<5>, imm_immediate<16>;
	reg_wr rd<5>, reg_sa<5>;
	reg_wr funct<8>; // 6bit
	reg_wr jmp_target<26>;
	reg_wr id_pc<32>;

	instrself stage_EX;
	sel rs_data<32>, rt_data<32>, sa, adrs<32>;
	reg_wr rt_data_reg<32>, rd_data_reg<32>;
	reg_wr mem_op<8>; // 6bit;
	reg_wr mem_rt<5>;
	reg_wr cop_rs<5>;
	reg_wr mem_funct<8>; // 6bit;
	reg_wr mem_rd<5>;
	reg_wr cop_rd<5>;
	instrself read_rt, write_rt;
	instrself jump(jump_pc);
	sel jump_pc<32>, data<32>;
	reg_wr ex_pc<32>, ex_opcode<32>;
	sel cpr0_rd_data<32>;
	reg_wr cpr0_rd_data_reg<32>;
	instrself rt_data_set(data), rd_data_set(data);

	instrself stage_MEM;
	instrself write_mem_rt;
	reg_wr stall_mem2;
	reg_wr mem_A<32>;
	reg_wr mem_pc<32>, mem_adrs<32>;

	instrself stage_WB;

	instrself exception(exception_code);
	sel exception_code<32>;

	mul_u32 mul;
	reg_wr mul_a<32>, mul_b<32>, mulf_reg<2>;

	div_u32 div;
	sel div_n<32>, div_d<32>;
	reg_wr div_ns, div_ds, divf_reg<2>;
	bsr_s32 sra;

	instrin dma_wait_set(dma_size);
	input dma_size<32>;

	instrin interrupt_set(i_code);
	input i_code<32>;
	reg_wr i_code_reg<32>;
	input IRQ_in<16>;
	reg_wr irq_wait<28>, irq_run<2>;
	instrself irq_check;

	output pc_out<32>, opcode_out<32>;

	instrself halt(h_code);
	sel h_code<8>;
	reg_wr halt_code_reg<8>;
	output halt_code<8>;

	stage_name read_wait { task do(rid_reg); }
	stage_name mul_wait { task do(mulf_reg, mul_a, mul_b); }
	stage_name div_wait { task do(divf_reg); }

	par{
		if(reset){
			reset_act();
			reset := 0b0;
		}

		if(read | write){
			A_reg := A;
			Word_reg := Word;
		}
		else{
			A = A_reg;
			Word = Word_reg;
		}

		if(write) Dout_reg := Dout;
		else Dout = Dout_reg;

		halt_code = halt_code_reg;
		pc_out = pc;
		opcode_out = opcode;
	}

	instruct reset_act par{
		pc := 0xBFC00000;
		hi := 0x00000000;
		lo := 0x00000000;
	}

	instruct exe_set any{
		hA==0x010 : pc := pc<31:8> || h_data;
		hA==0x011 : pc := pc<31:16> || h_data || pc<7:0>;
		hA==0x012 : pc := pc<31:24> || h_data || pc<15:0>;
		hA==0x013 : pc := h_data || pc<23:0>;
		hA==0x014 : gpr[0x1C] := gpr[0x1C]<31:8> || h_data;
		hA==0x015 : gpr[0x1C] := gpr[0x1C]<31:16> || h_data || gpr[0x1C]<7:0>;
		hA==0x016 : gpr[0x1C] := gpr[0x1C]<31:24> || h_data || gpr[0x1C]<15:0>;
		hA==0x017 : gpr[0x1C] := h_data || gpr[0x1C]<23:0>;
		hA==0x030 : gpr[0x1D] := gpr[0x1D]<31:8> || h_data;
		hA==0x031 : gpr[0x1D] := gpr[0x1D]<31:16> || h_data || gpr[0x1D]<7:0>;
		hA==0x032 : gpr[0x1D] := gpr[0x1D]<31:24> || h_data || gpr[0x1D]<15:0>;
		hA==0x033 : gpr[0x1D] := h_data || gpr[0x1D]<23:0>;
	}

	instruct halt par{
		halt_code_reg := h_code;
	}

	instruct read par{
		read_req();
		generate read_wait.do(rid);
	}

	instruct write par{
		if(cpr0[0x0C]<16>==0) write_req();
	}

	instruct exception par{
		cpr0[13] := exception_code;

	//	if(delay_type==DELAY_SLOT){
	//		cpr0[13] |= 0x80000000;
	//		cpr0[14] = pc - 4;
	//	}
	//	else{
			if(irq_run==3){ // これどうなの?
				cpr0[14] := pc - 4;
				irq_run := 0;
			}
			else{
				cpr0[14] := pc - 8;
			}
	//	}

		if(cpr0[12]<22>){ // Status.bev
			jump(0xBFC00180);
		}
		else{
			jump(0x80000080);
		}

		cpr0[12] := cpr0[12]<31:6> || cpr0[12]<3:0> || 0b00;
	}

	instruct interrupt_set par{
		i_code_reg := i_code;
	}

	instruct irq_check par{
		if((IRQ_in!=0) & (irq_run==0)){
			if(cpr0[12]<10> & cpr0[12]<0>){
				irq_run := 1;
			}
		}
	}

	instruct run par{
		alt{
			irq_wait!=0 : irq_wait--;
			else : irq_check();
		}

		if(div_wait.do){
		}
		else{
			alt{
				write_mem_rt : stall_mem2 := 1;
				read_rt | write_rt : stall_mem := 1;
				irq_run==2 : irq_run := 3;
				else : stage_IF();
			}
			alt{
				exception : stall_sys := 1;
				stall_mem | write_mem_rt : ;
				else : stage_ID();
			}
			alt{
				stall_mem | stall_sys : par{
					stall_mem := 0;
					stall_sys := 0;
				}
				else : par{
					if(write_mem_rt);
					else stage_EX();
					if(stall_mem2) stall_mem2 := 0;
					else stage_MEM();
					stage_WB();
				}
			}
		}
	}

	instruct stage_IF par{
		alt{
			jump : par{
				read(READ_OP, jump_pc, 4);
				pc := jump_pc + 4;
				id_pc := jump_pc;
				delay_slot_pre := 1;
			}
			else : par{
				read(READ_OP, pc, 4);
				pc += 4;
				id_pc := pc;
				delay_slot_pre := 0;
			}
		}
		delay_slot := delay_slot_pre;
	}

	instruct stage_ID par{
		op := 0b00 || opcode<31:26>;
		rs := opcode<25:21>;
		rt := opcode<20:16>;
		imm_immediate := opcode<15:0>;

		rd := opcode<15:11>;
		reg_sa := opcode<10:6>;
		funct := 0b00 || opcode<5:0>;

		// jmp_op := <31:26>
		jmp_target := opcode<25:0>;

		ex_pc := id_pc;
		ex_opcode := opcode;
	}

	instruct rt_data_set par{
		rt_data_reg := data;
		mem_rt := rt;
		mem_rd := 0;
	}

	instruct rd_data_set par{
		rd_data_reg := data;
		mem_rt := 0;
		mem_rd := rd;
	}

	instruct stage_EX par{

		alt{
			rs==0 : rs_data = 0x00000000;
			(mem_op==0x00) & (rs==mem_rd) : par{
				rs_data = rd_data_reg;
			}
			rs==mem_rt : par{
				rs_data = rt_data_reg;
			}
			else : rs_data = gpr[rs];
		}

		alt{
			rt==0 : rt_data = 0x00000000;
			(mem_op==0x00) & (rt==mem_rd) : par{
				rt_data = rd_data_reg;
			}
			rt==mem_rt : par{
				rt_data = rt_data_reg;
			}
			else : rt_data = gpr[rt];
		}

		cpr0_rd_data = cpr0[rd];

		any{
			op==0x00 : any{ // SPECIAL
				funct==0x00 : par{ // SLL
					rd_data_set(rt_data << reg_sa);
				}
				funct==0x02 : par{ // SRL
					rd_data_set(rt_data >> reg_sa);
				}
				funct==0x03 : par{ // SRA
					rd_data_set(sra.con(rt_data, reg_sa).dout);
				}
				funct==0x04 : par{ // SLLV
					rd_data_set(rt_data << rs_data<4:0>);
				}
				funct==0x06 : par{ // SRLV
					rd_data_set(rt_data >> rs_data<4:0>);
				}
				funct==0x07 : par{ // SRAV
					rd_data_set(sra.con(rt_data, rs_data<4:0>).dout);
				}
				funct==0x08 : par{ // JR
					jump(rs_data);
					mem_rd := 0; mem_rt := 0;
				}
				funct==0x09 : par{ // JALR
					rd_data_set(pc);
					jump(rs_data);
				}
				funct==0x0C : par{ // SYSCALL
					if(irq_run==3) exception(0x00000400);
					else exception(0x00000020);
					mem_rd := 0; mem_rt := 0;
				}
				funct==0x10 : par{ // MFHI
					rd_data_set(hi);
				}
				funct==0x11 : par{ // MTHI
					hi := rs_data;
					mem_rd := 0; mem_rt := 0;
				}
				funct==0x12 : par{ // MFLO
					rd_data_set(lo);
				}
				funct==0x13 : par{ // MTLO
					lo := rs_data;
					mem_rd := 0; mem_rt := 0;
				}
				funct==0x18 : par{ // MULT
					generate mul_wait.do(1, rs_data, rt_data);
					mem_rd := 0; mem_rt := 0;
				}
				funct==0x19 : par{ // MULTU
					generate mul_wait.do(2, rs_data, rt_data);
					mem_rd := 0; mem_rt := 0;
				}
				funct==0x1A : par{ // DIV
					if(rs_data<31>) div_n = -rs_data;
					else div_n = rs_data;
					if(rt_data<31>) div_d = -rt_data;
					else div_d = rt_data;
					div.con(div_n, div_d);
					div_ns := rs_data<31>;
					div_ds := rt_data<31>;
					generate div_wait.do(1);
					mem_rd := 0; mem_rt := 0;
				}
				funct==0x1B : par{ // DIVU
					div.con(rs_data, rt_data);
					generate div_wait.do(2);
					mem_rd := 0; mem_rt := 0;
				}
				funct==0x20 : par{ // ADD
					rd_data_set(rs_data + rt_data);
				}
				funct==0x21 : par{ // ADDU
					rd_data_set(rs_data + rt_data);
				}
				funct==0x23: par{ // SUBU
					rd_data_set(rs_data - rt_data);
				}
				funct==0x24 : par{ // AND
					rd_data_set(rs_data & rt_data);
				}
				funct==0x25 : par{ // OR
					rd_data_set(rs_data | rt_data);
				}
				funct==0x26 : par{ // XOR
					rd_data_set(rs_data @ rt_data);
				}
				funct==0x27 : par{ // NOR
					rd_data_set(^(rs_data | rt_data));
				}
				funct==0x2A : par{ // SLT
					sa = ((33#rs_data) - (33#rt_data))<32>;
					rd_data_set(0x0000000||0b000||sa);
				}
				funct==0x2B : par{ // SLTU
					sa = ((0b0 || rs_data) - (0b0 || rt_data))<32>;
					rd_data_set(0x0000000||0b000||sa);
				}
				else : halt(0x02);
			}
			op==0x01 : any{
				rt==0 : par{ // BLTZ
					data = 0x0000000||0b000||rs_data<31>;
					if(rs_data<31>){
						jump(pc + ((32#imm_immediate)<29:0>||0b00) - 4);
					}
					mem_rt := 0; mem_rd := 0;
				}
				rt==1 : par{ // BGEZ
					data = 0x0000000||0b000||((^rs_data<31>) | (rs_data==0));
					if((^rs_data<31>) | (rs_data==0)){
						jump(pc + ((32#imm_immediate)<29:0>||0b00) - 4);
					}
					mem_rt := 0; mem_rd := 0;
				}
				else : halt(0x03);
			}
			op==0x02 : par{ // J
				jump(pc<31:28>||jmp_target||0b00);
				mem_rt := 0; mem_rd := 0;
			}
			op==0x03 : par{ // JAL
				rt_data_reg := pc; // IFで+4,IDで+4しているので合わせて+8
				mem_rt := 31; mem_rd := 0;
				jump(pc<31:28>||jmp_target||0b00);
			}
			op==0x04 : par{ // BEQ
				if(rs_data==rt_data){
					jump(pc + ((32#imm_immediate)<29:0>||0b00) - 4);
				}
				mem_rt := 0; mem_rd := 0;
			}
			op==0x05 : par{ // BNE
				if(rs_data!=rt_data){
					jump(pc + ((32#imm_immediate)<29:0>||0b00) - 4);
				}
				mem_rt := 0; mem_rd := 0;
			}
			op==0x06 : par{ // BLEZ
				data = 0x0000000||0b000||(rs_data<31> | (rs_data==0));
				if(rs_data<31> | (rs_data==0)){
					jump(pc + ((32#imm_immediate)<29:0>||0b00) - 4);
				}
				mem_rt := 0; mem_rd := 0;
			}
			op==0x07 : par{ // BGTZ
				data = 0x0000000||0b000||((rs_data<31>==0) & (rs_data!=0));
				if((rs_data<31>==0) & (rs_data!=0)){
					jump(pc + ((32#imm_immediate)<29:0>||0b00) - 4);
				}
				mem_rt := 0; mem_rd := 0;
			}
			op==0x08 : par{ // ADDI
				rt_data_set((32#imm_immediate) + rs_data);
			}
			op==0x09 : par{ // ADDIU
				rt_data_set((32#imm_immediate) + rs_data);
			}
			op==0x0A : par{ // SLTI
				sa = ((33#rs_data) - (33#imm_immediate))<32>;
				rt_data_set(0x0000000||0b000||sa);
			}
			op==0x0B : par{ // SLTIU
				sa = ((0b0 || rs_data) - (0b0 || 0x0000 || imm_immediate))<32>;
				rt_data_set(0x0000000||0b000||sa);
			}
			op==0x0C : par{ // ANDI
				rt_data_set((0x0000||imm_immediate) & rs_data);
			}
			op==0x0D : par{ // ORI
				rt_data_set((0x0000||imm_immediate) | rs_data);
			}
			op==0x0E : par{ // XORI
				rt_data_set((0x0000||imm_immediate) @ rs_data);
			}
			op==0x0F : par{ // LUI
				rt_data_set(imm_immediate || 0x0000);
			}
			op==0x10 : any{ // COP0
				rs==0 : par{ // MFC0
					rt_data_set(cpr0_rd_data);
					cop_rs := rs;
				}
				rs==4 : par{ // 0x04 // MTC0
					any{
						rd==12 : par{
							cpr0_rd_data_reg := rt_data;
						}
						rd==13: par{
							cpr0_rd_data_reg := rt_data & 0xFFFF03FF;
						}
						(rd==6) | (rd==8) | (rd==14) | (rd==15) : ; // none
						else : par{
							cpr0_rd_data_reg := rt_data;
						}
					}
					mem_rt := 0; mem_rd := 0;
					cop_rs := rs; cop_rd := rd;
				}
				rs==16 : par{
					any{
						funct==0x10 : par{ // RFE
							cpr0[12] := cpr0[12]<31:4> || cpr0[12]<5:2>;
						}
					}
					cop_rs := rs;
					mem_rt := 0; mem_rd := 0;
				}
			}
			op==0x20 : par{ // LB
				adrs = rs_data + (32#imm_immediate);
				read(READ_RT, adrs, 1);
				read_rt();
				mem_rt := rt; mem_rd := 0;
				mem_adrs := adrs;
			}
			op==0x21 : par{ // LH
				adrs = rs_data + (32#imm_immediate);
				read(READ_RT, adrs, 2);
				read_rt();
				mem_rt := rt; mem_rd := 0;
				mem_adrs := adrs;
			}
			op==0x22 : par{ // LWL
				adrs = rs_data + (32#imm_immediate);
				read(READ_RT, adrs<31:2>||0b00, 4);
				read_rt();
				mem_rt := rt; mem_rd := 0;
				rt_data_reg := rt_data;
				mem_A := adrs;
				mem_adrs := adrs<31:2>||0b00;
			}
			op==0x23 : par{ // LW
				adrs = rs_data + (32#imm_immediate);
				read(READ_RT, adrs, 4);
				read_rt();
				mem_rt := rt; mem_rd := 0;
				mem_adrs := adrs;
			}
			op==0x24 : par{ // LBU
				adrs = rs_data + (32#imm_immediate);
				read(READ_RT, adrs, 1);
				read_rt();
				mem_rt := rt; mem_rd := 0;
				mem_adrs := adrs;
			}
			op==0x25 : par{ // LHU
				adrs = rs_data + (32#imm_immediate);
				read(READ_RT, adrs, 2);
				read_rt();
				mem_rt := rt; mem_rd := 0;
				mem_adrs := adrs;
			}
			op==0x26 : par{ // LWR
				adrs = rs_data + (32#imm_immediate);
				read(READ_RT, adrs<31:2>||0b00, 4);
				read_rt();
				mem_rt := rt; mem_rd := 0;
				rt_data_reg := rt_data;
				mem_A := adrs;
				mem_adrs := adrs<31:2>||0b00;
			}
			op==0x28 : par{ // SB
				write(rs_data + (32#imm_immediate), 0x000000||rt_data<7:0>, 1);
				write_rt();
				mem_rt := 0; mem_rd := 0;
			}
			op==0x29 : par{ // SH
				write(rs_data + (32#imm_immediate), 0x0000||rt_data<15:0>, 2);
				write_rt();
				mem_rt := 0; mem_rd := 0;
			}
			op==0x2A : par{ // SWL
				adrs = rs_data + (32#imm_immediate);
				read(READ_RT, adrs<31:2>||0b00, 4);
				read_rt();
				mem_rt := 0; mem_rd := 0;
				rt_data_reg := rt_data;
				mem_A := adrs;
				mem_adrs := adrs<31:2>||0b00;
			}
			op==0x2B : par{ // SW
				write(rs_data + (32#imm_immediate), rt_data, 4);
				write_rt();
				mem_rt := 0; mem_rd := 0;
			}
			op==0x2E : par{ // SWR
				adrs = rs_data + (32#imm_immediate);
				read(READ_RT, adrs<31:2>||0b00, 4);
				read_rt();
				mem_rt := 0; mem_rd := 0;
				rt_data_reg := rt_data;
				mem_A := adrs;
				mem_adrs := adrs<31:2>||0b00;
			}
			else : halt(0x01);
		}

		mem_op := op;
		mem_funct := funct;

		mem_pc := ex_pc;
	}

	instruct stage_MEM par{

		any{
			mem_op==0x00 : any{
				(mem_funct==0x00) | (mem_funct==0x02) | (mem_funct==0x03) |
				(mem_funct==0x04) | (mem_funct==0x06) | (mem_funct==0x07) |
				(mem_funct==0x09) |
				(mem_funct==0x10) | (mem_funct==0x12) |
				(mem_funct==0x20) | (mem_funct==0x21) | (mem_funct==0x23) |
				(mem_funct==0x24) | (mem_funct==0x25) | (mem_funct==0x26) | (mem_funct==0x27) |
				(mem_funct==0x2A) | (mem_funct==0x2B) : par{
					gpr[mem_rd] := rd_data_reg;
				}
			}
			mem_op==0x10 : any{
				cop_rs==0 : par{
					gpr[mem_rt] := rt_data_reg;
				}
				cop_rs==4 : par{
					cpr0[cop_rd] := cpr0_rd_data_reg;
				}
			}
			(mem_op==0x03) |
			(mem_op==0x08) | (mem_op==0x09) | (mem_op==0x0A) | (mem_op==0x0B) |
			(mem_op==0x0C) | (mem_op==0x0D) | (mem_op==0x0E) | (mem_op==0x0F) |
			(mem_op==0x20) | (mem_op==0x21) | (mem_op==0x22) | (mem_op==0x23) |
			(mem_op==0x24) | (mem_op==0x25) | (mem_op==0x26) : par{
				gpr[mem_rt] := rt_data_reg;
			}
			(mem_op==0x2A) | (mem_op==0x2E) : par{
				write(mem_A<31:2>||0b00, rt_data_reg, 4);
				write_mem_rt();
			}
		}
	}

	instruct stage_WB par{

	}

	stage read_wait {
		sel din_half<16>, din_byte<8>;
		if(read_ack){
			any{
				Word_reg==4 : ;
				Word_reg==2 : any{
					A_reg<1>==0b0 : din_half = Din<15:0>;
					A_reg<1>==0b1 : din_half = Din<31:16>;
				}
				Word_reg==1 : any{
					A_reg<1:0>==0b00 : din_byte = Din<7:0>;
					A_reg<1:0>==0b01 : din_byte = Din<15:8>;
					A_reg<1:0>==0b10 : din_byte = Din<23:16>;
					A_reg<1:0>==0b11 : din_byte = Din<31:24>;
				}
			}
			any{
				rid_reg==READ_OP : par{
					if((irq_run==1) & (^delay_slot)){
						opcode := 0x0000000C; // IRQ
						irq_run := 2;
					}
					else any{
						Word_reg==4 : opcode := Din;
						Word_reg==2 : opcode := 0x0000 || din_half;
						Word_reg==1 : opcode := 0x000000 || din_byte;
					}
				}
				rid_reg==READ_RT : any{
					Word_reg==4 : any{
						mem_op==0x22 : any{
							mem_A<1:0>==0 : rt_data_reg := Din< 7:0> || rt_data_reg<23:0>;
							mem_A<1:0>==1 : rt_data_reg := Din<15:0> || rt_data_reg<15:0>;
							mem_A<1:0>==2 : rt_data_reg := Din<23:0> || rt_data_reg< 7:0>;
							mem_A<1:0>==3 : rt_data_reg := Din;
						}
						mem_op==0x26 : any{
							mem_A<1:0>==0 : rt_data_reg := Din;
							mem_A<1:0>==1 : rt_data_reg := rt_data_reg<31:24> || Din<31: 8>;
							mem_A<1:0>==2 : rt_data_reg := rt_data_reg<31:16> || Din<31:16>;
							mem_A<1:0>==3 : rt_data_reg := rt_data_reg<31: 8> || Din<31:24>;
						}
						mem_op==0x2A : any{
							mem_A<1:0>==0 : rt_data_reg := Din<31: 8> || rt_data_reg<31:24>;
							mem_A<1:0>==1 : rt_data_reg := Din<31:16> || rt_data_reg<31:16>;
							mem_A<1:0>==2 : rt_data_reg := Din<31:24> || rt_data_reg<31: 8>;
							mem_A<1:0>==3 : ;
						}
						mem_op==0x2E : any{
							mem_A<1:0>==0 : ;
							mem_A<1:0>==1 : rt_data_reg := rt_data_reg<23:0> || Din< 7:0>;
							mem_A<1:0>==2 : rt_data_reg := rt_data_reg<15:0> || Din<15:0>;
							mem_A<1:0>==3 : rt_data_reg := rt_data_reg<7: 0> || Din<23:0>;
						}
						else : rt_data_reg := Din;
					}
					Word_reg==2 : any{
						mem_op==0x21 : rt_data_reg := 32#din_half;
						mem_op==0x25 : rt_data_reg := 0x0000 || din_half;
					}
					Word_reg==1 : any{
						mem_op==0x20 : rt_data_reg := 32#din_byte;
						mem_op==0x24 : rt_data_reg := 0x000000 || din_byte;
					}
				}

			}
			finish;
		}
	}

	stage mul_wait {
		sel as<32>, bs<32>;
		sel mul_dout<64>;
		par{
			any{
				mulf_reg==1 : par{ // MULT
					if(mul_a<31>) as = -mul_a;
					else as = mul_a;
					if(mul_b<31>) bs = -mul_b;
					else bs = mul_b;
					mul.con(as, bs);
					if(mul_a<31> @ mul_b<31>) mul_dout = -mul.dout;
					else mul_dout = mul.dout;
					lo := mul_dout<31:0>;
					hi := mul_dout<63:32>;
				}
				mulf_reg==2 : par{ // MULTU
					mul.con(mul_a, mul_b);
					lo := mul.dout<31:0>;
					hi := mul.dout<63:32>;
				}
			}
			finish;
		}
	}

	stage div_wait {
		if(div.ack){
			any{
				divf_reg==1 : par{ // DIV
					if(div_ns@div_ds) lo := -div.q;
					else lo := div.q;
					if(div_ns) hi := -div.r;
					else hi := div.r;
				}
				divf_reg==2 : par{ // DIVU
					lo := div.q;
					hi := div.r;
				}
			}
			finish;
		}
	}
}