mirror of https://github.com/zxdos/zxuno.git
223 lines
8.2 KiB
Verilog
223 lines
8.2 KiB
Verilog
`timescale 1ns / 1ps
|
|
|
|
// This file is part of the ZXUNO Spectrum core.
|
|
// Creation date is 04:04:00 2012-04-01 by Miguel Angel Rodriguez Jodar
|
|
// (c)2014-2020 ZXUNO association.
|
|
// ZXUNO official repository: http://svn.zxuno.com/svn/zxuno
|
|
// Username: guest Password: zxuno
|
|
// Github repository for this core: https://github.com/mcleod-ideafix/zxuno_spectrum_core
|
|
//
|
|
// ZXUNO Spectrum core is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// ZXUNO Spectrum core is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with the ZXUNO Spectrum core. If not, see <https://www.gnu.org/licenses/>.
|
|
//
|
|
// Any distributed copy of this file must keep this notice intact.
|
|
|
|
`define MSBI 8 // Most significant Bit of DAC input
|
|
|
|
//This is a Delta-Sigma Digital to Analog Converter
|
|
module dac (DACout, DACin, Clk, Reset);
|
|
output DACout; // This is the average output that feeds low pass filter
|
|
input [`MSBI:0] DACin; // DAC input (excess 2**MSBI)
|
|
input Clk;
|
|
input Reset;
|
|
|
|
reg DACout; // for optimum performance, ensure that this ff is in IOB
|
|
reg [`MSBI+2:0] DeltaAdder; // Output of Delta adder
|
|
reg [`MSBI+2:0] SigmaAdder; // Output of Sigma adder
|
|
reg [`MSBI+2:0] SigmaLatch = 1'b1 << (`MSBI+1); // Latches output of Sigma adder
|
|
reg [`MSBI+2:0] DeltaB; // B input of Delta adder
|
|
|
|
always @(SigmaLatch) DeltaB = {SigmaLatch[`MSBI+2], SigmaLatch[`MSBI+2]} << (`MSBI+1);
|
|
always @(DACin or DeltaB) DeltaAdder = DACin + DeltaB;
|
|
always @(DeltaAdder or SigmaLatch) SigmaAdder = DeltaAdder + SigmaLatch;
|
|
always @(posedge Clk)
|
|
begin
|
|
if(Reset)
|
|
begin
|
|
SigmaLatch <= #1 1'b1 << (`MSBI+1);
|
|
DACout <= #1 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
SigmaLatch <= #1 SigmaAdder;
|
|
DACout <= #1 SigmaLatch[`MSBI+2];
|
|
end
|
|
end
|
|
endmodule
|
|
|
|
|
|
/*
|
|
The sound mix is controlled by port #F7 (sets the mix for the
|
|
currently selected PSG). There are two channels for the beeper.
|
|
When one channel is active the beeper is at the same volume level as
|
|
a single PSG channel at full volume. When both are active and have
|
|
the same pan it is then double the volume of a single PSG channel.
|
|
This approximates the relative loudness of the beeper on 128K
|
|
machines.
|
|
|
|
D6-7: channel A
|
|
D4-5: channel B
|
|
D3-2: channel C
|
|
D1-0: channel D (beeper)
|
|
|
|
Panning is limited to switching a channel on or off for a given
|
|
speaker. The bits are decoded as follows:
|
|
|
|
00 = mute
|
|
10 = left
|
|
01 = right
|
|
11 = both
|
|
|
|
The default port value on reset is zero (all channels off).
|
|
*/
|
|
module panner_and_mixer (
|
|
input wire clk,
|
|
input wire mrst_n,
|
|
input wire [7:0] a,
|
|
input wire iorq_n,
|
|
input wire rd_n,
|
|
input wire wr_n,
|
|
input wire [7:0] din,
|
|
output reg [7:0] dout,
|
|
output reg oe,
|
|
//--- SOUND SOURCES ---
|
|
input wire mic,
|
|
input wire ear,
|
|
input wire spk,
|
|
input wire [7:0] ay1_cha,
|
|
input wire [7:0] ay1_chb,
|
|
input wire [7:0] ay1_chc,
|
|
input wire [7:0] ay2_cha,
|
|
input wire [7:0] ay2_chb,
|
|
input wire [7:0] ay2_chc,
|
|
input wire [7:0] specdrum,
|
|
input wire [15:0] midi_left,
|
|
input wire [15:0] midi_right,
|
|
input wire [ 7:0] saa_left,
|
|
input wire [ 7:0] saa_right,
|
|
|
|
// --- OUTPUTs ---
|
|
output wire output_left,
|
|
output wire output_right
|
|
);
|
|
|
|
`include "config.vh"
|
|
|
|
// Register accepts data from CPU
|
|
reg [7:0] mixer = 8'b10_01_11_11; // ACB mode, Specdrum and beeper on both channels
|
|
always @(posedge clk) begin
|
|
if (mrst_n == 1'b0)
|
|
mixer <= 8'b10_01_11_11;
|
|
else if (a == AUDIOMIXER && iorq_n == 1'b0 && wr_n == 1'b0)
|
|
mixer <= din;
|
|
end
|
|
|
|
// CPU reads register
|
|
always @* begin
|
|
dout = mixer;
|
|
if (a == 8'hF7 && iorq_n == 1'b0 && rd_n == 1'b0)
|
|
oe = 1'b1;
|
|
else
|
|
oe = 1'b0;
|
|
end
|
|
|
|
// Mixer for EAR, MIC and SPK
|
|
reg [7:0] beeper;
|
|
always @(posedge clk) begin
|
|
case ({ear,spk,mic})
|
|
3'b000: beeper <= 8'd0;
|
|
3'b001: beeper <= 8'd36;
|
|
3'b010: beeper <= 8'd184;
|
|
3'b011: beeper <= 8'd192;
|
|
3'b100: beeper <= 8'd64;
|
|
3'b101: beeper <= 8'd100;
|
|
3'b110: beeper <= 8'd248;
|
|
3'b111: beeper <= 8'd255;
|
|
endcase
|
|
end
|
|
|
|
reg [10:0] mixleft = 11'h000;
|
|
reg [10:0] mixright = 11'h000;
|
|
reg [8:0] left, right;
|
|
// reg [7:0] compressor[0:2047];
|
|
// initial $readmemh ("curva_compress.hex", compressor);
|
|
|
|
// always @(posedge clk) begin
|
|
//// mixleft <= ((mixer[7])? {4'b0000,ay1_cha[7:1]} + {4'b0000,ay2_cha[7:1]} : 11'h000 ) +
|
|
//// ((mixer[5])? {4'b0000,ay1_chb[7:1]} + {4'b0000,ay2_chb[7:1]} : 11'h000 ) +
|
|
//// ((mixer[3])? {4'b0000,ay1_chc[7:1]} + {4'b0000,ay2_chc[7:1]} : 11'h000 ) +
|
|
//// ((mixer[1])? {3'b000,beeper} + midi_left[15:5] + {{3{specdrum_left[7]}},specdrum_left}: 11'h000 );
|
|
//// mixright <= ((mixer[6])? {4'b0000,ay1_cha[7:1]} + {4'b0000,ay2_cha[7:1]} : 11'h000 ) +
|
|
//// ((mixer[4])? {4'b0000,ay1_chb[7:1]} + {4'b0000,ay2_chb[7:1]} : 11'h000 ) +
|
|
//// ((mixer[2])? {4'b0000,ay1_chc[7:1]} + {4'b0000,ay2_chc[7:1]} : 11'h000 ) +
|
|
//// ((mixer[0])? {3'b000,beeper} + midi_right[15:5] + {{3{specdrum_right[7]}},specdrum_right}: 11'h000 );
|
|
// mixleft <= ((mixer[7])? {3'b000,ay1_cha} + {3'b000,ay2_cha} : 11'h000 ) +
|
|
// ((mixer[5])? {3'b000,ay1_chb} + {3'b000,ay2_chb} : 11'h000 ) +
|
|
// ((mixer[3])? {3'b000,ay1_chc} + {3'b000,ay2_chc} : 11'h000 ) +
|
|
// ((mixer[1])? {2'b00,beeper,beeper[7]} + midi_left[15:5] + {specdrum_left[7],specdrum_left,2'b00}: 11'h000 );
|
|
// mixright <= ((mixer[6])? {3'b000,ay1_cha} + {3'b000,ay2_cha} : 11'h000 ) +
|
|
// ((mixer[4])? {3'b000,ay1_chb} + {3'b000,ay2_chb} : 11'h000 ) +
|
|
// ((mixer[2])? {3'b000,ay1_chc} + {3'b000,ay2_chc} : 11'h000 ) +
|
|
// ((mixer[0])? {2'b00,beeper,beeper[7]} + midi_right[15:5] + {specdrum_right[7],specdrum_right,2'b00}: 11'h000 );
|
|
// left <= compressor[mixleft];
|
|
// right <= compressor[mixright];
|
|
// end
|
|
|
|
reg [10:0] ay1_cha_signed, ay1_chb_signed, ay1_chc_signed;
|
|
reg [10:0] ay2_cha_signed, ay2_chb_signed, ay2_chc_signed;
|
|
reg [10:0] beeper_signed, specdrum_signed;
|
|
reg [10:0] midi_left_signed, midi_right_signed;
|
|
reg [10:0] saa_left_signed, saa_right_signed;
|
|
always @(posedge clk) begin
|
|
// extender a 11 bits
|
|
ay1_cha_signed <= {3'b000, ay1_cha};
|
|
ay1_chb_signed <= {3'b000, ay1_chb};
|
|
ay1_chc_signed <= {3'b000, ay1_chc};
|
|
ay2_cha_signed <= {3'b000, ay2_cha};
|
|
ay2_chb_signed <= {3'b000, ay2_chb};
|
|
ay2_chc_signed <= {3'b000, ay2_chc};
|
|
beeper_signed <= {3'b000, beeper};
|
|
specdrum_signed <= {2'b00, specdrum, specdrum[7]};
|
|
midi_left_signed <= midi_left[15:5] ^ 11'b10000000000;
|
|
midi_right_signed <= midi_right[15:5] ^ 11'b10000000000;
|
|
saa_left_signed <= {1'b0, saa_left, 2'b00};
|
|
saa_right_signed <= {1'b0, saa_right, 2'b00};
|
|
|
|
mixleft <= ((mixer[7])? ay1_cha_signed + ay2_cha_signed : 11'h000 ) +
|
|
((mixer[5])? ay1_chb_signed + ay2_chb_signed : 11'h000 ) +
|
|
((mixer[3])? ay1_chc_signed + ay2_chc_signed : 11'h000 ) +
|
|
((mixer[1])? beeper_signed + midi_left_signed + specdrum_signed + saa_left_signed: 11'h000 );
|
|
mixright <= ((mixer[6])? ay1_cha_signed + ay2_cha_signed : 11'h000 ) +
|
|
((mixer[4])? ay1_chb_signed + ay2_chb_signed : 11'h000 ) +
|
|
((mixer[2])? ay1_chc_signed + ay2_chc_signed : 11'h000 ) +
|
|
((mixer[0])? beeper_signed + midi_right_signed + specdrum_signed + saa_right_signed: 11'h000 );
|
|
left <= mixleft[10:2];
|
|
right <= mixright[10:2];
|
|
end
|
|
|
|
// DACs
|
|
dac audio_dac_left (
|
|
.DACout(output_left),
|
|
.DACin(left),
|
|
.Clk(clk),
|
|
.Reset(!mrst_n)
|
|
);
|
|
|
|
dac audio_dac_right (
|
|
.DACout(output_right),
|
|
.DACin(right),
|
|
.Clk(clk),
|
|
.Reset(!mrst_n)
|
|
);
|
|
endmodule
|