diff --git a/rc_filter_1o.vhd b/rc_filter_1o.vhd new file mode 100644 index 0000000..a6b0da0 --- /dev/null +++ b/rc_filter_1o.vhd @@ -0,0 +1,134 @@ +------------------------------------------------------------------------------- +-- +-- Basic RC low/highpass filter implemented as IIR filter for FPGA usage +-- +-- (c) copyright 2013...2015 by WoS (Wolfgang Scherr) +-- http://www.pin4.at - WoS pin4 at +-- +-- All rights reserved. Use at your own risk. +-- +-- This basic RC math can be found in similar fashion e.g. on the English Wiki +-- http://en.wikipedia.org/wiki/Low-pass_filter +-- +------------------------------------------------------------------------------- +-- Contributors: +-- +-- Status: functional +-- +-- SVN: $Id: rc_filter_1o.vhd 1328 2015-05-22 19:29:53Z wolfgang.scherr $ +-- +-- Change list: +-- Wolfgang: initial set up +-- +---------------------------------------------------------------------- +-- Redistribution and use in source or synthesized forms are permitted +-- provided that the following conditions are met (or a prior written +-- permission was given otherwise): +-- +-- * Redistributions of source code must retain this original header +-- incl. author, contributors, conditions, copyright and disclaimer. +-- +-- * Redistributions in synthesized (binary) form must also contain +-- the soure code according to this conditions to keep it "open". +-- +-- * Neither the name of the author nor the names of contributors may +-- be used to endorse or promote products derived from this code. +-- +-- * This code is only allowed to be used on: +-- - Replay hardware (from fpgaarcade.com) +-- +-- * Feedback or bug reports are welcome, but please check on the +-- web sites given in the header first for any updates available. +-- +-- * You are responsible for any legal issues arising from your use +-- or your own distribution of this code. +---------------------------------------------------------------------- +-- THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +-- FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +-- AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +-- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +-- STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS CODE OR ANY WORK +-- PRODUCTS, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +---------------------------------------------------------------------- +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.STD_LOGIC_ARITH.ALL; + +entity rc_filter_1o is + generic ( dwidthi_g : natural := 8; -- bitwidth of the (digital) source + dwidtho_g : natural := 8; -- output may use a different width (but <=dwidthi_g+cwidth_g) + R_ohms_g : natural := 1000; -- 1kOhms \ exemplary LP + C_p_farads_g : natural := 10000; -- 10 nF / with ~16kHz fg + fclk_hz_g : natural := 8867236; -- set accordingly to your clk_i+clken_i period + highpass_g : boolean := true; -- lowpass (unsigned out, gain=1.0) when false, highpass (signed out, gain=0.5) when true + cwidth_g : natural := 12); -- adopt resolution for RC and fclk (-> alpha factor) + Port ( clk_i : in std_logic; + clken_i : in std_logic; + res_i : in std_logic; + din_i : in std_logic_vector(dwidthi_g-1 downto 0); -- range: 0...(2^dwidthi_g)-1 + dout_o : out std_logic_vector(dwidtho_g-1 downto 0) -- range: 0...(2^dwidtho_g)-1 + ); +end rc_filter_1o; + +architecture RTL of rc_filter_1o is + +-- alpha factor for the IIR filter, classic "textbook" implementation +constant tau : real := real(R_ohms_g*C_p_farads_g)/1.0E12; -- s +constant tsamp : real := 1.0/real(fclk_hz_g); -- s +constant alpha_c : real := tsamp/(tau+tsamp); + +-- digitising the alpha factor, including some checks (shown as assert later on) +constant dig_alpha_c : integer := integer((2.0**cwidth_g)*alpha_c); +constant acheck_c : real := real(dig_alpha_c)/(2.0**cwidth_g); +constant aerror_c : real := 100.0*ABS(acheck_c-alpha_c)/acheck_c; + +-- internal bitwidth depends on the FP decimals of the alpha factor and the input bit width +signal dlocal_s : signed (dwidthi_g+cwidth_g downto 0); + +begin + -- print actual digitised alpha value and its error + assert false report "Using alpha: " & natural'image(dig_alpha_c) & " (= " & real'image(acheck_c) & ")" severity note; + assert false report "Alpha error: " & real'image(aerror_c) & "%" severity note; + + -- the main IIC routine, classic "textbook" implementation + iir_proc : process (res_i, clk_i) is + begin + if (res_i = '1') then + dlocal_s <= (others => '0'); + elsif rising_edge(clk_i) then + if (clken_i = '1') then + dlocal_s <= dlocal_s + conv_signed(dig_alpha_c,cwidth_g)*(unsigned(din_i)-dlocal_s(dwidthi_g+cwidth_g downto cwidth_g)); + end if; + end if; + end process iir_proc; + + -- output with optional re-scaling of bitwidth + output_map : process (din_i, dlocal_s) is + -- helper signal for delta generation in HP mode + variable din_resize_s : signed (dwidthi_g+cwidth_g downto 0); + -- helper signal for final subtraction (HP mode) + variable outsum_a_s : signed (dwidtho_g downto 0); + variable outsum_b_s : signed (dwidtho_g downto 0); + variable outsum_q_s : signed (dwidtho_g downto 0); + begin + if (highpass_g) then + -- helper signals to keep track of range/sign and decimals + din_resize_s := "0" & signed(din_i) & conv_signed(0,cwidth_g); + outsum_a_s := "0" & din_resize_s(dwidthi_g+cwidth_g-1 downto cwidth_g-dwidtho_g+dwidthi_g); + outsum_b_s := "0" & dlocal_s(dwidthi_g+cwidth_g-1 downto cwidth_g-dwidtho_g+dwidthi_g); + outsum_q_s := outsum_a_s - outsum_b_s; + -- output is signed, so the filter has a gain of 0.5 if input and output width is the same + dout_o <= std_logic_vector(outsum_q_s(dwidtho_g downto 1)); + else + -- output is unsigned, the filter has a gain of 1.0 if input and output width is the same + dout_o <= std_logic_vector(dlocal_s(dwidthi_g+cwidth_g-1 downto cwidth_g-dwidtho_g+dwidthi_g)); + end if; + end process output_map; + +end RTL; diff --git a/zx8x.qsf b/zx8x.qsf index ca377a3..75fbdf3 100644 --- a/zx8x.qsf +++ b/zx8x.qsf @@ -242,70 +242,70 @@ set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[15] # Fitter Assignments # ================== -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[0] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[1] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[2] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[3] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[4] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[5] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[6] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[7] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[8] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[9] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[10] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[11] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[12] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[0] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[1] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[2] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[3] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[4] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[5] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[6] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[7] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[8] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[9] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[10] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[11] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[12] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[13] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[14] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_A[0] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_A[1] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_A[2] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_A[3] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_A[4] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_A[5] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_A[6] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_A[7] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_A[8] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_A[9] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_A[10] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_A[11] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_A[12] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[0] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[1] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[2] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[3] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[4] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[5] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[6] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[7] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[8] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[9] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[10] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[11] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[12] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[13] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[14] set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[15] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_BA[0] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_BA[1] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQML -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQMH -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_nRAS -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_nCAS -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_nWE -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_nCS -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_CKE +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_BA[0] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_BA[1] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQML +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQMH +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nRAS +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nCAS +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nWE +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nCS +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_CKE set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_CLK -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_R[5] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_R[4] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_R[3] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_R[2] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_R[1] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_R[0] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_G[5] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_G[4] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_G[3] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_G[2] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_G[1] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_G[0] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_B[5] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_B[4] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_B[3] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_B[2] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_B[1] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_B[0] -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_HS -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to VGA_VS -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to LED -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to AUDIO_L -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to AUDIO_R -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SPI_DO -set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to CONF_DATA0 +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_R[5] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_R[4] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_R[3] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_R[2] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_R[1] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_R[0] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_G[5] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_G[4] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_G[3] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_G[2] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_G[1] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_G[0] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_B[5] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_B[4] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_B[3] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_B[2] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_B[1] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_B[0] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_HS +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_VS +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to LED +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to AUDIO_L +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to AUDIO_R +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SPI_DO +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to CONF_DATA0 # start DESIGN_PARTITION(Top) # --------------------------- @@ -326,6 +326,7 @@ set_location_assignment PIN_31 -to UART_RX +set_global_assignment -name VHDL_FILE rc_filter_1o.vhd set_global_assignment -name SYSTEMVERILOG_FILE sys/rgb2ypbpr.sv set_global_assignment -name SYSTEMVERILOG_FILE zx8x.sv set_global_assignment -name SYSTEMVERILOG_FILE sdram.sv @@ -340,4 +341,6 @@ set_global_assignment -name QIP_FILE sys/pll.qip set_global_assignment -name VERILOG_FILE sys/osd.v set_global_assignment -name VERILOG_FILE sys/mist_io.v set_global_assignment -name SIGNALTAP_FILE output_files/stp1.stp +set_global_assignment -name USE_SIGNALTAP_FILE output_files/stp2.stp +set_global_assignment -name SIGNALTAP_FILE output_files/stp2.stp set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/zx8x.sv b/zx8x.sv index 0b9f9fd..fd20f65 100644 --- a/zx8x.sv +++ b/zx8x.sv @@ -517,8 +517,26 @@ YM2149 psg .CHANNEL_C(psg_ch_c) ); -wire [8:0] audio_l = { 1'b0, psg_ch_a } + { 1'b0, psg_ch_c }; -wire [8:0] audio_r = { 1'b0, psg_ch_b } + { 1'b0, psg_ch_c }; +// Route vsync through a high-pass filter to filter out sync signals from the +// tape audio +wire [7:0] mic_out; +wire mic_bit = mic_out > 8'd8 && mic_out < 8'd224; + +rc_filter_1o #( + .R_ohms_g(33000), + .C_p_farads_g(47000), + .fclk_hz_g(6500000), + .cwidth_g(18)) mic_filter +( + .clk_i(clk_sys), + .clken_i(ce_65), + .res_i(reset), + .din_i({1'b0, vsync, 6'd0 }), + .dout_o(mic_out) +); + +wire [8:0] audio_l = { 1'b0, psg_ch_a } + { 1'b0, psg_ch_c } + { mic_bit, 4'd0 }; +wire [8:0] audio_r = { 1'b0, psg_ch_b } + { 1'b0, psg_ch_c } + { mic_bit, 4'd0 }; sigma_delta_dac #(7) dac_l (