]> rtime.felk.cvut.cz Git - fpga/lx-cpu1/lx-rocon.git/blob - hw/lx-fncapprox/lx_fncapprox.vhd
26732a7ac71ccb52c4593814ace8ef76735caea8
[fpga/lx-cpu1/lx-rocon.git] / hw / lx-fncapprox / lx_fncapprox.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.lx_fncapprox_pkg.all;
6
7 -- IRC bus interconnect
8 entity lx_fncapprox is
9         port
10         (
11                 clk_i        : in std_logic;
12                 reset_i      : in std_logic;
13                 -- Data bus
14                 address_i    : in std_logic_vector(4 downto 0);
15                 next_ce_i    : in std_logic;
16                 data_i       : in std_logic_vector(31 downto 0);
17                 data_o       : out std_logic_vector(31 downto 0);
18                 --
19                 bls_i        : in std_logic_vector(3 downto 0)
20         );
21 end lx_fncapprox;
22
23 -- reciproc ...  a + (b + c * x) * x
24 -- sin      ...  a + (b + c * x) * x
25
26
27 architecture Behavioral of lx_fncapprox is
28
29         -- Types
30
31         type state_fncapprox_t is (ST_IDLE, ST_RECI0, ST_RECI1,
32                          ST_SIN0, ST_SIN1, ST_COS0, ST_COS1);
33
34         -- Signals
35
36         constant approx_top_bits    : natural := 9;
37         constant reci_tab_bits      : natural := 8;
38         constant sin_tab_bits       : natural := 7;
39         constant approx_frac_bits   : natural := 18;
40         constant approx_tab_b_shift : natural := 8;
41         constant approx_tab_c_shift : natural := 25;
42
43         constant approx_lo_used_bit : natural := 31 - approx_top_bits - approx_frac_bits + 1;
44
45         signal ce_s                 : std_logic;
46         signal address_s            : std_logic_vector(4 downto 0);
47
48         signal argument_s           : std_logic_vector(31 downto 0);
49         signal argument_r           : std_logic_vector(31 downto 0);
50
51         signal dsp48_p_s            : std_logic_vector(47 downto 0);
52         signal dsp48_a_s            : std_logic_vector(17 downto 0);
53         signal dsp48_b_s            : std_logic_vector(17 downto 0);
54         signal dsp48_c_s            : std_logic_vector(47 downto 0);
55         signal dsp48_ce_s           : std_logic;
56
57         signal state_tab_s          : state_fncapprox_t;
58         signal state_tab_r          : state_fncapprox_t;
59         signal state_dsp48_r        : state_fncapprox_t;
60         signal state_regw_r         : state_fncapprox_t;
61
62         signal reci_tab_idx_s       : std_logic_vector(reci_tab_bits-1 downto 0);
63         signal approx_frac_s        : std_logic_vector(approx_frac_bits-1 downto 0);
64         signal approx_frac_r        : std_logic_vector(approx_frac_bits-1 downto 0);
65         signal reci_tab_a_data_s    : std_logic_vector(35 downto 0);
66         signal reci_tab_a_data_r    : std_logic_vector(35 downto 0);
67         signal reci_tab_bc_data_s   : std_logic_vector(35 downto 0);
68         signal reci_tab_bc_data_r   : std_logic_vector(35 downto 0);
69
70         signal sin_tab_idx_s        : std_logic_vector(sin_tab_bits-1 downto 0);
71         signal sin_tab_a_data_s     : std_logic_vector(35 downto 0);
72         signal sin_tab_bc_data_s    : std_logic_vector(35 downto 0);
73
74         signal approx_tab_b_shifted_r : std_logic_vector(47 downto 0);
75         signal reci_tab_a_shifted_r : std_logic_vector(47 downto 0);
76         signal frac_c_mult_s        : std_logic_vector(47 downto 0);
77         signal frac2_bc_mult_s      : std_logic_vector(47 downto 0);
78
79         signal reci_result_s        : std_logic_vector(31 downto 0);
80         signal reci_result_r        : std_logic_vector(31 downto 0);
81         signal sin_result_s         : std_logic_vector(31 downto 0);
82         signal sin_result_r         : std_logic_vector(31 downto 0);
83         signal cos_result_s         : std_logic_vector(31 downto 0);
84         signal cos_result_r         : std_logic_vector(31 downto 0);
85
86         signal reci_tab_a_stb_s     : std_logic;
87         signal reci_tab_bc_stb_s    : std_logic;
88         signal sin_tab_a_stb_s      : std_logic;
89         signal sin_tab_bc_stb_s     : std_logic;
90
91         signal sin_cos_force_one_s  : std_logic;
92         signal sin_cos_force_one_r  : std_logic;
93         signal sin_cos_force_one_r2 : std_logic;
94         signal sin_cos_negate_out_s : std_logic;
95         signal sin_cos_negate_out_r : std_logic;
96         signal sin_cos_negate_out_r2: std_logic;
97 begin
98
99 approx_dsp48: lx_fncapprox_dsp48
100         port map (
101                 P         => dsp48_p_s,
102                 A         => dsp48_a_s,
103                 B         => dsp48_b_s,
104                 C         => dsp48_c_s,
105                 CLK       => clk_i,
106                 CE        => dsp48_ce_s
107         );
108
109 reci_tab_a : rom_table
110         generic map (
111                 data_width => 36,
112                 addr_width => reci_tab_bits,
113                 init_file  => "reci_tab_a.lut"
114         )
115         port map
116         (
117                 clk_i  => clk_i,
118                 stb_i  => reci_tab_a_stb_s,
119                 addr_i => reci_tab_idx_s,
120                 data_o => reci_tab_a_data_s,
121                 ack_o => open
122         );
123
124 reci_tab_bc : rom_table
125         generic map (
126                 data_width => 36,
127                 addr_width => reci_tab_bits,
128                 init_file  => "reci_tab_bc.lut"
129         )
130         port map
131         (
132                 clk_i  => clk_i,
133                 stb_i  => reci_tab_bc_stb_s,
134                 addr_i => reci_tab_idx_s,
135                 data_o => reci_tab_bc_data_s,
136                 ack_o => open
137         );
138
139 sin_tab_a : rom_table
140         generic map (
141                 data_width => 36,
142                 addr_width => sin_tab_bits,
143                 init_file  => "sin_tab_a.lut"
144         )
145         port map
146         (
147                 clk_i  => clk_i,
148                 stb_i  => sin_tab_a_stb_s,
149                 addr_i => sin_tab_idx_s,
150                 data_o => sin_tab_a_data_s,
151                 ack_o => open
152         );
153
154 sin_tab_bc : rom_table
155         generic map (
156                 data_width => 36,
157                 addr_width => sin_tab_bits,
158                 init_file  => "sin_tab_bc.lut"
159         )
160         port map
161         (
162                 clk_i  => clk_i,
163                 stb_i  => sin_tab_bc_stb_s,
164                 addr_i => sin_tab_idx_s,
165                 data_o => sin_tab_bc_data_s,
166                 ack_o => open
167         );
168
169 wire_in_and_next_state:
170         process(next_ce_i, ce_s, bls_i, address_i, data_i, state_tab_r, argument_r)
171         begin
172                 -- Incoming bus request
173                 if (next_ce_i = '1') and (bls_i(0) = '1') then
174                         argument_s <= data_i;
175                         if address_i(4 downto 0) = "00001" then
176                                 state_tab_s <= ST_RECI0;
177                         elsif address_i(4 downto 0) = "00010" then
178                                 state_tab_s <= ST_SIN0;
179                         elsif address_i(4 downto 0) = "00011" then
180                                 state_tab_s <= ST_COS0;
181                         else
182                                 state_tab_s <= ST_IDLE;
183                         end if;
184                 else
185                         argument_s <= argument_r;
186                         case state_tab_r is
187                                 when ST_IDLE =>
188                                         state_tab_s <= ST_IDLE;
189                                 when ST_RECI0 =>
190                                         state_tab_s <= ST_RECI1;
191                                 when ST_RECI1 =>
192                                         state_tab_s <= ST_IDLE;
193                                 when ST_SIN0 =>
194                                         state_tab_s <= ST_SIN1;
195                                 when ST_SIN1 =>
196                                         state_tab_s <= ST_COS0;
197                                 when ST_COS0 =>
198                                         state_tab_s <= ST_COS1;
199                                 when ST_COS1 =>
200                                         state_tab_s <= ST_IDLE;
201                         end case;
202                 end if;
203         end process;
204
205 function_tables_access:
206         process(state_tab_r, argument_r)
207                 variable negate_arg_v : std_logic;
208                 variable arg_frac_is_zeros_v : std_logic;
209                 variable approx_frac_v : std_logic_vector(approx_frac_bits-1 downto 0);
210         begin
211                 -- init values
212                 reci_tab_idx_s <= (others => '-');
213                 sin_tab_idx_s <= (others => '-');
214                 approx_frac_s <= (others => '-');
215                 sin_cos_force_one_s <= '-';
216                 sin_cos_negate_out_s <= '-';
217
218                 negate_arg_v := '-';
219
220                 reci_tab_a_stb_s   <= '0';
221                 reci_tab_bc_stb_s  <= '0';
222                 sin_tab_a_stb_s    <= '0';
223                 sin_tab_bc_stb_s   <= '0';
224
225                 if argument_r(29 downto approx_lo_used_bit) = (28 - approx_lo_used_bit downto 0 => '0') then
226                         arg_frac_is_zeros_v := '1';
227                 else
228                         arg_frac_is_zeros_v := '0';
229                 end if;
230
231                 case state_tab_r is
232                         when ST_IDLE =>
233                                 null;
234
235                         when ST_RECI0 =>
236                                 reci_tab_idx_s <= argument_r(30 downto
237                                         30 - reci_tab_bits + 1);
238                                 reci_tab_bc_stb_s <= '1';
239                                 negate_arg_v := '0';
240
241                         when ST_RECI1 =>
242                                 reci_tab_idx_s <= argument_r(30 downto
243                                         30 - reci_tab_bits + 1);
244                                 reci_tab_a_stb_s <= '1';
245                                 negate_arg_v := '0';
246
247                         when ST_SIN0 =>
248                                 sin_tab_bc_stb_s <= '1';
249                                 sin_tab_a_stb_s <= '1';
250                                 negate_arg_v := argument_r(30);
251
252                         when ST_SIN1 =>
253                                 if (arg_frac_is_zeros_v = '1') and (argument_r(30) = '1') then
254                                         sin_cos_force_one_s <= '1';
255                                 else
256                                         sin_cos_force_one_s <= '0';
257                                 end if;
258
259                                 if argument_r(31) = '1' then
260                                         sin_cos_negate_out_s <= '1';
261                                 else
262                                         sin_cos_negate_out_s <= '0';
263                                 end if;
264
265                                 sin_tab_bc_stb_s <= '1';
266                                 negate_arg_v := argument_r(30);
267
268                         when ST_COS0 =>
269                                 sin_tab_bc_stb_s <= '1';
270                                 sin_tab_a_stb_s <= '1';
271                                 negate_arg_v := not argument_r(30);
272
273                         when ST_COS1 =>
274                                 if (arg_frac_is_zeros_v = '1') and (argument_r(30) = '0') then
275                                         sin_cos_force_one_s <= '1';
276                                 else
277                                         sin_cos_force_one_s <= '0';
278                                 end if;
279
280                                 if argument_r(31) /= argument_r(30) then
281                                         sin_cos_negate_out_s <= '1';
282                                 else
283                                         sin_cos_negate_out_s <= '0';
284                                 end if;
285
286                                 sin_tab_bc_stb_s <= '1';
287                                 negate_arg_v := not argument_r(30);
288                 end case;
289
290                 approx_frac_v := argument_r(31 - approx_top_bits downto
291                                 31 - approx_top_bits - approx_frac_bits + 1);
292                 approx_frac_v(approx_frac_bits - 1) := not approx_frac_v(approx_frac_bits - 1);
293
294                 if negate_arg_v = '0' then
295                         sin_tab_idx_s <= argument_r(29 downto
296                                 29 - sin_tab_bits + 1);
297                         approx_frac_s <= approx_frac_v;
298                 else
299                         sin_tab_idx_s <= not argument_r(29 downto
300                                 29 - sin_tab_bits + 1);
301                         approx_frac_s <= not approx_frac_v;
302                 end if;
303         end process;
304
305 dsp48_computation:
306         process(state_dsp48_r, approx_frac_r, dsp48_p_s,
307                 reci_tab_a_data_s, reci_tab_bc_data_s,
308                 sin_tab_a_data_s, sin_tab_bc_data_s)
309         begin
310                 dsp48_a_s <= (others => '-');
311                 dsp48_b_s <= (others => '-');
312                 dsp48_c_s <= (others => '-');
313                 dsp48_ce_s <= '0';
314
315                 case state_dsp48_r is
316                         when ST_IDLE =>
317                                 null;
318
319                         when ST_RECI0 =>
320                                 -- yl = reci_tab_a[ti];
321                                 -- yl -= ((reci_tab_b[ti] - ((reci_tab_c[ti] * xd) >> approx_tab_c_shift)) * xd) >> approx_tab_b_shift;
322
323                                 dsp48_c_s(approx_tab_c_shift - 1 downto 0) <= (others => '0');
324                                 dsp48_c_s(approx_tab_c_shift + 17 downto approx_tab_c_shift) <= reci_tab_bc_data_s(35 downto 18);
325                                 dsp48_c_s(47 downto approx_tab_c_shift + 18) <= (others => reci_tab_bc_data_s(35));
326
327                                 dsp48_a_s <= reci_tab_bc_data_s(17 downto 0);
328                                 dsp48_b_s <= approx_frac_r;
329                                 dsp48_ce_s <= '1';
330
331                         when ST_RECI1 =>
332                                 dsp48_c_s(approx_tab_b_shift - 1 downto 0) <= (others => '0');
333                                 dsp48_c_s(approx_tab_b_shift + 35 downto approx_tab_b_shift) <= reci_tab_a_data_s;
334                                 dsp48_c_s(47 downto approx_tab_b_shift + 36) <= (others => '0');
335
336                                 dsp48_a_s <= dsp48_p_s(approx_tab_c_shift + 17 downto approx_tab_c_shift);
337                                 dsp48_b_s <= approx_frac_r;
338                                 dsp48_ce_s <= '1';
339
340                         when ST_SIN0 | ST_COS0 =>
341                                 dsp48_c_s(approx_tab_c_shift - 1 downto 0) <= (others => '0');
342                                 dsp48_c_s(approx_tab_c_shift + 17 downto approx_tab_c_shift) <= sin_tab_bc_data_s(35 downto 18);
343                                 dsp48_c_s(47 downto approx_tab_c_shift + 18) <= (others => sin_tab_bc_data_s(35));
344
345                                 dsp48_a_s <= sin_tab_bc_data_s(17 downto 0);
346                                 dsp48_b_s <= approx_frac_r;
347                                 dsp48_ce_s <= '1';
348
349                         when ST_SIN1 | ST_COS1 =>
350                                 dsp48_c_s(approx_tab_b_shift - 1 downto 0) <= (others => '0');
351                                 dsp48_c_s(approx_tab_b_shift + 35 downto approx_tab_b_shift) <= sin_tab_a_data_s;
352                                 dsp48_c_s(47 downto approx_tab_b_shift + 36) <= (others => '0');
353
354                                 dsp48_a_s <= dsp48_p_s(approx_tab_c_shift + 17 downto approx_tab_c_shift);
355                                 dsp48_b_s <= approx_frac_r;
356                                 dsp48_ce_s <= '1';
357
358                 end case;
359         end process;
360
361 result_registers_write:
362         process(state_regw_r, dsp48_p_s, sin_cos_negate_out_r2, sin_cos_force_one_r2,
363                 reci_result_r, sin_result_r, cos_result_r)
364                 variable sin_cos_res_v  : std_logic_vector(31 downto 0);
365         begin
366                 reci_result_s <= reci_result_r;
367                 sin_result_s <= sin_result_r;
368                 cos_result_s <= cos_result_r;
369
370                 if sin_cos_force_one_r2 = '1' then
371                         sin_cos_res_v := (30 => '1', others => '0');
372                 else
373                         sin_cos_res_v := dsp48_p_s(approx_tab_b_shift + 35 -1 downto approx_tab_b_shift + 4 - 1);
374                 end if;
375
376                 if sin_cos_negate_out_r2 = '1' then
377                         sin_cos_res_v := std_logic_vector(-signed(sin_cos_res_v));
378                 end if;
379
380                 case state_regw_r is
381                         when ST_IDLE =>
382                                 null;
383
384                         when ST_RECI0 =>
385                                 null;
386
387                         when ST_RECI1 =>
388                                 reci_result_s <= dsp48_p_s(approx_tab_b_shift + 35 downto approx_tab_b_shift + 4);
389
390                         when ST_SIN0 =>
391                                 null;
392
393                         when ST_SIN1 =>
394                                 sin_result_s <= sin_cos_res_v;
395
396                         when ST_COS0 =>
397                                 null;
398
399                         when ST_COS1 =>
400                                 cos_result_s <= sin_cos_res_v;
401
402                 end case;
403         end process;
404
405 wire_out:
406         process(ce_s, reci_result_r, sin_result_r, cos_result_r, address_s, argument_r)
407         begin
408                 data_o <= (others => '-');
409
410                 if ce_s = '1' then
411                         if address_s(4 downto 0) = "00000" then
412                                 data_o <= x"12345678";
413                         elsif address_s(4 downto 0) = "00001" then
414                                 data_o <= reci_result_r;
415                         elsif address_s(4 downto 0) = "00010" then
416                                 data_o <= sin_result_r;
417                         elsif address_s(4 downto 0) = "00011" then
418                                 data_o <= cos_result_r;
419                         elsif address_s(4 downto 0) = "00100" then
420                                 data_o(17 downto 0) <= sin_result_r(31 downto 14);
421                                 data_o(31 downto 18) <= (others => sin_result_r(31));
422                         elsif address_s(4 downto 0) = "00101" then
423                                 data_o(17 downto 0) <= cos_result_r(31 downto 14);
424                                 data_o(31 downto 18) <= (others => cos_result_r(31));
425                         elsif address_s(4 downto 0) = "00110" then
426                                 data_o <= x"ABCDEF01";
427                         elsif address_s(4 downto 0) = "00111" then
428                                 data_o <= argument_r;
429                         else
430                                 data_o <= (others => '0');
431                         end if;
432                 end if;
433         end process;
434
435 update:
436         process
437         begin
438                 wait until clk_i'event and clk_i= '1';
439                 ce_s      <= next_ce_i;
440                 address_s <= address_i;
441
442                 approx_frac_r <= approx_frac_s;
443
444                 state_tab_r <= state_tab_s;
445                 state_dsp48_r <= state_tab_r;
446                 state_regw_r <= state_dsp48_r;
447
448                 argument_r <= argument_s;
449                 sin_cos_force_one_r <= sin_cos_force_one_s;
450                 sin_cos_force_one_r2 <= sin_cos_force_one_r;
451                 sin_cos_negate_out_r <= sin_cos_negate_out_s;
452                 sin_cos_negate_out_r2 <= sin_cos_negate_out_r;
453
454                 reci_result_r <= reci_result_s;
455                 sin_result_r <= sin_result_s;
456                 cos_result_r <= cos_result_s;
457         end process;
458
459 end Behavioral;
460