-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
408 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
Intel Avalon | ||
============ | ||
|
||
Implements the register block using an | ||
`Intel Avalon MM <https://www.intel.com/content/www/us/en/docs/programmable/683091/22-3/memory-mapped-interfaces.html>`_ | ||
CPU interface. | ||
|
||
The Avalon interface comes in two i/o port flavors: | ||
|
||
SystemVerilog Interface | ||
Class: :class:`peakrdl_regblock.cpuif.avalon.Avalon_Cpuif` | ||
|
||
Interface Definition: :download:`avalon_mm_intf.sv <../../hdl-src/avalon_mm_intf.sv>` | ||
|
||
Flattened inputs/outputs | ||
Flattens the interface into discrete input and output ports. | ||
|
||
Class: :class:`peakrdl_regblock.cpuif.avalon.Avalon_Cpuif_flattened` | ||
|
||
|
||
Implementation Details | ||
---------------------- | ||
This implementation of the Avalon protocol has the following features: | ||
|
||
* Interface uses word addressing. | ||
* Supports `pipelined transfers <https://www.intel.com/content/www/us/en/docs/programmable/683091/22-3/pipelined-transfers.html>`_ | ||
* Responses may have variable latency | ||
|
||
In most cases, latency is fixed and is determined by how many retiming | ||
stages are enabled in your design. | ||
However if your design contains external components, access latency is | ||
not guaranteed to be uniform. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
interface avalon_mm_intf #( | ||
parameter DATA_WIDTH = 32, | ||
parameter ADDR_WIDTH = 32 // Important! Avalon uses word addressing | ||
); | ||
// Command | ||
logic read; | ||
logic write; | ||
logic waitrequest; | ||
logic [ADDR_WIDTH-1:0] address; | ||
logic [DATA_WIDTH-1:0] writedata; | ||
logic [DATA_WIDTH/8-1:0] byteenable; | ||
|
||
// Response | ||
logic readdatavalid; | ||
logic writeresponsevalid; | ||
logic [DATA_WIDTH-1:0] readdata; | ||
logic [1:0] response; | ||
|
||
modport host ( | ||
output read, | ||
output write, | ||
input waitrequest, | ||
output address, | ||
output writedata, | ||
output byteenable, | ||
|
||
input readdatavalid, | ||
input writeresponsevalid, | ||
input readdata, | ||
input response | ||
); | ||
|
||
modport agent ( | ||
input read, | ||
input write, | ||
output waitrequest, | ||
input address, | ||
input writedata, | ||
input byteenable, | ||
|
||
output readdatavalid, | ||
output writeresponsevalid, | ||
output readdata, | ||
output response | ||
); | ||
endinterface |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
from ..base import CpuifBase | ||
from ...utils import clog2 | ||
|
||
class Avalon_Cpuif(CpuifBase): | ||
template_path = "avalon_tmpl.sv" | ||
|
||
@property | ||
def port_declaration(self) -> str: | ||
return "avalon_mm_intf.agent avalon" | ||
|
||
def signal(self, name:str) -> str: | ||
return "avalon." + name | ||
|
||
@property | ||
def word_addr_width(self) -> int: | ||
# Avalon agents use word addressing, therefore address width is reduced | ||
return self.addr_width - clog2(self.data_width_bytes) | ||
|
||
class Avalon_Cpuif_flattened(Avalon_Cpuif): | ||
@property | ||
def port_declaration(self) -> str: | ||
lines = [ | ||
"input wire " + self.signal("read"), | ||
"input wire " + self.signal("write"), | ||
"output logic " + self.signal("waitrequest"), | ||
f"input wire [{self.word_addr_width-1}:0] " + self.signal("address"), | ||
f"input wire [{self.data_width-1}:0] " + self.signal("writedata"), | ||
f"input wire [{self.data_width_bytes-1}:0] " + self.signal("byteenable"), | ||
"output logic " + self.signal("readdatavalid"), | ||
"output logic " + self.signal("writeresponsevalid"), | ||
f"output logic [{self.data_width-1}:0] " + self.signal("readdata"), | ||
"output logic [1:0] " + self.signal("response"), | ||
] | ||
return ",\n".join(lines) | ||
|
||
def signal(self, name:str) -> str: | ||
return "avalon_" + name |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Request | ||
always_comb begin | ||
cpuif_req = {{cpuif.signal("read")}} | {{cpuif.signal("write")}}; | ||
cpuif_req_is_wr = {{cpuif.signal("write")}}; | ||
{%- if cpuif.data_width_bytes == 1 %} | ||
cpuif_addr = {{cpuif.signal("address")}}; | ||
{%- else %} | ||
cpuif_addr = { {{-cpuif.signal("address")}}, {{clog2(cpuif.data_width_bytes)}}'b0}; | ||
{%- endif %} | ||
cpuif_wr_data = {{cpuif.signal("writedata")}}; | ||
for(int i=0; i<{{cpuif.data_width_bytes}}; i++) begin | ||
cpuif_wr_biten[i*8 +: 8] <= {8{ {{-cpuif.signal("byteenable")}}[i]}}; | ||
end | ||
{{cpuif.signal("waitrequest")}} = (cpuif_req_stall_rd & {{cpuif.signal("read")}}) | (cpuif_req_stall_wr & {{cpuif.signal("write")}}); | ||
end | ||
|
||
// Response | ||
always_comb begin | ||
{{cpuif.signal("readdatavalid")}} = cpuif_rd_ack; | ||
{{cpuif.signal("writeresponsevalid")}} = cpuif_wr_ack; | ||
{{cpuif.signal("readdata")}} = cpuif_rd_data; | ||
if(cpuif_rd_err || cpuif_wr_err) begin | ||
// SLVERR | ||
{{cpuif.signal("response")}} = 2'b10; | ||
end else begin | ||
// OK | ||
{{cpuif.signal("response")}} = 2'b00; | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from .passthrough import Passthrough | ||
from .apb3 import APB3, FlatAPB3 | ||
from .apb4 import APB4, FlatAPB4 | ||
from .axi4lite import AXI4Lite, FlatAXI4Lite | ||
from .avalon import Avalon, FlatAvalon | ||
|
||
ALL_CPUIF = [ | ||
Passthrough(), | ||
APB3(), | ||
FlatAPB3(), | ||
APB4(), | ||
FlatAPB4(), | ||
AXI4Lite(), | ||
FlatAXI4Lite(), | ||
Avalon(), | ||
FlatAvalon(), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from ..base import CpuifTestMode | ||
|
||
from peakrdl_regblock.cpuif.avalon import Avalon_Cpuif, Avalon_Cpuif_flattened | ||
|
||
class Avalon(CpuifTestMode): | ||
cpuif_cls = Avalon_Cpuif | ||
rtl_files = [ | ||
"../../../../hdl-src/avalon_mm_intf.sv", | ||
] | ||
tb_files = [ | ||
"../../../../hdl-src/avalon_mm_intf.sv", | ||
"avalon_mm_intf_driver.sv", | ||
] | ||
tb_template = "tb_inst.sv" | ||
|
||
class FlatAvalon(Avalon): | ||
cpuif_cls = Avalon_Cpuif_flattened | ||
rtl_files = [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
interface avalon_mm_intf_driver #( | ||
parameter DATA_WIDTH = 32, | ||
parameter ADDR_WIDTH = 32 | ||
)( | ||
input wire clk, | ||
input wire rst, | ||
avalon_mm_intf.host avalon | ||
); | ||
localparam ADDR_PAD = $clog2(DATA_WIDTH/8); | ||
localparam WORD_ADDR_WIDTH = ADDR_WIDTH - ADDR_PAD; | ||
|
||
timeunit 1ps; | ||
timeprecision 1ps; | ||
|
||
logic av_read; | ||
logic av_write; | ||
logic av_waitrequest; | ||
logic [WORD_ADDR_WIDTH-1:0] av_address; | ||
logic [DATA_WIDTH-1:0] av_writedata; | ||
logic [DATA_WIDTH/8-1:0] av_byteenable; | ||
logic av_readdatavalid; | ||
logic av_writeresponsevalid; | ||
logic [DATA_WIDTH-1:0] av_readdata; | ||
logic [1:0] av_response; | ||
|
||
assign avalon.read = av_read; | ||
assign avalon.write = av_write; | ||
assign av_waitrequest = avalon.waitrequest; | ||
assign avalon.address = av_address; | ||
assign avalon.writedata = av_writedata; | ||
assign avalon.byteenable = av_byteenable; | ||
assign av_readdatavalid = avalon.readdatavalid; | ||
assign av_writeresponsevalid = avalon.writeresponsevalid; | ||
assign av_readdata = avalon.readdata; | ||
assign av_response = avalon.response; | ||
|
||
default clocking cb @(posedge clk); | ||
default input #1step output #1; | ||
output av_read; | ||
output av_write; | ||
input av_waitrequest; | ||
output av_address; | ||
output av_writedata; | ||
output av_byteenable; | ||
input av_readdatavalid; | ||
input av_writeresponsevalid; | ||
input av_readdata; | ||
input av_response; | ||
endclocking | ||
|
||
task automatic reset(); | ||
cb.av_read <= '0; | ||
cb.av_write <= '0; | ||
cb.av_address <= '0; | ||
cb.av_writedata <= '0; | ||
cb.av_byteenable <= '0; | ||
endtask | ||
|
||
semaphore req_mutex = new(1); | ||
semaphore resp_mutex = new(1); | ||
|
||
task automatic write(logic [ADDR_WIDTH-1:0] addr, logic [DATA_WIDTH-1:0] data, logic [DATA_WIDTH/8-1:0] strb = '1); | ||
fork | ||
begin | ||
req_mutex.get(); | ||
##0; | ||
// Initiate transfer | ||
cb.av_write <= '1; | ||
cb.av_address <= (addr >> ADDR_PAD); | ||
cb.av_writedata <= data; | ||
cb.av_byteenable <= strb; | ||
@(cb); | ||
|
||
// Wait for transfer to be accepted | ||
while(cb.av_waitrequest == 1'b1) @(cb); | ||
reset(); | ||
req_mutex.put(); | ||
end | ||
|
||
begin | ||
resp_mutex.get(); | ||
@cb; | ||
// Wait for response | ||
while(cb.av_writeresponsevalid !== 1'b1) @(cb); | ||
assert(!$isunknown(cb.av_response)) else $error("Read from 0x%0x returned X's on av_response", addr); | ||
resp_mutex.put(); | ||
end | ||
join | ||
endtask | ||
|
||
task automatic read(logic [ADDR_WIDTH-1:0] addr, output logic [DATA_WIDTH-1:0] data); | ||
fork | ||
begin | ||
req_mutex.get(); | ||
##0; | ||
// Initiate transfer | ||
cb.av_read <= '1; | ||
cb.av_address <= (addr >> ADDR_PAD); | ||
@(cb); | ||
|
||
// Wait for transfer to be accepted | ||
while(cb.av_waitrequest == 1'b1) @(cb); | ||
reset(); | ||
req_mutex.put(); | ||
end | ||
|
||
begin | ||
resp_mutex.get(); | ||
@cb; | ||
// Wait for response | ||
while(cb.av_readdatavalid !== 1'b1) @(cb); | ||
assert(!$isunknown(cb.av_readdata)) else $error("Read from 0x%0x returned X's on av_response", av_readdata); | ||
assert(!$isunknown(cb.av_response)) else $error("Read from 0x%0x returned X's on av_response", addr); | ||
data = cb.av_readdata; | ||
resp_mutex.put(); | ||
end | ||
join | ||
endtask | ||
|
||
task automatic assert_read(logic [ADDR_WIDTH-1:0] addr, logic [DATA_WIDTH-1:0] expected_data, logic [DATA_WIDTH-1:0] mask = '1); | ||
logic [DATA_WIDTH-1:0] data; | ||
read(addr, data); | ||
data &= mask; | ||
assert(data == expected_data) else $error("Read from 0x%x returned 0x%x. Expected 0x%x", addr, data, expected_data); | ||
endtask | ||
|
||
initial begin | ||
reset(); | ||
end | ||
|
||
initial forever begin | ||
@cb; | ||
if(!rst) assert(!$isunknown(cb.av_waitrequest)) else $error("Saw X on av_waitrequest!"); | ||
if(!rst) assert(!$isunknown(cb.av_readdatavalid)) else $error("Saw X on av_readdatavalid!"); | ||
if(!rst) assert(!$isunknown(cb.av_writeresponsevalid)) else $error("Saw X on av_writeresponsevalid!"); | ||
end | ||
|
||
endinterface |
Oops, something went wrong.