1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-03-09 20:18:22 +00:00

new Soundcores on Common

This commit is contained in:
Marcel
2021-06-15 22:36:02 +02:00
parent 82b77722bb
commit 4f9cd9212b
25 changed files with 1515 additions and 12 deletions

View File

@@ -225,7 +225,6 @@ set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
set_global_assignment -name SYNTH_TIMING_DRIVEN_SYNTHESIS ON
set_global_assignment -name TIMEQUEST_MULTICORNER_ANALYSIS ON
set_global_assignment -name SMART_RECOMPILE ON
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
set_global_assignment -name SYSTEMVERILOG_FILE rtl/TimePilot84_MiST.sv
set_global_assignment -name SYSTEMVERILOG_FILE rtl/TimePilot84.sv
set_global_assignment -name SYSTEMVERILOG_FILE rtl/TimePilot84_CPU.sv
@@ -244,4 +243,5 @@ set_global_assignment -name SIGNALTAP_FILE output_files/char.stp
set_global_assignment -name SIGNALTAP_FILE output_files/cpu.stp
set_global_assignment -name SIGNALTAP_FILE output_files/sdram.stp
set_global_assignment -name SIGNALTAP_FILE output_files/spr.stp
set_global_assignment -name SIGNALTAP_FILE output_files/snd.stp
set_global_assignment -name SIGNALTAP_FILE output_files/snd.stp
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

View File

