Merge pull request #223 from MP2E/jt12_update

Update jt49 and jt12 to latest revision, rebalance ADPCMA audio to match real AES using MDFourier
This commit is contained in:
Alexey Melnikov
2024-08-26 13:34:27 +08:00
committed by GitHub
57 changed files with 1226 additions and 727 deletions

View File

@@ -1,5 +1,5 @@
set_global_assignment -name QIP_FILE rtl/jt12/hdl/jt10.qip
set_global_assignment -name QIP_FILE rtl/jt49/hdl/jt49.qip
set_global_assignment -name QIP_FILE rtl/jt12/target/quartus/jt10.qip
set_global_assignment -name QIP_FILE rtl/jt49/syn/quartus/jt49.qip
set_global_assignment -name QIP_FILE rtl/video/video.qip
set_global_assignment -name QIP_FILE rtl/cd/cd.qip
set_global_assignment -name QIP_FILE rtl/io/io.qip
@@ -11,4 +11,4 @@ set_global_assignment -name QIP_FILE rtl/cpu/T80/T80.qip
set_global_assignment -name VERILOG_FILE rtl/cpu/cpu_z80.v
set_global_assignment -name VERILOG_FILE rtl/cpu/cpu_68k.v
set_global_assignment -name SYSTEMVERILOG_FILE neogeo.sv
set_global_assignment -name SDC_FILE neogeo.sdc
set_global_assignment -name SDC_FILE NeoGeo.sdc

View File

