Improve serial divider performance by aligning operands, add serdiv testbench to CI

This commit is contained in:
Michael Schaffner 2018-10-18 13:17:02 +02:00 committed by Florian Zaruba
parent 7da347e17b
commit 76101fe9ed
15 changed files with 1345 additions and 317 deletions

View file

@ -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

View file

@ -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

View file

@ -82,7 +82,6 @@ src := $(filter-out src/ariane_regfile.sv, $(wildcard src/*.sv)) \
src/common_cells/src/stream_mux.sv \
src/common_cells/src/stream_demux.sv \
src/util/axi_connect.sv \
src/util/mock_mul.sv \
src/axi/src/axi_cut.sv \
src/axi/src/axi_join.sv \
src/fpga-support/rtl/SyncSpRamBeNx64.sv \

View file

@ -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 <zarubaf@iis.ee.ethz.ch>
//
// 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

258
src/serdiv.sv Normal file
View file

@ -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

View file

@ -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

27
tb/tb_serdiv/Makefile Executable file
View file

@ -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

314
tb/tb_serdiv/hdl/tb.sv Normal file
View file

@ -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

66
tb/tb_serdiv/hdl/tb.svh Normal file
View file

@ -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 <schaffner@iis.ee.ethz.ch>, 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);

117
tb/tb_serdiv/hdl/tb_div.sv Normal file
View file

@ -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)
///////////////////////////////////////////////

148
tb/tb_serdiv/hdl/tb_pkg.sv Normal file
View file

@ -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

116
tb/tb_serdiv/hdl/tb_rem.sv Normal file
View file

@ -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)
///////////////////////////////////////////////

127
tb/tb_serdiv/hdl/tb_udiv.sv Normal file
View file

@ -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)
///////////////////////////////////////////////

127
tb/tb_serdiv/hdl/tb_urem.sv Normal file
View file

@ -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)
///////////////////////////////////////////////

7
tb/tb_serdiv/tb.list Normal file
View file

@ -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