├── .gitignore ├── LICENSE ├── readme.md ├── rtl ├── tb_ym2149.vhd └── ym2149_audio.vhd └── ym2149_audio_simulation.png /.gitignore: -------------------------------------------------------------------------------- 1 | Thumbs.db 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, Matthew Hagerty 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # YM-2149 (AY-3-8913) Complex Sound Generator 2 | 3 | VHDL, BSD 3-Clause 4 | 5 | This core is based mostly on the YM-2149 Programmable Sound Generator (PSG), which is an upgraded version of the AY-3-8913 PSG. The main changes in theYM-2149 over the AY-3-8910 are: 6 | 7 | * 5-bit envelope shape counter for smoother volume ramping, with 1.5dB logarithmic steps. 8 | * simplified host interface, i.e. no BC2 input. 9 | * option to divide the input clock in half prior to further dividing. 10 | 11 | 12 | TODO: Currently the two external 8-bit I/O ports are not implemented. Their implementation should be easy enough, so it will probably happen in the future when a system that uses the I/O is implemented (they would need to be tested, and the SoC that this core was initially written for does not use the PSG's I/O ports). 13 | 14 | A huge amount of effort has gone into making this core as accurate as possible to the real IC, while at the same time making it usable in all-digital SoC designs, i.e. retro-computer and game systems, etc. Design elements from the real IC were used and implemented when possible, with any work-around or changes noted along with the reasons. 15 | 16 | Synthesized and FPGA proven: 17 | 18 | * Xilinx Spartan-6 LX16, SoC 21.477MHz system clock, 3.58MHz clock-enable. 19 | 20 | 21 | References: 22 | 23 | * The AY-3-8910 [die-shot and reverse engineered schematic][1]. This was the most beneficial reference and greatly appreciated! Removes any questions about what the real IC does. 24 | * The YM-2149 and AY-3-8910 datasheets. 25 | * Real YM-2149 IC. 26 | * Chip quirks, use, and abuse details from friends and retro enthusiasts. 27 | 28 | [1]: https://github.com/lvd2/ay-3-8910_reverse_engineered 29 | 30 | 31 | Generates: 32 | 33 | * Unsigned 12-bit output for each channel. 34 | * Unsigned 14-bit summation of the channels. 35 | * Signed 14-bit PCM summation of the channels, with each channel converted to -/+ zero-centered level or -/+ full-range level. 36 | 37 | The tone counters are period-limited to prevent the very high frequency outputs that the original IC is capable of producing. Frequencies above 20KHz cause problems in all-digital systems with sampling rates around 44.1KHz to 48KHz. The primary use of these high frequencies was as a carrier for amplitude modulated (AM) audio. The high frequency would be filtered out by external electronics, leaving only the low frequency audio. 38 | 39 | When the tone counters are limited, the normal square-wave is set to always output a '1', but the amplitude can still be changed, which allows the A.M. technique to still work in a digital Soc. 40 | 41 | 42 | ## Basic host interface: 43 | 44 | This core uses the simplified form where BC2 is not used or exposed externally (AY-3-8913). 45 | ``` 46 | BDIR BC1 State 47 | 0 0 Inactive 48 | 0 1 Read from PSG 49 | 1 0 Write to PSG 50 | 1 1 Latch address 51 | ``` 52 | -------------------------------------------------------------------------------- /rtl/tb_ym2149.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- Simple Testbench 3 | -- YM-2149 / AY-3-8910 Complex Sound Generator 4 | -- Matthew Hagerty 5 | -- June 2020 6 | -- https://dnotq.io 7 | -- 8 | 9 | library ieee; 10 | use ieee.std_logic_1164.all; 11 | use ieee.numeric_std.all; 12 | 13 | entity tb_ym2149 is 14 | end tb_ym2149; 15 | 16 | architecture behavior of tb_ym2149 is 17 | 18 | -- Unit Under Test (UUT) 19 | component ym2149_audio 20 | port 21 | ( clk_i : in std_logic 22 | ; en_clk_psg_i : in std_logic 23 | ; sel_n_i : in std_logic 24 | ; reset_n_i : in std_logic 25 | ; bc_i : in std_logic 26 | ; bdir_i : in std_logic 27 | ; data_i : in std_logic_vector(7 downto 0) 28 | ; data_r_o : out std_logic_vector(7 downto 0) 29 | ; ch_a_o : out unsigned(11 downto 0) 30 | ; ch_b_o : out unsigned(11 downto 0) 31 | ; ch_c_o : out unsigned(11 downto 0) 32 | ; mix_audio_o : out unsigned(13 downto 0) 33 | ; pcm14s_o : out unsigned(13 downto 0) 34 | ); 35 | end component; 36 | 37 | 38 | -- Inputs 39 | signal clk_i : std_logic := '0'; 40 | signal en_clk_psg_i : std_logic := '0'; 41 | signal sel_n_i : std_logic := '0'; 42 | signal reset_n_i : std_logic := '0'; 43 | signal bc_i : std_logic := '0'; 44 | signal bdir_i : std_logic := '0'; 45 | signal data_i : std_logic_vector(7 downto 0) := (others => '0'); 46 | 47 | --Outputs 48 | signal data_r_o : std_logic_vector(7 downto 0); 49 | signal ch_a_o : unsigned(11 downto 0); 50 | signal ch_b_o : unsigned(11 downto 0); 51 | signal ch_c_o : unsigned(11 downto 0); 52 | signal mix_audio_o : unsigned(13 downto 0); 53 | signal pcm14s_o : unsigned(13 downto 0); 54 | 55 | -- Clock period definitions 56 | constant clk_i_period : time := 46.560852 ns; 57 | 58 | signal clk_psg_r : unsigned(2 downto 0) := "000"; 59 | 60 | begin 61 | 62 | 63 | -- Instantiate the Unit Under Test (UUT) 64 | uut: ym2149_audio 65 | port map 66 | ( clk_i => clk_i 67 | , en_clk_psg_i => en_clk_psg_i 68 | , sel_n_i => sel_n_i 69 | , reset_n_i => reset_n_i 70 | , bc_i => bc_i 71 | , bdir_i => bdir_i 72 | , data_i => data_i 73 | , data_r_o => data_r_o 74 | , ch_a_o => ch_a_o 75 | , ch_b_o => ch_b_o 76 | , ch_c_o => ch_c_o 77 | , mix_audio_o => mix_audio_o 78 | , pcm14s_o => pcm14s_o 79 | ); 80 | 81 | 82 | -- Clock process definitions 83 | clk_i_process :process 84 | begin 85 | clk_i <= '1'; 86 | wait for clk_i_period/2; 87 | clk_i <= '0'; 88 | wait for clk_i_period/2; 89 | end process; 90 | 91 | en_clk_psg_i_process :process ( clk_i ) 92 | begin 93 | if rising_edge(clk_i) then 94 | if clk_psg_r = 5 then 95 | clk_psg_r <= "000"; 96 | else 97 | clk_psg_r <= clk_psg_r + 1; 98 | end if; 99 | 100 | if clk_psg_r = 2 then 101 | en_clk_psg_i <= '1'; 102 | else 103 | en_clk_psg_i <= '0'; 104 | end if; 105 | end if; 106 | end process; 107 | 108 | 109 | -- Stimulus process 110 | stim_proc: process 111 | begin 112 | sel_n_i <= '0'; 113 | reset_n_i <= '0'; 114 | bc_i <= '0'; 115 | bdir_i <= '0'; 116 | data_i <= x"00"; 117 | wait for clk_i_period*6*12; 118 | reset_n_i <= '1'; 119 | wait for clk_i_period*2*12; 120 | -- insert stimulus here 121 | 122 | wait for clk_i_period*32*12; 123 | 124 | 125 | -- See the PSG datasheet for programming details. 126 | -- Set up channels A, B, C for tone output, constant amplitude. 127 | 128 | -- Channel A 129 | -- Latch the register address. 130 | wait for 150 ns; 131 | bc_i <= '1'; 132 | bdir_i <= '1'; 133 | data_i <= x"00"; -- R0 (Channel A low 8-bits of tone counter). 134 | wait for 300 ns; 135 | bc_i <= '0'; 136 | bdir_i <= '0'; 137 | wait for 150 ns; 138 | 139 | -- Write a value to the register. 140 | wait for 150 ns; 141 | bc_i <= '0'; 142 | bdir_i <= '1'; 143 | data_i <= x"20"; -- register value 144 | wait for 300 ns; 145 | bc_i <= '0'; 146 | bdir_i <= '0'; 147 | wait for 150 ns; 148 | 149 | 150 | -- Latch the register address. 151 | wait for 150 ns; 152 | bc_i <= '1'; 153 | bdir_i <= '1'; 154 | data_i <= x"08"; -- R8 (Channel A amplitude). 155 | wait for 300 ns; 156 | bc_i <= '0'; 157 | bdir_i <= '0'; 158 | wait for 150 ns; 159 | 160 | -- Write a value to the register. 161 | wait for 150 ns; 162 | bc_i <= '0'; 163 | bdir_i <= '1'; 164 | data_i <= x"0F"; -- register value 165 | wait for 300 ns; 166 | bc_i <= '0'; 167 | bdir_i <= '0'; 168 | wait for 150 ns; 169 | 170 | 171 | -- Channel B 172 | -- Latch the register address. 173 | wait for 150 ns; 174 | bc_i <= '1'; 175 | bdir_i <= '1'; 176 | data_i <= x"02"; -- R2 (Channel B low 8-bits of tone counter). 177 | wait for 300 ns; 178 | bc_i <= '0'; 179 | bdir_i <= '0'; 180 | wait for 150 ns; 181 | 182 | -- Write a value to the register. 183 | wait for 150 ns; 184 | bc_i <= '0'; 185 | bdir_i <= '1'; 186 | data_i <= x"38"; -- register value 187 | wait for 300 ns; 188 | bc_i <= '0'; 189 | bdir_i <= '0'; 190 | wait for 150 ns; 191 | 192 | 193 | -- Latch the register address. 194 | wait for 150 ns; 195 | bc_i <= '1'; 196 | bdir_i <= '1'; 197 | data_i <= x"09"; -- R9 (Channel B amplitude). 198 | wait for 300 ns; 199 | bc_i <= '0'; 200 | bdir_i <= '0'; 201 | wait for 150 ns; 202 | 203 | -- Write a value to the register. 204 | wait for 150 ns; 205 | bc_i <= '0'; 206 | bdir_i <= '1'; 207 | data_i <= x"0A"; -- register value 208 | wait for 300 ns; 209 | bc_i <= '0'; 210 | bdir_i <= '0'; 211 | wait for 150 ns; 212 | 213 | 214 | -- Channel C 215 | -- Latch the register address. 216 | wait for 150 ns; 217 | bc_i <= '1'; 218 | bdir_i <= '1'; 219 | data_i <= x"04"; -- R4 (Channel C low 8-bits of tone counter). 220 | wait for 300 ns; 221 | bc_i <= '0'; 222 | bdir_i <= '0'; 223 | wait for 150 ns; 224 | 225 | -- Write a value to the register. 226 | wait for 150 ns; 227 | bc_i <= '0'; 228 | bdir_i <= '1'; 229 | data_i <= x"42"; -- register value 230 | wait for 300 ns; 231 | bc_i <= '0'; 232 | bdir_i <= '0'; 233 | wait for 150 ns; 234 | 235 | 236 | -- Latch the register address. 237 | wait for 150 ns; 238 | bc_i <= '1'; 239 | bdir_i <= '1'; 240 | data_i <= x"0A"; -- R10 (Channel C amplitude). 241 | wait for 300 ns; 242 | bc_i <= '0'; 243 | bdir_i <= '0'; 244 | wait for 150 ns; 245 | 246 | -- Write a value to the register. 247 | wait for 150 ns; 248 | bc_i <= '0'; 249 | bdir_i <= '1'; 250 | data_i <= x"07"; -- register value 251 | wait for 300 ns; 252 | bc_i <= '0'; 253 | bdir_i <= '0'; 254 | wait for 150 ns; 255 | 256 | 257 | 258 | -- Mixer Settings, enable tones without noise. 259 | -- Latch the register address. 260 | wait for 150 ns; 261 | bc_i <= '1'; 262 | bdir_i <= '1'; 263 | data_i <= x"07"; -- R7, mixer control 264 | wait for 300 ns; 265 | bc_i <= '0'; 266 | bdir_i <= '0'; 267 | wait for 150 ns; 268 | 269 | -- Write a value to the register. 270 | wait for 150 ns; 271 | bc_i <= '0'; 272 | bdir_i <= '1'; 273 | data_i <= x"38"; -- register value 274 | wait for 300 ns; 275 | bc_i <= '0'; 276 | bdir_i <= '0'; 277 | wait for 150 ns; 278 | 279 | 280 | wait; 281 | end process; 282 | 283 | end; 284 | -------------------------------------------------------------------------------- /rtl/ym2149_audio.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- YM-2149 / AY-3-8910 Complex Sound Generator 3 | -- Matthew Hagerty 4 | -- June 2020 5 | -- https://dnotq.io 6 | -- 7 | 8 | -- Released under the 3-Clause BSD License: 9 | -- 10 | -- Copyright 2020 Matthew Hagerty (matthew dnotq io) 11 | -- 12 | -- Redistribution and use in source and binary forms, with or without 13 | -- modification, are permitted provided that the following conditions are met: 14 | -- 15 | -- 1. Redistributions of source code must retain the above copyright notice, 16 | -- this list of conditions and the following disclaimer. 17 | -- 18 | -- 2. Redistributions in binary form must reproduce the above copyright 19 | -- notice, this list of conditions and the following disclaimer in the 20 | -- documentation and/or other materials provided with the distribution. 21 | -- 22 | -- 3. Neither the name of the copyright holder nor the names of its 23 | -- contributors may be used to endorse or promote products derived from this 24 | -- software without specific prior written permission. 25 | -- 26 | -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 | -- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 30 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 | -- POSSIBILITY OF SUCH DAMAGE. 37 | 38 | -- 39 | -- This core is based mostly on the YM-2149 Programmable Sound Generator (PSG), 40 | -- which is an upgraded version of the AY-3-8913 PSG. The main changes in the 41 | -- YM-2149 over the AY-3-8910 are: 42 | -- 43 | -- * 5-bit envelope shape counter for smoother volume ramping, with 1.5dB 44 | -- logarithmic steps. 45 | -- * simplified host interface, i.e. no BC2 input. 46 | -- * option to divide the input clock in half prior to further dividing. 47 | -- 48 | -- 49 | -- TODO: Currently the two external 8-bit I/O ports are not implemented. 50 | -- Their implementation should be easy enough, so it will probably happen in 51 | -- the future when a system that uses the I/O is implemented (they would need 52 | -- to be tested, and the SoC that this core was initially written for does not 53 | -- use the PSG's I/O ports). 54 | 55 | -- A huge amount of effort has gone into making this core as accurate as 56 | -- possible to the real IC, while at the same time making it usable in all- 57 | -- digital SoC designs, i.e. retro-computer and game systems, etc. Design 58 | -- elements from the real IC were used and implemented when possible, with any 59 | -- work-around or changes noted along with the reasons. 60 | -- 61 | -- Synthesized and FPGA proven: 62 | -- 63 | -- * Xilinx Spartan-6 LX16, SoC 25.0MHz system clock, 3.58MHz clock-enable. 64 | -- 65 | -- 66 | -- References: 67 | -- 68 | -- * The AY-3-8910 die-shot and reverse engineered schematic. This was the 69 | -- most beneficial reference and greatly appreciated! Removes any questions 70 | -- about what the real IC does. 71 | -- https://github.com/lvd2/ay-3-8910_reverse_engineered 72 | -- * The YM-2149 and AY-3-8910 datasheets. 73 | -- * Real YM-2149 IC. 74 | -- * Chip quirks, use, and abuse details from friends and retro enthusiasts. 75 | -- 76 | -- 77 | -- Generates: 78 | -- 79 | -- * Unsigned 12-bit output for each channel. 80 | -- * Unsigned 14-bit summation of the channels. 81 | -- * Signed 14-bit PCM summation of the channels, with each channel 82 | -- converted to -/+ zero-centered level or -/+ full-range level. 83 | -- 84 | -- The tone counters are period-limited to prevent the very high frequency 85 | -- outputs that the original IC is capable of producing. Frequencies above 86 | -- 20KHz cause problems in all-digital systems with sampling rates around 87 | -- 44.1KHz to 48KHz. The primary use of these high frequencies was as a 88 | -- carrier for amplitude modulated (AM) audio. The high frequency would be 89 | -- filtered out by external electronics, leaving only the low frequency audio. 90 | -- 91 | -- When the tone counters are limited, the normal square-wave is set to always 92 | -- output a '1', but the amplitude can still be changed, which allows the A.M. 93 | -- technique to still work in a digital Soc. 94 | -- 95 | 96 | -- Clock, Clock-enable, and Sel. 97 | -- 98 | -- The clk_i input should be the full-speed clock of the system, and 99 | -- en_clk_psg_i must be a strobe (single clk_i tick) at the PSG operating 100 | -- frequency. 101 | -- 102 | -- If the sel_n_i input is used to divide the en_clk_psg_i strobe, the host 103 | -- interface will continue to operate with the non-divided en_clk_psg_i strobe. 104 | -- 105 | -- sel_n_i : 0 1 106 | -- en_clk_psg_i max : 4.0MHz 2.0MHz 107 | -- 108 | -- This core can use a much faster clock-enable than the original PSG, however 109 | -- the clock-enable frequency affects the output audio frequency directly. If 110 | -- producing sounds similar to the original ICs is desired, then using an 111 | -- accurate input clock-enable is important. 112 | -- 113 | -- In circuits where these PSG ICs were used, the clocks tend to be derived 114 | -- from division of the video clock frequency, and generally fell very close to 115 | -- a frequency of 1.78MHz. 116 | -- 117 | -- Internally the PSG divides the clock by 3 or 4 to obtain a typical internal 118 | -- operating frequency of around 447KHz. Some PSGs take this lower frequency 119 | -- directly, but most do clock division internally to reduce the external 120 | -- components needed by a designed using the PSG IC. 121 | -- 122 | -- Common frequencies found in retro systems: 123 | -- 124 | -- Crystal Pixel CPU PSG other PSG 125 | -- 10.738MHz /2 = 5.369MHz /3 = 3.579MHz /6 = 1.789MHz /24 = 447.437KHz 126 | -- 14.318MHz /2 = 7.159MHz /4 = 3.579MHz /8 = 1.789MHz 127 | -- 21.477MHz /2 =10.738MHz /6 = 3.579MHz /12 = 1.789MHz 128 | -- 129 | -- A pixel clock of 5.369MHz is common for NTSC, and 7.159MHz is common for 130 | -- standard resolution arcade games. 131 | -- 132 | 133 | -- Basic host interface, uses the simplified form where BC2 is not used or 134 | -- exposed externally (AY-3-8913). 135 | -- 136 | -- BDIR BC1 State 137 | -- 0 0 Inactive 138 | -- 0 1 Read from PSG 139 | -- 1 0 Write to PSG 140 | -- 1 1 Latch address 141 | -- 142 | 143 | -- 144 | -- Version history: 145 | -- 146 | -- June 28 2020 147 | -- V1.0. Release. SoC tested. 148 | -- 149 | 150 | 151 | library ieee; 152 | use ieee.std_logic_1164.all; 153 | use ieee.numeric_std.all; 154 | 155 | entity ym2149_audio is 156 | generic -- Non-custom PSG address mask is 0000. 157 | ( ADDRESS_G : std_logic_vector(3 downto 0) := x"0" 158 | ); 159 | port 160 | ( clk_i : in std_logic -- system clock 161 | ; en_clk_psg_i : in std_logic -- PSG clock enable 162 | ; sel_n_i : in std_logic -- divide select, 0=clock-enable/2 163 | ; reset_n_i : in std_logic -- active low 164 | ; bc_i : in std_logic -- bus control 165 | ; bdir_i : in std_logic -- bus direction 166 | ; data_i : in std_logic_vector(7 downto 0) 167 | ; data_r_o : out std_logic_vector(7 downto 0) -- registered output data 168 | ; ch_a_o : out unsigned(11 downto 0) 169 | ; ch_b_o : out unsigned(11 downto 0) 170 | ; ch_c_o : out unsigned(11 downto 0) 171 | ; mix_audio_o : out unsigned(13 downto 0) 172 | ; pcm14s_o : out unsigned(13 downto 0) 173 | ); 174 | end ym2149_audio; 175 | 176 | architecture rtl of ym2149_audio is 177 | 178 | -- Registered inputs. 179 | signal reg_addr_r : unsigned(3 downto 0) := x"0"; 180 | signal reg_addr_x : unsigned(3 downto 0); 181 | signal data_i_r : std_logic_vector(7 downto 0) := x"00"; 182 | signal data_o_r : std_logic_vector(7 downto 0) := x"00"; 183 | signal busctl_r : std_logic_vector(1 downto 0) := "00"; 184 | signal sel_n_r : std_logic := '1'; 185 | signal sel_ff_r : std_logic := '1'; 186 | signal sel_ff_x : std_logic; 187 | signal en_int_clk_psg_s : std_logic; 188 | 189 | -- Register file, should infer to discrete flip-flops. 190 | type reg_file_type is array (0 to 15) of std_logic_vector(7 downto 0); 191 | signal reg_file_ar : reg_file_type := (others => (others => '0')); 192 | 193 | signal en_data_rd_s : std_logic; 194 | signal en_data_wr_s : std_logic; 195 | 196 | -- Channel DAC levels. 197 | signal ch_a_level_r : unsigned(11 downto 0) := (others => '0'); 198 | signal ch_a_level_x : unsigned(11 downto 0); 199 | signal ch_b_level_r : unsigned(11 downto 0) := (others => '0'); 200 | signal ch_b_level_x : unsigned(11 downto 0); 201 | signal ch_c_level_r : unsigned(11 downto 0) := (others => '0'); 202 | signal ch_c_level_x : unsigned(11 downto 0); 203 | 204 | -- Added init value to channel period conbinatorial signals to keep 205 | -- simulation from complaining about metavalues at 0ps. 206 | 207 | -- Register-name signals. 208 | signal ch_a_period_s : unsigned(11 downto 0) := (others => '0'); 209 | signal ch_a_tone_en_n_s : std_logic; 210 | signal ch_a_noise_en_n_s : std_logic; 211 | signal ch_a_mode_s : std_logic; 212 | 213 | signal ch_b_period_s : unsigned(11 downto 0) := (others => '0'); 214 | signal ch_b_tone_en_n_s : std_logic; 215 | signal ch_b_noise_en_n_s : std_logic; 216 | signal ch_b_mode_s : std_logic; 217 | 218 | signal ch_c_period_s : unsigned(11 downto 0) := (others => '0'); 219 | signal ch_c_tone_en_n_s : std_logic; 220 | signal ch_c_noise_en_n_s : std_logic; 221 | signal ch_c_mode_s : std_logic; 222 | 223 | signal noise_period_s : unsigned( 4 downto 0) := (others => '0'); 224 | 225 | signal env_period_s : unsigned(15 downto 0); 226 | signal env_continue_s : std_logic; 227 | signal env_attack_s : std_logic; 228 | signal env_alternate_s : std_logic; 229 | signal env_hold_s : std_logic; 230 | 231 | -- Clock conditioning counters and enables. 232 | signal clk_div8_r : unsigned(2 downto 0) := "000"; 233 | signal clk_div8_x : unsigned(2 downto 0); 234 | signal en_cnt_r : std_logic := '0'; 235 | signal en_cnt_x : std_logic; 236 | 237 | -- Channel tone and noise counters. 238 | signal ch_a_cnt_r : unsigned(11 downto 0) := (others => '0'); 239 | signal ch_a_cnt_x : unsigned(11 downto 0); 240 | signal flatline_a_s : std_logic; 241 | signal tone_a_r : std_logic := '1'; 242 | signal tone_a_x : std_logic; 243 | 244 | signal ch_b_cnt_r : unsigned(11 downto 0) := (others => '0'); 245 | signal ch_b_cnt_x : unsigned(11 downto 0); 246 | signal flatline_b_s : std_logic; 247 | signal tone_b_r : std_logic := '1'; 248 | signal tone_b_x : std_logic; 249 | 250 | signal ch_c_cnt_r : unsigned(11 downto 0) := (others => '0'); 251 | signal ch_c_cnt_x : unsigned(11 downto 0); 252 | signal flatline_c_s : std_logic; 253 | signal tone_c_r : std_logic := '1'; 254 | signal tone_c_x : std_logic; 255 | 256 | signal noise_cnt_r : unsigned(4 downto 0) := (others => '0'); 257 | signal noise_cnt_x : unsigned(4 downto 0); 258 | signal flatline_n_s : std_logic; 259 | signal noise_ff_r : std_logic := '1'; 260 | signal noise_ff_x : std_logic; 261 | 262 | -- 17-bit Noise LFSR. 263 | signal noise_lfsr_r : std_logic_vector(16 downto 0) := b"1_0000_0000_0000_0000"; 264 | signal noise_lfsr_x : std_logic_vector(16 downto 0); 265 | signal noise_fb_s : std_logic; 266 | signal noise_s : std_logic; 267 | 268 | -- Tone and noise mixer. 269 | signal mix_a_s : std_logic; 270 | signal mix_b_s : std_logic; 271 | signal mix_c_s : std_logic; 272 | 273 | -- Envelope counter. 274 | signal env_shape_wr_r : std_logic := '0'; 275 | signal env_shape_wr_x : std_logic; 276 | signal env_rst_s : std_logic; 277 | signal env_cnt_r : unsigned(15 downto 0) := (others => '0'); 278 | signal env_cnt_x : unsigned(15 downto 0); 279 | signal env_ff_r : std_logic := '1'; 280 | signal env_ff_x : std_logic; 281 | 282 | signal shape_cnt_r : unsigned(4 downto 0) := (others => '0'); 283 | signal shape_cnt_x : unsigned(4 downto 0); 284 | 285 | signal continue_ff_r : std_logic := '1'; 286 | signal continue_ff_x : std_logic; 287 | signal attack_ff_r : std_logic := '0'; 288 | signal attack_ff_x : std_logic; 289 | signal hold_ff_r : std_logic := '0'; 290 | signal hold_ff_x : std_logic; 291 | 292 | -- Added init value to env_out_s to keep simulation from complaining 293 | -- about metavalues at 0ps. 294 | signal env_sel_s : std_logic; 295 | signal env_out_s : unsigned(4 downto 0) := (others => '0'); 296 | 297 | -- Amplitude control. 298 | signal level_a_s : unsigned(11 downto 0); 299 | signal level_b_s : unsigned(11 downto 0); 300 | signal level_c_s : unsigned(11 downto 0); 301 | 302 | -- DAC. 303 | signal dac_a_r : unsigned(11 downto 0) := (others => '0'); 304 | signal dac_b_r : unsigned(11 downto 0) := (others => '0'); 305 | signal dac_c_r : unsigned(11 downto 0) := (others => '0'); 306 | signal sum_audio_r : unsigned(13 downto 0) := (others => '0'); 307 | 308 | -- Digital to Analogue Output-level lookup table ROM. 309 | -- 310 | -- The DAC is implemented with tuned NMOS transistors in the real IC. For 311 | -- the FPGA version, the 4-bit register level or 5-bit output from the 312 | -- envelop is used as an index into a calculated table of values that 313 | -- represent the equivalent voltage. 314 | -- 315 | -- The output scale is amplitude logarithmic. 316 | -- 317 | -- ln10 = Natural logarithm of 10, ~= 2.302585 318 | -- amp = Amplitude in voltage, 0.2, 1.45, etc. 319 | -- dB = decibel value in dB, -1.5, -3, etc. 320 | -- 321 | -- dB = 20 * log(amp) / ln10 322 | -- amp = 10 ^ (dB / 20) 323 | -- 324 | -- -1.5dB = 0.8413951416 325 | -- -2.0dB = 0.7943282347 326 | -- -3.0dB = 0.7079457843 327 | -- 328 | -- The datasheet defines a normalize 0V to 1V graph and oscilloscope photo 329 | -- of the output curve. The AY-3-8910 has 16-steps that are -3.0dB apart, 330 | -- and the YM-2149 has 32-steps that are -1.5dB apart. 331 | -- 332 | -- 1V reference values based on the datasheet: 333 | -- 334 | -- 1.0000, 0.8414, 0.7079, 0.5957, 0.5012, 0.4217, 0.3548, 0.2985, 335 | -- 0.2512, 0.2113, 0.1778, 0.1496, 0.1259, 0.1059, 0.0891, 0.0750, 336 | -- 0.0631, 0.0531, 0.0447, 0.0376, 0.0316, 0.0266, 0.0224, 0.0188, 337 | -- 0.0158, 0.0133, 0.0112, 0.0094, 0.0079, 0.0067, 0.0056, 0.0047 338 | -- 339 | -- A 10-bit number (0..1023) can support a scaled version of the reference 340 | -- list without having any repeating values. Using 9-bits is close, and 341 | -- 8-bit values have too many duplicate values at the bottom-end to make for 342 | -- a nice curve. Duplicate values means several volume levels produce the 343 | -- same output level, and is not accurate. 344 | -- 345 | -- Using a 12-bit output value means the three channels can be summed into a 346 | -- 14-bit value without overflow, and leaves room for adjustments if 347 | -- converting to something like 16-bit PCM. The 12-bit values also provide 348 | -- a nicer curve, and are easier to initialize in VHDL. 349 | -- 350 | -- The lowest volume level needs to go to 0 in a digital SoC to prevent 351 | -- noise that would be filtered in a real system with external electronics. 352 | 353 | -- Added init value to dac_reg_bit0_s to keep simulation from complaining 354 | -- about metavalues at 0ps. 355 | signal dac_reg_bit0_s : std_logic := '0'; 356 | signal dac_reg_level_s : unsigned(11 downto 0); 357 | signal dac_env_level_s : unsigned(11 downto 0); 358 | 359 | -- Output-level lookup table ROM. 360 | type dacrom_type is array (0 to 31) of unsigned(11 downto 0); 361 | signal dacrom_ar : dacrom_type := ( 362 | -- 19, 23, 27, 33, 39, 46, 55, 65, 363 | -- 77, 92, 109, 129, 154, 183, 217, 258, 364 | -- 307, 365, 434, 516, 613, 728, 865,1029, 365 | -- 1223,1453,1727,2052,2439,2899,3446,4095 366 | x"000",x"017",x"01B",x"021",x"027",x"02E",x"037",x"041", 367 | x"04D",x"05C",x"06D",x"081",x"09A",x"0B7",x"0D9",x"102", 368 | x"133",x"16D",x"1B2",x"204",x"265",x"2D8",x"361",x"405", 369 | x"4C7",x"5AD",x"6BF",x"804",x"987",x"B53",x"D76",x"FFF"); 370 | 371 | -- PCM signed 14-bit. 372 | signal sign_a_r : unsigned(11 downto 0) := (others => '0'); 373 | signal sign_a_x : unsigned(11 downto 0); 374 | signal level_a_env_s : unsigned(11 downto 0); 375 | signal sign_b_r : unsigned(11 downto 0) := (others => '0'); 376 | signal sign_b_x : unsigned(11 downto 0); 377 | signal level_b_env_s : unsigned(11 downto 0); 378 | signal sign_c_r : unsigned(11 downto 0) := (others => '0'); 379 | signal sign_c_x : unsigned(11 downto 0); 380 | signal level_c_env_s : unsigned(11 downto 0); 381 | 382 | signal pcm14s_r : unsigned(13 downto 0) := (others => '0'); 383 | 384 | begin 385 | 386 | -- Register the input data at the full clock rate. 387 | process ( clk_i ) begin if rising_edge(clk_i) then 388 | sel_n_r <= sel_n_i; 389 | busctl_r <= bdir_i & bc_i; 390 | data_i_r <= data_i; 391 | end if; end process; 392 | 393 | -- Registered data output. 394 | data_r_o <= data_o_r; 395 | 396 | 397 | -- ----------------------------------------------------------------------- 398 | -- 399 | -- External bus interface and register file. 400 | -- 401 | -- BDIR BC State 402 | -- 0 0 Inactive 403 | -- 0 1 Read from PSG register 404 | -- 1 0 Write to PSG register 405 | -- 1 1 Latch address 406 | -- 407 | -- A generic register file is used here instead of specific registers and 408 | -- decode logic. However, the real IC only has registers of exact size and 409 | -- performs decode and generates enable signals. 410 | -- 411 | 412 | process 413 | ( bdir_i, bc_i, busctl_r 414 | , data_i_r, reg_addr_r 415 | ) begin 416 | 417 | reg_addr_x <= reg_addr_r; 418 | en_data_rd_s <= '0'; 419 | en_data_wr_s <= '0'; 420 | 421 | case ( busctl_r ) is 422 | when "00" => -- inactive. 423 | null; 424 | when "01" => -- read from PSG register. 425 | en_data_rd_s <= '1'; 426 | when "10" => -- write to PSG register. 427 | en_data_wr_s <= '1'; 428 | -- "11" 429 | when others => -- latch register address. 430 | -- The PSG is factory set to a high-address mask of "0000", unless the 431 | -- PSG was special ordered with a custom-masked address. 432 | if data_i_r(7 downto 4) = ADDRESS_G then 433 | reg_addr_x <= unsigned(data_i_r(3 downto 0)); 434 | end if; 435 | end case; 436 | end process; 437 | 438 | -- Decode envelope shape register writes since they cause a reset of the 439 | -- envelope counter and state machine. The enable lasts as long as the 440 | -- write cycle, which is accurate to the real IC. It is registered to 441 | -- prevent long combinatorial paths from the write enable. 442 | env_shape_wr_x <= en_data_wr_s when reg_addr_r = x"D" else '0'; 443 | 444 | 445 | -- The output-level is converted to the equivalent DAC value and stored as 446 | -- as the look-up result, rather than the 4-bit level index. This allows 447 | -- sharing of the ROM lookup table, and uses less FPGA resources. 448 | dac_reg_bit0_s <= '0' when data_i_r(3 downto 0) = "0000" else '1'; 449 | dac_reg_level_s <= dacrom_ar(to_integer(unsigned(data_i_r(3 downto 0) & dac_reg_bit0_s))); 450 | 451 | ch_a_level_x <= dac_reg_level_s when reg_addr_r = x"8" else ch_a_level_r; 452 | ch_b_level_x <= dac_reg_level_s when reg_addr_r = x"9" else ch_b_level_r; 453 | ch_c_level_x <= dac_reg_level_s when reg_addr_r = x"A" else ch_c_level_r; 454 | 455 | 456 | -- Registers. 457 | -- 458 | -- 7654 3210 459 | -- R0 PPPP PPPP Channel A tone period 7..0. 460 | -- R1 ---- PPPP Channel A tone period 11..8. 461 | -- R2 PPPP PPPP Channel B tone period 7..0. 462 | -- R3 ---- PPPP Channel B tone period 11..8. 463 | -- R4 PPPP PPPP Channel C tone period 7..0. 464 | -- R5 ---- PPPP Channel C tone period 11..8. 465 | -- R6 ---P PPPP Noise shift period. 466 | -- R7 I--- ---- I/O Port B IN_n/OUT control. 467 | -- -I-- ---- I/O Port A IN_n/OUT control. 468 | -- --C- ---- Mix Noise with Channel C, active low. 469 | -- ---B ---- Mix Noise with Channel B, active low. 470 | -- ---- A--- Mix Noise with Channel A, active low. 471 | -- ---- -C-- Enable Channel C, active low. 472 | -- ---- --B- Enable Channel B, active low. 473 | -- ---- ---A Enable Channel A, active low. 474 | -- R8 ---M ---- Channel A Mode, 0=level, 1=envelope. 475 | -- ---- LLLL Channel A Level. 476 | -- R9 ---M ---- Channel B Mode, 0=level, 1=envelope. 477 | -- ---- LLLL Channel B Level. 478 | -- R10 ---M ---- Channel C Mode, 0=level, 1=envelope. 479 | -- ---- LLLL Channel C Level. 480 | -- R11 PPPP PPPP Envelope period 7..0. 481 | -- R12 PPPP PPPP Envelope period 15..8. 482 | -- R13 ---- C--- Envelope shape "Continue" control. 483 | -- ---- -A-- Envelope shape "Attack" control. 484 | -- ---- --A- Envelope shape "Alternate" control. 485 | -- ---- ---H Envelope shape "Hole" control. 486 | -- R14 DDDD DDDD I/O port A data. 487 | -- R15 DDDD DDDD I/O port B data. 488 | 489 | process 490 | ( clk_i, en_clk_psg_i, reset_n_i 491 | ) begin 492 | if rising_edge(clk_i) then 493 | if reset_n_i = '0' then 494 | 495 | reg_addr_r <= (others => '0'); 496 | data_o_r <= (others => '0'); 497 | env_shape_wr_r <= '0'; 498 | ch_a_level_r <= x"800"; -- Default to half-range for 0 level. 499 | ch_b_level_r <= x"800"; -- Default to half-range for 0 level. 500 | ch_c_level_r <= x"800"; -- Default to half-range for 0 level. 501 | 502 | reg_file_ar(0) <= x"00"; 503 | reg_file_ar(1) <= x"00"; 504 | reg_file_ar(2) <= x"00"; 505 | reg_file_ar(3) <= x"00"; 506 | reg_file_ar(4) <= x"00"; 507 | reg_file_ar(5) <= x"00"; 508 | reg_file_ar(6) <= x"00"; 509 | reg_file_ar(7) <= x"00"; 510 | reg_file_ar(8) <= x"00"; 511 | reg_file_ar(9) <= x"00"; 512 | reg_file_ar(10) <= x"00"; 513 | reg_file_ar(11) <= x"00"; 514 | reg_file_ar(12) <= x"00"; 515 | reg_file_ar(13) <= x"00"; 516 | reg_file_ar(14) <= x"00"; 517 | reg_file_ar(15) <= x"00"; 518 | 519 | elsif en_clk_psg_i = '1' then 520 | 521 | reg_addr_r <= reg_addr_x; 522 | env_shape_wr_r <= env_shape_wr_x; 523 | 524 | if en_data_rd_s = '1' then 525 | data_o_r <= reg_file_ar(to_integer(reg_addr_r)); 526 | elsif en_data_wr_s = '1' then 527 | reg_file_ar(to_integer(reg_addr_r)) <= data_i_r; 528 | 529 | ch_a_level_r <= ch_a_level_x; 530 | ch_b_level_r <= ch_b_level_x; 531 | ch_c_level_r <= ch_c_level_x; 532 | end if; 533 | 534 | end if; 535 | end if; 536 | end process; 537 | 538 | 539 | -- Register file name mapping. Convenience for this implementation. The 540 | -- real IC does not have full 16x8-bit registers. Confirmed via die-shots. 541 | ch_a_period_s <= unsigned(reg_file_ar(1)(3 downto 0)) & unsigned(reg_file_ar(0)); 542 | ch_a_tone_en_n_s <= reg_file_ar(7)(0); 543 | ch_a_noise_en_n_s <= reg_file_ar(7)(3); 544 | ch_a_mode_s <= reg_file_ar(8)(4); 545 | 546 | ch_b_period_s <= unsigned(reg_file_ar(3)(3 downto 0)) & unsigned(reg_file_ar(2)); 547 | ch_b_tone_en_n_s <= reg_file_ar(7)(1); 548 | ch_b_noise_en_n_s <= reg_file_ar(7)(4); 549 | ch_b_mode_s <= reg_file_ar(9)(4); 550 | 551 | ch_c_period_s <= unsigned(reg_file_ar(5)(3 downto 0)) & unsigned(reg_file_ar(4)); 552 | ch_c_tone_en_n_s <= reg_file_ar(7)(2); 553 | ch_c_noise_en_n_s <= reg_file_ar(7)(5); 554 | ch_c_mode_s <= reg_file_ar(10)(4); 555 | 556 | noise_period_s <= unsigned(reg_file_ar(6)(4 downto 0)); 557 | 558 | env_period_s <= unsigned(reg_file_ar(12)) & unsigned(reg_file_ar(11)); 559 | env_continue_s <= reg_file_ar(13)(3); 560 | env_attack_s <= reg_file_ar(13)(2); 561 | env_alternate_s <= reg_file_ar(13)(1); 562 | env_hold_s <= reg_file_ar(13)(0); 563 | 564 | -- TODO implement I/O registers. 565 | 566 | 567 | -- ----------------------------------------------------------------------- 568 | -- 569 | -- Clock conditioning. 570 | -- 571 | 572 | -- Divide the input clock enable. 573 | sel_ff_x <= not sel_ff_r; 574 | 575 | -- Select the clock enable based on the sel_n_i input. 576 | en_int_clk_psg_s <= en_clk_psg_i and sel_ff_r when sel_n_r = '0' else en_clk_psg_i; 577 | 578 | process ( clk_i, en_clk_psg_i ) begin 579 | if rising_edge(clk_i) then 580 | if en_clk_psg_i = '1' then 581 | sel_ff_r <= sel_ff_x; 582 | end if; 583 | end if; end process; 584 | 585 | 586 | -- Reduce the input clock to provide the divide by eight clock-phases, count 587 | -- enable, and count reset. 588 | clk_div8_x <= clk_div8_r + 1; 589 | 590 | -- The real IC counts on the 4th divider count (100), so do the same with 591 | -- the enable (which is active during the next state, thus 3 instead of 4). 592 | en_cnt_x <= '1' when clk_div8_r = 3 else '0'; 593 | 594 | process 595 | ( clk_i, en_int_clk_psg_s, reset_n_i 596 | ) begin 597 | if rising_edge(clk_i) then 598 | if reset_n_i = '0' then 599 | clk_div8_r <= (others => '0'); 600 | en_cnt_r <= '0'; 601 | elsif en_int_clk_psg_s = '1' then 602 | clk_div8_r <= clk_div8_x; 603 | en_cnt_r <= en_cnt_x; 604 | end if; 605 | end if; 606 | end process; 607 | 608 | 609 | -- ----------------------------------------------------------------------- 610 | -- 611 | -- Channel tone counters. The counters *always* count unless in reset. 612 | -- 613 | 614 | -- Timing for 0 and 1 period-count, showing why they are the same. The real 615 | -- IC counts on the 4-count of the clock divider, so this implementation 616 | -- does the same. In the real IC, the >= reset and count enable happen in 617 | -- the same 4-count cycle due to the asynchronous nature of the IC. In a 618 | -- synchronous FPGA design, the >= reset is performed 1-cycle prior to the 619 | -- count enable. 620 | -- _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 621 | -- _/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_ PSG clock (input clock enable) 622 | -- _______________ _______________ 623 | -- ___3___4_/ 5 6 7 0 \_1___2___3___4_/ 5 6 7 0 \_1___2___3___4_ divided clock count 624 | -- ___ ___ ___ 625 | -- _/ \___________________________/ \___________________________/ \___ >= enable (resets count to 0) 626 | -- ___ ___ ___ 627 | -- _____/ \___________________________/ \___________________________/ count enable 628 | -- _____ ___ ___________________________ ___ ___________________________ ___ 629 | -- _____X_0_X______________1____________X_0_X______________1____________X_0_ tone counter 630 | -- _____ _______________________________ 631 | -- \_______________________________/ \___ tone flip-flop 632 | 633 | -- The tone counter >= reset strobe must be enabled prior to the count enable 634 | -- so the tone counter is only a zero-count for *one input clock cycle*, and 635 | -- not the count-enable cycle (i.e. input clock divided by 8). 636 | -- 637 | -- This is the reason why a period-count of zero is the same as a period- 638 | -- count of one. The time the counter has a zero value is merged with the 639 | -- last 8-cycle period where the >= condition is detected. 640 | -- 641 | -- In the real IC the reset is asynchronous combinatorial logic (as is the 642 | -- whole IC). For the FPGA, combinatorial look-ahead is used. 643 | -- 644 | -- The channel counters in the real IC perform a greater-than or equal-to 645 | -- comparison to toggle the tone output flip-flop. 646 | -- 647 | -- Loading new values into the registers does NOT affect the counter or tone 648 | -- flip-flop in any way directly. A new register value many cause the >= 649 | -- comparison be become true immediately, which will cause the tone flip- 650 | -- flop to *toggle*, but does not guarantee the high or low state of the 651 | -- flip-flop. 652 | -- 653 | -- The *only* way to set the tone flip-flop to a known state is via the 654 | -- external chip reset, in which case the flip-flop will be set ('1'). 655 | -- 656 | -- A chip-accurate counter implementation in C might look like this: 657 | -- 658 | -- { 659 | -- if ( counter >= period ) { 660 | -- tone = !tone; 661 | -- counter = 0; 662 | -- } 663 | -- 664 | -- counter++; 665 | -- } 666 | -- 667 | -- With the period work-around described below: 668 | -- 669 | -- { 670 | -- if ( counter >= period ) 671 | -- { 672 | -- if ( period < 6 ) { 673 | -- tone = 1; 674 | -- } else { 675 | -- tone = !tone; 676 | -- } 677 | -- 678 | -- counter = 0; 679 | -- } 680 | -- 681 | -- counter++; 682 | -- } 683 | 684 | -- High frequency noise problem. 685 | -- 686 | -- With a typical 1.78MHz input clock, the divide by eight produces a 687 | -- 223.72KHz clock into the tone counters. With small period counts, 688 | -- frequencies *well over* the human hearing range can be produced. 689 | -- 690 | -- The problem with the frequencies over 20KHz is, in a digital SoC the high 691 | -- frequencies do not filter out like they do when the output is connected 692 | -- to an external low-pass filter and inductive load (speaker), like they 693 | -- are with the real IC. 694 | -- 695 | -- In an all digital system with digital audio, the generated frequencies 696 | -- should never be more than the Nyquist frequency (twice the sample rate). 697 | -- Typical sample rates are 44KHz or 48KHz, so any frequency over 20KHz 698 | -- should not be output (and is not audible to a human anyway). 699 | -- 700 | -- The work-around here is to flat-line the toggle flip-flop for any tone 701 | -- counter with a period that produces a frequency over the Nyquist rate. 702 | -- This change still allows the technique of modulating the output with 703 | -- rapid volume level changes. 704 | -- 705 | -- Based on a typical PSG clock of 1.78MHz for a Z80-based system, the 706 | -- period counts that cause frequencies above 20KHz are: 707 | -- 708 | -- f = CLK / (16 * Count) 709 | -- 710 | -- Clock 1,789,772Hz 55.873ns 711 | -- 712 | -- Count Frequency Period 713 | -- 0 111860.78Hz 8.9396us * same as a count of 1, see above. 714 | -- 1 111860.78Hz 8.9396us 715 | -- 2 55930.39Hz 17.8793us 716 | -- 3 37286.92Hz 26.8190us 717 | -- 4 27965.19Hz 35.7587us 718 | -- 5 22372.15Hz 44.6984us 719 | -- ---------------------------- 720 | -- 6 18643.46Hz 53.6381us First audible count. 721 | 722 | 723 | -- A channel counter and tone flip-flop. 724 | ch_a_cnt_x <= 725 | -- Reset uses counter next-state look-ahead. 726 | (others => '0') when (en_cnt_x = '1' and ch_a_cnt_r >= ch_a_period_s) else 727 | -- Counting uses current-state. 728 | ch_a_cnt_r + 1 when en_cnt_r = '1' else 729 | ch_a_cnt_r; 730 | 731 | flatline_a_s <= '1' when ch_a_period_s < 6 else '0'; 732 | 733 | tone_a_x <= 734 | -- Flat-line the output for counts that produce frequencies > 20KHz. 735 | '1' when flatline_a_s = '1' else 736 | -- Toggle uses counter next-state look-ahead, same condition as reset. 737 | not tone_a_r when (en_cnt_x = '1' and ch_a_cnt_r >= ch_a_period_s) else 738 | tone_a_r; 739 | 740 | -- B channel counter and tone flip-flop. 741 | ch_b_cnt_x <= 742 | (others => '0') when (en_cnt_x = '1' and ch_b_cnt_r >= ch_b_period_s) else 743 | ch_b_cnt_r + 1 when en_cnt_r = '1' else 744 | ch_b_cnt_r; 745 | 746 | flatline_b_s <= '1' when ch_b_period_s < 6 else '0'; 747 | 748 | tone_b_x <= 749 | '1' when flatline_b_s = '1' else 750 | not tone_b_r when (en_cnt_x = '1' and ch_b_cnt_r >= ch_b_period_s) else 751 | tone_b_r; 752 | 753 | -- C channel counter and tone flip-flop. 754 | ch_c_cnt_x <= 755 | (others => '0') when (en_cnt_x = '1' and ch_c_cnt_r >= ch_c_period_s) else 756 | ch_c_cnt_r + 1 when en_cnt_r = '1' else 757 | ch_c_cnt_r; 758 | 759 | flatline_c_s <= '1' when ch_c_period_s < 6 else '0'; 760 | 761 | tone_c_x <= 762 | '1' when flatline_c_s = '1' else 763 | not tone_c_r when (en_cnt_x = '1' and ch_c_cnt_r >= ch_c_period_s) else 764 | tone_c_r; 765 | 766 | 767 | process 768 | ( clk_i, en_int_clk_psg_s, reset_n_i 769 | ) begin 770 | if rising_edge(clk_i) then 771 | 772 | if reset_n_i = '0' then 773 | ch_a_cnt_r <= (others => '0'); 774 | tone_a_r <= '1'; -- Verified resets to '1' in the real IC. 775 | 776 | ch_b_cnt_r <= (others => '0'); 777 | tone_b_r <= '1'; -- Verified resets to '1' in the real IC. 778 | 779 | ch_c_cnt_r <= (others => '0'); 780 | tone_c_r <= '1'; -- Verified resets to '1' in the real IC. 781 | 782 | elsif en_int_clk_psg_s = '1' then 783 | ch_a_cnt_r <= ch_a_cnt_x; 784 | tone_a_r <= tone_a_x; 785 | 786 | ch_b_cnt_r <= ch_b_cnt_x; 787 | tone_b_r <= tone_b_x; 788 | 789 | ch_c_cnt_r <= ch_c_cnt_x; 790 | tone_c_r <= tone_c_x; 791 | end if; 792 | 793 | end if; 794 | end process; 795 | 796 | 797 | -- ----------------------------------------------------------------------- 798 | -- 799 | -- Noise period counter. Identical to the tone counters, only shorter, and 800 | -- the toggle flip-flop output of the counter is used as the clock input to 801 | -- the LFSR. Thus, the noise counter effectively divides the output shift 802 | -- rate in half one additional time. 803 | -- 804 | -- With the lowest period counter of 0 or 1 (both values produce the same 805 | -- count), the LFSR will output a bit at the rate of one-bit for every 16 806 | -- main clock cycles, maximum. 807 | -- 808 | -- The noise counter has the same high frequency problem for digital systems 809 | -- as the tone counters, but the noise counter has one extra flip-flop 810 | -- before the counter, so its minimum counter will be one lower than the 811 | -- tone counter minimum. 812 | -- 813 | -- PSG 814 | -- Clk 3,579,545Hz 2.793651ns 815 | -- 816 | -- Cnt Frequency Period 817 | -- 0 55930.39062Hz 17.87936us * same as a count of 1, see above. 818 | -- 1 55930.39062Hz 17.87936us 819 | -- 2 37286.92708Hz 26.81905us 820 | -- 3 27965.19531Hz 35.75873us 821 | -- 4 22372.15625Hz 44.69841us 822 | -- ------------------------------- 823 | -- 5 18643.46354Hz 53.63810us First audible count. 824 | 825 | noise_cnt_x <= 826 | -- Reset uses counter next-state look-ahead. 827 | (others => '0') when (en_cnt_x = '1' and noise_cnt_r >= noise_period_s) else 828 | -- Counting uses current-state. 829 | noise_cnt_r + 1 when en_cnt_r = '1' else 830 | noise_cnt_r; 831 | 832 | flatline_n_s <= '1' when noise_period_s < 5 else '0'; 833 | 834 | noise_ff_x <= 835 | -- Flat-line the output for counts that produce frequencies > 20KHz. 836 | '1' when flatline_n_s = '1' else 837 | -- Toggle uses counter next-state look-ahead, same condition as reset. 838 | not noise_ff_r when (en_cnt_x = '1' and noise_cnt_r >= noise_period_s) else 839 | noise_ff_r; 840 | 841 | 842 | -- Noise 17-bit right-shift LFSR with taps at 0 and 3, LS-bit is the output. 843 | -- Verified against the reverse engineered 8910 die-shot. Reset loads the 844 | -- LFSR with 0x10000 to prevent lock-up. 845 | noise_fb_s <= noise_lfsr_r(3) xor noise_lfsr_r(0); 846 | noise_lfsr_x <= noise_fb_s & noise_lfsr_r(16 downto 1); 847 | noise_s <= noise_lfsr_r(0); 848 | 849 | 850 | process 851 | ( clk_i, en_int_clk_psg_s, reset_n_i 852 | ) begin 853 | if rising_edge(clk_i) then 854 | 855 | if reset_n_i = '0' then 856 | noise_cnt_r <= (others => '0'); 857 | noise_ff_r <= '1'; -- Verified resets to '1' in the real IC. 858 | noise_lfsr_r <= b"1_0000_0000_0000_0000"; 859 | 860 | elsif en_int_clk_psg_s = '1' then 861 | noise_cnt_r <= noise_cnt_x; 862 | noise_ff_r <= noise_ff_x; 863 | -- Look-ahead rising-edge detect the noise flip-flop. 864 | if noise_ff_r = '0' and noise_ff_x = '1' then 865 | noise_lfsr_r <= noise_lfsr_x; 866 | end if; 867 | end if; 868 | 869 | end if; 870 | end process; 871 | 872 | 873 | -- ----------------------------------------------------------------------- 874 | -- 875 | -- Tone and Noise mixer. 876 | -- 877 | -- The output of the tone and noise section is a '0' or '1' for each channel 878 | -- and the noise. Each tone bit is optionally mixed with the noise bit. 879 | -- The final bit is used to determine if the amplitude is used or not. 880 | 881 | -- Tone and noise mixer. The enables are active low, so if the channel and 882 | -- noise are disabled, the output will be a '1', not a '0'. This allows a 883 | -- disabled channel to still be amplitude modulated by changing the volume. 884 | 885 | mix_a_s <= (ch_a_tone_en_n_s or tone_a_r) and (ch_a_noise_en_n_s or noise_s); 886 | mix_b_s <= (ch_b_tone_en_n_s or tone_b_r) and (ch_b_noise_en_n_s or noise_s); 887 | mix_c_s <= (ch_c_tone_en_n_s or tone_c_r) and (ch_c_noise_en_n_s or noise_s); 888 | 889 | 890 | -- ----------------------------------------------------------------------- 891 | -- 892 | -- Envelope counter. Works the same as the noise counter, with the envelope 893 | -- period-counter clocking the envelope shape-counter. The YM-2149 has a 894 | -- 5-bit shape counter, but it counts twice as fast so it produces smoother 895 | -- ramping of the envelope in the same time (one cycle of the envelope 896 | -- period). 897 | -- 898 | -- When the envelope-period is 0 or 1, the AY-3-8910 shape-counter counts at 899 | -- one-count for every 16 main-clock cycles, and the YM-2149 counts twice in 900 | -- the same 16 cycles. 901 | -- 902 | -- Unlike the other counters, the envelope period-counter, shape-counter, 903 | -- and shape FSM are reset when the shape register is written, as well as 904 | -- the global reset. 905 | 906 | env_cnt_x <= 907 | -- Reset uses counter next-state look-ahead. 908 | (others => '0') when (en_cnt_x = '1' and env_cnt_r >= env_period_s) else 909 | -- Counting uses current-state. 910 | env_cnt_r + 1 when en_cnt_r = '1' else 911 | env_cnt_r; 912 | 913 | env_ff_x <= 914 | -- Toggle uses counter next-state look-ahead, same condition as reset. 915 | not env_ff_r when (en_cnt_x = '1' and env_cnt_r >= env_period_s) else 916 | env_ff_r; 917 | 918 | -- The envelope reset is active during the global reset input as well as 919 | -- when the envelope shape register is written. 920 | env_rst_s <= (not reset_n_i) or env_shape_wr_r; 921 | 922 | -- Shape counter. Hold forces the shape counter to a "set" state. 923 | -- Look-ahead on the hold flip-flop to prevent counter roll-over. 924 | shape_cnt_x <= (others => '1') when hold_ff_x = '1' else shape_cnt_r + 1; 925 | 926 | 927 | process 928 | ( clk_i, en_int_clk_psg_s, env_rst_s 929 | , hold_ff_r, env_ff_r, env_ff_x 930 | ) begin 931 | if rising_edge(clk_i) then 932 | 933 | -- ** NOTE: This reset is active high. 934 | if env_rst_s = '1' then 935 | env_cnt_r <= (others => '0'); 936 | env_ff_r <= '1'; -- Verified resets to '1' in the real IC. 937 | shape_cnt_r <= (others => '0'); 938 | 939 | elsif en_int_clk_psg_s = '1' then 940 | env_cnt_r <= env_cnt_x; 941 | env_ff_r <= env_ff_x; 942 | 943 | -- Look-ahead edge detect the envelope flip-flop to provide two 944 | -- counts in the same number of cycles. Hold inhibits the shape 945 | -- counter's clock input. 946 | if hold_ff_r = '0' and env_ff_r /= env_ff_x then 947 | shape_cnt_r <= shape_cnt_x; 948 | end if; 949 | end if; 950 | 951 | end if; 952 | end process; 953 | 954 | 955 | -- ----------------------------------------------------------------------- 956 | -- 957 | -- Envelope FSM. Four envelope control bits determine how the shape 958 | -- counter operates after it has counted from 0 to 31. 959 | -- 960 | -- The envelope waveform is used as an amplitude control for use with the 961 | -- tone channels. 962 | -- 963 | -- Register 15 Envelope Shape Control 964 | -- 965 | -- +------- Continue 966 | -- | +----- Attack 967 | -- | | +--- Alternate 968 | -- | | | +- Hold 969 | -- 3 2 1 0 970 | -- ------- 971 | -- \ 972 | -- 0 0 X X \______________ 973 | -- 974 | -- /| 975 | -- 0 1 X X / |_____________ 976 | -- 977 | -- \ |\ |\ |\ |\ |\ 978 | -- 1 0 0 0 \| \| \| \| \| \ 979 | -- 980 | -- \ 981 | -- 1 0 0 1 \______________ 982 | -- 983 | -- \ /\ /\ /\ / 984 | -- 1 0 1 0 \/ \/ \/ \/ 985 | -- _____________ 986 | -- \ | 987 | -- 1 0 1 1 \| 988 | -- 989 | -- /| /| /| /| /| /| 990 | -- 1 1 0 0 / |/ |/ |/ |/ |/ | 991 | -- _______________ 992 | -- / 993 | -- 1 1 0 1 / 994 | -- 995 | -- /\ /\ /\ /\ 996 | -- 1 1 1 0 / \/ \/ \/ \ 997 | -- 998 | -- /| 999 | -- 1 1 1 1 / |______________ 1000 | 1001 | -- Continue is rather useless, since the envelopes created by using it are 1002 | -- duplicates of envelopes created with the other three control bits. 1003 | 1004 | -- "Continue" is a final envelope output select. After the shape counter 1005 | -- completes the first 0..31 count after being reset, if the continue bit 1006 | -- from the shape register is zero, the final envelope output will be zero. 1007 | continue_ff_x <= env_continue_s when shape_cnt_r = 31 else continue_ff_r; 1008 | 1009 | -- "Attack" is a selection between the regular or inverted shape count. 1010 | -- The real IC gates the ~q output from the attack flip-flop when the 1011 | -- attack register is '1'. 1012 | env_sel_s <= not attack_ff_r when env_attack_s = '1' else attack_ff_r; 1013 | 1014 | -- "Alternate" is an enable for toggling the Attack flip-flop. 1015 | attack_ff_x <= 1016 | not attack_ff_r when shape_cnt_r = 31 and env_alternate_s = '1' else 1017 | attack_ff_r; 1018 | 1019 | -- "Hold" sets ('1') all the flip-flops in the shape counter and inhibits it 1020 | -- it from counting. The only way to reset the hold is the global reset or 1021 | -- writing to the shape register (which issues the local envelope reset). 1022 | hold_ff_x <= env_hold_s when shape_cnt_r = 31 else hold_ff_r; 1023 | 1024 | env_out_s <= 1025 | (others => '0') when continue_ff_r = '0' else 1026 | not shape_cnt_r when env_sel_s = '0' else 1027 | shape_cnt_r; 1028 | 1029 | dac_env_level_s <= dacrom_ar(to_integer(env_out_s)); 1030 | 1031 | process 1032 | ( clk_i, en_int_clk_psg_s, env_rst_s, hold_ff_r 1033 | ) begin 1034 | if rising_edge(clk_i) then 1035 | 1036 | -- ** NOTE: This reset is active high. 1037 | if env_rst_s = '1' then 1038 | continue_ff_r <= '1'; 1039 | attack_ff_r <= '0'; 1040 | hold_ff_r <= '0'; 1041 | 1042 | elsif en_int_clk_psg_s = '1' then 1043 | 1044 | -- Look-ahead edge detect the envelope flip-flop to provide two 1045 | -- counts in the same number of cycles. Hold inhibits the shape 1046 | -- counter's clock input. 1047 | if hold_ff_r = '0' and env_ff_r /= env_ff_x then 1048 | continue_ff_r <= continue_ff_x; 1049 | attack_ff_r <= attack_ff_x; 1050 | hold_ff_r <= hold_ff_x; 1051 | end if; 1052 | end if; 1053 | 1054 | end if; 1055 | end process; 1056 | 1057 | 1058 | -- ----------------------------------------------------------------------- 1059 | -- 1060 | -- Amplitude control. The amplitude of each tone channel is controlled 1061 | -- by one of two ways: 1062 | -- 1063 | -- 1. The 4-bit amplitude setting from the channel's amplitude register. 1064 | -- 2. The 5-bit amplitude from the envelope generator. 1065 | -- 1066 | -- The selection is controlled by a mode-bit in each channel's amplitude 1067 | -- register. 1068 | -- 1069 | -- Because the envelope amplitude is 5-bits vs the 4-bits of the amplitude 1070 | -- register, the envelope amplitude will produce smoother ramps by changing 1071 | -- the level in 1.5dB half steps. 1072 | -- 1073 | -- The output of the mixer takes precedence, otherwise the level vs. 1074 | -- envelope selection is used. 1075 | 1076 | 1077 | level_a_s <= 1078 | (others => '0') when mix_a_s = '0' else 1079 | ch_a_level_r when ch_a_mode_s = '0' else 1080 | dac_env_level_s; 1081 | 1082 | level_b_s <= 1083 | (others => '0') when mix_b_s = '0' else 1084 | ch_b_level_r when ch_b_mode_s = '0' else 1085 | dac_env_level_s; 1086 | 1087 | level_c_s <= 1088 | (others => '0') when mix_c_s = '0' else 1089 | ch_c_level_r when ch_c_mode_s = '0' else 1090 | dac_env_level_s; 1091 | 1092 | 1093 | -- ----------------------------------------------------------------------- 1094 | -- 1095 | -- Digital to Analogue Converter. 1096 | -- 1097 | 1098 | ch_a_o <= dac_a_r; 1099 | ch_b_o <= dac_b_r; 1100 | ch_c_o <= dac_c_r; 1101 | mix_audio_o <= sum_audio_r; 1102 | 1103 | process 1104 | ( clk_i, en_clk_psg_i 1105 | ) begin 1106 | if rising_edge(clk_i) then 1107 | if en_clk_psg_i = '1' then 1108 | 1109 | dac_a_r <= level_a_s; 1110 | dac_b_r <= level_b_s; 1111 | dac_c_r <= level_c_s; 1112 | 1113 | -- Convenience sum the audio channels. 1114 | sum_audio_r <= ("00" & dac_a_r) + ("00" & dac_b_r) + ("00" & dac_c_r); 1115 | end if; 1116 | end if; 1117 | end process; 1118 | 1119 | 1120 | -- ----------------------------------------------------------------------- 1121 | -- 1122 | -- Signed zero-centered 14-bit PCM. 1123 | -- 1124 | 1125 | -- Make a -/+ level value depending on the tone state. When the tone is 1126 | -- disabled, adjust the unsigned level-range to a signed-level range. 1127 | -- 1128 | -- signed_level = 1129 | -- level - (range / 2) when disabled 1130 | -- -(level / 2) when tone == 0 1131 | -- (level / 2) when tone == 1 1132 | 1133 | level_a_env_s <= ch_a_level_r when ch_a_mode_s = '0' else dac_env_level_s; 1134 | level_b_env_s <= ch_b_level_r when ch_b_mode_s = '0' else dac_env_level_s; 1135 | level_c_env_s <= ch_c_level_r when ch_c_mode_s = '0' else dac_env_level_s; 1136 | 1137 | sign_a_x <= 1138 | -- Make a flat-level into a full-range signed value. 1139 | level_a_env_s - x"800" when 1140 | -- Channel is disabled, produces a constant '1' for the channel. 1141 | ((ch_a_tone_en_n_s and ch_a_noise_en_n_s) or 1142 | -- Channel is flat-lined. 1143 | flatline_a_s or 1144 | -- Channel + noise enabled, but noise is flat-lined. 1145 | ((not ch_a_noise_en_n_s) and flatline_n_s)) = '1' else 1146 | 1147 | -- Otherwise, make signed range value from tone 0 or 1. 1148 | ("1" & (not level_a_env_s(11 downto 1))) + 1 when mix_a_s = '0' else 1149 | ("0" & level_a_env_s(11 downto 1)); 1150 | 1151 | sign_b_x <= 1152 | level_b_env_s - x"800" when 1153 | ((ch_b_tone_en_n_s and ch_b_noise_en_n_s) or 1154 | flatline_b_s or 1155 | ((not ch_b_noise_en_n_s) and flatline_n_s)) = '1' else 1156 | ("1" & (not level_b_env_s(11 downto 1))) + 1 when mix_b_s = '0' else 1157 | ("0" & level_b_env_s(11 downto 1)); 1158 | 1159 | sign_c_x <= 1160 | level_c_env_s - x"800" when 1161 | ((ch_c_tone_en_n_s and ch_c_noise_en_n_s) or 1162 | flatline_c_s or 1163 | ((not ch_c_noise_en_n_s) and flatline_n_s)) = '1' else 1164 | ("1" & (not level_c_env_s(11 downto 1))) + 1 when mix_c_s = '0' else 1165 | ("0" & level_c_env_s(11 downto 1)); 1166 | 1167 | 1168 | pcm14s_o <= pcm14s_r; 1169 | 1170 | 1171 | process 1172 | ( clk_i, en_clk_psg_i 1173 | ) begin 1174 | if rising_edge(clk_i) then 1175 | if en_clk_psg_i = '1' then 1176 | 1177 | sign_a_r <= sign_a_x; 1178 | sign_b_r <= sign_b_x; 1179 | sign_c_r <= sign_c_x; 1180 | 1181 | -- Sum to signed 14-bit. 1182 | pcm14s_r <= 1183 | (sign_a_r(11) & sign_a_r(11) & sign_a_r) + 1184 | (sign_b_r(11) & sign_b_r(11) & sign_b_r) + 1185 | (sign_c_r(11) & sign_c_r(11) & sign_c_r); 1186 | 1187 | end if; 1188 | end if; 1189 | end process; 1190 | 1191 | end rtl; 1192 | -------------------------------------------------------------------------------- /ym2149_audio_simulation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnotq/ym2149_audio/ce6654e79768d3aff7f345f1fed51f33a8be593d/ym2149_audio_simulation.png --------------------------------------------------------------------------------