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;