Subject: Re: Fwd: RE: Data Channels
From: Tom Fitzpatrick (fitz@co-design.com)
Date: Thu Aug 01 2002 - 08:40:27 PDT
Hi Everyone,
Here's a more detailed explanation of interfaces from one of our AEs,
Christian Burisch. I'm hoping that this explanation, combined with the email
I sent out on 7/19/02 ("Fitz's Actions for 7/22 Meeting") will clear up any
misunderstandings about interfaces.
Please let me know if there are still questions about what interfaces can or
cannot do.
Thanks,
-Tom
Subject: RE: Data Channels
Date: Fri, 26 Jul 2002 11:22:32 -0700
From: "Stuart Swan" <stuart@cadence.com>
To: "Kevin Cameron x3251" <Kevin.Cameron@nsc.com>
Cc: <sv-ec@server.eda.org>
For example, a channel in SystemC can have embedded modules, and can
implement interface
methods that convert abstract transactions modeled as function calls
into low-level signal interactions with such
embedded modules. I don't believe this is possible with SystemVerilog
"interfaces".
I'm still trying to figure out some of the specific characteristics of
SystemVerilog
"interfaces" and such. As can be expected, when you dive into the details
they are
quite different from SystemC channels. It's not even clear to me at the
moment
whether each instantiation of an interface in SystemVerilog truely
represents
a unique instance with instance-specific data, as occurs with module
instantiation.
Hi,
Let me explain:
The data inside an interface is instance specific. The trick is that the
interface spans the modules that it connects.
You can start writing very abstract interfaces, later refining them to
bus functional models and then still later refining them to RTL.
You can swap between these different versions of interfaces, WITHOUT having
to edit the interconnecting modules. The module headers of different
levels of abstractions are the same.
Modules can contain interface instances and can be connected via interfaces.
Interfaces cannot instance modules.
Interfaces can instance other interfaces.
Let me show you an example. Here is a sender and a receiver connected by
an interface, called channel_i:
module top;
bit clk;
channel_i channel(clk);
always #10 clk = ~clk;
sender s(clk, channel);
receiver r(clk, channel);
endmodule
module sender (input bit clk, channel_i channel);
initial
begin
channel.transmit('hF0);
channel.transmit('h42);
channel.transmit('h27);
#50 $finish();
end
endmodule
module receiver (input bit clk, channel_i channel);
always
begin
logic [7:0] data;
channel.receive(data);
$display("Received %h", data);
end
endmodule
We can start simulating to make sure that the communication works
using an interface that just shuffles the data across:
interface channel_i(input bit clk);
bit valid;
bit [7:0] data;
task transmit(input bit [7:0] d);
wait(valid == 0);
data = d;
valid = 1;
endtask
task receive(output bit [7:0] d);
wait(valid == 1);
d = data;
valid = 0;
endtask
endinterface
This interface is only useful to check functionality. If we want
to make tradeoff decisions and need more accurate timing, we need
a cycle accurate interface. Here is one that send the data serially:
interface channel_i(input bit clk);
logic ready=0;
logic valid=0;
logic data;
modport rtl_transmitmode(output valid, data, input ready);
modport rtl_receivemode( input valid, data, output ready);
task transmit(input logic [7:0] d);
while (ready !== 1) @(negedge clk) ;
valid <= 1;
for (int i = 7; i >= 0; i--)
begin
data <= d[i];
@(negedge clk);
end
data<= 'x;
valid <= 0;
endtask
task receive(output logic [7:0] d);
ready <= 1;
while (valid !== 1) @(posedge clk) ;
ready <= 0;
for (int i = 7; i >= 0; i--)
begin
d[i] <= data;
@(posedge clk);
end
endtask
endinterface
The clk is not actually part of the interface, but it passed in because
the receive and transmit methods need it.
To use this interface NO modification to top, sender or receiver is
necessary!
The receiver uses the receive method in the interface, so it may not be
synthesizable. If we want to rewrite it at RTL, then we may want to
implement the receive functionality as a FSM and it needs to use
the actual signals inside the interface, instead of the task:
module receiver (input bit clk,
channel_i.rtl_receivemode channel);
logic [7:0] data;
logic [7:0] index;
enum {wait_for_valid, receiving, done} st;
always @(posedge clk)
case (st)
wait_for_valid:
begin
channel.ready <= 1;
index <= 6;
if (channel.valid==1)
begin
data[7] <= channel.data;
st <= receiving;
end
end
receiving:
begin
channel.ready <= 0;
index <= index - 1;
if ((index >= 0) && (index <= 6))
data[index] <= channel.data;
else
st <= done;
end
done:
begin
st <= wait_for_valid;
$display("Received %h", data);
end
endcase
endmodule
Note that this change in abstraction of the receiver module requires no
change to the sender module because the abstraction difference is masked by
the interface. So I am sure that you see the power of this approach. This
allows some interesting methodologies, for example:
*) step-wise refinement from architecture to RTL
*) verifying interfaces seperate from the design
*) reuse of interfaces
*) separating communication from the processing functionality
*) huge code compaction
This archive was generated by hypermail 2b28 : Thu Aug 01 2002 - 08:42:33 PDT