@@ -197,7 +197,7 @@ dac #(
dac_l(
.clk_i(clk_sys),
.res_n_i(1),
.dac_i(audio_ch2),
.dac_i(audio_ch1),
.dac_o(AUDIO_L)
);
@@ -206,12 +206,11 @@ dac #(
dac_r(
.clk_i(clk_sys),
.res_n_i(1),
.dac_i(audio_ch1),
.dac_i(audio_ch2),
.dac_o(AUDIO_R)
);
wire m_up, m_down, m_left, m_right, m_fireA, m_fireB, m_fireC, m_fireD, m_fireE, m_fireF;
wire m_up2, m_down2, m_left2, m_right2, m_fire2A, m_fire2B, m_fire2C, m_fire2D, m_fire2E, m_fire2F;
wire m_tilt, m_coin1, m_coin2, m_coin3, m_coin4, m_one_player, m_two_players, m_three_players, m_four_players;
arcade_inputs inputs (
@@ -220,13 +219,10 @@ arcade_inputs inputs (
.key_pressed ( key_pressed ),
.key_code ( key_code ),
.joystick_0 ( joystick_0 ),
//.rotate ( rotate ),
//.orientation ( orientation ),
.joyswap ( status[6] ),
.oneplayer ( 1'b1 ),
.controls ( {m_tilt, m_coin4, m_coin3, m_coin2, m_coin1, m_four_players, m_three_players, m_two_players, m_one_player} ),
.player1 ( {m_fireF, m_fireE, m_fireD, m_fireC, m_fireB, m_fireA, m_up, m_down, m_left, m_right} ),
.player2 ( {m_fire2F, m_fire2E, m_fire2D, m_fire2C, m_fire2B, m_fire2A, m_up2, m_down2, m_left2, m_right2} )
.player1 ( {m_fireF, m_fireE, m_fireD, m_fireC, m_fireB, m_fireA, m_up, m_down, m_left, m_right} )
);
endmodule

View File

@@ -92,7 +92,7 @@ always @(posedge clk_cpu)
else
timer_div <= 14'hff;
irq_timer
// irq_timer
always @(posedge clk_cpu)
if (sys_cs && cpu_we && AB[2:0] == 3'h3)
irq_timer <= cpu_dout;
@@ -239,7 +239,7 @@ always @(posedge clk_sys)
//);
assign cpu_rom_addr = rom_addr;
assign rom_dout = rom_cs ? cpu_rom_data : 8'hff;
assign rom_dout = cpu_rom_data;
ram88 wram(
@@ -330,5 +330,4 @@ cpu_65c02 cpu(
.RDY(cpu_rdy)
);
endmodule

View File

@@ -0,0 +1,8 @@
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_bus.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_cen.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_div.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_eg.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_exp.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt49_noise.v]

224
common/Sound/JT49/jt49.v Normal file
View File

@@ -0,0 +1,224 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
module jt49 ( // note that input ports are not multiplexed
input rst_n,
input clk, // signal on positive edge
input clk_en,
input [3:0] addr,
input cs_n,
input wr_n, // write
input [7:0] din,
input sel, // if sel is low, the clock is divided by 2
output reg [7:0] dout,
output reg [7:0] A, // linearised channel output
output reg [7:0] B,
output reg [7:0] C
);
parameter [1:0] COMP=2'b00;
parameter CLKDIV=3;
wire [1:0] comp = COMP;
reg [7:0] regarray[15:0];
wire [4:0] envelope;
wire bitA, bitB, bitC;
wire noise;
reg Amix, Bmix, Cmix;
wire cen16, cen256;
jt49_cen #(.CLKDIV(CLKDIV)) u_cen(
.clk ( clk ),
.rst_n ( rst_n ),
.cen ( clk_en ),
.sel ( sel ),
.cen16 ( cen16 ),
.cen256 ( cen256 )
);
// internal modules operate at clk/16
jt49_div #(12) u_chA(
.clk ( clk ),
.rst_n ( rst_n ),
.cen ( cen16 ),
.period ( {regarray[1][3:0], regarray[0][7:0] } ),
.div ( bitA )
);
jt49_div #(12) u_chB(
.clk ( clk ),
.rst_n ( rst_n ),
.cen ( cen16 ),
.period ( {regarray[3][3:0], regarray[2][7:0] } ),
.div ( bitB )
);
jt49_div #(12) u_chC(
.clk ( clk ),
.rst_n ( rst_n ),
.cen ( cen16 ),
.period ( {regarray[5][3:0], regarray[4][7:0] } ),
.div ( bitC )
);
jt49_noise u_ng(
.clk ( clk ),
.cen ( cen16 ),
.rst_n ( rst_n ),
.period ( regarray[6][4:0] ),
.noise ( noise )
);
// envelope generator
wire eg_step;
wire [15:0] eg_period = {regarray[4'hc],regarray[4'hb]};
wire null_period = eg_period == 16'h0;
jt49_div #(16) u_envdiv(
.clk ( clk ),
.cen ( cen256 ),
.rst_n ( rst_n ),
.period ( eg_period ),
.div ( eg_step )
);
reg eg_restart;
jt49_eg u_env(
.clk ( clk ),
.cen ( cen256 ),
.step ( eg_step ),
.rst_n ( rst_n ),
.restart ( eg_restart ),
.null_period( null_period ),
.ctrl ( regarray[4'hD][3:0] ),
.env ( envelope )
);
reg [4:0] logA, logB, logC, log;
wire [7:0] lin;
jt49_exp u_exp(
.clk ( clk ),
.comp ( comp ),
.din ( log ),
.dout ( lin )
);
wire [4:0] volA = { regarray[ 8][3:0], regarray[ 8][3] };
wire [4:0] volB = { regarray[ 9][3:0], regarray[ 9][3] };
wire [4:0] volC = { regarray[10][3:0], regarray[10][3] };
wire use_envA = regarray[ 8][4];
wire use_envB = regarray[ 9][4];
wire use_envC = regarray[10][4];
wire use_noA = regarray[ 7][3];
wire use_noB = regarray[ 7][4];
wire use_noC = regarray[ 7][5];
reg [3:0] acc_st;
always @(posedge clk) if( clk_en ) begin
Amix <= (noise|use_noA) & (bitA|regarray[7][0]);
Bmix <= (noise|use_noB) & (bitB|regarray[7][1]);
Cmix <= (noise|use_noC) & (bitC|regarray[7][2]);
logA <= !Amix ? 5'd0 : (use_envA ? envelope : volA );
logB <= !Bmix ? 5'd0 : (use_envB ? envelope : volB );
logC <= !Cmix ? 5'd0 : (use_envC ? envelope : volC );
end
always @(posedge clk, negedge rst_n) begin
if( !rst_n ) begin
acc_st <= 4'b1;
A <= 8'd0;
B <= 8'd0;
C <= 8'd0;
end else if(clk_en) begin
acc_st <= { acc_st[2:0], acc_st[3] };
case( acc_st )
4'b0001: begin
log <= logA;
end
4'b0010: begin
A <= lin;
log <= logB;
end
4'b0100: begin
B <= lin;
log <= logC;
end
4'b1000: begin // last sum
C <= lin;
end
default:;
endcase
end
end
reg [7:0] read_mask;
always @(*)
case(addr)
4'h0,4'h2,4'h4,4'h7,4'hb,4'hc,4'he,4'hf:
read_mask = 8'hff;
4'h1,4'h3,4'h5,4'hd:
read_mask = 8'h0f;
4'h6,4'h8,4'h9,4'ha:
read_mask = 8'h1f;
endcase // addr
// register array
wire write;
reg last_write;
wire wr_edge = write & ~last_write;
assign write = !wr_n && !cs_n;
always @(posedge clk, negedge rst_n) begin
if( !rst_n ) begin
dout <= 8'd0;
last_write <= 0;
eg_restart <= 0;
regarray[0]<=8'd0; regarray[4]<=8'd0; regarray[ 8]<=8'd0; regarray[12]<=8'd0;
regarray[1]<=8'd0; regarray[5]<=8'd0; regarray[ 9]<=8'd0; regarray[13]<=8'd0;
regarray[2]<=8'd0; regarray[6]<=8'd0; regarray[10]<=8'd0; regarray[14]<=8'd0;
regarray[3]<=8'd0; regarray[7]<=8'd0; regarray[11]<=8'd0; regarray[15]<=8'd0;
end else begin
last_write <= write;
// Data read
case( addr )
default: dout <= regarray[ addr ] & read_mask;
endcase
// Data write
if( write ) begin
regarray[addr] <= din;
if ( addr == 4'hD && wr_edge ) eg_restart <= 1;
end else begin
eg_restart <= 0;
end
end
end
endmodule

View File

@@ -0,0 +1,87 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 28-Jan-2019
Based on sqmusic, by the same author
*/
// This is a wrapper with the BDIR/BC1 pins
module jt49_bus ( // note that input ports are not multiplexed
input rst_n,
input clk, // signal on positive edge
input clk_en,
// bus control pins of original chip
input bdir,
input bc1,
input [7:0] din,
input sel, // if sel is low, the clock is divided by 2
output [7:0] dout,
output [7:0] A, // linearised channel output
output [7:0] B,
output [7:0] C
);
parameter [1:0] COMP=2'b00;
reg wr_n, cs_n;
reg [3:0] addr;
reg addr_ok;
reg [7:0] din_latch;
always @(posedge clk)
if( !rst_n ) begin
wr_n <= 1'b1;
cs_n <= 1'b1;
addr <= 4'd0;
addr_ok <= 1'b1;
end else begin // I/O cannot use clk_en
// addr must be
case( {bdir,bc1} )
2'b00: { wr_n, cs_n } <= 2'b11;
2'b01: { wr_n, cs_n } <= addr_ok ? 2'b10 : 2'b11;
2'b10: begin
{ wr_n, cs_n } <= addr_ok ? 2'b00 : 2'b11;
din_latch <= din;
end
2'b11: begin
{ wr_n, cs_n } <= 2'b11;
addr <= din[3:0];
addr_ok <= din[7:4] == 4'd0;
end
endcase // {bdir,bc1}
end
jt49 #(.COMP(COMP)) u_jt49( // note that input ports are not multiplexed
.rst_n ( rst_n ),
.clk ( clk ), // signal on positive edge
.clk_en ( clk_en ), // clock enable on negative edge
.addr ( addr[3:0] ),
.cs_n ( cs_n ),
.wr_n ( wr_n ), // write
.din ( din_latch ),
.sel ( sel ), // if sel is low, the clock is divided by 2
.dout ( dout ),
.A ( A ), // linearised channel output
.B ( B ),
.C ( C )
);
endmodule // jt49_bus

View File

@@ -0,0 +1,56 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
module jt49_cen(
input clk,
input rst_n,
input cen, // base clock enable signal
input sel, // when low, divide by 2 once more
output reg cen16,
output reg cen256
);
parameter CLKDIV = 3; // use 3 for standalone JT49 or 2
reg [CLKDIV:0] cencnt;
localparam eg = CLKDIV; //8;
wire toggle16 = sel ? ~|cencnt[CLKDIV-1:0] : ~|cencnt[CLKDIV:0];
wire toggle256= sel ? ~|cencnt[eg-2:0] : ~|cencnt[eg-1:0];
always @(posedge clk, negedge rst_n) begin
if(!rst_n)
cencnt <= 1'd0;
else begin
if(cen) cencnt <= cencnt+1'd1;
end
end
always @(posedge clk) begin
cen16 <= cen & toggle16;
cen256 <= cen & toggle256;
end
endmodule // jt49_cen

View File

@@ -0,0 +1,53 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
module jt49_div #(parameter W=12 )
(
input wire clk, // this is the divided down clock from the core
input wire cen,
input wire rst_n,
input wire[W-1:0] period,
output reg div
);
reg [W-1:0]count;
wire [W-1:0] one = { {W-1{1'b0}}, 1'b1};
always @(posedge clk, negedge rst_n ) begin
if( !rst_n) begin
count <= one;
div <= 1'b0;
end
else if(cen) begin
if( count>=period ) begin
count <= one;
div <= ~div;
end
else
/*if( period!={W{1'b0}} )*/ count <= count + one ;
end
end
endmodule

View File

@@ -0,0 +1,88 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
module jt49_eg(
input wire cen,
input wire clk, // this is the divided down clock from the core
input wire step,
input wire null_period,
input wire rst_n,
input wire restart,
input wire[3:0] ctrl,
output reg [4:0] env
);
reg inv, stop;
reg [4:0] gain;
wire CONT = ctrl[3];
wire ATT = ctrl[2];
wire ALT = ctrl[1];
wire HOLD = ctrl[0];
wire will_hold = !CONT || HOLD;
always @(posedge clk)
if( cen ) env <= inv ? ~gain : gain;
reg last_step;
wire step_edge = (step && !last_step) || null_period;
wire will_invert = (!CONT&&ATT) || (CONT&&ALT);
reg rst_latch, rst_clr;
always @(posedge clk) begin
if( restart ) rst_latch <= 1;
else if(rst_clr ) rst_latch <= 0;
end
always @( posedge clk, negedge rst_n )
if( !rst_n) begin
gain <= 5'h1F;
inv <= 0;
stop <= 0;
rst_clr <= 0;
end
else if( cen ) begin
last_step <= step;
if( rst_latch ) begin
gain <= 5'h1F;
inv <= ATT;
stop <= 1'b0;
rst_clr <= 1;
end
else begin
rst_clr <= 0;
if (step_edge && !stop) begin
if( gain==5'h00 ) begin
if( will_hold )
stop <= 1'b1;
else
gain <= gain-5'b1;
if( will_invert ) inv<=~inv;
end
else gain <= gain-5'b1;
end
end
end
endmodule

View File

@@ -0,0 +1,174 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
`timescale 1ns / 1ps
// Compression vs dynamic range
// 0 -> 43.6dB
// 1 -> 29.1
// 2 -> 21.8
// 3 -> 13.4
module jt49_exp(
input wire clk,
input wire[1:0] comp, // compression
input wire[4:0] din,
output reg [7:0] dout
);
reg [7:0] lut[0:127];
wire[6:0] addr = {comp,din};
always @(posedge clk) dout <= lut[addr];
initial begin
lut[0] = 8'd0;
lut[1] = 8'd1;
lut[2] = 8'd1;
lut[3] = 8'd1;
lut[4] = 8'd2;
lut[5] = 8'd2;
lut[6] = 8'd3;
lut[7] = 8'd3;
lut[8] = 8'd4;
lut[9] = 8'd5;
lut[10] = 8'd6;
lut[11] = 8'd7;
lut[12] = 8'd9;
lut[13] = 8'd11;
lut[14] = 8'd13;
lut[15] = 8'd15;
lut[16] = 8'd18;
lut[17] = 8'd22;
lut[18] = 8'd26;
lut[19] = 8'd31;
lut[20] = 8'd37;
lut[21] = 8'd45;
lut[22] = 8'd53;
lut[23] = 8'd63;
lut[24] = 8'd75;
lut[25] = 8'd90;
lut[26] = 8'd107;
lut[27] = 8'd127;
lut[28] = 8'd151;
lut[29] = 8'd180;
lut[30] = 8'd214;
lut[31] = 8'd255;
lut[32] = 8'd0;
lut[33] = 8'd7;
lut[34] = 8'd8;
lut[35] = 8'd10;
lut[36] = 8'd11;
lut[37] = 8'd12;
lut[38] = 8'd14;
lut[39] = 8'd15;
lut[40] = 8'd17;
lut[41] = 8'd20;
lut[42] = 8'd22;
lut[43] = 8'd25;
lut[44] = 8'd28;
lut[45] = 8'd31;
lut[46] = 8'd35;
lut[47] = 8'd40;
lut[48] = 8'd45;
lut[49] = 8'd50;
lut[50] = 8'd56;
lut[51] = 8'd63;
lut[52] = 8'd71;
lut[53] = 8'd80;
lut[54] = 8'd90;
lut[55] = 8'd101;
lut[56] = 8'd113;
lut[57] = 8'd127;
lut[58] = 8'd143;
lut[59] = 8'd160;
lut[60] = 8'd180;
lut[61] = 8'd202;
lut[62] = 8'd227;
lut[63] = 8'd255;
lut[64] = 8'd0;
lut[65] = 8'd18;
lut[66] = 8'd20;
lut[67] = 8'd22;
lut[68] = 8'd24;
lut[69] = 8'd26;
lut[70] = 8'd29;
lut[71] = 8'd31;
lut[72] = 8'd34;
lut[73] = 8'd37;
lut[74] = 8'd41;
lut[75] = 8'd45;
lut[76] = 8'd49;
lut[77] = 8'd53;
lut[78] = 8'd58;
lut[79] = 8'd63;
lut[80] = 8'd69;
lut[81] = 8'd75;
lut[82] = 8'd82;
lut[83] = 8'd90;
lut[84] = 8'd98;
lut[85] = 8'd107;
lut[86] = 8'd116;
lut[87] = 8'd127;
lut[88] = 8'd139;
lut[89] = 8'd151;
lut[90] = 8'd165;
lut[91] = 8'd180;
lut[92] = 8'd196;
lut[93] = 8'd214;
lut[94] = 8'd233;
lut[95] = 8'd255;
lut[96] = 8'd0;
lut[97] = 8'd51;
lut[98] = 8'd54;
lut[99] = 8'd57;
lut[100] = 8'd60;
lut[101] = 8'd63;
lut[102] = 8'd67;
lut[103] = 8'd70;
lut[104] = 8'd74;
lut[105] = 8'd78;
lut[106] = 8'd83;
lut[107] = 8'd87;
lut[108] = 8'd92;
lut[109] = 8'd97;
lut[110] = 8'd103;
lut[111] = 8'd108;
lut[112] = 8'd114;
lut[113] = 8'd120;
lut[114] = 8'd127;
lut[115] = 8'd134;
lut[116] = 8'd141;
lut[117] = 8'd149;
lut[118] = 8'd157;
lut[119] = 8'd166;
lut[120] = 8'd175;
lut[121] = 8'd185;
lut[122] = 8'd195;
lut[123] = 8'd206;
lut[124] = 8'd217;
lut[125] = 8'd229;
lut[126] = 8'd241;
lut[127] = 8'd255;
end
endmodule

View File

@@ -0,0 +1,63 @@
/* This file is part of JT49.
JT49 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.
JT49 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 JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-Nov-2018
Based on sqmusic, by the same author
*/
`timescale 1ns / 1ps
module jt49_noise(
input wire cen,
input wire clk,
input wire rst_n,
input wire[4:0] period,
output reg noise
);
reg[5:0] count;
reg[16:0] poly17;
wire poly17_zero = poly17==17'b0;
wire noise_en;
reg last_en;
wire noise_up = noise_en && !last_en;
always @(posedge clk ) if(cen) begin
noise <= ~poly17[0];
end
always @( posedge clk, negedge rst_n )
if( !rst_n )
poly17 <= 17'd0;
else if( cen ) begin
last_en <= noise_en;
if( noise_up )
poly17 <= { poly17[0] ^ poly17[3] ^ poly17_zero, poly17[16:1] };
end
jt49_div #(5) u_div(
.clk ( clk ),
.cen ( cen ),
.rst_n ( rst_n ),
.period ( period ),
.div ( noise_en )
);
endmodule

View File

@@ -0,0 +1,6 @@
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) jt89.vhd ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt89.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt89_noise.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt89_vol.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt89_mixer.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt89_tone.v ]

159
common/Sound/jt89/jt89.v Normal file
View File

@@ -0,0 +1,159 @@
/* This file is part of JT89.
JT89 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.
JT89 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 JT89. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: March, 8th 2017
This work was originally based in the implementation found on the
SMS core of MiST. Some of the changes, all according to data sheet:
-Fixed volume
-Fixed tone 2 rate option of noise generator
-Fixed rate of noise generator
-Fixed noise shift clear
-Fixed noise generator update bug by which it gets updated
multiple times if v='0'
-Added all 0's prevention circuit to noise generator
*/
module jt89(
input clk,
(* direct_enable = 1 *) input clk_en,
input rst,
input wr_n,
input [7:0] din,
output signed [10:0] sound,
output ready
);
parameter interpol16=0;
wire signed [ 8:0] ch0, ch1, ch2, noise;
assign ready = 1'b1;
(* direct_enable = 1 *) reg cen_16;
(* direct_enable = 1 *) reg cen_4;
jt89_mixer #(.interpol16(interpol16)) mix(
.clk ( clk ),
.clk_en ( clk_en), // uses main clock enable
.cen_16 ( cen_16),
.cen_4 ( cen_4 ),
.rst ( rst ),
.ch0 ( ch0 ),
.ch1 ( ch1 ),
.ch2 ( ch2 ),
.noise ( noise ),
.sound ( sound )
);
// configuration registers
reg [9:0] tone0, tone1, tone2;
reg [3:0] vol0, vol1, vol2, vol3;
reg [2:0] ctrl3;
reg [2:0] regn;
reg [3:0] clk_div;
always @(posedge clk )
if( rst ) begin
cen_16 <= 1'b1;
cen_4 <= 1'b1;
end else begin
cen_16 <= clk_en & (&clk_div);
cen_4 <= clk_en & (&clk_div[1:0]);
end
always @(posedge clk )
if( rst )
clk_div <= 4'd0;
else if( clk_en )
clk_div <= clk_div + 1'b1;
reg clr_noise, last_wr;
wire [2:0] reg_sel = din[7] ? din[6:4] : regn;
always @(posedge clk)
if( rst ) begin
{ vol0, vol1, vol2, vol3 } <= {16{1'b1}};
{ tone0, tone1, tone2 } <= 30'd0;
ctrl3 <= 3'b100;
end
else begin
last_wr <= wr_n;
if( !wr_n && last_wr ) begin
clr_noise <= din[7:4] == 4'b1110; // clear noise
// when there is an access to the control register
regn <= reg_sel;
case( reg_sel )
3'b00_0: if( din[7] ) tone0[3:0]<=din[3:0]; else tone0[9:4]<=din[5:0];
3'b01_0: if( din[7] ) tone1[3:0]<=din[3:0]; else tone1[9:4]<=din[5:0];
3'b10_0: if( din[7] ) tone2[3:0]<=din[3:0]; else tone2[9:4]<=din[5:0];
3'b11_0: ctrl3 <= din[2:0];
3'b00_1: vol0 <= din[3:0];
3'b01_1: vol1 <= din[3:0];
3'b10_1: vol2 <= din[3:0];
3'b11_1: vol3 <= din[3:0];
endcase
end
else clr_noise <= 1'b0;
end
jt89_tone u_tone0(
.clk ( clk ),
.rst ( rst ),
.clk_en ( cen_16 ),
.vol ( vol0 ),
.tone ( tone0 ),
.snd ( ch0 ),
.out ( )
);
jt89_tone u_tone1(
.clk ( clk ),
.rst ( rst ),
.clk_en ( cen_16 ),
.vol ( vol1 ),
.tone ( tone1 ),
.snd ( ch1 ),
.out ( )
);
wire out2;
jt89_tone u_tone2(
.clk ( clk ),
.rst ( rst ),
.clk_en ( cen_16 ),
.vol ( vol2 ),
.tone ( tone2 ),
.snd ( ch2 ),
.out ( out2 )
);
jt89_noise u_noise(
.clk ( clk ),
.rst ( rst ),
.clk_en ( cen_16 ),
.clr ( clr_noise ),
.vol ( vol3 ),
.ctrl3 ( ctrl3 ),
.tone2 ( tone2 ),
.snd ( noise )
);
endmodule

View File

@@ -0,0 +1,19 @@
library IEEE;
use IEEE.std_logic_1164.all;
package jt89 is
component jt89
port
(
rst : in std_logic;
clk : in std_logic; -- CPU clock
clk_en : in std_logic := '1'; -- optional clock enable, if not needed leave as '1'
din : in std_logic_vector(7 downto 0);
wr_n : in std_logic;
ready : out std_logic;
sound : out std_logic_vector(10 downto 0) -- signed
);
end component;
end;

View File

@@ -0,0 +1,68 @@
/* This file is part of JT89.
JT89 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.
JT89 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 JT89. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: December, 1st 2018
*/
module jt89_mixer #(parameter bw=9, interpol16=0)(
input rst,
input clk,
input clk_en,
input cen_16,
input cen_4,
input [bw-1:0] ch0,
input [bw-1:0] ch1,
input [bw-1:0] ch2,
input [bw-1:0] noise,
output signed [bw+1:0] sound
);
reg signed [bw+1:0] fresh;
always @(posedge clk)
fresh <=
{ {2{ch0[bw-1]}}, ch0 }+
{ {2{ch1[bw-1]}}, ch1 }+
{ {2{ch2[bw-1]}}, ch2 }+
{ {2{noise[bw-1]}}, noise };
generate
if( interpol16==1 ) begin
wire signed [bw+1:0] snd4;
localparam calcw=bw+8;
jt12_interpol #(.calcw(calcw),.inw(bw+2),.rate(4),.m(4),.n(2)) u_uprate1 (
.rst ( rst ),
.clk ( clk ),
.cen_in ( cen_16 ),
.cen_out( cen_4 ),
.snd_in ( fresh ),
.snd_out( snd4 )
);
jt12_interpol #(.calcw(calcw),.inw(bw+2),.rate(4),.m(4),.n(2)) u_uprate2 (
.rst ( rst ),
.clk ( clk ),
.cen_in ( cen_4 ),
.cen_out( clk_en ),
.snd_in ( snd4 ),
.snd_out( sound )
);
end else
assign sound = fresh;
endgenerate
endmodule

