From e64964ce9f021e2b17d93dae8cfef663e138522d Mon Sep 17 00:00:00 2001 From: Gyorgy Szombathelyi Date: Thu, 30 Dec 2021 03:04:03 +0100 Subject: [PATCH] Konami Iron Horse --- Arcade_MiST/Konami Iron Horse/IronHors.qpf | 31 + Arcade_MiST/Konami Iron Horse/IronHors.qsf | 257 +++++ Arcade_MiST/Konami Iron Horse/IronHors.sdc | 134 +++ Arcade_MiST/Konami Iron Horse/README.md | 11 + .../meta/Iron Horse (Ver. K).mra | 84 ++ .../Konami Iron Horse/rtl/IronHorse.sv | 627 +++++++++++ .../Konami Iron Horse/rtl/IronHorse_MiST.sv | 323 ++++++ .../Konami Iron Horse/rtl/audio_iir_filter.v | 173 +++ .../Konami Iron Horse/rtl/build_id.tcl | 35 + .../Konami Iron Horse/rtl/dpram_dc.vhd | 136 +++ .../Konami Iron Horse/rtl/ironhorse_fm_lpf.sv | 60 ++ .../rtl/ironhorse_ssg_lpf.sv | 61 ++ .../Konami Iron Horse/rtl/jt49_dcrm2.v | 62 ++ .../Konami Iron Horse/rtl/jtframe_frac_cen.v | 58 + Arcade_MiST/Konami Iron Horse/rtl/k005885.sv | 992 ++++++++++++++++++ Arcade_MiST/Konami Iron Horse/rtl/pll.qip | 4 + Arcade_MiST/Konami Iron Horse/rtl/pll.v | 348 ++++++ .../Konami Iron Horse/rtl/rom_loader.sv | 366 +++++++ Arcade_MiST/Konami Iron Horse/rtl/sdram.sv | 363 +++++++ Arcade_MiST/Konami Iron Horse/rtl/spram.vhd | 46 + common/CPU/MC6809/mc6809is.v | 10 +- common/Sound/JT12/LICENSE | 674 ++++++++++++ common/Sound/JT12/README.md | 43 + common/Sound/JT12/hdl/adpcm/gen_lingain.py | 14 + common/Sound/JT12/hdl/adpcm/jt10_adpcm.v | 132 +++ common/Sound/JT12/hdl/adpcm/jt10_adpcm_acc.v | 90 ++ common/Sound/JT12/hdl/adpcm/jt10_adpcm_cnt.v | 181 ++++ common/Sound/JT12/hdl/adpcm/jt10_adpcm_comb.v | 134 +++ .../Sound/JT12/hdl/adpcm/jt10_adpcm_dbrom.v | 54 + common/Sound/JT12/hdl/adpcm/jt10_adpcm_div.v | 62 ++ common/Sound/JT12/hdl/adpcm/jt10_adpcm_drvA.v | 335 ++++++ common/Sound/JT12/hdl/adpcm/jt10_adpcm_drvB.v | 124 +++ common/Sound/JT12/hdl/adpcm/jt10_adpcm_dt.v | 130 +++ common/Sound/JT12/hdl/adpcm/jt10_adpcm_gain.v | 176 ++++ common/Sound/JT12/hdl/adpcm/jt10_adpcma_lut.v | 142 +++ common/Sound/JT12/hdl/adpcm/jt10_adpcmb.v | 112 ++ common/Sound/JT12/hdl/adpcm/jt10_adpcmb_cnt.v | 108 ++ .../Sound/JT12/hdl/adpcm/jt10_adpcmb_gain.v | 39 + .../JT12/hdl/adpcm/jt10_adpcmb_interpol.v | 96 ++ common/Sound/JT12/hdl/adpcm/jt10_cen_burst.v | 59 ++ common/Sound/JT12/hdl/alt/eg_cnt.v | 84 ++ common/Sound/JT12/hdl/alt/eg_comb.v | 184 ++++ common/Sound/JT12/hdl/alt/eg_mux.v | 79 ++ common/Sound/JT12/hdl/alt/eg_step.v | 46 + common/Sound/JT12/hdl/alt/eg_step_ram.v | 45 + common/Sound/JT12/hdl/dac/jt12_dac.v | 56 + common/Sound/JT12/hdl/dac/jt12_dac2.v | 63 ++ common/Sound/JT12/hdl/deprecated/jt12_amp.v | 172 +++ common/Sound/JT12/hdl/deprecated/jt12_mod24.v | 14 + common/Sound/JT12/hdl/deprecated/jt12_mod6.v | 52 + common/Sound/JT12/hdl/deprecated/jt12_opram.v | 45 + common/Sound/JT12/hdl/jt03.qip | 35 + common/Sound/JT12/hdl/jt03.v | 97 ++ common/Sound/JT12/hdl/jt03_acc.v | 73 ++ common/Sound/JT12/hdl/jt03_fm.qip | 33 + common/Sound/JT12/hdl/jt10.qip | 63 ++ common/Sound/JT12/hdl/jt10.v | 97 ++ common/Sound/JT12/hdl/jt10_acc.v | 173 +++ common/Sound/JT12/hdl/jt12.qip | 42 + common/Sound/JT12/hdl/jt12.v | 80 ++ common/Sound/JT12/hdl/jt12.vhd | 44 + common/Sound/JT12/hdl/jt12_acc.v | 107 ++ common/Sound/JT12/hdl/jt12_csr.v | 82 ++ common/Sound/JT12/hdl/jt12_div.v | 141 +++ common/Sound/JT12/hdl/jt12_dout.v | 47 + common/Sound/JT12/hdl/jt12_eg.v | 203 ++++ common/Sound/JT12/hdl/jt12_eg_cnt.v | 50 + common/Sound/JT12/hdl/jt12_eg_comb.v | 139 +++ common/Sound/JT12/hdl/jt12_eg_ctrl.v | 122 +++ common/Sound/JT12/hdl/jt12_eg_final.v | 57 + common/Sound/JT12/hdl/jt12_eg_pure.v | 81 ++ common/Sound/JT12/hdl/jt12_eg_step.v | 111 ++ common/Sound/JT12/hdl/jt12_exprom.v | 302 ++++++ common/Sound/JT12/hdl/jt12_kon.v | 151 +++ common/Sound/JT12/hdl/jt12_lfo.v | 103 ++ common/Sound/JT12/hdl/jt12_logsin.v | 298 ++++++ common/Sound/JT12/hdl/jt12_mmr.v | 511 +++++++++ common/Sound/JT12/hdl/jt12_mmr_sim.vh | 854 +++++++++++++++ common/Sound/JT12/hdl/jt12_mod.v | 153 +++ common/Sound/JT12/hdl/jt12_op.v | 332 ++++++ common/Sound/JT12/hdl/jt12_pcm.v | 109 ++ common/Sound/JT12/hdl/jt12_pcm_interpol.v | 109 ++ common/Sound/JT12/hdl/jt12_pg.v | 114 ++ common/Sound/JT12/hdl/jt12_pg_comb.v | 90 ++ common/Sound/JT12/hdl/jt12_pg_dt.v | 82 ++ common/Sound/JT12/hdl/jt12_pg_inc.v | 50 + common/Sound/JT12/hdl/jt12_pg_sum.v | 49 + common/Sound/JT12/hdl/jt12_pm.v | 186 ++++ common/Sound/JT12/hdl/jt12_reg.v | 372 +++++++ common/Sound/JT12/hdl/jt12_rst.v | 38 + common/Sound/JT12/hdl/jt12_sh.v | 44 + common/Sound/JT12/hdl/jt12_sh24.v | 81 ++ common/Sound/JT12/hdl/jt12_sh_rst.v | 56 + common/Sound/JT12/hdl/jt12_single_acc.v | 63 ++ common/Sound/JT12/hdl/jt12_sumch.v | 47 + common/Sound/JT12/hdl/jt12_timers.v | 141 +++ common/Sound/JT12/hdl/jt12_top.v | 671 ++++++++++++ common/Sound/JT12/hdl/mixer/jt12_comb.v | 59 ++ common/Sound/JT12/hdl/mixer/jt12_decim.v | 90 ++ common/Sound/JT12/hdl/mixer/jt12_fm_uprate.v | 95 ++ common/Sound/JT12/hdl/mixer/jt12_genmix.v | 180 ++++ common/Sound/JT12/hdl/mixer/jt12_interpol.v | 92 ++ common/Sound/JT12/hdl/mixer/jt12_mixer.v | 84 ++ 103 files changed, 15207 insertions(+), 2 deletions(-) create mode 100644 Arcade_MiST/Konami Iron Horse/IronHors.qpf create mode 100644 Arcade_MiST/Konami Iron Horse/IronHors.qsf create mode 100644 Arcade_MiST/Konami Iron Horse/IronHors.sdc create mode 100644 Arcade_MiST/Konami Iron Horse/README.md create mode 100644 Arcade_MiST/Konami Iron Horse/meta/Iron Horse (Ver. K).mra create mode 100644 Arcade_MiST/Konami Iron Horse/rtl/IronHorse.sv create mode 100644 Arcade_MiST/Konami Iron Horse/rtl/IronHorse_MiST.sv create mode 100644 Arcade_MiST/Konami Iron Horse/rtl/audio_iir_filter.v create mode 100644 Arcade_MiST/Konami Iron Horse/rtl/build_id.tcl create mode 100644 Arcade_MiST/Konami Iron Horse/rtl/dpram_dc.vhd create mode 100644 Arcade_MiST/Konami Iron Horse/rtl/ironhorse_fm_lpf.sv create mode 100644 Arcade_MiST/Konami Iron Horse/rtl/ironhorse_ssg_lpf.sv create mode 100644 Arcade_MiST/Konami Iron Horse/rtl/jt49_dcrm2.v create mode 100644 Arcade_MiST/Konami Iron Horse/rtl/jtframe_frac_cen.v create mode 100644 Arcade_MiST/Konami Iron Horse/rtl/k005885.sv create mode 100644 Arcade_MiST/Konami Iron Horse/rtl/pll.qip create mode 100644 Arcade_MiST/Konami Iron Horse/rtl/pll.v create mode 100644 Arcade_MiST/Konami Iron Horse/rtl/rom_loader.sv create mode 100644 Arcade_MiST/Konami Iron Horse/rtl/sdram.sv create mode 100644 Arcade_MiST/Konami Iron Horse/rtl/spram.vhd create mode 100644 common/Sound/JT12/LICENSE create mode 100644 common/Sound/JT12/README.md create mode 100644 common/Sound/JT12/hdl/adpcm/gen_lingain.py create mode 100644 common/Sound/JT12/hdl/adpcm/jt10_adpcm.v create mode 100644 common/Sound/JT12/hdl/adpcm/jt10_adpcm_acc.v create mode 100644 common/Sound/JT12/hdl/adpcm/jt10_adpcm_cnt.v create mode 100644 common/Sound/JT12/hdl/adpcm/jt10_adpcm_comb.v create mode 100644 common/Sound/JT12/hdl/adpcm/jt10_adpcm_dbrom.v create mode 100644 common/Sound/JT12/hdl/adpcm/jt10_adpcm_div.v create mode 100644 common/Sound/JT12/hdl/adpcm/jt10_adpcm_drvA.v create mode 100644 common/Sound/JT12/hdl/adpcm/jt10_adpcm_drvB.v create mode 100644 common/Sound/JT12/hdl/adpcm/jt10_adpcm_dt.v create mode 100644 common/Sound/JT12/hdl/adpcm/jt10_adpcm_gain.v create mode 100644 common/Sound/JT12/hdl/adpcm/jt10_adpcma_lut.v create mode 100644 common/Sound/JT12/hdl/adpcm/jt10_adpcmb.v create mode 100644 common/Sound/JT12/hdl/adpcm/jt10_adpcmb_cnt.v create mode 100644 common/Sound/JT12/hdl/adpcm/jt10_adpcmb_gain.v create mode 100644 common/Sound/JT12/hdl/adpcm/jt10_adpcmb_interpol.v create mode 100644 common/Sound/JT12/hdl/adpcm/jt10_cen_burst.v create mode 100644 common/Sound/JT12/hdl/alt/eg_cnt.v create mode 100644 common/Sound/JT12/hdl/alt/eg_comb.v create mode 100644 common/Sound/JT12/hdl/alt/eg_mux.v create mode 100644 common/Sound/JT12/hdl/alt/eg_step.v create mode 100644 common/Sound/JT12/hdl/alt/eg_step_ram.v create mode 100644 common/Sound/JT12/hdl/dac/jt12_dac.v create mode 100644 common/Sound/JT12/hdl/dac/jt12_dac2.v create mode 100644 common/Sound/JT12/hdl/deprecated/jt12_amp.v create mode 100644 common/Sound/JT12/hdl/deprecated/jt12_mod24.v create mode 100644 common/Sound/JT12/hdl/deprecated/jt12_mod6.v create mode 100644 common/Sound/JT12/hdl/deprecated/jt12_opram.v create mode 100644 common/Sound/JT12/hdl/jt03.qip create mode 100644 common/Sound/JT12/hdl/jt03.v create mode 100644 common/Sound/JT12/hdl/jt03_acc.v create mode 100644 common/Sound/JT12/hdl/jt03_fm.qip create mode 100644 common/Sound/JT12/hdl/jt10.qip create mode 100644 common/Sound/JT12/hdl/jt10.v create mode 100644 common/Sound/JT12/hdl/jt10_acc.v create mode 100644 common/Sound/JT12/hdl/jt12.qip create mode 100644 common/Sound/JT12/hdl/jt12.v create mode 100644 common/Sound/JT12/hdl/jt12.vhd create mode 100644 common/Sound/JT12/hdl/jt12_acc.v create mode 100644 common/Sound/JT12/hdl/jt12_csr.v create mode 100644 common/Sound/JT12/hdl/jt12_div.v create mode 100644 common/Sound/JT12/hdl/jt12_dout.v create mode 100644 common/Sound/JT12/hdl/jt12_eg.v create mode 100644 common/Sound/JT12/hdl/jt12_eg_cnt.v create mode 100644 common/Sound/JT12/hdl/jt12_eg_comb.v create mode 100644 common/Sound/JT12/hdl/jt12_eg_ctrl.v create mode 100644 common/Sound/JT12/hdl/jt12_eg_final.v create mode 100644 common/Sound/JT12/hdl/jt12_eg_pure.v create mode 100644 common/Sound/JT12/hdl/jt12_eg_step.v create mode 100644 common/Sound/JT12/hdl/jt12_exprom.v create mode 100644 common/Sound/JT12/hdl/jt12_kon.v create mode 100644 common/Sound/JT12/hdl/jt12_lfo.v create mode 100644 common/Sound/JT12/hdl/jt12_logsin.v create mode 100644 common/Sound/JT12/hdl/jt12_mmr.v create mode 100644 common/Sound/JT12/hdl/jt12_mmr_sim.vh create mode 100644 common/Sound/JT12/hdl/jt12_mod.v create mode 100644 common/Sound/JT12/hdl/jt12_op.v create mode 100644 common/Sound/JT12/hdl/jt12_pcm.v create mode 100644 common/Sound/JT12/hdl/jt12_pcm_interpol.v create mode 100644 common/Sound/JT12/hdl/jt12_pg.v create mode 100644 common/Sound/JT12/hdl/jt12_pg_comb.v create mode 100644 common/Sound/JT12/hdl/jt12_pg_dt.v create mode 100644 common/Sound/JT12/hdl/jt12_pg_inc.v create mode 100644 common/Sound/JT12/hdl/jt12_pg_sum.v create mode 100644 common/Sound/JT12/hdl/jt12_pm.v create mode 100644 common/Sound/JT12/hdl/jt12_reg.v create mode 100644 common/Sound/JT12/hdl/jt12_rst.v create mode 100644 common/Sound/JT12/hdl/jt12_sh.v create mode 100644 common/Sound/JT12/hdl/jt12_sh24.v create mode 100644 common/Sound/JT12/hdl/jt12_sh_rst.v create mode 100644 common/Sound/JT12/hdl/jt12_single_acc.v create mode 100644 common/Sound/JT12/hdl/jt12_sumch.v create mode 100644 common/Sound/JT12/hdl/jt12_timers.v create mode 100644 common/Sound/JT12/hdl/jt12_top.v create mode 100644 common/Sound/JT12/hdl/mixer/jt12_comb.v create mode 100644 common/Sound/JT12/hdl/mixer/jt12_decim.v create mode 100644 common/Sound/JT12/hdl/mixer/jt12_fm_uprate.v create mode 100644 common/Sound/JT12/hdl/mixer/jt12_genmix.v create mode 100644 common/Sound/JT12/hdl/mixer/jt12_interpol.v create mode 100644 common/Sound/JT12/hdl/mixer/jt12_mixer.v diff --git a/Arcade_MiST/Konami Iron Horse/IronHors.qpf b/Arcade_MiST/Konami Iron Horse/IronHors.qpf new file mode 100644 index 00000000..17e50e86 --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/IronHors.qpf @@ -0,0 +1,31 @@ +# -------------------------------------------------------------------------- # +# +# Copyright (C) 1991-2013 Altera Corporation +# Your use of Altera Corporation's design tools, logic functions +# and other software and tools, and its AMPP partner logic +# functions, and any output files from any of the foregoing +# (including device programming or simulation files), and any +# associated documentation or information are expressly subject +# to the terms and conditions of the Altera Program License +# Subscription Agreement, Altera MegaCore Function License +# Agreement, or other applicable license agreement, including, +# without limitation, that your use is for the sole purpose of +# programming logic devices manufactured by Altera and sold by +# Altera or its authorized distributors. Please refer to the +# applicable agreement for further details. +# +# -------------------------------------------------------------------------- # +# +# Quartus II 64-Bit +# Version 13.1.0 Build 162 10/23/2013 SJ Web Edition +# Date created = 00:21:03 December 03, 2019 +# +# -------------------------------------------------------------------------- # + +QUARTUS_VERSION = "13.1" +DATE = "00:21:03 December 03, 2019" + +# Revisions + +PROJECT_REVISION = "IronHors" + diff --git a/Arcade_MiST/Konami Iron Horse/IronHors.qsf b/Arcade_MiST/Konami Iron Horse/IronHors.qsf new file mode 100644 index 00000000..7fcc10f7 --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/IronHors.qsf @@ -0,0 +1,257 @@ +# -------------------------------------------------------------------------- # +# +# Copyright (C) 1991-2014 Altera Corporation +# Your use of Altera Corporation's design tools, logic functions +# and other software and tools, and its AMPP partner logic +# functions, and any output files from any of the foregoing +# (including device programming or simulation files), and any +# associated documentation or information are expressly subject +# to the terms and conditions of the Altera Program License +# Subscription Agreement, Altera MegaCore Function License +# Agreement, or other applicable license agreement, including, +# without limitation, that your use is for the sole purpose of +# programming logic devices manufactured by Altera and sold by +# Altera or its authorized distributors. Please refer to the +# applicable agreement for further details. +# +# -------------------------------------------------------------------------- # +# +# Quartus II 64-Bit +# Version 13.1.4 Build 182 03/12/2014 SJ Full Version +# Date created = 19:54:12 November 22, 2020 +# +# -------------------------------------------------------------------------- # +# +# Notes: +# +# 1) The default values for assignments are stored in the file: +# IronHors_assignment_defaults.qdf +# If this file doesn't exist, see file: +# assignment_defaults.qdf +# +# 2) Altera recommends that you do not modify this file. This +# file is updated automatically by the Quartus II software +# and any changes you make may be lost or overwritten. +# +# -------------------------------------------------------------------------- # + + + +# Project-Wide Assignments +# ======================== +set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files +set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL +set_global_assignment -name LAST_QUARTUS_VERSION 13.1 +set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:rtl/build_id.tcl" + +# Pin & Location Assignments +# ========================== +set_location_assignment PIN_7 -to LED +set_location_assignment PIN_54 -to CLOCK_27 +set_location_assignment PIN_144 -to VGA_R[5] +set_location_assignment PIN_143 -to VGA_R[4] +set_location_assignment PIN_142 -to VGA_R[3] +set_location_assignment PIN_141 -to VGA_R[2] +set_location_assignment PIN_137 -to VGA_R[1] +set_location_assignment PIN_135 -to VGA_R[0] +set_location_assignment PIN_133 -to VGA_B[5] +set_location_assignment PIN_132 -to VGA_B[4] +set_location_assignment PIN_125 -to VGA_B[3] +set_location_assignment PIN_121 -to VGA_B[2] +set_location_assignment PIN_120 -to VGA_B[1] +set_location_assignment PIN_115 -to VGA_B[0] +set_location_assignment PIN_114 -to VGA_G[5] +set_location_assignment PIN_113 -to VGA_G[4] +set_location_assignment PIN_112 -to VGA_G[3] +set_location_assignment PIN_111 -to VGA_G[2] +set_location_assignment PIN_110 -to VGA_G[1] +set_location_assignment PIN_106 -to VGA_G[0] +set_location_assignment PIN_136 -to VGA_VS +set_location_assignment PIN_119 -to VGA_HS +set_location_assignment PIN_65 -to AUDIO_L +set_location_assignment PIN_80 -to AUDIO_R +set_location_assignment PIN_105 -to SPI_DO +set_location_assignment PIN_88 -to SPI_DI +set_location_assignment PIN_126 -to SPI_SCK +set_location_assignment PIN_127 -to SPI_SS2 +set_location_assignment PIN_91 -to SPI_SS3 +set_location_assignment PIN_13 -to CONF_DATA0 +set_location_assignment PIN_49 -to SDRAM_A[0] +set_location_assignment PIN_44 -to SDRAM_A[1] +set_location_assignment PIN_42 -to SDRAM_A[2] +set_location_assignment PIN_39 -to SDRAM_A[3] +set_location_assignment PIN_4 -to SDRAM_A[4] +set_location_assignment PIN_6 -to SDRAM_A[5] +set_location_assignment PIN_8 -to SDRAM_A[6] +set_location_assignment PIN_10 -to SDRAM_A[7] +set_location_assignment PIN_11 -to SDRAM_A[8] +set_location_assignment PIN_28 -to SDRAM_A[9] +set_location_assignment PIN_50 -to SDRAM_A[10] +set_location_assignment PIN_30 -to SDRAM_A[11] +set_location_assignment PIN_32 -to SDRAM_A[12] +set_location_assignment PIN_83 -to SDRAM_DQ[0] +set_location_assignment PIN_79 -to SDRAM_DQ[1] +set_location_assignment PIN_77 -to SDRAM_DQ[2] +set_location_assignment PIN_76 -to SDRAM_DQ[3] +set_location_assignment PIN_72 -to SDRAM_DQ[4] +set_location_assignment PIN_71 -to SDRAM_DQ[5] +set_location_assignment PIN_69 -to SDRAM_DQ[6] +set_location_assignment PIN_68 -to SDRAM_DQ[7] +set_location_assignment PIN_86 -to SDRAM_DQ[8] +set_location_assignment PIN_87 -to SDRAM_DQ[9] +set_location_assignment PIN_98 -to SDRAM_DQ[10] +set_location_assignment PIN_99 -to SDRAM_DQ[11] +set_location_assignment PIN_100 -to SDRAM_DQ[12] +set_location_assignment PIN_101 -to SDRAM_DQ[13] +set_location_assignment PIN_103 -to SDRAM_DQ[14] +set_location_assignment PIN_104 -to SDRAM_DQ[15] +set_location_assignment PIN_58 -to SDRAM_BA[0] +set_location_assignment PIN_51 -to SDRAM_BA[1] +set_location_assignment PIN_85 -to SDRAM_DQMH +set_location_assignment PIN_67 -to SDRAM_DQML +set_location_assignment PIN_60 -to SDRAM_nRAS +set_location_assignment PIN_64 -to SDRAM_nCAS +set_location_assignment PIN_66 -to SDRAM_nWE +set_location_assignment PIN_59 -to SDRAM_nCS +set_location_assignment PIN_33 -to SDRAM_CKE +set_location_assignment PIN_43 -to SDRAM_CLK +set_location_assignment PLL_1 -to "pll:pll|altpll:altpll_component" + +# Classic Timing Assignments +# ========================== +set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 +set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85 + +# Analysis & Synthesis Assignments +# ================================ +set_global_assignment -name FAMILY "Cyclone III" +set_global_assignment -name TOP_LEVEL_ENTITY IronHorse_MiST +set_global_assignment -name DEVICE_FILTER_PIN_COUNT 144 +set_global_assignment -name DEVICE_FILTER_SPEED_GRADE 8 +set_global_assignment -name DEVICE_FILTER_PACKAGE TQFP + +# Fitter Assignments +# ================== +set_global_assignment -name DEVICE EP3C25E144C8 +set_global_assignment -name ENABLE_CONFIGURATION_PINS OFF +set_global_assignment -name ENABLE_NCE_PIN OFF +set_global_assignment -name ENABLE_BOOT_SEL_PIN OFF +set_global_assignment -name CYCLONEIII_CONFIGURATION_SCHEME "PASSIVE SERIAL" +set_global_assignment -name CRC_ERROR_OPEN_DRAIN OFF +set_global_assignment -name FORCE_CONFIGURATION_VCCIO ON +set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "3.3-V LVTTL" +set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name RESERVE_DATA0_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name RESERVE_DATA1_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name RESERVE_FLASH_NCE_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name RESERVE_DCLK_AFTER_CONFIGURATION "USE AS REGULAR IO" + +# Assembler Assignments +# ===================== +set_global_assignment -name GENERATE_RBF_FILE ON +set_global_assignment -name USE_CONFIGURATION_DEVICE OFF + +# SignalTap II Assignments +# ======================== +set_global_assignment -name ENABLE_SIGNALTAP OFF +set_global_assignment -name USE_SIGNALTAP_FILE output_files/sdram.stp + +# Power Estimation Assignments +# ============================ +set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW" +set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)" + +# Advanced I/O Timing Assignments +# =============================== +set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -rise +set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -fall +set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -rise +set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -fall + +# ------------------------------ +# start ENTITY(IronHorse_MiST) + + # Pin & Location Assignments + # ========================== + + # Fitter Assignments + # ================== + + # start DESIGN_PARTITION(Top) + # --------------------------- + + # Incremental Compilation Assignments + # =================================== + + # end DESIGN_PARTITION(Top) + # ------------------------- + +# end ENTITY(IronHorse_MiST) +# ---------------------------- +set_global_assignment -name SYNTH_TIMING_DRIVEN_SYNTHESIS ON +set_global_assignment -name TIMEQUEST_MULTICORNER_ANALYSIS ON +set_global_assignment -name SMART_RECOMPILE ON +set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top +set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top +set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[*] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_A[*] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_BA[0] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_BA[1] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQMH +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQML +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nRAS +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nCAS +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nWE +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nCS +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[*] +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[*] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_A[*] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[*] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_BA[*] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQML +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQMH +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nRAS +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nCAS +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nWE +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nCS +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_CKE +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_CLK +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_R[*] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_G[*] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_B[*] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_HS +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_VS +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to AUDIO_L +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to AUDIO_R +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SPI_DO +set_global_assignment -name ALLOW_POWER_UP_DONT_CARE ON +set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_RETIMING ON +set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_DUPLICATION ON +set_global_assignment -name CYCLONEII_OPTIMIZATION_TECHNIQUE SPEED +set_global_assignment -name OPTIMIZE_HOLD_TIMING "ALL PATHS" +set_global_assignment -name OPTIMIZE_MULTI_CORNER_TIMING ON +set_global_assignment -name FITTER_EFFORT "STANDARD FIT" +set_global_assignment -name SYSTEMVERILOG_FILE rtl/IronHorse_MiST.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/sdram.sv +set_global_assignment -name QIP_FILE rtl/pll.qip +set_global_assignment -name SYSTEMVERILOG_FILE rtl/IronHorse.sv +set_global_assignment -name VHDL_FILE rtl/spram.vhd +set_global_assignment -name SYSTEMVERILOG_FILE rtl/rom_loader.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/k005885.sv +set_global_assignment -name VERILOG_FILE rtl/jt49_dcrm2.v +set_global_assignment -name SYSTEMVERILOG_FILE rtl/ironhorse_ssg_lpf.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/ironhorse_fm_lpf.sv +set_global_assignment -name VERILOG_FILE rtl/audio_iir_filter.v +set_global_assignment -name VERILOG_FILE rtl/jtframe_frac_cen.v +set_global_assignment -name VHDL_FILE rtl/dpram_dc.vhd +set_global_assignment -name QIP_FILE ../../common/mist/mist.qip +set_global_assignment -name VERILOG_FILE ../../common/CPU/MC6809/mc6809is.v +set_global_assignment -name QIP_FILE ../../common/CPU/T80/T80.qip +set_global_assignment -name QIP_FILE ../../common/Sound/JT12/hdl/jt03.qip +set_global_assignment -name QIP_FILE ../../common/Sound/JT49/jt49.qip +set_global_assignment -name VERILOG_SHOW_LMF_MAPPING_MESSAGES OFF +set_global_assignment -name VERILOG_MACRO "EXT_ROM=" +set_global_assignment -name FORCE_SYNCH_CLEAR ON +set_global_assignment -name SIGNALTAP_FILE output_files/sdram.stp +set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/Arcade_MiST/Konami Iron Horse/IronHors.sdc b/Arcade_MiST/Konami Iron Horse/IronHors.sdc new file mode 100644 index 00000000..4a373c09 --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/IronHors.sdc @@ -0,0 +1,134 @@ +## Generated SDC file "vectrex_MiST.out.sdc" + +## Copyright (C) 1991-2013 Altera Corporation +## Your use of Altera Corporation's design tools, logic functions +## and other software and tools, and its AMPP partner logic +## functions, and any output files from any of the foregoing +## (including device programming or simulation files), and any +## associated documentation or information are expressly subject +## to the terms and conditions of the Altera Program License +## Subscription Agreement, Altera MegaCore Function License +## Agreement, or other applicable license agreement, including, +## without limitation, that your use is for the sole purpose of +## programming logic devices manufactured by Altera and sold by +## Altera or its authorized distributors. Please refer to the +## applicable agreement for further details. + + +## VENDOR "Altera" +## PROGRAM "Quartus II" +## VERSION "Version 13.1.0 Build 162 10/23/2013 SJ Web Edition" + +## DATE "Sun Jun 24 12:53:00 2018" + +## +## DEVICE "EP3C25E144C8" +## + +# Clock constraints + +# Automatically constrain PLL and other generated clocks +derive_pll_clocks -create_base_clocks + +# Automatically calculate clock uncertainty to jitter and other effects. +derive_clock_uncertainty + +# tsu/th constraints + +# tco constraints + +# tpd constraints + +#************************************************************** +# Time Information +#************************************************************** + +set_time_format -unit ns -decimal_places 3 + + + +#************************************************************** +# Create Clock +#************************************************************** + +create_clock -name {SPI_SCK} -period 41.666 -waveform { 20.8 41.666 } [get_ports {SPI_SCK}] + +set sdram_clk "pll|altpll_component|auto_generated|pll1|clk[0]" +set sys_clk "pll|altpll_component|auto_generated|pll1|clk[1]" +#************************************************************** +# Create Generated Clock +#************************************************************** + + +#************************************************************** +# Set Clock Latency +#************************************************************** + + + +#************************************************************** +# Set Clock Uncertainty +#************************************************************** + +#************************************************************** +# Set Input Delay +#************************************************************** + +set_input_delay -add_delay -clock_fall -clock [get_clocks {CLOCK_27}] 1.000 [get_ports {CLOCK_27}] +set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {CONF_DATA0}] +set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_DI}] +set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_SCK}] +set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_SS2}] +set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_SS3}] + +set_input_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -max 6.6 [get_ports SDRAM_DQ[*]] +set_input_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -min 3.5 [get_ports SDRAM_DQ[*]] + +#************************************************************** +# Set Output Delay +#************************************************************** + +set_output_delay -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_DO}] +set_output_delay -clock [get_clocks $sys_clk] 1.000 [get_ports {AUDIO_L}] +set_output_delay -clock [get_clocks $sys_clk] 1.000 [get_ports {AUDIO_R}] +set_output_delay -clock [get_clocks $sys_clk] 1.000 [get_ports {LED}] +set_output_delay -clock [get_clocks $sys_clk] 1.000 [get_ports {VGA_*}] + +set_output_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -max 1.5 [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}] +set_output_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -min -0.8 [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}] + +#************************************************************** +# Set Clock Groups +#************************************************************** + +set_clock_groups -asynchronous -group [get_clocks {SPI_SCK}] -group [get_clocks {pll|altpll_component|auto_generated|pll1|clk[*]}] + +#************************************************************** +# Set False Path +#************************************************************** + + + +#************************************************************** +# Set Multicycle Path +#************************************************************** + +set_multicycle_path -to {VGA_*[*]} -setup 2 +set_multicycle_path -to {VGA_*[*]} -hold 1 + +#************************************************************** +# Set Maximum Delay +#************************************************************** + + + +#************************************************************** +# Set Minimum Delay +#************************************************************** + + + +#************************************************************** +# Set Input Transition +#************************************************************** + diff --git a/Arcade_MiST/Konami Iron Horse/README.md b/Arcade_MiST/Konami Iron Horse/README.md new file mode 100644 index 00000000..9e8bd00a --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/README.md @@ -0,0 +1,11 @@ +# MiST port of Konami Iron Horse by ACE + +https://github.com/MiSTer-devel/Arcade-IronHorse_MiSTer + +## Usage + +- Create ROM and ARC files from the MRA files using the MRA utility. + Example: mra -A -z /path/to/mame/roms "Iron Horse (Ver. K).mra" +- Copy the ROM files to the root of the SD Card +- Copy the RBF and ARC files to the same folder on the SD Card +- MRA utility: https://github.com/sebdel/mra-tools-c/ \ No newline at end of file diff --git a/Arcade_MiST/Konami Iron Horse/meta/Iron Horse (Ver. K).mra b/Arcade_MiST/Konami Iron Horse/meta/Iron Horse (Ver. K).mra new file mode 100644 index 00000000..3c5f7d58 --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/meta/Iron Horse (Ver. K).mra @@ -0,0 +1,84 @@ + + Iron Horse + World + no + no + Version K + + + + 1986 + Konami + Platformer + + ironhors + ironhors + 0224 + IronHors + + + 15kHz + no + no + + 2 (alternating) + 8-way + + 3 + + + + + + + + + + + + + + + + + 00 + + + + + + + + + + + + + + + + + + + 16 00 00 00 00 FF 00 02 + 00 02 00 01 00 FF 02 00 + 00 00 32 F1 00 03 02 00 + 00 00 33 00 00 40 23 00 + + + + + 02 58 00 23 2C 1F 01 00 02 58 00 29 2C 29 01 00 + 02 22 00 11 2C 24 00 00 01 95 00 1B 2C 11 00 00 + 01 38 00 19 2C 25 00 00 01 30 00 23 2C 23 00 00 + 01 20 00 1E 2C 1D 00 00 01 10 00 23 2C 19 00 00 + 01 00 00 + + + + + + + + 20210803143815 + diff --git a/Arcade_MiST/Konami Iron Horse/rtl/IronHorse.sv b/Arcade_MiST/Konami Iron Horse/rtl/IronHorse.sv new file mode 100644 index 00000000..bec013e7 --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/rtl/IronHorse.sv @@ -0,0 +1,627 @@ +//============================================================================ +// +// Iron Horse PCB model +// Copyright (C) 2020, 2021 Ace, Ash Evans (aka ElectronAsh/OzOnE) and +// Kitrinx +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +//============================================================================ + +//Module declaration, I/O ports +module IronHorse +( + input reset, + input clk_49m, //Actual frequency: 49.152MHz + input [1:0] coin, + input [1:0] btn_start, //1 = Player 2, 0 = Player 1 + input [3:0] p1_joystick, p2_joystick, //3 = down, 2 = up, 1 = right, 0 = left + input [2:0] p1_buttons, p2_buttons, //3 buttons per player + input btn_service, + input [23:0] dipsw, + + //The following flag is used to reconfigure the 005885s' video timings and logic for drawing sprites to + //reproduce the errors found on bootleg Iron Horse PCBs (this is a 2-bit signal to reconfigure the 005885s + //depending on which game's bootleg ROM sets are loaded) + input [1:0] is_bootleg, + + //This input serves to select a fractional divider to acheive 3.072MHz for the YM2203 depending on whether Iron Horse + //runs with original or underclocked timings to normalize sync frequencies + input underclock, + + //Screen centering (alters HSync and VSync timing in the primary Konami 005885 to reposition the video output) + input [3:0] h_center, v_center, + + output video_hsync, video_vsync, video_csync, + output video_vblank, video_hblank, + output [3:0] video_r, video_g, video_b, + output signed [15:0] sound, + + input [24:0] ioctl_addr, + input [7:0] ioctl_data, + input ioctl_wr, + + input pause, +`ifdef MISTER_HISCORE + input [11:0] hs_address, + input [7:0] hs_data_in, + output [7:0] hs_data_out, + input hs_write_enable, + input hs_access_read, + input hs_access_write, +`endif + + //SDRAM signals + output reg [15:0] main_cpu_rom_addr, + input [7:0] main_cpu_rom_do, + output reg [14:0] sub_cpu_rom_addr, + input [7:0] sub_cpu_rom_do, + output reg [15:1] char1_rom_addr, + input [15:0] char1_rom_do, + output sp1_req, + input sp1_ack, + output [15:1] sp1_rom_addr, + input [15:0] sp1_rom_do +); + +//------------------------------------------------- MiSTer data write selector -------------------------------------------------// + +//Instantiate MiSTer data write selector to generate write enables for loading ROMs into the FPGA's BRAM +wire ep1_cs_i, ep2_cs_i, ep3_cs_i, ep4_cs_i, ep5_cs_i, ep6_cs_i, ep7_cs_i; +wire prom1_cs_i, prom2_cs_i, prom3_cs_i, prom4_cs_i, prom5_cs_i; +selector DLSEL +( + .ioctl_addr(ioctl_addr), + .ep1_cs(ep1_cs_i), + .ep2_cs(ep2_cs_i), + .ep3_cs(ep3_cs_i), + .ep4_cs(ep4_cs_i), + .ep5_cs(ep5_cs_i), + .ep6_cs(ep6_cs_i), + .ep7_cs(ep7_cs_i), + .prom1_cs(prom1_cs_i), + .prom2_cs(prom2_cs_i), + .prom3_cs(prom3_cs_i), + .prom4_cs(prom4_cs_i), + .prom5_cs(prom5_cs_i) +); + +//------------------------------------------------------- Clock division -------------------------------------------------------// + +//Generate 6.144MHz and (inverted) 3.072MHz clock enables (clock division is normally handled inside the Konami 005885) +//Also generate an extra clock enable for DC offset removal in the sound section +reg [6:0] div = 7'd0; +always_ff @(posedge clk_49m) begin + div <= div + 7'd1; +end +wire cen_6m = !div[2:0]; +wire cen_3m = !div[3:0]; +wire dcrm_cen = !div; + +//Phase generator for MC6809E (taken from MiSTer Vectrex core) +//Normally handled internally on the Konami 005885 +reg E = 0; +reg Q = 0; +always_ff @(posedge clk_49m) begin + reg [1:0] clk_phase = 0; + E <= 0; + Q <= 0; + if(cen_6m) begin + clk_phase <= clk_phase + 1'd1; + case(clk_phase) + 2'b01: Q <= 1; + 2'b10: E <= 1; + endcase + end +end + +//Generate 3.072MHz clock enable for YM2203 to maintain consistent sound pitch when underclocked to normalize video timings +//(uses Jotego's fractional clock divider from JTFRAME) +wire cen_3m_adjust; +jtframe_frac_cen sound_cen +( + .clk(clk_49m), + .n(10'd50), + .m(10'd786), + .cen({1'bZ, cen_3m_adjust}) +); + +//------------------------------------------------------------ CPUs ------------------------------------------------------------// + +//Main CPU (Motorola MC6809E - uses synchronous version of Greg Miller's cycle-accurate MC6809E made by Sorgelig) +wire [15:0] mc6809e_A; +wire [7:0] mc6809e_Din, mc6809e_Dout; +wire mc6809e_rw; +mc6809is u13A +( + .CLK(clk_49m), + .fallE_en(E), + .fallQ_en(Q), + .D(mc6809e_Din), + .DOut(mc6809e_Dout), + .ADDR(mc6809e_A), + .RnW(mc6809e_rw), + .nIRQ(irq), + .nFIRQ(firq), + .nNMI(nmi), + .nHALT(pause), + .nRESET(reset), + .nDMABREQ(1) +); +//Address decoding for data inputs to MC6809E +wire cs_k005885 = (mc6809e_A[15:14] == 2'b00); +wire cs_soundlatch = ~nioc & (mc6809e_A[10:8] == 3'b000) & ~mc6809e_rw; +wire cs_dip3 = ~nioc & (mc6809e_A[10:8] == 3'b001) & mc6809e_rw; +wire sirq_trigger = ~nioc & (mc6809e_A[10:8] == 3'b001) & ~mc6809e_rw; +wire cs_dip2 = ~nioc & (mc6809e_A[10:8] == 3'b010) & mc6809e_rw; +wire cs_palettelatch = ~nioc & (mc6809e_A[10:8] == 3'b010) & ~mc6809e_rw; +wire cs_controls_dip1 = ~nioc & (mc6809e_A[10:8] == 3'b011) & mc6809e_rw; +wire cs_rom1 = (mc6809e_A[15:14] == 2'b01 || mc6809e_A[15:14] == 2'b10) & mc6809e_rw; +wire cs_rom2 = (mc6809e_A[15:14] == 2'b11 & mc6809e_rw); +//Multiplex data inputs to main CPU +assign mc6809e_Din = + (cs_k005885 & nioc) ? k005885_Dout: + cs_dip3 ? {4'hF, dipsw[19:16]}: + cs_dip2 ? dipsw[15:8]: + cs_controls_dip1 ? controls_dip1: + cs_rom1 ? eprom1_D: + cs_rom2 ? eprom2_D: + 8'hFF; + +//Game ROMs +`ifdef EXT_ROM +always_ff @(posedge clk_49m) + if (|mc6809e_A[15:14] & mc6809e_rw) + main_cpu_rom_addr <= mc6809e_A[15:0] - 16'h4000; + +wire [7:0] eprom1_D = main_cpu_rom_do; +wire [7:0] eprom2_D = main_cpu_rom_do; +`else +wire [7:0] eprom1_D; +eprom_1 u13C +( + .ADDR({~mc6809e_A[14], mc6809e_A[13:0]}), + .CLK(clk_49m), + .DATA(eprom1_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(ep1_cs_i), + .WR(ioctl_wr) +); +wire [7:0] eprom2_D; +eprom_2 u12C +( + .ADDR(mc6809e_A[13:0]), + .CLK(clk_49m), + .DATA(eprom2_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(ep2_cs_i), + .WR(ioctl_wr) +); +`endif + +//Palette latch +reg [7:0] pal_latch = 8'd0; +always_ff @(posedge clk_49m) begin + if(!reset) + pal_latch <= 8'd0; + else if(cen_3m) begin + if(cs_palettelatch) + pal_latch <= mc6809e_Dout; + end +end +wire [2:0] FA = pal_latch[2:0]; + +//Sound latch +reg [7:0] sound_data = 8'd0; +always_ff @(posedge clk_49m) begin + if(cen_3m && cs_soundlatch) + sound_data <= mc6809e_Dout; +end + +//Sound IRQ trigger +reg sound_irq = 1; +always_ff @(posedge clk_49m) begin + if(cen_3m) begin + if(sirq_trigger) + sound_irq <= 1; + else + sound_irq <= 0; + end +end + +//Sound CPU - Zilog Z80 (uses T80s variant of the T80 soft core) +wire z80_n_m1, z80_n_mreq, z80_n_iorq, z80_n_rfsh, z80_n_rd, z80_n_wr; +wire [15:0] z80_A; +wire [7:0] z80_Din, z80_Dout; +T80s u9A +( + .RESET_n(reset), + .CLK(clk_49m), + .CEN(cen_sound), + .INT_n(z80_n_int), + .MREQ_n(z80_n_mreq), + .IORQ_n(z80_n_iorq), + .RD_n(z80_n_rd), + .WR_n(z80_n_wr), + .M1_n(z80_n_m1), + .RFSH_n(z80_n_rfsh), + .A(z80_A), + .DI(z80_Din), + .DO(z80_Dout) +); +//Address decoding for data inputs to Z80 +wire z80_decode_en = (z80_n_rfsh & ~z80_n_mreq); +wire soundrom_cs = z80_decode_en & (z80_A[15:14] == 2'b00); +wire soundram_cs = z80_decode_en & (z80_A[15:14] == 2'b01); +wire sounddata_cs = z80_decode_en & (z80_A[15:14] == 2'b10); +//Multiplex data inputs to sound CPU +assign z80_Din = + soundrom_cs ? eprom3_D: + (soundram_cs & ~z80_n_rd) ? soundram_D: + sounddata_cs ? sound_data: + (~z80_n_iorq & ~z80_n_rd) ? ym2203_D: + 8'hFF; + +//Sound ROM +`ifdef EXT_ROM +wire [7:0] eprom3_D = sub_cpu_rom_do; +always_ff @(posedge clk_49m) + if (soundrom_cs) sub_cpu_rom_addr <= z80_A[13:0]; + +`else +wire [7:0] eprom3_D; +eprom_3 u10C +( + .ADDR(z80_A[13:0]), + .CLK(clk_49m), + .DATA(eprom3_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(ep3_cs_i), + .WR(ioctl_wr) +); +`endif + +//Sound RAM +wire [7:0] soundram_D; +spram #(8, 11) u11C +( + .clk(clk_49m), + .we(soundram_cs & ~z80_n_wr), + .addr(z80_A[10:0]), + .data(z80_Dout), + .q(soundram_D) +); + +//Generate sound IRQ +wire sirq_clr = (~reset | ~(z80_n_m1 | z80_n_iorq)); +reg z80_n_int = 1; +always_ff @(posedge clk_49m or posedge sirq_clr) begin + if(sirq_clr) + z80_n_int <= 1; + else if(cen_sound && sound_irq) + z80_n_int <= 0; +end + +//--------------------------------------------------- Controls & DIP switches --------------------------------------------------// + +//Multiplex player inputs and DIP switch bank 1 +wire [7:0] controls_dip1 = (mc6809e_A[1:0] == 2'b00) ? dipsw[7:0]: + (mc6809e_A[1:0] == 2'b01) ? {1'b1, p1_buttons[2], p2_buttons[1:0], p2_joystick}: + (mc6809e_A[1:0] == 2'b10) ? {1'b1, p2_buttons[2], p1_buttons[1:0], p1_joystick}: + (mc6809e_A[1:0] == 2'b11) ? {3'b111, btn_start, btn_service, coin}: + 8'hFF; + +//--------------------------------------------------- Video timing & graphics --------------------------------------------------// + +//Konami 005885 custom chip - this is a large ceramic pin-grid array IC responsible for the majority of Iron Horse's critical +//functions: IRQ generation, clock dividers and all video logic for generating tilemaps and sprites +wire [15:0] gfxrom_A, sprites_A; +//wire [12:0] vram_A; +//wire [7:0] vram_Din, vram_Dout; +//wire n_vram_oe, n_vram_we; +wire [7:0] k005885_Dout, tilemap_lut_A, sprite_lut_A; +wire [4:0] color_A; +wire tile_attrib_D5, firq, irq, nmi, nioc; +k005885 u11D +( + .CK49(clk_49m), + .NRD(~mc6809e_rw), + .A(mc6809e_A[13:0]), + .DBi(mc6809e_Dout), + .DBo(k005885_Dout), + .R(gfxrom_A), + .RDU(tiles_D[15:8]), + .RDL(tiles_D[7:0]), + .S(sprites_A), + .S_req(sp1_req), + .S_ack(sp1_ack), + .SDU(sprites_D[15:8]), + .SDL(sprites_D[7:0]), + .VCF(tilemap_lut_A[7:4]), + .VCB(tilemap_lut_A[3:0]), + .VCD(tilemap_lut_D), + .OCF(sprite_lut_A[7:4]), + .OCB(sprite_lut_A[3:0]), + .OCD(sprite_lut_D), + .COL(color_A), + .NEXR(reset), + .NXCS(~cs_k005885), + .NCSY(video_csync), + .NHSY(video_hsync), + .NVSY(video_vsync), + .HBLK(video_hblank), + .VBLK(video_vblank), + .NFIR(firq), + .NIRQ(irq), + .NNMI(nmi), + .NIOC(nioc), + .ATR5(tile_attrib_D5), + .HCTR(h_center), + .VCTR(v_center), + .BTLG(is_bootleg) +`ifdef MISTER_HISCORE + , + .hs_address(hs_address), + .hs_data_out(hs_data_out), + .hs_data_in(hs_data_in), + .hs_write_enable(hs_write_enable), + .hs_access_read(hs_access_read), + .hs_access_write(hs_access_write) +`endif + +); + +//Graphics ROMs +always_ff @(posedge clk_49m) + char1_rom_addr <= {gfxrom_A[14], tile_attrib_D5, gfxrom_A[12:0]}; +assign sp1_rom_addr = sprites_A[14:0]; + +`ifdef EXT_ROM +wire [7:0] eprom4_D = sp1_rom_do[15:8]; +wire [7:0] eprom5_D = sp1_rom_do[7:0]; +wire [7:0] eprom6_D = char1_rom_do[15:8]; +wire [7:0] eprom7_D = char1_rom_do[7:0]; +`else +wire [7:0] eprom4_D, eprom5_D; +eprom_4 u8F +( + .ADDR(sprites_A[14:0]), + .CLK(~clk_49m), + .DATA(eprom4_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(ep4_cs_i), + .WR(ioctl_wr) +); +eprom_5 u7F +( + .ADDR(sprites_A[14:0]), + .CLK(~clk_49m), + .DATA(eprom5_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(ep5_cs_i), + .WR(ioctl_wr) +); + +wire [7:0] eprom6_D, eprom7_D; +eprom_6 u9F +( + .ADDR({gfxrom_A[14], tile_attrib_D5, gfxrom_A[12:0]}), + .CLK(clk_49m), + .DATA(eprom6_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(ep6_cs_i), + .WR(ioctl_wr) +); +eprom_7 u6F +( + .ADDR({gfxrom_A[14], tile_attrib_D5, gfxrom_A[12:0]}), + .CLK(clk_49m), + .DATA(eprom7_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(ep7_cs_i), + .WR(ioctl_wr) +); +`endif + +//Combine graphics ROM data outputs to 16 bits +wire [15:0] tiles_D = {eprom6_D, eprom7_D}; +wire [15:0] sprites_D = {eprom4_D, eprom5_D}; + +//Tilemap LUT PROM +wire [3:0] tilemap_lut_D; +prom_4 u11F +( + .ADDR(tilemap_lut_A), + .CLK(clk_49m), + .DATA(tilemap_lut_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(prom4_cs_i), + .WR(ioctl_wr) +); + +//Sprite LUT PROM +wire [3:0] sprite_lut_D; +prom_5 u10F +( + .ADDR(sprite_lut_A), + .CLK(clk_49m), + .DATA(sprite_lut_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(prom5_cs_i), + .WR(ioctl_wr) +); + +//--------------------------------------------------------- Sound chips --------------------------------------------------------// + +//Select whether to use a fractional or integer clock divider for the YM2203 to maintain consistent sound pitch at both original +//and underclocked timings +wire cen_sound = underclock ? cen_3m_adjust : cen_3m; + +//Sound chip (Yamaha YM2203 - uses JT03 implementation by Jotego) +wire [2:0] filter_en; +wire [7:0] ym2203_D; +wire [7:0] ym2203_ssgA_raw, ym2203_ssgB_raw, ym2203_ssgC_raw; +wire signed [15:0] ym2203_fm_raw; + +jt03 u6D +( + .rst(~reset), + .clk(clk_49m), + .cen(cen_sound), + .din(z80_Dout), + .dout(ym2203_D), + .IOA_out({5'bZZZZZ, filter_en}), + .addr(z80_A[0]), + .cs_n(z80_n_iorq), + .wr_n(z80_n_wr), + .psg_A(ym2203_ssgA_raw), + .psg_B(ym2203_ssgB_raw), + .psg_C(ym2203_ssgC_raw), + .fm_snd(ym2203_fm_raw) +); + +//----------------------------------------------------- Final video output -----------------------------------------------------// + +//Iron Horse's video output is straightforward: three color LUT PROMs, one per color, 12-bit RGB with 4 bits per color +prom_1 u3F +( + .ADDR({FA, color_A}), + .CLK(clk_49m), + .DATA(video_r), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(prom1_cs_i), + .WR(ioctl_wr) +); +prom_2 u4F +( + .ADDR({FA, color_A}), + .CLK(clk_49m), + .DATA(video_g), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(prom2_cs_i), + .WR(ioctl_wr) +); +prom_3 u5F +( + .ADDR({FA, color_A}), + .CLK(clk_49m), + .DATA(video_b), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(prom3_cs_i), + .WR(ioctl_wr) +); + +//----------------------------------------------------- Final audio output -----------------------------------------------------// + +//Iron Horse uses a 4.823KHz low-pass filter for the FM side of its YM2203 - filter the audio accordingly here. +wire signed [15:0] ym2203_fm_lpf; +ironhorse_fm_lpf lpf_fm +( + .clk(clk_49m), + .reset(~reset), + .in(ym2203_fm_raw), + .out(ym2203_fm_lpf) +); + +//Iron Horse also uses 3 switchable low-pass filters on the SSG side of its YM2203 with a cutoff frequency of +//723.432Hz (actually closer to 492.130Hz due to internal resistance inside the 74HC4066 handling the filter switching). +//Model the switchable filters here. +wire signed [15:0] ym2203_ssgA_lpf, ym2203_ssgB_lpf, ym2203_ssgC_lpf; +ironhorse_ssg_lpf lpf_ssgA +( + .clk(clk_49m), + .reset(~reset), + .in(ym2203_ssgA_dcrm), + .out(ym2203_ssgA_lpf) +); +ironhorse_ssg_lpf lpf_ssgB +( + .clk(clk_49m), + .reset(~reset), + .in(ym2203_ssgB_dcrm), + .out(ym2203_ssgB_lpf) +); +ironhorse_ssg_lpf lpf_ssgC +( + .clk(clk_49m), + .reset(~reset), + .in(ym2203_ssgC_dcrm), + .out(ym2203_ssgC_lpf) +); + +//Remove DC offset from SSG outputs and apply gain to prevent losing quiet sounds after low-pass filtering +wire signed [15:0] ym2203_ssgA_dcrm, ym2203_ssgB_dcrm, ym2203_ssgC_dcrm; +jt49_dcrm2 #(16) dcrm_ssgA +( + .clk(clk_49m), + .cen(dcrm_cen), + .rst(~reset), + .din({3'd0, ym2203_ssgA_raw, 5'd0}), + .dout(ym2203_ssgA_dcrm) +); +jt49_dcrm2 #(16) dcrm_ssgB +( + .clk(clk_49m), + .cen(dcrm_cen), + .rst(~reset), + .din({3'd0, ym2203_ssgB_raw, 5'd0}), + .dout(ym2203_ssgB_dcrm) +); +jt49_dcrm2 #(16) dcrm_ssgC +( + .clk(clk_49m), + .cen(dcrm_cen), + .rst(~reset), + .din({3'd0, ym2203_ssgC_raw, 5'd0}), + .dout(ym2203_ssgC_dcrm) +); + +//Apply the switchable low-pass filters and attenuate SSG outputs back to raw levels +wire signed [15:0] ym2203_ssgA = filter_en[2] ? ym2203_ssgA_lpf >>> 15'd5 : ym2203_ssgA_dcrm >>> 15'd5; +wire signed [15:0] ym2203_ssgB = filter_en[1] ? ym2203_ssgB_lpf >>> 15'd5 : ym2203_ssgB_dcrm >>> 15'd5; +wire signed [15:0] ym2203_ssgC = filter_en[0] ? ym2203_ssgC_lpf >>> 15'd5 : ym2203_ssgC_dcrm >>> 15'd5; + +//Mix all audio sources for the final output +assign sound = (ym2203_fm_lpf + (ym2203_ssgA * 15'd24) + (ym2203_ssgB * 15'd24) + (ym2203_ssgC * 15'd24)) <<< 15'd1; + +endmodule diff --git a/Arcade_MiST/Konami Iron Horse/rtl/IronHorse_MiST.sv b/Arcade_MiST/Konami Iron Horse/rtl/IronHorse_MiST.sv new file mode 100644 index 00000000..cd7cb069 --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/rtl/IronHorse_MiST.sv @@ -0,0 +1,323 @@ +module IronHorse_MiST ( + output LED, + output [5:0] VGA_R, + output [5:0] VGA_G, + output [5:0] VGA_B, + output VGA_HS, + output VGA_VS, + output AUDIO_L, + output AUDIO_R, + input SPI_SCK, + output SPI_DO, + input SPI_DI, + input SPI_SS2, + input SPI_SS3, + input CONF_DATA0, + input CLOCK_27, + output [12:0] SDRAM_A, + inout [15:0] SDRAM_DQ, + output SDRAM_DQML, + output SDRAM_DQMH, + output SDRAM_nWE, + output SDRAM_nCAS, + output SDRAM_nRAS, + output SDRAM_nCS, + output [1:0] SDRAM_BA, + output SDRAM_CLK, + output SDRAM_CKE + +); + +`include "rtl\build_id.v" + +localparam CONF_STR = { + "IRONHORS;;", + "O2,Rotate Controls,Off,On;", + "O34,Scanlines,Off,25%,50%,75%;", + "O5,Blend,Off,On;", + "O6,Joystick Swap,Off,On;", + "O7,Service,Off,On;", + "O1,Pause,Off,On;", + "DIP;", + "T0,Reset;", + "V,v1.00.",`BUILD_DATE +}; + +wire rotate = status[2]; +wire [1:0] scanlines = status[4:3]; +wire blend = status[5]; +wire joyswap = status[6]; +wire service = status[7]; +wire pause = status[1]; + +wire [1:0] orientation = 2'b10; +wire [23:0] dip_sw = ~status[31:8]; + +wire [1:0] is_bootleg = core_mod[1:0]; + +assign LED = ~ioctl_downl; +assign SDRAM_CLK = clock_98; +assign SDRAM_CKE = 1; + +wire clock_98, clock_49, pll_locked; +pll pll( + .inclk0(CLOCK_27), + .c0(clock_98), + .c1(clock_49),//49.152MHz + .locked(pll_locked) + ); + +wire [31:0] status; +wire [1:0] buttons; +wire [1:0] switches; +wire [7:0] joystick_0; +wire [7:0] joystick_1; +wire scandoublerD; +wire ypbpr; +wire no_csync; +wire [6:0] core_mod; +wire key_strobe; +wire key_pressed; +wire [7:0] key_code; + +user_io #(.STRLEN(($size(CONF_STR)>>3)))user_io( + .clk_sys (clock_49 ), + .conf_str (CONF_STR ), + .SPI_CLK (SPI_SCK ), + .SPI_SS_IO (CONF_DATA0 ), + .SPI_MISO (SPI_DO ), + .SPI_MOSI (SPI_DI ), + .buttons (buttons ), + .switches (switches ), + .scandoubler_disable (scandoublerD), + .ypbpr (ypbpr ), + .no_csync (no_csync ), + .core_mod (core_mod ), + .key_strobe (key_strobe ), + .key_pressed (key_pressed ), + .key_code (key_code ), + .joystick_0 (joystick_0 ), + .joystick_1 (joystick_1 ), + .status (status ) + ); + +wire [15:0] main_rom_addr; +wire [15:0] main_rom_do; +wire [14:0] sub_rom_addr; +wire [15:0] sub_rom_do; +wire [15:1] ch1_addr; +wire [15:0] ch1_do; +wire sp1_req, sp1_ack; +wire [15:1] sp1_addr; +wire [15:0] sp1_do; + +wire ioctl_downl; +wire [7:0] ioctl_index; +wire ioctl_wr; +wire [24:0] ioctl_addr; +wire [7:0] ioctl_dout; + +data_io data_io( + .clk_sys ( clock_49 ), + .SPI_SCK ( SPI_SCK ), + .SPI_SS2 ( SPI_SS2 ), + .SPI_DI ( SPI_DI ), + .ioctl_download( ioctl_downl ), + .ioctl_index ( ioctl_index ), + .ioctl_wr ( ioctl_wr ), + .ioctl_addr ( ioctl_addr ), + .ioctl_dout ( ioctl_dout ) +); +wire [24:0] bg_ioctl_addr = ioctl_addr - 17'h10000; + +reg port1_req, port2_req; +sdram #(98) sdram( + .*, + .init_n ( pll_locked ), + .clk ( clock_98 ), + + // port1 for CPUs + .port1_req ( port1_req ), + .port1_ack ( ), + .port1_a ( ioctl_addr[23:1] ), + .port1_ds ( {ioctl_addr[0], ~ioctl_addr[0]} ), + .port1_we ( ioctl_downl ), + .port1_d ( {ioctl_dout, ioctl_dout} ), + .port1_q ( ), + + .cpu1_addr ( ioctl_downl ? 16'h0000 : main_rom_addr[15:1] ), + .cpu1_q ( main_rom_do ), + .cpu2_addr ( ioctl_downl ? 16'h0000 : sub_rom_addr[14:1] + 16'h6000 ), + .cpu2_q ( sub_rom_do ), + + // port2 for graphics + .port2_req ( port2_req ), + .port2_ack ( ), + .port2_a ( {bg_ioctl_addr[23:16], bg_ioctl_addr[14:0]} ), // merge gfx roms to 16-bit wide words + .port2_ds ( {~bg_ioctl_addr[15], bg_ioctl_addr[15]} ), + .port2_we ( ioctl_downl ), + .port2_d ( {ioctl_dout, ioctl_dout} ), + .port2_q ( ), + + .ch1_addr ( ioctl_downl ? 16'hffff : ch1_addr ), + .ch1_q ( ch1_do ), + .ch2_addr ( ), + .ch2_q ( ), + .sp1_req ( sp1_req ), + .sp1_ack ( sp1_ack ), + .sp1_addr ( ioctl_downl ? 16'hffff : sp1_addr ), + .sp1_q ( sp1_do ), + .sp2_req ( ), + .sp2_ack ( ), + .sp2_addr ( ), + .sp2_q ( ) +); + +// ROM download controller +always @(posedge clock_49) begin + reg ioctl_wr_last = 0; + + ioctl_wr_last <= ioctl_wr; + if (ioctl_downl) begin + if (~ioctl_wr_last && ioctl_wr) begin + port1_req <= ~port1_req; + port2_req <= ~port2_req; + end + end +end + +reg reset = 1; +reg rom_loaded = 0; +always @(posedge clock_49) begin + reg ioctl_downlD; + ioctl_downlD <= ioctl_downl; + + if (ioctl_downlD & ~ioctl_downl) rom_loaded <= 1; + reset <= status[0] | buttons[1] | ~rom_loaded; +end + +wire [15:0] audio; +wire hs, vs, cs; +wire hblank, vblank; +wire blankn = ~(hblank | vblank); +wire [3:0] r, g, b; + +//Instantiate Iron Horse top-level module +IronHorse IronHorse_inst +( + .reset(~reset), // input reset + + .clk_49m(clock_49), // input clk_49m + + .coin({~m_coin2, ~m_coin1}), // input coin + .btn_service(~service), // input btn_service + + .btn_start({~m_two_players, ~m_one_player}), // input [1:0] btn_start + + .p1_joystick({~m_down, ~m_up, ~m_right, ~m_left}), + .p2_joystick({~m_down2, ~m_up2, ~m_right2, ~m_left2}), + .p1_buttons({~m_fireC, ~m_fireB, ~m_fireA}), + .p2_buttons({~m_fire2C, ~m_fire2B, ~m_fire2A}), + + .dipsw(dip_sw), // input [24:0] dipsw + + .is_bootleg(is_bootleg), // Flag to reconfigure core for differences + // present on bootleg Iron Horse PCBs + + .sound(audio), // output [15:0] sound + + .h_center(), // Screen centering + .v_center(), + + .video_hsync(hs), // output video_hsync + .video_vsync(vs), // output video_vsync + .video_vblank(vblank), // output video_vblank + .video_hblank(hblank), // output video_hblank + + .video_r(r), // output [4:0] video_r + .video_g(g), // output [4:0] video_g + .video_b(b), // output [4:0] video_b + + .ioctl_addr(ioctl_addr), + .ioctl_wr(ioctl_wr && ioctl_index == 0), + .ioctl_data(ioctl_dout), + + .pause(~pause), + + .underclock(), //Flag to signal that Iron Horse has been underclocked to normalize video timings in order to maintain consistent sound pitch +/* + .hs_address(hs_address), + .hs_data_out(hs_data_out), + .hs_data_in(hs_data_in), + .hs_write_enable(hs_write_enable), + .hs_access_read(hs_access_read), + .hs_access_write(hs_access_write), +*/ + .main_cpu_rom_addr(main_rom_addr), + .main_cpu_rom_do(main_rom_addr[0] ? main_rom_do[15:8] : main_rom_do[7:0]), + .sub_cpu_rom_addr(sub_rom_addr), + .sub_cpu_rom_do(sub_rom_addr[0] ? sub_rom_do[15:8] : sub_rom_do[7:0]), + .char1_rom_addr(ch1_addr), + .char1_rom_do(ch1_do), + .sp1_req(sp1_req), + .sp1_ack(sp1_ack), + .sp1_rom_addr(sp1_addr), + .sp1_rom_do(sp1_do) +); + +mist_video #(.COLOR_DEPTH(4), .SD_HCNT_WIDTH(10)) mist_video( + .clk_sys ( clock_49 ), + .SPI_SCK ( SPI_SCK ), + .SPI_SS3 ( SPI_SS3 ), + .SPI_DI ( SPI_DI ), + .R ( blankn ? r : 0 ), + .G ( blankn ? g : 0 ), + .B ( blankn ? b : 0 ), + .HSync ( hs ), + .VSync ( vs ), + .VGA_R ( VGA_R ), + .VGA_G ( VGA_G ), + .VGA_B ( VGA_B ), + .VGA_VS ( VGA_VS ), + .VGA_HS ( VGA_HS ), + .ce_divider ( 0 ), + .rotate ( { orientation[1], rotate } ), + .blend ( blend ), + .scandoubler_disable( scandoublerD ), + .scanlines ( scanlines ), + .ypbpr ( ypbpr ), + .no_csync ( no_csync ) + ); + +wire audio_out; +assign AUDIO_L = audio_out; +assign AUDIO_R = audio_out; + +dac #(.C_bits(16))dac( + .clk_i(clock_49), + .res_n_i(1'b1), + .dac_i({~audio[15], audio[14:0]}), + .dac_o(audio_out) + ); + +wire m_up, m_down, m_left, m_right, m_fireA, m_fireB, m_fireC, m_fireD, m_fireE, m_fireF; +wire m_up2, m_down2, m_left2, m_right2, m_fire2A, m_fire2B, m_fire2C, m_fire2D, m_fire2E, m_fire2F; +wire m_tilt, m_coin1, m_coin2, m_coin3, m_coin4, m_one_player, m_two_players, m_three_players, m_four_players; + +arcade_inputs inputs ( + .clk ( clock_49 ), + .key_strobe ( key_strobe ), + .key_pressed ( key_pressed ), + .key_code ( key_code ), + .joystick_0 ( joystick_0 ), + .joystick_1 ( joystick_1 ), + .rotate ( rotate ), + .orientation ( orientation ), + .joyswap ( joyswap ), + .oneplayer ( 1'b0 ), + .controls ( {m_tilt, m_coin4, m_coin3, m_coin2, m_coin1, m_four_players, m_three_players, m_two_players, m_one_player} ), + .player1 ( {m_fireF, m_fireE, m_fireD, m_fireC, m_fireB, m_fireA, m_up, m_down, m_left, m_right} ), + .player2 ( {m_fire2F, m_fire2E, m_fire2D, m_fire2C, m_fire2B, m_fire2A, m_up2, m_down2, m_left2, m_right2} ) +); + +endmodule diff --git a/Arcade_MiST/Konami Iron Horse/rtl/audio_iir_filter.v b/Arcade_MiST/Konami Iron Horse/rtl/audio_iir_filter.v new file mode 100644 index 00000000..ad324f04 --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/rtl/audio_iir_filter.v @@ -0,0 +1,173 @@ +/*MIT License + +Copyright (c) 2019 Gregory Hogan (Soltan_G42) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ + +module iir_1st_order +#( + parameter COEFF_WIDTH = 18, + parameter COEFF_SCALE = 15, + parameter DATA_WIDTH = 16, + parameter COUNT_BITS = 10 +) +( + input clk, + input reset, + input [COUNT_BITS - 1 : 0] div, + input signed [COEFF_WIDTH - 1 : 0] A2, B1, B2, + input signed [DATA_WIDTH - 1 :0] in, + output [DATA_WIDTH - 1:0] out +); + + reg signed [DATA_WIDTH-1:0] x0,x1,y0; + reg signed [DATA_WIDTH + COEFF_WIDTH - 1 : 0] out32; + reg [COUNT_BITS - 1:0] count; + + // Usage: + // Design your 1st order iir low/high-pass with a tool that will give you the + // filter coefficients for the difference equation. Filter coefficients can + // be generated in Octave/matlab/scipy using a command similar to + // [B, A] = butter( 1, 3500/(106528/2), 'low') for a 3500 hz 1st order low-pass + // assuming 106528Hz sample rate. + // + // The Matlab output is: + // B = [0.093863 0.093863] + // A = [1.00000 -0.81227] + // + // Then scale coefficients by multiplying by 2^COEFF_SCALE and round to nearest integer + // + // B = [3076 3076] + // A = [32768 -26616] + // + // Discard A(1) because it is assumed 1.0 before scaling + // + // This leaves you with A2 = -26616 , B1 = 3076 , B2 = 3076 + // B1 + B2 - A2 should sum to 2^COEFF_SCALE = 32768 + // + // Sample frequency is "clk rate/div": for Genesis this is 53.69mhz/504 = 106528hz + // + // COEFF_WIDTH must be at least COEFF_SCALE+1 and must be large enough to + // handle temporary overflow during this computation: out32 <= (B1*x0 + B2*x1) - A2*y0 + + assign out = y0; + + always @ (*) begin + out32 <= (B1*x0 + B2*x1) - A2*y0; //Previous output is y0 not y1 + end + + always @ (posedge clk) begin + if(reset) begin + count <= 0; + x0 <= 0; + x1 <= 0; + y0 <= 0; + end + else begin + count <= count + 1'd1; + if (count == div - 1) begin + count <= 0; + y0 <= {out32[DATA_WIDTH + COEFF_WIDTH - 1] , out32[COEFF_SCALE + DATA_WIDTH - 2 : COEFF_SCALE]}; + x1 <= x0; + x0 <= in; + end + end + end + +endmodule //iir_1st_order + +module iir_2nd_order +#( + parameter COEFF_WIDTH = 18, + parameter COEFF_SCALE = 14, + parameter DATA_WIDTH = 16, + parameter COUNT_BITS = 10 +) +( + input clk, + input reset, + input [COUNT_BITS - 1 : 0] div, + input signed [COEFF_WIDTH - 1 : 0] A2, A3, B1, B2, B3, + input signed [DATA_WIDTH - 1 : 0] in, + output [DATA_WIDTH - 1 : 0] out +); + + reg signed [DATA_WIDTH-1 : 0] x0,x1,x2; + reg signed [DATA_WIDTH-1 : 0] y0,y1; + reg signed [(DATA_WIDTH + COEFF_WIDTH - 1) : 0] out32; + reg [COUNT_BITS : 0] count; + + + // Usage: + // Design your 1st order iir low/high-pass with a tool that will give you the + // filter coefficients for the difference equation. Filter coefficients can + // be generated in Octave/matlab/scipy using a command similar to + // [B, A] = butter( 2, 5000/(48000/2), 'low') for a 5000 hz 2nd order low-pass + // assuming 48000Hz sample rate. + // + // Output is: + // B = [ 0.072231 0.144462 0.072231] + // A = [1.00000 -1.10923 0.39815] + // + // Then scale coefficients by multiplying by 2^COEFF_SCALE and round to nearest integer + // Make sure your coefficients can be stored as a signed number with COEFF_WIDTH bits. + // + // B = [1183 2367 1183] + // A = [16384 -18174 6523] + // + // Discard A(1) because it is assumed 1.0 before scaling + // + // This leaves you with A2 = -18174 , A3 = 6523, B1 = 1183 , B2 = 2367 , B3 = 1183 + // B1 + B2 + B3 - A2 - A3 should sum to 2^COEFF_SCALE = 16384 + // + // Sample frequency is "clk rate/div" + // + // COEFF_WIDTH must be at least COEFF_SCALE+1 and must be large enough to + // handle temporary overflow during this computation: + // out32 <= (B1*x0 + B2*x1 + B3*x2) - (A2*y0 + A3*y1); + + assign out = y0; + + always @ (*) begin + out32 <= (B1*x0 + B2*x1 + B3*x2) - (A2*y0 + A3*y1); //Previous output is y0 not y1 + end + + always @ (posedge clk) begin + if(reset) begin + count <= 0; + x0 <= 0; + x1 <= 0; + x2 <= 0; + y0 <= 0; + y1 <= 0; + end + else begin + count <= count + 1'd1; + if (count == div - 1) begin + count <= 0; + y1 <= y0; + y0 <= {out32[DATA_WIDTH + COEFF_WIDTH - 1] , out32[(DATA_WIDTH + COEFF_SCALE - 2) : COEFF_SCALE]}; + x2 <= x1; + x1 <= x0; + x0 <= in; + end + end + end + +endmodule //iir_2nd_order \ No newline at end of file diff --git a/Arcade_MiST/Konami Iron Horse/rtl/build_id.tcl b/Arcade_MiST/Konami Iron Horse/rtl/build_id.tcl new file mode 100644 index 00000000..938515d8 --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/rtl/build_id.tcl @@ -0,0 +1,35 @@ +# ================================================================================ +# +# Build ID Verilog Module Script +# Jeff Wiencrot - 8/1/2011 +# +# Generates a Verilog module that contains a timestamp, +# from the current build. These values are available from the build_date, build_time, +# physical_address, and host_name output ports of the build_id module in the build_id.v +# Verilog source file. +# +# ================================================================================ + +proc generateBuildID_Verilog {} { + + # Get the timestamp (see: http://www.altera.com/support/examples/tcl/tcl-date-time-stamp.html) + set buildDate [ clock format [ clock seconds ] -format %y%m%d ] + set buildTime [ clock format [ clock seconds ] -format %H%M%S ] + + # Create a Verilog file for output + set outputFileName "rtl/build_id.v" + set outputFile [open $outputFileName "w"] + + # Output the Verilog source + puts $outputFile "`define BUILD_DATE \"$buildDate\"" + puts $outputFile "`define BUILD_TIME \"$buildTime\"" + close $outputFile + + # Send confirmation message to the Messages window + post_message "Generated build identification Verilog module: [pwd]/$outputFileName" + post_message "Date: $buildDate" + post_message "Time: $buildTime" +} + +# Comment out this line to prevent the process from automatically executing when the file is sourced: +generateBuildID_Verilog \ No newline at end of file diff --git a/Arcade_MiST/Konami Iron Horse/rtl/dpram_dc.vhd b/Arcade_MiST/Konami Iron Horse/rtl/dpram_dc.vhd new file mode 100644 index 00000000..69d4c5fb --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/rtl/dpram_dc.vhd @@ -0,0 +1,136 @@ +LIBRARY ieee; +USE ieee.std_logic_1164.all; + +LIBRARY altera_mf; +USE altera_mf.all; + +ENTITY dpram_dc IS + GENERIC + ( + init_file : string := " "; + widthad_a : natural; + width_a : natural := 8; + outdata_reg_a : string := "UNREGISTERED"; + outdata_reg_b : string := "UNREGISTERED" + ); + PORT + ( + address_a : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0); + address_b : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0) := (others => '0'); + clock_a : IN STD_LOGIC ; + clock_b : IN STD_LOGIC ; + data_a : IN STD_LOGIC_VECTOR (width_a-1 DOWNTO 0) := (others => '0'); + data_b : IN STD_LOGIC_VECTOR (width_a-1 DOWNTO 0) := (others => '0'); + wren_a : IN STD_LOGIC := '0'; + wren_b : IN STD_LOGIC := '0'; + byteena_a : IN STD_LOGIC_VECTOR (width_a/8-1 DOWNTO 0) := (others => '1'); + byteena_b : IN STD_LOGIC_VECTOR (width_a/8-1 DOWNTO 0) := (others => '1'); + q_a : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0); + q_b : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0) + ); +END dpram_dc; + + +ARCHITECTURE SYN OF dpram_dc IS + + SIGNAL sub_wire0 : STD_LOGIC_VECTOR (width_a-1 DOWNTO 0); + SIGNAL sub_wire1 : STD_LOGIC_VECTOR (width_a-1 DOWNTO 0); + + + + COMPONENT altsyncram + GENERIC ( + address_reg_b : STRING; + clock_enable_input_a : STRING; + clock_enable_input_b : STRING; + clock_enable_output_a : STRING; + clock_enable_output_b : STRING; + indata_reg_b : STRING; + init_file : STRING; + intended_device_family : STRING; + lpm_type : STRING; + numwords_a : NATURAL; + numwords_b : NATURAL; + operation_mode : STRING; + outdata_aclr_a : STRING; + outdata_aclr_b : STRING; + outdata_reg_a : STRING; + outdata_reg_b : STRING; + power_up_uninitialized : STRING; + read_during_write_mode_port_a : STRING; + read_during_write_mode_port_b : STRING; + widthad_a : NATURAL; + widthad_b : NATURAL; + width_a : NATURAL; + width_b : NATURAL; + width_byteena_a : NATURAL; + width_byteena_b : NATURAL; + wrcontrol_wraddress_reg_b : STRING + ); + PORT ( + wren_a : IN STD_LOGIC ; + clock0 : IN STD_LOGIC ; + wren_b : IN STD_LOGIC ; + clock1 : IN STD_LOGIC ; + address_a : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0); + address_b : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0); + q_a : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0); + q_b : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0); + byteena_a : IN STD_LOGIC_VECTOR (width_a/8-1 DOWNTO 0) ; + byteena_b : IN STD_LOGIC_VECTOR (width_a/8-1 DOWNTO 0) ; + data_a : IN STD_LOGIC_VECTOR (width_a-1 DOWNTO 0); + data_b : IN STD_LOGIC_VECTOR (width_a-1 DOWNTO 0) + ); + END COMPONENT; + +BEGIN + q_a <= sub_wire0(width_a-1 DOWNTO 0); + q_b <= sub_wire1(width_a-1 DOWNTO 0); + + altsyncram_component : altsyncram + GENERIC MAP ( + address_reg_b => "CLOCK1", + clock_enable_input_a => "BYPASS", + clock_enable_input_b => "BYPASS", + clock_enable_output_a => "BYPASS", + clock_enable_output_b => "BYPASS", + indata_reg_b => "CLOCK1", + init_file => init_file, + intended_device_family => "Cyclone III", + lpm_type => "altsyncram", + numwords_a => 2**widthad_a, + numwords_b => 2**widthad_a, + operation_mode => "BIDIR_DUAL_PORT", + outdata_aclr_a => "NONE", + outdata_aclr_b => "NONE", + outdata_reg_a => outdata_reg_a, + outdata_reg_b => outdata_reg_a, + power_up_uninitialized => "FALSE", + read_during_write_mode_port_a => "NEW_DATA_NO_NBE_READ", + read_during_write_mode_port_b => "NEW_DATA_NO_NBE_READ", + widthad_a => widthad_a, + widthad_b => widthad_a, + width_a => width_a, + width_b => width_a, + width_byteena_a => width_a/8, + width_byteena_b => width_a/8, + wrcontrol_wraddress_reg_b => "CLOCK1" + ) + PORT MAP ( + wren_a => wren_a, + clock0 => clock_a, + wren_b => wren_b, + clock1 => clock_b, + address_a => address_a, + address_b => address_b, + data_a => data_a, + data_b => data_b, + q_a => sub_wire0, + q_b => sub_wire1, + byteena_a => byteena_a, + byteena_b => byteena_b + ); + + + +END SYN; diff --git a/Arcade_MiST/Konami Iron Horse/rtl/ironhorse_fm_lpf.sv b/Arcade_MiST/Konami Iron Horse/rtl/ironhorse_fm_lpf.sv new file mode 100644 index 00000000..37eb3294 --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/rtl/ironhorse_fm_lpf.sv @@ -0,0 +1,60 @@ +/*MIT License + +Copyright (c) 2019 Gregory Hogan (Soltan_G42) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ + +//This is a variation of Gregory Hogan's MISTer Genesis core low-pass filter +//tuned to low-pass filter the FM part of the YM2203 on Iron Horse. + +module ironhorse_fm_lpf( + input clk, + input reset, + input signed [15:0] in, + output signed [15:0] out); + + localparam [9:0] div = 128; //Sample at 49.152MHz/128 = 384000Hz + + //Coefficients computed with Octave/Matlab/Online filter calculators. + //or with scipy.signal.bessel or similar tools + + //0.037979203, 0.037979203 + //1.0000000, -0.92404159 + reg signed [17:0] A2; + reg signed [17:0] B2; + reg signed [17:0] B1; + + wire signed [15:0] audio_post_lpf1; + + always @ (*) begin + A2 = -18'd30278; + B1 = 18'd1245; + B2 = 18'd1245; + end + + iir_1st_order lpf6db(.clk(clk), + .reset(reset), + .div(div), + .A2(A2), + .B1(B1), + .B2(B2), + .in(in), + .out(audio_post_lpf1)); + + assign out = audio_post_lpf1; + +endmodule diff --git a/Arcade_MiST/Konami Iron Horse/rtl/ironhorse_ssg_lpf.sv b/Arcade_MiST/Konami Iron Horse/rtl/ironhorse_ssg_lpf.sv new file mode 100644 index 00000000..8c40f2e4 --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/rtl/ironhorse_ssg_lpf.sv @@ -0,0 +1,61 @@ +/*MIT License + +Copyright (c) 2019 Gregory Hogan (Soltan_G42) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ + +//This is a variation of Gregory Hogan's MISTer Genesis core low-pass filter +//tuned for the switchable low-pass filters the SSG part of the YM2203 on +//Iron Horse. + +module ironhorse_ssg_lpf( + input clk, + input reset, + input signed [15:0] in, + output signed [15:0] out); + + localparam [9:0] div = 256; //Sample at 49.152MHz/96 = 192000Hz + + //Coefficients computed with Octave/Matlab/Online filter calculators. + //or with scipy.signal.bessel or similar tools + + //0.0079883055, 0.0079883055 + //1.0000000, -0.98402339 + reg signed [17:0] A2; + reg signed [17:0] B2; + reg signed [17:0] B1; + + wire signed [15:0] audio_post_lpf1; + + always @ (*) begin + A2 = -18'd32244; + B1 = 18'd262; + B2 = 18'd262; + end + + iir_1st_order lpf6db(.clk(clk), + .reset(reset), + .div(div), + .A2(A2), + .B1(B1), + .B2(B2), + .in(in), + .out(audio_post_lpf1)); + + assign out = audio_post_lpf1; + +endmodule diff --git a/Arcade_MiST/Konami Iron Horse/rtl/jt49_dcrm2.v b/Arcade_MiST/Konami Iron Horse/rtl/jt49_dcrm2.v new file mode 100644 index 00000000..4b434aec --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/rtl/jt49_dcrm2.v @@ -0,0 +1,62 @@ +/* This file is part of JT49. + + JT49 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT49 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT49. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 15-Jan-2019 + + */ + +// DC removal filter +// input is unsigned +// output is signed + +module jt49_dcrm2 #(parameter sw=8) ( + input clk, + input cen, + input rst, + input [sw-1:0] din, + output signed [sw-1:0] dout +); + +localparam dw=10; // widht 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:0] pre_dout; +// reg signed [sw+dw:0] dout_ext; +reg signed [sw:0] q; + +always @(*) begin + exact = integ+error; + q = exact[sw+dw:dw]; + pre_dout = { 1'b0, din } - q; + //dout_ext = { pre_dout, {dw{1'b0}} }; + //mult = dout_ext; +end + +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}}; + end else if( cen ) begin + integ <= integ + pre_dout; //mult[sw+dw*2:dw]; + error <= exact-{q, {dw{1'b0}}}; + end + +endmodule \ No newline at end of file diff --git a/Arcade_MiST/Konami Iron Horse/rtl/jtframe_frac_cen.v b/Arcade_MiST/Konami Iron Horse/rtl/jtframe_frac_cen.v new file mode 100644 index 00000000..8707e766 --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/rtl/jtframe_frac_cen.v @@ -0,0 +1,58 @@ +/////////////////////////////////////////////////////////////////////////// +// Fractional clock enable signal +// W refers to the number of divided down cen signals available +// each one is divided by 2 + +module jtframe_frac_cen #(parameter W=2)( + input clk, + input [9:0] n, // numerator + input [9:0] m, // denominator + output reg [W-1:0] cen, + output reg [W-1:0] cenb // 180 shifted +); + +wire [10:0] step={1'b0,n}; +wire [10:0] lim ={1'b0,m}; +wire [10:0] absmax = lim+step; + +reg [10:0] cencnt=11'd0; +reg [10:0] next; +reg [10:0] next2; + +always @(*) begin + next = cencnt+step; + next2 = next-lim; +end + +reg half = 1'b0; +wire over = next>=lim; +wire halfway = next >= (lim>>1) && !half; + +reg [W-1:0] edgecnt = {W{1'b0}}; +wire [W-1:0] next_edgecnt = edgecnt + 1'b1; +wire [W-1:0] toggle = next_edgecnt & ~edgecnt; + +always @(posedge clk) begin + cen <= {W{1'b0}}; + cenb <= {W{1'b0}}; + + if( cencnt >= absmax ) begin + // something went wrong: restart + cencnt <= 11'd0; + end else + if( halfway ) begin + half <= 1'b1; + cenb[0] <= 1'b1; + end + if( over ) begin + cencnt <= next2; + half <= 1'b0; + edgecnt <= next_edgecnt; + cen <= { toggle[W-2:0], 1'b1 }; + end else begin + cencnt <= next; + end +end + + +endmodule \ No newline at end of file diff --git a/Arcade_MiST/Konami Iron Horse/rtl/k005885.sv b/Arcade_MiST/Konami Iron Horse/rtl/k005885.sv new file mode 100644 index 00000000..f8dff57a --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/rtl/k005885.sv @@ -0,0 +1,992 @@ +//============================================================================ +// +// SystemVerilog implementation of the Konami 005885 custom tilemap +// generator +// Graphics logic based on the video section of the Green Beret core for +// MiSTer by MiSTer-X +// Copyright (C) 2020, 2022 Ace +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +//============================================================================ + +//Note: This model of the 005885 cannot be used as-is to replace an original 005885. + +module k005885 +( + input CK49, //49.152MHz clock input + output NCK2, //6.144MHz clock output + output H1O, //3.072MHz clock output + output NCPE, //E clock for MC6809E + output NCPQ, //Q clock for MC6809E + output NEQ, //AND of E and Q clocks for MC6809E + input NRD, //Read enable (active low) + output NRES, //Reset passthrough + input [13:0] A, //Address bus from CPU + input [7:0] DBi, //Data bus input from CPU + output [7:0] DBo, //Data output to CPU + output [3:0] VCF, //Color address to tilemap LUT PROM + output [3:0] VCB, //Tile index to tilemap LUT PROM + input [3:0] VCD, //Data input from tilemap LUT PROM + output [3:0] OCF, //Color address to sprite LUT PROM + output [3:0] OCB, //Sprite index to sprite LUT PROM + input [3:0] OCD, //Data input from sprite LUT PROM + output [4:0] COL, //Color data output from color mixer + input NEXR, //Reset input (active low) + input NXCS, //Chip select (active low) + output NCSY, //Composite sync (active low) + output NHSY, //HSync (active low) - Not exposed on the original chip + output NVSY, //VSync (active low) + output HBLK, //HBlank (active high) - Not exposed on the original chip + output VBLK, //VBlank (active high) - Not exposed on the original chip + input NBUE, //Unknown + output NFIR, //Fast IRQ (FIRQ) output for MC6809E + output NIRQ, //IRQ output for MC6809E (VBlank IRQ) + output NNMI, //Non-maskable IRQ (NMI) for MC6809E + output NIOC, //Inverse of address line A11 for external address decoding logic + output NRMW, + + //Split I/O for tile and sprite data + output [15:0] R, //Address output to graphics ROMs (tiles) + input [7:0] RDU, //Upper 8 bits of graphics ROM data (tiles) + input [7:0] RDL, //Lower 8 bits of graphics ROM data (tiles) + output [15:0] S, //Address output to graphics ROMs (sprites) + output reg S_req = 0, + input S_ack, + input [7:0] SDU, //Upper 8 bits of graphics ROM data (sprites) + input [7:0] SDL, //Lower 8 bits of graphics ROM data (sprites) + + //Extra inputs for screen centering (alters HSync and VSync timing to reposition the video output) + input [3:0] HCTR, VCTR, + + //Special flag for reconfiguring the chip to mimic the anomalies found on bootlegs of games that use the 005885 + //Valid values: + //-00: Original behavior + //-01: Jackal bootleg (faster video timings, missing 4 lines from the video signal, misplaced HBlank, altered screen + // centering, sprite layer is missing one line per sprite, sprite layer is misplaced by one line when the screen is + // flipped) + //-10: Iron Horse bootleg (10 extra vertical lines resulting in slower VSync, altered screen centering, sprite layer is + // offset vertically by 1 line, sprite limit significantly lower than normal) + input [1:0] BTLG, + //Extra data outputs for graphics ROMs + output reg ATR4, //Tilemap attribute bit 4 + output reg ATR5 //Tilemap attribute bit 5 + + `ifdef MISTER_HISCORE + //MiSTer high score system I/O (to be used only with Iron Horse) + , + input [11:0] hs_address, + input [7:0] hs_data_in, + output [7:0] hs_data_out, + input hs_write_enable, + input hs_access_read, + input hs_access_write + `endif +); + +//------------------------------------------------------- Signal outputs -------------------------------------------------------// + +//Reset line passthrough +assign NRES = NEXR; + +//Generate NIOC output (active low) +assign NIOC = ~(~NXCS & (A[13:11] == 3'b001)); + +//TODO: The timing of the NRMW output is currently unknown - set to 1 for now +assign NRMW = 1; + +//Output bits 4 and 5 of tilemap attributes for graphics ROM addressing +/* +assign ATR4 = tile_ctrl[2] ? tile_attrib_D[4] : tile0_attrib_D[4]; +assign ATR5 = tile_ctrl[2] ? tile_attrib_D[5] : tile0_attrib_D[5]; +*/ +//Data output to CPU +assign DBo = (ram_cs & ~NRD) ? ram_Dout: + (zram0_cs & ~NRD) ? zram0_Dout: + (zram1_cs & ~NRD) ? zram1_Dout: + (zram2_cs & ~NRD) ? zram2_Dout: + (tile_attrib_cs & ~NRD) ? tile0_attrib_Dout: + (tile_cs & ~NRD) ? tile0_Dout: + (tile1_attrib_cs & ~NRD) ? tile1_attrib_Dout: + (tile1_cs & ~NRD) ? tile1_Dout: + (spriteram_cs & ~NRD) ? spriteram_Dout: + 8'hFF; + +//------------------------------------------------------- Clock division -------------------------------------------------------// + +//Divide the incoming 49.152MHz clock to 6.144MHz and 3.072MHz +reg [3:0] div = 4'd0; +always_ff @(posedge CK49) begin + div <= div + 4'd1; +end +wire cen_6m = !div[2:0]; +wire cen_3m = !div; +assign NCK2 = div[2]; +assign H1O = div[3]; + +//The MC6809E requires two identical clocks with a 90-degree offset - assign these here +reg mc6809e_E = 0; +reg mc6809e_Q = 0; +always_ff @(posedge CK49) begin + reg [1:0] clk_phase = 0; + if(cen_6m) begin + clk_phase <= clk_phase + 1'd1; + case(clk_phase) + 2'b00: mc6809e_E <= 0; + 2'b01: mc6809e_Q <= 1; + 2'b10: mc6809e_E <= 1; + 2'b11: mc6809e_Q <= 0; + endcase + end +end +assign NCPQ = mc6809e_Q; +assign NCPE = mc6809e_E; + +//Output NEQ combines NCPE and NCPQ together via an AND gate - assign this here +assign NEQ = NCPE & NCPQ; + +//-------------------------------------------------------- Video timings -------------------------------------------------------// + +//The 005885's video output has 384 horziontal lines and 262 vertical lines with an active resolution of 240x224. Declare both +//counters as 9-bit registers. +reg [8:0] h_cnt = 9'd0; +reg [8:0] v_cnt = 9'd0; + +//Increment horizontal counter on every falling edge of the pixel clock and increment vertical counter when horizontal counter +//rolls over +reg hblank = 0; +reg vblank = 0; +reg frame_odd_even = 0; +//Add an extra 10 lines to the vertical counter if a bootleg Iron Horse ROM set is loaded or remove 9 lines from the vertical +//counter if a bootleg Jackal ROM set is loaded +reg [8:0] vcnt_end = 0; +always_ff @(posedge CK49) begin + if(cen_6m) begin + if(BTLG == 2'b01) + vcnt_end <= 9'd252; + else if(BTLG == 2'b10) + vcnt_end <= 9'd271; + else + vcnt_end <= 9'd261; + end +end +//Reposition HSync and VSync if a bootleg Iron Horse or Jackal ROM set is loaded +reg [8:0] hsync_start = 9'd0; +reg [8:0] hsync_end = 9'd0; +reg [8:0] vsync_start = 9'd0; +reg [8:0] vsync_end = 9'd0; +always_ff @(posedge CK49) begin + if(BTLG == 2'b01) begin + hsync_start <= HCTR[3] ? 9'd287 : 9'd295; + hsync_end <= HCTR[3] ? 9'd318 : 9'd326; + vsync_start <= 9'd244; + vsync_end <= 9'd251; + end + else if(BTLG == 2'b10) begin + hsync_start <= HCTR[3] ? 9'd290 : 9'd310; + hsync_end <= HCTR[3] ? 9'd321 : 9'd341; + vsync_start <= 9'd255; + vsync_end <= 9'd262; + end + else if(tile_ctrl[2]) begin + hsync_start <= HCTR[3] ? 9'd312 : 9'd320; + hsync_end <= HCTR[3] ? 9'd343 : 9'd351; + vsync_start <= 9'd254; + vsync_end <= 9'd261; + end + else begin + hsync_start <= HCTR[3] ? 9'd288 : 9'd296; + hsync_end <= HCTR[3] ? 9'd319 : 9'd327; + vsync_start <= 9'd254; + vsync_end <= 9'd261; + end +end +always_ff @(posedge CK49) begin + if(cen_6m) begin + case(h_cnt) + //HBlank ends two lines earlier than normal on bootleg Jackal PCBs + 10: begin + if(BTLG == 2'b01) + hblank <= 0; + h_cnt <= h_cnt + 9'd1; + end + 12: begin + if(BTLG != 2'b01) + hblank <= 0; + h_cnt <= h_cnt + 9'd1; + end + //Shift the start of HBlank two lines earlier when bootleg Jackal ROMs are loaded + 250: begin + if(BTLG == 2'b01 && !tile_ctrl[2]) + hblank <= 1; + h_cnt <= h_cnt + 9'd1; + end + 252: begin + if(BTLG != 2'b01 && !tile_ctrl[2]) + hblank <= 1; + h_cnt <= h_cnt + 9'd1; + end + //Shift the start of HBlank 40 lines later when using the wider 280x224 video mode + 292: begin + if(tile_ctrl[2]) + hblank <= 1; + h_cnt <= h_cnt + 9'd1; + end + 383: begin + h_cnt <= 0; + case(v_cnt) + 15: begin + vblank <= 0; + v_cnt <= v_cnt + 9'd1; + end + 239: begin + vblank <= 1; + frame_odd_even <= ~frame_odd_even; + v_cnt <= v_cnt + 9'd1; + end + vcnt_end: begin + v_cnt <= 9'd0; + end + default: v_cnt <= v_cnt + 9'd1; + endcase + end + default: h_cnt <= h_cnt + 9'd1; + endcase + end +end + +//Output HBlank and VBlank (both active high) +assign HBLK = hblank; +assign VBLK = vblank; + +//Generate horizontal sync and vertical sync (both active low) +assign NHSY = HCTR[3] ? ~(h_cnt >= hsync_start - ~HCTR[2:0] && h_cnt <= hsync_end - ~HCTR[2:0]): + ~(h_cnt >= hsync_start + HCTR[2:0] && h_cnt <= hsync_end + HCTR[2:0]); +assign NVSY = ~(v_cnt >= vsync_start - VCTR && v_cnt <= vsync_end - VCTR); +assign NCSY = NHSY ^ NVSY; + +//------------------------------------------------------------- IRQs -----------------------------------------------------------// + +//Edge detection for VBlank and vertical counter bits 4 and 5 for IRQ generation +reg old_vblank, old_vcnt4, old_vcnt5; +always_ff @(posedge CK49) begin + old_vcnt4 <= v_cnt[4]; + old_vcnt5 <= v_cnt[5]; + old_vblank <= vblank; +end + +//IRQ (triggers every VBlank) +reg vblank_irq = 1; +always_ff @(posedge CK49) begin + if(!NEXR || !irq_mask) + vblank_irq <= 1; + else if(!old_vblank && vblank) + vblank_irq <= 0; +end +assign NIRQ = vblank_irq; + +//NMI (triggers on the falling edge of vertical counter bits 4 or 5 based on the state of tile control register bit 2) +reg nmi = 1; +always_ff @(posedge CK49) begin + if(!NEXR || !nmi_mask) + nmi <= 1; + else begin + if(tile_ctrl[2]) begin + if(old_vcnt4 && !v_cnt[4]) + nmi <= 0; + end + else begin + if(old_vcnt5 && !v_cnt[5]) + nmi <= 0; + end + end +end +assign NNMI = nmi; + +//FIRQ (triggers every second VBlank) +reg firq = 1; +always_ff @(posedge CK49) begin + if(!NEXR || !firq_mask) + firq <= 1; + else begin + if(frame_odd_even && !old_vblank && vblank) + firq <= 0; + end +end +assign NFIR = firq; + +//----------------------------------------------------- Internal registers -----------------------------------------------------// + +//The 005885 has five 8-bit registers set up as follows according to information in konamiic.txt found in MAME's source code: +/* +control registers +000: scroll y +001: scroll x (low 8 bits) +002: -------x scroll x (high bit) + ----xxx- row/colscroll control + 000 = solid scroll (finalizr, ddribble bg) + 100 = solid scroll (jackal) + 001 = ? (ddribble fg) + 011 = colscroll (jackal high scores) + 101 = rowscroll (ironhors, jackal map) +003: ------xx high bits of the tile code + -----x-- unknown (finalizr) + ----x--- selects sprite buffer (and makes a copy to a private buffer?) + --x----- unknown (ironhors) + -x------ unknown (ironhors) + x------- unknown (ironhors, jackal) +004: -------x nmi enable + ------x- irq enable + -----x-- firq enable + ----x--- flip screen +*/ + +wire regs_cs = ~NXCS & (A[13:11] == 2'b00) & (A[6:3] == 4'd0); + +reg [7:0] scroll_y, scroll_x, scroll_ctrl, tile_ctrl; +reg nmi_mask = 0; +reg irq_mask = 0; +reg firq_mask = 0; +reg flipscreen = 0; + +//Write to the appropriate register +always_ff @(posedge CK49) begin + reg rightD, leftD, upD; + if(cen_3m) begin + if(regs_cs && NRD) + case(A[2:0]) + 3'b000: scroll_y <= DBi; + 3'b001: scroll_x <= DBi; + 3'b010: scroll_ctrl <= DBi; + 3'b011: tile_ctrl <= DBi; + 3'b100: begin + nmi_mask <= DBi[0]; + irq_mask <= DBi[1]; + firq_mask <= DBi[2]; + flipscreen <= DBi[3]; + end + default; + endcase + end +end + +//--------------------------------------------------------- Unknown RAM --------------------------------------------------------// + +wire ram_cs = ~NXCS & (A >= 14'h0005 && A <= 14'h001F); + +wire [7:0] ram_Dout; +spram #(8, 5) RAM +( + .clk(CK49), + .we(ram_cs & NRD), + .addr(A[4:0]), + .data(DBi), + .q(ram_Dout) +); + +//-------------------------------------------------------- Internal ZRAM -------------------------------------------------------// + +wire zram0_cs = ~NXCS & (A >= 16'h0020 && A <= 16'h003F); +wire zram1_cs = ~NXCS & (A >= 16'h0040 && A <= 16'h005F); +wire zram2_cs = ~NXCS & (A >= 16'h0060 && A <= 16'h00DF); + +//The 005885 addresses ZRAM with either horizontal or vertical position bits depending on whether its scroll mode is set to +//line scroll or column scroll - use vertical position bits for line scroll and horizontal position bits for column scroll, +//otherwise don't address it +wire [4:0] zram_A = (scroll_ctrl[3:1] == 3'b101) ? tilemap_vpos[7:3]: + (scroll_ctrl[3:1] == 3'b011) ? tilemap_hpos[7:3]: + 5'h00; +wire [7:0] zram0_D, zram1_D, zram2_D, zram0_Dout, zram1_Dout, zram2_Dout; +dpram_dc #(.widthad_a(5)) ZRAM0 +( + .clock_a(CK49), + .address_a(A[4:0]), + .data_a(DBi), + .q_a(zram0_Dout), + .wren_a(zram0_cs & NRD), + + .clock_b(CK49), + .address_b(zram_A), + .q_b(zram0_D) +); +spram #(8, 5) ZRAM1 +( + .clk(CK49), + .we(zram1_cs & NRD), + .addr(A[4:0]), + .data(DBi), + .q(zram1_Dout) +); +spram #(8, 5) ZRAM2 +( + .clk(CK49), + .we(zram2_cs & NRD), + .addr(A[4:0]), + .data(DBi), + .q(zram2_Dout) +); + +//------------------------------------------------------------ VRAM ------------------------------------------------------------// + +//VRAM is external to the 005885 and combines multiple banks into a single 8KB RAM chip for tile attributes and data (two layers), +//and two sprite banks. For simplicity, this RAM has been made internal to the 005885 implementation and split into its +//constituent components. +wire tile_attrib_cs = ~NXCS & (A[13:10] == 4'b1000); +wire tile_cs = ~NXCS & (A[13:10] == 4'b1001); +wire tile1_attrib_cs = ~NXCS & (A[13:10] == 4'b1010); +wire tile1_cs = ~NXCS & (A[13:10] == 4'b1011); +wire spriteram_cs = ~NXCS & (A[13:12] == 2'b11); + +wire [7:0] tile0_attrib_Dout, tile0_Dout, tile1_attrib_Dout, tile1_Dout, spriteram_Dout; +wire [7:0] tile0_attrib_D, tile0_D, tile1_attrib_D, tile1_D, spriteram_D; +//Tilemap layer 0 +dpram_dc #(.widthad_a(10)) VRAM_TILEATTRIB0 +( + .clock_a(CK49), + .address_a(A[9:0]), + .data_a(DBi), + .q_a(tile0_attrib_Dout), + .wren_a(tile_attrib_cs & NRD), + + .clock_b(CK49), + .address_b(vram_A), + .q_b(tile0_attrib_D) +); +dpram_dc #(.widthad_a(10)) VRAM_TILECODE0 +( + .clock_a(CK49), + .address_a(A[9:0]), + .data_a(DBi), + .q_a(tile0_Dout), + .wren_a(tile_cs & NRD), + + .clock_b(CK49), + .address_b(vram_A), + .q_b(tile0_D) +); +//Tilemap layer 1 +dpram_dc #(.widthad_a(10)) VRAM_TILEATTRIB1 +( + .clock_a(CK49), + .address_a(A[9:0]), + .data_a(DBi), + .q_a(tile1_attrib_Dout), + .wren_a(tile1_attrib_cs & NRD), + + .clock_b(CK49), + .address_b(vram_A), + .q_b(tile1_attrib_D) +); +dpram_dc #(.widthad_a(10)) VRAM_TILECODE1 +( + .clock_a(CK49), + .address_a(A[9:0]), + .data_a(DBi), + .q_a(tile1_Dout), + .wren_a(tile1_cs & NRD), + + .clock_b(CK49), + .address_b(vram_A), + .q_b(tile1_D) +); + + + +`ifndef MISTER_HISCORE +//Sprites +dpram_dc #(.widthad_a(12)) VRAM_SPR +( + .clock_a(CK49), + .address_a(A[11:0]), + .data_a(DBi), + .q_a(spriteram_Dout), + .wren_a(spriteram_cs & NRD), + + .clock_b(~CK49), + .address_b(spriteram_A), + .q_b(spriteram_D) +); +`else +// Hiscore mux (this is only to be used with Iron Horse as its high scores are stored in sprite RAM) +// - Mirrored sprite RAM used to protect against corruption while retrieving highscore data +wire [11:0] VRAM_SPR_AD = hs_access_write ? hs_address : A[11:0]; +wire [7:0] VRAM_SPR_DIN = hs_access_write ? hs_data_in : DBi; +wire VRAM_SPR_WE = hs_access_write ? hs_write_enable : (spriteram_cs & NRD); +//Sprites +dpram_dc #(.widthad_a(12)) VRAM_SPR +( + .clock_a(CK49), + .address_a(VRAM_SPR_AD), + .data_a(VRAM_SPR_DIN), + .q_a(spriteram_Dout), + .wren_a(VRAM_SPR_WE), + + .clock_b(~CK49), + .address_b(spriteram_A), + .q_b(spriteram_D) +); +//Sprite RAM shadow for highscore read access +dpram_dc #(.widthad_a(12)) VRAM_SPR_SHADOW +( + .clock_a(CK49), + .address_a(VRAM_SPR_AD), + .data_a(VRAM_SPR_DIN), + .wren_a(VRAM_SPR_WE), + + .clock_b(CK49), + .address_b(hs_address), + .q_b(hs_data_out) +); +`endif + +//-------------------------------------------------------- Tilemap layer -------------------------------------------------------// + +//The Konami 005885 contains two tilemap layers. Finalizer - Super Transformation uses the second layer to draw the HUD at the +//top of the screen. Latch tilemap data out of bank 0 or bank 1 of the tilemap section of VRAM based on how far the game has +//drawn the tilemap layer when tile control bit 2 is set, otherwise grab tilemap data from bank 0 of the tilemap section of VRAM +//at all times + +//Loosely based on TimePilot 84's schematics +reg [7:0] tile_attrib_D, tile_D; +wire tile1_en = flipscreen ? h_cnt > 9'd243 : h_cnt < 9'd40; +wire [5:0] tile_hoffset = tile_ctrl[2] ? (~tile1_en ? (flipscreen ? 6'd4 : 6'd32) : 6'd0) : (flipscreen ? 6'd4 : 6'd0); + +always_ff @(posedge CK49) begin + if (cen_6m) begin + if(h_cnt[1:0] == 2'b01) begin // posedge of h_cnt[1] + if(tile_ctrl[2] && tile1_en) begin + tile_D <= tile1_D; + tile_attrib_D <= tile1_attrib_D; + end + else begin + tile_D <= tile0_D; + tile_attrib_D <= tile0_attrib_D; + end + end + end +end + +//XOR horizontal and vertical counter bits with flipscreen bit +wire [8:0] hcnt_x = h_cnt ^ {9{flipscreen}}; +wire [8:0] vcnt_x = v_cnt ^ {9{flipscreen}}; + +//Generate tilemap position by summing the XORed counter bits with their respective scroll registers or ZRAM bank 0 based on +//whether row scroll or column scroll is enabled (do not allow scrolling when drawing Finalizer - Super Transformation's HUD +//and offset the tilemap layer with this game) +wire [8:0] row_scroll = (tile_ctrl[2] & !flipscreen & tile1_en) ? 9'd0: + (tile_ctrl[2] & flipscreen & tile1_en) ? 9'd28: + (scroll_ctrl[3:1] == 3'b101) ? zram0_D : {scroll_ctrl[0], scroll_x}; +wire [8:0] col_scroll = (scroll_ctrl[3:1] == 3'b011) ? zram0_D : scroll_y; +wire [7:2] tilemap_hpos = hcnt_x[7:2] + row_scroll[7:2] - tile_hoffset[5:2] + {!tile_ctrl[2] & !flipscreen, 1'b0}/* synthesis keep */; +wire [8:0] tilemap_vpos = vcnt_x + col_scroll; + +//Address output to tilemap section of VRAM +wire [9:0] vram_A = {tilemap_vpos[7:3], tilemap_hpos[7:3]}; + +//Assign tile index as bits 5 and 6 of tilemap attributes and the tile code +wire [9:0] tile_index = {tile_attrib_D[7:6], tile_D} /* synthesis keep */; + +//XOR tile H/V flip bits with the flipscreen bit +wire tile_hflip = tile_attrib_D[4]; +wire tile_vflip = tile_attrib_D[5]; + +//Latch tile data from graphics ROMs, tile colors and tile H flip bit from VRAM on the falling edge of tilemap horizontal position +//bit 1 (direct for Finalizer) +reg [15:0] RD_lat = 16'd0; +reg [3:0] tile_color, tile_color_r; +reg tile_hflip_lat, tile_hflip_lat_r; +reg tile_vflip_lat; +reg hpos2_lat; +reg [2:0] yscroll_lat; +reg [1:0] xscroll_lat, xscroll_lat_r, xscroll_lat_rr; + +always_ff @(posedge CK49) begin + if (cen_6m) begin + if(h_cnt[1:0] == 2'b11) begin // negedge of h_cnt[1] + hpos2_lat <= tilemap_hpos[2]; + xscroll_lat <= row_scroll[1:0]; + xscroll_lat_r <= xscroll_lat; + yscroll_lat <= tilemap_vpos[2:0]; + tile_color <= tile_attrib_D[3:0]; + tile_color_r <= tile_color; + tile_hflip_lat <= tile_hflip; + tile_hflip_lat_r <= tile_hflip_lat; + tile_vflip_lat <= tile_vflip; + //Address output to graphics ROMs + R[15:4] <= {tile_ctrl[1:0], tile_index}; + //Latch graphics ROM output + RD_lat <= {RDU, RDL}; + //Output bits 4 and 5 of tilemap attributes for graphics ROM addressing + ATR4 <= tile_attrib_D[4]; + ATR5 <= tile_attrib_D[5]; + end + xscroll_lat_rr <= xscroll_lat_r; + end +end +assign R[3:0] = {yscroll_lat[2:0] ^ {3{tile_vflip_lat}}, hpos2_lat ^ tile_hflip_lat}; + +reg [3:0] tile_pixel /* synthesis keep */; +always @(*) begin + case (hcnt_x[1:0] ^ {2{tile_hflip_lat_r}}) + 2'b00: tile_pixel = RD_lat[15:12]; + 2'b01: tile_pixel = RD_lat[11: 8]; + 2'b10: tile_pixel = RD_lat[ 7: 4]; + 2'b11: tile_pixel = RD_lat[ 3: 0]; + default: ; + endcase +end + +//Address output to tilemap LUT PROM +assign VCF = tile_color_r; +assign VCB = tile_pixel; + +// latch pixel data, and generate 4 shifted pixel positions for fine scroll +reg [3:0] pix0, pix1, pix2, pix3; +always_ff @(posedge CK49) begin + if (cen_6m) begin + pix0 <= VCD; + pix1 <= pix0; + pix2 <= pix1; + pix3 <= pix2; + end +end + +// select the appropriate shifted pixel according to scroll value +reg [3:0] tilemap_D /* synthesis keep */; +wire hud_left = !flipscreen && tile_ctrl[2] && h_cnt < 52; +wire hud_right = flipscreen && tile_ctrl[2] && h_cnt > 252; +always @(*) begin + case ({2{flipscreen}} ^ xscroll_lat_rr) + 2'b00: tilemap_D = pix3; + 2'b01: tilemap_D = pix2; + 2'b10: tilemap_D = pix1; + 2'b11: tilemap_D = pix0; + default: ; + endcase + if (hud_left ) tilemap_D = pix3; + if (hud_right) tilemap_D = pix0; +end + +//Retrieve tilemap select bit from bit 1 of the tile control register XORed with bit 5 of the same register +wire tile_sel = tile_ctrl[1] ^ tile_ctrl[5]; +//Prioritize the tilemap layer when using the extended 280x224 mode for Finalizer in the score display area, otherwise give priority +//to sprites +wire tilemap_en = tile_ctrl[2] ? (hud_left | hud_right) : tile_sel; + +//-------------------------------------------------------- Sprite layer --------------------------------------------------------// + +//The following code is an adaptation of the sprite renderer from MiSTer-X's Green Beret core tweaked for the 005885's sprite format +reg [8:0] sprite_hpos = 9'd0; +reg [8:0] sprite_vpos = 9'd0; +always_ff @(posedge CK49) begin + if(cen_6m) begin + sprite_hpos <= h_cnt; + //If a bootleg Iron Horse ROM set is loaded, apply a vertical offset of 65 lines (66 when flipped) to recreate the + //bootleg hardware's 1-line downward vertical offset between the sprite and tilemap layers, otherwise apply a + //vertical offset of 66 lines (65 lines when flipped) + if(BTLG == 2'b10) + if(flipscreen) + sprite_vpos <= v_cnt + 9'd66; + else + sprite_vpos <= v_cnt + 9'd65; + else + if(flipscreen) + sprite_vpos <= v_cnt + 9'd65; + else + sprite_vpos <= v_cnt + 9'd66; + end +end + +//Sprite state machine +reg [8:0] sprite_index; +reg [2:0] sprite_offset; +reg [2:0] sprite_fsm_state; +reg [11:0] sprite_code; +reg [8:0] sprite_limit; +reg [8:0] sprite_x; +reg [7:0] sprite_y; +reg [5:0] sprite_width; +reg [3:0] sprite_color; +reg [2:0] sprite_size; +reg sprite_hflip, sprite_vflip, sprite_x8_sel, sprite_x8_vram; +wire [8:0] sprite_fsm_reset = tile_ctrl[2] ? 9'd40 : 9'd0; +always_ff @(posedge CK49) begin + //Bootleg Iron Horse PCBs have a lower-than-normal sprite limit causing noticeable sprite flickering - reduce the sprite limit + //to 32 sprites (0 - 155 in increments of 5) if one such ROM set is loaded (render 96 sprites at once, 0 - 485 in increments of + //5, otherwise) + sprite_limit <= (BTLG == 2'b10) ? 9'd155 : 9'd485; + //Reset the sprite state machine whenever the sprite horizontal postion, and in turn the horziontal counter, returns to 0 + //Also hold the sprite state machine in this initial state for the first line while drawing sprites for bootleg Iron Horse + //ROM sets to prevent graphical garbage from occurring on the top-most line + if(sprite_hpos == sprite_fsm_reset || (BTLG == 2'b10 && (!flipscreen && sprite_vpos <= 9'd80) || (flipscreen && sprite_vpos >= 9'd304))) begin + sprite_width <= 0; + sprite_index <= 0; + sprite_offset <= 3'd4; + sprite_fsm_state <= 1; + end + else + case(sprite_fsm_state) + 0: /* empty */ ; + 1: begin + //If the sprite limit is reached, hold the state machine in an empty state, otherwise latch the sprite H/V flip + //bits, sprite size, bit 8 of the sprite X position and its select bit + if(sprite_index > sprite_limit) + sprite_fsm_state <= 0; + else begin + sprite_vflip <= spriteram_D[6] ^ ~flipscreen; + sprite_hflip <= spriteram_D[5] ^ flipscreen; + sprite_size <= spriteram_D[4:2]; + sprite_x8_sel <= spriteram_D[1]; + sprite_x8_vram <= spriteram_D[0]; + sprite_offset <= 3'd3; + sprite_fsm_state <= sprite_fsm_state + 3'd1; + end + end + 2: begin + //Latch sprite X position and set the 9th bit as either the one latched previously from VRAM or the AND of position + //bits [7:3] based on the state of the select bit + if(sprite_x8_sel) + sprite_x[8] <= sprite_x8_vram ^ flipscreen; + else + sprite_x[8] <= (&spriteram_D[7:3]) ^ flipscreen; + sprite_x[7:0] <= spriteram_D ^ {8{flipscreen}}; + sprite_offset <= 3'd2; + sprite_fsm_state <= sprite_fsm_state + 3'd1; + end + 3: begin + //Latch sprite Y position + sprite_y <= spriteram_D; + sprite_offset <= 3'd1; + sprite_fsm_state <= sprite_fsm_state + 3'd1; + end + 4: begin + //Skip the current sprite if it's inactive, otherwise latch sprite color and the upper/lower 2 bits of the sprite + //code, and continue scanning out the rest of the sprite attributes + if(sprite_active) begin + sprite_color <= spriteram_D[7:4]; + sprite_code[1:0] <= spriteram_D[3:2]; + sprite_code[11:10] <= spriteram_D[1:0]; + sprite_offset <= 3'd0; + sprite_fsm_state <= sprite_fsm_state + 3'd1; + end + else begin + sprite_index <= sprite_index + 9'd5; + sprite_offset <= 3'd4; + sprite_fsm_state <= 3'd1; + end + end + 5: begin + //Latch bits [9:2] of the sprite code and set up the sprite width based on the sprite size + sprite_code[9:2] <= spriteram_D; + sprite_offset <= 3'd4; + sprite_index <= sprite_index + 9'd5; + case(sprite_size) + 3'b000: sprite_width <= 6'b110000 + (BTLG == 2'b01 && flipscreen); + 3'b001: sprite_width <= 6'b110000 + (BTLG == 2'b01 && flipscreen); + 3'b010: sprite_width <= 6'b111000 + (BTLG == 2'b01 && flipscreen); + 3'b011: sprite_width <= 6'b111000 + (BTLG == 2'b01 && flipscreen); + default: sprite_width <= 6'b100000 + (BTLG == 2'b01 && flipscreen); + endcase + sprite_fsm_state <= sprite_fsm_state + 3'd1; + S_req <= !S_req; + end + 6: if (S_req == S_ack) begin + //Skip the last line of a sprite if a bootleg Jackal ROM set is loaded (the hardware on such bootlegs fails + //to render the last line of sprites), otherwise write sprites as normal + if(BTLG == 2'b01 && !flipscreen) + if(sprite_width == 6'b111110) + sprite_width <= sprite_width + 6'd2; + else + sprite_width <= sprite_width + 6'd1; + else + sprite_width <= sprite_width + 6'd1; + sprite_fsm_state <= wre ? sprite_fsm_state : 3'd1; + S_req <= (wre & sprite_width[1:0] == 2'b11) ? !S_req : S_req; + + end + default:; + endcase +end + +//Adjust sprite code based on sprite size +wire [11:0] sprite_code_sized = sprite_size == 3'b000 ? {sprite_code[11:2], ly[3], lx[3]}: //16x16 + sprite_size == 3'b001 ? {sprite_code[11:1], lx[3]}: //16x8 + sprite_size == 3'b010 ? {sprite_code[11:2], ly[3], sprite_code[0]}: //8x16 + sprite_size == 3'b011 ? sprite_code: //8x8 + {sprite_code[11:2] + {ly[4], lx[4]}, ly[3], lx[3]}; //32x32 + +//Subtract vertical sprite position from sprite Y parameter to obtain sprite height +wire [8:0] sprite_height = {(sprite_y[7:4] == 4'hF), sprite_y ^ {8{flipscreen}}} - sprite_vpos; + +//Set when a sprite is active depending on whether it is 8, 16 or 32 pixels tall +reg sprite_active; +always @(*) begin + case(sprite_size) + 3'b000: sprite_active = (sprite_height[8:7] == 2'b11) & (sprite_height[6] ^ ~flipscreen) & (sprite_height[5] ^ flipscreen) + & (sprite_height[4] ^ flipscreen); + 3'b001: sprite_active = (sprite_height[8:7] == 2'b11) & (sprite_height[6] ^ ~flipscreen) & (sprite_height[5] ^ flipscreen) + & (sprite_height[4] ^ flipscreen) & (sprite_height[3] ^ flipscreen); + 3'b010: sprite_active = (sprite_height[8:7] == 2'b11) & (sprite_height[6] ^ ~flipscreen) & (sprite_height[5] ^ flipscreen) + & (sprite_height[4] ^ flipscreen); + 3'b011: sprite_active = (sprite_height[8:7] == 2'b11) & (sprite_height[6] ^ ~flipscreen) & (sprite_height[5] ^ flipscreen) + & (sprite_height[4] ^ flipscreen) & (sprite_height[3] ^ flipscreen); + 3'b100: sprite_active = (sprite_height[8:7] == 2'b11) & (sprite_height[6] ^ ~flipscreen) & (sprite_height[5] ^ flipscreen); + default: sprite_active = (sprite_height[8:7] == 2'b11) & (sprite_height[6] ^ ~flipscreen) & (sprite_height[5] ^ flipscreen); + endcase +end + +wire [4:0] lx = sprite_width[4:0] ^ {5{sprite_hflip}}; +wire [4:0] ly = sprite_height[4:0] ^ {5{sprite_vflip}}; + +//Assign address outputs to sprite ROMs +assign S = {sprite_code_sized, ly[2:0], lx[2]}; + +//Multiplex sprite ROM data down from 16 bits to 8 using bit 1 of the horizontal position +wire [7:0] SD = lx[1] ? SDL : SDU; + +//Further multiplex sprite ROM data down from 8 bits to 4 using bit 0 of the horizontal position +wire [3:0] sprite_pixel = lx[0] ? SD[3:0] : SD[7:4]; + +//Sum the sprite index with the sprite offset and address sprite RAM with it along with tile control register bit 3 +wire [8:0] sprite_address = (sprite_index + sprite_offset); +reg sprite_bank = 0; +reg old_vsync; +//Normally, the 005885 latches the sprite bank from bit 3 of the tile control register on the rising edge of VSync, though this causes +//jerky scrolling with sprites for bootleg Jackal ROM sets - bypass this latch if such ROM sets are loaded +//Finalizer - Super Transformation only reads sprite information from the lower sprite bank +always_ff @(posedge CK49) begin + old_vsync <= NVSY; + if(!NEXR) + sprite_bank <= 0; + else if(!old_vsync && NVSY) + sprite_bank <= tile_ctrl[3]; +end +wire [11:0] spriteram_A = {(BTLG == 2'b01) ? tile_ctrl[3] : sprite_bank, 2'b00, sprite_address}; + +//Address output to sprite LUT PROM +assign OCF = sprite_color; +assign OCB = sprite_pixel; + +//----------------------------------------------------- Sprite line buffer -----------------------------------------------------// + +//The sprite line buffer is external to the 005885 and consists of two 4464 DRAM chips. For simplicity, both the logic for the +//sprite line buffer and the sprite line buffer itself are internal to the 005885 implementation. + +//Enable writing to sprite line buffer when bit 5 of the sprite width is 1 +wire wre = sprite_width[5]; + +//Set sprite line buffer bank as bit 0 of the sprite vertical position +wire sprite_lbuff_bank = sprite_vpos[0]; + +//Sum sprite X position with the following bits of the sprite width to address the sprite line buffer based on sprite size: +//32 pixels wide: bits [4:0] +//16 pixels wide: bits [3:0] +//8 pixels wide: bits [2:0] +//XOR the upper bits for screen flipping on 16 pixel and 8 pixel wide sprites +reg [4:0] final_sprite_width; +always @(*) begin + case(sprite_size) + 3'b000: final_sprite_width = {sprite_width[4] ^ ~flipscreen, sprite_width[3:0]}; + 3'b001: final_sprite_width = {sprite_width[4] ^ ~flipscreen, sprite_width[3:0]}; + 3'b010: final_sprite_width = {sprite_width[4:3] ^ {2{~flipscreen}}, sprite_width[2:0]}; + 3'b011: final_sprite_width = {sprite_width[4:3] ^ {2{~flipscreen}}, sprite_width[2:0]}; + 3'b100: final_sprite_width = sprite_width[4:0]; + default: final_sprite_width = sprite_width[4:0]; + endcase +end +wire [8:0] wpx = sprite_x + final_sprite_width; + +//Generate sprite line buffer write addresses +reg [9:0] lbuff_A; +reg lbuff_we; +wire [3:0] lbuff_Din = OCD; +always_ff @(posedge CK49) begin + lbuff_A <= {~sprite_lbuff_bank, wpx}; + lbuff_we <= wre & S_req == S_ack; +end + +//Generate read address for sprite line buffer on the rising edge of the pixel clock (apply a -225 offset when the screen +//is flipped) +reg [9:0] radr0 = 10'd0; +reg [9:0] radr1 = 10'd1; +always_ff @(posedge CK49) begin + if(cen_6m) + radr0 <= {sprite_lbuff_bank, flipscreen ? sprite_hpos - 9'd225 : tile_ctrl[2] ? sprite_hpos - 9'd40 : sprite_hpos}; +end + +//Sprite line buffer +wire [3:0] lbuff_Dout; +dpram_dc #(.widthad_a(10)) LBUFF +( + .clock_a(CK49), + .address_a(lbuff_A), + .data_a({4'd0, lbuff_Din}), + .wren_a(lbuff_we & (lbuff_Din != 0)), + + .clock_b(CK49), + .address_b(radr0), + .data_b(8'h0), + .wren_b(radr0 == radr1), + .q_b({4'bZZZZ, lbuff_Dout}) +); + +//Latch sprite data from the sprite line buffer +wire lbuff_read_en = (div[2:0] == 3'b100); +reg [3:0] lbuff_read = 4'd0; +always_ff @(posedge CK49) begin + if(lbuff_read_en) begin + if(radr0 != radr1) + lbuff_read <= lbuff_Dout; + radr1 <= radr0; + end +end + +//Delay sprite layer by 2 horizontal lines (1 line if a bootleg Jackal ROM set is loaded and the screen is flipped) +reg [7:0] sprite_dly = 8'd0; +always_ff @(posedge CK49) begin + if(cen_6m) begin + if(BTLG == 2'b01 && flipscreen) + sprite_dly <= {4'd0, lbuff_read}; + else + sprite_dly <= {lbuff_read, sprite_dly[7:4]}; + end +end +//Jackal bootlegs fail to render the last two vertical lines of the sprite layer - model this behavior here +wire [3:0] sprite_D = (BTLG == 2'b01 && ((h_cnt >= 244 && ~flipscreen) || (h_cnt >= 248 && flipscreen))) ? 4'd0 : sprite_dly[3:0]; + +//--------------------------------------------------------- Color mixer --------------------------------------------------------// + +//Multiplex tile and sprite data, then output the final result +wire tile_sprite_sel = (tilemap_en | ~(|sprite_D)); +wire [3:0] tile_sprite_D = tile_sprite_sel ? tilemap_D : sprite_D; + +//Latch and output pixel data +reg [4:0] pixel_D; +always_ff @(posedge CK49) begin + if(cen_6m) + pixel_D <= {tile_sprite_sel, tile_sprite_D}; +end +assign COL = (BTLG == 2'b01 && ((h_cnt >= 247 && ~flipscreen) || (h_cnt <= 14 && flipscreen))) || + (BTLG == 2'b10 && ((h_cnt <= 20 && ~flipscreen) || ((h_cnt <= 18 || h_cnt >= 251) && flipscreen))) ? 5'd0 : pixel_D; +//The above condition blacks out the last 4 lines on the right side of the screen (left when flipped) when a bootleg Jackal ROM set +//is loaded and blacks out the left-most 8 lines (7 when flipped plus an extra 2 lines on the right side) when a bootleg Iron Horse +//ROM set is loaded - this simulates the earlier-than-normal start of HBlank for Jackal bootlegs and later-than-normal end of +//HBlank for Iron Horse bootlegs while maintaining the usual 240x224 display area + +endmodule diff --git a/Arcade_MiST/Konami Iron Horse/rtl/pll.qip b/Arcade_MiST/Konami Iron Horse/rtl/pll.qip new file mode 100644 index 00000000..afd958be --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/rtl/pll.qip @@ -0,0 +1,4 @@ +set_global_assignment -name IP_TOOL_NAME "ALTPLL" +set_global_assignment -name IP_TOOL_VERSION "13.1" +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "pll.v"] +set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll.ppf"] diff --git a/Arcade_MiST/Konami Iron Horse/rtl/pll.v b/Arcade_MiST/Konami Iron Horse/rtl/pll.v new file mode 100644 index 00000000..1960b7f8 --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/rtl/pll.v @@ -0,0 +1,348 @@ +// megafunction wizard: %ALTPLL% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altpll + +// ============================================================ +// File Name: pll.v +// Megafunction Name(s): +// altpll +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 13.1.4 Build 182 03/12/2014 Patches 4.26 SJ Web Edition +// ************************************************************ + + +//Copyright (C) 1991-2014 Altera Corporation +//Your use of Altera Corporation's design tools, logic functions +//and other software and tools, and its AMPP partner logic +//functions, and any output files from any of the foregoing +//(including device programming or simulation files), and any +//associated documentation or information are expressly subject +//to the terms and conditions of the Altera Program License +//Subscription Agreement, Altera MegaCore Function License +//Agreement, or other applicable license agreement, including, +//without limitation, that your use is for the sole purpose of +//programming logic devices manufactured by Altera and sold by +//Altera or its authorized distributors. Please refer to the +//applicable agreement for further details. + + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on +module pll ( + areset, + inclk0, + c0, + c1, + locked); + + input areset; + input inclk0; + output c0; + output c1; + output locked; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_off +`endif + tri0 areset; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_on +`endif + + wire [4:0] sub_wire0; + wire sub_wire2; + wire [0:0] sub_wire6 = 1'h0; + wire [0:0] sub_wire3 = sub_wire0[0:0]; + wire [1:1] sub_wire1 = sub_wire0[1:1]; + wire c1 = sub_wire1; + wire locked = sub_wire2; + wire c0 = sub_wire3; + wire sub_wire4 = inclk0; + wire [1:0] sub_wire5 = {sub_wire6, sub_wire4}; + + altpll altpll_component ( + .areset (areset), + .inclk (sub_wire5), + .clk (sub_wire0), + .locked (sub_wire2), + .activeclock (), + .clkbad (), + .clkena ({6{1'b1}}), + .clkloss (), + .clkswitch (1'b0), + .configupdate (1'b0), + .enable0 (), + .enable1 (), + .extclk (), + .extclkena ({4{1'b1}}), + .fbin (1'b1), + .fbmimicbidir (), + .fbout (), + .fref (), + .icdrclk (), + .pfdena (1'b1), + .phasecounterselect ({4{1'b1}}), + .phasedone (), + .phasestep (1'b1), + .phaseupdown (1'b1), + .pllena (1'b1), + .scanaclr (1'b0), + .scanclk (1'b0), + .scanclkena (1'b1), + .scandata (1'b0), + .scandataout (), + .scandone (), + .scanread (1'b0), + .scanwrite (1'b0), + .sclkout0 (), + .sclkout1 (), + .vcooverrange (), + .vcounderrange ()); + defparam + altpll_component.bandwidth_type = "AUTO", + altpll_component.clk0_divide_by = 105, + altpll_component.clk0_duty_cycle = 50, + altpll_component.clk0_multiply_by = 382, + altpll_component.clk0_phase_shift = "0", + altpll_component.clk1_divide_by = 105, + altpll_component.clk1_duty_cycle = 50, + altpll_component.clk1_multiply_by = 191, + altpll_component.clk1_phase_shift = "0", + altpll_component.compensate_clock = "CLK0", + altpll_component.inclk0_input_frequency = 37037, + altpll_component.intended_device_family = "Cyclone III", + altpll_component.lpm_hint = "CBX_MODULE_PREFIX=pll", + altpll_component.lpm_type = "altpll", + altpll_component.operation_mode = "NORMAL", + altpll_component.pll_type = "AUTO", + altpll_component.port_activeclock = "PORT_UNUSED", + altpll_component.port_areset = "PORT_USED", + altpll_component.port_clkbad0 = "PORT_UNUSED", + altpll_component.port_clkbad1 = "PORT_UNUSED", + altpll_component.port_clkloss = "PORT_UNUSED", + altpll_component.port_clkswitch = "PORT_UNUSED", + altpll_component.port_configupdate = "PORT_UNUSED", + altpll_component.port_fbin = "PORT_UNUSED", + altpll_component.port_inclk0 = "PORT_USED", + altpll_component.port_inclk1 = "PORT_UNUSED", + altpll_component.port_locked = "PORT_USED", + altpll_component.port_pfdena = "PORT_UNUSED", + altpll_component.port_phasecounterselect = "PORT_UNUSED", + altpll_component.port_phasedone = "PORT_UNUSED", + altpll_component.port_phasestep = "PORT_UNUSED", + altpll_component.port_phaseupdown = "PORT_UNUSED", + altpll_component.port_pllena = "PORT_UNUSED", + altpll_component.port_scanaclr = "PORT_UNUSED", + altpll_component.port_scanclk = "PORT_UNUSED", + altpll_component.port_scanclkena = "PORT_UNUSED", + altpll_component.port_scandata = "PORT_UNUSED", + altpll_component.port_scandataout = "PORT_UNUSED", + altpll_component.port_scandone = "PORT_UNUSED", + altpll_component.port_scanread = "PORT_UNUSED", + altpll_component.port_scanwrite = "PORT_UNUSED", + altpll_component.port_clk0 = "PORT_USED", + altpll_component.port_clk1 = "PORT_USED", + altpll_component.port_clk2 = "PORT_UNUSED", + altpll_component.port_clk3 = "PORT_UNUSED", + altpll_component.port_clk4 = "PORT_UNUSED", + altpll_component.port_clk5 = "PORT_UNUSED", + altpll_component.port_clkena0 = "PORT_UNUSED", + altpll_component.port_clkena1 = "PORT_UNUSED", + altpll_component.port_clkena2 = "PORT_UNUSED", + altpll_component.port_clkena3 = "PORT_UNUSED", + altpll_component.port_clkena4 = "PORT_UNUSED", + altpll_component.port_clkena5 = "PORT_UNUSED", + altpll_component.port_extclk0 = "PORT_UNUSED", + altpll_component.port_extclk1 = "PORT_UNUSED", + altpll_component.port_extclk2 = "PORT_UNUSED", + altpll_component.port_extclk3 = "PORT_UNUSED", + altpll_component.self_reset_on_loss_lock = "OFF", + altpll_component.width_clock = 5; + + +endmodule + +// ============================================================ +// CNX file retrieval info +// ============================================================ +// Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0" +// Retrieval info: PRIVATE: BANDWIDTH STRING "1.000" +// Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz" +// Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low" +// Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1" +// Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0" +// Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "0" +// Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0" +// Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0" +// Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0" +// Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0" +// Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0" +// Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "8" +// Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "105" +// Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "105" +// Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" +// Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "98.228569" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "49.114285" +// Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" +// Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" +// Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0" +// Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575" +// Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1" +// Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "27.000" +// Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +// Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1" +// Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "Not Available" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT1 STRING "ps" +// Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any" +// Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0" +// Retrieval info: PRIVATE: MIRROR_CLK1 STRING "0" +// Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "382" +// Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "191" +// Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "49.15200000" +// Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "14.31818000" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "0" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE1 STRING "0" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT1 STRING "MHz" +// Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT1 STRING "0.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT1 STRING "deg" +// Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "1" +// Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1" +// Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0" +// Retrieval info: PRIVATE: RECONFIG_FILE STRING "pll.mif" +// Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0" +// Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0" +// Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0" +// Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000" +// Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz" +// Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500" +// Retrieval info: PRIVATE: SPREAD_USE STRING "0" +// Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0" +// Retrieval info: PRIVATE: STICKY_CLK0 STRING "1" +// Retrieval info: PRIVATE: STICKY_CLK1 STRING "1" +// Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1" +// Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +// Retrieval info: PRIVATE: USE_CLK0 STRING "1" +// Retrieval info: PRIVATE: USE_CLK1 STRING "1" +// Retrieval info: PRIVATE: USE_CLKENA0 STRING "0" +// Retrieval info: PRIVATE: USE_CLKENA1 STRING "0" +// Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0" +// Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" +// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +// Retrieval info: CONSTANT: BANDWIDTH_TYPE STRING "AUTO" +// Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "105" +// Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "382" +// Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "105" +// Retrieval info: CONSTANT: CLK1_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK1_MULTIPLY_BY NUMERIC "191" +// Retrieval info: CONSTANT: CLK1_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0" +// Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "37037" +// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +// Retrieval info: CONSTANT: LPM_TYPE STRING "altpll" +// Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL" +// Retrieval info: CONSTANT: PLL_TYPE STRING "AUTO" +// Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: SELF_RESET_ON_LOSS_LOCK STRING "OFF" +// Retrieval info: CONSTANT: WIDTH_CLOCK NUMERIC "5" +// Retrieval info: USED_PORT: @clk 0 0 5 0 OUTPUT_CLK_EXT VCC "@clk[4..0]" +// Retrieval info: USED_PORT: areset 0 0 0 0 INPUT GND "areset" +// Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0" +// Retrieval info: USED_PORT: c1 0 0 0 0 OUTPUT_CLK_EXT VCC "c1" +// Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0" +// Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked" +// Retrieval info: CONNECT: @areset 0 0 0 0 areset 0 0 0 0 +// Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0 +// Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0 +// Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0 +// Retrieval info: CONNECT: c1 0 0 0 0 @clk 0 0 1 1 +// Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.ppf TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll_bb.v FALSE +// Retrieval info: LIB_FILE: altera_mf +// Retrieval info: CBX_MODULE_PREFIX: ON diff --git a/Arcade_MiST/Konami Iron Horse/rtl/rom_loader.sv b/Arcade_MiST/Konami Iron Horse/rtl/rom_loader.sv new file mode 100644 index 00000000..3f05104a --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/rtl/rom_loader.sv @@ -0,0 +1,366 @@ +//============================================================================ +// +// SD card ROM loader and ROM selector for MISTer. +// Copyright (C) 2019, 2020 Kitrinx (aka Rysha) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +//============================================================================ + +// Rom layout for Iron Horse: +// 0x0000 - 0xFFFF = eprom_1 +// 0x10000 - 0x13FFF = eprom_2 +// 0x14000 - 0x1BFFF = eprom_3 +// 0x1C000 - 0x3BFFF = maskrom_1 +// 0x3C000 - 0x5BFFF = maskrom_2 +// 0x5C000 - 0x7BFFF = maskrom_3 +// 0x7C000 - 0x9BFFF = maskrom_4 +// 0x9C000 - 0x9C0FF = prom_1 +// 0x9C100 - 0x9C1FF = prom_2 + +module selector +( + input logic [24:0] ioctl_addr, + output logic ep1_cs, ep2_cs, ep3_cs, ep4_cs, ep5_cs, ep6_cs, ep7_cs, prom1_cs, prom2_cs, prom3_cs, prom4_cs, prom5_cs +); + + always_comb begin + {ep1_cs, ep2_cs, ep3_cs, ep4_cs, ep5_cs, ep6_cs, ep7_cs, prom1_cs, prom2_cs, prom3_cs, prom4_cs, prom5_cs} = 0; + if(ioctl_addr < 'h8000) + ep1_cs = 1; // 0x8000 15 + else if(ioctl_addr < 'hC000) + ep2_cs = 1; // 0x4000 14 + else if(ioctl_addr < 'h10000) + ep3_cs = 1; // 0x4000 14 + else if(ioctl_addr < 'h18000) + ep4_cs = 1; // 0x8000 15 + else if(ioctl_addr < 'h20000) + ep5_cs = 1; // 0x8000 15 + else if(ioctl_addr < 'h28000) + ep6_cs = 1; // 0x8000 15 + else if(ioctl_addr < 'h30000) + ep7_cs = 1; // 0x8000 15 + else if(ioctl_addr < 'h30100) + prom1_cs = 1; // 0x100 8 + else if(ioctl_addr < 'h30200) + prom2_cs = 1; // 0x100 8 + else if(ioctl_addr < 'h30300) + prom3_cs = 1; // 0x100 8 + else if(ioctl_addr < 'h30400) + prom4_cs = 1; // 0x100 8 + else + prom5_cs = 1; // 0x100 8 + end +endmodule + +//////////// +// EPROMS // +//////////// + +module eprom_1 +( + input logic CLK, + input logic CLK_DL, + input logic [14:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(15)) eprom_1 + ( + .clock_a(CLK), + .address_a(ADDR[14:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[14:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module eprom_2 +( + input logic CLK, + input logic CLK_DL, + input logic [13:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(14)) eprom_2 + ( + .clock_a(CLK), + .address_a(ADDR[13:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[13:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module eprom_3 +( + input logic CLK, + input logic CLK_DL, + input logic [13:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(14)) eprom_3 + ( + .clock_a(CLK), + .address_a(ADDR[13:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[13:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module eprom_4 +( + input logic CLK, + input logic CLK_DL, + input logic [14:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(15)) eprom_4 + ( + .clock_a(CLK), + .address_a(ADDR[14:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[14:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module eprom_5 +( + input logic CLK, + input logic CLK_DL, + input logic [14:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(15)) eprom_5 + ( + .clock_a(CLK), + .address_a(ADDR[14:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[14:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module eprom_6 +( + input logic CLK, + input logic CLK_DL, + input logic [14:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(15)) eprom_6 + ( + .clock_a(CLK), + .address_a(ADDR[14:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[14:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module eprom_7 +( + input logic CLK, + input logic CLK_DL, + input logic [14:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(15)) eprom_7 + ( + .clock_a(CLK), + .address_a(ADDR[14:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[14:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +/////////// +// PROMS // +/////////// + +module prom_1 +( + input logic CLK, + input logic CLK_DL, + input logic [7:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [3:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [3:0] DATA +); + dpram_dc #(.widthad_a(8)) prom_1 + ( + .clock_a(CLK), + .address_a(ADDR), + .q_a(DATA[3:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[7:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module prom_2 +( + input logic CLK, + input logic CLK_DL, + input logic [7:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [3:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [3:0] DATA +); + dpram_dc #(.widthad_a(8)) prom_2 + ( + .clock_a(CLK), + .address_a(ADDR), + .q_a(DATA[3:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[7:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module prom_3 +( + input logic CLK, + input logic CLK_DL, + input logic [7:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [3:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [3:0] DATA +); + dpram_dc #(.widthad_a(8)) prom_3 + ( + .clock_a(CLK), + .address_a(ADDR), + .q_a(DATA[3:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[7:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module prom_4 +( + input logic CLK, + input logic CLK_DL, + input logic [7:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [3:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [3:0] DATA +); + dpram_dc #(.widthad_a(8)) prom_4 + ( + .clock_a(CLK), + .address_a(ADDR), + .q_a(DATA[3:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[7:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module prom_5 +( + input logic CLK, + input logic CLK_DL, + input logic [7:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [3:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [3:0] DATA +); + dpram_dc #(.widthad_a(8)) prom_5 + ( + .clock_a(CLK), + .address_a(ADDR), + .q_a(DATA[3:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[7:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule diff --git a/Arcade_MiST/Konami Iron Horse/rtl/sdram.sv b/Arcade_MiST/Konami Iron Horse/rtl/sdram.sv new file mode 100644 index 00000000..28b3c6ee --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/rtl/sdram.sv @@ -0,0 +1,363 @@ +// +// sdram.v +// +// sdram controller implementation for the MiST board +// https://github.com/mist-devel/mist-board +// +// Copyright (c) 2013 Till Harbaum +// Copyright (c) 2019 Gyorgy Szombathelyi +// +// This source file 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. +// +// This source file 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 this program. If not, see . +// + +module sdram ( + + // interface to the MT48LC16M16 chip + inout reg [15:0] SDRAM_DQ, // 16 bit bidirectional data bus + output reg [12:0] SDRAM_A, // 13 bit multiplexed address bus + output reg SDRAM_DQML, // two byte masks + output reg SDRAM_DQMH, // two byte masks + output reg [1:0] SDRAM_BA, // two banks + output SDRAM_nCS, // a single chip select + output SDRAM_nWE, // write enable + output SDRAM_nRAS, // row address select + output SDRAM_nCAS, // columns address select + + // cpu/chipset interface + input init_n, // init signal after FPGA config to initialize RAM + input clk, // sdram clock + + input port1_req, + output reg port1_ack, + input port1_we, + input [23:1] port1_a, + input [1:0] port1_ds, + input [15:0] port1_d, + output reg [15:0] port1_q, + + input [15:1] cpu1_addr, + output reg [15:0] cpu1_q, + input [15:1] cpu2_addr, + output reg [15:0] cpu2_q, + + input port2_req, + output reg port2_ack, + input port2_we, + input [23:1] port2_a, + input [1:0] port2_ds, + input [15:0] port2_d, + output reg [15:0] port2_q, + input [15:1] ch1_addr, + output reg [15:0] ch1_q, + input [15:1] ch2_addr, + output reg [15:0] ch2_q, + input sp1_req, + input [15:1] sp1_addr, + output reg [15:0] sp1_q, + output reg sp1_ack, + input sp2_req, + input [15:1] sp2_addr, + output reg [15:0] sp2_q, + output reg sp2_ack +); + +parameter MHZ = 16'd80; // 80 MHz default clock, set it to proper value to calculate refresh rate + +localparam RASCAS_DELAY = 3'd2; // tRCD=20ns -> 2 cycles@<100MHz +localparam BURST_LENGTH = 3'b000; // 000=1, 001=2, 010=4, 011=8 +localparam ACCESS_TYPE = 1'b0; // 0=sequential, 1=interleaved +localparam CAS_LATENCY = 3'd2; // 2/3 allowed +localparam OP_MODE = 2'b00; // only 00 (standard operation) allowed +localparam NO_WRITE_BURST = 1'b1; // 0= write burst enabled, 1=only single access write + +localparam MODE = { 3'b000, NO_WRITE_BURST, OP_MODE, CAS_LATENCY, ACCESS_TYPE, BURST_LENGTH}; + +// 64ms/8192 rows = 7.8us +localparam RFRSH_CYCLES = 16'd78*MHZ/4'd10; + +// --------------------------------------------------------------------- +// ------------------------ cycle state machine ------------------------ +// --------------------------------------------------------------------- + +/* + SDRAM state machine for 2 bank interleaved access + 1 word burst, CL2 +cmd issued registered + 0 RAS0 cas1 + 1 ras0 + 2 data1 returned + 3 CAS0 + 4 RAS1 cas0 + 5 ras1 + 6 CAS1 data0 returned +*/ + +localparam STATE_RAS0 = 3'd0; // first state in cycle +localparam STATE_RAS1 = 3'd4; // Second ACTIVE command after RAS0 + tRRD (15ns) +localparam STATE_CAS0 = STATE_RAS0 + RASCAS_DELAY + 1'd1; // CAS phase - 3 +localparam STATE_CAS1 = STATE_RAS1 + RASCAS_DELAY; // CAS phase - 6 +localparam STATE_READ0 = 3'd0;// STATE_CAS0 + CAS_LATENCY + 2'd2; // 7 +localparam STATE_READ1 = 3'd3; +localparam STATE_LAST = 3'd6; + +reg [2:0] t; + +always @(posedge clk) begin + t <= t + 1'd1; + if (t == STATE_LAST) t <= STATE_RAS0; +end + +// --------------------------------------------------------------------- +// --------------------------- startup/reset --------------------------- +// --------------------------------------------------------------------- + +// wait 1ms (32 8Mhz cycles) after FPGA config is done before going +// into normal operation. Initialize the ram in the last 16 reset cycles (cycles 15-0) +reg [4:0] reset; +reg init = 1'b1; +always @(posedge clk, negedge init_n) begin + if(!init_n) begin + reset <= 5'h1f; + init <= 1'b1; + end else begin + if((t == STATE_LAST) && (reset != 0)) reset <= reset - 5'd1; + init <= !(reset == 0); + end +end + +// --------------------------------------------------------------------- +// ------------------ generate ram control signals --------------------- +// --------------------------------------------------------------------- + +// all possible commands +localparam CMD_INHIBIT = 4'b1111; +localparam CMD_NOP = 4'b0111; +localparam CMD_ACTIVE = 4'b0011; +localparam CMD_READ = 4'b0101; +localparam CMD_WRITE = 4'b0100; +localparam CMD_BURST_TERMINATE = 4'b0110; +localparam CMD_PRECHARGE = 4'b0010; +localparam CMD_AUTO_REFRESH = 4'b0001; +localparam CMD_LOAD_MODE = 4'b0000; + +reg [3:0] sd_cmd; // current command sent to sd ram +reg [15:0] sd_din; +// drive control signals according to current command +assign SDRAM_nCS = sd_cmd[3]; +assign SDRAM_nRAS = sd_cmd[2]; +assign SDRAM_nCAS = sd_cmd[1]; +assign SDRAM_nWE = sd_cmd[0]; + +reg [24:1] addr_latch[2]; +reg [24:1] addr_latch_next[2]; +reg [15:1] addr_last[6]; +reg [15:1] addr_last2[6]; +reg [15:0] din_latch[2]; +reg [1:0] oe_latch; +reg [1:0] we_latch; +reg [1:0] ds[2]; + +reg port1_state; +reg port2_state; + +localparam PORT_NONE = 3'd0; +localparam PORT_CPU1 = 3'd1; +localparam PORT_CPU2 = 3'd2; +localparam PORT_CH1 = 3'd1; +localparam PORT_CH2 = 3'd2; +localparam PORT_SP1 = 3'd3; +localparam PORT_SP2 = 3'd4; +localparam PORT_REQ = 3'd5; + +reg [2:0] next_port[2]; +reg [2:0] port[2]; + +reg refresh; +reg [10:0] refresh_cnt; +wire need_refresh = (refresh_cnt >= RFRSH_CYCLES); + +// PORT1: bank 0,1 +always @(*) begin + if (refresh) begin + next_port[0] = PORT_NONE; + addr_latch_next[0] = addr_latch[0]; + end else if (port1_req ^ port1_state) begin + next_port[0] = PORT_REQ; + addr_latch_next[0] = { 1'b0, port1_a }; + end else if (cpu1_addr != addr_last[PORT_CPU1]) begin + next_port[0] = PORT_CPU1; + addr_latch_next[0] = { 9'd0, cpu1_addr }; + end else if (cpu2_addr != addr_last[PORT_CPU2]) begin + next_port[0] = PORT_CPU2; + addr_latch_next[0] = { 9'd0, cpu2_addr }; + end else begin + next_port[0] = PORT_NONE; + addr_latch_next[0] = addr_latch[0]; + end +end + +// PORT1: bank 2,3 +always @(*) begin + if (port2_req ^ port2_state) begin + next_port[1] = PORT_REQ; + addr_latch_next[1] = { 1'b1, port2_a }; + end else if (ch1_addr != addr_last2[PORT_CH1]) begin + next_port[1] = PORT_CH1; + addr_latch_next[1] = { 1'b1, 5'd0, 3'b001, ch1_addr }; + end else if (ch2_addr != addr_last2[PORT_CH2]) begin + next_port[1] = PORT_CH2; + addr_latch_next[1] = { 1'b1, 5'd0, 3'b011, ch2_addr }; + end else if (sp1_req != sp1_ack) begin + next_port[1] = PORT_SP1; + addr_latch_next[1] = { 1'b1, 5'd0, 3'b000, sp1_addr }; + end else if (sp2_req != sp2_ack) begin + next_port[1] = PORT_SP2; + addr_latch_next[1] = { 1'b1, 5'd0, 3'b010, sp2_addr }; + end else begin + next_port[1] = PORT_NONE; + addr_latch_next[1] = addr_latch[1]; + end +end + +always @(posedge clk) begin + + // permanently latch ram data to reduce delays + sd_din <= SDRAM_DQ; + SDRAM_DQ <= 16'bZZZZZZZZZZZZZZZZ; + { SDRAM_DQMH, SDRAM_DQML } <= 2'b11; + sd_cmd <= CMD_NOP; // default: idle + refresh_cnt <= refresh_cnt + 1'd1; + + if(init) begin + // initialization takes place at the end of the reset phase + if(t == STATE_RAS0) begin + + if(reset == 15) begin + sd_cmd <= CMD_PRECHARGE; + SDRAM_A[10] <= 1'b1; // precharge all banks + end + + if(reset == 10 || reset == 8) begin + sd_cmd <= CMD_AUTO_REFRESH; + end + + if(reset == 2) begin + sd_cmd <= CMD_LOAD_MODE; + SDRAM_A <= MODE; + SDRAM_BA <= 2'b00; + end + end + end else begin + // RAS phase + // bank 0,1 + if(t == STATE_RAS0) begin + addr_latch[0] <= addr_latch_next[0]; + port[0] <= next_port[0]; + { oe_latch[0], we_latch[0] } <= 2'b00; + + if (next_port[0] != PORT_NONE) begin + sd_cmd <= CMD_ACTIVE; + SDRAM_A <= addr_latch_next[0][22:10]; + SDRAM_BA <= addr_latch_next[0][24:23]; + addr_last[next_port[0]] <= addr_latch_next[0][15:1]; + if (next_port[0] == PORT_REQ) begin + { oe_latch[0], we_latch[0] } <= { ~port1_we, port1_we }; + ds[0] <= port1_ds; + din_latch[0] <= port1_d; + port1_state <= port1_req; + end else begin + { oe_latch[0], we_latch[0] } <= 2'b10; + ds[0] <= 2'b11; + end + end + end + + // bank 2,3 + if(t == STATE_RAS1) begin + refresh <= 1'b0; + addr_latch[1] <= addr_latch_next[1]; + { oe_latch[1], we_latch[1] } <= 2'b00; + port[1] <= next_port[1]; + + if (next_port[1] != PORT_NONE) begin + sd_cmd <= CMD_ACTIVE; + SDRAM_A <= addr_latch_next[1][22:10]; + SDRAM_BA <= addr_latch_next[1][24:23]; + addr_last2[next_port[1]] <= addr_latch_next[1][15:1]; + if (next_port[1] == PORT_REQ) begin + { oe_latch[1], we_latch[1] } <= { ~port1_we, port1_we }; + ds[1] <= port2_ds; + din_latch[1] <= port2_d; + port2_state <= port2_req; + end else begin + { oe_latch[1], we_latch[1] } <= 2'b10; + ds[1] <= 2'b11; + end + end + + if (next_port[1] == PORT_NONE && need_refresh && !we_latch[0] && !oe_latch[0]) begin + refresh <= 1'b1; + refresh_cnt <= 0; + sd_cmd <= CMD_AUTO_REFRESH; + end + end + + // CAS phase + if(t == STATE_CAS0 && (we_latch[0] || oe_latch[0])) begin + sd_cmd <= we_latch[0]?CMD_WRITE:CMD_READ; + { SDRAM_DQMH, SDRAM_DQML } <= ~ds[0]; + if (we_latch[0]) begin + SDRAM_DQ <= din_latch[0]; + port1_ack <= port1_req; + end + SDRAM_A <= { 4'b0010, addr_latch[0][9:1] }; // auto precharge + SDRAM_BA <= addr_latch[0][24:23]; + end + + if(t == STATE_CAS1 && (we_latch[1] || oe_latch[1])) begin + sd_cmd <= we_latch[1]?CMD_WRITE:CMD_READ; + { SDRAM_DQMH, SDRAM_DQML } <= ~ds[1]; + if (we_latch[1]) begin + SDRAM_DQ <= din_latch[1]; + port2_ack <= port2_req; + end + SDRAM_A <= { 4'b0010, addr_latch[1][9:1] }; // auto precharge + SDRAM_BA <= addr_latch[1][24:23]; + end + + // Data returned + if(t == STATE_READ0 && oe_latch[0]) begin + case(port[0]) + PORT_REQ: begin port1_q <= sd_din; port1_ack <= port1_req; end + PORT_CPU1: begin cpu1_q <= sd_din; end + PORT_CPU2: begin cpu2_q <= sd_din; end + default: ; + endcase; + end + + if(t == STATE_READ1 && oe_latch[1]) begin + case(port[1]) + PORT_REQ: begin port2_q <= sd_din; port2_ack <= port2_req; end + PORT_CH1 : ch1_q <= sd_din; + PORT_CH2 : ch2_q <= sd_din; + PORT_SP1 : begin sp1_q <= sd_din; sp1_ack <= sp1_req; end + PORT_SP2 : begin sp2_q <= sd_din; sp2_ack <= sp2_req; end + default: ; + endcase; + end + + end +end + +endmodule diff --git a/Arcade_MiST/Konami Iron Horse/rtl/spram.vhd b/Arcade_MiST/Konami Iron Horse/rtl/spram.vhd new file mode 100644 index 00000000..38302277 --- /dev/null +++ b/Arcade_MiST/Konami Iron Horse/rtl/spram.vhd @@ -0,0 +1,46 @@ +library ieee; +use IEEE.std_logic_1164.all; +use IEEE.std_logic_unsigned.ALL; +use IEEE.numeric_std.all; + +entity spram is + + generic + ( + DATA_WIDTH : natural := 8; + ADDR_WIDTH : natural := 10 + ); + + port + ( + clk : in std_logic; + addr : in std_logic_vector((ADDR_WIDTH - 1) downto 0); + data : in std_logic_vector((DATA_WIDTH - 1) downto 0); + q : out std_logic_vector((DATA_WIDTH - 1) downto 0); + we : in std_logic := '0' + ); + +end spram; + +architecture rtl of spram is + + subtype word_t is std_logic_vector((DATA_WIDTH-1) downto 0); + type memory_t is array(2**ADDR_WIDTH-1 downto 0) of word_t; + + shared variable ram : memory_t; + +begin + + process(clk) + begin + if(rising_edge(clk)) then + if(we = '1') then + ram(to_integer(unsigned(addr))) := data; + q <= data; + else + q <= ram(to_integer(unsigned(addr))); + end if; + end if; + end process; + +end rtl; diff --git a/common/CPU/MC6809/mc6809is.v b/common/CPU/MC6809/mc6809is.v index fdb860e6..0a86c7c4 100644 --- a/common/CPU/MC6809/mc6809is.v +++ b/common/CPU/MC6809/mc6809is.v @@ -17,6 +17,7 @@ // Revision: // Revision 1.0 - Initial Release // Revision 1.0s - Sinchronous version (by Sorgelig) +// Revision 1.0sk - Add direct injection of KONAMI-1 encrypted opcodes (by Ace) // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// @@ -41,12 +42,14 @@ module mc6809is #( - parameter ILLEGAL_INSTRUCTIONS="GHOST" + parameter ILLEGAL_INSTRUCTIONS="GHOST", + parameter IS_KONAMI1="FALSE" ) ( input CLK, input fallE_en, input fallQ_en, + input [7:0] OP, input [7:0] D, output [7:0] DOut, @@ -452,7 +455,10 @@ wire [7:0] MappedInstruction; generate if (ILLEGAL_INSTRUCTIONS=="GHOST") begin : ghost - assign MappedInstruction = MapInstruction(D); + if(IS_KONAMI1=="FALSE") //Modification by Ace: accept opcodes directly for KONAMI-1 CPU + assign MappedInstruction = MapInstruction(D); + else + assign MappedInstruction = MapInstruction(OP); end else begin diff --git a/common/Sound/JT12/LICENSE b/common/Sound/JT12/LICENSE new file mode 100644 index 00000000..9cecc1d4 --- /dev/null +++ b/common/Sound/JT12/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/common/Sound/JT12/README.md b/common/Sound/JT12/README.md new file mode 100644 index 00000000..7dc44b2f --- /dev/null +++ b/common/Sound/JT12/README.md @@ -0,0 +1,43 @@ +# JT12 FPGA Clone of Yamaha OPN 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 + + +JT12 is an FM sound source written in Verilog, fully compatible with YM2612/YM3438 (Megadrive), YM2610 (NeoGeo) and YM2203 (PC88, arcades). + +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 + +* 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) \ No newline at end of file diff --git a/common/Sound/JT12/hdl/adpcm/gen_lingain.py b/common/Sound/JT12/hdl/adpcm/gen_lingain.py new file mode 100644 index 00000000..d0fbb850 --- /dev/null +++ b/common/Sound/JT12/hdl/adpcm/gen_lingain.py @@ -0,0 +1,14 @@ +#!/usr/bin/python + +import sys + +db=0 + +for k in range(64): + lin = 10**(db/20)*511 + sys.stdout.write(" mem[%03d] = 9'd%03d;" % (k, lin)) + if( k%4 == 3 ): + sys.stdout.write("\n") + # else: + # sys.stdout.write(" ") + db = db - 0.75 diff --git a/common/Sound/JT12/hdl/adpcm/jt10_adpcm.v b/common/Sound/JT12/hdl/adpcm/jt10_adpcm.v new file mode 100644 index 00000000..2237300f --- /dev/null +++ b/common/Sound/JT12/hdl/adpcm/jt10_adpcm.v @@ -0,0 +1,132 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +// ADPCM-A algorithm + +module jt10_adpcm( + input rst_n, + input clk, // CPU clock + input cen, // optional clock enable, if not needed leave as 1'b1 + input [3:0] data, + input chon, // high if this channel is on + input clr, + output signed [15:0] pcm +); + +localparam sigw = 13; // 1 bit more than the actual signal width so +localparam shift = 3; //16-sigw; + // there is room for overflow +wire signed [sigw-1:0] max_pos = { 2'b00, {sigw-2{1'b1}} }; +wire signed [sigw-1:0] max_neg = { 2'b11, {sigw-2{1'b0}} }; + +reg signed [sigw-1:0] x1, x2, x3, x4, x5, x6; +reg signed [sigw-1:0] inc4; +reg [5:0] step1, step2, step6, step3, step4, step5; +reg [5:0] step_next, step_1p; +reg sign2, sign3, sign4, sign5, xsign5; + +// All outputs from stage 1 +assign pcm = { {16-sigw{x1[sigw-1]}}, x1 } <<< shift; + +// This could be decomposed in more steps as the pipeline +// has room for it +always @(*) begin + casez( data[2:0] ) + 3'b0??: step_next = step1==6'd0 ? 6'd0 : (step1-6'd1); + 3'b100: step_next = step1+6'd2; + 3'b101: step_next = step1+6'd5; + 3'b110: step_next = step1+6'd7; + 3'b111: step_next = step1+6'd9; + endcase + step_1p = step_next > 6'd48 ? 6'd48 : step_next; +end + +wire [11:0] inc3; +reg [8:0] lut_addr2; + + +jt10_adpcma_lut u_lut( + .clk ( clk ), + .rst_n ( rst_n ), + .cen ( cen ), + .addr ( lut_addr2 ), + .inc ( inc3 ) +); + +// Original pipeline: 6 stages, 6 channels take 36 clock cycles +// 8 MHz -> /12 divider -> 666 kHz +// 666 kHz -> 18.5 kHz = 55.5/3 kHz + +reg chon2, chon3, chon4; +wire [sigw-1:0] inc3_long = { {sigw-12{1'b0}},inc3 }; + +always @( posedge clk or negedge rst_n ) + if( ! rst_n ) begin + x1 <= 'd0; step1 <= 0; + x2 <= 'd0; step2 <= 0; + x3 <= 'd0; step3 <= 0; + x4 <= 'd0; step4 <= 0; + x5 <= 'd0; step5 <= 0; + x6 <= 'd0; step6 <= 0; + sign2 <= 'b0; + chon2 <= 'b0; chon3 <= 'b0; chon4 <= 'b0; + lut_addr2 <= 'd0; + inc4 <= 'd0; + end else if(cen) begin + // I + sign2 <= data[3]; + x2 <= clr ? {sigw{1'b0}} : x1; + step2 <= clr ? 6'd0 : (chon ? step_1p : step1); + chon2 <= chon; + lut_addr2 <= { step1, data[2:0] }; + // II 2's complement of inc2 if necessary + sign3 <= sign2; + x3 <= x2; + step3 <= step2; + chon3 <= chon2; + // III + sign4 <= sign3; + inc4 <= sign3 ? ~inc3_long + 1 : inc3_long; + x4 <= x3; + step4 <= step3; + chon4 <= chon3; + // IV + sign5 <= sign4; + xsign5 <= x4[sigw-1]; + x5 <= chon4 ? x4 + inc4 : x4; + step5 <= step4; + // V + // if( xsign5!=x5[sigw-1] && sign5!=x5[sigw-1] ) begin // enable limiter + // if( sign5 ) // it was negative + // x6 <= {1'b1, {sigw-1{1'b0}}}; + // else // it was positive + // x6 <= {1'b0, {sigw-1{1'b1}}}; + // end else + x6 <= x5; + if( x5 > max_pos) x6 <= max_pos; + if( x5 < max_neg) x6 <= max_neg; + step6 <= step5; + // VI: close the loop + x1 <= x6; + step1 <= step6; + end + +endmodule // jt10_adpcm \ No newline at end of file diff --git a/common/Sound/JT12/hdl/adpcm/jt10_adpcm_acc.v b/common/Sound/JT12/hdl/adpcm/jt10_adpcm_acc.v new file mode 100644 index 00000000..7e5ae01b --- /dev/null +++ b/common/Sound/JT12/hdl/adpcm/jt10_adpcm_acc.v @@ -0,0 +1,90 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +// Adds all 6 channels and apply linear interpolation to rise +// sampling frequency to 55.5 kHz + +module jt10_adpcm_acc( + input rst_n, + input clk, // CPU clock + input cen, // 111 kHz + // pipeline channel + input [5:0] cur_ch, + input [5:0] en_ch, + input match, + + input en_sum, + input signed [15:0] pcm_in, // 18.5 kHz + output signed [15:0] pcm_out // 55.5 kHz +); + +wire signed [17:0] pcm_in_long = en_sum ? { {2{pcm_in[15]}}, pcm_in } : 18'd0; +reg signed [17:0] acc, last, pcm_full; +reg signed [17:0] step; + +reg signed [17:0] diff; +reg signed [22:0] diff_ext, step_full; + +always @(*) begin + diff = acc-last; + diff_ext = { {5{diff[17]}}, diff }; + step_full = diff_ext // 1/128 + + ( diff_ext << 1 ) // 1/64 + + ( diff_ext << 3 ) // 1/16 + + ( diff_ext << 5 ); // 1/4 + +end + +wire adv = en_ch[0] & cur_ch[0]; + +always @(posedge clk or negedge rst_n) + if( !rst_n ) begin + step <= 'd0; + acc <= 18'd0; + last <= 18'd0; + end else if(cen) begin + if( match ) + acc <= en_ch[0] ? pcm_in_long : ( pcm_in_long + acc ); + if( adv ) begin + // step = diff * (1/4+1/16+1/64+1/128) + step <= { {2{step_full[22]}}, step_full[22:7] }; // >>>7; + last <= acc; + end + end +wire overflow = |pcm_full[17:15] & ~&pcm_full[17:15]; + +always @(posedge clk or negedge rst_n) + if( !rst_n ) begin + pcm_full <= 18'd0; + end else if(cen && cur_ch[0]) begin + case( en_ch ) + 6'b000_001: pcm_full <= last; + 6'b000_100, + 6'b010_000: pcm_full <= pcm_full + step; + default:; + endcase + if( overflow ) + pcm_out <= pcm_full[17] ? 16'h8000 : 16'h7fff; // saturate + else + pcm_out <= pcm_full[15:0]; + end + +endmodule // jt10_adpcm_acc \ No newline at end of file diff --git a/common/Sound/JT12/hdl/adpcm/jt10_adpcm_cnt.v b/common/Sound/JT12/hdl/adpcm/jt10_adpcm_cnt.v new file mode 100644 index 00000000..aeca48f8 --- /dev/null +++ b/common/Sound/JT12/hdl/adpcm/jt10_adpcm_cnt.v @@ -0,0 +1,181 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +module jt10_adpcm_cnt( + input rst_n, + input clk, // CPU clock + input cen, // 666 kHz + // pipeline channel + input [ 5:0] cur_ch, + input [ 5:0] en_ch, + // Address writes from CPU + input [15:0] addr_in, + input [ 2:0] addr_ch, + input up_start, + input up_end, + // Counter control + input aon, + input aoff, + // ROM driver + output [19:0] addr_out, + output [ 3:0] bank, + output sel, + output roe_n, + output decon, + output clr, // inform the decoder that a new section begins + // Flags + output reg [ 5:0] flags, + input [ 5:0] clr_flags, + // + output [15:0] start_top, + output [15:0] end_top +); + +reg [20:0] addr1, addr2, addr3, addr4, addr5, addr6; +reg [3:0] bank1, bank2, bank3, bank4, bank5, bank6; +reg [11:0] start1, start2, start3, start4, start5, start6, + end1, end2, end3, end4, end5, end6; +reg on1, on2, on3, on4, on5, on6; +reg done5, done6, done1; +reg [5:0] done_sr, zero; + +reg roe_n1, decon1; + +reg clr1, clr2, clr3, clr4, clr5, clr6; + +// All outputs from stage 1 +assign addr_out = addr1[20:1]; +assign sel = addr1[0]; +assign bank = bank1; +assign roe_n = roe_n1; +assign clr = clr1; +assign decon = decon1; + +wire active5 = { cur_ch[1:0], cur_ch[5:2] } == en_ch; +wire sumup5 = on5 && !done5 && active5; +reg sumup6; + +reg [5:0] last_done, set_flags; + +always @(posedge clk or negedge rst_n) + if( !rst_n ) begin + zero <= 6'd1; + done_sr <= ~6'd0; + last_done <= ~6'd0; + end else if(cen) begin + zero <= { zero[0], zero[5:1] }; + done_sr <= { done1, done_sr[5:1]}; + if( zero[0] ) begin + last_done <= done_sr; + set_flags <= ~last_done & done_sr; + end + end + +always @(posedge clk or negedge rst_n) + if( !rst_n ) begin + flags <= 6'd0; + end else begin + flags <= ~clr_flags & (set_flags | flags); + end + +`ifdef SIMULATION +wire [11:0] addr1_cmp = addr1[20:9]; +`endif + +assign start_top = {bank1, start1}; +assign end_top = {bank1, end1}; + +reg [5:0] cur_ch, addr_ch_dec; +reg [5:0] en_ch; + +always @(*) + case(addr_ch) + 3'd0: addr_ch_dec = 6'b000_001; + 3'd1: addr_ch_dec = 6'b000_010; + 3'd2: addr_ch_dec = 6'b000_100; + 3'd3: addr_ch_dec = 6'b001_000; + 3'd4: addr_ch_dec = 6'b010_000; + 3'd5: addr_ch_dec = 6'b100_000; + default: addr_ch_dec = 6'd0; + endcase // up_addr + +wire up1 = cur_ch == addr_ch_dec; + +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; + start1 <= 'd0; start2 <= 'd0; start3 <= 'd0; + start4 <= 'd0; start5 <= 'd0; start6 <= 'd0; + end1 <= 'd0; end2 <= 'd0; end3 <= 'd0; + end4 <= 'd0; end5 <= 'd0; end6 <= 'd0; + end else if( cen ) begin + addr2 <= addr1; + on2 <= aoff ? 1'b0 : (aon | on1); + clr2 <= aoff || (aon && !on1); // Each time a A-ON is sent the address counter restarts + start2 <= (up_start && up1) ? addr_in[11:0] : start1; + end2 <= (up_end && up1) ? addr_in[11:0] : end1; + bank2 <= ((up_end | up_start) && up1) ? addr_in[15:12] : bank1; + + addr3 <= addr2; // clr2 ? {start2,9'd0} : addr2; + on3 <= on2; + clr3 <= clr2; + start3 <= start2; + end3 <= end2; + bank3 <= bank2; + + addr4 <= addr3; + on4 <= on3; + clr4 <= clr3; + start4 <= start3; + end4 <= end3; + bank4 <= bank3; + + addr5 <= addr4; + on5 <= on4; + clr5 <= clr4; + done5 <= addr4[20:9] == end4; // && addr4[8:0]==~9'b0; + start5 <= start4; + end5 <= end4; + bank5 <= bank4; + // V + addr6 <= addr5; + on6 <= on5; + clr6 <= clr5; + done6 <= done5; + start6 <= start5; + end6 <= end5; + bank6 <= bank5; + sumup6 <= sumup5; + + addr1 <= clr6 ? {start6,9'd0} : (sumup6 ? addr6+21'd1 :addr6); + on1 <= on6; + done1 <= done6; + start1 <= start6; + end1 <= end6; + roe_n1 <= ~sumup6; + decon1 <= sumup6; + bank1 <= bank6; + clr1 <= clr6; + end + +endmodule // jt10_adpcm_cnt diff --git a/common/Sound/JT12/hdl/adpcm/jt10_adpcm_comb.v b/common/Sound/JT12/hdl/adpcm/jt10_adpcm_comb.v new file mode 100644 index 00000000..c0f63ac7 --- /dev/null +++ b/common/Sound/JT12/hdl/adpcm/jt10_adpcm_comb.v @@ -0,0 +1,134 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +// Sampling rates: 2kHz ~ 55.5 kHz. in 0.85Hz steps + +module jt10_adpcm_comb( + input rst_n, + input clk, // CPU clock + input cen, // optional clock enable, if not needed leave as 1'b1 + input [3:0] data, + input chon, // high if this channel is on + output signed [15:0] pcm +); + +localparam stepw = 15; + +reg signed [15:0] x1, x2, x3, x4, x5, x6; +reg [stepw-1:0] step1, step2, step6; +reg [stepw+1:0] step3, step4, step5; +assign pcm = x2; + +reg [18:0] d2l; +reg [15:0] d3,d4; +reg [3:0] d1,d2; +reg sign2, sign3, sign4, sign5; +reg [7:0] step_val; +reg [22:0] step2l; + +// Original pipeline: 6 stages, 6 channels take 36 clock cycles +// 8 MHz -> /12 divider -> 666 kHz +// 666 kHz -> 18.5 kHz = 55.5/3 kHz + +reg chon2, chon3, chon4, chon5; +reg signEqu4, signEqu5; +reg [3:0] data1,data2; + +always @( * ) + if( ! rst_n ) begin + x2 = 'd0; step2 = 'd127; + x3 = 'd0; step3 = 'd127; + x4 = 'd0; step4 = 'd127; + x5 = 'd0; step5 = 'd127; + x6 = 'd0; step6 = 'd127; + d2 = 'd0; d3 = 'd0; d4 = 'd0; + sign2 = 'b0; + sign3 = 'b0; + sign4 = 'b0; sign5 = 'b0; + chon2 = 'b0; chon3 = 'b0; chon4 = 'b0; chon5 = 1'b0; + end else begin + // I + d2 = d1; + sign2 = data1[3]; + data2 = data1; + x2 = x1; + step2 = step1; + chon2 = chon; + // II multiply and obtain the offset + casez( d2[3:1] ) + 3'b0_??: step_val = 8'd57; + 3'b1_00: step_val = 8'd77; + 3'b1_01: step_val = 8'd102; + 3'b1_10: step_val = 8'd128; + 3'b1_11: step_val = 8'd153; + endcase // data[2:0] + d2l = d2 * step2; // 4 + 15 = 19 bits -> div by 8 -> 16 bits + step2l = step_val * step2; // 15 bits + 8 bits = 23 bits -> div 64 -> 17 bits + d3 = d2l[18:3]; // 16 bits + sign3 = sign2; + x3 = x2; + step3 = step2l[22:6]; + chon3 = chon2; + // III 2's complement of d3 if necessary + d4 = sign3 ? ~d3+16'b1 : d3; + sign4 = sign3; + signEqu4 = sign3 == x3[15]; + x4 = x3; + step4 = step3; + chon4 = chon3; + // IV Advance the waveform + x5 = x4+d4; + sign5 = sign4; + signEqu5 = signEqu4; + step5 = step4; + chon5 = chon4; + // V: limit or reset outputs + if( chon5 ) begin + if( signEqu5 && (sign5!=x5[15]) ) + x6 = sign5 ? 16'h8000 : 16'h7FFF; + else + x6 = x5; + + if( step5 < 127 ) + step6 = 15'd127; + else if( step5 > 24576 ) + step6 = 15'd24576; + else + step6 = step5[14:0]; + end else begin + x6 = 'd0; + step6 = 'd127; + end + end + +always @(posedge clk or negedge rst_n) + if( ! rst_n ) begin + x1 <= 'd0; step1 <= 'd127; + d1 <= 'd0; data1 <= 'd0; + end else if(cen) begin + // VI: close the loop + d1 <= {data[2:0],1'b1}; + x1 <= x6; + step1 <= step6; + data1 <= data; + end + +endmodule // jt10_adpcm \ No newline at end of file diff --git a/common/Sound/JT12/hdl/adpcm/jt10_adpcm_dbrom.v b/common/Sound/JT12/hdl/adpcm/jt10_adpcm_dbrom.v new file mode 100644 index 00000000..5ba7d4ac --- /dev/null +++ b/common/Sound/JT12/hdl/adpcm/jt10_adpcm_dbrom.v @@ -0,0 +1,54 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +// dB to linear + +module jt10_adpcm_dbrom( + input clk, // CPU clock + input [5:0] db, + output [8:0] lin +); + +reg [8:0] mem[0:63]; + +initial begin // generated with file gen_lingain.py + mem[000] = 9'd511; mem[001] = 9'd468; mem[002] = 9'd429; mem[003] = 9'd394; + mem[004] = 9'd361; mem[005] = 9'd331; mem[006] = 9'd304; mem[007] = 9'd279; + mem[008] = 9'd256; mem[009] = 9'd234; mem[010] = 9'd215; mem[011] = 9'd197; + mem[012] = 9'd181; mem[013] = 9'd166; mem[014] = 9'd152; mem[015] = 9'd139; + mem[016] = 9'd128; mem[017] = 9'd117; mem[018] = 9'd107; mem[019] = 9'd099; + mem[020] = 9'd090; mem[021] = 9'd083; mem[022] = 9'd076; mem[023] = 9'd070; + mem[024] = 9'd064; mem[025] = 9'd059; mem[026] = 9'd054; mem[027] = 9'd049; + mem[028] = 9'd045; mem[029] = 9'd041; mem[030] = 9'd038; mem[031] = 9'd035; + mem[032] = 9'd032; mem[033] = 9'd029; mem[034] = 9'd027; mem[035] = 9'd024; + mem[036] = 9'd022; mem[037] = 9'd020; mem[038] = 9'd019; mem[039] = 9'd017; + mem[040] = 9'd016; mem[041] = 9'd014; mem[042] = 9'd013; mem[043] = 9'd012; + mem[044] = 9'd011; mem[045] = 9'd010; mem[046] = 9'd009; mem[047] = 9'd008; + mem[048] = 9'd008; mem[049] = 9'd007; mem[050] = 9'd006; mem[051] = 9'd006; + mem[052] = 9'd005; mem[053] = 9'd005; mem[054] = 9'd004; mem[055] = 9'd004; + mem[056] = 9'd004; mem[057] = 9'd003; mem[058] = 9'd003; mem[059] = 9'd003; + mem[060] = 9'd002; mem[061] = 9'd002; mem[062] = 9'd002; mem[063] = 9'd002; +end + +always @(posedge clk) + lin <= mem[db]; + +endmodule // jt10_adpcm_dbrom \ No newline at end of file diff --git a/common/Sound/JT12/hdl/adpcm/jt10_adpcm_div.v b/common/Sound/JT12/hdl/adpcm/jt10_adpcm_div.v new file mode 100644 index 00000000..41ed279a --- /dev/null +++ b/common/Sound/JT12/hdl/adpcm/jt10_adpcm_div.v @@ -0,0 +1,62 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +// calculates d=a/b +// a = b*d + r + +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, + output working +); + +reg [dw-1:0] cycle; +assign working = cycle[0]; + +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 <= {dw{1'd1}}; + r <= 'd0; + 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}; + end else begin + r <= { r[dw-2:0], d[dw-1] }; + d <= { d[dw-2:0], 1'b0 }; + end + end + end + +endmodule // jt10_adpcm_div diff --git a/common/Sound/JT12/hdl/adpcm/jt10_adpcm_drvA.v b/common/Sound/JT12/hdl/adpcm/jt10_adpcm_drvA.v new file mode 100644 index 00000000..8444f0c6 --- /dev/null +++ b/common/Sound/JT12/hdl/adpcm/jt10_adpcm_drvA.v @@ -0,0 +1,335 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +module jt10_adpcm_drvA( + input rst_n, + input clk, // CPU clock + input cen, // same cen as MMR + input cen6, // clk & cen = 666 kHz + input cen1, // clk & cen = 111 kHz + + output [19:0] addr, // real hardware has 10 pins multiplexed through RMPX pin + output [3:0] bank, + output reg roe_n, // ADPCM-A ROM output enable + + // Control Registers + input [5:0] atl, // ADPCM Total Level + input [7:0] lracl_in, + input [15:0] addr_in, + + input [2:0] up_lracl, + input up_start, + input up_end, + input [2:0] up_addr, + + input [7:0] aon_cmd, // ADPCM ON equivalent to key on for FM + input up_aon, + + input [7:0] datain, + + // Flags + output [5:0] flags, + input [5:0] clr_flags, + + output reg signed [15:0] pcm55_l, + output reg signed [15:0] pcm55_r +); + +/* verilator tracing_on */ + +reg [5:0] cur_ch; +reg [5:0] en_ch; +reg [3:0] data; +wire nibble_sel; +wire signed [15:0] pcm_att; + +always @(posedge clk or negedge rst_n) + if( !rst_n ) begin + data <= 4'd0; + end else if(cen) begin + data <= !nibble_sel ? datain[7:4] : datain[3:0]; + end + +reg [ 5:0] aon_sr, aoff_sr; + +reg [7:0] aon_cmd_cpy; + +always @(posedge clk) if(cen) begin + if( up_aon ) aon_cmd_cpy <= aon_cmd; else if(cur_ch[5] && cen6) aon_cmd_cpy <= 8'd0; +end + +always @(posedge clk) if(cen6) begin + if( cur_ch[5] ) begin + aon_sr <= ~{6{aon_cmd_cpy[7]}} & aon_cmd_cpy[5:0]; + aoff_sr <= {6{aon_cmd_cpy[7]}} & aon_cmd_cpy[5:0]; + end else begin + aon_sr <= { 1'b0, aon_sr[5:1] }; + aoff_sr <= { 1'b0, aoff_sr[5:1] }; + end +end + +reg match; // high when cur_ch==en_ch, but calculated one clock cycle ahead + // so it can be latched +wire [5:0] cur_next = { cur_ch[4:0], cur_ch[5] }; +wire [5:0] en_next = {en_ch[4:0], en_ch[5] }; + +always @(posedge clk or negedge rst_n) + if( !rst_n ) begin + cur_ch <= 6'b1; en_ch <= 6'b1; + match <= 0; + end else if( cen6 ) begin + cur_ch <= cur_next; + if( cur_ch[5] ) en_ch <= en_next; + match <= cur_next == (cur_ch[5] ? en_next : en_ch); + end + +wire [15:0] start_top, end_top; + +wire clr_dec, decon; + +jt10_adpcm_cnt u_cnt( + .rst_n ( rst_n ), + .clk ( clk ), + .cen ( cen6 ), + // Pipeline + .cur_ch ( cur_ch ), + .en_ch ( en_ch ), + // START/END update + .addr_in ( addr_in ), + .addr_ch ( up_addr ), + .up_start ( up_start ), + .up_end ( up_end ), + // Control + .aon ( aon_sr[0] ), + .aoff ( aoff_sr[0] ), + .clr ( clr_dec ), + // ROM driver + .addr_out ( addr ), + .bank ( bank ), + .sel ( nibble_sel ), + .roe_n ( roe_n ), + .decon ( decon ), + // Flags + .flags ( flags ), + .clr_flags ( clr_flags ), + .start_top ( start_top ), + .end_top ( end_top ) +); + +// wire chactive = chon & cen6; +wire signed [15:0] pcmdec; + +jt10_adpcm u_decoder( + .rst_n ( rst_n ), + .clk ( clk ), + .cen ( cen6 ), + .data ( data ), + .chon ( decon ), + .clr ( clr_dec ), + .pcm ( pcmdec ) +); +/* + +always @(posedge clk) begin + if( cen3 && chon ) begin + pcm55_l <= pre_pcm55_l; + pcm55_r <= pre_pcm55_r; + end +end +*/ + +wire [1:0] lr; + +jt10_adpcm_gain u_gain( + .rst_n ( rst_n ), + .clk ( clk ), + .cen ( cen6 ), + // Pipeline + .cur_ch ( cur_ch ), + .en_ch ( en_ch ), + .match ( match ), + // Gain control + .atl ( atl ), // ADPCM Total Level + .lracl ( lracl_in ), + .up_ch ( up_lracl ), + + .lr ( lr ), + .pcm_in ( pcmdec ), + .pcm_att( pcm_att ) +); + +wire signed [15:0] pre_pcm55_l, pre_pcm55_r; + +assign pcm55_l = pre_pcm55_l; +assign pcm55_r = pre_pcm55_r; + +jt10_adpcm_acc u_acc_left( + .rst_n ( rst_n ), + .clk ( clk ), + .cen ( cen6 ), + // Pipeline + .cur_ch ( cur_ch ), + .en_ch ( en_ch ), + .match ( match ), + // left/right enable + .en_sum ( lr[1] ), + + .pcm_in ( pcm_att ), // 18.5 kHz + .pcm_out( pre_pcm55_l ) // 55.5 kHz +); + +jt10_adpcm_acc u_acc_right( + .rst_n ( rst_n ), + .clk ( clk ), + .cen ( cen6 ), + // Pipeline + .cur_ch ( cur_ch ), + .en_ch ( en_ch ), + .match ( match ), + // left/right enable + .en_sum ( lr[0] ), + + .pcm_in ( pcm_att ), // 18.5 kHz + .pcm_out( pre_pcm55_r ) // 55.5 kHz +); + + +`ifdef SIMULATION +integer fch0, fch1, fch2, fch3, fch4, fch5; +initial begin + fch0 = $fopen("ch0.dec","w"); + fch1 = $fopen("ch1.dec","w"); + fch2 = $fopen("ch2.dec","w"); + fch3 = $fopen("ch3.dec","w"); + fch4 = $fopen("ch4.dec","w"); + fch5 = $fopen("ch5.dec","w"); +end + +reg signed [15:0] pcm_ch0, pcm_ch1, pcm_ch2, pcm_ch3, pcm_ch4, pcm_ch5; +always @(posedge cen6) if(en_ch[0]) begin + if(cur_ch[0]) begin + pcm_ch0 <= pcmdec; + $fwrite( fch0, "%d\n", pcmdec ); + end + if(cur_ch[1]) begin + pcm_ch1 <= pcmdec; + $fwrite( fch1, "%d\n", pcmdec ); + end + if(cur_ch[2]) begin + pcm_ch2 <= pcmdec; + $fwrite( fch2, "%d\n", pcmdec ); + end + if(cur_ch[3]) begin + pcm_ch3 <= pcmdec; + $fwrite( fch3, "%d\n", pcmdec ); + end + if(cur_ch[4]) begin + pcm_ch4 <= pcmdec; + $fwrite( fch4, "%d\n", pcmdec ); + end + if(cur_ch[5]) begin + pcm_ch5 <= pcmdec; + $fwrite( fch5, "%d\n", pcmdec ); + end +end + +reg [15:0] sim_start0, sim_start1, sim_start2, sim_start3, sim_start4, sim_start5; +reg [15:0] sim_end0, sim_end1, sim_end2, sim_end3, sim_end4, sim_end5; +reg [ 7:0] sim_lracl0, sim_lracl1, sim_lracl2, sim_lracl3, sim_lracl4, sim_lracl5; +/* +reg div3b; +reg [2:0] chframe; +always @(posedge clk) div3b<=div3; +always @(negedge div3b) chframe <= chfast; + + +reg [7:0] aon_cpy, aon_cpy2; +always @(posedge clk) begin + aon_cpy<=aon_cmd; // This prevents a Verilator circular-logic warning + aon_cpy2 <= aon_cmd; +end + +always @(posedge aon_cpy[0]) if(!aon_cpy2[7]) $display("INFO: ADPCM-A ON 0 - %X",sim_start0); +always @(posedge aon_cpy[1]) if(!aon_cpy2[7]) $display("INFO: ADPCM-A ON 1 - %X",sim_start1); +always @(posedge aon_cpy[2]) if(!aon_cpy2[7]) $display("INFO: ADPCM-A ON 2 - %X",sim_start2); +always @(posedge aon_cpy[3]) if(!aon_cpy2[7]) $display("INFO: ADPCM-A ON 3 - %X",sim_start3); +always @(posedge aon_cpy[4]) if(!aon_cpy2[7]) $display("INFO: ADPCM-A ON 4 - %X",sim_start4); +always @(posedge aon_cpy[5]) if(!aon_cpy2[7]) $display("INFO: ADPCM-A ON 5 - %X",sim_start5); +*/ +always @(posedge cen6) if(up_start) + case(up_addr) + 3'd0: sim_start0 <= addr_in; + 3'd1: sim_start1 <= addr_in; + 3'd2: sim_start2 <= addr_in; + 3'd3: sim_start3 <= addr_in; + 3'd4: sim_start4 <= addr_in; + 3'd5: sim_start5 <= addr_in; + default:; + endcase // up_addr + +always @(posedge cen6) if(up_end) + case(up_addr) + 3'd0: sim_end0 <= addr_in; + 3'd1: sim_end1 <= addr_in; + 3'd2: sim_end2 <= addr_in; + 3'd3: sim_end3 <= addr_in; + 3'd4: sim_end4 <= addr_in; + 3'd5: sim_end5 <= addr_in; + default:; + endcase // up_addr + +always @(posedge cen6) + case(up_lracl) + 3'd0: sim_lracl0 <= lracl_in; + 3'd1: sim_lracl1 <= lracl_in; + 3'd2: sim_lracl2 <= lracl_in; + 3'd3: sim_lracl3 <= lracl_in; + 3'd4: sim_lracl4 <= lracl_in; + 3'd5: sim_lracl5 <= lracl_in; + default:; + endcase // up_addr + + /* +reg start_error, end_error; +always @(posedge cen6) begin + case(chframe) + 3'd0: start_error <= start_top != sim_start0; + 3'd1: start_error <= start_top != sim_start1; + 3'd2: start_error <= start_top != sim_start2; + 3'd3: start_error <= start_top != sim_start3; + 3'd4: start_error <= start_top != sim_start4; + 3'd5: start_error <= start_top != sim_start5; + default:; + endcase + case(chframe) + 3'd0: end_error <= end_top != sim_end0; + 3'd1: end_error <= end_top != sim_end1; + 3'd2: end_error <= end_top != sim_end2; + 3'd3: end_error <= end_top != sim_end3; + 3'd4: end_error <= end_top != sim_end4; + 3'd5: end_error <= end_top != sim_end5; + default:; + endcase +end +*/ +`endif + +endmodule // jt10_adpcm_drvA \ No newline at end of file diff --git a/common/Sound/JT12/hdl/adpcm/jt10_adpcm_drvB.v b/common/Sound/JT12/hdl/adpcm/jt10_adpcm_drvB.v new file mode 100644 index 00000000..8c1ccd9a --- /dev/null +++ b/common/Sound/JT12/hdl/adpcm/jt10_adpcm_drvB.v @@ -0,0 +1,124 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +module jt10_adpcm_drvB( + input rst_n, + input clk, + input cen, // 8MHz cen + input cen55, // clk & cen55 = 55 kHz + // Control + input acmd_on_b, // Control - Process start, Key On + input acmd_rep_b, // Control - Repeat + input acmd_rst_b, // Control - Reset + input [ 1:0] alr_b, // Left / Right + input [15:0] astart_b, // Start address + input [15:0] aend_b, // End address + input [15:0] adeltan_b, // Delta-N + input [ 7:0] aeg_b, // Envelope Generator Control + output flag, + input clr_flag, + // memory + output [23:0] addr, + input [ 7:0] data, + output roe_n, + + output reg signed [15:0] pcm55_l, + output reg signed [15:0] pcm55_r +); + +wire nibble_sel; +wire adv; // advance to next reading + +// `ifdef SIMULATION +// real fsample; +// always @(posedge acmd_on_b) begin +// fsample = adeltan_b; +// fsample = fsample/65536; +// fsample = fsample * 55.5; +// $display("\nINFO: ADPCM-B ON: %X delta N = %6d (%2.1f kHz)", astart_b, adeltan_b, fsample ); +// end +// `endif + +always @(posedge clk) roe_n <= ~adv; + +jt10_adpcmb_cnt u_cnt( + .rst_n ( rst_n ), + .clk ( clk ), + .cen ( cen55 ), + .delta_n ( adeltan_b ), + .clr ( acmd_rst_b ), + .on ( acmd_on_b ), + .astart ( astart_b ), + .aend ( aend_b ), + .arepeat ( acmd_rep_b ), + .addr ( addr ), + .nibble_sel ( nibble_sel ), + // Flag control + .clr_flag ( clr_flag ), + .flag ( flag ), + .adv ( adv ) +); + +reg [3:0] din; + +always @(posedge clk) din <= !nibble_sel ? data[7:4] : data[3:0]; + +wire signed [15:0] pcmdec, pcminter, pcmgain; + +jt10_adpcmb u_decoder( + .rst_n ( rst_n ), + .clk ( clk ), + .cen ( cen ), + .adv ( adv & cen55 ), + .data ( din ), + .chon ( acmd_on_b ), + .pcm ( pcmdec ) +); + +`ifndef NOBINTERPOL +jt10_adpcmb_interpol u_interpol( + .rst_n ( rst_n ), + .clk ( clk ), + .cen ( cen ), + .cen55 ( cen55 ), + .adv ( adv ), + .pcmdec ( pcmdec ), + .pcmout ( pcminter ) +); +`else +assign pcminter = pcmdec; +`endif + +jt10_adpcmb_gain u_gain( + .rst_n ( rst_n ), + .clk ( clk ), + .cen55 ( cen55 ), + .tl ( aeg_b ), + .pcm_in ( pcminter ), + .pcm_out( pcmgain ) +); + +always @(posedge clk) if(cen55) begin + pcm55_l <= alr_b[1] ? pcmgain : 16'd0; + pcm55_r <= alr_b[0] ? pcmgain : 16'd0; +end + +endmodule // jt10_adpcm_drvB \ No newline at end of file diff --git a/common/Sound/JT12/hdl/adpcm/jt10_adpcm_dt.v b/common/Sound/JT12/hdl/adpcm/jt10_adpcm_dt.v new file mode 100644 index 00000000..06aba776 --- /dev/null +++ b/common/Sound/JT12/hdl/adpcm/jt10_adpcm_dt.v @@ -0,0 +1,130 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +// Sampling rates: 2kHz ~ 55.5 kHz. in 0.85Hz steps + +module jt10_adpcm_dt( + input rst_n, + input clk, // CPU clock + input cen, // optional clock enable, if not needed leave as 1'b1 + input [3:0] data, + input chon, // high if this channel is on + output signed [15:0] pcm +); + +localparam stepw = 15; + +reg signed [15:0] x1, x2, x3, x4, x5, x6; +reg [stepw-1:0] step1, step2, step6; +reg [stepw+1:0] step3, step4, step5; +assign pcm = x2; + +reg [18:0] d2l; +reg [15:0] d3,d4; +reg [3:0] d2; +reg sign2, sign3, sign4, sign5; +reg [7:0] step_val; +reg [22:0] step2l; + +always @(*) begin + casez( d2[3:1] ) + 3'b0_??: step_val = 8'd57; + 3'b1_00: step_val = 8'd77; + 3'b1_01: step_val = 8'd102; + 3'b1_10: step_val = 8'd128; + 3'b1_11: step_val = 8'd153; + endcase // data[2:0] + d2l = d2 * step2; // 4 + 15 = 19 bits -> div by 8 -> 16 bits + step2l = step_val * step2; // 15 bits + 8 bits = 23 bits -> div 64 -> 17 bits +end + +// Original pipeline: 6 stages, 6 channels take 36 clock cycles +// 8 MHz -> /12 divider -> 666 kHz +// 666 kHz -> 18.5 kHz = 55.5/3 kHz + +reg chon2, chon3, chon4, chon5; +reg signEqu4, signEqu5; +reg [3:0] data2; + +always @( posedge clk or negedge rst_n ) + if( ! rst_n ) begin + x1 <= 'd0; step1 <= 'd127; + x2 <= 'd0; step2 <= 'd127; + x3 <= 'd0; step3 <= 'd127; + x4 <= 'd0; step4 <= 'd127; + x5 <= 'd0; step5 <= 'd127; + x6 <= 'd0; step6 <= 'd127; + d2 <= 'd0; d3 <= 'd0; d4 <= 'd0; + sign2 <= 'b0; + sign3 <= 'b0; + sign4 <= 'b0; sign5 <= 'b0; + chon2 <= 'b0; chon3 <= 'b0; chon4 <= 'b0; chon5 <= 1'b0; + end else if(cen) begin + // I + d2 <= {data[2:0],1'b1}; + sign2 <= data[3]; + data2 <= data; + x2 <= x1; + step2 <= step1; + chon2 <= chon; + // II multiply and obtain the offset + d3 <= d2l[18:3]; // 16 bits + sign3 <= sign2; + x3 <= x2; + step3 <= step2l[22:6]; + chon3 <= chon2; + // III 2's complement of d3 if necessary + d4 <= sign3 ? ~d3+16'b1 : d3; + sign4 <= sign3; + signEqu4 <= sign3 == x3[15]; + x4 <= x3; + step4 <= step3; + chon4 <= chon3; + // IV Advance the waveform + x5 <= x4+d4; + sign5 <= sign4; + signEqu5 <= signEqu4; + step5 <= step4; + chon5 <= chon4; + // V: limit or reset outputs + if( chon5 ) begin + if( signEqu5 && (sign5!=x5[15]) ) + x6 <= sign5 ? 16'h8000 : 16'h7FFF; + else + x6 <= x5; + + if( step5 < 127 ) + step6 <= 15'd127; + else if( step5 > 24576 ) + step6 <= 15'd24576; + else + step6 <= step5[14:0]; + end else begin + x6 <= 'd0; + step6 <= 'd127; + end + // VI: close the loop + x1 <= x6; + step1 <= step6; + end + + +endmodule // jt10_adpcm \ No newline at end of file diff --git a/common/Sound/JT12/hdl/adpcm/jt10_adpcm_gain.v b/common/Sound/JT12/hdl/adpcm/jt10_adpcm_gain.v new file mode 100644 index 00000000..61cd327f --- /dev/null +++ b/common/Sound/JT12/hdl/adpcm/jt10_adpcm_gain.v @@ -0,0 +1,176 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +module jt10_adpcm_gain( + input rst_n, + input clk, // CPU clock + input cen, // 666 kHz + // pipeline channel + input [5:0] cur_ch, + input [5:0] en_ch, + input match, + + input [5:0] atl, // ADPCM Total Level + // Gain update + input [7:0] lracl, + input [2:0] up_ch, + // Data + output [1:0] lr, + input signed [15:0] pcm_in, + output signed [15:0] pcm_att +); + +reg [5:0] up_ch_dec; +always @(*) + case(up_ch) + 3'd0: up_ch_dec = 6'b000_001; + 3'd1: up_ch_dec = 6'b000_010; + 3'd2: up_ch_dec = 6'b000_100; + 3'd3: up_ch_dec = 6'b001_000; + 3'd4: up_ch_dec = 6'b010_000; + 3'd5: up_ch_dec = 6'b100_000; + default: up_ch_dec = 6'd0; + endcase + +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; + 3'd1: lin_5b = 10'd470; + 3'd2: lin_5b = 10'd431; + 3'd3: lin_5b = 10'd395; + 3'd4: lin_5b = 10'd362; + 3'd5: lin_5b = 10'd332; + 3'd6: lin_5b = 10'd305; + 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]; + +always @(posedge clk or negedge rst_n) + if( !rst_n ) begin + lracl1 <= 8'd0; lracl2 <= 8'd0; + lracl3 <= 8'd0; lracl4 <= 8'd0; + lracl5 <= 8'd0; lracl6 <= 8'd0; + db5 <= 'd0; + sh1 <= 4'd0; sh6 <= 4'd0; + lin1 <= 10'd0; + lin6 <= 10'd0; + end else if(cen) begin + + // I + lracl2 <= up_ch_dec == cur_ch ? lracl : lracl1; + // II + lracl3 <= lracl2; + // III + lracl4 <= lracl3; + // IV: new data is accepted here + lracl5 <= lracl4; + db5 <= { 1'b0, ~lracl4[5:0] } + {1'b0, ~atl}; + // V + lracl6 <= lracl5; + lin6 <= lin_5b; + sh6 <= db5[6:3]; + // VI close the loop + lracl1 <= lracl6; + lin1 <= sh6[3] ? 10'h0 : lin6; + sh1 <= sh6; + end + +// Apply gain +// The pipeline has 6 stages, there is new input data once every 6*6=36 clock cycles +// New data is read once and it takes 4*6 cycles to get through because the shift +// operation is distributed among several iterations. This prevents the need of +// a 10x16-input mux which is very large. Instead of that, this uses two 10x2-input mux'es +// which iterated allow the max 16 shift operation + +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}; + +always @(*) begin + shcnt_mod3 = shcnt3 != 0; + shcnt_mod4 = shcnt4 != 0; + shcnt_mod5 = shcnt5 != 0; + 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) + if( !rst_n ) begin + pcm1 <= 'd0; pcm2 <= 'd0; + pcm3 <= 'd0; pcm4 <= 'd0; + pcm5 <= 'd0; pcm6 <= 'd0; + shcnt1 <= 'd0; shcnt2 <= 'd0; + shcnt3 <= 'd0; shcnt4 <= 'd0; + shcnt5 <= 'd0; shcnt6 <= 'd0; + end else if(cen) begin + // I + pcm2 <= match ? pcm_in : pcm1; + lin2 <= lin1; + shcnt2 <= match ? sh1 : shcnt1; + match2 <= match; + // II + pcm3 <= match2 ? pcm2_mul[24:9] : pcm2; + shcnt3 <= shcnt2; + // III, shift by 0 or 1 + if( shcnt_mod3 ) begin + pcm4 <= pcm3>>>1; + shcnt4 <= shcnt3-1; + end else begin + pcm4 <= pcm3; + shcnt4 <= shcnt3; + end + // IV, shift by 0 or 1 + if( shcnt_mod4 ) begin + pcm5 <= pcm4>>>1; + shcnt5 <= shcnt4-1; + end else begin + pcm5 <= pcm4; + shcnt5 <= shcnt4; + end + // V, shift by 0 or 1 + if( shcnt_mod5 ) begin + pcm6 <= pcm5>>>1; + shcnt6 <= shcnt5-1; + end else begin + pcm6 <= pcm5; + shcnt6 <= shcnt5; + end + // VI close the loop and output + pcm1 <= pcm6; + shcnt1 <= shcnt6; + end + +endmodule // jt10_adpcm_gain diff --git a/common/Sound/JT12/hdl/adpcm/jt10_adpcma_lut.v b/common/Sound/JT12/hdl/adpcm/jt10_adpcma_lut.v new file mode 100644 index 00000000..138dff4c --- /dev/null +++ b/common/Sound/JT12/hdl/adpcm/jt10_adpcma_lut.v @@ -0,0 +1,142 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +// ADPCM-A uses a LUT because it is very sensitive to rounding +// it looks like the original algorithm also used a table + +module jt10_adpcma_lut( + input clk, // CPU clock + input rst_n, + input cen, + input [8:0] addr, // = {step,delta}; + output reg [11:0] inc +); + +reg [11:0] lut[0:391]; + +initial begin +lut[9'o00_0] = 12'd0002; lut[9'o00_1] = 12'd0006; lut[9'o00_2] = 12'd0012; lut[9'o00_3] = 12'd0016; +lut[9'o00_4] = 12'd0022; lut[9'o00_5] = 12'd0026; lut[9'o00_6] = 12'd0032; lut[9'o00_7] = 12'd0036; +lut[9'o01_0] = 12'd0002; lut[9'o01_1] = 12'd0006; lut[9'o01_2] = 12'd0012; lut[9'o01_3] = 12'd0016; +lut[9'o01_4] = 12'd0023; lut[9'o01_5] = 12'd0027; lut[9'o01_6] = 12'd0033; lut[9'o01_7] = 12'd0037; +lut[9'o02_0] = 12'd0002; lut[9'o02_1] = 12'd0007; lut[9'o02_2] = 12'd0013; lut[9'o02_3] = 12'd0020; +lut[9'o02_4] = 12'd0025; lut[9'o02_5] = 12'd0032; lut[9'o02_6] = 12'd0036; lut[9'o02_7] = 12'd0043; +lut[9'o03_0] = 12'd0002; lut[9'o03_1] = 12'd0007; lut[9'o03_2] = 12'd0015; lut[9'o03_3] = 12'd0022; +lut[9'o03_4] = 12'd0027; lut[9'o03_5] = 12'd0034; lut[9'o03_6] = 12'd0042; lut[9'o03_7] = 12'd0047; +lut[9'o04_0] = 12'd0002; lut[9'o04_1] = 12'd0010; lut[9'o04_2] = 12'd0016; lut[9'o04_3] = 12'd0024; +lut[9'o04_4] = 12'd0031; lut[9'o04_5] = 12'd0037; lut[9'o04_6] = 12'd0045; lut[9'o04_7] = 12'd0053; +lut[9'o05_0] = 12'd0003; lut[9'o05_1] = 12'd0011; lut[9'o05_2] = 12'd0017; lut[9'o05_3] = 12'd0025; +lut[9'o05_4] = 12'd0034; lut[9'o05_5] = 12'd0042; lut[9'o05_6] = 12'd0050; lut[9'o05_7] = 12'd0056; +lut[9'o06_0] = 12'd0003; lut[9'o06_1] = 12'd0012; lut[9'o06_2] = 12'd0021; lut[9'o06_3] = 12'd0030; +lut[9'o06_4] = 12'd0037; lut[9'o06_5] = 12'd0046; lut[9'o06_6] = 12'd0055; lut[9'o06_7] = 12'd0064; +lut[9'o07_0] = 12'd0003; lut[9'o07_1] = 12'd0013; lut[9'o07_2] = 12'd0023; lut[9'o07_3] = 12'd0033; +lut[9'o07_4] = 12'd0042; lut[9'o07_5] = 12'd0052; lut[9'o07_6] = 12'd0062; lut[9'o07_7] = 12'd0072; +lut[9'o10_0] = 12'd0004; lut[9'o10_1] = 12'd0014; lut[9'o10_2] = 12'd0025; lut[9'o10_3] = 12'd0035; +lut[9'o10_4] = 12'd0046; lut[9'o10_5] = 12'd0056; lut[9'o10_6] = 12'd0067; lut[9'o10_7] = 12'd0077; +lut[9'o11_0] = 12'd0004; lut[9'o11_1] = 12'd0015; lut[9'o11_2] = 12'd0027; lut[9'o11_3] = 12'd0040; +lut[9'o11_4] = 12'd0051; lut[9'o11_5] = 12'd0062; lut[9'o11_6] = 12'd0074; lut[9'o11_7] = 12'd0105; +lut[9'o12_0] = 12'd0005; lut[9'o12_1] = 12'd0017; lut[9'o12_2] = 12'd0031; lut[9'o12_3] = 12'd0043; +lut[9'o12_4] = 12'd0056; lut[9'o12_5] = 12'd0070; lut[9'o12_6] = 12'd0102; lut[9'o12_7] = 12'd0114; +lut[9'o13_0] = 12'd0005; lut[9'o13_1] = 12'd0020; lut[9'o13_2] = 12'd0034; lut[9'o13_3] = 12'd0047; +lut[9'o13_4] = 12'd0062; lut[9'o13_5] = 12'd0075; lut[9'o13_6] = 12'd0111; lut[9'o13_7] = 12'd0124; +lut[9'o14_0] = 12'd0006; lut[9'o14_1] = 12'd0022; lut[9'o14_2] = 12'd0037; lut[9'o14_3] = 12'd0053; +lut[9'o14_4] = 12'd0070; lut[9'o14_5] = 12'd0104; lut[9'o14_6] = 12'd0121; lut[9'o14_7] = 12'd0135; +lut[9'o15_0] = 12'd0006; lut[9'o15_1] = 12'd0024; lut[9'o15_2] = 12'd0042; lut[9'o15_3] = 12'd0060; +lut[9'o15_4] = 12'd0075; lut[9'o15_5] = 12'd0113; lut[9'o15_6] = 12'd0131; lut[9'o15_7] = 12'd0147; +lut[9'o16_0] = 12'd0007; lut[9'o16_1] = 12'd0026; lut[9'o16_2] = 12'd0045; lut[9'o16_3] = 12'd0064; +lut[9'o16_4] = 12'd0103; lut[9'o16_5] = 12'd0122; lut[9'o16_6] = 12'd0141; lut[9'o16_7] = 12'd0160; +lut[9'o17_0] = 12'd0010; lut[9'o17_1] = 12'd0030; lut[9'o17_2] = 12'd0051; lut[9'o17_3] = 12'd0071; +lut[9'o17_4] = 12'd0112; lut[9'o17_5] = 12'd0132; lut[9'o17_6] = 12'd0153; lut[9'o17_7] = 12'd0173; +lut[9'o20_0] = 12'd0011; lut[9'o20_1] = 12'd0033; lut[9'o20_2] = 12'd0055; lut[9'o20_3] = 12'd0077; +lut[9'o20_4] = 12'd0122; lut[9'o20_5] = 12'd0144; lut[9'o20_6] = 12'd0166; lut[9'o20_7] = 12'd0210; +lut[9'o21_0] = 12'd0012; lut[9'o21_1] = 12'd0036; lut[9'o21_2] = 12'd0062; lut[9'o21_3] = 12'd0106; +lut[9'o21_4] = 12'd0132; lut[9'o21_5] = 12'd0156; lut[9'o21_6] = 12'd0202; lut[9'o21_7] = 12'd0226; +lut[9'o22_0] = 12'd0013; lut[9'o22_1] = 12'd0041; lut[9'o22_2] = 12'd0067; lut[9'o22_3] = 12'd0115; +lut[9'o22_4] = 12'd0143; lut[9'o22_5] = 12'd0171; lut[9'o22_6] = 12'd0217; lut[9'o22_7] = 12'd0245; +lut[9'o23_0] = 12'd0014; lut[9'o23_1] = 12'd0044; lut[9'o23_2] = 12'd0074; lut[9'o23_3] = 12'd0124; +lut[9'o23_4] = 12'd0155; lut[9'o23_5] = 12'd0205; lut[9'o23_6] = 12'd0235; lut[9'o23_7] = 12'd0265; +lut[9'o24_0] = 12'd0015; lut[9'o24_1] = 12'd0050; lut[9'o24_2] = 12'd0102; lut[9'o24_3] = 12'd0135; +lut[9'o24_4] = 12'd0170; lut[9'o24_5] = 12'd0223; lut[9'o24_6] = 12'd0255; lut[9'o24_7] = 12'd0310; +lut[9'o25_0] = 12'd0016; lut[9'o25_1] = 12'd0054; lut[9'o25_2] = 12'd0111; lut[9'o25_3] = 12'd0147; +lut[9'o25_4] = 12'd0204; lut[9'o25_5] = 12'd0242; lut[9'o25_6] = 12'd0277; lut[9'o25_7] = 12'd0335; +lut[9'o26_0] = 12'd0020; lut[9'o26_1] = 12'd0060; lut[9'o26_2] = 12'd0121; lut[9'o26_3] = 12'd0161; +lut[9'o26_4] = 12'd0222; lut[9'o26_5] = 12'd0262; lut[9'o26_6] = 12'd0323; lut[9'o26_7] = 12'd0363; +lut[9'o27_0] = 12'd0021; lut[9'o27_1] = 12'd0065; lut[9'o27_2] = 12'd0131; lut[9'o27_3] = 12'd0175; +lut[9'o27_4] = 12'd0240; lut[9'o27_5] = 12'd0304; lut[9'o27_6] = 12'd0350; lut[9'o27_7] = 12'd0414; +lut[9'o30_0] = 12'd0023; lut[9'o30_1] = 12'd0072; lut[9'o30_2] = 12'd0142; lut[9'o30_3] = 12'd0211; +lut[9'o30_4] = 12'd0260; lut[9'o30_5] = 12'd0327; lut[9'o30_6] = 12'd0377; lut[9'o30_7] = 12'd0446; +lut[9'o31_0] = 12'd0025; lut[9'o31_1] = 12'd0100; lut[9'o31_2] = 12'd0154; lut[9'o31_3] = 12'd0227; +lut[9'o31_4] = 12'd0302; lut[9'o31_5] = 12'd0355; lut[9'o31_6] = 12'd0431; lut[9'o31_7] = 12'd0504; +lut[9'o32_0] = 12'd0027; lut[9'o32_1] = 12'd0107; lut[9'o32_2] = 12'd0166; lut[9'o32_3] = 12'd0246; +lut[9'o32_4] = 12'd0325; lut[9'o32_5] = 12'd0405; lut[9'o32_6] = 12'd0464; lut[9'o32_7] = 12'd0544; +lut[9'o33_0] = 12'd0032; lut[9'o33_1] = 12'd0116; lut[9'o33_2] = 12'd0202; lut[9'o33_3] = 12'd0266; +lut[9'o33_4] = 12'd0353; lut[9'o33_5] = 12'd0437; lut[9'o33_6] = 12'd0523; lut[9'o33_7] = 12'd0607; +lut[9'o34_0] = 12'd0034; lut[9'o34_1] = 12'd0126; lut[9'o34_2] = 12'd0217; lut[9'o34_3] = 12'd0311; +lut[9'o34_4] = 12'd0402; lut[9'o34_5] = 12'd0474; lut[9'o34_6] = 12'd0565; lut[9'o34_7] = 12'd0657; +lut[9'o35_0] = 12'd0037; lut[9'o35_1] = 12'd0136; lut[9'o35_2] = 12'd0236; lut[9'o35_3] = 12'd0335; +lut[9'o35_4] = 12'd0434; lut[9'o35_5] = 12'd0533; lut[9'o35_6] = 12'd0633; lut[9'o35_7] = 12'd0732; +lut[9'o36_0] = 12'd0042; lut[9'o36_1] = 12'd0150; lut[9'o36_2] = 12'd0256; lut[9'o36_3] = 12'd0364; +lut[9'o36_4] = 12'd0471; lut[9'o36_5] = 12'd0577; lut[9'o36_6] = 12'd0705; lut[9'o36_7] = 12'd1013; +lut[9'o37_0] = 12'd0046; lut[9'o37_1] = 12'd0163; lut[9'o37_2] = 12'd0277; lut[9'o37_3] = 12'd0414; +lut[9'o37_4] = 12'd0531; lut[9'o37_5] = 12'd0646; lut[9'o37_6] = 12'd0762; lut[9'o37_7] = 12'd1077; +lut[9'o40_0] = 12'd0052; lut[9'o40_1] = 12'd0176; lut[9'o40_2] = 12'd0322; lut[9'o40_3] = 12'd0446; +lut[9'o40_4] = 12'd0573; lut[9'o40_5] = 12'd0717; lut[9'o40_6] = 12'd1043; lut[9'o40_7] = 12'd1167; +lut[9'o41_0] = 12'd0056; lut[9'o41_1] = 12'd0213; lut[9'o41_2] = 12'd0347; lut[9'o41_3] = 12'd0504; +lut[9'o41_4] = 12'd0641; lut[9'o41_5] = 12'd0776; lut[9'o41_6] = 12'd1132; lut[9'o41_7] = 12'd1267; +lut[9'o42_0] = 12'd0063; lut[9'o42_1] = 12'd0231; lut[9'o42_2] = 12'd0377; lut[9'o42_3] = 12'd0545; +lut[9'o42_4] = 12'd0713; lut[9'o42_5] = 12'd1061; lut[9'o42_6] = 12'd1227; lut[9'o42_7] = 12'd1375; +lut[9'o43_0] = 12'd0070; lut[9'o43_1] = 12'd0250; lut[9'o43_2] = 12'd0430; lut[9'o43_3] = 12'd0610; +lut[9'o43_4] = 12'd0771; lut[9'o43_5] = 12'd1151; lut[9'o43_6] = 12'd1331; lut[9'o43_7] = 12'd1511; +lut[9'o44_0] = 12'd0075; lut[9'o44_1] = 12'd0271; lut[9'o44_2] = 12'd0464; lut[9'o44_3] = 12'd0660; +lut[9'o44_4] = 12'd1053; lut[9'o44_5] = 12'd1247; lut[9'o44_6] = 12'd1442; lut[9'o44_7] = 12'd1636; +lut[9'o45_0] = 12'd0104; lut[9'o45_1] = 12'd0314; lut[9'o45_2] = 12'd0524; lut[9'o45_3] = 12'd0734; +lut[9'o45_4] = 12'd1144; lut[9'o45_5] = 12'd1354; lut[9'o45_6] = 12'd1564; lut[9'o45_7] = 12'd1774; +lut[9'o46_0] = 12'd0112; lut[9'o46_1] = 12'd0340; lut[9'o46_2] = 12'd0565; lut[9'o46_3] = 12'd1013; +lut[9'o46_4] = 12'd1240; lut[9'o46_5] = 12'd1466; lut[9'o46_6] = 12'd1713; lut[9'o46_7] = 12'd2141; +lut[9'o47_0] = 12'd0122; lut[9'o47_1] = 12'd0366; lut[9'o47_2] = 12'd0633; lut[9'o47_3] = 12'd1077; +lut[9'o47_4] = 12'd1344; lut[9'o47_5] = 12'd1610; lut[9'o47_6] = 12'd2055; lut[9'o47_7] = 12'd2321; +lut[9'o50_0] = 12'd0132; lut[9'o50_1] = 12'd0417; lut[9'o50_2] = 12'd0704; lut[9'o50_3] = 12'd1171; +lut[9'o50_4] = 12'd1456; lut[9'o50_5] = 12'd1743; lut[9'o50_6] = 12'd2230; lut[9'o50_7] = 12'd2515; +lut[9'o51_0] = 12'd0143; lut[9'o51_1] = 12'd0452; lut[9'o51_2] = 12'd0761; lut[9'o51_3] = 12'd1270; +lut[9'o51_4] = 12'd1577; lut[9'o51_5] = 12'd2106; lut[9'o51_6] = 12'd2415; lut[9'o51_7] = 12'd2724; +lut[9'o52_0] = 12'd0155; lut[9'o52_1] = 12'd0510; lut[9'o52_2] = 12'd1043; lut[9'o52_3] = 12'd1376; +lut[9'o52_4] = 12'd1731; lut[9'o52_5] = 12'd2264; lut[9'o52_6] = 12'd2617; lut[9'o52_7] = 12'd3152; +lut[9'o53_0] = 12'd0170; lut[9'o53_1] = 12'd0551; lut[9'o53_2] = 12'd1131; lut[9'o53_3] = 12'd1512; +lut[9'o53_4] = 12'd2073; lut[9'o53_5] = 12'd2454; lut[9'o53_6] = 12'd3034; lut[9'o53_7] = 12'd3415; +lut[9'o54_0] = 12'd0204; lut[9'o54_1] = 12'd0615; lut[9'o54_2] = 12'd1226; lut[9'o54_3] = 12'd1637; +lut[9'o54_4] = 12'd2250; lut[9'o54_5] = 12'd2661; lut[9'o54_6] = 12'd3272; lut[9'o54_7] = 12'd3703; +lut[9'o55_0] = 12'd0221; lut[9'o55_1] = 12'd0665; lut[9'o55_2] = 12'd1330; lut[9'o55_3] = 12'd1774; +lut[9'o55_4] = 12'd2437; lut[9'o55_5] = 12'd3103; lut[9'o55_6] = 12'd3546; lut[9'o55_7] = 12'd3777; +lut[9'o56_0] = 12'd0240; lut[9'o56_1] = 12'd0740; lut[9'o56_2] = 12'd1441; lut[9'o56_3] = 12'd2141; +lut[9'o56_4] = 12'd2642; lut[9'o56_5] = 12'd3342; lut[9'o56_6] = 12'd3777; lut[9'o56_7] = 12'd3777; +lut[9'o57_0] = 12'd0260; lut[9'o57_1] = 12'd1021; lut[9'o57_2] = 12'd1561; lut[9'o57_3] = 12'd2322; +lut[9'o57_4] = 12'd3063; lut[9'o57_5] = 12'd3624; lut[9'o57_6] = 12'd3777; lut[9'o57_7] = 12'd3777; +lut[9'o60_0] = 12'd0302; lut[9'o60_1] = 12'd1106; lut[9'o60_2] = 12'd1712; lut[9'o60_3] = 12'd2516; +lut[9'o60_4] = 12'd3322; lut[9'o60_5] = 12'd3777; lut[9'o60_6] = 12'd3777; lut[9'o60_7] = 12'd3777; +end + +always @(posedge clk or negedge rst_n) + if(!rst_n) + inc <= 'd0; + else if(cen) + inc <= lut[addr]; + +endmodule // jt10_adpcma_lut \ No newline at end of file diff --git a/common/Sound/JT12/hdl/adpcm/jt10_adpcmb.v b/common/Sound/JT12/hdl/adpcm/jt10_adpcmb.v new file mode 100644 index 00000000..a17c754a --- /dev/null +++ b/common/Sound/JT12/hdl/adpcm/jt10_adpcmb.v @@ -0,0 +1,112 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +// Sampling rates: 2kHz ~ 55.5 kHz. in 0.85Hz steps + +module jt10_adpcmb( + input rst_n, + input clk, // CPU clock + input cen, // optional clock enable, if not needed leave as 1'b1 + input [3:0] data, + input chon, // high if this channel is on + input adv, + output signed [15:0] pcm +); + +localparam stepw = 15, xw=16; + +reg signed [xw-1:0] x1, next_x5; +reg [stepw-1:0] step1; +reg [stepw+1:0] next_step3; +assign pcm = x1[xw-1:xw-16]; + +wire [xw-1:0] limpos = {1'b0, {xw-1{1'b1}}}; +wire [xw-1:0] limneg = {1'b1, {xw-1{1'b0}}}; + +reg [18:0] d2l; +reg [xw-1:0] d3,d4; +reg [3:0] d2; +reg [7:0] step_val; +reg [22:0] step2l; + +always @(*) begin + casez( d2[3:1] ) + 3'b0_??: step_val = 8'd57; + 3'b1_00: step_val = 8'd77; + 3'b1_01: step_val = 8'd102; + 3'b1_10: step_val = 8'd128; + 3'b1_11: step_val = 8'd153; + endcase + d2l = d2 * step1; // 4 + 15 = 19 bits -> div by 8 -> 16 bits + step2l = step_val * step1; // 15 bits + 8 bits = 23 bits -> div 64 -> 17 bits +end + +// Original pipeline: 6 stages, 6 channels take 36 clock cycles +// 8 MHz -> /12 divider -> 666 kHz +// 666 kHz -> 18.5 kHz = 55.5/3 kHz + +reg [3:0] data2; +reg sign_data; + +reg [3:0] adv2; + +always @( posedge clk or negedge rst_n ) + if( ! rst_n ) begin + x1 <= 'd0; step1 <= 'd127; + d2 <= 'd0; d3 <= 'd0; d4 <= 'd0; + end else if(cen) begin + adv2 <= {1'b0,adv2[3:1]}; + // I + if( adv ) begin + d2 <= {data[2:0],1'b1}; + sign_data <= data[3]; + adv2[3] <= 1'b1; + end + // II multiply and obtain the offset + d3 <= { {xw-16{1'b0}}, d2l[18:3] }; // xw bits + next_step3<= step2l[22:6]; + // III 2's complement of d3 if necessary + d4 <= sign_data ? ~d3+1 : d3; + // IV Advance the waveform + next_x5 <= x1+d4; + // V: limit or reset outputs + if( chon ) begin // update values if needed + if( adv2[0] ) begin + if( sign_data == x1[xw-1] && (x1[xw-1]!=next_x5[xw-1]) ) + x1 <= x1[xw-1] ? limneg : limpos; + else + x1 <= next_x5; + + if( next_step3 < 127 ) + step1 <= 15'd127; + else if( next_step3 > 24576 ) + step1 <= 15'd24576; + else + step1 <= next_step3[14:0]; + end + end else begin + x1 <= 'd0; + step1 <= 'd127; + end + end + + +endmodule // jt10_adpcm \ No newline at end of file diff --git a/common/Sound/JT12/hdl/adpcm/jt10_adpcmb_cnt.v b/common/Sound/JT12/hdl/adpcm/jt10_adpcmb_cnt.v new file mode 100644 index 00000000..9491edc0 --- /dev/null +++ b/common/Sound/JT12/hdl/adpcm/jt10_adpcmb_cnt.v @@ -0,0 +1,108 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +// ADPCM-B counter + +module jt10_adpcmb_cnt( + input rst_n, + input clk, // CPU clock + input cen, // clk & cen = 55 kHz + + // counter control + input [15:0] delta_n, + input clr, + input on, + // Address + input [15:0] astart, + input [15:0] aend, + input arepeat, + output reg [23:0] addr, + output reg nibble_sel, + // Flag + output reg flag, + input clr_flag, + + output reg adv +); + +// Counter +reg [15:0] cnt; + +always @(posedge clk or negedge rst_n) + if(!rst_n) begin + cnt <= 'd0; + adv <= 'b0; + end else if(cen) begin + if( clr ) begin + cnt <= 'd0; + adv <= 'b0; + end else begin + if( on ) + {adv, cnt} <= {1'b0, cnt} + {1'b0, delta_n }; + else + adv <= 1'b1; // let the rest of the signal chain advance + // when channel is off so all registers go to reset values + end + end + +reg set_flag, last_set; + +always @(posedge clk or negedge rst_n) + if(!rst_n) begin + flag <= 1'b0; + last_set <= 'b0; + end else begin + last_set <= set_flag; + if( clr_flag ) flag <= 1'b0; + if( !last_set && set_flag ) flag <= 1'b1; + end + +// Address +reg last_on; + +always @(posedge clk or negedge rst_n) + if(!rst_n) begin + addr <= 'd0; + nibble_sel <= 'b0; + set_flag <= 'd0; + end else if(cen) begin + last_on <= on; + + if( (on && !last_on) || clr ) begin + addr <= {astart,8'd0}; + nibble_sel <= 'b0; + end else if( on && adv ) begin + if( addr[23:8] < aend ) begin + { addr, nibble_sel } <= { addr, nibble_sel } + 25'd1; + set_flag <= 'd0; + end + else begin + set_flag <= 'd1; + if(arepeat) begin + addr <= {astart,8'd0}; + nibble_sel <= 'b0; + end + end + end + end // cen + + +endmodule // jt10_adpcmb_cnt \ No newline at end of file diff --git a/common/Sound/JT12/hdl/adpcm/jt10_adpcmb_gain.v b/common/Sound/JT12/hdl/adpcm/jt10_adpcmb_gain.v new file mode 100644 index 00000000..e501c7d8 --- /dev/null +++ b/common/Sound/JT12/hdl/adpcm/jt10_adpcmb_gain.v @@ -0,0 +1,39 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +// Gain is assumed to be 0.75dB per bit. + +module jt10_adpcmb_gain( + input rst_n, + input clk, // CPU clock + input cen55, + input [ 7:0] tl, // ADPCM Total Level + input signed [15:0] pcm_in, + output reg signed [15:0] pcm_out +); + +wire signed [15:0] factor = {8'd0, tl}; +wire signed [31:0] pcm_mul = pcm_in * factor; // linear gain + +always @(posedge clk) if(cen55) + pcm_out <= pcm_mul[23:8]; + +endmodule // jt10_adpcm_gain diff --git a/common/Sound/JT12/hdl/adpcm/jt10_adpcmb_interpol.v b/common/Sound/JT12/hdl/adpcm/jt10_adpcmb_interpol.v new file mode 100644 index 00000000..02d91543 --- /dev/null +++ b/common/Sound/JT12/hdl/adpcm/jt10_adpcmb_interpol.v @@ -0,0 +1,96 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +module jt10_adpcmb_interpol( + input rst_n, + input clk, + input cen, // 8MHz cen + input cen55, // clk & cen55 = 55 kHz + input adv, + input signed [15:0] pcmdec, + output signed [15:0] pcmout +); + +localparam stages=6; + +reg signed [15:0] pcmlast, delta_x; +reg signed [16:0] pre_dx; +reg start_div=1'b0; +reg [3:0] deltan, pre_dn; +reg [stages-1:0] adv2; +reg signed [15:0] pcminter; +wire [15:0] step, next_step; +reg step_sign, next_step_sign; + +assign pcmout = pcminter; + +always @(posedge clk) if(cen) begin + adv2 <= {adv2[stages-2:0], cen55 & adv }; // give some time to get the data from memory +end + +always @(posedge clk) if(cen55) begin + if ( adv ) begin + pre_dn <= 'd1; + deltan <= pre_dn; + end else + pre_dn <= pre_dn + 1; +end + + +always @(posedge clk) if(cen) begin + start_div <= 1'b0; + if(adv2[1]) begin + pcmlast <= pcmdec; + pcminter <= pcmlast; + end + if(adv2[4]) begin + pre_dx <= { pcmdec[15], pcmdec } - { pcmlast[15], pcmlast }; + end + if( adv2[5] ) begin + start_div <= 1'b1; + delta_x <= pre_dx[16] ? ~pre_dx[15:0]+1 : pre_dx[15:0]; + next_step_sign <= pre_dx[16]; + end +end + +always @(posedge clk) if(cen55) begin + if( adv ) begin + step <= next_step; + step_sign <= next_step_sign; + pcminter <= pcmlast; + end + else pcminter <= step_sign ? pcminter - step : pcminter + step; +end + +jt10_adpcm_div #(.dw(16)) u_div( + .rst_n ( rst_n ), + .clk ( clk ), + .cen ( cen ), + .start ( start_div ), + .a ( delta_x ), + .b ( {12'd0, deltan } ), + .d ( next_step ), + .r ( ), + .working( ) +); + + +endmodule // jt10_adpcmb_interpol \ No newline at end of file diff --git a/common/Sound/JT12/hdl/adpcm/jt10_cen_burst.v b/common/Sound/JT12/hdl/adpcm/jt10_cen_burst.v new file mode 100644 index 00000000..393665ba --- /dev/null +++ b/common/Sound/JT12/hdl/adpcm/jt10_cen_burst.v @@ -0,0 +1,59 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +// Let a fixed number of clock enable pulses to pass through + +module jt10_cen_burst #(parameter cntmax=3'd6, cntw=3)( + input rst_n, + input clk, + input cen, // 8MHz cen + input start, + input start_cen, + output cen_out +); + +reg [cntw-1:0] cnt; +reg last_start; +reg pass; + +always @(posedge clk or negedge rst_n) + if( !rst_n ) begin + cnt <= {cntw{1'b1}}; + pass <= 1'b0; + end else if(cen) begin + last_start <= start; + if( start && start_cen ) begin + cnt <= 'd0; + pass <= 1'b1; + end else begin + if(cnt != cntmax ) cnt <= cnt+1; + else pass <= 1'b0; + end + end + +reg pass_negedge; +assign cen_out = cen & pass_negedge; + +always @(negedge clk) begin + pass_negedge <= pass; +end + +endmodule // jt10_cen_burst \ No newline at end of file diff --git a/common/Sound/JT12/hdl/alt/eg_cnt.v b/common/Sound/JT12/hdl/alt/eg_cnt.v new file mode 100644 index 00000000..8e838b8c --- /dev/null +++ b/common/Sound/JT12/hdl/alt/eg_cnt.v @@ -0,0 +1,84 @@ +/* +Using two large case statements: ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Module | Partition | Slices* | Slice Reg | LUTs | LUTRAM | BRAM/FIFO | DSP48A1 | BUFG | BUFIO | BUFR | DCM | PLL_ADV | Full Hierarchical | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| eg_cnt/ | | 9/13 | 13/19 | 15/18 | 0/3 | 0/0 | 0/0 | 1/1 | 0/0 | 0/0 | 0/0 | 0/0 | eg_cnt | +| +u_cntsh | | 4/4 | 6/6 | 3/3 | 3/3 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | eg_cnt/u_cntsh | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +Using one large case statement: ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Module | Partition | Slices* | Slice Reg | LUTs | LUTRAM | BRAM/FIFO | DSP48A1 | BUFG | BUFIO | BUFR | DCM | PLL_ADV | Full Hierarchical | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| eg_cnt/ | | 8/11 | 13/19 | 12/15 | 0/3 | 0/0 | 0/0 | 1/1 | 0/0 | 0/0 | 0/0 | 0/0 | eg_cnt | +| +u_cntsh | | 3/3 | 6/6 | 3/3 | 3/3 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | eg_cnt/u_cntsh | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +*/ + +module eg_cnt( + input clk, + input clk_en, + input rst, + input [14:0] eg_cnt, + input [2:0] state_IV, + input [5:0] rate_IV, + + output reg [2:0] state_V, + output reg [5:0] rate_V, + output [2:0] cnt_V, + output reg sum_up +); + +localparam ATTACK=3'd0, DECAY1=3'd1, DECAY2=3'd2, RELEASE=3'd7, HOLD=3'd3; +wire [2:0] cnt_out; +assign cnt_V = cnt_out; +reg lsb; +reg [2:0] cnt_in; +reg [3:0] mux_sel; + +always @(*) begin + mux_sel = (state_IV == ATTACK && rate_IV[5:2]!=4'hf) ? (rate_IV[5:2]+4'd1): rate_IV[5:2]; + case( mux_sel ) + 4'h0: lsb = eg_cnt[12]; + 4'h1: lsb = eg_cnt[11]; + 4'h2: lsb = eg_cnt[10]; + 4'h3: lsb = eg_cnt[ 9]; + 4'h4: lsb = eg_cnt[ 8]; + 4'h5: lsb = eg_cnt[ 7]; + 4'h6: lsb = eg_cnt[ 6]; + 4'h7: lsb = eg_cnt[ 5]; + 4'h8: lsb = eg_cnt[ 4]; + 4'h9: lsb = eg_cnt[ 3]; + 4'ha: lsb = eg_cnt[ 2]; + 4'hb: lsb = eg_cnt[ 1]; + default: lsb = eg_cnt[ 0]; + endcase + cnt_in =lsb!=cnt_out ? (cnt_out+3'd1) : cnt_out; +end + +always @(posedge clk) if( clk_en ) begin + if( rst ) begin + state_V <= RELEASE; + rate_V <= 6'h1F; // should it be 6'h3F? TODO + //cnt_V<= 3'd0; + end + else begin + state_V <= state_IV; + rate_V <= rate_IV; + end +end + +jt12_sh/*_rst*/ #( .width(3), .stages(24) ) u_cntsh( + .clk ( clk ), + .clk_en ( clk_en ), +// .rst ( rst ), + .din ( cnt_in ), + .drop ( cnt_out ) +); + +always @(posedge clk) + if( clk_en ) + sum_up <= lsb!=cnt_out; + +endmodule // eg_mux \ No newline at end of file diff --git a/common/Sound/JT12/hdl/alt/eg_comb.v b/common/Sound/JT12/hdl/alt/eg_comb.v new file mode 100644 index 00000000..7f127669 --- /dev/null +++ b/common/Sound/JT12/hdl/alt/eg_comb.v @@ -0,0 +1,184 @@ +/* ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Module | Partition | Slices* | Slice Reg | LUTs | LUTRAM | BRAM/FIFO | DSP48A1 | BUFG | BUFIO | BUFR | DCM | PLL_ADV | Full Hierarchical | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| eg_comb/ | | 49/49 | 0/0 | 153/153 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | eg_comb | +| eg_comb/ | | 42/42 | 0/0 | 134/134 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | eg_comb | +| eg_comb/ | | 39/39 | 0/0 | 129/129 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | eg_comb | +| eg_comb/ | | 43/43 | 0/0 | 122/122 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | eg_comb | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +This module represents all the envelope generator calculations. +Everything is combinational. The testbench ver/eg2 checks the +functionality of this module. + +*/ + +module eg_comb( + input attack, + input [ 4:0] base_rate, + input [ 4:0] keycode, + input [14:0] eg_cnt, + input cnt_in, + input [ 1:0] ks, + input [ 9:0] eg_in, + input [ 6:0] lfo_mod, + input amsen, + input [ 1:0] ams, + input [ 6:0] tl, + output cnt_lsb, + output reg [9:0] eg_limited, + output reg [9:0] eg_pure +); + +reg [6:0] pre_rate; +reg [5:0] rate; + +always @(*) begin : pre_rate_calc + if( base_rate == 5'd0 ) + pre_rate = 7'd0; + else + case( ks ) + 2'd3: pre_rate = { base_rate, 1'b0 } + { 1'b0, keycode }; + 2'd2: pre_rate = { base_rate, 1'b0 } + { 2'b0, keycode[4:1] }; + 2'd1: pre_rate = { base_rate, 1'b0 } + { 3'b0, keycode[4:2] }; + 2'd0: pre_rate = { base_rate, 1'b0 } + { 4'b0, keycode[4:3] }; + endcase +end + +always @(*) + rate = pre_rate[6] ? 6'd63 : pre_rate[5:0]; + +reg [2:0] cnt; + +reg [4:0] mux_sel; +always @(*) begin + mux_sel = attack ? (rate[5:2]+4'd1): {1'b0,rate[5:2]}; +end // always @(*) + +always @(*) + case( mux_sel ) + 5'h0: cnt = eg_cnt[14:12]; + 5'h1: cnt = eg_cnt[13:11]; + 5'h2: cnt = eg_cnt[12:10]; + 5'h3: cnt = eg_cnt[11: 9]; + 5'h4: cnt = eg_cnt[10: 8]; + 5'h5: cnt = eg_cnt[ 9: 7]; + 5'h6: cnt = eg_cnt[ 8: 6]; + 5'h7: cnt = eg_cnt[ 7: 5]; + 5'h8: cnt = eg_cnt[ 6: 4]; + 5'h9: cnt = eg_cnt[ 5: 3]; + 5'ha: cnt = eg_cnt[ 4: 2]; + 5'hb: cnt = eg_cnt[ 3: 1]; + default: cnt = eg_cnt[ 2: 0]; + endcase + +//////////////////////////////// +reg step; +reg [7:0] step_idx; + +always @(*) begin : rate_step + if( rate[5:4]==2'b11 ) begin // 0 means 1x, 1 means 2x + if( rate[5:2]==4'hf && attack) + step_idx = 8'b11111111; // Maximum attack speed, rates 60&61 + else + case( rate[1:0] ) + 2'd0: step_idx = 8'b00000000; + 2'd1: step_idx = 8'b10001000; // 2 + 2'd2: step_idx = 8'b10101010; // 4 + 2'd3: step_idx = 8'b11101110; // 6 + endcase + end + else begin + if( rate[5:2]==4'd0 && !attack) + step_idx = 8'b11111110; // limit slowest decay rate + else + case( rate[1:0] ) + 2'd0: step_idx = 8'b10101010; // 4 + 2'd1: step_idx = 8'b11101010; // 5 + 2'd2: step_idx = 8'b11101110; // 6 + 2'd3: step_idx = 8'b11111110; // 7 + endcase + end + // a rate of zero keeps the level still + step = rate[5:1]==5'd0 ? 1'b0 : step_idx[ cnt ]; +end + +reg sum_up; +assign cnt_lsb = cnt[0]; +always @(*) begin + sum_up = cnt[0] != cnt_in; +end +////////////////////////////////////////////////////////////// +// cnt/cnt_lsb/cnt_in not used below this point + +reg [3:0] dr_sum; +reg [10:0] dr_result; + +always @(*) begin + case( rate[5:2] ) + 4'b1100: dr_sum = { 2'b0, step, ~step }; // 12 + 4'b1101: dr_sum = { 1'b0, step, ~step, 1'b0 }; // 13 + 4'b1110: dr_sum = { step, ~step, 2'b0 }; // 14 + 4'b1111: dr_sum = 4'd8;// 15 + default: dr_sum = { 2'b0, step, 1'b0 }; + endcase + dr_result = {6'd0, dr_sum} + eg_in; +end + +reg [ 7:0] ar_sum0; +reg [ 8:0] ar_sum1; +reg [10:0] ar_result; +reg [ 9:0] ar_sum; + +always @(*) begin : ar_calculation + casez( rate[5:2] ) + default: ar_sum0 = {2'd0, eg_in[9:4]}; + 4'b1101: ar_sum0 = {1'd0, eg_in[9:3]}; + 4'b111?: ar_sum0 = eg_in[9:2]; + endcase + ar_sum1 = ar_sum0+9'd1; + if( rate[5:4] == 2'b11 ) + ar_sum = step ? { ar_sum1, 1'b0 } : { 1'b0, ar_sum1 }; + else + ar_sum = step ? { 1'b0, ar_sum1 } : 10'd0; + ar_result = rate[5:1]==5'h1F ? 11'd0 : eg_in-ar_sum; +end +/////////////////////////////////////////////////////////// +// rate not used below this point +always @(*) begin + if(sum_up) begin + if( attack ) + eg_pure = ar_result[10] ? 10'd0: ar_result[9:0]; + else + eg_pure = dr_result[10] ? 10'h3FF : dr_result[9:0]; + end + else eg_pure = eg_in; +end + +////////////////////////////////////////////////////////////// +reg [ 8:0] am_final; +reg [10:0] sum_eg_tl; +reg [11:0] sum_eg_tl_am; +reg [ 5:0] am_inverted; + +always @(*) begin + am_inverted = lfo_mod[6] ? ~lfo_mod[5:0] : lfo_mod[5:0]; +end + +always @(*) begin + casez( {amsen, ams } ) + default: am_final = 9'd0; + 3'b1_01: am_final = { 5'd0, am_inverted[5:2] }; + 3'b1_10: am_final = { 3'd0, am_inverted }; + 3'b1_11: am_final = { 2'd0, am_inverted, 1'b0 }; + endcase + sum_eg_tl = { tl, 3'd0 } + eg_pure; + sum_eg_tl_am = sum_eg_tl + { 3'd0, am_final }; +end + +always @(*) + eg_limited = sum_eg_tl_am[11:10]==2'd0 ? sum_eg_tl_am[9:0] : 10'h3ff; + + +endmodule // eg_comb \ No newline at end of file diff --git a/common/Sound/JT12/hdl/alt/eg_mux.v b/common/Sound/JT12/hdl/alt/eg_mux.v new file mode 100644 index 00000000..6e59c212 --- /dev/null +++ b/common/Sound/JT12/hdl/alt/eg_mux.v @@ -0,0 +1,79 @@ +/* +Using two large case statements: ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Module | Partition | Slices* | Slice Reg | LUTs | LUTRAM | BRAM/FIFO | DSP48A1 | BUFG | BUFIO | BUFR | DCM | PLL_ADV | Full Hierarchical | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| eg_mux/ | | 11/12 | 13/14 | 31/31 | 1/1 | 0/0 | 0/0 | 1/1 | 0/0 | 0/0 | 0/0 | 0/0 | eg_mux | +| +u_cntsh | | 1/1 | 1/1 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | eg_mux/u_cntsh | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +Using one large case statement: ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Module | Partition | Slices* | Slice Reg | LUTs | LUTRAM | BRAM/FIFO | DSP48A1 | BUFG | BUFIO | BUFR | DCM | PLL_ADV | Full Hierarchical | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| eg_mux/ | | 11/12 | 13/14 | 21/21 | 1/1 | 0/0 | 0/0 | 1/1 | 0/0 | 0/0 | 0/0 | 0/0 | eg_mux | +| +u_cntsh | | 1/1 | 1/1 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | eg_mux/u_cntsh | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +*/ + +module eg_mux( + input clk, + input clk_en, + input rst, + input [14:0] eg_cnt, + input [2:0] state_IV, + input [5:0] rate_IV, + + output reg [2:0] state_V, + output reg [5:0] rate_V, + output reg [2:0] cnt_V, + output reg sum_up +); + +localparam ATTACK=3'd0, DECAY1=3'd1, DECAY2=3'd2, RELEASE=3'd7, HOLD=3'd3; +wire cnt_out; +reg [3:0] mux_sel; + +always @(*) begin + mux_sel = (state_IV == ATTACK && rate_IV[5:2]!=4'hf) ? (rate_IV[5:2]+4'd1): rate_IV[5:2]; +end // always @(*) + +always @(posedge clk) if( clk_en ) begin + if( rst ) begin + state_V <= RELEASE; + rate_V <= 6'h1F; // should it be 6'h3F? TODO + //cnt_V<= 3'd0; + end + else begin + state_V <= state_IV; + rate_V <= rate_IV; + case( mux_sel ) + 4'h0: cnt_V <= eg_cnt[14:12]; + 4'h1: cnt_V <= eg_cnt[13:11]; + 4'h2: cnt_V <= eg_cnt[12:10]; + 4'h3: cnt_V <= eg_cnt[11: 9]; + 4'h4: cnt_V <= eg_cnt[10: 8]; + 4'h5: cnt_V <= eg_cnt[ 9: 7]; + 4'h6: cnt_V <= eg_cnt[ 8: 6]; + 4'h7: cnt_V <= eg_cnt[ 7: 5]; + 4'h8: cnt_V <= eg_cnt[ 6: 4]; + 4'h9: cnt_V <= eg_cnt[ 5: 3]; + 4'ha: cnt_V <= eg_cnt[ 4: 2]; + 4'hb: cnt_V <= eg_cnt[ 3: 1]; + default: cnt_V <= eg_cnt[ 2: 0]; + endcase + end +end + +jt12_sh/*_rst*/ #( .width(1), .stages(24) ) u_cntsh( + .clk ( clk ), + .clk_en ( clk_en ), +// .rst ( rst ), + .din ( cnt_V[0] ), + .drop ( cnt_out ) +); + +always @(posedge clk) + if( clk_en ) + sum_up <= cnt_V[0] != cnt_out; + +endmodule // eg_mux \ No newline at end of file diff --git a/common/Sound/JT12/hdl/alt/eg_step.v b/common/Sound/JT12/hdl/alt/eg_step.v new file mode 100644 index 00000000..a06614f6 --- /dev/null +++ b/common/Sound/JT12/hdl/alt/eg_step.v @@ -0,0 +1,46 @@ +/* ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Module | Partition | Slices* | Slice Reg | LUTs | LUTRAM | BRAM/FIFO | DSP48A1 | BUFG | BUFIO | BUFR | DCM | PLL_ADV | Full Hierarchical | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| eg_step/ | | 3/3 | 0/0 | 7/7 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | eg_step | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +*/ + +module eg_step( + input [2:0] state_V, + input [5:0] rate_V, + input [2:0] cnt_V, + output reg step_V +); + +localparam ATTACK=3'd0, DECAY1=3'd1, DECAY2=3'd2, RELEASE=3'd7, HOLD=3'd3; +reg [7:0] step_idx; + +always @(*) begin : rate_step + if( rate_V[5:4]==2'b11 ) begin // 0 means 1x, 1 means 2x + if( rate_V[5:2]==4'hf && state_V == ATTACK) + step_idx = 8'b11111111; // Maximum attack speed, rates 60&61 + else + case( rate_V[1:0] ) + 2'd0: step_idx = 8'b00000000; + 2'd1: step_idx = 8'b10001000; // 2 + 2'd2: step_idx = 8'b10101010; // 4 + 2'd3: step_idx = 8'b11101110; // 6 + endcase + end + else begin + if( rate_V[5:2]==4'd0 && state_V != ATTACK) + step_idx = 8'b11111110; // limit slowest decay rate_IV + else + case( rate_V[1:0] ) + 2'd0: step_idx = 8'b10101010; // 4 + 2'd1: step_idx = 8'b11101010; // 5 + 2'd2: step_idx = 8'b11101110; // 6 + 2'd3: step_idx = 8'b11111110; // 7 + endcase + end + // a rate_IV of zero keeps the level still + step_V = rate_V[5:1]==5'd0 ? 1'b0 : step_idx[ cnt_V ]; +end + +endmodule // eg_step \ No newline at end of file diff --git a/common/Sound/JT12/hdl/alt/eg_step_ram.v b/common/Sound/JT12/hdl/alt/eg_step_ram.v new file mode 100644 index 00000000..ea701ebc --- /dev/null +++ b/common/Sound/JT12/hdl/alt/eg_step_ram.v @@ -0,0 +1,45 @@ +/* ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Module | Partition | Slices* | Slice Reg | LUTs | LUTRAM | BRAM/FIFO | DSP48A1 | BUFG | BUFIO | BUFR | DCM | PLL_ADV | Full Hierarchical | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| eg_step_ram/ | | 3/3 | 0/0 | 7/7 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | 0/0 | eg_step | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +*/ + +module eg_step_ram( + input [2:0] state_V, + input [5:0] rate_V, + input [2:0] cnt_V, + output reg step_V +); + +localparam ATTACK=3'd0, DECAY1=3'd1, DECAY2=3'd2, RELEASE=3'd7, HOLD=3'd3; +reg [7:0] step_idx; +reg [7:0] step_ram; + +always @(*) + case( { rate_V[5:4]==2'b11, rate_V[1:0]} ) + 3'd0: step_ram = 8'b00000000; + 3'd1: step_ram = 8'b10001000; // 2 + 3'd2: step_ram = 8'b10101010; // 4 + 3'd3: step_ram = 8'b11101110; // 6 + 3'd4: step_ram = 8'b10101010; // 4 + 3'd5: step_ram = 8'b11101010; // 5 + 3'd6: step_ram = 8'b11101110; // 6 + 3'd7: step_ram = 8'b11111110; // 7 + endcase + +always @(*) begin : rate_step + if( rate_V[5:2]==4'hf && state_V == ATTACK) + step_idx = 8'b11111111; // Maximum attack speed, rates 60&61 + else + if( rate_V[5:2]==4'd0 && state_V != ATTACK) + step_idx = 8'b11111110; // limit slowest decay rate_IV + else + step_idx = step_ram; + // a rate_IV of zero keeps the level still + step_V = rate_V[5:1]==5'd0 ? 1'b0 : step_idx[ cnt_V ]; +end + +endmodule // eg_step \ No newline at end of file diff --git a/common/Sound/JT12/hdl/dac/jt12_dac.v b/common/Sound/JT12/hdl/dac/jt12_dac.v new file mode 100644 index 00000000..6fb6ed0e --- /dev/null +++ b/common/Sound/JT12/hdl/dac/jt12_dac.v @@ -0,0 +1,56 @@ +/* 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 . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: March, 9th 2017 + */ + +`timescale 1ns / 1ps + +/* + + input sampling rate must be the same as clk frequency + interpolation the input signal accordingly to get the + right sampling rate + +*/ + +module jt12_dac #(parameter width=12) +( + input clk, + input rst, + input signed [width-1:0] din, + output dout +); +localparam acc_w = width+1; + +reg [width-1:0] nosign; +reg [acc_w-1:0] acc; +wire [acc_w-2:0] err = acc[acc_w-2:0]; + +assign dout = acc[acc_w-1]; + +always @(posedge clk) +if( rst ) begin + acc <= {(acc_w){1'b0}}; + nosign <= {width{1'b0}}; +end +else begin + nosign <= { ~din[width-1], din[width-2:0] }; + acc <= nosign + err; +end + +endmodule diff --git a/common/Sound/JT12/hdl/dac/jt12_dac2.v b/common/Sound/JT12/hdl/dac/jt12_dac2.v new file mode 100644 index 00000000..08f7af41 --- /dev/null +++ b/common/Sound/JT12/hdl/dac/jt12_dac2.v @@ -0,0 +1,63 @@ +/* This file is part of JT12. + + JT12 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: March, 9th 2017 + */ + +`timescale 1ns / 1ps + +/* + + input sampling rate must be the same as clk frequency + interpolate input signal accordingly to get the + right sampling rate. + + Refer to sigmadelta.ods to see how the internal width (int_w) + was determined. + +*/ + +module jt12_dac2 #(parameter width=12) +( + input clk, + input rst, + input signed [width-1:0] din, + output reg dout +); + +localparam int_w = width+5; + +reg [int_w-1:0] y, error, error_1, error_2; + +wire [width-1:0] undin = { ~din[width-1], din[width-2:0] }; + +always @(*) begin + y = undin + { error_1, 1'b0} - error_2; + dout = ~y[int_w-1]; + error = y - {dout, {width{1'b0}}}; +end + +always @(posedge clk) + if( rst ) begin + error_1 <= {int_w{1'b0}}; + error_2 <= {int_w{1'b0}}; + end else begin + error_1 <= error; + error_2 <= error_1; + end + +endmodule diff --git a/common/Sound/JT12/hdl/deprecated/jt12_amp.v b/common/Sound/JT12/hdl/deprecated/jt12_amp.v new file mode 100644 index 00000000..ddb9c401 --- /dev/null +++ b/common/Sound/JT12/hdl/deprecated/jt12_amp.v @@ -0,0 +1,172 @@ +`timescale 1ns / 1ps + + +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 23-2-2017 + +*/ + + + +`timescale 1ns / 1ps + +module jt12_amp( + input clk, + input rst, + input sample, + input [2:0] volume, + + input signed [13:0] pre, + output reg signed [15:0] post +); + +wire signed [14:0] x2 = pre<<<1; +wire signed [15:0] x3 = x2+pre; +wire signed [15:0] x4 = pre<<<2; +//wire signed [16:0] x5 = x4+pre; +wire signed [16:0] x6 = x4+x2; +//wire signed [16:0] x7 = x4+x3; +wire signed [16:0] x8 = pre<<<3; +wire signed [17:0] x12 = x8+x4; +wire signed [17:0] x16 = pre<<<4; + +always @(posedge clk) +if( rst ) + post <= 16'd0; +else +if( sample ) + case( volume ) + 3'd0: // /2 + post <= { {2{pre[13]}}, pre }; + 3'd1: // x1 + post <= { x2[14], x2 }; + 3'd2: // x2 + post <= { x2, 1'd0 }; + /* + 3'd3: // x3 + case( x3[15:14] ) + 2'b00, 2'b11: post <= { x3[14:0], 1'd0 }; + 2'b01: post <= 16'h7FFF; + 2'b10: post <= 16'h8000; + endcase + */ + 3'd3: // x4 + post <= x4; + /* + 3'd5: // x5 + case( x5[16:15] ) + 2'b00, 2'b11: post <= x5[15:0]; + 2'b01: post <= 16'h7FFF; + 2'b10: post <= 16'h8000; + endcase + */ + 3'd4: // x6 + casex( x6[16:15] ) + 2'b00, 2'b11: post <= x6[15:0]; + 2'b0x: post <= 16'h7FFF; + 2'b1x: post <= 16'h8000; + endcase +/* + 3'd7: // x7 + case( x7[16:15] ) + 2'b00, 2'b11: post <= x7[15:0]; + 2'b01: post <= 16'h7FFF; + 2'b10: post <= 16'h8000; + endcase +*/ + 3'd5: // x8 + casex( x8[16:15] ) + 2'b00, 2'b11: post <= x8[15:0]; + 2'b0x: post <= 16'h7FFF; + 2'b1x: post <= 16'h8000; + endcase + 3'd6: // x12 + casex( x12[17:15] ) + 3'b000, 3'b111: post <= x12[15:0]; + 3'b0xx: post <= 16'h7FFF; + 3'b1xx: post <= 16'h8000; + endcase + 3'd7: // x16 + casex( x16[17:15] ) + 3'b000, 3'b111: post <= x16[15:0]; + 3'b0xx: post <= 16'h7FFF; + 3'b1xx: post <= 16'h8000; + endcase + endcase + +endmodule + +module jt12_amp_stereo( + input clk, + input rst, + input sample, + + input [ 5:0] psg, + input enable_psg, + + input signed [11:0] fmleft, + input signed [11:0] fmright, + input [2:0] volume, + + output signed [15:0] postleft, + output signed [15:0] postright +); + +wire signed [13:0] preleft; +wire signed [13:0] preright; + +// psg, 6'd0 suena muy fuerte +// According to Nemesis: +// All 4 PSG channels at max combined is equivalent to the maximum output of a single YM2612 channel at max. +// A single channel at max is 11'd255 + +//wire signed [5:0] psgm = psg-6'h20; +//wire signed [8:0] psg_dac = psgm<<<3; +//wire signed [12:0] psg_sum = {13{enable_psg}} & { {3{psg_dac[8]}}, psg_dac }; + +//wire signed [5:0] psgm = psg-6'h20; +wire signed [8:0] psg_dac = psg<<<3; + +//wire signed [12:0] psg_sum = {13{enable_psg}} & { 3'b0, psg_dac }; +wire signed [12:0] psg_sum = {13{enable_psg}} & { 2'b0, psg_dac, 1'b0 }; + + +assign preleft = { fmleft [11], fmleft, 1'd0 } + psg_sum; +assign preright= { fmright[11],fmright, 1'd0 } + psg_sum; + +jt12_amp amp_left( + .clk ( clk ), + .rst ( rst ), + .sample ( sample ), + .pre ( preleft ), + .post ( postleft ), + .volume ( volume ) +); + +jt12_amp amp_right( + .clk ( clk ), + .rst ( rst ), + .sample ( sample ), + .pre ( preright ), + .post ( postright ), + .volume ( volume ) +); + +endmodule diff --git a/common/Sound/JT12/hdl/deprecated/jt12_mod24.v b/common/Sound/JT12/hdl/deprecated/jt12_mod24.v new file mode 100644 index 00000000..0d5568a1 --- /dev/null +++ b/common/Sound/JT12/hdl/deprecated/jt12_mod24.v @@ -0,0 +1,14 @@ +`timescale 1ns / 1ps + +module jt12_mod24( + input [4:0] base, + input [3:0] extra, + output [4:0] mod +); + +wire [5:0] sum = base+extra; +wire [4:0] wrap = base+extra-5'd24; + +assign mod = sum > 6'd23 ? wrap : sum[4:0]; + +endmodule diff --git a/common/Sound/JT12/hdl/deprecated/jt12_mod6.v b/common/Sound/JT12/hdl/deprecated/jt12_mod6.v new file mode 100644 index 00000000..c64f25af --- /dev/null +++ b/common/Sound/JT12/hdl/deprecated/jt12_mod6.v @@ -0,0 +1,52 @@ +`timescale 1ns / 1ps + + +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 19-3-2017 + +*/ + + +module jt12_mod6 +( + input [2:0] in, // only 0 to 5 are valid entries + input [2:0] sum, + output reg [2:0] out // output between 0 to 5 +); + +reg [3:0] aux; + +always @(*) begin + aux <= in+sum; + case( aux ) + 4'd6: out <= 3'd0; + 4'd7: out <= 3'd1; + 4'd8: out <= 3'd2; + 4'd9: out <= 3'd3; + 4'ha: out <= 3'd4; + 4'hb: out <= 3'd5; + 4'hc: out <= 3'd0; + 4'he: out <= 3'd1; + 4'hf: out <= 3'd2; + default: out <= aux; + endcase +end + +endmodule diff --git a/common/Sound/JT12/hdl/deprecated/jt12_opram.v b/common/Sound/JT12/hdl/deprecated/jt12_opram.v new file mode 100644 index 00000000..d695a17a --- /dev/null +++ b/common/Sound/JT12/hdl/deprecated/jt12_opram.v @@ -0,0 +1,45 @@ +`timescale 1ns / 1ps + + +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots. + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 + +*/ + +module jt12_opram +( + input [4:0] wr_addr, + input [4:0] rd_addr, + input clk, + input clk_en, + input [43:0] data, + output reg [43:0] q +); + + reg [43:0] ram[31:0]; + + always @ (posedge clk) if(clk_en) begin + q <= ram[rd_addr]; + ram[wr_addr] <= data; + end + +endmodule diff --git a/common/Sound/JT12/hdl/jt03.qip b/common/Sound/JT12/hdl/jt03.qip new file mode 100644 index 00000000..649ed30c --- /dev/null +++ b/common/Sound/JT12/hdl/jt03.qip @@ -0,0 +1,35 @@ +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 ] + diff --git a/common/Sound/JT12/hdl/jt03.v b/common/Sound/JT12/hdl/jt03.v new file mode 100644 index 00000000..6a7fed86 --- /dev/null +++ b/common/Sound/JT12/hdl/jt03.v @@ -0,0 +1,97 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-12-2018 +*/ + +// 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 + input cen, // optional clock enable, if not needed leave as 1'b1 + input [7:0] din, + 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, + // 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 signed [15:0] snd, + output snd_sample +); + +jt12_top #( + .use_lfo(0),.use_ssg(1), .num_ch(3), .use_pcm(0), .use_adpcm(0) ) +u_jt12( + .rst ( rst ), // rst should be at least 6 clk&cen cycles long + .clk ( clk ), // CPU clock + .cen ( cen ), // optional clock enable, it not needed leave as 1'b1 + .din ( din ), + .addr ( {1'b0, addr} ), + .cs_n ( cs_n ), + .wr_n ( wr_n ), + + .dout ( dout ), + .irq_n ( irq_n ), + // YM2203 I/O pins + .IOA_out ( IOA_out ), + .IOB_out ( IOB_out ), + .IOA_in ( IOA_in ), + .IOB_in ( IOB_in ), + // 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 + // Separated output + .psg_A ( psg_A ), + .psg_B ( psg_B ), + .psg_C ( psg_C ), + .psg_snd ( psg_snd ), + .fm_snd_left ( fm_snd ), + .fm_snd_right (), + .adpcmA_l (), + .adpcmA_r (), + .adpcmB_l (), + .adpcmB_r (), + + .snd_right ( snd ), + .snd_left (), + .snd_sample ( snd_sample ) +); + +endmodule // jt03 diff --git a/common/Sound/JT12/hdl/jt03_acc.v b/common/Sound/JT12/hdl/jt03_acc.v new file mode 100644 index 00000000..d57419f9 --- /dev/null +++ b/common/Sound/JT12/hdl/jt03_acc.v @@ -0,0 +1,73 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 15-11-2018 + +*/ + +`timescale 1ns / 1ps + +// 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 +( + input rst, + input clk, + input clk_en /* synthesis direct_enable */, + input signed [13:0] op_result, + input s1_enters, + input s2_enters, + input s3_enters, + input s4_enters, + input zero, + input [2:0] alg, + // combined output + output signed [15:0] snd +); + +reg sum_en; + +always @(*) begin + case ( alg ) + default: sum_en = s4_enters; + 3'd4: sum_en = s2_enters | s4_enters; + 3'd5,3'd6: sum_en = ~s1_enters; + 3'd7: sum_en = 1'b1; + 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( + .clk ( clk ), + .clk_en ( clk_en ), + .op_result ( op_result ), + .sum_en ( sum_en ), + .zero ( zero ), + .snd ( hires ) +); + +endmodule diff --git a/common/Sound/JT12/hdl/jt03_fm.qip b/common/Sound/JT12/hdl/jt03_fm.qip new file mode 100644 index 00000000..312a4cc6 --- /dev/null +++ b/common/Sound/JT12/hdl/jt03_fm.qip @@ -0,0 +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 ] diff --git a/common/Sound/JT12/hdl/jt10.qip b/common/Sound/JT12/hdl/jt10.qip new file mode 100644 index 00000000..ba4076b3 --- /dev/null +++ b/common/Sound/JT12/hdl/jt10.qip @@ -0,0 +1,63 @@ +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 ] +# SSG +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 ] +# 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 ] diff --git a/common/Sound/JT12/hdl/jt10.v b/common/Sound/JT12/hdl/jt10.v new file mode 100644 index 00000000..38ebb87f --- /dev/null +++ b/common/Sound/JT12/hdl/jt10.v @@ -0,0 +1,97 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +// YM2610 wrapper +// Clock enabled at 7.5 - 8.5MHz + +module jt10( + input rst, // rst should be at least 6 clk&cen cycles long + input clk, // CPU clock + input cen, // optional clock enable, if not needed leave as 1'b1 + input [7:0] din, + input [1:0] addr, + input cs_n, + input wr_n, + + output [7:0] dout, + output irq_n, + // ADPCM pins + output [19:0] adpcma_addr, // real hardware has 10 pins multiplexed through RMPX pin + output [3:0] adpcma_bank, + output adpcma_roe_n, // ADPCM-A ROM output enable + 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, + // 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 signed [15:0] snd_right, + output signed [15:0] snd_left, + output snd_sample +); + +// 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), + .JT49_DIV(3) ) +u_jt12( + .rst ( rst ), // rst should be at least 6 clk&cen cycles long + .clk ( clk ), // CPU clock + .cen ( cen ), // optional clock enable, it not needed leave as 1'b1 + .din ( din ), + .addr ( addr ), + .cs_n ( cs_n ), + .wr_n ( wr_n ), + + .dout ( dout ), + .irq_n ( irq_n ), + // ADPCM pins + .adpcma_addr ( adpcma_addr ), // real hardware has 10 pins multiplexed through RMPX pin + .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 + // Separated output + .psg_A ( psg_A ), + .psg_B ( psg_B ), + .psg_C ( psg_C ), + .psg_snd ( psg_snd ), + .fm_snd_left ( fm_snd ), + .fm_snd_right (), + // Unused YM2203 + .IOA_in (), + .IOB_in (), + // Sound output + .snd_right ( snd_right ), + .snd_left ( snd_left ), + .snd_sample ( snd_sample ), + // unused pins + .en_hifi_pcm ( 1'b0 ) // used only on YM2612 mode +); + +endmodule // jt03 diff --git a/common/Sound/JT12/hdl/jt10_acc.v b/common/Sound/JT12/hdl/jt10_acc.v new file mode 100644 index 00000000..93d5534f --- /dev/null +++ b/common/Sound/JT12/hdl/jt10_acc.v @@ -0,0 +1,173 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 + + Each channel can use the full range of the DAC as they do not + get summed in the real chip. + + Operator data is summed up without adding extra bits. This is + the case of real YM3438, which was used on Megadrive 2 models. + + +*/ + +// YM2610 +// ADPCM inputs +// Full OP resolution +// No PCM +// 4 OP channels + +// ADPCM-A input is added for the time assigned to FM channel 0_10 (i.e. 3) + +module jt10_acc( + input clk, + input clk_en /* synthesis direct_enable */, + input signed [13:0] op_result, + input [ 1:0] rl, + input zero, + input s1_enters, + input s2_enters, + input s3_enters, + input s4_enters, + input [2:0] cur_ch, + input [1:0] cur_op, + input [2:0] alg, + input signed [15:0] adpcmA_l, + input signed [15:0] adpcmA_r, + input signed [15:0] adpcmB_l, + input signed [15:0] adpcmB_r, + // combined output + output signed [15:0] left, + output signed [15:0] right +); + +reg sum_en; + +always @(*) begin + case ( alg ) + default: sum_en = s4_enters; + 3'd4: sum_en = s2_enters | s4_enters; + 3'd5,3'd6: sum_en = ~s1_enters; + 3'd7: sum_en = 1'b1; + endcase +end + +wire left_en = rl[1]; +wire right_en= rl[0]; +wire signed [15:0] opext = { {2{op_result[13]}}, op_result }; +reg signed [15:0] acc_input_l, acc_input_r; +reg acc_en_l, acc_en_r; + +// YM2610 mode: +// uses channels 0 and 4 for ADPCM data, throwing away FM data for those channels +// reference: YM2610 Application Notes. +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); + `ifndef NOMIX + acc_en_l = 1'b1; + acc_en_r = 1'b1; + `else + acc_en_l = 1'b0; + acc_en_r = 1'b0; + `endif + end + {2'd0,3'd4}: begin // ADPCM-B: + acc_input_l = adpcmB_l >>> 1; // Operator width is 14 bit, ADPCM-B is 16 bit + acc_input_r = adpcmB_r >>> 1; // accumulator width per input channel is 14 bit + `ifndef NOMIX + acc_en_l = 1'b1; + acc_en_r = 1'b1; + `else + acc_en_l = 1'b0; + acc_en_r = 1'b0; + `endif + end + default: begin + // Note by Jose Tejada: + // I don't think we should divide down the FM output + // but someone was looking at the balance of the different + // channels and made this arrangement + // I suppose ADPCM-A would saturate if taken up a factor of 8 instead of 4 + // I'll leave it as it is but I think it is worth revisiting this: + acc_input_l = opext >>> 1; + acc_input_r = opext >>> 1; + acc_en_l = sum_en & left_en; + acc_en_r = sum_en & right_en; + end + endcase + +// Continuous output + +jt12_single_acc #(.win(16),.wout(16)) u_left( + .clk ( clk ), + .clk_en ( clk_en ), + .op_result ( acc_input_l ), + .sum_en ( acc_en_l ), + .zero ( zero ), + .snd ( left ) +); + +jt12_single_acc #(.win(16),.wout(16)) u_right( + .clk ( clk ), + .clk_en ( clk_en ), + .op_result ( acc_input_r ), + .sum_en ( acc_en_r ), + .zero ( zero ), + .snd ( right ) +); + +`ifdef SIMULATION +// 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]; + +initial begin + f0=$fopen("fm0.raw","w"); + f1=$fopen("fm1.raw","w"); + f2=$fopen("fm2.raw","w"); + f4=$fopen("fm4.raw","w"); + f5=$fopen("fm5.raw","w"); + f6=$fopen("fm6.raw","w"); +end + +always @(posedge clk) begin + if(cur_op==2'b0) begin + sum_l[cur_ch] <= acc_en_l ? acc_input_l : 16'd0; + sum_r[cur_ch] <= acc_en_r ? acc_input_r : 16'd0; + end else begin + sum_l[cur_ch] <= sum_l[cur_ch] + (acc_en_l ? acc_input_l : 16'd0); + sum_r[cur_ch] <= sum_r[cur_ch] + (acc_en_r ? acc_input_r : 16'd0); + end +end + +always @(posedge zero) begin + $fwrite(f0,"%d,%d\n", sum_l[0], sum_r[0]); + $fwrite(f1,"%d,%d\n", sum_l[1], sum_r[1]); + $fwrite(f2,"%d,%d\n", sum_l[2], sum_r[2]); + $fwrite(f4,"%d,%d\n", sum_l[4], sum_r[4]); + $fwrite(f5,"%d,%d\n", sum_l[5], sum_r[5]); + $fwrite(f6,"%d,%d\n", sum_l[6], sum_r[6]); +end +`endif + +endmodule diff --git a/common/Sound/JT12/hdl/jt12.qip b/common/Sound/JT12/hdl/jt12.qip new file mode 100644 index 00000000..8c5eb8f4 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12.qip @@ -0,0 +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 ] diff --git a/common/Sound/JT12/hdl/jt12.v b/common/Sound/JT12/hdl/jt12.v new file mode 100644 index 00000000..77683d9a --- /dev/null +++ b/common/Sound/JT12/hdl/jt12.v @@ -0,0 +1,80 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-12-2018 + +*/ + +// Wrapper to output only combined channels. Defaults to YM2612 mode. + +module jt12 ( + input rst, // rst should be at least 6 clk&cen cycles long + input clk, // CPU clock + input cen, // optional clock enable, if not needed leave as 1'b1 + input [7:0] din, + input [1:0] addr, + input cs_n, + input wr_n, + + output [7:0] dout, + output irq_n, + // configuration + input en_hifi_pcm, + // combined output + output signed [15:0] snd_right, + output signed [15:0] snd_left, + output snd_sample +); + +// 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 + .cen ( cen ), // optional clock enable, it not needed leave as 1'b1 + .din ( din ), + .addr ( addr ), + .cs_n ( cs_n ), + .wr_n ( wr_n ), + + .dout ( dout ), + .irq_n ( irq_n ), + // configuration + .en_hifi_pcm ( en_hifi_pcm ), + // Unused ADPCM pins + .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_addr ( ), // real hardware has 12 pins multiplexed through PMPX pin + .adpcmb_roe_n ( ), // ADPCM-B ROM output enable + // Separated output + .psg_A (), + .psg_B (), + .psg_C (), + .fm_snd_left (), + .fm_snd_right (), + // Unused YM2203 + .IOA_in (), + .IOB_in (), + // combined output + .psg_snd (), + .snd_right ( snd_right ), // FM+PSG + .snd_left ( snd_left ), // FM+PSG + .snd_sample ( snd_sample ) +); +endmodule // jt03 diff --git a/common/Sound/JT12/hdl/jt12.vhd b/common/Sound/JT12/hdl/jt12.vhd new file mode 100644 index 00000000..014ea1ce --- /dev/null +++ b/common/Sound/JT12/hdl/jt12.vhd @@ -0,0 +1,44 @@ +library IEEE; +use IEEE.std_logic_1164.all; + +package jt12 is + +component jt12 +port +( + rst : in std_logic; + clk : in std_logic; -- CPU clock + cen : in std_logic := '1'; -- optional clock enable, if not needed leave as '1' + din : in std_logic_vector(7 downto 0); + addr : in std_logic_vector(1 downto 0); + cs_n : in std_logic; + wr_n : in std_logic; + + dout : out std_logic_vector(7 downto 0); + irq_n : out std_logic; + en_hifi_pcm: in std_logic; -- set high to use interpolation on PCM samples + + -- combined output + snd_right : out std_logic_vector(15 downto 0); -- signed + snd_left : out std_logic_vector(15 downto 0); -- signed + snd_sample : out std_logic +); +end component; + +component jt12_genmix +port +( + rst : in std_logic; + clk : in std_logic; -- expects 54 MHz clock + fm_left : in std_logic_vector(15 downto 0); -- FM at 55kHz + fm_right: in std_logic_vector(15 downto 0); -- FM at 55kHz + psg_snd : in std_logic_vector(10 downto 0); -- PSG at 220kHz + fm_en : in std_logic; + psg_en : in std_logic; + -- Mixed sound at 54 MHz + snd_left : out std_logic_vector(15 downto 0); + snd_right : out std_logic_vector(15 downto 0) +); +end component; + +end; diff --git a/common/Sound/JT12/hdl/jt12_acc.v b/common/Sound/JT12/hdl/jt12_acc.v new file mode 100644 index 00000000..3d59c100 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_acc.v @@ -0,0 +1,107 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 + + Each channel can use the full range of the DAC as they do not + get summed in the real chip. + + Operator data is summed up without adding extra bits. This is + the case of real YM3438, which was used on Megadrive 2 models. + + +*/ + +/* + YM2612 had a limiter to prevent overflow + YM3438 did not + JT12 always has a limiter enabled + */ + +module jt12_acc( + input rst, + input clk, + input clk_en /* synthesis direct_enable */, + input signed [8:0] op_result, + input [ 1:0] rl, + input zero, + input s1_enters, + input s2_enters, + input s3_enters, + input s4_enters, + input ch6op, + input [2:0] alg, + input pcm_en, // only enabled for channel 6 + input signed [8:0] pcm, + // combined output + output reg signed [11:0] left, + output reg signed [11:0] right +); + +reg sum_en; + +always @(*) begin + case ( alg ) + default: sum_en = s4_enters; + 3'd4: sum_en = s2_enters | s4_enters; + 3'd5,3'd6: sum_en = ~s1_enters; + 3'd7: sum_en = 1'b1; + endcase +end + +reg pcm_sum; + +always @(posedge clk) if(clk_en) + if( zero ) pcm_sum <= 1'b1; + else if( ch6op ) pcm_sum <= 1'b0; + +wire use_pcm = ch6op && pcm_en; +wire sum_or_pcm = sum_en | use_pcm; +wire left_en = rl[1]; +wire right_en= rl[0]; +wire signed [8:0] pcm_data = pcm_sum ? pcm : 9'd0; +wire [8:0] acc_input = use_pcm ? pcm_data : op_result; + +// Continuous output +wire signed [11:0] pre_left, pre_right; +jt12_single_acc #(.win(9),.wout(12)) u_left( + .clk ( clk ), + .clk_en ( clk_en ), + .op_result ( acc_input ), + .sum_en ( sum_or_pcm & left_en ), + .zero ( zero ), + .snd ( pre_left ) +); + +jt12_single_acc #(.win(9),.wout(12)) u_right( + .clk ( clk ), + .clk_en ( clk_en ), + .op_result ( acc_input ), + .sum_en ( sum_or_pcm & right_en ), + .zero ( zero ), + .snd ( pre_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{pre_left [11]}}, pre_left [11:2] }; + right <= pre_right + { {2{pre_right[11]}}, pre_right[11:2] }; +end + +endmodule diff --git a/common/Sound/JT12/hdl/jt12_csr.v b/common/Sound/JT12/hdl/jt12_csr.v new file mode 100644 index 00000000..74e56abe --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_csr.v @@ -0,0 +1,82 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 14-2-2017 + +*/ + +module jt12_csr( // Circular Shift Register + input mux + input rst, + input clk, + input clk_en /* synthesis direct_enable */, + input [ 7:0] din, + input [43:0] shift_in, + output [43:0] shift_out, + + input up_tl, + input up_dt1, + input up_ks_ar, + input up_amen_dr, + input up_sr, + input up_sl_rr, + input up_ssgeg, + input update_op_I, + input update_op_II, + input update_op_IV +); + +localparam regop_width=44; + +reg [regop_width-1:0] regop_in; + +jt12_sh_rst #(.width(regop_width),.stages(12)) u_regch( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( regop_in ), + .drop ( shift_out ) +); + +wire up_tl_op = up_tl & update_op_IV; +wire up_dt1_op = up_dt1 & update_op_I; +wire up_mul_op = up_dt1 & update_op_II; +wire up_ks_op = up_ks_ar & update_op_II; +wire up_ar_op = up_ks_ar & update_op_I; +wire up_amen_op = up_amen_dr& update_op_IV; +wire up_dr_op = up_amen_dr& update_op_I; +wire up_sr_op = up_sr & update_op_I; +wire up_sl_op = up_sl_rr & update_op_I; +wire up_rr_op = up_sl_rr & update_op_I; +wire up_ssg_op = up_ssgeg & update_op_I; + +always @(*) + regop_in = { + up_tl_op ? din[6:0] : shift_in[43:37], // 7 + up_dt1_op ? din[6:4] : shift_in[36:34], // 3 + up_mul_op ? din[3:0] : shift_in[33:30], // 4 + up_ks_op ? din[7:6] : shift_in[29:28], // 2 + up_ar_op ? din[4:0] : shift_in[27:23], // 5 + up_amen_op ? din[7] : shift_in[ 22], // 1 + up_dr_op ? din[4:0] : shift_in[21:17], // 5 + up_sr_op ? din[4:0] : shift_in[16:12], // 5 + up_sl_op ? din[7:4] : shift_in[11: 8], // 4 + up_rr_op ? din[3:0] : shift_in[ 7: 4], // 4 + up_ssg_op ? din[3:0] : shift_in[ 3: 0] // 4 + }; + +endmodule // jt12_reg \ No newline at end of file diff --git a/common/Sound/JT12/hdl/jt12_div.v b/common/Sound/JT12/hdl/jt12_div.v new file mode 100644 index 00000000..e610bd68 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_div.v @@ -0,0 +1,141 @@ +/* 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 . + + 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 +); + +parameter use_ssg=0; + +reg [3:0] opn_pres, opn_cnt=4'd0; +reg [2:0] ssg_pres, ssg_cnt=3'd0; +reg [4:0] adpcm_cnt666 = 5'd0; +reg [2:0] adpcm_cnt111 = 3'd0, adpcm_cnt55=3'd0; +reg cen_int, cen_ssg_int, cen_adpcm_int, cen_adpcm3_int; + +// prescaler values for FM +// reset: 1/3 +// sel1/sel2 +// 0 0 1/3 +// 0 1 1/2 +// 1 0 1/6 +// 1 1 1/2 +// +// According to YM2608 document +// FM SSG div[1:0] +// reset value 1/6 1/4 10 +// 2D 1/6 1/4 10 | 10 +// 2D,2E 1/3 1/2 11 | 01 +// 2F 1/2 1/1 00 & 00 +// + +always @(*) begin + casez( div_setting ) + 2'b0?: begin // FM 1/2 - SSG 1/1 + opn_pres = 4'd2-4'd1; + ssg_pres = 3'd0; + end + 2'b10: begin // FM 1/6 - SSG 1/4 (reset value. Fixed for YM2610) + opn_pres = 4'd6-4'd1; + ssg_pres = 3'd3; + end + 2'b11: begin // FM 1/3 - SSG 1/2 + opn_pres = 4'd3-4'd1; + ssg_pres = 3'd1; + end + endcase // div_setting +end + +`ifdef SIMULATION +initial clk_en_666 = 1'b0; +`endif + +reg cen_55_int; +reg [1:0] div2=2'b0; + +always @(posedge clk) begin + cen_int <= opn_cnt == 4'd0; + cen_ssg_int <= ssg_cnt == 3'd0; + cen_adpcm_int <= adpcm_cnt666 == 5'd0; + 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) + clk_en <= 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_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_55 <= cen & cen_adpcm_int & cen_adpcm3_int & cen_55_int; + `endif +end + +// Div/2 +always @(posedge clk) + if( cen ) begin + div2 <= div2==2'b10 ? 2'b00 : (div2+2'b01); + end + +// OPN +always @(posedge clk) + if( cen ) begin + if( opn_cnt == opn_pres ) begin + opn_cnt <= 4'd0; + end + else opn_cnt <= opn_cnt + 4'd1; + end + +// SSG +always @(posedge clk) + if( cen ) begin + if( ssg_cnt == ssg_pres ) begin + ssg_cnt <= 3'd0; + end + else ssg_cnt <= ssg_cnt + 3'd1; + end + +// ADPCM-A +always @(posedge clk) + if( cen ) begin + adpcm_cnt666 <= adpcm_cnt666==5'd11 ? 5'd0 : adpcm_cnt666 + 5'd1; + if( adpcm_cnt666==5'd0 ) begin + adpcm_cnt111 <= adpcm_cnt111==3'd5 ? 3'd0 : adpcm_cnt111+3'd1; + if( adpcm_cnt111==3'd0) + adpcm_cnt55 <= adpcm_cnt55==3'd1 ? 3'd0: adpcm_cnt55+3'd1; + end + end + +endmodule // jt12_div diff --git a/common/Sound/JT12/hdl/jt12_dout.v b/common/Sound/JT12/hdl/jt12_dout.v new file mode 100644 index 00000000..4666b572 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_dout.v @@ -0,0 +1,47 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +module jt12_dout( + // input rst_n, + input clk, // CPU clock + input flag_A, + input flag_B, + input busy, + input [5:0] adpcma_flags, + input adpcmb_flag, + input [7:0] psg_dout, + input [1:0] addr, + output reg [7:0] dout +); + +parameter use_ssg=0, use_adpcm=0; + +always @(posedge clk) begin + casez( addr ) + 2'b00: dout <= {busy, 5'd0, flag_B, flag_A }; // YM2203 + 2'b01: dout <= (use_ssg ==1) ? psg_dout : {busy, 5'd0, flag_B, flag_A }; + 2'b1?: dout <= (use_adpcm==1) ? + { adpcmb_flag, 1'b0, adpcma_flags } : + { busy, 5'd0, flag_B, flag_A }; + endcase +end + +endmodule // jt12_dout \ No newline at end of file diff --git a/common/Sound/JT12/hdl/jt12_eg.v b/common/Sound/JT12/hdl/jt12_eg.v new file mode 100644 index 00000000..fbf10640 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_eg.v @@ -0,0 +1,203 @@ +/* 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 . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 29-10-2018 + + */ + +module jt12_eg ( + input rst, + input clk, + input clk_en /* synthesis direct_enable */, + input zero, + input eg_stop, + // envelope configuration + input [4:0] keycode_II, + input [4:0] arate_I, // attack rate + input [4:0] rate1_I, // decay rate + input [4:0] rate2_I, // sustain rate + input [3:0] rrate_I, // release rate + input [3:0] sl_I, // sustain level + input [1:0] ks_II, // key scale + // SSG operation + input ssg_en_I, + input [2:0] ssg_eg_I, + // envelope operation + input keyon_I, + // envelope number + input [6:0] lfo_mod, + input amsen_IV, + input [1:0] ams_IV, + input [6:0] tl_IV, + + output reg [9:0] eg_V, + output reg pg_rst_II +); + +parameter num_ch=6; + +wire [14:0] eg_cnt; + +jt12_eg_cnt u_egcnt( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en & ~eg_stop ), + .zero ( zero ), + .eg_cnt ( eg_cnt) +); + +wire keyon_last_I; +wire keyon_now_I = !keyon_last_I && keyon_I; +wire keyoff_now_I = keyon_last_I && !keyon_I; + +wire cnt_in_II, cnt_lsb_II, step_II, pg_rst_I; + +wire ssg_inv_in_I, ssg_inv_out_I; +reg ssg_inv_II, ssg_inv_III, ssg_inv_IV; +wire [2:0] state_in_I, state_next_I; + +reg attack_II, attack_III; +wire [4:0] base_rate_I; +reg [4:0] base_rate_II; +wire [5:0] rate_out_II; +reg [5:1] rate_in_III; +reg step_III, ssg_en_II, ssg_en_III; +wire sum_out_II; +reg sum_in_III; + +wire [9:0] eg_in_I, pure_eg_out_III, eg_next_III, eg_out_IV; +reg [9:0] eg_in_II, eg_in_III, eg_in_IV; + + + +jt12_eg_comb u_comb( + /////////////////////////////////// + // I + .keyon_now ( keyon_now_I ), + .keyoff_now ( keyoff_now_I ), + .state_in ( state_in_I ), + .eg_in ( eg_in_I ), + // envelope configuration + .arate ( arate_I ), // attack rate + .rate1 ( rate1_I ), // decay rate + .rate2 ( rate2_I ), // sustain rate + .rrate ( rrate_I ), + .sl ( sl_I ), // sustain level + // SSG operation + .ssg_en ( ssg_en_I ), + .ssg_eg ( ssg_eg_I ), + // SSG output inversion + .ssg_inv_in ( ssg_inv_in_I ), + .ssg_inv_out ( ssg_inv_out_I ), + + .base_rate ( base_rate_I ), + .state_next ( state_next_I ), + .pg_rst ( pg_rst_I ), + /////////////////////////////////// + // II + .step_attack ( attack_II ), + .step_rate_in ( base_rate_II ), + .keycode ( keycode_II ), + .eg_cnt ( eg_cnt ), + .cnt_in ( cnt_in_II ), + .ks ( ks_II ), + .cnt_lsb ( cnt_lsb_II ), + .step ( step_II ), + .step_rate_out ( rate_out_II ), + .sum_up_out ( sum_out_II ), + /////////////////////////////////// + // III + .pure_attack ( attack_III ), + .pure_step ( step_III ), + .pure_rate ( rate_in_III[5:1] ), + .pure_ssg_en ( ssg_en_III ), + .pure_eg_in ( eg_in_III ), + .pure_eg_out ( pure_eg_out_III ), + .sum_up_in ( sum_in_III ), + /////////////////////////////////// + // IV + .lfo_mod ( lfo_mod ), + .amsen ( amsen_IV ), + .ams ( ams_IV ), + .tl ( tl_IV ), + .final_ssg_inv ( ssg_inv_IV ), + .final_eg_in ( eg_in_IV ), + .final_eg_out ( eg_out_IV ) +); + +always @(posedge clk) if(clk_en) begin + eg_in_II <= eg_in_I; + attack_II <= state_next_I[0]; + base_rate_II<= base_rate_I; + ssg_en_II <= ssg_en_I; + ssg_inv_II <= ssg_inv_out_I; + pg_rst_II <= pg_rst_I; + + eg_in_III <= eg_in_II; + attack_III <= attack_II; + rate_in_III <= rate_out_II[5:1]; + ssg_en_III <= ssg_en_II; + ssg_inv_III <= ssg_inv_II; + step_III <= step_II; + sum_in_III <= sum_out_II; + + ssg_inv_IV <= ssg_inv_III; + eg_in_IV <= pure_eg_out_III; + eg_V <= eg_out_IV; +end + +jt12_sh #( .width(1), .stages(4*num_ch) ) u_cntsh( + .clk ( clk ), + .clk_en ( clk_en ), + .din ( cnt_lsb_II), + .drop ( cnt_in_II ) +); + +jt12_sh_rst #( .width(10), .stages(4*num_ch-3), .rstval(1'b1) ) u_egsh( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( eg_in_IV ), + .drop ( eg_in_I ) +); + +jt12_sh_rst #( .width(3), .stages(4*num_ch), .rstval(1'b1) ) u_egstate( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( state_next_I ), + .drop ( state_in_I ) +); + +jt12_sh_rst #( .width(1), .stages(4*num_ch-3), .rstval(1'b0) ) u_ssg_inv( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( ssg_inv_IV ), + .drop ( ssg_inv_in_I ) +); + +jt12_sh_rst #( .width(1), .stages(4*num_ch), .rstval(1'b0) ) u_konsh( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( keyon_I ), + .drop ( keyon_last_I ) +); + + +endmodule // jt12_eg \ No newline at end of file diff --git a/common/Sound/JT12/hdl/jt12_eg_cnt.v b/common/Sound/JT12/hdl/jt12_eg_cnt.v new file mode 100644 index 00000000..df006d6e --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_eg_cnt.v @@ -0,0 +1,50 @@ +/* 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 . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 29-10-2018 + + */ + +module jt12_eg_cnt( + input rst, + input clk, + input clk_en /* synthesis direct_enable */, + input zero, + output reg [14:0] eg_cnt +); + +reg [1:0] eg_cnt_base; + +always @(posedge clk, posedge rst) begin : envelope_counter + if( rst ) begin + eg_cnt_base <= 2'd0; + eg_cnt <=15'd0; + end + else begin + if( zero && clk_en ) begin + // envelope counter increases every 3 output samples, + // there is one sample every 24 clock ticks + if( eg_cnt_base == 2'd2 ) begin + eg_cnt <= eg_cnt + 1'b1; + eg_cnt_base <= 2'd0; + end + else eg_cnt_base <= eg_cnt_base + 1'b1; + end + end +end + +endmodule // jt12_eg_cnt \ No newline at end of file diff --git a/common/Sound/JT12/hdl/jt12_eg_comb.v b/common/Sound/JT12/hdl/jt12_eg_comb.v new file mode 100644 index 00000000..ddf0c533 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_eg_comb.v @@ -0,0 +1,139 @@ +/* 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 . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 30-10-2018 + + */ + +module jt12_eg_comb( + input keyon_now, + input keyoff_now, + input [2:0] state_in, + input [9:0] eg_in, + // envelope configuration + input [4:0] arate, // attack rate + input [4:0] rate1, // decay rate + input [4:0] rate2, // sustain rate + input [3:0] rrate, + input [3:0] sl, // sustain level + // SSG operation + input ssg_en, + input [2:0] ssg_eg, + // SSG output inversion + input ssg_inv_in, + output ssg_inv_out, + + output [4:0] base_rate, + output [2:0] state_next, + output pg_rst, + /////////////////////////////////// + // II + input step_attack, + input [ 4:0] step_rate_in, + input [ 4:0] keycode, + input [14:0] eg_cnt, + input cnt_in, + input [ 1:0] ks, + output cnt_lsb, + output step, + output [5:0] step_rate_out, + output sum_up_out, + /////////////////////////////////// + // III + input pure_attack, + input pure_step, + input [ 5:1] pure_rate, + input pure_ssg_en, + input [ 9:0] pure_eg_in, + output [9:0] pure_eg_out, + input sum_up_in, + /////////////////////////////////// + // IV + input [ 6:0] lfo_mod, + input amsen, + input [ 1:0] ams, + input [ 6:0] tl, + input [ 9:0] final_eg_in, + input final_ssg_inv, + output [9:0] final_eg_out +); + +// I +jt12_eg_ctrl u_ctrl( + .keyon_now ( keyon_now ), + .keyoff_now ( keyoff_now ), + .state_in ( state_in ), + .eg ( eg_in ), + // envelope configuration + .arate ( arate ), // attack rate + .rate1 ( rate1 ), // decay rate + .rate2 ( rate2 ), // sustain rate + .rrate ( rrate ), + .sl ( sl ), // sustain level + // SSG operation + .ssg_en ( ssg_en ), + .ssg_eg ( ssg_eg ), + // SSG output inversion + .ssg_inv_in ( ssg_inv_in ), + .ssg_inv_out ( ssg_inv_out ), + + .base_rate ( base_rate ), + .state_next ( state_next ), + .pg_rst ( pg_rst ) +); + +// II + +jt12_eg_step u_step( + .attack ( step_attack ), + .base_rate ( step_rate_in ), + .keycode ( keycode ), + .eg_cnt ( eg_cnt ), + .cnt_in ( cnt_in ), + .ks ( ks ), + .cnt_lsb ( cnt_lsb ), + .step ( step ), + .rate ( step_rate_out ), + .sum_up ( sum_up_out ) +); + +// III + +wire [9:0] egin, egout; +jt12_eg_pure u_pure( + .attack ( pure_attack ), + .step ( pure_step ), + .rate ( pure_rate ), + .ssg_en ( pure_ssg_en ), + .eg_in ( pure_eg_in ), + .eg_pure( pure_eg_out ), + .sum_up ( sum_up_in ) +); + +// IV + +jt12_eg_final u_final( + .lfo_mod ( lfo_mod ), + .amsen ( amsen ), + .ams ( ams ), + .tl ( tl ), + .ssg_inv ( final_ssg_inv ), + .eg_pure_in ( final_eg_in ), + .eg_limited ( final_eg_out ) +); + +endmodule // jt12_eg_comb \ No newline at end of file diff --git a/common/Sound/JT12/hdl/jt12_eg_ctrl.v b/common/Sound/JT12/hdl/jt12_eg_ctrl.v new file mode 100644 index 00000000..ddd8698e --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_eg_ctrl.v @@ -0,0 +1,122 @@ +/* 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 . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 29-10-2018 + + */ + +module jt12_eg_ctrl( + input keyon_now, + input keyoff_now, + input [2:0] state_in, + input [9:0] eg, + // envelope configuration + input [4:0] arate, // attack rate + input [4:0] rate1, // decay rate + input [4:0] rate2, // sustain rate + input [3:0] rrate, + input [3:0] sl, // sustain level + // SSG operation + input ssg_en, + input [2:0] ssg_eg, + // SSG output inversion + input ssg_inv_in, + output reg ssg_inv_out, + + output reg [4:0] base_rate, + output reg [2:0] state_next, + output reg pg_rst +); + +localparam ATTACK = 3'b001, + DECAY = 3'b010, + HOLD = 3'b100, + RELEASE= 3'b000; // default state is release + +// wire is_decaying = state_in[1] | state_in[2]; + +reg [4:0] sustain; + +always @(*) + if( sl == 4'd15 ) + sustain = 5'h1f; // 93dB + else + sustain = {1'b0, sl}; + +wire ssg_en_out; +reg ssg_en_in, ssg_pg_rst; + +// aliases +wire ssg_att = ssg_eg[2]; +wire ssg_alt = ssg_eg[1]; +wire ssg_hold = ssg_eg[0] & ssg_en; + +reg ssg_over; + + +always @(*) begin + ssg_over = ssg_en && eg[9]; // eg >=10'h200 + ssg_pg_rst = ssg_over && !( ssg_alt || ssg_hold ); + pg_rst = keyon_now | ssg_pg_rst; +end + +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}: + if( eg==10'd0 ) begin + base_rate = rate1; + state_next = DECAY; + ssg_inv_out = ssg_inv_in; + end + else begin + base_rate = arate; + state_next = ATTACK; + ssg_inv_out = ssg_inv_in; + end + {2'b00, DECAY}: begin + if( ssg_over ) begin + base_rate = ssg_hold ? 5'd0 : arate; + state_next = ssg_hold ? HOLD : ATTACK; + ssg_inv_out = ssg_en & (ssg_alt ^ ssg_inv_in); + end + else begin + base_rate = eg[9:5] >= sustain ? rate2 : rate1; // equal comparison according to Nuke + state_next = DECAY; + ssg_inv_out = ssg_inv_in; + end + end + {2'b00, HOLD}: begin + base_rate = 5'd0; + state_next = HOLD; + ssg_inv_out = ssg_inv_in; + end + default: begin // RELEASE, note that keyoff_now==1 will enter this state too + base_rate = { rrate, 1'b1 }; + state_next = RELEASE; // release + ssg_inv_out = 1'b0; // this can produce a glitch in the output + // But to release from SSG cannot be done nicely while + // inverting the ouput + end + endcase + + +endmodule // jt12_eg_ctrl \ No newline at end of file diff --git a/common/Sound/JT12/hdl/jt12_eg_final.v b/common/Sound/JT12/hdl/jt12_eg_final.v new file mode 100644 index 00000000..5919fc0f --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_eg_final.v @@ -0,0 +1,57 @@ +/* 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 . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 29-10-2018 + + */ + +module jt12_eg_final( + input [ 6:0] lfo_mod, + input amsen, + input [ 1:0] ams, + input [ 6:0] tl, + input [ 9:0] eg_pure_in, + input ssg_inv, + output reg [9:0] eg_limited +); + +reg [ 8:0] am_final; +reg [11:0] sum_eg_tl; +reg [11:0] sum_eg_tl_am; +reg [ 5:0] am_inverted; +reg [ 9:0] eg_pream; + +always @(*) begin + am_inverted = lfo_mod[6] ? ~lfo_mod[5:0] : lfo_mod[5:0]; +end + +always @(*) begin + casez( {amsen, ams } ) + default: am_final = 9'd0; + 3'b1_01: am_final = { 5'd0, am_inverted[5:2] }; + 3'b1_10: am_final = { 3'd0, am_inverted }; + 3'b1_11: am_final = { 2'd0, am_inverted, 1'b0 }; + endcase + eg_pream = ssg_inv ? (10'h200-eg_pure_in) : eg_pure_in; + sum_eg_tl = { 1'b0, tl, 3'd0 } + {1'b0, eg_pream}; // leading zeros needed to compute correctly + sum_eg_tl_am = sum_eg_tl + { 3'd0, am_final }; +end + +always @(*) + eg_limited = sum_eg_tl_am[11:10]==2'd0 ? sum_eg_tl_am[9:0] : 10'h3ff; + +endmodule // jt12_eg_final \ No newline at end of file diff --git a/common/Sound/JT12/hdl/jt12_eg_pure.v b/common/Sound/JT12/hdl/jt12_eg_pure.v new file mode 100644 index 00000000..02a36780 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_eg_pure.v @@ -0,0 +1,81 @@ +/* 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 . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 29-10-2018 + + */ + +module jt12_eg_pure( + input attack, + input step, + input [ 5:1] rate, + input [ 9:0] eg_in, + input ssg_en, + input sum_up, + output reg [9:0] eg_pure +); + +reg [ 3:0] dr_sum; +reg [ 9:0] dr_adj; +reg [10:0] dr_result; + +always @(*) begin : dr_calculation + case( rate[5:2] ) + 4'b1100: dr_sum = { 2'b0, step, ~step }; // 12 + 4'b1101: dr_sum = { 1'b0, step, ~step, 1'b0 }; // 13 + 4'b1110: dr_sum = { step, ~step, 2'b0 }; // 14 + 4'b1111: dr_sum = 4'd8;// 15 + default: dr_sum = { 2'b0, step, 1'b0 }; + endcase + // Decay rate attenuation is multiplied by 4 for SSG operation + dr_adj = ssg_en ? {4'd0, dr_sum, 2'd0} : {6'd0, dr_sum}; + dr_result = dr_adj + eg_in; +end + +reg [ 7:0] ar_sum0; +reg [ 8:0] ar_sum1; +reg [10:0] ar_result; +reg [ 9:0] ar_sum; + +always @(*) begin : ar_calculation + casez( rate[5:2] ) + default: ar_sum0 = {2'd0, eg_in[9:4]}; + 4'b1101: ar_sum0 = {1'd0, eg_in[9:3]}; + 4'b111?: ar_sum0 = eg_in[9:2]; + endcase + ar_sum1 = ar_sum0+9'd1; + if( rate[5:4] == 2'b11 ) + ar_sum = step ? { ar_sum1, 1'b0 } : { 1'b0, ar_sum1 }; + else + ar_sum = step ? { 1'b0, ar_sum1 } : 10'd0; + ar_result = eg_in-ar_sum; +end +/////////////////////////////////////////////////////////// +// rate not used below this point +reg [9:0] eg_pre_fastar; // pre fast attack rate +always @(*) begin + if(sum_up) begin + if( attack ) + eg_pre_fastar = ar_result[10] ? 10'd0: ar_result[9:0]; + else + eg_pre_fastar = dr_result[10] ? 10'h3FF : dr_result[9:0]; + end + else eg_pre_fastar = eg_in; + eg_pure = (attack&rate[5:1]==5'h1F) ? 10'd0 : eg_pre_fastar; +end + +endmodule // jt12_eg_pure \ No newline at end of file diff --git a/common/Sound/JT12/hdl/jt12_eg_step.v b/common/Sound/JT12/hdl/jt12_eg_step.v new file mode 100644 index 00000000..4225e4ef --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_eg_step.v @@ -0,0 +1,111 @@ +/* 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 . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 29-10-2018 + + */ + +module jt12_eg_step( + input attack, + input [ 4:0] base_rate, + input [ 4:0] keycode, + input [14:0] eg_cnt, + input cnt_in, + input [ 1:0] ks, + output cnt_lsb, + output reg step, + output reg [5:0] rate, + output reg sum_up +); + +reg [6:0] pre_rate; + +always @(*) begin : pre_rate_calc + if( base_rate == 5'd0 ) + pre_rate = 7'd0; + else + case( ks ) + 2'd3: pre_rate = { base_rate, 1'b0 } + { 1'b0, keycode }; + 2'd2: pre_rate = { base_rate, 1'b0 } + { 2'b0, keycode[4:1] }; + 2'd1: pre_rate = { base_rate, 1'b0 } + { 3'b0, keycode[4:2] }; + 2'd0: pre_rate = { base_rate, 1'b0 } + { 4'b0, keycode[4:3] }; + endcase +end + +always @(*) + rate = pre_rate[6] ? 6'd63 : pre_rate[5:0]; + +reg [2:0] cnt; + +reg [4:0] mux_sel; +always @(*) begin + mux_sel = attack ? (rate[5:2]+4'd1): {1'b0,rate[5:2]}; +end // always @(*) + +always @(*) + case( mux_sel ) + 5'h0: cnt = eg_cnt[14:12]; + 5'h1: cnt = eg_cnt[13:11]; + 5'h2: cnt = eg_cnt[12:10]; + 5'h3: cnt = eg_cnt[11: 9]; + 5'h4: cnt = eg_cnt[10: 8]; + 5'h5: cnt = eg_cnt[ 9: 7]; + 5'h6: cnt = eg_cnt[ 8: 6]; + 5'h7: cnt = eg_cnt[ 7: 5]; + 5'h8: cnt = eg_cnt[ 6: 4]; + 5'h9: cnt = eg_cnt[ 5: 3]; + 5'ha: cnt = eg_cnt[ 4: 2]; + 5'hb: cnt = eg_cnt[ 3: 1]; + default: cnt = eg_cnt[ 2: 0]; + endcase + +//////////////////////////////// +reg [7:0] step_idx; + +always @(*) begin : rate_step + if( rate[5:4]==2'b11 ) begin // 0 means 1x, 1 means 2x + if( rate[5:2]==4'hf && attack) + step_idx = 8'b11111111; // Maximum attack speed, rates 60&61 + else + case( rate[1:0] ) + 2'd0: step_idx = 8'b00000000; + 2'd1: step_idx = 8'b10001000; // 2 + 2'd2: step_idx = 8'b10101010; // 4 + 2'd3: step_idx = 8'b11101110; // 6 + endcase + end + else begin + if( rate[5:2]==4'd0 && !attack) + step_idx = 8'b11111110; // limit slowest decay rate + else + case( rate[1:0] ) + 2'd0: step_idx = 8'b10101010; // 4 + 2'd1: step_idx = 8'b11101010; // 5 + 2'd2: step_idx = 8'b11101110; // 6 + 2'd3: step_idx = 8'b11111110; // 7 + endcase + end + // a rate of zero keeps the level still + step = rate[5:1]==5'd0 ? 1'b0 : step_idx[ cnt ]; +end + +assign cnt_lsb = cnt[0]; +always @(*) begin + sum_up = cnt[0] != cnt_in; +end + +endmodule // eg_step \ No newline at end of file diff --git a/common/Sound/JT12/hdl/jt12_exprom.v b/common/Sound/JT12/hdl/jt12_exprom.v new file mode 100644 index 00000000..b50e4191 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_exprom.v @@ -0,0 +1,302 @@ +`timescale 1ns / 1ps + + +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots. + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 + +*/ + +// altera message_off 10030 + +module jt12_exprom +( + input [7:0] addr, + input clk, + input clk_en /* synthesis direct_enable */, + output reg [9:0] exp +); + + reg [9:0] explut_jt51[255:0]; + initial + begin + explut_jt51[8'd000] = 10'd1018; + explut_jt51[8'd001] = 10'd1013; + explut_jt51[8'd002] = 10'd1007; + explut_jt51[8'd003] = 10'd1002; + explut_jt51[8'd004] = 10'd0996; + explut_jt51[8'd005] = 10'd0991; + explut_jt51[8'd006] = 10'd0986; + explut_jt51[8'd007] = 10'd0980; + explut_jt51[8'd008] = 10'd0975; + explut_jt51[8'd009] = 10'd0969; + explut_jt51[8'd010] = 10'd0964; + explut_jt51[8'd011] = 10'd0959; + explut_jt51[8'd012] = 10'd0953; + explut_jt51[8'd013] = 10'd0948; + explut_jt51[8'd014] = 10'd0942; + explut_jt51[8'd015] = 10'd0937; + explut_jt51[8'd016] = 10'd0932; + explut_jt51[8'd017] = 10'd0927; + explut_jt51[8'd018] = 10'd0921; + explut_jt51[8'd019] = 10'd0916; + explut_jt51[8'd020] = 10'd0911; + explut_jt51[8'd021] = 10'd0906; + explut_jt51[8'd022] = 10'd0900; + explut_jt51[8'd023] = 10'd0895; + explut_jt51[8'd024] = 10'd0890; + explut_jt51[8'd025] = 10'd0885; + explut_jt51[8'd026] = 10'd0880; + explut_jt51[8'd027] = 10'd0874; + explut_jt51[8'd028] = 10'd0869; + explut_jt51[8'd029] = 10'd0864; + explut_jt51[8'd030] = 10'd0859; + explut_jt51[8'd031] = 10'd0854; + explut_jt51[8'd032] = 10'd0849; + explut_jt51[8'd033] = 10'd0844; + explut_jt51[8'd034] = 10'd0839; + explut_jt51[8'd035] = 10'd0834; + explut_jt51[8'd036] = 10'd0829; + explut_jt51[8'd037] = 10'd0824; + explut_jt51[8'd038] = 10'd0819; + explut_jt51[8'd039] = 10'd0814; + explut_jt51[8'd040] = 10'd0809; + explut_jt51[8'd041] = 10'd0804; + explut_jt51[8'd042] = 10'd0799; + explut_jt51[8'd043] = 10'd0794; + explut_jt51[8'd044] = 10'd0789; + explut_jt51[8'd045] = 10'd0784; + explut_jt51[8'd046] = 10'd0779; + explut_jt51[8'd047] = 10'd0774; + explut_jt51[8'd048] = 10'd0770; + explut_jt51[8'd049] = 10'd0765; + explut_jt51[8'd050] = 10'd0760; + explut_jt51[8'd051] = 10'd0755; + explut_jt51[8'd052] = 10'd0750; + explut_jt51[8'd053] = 10'd0745; + explut_jt51[8'd054] = 10'd0741; + explut_jt51[8'd055] = 10'd0736; + explut_jt51[8'd056] = 10'd0731; + explut_jt51[8'd057] = 10'd0726; + explut_jt51[8'd058] = 10'd0722; + explut_jt51[8'd059] = 10'd0717; + explut_jt51[8'd060] = 10'd0712; + explut_jt51[8'd061] = 10'd0708; + explut_jt51[8'd062] = 10'd0703; + explut_jt51[8'd063] = 10'd0698; + explut_jt51[8'd064] = 10'd0693; + explut_jt51[8'd065] = 10'd0689; + explut_jt51[8'd066] = 10'd0684; + explut_jt51[8'd067] = 10'd0680; + explut_jt51[8'd068] = 10'd0675; + explut_jt51[8'd069] = 10'd0670; + explut_jt51[8'd070] = 10'd0666; + explut_jt51[8'd071] = 10'd0661; + explut_jt51[8'd072] = 10'd0657; + explut_jt51[8'd073] = 10'd0652; + explut_jt51[8'd074] = 10'd0648; + explut_jt51[8'd075] = 10'd0643; + explut_jt51[8'd076] = 10'd0639; + explut_jt51[8'd077] = 10'd0634; + explut_jt51[8'd078] = 10'd0630; + explut_jt51[8'd079] = 10'd0625; + explut_jt51[8'd080] = 10'd0621; + explut_jt51[8'd081] = 10'd0616; + explut_jt51[8'd082] = 10'd0612; + explut_jt51[8'd083] = 10'd0607; + explut_jt51[8'd084] = 10'd0603; + explut_jt51[8'd085] = 10'd0599; + explut_jt51[8'd086] = 10'd0594; + explut_jt51[8'd087] = 10'd0590; + explut_jt51[8'd088] = 10'd0585; + explut_jt51[8'd089] = 10'd0581; + explut_jt51[8'd090] = 10'd0577; + explut_jt51[8'd091] = 10'd0572; + explut_jt51[8'd092] = 10'd0568; + explut_jt51[8'd093] = 10'd0564; + explut_jt51[8'd094] = 10'd0560; + explut_jt51[8'd095] = 10'd0555; + explut_jt51[8'd096] = 10'd0551; + explut_jt51[8'd097] = 10'd0547; + explut_jt51[8'd098] = 10'd0542; + explut_jt51[8'd099] = 10'd0538; + explut_jt51[8'd100] = 10'd0534; + explut_jt51[8'd101] = 10'd0530; + explut_jt51[8'd102] = 10'd0526; + explut_jt51[8'd103] = 10'd0521; + explut_jt51[8'd104] = 10'd0517; + explut_jt51[8'd105] = 10'd0513; + explut_jt51[8'd106] = 10'd0509; + explut_jt51[8'd107] = 10'd0505; + explut_jt51[8'd108] = 10'd0501; + explut_jt51[8'd109] = 10'd0496; + explut_jt51[8'd110] = 10'd0492; + explut_jt51[8'd111] = 10'd0488; + explut_jt51[8'd112] = 10'd0484; + explut_jt51[8'd113] = 10'd0480; + explut_jt51[8'd114] = 10'd0476; + explut_jt51[8'd115] = 10'd0472; + explut_jt51[8'd116] = 10'd0468; + explut_jt51[8'd117] = 10'd0464; + explut_jt51[8'd118] = 10'd0460; + explut_jt51[8'd119] = 10'd0456; + explut_jt51[8'd120] = 10'd0452; + explut_jt51[8'd121] = 10'd0448; + explut_jt51[8'd122] = 10'd0444; + explut_jt51[8'd123] = 10'd0440; + explut_jt51[8'd124] = 10'd0436; + explut_jt51[8'd125] = 10'd0432; + explut_jt51[8'd126] = 10'd0428; + explut_jt51[8'd127] = 10'd0424; + explut_jt51[8'd128] = 10'd0420; + explut_jt51[8'd129] = 10'd0416; + explut_jt51[8'd130] = 10'd0412; + explut_jt51[8'd131] = 10'd0409; + explut_jt51[8'd132] = 10'd0405; + explut_jt51[8'd133] = 10'd0401; + explut_jt51[8'd134] = 10'd0397; + explut_jt51[8'd135] = 10'd0393; + explut_jt51[8'd136] = 10'd0389; + explut_jt51[8'd137] = 10'd0385; + explut_jt51[8'd138] = 10'd0382; + explut_jt51[8'd139] = 10'd0378; + explut_jt51[8'd140] = 10'd0374; + explut_jt51[8'd141] = 10'd0370; + explut_jt51[8'd142] = 10'd0367; + explut_jt51[8'd143] = 10'd0363; + explut_jt51[8'd144] = 10'd0359; + explut_jt51[8'd145] = 10'd0355; + explut_jt51[8'd146] = 10'd0352; + explut_jt51[8'd147] = 10'd0348; + explut_jt51[8'd148] = 10'd0344; + explut_jt51[8'd149] = 10'd0340; + explut_jt51[8'd150] = 10'd0337; + explut_jt51[8'd151] = 10'd0333; + explut_jt51[8'd152] = 10'd0329; + explut_jt51[8'd153] = 10'd0326; + explut_jt51[8'd154] = 10'd0322; + explut_jt51[8'd155] = 10'd0318; + explut_jt51[8'd156] = 10'd0315; + explut_jt51[8'd157] = 10'd0311; + explut_jt51[8'd158] = 10'd0308; + explut_jt51[8'd159] = 10'd0304; + explut_jt51[8'd160] = 10'd0300; + explut_jt51[8'd161] = 10'd0297; + explut_jt51[8'd162] = 10'd0293; + explut_jt51[8'd163] = 10'd0290; + explut_jt51[8'd164] = 10'd0286; + explut_jt51[8'd165] = 10'd0283; + explut_jt51[8'd166] = 10'd0279; + explut_jt51[8'd167] = 10'd0276; + explut_jt51[8'd168] = 10'd0272; + explut_jt51[8'd169] = 10'd0268; + explut_jt51[8'd170] = 10'd0265; + explut_jt51[8'd171] = 10'd0262; + explut_jt51[8'd172] = 10'd0258; + explut_jt51[8'd173] = 10'd0255; + explut_jt51[8'd174] = 10'd0251; + explut_jt51[8'd175] = 10'd0248; + explut_jt51[8'd176] = 10'd0244; + explut_jt51[8'd177] = 10'd0241; + explut_jt51[8'd178] = 10'd0237; + explut_jt51[8'd179] = 10'd0234; + explut_jt51[8'd180] = 10'd0231; + explut_jt51[8'd181] = 10'd0227; + explut_jt51[8'd182] = 10'd0224; + explut_jt51[8'd183] = 10'd0220; + explut_jt51[8'd184] = 10'd0217; + explut_jt51[8'd185] = 10'd0214; + explut_jt51[8'd186] = 10'd0210; + explut_jt51[8'd187] = 10'd0207; + explut_jt51[8'd188] = 10'd0204; + explut_jt51[8'd189] = 10'd0200; + explut_jt51[8'd190] = 10'd0197; + explut_jt51[8'd191] = 10'd0194; + explut_jt51[8'd192] = 10'd0190; + explut_jt51[8'd193] = 10'd0187; + explut_jt51[8'd194] = 10'd0184; + explut_jt51[8'd195] = 10'd0181; + explut_jt51[8'd196] = 10'd0177; + explut_jt51[8'd197] = 10'd0174; + explut_jt51[8'd198] = 10'd0171; + explut_jt51[8'd199] = 10'd0168; + explut_jt51[8'd200] = 10'd0164; + explut_jt51[8'd201] = 10'd0161; + explut_jt51[8'd202] = 10'd0158; + explut_jt51[8'd203] = 10'd0155; + explut_jt51[8'd204] = 10'd0152; + explut_jt51[8'd205] = 10'd0148; + explut_jt51[8'd206] = 10'd0145; + explut_jt51[8'd207] = 10'd0142; + explut_jt51[8'd208] = 10'd0139; + explut_jt51[8'd209] = 10'd0136; + explut_jt51[8'd210] = 10'd0133; + explut_jt51[8'd211] = 10'd0130; + explut_jt51[8'd212] = 10'd0126; + explut_jt51[8'd213] = 10'd0123; + explut_jt51[8'd214] = 10'd0120; + explut_jt51[8'd215] = 10'd0117; + explut_jt51[8'd216] = 10'd0114; + explut_jt51[8'd217] = 10'd0111; + explut_jt51[8'd218] = 10'd0108; + explut_jt51[8'd219] = 10'd0105; + explut_jt51[8'd220] = 10'd0102; + explut_jt51[8'd221] = 10'd0099; + explut_jt51[8'd222] = 10'd0096; + explut_jt51[8'd223] = 10'd0093; + explut_jt51[8'd224] = 10'd0090; + explut_jt51[8'd225] = 10'd0087; + explut_jt51[8'd226] = 10'd0084; + explut_jt51[8'd227] = 10'd0081; + explut_jt51[8'd228] = 10'd0078; + explut_jt51[8'd229] = 10'd0075; + explut_jt51[8'd230] = 10'd0072; + explut_jt51[8'd231] = 10'd0069; + explut_jt51[8'd232] = 10'd0066; + explut_jt51[8'd233] = 10'd0063; + explut_jt51[8'd234] = 10'd0060; + explut_jt51[8'd235] = 10'd0057; + explut_jt51[8'd236] = 10'd0054; + explut_jt51[8'd237] = 10'd0051; + explut_jt51[8'd238] = 10'd0048; + explut_jt51[8'd239] = 10'd0045; + explut_jt51[8'd240] = 10'd0042; + explut_jt51[8'd241] = 10'd0040; + explut_jt51[8'd242] = 10'd0037; + explut_jt51[8'd243] = 10'd0034; + explut_jt51[8'd244] = 10'd0031; + explut_jt51[8'd245] = 10'd0028; + explut_jt51[8'd246] = 10'd0025; + explut_jt51[8'd247] = 10'd0022; + explut_jt51[8'd248] = 10'd0020; + explut_jt51[8'd249] = 10'd0017; + explut_jt51[8'd250] = 10'd0014; + explut_jt51[8'd251] = 10'd0011; + explut_jt51[8'd252] = 10'd0008; + explut_jt51[8'd253] = 10'd0006; + explut_jt51[8'd254] = 10'd0003; + explut_jt51[8'd255] = 10'd0000; + end + + always @ (posedge clk) if(clk_en) + exp <= explut_jt51[addr]; + +endmodule diff --git a/common/Sound/JT12/hdl/jt12_kon.v b/common/Sound/JT12/hdl/jt12_kon.v new file mode 100644 index 00000000..9444b999 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_kon.v @@ -0,0 +1,151 @@ +`timescale 1ns / 1ps + + +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 + +*/ + +module jt12_kon( + input rst, + input clk, + input clk_en /* synthesis direct_enable */, + input [3:0] keyon_op, + input [2:0] keyon_ch, + input [1:0] next_op, + input [2:0] next_ch, + input up_keyon, + input csm, + // input flag_A, + input overflow_A, + + output reg keyon_I +); + +parameter num_ch=6; + +wire csr_out; + +generate +if(num_ch==6) begin + // capture overflow signal so it lasts long enough + reg overflow2; + reg [4:0] overflow_cycle; + + always @(posedge clk) if( clk_en ) begin + if(overflow_A) begin + overflow2 <= 1'b1; + overflow_cycle <= { next_op, next_ch }; + end else begin + if(overflow_cycle == {next_op, next_ch}) overflow2<=1'b0; + end + end + + always @(posedge clk) if( clk_en ) + keyon_I <= (csm&&next_ch==3'd2&&overflow2) || csr_out; + + 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 ? 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 ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( din ), + .drop ( middle1 ) + ); + + jt12_sh_rst #(.width(1),.stages(6),.rstval(1'b0)) u_konch1( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( mid_din2 ), + .drop ( middle2 ) + ); + + jt12_sh_rst #(.width(1),.stages(6),.rstval(1'b0)) u_konch2( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( mid_din3 ), + .drop ( middle3 ) + ); + + jt12_sh_rst #(.width(1),.stages(6),.rstval(1'b0)) u_konch3( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( mid_din4 ), + .drop ( csr_out ) + ); +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 + 2'd1: next_op_hot = 4'b0100; // S3 + 2'd2: next_op_hot = 4'b0010; // S2 + 2'd3: next_op_hot = 4'b1000; // S4 + endcase + 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 ) + keyon_I <= csr_out; // No CSM for YM2203 + + jt12_sh_rst #(.width(1),.stages(12),.rstval(1'b0)) u_konch1( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( din ), + .drop ( csr_out ) + ); +end +endgenerate + + +endmodule diff --git a/common/Sound/JT12/hdl/jt12_lfo.v b/common/Sound/JT12/hdl/jt12_lfo.v new file mode 100644 index 00000000..3f3fa908 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_lfo.v @@ -0,0 +1,103 @@ +/* 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 . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 25-2-2017 + */ + +`timescale 1ns / 1ps + +/* + + Does the LFO frequency depend on the pre-scaler for YM2608 ? + + From spritesmind.net: + "That would be 7-bit LFO step counter (which is incremented on each LFO clock and reset when LFO enable bit is cleared). + LFO AM value indeed corresponds to LFO step counter bits 0:5 shifted left by one + and XORed with inversion of bit 6 (to generate an inverted triangle waveform) + + LFO AM sensitivity (2 bits) indicates to EG how much LFO AM value is shifted before adding to EG output + [...] + LFO PM step (0-31), which takes bits 2:6 of LFO step counter (0-127) and goes to LFO PM calcuation unit + " + + From Sauraen: + +The LFO seems to have 3 sections: + + [*] 7-bit linear prescaler. The test bit 0x21:1 goes into what looks like the carry-in or something similar; + it could go into the reset, I can't quite tell with more detailed analysis. The 7-bit output (plus maybe carry-out) + gets logiced together into 8 lines (evidently perform "== N" with N hardcoded for each line), and these go into a + little selector unit which is also fed by the LFO Speed and LFO Enable bits. I can't quite see the output of this, + but I do see there's some sort of feedback to the prescaler's reset. So this clearly seems like a divide-by-N prescaler. + I can try to read the eight N's for you if you want, but you should be able to reverse engineer them from knowing what the LFO speeds are. + + [*] 7-bit linear counter, with an 8-bit unit after the output (possibly inverts the output after each cycle to make a triangle wave?). + Bits 1:6 of the output of this go to the EG, and stick into its pipeline at the same place where the LFO->Amplitude two bits go. + (Elsewhere the operator LFO enable flag simply forces these two bits to zero for operators not affected by the LFO.) + Some modified version of the 8-bit signal between the counter and the inverter unit thing goes to the third unit of the LFO. + + [*] Highly complex unit which modifies the frequency data as it goes from the channel registers to the PG. The block bits bypass this, + but all the frequency bits get modified by it. There's a bitslice portion corresponding to bits 0:6, and then what appears to be + the same logic folded over to process bits 7:A. But the interesting part is that bits 4:A of the frequency data go into the + bitslices 0:6. That is, the bitslice unit for bit 0 has bit 0 enter at the middle and leave (to the PG) at the bottom. But it also has bit 4 enter at the top. + And so on through bit 6 having bit A enter at the top. It looks like the top portion is some sort of shifter for bits 4:A--the wires go diagonally + so that bit 4 only gets used once, bit 5 gets used in bitslice 1 and 0, bit 6 gets used in bitslices 2:0, and so on so that bit A gets used in all of them. + I'm guessing this whole unit is basically a multiplier, multiplying bits 4:A of the frequency value by bits 0:7 of the LFO state, and then adding the result + to bits 0:6 of the frequency value (with carry up to the higher bits). It looks like, between the multiplied output and the adder, there's another shifter + whose value is based on the the LFO->Frequency bits. But it looks like it's a bit more complex than I'm describing. + +*/ + +module jt12_lfo( + input rst, + input clk, + input clk_en, + input zero, + input lfo_rst, + input lfo_en, + input [2:0] lfo_freq, + output reg [6:0] lfo_mod // 7-bit width according to spritesmind.net +); + +reg [6:0] cnt, limit; + +always @(*) + case( lfo_freq ) // same values as in MAME + 3'd0: limit = 7'd108; + 3'd1: limit = 7'd77; + 3'd2: limit = 7'd71; + 3'd3: limit = 7'd67; + 3'd4: limit = 7'd62; + 3'd5: limit = 7'd44; + 3'd6: limit = 7'd8; + 3'd7: limit = 7'd5; + endcase + +always @(posedge clk) + if( rst || !lfo_en ) + { lfo_mod, cnt } <= 14'd0; + else if( clk_en && zero) begin + if( cnt == limit ) begin + cnt <= 7'd0; + lfo_mod <= lfo_mod + 1'b1; + end + else begin + cnt <= cnt + 1'b1; + end + end + +endmodule diff --git a/common/Sound/JT12/hdl/jt12_logsin.v b/common/Sound/JT12/hdl/jt12_logsin.v new file mode 100644 index 00000000..89743754 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_logsin.v @@ -0,0 +1,298 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots. + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 + +*/ + +//altera message_off 10030 + +module jt12_logsin +( + input [7:0] addr, + input clk, + input clk_en, + output reg [11:0] logsin +); + +reg [11:0] sinelut[255:0]; +initial begin + sinelut[8'd000] = 12'h000; + sinelut[8'd001] = 12'h000; + sinelut[8'd002] = 12'h000; + sinelut[8'd003] = 12'h000; + sinelut[8'd004] = 12'h000; + sinelut[8'd005] = 12'h000; + sinelut[8'd006] = 12'h000; + sinelut[8'd007] = 12'h000; + sinelut[8'd008] = 12'h001; + sinelut[8'd009] = 12'h001; + sinelut[8'd010] = 12'h001; + sinelut[8'd011] = 12'h001; + sinelut[8'd012] = 12'h001; + sinelut[8'd013] = 12'h001; + sinelut[8'd014] = 12'h001; + sinelut[8'd015] = 12'h002; + sinelut[8'd016] = 12'h002; + sinelut[8'd017] = 12'h002; + sinelut[8'd018] = 12'h002; + sinelut[8'd019] = 12'h003; + sinelut[8'd020] = 12'h003; + sinelut[8'd021] = 12'h003; + sinelut[8'd022] = 12'h004; + sinelut[8'd023] = 12'h004; + sinelut[8'd024] = 12'h004; + sinelut[8'd025] = 12'h005; + sinelut[8'd026] = 12'h005; + sinelut[8'd027] = 12'h005; + sinelut[8'd028] = 12'h006; + sinelut[8'd029] = 12'h006; + sinelut[8'd030] = 12'h007; + sinelut[8'd031] = 12'h007; + sinelut[8'd032] = 12'h007; + sinelut[8'd033] = 12'h008; + sinelut[8'd034] = 12'h008; + sinelut[8'd035] = 12'h009; + sinelut[8'd036] = 12'h009; + sinelut[8'd037] = 12'h00a; + sinelut[8'd038] = 12'h00a; + sinelut[8'd039] = 12'h00b; + sinelut[8'd040] = 12'h00c; + sinelut[8'd041] = 12'h00c; + sinelut[8'd042] = 12'h00d; + sinelut[8'd043] = 12'h00d; + sinelut[8'd044] = 12'h00e; + sinelut[8'd045] = 12'h00f; + sinelut[8'd046] = 12'h00f; + sinelut[8'd047] = 12'h010; + sinelut[8'd048] = 12'h011; + sinelut[8'd049] = 12'h011; + sinelut[8'd050] = 12'h012; + sinelut[8'd051] = 12'h013; + sinelut[8'd052] = 12'h014; + sinelut[8'd053] = 12'h014; + sinelut[8'd054] = 12'h015; + sinelut[8'd055] = 12'h016; + sinelut[8'd056] = 12'h017; + sinelut[8'd057] = 12'h017; + sinelut[8'd058] = 12'h018; + sinelut[8'd059] = 12'h019; + sinelut[8'd060] = 12'h01a; + sinelut[8'd061] = 12'h01b; + sinelut[8'd062] = 12'h01c; + sinelut[8'd063] = 12'h01d; + sinelut[8'd064] = 12'h01e; + sinelut[8'd065] = 12'h01f; + sinelut[8'd066] = 12'h020; + sinelut[8'd067] = 12'h021; + sinelut[8'd068] = 12'h022; + sinelut[8'd069] = 12'h023; + sinelut[8'd070] = 12'h024; + sinelut[8'd071] = 12'h025; + sinelut[8'd072] = 12'h026; + sinelut[8'd073] = 12'h027; + sinelut[8'd074] = 12'h028; + sinelut[8'd075] = 12'h029; + sinelut[8'd076] = 12'h02a; + sinelut[8'd077] = 12'h02b; + sinelut[8'd078] = 12'h02d; + sinelut[8'd079] = 12'h02e; + sinelut[8'd080] = 12'h02f; + sinelut[8'd081] = 12'h030; + sinelut[8'd082] = 12'h031; + sinelut[8'd083] = 12'h033; + sinelut[8'd084] = 12'h034; + sinelut[8'd085] = 12'h035; + sinelut[8'd086] = 12'h037; + sinelut[8'd087] = 12'h038; + sinelut[8'd088] = 12'h039; + sinelut[8'd089] = 12'h03b; + sinelut[8'd090] = 12'h03c; + sinelut[8'd091] = 12'h03e; + sinelut[8'd092] = 12'h03f; + sinelut[8'd093] = 12'h040; + sinelut[8'd094] = 12'h042; + sinelut[8'd095] = 12'h043; + sinelut[8'd096] = 12'h045; + sinelut[8'd097] = 12'h046; + sinelut[8'd098] = 12'h048; + sinelut[8'd099] = 12'h04a; + sinelut[8'd100] = 12'h04b; + sinelut[8'd101] = 12'h04d; + sinelut[8'd102] = 12'h04e; + sinelut[8'd103] = 12'h050; + sinelut[8'd104] = 12'h052; + sinelut[8'd105] = 12'h053; + sinelut[8'd106] = 12'h055; + sinelut[8'd107] = 12'h057; + sinelut[8'd108] = 12'h059; + sinelut[8'd109] = 12'h05b; + sinelut[8'd110] = 12'h05c; + sinelut[8'd111] = 12'h05e; + sinelut[8'd112] = 12'h060; + sinelut[8'd113] = 12'h062; + sinelut[8'd114] = 12'h064; + sinelut[8'd115] = 12'h066; + sinelut[8'd116] = 12'h068; + sinelut[8'd117] = 12'h06a; + sinelut[8'd118] = 12'h06c; + sinelut[8'd119] = 12'h06e; + sinelut[8'd120] = 12'h070; + sinelut[8'd121] = 12'h072; + sinelut[8'd122] = 12'h074; + sinelut[8'd123] = 12'h076; + sinelut[8'd124] = 12'h078; + sinelut[8'd125] = 12'h07a; + sinelut[8'd126] = 12'h07d; + sinelut[8'd127] = 12'h07f; + sinelut[8'd128] = 12'h081; + sinelut[8'd129] = 12'h083; + sinelut[8'd130] = 12'h086; + sinelut[8'd131] = 12'h088; + sinelut[8'd132] = 12'h08a; + sinelut[8'd133] = 12'h08d; + sinelut[8'd134] = 12'h08f; + sinelut[8'd135] = 12'h092; + sinelut[8'd136] = 12'h094; + sinelut[8'd137] = 12'h097; + sinelut[8'd138] = 12'h099; + sinelut[8'd139] = 12'h09c; + sinelut[8'd140] = 12'h09f; + sinelut[8'd141] = 12'h0a1; + sinelut[8'd142] = 12'h0a4; + sinelut[8'd143] = 12'h0a7; + sinelut[8'd144] = 12'h0a9; + sinelut[8'd145] = 12'h0ac; + sinelut[8'd146] = 12'h0af; + sinelut[8'd147] = 12'h0b2; + sinelut[8'd148] = 12'h0b5; + sinelut[8'd149] = 12'h0b8; + sinelut[8'd150] = 12'h0bb; + sinelut[8'd151] = 12'h0be; + sinelut[8'd152] = 12'h0c1; + sinelut[8'd153] = 12'h0c4; + sinelut[8'd154] = 12'h0c7; + sinelut[8'd155] = 12'h0ca; + sinelut[8'd156] = 12'h0cd; + sinelut[8'd157] = 12'h0d1; + sinelut[8'd158] = 12'h0d4; + sinelut[8'd159] = 12'h0d7; + sinelut[8'd160] = 12'h0db; + sinelut[8'd161] = 12'h0de; + sinelut[8'd162] = 12'h0e2; + sinelut[8'd163] = 12'h0e5; + sinelut[8'd164] = 12'h0e9; + sinelut[8'd165] = 12'h0ec; + sinelut[8'd166] = 12'h0f0; + sinelut[8'd167] = 12'h0f4; + sinelut[8'd168] = 12'h0f8; + sinelut[8'd169] = 12'h0fb; + sinelut[8'd170] = 12'h0ff; + sinelut[8'd171] = 12'h103; + sinelut[8'd172] = 12'h107; + sinelut[8'd173] = 12'h10b; + sinelut[8'd174] = 12'h10f; + sinelut[8'd175] = 12'h114; + sinelut[8'd176] = 12'h118; + sinelut[8'd177] = 12'h11c; + sinelut[8'd178] = 12'h121; + sinelut[8'd179] = 12'h125; + sinelut[8'd180] = 12'h129; + sinelut[8'd181] = 12'h12e; + sinelut[8'd182] = 12'h133; + sinelut[8'd183] = 12'h137; + sinelut[8'd184] = 12'h13c; + sinelut[8'd185] = 12'h141; + sinelut[8'd186] = 12'h146; + sinelut[8'd187] = 12'h14b; + sinelut[8'd188] = 12'h150; + sinelut[8'd189] = 12'h155; + sinelut[8'd190] = 12'h15b; + sinelut[8'd191] = 12'h160; + sinelut[8'd192] = 12'h166; + sinelut[8'd193] = 12'h16b; + sinelut[8'd194] = 12'h171; + sinelut[8'd195] = 12'h177; + sinelut[8'd196] = 12'h17c; + sinelut[8'd197] = 12'h182; + sinelut[8'd198] = 12'h188; + sinelut[8'd199] = 12'h18f; + sinelut[8'd200] = 12'h195; + sinelut[8'd201] = 12'h19b; + sinelut[8'd202] = 12'h1a2; + sinelut[8'd203] = 12'h1a9; + sinelut[8'd204] = 12'h1b0; + sinelut[8'd205] = 12'h1b7; + sinelut[8'd206] = 12'h1be; + sinelut[8'd207] = 12'h1c5; + sinelut[8'd208] = 12'h1cd; + sinelut[8'd209] = 12'h1d4; + sinelut[8'd210] = 12'h1dc; + sinelut[8'd211] = 12'h1e4; + sinelut[8'd212] = 12'h1ec; + sinelut[8'd213] = 12'h1f5; + sinelut[8'd214] = 12'h1fd; + sinelut[8'd215] = 12'h206; + sinelut[8'd216] = 12'h20f; + sinelut[8'd217] = 12'h218; + sinelut[8'd218] = 12'h222; + sinelut[8'd219] = 12'h22c; + sinelut[8'd220] = 12'h236; + sinelut[8'd221] = 12'h240; + sinelut[8'd222] = 12'h24b; + sinelut[8'd223] = 12'h256; + sinelut[8'd224] = 12'h261; + sinelut[8'd225] = 12'h26d; + sinelut[8'd226] = 12'h279; + sinelut[8'd227] = 12'h286; + sinelut[8'd228] = 12'h293; + sinelut[8'd229] = 12'h2a0; + sinelut[8'd230] = 12'h2af; + sinelut[8'd231] = 12'h2bd; + sinelut[8'd232] = 12'h2cd; + sinelut[8'd233] = 12'h2dc; + sinelut[8'd234] = 12'h2ed; + sinelut[8'd235] = 12'h2ff; + sinelut[8'd236] = 12'h311; + sinelut[8'd237] = 12'h324; + sinelut[8'd238] = 12'h339; + sinelut[8'd239] = 12'h34e; + sinelut[8'd240] = 12'h365; + sinelut[8'd241] = 12'h37e; + sinelut[8'd242] = 12'h398; + sinelut[8'd243] = 12'h3b5; + sinelut[8'd244] = 12'h3d3; + sinelut[8'd245] = 12'h3f5; + sinelut[8'd246] = 12'h41a; + sinelut[8'd247] = 12'h443; + sinelut[8'd248] = 12'h471; + sinelut[8'd249] = 12'h4a6; + sinelut[8'd250] = 12'h4e4; + sinelut[8'd251] = 12'h52e; + sinelut[8'd252] = 12'h58b; + sinelut[8'd253] = 12'h607; + sinelut[8'd254] = 12'h6c3; + sinelut[8'd255] = 12'h859; +end + + always @ (posedge clk) if(clk_en) + logsin <= sinelut[addr]; + +endmodule diff --git a/common/Sound/JT12/hdl/jt12_mmr.v b/common/Sound/JT12/hdl/jt12_mmr.v new file mode 100644 index 00000000..a6a70283 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_mmr.v @@ -0,0 +1,511 @@ +/* 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 . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 14-2-2017 + */ + +`timescale 1ns / 1ps + +module jt12_mmr( + input rst, + input clk, + input cen /* synthesis direct_enable */, + output clk_en, + output clk_en_2, + output clk_en_ssg, + output clk_en_666, + output clk_en_111, + output clk_en_55, + input [7:0] din, + input write, + input [1:0] addr, + output reg busy, + output ch6op, + output [2:0] cur_ch, + output [1:0] cur_op, + // LFO + output reg [2:0] lfo_freq, + output reg lfo_en, + // Timers + output reg [9:0] value_A, + output reg [7:0] value_B, + output reg load_A, + output reg load_B, + output reg enable_irq_A, + output reg enable_irq_B, + output reg clr_flag_A, + output reg clr_flag_B, + output reg fast_timers, + input flag_A, + input overflow_A, + // PCM + output reg [8:0] pcm, + output reg pcm_en, + output reg pcm_wr, // high for one clock cycle when PCM is written + // ADPCM-A + output reg [ 7:0] aon_a, // ON + output reg [ 5:0] atl_a, // TL + output reg [15:0] addr_a, // address latch + output reg [ 7:0] lracl, // L/R ADPCM Channel Level + output reg up_start, // write enable start address latch + output reg up_end, // write enable end address latch + output reg [ 2:0] up_addr, // write enable end address latch + output reg [ 2:0] up_lracl, + output reg up_aon, // There was a write AON register + // ADPCM-B + output reg acmd_on_b, // Control - Process start, Key On + output reg acmd_rep_b, // Control - Repeat + output reg acmd_rst_b, // Control - Reset + output reg acmd_up_b, // Control - New cmd received + output reg [ 1:0] alr_b, // Left / Right + output reg [15:0] astart_b, // Start address + output reg [15:0] aend_b, // End address + output reg [15:0] adeltan_b, // Delta-N + output reg [ 7:0] aeg_b, // Envelope Generator Control + output reg [ 6:0] flag_ctl, + // Operator + output xuse_prevprev1, + output xuse_internal, + output yuse_internal, + output xuse_prev2, + output yuse_prev1, + output yuse_prev2, + // PG + output [10:0] fnum_I, + output [ 2:0] block_I, + output reg pg_stop, + // REG + output [ 1:0] rl, + output [ 2:0] fb_II, + output [ 2:0] alg_I, + output [ 2:0] pms_I, + output [ 1:0] ams_IV, + output amsen_IV, + output [ 2:0] dt1_I, + output [ 3:0] mul_II, + output [ 6:0] tl_IV, + output reg eg_stop, + + output [ 4:0] ar_I, + output [ 4:0] d1r_I, + output [ 4:0] d2r_I, + output [ 3:0] rr_I, + output [ 3:0] sl_I, + output [ 1:0] ks_II, + // SSG operation + output ssg_en_I, + output [2:0] ssg_eg_I, + + output keyon_I, + + // Operator + output zero, + output s1_enters, + output s2_enters, + output s3_enters, + output s4_enters, + + // PSG interace + output [3:0] psg_addr, + output [7:0] psg_data, + output reg psg_wr_n +); + +parameter use_ssg=0, num_ch=6, use_pcm=1, use_adpcm=0; + +reg [1:0] div_setting; + + +jt12_div #(.use_ssg(use_ssg)) u_div ( + .rst ( rst ), + .clk ( clk ), + .cen ( cen ), + .div_setting ( div_setting ), + .clk_en ( clk_en ), + .clk_en_2 ( clk_en_2 ), + .clk_en_ssg ( clk_en_ssg ), + .clk_en_666 ( clk_en_666 ), + .clk_en_111 ( clk_en_111 ), + .clk_en_55 ( clk_en_55 ) +); + +reg [7:0] selected_register; + +/* +reg irq_zero_en, irq_brdy_en, irq_eos_en, + irq_tb_en, irq_ta_en; + */ +reg [6:0] up_opreg; // hot-one encoding. tells which operator register gets updated next +reg [2:0] up_chreg; // hot-one encoding. tells which channel register gets updated next +reg up_keyon; + +localparam REG_TESTYM = 8'h21, + REG_LFO = 8'h22, + REG_CLKA1 = 8'h24, + REG_CLKA2 = 8'h25, + REG_CLKB = 8'h26, + REG_TIMER = 8'h27, + REG_KON = 8'h28, + REG_IRQMASK = 8'h29, + REG_PCM = 8'h2A, + REG_PCM_EN = 8'h2B, + REG_DACTEST = 8'h2C, + REG_CLK_N6 = 8'h2D, + REG_CLK_N3 = 8'h2E, + REG_CLK_N2 = 8'h2F, + // ADPCM (YM2610) + REG_ADPCMA_ON = 8'h00, + REG_ADPCMA_TL = 8'h01, + REG_ADPCMA_TEST = 8'h02; + +reg csm, effect; + +reg [ 2:0] block_ch3op2, block_ch3op3, block_ch3op1; +reg [10:0] fnum_ch3op2, fnum_ch3op3, fnum_ch3op1; +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; + +generate + if( use_ssg ) begin + assign psg_addr = selected_register[3:0]; + assign psg_data = din_copy; + end else begin + assign psg_addr = 4'd0; + assign psg_data = 8'd0; + end +endgenerate + +reg part; + +// 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; + 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; + // 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; + { clr_flag_B, clr_flag_A, + enable_irq_B, enable_irq_A, load_B, load_A } <= 6'd0; + fast_timers <= 1'b0; + // LFO + lfo_freq <= 3'd0; + lfo_en <= 1'b0; + csm <= 1'b0; + effect <= 1'b0; + // PCM + pcm <= 9'h0; + pcm_en <= 1'b0; + pcm_wr <= 1'b0; + // 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; + // 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; + aeg_b <= 8'hff; + // Original test features + eg_stop <= 1'b0; + pg_stop <= 1'b0; + psg_wr_n <= 1'b1; + // + { 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; + end else begin + // WRITE IN REGISTERS + if( write ) begin + if( !addr[0] ) begin + selected_register <= din; + part <= addr[1]; + 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 + + // General control (<0x20 registers and A0==0) + if(!part) begin + casez( selected_register) + //REG_TEST: lfo_rst <= 1'b1; // regardless of din + 8'h0?: psg_wr_n <= 1'b0; + REG_TESTYM: begin + eg_stop <= din[5]; + pg_stop <= din[3]; + fast_timers <= din[2]; + end + REG_CLKA1: value_A[9:2]<= din; + REG_CLKA2: value_A[1:0]<= din[1:0]; + REG_CLKB: value_B <= din; + REG_TIMER: begin + effect <= |din[7:6]; + csm <= din[7:6] == 2'b10; + { clr_flag_B, clr_flag_A, + enable_irq_B, enable_irq_A, + load_B, load_A } <= din[5:0]; + end + `ifndef NOLFO + REG_LFO: { lfo_en, lfo_freq } <= din[3:0]; + `endif + default:; + endcase + end + + // CH3 special registers + casez( selected_register) + 8'hA9: { block_ch3op1, fnum_ch3op1 } <= { latch_fnum, din }; + 8'hA8: { block_ch3op3, fnum_ch3op3 } <= { latch_fnum, din }; + 8'hAA: { block_ch3op2, fnum_ch3op2 } <= { latch_fnum, din }; + // According to http://www.mjsstuf.x10host.com/pages/vgmPlay/vgmPlay.htm + // There is a single fnum latch for all channels + 8'hA4, 8'hA5, 8'hA6, 8'hAD, 8'hAC, 8'hAE: latch_fnum <= din[5:0]; + default:; // avoid incomplete-case warning + endcase + + // YM2612 PCM support + if( use_pcm==1 ) begin + casez( selected_register) + REG_DACTEST: pcm[0] <= din[3]; + REG_PCM: + pcm <= { ~din[7], din[6:0], 1'b1 }; + REG_PCM_EN: pcm_en <= din[7]; + default:; + endcase + pcm_wr <= selected_register==REG_PCM; + end + if( use_adpcm==1 ) begin + // YM2610 ADPCM-A support, A1=1, regs 0-2D + if(part && selected_register[7:6]==2'b0) begin + casez( selected_register[5:0] ) + 6'h0: begin + aon_a <= din; + up_aon <= 1'b1; + end + 6'h1: atl_a <= din[5:0]; + // LRACL + 6'h8, 6'h9, 6'hA, 6'hB, 6'hC, 6'hD: begin + lracl <= din; + up_lracl <= selected_register[2:0]; + end + 6'b01_????, 6'b10_????: begin + if( !selected_register[3] ) addr_a[ 7:0] <= din; + if( selected_register[3] ) addr_a[15:8] <= din; + case( selected_register[5:4] ) + 2'b01, 2'b10: begin + {up_end, up_start } <= selected_register[5:4]; + up_addr <= selected_register[2:0]; + end + default: begin + up_start <= 1'b0; + up_end <= 1'b0; + end + endcase + end + default:; + endcase + end + if( !part && selected_register[7:4]==4'h1 ) begin + // YM2610 ADPCM-B support, A1=0, regs 1x + case(selected_register[3:0]) + 4'd0: {acmd_up_b, acmd_on_b, acmd_rep_b,acmd_rst_b} <= {1'd1,din[7],din[4],din[0]}; + 4'd1: alr_b <= din[7:6]; + 4'd2: astart_b [ 7:0] <= din; + 4'd3: astart_b [15:8] <= din; + 4'd4: aend_b [ 7:0] <= din; + 4'd5: aend_b [15:8] <= din; + 4'h9: adeltan_b[ 7:0] <= din; + 4'ha: adeltan_b[15:8] <= din; + 4'hb: aeg_b <= din; + 4'hc: flag_ctl <= {din[7],din[5:0]}; // this lasts a single clock cycle + default:; + endcase + end + end + if( selected_register[1:0]==2'b11 ) + { up_chreg, up_opreg } <= { 3'h0, 7'h0 }; + else + casez( selected_register ) + // channel registers + 8'hA0, 8'hA1, 8'hA2: { up_chreg, up_opreg } <= { 3'h1, 7'd0 }; // up_fnumlo + // FB + Algorithm + 8'hB0, 8'hB1, 8'hB2: { up_chreg, up_opreg } <= { 3'h2, 7'd0 }; // up_alg + 8'hB4, 8'hB5, 8'hB6: { up_chreg, up_opreg } <= { 3'h4, 7'd0 }; // up_pms + // operator registers + 8'h3?: { up_chreg, up_opreg } <= { 3'h0, 7'h01 }; // up_dt1 + 8'h4?: { up_chreg, up_opreg } <= { 3'h0, 7'h02 }; // up_tl + 8'h5?: { up_chreg, up_opreg } <= { 3'h0, 7'h04 }; // up_ks_ar + 8'h6?: { up_chreg, up_opreg } <= { 3'h0, 7'h08 }; // up_amen_dr + 8'h7?: { up_chreg, up_opreg } <= { 3'h0, 7'h10 }; // up_sr + 8'h8?: { up_chreg, up_opreg } <= { 3'h0, 7'h20 }; // up_sl + 8'h9?: { up_chreg, up_opreg } <= { 3'h0, 7'h40 }; // up_ssgeg + default: { up_chreg, up_opreg } <= { 3'h0, 7'h0 }; + endcase // selected_register + end + end + else if(clk_en) begin /* clear once-only bits */ + // lfo_rst <= 1'b0; + { clr_flag_B, clr_flag_A } <= 2'd0; + psg_wr_n <= 1'b1; + pcm_wr <= 1'b0; + flag_ctl <= 'd0; + up_aon <= 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 + +always @(posedge clk, posedge rst) + 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; + end + end +/* verilator tracing_on */ +jt12_reg #(.num_ch(num_ch)) u_reg( + .rst ( rst ), + .clk ( clk ), // P1 + .clk_en ( clk_en ), + .din ( din_copy ), + + .up_keyon ( up_keyon ), + .up_fnumlo ( up_chreg[0] ), + .up_alg ( up_chreg[1] ), + .up_pms ( up_chreg[2] ), + .up_dt1 ( up_opreg[0] ), + .up_tl ( up_opreg[1] ), + .up_ks_ar ( up_opreg[2] ), + .up_amen_dr ( up_opreg[3] ), + .up_sr ( up_opreg[4] ), + .up_sl_rr ( up_opreg[5] ), + .up_ssgeg ( up_opreg[6] ), + + .op ( up_op ), // operator to update + .ch ( up_ch ), // channel to update + + .csm ( csm ), + .flag_A ( flag_A ), + .overflow_A ( overflow_A), + + .ch6op ( ch6op ), + .cur_ch ( cur_ch ), + .cur_op ( cur_op ), + // CH3 Effect-mode operation + .effect ( effect ), // allows independent freq. for CH 3 + .fnum_ch3op2( fnum_ch3op2 ), + .fnum_ch3op3( fnum_ch3op3 ), + .fnum_ch3op1( fnum_ch3op1 ), + .block_ch3op2( block_ch3op2 ), + .block_ch3op3( block_ch3op3 ), + .block_ch3op1( block_ch3op1 ), + .latch_fnum ( latch_fnum ), + // Operator + .xuse_prevprev1 ( xuse_prevprev1 ), + .xuse_internal ( xuse_internal ), + .yuse_internal ( yuse_internal ), + .xuse_prev2 ( xuse_prev2 ), + .yuse_prev1 ( yuse_prev1 ), + .yuse_prev2 ( yuse_prev2 ), + // PG + .fnum_I ( fnum_I ), + .block_I ( block_I ), + .mul_II ( mul_II ), + .dt1_I ( dt1_I ), + + // EG + .ar_I (ar_I ), // attack rate + .d1r_I (d1r_I ), // decay rate + .d2r_I (d2r_I ), // sustain rate + .rr_I (rr_I ), // release rate + .sl_I (sl_I ), // sustain level + .ks_II (ks_II ), // key scale + // SSG operation + .ssg_en_I ( ssg_en_I ), + .ssg_eg_I ( ssg_eg_I ), + // envelope number + .tl_IV (tl_IV ), + .pms_I (pms_I ), + .ams_IV (ams_IV ), + .amsen_IV (amsen_IV ), + // channel configuration + .rl ( rl ), + .fb_II ( fb_II ), + .alg_I ( alg_I ), + .keyon_I ( keyon_I ), + + .zero ( zero ), + .s1_enters ( s1_enters ), + .s2_enters ( s2_enters ), + .s3_enters ( s3_enters ), + .s4_enters ( s4_enters ) +); + +endmodule diff --git a/common/Sound/JT12/hdl/jt12_mmr_sim.vh b/common/Sound/JT12/hdl/jt12_mmr_sim.vh new file mode 100644 index 00000000..96d60d8f --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_mmr_sim.vh @@ -0,0 +1,854 @@ +`ifdef SIMULATION +/* verilator lint_off PINMISSING */ + +reg [4:0] sep24_cnt; +reg mmr_dump; + +always @(posedge clk ) if(clk_en) + sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0; + +wire [10:0] fnum_ch0s1, fnum_ch1s1, fnum_ch2s1, fnum_ch3s1, + fnum_ch4s1, fnum_ch5s1, fnum_ch0s2, fnum_ch1s2, + fnum_ch2s2, fnum_ch3s2, fnum_ch4s2, fnum_ch5s2, + fnum_ch0s3, fnum_ch1s3, fnum_ch2s3, fnum_ch3s3, + fnum_ch4s3, fnum_ch5s3, fnum_ch0s4, fnum_ch1s4, + fnum_ch2s4, fnum_ch3s4, fnum_ch4s4, fnum_ch5s4; + +sep24 #( .width(11), .pos0(1) ) fnum_sep +( + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( fnum_I ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (fnum_ch0s1), + .ch1s1 (fnum_ch1s1), + .ch2s1 (fnum_ch2s1), + .ch3s1 (fnum_ch3s1), + .ch4s1 (fnum_ch4s1), + .ch5s1 (fnum_ch5s1), + + .ch0s2 (fnum_ch0s2), + .ch1s2 (fnum_ch1s2), + .ch2s2 (fnum_ch2s2), + .ch3s2 (fnum_ch3s2), + .ch4s2 (fnum_ch4s2), + .ch5s2 (fnum_ch5s2), + + .ch0s3 (fnum_ch0s3), + .ch1s3 (fnum_ch1s3), + .ch2s3 (fnum_ch2s3), + .ch3s3 (fnum_ch3s3), + .ch4s3 (fnum_ch4s3), + .ch5s3 (fnum_ch5s3), + + .ch0s4 (fnum_ch0s4), + .ch1s4 (fnum_ch1s4), + .ch2s4 (fnum_ch2s4), + .ch3s4 (fnum_ch3s4), + .ch4s4 (fnum_ch4s4), + .ch5s4 (fnum_ch5s4) +); + +wire [2:0] block_ch0s1, block_ch1s1, block_ch2s1, block_ch3s1, + block_ch4s1, block_ch5s1, block_ch0s2, block_ch1s2, + block_ch2s2, block_ch3s2, block_ch4s2, block_ch5s2, + block_ch0s3, block_ch1s3, block_ch2s3, block_ch3s3, + block_ch4s3, block_ch5s3, block_ch0s4, block_ch1s4, + block_ch2s4, block_ch3s4, block_ch4s4, block_ch5s4; + +sep24 #( .width(3), .pos0(1) ) block_sep +( + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( block_I ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (block_ch0s1), + .ch1s1 (block_ch1s1), + .ch2s1 (block_ch2s1), + .ch3s1 (block_ch3s1), + .ch4s1 (block_ch4s1), + .ch5s1 (block_ch5s1), + + .ch0s2 (block_ch0s2), + .ch1s2 (block_ch1s2), + .ch2s2 (block_ch2s2), + .ch3s2 (block_ch3s2), + .ch4s2 (block_ch4s2), + .ch5s2 (block_ch5s2), + + .ch0s3 (block_ch0s3), + .ch1s3 (block_ch1s3), + .ch2s3 (block_ch2s3), + .ch3s3 (block_ch3s3), + .ch4s3 (block_ch4s3), + .ch5s3 (block_ch5s3), + + .ch0s4 (block_ch0s4), + .ch1s4 (block_ch1s4), + .ch2s4 (block_ch2s4), + .ch3s4 (block_ch3s4), + .ch4s4 (block_ch4s4), + .ch5s4 (block_ch5s4) +); + +wire [1:0] rl_ch0s1, rl_ch1s1, rl_ch2s1, rl_ch3s1, + rl_ch4s1, rl_ch5s1, rl_ch0s2, rl_ch1s2, + rl_ch2s2, rl_ch3s2, rl_ch4s2, rl_ch5s2, + rl_ch0s3, rl_ch1s3, rl_ch2s3, rl_ch3s3, + rl_ch4s3, rl_ch5s3, rl_ch0s4, rl_ch1s4, + rl_ch2s4, rl_ch3s4, rl_ch4s4, rl_ch5s4; + +sep24 #( .width(2), .pos0(1) ) rl_sep +( + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( rl ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (rl_ch0s1), + .ch1s1 (rl_ch1s1), + .ch2s1 (rl_ch2s1), + .ch3s1 (rl_ch3s1), + .ch4s1 (rl_ch4s1), + .ch5s1 (rl_ch5s1), + + .ch0s2 (rl_ch0s2), + .ch1s2 (rl_ch1s2), + .ch2s2 (rl_ch2s2), + .ch3s2 (rl_ch3s2), + .ch4s2 (rl_ch4s2), + .ch5s2 (rl_ch5s2), + + .ch0s3 (rl_ch0s3), + .ch1s3 (rl_ch1s3), + .ch2s3 (rl_ch2s3), + .ch3s3 (rl_ch3s3), + .ch4s3 (rl_ch4s3), + .ch5s3 (rl_ch5s3), + + .ch0s4 (rl_ch0s4), + .ch1s4 (rl_ch1s4), + .ch2s4 (rl_ch2s4), + .ch3s4 (rl_ch3s4), + .ch4s4 (rl_ch4s4), + .ch5s4 (rl_ch5s4) +); + +wire [2:0] fb_ch0s1, fb_ch1s1, fb_ch2s1, fb_ch3s1, + fb_ch4s1, fb_ch5s1, fb_ch0s2, fb_ch1s2, + fb_ch2s2, fb_ch3s2, fb_ch4s2, fb_ch5s2, + fb_ch0s3, fb_ch1s3, fb_ch2s3, fb_ch3s3, + fb_ch4s3, fb_ch5s3, fb_ch0s4, fb_ch1s4, + fb_ch2s4, fb_ch3s4, fb_ch4s4, fb_ch5s4; + +sep24 #( .width(3), .pos0(0) ) fb_sep +( + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( fb_II ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (fb_ch0s1), + .ch1s1 (fb_ch1s1), + .ch2s1 (fb_ch2s1), + .ch3s1 (fb_ch3s1), + .ch4s1 (fb_ch4s1), + .ch5s1 (fb_ch5s1), + + .ch0s2 (fb_ch0s2), + .ch1s2 (fb_ch1s2), + .ch2s2 (fb_ch2s2), + .ch3s2 (fb_ch3s2), + .ch4s2 (fb_ch4s2), + .ch5s2 (fb_ch5s2), + + .ch0s3 (fb_ch0s3), + .ch1s3 (fb_ch1s3), + .ch2s3 (fb_ch2s3), + .ch3s3 (fb_ch3s3), + .ch4s3 (fb_ch4s3), + .ch5s3 (fb_ch5s3), + + .ch0s4 (fb_ch0s4), + .ch1s4 (fb_ch1s4), + .ch2s4 (fb_ch2s4), + .ch3s4 (fb_ch3s4), + .ch4s4 (fb_ch4s4), + .ch5s4 (fb_ch5s4) +); + +wire [2:0] alg_ch0s1, alg_ch1s1, alg_ch2s1, alg_ch3s1, + alg_ch4s1, alg_ch5s1, alg_ch0s2, alg_ch1s2, + alg_ch2s2, alg_ch3s2, alg_ch4s2, alg_ch5s2, + alg_ch0s3, alg_ch1s3, alg_ch2s3, alg_ch3s3, + alg_ch4s3, alg_ch5s3, alg_ch0s4, alg_ch1s4, + alg_ch2s4, alg_ch3s4, alg_ch4s4, alg_ch5s4; + +sep24 #( .width(3), .pos0(1) ) alg_sep +( + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( alg ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (alg_ch0s1), + .ch1s1 (alg_ch1s1), + .ch2s1 (alg_ch2s1), + .ch3s1 (alg_ch3s1), + .ch4s1 (alg_ch4s1), + .ch5s1 (alg_ch5s1), + + .ch0s2 (alg_ch0s2), + .ch1s2 (alg_ch1s2), + .ch2s2 (alg_ch2s2), + .ch3s2 (alg_ch3s2), + .ch4s2 (alg_ch4s2), + .ch5s2 (alg_ch5s2), + + .ch0s3 (alg_ch0s3), + .ch1s3 (alg_ch1s3), + .ch2s3 (alg_ch2s3), + .ch3s3 (alg_ch3s3), + .ch4s3 (alg_ch4s3), + .ch5s3 (alg_ch5s3), + + .ch0s4 (alg_ch0s4), + .ch1s4 (alg_ch1s4), + .ch2s4 (alg_ch2s4), + .ch3s4 (alg_ch3s4), + .ch4s4 (alg_ch4s4), + .ch5s4 (alg_ch5s4) +); + +wire [2:0] dt1_ch0s1, dt1_ch1s1, dt1_ch2s1, dt1_ch3s1, + dt1_ch4s1, dt1_ch5s1, dt1_ch0s2, dt1_ch1s2, + dt1_ch2s2, dt1_ch3s2, dt1_ch4s2, dt1_ch5s2, + dt1_ch0s3, dt1_ch1s3, dt1_ch2s3, dt1_ch3s3, + dt1_ch4s3, dt1_ch5s3, dt1_ch0s4, dt1_ch1s4, + dt1_ch2s4, dt1_ch3s4, dt1_ch4s4, dt1_ch5s4; + +sep24 #( .width(3), .pos0(0) ) dt1_sep +( + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( dt1_II ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (dt1_ch0s1), + .ch1s1 (dt1_ch1s1), + .ch2s1 (dt1_ch2s1), + .ch3s1 (dt1_ch3s1), + .ch4s1 (dt1_ch4s1), + .ch5s1 (dt1_ch5s1), + + .ch0s2 (dt1_ch0s2), + .ch1s2 (dt1_ch1s2), + .ch2s2 (dt1_ch2s2), + .ch3s2 (dt1_ch3s2), + .ch4s2 (dt1_ch4s2), + .ch5s2 (dt1_ch5s2), + + .ch0s3 (dt1_ch0s3), + .ch1s3 (dt1_ch1s3), + .ch2s3 (dt1_ch2s3), + .ch3s3 (dt1_ch3s3), + .ch4s3 (dt1_ch4s3), + .ch5s3 (dt1_ch5s3), + + .ch0s4 (dt1_ch0s4), + .ch1s4 (dt1_ch1s4), + .ch2s4 (dt1_ch2s4), + .ch3s4 (dt1_ch3s4), + .ch4s4 (dt1_ch4s4), + .ch5s4 (dt1_ch5s4) +); + +wire [3:0] mul_ch0s1, mul_ch1s1, mul_ch2s1, mul_ch3s1, + mul_ch4s1, mul_ch5s1, mul_ch0s2, mul_ch1s2, + mul_ch2s2, mul_ch3s2, mul_ch4s2, mul_ch5s2, + mul_ch0s3, mul_ch1s3, mul_ch2s3, mul_ch3s3, + mul_ch4s3, mul_ch5s3, mul_ch0s4, mul_ch1s4, + mul_ch2s4, mul_ch3s4, mul_ch4s4, mul_ch5s4; + +sep24 #( .width(4), .pos0(21) ) mul_sep +( + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( mul_V ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (mul_ch0s1), + .ch1s1 (mul_ch1s1), + .ch2s1 (mul_ch2s1), + .ch3s1 (mul_ch3s1), + .ch4s1 (mul_ch4s1), + .ch5s1 (mul_ch5s1), + + .ch0s2 (mul_ch0s2), + .ch1s2 (mul_ch1s2), + .ch2s2 (mul_ch2s2), + .ch3s2 (mul_ch3s2), + .ch4s2 (mul_ch4s2), + .ch5s2 (mul_ch5s2), + + .ch0s3 (mul_ch0s3), + .ch1s3 (mul_ch1s3), + .ch2s3 (mul_ch2s3), + .ch3s3 (mul_ch3s3), + .ch4s3 (mul_ch4s3), + .ch5s3 (mul_ch5s3), + + .ch0s4 (mul_ch0s4), + .ch1s4 (mul_ch1s4), + .ch2s4 (mul_ch2s4), + .ch3s4 (mul_ch3s4), + .ch4s4 (mul_ch4s4), + .ch5s4 (mul_ch5s4) +); + +wire [6:0] tl_ch0s1, tl_ch1s1, tl_ch2s1, tl_ch3s1, + tl_ch4s1, tl_ch5s1, tl_ch0s2, tl_ch1s2, + tl_ch2s2, tl_ch3s2, tl_ch4s2, tl_ch5s2, + tl_ch0s3, tl_ch1s3, tl_ch2s3, tl_ch3s3, + tl_ch4s3, tl_ch5s3, tl_ch0s4, tl_ch1s4, + tl_ch2s4, tl_ch3s4, tl_ch4s4, tl_ch5s4; + +sep24 #( .width(7), .pos0(22) ) tl_step +( + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( tl_IV ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (tl_ch0s1), + .ch1s1 (tl_ch1s1), + .ch2s1 (tl_ch2s1), + .ch3s1 (tl_ch3s1), + .ch4s1 (tl_ch4s1), + .ch5s1 (tl_ch5s1), + + .ch0s2 (tl_ch0s2), + .ch1s2 (tl_ch1s2), + .ch2s2 (tl_ch2s2), + .ch3s2 (tl_ch3s2), + .ch4s2 (tl_ch4s2), + .ch5s2 (tl_ch5s2), + + .ch0s3 (tl_ch0s3), + .ch1s3 (tl_ch1s3), + .ch2s3 (tl_ch2s3), + .ch3s3 (tl_ch3s3), + .ch4s3 (tl_ch4s3), + .ch5s3 (tl_ch5s3), + + .ch0s4 (tl_ch0s4), + .ch1s4 (tl_ch1s4), + .ch2s4 (tl_ch2s4), + .ch3s4 (tl_ch3s4), + .ch4s4 (tl_ch4s4), + .ch5s4 (tl_ch5s4) +); + +wire [4:0] ar_ch0s1, ar_ch1s1, ar_ch2s1, ar_ch3s1, + ar_ch4s1, ar_ch5s1, ar_ch0s2, ar_ch1s2, + ar_ch2s2, ar_ch3s2, ar_ch4s2, ar_ch5s2, + ar_ch0s3, ar_ch1s3, ar_ch2s3, ar_ch3s3, + ar_ch4s3, ar_ch5s3, ar_ch0s4, ar_ch1s4, + ar_ch2s4, ar_ch3s4, ar_ch4s4, ar_ch5s4; + +sep24 #( .width(5), .pos0(1) ) ar_step +( + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( ar_I ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (ar_ch0s1), + .ch1s1 (ar_ch1s1), + .ch2s1 (ar_ch2s1), + .ch3s1 (ar_ch3s1), + .ch4s1 (ar_ch4s1), + .ch5s1 (ar_ch5s1), + + .ch0s2 (ar_ch0s2), + .ch1s2 (ar_ch1s2), + .ch2s2 (ar_ch2s2), + .ch3s2 (ar_ch3s2), + .ch4s2 (ar_ch4s2), + .ch5s2 (ar_ch5s2), + + .ch0s3 (ar_ch0s3), + .ch1s3 (ar_ch1s3), + .ch2s3 (ar_ch2s3), + .ch3s3 (ar_ch3s3), + .ch4s3 (ar_ch4s3), + .ch5s3 (ar_ch5s3), + + .ch0s4 (ar_ch0s4), + .ch1s4 (ar_ch1s4), + .ch2s4 (ar_ch2s4), + .ch3s4 (ar_ch3s4), + .ch4s4 (ar_ch4s4), + .ch5s4 (ar_ch5s4) +); + +wire [4:0] d1r_ch0s1, d1r_ch1s1, d1r_ch2s1, d1r_ch3s1, + d1r_ch4s1, d1r_ch5s1, d1r_ch0s2, d1r_ch1s2, + d1r_ch2s2, d1r_ch3s2, d1r_ch4s2, d1r_ch5s2, + d1r_ch0s3, d1r_ch1s3, d1r_ch2s3, d1r_ch3s3, + d1r_ch4s3, d1r_ch5s3, d1r_ch0s4, d1r_ch1s4, + d1r_ch2s4, d1r_ch3s4, d1r_ch4s4, d1r_ch5s4; + +sep24 #( .width(5), .pos0(1) ) d1r_step +( + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( d1r_I ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (d1r_ch0s1), + .ch1s1 (d1r_ch1s1), + .ch2s1 (d1r_ch2s1), + .ch3s1 (d1r_ch3s1), + .ch4s1 (d1r_ch4s1), + .ch5s1 (d1r_ch5s1), + + .ch0s2 (d1r_ch0s2), + .ch1s2 (d1r_ch1s2), + .ch2s2 (d1r_ch2s2), + .ch3s2 (d1r_ch3s2), + .ch4s2 (d1r_ch4s2), + .ch5s2 (d1r_ch5s2), + + .ch0s3 (d1r_ch0s3), + .ch1s3 (d1r_ch1s3), + .ch2s3 (d1r_ch2s3), + .ch3s3 (d1r_ch3s3), + .ch4s3 (d1r_ch4s3), + .ch5s3 (d1r_ch5s3), + + .ch0s4 (d1r_ch0s4), + .ch1s4 (d1r_ch1s4), + .ch2s4 (d1r_ch2s4), + .ch3s4 (d1r_ch3s4), + .ch4s4 (d1r_ch4s4), + .ch5s4 (d1r_ch5s4) +); + +wire [4:0] d2r_ch0s1, d2r_ch1s1, d2r_ch2s1, d2r_ch3s1, + d2r_ch4s1, d2r_ch5s1, d2r_ch0s2, d2r_ch1s2, + d2r_ch2s2, d2r_ch3s2, d2r_ch4s2, d2r_ch5s2, + d2r_ch0s3, d2r_ch1s3, d2r_ch2s3, d2r_ch3s3, + d2r_ch4s3, d2r_ch5s3, d2r_ch0s4, d2r_ch1s4, + d2r_ch2s4, d2r_ch3s4, d2r_ch4s4, d2r_ch5s4; + +sep24 #( .width(5), .pos0(1) ) d2r_step +( + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( d2r_I ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (d2r_ch0s1), + .ch1s1 (d2r_ch1s1), + .ch2s1 (d2r_ch2s1), + .ch3s1 (d2r_ch3s1), + .ch4s1 (d2r_ch4s1), + .ch5s1 (d2r_ch5s1), + + .ch0s2 (d2r_ch0s2), + .ch1s2 (d2r_ch1s2), + .ch2s2 (d2r_ch2s2), + .ch3s2 (d2r_ch3s2), + .ch4s2 (d2r_ch4s2), + .ch5s2 (d2r_ch5s2), + + .ch0s3 (d2r_ch0s3), + .ch1s3 (d2r_ch1s3), + .ch2s3 (d2r_ch2s3), + .ch3s3 (d2r_ch3s3), + .ch4s3 (d2r_ch4s3), + .ch5s3 (d2r_ch5s3), + + .ch0s4 (d2r_ch0s4), + .ch1s4 (d2r_ch1s4), + .ch2s4 (d2r_ch2s4), + .ch3s4 (d2r_ch3s4), + .ch4s4 (d2r_ch4s4), + .ch5s4 (d2r_ch5s4) +); + +wire [3:0] rr_ch0s1, rr_ch1s1, rr_ch2s1, rr_ch3s1, + rr_ch4s1, rr_ch5s1, rr_ch0s2, rr_ch1s2, + rr_ch2s2, rr_ch3s2, rr_ch4s2, rr_ch5s2, + rr_ch0s3, rr_ch1s3, rr_ch2s3, rr_ch3s3, + rr_ch4s3, rr_ch5s3, rr_ch0s4, rr_ch1s4, + rr_ch2s4, rr_ch3s4, rr_ch4s4, rr_ch5s4; + +sep24 #( .width(4), .pos0(1) ) rr_step +( + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( rr_I ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (rr_ch0s1), + .ch1s1 (rr_ch1s1), + .ch2s1 (rr_ch2s1), + .ch3s1 (rr_ch3s1), + .ch4s1 (rr_ch4s1), + .ch5s1 (rr_ch5s1), + + .ch0s2 (rr_ch0s2), + .ch1s2 (rr_ch1s2), + .ch2s2 (rr_ch2s2), + .ch3s2 (rr_ch3s2), + .ch4s2 (rr_ch4s2), + .ch5s2 (rr_ch5s2), + + .ch0s3 (rr_ch0s3), + .ch1s3 (rr_ch1s3), + .ch2s3 (rr_ch2s3), + .ch3s3 (rr_ch3s3), + .ch4s3 (rr_ch4s3), + .ch5s3 (rr_ch5s3), + + .ch0s4 (rr_ch0s4), + .ch1s4 (rr_ch1s4), + .ch2s4 (rr_ch2s4), + .ch3s4 (rr_ch3s4), + .ch4s4 (rr_ch4s4), + .ch5s4 (rr_ch5s4) +); + +wire [3:0] d1l_ch0s1, d1l_ch1s1, d1l_ch2s1, d1l_ch3s1, + d1l_ch4s1, d1l_ch5s1, d1l_ch0s2, d1l_ch1s2, + d1l_ch2s2, d1l_ch3s2, d1l_ch4s2, d1l_ch5s2, + d1l_ch0s3, d1l_ch1s3, d1l_ch2s3, d1l_ch3s3, + d1l_ch4s3, d1l_ch5s3, d1l_ch0s4, d1l_ch1s4, + d1l_ch2s4, d1l_ch3s4, d1l_ch4s4, d1l_ch5s4; + +sep24 #( .width(4), .pos0(1) ) d1l_step +( + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( sl_I ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (d1l_ch0s1), + .ch1s1 (d1l_ch1s1), + .ch2s1 (d1l_ch2s1), + .ch3s1 (d1l_ch3s1), + .ch4s1 (d1l_ch4s1), + .ch5s1 (d1l_ch5s1), + + .ch0s2 (d1l_ch0s2), + .ch1s2 (d1l_ch1s2), + .ch2s2 (d1l_ch2s2), + .ch3s2 (d1l_ch3s2), + .ch4s2 (d1l_ch4s2), + .ch5s2 (d1l_ch5s2), + + .ch0s3 (d1l_ch0s3), + .ch1s3 (d1l_ch1s3), + .ch2s3 (d1l_ch2s3), + .ch3s3 (d1l_ch3s3), + .ch4s3 (d1l_ch4s3), + .ch5s3 (d1l_ch5s3), + + .ch0s4 (d1l_ch0s4), + .ch1s4 (d1l_ch1s4), + .ch2s4 (d1l_ch2s4), + .ch3s4 (d1l_ch3s4), + .ch4s4 (d1l_ch4s4), + .ch5s4 (d1l_ch5s4) +); + +wire [1:0] ks_ch0s1, ks_ch1s1, ks_ch2s1, ks_ch3s1, + ks_ch4s1, ks_ch5s1, ks_ch0s2, ks_ch1s2, + ks_ch2s2, ks_ch3s2, ks_ch4s2, ks_ch5s2, + ks_ch0s3, ks_ch1s3, ks_ch2s3, ks_ch3s3, + ks_ch4s3, ks_ch5s3, ks_ch0s4, ks_ch1s4, + ks_ch2s4, ks_ch3s4, ks_ch4s4, ks_ch5s4; + +sep24 #( .width(2), .pos0(0) ) ks_step +( + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( ks_II ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (ks_ch0s1), + .ch1s1 (ks_ch1s1), + .ch2s1 (ks_ch2s1), + .ch3s1 (ks_ch3s1), + .ch4s1 (ks_ch4s1), + .ch5s1 (ks_ch5s1), + + .ch0s2 (ks_ch0s2), + .ch1s2 (ks_ch1s2), + .ch2s2 (ks_ch2s2), + .ch3s2 (ks_ch3s2), + .ch4s2 (ks_ch4s2), + .ch5s2 (ks_ch5s2), + + .ch0s3 (ks_ch0s3), + .ch1s3 (ks_ch1s3), + .ch2s3 (ks_ch2s3), + .ch3s3 (ks_ch3s3), + .ch4s3 (ks_ch4s3), + .ch5s3 (ks_ch5s3), + + .ch0s4 (ks_ch0s4), + .ch1s4 (ks_ch1s4), + .ch2s4 (ks_ch2s4), + .ch3s4 (ks_ch3s4), + .ch4s4 (ks_ch4s4), + .ch5s4 (ks_ch5s4) +); + +wire [3:0] ssg_I = {ssg_en_I, ssg_eg_I}; + +wire [3:0] ssg_ch0s1, ssg_ch1s1, ssg_ch2s1, ssg_ch3s1, + ssg_ch4s1, ssg_ch5s1, ssg_ch0s2, ssg_ch1s2, + ssg_ch2s2, ssg_ch3s2, ssg_ch4s2, ssg_ch5s2, + ssg_ch0s3, ssg_ch1s3, ssg_ch2s3, ssg_ch3s3, + ssg_ch4s3, ssg_ch5s3, ssg_ch0s4, ssg_ch1s4, + ssg_ch2s4, ssg_ch3s4, ssg_ch4s4, ssg_ch5s4; + +sep24 #( .width(4), .pos0(1) ) ssg_step +( + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( ssg_I ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (ssg_ch0s1), + .ch1s1 (ssg_ch1s1), + .ch2s1 (ssg_ch2s1), + .ch3s1 (ssg_ch3s1), + .ch4s1 (ssg_ch4s1), + .ch5s1 (ssg_ch5s1), + + .ch0s2 (ssg_ch0s2), + .ch1s2 (ssg_ch1s2), + .ch2s2 (ssg_ch2s2), + .ch3s2 (ssg_ch3s2), + .ch4s2 (ssg_ch4s2), + .ch5s2 (ssg_ch5s2), + + .ch0s3 (ssg_ch0s3), + .ch1s3 (ssg_ch1s3), + .ch2s3 (ssg_ch2s3), + .ch3s3 (ssg_ch3s3), + .ch4s3 (ssg_ch4s3), + .ch5s3 (ssg_ch5s3), + + .ch0s4 (ssg_ch0s4), + .ch1s4 (ssg_ch1s4), + .ch2s4 (ssg_ch2s4), + .ch3s4 (ssg_ch3s4), + .ch4s4 (ssg_ch4s4), + .ch5s4 (ssg_ch5s4) +); + +wire kon_ch0s1, kon_ch1s1, kon_ch2s1, kon_ch3s1, + kon_ch4s1, kon_ch5s1, kon_ch0s2, kon_ch1s2, + kon_ch2s2, kon_ch3s2, kon_ch4s2, kon_ch5s2, + kon_ch0s3, kon_ch1s3, kon_ch2s3, kon_ch3s3, + kon_ch4s3, kon_ch5s3, kon_ch0s4, kon_ch1s4, + kon_ch2s4, kon_ch3s4, kon_ch4s4, kon_ch5s4; + +sep24 #( .width(1), .pos0(1) ) konstep +( + .clk ( clk ), + .clk_en ( clk_en ), + .mixed ( keyon_I ), + .mask ( 24'd0 ), + .cnt ( sep24_cnt ), + + .ch0s1 (kon_ch0s1), + .ch1s1 (kon_ch1s1), + .ch2s1 (kon_ch2s1), + .ch3s1 (kon_ch3s1), + .ch4s1 (kon_ch4s1), + .ch5s1 (kon_ch5s1), + + .ch0s2 (kon_ch0s2), + .ch1s2 (kon_ch1s2), + .ch2s2 (kon_ch2s2), + .ch3s2 (kon_ch3s2), + .ch4s2 (kon_ch4s2), + .ch5s2 (kon_ch5s2), + + .ch0s3 (kon_ch0s3), + .ch1s3 (kon_ch1s3), + .ch2s3 (kon_ch2s3), + .ch3s3 (kon_ch3s3), + .ch4s3 (kon_ch4s3), + .ch5s3 (kon_ch5s3), + + .ch0s4 (kon_ch0s4), + .ch1s4 (kon_ch1s4), + .ch2s4 (kon_ch2s4), + .ch3s4 (kon_ch3s4), + .ch4s4 (kon_ch4s4), + .ch5s4 (kon_ch5s4) +); + +/* Dump all registers on request */ +integer fmmr; +initial begin + fmmr=$fopen("mmr_dump.log","w"); +end + +always @(posedge clk ) +if (mmr_dump ) begin + $fdisplay( fmmr, "-------------------------------"); + // Channel 0 + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch0s1, fnum_ch0s1, rl_ch0s1, fb_ch0s1, alg_ch0s1, + dt1_ch0s1, mul_ch0s1, tl_ch0s1, ar_ch0s1, d1r_ch0s1, + d2r_ch0s1, rr_ch0s1, d1l_ch0s1, ks_ch0s1, ssg_ch0s1, + kon_ch0s1 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch0s2, fnum_ch0s2, rl_ch0s2, fb_ch0s2, alg_ch0s2, + dt1_ch0s2, mul_ch0s2, tl_ch0s2, ar_ch0s2, d1r_ch0s2, + d2r_ch0s2, rr_ch0s2, d1l_ch0s2, ks_ch0s2, ssg_ch0s2, + kon_ch0s2 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch0s1, fnum_ch0s3, rl_ch0s3, fb_ch0s3, alg_ch0s3, + dt1_ch0s3, mul_ch0s3, tl_ch0s3, ar_ch0s3, d1r_ch0s3, + d2r_ch0s3, rr_ch0s3, d1l_ch0s3, ks_ch0s3, ssg_ch0s3, + kon_ch0s3 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch0s4, fnum_ch0s4, rl_ch0s4, fb_ch0s4, alg_ch0s4, + dt1_ch0s4, mul_ch0s4, tl_ch0s4, ar_ch0s4, d1r_ch0s4, + d2r_ch0s4, rr_ch0s4, d1l_ch0s4, ks_ch0s4, ssg_ch0s4, + kon_ch0s4 ); + // Channel 1 + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch1s1, fnum_ch1s1, rl_ch1s1, fb_ch1s1, alg_ch1s1, + dt1_ch1s1, mul_ch1s1, tl_ch1s1, ar_ch1s1, d1r_ch1s1, + d2r_ch1s1, rr_ch1s1, d1l_ch1s1, ks_ch1s1, ssg_ch1s1, + kon_ch1s1 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch1s2, fnum_ch1s2, rl_ch1s2, fb_ch1s2, alg_ch1s2, + dt1_ch1s2, mul_ch1s2, tl_ch1s2, ar_ch1s2, d1r_ch1s2, + d2r_ch1s2, rr_ch1s2, d1l_ch1s2, ks_ch1s2, ssg_ch1s2, + kon_ch1s2 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch1s3, fnum_ch1s3, rl_ch1s3, fb_ch1s3, alg_ch1s3, + dt1_ch1s3, mul_ch1s3, tl_ch1s3, ar_ch1s3, d1r_ch1s3, + d2r_ch1s3, rr_ch1s3, d1l_ch1s3, ks_ch1s3, ssg_ch1s3, + kon_ch1s3 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch1s4, fnum_ch1s4, rl_ch1s4, fb_ch1s4, alg_ch1s4, + dt1_ch1s4, mul_ch1s4, tl_ch1s4, ar_ch1s4, d1r_ch1s4, + d2r_ch1s4, rr_ch1s4, d1l_ch1s4, ks_ch1s4, ssg_ch1s4, + kon_ch1s4 ); + // Channel 2 + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch2s1, fnum_ch2s1, rl_ch2s1, fb_ch2s1, alg_ch2s1, + dt1_ch2s1, mul_ch2s1, tl_ch2s1, ar_ch2s1, d1r_ch2s1, + d2r_ch2s1, rr_ch2s1, d1l_ch2s1, ks_ch2s1, ssg_ch2s1, + kon_ch2s1 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch2s2, fnum_ch2s2, rl_ch2s2, fb_ch2s2, alg_ch2s2, + dt1_ch2s2, mul_ch2s2, tl_ch2s2, ar_ch2s2, d1r_ch2s2, + d2r_ch2s2, rr_ch2s2, d1l_ch2s2, ks_ch2s2, ssg_ch2s2, + kon_ch2s2 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch2s3, fnum_ch2s3, rl_ch2s3, fb_ch2s3, alg_ch2s3, + dt1_ch2s3, mul_ch2s3, tl_ch2s3, ar_ch2s3, d1r_ch2s3, + d2r_ch2s3, rr_ch2s3, d1l_ch2s3, ks_ch2s3, ssg_ch2s3, + kon_ch2s3 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch2s4, fnum_ch2s4, rl_ch2s4, fb_ch2s4, alg_ch2s4, + dt1_ch2s4, mul_ch2s4, tl_ch2s4, ar_ch2s4, d1r_ch2s4, + d2r_ch2s4, rr_ch2s4, d1l_ch2s4, ks_ch2s4, ssg_ch2s4, + kon_ch2s4 ); + // Channel 3 + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch3s1, fnum_ch3s1, rl_ch3s1, fb_ch3s1, alg_ch3s1, + dt1_ch3s1, mul_ch3s1, tl_ch3s1, ar_ch3s1, d1r_ch3s1, + d2r_ch3s1, rr_ch3s1, d1l_ch3s1, ks_ch3s1, ssg_ch3s1, + kon_ch3s1 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch3s2, fnum_ch3s2, rl_ch3s2, fb_ch3s2, alg_ch3s2, + dt1_ch3s2, mul_ch3s2, tl_ch3s2, ar_ch3s2, d1r_ch3s2, + d2r_ch3s2, rr_ch3s2, d1l_ch3s2, ks_ch3s2, ssg_ch3s2, + kon_ch3s2 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch3s3, fnum_ch3s3, rl_ch3s3, fb_ch3s3, alg_ch3s3, + dt1_ch3s3, mul_ch3s3, tl_ch3s3, ar_ch3s3, d1r_ch3s3, + d2r_ch3s3, rr_ch3s3, d1l_ch3s3, ks_ch3s3, ssg_ch3s3, + kon_ch3s3 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch3s4, fnum_ch3s4, rl_ch3s4, fb_ch3s4, alg_ch3s4, + dt1_ch3s4, mul_ch3s4, tl_ch3s4, ar_ch3s4, d1r_ch3s4, + d2r_ch3s4, rr_ch3s4, d1l_ch3s4, ks_ch3s4, ssg_ch3s4, + kon_ch3s4 ); + // Channel 4 + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch4s1, fnum_ch4s1, rl_ch4s1, fb_ch4s1, alg_ch4s1, + dt1_ch4s1, mul_ch4s1, tl_ch4s1, ar_ch4s1, d1r_ch4s1, + d2r_ch4s1, rr_ch4s1, d1l_ch4s1, ks_ch4s1, ssg_ch4s1, + kon_ch4s1 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch4s2, fnum_ch4s2, rl_ch4s2, fb_ch4s2, alg_ch4s2, + dt1_ch4s2, mul_ch4s2, tl_ch4s2, ar_ch4s2, d1r_ch4s2, + d2r_ch4s2, rr_ch4s2, d1l_ch4s2, ks_ch4s2, ssg_ch4s2, + kon_ch4s2 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch4s3, fnum_ch4s3, rl_ch4s3, fb_ch4s3, alg_ch4s3, + dt1_ch4s3, mul_ch4s3, tl_ch4s3, ar_ch4s3, d1r_ch4s3, + d2r_ch4s3, rr_ch4s3, d1l_ch4s3, ks_ch4s3, ssg_ch4s3, + kon_ch4s3 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch4s4, fnum_ch4s4, rl_ch4s4, fb_ch4s4, alg_ch4s4, + dt1_ch4s4, mul_ch4s4, tl_ch4s4, ar_ch4s4, d1r_ch4s4, + d2r_ch4s4, rr_ch4s4, d1l_ch4s4, ks_ch4s4, ssg_ch4s4, + kon_ch4s4 ); + // Channel 5 + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch5s1, fnum_ch5s1, rl_ch5s1, fb_ch5s1, alg_ch5s1, + dt1_ch5s1, mul_ch5s1, tl_ch5s1, ar_ch5s1, d1r_ch5s1, + d2r_ch5s1, rr_ch5s1, d1l_ch5s1, ks_ch5s1, ssg_ch5s1, + kon_ch5s1 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch5s2, fnum_ch5s2, rl_ch5s2, fb_ch5s2, alg_ch5s2, + dt1_ch5s2, mul_ch5s2, tl_ch5s2, ar_ch5s2, d1r_ch5s2, + d2r_ch5s2, rr_ch5s2, d1l_ch5s2, ks_ch5s2, ssg_ch5s2, + kon_ch5s2 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch5s3, fnum_ch5s3, rl_ch5s3, fb_ch5s3, alg_ch5s3, + dt1_ch5s3, mul_ch5s3, tl_ch5s3, ar_ch5s3, d1r_ch5s3, + d2r_ch5s3, rr_ch5s3, d1l_ch5s3, ks_ch5s3, ssg_ch5s3, + kon_ch5s3 ); + $fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x", + block_ch5s4, fnum_ch5s4, rl_ch5s4, fb_ch5s4, alg_ch5s4, + dt1_ch5s4, mul_ch5s4, tl_ch5s4, ar_ch5s4, d1r_ch5s4, + d2r_ch5s4, rr_ch5s4, d1l_ch5s4, ks_ch5s4, ssg_ch5s4, + kon_ch5s4 ); +end +/* verilator lint_on PINMISSING */ +`endif + diff --git a/common/Sound/JT12/hdl/jt12_mod.v b/common/Sound/JT12/hdl/jt12_mod.v new file mode 100644 index 00000000..93ac478b --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_mod.v @@ -0,0 +1,153 @@ +`timescale 1ns / 1ps + + +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 + +*/ + +module jt12_mod( + input s1_enters, + input s2_enters, + input s3_enters, + input s4_enters, + + input [2:0] alg_I, + + output reg xuse_prevprev1, + output reg xuse_internal, + output reg yuse_internal, + output reg xuse_prev2, + output reg yuse_prev1, + output reg yuse_prev2 +); + +parameter num_ch=6; + +reg [7:0] alg_hot; + +always @(*) begin + case( alg_I ) + 3'd0: alg_hot = 8'h1; // D0 + 3'd1: alg_hot = 8'h2; // D1 + 3'd2: alg_hot = 8'h4; // D2 + 3'd3: alg_hot = 8'h8; // D3 + 3'd4: alg_hot = 8'h10; // D4 + 3'd5: alg_hot = 8'h20; // D5 + 3'd6: alg_hot = 8'h40; // D6 + 3'd7: alg_hot = 8'h80; // D7 + endcase +end + +// prev2 cannot modulate with prevprev1 at the same time +// x = prev2, prevprev1, internal_x +// y = prev1, internal_y + +generate + if( num_ch==6 ) begin + always @(*) begin + xuse_prevprev1 = s1_enters | (s3_enters&alg_hot[5]); + xuse_prev2 = (s3_enters&(|alg_hot[2:0])) | (s4_enters&alg_hot[3]); + xuse_internal = s4_enters & alg_hot[2]; + yuse_internal = s4_enters & (|{alg_hot[4:3],alg_hot[1:0]}); + yuse_prev1 = s1_enters | (s3_enters&alg_hot[1]) | + (s2_enters&(|{alg_hot[6:3],alg_hot[0]}) )| + (s4_enters&(|{alg_hot[5],alg_hot[2]})); + yuse_prev2 = 1'b0; // unused for 6 channels + end + end else begin + reg [2:0] xuse_s4, xuse_s3, xuse_s2, xuse_s1; + reg [2:0] yuse_s4, yuse_s3, yuse_s2, yuse_s1; + always @(*) begin // 3 ch + // S1 + { xuse_s1, yuse_s1 } = { 3'b001, 3'b100 }; + // S2 + casez( 1'b1 ) + // S2 modulated by S1 + alg_hot[6], alg_hot[5], alg_hot[4], alg_hot[3], alg_hot[0]: + { xuse_s2, yuse_s2 } = { 3'b000, 3'b100 }; // prev1 + default: { xuse_s2, yuse_s2 } = 6'd0; + endcase + // S3 + casez( 1'b1 ) + // S3 modulated by S1 + alg_hot[5]: + { xuse_s3, yuse_s3 } = { 3'b000, 3'b100 }; // prev1 + // S3 modulated by S2 + alg_hot[2], alg_hot[0]: + { xuse_s3, yuse_s3 } = { 3'b000, 3'b010 }; // prev2 + // S3 modulated by S2+S1 + alg_hot[1]: + { xuse_s3, yuse_s3 } = { 3'b010, 3'b100 }; // prev2 + prev1 + default: { xuse_s3, yuse_s3 } = 6'd0; + endcase + // S4 + casez( 1'b1 ) + // S4 modulated by S1 + alg_hot[5]: + { xuse_s4, yuse_s4 } = { 3'b000, 3'b100 }; // prev1 + // S4 modulated by S3 + alg_hot[4], alg_hot[1], alg_hot[0]: + { xuse_s4, yuse_s4 } = { 3'b100, 3'b000 }; // prevprev1 + // S4 modulated by S3+S2 + alg_hot[3]: + { xuse_s4, yuse_s4 } = { 3'b100, 3'b010 }; // prevprev1+prev2 + // S4 modulated by S3+S1 + alg_hot[2]: + { xuse_s4, yuse_s4 } = { 3'b100, 3'b100 }; // prevprev1+prev1 + default: { xuse_s4, yuse_s4 } = 6'd0; + endcase + case( {s4_enters, s3_enters, s2_enters, s1_enters}) + 4'b1000: begin + {xuse_prevprev1, xuse_prev2, xuse_internal} = xuse_s4; + {yuse_prev1, yuse_prev2, yuse_internal } = yuse_s4; + end + 4'b0100: begin + {xuse_prevprev1, xuse_prev2, xuse_internal} = xuse_s3; + {yuse_prev1, yuse_prev2, yuse_internal } = yuse_s3; + end + 4'b0010: begin + {xuse_prevprev1, xuse_prev2, xuse_internal} = xuse_s2; + {yuse_prev1, yuse_prev2, yuse_internal } = yuse_s2; + end + 4'b0001: begin + {xuse_prevprev1, xuse_prev2, xuse_internal} = xuse_s1; + {yuse_prev1, yuse_prev2, yuse_internal } = yuse_s1; + end + default: begin + {xuse_prevprev1, xuse_prev2, xuse_internal} = 3'b0; + {yuse_prev1, yuse_prev2, yuse_internal } = 3'b0; + end + endcase + end + end +endgenerate + +// Control signals for simulation: should be 2'b0 or 2'b1 +// wire [1:0] xusage = xuse_prevprev1+xuse_prev2+xuse_internal; +// wire [1:0] yusage = yuse_prev1+yuse_internal; +// +// always @(xusage,yusage) +// if( xusage>2'b1 || yusage>2'b1 ) begin +// $display("ERROR: x/y over use in jt12_mod"); +// $finish; +// end + +endmodule diff --git a/common/Sound/JT12/hdl/jt12_op.v b/common/Sound/JT12/hdl/jt12_op.v new file mode 100644 index 00000000..43e14542 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_op.v @@ -0,0 +1,332 @@ +`timescale 1ns / 1ps + + +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots. + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 + +*/ + + +module jt12_op( + input rst, + input clk, + input clk_en /* synthesis direct_enable */, + input [9:0] pg_phase_VIII, + input [9:0] eg_atten_IX, // output from envelope generator + input [2:0] fb_II, // voice feedback + input xuse_prevprev1, + input xuse_prev2, + input xuse_internal, + input yuse_prev1, + input yuse_prev2, + input yuse_internal, + input test_214, + + input s1_enters, + input s2_enters, + input s3_enters, + input s4_enters, + input zero, + + output signed [ 8:0] op_result, + output signed [13:0] full_result +); + +parameter num_ch = 6; + +/* enters exits + S1 S2 + S3 S4 + S2 S1 + S4 S3 +*/ + +reg [13:0] op_result_internal, op_XII; +reg [11:0] atten_internal_IX; + +assign op_result = op_result_internal[13:5]; +assign full_result = op_result_internal; + +reg signbit_IX, signbit_X, signbit_XI; +reg [11:0] totalatten_X; + +wire [13:0] prev1, prevprev1, prev2; + +reg [13:0] prev1_din, prevprev1_din, prev2_din; + +always @(*) + if( num_ch==3 ) begin + prev1_din = s1_enters ? op_result_internal : prev1; + prevprev1_din = s3_enters ? op_result_internal : prevprev1; + prev2_din = s2_enters ? op_result_internal : prev2; + end else begin // 6 channels + prev1_din = s2_enters ? op_result_internal : prev1; + prevprev1_din = s2_enters ? prev1 : prevprev1; + prev2_din = s1_enters ? op_result_internal : prev2; + end + +jt12_sh #( .width(14), .stages(num_ch)) prev1_buffer( +// .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .din ( prev1_din ), + .drop ( prev1 ) +); + +jt12_sh #( .width(14), .stages(num_ch)) prevprev1_buffer( +// .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .din ( prevprev1_din ), + .drop ( prevprev1 ) +); + +jt12_sh #( .width(14), .stages(num_ch)) prev2_buffer( +// .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .din ( prev2_din ), + .drop ( prev2 ) +); + + +reg [10:0] subtresult; + +reg [12:0] shifter, shifter_2, shifter_3; + +// REGISTER/CYCLE 1 +// Creation of phase modulation (FM) feedback signal, before shifting +reg [13:0] x, y; +reg [14:0] xs, ys, pm_preshift_II; +reg s1_II; + +always @(*) begin + casez( {xuse_prevprev1, xuse_prev2, xuse_internal }) + 3'b1??: x = prevprev1; + 3'b01?: x = prev2; + 3'b001: x = op_result_internal; + default: x = 14'd0; + endcase + casez( {yuse_prev1, yuse_prev2, yuse_internal }) + 3'b1??: y = prev1; + 3'b01?: y = prev2; + 3'b001: y = op_result_internal; + default: y = 14'd0; + endcase + xs = { x[13], x }; // sign-extend + ys = { y[13], y }; // sign-extend +end + +always @(posedge clk) if( clk_en ) begin + pm_preshift_II <= xs + ys; // carry is discarded + s1_II <= s1_enters; +end + +/* REGISTER/CYCLE 2-7 (also YM2612 extra cycles 1-6) + Shifting of FM feedback signal, adding phase from PG to FM phase + In YM2203, phasemod_II is not registered at all, it is latched on the first edge + in add_pg_phase and the second edge is the output of add_pg_phase. In the YM2612, there + are 6 cycles worth of registers between the generated (non-registered) phasemod_II signal + and the input to add_pg_phase. */ + +reg [9:0] phasemod_II; +wire [9:0] phasemod_VIII; + +always @(*) begin + // Shift FM feedback signal + if (!s1_II ) // Not S1 + phasemod_II = pm_preshift_II[10:1]; // Bit 0 of pm_preshift_II is never used + else // S1 + case( fb_II ) + 3'd0: phasemod_II = 10'd0; + 3'd1: phasemod_II = { {4{pm_preshift_II[14]}}, pm_preshift_II[14:9] }; + 3'd2: phasemod_II = { {3{pm_preshift_II[14]}}, pm_preshift_II[14:8] }; + 3'd3: phasemod_II = { {2{pm_preshift_II[14]}}, pm_preshift_II[14:7] }; + 3'd4: phasemod_II = { pm_preshift_II[14], pm_preshift_II[14:6] }; + 3'd5: phasemod_II = pm_preshift_II[14:5]; + 3'd6: phasemod_II = pm_preshift_II[13:4]; + 3'd7: phasemod_II = pm_preshift_II[12:3]; + endcase +end + +// REGISTER/CYCLE 2-7 +//generate +// if( num_ch==6 ) + jt12_sh #( .width(10), .stages(6)) phasemod_sh( + .clk ( clk ), + .clk_en ( clk_en), + .din ( phasemod_II ), + .drop ( phasemod_VIII ) + ); +// else begin +// assign phasemod_VIII = phasemod_II; +// end +// endgenerate + +// REGISTER/CYCLE 8 +reg [ 9:0] phase; +// Sets the maximum number of fanouts for a register or combinational +// cell. The Quartus II software will replicate the cell and split +// the fanouts among the duplicates until the fanout of each cell +// is below the maximum. + +reg [ 7:0] aux_VIII; + +always @(*) begin + phase = phasemod_VIII + pg_phase_VIII; + aux_VIII= phase[7:0] ^ {8{~phase[8]}}; +end + +always @(posedge clk) if( clk_en ) begin + signbit_IX <= phase[9]; +end + +wire [11:0] logsin_IX; + +jt12_logsin u_logsin ( + .clk ( clk ), + .clk_en ( clk_en ), + .addr ( aux_VIII[7:0] ), + .logsin ( logsin_IX ) +); + + +// REGISTER/CYCLE 9 +// Sine table +// Main sine table body + +always @(*) begin + subtresult = eg_atten_IX + logsin_IX[11:2]; + atten_internal_IX = { subtresult[9:0], logsin_IX[1:0] } | {12{subtresult[10]}}; +end + +wire [9:0] mantissa_X; +reg [9:0] mantissa_XI; +reg [3:0] exponent_X, exponent_XI; + +jt12_exprom u_exprom( + .clk ( clk ), + .clk_en ( clk_en ), + .addr ( atten_internal_IX[7:0] ), + .exp ( mantissa_X ) +); + +always @(posedge clk) if( clk_en ) begin + exponent_X <= atten_internal_IX[11:8]; + signbit_X <= signbit_IX; +end + +always @(posedge clk) if( clk_en ) begin + mantissa_XI <= mantissa_X; + exponent_XI <= exponent_X; + signbit_XI <= signbit_X; +end + +// REGISTER/CYCLE 11 +// Introduce test bit as MSB, 2's complement & Carry-out discarded + +always @(*) begin + // Floating-point to integer, and incorporating sign bit + // Two-stage shifting of mantissa_XI by exponent_XI + shifter = { 3'b001, mantissa_XI }; + case( ~exponent_XI[1:0] ) + 2'b00: shifter_2 = { 1'b0, shifter[12:1] }; // LSB discarded + 2'b01: shifter_2 = shifter; + 2'b10: shifter_2 = { shifter[11:0], 1'b0 }; + 2'b11: shifter_2 = { shifter[10:0], 2'b0 }; + endcase + case( ~exponent_XI[3:2] ) + 2'b00: shifter_3 = {12'b0, shifter_2[12] }; + 2'b01: shifter_3 = { 8'b0, shifter_2[12:8] }; + 2'b10: shifter_3 = { 4'b0, shifter_2[12:4] }; + 2'b11: shifter_3 = shifter_2; + endcase +end + +always @(posedge clk) if( clk_en ) begin + // REGISTER CYCLE 11 + op_XII <= ({ test_214, shifter_3 } ^ {14{signbit_XI}}) + {13'd0,signbit_XI}; + // REGISTER CYCLE 12 + // Extra register, take output after here + 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 diff --git a/common/Sound/JT12/hdl/jt12_pcm.v b/common/Sound/JT12/hdl/jt12_pcm.v new file mode 100644 index 00000000..b0d04f53 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_pcm.v @@ -0,0 +1,109 @@ +module jt12_pcm( + input rst, + input clk, + input clk_en /* synthesis direct_enable */, + input zero, + input signed [8:0] pcm, + input pcm_wr, + output reg signed [8:0] pcm_resampled +); + +// reg [2:0] ratesel; +// reg [3:0] cnt8; +// reg wrcnt, wrclr; +reg last_zero; +wire zero_edge = !last_zero && zero; +/* +always @(posedge clk) + if(rst) begin + cnt8 <= 4'd0; + wrclr <= 1'd0; + ratesel <= 3'd1; + wrcnt <= 1'b0; + end else if(clk_en) begin + if( pcm_wr ) begin + if( wrcnt ) begin + // case( cnt8[3:2] ) + // 2'd3: ratesel <= 3'b111; // x8 + // 2'd2: ratesel <= 3'b011; // x4 + // 2'd1: ratesel <= 3'b001; // x2 + // 2'd0: ratesel <= 3'b000; // x1 + // endcase + cnt8 <= 4'd0; + wrcnt <= 1'b0; + end + else wrcnt <= 1'b1; + end else + if( cnt8!=4'hf && zero ) cnt8 <= cnt8 + 4'd1; + end +*/ +// up-rate PCM samples +reg rate1, rate2; //, rate4, rate8; +reg cen1, cen2; //, cen4, cen8; + +always @(posedge clk, posedge rst) + if(rst) + rate2 <= 1'b0; + else begin + last_zero <= zero; + rate1 <= zero_edge; + if(zero_edge) begin + rate2 <= ~rate2; +// if(rate2) begin +// rate4 <= ~rate4; +// if(rate4) rate8<=~rate8; +// end + end + end + +always @(posedge clk) begin + cen1 <= rate1; + cen2 <= rate1 && rate2; +// cen4 <= rate1 && rate2 && rate4; +// cen8 <= rate1 && rate2 && rate4 && rate8; +end + +wire signed [8:0] pcm3; //,pcm2, pcm1; + +//always @(posedge clk) if( clk_en ) +// pcm_resampled <= ratesel[0] ? pcm3 : pcm; +always @(*) + pcm_resampled = pcm3; + +// rate x2 +//wire signed [8:0] pcm_in2 = ratesel[1] ? pcm2 : pcm; +jt12_interpol #(.calcw(10),.inw(9),.rate(2),.m(1),.n(2)) +u_uprate_3( + .clk ( clk ), + .rst ( rst ), + .cen_in ( cen2 ), + .cen_out( cen1 ), + // .snd_in ( pcm_in2 ), + .snd_in ( pcm ), + .snd_out( pcm3 ) +); +/* +// rate x2 +wire signed [8:0] pcm_in1 = ratesel[2] ? pcm1 : pcm; +jt12_interpol #(.calcw(10),.inw(9),.rate(2),.m(1),.n(2)) +u_uprate_2( + .clk ( clk ), + .rst ( rst ), + .cen_in ( cen4 ), + .cen_out( cen2 ), + .snd_in ( pcm_in1 ), + .snd_out( pcm2 ) +); + +// rate x2 +jt12_interpol #(.calcw(10),.inw(9),.rate(2),.m(1),.n(2)) +u_uprate_1( + .clk ( clk ), + .rst ( rst ), + .cen_in ( cen8 ), + .cen_out( cen4 ), + .snd_in ( pcm ), + .snd_out( pcm1 ) +); +*/ +endmodule // jt12_pcm \ No newline at end of file diff --git a/common/Sound/JT12/hdl/jt12_pcm_interpol.v b/common/Sound/JT12/hdl/jt12_pcm_interpol.v new file mode 100644 index 00000000..14cb1ad5 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_pcm_interpol.v @@ -0,0 +1,109 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +module jt12_pcm_interpol +#(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 +); + +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; + +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; + +// latch new data and compute the two deltas : dx and dn, slope = dx/dn +always @(posedge clk) begin + last_pcm_wr <= pcm_wr; + start_div <= posedge_pcmwr; + + if( posedge_pcmwr ) begin + pre_dn <= 1; + 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]; + start_div <= 1; + end + + if( !pcm_wr && cen55 ) begin + if( pre_dn != {stepw{1'b1}} ) pre_dn <= pre_dn + 'd1; + end +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]; + + +always @(posedge clk) begin + if( negedge_pcmwr ) begin + pcminter <= pcmlast; + end else if(cen55 && !working && !pcm_wr) begin // only advance if the divider has finished + if( sign ) begin // subtract + if( next_down > pcmnew && !overflow_down ) + pcminter <= next_down; + else + pcminter <= pcmnew; // done + end + else begin // add + if( next_up < pcmnew && !overflow_up ) + pcminter <= next_up; + else + pcminter <= pcmnew; // done + end + end +end + +// output only at cen55 + +always @(posedge clk) if(cen55) pcmout <= pcminter; + +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 } ), + .d ( step ), + .r ( ), + .working( working ) +); + + +endmodule // jt10_adpcmb_interpol \ No newline at end of file diff --git a/common/Sound/JT12/hdl/jt12_pg.v b/common/Sound/JT12/hdl/jt12_pg.v new file mode 100644 index 00000000..b1e5128b --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_pg.v @@ -0,0 +1,114 @@ +/* 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 . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 14-2-2016 + + 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 + + */ + +`timescale 1ns / 1ps + +/* + + tab size 4 + +*/ + +module jt12_pg( + input clk, + input clk_en /* synthesis direct_enable */, + input rst, + // Channel frequency + input [10:0] fnum_I, + input [ 2:0] block_I, + // Operator multiplying + input [ 3:0] mul_II, + // Operator detuning + input [ 2:0] dt1_I, // same as JT51's DT1 + // phase modulation from LFO + input [ 6:0] lfo_mod, + input [ 2:0] pms_I, + // phase operation + input pg_rst_II, + input pg_stop, // not implemented + + output reg [ 4:0] keycode_II, + output [ 9:0] phase_VIII +); + +parameter num_ch=6; + +wire [4:0] keycode_I; +wire signed [5:0] detune_mod_I; +reg signed [5:0] detune_mod_II; +wire [16:0] phinc_I; +reg [16:0] phinc_II; +wire [19:0] phase_drop, phase_in; +wire [ 9:0] phase_II; + +always @(posedge clk) if(clk_en) begin + keycode_II <= keycode_I; + detune_mod_II <= detune_mod_I; + phinc_II <= phinc_I; +end + +jt12_pg_comb u_comb( + .block ( block_I ), + .fnum ( fnum_I ), + // Phase Modulation + .lfo_mod ( lfo_mod[6:2] ), + .pms ( pms_I ), + + // Detune + .detune ( dt1_I ), + .keycode ( keycode_I ), + .detune_out ( detune_mod_I ), + // Phase increment + .phinc_out ( phinc_I ), + // Phase add + .mul ( mul_II ), + .phase_in ( phase_drop ), + .pg_rst ( pg_rst_II ), + .detune_in ( detune_mod_II ), + .phinc_in ( phinc_II ), + + .phase_out ( phase_in ), + .phase_op ( phase_II ) +); + +jt12_sh_rst #( .width(20), .stages(4*num_ch) ) u_phsh( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( phase_in ), + .drop ( phase_drop) +); + +jt12_sh_rst #( .width(10), .stages(6) ) u_pad( + .clk ( clk ), + .clk_en ( clk_en ), + .rst ( rst ), + .din ( phase_II ), + .drop ( phase_VIII) +); + +endmodule + diff --git a/common/Sound/JT12/hdl/jt12_pg_comb.v b/common/Sound/JT12/hdl/jt12_pg_comb.v new file mode 100644 index 00000000..a8091d21 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_pg_comb.v @@ -0,0 +1,90 @@ +/* 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 . + + 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 + + 100% compared with Alexey Khokholov (Nuke.YKT) work with identical results. +*/ + +module jt12_pg_comb( + input [ 2:0] block, + input [10:0] fnum, + // Phase Modulation + input [ 4:0] lfo_mod, + input [ 2:0] pms, + // output [ 7:0] pm_out, + + // Detune + input [ 2:0] detune, + + output [ 4:0] keycode, + output signed [5:0] detune_out, + // Phase increment + output [16:0] phinc_out, + // Phase add + input [ 3:0] mul, + input [19:0] phase_in, + input pg_rst, + // input signed [7:0] pm_in, + input signed [5:0] detune_in, + input [16:0] phinc_in, + + output [19:0] phase_out, + output [ 9:0] phase_op +); + +wire signed [8:0] pm_offset; + +/* pm, pg_dt and pg_inc operate in parallel */ +jt12_pm u_pm( + .lfo_mod ( lfo_mod ), + .fnum ( fnum ), + .pms ( pms ), + .pm_offset ( pm_offset ) +); + +jt12_pg_dt u_dt( + .block ( block ), + .fnum ( fnum ), + .detune ( detune ), + .keycode ( keycode ), + .detune_signed( detune_out ) +); + +jt12_pg_inc u_inc( + .block ( block ), + .fnum ( fnum ), + .pm_offset ( pm_offset ), + .phinc_pure ( phinc_out ) +); + +// pg_sum uses the output from the previous blocks + +jt12_pg_sum u_sum( + .mul ( mul ), + .phase_in ( phase_in ), + .pg_rst ( pg_rst ), + .detune_signed ( detune_in ), + .phinc_pure ( phinc_in ), + .phase_out ( phase_out ), + .phase_op ( phase_op ) +); + +endmodule // jt12_pg_comb \ No newline at end of file diff --git a/common/Sound/JT12/hdl/jt12_pg_dt.v b/common/Sound/JT12/hdl/jt12_pg_dt.v new file mode 100644 index 00000000..9b9e0f31 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_pg_dt.v @@ -0,0 +1,82 @@ +/* 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 . + + 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 + + Note that detune produces an output even for fnum==0, is that correct? + + Based on jt51_phasegen.v, from JT51 + + */ + +module jt12_pg_dt( + input [ 2:0] block, + input [10:0] fnum, + input [ 2:0] detune, + + output reg [ 4:0] keycode, + output reg signed [5:0] detune_signed +); + +reg [5:0] detune_kf; +reg [4:0] pow2; +reg [5:0] detune_unlimited; +reg [4:0] detune_limit, detune_limited; + + +always @(*) begin + keycode = { block, fnum[10], fnum[10] ? (|fnum[9:7]) : (&fnum[9:7])}; + case( detune[1:0] ) + 2'd1: detune_kf = { 1'b0, keycode } - 6'd4; + 2'd2: detune_kf = { 1'b0, keycode } + 6'd4; + 2'd3: detune_kf = { 1'b0, keycode } + 6'd8; + default:detune_kf = { 1'b0, keycode }; + endcase + case( detune_kf[2:0] ) + 3'd0: pow2 = 5'd16; + 3'd1: pow2 = 5'd17; + 3'd2: pow2 = 5'd19; + 3'd3: pow2 = 5'd20; + 3'd4: pow2 = 5'd22; + 3'd5: pow2 = 5'd24; + 3'd6: pow2 = 5'd26; + 3'd7: pow2 = 5'd29; + endcase + case( detune[1:0] ) + 2'd0: detune_limit = 5'd0; + 2'd1: detune_limit = 5'd8; + 2'd2: detune_limit = 5'd16; + 2'd3: detune_limit = 5'd22; + endcase + case( detune_kf[5:3] ) + 3'd0: detune_unlimited = { 5'd0, pow2[4] }; // <2 + 3'd1: detune_unlimited = { 4'd0, pow2[4:3] }; // <4 + 3'd2: detune_unlimited = { 3'd0, pow2[4:2] }; // <8 + 3'd3: detune_unlimited = { 2'd0, pow2[4:1] }; + 3'd4: detune_unlimited = { 1'd0, pow2[4:0] }; + 3'd5: detune_unlimited = { pow2[4:0], 1'd0 }; + default:detune_unlimited = 6'd0; + endcase + detune_limited = detune_unlimited > {1'b0, detune_limit} ? + detune_limit : detune_unlimited[4:0]; + detune_signed = !detune[2] ? {1'b0,detune_limited} : (~{1'b0,detune_limited}+6'd1); +end + +endmodule diff --git a/common/Sound/JT12/hdl/jt12_pg_inc.v b/common/Sound/JT12/hdl/jt12_pg_inc.v new file mode 100644 index 00000000..bee1c8db --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_pg_inc.v @@ -0,0 +1,50 @@ +/* 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 . + + 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 + + */ + +module jt12_pg_inc ( + input [ 2:0] block, + input [10:0] fnum, + input signed [8:0] pm_offset, + output reg [16:0] phinc_pure +); + +reg [11:0] fnum_mod; + +always @(*) begin + fnum_mod = {fnum,1'b0} + {{3{pm_offset[8]}},pm_offset}; + case ( block ) + 3'd0: phinc_pure = { 7'd0, fnum_mod[11:2] }; + 3'd1: phinc_pure = { 6'd0, fnum_mod[11:1] }; + 3'd2: phinc_pure = { 5'd0, fnum_mod[11:0] }; + 3'd3: phinc_pure = { 4'd0, fnum_mod, 1'd0 }; + 3'd4: phinc_pure = { 3'd0, fnum_mod, 2'd0 }; + 3'd5: phinc_pure = { 2'd0, fnum_mod, 3'd0 }; + 3'd6: phinc_pure = { 1'd0, fnum_mod, 4'd0 }; + 3'd7: phinc_pure = { fnum_mod, 5'd0 }; + endcase +end + +endmodule // jt12_pg_inc \ No newline at end of file diff --git a/common/Sound/JT12/hdl/jt12_pg_sum.v b/common/Sound/JT12/hdl/jt12_pg_sum.v new file mode 100644 index 00000000..6369c53a --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_pg_sum.v @@ -0,0 +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 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 . + + 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 + + */ + +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, + + 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]; +end + +endmodule // jt12_pg_sum \ No newline at end of file diff --git a/common/Sound/JT12/hdl/jt12_pm.v b/common/Sound/JT12/hdl/jt12_pm.v new file mode 100644 index 00000000..89179210 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_pm.v @@ -0,0 +1,186 @@ +/* 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 . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 14-10-2018 + */ + +`timescale 1ns / 1ps + +// This implementation follows that of Alexey Khokholov (Nuke.YKT) in C language. + +module jt12_pm ( + input [4:0] lfo_mod, + input [10:0] fnum, + input [2:0] pms, + output reg signed [8:0] pm_offset +); + + +reg [7:0] pm_unsigned; +reg [7:0] pm_base; +reg [9:0] pm_shifted; + +wire [2:0] index = lfo_mod[3] ? (~lfo_mod[2:0]) : lfo_mod[2:0]; + +reg [2:0] lfo_sh1_lut [0:63]; +reg [2:0] lfo_sh2_lut [0:63]; +reg [2:0] lfo_sh1, lfo_sh2; + +initial begin + lfo_sh1_lut[6'h00] = 3'd7; + lfo_sh1_lut[6'h01] = 3'd7; + lfo_sh1_lut[6'h02] = 3'd7; + lfo_sh1_lut[6'h03] = 3'd7; + lfo_sh1_lut[6'h04] = 3'd7; + lfo_sh1_lut[6'h05] = 3'd7; + lfo_sh1_lut[6'h06] = 3'd7; + lfo_sh1_lut[6'h07] = 3'd7; + lfo_sh1_lut[6'h08] = 3'd7; + lfo_sh1_lut[6'h09] = 3'd7; + lfo_sh1_lut[6'h0A] = 3'd7; + lfo_sh1_lut[6'h0B] = 3'd7; + lfo_sh1_lut[6'h0C] = 3'd7; + lfo_sh1_lut[6'h0D] = 3'd7; + lfo_sh1_lut[6'h0E] = 3'd7; + lfo_sh1_lut[6'h0F] = 3'd7; + lfo_sh1_lut[6'h10] = 3'd7; + lfo_sh1_lut[6'h11] = 3'd7; + lfo_sh1_lut[6'h12] = 3'd7; + lfo_sh1_lut[6'h13] = 3'd7; + lfo_sh1_lut[6'h14] = 3'd7; + lfo_sh1_lut[6'h15] = 3'd7; + lfo_sh1_lut[6'h16] = 3'd1; + lfo_sh1_lut[6'h17] = 3'd1; + lfo_sh1_lut[6'h18] = 3'd7; + lfo_sh1_lut[6'h19] = 3'd7; + lfo_sh1_lut[6'h1A] = 3'd7; + lfo_sh1_lut[6'h1B] = 3'd7; + lfo_sh1_lut[6'h1C] = 3'd1; + lfo_sh1_lut[6'h1D] = 3'd1; + lfo_sh1_lut[6'h1E] = 3'd1; + lfo_sh1_lut[6'h1F] = 3'd1; + lfo_sh1_lut[6'h20] = 3'd7; + lfo_sh1_lut[6'h21] = 3'd7; + lfo_sh1_lut[6'h22] = 3'd7; + lfo_sh1_lut[6'h23] = 3'd1; + lfo_sh1_lut[6'h24] = 3'd1; + lfo_sh1_lut[6'h25] = 3'd1; + lfo_sh1_lut[6'h26] = 3'd1; + lfo_sh1_lut[6'h27] = 3'd0; + lfo_sh1_lut[6'h28] = 3'd7; + lfo_sh1_lut[6'h29] = 3'd7; + lfo_sh1_lut[6'h2A] = 3'd1; + lfo_sh1_lut[6'h2B] = 3'd1; + lfo_sh1_lut[6'h2C] = 3'd0; + lfo_sh1_lut[6'h2D] = 3'd0; + lfo_sh1_lut[6'h2E] = 3'd0; + lfo_sh1_lut[6'h2F] = 3'd0; + lfo_sh1_lut[6'h30] = 3'd7; + lfo_sh1_lut[6'h31] = 3'd7; + lfo_sh1_lut[6'h32] = 3'd1; + lfo_sh1_lut[6'h33] = 3'd1; + lfo_sh1_lut[6'h34] = 3'd0; + lfo_sh1_lut[6'h35] = 3'd0; + lfo_sh1_lut[6'h36] = 3'd0; + lfo_sh1_lut[6'h37] = 3'd0; + lfo_sh1_lut[6'h38] = 3'd7; + lfo_sh1_lut[6'h39] = 3'd7; + lfo_sh1_lut[6'h3A] = 3'd1; + lfo_sh1_lut[6'h3B] = 3'd1; + lfo_sh1_lut[6'h3C] = 3'd0; + lfo_sh1_lut[6'h3D] = 3'd0; + lfo_sh1_lut[6'h3E] = 3'd0; + lfo_sh1_lut[6'h3F] = 3'd0; + lfo_sh2_lut[6'h00] = 3'd7; + lfo_sh2_lut[6'h01] = 3'd7; + lfo_sh2_lut[6'h02] = 3'd7; + lfo_sh2_lut[6'h03] = 3'd7; + lfo_sh2_lut[6'h04] = 3'd7; + lfo_sh2_lut[6'h05] = 3'd7; + lfo_sh2_lut[6'h06] = 3'd7; + lfo_sh2_lut[6'h07] = 3'd7; + lfo_sh2_lut[6'h08] = 3'd7; + lfo_sh2_lut[6'h09] = 3'd7; + lfo_sh2_lut[6'h0A] = 3'd7; + lfo_sh2_lut[6'h0B] = 3'd7; + lfo_sh2_lut[6'h0C] = 3'd2; + lfo_sh2_lut[6'h0D] = 3'd2; + lfo_sh2_lut[6'h0E] = 3'd2; + lfo_sh2_lut[6'h0F] = 3'd2; + lfo_sh2_lut[6'h10] = 3'd7; + lfo_sh2_lut[6'h11] = 3'd7; + lfo_sh2_lut[6'h12] = 3'd7; + lfo_sh2_lut[6'h13] = 3'd2; + lfo_sh2_lut[6'h14] = 3'd2; + lfo_sh2_lut[6'h15] = 3'd2; + lfo_sh2_lut[6'h16] = 3'd7; + lfo_sh2_lut[6'h17] = 3'd7; + lfo_sh2_lut[6'h18] = 3'd7; + lfo_sh2_lut[6'h19] = 3'd7; + lfo_sh2_lut[6'h1A] = 3'd2; + lfo_sh2_lut[6'h1B] = 3'd2; + lfo_sh2_lut[6'h1C] = 3'd7; + lfo_sh2_lut[6'h1D] = 3'd7; + lfo_sh2_lut[6'h1E] = 3'd2; + lfo_sh2_lut[6'h1F] = 3'd2; + lfo_sh2_lut[6'h20] = 3'd7; + lfo_sh2_lut[6'h21] = 3'd7; + lfo_sh2_lut[6'h22] = 3'd2; + lfo_sh2_lut[6'h23] = 3'd7; + lfo_sh2_lut[6'h24] = 3'd7; + lfo_sh2_lut[6'h25] = 3'd7; + lfo_sh2_lut[6'h26] = 3'd2; + lfo_sh2_lut[6'h27] = 3'd7; + lfo_sh2_lut[6'h28] = 3'd7; + lfo_sh2_lut[6'h29] = 3'd7; + lfo_sh2_lut[6'h2A] = 3'd7; + lfo_sh2_lut[6'h2B] = 3'd2; + lfo_sh2_lut[6'h2C] = 3'd7; + lfo_sh2_lut[6'h2D] = 3'd7; + lfo_sh2_lut[6'h2E] = 3'd2; + lfo_sh2_lut[6'h2F] = 3'd1; + lfo_sh2_lut[6'h30] = 3'd7; + lfo_sh2_lut[6'h31] = 3'd7; + lfo_sh2_lut[6'h32] = 3'd7; + lfo_sh2_lut[6'h33] = 3'd2; + lfo_sh2_lut[6'h34] = 3'd7; + lfo_sh2_lut[6'h35] = 3'd7; + lfo_sh2_lut[6'h36] = 3'd2; + lfo_sh2_lut[6'h37] = 3'd1; + lfo_sh2_lut[6'h38] = 3'd7; + lfo_sh2_lut[6'h39] = 3'd7; + lfo_sh2_lut[6'h3A] = 3'd7; + lfo_sh2_lut[6'h3B] = 3'd2; + lfo_sh2_lut[6'h3C] = 3'd7; + lfo_sh2_lut[6'h3D] = 3'd7; + lfo_sh2_lut[6'h3E] = 3'd2; + lfo_sh2_lut[6'h3F] = 3'd1; +end + +always @(*) begin + lfo_sh1 = lfo_sh1_lut[{pms,index}]; + lfo_sh2 = lfo_sh2_lut[{pms,index}]; + pm_base = ({1'b0,fnum[10:4]}>>lfo_sh1) + ({1'b0,fnum[10:4]}>>lfo_sh2); + case( pms ) + default: pm_shifted = { 2'b0, pm_base }; + 3'd6: pm_shifted = { 1'b0, pm_base, 1'b0 }; + 3'd7: pm_shifted = { pm_base, 2'b0 }; + endcase // pms + pm_offset = lfo_mod[4] ? (-{1'b0,pm_shifted[9:2]}) : {1'b0,pm_shifted[9:2]}; +end // always @(*) + +endmodule diff --git a/common/Sound/JT12/hdl/jt12_reg.v b/common/Sound/JT12/hdl/jt12_reg.v new file mode 100644 index 00000000..89b2017c --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_reg.v @@ -0,0 +1,372 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 14-2-2017 + +*/ + +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, + + input csm, + input flag_A, + input overflow_A, + + input up_keyon, + input up_alg, + input up_fnumlo, + 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, + + output reg ch6op, // 1 when the operator belongs to CH6 + output reg [2:0] cur_ch, + output reg [1:0] cur_op, + + // CH3 Effect-mode operation + input effect, + input [10:0] fnum_ch3op2, + input [10:0] fnum_ch3op3, + input [10:0] fnum_ch3op1, + input [ 2:0] block_ch3op2, + input [ 2:0] block_ch3op3, + input [ 2:0] block_ch3op1, + input [ 5:0] latch_fnum, + // Pipeline order + output reg zero, + output s1_enters, + output s2_enters, + output s3_enters, + output s4_enters, + + // Operator + output xuse_prevprev1, + output xuse_internal, + output yuse_internal, + output xuse_prev2, + output yuse_prev1, + output yuse_prev2, + + // PG + output [10:0] fnum_I, + output [ 2:0] block_I, + // channel configuration + output [1:0] rl, + output reg [2:0] fb_II, + output [2:0] alg_I, + // Operator multiplying + output [ 3:0] mul_II, + // Operator detuning + output [ 2:0] dt1_I, + + // EG + output [4:0] ar_I, // attack rate + output [4:0] d1r_I, // decay rate + output [4:0] d2r_I, // sustain rate + output [3:0] rr_I, // release rate + output [3:0] sl_I, // sustain level + output [1:0] ks_II, // key scale + output ssg_en_I, + output [2:0] ssg_eg_I, + output [6:0] tl_IV, + output [2:0] pms_I, + output [1:0] ams_IV, + output amsen_IV, + + // envelope operation + output keyon_I +); + +parameter num_ch=6; // Use only 3 (YM2203/YM2610) or 6 (YM2612/YM2608) + + +reg [1:0] next_op; +reg [2:0] next_ch; +reg last; + +`ifdef SIMULATION +// These signals need to operate during rst +// initial state is not relevant (or critical) in real life +// but we need a clear value during simulation +// This does not work with NCVERILOG +initial begin + cur_op = 2'd0; + cur_ch = 3'd0; + next_op = 2'd0; + next_ch = 3'd1; + last = 1'b0; + zero = 1'b1; +end +`endif + +assign s1_enters = cur_op == 2'b00; +assign s3_enters = cur_op == 2'b01; +assign s2_enters = cur_op == 2'b10; +assign s4_enters = cur_op == 2'b11; + +wire [4:0] next = { next_op, next_ch }; +wire [4:0] cur = { cur_op, cur_ch }; + +wire [2:0] fb_I; + +always @(posedge clk) if( clk_en ) begin + fb_II <= fb_I; + ch6op <= next_ch==3'd6; +end + +// FNUM and BLOCK +wire [10:0] fnum_I_raw; +wire [ 2:0] block_I_raw; +wire effect_on = effect && (cur_ch==3'd2); +wire effect_on_s1 = effect_on && (cur_op == 2'd0 ); +wire effect_on_s3 = effect_on && (cur_op == 2'd1 ); +wire effect_on_s2 = effect_on && (cur_op == 2'd2 ); +wire noeffect = ~|{effect_on_s1, effect_on_s3, effect_on_s2}; +assign fnum_I = ( {11{effect_on_s1}} & fnum_ch3op1 ) | + ( {11{effect_on_s2}} & fnum_ch3op2 ) | + ( {11{effect_on_s3}} & fnum_ch3op3 ) | + ( {11{noeffect}} & fnum_I_raw ); + +assign block_I =( {3{effect_on_s1}} & block_ch3op1 ) | + ( {3{effect_on_s2}} & block_ch3op2 ) | + ( {3{effect_on_s3}} & block_ch3op3 ) | + ( {3{noeffect}} & block_I_raw ); + +wire [4:0] req_opch_I = { op, ch }; +wire [4:0] req_opch_II, req_opch_III, + req_opch_IV, req_opch_V; //, req_opch_VI; + +jt12_sumch #(.num_ch(num_ch)) u_opch_II ( .chin(req_opch_I ), .chout(req_opch_II ) ); +jt12_sumch #(.num_ch(num_ch)) u_opch_III( .chin(req_opch_II ), .chout(req_opch_III) ); +jt12_sumch #(.num_ch(num_ch)) u_opch_IV ( .chin(req_opch_III), .chout(req_opch_IV ) ); +jt12_sumch #(.num_ch(num_ch)) u_opch_V ( .chin(req_opch_IV ), .chout(req_opch_V ) ); +// jt12_sumch #(.num_ch(num_ch)) u_opch_VI ( .chin(req_opch_V ), .chout(req_opch_VI) ); + +wire update_op_I = cur == req_opch_I; +wire update_op_II = cur == req_opch_II; +// wire update_op_III= cur == req_opch_III; +wire update_op_IV = cur == req_opch_IV; +// wire update_op_V = cur == req_opch_V; +// wire update_op_VI = cur == opch_VI; +// wire [2:0] op_plus1 = op+2'd1; +// wire update_op_VII= cur == { op_plus1[1:0], ch }; + +// 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; + if( num_ch==6 ) begin + next_op = cur_ch==3'd6 ? cur_op+1'b1 : cur_op; + next_ch = cur_ch[1:0]==2'b10 ? cur_ch+2'd2 : cur_ch+1'd1; + end else begin // 3 channels + next_op = cur_ch==3'd2 ? cur_op+1'b1 : cur_op; + next_ch = cur_ch[1:0]==2'b10 ? 3'd0 : cur_ch+1'd1; + end +end + +always @(posedge clk) begin : up_counter + if( clk_en ) begin + { cur_op, cur_ch } <= { next_op, next_ch }; + zero <= next == 5'd0; + end +end + +`ifndef NOFM +jt12_kon #(.num_ch(num_ch)) u_kon( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .keyon_op ( keyon_op ), + .keyon_ch ( keyon_ch ), + .next_op ( next_op ), + .next_ch ( next_ch ), + .up_keyon ( up_keyon ), + .csm ( csm ), + // .flag_A ( flag_A ), + .overflow_A ( overflow_A), + + .keyon_I ( keyon_I ) +); + +jt12_mod #(.num_ch(num_ch)) u_mod( + .alg_I ( alg_I ), + .s1_enters ( s1_enters ), + .s3_enters ( s3_enters ), + .s2_enters ( s2_enters ), + .s4_enters ( s4_enters ), + + .xuse_prevprev1 ( xuse_prevprev1 ), + .xuse_internal ( xuse_internal ), + .yuse_internal ( yuse_internal ), + .xuse_prev2 ( xuse_prev2 ), + .yuse_prev1 ( yuse_prev1 ), + .yuse_prev2 ( yuse_prev2 ) +); + +wire [43:0] shift_out; + +generate + if( num_ch==6 ) begin + // YM2612 / YM3438: Two CSR. + wire [43:0] shift_middle; + + jt12_csr u_csr0( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .din ( din ), + .shift_in ( shift_out ), + .shift_out ( shift_middle ), + .up_tl ( up_tl ), + .up_dt1 ( up_dt1 ), + .up_ks_ar ( up_ks_ar ), + .up_amen_dr ( up_amen_dr ), + .up_sr ( up_sr ), + .up_sl_rr ( up_sl_rr ), + .up_ssgeg ( up_ssgeg ), + .update_op_I ( update_op_I ), + .update_op_II ( update_op_II ), + .update_op_IV ( update_op_IV ) + ); + + wire up_midop_I = { ~cur[4], cur[3:0] } == req_opch_I; + wire up_midop_II = { ~cur[4], cur[3:0] } == req_opch_II; + wire up_midop_IV = { ~cur[4], cur[3:0] } == req_opch_IV; + + jt12_csr u_csr1( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .din ( din ), + .shift_in ( shift_middle ), + .shift_out ( shift_out ), + .up_tl ( up_tl ), + .up_dt1 ( up_dt1 ), + .up_ks_ar ( up_ks_ar ), + .up_amen_dr ( up_amen_dr ), + .up_sr ( up_sr ), + .up_sl_rr ( up_sl_rr ), + .up_ssgeg ( up_ssgeg ), + // update in the middle: + .update_op_I ( up_midop_I ), + .update_op_II ( up_midop_II ), + .update_op_IV ( up_midop_IV ) + ); + end + else begin // YM2203 only has one CSR + jt12_csr u_csr0( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .din ( din ), + .shift_in ( shift_out ), + .shift_out ( shift_out ), + .up_tl ( up_tl ), + .up_dt1 ( up_dt1 ), + .up_ks_ar ( up_ks_ar ), + .up_amen_dr ( up_amen_dr ), + .up_sr ( up_sr ), + .up_sl_rr ( up_sl_rr ), + .up_ssgeg ( up_ssgeg ), + .update_op_I ( update_op_I ), + .update_op_II ( update_op_II ), + .update_op_IV ( update_op_IV ) + ); + end // else +endgenerate + +assign { tl_IV, dt1_I, mul_II, ks_II, + ar_I, amsen_IV, d1r_I, d2r_I, + sl_I, rr_I, ssg_en_I, ssg_eg_I } = shift_out; + + +// 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 +}; + +assign { block_I_raw, fnum_I_raw, + fb_I, alg_I, ams_IV, pms_I } = regch_out; + +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 ) +); + +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 diff --git a/common/Sound/JT12/hdl/jt12_rst.v b/common/Sound/JT12/hdl/jt12_rst.v new file mode 100644 index 00000000..01756580 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_rst.v @@ -0,0 +1,38 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 21-03-2019 +*/ + +module jt12_rst( + input rst, + input clk, + output reg rst_n +); + +reg r; + +always @(negedge clk) + if( rst ) begin + r <= 1'b0; + rst_n <= 1'b0; + end else begin + { rst_n, r } <= { r, 1'b1 }; + end + +endmodule // jt12_rst \ No newline at end of file diff --git a/common/Sound/JT12/hdl/jt12_sh.v b/common/Sound/JT12/hdl/jt12_sh.v new file mode 100644 index 00000000..5578f106 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_sh.v @@ -0,0 +1,44 @@ +/* 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 . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 1-31-2017 + */ + +`timescale 1ns / 1ps + +// stages must be greater than 2 +module jt12_sh #(parameter width=5, stages=24 ) +( + input clk, + input clk_en /* synthesis direct_enable */, + input [width-1:0] din, + output [width-1:0] drop +); + +reg [stages-1:0] bits[width-1:0]; + +genvar i; +generate + for (i=0; i < width; i=i+1) begin: bit_shifter + always @(posedge clk) if(clk_en) begin + bits[i] <= {bits[i][stages-2:0], din[i]}; + end + assign drop[i] = bits[i][stages-1]; + end +endgenerate + +endmodule diff --git a/common/Sound/JT12/hdl/jt12_sh24.v b/common/Sound/JT12/hdl/jt12_sh24.v new file mode 100644 index 00000000..feb0cfa9 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_sh24.v @@ -0,0 +1,81 @@ +/* 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 . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 1-31-2017 + */ + +`timescale 1ns / 1ps + +module jt12_sh24 #(parameter width=5 ) +( + input clk, + input clk_en /* synthesis direct_enable */, + input [width-1:0] din, + output reg [width-1:0] st1, + output reg [width-1:0] st2, + output reg [width-1:0] st3, + output reg [width-1:0] st4, + output reg [width-1:0] st5, + output reg [width-1:0] st6, + output reg [width-1:0] st7, + output reg [width-1:0] st8, + output reg [width-1:0] st9, + output reg [width-1:0] st10, + output reg [width-1:0] st11, + output reg [width-1:0] st12, + output reg [width-1:0] st13, + output reg [width-1:0] st14, + output reg [width-1:0] st15, + output reg [width-1:0] st16, + output reg [width-1:0] st17, + output reg [width-1:0] st18, + output reg [width-1:0] st19, + output reg [width-1:0] st20, + output reg [width-1:0] st21, + output reg [width-1:0] st22, + output reg [width-1:0] st23, + output reg [width-1:0] st24 +); + +always @(posedge clk) if(clk_en) begin + st24<= st23; + st23<= st22; + st22<= st21; + st21<= st20; + st20<= st19; + st19<= st18; + st18<= st17; + st17<= st16; + st16<= st15; + st15<= st14; + st14<= st13; + st13<= st12; + st12<= st11; + st11<= st10; + st10<= st9; + st9 <= st8; + st8 <= st7; + st7 <= st6; + st6 <= st5; + st5 <= st4; + st4 <= st3; + st3 <= st2; + st2 <= st1; + st1 <= din; +end + +endmodule diff --git a/common/Sound/JT12/hdl/jt12_sh_rst.v b/common/Sound/JT12/hdl/jt12_sh_rst.v new file mode 100644 index 00000000..d50302e9 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_sh_rst.v @@ -0,0 +1,56 @@ +/* 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 . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + 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 ) +( + input rst, + input clk, + input clk_en /* synthesis direct_enable */, + input [width-1:0] din, + output [width-1:0] drop +); + +reg [stages-1:0] bits[width-1:0]; + +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, posedge rst) + if( rst ) begin + bits[i] <= {stages{rstval}}; + end else if(clk_en) begin + bits[i] <= {bits[i][stages-2:0], din[i]}; + end + assign drop[i] = bits[i][stages-1]; + end +endgenerate + +endmodule diff --git a/common/Sound/JT12/hdl/jt12_single_acc.v b/common/Sound/JT12/hdl/jt12_single_acc.v new file mode 100644 index 00000000..411adc2a --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_single_acc.v @@ -0,0 +1,63 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 27-1-2017 + +*/ + +// 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 + wout=16 // output data width +)( + input clk, + input clk_en /* synthesis direct_enable */, + input [win-1:0] op_result, + input sum_en, + input zero, + output reg [wout-1:0] snd +); + +// for full resolution use win=14, wout=16 +// for cut down resolution use win=9, wout=12 +// wout-win should be > 0 + +reg signed [wout-1:0] next, acc, current; +reg overflow; + +wire [wout-1:0] plus_inf = { 1'b0, {(wout-1){1'b1}} }; // maximum positive value +wire [wout-1:0] minus_inf = { 1'b1, {(wout-1){1'b0}} }; // minimum negative value + +always @(*) begin + current = sum_en ? { {(wout-win){op_result[win-1]}}, op_result } : {wout{1'b0}}; + next = zero ? current : current + acc; + overflow = !zero && + (current[wout-1] == acc[wout-1]) && + (acc[wout-1]!=next[wout-1]); +end + +always @(posedge clk) if( clk_en ) begin + acc <= overflow ? (acc[wout-1] ? minus_inf : plus_inf) : next; + if(zero) snd <= acc; +end + +endmodule // jt12_single_acc \ No newline at end of file diff --git a/common/Sound/JT12/hdl/jt12_sumch.v b/common/Sound/JT12/hdl/jt12_sumch.v new file mode 100644 index 00000000..75b1d4f5 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_sumch.v @@ -0,0 +1,47 @@ +/* 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 . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + 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 */ + +module jt12_sumch +( + input [4:0] chin, + output reg [4:0] chout +); + +parameter num_ch=6; + +reg [2:0] aux; + +always @(*) begin + aux = chin[2:0] + 3'd1; + if( num_ch==6 ) begin + chout[2:0] = aux[1:0]==2'b11 ? aux+3'd1 : aux; + chout[4:3] = chin[2:0]==3'd6 ? chin[4:3]+2'd1 : chin[4:3]; // next operator + end else begin // 3 channels + chout[2:0] = aux[1:0]==2'b11 ? 3'd0 : aux; + chout[4:3] = chin[2:0]==3'd2 ? chin[4:3]+2'd1 : chin[4:3]; // next operator + end +end + +endmodule diff --git a/common/Sound/JT12/hdl/jt12_timers.v b/common/Sound/JT12/hdl/jt12_timers.v new file mode 100644 index 00000000..fb5668d1 --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_timers.v @@ -0,0 +1,141 @@ +/* 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 . + + 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 + */ + +`timescale 1ns / 1ps + +module jt12_timers( + 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) ); + +/* +reg zero2; + +always @(posedge clk, posedge rst) begin + if( rst ) + zero2 <= 0; + else if(clk_en) begin + if( zero ) zero2 <= ~zero; + end +end + +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 +); + +reg last_load; +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(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) if(cen && zero) begin : counter + last_load <= load; + if( (load && !last_load) || overflow ) begin + cnt <= start_value; + end + else if( last_load ) cnt <= next; +end + +// Free running counter +always @(posedge clk) begin + if( rst ) begin + free_cnt <= {FW{1'b0}}; + end else if( cen&&zero ) begin + free_cnt <= free_cnt+1'd1; + end +end + +endmodule diff --git a/common/Sound/JT12/hdl/jt12_top.v b/common/Sound/JT12/hdl/jt12_top.v new file mode 100644 index 00000000..32fb84cb --- /dev/null +++ b/common/Sound/JT12/hdl/jt12_top.v @@ -0,0 +1,671 @@ +/* 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 . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 14-2-2016 + + 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 + + */ + +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 + input [7:0] din, + input [1:0] addr, + input cs_n, + input wr_n, + + output [7:0] dout, + output irq_n, + // Configuration + input en_hifi_pcm, // high to enable PCM interpolation on YM2612 mode + // ADPCM pins + output [19:0] adpcma_addr, // real hardware has 10 pins multiplexed through RMPX pin + output [ 3:0] adpcma_bank, + output adpcma_roe_n, // ADPCM-A ROM output enable + input [ 7:0] adpcma_data, // Data from RAM + 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, + // Separated output + output [ 7:0] psg_A, + output [ 7:0] psg_B, + output [ 7:0] psg_C, + output signed [15:0] fm_snd_left, + output signed [15:0] fm_snd_right, + output signed [15:0] adpcmA_l, + output signed [15:0] adpcmA_r, + output signed [15:0] adpcmB_l, + output signed [15:0] adpcmB_r, + // combined output + output [ 9:0] psg_snd, + output signed [15:0] snd_right, // FM+PSG + output signed [15:0] snd_left, // FM+PSG + output snd_sample +); + +// 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; +parameter JT49_DIV=2; + +wire flag_A, flag_B, busy; + +wire write = !cs_n && !wr_n; +wire clk_en, clk_en_ssg; + +// Timers +wire [9:0] value_A; +wire [7:0] value_B; +wire load_A, load_B; +wire enable_irq_A, enable_irq_B; +wire clr_flag_A, clr_flag_B; +wire overflow_A; +wire fast_timers; + +wire zero; // Single-clock pulse at the begginig of s1_enters +// LFO +wire [2:0] lfo_freq; +wire lfo_en; +// Operators +wire amsen_IV; +wire [ 2:0] dt1_I; +wire [ 3:0] mul_II; +wire [ 6:0] tl_IV; + +wire [ 4:0] keycode_II; +wire [ 4:0] ar_I; +wire [ 4:0] d1r_I; +wire [ 4:0] d2r_I; +wire [ 3:0] rr_I; +wire [ 3:0] sl_I; +wire [ 1:0] ks_II; +// SSG operation +wire ssg_en_I; +wire [2:0] ssg_eg_I; +// envelope operation +wire keyon_I; +wire [9:0] eg_IX; +wire pg_rst_II; +// Channel +wire [10:0] fnum_I; +wire [ 2:0] block_I; +wire [ 1:0] rl; +wire [ 2:0] fb_II; +wire [ 2:0] alg_I; +wire [ 2:0] pms_I; +wire [ 1:0] ams_IV; +// PCM +wire pcm_en, pcm_wr; +wire [ 8:0] pcm; +// Test +wire pg_stop, eg_stop; + +wire ch6op; +wire [ 2:0] cur_ch; +wire [ 1:0] cur_op; + +// Operator +wire xuse_internal, yuse_internal; +wire xuse_prevprev1, xuse_prev2, yuse_prev1, yuse_prev2; +wire [ 9:0] phase_VIII; +wire s1_enters, s2_enters, s3_enters, s4_enters; +wire rst_int; +// LFO +wire [6:0] lfo_mod; +wire lfo_rst; +// PSG +wire [3:0] psg_addr; +wire [7:0] psg_data, psg_dout; +wire psg_wr_n; +// ADPCM-A +wire [15:0] addr_a; +wire [ 2:0] up_addr, up_lracl; +wire up_start, up_end; +wire [ 7:0] aon_a, lracl; +wire [ 5:0] atl_a; // ADPCM Total Level +wire up_aon; +// APDCM-B +wire acmd_on_b; // Control - Process start, Key On +wire acmd_rep_b; // Control - Repeat +wire acmd_rst_b; // Control - Reset +wire acmd_up_b; // Control - New cmd received +wire [ 1:0] alr_b; // Left / Right +wire [15:0] astart_b; // Start address +wire [15:0] aend_b; // End address +wire [15:0] adeltan_b; // Delta-N +wire [ 7:0] aeg_b; // Envelope Generator Control +wire [ 5:0] adpcma_flags; // ADPMC-A read over flags +wire adpcmb_flag; +wire [ 6:0] flag_ctl; + + +wire clk_en_2, clk_en_666, clk_en_111, clk_en_55; + +generate +if( use_adpcm==1 ) begin: gen_adpcm + wire rst_n; + + jt12_rst u_rst( + .rst ( rst ), + .clk ( clk ), + .rst_n ( rst_n ) + ); + + jt10_adpcm_drvA u_adpcm_a( + .rst_n ( rst_n ), + .clk ( clk ), + .cen ( cen ), + .cen6 ( clk_en_666 ), // clk & cen must be 666 kHz + .cen1 ( clk_en_111 ), // clk & cen must be 111 kHz + + .addr ( adpcma_addr ), // real hardware has 10 pins multiplexed through RMPX pin + .bank ( adpcma_bank ), + .roe_n ( adpcma_roe_n ), // ADPCM-A ROM output enable + .datain ( adpcma_data ), + + // Control Registers + .atl ( atl_a ), // ADPCM Total Level + .addr_in ( addr_a ), + .lracl_in ( lracl ), + .up_start ( up_start ), + .up_end ( up_end ), + .up_addr ( up_addr ), + .up_lracl ( up_lracl ), + + .aon_cmd ( aon_a ), // ADPCM ON equivalent to key on for FM + .up_aon ( up_aon ), + // Flags + .flags ( adpcma_flags ), + .clr_flags ( flag_ctl[5:0] ), + + .pcm55_l ( adpcmA_l ), + .pcm55_r ( adpcmA_r ) + ); + /* 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 + .alr_b ( alr_b ), // Left / Right + .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 + // Flag + .flag ( adpcmb_flag ), + .clr_flag ( flag_ctl[6] ), + // memory + .addr ( adpcmb_addr ), + .data ( adpcmb_data ), + .roe_n ( adpcmb_roe_n ), + + .pcm55_l ( adpcmB_l ), + .pcm55_r ( adpcmB_r ) + ); + + /* verilator tracing_on */ + assign snd_sample = zero; + jt10_acc u_acc( + .clk ( clk ), + .clk_en ( clk_en ), + .op_result ( op_result_hd ), + .rl ( rl ), + .zero ( zero ), + .s1_enters ( s2_enters ), + .s2_enters ( s1_enters ), + .s3_enters ( s4_enters ), + .s4_enters ( s3_enters ), + .cur_ch ( cur_ch ), + .cur_op ( cur_op ), + .alg ( alg_I ), + .adpcmA_l ( adpcmA_l ), + .adpcmA_r ( adpcmA_r ), + .adpcmB_l ( adpcmB_l ), + .adpcmB_r ( adpcmB_r ), + // combined output + .left ( fm_snd_left ), + .right ( fm_snd_right ) + ); +end else begin : gen_adpcm_no + assign adpcmA_l = 'd0; + assign adpcmA_r = 'd0; + assign adpcmB_l = 'd0; + assign adpcmB_r = 'd0; + assign adpcma_addr = 'd0; + assign adpcma_bank = 'd0; + assign adpcma_roe_n = 'b1; + assign adpcmb_addr = 'd0; + assign adpcmb_roe_n = 'd1; +end +endgenerate + +/* verilator tracing_on */ +jt12_dout #(.use_ssg(use_ssg),.use_adpcm(use_adpcm)) u_dout( +// .rst_n ( rst_n ), + .clk ( clk ), // CPU clock + .flag_A ( flag_A ), + .flag_B ( flag_B ), + .busy ( busy ), + .adpcma_flags ( adpcma_flags ), + .adpcmb_flag ( adpcmb_flag ), + .psg_dout ( psg_dout ), + .addr ( addr ), + .dout ( dout ) +); + + +/* verilator tracing_on */ +jt12_mmr #(.use_ssg(use_ssg),.num_ch(num_ch),.use_pcm(use_pcm), .use_adpcm(use_adpcm)) + u_mmr( + .rst ( rst ), + .clk ( clk ), + .cen ( cen ), // external clock enable + .clk_en ( clk_en ), // internal clock enable + .clk_en_2 ( clk_en_2 ), // input cen divided by 2 + .clk_en_ssg ( clk_en_ssg), // internal clock enable + .clk_en_666 ( clk_en_666), + .clk_en_111 ( clk_en_111), + .clk_en_55 ( clk_en_55 ), + .din ( din ), + .write ( write ), + .addr ( addr ), + .busy ( busy ), + .ch6op ( ch6op ), + .cur_ch ( cur_ch ), + .cur_op ( cur_op ), + // LFO + .lfo_freq ( lfo_freq ), + .lfo_en ( lfo_en ), + // Timers + .value_A ( value_A ), + .value_B ( value_B ), + .load_A ( load_A ), + .load_B ( load_B ), + .enable_irq_A ( enable_irq_A ), + .enable_irq_B ( enable_irq_B ), + .clr_flag_A ( clr_flag_A ), + .clr_flag_B ( clr_flag_B ), + .flag_A ( flag_A ), + .overflow_A ( overflow_A ), + .fast_timers( fast_timers ), + // PCM + .pcm ( pcm ), + .pcm_en ( pcm_en ), + .pcm_wr ( pcm_wr ), + // ADPCM-A + .aon_a ( aon_a ), // ON + .atl_a ( atl_a ), // TL + .addr_a ( addr_a ), // address latch + .lracl ( lracl ), // L/R ADPCM Channel Level + .up_start ( up_start ), // write enable start address latch + .up_end ( up_end ), // write enable end address latch + .up_addr ( up_addr ), // write enable end address latch + .up_lracl ( up_lracl ), + .up_aon ( up_aon ), + // ADPCM-B + .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 + .alr_b ( alr_b ), // Left / Right + .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 + .flag_ctl ( flag_ctl ), + // Operator + .xuse_prevprev1 ( xuse_prevprev1 ), + .xuse_internal ( xuse_internal ), + .yuse_internal ( yuse_internal ), + .xuse_prev2 ( xuse_prev2 ), + .yuse_prev1 ( yuse_prev1 ), + .yuse_prev2 ( yuse_prev2 ), + // PG + .fnum_I ( fnum_I ), + .block_I ( block_I ), + .pg_stop ( pg_stop ), + // EG + .rl ( rl ), + .fb_II ( fb_II ), + .alg_I ( alg_I ), + .pms_I ( pms_I ), + .ams_IV ( ams_IV ), + .amsen_IV ( amsen_IV ), + .dt1_I ( dt1_I ), + .mul_II ( mul_II ), + .tl_IV ( tl_IV ), + + .ar_I ( ar_I ), + .d1r_I ( d1r_I ), + .d2r_I ( d2r_I ), + .rr_I ( rr_I ), + .sl_I ( sl_I ), + .ks_II ( ks_II ), + + .eg_stop ( eg_stop ), + // SSG operation + .ssg_en_I ( ssg_en_I ), + .ssg_eg_I ( ssg_eg_I ), + + .keyon_I ( keyon_I ), + // Operator + .zero ( zero ), + .s1_enters ( s1_enters ), + .s2_enters ( s2_enters ), + .s3_enters ( s3_enters ), + .s4_enters ( s4_enters ), + // PSG interace + .psg_addr ( psg_addr ), + .psg_data ( psg_data ), + .psg_wr_n ( psg_wr_n ) +); + +/* verilator tracing_on */ +// YM2203 seems to use a fixed cen/3 clock for the timers, regardless +// of the prescaler setting +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 ), + .load_B ( load_B ), + .enable_irq_A( enable_irq_A ), + .enable_irq_B( enable_irq_B ), + .clr_flag_A ( clr_flag_A ), + .clr_flag_B ( clr_flag_B ), + .flag_A ( flag_A ), + .flag_B ( flag_B ), + .overflow_A ( overflow_A ), + .irq_n ( irq_n ) +); + +// YM2203 does not have LFO +generate +if( use_lfo== 1) begin : gen_lfo + jt12_lfo u_lfo( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .zero ( zero ), + `ifdef NOLFO + .lfo_rst ( 1'b1 ), + `else + .lfo_rst ( 1'b0 ), + `endif + .lfo_en ( lfo_en ), + .lfo_freq ( lfo_freq ), + .lfo_mod ( lfo_mod ) + ); +end else begin : gen_nolfo + assign lfo_mod = 7'd0; +end +endgenerate + +// YM2203/YM2610 have a PSG + +`ifndef NOSSG +generate + if( use_ssg==1 ) begin : gen_ssg + jt49 #(.COMP(2'b00), .CLKDIV(JT49_DIV)) + u_psg( // note that input ports are not multiplexed + .rst_n ( ~rst ), + .clk ( clk ), // signal on positive edge + .clk_en ( clk_en_ssg), // clock enable on negative edge + .addr ( psg_addr ), + .cs_n ( 1'b0 ), + .wr_n ( psg_wr_n ), // write + .din ( psg_data ), + .sound ( psg_snd ), // combined output + .A ( psg_A ), + .B ( psg_B ), + .C ( psg_C ), + .dout ( psg_dout ), + .sel ( 1'b1 ), // half clock speed + // Unused: + .IOA_out ( IOA_out ), + .IOB_out ( IOB_out ), + .IOA_in ( IOA_in ), + .IOB_in ( IOB_in ), + .sample ( ) + ); + assign snd_left = fm_snd_left + { 1'b0, psg_snd[9:0],5'd0}; + assign snd_right = fm_snd_right + { 1'b0, psg_snd[9:0],5'd0}; + end else begin : gen_nossg + assign psg_snd = 10'd0; + assign snd_left = fm_snd_left; + assign snd_right= fm_snd_right; + assign psg_dout = 8'd0; + assign psg_A = 8'd0; + assign psg_B = 8'd0; + assign psg_C = 8'd0; + end +endgenerate +`else + assign psg_snd = 10'd0; + assign snd_left = fm_snd_left; + assign snd_right= fm_snd_right; + assign psg_dout = 8'd0; +`endif + +wire [ 8:0] op_result; +wire [13:0] op_result_hd; +`ifndef NOFM +/* verilator tracing_on */ +jt12_pg #(.num_ch(num_ch)) u_pg( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + // Channel frequency + .fnum_I ( fnum_I ), + .block_I ( block_I ), + // Operator multiplying + .mul_II ( mul_II ), + // Operator detuning + .dt1_I ( dt1_I ), // same as JT51's DT1 + // Phase modulation by LFO + .lfo_mod ( lfo_mod ), + .pms_I ( pms_I ), + // phase operation + .pg_rst_II ( pg_rst_II ), + .pg_stop ( pg_stop ), + .keycode_II ( keycode_II ), + .phase_VIII ( phase_VIII ) +); + +wire [9:0] eg_V; + +jt12_eg #(.num_ch(num_ch)) u_eg( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .zero ( zero ), + .eg_stop ( eg_stop ), + // envelope configuration + .keycode_II ( keycode_II ), + .arate_I ( ar_I ), // attack rate + .rate1_I ( d1r_I ), // decay rate + .rate2_I ( d2r_I ), // sustain rate + .rrate_I ( rr_I ), // release rate + .sl_I ( sl_I ), // sustain level + .ks_II ( ks_II ), // key scale + // SSG operation + .ssg_en_I ( ssg_en_I ), + .ssg_eg_I ( ssg_eg_I ), + // envelope operation + .keyon_I ( keyon_I ), + // envelope number + .lfo_mod ( lfo_mod ), + .tl_IV ( tl_IV ), + .ams_IV ( ams_IV ), + .amsen_IV ( amsen_IV ), + + .eg_V ( eg_V ), + .pg_rst_II ( pg_rst_II ) +); + +jt12_sh #(.width(10),.stages(4)) u_egpad( + .clk ( clk ), + .clk_en ( clk_en ), + .din ( eg_V ), + .drop ( eg_IX ) +); + +jt12_op #(.num_ch(num_ch)) u_op( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .pg_phase_VIII ( phase_VIII ), + .eg_atten_IX ( eg_IX ), + .fb_II ( fb_II ), + + .test_214 ( 1'b0 ), + .s1_enters ( s1_enters ), + .s2_enters ( s2_enters ), + .s3_enters ( s3_enters ), + .s4_enters ( s4_enters ), + .xuse_prevprev1 ( xuse_prevprev1), + .xuse_internal ( xuse_internal ), + .yuse_internal ( yuse_internal ), + .xuse_prev2 ( xuse_prev2 ), + .yuse_prev1 ( yuse_prev1 ), + .yuse_prev2 ( yuse_prev2 ), + .zero ( zero ), + .op_result ( op_result ), + .full_result ( op_result_hd ) +); +`else +assign op_result = 'd0; +assign op_result_hd = 'd0; +`endif + +/* verilator tracing_on */ + +generate + if( use_pcm==1 ) begin: gen_pcm_acc // YM2612 accumulator + assign fm_snd_right[3:0] = 4'd0; + assign fm_snd_left [3:0] = 4'd0; + assign snd_sample = zero; + reg signed [8:0] pcm2; + + // interpolate PCM samples with automatic sample rate detection + // this feature is not present in original YM2612 + // this improves PCM sample sound greatly + /* + jt12_pcm u_pcm( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .zero ( zero ), + .pcm ( pcm ), + .pcm_wr ( pcm_wr ), + .pcm_resampled ( pcm2 ) + ); + */ + wire rst_pcm_n; + + jt12_rst u_rst_pcm( + .rst ( rst ), + .clk ( clk ), + .rst_n ( rst_pcm_n ) + ); + + `ifndef NOPCMLINEAR + 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 ( + .rst_n ( rst_pcm_n ), + .clk ( clk ), + .cen ( clk_en ), + .cen55 ( clk_en_55 ), + .pcm_wr( pcm_wr ), + .pcmin ( {pcm[8],pcm, 1'b0} ), + .pcmout( pcm_full ) + ); + `else + assign pcm2 = pcm; + `endif + + jt12_acc u_acc( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .op_result ( op_result ), + .rl ( rl ), + // note that the order changes to deal + // with the operator pipeline delay + .zero ( zero ), + .s1_enters ( s2_enters ), + .s2_enters ( s1_enters ), + .s3_enters ( s4_enters ), + .s4_enters ( s3_enters ), + .ch6op ( ch6op ), + .pcm_en ( pcm_en ), // only enabled for channel 6 + .pcm ( pcm2 ), + .alg ( alg_I ), + // combined output + .left ( fm_snd_left [15:4] ), + .right ( fm_snd_right[15:4] ) + ); + end + if( use_pcm==0 && use_adpcm==0 ) begin : gen_2203_acc // YM2203 accumulator + wire signed [15:0] mono_snd; + assign fm_snd_left = mono_snd; + assign fm_snd_right = mono_snd; + assign snd_sample = zero; + jt03_acc u_acc( + .rst ( rst ), + .clk ( clk ), + .clk_en ( clk_en ), + .op_result ( op_result_hd ), + // note that the order changes to deal + // with the operator pipeline delay + .s1_enters ( s1_enters ), + .s2_enters ( s2_enters ), + .s3_enters ( s3_enters ), + .s4_enters ( s4_enters ), + .alg ( alg_I ), + .zero ( zero ), + // combined output + .snd ( mono_snd ) + ); + end +endgenerate +endmodule diff --git a/common/Sound/JT12/hdl/mixer/jt12_comb.v b/common/Sound/JT12/hdl/mixer/jt12_comb.v new file mode 100644 index 00000000..dfd390e6 --- /dev/null +++ b/common/Sound/JT12/hdl/mixer/jt12_comb.v @@ -0,0 +1,59 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 10-12-2018 + +*/ + +module jt12_comb #(parameter + w=16, // bit width + m=1 // depth of comb filter +)( + input rst, + input clk, +(* direct_enable *) input cen, + input signed [w-1:0] snd_in, + output reg signed [w-1:0] snd_out +); + +wire signed [w-1:0] prev; + +// m-delay stage +generate + genvar k; + reg signed [w-1:0] mem[0:m-1]; + assign prev=mem[m-1]; + for(k=0;k. + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 10-12-2018 + +*/ + +module jt12_decim #(parameter calcw=18, inw=16, + n=2, // number of stages + m=1, // depth of comb filter + rate=2 // it will stuff with as many as (rate-1) zeros +)( + input rst, + input clk, +(* direct_enable *) input cen_in, +(* direct_enable *) input cen_out, + input signed [inw-1:0] snd_in, + output reg signed [inw-1:0] snd_out +); + +reg signed [calcw-1:0] inter6; +wire signed [calcw-1:0] integ_op, comb_op; +localparam wdiff = calcw - inw; + +// integrator at clk x cen sampling rate +generate + genvar k2; + reg [calcw-1:0] integ_data[0:n]; + assign integ_op = integ_data[n]; + always @(*) + integ_data[0] = { {wdiff{snd_in[inw-1]}}, snd_in }; + for(k2=1;k2<=n;k2=k2+1) begin : integ_gen + always @(posedge clk) + if(rst) begin + integ_data[k2] <= {calcw{1'b0}}; + end else if(cen_in) begin + integ_data[k2] <= integ_data[k2] + integ_data[k2-1]; + end + end +endgenerate + +// interpolator +always @(posedge clk) + if(rst) begin + inter6 <= {calcw{1'b0}}; + end else if(cen_out) begin + inter6 <= integ_op; + end + +generate + genvar k; + wire [calcw-1:0] comb_data[0:n]; + assign comb_data[0] = inter6; + assign comb_op = comb_data[n]; + for(k=0;k. + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 11-12-2018 + + Each channel can use the full range of the DAC as they do not + get summed in the real chip. + + Operator data is summed up without adding extra bits. This is + the case of real YM3438, which was used on Megadrive 2 models. + +*/ + +/* rate up-scaler for FM+PSG channel +*/ + +module jt12_fm_uprate( + input rst, + input clk, + input signed [15:0] fm_snd, + input signed [11:0] psg_snd, + input fm_en, // enable FM + input cen_1008, + input cen_252, + input cen_63, + input cen_9, + output signed [15:0] snd // Mixed sound at clk sample rate +); + +wire signed [15:0] fm2,fm3,fm4; + +reg [15:0] mixed; +always @(posedge clk) + mixed <= (fm_en?fm_snd:16'd0) + {{1{psg_snd[11]}},psg_snd,3'b0}; + +// 1008 --> 252 x4 +jt12_interpol #(.calcw(17),.inw(16),.rate(4),.m(1),.n(1)) +u_fm2( + .clk ( clk ), + .rst ( rst ), + .cen_in ( cen_1008 ), + .cen_out( cen_252 ), + .snd_in ( mixed ), + .snd_out( fm2 ) +); + +// 252 --> 63 x4 +jt12_interpol #(.calcw(19),.inw(16),.rate(4),.m(1),.n(3)) +u_fm3( + .clk ( clk ), + .rst ( rst ), + .cen_in ( cen_252 ), + .cen_out( cen_63 ), + .snd_in ( fm2 ), + .snd_out( fm3 ) +); + +// 63 --> 9 x7 +jt12_interpol #(.calcw(21),.inw(16),.rate(7),.m(2),.n(2)) +u_fm4( + .clk ( clk ), + .rst ( rst ), + .cen_in ( cen_63 ), + .cen_out( cen_9 ), + .snd_in ( fm3 ), + .snd_out( fm4 ) +); + +// 9 --> 1 x9 +jt12_interpol #(.calcw(21),.inw(16),.rate(9),.m(2),.n(2)) +u_fm5( + .clk ( clk ), + .rst ( rst ), + .cen_in ( cen_9 ), + .cen_out( 1'b1 ), + .snd_in ( fm4 ), + .snd_out( snd ) +); + +endmodule // jt12_fm_uprate \ No newline at end of file diff --git a/common/Sound/JT12/hdl/mixer/jt12_genmix.v b/common/Sound/JT12/hdl/mixer/jt12_genmix.v new file mode 100644 index 00000000..1963fdcd --- /dev/null +++ b/common/Sound/JT12/hdl/mixer/jt12_genmix.v @@ -0,0 +1,180 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 11-12-2018 + + Each channel can use the full range of the DAC as they do not + get summed in the real chip. + + Operator data is summed up without adding extra bits. This is + the case of real YM3438, which was used on Megadrive 2 models. + +*/ + +/* Mixer for Megadrive/Genesis + cen_fm must be 1 over 7 of clk + psg_cen_240 must be 1 over 15 of clk + PSG and FM signals are interpolated up to clk sample rate. +*/ + +module jt12_genmix( + input rst, + input clk, + input signed [15:0] fm_left, + input signed [15:0] fm_right, + input signed [10:0] psg_snd, + input fm_en, // enable FM + input psg_en, // enable PSG + // Mixed sound at clk sample rate + output signed [15:0] snd_left, + output signed [15:0] snd_right +); + +///////////////////////////////////////////////// +// PSG +// x5 -> div 3 -> div 7 +// 54MHz count up to: +// orig -> 16*15 = 240 +// x5 -> 16*15/5 = 48 +// div 3 -> 48*3 = 144 +// div 7 -> 144*7 = 1008 <=> fm_sample +// 48 x 5 = 240, +reg [5:0] psgcnt48; +reg [2:0] psgcnt240, psgcnt1008; +reg [1:0] psgcnt144; + +always @(posedge clk) + if( rst ) begin + psgcnt48 <= 6'd0; + psgcnt240 <= 3'd0; + psgcnt144 <= 2'd0; + psgcnt1008<= 3'd0; + end else begin + psgcnt48 <= psgcnt48 ==6'd47 ? 6'd0 : psgcnt48 +6'd1; + if( psgcnt48 == 6'd47 ) begin + psgcnt240 <= psgcnt240==3'd4 ? 3'd0 : psgcnt240+3'd1; + psgcnt144 <= psgcnt144 ==2'd2 ? 2'd0 : psgcnt144+2'd1; + if( psgcnt144==2'd0 ) + psgcnt1008 <= psgcnt1008==3'd6 ? 3'd0 : psgcnt1008+3'd1; + end + end + +reg psg_cen_1008, psg_cen_240, psg_cen_48, psg_cen_144; +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; + psg_cen_1008<= psgcnt48 ==6'd47 && psgcnt144==2'd0 && psgcnt1008==3'd0; +end + +wire signed [11:0] psg0, psg1, psg2, psg3; +assign psg0 = psg_en ? { psg_snd[10], psg_snd } : 12'b0; + +// 48 +jt12_interpol #(.calcw(19),.inw(12),.rate(5),.m(4),.n(2)) +u_psg1( + .clk ( clk ), + .rst ( rst ), + .cen_in ( psg_cen_240 ), + .cen_out( psg_cen_48 ), + .snd_in ( psg0 ), + .snd_out( psg1 ) +); + +// 144 +jt12_decim #(.calcw(19),.inw(12),.rate(3),.m(2),.n(3) ) +u_psg2( + .clk ( clk ), + .rst ( rst ), + .cen_in ( psg_cen_48 ), + .cen_out( psg_cen_144 ), + .snd_in ( psg1 ), + .snd_out( psg2 ) +); + +// 1008 +jt12_decim #(.calcw(15),.inw(12),.rate(7),.m(1),.n(1) ) +u_psg3( + .clk ( clk ), + .rst ( rst ), + .cen_in ( psg_cen_144 ), + .cen_out( psg_cen_1008), + .snd_in ( psg2 ), + .snd_out( psg3 ) +); + +///////////////////////////////////////////////// +// FM +// x4 -> x4 -> x7 -> x9 +// 54MHz count up to: +// 252 -> 63 -> 9 -> 1 +reg [1:0] clkcnt252, clkcnt1008; +reg [2:0] clkcnt63; +reg [3:0] clkcnt9; +always @(posedge clk) + if( rst ) begin + clkcnt1008<= 2'd0; + clkcnt252 <= 2'd0; + clkcnt63 <= 3'd0; + clkcnt9 <= 4'd0; + end else begin + clkcnt9 <= clkcnt9 ==4'd8 ? 4'd0 : clkcnt9 +4'd1; + if( clkcnt9== 4'd8 ) begin + clkcnt63 <= clkcnt63 ==3'd6 ? 3'd0 : clkcnt63 +3'd1; + if( clkcnt63==3'd6 ) begin + clkcnt252 <= clkcnt252+2'd1; + if(clkcnt252==2'd3) clkcnt1008<=clkcnt1008+2'd1; + end + end + end +// evenly spaced clock enable signals +reg cen_1008, cen_252, cen_63, cen_9; +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; + cen_1008 <= clkcnt9 ==4'd8 && clkcnt63 ==3'd0 && clkcnt252 ==2'd0 && clkcnt1008==2'd0; +end + +jt12_fm_uprate u_left( + .rst ( rst ), + .clk ( clk ), + .fm_snd ( fm_left ), + .psg_snd ( psg3 ), + .fm_en ( fm_en ), + .cen_1008 ( cen_1008 ), + .cen_252 ( cen_252 ), + .cen_63 ( cen_63 ), + .cen_9 ( cen_9 ), + .snd ( snd_left ) // Mixed sound at clk sample rate +); + +jt12_fm_uprate u_right( + .rst ( rst ), + .clk ( clk ), + .fm_snd ( fm_right ), + .psg_snd ( psg3 ), + .fm_en ( fm_en ), + .cen_1008 ( cen_1008 ), + .cen_252 ( cen_252 ), + .cen_63 ( cen_63 ), + .cen_9 ( cen_9 ), + .snd ( snd_right ) // Mixed sound at clk sample rate +); + +endmodule // jt12_genmix \ No newline at end of file diff --git a/common/Sound/JT12/hdl/mixer/jt12_interpol.v b/common/Sound/JT12/hdl/mixer/jt12_interpol.v new file mode 100644 index 00000000..e5ff23ba --- /dev/null +++ b/common/Sound/JT12/hdl/mixer/jt12_interpol.v @@ -0,0 +1,92 @@ +/* This file is part of JT12. + + + JT12 program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT12 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT12. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 10-12-2018 + +*/ + +module jt12_interpol #(parameter calcw=18, inw=16, + n=2, // number of stages + m=1, // depth of comb filter + rate=2 // it will stuff with as many as (rate-1) zeros +)( + input rst, + input clk, +(* direct_enable *) input cen_in, +(* direct_enable *) input cen_out, + input signed [inw-1:0] snd_in, + output reg signed [inw-1:0] snd_out +); + +reg signed [calcw-1:0] inter6; +wire signed [calcw-1:0] comb_op, integ_op; +localparam wdiff = calcw - inw; + +generate + genvar k; + wire [calcw-1:0] comb_data[0:n]; + assign comb_data[0] = { {wdiff{snd_in[inw-1]}}, snd_in }; + assign comb_op = comb_data[n]; + for(k=0;k. + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 11-12-2018 + + Each channel can use the full range of the DAC as they do not + get summed in the real chip. + + Operator data is summed up without adding extra bits. This is + the case of real YM3438, which was used on Megadrive 2 models. + +*/ + +// Generic mixer +// wout should be larger or equal than any input (w0,w1,w2,w3) + +module jt12_mixer #(parameter w0=16,w1=16,w2=16,w3=16,wout=20) +( + input clk, + input cen, + // input signals + input signed [w0-1:0] ch0, + input signed [w1-1:0] ch1, + input signed [w2-1:0] ch2, + input signed [w3-1:0] ch3, + // gain for each channel in 4.4 fixed point format + input [7:0] gain0, + input [7:0] gain1, + input [7:0] gain2, + input [7:0] gain3, + output reg signed [wout-1:0] mixed +); + +reg signed [w0+7:0] ch0_amp; +reg signed [w1+7:0] ch1_amp; +reg signed [w2+7:0] ch2_amp; +reg signed [w3+7:0] ch3_amp; + +// rescale to wout+4+8 +wire signed [wout+11:0] scaled0 = { {wout+4-w0{ch0_amp[w0+7]}}, ch0_amp }; +wire signed [wout+11:0] scaled1 = { {wout+4-w1{ch1_amp[w1+7]}}, ch1_amp }; +wire signed [wout+11:0] scaled2 = { {wout+4-w2{ch2_amp[w2+7]}}, ch2_amp }; +wire signed [wout+11:0] scaled3 = { {wout+4-w3{ch3_amp[w3+7]}}, ch3_amp }; + +reg signed [wout+11:0] sum, limited; + +wire signed [wout+11:0] max_pos = { {12{1'b0}}, {(wout-1){1'b1}}}; + +wire signed [8:0] + g0 = {1'b0, gain0}, + g1 = {1'b0, gain1}, + g2 = {1'b0, gain2}, + g3 = {1'b0, gain3}; + +// Apply gain +always @(posedge clk) if(cen) begin + ch0_amp <= g0 * ch0; + ch1_amp <= g1 * ch1; + ch2_amp <= g2 * ch2; + ch3_amp <= g3 * ch3; + + // divides by 16 to take off the decimal part and leave only + // the integer part + sum <= (scaled0 + scaled1 + scaled2 + scaled3)>>>4; + limited <= sum>max_pos ? max_pos : (sum<~max_pos ? ~max_pos : sum); + mixed <= limited[wout-1:0]; +end + +endmodule // jt12_mixer