diff options
author | Wojciech Kosior <kwojtus@protonmail.com> | 2020-09-01 10:54:59 +0200 |
---|---|---|
committer | Wojciech Kosior <kwojtus@protonmail.com> | 2020-09-01 11:04:22 +0200 |
commit | ee1f6c47e1eff920068f4bceaf604f9535a2e8a9 (patch) | |
tree | 580eb001a72601d254bb29cc348a529490f84808 /design/vga.v | |
parent | cd02ddff8886aa1db29f80d3cc5cf99a349d8258 (diff) | |
download | AGH-engineering-thesis-ee1f6c47e1eff920068f4bceaf604f9535a2e8a9.tar.gz AGH-engineering-thesis-ee1f6c47e1eff920068f4bceaf604f9535a2e8a9.zip |
start anew
Diffstat (limited to 'design/vga.v')
-rw-r--r-- | design/vga.v | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/design/vga.v b/design/vga.v new file mode 100644 index 0000000..4b71b28 --- /dev/null +++ b/design/vga.v @@ -0,0 +1,241 @@ +`default_nettype none + + module vga + #( + parameter FONT_FILE = "font.mem" + ) + ( + output wire ACK_O, + input wire CLK_I, + input wire [10:0] ADR_I, + input wire [15:0] DAT_I, + output wire [15:0] DAT_O, + input wire RST_I, + input wire STB_I, + input wire WE_I, + output wire STALL_O, + + /* Non-wishbone */ + input wire clock_25mhz, + output reg h_sync, + output reg v_sync, + output reg [2:0] red, + output reg [2:0] green, + output reg [2:0] blue + ); + + reg powered_on; + + parameter LINES = V_ACTIVE_VIDEO / 16; /* 30 */ + parameter LINE_LENGTH = H_ACTIVE_VIDEO / 8; /* 80 */ + parameter CHARACTERS_ON_SCREEN = LINE_LENGTH * LINES; /* 2400 */ + + /* + * We want to store 2400 characters in memory. 2 chars go into one 16-bit + * word, so wee need a 1200x16 array. One embedded RAM block in iCE40 FPGAs + * is able to store 256x16 bits. This means, instead of choosing 1200 as + * array size, we can choose 1280, which is a multiple of 256. + */ + reg [15:0] text_memory [1279 : 0]; + + /* + * Enable writes to text_memory using wishbone interface. + * (no reads for now) + */ + + reg ack; + + assign DAT_O = {16{powered_on}}; + assign ACK_O = ack; + assign STALL_O = 1'b0; + + always @ (posedge CLK_I) begin + ack <= STB_I && !RST_I; + + if (STB_I && WE_I) begin + if (ADR_I < 1280) + text_memory[ADR_I] <= DAT_I; + else + powered_on <= DAT_I != 16'b0; + end + end + + /* Non-wishbone part - generate 640x480 60Hz VGA output */ + + reg powered_on_latched; + + always @ (posedge clock_25mhz) + powered_on_latched <= powered_on; + + parameter H_POLARITY = 1'b0; + parameter H_FRONT_PORCH = 8; + parameter H_SYNC = 96; + parameter H_BACK_PORCH = 40; + parameter H_LEFT_BORDER = 8; + parameter H_ACTIVE_VIDEO = 640; + parameter H_RIGHT_BORDER = 8; + + reg [9:0] h_counter; + + parameter H_STAGE_RB_OR_FP = 0; /* right border of front porch */ + parameter H_STAGE_SYNC = 1; + parameter H_STAGE_BP_OR_LB = 2; /* back porch or left border */ + parameter H_STAGE_ACTIVE_VIDEO = 3; + + reg [1:0] h_stage; + + always @ (posedge clock_25mhz) begin + if (powered_on_latched) begin + if ((h_stage == H_STAGE_RB_OR_FP && + h_counter + 1 == H_RIGHT_BORDER + H_FRONT_PORCH) || + (h_stage == H_STAGE_SYNC && + h_counter + 1 == H_SYNC) || + (h_stage == H_STAGE_BP_OR_LB && + h_counter + 1 == H_BACK_PORCH + H_LEFT_BORDER) || + (h_stage == H_STAGE_ACTIVE_VIDEO && + h_counter + 1 == H_ACTIVE_VIDEO)) begin + h_stage <= h_stage + 1; + h_counter <= 0; + end else begin // if ((h_stage == H_STAGE_RB_OR_FP &&... + h_counter <= h_counter + 1; + end + end else begin // if (powered_on_latched) + h_stage <= H_STAGE_RB_OR_FP; + h_counter <= H_RIGHT_BORDER; + end // else: !if(powered_on_latched) + end // always @ (posedge clock_25mhz) + + wire end_of_line; + assign end_of_line = h_stage == H_STAGE_RB_OR_FP && + h_counter + 1 == H_RIGHT_BORDER; + + parameter V_POLARITY = 1'b1; + parameter V_FRONT_PORCH = 2; + parameter V_SYNC = 2; + parameter V_BACK_PORCH = 25; + parameter V_TOP_BORDER = 8; + parameter V_ACTIVE_VIDEO = 480; + parameter V_BOTTOM_BORDER = 8; + + reg [8:0] v_counter; + + parameter V_STAGE_BB_OR_FP = 0; /* bottom border of front porch */ + parameter V_STAGE_SYNC = 1; + parameter V_STAGE_BP_OR_TB = 2; /* back porch or top border */ + parameter V_STAGE_ACTIVE_VIDEO = 3; + + reg [1:0] v_stage; + + always @ (posedge clock_25mhz) begin + if (powered_on_latched) begin + if (end_of_line) begin + if ((v_stage == V_STAGE_BB_OR_FP && + v_counter + 1 == V_BOTTOM_BORDER + V_FRONT_PORCH) || + (v_stage == V_STAGE_SYNC && + v_counter + 1 == V_SYNC) || + (v_stage == V_STAGE_BP_OR_TB && + v_counter + 1 == V_BACK_PORCH + V_TOP_BORDER) || + (v_stage == V_STAGE_ACTIVE_VIDEO && + v_counter + 1 == V_ACTIVE_VIDEO)) begin + v_stage <= v_stage + 1; + v_counter <= 0; + end else begin // if ((v_stage == V_STAGE_BB_OR_FP &&... + v_counter <= v_counter + 1; + end + end // if (end_of_line) + end else begin // if (powered_on_latched) + v_stage <= V_STAGE_BB_OR_FP; + v_counter <= V_BOTTOM_BORDER; + end // else: !if(powered_on_latched) + end // always @ (posedge clock_25mhz) + + reg [0:7] font [128 * 16 - 1 : 0]; + + initial begin + $readmemb(FONT_FILE, font, 0, 128 * 16 - 1); + end + + wire [6:0] char_x; + wire [4:0] char_y; + wire [12:0] char_flat_idx; + wire [15:0] text_memory_field; + wire [7:0] char; + assign char_x = h_counter / 8; + assign char_y = v_counter / 16; + assign char_flat_idx = char_x + char_y * LINE_LENGTH; + assign text_memory_field = text_memory[char_flat_idx[12:1]]; + assign char = char_flat_idx[0] ? + text_memory_field[15:8] : text_memory_field[7:0]; + + wire [0:7] replacement_char [0:16]; + assign replacement_char[0] = 8'b00000000; + assign replacement_char[1] = 8'b00011000; + assign replacement_char[2] = 8'b00111100; + assign replacement_char[3] = 8'b01100110; + assign replacement_char[4] = 8'b01011010; + assign replacement_char[5] = 8'b01111010; + assign replacement_char[6] = 8'b01111010; + assign replacement_char[7] = 8'b01111010; + assign replacement_char[8] = 8'b01110110; + assign replacement_char[9] = 8'b01101110; + assign replacement_char[10] = 8'b01101110; + assign replacement_char[11] = 8'b01111110; + assign replacement_char[12] = 8'b01101110; + assign replacement_char[13] = 8'b00111100; + assign replacement_char[14] = 8'b00011000; + assign replacement_char[15] = 8'b00000000; + + wire [2:0] char_pixel_x; + wire [3:0] char_pixel_y; + wire pixel_on; + wire display_on; + assign char_pixel_x = h_counter % 8; + assign char_pixel_y = v_counter % 16; + /* Replace non-ASCII characters (i.e. chars with values above 127) */ + assign pixel_on = char[7] ? replacement_char[char_pixel_y][char_pixel_x] : + font[char[6:0] * 16 + char_pixel_y][char_pixel_x]; + assign display_on = h_stage == H_STAGE_ACTIVE_VIDEO && + v_stage == V_STAGE_ACTIVE_VIDEO; + + parameter FG_COLOR = {3'b010, 3'b111, 3'b101}; + parameter BG_COLOR = {3'b000, 3'b000, 3'b111}; + + always @ (posedge clock_25mhz) begin + if (h_stage == H_STAGE_SYNC) + h_sync <= H_POLARITY; + else + h_sync <= ~H_POLARITY; + + if (v_stage == V_STAGE_SYNC) + v_sync <= V_POLARITY; + else + v_sync <= ~V_POLARITY; + + if (!display_on) + {red, green, blue} <= 9'b0; + else if (pixel_on) + {red, green, blue} <= FG_COLOR; + else + {red, green, blue} <= BG_COLOR; + end // always @ (posedge clock_25mhz) + +`ifdef SIMULATION + /* avoid undefined values */ + initial begin + powered_on <= 0; + powered_on_latched <= 0; + ack <= 0; + + h_sync <= ~H_POLARITY; + v_sync <= ~V_POLARITY; + {red, green, blue} <= 9'b0; + + h_counter <= 0; + h_stage <= H_STAGE_RB_OR_FP; + + v_counter <= 0; + v_stage <= V_STAGE_BB_OR_FP; + end +`endif +endmodule // vga + |