diff --git a/Changes b/Changes index b42f99059..0bd252726 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks! * Verilator 3.62** +**** Public functions now allow > 64 bit arguments. + **** Don't core dump on errors when not under --debug. [Allan Cochrane] **** Remove .vpp intermediate files when not under --debug. diff --git a/bin/verilator b/bin/verilator index 26eded8f6..e0f000a35 100755 --- a/bin/verilator +++ b/bin/verilator @@ -1088,9 +1088,9 @@ function. Any output arguments will become C++ reference arguments. Any local registers/integers will become function automatic variables on the stack. -Wide variables over 64 bits cannot be I/O to the module, to avoid exposing -complexities; generally the cleanest technique is to pass a word number to -the function, and do appropriate bit selection. +Wide variables over 64 bits cannot be function returns, to avoid exposing +complexities. However, wide variables can be input/outputs; they will be +passed as references to an array of 32 bit numbers. This feature is still somewhat experimental. Generally, only the values of stored state (flops) should be written, as the model will NOT notice diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index fc79a56b6..ab6aa13a2 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -103,6 +103,18 @@ string AstVar::verilogKwd() const { } string AstVar::cType() const { + if (widthMin() == 1) { + return "bool"; + } else if (widthMin() <= VL_WORDSIZE) { + return "uint32_t"; + } else if (isScWide()) { + return "uint32_t"; // []'s added later + } else { + return "uint64_t"; + } +} + +string AstVar::scType() const { if (widthMin() == 1) { return "bool"; } else if (widthMin() <= VL_WORDSIZE) { diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 1f33d1581..5050ee371 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -288,7 +288,8 @@ public: virtual string name() const { return m_name; } // * = Var name virtual bool maybePointedTo() const { return true; } AstVarType varType() const { return m_varType; } // * = Type of variable - string cType() const; // Return C type: bool, uint32_t, uint64_t, etc. + string cType() const; // Return C type for declaration: bool, uint32_t, uint64_t, etc. + string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv void combineType(AstVarType type); AstRange* rangep() const { return op1p()->castRange(); } // op1 = Range of variable AstRange* arraysp() const { return op2p()->castRange(); } // op2 = Array(s) of variable diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 207df58a8..45317202b 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -102,9 +102,16 @@ public: if (AstVar* portp = stmtp->castVar()) { if (portp->isIO() && !portp->isFuncReturn()) { if (args != "") args+= ", "; - args += portp->cType(); - if (portp->isOutput()) args += "&"; - args += " "+portp->name(); + if (portp->isWide()) { + if (portp->isInOnly()) args += "const "; + args += portp->cType(); + args += " (& "+portp->name(); + args += ")["+cvtToStr(portp->widthWords())+"]"; + } else { + args += portp->cType(); + if (portp->isOutput()) args += "&"; + args += " "+portp->name(); + } } } } @@ -707,7 +714,7 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) { else if (nodep->isOutput()) puts("sc_out<"); else nodep->v3fatalSrc("Unknown type"); - puts(nodep->cType()); + puts(nodep->scType()); puts(">\t"); } puts(nodep->name()); diff --git a/src/V3Task.cpp b/src/V3Task.cpp index a1efc0158..bb6436754 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -304,7 +304,7 @@ private: AstVar* portp = NULL; if (NULL!=(portp = nodep->castFunc()->fvarp()->castVar())) { if (!portp->isFuncReturn()) nodep->v3error("Not marked as function return var"); - if (portp->isWide()) nodep->v3error("Unsupported: Public functions/tasks with inputs or outputs > 64 bits wide."); + if (portp->isWide()) nodep->v3error("Unsupported: Public functions with return > 64 bits wide. (Make it a output instead.)"); portp->unlinkFrBack(); rtnvarp = portp; rtnvarp->funcLocal(true); @@ -339,11 +339,6 @@ private: portp->unlinkFrBack(); portp->funcLocal(true); funcp->addArgsp(portp); - if (portp->isWide()) { - // As we don't want to export our WData arrays to users, - // and casting to sc_bv's is ugly, we'll just... - nodep->v3error("Unsupported: Public functions/tasks with inputs or outputs > 64 bits wide."); - } } else { // "Normal" variable, mark inside function portp->funcLocal(true); diff --git a/test_regress/t/t_func_public.v b/test_regress/t/t_func_public.v index 2f11e985a..00e6ddec5 100644 --- a/test_regress/t/t_func_public.v +++ b/test_regress/t/t_func_public.v @@ -103,8 +103,8 @@ module tpub ( if (24'h11bca != got_long) $stop; $c("{ uint64_t qq; publicGetQuad(qq); got_quad=qq; }"); if (60'haaaa_bbbb_cccc != got_quad) $stop; - //Unsupported: $c("publicGetWide(got_wide);"); - //Unsupported: if (72'hac_abca_aaaa_bbbb_1234 != got_wide) $stop; + $c("{ WData gw[3]; publicGetWide(gw); VL_ASSIGN_W(72,got_wide,gw); }"); + if (72'hac_abca_aaaa_bbbb_1234 != got_wide) $stop; //Below doesn't work, because we're calling it inside the loop that sets var_flop // if (12'h321 != var_flop) $stop; end @@ -154,7 +154,7 @@ module tpub ( endtask task publicSetWide; - // Can't be public, as no wide return types in C++ + // verilator public input [71:0] in_wide; var_wide = in_wide; endtask @@ -178,7 +178,7 @@ module tpub ( endtask task publicGetWide; - // Can't be public, as no wide return types in C++ + // verilator public output [71:0] out_wide; out_wide = var_wide; endtask