View File

@@ -0,0 +1,76 @@
/* This file is part of JT89.
JT89 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.
JT89 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 JT89. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: March, 8th 2017
This work was originally based in the implementation found on the
SMS core of MiST
*/
module jt89_noise(
input clk,
(* direct_enable = 1 *) input clk_en,
input rst,
input clr,
input [2:0] ctrl3,
input [3:0] vol,
input [9:0] tone2,
output [8:0] snd
);
reg [15:0] shift;
reg [10:0] cnt;
reg update;
jt89_vol u_vol(
.rst ( rst ),
.clk ( clk ),
.clk_en ( clk_en ),
.din ( shift[0] ),
.vol ( vol ),
.snd ( snd )
);
always @(posedge clk)
if( rst ) begin
cnt <= 'd0;
end else if( clk_en ) begin
if( cnt==11'd1 ) begin
case( ctrl3[1:0] )
2'd0: cnt <= 11'h20; // clk_en already divides by 16
2'd1: cnt <= 11'h40;
2'd2: cnt <= 11'h80;
2'd3: cnt <= (tone2 == 0) ? 11'h02 : {tone2, 1'b0};
endcase
end else begin
cnt <= cnt-11'b1;
end
end
wire fb = ctrl3[2]?(shift[0]^shift[3]):shift[0];
always @(posedge clk)
if( rst || clr )
shift <= { 1'b1, 15'd0 };
else if( clk_en ) begin
if( cnt==1 ) begin
shift <= (|shift == 1'b0) ? {1'b1, 15'd0 } : {fb, shift[15:1]};
end
end
endmodule

View File

@@ -0,0 +1,10 @@
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) jt89_sms.vhd ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt89_sms.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt89.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt89_noise.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt89_vol.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt89_mixer.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt89_tone.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) mixer/jt12_interpol.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) mixer/jt12_comb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) mixer/jt12_dac2.v ]

