2018-01-26 13:21:05 +00:00
|
|
|
module vga(
|
2018-01-29 11:53:16 +00:00
|
|
|
input clk25,
|
2018-01-26 13:21:05 +00:00
|
|
|
input [6:0] in,
|
|
|
|
input in_stb,
|
|
|
|
output vga_h_sync,
|
|
|
|
output vga_v_sync,
|
2018-01-29 13:19:21 +00:00
|
|
|
output vga_red,
|
|
|
|
output vga_grn,
|
|
|
|
output vga_blu
|
2018-01-26 13:21:05 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
reg [5:0] v_ram[0:959] /* synthesis syn_ramstyle = "block_ram" */;
|
|
|
|
reg [4:0] c_rom[0:447] /* synthesis syn_ramstyle = "block_ram" */;
|
|
|
|
initial begin
|
2018-01-29 11:53:16 +00:00
|
|
|
$readmemb("../../roms/vga_vram.bin", v_ram, 0, 959);
|
|
|
|
$readmemb("../../roms/vga_font.bin", c_rom, 0, 447);
|
2018-01-26 13:21:05 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
// video structure constants
|
|
|
|
parameter hpixels = 800; // horizontal pixels per line
|
|
|
|
parameter vlines = 521; // vertical lines per frame
|
|
|
|
parameter hpulse = 96; // hsync pulse length
|
|
|
|
parameter vpulse = 2; // vsync pulse length
|
|
|
|
parameter hbp = 144; // end of horizontal back porch
|
|
|
|
parameter hfp = 784; // beginning of horizontal front porch
|
|
|
|
parameter vbp = 31; // end of vertical back porch
|
|
|
|
parameter vfp = 511; // beginning of vertical front porch
|
|
|
|
|
|
|
|
// registers for storing the horizontal & vertical counters
|
|
|
|
reg [9:0] hc;
|
|
|
|
reg [9:0] vc;
|
|
|
|
reg [5:0] hpos;
|
|
|
|
reg [4:0] vpos;
|
|
|
|
reg [3:0] hdot;
|
|
|
|
reg [4:0] vdot;
|
|
|
|
|
2018-01-29 11:53:16 +00:00
|
|
|
wire vga_h_act;
|
|
|
|
wire vga_v_act;
|
|
|
|
|
|
|
|
assign vga_h_act = (hc >= hbp && hc < hfp);
|
|
|
|
assign vga_v_act = (vc >= vbp && vc < vfp);
|
|
|
|
|
|
|
|
assign vga_h_sync = (hc < hpulse) ? 0 : 1;
|
|
|
|
assign vga_v_sync = (vc < vpulse) ? 0 : 1;
|
|
|
|
// assign vblank = (vc >= vbp && vc < vfp) ? 0:1;
|
|
|
|
|
|
|
|
always @(posedge clk25)
|
2018-01-26 13:21:05 +00:00
|
|
|
begin
|
2018-01-29 11:53:16 +00:00
|
|
|
if (hc < hpixels - 1)
|
2018-01-26 13:21:05 +00:00
|
|
|
begin
|
2018-01-29 11:53:16 +00:00
|
|
|
hc <= hc + 1;
|
|
|
|
|
|
|
|
// count 16 pixels, so 640px / 16 = 40 characters
|
|
|
|
if (vga_h_act)
|
2018-01-26 13:21:05 +00:00
|
|
|
begin
|
2018-01-29 11:53:16 +00:00
|
|
|
hdot <= hdot + 1;
|
2018-01-26 13:21:05 +00:00
|
|
|
|
2018-01-29 11:53:16 +00:00
|
|
|
if (hdot == 4'hF)
|
2018-01-26 13:21:05 +00:00
|
|
|
begin
|
2018-01-29 11:53:16 +00:00
|
|
|
hdot <= 0;
|
|
|
|
hpos <= hpos + 1;
|
2018-01-26 13:21:05 +00:00
|
|
|
end
|
|
|
|
end
|
2018-01-29 11:53:16 +00:00
|
|
|
end
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
// reset horizontal counters
|
|
|
|
hc <= 0;
|
|
|
|
hdot <= 0;
|
|
|
|
hpos <= 0;
|
|
|
|
|
|
|
|
if (vc < vlines - 1)
|
2018-01-26 13:21:05 +00:00
|
|
|
begin
|
2018-01-29 11:53:16 +00:00
|
|
|
vc <= vc + 1;
|
2018-01-26 13:21:05 +00:00
|
|
|
|
2018-01-29 11:53:16 +00:00
|
|
|
// count 20 rows, so 480px / 20 = 24 rows
|
|
|
|
if (vga_v_act)
|
2018-01-26 13:21:05 +00:00
|
|
|
begin
|
2018-01-29 11:53:16 +00:00
|
|
|
vdot <= vdot + 1;
|
2018-01-26 13:21:05 +00:00
|
|
|
|
2018-01-29 11:53:16 +00:00
|
|
|
if (vdot == 5'd19)
|
|
|
|
begin
|
|
|
|
vdot <= 0;
|
|
|
|
vpos <= vpos + 1;
|
2018-01-26 13:21:05 +00:00
|
|
|
end
|
|
|
|
end
|
2018-01-29 11:53:16 +00:00
|
|
|
end
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
vc <= 0;
|
|
|
|
vdot <= 0;
|
|
|
|
vpos <= 0;
|
2018-01-26 13:21:05 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-01-29 13:19:21 +00:00
|
|
|
reg out;
|
|
|
|
assign vga_red = out;
|
|
|
|
assign vga_grn = out;
|
|
|
|
assign vga_blu = out;
|
2018-01-26 13:21:05 +00:00
|
|
|
|
2018-01-29 11:53:16 +00:00
|
|
|
always @(posedge clk25)
|
2018-01-26 13:21:05 +00:00
|
|
|
begin
|
2018-01-29 13:19:21 +00:00
|
|
|
case ({vga_h_act, vga_v_act})
|
|
|
|
default:
|
|
|
|
begin
|
|
|
|
// outside display area
|
|
|
|
out = 1'b0;
|
|
|
|
end
|
2018-01-26 13:21:05 +00:00
|
|
|
|
2018-01-29 13:19:21 +00:00
|
|
|
2'b11:
|
|
|
|
begin
|
|
|
|
// inside display frame
|
|
|
|
case (vdot)
|
|
|
|
5'b00000,
|
|
|
|
5'b00001,
|
|
|
|
5'b00010,
|
|
|
|
5'b00011,
|
|
|
|
5'b10010,
|
|
|
|
5'b10011:
|
|
|
|
// blank row for spacing
|
|
|
|
out = 1'b0;
|
|
|
|
|
|
|
|
default:
|
|
|
|
case (hdot)
|
|
|
|
4'b0000,
|
|
|
|
4'b0001,
|
|
|
|
4'b1100,
|
|
|
|
4'b1101,
|
|
|
|
4'b1110,
|
|
|
|
4'b1111:
|
|
|
|
// blank column for spacing
|
|
|
|
out = 1'b0;
|
|
|
|
|
|
|
|
default:
|
|
|
|
// into character pixels
|
|
|
|
// TODO: fix this mess
|
|
|
|
out = c_rom[(v_ram[hpos + (vpos * 40)] * 7) + (vdot[4:1] - 2)][5 - hdot[3:1]];
|
|
|
|
endcase
|
|
|
|
endcase
|
|
|
|
end
|
|
|
|
endcase
|
2018-01-26 13:21:05 +00:00
|
|
|
end
|
|
|
|
|
2018-01-29 13:19:21 +00:00
|
|
|
// FIXME: This is horrible
|
2018-01-26 13:21:05 +00:00
|
|
|
reg [5:0] cur_pos;
|
|
|
|
reg stb;
|
2018-01-29 11:53:16 +00:00
|
|
|
always @(posedge clk25)
|
2018-01-26 13:21:05 +00:00
|
|
|
begin
|
|
|
|
if (in_stb & ~stb)
|
|
|
|
begin
|
2018-01-29 11:53:16 +00:00
|
|
|
v_ram[{4'b0, cur_pos}] <= {~in[6], in[4:0]};
|
2018-01-26 13:21:05 +00:00
|
|
|
stb <= 1;
|
|
|
|
cur_pos <= cur_pos + 1;
|
|
|
|
end
|
|
|
|
|
|
|
|
if (~in_stb & stb)
|
|
|
|
begin
|
|
|
|
stb <= 0;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
endmodule
|