@@ -2,7 +2,7 @@
===================================================================
You can show your appreciation through
* [Patreon](https://patreon.com/topapate), by supporting releases
* [Patreon](https://patreon.com/jotego), by supporting releases
* [Paypal](https://paypal.me/topapate), with a donation
@@ -10,19 +10,50 @@ JT12 is an FM sound source written in Verilog, fully compatible with YM2612/YM34
The implementation tries to be as close to original hardware as possible. Low usage of FPGA resources has also been a design goal. Except in the operator section (jt12_op) where an exact replica of the original circuit is done. This could be done in less space with a different style but because this piece of the circuit was reversed engineered by Sauraen, I decided to use that knowledge.
Directories:
## Using JT12 in a git project
hdl -> all relevant RTL files, written in verilog
ver -> test benches
ver/verilator -> test bench that can play vgm files
If you are using JT12 in a git project, the best way to add it to your project is:
Usage:
1. Optionally fork JT12's repository to your own GitHub account
2. Add it as a submodule to your git project: `git submodule add https://github.com/jotego/jt12.git`
3. Now you can refer to the RTL files in **jt12/hdl**
YM2610: top level file hdl/jt10.v. Use jt10.qip to automatically get all relevant files in Quartus.
YM2612: top level file hdl/jt12.v. Use jt12.qip to automatically get all relevant files in Quartus.
YM2203: top level file hdl/jt03.v. Use jt03.qip to automatically get all relevant files in Quartus.
The advantages of a using a git submodule are:
1. Your project contains a reference to a commit of the JT12 repository
2. As long as you do not manually update the JT12 submodule, it will keep pointing to the same commit
3. Each time you make a commit in your project, it will include a pointer to the JT12 commit used. So you will always know the JT12 that worked for you
4. If JT12 is updated and you want to get the changes, simply update the submodule using git. The new JT12 commit used will be annotated in your project's next commit. So the history of your project will reflect that change too.
5. JT12 files will be intact and you will use the files without altering them.
## Directories
* hdl -> all relevant RTL files, written in verilog
* ver -> test benches
* ver/verilator -> test bench that can play vgm files
## Usage
Chip | Top Level | QIP File
--------|---------------|---------
YM2610 | jt10.v | jt10.qip
YM2612 | jt12.v | jt12.qip
YM2203 | jt03.v | jt03.qip
## Simulation
=============
There are several simulation test benches in the **ver** folder. The most important one is in the **ver/verilator** folder. The simulation script is called with the shell script **go** in the same folder. The script will compile the file **test.cpp** together with other files and the design and will simulate the tune specificied with the -f command. It can read **vgm** tunes and generate .wav output of them.
## Related Projects
Other sound chips from the same author
Chip | Repository
-----------------------|------------
YM2203, YM2612, YM2610 | [JT12](https://github.com/jotego/jt12)
YM2151 | [JT51](https://github.com/jotego/jt51)
YM3526 | [JTOPL](https://github.com/jotego/jtopl)
YM2149 | [JT49](https://github.com/jotego/jt49)
sn76489an | [JT89](https://github.com/jotego/jt89)
OKI 6295 | [JT6295](https://github.com/jotego/jt6295)
OKI MSM5205 | [JT5205](https://github.com/jotego/jt5205)

View File

@@ -124,7 +124,8 @@ always @(posedge clk or negedge rst_n)
if( !rst_n ) begin
addr1 <= 'd0; addr2 <= 'd0; addr3 <= 'd0;
addr4 <= 'd0; addr5 <= 'd0; addr6 <= 'd0;
done1 <= 'd1; done5 <= 'd1; done6 <= 'd1;
done1 <= 'd1; done2 <= 'd1; done3 <= 'd1;
done4 <= 'd1; done5 <= 'd1; done6 <= 'd1;
start1 <= 'd0; start2 <= 'd0; start3 <= 'd0;
start4 <= 'd0; start5 <= 'd0; start6 <= 'd0;
end1 <= 'd0; end2 <= 'd0; end3 <= 'd0;

View File

@@ -22,39 +22,39 @@
// calculates d=a/b
// a = b*d + r
module jt10_adpcm_div #(parameter dw=16)(
module jt10_adpcm_div #(parameter DW=16)(
input rst_n,
input clk, // CPU clock
input cen,
input start, // strobe
input [dw-1:0] a,
input [dw-1:0] b,
output reg [dw-1:0] d,
output reg [dw-1:0] r,
input [DW-1:0] a,
input [DW-1:0] b,
output reg [DW-1:0] d,
output reg [DW-1:0] r,
output working
);
reg [dw-1:0] cycle;
reg [DW-1:0] cycle;
assign working = cycle[0];
wire [dw:0] sub = { r[dw-2:0], d[dw-1] } - b;
wire [DW:0] sub = { r[DW-2:0], d[DW-1] } - b;
always @(posedge clk or negedge rst_n)
if( !rst_n ) begin
cycle <= 'd0;
end else if(cen) begin
if( start ) begin
cycle <= ~16'd0;
r <= 16'd0;
cycle <= {DW{1'b1}};
r <= 0;
d <= a;
end else if(cycle[0]) begin
cycle <= { 1'b0, cycle[dw-1:1] };
if( sub[dw] == 0 ) begin
r <= sub[dw-1:0];
d <= { d[dw-2:0], 1'b1};
cycle <= { 1'b0, cycle[DW-1:1] };
if( sub[DW] == 0 ) begin
r <= sub[DW-1:0];
d <= { d[DW-2:0], 1'b1};
end else begin
r <= { r[dw-2:0], d[dw-1] };
d <= { d[dw-2:0], 1'b0 };
r <= { r[DW-2:0], d[DW-1] };
d <= { d[DW-2:0], 1'b0 };
end
end
end

View File

@@ -54,8 +54,6 @@ module jt10_adpcm_drvA(
input [5:0] ch_enable
);
/* verilator tracing_on */
reg [5:0] cur_ch;
reg [5:0] en_ch;
reg [3:0] data;

View File

@@ -38,7 +38,12 @@ module jt10_adpcm_gain(
output signed [15:0] pcm_att
);
reg [9:0] lin_5b, lin1, lin2, lin6;
reg [7:0] lracl1, lracl2, lracl3, lracl4, lracl5, lracl6;
reg [6:0] db5;
reg [5:0] up_ch_dec;
reg [3:0] sh1, sh6;
always @(*)
case(up_ch)
3'd0: up_ch_dec = 6'b000_001;
@@ -52,7 +57,6 @@ always @(*)
//wire [5:0] en_ch2 = { en_ch[4:0], en_ch[5] }; // shift the bits to fit in the pipeline slot correctly
reg [6:0] db5;
always @(*)
case( db5[2:0] )
3'd0: lin_5b = 10'd512;
@@ -65,9 +69,6 @@ always @(*)
3'd7: lin_5b = 10'd280;
endcase
reg [7:0] lracl1, lracl2, lracl3, lracl4, lracl5, lracl6;
reg [9:0] lin_5b, lin1, lin2, lin6;
reg [3:0] sh1, sh6;
// dB to linear conversion
assign lr = lracl1[7:6];
@@ -114,6 +115,8 @@ reg [3:0] shcnt1, shcnt2, shcnt3, shcnt4, shcnt5, shcnt6;
reg shcnt_mod3, shcnt_mod4, shcnt_mod5;
reg [31:0] pcm2_mul;
wire signed [15:0] lin2s = {6'b0,lin2};
reg signed [15:0] pcm1, pcm2, pcm3, pcm4, pcm5, pcm6;
reg match2;
always @(*) begin
shcnt_mod3 = shcnt3 != 0;
@@ -122,9 +125,6 @@ always @(*) begin
pcm2_mul = pcm2 * lin2s;
end
reg signed [15:0] pcm1, pcm2, pcm3, pcm4, pcm5, pcm6;
reg match2;
assign pcm_att = pcm1;
always @(posedge clk or negedge rst_n)

View File

@@ -80,7 +80,7 @@ always @(posedge clk) if(cen55) begin
else pcminter <= ( (pcminter < pcmlast) == step_sign ) ? pcminter : step_sign ? pcminter - step : pcminter + step;
end
jt10_adpcm_div #(.dw(16)) u_div(
jt10_adpcm_div #(.DW(16)) u_div(
.rst_n ( rst_n ),
.clk ( clk ),
.cen ( cen ),

View File

@@ -1,6 +1,6 @@
/* 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
@@ -21,8 +21,6 @@
// Wrapper to output only combined channels. Defaults to YM2203 mode.
module jt03(
input rst, // rst should be at least 6 clk&cen cycles long
input clk, // CPU clock
@@ -31,22 +29,35 @@ module jt03(
input addr,
input cs_n,
input wr_n,
output [7:0] dout,
output irq_n,
// I/O pins used by YM2203 embedded YM2149 chip
input [7:0] IOA_in,
input [7:0] IOB_in,
output [7:0] IOA_out,
output [7:0] IOB_out,
output IOA_oe,
output IOB_oe,
// Separated output
output [ 7:0] psg_A,
output [ 7:0] psg_B,
output [ 7:0] psg_C,
output signed [15:0] fm_snd,
// combined output
output [ 9:0] psg_snd,
output [ 9:0] psg_snd,
output signed [15:0] snd,
output snd_sample
output snd_sample,
// Debug
//input [ 7:0] debug_bus,
output [ 7:0] debug_view
);
parameter YM2203_LUMPED=0; // set to 1 if all PSG outputs are shorted together without any resistor
jt12_top #(
.use_lfo(0),.use_ssg(1), .num_ch(3), .use_pcm(0), .use_adpcm(0) )
.use_lfo(0),.use_ssg(1), .num_ch(3), .use_pcm(0), .use_adpcm(0), .mask_div(0),
.YM2203_LUMPED(YM2203_LUMPED) )
u_jt12(
.rst ( rst ), // rst should be at least 6 clk&cen cycles long
.clk ( clk ), // CPU clock
@@ -55,23 +66,31 @@ u_jt12(
.addr ( {1'b0, addr} ),
.cs_n ( cs_n ),
.wr_n ( wr_n ),
.ch_enable ( 6'd0 ),
.dout ( dout ),
.irq_n ( irq_n ),
// YM2203 I/O pins
.IOA_in ( IOA_in ),
.IOB_in ( IOB_in ),
.IOA_out ( IOA_out ),
.IOB_out ( IOB_out ),
.IOA_oe ( IOA_oe ),
.IOB_oe ( IOB_oe ),
// Unused ADPCM pins
.en_hifi_pcm ( 1'b0 ), // used only on YM2612 mode
.adpcma_addr ( ), // real hardware has 10 pins multiplexed through RMPX pin
.adpcma_bank ( ),
.adpcma_roe_n ( ), // ADPCM-A ROM output enable
.adpcma_data ( 8'd0 ), // Data from RAM
.adpcmb_data ( 8'd0 ),
.adpcmb_addr ( ), // real hardware has 12 pins multiplexed through PMPX pin
.adpcmb_roe_n ( ), // ADPCM-B ROM output enable
.en_hifi_pcm ( 1'b0 ), // used only on YM2612 mode
.adpcma_addr ( ), // real hardware has 10 pins multiplexed through RMPX pin
.adpcma_bank ( ),
.adpcma_roe_n ( ), // ADPCM-A ROM output enable
.adpcma_data ( 8'd0 ), // Data from RAM
.adpcmb_data ( 8'd0 ),
.adpcmb_addr ( ), // real hardware has 12 pins multiplexed through PMPX pin
.adpcmb_roe_n ( ), // ADPCM-B ROM output enable
// Separated output
.psg_A ( psg_A ),
.psg_B ( psg_B ),
.psg_C ( psg_C ),
.psg_snd ( psg_snd ),
.psg_snd ( psg_snd ),
.fm_snd_left ( fm_snd ),
.fm_snd_right (),
.adpcmA_l (),
@@ -81,7 +100,11 @@ u_jt12(
.snd_right ( snd ),
.snd_left (),
.snd_sample ( snd_sample )
.snd_sample ( snd_sample ),
//.debug_bus ( debug_bus ),
.debug_bus ( 8'd0 ),
.debug_view ( debug_view )
);
endmodule // jt03
endmodule // jt03

36
rtl/jt12/hdl/jt03.yaml Normal file
View File

@@ -0,0 +1,36 @@
here:
- jt03.v
- jt12_top.v
- jt03_acc.v
- jt12_single_acc.v
- jt12_eg.v
- jt12_eg_cnt.v
- jt12_eg_comb.v
- jt12_eg_step.v
- jt12_eg_pure.v
- jt12_eg_final.v
- jt12_eg_ctrl.v
- jt12_exprom.v
- jt12_kon.v
- jt12_lfo.v
- jt12_mmr.v
- jt12_div.v
- jt12_mod.v
- jt12_op.v
- jt12_csr.v
- jt12_pg.v
- jt12_pg_inc.v
- jt12_pg_dt.v
- jt12_pg_sum.v
- jt12_pg_comb.v
- jt12_pm.v
- jt12_logsin.v
- jt12_reg.v
- jt12_reg_ch.v
- jt12_sh.v
- jt12_sh_rst.v
- jt12_sh24.v
- jt12_sumch.v
- jt12_timers.v
- jt12_dout.v
- ../jt49/hdl/jt49.yaml

View File

@@ -20,12 +20,14 @@
*/
`timescale 1ns / 1ps
/* Use for YM2203
no left/right channels
full operator resolution
clamped to maximum output of signed 16 bits */
// Use for YM2203
// no left/right channels
// full operator resolution
// clamped to maximum output of signed 16 bits
// This version does not clamp each channel individually
// That does not correspond to real hardware behaviour. I should
// change it.
module jt03_acc
(
@@ -54,17 +56,18 @@ always @(*) begin
endcase
end
localparam res=18;
wire [res-1:0] hires;
assign snd = hires[res-1:res-16];
jt12_single_acc #(.win(14),.wout(res)) u_mono(
// real YM2608 drops the op_result LSB, resulting in a 13-bit accumulator
// but in YM2203, a 13-bit acc for 3 channels only requires 15 bits
// and YM3014 has a 16-bit dynamic range.
// I am leaving the LSB and scaling the output voltage accordingly. This
// should result in less quantification noise.
jt12_single_acc #(.win(14),.wout(16)) u_mono(
.clk ( clk ),
.clk_en ( clk_en ),
.op_result ( op_result ),
.sum_en ( sum_en ),
.zero ( zero ),
.snd ( hires )
.snd ( snd )
);
endmodule

View File

@@ -1,6 +1,6 @@
/* 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
@@ -30,7 +30,7 @@ module jt10(
input [1:0] addr,
input cs_n,
input wr_n,
output [7:0] dout,
output irq_n,
// ADPCM pins
@@ -40,24 +40,24 @@ module jt10(
input [7:0] adpcma_data, // Data from RAM
output [23:0] adpcmb_addr, // real hardware has 12 pins multiplexed through PMPX pin
output adpcmb_roe_n, // ADPCM-B ROM output enable
input [7:0] adpcmb_data,
input [7:0] adpcmb_data,
// Separated output
output [ 7:0] psg_A,
output [ 7:0] psg_B,
output [ 7:0] psg_C,
output signed [15:0] fm_snd,
// combined output
output [ 9:0] psg_snd,
output [ 9:0] psg_snd,
output signed [15:0] snd_right,
output signed [15:0] snd_left,
output snd_sample,
input [3:0] snd_enable,
input [5:0] ch_enable
input [ 5:0] ch_enable // ADPCM-A channels
);
// Uses 6 FM channels but only 4 are outputted
jt12_top #(
.use_lfo(1),.use_ssg(1), .num_ch(6), .use_pcm(0), .use_adpcm(1), .use_clkdiv(0),
.use_lfo(1),.use_ssg(1), .num_ch(6), .use_pcm(0), .use_adpcm(1),
.JT49_DIV(3) )
u_jt12(
.rst ( rst ), // rst should be at least 6 clk&cen cycles long
@@ -67,7 +67,7 @@ u_jt12(
.addr ( addr ),
.cs_n ( cs_n ),
.wr_n ( wr_n ),
.dout ( dout ),
.irq_n ( irq_n ),
// ADPCM pins
@@ -75,7 +75,6 @@ u_jt12(
.adpcma_bank ( adpcma_bank ),
.adpcma_roe_n ( adpcma_roe_n ), // ADPCM-A ROM output enable
.adpcma_data ( adpcma_data ), // Data from RAM
.adpcmb_addr ( adpcmb_addr ), // real hardware has 12 pins multiplexed through PMPX pin
.adpcmb_roe_n ( adpcmb_roe_n ), // ADPCM-B ROM output enable
.adpcmb_data ( adpcmb_data ), // Data from RAM
@@ -83,18 +82,31 @@ u_jt12(
.psg_A ( psg_A ),
.psg_B ( psg_B ),
.psg_C ( psg_C ),
.psg_snd ( psg_snd ),
.psg_snd ( psg_snd ),
.fm_snd_left ( fm_snd ),
.fm_snd_right (),
.fm_snd_right ( ),
.adpcmA_l ( ),
.adpcmA_r ( ),
.adpcmB_l ( ),
.adpcmB_r ( ),
// Unused YM2203
// unused
.IOA_in ( 8'b0 ),
.IOB_in ( 8'b0 ),
.IOA_out ( ),
.IOB_out ( ),
.IOA_oe ( ),
.IOB_oe ( ),
.debug_bus ( 8'd0 ),
// Sound output
.snd_right ( snd_right ),
.snd_left ( snd_left ),
.snd_sample ( snd_sample ),
.snd_enable ( snd_enable ),
.ch_enable ( ch_enable ),
// unused pins
.en_hifi_pcm ( 1'b0 ) // used only on YM2612 mode
.en_hifi_pcm ( 1'b0 ), // used only on YM2612 mode
.debug_view ( )
);
endmodule // jt03
endmodule // jt03

36
rtl/jt12/hdl/jt10.yaml Normal file
View File

@@ -0,0 +1,36 @@
here:
- jt10.v
- jt10_acc.v
- jt12_top.v
- jt12_single_acc.v
- jt12_eg.v
- jt12_eg_cnt.v
- jt12_eg_comb.v
- jt12_eg_step.v
- jt12_eg_pure.v
- jt12_eg_final.v
- jt12_eg_ctrl.v
- jt12_exprom.v
- jt12_kon.v
- jt12_lfo.v
- jt12_mmr.v
- jt12_div.v
- jt12_mod.v
- jt12_op.v
- jt12_csr.v
- jt12_pg.v
- jt12_pg_inc.v
- jt12_pg_dt.v
- jt12_pg_sum.v
- jt12_pg_comb.v
- jt12_pm.v
- jt12_logsin.v
- jt12_reg.v
- jt12_reg_ch.v
- jt12_sh.v
- jt12_sh_rst.v
- jt12_sh24.v
- jt12_sumch.v
- jt12_timers.v
- jt12_dout.v
- ../jt49/hdl/jt49.yaml

View File

@@ -80,8 +80,8 @@ reg acc_en_l, acc_en_r;
always @(*)
case( {cur_op,cur_ch} )
{2'd0,3'd0}: begin // ADPCM-A:
acc_input_l = (adpcmA_l <<< 2) + (adpcmA_l <<< 1);
acc_input_r = (adpcmA_r <<< 2) + (adpcmA_r <<< 1);
acc_input_l = (adpcmA_l <<< 2) + (adpcmA_l <<< 1) + adpcmA_l + (adpcmA_l >>> 2); // amplify by 7.25x to match AES channel balance
acc_input_r = (adpcmA_r <<< 2) + (adpcmA_r <<< 1) + adpcmA_r + (adpcmA_r >>> 2);
`ifndef NOMIX
acc_en_l = 1'b1;
acc_en_r = 1'b1;
@@ -139,7 +139,7 @@ jt12_single_acc #(.win(16),.wout(16)) u_right(
// Dump each channel independently
// It dumps values in decimal, left and right
integer f0,f1,f2,f4,f5,f6;
reg signed [15:0] sum_l[7], sum_r[7];
reg signed [15:0] sum_l[0:7], sum_r[0:7];
initial begin
f0=$fopen("fm0.raw","w");

View File

@@ -1,6 +1,6 @@
/* 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
@@ -30,7 +30,7 @@ module jt12 (
input [1:0] addr,
input cs_n,
input wr_n,
output [7:0] dout,
output irq_n,
// configuration
@@ -41,7 +41,7 @@ module jt12 (
output snd_sample
);
// Default parameters for JT12 select a YM2610
// Default parameters for JT12 select a YM2612
jt12_top u_jt12(
.rst ( rst ), // rst should be at least 6 clk&cen cycles long
.clk ( clk ), // CPU clock
@@ -50,8 +50,8 @@ jt12_top u_jt12(
.addr ( addr ),
.cs_n ( cs_n ),
.wr_n ( wr_n ),
.dout ( dout ),
.dout ( dout ),
.irq_n ( irq_n ),
// configuration
.en_hifi_pcm ( en_hifi_pcm ),
@@ -62,16 +62,31 @@ jt12_top u_jt12(
.adpcma_data ( 8'd0 ), // Data from RAM
.adpcmb_addr ( ), // real hardware has 12 pins multiplexed through PMPX pin
.adpcmb_roe_n ( ), // ADPCM-B ROM output enable
.adpcmb_data ( 8'd0 ),
.ch_enable ( 6'h3f),
// Separated output
.psg_A (),
.psg_B (),
.psg_C (),
.fm_snd_left (),
.fm_snd_right (),
.adpcmA_l ( ),
.adpcmA_r ( ),
.adpcmB_l ( ),
.adpcmB_r ( ),
// Unused YM2203
.IOA_in ( 8'b0 ),
.IOB_in ( 8'b0 ),
.IOA_out ( ),
.IOB_out ( ),
.IOA_oe ( ),
.IOB_oe ( ),
.debug_bus ( 8'd0 ),
// combined output
.psg_snd (),
.snd_right ( snd_right ), // FM+PSG
.snd_left ( snd_left ), // FM+PSG
.snd_sample ( snd_sample )
.snd_sample ( snd_sample ),
.debug_view ( )
);
endmodule // jt03
endmodule // jt03

10
rtl/jt12/hdl/jt12.yaml Normal file
View File

@@ -0,0 +1,10 @@
modules:
other:
- from: jt12/hdl
get:
- "*.v"
- adpcm/*.v
- from: jt12/jt49/hdl
get:
- jt49.yaml

View File

@@ -100,8 +100,8 @@ jt12_single_acc #(.win(9),.wout(12)) u_right(
// Output can be amplied by 8/6=1.33 to use full range
// an easy alternative is to add 1/4th and get 1.25 amplification
always @(posedge clk) if(clk_en) begin
left <= pre_left + { {2{left [11]}}, left [11:2] };
right <= pre_right + { {2{right[11]}}, right[11:2] };
left <= pre_left + { {2{pre_left [11]}}, pre_left [11:2] };
right <= pre_right + { {2{pre_right[11]}}, pre_right[11:2] };
end
endmodule

View File

@@ -1,32 +1,35 @@
/* 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: 14-2-2017
*/
`timescale 1ns / 1ps
module jt12_div(
input rst,
input clk,
input cen /* synthesis direct_enable */,
input [1:0] div_setting,
output reg clk_en, // after prescaler
output reg clk_en_2, // cen divided by 2
output reg clk_en_ssg,
output reg clk_en_666, // 666 kHz
output reg clk_en_111, // 111 kHz
output reg clk_en_55 // 55 kHz
input [1:0] div_setting,
output reg clk_en, // after prescaler
output reg clk_en_2, // cen divided by 2
output reg clk_en_ssg,
output reg clk_en_666, // 666 kHz
output reg clk_en_111, // 111 kHz
output reg clk_en_55 // 55 kHz
);
parameter use_ssg=0;
@@ -54,7 +57,6 @@ reg cen_int, cen_ssg_int, cen_adpcm_int, cen_adpcm3_int;
//
always @(*) begin
casez( div_setting )
2'b0?: begin // FM 1/2 - SSG 1/1
opn_pres = 4'd2-4'd1;
@@ -85,18 +87,18 @@ always @(negedge clk) begin
cen_adpcm3_int <= adpcm_cnt111 == 3'd0;
cen_55_int <= adpcm_cnt55 == 3'd0;
`ifdef FASTDIV
// always enabled for fast sims (use with GYM output, timer will not work well)
// always enabled for fast sims (use with GYM output, the timers will not work well)
clk_en <= 1'b1;
clk_en2 <= 1'b1;
clk_en_2 <= 1'b1;
clk_en_ssg <= 1'b1;
clk_en_666 <= 1'b1;
clk_en_55 <= 1'b1;
`else
clk_en <= cen & cen_int;
clk_en <= cen & cen_int;
clk_en_2 <= cen && (div2==2'b00);
clk_en_ssg <= use_ssg ? (cen & cen_ssg_int) : 1'b0;
clk_en_666 <= cen & cen_adpcm_int;
clk_en_111 <= cen & cen_adpcm_int & cen_adpcm3_int;
clk_en_666 <= cen & cen_adpcm_int;
clk_en_111 <= cen & cen_adpcm_int & cen_adpcm3_int;
clk_en_55 <= cen & cen_adpcm_int & cen_adpcm3_int & cen_55_int;
`endif
end
@@ -136,4 +138,4 @@ always @(posedge clk)
end
end
endmodule // jt12_div
endmodule // jt12_div

View File

@@ -29,7 +29,7 @@ module jt12_eg_cnt(
reg [1:0] eg_cnt_base;
always @(posedge clk) begin : envelope_counter
always @(posedge clk, posedge rst) begin : envelope_counter
if( rst ) begin
eg_cnt_base <= 2'd0;
eg_cnt <=15'd0;

View File

@@ -24,7 +24,7 @@ module jt12_eg_ctrl(
input keyoff_now,
input [2:0] state_in,
input [9:0] eg,
// envelope configuration
// envelope configuration
input [4:0] arate, // attack rate
input [4:0] rate1, // decay rate
input [4:0] rate2, // sustain rate
@@ -42,16 +42,16 @@ module jt12_eg_ctrl(
output reg pg_rst
);
localparam ATTACK = 3'b001,
DECAY = 3'b010,
localparam ATTACK = 3'b001,
DECAY = 3'b010,
HOLD = 3'b100,
RELEASE= 3'b000; // default state is release
RELEASE= 3'b000; // default state is release
// wire is_decaying = state_in[1] | state_in[2];
reg [4:0] sustain;
always @(*)
always @(*)
if( sl == 4'd15 )
sustain = 5'h1f; // 93dB
else
@@ -74,14 +74,14 @@ always @(*) begin
pg_rst = keyon_now | ssg_pg_rst;
end
always @(*)
always @(*)
casez ( { keyoff_now, keyon_now, state_in} )
5'b01_???: begin // key on
base_rate = arate;
state_next = ATTACK;
ssg_inv_out = ssg_att & ssg_en;
end
{2'b00, ATTACK}:
{2'b00, ATTACK}:
if( eg==10'd0 ) begin
base_rate = rate1;
state_next = DECAY;
@@ -99,7 +99,7 @@ always @(*)
ssg_inv_out = ssg_en & (ssg_alt ^ ssg_inv_in);
end
else begin
base_rate = eg[9:5] >= sustain ? rate2 : rate1;
base_rate = eg[9:5] >= sustain ? rate2 : rate1; // equal comparison according to Nuke
state_next = DECAY;
ssg_inv_out = ssg_inv_in;
end

View File

@@ -1,4 +1,3 @@
`timescale 1ns / 1ps
/* This file is part of JT12.

View File

@@ -1,4 +1,3 @@
`timescale 1ns / 1ps
/* This file is part of JT12.
@@ -61,14 +60,32 @@ if(num_ch==6) begin
always @(posedge clk) if( clk_en )
keyon_I <= (csm&&next_ch==3'd2&&overflow2) || csr_out;
wire key_upnow = up_keyon && (keyon_ch==next_ch) && (next_op == 2'd3);
reg up_keyon_reg;
reg [3:0] tkeyon_op;
reg [2:0] tkeyon_ch;
wire key_upnow;
assign key_upnow = up_keyon_reg && (tkeyon_ch==next_ch) && (next_op == 2'd3);
always @(posedge clk) if( clk_en ) begin
if (rst)
up_keyon_reg <= 1'b0;
if (up_keyon) begin
up_keyon_reg <= 1'b1;
tkeyon_op <= keyon_op;
tkeyon_ch <= keyon_ch; end
else if (key_upnow)
up_keyon_reg <= 1'b0;
end
wire middle1;
wire middle2;
wire middle3;
wire din = key_upnow ? keyon_op[3] : csr_out;
wire mid_din2 = key_upnow ? keyon_op[1] : middle1;
wire mid_din3 = key_upnow ? keyon_op[2] : middle2;
wire mid_din4 = key_upnow ? keyon_op[0] : middle3;
wire din = key_upnow ? tkeyon_op[3] : csr_out;
wire mid_din2 = key_upnow ? tkeyon_op[1] : middle1;
wire mid_din3 = key_upnow ? tkeyon_op[2] : middle2;
wire mid_din4 = key_upnow ? tkeyon_op[0] : middle3;
jt12_sh_rst #(.width(1),.stages(6),.rstval(1'b0)) u_konch0(
.clk ( clk ),
@@ -105,7 +122,7 @@ end
else begin // 3 channels
reg din;
reg [3:0] next_op_hot;
always @(*) begin
case( next_op )
2'd0: next_op_hot = 4'b0001; // S1
@@ -113,10 +130,10 @@ else begin // 3 channels
2'd2: next_op_hot = 4'b0010; // S2
2'd3: next_op_hot = 4'b1000; // S4
endcase
din = keyon_ch==next_ch && up_keyon ? |(keyon_op&next_op_hot) : csr_out;
din = keyon_ch[1:0]==next_ch[1:0] && up_keyon ? |(keyon_op&next_op_hot) : csr_out;
end
always @(posedge clk) if( clk_en )
always @(posedge clk) if( clk_en )
keyon_I <= csr_out; // No CSM for YM2203
jt12_sh_rst #(.width(1),.stages(12),.rstval(1'b0)) u_konch1(

View File

@@ -18,7 +18,6 @@
Date: 25-2-2017
*/
`timescale 1ns / 1ps
/*

View File

@@ -18,7 +18,6 @@
Date: 14-2-2017
*/
`timescale 1ns / 1ps
module jt12_mmr(
input rst,
@@ -52,6 +51,7 @@ module jt12_mmr(
output reg fast_timers,
input flag_A,
input overflow_A,
output reg [1:0] div_setting,
// PCM
output reg [8:0] pcm,
output reg pcm_en,
@@ -123,13 +123,11 @@ module jt12_mmr(
// PSG interace
output [3:0] psg_addr,
output [7:0] psg_data,
output reg psg_wr_n
output reg psg_wr_n,
input [7:0] debug_bus
);
parameter use_ssg=0, num_ch=6, use_pcm=1, use_adpcm=0, use_clkdiv=1;
reg [1:0] div_setting;
parameter use_ssg=0, num_ch=6, use_pcm=1, use_adpcm=0, mask_div=1;
jt12_div #(.use_ssg(use_ssg)) u_div (
.rst ( rst ),
@@ -183,16 +181,12 @@ reg [ 5:0] latch_fnum;
reg [2:0] up_ch;
reg [1:0] up_op;
reg old_write;
reg [7:0] din_copy;
always @(posedge clk)
old_write <= write;
reg [7:0] op_din, ch_din;
generate
if( use_ssg ) begin
assign psg_addr = selected_register[3:0];
assign psg_data = din_copy;
assign psg_data = ch_din;
end else begin
assign psg_addr = 4'd0;
assign psg_data = 8'd0;
@@ -202,88 +196,102 @@ endgenerate
reg part;
reg [5:0] exbank;
`ifdef SIMULATION
always @(posedge clk) if( write && rst ) begin
$display("WARNING [JT12]: detected write request while in reset.\nThis is likely a glue-logic error in the CPU-FM module.");
$finish;
end
`endif
wire [2:0] ch_sel = {part, selected_register[1:0]};
// this runs at clk speed, no clock gating here
// if I try to make this an async rst it fails to map it
// as flip flops but uses latches instead. So I keep it as sync. reset
always @(posedge clk) begin : memory_mapped_registers
if( rst ) begin
selected_register <= 8'h0;
selected_register <= 0;
div_setting <= 2'b10; // FM=1/6, SSG=1/4
up_ch <= 3'd0;
up_op <= 2'd0;
up_keyon <= 1'd0;
up_opreg <= 7'd0;
up_chreg <= 3'd0;
up_ch <= 0;
up_op <= 0;
up_keyon <= 0;
up_opreg <= 0;
up_chreg <= 0;
// IRQ Mask
/*{ irq_zero_en, irq_brdy_en, irq_eos_en,
irq_tb_en, irq_ta_en } = 5'h1f; */
// timers
{ value_A, value_B } <= 18'd0;
{ value_A, value_B } <= 0;
{ clr_flag_B, clr_flag_A,
enable_irq_B, enable_irq_A, load_B, load_A } <= 6'd0;
fast_timers <= 1'b0;
enable_irq_B, enable_irq_A, load_B, load_A } <= 0;
fast_timers <= 0;
// LFO
lfo_freq <= 3'd0;
lfo_en <= 1'b0;
csm <= 1'b0;
effect <= 1'b0;
lfo_freq <= 0;
lfo_en <= 0;
csm <= 0;
effect <= 0;
// PCM
pcm <= 9'h0;
pcm_en <= 1'b0;
pcm_wr <= 1'b0;
pcm <= 0;
pcm_en <= 0;
pcm_wr <= 0;
// ADPCM-A
aon_a <= 'd0;
atl_a <= 'd0;
up_start <= 'd0;
up_end <= 'd0;
up_addr <= 3'd7;
up_lracl <= 3'd7;
up_aon <= 'd0;
lracl <= 'd0;
addr_a <= 'd0;
aon_a <= 0;
atl_a <= 0;
up_start <= 0;
up_end <= 0;
up_addr <= 7;
up_lracl <= 7;
up_aon <= 0;
lracl <= 0;
addr_a <= 0;
// ADPCM-B
acmd_on_b <= 'd0;
acmd_rep_b <= 'd0;
acmd_rst_b <= 'd0;
alr_b <= 'd0;
flag_ctl <= 'd0;
astart_b <= 'd0;
aend_b <= 'd0;
adeltan_b <= 'd0;
acmd_on_b <= 0;
acmd_rep_b <= 0;
acmd_rst_b <= 0;
alr_b <= 0;
flag_ctl <= 0;
astart_b <= 0;
aend_b <= 0;
adeltan_b <= 0;
flag_mask <= 0;
aeg_b <= 8'hff;
// Original test features
eg_stop <= 1'b0;
pg_stop <= 1'b0;
psg_wr_n <= 1'b1;
eg_stop <= 0;
pg_stop <= 0;
psg_wr_n <= 1;
//
{ block_ch3op1, fnum_ch3op1 } <= {3'd0, 11'd0 };
{ block_ch3op3, fnum_ch3op3 } <= {3'd0, 11'd0 };
{ block_ch3op2, fnum_ch3op2 } <= {3'd0, 11'd0 };
latch_fnum <= 6'd0;
din_copy <= 8'd0;
part <= 1'b0;
latch_fnum <= 0;
op_din <= 0;
part <= 0;
end else begin
up_chreg <= 0;
// WRITE IN REGISTERS
if( write ) begin
if( !addr[0] ) begin
selected_register <= din;
part <= addr[1];
if( use_clkdiv==1 ) begin
case(din)
// clock divider: should work only for ym2203
// and ym2608.
// clock divider works just by selecting the register
REG_CLK_N6: div_setting[1] <= 1'b1; // 2D
REG_CLK_N3: div_setting[0] <= 1'b1; // 2E
REG_CLK_N2: div_setting <= 2'b0; // 2F
default:;
endcase
end
if (!mask_div)
case(din)
// clock divider: should work only for ym2203
// and ym2608.
// clock divider works just by selecting the register
REG_CLK_N6: div_setting[1] <= 1'b1; // 2D
REG_CLK_N3: div_setting[0] <= 1'b1; // 2E
REG_CLK_N2: div_setting <= 2'b0; // 2F
default:;
endcase
end else begin
// Global registers
din_copy <= din;
up_keyon <= selected_register == REG_KON && !part;
up_ch <= {part, selected_register[1:0]};
up_op <= selected_register[3:2]; // 0=S1,1=S3,2=S2,3=S4
ch_din <= din;
if( selected_register == REG_KON && !part ) begin
up_keyon <= 1;
op_din <= din;
end else begin
up_keyon <= 0;
end
// General control (<0x20 registers and A0==0)
if(!part) begin
casez( selected_register)
@@ -378,17 +386,16 @@ always @(posedge clk) begin : memory_mapped_registers
4'ha: adeltan_b[15:8] <= din;
4'hb: aeg_b <= din;
4'hc: begin
flag_mask <= ~{din[7],din[5:0]};
flag_ctl <= {din[7],din[5:0]}; // this lasts a single clock cycle
end
flag_mask <= ~{din[7],din[5:0]};
flag_ctl <= {din[7],din[5:0]}; // this lasts a single clock cycle
end
default:;
endcase
end
end
if( selected_register[1:0]==2'b11 )
{ up_chreg, up_opreg } <= { 3'h0, 7'h0 };
else
else begin
casez( selected_register )
// channel registers
8'hA0, 8'hA1, 8'hA2: { up_chreg, up_opreg } <= { 3'h1, 7'd0 }; // up_fnumlo
@@ -405,6 +412,12 @@ always @(posedge clk) begin : memory_mapped_registers
8'h9?: { up_chreg, up_opreg } <= { 3'h0, 7'h40 }; // up_ssgeg
default: { up_chreg, up_opreg } <= { 3'h0, 7'h0 };
endcase // selected_register
if( selected_register[7:4]>=3 && selected_register[7:4]<=9 ) begin
op_din <= din;
up_ch <= {part, selected_register[1:0]};
up_op <= selected_register[3:2]; // 0=S1,1=S3,2=S2,3=S4
end
end
end
end
else if(clk_en) begin /* clear once-only bits */
@@ -414,39 +427,44 @@ always @(posedge clk) begin : memory_mapped_registers
pcm_wr <= 1'b0;
flag_ctl <= 'd0;
up_aon <= 1'b0;
acmd_up_b <= 1'b0;
acmd_up_b <= 1'b0;
end
end
end
reg [4:0] busy_cnt; // busy lasts for 32 synth clock cycles, like in real chip
reg [4:0] busy_cnt; // busy lasts for 32 synthesizer clock cycles
wire [5:0] nx_busy = {1'd0,busy_cnt}+{5'd0,busy};
always @(posedge clk)
always @(posedge clk, posedge rst) begin
if( rst ) begin
busy <= 1'b0;
busy_cnt <= 5'd0;
end
else begin
if (!old_write && write && addr[0] ) begin // only set for data writes
busy <= 1'b1;
busy_cnt <= 5'd0;
end
else if(clk_en) begin
if( busy_cnt == 5'd31 ) busy <= 1'b0;
busy_cnt <= busy_cnt+5'd1;
busy <= 0;
busy_cnt <= 0;
end else begin
if( write&addr[0] ) begin
busy <= 1;
busy_cnt <= 0;
end else if(clk_en) begin
busy <= ~nx_busy[5] & busy;
busy_cnt <= nx_busy[4:0];
end
end
/* verilator tracing_off */
end
jt12_reg #(.num_ch(num_ch)) u_reg(
.rst ( rst ),
.clk ( clk ), // P1
.clk_en ( clk_en ),
.din ( din_copy ),
.up_keyon ( up_keyon ),
// channel udpates
.ch_sel ( ch_sel ),
.ch_din ( ch_din ),
.up_fnumlo ( up_chreg[0] ),
.up_alg ( up_chreg[1] ),
.up_pms ( up_chreg[2] ),
// operator updates
.din ( op_din ),
.up_keyon ( up_keyon ),
.up_dt1 ( up_opreg[0] ),
.up_tl ( up_opreg[1] ),
.up_ks_ar ( up_opreg[2] ),

View File

@@ -1,4 +1,3 @@
`timescale 1ns / 1ps
/* This file is part of JT12.

View File

@@ -1,4 +1,3 @@
`timescale 1ns / 1ps
/* This file is part of JT12.
@@ -270,4 +269,63 @@ always @(posedge clk) if( clk_en ) begin
op_result_internal <= op_XII;
end
`ifdef SIMULATION
reg signed [13:0] op_sep2_0;
reg signed [13:0] op_sep4_0;
reg signed [13:0] op_sep5_0;
reg signed [13:0] op_sep6_0;
reg signed [13:0] op_sep0_0;
reg signed [13:0] op_sep1_0;
reg signed [13:0] op_sep2_1;
reg signed [13:0] op_sep4_1;
reg signed [13:0] op_sep5_1;
reg signed [13:0] op_sep6_1;
reg signed [13:0] op_sep0_1;
reg signed [13:0] op_sep1_1;
reg signed [13:0] op_sep2_2;
reg signed [13:0] op_sep4_2;
reg signed [13:0] op_sep5_2;
reg signed [13:0] op_sep6_2;
reg signed [13:0] op_sep0_2;
reg signed [13:0] op_sep1_2;
reg signed [13:0] op_sep2_3;
reg signed [13:0] op_sep4_3;
reg signed [13:0] op_sep5_3;
reg signed [13:0] op_sep6_3;
reg signed [13:0] op_sep0_3;
reg signed [13:0] op_sep1_3;
reg [ 4:0] sepcnt;
always @(posedge clk) if(clk_en) begin
sepcnt <= zero ? 5'd0 : sepcnt+5'd1;
case( (sepcnt+14)%24 )
0: op_sep0_0 <= op_XII;
1: op_sep1_0 <= op_XII;
2: op_sep2_0 <= op_XII;
3: op_sep4_0 <= op_XII;
4: op_sep5_0 <= op_XII;
5: op_sep6_0 <= op_XII;
6: op_sep0_2 <= op_XII;
7: op_sep1_2 <= op_XII;
8: op_sep2_2 <= op_XII;
9: op_sep4_2 <= op_XII;
10: op_sep5_2 <= op_XII;
11: op_sep6_2 <= op_XII;
12: op_sep0_1 <= op_XII;
13: op_sep1_1 <= op_XII;
14: op_sep2_1 <= op_XII;
15: op_sep4_1 <= op_XII;
16: op_sep5_1 <= op_XII;
17: op_sep6_1 <= op_XII;
18: op_sep0_3 <= op_XII;
19: op_sep1_3 <= op_XII;
20: op_sep2_3 <= op_XII;
21: op_sep4_3 <= op_XII;
22: op_sep5_3 <= op_XII;
23: op_sep6_3 <= op_XII;
endcase
end
`endif
endmodule

View File

@@ -41,7 +41,7 @@ always @(posedge clk)
reg rate1, rate2; //, rate4, rate8;
reg cen1, cen2; //, cen4, cen8;
always @(posedge clk)
always @(posedge clk, posedge rst)
if(rst)
rate2 <= 1'b0;
else begin
@@ -56,7 +56,7 @@ always @(posedge clk)
end
end
always @(negedge clk) begin
always @(posedge clk) begin
cen1 <= rate1;
cen2 <= rate1 && rate2;
// cen4 <= rate1 && rate2 && rate4;

View File

@@ -20,17 +20,18 @@
*/
module jt12_pcm_interpol
#(parameter dw=9, stepw=5)
#(parameter DW=9, stepw=5)
(
input rst_n,
input clk,
input cen, // 8MHz cen
input cen55, // clk & cen55 = 55 kHz
input pcm_wr, // advance to next sample
input signed [dw-1:0] pcmin,
output reg signed [dw-1:0] pcmout
input signed [DW-1:0] pcmin,
output reg signed [DW-1:0] pcmout
);
reg sign, last_pcm_wr;
reg [stepw-1:0] dn, pre_dn={stepw{1'b1}};
wire posedge_pcmwr = pcm_wr && !last_pcm_wr;
wire negedge_pcmwr = !pcm_wr && last_pcm_wr;
@@ -38,9 +39,8 @@ wire negedge_pcmwr = !pcm_wr && last_pcm_wr;
reg start_div = 0;
wire working;
reg signed [dw-1:0] pcmnew, dx, pcmlast, pcminter;
wire signed [dw:0] dx_ext = { pcmin[dw-1], pcmin } - { pcmnew[dw-1], pcmnew };
reg sign, last_pcm_wr;
reg signed [DW-1:0] pcmnew, dx, pcmlast, pcminter;
wire signed [DW:0] dx_ext = { pcmin[DW-1], pcmin } - { pcmnew[DW-1], pcmnew };
// latch new data and compute the two deltas : dx and dn, slope = dx/dn
always @(posedge clk) begin
@@ -52,8 +52,8 @@ always @(posedge clk) begin
pcmnew <= pcmin;
pcmlast <= pcmnew;
dn <= pre_dn;
dx <= dx_ext[dw] ? ~dx_ext[dw-1:0] + 'd1 : dx_ext[dw-1:0];
sign <= dx_ext[dw];
dx <= dx_ext[DW] ? -dx_ext[DW-1:0] : dx_ext[DW-1:0];
sign <= dx_ext[DW];
start_div <= 1;
end
@@ -63,11 +63,11 @@ always @(posedge clk) begin
end
// interpolate samples
wire [dw-1:0] step;
wire signed [dw-1:0] next_up = pcminter + step;
wire signed [dw-1:0] next_down = pcminter - step;
wire overflow_up = 0;//next_up[dw-1] != pcmnew[dw-1];
wire overflow_down = 0;//next_down[dw-1] != pcmnew[dw-1];
wire [DW-1:0] step;
wire signed [DW-1:0] next_up = pcminter + step;
wire signed [DW-1:0] next_down = pcminter - step;
wire overflow_up = 0;//next_up[DW-1] != pcmnew[DW-1];
wire overflow_down = 0;//next_down[DW-1] != pcmnew[DW-1];
always @(posedge clk) begin
@@ -93,13 +93,13 @@ end
always @(posedge clk) if(cen55) pcmout <= pcminter;
jt10_adpcm_div #(.dw(dw)) u_div(
jt10_adpcm_div #(.DW(DW)) u_div(
.rst_n ( rst_n ),
.clk ( clk ),
.cen ( 1'b1 ),
.start ( start_div ),
.a ( dx ),
.b ( { {dw-stepw{1'b0}}, dn } ),
.b ( { {DW-stepw{1'b0}}, dn } ),
.d ( step ),
.r ( ),
.working( working )

View File

@@ -24,7 +24,6 @@ http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc
*/
`timescale 1ns / 1ps
/*

View File

@@ -1,49 +1,49 @@
/* 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 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.
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: 2-11-2018
Based on information posted by Nemesis on:
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: 2-11-2018
Based on information posted by Nemesis on:
http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc&start=167
Based on jt51_phasegen.v, from JT51
*/
Based on jt51_phasegen.v, from JT51
*/
module jt12_pg_sum (
input [ 3:0] mul,
input [19:0] phase_in,
input pg_rst,
input signed [5:0] detune_signed,
input [16:0] phinc_pure,
input [ 3:0] mul,
input [19:0] phase_in,
input pg_rst,
input signed [5:0] detune_signed,
input [16:0] phinc_pure,
output reg [19:0] phase_out,
output reg [ 9:0] phase_op
output reg [19:0] phase_out,
output reg [ 9:0] phase_op
);
reg [16:0] phinc_premul;
reg [19:0] phinc_mul;
always @(*) begin
phinc_premul = phinc_pure + {{11{detune_signed[5]}},detune_signed};
phinc_mul = ( mul==4'd0 ) ? {4'b0,phinc_premul[16:1]} : ({3'd0,phinc_premul} * mul);
phase_out = pg_rst ? 20'd0 : (phase_in + { phinc_mul});
phase_op = phase_out[19:10];
phinc_premul = phinc_pure + {{11{detune_signed[5]}},detune_signed};
phinc_mul = ( mul==4'd0 ) ? {4'b0,phinc_premul[16:1]} : ({3'd0,phinc_premul} * mul);
phase_out = pg_rst ? 20'd0 : (phase_in + { phinc_mul});
phase_op = phase_out[19:10];
end
endmodule // jt12_pg_sum

View File

@@ -17,9 +17,7 @@
Version: 1.0
Date: 14-10-2018
*/
// altera message_off 10030
`timescale 1ns / 1ps
// This implementation follows that of Alexey Khokholov (Nuke.YKT) in C language.

View File

@@ -24,7 +24,6 @@ module jt12_reg(
input rst,
input clk,
input clk_en /* synthesis direct_enable */,
input [7:0] din,
input [2:0] ch, // channel to update
input [1:0] op,
@@ -33,16 +32,20 @@ module jt12_reg(
input flag_A,
input overflow_A,
input up_keyon,
// channel udpates
input [2:0] ch_sel,
input [7:0] ch_din,
input up_alg,
input up_fnumlo,
// operator updates
input [7:0] din,
input up_keyon,
input up_pms,
input up_dt1,
input up_tl,
input up_ks_ar,
input up_amen_dr,
input up_sr,
input up_sl_rr,
input up_ssgeg,
@@ -181,23 +184,6 @@ wire update_op_IV = cur == req_opch_IV;
// key on/off
wire [3:0] keyon_op = din[7:4];
wire [2:0] keyon_ch = din[2:0];
// channel data
wire [2:0] fb_in = din[5:3];
wire [2:0] alg_in = din[2:0];
wire [2:0] pms_in = din[2:0];
wire [1:0] ams_in = din[5:4];
wire [7:0] fnlo_in = din;
wire update_ch_I = cur_ch == ch;
wire update_ch_IV = num_ch==6 ?
{ ~cur_ch[2], cur_ch[1:0]} == ch : // 6 channels
cur[1:0] == ch[1:0]; // 3 channels
wire up_alg_ch = up_alg & update_ch_I;
wire up_fnumlo_ch=up_fnumlo & update_ch_I;
wire up_pms_ch = up_pms & update_ch_I;
wire up_ams_ch = up_pms & update_ch_IV;
always @(*) begin
// next = cur==5'd23 ? 5'd0 : cur +1'b1;
@@ -327,46 +313,27 @@ assign { tl_IV, dt1_I, mul_II, ks_II,
// memory for CH registers
// Block/fnum data is latched until fnum low byte is written to
// Trying to synthesize this memory as M-9K RAM in Altera devices
// turns out worse in terms of resource utilization. Probably because
// this memory is already very small. It is better to leave it as it is.
localparam regch_width=25;
wire [regch_width-1:0] regch_out;
wire [regch_width-1:0] regch_in = {
up_fnumlo_ch? { latch_fnum, fnlo_in } : { block_I_raw, fnum_I_raw }, // 14
up_alg_ch ? { fb_in, alg_in } : { fb_I, alg_I },//3+3
up_ams_ch ? ams_in : ams_IV, //2
up_pms_ch ? pms_in : pms_I //3
};
jt12_reg_ch #(.NUM_CH(num_ch)) u_regch(
.rst ( rst ),
.clk ( clk ),
.cen ( clk_en ),
.din ( ch_din ),
assign { block_I_raw, fnum_I_raw,
fb_I, alg_I, ams_IV, pms_I } = regch_out;
.up_ch ( ch_sel ),
.latch_fnum ( latch_fnum ),
.up_fnumlo ( up_fnumlo ),
.up_alg ( up_alg ),
.up_pms ( up_pms ),
jt12_sh_rst #(.width(regch_width),.stages(num_ch)) u_regch(
.clk ( clk ),
.clk_en ( clk_en ),
.rst ( rst ),
.din ( regch_in ),
.drop ( regch_out )
.ch ( next_ch ), // next active channel
.block ( block_I_raw ),
.fnum ( fnum_I_raw ),
.fb ( fb_I ),
.alg ( alg_I ),
.rl ( rl ),
.ams_IV ( ams_IV ),
.pms ( pms_I )
);
generate
if( num_ch==6 ) begin
// RL is on a different register to
// have the reset to 1
wire [1:0] rl_in = din[7:6];
jt12_sh_rst #(.width(2),.stages(num_ch),.rstval(1'b1)) u_regch_rl(
.clk ( clk ),
.clk_en ( clk_en ),
.rst ( rst ),
.din ( up_pms_ch ? rl_in : rl ),
.drop ( rl )
);
end else begin // YM2203 has no stereo output
assign rl=2'b11;
end
endgenerate
`endif
endmodule

128
rtl/jt12/hdl/jt12_reg_ch.v Normal file
View File

@@ -0,0 +1,128 @@
/* 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: 23-10-2019
*/
// Channel data is not stored in a CSR as operators
// Proof of that is the Splatter House arcade writes
// channel and operator data in two consequitive accesses
// without enough time in between to have the eight
// channels go through the CSR. So the channel data
// cannot be CSR, but regular registers.
module jt12_reg_ch(
input rst,
input clk,
input cen,
input [ 7:0] din,
input [ 2:0] up_ch,
input [ 5:0] latch_fnum,
input up_fnumlo,
input up_alg,
input up_pms,
input [ 2:0] ch, // next active channel
output reg [ 2:0] block,
output reg [10:0] fnum,
output reg [ 2:0] fb,
output reg [ 2:0] alg,
output reg [ 1:0] rl,
output reg [ 1:0] ams_IV,
output reg [ 2:0] pms
);
parameter NUM_CH=6;
localparam M=NUM_CH==3?2:3;
reg [ 2:0] reg_block[0:NUM_CH-1];
reg [10:0] reg_fnum [0:NUM_CH-1];
reg [ 2:0] reg_fb [0:NUM_CH-1];
reg [ 2:0] reg_alg [0:NUM_CH-1];
reg [ 1:0] reg_rl [0:NUM_CH-1];
reg [ 1:0] reg_ams [0:NUM_CH-1];
reg [ 2:0] reg_pms [0:NUM_CH-1];
reg [ 2:0] ch_IV;
wire [M-1:0] ch_sel, out_sel;
function [M-1:0] chtr( input [2:0] chin );
reg [2:0] aux;
begin
aux = chin[M-1] ? {1'b0,chin[1:0]}+3'd3 : // upper channels
{1'b0,chin[1:0]}; // lower
chtr = NUM_CH==3 ? chin[M-1:0] : aux[M-1:0];
end
endfunction
assign ch_sel = chtr(up_ch);
assign out_sel = chtr(ch);
integer i;
/* verilator lint_off WIDTHEXPAND */
always @* begin
ch_IV = ch;
if( NUM_CH==6 )
case(out_sel)
0: ch_IV = 3;
1: ch_IV = 4;
2: ch_IV = 5;
3: ch_IV = 0;
4: ch_IV = 1;
5: ch_IV = 2;
default: ch_IV = 0;
endcase
end
/* verilator lint_on WIDTHEXPAND */
always @(posedge clk) if(cen) begin
block <= reg_block[out_sel];
fnum <= reg_fnum [out_sel];
fb <= reg_fb [out_sel];
alg <= reg_alg [out_sel];
rl <= reg_rl [out_sel];
ams_IV<= reg_ams [ch_IV[M-1:0]];
pms <= reg_pms [out_sel];
if( NUM_CH==3 ) rl <= 3; // YM2203 has no stereo output
end
always @(posedge clk, posedge rst) begin
if( rst ) for(i=0;i<NUM_CH;i=i+1) begin
reg_block[i] <= 0;
reg_fnum [i] <= 0;
reg_fb [i] <= 0;
reg_alg [i] <= 0;
reg_rl [i] <= 3;
reg_ams [i] <= 0;
reg_pms [i] <= 0;
end else begin
i = 0; // prevents latch warning in Quartus
if( up_fnumlo ) { reg_block[ch_sel], reg_fnum[ch_sel] } <= {latch_fnum,din};
if( up_alg ) begin
reg_fb [ch_sel] <= din[5:3];
reg_alg[ch_sel] <= din[2:0];
end
if( up_pms ) begin
reg_rl [ch_sel] <= din[7:6];
reg_ams[ch_sel] <= din[5:4];
reg_pms[ch_sel] <= din[2:0];
end
end
end
endmodule

View File

@@ -18,7 +18,6 @@
Date: 1-31-2017
*/
`timescale 1ns / 1ps
// stages must be greater than 2
module jt12_sh #(parameter width=5, stages=24 )

View File

@@ -18,7 +18,6 @@
Date: 1-31-2017
*/
`timescale 1ns / 1ps
module jt12_sh24 #(parameter width=5 )
(

View File

@@ -18,7 +18,6 @@
Date: 1-31-2017
*/
`timescale 1ns / 1ps
// stages must be greater than 2
module jt12_sh_rst #(parameter width=5, stages=32, rstval=1'b0 )
@@ -31,24 +30,14 @@ module jt12_sh_rst #(parameter width=5, stages=32, rstval=1'b0 )
);
reg [stages-1:0] bits[width-1:0];
wire [width-1:0] din_mx = rst ? {width{rstval[0]}} : din;
genvar i;
integer k;
generate
initial
for (k=0; k < width; k=k+1) begin
bits[k] = { stages{rstval}};
end
endgenerate
generate
for (i=0; i < width; i=i+1) begin: bit_shifter
always @(posedge clk)
if( rst ) begin
bits[i] <= {stages{rstval}};
end else if(clk_en) begin
bits[i] <= {bits[i][stages-2:0], din[i]};
end
always @(posedge clk) if(clk_en) begin
bits[i] <= {bits[i][stages-2:0], din_mx[i]};
end
assign drop[i] = bits[i][stages-1];
end
endgenerate

View File

@@ -23,7 +23,6 @@
// Accumulates an arbitrary number of inputs with saturation
// restart the sum when input "zero" is high
`timescale 1ns / 1ps
module jt12_single_acc #(parameter
win=14, // input data width

View File

@@ -18,7 +18,6 @@
Date: 1-31-2017
*/
`timescale 1ns / 1ps
/* The input is {op[1:0], ch[2:0]}
it adds 1 to the channel and overflow to the operator correctly */

View File

@@ -1,113 +1,140 @@
/* 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 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.
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/>.
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: 14-2-2017
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 14-2-2017
YM3438_APL.pdf
Timer A = 144*(1024-NA)/Phi M
Timer B = 2304*(256-NB)/Phi M
*/
YM3438_APL.pdf
Timer A = 144*(1024-NA)/Phi M
Timer B = 2304*(256-NB)/Phi M
*/
`timescale 1ns / 1ps
module jt12_timers(
input clk,
input rst,
input clk_en /* synthesis direct_enable */,
input [9:0] value_A,
input [7:0] value_B,
input load_A,
input load_B,
input clr_flag_A,
input clr_flag_B,
input enable_irq_A,
input enable_irq_B,
output flag_A,
output flag_B,
output overflow_A,
output irq_n
input clk,
input rst,
input clk_en /* synthesis direct_enable */,
input zero,
input [9:0] value_A,
input [7:0] value_B,
input load_A,
input load_B,
input clr_flag_A,
input clr_flag_B,
input enable_irq_A,
input enable_irq_B,
output flag_A,
output flag_B,
output overflow_A,
output irq_n
);
parameter num_ch = 6;
assign irq_n = ~( (flag_A&enable_irq_A) | (flag_B&enable_irq_B) );
jt12_timer #(.mult_width(5), .mult_max(24), .counter_width(10))
timer_A(
.clk ( clk ),
.rst ( rst ),
.clk_en ( clk_en ),
.start_value( value_A ),
.load ( load_A ),
.clr_flag ( clr_flag_A),
.flag ( flag_A ),
.overflow ( overflow_A)
);
/*
reg zero2;
jt12_timer #(.mult_width(9), .mult_max(384), .counter_width(8))
timer_B(
.clk ( clk ),
.rst ( rst ),
.clk_en ( clk_en ),
.start_value( value_B ),
.load ( load_B ),
.clr_flag ( clr_flag_B),
.flag ( flag_B ),
.overflow ( )
);
endmodule
module jt12_timer #(parameter counter_width = 10, mult_width=5, mult_max=4 )
(
input clk,
input rst,
(* direct_enable *) input clk_en,
input [counter_width-1:0] start_value,
input load,
input clr_flag,
output reg flag,
output reg overflow
);
reg [ mult_width-1:0] mult;
reg [counter_width-1:0] cnt;
always@(posedge clk)
if( clr_flag || rst)
flag <= 1'b0;
else if(overflow) flag<=1'b1;
reg [mult_width+counter_width-1:0] next, init;
always @(*) begin
if( mult+1'b1<mult_max ) begin
// mult not meant to overflow in this line
{overflow, next } = { {1'b0, cnt}, mult+1'b1 } ;
end else begin
{overflow, next } = { {1'b0, cnt}+1'b1, {mult_width{1'b0}} };
end
init = { start_value, {mult_width{1'b0}} };
always @(posedge clk, posedge rst) begin
if( rst )
zero2 <= 0;
else if(clk_en) begin
if( zero ) zero2 <= ~zero;
end
end
always @(posedge clk)
if( ~load || rst) begin
mult <= { (mult_width){1'b0} };
cnt <= start_value;
end
else if( clk_en )
{ cnt, mult } <= overflow ? init : next;
wire zero = num_ch == 6 ? zero : (zero2&zero);
*/
jt12_timer #(.CW(10)) timer_A(
.clk ( clk ),
.rst ( rst ),
.cen ( clk_en ),
.zero ( zero ),
.start_value( value_A ),
.load ( load_A ),
.clr_flag ( clr_flag_A ),
.flag ( flag_A ),
.overflow ( overflow_A )
);
jt12_timer #(.CW(8),.FREE_EN(1)) timer_B(
.clk ( clk ),
.rst ( rst ),
.cen ( clk_en ),
.zero ( zero ),
.start_value( value_B ),
.load ( load_B ),
.clr_flag ( clr_flag_B ),
.flag ( flag_B ),
.overflow ( )
);
endmodule
module jt12_timer #(parameter
CW = 8, // counter bit width. This is the counter that can be loaded
FW = 4, // number of bits for the free-running counter
FREE_EN = 0 // enables a 4-bit free enable count
) (
input rst,
input clk,
input cen,
input zero,
input [CW-1:0] start_value,
input load,
input clr_flag,
output reg flag,
output reg overflow
);
/* verilator lint_off WIDTH */
reg load_l;
reg [CW-1:0] cnt, next;
reg [FW-1:0] free_cnt, free_next;
reg free_ov;
always@(posedge clk, posedge rst)
if( rst )
flag <= 1'b0;
else /*if(cen)*/ begin
if( clr_flag )
flag <= 1'b0;
else if( cen && zero && load && overflow ) flag<=1'b1;
end
always @(*) begin
{free_ov, free_next} = { 1'b0, free_cnt} + 1'b1;
{overflow, next } = { 1'b0, cnt } + (FREE_EN ? free_ov : 1'b1);
end
always @(posedge clk) begin
load_l <= load;
if( !load_l && load ) begin
cnt <= start_value;
end else if( cen && zero && load )
cnt <= overflow ? start_value : next;
end
// Free running counter
always @(posedge clk) begin
if( rst ) begin
free_cnt <= 0;
end else if( cen && zero ) begin
free_cnt <= free_next;
end
end
/* verilator lint_on WIDTH */
endmodule

View File

@@ -27,7 +27,7 @@ http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc
module jt12_top (
input rst, // rst should be at least 6 clk&cen cycles long
input clk, // CPU clock
input cen, // optional clock enable, it not needed leave as 1'b1
(* direct_enable *) input cen, // optional clock enable, if not needed leave as 1'b1
input [7:0] din,
input [1:0] addr,
input cs_n,
@@ -45,6 +45,13 @@ module jt12_top (
output [23:0] adpcmb_addr, // real hardware has 12 pins multiplexed through PMPX pin
input [ 7:0] adpcmb_data,
output adpcmb_roe_n, // ADPCM-B ROM output enable
// I/O pins used by YM2203 embedded YM2149 chip
input [7:0] IOA_in,
input [7:0] IOB_in,
output [7:0] IOA_out,
output [7:0] IOB_out,
output IOA_oe,
output IOB_oe,
// Separated output
output [ 7:0] psg_A,
output [ 7:0] psg_B,
@@ -61,14 +68,18 @@ module jt12_top (
output signed [15:0] snd_left, // FM+PSG
output snd_sample,
input [3:0] snd_enable,
input [5:0] ch_enable
input [ 5:0] ch_enable, // ADPCM-A channels
input [ 7:0] debug_bus,
output [ 7:0] debug_view
);
// parameters to select the features for each chip type
// defaults to YM2612
parameter use_lfo=1, use_ssg=0, num_ch=6, use_pcm=1;
parameter use_adpcm=0, use_clkdiv=1;
parameter JT49_DIV=2;
parameter use_adpcm=0;
parameter JT49_DIV=2,
YM2203_LUMPED=0;
parameter mask_div=1;
wire flag_A, flag_B, busy;
@@ -160,7 +171,7 @@ wire [ 5:0] adpcma_flags; // ADPMC-A read over flags
wire adpcmb_flag;
wire [ 6:0] flag_ctl;
wire [ 6:0] flag_mask;
wire [ 1:0] div_setting;
wire clk_en_2, clk_en_666, clk_en_111, clk_en_55;
wire signed [15:0] adpcmAt_l;
@@ -174,6 +185,8 @@ assign adpcmB_r = snd_enable[2] ? adpcmBt_r : 16'd0;
wire [13:0] op_result_hdt;
assign op_result_hd = snd_enable[0] ? op_result_hdt : 14'd0;
assign debug_view = { 4'd0, flag_B, flag_A, div_setting };
generate
if( use_adpcm==1 ) begin: gen_adpcm
wire rst_n;
@@ -213,20 +226,20 @@ if( use_adpcm==1 ) begin: gen_adpcm
.pcm55_l ( adpcmAt_l ),
.pcm55_r ( adpcmAt_r ),
.ch_enable ( ch_enable )
.ch_enable ( ch_enable )
);
/* verilator tracing_on */
jt10_adpcm_drvB u_adpcm_b(
.rst_n ( rst_n ),
.clk ( clk ),
.cen ( cen ),
.cen55 ( clk_en_55 ),
// Control
.acmd_on_b ( acmd_on_b ), // Control - Process start, Key On
.acmd_rep_b ( acmd_rep_b ), // Control - Repeat
.acmd_rst_b ( acmd_rst_b ), // Control - Reset
.acmd_up_b ( acmd_up_b ), // Control - New command received
.acmd_up_b ( acmd_up_b ), // Control - New command received
.alr_b ( alr_b ), // Left / Right
.astart_b ( astart_b ), // Start address
.aend_b ( aend_b ), // End address
@@ -244,8 +257,7 @@ if( use_adpcm==1 ) begin: gen_adpcm
.pcm55_r ( adpcmBt_r )
);
/* verilator tracing_on */
assign snd_sample = zero;
assign snd_sample = zero;
jt10_acc u_acc(
.clk ( clk ),
.clk_en ( clk_en ),
@@ -277,10 +289,11 @@ end else begin : gen_adpcm_no
assign adpcma_roe_n = 'b1;
assign adpcmb_addr = 'd0;
assign adpcmb_roe_n = 'd1;
assign adpcma_flags = 0;
assign adpcmb_flag = 0;
end
endgenerate
/* verilator tracing_off */
jt12_dout #(.use_ssg(use_ssg),.use_adpcm(use_adpcm)) u_dout(
// .rst_n ( rst_n ),
.clk ( clk ), // CPU clock
@@ -294,9 +307,7 @@ jt12_dout #(.use_ssg(use_ssg),.use_adpcm(use_adpcm)) u_dout(
.dout ( dout )
);
/* verilator tracing_off */
jt12_mmr #(.use_ssg(use_ssg),.num_ch(num_ch),.use_pcm(use_pcm), .use_adpcm(use_adpcm), .use_clkdiv(use_clkdiv))
jt12_mmr #(.use_ssg(use_ssg),.num_ch(num_ch),.use_pcm(use_pcm), .use_adpcm(use_adpcm), .mask_div(mask_div))
u_mmr(
.rst ( rst ),
.clk ( clk ),
@@ -352,7 +363,7 @@ jt12_mmr #(.use_ssg(use_ssg),.num_ch(num_ch),.use_pcm(use_pcm), .use_adpcm(use_a
.astart_b ( astart_b ), // Start address
.aend_b ( aend_b ), // End address
.adeltan_b ( adeltan_b ), // Delta-N
.aeg_b ( aeg_b ), // Envelope Generator Control
.aeg_b ( aeg_b ), // Envelope Generator Control
.flag_ctl ( flag_ctl ),
.flag_mask ( flag_mask ),
// Operator
@@ -399,17 +410,19 @@ jt12_mmr #(.use_ssg(use_ssg),.num_ch(num_ch),.use_pcm(use_pcm), .use_adpcm(use_a
// PSG interace
.psg_addr ( psg_addr ),
.psg_data ( psg_data ),
.psg_wr_n ( psg_wr_n )
.psg_wr_n ( psg_wr_n ),
.debug_bus ( debug_bus ),
.div_setting(div_setting)
);
/* verilator tracing_off */
// YM2203 seems to use a fixed cen/3 clock for the timers, regardless
// YM2203 seems to use a fixed cen/3 clock for the timers, regardless
// of the prescaler setting
wire timer_cen = num_ch==3 ? clk_en_2 : ( fast_timers ? cen : clk_en);
jt12_timers u_timers(
wire timer_cen = fast_timers ? cen : clk_en;
jt12_timers #(.num_ch(num_ch)) u_timers (
.clk ( clk ),
.clk_en ( timer_cen ),
.rst ( rst ),
.zero ( zero ),
.value_A ( value_A ),
.value_B ( value_B ),
.load_A ( load_A ),
@@ -451,7 +464,7 @@ endgenerate
`ifndef NOSSG
generate
if( use_ssg==1 ) begin : gen_ssg
jt49 #(.COMP(2'b01), .CLKDIV(JT49_DIV))
jt49 #(.COMP(3'b01), .CLKDIV(JT49_DIV), .YM2203_LUMPED(YM2203_LUMPED))
u_psg( // note that input ports are not multiplexed
.rst_n ( ~rst ),
.clk ( clk ), // signal on positive edge
@@ -466,13 +479,16 @@ generate
.C ( psg_C ),
.dout ( psg_dout ),
.sel ( 1'b1 ), // half clock speed
.IOA_out ( IOA_out ),
.IOB_out ( IOB_out ),
.IOA_in ( IOA_in ),
.IOB_in ( IOB_in ),
.IOA_oe ( IOA_oe ),
.IOB_oe ( IOB_oe ),
// Unused:
.IOA_out (),
.IOB_out (),
.IOA_in (8'd0),
.IOB_in (8'd0)
.sample ( )
);
assign snd_left = snd_enable[3] ? fm_snd_left + { 1'b0, psg_snd[9:0],5'd0} : fm_snd_left;
assign snd_left = snd_enable[3] ? fm_snd_left + { 1'b0, psg_snd[9:0],5'd0} : fm_snd_left;
assign snd_right = snd_enable[3] ? fm_snd_right + { 1'b0, psg_snd[9:0],5'd0} : fm_snd_right;
end else begin : gen_nossg
assign psg_snd = 10'd0;
@@ -482,6 +498,10 @@ generate
assign psg_A = 8'd0;
assign psg_B = 8'd0;
assign psg_C = 8'd0;
assign IOA_oe = 0;
assign IOB_oe = 0;
assign IOA_out = 0;
assign IOB_out = 0;
end
endgenerate
`else
@@ -494,7 +514,7 @@ endgenerate
wire [ 8:0] op_result;
wire [13:0] op_result_hd;
`ifndef NOFM
/* verilator tracing_off */
jt12_pg #(.num_ch(num_ch)) u_pg(
.rst ( rst ),
.clk ( clk ),
@@ -575,15 +595,13 @@ jt12_op #(.num_ch(num_ch)) u_op(
.yuse_prev2 ( yuse_prev2 ),
.zero ( zero ),
.op_result ( op_result ),
.full_result ( op_result_hdt )
.full_result ( op_result_hdt )
);
`else
`else
assign op_result = 'd0;
assign op_result_hd = 'd0;
assign op_result_hdt = 'd0;
`endif
/* verilator tracing_on */
generate
if( use_pcm==1 ) begin: gen_pcm_acc // YM2612 accumulator
assign fm_snd_right[3:0] = 4'd0;
@@ -617,8 +635,8 @@ generate
wire signed [10:0] pcm_full;
always @(*)
pcm2 = en_hifi_pcm ? pcm_full[9:1] : pcm;
jt12_pcm_interpol #(.dw(11), .stepw(5)) u_pcm (
jt12_pcm_interpol #(.DW(11), .stepw(5)) u_pcm (
.rst_n ( rst_pcm_n ),
.clk ( clk ),
.cen ( clk_en ),
@@ -676,4 +694,15 @@ generate
);
end
endgenerate
`ifdef SIMULATION
integer fsnd;
initial begin
fsnd=$fopen("jt12.raw","wb");
end
always @(posedge zero) begin
$fwrite(fsnd,"%u", {snd_left, snd_right});
end
`endif
endmodule

View File

@@ -43,10 +43,19 @@ module jt12_fm_uprate(
);
wire signed [15:0] fm2,fm3,fm4;
reg signed [15:0] mix_sum, mixed, fmin, psgin;
reg ov;
reg [15:0] mixed;
always @(posedge clk)
mixed <= (fm_en?fm_snd:16'd0) + {{1{psg_snd[11]}},psg_snd,3'b0};
always @* begin
fmin = fm_en?fm_snd:16'd0;
psgin = {{1{psg_snd[11]}},psg_snd,3'b0};
mix_sum = fmin + psgin;
ov = &{fmin[15],psgin[15],~mix_sum[15]} | &{~fmin[15],~psgin[15],mix_sum[15]};
end
always @(posedge clk) begin
mixed <= ov ? {fmin[15],{15{~fmin[15]}}} : mix_sum;
end
// 1008 --> 252 x4
jt12_interpol #(.calcw(17),.inw(16),.rate(4),.m(1),.n(1))

View File

@@ -75,7 +75,7 @@ always @(posedge clk)
end
reg psg_cen_1008, psg_cen_240, psg_cen_48, psg_cen_144;
always @(negedge clk) begin
always @(posedge clk) begin
psg_cen_240 <= psgcnt48 ==6'd47 && psgcnt240 == 3'd0;
psg_cen_48 <= psgcnt48 ==6'd47;
psg_cen_144 <= psgcnt48 ==6'd47 && psgcnt144==2'd0;
@@ -144,7 +144,7 @@ always @(posedge clk)
end
// evenly spaced clock enable signals
reg cen_1008, cen_252, cen_63, cen_9;
always @(negedge clk) begin
always @(posedge clk) begin
cen_9 <= clkcnt9 ==4'd8;
cen_63 <= clkcnt9 ==4'd8 && clkcnt63 ==3'd0;
cen_252 <= clkcnt9 ==4'd8 && clkcnt63 ==3'd0 && clkcnt252 ==2'd0;

View File

@@ -81,4 +81,4 @@ always @(posedge clk) if(cen) begin
mixed <= limited[wout-1:0];
end
endmodule // jt12_mixer
endmodule // jt12_mixer

View File

@@ -1,40 +1,36 @@
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt03.v ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) jt12.vhd ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_top.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt03_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_single_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_cnt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_comb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_step.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_pure.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_final.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_ctrl.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_exprom.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_kon.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_lfo.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_mmr.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_div.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_mod.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_op.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_csr.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_inc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_dt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_sum.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_comb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pm.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_logsin.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_reg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sh.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sh_rst.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sh24.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sumch.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_timers.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_dout.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../jt49/hdl/jt49.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../jt49/hdl/jt49_div.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../jt49/hdl/jt49_eg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../jt49/hdl/jt49_exp.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../jt49/hdl/jt49_noise.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../jt49/hdl/jt49_cen.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt03.v ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) ../../hdl/jt12.vhd ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_top.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt03_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_single_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_cnt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_comb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_step.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_pure.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_final.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_ctrl.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_exprom.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_kon.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_lfo.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_mmr.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_div.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_mod.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_op.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_csr.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg_inc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg_dt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg_sum.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg_comb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pm.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_logsin.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_reg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_reg_ch.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_sh.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_sh_rst.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_sh24.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_sumch.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_timers.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_dout.v ]
set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) ../../jt49/syn/quartus/jt49.qip ]

View File

@@ -1,33 +1,33 @@
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt03.v ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) jt12.vhd ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_top.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt03_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_single_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_cnt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_comb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_step.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_pure.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_final.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_ctrl.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_exprom.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_kon.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_lfo.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_mmr.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_div.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_mod.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_op.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_csr.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_inc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_dt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_sum.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_comb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pm.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_logsin.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_reg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sh.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sh_rst.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sh24.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sumch.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_timers.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt03.v ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) ../../hdl/jt12.vhd ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_top.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt03_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_single_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_cnt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_comb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_step.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_pure.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_final.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_ctrl.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_exprom.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_kon.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_lfo.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_mmr.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_div.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_mod.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_op.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_csr.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg_inc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg_dt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg_sum.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg_comb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pm.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_logsin.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_reg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_sh.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_sh_rst.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_sh24.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_sumch.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_timers.v ]

View File

@@ -1,56 +1,57 @@
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt10.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_rst.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_mmr.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_top.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_single_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_cnt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_comb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_step.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_pure.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_final.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_ctrl.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_exprom.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_kon.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_lfo.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_div.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_mod.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_op.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_csr.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_inc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_dt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_sum.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_comb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pm.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_logsin.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_reg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sh.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sh_rst.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sh24.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sumch.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_timers.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pcm.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) mixer/jt12_genmix.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) mixer/jt12_decim.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_fm_uprate.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_dout.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt10.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_rst.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_mmr.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_top.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_single_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_cnt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_comb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_step.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_pure.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_final.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_ctrl.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_exprom.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_kon.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_lfo.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_div.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_mod.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_op.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_csr.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg_inc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg_dt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg_sum.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg_comb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pm.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_logsin.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_reg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_reg_ch.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_sh.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_sh_rst.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_sh24.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_sumch.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_timers.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pcm.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/mixer/jt12_genmix.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/mixer/jt12_decim.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/mixer/jt12_interpol.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/mixer/jt12_comb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/mixer/jt12_fm_uprate.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_dout.v ]
# ADPCM
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) adpcm/jt10_adpcm.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) adpcm/jt10_adpcm_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) adpcm/jt10_adpcma_lut.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) adpcm/jt10_adpcmb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) adpcm/jt10_adpcmb_cnt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) adpcm/jt10_adpcmb_gain.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) adpcm/jt10_adpcm_cnt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) adpcm/jt10_adpcm_dbrom.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) adpcm/jt10_adpcm_drvA.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) adpcm/jt10_adpcm_drvB.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) adpcm/jt10_adpcm_gain.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) adpcm/jt10_cen_burst.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) adpcm/jt10_adpcm_div.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) adpcm/jt10_adpcmb_interpol.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt10_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/adpcm/jt10_adpcm.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/adpcm/jt10_adpcm_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/adpcm/jt10_adpcma_lut.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/adpcm/jt10_adpcmb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/adpcm/jt10_adpcmb_cnt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/adpcm/jt10_adpcmb_gain.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/adpcm/jt10_adpcm_cnt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/adpcm/jt10_adpcm_dbrom.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/adpcm/jt10_adpcm_drvA.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/adpcm/jt10_adpcm_drvB.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/adpcm/jt10_adpcm_gain.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/adpcm/jt10_cen_burst.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/adpcm/jt10_adpcm_div.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/adpcm/jt10_adpcmb_interpol.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt10_acc.v ]

View File

@@ -1,42 +1,42 @@
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) jt12.vhd ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_top.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_single_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_cnt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_comb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_step.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_pure.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_final.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg_ctrl.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_exprom.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_kon.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_lfo.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_div.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_mod.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_op.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_csr.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_inc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_dt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_sum.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg_comb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pm.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_logsin.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_reg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sh.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sh_rst.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sh24.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sumch.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_timers.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pcm_interpol.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_mmr.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_dout.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_rst.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) adpcm/jt10_adpcm_div.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) mixer/jt12_genmix.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) mixer/jt12_decim.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_fm_uprate.v ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) ../../hdl/jt12.vhd ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_top.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_single_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_cnt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_comb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_step.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_pure.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_final.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_eg_ctrl.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_exprom.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_kon.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_lfo.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_div.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_mod.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_op.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_csr.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg_inc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg_dt.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg_sum.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pg_comb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pm.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_logsin.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_reg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_sh.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_sh_rst.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_sh24.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_sumch.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_timers.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_pcm_interpol.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_mmr.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_dout.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt12_rst.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/adpcm/jt10_adpcm_div.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/mixer/jt12_genmix.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/mixer/jt12_decim.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/mixer/jt12_interpol.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/mixer/jt12_comb.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/mixer/jt12_fm_uprate.v ]

View File

@@ -1,12 +1,33 @@
# JT49 FPGA Clone of YM2149 hardware by Jose Tejada (@topapate)
You can show your appreciation through
* [Patreon](https://patreon.com/topapate), by supporting releases
* [Paypal](https://paypal.me/topapate), with a donation
* [Patreon](https://patreon.com/jotego), by supporting open source retro releases
YM2149 compatible Verilog core, with emphasis on FPGA implementation as part of JT12 in order to recreate the YM2203 part.
## Documentation
- [AY-3-8910 Data Manual](https://archive.org/details/AY-3-8910-8912_Feb-1979/page/n51/mode/2up)
- [AY-3-8919 Reverse Engineered](https://github.com/lvd2/ay-3-8910_reverse_engineered)
- [YM2149](https://archive.org/details/bitsavers_yamahaYM21_3070829)
## Using JT49 in a git project
If you are using JT49 in a git project, the best way to add it to your project is:
1. Optionally fork JT49's repository to your own GitHub account
2. Add it as a submodule to your git project: `git submodule add https://github.com/jotego/jt49.git`
3. Now you can refer to the RTL files in **jt49/hdl**
The advantages of a using a git submodule are:
1. Your project contains a reference to a commit of the JT49 repository
2. As long as you do not manually update the JT49 submodule, it will keep pointing to the same commit
3. Each time you make a commit in your project, it will include a pointer to the JT49 commit used. So you will always know the JT49 that worked for you
4. If JT49 is updated and you want to get the changes, simply update the submodule using git. The new JT49 commit used will be annotated in your project's next commit. So the history of your project will reflect that change too.
5. JT49 files will be intact and you will use the files without altering them.
## Usage
There are two top level files you can use:
@@ -15,6 +36,13 @@ There are two top level files you can use:
clk_en cannot be set to 1 for correct operation. The design assumes that there will be at least one empty clock cycle between every two clk_en high clock cycles.
## Files for Simulation and Synthesis
When used inside a [JTFRAME](https://github.com/jotego/jtframe) project, you can use the [yaml](hdl/jt49.yaml) file provided. If you are using this repository on its own, there is a [qip](syn/quartus/jt49.qip) for Intel Quartus available.
It is recommended to use this repository as a [git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) in your project.
## Port Description jt49
Name | Direction | Width | Purpose
@@ -69,16 +97,35 @@ envelope period | Yes | Tested 0 and FFF values
## Resistor Load Modelling
The resistor load had an effect of gain compression on the chip. There is a parameter called **COMP** which can be used to model this effect. You can assign a value from 0 to 3.
The YM2149 was used to measure the output circuitry. According to AY-3-8910 schematics, there are 16 NMOS devices for each channel. Depending on the amplitude settings, only one of them will be active. These numbers render values that agree with the datasheet and measurements:
Value | Dynamic Range | Equivalent resistor
------|---------------|--------------------
0 | 43.6 dB | <1000 Ohm
1 | 29.1 dB | ~8000 Ohm
2 | 21.8 dB | ~40 kOhm (?)
3 | 13.4 dB | ~99 kOhm
- Rload = 1 kOhm
- Smallest Ron = 900 Ohm (for level=15)
- Largest Roff = 3 MOhm (for level=0)
- Scale factor from one MOS to the next = 1.55
Each output level is the combination of one MOS being on and the rest off, so they combine into a single impedance, which then forms a resistor divider with the load.
The output MOS will hold its impedance even if an extra 1V is added at the load resistor (reducing the MOS headroom)
## Non Linear Effects
- Saturation effects are not modelled
- Channel mixing effects by short circuiting the outputs are not modelled
- Channel mixing effects by short circuiting the outputs in AY-3-8910 are not modelled
- Non linearity in YM2203 when shorting all outputs is modeled via parameter YM2203_LUMPED
Non linear effects depend on the way the chip is connected and its model. See [the connection list](doc/conn.md).
## Related Projects
Other sound chips from the same author
Chip | Repository
-----------------------|------------
YM2203, YM2612, YM2610 | [JT12](https://github.com/jotego/jt12)
YM2151 | [JT51](https://github.com/jotego/jt51)
YM3526 | [JTOPL](https://github.com/jotego/jtopl)
YM2149 | [JT49](https://github.com/jotego/jt49)
sn76489an | [JT89](https://github.com/jotego/jt89)
OKI 6295 | [JT6295](https://github.com/jotego/jt6295)
OKI MSM5205 | [JT5205](https://github.com/jotego/jt5205)
NEC uPN7759 | [JT7759](https://github.com/jotego/jt7759)

View File

@@ -22,7 +22,7 @@
// DC removal filter
// input is unsigned
// output is signed
/* verilator tracing_off */
module jt49_dcrm(
input clk,
input cen,

View File

@@ -31,20 +31,20 @@ module jt49_dcrm2 #(parameter sw=8) (
output signed [sw-1:0] dout
);
localparam dw=10; // width of the decimal portion
localparam DW=10; // width of the decimal portion
reg signed [sw+dw:0] integ, exact, error;
//reg signed [2*(9+dw)-1:0] mult;
// wire signed [sw+dw:0] plus1 = { {sw+dw{1'b0}},1'b1};
reg signed [sw+DW:0] integ, exact, error;
//reg signed [2*(9+DW)-1:0] mult;
// wire signed [sw+DW:0] plus1 = { {sw+DW{1'b0}},1'b1};
reg signed [sw:0] pre_dout;
// reg signed [sw+dw:0] dout_ext;
// reg signed [sw+DW:0] dout_ext;
reg signed [sw:0] q;
always @(*) begin
exact = integ+error;
q = exact[sw+dw:dw];
q = exact[sw+DW:DW];
pre_dout = { 1'b0, din } - q;
//dout_ext = { pre_dout, {dw{1'b0}} };
//dout_ext = { pre_dout, {DW{1'b0}} };
//mult = dout_ext;
end
@@ -52,13 +52,13 @@ assign dout = pre_dout[sw-1:0];
always @(posedge clk)
if( rst ) begin
integ <= {sw+dw+1{1'b0}};
error <= {sw+dw+1{1'b0}};
integ <= {sw+DW+1{1'b0}};
error <= {sw+DW+1{1'b0}};
end else if( cen ) begin
/* verilator lint_off WIDTH */
integ <= integ + pre_dout; //mult[sw+dw*2:dw];
integ <= integ + pre_dout; //mult[sw+DW*2:DW];
/* verilator lint_on WIDTH */
error <= exact-{q, {dw{1'b0}}};
error <= exact-{q, {DW{1'b0}}};
end
endmodule

View File

@@ -22,7 +22,7 @@
// Delay stage
// use for long delays
module jt49_dly #(parameter dw=8, depth=10)(
module jt49_dly #(parameter DW=8, depth=10)(
input clk,
input cen,
input rst,
@@ -36,10 +36,10 @@ reg [depth-1:0] rdpos, wrpos;
// memory
reg [dw-1:0] ram[0:2**depth-1];
reg [DW-1:0] ram[0:2**depth-1];
always @(posedge clk)
if(rst)
pre_dout <= {dw{1'b0}};
pre_dout <= {DW{1'b0}};
else begin
pre_dout <= ram[rdpos];
if( cen ) ram[wrpos] <= din;
@@ -57,7 +57,7 @@ always @(posedge clk)
if( rst ) begin
rdpos <= { {depth-1{1'b0}}, 1'b1};
wrpos <= {depth{1'b1}};
dout <= {dw{1'b0}};
dout <= {DW{1'b0}};
end else if(cen) begin
dout <= pre_dout;
rdpos <= rdpos+1'b1;

View File

@@ -21,18 +21,18 @@
// Moving averager
module jt49_mave #(parameter depth=8, dw=8)(
module jt49_mave #(parameter depth=8, DW=8)(
input clk,
input cen,
input rst,
input signed [dw-1:0] din,
output signed [dw-1:0] dout
input signed [DW-1:0] din,
output signed [DW-1:0] dout
);
wire [dw-1:0] dly0;
wire [dw-1:0] pre_dly0;
wire [DW-1:0] dly0;
wire [DW-1:0] pre_dly0;
jt49_dly #(.depth(depth),.dw(dw)) u_dly0(
jt49_dly #(.depth(depth),.DW(DW)) u_dly0(
.clk ( clk ),
.cen ( cen ),
.rst ( rst ),
@@ -43,18 +43,18 @@ jt49_dly #(.depth(depth),.dw(dw)) u_dly0(
// moving average
// D=2048
reg signed [dw:0] diff;
reg signed [dw+depth-1:0] sum;
reg signed [DW:0] diff;
reg signed [DW+depth-1:0] sum;
always @(posedge clk)
if( rst ) begin
diff <= {dw+1{1'd0}};
sum <= {dw+depth+1{1'd0}};
diff <= {DW+1{1'd0}};
sum <= {DW+depth+1{1'd0}};
end else if(cen) begin
diff <= {1'b0,din } - { 1'b0, dly0 };
sum <= { {depth{diff[dw]}}, diff } + sum;
sum <= { {depth{diff[DW]}}, diff } + sum;
end
assign dout = sum[dw+depth-1:depth];
assign dout = sum[DW+depth-1:depth];
endmodule

View File

@@ -35,22 +35,24 @@ module jt49 ( // note that input ports are not multiplexed
output reg [7:0] A, // linearised channel output
output reg [7:0] B,
output reg [7:0] C,
output sample,
input [7:0] IOA_in,
output [7:0] IOA_out,
output IOA_oe,
input [7:0] IOB_in,
output [7:0] IOB_out
output [7:0] IOB_out,
output IOB_oe
);
parameter [1:0] COMP=2'b00;
parameter [2:0] COMP=3'b000;
parameter YM2203_LUMPED=0;
parameter CLKDIV=3;
wire [1:0] comp = COMP;
wire [2:0] comp = COMP;
reg [7:0] regarray[15:0];
assign IOA_out = regarray[14];
assign IOB_out = regarray[15];
reg [7:0] regarray[15:0];
wire [7:0] port_A, port_B;
wire [4:0] envelope;
wire bitA, bitB, bitC;
@@ -59,6 +61,14 @@ reg Amix, Bmix, Cmix;
wire cen16, cen256;
assign IOA_out = regarray[14];
assign IOB_out = regarray[15];
assign port_A = IOA_in;
assign port_B = IOB_in;
assign IOA_oe = regarray[7][6];
assign IOB_oe = regarray[7][7];
assign sample = cen16;
jt49_cen #(.CLKDIV(CLKDIV)) u_cen(
.clk ( clk ),
.rst_n ( rst_n ),
@@ -159,7 +169,10 @@ always @(posedge clk) if( clk_en ) begin
logC <= !Cmix ? 5'd0 : (use_envC ? envelope : volC );
end
reg [9:0] acc;
reg [9:0] acc;
wire [9:0] elin;
assign elin = {2'd0,lin};
always @(posedge clk, negedge rst_n) begin
if( !rst_n ) begin
@@ -171,7 +184,9 @@ always @(posedge clk, negedge rst_n) begin
sound <= 10'd0;
end else if(clk_en) begin
acc_st <= { acc_st[2:0], acc_st[3] };
acc <= acc + {2'b0,lin};
// Lumping the channel outputs for YM2203 will cause only the higher
// voltage to pass throuh, as the outputs seem to use a source follower.
acc <= YM2203_LUMPED==1 ? (acc>elin ? acc : elin) : acc + elin;
case( acc_st )
4'b0001: begin
log <= logA;
@@ -194,7 +209,7 @@ always @(posedge clk, negedge rst_n) begin
end
end
reg [7:0] read_mask;
reg [7:0] read_mask;
always @(*)
case(addr)
@@ -226,8 +241,8 @@ always @(posedge clk, negedge rst_n) begin
last_write <= write;
// Data read
case( addr )
4'he: dout <= !regarray[7][6] ? IOA_in : 8'hff;
4'hf: dout <= !regarray[7][7] ? IOB_in : 8'hff;
4'he: dout <= port_A;
4'hf: dout <= port_B;
default: dout <= regarray[ addr ] & read_mask;
endcase
// Data write

8
rtl/jt49/hdl/jt49.yaml Normal file
View File

@@ -0,0 +1,8 @@
here:
- jt49.v
- jt49_bus.v
- jt49_div.v
- jt49_cen.v
- jt49_eg.v
- jt49_exp.v
- jt49_noise.v

View File

@@ -12,16 +12,16 @@
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
// This is a wrapper with the BDIR/BC1 pins
module jt49_bus ( // note that input ports are not multiplexed
input rst_n,
@@ -38,22 +38,25 @@ module jt49_bus ( // note that input ports are not multiplexed
output [7:0] A, // linearised channel output
output [7:0] B,
output [7:0] C,
output sample,
input [7:0] IOA_in,
output [7:0] IOA_out,
output IOA_oe,
input [7:0] IOB_in,
output [7:0] IOB_out
output [7:0] IOB_out,
output IOB_oe
);
parameter [1:0] COMP=2'b00;
parameter [2:0] COMP=3'b000;
reg wr_n, cs_n;
reg [3:0] addr;
reg addr_ok;
reg [7:0] din_latch;
always @(posedge clk)
always @(posedge clk)
if( !rst_n ) begin
wr_n <= 1'b1;
cs_n <= 1'b1;
@@ -87,13 +90,16 @@ jt49 #(.COMP(COMP)) u_jt49( // note that input ports are not multiplexed
.sel ( sel ), // if sel is low, the clock is divided by 2
.dout ( dout ),
.sound ( sound ), // combined channel output
.sample ( sample ),
.A ( A ), // linearised channel output
.B ( B ),
.C ( C ),
.IOA_in ( IOA_in ),
.IOA_out( IOA_out ),
.IOA_oe ( IOA_oe ),
.IOB_in ( IOB_in ),
.IOB_out( IOB_out )
.IOB_out( IOB_out ),
.IOB_oe ( IOB_oe )
);
endmodule // jt49_bus

View File

@@ -21,10 +21,6 @@
*/
// altera message_off 10030
`timescale 1ns / 1ps
// Compression vs dynamic range
// 0 -> 43.6dB
// 1 -> 29.1
@@ -33,12 +29,12 @@
module jt49_exp(
input clk,
input [1:0] comp, // compression
input [2:0] comp, // compression
input [4:0] din,
output reg [7:0] dout
);
reg [7:0] lut[0:127];
reg [7:0] lut[0:159];
always @(posedge clk)
dout <= lut[ {comp,din} ];
@@ -172,6 +168,38 @@ initial begin
lut[125] = 8'd229;
lut[126] = 8'd241;
lut[127] = 8'd255;
lut[128] = 8'd0;
lut[129] = 8'd8;
lut[130] = 8'd10;
lut[131] = 8'd12;
lut[132] = 8'd16;
lut[133] = 8'd22;
lut[134] = 8'd29;
lut[135] = 8'd35;
lut[136] = 8'd44;
lut[137] = 8'd50;
lut[138] = 8'd56;
lut[139] = 8'd60;
lut[140] = 8'd64;
lut[141] = 8'd85;
lut[142] = 8'd97;
lut[143] = 8'd103;
lut[144] = 8'd108;
lut[145] = 8'd120;
lut[146] = 8'd127;
lut[147] = 8'd134;
lut[148] = 8'd141;
lut[149] = 8'd149;
lut[150] = 8'd157;
lut[151] = 8'd166;
lut[152] = 8'd175;
lut[153] = 8'd185;
lut[154] = 8'd195;
lut[155] = 8'd206;
lut[156] = 8'd217;
lut[157] = 8'd229;
lut[158] = 8'd241;
lut[159] = 8'd255;
end
endmodule

View File

@@ -21,7 +21,6 @@
*/
`timescale 1ns / 1ps
module jt49_noise(
(* direct_enable *) input cen,

View File

@@ -1,7 +1,7 @@
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_div.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_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 ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt49.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt49_bus.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt49_div.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt49_cen.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt49_eg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt49_exp.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ../../hdl/jt49_noise.v ]