repo2/atari_chips/pokeyv2/dc_blocker.vhdl @ 1553
| 1551 | markw | ---------------------------------------------------------------------------
|
|
-- (c) 2020 mark watson
|
|||
-- I am happy for anyone to use this for non-commercial use.
|
|||
-- If my vhdl files are used commercially or otherwise sold,
|
|||
-- please contact me for explicit permission at scrameta (gmail).
|
|||
-- This applies for source and binary form and derived works.
|
|||
---------------------------------------------------------------------------
|
|||
LIBRARY ieee;
|
|||
USE ieee.std_logic_1164.all;
|
|||
USE ieee.numeric_std.all;
|
|||
-- Generic unsigned-input to signed-output DC blocker.
|
|||
-- AUDIO_IN is treated as offset-binary unsigned audio:
|
|||
-- 0 -> most negative signed value
|
|||
-- 2**(BITS-1) -> zero
|
|||
-- 2**BITS - 1 -> most positive signed value
|
|||
--
|
|||
-- Filter:
|
|||
-- y = x - dc_old
|
|||
-- dc = dc_old + (y / 2**K)
|
|||
--
|
|||
-- AUDIO_OUT is registered and saturated to BITS bits.
|
|||
ENTITY dc_blocker IS
|
|||
GENERIC
|
|||
(
|
|||
BITS : positive := 16;
|
|||
EXTRA_BITS : positive := 4;
|
|||
K : natural := 10
|
|||
);
|
|||
PORT
|
|||
(
|
|||
CLK : IN std_logic;
|
|||
RESET_N : IN std_logic;
|
|||
ENABLE_CYCLE : IN std_logic;
|
|||
AUDIO_IN : IN unsigned(BITS-1 downto 0);
|
|||
AUDIO_OUT : OUT signed(BITS-1 downto 0)
|
|||
);
|
|||
END dc_blocker;
|
|||
ARCHITECTURE vhdl OF dc_blocker IS
|
|||
constant ACC_WIDTH : positive := BITS + EXTRA_BITS;
|
|||
subtype acc_t is signed(ACC_WIDTH-1 downto 0);
|
|||
function midpoint return acc_t is
|
|||
variable r : acc_t := (others => '0');
|
|||
begin
|
|||
r(BITS-1) := '1';
|
|||
return r;
|
|||
end function;
|
|||
function saturate_to_bits(v : acc_t) return signed is
|
|||
variable r : signed(BITS-1 downto 0);
|
|||
variable overflow : boolean := false;
|
|||
variable max_val : signed(BITS-1 downto 0) := (others => '1');
|
|||
variable min_val : signed(BITS-1 downto 0) := (others => '0');
|
|||
begin
|
|||
max_val(BITS-1) := '0';
|
|||
min_val(BITS-1) := '1';
|
|||
-- A value fits into BITS signed bits when all bits above BITS-1
|
|||
-- match the sign bit that will remain after truncation.
|
|||
for i in BITS to ACC_WIDTH-1 loop
|
|||
if v(i) /= v(BITS-1) then
|
|||
overflow := true;
|
|||
end if;
|
|||
end loop;
|
|||
if overflow then
|
|||
if v(ACC_WIDTH-1) = '0' then
|
|||
r := max_val;
|
|||
else
|
|||
r := min_val;
|
|||
end if;
|
|||
else
|
|||
r := v(BITS-1 downto 0);
|
|||
end if;
|
|||
return r;
|
|||
end function;
|
|||
constant MIDPOINT_VALUE : acc_t := midpoint;
|
|||
signal dc_reg : acc_t;
|
|||
signal dc_next : acc_t;
|
|||
signal audio_out_reg : signed(BITS-1 downto 0);
|
|||
signal audio_out_next : signed(BITS-1 downto 0);
|
|||
BEGIN
|
|||
process(AUDIO_IN, ENABLE_CYCLE, dc_reg)
|
|||
variable x_ext : acc_t;
|
|||
variable err : acc_t;
|
|||
variable adj : acc_t;
|
|||
begin
|
|||
x_ext := signed(resize(AUDIO_IN, ACC_WIDTH)) - MIDPOINT_VALUE;
|
|||
err := x_ext - dc_reg;
|
|||
adj := shift_right(err, K);
|
|||
dc_next <= dc_reg;
|
|||
audio_out_next <= saturate_to_bits(err);
|
|||
if ENABLE_CYCLE = '1' then
|
|||
dc_next <= dc_reg + adj;
|
|||
end if;
|
|||
end process;
|
|||
process(CLK, RESET_N)
|
|||
begin
|
|||
if RESET_N = '0' then
|
|||
dc_reg <= (others => '0');
|
|||
audio_out_reg <= (others => '0');
|
|||
elsif CLK'event and CLK = '1' then
|
|||
dc_reg <= dc_next;
|
|||
audio_out_reg <= audio_out_next;
|
|||
end if;
|
|||
end process;
|
|||
AUDIO_OUT <= audio_out_reg;
|
|||
END vhdl;
|