Disabled external gits
This commit is contained in:
43
cs473-es/lab3/hw/hdl/LCDController/ClkGen.vhd
Normal file
43
cs473-es/lab3/hw/hdl/LCDController/ClkGen.vhd
Normal file
@ -0,0 +1,43 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use ieee.math_real.all;
|
||||
|
||||
entity ClkGen is
|
||||
generic (
|
||||
F_CLK : natural; -- Hz
|
||||
F_OUT : natural; -- Hz
|
||||
F_MIN : natural; -- Hz
|
||||
F_MAX : natural -- Hz
|
||||
);
|
||||
port (
|
||||
clk : in std_logic;
|
||||
rst_n : in std_logic;
|
||||
clk_o : out std_logic;
|
||||
en : in std_logic
|
||||
);
|
||||
end ClkGen;
|
||||
|
||||
architecture Behavioral of ClkGen is
|
||||
constant CNT_MAX : integer := integer(floor(real(F_CLK) / real(F_OUT))) - 1;
|
||||
constant F_ACTUAL : integer := (F_CLK/natural(CNT_MAX+1));
|
||||
signal counter_reg, counter_next: integer range CNT_MAX downto 0;
|
||||
begin
|
||||
assert F_MIN <= F_ACTUAL report "Invalid Timings for ClkGen ("&integer'image(F_ACTUAL)&"hz < "&integer'image(F_MIN)&"hz)" severity error;
|
||||
assert F_MAX >= F_ACTUAL report "Invalid Timings for ClkGen ("&integer'image(F_ACTUAL)&"hz > "&integer'image(F_MAX)&"hz)" severity error;
|
||||
assert F_MIN <= F_OUT and F_OUT <= F_MAX report "Invalid Timings for ClkGen (F_MIN<=F_OUT<=F_MAX)." severity error;
|
||||
|
||||
counter_next <= CNT_MAX when counter_reg = 0 else counter_reg - 1;
|
||||
process(clk, rst_n) begin
|
||||
if rising_edge(clk) then
|
||||
if rst_n = '0' then
|
||||
counter_reg <= CNT_MAX;
|
||||
else
|
||||
if en = '1' then
|
||||
counter_reg <= counter_next;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
clk_o <= '1' when counter_reg = 0 and en = '1' else '0';
|
||||
end Behavioral; -- Behavioral
|
136
cs473-es/lab3/hw/hdl/LCDController/LCDAvalonMaster.vhd
Normal file
136
cs473-es/lab3/hw/hdl/LCDController/LCDAvalonMaster.vhd
Normal file
@ -0,0 +1,136 @@
|
||||
-- altera vhdl_input_version vhdl_2008
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use ieee.math_real.all;
|
||||
|
||||
|
||||
entity LCDAvalonMaster is
|
||||
generic (
|
||||
NWORDS_MAX : natural
|
||||
);
|
||||
port (
|
||||
clk : in std_logic;
|
||||
rst_n : in std_logic;
|
||||
waitreq : in std_logic;
|
||||
readdata : in std_logic_vector(31 downto 0);
|
||||
readdatavalid : in std_logic;
|
||||
address : out std_logic_vector(31 downto 0);
|
||||
burstcount : out std_logic_vector(4 downto 0);
|
||||
am_read : out std_logic;
|
||||
refresh : in std_logic;
|
||||
fifo_almost_empty : in std_logic;
|
||||
fifo_data : out std_logic_vector(31 downto 0);
|
||||
fifo_wr_req : out std_logic;
|
||||
baseaddress : in std_logic_vector(31 downto 0);
|
||||
nwords : in std_logic_vector(integer(ceil(log2(real(NWORDS_MAX)))) downto 0)
|
||||
);
|
||||
end LCDAvalonMaster;
|
||||
|
||||
architecture behavioral of LCDAvalonMaster is
|
||||
-- Generic constants
|
||||
constant BURST_COUNT : integer := 16;
|
||||
constant BURST_COUNT_SLV : std_logic_vector(burstcount'left downto 0) := std_logic_vector(to_unsigned(BURST_COUNT, burstcount'length));
|
||||
|
||||
|
||||
-- Type definitions
|
||||
type State is (S_READY, S_BURSTREQ, S_BURSTRD, S_FIFOWAIT);
|
||||
subtype BurstCounter is integer range 0 to BURST_COUNT;
|
||||
subtype WordCounter is integer range 0 to NWORDS_MAX;
|
||||
|
||||
|
||||
-- Inferred registers
|
||||
signal rdaddr_reg, rdaddr_next : std_logic_vector(31 downto 0);
|
||||
signal state_reg, state_next : State;
|
||||
signal burstcnt_reg, burstcnt_next : BurstCounter; -- Counts # of words read during a single burst
|
||||
signal wordcnt_reg, wordcnt_next : WordCounter; -- Counts # of words read during a refresh cycle
|
||||
|
||||
|
||||
begin
|
||||
-- PROCESS state machine
|
||||
process(all) begin
|
||||
state_next <= state_reg;
|
||||
rdaddr_next <= rdaddr_reg;
|
||||
burstcnt_next <= burstcnt_reg;
|
||||
wordcnt_next <= wordcnt_reg;
|
||||
|
||||
-- Avalon master default output signals
|
||||
burstcount <= BURST_COUNT_SLV;
|
||||
am_read <= '0';
|
||||
|
||||
case state_reg is
|
||||
when S_READY =>
|
||||
-- ====================== AM STATE: READY ======================
|
||||
if refresh = '1' then
|
||||
wordcnt_next <= integer(to_integer(unsigned(nwords)));
|
||||
state_next <= S_BURSTREQ;
|
||||
end if;
|
||||
when S_BURSTREQ =>
|
||||
-- ================== AM STATE: BURST REQUEST ==================
|
||||
am_read <= '1';
|
||||
if waitreq = '0' then
|
||||
-- Burst was accepted,
|
||||
state_next <= S_BURSTRD;
|
||||
|
||||
-- Calculate the # of words we plan to read during this burst
|
||||
-- and update counters accordingly.
|
||||
if wordcnt_reg < BURST_COUNT then
|
||||
burstcnt_next <= wordcnt_reg;
|
||||
wordcnt_next <= 0;
|
||||
else
|
||||
burstcnt_next <= BURST_COUNT;
|
||||
wordcnt_next <= wordcnt_reg - BURST_COUNT;
|
||||
end if;
|
||||
end if;
|
||||
when S_BURSTRD =>
|
||||
-- ==================== AM STATE: BURST READ ===================
|
||||
if readdatavalid = '1' then
|
||||
if burstcnt_reg = 1 then
|
||||
-- Got last word, burst read finished
|
||||
if wordcnt_reg = 0 then
|
||||
-- All nwords read
|
||||
state_next <= S_READY;
|
||||
else
|
||||
-- < nwords read
|
||||
state_next <= S_FIFOWAIT;
|
||||
end if;
|
||||
else
|
||||
burstcnt_next <= burstcnt_reg - 1;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when S_FIFOWAIT =>
|
||||
-- ==================== AM STATE: FIFO WAIT ====================
|
||||
-- Await the assertion of fifo_almost_empty until reinitiating a
|
||||
-- burst read
|
||||
if fifo_almost_empty = '1' then
|
||||
state_next <= S_BURSTREQ;
|
||||
end if;
|
||||
end case;
|
||||
end process;
|
||||
|
||||
|
||||
-- FIFO data transfer routing
|
||||
fifo_wr_req <= '1' when state_reg = S_BURSTRD and readdatavalid = '1' else '0';
|
||||
fifo_data <= readdata when state_reg = S_BURSTRD else (others => 'Z');
|
||||
address <= std_logic_vector(unsigned(baseaddress) + resize((unsigned(nwords) - wordcnt_reg) * 4, address'length)) when state_reg = S_BURSTREQ else (others => 'Z');
|
||||
|
||||
-- Clocking process/register inferrence
|
||||
process(clk) begin
|
||||
if rising_edge(clk) then
|
||||
if rst_n = '0' then
|
||||
rdaddr_reg <= (others => '0');
|
||||
state_reg <= S_READY;
|
||||
burstcnt_reg <= BURST_COUNT;
|
||||
wordcnt_reg <= 0;
|
||||
else
|
||||
rdaddr_reg <= rdaddr_next;
|
||||
state_reg <= state_next;
|
||||
burstcnt_reg <= burstcnt_next;
|
||||
wordcnt_reg <= wordcnt_next;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
end behavioral;
|
108
cs473-es/lab3/hw/hdl/LCDController/LCDAvalonMaster_tb.vhd
Normal file
108
cs473-es/lab3/hw/hdl/LCDController/LCDAvalonMaster_tb.vhd
Normal file
@ -0,0 +1,108 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use ieee.math_real.all;
|
||||
|
||||
|
||||
entity LCDAvalonMaster_tb is
|
||||
end LCDAvalonMaster_tb;
|
||||
|
||||
architecture test of LCDAvalonMaster_tb is
|
||||
constant CLK_PERIOD : time := 20 ns;
|
||||
constant N_LED_MAX : integer := 255;
|
||||
|
||||
-- 20 = 1 full burst + 1 non full burst
|
||||
constant NWORDS : natural := 20;
|
||||
|
||||
constant NWORDS_MAX :natural := (320*240)/2;
|
||||
|
||||
signal clk : std_logic := '0';
|
||||
signal rst_n : std_logic;
|
||||
signal waitreq, readdatavalid, refresh, fifo_almost_empty : std_logic;
|
||||
signal readdata : std_logic_vector(31 downto 0);
|
||||
signal baseaddress : std_logic_vector(31 downto 0);
|
||||
signal nwords_sig : std_logic_vector(integer(floor(log2(real(NWORDS_MAX)))) downto 0);
|
||||
|
||||
begin
|
||||
|
||||
nwords_sig <= std_logic_vector(to_unsigned(NWORDS, nwords_sig'length));
|
||||
|
||||
-- Instantiate DUT
|
||||
dut : entity work.LCDAvalonMaster
|
||||
generic map (
|
||||
NWORDS_MAX => NWORDS_MAX
|
||||
)
|
||||
port map(
|
||||
clk => clk,
|
||||
rst_n => rst_n,
|
||||
waitreq => waitreq,
|
||||
readdatavalid => readdatavalid,
|
||||
refresh => refresh,
|
||||
fifo_almost_empty => fifo_almost_empty,
|
||||
readdata => readdata,
|
||||
baseaddress => baseaddress,
|
||||
nwords => nwords_sig
|
||||
);
|
||||
|
||||
-- Clocking process
|
||||
clk_generation : process
|
||||
begin
|
||||
clk <= not clk;
|
||||
wait for CLK_PERIOD / 2;
|
||||
end process;
|
||||
|
||||
-- Testbench
|
||||
tb : process
|
||||
begin
|
||||
while true loop
|
||||
-- Dummy signals from bus
|
||||
readdata <= X"12341234";
|
||||
readdatavalid <= '0';
|
||||
waitreq <= '1';
|
||||
baseaddress <= X"10000000";
|
||||
fifo_almost_empty <= '0';
|
||||
|
||||
-- Reset
|
||||
rst_n <= '0';
|
||||
wait for CLK_PERIOD * 2.5;
|
||||
rst_n <= '1';
|
||||
wait for CLK_PERIOD * 2;
|
||||
|
||||
-- Initiate a refresh cycle
|
||||
wait until rising_edge(clk);
|
||||
refresh <= '1';
|
||||
wait for CLK_PERIOD;
|
||||
refresh <= '0';
|
||||
|
||||
-- Wait until bus grant
|
||||
wait for CLK_PERIOD * 3;
|
||||
waitreq <= '0';
|
||||
wait for CLK_PERIOD;
|
||||
|
||||
-- Emulate that new read data is valid each cycle of the burst
|
||||
readdatavalid <= '1';
|
||||
for i in 1 to 16 loop
|
||||
wait for CLK_PERIOD;
|
||||
end loop;
|
||||
readdatavalid <= '0';
|
||||
|
||||
wait for CLK_PERIOD * 5;
|
||||
|
||||
-- Assert fifo_almost empty; should repromt another transfer
|
||||
fifo_almost_empty <= '1';
|
||||
wait for CLK_period;
|
||||
fifo_almost_empty <= '0';
|
||||
wait for CLK_PERIOD * 2;
|
||||
|
||||
readdatavalid <= '1';
|
||||
for i in 1 to 16 loop
|
||||
wait for CLK_PERIOD;
|
||||
end loop;
|
||||
|
||||
-- Test finished
|
||||
wait for CLK_PERIOD * 5;
|
||||
end loop;
|
||||
|
||||
end process;
|
||||
|
||||
end;
|
370
cs473-es/lab3/hw/hdl/LCDController/LCDController.vhd
Normal file
370
cs473-es/lab3/hw/hdl/LCDController/LCDController.vhd
Normal file
@ -0,0 +1,370 @@
|
||||
-- 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;
|
199
cs473-es/lab3/hw/hdl/LCDController/LCDController_hw.tcl
Normal file
199
cs473-es/lab3/hw/hdl/LCDController/LCDController_hw.tcl
Normal file
@ -0,0 +1,199 @@
|
||||
# TCL File Generated by Component Editor 18.1
|
||||
# Wed Jan 06 17:21:08 CET 2021
|
||||
# DO NOT MODIFY
|
||||
|
||||
|
||||
#
|
||||
# LCDController "LCDController" v1.0
|
||||
# 2021.01.06.17:21:08
|
||||
#
|
||||
#
|
||||
|
||||
#
|
||||
# request TCL package from ACDS 16.1
|
||||
#
|
||||
package require -exact qsys 16.1
|
||||
|
||||
|
||||
#
|
||||
# module LCDController
|
||||
#
|
||||
set_module_property DESCRIPTION ""
|
||||
set_module_property NAME LCDController
|
||||
set_module_property VERSION 1.0
|
||||
set_module_property INTERNAL false
|
||||
set_module_property OPAQUE_ADDRESS_MAP true
|
||||
set_module_property AUTHOR ""
|
||||
set_module_property DISPLAY_NAME LCDController
|
||||
set_module_property INSTANTIATE_IN_SYSTEM_MODULE true
|
||||
set_module_property EDITABLE true
|
||||
set_module_property REPORT_TO_TALKBACK false
|
||||
set_module_property ALLOW_GREYBOX_GENERATION false
|
||||
set_module_property REPORT_HIERARCHY false
|
||||
|
||||
|
||||
#
|
||||
# file sets
|
||||
#
|
||||
add_fileset QUARTUS_SYNTH QUARTUS_SYNTH "" ""
|
||||
set_fileset_property QUARTUS_SYNTH TOP_LEVEL LCDController
|
||||
set_fileset_property QUARTUS_SYNTH ENABLE_RELATIVE_INCLUDE_PATHS false
|
||||
set_fileset_property QUARTUS_SYNTH ENABLE_FILE_OVERWRITE_MODE false
|
||||
add_fileset_file LCDController.vhd VHDL PATH LCDController.vhd TOP_LEVEL_FILE
|
||||
add_fileset_file ClkGen.vhd VHDL PATH ClkGen.vhd
|
||||
add_fileset_file LCDAvalonMaster.vhd VHDL PATH LCDAvalonMaster.vhd
|
||||
add_fileset_file LCDDriver.vhd VHDL PATH LCDDriver.vhd
|
||||
add_fileset_file PixTrans.vhd VHDL PATH PixTrans.vhd
|
||||
|
||||
|
||||
#
|
||||
# parameters
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# display items
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# connection point avalon_slave
|
||||
#
|
||||
add_interface avalon_slave avalon end
|
||||
set_interface_property avalon_slave addressUnits WORDS
|
||||
set_interface_property avalon_slave associatedClock clock_sink
|
||||
set_interface_property avalon_slave associatedReset reset_sink
|
||||
set_interface_property avalon_slave bitsPerSymbol 8
|
||||
set_interface_property avalon_slave burstOnBurstBoundariesOnly false
|
||||
set_interface_property avalon_slave burstcountUnits WORDS
|
||||
set_interface_property avalon_slave explicitAddressSpan 0
|
||||
set_interface_property avalon_slave holdTime 0
|
||||
set_interface_property avalon_slave linewrapBursts false
|
||||
set_interface_property avalon_slave maximumPendingReadTransactions 0
|
||||
set_interface_property avalon_slave maximumPendingWriteTransactions 0
|
||||
set_interface_property avalon_slave readLatency 0
|
||||
set_interface_property avalon_slave readWaitStates 0
|
||||
set_interface_property avalon_slave readWaitTime 0
|
||||
set_interface_property avalon_slave setupTime 0
|
||||
set_interface_property avalon_slave timingUnits Cycles
|
||||
set_interface_property avalon_slave writeWaitTime 0
|
||||
set_interface_property avalon_slave ENABLED true
|
||||
set_interface_property avalon_slave EXPORT_OF ""
|
||||
set_interface_property avalon_slave PORT_NAME_MAP ""
|
||||
set_interface_property avalon_slave CMSIS_SVD_VARIABLES ""
|
||||
set_interface_property avalon_slave SVD_ADDRESS_GROUP ""
|
||||
|
||||
add_interface_port avalon_slave avalon_slave_address address Input 4
|
||||
add_interface_port avalon_slave avalon_slave_write write Input 1
|
||||
add_interface_port avalon_slave avalon_slave_writedata writedata Input 32
|
||||
add_interface_port avalon_slave avalon_slave_read read Input 1
|
||||
add_interface_port avalon_slave avalon_slave_readdata readdata Output 32
|
||||
add_interface_port avalon_slave avalon_slave_waitrequest waitrequest Output 1
|
||||
set_interface_assignment avalon_slave embeddedsw.configuration.isFlash 0
|
||||
set_interface_assignment avalon_slave embeddedsw.configuration.isMemoryDevice 0
|
||||
set_interface_assignment avalon_slave embeddedsw.configuration.isNonVolatileStorage 0
|
||||
set_interface_assignment avalon_slave embeddedsw.configuration.isPrintableDevice 0
|
||||
|
||||
|
||||
#
|
||||
# connection point clock_sink
|
||||
#
|
||||
add_interface clock_sink clock end
|
||||
set_interface_property clock_sink clockRate 0
|
||||
set_interface_property clock_sink ENABLED true
|
||||
set_interface_property clock_sink EXPORT_OF ""
|
||||
set_interface_property clock_sink PORT_NAME_MAP ""
|
||||
set_interface_property clock_sink CMSIS_SVD_VARIABLES ""
|
||||
set_interface_property clock_sink SVD_ADDRESS_GROUP ""
|
||||
|
||||
add_interface_port clock_sink clk clk Input 1
|
||||
|
||||
|
||||
#
|
||||
# connection point reset_sink
|
||||
#
|
||||
add_interface reset_sink reset end
|
||||
set_interface_property reset_sink associatedClock clock_sink
|
||||
set_interface_property reset_sink synchronousEdges DEASSERT
|
||||
set_interface_property reset_sink ENABLED true
|
||||
set_interface_property reset_sink EXPORT_OF ""
|
||||
set_interface_property reset_sink PORT_NAME_MAP ""
|
||||
set_interface_property reset_sink CMSIS_SVD_VARIABLES ""
|
||||
set_interface_property reset_sink SVD_ADDRESS_GROUP ""
|
||||
|
||||
add_interface_port reset_sink rst_n reset_n Input 1
|
||||
|
||||
|
||||
#
|
||||
# connection point avalon_master
|
||||
#
|
||||
add_interface avalon_master avalon start
|
||||
set_interface_property avalon_master addressUnits SYMBOLS
|
||||
set_interface_property avalon_master associatedClock clock_sink
|
||||
set_interface_property avalon_master associatedReset reset_sink
|
||||
set_interface_property avalon_master bitsPerSymbol 8
|
||||
set_interface_property avalon_master burstOnBurstBoundariesOnly false
|
||||
set_interface_property avalon_master burstcountUnits WORDS
|
||||
set_interface_property avalon_master doStreamReads false
|
||||
set_interface_property avalon_master doStreamWrites false
|
||||
set_interface_property avalon_master holdTime 0
|
||||
set_interface_property avalon_master linewrapBursts false
|
||||
set_interface_property avalon_master maximumPendingReadTransactions 0
|
||||
set_interface_property avalon_master maximumPendingWriteTransactions 0
|
||||
set_interface_property avalon_master readLatency 0
|
||||
set_interface_property avalon_master readWaitTime 1
|
||||
set_interface_property avalon_master setupTime 0
|
||||
set_interface_property avalon_master timingUnits Cycles
|
||||
set_interface_property avalon_master writeWaitTime 0
|
||||
set_interface_property avalon_master ENABLED true
|
||||
set_interface_property avalon_master EXPORT_OF ""
|
||||
set_interface_property avalon_master PORT_NAME_MAP ""
|
||||
set_interface_property avalon_master CMSIS_SVD_VARIABLES ""
|
||||
set_interface_property avalon_master SVD_ADDRESS_GROUP ""
|
||||
|
||||
add_interface_port avalon_master avalon_master_address address Output 32
|
||||
add_interface_port avalon_master avalon_master_burstcount burstcount Output 5
|
||||
add_interface_port avalon_master avalon_master_read read Output 1
|
||||
add_interface_port avalon_master avalon_master_readdata readdata Input 32
|
||||
add_interface_port avalon_master avalon_master_readdatavalid readdatavalid Input 1
|
||||
add_interface_port avalon_master avalon_master_waitreq waitrequest Input 1
|
||||
|
||||
|
||||
#
|
||||
# connection point irq
|
||||
#
|
||||
add_interface irq interrupt end
|
||||
set_interface_property irq associatedAddressablePoint avalon_slave
|
||||
set_interface_property irq associatedClock clock_sink
|
||||
set_interface_property irq associatedReset reset_sink
|
||||
set_interface_property irq bridgedReceiverOffset ""
|
||||
set_interface_property irq bridgesToReceiver ""
|
||||
set_interface_property irq ENABLED true
|
||||
set_interface_property irq EXPORT_OF ""
|
||||
set_interface_property irq PORT_NAME_MAP ""
|
||||
set_interface_property irq CMSIS_SVD_VARIABLES ""
|
||||
set_interface_property irq SVD_ADDRESS_GROUP ""
|
||||
|
||||
add_interface_port irq av_irq irq Output 1
|
||||
|
||||
|
||||
#
|
||||
# connection point LT24
|
||||
#
|
||||
add_interface LT24 conduit end
|
||||
set_interface_property LT24 associatedClock clock_sink
|
||||
set_interface_property LT24 associatedReset reset_sink
|
||||
set_interface_property LT24 ENABLED true
|
||||
set_interface_property LT24 EXPORT_OF ""
|
||||
set_interface_property LT24 PORT_NAME_MAP ""
|
||||
set_interface_property LT24 CMSIS_SVD_VARIABLES ""
|
||||
set_interface_property LT24 SVD_ADDRESS_GROUP ""
|
||||
|
||||
add_interface_port LT24 lt24_cs_n cs_n Output 1
|
||||
add_interface_port LT24 lt24_data data Output 16
|
||||
add_interface_port LT24 lt24_lcd_on lcd_on Output 1
|
||||
add_interface_port LT24 lt24_rd_n rd_n Output 1
|
||||
add_interface_port LT24 lt24_reset_n reset_n Output 1
|
||||
add_interface_port LT24 lt24_rs rs Output 1
|
||||
add_interface_port LT24 lt24_wr_n wr_n Output 1
|
||||
|
142
cs473-es/lab3/hw/hdl/LCDController/LCDController_tb.vhd
Normal file
142
cs473-es/lab3/hw/hdl/LCDController/LCDController_tb.vhd
Normal file
@ -0,0 +1,142 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use ieee.math_real.all;
|
||||
use std.env.finish;
|
||||
|
||||
|
||||
entity LCDController_tb is
|
||||
end LCDController_tb;
|
||||
|
||||
architecture test of LCDController_tb is
|
||||
constant CLK_PERIOD : time := 20 ns;
|
||||
|
||||
signal clk : std_logic := '0';
|
||||
signal rst_n : std_logic;
|
||||
signal waitreq, readdatavalid, fifo_almost_empty : std_logic;
|
||||
|
||||
-- Avalon slave interface
|
||||
signal avalon_slave_address : std_logic_vector (3 downto 0);
|
||||
signal avalon_slave_write : std_logic;
|
||||
signal avalon_slave_writedata : std_logic_vector(31 downto 0);
|
||||
signal avalon_slave_read : std_logic;
|
||||
signal avalon_slave_readdata : std_logic_vector(31 downto 0);
|
||||
|
||||
-- Avalon master interface
|
||||
signal avalon_master_waitreq : std_logic;
|
||||
signal avalon_master_readdata : std_logic_vector(31 downto 0);
|
||||
signal avalon_master_readdatavalid : std_logic;
|
||||
|
||||
signal avalon_master_read : std_logic;
|
||||
signal irq : std_logic;
|
||||
|
||||
begin
|
||||
|
||||
-- Instantiate DUT
|
||||
dut : entity work.LCDController
|
||||
port map(
|
||||
clk => clk,
|
||||
rst_n => rst_n,
|
||||
av_irq => irq,
|
||||
|
||||
avalon_slave_address => avalon_slave_address,
|
||||
avalon_slave_write => avalon_slave_write,
|
||||
avalon_slave_writedata => avalon_slave_writedata,
|
||||
avalon_slave_read => avalon_slave_read,
|
||||
avalon_slave_readdata => avalon_slave_readdata,
|
||||
avalon_master_waitreq => avalon_master_waitreq,
|
||||
avalon_master_readdata => avalon_master_readdata,
|
||||
avalon_master_readdatavalid => avalon_master_readdatavalid,
|
||||
avalon_master_read => avalon_master_read
|
||||
);
|
||||
|
||||
-- Clocking process
|
||||
clk_generation : process
|
||||
begin
|
||||
clk <= not clk;
|
||||
wait for CLK_PERIOD / 2;
|
||||
end process;
|
||||
|
||||
-- Testbench
|
||||
tb : process
|
||||
begin
|
||||
avalon_slave_address <= "0011";
|
||||
avalon_slave_write <= '0';
|
||||
avalon_slave_writedata <= (others => 'Z');
|
||||
|
||||
-- Dummy signals from bus
|
||||
avalon_master_readdata <= X"12341234";
|
||||
avalon_master_readdatavalid <= '0';
|
||||
avalon_master_waitreq <= '1';
|
||||
|
||||
-- Reset
|
||||
rst_n <= '0';
|
||||
wait for CLK_PERIOD * 2.5;
|
||||
rst_n <= '1';
|
||||
wait for CLK_PERIOD * 2;
|
||||
|
||||
-- Initiate CMD cycle
|
||||
avalon_slave_address <= "0000";
|
||||
wait until rising_edge(clk);
|
||||
avalon_slave_writedata <= (27 downto 0 => '0') & "1000";
|
||||
avalon_slave_write <= '1';
|
||||
wait until rising_edge(clk);
|
||||
avalon_slave_write <= '0';
|
||||
wait for CLK_PERIOD * 20;
|
||||
|
||||
avalon_slave_address <= "0001";
|
||||
wait until rising_edge(clk);
|
||||
avalon_slave_writedata <= (27 downto 0 => '0') & "1111";
|
||||
avalon_slave_write <= '1';
|
||||
wait until rising_edge(clk);
|
||||
avalon_slave_write <= '0';
|
||||
wait for CLK_PERIOD * 20;
|
||||
|
||||
-- Loop refreshing
|
||||
loop
|
||||
wait for CLK_PERIOD * 50;
|
||||
|
||||
-- Initiate a refresh cycle
|
||||
avalon_slave_address <= "0011";
|
||||
wait until rising_edge(clk);
|
||||
avalon_slave_write <= '1';
|
||||
wait until rising_edge(clk);
|
||||
avalon_slave_write <= '0';
|
||||
|
||||
-- Wait until bus grant
|
||||
wait for CLK_PERIOD * 3;
|
||||
avalon_master_waitreq <= '0';
|
||||
wait for CLK_PERIOD;
|
||||
|
||||
-- Emulate that new read data is valid each cycle of the burst
|
||||
avalon_master_readdatavalid <= '1';
|
||||
for i in 0 to 15 loop
|
||||
avalon_master_readdata <= std_logic_vector(to_unsigned(i*2 + ((i*2+1)*2**16), avalon_master_readdata'length));
|
||||
wait for CLK_PERIOD;
|
||||
end loop;
|
||||
-- burst finished
|
||||
avalon_master_readdatavalid <= '0';
|
||||
|
||||
loop
|
||||
-- Wait until the previous 16 words have been shifted to LCD and new pixels
|
||||
-- are requested
|
||||
wait until avalon_master_read = '1' or irq = '1';
|
||||
exit when irq = '1';
|
||||
|
||||
-- Wait some time for bus grant...
|
||||
wait for CLK_PERIOD * 3;
|
||||
|
||||
-- Start providing some data
|
||||
avalon_master_readdatavalid <= '1';
|
||||
for i in 0 to 15 loop
|
||||
avalon_master_readdata <= std_logic_vector(to_unsigned(i*2 + ((i*2+1)*2**16), avalon_master_readdata'length));
|
||||
wait for CLK_PERIOD;
|
||||
end loop;
|
||||
avalon_master_readdatavalid <= '0';
|
||||
end loop;
|
||||
|
||||
end loop;
|
||||
|
||||
end process;
|
||||
|
||||
end;
|
188
cs473-es/lab3/hw/hdl/LCDController/LCDDriver.vhd
Normal file
188
cs473-es/lab3/hw/hdl/LCDController/LCDDriver.vhd
Normal file
@ -0,0 +1,188 @@
|
||||
-- altera vhdl_input_version vhdl_2008
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use ieee.math_real.all;
|
||||
|
||||
entity LCDDriver is
|
||||
generic (
|
||||
F_CLK : natural -- Board frequency in Hz
|
||||
);
|
||||
port (
|
||||
clk : in std_logic;
|
||||
rst_n : in std_logic;
|
||||
|
||||
data_in : in std_logic_vector(15 downto 0);
|
||||
empty_in : in std_logic;
|
||||
refresh_in : in std_logic;
|
||||
|
||||
cmd_en_in : in std_logic;
|
||||
cmd_dcx_in : in std_logic;
|
||||
cmd_data_in : in std_logic_vector(7 downto 0);
|
||||
|
||||
data_out : out std_logic_vector(15 downto 0);
|
||||
rd_n : out std_logic;
|
||||
wr_n : out std_logic;
|
||||
rs : out std_logic;
|
||||
cs_n : out std_logic;
|
||||
|
||||
lcd_rdreq : out std_logic;
|
||||
|
||||
busy : out std_logic
|
||||
);
|
||||
end LCDDriver;
|
||||
|
||||
architecture Behavioral of LCDDriver is
|
||||
|
||||
constant F_LCD : natural := natural(real(25)*10**(6.0));
|
||||
constant F_LCD_MIN : natural := natural(real(12.5)*10**(6.0));
|
||||
constant F_LCD_MAX : natural := natural(real(30)*10**(6.0));
|
||||
|
||||
constant lcd_clk_en : std_logic := '1' ;
|
||||
signal lcd_clk : std_logic;
|
||||
|
||||
type GState is (tx, cmd, ready, std_wait,cmd_wait);
|
||||
type SNDState is (init, wrx, tx, done);
|
||||
|
||||
signal snds_reg, snds_next : SNDState;
|
||||
signal gs_reg, gs_next : GState;
|
||||
|
||||
signal data_reg : std_logic_vector(15 downto 0);
|
||||
|
||||
signal cmd_dcx_reg : std_logic := '1';
|
||||
signal cmd_data_reg : std_logic_vector(7 downto 0);
|
||||
|
||||
signal rdreq_limiter : std_logic;
|
||||
|
||||
begin
|
||||
|
||||
busy <= '0' when gs_reg = ready else '1';
|
||||
|
||||
--Global State Process
|
||||
process (all) begin
|
||||
gs_next <= gs_reg;
|
||||
snds_next <= snds_reg;
|
||||
|
||||
case gs_reg is
|
||||
when ready =>
|
||||
if cmd_en_in = '1' then
|
||||
if lcd_clk = '1' then
|
||||
gs_next <= cmd;
|
||||
snds_next <= wrx;
|
||||
else
|
||||
gs_next <= cmd_wait;
|
||||
end if;
|
||||
elsif refresh_in = '1' then
|
||||
gs_next <= std_wait;
|
||||
end if;
|
||||
when cmd_wait =>
|
||||
if lcd_clk = '1' then
|
||||
gs_next <= cmd;
|
||||
snds_next <= wrx;
|
||||
end if;
|
||||
when std_wait =>
|
||||
if empty_in = '0' then
|
||||
if lcd_clk = '1' then
|
||||
gs_next <= tx;
|
||||
snds_next <= init;
|
||||
end if;
|
||||
end if;
|
||||
when tx =>
|
||||
if snds_reg = done then
|
||||
gs_next <= ready;
|
||||
end if;
|
||||
when cmd =>
|
||||
if snds_reg = done then
|
||||
gs_next <= ready;
|
||||
end if;
|
||||
end case;
|
||||
|
||||
if (gs_reg = cmd or gs_reg = tx) then
|
||||
case snds_reg is
|
||||
when wrx =>
|
||||
snds_next <= tx;
|
||||
when tx =>
|
||||
if gs_reg = cmd then
|
||||
snds_next <= done;
|
||||
elsif gs_reg = tx then
|
||||
if empty_in = '1' then
|
||||
snds_next <= done;
|
||||
else
|
||||
snds_next <= wrx;
|
||||
end if;
|
||||
end if;
|
||||
when init =>
|
||||
snds_next <= wrx;
|
||||
when others =>
|
||||
null;
|
||||
end case;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
rs <= cmd_dcx_reg when gs_reg = cmd else '1'; -- DCX when CMD else Keep high
|
||||
cs_n <= not rst_n; -- Chip Select
|
||||
wr_n <= '0' when (gs_reg = cmd or gs_reg = tx) and
|
||||
snds_reg = wrx else '1'; -- Write data on rising edge
|
||||
rd_n <= '1'; -- Unused, Read data on rising edge
|
||||
|
||||
data_out <= data_reg when gs_reg = tx else
|
||||
"00000000" & cmd_data_reg when gs_reg = cmd else
|
||||
(others => '0');
|
||||
|
||||
lcd_rdreq <= '1' when (gs_reg = ready and gs_next = std_wait) or
|
||||
(snds_reg /= init and snds_next = init) or
|
||||
(rdreq_limiter = '0' and gs_reg = tx and snds_reg = tx) else '0';
|
||||
|
||||
-- Clock Sync & State Handler
|
||||
process (clk, rst_n) begin
|
||||
if rst_n = '0' then
|
||||
gs_reg <= ready;
|
||||
snds_reg <= wrx;
|
||||
|
||||
data_reg <= (others => '0');
|
||||
|
||||
cmd_dcx_reg <= '0';
|
||||
cmd_data_reg <= (others => '0');
|
||||
elsif rising_edge(clk) then
|
||||
|
||||
gs_reg <= gs_next;
|
||||
if lcd_clk = '1' then
|
||||
snds_reg <= snds_next; -- We run the SND at 25Mhz to respect state timings
|
||||
|
||||
if (snds_reg = tx or snds_reg = init) then
|
||||
data_reg <= data_in;
|
||||
end if;
|
||||
if (snds_reg = wrx) then
|
||||
rdreq_limiter <= '0';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if lcd_rdreq = '1' then
|
||||
rdreq_limiter <= '1';
|
||||
end if;
|
||||
|
||||
if gs_reg = ready and (cmd_en_in = '1') then
|
||||
cmd_dcx_reg <= cmd_dcx_in;
|
||||
cmd_data_reg <= cmd_data_in;
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- WS output clock
|
||||
clkgen_ent : entity work.ClkGen
|
||||
generic map (
|
||||
F_CLK => F_CLK,
|
||||
F_OUT => integer(F_LCD),
|
||||
F_MIN => integer(F_LCD_MIN),
|
||||
F_MAX => integer(F_LCD_MAX)
|
||||
)
|
||||
port map (
|
||||
clk => clk,
|
||||
rst_n => rst_n,
|
||||
clk_o => lcd_clk,
|
||||
en => lcd_clk_en
|
||||
);
|
||||
|
||||
|
||||
end Behavioral;
|
141
cs473-es/lab3/hw/hdl/LCDController/LCDDriver_tb.vhd
Normal file
141
cs473-es/lab3/hw/hdl/LCDController/LCDDriver_tb.vhd
Normal file
@ -0,0 +1,141 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use ieee.math_real.all;
|
||||
|
||||
|
||||
entity LCDDriver_tb is
|
||||
end LCDDriver_tb;
|
||||
|
||||
architecture test of LCDDriver_tb is
|
||||
constant CLK_PERIOD : time := 20 ns;
|
||||
constant N_LED_MAX : integer := 255;
|
||||
|
||||
signal clk : std_logic := '0';
|
||||
signal rst_n : std_logic := '1';
|
||||
|
||||
signal data_in : std_logic_vector(15 downto 0) := (others=> '0');
|
||||
signal empty_in : std_logic := '1';
|
||||
signal refresh_in : std_logic := '0';
|
||||
|
||||
signal cmd_en_in : std_logic := '0';
|
||||
signal cmd_dcx_in : std_logic := '0';
|
||||
signal cmd_data_in : std_logic_vector(7 downto 0) := (others => '0');
|
||||
|
||||
signal m_finished_in : std_logic := '0';
|
||||
|
||||
signal data_out : std_logic_vector(15 downto 0);
|
||||
signal rd_n : std_logic;
|
||||
signal wr_n : std_logic;
|
||||
signal rs : std_logic;
|
||||
signal cs_n : std_logic;
|
||||
|
||||
signal lcd_rdreq : std_logic;
|
||||
signal rdreq_cnt : integer := 0;
|
||||
|
||||
signal busy : std_logic;
|
||||
|
||||
begin
|
||||
-- Instantiate DUT
|
||||
dut : entity work.LCDDriver
|
||||
generic map (
|
||||
F_CLK => 50000000
|
||||
)
|
||||
port map(
|
||||
clk => clk,
|
||||
rst_n => rst_n,
|
||||
data_in => data_in,
|
||||
empty_in => empty_in,
|
||||
refresh_in => refresh_in,
|
||||
|
||||
cmd_en_in => cmd_en_in,
|
||||
cmd_dcx_in => cmd_dcx_in,
|
||||
cmd_data_in => cmd_data_in,
|
||||
|
||||
m_finished_in => m_finished_in,
|
||||
|
||||
data_out => data_out,
|
||||
rd_n => rd_n,
|
||||
wr_n => wr_n,
|
||||
rs => rs,
|
||||
cs_n => cs_n,
|
||||
|
||||
lcd_rdreq => lcd_rdreq,
|
||||
|
||||
busy => busy
|
||||
);
|
||||
|
||||
-- Clocking process
|
||||
clk_generation : process
|
||||
begin
|
||||
clk <= not clk;
|
||||
wait for CLK_PERIOD / 2;
|
||||
end process;
|
||||
|
||||
process (lcd_rdreq) begin
|
||||
if rising_edge(lcd_rdreq) then
|
||||
if (rdreq_cnt = 0) then
|
||||
data_in <= "1111111111111111";
|
||||
elsif (rdreq_cnt = 1) then
|
||||
data_in <= "1111000000001111";
|
||||
elsif (rdreq_cnt = 2) then
|
||||
data_in <= "1111111100000000";
|
||||
elsif (rdreq_cnt = 3) then
|
||||
data_in <= "0000000011111111";
|
||||
else
|
||||
data_in <= "0000000000000000";
|
||||
end if;
|
||||
rdreq_cnt <= rdreq_cnt + 1;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
tb : process
|
||||
procedure wait_ready is
|
||||
begin
|
||||
if busy = '1' then
|
||||
wait until busy = '0';
|
||||
end if;
|
||||
end procedure wait_ready;
|
||||
|
||||
procedure finish is
|
||||
begin
|
||||
wait until falling_edge(clk);
|
||||
wait_ready;
|
||||
wait;
|
||||
end procedure finish ;
|
||||
|
||||
begin
|
||||
-- Reset
|
||||
rst_n <= '0';
|
||||
wait for CLK_PERIOD * 2.5;
|
||||
rst_n <= '1';
|
||||
wait for CLK_PERIOD * 2;
|
||||
wait_ready;
|
||||
|
||||
-- Test CMD
|
||||
cmd_en_in <= '1';
|
||||
cmd_dcx_in <= '1';
|
||||
cmd_data_in <= "11010011";
|
||||
wait for CLK_PERIOD * 2.5;
|
||||
cmd_en_in <= '0';
|
||||
|
||||
wait_ready;
|
||||
|
||||
-- Test REFRESH
|
||||
refresh_in <= '1';
|
||||
wait for CLK_PERIOD * 2.5;
|
||||
refresh_in <= '0';
|
||||
wait for CLK_PERIOD * 4;
|
||||
empty_in <= '0';
|
||||
wait until rdreq_cnt = 4;
|
||||
empty_in <= '1';
|
||||
--m_finished_in => m_finished_in,
|
||||
wait_ready;
|
||||
|
||||
|
||||
-- Test finished
|
||||
finish;
|
||||
|
||||
end process;
|
||||
|
||||
end;
|
157
cs473-es/lab3/hw/hdl/LCDController/PixTrans.vhd
Normal file
157
cs473-es/lab3/hw/hdl/LCDController/PixTrans.vhd
Normal file
@ -0,0 +1,157 @@
|
||||
-- altera vhdl_input_version vhdl_2008
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
|
||||
entity PixTrans is
|
||||
generic (
|
||||
MAX_H : natural;
|
||||
MAX_W : natural
|
||||
);
|
||||
port (
|
||||
clk : in std_logic;
|
||||
rst_n : in std_logic;
|
||||
|
||||
lcd_req : in std_logic;
|
||||
data : out std_logic_vector(15 downto 0);
|
||||
empty : out std_logic;
|
||||
|
||||
fifo_req : out std_logic;
|
||||
fifo_q : in std_logic_vector(31 downto 0);
|
||||
fifo_empty : in std_logic;
|
||||
|
||||
-- Currently configured width/height of the buffer
|
||||
w : in natural;
|
||||
h : in natural
|
||||
);
|
||||
end PixTrans;
|
||||
|
||||
architecture behavioral of PixTrans is
|
||||
subtype Pixel is std_logic_vector(15 downto 0);
|
||||
|
||||
-- Generic constants
|
||||
constant BLANK : Pixel := "0000000000000000"; --(others => '0');
|
||||
|
||||
-- Type definitions
|
||||
type PIXEL_SOURCE is (S_BLANK, S_FIFO, S_BUFFER);
|
||||
|
||||
-- Inferred registers
|
||||
signal pixbuf_reg, pixbuf_next : Pixel;
|
||||
signal pixbufvalid_reg, pixbufvalid_next : boolean;
|
||||
signal pos_x_reg, pos_x_next : integer range 1 to MAX_W;
|
||||
signal pos_y_reg, pos_y_next : integer range 1 to MAX_H;
|
||||
signal pix_src_reg, pix_src_next : PIXEL_SOURCE;
|
||||
signal finished_next, finished_reg : std_logic;
|
||||
|
||||
-- Convenience signals
|
||||
signal inBlankArea_reg, inBlankArea_next : boolean;
|
||||
signal lcd_req_delayed_reg : std_logic;
|
||||
|
||||
begin
|
||||
|
||||
-- Update cursor
|
||||
process(all) begin
|
||||
finished_next <= finished_reg;
|
||||
pos_y_next <= pos_y_reg;
|
||||
pos_x_next <= pos_x_reg;
|
||||
|
||||
if lcd_req_delayed_reg = '1' then
|
||||
if pos_x_reg = MAX_W and pos_y_reg = MAX_H then
|
||||
pos_x_next <= 1;
|
||||
pos_y_next <= 1;
|
||||
|
||||
elsif pos_x_reg = MAX_W then
|
||||
pos_x_next <= 1;
|
||||
pos_y_next <= pos_y_reg + 1;
|
||||
else
|
||||
pos_x_next <= pos_x_reg + 1;
|
||||
end if;
|
||||
|
||||
if pos_x_reg = MAX_W and pos_y_reg = MAX_H then
|
||||
finished_next <= '1' and not finished_reg;
|
||||
else
|
||||
finished_next <= '0';
|
||||
end if;
|
||||
end if;
|
||||
inBlankArea_next <= pos_y_next > h or pos_x_next > w;
|
||||
end process;
|
||||
|
||||
|
||||
-- Data process
|
||||
process(all) begin
|
||||
pix_src_next <= pix_src_reg;
|
||||
pixbufvalid_next <= pixbufvalid_reg;
|
||||
|
||||
-- FIFO output signals
|
||||
fifo_req <= '0';
|
||||
|
||||
if lcd_req_delayed_reg = '1' then
|
||||
if inBlankArea_next then
|
||||
pix_src_next <= S_BLANK;
|
||||
elsif pixbufvalid_reg then
|
||||
-- Has valid pixel in pixel buffer
|
||||
pix_src_next <= S_BUFFER;
|
||||
pixbufvalid_next <= false;
|
||||
else
|
||||
|
||||
fifo_req <= '1';
|
||||
|
||||
-- fifo_req should be kept high until pixel is available
|
||||
if fifo_empty = '0' then
|
||||
-- Must request pixel from FIFO
|
||||
pix_src_next <= S_FIFO;
|
||||
pixbufvalid_next <= true;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
end process;
|
||||
|
||||
-- Data request multiplexer (pixel source)
|
||||
with pix_src_reg select data <=
|
||||
BLANK when S_BLANK,
|
||||
fifo_q(15 downto 0) when S_FIFO,
|
||||
pixbuf_reg when S_BUFFER;
|
||||
|
||||
|
||||
-- Fill pixel buffer with the upper half word of the input FIFO word when
|
||||
-- reading from the fifo
|
||||
pixbuf_next <= fifo_q(31 downto 16) when pix_src_reg = S_FIFO else pixbuf_reg;
|
||||
|
||||
-- LCD Controller empty signal
|
||||
process(all) begin
|
||||
if fifo_empty = '1' then
|
||||
empty <= '1';
|
||||
else
|
||||
empty <= finished_reg;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- Clocking process/register inferrence
|
||||
process(clk) begin
|
||||
if rising_edge(clk) then
|
||||
if rst_n = '0' then
|
||||
pos_x_reg <= 1;
|
||||
pos_y_reg <= 1;
|
||||
pixbuf_reg <= BLANK;
|
||||
pixbufvalid_reg <= false;
|
||||
pix_src_reg <= S_BLANK;
|
||||
inBlankArea_reg <= false;
|
||||
finished_reg <= '0';
|
||||
lcd_req_delayed_reg <= '0';
|
||||
else
|
||||
pos_x_reg <= pos_x_next;
|
||||
pos_y_reg <= pos_y_next;
|
||||
pixbuf_reg <= pixbuf_next;
|
||||
pixbufvalid_reg <= pixbufvalid_next;
|
||||
pix_src_reg <= pix_src_next;
|
||||
inBlankArea_reg <= inBlankArea_next;
|
||||
finished_reg <= finished_next;
|
||||
lcd_req_delayed_reg <= lcd_req;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
end behavioral ; -- behavioral
|
90
cs473-es/lab3/hw/hdl/LCDController/PixTrans_tb.vhd
Normal file
90
cs473-es/lab3/hw/hdl/LCDController/PixTrans_tb.vhd
Normal file
@ -0,0 +1,90 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use ieee.math_real.all;
|
||||
|
||||
|
||||
entity PixTrans_tb is
|
||||
end PixTrans_tb;
|
||||
|
||||
architecture test of PixTrans_tb is
|
||||
constant CLK_PERIOD : time := 20 ns;
|
||||
constant N_LED_MAX : integer := 255;
|
||||
|
||||
constant MAX_H : natural := 4;
|
||||
constant MAX_W : natural := 4;
|
||||
|
||||
constant ACTUAL_H : natural := 2;
|
||||
constant ACTUAL_W : natural := 2;
|
||||
|
||||
signal clk : std_logic := '0';
|
||||
signal rst_n : std_logic;
|
||||
|
||||
signal fifo_empty, lcd_req : std_logic;
|
||||
signal fifo_q : std_logic_vector(31 downto 0);
|
||||
signal w, h : natural;
|
||||
|
||||
begin
|
||||
|
||||
w <= ACTUAL_W;
|
||||
h <= ACTUAL_H;
|
||||
|
||||
-- Instantiate DUT
|
||||
dut : 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,
|
||||
fifo_q => fifo_q,
|
||||
fifo_empty => fifo_empty,
|
||||
w => w,
|
||||
h => h
|
||||
);
|
||||
|
||||
-- Clocking process
|
||||
clk_generation : process
|
||||
begin
|
||||
clk <= not clk;
|
||||
wait for CLK_PERIOD / 2;
|
||||
end process;
|
||||
|
||||
-- Testbench
|
||||
tb : process
|
||||
|
||||
procedure getPixel is
|
||||
begin
|
||||
wait until rising_edge(clk);
|
||||
lcd_req <= '1';
|
||||
wait for CLK_PERIOD;
|
||||
wait until rising_edge(clk);
|
||||
lcd_req <= '0';
|
||||
wait for CLK_PERIOD*3;
|
||||
end procedure getPixel;
|
||||
begin
|
||||
-- Just let the FIFO interface always provide data
|
||||
fifo_q <= X"FFFF" & X"F0F0";
|
||||
fifo_empty <= '0';
|
||||
lcd_req <= '0';
|
||||
|
||||
-- Reset
|
||||
rst_n <= '0';
|
||||
wait for CLK_PERIOD * 2.5;
|
||||
rst_n <= '1';
|
||||
wait for CLK_PERIOD * 2;
|
||||
|
||||
-- Get some pixels
|
||||
for i in 1 to MAX_H*MAX_W loop
|
||||
report "hello";
|
||||
getPixel;
|
||||
end loop;
|
||||
|
||||
-- Test finished
|
||||
wait;
|
||||
|
||||
end process;
|
||||
|
||||
end;
|
Reference in New Issue
Block a user