vt52-fpga  1.0.0 Initial
vt52-fpga is a serial terminal implemented on a FPGA
video_generator.v
Go to the documentation of this file.
1 /**
2  * 80x24 char generator (8x16 char size) & sync generator
3  */
4 module video_generator
5  #(parameter ROWS = 24,
6  parameter COLS = 80,
7  // XXX These could probably be calculated from the above
8  parameter ROW_BITS = 5,
9  parameter COL_BITS = 7,
10  parameter ADDR_BITS = 11
11  // first address outside the visible area
12  )
13  (input clk,
14  input reset,
15  // video output
16  output reg hsync,
17  output reg vsync,
18  output reg video,
19  // video output extra info
20  output reg hblank,
21  output reg vblank,
22  // cursor
23  input [COL_BITS-1:0] cursor_x,
24  input [ROW_BITS-1:0] cursor_y,
25  input cursor_blink_on,
26  // scrolling
27  input [ADDR_BITS-1:0] first_char,
28  // char buffer
29  output wire [ADDR_BITS-1:0] char_buffer_address,
30  input [7:0] char_buffer_data,
31  // char rom
32  output wire [11:0] char_rom_address,
33  input [7:0] char_rom_data,
34  input graphic_mode_state
35  );
36  localparam PAST_LAST_ROW = ROWS * COLS;
37  // VGA Signal 640x400 @ 70 Hz timing
38  // from http://tinyvga.com/vga-timing/640x400@70Hz
39  // Total size, visible size, front and back porches and sync pulse size
40  // clk is 24Mhz (half USB...), so about what we need (around 25Mhz)
41  localparam hbits = 10;
42  localparam hpixels = 800;
43  localparam hbp = 48;
44  localparam hvisible = 640;
45  localparam hfp = 16;
46  localparam hpulse = 96;
47  // Added 8 to vbp and vfp to compensate for the missing character row
48  // (25 * 16 == 400, we are using 24 rows so we are 16 pixels short)
49  localparam vbits = 9;
50  localparam vlines = 449;
51  localparam vbp = 35 + 8;
52  localparam vvisible = 400 - 16;
53  localparam vfp = 12 + 8;
54  localparam vpulse = 2;
55  // sync polarity
56  localparam hsync_on = 1'b0;
57  localparam vsync_on = 1'b1;
58  localparam hsync_off = ~hsync_on;
59  localparam vsync_off = ~vsync_on;
60  // video polarity
61  localparam video_on = 1'b1;
62  localparam video_off = ~video_on;
63 
64  // These are to combine the chars & the cursor for video output
65  reg is_under_cursor;
66  reg cursor_pixel;
67  reg char_pixel;
68  reg combined_pixel;
69 
70  // horizontal & vertical counters
71  reg [hbits-1:0] hc, next_hc;
72  reg [vbits-1:0] vc, next_vc;
73  // syncs and blanks
74  reg next_hblank, next_vblank, next_hsync, next_vsync;
75  // character generation
76  reg [ROW_BITS-1:0] row, next_row;
77  reg [COL_BITS-1:0] col, next_col;
78  // these count the rows and cols of pixels inside a char (8x16)
79  reg [2:0] colc, next_colc;
80  reg [3:0] rowc, next_rowc;
81  // maintain the next address to the char buffer
82  reg [ADDR_BITS-1:0] char, next_char;
83 
84  // we must use next_char instead of char because we need it ready for
85  // the next clock cycle
86  assign char_buffer_address = next_char;
87  // The address of the char row in rom is formed with the char and the row offset
88  // we can get away with the addition here because the number of rows
89  // in this font is a power of 2 (16 in this case)
90  assign char_rom_address = { char_buffer_data, rowc };
91 
92  //
93  // horizontal & vertical counters, syncs and blanks
94  //
95  always @(posedge clk) begin
96  if (reset) begin
97  hc <= 0;
98  vc <= 0;
99  hsync <= hsync_off;
100  vsync <= vsync_off;
101  hblank <= 1;
102  vblank <= 1;
103  end
104  else begin
105  hc <= next_hc;
106  vc <= next_vc;
107  hsync <= next_hsync;
108  vsync <= next_vsync;
109  hblank <= next_hblank;
110  vblank <= next_vblank;
111  end
112  end
113 
114  always @(*) begin
115  if (hc == hpixels) begin
116  next_hc = 0;
117  next_vc = (vc == vlines)? 0 : vc + 1;
118  end
119  else begin
120  next_hc = hc + 1;
121  next_vc = vc;
122  end
123  next_hsync = (next_hc >= hbp + hvisible + hfp)? hsync_on : hsync_off;
124  next_vsync = (next_vc >= vbp + vvisible + vfp)? vsync_on : vsync_off;
125  next_hblank = (next_hc < hbp || next_hc >= hbp + hvisible);
126  next_vblank = (next_vc < vbp || next_vc >= vbp + vvisible);
127  end
128 
129  //
130  // character generation
131  //
132  always @(posedge clk) begin
133  if (reset) begin
134  row <= 0;
135  col <= 0;
136  rowc <= 0;
137  colc <= 0;
138  char <= 0;
139  end
140  else begin
141  row <= next_row;
142  col <= next_col;
143  rowc <= next_rowc;
144  colc <= next_colc;
145  char <= next_char;
146  end
147  end
148 
149  always @(*) begin
150  if (vblank) begin
151  next_row = 0;
152  next_rowc = 0;
153  next_col = 0;
154  next_colc = 0;
155  next_char = first_char;
156  end
157  // we need next_hblank here because we must detect the edge
158  // in hblank & prepare for the row
159  else if (next_hblank) begin
160  // some nice defaults
161  next_row = row;
162  next_rowc = rowc;
163  next_col = 0;
164  next_colc = 0;
165  next_char = char;
166 
167  // only do this once per line (positive hblank edge)
168  if (hblank == 0) begin
169  if (rowc == 15) begin
170  // we are moving to the next row, so char
171  // is already set at the correct value, unless
172  // we reached the end of the buffer
173  next_row = row + 1;
174  next_rowc = 0;
175  if (char == PAST_LAST_ROW) begin
176  next_char = 0;
177  end
178  end
179  else begin
180  // we are still on the same row, so
181  // go back to the first char in this line
182  next_char = char - COLS;
183  next_rowc = rowc + 1;
184  end
185  end
186  end
187  else begin
188  // some nice defaults
189  next_row = row;
190  next_rowc = rowc;
191  next_col = col;
192  next_colc = colc+1;
193  next_char = char;
194 
195  if (colc == 7) begin
196  // prepare to read next char (it takes two cycles,
197  // one to read from ram & one to read from rom)
198  // Since the memory bus runs at twice the pixel clock rate
199  // we can do it just at the last pixel
200  next_char = char+1;
201  // move to the next char
202  next_col = col+1;
203  next_colc = 0;
204  end
205  end // else: !if(next_hblank)
206  end // always @ (*)
207 
208  //
209  // pixel out (char & cursor combination)
210  //
211  always @(posedge clk) begin
212  if (reset) video <= video_off;
213  else video <= combined_pixel;
214  end
215 
216  always @(*) begin
217  // cursor pixel: invert video when we are under the cursor (if it's blinking)
218  is_under_cursor = (cursor_x == col) & (cursor_y == row);
219  cursor_pixel = is_under_cursor & cursor_blink_on;
220  // char pixel: read from the appropiate char, row & col on the font ROM,
221  // the pixels LSB->MSB ordered
222  char_pixel = char_rom_data[7 - colc];
223  // combine, but only emit video on non-blanking periods
224  combined_pixel = (next_hblank || next_vblank)?
225  video_off :
226  char_pixel ^ cursor_pixel;
227  end
228 endmodule // video_generator
module video_generator(input clk, input reset, output reg hsync, output reg vsync, output reg video, output reg hblank, output reg vblank, input[COL_BITS-1:0] cursor_x, input[ROW_BITS-1:0] cursor_y, input cursor_blink_on, input[ADDR_BITS-1:0] first_char, output wire< ADDR_BITS-1:0 > char_buffer_address, input[8] char_buffer_data, output wire< 11:0 > char_rom_address, input[8] char_rom_data, input graphic_mode_state)
80x24 char generator (8x16 char size) & sync generator
always(posedge clk)
Definition: uart_rx.v:86