Index: atari_chips/pokeyv2/build.sh
===================================================================
--- atari_chips/pokeyv2/build.sh	(revision 1453)
+++ atari_chips/pokeyv2/build.sh	(revision 1454)
@@ -559,7 +559,7 @@
 				"paddle_lvds"=>1,
 				"paddle_comp"=>0,
 				"enable_iox"=>0,
-				"enable_adc"=>1,
+				"enable_adc"=>0,
 				"pll_v2" => 0, 
 				"optimisearea" => 1,
 			},
@@ -591,7 +591,7 @@
 				"paddle_lvds"=>1,
 				"paddle_comp"=>0,
 				"enable_iox"=>0,
-				"enable_adc"=>1,
+				"enable_adc"=>0,
 				"pll_v2" => 0, 
 				"optimisearea" => 1,
 			},
@@ -945,7 +945,11 @@
 			`cp -r pokey $dir`;
 			`cp -r sample $dir`;
 			`cp -r covox $dir`;
+			`cp -r sigma_delta $dir`;
 			`cp -r *.bin $dir`;
+			`cp -r fir_*vhdl $dir`;
+			`cp -r fir_sample_buffer* $dir`;
+			`cp -r fir_buffer* $dir`;
 		
 			chdir $dir;
 		
Index: atari_chips/pokeyv2/fir2_notch.m
===================================================================
--- atari_chips/pokeyv2/fir2_notch.m	(nonexistent)
+++ atari_chips/pokeyv2/fir2_notch.m	(revision 1454)
@@ -0,0 +1,65 @@
+pkg load signal;
+
+fsample = 48000;
+%fsample = 24000;
+
+%notches = [15600/4,15600/2,15600];
+cutoff = [15600,15600];
+cutoff_norm = cutoff/(fsample/2);
+%notches = load('notches');
+%notches = notches.freqs;
+notches = []
+linepal = 312*49.86;
+linentsc = 262*59.92;
+for i=1:8
+  notches(end+1) = i*linepal/8;
+  notches(end+1) = i*linentsc/8;
+end
+notches(end+1) = linepal/64;
+notches(end+1) = linentsc/64;
+notches = notches(notches<cutoff(2));
+notches_norm = notches/(fsample/2);
+
+steps = 10000;
+
+l=0;
+%thr = 0.0008;
+thr = 0.0016;
+%thr = 0.0032;
+for i = 0.0:1.0/steps:1.0
+  l=l+1;
+  pos(l) = i;
+  val = min(((i-notches_norm).^2).^0.5);
+  if val>thr
+    func(l)=  1.0;
+  else
+    func(l) = 0.0;
+  endif
+  if i>cutoff_norm(2)
+    func(l) = 0;
+    continue;
+  endif
+  if i>cutoff_norm(1)
+    cutoff_normd = cutoff_norm(2)-cutoff_norm(1);
+    func(l) = (cutoff_norm(2)-i)/cutoff_normd;
+  endif
+end
+
+fil_len = 2031;
+fil = fir2(fil_len,pos,func);
+
+bits = 16;
+range = (2^bits-2)/2;
+fil = round(fil*range)/range;
+
+[h,w] = freqz(fil,1,10000);
+
+f = pos;
+m = func;
+
+figure();
+subplot(121);
+plot(f,m,';target response;',w/pi,abs(h),';filter response;');
+subplot(122);
+plot(f,20*log10(m+1e-5),';target response (dB);',...
+      w/pi,20*log10(abs(h)),';filter response (dB);');
Index: atari_chips/pokeyv2/fir_buffer.cmp
===================================================================
--- atari_chips/pokeyv2/fir_buffer.cmp	(nonexistent)
+++ atari_chips/pokeyv2/fir_buffer.cmp	(revision 1454)
@@ -0,0 +1,28 @@
+--Copyright (C) 2024  Intel Corporation. All rights reserved.
+--Your use of Intel Corporation's design tools, logic functions 
+--and other software and tools, and any partner logic 
+--functions, and any output files from any of the foregoing 
+--(including device programming or simulation files), and any 
+--associated documentation or information are expressly subject 
+--to the terms and conditions of the Intel Program License 
+--Subscription Agreement, the Intel Quartus Prime License Agreement,
+--the Intel FPGA IP License Agreement, or other applicable license
+--agreement, including, without limitation, that your use is for
+--the sole purpose of programming logic devices manufactured by
+--Intel and sold by Intel or its authorized distributors.  Please
+--refer to the applicable agreement for further details, at
+--https://fpgasoftware.intel.com/eula.
+
+
+component fir_buffer
+	PORT
+	(
+		data		: IN STD_LOGIC_VECTOR (31 DOWNTO 0);
+		rdaddress		: IN STD_LOGIC_VECTOR (9 DOWNTO 0);
+		rdclock		: IN STD_LOGIC ;
+		wraddress		: IN STD_LOGIC_VECTOR (9 DOWNTO 0);
+		wrclock		: IN STD_LOGIC  := '1';
+		wren		: IN STD_LOGIC  := '0';
+		q		: OUT STD_LOGIC_VECTOR (31 DOWNTO 0)
+	);
+end component;
Index: atari_chips/pokeyv2/fir_buffer.qip
===================================================================
--- atari_chips/pokeyv2/fir_buffer.qip	(nonexistent)
+++ atari_chips/pokeyv2/fir_buffer.qip	(revision 1454)
@@ -0,0 +1,5 @@
+set_global_assignment -name IP_TOOL_NAME "RAM: 2-PORT"
+set_global_assignment -name IP_TOOL_VERSION "23.1"
+set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{MAX 10}"
+set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "fir_buffer.vhd"]
+set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "fir_buffer.cmp"]
Index: atari_chips/pokeyv2/fir_buffer.vhd
===================================================================
--- atari_chips/pokeyv2/fir_buffer.vhd	(nonexistent)
+++ atari_chips/pokeyv2/fir_buffer.vhd	(revision 1454)
@@ -0,0 +1,199 @@
+-- megafunction wizard: %RAM: 2-PORT%
+-- GENERATION: STANDARD
+-- VERSION: WM1.0
+-- MODULE: altsyncram 
+
+-- ============================================================
+-- File Name: fir_buffer.vhd
+-- Megafunction Name(s):
+-- 			altsyncram
+--
+-- Simulation Library Files(s):
+-- 			altera_mf
+-- ============================================================
+-- ************************************************************
+-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
+--
+-- 23.1std.1 Build 993 05/14/2024 SC Lite Edition
+-- ************************************************************
+
+
+--Copyright (C) 2024  Intel Corporation. All rights reserved.
+--Your use of Intel Corporation's design tools, logic functions 
+--and other software and tools, and any partner logic 
+--functions, and any output files from any of the foregoing 
+--(including device programming or simulation files), and any 
+--associated documentation or information are expressly subject 
+--to the terms and conditions of the Intel Program License 
+--Subscription Agreement, the Intel Quartus Prime License Agreement,
+--the Intel FPGA IP License Agreement, or other applicable license
+--agreement, including, without limitation, that your use is for
+--the sole purpose of programming logic devices manufactured by
+--Intel and sold by Intel or its authorized distributors.  Please
+--refer to the applicable agreement for further details, at
+--https://fpgasoftware.intel.com/eula.
+
+
+LIBRARY ieee;
+USE ieee.std_logic_1164.all;
+
+LIBRARY altera_mf;
+USE altera_mf.altera_mf_components.all;
+
+ENTITY fir_buffer IS
+	PORT
+	(
+		data		: IN STD_LOGIC_VECTOR (31 DOWNTO 0);
+		rdaddress		: IN STD_LOGIC_VECTOR (9 DOWNTO 0);
+		rdclock		: IN STD_LOGIC ;
+		wraddress		: IN STD_LOGIC_VECTOR (9 DOWNTO 0);
+		wrclock		: IN STD_LOGIC  := '1';
+		wren		: IN STD_LOGIC  := '0';
+		q		: OUT STD_LOGIC_VECTOR (31 DOWNTO 0)
+	);
+END fir_buffer;
+
+
+ARCHITECTURE SYN OF fir_buffer IS
+
+	SIGNAL sub_wire0	: STD_LOGIC_VECTOR (31 DOWNTO 0);
+
+BEGIN
+	q    <= sub_wire0(31 DOWNTO 0);
+
+	altsyncram_component : altsyncram
+	GENERIC MAP (
+		address_aclr_b => "NONE",
+		address_reg_b => "CLOCK1",
+		clock_enable_input_a => "BYPASS",
+		clock_enable_input_b => "BYPASS",
+		clock_enable_output_b => "BYPASS",
+		intended_device_family => "MAX 10",
+		lpm_type => "altsyncram",
+		numwords_a => 1021,
+		numwords_b => 1021,
+		operation_mode => "DUAL_PORT",
+		outdata_aclr_b => "NONE",
+		outdata_reg_b => "CLOCK1",
+		power_up_uninitialized => "FALSE",
+		widthad_a => 10,
+		widthad_b => 10,
+		width_a => 32,
+		width_b => 32,
+		width_byteena_a => 1
+	)
+	PORT MAP (
+		address_a => wraddress,
+		address_b => rdaddress,
+		clock0 => wrclock,
+		clock1 => rdclock,
+		data_a => data,
+		wren_a => wren,
+		q_b => sub_wire0
+	);
+
+
+
+END SYN;
+
+-- ============================================================
+-- CNX file retrieval info
+-- ============================================================
+-- Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0"
+-- Retrieval info: PRIVATE: ADDRESSSTALL_B NUMERIC "0"
+-- Retrieval info: PRIVATE: BYTEENA_ACLR_A NUMERIC "0"
+-- Retrieval info: PRIVATE: BYTEENA_ACLR_B NUMERIC "0"
+-- Retrieval info: PRIVATE: BYTE_ENABLE_A NUMERIC "0"
+-- Retrieval info: PRIVATE: BYTE_ENABLE_B NUMERIC "0"
+-- Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8"
+-- Retrieval info: PRIVATE: BlankMemory NUMERIC "1"
+-- Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "0"
+-- Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_B NUMERIC "0"
+-- Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "0"
+-- Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_B NUMERIC "0"
+-- Retrieval info: PRIVATE: CLRdata NUMERIC "0"
+-- Retrieval info: PRIVATE: CLRq NUMERIC "0"
+-- Retrieval info: PRIVATE: CLRrdaddress NUMERIC "0"
+-- Retrieval info: PRIVATE: CLRrren NUMERIC "0"
+-- Retrieval info: PRIVATE: CLRwraddress NUMERIC "0"
+-- Retrieval info: PRIVATE: CLRwren NUMERIC "0"
+-- Retrieval info: PRIVATE: Clock NUMERIC "1"
+-- Retrieval info: PRIVATE: Clock_A NUMERIC "0"
+-- Retrieval info: PRIVATE: Clock_B NUMERIC "0"
+-- Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0"
+-- Retrieval info: PRIVATE: INDATA_ACLR_B NUMERIC "0"
+-- Retrieval info: PRIVATE: INDATA_REG_B NUMERIC "0"
+-- Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_B"
+-- Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0"
+-- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "MAX 10"
+-- Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0"
+-- Retrieval info: PRIVATE: JTAG_ID STRING "NONE"
+-- Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0"
+-- Retrieval info: PRIVATE: MEMSIZE NUMERIC "32672"
+-- Retrieval info: PRIVATE: MEM_IN_BITS NUMERIC "0"
+-- Retrieval info: PRIVATE: MIFfilename STRING ""
+-- Retrieval info: PRIVATE: OPERATION_MODE NUMERIC "2"
+-- Retrieval info: PRIVATE: OUTDATA_ACLR_B NUMERIC "0"
+-- Retrieval info: PRIVATE: OUTDATA_REG_B NUMERIC "1"
+-- Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0"
+-- Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_MIXED_PORTS NUMERIC "2"
+-- Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_A NUMERIC "3"
+-- Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_B NUMERIC "3"
+-- Retrieval info: PRIVATE: REGdata NUMERIC "1"
+-- Retrieval info: PRIVATE: REGq NUMERIC "0"
+-- Retrieval info: PRIVATE: REGrdaddress NUMERIC "1"
+-- Retrieval info: PRIVATE: REGrren NUMERIC "1"
+-- Retrieval info: PRIVATE: REGwraddress NUMERIC "1"
+-- Retrieval info: PRIVATE: REGwren NUMERIC "1"
+-- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
+-- Retrieval info: PRIVATE: USE_DIFF_CLKEN NUMERIC "0"
+-- Retrieval info: PRIVATE: UseDPRAM NUMERIC "1"
+-- Retrieval info: PRIVATE: VarWidth NUMERIC "0"
+-- Retrieval info: PRIVATE: WIDTH_READ_A NUMERIC "32"
+-- Retrieval info: PRIVATE: WIDTH_READ_B NUMERIC "32"
+-- Retrieval info: PRIVATE: WIDTH_WRITE_A NUMERIC "32"
+-- Retrieval info: PRIVATE: WIDTH_WRITE_B NUMERIC "32"
+-- Retrieval info: PRIVATE: WRADDR_ACLR_B NUMERIC "0"
+-- Retrieval info: PRIVATE: WRADDR_REG_B NUMERIC "0"
+-- Retrieval info: PRIVATE: WRCTRL_ACLR_B NUMERIC "0"
+-- Retrieval info: PRIVATE: enable NUMERIC "0"
+-- Retrieval info: PRIVATE: rden NUMERIC "0"
+-- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
+-- Retrieval info: CONSTANT: ADDRESS_ACLR_B STRING "NONE"
+-- Retrieval info: CONSTANT: ADDRESS_REG_B STRING "CLOCK1"
+-- Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "BYPASS"
+-- Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_B STRING "BYPASS"
+-- Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_B STRING "BYPASS"
+-- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "MAX 10"
+-- Retrieval info: CONSTANT: LPM_TYPE STRING "altsyncram"
+-- Retrieval info: CONSTANT: NUMWORDS_A NUMERIC "1021"
+-- Retrieval info: CONSTANT: NUMWORDS_B NUMERIC "1021"
+-- Retrieval info: CONSTANT: OPERATION_MODE STRING "DUAL_PORT"
+-- Retrieval info: CONSTANT: OUTDATA_ACLR_B STRING "NONE"
+-- Retrieval info: CONSTANT: OUTDATA_REG_B STRING "CLOCK1"
+-- Retrieval info: CONSTANT: POWER_UP_UNINITIALIZED STRING "FALSE"
+-- Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "10"
+-- Retrieval info: CONSTANT: WIDTHAD_B NUMERIC "10"
+-- Retrieval info: CONSTANT: WIDTH_A NUMERIC "32"
+-- Retrieval info: CONSTANT: WIDTH_B NUMERIC "32"
+-- Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1"
+-- Retrieval info: USED_PORT: data 0 0 32 0 INPUT NODEFVAL "data[31..0]"
+-- Retrieval info: USED_PORT: q 0 0 32 0 OUTPUT NODEFVAL "q[31..0]"
+-- Retrieval info: USED_PORT: rdaddress 0 0 10 0 INPUT NODEFVAL "rdaddress[9..0]"
+-- Retrieval info: USED_PORT: rdclock 0 0 0 0 INPUT NODEFVAL "rdclock"
+-- Retrieval info: USED_PORT: wraddress 0 0 10 0 INPUT NODEFVAL "wraddress[9..0]"
+-- Retrieval info: USED_PORT: wrclock 0 0 0 0 INPUT VCC "wrclock"
+-- Retrieval info: USED_PORT: wren 0 0 0 0 INPUT GND "wren"
+-- Retrieval info: CONNECT: @address_a 0 0 10 0 wraddress 0 0 10 0
+-- Retrieval info: CONNECT: @address_b 0 0 10 0 rdaddress 0 0 10 0
+-- Retrieval info: CONNECT: @clock0 0 0 0 0 wrclock 0 0 0 0
+-- Retrieval info: CONNECT: @clock1 0 0 0 0 rdclock 0 0 0 0
+-- Retrieval info: CONNECT: @data_a 0 0 32 0 data 0 0 32 0
+-- Retrieval info: CONNECT: @wren_a 0 0 0 0 wren 0 0 0 0
+-- Retrieval info: CONNECT: q 0 0 32 0 @q_b 0 0 32 0
+-- Retrieval info: GEN_FILE: TYPE_NORMAL fir_buffer.vhd TRUE
+-- Retrieval info: GEN_FILE: TYPE_NORMAL fir_buffer.inc FALSE
+-- Retrieval info: GEN_FILE: TYPE_NORMAL fir_buffer.cmp TRUE
+-- Retrieval info: GEN_FILE: TYPE_NORMAL fir_buffer.bsf FALSE
+-- Retrieval info: GEN_FILE: TYPE_NORMAL fir_buffer_inst.vhd FALSE
+-- Retrieval info: LIB_FILE: altera_mf
Index: atari_chips/pokeyv2/fir_filter.vhdl
===================================================================
--- atari_chips/pokeyv2/fir_filter.vhdl	(nonexistent)
+++ atari_chips/pokeyv2/fir_filter.vhdl	(revision 1454)
@@ -0,0 +1,325 @@
+---------------------------------------------------------------------------
+-- (c) 2024 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;
+use ieee.math_real.all;
+use IEEE.STD_LOGIC_MISC.all;
+
+ENTITY fir_filter IS
+GENERIC
+(
+	sample_bits : integer := 16;
+	filter_bits : integer := 16;
+	filter_len : integer := 2048
+);
+PORT 
+( 
+	FILTER_CLK : IN STD_LOGIC;
+	RESET_N : IN STD_LOGIC;
+
+	SAMPLE_ENABLE : IN STD_LOGIC;
+	SAMPLE_DATA : IN SIGNED(sample_bits-1 downto 0);
+
+	SAMPLE_OUT : OUT SIGNED(sample_bits-1 downto 0);
+
+	FLASH_CLK : IN STD_LOGIC;
+	FLASH_REQUEST : OUT STD_LOGIC;
+	FLASH_ADDRESS : OUT STD_LOGIC_VECTOR(9 downto 0);
+	FLASH_DATA : IN STD_LOGIC_VECTOR(31 downto 0);
+	FLASH_READY : IN STD_LOGIC
+);
+END fir_filter;
+
+ARCHITECTURE vhdl OF fir_filter IS
+	function log2c(n : integer) return integer is
+		variable m,p : integer;
+	begin
+		m := 0;
+		p := 1;
+		while p<n loop
+			m:=m+1;
+			p:=p*2;
+		end loop;
+		return m;
+	end log2c;
+
+	constant ADDR_WIDTH : natural := log2c(FILTER_LEN);
+	signal sample_ram_write_enable : std_logic;
+	signal sample_ram_address1 : std_logic_vector(ADDR_WIDTH-1 downto 0);
+	signal sample_ram_address2 : std_logic_vector(ADDR_WIDTH-1 downto 0);
+	signal sample_ram_data1_reg : std_logic_vector(SAMPLE_BITS-1 downto 0);
+	signal sample_ram_data1_next : std_logic_vector(SAMPLE_BITS-1 downto 0);
+	signal sample_ram_data2_reg : std_logic_vector(SAMPLE_BITS-1 downto 0);
+	signal sample_ram_data2_next : std_logic_vector(SAMPLE_BITS-1 downto 0);
+
+	signal sample_ram_write_address_reg : std_logic_vector(ADDR_WIDTH-1 downto 0);
+	signal sample_ram_write_address_next : std_logic_vector(ADDR_WIDTH-1 downto 0);
+
+	signal sample_ram_read_address1_reg : std_logic_vector(ADDR_WIDTH-1 downto 0);
+	signal sample_ram_read_address1_next : std_logic_vector(ADDR_WIDTH-1 downto 0);
+	signal sample_ram_read_address2_reg : std_logic_vector(ADDR_WIDTH-1 downto 0);
+	signal sample_ram_read_address2_next : std_logic_vector(ADDR_WIDTH-1 downto 0);
+
+	signal fir_rom_address_reg : std_logic_vector(ADDR_WIDTH-2 downto 0);
+	signal fir_rom_address_next : std_logic_vector(ADDR_WIDTH-2 downto 0);
+	signal fir_rom_data1_reg : std_logic_vector(FILTER_BITS-1 downto 0);
+	signal fir_rom_data1_next : std_logic_vector(FILTER_BITS-1 downto 0);
+	signal fir_rom_data2_reg : std_logic_vector(FILTER_BITS-1 downto 0);
+	signal fir_rom_data2_next : std_logic_vector(FILTER_BITS-1 downto 0);
+
+	signal mult1_reg : signed(SAMPLE_BITS+FILTER_BITS-1 downto 0);
+	signal mult1_next : signed(SAMPLE_BITS+FILTER_BITS-1 downto 0); -- up to 18x18
+	signal mult2_reg : signed(SAMPLE_BITS+FILTER_BITS-1 downto 0);
+	signal mult2_next : signed(SAMPLE_BITS+FILTER_BITS-1 downto 0); -- up to 18x18
+
+	signal accumulator_reg : signed(SAMPLE_BITS+FILTER_BITS-1 downto 0);
+	signal accumulator_next : signed(SAMPLE_BITS+FILTER_BITS-1 downto 0); -- up to 18x18
+
+	signal sample_out_reg : signed(SAMPLE_BITS-1 downto 0);
+	signal sample_out_next : signed(SAMPLE_BITS-1 downto 0);
+
+	signal state_reg : std_logic_vector(2 downto 0);
+	signal state_next : std_logic_vector(2 downto 0);
+	constant state_wait_sample : std_logic_vector(2 downto 0) := "001";
+	constant state_fir_prepare : std_logic_vector(2 downto 0) := "010";
+	constant state_fir_compute1 : std_logic_vector(2 downto 0) := "011";
+	constant state_fir_compute2 : std_logic_vector(2 downto 0) := "100";
+	constant state_fir_compute3 : std_logic_vector(2 downto 0) := "101";
+	constant state_fir_compute4 : std_logic_vector(2 downto 0) := "110";
+	constant state_fir_compute5 : std_logic_vector(2 downto 0) := "111";
+
+	-- Clock domain flash
+	signal fir_rom_write_enable : std_logic;
+	signal fir_rom_write_address_reg : std_logic_vector(ADDR_WIDTH-2 downto 0);
+	signal fir_rom_write_address_next : std_logic_vector(ADDR_WIDTH-2 downto 0);	
+	
+	signal flash_state_reg : std_logic_vector(1 downto 0);
+	signal flash_state_next : std_logic_vector(1 downto 0);
+	constant flash_state_init : std_logic_vector(1 downto 0) := "00";
+	constant flash_state_request : std_logic_vector(1 downto 0) := "01";
+	constant flash_state_wait : std_logic_vector(1 downto 0) := "10";
+	constant flash_state_done : std_logic_vector(1 downto 0) := "11";
+	
+	-- pipeline
+	-- rom->register
+	-- register->multiplier
+	-- multiplier->adder
+BEGIN
+	process(filter_clk,reset_n)
+	begin
+		if (reset_n='0') then
+			sample_ram_write_address_reg <= (others=>'0');
+			sample_ram_read_address1_reg <= (others=>'0');
+			sample_ram_read_address2_reg <= (others=>'0');
+			fir_rom_address_reg <= (others=>'0');
+			mult1_reg <= (others=>'0');
+			mult2_reg <= (others=>'0');
+			accumulator_reg <= (others=>'0');
+			sample_out_reg <= (others=>'0');
+			state_reg <= state_wait_sample;
+			sample_ram_data1_reg <= (others=>'0');
+			sample_ram_data2_reg <= (others=>'0');
+			fir_rom_data1_reg <= (others=>'0');
+			fir_rom_data2_reg <= (others=>'0');
+		elsif (filter_clk'event and filter_clk='1') then
+			sample_ram_write_address_reg <= sample_ram_write_address_next;
+			sample_ram_read_address1_reg <= sample_ram_read_address1_next;
+			sample_ram_read_address2_reg <= sample_ram_read_address2_next;
+			fir_rom_address_reg <= fir_rom_address_next;
+			mult1_reg <= mult1_next;
+			mult2_reg <= mult2_next;
+			accumulator_reg <= accumulator_next;
+			sample_out_reg <= sample_out_next;
+			state_reg <= state_next;
+			sample_ram_data1_reg <= sample_ram_data1_next;
+			sample_ram_data2_reg <= sample_ram_data2_next;
+			fir_rom_data1_reg <= fir_rom_data1_next;
+			fir_rom_data2_reg <= fir_rom_data2_next;
+		end if;
+	end process;
+	
+	process(flash_clk,reset_n)
+	begin
+		if (reset_n='0') then
+			flash_state_reg <= flash_state_init;
+			fir_rom_write_address_reg <= (others=>'0');
+		elsif (flash_clk'event and flash_clk='1') then
+			flash_state_reg <= flash_state_next;
+			fir_rom_write_address_reg <= fir_rom_write_address_next;		
+		end if;
+	end process;	
+
+	sample_buffer_inst : entity work.fir_sample_buffer
+	PORT MAP
+	(
+		address_a		=> sample_ram_address1,
+		address_b		=> sample_ram_address2,
+		clock		=> filter_clk,
+		data_a		=> std_logic_vector(sample_data),
+		data_b		=> (others=>'0'),
+		wren_a		=> sample_ram_write_enable,
+		wren_b		=> '0',
+		q_a		=> sample_ram_data1_next,
+		q_b		=> sample_ram_data2_next
+	);
+	
+	fir_data_inst : entity work.fir_buffer
+	PORT MAP
+	(
+	   rdclock => filter_clk,			  
+		rdaddress => fir_rom_address_reg,
+		q((filter_bits*2)-1 downto filter_bits) => fir_rom_data1_next,
+		q(filter_bits-1 downto 0) => fir_rom_data2_next,
+	
+		wrclock => flash_clk,
+		wraddress => fir_rom_write_address_reg,				
+		data => flash_data,
+		wren => fir_rom_write_enable
+	);
+
+	-- res = sum(Fi*Si)
+	-- so...
+	-- sample in -> store sample
+	-- iterate over filter and samples doing multiply and add
+	-- store result in register
+
+	process(state_reg,
+		sample_enable,
+		sample_ram_data1_reg,sample_ram_data2_reg,fir_rom_data1_reg,fir_rom_data2_reg,mult1_reg,mult2_reg,accumulator_reg,
+		sample_ram_write_address_reg,sample_ram_read_address1_reg, sample_ram_read_address2_reg,
+		fir_rom_address_reg,
+		sample_out_reg		
+	) is
+	begin
+		state_next <= state_reg;
+
+		sample_ram_write_address_next <= sample_ram_write_address_reg;
+
+		sample_ram_read_address1_next <= std_logic_vector(unsigned(sample_ram_read_address1_reg)-2);
+		sample_ram_read_address2_next <= std_logic_vector(unsigned(sample_ram_read_address2_reg)-2);
+		fir_rom_address_next <= std_logic_vector(unsigned(fir_rom_address_reg)+1);
+
+		sample_out_next <= sample_out_reg;
+
+		mult1_next <= signed(sample_ram_data1_reg) * signed(fir_rom_data1_reg);
+		mult2_next <= signed(sample_ram_data2_reg) * signed(fir_rom_data2_reg);
+		accumulator_next <= accumulator_reg + mult1_reg + mult2_reg;
+
+		sample_ram_write_enable <= '0';
+		sample_ram_address1 <= sample_ram_read_address1_reg;
+		sample_ram_address2 <= sample_ram_read_address2_reg;
+
+		if (sample_enable='1') then
+			sample_ram_write_address_next <= std_logic_vector(unsigned(sample_ram_write_address_reg)-1);
+		end if;
+
+		case state_reg is
+			when state_wait_sample =>
+				sample_ram_write_enable <= sample_enable;
+				sample_ram_address1 <= sample_ram_write_address_reg;
+				if (sample_enable='1') then
+					state_next <= state_fir_prepare;
+					--sample_ram_read_address1_next <= std_logic_vector(unsigned(sample_ram_write_address_reg) + to_unsigned(filter_len-1,ADDR_WIDTH));
+					--sample_ram_read_address2_next <= std_logic_vector(unsigned(sample_ram_write_address_reg) + to_unsigned(filter_len-2,ADDR_WIDTH));
+					sample_ram_read_address1_next <= std_logic_vector(unsigned(sample_ram_write_address_reg) + to_unsigned(0,ADDR_WIDTH));
+					sample_ram_read_address2_next <= std_logic_vector(unsigned(sample_ram_write_address_reg) + to_unsigned(-1,ADDR_WIDTH));
+					fir_rom_address_next <= (others=>'0');
+				end if;
+			when state_fir_prepare =>
+				state_next <= state_fir_compute1;
+			when state_fir_compute1 =>
+				state_next <= state_fir_compute2;
+			when state_fir_compute2 =>
+				state_next <= state_fir_compute3;
+			when state_fir_compute3 =>
+				state_next <= state_fir_compute4;
+				accumulator_next <= (others=>'0');
+			when state_fir_compute4 => --6
+				-- pipeline is ready, we have data to add to the accumulator
+				state_next <= state_fir_compute5;
+			when state_fir_compute5 =>
+				-- When entering this state we have the accum res
+				-- If we have fir length of 1, then it will be 0 in compute1,-1 in compute2 and -2 in compute3. So done==-2 (ffff...ffe)
+
+				if (fir_rom_address_reg = std_logic_vector(to_unsigned((filter_len/2)-1,ADDR_WIDTH-1) + 5)) then
+					state_next <= state_wait_sample;
+					sample_out_next <= accumulator_reg(FILTER_BITS+SAMPLE_BITS-2 downto FILTER_BITS-1);
+				end if;
+			when others=>
+				state_next <=state_wait_sample;
+		end case;
+
+	end process;
+	
+	-- write domain
+	process(flash_state_reg,
+		fir_rom_write_address_reg,
+		flash_ready
+	) is
+	begin
+		flash_state_next <= flash_state_reg;
+
+		fir_rom_write_address_next <= fir_rom_write_address_reg;
+		
+		fir_rom_write_enable <= '0';
+		flash_request <= '0';
+
+		case flash_state_reg is
+			when flash_state_init =>
+				fir_rom_write_address_next <= std_logic_vector(to_unsigned(filter_len/2-1,ADDR_WIDTH-1));
+				flash_state_next <= flash_state_request;
+			when flash_state_request =>
+				flash_request <= '1';
+				flash_state_next <= flash_state_wait;
+			when flash_state_wait =>			    
+				flash_request <= '1';
+				if (flash_ready = '1') then 
+					fir_rom_write_enable <= '1';
+					fir_rom_write_address_next <= std_logic_vector(unsigned(fir_rom_write_address_reg)-1);
+					flash_request <= '0';
+
+					if (or_reduce(fir_rom_write_address_reg)='0') then
+						flash_state_next <= flash_state_done;
+					else
+						flash_state_next <= flash_state_wait;
+					end if;
+				end if;
+			when flash_state_done =>
+				-- nothing
+				
+			when others=>
+				flash_state_next <=flash_state_init;
+		end case;
+	end process;	
+
+	-- outputs
+	sample_out <= sample_out_reg;
+	
+	FLASH_ADDRESS <= fir_rom_write_address_reg;
+
+end vhdl;
+
+--ARCHITECTURE rtl OF sync_rom IS
+--BEGIN
+--PROCESS (clock)
+--	BEGIN
+--	IF rising_edge (clock) THEN
+--		CASE address IS
+--			WHEN "00000000" => data_out <= "101111";
+--			WHEN "00000001" => data_out <= "110110";
+--			...
+--			WHEN "11111110" => data_out <= "000001";
+--			WHEN "11111111" => data_out <= "101010";
+--			WHEN OTHERS     => data_out <= "101111";
+--		END CASE;
+--	END IF;
+--	END PROCESS;
+--END rtl;
+
Index: atari_chips/pokeyv2/fir_rom.bin
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: atari_chips/pokeyv2/fir_rom.bin
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: atari_chips/pokeyv2/fir_sample_buffer.cmp
===================================================================
--- atari_chips/pokeyv2/fir_sample_buffer.cmp	(nonexistent)
+++ atari_chips/pokeyv2/fir_sample_buffer.cmp	(revision 1454)
@@ -0,0 +1,30 @@
+--Copyright (C) 2024  Intel Corporation. All rights reserved.
+--Your use of Intel Corporation's design tools, logic functions 
+--and other software and tools, and any partner logic 
+--functions, and any output files from any of the foregoing 
+--(including device programming or simulation files), and any 
+--associated documentation or information are expressly subject 
+--to the terms and conditions of the Intel Program License 
+--Subscription Agreement, the Intel Quartus Prime License Agreement,
+--the Intel FPGA IP License Agreement, or other applicable license
+--agreement, including, without limitation, that your use is for
+--the sole purpose of programming logic devices manufactured by
+--Intel and sold by Intel or its authorized distributors.  Please
+--refer to the applicable agreement for further details, at
+--https://fpgasoftware.intel.com/eula.
+
+
+component fir_sample_buffer
+	PORT
+	(
+		address_a		: IN STD_LOGIC_VECTOR (10 DOWNTO 0);
+		address_b		: IN STD_LOGIC_VECTOR (10 DOWNTO 0);
+		clock		: IN STD_LOGIC  := '1';
+		data_a		: IN STD_LOGIC_VECTOR (15 DOWNTO 0);
+		data_b		: IN STD_LOGIC_VECTOR (15 DOWNTO 0);
+		wren_a		: IN STD_LOGIC  := '0';
+		wren_b		: IN STD_LOGIC  := '0';
+		q_a		: OUT STD_LOGIC_VECTOR (15 DOWNTO 0);
+		q_b		: OUT STD_LOGIC_VECTOR (15 DOWNTO 0)
+	);
+end component;
Index: atari_chips/pokeyv2/fir_sample_buffer.qip
===================================================================
--- atari_chips/pokeyv2/fir_sample_buffer.qip	(nonexistent)
+++ atari_chips/pokeyv2/fir_sample_buffer.qip	(revision 1454)
@@ -0,0 +1,5 @@
+set_global_assignment -name IP_TOOL_NAME "RAM: 2-PORT"
+set_global_assignment -name IP_TOOL_VERSION "23.1"
+set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{MAX 10}"
+set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "fir_sample_buffer.vhd"]
+set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "fir_sample_buffer.cmp"]
Index: atari_chips/pokeyv2/fir_sample_buffer.vhd
===================================================================
--- atari_chips/pokeyv2/fir_sample_buffer.vhd	(nonexistent)
+++ atari_chips/pokeyv2/fir_sample_buffer.vhd	(revision 1454)
@@ -0,0 +1,225 @@
+-- megafunction wizard: %RAM: 2-PORT%
+-- GENERATION: STANDARD
+-- VERSION: WM1.0
+-- MODULE: altsyncram 
+
+-- ============================================================
+-- File Name: fir_sample_buffer.vhd
+-- Megafunction Name(s):
+-- 			altsyncram
+--
+-- Simulation Library Files(s):
+-- 			altera_mf
+-- ============================================================
+-- ************************************************************
+-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
+--
+-- 23.1std.1 Build 993 05/14/2024 SC Lite Edition
+-- ************************************************************
+
+
+--Copyright (C) 2024  Intel Corporation. All rights reserved.
+--Your use of Intel Corporation's design tools, logic functions 
+--and other software and tools, and any partner logic 
+--functions, and any output files from any of the foregoing 
+--(including device programming or simulation files), and any 
+--associated documentation or information are expressly subject 
+--to the terms and conditions of the Intel Program License 
+--Subscription Agreement, the Intel Quartus Prime License Agreement,
+--the Intel FPGA IP License Agreement, or other applicable license
+--agreement, including, without limitation, that your use is for
+--the sole purpose of programming logic devices manufactured by
+--Intel and sold by Intel or its authorized distributors.  Please
+--refer to the applicable agreement for further details, at
+--https://fpgasoftware.intel.com/eula.
+
+
+LIBRARY ieee;
+USE ieee.std_logic_1164.all;
+
+LIBRARY altera_mf;
+USE altera_mf.altera_mf_components.all;
+
+ENTITY fir_sample_buffer IS
+	PORT
+	(
+		address_a		: IN STD_LOGIC_VECTOR (10 DOWNTO 0);
+		address_b		: IN STD_LOGIC_VECTOR (10 DOWNTO 0);
+		clock		: IN STD_LOGIC  := '1';
+		data_a		: IN STD_LOGIC_VECTOR (15 DOWNTO 0);
+		data_b		: IN STD_LOGIC_VECTOR (15 DOWNTO 0);
+		wren_a		: IN STD_LOGIC  := '0';
+		wren_b		: IN STD_LOGIC  := '0';
+		q_a		: OUT STD_LOGIC_VECTOR (15 DOWNTO 0);
+		q_b		: OUT STD_LOGIC_VECTOR (15 DOWNTO 0)
+	);
+END fir_sample_buffer;
+
+
+ARCHITECTURE SYN OF fir_sample_buffer IS
+
+	SIGNAL sub_wire0	: STD_LOGIC_VECTOR (15 DOWNTO 0);
+	SIGNAL sub_wire1	: STD_LOGIC_VECTOR (15 DOWNTO 0);
+
+BEGIN
+	q_a    <= sub_wire0(15 DOWNTO 0);
+	q_b    <= sub_wire1(15 DOWNTO 0);
+
+	altsyncram_component : altsyncram
+	GENERIC MAP (
+		address_reg_b => "CLOCK0",
+		clock_enable_input_a => "BYPASS",
+		clock_enable_input_b => "BYPASS",
+		clock_enable_output_a => "BYPASS",
+		clock_enable_output_b => "BYPASS",
+		indata_reg_b => "CLOCK0",
+		intended_device_family => "MAX 10",
+		lpm_type => "altsyncram",
+		numwords_a => 2048,
+		numwords_b => 2048,
+		operation_mode => "BIDIR_DUAL_PORT",
+		outdata_aclr_a => "NONE",
+		outdata_aclr_b => "NONE",
+		outdata_reg_a => "CLOCK0",
+		outdata_reg_b => "CLOCK0",
+		power_up_uninitialized => "FALSE",
+		read_during_write_mode_mixed_ports => "DONT_CARE",
+		read_during_write_mode_port_a => "NEW_DATA_WITH_NBE_READ",
+		read_during_write_mode_port_b => "NEW_DATA_WITH_NBE_READ",
+		widthad_a => 11,
+		widthad_b => 11,
+		width_a => 16,
+		width_b => 16,
+		width_byteena_a => 1,
+		width_byteena_b => 1,
+		wrcontrol_wraddress_reg_b => "CLOCK0"
+	)
+	PORT MAP (
+		address_a => address_a,
+		address_b => address_b,
+		clock0 => clock,
+		data_a => data_a,
+		data_b => data_b,
+		wren_a => wren_a,
+		wren_b => wren_b,
+		q_a => sub_wire0,
+		q_b => sub_wire1
+	);
+
+
+
+END SYN;
+
+-- ============================================================
+-- CNX file retrieval info
+-- ============================================================
+-- Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0"
+-- Retrieval info: PRIVATE: ADDRESSSTALL_B NUMERIC "0"
+-- Retrieval info: PRIVATE: BYTEENA_ACLR_A NUMERIC "0"
+-- Retrieval info: PRIVATE: BYTEENA_ACLR_B NUMERIC "0"
+-- Retrieval info: PRIVATE: BYTE_ENABLE_A NUMERIC "0"
+-- Retrieval info: PRIVATE: BYTE_ENABLE_B NUMERIC "0"
+-- Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8"
+-- Retrieval info: PRIVATE: BlankMemory NUMERIC "1"
+-- Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "0"
+-- Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_B NUMERIC "0"
+-- Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "0"
+-- Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_B NUMERIC "0"
+-- Retrieval info: PRIVATE: CLRdata NUMERIC "0"
+-- Retrieval info: PRIVATE: CLRq NUMERIC "0"
+-- Retrieval info: PRIVATE: CLRrdaddress NUMERIC "0"
+-- Retrieval info: PRIVATE: CLRrren NUMERIC "0"
+-- Retrieval info: PRIVATE: CLRwraddress NUMERIC "0"
+-- Retrieval info: PRIVATE: CLRwren NUMERIC "0"
+-- Retrieval info: PRIVATE: Clock NUMERIC "0"
+-- Retrieval info: PRIVATE: Clock_A NUMERIC "0"
+-- Retrieval info: PRIVATE: Clock_B NUMERIC "0"
+-- Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0"
+-- Retrieval info: PRIVATE: INDATA_ACLR_B NUMERIC "0"
+-- Retrieval info: PRIVATE: INDATA_REG_B NUMERIC "1"
+-- Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_A"
+-- Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0"
+-- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "MAX 10"
+-- Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0"
+-- Retrieval info: PRIVATE: JTAG_ID STRING "NONE"
+-- Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0"
+-- Retrieval info: PRIVATE: MEMSIZE NUMERIC "32768"
+-- Retrieval info: PRIVATE: MEM_IN_BITS NUMERIC "1"
+-- Retrieval info: PRIVATE: MIFfilename STRING ""
+-- Retrieval info: PRIVATE: OPERATION_MODE NUMERIC "3"
+-- Retrieval info: PRIVATE: OUTDATA_ACLR_B NUMERIC "0"
+-- Retrieval info: PRIVATE: OUTDATA_REG_B NUMERIC "1"
+-- Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0"
+-- Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_MIXED_PORTS NUMERIC "2"
+-- Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_A NUMERIC "4"
+-- Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_B NUMERIC "4"
+-- Retrieval info: PRIVATE: REGdata NUMERIC "1"
+-- Retrieval info: PRIVATE: REGq NUMERIC "1"
+-- Retrieval info: PRIVATE: REGrdaddress NUMERIC "0"
+-- Retrieval info: PRIVATE: REGrren NUMERIC "0"
+-- Retrieval info: PRIVATE: REGwraddress NUMERIC "1"
+-- Retrieval info: PRIVATE: REGwren NUMERIC "1"
+-- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
+-- Retrieval info: PRIVATE: USE_DIFF_CLKEN NUMERIC "0"
+-- Retrieval info: PRIVATE: UseDPRAM NUMERIC "1"
+-- Retrieval info: PRIVATE: VarWidth NUMERIC "0"
+-- Retrieval info: PRIVATE: WIDTH_READ_A NUMERIC "16"
+-- Retrieval info: PRIVATE: WIDTH_READ_B NUMERIC "16"
+-- Retrieval info: PRIVATE: WIDTH_WRITE_A NUMERIC "16"
+-- Retrieval info: PRIVATE: WIDTH_WRITE_B NUMERIC "16"
+-- Retrieval info: PRIVATE: WRADDR_ACLR_B NUMERIC "0"
+-- Retrieval info: PRIVATE: WRADDR_REG_B NUMERIC "1"
+-- Retrieval info: PRIVATE: WRCTRL_ACLR_B NUMERIC "0"
+-- Retrieval info: PRIVATE: enable NUMERIC "0"
+-- Retrieval info: PRIVATE: rden NUMERIC "0"
+-- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
+-- Retrieval info: CONSTANT: ADDRESS_REG_B STRING "CLOCK0"
+-- Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "BYPASS"
+-- Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_B STRING "BYPASS"
+-- Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "BYPASS"
+-- Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_B STRING "BYPASS"
+-- Retrieval info: CONSTANT: INDATA_REG_B STRING "CLOCK0"
+-- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "MAX 10"
+-- Retrieval info: CONSTANT: LPM_TYPE STRING "altsyncram"
+-- Retrieval info: CONSTANT: NUMWORDS_A NUMERIC "2048"
+-- Retrieval info: CONSTANT: NUMWORDS_B NUMERIC "2048"
+-- Retrieval info: CONSTANT: OPERATION_MODE STRING "BIDIR_DUAL_PORT"
+-- Retrieval info: CONSTANT: OUTDATA_ACLR_A STRING "NONE"
+-- Retrieval info: CONSTANT: OUTDATA_ACLR_B STRING "NONE"
+-- Retrieval info: CONSTANT: OUTDATA_REG_A STRING "CLOCK0"
+-- Retrieval info: CONSTANT: OUTDATA_REG_B STRING "CLOCK0"
+-- Retrieval info: CONSTANT: POWER_UP_UNINITIALIZED STRING "FALSE"
+-- Retrieval info: CONSTANT: READ_DURING_WRITE_MODE_MIXED_PORTS STRING "DONT_CARE"
+-- Retrieval info: CONSTANT: READ_DURING_WRITE_MODE_PORT_A STRING "NEW_DATA_WITH_NBE_READ"
+-- Retrieval info: CONSTANT: READ_DURING_WRITE_MODE_PORT_B STRING "NEW_DATA_WITH_NBE_READ"
+-- Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "11"
+-- Retrieval info: CONSTANT: WIDTHAD_B NUMERIC "11"
+-- Retrieval info: CONSTANT: WIDTH_A NUMERIC "16"
+-- Retrieval info: CONSTANT: WIDTH_B NUMERIC "16"
+-- Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1"
+-- Retrieval info: CONSTANT: WIDTH_BYTEENA_B NUMERIC "1"
+-- Retrieval info: CONSTANT: WRCONTROL_WRADDRESS_REG_B STRING "CLOCK0"
+-- Retrieval info: USED_PORT: address_a 0 0 11 0 INPUT NODEFVAL "address_a[10..0]"
+-- Retrieval info: USED_PORT: address_b 0 0 11 0 INPUT NODEFVAL "address_b[10..0]"
+-- Retrieval info: USED_PORT: clock 0 0 0 0 INPUT VCC "clock"
+-- Retrieval info: USED_PORT: data_a 0 0 16 0 INPUT NODEFVAL "data_a[15..0]"
+-- Retrieval info: USED_PORT: data_b 0 0 16 0 INPUT NODEFVAL "data_b[15..0]"
+-- Retrieval info: USED_PORT: q_a 0 0 16 0 OUTPUT NODEFVAL "q_a[15..0]"
+-- Retrieval info: USED_PORT: q_b 0 0 16 0 OUTPUT NODEFVAL "q_b[15..0]"
+-- Retrieval info: USED_PORT: wren_a 0 0 0 0 INPUT GND "wren_a"
+-- Retrieval info: USED_PORT: wren_b 0 0 0 0 INPUT GND "wren_b"
+-- Retrieval info: CONNECT: @address_a 0 0 11 0 address_a 0 0 11 0
+-- Retrieval info: CONNECT: @address_b 0 0 11 0 address_b 0 0 11 0
+-- Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0
+-- Retrieval info: CONNECT: @data_a 0 0 16 0 data_a 0 0 16 0
+-- Retrieval info: CONNECT: @data_b 0 0 16 0 data_b 0 0 16 0
+-- Retrieval info: CONNECT: @wren_a 0 0 0 0 wren_a 0 0 0 0
+-- Retrieval info: CONNECT: @wren_b 0 0 0 0 wren_b 0 0 0 0
+-- Retrieval info: CONNECT: q_a 0 0 16 0 @q_a 0 0 16 0
+-- Retrieval info: CONNECT: q_b 0 0 16 0 @q_b 0 0 16 0
+-- Retrieval info: GEN_FILE: TYPE_NORMAL fir_sample_buffer.vhd TRUE
+-- Retrieval info: GEN_FILE: TYPE_NORMAL fir_sample_buffer.inc FALSE
+-- Retrieval info: GEN_FILE: TYPE_NORMAL fir_sample_buffer.cmp TRUE
+-- Retrieval info: GEN_FILE: TYPE_NORMAL fir_sample_buffer.bsf FALSE
+-- Retrieval info: GEN_FILE: TYPE_NORMAL fir_sample_buffer_inst.vhd FALSE
+-- Retrieval info: LIB_FILE: altera_mf
Index: atari_chips/pokeyv2/init.c
===================================================================
--- atari_chips/pokeyv2/init.c	(revision 1453)
+++ atari_chips/pokeyv2/init.c	(revision 1454)
@@ -413,6 +413,13 @@
 	}
 	fclose(f);
 
