blob: d63e7fdf2520b0b58da810a923b9508191ee5a59 [file] [log] [blame]
/*
*
* This file is part of the Elpis processor project.
*
* Copyright © 2020-present. All rights reserved.
* Authors: Aurora Tomas and Rodrigo Huerta.
*
* This file is licensed under both the BSD-3 license for individual/non-commercial
* use. Full text of both licenses can be found in LICENSE file.
*/
`default_nettype none
`ifdef TESTS
`include "elpis/definitions.v"
`else
`include "/project/openlane/user_proj_example/../../verilog/rtl/elpis/definitions.v"
`endif
module datapath #(parameter CORE_ID=0) (
input clk,
input reset,
input[31:0] mem_data_rd_f,
input[31:0] mem_data_rd_m,
input hit_icache,
input hit_dcache,
input hit_itlb,
input hit_dtlb,
input[31:0] read_interactive_value,
input is_read_interactive_enabled,
output[31:0] mem_addr_f,
output[31:0] mem_addr_m,
output[31:0] mem_data_wr,
output mem_wrd,
output dcache_re,
output mem_isbyte,
output reset_mem_req,
output privilege_mode, // PSW/rm3
output is_tlbwrite,
output[31:0] current_address_rm2,
output[19:0] mem_physical_tlb_addr_out,
output[31:0] exception_type,
output[31:0] print_output,
output print_hex_enable,
output read_interactive_req,
input is_print_done
);
wire stall_icache, stall_dcache;
wire[31:0] global_rm0; // PC of current exception (if exists)
wire[31:0] branch_or_jump_address_wire;
wire is_branch_or_jump_taken_wire, is_iret_wire;
reg is_iret_ff;
reg flush;
reg boot;
wire[3:0] id_alu_op;
wire id_reg_we;
wire[4:0] id_reg_src1_addr, id_reg_src2_addr, id_reg_dest_addr;
wire[31:0] id_reg_a_content, id_reg_b_content;
wire[2:0] id_branch_code;
wire id_is_a_jump;
wire id_regb_immed;
wire[31:0] id_immediate;
wire id_mem_to_reg;
wire id_mem_we;
wire id_stall;
wire id_is_byte, id_is_ecall, id_is_iret;
wire[1:0] id_is_mov;
wire[6:0] id_io_code;
wire[31:0] id_is_illegal;
wire[31:0] id_reg_rm, id_rm2, id_rm1, id_rm0, id_current_rm1, id_current_rm2, id_current_rm4;
wire id_is_tlbwrite, is_iret, id_hit_itlb;
wire[31:0] id_reg_dest_value;
wire[31:0] ex_reg_a, ex_reg_b;
wire[31:0] ex_res_alu, ex_res_mul;
wire[31:0] ex_reg_opX, ex_reg_opY;
wire[3:0] ex_alu_op;
wire[4:0] ex_reg_addr_dest;
wire ex_z;
wire ex_reg_write_enable;
wire ex_mem_to_reg;
wire ex_mem_we;
wire ex_is_branch_taken;
wire[31:0] ex_immed;
wire ex_regb_immed;
wire[31:0] ex_pc;
wire[2:0] ex_branch_code;
wire ex_is_a_jump;
wire[4:0] ex_reg_a_addr, ex_reg_b_addr;
wire[31:0] ex_exc_code;
wire[31:0] ex_rm0, ex_rm1, ex_rm2;
wire ex_is_byte, ex_pend_haz, ex_is_ecall;
wire[1:0] ex_is_mov;
wire[6:0] ex_io_code;
wire[31:0] ex_reg_rm, ex_reg_rm3, ex_current_rm1, ex_current_rm2, ex_current_rm4, ex_physical_tlb_addr;
wire ex_is_tlbwrite, ex_is_iret, ex_hit_itlb;
wire mem_z;
wire[31:0] mem_branch_or_jump_address;
wire mem_is_branch_taken;
wire mem_is_a_jump;
wire mem_is_branch_or_jump_taken;
wire mem_reg_write_enable;
wire[4:0] mem_reg_addr_dest;
wire[31:0] mem_reg_data;
wire mem_mem_to_reg;
wire mem_mem_we;
wire[31:0] mem_reg_b;
wire[31:0] mem_rm0, mem_rm1, mem_rm2, mem_rm3, mem_current_rm1, mem_current_rm2, mem_current_rm4, mem_physical_tlb_addr;
wire mem_is_byte;
wire[1:0] mem_is_mov;
wire[4:0] mem_reg_b_addr;
wire[6:0] mem_io_code;
wire mem_is_iret, mem_hit_itlb, mem_is_ecall, mem_is_tlbwrite;
wire[31:0] mem_pc;
wire mem_stall_read_sw;
wire[31:0] wb_alu_res;
wire[31:0] wb_current_rm4;
wire[4:0] wb_addr_d, wb_addr_d_from_mem, wb_addr_d_from_m5;
wire wb_reg_write_enable, wb_reg_write_enable_from_mem, wb_reg_write_enable_from_m5;
wire[31:0] wb_data_to_reg, wb_data_to_reg_from_mem, wb_data_to_reg_from_m5;
wire[31:0] wb_rm0, wb_rm1, wb_rm2;
wire wb_is_iret, wb_hit_dtlb, wb_hit_itlb;
wire[1:0] wb_is_mov;
wire[6:0] wb_io_code;
wire[31:0] wb_pc;
wire[31:0] wb_read_interactive_value;
wire wb_read_interactive_enable;
// SB
wire was_stall_dcache, sb_data_to_cache_aux_in, sb_data_to_cache_aux_out, sb_hit_aux_in,sb_hit_aux_out, sb_is_byte_aux_out, sb_is_byte_aux_in;
wire[31:0] sb_addr_out_aux_in, sb_data_out_aux_in, sb_addr_out_aux_out, sb_data_out_aux_out;
wire sb_hit, sb_full, sb_empty, sb_is_byte, sb_continue_drain_out, sb_data_to_cache_out, sb_drain;
wire wb_or_hf_reg_write_enable;
wire[31:0] wb_or_hf_data_to_reg;
wire[4:0] wb_or_hf_addr_to_reg;
wire[31:0] wb_or_hf_rm0, wb_or_hf_rm1, wb_or_hf_rm2;
wire id_is_flush, ex_is_flush, mem_is_flush, wb_is_flush;
wire is_exception, is_exception_reached;
reg is_exception_pending;
reg f_PSW;
wire id_PSW, ex_PSW, mem_PSW, wb_PSW;
wire stall_print;
// DEBUG
// Number of current cycle
reg[31:0] cycleNumber;
initial cycleNumber = 0;
always@(posedge clk) cycleNumber = cycleNumber + 1'b1;
// IF stage
reg[31:0] pc;
wire[31:0] pc_next, id_pc, id_inst, f_pc;
always@(reset or is_branch_or_jump_taken_wire)
begin
if(reset) begin
flush <= 1'b1;
end
else begin
flush <= is_branch_or_jump_taken_wire;
end
end
assign stall_icache = !hit_icache;
// Trigger flush memory request in case of exception
assign is_exception = is_exception_pending || is_exception_reached;
assign reset_mem_req = is_exception;
reg[31:0] branch_or_jump_address_ff;
reg is_branch_or_jump_taken_ff;
reg was_a_stall;
assign branch_or_jump_address_wire = was_a_stall ? ((is_iret_wire) ? global_rm0 : branch_or_jump_address_ff) : ((is_iret_wire) ? global_rm0 : mem_branch_or_jump_address);
assign is_branch_or_jump_taken_wire = was_a_stall ? is_branch_or_jump_taken_ff : mem_is_branch_or_jump_taken;
assign is_iret_wire = was_a_stall ? is_iret_ff : mem_is_iret;
always@(posedge clk) begin
if (reset) begin
pc <= `PC_INITIAL;
was_a_stall <= 1'b0;
is_branch_or_jump_taken_ff <= 1'b0;
f_PSW <= 1'b1;
is_iret_ff <= 1'b0;
boot <= 1'b1;
is_exception_pending <= 1'b0;
end else if (is_exception | boot) begin
pc <= `PC_EXCEPTIONS;
f_PSW <= 1'b1;
boot <= 1'b0;
is_exception_pending <= 1'b0;
end else if ((id_stall | stall_icache | stall_dcache | mem_stall_read_sw | stall_print)) begin
pc <= pc;
was_a_stall <= 1'b1;
f_PSW <= f_PSW;
if(mem_is_branch_or_jump_taken) begin
branch_or_jump_address_ff <= is_branch_or_jump_taken_ff ? branch_or_jump_address_ff : mem_branch_or_jump_address;
is_branch_or_jump_taken_ff <= mem_is_branch_or_jump_taken;
is_iret_ff <= mem_is_iret;
end
is_exception_pending <= is_exception_pending || is_exception_reached;
end else begin
pc <= (is_branch_or_jump_taken_wire == 1'b0) ? pc_next : branch_or_jump_address_wire;
was_a_stall <= 1'b0;
is_branch_or_jump_taken_ff <= 1'b0;
f_PSW <= is_iret_wire ? 1'b0 : f_PSW;
is_iret_ff <= 1'b0;
is_exception_pending <= is_exception_pending || is_exception_reached;
end
end
assign pc_next = pc+4;
assign mem_addr_f = pc;
wire[31:0] f_inst = mem_data_rd_f;
wire[31:0] f_exc_code_in = (!hit_itlb && !privilege_mode) ? `EXC_ITLB_MISS : 0;
IF_ID IF_ID(.clk(clk), .stall_icache(stall_icache), .stall(id_stall | stall_dcache | (sb_drain && sb_full) | stall_print), .flush(flush | is_exception | mem_stall_read_sw), .pc_in(pc),
.psw_in(f_PSW), .is_flush_in(1'b0),
.inst_in(f_inst), .is_hit_itlb_in(hit_itlb), .exc_code_in(f_exc_code_in), .pc_out(id_pc), .inst_out(id_inst), .is_hit_itlb_out(id_hit_itlb), .rm2_out(id_rm2),
.psw_out(id_PSW), .rm1_out(id_rm1), .rm0_out(id_rm0), .is_flush_out(id_is_flush));
// ID stage
assign id_reg_src1_addr = id_inst[19:15];
assign id_reg_src2_addr = id_inst[24:20];
hazardDetectionUnit hazardDetectionUnit(
.ex_reg_dest_addr_in(ex_reg_addr_dest),
.ex_mem_read_in(ex_mem_to_reg),
.id_reg_a_addr_in(id_reg_src1_addr),
.id_reg_b_addr_in(id_reg_src2_addr),
.stall_out(id_stall)
);
controlunit controlunit(
.rst(reset),
.ir(id_inst),
.op_alu(id_alu_op),
.wrd_reg(id_reg_we),
.addr_d(id_reg_dest_addr),
.rb_immed(id_regb_immed),
.imm(id_immediate),
.mem_to_reg(id_mem_to_reg),
.wrd_mem(id_mem_we),
.branch_code(id_branch_code),
.is_a_jump(id_is_a_jump),
.is_byte(id_is_byte),
.is_mov(id_is_mov),
.is_illegal(id_is_illegal),
.is_tlbwrite(id_is_tlbwrite),
.is_iret(id_is_iret),
.is_ecall(id_is_ecall),
.io_code(id_io_code)
);
regfile regfile(
.clk(clk),
.reset(reset),
.wrd(wb_or_hf_reg_write_enable),
.d(wb_or_hf_data_to_reg),
.addr_a(id_reg_src1_addr),
.addr_b(id_reg_src2_addr),
.addr_d(wb_or_hf_addr_to_reg),
.a(id_reg_a_content),
.b(id_reg_b_content),
.dest_read(id_reg_dest_addr),
.dest_value(id_reg_dest_value)
);
specialreg specialreg(
.clk(clk),
.reset(reset),
.in_rm0(wb_or_hf_rm0),
.in_rm1(wb_or_hf_rm1),
.in_rm2(is_branch_or_jump_taken_wire ? 0 : wb_or_hf_rm2),
.in_other_rm(wb_data_to_reg),
.sel(id_reg_src2_addr[2:0]),
.we(wb_is_mov == `MOV_REGULAR_TO_RM || wb_read_interactive_enable),
.out_rm0(global_rm0),
.out_rm1(id_current_rm1),
.out_rm2(id_current_rm2),
.out_rm(id_reg_rm),
.out_rm4(id_current_rm4)
);
ID_EX ID_EX(.clk(clk), .flush(flush | is_exception), .haz(id_stall | ex_pend_haz), .stall(stall_dcache | (sb_drain && sb_full) | mem_stall_read_sw | stall_print), .reg_a_in(id_reg_a_content), .reg_b_in(id_reg_b_content), .alu_op_in(id_alu_op),
.reg_addr_dest_in(id_reg_dest_addr), .reg_write_enable_in(id_reg_we), .rb_imm_in(id_regb_immed), .immed_in(id_immediate), .io_code_in(id_io_code),
.mem_to_reg_in(id_mem_to_reg), .mem_we_in(id_mem_we), .pc_in(id_pc), .branch_code_in(id_branch_code), .is_flush_in(1'b0),
.is_a_jump_in(id_is_a_jump), .reg_a_addr_in(id_reg_src1_addr), .reg_b_addr_in(id_reg_src2_addr), .is_byte_in(id_is_byte),
.is_mov_in(id_is_mov), .reg_rm_in(id_reg_rm), .psw_in(id_PSW), .exc_code_in(id_is_illegal), .is_tlbwrite_in(id_is_tlbwrite), .is_iret_in(id_is_iret), .is_ecall_in(id_is_ecall),
.is_hit_itlb_in(id_hit_itlb), .rm2_in(id_rm2), .rm1_in(id_rm1), .rm0_in(id_rm0), .stored_rm1_in(id_current_rm1), .stored_rm2_in(id_current_rm2), .stored_rm4_in(id_current_rm4), .fw_reg_a_in(ex_reg_opX), .fw_reg_b_in(ex_reg_opY),
.reg_a_out(ex_reg_a), .reg_b_out(ex_reg_b), .alu_op_out(ex_alu_op), .reg_addr_dest_out(ex_reg_addr_dest), .reg_write_enable_out(ex_reg_write_enable),
.rb_imm_out(ex_regb_immed), .immed_out(ex_immed), .mem_to_reg_out(ex_mem_to_reg), .mem_we_out(ex_mem_we), .pc_out(ex_pc), .io_code_out(ex_io_code),
.branch_code_out(ex_branch_code), .is_a_jump_out(ex_is_a_jump), .reg_a_addr_out(ex_reg_a_addr), .reg_b_addr_out(ex_reg_b_addr), .is_flush_out(ex_is_flush),
.is_byte_out(ex_is_byte), .is_mov_out(ex_is_mov), .reg_rm_out(ex_reg_rm), .psw_out(ex_PSW), .stored_rm1_out(ex_current_rm1), .stored_rm2_out(ex_current_rm2), .stored_rm4_out(ex_current_rm4),
.is_tlbwrite_out(ex_is_tlbwrite), .is_iret_out(ex_is_iret), .is_hit_itlb_out(ex_hit_itlb), .rm2_out(ex_rm2), .rm1_out(ex_rm1), .rm0_out(ex_rm0), .pending_haz(ex_pend_haz), .is_ecall_out(ex_is_ecall));
// EX stage
wire[1:0] ex_forward_x, ex_forward_y;
forwardingunit forwardingunit(
.ex_reg_a_in(ex_reg_a_addr),
.ex_reg_b_in(ex_reg_b_addr),
.mem_reg_d_in(mem_reg_addr_dest),
.wb_reg_d_in(wb_addr_d),
.mem_reg_we_in(mem_reg_write_enable),
.wb_reg_we_in(wb_reg_write_enable),
.forward_x(ex_forward_x),
.forward_y(ex_forward_y)
);
mux3_1 muxOpX(ex_forward_x, ex_reg_a, wb_data_to_reg, mem_reg_data, ex_reg_opX);
mux3_1 muxOpY(ex_forward_y, ex_reg_b, wb_data_to_reg, mem_reg_data, ex_reg_opY);
// Bypass ALU-ALU to ST
wire[31:0] ex_reg_b_fw;
wire[1:0] forwarding_reg_b;
forwardingunit_st forwardingunit_st(
.mem_we(ex_mem_we),
.ex_reg_b_in(ex_reg_b_addr),
.mem_reg_b_in(mem_reg_b_addr),
.forwarding_y(ex_forward_y),
.forwarding_regb(forwarding_reg_b)
);
mux3_1 muxRegB(forwarding_reg_b, ex_reg_b, ex_reg_opY, mem_reg_b, ex_reg_b_fw);
wire[31:0] ex_opX, ex_opX_pre;
wire[31:0] ex_opY, ex_opY_pre;
assign ex_opX_pre = (ex_branch_code != `FUNCT3_BRANCH_NO) ? ex_pc : ex_reg_opX;
assign ex_opY_pre = (ex_regb_immed > 0) ? ex_immed : ex_reg_opY;
assign ex_opX = (ex_is_mov == 2'b01) ? ex_reg_rm : ( (ex_is_mov == 2'b10) ? 32'b0 : ex_opX_pre);
assign ex_opY = (ex_is_mov == 2'b01) ? 32'b0 : ex_opY_pre;
branchComparer branchComparer(
.branch_code_in(ex_branch_code),
.reg_a_content_in(ex_reg_opX),
.reg_b_content_in(ex_reg_opY),
.is_branch_taken_out(ex_is_branch_taken)
);
alu alu(
.x(ex_opX),
.y(ex_opY),
.op(ex_alu_op),
.w(ex_res_alu),
.z(ex_z),
.exception_code(ex_exc_code)
);
TLBAddressAdder #(.CORE_ID(CORE_ID)) TLBAddressAdder(
.address_in(ex_current_rm1),
.exception_code_in(ex_current_rm2),
.address_out(ex_physical_tlb_addr)
);
EX_MEM EX_MEM(.clk(clk), .flush(flush | is_exception), .stall(stall_dcache | (sb_drain && sb_full) | mem_stall_read_sw | stall_print), .reg_write_enable_in(ex_reg_write_enable), .reg_dest_in(ex_reg_addr_dest),
.reg_data_in(ex_res_alu), .mem_to_reg_in(ex_mem_to_reg), .mem_we_in(ex_mem_we), .reg_b_in(ex_reg_b_fw), .pc_in(ex_pc), .is_ecall_in(ex_is_ecall), .io_code_in(ex_io_code),
.pc_candidate_address_in(ex_res_alu), .z_in(ex_z), .is_branch_taken_in(ex_is_branch_taken), .is_a_jump_in(ex_is_a_jump), .physical_tlb_addr_in(ex_physical_tlb_addr), .is_mov_in(ex_is_mov),
.exc_code_in(ex_exc_code), .rm0_in(ex_rm0), .rm1_in(ex_rm1), .rm2_in(ex_rm2), .psw_in(ex_PSW), .is_byte_in(ex_is_byte), .stored_rm1_in(ex_current_rm1), .stored_rm2_in(ex_current_rm2), .stored_rm4_in(ex_current_rm4),
.reg_b_addr_in(ex_reg_b_addr), .sb_addr_out_in(sb_addr_out_aux_in), .sb_is_byte_in(sb_is_byte_aux_in), .sb_data_out_in(sb_data_out_aux_in), .sb_data_to_cache_in(sb_data_to_cache_aux_in),
.sb_hit_in(sb_hit_aux_in), .was_stall_dcache_in(stall_dcache), .is_tlbwrite_in(ex_is_tlbwrite), .is_iret_in(ex_is_iret), .is_hit_itlb_in(ex_hit_itlb), .is_flush_in(1'b0),
.reg_write_enable_out(mem_reg_write_enable), .reg_dest_out(mem_reg_addr_dest), .reg_data_out(mem_reg_data), .mem_to_reg_out(mem_mem_to_reg), .is_mov_out(mem_is_mov),
.mem_we_out(mem_mem_we), .reg_b_out(mem_reg_b), .pc_candidate_address_out(mem_branch_or_jump_address), .z_out(mem_z), .is_branch_taken_out(mem_is_branch_taken), .is_flush_out(mem_is_flush), .io_code_out(mem_io_code),
.is_a_jump_out(mem_is_a_jump), .rm0_out(mem_rm0), .rm1_out(mem_rm1), .rm2_out(mem_rm2), .psw_out(mem_PSW), .is_byte_out(mem_is_byte), .sb_is_byte_out(sb_is_byte_aux_out), .stored_rm1_out(mem_current_rm1), .stored_rm2_out(mem_current_rm2),
.reg_b_addr_out(mem_reg_b_addr), .sb_addr_out_out(sb_addr_out_aux_out), .sb_data_out_out(sb_data_out_aux_out), .sb_data_to_cache_out(sb_data_to_cache_aux_out), .physical_tlb_addr_out(mem_physical_tlb_addr), .stored_rm4_out(mem_current_rm4),
.sb_hit_out(sb_hit_aux_out), .was_stall_dcache_out(was_stall_dcache), .is_tlbwrite_out(mem_is_tlbwrite), .is_iret_out(mem_is_iret), .is_hit_itlb_out(mem_hit_itlb), .pc_out(mem_pc),.is_ecall_out(mem_is_ecall));
assign mem_is_branch_or_jump_taken = mem_is_branch_taken | mem_is_a_jump;
assign stall_dcache = (!hit_dcache & mem_mem_to_reg & sb_hit_aux_in) ? 1'b0 : !hit_dcache;
// MEM stage
assign dcache_re = mem_mem_to_reg;
wire[31:0] sb_addr_out, sb_data_out;
assign sb_drain = sb_continue_drain_out;
assign privilege_mode = f_PSW;
assign is_tlbwrite = mem_is_tlbwrite;
assign exception_type = mem_current_rm2;
assign current_address_rm2 = mem_current_rm1;
assign mem_physical_tlb_addr_out = mem_physical_tlb_addr[19:0];
storebuffer storebuffer(
.clk(clk),
.reset(reset),
.addr_in(mem_reg_data),
.data_in(mem_reg_b),
.is_byte(mem_is_byte),
.sb_we(mem_mem_we && !flush),
.sb_re(mem_mem_to_reg),
.stall_dcache(stall_dcache),
.hit_dtlb(hit_dtlb),
.sb_hit(sb_hit_aux_in),
.full_out(sb_full),
.empty_out(sb_empty),
.addr_out(sb_addr_out_aux_in),
.data_out(sb_data_out_aux_in),
.is_byte_out(sb_is_byte_aux_in),
.drain_out(sb_continue_drain_out),
.is_data_to_cache(sb_data_to_cache_aux_in)
);
assign sb_addr_out = (was_stall_dcache) ? sb_addr_out_aux_out : sb_addr_out_aux_in;
assign sb_data_out = (was_stall_dcache) ? sb_data_out_aux_out : sb_data_out_aux_in;
assign sb_data_to_cache_out = (was_stall_dcache) ? sb_data_to_cache_aux_out : sb_data_to_cache_aux_in;
assign sb_hit = (was_stall_dcache) ? sb_hit_aux_out : sb_hit_aux_in;
assign sb_is_byte = (was_stall_dcache) ? sb_is_byte_aux_out : sb_is_byte_aux_in;
assign mem_addr_m = (sb_data_to_cache_out) ? sb_addr_out : mem_reg_data;
assign mem_data_wr = sb_data_out; // regb content
assign mem_isbyte = mem_mem_to_reg ? mem_is_byte : sb_is_byte;
assign mem_wrd = sb_data_to_cache_out;
wire[31:0] data_from_mem = (sb_hit) ? sb_data_out : mem_data_rd_m;
wire[31:0] mem_exc_code_in = ( (mem_mem_to_reg || mem_wrd || (mem_mem_we && !hit_dtlb)) && !hit_dtlb && !privilege_mode) ? `EXC_DTLB_MISS : 0;
assign read_interactive_req = (mem_io_code == `FUNCT7_IO_READ_SW);
assign mem_stall_read_sw = read_interactive_req && !is_read_interactive_enabled;
// WB stage
wire[31:0] wb_mem_data;
wire wb_mem_to_reg;
wire mem_flush = (stall_dcache && hit_dtlb) | is_exception;
MEM_WB MEM_WB(.clk(clk), .flush(mem_flush), .stall(stall_print), .reg_dest_in(mem_reg_addr_dest), .reg_write_enable_in(mem_reg_write_enable), .reg_data_alu_in(mem_reg_data), .io_code_in(mem_io_code), .read_interactive_value_in(read_interactive_value), .is_read_interactive_enabled_in(is_read_interactive_enabled),
.mem_data_in(data_from_mem), .mem_to_reg_in(mem_mem_to_reg), .rm0_in(mem_rm0), .rm1_in(mem_rm1), .rm2_in(mem_rm2), .psw_in(mem_PSW), .is_iret_in(mem_is_iret), .is_ecall_in(mem_is_ecall), .stored_rm4_in(mem_current_rm4),
.is_hit_dtlb_in(hit_dtlb), .is_hit_itlb_in(mem_hit_itlb), .exc_code_in(mem_exc_code_in), .mem_addr_in(mem_addr_m), .pc_in(mem_pc), .is_flush_in(1'b0), .is_mov_in(mem_is_mov),
.reg_dest_out(wb_addr_d_from_mem), .reg_data_alu_out(wb_alu_res), .reg_write_enable_out(wb_reg_write_enable_from_mem), .mem_data_out(wb_mem_data), .io_code_out(wb_io_code),
.mem_to_reg_out(wb_mem_to_reg), .rm0_out(wb_rm0), .rm1_out(wb_rm1), .rm2_out(wb_rm2), .is_iret_out(wb_is_iret), .is_hit_dtlb_out(wb_hit_dtlb), .is_mov_out(wb_is_mov),
.is_hit_itlb_out(wb_hit_itlb), .pc_out(wb_pc), .is_flush_out(wb_is_flush), .stored_rm4_out(wb_current_rm4), .read_interactive_value_out(wb_read_interactive_value), .is_read_interactive_enabled_out(wb_read_interactive_enable));
assign wb_data_to_reg_from_mem = (wb_mem_to_reg > 0) ? wb_mem_data : wb_alu_res;
assign wb_reg_write_enable = (wb_read_interactive_enable ? 1'b0 : wb_reg_write_enable_from_mem );
assign wb_data_to_reg = (wb_read_interactive_enable ? wb_read_interactive_value : wb_data_to_reg_from_mem);
assign wb_addr_d = wb_addr_d_from_mem;
assign print_output = wb_current_rm4;
assign print_hex_enable = (wb_io_code == `FUNCT7_IO_PRINT_HEX);
assign stall_print = !is_print_done;
assign wb_or_hf_addr_to_reg = wb_addr_d;
assign wb_or_hf_data_to_reg = wb_data_to_reg;
assign wb_or_hf_reg_write_enable = wb_reg_write_enable;
assign is_exception_reached = (wb_rm2 > 0 && !is_branch_or_jump_taken_wire);
assign wb_or_hf_rm0 = wb_rm0;
assign wb_or_hf_rm1 = wb_rm1;
assign wb_or_hf_rm2 = wb_rm2;
endmodule