Add Intel Avalon MM cpuif. #40
This commit is contained in:
32
docs/cpuif/avalon.rst
Normal file
32
docs/cpuif/avalon.rst
Normal file
@@ -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.
|
||||||
@@ -112,6 +112,7 @@ Links
|
|||||||
cpuif/introduction
|
cpuif/introduction
|
||||||
cpuif/apb
|
cpuif/apb
|
||||||
cpuif/axi4lite
|
cpuif/axi4lite
|
||||||
|
cpuif/avalon
|
||||||
cpuif/passthrough
|
cpuif/passthrough
|
||||||
cpuif/internal_protocol
|
cpuif/internal_protocol
|
||||||
cpuif/customizing
|
cpuif/customizing
|
||||||
|
|||||||
46
hdl-src/avalon_mm_intf.sv
Normal file
46
hdl-src/avalon_mm_intf.sv
Normal file
@@ -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
|
||||||
@@ -6,7 +6,7 @@ from peakrdl.plugins.exporter import ExporterSubcommandPlugin #pylint: disable=i
|
|||||||
from peakrdl.config import schema #pylint: disable=import-error
|
from peakrdl.config import schema #pylint: disable=import-error
|
||||||
|
|
||||||
from .exporter import RegblockExporter
|
from .exporter import RegblockExporter
|
||||||
from .cpuif import apb3, apb4, axi4lite, passthrough, CpuifBase
|
from .cpuif import CpuifBase, apb3, apb4, axi4lite, passthrough, avalon
|
||||||
from .udps import ALL_UDPS
|
from .udps import ALL_UDPS
|
||||||
from . import entry_points
|
from . import entry_points
|
||||||
|
|
||||||
@@ -48,13 +48,15 @@ class Exporter(ExporterSubcommandPlugin):
|
|||||||
|
|
||||||
# All built-in CPUIFs
|
# All built-in CPUIFs
|
||||||
cpuifs = {
|
cpuifs = {
|
||||||
|
"passthrough": passthrough.PassthroughCpuif,
|
||||||
"apb3": apb3.APB3_Cpuif,
|
"apb3": apb3.APB3_Cpuif,
|
||||||
"apb3-flat": apb3.APB3_Cpuif_flattened,
|
"apb3-flat": apb3.APB3_Cpuif_flattened,
|
||||||
"apb4": apb4.APB4_Cpuif,
|
"apb4": apb4.APB4_Cpuif,
|
||||||
"apb4-flat": apb4.APB4_Cpuif_flattened,
|
"apb4-flat": apb4.APB4_Cpuif_flattened,
|
||||||
"axi4-lite": axi4lite.AXI4Lite_Cpuif,
|
"axi4-lite": axi4lite.AXI4Lite_Cpuif,
|
||||||
"axi4-lite-flat": axi4lite.AXI4Lite_Cpuif_flattened,
|
"axi4-lite-flat": axi4lite.AXI4Lite_Cpuif_flattened,
|
||||||
"passthrough": passthrough.PassthroughCpuif
|
"avalon-mm": avalon.Avalon_Cpuif,
|
||||||
|
"avalon-mm-flat": avalon.Avalon_Cpuif_flattened,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Load any cpuifs specified via entry points
|
# Load any cpuifs specified via entry points
|
||||||
|
|||||||
37
src/peakrdl_regblock/cpuif/avalon/__init__.py
Normal file
37
src/peakrdl_regblock/cpuif/avalon/__init__.py
Normal file
@@ -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
|
||||||
29
src/peakrdl_regblock/cpuif/avalon/avalon_tmpl.sv
Normal file
29
src/peakrdl_regblock/cpuif/avalon/avalon_tmpl.sv
Normal file
@@ -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
|
||||||
@@ -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(),
|
||||||
|
]
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ interface apb4_intf_driver #(
|
|||||||
|
|
||||||
semaphore txn_mutex = new(1);
|
semaphore txn_mutex = new(1);
|
||||||
|
|
||||||
task automatic write(logic [ADDR_WIDTH-1:0] addr, logic [DATA_WIDTH-1:0] data);
|
task automatic write(logic [ADDR_WIDTH-1:0] addr, logic [DATA_WIDTH-1:0] data, logic [DATA_WIDTH/8-1:0] strb = '1);
|
||||||
txn_mutex.get();
|
txn_mutex.get();
|
||||||
##0;
|
##0;
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ interface apb4_intf_driver #(
|
|||||||
cb.PPROT <= '0;
|
cb.PPROT <= '0;
|
||||||
cb.PADDR <= addr;
|
cb.PADDR <= addr;
|
||||||
cb.PWDATA <= data;
|
cb.PWDATA <= data;
|
||||||
cb.PSTRB <= '1;
|
cb.PSTRB <= strb;
|
||||||
@(cb);
|
@(cb);
|
||||||
|
|
||||||
// active phase
|
// active phase
|
||||||
|
|||||||
18
tests/lib/cpuifs/avalon/__init__.py
Normal file
18
tests/lib/cpuifs/avalon/__init__.py
Normal file
@@ -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 = []
|
||||||
138
tests/lib/cpuifs/avalon/avalon_mm_intf_driver.sv
Normal file
138
tests/lib/cpuifs/avalon/avalon_mm_intf_driver.sv
Normal file
@@ -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
|
||||||
36
tests/lib/cpuifs/avalon/tb_inst.sv
Normal file
36
tests/lib/cpuifs/avalon/tb_inst.sv
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{% sv_line_anchor %}
|
||||||
|
avalon_mm_intf #(
|
||||||
|
.DATA_WIDTH({{exporter.cpuif.data_width}}),
|
||||||
|
.ADDR_WIDTH({{exporter.cpuif.word_addr_width}})
|
||||||
|
) avalon();
|
||||||
|
avalon_mm_intf_driver #(
|
||||||
|
.DATA_WIDTH({{exporter.cpuif.data_width}}),
|
||||||
|
.ADDR_WIDTH({{exporter.cpuif.addr_width}})
|
||||||
|
) cpuif (
|
||||||
|
.clk(clk),
|
||||||
|
.rst(rst),
|
||||||
|
.avalon(avalon)
|
||||||
|
);
|
||||||
|
{% if type(cpuif).__name__.startswith("Flat") %}
|
||||||
|
{% sv_line_anchor %}
|
||||||
|
wire avalon_read;
|
||||||
|
wire avalon_write;
|
||||||
|
wire avalon_waitrequest;
|
||||||
|
wire [{{exporter.cpuif.word_addr_width - 1}}:0] avalon_address;
|
||||||
|
wire [{{exporter.cpuif.data_width - 1}}:0] avalon_writedata;
|
||||||
|
wire [{{exporter.cpuif.data_width_bytes - 1}}:0] avalon_byteenable;
|
||||||
|
wire avalon_readdatavalid;
|
||||||
|
wire avalon_writeresponsevalid;
|
||||||
|
wire [{{exporter.cpuif.data_width - 1}}:0] avalon_readdata;
|
||||||
|
wire [1:0] avalon_response;
|
||||||
|
assign avalon_read = avalon.read;
|
||||||
|
assign avalon_write = avalon.write;
|
||||||
|
assign avalon.waitrequest = avalon_waitrequest;
|
||||||
|
assign avalon_address = avalon.address;
|
||||||
|
assign avalon_writedata = avalon.writedata;
|
||||||
|
assign avalon_byteenable = avalon.byteenable;
|
||||||
|
assign avalon.readdatavalid = avalon_readdatavalid;
|
||||||
|
assign avalon.writeresponsevalid = avalon_writeresponsevalid;
|
||||||
|
assign avalon.readdata = avalon_readdata;
|
||||||
|
assign avalon.response = avalon_response;
|
||||||
|
{% endif %}
|
||||||
@@ -101,7 +101,7 @@ interface axi4lite_intf_driver #(
|
|||||||
semaphore txn_ar_mutex = new(1);
|
semaphore txn_ar_mutex = new(1);
|
||||||
semaphore txn_r_mutex = new(1);
|
semaphore txn_r_mutex = new(1);
|
||||||
|
|
||||||
task automatic write(logic [ADDR_WIDTH-1:0] addr, logic [DATA_WIDTH-1:0] data);
|
task automatic write(logic [ADDR_WIDTH-1:0] addr, logic [DATA_WIDTH-1:0] data, logic [DATA_WIDTH/8-1:0] strb = '1);
|
||||||
bit w_before_aw;
|
bit w_before_aw;
|
||||||
w_before_aw = $urandom_range(1,0);
|
w_before_aw = $urandom_range(1,0);
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ interface axi4lite_intf_driver #(
|
|||||||
if(!w_before_aw) repeat($urandom_range(2,0)) @cb;
|
if(!w_before_aw) repeat($urandom_range(2,0)) @cb;
|
||||||
cb.WVALID <= '1;
|
cb.WVALID <= '1;
|
||||||
cb.WDATA <= data;
|
cb.WDATA <= data;
|
||||||
cb.WSTRB <= '1; // TODO: Support byte strobes
|
cb.WSTRB <= strb;
|
||||||
@(cb);
|
@(cb);
|
||||||
while(cb.WREADY !== 1'b1) @(cb);
|
while(cb.WREADY !== 1'b1) @(cb);
|
||||||
cb.WVALID <= '0;
|
cb.WVALID <= '0;
|
||||||
|
|||||||
@@ -1,32 +1,7 @@
|
|||||||
from itertools import product
|
from itertools import product
|
||||||
|
|
||||||
from .cpuifs.apb3 import APB3, FlatAPB3
|
|
||||||
from .cpuifs.apb4 import APB4, FlatAPB4
|
|
||||||
from .cpuifs.axi4lite import AXI4Lite, FlatAXI4Lite
|
|
||||||
from .cpuifs.passthrough import Passthrough
|
|
||||||
|
|
||||||
|
|
||||||
all_cpuif = [
|
|
||||||
APB3(),
|
|
||||||
FlatAPB3(),
|
|
||||||
APB4(),
|
|
||||||
FlatAPB4(),
|
|
||||||
AXI4Lite(),
|
|
||||||
FlatAXI4Lite(),
|
|
||||||
Passthrough(),
|
|
||||||
]
|
|
||||||
|
|
||||||
def get_permutations(spec):
|
def get_permutations(spec):
|
||||||
param_list = []
|
param_list = []
|
||||||
for v in product(*spec.values()):
|
for v in product(*spec.values()):
|
||||||
param_list.append(dict(zip(spec, v)))
|
param_list.append(dict(zip(spec, v)))
|
||||||
return param_list
|
return param_list
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
|
||||||
# TODO: this wont scale well. Create groups of permutations. not necessary to permute everything all the time.
|
|
||||||
TEST_PARAMS = get_permutations({
|
|
||||||
"cpuif": all_cpuif,
|
|
||||||
"retime_read_fanin": [True, False],
|
|
||||||
"retime_read_response": [True, False],
|
|
||||||
"reuse_hwif_typedefs": [True, False],
|
|
||||||
})
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from ..lib.cpuifs.apb4 import APB4
|
|||||||
from ..lib.cpuifs.axi4lite import AXI4Lite
|
from ..lib.cpuifs.axi4lite import AXI4Lite
|
||||||
from ..lib.cpuifs.passthrough import Passthrough
|
from ..lib.cpuifs.passthrough import Passthrough
|
||||||
|
|
||||||
TEST_PARAMS = get_permutations({
|
@parameterized_class(get_permutations({
|
||||||
"cpuif": [
|
"cpuif": [
|
||||||
APB4(),
|
APB4(),
|
||||||
AXI4Lite(),
|
AXI4Lite(),
|
||||||
@@ -15,9 +15,7 @@ TEST_PARAMS = get_permutations({
|
|||||||
"retime_read_fanin": [True, False],
|
"retime_read_fanin": [True, False],
|
||||||
"retime_read_response": [True, False],
|
"retime_read_response": [True, False],
|
||||||
"retime_external": [True, False],
|
"retime_external": [True, False],
|
||||||
})
|
}))
|
||||||
|
|
||||||
@parameterized_class(TEST_PARAMS)
|
|
||||||
class Test(SimTestCase):
|
class Test(SimTestCase):
|
||||||
extra_tb_files = [
|
extra_tb_files = [
|
||||||
"../lib/external_reg.sv",
|
"../lib/external_reg.sv",
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
from parameterized import parameterized_class
|
from parameterized import parameterized_class
|
||||||
|
|
||||||
from ..lib.sim_testcase import SimTestCase
|
from ..lib.sim_testcase import SimTestCase
|
||||||
from ..lib.test_params import TEST_PARAMS
|
from ..lib.test_params import get_permutations
|
||||||
|
from ..lib.cpuifs import ALL_CPUIF
|
||||||
|
|
||||||
@parameterized_class(TEST_PARAMS)
|
@parameterized_class(get_permutations({
|
||||||
|
"cpuif": ALL_CPUIF,
|
||||||
|
"retime_read_fanin": [True, False],
|
||||||
|
"retime_read_response": [True, False],
|
||||||
|
}))
|
||||||
class Test(SimTestCase):
|
class Test(SimTestCase):
|
||||||
def test_dut(self):
|
def test_dut(self):
|
||||||
self.run_test()
|
self.run_test()
|
||||||
|
|||||||
@@ -1,18 +1,37 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from parameterized import parameterized_class
|
from parameterized import parameterized_class
|
||||||
|
import pytest
|
||||||
|
|
||||||
from ..lib.sim_testcase import SimTestCase
|
from ..lib.sim_testcase import SimTestCase
|
||||||
from ..lib.synth_testcase import SynthTestCase
|
from ..lib.synth_testcase import SynthTestCase
|
||||||
from ..lib.test_params import TEST_PARAMS, get_permutations
|
from ..lib.test_params import get_permutations
|
||||||
|
from ..lib.cpuifs import ALL_CPUIF
|
||||||
from ..lib.simulators.xilinx import Xilinx
|
from ..lib.simulators.xilinx import Xilinx
|
||||||
import pytest
|
|
||||||
|
|
||||||
@parameterized_class(TEST_PARAMS)
|
|
||||||
class TestParameterizations(SimTestCase):
|
|
||||||
|
|
||||||
|
@parameterized_class(get_permutations({
|
||||||
|
"cpuif": ALL_CPUIF,
|
||||||
|
"retime_read_fanin": [True, False],
|
||||||
|
"retime_read_response": [True, False],
|
||||||
|
}))
|
||||||
|
class TestCPUIFS(SimTestCase):
|
||||||
def test_dut(self):
|
def test_dut(self):
|
||||||
self.run_test()
|
self.run_test()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@parameterized_class(get_permutations({
|
||||||
|
"reuse_hwif_typedefs": [True, False],
|
||||||
|
}))
|
||||||
|
class TestTypedefs(SimTestCase):
|
||||||
|
def test_dut(self):
|
||||||
|
self.run_test()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@parameterized_class(get_permutations({
|
@parameterized_class(get_permutations({
|
||||||
"default_reset_activelow": [True, False],
|
"default_reset_activelow": [True, False],
|
||||||
"default_reset_async": [True, False],
|
"default_reset_async": [True, False],
|
||||||
@@ -22,14 +41,26 @@ class TestDefaultResets(SimTestCase):
|
|||||||
self.run_test()
|
self.run_test()
|
||||||
|
|
||||||
|
|
||||||
@parameterized_class(TEST_PARAMS)
|
|
||||||
|
@parameterized_class(get_permutations({
|
||||||
|
"cpuif": ALL_CPUIF,
|
||||||
|
"retime_read_fanin": [True, False],
|
||||||
|
"retime_read_response": [True, False],
|
||||||
|
"reuse_hwif_typedefs": [True, False],
|
||||||
|
}))
|
||||||
class TestSynth(SynthTestCase):
|
class TestSynth(SynthTestCase):
|
||||||
def test_dut(self):
|
def test_dut(self):
|
||||||
self.run_synth()
|
self.run_synth()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(os.environ.get("STUB_SIMULATOR", False) or os.environ.get("NO_XSIM", False), reason="user skipped")
|
@pytest.mark.skipif(os.environ.get("STUB_SIMULATOR", False) or os.environ.get("NO_XSIM", False), reason="user skipped")
|
||||||
@parameterized_class(TEST_PARAMS)
|
@parameterized_class(get_permutations({
|
||||||
|
"cpuif": ALL_CPUIF,
|
||||||
|
"retime_read_fanin": [True, False],
|
||||||
|
"retime_read_response": [True, False],
|
||||||
|
"reuse_hwif_typedefs": [True, False],
|
||||||
|
}))
|
||||||
class TestVivado(SimTestCase):
|
class TestVivado(SimTestCase):
|
||||||
"""
|
"""
|
||||||
Vivado XSIM's implementation of clocking blocks is broken, which is heavily used
|
Vivado XSIM's implementation of clocking blocks is broken, which is heavily used
|
||||||
|
|||||||
Reference in New Issue
Block a user