Forum Discussion
Altera_Forum
Honored Contributor
12 years agoI have looked at the Avalon bus specification for memory mapped slaves and devised a similar protocol:
Below is the user of the FT245 driver - it is a 2 process state machine:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY Comm IS
PORT
(
clk : IN STD_LOGIC;
rstn : IN STD_LOGIC;
debug_wr_flag : STD_LOGIC;
debug_in_data : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
debug_data_rd : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
debug_data_wr : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
);
END ENTITY;
ARCHITECTURE behavioral OF Comm is
SIGNAL debug_wr_flag_reg : STD_LOGIC;
SIGNAL debug_in_data_reg : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL rd_fifo_has_data : STD_LOGIC; -- FT245 fifo has data for reading
SIGNAL wr_fifo_full : STD_LOGIC; -- FT245 fifo is full for writing
SIGNAL waitreq : STD_LOGIC; -- FT245 is busy
SIGNAL rd : STD_LOGIC; -- request rd
SIGNAL wr : STD_LOGIC; -- request wr
SIGNAL rddatavalid : STD_LOGIC; -- data is valid
SIGNAL rd_data : STD_LOGIC_VECTOR(7 DOWNTO 0); -- received (read) data by FT245
SIGNAL wr_data : STD_LOGIC_VECTOR(7 DOWNTO 0); -- data to be written to FT245
SIGNAL can_write : STD_LOGIC;
SIGNAL can_read : STD_LOGIC;
TYPE state IS (init, idle, wait_write, wait_read);
SIGNAL pr_state, nx_state : state;
COMPONENT FT245 IS
PORT
(
clk : IN STD_LOGIC;
rstn : IN STD_LOGIC;
rd_flag : IN STD_LOGIC;
wr_flag : IN STD_LOGIC;
rd_fifo_has_data : OUT STD_LOGIC;
wr_fifo_full : OUT STD_LOGIC;
waitreq : OUT STD_LOGIC;
rddatavalid : OUT STD_LOGIC;
data_write : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
data_read : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
);
END COMPONENT;
BEGIN
driver : FT245 port map
(
clk => clk,
rstn => rstn,
rd_flag => rd,
wr_flag => wr,
rd_fifo_has_data => rd_fifo_has_data,
wr_fifo_full => wr_fifo_full,
waitreq => waitreq,
rddatavalid => rddatavalid,
data_write => wr_data,
data_read => rd_data
);
-- For debug purposes - show current values of rd and wr data. Not synced on purpose.
debug_data_rd <= rd_data;
debug_data_wr <= wr_data;
-- For debug purposes - to inject some data to send...
PROCESS(clk)
BEGIN
IF(rising_edge(clk)) THEN
debug_wr_flag_reg <= debug_wr_flag;
debug_in_data_reg <= debug_in_data;
END IF;
END PROCESS;
-- Sequential part
PROCESS(clk, rstn)
BEGIN
IF(rstn = '0') THEN
pr_state <= init;
ELSIF(rising_edge(clk)) THEN
pr_state <= nx_state;
END IF;
END PROCESS;
-- Combinatorial part
-- can write only if debug wr flag is 1 and fifo is not full and no transaction is in progress
can_write <= '1' WHEN debug_wr_flag_reg = '1' and wr_fifo_full = '0' and wr = '0' and rd = '0' and waitreq = '0'
ELSE '0';
-- can read only if FT245 fifo has data and no transacation is in progress
can_read <= '1' WHEN rd_fifo_has_data = '1' and wr = '0' and rd = '0' and waitreq = '0'
ELSE '0';
PROCESS(pr_state, wr_fifo_full, waitreq, rddatavalid, rd_data, can_write, can_read, debug_in_data_reg)
BEGIN
CASE pr_state IS
WHEN init =>
wr_data <= (others => '0');
rd <= '0';
wr <= '0';
nx_state <= idle;
WHEN idle =>
wr_data <= (others => '0');
rd <= '0';
wr <= '0';
nx_state <= idle;
IF(can_write = '1') THEN
wr_data <= debug_in_data_reg;
wr <= '1';
nx_state <= wait_write;
ELSIF(can_read = '1') THEN
rd <= '1';
nx_state <= wait_read;
END IF;
WHEN wait_write =>
wr_data <= debug_in_data_reg;
wr <= '1';
rd <= '0';
nx_state <= wait_write;
IF(waitreq = '0') THEN
wr <='0';
nx_state <= idle;
END IF;
WHEN wait_read =>
rd <= '1';
wr <= '0';
wr_data <= (others => '0');
nx_state <= wait_read;
IF(waitreq = '0' and rddatavalid = '1') THEN
rd <= '0';
nx_state <= idle;
END IF;
WHEN others =>
wr_data <= (others => '0');
wr <= '0';
rd <= '0';
nx_state <= init;
END CASE;
END PROCESS;
END behavioral;
And this is the skeleton of FT245 driver as a single process timed state machine. When it enters do_write and do_read, it will have sub-states to actually strobe the FT245 chip with data, etc. This code only shows the communication side towards. I had some trouble with inferring latches for the output so I did a single process FSM.
library ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
ENTITY FT245 IS
PORT
(
clk : IN STD_LOGIC;
rstn : IN STD_LOGIC;
rd_flag : IN STD_LOGIC;
wr_flag : IN STD_LOGIC;
rd_fifo_has_data : OUT STD_LOGIC;
wr_fifo_full : OUT STD_LOGIC;
waitreq : OUT STD_LOGIC;
rddatavalid : OUT STD_LOGIC;
data_write : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
data_read : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
);
END ENTITY;
ARCHITECTURE behavioral OF FT245 IS
BEGIN
-- Debug values
rd_fifo_has_data <= '0'; -- will not go into reading
wr_fifo_full <= '0'; -- will always mark as write is OK....
PROCESS(clk, rstn)
TYPE state IS (init, idle, do_write, write_end, do_read, read_end);
VARIABLE pr_state, nx_state : state;
VARIABLE dummy : INTEGER RANGE 0 to 100; -- dummy counter for read data
VARIABLE count : INTEGER RANGE 0 to 5;
VARIABLE timer : INTEGER RANGE 0 to 5;
BEGIN
IF(rstn = '0') THEN
count := 0;
pr_state := init;
nx_state := init;
ELSIF(rising_edge(clk)) THEN
count := count +1;
CASE pr_state IS
WHEN init =>
dummy := 0;
rddatavalid <= '0';
waitreq <= '0';
timer := 0;
nx_state := idle;
data_read <= (others => '0');
WHEN idle =>
rddatavalid <= '0';
waitreq <= '0';
nx_state := idle;
timer := 0;
IF(wr_flag = '1') THEN
waitreq <= '1';
nx_state := do_write;
ELSIF(rd_flag = '1') THEN
waitreq <= '1';
nx_state := do_read;
END IF;
WHEN do_write =>
rddatavalid <= '0';
waitreq <= '1';
nx_state := write_end;
timer := 5; -- 100ns delay - as needed for FT245 to do its work....substates should be
-- here to do actual protocol to FT245
WHEN write_end =>
rddatavalid <= '0';
waitreq <= '0';
nx_state := idle;
timer := 0;
WHEN do_read =>
dummy := dummy +1;
rddatavalid <= '0';
waitreq <= '1';
nx_state := read_end;
timer := 5; -- 100 ns delay; actually there should be sub-states here
-- to talk to FT245 chip as required
WHEN read_end =>
data_read <= std_logic_vector(to_unsigned(dummy,8));
rddatavalid <= '1';
waitreq <= '0';
nx_state := idle;
timer := 0;
WHEN others =>
data_read <= (others => '0');
rddatavalid <= '0';
waitreq <= '0';
timer := 0;
nx_state := init;
END CASE;
-- Update present state with next state
IF(count >= timer) THEN
pr_state := nx_state;
count := 0;
END IF;
END IF; -- rising clock
END PROCESS; -- fsm
END behavioral;
Didn't have time to do simulation yet - holidays & such. What do you all think?