diff --git a/hdl-src/axi4lite_intf.sv b/hdl-src/axi4lite_intf.sv index b0a232d..befda61 100644 --- a/hdl-src/axi4lite_intf.sv +++ b/hdl-src/axi4lite_intf.sv @@ -54,14 +54,14 @@ interface axi4lite_intf #( modport slave ( output AWREADY, - input AWVALID, - input AWADDR, + // input AWVALID, + // input AWADDR, input AWPROT, output WREADY, - input WVALID, - input WDATA, - input WSTRB, + // input WVALID, + // input WDATA, + // input WSTRB, input BREADY, output BVALID, @@ -73,8 +73,8 @@ interface axi4lite_intf #( input ARPROT, input RREADY, - output RVALID, - output RDATA, - output RRESP + // output RVALID, + // output RDATA, + // output RRESP ); endinterface diff --git a/src/peakrdl_busdecoder/cpuif/apb3/apb3_cpuif.py b/src/peakrdl_busdecoder/cpuif/apb3/apb3_cpuif.py index c511c7f..3602404 100644 --- a/src/peakrdl_busdecoder/cpuif/apb3/apb3_cpuif.py +++ b/src/peakrdl_busdecoder/cpuif/apb3/apb3_cpuif.py @@ -1,3 +1,5 @@ +from typing import overload + from systemrdl.node import AddressableNode from ...utils import get_indexed_path @@ -10,11 +12,11 @@ class APB3Cpuif(BaseCpuif): def _port_declaration(self, child: AddressableNode) -> str: base = f"apb3_intf.master m_apb_{child.inst_name}" - if not child.is_array: + if child.array_dimensions is None: return base if child.current_idx is not None: - return f"{base}_{'_'.join(map(str, child.current_idx))}" - return f"{base} [N_{child.inst_name.upper()}S]" + return f"{base}_{'_'.join(map(str, child.current_idx))} {''.join(f'[{dim}]' for dim in child.array_dimensions)}" + return f"{base} {''.join(f'[{dim}]' for dim in child.array_dimensions)}" @property def port_declaration(self) -> str: @@ -23,36 +25,48 @@ class APB3Cpuif(BaseCpuif): return ",\n".join(slave_ports + master_ports) - def signal( - self, - signal: str, - node: AddressableNode | None = None, - ) -> str: - if node is None: + @overload + def signal(self, signal: str, node: None = None, indexer: None = None) -> str: ... + @overload + def signal(self, signal: str, node: AddressableNode, indexer: str) -> str: ... + def signal(self, signal: str, node: AddressableNode | None = None, indexer: str | None = None) -> str: + if node is None or indexer is None: # Node is none, so this is a slave signal return f"s_apb.{signal}" # Master signal - return f"m_apb_{node.inst_name}.{signal}" + return f"m_apb_{get_indexed_path(node.parent, node, indexer, skip_kw_filter=True)}.{signal}" - def fanout(self, node: AddressableNode, idx: str | None = None) -> str: + def fanout(self, node: AddressableNode) -> str: fanout: dict[str, str] = {} - fanout[self.signal("PSEL", node, idx)] = ( - f"cpuif_wr_sel.{get_indexed_path(self.exp.ds.top_node, node)}|cpuif_rd_sel.{get_indexed_path(self.exp.ds.top_node, node)}" + fanout[self.signal("PSEL", node, "gi")] = ( + f"cpuif_wr_sel.{get_indexed_path(self.exp.ds.top_node, node, 'gi')}|cpuif_rd_sel.{get_indexed_path(self.exp.ds.top_node, node, 'gi')}" ) - fanout[self.signal("PSEL", node, idx)] = self.signal("PSEL") - fanout[self.signal("PWRITE", node, idx)] = ( - f"cpuif_wr_sel.{get_indexed_path(self.exp.ds.top_node, node)}" + fanout[self.signal("PENABLE", node, "gi")] = self.signal("PENABLE") + fanout[self.signal("PWRITE", node, "gi")] = ( + f"cpuif_wr_sel.{get_indexed_path(self.exp.ds.top_node, node, 'gi')}" ) - fanout[self.signal("PADDR", node, idx)] = self.signal("PADDR") - fanout[self.signal("PWDATA", node, idx)] = "cpuif_wr_data" + fanout[self.signal("PADDR", node, "gi")] = self.signal("PADDR") + fanout[self.signal("PWDATA", node, "gi")] = "cpuif_wr_data" return "\n".join(map(lambda kv: f"assign {kv[0]} = {kv[1]};", fanout.items())) - def fanin(self, node: AddressableNode, idx: str | None = None) -> str: + def fanin(self, node: AddressableNode | None = None) -> str: fanin: dict[str, str] = {} - fanin["cpuif_rd_data"] = self.signal("PRDATA", node, idx) - fanin["cpuif_rd_ack"] = self.signal("PREADY", node, idx) - fanin["cpuif_rd_err"] = self.signal("PSLVERR", node, idx) + if node is None: + fanin["cpuif_rd_ack"] = "'0" + fanin["cpuif_rd_err"] = "'0" + else: + fanin["cpuif_rd_ack"] = self.signal("PREADY", node, "i") + fanin["cpuif_rd_err"] = self.signal("PSLVERR", node, "i") + + return "\n".join(map(lambda kv: f"{kv[0]} = {kv[1]};", fanin.items())) + + def readback(self, node: AddressableNode | None = None) -> str: + fanin: dict[str, str] = {} + if node is None: + fanin["cpuif_rd_data"] = "'0" + else: + fanin["cpuif_rd_data"] = self.signal("PRDATA", node, "i") return "\n".join(map(lambda kv: f"{kv[0]} = {kv[1]};", fanin.items())) diff --git a/src/peakrdl_busdecoder/cpuif/apb3/apb3_tmpl.sv b/src/peakrdl_busdecoder/cpuif/apb3/apb3_tmpl.sv index 98ddbdc..1a3c8e5 100644 --- a/src/peakrdl_busdecoder/cpuif/apb3/apb3_tmpl.sv +++ b/src/peakrdl_busdecoder/cpuif/apb3/apb3_tmpl.sv @@ -9,15 +9,18 @@ `endif {% endif -%} -assign cpuif_req = {{cpuif.signal("PSELx")}}; +assign cpuif_req = {{cpuif.signal("PSEL")}}; assign cpuif_wr_en = {{cpuif.signal("PWRITE")}}; assign cpuif_rd_en = !{{cpuif.signal("PWRITE")}}; +assign cpuif_wr_addr = {{cpuif.signal("PADDR")}}; +assign cpuif_rd_addr = {{cpuif.signal("PADDR")}}; + assign cpuif_wr_data = {{cpuif.signal("PWDATA")}}; assign {{cpuif.signal("PRDATA")}} = cpuif_rd_data; assign {{cpuif.signal("PREADY")}} = cpuif_rd_ack; -assign {{cpuif.signal("PSLVERR")}} = cpuif_rd_err; +assign {{cpuif.signal("PSLVERR")}} = cpuif_rd_err | cpuif_rd_sel.cpuif_err | cpuif_wr_sel.cpuif_err; //-------------------------------------------------------------------------- // Fanout CPU Bus interface signals diff --git a/src/peakrdl_busdecoder/cpuif/axi4lite/__init__.py b/src/peakrdl_busdecoder/cpuif/axi4lite/__init__.py deleted file mode 100644 index 24e5b1a..0000000 --- a/src/peakrdl_busdecoder/cpuif/axi4lite/__init__.py +++ /dev/null @@ -1,67 +0,0 @@ -from ..base_cpuif import CpuifBase - - -class AXI4Lite_Cpuif(CpuifBase): - template_path = "axi4lite_tmpl.sv" - is_interface = True - - @property - def port_declaration(self) -> str: - return "axi4lite_intf.slave s_axil" - - def signal(self, name: str) -> str: - return "s_axil." + name.upper() - - @property - def busdecoder_latency(self) -> int: - return max(self.exp.ds.min_read_latency, self.exp.ds.min_write_latency) - - @property - def max_outstanding(self) -> int: - """ - Best pipelined performance is when the max outstanding transactions - is the design's latency + 2. - Anything beyond that does not have any effect, aside from adding unnecessary - logic and additional buffer-bloat latency. - """ - return self.busdecoder_latency + 2 - - @property - def resp_buffer_size(self) -> int: - """ - Response buffer size must be greater or equal to max outstanding - transactions to prevent response overrun. - """ - return self.max_outstanding - - -class AXI4Lite_Cpuif_flattened(AXI4Lite_Cpuif): - is_interface = False - - @property - def port_declaration(self) -> str: - lines = [ - "output logic " + self.signal("awready"), - "input wire " + self.signal("awvalid"), - f"input wire [{self.addr_width - 1}:0] " + self.signal("awaddr"), - "input wire [2:0] " + self.signal("awprot"), - "output logic " + self.signal("wready"), - "input wire " + self.signal("wvalid"), - f"input wire [{self.data_width - 1}:0] " + self.signal("wdata"), - f"input wire [{self.data_width_bytes - 1}:0]" + self.signal("wstrb"), - "input wire " + self.signal("bready"), - "output logic " + self.signal("bvalid"), - "output logic [1:0] " + self.signal("bresp"), - "output logic " + self.signal("arready"), - "input wire " + self.signal("arvalid"), - f"input wire [{self.addr_width - 1}:0] " + self.signal("araddr"), - "input wire [2:0] " + self.signal("arprot"), - "input wire " + self.signal("rready"), - "output logic " + self.signal("rvalid"), - f"output logic [{self.data_width - 1}:0] " + self.signal("rdata"), - "output logic [1:0] " + self.signal("rresp"), - ] - return ",\n".join(lines) - - def signal(self, name: str) -> str: - return "s_axil_" + name diff --git a/src/peakrdl_busdecoder/cpuif/axi4lite/axi4_lite_cpuif.py b/src/peakrdl_busdecoder/cpuif/axi4lite/axi4_lite_cpuif.py new file mode 100644 index 0000000..e6d245e --- /dev/null +++ b/src/peakrdl_busdecoder/cpuif/axi4lite/axi4_lite_cpuif.py @@ -0,0 +1,89 @@ +from typing import overload + +from systemrdl.node import AddressableNode + +from ...utils import get_indexed_path +from ..base_cpuif import BaseCpuif + + +class AXI4LiteCpuif(BaseCpuif): + template_path = "axi4lite_tmpl.sv" + is_interface = True + + def _port_declaration(self, child: AddressableNode) -> str: + base = f"axi4lite_intf.master m_axil_{child.inst_name}" + if child.array_dimensions is None: + return base + if child.current_idx is not None: + return f"{base}_{'_'.join(map(str, child.current_idx))} {''.join(f'[{dim}]' for dim in child.array_dimensions)}" + return f"{base} {''.join(f'[{dim}]' for dim in child.array_dimensions)}" + + @property + def port_declaration(self) -> str: + """Returns the port declaration for the AXI4-Lite interface.""" + slave_ports: list[str] = ["axi4lite_intf.slave s_axil"] + master_ports: list[str] = list(map(self._port_declaration, self.addressable_children)) + + return ",\n".join(slave_ports + master_ports) + + @overload + def signal(self, signal: str, node: None = None, indexer: None = None) -> str: ... + @overload + def signal(self, signal: str, node: AddressableNode, indexer: str) -> str: ... + def signal(self, signal: str, node: AddressableNode | None = None, indexer: str | None = None) -> str: + if node is None or indexer is None: + # Node is none, so this is a slave signal + return f"s_axil.{signal}" + + # Master signal + return f"m_axil_{get_indexed_path(node.parent, node, indexer, skip_kw_filter=True)}.{signal}" + + def fanout(self, node: AddressableNode) -> str: + fanout: dict[str, str] = {} + + wr_sel = f"cpuif_wr_sel.{get_indexed_path(self.exp.ds.top_node, node, 'gi')}" + rd_sel = f"cpuif_rd_sel.{get_indexed_path(self.exp.ds.top_node, node, 'gi')}" + + # Write address channel + fanout[self.signal("AWVALID", node, "gi")] = wr_sel + fanout[self.signal("AWADDR", node, "gi")] = self.signal("AWADDR") + fanout[self.signal("AWPROT", node, "gi")] = self.signal("AWPROT") + + # Write data channel + fanout[self.signal("WVALID", node, "gi")] = wr_sel + fanout[self.signal("WDATA", node, "gi")] = "cpuif_wr_data" + fanout[self.signal("WSTRB", node, "gi")] = "cpuif_wr_byte_en" + + # Write response channel (master -> slave) + fanout[self.signal("BREADY", node, "gi")] = self.signal("BREADY") + + # Read address channel + fanout[self.signal("ARVALID", node, "gi")] = rd_sel + fanout[self.signal("ARADDR", node, "gi")] = self.signal("ARADDR") + fanout[self.signal("ARPROT", node, "gi")] = self.signal("ARPROT") + + # Read data channel (master -> slave) + fanout[self.signal("RREADY", node, "gi")] = self.signal("RREADY") + + return "\n".join(f"assign {lhs} = {rhs};" for lhs, rhs in fanout.items()) + + def fanin(self, node: AddressableNode | None = None) -> str: + fanin: dict[str, str] = {} + if node is None: + fanin["cpuif_rd_ack"] = "'0" + fanin["cpuif_rd_err"] = "'0" + else: + # Read side: ack comes from RVALID; err if RRESP[1] is set (SLVERR/DECERR) + fanin["cpuif_rd_ack"] = self.signal("RVALID", node, "i") + fanin["cpuif_rd_err"] = f"{self.signal('RRESP', node, 'i')}[1]" + + return "\n".join(f"{lhs} = {rhs};" for lhs, rhs in fanin.items()) + + def readback(self, node: AddressableNode | None = None) -> str: + fanin: dict[str, str] = {} + if node is None: + fanin["cpuif_rd_data"] = "'0" + else: + fanin["cpuif_rd_data"] = self.signal("RDATA", node, "i") + + return "\n".join(f"{lhs} = {rhs};" for lhs, rhs in fanin.items()) diff --git a/src/peakrdl_busdecoder/cpuif/axi4lite/axi4lite_tmpl.sv b/src/peakrdl_busdecoder/cpuif/axi4lite/axi4lite_tmpl.sv index d89113e..4a7dc24 100644 --- a/src/peakrdl_busdecoder/cpuif/axi4lite/axi4lite_tmpl.sv +++ b/src/peakrdl_busdecoder/cpuif/axi4lite/axi4lite_tmpl.sv @@ -1,254 +1,60 @@ {%- if cpuif.is_interface -%} `ifndef SYNTHESIS initial begin - assert_bad_addr_width: assert($bits({{cpuif.signal("araddr")}}) >= {{ds.package_name}}::{{ds.module_name.upper()}}_MIN_ADDR_WIDTH) - else $error("Interface address width of %0d is too small. Shall be at least %0d bits", $bits({{cpuif.signal("araddr")}}), {{ds.package_name}}::{{ds.module_name.upper()}}_MIN_ADDR_WIDTH); - assert_bad_data_width: assert($bits({{cpuif.signal("wdata")}}) == {{ds.package_name}}::{{ds.module_name.upper()}}_DATA_WIDTH) - else $error("Interface data width of %0d is incorrect. Shall be %0d bits", $bits({{cpuif.signal("wdata")}}), {{ds.package_name}}::{{ds.module_name.upper()}}_DATA_WIDTH); - end -`endif + // Width checks (AXI4-Lite) + assert_bad_awaddr_width: assert($bits({{cpuif.signal("AWADDR")}}) >= {{ds.package_name}}::{{ds.module_name|upper}}_MIN_ADDR_WIDTH) + else $error("AWADDR width %0d < MIN_ADDR_WIDTH %0d", + $bits({{cpuif.signal("AWADDR")}}), {{ds.package_name}}::{{ds.module_name|upper}}_MIN_ADDR_WIDTH); + assert_bad_araddr_width: assert($bits({{cpuif.signal("ARADDR")}}) >= {{ds.package_name}}::{{ds.module_name|upper}}_MIN_ADDR_WIDTH) + else $error("ARADDR width %0d < MIN_ADDR_WIDTH %0d", + $bits({{cpuif.signal("ARADDR")}}), {{ds.package_name}}::{{ds.module_name|upper}}_MIN_ADDR_WIDTH); + + assert_bad_data_width: assert($bits({{cpuif.signal("WDATA")}}) == {{ds.package_name}}::{{ds.module_name|upper}}_DATA_WIDTH) + else $error("WDATA width %0d != DATA_WIDTH %0d", + $bits({{cpuif.signal("WDATA")}}), {{ds.package_name}}::{{ds.module_name|upper}}_DATA_WIDTH); + end + + // Simple handshake sanity (one-cycle implication; relax/adjust as needed) + assert_rd_resp_enc: assert property (@(posedge {{cpuif.signal("ACLK")}}) + {{cpuif.signal("RVALID")}} |-> (^{{cpuif.signal("RRESP")}} !== 1'bx)) + else $error("RRESP must be a legal AXI response when RVALID is high"); + + assert_wr_resp_enc: assert property (@(posedge {{cpuif.signal("ACLK")}}) + {{cpuif.signal("BVALID")}} |-> (^{{cpuif.signal("BRESP")}} !== 1'bx)) + else $error("BRESP must be a legal AXI response when BVALID is high"); +`endif {% endif -%} -// Max Outstanding Transactions: {{cpuif.max_outstanding}} -logic [{{clog2(cpuif.max_outstanding+1)-1}}:0] axil_n_in_flight; -logic axil_prev_was_rd; -logic axil_arvalid; -logic [{{cpuif.addr_width-1}}:0] axil_araddr; -logic axil_ar_accept; -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_bytes-1}}:0] axil_wstrb; -logic axil_aw_accept; -logic axil_resp_acked; -// Transaction request acceptance -always_ff {{get_always_ff_event(cpuif.reset)}} begin - if({{get_resetsignal(cpuif.reset)}}) begin - axil_prev_was_rd <= '0; - axil_arvalid <= '0; - axil_araddr <= '0; - axil_awvalid <= '0; - axil_awaddr <= '0; - axil_wvalid <= '0; - axil_wdata <= '0; - axil_wstrb <= '0; - axil_n_in_flight <= '0; - end else begin - // AR* acceptance register - if(axil_ar_accept) begin - axil_prev_was_rd <= '1; - axil_arvalid <= '0; - end - if({{cpuif.signal("arvalid")}} && {{cpuif.signal("arready")}}) begin - axil_arvalid <= '1; - axil_araddr <= {{cpuif.signal("araddr")}}; - end +assign cpuif_req = {{cpuif.signal("AWVALID")}} | {{cpuif.signal("ARVALID")}}; +assign cpuif_wr_en = {{cpuif.signal("AWVALID")}} & {{cpuif.signal("WVALID")}}; +assign cpuif_rd_en = {{cpuif.signal("ARVALID")}}; - // AW* & W* acceptance registers - if(axil_aw_accept) begin - axil_prev_was_rd <= '0; - axil_awvalid <= '0; - axil_wvalid <= '0; - end - if({{cpuif.signal("awvalid")}} && {{cpuif.signal("awready")}}) begin - axil_awvalid <= '1; - axil_awaddr <= {{cpuif.signal("awaddr")}}; - end - if({{cpuif.signal("wvalid")}} && {{cpuif.signal("wready")}}) begin - axil_wvalid <= '1; - axil_wdata <= {{cpuif.signal("wdata")}}; - axil_wstrb <= {{cpuif.signal("wstrb")}}; - end +assign cpuif_wr_addr = {{cpuif.signal("AWADDR")}}; +assign cpuif_rd_addr = {{cpuif.signal("ARADDR")}}; - // Keep track of in-flight transactions - if((axil_ar_accept || axil_aw_accept) && !axil_resp_acked) begin - axil_n_in_flight <= axil_n_in_flight + 1'b1; - end else if(!(axil_ar_accept || axil_aw_accept) && axil_resp_acked) begin - axil_n_in_flight <= axil_n_in_flight - 1'b1; - end - end -end +assign cpuif_wr_data = {{cpuif.signal("WDATA")}}; +assign cpuif_wr_byte_en = {{cpuif.signal("WSTRB")}}; -always_comb begin - {{cpuif.signal("arready")}} = (!axil_arvalid || axil_ar_accept); - {{cpuif.signal("awready")}} = (!axil_awvalid || axil_aw_accept); - {{cpuif.signal("wready")}} = (!axil_wvalid || axil_aw_accept); -end +// +// Return paths back to AXI master from generic cpuif_* +// Read: ack=RVALID, err=RRESP[1] (SLVERR/DECERR), data=RDATA +// +assign {{cpuif.signal("RDATA")}} = cpuif_rd_data; +assign {{cpuif.signal("RVALID")}} = cpuif_rd_ack; +assign {{cpuif.signal("RRESP")}} = (cpuif_rd_err | cpuif_rd_sel.cpuif_err | cpuif_wr_sel.cpuif_err) ? 2'b10 : 2'b00; -// 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; - axil_ar_accept = '0; - axil_aw_accept = '0; +// Write: ack=BVALID, err=BRESP[1] +assign {{cpuif.signal("BVALID")}} = cpuif_wr_ack; +assign {{cpuif.signal("BRESP")}} = (cpuif_wr_err | cpuif_wr_sel.cpuif_err | cpuif_rd_sel.cpuif_err) ? 2'b10 : 2'b00; - if(axil_n_in_flight < {{clog2(cpuif.max_outstanding+1)}}'d{{cpuif.max_outstanding}}) begin - // Can safely issue more transactions without overwhelming response buffer - if(axil_arvalid && !axil_prev_was_rd) begin - cpuif_req = '1; - cpuif_req_is_wr = '0; - {%- if cpuif.data_width_bytes == 1 %} - cpuif_addr = axil_araddr; - {%- else %} - cpuif_addr = {axil_araddr[{{cpuif.addr_width-1}}:{{clog2(cpuif.data_width_bytes)}}], {{clog2(cpuif.data_width_bytes)}}'b0}; - {%- endif %} - if(!cpuif_req_stall_rd) axil_ar_accept = '1; - end else if(axil_awvalid && axil_wvalid) begin - cpuif_req = '1; - cpuif_req_is_wr = '1; - {%- if cpuif.data_width_bytes == 1 %} - cpuif_addr = axil_awaddr; - {%- else %} - cpuif_addr = {axil_awaddr[{{cpuif.addr_width-1}}:{{clog2(cpuif.data_width_bytes)}}], {{clog2(cpuif.data_width_bytes)}}'b0}; - {%- endif %} - if(!cpuif_req_stall_wr) axil_aw_accept = '1; - end else if(axil_arvalid) begin - cpuif_req = '1; - cpuif_req_is_wr = '0; - {%- if cpuif.data_width_bytes == 1 %} - cpuif_addr = axil_araddr; - {%- else %} - cpuif_addr = {axil_araddr[{{cpuif.addr_width-1}}:{{clog2(cpuif.data_width_bytes)}}], {{clog2(cpuif.data_width_bytes)}}'b0}; - {%- endif %} - if(!cpuif_req_stall_rd) axil_ar_accept = '1; - end - end -end +//-------------------------------------------------------------------------- +// Fanout CPU Bus interface signals +//-------------------------------------------------------------------------- +{{fanout|walk(cpuif=cpuif)}} - -// AXI4-Lite Response Logic -{%- if cpuif.resp_buffer_size == 1 %} -always_ff {{get_always_ff_event(cpuif.reset)}} begin - if({{get_resetsignal(cpuif.reset)}}) begin - {{cpuif.signal("rvalid")}} <= '0; - {{cpuif.signal("rresp")}} <= '0; - {{cpuif.signal("rdata")}} <= '0; - {{cpuif.signal("bvalid")}} <= '0; - {{cpuif.signal("bresp")}} <= '0; - end else begin - if({{cpuif.signal("rvalid")}} && {{cpuif.signal("rready")}}) begin - {{cpuif.signal("rvalid")}} <= '0; - end - - if({{cpuif.signal("bvalid")}} && {{cpuif.signal("bready")}}) begin - {{cpuif.signal("bvalid")}} <= '0; - end - - if(cpuif_rd_ack) begin - {{cpuif.signal("rvalid")}} <= '1; - {{cpuif.signal("rdata")}} <= cpuif_rd_data; - if(cpuif_rd_err) {{cpuif.signal("rresp")}} <= 2'b10; // SLVERR - else {{cpuif.signal("rresp")}} <= 2'b00; // OKAY - end - - if(cpuif_wr_ack) begin - {{cpuif.signal("bvalid")}} <= '1; - if(cpuif_wr_err) {{cpuif.signal("bresp")}} <= 2'b10; // SLVERR - else {{cpuif.signal("bresp")}} <= 2'b00; // OKAY - end - end -end - -always_comb begin - axil_resp_acked = '0; - if({{cpuif.signal("rvalid")}} && {{cpuif.signal("rready")}}) axil_resp_acked = '1; - if({{cpuif.signal("bvalid")}} && {{cpuif.signal("bready")}}) axil_resp_acked = '1; -end - -{%- else %} -struct { - logic is_wr; - logic err; - logic [{{cpuif.data_width-1}}:0] rdata; -} axil_resp_buffer[{{roundup_pow2(cpuif.resp_buffer_size)}}]; -{%- if not is_pow2(cpuif.resp_buffer_size) %} -// axil_resp_buffer is intentionally padded to the next power of two despite -// only requiring {{cpuif.resp_buffer_size}} entries. -// This is to avoid quirks in some tools that cannot handle indexing into a non-power-of-2 array. -// Unused entries are expected to be optimized away -{% endif %} - -logic [{{clog2(cpuif.resp_buffer_size)}}:0] axil_resp_wptr; -logic [{{clog2(cpuif.resp_buffer_size)}}:0] axil_resp_rptr; - -always_ff {{get_always_ff_event(cpuif.reset)}} begin - if({{get_resetsignal(cpuif.reset)}}) begin - for(int i=0; i<{{cpuif.resp_buffer_size}}; i++) begin - axil_resp_buffer[i].is_wr <= '0; - axil_resp_buffer[i].err <= '0; - axil_resp_buffer[i].rdata <= '0; - end - axil_resp_wptr <= '0; - axil_resp_rptr <= '0; - end else begin - // Store responses in buffer until AXI response channel accepts them - if(cpuif_rd_ack || cpuif_wr_ack) begin - if(cpuif_rd_ack) begin - axil_resp_buffer[axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)-1}}:0]].is_wr <= '0; - axil_resp_buffer[axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)-1}}:0]].err <= cpuif_rd_err; - axil_resp_buffer[axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)-1}}:0]].rdata <= cpuif_rd_data; - - end else if(cpuif_wr_ack) begin - axil_resp_buffer[axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)-1}}:0]].is_wr <= '1; - axil_resp_buffer[axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)-1}}:0]].err <= cpuif_wr_err; - end - {%- if is_pow2(cpuif.resp_buffer_size) %} - axil_resp_wptr <= axil_resp_wptr + 1'b1; - {%- else %} - if(axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)-1}}:0] == {{cpuif.resp_buffer_size-1}}) begin - axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)-1}}:0] <= '0; - axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)}}] <= ~axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)}}]; - end else begin - axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)-1}}:0] <= axil_resp_wptr[{{clog2(cpuif.resp_buffer_size)-1}}:0] + 1'b1; - end - {%- endif %} - end - - // Advance read pointer when acknowledged - if(axil_resp_acked) begin - {%- if is_pow2(cpuif.resp_buffer_size) %} - axil_resp_rptr <= axil_resp_rptr + 1'b1; - {%- else %} - if(axil_resp_rptr[{{clog2(cpuif.resp_buffer_size)-1}}:0] == {{cpuif.resp_buffer_size-1}}) begin - axil_resp_rptr[{{clog2(cpuif.resp_buffer_size)-1}}:0] <= '0; - axil_resp_rptr[{{clog2(cpuif.resp_buffer_size)}}] <= ~axil_resp_rptr[{{clog2(cpuif.resp_buffer_size)}}]; - end else begin - axil_resp_rptr[{{clog2(cpuif.resp_buffer_size)-1}}:0] <= axil_resp_rptr[{{clog2(cpuif.resp_buffer_size)-1}}:0] + 1'b1; - end - {%- endif %} - end - end -end - -always_comb begin - axil_resp_acked = '0; - {{cpuif.signal("bvalid")}} = '0; - {{cpuif.signal("rvalid")}} = '0; - if(axil_resp_rptr != axil_resp_wptr) begin - if(axil_resp_buffer[axil_resp_rptr[{{clog2(cpuif.resp_buffer_size)-1}}:0]].is_wr) begin - {{cpuif.signal("bvalid")}} = '1; - if({{cpuif.signal("bready")}}) axil_resp_acked = '1; - end else begin - {{cpuif.signal("rvalid")}} = '1; - if({{cpuif.signal("rready")}}) axil_resp_acked = '1; - end - end - - {{cpuif.signal("rdata")}} = axil_resp_buffer[axil_resp_rptr[{{clog2(cpuif.resp_buffer_size)-1}}:0]].rdata; - if(axil_resp_buffer[axil_resp_rptr[{{clog2(cpuif.resp_buffer_size)-1}}:0]].err) begin - {{cpuif.signal("bresp")}} = 2'b10; - {{cpuif.signal("rresp")}} = 2'b10; - end else begin - {{cpuif.signal("bresp")}} = 2'b00; - {{cpuif.signal("rresp")}} = 2'b00; - end -end -{%- endif %} +//-------------------------------------------------------------------------- +// Fanin CPU Bus interface signals +//-------------------------------------------------------------------------- +{{fanin|walk(cpuif=cpuif)}} \ No newline at end of file