View File

@@ -0,0 +1,43 @@
/* This file is part of JT89.
JT89 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.
JT89 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 JT89. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: Dec, 22nd, 2018
JT89 with x16 interpolation filter. For use with SEGA MASTER SYSTEM cores.
*/
module jt89_sms(
input clk,
input rst,
input wr_n,
input [7:0] din,
output signed [10:0] sound,
output ready
);
jt89 #(.interpol16(1)) u_jt89(
.clk ( clk ),
.clk_en ( 1'b1 ),
.rst ( rst ),
.wr_n ( wr_n ),
.din ( din ),
.sound ( sound ), // output interpolated at clk data rate
.ready ( ready )
);
endmodule // jt89_sms

View File

@@ -0,0 +1,29 @@
library IEEE;
use IEEE.std_logic_1164.all;
package jt89 is
-- SMS wrapper. clk_en assumed to be 1. x16 LPF+interpolator enabled
component jt89_sms
port
(
rst : in std_logic;
clk : in std_logic; -- CPU clock
din : in std_logic_vector(7 downto 0);
wr_n : in std_logic;
ready : out std_logic;
sound : out std_logic_vector(10 downto 0) -- signed
);
end component;
component jt12_dac2
port
(
rst : in std_logic;
clk : in std_logic; -- CPU clock
din : in std_logic_vector(10 downto 0); -- signed
dout : out std_logic
);
end component;
end;