+	int fir_base = 0xc00*4;
+	unsigned short * fir = (unsigned short *)(buffer+fir_base);
+	FILE * fr =fopen("fir_rom.bin","rb");
+	        fread(fir,2,2032,fr);
+	fclose(fr);
+	
+
 	FILE * x =fopen("init_0.bin","w");
 		fwrite(&buffer[0],1,32768,x);
 	fclose(x);
Index: atari_chips/pokeyv2/pokeymax.vhd
===================================================================
--- atari_chips/pokeyv2/pokeymax.vhd	(revision 1453)
+++ atari_chips/pokeyv2/pokeymax.vhd	(revision 1454)
@@ -109,6 +109,17 @@
 END pokeymax;		
 		
 ARCHITECTURE vhdl OF pokeymax IS
+	component sigma_delta_adc is
+	port (
+    		clk : in std_logic;
+    		rst : in std_logic;
+    		adc_lvds_pin : in std_logic;
+    		adc_fb_pin : out std_logic;
+    		adc_output : out std_logic_vector(20 downto 0);
+    		adc_valid : out std_logic
+	);
+	end component;
+
 	component int_osc is
 	port (
 		clkout : out std_logic;        -- clkout.clk
@@ -439,18 +450,44 @@
 	signal PS2DAT : std_logic;
 
 	-- adc
-	signal sum_reg : unsigned(7 downto 0);
-	signal sum_next : unsigned(7 downto 0);
+	signal CLK49152 : std_logic;
 
-	signal sample_reg : unsigned(7 downto 0);
-	signal sample_next : unsigned(7 downto 0);
+	signal adc_reg : signed(15 downto 0);
+	signal adc_next : signed(15 downto 0);
 
-	signal toggle_reg : std_logic_vector(255 downto 0);
-	signal toggle_next : std_logic_vector(255 downto 0);
+	signal adc_use_reg : signed(15 downto 0);
+	signal adc_use_next : signed(15 downto 0);
 
-	signal ADC_FILTERED1 : unsigned(15 downto 0);	
-	signal ADC_FILTERED2 : unsigned(15 downto 0);	
+	signal adc_in_signed : signed(15 downto 0);
+	signal adc_out_signed : signed(15 downto 0);
+	
+	signal adc_min_reg : signed(11 downto 0);
+	signal adc_min_next : signed(11 downto 0);
 
+	signal adc_max_reg : signed(11 downto 0);
+	signal adc_max_next : signed(11 downto 0);
+
+	signal adc_diff_reg  : unsigned(11 downto 0);
+	signal adc_diff_next : unsigned(11 downto 0); 
+
+	signal adc_enabled_reg : unsigned(5 downto 0);
+	signal adc_enabled_next : unsigned(5 downto 0);
+
+	signal enable_reset_min_max_pre : std_logic;
+	signal enable_reset_min_max : std_logic;
+	
+	signal adc_valid : std_logic;
+	signal adc_output : std_logic_vector(20 downto 0);
+
+    	signal adc_lvds_pin : std_logic;
+    	signal adc_fb_pin : std_logic;
+
+	signal fir_data_request :std_logic;
+	signal fir_data_address :std_logic_vector(9 downto 0);
+	signal fir_data_ready :std_logic;
+
+	signal SIO_AUDIO : unsigned(15 downto 0);	
+
 	-- paddles
 	signal PADDLE_ADJ : std_logic_vector(7 downto 0);
 
@@ -539,6 +576,9 @@
 		flash_req7_addr(12 downto 9) => (others=>'0'),
 		flash_req7_addr(8 downto 0) => "11"&SATURATE_REG&POKEY_PROFILE_ADDR,  --TODO + init.bin
 
+		flash_req8_addr(12 downto 12) => (others=>'0'),
+		flash_req8_addr(11 downto 0) => "11"&FIR_DATA_ADDRESS,
+
 		flash_req_request(0) => CPU_FLASH_REQUEST_REG,
 		flash_req_request(1) => CONFIG_FLASH_REQUEST,
 		flash_req_request(2) => ADPCM_STEP_REQUEST,
@@ -546,7 +586,7 @@
 		flash_req_request(4) => SID_FLASH2_ROMREQUEST,
 		flash_req_request(5) => PSG_PROFILE_REQUEST,
 		flash_req_request(6) => POKEY_PROFILE_REQUEST,
-		flash_req_request(7 downto 7) => (others=>'0'),
+		flash_req_request(7) => FIR_DATA_REQUEST,
 		flash_req_complete(7 downto 0) => open,
 
 		flash_req_complete_slow(0) => CPU_FLASH_COMPLETE,
@@ -556,7 +596,7 @@
 		flash_req_complete_slow(4) => SID_FLASH2_ROMREADY,
 		flash_req_complete_slow(5) => PSG_PROFILE_READY,
 		flash_req_complete_slow(6) => POKEY_PROFILE_READY,
-		flash_req_complete_slow(7 downto 7) => open,
+		flash_req_complete_slow(7) => FIR_DATA_READY,
 
 		flash_data_out_slow => flash_do_slow
 	);
