-- altera vhdl_input_version vhdl_2008 library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.math_real.all; LIBRARY altera_mf; use altera_mf.altera_mf_components.all; entity LCDController is port( clk : in std_logic; rst_n : in std_logic; -- Avalon slave interface avalon_slave_address : in std_logic_vector (3 downto 0); avalon_slave_write : in std_logic; avalon_slave_writedata : in std_logic_vector(31 downto 0); avalon_slave_read : in std_logic; avalon_slave_readdata : out std_logic_vector(31 downto 0); avalon_slave_waitrequest : out std_logic; av_irq : out std_logic; -- Avalon master interface avalon_master_waitreq : in std_logic; avalon_master_readdata : in std_logic_vector(31 downto 0); avalon_master_readdatavalid : in std_logic; avalon_master_address : out std_logic_vector(31 downto 0); avalon_master_burstcount : out std_logic_vector(4 downto 0); avalon_master_read : out std_logic; -- LT24 conduit interface lt24_rd_n : out std_logic; lt24_wr_n : out std_logic; lt24_rs : out std_logic; lt24_cs_n : out std_logic; lt24_data : out std_logic_vector(15 downto 0); lt24_reset_n : out std_logic; lt24_lcd_on : out std_logic ); end LCDController; architecture comp of LCDController is -- Type definitions type State is (S_READY, S_REFRESHING); type IRQ_CTRL is record enabled : boolean; clear_on_refresh : boolean; irq0_active : std_logic; end record IRQ_CTRL; -- Generic constants constant F_CLK : natural := 50*10**6; constant ZERO_ADDR : std_logic_vector(31 downto 0) := (others => '0'); constant MAX_H : natural := 240; constant MAX_W : natural := 320; constant N_PIXELS : natural := MAX_H * MAX_W; constant PIXEL_WIDTH : natural := 16; constant AVM_BURST_LEN : natural := 256; constant IRQ_CTRL_DEFAULT : IRQ_CTRL := ( enabled => true, clear_on_refresh => true, irq0_active => '0' ); -- Avalon slave programmable interface constants constant A_WRITEREG : natural := 0; constant A_WRITEDATA : natural := 1; constant A_WRITEBASE : natural := 2; constant A_REFRESH : natural := 3; constant A_SETENABLED : natural := 4; constant A_SETHEIGHT : natural := 5; constant A_SETWIDTH : natural := 6; constant A_WRITEIRQ : natural := 7; constant A_SETIRQ : natural := 8; constant A_CLEARIRQ : natural := 9; constant A_ISBUSY : natural := 10; constant LAST_avalon_slave_ADDR : natural := A_ISBUSY; signal avalon_slave_address_int : integer range 0 to LAST_avalon_slave_ADDR; -- FIFO configuration parameters constant FIFO_N_ALMOST_EMPTY : natural := 32; constant FIFO_WIDTH : natural := 32; constant FIFO_SIZE : natural := AVM_BURST_LEN + FIFO_N_ALMOST_EMPTY; constant PIXELS_PER_WORD : natural := FIFO_WIDTH / PIXEL_WIDTH; constant NWORDS_MAX : natural := N_PIXELS / PIXELS_PER_WORD; -- FIFO signals signal fifo_almost_empty : std_logic; signal fifo_wr_req : std_logic; signal fifo_data_in, fifo_data_out : std_logic_vector(FIFO_WIDTH - 1 downto 0); signal fifo_rd_req : std_logic; signal fifo_empty : std_logic; -- Inferred registers signal baseaddr_reg, baseaddr_next : std_logic_vector(31 downto 0); signal state_reg, state_next : State; signal lcd_on_reg, lcd_on_next : std_logic := '1'; signal lcd_rst_reg, lcd_rst_next : std_logic := '0'; signal width_reg, width_next : integer range 0 to MAX_W; signal height_reg, height_next : integer range 0 to MAX_H; signal irq_ctrl_reg, irq_ctrl_next : IRQ_CTRL; -- LCD Driver interfacing signals signal lcd_cmd_en : std_logic; signal lcd_cmd_dcx : std_logic; signal lcd_cmd_data : std_logic_vector(7 downto 0); signal lcd_busy : std_logic; signal lcd_req : std_logic; signal lcd_data : std_logic_vector(15 downto 0); signal lcd_empty : std_logic; -- LCDController state signals signal refresh : std_logic; -- # of words required by the fifo to gather all pixels in an image based on -- current width and height values signal av_nwords : std_logic_vector(integer(ceil(log2(real(NWORDS_MAX)))) downto 0); function writeIRQCtrl(v : in std_logic_vector(2 downto 0)) return IRQ_CTRL is variable res : IRQ_CTRL; begin res.enabled := v(0) = '1'; res.clear_on_refresh := v(1) = '1'; res.irq0_active := v(2); return res; end writeIRQCtrl; function setIRQCtrl(current: in IRQ_CTRL; v : in std_logic_vector(2 downto 0)) return IRQ_CTRL is variable res : IRQ_CTRL; begin res := current; res.enabled := current.enabled or v(0) = '1'; res.clear_on_refresh := current.clear_on_refresh or v(1) = '1'; res.irq0_active := current.irq0_active or v(2); return res; end setIRQCtrl; function clearIRQCtrl(current: in IRQ_CTRL; v : in std_logic_vector(2 downto 0)) return IRQ_CTRL is variable res : IRQ_CTRL; begin res := current; res.enabled := current.enabled and not v(0) = '1'; res.clear_on_refresh := current.clear_on_refresh and not v(1) = '1'; res.irq0_active := current.irq0_active and not v(2); return res; end clearIRQCtrl; --Component declaration, required for altera library IP component scfifo generic ( almost_empty_value : natural; lpm_numwords : natural; lpm_width : natural; lpm_widthu : natural ); port( aclr : in std_logic; almost_empty : out std_logic; clock : in std_logic; data : in std_logic_vector(lpm_width-1 downto 0); empty : out std_logic; q : out std_logic_vector(lpm_width-1 downto 0); rdreq : in std_logic; sclr : in std_logic; wrreq : in std_logic ); end component; begin -- ENTITY LCDDriver: lcddriver_ent : entity work.LCDDriver generic map ( F_CLK => F_CLK ) port map ( clk => clk, rst_n => rst_n, data_in => lcd_data, empty_in => lcd_empty, refresh_in => refresh, cmd_en_in => lcd_cmd_en, cmd_dcx_in => lcd_cmd_dcx, cmd_data_in => lcd_cmd_data, data_out => lt24_data, rd_n => lt24_rd_n, wr_n => lt24_wr_n, rs => lt24_rs, cs_n => lt24_cs_n, lcd_rdreq => lcd_req, busy => lcd_busy ); -- ENTITY PixTrans: pixtrans_ent : entity work.PixTrans generic map ( MAX_H => MAX_H, MAX_W => MAX_W ) port map ( clk => clk, rst_n => rst_n, lcd_req => lcd_req, data => lcd_data, empty => lcd_empty, fifo_req => fifo_rd_req, fifo_q => fifo_data_out, fifo_empty => fifo_empty, w => width_reg, h => height_reg ); -- ENTITY Avalon master: avalon_master_ent : entity work.LCDAvalonMaster generic map ( NWORDS_MAX => NWORDS_MAX ) port map ( clk => clk, rst_n => rst_n, waitreq => avalon_master_waitreq, readdata => avalon_master_readdata, readdatavalid => avalon_master_readdatavalid, address => avalon_master_address, burstcount => avalon_master_burstcount, am_read => avalon_master_read, refresh => refresh, fifo_almost_empty => fifo_almost_empty, fifo_data => fifo_data_in, fifo_wr_req => fifo_wr_req, baseaddress => baseaddr_reg, nwords => av_nwords ); -- ENTITY FIFO fifo_ent : scfifo generic map ( lpm_widthu => 9, lpm_width => FIFO_WIDTH, lpm_numwords => FIFO_SIZE, almost_empty_value => FIFO_N_ALMOST_EMPTY ) port map ( clock => clk, data => fifo_data_in, q => fifo_data_out, wrreq => fifo_wr_req, rdreq => fifo_rd_req, empty => fifo_empty, almost_empty => fifo_almost_empty, sclr => not rst_n, aclr => '0' ); -- PROCESS Avalon slave interface avalon_slave_address_int <= to_integer(unsigned(avalon_slave_address)); process(all) begin state_next <= state_reg; height_next <= height_reg; width_next <= width_reg; irq_ctrl_next <= irq_ctrl_reg; refresh <= '0'; lcd_cmd_en <= '0'; lcd_cmd_dcx <= '0'; baseaddr_next <= baseaddr_reg; lcd_on_next <= lcd_on_reg; lcd_rst_next <= lcd_rst_reg; avalon_slave_readdata <= (others => 'Z'); -- Avalon slave interface if avalon_slave_write = '1' then case avalon_slave_address_int is when A_WRITEREG => lcd_cmd_en <= '1'; lcd_cmd_dcx <= '0'; when A_WRITEDATA => lcd_cmd_en <= '1'; lcd_cmd_dcx <= '1'; when A_WRITEBASE => baseaddr_next <= avalon_slave_writedata; when A_REFRESH => if state_reg = S_READY then refresh <= '1'; state_next <= S_REFRESHING; if irq_ctrl_reg.clear_on_refresh then irq_ctrl_next.irq0_active <= '0'; end if; end if; when A_SETENABLED => lcd_on_next <= avalon_slave_writedata(0); lcd_rst_next <= avalon_slave_writedata(1); when A_SETHEIGHT => height_next <= to_integer(unsigned(avalon_slave_writedata)); when A_SETWIDTH => width_next <= to_integer(unsigned(avalon_slave_writedata)); when A_WRITEIRQ => irq_ctrl_next <= writeIRQCtrl(avalon_slave_writedata(2 downto 0)); when A_SETIRQ => irq_ctrl_next <= setIRQCtrl(irq_ctrl_reg, avalon_slave_writedata(2 downto 0)); when A_CLEARIRQ => irq_ctrl_next <= clearIRQCtrl(irq_ctrl_reg, avalon_slave_writedata(2 downto 0)); when others => null; end case; end if; if avalon_slave_read = '1' then case avalon_slave_address_int is when A_ISBUSY => avalon_slave_readdata <= (avalon_slave_readdata'left downto 1 => '0') & lcd_busy; when others => null; end case; end if; -- LCD Controller state handling if (state_reg = S_REFRESHING) and lcd_busy = '0' then state_next <= S_READY; if irq_ctrl_reg.enabled then irq_ctrl_next.irq0_active <= '1'; -- register that we are now finished end if; end if; end process; av_irq <= irq_ctrl_reg.irq0_active; -- LCDController top level signals and functional units lcd_cmd_data <= avalon_slave_writedata(7 downto 0); av_nwords <= std_logic_vector(to_unsigned((height_reg * width_reg) / 2, av_nwords'length)); -- Output logic lt24_reset_n <= not lcd_rst_reg; lt24_lcd_on <= lcd_on_reg; avalon_slave_waitrequest <= '1' when (lcd_busy='1' or state_reg /= S_READY) else '0'; -- Clocking process/register inferrence process(clk) begin if rising_edge(clk) then if rst_n = '0' then baseaddr_reg <= (others => '0'); state_reg <= S_READY; height_reg <= MAX_H; width_reg <= MAX_W; irq_ctrl_reg <= IRQ_CTRL_DEFAULT; lcd_on_reg <= '1'; else state_reg <= state_next; baseaddr_reg <= baseaddr_next; height_reg <= height_next; width_reg <= width_next; irq_ctrl_reg <= irq_ctrl_next; lcd_on_reg <= lcd_on_next; lcd_rst_reg <= lcd_rst_next; end if; end if; end process; end comp;