// retroDE_ps2 — sif_dma_stub // // Minimal SIF DMA receive-side endpoint. First data-plane step on the SIF // seam. NOT an IOP — this is a bounded receive buffer that accepts qwords // from a DMAC channel and exposes them to the TB via a small read port. // No IOP CPU, no live peer logic, no directional policy beyond "incoming // qwords land in sequential slots." // // Contract refs: // docs/contracts/sif.md (DMA-linked data movement endpoints) // // Receive interface (connects to DMAC's ep_* endpoint): // in_valid / in_data / in_last / in_ready // One-cycle accept per beat when in_ready is high. in_last observed // alongside the final qword of a transfer. // // Read interface (TB-side verification): // rd_en pulses with rd_idx; rd_data / rd_valid return the stored qword // one cycle later. // // Stall input: // stall_in (level) forces in_ready low while asserted. Used by the // negative-path test to prove that a not-ready receiver does not let // the DMAC spuriously complete. // // Buffer: // Small internal array (DEPTH qwords). Full detection is tracked from // `rx_count`: once `rx_count >= DEPTH` the buffer is full and `in_ready` // drops so the DMAC stalls in ACTIVE_SEND. No silent wrap. There is no // consume path yet — once full, the buffer stays full (intentional for // the current scope). `full_o` is exposed for testbench observation. // // Trace: // One SIF EV_WRITE per accepted beat (one event per cycle). // arg0 = slot index into the receive buffer // arg1 = data[63:0] (low half) // arg2 = source id (hard-wired to 8'd1 = DMAC for Wave 3) // arg3 = 0 // flags bit 0 = in_last value for this beat // flags bit 1 = 1 (distinguishes DMA-receive writes from mailbox writes // if both subsystems are ever instantiated together) `timescale 1ns/1ps module sif_dma_stub import trace_pkg::*; #( parameter int DEPTH = 8 // max qwords buffered ) ( input logic clk, input logic rst_n, // DMAC-facing receive input logic in_valid, input logic [127:0] in_data, input logic in_last, output logic in_ready, // TB verification read port input logic rd_en, input logic [$clog2(DEPTH)-1:0] rd_idx, output logic [127:0] rd_data, output logic rd_valid, // Negative-path control input logic stall_in, // Status output logic [31:0] rx_count, // monotonic accepted-beat count output logic last_seen, // sticky: in_last observed output logic full_o, // buffer full, in_ready=0 // Trace output logic ev_valid, output subsys_e ev_subsys, output event_e ev_event, output logic [63:0] ev_arg0, output logic [63:0] ev_arg1, output logic [63:0] ev_arg2, output logic [63:0] ev_arg3, output logic [31:0] ev_flags ); localparam int IDX_W = $clog2(DEPTH); logic [127:0] buf_mem [0:DEPTH-1]; logic [IDX_W-1:0] wr_ptr; logic beat_accepted; assign full_o = (rx_count >= DEPTH); assign in_ready = !stall_in && !full_o; assign beat_accepted = in_valid && in_ready; // ------------------------------------------------------------------ // Receive path // ------------------------------------------------------------------ always_ff @(posedge clk) begin if (!rst_n) begin wr_ptr <= '0; rx_count <= 32'd0; last_seen <= 1'b0; for (int i = 0; i < DEPTH; i++) buf_mem[i] <= 128'd0; end else if (beat_accepted) begin buf_mem[wr_ptr] <= in_data; wr_ptr <= wr_ptr + IDX_W'(1); rx_count <= rx_count + 32'd1; if (in_last) last_seen <= 1'b1; end end // ------------------------------------------------------------------ // Read port (1-cycle latency) // ------------------------------------------------------------------ always_ff @(posedge clk) begin if (!rst_n) begin rd_data <= 128'd0; rd_valid <= 1'b0; end else begin rd_valid <= rd_en; if (rd_en) rd_data <= buf_mem[rd_idx]; end end // ------------------------------------------------------------------ // Trace — one event per accepted beat // ------------------------------------------------------------------ always_ff @(posedge clk) begin if (!rst_n) begin ev_valid <= 1'b0; ev_subsys <= SUBSYS_SIF; ev_event <= EV_WRITE; ev_arg0 <= 64'd0; ev_arg1 <= 64'd0; ev_arg2 <= 64'd0; ev_arg3 <= 64'd0; ev_flags <= 32'd0; end else if (beat_accepted) begin ev_valid <= 1'b1; ev_subsys <= SUBSYS_SIF; ev_event <= EV_WRITE; ev_arg0 <= {{(64-IDX_W){1'b0}}, wr_ptr}; ev_arg1 <= in_data[63:0]; ev_arg2 <= 64'd1; // DMAC ev_arg3 <= 64'd0; ev_flags <= {30'd0, 1'b1, in_last}; // bit1=DMA, bit0=in_last end else begin ev_valid <= 1'b0; end end endmodule : sif_dma_stub