blob: d41ce5a38f18e6a82a6b9acdeb91281be2b5a45b [file] [log] [blame]
module VGA #(
parameter ADDRESS_BITS = 13
)(
`ifdef USE_POWER_PINS
inout vccd1, // User area 1 1.8V supply
inout vssd1, // User area 1 digital ground
`endif
input wire clk,
input wire rst,
// Peripheral bus for configuration
input wire peripheralBus_we,
input wire peripheralBus_oe,
output wire peripheralBus_busy,
input wire[23:0] peripheralBus_address,
input wire[3:0] peripheralBus_byteSelect,
input wire[31:0] peripheralBus_dataWrite,
output reg[31:0] peripheralBus_dataRead,
output wire requestOutput,
// Memory interface
input wire vga_clk,
output wire vga_fetchData,
output reg[ADDRESS_BITS-1:0] vga_address,
input wire[31:0] vga_data,
// VGA output
output wire[1:0] vga_r,
output wire[1:0] vga_g,
output wire[1:0] vga_b,
output wire vga_vsync,
output wire vga_hsync
);
// MAX_ROW_WIDTH = 2^ROW_BITS = 64;
// MAX_COLUMN_WIDTH = 2^COLUMN_BITS * (MAX_SUB_PIXEL_VALUE+1) = 80;
localparam VERTICAL_BITS = 7;
localparam HORIZONTAL_BITS = 4;
localparam MAX_SUB_PIXEL_VALUE = 3'h4;
localparam DRAW_MODE_RAW = 2'b00;
localparam DRAW_MODE_RAW_TIGHT_MEM = 2'b01;
localparam DRAW_MODE_COLOUR_PALETTE = 2'b10;
localparam DRAW_MODE_SPRITES = 2'b11;
localparam CONFIG_ADDRESS = 12'h800;
wire configEnable = peripheralBus_address[23:12] == CONFIG_ADDRESS;
wire[11:0] configRegisterAddress = peripheralBus_address[11:0];
// Registers
// Configuration Default 0x0AA
// b00-b03: horizontalPixelSize Default 0xA
// b04-b07: verticalPixelSize Default 0xA
// b08-b09: drawMode Default 0b00
// b10: enableOutput Default 0
wire[10:0] configuration;
wire[31:0] configurationRegisterOutputData;
wire configurationRegisterOutputRequest;
ConfigurationRegister #(.WIDTH(11), .ADDRESS(12'h000), .DEFAULT(11'h0AA)) configurationRegister(
.clk(clk),
.rst(rst),
.enable(configEnable),
.peripheralBus_we(peripheralBus_we),
.peripheralBus_oe(peripheralBus_oe),
.peripheralBus_address(configRegisterAddress),
.peripheralBus_byteSelect(peripheralBus_byteSelect),
.peripheralBus_dataWrite(peripheralBus_dataWrite),
.peripheralBus_dataRead(configurationRegisterOutputData),
.requestOutput(configurationRegisterOutputRequest),
.currentValue(configuration));
wire[3:0] horizontalPixelSize = configuration[3:0];
wire[3:0] verticalPixelSize = configuration[7:4];
wire[1:0] drawMode = configuration[9:8];
wire enableOutput = configuration[10];
// Defaults are timing for 800 x 600 at 60Hz
// http://tinyvga.com/vga-timing/800x600@60Hz
// Horizontal visible area compare Default 799=0x31F
wire[10:0] horizontalVisibleAreaCompare;
wire[31:0] horizontalVisibleAreaCompareRegisterOutputData;
wire horizontalVisibleAreaCompareRegisterOutputRequest;
ConfigurationRegister #(.WIDTH(11), .ADDRESS(12'h010), .DEFAULT(11'h31F)) horizontalVisibleAreaCompareRegister(
.clk(clk),
.rst(rst),
.enable(configEnable),
.peripheralBus_we(peripheralBus_we),
.peripheralBus_oe(peripheralBus_oe),
.peripheralBus_address(configRegisterAddress),
.peripheralBus_byteSelect(peripheralBus_byteSelect),
.peripheralBus_dataWrite(peripheralBus_dataWrite),
.peripheralBus_dataRead(horizontalVisibleAreaCompareRegisterOutputData),
.requestOutput(horizontalVisibleAreaCompareRegisterOutputRequest),
.currentValue(horizontalVisibleAreaCompare));
// Horizontal front porch compare Default 839=0x347
wire[10:0] horizontalFrontPorchCompare;
wire[31:0] horizontalFrontPorchCompareRegisterOutputData;
wire horizontalFrontPorchCompareRegisterOutputRequest;
ConfigurationRegister #(.WIDTH(11), .ADDRESS(12'h014), .DEFAULT(11'h347)) horizontalFrontPorchCompareRegister(
.clk(clk),
.rst(rst),
.enable(configEnable),
.peripheralBus_we(peripheralBus_we),
.peripheralBus_oe(peripheralBus_oe),
.peripheralBus_address(configRegisterAddress),
.peripheralBus_byteSelect(peripheralBus_byteSelect),
.peripheralBus_dataWrite(peripheralBus_dataWrite),
.peripheralBus_dataRead(horizontalFrontPorchCompareRegisterOutputData),
.requestOutput(horizontalFrontPorchCompareRegisterOutputRequest),
.currentValue(horizontalFrontPorchCompare));
// Horizontal sync pulse compare Default 967=0x3C7
wire[10:0] horizontalSyncPulseCompare;
wire[31:0] horizontalSyncPulseCompareRegisterOutputData;
wire horizontalSyncPulseCompareRegisterOutputRequest;
ConfigurationRegister #(.WIDTH(11), .ADDRESS(12'h018), .DEFAULT(11'h3C7)) horizontalSyncPulseCompareRegister(
.clk(clk),
.rst(rst),
.enable(configEnable),
.peripheralBus_we(peripheralBus_we),
.peripheralBus_oe(peripheralBus_oe),
.peripheralBus_address(configRegisterAddress),
.peripheralBus_byteSelect(peripheralBus_byteSelect),
.peripheralBus_dataWrite(peripheralBus_dataWrite),
.peripheralBus_dataRead(horizontalSyncPulseCompareRegisterOutputData),
.requestOutput(horizontalSyncPulseCompareRegisterOutputRequest),
.currentValue(horizontalSyncPulseCompare));
// Horizontal whole line compare Default 1055=0x41F
wire[10:0] horizontalWholeLineCompare;
wire[31:0] horizontalWholeLineCompareRegisterOutputData;
wire horizontalWholeLineCompareRegisterOutputRequest;
ConfigurationRegister #(.WIDTH(11), .ADDRESS(12'h01C), .DEFAULT(11'h41F)) horizontalWholeLineCompareRegister(
.clk(clk),
.rst(rst),
.enable(configEnable),
.peripheralBus_we(peripheralBus_we),
.peripheralBus_oe(peripheralBus_oe),
.peripheralBus_address(configRegisterAddress),
.peripheralBus_byteSelect(peripheralBus_byteSelect),
.peripheralBus_dataWrite(peripheralBus_dataWrite),
.peripheralBus_dataRead(horizontalWholeLineCompareRegisterOutputData),
.requestOutput(horizontalWholeLineCompareRegisterOutputRequest),
.currentValue(horizontalWholeLineCompare));
// Vertical visible area compare Default 599=0x257
wire[9:0] verticalVisibleAreaCompare;
wire[31:0] verticalVisibleAreaCompareRegisterOutputData;
wire verticalVisibleAreaCompareRegisterOutputRequest;
ConfigurationRegister #(.WIDTH(10), .ADDRESS(12'h020), .DEFAULT(11'h257)) verticalVisibleAreaCompareRegister(
.clk(clk),
.rst(rst),
.enable(configEnable),
.peripheralBus_we(peripheralBus_we),
.peripheralBus_oe(peripheralBus_oe),
.peripheralBus_address(configRegisterAddress),
.peripheralBus_byteSelect(peripheralBus_byteSelect),
.peripheralBus_dataWrite(peripheralBus_dataWrite),
.peripheralBus_dataRead(verticalVisibleAreaCompareRegisterOutputData),
.requestOutput(verticalVisibleAreaCompareRegisterOutputRequest),
.currentValue(verticalVisibleAreaCompare));
// Vertical front porch compare Default 600=0x258
wire[9:0] verticalFrontPorchCompare;
wire[31:0] verticalFrontPorchCompareRegisterOutputData;
wire verticalFrontPorchCompareRegisterOutputRequest;
ConfigurationRegister #(.WIDTH(10), .ADDRESS(12'h024), .DEFAULT(11'h258)) verticalFrontPorchCompareRegister(
.clk(clk),
.rst(rst),
.enable(configEnable),
.peripheralBus_we(peripheralBus_we),
.peripheralBus_oe(peripheralBus_oe),
.peripheralBus_address(configRegisterAddress),
.peripheralBus_byteSelect(peripheralBus_byteSelect),
.peripheralBus_dataWrite(peripheralBus_dataWrite),
.peripheralBus_dataRead(verticalFrontPorchCompareRegisterOutputData),
.requestOutput(verticalFrontPorchCompareRegisterOutputRequest),
.currentValue(verticalFrontPorchCompare));
// Vertical sync pulse compare Default 604=0x25C
wire[9:0] verticalSyncPulseCompare;
wire[31:0] verticalSyncPulseCompareRegisterOutputData;
wire verticalSyncPulseCompareRegisterOutputRequest;
ConfigurationRegister #(.WIDTH(10), .ADDRESS(12'h028), .DEFAULT(11'h25C)) verticalSyncPulseCompareRegister(
.clk(clk),
.rst(rst),
.enable(configEnable),
.peripheralBus_we(peripheralBus_we),
.peripheralBus_oe(peripheralBus_oe),
.peripheralBus_address(configRegisterAddress),
.peripheralBus_byteSelect(peripheralBus_byteSelect),
.peripheralBus_dataWrite(peripheralBus_dataWrite),
.peripheralBus_dataRead(verticalSyncPulseCompareRegisterOutputData),
.requestOutput(verticalSyncPulseCompareRegisterOutputRequest),
.currentValue(verticalSyncPulseCompare));
// Vertical whole line compare Default 627=0x273
wire[9:0] verticalWholeLineCompare;
wire[31:0] verticalWholeLineCompareRegisterOutputData;
wire verticalWholeLineCompareRegisterOutputRequest;
ConfigurationRegister #(.WIDTH(10), .ADDRESS(12'h02C), .DEFAULT(11'h273)) verticalWholeLineCompareRegister(
.clk(clk),
.rst(rst),
.enable(configEnable),
.peripheralBus_we(peripheralBus_we),
.peripheralBus_oe(peripheralBus_oe),
.peripheralBus_address(configRegisterAddress),
.peripheralBus_byteSelect(peripheralBus_byteSelect),
.peripheralBus_dataWrite(peripheralBus_dataWrite),
.peripheralBus_dataRead(verticalWholeLineCompareRegisterOutputData),
.requestOutput(verticalWholeLineCompareRegisterOutputRequest),
.currentValue(verticalWholeLineCompare));
// VGA state register
reg inVerticalVisibleArea = 1'b1;
reg inHorizontalVisibleArea = 1'b1;
wire[31:0] stateRegisterOutputData;
wire stateRegisterOutputRequest;
wire stateReadDataEnable_nc;
wire stateRegisterBusyBusy_nc;
wire[4:0] stateRegisterWriteData_nc;
wire stateRegisterWriteDataEnable_nc;
DataRegister #(.WIDTH(5), .ADDRESS(12'h030)) stateRegister(
.clk(clk),
.rst(rst),
.enable(configEnable),
.peripheralBus_we(peripheralBus_we),
.peripheralBus_oe(peripheralBus_oe),
.peripheralBus_busy(stateRegisterBusyBusy_nc),
.peripheralBus_address(configRegisterAddress),
.peripheralBus_byteSelect(peripheralBus_byteSelect),
.peripheralBus_dataWrite(peripheralBus_dataWrite),
.peripheralBus_dataRead(stateRegisterOutputData),
.requestOutput(stateRegisterOutputRequest),
.writeData(stateRegisterWriteData_nc),
.writeData_en(stateRegisterWriteDataEnable_nc),
.writeData_busy(1'b0),
.readData({ inVerticalVisibleArea, inHorizontalVisibleArea, !vga_vsync, !vga_hsync, enableOutput }),
.readData_en(stateReadDataEnable_nc),
.readData_busy(1'b0));
assign peripheralBus_busy = 1'b0;
assign requestOutput = configurationRegisterOutputRequest
|| horizontalVisibleAreaCompareRegisterOutputRequest
|| horizontalFrontPorchCompareRegisterOutputRequest
|| horizontalSyncPulseCompareRegisterOutputRequest
|| horizontalWholeLineCompareRegisterOutputRequest
|| verticalVisibleAreaCompareRegisterOutputRequest
|| verticalFrontPorchCompareRegisterOutputRequest
|| verticalSyncPulseCompareRegisterOutputRequest
|| verticalWholeLineCompareRegisterOutputRequest
|| stateRegisterOutputRequest;
always @(*) begin
case (1'b1)
configurationRegisterOutputRequest:
peripheralBus_dataRead <= configurationRegisterOutputData;
horizontalVisibleAreaCompareRegisterOutputRequest:
peripheralBus_dataRead <= horizontalVisibleAreaCompareRegisterOutputData;
horizontalFrontPorchCompareRegisterOutputRequest:
peripheralBus_dataRead <= horizontalFrontPorchCompareRegisterOutputData;
horizontalSyncPulseCompareRegisterOutputRequest:
peripheralBus_dataRead <= horizontalSyncPulseCompareRegisterOutputData;
horizontalWholeLineCompareRegisterOutputRequest:
peripheralBus_dataRead <= horizontalWholeLineCompareRegisterOutputData;
verticalVisibleAreaCompareRegisterOutputRequest:
peripheralBus_dataRead <= verticalVisibleAreaCompareRegisterOutputData;
verticalFrontPorchCompareRegisterOutputRequest:
peripheralBus_dataRead <= verticalFrontPorchCompareRegisterOutputData;
verticalSyncPulseCompareRegisterOutputRequest:
peripheralBus_dataRead <= verticalSyncPulseCompareRegisterOutputData;
verticalWholeLineCompareRegisterOutputRequest:
peripheralBus_dataRead <= verticalWholeLineCompareRegisterOutputData;
stateRegisterOutputRequest:
peripheralBus_dataRead <= stateRegisterOutputData;
default: peripheralBus_dataRead <= ~32'b0;
endcase
end
// VGA sync signal generations
reg[10:0] horizontalCounter;
wire isEndHorizontalVisibleArea = horizontalCounter == horizontalVisibleAreaCompare;
wire isEndHorizontalFrontPorch = horizontalCounter == horizontalFrontPorchCompare;
wire isEndHorizontalSyncPulse = horizontalCounter == horizontalSyncPulseCompare;
wire isEndHorizontalWholeLine = horizontalCounter == horizontalWholeLineCompare;
reg hsync;
always @(posedge vga_clk) begin
if (rst || !enableOutput) begin
horizontalCounter <= 10'b0;
inHorizontalVisibleArea <= 1'b1;
hsync <= 1'b1;
end else begin
if (isEndHorizontalWholeLine) horizontalCounter <= 10'b0;
else horizontalCounter <= horizontalCounter + 1;
if (isEndHorizontalVisibleArea) inHorizontalVisibleArea <= 1'b0;
else if (isEndHorizontalWholeLine) inHorizontalVisibleArea <= 1'b1;
if (isEndHorizontalFrontPorch) hsync <= 1'b0;
else if (isEndHorizontalSyncPulse) hsync <= 1'b1;
end
end
reg[9:0] verticalCounter;
wire isEndVerticalVisibleArea = verticalCounter == verticalVisibleAreaCompare;
wire isEndVerticalFrontPorch = verticalCounter == verticalFrontPorchCompare;
wire isEndVerticalSyncPulse = verticalCounter == verticalSyncPulseCompare;
wire isEndVerticalWholeLine = verticalCounter == verticalWholeLineCompare;
reg vsync;
always @(posedge vga_clk) begin
if (rst || !enableOutput) begin
verticalCounter <= 10'b0;
inVerticalVisibleArea <= 1'b1;
vsync <= 1'b1;
end else begin
if (isEndHorizontalWholeLine) begin
if (isEndVerticalWholeLine) verticalCounter <= 10'b0;
else verticalCounter <= verticalCounter + 1;
if (isEndVerticalVisibleArea) inVerticalVisibleArea <= 1'b0;
else if (isEndVerticalWholeLine) inVerticalVisibleArea <= 1'b1;
if (isEndVerticalFrontPorch) vsync <= 1'b0;
else if (isEndVerticalSyncPulse) vsync <= 1'b1;
end
end
end
// Latch data in from sram and delay sync signals
// Data timing
// c0: pixel counter increments, sync signal set, and address is set
// c1: data is valid
reg loadPixel;
reg[1:0] hsyncDelay;
reg[1:0] vsyncDelay;
reg[31:0] currentPixelData;
always @(posedge vga_clk) begin
if (rst || !enableOutput) begin
currentPixelData <= 1'b0;
hsyncDelay <= 2'b11;
vsyncDelay <= 2'b11;
end else begin
if (loadPixel) currentPixelData <= vga_data;
hsyncDelay <= { hsyncDelay[0], hsync };
vsyncDelay <= { vsyncDelay[0], vsync };
end
end
assign vga_fetchData = loadPixel;
assign vga_hsync = enableOutput ? hsyncDelay[1] : 1'b1;
assign vga_vsync = enableOutput ? vsyncDelay[1] : 1'b1;
// VGA pixel address select
reg[17:0] raw_directPixelCounter;
reg[17:0] raw_directPixelCounter_d;
wire[17:0] raw_nextDirectPixelCounter = raw_directPixelCounter + 1;
reg[8:0] raw_horizontalPixelCounter;
reg[9:0] raw_verticalPixelCounter;
reg[2:0] raw_subPixelCounter;
reg[8:0] raw_horizontalPixelCounter_d;
reg[9:0] raw_verticalPixelCounter_d;
reg[2:0] raw_subPixelCounter_d;
reg[3:0] raw_horizontalPixelStretchCounter = 4'b0;
reg[3:0] raw_horizontalPixelStretchCounter_d;
wire[3:0] raw_nextHorizontalPixelStretchCounter = raw_horizontalPixelStretchCounter + 1;
reg[3:0] raw_verticalPixelStretchCounter = 4'b0;
reg[3:0] raw_verticalPixelStretchCounter_d;
wire[3:0] raw_nextVerticalPixelStretchCounter = raw_verticalPixelStretchCounter + 1;
wire raw_horizontalPixelStretchNextPixel = raw_horizontalPixelStretchCounter == horizontalPixelSize;
wire raw_verticalPixelStretchNextPixel = raw_verticalPixelStretchCounter == verticalPixelSize;
// Raw draw mode
always @(*) begin
if (inVerticalVisibleArea) begin
if (inHorizontalVisibleArea) begin
if (raw_horizontalPixelStretchNextPixel) begin
if (raw_subPixelCounter == MAX_SUB_PIXEL_VALUE) begin
raw_subPixelCounter_d <= 3'b0;
raw_horizontalPixelCounter_d <= raw_horizontalPixelCounter + 1;
raw_directPixelCounter_d <= raw_nextDirectPixelCounter;
end else begin
raw_subPixelCounter_d <= raw_subPixelCounter + 1;
end
raw_horizontalPixelStretchCounter_d <= 4'b0;
end else begin
raw_horizontalPixelStretchCounter_d <= raw_nextHorizontalPixelStretchCounter;
end
end else begin
raw_subPixelCounter_d <= 3'b0;
raw_horizontalPixelCounter_d <= 9'b0;
raw_horizontalPixelStretchCounter_d <= 4'b0;
end
if (isEndHorizontalWholeLine) begin
raw_directPixelCounter_d <= raw_nextDirectPixelCounter;
if (raw_verticalPixelStretchNextPixel) begin
raw_verticalPixelCounter_d <= raw_verticalPixelCounter + 1;
raw_verticalPixelStretchCounter_d <= 4'b0;
end else begin
raw_verticalPixelStretchCounter_d <= raw_nextVerticalPixelStretchCounter;
end
end
end else begin
raw_directPixelCounter_d <= 18'b0;
raw_subPixelCounter_d <= 3'b0;
raw_horizontalPixelCounter_d <= 9'b0;
raw_horizontalPixelStretchCounter_d <= 4'b0;
raw_verticalPixelCounter_d <= 9'b0;
raw_verticalPixelStretchCounter_d <= 4'b0;
end
end
always @(posedge vga_clk) begin
if (rst || !enableOutput) begin
raw_directPixelCounter <= 18'b0;
raw_horizontalPixelCounter <= 9'b0;
raw_verticalPixelCounter <= 10'b0;
raw_subPixelCounter <= 3'b0;
raw_horizontalPixelStretchCounter <= 4'b0;
raw_verticalPixelStretchCounter <= 4'b0;
end else begin
raw_directPixelCounter <= raw_directPixelCounter_d;
raw_horizontalPixelCounter <= raw_horizontalPixelCounter_d;
raw_verticalPixelCounter <= raw_verticalPixelCounter_d;
raw_subPixelCounter <= raw_subPixelCounter_d;
raw_horizontalPixelStretchCounter <= raw_horizontalPixelStretchCounter_d;
raw_verticalPixelStretchCounter <= raw_verticalPixelStretchCounter_d;
end
end
wire raw_directPixelCounterChanged = raw_directPixelCounter != raw_directPixelCounter_d;
wire raw_verticalPixelCounterChanged = raw_verticalPixelCounter != raw_verticalPixelCounter_d;
wire raw_horizontalPixelCounterChanged = raw_horizontalPixelCounter != raw_horizontalPixelCounter_d;
always @(*) begin
// Use data register inputs for new address
// This means that the address gets updated at the same time as the pixel counters
// And so the data is valid the cycle after
// Rather than being two cycles after
case (drawMode)
// Use Seperate horizontal and vertical portions of address
// This means that for some resolutions portions of memory are not used by the video device
DRAW_MODE_RAW: begin
vga_address <= { raw_verticalPixelCounter_d[VERTICAL_BITS-1:0], raw_horizontalPixelCounter_d[HORIZONTAL_BITS-1:0], 2'b00 };
loadPixel <= raw_verticalPixelCounterChanged || raw_horizontalPixelCounterChanged;
end
// Directly use the pixel index to access memory
// This better uses memory, but is also slightly more complex for the cpu to write to the frame buffer
DRAW_MODE_RAW_TIGHT_MEM: begin
vga_address <= { raw_directPixelCounter_d[ADDRESS_BITS-1:0], 2'b00 };
loadPixel <= raw_directPixelCounterChanged;
end
// TODO: Use some portion of memory to store colours, then index them with the frame buffer
// This will require loading the pixel information ahead of time, so that the correct colour can be found
// Is this really helpful, as we use 6-bit colour, so probably need to use 4-bit colour palette index
DRAW_MODE_COLOUR_PALETTE: begin
vga_address <= { raw_verticalPixelCounter_d[VERTICAL_BITS-1:0], raw_horizontalPixelCounter_d[HORIZONTAL_BITS-1:0], 2'b00 };
loadPixel <= raw_verticalPixelCounterChanged || raw_horizontalPixelCounterChanged;
end
// TODO: Use some portion of memory to store sprites
// Then use a sprite index rather than colour data or a colour index
// How many sprites do we want to allow
// How big will sprites be
// How configurable should this be
// We have very little video memory, so this may not work very well at all
DRAW_MODE_SPRITES: begin
vga_address <= { raw_verticalPixelCounter_d[VERTICAL_BITS-1:0], raw_horizontalPixelCounter_d[HORIZONTAL_BITS-1:0], 2'b00 };
loadPixel <= raw_verticalPixelCounterChanged || raw_horizontalPixelCounterChanged;
end
default: begin
vga_address <= { raw_verticalPixelCounter_d[VERTICAL_BITS-1:0], raw_horizontalPixelCounter_d[HORIZONTAL_BITS-1:0], 2'b00 };
loadPixel <= raw_verticalPixelCounterChanged || raw_horizontalPixelCounterChanged;
end
endcase
end
reg[5:0] raw_currentPixel;
always @(*) begin
case (raw_subPixelCounter)
4'h0: raw_currentPixel <= currentPixelData[5:0];
4'h1: raw_currentPixel <= currentPixelData[11:6];
4'h2: raw_currentPixel <= currentPixelData[17:12];
4'h3: raw_currentPixel <= currentPixelData[23:18];
4'h4: raw_currentPixel <= currentPixelData[29:24];
default: raw_currentPixel <= currentPixelData[5:0];
endcase
end
wire onScreen = inHorizontalVisibleArea && inVerticalVisibleArea;
assign vga_r = enableOutput && onScreen ? raw_currentPixel[1:0] : 2'b0;
assign vga_g = enableOutput && onScreen ? raw_currentPixel[3:2] : 2'b0;
assign vga_b = enableOutput && onScreen ? raw_currentPixel[5:4] : 2'b0;
endmodule