ec82764bef
RTL (GS rasterizer, EE core stub, platform bridge, LPDDR4B path), sim regression (272 TBs), docs, and tooling. Copyrighted PS2 content (BIOS, game code, GS dumps, and all dump-derived textures/traces) is excluded via .gitignore and stays local. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
155 lines
5.2 KiB
Systemverilog
155 lines
5.2 KiB
Systemverilog
// 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
|