library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity DS_dac is
    port (
        clk     : in  std_logic;
        reset   : in  std_logic;  -- active high synchronous reset
        data_in : in  signed(15 downto 0);
        pdm_out : out std_logic
    );
end entity DS_dac;

architecture behavioral of DS_dac is
    -- First integrator accumulator: sufficient bits to avoid overflow
    signal acc1 : signed(17 downto 0) := (others => '0');
    -- Second integrator accumulator
    signal acc2 : signed(17 downto 0) := (others => '0');
    
    -- 2-stage synchronizer for async data_in
    signal data_in_sync1 : signed(15 downto 0) := (others => '0');
    signal data_in_sync2 : signed(15 downto 0) := (others => '0');
    
    -- Quantizer output (MSB of second accumulator)
    signal quant : std_logic := '0';

begin

    -- Synchronizer process
    process(clk)
    begin
        if rising_edge(clk) then
            if reset = '1' then
                data_in_sync1 <= (others => '0');
                data_in_sync2 <= (others => '0');
            else
                data_in_sync1 <= data_in;
                data_in_sync2 <= data_in_sync1;
            end if;
        end if;
    end process;

    -- Second-order modulator process (two cascaded integrators with feedback)
process(clk)
    variable error      : signed(17 downto 0);
    variable acc1_old   : signed(17 downto 0);  -- holds value before update
begin
    if rising_edge(clk) then
        if reset = '1' then
            acc1    <= (others => '0');
            acc2    <= (others => '0');
            pdm_out <= '0';
            quant   <= '0';
        else
            -- Capture the old acc1 value first (before we overwrite it)
            acc1_old := acc1;

            -- Quantizer (can use current acc2, or delayed - both common)
-- 1. Quantizer (Decision based on current accumulator state)
            if acc1(17) = '1' then
                quant <= '0';
                error := to_signed(-32768, 18);
            else
                quant <= '1';
                error := to_signed(32768, 18);
            end if;

            -- 2. Update Output
            pdm_out <= not quant;
              --pdm_out <= quant;
            -- First integrator: uses input - feedback
            acc1 <= acc1 + resize(data_in_sync2, 18) - error;

            -- Second integrator: integrates the *previous* first-stage error
            acc2 <= acc2 + acc1_old + error;
        end if;
    end if;
end process;

end architecture behavioral;