Support for mixed-direction port concatenations?

E

Evan Lavelle

Guest
There's a (very) obscure (and totally pointless?) feature in the LRM
which allows port concatenations to have mixed directions (p176):

module mixed_direction (.p({a, e}));
input a; // p contains both input and output directions.
output e;
I flagged this as an error in my translator, and I've just tried it
out on some real simulators (icarus, modelsim, cver, veriwell, ISE).
Test code below.

Of these 5, one crashes, two report a syntax error, and the remaining
two appear to give the wrong answer, reporting

sreg1 data is zzzz
sreg2 data is 0101

'sreg1' should, I think, be 0101. Have I misunderstood how to do this,
or is this feature just universally ignored? Any results from other
sims?

Thanks -

Evan

------------------------------------------

module test;
reg clk, data;
wire [3:0] sreg1, sreg2;

mixed_direction m1(.clk(clk), .p({data, sreg1}));
sreg m2(.clk(clk), .a(data), .e(sreg2));

initial
main;

task main;
integer i;
begin
clk = 0;
for(i=0; i<4; i=i+1) begin
data = i;
#1 clk = 1;
#1 clk = 0;
end
$display("sreg1 data is %b", sreg1);
$display("sreg2 data is %b", sreg2);
end
endtask
endmodule

// the test module: the second port has a mixed direction
module mixed_direction (clk, .p({a, e}));
input clk;
input a;
output e;
reg [3:0] e;

always @(posedge clk)
e <= {e[2:0], a};
endmodule

// the sanity check module: this is identical to 'mixed_direction',
// but has a simpler port list
module sreg (clk, a, e);
input clk;
input a;
output e;
reg [3:0] e;

always @(posedge clk)
e <= {e[2:0], a};
endmodule
 
Evan Lavelle wrote:
Of these 5, one crashes, two report a syntax error, and the remaining
two appear to give the wrong answer, reporting
This may not all be due to your mixed-direction port. Your testcase
includes

output e;
reg [3:0] e;
This is invalid code, since you did not include a range on the output
declaration to match the one on the reg declaration. By the LRM, this
is illegal. However, since Verilog-XL accepted this in some cases,
other tools may as well. But it is unclear whether the port will be a
scalar or a vector, since the declarations conflict.

I would suggest fixing this error in your testcase before continuing
to investigate mixed directions.
 
Evan Lavelle wrote:

Of these 5, one crashes, two report a syntax error, and the remaining
two appear to give the wrong answer, reporting
I have now tried your testcase in Verilog-XL and NC-Verilog and they
reject it as invalid for another reason.

Since your port is at least partly an output, it has to be connected
to a net (or more precisely, a net lvalue expression). Your 'data' is
a variable, and therefore your concatentation is not a net lvalue.

It looks like you are assuming that the concatenations above and below
will get decomposed and the parts connected separately, with each part
following the rules for the direction of the part below. But this
was not declared as two separate ports; it is a single port. The
expression connected above must satisfy the rules for that port's
direction, which is mixed. There are not separate rules for different
parts of the port connection.

Another way of viewing this is that a port is defined to behave like a
continuous assignment from the source side to the sink side, or it can
be port-collapsed. A mixed port cannot be treated as a continuous
assignment; which way would it drive? The LRM does not say that a
port can be treated as multiple continuous assignments. So it can
only be handled by port-collapsing, which I am sure Verilog-XL is
doing.

If you want to test this, you should change 'data' to be a net, and
then drive it with an explicit continuous assignment. This will
probably get some of the simulators working.
 
