|
| 1 | +{%- if cpuif.is_interface -%} |
| 2 | +`ifndef SYNTHESIS |
| 3 | + initial begin |
| 4 | + assert_bad_addr_width: assert($bits({{cpuif.signal("addr")}}) >= {{ds.package_name}}::{{ds.module_name.upper()}}_MIN_ADDR_WIDTH) |
| 5 | + else $error("Interface address width of %0d is too small. Shall be at least %0d bits", $bits({{cpuif.signal("addr")}}), {{ds.package_name}}::{{ds.module_name.upper()}}_MIN_ADDR_WIDTH); |
| 6 | + assert_bad_data_width: assert($bits({{cpuif.signal("wdata")}}) == {{ds.package_name}}::{{ds.module_name.upper()}}_DATA_WIDTH) |
| 7 | + 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); |
| 8 | + end |
| 9 | +`endif |
| 10 | +{% endif -%} |
| 11 | + |
| 12 | +// OBI Interface Implementation |
| 13 | +// This register block acts as an OBI subordinate |
| 14 | + |
| 15 | +localparam int unsigned DATA_WIDTH = {{ds.package_name}}::{{ds.module_name.upper()}}_DATA_WIDTH; |
| 16 | +localparam int unsigned BYTES = DATA_WIDTH/8; |
| 17 | + |
| 18 | +// State & holding regs |
| 19 | +logic is_active; // A request is being served (not yet fully responded) |
| 20 | +logic gnt_q; // one-cycle grant for A-channel |
| 21 | +logic rsp_pending; // response ready but not yet accepted by manager |
| 22 | +logic [DATA_WIDTH-1:0] rsp_rdata_q; |
| 23 | +logic rsp_err_q; |
| 24 | +logic [$bits({{cpuif.signal("aid")}})-1:0] rid_q; |
| 25 | + |
| 26 | +// Latch AID on accept to echo back the response |
| 27 | +always_ff {{get_always_ff_event(cpuif.reset)}} begin |
| 28 | + if ({{get_resetsignal(cpuif.reset)}}) begin |
| 29 | + is_active <= 1'b0; |
| 30 | + gnt_q <= 1'b0; |
| 31 | + rsp_pending <= 1'b0; |
| 32 | + rsp_rdata_q <= '0; |
| 33 | + rsp_err_q <= 1'b0; |
| 34 | + rid_q <= '0; |
| 35 | + |
| 36 | + cpuif_req <= '0; |
| 37 | + cpuif_req_is_wr <= '0; |
| 38 | + cpuif_addr <= '0; |
| 39 | + cpuif_wr_data <= '0; |
| 40 | + cpuif_wr_biten <= '0; |
| 41 | + end else begin |
| 42 | + // defaults |
| 43 | + cpuif_req <= 1'b0; |
| 44 | + gnt_q <= {{cpuif.signal("req")}} & ~is_active; |
| 45 | + |
| 46 | + // Accept new request when idle |
| 47 | + if (~is_active) begin |
| 48 | + if ({{cpuif.signal("req")}}) begin |
| 49 | + is_active <= 1'b1; |
| 50 | + cpuif_req <= 1'b1; |
| 51 | + cpuif_req_is_wr <= {{cpuif.signal("we")}}; |
| 52 | + cpuif_addr <= {{cpuif.signal("addr")}}; |
| 53 | + cpuif_wr_data <= {{cpuif.signal("wdata")}}; |
| 54 | + rid_q <= {{cpuif.signal("aid")}}; |
| 55 | + for (int i = 0; i < BYTES; i++) begin |
| 56 | + cpuif_wr_biten[i*8 +: 8] <= {8{ {{cpuif.signal("be")}}[i] }}; |
| 57 | + end |
| 58 | + end |
| 59 | + end |
| 60 | + |
| 61 | + // Capture response |
| 62 | + if (is_active && (cpuif_rd_ack || cpuif_wr_ack)) begin |
| 63 | + rsp_pending <= 1'b1; |
| 64 | + rsp_rdata_q <= cpuif_rd_data; |
| 65 | + rsp_err_q <= cpuif_rd_err | cpuif_wr_err; |
| 66 | + // NOTE: Keep 'is_active' asserted until the external R handshake completes |
| 67 | + end |
| 68 | + |
| 69 | + // Complete external R-channel handshake only if manager ready |
| 70 | + if (rsp_pending && {{cpuif.signal("rvalid")}} && {{cpuif.signal("rready")}}) begin |
| 71 | + rsp_pending <= 1'b0; |
| 72 | + is_active <= 1'b0; // free to accept the next request |
| 73 | + end |
| 74 | + end |
| 75 | +end |
| 76 | + |
| 77 | +// R-channel outputs (held stable while rsp_pending=1) |
| 78 | +assign {{cpuif.signal("rvalid")}} = rsp_pending; |
| 79 | +assign {{cpuif.signal("rdata")}} = rsp_rdata_q; |
| 80 | +assign {{cpuif.signal("err")}} = rsp_err_q; |
| 81 | +assign {{cpuif.signal("rid")}} = rid_q; |
| 82 | + |
| 83 | +// A-channel grant (registered one-cycle pulse when we accept a request) |
| 84 | +assign {{cpuif.signal("gnt")}} = gnt_q; |
| 85 | + |
| 86 | +// If OBI config RReady is disabled, tie it high in the top-level/TB. |
| 87 | +// `ifndef SYNTHESIS |
| 88 | +// initial begin |
| 89 | +// if (0) $display("RReady supported; tie high if unused."); |
| 90 | +// end |
| 91 | +// `endif |
0 commit comments