1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-03-04 18:33:50 +00:00

Konami Iron Horse

This commit is contained in:
Gyorgy Szombathelyi
2021-12-30 03:04:03 +01:00
parent 235fdb6cb2
commit e64964ce9f
103 changed files with 15207 additions and 2 deletions

View File

@@ -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"

View File

@@ -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=<None>"
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

View File

@@ -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
#**************************************************************

View File

@@ -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/

View File

@@ -0,0 +1,84 @@
<misterromdescription>
<name>Iron Horse</name>
<region>World</region>
<homebrew>no</homebrew>
<bootleg>no</bootleg>
<version>Version K</version>
<alternative></alternative>
<platform></platform>
<series></series>
<year>1986</year>
<manufacturer>Konami</manufacturer>
<category>Platformer</category>
<setname>ironhors</setname>
<parent>ironhors</parent>
<mameversion>0224</mameversion>
<rbf>IronHors</rbf>
<about author="Ace" twitter="@Ace9921Tweets"></about>
<resolution>15kHz</resolution>
<rotation>no</rotation>
<flip>no</flip>
<players>2 (alternating)</players>
<joystick>8-way</joystick>
<special_controls></special_controls>
<num_buttons>3</num_buttons>
<buttons default="Y,B,A,Start,R,Select,L" names="Power,Attack,Crouch,Start P1,Coin,Start P2,Pause"></buttons>
<switches default="00,45,00" base="8" page_id="1" page_name="Switches">
<dip bits="0,3" name="Credits A" ids="1c/1cr,1c/2cr,1c/3cr,1c/4cr,1c/5cr,1c/7cr,1c/6cr,2c/1cr,2c/3cr,3c/1cr,2c/5cr,3c/2cr,3c/4cr,4c/3cr,4c/1cr,Free Play"/>
<dip bits="4,7" name="Credits B" ids="1c/1cr,1c/2cr,1c/3cr,1c/4cr,1c/5cr,1c/6cr,1c/7cr,2c/1cr,2c/3cr,2c/5cr,3c/1cr,3c/2cr,3c/4cr,4c/1cr,4c/3cr,Free Play"/>
<dip bits="8,9" name="Lives" ids="2,3,5,7"/>
<dip bits="10" name="Cabinet Type" ids="Cocktail,Upright"/>
<dip bits="11,12" name="Bonus" ids="30K/70K+,40K/80K+,40K only,50K only"/>
<dip bits="13,14" name="Difficulty" ids="Easy,Normal,Hard,Hardest"/>
<dip bits="15" name="Attract Mode Sound" ids="Off,On"/>
<dip bits="16" name="Flip Screen" ids="Off,On"/>
<dip bits="17" name="Upright Controls" ids="Single,Dual"/>
<dip bits="18" name="Swap Power/Crouch" ids="Off,On"/>
</switches>
<rom index="1">
<part>00</part>
</rom>
<rom index='0' md5="None" type='merged' zip='ironhors.zip'>
<part crc="395351b4" name="560_k03.13c"/>
<part crc="1cff3d59" name="560_k02.12c"/>
<part crc="2b17930f" name="560_h01.10c"/>
<part crc="f21d8c93" name="560_h06.08f"/>
<part crc="60107859" name="560_h05.07f"/>
<part crc="c761ec73" name="560_h07.09f"/>
<part crc="c1486f61" name="560_h04.06f"/>
<part crc="9f6ddf83" name="03f_h08.bin"/>
<part crc="e6773825" name="04f_h09.bin"/>
<part crc="30a57860" name="05f_h10.bin"/>
<part crc="5eb33e73" name="10f_h12.bin"/>
<part crc="a63e37d8" name="10f_h11.bin"/>
</rom>
<rom index="2"></rom>
<rom index="3" md5="none">
<part>
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
</part>
</rom>
<rom index="4">
<part>
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
</part>
</rom>
<nvram index="4" size="67"></nvram>
<remark></remark>
<mratimestamp>20210803143815</mratimestamp>
</misterromdescription>

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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

