module video(input pixclk, input reset, input [15:0] pixels, output reg req_pix, input ack_pix, output _hsync, output _vsync, output [3:0] red, output [3:0] green, output [3:0] blue, output hblank); /* Max coordinate size in bits - 1 */ parameter csize = 9; /* Fixed CRTC params for now. Based on a 640x480 VGA signal with * added borders to center the Mac's 512x342. * * The added border is 64 pixels left and right and 69 pixels top * and bottom. * * The constants are used as count-down and thus include a -1 to * account for the 0 state. */ parameter hdisp_frontp = 8 - 1; parameter hdisp_hsync = 96 - 1; parameter hdisp_backp = 40 - 1; parameter hdisp_lbord = 8 + 64 - 1; parameter hdisp_display = 512 - 1; parameter hdisp_rbord = 8 + 64 - 1; parameter vdisp_frontp = 2 - 1; parameter vdisp_vsync = 2 - 1; parameter vdisp_backp = 25 - 1; parameter vdisp_tbord = 8 + 69 - 1; parameter vdisp_display = 342 - 1; parameter vdisp_bbord = 8 + 69 - 1; /* Corresponding stages */ localparam hstage_frontp = 0; localparam hstage_hsync = 1; localparam hstage_backp = 2; localparam hstage_lbord = 3; localparam hstage_display = 4; localparam hstage_rbord = 5; localparam vstage_frontp = 0; localparam vstage_vsync = 1; localparam vstage_backp = 2; localparam vstage_tbord = 3; localparam vstage_display = 4; localparam vstage_bbord = 5; /* Running h/v counters */ reg [csize:0] hcnt; reg [csize:0] vcnt; reg [csize:0] hnextcnt; reg [csize:0] vnextcnt; /* State machines */ reg [2:0] hstage; reg [2:0] vstage; /* Output latches */ reg _hsync_r; reg _vsync_r; reg pix_r; /* Pixel shift reg */ reg [15:0] pix_shift; wire vid_on; /* Request/ack protocol helpers */ wire pix_req_reset; /* Obtain the new count for the next stage */ always@(hstage) begin case(hstage) hstage_frontp: hnextcnt = hdisp_hsync; hstage_hsync: hnextcnt = hdisp_backp; hstage_backp: hnextcnt = hdisp_lbord; hstage_lbord: hnextcnt = hdisp_display; hstage_display: hnextcnt = hdisp_rbord; hstage_rbord: hnextcnt = hdisp_frontp; default: hnextcnt = hdisp_frontp; endcase end always@(vstage) begin case(vstage) vstage_frontp: vnextcnt = vdisp_vsync; vstage_vsync: vnextcnt = vdisp_backp; vstage_backp: vnextcnt = vdisp_tbord; vstage_tbord: vnextcnt = vdisp_display; vstage_display: vnextcnt = vdisp_bbord; vstage_bbord: vnextcnt = vdisp_frontp; default: vnextcnt = vdisp_frontp; endcase end /* H counter */ always@(posedge pixclk or posedge reset) begin if (reset) begin hcnt <= 0; hstage <= hstage_frontp; end else begin if (hcnt == 0) begin hcnt <= hnextcnt; if (hstage == hstage_rbord) hstage <= hstage_frontp; else hstage <= hstage + 1; end else hcnt <= hcnt - 1; end end /* V counter */ always@(posedge pixclk or posedge reset) begin if (reset) begin vcnt <= 0; vstage <= vstage_frontp; end else begin if (hstage == hstage_rbord && hcnt == 0) begin if (vcnt == 0) begin vcnt <= vnextcnt; if (vstage == vstage_bbord) vstage <= vstage_frontp; else vstage <= vstage + 1; end else begin vcnt <= vcnt - 1; end end end end /* Visible signal */ assign vid_on = hstage == hstage_display && vstage == vstage_display; /* Pixel request, async clear */ assign pix_req_reset = reset | ack_pix; /* Generate pixel request. NOTE: This relies on the display * width being a multiple of 16 */ always@(posedge pixclk or posedge pix_req_reset) begin if (pix_req_reset) begin req_pix <= 0; end else begin if (vstage == vstage_display) begin if (hstage == hstage_backp && hcnt == 0) begin req_pix <= 1; end else if (hstage == hstage_display && hcnt[3:0] == 4'b1111 && hcnt[csize:4]) begin req_pix <= 1; end end end end /* Shift register */ always@(posedge pixclk or posedge reset) begin if (reset) begin pix_shift <= 0; end else begin if (hcnt[3:0] == 0) pix_shift <= pixels; else pix_shift[15:1] <= pix_shift[14:0]; end end /* Output latches */ always@(posedge pixclk or posedge reset) begin if (reset) begin _hsync_r <= 1; _vsync_r <= 1; pix_r <= 0; end else begin _hsync_r <= ~(hstage == hstage_hsync); _vsync_r <= ~(vstage == vstage_vsync); pix_r <= vid_on & ~pix_shift[15]; end end /* Output wires */ assign _hsync = _hsync_r; assign _vsync = _vsync_r; assign red = { pix_r, pix_r, pix_r, pix_r }; assign green = { pix_r, pix_r, pix_r, pix_r }; assign blue = { pix_r, pix_r, pix_r, pix_r }; assign hblank = hstage != hstage_display; endmodule