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:
Executable
+236
@@ -0,0 +1,236 @@
|
||||
// ============================================================================
|
||||
// I2C_HDMI_Config.v — ADV7513 HDMI transmitter configuration via I2C
|
||||
// ============================================================================
|
||||
//
|
||||
// Derived from Terasic DE-series reference design (I2C_HDMI_Config.v).
|
||||
// Original copyright belongs to Terasic Technologies Inc.; this file is
|
||||
// distributed under the terms of the Terasic Reference Design license that
|
||||
// ships with the DE25-Nano System CD (free use on Terasic hardware,
|
||||
// copyright notice retained).
|
||||
//
|
||||
// retroDE modifications (2025-2026):
|
||||
// - LUT_SIZE expanded to 38 entries
|
||||
// - Audio configuration for I2S input @ 48 kHz, MCLK 12.288 MHz
|
||||
// - HPD override (0xD6 = 0xC0) for monitors that misreport hot-plug
|
||||
// - AVI InfoFrame configured for full-range RGB 444 output
|
||||
// - Comments documenting each ADV7513 register write
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module I2C_HDMI_Config ( // Host Side
|
||||
iCLK,
|
||||
iRST_N,
|
||||
// I2C Side
|
||||
I2C_SCLK,
|
||||
I2C_SDAT,
|
||||
HDMI_TX_INT,
|
||||
READY,
|
||||
// Ch166: sticky NACK watchdog
|
||||
ERROR
|
||||
);
|
||||
// Host Side
|
||||
input iCLK;
|
||||
input iRST_N;
|
||||
// I2C Side: SCL is actively driven by the master; SDA is open-drain
|
||||
// (master drives low / releases to 1'bz; slave drives ACK).
|
||||
output I2C_SCLK;
|
||||
inout I2C_SDAT;
|
||||
input HDMI_TX_INT;
|
||||
output READY ;
|
||||
// Ch166: ERROR latches HIGH if the same LUT entry NACKs
|
||||
// NACK_LIMIT consecutive times (chip absent, address wrong,
|
||||
// bus shorted). Sticky until iRST_N. Cleared on reset.
|
||||
output ERROR;
|
||||
|
||||
// Internal Registers/Wires
|
||||
reg [15:0] mI2C_CLK_DIV;
|
||||
reg [23:0] mI2C_DATA;
|
||||
reg mI2C_CTRL_CLK;
|
||||
reg mI2C_GO;
|
||||
wire mI2C_END;
|
||||
wire mI2C_ACK;
|
||||
reg [15:0] LUT_DATA;
|
||||
reg [5:0] LUT_INDEX;
|
||||
reg [3:0] mSetup_ST;
|
||||
reg READY ;
|
||||
|
||||
// Clock Setting
|
||||
parameter CLK_Freq = 50000000; // 50 MHz
|
||||
parameter I2C_Freq = 20000; // 20 KHz
|
||||
// LUT Data Number
|
||||
parameter LUT_SIZE = 38;
|
||||
// Ch166 - NACK watchdog threshold (consecutive retries on the
|
||||
// same LUT entry before ERROR latches). At I2C_Freq=20 kHz a
|
||||
// full byte transaction is ~1.5 ms, so 16 retries ~= 24 ms before
|
||||
// we declare the bus dead - generous enough for real-world bus
|
||||
// settling but well short of a stuck-LED user complaint.
|
||||
parameter NACK_LIMIT = 16;
|
||||
|
||||
///////////////////// I2C Control Clock ////////////////////////
|
||||
always@(posedge iCLK or negedge iRST_N)
|
||||
begin
|
||||
if(!iRST_N)
|
||||
begin
|
||||
mI2C_CTRL_CLK <= 0;
|
||||
mI2C_CLK_DIV <= 0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if( mI2C_CLK_DIV < (CLK_Freq/I2C_Freq) )
|
||||
mI2C_CLK_DIV <= mI2C_CLK_DIV+1;
|
||||
else
|
||||
begin
|
||||
mI2C_CLK_DIV <= 0;
|
||||
mI2C_CTRL_CLK <= ~mI2C_CTRL_CLK;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
I2C_Controller u0 ( .CLK(mI2C_CTRL_CLK), // Controller work clock
|
||||
.CLK_EN(1'b1), // Advance every controller clock
|
||||
.CLK_PHASE(mI2C_CTRL_CLK), // Phase for SCL generation
|
||||
.I2C_SCLK(I2C_SCLK), // I2C CLOCK
|
||||
.I2C_SDAT(I2C_SDAT), // I2C DATA
|
||||
.I2C_DATA(mI2C_DATA), // DATA:[SLAVE_ADDR,SUB_ADDR,DATA]
|
||||
.GO(mI2C_GO), // GO transfor
|
||||
.END(mI2C_END), // END transfor
|
||||
.W_R(1'b0), // Ch165 audit Low — tie retained-compat port off (always WRITE)
|
||||
.ACK(mI2C_ACK), // ACK
|
||||
.RESET(iRST_N) );
|
||||
////////////////////////////////////////////////////////////////////
|
||||
////////////////////// Config Control ////////////////////////////
|
||||
always@(posedge mI2C_CTRL_CLK or negedge iRST_N)
|
||||
begin
|
||||
if(!iRST_N)
|
||||
begin
|
||||
READY <= 0;
|
||||
LUT_INDEX <= 0;
|
||||
mSetup_ST <= 0;
|
||||
mI2C_GO <= 0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if(LUT_INDEX<LUT_SIZE)
|
||||
begin
|
||||
READY<=0;
|
||||
case(mSetup_ST)
|
||||
0: begin
|
||||
mI2C_DATA <= {8'h72,LUT_DATA};
|
||||
mI2C_GO <= 1;
|
||||
mSetup_ST <= 1;
|
||||
end
|
||||
1: begin
|
||||
if(mI2C_END)
|
||||
begin
|
||||
if(!mI2C_ACK)
|
||||
mSetup_ST <= 2;
|
||||
else
|
||||
mSetup_ST <= 0;
|
||||
mI2C_GO <= 0;
|
||||
end
|
||||
end
|
||||
2: begin
|
||||
LUT_INDEX <= LUT_INDEX+1;
|
||||
mSetup_ST <= 0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
else
|
||||
begin
|
||||
READY<=1;
|
||||
if(!HDMI_TX_INT)
|
||||
begin
|
||||
LUT_INDEX <= 0;
|
||||
end
|
||||
else
|
||||
LUT_INDEX <= LUT_INDEX;
|
||||
end
|
||||
end
|
||||
end
|
||||
////////////////////////////////////////////////////////////////////
|
||||
////////////////// Ch166 NACK watchdog (sticky) //////////////////
|
||||
//
|
||||
// Counts consecutive NACK retries on the *current* LUT entry.
|
||||
// In the config FSM above, state 1 sees mI2C_END at the end of
|
||||
// each I2C transaction; if mI2C_ACK is HIGH (slave didn't drive
|
||||
// the ACK bit LOW), the FSM bounces back to state 0 and retries
|
||||
// the same LUT_DATA. State 2 means the byte ACKed and LUT_INDEX
|
||||
// is about to advance, so we clear the retry count there. Once
|
||||
// the count hits NACK_LIMIT, ERROR latches HIGH (sticky until
|
||||
// iRST_N) so the top level can surface a stuck bus on an LED.
|
||||
reg [7:0] nack_retries;
|
||||
reg error_latched;
|
||||
always @(posedge mI2C_CTRL_CLK or negedge iRST_N)
|
||||
begin
|
||||
if (!iRST_N)
|
||||
begin
|
||||
nack_retries <= 0;
|
||||
error_latched <= 1'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (mSetup_ST == 1 && mI2C_END && mI2C_ACK)
|
||||
begin
|
||||
nack_retries <= nack_retries + 1;
|
||||
if (nack_retries == NACK_LIMIT - 1)
|
||||
error_latched <= 1'b1;
|
||||
end
|
||||
else if (mSetup_ST == 2)
|
||||
begin
|
||||
nack_retries <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
assign ERROR = error_latched;
|
||||
////////////////////////////////////////////////////////////////////
|
||||
///////////////////// Config Data LUT //////////////////////////
|
||||
always@(*)
|
||||
begin
|
||||
case(LUT_INDEX)
|
||||
// Video Config Data
|
||||
00 : LUT_DATA <= 16'h9803; //Must be set to 0x03 for proper operation
|
||||
01 : LUT_DATA <= 16'hD6C0; //HPD override: force HPD always-high (bits[7:6]=11)
|
||||
02 : LUT_DATA <= 16'h0100; //Set 'N' value at 6144
|
||||
03 : LUT_DATA <= 16'h0218; //Set 'N' value at 6144
|
||||
04 : LUT_DATA <= 16'h0300; //Set 'N' value at 6144
|
||||
05 : LUT_DATA <= 16'h0a01; //MCLK ratio = 256x fs (12.288 MHz / 48 kHz)
|
||||
06 : LUT_DATA <= 16'h0b2e; //MCLK Active
|
||||
07 : LUT_DATA <= 16'h0cbc; //Serial Audio standard i2s, R0x0C[1:0] = '00
|
||||
08 : LUT_DATA <= 16'h1402; //Audio Word Length 16 bit, stereo (2 channels)
|
||||
09 : LUT_DATA <= 16'h1520; //Input 444 (RGB or YCrCb) with Separate Syncs, 48kHz fs
|
||||
10 : LUT_DATA <= 16'h1630; //Output format 444, 24-bit input
|
||||
11 : LUT_DATA <= 16'h1846; //Disable CSC
|
||||
12 : LUT_DATA <= 16'h4080; //General control packet enable
|
||||
13 : LUT_DATA <= 16'h4110; //Power down control
|
||||
14 : LUT_DATA <= 16'h49A8; //Set dither mode - 12-to-10 bit
|
||||
15 : LUT_DATA <= 16'h5510; //AVI InfoFrame byte 1: Y=RGB, A0=active fmt valid
|
||||
16 : LUT_DATA <= 16'h5608; //AVI InfoFrame byte 2: active format aspect
|
||||
17 : LUT_DATA <= 16'h5708; //AVI InfoFrame byte 3: Q=10 (full range RGB 0-255)
|
||||
18 : LUT_DATA <= 16'h94C0; //INT enable 1: HPD + monitor sense only
|
||||
19 : LUT_DATA <= 16'h9500; //INT enable 2: all disabled
|
||||
20 : LUT_DATA <= 16'h96C0; //Clear HPD + monitor sense status (matches 0x94 enable mask)
|
||||
21 : LUT_DATA <= 16'h7301; //Info frame Ch count = 2 (stereo)
|
||||
22 : LUT_DATA <= 16'h7600; //Speaker allocation: FL+FR (stereo)
|
||||
23 : LUT_DATA <= 16'h9803; //Must be set to 0x03 for proper operation
|
||||
24 : LUT_DATA <= 16'h9902; //Must be set to Default Value
|
||||
25 : LUT_DATA <= 16'h9ae0; //Must be set to 0b1110000
|
||||
26 : LUT_DATA <= 16'h9c30; //PLL filter R1 value
|
||||
27 : LUT_DATA <= 16'h9d61; //Set clock divide
|
||||
28 : LUT_DATA <= 16'ha2a4; //Must be set to 0xA4 for proper operation
|
||||
29 : LUT_DATA <= 16'ha3a4; //Must be set to 0xA4 for proper operation
|
||||
30 : LUT_DATA <= 16'ha504; //Must be set to Default Value
|
||||
31 : LUT_DATA <= 16'hab40; //Must be set to Default Value
|
||||
32 : LUT_DATA <= 16'haf16; //Select HDMI mode
|
||||
33 : LUT_DATA <= 16'hba60; //No clock delay
|
||||
34 : LUT_DATA <= 16'hd1ff; //Must be set to Default Value
|
||||
35 : LUT_DATA <= 16'hde10; //Must be set to Default for proper operation
|
||||
36 : LUT_DATA <= 16'he460; //Must be set to Default Value
|
||||
37 : LUT_DATA <= 16'hfa7d; //Nbr of times to look for good phase
|
||||
default: LUT_DATA <= 16'h9803;
|
||||
endcase
|
||||
end
|
||||
////////////////////////////////////////////////////////////////////
|
||||
endmodule
|
||||
Reference in New Issue
Block a user