@@ -619,16 +659,18 @@
 			 c1 => CLK116,  --113ish
 			 c2 => CLK106,  --106ish
 			 locked => RESET_N);
+	CLK49152 <= '0';
 end generate;
 
 pll_v3_inst : if pll_v2=0 generate
 	pll_inst : pllv3
 	PORT MAP(inclk0 => CLK0, --49.192 (50 on prototype)
-			 c0 => CLK, --49.192 
-			 c1 => CLK116,  --113ish
+			 c0 => CLK, --56ish
+			 c1 => CLK116,  --56ish
 			 c2 => CLK106,  --106ish
 			 c3 => CLK6144,  --6.44MHz
 			 locked => RESET_N);
+	CLK49152 <= CLK0;
 end generate;
 
 
@@ -1748,7 +1790,7 @@
 	CH9 => unsigned(PSG_AUDIO(1)),		
 	CHA(14 downto 0) => (others=>'0'),
 	CHA(15) => GTIA_AUDIO,			
-	CHB => ADC_FILTERED2,			
+	CHB => SIO_AUDIO,			
 	
 	AUDIO_0_UNSIGNED => AUDIO_0_UNSIGNED,
 	AUDIO_1_UNSIGNED => AUDIO_1_UNSIGNED,
@@ -1913,6 +1955,12 @@
 
 iox_off : if enable_iox=0 generate 
 	iox_keyboard_response <= KR2&KR1;
