It's not complete and it only works on 8x16 fonts, but here's
something I slapped together to do the VGA text mode in Verilog:
// Copyright 2005, Timothy Miller, LGPL license
module vga_convert_text(
clock,
reset,
// read request fifo
req_busy_i,
req_send_o,
req_addr_o,
// read receipt fifo
read_valid_i,
read_data_i,
read_deq_o,
// write fifo
write_busy_i,
write_valid_o,
write_addr_o,
write_data_o,
// config_data
text_base,
font_base,
video_base,
video_stride,
last_column,
last_row,
char_total,
// other
blink_on
);
input clock, reset;
input blink_on;
input req_busy_i;
output req_send_o;
output [27:0] req_addr_o;
input read_valid_i;
input [31:0] read_data_i;
output read_deq_o;
input write_busy_i;
output write_valid_o;
output [27:0] write_addr_o;
output [31:0] write_data_o;
input [27:0] text_base;
input [27:0] font_base;
input [27:0] video_base;
input [15:0] video_stride;
input [7:0] last_column;
input [7:0] last_row;
input [12:0] char_total;
// Note that the interface to the req, read, and write fifos is not correct.
// I'll fix it later.
// Also, this doesn't do a cursor yet
// Fifo between reader and writer
// If this is done right, ISE will infer distributed RAM properly
reg [31+8:0] fifo_data [0:16];
reg [4:0] fifo_head, fifo_tail;
wire fifo_full = (fifo_head[3:0] == fifo_tail[3:0]) &&
(fifo_head[4] != fifo_tail[4]);
wire fifo_empty = fifo_head == fifo_tail;
// Read state machine
parameter s_start = 0;
parameter s_get_char = 1;
parameter s_wait_char = 2;
parameter s_get_font0 = 3;
parameter s_get_font1 = 3;
parameter s_wait_font0 = 4;
parameter s_wait_font1 = 5;
parameter s_loop = 6;
reg [7:0] attr0, addr1;
reg [11:0] char0, char1;
reg [1:0] font_count;
reg [12:0] char_count;
always @(posedge clock) begin
if (reset) begin
fifo_tail <= 0;
req_send_o <= 0;
read_deq_o <= 0;
state <= s_start;
end else begin
req_send_o <= 0;
read_deq_o <= 0;
case (reader_state)
s_start: begin
// Wait for the writer to finish to be sure we
// never get out of sync
if (writer_idle) begin
text_address <= text_base;
char_count <= 0;
state <= s_get_char;
end
end
s_get_char: begin
if (!req_busy_i) begin
req_send_o <= 1;
req_addr_o <= text_address;
text_address <= text_address + 1;
char_count <= char_count + 1;
state <= s_wait_char;
end
end
s_wait_char: begin
if (read_valid_i) begin
read_deq_o <= 1;
// Note: check byte ordering
char0 <= {read_data_i[31:24], 4'b0};
attr0 <= read_data_i[23:16];
char1 <= {read_data_i[15:8], 4'b0};
attr1 <= read_data_i[7:0];
state <= s_get_font;
// We'll change this a bit for char_height != 16
font_count <= 3;
end
end
s_get_font0: begin
if (!req_busy_i) begin
req_send_o <= 1;
req_addr_o <= font_address + char0;
char0 <= char0 + 1;
if (!font_count) state <= s_get_font1;
found_count <= font_count - 1;
end
end
s_get_font1: begin
if (!req_busy_i) begin
req_send_o <= 1;
req_addr_o <= font_address + char1;
char1 <= char1 + 1;
if (!font_count) state <= s_wait_font0;
found_count <= font_count - 1;
end
end
s_wait_font0: begin
if (read_valid_i && !fifo_full) begin
read_deq_o <= 1;
fifo_data[fifo_tail] <= {attr0, read_data_i};
fifo_tail <= fifo_tail + 1;
if (!font_count) state <= s_wait_font1;
found_count <= font_count - 1;
end
end
s_wait_font1: begin
if (read_valid_i && !fifo_full) begin
read_deq_o <= 1;
fifo_data[fifo_tail] <= {attr1, read_data_i};
fifo_tail <= fifo_tail + 1;
if (!font_count) state <= s_loop;
found_count <= font_count - 1;
end
end
s_loop: begin
if (char_count == char_total) begin
state <= s_start;
end else begin
state <= s_get_char;
end
end
endcase
end
end
// writer states
parameter w_start = 0;
parameter w_left_char0 = 1;
parameter w_left_char1
reg [27:0] write_address [0:3];
reg [10:0] column, row;
wire [27:0] down1line = write_address[1] + video_stride;
wire [27:0] over1char = write_address[2] + 8;
wire [27:0] down1char = write_address[3] + {video_stride, 4'b0};
// convert col/row to fifo word bit. Notice how we let the synthesizer
// reorder the bits
wire [31+8:0] fifo_word = fifo_data[fifo_head];
wire [0:31] fifo_bdata = fifo_word;
wire fifo_bit = fifo_bdata[{row[1:0], column[2:0]}];
// extract the attribute bits
// I'm sure I have the bit order wrong
wire [2:0] bg_index = fifo_word[38:36];
wire [3:0] fg_index = (blink_on == fifo_word[39]) ?
fifo_word[35:32] : bg_index;
// quick and dirty way of converting to RGB
wire [31:0] bg_color = {1'b0, {7{bg_index[2]}}, 1'b0, {7{bg_index[1]}},
1'b0, {7{bg_index[0]}}};
wire [31:0] fg_color = {fg_index[3], {7{fg_index[2]}},
fg_index[3], {7{fg_index[1]}},
fg_index[3], {7{fg_index[0]}}};
always @(posedge clock) begin
if (reset) begin
write_address[0] <= video_base;
write_address[1] <= video_base;
write_address[2] <= video_base;
write_address[3] <= video_base;
writer_idle <= 1;
column <= 0;
row <= 0;
end else begin
if (!fifo_empty) begin
writer_idle <= 0;
end
if (!write_busy_i && !fifo_empty) begin
// dequeue at the right time
if (column[2:0] == 7 && row[1:0] == 3) begin
fifo_head <= fifo_head + 1;
end
// Move to the right
write_address[0] <= write_address[0] + 1;
column[2:0] <= column[2:0] + 1;
if (column[2:0] == 7) begin
// At right of char cell, move down a scanline
write_address[0] <= down1line;
write_address[1] <= down1line;
row[3:0] <= row[3:0] + 1;
if (row[3:0] == 15) begin
// At bottom of char cell, move back up and over 1 char
write_address[0] <= over1char;
write_address[1] <= over1char;
write_address[2] <= over1char;
column[10:3] <= column[10:3] + 1;
if (column[10:3] == last_column) begin
// at end of line, move down to next char line
write_address[0] <= down1char;
write_address[1] <= down1char;
write_address[2] <= down1char;
write_address[3] <= down1char;
column[10:3] <= 0;
row[10:4] <= row[10:4] + 1;
if (row[10:4] == last_row) begin
// Last col/row of last cell of last
// col/row of character array, stop
writer_idle <= 1;
end
end
end
end
write_valid_o <= 1;
write_data_o <= fifo_bit ? fg_color : bg_color;
write_addr_o <= write_address[0];
end
end
end
endmodule
_______________________________________________
Open-graphics mailing list
[email protected]
http://lists.duskglow.com/mailman/listinfo/open-graphics
List service provided by Duskglow Consulting, LLC (www.duskglow.com)