mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-11-22 14:33:51 +00:00
182 lines
4.8 KiB
Verilog
182 lines
4.8 KiB
Verilog
// DESCRIPTION: Verilator: Verilog Test module
|
|
//
|
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
|
// any use, without warranty, 2010 by Wilson Snyder.
|
|
// SPDX-License-Identifier: CC0-1.0
|
|
//
|
|
// --------------------------------------------------------
|
|
// Bug Description:
|
|
//
|
|
// Issue: The gated clock gclk_vld[0] toggles but dvld[0]
|
|
// input to the flop does not propagate to the output
|
|
// signal entry_vld[0] correctly. The value that propagates
|
|
// is the new value of dvld[0] not the one just before the
|
|
// posedge of gclk_vld[0].
|
|
// --------------------------------------------------------
|
|
|
|
// Define to see the bug with test failing with gated clock 'gclk_vld'
|
|
// Comment out the define to see the test passing with ungated clock 'clk'
|
|
`define GATED_CLK_TESTCASE 1
|
|
|
|
// A side effect of the problem is this warning, disabled by default
|
|
//verilator lint_on IMPERFECTSCH
|
|
|
|
// Test Bench
|
|
module t (/*AUTOARG*/
|
|
// Inputs
|
|
clk
|
|
);
|
|
input clk;
|
|
|
|
integer cyc=0;
|
|
reg [63:0] crc;
|
|
|
|
// Take CRC data and apply to testblock inputs
|
|
wire [7:0] dvld = crc[7:0];
|
|
wire [7:0] ff_en_e1 = crc[15:8];
|
|
|
|
/*AUTOWIRE*/
|
|
// Beginning of automatic wires (for undeclared instantiated-module outputs)
|
|
wire [7:0] entry_vld; // From test of Test.v
|
|
wire [7:0] ff_en_vld; // From test of Test.v
|
|
// End of automatics
|
|
|
|
Test test (/*AUTOINST*/
|
|
// Outputs
|
|
.ff_en_vld (ff_en_vld[7:0]),
|
|
.entry_vld (entry_vld[7:0]),
|
|
// Inputs
|
|
.clk (clk),
|
|
.dvld (dvld[7:0]),
|
|
.ff_en_e1 (ff_en_e1[7:0]));
|
|
|
|
reg err_code;
|
|
reg ffq_clk_active;
|
|
reg [7:0] prv_dvld;
|
|
|
|
initial begin
|
|
err_code = 0;
|
|
ffq_clk_active = 0;
|
|
end
|
|
always @ (posedge clk) begin
|
|
prv_dvld = test.dvld;
|
|
end
|
|
always @ (negedge test.ff_entry_dvld_0.clk) begin
|
|
ffq_clk_active = 1;
|
|
if (test.entry_vld[0] !== prv_dvld[0]) err_code = 1;
|
|
end
|
|
|
|
// Test loop
|
|
always @ (posedge clk) begin
|
|
`ifdef TEST_VERBOSE
|
|
$write("[%0t] cyc==%0d crc=%x ",$time, cyc, crc);
|
|
$display(" en=%b fen=%b d=%b ev=%b",
|
|
test.flop_en_vld[0], test.ff_en_vld[0],
|
|
test.dvld[0], test.entry_vld[0]);
|
|
`endif
|
|
cyc <= cyc + 1;
|
|
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
|
if (cyc<3) begin
|
|
crc <= 64'h5aef0c8d_d70a4497;
|
|
end
|
|
else if (cyc==99) begin
|
|
$write("[%0t] cyc==%0d crc=%x\n",$time, cyc, crc);
|
|
if (ffq_clk_active == 0) begin
|
|
$display ("----");
|
|
$display ("%%Error: TESTCASE FAILED with no Clock arriving at FFQs");
|
|
$display ("----");
|
|
$stop;
|
|
end
|
|
else if (err_code) begin
|
|
$display ("----");
|
|
$display ("%%Error: TESTCASE FAILED with invalid propagation of 'd' to 'q' of FFQs");
|
|
$display ("----");
|
|
$stop;
|
|
end
|
|
else begin
|
|
$write("*-* All Finished *-*\n");
|
|
$finish;
|
|
end
|
|
end
|
|
end
|
|
|
|
endmodule
|
|
|
|
module llq (clk, d, q);
|
|
parameter WIDTH = 32;
|
|
input clk;
|
|
input [WIDTH-1:0] d;
|
|
output [WIDTH-1:0] q;
|
|
|
|
reg [WIDTH-1:0] qr;
|
|
|
|
/* verilator lint_off COMBDLY */
|
|
/* verilator lint_off LATCH */
|
|
|
|
always @(clk or d)
|
|
if (clk == 1'b0)
|
|
qr <= d;
|
|
|
|
/* verilator lint_on LATCH */
|
|
/* verilator lint_on COMBDLY */
|
|
|
|
assign q = qr;
|
|
endmodule
|
|
|
|
module ffq (clk, d, q);
|
|
parameter WIDTH = 32;
|
|
input clk;
|
|
input [WIDTH-1:0] d;
|
|
output [WIDTH-1:0] q;
|
|
|
|
reg [WIDTH-1:0] qr;
|
|
|
|
always @(posedge clk)
|
|
qr <= d;
|
|
|
|
assign q = qr;
|
|
endmodule
|
|
|
|
// DUT module
|
|
module Test (/*AUTOARG*/
|
|
// Outputs
|
|
ff_en_vld, entry_vld,
|
|
// Inputs
|
|
clk, dvld, ff_en_e1
|
|
);
|
|
input clk;
|
|
|
|
input [7:0] dvld;
|
|
input [7:0] ff_en_e1;
|
|
|
|
output [7:0] ff_en_vld;
|
|
output wire [7:0] entry_vld;
|
|
|
|
wire [7:0] gclk_vld;
|
|
wire [7:0] ff_en_vld /*verilator clock_enable*/;
|
|
reg [7:0] flop_en_vld;
|
|
|
|
always @(posedge clk) flop_en_vld <= ff_en_e1;
|
|
|
|
// clock gating
|
|
`ifdef GATED_CLK_TESTCASE
|
|
assign gclk_vld = {8{clk}} & ff_en_vld;
|
|
`else
|
|
assign gclk_vld = {8{clk}};
|
|
`endif
|
|
|
|
// latch for avoiding glitch on the clock gating control
|
|
llq #(8) dp_ff_en_vld (.clk(clk), .d(flop_en_vld), .q(ff_en_vld));
|
|
|
|
// flops that use the gated clock signal
|
|
ffq #(1) ff_entry_dvld_0 (.clk(gclk_vld[0]), .d(dvld[0]), .q(entry_vld[0]));
|
|
ffq #(1) ff_entry_dvld_1 (.clk(gclk_vld[1]), .d(dvld[1]), .q(entry_vld[1]));
|
|
ffq #(1) ff_entry_dvld_2 (.clk(gclk_vld[2]), .d(dvld[2]), .q(entry_vld[2]));
|
|
ffq #(1) ff_entry_dvld_3 (.clk(gclk_vld[3]), .d(dvld[3]), .q(entry_vld[3]));
|
|
ffq #(1) ff_entry_dvld_4 (.clk(gclk_vld[4]), .d(dvld[4]), .q(entry_vld[4]));
|
|
ffq #(1) ff_entry_dvld_5 (.clk(gclk_vld[5]), .d(dvld[5]), .q(entry_vld[5]));
|
|
ffq #(1) ff_entry_dvld_6 (.clk(gclk_vld[6]), .d(dvld[6]), .q(entry_vld[6]));
|
|
ffq #(1) ff_entry_dvld_7 (.clk(gclk_vld[7]), .d(dvld[7]), .q(entry_vld[7]));
|
|
|
|
endmodule
|