Project

General

Profile

---------------------------------------------------------------------------
-- (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;

ENTITY SID_f_distortion IS
PORT
(
CLK : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;

STATE : IN SIGNED(17 downto 8); -- Voltage of filter, which should not impact F
F_RAW : IN UNSIGNED(12 downto 0); -- Wanted F, scaled to same units as voltage of filter
F_DISTORTED : OUT UNSIGNED(12 downto 0) --Result F
);
END SID_f_distortion;

ARCHITECTURE vhdl OF SID_f_distortion IS
signal y1 : unsigned(12 downto 0);
signal y1_reg : unsigned(12 downto 0);
signal y2 : unsigned(12 downto 0);
signal ych : unsigned(12 downto 0);
signal yadj_next : unsigned(25 downto 0);
signal yadj_reg : unsigned(25 downto 0);
signal ychpos : unsigned(12 downto 0);
signal f_distorted_next : unsigned(12 downto 0);
signal STATE_next : SIGNED(17 downto 8);
signal STATE_reg : SIGNED(17 downto 8);
signal F_RAW_next : UNSIGNED(12 downto 0);
signal F_RAW_reg : UNSIGNED(12 downto 0);
begin
-- register
process(clk,reset_n)
begin
if (reset_n='0') then
y1_reg <= (others=>'0');
yadj_reg <= (others=>'0');
state_reg <= (others=>'0');
f_raw_reg <= (others=>'0');
elsif (clk'event and clk='1') then
y1_reg <= y1;
yadj_reg <= yadj_next;
state_reg <= state_next;
f_raw_reg <= f_raw_next;
end if;
end process;

state_next <= state;
f_raw_next <= f_raw;

process (state_reg,f_raw_reg, y1, y2, ych, ychpos, y1_reg, yadj_reg)
type LOOKUP_TYPE is array (0 to 38) of unsigned(12 downto 0);
variable lookup : LOOKUP_TYPE;

variable pos: unsigned(18 downto 5);
begin
-- assumption: /home/markw/fpga/svn/jsidplay2-code/jsidplay2/src/main/java/builder/resid/residfp/Filter6581.java
pos := (others=>'0');
if (state_reg(17)='0') then
pos := unsigned('0'&state_reg(16 downto 8)&"000"&"0") + resize('0'&f_raw_reg,14);
end if;
if (pos(18 downto 12) > to_unsigned(37,6)) then
pos(18) := '0';
pos(17 downto 12) := to_unsigned(37,6);
pos(11 downto 5) := (others=>'1');
end if;

-- replace with piecewise interp. Takes a mul unit but saves lookup space.
lookup := (
"0000001000100","0000001000101","0000001000110","0000001001000","0000001001011","0000001001111","0000001010110","0000001100000","0000001110000","0000010001000","0000010101011","0000011100000","0000100101111","0000110100001","0001001000101","0001100101001","0010001011000","0010111010111","0011110011010","0100110000111","0101101110011","0110100110111","0111010110110","0111111100110","1000011001001","1000101101110","1000111100001","1001000101111","1001001100100","1001010001000","1001010100000","1001010101111","1001010111010","1001011000001","1001011000101","1001011001000","1001011001010","1001011001011","1001011001100");

ychpos <= resize(pos(11 downto 5)&"00000",13);
y1 <= lookup(to_integer(pos(17 downto 12)));
y2 <= lookup(to_integer(pos(17 downto 12))+1);

ych <= y2-y1;

yadj_next <= ych * ychpos;

f_distorted_next <= y1_reg + resize(yadj_reg(25 downto 12),13);
end process;

-- output
f_distorted <= f_distorted_next;
end vhdl;


(4-4/12)