]> rtime.felk.cvut.cz Git - fpga/lx-cpu1/lx-rocon.git/blob - hw/lxmaster_transmitter.vhd
Update LX Master transmitter structure layout
[fpga/lx-cpu1/lx-rocon.git] / hw / lxmaster_transmitter.vhd
1 library ieee;
2 use ieee.std_logic_1164.all;
3 use ieee.std_logic_unsigned.all;
4 use ieee.numeric_std.all;
5 use work.util_pkg.all;
6 use work.lx_rocon_pkg.all;
7
8 -- LX Master (Transmitter)
9 entity lxmaster_transmitter is
10         port
11         (
12                 clk_i             : in std_logic;
13                 reset_i           : in std_logic;
14                 -- Transmision
15                 clock_o           : out std_logic;
16                 mosi_o            : out std_logic;
17                 sync_o            : out std_logic;
18                 -- Register
19                 register_i        : in std_logic;
20                 register_o        : out std_logic;
21                 register_we_i     : in std_logic;
22                 -- BRAM access
23                 mem_clk_i         : in std_logic;
24     mem_en_i          : in std_logic;
25     mem_we_i          : in std_logic_vector(1 downto 0);
26     mem_addr_i        : in std_logic_vector(8 downto 0);
27     mem_data_i        : in std_logic_vector(15 downto 0);
28     mem_data_o        : out std_logic_vector(15 downto 0)
29         );
30 end lxmaster_transmitter;
31
32 architecture Behavioral of lxmaster_transmitter is
33
34         -- Types
35         type state_t is (ST_INIT, ST_READY, ST_XFER, ST_CRC, ST_END);
36         constant frame_length_c         : positive := 2500; -- 50 MHz -> 20 kHz
37         constant msg_max_count_c        : positive := 8;
38         -- RAM Access (both ARM and Tumbl)
39         signal ram_en_s                 : std_logic;
40         signal ram_rst_s                : std_logic;
41         --
42         signal ram_addr_s               : std_logic_vector(8 downto 0);
43         signal ram_addr_r               : std_logic_vector(8 downto 0);
44         signal ram_data_o_s             : std_logic_vector(15 downto 0);
45         -- State
46         signal lxmaster_state_s         : state_t;
47         signal lxmaster_state_r         : state_t;
48         signal lxmaster_not_last_word_s : std_logic;
49         signal lxmaster_not_last_word_r : std_logic;
50         -- Data
51         signal lxmaster_num_data_s      : std_logic_vector(7 downto 0); -- If 0 then the peripheral is not active this cycle
52         signal lxmaster_num_data_r      : std_logic_vector(7 downto 0);
53         signal lxmaster_loaded_data_s   : std_logic_vector(15 downto 0);
54         signal lxmaster_loaded_data_r   : std_logic_vector(15 downto 0);
55         signal lxmaster_data_counter_s  : std_logic_vector(3 downto 0); -- Shift: 0 - 15
56         signal lxmaster_data_counter_r  : std_logic_vector(3 downto 0);
57         -- Transmission
58         signal lxmaster_sync_s          : std_logic;
59         signal lxmaster_sync_r          : std_logic;
60         signal lxmaster_sync_last_bit_s : std_logic;
61         signal lxmaster_sync_last_bit_r : std_logic;
62         -- Counters
63         signal lxmaster_frame_counter_s : natural range 0 to (frame_length_c-1);
64         signal lxmaster_msg_counter_s   : natural range 0 to (msg_max_count_c-1);
65         signal lxmaster_msg_counter_r   : natural range 0 to (msg_max_count_c-1);
66         -- CRC
67         signal lxmaster_crc_data_s      : std_logic;
68         signal lxmaster_crc_reset_s     : std_logic;
69         signal lxmaster_crc_out_s       : std_logic_vector(7 downto 0);
70         signal lxmaster_crc_reg_s       : std_logic_vector(7 downto 0);
71         signal lxmaster_crc_reg_r       : std_logic_vector(7 downto 0);
72         -- RAM reset
73         signal lxmaster_ram_reset_s     : std_logic;
74         -- Register
75         -- Bit 0: Transmitter - use first or second buffer
76         signal lxmaster_register_in_s   : std_logic;
77         signal lxmaster_register_out_s  : std_logic;
78
79 begin
80
81         -- Directly route out some signals
82         clock_o              <= clk_i; -- Cannot mix with logic
83         sync_o               <= not lxmaster_sync_r; -- Active in log. 0
84         mosi_o               <= '1' when lxmaster_sync_r = '0' and lxmaster_sync_last_bit_r = '0'
85                                  else lxmaster_crc_reg_r(0) when lxmaster_state_r = ST_CRC
86                                  else lxmaster_loaded_data_r(0);
87         -- CRC
88         lxmaster_crc_reg_s   <= '0' & lxmaster_crc_reg_r(7 downto 1) when lxmaster_state_r = ST_CRC else lxmaster_crc_out_s;
89         lxmaster_crc_data_s  <= '1' when lxmaster_state_r = ST_CRC else lxmaster_loaded_data_r(0);
90         lxmaster_crc_reset_s <= '1' when lxmaster_state_r = ST_READY or reset_i = '1' else '0';
91
92         -- Register
93         register_o           <= lxmaster_register_out_s;
94
95 ram: xilinx_dualport_bram_write_first
96         generic map
97         (
98                 we_width      => 2,
99                 byte_width    => 8,
100                 address_width => 9
101         )
102         port map
103         (
104                 -- Internal
105                 clka  => clk_i,
106                 rsta  => ram_rst_s,
107                 ena   => ram_en_s,
108                 wea   => (others => '0'),
109                 addra => ram_addr_s,
110                 dina  => (others => '0'),
111                 douta => ram_data_o_s,
112                 -- External
113                 clkb  => mem_clk_i,
114                 rstb  => '0',
115                 enb   => mem_en_i,
116                 web   => mem_we_i,
117                 addrb => mem_addr_i,
118                 dinb  => mem_data_i,
119                 doutb => mem_data_o
120         );
121
122 crc_out: crc
123         port map
124         (
125                 clk_i   => clk_i,
126                 reset_i => lxmaster_crc_reset_s,
127                 input_i => lxmaster_crc_data_s,
128                 crc_o   => lxmaster_crc_out_s
129         );
130
131         ram_rst_s <= reset_i or lxmaster_ram_reset_s;
132
133 -- Update
134 -- TODO: Maybe some exception handling (overflows etc.)
135 transmitter_update:
136         process (ram_data_o_s, ram_addr_r, lxmaster_state_r, lxmaster_loaded_data_r, lxmaster_num_data_r, lxmaster_not_last_word_r,
137                  lxmaster_data_counter_r, reset_i, lxmaster_frame_counter_s, lxmaster_register_in_s)
138                 variable ram_addr_v : std_logic_vector(8 downto 0);
139         begin
140
141                 -- Defaults
142                 lxmaster_ram_reset_s               <= '0';
143                 lxmaster_sync_last_bit_s           <= '0';
144                 -- Defaults of state variables (no change)
145                 ram_addr_s                         <= ram_addr_r;
146                 lxmaster_state_s                   <= lxmaster_state_r;
147                 lxmaster_loaded_data_s             <= lxmaster_loaded_data_r;
148                 lxmaster_data_counter_s            <= lxmaster_data_counter_r;
149                 lxmaster_num_data_s                <= lxmaster_num_data_r;
150                 lxmaster_not_last_word_s           <= lxmaster_not_last_word_r;
151                 lxmaster_msg_counter_s             <= lxmaster_msg_counter_r;
152
153                 if reset_i = '1' then
154                         lxmaster_num_data_s              <= x"00";
155                         lxmaster_loaded_data_s           <= x"0000";
156                         lxmaster_state_s                 <= ST_END;
157                         lxmaster_sync_s                  <= '0';
158                         --
159                         ram_addr_s                       <= '0' & x"00";
160                         ram_en_s                         <= '0';
161                         --
162                         lxmaster_ram_reset_s             <= '1';
163
164                 else
165
166                         -- OK, we are enabled, default values
167                         lxmaster_sync_s                  <= '0'; -- Not transferring
168                         ram_en_s                         <= '0'; -- Not reading
169
170                         case lxmaster_state_r is
171
172                                 when ST_INIT =>
173                                         -- We just read number of commands
174                                         if ram_data_o_s(7 downto 0) = x"00" then
175                                                 lxmaster_state_s           <= ST_END; --Nothing
176                                         else
177                                                 lxmaster_state_s           <= ST_READY; -- Make next read init the transfer
178                                         end if;
179
180                                         -- Prepare message counter
181                                         lxmaster_msg_counter_s       <= 0;
182
183                                         -- Regardless, write the number of data and schedule reading
184                                         ram_addr_v                   := ram_addr_r(8) & ram_data_o_s(15 downto 8); -- Update address
185                                         ram_addr_s                   <= ram_addr_v;
186                                         lxmaster_num_data_s          <= std_logic_vector(unsigned(ram_addr_v(7 downto 0)) + unsigned(ram_data_o_s(7 downto 0)));
187                                         ram_en_s                     <= '1'; -- Read
188
189                                 when ST_READY =>
190                                         -- We are ready to begin transferring
191                                         lxmaster_loaded_data_s       <= ram_data_o_s;
192                                         lxmaster_sync_s              <= '1'; -- Transferring data next cycle
193                                         lxmaster_data_counter_s      <= x"0"; -- Reset counter
194                                         lxmaster_state_s             <= ST_XFER; --Go to transfer loop
195                                         lxmaster_not_last_word_s     <= '0'; -- Not last word
196
197                                 when ST_XFER =>
198                                         lxmaster_loaded_data_s       <= '0' & lxmaster_loaded_data_r(15 downto 1); -- Shift it
199                                         lxmaster_sync_s              <= '1'; -- Transferring data next cycle
200
201                                         if lxmaster_data_counter_r = x"E" and ram_addr_r(7 downto 0) /= lxmaster_num_data_r then
202                                                 -- At 14th bit, we need to read from RAM if more words are to come
203                                                 ram_addr_s                 <= ram_addr_r + 1; -- Update address
204                                                 lxmaster_data_counter_s    <= lxmaster_data_counter_r + 1; -- Increment
205                                                 ram_en_s                   <= '1'; -- Read
206                                                 lxmaster_not_last_word_s   <= '1';
207                                         elsif lxmaster_data_counter_r = x"F" then
208                                                 -- At 15th bit, we either stop if ram_addr_r equals lxmaster_num_data_r (wasn't updated so it would not overflow)
209                                                 if ram_addr_r(7 downto 0) = lxmaster_num_data_r and lxmaster_not_last_word_r = '0' then
210                                                         lxmaster_state_s         <= ST_CRC;
211                                                         lxmaster_data_counter_s  <= x"0";
212                                                 else
213                                                         lxmaster_loaded_data_s   <= ram_data_o_s;
214                                                         lxmaster_data_counter_s  <= x"0";
215                                                         lxmaster_not_last_word_s <= '0';
216                                                 end if;
217                                         else
218                                                 -- Increment
219                                                 lxmaster_data_counter_s    <= lxmaster_data_counter_r + 1;
220                                         end if;
221
222                                 when ST_CRC =>
223
224                                         -- Check if this is last command, first read one more
225                                         if lxmaster_data_counter_r = x"0" then
226                                                 if lxmaster_msg_counter_r = (msg_max_count_c - 1) then
227                                                         lxmaster_ram_reset_s     <= '1'; -- Make sure we read 0 if we are on the last message
228                                                 else
229                                                         lxmaster_msg_counter_s  <= lxmaster_msg_counter_r + 1;
230                                                 end if;
231
232                                                 ram_addr_s                 <= ram_addr_r(8) & std_logic_vector(to_unsigned(lxmaster_msg_counter_r + 1, ram_addr_r'length - 1)); -- Update address
233                                                 ram_en_s                   <= '1'; -- Read
234
235                                         elsif lxmaster_data_counter_r = x"1" then
236
237                                                 if ram_data_o_s(15 downto 8) >= msg_max_count_c then -- Need to read first command, make sure it's valid
238                                                         ram_addr_v               := ram_addr_r(8) & ram_data_o_s(15 downto 8); -- Update address
239                                                         ram_addr_s               <= ram_addr_v;
240                                                         lxmaster_num_data_s      <= std_logic_vector(unsigned(ram_addr_v(7 downto 0)) + unsigned(ram_data_o_s(7 downto 0)));
241                                                         ram_en_s                 <= '1'; -- Read
242                                                 else
243                                                         lxmaster_num_data_s      <= x"00"; -- Signalize termination
244                                                 end if;
245
246                                         end if;
247
248                                         if lxmaster_data_counter_r = x"7" then -- Ending
249                                                 lxmaster_data_counter_s    <= x"0";
250
251                                                 if lxmaster_num_data_r(7 downto 0) = x"00" then
252                                                         lxmaster_state_s         <= ST_END; -- Last command
253                                                 else
254                                                         -- Begin transmission of next data
255                                                         lxmaster_loaded_data_s   <= ram_data_o_s;
256                                                         lxmaster_sync_s          <= '1'; -- Transferring data next cycle
257                                                         lxmaster_data_counter_s  <= x"0"; -- Reset counter
258                                                         lxmaster_state_s         <= ST_XFER; --Go to transfer loop
259                                                         lxmaster_not_last_word_s <= '0'; -- Not last word
260                                                 end if;
261
262                                         else
263                                                 if lxmaster_data_counter_r /= x"6" then
264                                                         lxmaster_sync_s          <= '1'; -- Sync goes inactive to signalize termination
265                                                 else
266                                                   lxmaster_sync_last_bit_s <= '1';
267                                                 end if;
268
269                                                 lxmaster_data_counter_s    <= lxmaster_data_counter_r + 1; -- Increment
270                                         end if;
271
272                                 when ST_END =>
273                                         if lxmaster_frame_counter_s = (frame_length_c - 1) then
274                                                 -- Initialize first step
275                                                 lxmaster_state_s           <= ST_INIT;
276                                                 ram_addr_s                 <= lxmaster_register_in_s & x"00";
277                                                 ram_en_s                   <= '1';
278                                         end if;
279
280                         end case;
281
282                 end if;
283
284         end process;
285
286 -- This function toggles outputs directly, make sure the outputs
287 -- are updated with clock to minimize phase.
288 state:
289         process
290         begin
291
292                 wait until clk_i'event and clk_i = '1';
293
294                 -- State update
295                 ram_addr_r                   <= ram_addr_s;
296                 lxmaster_state_r             <= lxmaster_state_s;
297                 lxmaster_loaded_data_r       <= lxmaster_loaded_data_s;
298                 lxmaster_data_counter_r      <= lxmaster_data_counter_s;
299                 lxmaster_num_data_r          <= lxmaster_num_data_s;
300                 lxmaster_not_last_word_r     <= lxmaster_not_last_word_s;
301                 lxmaster_crc_reg_r           <= lxmaster_crc_reg_s;
302                 lxmaster_msg_counter_r       <= lxmaster_msg_counter_s;
303
304                 -- Increment counter
305                 if reset_i = '1' then
306                         lxmaster_frame_counter_s   <= (frame_length_c - 1);
307                         lxmaster_register_in_s     <= '0';
308                         lxmaster_register_out_s    <= '0';
309                 else
310
311                         if register_we_i = '1' then
312                                 lxmaster_register_in_s   <= register_i;
313                         end if;
314
315                         if lxmaster_frame_counter_s = (frame_length_c - 1) then
316                                 lxmaster_register_out_s  <= lxmaster_register_in_s;
317                                 lxmaster_frame_counter_s <= 0;
318                         else
319                                 lxmaster_frame_counter_s <= lxmaster_frame_counter_s + 1;
320                         end if;
321
322                 end if;
323
324                 lxmaster_sync_r              <= lxmaster_sync_s;
325                 lxmaster_sync_last_bit_r     <= lxmaster_sync_last_bit_s;
326
327         end process;
328
329 end Behavioral;