Add support for cpuif that have write strobes
This commit is contained in:
@@ -34,6 +34,10 @@ cpuif_wr_data
|
||||
Data to be written for the write transfer. This signal is ignored for read
|
||||
transfers.
|
||||
|
||||
cpuif_wr_biten
|
||||
Active-high bit-level write-enable strobes.
|
||||
Only asserted bit positions will change the register value during a write transfer.
|
||||
|
||||
cpuif_req_stall_rd
|
||||
If asserted, and the next pending request is a read operation, then the
|
||||
transfer will not be accepted until this signal is deasserted.
|
||||
|
||||
@@ -173,6 +173,10 @@ X Do not allow unaligned addresses
|
||||
! Error if a property references a non-signal component, or property reference from
|
||||
outside the export hierarchy
|
||||
|
||||
! Error if a property is a reference to something that is external, or enclosed
|
||||
in an external component.
|
||||
Limit this check to child nodes inside the export hierarchy
|
||||
|
||||
! Add warning for sticky race condition
|
||||
stickybit and other similar situations generally should use hw precedence.
|
||||
Emit a warning as appropriate
|
||||
|
||||
@@ -28,6 +28,7 @@ always_ff {{get_always_ff_event(cpuif.reset)}} begin
|
||||
end
|
||||
end
|
||||
end
|
||||
assign cpuif_wr_biten = '1;
|
||||
|
||||
// Response
|
||||
assign {{cpuif.signal("pready")}} = cpuif_rd_ack | cpuif_wr_ack;
|
||||
|
||||
@@ -8,6 +8,7 @@ logic axil_awvalid;
|
||||
logic [{{cpuif.addr_width-1}}:0] axil_awaddr;
|
||||
logic axil_wvalid;
|
||||
logic [{{cpuif.data_width-1}}:0] axil_wdata;
|
||||
logic [{{cpuif.data_width-1}}:0] axil_wstrb;
|
||||
logic axil_aw_accept;
|
||||
logic axil_resp_acked;
|
||||
|
||||
@@ -21,6 +22,7 @@ always_ff {{get_always_ff_event(cpuif.reset)}} begin
|
||||
axil_awaddr <= '0;
|
||||
axil_wvalid <= '0;
|
||||
axil_wdata <= '0;
|
||||
axil_wstrb <= '0;
|
||||
axil_n_in_flight <= '0;
|
||||
end else begin
|
||||
// AR* acceptance register
|
||||
@@ -46,6 +48,7 @@ always_ff {{get_always_ff_event(cpuif.reset)}} begin
|
||||
if({{cpuif.signal("wvalid")}} && {{cpuif.signal("wready")}}) begin
|
||||
axil_wvalid <= '1;
|
||||
axil_wdata <= {{cpuif.signal("wdata")}};
|
||||
axil_wstrb <= {{cpuif.signal("wstrb")}};
|
||||
end
|
||||
|
||||
// Keep track of in-flight transactions
|
||||
@@ -66,6 +69,9 @@ end
|
||||
// Request dispatch
|
||||
always_comb begin
|
||||
cpuif_wr_data = axil_wdata;
|
||||
for(int i=0; i<{{cpuif.data_width_bytes}}; i++) begin
|
||||
cpuif_wr_biten[i*8 +: 8] = {8{axil_wstrb[i]}};
|
||||
end
|
||||
cpuif_req = '0;
|
||||
cpuif_req_is_wr = '0;
|
||||
cpuif_addr = '0;
|
||||
|
||||
@@ -10,6 +10,7 @@ class PassthroughCpuif(CpuifBase):
|
||||
"input wire s_cpuif_req_is_wr",
|
||||
f"input wire [{self.addr_width-1}:0] s_cpuif_addr",
|
||||
f"input wire [{self.data_width-1}:0] s_cpuif_wr_data",
|
||||
f"input wire [{self.data_width-1}:0] s_cpuif_wr_biten",
|
||||
"output wire s_cpuif_req_stall_wr",
|
||||
"output wire s_cpuif_req_stall_rd",
|
||||
"output wire s_cpuif_rd_ack",
|
||||
|
||||
@@ -2,6 +2,7 @@ assign cpuif_req = s_cpuif_req;
|
||||
assign cpuif_req_is_wr = s_cpuif_req_is_wr;
|
||||
assign cpuif_addr = s_cpuif_addr;
|
||||
assign cpuif_wr_data = s_cpuif_wr_data;
|
||||
assign cpuif_wr_biten = s_cpuif_wr_biten;
|
||||
assign s_cpuif_req_stall_wr = cpuif_req_stall_wr;
|
||||
assign s_cpuif_req_stall_rd = cpuif_req_stall_rd;
|
||||
assign s_cpuif_rd_ack = cpuif_rd_ack;
|
||||
|
||||
@@ -33,14 +33,25 @@ class _OnWrite(NextStateConditional):
|
||||
value = f"decoded_wr_data[{field.high}:{field.low}]"
|
||||
return value
|
||||
|
||||
def _wr_biten(self, field: 'FieldNode') -> str:
|
||||
if field.msb < field.lsb:
|
||||
# Field gets bitswapped since it is in [low:high] orientation
|
||||
value = f"{{<<{{decoded_wr_biten[{field.high}:{field.low}]}}}}"
|
||||
else:
|
||||
value = f"decoded_wr_biten[{field.high}:{field.low}]"
|
||||
return value
|
||||
|
||||
|
||||
class WriteOneSet(_OnWrite):
|
||||
comment = "SW write 1 set"
|
||||
onwritetype = OnWriteType.woset
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
D = self._wr_data(field)
|
||||
S = self._wr_biten(field)
|
||||
return [
|
||||
f"next_c = {R} | {self._wr_data(field)};",
|
||||
f"next_c = {R} | ({D} & {S});",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
@@ -50,8 +61,10 @@ class WriteOneClear(_OnWrite):
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
D = self._wr_data(field)
|
||||
S = self._wr_biten(field)
|
||||
return [
|
||||
f"next_c = {R} & ~{self._wr_data(field)};",
|
||||
f"next_c = {R} & ~({D} & {S});",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
@@ -61,8 +74,10 @@ class WriteOneToggle(_OnWrite):
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
D = self._wr_data(field)
|
||||
S = self._wr_biten(field)
|
||||
return [
|
||||
f"next_c = {R} ^ {self._wr_data(field)};",
|
||||
f"next_c = {R} ^ ({D} & {S});",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
@@ -72,8 +87,10 @@ class WriteZeroSet(_OnWrite):
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
D = self._wr_data(field)
|
||||
S = self._wr_biten(field)
|
||||
return [
|
||||
f"next_c = {R} | ~{self._wr_data(field)};",
|
||||
f"next_c = {R} | (~{D} & {S});",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
@@ -83,8 +100,10 @@ class WriteZeroClear(_OnWrite):
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
D = self._wr_data(field)
|
||||
S = self._wr_biten(field)
|
||||
return [
|
||||
f"next_c = {R} & {self._wr_data(field)};",
|
||||
f"next_c = {R} & ({D} | ~{S});",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
@@ -94,8 +113,10 @@ class WriteZeroToggle(_OnWrite):
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
D = self._wr_data(field)
|
||||
S = self._wr_biten(field)
|
||||
return [
|
||||
f"next_c = {R} ^ ~{self._wr_data(field)};",
|
||||
f"next_c = {R} ^ (~{D} & {S});",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
@@ -124,7 +145,10 @@ class Write(_OnWrite):
|
||||
onwritetype = None
|
||||
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
R = self.exp.field_logic.get_storage_identifier(field)
|
||||
D = self._wr_data(field)
|
||||
S = self._wr_biten(field)
|
||||
return [
|
||||
f"next_c = {self._wr_data(field)};",
|
||||
f"next_c = ({R} & ~{S}) | ({D} & {S});",
|
||||
"load_next_c = '1;",
|
||||
]
|
||||
|
||||
@@ -26,6 +26,7 @@ module {{module_name}} (
|
||||
logic cpuif_req_is_wr;
|
||||
logic [{{cpuif.addr_width-1}}:0] cpuif_addr;
|
||||
logic [{{cpuif.data_width-1}}:0] cpuif_wr_data;
|
||||
logic [{{cpuif.data_width-1}}:0] cpuif_wr_biten;
|
||||
logic cpuif_req_stall_wr;
|
||||
logic cpuif_req_stall_rd;
|
||||
|
||||
@@ -84,6 +85,7 @@ module {{module_name}} (
|
||||
logic decoded_req;
|
||||
logic decoded_req_is_wr;
|
||||
logic [{{cpuif.data_width-1}}:0] decoded_wr_data;
|
||||
logic [{{cpuif.data_width-1}}:0] decoded_wr_biten;
|
||||
|
||||
always_comb begin
|
||||
{{address_decode.get_implementation()|indent(8)}}
|
||||
@@ -93,6 +95,7 @@ module {{module_name}} (
|
||||
assign decoded_req = cpuif_req_masked;
|
||||
assign decoded_req_is_wr = cpuif_req_is_wr;
|
||||
assign decoded_wr_data = cpuif_wr_data;
|
||||
assign decoded_wr_biten = cpuif_wr_biten;
|
||||
|
||||
// Writes are always granted with no error response
|
||||
assign cpuif_wr_ack = decoded_req & decoded_req_is_wr;
|
||||
|
||||
@@ -9,6 +9,7 @@ interface passthrough_driver #(
|
||||
output logic m_cpuif_req_is_wr,
|
||||
output logic [ADDR_WIDTH-1:0] m_cpuif_addr,
|
||||
output logic [DATA_WIDTH-1:0] m_cpuif_wr_data,
|
||||
output logic [DATA_WIDTH-1:0] m_cpuif_wr_biten,
|
||||
input wire m_cpuif_req_stall_wr,
|
||||
input wire m_cpuif_req_stall_rd,
|
||||
input wire m_cpuif_rd_ack,
|
||||
@@ -27,6 +28,7 @@ interface passthrough_driver #(
|
||||
output m_cpuif_req_is_wr;
|
||||
output m_cpuif_addr;
|
||||
output m_cpuif_wr_data;
|
||||
output m_cpuif_wr_biten;
|
||||
input m_cpuif_req_stall_wr;
|
||||
input m_cpuif_req_stall_rd;
|
||||
input m_cpuif_rd_ack;
|
||||
@@ -41,12 +43,13 @@ interface passthrough_driver #(
|
||||
cb.m_cpuif_req_is_wr <= '0;
|
||||
cb.m_cpuif_addr <= '0;
|
||||
cb.m_cpuif_wr_data <= '0;
|
||||
cb.m_cpuif_wr_biten <= '0;
|
||||
endtask
|
||||
|
||||
semaphore txn_req_mutex = new(1);
|
||||
semaphore txn_resp_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-1:0] biten = '1);
|
||||
fork
|
||||
begin
|
||||
// Initiate transfer
|
||||
@@ -56,6 +59,7 @@ interface passthrough_driver #(
|
||||
cb.m_cpuif_req_is_wr <= '1;
|
||||
cb.m_cpuif_addr <= addr;
|
||||
cb.m_cpuif_wr_data <= data;
|
||||
cb.m_cpuif_wr_biten <= biten;
|
||||
@(cb);
|
||||
while(cb.m_cpuif_req_stall_wr !== 1'b0) @(cb);
|
||||
reset();
|
||||
|
||||
@@ -3,6 +3,7 @@ wire s_cpuif_req;
|
||||
wire s_cpuif_req_is_wr;
|
||||
wire [{{exporter.cpuif.addr_width-1}}:0] s_cpuif_addr;
|
||||
wire [{{exporter.cpuif.data_width-1}}:0] s_cpuif_wr_data;
|
||||
wire [{{exporter.cpuif.data_width-1}}:0] s_cpuif_wr_biten;
|
||||
wire s_cpuif_req_stall_wr;
|
||||
wire s_cpuif_req_stall_rd;
|
||||
wire s_cpuif_rd_ack;
|
||||
@@ -20,6 +21,7 @@ passthrough_driver #(
|
||||
.m_cpuif_req_is_wr(s_cpuif_req_is_wr),
|
||||
.m_cpuif_addr(s_cpuif_addr),
|
||||
.m_cpuif_wr_data(s_cpuif_wr_data),
|
||||
.m_cpuif_wr_biten(s_cpuif_wr_biten),
|
||||
.m_cpuif_req_stall_wr(s_cpuif_req_stall_wr),
|
||||
.m_cpuif_req_stall_rd(s_cpuif_req_stall_rd),
|
||||
.m_cpuif_rd_ack(s_cpuif_rd_ack),
|
||||
|
||||
0
tests/test_write_strobes/__init__.py
Normal file
0
tests/test_write_strobes/__init__.py
Normal file
54
tests/test_write_strobes/regblock.rdl
Normal file
54
tests/test_write_strobes/regblock.rdl
Normal file
@@ -0,0 +1,54 @@
|
||||
addrmap top {
|
||||
|
||||
reg {
|
||||
field {
|
||||
sw=rw; hw=na;
|
||||
onwrite = woset;
|
||||
} f1[3:0] = 0x0;
|
||||
|
||||
field {
|
||||
sw=rw; hw=na;
|
||||
onwrite = woclr;
|
||||
} f2[7:4] = 0xF;
|
||||
|
||||
field {
|
||||
sw=rw; hw=na;
|
||||
onwrite = wot;
|
||||
} f3[11:8] = 0x0;
|
||||
} r1;
|
||||
|
||||
reg {
|
||||
field {
|
||||
sw=rw; hw=na;
|
||||
onwrite = wzs;
|
||||
} f1[3:0] = 0x0;
|
||||
|
||||
field {
|
||||
sw=rw; hw=na;
|
||||
onwrite = wzc;
|
||||
} f2[7:4] = 0xF;
|
||||
|
||||
field {
|
||||
sw=rw; hw=na;
|
||||
onwrite = wzt;
|
||||
} f3[11:8] = 0x0;
|
||||
} r2;
|
||||
|
||||
reg {
|
||||
field {
|
||||
sw=rw; hw=na;
|
||||
onwrite = wclr;
|
||||
} f1[7:0] = 0xF0;
|
||||
|
||||
field {
|
||||
sw=rw; hw=na;
|
||||
onwrite = wset;
|
||||
} f2[15:8] = 0x0F;
|
||||
} r3;
|
||||
|
||||
reg {
|
||||
field {
|
||||
sw=rw; hw=na;
|
||||
} f3[7:0] = 0x00;
|
||||
} r4;
|
||||
};
|
||||
31
tests/test_write_strobes/tb_template.sv
Normal file
31
tests/test_write_strobes/tb_template.sv
Normal file
@@ -0,0 +1,31 @@
|
||||
{% extends "lib/tb_base.sv" %}
|
||||
|
||||
{% block seq %}
|
||||
{% sv_line_anchor %}
|
||||
##1;
|
||||
cb.rst <= '0;
|
||||
##1;
|
||||
|
||||
cpuif.assert_read('h0, 'h0_F_0);
|
||||
cpuif.write ('h0, 'h5_5_5, 'h3_3_3);
|
||||
cpuif.assert_read('h0, 'h1_E_1);
|
||||
cpuif.write ('h0, 'h5_A_A, 'h3_3_3);
|
||||
cpuif.assert_read('h0, 'h0_C_3);
|
||||
|
||||
cpuif.assert_read('h4, 'h0_F_0);
|
||||
cpuif.write ('h4, 'hA_A_A, 'h3_3_3);
|
||||
cpuif.assert_read('h4, 'h1_E_1);
|
||||
cpuif.write ('h4, 'hA_5_5, 'h3_3_3);
|
||||
cpuif.assert_read('h4, 'h0_C_3);
|
||||
|
||||
cpuif.assert_read('h8, 'h0F_F0);
|
||||
cpuif.write ('h8, 'h12_34, 'hFF_00);
|
||||
cpuif.assert_read('h8, 'hFF_00);
|
||||
|
||||
cpuif.assert_read('hC, 'h00);
|
||||
cpuif.write ('hC, 'hFF, 'hF0);
|
||||
cpuif.assert_read('hC, 'hF0);
|
||||
cpuif.write ('hC, 'h00, 'h3C);
|
||||
cpuif.assert_read('hC, 'hC0);
|
||||
|
||||
{% endblock %}
|
||||
9
tests/test_write_strobes/testcase.py
Normal file
9
tests/test_write_strobes/testcase.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from ..lib.sim_testcase import SimTestCase
|
||||
|
||||
from ..lib.cpuifs.passthrough import Passthrough
|
||||
|
||||
class Test(SimTestCase):
|
||||
cpuif = Passthrough()
|
||||
|
||||
def test_dut(self):
|
||||
self.run_test()
|
||||
Reference in New Issue
Block a user