1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Ted Campbell.
// SPDX-License-Identifier: CC0-1.0
//With MULTI_CLK defined shows bug, without it is hidden
`define MULTI_CLK
//bug634
module t (
input i_clk_wr,
input i_clk_rd
);
wire wr$wen;
wire [7:0] wr$addr;
wire [7:0] wr$wdata;
wire [7:0] wr$rdata;
wire rd$wen;
wire [7:0] rd$addr;
wire [7:0] rd$wdata;
wire [7:0] rd$rdata;
wire clk_wr;
wire clk_rd;
`ifdef MULTI_CLK
assign clk_wr = i_clk_wr;
assign clk_rd = i_clk_rd;
`else
assign clk_wr = i_clk_wr;
assign clk_rd = i_clk_wr;
`endif
FooWr u_wr (
.i_clk ( clk_wr ),
.o_wen ( wr$wen ),
.o_addr ( wr$addr ),
.o_wdata ( wr$wdata ),
.i_rdata ( wr$rdata )
);
FooRd u_rd (
.i_clk ( clk_rd ),
.o_wen ( rd$wen ),
.o_addr ( rd$addr ),
.o_wdata ( rd$wdata ),
.i_rdata ( rd$rdata )
);
FooMem u_mem (
.iv_clk ( {clk_wr, clk_rd } ),
.iv_wen ( {wr$wen, rd$wen } ),
.iv_addr ( {wr$addr, rd$addr } ),
.iv_wdata ( {wr$wdata,rd$wdata} ),
.ov_rdata ( {wr$rdata,rd$rdata} )
);
endmodule
// Memory Writer
module FooWr(
input i_clk,
output o_wen,
output [7:0] o_addr,
output [7:0] o_wdata,
input [7:0] i_rdata
);
reg [7:0] cnt = 0;
// Count [0,200]
always @( posedge i_clk )
if ( cnt < 8'd50 )
cnt <= cnt + 8'd1;
// Write addr in (10,30) if even
assign o_wen = ( cnt > 8'd10 ) && ( cnt < 8'd30 ) && ( cnt[0] == 1'b0 );
assign o_addr = cnt;
assign o_wdata = cnt;
endmodule
// Memory Reader
module FooRd(
input i_clk,
output o_wen,
output [7:0] o_addr,
output [7:0] o_wdata,
input [7:0] i_rdata
);
reg [7:0] cnt = 0;
reg [7:0] addr_r;
reg en_r;
// Count [0,200]
always @( posedge i_clk )
if ( cnt < 8'd200 )
cnt <= cnt + 8'd1;
// Read data
assign o_wen = 0;
assign o_addr = cnt - 8'd100;
// Track issued read
always @( posedge i_clk )
begin
addr_r <= o_addr;
en_r <= ( cnt > 8'd110 ) && ( cnt < 8'd130 ) && ( cnt[0] == 1'b0 );
end
// Display to console 100 cycles after writer
always @( negedge i_clk )
if ( en_r ) begin
`ifdef TEST_VERBOSE
$display( "MEM[%x] == %x", addr_r, i_rdata );
`endif
if (addr_r != i_rdata) $stop;
end
endmodule
// Multi-port memory abstraction
module FooMem(
input [2 -1:0] iv_clk,
input [2 -1:0] iv_wen,
input [2*8-1:0] iv_addr,
input [2*8-1:0] iv_wdata,
output [2*8-1:0] ov_rdata
);
FooMemImpl u_impl (
.a_clk ( iv_clk [0*1+:1] ),
.a_wen ( iv_wen [0*1+:1] ),
.a_addr ( iv_addr [0*8+:8] ),
.a_wdata ( iv_wdata[0*8+:8] ),
.a_rdata ( ov_rdata[0*8+:8] ),
.b_clk ( iv_clk [1*1+:1] ),
.b_wen ( iv_wen [1*1+:1] ),
.b_addr ( iv_addr [1*8+:8] ),
.b_wdata ( iv_wdata[1*8+:8] ),
.b_rdata ( ov_rdata[1*8+:8] )
);
endmodule
// Dual-Port L1 Memory Implementation
module FooMemImpl(
input a_clk,
input a_wen,
input [7:0] a_addr,
input [7:0] a_wdata,
output reg [7:0] a_rdata,
input b_clk,
input b_wen,
input [7:0] b_addr,
input [7:0] b_wdata,
output reg [7:0] b_rdata
);
/* verilator lint_off MULTIDRIVEN */
reg [7:0] mem[0:255];
/* verilator lint_on MULTIDRIVEN */
always @( posedge a_clk )
if ( a_wen )
mem[a_addr] <= a_wdata;
always @( posedge b_clk )
if ( b_wen )
mem[b_addr] <= b_wdata;
always @( posedge a_clk )
a_rdata <= mem[a_addr];
always @( posedge b_clk )
b_rdata <= mem[b_addr];
endmodule
|