`default_nettype none module serv_mem_if #(parameter WITH_CSR = 1) ( input wire i_clk, //State input wire i_en, input wire i_init, input wire i_cnt_done, input wire [1:0] i_bytecnt, input wire [1:0] i_lsb, output wire o_misalign, output wire o_sh_done, output wire o_sh_done_r, //Control input wire i_mem_op, input wire i_shift_op, input wire i_signed, input wire i_word, input wire i_half, //Data input wire i_op_b, output wire o_rd, //External interface output wire [31:0] o_wb_dat, output wire [3:0] o_wb_sel, input wire [31:0] i_wb_rdt, input wire i_wb_ack); reg signbit; reg [31:0] dat; wire [2:0] tmp = {1'b0,i_bytecnt}+{1'b0,i_lsb}; wire dat_en = i_shift_op | (i_en & !tmp[2]); wire dat_cur = ((i_lsb == 2'd3) & dat[24]) | ((i_lsb == 2'd2) & dat[16]) | ((i_lsb == 2'd1) & dat[8]) | ((i_lsb == 2'd0) & dat[0]); wire dat_valid = i_word | (i_bytecnt == 2'b00) | (i_half & !i_bytecnt[1]); assign o_rd = i_mem_op & (dat_valid ? dat_cur : signbit & i_signed); assign o_wb_sel[3] = (i_lsb == 2'b11) | i_word | (i_half & i_lsb[1]); assign o_wb_sel[2] = (i_lsb == 2'b10) | i_word; assign o_wb_sel[1] = (i_lsb == 2'b01) | i_word | (i_half & !i_lsb[1]); assign o_wb_sel[0] = (i_lsb == 2'b00); assign o_wb_dat = dat; /* The dat register has three different use cases for store, load and shift operations. store : Data to be written is shifted to the correct position in dat during init by dat_en and is presented on the data bus as o_wb_dat load : Data from the bus gets latched into dat during i_wb_ack and is then shifted out at the appropriate time to end up in the correct position in rd shift : Data is shifted in during init. After that, the six LSB are used as a downcounter (with bit 5 initially set to 0) that triggers o_sh_done and o_sh_done_r when they wrap around to indicate that the requested number of shifts have been performed */ wire [5:0] dat_shamt = (i_shift_op & !i_init) ? //Down counter mode dat[5:0]-1 : //Shift reg mode with optional clearing of bit 5 {dat[6] & !(i_shift_op & i_cnt_done),dat[5:1]}; assign o_sh_done = dat_shamt[5]; assign o_sh_done_r = dat[5]; always @(posedge i_clk) begin if (dat_en | i_wb_ack) dat <= i_wb_ack ? i_wb_rdt : {i_op_b, dat[31:7], dat_shamt}; if (dat_valid) signbit <= dat_cur; end /* mem_misalign is checked after the init stage to decide whether to do a data bus transaction or go to the trap state. It is only guaranteed to be correct at this time */ assign o_misalign = WITH_CSR & ((i_lsb[0] & (i_word | i_half)) | (i_lsb[1] & i_word)); endmodule