// retroDE_ps2 — ee_dmac_passive_chan_stub // // Ch288 — Lightweight per-channel register surface for the EE DMAC // channels NOT covered by a dedicated transfer-FSM stub. Hosts the // four standard per-channel registers (CHCR/MADR/QWC/TADR) for each // covered channel; reset to zero, writes latch, reads return the // latched value. NO transfer FSM, NO start-bit side effects, NO // D_STAT interaction. This is the "init-time channel-clear / quiet // register surface" Codex framed for Ch288. // // Channels covered (4 KiB window each, starting at 0x1000_8000): // ch0 (VIF0) 0x1000_8000-0x1000_8FFF // ch1 (VIF1) 0x1000_9000-0x1000_9FFF // ch3 (IPU_FROM) 0x1000_B000-0x1000_BFFF // ch4 (IPU_TO) 0x1000_C000-0x1000_CFFF ← qbert's first hit // ch5 (SIF0) 0x1000_D000-0x1000_DFFF // // SKIPPED: // ch2 (GIF) 0x1000_A000-0x1000_AFFF — already routed // externally to dmac_reg_stub via the map's // ee_dmac_ch2_* ports. Do NOT shadow it here. // // Channel index extracted from chan_addr[15:12]: // 0x8 → ch0, 0x9 → ch1, 0xB → ch3, 0xC → ch4, 0xD → ch5 // (0xA / ch2 is filtered by the caller; if chan_addr[15:12]==0xA // arrives here the module silently drops it.) // // Register offsets (chan_addr[11:0], matches dmac_reg_stub layout): // 0x00 CHCR — control (start bit at [0]); latched, no FSM // 0x10 MADR — main address // 0x20 QWC — quadword count // 0x30 TADR — tag address // any other offset: read = 0, write dropped + traced `timescale 1ns/1ps module ee_dmac_passive_chan_stub import trace_pkg::*; ( input logic clk, input logic rst_n, // Write port. chan_addr is the 16-bit offset into the entire // 0x1000_8000-base window: chan_addr[15:12] = channel selector, // chan_addr[11:0] = register offset within that channel. input logic reg_wr_en, input logic [15:0] chan_addr, input logic [31:0] reg_wr_data, // Read port (1-cycle latency). input logic reg_rd_en, output logic [31:0] reg_rd_data, output logic reg_rd_valid, // 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 logic [11:0] CHCR_OFFSET = 12'h000; localparam logic [11:0] MADR_OFFSET = 12'h010; localparam logic [11:0] QWC_OFFSET = 12'h020; localparam logic [11:0] TADR_OFFSET = 12'h030; // Channel index from the high nibble of chan_addr. Out-of-range // nibbles (anything outside 0x8/0x9/0xB/0xC/0xD) get // chan_valid=0 and the access is dropped. logic [3:0] chan_nibble; logic [2:0] chan_idx; // 0..4 packed: 0=ch0, 1=ch1, 2=ch3, 3=ch4, 4=ch5 logic chan_valid; always_comb begin chan_nibble = chan_addr[15:12]; chan_idx = 3'd0; chan_valid = 1'b0; unique case (chan_nibble) 4'h8: begin chan_idx = 3'd0; chan_valid = 1'b1; end // ch0 4'h9: begin chan_idx = 3'd1; chan_valid = 1'b1; end // ch1 4'hB: begin chan_idx = 3'd2; chan_valid = 1'b1; end // ch3 4'hC: begin chan_idx = 3'd3; chan_valid = 1'b1; end // ch4 4'hD: begin chan_idx = 3'd4; chan_valid = 1'b1; end // ch5 default: ; endcase end logic [11:0] reg_offset; assign reg_offset = chan_addr[11:0]; // ------------------------------------------------------------------ // Register file: 5 channels × 4 registers // ------------------------------------------------------------------ logic [31:0] chcr [0:4]; logic [31:0] madr [0:4]; logic [31:0] qwc [0:4]; logic [31:0] tadr [0:4]; always_ff @(posedge clk) begin if (!rst_n) begin for (int i = 0; i < 5; i++) begin chcr[i] <= 32'd0; madr[i] <= 32'd0; qwc[i] <= 32'd0; tadr[i] <= 32'd0; end end else if (reg_wr_en && chan_valid) begin unique case (reg_offset) CHCR_OFFSET: chcr[chan_idx] <= reg_wr_data; MADR_OFFSET: madr[chan_idx] <= reg_wr_data; QWC_OFFSET: qwc[chan_idx] <= reg_wr_data; TADR_OFFSET: tadr[chan_idx] <= reg_wr_data; default: ; endcase end end // Read mux (1-cycle latency). Returns 0 for invalid channel / // unknown offset. always_ff @(posedge clk) begin if (!rst_n) begin reg_rd_data <= 32'd0; reg_rd_valid <= 1'b0; end else begin reg_rd_valid <= reg_rd_en; if (reg_rd_en && chan_valid) begin unique case (reg_offset) CHCR_OFFSET: reg_rd_data <= chcr[chan_idx]; MADR_OFFSET: reg_rd_data <= madr[chan_idx]; QWC_OFFSET: reg_rd_data <= qwc[chan_idx]; TADR_OFFSET: reg_rd_data <= tadr[chan_idx]; default: reg_rd_data <= 32'd0; endcase end else if (reg_rd_en) begin reg_rd_data <= 32'd0; // invalid channel end end end // ------------------------------------------------------------------ // Trace — write priority over read; tagged SUBSYS_DMAC with // arg0 = chan_nibble (0x8/0x9/0xB/0xC/0xD = phys channel), arg1 // = data, arg2 = reg_offset, arg3 = chan_idx (packed 0..4). // ------------------------------------------------------------------ always_ff @(posedge clk) begin if (!rst_n) begin ev_valid <= 1'b0; ev_subsys <= SUBSYS_DMAC; 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 (reg_wr_en) begin ev_valid <= 1'b1; ev_subsys <= SUBSYS_DMAC; ev_event <= EV_WRITE; ev_arg0 <= {60'd0, chan_nibble}; ev_arg1 <= {32'd0, reg_wr_data}; ev_arg2 <= {52'd0, reg_offset}; ev_arg3 <= {61'd0, chan_idx}; ev_flags <= {31'd0, chan_valid}; end else if (reg_rd_en) begin ev_valid <= 1'b1; ev_subsys <= SUBSYS_DMAC; ev_event <= EV_READ; ev_arg0 <= {60'd0, chan_nibble}; ev_arg1 <= 64'd0; ev_arg2 <= {52'd0, reg_offset}; ev_arg3 <= {61'd0, chan_idx}; ev_flags <= {31'd0, chan_valid}; end else begin ev_valid <= 1'b0; end end endmodule : ee_dmac_passive_chan_stub