Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Doubt about SystemVerilog tasks in interfaces

734 views
Skip to first unread message

Andreas Ehliar

unread,
Oct 11, 2007, 6:07:22 AM10/11/07
to
I am playing around a little bit with SystemVerilog but
I have encountered a problem which I don't really know
how to solve.

My scenario is as follows:

I have created an interface for a certain bus.
Two modports, one for a bus master and one for a bus
slave.
There is also tasks in the interface that allows the
testbench to perform read and write transactions on
the bus.

My problem is that the assignments I have to make
procedurally inside the task in order to read/write
conflicts with continuous assignments made in another
part of the design (even though I never even use that
task anywhere).

The source code included below will give the following
error message in ModelSim 6.3c:

# ** Fatal: (vsim-3838) argh.sv(12): Variable '/argh2/thebus/adr' written by continuous and procedural assignments. See argh.sv(49).

Is this really the correct behavior? If so it seems
like tasks in interfaces aren't as useful as I
initially thought. Is there any sort of workaround
for my problem? I have looked at various tutorials
on the web but never seen this problem mentioned
or any ways around it.


/Andreas


---------------------------------------------
argh.sv follows below:
---------------------------------------------
`timescale 1ns / 10ps

module testmod3(
output reg [31:0] address_o);

assign address_o = 32'hdeadbeef;

endmodule // testmod3


module testmod2(bus.master thebus);
testmod3 foo(.address_o(thebus.adr));

endmodule // testmod2


module argh2;
reg clk;
bus thebus(clk);


testmod2 uut(.*);

endmodule // argh2

interface bus(input clk);

typedef reg [31:0] adr_t;
typedef reg [31:0] dat_t;

adr_t adr; // address bus
dat_t dat_o; // write data bus
dat_t dat_i; // read data bus
reg stb; // strobe
reg we; // indicates write transfer
reg ack; // normal termination

modport master(
output adr, dat_o, stb, we,
input clk, dat_i, ack);

modport slave(
input clk, adr, dat_o, stb, we,
output dat_i, ack);

task read(input adr_t radr, output dat_t rdat);
begin
adr = radr;
stb = 1'b1;
we = 1'b0;

while (!ack) begin
@(posedge clk);
end

stb = 1'b0;
we = 1'b0;

rdat = dat_i;
end
endtask


endinterface // bus


Jonathan Bromley

unread,
Oct 11, 2007, 5:14:12 PM10/11/07
to
On Thu, 11 Oct 2007 10:07:22 +0000 (UTC), Andreas Ehliar
<ehliar...@isy.liu.se> wrote:

>I am playing around a little bit with SystemVerilog but
>I have encountered a problem which I don't really know
>how to solve.
>
>My scenario is as follows:
>
>I have created an interface for a certain bus.
>Two modports, one for a bus master and one for a bus
>slave.
>There is also tasks in the interface that allows the
>testbench to perform read and write transactions on
>the bus.
>
>My problem is that the assignments I have to make
>procedurally inside the task in order to read/write
>conflicts with continuous assignments made in another
>part of the design (even though I never even use that
>task anywhere).

Andreas, does the following work for you?

Make the modport drive a stub variable, which is
then copied on to the real "adr" variable:

interface foo;
// adr is the real thing, master_adr is a stub
reg [...] adr, master_adr;
modport slave (input adr);
modport master (output master_adr); // driven by master
// Procedural copy, will do nothing if master not connected
always @master_adr adr = master_adr;
// Drive from task, will do nothing if task not called
task set_adr(reg [...] A); adr = a; endtask
endinterface

I agree that it's a tiresome mess.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan...@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.

Andrew Burnside

unread,
Oct 12, 2007, 3:48:48 AM10/12/07
to
Hi Andreas

I found that I could get round some of these problems by using
always_comb instead of assign, when dealing with interfaces containing
tasks. The semantics are slightly different, but might not worry you.

Jonathan and I had a longer discussion in the thread:
SystemVerilog Interface style (managing continuous and non-continuous
assignments)

A direct URL is below:
http://groups.google.co.uk/group/comp.lang.verilog/browse_thread/thread/7f0773cc87366b5e/b0bdc2f6bc4abac4?lnk=st&q=#b0bdc2f6bc4abac4

Regards

Andrew

Andreas Ehliar

unread,
Oct 12, 2007, 2:30:28 AM10/12/07
to
On 2007-10-11, Jonathan Bromley <jonathan...@MYCOMPANY.com> wrote:
> Andreas, does the following work for you?
>
> Make the modport drive a stub variable, which is
> then copied on to the real "adr" variable:
>
> interface foo;
> // adr is the real thing, master_adr is a stub
> reg [...] adr, master_adr;
> modport slave (input adr);
> modport master (output master_adr); // driven by master
> // Procedural copy, will do nothing if master not connected
> always @master_adr adr = master_adr;
> // Drive from task, will do nothing if task not called
> task set_adr(reg [...] A); adr = a; endtask
> endinterface
>
> I agree that it's a tiresome mess.

Hi, it seems to work for me. But as you said, it is
tiresome.

I have been thinking about this and have another
possible solution. I'm removing the task from the
interface altogether and putting the task into a
regular module instead:

module bus_tasks(bus.master thebus);
task read(input [31:0] radr, output reg [31:0] rdat);
begin
@(posedge thebus.clk);

thebus.adr <= radr;
thebus.stb <= 1'b1;
thebus.we <= 1'b0;

while (!thebus.ack) begin
@(posedge thebus.clk);
end

thebus.stb <= 1'b0;
thebus.we <= 1'b0;

rdat = thebus.dat_i;
end
endtask
endmodule


Inside my testbench I can then do something like this:

bus thebus(clk);
bus_tasks bt(thebus);

reg [31:0] dat;
initial begin
// reset stuff
...
...
bt.read(32'hfffffffc0,dat);
$display("Read %08x",dat);
end


What do you think about this solution? Does it have any
hidden pitfalls that I'm not aware of?


/Andreas

mjl...@hotmail.com

unread,
Oct 12, 2007, 8:43:22 AM10/12/07
to
On 12 Oct, 07:30, Andreas Ehliar <ehliar-nos...@isy.liu.se> wrote:

Thanks all for the useful comments and link to the other thread. I
have been struggling with this one too recently, and was pleased to
see some suggested solutions.

Dave Rich

unread,
Oct 20, 2007, 2:16:19 AM10/20/07
to

Hi Andreas,

This is a classic Verilog bidirectional bus problem. If one driver is
continuously driving

assign address_o = 32'hdeadbeef;

How do expect any other assignment to effect those bus bits? The
simulator doesn't know that the read task is never called. It's there
because someone expect to be able to call it. You really have two
drivers on one bus. Then you need to define adr as a wire and have
have each drive assign 'z when it is not driving. So your read task
will look like

interface bus(input clk);

typedef reg [31:0] adr_t;
typedef reg [31:0] dat_t;

wire adr_t adr; // address bus as a wire
var adr_t adr_reg='z; // address_bus as a reg
assign adr = adr_reg; // has no effect until someone removes the z's


dat_t dat_o; // write data bus
dat_t dat_i; // read data bus
reg stb; // strobe
reg we; // indicates write transfer
reg ack; // normal termination

modport master(
output adr, dat_o, stb, we,
input clk, dat_i, ack);

modport slave(
input clk, adr, dat_o, stb, we,
output dat_i, ack);

task read(input adr_t radr, output dat_t rdat);
begin

adr_reg = radr; // start driving


stb = 1'b1;
we = 1'b0;

while (!ack) begin
@(posedge clk);
end

stb = 1'b0;
we = 1'b0;

rdat = dat_i;
adr_reg = 'z; // disable this driver
end
endtask

endinterface // bus


Your testmod3 will also need to be modified to drive 'z when someone
else wants to drive.


Dave

0 new messages