Klemens Schölhorn
1c22e73128
The line where the cursor located is always displayed at the bottom and old content scrolls up until disappearing eventually at the top of the screen. This is implemented using a ring buffer of all rows, where old chars are only overwritten when writing new ones. To avoid displaying stale data at the end of rows, we save the length of every row and hide chars that were not overwritten (yet).
152 lines
4.5 KiB
VHDL
152 lines
4.5 KiB
VHDL
library ieee;
|
|
library unisim;
|
|
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.std_logic_unsigned.all;
|
|
use ieee.numeric_std.all;
|
|
-- Xilinx primitives (obufds)
|
|
use unisim.VComponents.all;
|
|
|
|
entity terminal is
|
|
generic (
|
|
clk_f: integer := 48_000_000
|
|
);
|
|
port (
|
|
clk: in std_logic;
|
|
reset: in std_logic;
|
|
|
|
write_enable: in std_logic;
|
|
write_data: in std_logic_vector(7 downto 0);
|
|
|
|
dvi_d: out std_logic_vector(11 downto 0);
|
|
dvi_clk_p: out std_logic;
|
|
dvi_clk_n: out std_logic;
|
|
dvi_hsync: out std_logic;
|
|
dvi_vsync: out std_logic;
|
|
dvi_de: out std_logic;
|
|
dvi_reset: out std_logic;
|
|
i2c_scl: inout std_logic;
|
|
i2c_sda: inout std_logic
|
|
);
|
|
end terminal;
|
|
|
|
architecture syn of terminal is
|
|
signal image_x: std_logic_vector(9 downto 0);
|
|
signal image_y: std_logic_vector(8 downto 0);
|
|
signal pixel_rgb: std_logic_vector(23 downto 0);
|
|
|
|
-- the cursor points to the position where the next char will be written
|
|
signal cursor_row: unsigned(5 downto 0);
|
|
signal cursor_col: unsigned(6 downto 0);
|
|
|
|
signal charbuf_we: std_logic;
|
|
signal charbuf_wa: std_logic_vector(12 downto 0);
|
|
signal charbuf_di: std_logic_vector(7 downto 0);
|
|
|
|
signal rowlen_we: std_logic;
|
|
signal rowlen_wa: std_logic_vector(5 downto 0);
|
|
signal rowlen_di: std_logic_vector(6 downto 0);
|
|
begin
|
|
|
|
-- writes the next character, advances the cursor and saves the length of
|
|
-- the current row before jumping to the next one
|
|
process(clk)
|
|
variable next_line: unsigned(5 downto 0);
|
|
begin
|
|
if rising_edge(clk) then
|
|
-- we write to the current cursor position and simply pass the data
|
|
-- through (but CR and LF are ignored, so charbuf_we is 0 by default)
|
|
charbuf_we <= '0';
|
|
charbuf_wa <= std_logic_vector(cursor_col) & std_logic_vector(cursor_row);
|
|
charbuf_di <= write_data;
|
|
|
|
-- we save the length of the current row before advancing to the
|
|
-- next row (the current row length is the cursor column when using
|
|
-- LF the go to the next line or one more when wrapping around)
|
|
rowlen_we <= '0';
|
|
rowlen_wa <= std_logic_vector(cursor_row);
|
|
rowlen_di <= std_logic_vector(cursor_col);
|
|
|
|
-- calculate next line
|
|
if cursor_row = 59 then
|
|
next_line := (others => '0');
|
|
else
|
|
next_line := cursor_row + 1;
|
|
end if;
|
|
|
|
if write_enable = '1' then
|
|
-- carriage return
|
|
if write_data = x"0d" then
|
|
cursor_col <= (others => '0');
|
|
|
|
-- line feed (implicit CR)
|
|
elsif write_data = x"0a" then
|
|
cursor_col <= (others => '0');
|
|
cursor_row <= next_line;
|
|
rowlen_we <= '1'; -- save row length
|
|
|
|
-- normal characters
|
|
else
|
|
charbuf_we <= '1'; -- write normal characters
|
|
if cursor_col = 79 then
|
|
cursor_col <= (others => '0');
|
|
cursor_row <= next_line;
|
|
rowlen_we <= '1'; -- save row length
|
|
rowlen_di <= "1010000"; -- 80 (cursor_col is only 79)
|
|
else
|
|
cursor_col <= cursor_col + 1;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
dvi_clk_ds: obufds port map (
|
|
I => clk,
|
|
O => dvi_clk_p,
|
|
OB => dvi_clk_n
|
|
);
|
|
|
|
init_ch7301c: entity work.init_ch7301c generic map (
|
|
input_clk => clk_f
|
|
) port map (
|
|
clk => clk,
|
|
reset => reset,
|
|
finished => open,
|
|
error => open,
|
|
i2c_scl => i2c_scl,
|
|
i2c_sda => i2c_sda,
|
|
dvi_reset => dvi_reset
|
|
);
|
|
|
|
vga: entity work.vga port map (
|
|
clk => clk,
|
|
x => image_x,
|
|
y => image_y,
|
|
pixel_rgb => pixel_rgb,
|
|
dvi_d => dvi_d,
|
|
dvi_hsync => dvi_hsync,
|
|
dvi_vsync => dvi_vsync,
|
|
dvi_de => dvi_de
|
|
);
|
|
|
|
framebuffer: entity work.framebuffer generic map (
|
|
input_clk => clk_f
|
|
) port map (
|
|
clk => clk,
|
|
x => image_x,
|
|
y => image_y,
|
|
rgb => pixel_rgb,
|
|
cursor_row => cursor_row,
|
|
cursor_col => cursor_col,
|
|
charbuf_we => charbuf_we,
|
|
charbuf_wa => charbuf_wa,
|
|
charbuf_di => charbuf_di,
|
|
rowlen_we => rowlen_we,
|
|
rowlen_wa => rowlen_wa,
|
|
rowlen_di => rowlen_di
|
|
);
|
|
|
|
end syn;
|
|
|