-- readout.vhd -- interface for FTDI FT245BM USB driver chip (write only) -- transmits the contents of an attached blockRAM over USB -- July 2009 -- Alexander Law (atlaw@lbl.gov) -- Lawrence Berkeley National Laboratory library IEEE; use IEEE.STD_LOGIC_1164.ALL; --use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; use ieee.numeric_std.all; entity readout is generic( WRhold : integer := 3 -- 75ns @ 40MHz, 50ns min for FTDI ); port( ------- global synchronization signals ------ clock : in std_logic; reset : in std_logic; trigger : in std_logic; dataLen : in std_logic_vector(12 downto 0); ready_out : out std_logic; -------- FTDI read/write signals ------------ ftdi_TXE : in std_logic; ftdi_WR_out : out std_logic := '0'; ftdi_wrData_out : out std_logic_vector(7 downto 0); -- connected to ftdi_wrData signal -------- transmit buffer signals ------------ xmtBuf_rdPtr_out : out std_logic_vector(12 downto 0); xmtBuf_rdData : in std_logic_vector(7 downto 0); xmtBuf_wrPtr_out : out std_logic_vector(12 downto 0); xmtBuf_wrData_out : out std_logic_vector (7 downto 0); xmtBuf_wrEn_out : out std_logic ); end readout; architecture behavioral of readout is signal xmtBuf_rdPtr : integer range 0 to 8191 := 0; signal xmtBuf_rdPtr_next : integer range 0 to 8191 := 0; signal xmtBuf_wrPtr : integer range 0 to 8191 := 0; signal xmtBuf_wrPtr_next : integer range 0 to 8191 := 0; signal xmtBuf_wrData : std_logic_vector(7 downto 0) := "00000000"; signal xmtBuf_wrData_next : std_logic_vector(7 downto 0) := "00000000"; signal xmtBuf_wrEn : std_logic := '0'; signal xmtBuf_wrEn_next : std_logic := '0'; type wr_states is (wr_waiting,wr_writing,wr_holdLow,wr_done); signal wr_state : wr_states := wr_done; signal wr_nextState : wr_states := wr_done; signal ftdi_WR : std_logic := '0'; signal ftdi_WR_next : std_logic := '0'; signal readoutCount : integer range 0 to 8191 := 0; -- number of bytes transmitted over FTDI signal readoutCount_next : integer range 0 to 8191 := 0; -- readoutCount synchronous-assignment signal signal WRholdCount : integer range 0 to WRhold := 0; -- counter for holding ftdi_WR high during write cycle signal WRholdCount_next : integer range 0 to WRhold := 0; -- WRholdCount synchronous-assignment signal signal holdLow : std_logic := '1'; signal holdLow_next : std_logic := '1'; signal dataLenReg : std_logic_vector(12 downto 0) := "0000000000000"; -- registers the dataLength input at time of trigger signal dataLenReg_next : std_logic_vector(12 downto 0) := "0000000000000"; -- dataLenReg synchronous-assignment signal signal ready : std_logic := '0'; begin ----------- persistent assignments -------------- -- "out" ports can't be read, so to use their values -- internally, they have to be duplicated to signals. ftdi_WR_out <= ftdi_WR; ftdi_wrData_out <= xmtBuf_rdData; ready_out <= ready; xmtBuf_rdPtr_out <= std_logic_vector(to_unsigned(xmtBuf_rdPtr,13)); xmtBuf_wrPtr_out <= std_logic_vector(to_unsigned(xmtBuf_wrPtr,13)); xmtBuf_wrData_out <= xmtBuf_wrData; xmtBuf_wrEn_out <= xmtBuf_wrEn; ------------------------------------------------- -------synchronous assignments------------ process(clock,reset,dataLen) begin if(reset = '1') then wr_state <= wr_done; ftdi_WR <= '0'; readoutCount <= 0; WRholdCount <= 0; holdLow <= '1'; dataLenReg <= "0000000000000"; xmtBuf_rdPtr <= 0; xmtBuf_wrPtr <= 0; xmtBuf_wrData <= "00000000"; xmtBuf_wrEn <= '0'; elsif(clock'event and clock = '1') then wr_state <= wr_nextState; ftdi_WR <= ftdi_WR_next; readoutCount <= readoutCount_next; WRholdCount <= WRholdCount_next; holdLow <= holdLow_next; dataLenReg <= dataLenReg_next; xmtBuf_rdPtr <= xmtBuf_rdPtr_next; xmtBuf_wrPtr <= xmtBuf_wrPtr_next; xmtBuf_wrData <= xmtBuf_wrData_next; xmtBuf_wrEn <= xmtBuf_wrEn_next; end if; end process; ------------------------------------------ xmtBuf_wrData_next <= "00000000"; -- set to 0x00 for "clear" function -------- ready flag ---------------------- with wr_state select ready <= '1' when wr_done, '0' when others; ------------------------------------------ ------------ writing over FTDI ------------------ process(wr_state,ftdi_TXE,WRholdCount,readoutCount,holdLow,dataLenReg,xmtBuf_rdPtr,xmtBuf_wrPtr,dataLen,trigger) begin case wr_state is when wr_waiting => readoutCount_next <= readoutCount; holdLow_next <= '0'; dataLenReg_next <= dataLenReg; xmtBuf_rdPtr_next <= xmtBuf_rdPtr; xmtBuf_wrPtr_next <= xmtBuf_wrPtr; xmtBuf_wrEn_next <= '0'; if ( (ftdi_TXE = '1') ) then ftdi_WR_next <= '0'; WRholdCount_next <= 0; wr_nextState <= wr_waiting; else ftdi_WR_next <= '1'; WRholdCount_next <= 1; wr_nextState <= wr_writing; end if; when wr_writing => dataLenReg_next <= dataLenReg; xmtBuf_rdPtr_next <= xmtBuf_rdPtr; xmtBuf_wrPtr_next <= xmtBuf_wrPtr; xmtBuf_wrEn_next <= '0'; if ( (WRholdCount > WRhold-1) AND (ftdi_TXE = '0') ) then ftdi_WR_next <= '0'; WRholdCount_next <= 0; wr_nextState <= wr_holdLow; holdLow_next <= '1'; readoutCount_next <= readoutCount +1; else ftdi_WR_next <= '1'; WRholdCount_next <= WRholdCount +1; readoutCount_next <= readoutCount; wr_nextState <= wr_writing; holdLow_next <= '0'; end if; -- need to make sure WR stays low 2 ticks, since TXE can take 25 ns to rise when wr_holdLow => readoutCount_next <= readoutCount; ftdi_WR_next <= '0'; WRholdCount_next <= 0; dataLenReg_next <= dataLenReg; holdLow_next <= '0'; xmtBuf_wrPtr_next <= xmtBuf_wrPtr; xmtBuf_wrEn_next <= '0'; if( holdLow = '1' ) then wr_nextState <= wr_holdLow; xmtBuf_rdPtr_next <= xmtBuf_rdPtr +1; -- xmtBuf_rdPtr increments AFTER ftdi_WR is low one tick. elsif ( (readoutCount < dataLenReg ) ) then wr_nextState <= wr_waiting; xmtBuf_rdPtr_next <= xmtBuf_rdPtr; else wr_nextState <= wr_done; xmtBuf_rdPtr_next <= xmtBuf_rdPtr; end if; when wr_done => ftdi_WR_next <= '0'; WRholdCount_next <= 0; readoutCount_next <= readoutCount; holdLow_next <= '0'; xmtBuf_wrEn_next <= '0'; if (trigger = '1') then wr_nextState <= wr_waiting; readoutCount_next <= 0; dataLenReg_next <= dataLen; xmtBuf_rdPtr_next <= 0; xmtBuf_wrPtr_next <= 0; else wr_nextState <= wr_done; readoutCount_next <= readoutCount; dataLenReg_next <= dataLenReg; xmtBuf_rdPtr_next <= xmtBuf_rdPtr; xmtBuf_wrPtr_next <= xmtBuf_wrPtr; end if; when others => readoutCount_next <= readoutCount; holdLow_next <= '0'; dataLenReg_next <= dataLenReg; xmtBuf_rdPtr_next <= xmtBuf_rdPtr; xmtBuf_wrPtr_next <= xmtBuf_wrPtr; xmtBuf_wrEn_next <= '0'; ftdi_WR_next <= '0'; WRholdCount_next <= 0; wr_nextState <= wr_waiting; end case; end process; ------------------------------------------------- end behavioral;