OpenCores
URL https://opencores.org/ocsvn/forth-cpu/forth-cpu/trunk

Subversion Repositories forth-cpu

[/] [forth-cpu/] [trunk/] [vga.vhd] - Blame information for rev 5

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 howe.r.j.8
-------------------------------------------------------------------------------
2
--| @file vga.vhd
3
--| @brief      Text Mode Video Controller VHDL Module and VT100
4
--|             Terminal Emulator
5 5 howe.r.j.8
--| @author     Javier Valcarce García
6
--| @author     Richard James Howe (vt100, vt100_tb, atoi, color attributes)
7
--| @copyright  Copyright 2007 Javier Valcarce García, 2017, 2019 Richard James Howe
8 3 howe.r.j.8
--| @license    LGPL version 3
9
--| @email      javier.valcarce@gmail.com
10
--| @note       (Modifications and repackaging by Richard James Howe)
11
--|
12
--| This is a modified version of the text terminal available at
13
--| <https://opencores.org/project,interface_vga80x40>. Additions include per
14 5 howe.r.j.8
--| character attribute information (color, bold, reverse video, blink text)
15
--| and a VT100 terminal interface.
16 3 howe.r.j.8
--|
17 5 howe.r.j.8
--| See also <http://www.javiervalcarce.eu/html/vhdl-vga80x40-en.html>.
18
--|
19 3 howe.r.j.8
-------------------------------------------------------------------------------
20
 
21
----- VGA Package -------------------------------------------------------------
22 5 howe.r.j.8
library ieee, work;
23 3 howe.r.j.8
use ieee.std_logic_1164.all;
24
use ieee.numeric_std.all;
25 5 howe.r.j.8
use work.util.common_generics;
26 3 howe.r.j.8
 
27
package vga_pkg is
28
        type vga_physical_interface is record
29
                red:   std_ulogic_vector(2 downto 0);
30
                green: std_ulogic_vector(2 downto 0);
31
                blue:  std_ulogic_vector(1 downto 0);
32
                hsync: std_ulogic;
33
                vsync: std_ulogic;
34
        end record;
35
 
36
        type vga_control_registers_we_interface is record
37
                crx: std_ulogic; -- Write enable for cursor X position register
38
                cry: std_ulogic; -- Write enable for VGA control register
39
                ctl: std_ulogic; -- Write enable for cursor Y position register
40
        end record;
41
 
42
        type vga_control_registers_interface is record
43
                crx:    std_ulogic_vector(6 downto 0); -- Cursor position X
44
                cry:    std_ulogic_vector(5 downto 0); -- Cursor position Y
45
                ctl:    std_ulogic_vector(4 downto 0); -- Control register
46
        end record;
47
 
48
        constant vga_control_registers_initialize: vga_control_registers_interface := (
49
                        cry => (others => '0'),
50
                        crx => (others => '0'),
51
                        ctl => (others => '0'));
52
 
53
        constant vga_control_registers_we_initialize: vga_control_registers_we_interface := (
54
                        cry => '0',
55
                        crx => '0',
56
                        ctl => '0');
57
 
58
        component vga_top is
59 5 howe.r.j.8
        generic(g: common_generics);
60 3 howe.r.j.8
        port(
61
                clk:         in  std_ulogic;
62
                clk25MHz:    in  std_ulogic;
63
                rst:         in  std_ulogic;
64
 
65
                -- VGA Text buffer interface
66
                vga_we_ram:  in  std_ulogic; -- Write enable RAM
67
                vga_din:     in  std_ulogic_vector(15 downto 0);
68
                vga_addr:    in  std_ulogic_vector(12 downto 0);
69 5 howe.r.j.8
                base:        in  std_ulogic_vector(12 downto 0);
70 3 howe.r.j.8
 
71
                -- VGA control registers
72 5 howe.r.j.8
                i_font_sel:       in std_ulogic_vector(0 downto 0);
73 3 howe.r.j.8
                i_vga_control_we: in vga_control_registers_we_interface;
74
                i_vga_control:    in vga_control_registers_interface;
75
 
76
                o_vga:    out vga_physical_interface);
77
        end component;
78
 
79
        component vga_core is
80 5 howe.r.j.8
        generic(g: common_generics);
81 3 howe.r.j.8
        port (
82
                rst:       in  std_ulogic;
83
                clk25MHz:  in  std_ulogic;
84
                text_a:    out std_ulogic_vector(11 downto 0); -- text buffer
85 5 howe.r.j.8
                text_d:    in  std_ulogic_vector(15 downto 0);
86
                font_a:    out std_ulogic_vector(12 downto 0); -- font buffer
87 3 howe.r.j.8
                font_d:    in  std_ulogic_vector( 7 downto 0);
88 5 howe.r.j.8
                font_sel:  in  std_ulogic_vector(0 downto 0);
89 3 howe.r.j.8
                 --
90
                ocrx:      in  std_ulogic_vector(6 downto 0);
91
                ocry:      in  std_ulogic_vector(5 downto 0);
92 5 howe.r.j.8
                octl:      in  std_ulogic_vector(4 downto 0);
93 3 howe.r.j.8
                --
94 5 howe.r.j.8
                o_vga: out vga_physical_interface);
95 3 howe.r.j.8
        end component;
96
 
97
        component losr is
98 5 howe.r.j.8
        generic (g: common_generics; N: positive := 4);
99 3 howe.r.j.8
        port
100
        (
101
                rst:  in  std_ulogic;
102
                clk:  in  std_ulogic;
103
                load: in  std_ulogic;
104
                ce:   in  std_ulogic;
105
                do:   out std_ulogic := '0';
106
                di:   in  std_ulogic_vector(N - 1 downto 0));
107
        end component;
108
 
109
        component ctrm is
110 5 howe.r.j.8
        generic (g: common_generics; M: positive := 8);
111 3 howe.r.j.8
        port (
112
                rst: in  std_ulogic; -- asynchronous rst
113
                clk: in  std_ulogic;
114
                ce:  in  std_ulogic; -- enable counting
115
                rs:  in  std_ulogic; -- synchronous rst
116
                do:  out integer range (M-1) downto 0 := 0);
117
        end component;
118
 
119
        component vt100 is
120 5 howe.r.j.8
        generic (g: common_generics);
121 3 howe.r.j.8
        port(
122
                clk:        in  std_ulogic;
123
                clk25MHz:   in  std_ulogic;
124
                rst:        in  std_ulogic;
125
                we:         in  std_ulogic;
126
                char:       in  std_ulogic_vector(7 downto 0);
127
 
128
                busy:       out std_ulogic;
129
                o_vga:      out vga_physical_interface);
130
        end component;
131
 
132 5 howe.r.j.8
        -- VGA test bench, not-synthesizeable
133 3 howe.r.j.8
        component vt100_tb is
134 5 howe.r.j.8
                generic(g: common_generics);
135 3 howe.r.j.8
        end component;
136
 
137
        component atoi is
138 5 howe.r.j.8
                generic(g: common_generics; N: positive := 16);
139 3 howe.r.j.8
                port(
140
                        clk:    in  std_ulogic;
141
                        rst:    in  std_ulogic;
142
                        we:     in  std_ulogic;
143
                        init:   in  std_ulogic;
144
                        char:   in  std_ulogic_vector(7 downto 0);
145
                        char_o: out std_ulogic_vector(7 downto 0);
146
                        done_o: out std_ulogic;
147 5 howe.r.j.8
                        -- ready:  out std_ulogic;
148 3 howe.r.j.8
                        n_o:    out unsigned(N - 1 downto 0));
149
        end component;
150
end package;
151
 
152
----- VGA Package -------------------------------------------------------------
153
 
154
----- VGA Test Bench ----------------------------------------------------------
155
 
156 5 howe.r.j.8
library ieee, work;
157 3 howe.r.j.8
use ieee.std_logic_1164.all;
158
use ieee.numeric_std.all;
159 5 howe.r.j.8
use ieee.math_real.all;
160 3 howe.r.j.8
use work.vga_pkg.all;
161
use work.util.all;
162
 
163
entity vt100_tb is
164 5 howe.r.j.8
        generic(g: common_generics);
165 3 howe.r.j.8
end entity;
166
 
167
architecture behav of vt100_tb is
168 5 howe.r.j.8
        constant clock_period: time := 1000 ms / g.clock_frequency;
169 3 howe.r.j.8
        signal clk, rst: std_ulogic := '0';
170
        signal stop:     std_ulogic := '0';
171
        signal clk25MHz, rst25MHz: std_ulogic := '0';
172
 
173
        signal char:     std_ulogic_vector(7 downto 0);
174
        signal we:       std_ulogic := '0';
175
        signal busy:     std_ulogic := '0';
176
        signal physical: vga_physical_interface;
177
 
178
        -- NB. 'string' range is (1 to X), not (X-1 downto 0)
179
        -- HT = Horizontal Tab
180
        -- LF = Line Feed
181
        -- CR = Carriage Return
182
        -- ESC = Escape
183 5 howe.r.j.8
        constant CSI:   string := ESC & "[";
184 3 howe.r.j.8
        constant RESET: string := CSI & "0m";
185
        constant RED:   string := CSI & "31m";