View File

@@ -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

View File

@@ -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"]

View File

@@ -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

View File

@@ -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

View File

@@ -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 <till@harbaum.org>
// 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 <http://www.gnu.org/licenses/>.
//
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

View File

@@ -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;

View File

@@ -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

674
common/Sound/JT12/LICENSE Normal file
View File

@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
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 <http://www.gnu.org/licenses/>.
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
<http://www.gnu.org/licenses/>.
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
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@@ -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)

View File

@@ -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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -0,0 +1,59 @@
/* This file is part of JT12.
JT12 program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT12 program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: March, 9th 2017
*/
`timescale 1ns / 1ps
/*
input sampling rate must be the same as clk frequency
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

View File

@@ -0,0 +1,63 @@
/* This file is part of JT12.
JT12 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT12 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: March, 9th 2017
*/
`timescale 1ns / 1ps
/*
input sampling rate must be the same as clk frequency
interpolate input signal accordingly to get the
right sampling rate.
Refer to sigmadelta.ods to see how the internal width (int_w)
was determined.
*/
module jt12_dac2 #(parameter width=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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 ]

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 ]

View File

@@ -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 ]

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 ]

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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;

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 14-2-2017
*/
`timescale 1ns / 1ps
module jt12_div(
input rst,
input clk,
input cen /* synthesis direct_enable */,
input [1:0] div_setting,
output reg clk_en, // after prescaler
output reg clk_en_2, // cen divided by 2
output reg clk_en_ssg,
output reg clk_en_666, // 666 kHz
output reg clk_en_111, // 111 kHz
output reg clk_en_55 // 55 kHz
);
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 2-11-2018
Based on information posted by Nemesis on:
http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc&start=167
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 2-11-2018
Based on information posted by Nemesis on:
http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc&start=167
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 2-11-2018
Based on information posted by Nemesis on:
http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc&start=167
Based on jt51_phasegen.v, from JT51
*/
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 2-11-2018
Based on information posted by Nemesis on:
http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc&start=167
Based on jt51_phasegen.v, from JT51
*/
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -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 <http://www.gnu.org/licenses/>.
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

View File

@@ -0,0 +1,59 @@
/* This file is part of JT12.
JT12 program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT12 program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 10-12-2018
*/
module jt12_comb #(parameter
w=16, // bit width
m=1 // depth of comb filter
)(
input rst,
input clk,
(* direct_enable *) input cen,
input signed [w-1:0] snd_in,
output reg signed [w-1:0] snd_out
);
wire signed [w-1:0] prev;
// m-delay stage
generate
genvar k;
reg signed [w-1:0] mem[0:m-1];
assign prev=mem[m-1];
for(k=0;k<m;k=k+1) begin : mem_gen
always @(posedge clk)
if(rst) begin
mem[k] <= {w{1'b0}};
end else if(cen) begin
mem[k] <= k==0 ? snd_in : mem[k-1];
end
end
endgenerate
// Comb filter at synthesizer sampling rate
always @(posedge clk)
if(rst) begin
snd_out <= {w{1'b0}};
end else if(cen) begin
snd_out <= snd_in - prev;
end
endmodule // jt12_comb

View File

@@ -0,0 +1,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 <http://www.gnu.org/licenses/>.
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<n;k=k+1) begin : com_gen
jt12_comb #(.w(calcw),.m(m)) u_comb(
.rst ( rst ),
.clk ( clk ),
.cen ( cen_out ),
.snd_in ( comb_data[k] ),
.snd_out( comb_data[k+1] )
);
end
endgenerate
// Comb filter at synthesizer sampling rate
always @(posedge clk)
if(rst) begin
snd_out <= {inw{1'b0}};
end else if(cen_out) begin
snd_out<= comb_op[calcw-1:wdiff];
end
endmodule

View File

@@ -0,0 +1,95 @@
/* This file is part of JT12.
JT12 program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT12 program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 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

Some files were not shown because too many files have changed in this diff Show More