// retroDE_ps2 — sif_dma_iop_ram_bridge_stub // // Width-adapting bridge from a 128-bit SIF DMA endpoint to the 32-bit // IOP memory map. Splits each incoming qword into four 32-bit writes at // consecutive physical addresses starting from DEST_BASE_ADDR. // // First real coupling between the SIF data-plane and the IOP side. NOT an // IOP, not a DMAC, not a peer — just a width/ordering adapter. // // Contract refs: // docs/contracts/sif.md (DMA-linked data movement endpoints) // docs/contracts/iop.md (IOP-local RAM/I/O decode; writes land // through the IOP memory map) // // Handshake (upstream, from DMAC ep_* port or equivalent): // in_valid / in_data[127:0] / in_last / in_ready // Bridge asserts in_ready only while idle. During the four-write // expansion of a qword, in_ready drops — natural backpressure onto // whatever's producing qwords. // // Handshake (downstream, to iop_memory_map_stub's bridge-write port): // bridge_wr_en / bridge_wr_addr[31:0] / bridge_wr_data[31:0] / // bridge_wr_be[3:0] / bridge_master_id[7:0] // Addresses are physical (no kseg stripping) — the IOP map must treat // this port's addresses differently from its CPU-side port. // // Data layout: // Little-endian unpacking: in_data[31:0] -> DEST_BASE+0 // in_data[63:32] -> DEST_BASE+4 // in_data[95:64] -> DEST_BASE+8 // in_data[127:96] -> DEST_BASE+12 // Subsequent qwords append: DEST_BASE+16, +20, +24, +28, ... // // Parameters: // DEST_BASE_ADDR — where the bridge starts writing. Persistent across // the life of the transfer; would become a register in // a later wave where software programs the target. // MASTER_ID — bridge's identity in MEM / IOP traces (default 3, // distinct from EE IFETCH=0, DMAC=1, IOP_CPU=2). // // Non-goals: // - multiple in-flight qwords // - ack back upstream beyond in_ready / in_last observation // - byte-enable variation per write (all writes are full 32-bit) // - arbitration against other masters on the map's write path `timescale 1ns/1ps module sif_dma_iop_ram_bridge_stub #( parameter logic [31:0] DEST_BASE_ADDR = 32'h0000_0000, parameter logic [7:0] MASTER_ID = 8'd3 ) ( input logic clk, input logic rst_n, // Upstream (DMAC endpoint side) input logic in_valid, input logic [127:0] in_data, input logic in_last, output logic in_ready, // Downstream (IOP map bridge-write port) output logic bridge_wr_en, output logic [31:0] bridge_wr_addr, output logic [31:0] bridge_wr_data, output logic [3:0] bridge_wr_be, output logic [7:0] bridge_master_id ); typedef enum logic [1:0] { S_IDLE = 2'd0, S_WRITE = 2'd1 } state_e; state_e state; logic [127:0] latched_qword; logic [1:0] beat_index; // 0..3 across the 4 writes logic [31:0] wr_offset; // running byte offset assign in_ready = (state == S_IDLE); assign bridge_master_id = MASTER_ID; logic accept_new_qword; assign accept_new_qword = in_valid && in_ready; // ------------------------------------------------------------------ // State machine // ------------------------------------------------------------------ always_ff @(posedge clk) begin if (!rst_n) begin state <= S_IDLE; latched_qword <= 128'd0; beat_index <= 2'd0; wr_offset <= 32'd0; end else begin unique case (state) S_IDLE: begin if (accept_new_qword) begin latched_qword <= in_data; beat_index <= 2'd0; state <= S_WRITE; end end S_WRITE: begin // Each cycle here drives one 32-bit write. After the // fourth, go idle. wr_offset advances per write. wr_offset <= wr_offset + 32'd4; if (beat_index == 2'd3) begin state <= S_IDLE; beat_index <= 2'd0; end else begin beat_index <= beat_index + 2'd1; end end default: state <= S_IDLE; endcase end end // ------------------------------------------------------------------ // Downstream write-port drive (combinational on state) // ------------------------------------------------------------------ // Indexed part-select picks the 32-bit slice for the current beat. // Avoids the constant-select-in-always_comb pattern that trips // portability warnings on some simulators. logic [31:0] beat_data; assign beat_data = latched_qword[beat_index*32 +: 32]; assign bridge_wr_en = (state == S_WRITE); assign bridge_wr_addr = DEST_BASE_ADDR + wr_offset; assign bridge_wr_data = beat_data; assign bridge_wr_be = 4'b1111; // full-word writes only endmodule : sif_dma_iop_ram_bridge_stub