Skip to content

Commit

Permalink
Route vsync to audio out via a high-pass filter
Browse files Browse the repository at this point in the history
  • Loading branch information
gyurco committed Apr 14, 2019
1 parent 52cdcfe commit 73f9d31
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 64 deletions.
134 changes: 134 additions & 0 deletions rc_filter_1o.vhd
Original file line number Diff line number Diff line change
@@ -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 <at> pin4 <dot> 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;
127 changes: 65 additions & 62 deletions zx8x.qsf
Original file line number Diff line number Diff line change
Expand Up @@ -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)
# ---------------------------
Expand All @@ -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
Expand All @@ -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
22 changes: 20 additions & 2 deletions zx8x.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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
(
Expand Down

0 comments on commit 73f9d31

Please sign in to comment.