diff --git a/framebuffer.vhd b/framebuffer.vhd index 8a9eb21..4cbbbfb 100644 --- a/framebuffer.vhd +++ b/framebuffer.vhd @@ -18,9 +18,16 @@ entity framebuffer is rgb: out std_logic_vector(23 downto 0); - write_enable: std_logic; - write_address: std_logic_vector(12 downto 0); - write_data: std_logic_vector(7 downto 0) + cursor_row: in unsigned(5 downto 0); + cursor_col: in unsigned(6 downto 0); + + -- write access to the character and row length rams + charbuf_we: in std_logic; + charbuf_wa: in std_logic_vector(12 downto 0); + charbuf_di: in std_logic_vector(7 downto 0); + rowlen_we: in std_logic; + rowlen_wa: in std_logic_vector(5 downto 0); + rowlen_di: in std_logic_vector(6 downto 0) ); end framebuffer; @@ -45,10 +52,18 @@ architecture logic of framebuffer is constant font: rom_type := read_font("font.hex"); + signal row: unsigned(5 downto 0); + signal col: unsigned(6 downto 0); + + signal eff_row_wide: unsigned(6 downto 0); + signal eff_row: unsigned(5 downto 0); + signal read_address: std_logic_vector(12 downto 0); signal current_char: std_logic_vector(7 downto 0); + signal current_row_length: std_logic_vector(6 downto 0); signal current_glyph: std_logic_vector(63 downto 0); + signal current_glyph_valid: boolean; -- delay by 2 cycles to match the delay of x/y -> rgb constant glyph_pos_length: integer := 2; @@ -56,7 +71,16 @@ architecture logic of framebuffer is signal glyph_pos: glyph_pos_type; begin - read_address <= x(9 downto 3) & y(8 downto 3); + row <= unsigned(y(8 downto 3)); + col <= unsigned(x(9 downto 3)); + + -- calculate effective row with respect to the cursor; this keeps the + -- cursor always at the bottom of the screen and old contents scoll up + eff_row_wide <= resize(cursor_row, 7) + row + 1; + eff_row <= resize(eff_row_wide, 6) when eff_row_wide < "0111100" else -- 60 + resize(eff_row_wide - "0111100", 6); -- 60 + + read_address <= std_logic_vector(col) & std_logic_vector(eff_row); terminal_buffer: entity work.ram_2port generic map ( WIDTH_BITS => 8, @@ -65,11 +89,32 @@ begin clk => clk, ra => read_address, do => current_char, - we => write_enable, - wa => write_address, - di => write_data + we => charbuf_we, + wa => charbuf_wa, + di => charbuf_di ); + -- store the length of every row so that we don't have to overwrite + -- existing rows when wrapping around and can simply disable display + -- of non-overwritten characters + row_lengths: entity work.ram_2port generic map ( + WIDTH_BITS => 7, + DEPTH_BITS => 6 + ) port map ( + clk => clk, + ra => std_logic_vector(eff_row), + do => current_row_length, + we => rowlen_we, + wa => rowlen_wa, + di => rowlen_di + ); + + -- as the row length is only saved after switching to the next row, we use + -- the current cursor col position in the case of the current row, which + -- is always at the bottom, so it is always row 59 + current_glyph_valid <= col < cursor_col when row = "111011" else -- 59 + col < unsigned(current_row_length); + process(clk) variable current_glyph_pos: integer range 0 to 127; begin @@ -95,8 +140,9 @@ begin end process delay_glyph_pos; -- actually currently BRG - rgb <= - "111111111111111111111111" when current_glyph(glyph_pos(1)) = '1' else - "000000000000000000000000"; + with current_glyph(glyph_pos(1)) = '1' and current_glyph_valid + select rgb <= + "111111111111111111111111" when true, + "000000000000000000000000" when false; end logic; diff --git a/terminal.vhd b/terminal.vhd index ffc8bba..462052d 100644 --- a/terminal.vhd +++ b/terminal.vhd @@ -35,50 +35,67 @@ architecture syn of terminal is signal image_y: std_logic_vector(8 downto 0); signal pixel_rgb: std_logic_vector(23 downto 0); - signal fb_write_enable: std_logic; - signal fb_write_address: std_logic_vector(12 downto 0); - signal fb_write_data: std_logic_vector(7 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 write_x: unsigned(6 downto 0); - signal write_y: unsigned(5 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 - fb_write_address <= std_logic_vector(write_x) & std_logic_vector(write_y); - + -- 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 - fb_write_enable <= '0'; - fb_write_data <= write_data; + -- 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 write_y = 59 then + if cursor_row = 59 then next_line := (others => '0'); else - next_line := write_y + 1; + next_line := cursor_row + 1; end if; if write_enable = '1' then - fb_write_enable <= '1'; - if write_x = 79 then - write_x <= (others => '0'); - write_y <= next_line; - else - write_x <= write_x + 1; - end if; - -- carriage return if write_data = x"0d" then - fb_write_enable <= '0'; - write_x <= (others => '0'); - end if; + cursor_col <= (others => '0'); -- line feed (implicit CR) - if write_data = x"0a" then - fb_write_enable <= '0'; - write_x <= (others => '0'); - write_y <= next_line; + 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; @@ -120,9 +137,14 @@ begin x => image_x, y => image_y, rgb => pixel_rgb, - write_enable => fb_write_enable, - write_address => fb_write_address, - write_data => fb_write_data + 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;