Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- library ieee;
- use ieee.std_logic_1164.all;
- use ieee.numeric_std.all;
- entity generator is
- port (
- clk : in std_logic;
- -- Reset? rst : in std_logic;
- freq : in unsigned(15 downto 0);
- ampl : in unsigned(7 downto 0); -- Why shorten the name? amplitude is descriptive and obvious, already not too short.
- phs : in unsigned(7 downto 0); -- degrees? what is phs? Phase? Just name it phase
- sig : out std_logic; -- Stylistic choice, but I always would put the output at the bottom of the entity
- sig_sel : in std_logic_vector(1 downto 0); -- 00:sin; 01:square; 10:saw; 11:triangle
- duty_cycle : in integer range 0 to 100
- );
- end entity generator;
- architecture behavioral of generator is
- constant C_F_CLK : integer := 50000000; -- 50 MHz
- signal phase_accu : unsigned(31 downto 0) := (others => '0');
- signal phase_step : unsigned(31 downto 0) := (others => '0');
- signal lut_index : unsigned(4 downto 0) := (others => '0');
- signal sig_tmp : unsigned(15 downto 0) := (others => '0'); -- holds 8bitΓ8bit product
- signal sig_int : unsigned(7 downto 0) := (others => '0');
- signal pwm_counter : unsigned(7 downto 0) := (others => '0');
- signal duty_thresh : unsigned(31 downto 0) := (others => '0');
- signal lut_value : std_logic_vector(7 downto 0);
- signal lut_value_mirror : std_logic_vector(7 downto 0);
- begin
- lut_inst : entity work.lut(rtl)
- port map (
- index => std_logic_vector(lut_index),
- value => lut_value,
- value_mirror => lut_value_mirror
- );
- main_proc : process (clk) is
- variable freq64 : unsigned(63 downto 0);
- variable temp64 : unsigned(63 downto 0);
- variable duty64 : unsigned(63 downto 0);
- variable sum64 : unsigned(63 downto 0);
- variable sig_tmp64 : unsigned(31 downto 0);
- variable temp8 : unsigned(7 downto 0);
- begin
- sig <= '0'; -- It is very bad practice to assign anything outside of the rising_edge(clk) in a clocked process. This is definitely causing you trouble.
- if rising_edge(clk) then
- -- Reset?
- -- if rst = '1' then
- -- Reset registers here
- -- else
- freq64 := resize(freq, 64);
- temp64 := shift_left(freq64, 32) / to_unsigned(C_F_CLK, 64);
- -- phase accumulator with safe wrap, no overflow
- sum64 := resize(phase_accu, 64) + resize(phase_step, 64);
- phase_accu <= sum64(31 downto 0);
- phase_step <= temp64(31 downto 0);
- case sig_sel is -- case statement based on input is fine, but if you want to run this faster, I would hold stateful information in local registers
- -- sine
- when "00" =>
- lut_index <= phase_accu(31 downto 27);
- case phase_accu(31 downto 30) is
- when "00" => -- 1st quadrant
- sig_tmp <= unsigned(lut_value) * ampl;
- sig_int <= sig_tmp(15 downto 8);
- when "01" => -- 2nd quadrant (mirror)
- sig_tmp <= unsigned(lut_value_mirror) * ampl;
- sig_int <= sig_tmp(15 downto 8);
- when "10" => -- 3rd quadrant (negative)
- sig_tmp <= unsigned(lut_value) * ampl;
- sig_int <= 255 - sig_tmp(15 downto 8);
- when "11" => -- 4th quadrant (negative mirror)
- sig_tmp <= unsigned(lut_value_mirror) * ampl;
- sig_int <= 255 - sig_tmp(15 downto 8);
- when others =>
- sig_int <= (others => '0');
- end case;
- if (pwm_counter = 255) then -- numeric_std unsigned already does this :) wraps cleanly by default. This is great practice though if you want other pwm freq.
- pwm_counter <= (others => '0');
- else
- pwm_counter <= pwm_counter + 1;
- end if;
- if (pwm_counter < resize(sig_int, 8)) then
- sig <= '1';
- else
- sig <= '0';
- end if;
- -- square
- when "01" =>
- duty64 := shift_left(resize(to_unsigned(duty_cycle, 64), 64), 32) / to_unsigned(100, 64);
- duty_thresh <= duty64(31 downto 0);
- -- I see you are assigning sig differently depending on case... This is maybe fine but I would prefer to see
- -- the pwm logic independant of this case statement, and the waveform control be done exclusively with sig_int.
- if (phase_accu >= duty_thresh) then
- sig <= '0';
- else
- sig <= '1';
- end if;
- -- saw
- when "10" =>
- sig_tmp64 := resize(phase_accu(31 downto 24), 16) * resize(ampl, 16);
- temp8 := sig_tmp64(23 downto 16); -- take the slice
- sig_int <= temp8;
- if (pwm_counter < sig_int) then
- sig <= '1';
- else
- sig <= '0';
- end if;
- -- triangle
- when "11" =>
- duty64 := shift_left(resize(to_unsigned(duty_cycle, 64), 64), 32) / to_unsigned(100, 64);
- duty_thresh <= duty64(31 downto 0);
- if (phase_accu < duty_thresh) then
- -- Rising slope
- sig_tmp64 := resize(phase_accu(31 downto 24), 16) * resize(ampl, 16);
- temp8 := sig_tmp64(15 downto 8);
- sig_int <= temp8;
- else
- -- Falling slope
- sig_tmp64 := resize(not phase_accu(31 downto 24), 16) * resize(ampl, 16);
- temp8 := sig_tmp64(15 downto 8);
- sig_int <= temp8;
- end if;
- if (pwm_counter < sig_int) then
- sig <= '1';
- else
- sig <= '0';
- end if;
- when others =>
- sig <= '0';
- end case;
- end if;
- end process main_proc;
- end architecture behavioral;
- library ieee;
- use ieee.std_logic_1164.all;
- use ieee.numeric_std.all;
- entity lut is
- generic (
- GC_LUT_SIZE : integer := 32; -- Great use of generics! They got renamed with prefixes by my formatter.
- GC_DATA_WIDTH : integer := 8
- );
- port (
- index : in std_logic_vector(4 downto 0); -- HARDCODED
- value : out std_logic_vector(GC_DATA_WIDTH - 1 downto 0);
- value_mirror : out std_logic_vector(GC_DATA_WIDTH - 1 downto 0)
- );
- end entity lut;
- architecture rtl of lut is
- type lut_array is array (0 to 31) of std_logic_vector(GC_DATA_WIDTH - 1 downto 0);
- constant SINE_TABLE : lut_array :=
- (
- 0 => "00000000",
- 1 => "00000110",
- 2 => "00001100",
- 3 => "00010010",
- 4 => "00011000",
- 5 => "00011111",
- 6 => "00100101",
- 7 => "00101011",
- 8 => "00110000",
- 9 => "00110110",
- 10 => "00111100",
- 11 => "01000001",
- 12 => "01000111",
- 13 => "01001100",
- 14 => "01010001",
- 15 => "01010101",
- 16 => "01011010",
- 17 => "01011110",
- 18 => "01100010",
- 19 => "01100110",
- 20 => "01101010",
- 21 => "01101101",
- 22 => "01110000",
- 23 => "01110011",
- 24 => "01110110",
- 25 => "01111000",
- 26 => "01111010",
- 27 => "01111100",
- 28 => "01111101",
- 29 => "01111110",
- 30 => "01111111",
- 31 => "01111111"
- );
- begin
- -- always 0 unless index is all 1? This is certainly not what you intended?
- -- Did you not just want value to always be equal to sine_table(index).
- value <= sine_table(to_integer(unsigned(index))) when index <= "11111" else
- (others => '0');
- value_mirror <= sine_table(GC_LUT_SIZE - 1 - to_integer(unsigned(index))) when index <= "11111" else
- (others => '0');
- end architecture rtl;
Advertisement
Add Comment
Please, Sign In to add comment