URL
https://opencores.org/ocsvn/forwardcom/forwardcom/trunk
Subversion Repositories forwardcom
[/] [forwardcom/] [trunk/] [mul_div.sv] - Rev 11
Go to most recent revision | Compare with Previous | Blame | View Log
//////////////////////////////////////////////////////////////////////////////////// Engineer: Agner Fog//// Create Date: 2021-06-06// Last modified: 2021-06-06// Module Name: mul_div// Project Name: ForwardCom soft core// Target Devices: Artix 7// Tool Versions: Vivado v. 2020.1// License: CERN-OHL-W v. 2 or later// Description: Arithmetic-logic unit for multiplication and division// of general purpose registers.//////////////////////////////////////////////////////////////////////////////////`include "defines.vh"module mul_div (input clock, // system clock (100 MHz)input clock_enable, // clock enable. Used when single-steppinginput reset, // system resetinput valid_in, // data from previous stage readyinput stall_in, // pipeline is stalledinput [31:0] instruction_in, // current instruction, up to 3 words long. Only first word used hereinput [`TAG_WIDTH-1:0] tag_val_in, // instruction tag valueinput [1:0] category_in, // 00: multiformat, 01: single format, 10: jumpinput mask_alternative_in, // mask register and fallback register used for alternative purposesinput [1:0] result_type_in, // type of result: 0: register, 1: system register, 2: memory, 3: other or nothinginput vector_in, // vector registers usedinput [6:0] opx_in, // operation ID in execution unit. This is mostly equal to op1 for multiformat instructionsinput [2:0] ot_in, // operand typeinput [5:0] option_bits_in, // option bits from IM3 or mask// monitor result buses:input write_en1, // a result is written to writeport1input [`TAG_WIDTH-1:0] write_tag1_in, // tag of result inwriteport1input [`RB1:0] writeport1_in, // result bus 1input write_en2, // a result is written to writeport2input [`TAG_WIDTH-1:0] write_tag2_in, // tag of result inwriteport2input [`RB1:0] writeport2_in, // result bus 2input [`TAG_WIDTH-1:0] predict_tag1_in, // result tag value on writeport1 in next clock cycleinput [`TAG_WIDTH-1:0] predict_tag2_in, // result tag value on writeport2 in next clock cycle// Register values sampled from result bus in previous stagesinput [`RB:0] operand1_in, // first register operand or fallbackinput [`RB:0] operand2_in, // second register operand RSinput [`RB:0] operand3_in, // last register operand RTinput [`MASKSZ:0] regmask_val_in, // mask registerinput [`RB1:0] ram_data_in, // memory operand from data raminput opr2_from_ram_in, // value of operand 2 comes from data raminput opr3_from_ram_in, // value of last operand comes from data raminput opr1_used_in, // operand1_in is neededinput opr2_used_in, // operand2_in is neededinput opr3_used_in, // operand3_in is neededinput regmask_used_in, // regmask_val_in is neededoutput reg valid_out, // for debug display: alu is activeoutput reg register_write_out,output reg [4:0] register_a_out, // register to writeoutput reg [`RB1:0] result_out, //output reg [`TAG_WIDTH-1:0] tag_val_out,// instruction tag valueoutput reg stall_out, // alu is waiting for an operand or not ready to receive a new instructionoutput reg stall_next_out, // alu will be waiting in next clock cycleoutput reg error_out, // unknown instructionoutput reg error_parm_out, // wrong parameter for instruction// outputs for debugger:output reg [31:0] debug1_out, // debug informationoutput reg [31:0] debug2_out // temporary debug information);logic [`RB1:0] operand1; // first register operand RD or RU. bit `RB is 1 if invalidlogic [`RB1:0] operand2; // second register operand RS. bit `RB is 1 if invalidlogic [`RB1:0] operand3; // last register operand RT. bit `RB is 1 if invalidlogic [`MASKSZ:0] regmask_val; // mask registerlogic [1:0] otout; // operand type for outputlogic [5:0] msb; // index to most significant bitlogic signbit2, signbit3; // sign bits of three operandslogic [`RB1:0] sbit; // position of sign bitlogic [`RB1:0] result; // result for outputlogic [1:0] result_type; // type of resultlogic [6:0] opx; // operation ID in execution unit. This is mostly equal to op1 for multiformat instructionslogic mask_off; // result is masked offlogic stall; // waiting for operandslogic stall_next; // will be waiting for operands in next clock cyclelogic error; // unknown instructionlogic error_parm; // wrong parameter for instruction// It seems to be more efficient to truncate operands locally by ANDing with sizemask than to// make separate wires for the truncated operands, because wiring is more expensive than logic:logic [`RB1:0] sizemask; // mask for operand typelogic [31:0] temp_debug; // temporary debug signalsalways_comb begin// get all inputsstall = 0;stall_next = 0;regmask_val = 0;temp_debug = 0; // temporary debug signalsif (regmask_val_in[`MASKSZ]) begin // value missingif (write_en1 && regmask_val_in[`TAG_WIDTH-1:0] == write_tag1_in) beginregmask_val = writeport1_in; // obtained from result bus 1 (which may be my own output)end else if (write_en2 && regmask_val_in[`TAG_WIDTH-1:0] == write_tag2_in) beginregmask_val = writeport2_in[(`MASKSZ-1):0]; // obtained from result bus 2end else beginif (regmask_used_in) beginstall = 1; // operand not readytemp_debug[0] = 1; // debug info about cause of stallif (regmask_val_in[`TAG_WIDTH-1:0] != predict_tag1_in && regmask_val_in[`TAG_WIDTH-1:0] != predict_tag2_in) beginstall_next = 1; // operand not ready in next clock cycleendendendend else begin // value availableregmask_val = regmask_val_in;endmask_off = regmask_used_in && regmask_val[`MASKSZ] == 0 && regmask_val[0] == 0 && !mask_alternative_in;operand1 = 0;if (operand1_in[`RB]) begin // value missingif (write_en1 && operand1_in[`TAG_WIDTH-1:0] == write_tag1_in) beginoperand1 = writeport1_in; // obtained from result bus 1 (which may be my own output)end else if (write_en2 && operand1_in[`TAG_WIDTH-1:0] == write_tag2_in) beginoperand1 = writeport2_in; // obtained from result bus 2end else beginif (opr1_used_in) beginstall = 1; // operand not readytemp_debug[1] = 1; // debug info about cause of stallif (operand1_in[`TAG_WIDTH-1:0] != predict_tag1_in && operand1_in[`TAG_WIDTH-1:0] != predict_tag2_in) beginstall_next = 1; // operand not ready in next clock cycleendendendend else beginoperand1 = operand1_in[`RB1:0];endoperand2 = 0;if (opr2_from_ram_in) beginoperand2 = ram_data_in;end else if (operand2_in[`RB]) begin // value missingif (write_en1 && operand2_in[`TAG_WIDTH-1:0] == write_tag1_in) beginoperand2 = writeport1_in; // obtained from result bus 1 (which may be my own output)end else if (write_en2 && operand2_in[`TAG_WIDTH-1:0] == write_tag2_in) beginoperand2 = writeport2_in; // obtained from result bus 2end else beginif (opr2_used_in && !mask_off) beginstall = 1; // operand not readytemp_debug[2] = 1; // debug info about cause of stallif (operand2_in[`TAG_WIDTH-1:0] != predict_tag1_in && operand2_in[`TAG_WIDTH-1:0] != predict_tag2_in) beginstall_next = 1; // operand not ready in next clock cycleendendendend else begin // value availableoperand2 = operand2_in[`RB1:0];endoperand3 = 0;if (opr3_from_ram_in) beginoperand3 = ram_data_in;end else if (operand3_in[`RB]) begin // value missingif (write_en1 && operand3_in[`TAG_WIDTH-1:0] == write_tag1_in) beginoperand3 = writeport1_in; // obtained from result bus 1 (which may be my own output)end else if (write_en2 && operand3_in[`TAG_WIDTH-1:0] == write_tag2_in) beginoperand3 = writeport2_in; // obtained from result bus 2end else beginif (opr3_used_in && !mask_off) beginstall = 1; // operand not readytemp_debug[3] = 1; // debug info about cause of stallif (operand3_in[`TAG_WIDTH-1:0] != predict_tag1_in && operand3_in[`TAG_WIDTH-1:0] != predict_tag2_in) beginstall_next = 1; // operand not ready in next clock cycleendendendend else begin // value availableoperand3 = operand3_in[`RB1:0];endopx = opx_in; // operation ID in execution unit. This is mostly equal to op1 for multiformat instructionsresult = 0;otout = ot_in[1:0]; // operand type for outputresult_type = result_type_in;error = 0;error_parm = 0;case (ot_in[1:0])0: beginmsb = 7; // 8 bitsbit = 8'H80;sizemask = 8'HFF;//signbit1 = operand1[7];signbit2 = operand2[7];signbit3 = operand3[7];end1: beginmsb = 15; // 16 bitsbit = 16'H8000;sizemask = 16'HFFFF;//signbit1 = operand1[15];signbit2 = operand2[15];signbit3 = operand3[15];end2: beginmsb = 31; // 32 bitsbit = 32'H80000000;sizemask = 32'HFFFFFFFF;//signbit1 = operand1[31];signbit2 = operand2[31];signbit3 = operand3[31];end3: beginmsb = `RB1; // 64 bitsbit = {1'b1,{(`RB-1){1'b0}}};sizemask = ~(`RB'b0);//signbit1 = operand1[`RB1];signbit2 = operand2[`RB1];signbit3 = operand3[`RB1];endendcase////////////////////////////////////////////////// Select ALU operation////////////////////////////////////////////////result = 0;if (opx == `II_MUL) beginerror = 1; // instruction not supported yetend else if (opx == `II_MUL_HI || opx == `II_MUL_HI_U) beginerror = 1; // instruction not supported yetend else if (opx == `II_DIV || opx == `II_DIV_U) beginerror = 1; // instruction not supported yetend else if (opx == `II_REM || opx == `II_REM_U) beginerror = 1; // instruction not supported yetend else beginerror = 1; // unknown instructionendif (vector_in) error = 1; // Vector instructions not supported yetend// outputalways_ff @(posedge clock) if (clock_enable) beginif (!valid_in) beginregister_write_out <= 0;// note: the FPGA has no internal tri-state buffers. We need to simulate result bus by or'ing outputsresult_out <= 0;register_a_out <= 0;tag_val_out <= 0;// stall_in must disable the output to avoid executing the same instruction twice)end else if (stall || stall_in) beginregister_write_out <= 0;result_out <= 0;register_a_out <= 0;tag_val_out <= 0;end else if (result_type != `RESULT_REG) begin// no output?register_write_out <= 0;result_out <= 0;register_a_out <= 0;tag_val_out <= 0;end else if (regmask_used_in && !regmask_val[0] & !vector_in) begin// mask is zero. output is fallbackcase (otout)0: result_out <= operand1[7:0];1: result_out <= operand1[15:0];2: result_out <= operand1[31:0];3: result_out <= operand1[`RB1:0];endcaseregister_write_out <= ~reset;register_a_out <= {1'b0,instruction_in[`RD]};tag_val_out <= tag_val_in;end else begin// normal register outputcase (otout)0: result_out <= result[7:0];1: result_out <= result[15:0];2: result_out <= result[31:0];3: result_out <= result[`RB1:0];endcaseregister_write_out <= ~reset;register_a_out <= {1'b0,instruction_in[`RD]};tag_val_out <= tag_val_in;endvalid_out <= !stall & valid_in & !reset;stall_out <= stall & valid_in & !reset;stall_next_out <= stall_next & valid_in & !reset;error_out <= error & valid_in & !reset; // unknown instructionerror_parm_out <= error_parm & valid_in & !reset; // wrong parameter// outputs for debugger:debug1_out <= 0;debug1_out[6:0] <= opx;debug1_out[21:20] <= category_in;debug1_out[24] <= stall;debug1_out[25] <= stall_next;debug1_out[27] <= error;debug2_out <= temp_debug;debug2_out[16] <= opr1_used_in;debug2_out[17] <= opr2_used_in;debug2_out[18] <= opr3_used_in;debug2_out[19] <= regmask_used_in;debug2_out[20] <= mask_alternative_in;debug2_out[21] <= mask_off;debug2_out[22] <= regmask_val_in[0];debug2_out[23] <= regmask_val_in[`MASKSZ];debug2_out[27:24] <= regmask_val[3:0];debug2_out[28] <= regmask_val[`MASKSZ];endendmodule
Go to most recent revision | Compare with Previous | Blame | View Log
