Fix lvalue errors with public functions; bug25.

This commit is contained in:
Wilson Snyder 2008-07-22 11:15:28 -04:00
parent 4591f35b7c
commit fb34bf7222
5 changed files with 176 additions and 7 deletions

View File

@ -20,6 +20,8 @@ indicates the contributor was also the author of the fix; Thanks!
**** Fix IMPURE errors due to X-assignment temporary variables. [Steve Tong]
**** Fix "lvalue" errors with public functions; bug25. [CY Wang]
**** Add WIDTH warning to $fopen etc file descriptors.
**** Internal changes to how $displays get compiled and executed.

View File

@ -1311,10 +1311,9 @@ 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
changes made to variables in these functions. (Same as when a signal is
declared public.)
Generally, only the values of stored state (flops) should be written, as
the model will NOT notice changes made to variables in these functions.
(Same as when a signal is declared public.)
=item /*verilator public_flat*/ (variable)
@ -2153,11 +2152,49 @@ uses one large symbol table, as that results in 2-3 less assembly
instructions for each signal access. This makes the execution time 10-15%
faster, but can result in more compilations when something changes.
=item How do I access functions/tasks in C?
Write a Verilog function or task with input/outputs that match what you
want to call in with C. Then mark that function public.
Verilog inputs of one bit become C++ bool inputs. Inputs 32 bits or
smaller become C uint32_t inputs, 64-32 bits become C uint64_t inputs, and
wider signals become arrays of 32 bits. Outputs are passed as references
to bool, uint32_t, uint64_t or uint32_t[] arrays.
Signals wider than 64 bits are passed as an array of 32-bit uint32_t's.
Thus to read bits 31:0, access signal[0], and for bits 63:32, access
signal[1]. Unused bits (for example bit numbers 65-96 of a 65 bit vector)
will always be zero. if you change the value you must make sure to pack
zeros in the unused bits or core-dumps may result. (Because Verilator
strips array bound checks where it believes them to be unnecessary.)
In the SYSTEMC example above, if you had in our.v:
task publicSetBool;
// verilator public
input in_bool;
var_bool = in_bool;
endtask
From the sc_main.cpp file, you'd then:
#include "Vour.h"
#include "Vour_our.h"
top->v.publicSetBool(value);
See additional notes under the /*verilator public*/ section.
=item How do I access signals in C?
First, declare the signals you will be accessing with a /*verilator
public*/ comment before the closing semicolon. Then scope into the C++
class to read the value of the signal, as you would any other member variable.
The best thing is to make a Verilator public task or function accessor that
can read or write that signal, as described in the previous FAQ. This will
allow Verilator to better optimize the model.
If you really want raw access to the signals, declare the signals you will
be accessing with a /*verilator public*/ comment before the closing
semicolon. Then scope into the C++ class to read the value of the signal,
as you would any other member variable.
Signals are the smallest of 8 bit chars, 16 bit shorts, 32 bit longs, or 64
bit long longs that fits the width of the signal. Generally, you can use

View File

@ -199,6 +199,27 @@ private:
nodep->iterateChildren(*this);
m_ftaskp = NULL;
}
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
AstNode* pinp = nodep->pinsp();
AstNodeFTask* taskp = nodep->taskp();
// We'll deal with mismatching pins later
if (!taskp) return;
for (AstNode* stmtp = taskp->stmtsp(); stmtp && pinp; stmtp=stmtp->nextp()) {
if (AstVar* portp = stmtp->castVar()) {
if (portp->isIO()) {
if (portp->isInput()) {
pinp->iterateAndNext(*this);
} else { // Output or Inout
m_setRefLvalue = true;
pinp->iterateAndNext(*this);
m_setRefLvalue = false;
}
// Advance pin
pinp = pinp->nextp();
}
}
}
}
virtual void visit(AstNode* nodep, AstNUser*) {
// Default: Just iterate

17
test_regress/t/t_func_sum.pl Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
# 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;

View File

@ -0,0 +1,92 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2008-2008 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
reg [63:0] crc;
reg [63:0] sum;
wire [9:0] I1 = crc[9:0];
wire [9:0] I2 = crc[19:10];
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [9:0] S; // From test of Test.v
// End of automatics
Test test (/*AUTOINST*/
// Outputs
.S (S[9:0]),
// Inputs
.I1 (I1[9:0]),
.I2 (I2[9:0]));
wire [63:0] result = {32'h0, 22'h0, S};
`define EXPECTED_SUM 64'h24c38b77b0fcc2e7
// 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;
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;
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module Test (/*AUTOARG*/
// Outputs
S,
// Inputs
I1, I2
);
input [9:0] I1/*verilator public*/;
input [9:0] I2/*verilator public*/;
output reg [9:0] S/*verilator public*/;
always @(I1 or I2)
t2(I1,I2,S);
task t1;
input In1,In2;
output Sum;
Sum = In1 ^ In2;
endtask
task t2;
input[9:0] In1,In2;
output [9:0] Sum;
integer I;
begin
for (I=0;I<10;I=I+1)
t1(In1[I],In2[I],Sum[I]);
end
endtask
endmodule