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>
489 lines
20 KiB
Systemverilog
489 lines
20 KiB
Systemverilog
// retroDE_ps2 — tb_bridge_iop_pad_input (Ch235)
|
|
// ============================================================================
|
|
// First end-to-end integration TB for the HPS → bridge → IOP-fabric
|
|
// input path. Wires `ps2_hps_bridge` (Ch222 INPUT_P1/P2 store) into
|
|
// `iop_memory_map_stub` (Ch234 sio2_input_stub region) across two
|
|
// distinct clocks so the bridge-clk → IOP-clk CDC is exercised end-to-end:
|
|
//
|
|
// HPS AXI write @ 0x040 (INPUT_P1) →
|
|
// ps2_hps_bridge.input_p1_q latch (bclk @ 100 MHz) →
|
|
// ps2_hps_bridge.input_p1_o output →
|
|
// iop_memory_map_stub.input_p1 →
|
|
// u_sio2_input.input_p1 →
|
|
// 2-FF sync into iclk @ 33 MHz →
|
|
// PAD_P1_STATE readable at IOP phys 0x1F80_8500
|
|
//
|
|
// Verifies:
|
|
// §1. Reset: IOP-side PAD_P1/P2 = 0xFFFF, PAD_STATUS = 1.
|
|
// §2. AXI write INPUT_P1 single bit → after CDC latency, IOP read
|
|
// shows the corresponding Sony bit cleared.
|
|
// §3. AXI write INPUT_P2 with a different pattern → P1 unchanged,
|
|
// P2 reflects new state (independence).
|
|
// §4. Multi-bit AXI write → IOP sees the matching combo word.
|
|
// §5. AXI clear → IOP reads back to 0xFFFF.
|
|
// §6. Bridge reset cycle → IOP sees 0xFFFF (Ch222 latches clear),
|
|
// even if iclk reset stays asserted.
|
|
// ============================================================================
|
|
|
|
`timescale 1ns/1ps
|
|
|
|
module tb_bridge_iop_pad_input;
|
|
|
|
// ------------------------------------------------------------------
|
|
// Two clocks — bridge on bclk @ 100 MHz, IOP on iclk @ 33 MHz.
|
|
// Different periods deliberately exercise the bclk → iclk CDC.
|
|
// ------------------------------------------------------------------
|
|
logic bclk;
|
|
logic iclk;
|
|
initial bclk = 1'b0;
|
|
initial iclk = 1'b0;
|
|
always #5 bclk = ~bclk; // 100 MHz
|
|
always #15 iclk = ~iclk; // 33 MHz
|
|
|
|
logic breset_n;
|
|
logic ireset_n;
|
|
|
|
// ------------------------------------------------------------------
|
|
// Bridge status inputs (tied LOW — we don't exercise CORE_STATUS).
|
|
// ------------------------------------------------------------------
|
|
logic core_halt;
|
|
logic dma_done_seen;
|
|
logic frame_seen;
|
|
logic hdmi_init_done;
|
|
logic hdmi_i2c_error;
|
|
logic raster_overflow;
|
|
logic frame_toggle;
|
|
logic dma_done_toggle;
|
|
|
|
// ------------------------------------------------------------------
|
|
// Bridge AXI slave (TB drives master).
|
|
// ------------------------------------------------------------------
|
|
logic [3:0] s_axi_awid;
|
|
logic [37:0] s_axi_awaddr;
|
|
logic [7:0] s_axi_awlen;
|
|
logic [2:0] s_axi_awsize;
|
|
logic [1:0] s_axi_awburst;
|
|
logic s_axi_awlock;
|
|
logic [3:0] s_axi_awcache;
|
|
logic [2:0] s_axi_awprot;
|
|
logic s_axi_awvalid;
|
|
logic s_axi_awready;
|
|
logic [127:0] s_axi_wdata;
|
|
logic [15:0] s_axi_wstrb;
|
|
logic s_axi_wlast;
|
|
logic s_axi_wvalid;
|
|
logic s_axi_wready;
|
|
logic [3:0] s_axi_bid;
|
|
logic [1:0] s_axi_bresp;
|
|
logic s_axi_bvalid;
|
|
logic s_axi_bready;
|
|
logic [3:0] s_axi_arid;
|
|
logic [37:0] s_axi_araddr;
|
|
logic [7:0] s_axi_arlen;
|
|
logic [2:0] s_axi_arsize;
|
|
logic [1:0] s_axi_arburst;
|
|
logic s_axi_arlock;
|
|
logic [3:0] s_axi_arcache;
|
|
logic [2:0] s_axi_arprot;
|
|
logic s_axi_arvalid;
|
|
logic s_axi_arready;
|
|
logic [3:0] s_axi_rid;
|
|
logic [127:0] s_axi_rdata;
|
|
logic [1:0] s_axi_rresp;
|
|
logic s_axi_rlast;
|
|
logic s_axi_rvalid;
|
|
logic s_axi_rready;
|
|
|
|
// ------------------------------------------------------------------
|
|
// Bridge outputs we ignore (Ch176/Ch229/Ch230).
|
|
// ------------------------------------------------------------------
|
|
logic core_reset_req;
|
|
logic tile_wr_toggle;
|
|
logic [9:0] tile_wr_index;
|
|
logic [31:0] tile_wr_data;
|
|
// Ch245 — platform OSD register-surface ports (unused by this
|
|
// integration TB; declared so the `.*` wildcard binds them).
|
|
wire [31:0] osd_ctrl_o;
|
|
wire [31:0] osd_cfg0_o;
|
|
wire [31:0] osd_cfg1_o;
|
|
logic osd_active_i = 1'b0;
|
|
logic [4:0] osd_cursor_row_i = 5'd0;
|
|
logic osd_set_trigger_i = 1'b0;
|
|
logic osd_back_trigger_i = 1'b0;
|
|
logic osd_scroll_down_trigger_i = 1'b0;
|
|
logic osd_scroll_up_trigger_i = 1'b0;
|
|
logic osd_open_trigger_i = 1'b0;
|
|
logic [4:0] osd_trigger_row_i = 5'd0;
|
|
|
|
// Ch248 DS2 wired-controller inputs (unused by this TB; tied
|
|
// unplugged so the bridge's DS2_STATUS reads as such).
|
|
logic [31:0] ds2_buttons_i = 32'd0;
|
|
logic ds2_connected_i = 1'b0;
|
|
logic ds2_error_i = 1'b0;
|
|
|
|
// ------------------------------------------------------------------
|
|
// The new Ch235 broadcast — bridge → IOP map.
|
|
// ------------------------------------------------------------------
|
|
wire [31:0] bridge_input_p1;
|
|
wire [31:0] bridge_input_p2;
|
|
|
|
// ------------------------------------------------------------------
|
|
// ps2_hps_bridge instance.
|
|
// ------------------------------------------------------------------
|
|
// Ch318 — LPDDR test ports (this TB doesn't exercise them; nets exist so the
|
|
// bridge's .* connects, status inputs tied safe).
|
|
logic lpddr_arm_o, lpddr_canary_o;
|
|
logic lpddr_ctrl_commit_o;
|
|
logic [31:0] lpddr_fb_base_o;
|
|
logic [31:0] lpddr_bytes_i = 32'd0, lpddr_bursts_i = 32'd0, lpddr_bresp_err_i = 32'd0, lpddr_fifo_ovf_i = 32'd0;
|
|
logic lpddr_idle_i = 1'b1;
|
|
// Ch319 — read-probe nets (tie inputs safe; .* binds them).
|
|
logic [31:0] lpddr_rd_addr_o; logic lpddr_rd_pulse_o;
|
|
logic [31:0] lpddr_rd_data_i = 32'd0; logic lpddr_rd_done_i = 1'b0;
|
|
logic lpddr_video_src_o;
|
|
logic lpddr_scanout_lb_o;
|
|
logic lpddr_scan_valid_i = 1'b0, lpddr_scan_err_i = 1'b0;
|
|
// Ch322 — write-probe + texture-cache fill nets (matched by the .* below).
|
|
logic [31:0] lpddr_wr_addr_o, lpddr_wr_data_o; logic lpddr_wr_pulse_o;
|
|
logic lpddr_wr_busy_i = 1'b0, lpddr_wr_done_i = 1'b0; logic [31:0] lpddr_wr_bresp_err_i = 32'd0;
|
|
logic tex_fill_start_o, tex_fill_done_i = 1'b0;
|
|
logic [31:0] tex_fill_beats_i = 32'd0, tex_fill_bytes_i = 32'd0, tex_rd_errs_i = 32'd0, tex_fill_crc_i = 32'd0;
|
|
logic [31:0] tex_cache_hits_i = 32'd0, tex_bram_hits_i = 32'd0;
|
|
// Ch323 — tile COLOR+Z spill/reload counters (unused here; 0 so the .* connect resolves).
|
|
logic [31:0] spill_color_beats_i = 32'd0, spill_z_beats_i = 32'd0;
|
|
logic [31:0] reload_color_beats_i = 32'd0, reload_z_beats_i = 32'd0;
|
|
logic [31:0] reload_rd_errs_i = 32'd0, spill_color_errs_i = 32'd0, spill_z_errs_i = 32'd0;
|
|
logic spill_color_ovf_i = 1'b0, spill_z_ovf_i = 1'b0;
|
|
logic [1:0] diag_ctrl_o; // Ch323 diag DIAG_CTRL output
|
|
logic [31:0] color_spill_awaddr_i=0, color_spill_wdata0_i=0;
|
|
logic [31:0] dbg_c_first_awaddr_i=0, dbg_c_first_wdata0_i=0, dbg_c_first_wstrb_i=0, dbg_c_last_wstrb_i=0, dbg_c_beat_count_i=0;
|
|
logic [31:0] dbg_c_emit_count_i=0, dbg_c_push_count_i=0, dbg_c_pop_count_i=0; // Ch323 pipeline-split (.* tie-off)
|
|
logic [31:0] dbg_z_beat_count_i=0, dbg_z_emit_count_i=0, dbg_z_push_count_i=0, dbg_z_pop_count_i=0; // Ch324 (.* tie-off)
|
|
logic [31:0] dbg_m_first_awaddr_i=0, dbg_m_first_wdata0_i=0, dbg_m_first_wstrb_i=0;
|
|
logic [31:0] ev_tp_flush_i=0, ev_tp_zflush_i=0, ev_tp_reload_i=0, ev_tp_render_i=0;
|
|
logic [31:0] ev_flush_emit_i=0, ev_zflush_emit_i=0, ev_reload_start_i=0, ev_reload_ready_i=0;
|
|
// Ch330 Brick 4 — feeder control ports (.* tie-off; this TB doesn't exercise the feeder).
|
|
logic feeder_stg_we_tgl_o, feeder_go_tgl_o;
|
|
logic [11:0] feeder_stg_waddr_o;
|
|
logic [63:0] feeder_stg_wdata_o;
|
|
logic feeder_ready_i = 1'b0;
|
|
logic [15:0] feeder_records_i = 16'd0;
|
|
logic [31:0] feeder_waits_i = 32'd0;
|
|
ps2_hps_bridge u_bridge (
|
|
.clk (bclk),
|
|
.reset_n (breset_n),
|
|
.h2f_reset (1'b0),
|
|
.core_halt (core_halt),
|
|
.dma_done_seen (dma_done_seen),
|
|
.frame_seen (frame_seen),
|
|
.hdmi_init_done (hdmi_init_done),
|
|
.hdmi_i2c_error (hdmi_i2c_error),
|
|
.raster_overflow(raster_overflow),
|
|
.frame_toggle (frame_toggle),
|
|
.dma_done_toggle(dma_done_toggle),
|
|
.core_reset_req (core_reset_req),
|
|
.tile_wr_toggle (tile_wr_toggle),
|
|
.tile_wr_index (tile_wr_index),
|
|
.tile_wr_data (tile_wr_data),
|
|
.input_p1_o (bridge_input_p1),
|
|
.input_p2_o (bridge_input_p2),
|
|
.input_p1_raw_o (),
|
|
.* // AXI signals
|
|
);
|
|
|
|
// ------------------------------------------------------------------
|
|
// IOP map signals (TB drives the CPU-side read; all other ports
|
|
// tied off since we only care about the pad path).
|
|
// ------------------------------------------------------------------
|
|
logic iop_rd_en;
|
|
logic [31:0] iop_rd_addr;
|
|
wire [31:0] iop_rd_data;
|
|
wire iop_rd_valid;
|
|
logic [7:0] iop_master_id;
|
|
|
|
// Trace outputs (ignored).
|
|
wire tr_valid;
|
|
wire [3:0] tr_subsys;
|
|
wire [3:0] tr_event;
|
|
wire [63:0] tr_arg0, tr_arg1, tr_arg2, tr_arg3;
|
|
wire [31:0] tr_flags;
|
|
|
|
iop_memory_map_stub u_map (
|
|
.clk(iclk), .rst_n(ireset_n),
|
|
|
|
// CPU side — TB drives reads only.
|
|
.iop_rd_en(iop_rd_en), .iop_rd_addr(iop_rd_addr),
|
|
.iop_rd_data(iop_rd_data), .iop_rd_valid(iop_rd_valid),
|
|
.iop_wr_en(1'b0), .iop_wr_addr(32'd0),
|
|
.iop_wr_data(32'd0), .iop_wr_be(4'd0),
|
|
.master_id(iop_master_id),
|
|
|
|
// Bridge-side write port — unused by this TB.
|
|
.bridge_wr_en(1'b0), .bridge_wr_addr(32'd0),
|
|
.bridge_wr_data(32'd0), .bridge_wr_be(4'd0),
|
|
.bridge_master_id(8'd0),
|
|
|
|
// DMA-side read port — unused.
|
|
.dma_rd_en(1'b0), .dma_rd_addr(32'd0),
|
|
.dma_master_id(8'd0),
|
|
.dma_rd_data(), .dma_rd_valid(),
|
|
|
|
// RAM port — tied off; CPU reads of RAM aren't exercised.
|
|
.ram_rd_en(), .ram_rd_addr(),
|
|
.ram_rd_data(32'd0), .ram_rd_valid(1'b0),
|
|
.ram_wr_en(), .ram_wr_addr(),
|
|
.ram_wr_data(), .ram_wr_be(),
|
|
.ram_master_id(),
|
|
|
|
// SIF port — tied off.
|
|
.sif_rd_en(), .sif_rd_addr(),
|
|
.sif_rd_data(32'd0), .sif_rd_valid(1'b0),
|
|
.sif_wr_en(), .sif_wr_addr(), .sif_wr_data(),
|
|
|
|
// IOP DMAC port — tied off.
|
|
.iop_dmac_rd_en(), .iop_dmac_rd_addr(),
|
|
.iop_dmac_rd_data(32'd0), .iop_dmac_rd_valid(1'b0),
|
|
.iop_dmac_wr_en(), .iop_dmac_wr_addr(), .iop_dmac_wr_data(),
|
|
|
|
// IOP INTC port — tied off.
|
|
.iop_intc_rd_en(), .iop_intc_rd_addr(),
|
|
.iop_intc_rd_data(32'd0), .iop_intc_rd_valid(1'b0),
|
|
.iop_intc_wr_en(), .iop_intc_wr_addr(), .iop_intc_wr_data(),
|
|
|
|
// Ch235 — bridge → IOP wiring (the whole point of this TB).
|
|
.input_p1(bridge_input_p1),
|
|
.input_p2(bridge_input_p2),
|
|
|
|
// BIOS port — tied off.
|
|
.bios_rd_en(), .bios_rd_addr(),
|
|
.bios_rd_data(32'd0), .bios_rd_valid(1'b0),
|
|
|
|
// Trace outputs.
|
|
.ev_valid(tr_valid), .ev_subsys(tr_subsys), .ev_event(tr_event),
|
|
.ev_arg0(tr_arg0), .ev_arg1(tr_arg1),
|
|
.ev_arg2(tr_arg2), .ev_arg3(tr_arg3),
|
|
.ev_flags(tr_flags)
|
|
);
|
|
|
|
int errors;
|
|
|
|
task automatic check_eq(input string label,
|
|
input logic [31:0] got,
|
|
input logic [31:0] expected);
|
|
if (got !== expected) begin
|
|
$error("[%s] got 0x%08x expected 0x%08x", label, got, expected);
|
|
errors = errors + 1;
|
|
end
|
|
endtask
|
|
|
|
// ------------------------------------------------------------------
|
|
// AXI master tasks (mirror tb_ps2_hps_bridge.sv).
|
|
// ------------------------------------------------------------------
|
|
task automatic axi_write32(input logic [37:0] addr,
|
|
input logic [31:0] data);
|
|
@(posedge bclk);
|
|
s_axi_awid <= 4'd0;
|
|
s_axi_awaddr <= addr;
|
|
s_axi_awlen <= 8'd0;
|
|
s_axi_awsize <= 3'd2;
|
|
s_axi_awburst <= 2'b01;
|
|
s_axi_awlock <= 1'b0;
|
|
s_axi_awcache <= 4'd0;
|
|
s_axi_awprot <= 3'd0;
|
|
s_axi_awvalid <= 1'b1;
|
|
case (addr[3:2])
|
|
2'b00: s_axi_wdata <= {96'd0, data};
|
|
2'b01: s_axi_wdata <= {64'd0, data, 32'd0};
|
|
2'b10: s_axi_wdata <= {32'd0, data, 64'd0};
|
|
default: s_axi_wdata <= {data, 96'd0};
|
|
endcase
|
|
s_axi_wstrb <= 16'h000F << ({addr[3:2], 2'b00});
|
|
s_axi_wlast <= 1'b1;
|
|
s_axi_wvalid <= 1'b1;
|
|
s_axi_bready <= 1'b1;
|
|
wait (s_axi_awready);
|
|
@(posedge bclk);
|
|
s_axi_awvalid <= 1'b0;
|
|
wait (s_axi_wready);
|
|
@(posedge bclk);
|
|
s_axi_wvalid <= 1'b0;
|
|
wait (s_axi_bvalid);
|
|
@(posedge bclk);
|
|
s_axi_bready <= 1'b0;
|
|
endtask
|
|
|
|
// ------------------------------------------------------------------
|
|
// IOP read helper. Follows the existing tb_iop_memory_map_stub
|
|
// pattern: drive on @(negedge iclk) with BLOCKING assigns so the
|
|
// address is stable through the next posedge that registers
|
|
// rd_pending. Sample iop_rd_data on the following negedge — by
|
|
// then the map's read response (and the stub's pad_rd_data) have
|
|
// both been registered, and iop_rd_valid is HIGH for one cycle.
|
|
// ------------------------------------------------------------------
|
|
task automatic iop_read32(input logic [31:0] addr,
|
|
output logic [31:0] data);
|
|
@(negedge iclk);
|
|
iop_rd_en = 1'b1;
|
|
iop_rd_addr = addr;
|
|
@(negedge iclk);
|
|
iop_rd_en = 1'b0;
|
|
iop_rd_addr = 32'd0;
|
|
data = iop_rd_data;
|
|
if (iop_rd_valid !== 1'b1) begin
|
|
$error("[iop_read32] iop_rd_valid not high at sample (addr=0x%08x)", addr);
|
|
errors = errors + 1;
|
|
end
|
|
endtask
|
|
|
|
// ------------------------------------------------------------------
|
|
// Sony pad-word expected-value helper (mirrors sio2_input_stub).
|
|
// ------------------------------------------------------------------
|
|
function automatic logic [15:0] expected_sony(input logic [31:0] joy);
|
|
logic [7:0] b3, b4;
|
|
b3 = ~{joy[1], joy[2], joy[0], joy[3], joy[4], joy[15], joy[14], joy[5]};
|
|
b4 = ~{joy[8], joy[7], joy[9], joy[6], joy[11], joy[10], joy[13], joy[12]};
|
|
expected_sony = {b4, b3};
|
|
endfunction
|
|
|
|
// ------------------------------------------------------------------
|
|
// Wait long enough for an AXI-written value to propagate through
|
|
// the bridge latch + the 2-FF sync inside sio2_input_stub.
|
|
// Conservative — 20 iclk cycles is many sync windows.
|
|
// ------------------------------------------------------------------
|
|
task automatic settle_cdc();
|
|
repeat (20) @(posedge iclk);
|
|
endtask
|
|
|
|
logic [31:0] rd;
|
|
|
|
localparam logic [31:0] PAD_P1_ADDR = 32'h1F80_8500;
|
|
localparam logic [31:0] PAD_P2_ADDR = 32'h1F80_8504;
|
|
localparam logic [31:0] PAD_ST_ADDR = 32'h1F80_8508;
|
|
|
|
initial begin
|
|
errors = 0;
|
|
breset_n = 1'b0;
|
|
ireset_n = 1'b0;
|
|
|
|
// AXI defaults.
|
|
s_axi_arvalid = 1'b0;
|
|
s_axi_awvalid = 1'b0;
|
|
s_axi_wvalid = 1'b0;
|
|
s_axi_rready = 1'b0;
|
|
s_axi_bready = 1'b0;
|
|
|
|
// Bridge status (all LOW — we don't exercise CORE_STATUS).
|
|
core_halt = 1'b0;
|
|
dma_done_seen = 1'b0;
|
|
frame_seen = 1'b0;
|
|
hdmi_init_done = 1'b0;
|
|
hdmi_i2c_error = 1'b0;
|
|
raster_overflow = 1'b0;
|
|
frame_toggle = 1'b0;
|
|
dma_done_toggle = 1'b0;
|
|
|
|
// IOP-side defaults.
|
|
iop_rd_en = 1'b0;
|
|
iop_rd_addr = 32'd0;
|
|
iop_master_id = 8'd0;
|
|
|
|
repeat (4) @(posedge bclk);
|
|
@(posedge iclk);
|
|
breset_n = 1'b1;
|
|
ireset_n = 1'b1;
|
|
// Settle both domains.
|
|
repeat (8) @(posedge bclk);
|
|
repeat (8) @(posedge iclk);
|
|
|
|
// ----------------------------------------------------------
|
|
// §1. Reset state — bridge latches at 0 → Sony word 0xFFFF.
|
|
// PAD_STATUS = 1.
|
|
// ----------------------------------------------------------
|
|
iop_read32(PAD_P1_ADDR, rd); check_eq("rst_P1", rd, 32'h0000_FFFF);
|
|
iop_read32(PAD_P2_ADDR, rd); check_eq("rst_P2", rd, 32'h0000_FFFF);
|
|
iop_read32(PAD_ST_ADDR, rd); check_eq("rst_ST", rd, 32'h0000_0001);
|
|
|
|
// ----------------------------------------------------------
|
|
// §2. AXI write JOY_RIGHT (bit 0) into INPUT_P1 @ 0x040.
|
|
// After CDC settle, IOP-side P1 has byte3.5 (RIGHT)
|
|
// cleared.
|
|
// ----------------------------------------------------------
|
|
axi_write32(38'h040, 32'h0000_0001);
|
|
settle_cdc();
|
|
iop_read32(PAD_P1_ADDR, rd);
|
|
check_eq("P1_RIGHT_only",
|
|
rd, {16'd0, expected_sony(32'h0000_0001)});
|
|
// P2 unchanged.
|
|
iop_read32(PAD_P2_ADDR, rd);
|
|
check_eq("P2_unaffected_by_P1_write", rd, 32'h0000_FFFF);
|
|
|
|
// ----------------------------------------------------------
|
|
// §3. AXI write a different pattern into INPUT_P2 @ 0x044
|
|
// (JOY_DOWN | JOY_A = bits 2 | 9). P1 retains its
|
|
// previous state.
|
|
// ----------------------------------------------------------
|
|
axi_write32(38'h044, 32'h0000_0204);
|
|
settle_cdc();
|
|
iop_read32(PAD_P2_ADDR, rd);
|
|
check_eq("P2_DOWN_A",
|
|
rd, {16'd0, expected_sony(32'h0000_0204)});
|
|
iop_read32(PAD_P1_ADDR, rd);
|
|
check_eq("P1_persist_after_P2_write",
|
|
rd, {16'd0, expected_sony(32'h0000_0001)});
|
|
|
|
// ----------------------------------------------------------
|
|
// §4. Multi-bit combo. All D-pad + START + SELECT pressed
|
|
// on P1 (bits 0..5).
|
|
// ----------------------------------------------------------
|
|
axi_write32(38'h040, 32'h0000_003F);
|
|
settle_cdc();
|
|
iop_read32(PAD_P1_ADDR, rd);
|
|
check_eq("P1_dpad_start_sel_combo",
|
|
rd, {16'd0, expected_sony(32'h0000_003F)});
|
|
|
|
// ----------------------------------------------------------
|
|
// §5. AXI clear INPUT_P1 → IOP reads back to 0xFFFF.
|
|
// INPUT_P2 unchanged.
|
|
// ----------------------------------------------------------
|
|
axi_write32(38'h040, 32'h0000_0000);
|
|
settle_cdc();
|
|
iop_read32(PAD_P1_ADDR, rd);
|
|
check_eq("P1_cleared", rd, 32'h0000_FFFF);
|
|
iop_read32(PAD_P2_ADDR, rd);
|
|
check_eq("P2_persist_after_P1_clear",
|
|
rd, {16'd0, expected_sony(32'h0000_0204)});
|
|
|
|
// ----------------------------------------------------------
|
|
// §6. Bridge reset cycle — Ch222 latches clear; IOP sees
|
|
// 0xFFFF for both pads regardless of any prior state.
|
|
// ----------------------------------------------------------
|
|
@(posedge bclk); breset_n = 1'b0;
|
|
// Hold reset long enough to cycle through the sync chain.
|
|
repeat (8) @(posedge bclk);
|
|
repeat (8) @(posedge iclk);
|
|
@(posedge bclk); breset_n = 1'b1;
|
|
// Need more iclk settle: bridge clears at bclk, sio2_input
|
|
// sync takes 2 iclk to propagate the new value.
|
|
repeat (8) @(posedge bclk);
|
|
settle_cdc();
|
|
iop_read32(PAD_P1_ADDR, rd); check_eq("rst_clr_P1", rd, 32'h0000_FFFF);
|
|
iop_read32(PAD_P2_ADDR, rd); check_eq("rst_clr_P2", rd, 32'h0000_FFFF);
|
|
iop_read32(PAD_ST_ADDR, rd); check_eq("rst_clr_ST", rd, 32'h0000_0001);
|
|
|
|
// ----------------------------------------------------------
|
|
// Done.
|
|
// ----------------------------------------------------------
|
|
$display("[tb_bridge_iop_pad_input] errors=%0d", errors);
|
|
if (errors == 0) $display("[tb_bridge_iop_pad_input] PASS");
|
|
else $display("[tb_bridge_iop_pad_input] FAIL");
|
|
$finish;
|
|
end
|
|
|
|
initial begin
|
|
#5_000_000;
|
|
$error("[tb_bridge_iop_pad_input] TIMEOUT");
|
|
$finish;
|
|
end
|
|
|
|
endmodule : tb_bridge_iop_pad_input
|