Fix simulation error when inputs and MULTIDRIVEN, bug634.
This commit is contained in:
parent
d581582339
commit
1bea845ceb
2
Changes
2
Changes
|
|
@ -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]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue