X-Git-Url: http://git.joshuawise.com/fpgaboy.git/blobdiff_plain/f9000d73c8971e2e6323122efb06bcfd846b5d62..537e1f833b8eba858c06053ea6006ea608b9a5cc:/LCDC.v diff --git a/LCDC.v b/LCDC.v new file mode 100644 index 0000000..41b5500 --- /dev/null +++ b/LCDC.v @@ -0,0 +1,104 @@ +`define ADDR_LCDC 16'hFF40 +`define ADDR_STAT 16'hFF41 +`define ADDR_SCY 16'hFF42 +`define ADDR_SCX 16'hFF43 +`define ADDR_LY 16'hFF44 +`define ADDR_LYC 16'hFF45 +`define ADDR_DMA 16'hFF46 +`define ADDR_BGP 16'hFF47 +`define ADDR_OBP0 16'hFF48 +`define ADDR_OBP1 16'hFF49 +`define ADDR_WY 16'hFF4A +`define ADDR_WX 16'hFF4B + +module LCDC( + input [15:0] addr, + inout [7:0] data, + input clk, // 8MHz clock + input wr, rd, + output reg irq = 0); + + /***** Internal clock that is stable and does not depend on CPU in single/double clock mode *****/ + reg clk4 = 0; + always @(posedge clk) + clk4 = ~clk4; + + /***** Sync generation *****/ + + /* A complete cycle takes 456 clocks. + * VBlank lasts 4560 clocks (10 scanlines) -- LY = 144 - 153. + * + * Modes: 0 -> in hblank and OAM/VRAM available - present 207 clks + * 1 -> in vblank and OAM/VRAM available + * 2 -> OAM in use - present 83 clks + * 3 -> OAM/VRAM in use - present 166 clks + * So, X = 0~165 is HActive, + * X = 166-372 is HBlank, + * X = 373-455 is HWhirrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr. + */ + reg [8:0] posx = 9'h000; + reg [7:0] posy = 8'h00; + wire [1:0] mode = (posy < 144) ? + ((posx < 166) ? 2'b11 : + (posx < 373) ? 2'b00 : + 2'b10) + : 2'b01; + + always @(posedge clk) + begin + if (posx == 455) begin + posx <= 0; + if (posy == 153) + posy <= 0; + else + posy <= posy + 1; + end else + posx <= posx + 1; + end + + /***** Bus interface *****/ + reg [7:0] rLCDC = 8'h91; + reg [7:0] rSTAT = 8'h00; + reg [7:0] rSCY = 8'b00; + reg [7:0] rSCX = 8'b00; + reg [7:0] rLYC = 8'b00; + reg [7:0] rDMA = 8'b00; + reg [7:0] rBGP = 8'b00; + reg [7:0] rOBP0 = 8'b00; + reg [7:0] rOBP1 = 8'b00; + reg [7:0] rWY = 8'b00; + reg [7:0] rWX = 8'b00; + + assign data = rd ? + (addr == `ADDR_LCDC) ? rLCDC : + (addr == `ADDR_STAT) ? {rSTAT[7:3], (rLYC == posy) ? 1'b1 : 1'b0, mode} : + (addr == `ADDR_SCY) ? rSCY : + (addr == `ADDR_SCX) ? rSCX : + (addr == `ADDR_LY) ? posy : + (addr == `ADDR_LYC) ? rLYC : + (addr == `ADDR_BGP) ? rBGP : + (addr == `ADDR_OBP0) ? rOBP0 : + (addr == `ADDR_OBP1) ? rOBP1 : + (addr == `ADDR_WY) ? rWY : + (addr == `ADDR_WX) ? rWX : + 8'bzzzzzzzz : + 8'bzzzzzzzz; + + always @(negedge clk) + begin + if (wr) + case (addr) + `ADDR_LCDC: rLCDC <= data; + `ADDR_STAT: rSTAT <= {data[7:2],rSTAT[1:0]}; + `ADDR_SCY: rSCY <= data; + `ADDR_SCX: rSCX <= data; + `ADDR_LYC: rLYC <= data; + `ADDR_DMA: rDMA <= data; + `ADDR_BGP: rBGP <= data; + `ADDR_OBP0: rOBP0 <= data; + `ADDR_OBP1: rOBP1 <= data; + `ADDR_WY: rWY <= data; + `ADDR_WX: rWX <= data; + endcase + end +endmodule