]> rtime.felk.cvut.cz Git - fpga/lx-cpu1/lx-rocon.git/blobdiff - hw/lxmaster_transmitter.vhd
Add registers to LX Master MOSI and SYNC signals to ensure right timing.
[fpga/lx-cpu1/lx-rocon.git] / hw / lxmaster_transmitter.vhd
index c111f4711805c545613fc4a722ad041497b15725..1c9153c310cdd74eebed0044408464c0cd7b644d 100644 (file)
@@ -7,6 +7,9 @@ use work.lx_rocon_pkg.all;
 
 -- LX Master (Transmitter)
 entity lxmaster_transmitter is
+       generic (
+               cycle_cnt_width_g : natural := 12
+       );
        port
        (
                clk_i             : in std_logic;
@@ -17,8 +20,15 @@ entity lxmaster_transmitter is
                sync_o            : out std_logic;
                -- Register
                register_i        : in std_logic;
-               register_o        : out std_logic;
+               register_o        : out std_logic_vector(1 downto 0);
                register_we_i     : in std_logic;
+               -- Cycle period
+               cycle_reg_i       : in std_logic_vector(cycle_cnt_width_g-1 downto 0);
+               cycle_reg_o       : out std_logic_vector(cycle_cnt_width_g-1 downto 0);
+               cycle_reg_we_i    : in std_logic;
+               -- Watchdog
+               wdog_i            : in std_logic;
+               wdog_we_i         : in std_logic;
                -- BRAM access
                mem_clk_i         : in std_logic;
     mem_en_i          : in std_logic;
@@ -34,32 +44,37 @@ architecture Behavioral of lxmaster_transmitter is
        -- Types
        type state_t is (ST_INIT, ST_READY, ST_XFER, ST_CRC, ST_END);
        constant frame_length_c         : positive := 2500; -- 50 MHz -> 20 kHz
-       -- RAM Access (both ARM and Tumbl)
+       constant wdog_length_c          : positive := 2500000; -- 50 ms
+       constant msg_max_count_c        : positive := 8;
+       -- RAM Access
        signal ram_en_s                 : std_logic;
        signal ram_rst_s                : std_logic;
-       --
        signal ram_addr_s               : std_logic_vector(8 downto 0);
        signal ram_addr_r               : std_logic_vector(8 downto 0);
        signal ram_data_o_s             : std_logic_vector(15 downto 0);
        -- State
        signal lxmaster_state_s         : state_t;
        signal lxmaster_state_r         : state_t;
-       signal lxmaster_not_last_word_s : std_logic;
-       signal lxmaster_not_last_word_r : std_logic;
+       signal lxmaster_last_word_s     : std_logic;
+       signal lxmaster_last_word_r     : std_logic;
        -- Data
        signal lxmaster_num_data_s      : std_logic_vector(7 downto 0); -- If 0 then the peripheral is not active this cycle
        signal lxmaster_num_data_r      : std_logic_vector(7 downto 0);
        signal lxmaster_loaded_data_s   : std_logic_vector(15 downto 0);
        signal lxmaster_loaded_data_r   : std_logic_vector(15 downto 0);
-       signal lxmaster_data_counter_s  : std_logic_vector(3 downto 0); -- Shift: 0 - 15
-       signal lxmaster_data_counter_r  : std_logic_vector(3 downto 0);
+       signal lxmaster_data_counter_s  : natural range 0 to 15;
+       signal lxmaster_data_counter_r  : natural range 0 to 15;
        -- Transmission
        signal lxmaster_sync_s          : std_logic;
        signal lxmaster_sync_r          : std_logic;
        signal lxmaster_sync_last_bit_s : std_logic;
        signal lxmaster_sync_last_bit_r : std_logic;
-       -- Frame counter
-       signal lxmaster_frame_counter_s : natural range 0 to (frame_length_c-1);
+       -- Counters
+       signal lxmaster_wdog_counter_s  : natural range 0 to (wdog_length_c-1);
+       signal lxmaster_frame_counter_s : natural range 0 to (2**cycle_cnt_width_g - 1);
+       signal lxmaster_cycle_limit_r   : std_logic_vector(cycle_cnt_width_g-1 downto 0);
+       signal lxmaster_msg_counter_s   : natural range 0 to (msg_max_count_c-1);
+       signal lxmaster_msg_counter_r   : natural range 0 to (msg_max_count_c-1);
        -- CRC
        signal lxmaster_crc_data_s      : std_logic;
        signal lxmaster_crc_reset_s     : std_logic;
@@ -69,32 +84,44 @@ architecture Behavioral of lxmaster_transmitter is
        -- RAM reset
        signal lxmaster_ram_reset_s     : std_logic;
        -- Register
-       -- Bit 0: Transmitter - use first or second buffer
+       -- Bit 0: Transmitter - use first or second buffer (I/O)
+       -- Bit 1: Watchdog not kicked (O)
        signal lxmaster_register_in_s   : std_logic;
-       signal lxmaster_register_out_s  : std_logic;
+       signal lxmaster_register_out_s  : std_logic_vector(1 downto 0);
+       -- Output buffers
+       signal sync_s                   : std_logic;
+       signal sync_r                   : std_logic;
+       signal mosi_s                   : std_logic;
+       signal mosi_r                   : std_logic;
 
 begin
 
        -- Directly route out some signals
        clock_o              <= clk_i; -- Cannot mix with logic
-       sync_o               <= not lxmaster_sync_r; -- Active in log. 0
-       mosi_o               <= '1' when lxmaster_sync_r = '0' and lxmaster_sync_last_bit_r = '0'
+       sync_s               <= not lxmaster_sync_r; -- Active in log. 0
+       mosi_s               <= '1' when lxmaster_sync_r = '0' and lxmaster_sync_last_bit_r = '0'
                                 else lxmaster_crc_reg_r(0) when lxmaster_state_r = ST_CRC
                                 else lxmaster_loaded_data_r(0);
+       sync_o               <= sync_r;
+       mosi_o               <= mosi_r;
+
        -- CRC
        lxmaster_crc_reg_s   <= '0' & lxmaster_crc_reg_r(7 downto 1) when lxmaster_state_r = ST_CRC else lxmaster_crc_out_s;
        lxmaster_crc_data_s  <= '1' when lxmaster_state_r = ST_CRC else lxmaster_loaded_data_r(0);
-       lxmaster_crc_reset_s <= '1' when lxmaster_state_r = ST_READY or reset_i = '1' else '0';
+       lxmaster_crc_reset_s <= '1' when lxmaster_state_r /= ST_XFER or reset_i = '1' else '0';
 
-       -- Register
+       -- Registers output
        register_o           <= lxmaster_register_out_s;
+       cycle_reg_o          <= lxmaster_cycle_limit_r;
 
-ram: xilinx_dualport_bram_write_first
+ram: xilinx_dualport_bram
        generic map
        (
                we_width      => 2,
                byte_width    => 8,
-               address_width => 9
+               address_width => 9,
+               port_a_type   => WRITE_FIRST,
+               port_b_type   => READ_FIRST
        )
        port map
        (
@@ -130,8 +157,8 @@ crc_out: crc
 -- Update
 -- TODO: Maybe some exception handling (overflows etc.)
 transmitter_update:
-       process (ram_data_o_s, ram_addr_r, lxmaster_state_r, lxmaster_loaded_data_r, lxmaster_num_data_r, lxmaster_not_last_word_r,
-                lxmaster_data_counter_r, reset_i, lxmaster_frame_counter_s, lxmaster_register_in_s)
+       process (ram_data_o_s, ram_addr_r, lxmaster_state_r, lxmaster_loaded_data_r, lxmaster_num_data_r, lxmaster_msg_counter_r,
+                lxmaster_last_word_r, lxmaster_data_counter_r, reset_i, lxmaster_frame_counter_s, lxmaster_register_in_s, lxmaster_wdog_counter_s)
                variable ram_addr_v : std_logic_vector(8 downto 0);
        begin
 
@@ -144,13 +171,15 @@ transmitter_update:
                lxmaster_loaded_data_s             <= lxmaster_loaded_data_r;
                lxmaster_data_counter_s            <= lxmaster_data_counter_r;
                lxmaster_num_data_s                <= lxmaster_num_data_r;
-               lxmaster_not_last_word_s           <= lxmaster_not_last_word_r;
+               lxmaster_msg_counter_s             <= lxmaster_msg_counter_r;
+               lxmaster_last_word_s               <= lxmaster_last_word_r;
 
                if reset_i = '1' then
                        lxmaster_num_data_s              <= x"00";
                        lxmaster_loaded_data_s           <= x"0000";
                        lxmaster_state_s                 <= ST_END;
                        lxmaster_sync_s                  <= '0';
+                       lxmaster_last_word_s             <= '0';
                        --
                        ram_addr_s                       <= '0' & x"00";
                        ram_en_s                         <= '0';
@@ -171,42 +200,46 @@ transmitter_update:
                                                lxmaster_state_s           <= ST_END; --Nothing
                                        else
                                                lxmaster_state_s           <= ST_READY; -- Make next read init the transfer
+                                               ram_addr_v                   := ram_addr_r(8) & ram_data_o_s(15 downto 8); -- Update address
+                                               ram_addr_s                   <= ram_addr_v;
+                                               lxmaster_num_data_s          <= std_logic_vector(unsigned(ram_addr_v(7 downto 0)) + unsigned(ram_data_o_s(7 downto 0)));
+                                               ram_en_s                     <= '1'; -- Read
                                        end if;
 
-                                       -- Regardless, write the number of data
-                                       lxmaster_num_data_s          <= ram_data_o_s(7 downto 0);
-
-                                       -- And schedule reading
-                                       ram_addr_s                   <= ram_addr_r + 1; -- Update address
-                                       ram_en_s                     <= '1'; -- Read
+                                       -- Prepare message counter
+                                       lxmaster_msg_counter_s       <= 0;
 
                                when ST_READY =>
                                        -- We are ready to begin transferring
                                        lxmaster_loaded_data_s       <= ram_data_o_s;
                                        lxmaster_sync_s              <= '1'; -- Transferring data next cycle
-                                       lxmaster_data_counter_s      <= x"0"; -- Reset counter
+                                       lxmaster_data_counter_s      <= 0; -- Reset counter
                                        lxmaster_state_s             <= ST_XFER; --Go to transfer loop
-                                       lxmaster_not_last_word_s     <= '0'; -- Not last word
 
                                when ST_XFER =>
                                        lxmaster_loaded_data_s       <= '0' & lxmaster_loaded_data_r(15 downto 1); -- Shift it
                                        lxmaster_sync_s              <= '1'; -- Transferring data next cycle
 
-                                       if lxmaster_data_counter_r = x"E" and ram_addr_r(7 downto 0) /= lxmaster_num_data_r then
-                                               -- At 14th bit, we need to read from RAM if more words are to come
-                                               ram_addr_s                 <= ram_addr_r + 1; -- Update address
+                                       if lxmaster_data_counter_r = 14 then
                                                lxmaster_data_counter_s    <= lxmaster_data_counter_r + 1; -- Increment
-                                               ram_en_s                   <= '1'; -- Read
-                                               lxmaster_not_last_word_s   <= '1';
-                                       elsif lxmaster_data_counter_r = x"F" then
-                                               -- At 15th bit, we either stop if ram_addr_r equals lxmaster_num_data_r (wasn't updated so it would not overflow)
-                                               if ram_addr_r(7 downto 0) = lxmaster_num_data_r and lxmaster_not_last_word_r = '0' then
+
+                                               if (ram_addr_r(7 downto 0) + 1) /= lxmaster_num_data_r then
+                                                       -- At 14th bit, we need to read from RAM if more words are to come
+                                                       ram_addr_s                 <= ram_addr_r(8) & (ram_addr_r(7 downto 0) + 1); -- Update address
+                                                       ram_en_s                   <= '1'; -- Read
+                                                       lxmaster_last_word_s       <= '0';
+                                               else
+                                                       lxmaster_last_word_s       <= '1';
+                                               end if;
+
+                                       elsif lxmaster_data_counter_r = 15 then
+                                               -- At 15th bit, we either stop if ram_addr_r equals lxmaster_num_data_r
+                                               if lxmaster_last_word_r = '1' then
                                                        lxmaster_state_s         <= ST_CRC;
-                                                       lxmaster_data_counter_s  <= x"0";
+                                                       lxmaster_data_counter_s  <= 0;
                                                else
                                                        lxmaster_loaded_data_s   <= ram_data_o_s;
-                                                       lxmaster_data_counter_s  <= x"0";
-                                                       lxmaster_not_last_word_s <= '0';
+                                                       lxmaster_data_counter_s  <= 0;
                                                end if;
                                        else
                                                -- Increment
@@ -216,16 +249,19 @@ transmitter_update:
                                when ST_CRC =>
 
                                        -- Check if this is last command, first read one more
-                                       if lxmaster_data_counter_r = x"0" then
-                                               if (ram_addr_r(7 downto 0) = x"FF") then
-                                                       lxmaster_ram_reset_s     <= '1'; -- Make sure we read 0 in this case
+                                       if lxmaster_data_counter_r = 0 then
+                                               if lxmaster_msg_counter_r = (msg_max_count_c - 1) then
+                                                       lxmaster_ram_reset_s     <= '1'; -- Make sure we read 0 if we are on the last message
+                                               else
+                                                       lxmaster_msg_counter_s  <= lxmaster_msg_counter_r + 1;
                                                end if;
 
-                                               ram_addr_s                 <= ram_addr_r + 1; -- Update address
+                                               ram_addr_s                 <= ram_addr_r(8) & std_logic_vector(to_unsigned(lxmaster_msg_counter_r + 1, ram_addr_r'length - 1)); -- Update address
                                                ram_en_s                   <= '1'; -- Read
-                                       elsif lxmaster_data_counter_r = x"1" then
 
-                                               if ram_data_o_s(7 downto 0) /= x"00" then -- Need to read first command
+                                       elsif lxmaster_data_counter_r = 1 then
+
+                                               if ram_data_o_s(15 downto 8) >= msg_max_count_c then -- Need to read first command, make sure it's valid
                                                        ram_addr_v               := ram_addr_r(8) & ram_data_o_s(15 downto 8); -- Update address
                                                        ram_addr_s               <= ram_addr_v;
                                                        lxmaster_num_data_s      <= std_logic_vector(unsigned(ram_addr_v(7 downto 0)) + unsigned(ram_data_o_s(7 downto 0)));
@@ -236,18 +272,22 @@ transmitter_update:
 
                                        end if;
 
-                                       if lxmaster_data_counter_r = x"7" then -- Ending
-                                               lxmaster_data_counter_s    <= x"0";
+                                       if lxmaster_data_counter_r = 7 then -- Ending
+                                               lxmaster_data_counter_s    <= 0;
 
-                                               if lxmaster_num_data_r(7 downto 0) = x"00" then
+                                               if lxmaster_num_data_r = x"00" then
                                                        lxmaster_state_s         <= ST_END; -- Last command
                                                else
-                                                       -- We are at init at the moment
-                                                       lxmaster_state_s         <= ST_READY; -- Sync goes inactive for a cycle
+                                                       -- Begin transmission of next data
+                                                       lxmaster_loaded_data_s   <= ram_data_o_s;
+                                                       lxmaster_sync_s          <= '1'; -- Transferring data next cycle
+                                                       lxmaster_data_counter_s  <= 0; -- Reset counter
+                                                       lxmaster_state_s         <= ST_XFER; --Go to transfer loop
                                                end if;
 
                                        else
-                                               if lxmaster_data_counter_r /= x"6" then
+                                               -- Sync goes inactive to signalize termination if we're on last message
+                                               if lxmaster_data_counter_r /= 6 or lxmaster_num_data_r /= x"00" then
                                                        lxmaster_sync_s          <= '1';
                                                else
                                                  lxmaster_sync_last_bit_s <= '1';
@@ -257,11 +297,15 @@ transmitter_update:
                                        end if;
 
                                when ST_END =>
-                                       if lxmaster_frame_counter_s = (frame_length_c - 1) then
+                                       if lxmaster_frame_counter_s < 2 then
                                                -- Initialize first step
                                                lxmaster_state_s           <= ST_INIT;
                                                ram_addr_s                 <= lxmaster_register_in_s & x"00";
                                                ram_en_s                   <= '1';
+                                               -- Watchdog - make sure we read 0 if not kicked
+                                               if lxmaster_wdog_counter_s = (wdog_length_c - 1) then
+                                                       lxmaster_ram_reset_s     <= '1';
+                                               end if;
                                        end if;
 
                        end case;
@@ -279,37 +323,67 @@ state:
                wait until clk_i'event and clk_i = '1';
 
                -- State update
-               ram_addr_r                   <= ram_addr_s;
-               lxmaster_state_r             <= lxmaster_state_s;
-               lxmaster_loaded_data_r       <= lxmaster_loaded_data_s;
-               lxmaster_data_counter_r      <= lxmaster_data_counter_s;
-               lxmaster_num_data_r          <= lxmaster_num_data_s;
-               lxmaster_not_last_word_r     <= lxmaster_not_last_word_s;
-               lxmaster_crc_reg_r           <= lxmaster_crc_reg_s;
+               ram_addr_r                     <= ram_addr_s;
+               lxmaster_state_r               <= lxmaster_state_s;
+               lxmaster_loaded_data_r         <= lxmaster_loaded_data_s;
+               lxmaster_data_counter_r        <= lxmaster_data_counter_s;
+               lxmaster_num_data_r            <= lxmaster_num_data_s;
+               lxmaster_crc_reg_r             <= lxmaster_crc_reg_s;
+               lxmaster_msg_counter_r         <= lxmaster_msg_counter_s;
+               lxmaster_last_word_r           <= lxmaster_last_word_s;
 
                -- Increment counter
                if reset_i = '1' then
-                       lxmaster_frame_counter_s   <= (frame_length_c - 1);
-                       lxmaster_register_in_s     <= '0';
-                       lxmaster_register_out_s    <= '0';
+
+                       lxmaster_frame_counter_s     <= 1;
+                       lxmaster_wdog_counter_s      <= 0;
+                       lxmaster_register_in_s       <= '0';
+                       lxmaster_register_out_s      <= (others => '0');
+                       lxmaster_last_word_r         <= '1';
+                       lxmaster_cycle_limit_r       <= std_logic_vector(to_unsigned(frame_length_c,
+                                                       lxmaster_cycle_limit_r'length));
+
                else
 
                        if register_we_i = '1' then
-                               lxmaster_register_in_s   <= register_i;
+                               lxmaster_register_in_s     <= register_i;
+                       end if;
+
+                       if lxmaster_frame_counter_s < 2 then
+                               lxmaster_register_out_s(0) <= lxmaster_register_in_s;
+                               lxmaster_frame_counter_s   <= to_integer(unsigned(lxmaster_cycle_limit_r));
+                       else
+                               lxmaster_frame_counter_s   <= lxmaster_frame_counter_s - 1;
                        end if;
 
-                       if lxmaster_frame_counter_s = (frame_length_c - 1) then
-                               lxmaster_register_out_s  <= lxmaster_register_in_s;
-                               lxmaster_frame_counter_s <= 0;
+                       if wdog_we_i = '1' and wdog_i = '1' then
+                               lxmaster_wdog_counter_s     <= 0;
+                               lxmaster_register_out_s(1)  <= '0';
+                       elsif lxmaster_wdog_counter_s /= (wdog_length_c - 1) then
+                               lxmaster_wdog_counter_s     <= lxmaster_wdog_counter_s + 1;
+                               lxmaster_register_out_s(1)  <= '0';
                        else
-                               lxmaster_frame_counter_s <= lxmaster_frame_counter_s + 1;
+                               lxmaster_register_out_s(1)  <= '1';
+                       end if;
+
+                       if cycle_reg_we_i = '1' then
+                               lxmaster_cycle_limit_r      <= cycle_reg_i;
                        end if;
 
                end if;
 
-               lxmaster_sync_r              <= lxmaster_sync_s;
-               lxmaster_sync_last_bit_r     <= lxmaster_sync_last_bit_s;
+               lxmaster_sync_r                 <= lxmaster_sync_s;
+               lxmaster_sync_last_bit_r        <= lxmaster_sync_last_bit_s;
+
+       end process;
+
+update_outputs:
+       process
+       begin
+               wait until clk_i'event and clk_i = '0';
 
+               sync_r  <= sync_s;
+               mosi_r  <= mosi_s;
        end process;
 
 end Behavioral;