View File

@@ -0,0 +1,63 @@
/* This file is part of JT89.
JT89 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.
JT89 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 JT89. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: March, 8th 2017
This work was originally based in the implementation found on the
SMS core of MiST
*/
module jt89_tone(
input clk,
(* direct_enable = 1 *) input clk_en,
input rst,
input [9:0] tone,
input [3:0] vol,
output [8:0] snd,
output reg out
);
reg [9:0] cnt;
reg last_out;
jt89_vol u_vol(
.rst ( rst ),
.clk ( clk ),
.clk_en ( clk_en ),
.din ( out ),
.vol ( vol ),
.snd ( snd )
);
always @(posedge clk)
if( rst ) begin
cnt <= 10'd0;
out <= 1'b0;
end else if( clk_en ) begin
if( tone==10'd0 || tone==10'd1 ) // special case. This is used for sample playing.
out <= 1'b1;
else begin
if( cnt[9:0]==10'd1 ) begin
cnt[9:0] <= (tone==10'd0) ? 10'd1 : tone;
out <= ~out;
end
else cnt <= cnt-10'b1;
end
end
endmodule

View File

@@ -0,0 +1,5 @@
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt89.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt89_noise.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt89_vol.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt89_mixer.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt89_tone.v ]

View File

@@ -0,0 +1,63 @@
/* This file is part of JT89.
JT89 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.
JT89 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 JT89. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: December, 1st 2018
This work was originally based in the implementation found on the
SMS core of MiST
*/
module jt89_vol(
input clk,
input clk_en,
input rst,
input din,
input [3:0] vol,
output reg signed [8:0] snd
);
reg [7:0] max;
always @(*)
case ( vol ) // 2dB per LSB (20*log10)
4'd0: max = 8'd255;
4'd1: max = 8'd203;
4'd2: max = 8'd161;
4'd3: max = 8'd128;
4'd4: max = 8'd102;
4'd5: max = 8'd81;
4'd6: max = 8'd64;
4'd7: max = 8'd51;
4'd8: max = 8'd40;
4'd9: max = 8'd32;
4'd10: max = 8'd26;
4'd11: max = 8'd20;
4'd12: max = 8'd16;
4'd13: max = 8'd13;
4'd14: max = 8'd10;
4'd15: max = 8'd0;
endcase
always @(posedge clk)
if( rst )
snd <= 9'd0;
else if( clk_en )
snd <= din ? {1'b0,max} : -{1'b0,max};
endmodule

View File

@@ -0,0 +1,59 @@
/* This file is part of JT12.
JT12 program 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.
JT12 program 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 JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-12-2018
*/
module jt12_comb #(parameter
w=16, // bit width
m=1 // depth of comb filter
)(
input rst,
input clk,
(* direct_enable *) input cen,
input signed [w-1:0] snd_in,
output reg signed [w-1:0] snd_out
);
wire signed [w-1:0] prev;
// m-delay stage
generate
genvar k;
reg signed [w-1:0] mem[0:m-1];
assign prev=mem[m-1];
for(k=0;k<m;k=k+1) begin : mem_gen
always @(posedge clk)
if(rst) begin
mem[k] <= {w{1'b0}};
end else if(cen) begin
mem[k] <= k==0 ? snd_in : mem[k-1];
end
end
endgenerate
// Comb filter at synthesizer sampling rate
always @(posedge clk)
if(rst) begin
snd_out <= {w{1'b0}};
end else if(cen) begin
snd_out <= snd_in - prev;
end
endmodule // jt12_comb

View File

@@ -0,0 +1,63 @@
/* This file is part of JT12.
JT12 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.
JT12 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 JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: March, 9th 2017
*/
`timescale 1ns / 1ps
/*
input sampling rate must be the same as clk frequency
interpolate input signal accordingly to get the
right sampling rate.
Refer to sigmadelta.ods to see how the internal width (int_w)
was determined.
*/
module jt12_dac2 #(parameter width=11)
(
input clk,
input rst,
input signed [width-1:0] din,
output reg dout
);
localparam int_w = width+5;
reg [int_w-1:0] y, error, error_1, error_2;
wire [width-1:0] undin = { ~din[width-1], din[width-2:0] };
always @(*) begin
y = undin + { error_1, 1'b0} - error_2;
dout = ~y[int_w-1];
error = y - {dout, {width{1'b0}}};
end
always @(posedge clk)
if( rst ) begin
error_1 <= {int_w{1'b0}};
error_2 <= {int_w{1'b0}};
end else begin
error_1 <= error;
error_2 <= error_1;
end
endmodule

View File

@@ -0,0 +1,92 @@
/* This file is part of JT12.
JT12 program 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.
JT12 program 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 JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-12-2018
*/
module jt12_interpol #(parameter calcw=18, inw=16,
n=2, // number of stages
m=1, // depth of comb filter
rate=2 // it will stuff with as many as (rate-1) zeros
)(
input rst,
input clk,
(* direct_enable *) input cen_in,
(* direct_enable *) input cen_out,
input signed [inw-1:0] snd_in,
output reg signed [inw-1:0] snd_out
);
reg signed [calcw-1:0] inter6;
wire signed [calcw-1:0] comb_op, integ_op;
localparam wdiff = calcw - inw;
generate
genvar k;
wire [calcw-1:0] comb_data[0:n];
assign comb_data[0] = { {wdiff{snd_in[inw-1]}}, snd_in };
assign comb_op = comb_data[n];
for(k=0;k<n;k=k+1) begin : comb_gen
jt12_comb #(.w(calcw),.m(m)) u_comb(
.rst ( rst ),
.clk ( clk ),
.cen ( cen_in ),
.snd_in ( comb_data[k] ),
.snd_out( comb_data[k+1] )
);
end
endgenerate
reg [rate-1:0] inter_cnt;
// interpolator
always @(posedge clk)
if(rst) begin
inter6 <= {calcw{1'b0}};
inter_cnt <= { {(rate-1){1'b0}}, 1'b1};
end else if(cen_out) begin
inter6 <= inter_cnt[0] ? comb_op : {calcw{1'b0}};
inter_cnt <= { inter_cnt[0], inter_cnt[rate-1:1] };
end
// integrator at clk x cen sampling rate
generate
genvar k2;
reg [calcw-1:0] integ_data[0:n];
assign integ_op = integ_data[n];
always @(*)
integ_data[0] = inter6;
for(k2=1;k2<=n;k2=k2+1) begin : integ_gen
always @(posedge clk)
if(rst) begin
integ_data[k2] <= {calcw{1'b0}};
end else if(cen_out) begin
integ_data[k2] <= integ_data[k2] + integ_data[k2-1];
end
end
endgenerate
always @(posedge clk)
if(rst) begin
snd_out <= {inw{1'b0}};
end else if(cen_out) begin
snd_out<= integ_op[calcw-1:wdiff];
end
endmodule