17
17
-- | Cosine Transform, Pulse Width/Code/Position Modulation modules, so long as
18
18
-- | they are fairly generic and synthesizable.
19
19
-- |
20
- -- | An alternative to CORDIC, is this sin-cosine implementation written in
21
- -- | Verilog <https://github.com/jamesbowman/sincos>. It requires a multiplier
22
- -- | however.
20
+ -- | Potential improvements to the library:
21
+ -- | - Optional registers on either input or output, selectable by a generic
22
+ -- | - Better timing models
23
+ -- | - More assertions
24
+ -- | - Put a modules state in a record that represents that state, to make
25
+ -- | assignment and handling of that state easier.
23
26
-- |
24
27
-- | @author Richard James Howe
25
28
-- | @copyright Copyright 2017, 2019 Richard James Howe
@@ -524,6 +527,24 @@ package util is
524
527
generic (g: common_generics);
525
528
end component ;
526
529
530
+ component sine is
531
+ generic (g: common_generics);
532
+ port (
533
+ x: in std_ulogic_vector (15 downto 0 );
534
+ s: out std_ulogic_vector (15 downto 0 ));
535
+ end component ;
536
+
537
+ component cosine is
538
+ generic (g: common_generics);
539
+ port (
540
+ x: in std_ulogic_vector (15 downto 0 );
541
+ s: out std_ulogic_vector (15 downto 0 ));
542
+ end component ;
543
+
544
+ component sine_tb is
545
+ generic (g: common_generics);
546
+ end component ;
547
+
527
548
function max (a: natural ; b: natural ) return natural ;
528
549
function min (a: natural ; b: natural ) return natural ;
529
550
function reverse (a: in std_ulogic_vector ) return std_ulogic_vector ;
@@ -892,6 +913,7 @@ begin
892
913
uut_gray: work.util.gray_tb generic map (g => g);
893
914
uut_ham: work.util.hamming_7_4_tb generic map (g => g); -- Oink!
894
915
uut_vga: work.util.vga_tb generic map (g => g, simulation_us => 1 us );
916
+ uut_sine: work.util.sine_tb generic map (g => g);
895
917
uut_7_seg: work.util.led_7_segment_display_tb generic map (g => g);
896
918
897
919
stimulus_process : process
@@ -2292,7 +2314,7 @@ end architecture;
2292
2314
-- state to fetch the operand and another register, or more states.
2293
2315
--
2294
2316
-- @todo Test in hardware, document, make assembler, and a project that
2295
- -- just contains an instantiation of this core, Select CPU behaviour with
2317
+ -- just contains an instantiation of this core, Select CPU behavior with
2296
2318
-- generics (instructions, branch conditions...)
2297
2319
--
2298
2320
@@ -2805,7 +2827,7 @@ entity reset_generator is
2805
2827
rst: out std_logic := '0' ); -- reset out!
2806
2828
end entity ;
2807
2829
2808
- architecture behaviour of reset_generator is
2830
+ architecture behavior of reset_generator is
2809
2831
constant cycles: natural := (g.clock_frequency / 1000000 ) * reset_period_us;
2810
2832
subtype counter is unsigned (max(1 , n_bits(cycles) - 1 ) downto 0 );
2811
2833
signal c_c, c_n: counter := (others => '0' );
@@ -2876,7 +2898,7 @@ entity bit_count is
2876
2898
count: out std_ulogic_vector (n_bits(N) downto 0 ));
2877
2899
end entity ;
2878
2900
2879
- architecture behaviour of bit_count is
2901
+ architecture behavior of bit_count is
2880
2902
begin
2881
2903
process (bits)
2882
2904
constant zero: unsigned (count'high - 1 downto count'low ) := (others => '0' );
@@ -2946,7 +2968,7 @@ entity majority is
2946
2968
tie: out std_ulogic );
2947
2969
end entity ;
2948
2970
2949
- architecture behaviour of majority is
2971
+ architecture behavior of majority is
2950
2972
signal count: std_ulogic_vector (n_bits(N) downto 0 ) := (others => '0' );
2951
2973
-- It might be worth handling up to five or so bits in combinatorial
2952
2974
-- logic, or it might not.
@@ -3122,7 +3144,7 @@ entity delay_line is
3122
3144
do: out std_ulogic_vector (width - 1 downto 0 ));
3123
3145
end entity ;
3124
3146
3125
- architecture behaviour of delay_line is
3147
+ architecture behavior of delay_line is
3126
3148
type delay_line_t is array (integer range 0 to depth) of std_ulogic_vector (di'range );
3127
3149
signal sigs: delay_line_t := (others => (others => '0' ));
3128
3150
begin
@@ -3200,7 +3222,7 @@ entity gray_encoder is
3200
3222
do: out std_ulogic_vector (N - 1 downto 0 ));
3201
3223
end entity ;
3202
3224
3203
- architecture behaviour of gray_encoder is
3225
+ architecture behavior of gray_encoder is
3204
3226
begin
3205
3227
gry : for i in N - 1 downto 0 generate
3206
3228
first : if i = (N - 1 ) generate
@@ -3223,7 +3245,7 @@ entity gray_decoder is
3223
3245
do: out std_ulogic_vector (N - 1 downto 0 ));
3224
3246
end entity ;
3225
3247
3226
- architecture behaviour of gray_decoder is
3248
+ architecture behavior of gray_decoder is
3227
3249
begin
3228
3250
gry : for i in N - 1 downto 0 generate
3229
3251
first : if i = (N - 1 ) generate
@@ -3296,7 +3318,7 @@ entity parity_module is
3296
3318
port (di: in std_ulogic_vector (N - 1 downto 0 ); do: out std_ulogic );
3297
3319
end entity ;
3298
3320
3299
- architecture behaviour of parity_module is
3321
+ architecture behavior of parity_module is
3300
3322
begin
3301
3323
do <= parity(di, even) after g.delay;
3302
3324
end architecture ;
@@ -3327,7 +3349,7 @@ entity hamming_7_4_encoder is
3327
3349
parity: out std_ulogic );
3328
3350
end entity ;
3329
3351
3330
- architecture behaviour of hamming_7_4_encoder is
3352
+ architecture behavior of hamming_7_4_encoder is
3331
3353
signal p1, p2, p3: std_ulogic := '0' ;
3332
3354
begin
3333
3355
p1 <= di(0 ) xor di(1 ) xor di(3 ) after g.delay;
@@ -3357,7 +3379,7 @@ entity hamming_7_4_decoder is
3357
3379
single, double: out std_ulogic );
3358
3380
end entity ;
3359
3381
3360
- architecture behaviour of hamming_7_4_decoder is
3382
+ architecture behavior of hamming_7_4_decoder is
3361
3383
signal s: std_ulogic_vector (2 downto 0 ) := (others => '0' );
3362
3384
signal co, ct, dip: std_ulogic_vector (di'high + 1 downto 0 ) := (others => '0' );
3363
3385
signal cp: std_ulogic := '0' ;
@@ -3685,7 +3707,7 @@ end architecture;
3685
3707
-- | Each of the display shares a common anode for all of its LEDs, this can be
3686
3708
-- | used to select an individual display
3687
3709
3688
- library ieee,work;
3710
+ library ieee, work;
3689
3711
use ieee.std_logic_1164.all ;
3690
3712
use ieee.numeric_std.all ;
3691
3713
use work.util.all ;
@@ -3891,7 +3913,7 @@ begin
3891
3913
end process ;
3892
3914
end architecture ;
3893
3915
3894
- library ieee,work;
3916
+ library ieee, work;
3895
3917
use ieee.std_logic_1164.all ;
3896
3918
use ieee.numeric_std.all ;
3897
3919
use work.util.all ;
@@ -3935,4 +3957,111 @@ begin
3935
3957
end architecture ;
3936
3958
3937
3959
-- ----------------------- LED Controller ------------------------------------------------------
3960
+ -- ----------------------- Sine / Cosine ------------------------------------------------------
3961
+ -- Sine / Cosine calculation using multiplication
3962
+ -- Half-inched from <https://github.com/jamesbowman/sincos>
3963
+ -- Angles are input as signed Furmans (1 Furman = (1/pow(2, 16) of a circle))
3964
+ -- 1 Degree is ~182 Furmans. 1 rad is ~10430 Furmans.
3965
+ -- Result is signed scaled 16-bit integer; -1 = -32767, +1 = 32767
3966
+ library ieee, work;
3967
+ use ieee.std_logic_1164.all ;
3968
+ use ieee.numeric_std.all ;
3969
+ use work.util.all ;
3938
3970
3971
+ entity sine is
3972
+ generic (g: common_generics);
3973
+ port (
3974
+ x: in std_ulogic_vector (15 downto 0 );
3975
+ s: out std_ulogic_vector (15 downto 0 ));
3976
+ end entity ;
3977
+
3978
+ architecture behavior of sine is
3979
+ subtype val is signed (x'range );
3980
+ subtype mul is signed ((val'high * 2 ) + 1 downto 0 );
3981
+ function half_multiply_add (a, b, c: val) return val is
3982
+ variable t: mul;
3983
+ variable r: val;
3984
+ begin
3985
+ t := a * b;
3986
+ r := t(t'high downto r'high + 1 ) + c;
3987
+ return r;
3988
+ end function ;
3989
+ signal n: signed (2 downto 0 );
3990
+ signal z, y, sums, sumc, sum1, cc, t0, t1, sa, so: val;
3991
+ signal cc32: mul;
3992
+ begin
3993
+ y(1 downto 0 ) <= (others => '0' ) after g.delay;
3994
+ y(15 downto 2 ) <= signed (x(13 downto 0 )) after g.delay;
3995
+ n <= signed (x(15 downto 13 )) + "01" after g.delay;
3996
+ z <= half_multiply_add(y, y, x"0000" ) after g.delay;
3997
+ sumc <= half_multiply_add(z, x"0FBD" , - x"4EE9" ) after g.delay;
3998
+ sums <= half_multiply_add(z, x"04F8" , - x"2953" ) after g.delay;
3999
+ sum1 <= half_multiply_add(z, sums, x"6487" ) after g.delay;
4000
+ cc32 <= t0 * t1 after g.delay;
4001
+ cc <= cc32(cc32'high - 1 downto cc'high ) after g.delay;
4002
+ t0 <= z when n(1 ) = '1' else y after g.delay;
4003
+ t1 <= sumc when n(1 ) = '1' else sum1 after g.delay;
4004
+ sa <= cc + x"7FFF" when n(1 ) = '1' else cc after g.delay;
4005
+ so <= - sa when n(2 ) = '1' else sa after g.delay;
4006
+ s <= std_ulogic_vector (so) after g.delay;
4007
+ end architecture ;
4008
+
4009
+ library ieee, work;
4010
+ use ieee.std_logic_1164.all ;
4011
+ use ieee.numeric_std.all ;
4012
+ use work.util.all ;
4013
+
4014
+ entity cosine is
4015
+ generic (g: common_generics);
4016
+ port (
4017
+ x: in std_ulogic_vector (15 downto 0 );
4018
+ c: out std_ulogic_vector (15 downto 0 ));
4019
+ end entity ;
4020
+
4021
+ architecture behavior of cosine is
4022
+ signal xn: std_ulogic_vector (c'range );
4023
+ begin
4024
+ xn <= std_ulogic_vector (signed (x) + x"4000" );
4025
+ calc : entity work .sine
4026
+ generic map (g => g) port map (x => xn, s => c);
4027
+ end architecture ;
4028
+
4029
+ library ieee, work;
4030
+ use ieee.std_logic_1164.all ;
4031
+ use ieee.numeric_std.all ;
4032
+ use work.util.all ;
4033
+
4034
+ entity sine_tb is
4035
+ generic (g: common_generics);
4036
+ end entity ;
4037
+
4038
+ architecture testing of sine_tb is
4039
+ constant clock_period: time := 1000 ms / g.clock_frequency;
4040
+ signal clk, rst: std_ulogic := '0' ;
4041
+ signal stop : std_ulogic := '0' ;
4042
+
4043
+ constant number_of_led_displays: positive := 4 ;
4044
+ signal x: std_ulogic_vector (15 downto 0 );
4045
+ signal s, c: std_ulogic_vector (x'range );
4046
+ begin
4047
+ cs : entity work .clock_source_tb
4048
+ generic map (g => g, hold_rst => 2 )
4049
+ port map (stop => stop , clk => clk, rst => rst);
4050
+
4051
+ uut_c : entity work .sine generic map (g => g) port map (x => x, s => s);
4052
+ uut_s : entity work .cosine generic map (g => g) port map (x => x, c => c);
4053
+
4054
+ stimulus_process : process
4055
+ variable cnt: integer := - 32768 ;
4056
+ begin
4057
+ x <= std_ulogic_vector (to_signed (cnt, x'length ));
4058
+ wait for clock_period * 2 ;
4059
+ while cnt < 32768 loop
4060
+ x <= std_ulogic_vector (to_signed (cnt, x'length ));
4061
+ wait for clock_period;
4062
+ cnt := cnt + 182 ;
4063
+ end loop ;
4064
+ stop <= '1' ;
4065
+ wait ;
4066
+ end process ;
4067
+ end architecture ;
0 commit comments