190 lines
4.5 KiB
VHDL
190 lines
4.5 KiB
VHDL
|
library ieee;
|
||
|
use ieee.std_logic_1164.all;
|
||
|
use ieee.numeric_std.all;
|
||
|
|
||
|
library ip;
|
||
|
use ip.all;
|
||
|
|
||
|
entity lmg6202 is
|
||
|
generic(
|
||
|
F_CLK : natural;
|
||
|
LCD_F_CLP : natural := 2_000_000 -- Max 2.5 MHz atm (because fo t_lc)
|
||
|
);
|
||
|
port(
|
||
|
-- System signals
|
||
|
clk : in std_logic;
|
||
|
rst : in std_logic; --
|
||
|
|
||
|
-- Interface signals
|
||
|
addr_in : in std_logic_vector(12 downto 0);
|
||
|
data_in : in std_logic_vector(8 downto 0);
|
||
|
data_we : in std_logic;
|
||
|
data_out : out std_logic_vector(8 downto 0);
|
||
|
vsync_out : out std_logic; -- Strobed when resetting to the top left
|
||
|
vsync_in : in std_logic; -- Reset renderer to the top left corner
|
||
|
|
||
|
-- LCD hardware signals
|
||
|
lcd_data : out std_logic_vector(3 downto 0);
|
||
|
lcd_clp : out std_logic;
|
||
|
lcd_load : out std_logic;
|
||
|
lcd_frp : out std_logic;
|
||
|
lcd_frmb : out std_logic
|
||
|
);
|
||
|
end entity lmg6202;
|
||
|
|
||
|
architecture RTL of lmg6202 is
|
||
|
constant DISPLAY_WIDTH_PX : natural := 480;
|
||
|
constant DISPLAY_HEIGHT_PX : natural := 128;
|
||
|
|
||
|
constant DISPLAY_WIDTH : natural := DISPLAY_WIDTH_PX / 4;
|
||
|
constant DISPLAY_HEIGHT : natural := DISPLAY_HEIGHT_PX;
|
||
|
|
||
|
-- CLP Gen
|
||
|
constant CLP_CNT_MAX : integer := F_CLK / LCD_F_CLP / 2 - 1;
|
||
|
signal clp_cnt : integer range 0 to CLP_CNT_MAX;
|
||
|
signal clp_falling : std_logic;
|
||
|
|
||
|
signal row : integer range 0 to DISPLAY_HEIGHT - 1;
|
||
|
signal col : integer range 0 to DISPLAY_WIDTH - 1;
|
||
|
|
||
|
signal renderer_addr : unsigned(12 downto 0);
|
||
|
signal renderer_data : std_logic_vector(8 downto 0);
|
||
|
signal additional_nibble : std_logic_vector(3 downto 0);
|
||
|
signal cached_nibble : std_logic_vector(3 downto 0);
|
||
|
signal clp_rising : std_logic;
|
||
|
signal step_cnt : unsigned(3 downto 0);
|
||
|
|
||
|
begin
|
||
|
gram0_inst : entity ip.gram0
|
||
|
port map(
|
||
|
DataInA => data_in,
|
||
|
DataInB => (others => '0'),
|
||
|
AddressA => addr_in,
|
||
|
AddressB => std_logic_vector(renderer_addr),
|
||
|
ClockA => clk,
|
||
|
ClockB => clk,
|
||
|
ClockEnA => '1',
|
||
|
ClockEnB => '1',
|
||
|
WrA => data_we,
|
||
|
WrB => '0',
|
||
|
ResetA => rst,
|
||
|
ResetB => rst,
|
||
|
QA => data_out,
|
||
|
QB => renderer_data
|
||
|
);
|
||
|
|
||
|
renderer : process(clk, rst) is
|
||
|
procedure reset_renderer is
|
||
|
|
||
|
begin
|
||
|
row <= 0;
|
||
|
col <= 0;
|
||
|
renderer_addr <= (others => '0');
|
||
|
step_cnt <= (others => '0');
|
||
|
vsync_out <= '1';
|
||
|
end procedure reset_renderer;
|
||
|
|
||
|
begin
|
||
|
if (rst = '1') then
|
||
|
additional_nibble <= (others => '0');
|
||
|
cached_nibble <= (others => '0');
|
||
|
lcd_load <= '0';
|
||
|
lcd_frp <= '0';
|
||
|
lcd_frmb <= '0';
|
||
|
lcd_data <= (others => '0');
|
||
|
reset_renderer;
|
||
|
|
||
|
elsif (rising_edge(clk)) then
|
||
|
vsync_out <= '0';
|
||
|
|
||
|
if (clp_falling = '1') then
|
||
|
if (col = DISPLAY_WIDTH - 1) then
|
||
|
col <= 0;
|
||
|
lcd_load <= '1';
|
||
|
|
||
|
if (row = 0) then
|
||
|
lcd_frp <= '1';
|
||
|
lcd_frmb <= not lcd_frmb;
|
||
|
else
|
||
|
lcd_frp <= '0';
|
||
|
end if;
|
||
|
|
||
|
if (row = DISPLAY_HEIGHT - 1) then
|
||
|
reset_renderer;
|
||
|
else
|
||
|
row <= row + 1;
|
||
|
end if;
|
||
|
else
|
||
|
col <= col + 1;
|
||
|
end if;
|
||
|
end if;
|
||
|
|
||
|
if (clp_rising = '1') then
|
||
|
lcd_load <= '0';
|
||
|
|
||
|
step_cnt <= step_cnt + 1;
|
||
|
if (step_cnt = 8) then
|
||
|
step_cnt <= (others => '0');
|
||
|
lcd_data <= additional_nibble;
|
||
|
|
||
|
elsif (step_cnt(0) = '0') then
|
||
|
renderer_addr <= renderer_addr + 1;
|
||
|
|
||
|
lcd_data <= renderer_data(8 downto 5);
|
||
|
cached_nibble <= renderer_data(4 downto 1);
|
||
|
additional_nibble <= additional_nibble(2 downto 0) & renderer_data(0);
|
||
|
|
||
|
else
|
||
|
lcd_data <= cached_nibble;
|
||
|
end if;
|
||
|
|
||
|
-- DEBUG BEGIN
|
||
|
-- lcd_data <= (others => '0');
|
||
|
-- if (col = 0) then
|
||
|
-- lcd_data <= x"8";
|
||
|
-- end if;
|
||
|
-- if (col = DISPLAY_WIDTH - 1) then
|
||
|
-- lcd_data <= x"1";
|
||
|
-- end if;
|
||
|
-- if (row = 0 or row = DISPLAY_HEIGHT - 1) then
|
||
|
-- lcd_data <= (others => '1');
|
||
|
-- end if;
|
||
|
-- DEBUG END
|
||
|
end if;
|
||
|
|
||
|
if (vsync_in = '1') then
|
||
|
reset_renderer;
|
||
|
end if;
|
||
|
end if;
|
||
|
end process renderer;
|
||
|
|
||
|
cpgen : process(clk, rst) is
|
||
|
begin
|
||
|
if (rst = '1') then
|
||
|
clp_cnt <= CLP_CNT_MAX;
|
||
|
lcd_clp <= '0';
|
||
|
clp_falling <= '0';
|
||
|
clp_rising <= '0';
|
||
|
|
||
|
elsif (rising_edge(clk)) then
|
||
|
clp_falling <= '0';
|
||
|
clp_rising <= '0';
|
||
|
|
||
|
if (clp_cnt = 0) then
|
||
|
lcd_clp <= not lcd_clp;
|
||
|
clp_cnt <= CLP_CNT_MAX;
|
||
|
else
|
||
|
if (clp_cnt = 1) then
|
||
|
if (lcd_clp = '1') then
|
||
|
clp_falling <= '1';
|
||
|
else
|
||
|
clp_rising <= '1';
|
||
|
end if;
|
||
|
end if;
|
||
|
clp_cnt <= clp_cnt - 1;
|
||
|
end if;
|
||
|
end if;
|
||
|
end process cpgen;
|
||
|
|
||
|
end architecture RTL;
|