+--	k(0) <= '0' when keyboard_scan(0)='0' else 'Z';
+--	k(1) <= '0' when keyboard_scan(1)='0' else 'Z';
+--	k(2) <= '0' when keyboard_scan(2)='0' else 'Z';
+--	k(3) <= '0' when keyboard_scan(3)='0' else 'Z';
+--	k(4) <= '0' when keyboard_scan(4)='0' else 'Z';
+--	k(5) <= '0' when keyboard_scan(5)='0' else 'Z';
 	k <= keyboard_scan;
 end generate iox_off;
 
@@ -1959,23 +2007,46 @@
 end generate ps2_off;
 
 adc_on : if enable_adc=1 generate 
+
+ -- Proper ADC for SIO/PBI audio in
+	sdelta : sigma_delta_adc
+	port map(
+		clk=>CLK49152,
+		rst=>not(reset_n),
+
+		adc_lvds_pin => adc_lvds_pin,
+		adc_fb_pin => adc_fb_pin,
+		
+    		adc_output => adc_output,
+    		adc_valid => adc_valid
+	);
+
+--	adc_valid <= '1';
+--	adc_output <= x"abcd";
+
  -- Simple ADC for SIO/PBI audio in
-	 process(clk,reset_n)
+	 process(CLK49152,reset_n)
 	 begin
 	   if (reset_n='0') then
