Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion files.qip
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
set_global_assignment -name SYSTEMVERILOG_FILE rtl/sdram.sv
set_global_assignment -name SYSTEMVERILOG_FILE rtl/ddram.sv
set_global_assignment -name VERILOG_FILE rtl/lfsr.v
set_global_assignment -name SYSTEMVERILOG_FILE rtl/cos.sv
set_global_assignment -name SYSTEMVERILOG_FILE rtl/native_video_reader.sv
set_global_assignment -name SYSTEMVERILOG_FILE rtl/native_video_timing.sv
set_global_assignment -name SYSTEMVERILOG_FILE rtl/native_video_top.sv
set_global_assignment -name SYSTEMVERILOG_FILE menu.sv
185 changes: 97 additions & 88 deletions menu.sv
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,16 @@ assign LED_POWER[0]= FB ? led[2] : act_cnt2[26] ? act_cnt2[25:18] > act_cnt2[7:0


`include "build_id.v"
// Image centering: 4-bit signed in OSD ordering 0,+1..+7,-8..-1 so that the
// power-on default (status bits = 0) maps to "no shift". Bit pattern matches
// 4-bit two's complement when reinterpreted as signed.
localparam CONF_STR = {
"MENU;UART31250,MIDI;",
"-;",
"V,v",`BUILD_DATE
"O[13:10],H Offset,0,+1,+2,+3,+4,+5,+6,+7,-8,-7,-6,-5,-4,-3,-2,-1;",
"O[17:14],V Offset,0,+1,+2,+3,+4,+5,+6,+7,-8,-7,-6,-5,-4,-3,-2,-1;",
"-;",
"V,v",`BUILD_DATE
};

wire forced_scandoubler;
Expand Down Expand Up @@ -336,36 +342,15 @@ always @(posedge clk_sys) begin
state <= state+1'd1;
end
16: begin
sdram_addr <= addr[24:0];
sdram_din <= 0;
sdram_we <= we;
sdram_we <= 0;
end
endcase
end
end

ddram ddr
(
.*,
.reset(RESET),
.dout(),
.din(0),
.rd(0),
.ready()
);

reg we;
reg [28:0] addr = 0;

always @(posedge clk_sys) begin
reg [4:0] cnt = 9;

if(~RESET & cfg[15]) begin
cnt <= cnt + 1'b1;
we <= &cnt;
if(cnt == 8) addr <= addr + 1'd1;
end
end
// DDR clear loop removed: native_video_reader owns DDRAM_* signals.
// When status[9]=0 the reader is held in idle (rd=0, we=0) and DDR is unused;
// when status[9]=1 the reader takes over to fetch the linux-rendered framebuffer.

//////////////////////////// MT32pi //////////////////////////////////

Expand Down Expand Up @@ -480,81 +465,105 @@ wire PAL = status[4];
wire FB = status[5];
wire [2:0] led = status[8:6];

reg [9:0] hc;
reg [9:0] vc;
reg [9:0] vvc;
// Pixel clock: CLK_VIDEO = 27.027 MHz; ce_pix /4 = ~6.756 MHz, which gives
// an NTSC-spec 15.734 kHz line rate when fed into native_video_timing
// (H_TOTAL=429). Both the cosine fallback and the FB reader use this ce_pix.
reg [1:0] ce_div;
reg ce_pix;
always @(posedge CLK_VIDEO) begin
if (RESET) ce_div <= 2'd0;
else ce_div <= ce_div + 2'd1;
ce_pix <= (ce_div == 2'd0);
end

// Native video timing + DDR reader. Timing outputs (sync, DE, vcount, frame
// edge) are the SINGLE source of truth for VGA scanout in both modes — that's
// what guarantees the CRT sees a clean 15.734 kHz line rate whether we're
// painting cosine noise or reading a Linux-rendered framebuffer.
wire mode_zaparoo = status[9];

wire [7:0] native_r;
wire [7:0] native_g;
wire [7:0] native_b;
wire native_hs;
wire native_vs;
wire native_de;
wire [8:0] native_vcount;
wire native_new_frame;
wire native_active;

native_video_top native_video
(
.clk_sys (clk_sys),
.clk_vid (CLK_VIDEO),
.ce_pix (ce_pix),
.reset (RESET),

.ddr_busy (DDRAM_BUSY),
.ddr_burstcnt (DDRAM_BURSTCNT),
.ddr_addr (DDRAM_ADDR),
.ddr_dout (DDRAM_DOUT),
.ddr_dout_ready (DDRAM_DOUT_READY),
.ddr_rd (DDRAM_RD),
.ddr_din (DDRAM_DIN),
.ddr_be (DDRAM_BE),
.ddr_we (DDRAM_WE),

.vga_r (native_r),
.vga_g (native_g),
.vga_b (native_b),
.vga_hs (native_hs),
.vga_vs (native_vs),
.vga_de (native_de),
.vga_hblank (),
.vga_vblank (),
.vga_vcount (native_vcount),
.vga_new_frame (native_new_frame),
.enable (mode_zaparoo),
.active (native_active),

// status[13:10] / status[17:14] are 4-bit fields whose bit pattern
// matches signed two's complement when the OSD enum is ordered
// 0,+1..+7,-8..-1 (see CONF_STR). $signed() makes the reinterpretation
// explicit at the port boundary.
.h_offset ($signed(status[13:10])),
.v_offset ($signed(status[17:14]))
);

// Cosine + LFSR fallback noise pattern, painted into the 320x240 active area
// of the shared native timing. vvc steps once per frame; the LFSR walks every
// pixel; cos LUT is indexed by vvc + vcount so the pattern shifts vertically
// over time. Outside the active area we drive black to keep sync clean.
reg [9:0] vvc;
reg [lfsr_n:0] rnd_reg;
wire [lfsr_n:0] rnd;

wire [5:0] rnd_c = {rnd_reg[0],rnd_reg[1],rnd_reg[2],rnd_reg[2],rnd_reg[2],rnd_reg[2]};

lfsr #(lfsr_n) random(rnd);

always @(posedge CLK_VIDEO) begin
if(forced_scandoubler) ce_pix <= 1;
else ce_pix <= ~ce_pix;

if(ce_pix) begin
if(hc == 637) begin
hc <= 0;
if(vc == (PAL ? (forced_scandoubler ? 623 : 311) : (forced_scandoubler ? 523 : 261))) begin
vc <= 0;
vvc <= vvc + 9'd6;
end else begin
vc <= vc + 1'd1;
end
end else begin
hc <= hc + 1'd1;
end

rnd_reg <= rnd;
end
end

reg HBlank;
reg HSync;
reg VBlank;
reg VSync;

reg ce_pix;
always @(posedge CLK_VIDEO) begin
if (hc == 529) HBlank <= 1;
else if (hc == 0) HBlank <= 0;

if (hc == 544) begin
HSync <= 1;

if(PAL) begin
if(vc == (forced_scandoubler ? 609 : 304)) VSync <= 1;
else if (vc == (forced_scandoubler ? 617 : 308)) VSync <= 0;

if(vc == (forced_scandoubler ? 601 : 300)) VBlank <= 1;
else if (vc == 0) VBlank <= 0;
end
else begin
if(vc == (forced_scandoubler ? 490 : 245)) VSync <= 1;
else if (vc == (forced_scandoubler ? 496 : 248)) VSync <= 0;

if(vc == (forced_scandoubler ? 480 : 240)) VBlank <= 1;
else if (vc == 0) VBlank <= 0;
end
end

if (hc == 590) HSync <= 0;
if (RESET) vvc <= 10'd0;
else if (native_new_frame) vvc <= vvc + 10'd6;
if (ce_pix) rnd_reg <= rnd;
end

reg [7:0] cos_out;
wire [5:0] cos_g = cos_out[7:3]+6'd32;
cos cos(vvc + {vc>>forced_scandoubler, 2'b00}, cos_out);
wire [5:0] cos_g = cos_out[7:3] + 6'd32;
cos cos(vvc + {native_vcount, 2'b00}, cos_out);

wire [7:0] comp_v = (cos_g >= rnd_c) ? {cos_g - rnd_c, 2'b00} : 8'd0;

assign VGA_DE = ~(HBlank | VBlank);
assign VGA_HS = HSync;
assign VGA_VS = VSync;
assign VGA_G = comp_v;
assign VGA_R = comp_v;
assign VGA_B = comp_v;
// Mode A (default): cosine pattern paints into the native active area.
// Mode B (status[9]=1, frame ready): DDR-read RGB replaces the cosine pattern.
// Sync/DE come from the same native timing in both cases — the CRT sees one
// continuous, NTSC-spec signal regardless of which RGB source is selected.
wire use_native = mode_zaparoo & native_active;

assign VGA_DE = native_de;
assign VGA_HS = native_hs;
assign VGA_VS = native_vs;
assign VGA_R = use_native ? native_r : (native_de ? comp_v : 8'd0);
assign VGA_G = use_native ? native_g : (native_de ? comp_v : 8'd0);
assign VGA_B = use_native ? native_b : (native_de ? comp_v : 8'd0);

endmodule
Loading
Loading