From e6dea2f614e2624e10aea316a448b29a4b39c4fb Mon Sep 17 00:00:00 2001 From: rattboi Date: Mon, 6 May 2019 09:50:53 -0700 Subject: [PATCH] Dual HDMI/Analog output #37 * Parameterized LCD module to allow for padding * Removed 4x vertical multiply stuff in lcd/top-level --- Gameboy.sv | 35 +++++----- lcd.v | 193 +++++++++++++++++++++++------------------------------ 2 files changed, 98 insertions(+), 130 deletions(-) diff --git a/Gameboy.sv b/Gameboy.sv index 729bc46..fdf86d4 100644 --- a/Gameboy.sv +++ b/Gameboy.sv @@ -568,8 +568,8 @@ gb gb ( wire [7:0] video_r, video_g, video_b; wire video_hs, video_vs, video_bl; -lcd lcd ( - .pclk ( clk_sys_old), +lcd #(80, 80, 48, 48) lcd ( + .pclk ( clk_sys ), .pce ( ce_pix ), .clk ( clk_cpu ), .isGBC ( isGBC ), @@ -603,25 +603,32 @@ assign VGA_G = video_g; assign VGA_B = video_b; assign VGA_DE = ~video_bl; assign CLK_VIDEO = clk_sys; -assign CE_PIXEL = ce_pix & !line_cnt; +assign CE_PIXEL = ce_pix; assign VGA_HS = video_hs; assign VGA_VS = video_vs; -wire clk_sys_old = clk_sys & ce_sys; -wire ce_cpu2x = ce_pix; wire clk_cpu = clk_sys & ce_cpu; -wire clk_cpu2x = clk_sys & ce_pix; +wire clk_cpu2x = clk_sys & ce_cpu2x; -reg ce_pix, ce_cpu,ce_sys; +reg ce_pix, ce_cpu, ce_cpu2x, ce_sys; always @(negedge clk_sys) begin reg [3:0] div = 0; div <= div + 1'd1; ce_sys <= !div[0]; - ce_pix <= !div[2:0]; + ce_cpu2x <= !div[2:0]; ce_cpu <= !div[3:0]; end +always @(negedge clk_sys) begin + reg [4:0] div = 0; + + div <= div + 1; + if (div == 5'd10) + div <= 0; + ce_pix <= !div; +end + ///////////////////////////// GBC BIOS ///////////////////////////////// @@ -803,16 +810,4 @@ always @(posedge clk_sys) begin end end -reg [1:0] line_cnt; -always @(posedge clk_sys_old) begin - reg old_hs; - reg old_vs; - - old_vs <= video_vs; - old_hs <= video_hs; - - if(old_hs & ~video_hs) line_cnt <= line_cnt + 1'd1; - if(old_vs & ~video_vs) line_cnt <= 0; -end - endmodule diff --git a/lcd.v b/lcd.v index 79792f8..af91dfa 100644 --- a/lcd.v +++ b/lcd.v @@ -3,13 +3,23 @@ // The gameboy lcd runs from a shift register which is filled at 4194304 pixels/sec -module lcd ( - input clk, - input clkena, +module lcd #( + parameter HPRE=0, + parameter HPOST=0, + parameter VPRE=0, + parameter VPOST=0 +) +( + // pixel clock + input pclk, + input pce, + + input clk, + input clkena, input [14:0] data, - input [1:0] mode, - input isGBC, - + input [1:0] mode, + input on, + //palette input [23:0] pal1, input [23:0] pal2, @@ -18,30 +28,22 @@ module lcd ( input tint, input inv, + input isGBC, - // pixel clock - input pclk, - input pce, - input on, - - // VGA output + // video output output reg hs, - output reg vs, - output reg blank, + output reg vs, + output reg blank, output [7:0] r, output [7:0] g, output [7:0] b ); - reg [14:0] vbuffer_inptr; -reg vbuffer_write; reg [14:0] vbuffer_outptr; reg [14:0] vbuffer_lineptr; - -//image buffer 160x144x2bits for now , later 15bits for cgb dpram #(15,15) vbuffer ( .clock_a (clk), .address_a (vbuffer_inptr), @@ -57,67 +59,47 @@ dpram #(15,15) vbuffer ( ); always @(posedge clk) begin - if(!on || (mode==2'd01)) begin //lcd disabled of vsync restart pointer + if(!on || (mode==2'd01)) begin //lcd disabled or vsync restart pointer vbuffer_inptr <= 15'h0; end else begin - - // end of vsync - if(clkena) begin - vbuffer_inptr <= vbuffer_inptr + 15'd1; - end - - end; -end - - -// Mode 00: h-blank -// Mode 01: v-blank -// Mode 10: oam -// Mode 11: oam and vram - -// -parameter H = 160; // width of visible area -parameter HFP = 16; // unused time before hsync -parameter HS = 20; // width of hsync -parameter HBP = 32; // unused time after hsync -// total = 228 - -parameter V = 576; // height of visible area -parameter VFP = 2; // unused time before vsync -parameter VS = 2; // width of vsync -parameter VBP = 36; // unused time after vsync -// total = 616 - -reg[7:0] h_cnt; // horizontal pixel counter -reg[9:0] v_cnt; // vertical pixel counter - -// horizontal pixel counter -reg [1:0] last_mode_h; -always@(posedge pclk) begin - if(pce) begin - - if(h_cnt==H+HFP+HS+HBP-1) h_cnt <= 0; - else h_cnt <= h_cnt + 1'd1; - - // generate positive hsync signal - if(h_cnt == H+HFP) hs <= 1'b1; - if(h_cnt == H+HFP+HS) hs <= 1'b0; - + if(clkena) vbuffer_inptr <= vbuffer_inptr + 15'd1; // end of vsync end end -// veritical pixel counter -reg [1:0] last_mode_v; +parameter H = 160; // width of visible area +parameter HFP = 8; // unused time before hsync +parameter HS = 32; // width of hsync +parameter HBP = 24; // unused time after hsync + +parameter V = 144; // height of visible area +parameter VFP = 4; // unused time before vsync +parameter VS = 3; // width of vsync +parameter VBP = 16; // unused time after vsync + +reg[8:0] h_cnt; // horizontal pixel counter +reg[8:0] v_cnt; // vertical pixel counter + +// horizontal pixel counter +always@(posedge pclk) begin + if(pce) begin + if(h_cnt==HPRE+H+HPOST+HFP+HS+HBP-1) h_cnt <= 0; + else h_cnt <= h_cnt + 1'd1; + // generate positive hsync signal + if(h_cnt == HPRE+H+HPOST+HFP) hs <= 1'b1; + if(h_cnt == HPRE+H+HPOST+HFP+HS) hs <= 1'b0; + end +end + +// vertical pixel counter always@(posedge pclk) begin if(pce) begin // the vertical counter is processed at the begin of each hsync - if(h_cnt == H+HFP+HS+HBP-1) begin - if(v_cnt==VS+VFP+V+VBP-1) v_cnt <= 0; - else v_cnt <= v_cnt + 1'd1; - + if(h_cnt == HPRE+H+HPOST+HFP+HS+HBP-1) begin + if(v_cnt==VPRE+V+VPOST+VFP+VS+VBP-1) v_cnt <= 0; + else v_cnt <= v_cnt + 1'd1; // generate positive vsync signal - if(v_cnt == V+VFP) vs <= 1'b1; - if(v_cnt == V+VFP+VS) vs <= 1'b0; + if(v_cnt == VPRE+V+VPOST+VFP) vs <= 1'b1; + if(v_cnt == VPRE+V+VPOST+VFP+VS) vs <= 1'b0; end end end @@ -127,62 +109,52 @@ end // ------------------------------------------------------------------------------- reg [14:0] pixel_reg; +wire prepost = (v_cnt < VPRE) || (v_cnt >= VPRE+V) || (h_cnt < HPRE) || (h_cnt >= HPRE+H); + always@(posedge pclk) begin if(pce) begin // visible area? - if((v_cnt < V) && (h_cnt < H)) begin - blank <= 1'b0; - end else begin - blank <= 1'b1; - end + blank <= prepost; end end - -reg [7:0] currentpixel; -reg [1:0] linecnt; +reg [8:0] currentpixel; always@(posedge pclk) begin - if(pce) begin - if(h_cnt == H+HFP+HS+HBP-1) begin - - //reset output at vsync - if(v_cnt == V+VFP) begin - vbuffer_outptr <= 15'd0; - vbuffer_lineptr <= 15'd0; - currentpixel <= 8'd0; - linecnt <= 2'd3; - end - end else - // visible area? - if((v_cnt < V) && (h_cnt < H)) begin - vbuffer_outptr <= vbuffer_lineptr + currentpixel; - if (currentpixel + 8'd1 == 160) begin - currentpixel <= 8'd0; - linecnt <= linecnt - 2'd1; - - //increment vbuffer_lineptr after 4 lines - if (!linecnt) - vbuffer_lineptr <= vbuffer_lineptr + 15'd160; - end else - currentpixel <= currentpixel + 8'd1; - end + // visible area? + if((v_cnt >= VPRE) && (v_cnt < (VPRE + V))) begin + // visible pixel? + if ((h_cnt >= HPRE) && (h_cnt < (HPRE + H))) begin + currentpixel <= currentpixel + 9'd1; + end else begin + // move to the next line after visible area + if(h_cnt == HPRE+H+HPOST+HFP) begin + vbuffer_lineptr <= vbuffer_lineptr + H; + currentpixel <= 9'd0; + end + end + vbuffer_outptr <= vbuffer_lineptr + currentpixel; + // not visible area, reset pointers + end else begin + vbuffer_outptr <= 15'd0; + vbuffer_lineptr <= 15'd0; + currentpixel <= 9'd0; + end end end - wire [14:0] pixel = on?isGBC?pixel_reg: {13'd0,(pixel_reg[1:0] ^ {inv,inv})}: //invert gb only 15'd0; - wire [4:0] r5 = pixel_reg[4:0]; wire [4:0] g5 = pixel_reg[9:5]; wire [4:0] b5 = pixel_reg[14:10]; -wire [31:0] r10 = (r5 * 13) + (g5 * 2) +b5; -wire [31:0] g10 = (g5 * 3) + b5; -wire [31:0] b10 = (r5 * 3) + (g5 * 2) + (b5 * 11); +wire [31:0] r10 = (r5 * 13) + (g5 * 2) + b5; +wire [31:0] g10 = (g5 * 3) + b5; +wire [31:0] b10 = (r5 * 3) + (g5 * 2) + (b5 * 11); + // gameboy "color" palette wire [7:0] pal_r = //isGBC?{pixel_reg[4:0],3'd0}: @@ -208,8 +180,9 @@ wire [7:0] pal_b = //isGBC?{pixel_reg[14:10],3'd0}: // greyscale wire [7:0] grey = (pixel==0)?8'd252:(pixel==1)?8'd168:(pixel==2)?8'd96:8'd0; -assign r = blank?8'b00000000:tint||isGBC?pal_r:grey; -assign g = blank?8'b00000000:tint||isGBC?pal_g:grey; -assign b = blank?8'b00000000:tint||isGBC?pal_b:grey; + +assign r = blank?8'd0:tint||isGBC?pal_r:grey; +assign g = blank?8'd0:tint||isGBC?pal_g:grey; +assign b = blank?8'd0:tint||isGBC?pal_b:grey; endmodule