From 1f2abb9c0f812bed0636600622bb6be46b2b48ea Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 15 May 2014 20:57:09 -0400 Subject: [PATCH] Fix gate primitives with arrays and non-arrayed pins. --- Changes | 2 + src/V3AstNodes.h | 13 +++++ src/V3Width.cpp | 26 ++++++++++ src/verilog.y | 65 +++++++++++++++---------- test_regress/t/t_gate_array.pl | 18 +++++++ test_regress/t/t_gate_array.v | 88 ++++++++++++++++++++++++++++++++++ 6 files changed, 188 insertions(+), 24 deletions(-) create mode 100755 test_regress/t/t_gate_array.pl create mode 100644 test_regress/t/t_gate_array.v diff --git a/Changes b/Changes index f583bc0c2..c65dd7ae9 100644 --- a/Changes +++ b/Changes @@ -11,6 +11,8 @@ indicates the contributor was also the author of the fix; Thanks! **** Fix huge shifts to zero with -Wno-WIDTH, bug765. [Clifford Wolf] +**** Fix gate primitives with arrays and non-arrayed pins. + **** Fix ENDLABEL warnings on escaped identifiers. diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 2b1f38654..28226a72a 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -163,6 +163,19 @@ public: virtual bool same(AstNode* samep) const { return true; } }; +struct AstGatePin : public AstNodeMath { + // Possibly expand a gate primitive input pin value to match the range of the gate primitive + AstGatePin(FileLine* fl, AstNode* lhsp, AstRange* rangep) : AstNodeMath(fl) { + setOp1p(lhsp); setOp2p(rangep); + } + ASTNODE_NODE_FUNCS(GatePin, GATEPIN) + virtual string emitVerilog() { return "%l"; } + virtual string emitC() { V3ERROR_NA; return ""; } + virtual bool cleanOut() { return true; } + AstNode* exprp() const { return op1p(); } // op1 = Pin expression + AstRange* rangep() const { return op2p()->castRange(); } // op2 = Range of pin +}; + //###################################################################### //==== Data Types diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 271f878a2..590fe2220 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1849,6 +1849,32 @@ private: nodep->paramsp()->iterateAndNext(*this); m_cellRangep = NULL; } + virtual void visit(AstGatePin* nodep, AstNUser* vup) { + if (vup->c()->prelim()) { + nodep->rangep()->iterateAndNext(*this,WidthVP(SELF,BOTH).p()); + nodep->exprp()->iterateAndNext(*this,WidthVP(CONTEXT,PRELIM).p()); + nodep->dtypeFrom(nodep->rangep()); + // Very much like like an pin + AstNodeDType* conDTypep = nodep->exprp()->dtypep(); + int numInsts = nodep->rangep()->elementsConst(); + int pinwidth = numInsts; + int conwidth = conDTypep->width(); + if (conwidth == 1 && pinwidth > 1) { // Multiple connections + AstNodeDType* subDTypep = nodep->findLogicDType(1,1, conDTypep->numeric()); + nodep->exprp()->iterateAndNext(*this,WidthVP(subDTypep,FINAL).p()); + AstNode* newp = new AstReplicate(nodep->fileline(), + nodep->exprp()->unlinkFrBack(), + numInsts); + nodep->replaceWith(newp); + } + else { + // Eliminating so pass down all of vup + nodep->exprp()->iterateAndNext(*this,vup); + nodep->replaceWith(nodep->exprp()->unlinkFrBack()); + } + pushDeletep(nodep); nodep=NULL; + } + } virtual void visit(AstNodeFTask* nodep, AstNUser* vup) { // Grab width from the output variable (if it's a function) if (nodep->didWidth()) return; diff --git a/src/verilog.y b/src/verilog.y index 8f0e35ede..2b6389abe 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -55,6 +55,7 @@ public: AstVarType m_varDecl; // Type for next signal declaration (reg/wire/etc) AstVarType m_varIO; // Type for next signal declaration (input/output/etc) AstVar* m_varAttrp; // Current variable for attribute adding + AstRange* m_gateRangep; // Current range for gate declarations AstCase* m_caseAttrp; // Current case statement for attribute adding AstNodeDType* m_varDTypep; // Pointer to data type for next signal declaration AstNodeDType* m_memDTypep; // Pointer to data type for next member declaration @@ -70,6 +71,7 @@ public: m_varDecl = AstVarType::UNKNOWN; m_varIO = AstVarType::UNKNOWN; m_varDTypep = NULL; + m_gateRangep = NULL; m_memDTypep = NULL; m_pinNum = -1; m_instModule = ""; @@ -98,6 +100,11 @@ public: nodep->addNext(new AstStop(fileline)); return nodep; } + AstNode* createGatePin(AstNode* exprp) { + AstRange* rangep = m_gateRangep; + if (!rangep) return exprp; + else return new AstGatePin(rangep->fileline(), exprp, rangep->cloneTree(true)); + } void endLabel(FileLine* fl, AstNode* nodep, string* endnamep) { endLabel(fl, nodep->prettyName(), endnamep); } void endLabel(FileLine* fl, string name, string* endnamep) { if (fl && endnamep && *endnamep != "" && name != *endnamep @@ -176,6 +183,8 @@ const AstBasicDTypeKwd LOGIC_IMPLICIT = AstBasicDTypeKwd::LOGIC_IMPLICIT; #define VARDONEP(portp,array,attrs) GRAMMARP->createVariable((portp)->fileline(),(portp)->name(),(array),(attrs)) #define PINNUMINC() (GRAMMARP->m_pinNum++) +#define GATERANGE(rangep) { GRAMMARP->m_gateRangep = rangep; } + #define INSTPREP(modname,paramsp) { GRAMMARP->m_impliedDecl = true; GRAMMARP->m_instModule = modname; GRAMMARP->m_instParamp = paramsp; } #define DEL(nodep) { if (nodep) nodep->deleteTree(); } @@ -1921,7 +1930,7 @@ sigAttr: | yVL_PUBLIC_FLAT { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT); v3Global.dpi(true); } | yVL_PUBLIC_FLAT_RD { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RD); v3Global.dpi(true); } | yVL_PUBLIC_FLAT_RW { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RW); v3Global.dpi(true); } - | yVL_PUBLIC_FLAT_RW attr_event_control { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RW); v3Global.dpi(true); + | yVL_PUBLIC_FLAT_RW attr_event_control { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RW); v3Global.dpi(true); $$ = $$->addNext(new AstAlwaysPublic($1,$2,NULL)); } | yVL_ISOLATE_ASSIGNMENTS { $$ = new AstAttrOf($1,AstAttrType::VAR_ISOLATE_ASSIGNMENTS); } | yVL_SC_BV { $$ = new AstAttrOf($1,AstAttrType::VAR_SC_BV); } @@ -3255,62 +3264,66 @@ gateUnsupList: | gateUnsupList ',' gateUnsup { $$ = $1->addNext($3); } ; +gateRangeE: + instRangeE { $$ = $1; GATERANGE($1); } + ; + gateBuf: - gateIdE instRangeE '(' variable_lvalue ',' expr ')' + gateIdE gateRangeE '(' variable_lvalue ',' gatePinExpr ')' { $$ = new AstAssignW ($3,$4,$6); DEL($2); } ; gateBufif0: - gateIdE instRangeE '(' variable_lvalue ',' expr ',' expr ')' + gateIdE gateRangeE '(' variable_lvalue ',' gatePinExpr ',' gatePinExpr ')' { $$ = new AstAssignW ($3,$4,new AstBufIf1($3,new AstNot($3,$8),$6)); DEL($2); } ; gateBufif1: - gateIdE instRangeE '(' variable_lvalue ',' expr ',' expr ')' + gateIdE gateRangeE '(' variable_lvalue ',' gatePinExpr ',' gatePinExpr ')' { $$ = new AstAssignW ($3,$4,new AstBufIf1($3,$8,$6)); DEL($2); } ; gateNot: - gateIdE instRangeE '(' variable_lvalue ',' expr ')' + gateIdE gateRangeE '(' variable_lvalue ',' gatePinExpr ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); DEL($2); } ; gateNotif0: - gateIdE instRangeE '(' variable_lvalue ',' expr ',' expr ')' + gateIdE gateRangeE '(' variable_lvalue ',' gatePinExpr ',' gatePinExpr ')' { $$ = new AstAssignW ($3,$4,new AstBufIf1($3,new AstNot($3,$8), new AstNot($3, $6))); DEL($2); } ; gateNotif1: - gateIdE instRangeE '(' variable_lvalue ',' expr ',' expr ')' + gateIdE gateRangeE '(' variable_lvalue ',' gatePinExpr ',' gatePinExpr ')' { $$ = new AstAssignW ($3,$4,new AstBufIf1($3,$8, new AstNot($3,$6))); DEL($2); } ; gateAnd: - gateIdE instRangeE '(' variable_lvalue ',' gateAndPinList ')' + gateIdE gateRangeE '(' variable_lvalue ',' gateAndPinList ')' { $$ = new AstAssignW ($3,$4,$6); DEL($2); } ; gateNand: - gateIdE instRangeE '(' variable_lvalue ',' gateAndPinList ')' + gateIdE gateRangeE '(' variable_lvalue ',' gateAndPinList ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); DEL($2); } ; gateOr: - gateIdE instRangeE '(' variable_lvalue ',' gateOrPinList ')' + gateIdE gateRangeE '(' variable_lvalue ',' gateOrPinList ')' { $$ = new AstAssignW ($3,$4,$6); DEL($2); } ; gateNor: - gateIdE instRangeE '(' variable_lvalue ',' gateOrPinList ')' + gateIdE gateRangeE '(' variable_lvalue ',' gateOrPinList ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); DEL($2); } ; gateXor: - gateIdE instRangeE '(' variable_lvalue ',' gateXorPinList ')' + gateIdE gateRangeE '(' variable_lvalue ',' gateXorPinList ')' { $$ = new AstAssignW ($3,$4,$6); DEL($2); } ; gateXnor: - gateIdE instRangeE '(' variable_lvalue ',' gateXorPinList ')' + gateIdE gateRangeE '(' variable_lvalue ',' gateXorPinList ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); DEL($2); } ; gatePullup: - gateIdE instRangeE '(' variable_lvalue ')' { $$ = new AstPull ($3, $4, true); DEL($2); } + gateIdE gateRangeE '(' variable_lvalue ')' { $$ = new AstPull ($3, $4, true); DEL($2); } ; gatePulldown: - gateIdE instRangeE '(' variable_lvalue ')' { $$ = new AstPull ($3, $4, false); DEL($2); } + gateIdE gateRangeE '(' variable_lvalue ')' { $$ = new AstPull ($3, $4, false); DEL($2); } ; gateUnsup: - gateIdE instRangeE '(' gateUnsupPinList ')' { $$ = new AstImplicit ($3,$4); DEL($2); } + gateIdE gateRangeE '(' gateUnsupPinList ')' { $$ = new AstImplicit ($3,$4); DEL($2); } ; gateIdE: @@ -3319,20 +3332,24 @@ gateIdE: ; gateAndPinList: - expr { $$ = $1; } - | gateAndPinList ',' expr { $$ = new AstAnd($2,$1,$3); } + gatePinExpr { $$ = $1; } + | gateAndPinList ',' gatePinExpr { $$ = new AstAnd($2,$1,$3); } ; gateOrPinList: - expr { $$ = $1; } - | gateOrPinList ',' expr { $$ = new AstOr($2,$1,$3); } + gatePinExpr { $$ = $1; } + | gateOrPinList ',' gatePinExpr { $$ = new AstOr($2,$1,$3); } ; gateXorPinList: - expr { $$ = $1; } - | gateXorPinList ',' expr { $$ = new AstXor($2,$1,$3); } + gatePinExpr { $$ = $1; } + | gateXorPinList ',' gatePinExpr { $$ = new AstXor($2,$1,$3); } ; gateUnsupPinList: - expr { $$ = $1; } - | gateUnsupPinList ',' expr { $$ = $1->addNext($3); } + gatePinExpr { $$ = $1; } + | gateUnsupPinList ',' gatePinExpr { $$ = $1->addNext($3); } + ; + +gatePinExpr: + expr { $$ = GRAMMARP ->createGatePin($1); } ; strengthSpecE: // IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty diff --git a/test_regress/t/t_gate_array.pl b/test_regress/t/t_gate_array.pl new file mode 100755 index 000000000..30da50378 --- /dev/null +++ b/test_regress/t/t_gate_array.pl @@ -0,0 +1,18 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2004 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. + +compile ( + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_gate_array.v b/test_regress/t/t_gate_array.v new file mode 100644 index 000000000..6fcf23ccc --- /dev/null +++ b/test_regress/t/t_gate_array.v @@ -0,0 +1,88 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2014 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc=0; + reg [63:0] crc; + reg [63:0] sum; + + // Take CRC data and apply to testblock inputs + wire [7:0] a = crc[7:0]; + wire [7:0] b = crc[15:8]; + + /*AUTOWIRE*/ + // Beginning of automatic wires (for undeclared instantiated-module outputs) + wire [63:0] out; // From test of Test.v + // End of automatics + + Test test (/*AUTOINST*/ + // Outputs + .out (out[63:0]), + // Inputs + .clk (clk), + .a (a[7:0]), + .b (b[7:0])); + + // Aggregate outputs into a single result vector + wire [63:0] result = {out}; + + // Test loop + always @ (posedge clk) begin +`ifdef TEST_VERBOSE + $write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result); +`endif + cyc <= cyc + 1; + crc <= {crc[62:0], crc[63]^crc[2]^crc[0]}; + sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]}; + if (cyc==0) begin + // Setup + crc <= 64'h5aef0c8d_d70a4497; + sum <= 64'h0; + end + else if (cyc<10) begin + sum <= 64'h0; + end + else if (cyc<90) begin + end + else if (cyc==99) begin + $write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum); + if (crc !== 64'hc77bb9b3784ea091) $stop; + // What checksum will we end up with (above print should match) +`define EXPECTED_SUM 64'h0908a1f2194d24ee + if (sum !== `EXPECTED_SUM) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + +module Test (/*AUTOARG*/ + // Outputs + out, + // Inputs + clk, a, b + ); + + input clk; + input [7:0] a; + input [7:0] b; + output reg [63:0] out; + + and u0[7:0] (out[7:0], a[7:0], b[7:0]); + and u1[7:0] (out[15:8], a[0], b[7:0]); + and u2[7:0] (out[23:16], a[0], b[0]); + nand u3[7:0] (out[31:24], a[0], b[7:0]); + or u4[7:0] (out[39:32], a[0], b[7:0]); + nor u5[7:0] (out[47:40], a[0], b[7:0]); + xor u6[7:0] (out[55:48], a[0], b[7:0]); + xnor u7[7:0] (out[63:56], a[0], b[7:0]); + +endmodule