Very interesting; thanks. I've attached the corrected (ie. making
'data' a net, so allowing port collapsing) code below, which produces
the expected result on 2 of the 5 sims (adding an explicit range to
output declarations isn't necessary for any of these 5 sims, though).

On Mon, 04 Jun 2007 14:00:37 -0700, sharp@cadence.com wrote:

It looks like you are assuming that the concatenations above and below
will get decomposed and the parts connected separately, with each part
following the rules for the direction of the part below. But this
was not declared as two separate ports; it is a single port. The
expression connected above must satisfy the rules for that port's
direction, which is mixed. There are not separate rules for different
parts of the port connection.

Another way of viewing this is that a port is defined to behave like a
continuous assignment from the source side to the sink side, or it can
be port-collapsed. A mixed port cannot be treated as a continuous
assignment; which way would it drive? The LRM does not say that a
port can be treated as multiple continuous assignments. So it can
only be handled by port-collapsing, which I am sure Verilog-XL is
doing.
Yes, I'd assumed that the concatenation would be decomposed, with
different directions of continuous assignments on each part. At first
sight, this seems logical - the LRM has no mention of mixed-direction
ports (apart from one entry in vpi_user.h), and the LRM explicitly
states that each connection has to be a continuous assignment. It
looks like the port collapsing text was only in the OVI LRM, and was
dropped from the subsequent LRMs, presumably because it was
(incorrectly) thought to be relevant only to optimisation.

The port-range-declaration issue is interesting. My reading of the 95
LRM was that it was allowable to have:

output e;
reg [3:0] e;
the 2001 text is clearer (disallowing this code), but the '95 text
says "a port can be declared in both a port declaration and a net or
register declaration. If a port is declared as a vector, the range
specification between the two declarations of a port shall be
identical". My original reading of "if a port is declared as vector"
was "if the port declaration includes a range specification", which
seems to be the common interpretation.

thanks -

Evan

---------------------------------------

module test;
reg clk, rdata;
wire [3:0] sreg1, sreg2;
wire ndata;

mixed_direction m1(.clk(clk), .p({ndata, sreg1}));
sreg m2(.clk(clk), .a(ndata), .e(sreg2));

initial
main;

assign ndata = rdata;

task main;
integer i;
begin
clk = 0;
for(i=0; i<4; i=i+1) begin
rdata = i;
#1 clk = 1;
#1 clk = 0;
end
$display("sreg1 data is %b", sreg1);
$display("sreg2 data is %b", sreg2);
end
endtask
endmodule

// the test module: the second port has a mixed direction
module mixed_direction (clk, .p({a, e}));
input clk;
input a;
output [3:0] e;
reg [3:0] e;

always @(posedge clk)
e <= {e[2:0], a};
endmodule

// the sanity check module: this is identical to 'mixed_direction',
but has
// a simpler port list
module sreg (clk, a, e);
input clk;
input a;
output [3:0] e;
reg [3:0] e;

always @(posedge clk)
e <= {e[2:0], a};
endmodule
 
Evan Lavelle wrote:
Very interesting; thanks. I've attached the corrected (ie. making
'data' a net, so allowing port collapsing) code below, which produces
the expected result on 2 of the 5 sims (adding an explicit range to
output declarations isn't necessary for any of these 5 sims, though).
The modified testcase executes successfully in NC-Verilog, giving:

sreg1 data is 0101
sreg2 data is 0101

It is still rejected by Verilog-XL. Now the complaint is that the
*inside* connection to the mixed port is a continuous assignment. You
are connecting e to the inside of the port, and e is declared as a
reg. So the concatenation on the inside is regarded as an expression
continuous-assigned to the port, rather than as a net_lvalue.

The tools that are accepting this are probably creating a net version
of e, continuous-assigned from the reg, and connecting that to the
inside of the port.

As you say, there are no explicit rules for this in the LRM. I am
just reverse-engineering the rules that XL seems to be using. Given
the lack of explicit rules, it is not surprising that implementations
differ.

If I change the inside connection to a net also, assigned from the
reg, then XL accepts it and gives the same answer. You might want to
try this with the other tools.


It looks like the port collapsing text was only in the OVI LRM, and was
dropped from the subsequent LRMs, presumably because it was
(incorrectly) thought to be relevant only to optimisation.
There is still some mention of it in 12.3.10. It says that it is
permissible to merge the two nets. However, it spends far more text
describing the resulting net type of the net than the fact that this
merging is an acceptable alternative to a continuous assignment.

Also, 12.3.8 describes some direction coercion that someone apparently
thought was a deliberate attempt by XL to "fix" port directions that
it recognized as incorrect. In fact, they were just observing XL
collapsing most ports, which makes them inout, rather than any
deliberate "corrections".


The port-range-declaration issue is interesting. My reading of the 95
LRM was that it was allowable to have:

output e;
reg [3:0] e;

the 2001 text is clearer (disallowing this code), but the '95 text
says "a port can be declared in both a port declaration and a net or
register declaration. If a port is declared as a vector, the range
specification between the two declarations of a port shall be
identical". My original reading of "if a port is declared as vector"
was "if the port declaration includes a range specification", which
seems to be the common interpretation.
This lack of clarity was submitted as an erratum to the IEEE
committees, and the consensus was that their ranges had to match, and
the lack of a range does not match a range. However, I don't think
any clarifications were added to the LRM.
 

Welcome to EDABoard.com

Sponsor

Back
Top