]> 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 d98f7e46a7bb68923a3d0a60389f5b322a97af6f..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;
@@ -19,6 +22,10 @@ entity lxmaster_transmitter is
                register_i        : in 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;
@@ -39,10 +46,9 @@ architecture Behavioral of lxmaster_transmitter is
        constant frame_length_c         : positive := 2500; -- 50 MHz -> 20 kHz
        constant wdog_length_c          : positive := 2500000; -- 50 ms
        constant msg_max_count_c        : positive := 8;
-       -- RAM Access (both ARM and Tumbl)
+       -- 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);
@@ -56,8 +62,8 @@ architecture Behavioral of lxmaster_transmitter is
        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;
@@ -65,7 +71,8 @@ architecture Behavioral of lxmaster_transmitter is
        signal lxmaster_sync_last_bit_r : std_logic;
        -- Counters
        signal lxmaster_wdog_counter_s  : natural range 0 to (wdog_length_c-1);
-       signal lxmaster_frame_counter_s : natural range 0 to (frame_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
@@ -81,29 +88,40 @@ architecture Behavioral of lxmaster_transmitter is
        -- Bit 1: Watchdog not kicked (O)
        signal lxmaster_register_in_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_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
        (
@@ -195,14 +213,14 @@ transmitter_update:
                                        -- 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
 
                                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" then
+                                       if lxmaster_data_counter_r = 14 then
                                                lxmaster_data_counter_s    <= lxmaster_data_counter_r + 1; -- Increment
 
                                                if (ram_addr_r(7 downto 0) + 1) /= lxmaster_num_data_r then
@@ -214,14 +232,14 @@ transmitter_update:
                                                        lxmaster_last_word_s       <= '1';
                                                end if;
 
-                                       elsif lxmaster_data_counter_r = x"F" then
+                                       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_data_counter_s  <= 0;
                                                end if;
                                        else
                                                -- Increment
@@ -231,7 +249,7 @@ transmitter_update:
                                when ST_CRC =>
 
                                        -- Check if this is last command, first read one more
-                                       if lxmaster_data_counter_r = x"0" then
+                                       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
@@ -241,7 +259,7 @@ transmitter_update:
                                                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
+                                       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
@@ -254,22 +272,23 @@ 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
                                                        -- 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  <= x"0"; -- Reset counter
+                                                       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
-                                                       lxmaster_sync_s          <= '1'; -- Sync goes inactive to signalize termination
+                                               -- 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';
                                                end if;
@@ -278,7 +297,7 @@ 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";
@@ -315,22 +334,26 @@ state:
 
                -- Increment counter
                if reset_i = '1' then
-                       lxmaster_frame_counter_s     <= (frame_length_c - 1);
+
+                       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;
                        end if;
 
-                       if lxmaster_frame_counter_s = (frame_length_c - 1) then
+                       if lxmaster_frame_counter_s < 2 then
                                lxmaster_register_out_s(0) <= lxmaster_register_in_s;
-                               lxmaster_frame_counter_s   <= 0;
+                               lxmaster_frame_counter_s   <= to_integer(unsigned(lxmaster_cycle_limit_r));
                        else
-                               lxmaster_frame_counter_s   <= lxmaster_frame_counter_s + 1;
+                               lxmaster_frame_counter_s   <= lxmaster_frame_counter_s - 1;
                        end if;
 
                        if wdog_we_i = '1' and wdog_i = '1' then
@@ -343,6 +366,10 @@ state:
                                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;
@@ -350,4 +377,13 @@ state:
 
        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;