Refactor readback mux implementation. Improves performance (#155) and eliminates illegal streaming operator usage (#165)

This commit is contained in:
Alex Mykyta
2025-12-10 23:17:33 -08:00
parent 4201ce975e
commit 9fc95b8769
24 changed files with 1116 additions and 634 deletions

View File

@@ -6,10 +6,10 @@
Testcases require an installation of the Questa simulator, and for `vlog` & `vsim`
commands to be visible via the PATH environment variable.
*Questa - Intel FPGA Starter Edition* can be downloaded for free from Intel:
* Go to https://www.intel.com/content/www/us/en/collections/products/fpga/software/downloads.html?edition=pro&q=questa&s=Relevancy
* Select latest version of Questa
* Download Questa files.
*Questa-Altera FPGA and Starter Edition* can be downloaded for free from Altera:
* Go to https://www.altera.com/downloads
* Select "Simulation Tools"
* Download Questa
* Install
* Be sure to choose "Starter Edition" for the free version.
* Create an account on https://licensing.intel.com
@@ -18,7 +18,7 @@ commands to be visible via the PATH environment variable.
* Go to https://licensing.intel.com/psg/s/sales-signup-evaluationlicenses
* Generate a free *Starter Edition* license file for Questa
* Easiest to use a *fixed* license using your NIC ID (MAC address of your network card via `ifconfig`)
* Download the license file and point the `LM_LICENSE_FILE` environment variable to the folder which contains it.
* Download the license file and point the `LM_LICENSE_FILE` environment variable to the folder which contains it. In newer versions of Questa, use the `SALT_LICENSE_SERVER` environment variable instead.
* (optional) Delete Intel libraries to save some disk space
* Delete `<install_dir>/questa_fse/intel`
* Edit `<install_dir>/questa_fse/modelsim.ini` and remove lines that reference the `intel` libraries

View File

@@ -0,0 +1,11 @@
addrmap top {
mem ext_mem #(
longint SIZE = 0x100
) {
memwidth = 32;
mementries = SIZE / 4;
};
external ext_mem #(.SIZE(0x10)) mem1 @ 0x0000;
external ext_mem #(.SIZE(0x90)) mem2 @ 0x0200;
};

View File

@@ -0,0 +1,115 @@
{% extends "lib/tb_base.sv" %}
{%- block dut_support %}
{% sv_line_anchor %}
external_block #(
.ADDR_WIDTH($clog2('h10))
) mem1_inst (
.clk(clk),
.rst(rst),
.req(hwif_out.mem1.req),
.req_is_wr(hwif_out.mem1.req_is_wr),
.addr(hwif_out.mem1.addr),
.wr_data(hwif_out.mem1.wr_data),
.wr_biten(hwif_out.mem1.wr_biten),
.rd_ack(hwif_in.mem1.rd_ack),
.rd_data(hwif_in.mem1.rd_data),
.wr_ack(hwif_in.mem1.wr_ack)
);
external_block #(
.ADDR_WIDTH($clog2('h90))
) mem2_inst (
.clk(clk),
.rst(rst),
.req(hwif_out.mem2.req),
.req_is_wr(hwif_out.mem2.req_is_wr),
.addr(hwif_out.mem2.addr),
.wr_data(hwif_out.mem2.wr_data),
.wr_biten(hwif_out.mem2.wr_biten),
.rd_ack(hwif_in.mem2.rd_ack),
.rd_data(hwif_in.mem2.rd_data),
.wr_ack(hwif_in.mem2.wr_ack)
);
{%- endblock %}
{% block seq %}
{% sv_line_anchor %}
##1;
cb.rst <= '0;
##1;
//--------------------------------------------------------------------------
// Simple read/write tests
//--------------------------------------------------------------------------
// mem1
repeat(32) begin
logic [31:0] x;
int unsigned addr;
x = $urandom();
addr = 'h0;
addr += $urandom_range(('h10 / 4) - 1) * 4;
cpuif.write(addr, x);
cpuif.assert_read(addr, x);
end
// mem2
repeat(32) begin
logic [31:0] x;
int unsigned addr;
x = $urandom();
addr = 'h200;
addr += $urandom_range(('h90 / 4) - 1) * 4;
cpuif.write(addr, x);
cpuif.assert_read(addr, x);
end
//--------------------------------------------------------------------------
// Pipelined access
//--------------------------------------------------------------------------
// init array with unique known value
for(int i=0; i<('h10 / 4); i++) begin
cpuif.write('h0 + i*4, 'h1000 + i);
end
for(int i=0; i<('h90 / 4); i++) begin
cpuif.write('h200 + i*4, 'h3000 + i);
end
// random pipelined read/writes
repeat(256) begin
fork
begin
int i;
logic [31:0] x;
int unsigned addr;
case($urandom_range(1))
0: begin
i = $urandom_range(('h10 / 4) - 1);
x = 'h1000 + i;
addr = 'h0 + i*4;
end
1: begin
i = $urandom_range(('h90 / 4) - 1);
x = 'h3000 + i;
addr = 'h200 + i*4;
end
endcase
case($urandom_range(1))
0: cpuif.write(addr, x);
1: cpuif.assert_read(addr, x);
endcase
end
join_none
end
wait fork;
{% endblock %}

View File

@@ -0,0 +1,29 @@
from parameterized import parameterized_class
from ..lib.cpuifs.apb4 import APB4
from ..lib.cpuifs.axi4lite import AXI4Lite
from ..lib.cpuifs.passthrough import Passthrough
from ..lib.sim_testcase import SimTestCase
from ..lib.test_params import get_permutation_class_name, get_permutations
@parameterized_class(get_permutations({
"cpuif": [
APB4(),
Passthrough(),
],
"retime_read_fanin": [True, False],
"retime_read_response": [True, False],
"retime_external": [True, False],
}), class_name_func=get_permutation_class_name)
class Test(SimTestCase):
extra_tb_files = [
"../lib/external_reg.sv",
"../lib/external_block.sv",
]
init_hwif_in = False
clocking_hwif_in = False
timeout_clk_cycles = 30000
def test_dut(self):
self.run_test()