]> jspc29.x-matter.uni-frankfurt.de Git - trb3.git/commitdiff
Added trigger receiver for Mainz A2
authorAndreas Neiser <neiser@kph.uni-mainz.de>
Mon, 22 Apr 2013 09:01:13 +0000 (11:01 +0200)
committerAndreas Neiser <neiser@kph.uni-mainz.de>
Mon, 22 Apr 2013 17:13:07 +0000 (19:13 +0200)
base/code/mainz_a2_recv.vhd [new symlink]
cts/source/mainz_a2_recv.vhd [new file with mode: 0644]

diff --git a/base/code/mainz_a2_recv.vhd b/base/code/mainz_a2_recv.vhd
new file mode 120000 (symlink)
index 0000000..f6b3be0
--- /dev/null
@@ -0,0 +1 @@
+../../cts/source/mainz_a2_recv.vhd
\ No newline at end of file
diff --git a/cts/source/mainz_a2_recv.vhd b/cts/source/mainz_a2_recv.vhd
new file mode 100644 (file)
index 0000000..caa05e0
--- /dev/null
@@ -0,0 +1,244 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+use work.trb_net_std.all;
+use work.trb3_components.all;
+
+
+entity mainz_a2_recv is
+  port(
+    CLK      : in std_logic;    -- must be 100 MHz!
+    RESET_IN : in std_logic;   -- could be used after busy_release to make sure entity is in correct state
+
+    --Module inputs
+    SERIAL_IN  : in std_logic;             -- serial raw in, externally clock'ed at 12.5 MHz
+    EXT_TRG_IN : in std_logic;                         -- external trigger in, ~10us later
+                                                                                                                                                                               -- the external trigger id is sent on SERIAL_IN
+
+    --trigger outputs
+    TRG_ASYNC_OUT : out std_logic;  -- asynchronous rising edge, length varying, here: approx. 110 ns
+    TRG_SYNC_OUT  : out std_logic;      -- sync. to CLK
+
+    --data output for read-out
+    TRIGGER_IN    : in  std_logic;
+    DATA_OUT      : out std_logic_vector(31 downto 0);
+    WRITE_OUT     : out std_logic;
+    STATUSBIT_OUT : out std_logic_vector(31 downto 0);
+    FINISHED_OUT  : out std_logic;
+
+    --Registers / Debug    
+    CONTROL_REG_IN : in  std_logic_vector(31 downto 0);
+    STATUS_REG_OUT : out std_logic_vector(31 downto 0) := (others => '0');
+    DEBUG          : out std_logic_vector(31 downto 0)
+    );
+end entity;
+
+--A2 trigger format of SERIAL_IN
+--Startbit    : "1"
+--Trig.nr.    : 32bit (but only ~20bit used at the moment)
+--Paritybit   : "0" or "1" 
+--Stopbit/Controlbit: "1"
+--Parity check over trig Nr and parity bit
+
+--Data Format of DATA_OUT (goes into DAQ stream)
+-- Bit 30 -  0 : Trigger Number (Bit 32 is cut off and used for error flag)
+-- Bit 31      : Error flag (either parity wrong or no stop/control bit seen)
+
+--statusbit 23 of STATUSBIT_OUT is equal to Bit 31 of DATA_OUT
+
+architecture arch1 of mainz_a2_recv is
+
+       constant timeoutcnt_Max : integer := 2000000; -- x 10 ns = 20us maximum
+                                                    -- time until trigger id can
+                                                    -- be received;
+       signal timeoutcnt : integer range 0 to timeoutcnt_Max := timeoutcnt_Max;
+       
+       signal shift_reg : std_logic_vector(34 downto 0);
+       signal bitcnt    : integer range 0 to shift_reg'length;
+       
+  
+
+  --signal first_bits_fast : std_logic;
+  --signal first_bits_slow : std_logic;
+  signal reg_SERIAL_IN      : std_logic;
+  signal done            : std_logic;
+  --signal done_slow       : std_logic;
+
+  signal number_reg : std_logic_vector(30 downto 0);
+  --signal status_reg : std_logic_vector(1 downto 0);
+  signal error_reg  : std_logic;
+
+  signal trg_async : std_logic;
+  signal trg_sync  : std_logic;
+
+  type state_t is (IDLE, WAIT_FOR_STARTBIT, WAIT1, WAIT2, WAIT3, READ_BIT,
+                   WAIT5, WAIT6, WAIT7, WAIT8, NO_TRG_ID_RECV, FINISH);
+  signal state : state_t := IDLE;
+
+  type rdo_state_t is (RDO_IDLE, RDO_WAIT, RDO_WRITE, RDO_FINISH);
+  signal rdostate : rdo_state_t := RDO_IDLE;
+
+  signal config_rdo_disable_i : std_logic;
+
+begin
+
+
+  reg_SERIAL_IN <= SERIAL_IN when rising_edge(CLK);
+
+  --PROC_FIRST_BITS : process
+  --begin
+  --  wait until rising_edge(CLK_200);
+  --  if bitcnt > 32 and RESET_IN = '0' then
+  --    first_bits_fast <= '1';
+  --  else
+  --    first_bits_fast <= '0';
+  --  end if;
+  --end process;
+
+  --first_bits_slow <= first_bits_fast when rising_edge(CLK);
+
+  --trg_async <= (not MBS_IN or trg_async)                        when first_bits_fast = '1' else '0';
+  --trg_sync  <= (not reg_MBS_IN or trg_sync) and first_bits_slow when rising_edge(CLK);
+  trg_async <= EXT_TRG_IN;
+  trg_sync <= EXT_TRG_IN when rising_edge(CLK); -- do we need another register
+                                                                                                                                                                                               -- here?
+  
+  TRG_ASYNC_OUT <= trg_async;
+  TRG_SYNC_OUT  <= trg_sync when rising_edge(CLK);
+
+  -- since CLK runs at 100MHz, we sample at 12.5MHz due to 8 WAIT states
+  PROC_FSM : process
+  begin
+    wait until rising_edge(CLK);
+    case state is
+
+           when IDLE =>
+                   done   <= '1';
+                   if trg_sync = '1' then
+                           done <= '0';
+                           timeoutcnt <= timeoutcnt_Max;
+                           state <= WAIT_FOR_STARTBIT;
+                   end if;     
+                   
+      when WAIT_FOR_STARTBIT =>
+        
+        if reg_SERIAL_IN = '1' then
+               bitcnt <= shift_reg'length;
+               state <= WAIT1;
+        elsif timeoutcnt = 0 then
+               state <= NO_TRG_ID_RECV;
+        else 
+               timeoutcnt <= timeoutcnt-1;     
+        end if;
+
+        
+      when WAIT1 =>
+        state <= WAIT2;
+           when WAIT2 =>
+             state <= WAIT3;
+           when WAIT3 =>
+             state <= READ_BIT;
+             
+             
+      when READ_BIT => -- actually WAIT4, but we read here, in the middle of
+                                                                                        -- the serial line communication
+        bitcnt    <= bitcnt - 1;
+        -- we fill the shift_reg LSB first since this way the trg id arrives
+        shift_reg <= reg_SERIAL_IN & shift_reg(shift_reg'high downto 1);
+        state     <= WAIT5;
+        
+      when WAIT5 =>
+             -- check if we're done reading
+        if bitcnt = 0 then
+          state <= FINISH;
+        else
+          state <= WAIT6;
+        end if;
+        
+      when WAIT6 =>
+             state <= WAIT7;
+           when WAIT7 =>
+             state <= WAIT8;         
+           when WAIT8 =>
+             state <= WAIT1;                 
+
+           when NO_TRG_ID_RECV =>
+                   -- we received no id after a trigger within the timeout, so
+                   -- set bogus trigger id and no control bit (forces error flag set!)
+                   shift_reg <= b"00" & x"ffffffff" & b"1"; 
+                   state <= FINISH;
+                   
+      when FINISH =>
+             -- wait until serial line is idle again
+        if reg_SERIAL_IN = '0' then
+          state <= IDLE;
+        end if;
+        done <= '1';
+    end case;
+    
+    if RESET_IN = '1' then
+      state <= IDLE;
+      done  <= '0';
+    end if;
+  end process;
+
+  --done_slow <= done when rising_edge(CLK);
+
+  PROC_REG_INFO : process
+  begin
+    wait until rising_edge(CLK);
+    if done = '1' then
+           -- here we cut off the highest bit of the received trigger id
+           -- so shift_reg(32) is discarded (but used for checksum)
+      number_reg <= shift_reg(31 downto 1);
+      --status_reg <= shift_reg(7 downto 6);
+
+      -- check if start and control bit is 1 and parity is okay
+      if shift_reg(34) = '1' and shift_reg(0) = '1'
+             and xor_all(shift_reg(33 downto 1)) = '0' then
+        error_reg <= '0';
+      else
+        error_reg <= '1';
+      end if;
+    end if;
+  end process;
+
+
+  PROC_RDO : process
+  begin
+    wait until rising_edge(CLK);
+    WRITE_OUT     <= '0';
+    FINISHED_OUT  <= config_rdo_disable_i;
+    STATUSBIT_OUT <= (23 => error_reg, others => '0');
+    case rdostate is
+      when RDO_IDLE =>
+        if TRIGGER_IN = '1' and config_rdo_disable_i = '0' then
+          if done = '0' then
+            rdostate <= RDO_WAIT;
+          else
+            rdostate <= RDO_WRITE;
+          end if;
+        end if;
+      when RDO_WAIT =>
+        if done = '1' then
+          rdostate <= RDO_WRITE;
+        end if;
+      when RDO_WRITE =>
+        rdostate  <= RDO_FINISH;
+        DATA_OUT  <= error_reg & number_reg;
+        WRITE_OUT <= '1';
+        
+      when RDO_FINISH =>
+        FINISHED_OUT <= '1';
+        rdostate     <= RDO_IDLE;
+    end case;
+  end process;
+
+  config_rdo_disable_i <= CONTROL_REG_IN(0);
+
+  STATUS_REG_OUT <= error_reg & std_logic_vector(to_unsigned(bitcnt, 6)) & number_reg(24 downto 0);
+  DEBUG          <= x"00000000";  -- & done & '0' & shift_reg(13 downto 0);
+
+end architecture;