commit df5a81c80e88fe49c3d7bada90c93c9d5f14fd2c
parent 04fd1dc2ee9722f0bb38817b560ae5286049e324
Author: Brian Swetland <swetland@frotz.net>
Date: Wed, 21 Nov 2018 19:20:23 -0800
vga: rework most of this
Less embarrassing now and works with Yosys+ArachnePNR as well as
Verilator and iceCube2+Synplify. Vivado is not pleased.
Diffstat:
4 files changed, 92 insertions(+), 161 deletions(-)
diff --git a/hdl/vga/chardata.v b/hdl/vga/chardata.v
@@ -1,11 +1,11 @@
-// Copyright 2012, Brian Swetland
+// Copyright 2018, Brian Swetland <swetland@frotz.net>
+// Licensed under the Apache License, Version 2.0.
//
-// Pixel Data Reader / Character Data Reader
+// Character Display Engine
//
-// assert newline and provide line address to start linefetch
-// character data will be provided on cdata two clocks later
-//
-// assert next to advance: character data will be provided two clocks later
+// newline strobes on the first pixel of a new line
+// advance strobes on each visible pixel of a new line
+// line provides the visible line count 0..239
//
// vram_addr/vram_data: connect to sync sram
@@ -16,102 +16,12 @@ module pixeldata(
input newline,
input advance,
input [7:0] line,
-
output [11:0] pixel,
-
input [7:0] vram_data,
output [10:0] vram_addr
);
-wire [7:0] new_cdata;
-reg next;
-
-chardata chardata(
- .clk(clk),
- .newline(newline),
- .line(line),
- .next(next),
- .cdata_o(new_cdata),
- .vram_data(vram_data),
- .vram_addr_o(vram_addr)
- );
-
-reg [7:0] cdata, next_cdata;
-reg [3:0] bitcount, next_bitcount;
-reg [1:0] state = 2'h0, next_state;
-
-always @(*) begin
- next_bitcount = bitcount;
- next_cdata = cdata;
- next = 1'b0;
-
- /* s0 machine is used to wait until the first cdata
- * is ready after a newline signal, load that cdata,
- * then enter the shift-out (s0=0) mode
- */
- case (state)
- 2'h3: next_state = 2'h2;
- 2'h2: next_state = 2'h1;
- 2'h1: begin
- next_state = 2'h0;
- next_cdata = new_cdata;
- end
- 2'h0: begin
- next_state = 2'h0;
- if (advance)
- next_bitcount = bitcount - 4'd1;
- if (bitcount == 4'h4)
- next = 1'b1;
- if (bitcount == 4'h0)
- next_cdata = new_cdata;
- end
- endcase
-
- if (newline) begin
- next_state = 2'h3;
- next_bitcount = 4'hF;
- end
-
-end
-
-assign pixel = (cdata[bitcount[3:1]] ? 12'hFFF : 12'h00F);
-
-always @(posedge clk) begin
- bitcount <= next_bitcount;
- state <= next_state;
- cdata <= next_cdata;
-end
-
-endmodule
-
-
-module chardata(
- input clk,
- input newline,
- input next,
- input [7:0] line,
- output [7:0] cdata_o,
-
- input [7:0] vram_data,
- output [10:0] vram_addr_o
- );
-
-`define SWAIT 2'h0
-`define SLOAD 2'h1
-`define SLATCH 2'h2
-
reg [7:0] pattern_rom [0:1023];
-reg [2:0] pline, next_pline;
-
-reg [1:0] state = `SWAIT, next_state;
-reg [10:0] next_addr;
-reg [7:0] next_cdata;
-
-reg [7:0] cdata;
-reg [10:0] vram_addr;
-
-assign cdata_o = cdata;
-assign vram_addr_o = vram_addr;
`ifdef HEX_PATHS
initial $readmemh("hdl/vga/prom.txt", pattern_rom);
@@ -119,42 +29,70 @@ initial $readmemh("hdl/vga/prom.txt", pattern_rom);
initial $readmemh("prom.txt", pattern_rom);
`endif
+reg next_load;
+reg [5:0] next_xpos;
+reg [3:0] next_ppos;
+reg [15:0] next_pattern;
+
+reg load = 1'b0;
+reg [5:0] xpos = 6'b0;
+reg [3:0] ppos = 4'b0;
+reg [15:0] pattern = 16'b0;
+
+// generate vram address by using the high bits of the display
+// line and the local xpos character counter
+assign vram_addr = { line[7:3], next_xpos };
+
+// generate pattern rom address by using the character id
+// fetched from vram as the high bits and the low bits of
+// the display line to further index into the correct pattern
+wire [9:0] pattern_addr = { vram_data[6:0], line[2:0] };
+
+wire [7:0] cdata = pattern_rom[pattern_addr];
+
+// the high bit of the pattern shift register is used to
+// select the FG or BG color and feed out to the vga core
+assign pixel = pattern[15] ? 12'hFFF : 12'h00F;
+
always_comb begin
- next_state = state;
- next_addr = vram_addr;
- next_cdata = cdata;
- next_pline = pline;
+ next_xpos = xpos;
+ next_ppos = ppos;
+ next_pattern = pattern;
+ next_load = 1'b0;
+
if (newline) begin
- next_state = `SLOAD;
- next_addr = { line[7:3], 6'b0 };
- next_pline = line[2:0];
- end
-`ifndef YOSYS
- else
-`endif
- case (state)
- `SWAIT: if (next) begin
- next_state = `SLOAD;
- end
- `SLOAD: begin
- next_state = `SLATCH;
+ next_load = 1'b1;
+ next_xpos = 6'b0;
+ next_ppos = 4'b0;
+ end else if (advance) begin
+ next_ppos = ppos + 4'h1;
+ if (ppos == 4'hF) begin
+ next_load = 1'b1;
+ next_xpos = xpos + 6'b1;
end
- `SLATCH: begin
- next_state = `SWAIT;
- next_addr = vram_addr + 11'd1;
- next_cdata = pattern_rom[{vram_data[6:0], pline}];
- end
- default: begin
- next_state = `SWAIT;
end
- endcase
+
+ // pattern shift register
+ if (load) begin
+ // 8bit wide character pattern line is expanded
+ // into the 16bit pattern shift register
+ next_pattern = {
+ cdata[7], cdata[7], cdata[6], cdata[6],
+ cdata[5], cdata[5], cdata[4], cdata[4],
+ cdata[3], cdata[3], cdata[2], cdata[2],
+ cdata[1], cdata[1], cdata[0], cdata[0]
+ };
+ end else if (advance) begin
+ next_pattern = { pattern[14:0], 1'b0 };
+ end
+
end
always_ff @(posedge clk) begin
- state <= next_state;
- vram_addr <= next_addr;
- cdata <= next_cdata;
- pline <= next_pline;
+ load <= next_load;
+ xpos <= next_xpos;
+ ppos <= next_ppos;
+ pattern <= next_pattern;
end
-endmodule
+endmodule
diff --git a/hdl/vga/vga.v b/hdl/vga/vga.v
@@ -1,4 +1,5 @@
-// Copyright 2012, Brian Swetland
+// Copyright 2012, Brian Swetland <swetland@frotz.net>
+// Licensed under the Apache License, Version 2.0.
`timescale 1ns/1ns
@@ -37,13 +38,13 @@ reg next_active;
reg next_startline;
reg [9:0] next_hcount;
reg [9:0] next_vcount;
-reg [9:0] next_lineno;
-reg [7:0] lineno;
+
+wire [9:0] adjusted_vcount = next_vcount - 10'd32;
assign hs = hsync;
assign vs = vsync;
assign fr = frame;
-assign line = lineno;
+assign line = adjusted_vcount[8:1];
assign advance = active;
assign newline = startline;
@@ -52,60 +53,49 @@ assign g = active ? pixel[7:4] : 4'd0;
assign b = active ? pixel[3:0] : 4'd0;
always_comb begin
- next_hsync = 1'b0;
- next_vsync = 1'b0;
+ next_hsync = hsync;
+ next_vsync = vsync;
next_frame = 1'b0;
- next_hcount = 10'd0;
- next_vcount = 10'd0;
next_active = 1'b0;
next_startline = 1'b0;
- next_lineno = 10'b0;
+ next_hcount = 10'd0;
+ next_vcount = 10'd0;
if (hcount == 10'd799) begin
if (vcount == 10'd523) begin
next_vcount = 10'd0;
next_frame = 1'b1;
+ next_vsync = 1'b0;
end else
next_vcount = vcount + 10'd1;
next_hcount = 10'd0;
+ next_hsync = 1'b0;
+ next_startline = 1'b1;
end else begin
next_vcount = vcount;
next_hcount = hcount + 10'd1;
- end
-
- if (next_hcount == 0)
- next_startline = 1'b1;
- else
- next_startline = 1'b0;
+
+ if (hcount == 10'd96)
+ next_hsync = 1'b1;
- if (next_hcount < 10'd96)
- next_hsync = 1'b0;
- else
- next_hsync = 1'b1;
-
- if (next_vcount < 10'd2)
- next_vsync = 1'b0;
- else
- next_vsync = 1'b1;
+ if (vcount == 10'd2)
+ next_vsync = 1'b1;
- if ((next_vcount > 31) && (next_vcount < 512))
- if ((next_hcount > 143) && (next_hcount < 784))
- next_active = 1'b1;
+ if ((vcount > 30) && (vcount < 511))
+ if ((hcount > 142) && (hcount < 783))
+ next_active = 1'b1;
+ end
- next_lineno = next_vcount - 10'd32;
end
always_ff @(posedge clk) begin
- hcount <= next_hcount;
- vcount <= next_vcount;
hsync <= next_hsync;
vsync <= next_vsync;
frame <= next_frame;
-
- /* signals to pixel generator */
- startline <= next_startline;
active <= next_active;
- lineno <= next_lineno[8:1];
+ startline <= next_startline;
+ hcount <= next_hcount;
+ vcount <= next_vcount;
end
endmodule
diff --git a/hdl/vga/vga40x30x2.v b/hdl/vga/vga40x30x2.v
@@ -1,3 +1,5 @@
+// Copyright 2012, Brian Swetland <swetland@frotz.net>
+// Licensed under the Apache License, Version 2.0.
module vga40x30x2(
input clk25m,
diff --git a/hdl/vga/videoram.v b/hdl/vga/videoram.v
@@ -1,4 +1,5 @@
-// Copyright 2012, Brian Swetland. Use at your own risk.
+// Copyright 2012, Brian Swetland <swetland@frotz.net>
+// Licensed under the Apache License, Version 2.0.
//
// sync sram with independent read/write addressing