diff --git a/Changes b/Changes index 04506c9bd..2e63a8376 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks! * Verilator 3.64** +*** Support SystemVerilog .name and .* interconnect. + *** Support while and do-while loops. **** Fix dotted bit reference to local memory. [Eugene Weber] diff --git a/bin/verilator b/bin/verilator index e0881c518..2f14a44f3 100755 --- a/bin/verilator +++ b/bin/verilator @@ -893,7 +893,7 @@ as the build system. =head1 VERILOG 2001 (IEEE 1364-2001) SUPPORT -Verilator supports the more common Verilog 2001 language features. This +Verilator supports almost all Verilog 2001 language features. This includes signed numbers, "always @*", comma separated sensitivity lists, generate statements, multidimensional arrays, localparam, and C-style declarations inside port lists. @@ -907,15 +907,16 @@ Verilator partially supports the uwire keyword. =head1 SYSTEMVERILOG (IEEE 1800-2005) SUPPORT -Verilator currently has very minimal support for SystemVerilog as they -become more common, contact the author if a feature you need is missing. +Verilator currently has very minimal support for SystemVerilog. As +SystemVerilog features enter common usage they will be added. Contact the +author if a feature you need is missing. Verilator implements the full SystemVerilog 1800-2005 preprocessor subset, including function call-like preprocessor defines. Verilator supports $bits, $countones, $error, $fatal, $info, $isunknown, -$onehot, $onehot0, $warning, always_comb, always_ff, always_latch, and -final. +$onehot, $onehot0, $warning, always_comb, always_ff, always_latch, +do-while, and final. It also supports .name and .* interconnection. Verilator partially supports assert. diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 59d0d0bcb..3dde53f90 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -298,6 +298,7 @@ void AstCell::dump(ostream& str) { this->AstNode::dump(str); if (modp()) { str<<" -> "; modp()->dump(str); } else { str<<" ->UNLINKED:"<AstNode::dump(str); @@ -307,6 +308,7 @@ void AstPin::dump(ostream& str) { this->AstNode::dump(str); if (modVarp()) { str<<" -> "; modVarp()->dump(str); } else { str<<" ->UNLINKED"; } + if (svImplicit()) str<<" [.SV]"; } void AstVarXRef::dump(ostream& str) { this->AstNode::dump(str); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 0dff4bd49..3e422845a 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -576,10 +576,11 @@ private: int m_pinNum; // Pin number string m_name; // Pin name, or "" for number based interconnect AstVar* m_modVarp; // Input/output this pin connects to on submodule. + bool m_svImplicit; // Pin is SystemVerilog .name'ed public: AstPin(FileLine* fl, int pinNum, const string& name, AstNode* exprp) :AstNode(fl) - ,m_name(name) { + ,m_name(name), m_svImplicit(false) { m_pinNum = pinNum; m_modVarp = NULL; setNOp1p(exprp); } @@ -596,6 +597,8 @@ public: AstNode* exprp() const { return op1p()->castNode(); } // op1 = Expression connected to pin AstVar* modVarp() const { return m_modVarp; } // [After Link] Pointer to variable void modVarp(AstVar* varp) { m_modVarp=varp; } + bool svImplicit() const { return m_svImplicit; } + void svImplicit(bool flag) { m_svImplicit=flag; } }; struct AstModule : public AstNode { @@ -652,12 +655,14 @@ private: string m_name; // Cell name string m_origName; // Original name before dot addition string m_modName; // Module the cell instances + bool m_pinStar; // Pin list has .* AstModule* m_modp; // [AfterLink] Pointer to module instanced public: AstCell(FileLine* fl, const string& instName, const string& modName, AstPin* pinsp, AstPin* paramsp, AstRange* rangep) : AstNode(fl) - , m_name(instName), m_origName(instName), m_modName(modName), m_modp(NULL) { + , m_name(instName), m_origName(instName), m_modName(modName) + , m_pinStar(false), m_modp(NULL) { addNOp1p(pinsp); addNOp2p(paramsp); setNOp3p(rangep); } virtual ~AstCell() {} virtual AstType type() const { return AstType::CELL;} @@ -674,6 +679,8 @@ public: void origName(const string& name) { m_origName = name; } string modName() const { return m_modName; } // * = Instance name void modName(const string& name) { m_modName = name; } + bool pinStar() const { return m_pinStar; } + void pinStar(bool flag) { m_pinStar = flag; } AstPin* pinsp() const { return op1p()->castPin(); } // op1 = List of cell ports AstPin* paramsp() const { return op2p()->castPin(); } // op2 = List of parameter #(##) values AstRange* rangep() const { return op3p()->castRange(); } // op3 = Range of arrayed instants (NULL=not ranged) diff --git a/src/V3Link.cpp b/src/V3Link.cpp index 11bdd64c9..06111472d 100644 --- a/src/V3Link.cpp +++ b/src/V3Link.cpp @@ -372,7 +372,8 @@ private: } } // Deal with implicit definitions - if (m_idState==ID_RESOLVE && nodep->modVarp()) { + if (m_idState==ID_RESOLVE && nodep->modVarp() + && !nodep->svImplicit()) { // SV 19.11.3: .name pins don't allow implicit decls pinImplicitExprRecurse(nodep->exprp()); } nodep->iterateChildren(*this); diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index f38fe3009..d35e42a31 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -163,6 +163,32 @@ private: new V3GraphEdge(&m_graph, vertex(m_modp), vertex(modp), 1, false); } } + // Convert .* to list of pins + if (nodep->modp() && nodep->pinStar()) { + // Note what pins exist + UINFO(9," CELL .* connect "<pinsp(); pinp; pinp=pinp->nextp()->castPin()) { + if (pinp->name()=="") pinp->v3error("Connect by position is illegal in .* connected cells"); + if (!ports.findIdName(pinp->name())) { + ports.insert(pinp->name(), pinp); + } + } + // We search ports, rather then in/out declarations as they aren't resolved yet, + // and it's easier to do it now then in V3Link when we'd need to repeat steps. + for (AstNode* portnodep = nodep->modp()->stmtsp(); portnodep; portnodep=portnodep->nextp()) { + if (AstPort* portp = portnodep->castPort()) { + if (!ports.findIdName(portp->name())) { + UINFO(9," need PORT "<fileline(),0,portp->name(), + new AstVarRef(nodep->fileline(),portp->name(),false)); + newp->svImplicit(true); + nodep->addPinsp(newp); + } + } + } + } // Convert unnamed pins to pin number based assignments for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) { if (pinp->name()=="") pinp->name("__pinNumber"+cvtToStr(pinp->pinNum())); diff --git a/src/verilog.y b/src/verilog.y index e6489c130..cbe9fa078 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -53,6 +53,7 @@ public: static AstCase* s_caseAttrp; // Current case statement for attribute adding static AstRange* s_varRangep; // Pointer to range for next signal declaration static int s_pinNum; // Pin number currently parsing + static bool s_pinStar; // Encountered SystemVerilog .* static string s_instModule; // Name of module referenced for instantiations static AstPin* s_instParamp; // Parameters for instantiations static bool s_trace; // Tracing is turned on @@ -75,6 +76,7 @@ AstVarType V3Parse::s_varIO = AstVarType::UNKNOWN; bool V3Parse::s_varSigned = false; AstRange* V3Parse::s_varRangep = NULL; int V3Parse::s_pinNum = -1; +bool V3Parse::s_pinStar = false; string V3Parse::s_instModule; AstPin* V3Parse::s_instParamp = NULL; AstVar* V3Parse::s_varAttrp = NULL; @@ -108,6 +110,7 @@ class AstSenTree; AstBegin* beginp; AstCase* casep; AstCaseItem* caseitemp; + AstCell* cellp; AstConst* constp; AstFunc* funcp; AstFuncRef* funcrefp; @@ -240,7 +243,8 @@ class AstSenTree; %type netSig netSigList %type rangeListE regrangeE anyrange rangeList delayrange portrangeE %type param paramList -%type instnameList instname +%type instnameList +%type instname %type cellpinList cellpinlist2 cellpinitemE instparamListE %type defpList defpOne %type sensitivityE @@ -614,10 +618,10 @@ instnameList: instname { $$ = $1; } | instnameList ',' instname { $$ = $1->addNext($3); } ; -instname: yID funcRange '(' cellpinList ')' { $$ = new AstCell($3,*$1,V3Parse::s_instModule,$4,V3Parse::s_instParamp,$2); } +instname: yID funcRange '(' cellpinList ')' { $$ = new AstCell($3,*$1,V3Parse::s_instModule,$4,V3Parse::s_instParamp,$2); $$->pinStar(V3Parse::s_pinStar); } ; -cellpinList: {V3Parse::s_pinNum=1;} cellpinlist2 { $$ = $2; } +cellpinList: {V3Parse::s_pinNum=1; V3Parse::s_pinStar=false; } cellpinlist2 { $$ = $2; } ; cellpinlist2: cellpinitemE { $$ = $1; } @@ -625,6 +629,8 @@ cellpinlist2: cellpinitemE { $$ = $1; } ; cellpinitemE: /* empty */ { $$ = NULL; V3Parse::s_pinNum++; } + | '.' '*' { $$ = NULL; if (V3Parse::s_pinStar) $1->v3error("Duplicate .* in a cell"); V3Parse::s_pinStar=true; } + | '.' yID { $$ = new AstPin($1,V3Parse::s_pinNum++,*$2,new AstVarRef($1,*$2,false)); $$->svImplicit(true);} | '.' yID '(' ')' { $$ = NULL; V3Parse::s_pinNum++; } | '.' yID '(' expr ')' { $$ = new AstPin($1,V3Parse::s_pinNum++,*$2,$4); } | expr { $$ = new AstPin(CRELINE(),V3Parse::s_pinNum++,"",$1); } diff --git a/test_regress/t/t_inst_sv.pl b/test_regress/t/t_inst_sv.pl new file mode 100755 index 000000000..7bfdbe852 --- /dev/null +++ b/test_regress/t/t_inst_sv.pl @@ -0,0 +1,18 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; } +# $Id$ +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# General Public License or the Perl Artistic License. + +compile ( + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_inst_sv.v b/test_regress/t/t_inst_sv.v new file mode 100644 index 000000000..fe704a46c --- /dev/null +++ b/test_regress/t/t_inst_sv.v @@ -0,0 +1,75 @@ +// $Id$ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2007 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + integer cyc; initial cyc=1; + + supply0 [1:0] low; + supply1 [1:0] high; + + reg [7:0] isizedwire; + reg ionewire; + + wire oonewire; + wire [7:0] osizedreg; // From sub of t_inst_v2k_sub.v + + t_inst sub + ( + .osizedreg, + .oonewire, + // Inputs + .isizedwire (isizedwire[7:0]), + .* + //.ionewire (ionewire) + ); + + always @ (posedge clk) begin + if (cyc!=0) begin + cyc <= cyc + 1; + if (cyc==1) begin + ionewire <= 1'b1; + isizedwire <= 8'd8; + end + if (cyc==2) begin + if (low != 2'b00) $stop; + if (high != 2'b11) $stop; + if (oonewire !== 1'b1) $stop; + if (isizedwire !== 8'd8) $stop; + end + if (cyc==3) begin + ionewire <= 1'b0; + isizedwire <= 8'd7; + end + if (cyc==4) begin + if (oonewire !== 1'b0) $stop; + if (isizedwire !== 8'd7) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + end +endmodule + +module t_inst + ( + output reg [7:0] osizedreg, + output wire oonewire /*verilator public*/, + input [7:0] isizedwire, + input wire ionewire + ); + + assign oonewire = ionewire; + + always @* begin + osizedreg = isizedwire; + end + +endmodule