`timescale 1ns / 1ps
|
`timescale 1ns / 1ps
|
// ============================================================================
|
// ============================================================================
|
// __
|
// __
|
// \\__/ o\ (C) 2007-2017 Robert Finch, Waterloo
|
// \\__/ o\ (C) 2007-2017 Robert Finch, Waterloo
|
// \ __ / All rights reserved.
|
// \ __ / All rights reserved.
|
// \/_// robfinch<remove>@finitron.ca
|
// \/_// robfinch<remove>@finitron.ca
|
// ||
|
// ||
|
//
|
//
|
// PSG32.v
|
// PSG32.v
|
//
|
//
|
// This source file is free software: you can redistribute it and/or modify
|
// This source file is free software: you can redistribute it and/or modify
|
// it under the terms of the GNU Lesser General Public License as published
|
// it under the terms of the GNU Lesser General Public License as published
|
// by the Free Software Foundation, either version 3 of the License, or
|
// by the Free Software Foundation, either version 3 of the License, or
|
// (at your option) any later version.
|
// (at your option) any later version.
|
//
|
//
|
// This source file is distributed in the hope that it will be useful,
|
// This source file is distributed in the hope that it will be useful,
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
//
|
//
|
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
//
|
//
|
//
|
//
|
// Registers
|
// Registers
|
// 00 -------- ffffffff ffffffff ffffffff freq [23:0]
|
// 00 -------- ffffffff ffffffff ffffffff freq [23:0]
|
// 04 -------- -------- pppppppp pppppppp pulse width
|
// 04 -------- -------- pppppppp pppppppp pulse width
|
// 08 -------- -------- trsg--fo -vvvvv-- test, ringmod, sync, gate, filter, output, voice type
|
// 08 -------- -------- trsg-efo vvvvvv-- test, ringmod, sync, gate, filter, output, voice type
|
// 0C aaaaaaaa aaaaaaaa dddddddd dddddddd attack, decay
|
// 0C -------- aaaaaaaa aaaaaaaa aaaaaaaa attack
|
// 10 -------- ssssssss rrrrrrrr rrrrrrrr sustain, release
|
// 10 -------- dddddddd dddddddd dddddddd decay
|
// 14 -------- -------- --aaaaaa aaaaaaa- wave table base address
|
// 14 -------- -------- -------- ssssssss sustain
|
|
// 18 -------- rrrrrrrr rrrrrrrr rrrrrrrr release
|
|
// 1C -------- -------- --aaaaaa aaaaaaa- wave table base address
|
// vvvvv
|
// vvvvv
|
// wnpst
|
// wnpst
|
// 18-2C Voice #2
|
// 20-3C Voice #2
|
// 30-44 Voice #3
|
// 40-5C Voice #3
|
// 48-5C Voice #4
|
// 60-7C Voice #4
|
//
|
//
|
// ...
|
// ...
|
// B0 -------- -------- -------- vvvvvvvv volume (0-255)
|
// B0 -------- -------- -------- ----vvvv volume (0-255)
|
// B4 nnnnnnnn nnnnnnnn nnnnnnnn nnnnnnnn osc3 oscillator 3
|
// B4 nnnnnnnn nnnnnnnn nnnnnnnn nnnnnnnn osc3 oscillator 3
|
// B8 -------- -------- -------- nnnnnnnn env3 envelope 3
|
// B8 -------- -------- -------- nnnnnnnn env3 envelope 3
|
|
// BC -------- -------- -sss-sss -sss-sss env state
|
//
|
//
|
// C0-DC -------- -------- s---kkkk kkkkkkkk filter coefficients
|
// C0-DC -------- -------- s---kkkk kkkkkkkk filter coefficients
|
// E0-FC -------- -------- -------- -------- reserved for more filter coefficients
|
// E0-FC -------- -------- -------- -------- reserved for more filter coefficients
|
//
|
//
|
//=============================================================================
|
//=============================================================================
|
|
|
module PSG32(rst_i, clk_i, cs_i, cyc_i, stb_i, ack_o, we_i, adr_i, dat_i, dat_o,
|
module PSG32(rst_i, clk_i, cs_i, cyc_i, stb_i, ack_o, we_i, adr_i, dat_i, dat_o,
|
m_adr_o, m_dat_i, o
|
m_adr_o, m_dat_i, o
|
);
|
);
|
parameter pClkDivide = 37;
|
parameter pClkDivide = 37;
|
|
|
// WISHBONE SYSCON
|
// WISHBONE SYSCON
|
input rst_i;
|
input rst_i;
|
input clk_i; // system clock
|
input clk_i; // system clock
|
// NON-WISHBONE
|
// NON-WISHBONE
|
input cs_i; // circuit select
|
input cs_i; // circuit select
|
// WISHBONE SLAVE
|
// WISHBONE SLAVE
|
input cyc_i; // cycle valid
|
input cyc_i; // cycle valid
|
input stb_i; // circuit select
|
input stb_i; // circuit select
|
output ack_o;
|
output ack_o;
|
input we_i; // write
|
input we_i; // write
|
input [7:0] adr_i; // address input
|
input [7:0] adr_i; // address input
|
input [31:0] dat_i; // data input
|
input [31:0] dat_i; // data input
|
output [31:0] dat_o; // data output
|
output [31:0] dat_o; // data output
|
|
|
// WISHBONE MASTER
|
// WISHBONE MASTER
|
output [13:0] m_adr_o; // wave table address
|
output [13:0] m_adr_o; // wave table address
|
input [11:0] m_dat_i; // wave table data input
|
input [11:0] m_dat_i; // wave table data input
|
|
|
output [17:0] o;
|
output [17:0] o;
|
|
|
// I/O registers
|
// I/O registers
|
reg [31:0] dat_o;
|
reg [31:0] dat_o;
|
reg [13:0] m_adr_o;
|
reg [13:0] m_adr_o;
|
|
|
reg [3:0] test; // test (enable note generator)
|
reg [3:0] test; // test (enable note generator)
|
reg [4:0] vt [3:0]; // voice type
|
reg [5:0] vt [3:0]; // voice type
|
reg [23:0] freq0, freq1, freq2, freq3; // frequency control
|
reg [23:0] freq0, freq1, freq2, freq3; // frequency control
|
reg [15:0] pw0, pw1, pw2, pw3; // pulse width control
|
reg [15:0] pw0, pw1, pw2, pw3; // pulse width control
|
reg [3:0] gate;
|
reg [3:0] gate;
|
reg [15:0] attack0, attack1, attack2, attack3;
|
reg [23:0] attack0, attack1, attack2, attack3;
|
reg [15:0] decay0, decay1, decay2, decay3;
|
reg [23:0] decay0, decay1, decay2, decay3;
|
reg [7:0] sustain0, sustain1, sustain2, sustain3;
|
reg [7:0] sustain0, sustain1, sustain2, sustain3;
|
reg [15:0] relese0, relese1, relese2, relese3;
|
reg [23:0] relese0, relese1, relese2, relese3;
|
reg [13:0] wtadr0, wtadr1, wtadr2, wtadr3;
|
reg [13:0] wtadr0, wtadr1, wtadr2, wtadr3;
|
reg [3:0] sync;
|
reg [3:0] sync;
|
reg [3:0] ringmod;
|
reg [3:0] ringmod;
|
reg [3:0] outctrl;
|
reg [3:0] outctrl;
|
reg [3:0] filt; // 1 = output goes to filter
|
reg [3:0] filt; // 1 = output goes to filter
|
|
reg [3:0] eg; // 1 = output goes through envelope generator
|
wire [31:0] acc0, acc1, acc2, acc3;
|
wire [31:0] acc0, acc1, acc2, acc3;
|
reg [7:0] volume; // master volume
|
reg [3:0] volume; // master volume
|
wire [11:0] tg1_o,tg2_o,tg3_o,tg4_o; // tone generator output
|
wire [11:0] tg1_o,tg2_o,tg3_o,tg4_o; // tone generator output
|
wire [7:0] env; // envelope generator output
|
wire [7:0] env; // envelope generator output
|
wire [7:0] env3;
|
wire [7:0] env0, env1, env2, env3;
|
wire [19:0] out0,out1,out2,out3;
|
wire [19:0] out0,out1,out2,out3;
|
wire [2:0] es0,es1,es2,es3;
|
wire [2:0] es0,es1,es2,es3;
|
wire [29:0] out4;
|
wire [29:0] out4;
|
reg [21:0] sum,fsum;
|
reg [21:0] sum,fsum;
|
reg [21:0] sum2;
|
reg [21:0] sum2;
|
wire [21:0] filtin1; // FIR filter input
|
wire [21:0] filtin1; // FIR filter input
|
wire [37:0] filt_o; // FIR filter output
|
wire [37:0] filt_o; // FIR filter output
|
reg [1:0] cnt;
|
reg [1:0] cnt;
|
reg [1:0] cnt1,cnt2,cnt3;
|
reg [1:0] cnt1,cnt2,cnt3;
|
|
|
// channel select signal
|
// channel select signal
|
wire [1:0] sel = cnt[1:0];
|
wire [1:0] sel = cnt[1:0];
|
|
|
and(cs, cyc_i, stb_i, cs_i);
|
and(cs, cyc_i, stb_i, cs_i);
|
reg ack1,ack2;
|
reg ack1,ack2;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
ack1 <= cs;
|
ack1 <= cs;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
ack2 <= ack1 & cs;
|
ack2 <= ack1 & cs;
|
assign ack_o = cs ? (we_i ? 1'b1 : ack2) : 1'b0;
|
assign ack_o = cs ? (we_i ? 1'b1 : ack2) : 1'b0;
|
|
|
// Register shadow ram for register readback
|
// Register shadow ram for register readback
|
reg [15:0] reg_shadow [63:0];
|
reg [15:0] reg_shadow [63:0];
|
reg [8:0] radr;
|
reg [8:0] radr;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
if (cs & we_i) reg_shadow[adr_i[7:2]] <= dat_i[15:0];
|
if (cs & we_i) reg_shadow[adr_i[7:2]] <= dat_i[15:0];
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
radr <= adr_i[7:2];
|
radr <= adr_i[7:2];
|
wire [15:0] reg_shadow_o = reg_shadow[radr];
|
wire [15:0] reg_shadow_o = reg_shadow[radr];
|
|
|
// write to registers
|
// write to registers
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
begin
|
begin
|
if (rst_i) begin
|
if (rst_i) begin
|
freq0 <= 0;
|
freq0 <= 0;
|
freq1 <= 0;
|
freq1 <= 0;
|
freq2 <= 0;
|
freq2 <= 0;
|
freq3 <= 0;
|
freq3 <= 0;
|
pw0 <= 0;
|
pw0 <= 0;
|
pw1 <= 0;
|
pw1 <= 0;
|
pw2 <= 0;
|
pw2 <= 0;
|
pw3 <= 0;
|
pw3 <= 0;
|
test <= 0;
|
test <= 0;
|
vt[0] <= 0;
|
vt[0] <= 0;
|
vt[1] <= 0;
|
vt[1] <= 0;
|
vt[2] <= 0;
|
vt[2] <= 0;
|
vt[3] <= 0;
|
vt[3] <= 0;
|
gate <= 0;
|
gate <= 0;
|
outctrl <= 0;
|
outctrl <= 0;
|
filt <= 0;
|
filt <= 0;
|
attack0 <= 0;
|
attack0 <= 0;
|
attack1 <= 0;
|
attack1 <= 0;
|
attack2 <= 0;
|
attack2 <= 0;
|
attack3 <= 0;
|
attack3 <= 0;
|
decay0 <= 0;
|
decay0 <= 0;
|
sustain0 <= 0;
|
sustain0 <= 0;
|
relese0 <= 0;
|
relese0 <= 0;
|
decay1 <= 0;
|
decay1 <= 0;
|
sustain1 <= 0;
|
sustain1 <= 0;
|
relese1 <= 0;
|
relese1 <= 0;
|
decay2 <= 0;
|
decay2 <= 0;
|
sustain2 <= 0;
|
sustain2 <= 0;
|
relese2 <= 0;
|
relese2 <= 0;
|
decay3 <= 0;
|
decay3 <= 0;
|
sustain3 <= 0;
|
sustain3 <= 0;
|
relese3 <= 0;
|
relese3 <= 0;
|
sync <= 0;
|
sync <= 0;
|
ringmod <= 0;
|
ringmod <= 0;
|
volume <= 0;
|
volume <= 0;
|
end
|
end
|
else begin
|
else begin
|
if (cs & we_i) begin
|
if (cs & we_i) begin
|
case(adr_i[7:2])
|
case(adr_i[7:2])
|
//---------------------------------------------------------
|
//---------------------------------------------------------
|
6'd00: freq0 <= dat_i[23:0];
|
6'd00: freq0 <= dat_i[23:0];
|
6'd01: pw0 <= dat_i[15:0];
|
6'd01: pw0 <= dat_i[15:0];
|
6'd02: begin
|
6'd02: begin
|
vt[0] <= dat_i[6:2];
|
vt[0] <= dat_i[7:2];
|
outctrl[0] <= dat_i[8];
|
outctrl[0] <= dat_i[8];
|
filt[0] <= dat_i[9];
|
filt[0] <= dat_i[9];
|
|
eg[0] <= dat_i[10];
|
gate[0] <= dat_i[12];
|
gate[0] <= dat_i[12];
|
sync[0] <= dat_i[13];
|
sync[0] <= dat_i[13];
|
ringmod[0] <= dat_i[14];
|
ringmod[0] <= dat_i[14];
|
test[0] <= dat_i[15];
|
test[0] <= dat_i[15];
|
end
|
end
|
6'd03: begin
|
6'd03: attack0 <= dat_i[23:0];
|
attack0 <= dat_i[31:16];
|
6'd04: decay0 <= dat_i[23:0];
|
decay0 <= dat_i[15:0];
|
6'd05: sustain0 <= dat_i[7:0];
|
end
|
6'd06: relese0 <= dat_i[23:0];
|
6'd04: begin
|
6'd07: wtadr0 <= {dat_i[13:1],1'b0};
|
relese0 <= dat_i[15:0];
|
|
sustain0 <= dat_i[23:16];
|
|
end
|
|
6'd05: wtadr0 <= {dat_i[13:1],1'b0};
|
|
|
|
//---------------------------------------------------------
|
//---------------------------------------------------------
|
6'd06: freq1 <= dat_i[23:0];
|
6'd08: freq1 <= dat_i[23:0];
|
6'd07: pw1 <= dat_i[15:0];
|
6'd09: pw1 <= dat_i[15:0];
|
6'd08: begin
|
6'd10: begin
|
vt[1] <= dat_i[6:2];
|
vt[1] <= dat_i[7:2];
|
outctrl[1] <= dat_i[8];
|
outctrl[1] <= dat_i[8];
|
filt[1] <= dat_i[9];
|
filt[1] <= dat_i[9];
|
|
eg[1] <= dat_i[10];
|
gate[1] <= dat_i[12];
|
gate[1] <= dat_i[12];
|
sync[1] <= dat_i[13];
|
sync[1] <= dat_i[13];
|
ringmod[1] <= dat_i[14];
|
ringmod[1] <= dat_i[14];
|
test[1] <= dat_i[15];
|
test[1] <= dat_i[15];
|
end
|
end
|
6'd09: begin
|
6'd11: attack1 <= dat_i[23:0];
|
attack1 <= dat_i[31:16];
|
6'd12: decay1 <= dat_i[23:0];
|
decay1 <= dat_i[15:0];
|
6'd13: sustain1 <= dat_i[7:0];
|
end
|
6'd14: relese1 <= dat_i[23:0];
|
6'd10:
|
6'd15: wtadr1 <= {dat_i[13:1],1'b0};
|
begin
|
|
relese1 <= dat_i[15:0];
|
|
sustain1 <= dat_i[23:16];
|
|
end
|
|
6'd11: wtadr1 <= {dat_i[13:1],1'b0};
|
|
|
|
//---------------------------------------------------------
|
//---------------------------------------------------------
|
6'd12: freq2 <= dat_i[23:0];
|
6'd16: freq2 <= dat_i[23:0];
|
6'd13: pw2 <= dat_i[15:0];
|
6'd17: pw2 <= dat_i[15:0];
|
6'd14: begin
|
6'd18: begin
|
vt[2] <= dat_i[6:2];
|
vt[2] <= dat_i[7:2];
|
outctrl[2] <= dat_i[8];
|
outctrl[2] <= dat_i[8];
|
filt[2] <= dat_i[9];
|
filt[2] <= dat_i[9];
|
|
eg[2] <= dat_i[10];
|
gate[2] <= dat_i[12];
|
gate[2] <= dat_i[12];
|
sync[2] <= dat_i[5];
|
sync[2] <= dat_i[5];
|
outctrl[0] <= dat_i[13];
|
outctrl[0] <= dat_i[13];
|
ringmod[2] <= dat_i[14];
|
ringmod[2] <= dat_i[14];
|
test[2] <= dat_i[15];
|
test[2] <= dat_i[15];
|
end
|
end
|
6'd15: begin
|
6'd19: attack2 <= dat_i[23:0];
|
attack2 <= dat_i[31:16];
|
6'd20: decay2 <= dat_i[23:0];
|
decay2 <= dat_i[15:0];
|
6'd21: sustain2 <= dat_i[7:0];
|
end
|
6'd22: relese2 <= dat_i[23:0];
|
6'd16: begin
|
6'd23: wtadr2 <= {dat_i[13:1],1'b0};
|
relese2 <= dat_i[15:0];
|
|
sustain2 <= dat_i[23:16];
|
|
end
|
|
6'd17: wtadr1 <= {dat_i[13:1],1'b0};
|
|
|
|
//---------------------------------------------------------
|
//---------------------------------------------------------
|
6'd18: freq3 <= dat_i[23:0];
|
6'd24: freq3 <= dat_i[23:0];
|
6'd19: pw3 <= dat_i[15:0];
|
6'd25: pw3 <= dat_i[15:0];
|
6'd20: begin
|
6'd26: begin
|
vt[3] <= dat_i[6:2];
|
vt[3] <= dat_i[7:2];
|
outctrl[3] <= dat_i[8];
|
outctrl[3] <= dat_i[8];
|
filt[3] <= dat_i[9];
|
filt[3] <= dat_i[9];
|
|
eg[3] <= dat_i[10];
|
gate[3] <= dat_i[12];
|
gate[3] <= dat_i[12];
|
sync[3] <= dat_i[13];
|
sync[3] <= dat_i[13];
|
ringmod[3] <= dat_i[14];
|
ringmod[3] <= dat_i[14];
|
test[3] <= dat_i[15];
|
test[3] <= dat_i[15];
|
end
|
end
|
6'd21: begin
|
6'd27: attack3 <= dat_i[23:0];
|
attack3 <= dat_i[31:16];
|
6'd28: decay3 <= dat_i[23:0];
|
decay3 <= dat_i[15:0];
|
6'd29: sustain3 <= dat_i[7:0];
|
relese3 <= dat_i[15:0];
|
6'd30: relese3 <= dat_i[23:0];
|
sustain3 <= dat_i[23:16];
|
6'd31: wtadr3 <= {dat_i[13:1],1'b0};
|
end
|
|
6'd22: wtadr1 <= {dat_i[13:1],1'b0};
|
|
|
|
//---------------------------------------------------------
|
//---------------------------------------------------------
|
6'd44: volume <= dat_i[7:0];
|
6'd44: volume <= dat_i[3:0];
|
|
|
default: ;
|
default: ;
|
endcase
|
endcase
|
end
|
end
|
end
|
end
|
end
|
end
|
|
|
|
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
case(adr_i[7:2])
|
case(adr_i[7:2])
|
6'd45: begin
|
6'd45: begin
|
dat_o <= acc3;
|
dat_o <= acc3;
|
end
|
end
|
6'd45: begin
|
6'd46: begin
|
dat_o <= {24'h0,env3};
|
dat_o <= {24'h0,env3};
|
end
|
end
|
6'd46: dat_o <= {17'h0,es3,1'b0,es2,1'b0,es1,1'b0,es0};
|
6'd47: dat_o <= {17'h0,es3,1'b0,es2,1'b0,es1,1'b0,es0};
|
default: begin
|
default: begin
|
dat_o <= reg_shadow_o;
|
dat_o <= reg_shadow_o;
|
end
|
end
|
endcase
|
endcase
|
|
|
wire [13:0] madr;
|
wire [13:0] madr;
|
mux4to1 #(12) u11
|
mux4to1 #(12) u11
|
(
|
(
|
.e(1'b1),
|
.e(1'b1),
|
.s(cnt),
|
.s(cnt),
|
.i0(wtadr0 + {acc0[27:17],1'b0}),
|
.i0(wtadr0 + {acc0[27:17],1'b0}),
|
.i1(wtadr1 + {acc1[27:17],1'b0}),
|
.i1(wtadr1 + {acc1[27:17],1'b0}),
|
.i2(wtadr2 + {acc2[27:17],1'b0}),
|
.i2(wtadr2 + {acc2[27:17],1'b0}),
|
.i3(wtadr3 + {acc3[27:17],1'b0}),
|
.i3(wtadr3 + {acc3[27:17],1'b0}),
|
.z(madr)
|
.z(madr)
|
);
|
);
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
m_adr_o <= madr;
|
m_adr_o <= madr;
|
|
wire [11:0] wave_i = m_dat_i;
|
|
|
// This counter controls channel multiplexing for the wave table
|
// This counter controls channel multiplexing for the wave table
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
if (rst_i)
|
if (rst_i)
|
cnt <= 2'd0;
|
cnt <= 2'd0;
|
else
|
else
|
cnt <= cnt + 2'd1;
|
cnt <= cnt + 2'd1;
|
|
|
// note generator - multi-channel
|
// note generator - multi-channel
|
PSGToneGenerator u1a
|
PSGToneGenerator u1a
|
(
|
(
|
.rst(rst_i),
|
.rst(rst_i),
|
.clk(clk_i),
|
.clk(clk_i),
|
.ack(cnt==2'b11),
|
.ack(cnt==2'b11),
|
.test(test[0]),
|
.test(test[0]),
|
.vt(vt[0]),
|
.vt(vt[0]),
|
.freq(freq0),
|
.freq(freq0),
|
.pw(pw0),
|
.pw(pw0),
|
.acc(acc0),
|
.acc(acc0),
|
.prev_acc(acc3),
|
.prev_acc(acc3),
|
.wave(wave_i),
|
.wave(wave_i),
|
.sync(sync[0]),
|
.sync(sync[0]),
|
.ringmod(ringmod[0]),
|
.ringmod(ringmod[0]),
|
.o(tg1_o)
|
.o(tg1_o)
|
);
|
);
|
|
|
PSGToneGenerator u1b
|
PSGToneGenerator u1b
|
(
|
(
|
.rst(rst_i),
|
.rst(rst_i),
|
.clk(clk_i),
|
.clk(clk_i),
|
.ack(cnt==2'b00),
|
.ack(cnt==2'b00),
|
.test(test[1]),
|
.test(test[1]),
|
.vt(vt[1]),
|
.vt(vt[1]),
|
.freq(freq1),
|
.freq(freq1),
|
.pw(pw1),
|
.pw(pw1),
|
.acc(acc1),
|
.acc(acc1),
|
.prev_acc(acc0),
|
.prev_acc(acc0),
|
.wave(wave_i),
|
.wave(wave_i),
|
.sync(sync[1]),
|
.sync(sync[1]),
|
.ringmod(ringmod[1]),
|
.ringmod(ringmod[1]),
|
.o(tg2_o)
|
.o(tg2_o)
|
);
|
);
|
|
|
PSGToneGenerator u1c
|
PSGToneGenerator u1c
|
(
|
(
|
.rst(rst_i),
|
.rst(rst_i),
|
.clk(clk_i),
|
.clk(clk_i),
|
.ack(cnt==2'b01),
|
.ack(cnt==2'b01),
|
.test(test[2]),
|
.test(test[2]),
|
.vt(vt[2]),
|
.vt(vt[2]),
|
.freq(freq2),
|
.freq(freq2),
|
.pw(pw2),
|
.pw(pw2),
|
.acc(acc2),
|
.acc(acc2),
|
.prev_acc(acc1),
|
.prev_acc(acc1),
|
.wave(wave_i),
|
.wave(wave_i),
|
.sync(sync[2]),
|
.sync(sync[2]),
|
.ringmod(ringmod[2]),
|
.ringmod(ringmod[2]),
|
.o(tg3_o)
|
.o(tg3_o)
|
);
|
);
|
|
|
PSGToneGenerator u1d
|
PSGToneGenerator u1d
|
(
|
(
|
.rst(rst_i),
|
.rst(rst_i),
|
.clk(clk_i),
|
.clk(clk_i),
|
.ack(cnt==2'b10),
|
.ack(cnt==2'b10),
|
.test(test[3]),
|
.test(test[3]),
|
.vt(vt[3]),
|
.vt(vt[3]),
|
.freq(freq3),
|
.freq(freq3),
|
.pw(pw3),
|
.pw(pw3),
|
.acc(acc3),
|
.acc(acc3),
|
.prev_acc(acc2),
|
.prev_acc(acc2),
|
.wave(wave_i),
|
.wave(wave_i),
|
.sync(sync[3]),
|
.sync(sync[3]),
|
.ringmod(ringmod[3]),
|
.ringmod(ringmod[3]),
|
.o(tg4_o)
|
.o(tg4_o)
|
);
|
);
|
|
|
PSGEnvelopeGenerator u2a
|
PSGEnvelopeGenerator u2a
|
(
|
(
|
.rst(rst_i),
|
.rst(rst_i),
|
.clk(clk_i),
|
.clk(clk_i),
|
.gate(gate[0]),
|
.gate(gate[0]),
|
.attack(attack0),
|
.attack(attack0),
|
.decay(decay0),
|
.decay(decay0),
|
.sustain(sustain0),
|
.sustain(sustain0),
|
.relese(relese0),
|
.relese(relese0),
|
.o(env0),
|
.o(env0),
|
.envState(es0)
|
.envState(es0)
|
);
|
);
|
|
|
PSGEnvelopeGenerator u2b
|
PSGEnvelopeGenerator u2b
|
(
|
(
|
.rst(rst_i),
|
.rst(rst_i),
|
.clk(clk_i),
|
.clk(clk_i),
|
.gate(gate[1]),
|
.gate(gate[1]),
|
.attack(attack1),
|
.attack(attack1),
|
.decay(decay1),
|
.decay(decay1),
|
.sustain(sustain1),
|
.sustain(sustain1),
|
.relese(relese1),
|
.relese(relese1),
|
.o(env1),
|
.o(env1),
|
.envState(es1)
|
.envState(es1)
|
);
|
);
|
|
|
PSGEnvelopeGenerator u2c
|
PSGEnvelopeGenerator u2c
|
(
|
(
|
.rst(rst_i),
|
.rst(rst_i),
|
.clk(clk_i),
|
.clk(clk_i),
|
.gate(gate[2]),
|
.gate(gate[2]),
|
.attack(attack2),
|
.attack(attack2),
|
.decay(decay2),
|
.decay(decay2),
|
.sustain(sustain2),
|
.sustain(sustain2),
|
.relese(relese2),
|
.relese(relese2),
|
.o(env2),
|
.o(env2),
|
.envState(es2)
|
.envState(es2)
|
);
|
);
|
|
|
PSGEnvelopeGenerator u2d
|
PSGEnvelopeGenerator u2d
|
(
|
(
|
.rst(rst_i),
|
.rst(rst_i),
|
.clk(clk_i),
|
.clk(clk_i),
|
.gate(gate[3]),
|
.gate(gate[3]),
|
.attack(attack3),
|
.attack(attack3),
|
.decay(decay3),
|
.decay(decay3),
|
.sustain(sustain3),
|
.sustain(sustain3),
|
.relese(relese3),
|
.relese(relese3),
|
.o(env3),
|
.o(env3),
|
.envState(es3)
|
.envState(es3)
|
);
|
);
|
|
|
// shape output according to envelope
|
// shape output according to envelope
|
PSGShaper u5a
|
PSGShaper u5a
|
(
|
(
|
.clk_i(clk_i),
|
.clk_i(clk_i),
|
.ce(1'b1),
|
.ce(1'b1),
|
.tgi(tg1_o),
|
.tgi(tg1_o),
|
.env(env0),
|
.env(eg[0] ? env0 : 8'hFF),
|
.o(out0)
|
.o(out0)
|
);
|
);
|
|
|
PSGShaper u5b
|
PSGShaper u5b
|
(
|
(
|
.clk_i(clk_i),
|
.clk_i(clk_i),
|
.ce(1'b1),
|
.ce(1'b1),
|
.tgi(tg2_o),
|
.tgi(tg2_o),
|
.env(env1),
|
.env(eg[1] ? env1 : 8'hFF),
|
.o(out1)
|
.o(out1)
|
);
|
);
|
|
|
PSGShaper u5c
|
PSGShaper u5c
|
(
|
(
|
.clk_i(clk_i),
|
.clk_i(clk_i),
|
.ce(1'b1),
|
.ce(1'b1),
|
.tgi(tg3_o),
|
.tgi(tg3_o),
|
.env(env2),
|
.env(eg[2] ? env2 : 8'hFF),
|
.o(out2)
|
.o(out2)
|
);
|
);
|
|
|
PSGShaper u5d
|
PSGShaper u5d
|
(
|
(
|
.clk_i(clk_i),
|
.clk_i(clk_i),
|
.ce(1'b1),
|
.ce(1'b1),
|
.tgi(tg4_o),
|
.tgi(tg4_o),
|
.env(env3),
|
.env(eg[3] ? env3 : 8'hFF),
|
.o(out3)
|
.o(out3)
|
);
|
);
|
|
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
cnt1 <= cnt;
|
cnt1 <= cnt;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
cnt2 <= cnt1;
|
cnt2 <= cnt1;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
cnt3 <= cnt2;
|
cnt3 <= cnt2;
|
|
|
// Sum the channels not going to the filter
|
// Sum the channels not going to the filter
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
sum <=
|
sum <=
|
{2'd0,(out0 & {20{outctrl[0]}})} +
|
{2'd0,(out0 & {20{outctrl[0]}})} +
|
{2'd0,(out1 & {20{outctrl[1]}})} +
|
{2'd0,(out1 & {20{outctrl[1]}})} +
|
{2'd0,(out2 & {20{outctrl[2]}})} +
|
{2'd0,(out2 & {20{outctrl[2]}})} +
|
{2'd0,(out3 & {20{outctrl[3]}})};
|
{2'd0,(out3 & {20{outctrl[3]}})};
|
|
|
// Sum the channels going to the filter
|
// Sum the channels going to the filter
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
fsum <=
|
fsum <=
|
{2'd0,(out0 & {20{filt[0]}})} +
|
{2'd0,(out0 & {20{filt[0]}})} +
|
{2'd0,(out1 & {20{filt[1]}})} +
|
{2'd0,(out1 & {20{filt[1]}})} +
|
{2'd0,(out2 & {20{filt[2]}})} +
|
{2'd0,(out2 & {20{filt[2]}})} +
|
{2'd0,(out3 & {20{filt[3]}})};
|
{2'd0,(out3 & {20{filt[3]}})};
|
|
|
// The FIR filter
|
// The FIR filter
|
PSGFilter2 u8
|
PSGFilter2 u8
|
(
|
(
|
.rst(rst_i),
|
.rst(rst_i),
|
.clk(clk_i),
|
.clk(clk_i),
|
.cnt(cnt2),
|
.cnt(cnt2),
|
.wr(we_i && stb_i && adr_i[7:6]==3'b11),
|
.wr(we_i && stb_i && adr_i[7:6]==3'b11),
|
.adr(adr_i[5:2]),
|
.adr(adr_i[5:2]),
|
.din({dat_i[15],dat_i[11:0]}),
|
.din({dat_i[15],dat_i[11:0]}),
|
.i(fsum),
|
.i(fsum),
|
.o(filt_o)
|
.o(filt_o)
|
);
|
);
|
|
|
// Sum the filtered and unfiltered output
|
// Sum the filtered and unfiltered output
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
sum2 <= sum + filt_o[37:16];
|
sum2 <= sum + filt_o[37:16];
|
|
|
// Last stage:
|
// Last stage:
|
// Adjust output according to master volume
|
// Adjust output according to master volume
|
PSGVolumeControl u10
|
PSGVolumeControl u10
|
(
|
(
|
.rst_i(rst_i),
|
.rst_i(rst_i),
|
.clk_i(clk_i),
|
.clk_i(clk_i),
|
.i(sum2),
|
.i(sum2),
|
.volume(volume),
|
.volume(volume),
|
.o(out4)
|
.o(out4)
|
);
|
);
|
|
|
assign o = out4[29:12];
|
assign o = out4[29:12];
|
|
|
endmodule
|
endmodule
|
|
|