186
        constant GREEN: string := CSI & "32m";
187 5 howe.r.j.8
        constant NL:    string := CR & LF;
188 3 howe.r.j.8
        constant test_string: string := "Hello!" & HT & "World!" & RED & NL & "How are you?" & RESET & NL ;
189
        shared variable test_vector: ulogic_string(test_string'range) := to_std_ulogic_vector(test_string);
190
        shared variable index: integer := 1; -- starts at '1' due to string range
191 5 howe.r.j.8
 
192
        constant g_cs25MHz: common_generics := (clock_frequency => 25_000_000, asynchronous_reset => g.asynchronous_reset, delay => g.delay);
193 3 howe.r.j.8
begin
194
        cs: entity work.clock_source_tb
195 5 howe.r.j.8
                generic map(g => g, hold_rst => 2)
196 3 howe.r.j.8
                port map(stop => stop, clk => clk, rst => rst);
197
 
198
        cs25MHz: entity work.clock_source_tb
199 5 howe.r.j.8
                generic map(g => g_cs25MHz, hold_rst => 2)
200 3 howe.r.j.8
                port map(stop => stop, clk => clk25MHz, rst => rst25MHz);
201
 
202
 
203
        uut: work.vga_pkg.vt100
204 5 howe.r.j.8
        generic map(g => g)
205 3 howe.r.j.8
        port map(
206
                clk      => clk,
207
                clk25MHz => clk25MHz,
208
                rst      => rst,
209
                we       => we,
210
                char     => char,
211
                busy     => busy,
212
                o_vga    => physical);
213
 
214
        stimulus_process: process
215
        begin
216
                char <= test_vector(index);
217
                we <= '0';
218
                wait for clock_period * 20;
219
 
220
                for i in test_vector'range loop
221
                        we <= '1';
222
                        char <= test_vector(index);
223
                        wait for clock_period;
224
                        we <= '0';
225
                        wait for clock_period;
226
 
227
                        while busy = '1' loop
228
                                wait until busy = '0';
229
                                wait for clock_period;
230
                        end loop;
231
 
232
                        -- wait for clock_period * 20;
233
                        -- wait until busy = '0';
234
                        -- report integer'image(index);
235
                        if index < (test_vector'high - 1) then
236
                                index := index + 1;
237
                        else
238
                                index := 1;
239
                        end if;
240
                end loop;
241
 
242
                stop <= '1';
243
                wait;
244
        end process;
245
end architecture;
246
 
247
----- VGA Test Bench ----------------------------------------------------------
248
 
249
----- ATOI --------------------------------------------------------------------
250
-- The purpose of this module is to read in numeric characters ('0' through
251
-- '9') and convert the string into a binary number ('n_o'). On the first non-
252
-- numeric character the module stops and outputs that non-numeric character
253
-- as well as the converted number string. The module waits in the FINISHED
254
-- state until the module is reset by an external signal ('init').
255
--
256
-- The module is named after the C function, 'atoi', for converting a string
257
-- into an integer.
258
--
259
 
260
library ieee,work;
261
use ieee.std_logic_1164.all;
262
use ieee.numeric_std.all;
263
use work.vga_pkg.all;
264 5 howe.r.j.8
use work.util.common_generics;
265 3 howe.r.j.8
 
266
entity atoi is
267 5 howe.r.j.8
        generic(g: common_generics; N: positive := 16);
268 3 howe.r.j.8
        port(
269
                clk:    in  std_ulogic;
270
                rst:    in  std_ulogic;
271
                we:     in  std_ulogic;
272
                init:   in  std_ulogic;
273
                char:   in  std_ulogic_vector(7 downto 0);
274
                char_o: out std_ulogic_vector(7 downto 0);
275
                done_o: out std_ulogic;
276 5 howe.r.j.8
                -- ready:  out std_ulogic;
277 3 howe.r.j.8
                n_o:    out unsigned(N - 1 downto 0));
278
end entity;
279
 
280
architecture rlt of atoi is
281
        type state_type is (RESET, WAITING, COMMAND, ACCUMULATE, WRITE, FINISHED);
282
        signal state_c, state_n: state_type   := RESET;
283
        signal c_c, c_n: unsigned(char'range) := (others => '0');
284
        signal n_c, n_n: unsigned(n_o'range)  := (others => '0');
285
        signal f_c, f_n: boolean              := true;
286
begin
287
        char_o <= std_ulogic_vector(c_c);
288
        n_o    <= n_c;
289 5 howe.r.j.8
        -- ready  <= '1' when state_c = WAITING else '0';
290 3 howe.r.j.8
 
291
        process(clk, rst)
292
                variable akk: unsigned((2 * N) - 1 downto 0) := (others => '0');
293
        begin
294 5 howe.r.j.8
                if rst = '1' and g.asynchronous_reset then
295 3 howe.r.j.8
                        state_n   <= RESET;
296
                elsif rising_edge(clk) then
297 5 howe.r.j.8
                        if rst = '1' and not g.asynchronous_reset then
298
                                state_n <= RESET;
299
                        else
300
                                state_c <= state_n;
301
                                c_c     <= c_n;
302
                                n_c     <= n_n;
303
                                f_c     <= f_n;
304
                                done_o  <= '0';
305 3 howe.r.j.8
 
306 5 howe.r.j.8
                                if state_c = RESET then
307
                                        c_n     <= (others => '0');
308
                                        n_n     <= (others => '0');
309
                                        f_n     <= true;
310
                                        state_n <= WAITING;
311
                                elsif state_c = WAITING then
312
                                        if we = '1' then
313
                                                c_n     <= unsigned(char);
314
                                                state_n <= COMMAND;
315
                                        end if;
316
                                elsif state_c = COMMAND then
317
                                        state_n <= ACCUMULATE;
318
                                        case c_c is
319
                                        when x"30"  =>
320
                                        when x"31"  =>
321
                                        when x"32"  =>
322
                                        when x"33"  =>
323
                                        when x"34"  =>
324
                                        when x"35"  =>
325
                                        when x"36"  =>
326
                                        when x"37"  =>
327
                                        when x"38"  =>
328
                                        when x"39"  =>
329
                                        when others =>
330
                                                state_n <= WRITE;
331
                                        end case;
332
                                elsif state_c = ACCUMULATE then
333
                                        if f_c then
334
                                                f_n <= false;
335
                                                n_n <= n_c + (c_c - x"30");
336
                                        else
337
                                                akk := n_c * to_unsigned(10, N);
338
                                                n_n <= akk(N - 1 downto 0) + (c_c - x"30");
339
                                        end if;
340
                                        state_n <= WAITING;
341
                                elsif state_c = WRITE then
342
                                        done_o  <= '1';
343
                                        state_n <= FINISHED;
344
                                elsif state_c = FINISHED then
345
                                        null; -- wait for a reset
346 3 howe.r.j.8
                                else
347 5 howe.r.j.8
                                        state_n <= RESET;
348
                                        report "Invalid State" severity failure;
349 3 howe.r.j.8
                                end if;
350
 
351 5 howe.r.j.8
                                if init = '1' then
352
                                        assert state_c = FINISHED report "Lost Conversion" severity error;
353
                                        state_n <= RESET;
354
                                end if;
355 3 howe.r.j.8
                        end if;
356
                end if;
357
        end process;
358
 
359
end architecture;
360
----- ATOI --------------------------------------------------------------------
361
 
362
----- VT100 Terminal Emulator -------------------------------------------------
363
-- This module contains the VGA module and wraps it in a terminal emulator,
364
-- based on the VT100 <https://en.wikipedia.org/wiki/VT100>, it only implements
365
-- a subset of the commands supplied by the VT100. This simplifies the usage
366
-- of the VGA text mode display, other VHDL components only have to write bytes
367
-- and do not have to worry about cursor position or implementing new lines,
368
-- tabs, and other very basic features.
369
--
370
-- The interface is designed to act like a UART, simply write a byte to it
371
-- and so long as the interface is not busy, it will be written to the screen
372
-- (or interpreter as part of a command sequence).
373
 
374 5 howe.r.j.8
library ieee, work;
375 3 howe.r.j.8
use ieee.std_logic_1164.all;
376
use ieee.numeric_std.all;
377
use work.vga_pkg.all;
378 5 howe.r.j.8
use work.util.common_generics;
379 3 howe.r.j.8
 
380
entity vt100 is
381 5 howe.r.j.8
        generic(g: common_generics);
382 3 howe.r.j.8
        port(
383
                clk:        in  std_ulogic;
384
                clk25MHz:   in  std_ulogic;
385
                rst:        in  std_ulogic;
386
                we:         in  std_ulogic;
387
                char:       in  std_ulogic_vector(7 downto 0);
388
 
389
                busy:       out std_ulogic;
390
                o_vga:      out vga_physical_interface);
391
end entity;
392
 
393
-- A better way of structuring this would be to process numbers in parallel
394
-- with different components, one processing potential attributes, one holding
395
-- one to two numbers - the results are then used. This would deal with runs
396
-- of attributes, which is allowed.
397
architecture rtl of vt100 is
398
        constant width:  positive := 80;
399
        constant height: positive := 40;
400
        constant number: positive := 8;
401
 
402
        type state_type is (RESET, ACCEPT, NORMAL, WRAP, LIMIT, CSI, COMMAND,
403 5 howe.r.j.8
        NUMBER1, NUMBER2, COMMAND1, COMMAND2, WRITE, ERASING, ATTRIB, ADVANCE);
404 3 howe.r.j.8
        signal state_c, state_n: state_type := RESET;
405
 
406
        constant tab:          unsigned(char'range) := x"09";
407 5 howe.r.j.8
        constant backspace:    unsigned(char'range) := x"08";
408
        constant ascii_bell:   unsigned(char'range) := x"07";
409
        constant lf:           unsigned(char'range) := x"0a";
410 3 howe.r.j.8
        constant cr:           unsigned(char'range) := x"0d";
411 5 howe.r.j.8
        constant esc:          unsigned(char'range) := x"1b";
412 3 howe.r.j.8
        constant blank:        unsigned(char'range) := x"20";
413 5 howe.r.j.8
        constant asterisk:     unsigned(char'range) := x"2A";
414
        constant ascii_7:      unsigned(char'range) := x"37"; -- '7'
415
        constant ascii_8:      unsigned(char'range) := x"38"; -- '8'
416
        constant lsqb:         unsigned(char'range) := x"5b"; -- '['
417
        constant ascii_c:      unsigned(char'range) := x"63"; -- 'c'
418 3 howe.r.j.8
        constant attr_default: unsigned(7 downto 0) := "00111000";
419
        constant ctl_default:  unsigned(4 downto 0) := "01111";
420
 
421
        signal addr:           std_ulogic_vector(12 downto 0) := (others => '0');
422
        signal data_we:        std_ulogic                     := '0';
423
        signal x:              std_ulogic_vector(6 downto 0)  := (others => '0');
424
        signal y:              std_ulogic_vector(5 downto 0)  := (others => '0');
425
        signal cursor_we:      std_ulogic                     := '0';
426
 
427
        signal x_n, x_c:       unsigned(x'range)    := (others => '0');
428
        signal y_n, y_c:       unsigned(y'range)    := (others => '0');
429
        signal c_n, c_c:       unsigned(char'range) := (others => '0');
430
 
431
        signal attr_c, attr_n: unsigned(attr_default'range) := attr_default;
432
        signal ctl_c, ctl_n:   unsigned(ctl_default'range)  := ctl_default;
433
 
434
        signal n1_n, n1_c:     unsigned(7 downto 0) := (others => '0');
435
        signal n2_n, n2_c:     unsigned(6 downto 0) := (others => '0');
436
 
437
        signal conceal_n, conceal_c: boolean := false;
438
 
439
        signal x_minus_one:         unsigned(x'range) := (others => '0');
440
        signal x_minus_one_limited: unsigned(x'range) := (others => '0');
441
        signal x_underflow:         boolean           := false;
442
        signal x_plus_one:          unsigned(x'range) := (others => '0');
443
        signal x_plus_one_limited:  unsigned(x'range) := (others => '0');
444
        signal x_overflow:          boolean           := false;
445
 
446
        signal y_minus_one:         unsigned(y'range) := (others => '0');
447
        signal y_minus_one_limited: unsigned(y'range) := (others => '0');
448
        signal y_underflow:         boolean           := false;
449
        signal y_plus_one:          unsigned(y'range) := (others => '0');
450
        signal y_plus_one_limited:  unsigned(y'range) := (others => '0');
451
        signal y_overflow:          boolean           := false;
452
 
453
        signal count_c, count_n:    unsigned(addr'range) := (others => '0');
454
        signal limit_c, limit_n:    unsigned(addr'high - 3 downto 0) := (others => '0');
455
 
456
        signal akk_done_o:  std_ulogic := '0';
457 5 howe.r.j.8
        -- signal akk_ready_o: std_ulogic := '0';
458 3 howe.r.j.8
        signal akk_init:    std_ulogic := '0';
459
        signal n_o:         unsigned(number - 1 downto 0) := (others => '0');
460 5 howe.r.j.8
        signal akk_char_o:  std_ulogic_vector(char'range) := (others => '0');
461
 
462
        signal font_sel_c, font_sel_n: std_ulogic_vector(0 downto 0) := (others => '0');
463
 
464
        signal saved_x_n, saved_x_c:       unsigned(x'range)    := (others => '0');
465
        signal saved_y_n, saved_y_c:       unsigned(y'range)    := (others => '0');
466
        signal saved_attr_n, saved_attr_c: unsigned(attr_default'range) := (others => '0');
467
 
468
        signal reverse_video_c, reverse_video_n: boolean := false;
469
        signal base_n, base_c: unsigned(addr'high downto 4) := (others => '0');
470
        signal addr_sel:       unsigned(addr'range) := (others => '0');
471
 
472
        signal saved_base_n, saved_base_c: unsigned(base_c'range) := (others => '0');
473
        signal is_base_saved_n, is_base_saved_c: boolean := false;
474
 
475 3 howe.r.j.8
begin
476
        accumulator_0: work.vga_pkg.atoi
477 5 howe.r.j.8
                generic map(g => g, N => number)
478 3 howe.r.j.8
                port map(
479
                        clk    => clk,
480
                        rst    => rst,
481
                        we     => we,
482
                        init   => akk_init,
483
                        char   => char,
484
                        char_o => akk_char_o,
485
                        done_o => akk_done_o,
486 5 howe.r.j.8
                        -- ready  => akk_ready_o,
487 3 howe.r.j.8
                        n_o    => n_o);
488
 
489
        address: block
490 5 howe.r.j.8
                signal mul: unsigned(15 downto 0)     := (others => '0');
491 3 howe.r.j.8
                signal addr_int: unsigned(addr'range) := (others => '0');
492
        begin
493
                mul      <= to_unsigned(to_integer(y_c) * width, mul'length);
494
                addr_int <= mul(addr_int'range) + ("000000" & x_c);
495 5 howe.r.j.8
                addr_sel <= addr_int when state_c /= ERASING else count_c;
496
                addr     <= std_ulogic_vector(addr_sel + (base_c & "0000"));
497 3 howe.r.j.8
        end block;
498
 
499
        x_minus_one         <= x_c - 1;
500
        x_plus_one          <= x_c + 1;
501 5 howe.r.j.8
        x_overflow          <= x_c         >  (width  - 1);
502
        x_underflow         <= x_minus_one >= (width  - 1);
503 3 howe.r.j.8
        x_minus_one_limited <= (others => '0') when x_underflow else x_minus_one;
504
        x_plus_one_limited  <= to_unsigned(width - 1, x_c'length) when x_overflow else x_plus_one;
505
 
506
        y_plus_one          <= y_c + 1;
507
        y_minus_one         <= y_c - 1;
508 5 howe.r.j.8
        y_overflow          <= y_c         >= (height - 1); -- NB. > for 1 more row, slightly off edge of screen
509
        y_underflow         <= y_minus_one >  (height - 1);
510 3 howe.r.j.8
        y_minus_one_limited <= (others => '0') when y_underflow else y_minus_one;
511
        y_plus_one_limited  <= to_unsigned(height - 1, y_c'length) when y_overflow else y_plus_one;
512
 
513 5 howe.r.j.8
        busy <= '1' when state_c = ERASING
514
                        or state_c = WRITE
515
                        or state_c = RESET
516
                        or state_c = WRAP
517
                        or state_c = ATTRIB
518
                        or state_c = ADVANCE
519
                        else '0';
520 3 howe.r.j.8
 
521
        vga_blk: block
522
                signal vga_din:    std_ulogic_vector(15 downto 0)     := (others => '0');
523
                signal vga_ctr_we: vga_control_registers_we_interface := vga_control_registers_we_initialize;
524
                signal vga_ctr:    vga_control_registers_interface    := vga_control_registers_initialize;
525
                signal attr:       unsigned(attr_c'range)             := attr_default;
526 5 howe.r.j.8
                signal ch:         std_ulogic_vector(c_c'range)       := (others => '0');
527 3 howe.r.j.8
        begin
528 5 howe.r.j.8
                ch             <= std_ulogic_vector(asterisk) when conceal_c else std_ulogic_vector(c_c);
529 3 howe.r.j.8
                attr           <= attr_c when state_c /= ERASING else attr_default;
530 5 howe.r.j.8
                vga_din        <= std_ulogic_vector(attr) & ch;
531
                vga_ctr.crx    <= std_ulogic_vector(x_plus_one); -- not limited, goes off screen edge
532 3 howe.r.j.8
                vga_ctr.cry    <= std_ulogic_vector(y_c);
533
                vga_ctr.ctl    <= std_ulogic_vector(ctl_c);
534
                vga_ctr_we.crx <= cursor_we;
535
                vga_ctr_we.cry <= cursor_we;
536
                vga_ctr_we.ctl <= cursor_we;
537
 
538
                vga_0: work.vga_pkg.vga_top
539 5 howe.r.j.8
                generic map(g => g)
540 3 howe.r.j.8
                port map(
541
                        clk               =>  clk,
542
                        clk25MHz          =>  clk25MHz,
543
                        rst               =>  rst,
544
                        vga_we_ram        =>  data_we,
545
                        vga_din           =>  vga_din,
546
                        vga_addr          =>  addr,
547 5 howe.r.j.8
                        base(base_c'range)=>  std_ulogic_vector(base_c),
548
                        base(3 downto 0)  =>  "0000",
549
                        i_font_sel        =>  font_sel_c,
550 3 howe.r.j.8
                        i_vga_control_we  =>  vga_ctr_we,
551
                        i_vga_control     =>  vga_ctr,
552
                        o_vga             =>  o_vga);
553
        end block;
554
 
555
        -- Subset of commands implemented:
556
        -- ED  - Erase Display, CSI n 'J'
557
        -- RIS - Erase Display, ESC 'c'
558
        -- SGR - Select Graphic Rendition - for colors, CSI n 'm'
559
        -- HVP - Horizontal and Vertical Position - CSI n ; m 'f'
560
        -- The cursor commands are also supported: CUU, CUD, CUF,
561
        -- CUB, CNL, CPL and CHA
562
        fsm: process(clk, rst)
563
                variable limit_value: unsigned(addr'range) := (others => '0');
564
                variable repeat:      boolean    := false;
565
                variable exit_repeat: state_type := RESET;
566 5 howe.r.j.8
                procedure reverse_video(a: unsigned(2 downto 0); foreground: boolean) is
567
                begin
568
                        if foreground then
569
                                if reverse_video_c then
570
                                        attr_n(2 downto 0) <= a;
571
                                else
572
                                        attr_n(5 downto 3) <= a;
573
                                end if;
574
                        else
575
                                if reverse_video_c then
576
                                        attr_n(5 downto 3) <= a;
577
                                else
578
                                        attr_n(2 downto 0) <= a;
579
                                end if;
580
                        end if;
581
                end procedure;
582 3 howe.r.j.8
        begin
583 5 howe.r.j.8
                if rst = '1' and g.asynchronous_reset then
584 3 howe.r.j.8
                        state_c <= RESET;
585
                elsif rising_edge(clk) then
586 5 howe.r.j.8
                        if rst = '1' and not g.asynchronous_reset then
587
                                state_c <= RESET;
588
                        else
589
                                x_c             <= x_n;
590
                                y_c             <= y_n;
591
                                c_c             <= c_n;
592
                                count_c         <= count_n;
593
                                limit_c         <= limit_n;
594
                                state_c         <= state_n;
595
                                n1_c            <= n1_n;
596
                                n2_c            <= n2_n;
597
                                data_we         <= '0';
598
                                cursor_we       <= '0';
599
                                akk_init        <= '0';
600
                                attr_c          <= attr_n;
601
                                ctl_c           <= ctl_n;
602
                                conceal_c       <= conceal_n;
603
                                font_sel_c      <= font_sel_n;
604
                                saved_x_c       <= saved_x_n;
605
                                saved_y_c       <= saved_y_n;
606
                                saved_attr_c    <= saved_attr_n;
607
                                reverse_video_c <= reverse_video_n;
608
                                base_c          <= base_n;
609
                                saved_base_c    <= saved_base_n;
610
                                is_base_saved_c <= is_base_saved_n;
611 3 howe.r.j.8
 
612 5 howe.r.j.8
                                if state_c = RESET then
613
                                        n1_n         <= (others => '0');
614
                                        n2_n         <= (others => '0');
615
                                        x_n          <= (others => '0');
616
                                        y_n          <= (others => '0');
617
                                        c_n          <= (others => '0');
618
                                        count_n      <= (others => '0');
619
                                        limit_n      <= (others => '0');
620
                                        saved_x_n    <= (others => '0');
621
                                        saved_y_n    <= (others => '0');
622
                                        saved_attr_n <= (others => '0');
623
                                        font_sel_n   <= (others => '0');
624
                                        state_n      <= ACCEPT;
625
                                        attr_n       <= attr_default;
626
                                        ctl_n        <= ctl_default;
627
                                        conceal_n    <= false;
628
                                        reverse_video_n <= false;
629
                                        base_n       <= (others => '0');
630
                                        is_base_saved_n <= false;
631
                                        saved_base_n <= (others => '0');
632
                                elsif state_c = ACCEPT then
633
                                        if we = '1' then
634
                                                c_n     <= unsigned(char);
635
                                                state_n <= NORMAL;
636
                                        end if;
637
                                        -- This behavior does not really mix well
638
                                        -- with the eForth interpreter.
639
                                        --
640
                                        -- if is_base_saved_c then
641
                                        --      is_base_saved_n <= false;
642
                                        --      base_n          <= saved_base_c;
643
                                        -- end if;
644
                                elsif state_c = NORMAL then
645
                                        case c_c is
646
                                        when tab =>
647
                                                x_n     <= (x_c and "1111000") + 8;
648
                                                state_n <= ERASING;
649
                                                c_n     <= blank;
650
                                                limit_value := unsigned(addr and "1111111111000") + 8;
651
                                                limit_n <= limit_value(limit_n'high + 3 downto limit_n'low + 3);
652
                                                count_n <= unsigned(addr);
653
                                        when ascii_bell =>
654
                                                ctl_n(4) <= not ctl_c(4); -- ctr_n(4) goes to edge triggered logic
655
                                                state_n  <= ACCEPT;
656
                                        when cr =>
657
                                                y_n     <= y_plus_one;
658
                                                state_n <= WRAP;
659
                                        when lf =>
660
                                                x_n     <= (others => '0');
661
                                                state_n <= WRITE;
662
                                        when backspace =>
663
                                                x_n     <= x_minus_one_limited;
664
                                                state_n <= WRITE;
665
                                        when esc =>
666
                                                state_n <= CSI;
667
                                        when others =>
668
                                                data_we <= '1';
669
                                                state_n <= ADVANCE;
670
                                        end case;
671
                                elsif state_c = ADVANCE then
672
                                        x_n     <= x_plus_one;
673 3 howe.r.j.8
                                        state_n <= WRAP;
674 5 howe.r.j.8
                                elsif state_c = CSI then
675
                                        if we = '1' then
676
                                                c_n     <= unsigned(char);
677
                                                state_n <= COMMAND;
678
                                        end if;
679
                                elsif state_c = COMMAND then
680
                                        case c_c is
681
                                        when ascii_c =>
682
                                                x_n     <= (others => '0');
683
                                                y_n     <= (others => '0');
684
                                                c_n     <= blank;
685
                                                count_n <= (others => '0');
686
                                                limit_n <= "1000000000";
687
                                                state_n <= ERASING;
688
                                                base_n  <= (others => '0');
689
                                        when lsqb =>
690
                                                state_n  <= NUMBER1;
691
                                                akk_init <= '1';
692 3 howe.r.j.8
 
693 5 howe.r.j.8
                                        when ascii_7 => -- 'ESC 7'; Save Cursor and Attributes
694
                                                saved_x_n    <= x_c;
695
                                                saved_y_n    <= y_c;
696
                                                saved_attr_n <= attr_c;
697
                                                state_n      <= ACCEPT;
698
                                        when ascii_8 => -- 'ESC 8'; Restore Cursor and Attributes
699
                                                x_n          <= saved_x_c;
700
                                                y_n          <= saved_y_c;
701
                                                attr_n       <= saved_attr_c;
702
                                                state_n      <= ACCEPT;
703
                                        when others => -- Error
704
                                                state_n <= ACCEPT;
705
                                        end case;
706
                                elsif state_c = NUMBER1 then
707
                                        if akk_done_o = '1' then
708
                                                state_n <= COMMAND1;
709
                                                n1_n    <= n_o(n1_n'range);
710
                                        end if;
711
                                elsif state_c = COMMAND1 then
712
                                        repeat := false;
713
                                        case akk_char_o is
714
                                        when x"41" => -- CSI n 'A' : CUU Cursor up
715
                                                y_n         <= y_minus_one_limited;
716
                                                exit_repeat := WRITE;
717
                                                repeat      := true;
718
                                        when x"42" => -- CSI n 'B' : CUD Cursor Down
719
                                                y_n         <= y_plus_one_limited;
720
                                                exit_repeat := LIMIT;
721
                                                repeat      := true;
722
                                        when x"43" => -- CSI n 'C' : CUF Cursor Forward
723
                                                x_n         <= x_plus_one_limited;
724
                                                exit_repeat := LIMIT;
725
                                                repeat      := true;
726
                                        when x"44" => -- CSI n 'D' : CUB Cursor Back
727
                                                x_n         <= x_minus_one_limited;
728
                                                exit_repeat := WRITE;
729
                                                repeat      := true;
730
                                        when x"45" => -- CSI n 'E'
731
                                                y_n         <= y_minus_one_limited;
732
                                                x_n         <= (others => '0');
733
                                                exit_repeat := WRITE;
734
                                                repeat      := true;
735
                                        when x"46" => -- CSI n 'F'
736
                                                y_n         <= y_plus_one_limited;
737
                                                x_n         <= (others => '0');
738
                                                exit_repeat := LIMIT;
739
                                                repeat      := true;
740
                                        when x"47" => -- CSI n 'G' : CHA Cursor Horizontal Absolute
741
                                                x_n      <= n1_c(x_n'range);
742
                                                state_n  <= LIMIT;
743
                                        when x"4a" => -- CSI n 'J'
744
                                                x_n       <= (others => '0');
745
                                                y_n       <= (others => '0');
746
                                                base_n    <= (others => '0');
747
                                                cursor_we <= '1';
748
                                                state_n   <= ERASING;
749
                                                c_n       <= blank;
750
                                                count_n   <= (others => '0');
751
                                                limit_n   <= "1000000000";
752
                                        when x"3b" => -- ESC n ';' ...
753
                                                state_n <= NUMBER2;
754
                                                akk_init <= '1';
755
                                        when x"6d" => -- CSI n 'm' : SGR
756
                                                state_n <= ATTRIB;
757 3 howe.r.j.8
 
758 5 howe.r.j.8
                                        -- NB. Number parameter does nothing.
759
                                        when x"53" => -- CSI n 'S' : scroll up
760
                                                saved_base_n <= base_c;
761
                                                is_base_saved_n <= true;
762
                                                base_n   <= (others => '0');
763
                                                state_n  <= WRITE;
764
                                        when x"54" => -- CSI n 'T' : scroll down
765
                                                state_n  <= WRITE;
766
                                                if is_base_saved_c then
767
                                                        base_n <= saved_base_c;
768
                                                        is_base_saved_n <= false;
769
                                                end if;
770
                                        when x"73" => -- CSI 's': SCP (Secure, Contain, Protect the Cursor Position)
771
                                                saved_x_n    <= x_c;
772
                                                saved_y_n    <= y_c;
773
                                                state_n      <= ACCEPT;
774
                                        when x"75" => -- CSI 'u': RCP Restore Cursor Position
775
                                                x_n          <= saved_x_c;
776
                                                y_n          <= saved_y_c;
777
                                                state_n      <= ACCEPT;
778
 
779
                                        -- This is an extension, it is for setting the
780
                                        -- control lines of the VGA module directly.
781
                                        when x"78" => -- ESC n 'x' : Set VGA control registers directly
782
                                                ctl_n    <= n1_c(ctl_n'range);
783
                                                state_n  <= WRITE;
784
                                        when others => -- Error
785
                                                state_n <= ACCEPT;
786
                                        end case;
787
 
788
                                        if repeat then
789
                                                if n1_c <= 1 then
790
                                                        state_n <= exit_repeat;
791
                                                else
792
                                                        n1_n <= n1_c - 1;
793
                                                end if;
794
                                        end if;
795
                                elsif state_c = NUMBER2 then
796
                                        if akk_done_o = '1' then
797
                                                state_n <= COMMAND2;
798
                                                n2_n    <= n_o(n2_n'range);
799
                                        end if;
800
                                elsif state_c = COMMAND2 then
801
                                        case akk_char_o is
802
                                        when x"66" => -- f
803
                                                y_n       <= n1_c(y_n'range) - 1;
804
                                                x_n       <= n2_c(x_n'range) - 1;
805
                                                cursor_we <= '1';
806
                                                state_n   <= LIMIT;
807
                                        when x"48" => -- H
808
                                                y_n       <= n1_c(y_n'range) - 1;
809
                                                x_n       <= n2_c(x_n'range) - 1;
810
                                                cursor_we <= '1';
811
                                                state_n   <= LIMIT;
812
                                        when x"6d" => -- ESC n ';' m 'm'
813
                                                state_n <= ATTRIB;
814
                                        when others =>
815
                                                state_n <= ACCEPT;
816
                                        end case;
817
                                elsif state_c = WRAP then
818
                                        if x_overflow then
819
                                                x_n <= (others => '0');
820
                                                y_n <= y_plus_one;
821
                                        elsif y_overflow then
822
                                                x_n     <= (others => '0');
823
                                                y_n     <= y_minus_one;
824
                                                state_n <= ERASING;
825
                                                c_n     <= blank;
826
                                                count_n <= unsigned(addr_sel);
827
                                                limit_value := unsigned(addr_sel) + (3*width);
828
                                                limit_n <= limit_value(limit_n'high + 3 downto limit_n'low + 3);
829
                                                base_n  <= base_c + (width / 16);
830 3 howe.r.j.8
                                        else
831 5 howe.r.j.8
                                                state_n <= WRITE;
832 3 howe.r.j.8
                                        end if;
833 5 howe.r.j.8
                                elsif state_c = LIMIT then
834
                                        if x_overflow then
835
                                                x_n <= to_unsigned(width - 1, x_n'high + 1);
836
                                        end if;
837
                                        if y_overflow then
838
                                                y_n <= to_unsigned(height - 1, y_n'high + 1);
839
                                        end if;
840
                                        state_n <= WRITE;
841
                                elsif state_c = WRITE then
842
                                        state_n   <= ACCEPT;
843 3 howe.r.j.8
                                        cursor_we <= '1';
844 5 howe.r.j.8
                                elsif state_c = ERASING then
845
                                        if count_c(limit_c'high + 3 downto limit_c'low + 3) /= limit_c then
846
                                                count_n <= count_c + 1;
847
                                                data_we <= '1';
848
                                        else
849
                                                state_n <= WRAP;
850
                                        end if;
851
                                elsif state_c = ATTRIB then
852
                                        case n1_c is
853
                                        when x"00"  =>
854
                                                attr_n          <= attr_default;
855
                                                conceal_n       <= false;
856
                                                reverse_video_n <= false;
857
                                        when x"01"  => attr_n(6) <= '1'; -- bold
858
                                        -- when x"02"  => -- faint
859
                                        when x"16"  => attr_n(6) <= '0'; -- normal brightness
860
                                        when x"05"  => attr_n(7) <= '1'; -- slow blink
861
                                        when x"19"  => attr_n(7) <= '0'; -- blink off
862
                                        when x"07"  =>
863
                                                if not reverse_video_c then
864
                                                        attr_n    <= attr_c(7 downto 6) & attr_c(2 downto 0) & attr_c(5 downto 3);
865
                                                end if;
866
                                                reverse_video_n <= true;
867
                                        when x"1B" =>
868
                                                if reverse_video_c then
869
                                                        attr_n    <= attr_c(7 downto 6) & attr_c(2 downto 0) & attr_c(5 downto 3);
870
                                                end if;
871
                                                reverse_video_n <= false;
872
                                        when x"08"  => conceal_n <= true;
873
                                        when x"1C"  => conceal_n <= false;
874 3 howe.r.j.8
 
875 5 howe.r.j.8
                                        when x"0A"  => font_sel_n <= (others => '0');
876
                                        when x"0B"  => font_sel_n <= "1";
877 3 howe.r.j.8
 
878 5 howe.r.j.8
                                        when x"1E"  => reverse_video("000", true); -- 30
879
                                        when x"1F"  => reverse_video("001", true);
880
                                        when x"20"  => reverse_video("010", true);
881
                                        when x"21"  => reverse_video("011", true);
882
                                        when x"22"  => reverse_video("100", true);
883
                                        when x"23"  => reverse_video("101", true);
884
                                        when x"24"  => reverse_video("110", true);
885
                                        when x"25"  => reverse_video("111", true);
886 3 howe.r.j.8
 
887 5 howe.r.j.8
                                        when x"28"  => reverse_video("000", false); -- 40
888
                                        when x"29"  => reverse_video("001", false);
889
                                        when x"2A"  => reverse_video("010", false);
890
                                        when x"2B"  => reverse_video("011", false);
891
                                        when x"2C"  => reverse_video("100", false);
892
                                        when x"2D"  => reverse_video("101", false);
893
                                        when x"2E"  => reverse_video("110", false);
894
                                        when x"2F"  => reverse_video("111", false);
895 3 howe.r.j.8
 
896 5 howe.r.j.8
                                        when others =>
897
                                        end case;
898
                                        state_n <= ACCEPT;
899
                                else
900
                                        state_n <= RESET;
901
                                        report "Invalid State" severity failure;
902
                                end if;
903 3 howe.r.j.8
                        end if;
904
                end if;
905
        end process;
906
end architecture;
907
----- VT100 Terminal Emulator -------------------------------------------------
908
 
909
----- VGA Top Level Component -------------------------------------------------
910
library ieee,work;
911
use ieee.std_logic_1164.all;
912
use ieee.numeric_std.all;
913
use work.vga_pkg.all;
914
use work.util.file_format;
915 5 howe.r.j.8
use work.util.file_hex;
916
use work.util.file_binary;
917
use work.util.common_generics;
918 3 howe.r.j.8
 
919
entity vga_top is
920 5 howe.r.j.8
        generic(g: common_generics);
921 3 howe.r.j.8
        port(
922
                clk:              in  std_ulogic;
923
                clk25MHz:         in  std_ulogic;
924
                rst:              in  std_ulogic;
925
 
926
                -- VGA Text buffer interface
927
                vga_we_ram:       in  std_ulogic; -- Write enable RAM
928
                vga_din:          in  std_ulogic_vector(15 downto 0);
929
                vga_addr:         in  std_ulogic_vector(12 downto 0);
930 5 howe.r.j.8
                base:             in  std_ulogic_vector(12 downto 0);
931 3 howe.r.j.8
 
932
                -- VGA control registers
933 5 howe.r.j.8
                i_font_sel:       in std_ulogic_vector(0 downto 0);
934 3 howe.r.j.8
                i_vga_control_we: in vga_control_registers_we_interface;
935
                i_vga_control:    in vga_control_registers_interface;
936
 
937
                o_vga:            out vga_physical_interface);
938
end;
939
 
940
architecture behav of vga_top is
941
        -- Setup for text buffer memory
942
        constant text_addr_length: positive    := 13;
943
        constant text_data_length: positive    := 16;
944
        constant text_file_name:   string      := "text.hex";
945
        constant text_file_type:   file_format := FILE_HEX;
946
 
947
        -- Setup for font buffer memory
948 5 howe.r.j.8
        constant font_addr_length: positive    := 13;
949 3 howe.r.j.8
        constant font_data_length: positive    := 8;
950
        constant font_file_name:   string      := "font.bin";
951
        constant font_file_type:   file_format := FILE_BINARY;
952
 
953
        -- Internal signals for mapping output <--> VGA module
954
        signal  foreground_draw_internal:      std_ulogic := '0';
955
 
956
        -- Text RAM signals, RAM <--> VGA module
957
        signal  text_dout:       std_ulogic_vector(15 downto 0) := (others => '0');
958
        signal  text_din:        std_ulogic_vector(15 downto 0) := (others => '0');
959
        signal  text_addr:       std_ulogic_vector(11 downto 0) := (others => '0');
960
        signal  text_addr_full:  std_ulogic_vector(12 downto 0) := (others => '0');
961
 
962
        -- Font ROM signals, ROM<-->VGA module
963 5 howe.r.j.8
        signal  font_addr:       std_ulogic_vector(12 downto 0) := (others => '0');
964 3 howe.r.j.8
        signal  font_dout:       std_ulogic_vector( 7 downto 0) := (others => '0');
965
 
966
        signal  control_c, control_n: vga_control_registers_interface := vga_control_registers_initialize;
967
 
968
        signal  foreground_draw: std_ulogic := '0';
969
        signal  background_draw: std_ulogic := '0';
970
begin
971
 
972
        vga_ns: process(clk, rst)
973
        begin
974 5 howe.r.j.8
                if rst = '1' and g.asynchronous_reset then
975 3 howe.r.j.8
                        control_c   <= vga_control_registers_initialize;
976
                elsif rising_edge(clk) then
977 5 howe.r.j.8
                        if rst = '1' and not g.asynchronous_reset then
978
                                control_c <= vga_control_registers_initialize;
979
                        else
980
                                control_c <= control_n;
981
                        end if;
982 3 howe.r.j.8
                end if;
983
        end process;
984
 
985
        vga_creg_we: process(
986
                control_c,
987
                i_vga_control,
988
                i_vga_control_we)
989
        begin
990
                control_n <= control_c;
991
 
992
                if i_vga_control_we.crx = '1' then control_n.crx <= i_vga_control.crx; end if;
993
                if i_vga_control_we.cry = '1' then control_n.cry <= i_vga_control.cry; end if;
994
                if i_vga_control_we.ctl = '1' then control_n.ctl <= i_vga_control.ctl; end if;
995
        end process;
996
 
997 5 howe.r.j.8
        u_vga: work.vga_pkg.vga_core
998
                generic map(g => g)
999
                port map (
1000 3 howe.r.j.8
                rst       => rst,
1001
                clk25MHz  => clk25MHz,
1002
 
1003
                text_a    => text_addr,
1004 5 howe.r.j.8
                text_d    => text_dout,
1005 3 howe.r.j.8
 
1006
                font_a    => font_addr,
1007
                font_d    => font_dout,
1008
 
1009 5 howe.r.j.8
                font_sel  => i_font_sel,
1010
 
1011 3 howe.r.j.8
                ocrx      => control_c.crx,
1012
                ocry      => control_c.cry,
1013 5 howe.r.j.8
                octl      => control_c.ctl,
1014 3 howe.r.j.8
 
1015 5 howe.r.j.8
                o_vga     => o_vga);
1016 3 howe.r.j.8
 
1017 5 howe.r.j.8
        text_addr_full <= std_ulogic_vector(unsigned(base) + unsigned(text_addr));
1018 3 howe.r.j.8
 
1019 5 howe.r.j.8
        u_text_memory: entity work.dual_port_block_ram -- holds at least 80x40 characters
1020
        generic map(g => g,
1021
                addr_length => text_addr_length,
1022
                data_length => text_data_length,
1023
                file_name   => text_file_name,
1024
                file_type   => text_file_type)
1025 3 howe.r.j.8
        port map (
1026
                a_clk   => clk,
1027
                -- External interface
1028
                a_dwe   => vga_we_ram,
1029
                a_dre   => '1',
1030
                a_addr  => vga_addr,
1031
                a_din   => vga_din,
1032 5 howe.r.j.8
                a_dout  => open,
1033 3 howe.r.j.8
                -- Internal interface
1034
                b_clk   => clk25MHz,
1035
                b_dwe   => '0',
1036
                b_dre   => '1',
1037
                b_addr  => text_addr_full,
1038
                b_din   => (others => '0'),
1039
                b_dout  => text_dout);
1040
 
1041 5 howe.r.j.8
        u_font_memory: entity work.single_port_block_ram
1042
        generic map(g => g,
1043 3 howe.r.j.8
                addr_length => font_addr_length,
1044
                data_length => font_data_length,
1045
                file_name   => font_file_name,
1046
                file_type   => font_file_type)
1047
        port map (
1048
                clk  => clk25MHz,
1049
                dwe  => '0',
1050
                dre  => '1',
1051
                addr => font_addr,
1052
                din  => (others => '0'),
1053
                dout => font_dout);
1054
 
1055
end architecture;
1056
 
1057
----- VGA Top Level Component -------------------------------------------------
1058
 
1059
----- VGA Core ----------------------------------------------------------------
1060
 
1061
library ieee;
1062
use ieee.std_logic_1164.all;
1063
use ieee.numeric_std.all;
1064 5 howe.r.j.8
use work.vga_pkg.all;
1065
use work.util.common_generics;
1066 3 howe.r.j.8
 
1067
entity vga_core is
1068 5 howe.r.j.8
        generic(g: common_generics);
1069 3 howe.r.j.8
        port (
1070
                rst:      in  std_ulogic;
1071
                clk25MHz: in  std_ulogic;
1072
                text_a:   out std_ulogic_vector(11 downto 0); -- text buffer
1073 5 howe.r.j.8
                text_d:   in  std_ulogic_vector(15 downto 0);
1074
                font_a:   out std_ulogic_vector(12 downto 0); -- font buffer
1075 3 howe.r.j.8
                font_d:   in  std_ulogic_vector( 7 downto 0);
1076 5 howe.r.j.8
                font_sel: in  std_ulogic_vector(0 downto 0);
1077
                --
1078 3 howe.r.j.8
                ocrx:     in  std_ulogic_vector(6 downto 0);
1079
                ocry:     in  std_ulogic_vector(5 downto 0);
1080 5 howe.r.j.8
                octl:     in  std_ulogic_vector(4 downto 0);
1081 3 howe.r.j.8
                --
1082 5 howe.r.j.8
                o_vga:    out vga_physical_interface);
1083 3 howe.r.j.8
end entity;
1084
 
1085
architecture rtl of vga_core is
1086
        signal foreground_draw_int, background_draw_int: std_ulogic := '0';
1087
        signal hsync_int: std_ulogic := '1';
1088
        signal vsync_int: std_ulogic := '1';
1089
 
1090
        signal blank: std_ulogic := '0';
1091
        signal hctr:  integer range 793 downto 0 := 0;
1092
        signal vctr:  integer range 524 downto 0 := 0;
1093
 
1094
        -- character/pixel position on the screen
1095 5 howe.r.j.8
        signal scry_text:  integer range 39 downto 0 := 0; -- chr row   < 40 (6 bits)
1096
        signal scrx_text:  integer range 79 downto 0 := 0; -- chr col   < 80 (7 bits)
1097
        signal chry:  integer range 11 downto 0 := 0; -- chr hight < 12 (4 bits)
1098
        signal chrx:  integer range 7  downto 0 := 0; -- chr width < 08 (3 bits)
1099 3 howe.r.j.8
 
1100
        signal losr_ce: std_ulogic := '0';
1101
        signal losr_ld: std_ulogic := '0';
1102
        signal losr_do: std_ulogic := '0';
1103
        signal y:       std_ulogic := '0';  -- character luminance pixel value (0 or 1)
1104
 
1105
        -- control io register
1106 5 howe.r.j.8
        signal bell:      std_ulogic := '0';
1107 3 howe.r.j.8
        signal vga_en:    std_ulogic := '0';
1108
        signal cur_en:    std_ulogic := '0';
1109
        signal cur_mode:  std_ulogic := '0';
1110
        signal cur_blink: std_ulogic := '0';
1111
 
1112 5 howe.r.j.8
        signal background_draw, foreground_draw: std_ulogic := '0';
1113
        signal attr:          std_ulogic_vector(7 downto 0) := (others =>'0');
1114
        signal attr_we_delay: std_ulogic := '0';
1115
        signal slowclk, slowclk_cr: std_ulogic := '0';
1116
 
1117
        signal bell_c, bell_n: std_ulogic := '0';
1118
        signal bell_on_c, bell_on_n: std_ulogic := '0';
1119 3 howe.r.j.8
begin
1120 5 howe.r.j.8
        -- Control register. Individual control signal
1121
        bell_n    <= octl(4);
1122
        bell      <= bell_c xor bell_n;
1123
        vga_en    <= octl(3);
1124
        cur_en    <= octl(2);
1125
        cur_blink <= octl(1);
1126
        cur_mode  <= octl(0);
1127 3 howe.r.j.8
 
1128 5 howe.r.j.8
        -- bell register
1129
        process (rst, clk25MHz)
1130
        begin
1131
                if rst = '1' and g.asynchronous_reset then
1132
                        bell_c    <= '0';
1133
                        bell_on_c <= '0';
1134
                elsif rising_edge(clk25MHz) then
1135
                        if rst = '1' and not g.asynchronous_reset then
1136
                                bell_c    <= '0';
1137
                                bell_on_c <= '0';
1138
                        else
1139
                                bell_c    <= bell_n;
1140
                                bell_on_c <= bell_on_n;
1141
                        end if;
1142
                end if;
1143
        end process;
1144
 
1145
        process (bell_on_c, slowclk, bell)
1146
        begin
1147
                bell_on_n <= bell_on_c;
1148
                slowclk_cr <= '0';
1149
                if bell = '1' then
1150
                        bell_on_n  <= '1';
1151
                        slowclk_cr <= '1';
1152
                elsif slowclk = '1' then
1153
                        bell_on_n <= '0';
1154
                end if;
1155
        end process;
1156
 
1157 3 howe.r.j.8
        -- hsync generator, initialized with '1'
1158
        process (rst, clk25MHz)
1159
        begin
1160 5 howe.r.j.8
                if rst = '1' and g.asynchronous_reset then
1161 3 howe.r.j.8
                        hsync_int <= '1';
1162
                elsif rising_edge(clk25MHz) then
1163 5 howe.r.j.8
                        if rst = '1' and not g.asynchronous_reset then
1164
                                hsync_int <= '1';
1165 3 howe.r.j.8
                        else
1166 5 howe.r.j.8
                                if (hctr > 663) and (hctr < 757) then
1167
                                        hsync_int <= '0';
1168
                                else
1169
                                        hsync_int <= '1';
1170
                                end if;
1171 3 howe.r.j.8
                        end if;
1172
                end if;
1173
        end process;
1174
 
1175
        -- vsync generator, initialized with '1'
1176
        process (rst, clk25MHz)
1177
        begin
1178 5 howe.r.j.8
                if rst = '1' and g.asynchronous_reset then
1179 3 howe.r.j.8
                        vsync_int <= '1';
1180
                elsif rising_edge(clk25MHz) then
1181 5 howe.r.j.8
                        if rst = '1' and not g.asynchronous_reset then
1182
                                vsync_int <= '1';
1183 3 howe.r.j.8
                        else
1184 5 howe.r.j.8
                                if (vctr > 499) and (vctr < 502) then
1185
                                        vsync_int <= '0';
1186
                                else
1187
                                        vsync_int <= '1';
1188
                                end if;
1189 3 howe.r.j.8
                        end if;
1190
                end if;
1191
        end process;
1192
 
1193
        -- Blank signal, 0 = no draw, 1 = visible/draw zone
1194
 
1195
        -- Proboscide99 31/08/08
1196
        blank <= '0' when (hctr < 8) or (hctr > 647) or (vctr > 479) else '1';
1197
 
1198 5 howe.r.j.8
        -- flip-flops for sync of R, G y B signal, initialized with '0'
1199 3 howe.r.j.8
        process (rst, clk25MHz)
1200
        begin
1201 5 howe.r.j.8
                if rst = '1' and g.asynchronous_reset then
1202 3 howe.r.j.8
                        foreground_draw <= '0';
1203
                elsif rising_edge(clk25MHz) then
1204 5 howe.r.j.8
                        if rst = '1' and not g.asynchronous_reset then
1205
                                foreground_draw <= '0';
1206
                        else
1207
                                foreground_draw <= foreground_draw_int;
1208
                                background_draw <= background_draw_int;
1209
                        end if;
1210 3 howe.r.j.8
                end if;
1211
        end process;
1212
 
1213
        -- counters, hctr, vctr, srcx, srcy, chrx, chry
1214
        counters: block
1215
                signal hctr_ce: std_ulogic := '0';
1216
                signal hctr_rs: std_ulogic := '0';
1217
                signal vctr_ce: std_ulogic := '0';
1218
                signal vctr_rs: std_ulogic := '0';
1219
 
1220
                signal chrx_ce: std_ulogic := '0';
1221
                signal chrx_rs: std_ulogic := '0';
1222
                signal chry_ce: std_ulogic := '0';
1223
                signal chry_rs: std_ulogic := '0';
1224
                signal scrx_ce: std_ulogic := '0';
1225
                signal scrx_rs: std_ulogic := '0';
1226
                signal scry_ce: std_ulogic := '0';
1227
                signal scry_rs: std_ulogic := '0';
1228
 
1229
                signal hctr_639: std_ulogic := '0';
1230
                signal vctr_479: std_ulogic := '0';
1231
                signal chrx_007: std_ulogic := '0';
1232
                signal chry_011: std_ulogic := '0';
1233
 
1234
                -- RAM read, ROM read
1235
                signal ram_tmp: unsigned(11 downto 0) := (others => '0'); -- range 3199 downto 0
1236
                signal mul:     unsigned(15 downto 0) := (others => '0');
1237
                signal rom_tmp: unsigned(11 downto 0) := (others => '0'); -- range 3071 downto 0;
1238
 
1239 5 howe.r.j.8
                signal text_d_tmp: std_ulogic_vector(7 downto 0) := (others => '0');
1240 3 howe.r.j.8
        begin
1241 5 howe.r.j.8
                u_hctr: work.vga_pkg.ctrm generic map (g => g, M => 794)
1242
                                        port map (rst, clk25MHz, hctr_ce, hctr_rs, hctr);
1243
                u_vctr: work.vga_pkg.ctrm generic map (g => g, M => 525)
1244
                                        port map (rst, clk25MHz, vctr_ce, vctr_rs, vctr);
1245 3 howe.r.j.8
 
1246
                hctr_ce <= '1';
1247
                hctr_rs <= '1' when hctr = 793 else '0';
1248
                vctr_ce <= '1' when hctr = 663 else '0';
1249
                vctr_rs <= '1' when vctr = 524 else '0';
1250
 
1251 5 howe.r.j.8
                u_chrx: work.vga_pkg.ctrm generic map (g => g, M => 8)
1252
                                        port map (rst, clk25MHz, chrx_ce, chrx_rs, chrx);
1253
                u_chry: work.vga_pkg.ctrm generic map (g => g, M => 12)
1254
                                        port map (rst, clk25MHz, chry_ce, chry_rs, chry);
1255
                u_scrx: work.vga_pkg.ctrm generic map (g => g, M => 80)
1256
                                        port map (rst, clk25MHz, scrx_ce, scrx_rs, scrx_text);
1257
                u_scry: work.vga_pkg.ctrm generic map (g => g, M => 40)
1258
                                        port map (rst, clk25MHz, scry_ce, scry_rs, scry_text);
1259 3 howe.r.j.8
 
1260
                hctr_639 <= '1' when hctr = 639 else '0';
1261
                vctr_479 <= '1' when vctr = 479 else '0';
1262
                chrx_007 <= '1' when chrx = 7 else '0';
1263
                chry_011 <= '1' when chry = 11 else '0';
1264
 
1265
                chrx_rs <= chrx_007 or hctr_639;
1266
                chry_rs <= chry_011 or vctr_479;
1267
                scrx_rs <= hctr_639;
1268
                scry_rs <= vctr_479;
1269
 
1270
                chrx_ce <= '1' and blank;
1271
                scrx_ce <= chrx_007;
1272
                chry_ce <= hctr_639 and blank;
1273
                scry_ce <= chry_011 and hctr_639;
1274
 
1275 5 howe.r.j.8
                ram_tmp <=  (to_unsigned(scry_text, ram_tmp'length) sll 4) +
1276
                                (to_unsigned(scry_text, ram_tmp'length) sll 6) +
1277
                                to_unsigned(scrx_text, ram_tmp'length);
1278 3 howe.r.j.8
 
1279 5 howe.r.j.8
                text_d_tmp <= text_d(7 downto 0);
1280 3 howe.r.j.8
                text_a  <= std_ulogic_vector(ram_tmp);
1281 5 howe.r.j.8
                mul     <= unsigned(text_d_tmp) * 12;
1282 3 howe.r.j.8
                rom_tmp <= mul(rom_tmp'range) + chry;
1283 5 howe.r.j.8
                font_a  <= font_sel & std_ulogic_vector(rom_tmp);
1284 3 howe.r.j.8
        end block;
1285
 
1286 5 howe.r.j.8
        color_block: block
1287
                signal red_on:   std_ulogic := '0';
1288
                signal green_on: std_ulogic := '0';
1289
                signal blue_on:  std_ulogic := '0';
1290
                signal bold:     std_ulogic := '0';
1291
                signal reverse:  std_ulogic := '0';
1292
                signal final:    std_ulogic_vector(2 downto 0) := "111";
1293
        begin
1294
                reverse     <= bell_on_c when attr(7) = '0' else slowclk;
1295
                bold        <= attr(6);
1296
                final       <= "100" when bold = '0' else "111";
1297 3 howe.r.j.8
 
1298 5 howe.r.j.8
                red_on      <= (reverse   xor attr(3)) when foreground_draw = '1' else
1299
                               (bell_on_c xor attr(0)) when background_draw = '1' else '0';
1300
                green_on    <= (reverse   xor attr(4)) when foreground_draw = '1' else
1301
                               (bell_on_c xor attr(1)) when background_draw = '1' else '0';
1302
                blue_on     <= (reverse   xor attr(5)) when foreground_draw = '1' else
1303
                               (bell_on_c xor attr(2)) when background_draw = '1' else '0';
1304
 
1305
                o_vga.red   <= final             when red_on    = '1' else "000";
1306
                o_vga.green <= final             when green_on  = '1' else "000";
1307
                o_vga.blue  <= final(2 downto 1) when blue_on   = '1' else "00";
1308
        end block;
1309
 
1310
        u_reg_delay: work.util.reg generic map (g => g, N => 1)
1311
        port map(clk => clk25MHz, rst => rst, we => '1', di(0) => losr_ld, do(0) => attr_we_delay);
1312
 
1313
        u_reg_attr: work.util.reg generic map (g => g, N => 8)
1314
        port map(clk => clk25MHz, rst => rst, we => attr_we_delay, di => text_d(15 downto 8), do => attr);
1315
 
1316
        u_losr: work.vga_pkg.losr generic map (g => g, N => font_d'length)
1317
        port map (rst => rst, clk => clk25MHz, load => losr_ld, ce => losr_ce, do => losr_do, di => font_d);
1318
 
1319 3 howe.r.j.8
        losr_ce <= blank;
1320
        losr_ld <= '1' when (chrx = 7) else '0';
1321
 
1322
        -- video out, vga_en control signal enable/disable vga signal
1323
        foreground_draw_int <=      y  and blank;
1324
        background_draw_int <= (not y) and blank;
1325
 
1326 5 howe.r.j.8
        o_vga.hsync <= hsync_int and vga_en;
1327
        o_vga.vsync <= vsync_int and vga_en;
1328 3 howe.r.j.8
 
1329
        -- Hardware Cursor
1330
        hw_cursor: block
1331
                signal small:   std_ulogic := '0';
1332
                signal curen2:  std_ulogic := '0';
1333
                signal curpos:  std_ulogic := '0';
1334
                signal yint:    std_ulogic := '0';
1335
                signal crx:     integer range 127 downto 0;
1336
                signal cry:     integer range 64 downto 0;
1337 5 howe.r.j.8
                signal counter: unsigned(24 downto 0) := (others => '0');
1338
                signal cursorclk: std_ulogic := '0';
1339 3 howe.r.j.8
        begin
1340 5 howe.r.j.8
                process (counter, slowclk_cr, clk25MHz)
1341
                begin
1342
                        counter <= counter;
1343
                        if rising_edge(clk25MHz) then
1344
                                if slowclk_cr = '1' then
1345
                                        counter <= (others => '0');
1346
                                else
1347
                                        counter <= counter + 1;
1348
                                end if;
1349
                        end if;
1350
                end process;
1351 3 howe.r.j.8
 
1352 5 howe.r.j.8
                cursorclk <= counter(22); -- 2.98Hz
1353
                slowclk   <= counter(24); -- 0.745Hz
1354 3 howe.r.j.8
 
1355
                crx <= to_integer(unsigned(ocrx(6 downto 0)));
1356
                cry <= to_integer(unsigned(ocry(5 downto 0)));
1357
 
1358
                --
1359 5 howe.r.j.8
                curpos <= '1' when scry_text = cry and scrx_text = crx else '0';
1360 3 howe.r.j.8
                small  <= '1' when (chry > 8)                else '0';
1361 5 howe.r.j.8
                curen2 <= (cursorclk or (not cur_blink)) and cur_en;
1362 3 howe.r.j.8
                yint   <= '1' when cur_mode = '0'            else small;
1363
                y      <= (yint and curpos and curen2) xor losr_do;
1364
        end block;
1365
end;
1366
----- VGA Core ----------------------------------------------------------------
1367
 
1368
-------------------------------------------------------------------------------
1369
--| @file ctrm.vhd
1370
--| @brief Counter, asynchronous *and* synchronous reset, up only.
1371
--|        (ctrm.vhd, original filename)
1372
--| @author         Javier Valcarce García
1373
--| @copyright      Copyright 2007 Javier Valcarce García
1374
--| @license        LGPL version 3
1375
--| @email          javier.valcarce@gmail.com
1376
-------------------------------------------------------------------------------
1377 5 howe.r.j.8
library ieee, work;
1378 3 howe.r.j.8
use ieee.std_logic_1164.all;
1379
use ieee.numeric_std.all;
1380 5 howe.r.j.8
use work.util.common_generics;
1381 3 howe.r.j.8
 
1382
entity ctrm is
1383 5 howe.r.j.8
        generic (g: common_generics; M: positive := 8);
1384 3 howe.r.j.8
        port (
1385
                rst: in  std_ulogic; -- asynchronous rst
1386
                clk: in  std_ulogic;
1387
                ce:  in  std_ulogic; -- enable counting
1388
                rs:  in  std_ulogic; -- synchronous rst
1389
                do:  out integer range (M-1) downto 0 := 0);
1390 5 howe.r.j.8
end entity;
1391 3 howe.r.j.8
 
1392
architecture rtl of ctrm is
1393
        signal c: integer range (M-1) downto 0:= 0;
1394
begin
1395
        do <= c;
1396
        process(rst, clk)
1397
        begin
1398 5 howe.r.j.8
                if rst = '1' and g.asynchronous_reset then
1399
                        c <= 0 after g.delay;
1400 3 howe.r.j.8
                elsif rising_edge(clk) then
1401 5 howe.r.j.8
                        if rst = '1' and not g.asynchronous_reset then
1402
                                c <= 0 after g.delay;
1403
                        else
1404
                                if ce = '1' then
1405
                                        if rs = '1' then
1406
                                                c <= 0 after g.delay;
1407
                                        else
1408
                                        -- elsif c /= (M - 1) then
1409
                                                c <= c + 1 after g.delay;
1410
                                        end if;
1411 3 howe.r.j.8
                                end if;
1412
                        end if;
1413
                end if;
1414
        end process;
1415
end;
1416
 
1417
-------------------------------------------------------------------------------
1418
--| @file util.vhd
1419
--| @brief Shift register N-bit, asynchronous reset, synchronous load,
1420
--|        and enable
1421
--| @author         Javier Valcarce García
1422
--| @copyright      Copyright 2007 Javier Valcarce García
1423
--| @license        LGPL version 3
1424
--| @email          javier.valcarce@gmail.com
1425
-------------------------------------------------------------------------------
1426 5 howe.r.j.8
 
1427
library ieee, work;
1428 3 howe.r.j.8
use ieee.std_logic_1164.all;
1429
use ieee.numeric_std.all;
1430 5 howe.r.j.8
use work.util.common_generics;
1431 3 howe.r.j.8
 
1432
entity losr is
1433 5 howe.r.j.8
        generic (g: common_generics; N: positive := 4);
1434 3 howe.r.j.8
        port
1435
        (
1436
                rst:  in  std_ulogic;
1437
                clk:  in  std_ulogic;
1438
                load: in  std_ulogic;
1439
                ce:   in  std_ulogic;
1440
                do:   out std_ulogic := '0';
1441
                di:   in  std_ulogic_vector(N - 1 downto 0));
1442 5 howe.r.j.8
end entity;
1443 3 howe.r.j.8
 
1444
architecture rtl of losr is
1445
begin
1446
        process(rst, clk)
1447 5 howe.r.j.8
                variable data: std_ulogic_vector(N - 1 downto 0) := (others => '0');
1448 3 howe.r.j.8
        begin
1449 5 howe.r.j.8
                if rst = '1' and g.asynchronous_reset then
1450 3 howe.r.j.8
                        data := (others => '0');
1451
                elsif rising_edge(clk) then
1452 5 howe.r.j.8
                        if rst = '1' and not g.asynchronous_reset then
1453
                                data := (others => '0');
1454
                        else
1455
                                if load = '1' then
1456
                                        data := di;
1457
                                elsif ce = '1' then
1458
                                        data := data(N-2 downto 0) & "0";
1459
                                end if;
1460 3 howe.r.j.8
                        end if;
1461
                end if;
1462 5 howe.r.j.8
                do <= data(N-1) after g.delay;
1463 3 howe.r.j.8
        end process;
1464
end;
1465
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.