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>
185 lines
6.8 KiB
Systemverilog
185 lines
6.8 KiB
Systemverilog
// retroDE_ps2 — sif_mailbox_peer_stub
|
|
//
|
|
// Re-armable active peer for the SIF mailbox. Second step on the two-actor
|
|
// coordination track (A'' — lifecycle). Observes one mailbox/flag pattern
|
|
// and responds with a known acknowledgement pattern. NOT an IOP — does not
|
|
// execute code, does not boot anything, does not claim to be a CPU.
|
|
//
|
|
// Contract refs:
|
|
// docs/contracts/sif.md (mailbox/flag-only SIF stub)
|
|
// docs/stub_module_plan.md (Wave 2 SIF track)
|
|
//
|
|
// Canonical command-echo protocol:
|
|
// 1. EE writes MSCOM = cmd
|
|
// 2. EE writes MSFLG = CMD_PENDING_BIT (doorbell rising edge)
|
|
// 3. peer polls MSFLG; when it sees CMD_PENDING_BIT set AND it has not
|
|
// already responded to the current request, it reads MSCOM
|
|
// 4. peer writes SMCOM = <the cmd it just read>
|
|
// 5. peer writes SMFLG = CMD_ACK_BIT
|
|
// 6. peer latches `responded` and resumes polling; it will NOT respond
|
|
// again until the TB (or EE) clears CMD_PENDING_BIT in MSFLG
|
|
// 7. when the peer observes CMD_PENDING_BIT cleared, `responded` clears
|
|
// and the next rising edge of CMD_PENDING_BIT triggers a fresh echo
|
|
//
|
|
// The peer still does NOT clear any mailbox state itself. Re-arm is the
|
|
// TB's responsibility; the peer just refuses to double-fire while the
|
|
// doorbell bit is still high.
|
|
//
|
|
// Ports connect directly to sif_mailbox_stub's IOP-side register port:
|
|
// obs_* → mailbox iop_rd_* (peer reads MSFLG then MSCOM)
|
|
// resp_* → mailbox iop_wr_* (peer writes SMCOM then SMFLG)
|
|
//
|
|
// All peer activity is visible through the mailbox's own trace output
|
|
// (side_id=IOP=1). The peer does not emit its own trace; `ack_count_o`
|
|
// provides a testbench synchronisation point.
|
|
|
|
`timescale 1ns/1ps
|
|
|
|
module sif_mailbox_peer_stub
|
|
#(
|
|
parameter logic [7:0] MSCOM_OFF = 8'h00,
|
|
parameter logic [7:0] SMCOM_OFF = 8'h10,
|
|
parameter logic [7:0] MSFLG_OFF = 8'h20,
|
|
parameter logic [7:0] SMFLG_OFF = 8'h30,
|
|
parameter logic [31:0] CMD_PENDING_BIT = 32'h0000_0001,
|
|
parameter logic [31:0] CMD_ACK_BIT = 32'h0000_0002
|
|
) (
|
|
input logic clk,
|
|
input logic rst_n,
|
|
|
|
// Observation — connects to mailbox iop_rd_*
|
|
output logic obs_rd_en,
|
|
output logic [7:0] obs_rd_addr,
|
|
input logic [31:0] obs_rd_data,
|
|
input logic obs_rd_valid,
|
|
|
|
// Response — connects to mailbox iop_wr_*
|
|
output logic resp_wr_en,
|
|
output logic [7:0] resp_wr_addr,
|
|
output logic [31:0] resp_wr_data,
|
|
|
|
// Status
|
|
output logic done_o, // latched high after the first ack
|
|
output logic [31:0] ack_count_o // monotonic count of completed acks
|
|
);
|
|
|
|
typedef enum logic [2:0] {
|
|
S_POLL_REQ = 3'd0, // drive rd_en for MSFLG
|
|
S_POLL_WAIT = 3'd1, // wait for obs_rd_valid, decide
|
|
S_MSCOM_REQ = 3'd2, // drive rd_en for MSCOM
|
|
S_MSCOM_WAIT = 3'd3, // wait for obs_rd_valid, latch cmd
|
|
S_WRITE_SMCOM = 3'd4, // drive wr_en, addr=SMCOM, data=cmd
|
|
S_WRITE_SMFLG = 3'd5 // drive wr_en, addr=SMFLG, data=ACK
|
|
} state_e;
|
|
|
|
state_e state;
|
|
logic [31:0] latched_cmd;
|
|
logic responded; // peer has already acked the current
|
|
// doorbell assertion; suppresses re-fire
|
|
// until the doorbell is observed low
|
|
|
|
// ------------------------------------------------------------------
|
|
// State machine
|
|
// ------------------------------------------------------------------
|
|
|
|
always_ff @(posedge clk) begin
|
|
if (!rst_n) begin
|
|
state <= S_POLL_REQ;
|
|
latched_cmd <= 32'd0;
|
|
responded <= 1'b0;
|
|
end else begin
|
|
unique case (state)
|
|
S_POLL_REQ: state <= S_POLL_WAIT;
|
|
|
|
S_POLL_WAIT: begin
|
|
if (obs_rd_valid) begin
|
|
if (responded) begin
|
|
// Waiting for the TB to clear CMD_PENDING_BIT
|
|
// before we arm again.
|
|
if ((obs_rd_data & CMD_PENDING_BIT) == 32'd0)
|
|
responded <= 1'b0;
|
|
state <= S_POLL_REQ;
|
|
end else begin
|
|
if ((obs_rd_data & CMD_PENDING_BIT) != 32'd0)
|
|
state <= S_MSCOM_REQ;
|
|
else
|
|
state <= S_POLL_REQ;
|
|
end
|
|
end
|
|
end
|
|
|
|
S_MSCOM_REQ: state <= S_MSCOM_WAIT;
|
|
|
|
S_MSCOM_WAIT: begin
|
|
if (obs_rd_valid) begin
|
|
latched_cmd <= obs_rd_data;
|
|
state <= S_WRITE_SMCOM;
|
|
end
|
|
end
|
|
|
|
S_WRITE_SMCOM: state <= S_WRITE_SMFLG;
|
|
|
|
S_WRITE_SMFLG: begin
|
|
responded <= 1'b1; // refuse to re-fire until MSFLG
|
|
// clears
|
|
state <= S_POLL_REQ;
|
|
end
|
|
|
|
default: state <= S_POLL_REQ;
|
|
endcase
|
|
end
|
|
end
|
|
|
|
// ------------------------------------------------------------------
|
|
// Output drive (combinational, one-hot on state)
|
|
// ------------------------------------------------------------------
|
|
|
|
always_comb begin
|
|
obs_rd_en = 1'b0;
|
|
obs_rd_addr = 8'd0;
|
|
resp_wr_en = 1'b0;
|
|
resp_wr_addr = 8'd0;
|
|
resp_wr_data = 32'd0;
|
|
|
|
unique case (state)
|
|
S_POLL_REQ: begin
|
|
obs_rd_en = 1'b1;
|
|
obs_rd_addr = MSFLG_OFF;
|
|
end
|
|
S_MSCOM_REQ: begin
|
|
obs_rd_en = 1'b1;
|
|
obs_rd_addr = MSCOM_OFF;
|
|
end
|
|
S_WRITE_SMCOM: begin
|
|
resp_wr_en = 1'b1;
|
|
resp_wr_addr = SMCOM_OFF;
|
|
resp_wr_data = latched_cmd;
|
|
end
|
|
S_WRITE_SMFLG: begin
|
|
resp_wr_en = 1'b1;
|
|
resp_wr_addr = SMFLG_OFF;
|
|
resp_wr_data = CMD_ACK_BIT;
|
|
end
|
|
default: ;
|
|
endcase
|
|
end
|
|
|
|
// ------------------------------------------------------------------
|
|
// Ack bookkeeping
|
|
// ------------------------------------------------------------------
|
|
|
|
always_ff @(posedge clk) begin
|
|
if (!rst_n) begin
|
|
ack_count_o <= 32'd0;
|
|
done_o <= 1'b0;
|
|
end else if (state == S_WRITE_SMFLG) begin
|
|
// S_WRITE_SMFLG is a single-cycle state: the state machine
|
|
// unconditionally transitions to S_POLL_REQ on the next edge,
|
|
// so this branch is observed exactly once per completed ack.
|
|
ack_count_o <= ack_count_o + 32'd1;
|
|
done_o <= 1'b1;
|
|
end
|
|
end
|
|
|
|
endmodule : sif_mailbox_peer_stub
|