Files
retroDE_ps2/rtl/dmac/ee_dmac_passive_chan_stub.sv
thejayman77 ec82764bef Initial commit: retroDE_ps2 — first-of-its-kind PS2 GS FPGA core (DE25-Nano / Agilex 5)
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>
2026-06-29 20:10:50 -04:00

182 lines
6.8 KiB
Systemverilog
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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