From 061a8884d4f4a6dacd830f70564af95a02c74dd3 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Thu, 7 May 2026 01:16:57 +0200 Subject: [PATCH 1/3] feat: add Zaparoo native video core Add a 320x240 RGBX8888 DDR reader and native timing path for the launcher reference core. --- files.qip | 12 +- menu.sv | 133 ++++++++------- rtl/native_video_reader.sv | 337 +++++++++++++++++++++++++++++++++++++ rtl/native_video_timing.sv | 96 +++++++++++ rtl/native_video_top.sv | 96 +++++++++++ rtl/pll/pll_0002.v | 2 +- 6 files changed, 612 insertions(+), 64 deletions(-) create mode 100644 rtl/native_video_reader.sv create mode 100644 rtl/native_video_timing.sv create mode 100644 rtl/native_video_top.sv diff --git a/files.qip b/files.qip index 830b598..bb298f8 100644 --- a/files.qip +++ b/files.qip @@ -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 menu.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/sdram.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 diff --git a/menu.sv b/menu.sv index 5160e63..f55e016 100644 --- a/menu.sv +++ b/menu.sv @@ -186,8 +186,8 @@ assign CE_PIXEL = ce_pix; assign VGA_SL = 0; assign VGA_F1 = 0; -assign VIDEO_ARX = 0; -assign VIDEO_ARY = 0; +assign VIDEO_ARX = 13'd4; +assign VIDEO_ARY = 13'd3; assign VGA_SCALER= 0; assign VGA_DISABLE = 0; @@ -209,7 +209,7 @@ assign LED_POWER[0]= FB ? led[2] : act_cnt2[26] ? act_cnt2[25:18] > act_cnt2[7:0 `include "build_id.v" localparam CONF_STR = { - "MENU;UART31250,MIDI;", + "Zaparoo Launcher;UART31250,MIDI;", "-;", "V,v",`BUILD_DATE }; @@ -335,37 +335,15 @@ always @(posedge clk_sys) begin cfg[15] <= 1; state <= state+1'd1; end - 16: begin - sdram_addr <= addr[24:0]; - sdram_din <= 0; - sdram_we <= we; - 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 + 16: begin + sdram_we <= 0; + end + endcase + end +end + +// DDR clear helper removed for Zaparoo native video. The ARM launcher owns +// the RGBX8888 frame buffers; the FPGA only reads them. //////////////////////////// MT32pi ////////////////////////////////// @@ -491,12 +469,9 @@ wire [5:0] rnd_c = {rnd_reg[0],rnd_reg[1],rnd_reg[2],rnd_reg[2],rnd_reg[2],rnd_ 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 +always @(posedge CLK_VIDEO) begin + if(ce_pix) begin + if(hc == 637) begin hc <= 0; if(vc == (PAL ? (forced_scandoubler ? 623 : 311) : (forced_scandoubler ? 523 : 261))) begin vc <= 0; @@ -513,14 +488,19 @@ always @(posedge CLK_VIDEO) begin 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; +reg HSync; +reg VBlank; +reg VSync; + +reg ce_pix; +reg [1:0] ce_div; +always @(posedge CLK_VIDEO) begin + if(RESET) ce_div <= 2'd0; + else ce_div <= ce_div + 2'd1; + ce_pix <= (ce_div == 2'd0); + + if (hc == 529) HBlank <= 1; + else if (hc == 0) HBlank <= 0; if (hc == 544) begin HSync <= 1; @@ -548,13 +528,50 @@ 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 [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; - -endmodule +wire [7:0] comp_v = (cos_g >= rnd_c) ? {cos_g - rnd_c, 2'b00} : 8'd0; + +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 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 (), + .enable (cfg[15]), + .active (native_active) +); + +assign VGA_DE = native_de; +assign VGA_HS = native_hs; +assign VGA_VS = native_vs; +assign VGA_G = native_active ? native_g : comp_v; +assign VGA_R = native_active ? native_r : comp_v; +assign VGA_B = native_active ? native_b : comp_v; + +endmodule diff --git a/rtl/native_video_reader.sv b/rtl/native_video_reader.sv new file mode 100644 index 0000000..66e4ae7 --- /dev/null +++ b/rtl/native_video_reader.sv @@ -0,0 +1,337 @@ +// Zaparoo native video DDR reader. +// DDR contract: +// 0x3A000000: control word, (frame_counter << 2) | active_buffer +// 0x3A000100: buffer 0, 320x240 RGBX8888 +// 0x3A04B100: buffer 1, 320x240 RGBX8888 + +module native_video_reader +( + input wire ddr_clk, + input wire ddr_busy, + output reg [7:0] ddr_burstcnt, + output reg [28:0] ddr_addr, + input wire [63:0] ddr_dout, + input wire ddr_dout_ready, + output reg ddr_rd, + output wire [63:0] ddr_din, + output wire [7:0] ddr_be, + output wire ddr_we, + + input wire clk_vid, + input wire ce_pix, + input wire reset, + input wire de, + input wire vblank, + input wire new_frame, + input wire new_line, + input wire [8:0] vcount, + + output reg [7:0] r_out, + output reg [7:0] g_out, + output reg [7:0] b_out, + input wire enable, + output wire frame_ready +); + +assign ddr_din = 64'd0; +assign ddr_be = 8'hFF; +assign ddr_we = 1'b0; + +localparam [28:0] CTRL_ADDR = 29'h07400000; +localparam [28:0] BUF0_ADDR = 29'h07400020; +localparam [28:0] BUF1_ADDR = 29'h07409620; +localparam [7:0] LINE_BURST = 8'd160; +localparam [28:0] LINE_STRIDE = 29'd160; +localparam [8:0] V_ACTIVE = 9'd240; +localparam [19:0] TIMEOUT_MAX = 20'hF_FFFF; + +reg [1:0] enable_sync; +always @(posedge ddr_clk) begin + if(reset) enable_sync <= 2'b0; + else enable_sync <= {enable_sync[0], enable}; +end +wire enable_ddr = enable_sync[1]; + +reg [1:0] new_frame_sync; +always @(posedge ddr_clk) begin + if(reset) new_frame_sync <= 2'b0; + else new_frame_sync <= {new_frame_sync[0], new_frame}; +end +wire new_frame_ddr = ~new_frame_sync[1] & new_frame_sync[0]; + +reg [1:0] new_line_sync; +always @(posedge ddr_clk) begin + if(reset) new_line_sync <= 2'b0; + else new_line_sync <= {new_line_sync[0], new_line}; +end +wire new_line_ddr = ~new_line_sync[1] & new_line_sync[0]; + +reg [1:0] vblank_sync; +always @(posedge ddr_clk) begin + if(reset) vblank_sync <= 2'b0; + else vblank_sync <= {vblank_sync[0], vblank}; +end +wire vblank_ddr = vblank_sync[1]; + +reg [1:0] reset_vid_sync; +always @(posedge clk_vid or posedge reset) begin + if(reset) reset_vid_sync <= 2'b11; + else reset_vid_sync <= {reset_vid_sync[0], 1'b0}; +end +wire reset_vid = reset_vid_sync[1]; + +reg frame_ready_reg; +reg [1:0] frame_ready_sync; +always @(posedge clk_vid) begin + if(reset_vid) frame_ready_sync <= 2'b0; + else frame_ready_sync <= {frame_ready_sync[0], frame_ready_reg}; +end +wire frame_ready_vid = frame_ready_sync[1]; +assign frame_ready = frame_ready_vid; + +localparam [3:0] ST_IDLE = 4'd0; +localparam [3:0] ST_POLL_CTRL = 4'd1; +localparam [3:0] ST_WAIT_CTRL = 4'd2; +localparam [3:0] ST_CHECK_CTRL = 4'd3; +localparam [3:0] ST_READ_LINE = 4'd4; +localparam [3:0] ST_WAIT_LINE = 4'd5; +localparam [3:0] ST_LINE_DONE = 4'd6; +localparam [3:0] ST_WAIT_DISPLAY = 4'd7; + +reg [3:0] state; +reg [31:0] ctrl_word; +reg [29:0] prev_frame_counter; +reg [28:0] buf_base_addr; +reg [8:0] cur_line; +reg [7:0] beat_count; +reg first_frame_loaded; +reg preloading; +reg [19:0] timeout_cnt; +reg fifo_wr; +reg [63:0] fifo_wr_data; +wire fifo_full; + +reg [3:0] fifo_aclr_cnt; +wire fifo_aclr_ddr_active = (fifo_aclr_cnt != 4'd0); +wire fifo_aclr = reset | fifo_aclr_ddr_active; + +always @(posedge ddr_clk) begin + if(reset) begin + state <= ST_IDLE; + ddr_rd <= 1'b0; + ddr_burstcnt <= 8'd1; + ddr_addr <= 29'd0; + ctrl_word <= 32'd0; + prev_frame_counter <= 30'd0; + buf_base_addr <= BUF0_ADDR; + cur_line <= 9'd0; + beat_count <= 8'd0; + first_frame_loaded <= 1'b0; + frame_ready_reg <= 1'b0; + preloading <= 1'b0; + timeout_cnt <= 20'd0; + fifo_wr <= 1'b0; + fifo_wr_data <= 64'd0; + fifo_aclr_cnt <= 4'd0; + end + else begin + fifo_wr <= 1'b0; + if(fifo_aclr_cnt != 4'd0) fifo_aclr_cnt <= fifo_aclr_cnt - 4'd1; + if(!ddr_busy) ddr_rd <= 1'b0; + + if(state == ST_WAIT_LINE && ddr_dout_ready) begin + fifo_wr <= 1'b1; + fifo_wr_data <= ddr_dout; + beat_count <= beat_count + 8'd1; + timeout_cnt <= 20'd0; + end + + case(state) + ST_IDLE: begin + if(enable_ddr && new_frame_ddr) state <= ST_POLL_CTRL; + end + + ST_POLL_CTRL: begin + if(!ddr_busy) begin + ddr_addr <= CTRL_ADDR; + ddr_burstcnt <= 8'd1; + ddr_rd <= 1'b1; + timeout_cnt <= 20'd0; + state <= ST_WAIT_CTRL; + end + end + + ST_WAIT_CTRL: begin + if(ddr_dout_ready) begin + ctrl_word <= ddr_dout[31:0]; + timeout_cnt <= 20'd0; + state <= ST_CHECK_CTRL; + end + else if(timeout_cnt == TIMEOUT_MAX) state <= ST_IDLE; + else timeout_cnt <= timeout_cnt + 20'd1; + end + + ST_CHECK_CTRL: begin + if(ctrl_word[31:2] != prev_frame_counter) begin + prev_frame_counter <= ctrl_word[31:2]; + buf_base_addr <= ctrl_word[0] ? BUF1_ADDR : BUF0_ADDR; + cur_line <= 9'd0; + preloading <= 1'b1; + fifo_aclr_cnt <= 4'd8; + if(first_frame_loaded) frame_ready_reg <= 1'b1; + state <= ST_READ_LINE; + end + else if(first_frame_loaded) begin + cur_line <= 9'd0; + preloading <= 1'b1; + fifo_aclr_cnt <= 4'd8; + state <= ST_READ_LINE; + end + else begin + state <= ST_IDLE; + end + end + + ST_READ_LINE: begin + if(!ddr_busy && !fifo_aclr_ddr_active) begin + ddr_addr <= buf_base_addr + (cur_line * LINE_STRIDE); + ddr_burstcnt <= LINE_BURST; + ddr_rd <= 1'b1; + beat_count <= 8'd0; + timeout_cnt <= 20'd0; + state <= ST_WAIT_LINE; + end + end + + ST_WAIT_LINE: begin + if(beat_count == LINE_BURST) state <= ST_LINE_DONE; + else if(timeout_cnt == TIMEOUT_MAX) state <= ST_IDLE; + else if(!ddr_dout_ready) timeout_cnt <= timeout_cnt + 20'd1; + end + + ST_LINE_DONE: begin + cur_line <= cur_line + 9'd1; + if(cur_line == V_ACTIVE - 9'd1) begin + first_frame_loaded <= 1'b1; + frame_ready_reg <= 1'b1; + preloading <= 1'b0; + state <= ST_IDLE; + end + else if(preloading && cur_line < 9'd1) begin + state <= ST_READ_LINE; + end + else begin + preloading <= 1'b0; + state <= ST_WAIT_DISPLAY; + end + end + + ST_WAIT_DISPLAY: begin + if(cur_line < V_ACTIVE && new_line_ddr && !vblank_ddr) state <= ST_READ_LINE; + end + + default: state <= ST_IDLE; + endcase + end +end + +wire [63:0] fifo_rd_data; +wire fifo_empty; +reg fifo_rd; + +dcfifo #( + .intended_device_family ("Cyclone V"), + .lpm_numwords (512), + .lpm_showahead ("ON"), + .lpm_type ("dcfifo"), + .lpm_width (64), + .lpm_widthu (9), + .overflow_checking ("ON"), + .rdsync_delaypipe (4), + .underflow_checking ("ON"), + .use_eab ("ON"), + .wrsync_delaypipe (4) +) line_fifo ( + .aclr (fifo_aclr), + .data (fifo_wr_data), + .rdclk (clk_vid), + .rdreq (fifo_rd), + .wrclk (ddr_clk), + .wrreq (fifo_wr), + .q (fifo_rd_data), + .rdempty (fifo_empty), + .wrfull (fifo_full), + .eccstatus(), + .rdfull (), + .rdusedw (), + .wrempty (), + .wrusedw () +); + +reg [63:0] pixel_word; +reg pixel_high; +reg pixel_word_valid; + +wire [31:0] pixel_low = pixel_word[31:0]; +wire [31:0] pixel_high_word = pixel_word[63:32]; + +task automatic output_pixel; + input [31:0] pixel; + begin + r_out <= pixel[7:0]; + g_out <= pixel[15:8]; + b_out <= pixel[23:16]; + end +endtask + +always @(posedge clk_vid) begin + if(reset_vid) begin + fifo_rd <= 1'b0; + r_out <= 8'd0; + g_out <= 8'd0; + b_out <= 8'd0; + pixel_word <= 64'd0; + pixel_high <= 1'b0; + pixel_word_valid <= 1'b0; + end + else begin + fifo_rd <= 1'b0; + + if(ce_pix) begin + if(de && frame_ready_vid) begin + if(pixel_word_valid) begin + if(pixel_high) begin + output_pixel(pixel_high_word); + pixel_word_valid <= 1'b0; + pixel_high <= 1'b0; + end + else begin + output_pixel(pixel_low); + pixel_high <= 1'b1; + end + end + else if(!fifo_empty) begin + pixel_word <= fifo_rd_data; + pixel_word_valid <= 1'b1; + pixel_high <= 1'b1; + fifo_rd <= 1'b1; + output_pixel(fifo_rd_data[31:0]); + end + else begin + r_out <= 8'd0; + g_out <= 8'd0; + b_out <= 8'd0; + end + end + else begin + r_out <= 8'd0; + g_out <= 8'd0; + b_out <= 8'd0; + pixel_high <= 1'b0; + pixel_word_valid <= 1'b0; + end + end + end +end + +endmodule diff --git a/rtl/native_video_timing.sv b/rtl/native_video_timing.sv new file mode 100644 index 0000000..54a2aee --- /dev/null +++ b/rtl/native_video_timing.sv @@ -0,0 +1,96 @@ +// Zaparoo native video timing: 320x240 at 15.734 kHz from 27 MHz / 4. + +module native_video_timing +( + input wire clk, + input wire ce_pix, + input wire reset, + + output reg hsync, + output reg vsync, + output reg hblank, + output reg vblank, + output reg de, + output reg [9:0] hcount, + output reg [8:0] vcount, + output reg new_frame, + output reg new_line +); + +localparam [9:0] H_ACTIVE = 10'd320; +localparam [9:0] H_FP = 10'd14; +localparam [5:0] H_SYNC = 6'd32; +localparam [9:0] H_BP = 10'd63; +localparam [9:0] H_TOTAL = 10'd429; + +localparam [8:0] V_ACTIVE = 9'd240; +localparam [8:0] V_FP = 9'd6; +localparam [4:0] V_SYNC = 5'd3; +localparam [8:0] V_BP = 9'd13; +localparam [8:0] V_TOTAL = 9'd262; + +localparam [9:0] H_SYNC_START = H_ACTIVE + H_FP; +localparam [9:0] H_SYNC_END = H_SYNC_START + H_SYNC; +localparam [8:0] V_SYNC_START = V_ACTIVE + V_FP; +localparam [8:0] V_SYNC_END = V_SYNC_START + V_SYNC; + +always @(posedge clk) begin + if(reset) begin + hcount <= 10'd0; + vcount <= 9'd0; + hsync <= 1'b0; + vsync <= 1'b0; + hblank <= 1'b0; + vblank <= 1'b0; + de <= 1'b1; + new_frame <= 1'b0; + new_line <= 1'b0; + end + else if(ce_pix) begin + reg next_hblank; + reg next_vblank; + + new_frame <= 1'b0; + new_line <= 1'b0; + + if(hcount == H_TOTAL - 10'd1) begin + hcount <= 10'd0; + if(vcount == V_TOTAL - 9'd1) vcount <= 9'd0; + else vcount <= vcount + 9'd1; + end + else begin + hcount <= hcount + 10'd1; + end + + if(hcount == H_ACTIVE - 10'd1) hblank <= 1'b1; + else if(hcount == H_TOTAL - 10'd1) hblank <= 1'b0; + + if(hcount == H_SYNC_START - 10'd1) hsync <= 1'b1; + else if(hcount == H_SYNC_END - 10'd1) hsync <= 1'b0; + + if(hcount == H_TOTAL - 10'd1) begin + if(vcount == V_ACTIVE - 9'd1) vblank <= 1'b1; + else if(vcount == V_TOTAL - 9'd1) vblank <= 1'b0; + + if(vcount == V_SYNC_START - 9'd1) vsync <= 1'b1; + else if(vcount == V_SYNC_END - 9'd1) vsync <= 1'b0; + end + + if(hcount == H_ACTIVE - 10'd1) new_line <= 1'b1; + if(hcount == H_TOTAL - 10'd1 && vcount == V_ACTIVE - 9'd1) new_frame <= 1'b1; + + next_hblank = hblank; + if(hcount == H_ACTIVE - 10'd1) next_hblank = 1'b1; + else if(hcount == H_TOTAL - 10'd1) next_hblank = 1'b0; + + next_vblank = vblank; + if(hcount == H_TOTAL - 10'd1) begin + if(vcount == V_ACTIVE - 9'd1) next_vblank = 1'b1; + else if(vcount == V_TOTAL - 9'd1) next_vblank = 1'b0; + end + + de <= ~next_hblank & ~next_vblank; + end +end + +endmodule diff --git a/rtl/native_video_top.sv b/rtl/native_video_top.sv new file mode 100644 index 0000000..de4c0f9 --- /dev/null +++ b/rtl/native_video_top.sv @@ -0,0 +1,96 @@ +// Zaparoo native video wrapper: timing + RGBX8888 DDR reader. + +module native_video_top +( + input wire clk_sys, + input wire clk_vid, + input wire ce_pix, + input wire reset, + + input wire ddr_busy, + output wire [7:0] ddr_burstcnt, + output wire [28:0] ddr_addr, + input wire [63:0] ddr_dout, + input wire ddr_dout_ready, + output wire ddr_rd, + output wire [63:0] ddr_din, + output wire [7:0] ddr_be, + output wire ddr_we, + + output wire [7:0] vga_r, + output wire [7:0] vga_g, + output wire [7:0] vga_b, + output wire vga_hs, + output wire vga_vs, + output wire vga_de, + output wire vga_hblank, + output wire vga_vblank, + + input wire enable, + output wire active +); + +wire tim_hs; +wire tim_vs; +wire tim_hblank; +wire tim_vblank; +wire tim_de; +wire [8:0] tim_vcount; +wire tim_new_frame; +wire tim_new_line; + +native_video_timing timing +( + .clk (clk_vid), + .ce_pix (ce_pix), + .reset (reset), + .hsync (tim_hs), + .vsync (tim_vs), + .hblank (tim_hblank), + .vblank (tim_vblank), + .de (tim_de), + .hcount (), + .vcount (tim_vcount), + .new_frame (tim_new_frame), + .new_line (tim_new_line) +); + +wire frame_ready; + +native_video_reader reader +( + .ddr_clk (clk_sys), + .ddr_busy (ddr_busy), + .ddr_burstcnt (ddr_burstcnt), + .ddr_addr (ddr_addr), + .ddr_dout (ddr_dout), + .ddr_dout_ready (ddr_dout_ready), + .ddr_rd (ddr_rd), + .ddr_din (ddr_din), + .ddr_be (ddr_be), + .ddr_we (ddr_we), + + .clk_vid (clk_vid), + .ce_pix (ce_pix), + .reset (reset), + .de (tim_de), + .vblank (tim_vblank), + .new_frame (tim_new_frame), + .new_line (tim_new_line), + .vcount (tim_vcount), + + .r_out (vga_r), + .g_out (vga_g), + .b_out (vga_b), + .enable (enable), + .frame_ready (frame_ready) +); + +assign vga_hs = tim_hs; +assign vga_vs = tim_vs; +assign vga_de = tim_de; +assign vga_hblank = tim_hblank; +assign vga_vblank = tim_vblank; +assign active = enable & frame_ready; + +endmodule diff --git a/rtl/pll/pll_0002.v b/rtl/pll/pll_0002.v index 7320a57..0cae699 100644 --- a/rtl/pll/pll_0002.v +++ b/rtl/pll/pll_0002.v @@ -25,7 +25,7 @@ module pll_0002( .output_clock_frequency0("100.000000 MHz"), .phase_shift0("0 ps"), .duty_cycle0(50), - .output_clock_frequency1("20.000000 MHz"), + .output_clock_frequency1("27.000000 MHz"), .phase_shift1("0 ps"), .duty_cycle1(50), .output_clock_frequency2("0 MHz"), From c5349c451da726893543a234b590ad5c8b254ad9 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Thu, 7 May 2026 22:23:08 +0200 Subject: [PATCH 2/3] Fix output clock frequency in pll_0002 module --- rtl/pll/pll_0002.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtl/pll/pll_0002.v b/rtl/pll/pll_0002.v index 0cae699..4c7ed14 100644 --- a/rtl/pll/pll_0002.v +++ b/rtl/pll/pll_0002.v @@ -25,7 +25,7 @@ module pll_0002( .output_clock_frequency0("100.000000 MHz"), .phase_shift0("0 ps"), .duty_cycle0(50), - .output_clock_frequency1("27.000000 MHz"), + .output_clock_frequency1("27027027 Hz"), .phase_shift1("0 ps"), .duty_cycle1(50), .output_clock_frequency2("0 MHz"), From 5363e381eaa5bc23bae4418942db1234c6e6fbde Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Fri, 8 May 2026 09:08:21 +0200 Subject: [PATCH 3/3] swap channels --- rtl/native_video_reader.sv | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rtl/native_video_reader.sv b/rtl/native_video_reader.sv index 66e4ae7..1931028 100644 --- a/rtl/native_video_reader.sv +++ b/rtl/native_video_reader.sv @@ -278,9 +278,11 @@ wire [31:0] pixel_high_word = pixel_word[63:32]; task automatic output_pixel; input [31:0] pixel; begin - r_out <= pixel[7:0]; + // linuxfb write path lands as B,G,R,X in DDR on MiSTer; swap here + // so launcher can keep doing row memcpy with no CPU-side repack. + r_out <= pixel[23:16]; g_out <= pixel[15:8]; - b_out <= pixel[23:16]; + b_out <= pixel[7:0]; end endtask