mirror of
https://github.com/UzixLS/zx-sizif-xxs.git
synced 2025-07-19 07:11:28 +03:00
replace ym2149 implementation
new implementation uses less LE's
This commit is contained in:
@ -10,8 +10,6 @@ module turbosound(
|
||||
output [7:0] d_out,
|
||||
output d_out_active,
|
||||
|
||||
input pause,
|
||||
|
||||
output [7:0] ay_a0,
|
||||
output [7:0] ay_b0,
|
||||
output [7:0] ay_c0,
|
||||
@ -49,7 +47,7 @@ reg [1:0] ay_ck;
|
||||
always @(posedge clk28 or negedge rst_n) begin
|
||||
if (!rst_n)
|
||||
ay_ck <= 0;
|
||||
else if (ck35 && en && !pause)
|
||||
else if (ck35)
|
||||
ay_ck <= ay_ck + 1'b1;
|
||||
else
|
||||
ay_ck[1] <= 0;
|
||||
@ -59,41 +57,33 @@ end
|
||||
wire [7:0] ay_dout0, ay_dout1;
|
||||
YM2149 ym2149_0(
|
||||
.CLK(clk28),
|
||||
.ENA(ay_ck[1]),
|
||||
.RESET_H(~rst_n),
|
||||
.I_SEL_L(1'b1),
|
||||
.I_DA(bus.d_reg),
|
||||
.O_DA(ay_dout0),
|
||||
.I_REG(1'b0),
|
||||
.busctrl_addr(ay_bc1 & ay_bdir & ~ay_sel),
|
||||
.busctrl_we(~ay_bc1 & ay_bdir & ~ay_sel),
|
||||
.ctrl_aymode(1'b1),
|
||||
.port_a_i(8'hff),
|
||||
.port_b_i(8'hff),
|
||||
.port_a_o(),
|
||||
.port_b_o(),
|
||||
.O_AUDIO_A(ay_a0),
|
||||
.O_AUDIO_B(ay_b0),
|
||||
.O_AUDIO_C(ay_c0)
|
||||
.CE(ay_ck[1]),
|
||||
.RESET(~rst_n),
|
||||
.A8(~ay_sel),
|
||||
.BDIR(ay_bdir),
|
||||
.BC(ay_bc1),
|
||||
.DI(bus.d_reg),
|
||||
.DO(ay_dout0),
|
||||
.SEL(1'b0),
|
||||
.MODE(1'b1),
|
||||
.CHANNEL_A(ay_a0),
|
||||
.CHANNEL_B(ay_b0),
|
||||
.CHANNEL_C(ay_c0)
|
||||
);
|
||||
YM2149 ym2149_1(
|
||||
.CLK(clk28),
|
||||
.ENA(ay_ck[1]),
|
||||
.RESET_H(~rst_n || !en_ts),
|
||||
.I_SEL_L(1'b1),
|
||||
.I_DA(bus.d_reg),
|
||||
.O_DA(ay_dout1),
|
||||
.I_REG(1'b0),
|
||||
.busctrl_addr(ay_bc1 & ay_bdir & ay_sel),
|
||||
.busctrl_we(~ay_bc1 & ay_bdir & ay_sel),
|
||||
.ctrl_aymode(1'b1),
|
||||
.port_a_i(8'hff),
|
||||
.port_b_i(8'hff),
|
||||
.port_a_o(),
|
||||
.port_b_o(),
|
||||
.O_AUDIO_A(ay_a1),
|
||||
.O_AUDIO_B(ay_b1),
|
||||
.O_AUDIO_C(ay_c1)
|
||||
.CE(ay_ck[1]),
|
||||
.RESET(~rst_n || !en_ts),
|
||||
.A8(ay_sel),
|
||||
.BDIR(ay_bdir),
|
||||
.BC(ay_bc1),
|
||||
.DI(bus.d_reg),
|
||||
.DO(ay_dout1),
|
||||
.SEL(1'b0),
|
||||
.MODE(1'b0),
|
||||
.CHANNEL_A(ay_a1),
|
||||
.CHANNEL_B(ay_b1),
|
||||
.CHANNEL_C(ay_c1)
|
||||
);
|
||||
|
||||
|
||||
|
325
fpga/rtl/ym2149.sv
Normal file
325
fpga/rtl/ym2149.sv
Normal file
@ -0,0 +1,325 @@
|
||||
//
|
||||
// Copyright (c) MikeJ - Jan 2005
|
||||
// Copyright (c) 2016-2018 Sorgelig
|
||||
//
|
||||
// All rights reserved
|
||||
//
|
||||
// Redistribution and use in source and synthezised forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in synthesized form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// Neither the name of the author nor the names of other contributors may
|
||||
// be used to endorse or promote products derived from this software without
|
||||
// specific prior written permission.
|
||||
//
|
||||
// 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 SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
// BDIR BC MODE
|
||||
// 0 0 inactive
|
||||
// 0 1 read value
|
||||
// 1 0 write value
|
||||
// 1 1 set address
|
||||
//
|
||||
|
||||
module YM2149
|
||||
(
|
||||
input CLK, // Global clock
|
||||
input CE, // PSG Clock enable
|
||||
input RESET, // Chip RESET (set all Registers to '0', active hi)
|
||||
input BDIR, // Bus Direction (0 - read , 1 - write)
|
||||
input BC, // Bus control
|
||||
input [7:0] DI, // Data In
|
||||
output [7:0] DO, // Data Out
|
||||
output [7:0] CHANNEL_A, // PSG Output channel A
|
||||
output [7:0] CHANNEL_B, // PSG Output channel B
|
||||
output [7:0] CHANNEL_C, // PSG Output channel C
|
||||
|
||||
input SEL,
|
||||
input MODE,
|
||||
|
||||
output [5:0] ACTIVE,
|
||||
input A8,
|
||||
|
||||
input [7:0] IOA_in,
|
||||
output [7:0] IOA_out,
|
||||
|
||||
input [7:0] IOB_in,
|
||||
output [7:0] IOB_out
|
||||
);
|
||||
|
||||
reg [7:0] addr;
|
||||
reg [7:0] ymreg[16];
|
||||
|
||||
assign ACTIVE = ~ymreg[7][5:0];
|
||||
assign IOA_out = ymreg[14];
|
||||
assign IOB_out = ymreg[15];
|
||||
|
||||
// Write to PSG
|
||||
reg env_reset;
|
||||
reg old_BDIR;
|
||||
always @(posedge CLK) begin
|
||||
if(RESET) begin
|
||||
ymreg <= '{default:0};
|
||||
ymreg[7] <= '1;
|
||||
addr <= '0;
|
||||
env_reset <= 0;
|
||||
end else begin
|
||||
env_reset <= 0;
|
||||
old_BDIR <= BDIR;
|
||||
if(~old_BDIR & BDIR & A8) begin
|
||||
if(BC) addr <= DI;
|
||||
else if(!addr[7:4]) begin
|
||||
ymreg[addr[3:0]] <= DI;
|
||||
env_reset <= (addr == 13);
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// Read from PSG
|
||||
reg [7:0] dout;
|
||||
assign DO = dout;
|
||||
always_comb begin
|
||||
dout = 8'hFF;
|
||||
if(~BDIR & BC & !addr[7:4]) begin
|
||||
case(addr[3:0])
|
||||
0: dout = ymreg[0];
|
||||
1: dout = ymreg[1][3:0];
|
||||
2: dout = ymreg[2];
|
||||
3: dout = ymreg[3][3:0];
|
||||
4: dout = ymreg[4];
|
||||
5: dout = ymreg[5][3:0];
|
||||
6: dout = ymreg[6][4:0];
|
||||
7: dout = ymreg[7];
|
||||
8: dout = ymreg[8][4:0];
|
||||
9: dout = ymreg[9][4:0];
|
||||
10: dout = ymreg[10][4:0];
|
||||
11: dout = ymreg[11];
|
||||
12: dout = ymreg[12];
|
||||
13: dout = ymreg[13][3:0];
|
||||
14: dout = ymreg[7][6] ? ymreg[14] & IOA_in : IOA_in;
|
||||
15: dout = ymreg[7][7] ? ymreg[15] & IOA_in : IOB_in;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
reg ena_div;
|
||||
reg ena_div_noise;
|
||||
|
||||
// p_divider
|
||||
always @(posedge CLK) begin
|
||||
reg [3:0] cnt_div;
|
||||
reg noise_div;
|
||||
|
||||
if(CE) begin
|
||||
ena_div <= 0;
|
||||
ena_div_noise <= 0;
|
||||
if(!cnt_div) begin
|
||||
cnt_div <= {SEL, 3'b111};
|
||||
ena_div <= 1;
|
||||
|
||||
noise_div <= (~noise_div);
|
||||
if (noise_div) ena_div_noise <= 1;
|
||||
end else begin
|
||||
cnt_div <= cnt_div - 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
reg [2:0] noise_gen_op;
|
||||
|
||||
// p_noise_gen
|
||||
always @(posedge CLK) begin
|
||||
reg [16:0] poly17;
|
||||
reg [4:0] noise_gen_cnt;
|
||||
|
||||
if(CE) begin
|
||||
if (ena_div_noise) begin
|
||||
if (!ymreg[6][4:0] || (noise_gen_cnt >= ymreg[6][4:0] - 1'd1)) begin
|
||||
noise_gen_cnt <= 0;
|
||||
poly17 <= {(poly17[0] ^ poly17[2] ^ !poly17), poly17[16:1]};
|
||||
end else begin
|
||||
noise_gen_cnt <= noise_gen_cnt + 1'd1;
|
||||
end
|
||||
noise_gen_op <= {3{poly17[0]}};
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
wire [11:0] tone_gen_freq[1:3];
|
||||
assign tone_gen_freq[1] = {ymreg[1][3:0], ymreg[0]};
|
||||
assign tone_gen_freq[2] = {ymreg[3][3:0], ymreg[2]};
|
||||
assign tone_gen_freq[3] = {ymreg[5][3:0], ymreg[4]};
|
||||
|
||||
reg [3:1] tone_gen_op;
|
||||
|
||||
//p_tone_gens
|
||||
always @(posedge CLK) begin
|
||||
integer i;
|
||||
reg [11:0] tone_gen_cnt[1:3];
|
||||
|
||||
if(CE) begin
|
||||
// looks like real chips count up - we need to get the Exact behaviour ..
|
||||
|
||||
for (i = 1; i <= 3; i = i + 1) begin
|
||||
if(ena_div) begin
|
||||
if (!tone_gen_freq[i] || (tone_gen_cnt[i] >= (tone_gen_freq[i] - 1'd1))) begin
|
||||
tone_gen_cnt[i] <= 0;
|
||||
tone_gen_op[i] <= ~tone_gen_op[i];
|
||||
end else begin
|
||||
tone_gen_cnt[i] <= tone_gen_cnt[i] + 1'd1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
reg env_ena;
|
||||
wire [15:0] env_gen_comp = {ymreg[12], ymreg[11]} ? {ymreg[12], ymreg[11]} - 1'd1 : 16'd0;
|
||||
|
||||
//p_envelope_freq
|
||||
always @(posedge CLK) begin
|
||||
reg [15:0] env_gen_cnt;
|
||||
|
||||
if(CE) begin
|
||||
env_ena <= 0;
|
||||
if(ena_div) begin
|
||||
if (env_gen_cnt >= env_gen_comp) begin
|
||||
env_gen_cnt <= 0;
|
||||
env_ena <= 1;
|
||||
end else begin
|
||||
env_gen_cnt <= (env_gen_cnt + 1'd1);
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
reg [4:0] env_vol;
|
||||
|
||||
wire is_bot = (env_vol == 5'b00000);
|
||||
wire is_bot_p1 = (env_vol == 5'b00001);
|
||||
wire is_top_m1 = (env_vol == 5'b11110);
|
||||
wire is_top = (env_vol == 5'b11111);
|
||||
|
||||
always @(posedge CLK) begin
|
||||
reg env_hold;
|
||||
reg env_inc;
|
||||
|
||||
// envelope shapes
|
||||
// C AtAlH
|
||||
// 0 0 x x \___
|
||||
//
|
||||
// 0 1 x x /___
|
||||
//
|
||||
// 1 0 0 0 \\\\
|
||||
//
|
||||
// 1 0 0 1 \___
|
||||
//
|
||||
// 1 0 1 0 \/\/
|
||||
// ___
|
||||
// 1 0 1 1 \
|
||||
//
|
||||
// 1 1 0 0 ////
|
||||
// ___
|
||||
// 1 1 0 1 /
|
||||
//
|
||||
// 1 1 1 0 /\/\
|
||||
//
|
||||
// 1 1 1 1 /___
|
||||
|
||||
if(env_reset | RESET) begin
|
||||
// load initial state
|
||||
if(!ymreg[13][2]) begin // attack
|
||||
env_vol <= 5'b11111;
|
||||
env_inc <= 0; // -1
|
||||
end else begin
|
||||
env_vol <= 5'b00000;
|
||||
env_inc <= 1; // +1
|
||||
end
|
||||
env_hold <= 0;
|
||||
end
|
||||
else if(CE) begin
|
||||
if (env_ena) begin
|
||||
if (!env_hold) begin
|
||||
if (env_inc) env_vol <= (env_vol + 5'b00001);
|
||||
else env_vol <= (env_vol + 5'b11111);
|
||||
end
|
||||
|
||||
// envelope shape control.
|
||||
if(!ymreg[13][3]) begin
|
||||
if(!env_inc) begin // down
|
||||
if(is_bot_p1) env_hold <= 1;
|
||||
end else if (is_top) env_hold <= 1;
|
||||
end else if(ymreg[13][0]) begin // hold = 1
|
||||
if(!env_inc) begin // down
|
||||
if(ymreg[13][1]) begin // alt
|
||||
if(is_bot) env_hold <= 1;
|
||||
end else if(is_bot_p1) env_hold <= 1;
|
||||
end else if(ymreg[13][1]) begin // alt
|
||||
if(is_top) env_hold <= 1;
|
||||
end else if(is_top_m1) env_hold <= 1;
|
||||
end else if(ymreg[13][1]) begin // alternate
|
||||
if(env_inc == 1'b0) begin // down
|
||||
if(is_bot_p1) env_hold <= 1;
|
||||
if(is_bot) begin
|
||||
env_hold <= 0;
|
||||
env_inc <= 1;
|
||||
end
|
||||
end else begin
|
||||
if(is_top_m1) env_hold <= 1;
|
||||
if(is_top) begin
|
||||
env_hold <= 0;
|
||||
env_inc <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
reg [5:0] A,B,C;
|
||||
always @(posedge CLK) begin
|
||||
A <= {MODE, ~((ymreg[7][0] | tone_gen_op[1]) & (ymreg[7][3] | noise_gen_op[0])) ? 5'd0 : ymreg[8][4] ? env_vol[4:0] : { ymreg[8][3:0], ymreg[8][3]}};
|
||||
B <= {MODE, ~((ymreg[7][1] | tone_gen_op[2]) & (ymreg[7][4] | noise_gen_op[1])) ? 5'd0 : ymreg[9][4] ? env_vol[4:0] : { ymreg[9][3:0], ymreg[9][3]}};
|
||||
C <= {MODE, ~((ymreg[7][2] | tone_gen_op[3]) & (ymreg[7][5] | noise_gen_op[2])) ? 5'd0 : ymreg[10][4] ? env_vol[4:0] : {ymreg[10][3:0], ymreg[10][3]}};
|
||||
end
|
||||
|
||||
wire [7:0] volTable[64] = '{
|
||||
//YM2149
|
||||
8'h00, 8'h01, 8'h01, 8'h02, 8'h02, 8'h03, 8'h03, 8'h04,
|
||||
8'h06, 8'h07, 8'h09, 8'h0a, 8'h0c, 8'h0e, 8'h11, 8'h13,
|
||||
8'h17, 8'h1b, 8'h20, 8'h25, 8'h2c, 8'h35, 8'h3e, 8'h47,
|
||||
8'h54, 8'h66, 8'h77, 8'h88, 8'ha1, 8'hc0, 8'he0, 8'hff,
|
||||
|
||||
//AY8910
|
||||
8'h00, 8'h00, 8'h03, 8'h03, 8'h04, 8'h04, 8'h06, 8'h06,
|
||||
8'h0a, 8'h0a, 8'h0f, 8'h0f, 8'h15, 8'h15, 8'h22, 8'h22,
|
||||
8'h28, 8'h28, 8'h41, 8'h41, 8'h5b, 8'h5b, 8'h72, 8'h72,
|
||||
8'h90, 8'h90, 8'hb5, 8'hb5, 8'hd7, 8'hd7, 8'hff, 8'hff
|
||||
};
|
||||
|
||||
assign CHANNEL_A = volTable[A];
|
||||
assign CHANNEL_B = volTable[B];
|
||||
assign CHANNEL_C = volTable[C];
|
||||
|
||||
endmodule
|
||||
|
@ -1,543 +0,0 @@
|
||||
--
|
||||
-- A simulation model of YM2149 (AY-3-8910 with bells on)
|
||||
--
|
||||
-- Copyright (c) MikeJ - Jan 2005
|
||||
--
|
||||
-- All rights reserved
|
||||
--
|
||||
-- Redistribution and use in source and synthezised forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- Redistributions in synthesized form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- Neither the name of the author nor the names of other contributors may
|
||||
-- be used to endorse or promote products derived from this software without
|
||||
-- specific prior written permission.
|
||||
--
|
||||
-- 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 SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
--
|
||||
-- You are responsible for any legal issues arising from your use of this code.
|
||||
--
|
||||
-- The latest version of this file can be found at: www.fpgaarcade.com
|
||||
--
|
||||
-- Email support@fpgaarcade.com
|
||||
--
|
||||
-- Revision list
|
||||
--
|
||||
-- version 001 initial release
|
||||
--
|
||||
-- Clues from MAME sound driver and Kazuhiro TSUJIKAWA
|
||||
--
|
||||
-- These are the measured outputs from a real chip for a single Isolated channel into a 1K load (V)
|
||||
-- vol 15 .. 0
|
||||
-- 3.27 2.995 2.741 2.588 2.452 2.372 2.301 2.258 2.220 2.198 2.178 2.166 2.155 2.148 2.141 2.132
|
||||
-- As the envelope volume is 5 bit, I have fitted a curve to the not quite log shape in order
|
||||
-- to produced all the required values.
|
||||
-- (The first part of the curve is a bit steeper and the last bit is more linear than expected)
|
||||
--
|
||||
|
||||
-- Modifications made for the ZX Spectrum Next Project
|
||||
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
|
||||
--
|
||||
-- 1. Bus addressing moved out of module
|
||||
-- 2. Channel mixing moved out of module
|
||||
-- 3. Eliminate unnecessary busctrl_re
|
||||
-- 4. Make zero volume actually zero volume in the tables.
|
||||
-- (Not how the real hw works but it makes audio out of the zx next cleaner)
|
||||
-- 5. Add differences in how registers are read back on YM and AY
|
||||
-- 6. Fix bug where envelope period counter was not reset on envelope reset
|
||||
-- 7. Export currently selected register
|
||||
|
||||
library ieee;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
entity YM2149 is
|
||||
generic (
|
||||
constant AY_ID : std_logic_vector(1 downto 0) := "00"
|
||||
);
|
||||
port (
|
||||
CLK : in std_logic; -- note 6 Mhz
|
||||
ENA : in std_logic; -- clock enable for higher speed operation
|
||||
RESET_H : in std_logic;
|
||||
I_SEL_L : in std_logic;
|
||||
-- data bus
|
||||
I_DA : in std_logic_vector(7 downto 0);
|
||||
O_DA : out std_logic_vector(7 downto 0);
|
||||
I_REG : in std_logic;
|
||||
-- control
|
||||
busctrl_addr : in std_logic;
|
||||
busctrl_we : in std_logic;
|
||||
ctrl_aymode : in std_logic; -- 0 = YM, 1 = AY
|
||||
-- I/O ports
|
||||
port_a_i : in std_logic_vector(7 downto 0);
|
||||
port_a_o : out std_logic_vector(7 downto 0);
|
||||
port_b_i : in std_logic_vector(7 downto 0);
|
||||
port_b_o : out std_logic_vector(7 downto 0);
|
||||
-- audio channels out
|
||||
O_AUDIO_A : out std_logic_vector(7 downto 0);
|
||||
O_AUDIO_B : out std_logic_vector(7 downto 0);
|
||||
O_AUDIO_C : out std_logic_vector(7 downto 0)
|
||||
);
|
||||
end;
|
||||
|
||||
architecture RTL of YM2149 is
|
||||
|
||||
-- signals
|
||||
type array_16x8 is array (0 to 15) of std_logic_vector(7 downto 0);
|
||||
type array_3x12 is array (1 to 3) of std_logic_vector(11 downto 0);
|
||||
|
||||
signal cnt_div : std_logic_vector(3 downto 0) := (others => '0');
|
||||
signal noise_div : std_logic := '0';
|
||||
signal ena_div : std_logic;
|
||||
signal ena_div_noise : std_logic;
|
||||
signal noise_gen_comp : std_logic_vector(4 downto 0);
|
||||
signal poly17_zero : std_logic;
|
||||
signal poly17 : std_logic_vector(16 downto 0) := (others => '0');
|
||||
|
||||
-- registers
|
||||
signal addr : std_logic_vector(4 downto 0);
|
||||
|
||||
signal reg : array_16x8;
|
||||
signal env_reset : std_logic;
|
||||
|
||||
signal noise_gen_cnt : std_logic_vector(4 downto 0);
|
||||
signal noise_gen_op : std_logic;
|
||||
signal tone_gen_freq : array_3x12;
|
||||
signal tone_gen_comp : array_3x12;
|
||||
signal tone_gen_cnt : array_3x12 := (others => (others => '0'));
|
||||
signal tone_gen_op : std_logic_vector(3 downto 1) := "000";
|
||||
|
||||
signal is_zero : std_logic;
|
||||
signal is_ones : std_logic;
|
||||
signal is_bot : std_logic;
|
||||
signal is_bot_p1 : std_logic;
|
||||
signal is_top_m1 : std_logic;
|
||||
signal is_top : std_logic;
|
||||
|
||||
signal env_gen_freq : std_logic_vector(15 downto 0);
|
||||
signal env_gen_comp : std_logic_vector(15 downto 0);
|
||||
signal env_gen_cnt : std_logic_vector(15 downto 0);
|
||||
signal env_ena : std_logic;
|
||||
signal env_hold : std_logic;
|
||||
signal env_inc : std_logic;
|
||||
signal env_vol : std_logic_vector(4 downto 0);
|
||||
|
||||
signal chan_mixed : std_logic_vector(2 downto 0);
|
||||
|
||||
signal A : std_logic_vector(4 downto 0);
|
||||
signal B : std_logic_vector(4 downto 0);
|
||||
signal C : std_logic_vector(4 downto 0);
|
||||
|
||||
type volTableType32 is array (0 to 31) of unsigned(7 downto 0);
|
||||
type volTableType16 is array (0 to 15) of unsigned(7 downto 0);
|
||||
|
||||
constant volTableAy : volTableType16 :=(
|
||||
x"00", x"03", x"04", x"06",
|
||||
x"0a", x"0f", x"15", x"22",
|
||||
x"28", x"41", x"5b", x"72",
|
||||
x"90", x"b5", x"d7", x"ff"
|
||||
);
|
||||
|
||||
constant volTableYm : volTableType32 :=(
|
||||
x"00", x"01", x"01", x"02", x"02", x"03", x"03", x"04",
|
||||
x"06", x"07", x"09", x"0a", x"0c", x"0e", x"11", x"13",
|
||||
x"17", x"1b", x"20", x"25", x"2c", x"35", x"3e", x"47",
|
||||
x"54", x"66", x"77", x"88", x"a1", x"c0", x"e0", x"ff"
|
||||
);
|
||||
|
||||
begin
|
||||
|
||||
--p_waddr : process(RESET_H, busctrl_addr)
|
||||
process(clk)
|
||||
begin
|
||||
if clk'event and clk = '1' then
|
||||
if (RESET_H = '1') then
|
||||
addr <= (others => '0');
|
||||
elsif busctrl_addr = '1' then -- yuk
|
||||
addr <= I_DA(4 downto 0);
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
--p_wdata : process(RESET_H, busctrl_we, addr)
|
||||
process(clk)
|
||||
begin
|
||||
if clk'event and clk = '1' then
|
||||
env_reset <= '0';
|
||||
|
||||
if RESET_H = '1' then
|
||||
reg <= (others => (others => '0'));
|
||||
reg(7) <= x"ff";
|
||||
|
||||
elsif busctrl_we = '1' and addr(4) = '0' then -- bits 7:5 are checked for 0 outside this module
|
||||
case addr(3 downto 0) is
|
||||
when x"0" => reg(0) <= I_DA;
|
||||
when x"1" => reg(1) <= I_DA;
|
||||
when x"2" => reg(2) <= I_DA;
|
||||
when x"3" => reg(3) <= I_DA;
|
||||
when x"4" => reg(4) <= I_DA;
|
||||
when x"5" => reg(5) <= I_DA;
|
||||
when x"6" => reg(6) <= I_DA;
|
||||
when x"7" => reg(7) <= I_DA;
|
||||
when x"8" => reg(8) <= I_DA;
|
||||
when x"9" => reg(9) <= I_DA;
|
||||
when x"A" => reg(10) <= I_DA;
|
||||
when x"B" => reg(11) <= I_DA;
|
||||
when x"C" => reg(12) <= I_DA;
|
||||
when x"D" => reg(13) <= I_DA;
|
||||
when x"E" => reg(14) <= I_DA;
|
||||
when x"F" => reg(15) <= I_DA;
|
||||
when others => null;
|
||||
end case;
|
||||
|
||||
if addr(3 downto 0) = x"D" then
|
||||
env_reset <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
--p_rdata : process(busctrl_re, addr, reg)
|
||||
process(clk)
|
||||
begin
|
||||
if clk'event and clk = '1' then
|
||||
if I_REG = '1' then
|
||||
O_DA <= AY_ID & '0' & addr;
|
||||
elsif addr(4) = '1' and ctrl_aymode = '0' then
|
||||
O_DA <= x"FF";
|
||||
else
|
||||
case addr(3 downto 0) is
|
||||
when x"0" => O_DA <= reg(0) ;
|
||||
when x"1" => O_DA <= (reg(1)(7) and not ctrl_aymode) & (reg(1)(6) and not ctrl_aymode) & (reg(1)(5) and not ctrl_aymode) & (reg(1)(4) and not ctrl_aymode) & reg(1)(3 downto 0) ;
|
||||
when x"2" => O_DA <= reg(2) ;
|
||||
when x"3" => O_DA <= (reg(3)(7) and not ctrl_aymode) & (reg(3)(6) and not ctrl_aymode) & (reg(3)(5) and not ctrl_aymode) & (reg(3)(4) and not ctrl_aymode) & reg(3)(3 downto 0) ;
|
||||
when x"4" => O_DA <= reg(4) ;
|
||||
when x"5" => O_DA <= (reg(5)(7) and not ctrl_aymode) & (reg(5)(6) and not ctrl_aymode) & (reg(5)(5) and not ctrl_aymode) & (reg(5)(4) and not ctrl_aymode) & reg(5)(3 downto 0) ;
|
||||
when x"6" => O_DA <= (reg(6)(7) and not ctrl_aymode) & (reg(6)(6) and not ctrl_aymode) & (reg(6)(5) and not ctrl_aymode) & reg(6)(4 downto 0) ;
|
||||
when x"7" => O_DA <= reg(7) ;
|
||||
when x"8" => O_DA <= (reg(8)(7) and not ctrl_aymode) & (reg(8)(6) and not ctrl_aymode) & (reg(8)(5) and not ctrl_aymode) & reg(8)(4 downto 0) ;
|
||||
when x"9" => O_DA <= (reg(9)(7) and not ctrl_aymode) & (reg(9)(6) and not ctrl_aymode) & (reg(9)(5) and not ctrl_aymode) & reg(9)(4 downto 0) ;
|
||||
when x"A" => O_DA <= (reg(10)(7) and not ctrl_aymode) & (reg(10)(6) and not ctrl_aymode) & (reg(10)(5) and not ctrl_aymode) & reg(10)(4 downto 0) ;
|
||||
when x"B" => O_DA <= reg(11);
|
||||
when x"C" => O_DA <= reg(12);
|
||||
when x"D" => O_DA <= (reg(13)(7) and not ctrl_aymode) & (reg(13)(6) and not ctrl_aymode) & (reg(13)(5) and not ctrl_aymode) & (reg(13)(4) and not ctrl_aymode) & reg(13)(3 downto 0) ;
|
||||
when x"E" => if (reg(7)(6) = '0') then -- input
|
||||
O_DA <= port_a_i;
|
||||
else
|
||||
O_DA <= reg(14) and port_a_i;
|
||||
end if;
|
||||
when x"F" => if (Reg(7)(7) = '0') then
|
||||
O_DA <= port_b_i;
|
||||
else
|
||||
O_DA <= reg(15) and port_b_i;
|
||||
end if;
|
||||
when others => null;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
port_a_o <= reg(14);
|
||||
port_b_o <= reg(15);
|
||||
|
||||
-- p_divider : process
|
||||
process(clk)
|
||||
begin
|
||||
if clk'event and clk = '1' then
|
||||
if ENA = '1' then
|
||||
ena_div <= '0';
|
||||
ena_div_noise <= '0';
|
||||
if (cnt_div = "0000") then
|
||||
cnt_div <= (not I_SEL_L) & "111";
|
||||
ena_div <= '1';
|
||||
|
||||
noise_div <= not noise_div;
|
||||
if (noise_div = '1') then
|
||||
ena_div_noise <= '1';
|
||||
end if;
|
||||
else
|
||||
cnt_div <= std_logic_vector(unsigned(cnt_div) - 1);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- p_noise_gen : process
|
||||
|
||||
noise_gen_comp <= (std_logic_vector(unsigned(reg(6)(4 downto 0)) - 1)) when (reg(6)(4 downto 1) /= "0000") else (others => '0');
|
||||
poly17_zero <= '1' when (poly17 = "00000000000000000") else '0';
|
||||
|
||||
process(clk)
|
||||
begin
|
||||
if clk'event and clk = '1' then
|
||||
if (ENA = '1') then
|
||||
if (ena_div_noise = '1') then -- divider ena
|
||||
if (noise_gen_cnt >= noise_gen_comp) then
|
||||
noise_gen_cnt <= "00000";
|
||||
poly17 <= (poly17(0) xor poly17(2) xor poly17_zero) & poly17(16 downto 1);
|
||||
else
|
||||
noise_gen_cnt <= std_logic_vector(unsigned(noise_gen_cnt) + 1);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
noise_gen_op <= poly17(0);
|
||||
|
||||
--p_tone_gens : process
|
||||
|
||||
tone_gen_freq(1) <= reg(1)(3 downto 0) & reg(0);
|
||||
tone_gen_freq(2) <= reg(3)(3 downto 0) & reg(2);
|
||||
tone_gen_freq(3) <= reg(5)(3 downto 0) & reg(4);
|
||||
|
||||
tone_gen_comp(1) <= (std_logic_vector(unsigned(tone_gen_freq(1)) - 1)) when (tone_gen_freq(1)(11 downto 1) /= (x"00" & "000")) else (others => '0');
|
||||
tone_gen_comp(2) <= (std_logic_vector(unsigned(tone_gen_freq(2)) - 1)) when (tone_gen_freq(2)(11 downto 1) /= (x"00" & "000")) else (others => '0');
|
||||
tone_gen_comp(3) <= (std_logic_vector(unsigned(tone_gen_freq(3)) - 1)) when (tone_gen_freq(3)(11 downto 1) /= (x"00" & "000")) else (others => '0');
|
||||
|
||||
process(clk)
|
||||
begin
|
||||
if clk'event and clk = '1' then
|
||||
if (ENA = '1') then
|
||||
for i in 1 to 3 loop
|
||||
if (ena_div = '1') then -- divider ena
|
||||
if (tone_gen_cnt(i) >= tone_gen_comp(i)) then
|
||||
tone_gen_cnt(i) <= x"000";
|
||||
tone_gen_op(i) <= not tone_gen_op(i);
|
||||
else
|
||||
tone_gen_cnt(i) <= std_logic_vector(unsigned(tone_gen_cnt(i)) + 1);
|
||||
end if;
|
||||
end if;
|
||||
end loop;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
--p_envelope_freq : process
|
||||
|
||||
env_gen_freq <= reg(12) & reg(11);
|
||||
env_gen_comp <= (std_logic_vector(unsigned(env_gen_freq) - 1)) when (env_gen_freq(15 downto 1) /= (x"000" & "000")) else (others => '0');
|
||||
|
||||
process(clk)
|
||||
begin
|
||||
if clk'event and clk = '1' then
|
||||
if env_reset = '1' then
|
||||
env_gen_cnt <= x"0000";
|
||||
env_ena <= '1';
|
||||
elsif (ENA = '1') then
|
||||
if (ena_div = '1') then -- divider ena
|
||||
if (env_gen_cnt >= env_gen_comp) then
|
||||
env_gen_cnt <= x"0000";
|
||||
env_ena <= '1';
|
||||
else
|
||||
env_gen_cnt <= std_logic_vector( unsigned( env_gen_cnt ) + 1 );
|
||||
env_ena <= '0';
|
||||
end if;
|
||||
else
|
||||
env_ena <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
--p_envelope_shape : process(env_reset, CLK)
|
||||
|
||||
is_zero <= '1' when env_vol(4 downto 1) = "0000" else '0';
|
||||
is_ones <= '1' when env_vol(4 downto 1) = "1111" else '0';
|
||||
|
||||
is_bot <= '1' when is_zero = '1' and env_vol(0) = '0' else '0';
|
||||
is_bot_p1 <= '1' when is_zero ='1' and env_vol(0) = '1' else '0';
|
||||
is_top_m1 <= '1' when is_ones = '1' and env_vol(0) = '0' else '0';
|
||||
is_top <= '1' when is_ones = '1' and env_vol(0) = '1' else '0';
|
||||
|
||||
process(clk)
|
||||
begin
|
||||
-- envelope shapes
|
||||
-- C AtAlH
|
||||
-- 0 0 x x \___
|
||||
--
|
||||
-- 0 1 x x /___
|
||||
--
|
||||
-- 1 0 0 0 \\\\
|
||||
--
|
||||
-- 1 0 0 1 \___
|
||||
--
|
||||
-- 1 0 1 0 \/\/
|
||||
-- ___
|
||||
-- 1 0 1 1 \
|
||||
--
|
||||
-- 1 1 0 0 ////
|
||||
-- ___
|
||||
-- 1 1 0 1 /
|
||||
--
|
||||
-- 1 1 1 0 /\/\
|
||||
--
|
||||
-- 1 1 1 1 /___
|
||||
if clk'event and clk = '1' then
|
||||
if env_reset = '1' then
|
||||
-- load initial state
|
||||
if (reg(13)(2) = '0') then -- attack
|
||||
env_vol <= "11111";
|
||||
env_inc <= '0'; -- -1
|
||||
else
|
||||
env_vol <= "00000";
|
||||
env_inc <= '1'; -- +1
|
||||
end if;
|
||||
env_hold <= '0';
|
||||
elsif (ENA = '1') and (env_ena = '1') then
|
||||
if (env_hold = '0') then
|
||||
if (env_inc = '1') then
|
||||
env_vol <= std_logic_vector( unsigned( env_vol ) + "00001");
|
||||
else
|
||||
env_vol <= std_logic_vector( unsigned( env_vol ) + "11111");
|
||||
end if;
|
||||
end if;
|
||||
-- envelope shape control.
|
||||
if (reg(13)(3) = '0') then
|
||||
if (env_inc = '0') then -- down
|
||||
if is_bot_p1 = '1' then
|
||||
env_hold <= '1';
|
||||
end if;
|
||||
else
|
||||
if is_top = '1' then
|
||||
env_hold <= '1';
|
||||
end if;
|
||||
end if;
|
||||
elsif (reg(13)(0) = '1') then -- hold = 1
|
||||
if (env_inc = '0') then -- down
|
||||
if (reg(13)(1) = '1') then -- alt
|
||||
if is_bot = '1' then
|
||||
env_hold <= '1';
|
||||
end if;
|
||||
else
|
||||
if is_bot_p1 = '1' then
|
||||
env_hold <= '1';
|
||||
end if;
|
||||
end if;
|
||||
else
|
||||
if (reg(13)(1) = '1') then -- alt
|
||||
if is_top = '1' then
|
||||
env_hold <= '1';
|
||||
end if;
|
||||
else
|
||||
if is_top_m1 = '1' then
|
||||
env_hold <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
elsif (reg(13)(1) = '1') then -- alternate
|
||||
if (env_inc = '0') then -- down
|
||||
if is_bot_p1 = '1' then
|
||||
env_hold <= '1';
|
||||
end if;
|
||||
if is_bot = '1' then
|
||||
env_hold <= '0';
|
||||
env_inc <= '1';
|
||||
end if;
|
||||
else
|
||||
if is_top_m1 = '1' then
|
||||
env_hold <= '1';
|
||||
end if;
|
||||
if is_top = '1' then
|
||||
env_hold <= '0';
|
||||
env_inc <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
--p_chan_mixer_table : process
|
||||
|
||||
chan_mixed(0) <= (reg(7)(0) or tone_gen_op(1)) and (reg(7)(3) or noise_gen_op);
|
||||
chan_mixed(1) <= (reg(7)(1) or tone_gen_op(2)) and (reg(7)(4) or noise_gen_op);
|
||||
chan_mixed(2) <= (reg(7)(2) or tone_gen_op(3)) and (reg(7)(5) or noise_gen_op);
|
||||
|
||||
process(clk)
|
||||
begin
|
||||
if clk'event and clk = '1' then
|
||||
if (ENA = '1') then
|
||||
|
||||
A <= "00000";
|
||||
B <= "00000";
|
||||
C <= "00000";
|
||||
|
||||
if (chan_mixed(0) = '1') then
|
||||
if (reg(8)(4) = '0') then
|
||||
if (reg(8)(3 downto 0) = "0000") then
|
||||
A <= "00000";
|
||||
else
|
||||
A <= reg(8)(3 downto 0) & "1";
|
||||
end if;
|
||||
else
|
||||
A <= env_vol(4 downto 0);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if (chan_mixed(1) = '1') then
|
||||
if (reg(9)(4) = '0') then
|
||||
if (reg(9)(3 downto 0) = "0000") then
|
||||
B <= "00000";
|
||||
else
|
||||
B <= reg(9)(3 downto 0) & "1";
|
||||
end if;
|
||||
else
|
||||
B <= env_vol(4 downto 0);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if (chan_mixed(2) = '1') then
|
||||
if (reg(10)(4) = '0') then
|
||||
if (reg(10)(3 downto 0) = "0000") then
|
||||
C <= "00000";
|
||||
else
|
||||
C <= reg(10)(3 downto 0) & "1";
|
||||
end if;
|
||||
else
|
||||
C <= env_vol(4 downto 0);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
process(clk)
|
||||
begin
|
||||
if clk'event and clk = '1' then
|
||||
if RESET_H = '1' then
|
||||
O_AUDIO_A <= x"00";
|
||||
O_AUDIO_B <= x"00";
|
||||
O_AUDIO_C <= x"00";
|
||||
else
|
||||
if(ctrl_aymode = '0') then
|
||||
O_AUDIO_A <= std_logic_vector( volTableYm( to_integer( unsigned( A ) ) ) );
|
||||
O_AUDIO_B <= std_logic_vector( volTableYm( to_integer( unsigned( B ) ) ) );
|
||||
O_AUDIO_C <= std_logic_vector( volTableYm( to_integer( unsigned( C ) ) ) );
|
||||
else
|
||||
O_AUDIO_A <= std_logic_vector( volTableAy( to_integer( unsigned( A(4 downto 1) ) ) ) );
|
||||
O_AUDIO_B <= std_logic_vector( volTableAy( to_integer( unsigned( B(4 downto 1) ) ) ) );
|
||||
O_AUDIO_C <= std_logic_vector( volTableAy( to_integer( unsigned( C(4 downto 1) ) ) ) );
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end architecture RTL;
|
Reference in New Issue
Block a user