Fix simulation error when inputs and MULTIDRIVEN, bug634.

This commit is contained in:
Wilson Snyder 2013-05-02 08:23:17 -04:00
parent d581582339
commit 1bea845ceb
5 changed files with 310 additions and 12 deletions

View File

@ -9,6 +9,8 @@ indicates the contributor was also the author of the fix; Thanks!
*** Add --pins-sc-uint and --pins-sc-biguint, bug638. [Alex Hornung]
**** Fix simulation error when inputs and MULTIDRIVEN, bug634. [Ted Campbell]
**** Fix module resolution with __, bug631. [Jason McMullan]

View File

@ -375,8 +375,10 @@ private:
void processBrokeLoop();
#endif
void processCircular();
typedef deque<OrderEitherVertex*> VertexVec;
void processInputs();
void processInputsIterate(OrderEitherVertex* vertexp);
void processInputsInIterate(OrderEitherVertex* vertexp, VertexVec& todoVec);
void processInputsOutIterate(OrderEitherVertex* vertexp, VertexVec& todoVec);
void processSensitive();
void processDomains();
void processDomainsIterate(OrderEitherVertex* vertexp);
@ -1059,28 +1061,33 @@ void OrderVisitor::processBrokeLoop() {
// Clock propagation
void OrderVisitor::processInputs() {
m_graph.userClearVertices(); // Vertex::user() // true if processed
m_graph.userClearVertices(); // Vertex::user() // 1 if input recursed, 2 if marked as input, 3 if out-edges recursed
// Start at input vertex, process from input-to-output order
VertexVec todoVec; // List of newly-input marked vectors we need to process
todoVec.push_front(m_inputsVxp);
m_inputsVxp->isFromInput(true); // By definition
processInputsIterate(m_inputsVxp);
while (!todoVec.empty()) {
OrderEitherVertex* vertexp = todoVec.back(); todoVec.pop_back();
processInputsOutIterate(vertexp, todoVec);
}
}
void OrderVisitor::processInputsIterate(OrderEitherVertex* vertexp) {
void OrderVisitor::processInputsInIterate(OrderEitherVertex* vertexp, VertexVec& todoVec) {
// Propagate PrimaryIn through simple assignments
if (vertexp->user()) return; // Already processed
if (0 && debug()>=9) {
UINFO(9," InIt "<<vertexp<<endl);
UINFO(9," InIIter "<<vertexp<<endl);
if (OrderLogicVertex* vvertexp = dynamic_cast<OrderLogicVertex*>(vertexp)) {
vvertexp->nodep()->dumpTree(cout,"- TT: ");
}
}
vertexp->user(true); // Processing
vertexp->user(1); // Processing
// First handle all inputs to this vertex, in most cases they'll be already processed earlier
// Also, determine if this vertex is an input
int inonly = 1; // 0=no, 1=maybe, 2=yes until a no
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) {
OrderEitherVertex* frVertexp = (OrderEitherVertex*)edgep->fromp();
processInputsIterate(frVertexp);
processInputsInIterate(frVertexp, todoVec);
if (frVertexp->isFromInput()) {
if (inonly==1) inonly = 2;
} else if (dynamic_cast<OrderVarPostVertex*>(frVertexp)) {
@ -1091,20 +1098,38 @@ void OrderVisitor::processInputsIterate(OrderEitherVertex* vertexp) {
break;
}
}
if (inonly == 2) { // Set it. Note may have already been set earlier, too
if (inonly == 2 && vertexp->user()<2) { // Set it. Note may have already been set earlier, too
UINFO(9," Input reassignment: "<<vertexp<<endl);
vertexp->isFromInput(true);
vertexp->user(2); // 2 means on list
// Can't work on out-edges of a node we know is an input immediately,
// as it might visit other nodes before their input state is resolved.
// So push to list and work on it later when all in-edges known resolved
todoVec.push_back(vertexp);
}
// If we're still an input, process all targets of this vertex
if (vertexp->isFromInput()) {
//UINFO(9," InIdone "<<vertexp<<endl);
}
void OrderVisitor::processInputsOutIterate(OrderEitherVertex* vertexp, VertexVec& todoVec) {
if (vertexp->user()==3) return; // Already out processed
//UINFO(9," InOIter "<<vertexp<<endl);
// First make sure input path is fully recursed
processInputsInIterate(vertexp, todoVec);
// Propagate PrimaryIn through simple assignments
if (!vertexp->isFromInput()) v3fatalSrc("processInputsOutIterate only for input marked vertexes");
vertexp->user(3); // out-edges processed
{
// Propagate PrimaryIn through simple assignments, followint target of vertex
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
OrderEitherVertex* toVertexp = (OrderEitherVertex*)edgep->top();
if (OrderVarStdVertex* vvertexp = dynamic_cast<OrderVarStdVertex*>(toVertexp)) {
processInputsIterate(vvertexp);
processInputsInIterate(vvertexp, todoVec);
}
if (OrderLogicVertex* vvertexp = dynamic_cast<OrderLogicVertex*>(toVertexp)) {
if (vvertexp->nodep()->castNodeAssign()) {
processInputsIterate(vvertexp);
processInputsInIterate(vvertexp, todoVec);
}
}
}

View File

@ -0,0 +1,56 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Ted Campbell.
#include "Vt_order_multidriven.h"
#include "verilated.h"
#include "verilated_vcd_c.h"
Vt_order_multidriven * vcore;
VerilatedVcdC * vcd;
vluint64_t vtime;
#define PHASE_90
static void half_cycle( int clk ) {
if ( clk & 1 ) vcore->i_clk_wr = !vcore->i_clk_wr;
if ( clk & 2 ) vcore->i_clk_rd = !vcore->i_clk_rd;
vtime += 10 / 2;
vcore->eval();
vcore->eval();
vcd->dump( vtime );
}
static void cycle() {
#ifdef PHASE_90
half_cycle( 1 );
half_cycle( 2 );
half_cycle( 1 );
half_cycle( 2 );
#else
half_cycle( 3 );
half_cycle( 3 );
#endif
}
int main() {
Verilated::traceEverOn( true );
vcore = new Vt_order_multidriven;
vcd = new VerilatedVcdC;
vcore->trace( vcd, 99 );
vcd->open( "obj_dir/t_order_multidriven/sim.vcd" );
vcore->i_clk_wr = 0;
vcore->i_clk_rd = 0;
for ( int i = 0; i < 256; ++i )
cycle( );
vcd->close( );
printf("*-* All Finished *-*\n");
}

View File

@ -0,0 +1,23 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2013 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} or $Self->skip("Verilator only test");
compile (
make_top_shell => 0,
make_main => 0,
v_flags2 => ["--trace --exe $Self->{t_dir}/t_order_multidriven.cpp"],
);
execute (
check_finished=>1,
);
ok(1);
1;

View File

@ -0,0 +1,192 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Ted Campbell.
//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 [7:0] a_rdata,
input b_clk,
input b_wen,
input [7:0] b_addr,
input [7:0] b_wdata,
output [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