diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2ad80a61e..6e75dba1d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -98,3 +98,13 @@ torture: dependencies: - build +serdiv-quest: + stage: standard + script: + - cd tb/tb_serdiv/ + - make simc + - "grep 'CI: PASSED' summary.rep" + dependencies: + - build + + diff --git a/Bender.yml b/Bender.yml index 288942e5f..ad6b2259b 100644 --- a/Bender.yml +++ b/Bender.yml @@ -77,6 +77,7 @@ sources: - src/lsu.sv - src/mmu.sv - src/mult.sv + - src/serdiv.sv - src/perf_counters.sv - src/ptw.sv - src/ariane_regfile_ff.sv diff --git a/src/mult.sv b/src/mult.sv index 0ff5ac988..e57581614 100644 --- a/src/mult.sv +++ b/src/mult.sv @@ -1,17 +1,3 @@ -// Copyright 2018 ETH Zurich and University of Bologna. -// Copyright and related rights are licensed under the Solderpad Hardware -// License, Version 0.51 (the "License"); you may not use this file except in -// compliance with the License. You may obtain a copy of the License at -// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law -// or agreed to in writing, software, hardware and materials distributed under -// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. -// -// Author: Florian Zaruba -// -// Date: 05.06.2017 -// Description: Ariane Multiplier and Divider (as defined in the M-extension) import ariane_pkg::*; @@ -71,33 +57,17 @@ module mult ( // --------------------- // Division // --------------------- - logic [5:0] lzc_result; // holds the index of the last '1' (as the input operand is reversed) - logic lzc_no_one; // no one was found by find first one - logic [63:0] lzc_input; // input to find first one - logic [63:0] operand_b_rev, operand_b_rev_neg, operand_b_shift; // couple of different representations for the dividend - logic [6:0] div_shift; // amount of which to shift to left - logic div_signed; // should this operation be performed as a signed or unsigned division - logic div_op_signed; // actual sign signal depends on div_signed and the MSB of the word logic [63:0] operand_b, operand_a; // input operands after input MUX (input silencing, word operations or full inputs) logic [63:0] result; // result before result mux - logic word_op; // is it a word operation + logic div_signed; // signed or unsigned division logic rem; // is it a reminder (or not a reminder e.g.: a division) logic word_op_d, word_op_q; // save whether the operation was signed or not - // is this a signed operation? - assign div_signed = (fu_data_i.operator inside {DIV, DIVW, REM, REMW}) ? 1'b1 : 1'b0; - // if this operation is signed look at the actual sign bit to determine whether we should perform signed or unsigned division - assign div_op_signed = div_signed & operand_b[63]; - - // reverse input operands - generate - for (genvar k = 0; k < 64; k++) - assign operand_b_rev[k] = operand_b[63-k]; - endgenerate - // negated reverse input operand, used for signed divisions - assign operand_b_rev_neg = ~operand_b_rev; - assign lzc_input = (div_op_signed) ? operand_b_rev_neg : operand_b_rev; + // is this a signed op? + assign div_signed = fu_data_i.operator inside {DIV, DIVW, REM, REMW}; + // is this a modulo? + assign rem = fu_data_i.operator inside {REM, REMU, REMW, REMUW}; // prepare the input operands and control divider always_comb begin @@ -105,82 +75,53 @@ module mult ( operand_a = '0; operand_b = '0; // control signals - word_op_d = word_op_q; - word_op = 1'b0; - rem = 1'b0; + word_op_d = word_op_q; // we've go a new division operation if (mult_valid_i && fu_data_i.operator inside {DIV, DIVU, DIVW, DIVUW, REM, REMU, REMW, REMUW}) begin // is this a word operation? if (fu_data_i.operator inside {DIVW, DIVUW, REMW, REMUW}) begin - word_op = 1'b1; // yes so check if we should sign extend this is only done for a signed operation if (div_signed) begin operand_a = sext32(fu_data_i.operand_a[31:0]); operand_b = sext32(fu_data_i.operand_b[31:0]); end else begin - operand_a = {32'b0, fu_data_i.operand_a[31:0]}; - operand_b = {32'b0, fu_data_i.operand_b[31:0]}; + operand_a = fu_data_i.operand_a[31:0]; + operand_b = fu_data_i.operand_b[31:0]; end // save whether we want sign extend the result or not, this is done for all word operations word_op_d = 1'b1; - // regular operation end else begin - word_op_d = 1'b0; - // no sign extending is necessary as we are already using the full 64 bit + // regular op operand_a = fu_data_i.operand_a; operand_b = fu_data_i.operand_b; - end - - // is this a modulo? - if (fu_data_i.operator inside {REM, REMU, REMW, REMUW}) begin - rem = 1'b1; + word_op_d = 1'b0; end end end - // --------------------- - // Leading Zero Counter - // --------------------- - // this unit is used to speed up the sequential division by shifting the dividend first - lzc #( - .WIDTH ( 64 ) - ) i_lzc ( - .in_i ( lzc_input ), // signed = operand_b_rev_neg, unsigned operand_b_rev - .cnt_o ( lzc_result ), - .empty_o ( lzc_no_one ) - ); - - // if the dividend is all zero go for the full length - assign div_shift = lzc_no_one ? 7'd64 : lzc_result; - // prepare dividend by shifting - assign operand_b_shift = operand_b <<< div_shift; - // --------------------- // Serial Divider // --------------------- - serial_divider #( - .C_WIDTH ( 64 ), - .C_LOG_WIDTH ( $clog2(64) + 1 ) + serdiv #( + .WIDTH ( 64 ) ) i_div ( - .Clk_CI ( clk_i ), - .Rst_RBI ( rst_ni ), - .TransId_DI ( fu_data_i.trans_id ), - .OpA_DI ( operand_a ), - .OpB_DI ( operand_b_shift ), - .OpBShift_DI ( div_shift ), - .OpBIsZero_SI ( ~(|operand_b) ), - .OpBSign_SI ( div_op_signed ), // gate this to 0 in case of unsigned ops - .OpCode_SI ( {rem, div_signed} ), // 00: udiv, 10: urem, 01: div, 11: rem - .InVld_SI ( div_valid_op ), - .Flush_SI ( flush_i ), - .OutRdy_SO ( mult_ready_o ), - .OutRdy_SI ( div_ready_i ), - .OutVld_SO ( div_valid ), - .TransId_DO ( div_trans_id ), - .Res_DO ( result ) + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .id_i ( fu_data_i.trans_id ), + .op_a_i ( operand_a ), + .op_b_i ( operand_b ), + .opcode_i ( {rem, div_signed} ), // 00: udiv, 10: urem, 01: div, 11: rem + .in_vld_i ( div_valid_op ), + .in_rdy_o ( mult_ready_o ), + .flush_i ( flush_i ), + .out_vld_o ( div_valid ), + .out_rdy_i ( div_ready_i ), + .id_o ( div_trans_id ), + .res_o ( result ) ); + // Result multiplexer // if it was a signed word operation the bit will be set and the result will be sign extended accordingly assign div_result = (word_op_q) ? sext32(result) : result; @@ -190,7 +131,7 @@ module mult ( // --------------------- always_ff @(posedge clk_i or negedge rst_ni) begin if(~rst_ni) begin - word_op_q <= ADD; + word_op_q <= '0; end else begin word_op_q <= word_op_d; end diff --git a/src/serdiv.sv b/src/serdiv.sv new file mode 100644 index 000000000..67ca5ef97 --- /dev/null +++ b/src/serdiv.sv @@ -0,0 +1,258 @@ +// Copyright 2018 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Author: Michael Schaffner (schaffner@iis.ee.ethz.ch), ETH Zurich +// Andreas Traber (traber@iis.ee.ethz.ch), ETH Zurich +// +// Date: 18.10.2018 +// Description: simple 64bit serial divider + +import ariane_pkg::*; + +module serdiv #( + parameter WIDTH = 64 +)( + input logic clk_i, + input logic rst_ni, + // input IF + input logic [TRANS_ID_BITS-1:0] id_i, + input logic [WIDTH-1:0] op_a_i, + input logic [WIDTH-1:0] op_b_i, + input logic [1:0] opcode_i, // 0: udiv, 2: urem, 1: div, 3: rem + // handshake + input logic in_vld_i, // there is a cycle delay from in_rdy_o->in_vld_i, see issue_read_operands.sv stage + output logic in_rdy_o, + input logic flush_i, + // output IF + output logic out_vld_o, + input logic out_rdy_i, + output logic [TRANS_ID_BITS-1:0] id_o, + output logic [WIDTH-1:0] res_o +); + +///////////////////////////////////// +// signal declarations +///////////////////////////////////// + + enum logic [1:0] {IDLE, DIVIDE, FINISH} state_d, state_q; + + logic [WIDTH-1:0] res_q, res_d; + logic [WIDTH-1:0] op_a_q, op_a_d; + logic [WIDTH-1:0] op_b_q, op_b_d; + logic op_a_sign, op_b_sign; + logic op_b_zero, op_b_zero_q, op_b_zero_d; + + logic [TRANS_ID_BITS-1:0] id_q, id_d; + + logic rem_sel_d, rem_sel_q; + logic comp_inv_d, comp_inv_q; + logic res_inv_d, res_inv_q; + + logic [WIDTH-1:0] add_mux; + logic [WIDTH-1:0] add_out; + logic [WIDTH-1:0] add_tmp; + logic [WIDTH-1:0] b_mux; + logic [WIDTH-1:0] out_mux; + + logic [$clog2(WIDTH+1)-1:0] cnt_q, cnt_d; + logic cnt_zero; + + logic [WIDTH-1:0] lzc_a_input, lzc_b_input, op_b; + logic [$clog2(WIDTH)-1:0] lzc_a_result, lzc_b_result; + logic [$clog2(WIDTH+1)-1:0] shift_a; + logic [$clog2(WIDTH+1):0] div_shift; + + logic a_reg_en, b_reg_en, res_reg_en, ab_comp, pm_sel, load_en; + logic lzc_a_no_one, lzc_b_no_one; + logic div_res_zero_d, div_res_zero_q; + + +///////////////////////////////////// +// align the input operands +// for faster division +///////////////////////////////////// + + assign op_b_zero = (op_b_i == 0); + assign op_a_sign = op_a_i[$high(op_a_i)]; + assign op_b_sign = op_b_i[$high(op_b_i)]; + + assign lzc_a_input = (opcode_i[0] & op_a_sign) ? {~op_a_i, 1'b0} : op_a_i; + assign lzc_b_input = (opcode_i[0] & op_b_sign) ? ~op_b_i : op_b_i; + + lzc #( + .MODE ( 1 ), // count leading zeros + .WIDTH ( WIDTH ) + ) i_lzc_a ( + .in_i ( lzc_a_input ), + .cnt_o ( lzc_a_result ), + .empty_o ( lzc_a_no_one ) + ); + + lzc #( + .MODE ( 1 ), // count leading zeros + .WIDTH ( WIDTH ) + ) i_lzc_b ( + .in_i ( lzc_b_input ), + .cnt_o ( lzc_b_result ), + .empty_o ( lzc_b_no_one ) + ); + + assign shift_a = (lzc_a_no_one) ? WIDTH : lzc_a_result; + assign div_shift = (lzc_b_no_one) ? WIDTH : lzc_b_result-shift_a; + + assign op_b = op_b_i <<< $unsigned(div_shift); + + // the division is zero if |opB| > |opA| and can be terminated + assign div_res_zero_d = (load_en) ? ($signed(div_shift) < 0) : div_res_zero_q; + +///////////////////////////////////// +// Datapath +///////////////////////////////////// + + assign pm_sel = load_en & ~(opcode_i[0] & (op_a_sign ^ op_b_sign)); + + // muxes + assign add_mux = (load_en) ? op_a_i : op_b_q; + + // attention: logical shift by one in case of negative operand B! + assign b_mux = (load_en) ? op_b : {comp_inv_q, (op_b_q[$high(op_b_q):1])}; + + // in case of bad timing, we could output from regs -> needs a cycle more in the FSM + assign out_mux = (rem_sel_q) ? op_a_q : res_q; + // assign out_mux = (rem_sel_q) ? op_a_d : res_d; + + // invert if necessary + assign res_o = (res_inv_q) ? -$signed(out_mux) : out_mux; + + // main comparator + assign ab_comp = ((op_a_q == op_b_q) | ((op_a_q > op_b_q) ^ comp_inv_q)) & ((|op_a_q) | op_b_zero_q); + + // main adder + assign add_tmp = (load_en) ? 0 : op_a_q; + assign add_out = (pm_sel) ? add_tmp + add_mux : add_tmp - $signed(add_mux); + +///////////////////////////////////// +// FSM, counter +///////////////////////////////////// + + assign cnt_zero = (cnt_q == 0); + assign cnt_d = (load_en) ? div_shift : + (~cnt_zero) ? cnt_q - 1 : cnt_q; + + always_comb begin : p_fsm + // default + state_d = state_q; + in_rdy_o = 1'b0; + out_vld_o = 1'b0; + load_en = 1'b0; + a_reg_en = 1'b0; + b_reg_en = 1'b0; + res_reg_en = 1'b0; + + unique case (state_q) + IDLE: begin + in_rdy_o = 1'b1; + + if (in_vld_i) begin + in_rdy_o = 1'b0;// there is a cycle delay until the valid signal is asserted by the id stage + a_reg_en = 1'b1; + b_reg_en = 1'b1; + load_en = 1'b1; + state_d = DIVIDE; + end + end + DIVIDE: begin + if(~div_res_zero_q) begin + a_reg_en = ab_comp; + b_reg_en = 1'b1; + res_reg_en = 1'b1; + end + // can end the division now if the result is clearly 0 + if(div_res_zero_q) begin + out_vld_o = 1'b1; + state_d = FINISH; + if(out_rdy_i) begin + // in_rdy_o = 1'b1;// there is a cycle delay until the valid signal is asserted by the id stage + state_d = IDLE; + end + end else if (cnt_zero) begin + state_d = FINISH; + end + end + FINISH: begin + out_vld_o = 1'b1; + + if (out_rdy_i) begin + // in_rdy_o = 1'b1;// there is a cycle delay until the valid signal is asserted by the id stage + state_d = IDLE; + end + end + default : state_d = IDLE; + endcase + + if (flush_i) begin + in_rdy_o = 1'b0; + out_vld_o = 1'b0; + a_reg_en = 1'b0; + b_reg_en = 1'b0; + load_en = 1'b0; + state_d = IDLE; + end + end + + +///////////////////////////////////// +// regs, flags +///////////////////////////////////// + + // get flags + assign rem_sel_d = (load_en) ? opcode_i[1] : rem_sel_q; + assign comp_inv_d = (load_en) ? opcode_i[0] & op_b_sign : comp_inv_q; + assign op_b_zero_d = (load_en) ? op_b_zero : op_b_zero_q; + assign res_inv_d = (load_en) ? (~op_b_zero | opcode_i[1]) & opcode_i[0] & (op_a_sign ^ op_b_sign) : res_inv_q; + + // transaction id + assign id_d = (load_en) ? id_i : id_q; + assign id_o = id_q; + + assign op_a_d = (a_reg_en) ? add_out : op_a_q; + assign op_b_d = (b_reg_en) ? b_mux : op_b_q; + assign res_d = (load_en) ? '0 : + (res_reg_en) ? {res_q[$high(res_q)-1:0], ab_comp} : res_q; + + always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs + if (~rst_ni) begin + state_q <= IDLE; + op_a_q <= '0; + op_b_q <= '0; + res_q <= '0; + cnt_q <= '0; + id_q <= '0; + rem_sel_q <= 1'b0; + comp_inv_q <= 1'b0; + res_inv_q <= 1'b0; + op_b_zero_q <= 1'b0; + div_res_zero_q <= 1'b0; + end else begin + state_q <= state_d; + op_a_q <= op_a_d; + op_b_q <= op_b_d; + res_q <= res_d; + cnt_q <= cnt_d; + id_q <= id_d; + rem_sel_q <= rem_sel_d; + comp_inv_q <= comp_inv_d; + res_inv_q <= res_inv_d; + op_b_zero_q <= op_b_zero_d; + div_res_zero_q <= div_res_zero_d; + end + end + +endmodule \ No newline at end of file diff --git a/src/serial_divider.sv b/src/serial_divider.sv deleted file mode 100644 index 0c4efc0c1..000000000 --- a/src/serial_divider.sv +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright 2018 ETH Zurich and University of Bologna. -// Copyright and related rights are licensed under the Solderpad Hardware -// License, Version 0.51 (the "License"); you may not use this file except in -// compliance with the License. You may obtain a copy of the License at -// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law -// or agreed to in writing, software, hardware and materials distributed under -// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. -// File : serial_divider.sv -// Ver : 1.0 -// Date : 15.03.2016 -// -// -// -// Description: this is a simple serial divider for signed integers. -// -// -// Authors : Michael Schaffner (schaffner@iis.ee.ethz.ch) -// Andreas Traber (atraber@iis.ee.ethz.ch) - -import ariane_pkg::*; - -module serial_divider #( - parameter int unsigned C_WIDTH = 32, - parameter int unsigned C_LOG_WIDTH = 6 -)( - input logic Clk_CI, - input logic Rst_RBI, - // input IF - input logic [TRANS_ID_BITS-1:0] TransId_DI, - input logic [C_WIDTH-1:0] OpA_DI, - input logic [C_WIDTH-1:0] OpB_DI, - input logic [C_LOG_WIDTH-1:0] OpBShift_DI, - input logic OpBIsZero_SI, - // - input logic OpBSign_SI, // gate this to 0 in case of unsigned ops - input logic [1:0] OpCode_SI, // 0: udiv, 2: urem, 1: div, 3: rem - // handshake - input logic InVld_SI, - input logic Flush_SI, - // output IF - output logic OutRdy_SO, - input logic OutRdy_SI, - output logic OutVld_SO, - output logic [TRANS_ID_BITS-1:0] TransId_DO, - output logic [C_WIDTH-1:0] Res_DO -); - - // ---------------------------------- - // Signal Declarations - // ---------------------------------- - logic [C_WIDTH-1:0] ResReg_DP, ResReg_DN; - logic [C_WIDTH-1:0] ResReg_DP_rev; - logic [C_WIDTH-1:0] AReg_DP, AReg_DN; - logic [C_WIDTH-1:0] BReg_DP, BReg_DN; - logic OpBIsZero_SP, OpBIsZero_SN; - - logic [TRANS_ID_BITS-1:0] TransId_DP, TransId_DN; - - logic RemSel_SN, RemSel_SP; - logic CompInv_SN, CompInv_SP; - logic ResInv_SN, ResInv_SP; - - logic [C_WIDTH-1:0] AddMux_D; - logic [C_WIDTH-1:0] AddOut_D; - logic [C_WIDTH-1:0] AddTmp_D; - logic [C_WIDTH-1:0] BMux_D; - logic [C_WIDTH-1:0] OutMux_D; - - logic [C_LOG_WIDTH-1:0] Cnt_DP, Cnt_DN; - logic CntZero_S; - - logic ARegEn_S, BRegEn_S, ResRegEn_S, ABComp_S, PmSel_S, LoadEn_S; - - enum logic [1:0] {IDLE, DIVIDE, FINISH} State_SN, State_SP; - - - // ----------------- - // Datapath - // ----------------- - assign PmSel_S = LoadEn_S & ~(OpCode_SI[0] & (OpA_DI[$high(OpA_DI)] ^ OpBSign_SI)); - - // muxes - assign AddMux_D = (LoadEn_S) ? OpA_DI : BReg_DP; - - // attention: logical shift in case of negative operand B! - assign BMux_D = (LoadEn_S) ? OpB_DI : {CompInv_SP, (BReg_DP[$high(BReg_DP):1])}; - - assign ResReg_DP_rev = {<<{ResReg_DP}}; - assign OutMux_D = (RemSel_SP) ? AReg_DP : ResReg_DP_rev; - - // invert if necessary - assign Res_DO = (ResInv_SP) ? -$signed(OutMux_D) : OutMux_D; - - // main comparator - assign ABComp_S = ((AReg_DP == BReg_DP) | ((AReg_DP > BReg_DP) ^ CompInv_SP)) & ((|AReg_DP) | OpBIsZero_SP); - - // main adder - assign AddTmp_D = (LoadEn_S) ? 0 : AReg_DP; - assign AddOut_D = (PmSel_S) ? AddTmp_D + AddMux_D : AddTmp_D - $signed(AddMux_D); - - // ----------------- - // Counter - // ----------------- - assign Cnt_DN = (LoadEn_S) ? OpBShift_DI : - (~CntZero_S) ? Cnt_DP - 1 : Cnt_DP; - - assign CntZero_S = ~(|Cnt_DP); - - // ----------------- - // FSM - // ----------------- - always_comb begin : p_fsm - // default - State_SN = State_SP; - - OutVld_SO = 1'b0; - OutRdy_SO = 1'b0; - - LoadEn_S = 1'b0; - - ARegEn_S = 1'b0; - BRegEn_S = 1'b0; - ResRegEn_S = 1'b0; - - case (State_SP) - - IDLE: begin - OutRdy_SO = 1'b1; - - if (InVld_SI) begin - OutRdy_SO = 1'b0; - OutVld_SO = 1'b0; - ARegEn_S = 1'b1; - BRegEn_S = 1'b1; - LoadEn_S = 1'b1; - State_SN = DIVIDE; - end - end - - DIVIDE: begin - - ARegEn_S = ABComp_S; - BRegEn_S = 1'b1; - ResRegEn_S = 1'b1; - - // calculation finished - // one more divide cycle (C_WIDTH th divide cycle) - if (CntZero_S) begin - State_SN = FINISH; - end - end - - FINISH: begin - OutVld_SO = 1'b1; - - if (OutRdy_SI) begin - State_SN = IDLE; - end - end - - default : /* default */ ; - - endcase - - if (Flush_SI) begin - // OutRdy_SO = 1'b0; - // OutVld_SO = 1'b0; - ARegEn_S = 1'b0; - BRegEn_S = 1'b0; - LoadEn_S = 1'b0; - State_SN = IDLE; - end - end - - // ----------------- - // Registers - // ----------------- - // get flags - assign RemSel_SN = (LoadEn_S) ? OpCode_SI[1] : RemSel_SP; - assign CompInv_SN = (LoadEn_S) ? OpBSign_SI : CompInv_SP; - assign OpBIsZero_SN = (LoadEn_S) ? OpBIsZero_SI : OpBIsZero_SP; - assign ResInv_SN = (LoadEn_S) ? (~OpBIsZero_SI | OpCode_SI[1]) & OpCode_SI[0] & (OpA_DI[$high(OpA_DI)] ^ OpBSign_SI) : ResInv_SP; - - // transaction id - assign TransId_DN = (LoadEn_S) ? TransId_DI : TransId_DP; - assign TransId_DO = TransId_DP; - - assign AReg_DN = (ARegEn_S) ? AddOut_D : AReg_DP; - assign BReg_DN = (BRegEn_S) ? BMux_D : BReg_DP; - assign ResReg_DN = (LoadEn_S) ? '0 : - (ResRegEn_S) ? {ABComp_S, ResReg_DP[$high(ResReg_DP):1]} : ResReg_DP; - - always_ff @(posedge Clk_CI or negedge Rst_RBI) begin : p_regs - if (~Rst_RBI) begin - State_SP <= IDLE; - AReg_DP <= '0; - BReg_DP <= '0; - ResReg_DP <= '0; - Cnt_DP <= '0; - TransId_DP <= '0; - RemSel_SP <= 1'b0; - CompInv_SP <= 1'b0; - ResInv_SP <= 1'b0; - OpBIsZero_SP <= 1'b0; - end else begin - State_SP <= State_SN; - AReg_DP <= AReg_DN; - BReg_DP <= BReg_DN; - ResReg_DP <= ResReg_DN; - Cnt_DP <= Cnt_DN; - TransId_DP <= TransId_DN; - RemSel_SP <= RemSel_SN; - CompInv_SP <= CompInv_SN; - ResInv_SP <= ResInv_SN; - OpBIsZero_SP <= OpBIsZero_SN; - end - end - - // ------------ - // Assertions - // ------------ - //pragma translate_off - initial begin : p_assertions - assert (C_LOG_WIDTH == $clog2(C_WIDTH+1)) else $error("C_LOG_WIDTH must be $clog2(C_WIDTH+1)"); - end - //pragma translate_on - -endmodule diff --git a/tb/tb_serdiv/Makefile b/tb/tb_serdiv/Makefile new file mode 100755 index 000000000..aaee6ad2f --- /dev/null +++ b/tb/tb_serdiv/Makefile @@ -0,0 +1,27 @@ +library ?= work +toplevel ?= tb +src-list := tb.list +inc-path := $(shell pwd)/hdl/ +src := $(shell xargs printf '\n%s' < $(src-list) | cut -b 1-) +compile_flag += +cover+i_dut -incr -64 -nologo +sim_opts += -64 -coverage -classdebug -voptargs="+acc" +questa_version ?= ${QUESTASIM_VERSION} + + +build: clean + vlib${questa_version} $(library) + vlog${questa_version} -work $(library) -pedanticerrors $(src) $(compile_flag) +incdir+$(inc-path) + touch $(library)/.build + +sim: build + vsim${questa_version} -lib $(library) $(toplevel) -do "do wave.do" $(sim_opts) + +simc: build + vsim${questa_version} -lib $(library) $(toplevel) -c -do "run -all; exit" $(sim_opts) + + +clean: + rm -rf $(library) + +.PHONY: clean simc sim build + diff --git a/tb/tb_serdiv/hdl/tb.sv b/tb/tb_serdiv/hdl/tb.sv new file mode 100644 index 000000000..a01a1bfe3 --- /dev/null +++ b/tb/tb_serdiv/hdl/tb.sv @@ -0,0 +1,314 @@ +// Copyright 2018 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Author: Michael Schaffner (schaffner@iis.ee.ethz.ch), ETH Zurich +// Andreas Traber (traber@iis.ee.ethz.ch), ETH Zurich +// +// Date: 18.10.2018 +// Description: testbench for serial 64bit divider +// + +`include "tb.svh" + +import ariane_pkg::*; +import tb_pkg::*; + +// tb package +module tb; + +/////////////////////////////////////////////////////////////////////////////// +// config +/////////////////////////////////////////////////////////////////////////////// + + // leave this + timeunit 1ps; + timeprecision 1ps; + + parameter VERBOSE = 1; + parameter WIDTH = 64; + parameter logic [WIDTH-1:0] MAX_NUM64 = '1; + parameter logic [WIDTH-2:0] MAX_NUM63 = '1; + parameter logic signed [WIDTH-1:0] MIN_NUM = {1'b1,{WIDTH-1{1'b0}}}; + +/////////////////////////////////////////////////////////////////////////////// +// MUT signal declarations +/////////////////////////////////////////////////////////////////////////////// + + + logic signed [WIDTH:0] op_a, op_b; + logic signed [WIDTH:0] op_a_tmp, op_b_tmp; + + logic flush_i; + logic [TRANS_ID_BITS-1:0] id_i; + logic [TRANS_ID_BITS-1:0] id_o; + + logic [WIDTH-1:0] op_a_i; + logic [WIDTH-1:0] op_b_i; + + logic [1:0] opcode_i; + logic [1:0] opcode_tmp; + + logic in_rdy_o; + logic in_vld_i; + logic out_rdy_i; + logic out_vld_o; + logic [WIDTH-1:0] res_o; + +/////////////////////////////////////////////////////////////////////////////// +// TB signal declarations +/////////////////////////////////////////////////////////////////////////////// + + logic clk_i, rst_ni; + logic stim_start, stim_end, end_of_sim; + longint num_stim; + logic acq_trig; + string test_name; + +/////////////////////////////////////////////////////////////////////////////// +// Clock Process +/////////////////////////////////////////////////////////////////////////////// + + always @* + begin + do begin + clk_i = 1; #(CLK_HI); + clk_i = 0; #(CLK_LO); + end while (end_of_sim == 1'b0); + // generate one extra cycle to allow response acquisition to complete + clk_i = 1; #(CLK_HI); + clk_i = 0; #(CLK_LO); + end + + +/////////////////////////////////////////////////////////////////////////////// +// MUT +/////////////////////////////////////////////////////////////////////////////// + + + assign OpBIsZero_SI = ~(|op_b_i); + serdiv #(.WIDTH(WIDTH)) i_dut (.*); + +/////////////////////////////////////////////////////////////////////////////// +// application process +/////////////////////////////////////////////////////////////////////////////// + + initial begin : p_stim + longint signed k; + bit randBit; + + stim_start = 0; + stim_end = 0; + num_stim = 0; + test_name = ""; + acq_trig = 0; + + rst_ni = 0; + + op_a = 0; + op_b = 0; + + op_a_i = 0; + op_b_i = 0; + opcode_i = 0; + in_vld_i = 0; + flush_i = 0; + id_i = 0; + + `APPL_WAIT_CYC(clk_i, 100) + + rst_ni <= 1'b1; + + `APPL_WAIT_CYC(clk_i, 100) + + $display("TB> stimuli application started"); + stim_start <= 1'b1; + `APPL_WAIT_CYC(clk_i, 100) + + /////////////////////////////////////////////// + // unsigned division test + + `include "tb_udiv.sv" + + /////////////////////////////////////////////// + // unsigned modulo test + + `include "tb_urem.sv" + + /////////////////////////////////////////////// + // signed division test + + `include "tb_div.sv" + + /////////////////////////////////////////////// + // signed modulo test + + `include "tb_rem.sv" + + /////////////////////////////////////////////// + + `APPL_WAIT_CYC(clk_i, 400) + + stim_end <= 1; + $display("TB> stimuli application ended"); + + end + + +/////////////////////////////////////////////////////////////////////////////// +// acquisition process +/////////////////////////////////////////////////////////////////////////////// + + + initial begin : p_acq + + /////////////////////////////////////////////// + // define vars, init... + /////////////////////////////////////////////// + bit ok; + string opStr; + progress status; + string failingTests, tmpstr; + longint acqCnt, res, act; + + status = new("TB"); + failingTests = ""; + + out_rdy_i = 0; + end_of_sim = 0; + + `ACQ_WAIT_SIG(clk_i, stim_start) + + $display("TB> response acquisition started"); + + /////////////////////////////////////////////// + // acquisiton and verification + /////////////////////////////////////////////// + repeat(4) begin + + // wait for acquisition trigger + do begin + `ACQ_WAIT_CYC(clk_i, 1) + if (stim_end == 1) begin + end_of_sim <= 1; + $display("response acquisition ended"); + $finish(); + end + end while(acq_trig == 1'b0); + + acqCnt = 0; + + $display(""); + $display("TB> ----------------------------------------------------------------------"); + $display("TB> %s", test_name); + $display("TB> ----------------------------------------------------------------------\n"); + $display(""); + + $display("TB> checking %00d vectors",num_stim); + $display(""); + status.reset(num_stim); + + do begin + + + + out_rdy_i = 1'b1; + + `ACQ_WAIT_SIG(clk_i, in_vld_i) + + opcode_tmp = opcode_i; + op_a_tmp = op_a; + op_b_tmp = op_b; + + ////////////////////////// + // udiv / udiv + if(opcode_i[1] == 1'b0) begin + + res = op_a_tmp/op_b_tmp; + + if((op_b_tmp == 0) && (opcode_i[0] == 0)) begin + res = MAX_NUM64; + end else if ((op_b_tmp == 0) && (opcode_i[0] == 1'b1)) begin + res = -1; + end else if ((op_a_tmp == MIN_NUM) && (op_b_tmp == -1) && (opcode_i[0] == 1'b1)) begin + res = MIN_NUM; + end + + `ACQ_WAIT_SIG(clk_i, out_vld_o) + + // interpret result correctly! + if (opcode_tmp[0] == 1'b1) + act = $signed(res_o); + else + act = $unsigned(res_o); + + opStr="/"; + ////////////////////////// + // rem / urem + end else if(opcode_i[1] == 1'b1) begin + + res = op_a_tmp % op_b_tmp; + + if((op_b_tmp == 0)) begin + res = op_a_tmp; + end + + `ACQ_WAIT_SIG(clk_i, out_vld_o) + + // interpret result correctly! + if (opcode_tmp[0] == 1'b1) + act = $signed(res_o); + else + act = $unsigned(res_o); + + opStr="\%"; + end + + ok = (res==act); + + if(VERBOSE | !ok) begin + if(!ok) tmpstr = $psprintf("vector: %04d> %d %s %d = %d != %d -> error!", acqCnt, op_a_tmp, opStr, op_b_tmp, res, act); + else tmpstr = $psprintf("vector: %04d> %d %s %d = %d == %d " , acqCnt, op_a_tmp, opStr, op_b_tmp, res, act); + $display("TB> %s", tmpstr); + end + + if(!ok) begin + failingTests = $psprintf("%sTB> %s\n", failingTests, tmpstr); + end + + status.addRes(!ok); + status.print(); + + // status + acqCnt++; + end + while (acqCnt < num_stim); + end + /////////////////////////////////////////////// + + status.printToFile("summary.rep", 1); + + if(status.totErrCnt == 0) begin + $display("TB> ----------------------------------------------------------------------"); + $display("TB> PASSED %0d VECTORS", status.totAcqCnt); + $display("TB> ----------------------------------------------------------------------\n"); + end else begin + $display("TB> ----------------------------------------------------------------------\n"); + $display("TB> FAILED %0d OF %0d VECTORS\n" , status.totErrCnt, status.totAcqCnt); + $display("TB> failing tests:"); + $display("TB", failingTests); + $display("TB> ----------------------------------------------------------------------\n"); + end + + end_of_sim <= 1; + $finish(); + /////////////////////////////////////////////// + end + +endmodule diff --git a/tb/tb_serdiv/hdl/tb.svh b/tb/tb_serdiv/hdl/tb.svh new file mode 100644 index 000000000..ee4dabae6 --- /dev/null +++ b/tb/tb_serdiv/hdl/tb.svh @@ -0,0 +1,66 @@ +// Copyright (c) 2018 ETH Zurich, University of Bologna +// All rights reserved. +// +// This code is under development and not yet released to the public. +// Until it is released, the code is under the copyright of ETH Zurich and +// the University of Bologna, and may contain confidential and/or unpublished +// work. Any reuse/redistribution is strictly forbidden without written +// permission from ETH Zurich. +// +// Bug fixes and contributions will eventually be released under the +// SolderPad open hardware license in the context of the PULP platform +// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the +// University of Bologna. +// +// Author: Michael Schaffner , ETH Zurich +// Date: 15.08.2018 +// Description: +// + +////////////////////////////////////////////////////////////////////////////// +// use to ensure proper ATI timing +/////////////////////////////////////////////////////////////////////////////// + +`define APPL_ACQ_WAIT #(ACQ_DEL-APPL_DEL); + +`define WAIT_CYC(CLK, N) \ +repeat(N) @(posedge(CLK)); + +`define WAIT(CLK, SIG) \ +do begin \ + @(posedge(CLK)); \ +end while(SIG == 1'b0); + +`define WAIT_SIG(CLK,SIG) \ +do begin \ + @(posedge(CLK)); \ +end while(SIG == 1'b0); + +`define APPL_WAIT_COMB_SIG(CLK,SIG) \ +`APPL_ACQ_WAIT \ +while(SIG == 1'b0) begin \ + @(posedge(CLK)); \ + #(ACQ_DEL); \ +end + +`define APPL_WAIT_SIG(CLK,SIG) \ +do begin \ + @(posedge(CLK)); \ + #(APPL_DEL); \ +end while(SIG == 1'b0); + +`define ACQ_WAIT_SIG(CLK,SIG) \ +do begin \ + @(posedge(CLK)); \ + #(ACQ_DEL); \ +end while(SIG == 1'b0); + + +`define APPL_WAIT_CYC(CLK, N) \ +repeat(N) @(posedge(CLK)); \ +#(tb_pkg::APPL_DEL); + +`define ACQ_WAIT_CYC(CLK, N) \ +repeat(N) @(posedge(CLK)); \ +#(tb_pkg::ACQ_DEL); + diff --git a/tb/tb_serdiv/hdl/tb_div.sv b/tb/tb_serdiv/hdl/tb_div.sv new file mode 100644 index 000000000..4cd5cd8ce --- /dev/null +++ b/tb/tb_serdiv/hdl/tb_div.sv @@ -0,0 +1,117 @@ +// Copyright 2018 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Author: Michael Schaffner (schaffner@iis.ee.ethz.ch), ETH Zurich +// Andreas Traber (traber@iis.ee.ethz.ch), ETH Zurich +// +// Date: 18.10.2018 +// Description: testbench for serial 64bit divider +// + +/////////////////////////////////////////////// +// unsigned division test + +// init +num_stim = 5+1000; + +test_name = "div test"; + +acq_trig <= 1; +`APPL_WAIT_CYC(clk_i, 2) +acq_trig <= 0; +`APPL_WAIT_CYC(clk_i, 2) + +/////////////////////////////////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +opcode_i = 1; + +op_a = 100; +op_b = -10; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +/////////////////////////////////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +op_a = -100; +op_b = -10; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +/////////////////////////////////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +op_a = -100; +op_b = 0; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +/////////////////////////////////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + + +op_a = MIN_NUM; +op_b = 1; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +/////////////////////////////////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + + +op_a = MIN_NUM; +op_b = -1; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +//////////////////// +// a couple of random stimuli + +for (k = 0; k < 1000; k++) begin + + + void'(randomize(op_a_i)); + void'(randomize(op_b_i)); + op_a = $signed(op_a_i); + op_b = $signed(op_b_i); + + in_vld_i = 1; + `APPL_WAIT_CYC(clk_i, 1) + in_vld_i = 0; + `APPL_WAIT_SIG(clk_i, in_rdy_o) + +end + +`APPL_WAIT_CYC(clk_i, 400) + +/////////////////////////////////////////////// diff --git a/tb/tb_serdiv/hdl/tb_pkg.sv b/tb/tb_serdiv/hdl/tb_pkg.sv new file mode 100644 index 000000000..9767d472e --- /dev/null +++ b/tb/tb_serdiv/hdl/tb_pkg.sv @@ -0,0 +1,148 @@ +// Copyright 2018 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Author: Michael Schaffner (schaffner@iis.ee.ethz.ch), ETH Zurich +// Andreas Traber (traber@iis.ee.ethz.ch), ETH Zurich +// +// Date: 18.10.2018 +// Description: testbench package with some helper functions. +// + +package tb_pkg; + + // // for abs(double) function + // import mti_cstdlib::*; + + // for timestamps + import "DPI-C" \time = function int _time (inout int tloc[4]); + import "DPI-C" function string ctime(inout int tloc[4]); + +/////////////////////////////////////////////////////////////////////////////// +// parameters +/////////////////////////////////////////////////////////////////////////////// + + // creates a 10ns ATI timing cycle + time CLK_HI = 5ns; // set clock high time + time CLK_LO = 5ns; // set clock low time + time CLK_PERIOD = CLK_HI+CLK_LO; + time APPL_DEL = 2ns; // set stimuli application delay + time ACQ_DEL = 8ns; // set response aquisition delay + + parameter ERROR_CNT_STOP_LEVEL = 1; // use 1 for debugging. 0 runs the complete simulation... + + // tb_readport sequences + typedef enum logic [2:0] { RANDOM_SEQ, LINEAR_SEQ, BURST_SEQ, IDLE_SEQ, WRAP_SEQ } seq_t; + +/////////////////////////////////////////////////////////////////////////////// +// progress +/////////////////////////////////////////////////////////////////////////////// + + class progress; + real newState, oldState; + longint numResp, acqCnt, errCnt, totAcqCnt, totErrCnt; + string name; + + function new(string name); + begin + this.name = name; + this.acqCnt = 0; + this.errCnt = 0; + this.newState = 0.0; + this.oldState = 0.0; + this.numResp = 1; + this.totAcqCnt = 0; + this.totErrCnt = 0; + + end + endfunction : new + + function void reset(longint numResp_); + begin + this.acqCnt = 0; + this.errCnt = 0; + this.newState = 0.0; + this.oldState = 0.0; + this.numResp = numResp_; + end + endfunction : reset + + function void addRes(int isError); + begin + this.acqCnt++; + this.totAcqCnt++; + this.errCnt += isError; + this.totErrCnt += isError; + + if(ERROR_CNT_STOP_LEVEL <= this.errCnt && ERROR_CNT_STOP_LEVEL > 0) begin + $error("%s> simulation stopped (ERROR_CNT_STOP_LEVEL = %d reached).", this.name, ERROR_CNT_STOP_LEVEL); + $stop(); + end + end + endfunction : addRes + + function void print(); + begin + this.newState = $itor(this.acqCnt) / $itor(this.numResp); + if(this.newState - this.oldState >= 0.01) begin + $display("%s> validated %03d%% -- %01d failed (%03.3f%%) ", + this.name, + $rtoi(this.newState*100.0), + this.errCnt, + $itor(this.errCnt) / $itor(this.acqCnt) * 100.0); + // $fflush(); + this.oldState = this.newState; + end + end + endfunction : print + + function void printToFile(string file, bit summary = 0); + begin + int fptr; + + // sanitize string + for(fptr=0; fptr<$size(file);fptr++) begin + if(file[fptr] == " " || file[fptr] == "/" || file[fptr] == "\\") begin + file[fptr] = "_"; + end + end + + + fptr = $fopen(file,"w"); + if(summary) begin + $fdisplay(fptr, "Simulation Summary of %s", this.name); + $fdisplay(fptr, "total: %01d of %01d vectors failed (%03.3f%%) ", + this.totErrCnt, + this.totAcqCnt, + $itor(this.totErrCnt) / ($itor(this.totAcqCnt) * 100.0 + 0.000000001)); + if(this.totErrCnt == 0) begin + $fdisplay(fptr, "CI: PASSED"); + end else begin + $fdisplay(fptr, "CI: FAILED"); + end + end else begin + $fdisplay(fptr, "test name: %s", file); + $fdisplay(fptr, "this test: %01d of %01d vectors failed (%03.3f%%) ", + this.errCnt, + this.acqCnt, + $itor(this.errCnt) / $itor(this.acqCnt) * 100.0); + + $fdisplay(fptr, "total so far: %01d of %01d vectors failed (%03.3f%%) ", + this.totErrCnt, + this.totAcqCnt, + $itor(this.totErrCnt) / $itor(this.totAcqCnt) * 100.0); + end + $fclose(fptr); + end + endfunction : printToFile + + endclass : progress + +endpackage : tb_pkg + diff --git a/tb/tb_serdiv/hdl/tb_rem.sv b/tb/tb_serdiv/hdl/tb_rem.sv new file mode 100644 index 000000000..81bb93341 --- /dev/null +++ b/tb/tb_serdiv/hdl/tb_rem.sv @@ -0,0 +1,116 @@ +// Copyright 2018 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Author: Michael Schaffner (schaffner@iis.ee.ethz.ch), ETH Zurich +// Andreas Traber (traber@iis.ee.ethz.ch), ETH Zurich +// +// Date: 18.10.2018 +// Description: testbench for serial 64bit divider + +/////////////////////////////////////////////// +// unsigned division test + +// init +num_stim = 5+1000; + +test_name = "rem test"; + +acq_trig <= 1; +`APPL_WAIT_CYC(clk_i, 2) +acq_trig <= 0; +`APPL_WAIT_CYC(clk_i, 2) + +/////////////////////////////////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +opcode_i = 3; + +op_a = 100; +op_b = -10; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +/////////////////////////////////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +in_vld_i = 0; + +op_a = -100; +op_b = -10; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +/////////////////////////////////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +op_a = -100; +op_b = 0; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +/////////////////////////////////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +op_a = MIN_NUM; +op_b = 1; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +/////////////////////////////////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +op_a = MIN_NUM; +op_b = -1; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +//////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +//////////////////// +// a couple of random stimuli + +for (k = 0; k < 1000; k++) begin + + void'(randomize(op_a_i)); + void'(randomize(op_b_i)); + op_a = $signed(op_a_i); + op_b = $signed(op_b_i); + + in_vld_i = 1; + `APPL_WAIT_CYC(clk_i, 1) + in_vld_i = 0; + `APPL_WAIT_SIG(clk_i, in_rdy_o) + +end + +`APPL_WAIT_CYC(clk_i, 400) + +/////////////////////////////////////////////// diff --git a/tb/tb_serdiv/hdl/tb_udiv.sv b/tb/tb_serdiv/hdl/tb_udiv.sv new file mode 100644 index 000000000..1bee977c9 --- /dev/null +++ b/tb/tb_serdiv/hdl/tb_udiv.sv @@ -0,0 +1,127 @@ +// Copyright 2018 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Author: Michael Schaffner (schaffner@iis.ee.ethz.ch), ETH Zurich +// Andreas Traber (traber@iis.ee.ethz.ch), ETH Zurich +// +// Date: 18.10.2018 +// Description: testbench for serial 64bit divider + +/////////////////////////////////////////////// +// unsigned division test + +// init +num_stim = 6+1000; + +test_name = "udiv test"; + +acq_trig <= 1; +`APPL_WAIT_CYC(clk_i, 2) +acq_trig <= 0; +`APPL_WAIT_CYC(clk_i, 2) + +/////////////////////////////////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +opcode_i = 0; + +op_a = 100; +op_b = 2; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +//////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +op_a = MAX_NUM64; +op_b = 1; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +//////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +op_a = 1; +op_b = MAX_NUM64; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +//////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +op_a = 0; +op_b = 5456; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +//////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +op_a = 875; +op_b = 0; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +//////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +op_a = 0; +op_b = 0; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +//////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + + +//////////////////// +// a couple of random stimuli + +for (k = 0; k < 1000; k++) begin + + void'(randomize(op_a_i)); + void'(randomize(op_b_i)); + op_a = op_a_i; + op_b = op_b_i; + + in_vld_i = 1; + `APPL_WAIT_CYC(clk_i, 1) + in_vld_i = 0; + `APPL_WAIT_SIG(clk_i, in_rdy_o) + +end + +`APPL_WAIT_CYC(clk_i, 400) + +/////////////////////////////////////////////// diff --git a/tb/tb_serdiv/hdl/tb_urem.sv b/tb/tb_serdiv/hdl/tb_urem.sv new file mode 100644 index 000000000..e413c27f4 --- /dev/null +++ b/tb/tb_serdiv/hdl/tb_urem.sv @@ -0,0 +1,127 @@ +// Copyright 2018 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Author: Michael Schaffner (schaffner@iis.ee.ethz.ch), ETH Zurich +// Andreas Traber (traber@iis.ee.ethz.ch), ETH Zurich +// +// Date: 18.10.2018 +// Description: testbench for serial 64bit divider + +/////////////////////////////////////////////// +// unsigned division test + +// init +num_stim = 6+1000; + +test_name = "urem test"; + +acq_trig <= 1; +`APPL_WAIT_CYC(clk_i, 2) +acq_trig <= 0; +`APPL_WAIT_CYC(clk_i, 2) + +/////////////////////////////////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +opcode_i = 2; + +op_a = 100; +op_b = 2; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +//////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +op_a = MAX_NUM64; +op_b = 1; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +//////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +op_a = 1; +op_b = MAX_NUM64; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +//////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +op_a = 0; +op_b = 5456; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +//////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +op_a = 875; +op_b = 0; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +//////////////////// +`APPL_WAIT_SIG(clk_i, in_rdy_o) + +op_a = 0; +op_b = 0; + +op_a_i = op_a; +op_b_i = op_b; + +in_vld_i = 1; +`APPL_WAIT_CYC(clk_i, 1) +in_vld_i = 0; +`APPL_WAIT_SIG(clk_i, in_rdy_o) + + +//////////////////// +// a couple of random stimuli + +for (k = 0; k < 1000; k++) begin + + `APPL_WAIT_SIG(clk_i, in_rdy_o) + + void'(randomize(op_a_i)); + void'(randomize(op_b_i)); + op_a = op_a_i; + op_b = op_b_i; + + in_vld_i = 1; + `APPL_WAIT_CYC(clk_i, 1) + in_vld_i = 0; + `APPL_WAIT_SIG(clk_i, in_rdy_o) + +end + +`APPL_WAIT_CYC(clk_i, 400) +/////////////////////////////////////////////// diff --git a/tb/tb_serdiv/tb.list b/tb/tb_serdiv/tb.list new file mode 100644 index 000000000..913bb7b3e --- /dev/null +++ b/tb/tb_serdiv/tb.list @@ -0,0 +1,7 @@ +../../include/riscv_pkg.sv +../../src/debug/dm_pkg.sv +../../include/ariane_pkg.sv +../../src/common_cells/src/lzc.sv +../../src/serdiv.sv +hdl/tb_pkg.sv +hdl/tb.sv