|
|
Subject: Doubt about SystemVerilog tasks in interfaces
From: Andreas Ehliar
Date: 10/11/2007 10:07:22 AM
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
Subject: Doubt about SystemVerilog tasks in interfaces
From: Andreas Ehliar
Date: 10/12/2007 6:30:28 AM
On 2007-10-11, Jonathan Bromley <jonathan.bromley@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
|