-			toggle_reg <= (others=>'0');
-			sum_reg <= (others=>'0');
-			sample_reg <= (others=>'0');
-		elsif (clk'event and clk='1') then
-			toggle_reg <= toggle_next;
-			sum_reg <= sum_next;
-			sample_reg <= sample_next;
+			adc_reg <= (others=>'0');
+			adc_enabled_reg <= (others=>'0');
+			adc_use_reg <= (others=>'0');
+			adc_min_reg <= (others=>'1');
+			adc_max_reg <= (others=>'0');			
+			adc_diff_reg <= (others=>'0');			
+		elsif (CLK49152'event and CLK49152='1') then
+			adc_reg <= adc_next;
+			adc_enabled_reg <= adc_enabled_next;
+			adc_use_reg <= adc_use_next;
+			adc_min_reg <= adc_min_next;
+			adc_max_reg <= adc_max_next;
+			adc_diff_reg <= adc_diff_next;
 		end if;
 	 end process;	
 	 
 	 lvds_tx0: lvds_tx
 	 port map(
-	 	tx_in(0) => toggle_reg(0),
+	 	tx_in(0) => adc_fb_pin,
 	 	tx_out(0) => ADC_TX_P
 	 );
 	
@@ -1982,48 +2053,102 @@
 	 lvds_rx0: lvds_rx
 	 port map(
 	 	data(0) => ADC_RX_P,
-	 	clock => CLK,
-	 	q(0) => toggle_next(0)
+	 	clock => CLK49152,
+	 	q(0) => adc_lvds_pin
 	 );
-	 toggle_next(255 downto 1) <= toggle_reg(254 downto 0);
 	 
-adcfilter : entity work.simple_low_pass_filter
+	adc_in_signed <= adc_reg; --signed(not(adc_use_reg(15))&adc_use_reg(14 downto 0));
+	--adc_in_signed <= signed(not(adc_use_reg(15))&adc_use_reg(14 downto 0));
+	--adc_in_signed <= to_signed(1024,16);
+adcfirfilter : entity work.fir_filter
+GENERIC MAP
+(
+	filter_len => 2032
+)
 PORT  MAP
 ( 
-	CLK => CLK,
-	AUDIO_IN => not(sample_reg(7)&sample_reg(6 downto 0))&"00000000",
-	SAMPLE_IN => ENABLE_CYCLE,
-	AUDIO_OUT => ADC_FILTERED1
-);
+	FILTER_CLK => CLK49152,
+	RESET_N => RESET_N,
+	SAMPLE_ENABLE => adc_valid,
+	SAMPLE_DATA => adc_in_signed,
+	SAMPLE_OUT => adc_out_signed,
 
-adcfilter2 : entity work.simple_low_pass_filter
-PORT  MAP
-( 
-	CLK => CLK,
-	AUDIO_IN => ADC_FILTERED1,
-	SAMPLE_IN => ENABLE_CYCLE,
-	AUDIO_OUT => ADC_FILTERED2
+	FLASH_CLK => CLK,
+	FLASH_REQUEST => FIR_DATA_REQUEST,
+	FLASH_ADDRESS => FIR_DATA_ADDRESS,
+	FLASH_DATA => flash_do_slow,
+	FLASH_READY => FIR_DATA_READY
 );
+	SIO_AUDIO <= unsigned(not(adc_use_reg(15))&adc_use_reg(14 downto 0));
 
-process(sum_reg,sample_reg,toggle_reg)
+enable_div : work.enable_divider
+	generic map (COUNT=>128)
+	port map(clk=>CLK49152,reset_n=>reset_n,enable_in=>'1',enable_out=>enable_reset_min_max_pre);
+
+enable_div2 : work.enable_divider
+	generic map (COUNT=>128)
+	port map(clk=>CLK49152,reset_n=>reset_n,enable_in=>enable_reset_min_max_pre,enable_out=>enable_reset_min_max);
+
+process(adc_reg,adc_output,adc_valid)
+	variable adc_shrunk : signed(20 downto 0);
 begin
-	sum_next <= sum_reg;	
-	sample_next <= sample_reg;
+	adc_next <= adc_reg;
 
-	if (toggle_reg(255)='1' and toggle_reg(0)='0') then
-		sum_next <= sum_reg -1;
-	elsif (toggle_reg(255)='0' and toggle_reg(0)='1') then
-		sum_next <= sum_reg +1;
+	if (adc_valid='1') then
+		adc_shrunk := signed(not(adc_output(20)) & adc_output(19 downto 0));
+		adc_next <= adc_shrunk(18 downto (18-16+1)); --*2
 	end if;	
+end process;
 
-	sample_next <= sum_reg;
+process(adc_out_signed,adc_min_reg,adc_max_reg,adc_diff_reg,enable_reset_min_max,adc_enabled_reg)
+	variable detected : std_logic;
+begin
+	adc_min_next <= adc_min_reg;
+	adc_max_next <= adc_max_reg;
+	adc_diff_next <= unsigned(adc_max_reg-adc_min_reg);
+	adc_enabled_next <= adc_enabled_reg;
+
+	if (adc_out_signed(15 downto 4)<adc_min_reg) then
+		adc_min_next <= adc_out_signed(15 downto 4);
+	end if;
+
+	if (adc_out_signed(15 downto 4)>adc_max_reg) then
+		adc_max_next <= adc_out_signed(15 downto 4);
+	end if;	
+	
+	if (enable_reset_min_max='1') then
+	   detected := '0';
+		if (adc_diff_reg>16) then
+			detected := '1';
+		end if;	
+		if (detected='1' and adc_enabled_reg<63) then
+			adc_enabled_next <= adc_enabled_reg+1;
+		end if;
+		if (detected='0' and adc_enabled_reg>0) then
+			adc_enabled_next <= adc_enabled_reg-1;
+		end if;		
+		adc_min_next(11) <= '0';
+		adc_min_next(10 downto 0) <= (others=>'1');
+		adc_max_next(11) <= '1';
+		adc_max_next(10 downto 0) <= (others=>'0');
+	end if;
 end process;
+
+process(adc_reg,adc_enabled_reg,adc_out_signed)
+begin
+	adc_use_next <= adc_use_reg;
+	if (adc_enabled_reg>=32) then
+		adc_use_next <= adc_out_signed;
+	end if;
+end process;
+
+
 end generate adc_on;
 
 adc_off : if enable_adc=0 generate 
-	ADC_FILTERED2(15 downto 12) <= (others=>'0');
-	ADC_FILTERED2(11) <= SIO_RXD_SYNC;
-	ADC_FILTERED2(10 downto 0) <= (others=>'0');
+	SIO_AUDIO(15 downto 12) <= (others=>'0');
+	SIO_AUDIO(11) <= SIO_RXD_SYNC;
+	SIO_AUDIO(10 downto 0) <= (others=>'0');
 end generate adc_off;
 
 paddle_lvds_on : if paddle_lvds=1 generate 
Index: atari_chips/pokeyv2/pokeymaxv4.qsf
===================================================================
--- atari_chips/pokeyv2/pokeymaxv4.qsf	(revision 1453)
+++ atari_chips/pokeyv2/pokeymaxv4.qsf	(revision 1454)
@@ -180,6 +180,26 @@
 set_location_assignment PIN_L1 -to K[5]   #LVLB22,
 set_location_assignment PIN_K1 -to KR2    #LVLB23,
 
+set_instance_assignment -name CURRENT_STRENGTH_NEW "2MA" -to K[0]
+set_instance_assignment -name CURRENT_STRENGTH_NEW "2MA" -to K[1]
+set_instance_assignment -name CURRENT_STRENGTH_NEW "2MA" -to K[2]
+set_instance_assignment -name CURRENT_STRENGTH_NEW "2MA" -to K[3]
+set_instance_assignment -name CURRENT_STRENGTH_NEW "2MA" -to K[4]
+set_instance_assignment -name CURRENT_STRENGTH_NEW "2MA" -to K[5]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to K[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to K[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to K[2]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to K[3]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to K[4]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to K[5]
+
+#set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to K[0]
+#set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to K[1]
+#set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to K[2]
+#set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to K[3]
+#set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to K[4]
+#set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to K[5]
+
 set_location_assignment PIN_G9 -to CLK_SLOW  #CLK2 - G9
 set_location_assignment PIN_H8 -to CLK_OUT   #OUT  - H8
 set_location_assignment PIN_E13 -to CLK0    
@@ -258,6 +278,8 @@
 set_global_assignment -name VHDL_FILE sigmadelta_1storder.vhd
 set_global_assignment -name VHDL_FILE sigmadelta_2ndorder.vhd
 set_global_assignment -name VHDL_FILE filtered_sigmadelta.vhd
+set_global_assignment -name VHDL_FILE fir_filter.vhdl
+set_global_assignment -name VHDL_FILE fir_rom.vhdl
 set_global_assignment -name VHDL_FILE generic_ram_infer.vhdl
 set_global_assignment -name VHDL_FILE simple_low_pass_filter.vhdl
 set_global_assignment -name VHDL_FILE pokey/pokey_poly_17_9.vhdl
@@ -300,12 +322,19 @@
 set_global_assignment -name VHDL_FILE sample/adpcm.vhdl
 set_global_assignment -name VHDL_FILE sample/top.vhdl
 set_global_assignment -name VHDL_FILE covox/top.vhdl
+set_global_assignment -name SYSTEMVERILOG_FILE sigma_delta/sigma_delta_adc.sv
+set_global_assignment -name SYSTEMVERILOG_FILE sigma_delta/cic_comb.sv
+set_global_assignment -name SYSTEMVERILOG_FILE sigma_delta/cic_integrator.sv
+set_global_assignment -name SYSTEMVERILOG_FILE sigma_delta/fir_compensator.sv
 set_global_assignment -name QIP_FILE int_osc/synthesis/int_osc.qip
 set_global_assignment -name QIP_FILE pll.qip
+set_global_assignment -name QIP_FILE pllv3.qip
 set_global_assignment -name QIP_FILE flash/synthesis/flash.qip
 set_global_assignment -name QIP_FILE lvds_tx.qip
 set_global_assignment -name QIP_FILE lvds_rx.qip
 set_global_assignment -name QIP_FILE paddle_gpio.qip
+set_global_assignment -name QIP_FILE fir_sample_buffer.qip
+set_global_assignment -name QIP_FILE fir_buffer.qip
 
 
 set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
Index: atari_chips/pokeyv2/sigma_delta/cic_comb.sv
===================================================================
--- atari_chips/pokeyv2/sigma_delta/cic_comb.sv	(nonexistent)
+++ atari_chips/pokeyv2/sigma_delta/cic_comb.sv	(revision 1454)
@@ -0,0 +1,33 @@
+// Dave Muscle
+
+//Decimator designed for use in a multi-stage CIC filter
+
+/*
+    x[n] --|---------> + ----> y[n]
+           |           x (-1)
+           ---[z^-1]-->|
+*/
+
+module cic_comb #(
+    parameter int WIDTH = 32
+)(
+    input  bit clk,
+    input  bit rst,
+    input  bit ena,
+    input  bit [WIDTH-1:0] data_in ,
+    output bit [WIDTH-1:0] data_out
+);
+    bit [WIDTH-1:0] r_data;
+
+    always_ff @(posedge clk) begin
+        if(ena) begin
+            r_data <= data_in ;
+            data_out <= r_data - data_in ;
+        end
+        if(rst) begin
+            data_out <= 0;
+            r_data <= 0;
+        end
+    end
+
+endmodule: cic_comb
Index: atari_chips/pokeyv2/sigma_delta/cic_integrator.sv
===================================================================
--- atari_chips/pokeyv2/sigma_delta/cic_integrator.sv	(nonexistent)
+++ atari_chips/pokeyv2/sigma_delta/cic_integrator.sv	(revision 1454)
@@ -0,0 +1,30 @@
+// Dave Muscle
+
+//Integrator designed for use in a multi-stage CIC filter
+
+/*
+    x[n] ---> + --> y[n] --->
+              |             |
+              |<--[z^-1]----| 
+*/
+
+module cic_integrator #(
+    parameter int WIDTH = 32
+)(
+    input  bit clk,
+    input  bit rst,
+    input  bit ena,
+    input  bit [WIDTH-1:0] data_in ,
+    output bit [WIDTH-1:0] data_out
+);
+
+    always_ff @(posedge clk) begin
+        if(ena) begin
+            data_out <= data_out + data_in ;
+        end
+        if(rst) begin
+            data_out <= 0;
+        end
+    end
+
+endmodule: cic_integrator
Index: atari_chips/pokeyv2/sigma_delta/fir_compensator.sv
===================================================================
--- atari_chips/pokeyv2/sigma_delta/fir_compensator.sv	(nonexistent)
+++ atari_chips/pokeyv2/sigma_delta/fir_compensator.sv	(revision 1454)
@@ -0,0 +1,107 @@
+// DaveMuscle
+
+// Multiplier-less FIR compensator meant for post-processing CIC filters
+// ALPHA is reduced to a fraction out of 8, eg: 0.358 -> 0.375 = 3/8
+// Implicitly casts data to signed format, unsigned will not work
+
+//https://dsp.stackexchange.com/questions/19584/how-to-make-cic-compensation-filter
+
+/*
+    x[n] ------> [ z^-1 ] -----
+           |                  |
+           + <-- [ z^-1 ] ----| 
+           |                  x (1+a)
+    (-a/2) x                  |
+           |                  |
+           -------------------+---> y[n]
+*/
+
+module fir_compensator #(
+    parameter int WIDTH = 32,
+    parameter int ALPHA_8 = 2
+)(
+    input bit clk,
+    input bit rst,
+    input bit ena,
+    input  bit [WIDTH-1:0] data_in ,
+    output bit [WIDTH-1:0] data_out
+);
+
+    bit signed [WIDTH-1:0] d1, d2;
+    bit signed [WIDTH-1:0] sum, dly;
+    
+    bit signed [WIDTH-1:0] sum_mult;
+    bit signed [WIDTH-1:0] dly_mult;
+    bit signed [WIDTH-1:0] dly_dly;
+
+    // h = (-a / 2) * (n'' + n) + (1+a)*n'
+
+    // multiply by 'a/2' on the intermediate sum (n'' + n) and 'a' on the delay ( n')
+    always_comb begin
+        int i;
+        bit signed [WIDTH-1:0] d[2];
+        bit signed [WIDTH-1:0] e[2];
+        bit signed [WIDTH-1:0] f[2];
+        bit signed [WIDTH-1:0] h[2];
+        bit signed [WIDTH-1:0] s[2];
+
+        //shift amounts 
+        //   ALPHA_8 = 1 --> 0.125 == 1/8
+        //   ALPHA_8 = 2 --> 0.250 == 1/4
+        //   ALPHA_8 = 3 --> 0.375 == 1/4 + 1/8
+        //   ALPHA_8 = 4 --> 0.500 == 1/2
+        //   ALPHA_8 = 5 --> 0.625 == 1/2 + 1/8
+        //   ALPHA_8 = 6 --> 0.750 == 1/2 + 1/4
+        //   ALPHA_8 = 7 --> 0.875 == 1/2 + 1/4 + 1/8
+
+        d[0] = sum;
+        d[1] = dly;
+
+        //shifts
+        for(i = 0; i < 2; i = i + 1) begin
+            e[i] = 0;
+            f[i] = 0;
+            h[i] = 0;
+            if((ALPHA_8 % 2) == 1) begin
+                e[i] = d[i] >>> 3;
+            end
+            if((ALPHA_8 & 3) >= 2) begin
+                f[i] = d[i] >>> 2; 
+            end
+            if(ALPHA_8 >= 4) begin
+                h[i] = d[i] >>> 1;
+            end
+            //do the sum
+            if(ALPHA_8 == 0) begin
+                s[i] = 0;
+            end
+            else if(ALPHA_8 == 8) begin
+                s[i] = sum;
+            end
+            else begin
+                s[i] = e[i] + f[i] + h[i];
+            end
+        end
+        sum_mult = s[0] >>> 1;
+        dly_mult = s[1];
+        dly_dly  = d[1];
+    end
+
+    always_ff @(posedge clk) begin
+        if(ena) begin
+            d1 <= data_in ;
+            d2 <= d1;
+            sum <= d2 + data_in ;
+            dly <= d1;
+            data_out <= ~sum_mult + 1 + dly_dly + dly_mult;
+        end
+        if(rst) begin
+            d1 <= 0;
+            d2 <= 0;
+            sum <= 0;
+            dly <= 0;
+            data_out <= 0;
+        end
+    end
+
+endmodule: fir_compensator
Index: atari_chips/pokeyv2/sigma_delta/sigma_delta_adc.sv
===================================================================
--- atari_chips/pokeyv2/sigma_delta/sigma_delta_adc.sv	(nonexistent)
+++ atari_chips/pokeyv2/sigma_delta/sigma_delta_adc.sv	(revision 1454)
@@ -0,0 +1,140 @@
+// Dave Muscle
+
+// Sigma Delta ADC in FPGA
+
+module sigma_delta_adc #(
+    parameter int OVERSAMPLE_RATE = 1024,
+    parameter int CIC_STAGES = 2,
+    parameter int ADC_BITLEN = 21,
+    parameter bit USE_FIR_COMP = 1,
+    parameter int FIR_COMP_ALPHA_8 = 2
+)(
+    input bit clk,
+    input bit rst, //reset for optional power saving
+
+    input bit adc_lvds_pin, // connect to analog input
+    output bit adc_fb_pin,  // connect to integrator
+
+    output bit [ADC_BITLEN-1:0] adc_output, //digital output
+    output bit adc_valid              //signals valid output
+
+);
+    
+    //add an extra bit to pad a sign bit for underflows
+    localparam int CIC_BITLEN = 1 + 1 + int'((CIC_STAGES * $clog2(OVERSAMPLE_RATE)));
+
+    bit adc_in;
+
+    //decimator signals
+    localparam CNT_ADC_BITLEN = $clog2(OVERSAMPLE_RATE);
+    bit [CNT_ADC_BITLEN-1:0] dec_cnt = 0;
+    const bit [CNT_ADC_BITLEN-1:0] dec_cmp = CNT_ADC_BITLEN'(OVERSAMPLE_RATE-1);
+    bit dec_ena = 0;
+
+    //comb/integrator signals
+    bit [CIC_BITLEN-1:0] cic_inte_data [CIC_STAGES:0] = '{default:0};
+    bit [CIC_BITLEN-1:0] cic_comb_data [CIC_STAGES:0] = '{default:0};
+    
+    //sample analog input connected to lvds positive
+    always_ff @(posedge clk) begin
+        //sample input
+        adc_in <= adc_lvds_pin;
+        //feedback output connected to lvds negative
+        adc_fb_pin <= adc_lvds_pin;
+        //decimator control
+        dec_cnt <= dec_cnt + CNT_ADC_BITLEN'(1);
+        if(dec_cnt == dec_cmp) begin
+            dec_ena <= 1;
+        end
+        else begin
+            dec_ena <= 0;
+        end
+        //reset 
+        if(rst) begin
+            adc_in <= 0;
+            dec_cnt <= 0;
+        end
+    end
+
+    //assign first values to array
+    always_comb begin
+        cic_inte_data[0] = CIC_BITLEN'(adc_in);
+        cic_comb_data[0] = cic_inte_data[CIC_STAGES];
+    end
+
+    //place cic decimator
+    genvar i;
+    generate
+        for(i = 0; i < CIC_STAGES; i = i + 1) begin: gen_cic
+            cic_integrator #(
+                .WIDTH(CIC_BITLEN)
+            ) cic_inst_u0 (
+                .clk(clk), 
+                .rst(rst),
+                .ena(1'b1),
+                .data_in (cic_inte_data[i]),
+                .data_out(cic_inte_data[i+1])
+            );
+            cic_comb #(
+                .WIDTH(CIC_BITLEN)
+            ) cic_inst_u1 (
+                .clk(clk),
+                .rst(rst),
+                .ena(dec_ena),
+                .data_in (cic_comb_data[i]),
+                .data_out(cic_comb_data[i+1])
+            );
+        end
+    endgenerate
+
+    bit [CIC_BITLEN-1:0] fir_data;
+    bit [CIC_BITLEN-1:0] post_fir_data;
+
+    //place optional fir compensator
+    generate
+    if(USE_FIR_COMP) begin: gen_fir
+        fir_compensator #(
+            .WIDTH(CIC_BITLEN),
+            .ALPHA_8(FIR_COMP_ALPHA_8)
+        ) fir_comp_u0 (
+            .clk(clk),
+            .rst(rst),
+            .ena(dec_ena),
+            .data_in (cic_comb_data[CIC_STAGES]),
+            .data_out(fir_data)
+        );
+    end
+    endgenerate
+    
+    //switch between fir and cic path
+    always_comb begin
+        if(USE_FIR_COMP) begin
+            post_fir_data = fir_data;
+        end
+        else begin
+            post_fir_data = cic_comb_data[CIC_STAGES];
+        end
+    end
+
+    //assign output, do saturation if too high or low
+    //tested in sim with a sine input twice the fullscale voltage
+    always_ff @(posedge clk) begin
+        localparam cmp =  (2**ADC_BITLEN)-1;
+        adc_valid <= dec_ena;
+        //clip underflow
+        if(post_fir_data[CIC_BITLEN-1]) begin
+            adc_output <= 0;
+        end
+        //clip overflow
+        else if(post_fir_data > CIC_BITLEN'(cmp)) begin
+            adc_output <= ADC_BITLEN'(cmp);
+        end
+        //just assign normally
+        else begin
+            adc_output <= ADC_BITLEN'(post_fir_data);
+        end
+    end
+
+
+
+endmodule: sigma_delta_adc
