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>
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
// retroDE_ps2 — iop_fetch_stub
|
||||
//
|
||||
// Minimal IOP-side sequential fetcher. Mirrors ee_fetch_stub in shape and
|
||||
// discipline — just the smallest honest primitive that produces visible
|
||||
// IOP-side execution-flow traffic. Not a CPU. Explicitly NOT a BIOS boot
|
||||
// stub: the default reset vector lives in IOP RAM, not in BIOS space.
|
||||
//
|
||||
// Contract refs:
|
||||
// docs/contracts/iop.md (IOP CPU execution, required debug
|
||||
// visibility: PC stream)
|
||||
//
|
||||
// Behavior:
|
||||
// - On reset, PC = RESET_VECTOR (default 0x00000000, the low end of
|
||||
// IOP RAM).
|
||||
// - Each cycle while `enable` is high: issue a 32-bit read at PC,
|
||||
// advance PC += 4. No decode, no branches, no exceptions, no FPU.
|
||||
// - Responses return 1 cycle later via rd_valid/rd_data from the
|
||||
// map. The issued address is latched (pc_d1) so trace lines pair
|
||||
// address with data.
|
||||
//
|
||||
// Non-goals:
|
||||
// - full decode
|
||||
// - branch / exception / interrupt handling
|
||||
// - real IOP R3000 pipeline timing
|
||||
// - BIOS fetch (use a BIOS-pointing RESET_VECTOR param override if
|
||||
// needed, but that's intentionally not the default)
|
||||
//
|
||||
// Trace payload schema (matches ee_fetch_stub structure under SUBSYS_IOP):
|
||||
// IOP RESET arg0=reset_vector
|
||||
// IOP IFETCH arg0=pc arg1=data arg2=resp_kind arg3=-
|
||||
// resp_kind: 0=OK (only path in this scope)
|
||||
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module iop_fetch_stub
|
||||
import trace_pkg::*;
|
||||
#(
|
||||
parameter logic [31:0] RESET_VECTOR = 32'h0000_0000
|
||||
) (
|
||||
input logic clk,
|
||||
input logic rst_n,
|
||||
input logic enable,
|
||||
|
||||
// Map-facing fetch port
|
||||
output logic rd_en,
|
||||
output logic [31:0] rd_addr,
|
||||
input logic [31:0] rd_data,
|
||||
input logic 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
|
||||
);
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// PC and issued-address shadow (same pattern as ee_fetch_stub):
|
||||
// pc is the address being issued THIS cycle (rd_addr)
|
||||
// pc_d1 is the address whose response arrives THIS cycle on rd_valid
|
||||
// pc_d1 only advances alongside pc when enable is high, so it stays
|
||||
// aligned with the in-flight request.
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
logic [31:0] pc;
|
||||
logic [31:0] pc_d1;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (!rst_n) begin
|
||||
pc <= RESET_VECTOR;
|
||||
pc_d1 <= RESET_VECTOR;
|
||||
end else if (enable) begin
|
||||
pc_d1 <= pc;
|
||||
pc <= pc + 32'd4;
|
||||
end
|
||||
end
|
||||
|
||||
assign rd_en = enable;
|
||||
assign rd_addr = pc;
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Trace
|
||||
// - Single EV_RESET pulse at reset exit.
|
||||
// - EV_IFETCH one cycle after each rd_valid response.
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
logic reset_emit_pending;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (!rst_n) begin
|
||||
ev_valid <= 1'b0;
|
||||
ev_subsys <= SUBSYS_IOP;
|
||||
ev_event <= EV_RESET;
|
||||
ev_arg0 <= 64'd0;
|
||||
ev_arg1 <= 64'd0;
|
||||
ev_arg2 <= 64'd0;
|
||||
ev_arg3 <= 64'd0;
|
||||
ev_flags <= 32'd0;
|
||||
reset_emit_pending <= 1'b1;
|
||||
end else if (reset_emit_pending) begin
|
||||
ev_valid <= 1'b1;
|
||||
ev_subsys <= SUBSYS_IOP;
|
||||
ev_event <= EV_RESET;
|
||||
ev_arg0 <= {32'd0, RESET_VECTOR};
|
||||
ev_arg1 <= 64'd0;
|
||||
ev_arg2 <= 64'd0;
|
||||
ev_arg3 <= 64'd0;
|
||||
ev_flags <= 32'd0;
|
||||
reset_emit_pending <= 1'b0;
|
||||
end else if (rd_valid) begin
|
||||
ev_valid <= 1'b1;
|
||||
ev_subsys <= SUBSYS_IOP;
|
||||
ev_event <= EV_IFETCH;
|
||||
ev_arg0 <= {32'd0, pc_d1};
|
||||
ev_arg1 <= {32'd0, rd_data};
|
||||
ev_arg2 <= 64'd0;
|
||||
ev_arg3 <= 64'd0;
|
||||
ev_flags <= 32'd0;
|
||||
end else begin
|
||||
ev_valid <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule : iop_fetch_stub
|
||||
Reference in New Issue
Block a user