]> rtime.felk.cvut.cz Git - fpga/lx-cpu1/lx-rocon.git/blob - hw/lxmaster_transmitter.vhd
Fix LX Master transmission, update PXMC for new structure
[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_last_word_s     : std_logic;
49         signal lxmaster_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_XFER 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_msg_counter_r,
137                  lxmaster_last_word_r, 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_msg_counter_s             <= lxmaster_msg_counter_r;
151                 lxmaster_last_word_s               <= lxmaster_last_word_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                         lxmaster_last_word_s             <= '0';
159                         --
160                         ram_addr_s                       <= '0' & x"00";
161                         ram_en_s                         <= '0';
162                         --
163                         lxmaster_ram_reset_s             <= '1';
164
165                 else
166
167                         -- OK, we are enabled, default values
168                         lxmaster_sync_s                  <= '0'; -- Not transferring
169                         ram_en_s                         <= '0'; -- Not reading
170
171                         case lxmaster_state_r is
172
173                                 when ST_INIT =>
174                                         -- We just read number of commands
175                                         if ram_data_o_s(7 downto 0) = x"00" then
176                                                 lxmaster_state_s           <= ST_END; --Nothing
177                                         else
178                                                 lxmaster_state_s           <= ST_READY; -- Make next read init the transfer
179                                         end if;
180
181                                         -- Prepare message counter
182                                         lxmaster_msg_counter_s       <= 0;
183
184                                         -- Regardless, write the number of data and schedule reading
185                                         ram_addr_v                   := ram_addr_r(8) & ram_data_o_s(15 downto 8); -- Update address
186                                         ram_addr_s                   <= ram_addr_v;
187                                         lxmaster_num_data_s          <= std_logic_vector(unsigned(ram_addr_v(7 downto 0)) + unsigned(ram_data_o_s(7 downto 0)));
188                                         ram_en_s                     <= '1'; -- Read
189
190                                 when ST_READY =>
191                                         -- We are ready to begin transferring
192                                         lxmaster_loaded_data_s       <= ram_data_o_s;
193                                         lxmaster_sync_s              <= '1'; -- Transferring data next cycle
194                                         lxmaster_data_counter_s      <= x"0"; -- Reset counter
195                                         lxmaster_state_s             <= ST_XFER; --Go to transfer loop
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" then
202                                                 lxmaster_data_counter_s    <= lxmaster_data_counter_r + 1; -- Increment
203
204                                                 if (ram_addr_r(7 downto 0) + 1) /= lxmaster_num_data_r then
205                                                         -- At 14th bit, we need to read from RAM if more words are to come
206                                                         ram_addr_s                 <= ram_addr_r(8) & (ram_addr_r(7 downto 0) + 1); -- Update address
207                                                         ram_en_s                   <= '1'; -- Read
208                                                         lxmaster_last_word_s       <= '0';
209                                                 else
210                                                         lxmaster_last_word_s       <= '1';
211                                                 end if;
212
213                                         elsif lxmaster_data_counter_r = x"F" then
214                                                 -- At 15th bit, we either stop if ram_addr_r equals lxmaster_num_data_r
215                                                 if lxmaster_last_word_r = '1' then
216                                                         lxmaster_state_s         <= ST_CRC;
217                                                         lxmaster_data_counter_s  <= x"0";
218                                                 else
219                                                         lxmaster_loaded_data_s   <= ram_data_o_s;
220                                                         lxmaster_data_counter_s  <= x"0";
221                                                 end if;
222                                         else
223                                                 -- Increment
224                                                 lxmaster_data_counter_s    <= lxmaster_data_counter_r + 1;
225                                         end if;
226
227                                 when ST_CRC =>
228
229                                         -- Check if this is last command, first read one more
230                                         if lxmaster_data_counter_r = x"0" then
231                                                 if lxmaster_msg_counter_r = (msg_max_count_c - 1) then
232                                                         lxmaster_ram_reset_s     <= '1'; -- Make sure we read 0 if we are on the last message
233                                                 else
234                                                         lxmaster_msg_counter_s  <= lxmaster_msg_counter_r + 1;
235                                                 end if;
236
237                                                 ram_addr_s                 <= ram_addr_r(8) & std_logic_vector(to_unsigned(lxmaster_msg_counter_r + 1, ram_addr_r'length - 1)); -- Update address
238                                                 ram_en_s                   <= '1'; -- Read
239
240                                         elsif lxmaster_data_counter_r = x"1" then
241
242                                                 if ram_data_o_s(15 downto 8) >= msg_max_count_c then -- Need to read first command, make sure it's valid
243                                                         ram_addr_v               := ram_addr_r(8) & ram_data_o_s(15 downto 8); -- Update address
244                                                         ram_addr_s               <= ram_addr_v;
245                                                         lxmaster_num_data_s      <= std_logic_vector(unsigned(ram_addr_v(7 downto 0)) + unsigned(ram_data_o_s(7 downto 0)));
246                                                         ram_en_s                 <= '1'; -- Read
247                                                 else
248                                                         lxmaster_num_data_s      <= x"00"; -- Signalize termination
249                                                 end if;
250
251                                         end if;
252
253                                         if lxmaster_data_counter_r = x"7" then -- Ending
254                                                 lxmaster_data_counter_s    <= x"0";
255
256                                                 if lxmaster_num_data_r(7 downto 0) = x"00" then
257                                                         lxmaster_state_s         <= ST_END; -- Last command
258                                                 else
259                                                         -- Begin transmission of next data
260                                                         lxmaster_loaded_data_s   <= ram_data_o_s;
261                                                         lxmaster_sync_s          <= '1'; -- Transferring data next cycle
262                                                         lxmaster_data_counter_s  <= x"0"; -- Reset counter
263                                                         lxmaster_state_s         <= ST_XFER; --Go to transfer loop
264                                                 end if;
265
266                                         else
267                                                 if lxmaster_data_counter_r /= x"6" then
268                                                         lxmaster_sync_s          <= '1'; -- Sync goes inactive to signalize termination
269                                                 else
270                                                   lxmaster_sync_last_bit_s <= '1';
271                                                 end if;
272
273                                                 lxmaster_data_counter_s    <= lxmaster_data_counter_r + 1; -- Increment
274                                         end if;
275
276                                 when ST_END =>
277                                         if lxmaster_frame_counter_s = (frame_length_c - 1) then
278                                                 -- Initialize first step
279                                                 lxmaster_state_s           <= ST_INIT;
280                                                 ram_addr_s                 <= lxmaster_register_in_s & x"00";
281                                                 ram_en_s                   <= '1';
282                                         end if;
283
284                         end case;
285
286                 end if;
287
288         end process;
289
290 -- This function toggles outputs directly, make sure the outputs
291 -- are updated with clock to minimize phase.
292 state:
293         process
294         begin
295
296                 wait until clk_i'event and clk_i = '1';
297
298                 -- State update
299                 ram_addr_r                   <= ram_addr_s;
300                 lxmaster_state_r             <= lxmaster_state_s;
301                 lxmaster_loaded_data_r       <= lxmaster_loaded_data_s;
302                 lxmaster_data_counter_r      <= lxmaster_data_counter_s;
303                 lxmaster_num_data_r          <= lxmaster_num_data_s;
304                 lxmaster_crc_reg_r           <= lxmaster_crc_reg_s;
305                 lxmaster_msg_counter_r       <= lxmaster_msg_counter_s;
306                 lxmaster_last_word_r         <= lxmaster_last_word_s;
307
308                 -- Increment counter
309                 if reset_i = '1' then
310                         lxmaster_frame_counter_s   <= (frame_length_c - 1);
311                         lxmaster_register_in_s     <= '0';
312                         lxmaster_register_out_s    <= '0';
313                 else
314
315                         if register_we_i = '1' then
316                                 lxmaster_register_in_s   <= register_i;
317                         end if;
318
319                         if lxmaster_frame_counter_s = (frame_length_c - 1) then
320                                 lxmaster_register_out_s  <= lxmaster_register_in_s;
321                                 lxmaster_frame_counter_s <= 0;
322                         else
323                                 lxmaster_frame_counter_s <= lxmaster_frame_counter_s + 1;
324                         end if;
325
326                 end if;
327
328                 lxmaster_sync_r              <= lxmaster_sync_s;
329                 lxmaster_sync_last_bit_r     <= lxmaster_sync_last_bit_s;
330
331         end process;
332
333 end Behavioral;