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