mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-23 13:47:13 -04:00
Improve serial divider performance by aligning operands, add serdiv testbench to CI
This commit is contained in:
parent
7da347e17b
commit
76101fe9ed
15 changed files with 1345 additions and 317 deletions
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
1
Makefile
1
Makefile
|
@ -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 \
|
||||
|
|
113
src/mult.sv
113
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 <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
258
src/serdiv.sv
Normal 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
|
|
@ -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
27
tb/tb_serdiv/Makefile
Executable 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
314
tb/tb_serdiv/hdl/tb.sv
Normal 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
66
tb/tb_serdiv/hdl/tb.svh
Normal 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
117
tb/tb_serdiv/hdl/tb_div.sv
Normal 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
148
tb/tb_serdiv/hdl/tb_pkg.sv
Normal 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
116
tb/tb_serdiv/hdl/tb_rem.sv
Normal 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
127
tb/tb_serdiv/hdl/tb_udiv.sv
Normal 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
127
tb/tb_serdiv/hdl/tb_urem.sv
Normal 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
7
tb/tb_serdiv/tb.list
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue