diff --git a/Arcade_MiST/Konami Jackal/Jackal.qpf b/Arcade_MiST/Konami Jackal/Jackal.qpf new file mode 100644 index 00000000..45443300 --- /dev/null +++ b/Arcade_MiST/Konami Jackal/Jackal.qpf @@ -0,0 +1,31 @@ +# -------------------------------------------------------------------------- # +# +# Copyright (C) 1991-2013 Altera Corporation +# Your use of Altera Corporation's design tools, logic functions +# and other software and tools, and its AMPP partner logic +# functions, and any output files from any of the foregoing +# (including device programming or simulation files), and any +# associated documentation or information are expressly subject +# to the terms and conditions of the Altera Program License +# Subscription Agreement, Altera MegaCore Function License +# Agreement, or other applicable license agreement, including, +# without limitation, that your use is for the sole purpose of +# programming logic devices manufactured by Altera and sold by +# Altera or its authorized distributors. Please refer to the +# applicable agreement for further details. +# +# -------------------------------------------------------------------------- # +# +# Quartus II 64-Bit +# Version 13.1.0 Build 162 10/23/2013 SJ Web Edition +# Date created = 00:21:03 December 03, 2019 +# +# -------------------------------------------------------------------------- # + +QUARTUS_VERSION = "13.1" +DATE = "00:21:03 December 03, 2019" + +# Revisions + +PROJECT_REVISION = "Jackal" + diff --git a/Arcade_MiST/Konami Jackal/Jackal.qsf b/Arcade_MiST/Konami Jackal/Jackal.qsf new file mode 100644 index 00000000..6bcbe867 --- /dev/null +++ b/Arcade_MiST/Konami Jackal/Jackal.qsf @@ -0,0 +1,249 @@ +# -------------------------------------------------------------------------- # +# +# 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: +# Jackal_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 SP4.26" +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 Jackal_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/jackal.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(Jackal_MiST) + + # Pin & Location Assignments + # ========================== + + # Fitter Assignments + # ================== + + # start DESIGN_PARTITION(Top) + # --------------------------- + + # Incremental Compilation Assignments + # =================================== + + # end DESIGN_PARTITION(Top) + # ------------------------- + +# end ENTITY(Jackal_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/Jackal_MiST.sv +set_global_assignment -name QIP_FILE rtl/pll.qip +set_global_assignment -name VERILOG_FILE rtl/jtframe_frac_cen.v +set_global_assignment -name SYSTEMVERILOG_FILE rtl/Jackal.sv +set_global_assignment -name VERILOG_FILE rtl/hiscore.v +set_global_assignment -name VHDL_FILE rtl/spram.vhd +set_global_assignment -name SYSTEMVERILOG_FILE rtl/sdram.sv +set_global_assignment -name VHDL_FILE rtl/dpram_dc.vhd +set_global_assignment -name QIP_FILE rtl/custom/jackal_custom.qip +set_global_assignment -name QIP_FILE rtl/sound/jackal_sound.qip +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/Sound/jt51/jt51.qip +set_global_assignment -name SIGNALTAP_FILE output_files/jackal.stp +set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/Arcade_MiST/Konami Jackal/Jackal.sdc b/Arcade_MiST/Konami Jackal/Jackal.sdc new file mode 100644 index 00000000..4a373c09 --- /dev/null +++ b/Arcade_MiST/Konami Jackal/Jackal.sdc @@ -0,0 +1,134 @@ +## Generated SDC file "vectrex_MiST.out.sdc" + +## Copyright (C) 1991-2013 Altera Corporation +## Your use of Altera Corporation's design tools, logic functions +## and other software and tools, and its AMPP partner logic +## functions, and any output files from any of the foregoing +## (including device programming or simulation files), and any +## associated documentation or information are expressly subject +## to the terms and conditions of the Altera Program License +## Subscription Agreement, Altera MegaCore Function License +## Agreement, or other applicable license agreement, including, +## without limitation, that your use is for the sole purpose of +## programming logic devices manufactured by Altera and sold by +## Altera or its authorized distributors. Please refer to the +## applicable agreement for further details. + + +## VENDOR "Altera" +## PROGRAM "Quartus II" +## VERSION "Version 13.1.0 Build 162 10/23/2013 SJ Web Edition" + +## DATE "Sun Jun 24 12:53:00 2018" + +## +## DEVICE "EP3C25E144C8" +## + +# Clock constraints + +# Automatically constrain PLL and other generated clocks +derive_pll_clocks -create_base_clocks + +# Automatically calculate clock uncertainty to jitter and other effects. +derive_clock_uncertainty + +# tsu/th constraints + +# tco constraints + +# tpd constraints + +#************************************************************** +# Time Information +#************************************************************** + +set_time_format -unit ns -decimal_places 3 + + + +#************************************************************** +# Create Clock +#************************************************************** + +create_clock -name {SPI_SCK} -period 41.666 -waveform { 20.8 41.666 } [get_ports {SPI_SCK}] + +set sdram_clk "pll|altpll_component|auto_generated|pll1|clk[0]" +set sys_clk "pll|altpll_component|auto_generated|pll1|clk[1]" +#************************************************************** +# Create Generated Clock +#************************************************************** + + +#************************************************************** +# Set Clock Latency +#************************************************************** + + + +#************************************************************** +# Set Clock Uncertainty +#************************************************************** + +#************************************************************** +# Set Input Delay +#************************************************************** + +set_input_delay -add_delay -clock_fall -clock [get_clocks {CLOCK_27}] 1.000 [get_ports {CLOCK_27}] +set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {CONF_DATA0}] +set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_DI}] +set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_SCK}] +set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_SS2}] +set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_SS3}] + +set_input_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -max 6.6 [get_ports SDRAM_DQ[*]] +set_input_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -min 3.5 [get_ports SDRAM_DQ[*]] + +#************************************************************** +# Set Output Delay +#************************************************************** + +set_output_delay -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_DO}] +set_output_delay -clock [get_clocks $sys_clk] 1.000 [get_ports {AUDIO_L}] +set_output_delay -clock [get_clocks $sys_clk] 1.000 [get_ports {AUDIO_R}] +set_output_delay -clock [get_clocks $sys_clk] 1.000 [get_ports {LED}] +set_output_delay -clock [get_clocks $sys_clk] 1.000 [get_ports {VGA_*}] + +set_output_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -max 1.5 [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}] +set_output_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -min -0.8 [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}] + +#************************************************************** +# Set Clock Groups +#************************************************************** + +set_clock_groups -asynchronous -group [get_clocks {SPI_SCK}] -group [get_clocks {pll|altpll_component|auto_generated|pll1|clk[*]}] + +#************************************************************** +# Set False Path +#************************************************************** + + + +#************************************************************** +# Set Multicycle Path +#************************************************************** + +set_multicycle_path -to {VGA_*[*]} -setup 2 +set_multicycle_path -to {VGA_*[*]} -hold 1 + +#************************************************************** +# Set Maximum Delay +#************************************************************** + + + +#************************************************************** +# Set Minimum Delay +#************************************************************** + + + +#************************************************************** +# Set Input Transition +#************************************************************** + diff --git a/Arcade_MiST/Konami Jackal/README.md b/Arcade_MiST/Konami Jackal/README.md new file mode 100644 index 00000000..c4895a92 --- /dev/null +++ b/Arcade_MiST/Konami Jackal/README.md @@ -0,0 +1,11 @@ +# MiST port of Konami Jackal by ACE + +https://github.com/MiSTer-devel/Arcade-Jackal_MiSTer + +## Usage + +- Create ROM and ARC files from the MRA files using the MRA utility. + Example: mra -A -z /path/to/mame/roms "Jackal.mra" +- Copy the ROM files to the root of the SD Card +- Copy the RBF and ARC files to the same folder on the SD Card +- MRA utility: https://github.com/sebdel/mra-tools-c/ \ No newline at end of file diff --git a/Arcade_MiST/Konami Jackal/meta/Jackal (W) [bl].mra b/Arcade_MiST/Konami Jackal/meta/Jackal (W) [bl].mra new file mode 100644 index 00000000..069494b0 --- /dev/null +++ b/Arcade_MiST/Konami Jackal/meta/Jackal (W) [bl].mra @@ -0,0 +1,75 @@ + + Jackal (bootleg) + World + no + yes + + + + + 1986 + Konami + Shooter - Multidirectional + + jackalbl + jackal + 0224 + Jackal + + + 15kHz + vertical (cw) + no + + 2 (simultaneous) + 8-way + + 2 + + + + + + + + + + + + + + + + 01 + + + + + + + + + + + + + + + + + + 0E 00 00 00 00 FF 00 02 + 00 02 00 01 00 FF 00 00 + 00 00 72 F8 00 27 00 1D + 00 00 73 40 00 03 00 00 + 00 00 73 41 00 01 02 02 + + + + + + + + + 20210708094853 + diff --git a/Arcade_MiST/Konami Jackal/meta/Jackal (W).mra b/Arcade_MiST/Konami Jackal/meta/Jackal (W).mra new file mode 100644 index 00000000..2dcff8db --- /dev/null +++ b/Arcade_MiST/Konami Jackal/meta/Jackal (W).mra @@ -0,0 +1,74 @@ + + Jackal + World + no + no + 8-Way Joystick + + + + 1986 + Konami + Shooter - Multidirectional + + jackal + jackal + 0224 + Jackal + + + 15kHz + vertical (cw) + no + + 2 (simultaneous) + 8-way + + 2 + + + + + + + + + + + + + + + + 00 + + + + + + + + + + + + + + + + + 11 90 00 00 00 FF 00 02 + 00 02 00 01 00 FF 00 00 + 00 00 72 F8 00 27 00 1D + 00 00 73 40 00 03 00 00 + 00 00 73 41 00 01 02 02 + + + + + + + + + 20210708094853 + diff --git a/Arcade_MiST/Konami Jackal/meta/Jackal (W, Rotary).mra b/Arcade_MiST/Konami Jackal/meta/Jackal (W, Rotary).mra new file mode 100644 index 00000000..05014911 --- /dev/null +++ b/Arcade_MiST/Konami Jackal/meta/Jackal (W, Rotary).mra @@ -0,0 +1,74 @@ + + Jackal (Rotary Joystick) + World + no + no + Rotary Joystick + + + + 1986 + Konami + Shooter - Multidirectional + + jackalr + jackal + 0224 + Jackal + + + 15kHz + vertical (cw) + no + + 2 (simultaneous) + 8-way + Rotary + 2 + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + 11 90 00 00 00 FF 00 02 + 00 02 00 01 00 FF 00 00 + 00 00 72 F8 00 27 00 1D + 00 00 73 40 00 03 00 00 + 00 00 73 41 00 01 02 02 + + + + + + + + + 20210708094853 + diff --git a/Arcade_MiST/Konami Jackal/meta/Tokushu Butai Jackal (JP).mra b/Arcade_MiST/Konami Jackal/meta/Tokushu Butai Jackal (JP).mra new file mode 100644 index 00000000..691a3170 --- /dev/null +++ b/Arcade_MiST/Konami Jackal/meta/Tokushu Butai Jackal (JP).mra @@ -0,0 +1,74 @@ + + Tokushu Butai Jackal + Japan + no + no + + + + + 1986 + Konami + Shooter - Multidirectional + + jackalj + jackal + 0224 + Jackal + + + 15kHz + vertical (cw) + no + + 2 (simultaneous) + 8-way + + 2 + + + + + + + + + + + + + + + + 00 + + + + + + + + + + + + + + + + + 11 90 00 00 00 FF 00 02 + 00 02 00 01 00 FF 00 00 + 00 00 72 F8 00 27 00 1D + 00 00 73 40 00 03 00 00 + 00 00 73 41 00 01 02 02 + + + + + + + + + 20210708094853 + diff --git a/Arcade_MiST/Konami Jackal/meta/Top Gunner (US) [bl].mra b/Arcade_MiST/Konami Jackal/meta/Top Gunner (US) [bl].mra new file mode 100644 index 00000000..a031b7de --- /dev/null +++ b/Arcade_MiST/Konami Jackal/meta/Top Gunner (US) [bl].mra @@ -0,0 +1,75 @@ + + Top Gunner (bootleg) + US + no + yes + + + + + 1986 + Konami + Shooter - Multidirectional + + topgunbl + jackal + 0224 + Jackal + + + 15kHz + vertical (cw) + no + + 2 (simultaneous) + 8-way + + 2 + + + + + + + + + + + + + + + + 01 + + + + + + + + + + + + + + + + + + 0E 00 00 00 00 FF 00 02 + 00 02 00 01 00 FF 00 00 + 00 00 72 F8 00 27 00 1D + 00 00 73 40 00 03 00 00 + 00 00 73 41 00 01 02 02 + + + + + + + + + 20210708094853 + diff --git a/Arcade_MiST/Konami Jackal/meta/Top Gunner (US).mra b/Arcade_MiST/Konami Jackal/meta/Top Gunner (US).mra new file mode 100644 index 00000000..33b51aaa --- /dev/null +++ b/Arcade_MiST/Konami Jackal/meta/Top Gunner (US).mra @@ -0,0 +1,74 @@ + + Top Gunner + US + no + no + + + + + 1986 + Konami + Shooter - Multidirectional + + topgunr + jackal + 0224 + Jackal + + + 15kHz + vertical (cw) + no + + 2 (simultaneous) + 8-way + + 2 + + + + + + + + + + + + + + + + 00 + + + + + + + + + + + + + + + + + 11 90 00 00 00 FF 00 02 + 00 02 00 01 00 FF 00 00 + 00 00 72 F8 00 27 00 1D + 00 00 73 40 00 03 00 00 + 00 00 73 41 00 01 02 02 + + + + + + + + + 20210708094853 + diff --git a/Arcade_MiST/Konami Jackal/rtl/Jackal.sv b/Arcade_MiST/Konami Jackal/rtl/Jackal.sv new file mode 100644 index 00000000..4feecdc9 --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/Jackal.sv @@ -0,0 +1,566 @@ +//============================================================================ +// +// Jackal PCB model +// Copyright (C) 2020, 2021 Ace, brknglass, Ash Evans (aka ElectronAsh/OzOnE), +// Shane Lynch, JimmyStones and 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. +// +//============================================================================ + +//Module declaration, I/O ports +module Jackal +( + input reset, + input clk_49m, //Actual frequency: 49.152MHz + input [1:0] coins, + input btn_service, + 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 [7:0] p1_rotary, p2_rotary, + input [1:0] p1_buttons, p2_buttons, //2 buttons per player + + input [19:0] dipsw, + + //The following flag is used to reconfigure the 005885s' video timings, logic for drawing sprites and audio + //filtering to reproduce the errors found on bootleg Jackal 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, + + //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 signed [15:0] sound_l, sound_r, + output video_hsync, video_vsync, + output video_csync, //CSync not needed for MiSTer + output video_vblank, video_hblank, + output [4:0] video_r, video_g, video_b, + + input ioctl_clk, + input [24:0] ioctl_addr, + input [7:0] ioctl_data, + input ioctl_wr, + + input pause, + + input [12:0] hs_address, + input [7:0] hs_data_in, + output [7:0] hs_data_out, + input hs_write, + input hs_access, + + //SDRAM signals + output reg [16: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 [16:1] char1_rom_addr, + input [15:0] char1_rom_do, + output reg [16:1] char2_rom_addr, + input [15:0] char2_rom_do, + output sp1_req, + input sp1_ack, + output [16:1] sp1_rom_addr, + input [15:0] sp1_rom_do, + output sp2_req, + input sp2_ack, + output [16:1] sp2_rom_addr, + input [15:0] sp2_rom_do +); + +//------------------------------------------------------- Clock division -------------------------------------------------------// + +//Generate 6.144MHz and 3.072MHz clock enables (clock division is normally handled inside the primary Konami 005885) +reg [3:0] div = 4'd0; +always_ff @(posedge clk_49m) begin + div <= div + 4'd1; +end + +wire cen_6m = !div[2:0]; +wire n_cen_6m = div[2:0] == 3'b100; +wire cen_3m = !div; + +//Phase generator for MC6809E (taken from MiSTer Vectrex core) +//Normally handled internally on the primary Konami 005885 +reg mE = 0; +reg mQ = 0; +reg sE = 0; +reg sQ = 0; +always_ff @(posedge clk_49m) begin + reg [1:0] clk_phase = 0; + mE <= 0; + mQ <= 0; + sE <= 0; + sQ <= 0; + if(cen_6m) begin + clk_phase <= clk_phase + 1'd1; + case(clk_phase) + 2'b00: sE <= 1; + 2'b01: mE <= 1; + 2'b10: sQ <= 1; + 2'b11: mQ <= 1; + endcase + end +end + +//Fractional divider to obtain sound clock (implementation by Jotego as part of JTFRAME) +//The PCB uses a 3.579545MHz oscillator directly connected to its YM2151 - this fractional divider replaces it as 3.579545MHz is +//not divisible by any integer factor of the main clock +//Also use this divider to generate a clock enable for jt49_dcrm2 to high-pass filter the YM2151's sound for original Jackal ROM +//sets +wire cen_3m58, cen_1m79; +wire cen_dcrm; +jtframe_frac_cen #(4) jt51_cen +( + .clk(clk_49m), + .n(10'd60), + .m(10'd824), + .cen({cen_dcrm, 1'bZ, cen_1m79, cen_3m58}) +); + +//------------------------------------------------------------ CPUs ------------------------------------------------------------// + +//Main CPU (Motorola MC6809E - uses synchronous version of Greg Miller's cycle-accurate MC6809E made by Sorgelig) +wire maincpu_rw; +wire [15:0] maincpu_A; +wire [7:0] maincpu_Din, maincpu_Dout; + +mc6809is u16A +( + .CLK(clk_49m), + .fallE_en(mE), + .fallQ_en(mQ), + .D(maincpu_Din), + .DOut(maincpu_Dout), + .ADDR(maincpu_A), + .RnW(maincpu_rw), + .nIRQ(irq), + .nFIRQ(1), + .nNMI(1), + .nHALT(pause), + .nRESET(reset), + .nDMABREQ(1) +); +//Address decoding for data inputs to Main CPU +wire cs_controls_dip1_dip3 = ~n_iocs & (maincpu_A[3:2] == 2'b00) & maincpu_rw; +wire cs_rotary = ~n_iocs & (maincpu_A[3:2] == 2'b01) & maincpu_rw; +wire cs_dip2 = ~n_iocs & (maincpu_A[3:2] == 2'b10) & maincpu_rw; +wire cs_bankswitch = ~n_iocs & (maincpu_A[3:2] == 2'b11) & ~maincpu_rw; +wire cs_mainsharedram = (maincpu_A >= 16'h0060 & maincpu_A <= 16'h1FFF); +wire cs_eprom1 = (maincpu_A[15:14] == 2'b01 | maincpu_A[15:14] == 2'b10) & maincpu_rw; +wire cs_eprom2 = (maincpu_A[15:14] == 2'b11 & maincpu_rw); +//Some of Jackal's address decoding logic is implemented in a PAL chip marked by Konami as the 007343 - instantiate an +//implementation of this IC here +wire n_cs_main_k005885, n_cs_sec_k005885, n_iocs; +k007343 u12D +( + .A4(maincpu_A[4]), + .A5(maincpu_A[5]), + .A6(maincpu_A[6]), + .A7(maincpu_A[7]), + .A8_9(maincpu_A[8] | maincpu_A[9]), + .A10(maincpu_A[10]), + .A11(maincpu_A[11]), + .A12(maincpu_A[12]), + .A13(maincpu_A[13]), + .WR(maincpu_rw), + .OBJB(vram_bank), + .GATEB(zram_bank), + .GATECS(maincpu_A[15:14] != 2'b00), + .MGCS(n_cs_main_k005885), + .SGCS(n_cs_sec_k005885), + .IOCS(n_iocs) + //.CRCS +); +//Multiplex data inputs to main CPU +assign maincpu_Din = (~n_cs_main_k005885 & maincpu_rw) ? main_k005885_Dout: + (~n_cs_sec_k005885 & maincpu_rw) ? sec_k005885_Dout: + cs_controls_dip1_dip3 ? controls_dip1_dip3: + cs_rotary ? rotary: + cs_dip2 ? dipsw[15:8]: + (cs_mainsharedram & maincpu_rw) ? m_sharedram_D: + cs_eprom1 ? eprom1_D: + cs_eprom2 ? eprom2_D: + 8'hFF; + +//Primary game ROM +always @(posedge clk_49m) + if (|maincpu_A[15:14] & maincpu_rw) + main_cpu_rom_addr <= {maincpu_A[15:14] == 2'b11, maincpu_A[15:14] != 2'b11 & eprom1_bank, ~maincpu_A[14], maincpu_A[13:0]}; + +wire [7:0] eprom1_D = main_cpu_rom_do; +//Secondary game ROM +wire [7:0] eprom2_D = main_cpu_rom_do; + +//Bankswitching for primary game ROM, ZRAM + VRAM and sprite RAM +reg eprom1_bank = 0; +reg zram_bank = 0; +reg vram_bank = 0; +always_ff @(posedge clk_49m) begin + if(!reset) begin + eprom1_bank <= 0; + zram_bank <= 0; + vram_bank <= 0; + end + else if(cen_3m) begin + if(cs_bankswitch) begin + eprom1_bank <= maincpu_Dout[5]; + zram_bank <= maincpu_Dout[4]; + vram_bank <= maincpu_Dout[3]; + end + end +end + +// Hiscore mux +wire [12:0] u14B_addr = hs_access ? hs_address[12:0] : maincpu_A[12:0]; +wire [7:0] u14B_din = hs_access ? hs_data_in : maincpu_Dout; +wire u14B_wren = hs_access ? hs_write : (cs_mainsharedram & ~maincpu_rw); +wire [7:0] u14B_dout; +assign m_sharedram_D = hs_access ? 8'h00 : u14B_dout; +assign hs_data_out = hs_access ? u14B_dout : 8'h00; + +//Shared RAM +wire [7:0] m_sharedram_D, s_sharedram_D; +dpram_dc #(.widthad_a(13)) u14B +( + .clock_a(clk_49m), + .address_a(u14B_addr), + .data_a(u14B_din), + .q_a(u14B_dout), + .wren_a(u14B_wren), + + .clock_b(clk_49m), + .address_b(soundcpu_A[12:0]), + .data_b(soundcpu_Dout), + .q_b(s_sharedram_D), + .wren_b(cs_soundsharedram & ~soundcpu_rw) +); + +//Secondary CPU (Motorola MC6809E - uses synchronous version of Greg Miller's cycle-accurate MC6809E made by Sorgelig) +wire soundcpu_rw; +wire [15:0] soundcpu_A; +wire [7:0] soundcpu_Din, soundcpu_Dout; + +mc6809is u11A +( + .CLK(clk_49m), + .fallE_en(sE), + .fallQ_en(sQ), + .D(soundcpu_Din), + .DOut(soundcpu_Dout), + .ADDR(soundcpu_A), + .RnW(soundcpu_rw), + .nIRQ(1), + .nFIRQ(1), + .nNMI(irq), + .nHALT(1), + .nRESET(reset), + .nDMABREQ(1) +); +//Address decoding for data inputs to sound CPU +wire cs_ym2151 = (soundcpu_A[15:13] == 3'b001); +wire cs_k007327 = (soundcpu_A[15:13] == 3'b010); +wire cs_soundsharedram = (soundcpu_A[15:13] == 3'b011); +wire cs_eprom3 = (soundcpu_A[15] & soundcpu_rw); +//Multiplex data inputs to sound CPU +assign soundcpu_Din = (cs_ym2151 & soundcpu_rw) ? ym2151_Dout: + (cs_k007327 & soundcpu_rw) ? k007327_D: + (cs_soundsharedram & soundcpu_rw) ? s_sharedram_D: + cs_eprom3 ? eprom3_D: + 8'hFF; + +//Sound ROM +always @(posedge clk_49m) + if (cs_eprom3) sub_cpu_rom_addr <= soundcpu_A[14:0]; + +wire [7:0] eprom3_D = sub_cpu_rom_do; +//--------------------------------------------------- Controls & DIP switches --------------------------------------------------// + +//Multiplex player inputs with DIP switch banks 1 and 3 +wire [7:0] controls_dip1_dip3 = maincpu_A[1:0] == 2'b00 ? dipsw[7:0]: + maincpu_A[1:0] == 2'b01 ? {dipsw[19], 1'b1, p1_buttons, p1_joystick}: + maincpu_A[1:0] == 2'b10 ? {2'b1, p2_buttons, p2_joystick}: + maincpu_A[1:0] == 2'b11 ? {dipsw[18:16], btn_start[1:0], btn_service, coins}: + 8'hFF; + +//Multiplex rotary controls for supported ROM sets +wire [7:0] rotary = maincpu_A[1:0] == 2'b00 ? p1_rotary: + maincpu_A[1:0] == 2'b01 ? p2_rotary: + 8'hFF; + +//--------------------------------------------------- Video timing & graphics --------------------------------------------------// + +//Konami 005885 custom chip - this is a large ceramic pin-grid array IC responsible for the majority of Jackal's critical +//functions: IRQ generation, clock dividers and all video logic for generating tilemaps and sprites +//Jackal contains two of these in parallel - this instance is the primary tilemap generator +wire [15:0] gfxrom0_Atile, gfxrom0_Asprite; +wire [7:0] main_k005885_Dout; +wire [4:0] main_color; +wire [3:0] main_tile_data; //Jackal does not use a lookup table for tiles; tile data is fed back to the 005885 directly +wire [3:0] ocf0, ocb0; +wire tile_attrib_D4, tile_attrib_D5; +wire e, q, irq; +k005885 u11F +( + .CK49(clk_49m), + .NRD(~maincpu_rw), + .A(maincpu_A[13:0]), + .DBi(maincpu_Dout), + .DBo(main_k005885_Dout), + .R(gfxrom0_Atile), + .RDU(gfxrom0_Dtile[15:8]), + .RDL(gfxrom0_Dtile[7:0]), + .S(gfxrom0_Asprite), + .S_req(sp1_req), + .S_ack(sp1_ack), + .SDU(gfxrom0_Dsprite[15:8]), + .SDL(gfxrom0_Dsprite[7:0]), + .VCB(main_tile_data), + .VCD(main_tile_data), + .OCF(ocf0), + .OCB(ocb0), + .OCD(prom1_D), + .COL(main_color), + .NEXR(reset), + .NXCS(n_cs_main_k005885), + .NCSY(video_csync), + .NHSY(video_hsync), + .NVSY(video_vsync), + .HBLK(video_hblank), + .VBLK(video_vblank), + .NCPE(e), + .NCPQ(q), + .NIRQ(irq), + .ATR4(tile_attrib_D4), + .ATR5(tile_attrib_D5), + .HCTR(h_center), + .VCTR(v_center), + .BTLG(is_bootleg) +); + +//Graphics ROMs for primary 005885 tilemap generator (sprites only) +assign sp1_rom_addr = gfxrom0_Asprite[15:0]; +wire [15:0] gfxrom0_Dsprite = sp1_rom_do; +//Sprite LUT PROM for primary 005885 tilemap generator +wire [3:0] prom1_D; +wire prom1_cs_i = ioctl_addr[24:8] == 16'h0A00; +dpram_dc #(.widthad_a(8)) u9H +( + .clock_a(clk_49m), + .address_a({ocf0, ocb0}), + .q_a(prom1_D), + + .clock_b(ioctl_clk), + .address_b(ioctl_addr[7:0]), + .data_b(ioctl_data), + .wren_b(prom1_cs_i & ioctl_wr) +); + +//Konami 005885 custom chip - this is a large ceramic pin-grid array IC responsible for the majority of Jackal's critical +//functions: IRQ generation, clock dividers and all video logic for generating tilemaps and sprites +//Jackal contains two of these in parallel - this instance is the secondary tilemap generator +wire [15:0] gfxrom1_Atile, gfxrom1_Asprite; +wire [7:0] sec_k005885_Dout; +wire [4:0] sec_color; +wire [3:0] sec_tile_data; //Jackal does not use a lookup table for tiles; tile data is fed back to the 005885 directly +wire [3:0] ocf1, ocb1; +k005885 u14F +( + .CK49(clk_49m), + .NRD(~maincpu_rw), + .A(maincpu_A[13:0]), + .DBi(maincpu_Dout), + .DBo(sec_k005885_Dout), + .R(gfxrom1_Atile), + .RDU(gfxrom1_Dtile[15:8]), + .RDL(gfxrom1_Dtile[7:0]), + .S(gfxrom1_Asprite), + .S_req(sp2_req), + .S_ack(sp2_ack), + .SDU(gfxrom1_Dsprite[15:8]), + .SDL(gfxrom1_Dsprite[7:0]), + .VCB(sec_tile_data), + .VCD(sec_tile_data), + .OCF(ocf1), + .OCB(ocb1), + .OCD(prom2_D), + .COL(sec_color), + .NEXR(reset), + .NXCS(n_cs_sec_k005885), + .BTLG(is_bootleg) +); + +//Graphics ROMs for secondary 005885 tilemap generator (sprites only) +assign sp2_rom_addr = gfxrom1_Asprite[15:0]; +wire [15:0] gfxrom1_Dsprite = sp2_rom_do; + +//Graphics ROMs (tilemaps only) for both 005885 tilemap generators (accessed externally from SDRAM) +wire [15:0] gfxrom0_Dtile, gfxrom1_Dtile; + +always_ff @(posedge clk_49m) begin + char1_rom_addr <= {tile_attrib_D5, tile_attrib_D4, gfxrom0_Atile[13:0]}; + char2_rom_addr <= {tile_attrib_D5, tile_attrib_D4, gfxrom1_Atile[13:0]}; +end + +assign gfxrom0_Dtile = char1_rom_do; +assign gfxrom1_Dtile = char2_rom_do; + +//Sprite LUT PROM for secondary 005885 tilemap generator +wire [3:0] prom2_D; +wire prom2_cs_i = ioctl_addr[24:8] == 16'h0A01; +dpram_dc #(.widthad_a(8)) u14H +( + .clock_a(clk_49m), + .address_a({ocf1, ocb1}), + .q_a(prom2_D), + + .clock_b(ioctl_clk), + .address_b(ioctl_addr[7:0]), + .data_b(ioctl_data), + .wren_b(prom2_cs_i & ioctl_wr) +); + +//--------------------------------------------------------- Sound chip ---------------------------------------------------------// + +//Sound chip - Yamaha YM2151 (uses JT51 implementation by Jotego) +wire [7:0] ym2151_Dout; +wire signed [15:0] sound_l_raw, sound_r_raw; +wire [15:0] unsgined_sound_l_raw, unsgined_sound_r_raw; +jt51 u8C +( + .rst(~reset), + .clk(clk_49m), + .cen(cen_3m58), + .cen_p1(cen_1m79), + .cs_n(~cs_ym2151), + .wr_n(soundcpu_rw), + .a0(soundcpu_A[0]), + .din(soundcpu_Dout), + .dout(ym2151_Dout), + .xleft(sound_l_raw), + .xright(sound_r_raw), + .dacleft(unsgined_sound_l_raw), + .dacright(unsgined_sound_r_raw) +); + +//----------------------------------------------------- Final video output -----------------------------------------------------// + +//Multiplex color data from tilemap generators for color RAM +wire color_sel = (main_color[4] & sec_color[4]); +wire [3:0] color_mux = main_color[4] ? sec_color[3:0] : main_color[3:0]; +wire [7:0] color_bus = color_sel ? {main_color[3:0], sec_color[3:0]} : {3'b000, main_color[4], color_mux}; + +//Write enable logic for palette RAM +reg n_sQ_lat = 1; +wire n_sQlat_clr = (e & ~soundcpu_rw); +always_ff @(posedge clk_49m or negedge n_sQlat_clr) begin + if(!n_sQlat_clr) + n_sQ_lat <= 1; + else if(cen_6m) + n_sQ_lat <= ~q; +end +wire n_k007327_we = (~cs_k007327 | n_sQ_lat); + +//Multiplex the upper 4 address lines of palette RAM +wire [11:8] ra = cs_k007327 ? soundcpu_A[11:8] : {2'b00, color_sel, color_bus[7]}; + +//Blank input to palette RAM (black out the signal when all but the uppermost bit of each 005885's color outputs +//are all set to 0) +//This signal does not exist on bootleg Jackal PCBs +wire blank = (is_bootleg == 2'b01) ? 1'b1 : ((|main_color[3:0]) | (|sec_color[3:0])); + +//Konami 007327 custom module - integrates palette RAM along with its multiplexing and write enable logic (multiplexing +//logic only covers bits [7:0], the others are generated externally) +//This module normally is analog-only as it also integrates the video DAC - for this FPGA implementation of Jackal, +//the digital video data can be tapped directly +wire [7:0] k007327_D; +k007327 u1H +( + .CLK(clk_49m), + .CEN(n_cen_6m), + .RA(ra), + .A(soundcpu_A[7:0]), + .NA0(~soundcpu_A[0]), + .CB(color_bus[6:0]), + .Di(soundcpu_Dout), + .RW(~soundcpu_rw), + .SEL(~cs_k007327), + .CCS(~cs_k007327), + .CWR(n_k007327_we), + .BLK(blank), + .R(video_r), + .G(video_g), + .B(video_b), + .Do(k007327_D) +); + +//----------------------------------------------------- Final audio output -----------------------------------------------------// + +//The original Jackal PCB applies high-pass filtering at around 80Hz - use Jotego's jt49_dcrm2 module to apply this high-pass +//filtering with JT51's unsigned output +//TODO: Replace this with a proper high-pass filter +wire signed [15:0] sound_l_hpf, sound_r_hpf; +jt49_dcrm2 #(16) hpf_left +( + .clk(clk_49m), + .cen(cen_dcrm), + .rst(~reset), + .din(unsigned_sound_l_atten), + .dout(sound_l_hpf) +); +jt49_dcrm2 #(16) hpf_right +( + .clk(clk_49m), + .cen(cen_dcrm), + .rst(~reset), + .din(unsigned_sound_r_atten), + .dout(sound_r_hpf) +); + +//Jackal produces sound out of the YM2151 at a significantly higher volume than most other games on the MiSTer platform - apply +//6dB attenuation for better balance with other cores +wire [15:0] unsigned_sound_l_atten = unsgined_sound_l_raw >> 1; +wire [15:0] unsigned_sound_r_atten = unsgined_sound_r_raw >> 1; +wire signed [15:0] sound_l_atten = sound_l_raw >>> 1; +wire signed [15:0] sound_r_atten = sound_r_raw >>> 1; + +//Jackal employs a 4.823KHz low-pass filter for its YM2151 - filter the audio accordingly here and output the end result +//The original PCB also has a variable low-pass filter that applies heavier filtering the higher the volume is set - apply this +//extra low-pass filter when original ROMs are used (controlled by the is_bootleg flag - this filter and the 80Hz high-pass filter +//are absent on bootleg ROM sets) +jackal_lpf lpf_left +( + .clk(clk_49m), + .reset(~reset), + .select(is_bootleg[0]), + .in1(sound_l_atten), + .in2(sound_l_hpf), + .out(sound_l) +); +jackal_lpf lpf_right +( + .clk(clk_49m), + .reset(~reset), + .select(is_bootleg[0]), + .in1(sound_r_atten), + .in2(sound_r_hpf), + .out(sound_r) +); + +endmodule diff --git a/Arcade_MiST/Konami Jackal/rtl/Jackal_MiST.sv b/Arcade_MiST/Konami Jackal/rtl/Jackal_MiST.sv new file mode 100644 index 00000000..4bd94dab --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/Jackal_MiST.sv @@ -0,0 +1,360 @@ +module Jackal_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 = { + "JACKAL;;", + "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,Rotary speed,Normal,Fast;", + "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 rotary_speed = status[1]; + +wire [1:0] orientation = 2'b11; +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 [15:0] audio_l, audio_r; +wire hs, vs, cs; +wire hb, vb; +wire blankn = ~(hb | vb); +wire [4:0] r, g, b; +wire key_strobe; +wire key_pressed; +wire [7:0] key_code; + +wire [16:0] main_rom_addr; +wire [15:0] main_rom_do; +wire [14:0] sub_rom_addr; +wire [15:0] sub_rom_do; +wire [15:0] ch1_addr; +wire [15:0] ch1_do; +wire [15:0] ch2_addr; +wire [15:0] ch2_do; +wire sp1_req, sp1_ack; +wire [15:0] sp1_addr; +wire [15:0] sp1_do; +wire sp2_req, sp2_ack; +wire [15:0] sp2_addr; +wire [15:0] sp2_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_98 ), + .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 - 18'h20000; + +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[16:1] ), + .cpu1_q ( main_rom_do ), + .cpu2_addr ( ioctl_downl ? 16'h0000 : sub_rom_addr[14:1] + 16'hc000 ), + .cpu2_q ( sub_rom_do ), + + // port2 for graphics + .port2_req ( port2_req ), + .port2_ack ( ), + .port2_a ( {bg_ioctl_addr[23:18], bg_ioctl_addr[16:0]} ), // merge gfx roms to 16-bit wide words + .port2_ds ( {~bg_ioctl_addr[17], bg_ioctl_addr[17]} ), + .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 ( ioctl_downl ? 16'hffff : ch2_addr ), + .ch2_q ( ch2_do ), + .sp1_req ( sp1_req ), + .sp1_ack ( sp1_ack ), + .sp1_addr ( ioctl_downl ? 16'hffff : sp1_addr ), + .sp1_q ( sp1_do ), + .sp2_req ( sp2_req ), + .sp2_ack ( sp2_ack ), + .sp2_addr ( ioctl_downl ? 16'hffff : sp2_addr ), + .sp2_q ( sp2_do ) +); + +// ROM download controller +always @(posedge clock_98) 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 + +Jackal Jackal( + .reset(~reset), + .clk_49m(clock_49), + .coins({~m_coin2,~m_coin1}), + .btn_start({~m_two_players,~m_one_player}), + .p1_joystick({~m_down, ~m_up, ~m_right, ~m_left}), + .p2_joystick({~m_down2, ~m_up2, ~m_right2, ~m_left2}), + .p1_rotary(~p1_rotary), + .p2_rotary(~p2_rotary), + .p1_buttons({~m_fireB, ~m_fireA}), + .p2_buttons({~m_fire2B, ~m_fire2A}), + .btn_service(~service), + .dipsw(dip_sw), + .is_bootleg(is_bootleg), + .video_hsync(hs), + .video_vsync(vs), + .video_csync(cs), + .video_hblank(hb), + .video_vblank(vb), + .video_r(r), + .video_g(g), + .video_b(b), + .sound_l(audio_l), + .sound_r(audio_r), + .pause(1'b1), + .ioctl_clk(clock_98), + .ioctl_addr(ioctl_addr), + .ioctl_data(ioctl_dout), + .ioctl_wr(ioctl_wr), + + .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), + .char2_rom_addr(ch2_addr), + .char2_rom_do(ch2_do), + .sp1_req(sp1_req), + .sp1_ack(sp1_ack), + .sp1_rom_addr(sp1_addr), + .sp1_rom_do(sp1_do), + .sp2_req(sp2_req), + .sp2_ack(sp2_ack), + .sp2_rom_addr(sp2_addr), + .sp2_rom_do(sp2_do) +); + +mist_video #(.COLOR_DEPTH(5), .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 ) + ); + +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 ) + ); + +dac #(.C_bits(16))dac_l( + .clk_i(clock_49), + .res_n_i(1'b1), + .dac_i({~audio_l[15], audio_l[14:0]}), + .dac_o(AUDIO_L) + ); + +dac #(.C_bits(16))dac_r( + .clk_i(clock_49), + .res_n_i(1'b1), + .dac_i({~audio_r[15], audio_r[14:0]}), + .dac_o(AUDIO_R) + ); + +//Rotary controls (disable for bootleg ROM sets as although these support rotary controls, bootleg PCBs +//have no means of supporting rotary controls as there are no footprints for the required hardware) +//TODO: Map the inputs to absolute inputs using an analog stick (Jackal ignores out-of-order inputs) +reg [22:0] rotary_div = 23'd0; +reg [7:0] rotary1 = 8'h01; +reg [7:0] rotary2 = 8'h01; +wire m_rotary1_l = m_fireC; +wire m_rotary1_r = m_fireD; +wire m_rotary2_l = m_fire2C; +wire m_rotary2_r = m_fire2D; + +wire rotary_en = rotary_speed ? !rotary_div[21:0] : !rotary_div; +always_ff @(posedge clock_49) begin + rotary_div <= rotary_div + 23'd1; + if(rotary_en) begin + if(m_rotary1_l) begin + if(rotary1 != 8'h80) + rotary1 <= rotary1 << 1; + else + rotary1 <= 8'h01; + end + else if(m_rotary1_r) begin + if(rotary1 != 8'h01) + rotary1 <= rotary1 >> 1; + else + rotary1 <= 8'h80; + end + + if(m_rotary2_l) begin + if(rotary2 != 8'h80) + rotary2 <= rotary2 << 1; + else + rotary2 <= 8'h01; + end + else if(m_rotary2_r) begin + if(rotary2 != 8'h01) + rotary2 <= rotary2 >> 1; + else + rotary2 <= 8'h80; + end + end +end +wire [7:0] p1_rotary = (is_bootleg == 2'b01) ? 8'hFF : rotary1; +wire [7:0] p2_rotary = (is_bootleg == 2'b01) ? 8'hFF : rotary2; + +wire m_up, m_down, m_left, m_right, m_fireA, m_fireB, m_fireC, m_fireD, m_fireE, m_fireF; +wire m_up2, m_down2, m_left2, m_right2, m_fire2A, m_fire2B, m_fire2C, m_fire2D, m_fire2E, m_fire2F; +wire m_tilt, m_coin1, m_coin2, m_coin3, m_coin4, m_one_player, m_two_players, m_three_players, m_four_players; + +arcade_inputs inputs ( + .clk ( clock_49 ), + .key_strobe ( key_strobe ), + .key_pressed ( key_pressed ), + .key_code ( key_code ), + .joystick_0 ( joystick_0 ), + .joystick_1 ( joystick_1 ), + .rotate ( rotate ), + .orientation ( orientation ), + .joyswap ( joyswap ), + .oneplayer ( 1'b0 ), + .controls ( {m_tilt, m_coin4, m_coin3, m_coin2, m_coin1, m_four_players, m_three_players, m_two_players, m_one_player} ), + .player1 ( {m_fireF, m_fireE, m_fireD, m_fireC, m_fireB, m_fireA, m_up, m_down, m_left, m_right} ), + .player2 ( {m_fire2F, m_fire2E, m_fire2D, m_fire2C, m_fire2B, m_fire2A, m_up2, m_down2, m_left2, m_right2} ) +); + +endmodule diff --git a/Arcade_MiST/Konami Jackal/rtl/build_id.tcl b/Arcade_MiST/Konami Jackal/rtl/build_id.tcl new file mode 100644 index 00000000..938515d8 --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/build_id.tcl @@ -0,0 +1,35 @@ +# ================================================================================ +# +# Build ID Verilog Module Script +# Jeff Wiencrot - 8/1/2011 +# +# Generates a Verilog module that contains a timestamp, +# from the current build. These values are available from the build_date, build_time, +# physical_address, and host_name output ports of the build_id module in the build_id.v +# Verilog source file. +# +# ================================================================================ + +proc generateBuildID_Verilog {} { + + # Get the timestamp (see: http://www.altera.com/support/examples/tcl/tcl-date-time-stamp.html) + set buildDate [ clock format [ clock seconds ] -format %y%m%d ] + set buildTime [ clock format [ clock seconds ] -format %H%M%S ] + + # Create a Verilog file for output + set outputFileName "rtl/build_id.v" + set outputFile [open $outputFileName "w"] + + # Output the Verilog source + puts $outputFile "`define BUILD_DATE \"$buildDate\"" + puts $outputFile "`define BUILD_TIME \"$buildTime\"" + close $outputFile + + # Send confirmation message to the Messages window + post_message "Generated build identification Verilog module: [pwd]/$outputFileName" + post_message "Date: $buildDate" + post_message "Time: $buildTime" +} + +# Comment out this line to prevent the process from automatically executing when the file is sourced: +generateBuildID_Verilog \ No newline at end of file diff --git a/Arcade_MiST/Konami Jackal/rtl/custom/jackal_custom.qip b/Arcade_MiST/Konami Jackal/rtl/custom/jackal_custom.qip new file mode 100644 index 00000000..a122369d --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/custom/jackal_custom.qip @@ -0,0 +1,3 @@ +set_global_assignment -name SYSTEMVERILOG_FILE rtl/custom/k005885.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/custom/k007327.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/custom/k007343.sv diff --git a/Arcade_MiST/Konami Jackal/rtl/custom/k005885.sv b/Arcade_MiST/Konami Jackal/rtl/custom/k005885.sv new file mode 100644 index 00000000..f49fe4a5 --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/custom/k005885.sv @@ -0,0 +1,902 @@ +//============================================================================ +// +// 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, 2021 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 ATR4, //Tilemap attribute bit 4 + output ATR5, //Tilemap attribute bit 5 + + //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, + input hs_access +); + +//------------------------------------------------------- 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 = tileram_attrib_D[4]; +assign ATR5 = tileram_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) ? tileram_attrib_Dout: + (tile_cs & ~NRD) ? tileram_Dout: + (tile1_attrib_cs & ~NRD) ? tileram1_attrib_Dout: + (tile1_cs & ~NRD) ? tileram1_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 +reg [2:0] n_div = 3'd0; +always_ff @(negedge CK49) begin + n_div <= n_div + 3'd1; +end +wire cen_6m = !div[2:0]; +wire n_cen_6m = !n_div; +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 vblank_irq_en = 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 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) + 0: begin + vblank_irq_en <= 0; + h_cnt <= h_cnt + 9'd1; + end + //HBlank ends two lines earlier than normal on bootleg Jackal PCBs + 11: begin + if(BTLG == 2'b01) + hblank <= 0; + h_cnt <= h_cnt + 9'd1; + end + 13: 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 + 251: begin + if(BTLG == 2'b01) + hblank <= 1; + h_cnt <= h_cnt + 9'd1; + end + 253: begin + if(BTLG != 2'b01) + 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; + vblank_irq_en <= 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 -----------------------------------------------------------// + +//IRQ (triggers every VBlank) +reg vblank_irq = 1; +always_ff @(posedge CK49 or negedge NEXR) begin + if(!NEXR) + vblank_irq <= 1; + else if(cen_6m) begin + if(!irq_mask) + vblank_irq <= 1; + else if(vblank_irq_en) + vblank_irq <= 0; + end +end +assign NIRQ = vblank_irq; + +//NMI (triggers every 64 scanlines starting from scanline 48) +reg nmi = 1; +always_ff @(posedge CK49 or negedge NEXR) begin + if(!NEXR) + nmi <= 1; + else if(cen_3m) begin + if(!nmi_mask) + nmi <= 1; + else if((v_cnt[7:0] + 9'd16) % 9'd64 == 0) + nmi <= 0; + end +end +assign NNMI = nmi; + +//FIRQ (triggers every second VBlank) +reg firq = 1; +always_ff @(posedge CK49 or negedge NEXR) begin + if(!NEXR) + firq <= 1; + else if(cen_3m) begin + if(!firq_mask) + firq <= 1; + else if(!frame_odd_even && v_cnt == 9'd239) + 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, negedge NEXR) begin + if(!NEXR) begin + nmi_mask <= 1; + irq_mask <= 1; + firq_mask <= 1; + flipscreen <= 0; + end else 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] tileram_attrib_Dout, tileram_Dout, tileram1_attrib_Dout, tileram1_Dout, spriteram_Dout; +wire [7:0] tileram_attrib_D, tileram_D, tileram1_attrib_D, tileram1_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(tileram_attrib_Dout), + .wren_a(tile_attrib_cs & NRD), + + .clock_b(CK49), + .address_b(vram_A), + .q_b(tileram_attrib_D) +); +dpram_dc #(.widthad_a(10)) VRAM_TILECODE0 +( + .clock_a(CK49), + .address_a(A[9:0]), + .data_a(DBi), + .q_a(tileram_Dout), + .wren_a(tile_cs & NRD), + + .clock_b(CK49), + .address_b(vram_A), + .q_b(tileram_D) +); +//Tilemap layer 1 +dpram_dc #(.widthad_a(10)) VRAM_TILEATTRIB1 +( + .clock_a(CK49), + .address_a(A[9:0]), + .data_a(DBi), + .q_a(tileram1_attrib_Dout), + .wren_a(tile1_attrib_cs & NRD), + + .clock_b(CK49), + .address_b(vram_A), + .q_b(tileram1_attrib_D) +); +dpram_dc #(.widthad_a(10)) VRAM_TILECODE1 +( + .clock_a(CK49), + .address_a(A[9:0]), + .data_a(DBi), + .q_a(tileram1_Dout), + .wren_a(tile1_cs & NRD), + + .clock_b(CK49), + .address_b(vram_A), + .q_b(tileram1_D) +); + +// Hiscore mux (this is only to be used with Iron Horse as its high scores are stored in sprite RAM) +wire [11:0] VRAM_SPR_AD = hs_access ? hs_address : A[11:0]; +wire [7:0] VRAM_SPR_DIN = hs_access ? hs_data_in : DBi; +wire VRAM_SPR_WE = hs_access ? hs_write : (spriteram_cs & NRD); +wire [7:0] VRAM_SPR_DOUT; + +assign hs_data_out = hs_access ? VRAM_SPR_DOUT : 8'h00; +assign spriteram_Dout = hs_access ? 8'h00 : VRAM_SPR_DOUT; + +//Sprites +dpram_dc #(.widthad_a(12)) VRAM_SPR +( + .clock_a(CK49), + .address_a(VRAM_SPR_AD), + .data_a(VRAM_SPR_DIN), + .q_a(VRAM_SPR_DOUT), + .wren_a(VRAM_SPR_WE), + + .clock_b(~CK49), + .address_b(spriteram_A), + .q_b(spriteram_D) +); + +//-------------------------------------------------------- Tilemap layer -------------------------------------------------------// + +//TODO: The current implementation only handles one of the 005885's two tilemap layers - add logic to handle both layers + +//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 +wire [8:0] row_scroll = (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 [8:0] tilemap_hpos = hcnt_x + row_scroll; +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 = {tileram_attrib_D[7:6], tileram_D}; + +//XOR tile H/V flip bits with the flipscreen bit +wire tile_hflip = tileram_attrib_D[4]; +wire tile_vflip = tileram_attrib_D[5]; + +//Address output to graphics ROMs +assign R = {tile_ctrl[1:0], tile_index, (tilemap_vpos[2:0] ^ {3{tile_vflip}}), (tilemap_hpos[2] ^ tile_hflip)}; + +//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 +reg [15:0] RD_lat = 16'd0; +reg [3:0] tile_color = 4'd0; +reg tile_hflip_lat = 0; +reg old_tilehpos1; +always_ff @(posedge CK49) begin + old_tilehpos1 <= tilemap_hpos[1]; + if(old_tilehpos1 && !tilemap_hpos[1]) begin + tile_color <= tileram_attrib_D[3:0]; + RD_lat <= flipscreen ? {RDL, RDU} : {RDU, RDL}; + tile_hflip_lat <= tileram_attrib_D[4]; + end +end + +//Multiplex graphics ROM data down from 16 bits to 8 using bit 1 of the horizontal position +wire [7:0] RD = (tilemap_hpos[1] ^ tile_hflip_lat) ? RD_lat[7:0] : RD_lat[15:8]; + +//Further multiplex graphics ROM data down from 8 bits to 4 using bit 0 of the horizontal position +wire [3:0] tile_pixel = (tilemap_hpos[0] ^ tile_hflip_lat) ? RD[3:0] : RD[7:4]; + +//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]; +reg tilemap_en = 0; +always_ff @(posedge CK49) begin + if(n_cen_6m) begin + tilemap_en <= tile_sel; + end +end + +//Address output to tilemap LUT PROM +assign VCF = tile_color; +assign VCB = tile_pixel; + +//Shift the tilemap layer left by two lines when the screen is flipped +reg [7:0] tilemap_shift; +always_ff @(posedge CK49) begin + if(cen_6m) + tilemap_shift <= {VCD, tilemap_shift[7:4]}; +end +wire [3:0] tilemap_D = flipscreen ? tilemap_shift[3:0] : VCD; + +//-------------------------------------------------------- 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 [7:0] sprite_attrib0, sprite_attrib1, sprite_attrib2, sprite_attrib3, sprite_attrib4; +reg [2:0] sprite_fsm_state; +reg [5:0] sprite_width; +//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) +wire [8:0] sprite_limit = (BTLG == 2'b10) ? 9'd155 : 9'd485; +always_ff @(posedge CK49) begin + //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 == 9'd0 || (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(sprite_index > sprite_limit) + sprite_fsm_state <= 0; + else begin + sprite_attrib4 <= spriteram_D; + sprite_offset <= 3'd3; + sprite_fsm_state <= sprite_fsm_state + 3'd1; + end + end + 2: begin + sprite_attrib3 <= spriteram_D; + sprite_offset <= 3'd2; + sprite_fsm_state <= sprite_fsm_state + 3'd1; + end + 3: begin + //Skip the current sprite if it's inactive, otherwise obtain the sprite Y attribute and continue + //scanning out the rest of the sprite attributes + if(sprite_active) begin + sprite_attrib2 <= spriteram_D; + sprite_offset <= 3'd1; + 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 + 4: begin + sprite_attrib1 <= spriteram_D; + sprite_offset <= 3'd0; + sprite_fsm_state <= sprite_fsm_state + 3'd1; + end + 5: begin + sprite_attrib0 <= 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); + 3'b100: sprite_width <= 6'b100000 + (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 + +//Obtain sprite X position from sprite attribute byte 3 - append a 9th bit based on the state of bit 1 sprite attribute byte 4, +//bit 0 of sprite attribute byte 4 if high or the AND of the upper 5 bits of the horizontal position if low +reg sprite_x8; +always_ff @(posedge CK49) begin + if(sprite_attrib4[1]) + sprite_x8 <= sprite_attrib4[0]; + else + sprite_x8 <= &sprite_attrib3[7:3]; +end +wire [8:0] sprite_x = {sprite_x8 ^ flipscreen, sprite_attrib3 ^ {8{flipscreen}}}; + +//If the sprite state machine is in state 3, obtain sprite Y position directly from sprite RAM, otherwise obtain it from +//sprite attribute byte 2 +wire [7:0] sprite_y = (sprite_fsm_state == 3'd3) ? spriteram_D : sprite_attrib2; + +//Sprite flip attributes are stored in bits 5 (horizontal) and 6 (vertical) of sprite attribute byte 4 +//Also XOR these attributes with the flipscreen bit (XOR with the inverse for vertical flip) +wire sprite_hflip = sprite_attrib4[5] ^ flipscreen; +wire sprite_vflip = sprite_attrib4[6] ^ ~flipscreen; + +//Sprite code is sprite attribute byte 0 sandwiched between bits 1 and 0 and bits 3 and 2 of sprite attribute byte 1 +wire [11:0] sprite_code = {sprite_attrib1[1:0], sprite_attrib0, sprite_attrib1[3:2]}; + +//Sprite color is the upper 4 bits of sprite attribute byte 1 +wire [3:0] sprite_color = sprite_attrib1[7:4]; + +//The 005885 supports 5 different sprite sizes: 8x8, 8x16, 16x8, 16x16 and 32x32. Retrieve this attribute from bits [4:2] of +//sprite attribute byte 4 +wire [2:0] sprite_size = sprite_attrib4[4:2]; + +//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 +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 : sprite_hpos}; +end + +//Sprite line buffer +wire [3:0] lbuff_Dout; +dpram_dc #(.widthad_a(10)) LBUFF +( + .clock_a(CK49), + .address_a(lbuff_A), + .data_a({4'd0, lbuff_Din}), + .wren_a(lbuff_we & (lbuff_Din != 0)), + + .clock_b(CK49), + .address_b(radr0), + .data_b(8'h0), + .wren_b(radr0 == radr1), + .q_b({4'bZZZZ, lbuff_Dout}) +); + +//Latch sprite data from the sprite line buffer +wire lbuff_read_en = (div[2:0] == 3'b100); +reg [3:0] lbuff_read = 4'd0; +always_ff @(posedge CK49) begin + if(lbuff_read_en) begin + if(radr0 != radr1) + lbuff_read <= lbuff_Dout; + radr1 <= radr0; + end +end + +//Delay sprite layer by 2 horizontal lines (1 line if a bootleg Jackal ROM set is loaded and the screen is flipped) +reg [7:0] sprite_dly = 8'd0; +always_ff @(posedge CK49) begin + if(cen_6m) begin + if(BTLG == 2'b01 && flipscreen) + sprite_dly <= {4'd0, lbuff_read}; + else + sprite_dly <= {lbuff_read, sprite_dly[7:4]}; + end +end +//Jackal bootlegs fail to render the last two vertical lines of the sprite layer - model this behavior here +wire [3:0] sprite_D = (BTLG == 2'b01 && ((h_cnt >= 244 && ~flipscreen) || (h_cnt >= 248 && flipscreen))) ? 4'd0 : sprite_dly[3:0]; + +//--------------------------------------------------------- Color mixer --------------------------------------------------------// + +//Multiplex tile and sprite data, then output the final result +wire tile_sprite_sel = (tilemap_en | ~(|sprite_D)); +wire [3:0] tile_sprite_D = tile_sprite_sel ? tilemap_D : sprite_D; + +//Latch and output pixel data +reg [4:0] pixel_D; +always_ff @(posedge CK49) begin + if(cen_6m) + pixel_D <= {tile_sprite_sel, tile_sprite_D}; +end +assign COL = (BTLG == 2'b01 && ((h_cnt >= 247 && ~flipscreen) || (h_cnt <= 14 && flipscreen))) || + (BTLG == 2'b10 && ((h_cnt <= 20 && ~flipscreen) || ((h_cnt <= 18 || h_cnt >= 251) && flipscreen))) ? 5'd0 : pixel_D; +//The above condition blacks out the last 4 lines on the right side of the screen (left when flipped) when a bootleg Jackal ROM set +//is loaded and blacks out the left-most 8 lines (7 when flipped plus an extra 2 lines on the right side) when a bootleg Iron Horse +//ROM set is loaded - this simulates the earlier-than-normal start of HBlank for Jackal bootlegs and later-than-normal end of +//HBlank for Iron Horse bootlegs while maintaining the usual 240x224 display area + +endmodule diff --git a/Arcade_MiST/Konami Jackal/rtl/custom/k005885.sv.bakk b/Arcade_MiST/Konami Jackal/rtl/custom/k005885.sv.bakk new file mode 100644 index 00000000..243cd8eb --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/custom/k005885.sv.bakk @@ -0,0 +1,911 @@ +//============================================================================ +// +// 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, 2021 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) + 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 ATR4, //Tilemap attribute bit 4 + output ATR5, //Tilemap attribute bit 5 + + //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, + input hs_access +); + +//------------------------------------------------------- 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 = tileram_attrib_D[4]; +assign ATR5 = tileram_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) ? tileram_attrib_Dout: + (tile_cs & ~NRD) ? tileram_Dout: + (tile1_attrib_cs & ~NRD) ? tileram1_attrib_Dout: + (tile1_cs & ~NRD) ? tileram1_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 +reg [2:0] n_div = 3'd0; +always_ff @(negedge CK49) begin + n_div <= n_div + 3'd1; +end +wire cen_6m = !div[2:0]; +wire n_cen_6m = !n_div; +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 vblank_irq_en = 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 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) + 0: begin + vblank_irq_en <= 0; + h_cnt <= h_cnt + 9'd1; + end + //HBlank ends two lines earlier than normal on bootleg Jackal PCBs + 11: begin + if(BTLG == 2'b01) + hblank <= 0; + h_cnt <= h_cnt + 9'd1; + end + 13: 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 + 251: begin + if(BTLG == 2'b01) + hblank <= 1; + h_cnt <= h_cnt + 9'd1; + end + 253: begin + if(BTLG != 2'b01) + 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; + vblank_irq_en <= 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 -----------------------------------------------------------// + +//IRQ (triggers every VBlank) +reg vblank_irq = 1; +always_ff @(posedge CK49 or negedge NEXR) begin + if(!NEXR) + vblank_irq <= 1; + else if(cen_6m) begin + if(!irq_mask) + vblank_irq <= 1; + else if(vblank_irq_en) + vblank_irq <= 0; + end +end +assign NIRQ = vblank_irq; + +//NMI (triggers every 64 scanlines starting from scanline 48) +reg nmi = 1; +always_ff @(posedge CK49 or negedge NEXR) begin + if(!NEXR) + nmi <= 1; + else if(cen_3m) begin + if(!nmi_mask) + nmi <= 1; + else if((v_cnt[7:0] + 9'd16) % 9'd64 == 0) + nmi <= 0; + end +end +assign NNMI = nmi; + +//FIRQ (triggers every second VBlank) +reg firq = 1; +always_ff @(posedge CK49 or negedge NEXR) begin + if(!NEXR) + firq <= 1; + else if(cen_3m) begin + if(!firq_mask) + firq <= 1; + else if(!frame_odd_even && v_cnt == 9'd239) + 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 + 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] tileram_attrib_Dout, tileram_Dout, tileram1_attrib_Dout, tileram1_Dout, spriteram_Dout; +wire [7:0] tileram_attrib_D, tileram_D, tileram1_attrib_D, tileram1_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(tileram_attrib_Dout), + .wren_a(tile_attrib_cs & NRD), + + .clock_b(CK49), + .address_b(vram_A), + .q_b(tileram_attrib_D) +); +dpram_dc #(.widthad_a(10)) VRAM_TILECODE0 +( + .clock_a(CK49), + .address_a(A[9:0]), + .data_a(DBi), + .q_a(tileram_Dout), + .wren_a(tile_cs & NRD), + + .clock_b(CK49), + .address_b(vram_A), + .q_b(tileram_D) +); +//Tilemap layer 1 +dpram_dc #(.widthad_a(10)) VRAM_TILEATTRIB1 +( + .clock_a(CK49), + .address_a(A[9:0]), + .data_a(DBi), + .q_a(tileram1_attrib_Dout), + .wren_a(tile1_attrib_cs & NRD), + + .clock_b(CK49), + .address_b(vram_A), + .q_b(tileram1_attrib_D) +); +dpram_dc #(.widthad_a(10)) VRAM_TILECODE1 +( + .clock_a(CK49), + .address_a(A[9:0]), + .data_a(DBi), + .q_a(tileram1_Dout), + .wren_a(tile1_cs & NRD), + + .clock_b(CK49), + .address_b(vram_A), + .q_b(tileram1_D) +); + +// Hiscore mux (this is only to be used with Iron Horse as its high scores are stored in sprite RAM) +wire [11:0] VRAM_SPR_AD = hs_access ? hs_address : A[11:0]; +wire [7:0] VRAM_SPR_DIN = hs_access ? hs_data_in : DBi; +wire VRAM_SPR_WE = hs_access ? hs_write : (spriteram_cs & NRD); +wire [7:0] VRAM_SPR_DOUT; + +assign hs_data_out = hs_access ? VRAM_SPR_DOUT : 8'h00; +assign spriteram_Dout = hs_access ? 8'h00 : VRAM_SPR_DOUT; + +//Sprites +dpram_dc #(.widthad_a(12)) VRAM_SPR +( + .clock_a(CK49), + .address_a(VRAM_SPR_AD), + .data_a(VRAM_SPR_DIN), + .q_a(VRAM_SPR_DOUT), + .wren_a(VRAM_SPR_WE), + + .clock_b(~CK49), + .address_b(spriteram_A), + .q_b(spriteram_D) +); + +//-------------------------------------------------------- Tilemap layer -------------------------------------------------------// + +//TODO: The current implementation only handles one of the 005885's two tilemap layers - add logic to handle both layers + +//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 +wire [8:0] row_scroll = (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 [8:0] tilemap_hpos = hcnt_x + row_scroll; +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 = {tileram_attrib_D[7:6], tileram_D}; + +//XOR tile H/V flip bits with the flipscreen bit +wire tile_hflip = tileram_attrib_D[4]; +wire tile_vflip = tileram_attrib_D[5]; + +//Address output to graphics ROMs +assign R = {tile_ctrl[1:0], tile_index, (tilemap_vpos[2:0] ^ {3{tile_vflip}}), (tilemap_hpos[2] ^ tile_hflip)}; + +//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 +reg [15:0] RD_lat = 16'd0; +reg [3:0] tile_color = 4'd0; +reg tile_hflip_lat = 0; +reg old_tilehpos1; +always_ff @(posedge CK49) begin + old_tilehpos1 <= tilemap_hpos[1]; + if(old_tilehpos1 && !tilemap_hpos[1]) begin + tile_color <= tileram_attrib_D[3:0]; + RD_lat <= flipscreen ? {RDL, RDU} : {RDU, RDL}; + tile_hflip_lat <= tileram_attrib_D[4]; + end +end + +//Multiplex graphics ROM data down from 16 bits to 8 using bit 1 of the horizontal position +wire [7:0] RD = (tilemap_hpos[1] ^ tile_hflip_lat) ? RD_lat[7:0] : RD_lat[15:8]; + +//Further multiplex graphics ROM data down from 8 bits to 4 using bit 0 of the horizontal position +wire [3:0] tile_pixel = (tilemap_hpos[0] ^ tile_hflip_lat) ? RD[3:0] : RD[7:4]; + +//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]; +reg tilemap_en = 0; +always_ff @(posedge CK49) begin + if(n_cen_6m) begin + tilemap_en <= tile_sel; + end +end + +//Address output to tilemap LUT PROM +assign VCF = tile_color; +assign VCB = tile_pixel; + +//Shift the tilemap layer left by two lines when the screen is flipped +reg [7:0] tilemap_shift; +always_ff @(posedge CK49) begin + if(cen_6m) + tilemap_shift <= {VCD, tilemap_shift[7:4]}; +end +wire [3:0] tilemap_D = flipscreen ? tilemap_shift[3:0] : VCD; + +//-------------------------------------------------------- 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 [7:0] sprite_attrib0, sprite_attrib1, sprite_attrib2, sprite_attrib3, sprite_attrib4; +reg [2:0] sprite_fsm_state; +reg [5:0] sprite_width; +reg [15:0] sprite_rom_addr; +//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) +wire [8:0] sprite_limit = (BTLG == 2'b10) ? 9'd155 : 9'd485; +reg [3:0] waitstate; + +always_ff @(posedge CK49) begin + //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 == 9'd0 || (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; + waitstate <= 0; + end + else + case(sprite_fsm_state) + 0: /* empty */ ; + 1: begin + waitstate <= 0; + if(sprite_index > sprite_limit) + sprite_fsm_state <= 0; + else begin + sprite_attrib4 <= spriteram_D; + sprite_offset <= 3'd3; + sprite_fsm_state <= sprite_fsm_state + 3'd1; + end + end + 2: begin + sprite_attrib3 <= spriteram_D; + sprite_offset <= 3'd2; + sprite_fsm_state <= sprite_fsm_state + 3'd1; + end + 3: begin + //Skip the current sprite if it's inactive, otherwise obtain the sprite Y attribute and continue + //scanning out the rest of the sprite attributes + if(sprite_active) begin + sprite_attrib2 <= spriteram_D; + sprite_offset <= 3'd1; + 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 + 4: begin + sprite_attrib1 <= spriteram_D; + sprite_offset <= 3'd0; + sprite_fsm_state <= sprite_fsm_state + 3'd1; + end + 5: begin + sprite_attrib0 <= 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); + 3'b100: sprite_width <= 6'b100000 + (BTLG == 2'b01 && flipscreen); + default: sprite_width <= 6'b100000 + (BTLG == 2'b01 && flipscreen); + endcase + sprite_fsm_state <= sprite_fsm_state + 3'd1; + waitstate <= 4'd14; + end + 6: if (waitstate == 0) 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; + + if (sprite_width[1:0] == 2'b11) waitstate <= 4'd14; + sprite_fsm_state <= wre ? sprite_fsm_state : 3'd1; + end + else begin + sprite_rom_addr <= {sprite_code_sized, ly[2:0], lx[2]}; + waitstate <= waitstate - 1'd1; + end + default:; + endcase +end + +//Obtain sprite X position from sprite attribute byte 3 - append a 9th bit based on the state of bit 1 sprite attribute byte 4, +//bit 0 of sprite attribute byte 4 if high or the AND of the upper 5 bits of the horizontal position if low +reg sprite_x8; +always_ff @(posedge CK49) begin + if(sprite_attrib4[1]) + sprite_x8 <= sprite_attrib4[0]; + else + sprite_x8 <= &sprite_attrib3[7:3]; +end +wire [8:0] sprite_x = {sprite_x8 ^ flipscreen, sprite_attrib3 ^ {8{flipscreen}}}; + +//If the sprite state machine is in state 3, obtain sprite Y position directly from sprite RAM, otherwise obtain it from +//sprite attribute byte 2 +wire [7:0] sprite_y = (sprite_fsm_state == 3'd3) ? spriteram_D : sprite_attrib2; + +//Sprite flip attributes are stored in bits 5 (horizontal) and 6 (vertical) of sprite attribute byte 4 +//Also XOR these attributes with the flipscreen bit (XOR with the inverse for vertical flip) +wire sprite_hflip = sprite_attrib4[5] ^ flipscreen; +wire sprite_vflip = sprite_attrib4[6] ^ ~flipscreen; + +//Sprite code is sprite attribute byte 0 sandwiched between bits 1 and 0 and bits 3 and 2 of sprite attribute byte 1 +wire [11:0] sprite_code = {sprite_attrib1[1:0], sprite_fsm_state == 5 ? spriteram_D : sprite_attrib0, sprite_attrib1[3:2]}; + +//Sprite color is the upper 4 bits of sprite attribute byte 1 +wire [3:0] sprite_color = sprite_attrib1[7:4]; + +//The 005885 supports 5 different sprite sizes: 8x8, 8x16, 16x8, 16x16 and 32x32. Retrieve this attribute from bits [4:2] of +//sprite attribute byte 4 +wire [2:0] sprite_size = sprite_attrib4[4:2]; + +//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_rom_addr; + + +//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 +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; +always_ff @(posedge CK49) begin + lbuff_A <= {~sprite_lbuff_bank, wpx}; + lbuff_we <= wre & (waitstate == 0); + //lbuff_Din <= OCD; +end + +//Latch sprite LUT PROM data on the falling edge of the main clock +wire [3:0] lbuff_Din = OCD; +//always_ff @(negedge CK49) begin +// lbuff_Din <= OCD; +//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 : sprite_hpos}; +end + +//Sprite line buffer +wire [3:0] lbuff_Dout; +dpram_dc #(.widthad_a(10)) LBUFF +( + .clock_a(CK49), + .address_a(lbuff_A), + .data_a({4'd0, lbuff_Din}), + .wren_a(lbuff_we & (lbuff_Din != 0)), + + .clock_b(CK49), + .address_b(radr0), + .data_b(8'h0), + .wren_b(radr0 == radr1), + .q_b({4'bZZZZ, lbuff_Dout}) +); + +//Latch sprite data from the sprite line buffer +wire lbuff_read_en = (div[2:0] == 3'b100); +reg [3:0] lbuff_read = 4'd0; +always_ff @(posedge CK49) begin + if(lbuff_read_en) begin + if(radr0 != radr1) + lbuff_read <= lbuff_Dout; + radr1 <= radr0; + end +end + +//Delay sprite layer by 2 horizontal lines (1 line if a bootleg Jackal ROM set is loaded and the screen is flipped) +reg [7:0] sprite_dly = 8'd0; +always_ff @(posedge CK49) begin + if(cen_6m) begin + if(BTLG == 2'b01 && flipscreen) + sprite_dly <= {4'd0, lbuff_read}; + else + sprite_dly <= {lbuff_read, sprite_dly[7:4]}; + end +end +//Jackal bootlegs fail to render the last two vertical lines of the sprite layer - model this behavior here +wire [3:0] sprite_D = (BTLG == 2'b01 && ((h_cnt >= 244 && ~flipscreen) || (h_cnt >= 248 && flipscreen))) ? 4'd0 : sprite_dly[3:0]; + +//--------------------------------------------------------- Color mixer --------------------------------------------------------// + +//Multiplex tile and sprite data, then output the final result +wire tile_sprite_sel = (tilemap_en | ~(|sprite_D)); +wire [3:0] tile_sprite_D = tile_sprite_sel ? tilemap_D : sprite_D; + +//Latch and output pixel data +reg [4:0] pixel_D; +always_ff @(posedge CK49) begin + if(cen_6m) + pixel_D <= {tile_sprite_sel, tile_sprite_D}; +end +assign COL = (BTLG == 2'b01 && ((h_cnt >= 247 && ~flipscreen) || (h_cnt <= 14 && flipscreen))) || + (BTLG == 2'b10 && ((h_cnt <= 20 && ~flipscreen) || ((h_cnt <= 18 || h_cnt >= 251) && flipscreen))) ? 5'd0 : pixel_D; +//The above condition blacks out the last 4 lines on the right side of the screen (left when flipped) when a bootleg Jackal ROM set +//is loaded and blacks out the left-most 8 lines (7 when flipped plus an extra 2 lines on the right side) when a bootleg Iron Horse +//ROM set is loaded - this simulates the earlier-than-normal start of HBlank for Jackal bootlegs and later-than-normal end of +//HBlank for Iron Horse bootlegs while maintaining the usual 240x224 display area + +endmodule diff --git a/Arcade_MiST/Konami Jackal/rtl/custom/k007327.sv b/Arcade_MiST/Konami Jackal/rtl/custom/k007327.sv new file mode 100644 index 00000000..6fce8edd --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/custom/k007327.sv @@ -0,0 +1,149 @@ +//============================================================================ +// +// SystemVerilog implementation of the Konami 007327 custom palette RAM + +// video DAC module +// Copyright (C) 2021 Ace & SnakeGrunger +// +// 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 pinout: +/* _______________________ + _| |_ +CCS |_|1 40|_| CLK + _| |_ +CWR |_|2 39|_| BLK + _| |_ +D[7] |_|3 38|_| RW + _| |_ +D[6] |_|4 37|_| A[0] + _| |_ +D[5] |_|5 36|_| NA0 + _| |_ +D[4] |_|6 35|_| A[1] + _| |_ +D[3] |_|7 34|_| A[2] + _| |_ +D[2] |_|8 33|_| A[3] + _| |_ +D[1] |_|9 32|_| A[4] + _| |_ +D[0] |_|10 31|_| A[5] + _| |_ +GND |_|11 30|_| A[6] + _| |_ +VCC |_|12 29|_| A[7] + _| |_ +B |_|13 28|_| CB[0] + _| |_ +G |_|14 27|_| CB[1] + _| |_ +R |_|15 26|_| CB[2] + _| |_ +GND |_|16 25|_| CB[3] + _| |_ +RA[8] |_|17 24|_| CB[4] + _| |_ +RA[9] |_|18 23|_| CB[5] + _| |_ +RA[10] |_|19 22|_| CB[6] + _| |_ +RA[11] |_|20 21|_| SEL + |_______________________| +*/ + +module k007327 +( + input CLK, //Clock input + input CEN, //Clock enable input (set to 1 if replacing an actual 007327) + input [11:8] RA, //External address inputs to palette RAM's upper 4 address bits + input [7:0] A, //Address bus from CPU + input NA0, //Inverse of address bit A0 + input [6:0] CB, //7-bit Color bus input + input [7:0] Di, //CPU data input + input RW, //Read/write input + input SEL, //Color/CPU data select input + input CCS, //Chip select input (active low) + input CWR, //Color write enable (active low) + input BLK, //Blank input + output [4:0] R, G, B, //15-bit RGB color output, 5 bits per color + output [7:0] Do //CPU data output +); + +//Multiplex address lines A[6:0] for palette RAM +wire [10:0] paletteram_A; +assign paletteram_A[10:7] = RA[11:8]; +assign paletteram_A[6:0] = SEL ? CB : A[7:1]; + +//Generate read and write enable signals for palette RAM +wire n_paletteram0_cs = (CCS | NA0); +wire n_paletteram1_cs = (CCS | A[0]); +wire n_paletteram0_wr = (n_paletteram0_cs | CWR); +wire n_paletteram1_wr = (n_paletteram1_cs | CWR); + +//Palette RAM +wire [15:0] paletteram_D; +spram #(8, 11) PALRAM_L +( + .clk(CLK), + .addr(paletteram_A), + .data(Di), + .q(paletteram_D[7:0]), + .we(~n_paletteram0_wr & RW) +); +spram #(8, 11) PALRAM_H +( + .clk(CLK), + .addr(paletteram_A), + .data(Di), + .q(paletteram_D[15:8]), + .we(~n_paletteram1_wr & RW) +); + +//Output palette RAM data to CPU +assign Do = (~n_paletteram0_cs & ~RW) ? paletteram_D[7:0]: + (~n_paletteram1_cs & ~RW) ? paletteram_D[15:8]: + 8'hFF; + +//Latch blank input at every positive edge of the incoming clock +reg blank = 1; +always_ff @(posedge CLK) begin + if(CEN) + blank <= BLK; +end + +//Latch pixel data +reg [4:0] pixel_red = 0; +reg [4:0] pixel_green = 0; +reg [4:0] pixel_blue = 0; +always_ff @(posedge CLK) begin + if(CEN) begin + pixel_red <= paletteram_D[12:8]; + pixel_green <= {paletteram_D[1:0], paletteram_D[15:13]}; + pixel_blue <= paletteram_D[6:2]; + end +end + +//Generate final RGB output +assign R = blank ? pixel_red : 5'd0; +assign G = blank ? pixel_green : 5'd0; +assign B = blank ? pixel_blue : 5'd0; + +endmodule diff --git a/Arcade_MiST/Konami Jackal/rtl/custom/k007343.sv b/Arcade_MiST/Konami Jackal/rtl/custom/k007343.sv new file mode 100644 index 00000000..14a8f85b --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/custom/k007343.sv @@ -0,0 +1,92 @@ +//============================================================================ +// +// SystemVerilog implementation of the Konami K007343, a PAL16L8 used as part +// of the address decoding hardware on Jackal/Top Gunner arcade PCBs +// Converted from dump available at the PLD Archive +// http://wiki.pldarchive.co.uk/index.php?title=Jackal +// Copyright (C) 2021 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. +// +//============================================================================ + +//Chip pinout: +/* _____________ + _| |_ +A13 |_|1 20|_| VCC + _| |_ +A12 |_|2 19|_| MGCS + _| |_ +A11 |_|3 18|_| NC + _| |_ +A10 |_|4 17|_| CRCS + _| |_ +A8_9 |_|5 16|_| IOCS + _| |_ +A7 |_|6 15|_| GATEB + _| |_ +A6 |_|7 14|_| WR + _| |_ +A5 |_|8 13|_| OBJB + _| |_ +A4 |_|9 12|_| SGCS + _| |_ +GND |_|10 11|_| GATECS + |_____________| +*/ + +module k007343 +( + input A4, + input A5, + input A6, + input A7, + input A8_9, + input A10, + input A11, + input A12, + input A13, + input WR, + input OBJB, + input GATEB, + input GATECS, + output MGCS, + output SGCS, + output IOCS, + output CRCS +); + +wire o18 = ~(A13 & A12 & ~A10 & ~GATECS | + A13 & A12 & ~A8_9 & ~GATECS); + +assign MGCS = ~(~GATECS & ~OBJB & ~GATEB & IOCS & CRCS | + ~GATECS & ~GATEB & IOCS & CRCS & o18); +assign CRCS = ~(~A13 & A12 & ~GATECS | + ~A13 & ~A12 & A11 & ~GATECS | + ~A13 & ~A12 & A8_9 & ~GATECS | + ~A13 & ~A12 & A7 & ~GATECS | + ~A13 & ~A12 & A6 & A5 & ~GATECS | + ~A13 & ~A12 & A10 & ~GATECS); +assign IOCS = ~(~A13 & ~A12 & ~A11 & ~A10 & ~A8_9 & ~A7 & ~A6 & ~A5 & A4 & ~GATECS); +assign SGCS = ~(~GATECS & GATEB & IOCS & CRCS | + ~GATECS & OBJB & ~WR & IOCS & CRCS | + ~GATECS & OBJB & IOCS & CRCS & ~o18 | + ~GATECS & ~WR & IOCS & CRCS & o18); + +endmodule diff --git a/Arcade_MiST/Konami Jackal/rtl/dpram_dc.vhd b/Arcade_MiST/Konami Jackal/rtl/dpram_dc.vhd new file mode 100644 index 00000000..69d4c5fb --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/dpram_dc.vhd @@ -0,0 +1,136 @@ +LIBRARY ieee; +USE ieee.std_logic_1164.all; + +LIBRARY altera_mf; +USE altera_mf.all; + +ENTITY dpram_dc IS + GENERIC + ( + init_file : string := " "; + widthad_a : natural; + width_a : natural := 8; + outdata_reg_a : string := "UNREGISTERED"; + outdata_reg_b : string := "UNREGISTERED" + ); + PORT + ( + address_a : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0); + address_b : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0) := (others => '0'); + clock_a : IN STD_LOGIC ; + clock_b : IN STD_LOGIC ; + data_a : IN STD_LOGIC_VECTOR (width_a-1 DOWNTO 0) := (others => '0'); + data_b : IN STD_LOGIC_VECTOR (width_a-1 DOWNTO 0) := (others => '0'); + wren_a : IN STD_LOGIC := '0'; + wren_b : IN STD_LOGIC := '0'; + byteena_a : IN STD_LOGIC_VECTOR (width_a/8-1 DOWNTO 0) := (others => '1'); + byteena_b : IN STD_LOGIC_VECTOR (width_a/8-1 DOWNTO 0) := (others => '1'); + q_a : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0); + q_b : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0) + ); +END dpram_dc; + + +ARCHITECTURE SYN OF dpram_dc IS + + SIGNAL sub_wire0 : STD_LOGIC_VECTOR (width_a-1 DOWNTO 0); + SIGNAL sub_wire1 : STD_LOGIC_VECTOR (width_a-1 DOWNTO 0); + + + + COMPONENT altsyncram + GENERIC ( + address_reg_b : STRING; + clock_enable_input_a : STRING; + clock_enable_input_b : STRING; + clock_enable_output_a : STRING; + clock_enable_output_b : STRING; + indata_reg_b : STRING; + init_file : STRING; + intended_device_family : STRING; + lpm_type : STRING; + numwords_a : NATURAL; + numwords_b : NATURAL; + operation_mode : STRING; + outdata_aclr_a : STRING; + outdata_aclr_b : STRING; + outdata_reg_a : STRING; + outdata_reg_b : STRING; + power_up_uninitialized : STRING; + read_during_write_mode_port_a : STRING; + read_during_write_mode_port_b : STRING; + widthad_a : NATURAL; + widthad_b : NATURAL; + width_a : NATURAL; + width_b : NATURAL; + width_byteena_a : NATURAL; + width_byteena_b : NATURAL; + wrcontrol_wraddress_reg_b : STRING + ); + PORT ( + wren_a : IN STD_LOGIC ; + clock0 : IN STD_LOGIC ; + wren_b : IN STD_LOGIC ; + clock1 : IN STD_LOGIC ; + address_a : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0); + address_b : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0); + q_a : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0); + q_b : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0); + byteena_a : IN STD_LOGIC_VECTOR (width_a/8-1 DOWNTO 0) ; + byteena_b : IN STD_LOGIC_VECTOR (width_a/8-1 DOWNTO 0) ; + data_a : IN STD_LOGIC_VECTOR (width_a-1 DOWNTO 0); + data_b : IN STD_LOGIC_VECTOR (width_a-1 DOWNTO 0) + ); + END COMPONENT; + +BEGIN + q_a <= sub_wire0(width_a-1 DOWNTO 0); + q_b <= sub_wire1(width_a-1 DOWNTO 0); + + altsyncram_component : altsyncram + GENERIC MAP ( + address_reg_b => "CLOCK1", + clock_enable_input_a => "BYPASS", + clock_enable_input_b => "BYPASS", + clock_enable_output_a => "BYPASS", + clock_enable_output_b => "BYPASS", + indata_reg_b => "CLOCK1", + init_file => init_file, + intended_device_family => "Cyclone III", + lpm_type => "altsyncram", + numwords_a => 2**widthad_a, + numwords_b => 2**widthad_a, + operation_mode => "BIDIR_DUAL_PORT", + outdata_aclr_a => "NONE", + outdata_aclr_b => "NONE", + outdata_reg_a => outdata_reg_a, + outdata_reg_b => outdata_reg_a, + power_up_uninitialized => "FALSE", + read_during_write_mode_port_a => "NEW_DATA_NO_NBE_READ", + read_during_write_mode_port_b => "NEW_DATA_NO_NBE_READ", + widthad_a => widthad_a, + widthad_b => widthad_a, + width_a => width_a, + width_b => width_a, + width_byteena_a => width_a/8, + width_byteena_b => width_a/8, + wrcontrol_wraddress_reg_b => "CLOCK1" + ) + PORT MAP ( + wren_a => wren_a, + clock0 => clock_a, + wren_b => wren_b, + clock1 => clock_b, + address_a => address_a, + address_b => address_b, + data_a => data_a, + data_b => data_b, + q_a => sub_wire0, + q_b => sub_wire1, + byteena_a => byteena_a, + byteena_b => byteena_b + ); + + + +END SYN; diff --git a/Arcade_MiST/Konami Jackal/rtl/hiscore.v b/Arcade_MiST/Konami Jackal/rtl/hiscore.v new file mode 100644 index 00000000..0fd1ef66 --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/hiscore.v @@ -0,0 +1,602 @@ +//============================================================================ +// MAME hiscore.dat support for MiSTer arcade cores. +// +// https://github.com/JimmyStones/Hiscores_MiSTer +// +// Copyright (c) 2021 Alan Steremberg +// Copyright (c) 2021 Jim Gregory +// +// 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +//============================================================================ +/* + Version history: + 0001 - 2021-03-06 - First marked release + 0002 - 2021-03-06 - Added HS_DUMPFORMAT localparam to identify dump version (for future use) + Add HS_CONFIGINDEX and HS_DUMPINDEX parameters to configure ioctl_indexes + 0003 - 2021-03-10 - Added WRITE_REPEATCOUNT and WRITE_REPEATWAIT to handle tricky write situations + 0004 - 2021-03-15 - Fix ram_access assignment + 0005 - 2021-03-18 - Add configurable score table width, clean up some stupid mistakes + 0006 - 2021-03-27 - Move 'tweakable' parameters into MRA data header + 0007 - 2021-04-15 - Improve state machine maintainability, add new 'pause padding' states + 0008 - 2021-05-12 - Feed back core-level pause to halt startup timer +============================================================================ +*/ + +module hiscore +#( + parameter HS_ADDRESSWIDTH=10, // Max size of game RAM address for highscores + parameter HS_SCOREWIDTH=8, // Max size of capture RAM For highscore data (default 8 = 256 bytes max) + parameter HS_CONFIGINDEX=3, // ioctl_index for config transfer + parameter HS_DUMPINDEX=4, // ioctl_index for dump transfer + parameter CFG_ADDRESSWIDTH=4, // Max size of RAM address for highscore.dat entries (default 4 = 16 entries max) + parameter CFG_LENGTHWIDTH=1 // Max size of length for each highscore.dat entries (default 1 = 256 bytes max) +) +( + input clk, + input paused, // Signal from core confirming CPU is paused + input reset, + + input ioctl_upload, + input ioctl_download, + input ioctl_wr, + input [24:0] ioctl_addr, + input [7:0] ioctl_dout, + input [7:0] ioctl_din, + input [7:0] ioctl_index, + + output [HS_ADDRESSWIDTH-1:0] ram_address, // Address in game RAM to read/write score data + output [7:0] data_to_ram, // Data to write to game RAM + output reg ram_write, // Write to game RAM (active high) + output ram_access, // RAM read or write required (active high) + output reg pause_cpu // Pause core CPU to prepare for/relax after RAM access +); + +// Parameters read from config header +reg [31:0] START_WAIT =32'd0; // Delay before beginning check process +reg [15:0] CHECK_WAIT =16'hFF; // Delay between start/end check attempts +reg [15:0] CHECK_HOLD =16'd2; // Hold time for start/end check reads +reg [15:0] WRITE_HOLD =16'd2; // Hold time for game RAM writes +reg [15:0] WRITE_REPEATCOUNT =16'b1; // Number of times to write score to game RAM +reg [15:0] WRITE_REPEATWAIT =16'b1111; // Delay between subsequent write attempts to game RAM +reg [7:0] ACCESS_PAUSEPAD =8'd4; // Cycles to wait with paused CPU before and after RAM access + + +// State machine constants +localparam SM_STATEWIDTH = 4; // Width of state machine net + +localparam SM_INIT = 0; +localparam SM_TIMER = 1; + +localparam SM_CHECKPREP = 2; +localparam SM_CHECKBEGIN = 3; +localparam SM_CHECKSTARTVAL = 4; +localparam SM_CHECKENDVAL = 5; +localparam SM_CHECKCANCEL = 6; + +localparam SM_WRITEPREP = 7; +localparam SM_WRITEBEGIN = 8; +localparam SM_WRITEREADY = 9; +localparam SM_WRITEDONE = 10; +localparam SM_WRITECOMPLETE = 11; +localparam SM_WRITERETRY = 12; + +localparam SM_STOPPED = 13; + +/* +Hiscore config data structure (version 1) +----------------------------------------- +[16 byte header] +[8 byte * no. of entries] + +- Header format +00 00 FF FF 00 FF 00 02 00 02 00 01 11 11 00 00 +[ SW ] [ CW] [ CH] [ WH] [WRC] [WRW] [PAD] +4 byte START_WAIT +2 byte CHECK_WAIT +2 byte CHECK_HOLD +2 byte WRITE_HOLD +2 byte WRITE_REPEATCOUNT +2 byte WRITE_REPEATWAIT +2 byte (padding/future use) + +- Entry format (when CFG_LENGTHWIDTH=1) +00 00 43 0b 0f 10 01 00 +00 00 40 23 02 04 12 00 +[ ADDR ] LEN START END PAD + +4 bytes Address of ram entry (in core memory map) +1 byte Length of ram entry in bytes +1 byte Start value to check for at start of address range before proceeding +1 byte End value to check for at end of address range before proceeding +1 byte (padding) + +- Entry format (when CFG_LENGTHWIDTH=2) +00 00 43 0b 00 0f 10 01 +00 00 40 23 00 02 04 12 +[ ADDR ] [LEN ] START END + +4 bytes Address of ram entry (in core memory map) +2 bytes Length of ram entry in bytes +1 byte Start value to check for at start of address range before proceeding +1 byte End value to check for at end of address range before proceeding + +*/ + +localparam HS_VERSION =8; // Version identifier for module +localparam HS_DUMPFORMAT =1; // Version identifier for dump format +localparam HS_HEADERLENGTH =16; // Size of header chunk (default=16 bytes) + +// HS_DUMPFORMAT = 1 --> No header, just the extracted hiscore data + +// Hiscore config and dump status +wire downloading_config; +wire parsing_header; +wire downloading_dump; +wire uploading_dump; +reg downloaded_config = 1'b0; +reg downloaded_dump = 1'b0; +reg uploaded_dump = 1'b0; +reg [3:0] initialised; +reg writing_scores = 1'b0; +reg checking_scores = 1'b0; + +assign downloading_config = ioctl_download && (ioctl_index==HS_CONFIGINDEX); +assign parsing_header = downloading_config && (ioctl_addr<=HS_HEADERLENGTH); +assign downloading_dump = ioctl_download && (ioctl_index==HS_DUMPINDEX); +assign uploading_dump = ioctl_upload && (ioctl_index==HS_DUMPINDEX); +assign ram_access = uploading_dump | writing_scores | checking_scores; +assign ram_address = ram_addr[HS_ADDRESSWIDTH-1:0]; + +reg [(SM_STATEWIDTH-1):0] state = SM_INIT; // Current state machine index +reg [(SM_STATEWIDTH-1):0] next_state = SM_INIT; // Next state machine index to move to after wait timer expires +reg [31:0] wait_timer; // Wait timer for inital/read/write delays + +reg [CFG_ADDRESSWIDTH-1:0] counter = 1'b0; // Index for current config table entry +reg [CFG_ADDRESSWIDTH-1:0] total_entries = 1'b0; // Total count of config table entries +reg reset_last = 1'b0; // Last cycle reset +reg [7:0] write_counter = 1'b0; // Index of current game RAM write attempt + +reg [7:0] last_ioctl_index; // Last cycle HPS IO index +reg last_ioctl_download = 0;// Last cycle HPS IO download +reg last_ioctl_upload = 0; // Last cycle HPS IO upload +reg [7:0] last_ioctl_dout; // Last cycle HPS IO data out +reg [7:0] last_ioctl_dout2; // Last cycle +1 HPS IO data out +reg [7:0] last_ioctl_dout3; // Last cycle +2 HPS IO data out + +reg [24:0] ram_addr; // Target RAM address for hiscore read/write +reg [24:0] old_io_addr; +reg [24:0] base_io_addr; +wire [23:0] addr_base; +wire [(CFG_LENGTHWIDTH*8)-1:0] length; +wire [24:0] end_addr = (addr_base + length - 1'b1); +reg [HS_SCOREWIDTH-1:0] local_addr; +wire [7:0] start_val; +wire [7:0] end_val; + +wire [23:0] address_data_in; +wire [(CFG_LENGTHWIDTH*8)-1:0] length_data_in; + +assign address_data_in = {last_ioctl_dout2, last_ioctl_dout, ioctl_dout}; +assign length_data_in = (CFG_LENGTHWIDTH == 1'b1) ? ioctl_dout : {last_ioctl_dout, ioctl_dout}; + +wire address_we = downloading_config & ~parsing_header & (ioctl_addr[2:0] == 3'd3); +wire length_we = downloading_config & ~parsing_header & (ioctl_addr[2:0] == 3'd3 + CFG_LENGTHWIDTH); +wire startdata_we = downloading_config & ~parsing_header & (ioctl_addr[2:0] == 3'd4 + CFG_LENGTHWIDTH); +wire enddata_we = downloading_config & ~parsing_header & (ioctl_addr[2:0] == 3'd5 + CFG_LENGTHWIDTH); + +// RAM chunks used to store configuration data +// - address_table +// - length_table +// - startdata_table +// - enddata_table +dpram_hs #(.aWidth(CFG_ADDRESSWIDTH),.dWidth(24)) +address_table( + .clk(clk), + .addr_a(ioctl_addr[CFG_ADDRESSWIDTH+2:3] - 2'd2), + .we_a(address_we & ioctl_wr), + .d_a(address_data_in), + .addr_b(counter), + .q_b(addr_base) +); +// Length table - variable width depending on CFG_LENGTHWIDTH +dpram_hs #(.aWidth(CFG_ADDRESSWIDTH),.dWidth(CFG_LENGTHWIDTH*8)) +length_table( + .clk(clk), + .addr_a(ioctl_addr[CFG_ADDRESSWIDTH+2:3] - 2'd2), + .we_a(length_we & ioctl_wr), + .d_a(length_data_in), + .addr_b(counter), + .q_b(length) +); +dpram_hs #(.aWidth(CFG_ADDRESSWIDTH),.dWidth(8)) +startdata_table( + .clk(clk), + .addr_a(ioctl_addr[CFG_ADDRESSWIDTH+2:3] - 2'd2), + .we_a(startdata_we & ioctl_wr), + .d_a(ioctl_dout), + .addr_b(counter), + .q_b(start_val) +); +dpram_hs #(.aWidth(CFG_ADDRESSWIDTH),.dWidth(8)) +enddata_table( + .clk(clk), + .addr_a(ioctl_addr[CFG_ADDRESSWIDTH+2:3] - 2'd2), + .we_a(enddata_we & ioctl_wr), + .d_a(ioctl_dout), + .addr_b(counter), + .q_b(end_val) +); + +// RAM chunk used to store hiscore data +dpram_hs #(.aWidth(HS_SCOREWIDTH),.dWidth(8)) +hiscoredata ( + .clk(clk), + .addr_a(ioctl_addr[(HS_SCOREWIDTH-1):0]), + .we_a(downloading_dump), + .d_a(ioctl_dout), + .addr_b(local_addr), + .we_b(ioctl_upload), + .d_b(ioctl_din), + .q_b(data_to_ram) +); + +wire [3:0] header_chunk = ioctl_addr[3:0]; + +always @(posedge clk) +begin + + if (downloading_config) + begin + // Get header chunk data + if(parsing_header) + begin + if(ioctl_wr) + begin + if(header_chunk == 4'd3) START_WAIT <= { last_ioctl_dout3, last_ioctl_dout2, last_ioctl_dout, ioctl_dout }; + if(header_chunk == 4'd5) CHECK_WAIT <= { last_ioctl_dout, ioctl_dout }; + if(header_chunk == 4'd7) CHECK_HOLD <= { last_ioctl_dout, ioctl_dout }; + if(header_chunk == 4'd9) WRITE_HOLD <= { last_ioctl_dout, ioctl_dout }; + if(header_chunk == 4'd11) WRITE_REPEATCOUNT <= { last_ioctl_dout, ioctl_dout }; + if(header_chunk == 4'd13) WRITE_REPEATWAIT <= { last_ioctl_dout, ioctl_dout }; + if(header_chunk == 4'd14) ACCESS_PAUSEPAD <= ioctl_dout; + end + end + else + begin + // Keep track of the largest entry during config download + total_entries <= ioctl_addr[CFG_ADDRESSWIDTH+2:3] - 2'd2; + end + end + + // Track completion of configuration and dump download + if ((last_ioctl_download != ioctl_download) && (ioctl_download == 1'b0)) + begin + if (last_ioctl_index==HS_CONFIGINDEX) downloaded_config <= 1'b1; + if (last_ioctl_index==HS_DUMPINDEX) downloaded_dump <= 1'b1; + end + + // Track completion of dump upload + if ((last_ioctl_upload != ioctl_upload) && (ioctl_upload == 1'b0)) + begin + if (last_ioctl_index==HS_DUMPINDEX) + begin + uploaded_dump <= 1'b1; + // Mark uploaded dump as readable in case of reset + downloaded_dump <= 1'b1; + end + end + + // Track last ioctl values + last_ioctl_download <= ioctl_download; + last_ioctl_upload <= ioctl_upload; + last_ioctl_index <= ioctl_index; + if(ioctl_download && ioctl_wr) + begin + last_ioctl_dout3 = last_ioctl_dout2; + last_ioctl_dout2 = last_ioctl_dout; + last_ioctl_dout = ioctl_dout; + end + + if(downloaded_config) + begin + // Check for end of state machine reset to initialise state machine + reset_last <= reset; + if (reset_last == 1'b1 && reset == 1'b0) + begin + wait_timer <= START_WAIT; + next_state <= SM_INIT; + state <= SM_TIMER; + counter <= 1'b0; + initialised <= initialised + 1'b1; + end + else + begin + // Upload scores to HPS + if (uploading_dump == 1'b1) + begin + // generate addresses to read high score from game memory. Base addresses off ioctl_address + if (ioctl_addr == 25'b0) begin + local_addr <= 0; + base_io_addr <= 25'b0; + counter <= 1'b0000; + end + // Move to next entry when last address is reached + if (old_io_addr!=ioctl_addr && ram_addr==end_addr[24:0]) + begin + counter <= counter + 1'b1; + base_io_addr <= ioctl_addr; + end + // Set game ram address for reading back to HPS + ram_addr <= addr_base + (ioctl_addr - base_io_addr); + // Set local addresses to update cached dump in case of reset + local_addr <= ioctl_addr[HS_SCOREWIDTH-1:0]; + end + + if (ioctl_upload == 1'b0 && downloaded_dump == 1'b1 && reset == 1'b0) + begin + // State machine to write data to game RAM + case (state) + SM_INIT: // Start state machine + begin + // Setup base addresses + local_addr <= 0; + base_io_addr <= 25'b0; + // Reset entry counter and states + counter <= 0; + writing_scores <= 1'b0; + checking_scores <= 1'b0; + pause_cpu <= 1'b0; + state <= SM_CHECKPREP; + end + + // Start/end check states + // ---------------------- + SM_CHECKPREP: // Prepare start/end check run - pause CPU in readiness for RAM access + begin + state <= SM_TIMER; + next_state <= SM_CHECKBEGIN; + pause_cpu <= 1'b1; + wait_timer <= ACCESS_PAUSEPAD; + end + + SM_CHECKBEGIN: // Begin start/end check run - enable RAM access + begin + checking_scores <= 1'b1; + ram_addr <= {1'b0, addr_base}; + state <= SM_CHECKSTARTVAL; + wait_timer <= CHECK_HOLD; + end + + SM_CHECKSTARTVAL: // Start check + begin + // Check for matching start value + if(wait_timer != CHECK_HOLD & ioctl_din == start_val) + begin + // Prepare end check + ram_addr <= end_addr; + state <= SM_CHECKENDVAL; + wait_timer <= CHECK_HOLD; + end + else + begin + ram_addr <= {1'b0, addr_base}; + if (wait_timer > 1'b0) + begin + wait_timer <= wait_timer - 1'b1; + end + else + begin + // - If no match after read wait then stop check run and schedule restart of state machine + next_state <= SM_CHECKCANCEL; + state <= SM_TIMER; + checking_scores <= 1'b0; + wait_timer <= ACCESS_PAUSEPAD; + end + end + end + + SM_CHECKENDVAL: // End check + begin + // Check for matching end value + if (wait_timer != CHECK_HOLD & ioctl_din == end_val) + begin + if (counter == total_entries) + begin + // If this was the last entry then move on to writing scores to game ram + checking_scores <= 1'b0; + state <= SM_WRITEBEGIN; // Bypass SM_WRITEPREP as we are already paused + counter <= 1'b0; + write_counter <= 1'b0; + ram_write <= 1'b0; + ram_addr <= {1'b0, addr_base}; + end + else + begin + // Increment counter and restart state machine to check next entry + counter <= counter + 1'b1; + state <= SM_CHECKBEGIN; + end + end + else + begin + ram_addr <= end_addr; + if (wait_timer > 1'b0) + begin + wait_timer <= wait_timer - 1'b1; + end + else + begin + // - If no match after read wait then stop check run and schedule restart of state machine + next_state <= SM_CHECKCANCEL; + state <= SM_TIMER; + checking_scores <= 1'b0; + wait_timer <= ACCESS_PAUSEPAD; + end + end + end + + SM_CHECKCANCEL: // Cancel start/end check run - disable RAM access and keep CPU paused + begin + pause_cpu <= 1'b0; + next_state <= SM_INIT; + state <= SM_TIMER; + wait_timer <= CHECK_WAIT; + end + + // Write to game RAM states + // ---------------------- + SM_WRITEPREP: // Prepare to write scores - pause CPU in readiness for RAM access (only used on subsequent write attempts) + begin + state <= SM_TIMER; + next_state <= SM_WRITEBEGIN; + pause_cpu <= 1'b1; + wait_timer <= ACCESS_PAUSEPAD; + end + + SM_WRITEBEGIN: // Writing scores to game RAM begins + begin + writing_scores <= 1'b1; // Enable muxes if necessary + write_counter <= write_counter + 1'b1; + state <= SM_WRITEREADY; + end + + SM_WRITEREADY: // local ram should be correct, start write to game RAM + begin + ram_addr <= addr_base + (local_addr - base_io_addr); + state <= SM_TIMER; + next_state <= SM_WRITEDONE; + wait_timer <= WRITE_HOLD; + ram_write <= 1'b1; + end + + SM_WRITEDONE: + begin + local_addr <= local_addr + 1'b1; // Increment to next byte of entry + if (ram_addr == end_addr) + begin + // End of entry reached + if (counter == total_entries) + begin + state <= SM_WRITECOMPLETE; + end + else + begin + // Move to next entry + counter <= counter + 1'b1; + write_counter <= 1'b0; + base_io_addr <= local_addr + 1'b1; + state <= SM_WRITEBEGIN; + end + end + else + begin + state <= SM_WRITEREADY; + end + ram_write <= 1'b0; + end + + SM_WRITECOMPLETE: // Hiscore write to RAM completed + begin + ram_write <= 1'b0; + writing_scores <= 1'b0; + state <= SM_TIMER; + if(write_counter < WRITE_REPEATCOUNT) + begin + // Schedule next write + next_state <= SM_WRITERETRY; + local_addr <= 0; + wait_timer <= WRITE_REPEATWAIT; + end + else + begin + next_state <= SM_STOPPED; + wait_timer <= ACCESS_PAUSEPAD; + end + end + + SM_WRITERETRY: // Stop pause and schedule next write + begin + pause_cpu <= 1'b0; + state <= SM_TIMER; + next_state <= SM_WRITEPREP; + wait_timer <= WRITE_REPEATWAIT; + end + + SM_STOPPED: + begin + pause_cpu <= 1'b0; + end + + SM_TIMER: // timer wait state + begin + // Do not progress timer if CPU is paused by source other than this module + // - Stops initial hiscore load delay being foiled by user pausing/entering OSD + if (paused == 1'b0 || pause_cpu == 1'b1) + begin + if (wait_timer > 1'b0) + wait_timer <= wait_timer - 1'b1; + else + state <= next_state; + end + end + endcase + end + end + end + old_io_addr<=ioctl_addr; +end + +endmodule + +module dpram_hs #( + parameter dWidth=8, + parameter aWidth=8 +)( + input clk, + + input [aWidth-1:0] addr_a, + input [dWidth-1:0] d_a, + input we_a, + output reg [dWidth-1:0] q_a, + + input [aWidth-1:0] addr_b, + input [dWidth-1:0] d_b, + input we_b, + output reg [dWidth-1:0] q_b +); + +reg [dWidth-1:0] ram [2**aWidth-1:0]; + +always @(posedge clk) begin + if (we_a) begin + ram[addr_a] <= d_a; + q_a <= d_a; + end + else + begin + q_a <= ram[addr_a]; + end + + if (we_b) begin + ram[addr_b] <= d_b; + q_b <= d_b; + end + else + begin + q_b <= ram[addr_b]; + end +end + +endmodule \ No newline at end of file diff --git a/Arcade_MiST/Konami Jackal/rtl/jtframe_frac_cen.v b/Arcade_MiST/Konami Jackal/rtl/jtframe_frac_cen.v new file mode 100644 index 00000000..8707e766 --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/jtframe_frac_cen.v @@ -0,0 +1,58 @@ +/////////////////////////////////////////////////////////////////////////// +// Fractional clock enable signal +// W refers to the number of divided down cen signals available +// each one is divided by 2 + +module jtframe_frac_cen #(parameter W=2)( + input clk, + input [9:0] n, // numerator + input [9:0] m, // denominator + output reg [W-1:0] cen, + output reg [W-1:0] cenb // 180 shifted +); + +wire [10:0] step={1'b0,n}; +wire [10:0] lim ={1'b0,m}; +wire [10:0] absmax = lim+step; + +reg [10:0] cencnt=11'd0; +reg [10:0] next; +reg [10:0] next2; + +always @(*) begin + next = cencnt+step; + next2 = next-lim; +end + +reg half = 1'b0; +wire over = next>=lim; +wire halfway = next >= (lim>>1) && !half; + +reg [W-1:0] edgecnt = {W{1'b0}}; +wire [W-1:0] next_edgecnt = edgecnt + 1'b1; +wire [W-1:0] toggle = next_edgecnt & ~edgecnt; + +always @(posedge clk) begin + cen <= {W{1'b0}}; + cenb <= {W{1'b0}}; + + if( cencnt >= absmax ) begin + // something went wrong: restart + cencnt <= 11'd0; + end else + if( halfway ) begin + half <= 1'b1; + cenb[0] <= 1'b1; + end + if( over ) begin + cencnt <= next2; + half <= 1'b0; + edgecnt <= next_edgecnt; + cen <= { toggle[W-2:0], 1'b1 }; + end else begin + cencnt <= next; + end +end + + +endmodule \ No newline at end of file diff --git a/Arcade_MiST/Konami Jackal/rtl/pause.v b/Arcade_MiST/Konami Jackal/rtl/pause.v new file mode 100644 index 00000000..4f21042b --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/pause.v @@ -0,0 +1,93 @@ +//============================================================================ +// Generic pause handling for MiSTer cores. +// +// https://github.com/JimmyStones/Pause_MiSTer +// +// Copyright (c) 2021 Jim Gregory +// +// 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +//============================================================================ +/* + Features: + - Pause can be triggered by user input, hiscore module or OSD opening (optionally controlled by setting in OSD) + - When paused the RGB outputs will be halved after 10 seconds to reduce burn-in (optionally controlled by setting in OSD) + - Reset signal will cancel user triggered pause + + Version history: + 0001 - 2021-03-15 - First marked release +============================================================================ +*/ +module pause #( + parameter RW=8, // Width of red channel + parameter GW=8, // Width of green channel + parameter BW=8, // Width of blue channel + parameter CLKSPD = 12 // Main clock speed in MHz +) +( + input clk_sys, // Core system clock (should match HPS module) + input reset, // CPU reset signal (active-high) + input user_button, // User pause button signal (active-high) + input pause_request, // Pause requested by other code (active-high) + input [1:0] options, // Pause options from OSD + // [0] = pause in OSD (active-high) + // [1] = dim video (active-high) + input OSD_STATUS, // OSD is open (active-high) + input [(RW-1):0] r, // Red channel + input [(GW-1):0] g, // Green channel + input [(BW-1):0] b, // Blue channel + + output pause_cpu, // Pause signal to CPU (active-high) + output [(RW+GW+BW-1):0] rgb_out // RGB output to arcade_video module + +); + +// Option constants +localparam pause_in_osd = 1'b0; +localparam dim_video = 1'b1; + +reg pause_toggle = 1'b0; // User paused (active-high) +reg [31:0] pause_timer = 1'b0; // Time since pause +reg [31:0] dim_timeout = (CLKSPD*10000000); // Time until video output dim (10 seconds @ CLKSPD Mhz) + +assign pause_cpu = (pause_request | pause_toggle | (OSD_STATUS & options[pause_in_osd])) & !reset; + +always @(posedge clk_sys) begin + + // Track user pause button down + reg user_button_last; + user_button_last <= user_button; + if(!user_button_last & user_button) pause_toggle <= ~pause_toggle; + + // Clear user pause on reset + if(pause_toggle & reset) pause_toggle <= 0; + + if(pause_cpu & options[dim_video]) + begin + // Track pause duration for video dim + if((pause_timer= dim_timeout) ? {r >> 1,g >> 1, b >> 1} : {r,g,b}; + +endmodule \ No newline at end of file diff --git a/Arcade_MiST/Konami Jackal/rtl/pll.qip b/Arcade_MiST/Konami Jackal/rtl/pll.qip new file mode 100644 index 00000000..afd958be --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/pll.qip @@ -0,0 +1,4 @@ +set_global_assignment -name IP_TOOL_NAME "ALTPLL" +set_global_assignment -name IP_TOOL_VERSION "13.1" +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "pll.v"] +set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll.ppf"] diff --git a/Arcade_MiST/Konami Jackal/rtl/pll.v b/Arcade_MiST/Konami Jackal/rtl/pll.v new file mode 100644 index 00000000..1960b7f8 --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/pll.v @@ -0,0 +1,348 @@ +// megafunction wizard: %ALTPLL% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altpll + +// ============================================================ +// File Name: pll.v +// Megafunction Name(s): +// altpll +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 13.1.4 Build 182 03/12/2014 Patches 4.26 SJ Web Edition +// ************************************************************ + + +//Copyright (C) 1991-2014 Altera Corporation +//Your use of Altera Corporation's design tools, logic functions +//and other software and tools, and its AMPP partner logic +//functions, and any output files from any of the foregoing +//(including device programming or simulation files), and any +//associated documentation or information are expressly subject +//to the terms and conditions of the Altera Program License +//Subscription Agreement, Altera MegaCore Function License +//Agreement, or other applicable license agreement, including, +//without limitation, that your use is for the sole purpose of +//programming logic devices manufactured by Altera and sold by +//Altera or its authorized distributors. Please refer to the +//applicable agreement for further details. + + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on +module pll ( + areset, + inclk0, + c0, + c1, + locked); + + input areset; + input inclk0; + output c0; + output c1; + output locked; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_off +`endif + tri0 areset; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_on +`endif + + wire [4:0] sub_wire0; + wire sub_wire2; + wire [0:0] sub_wire6 = 1'h0; + wire [0:0] sub_wire3 = sub_wire0[0:0]; + wire [1:1] sub_wire1 = sub_wire0[1:1]; + wire c1 = sub_wire1; + wire locked = sub_wire2; + wire c0 = sub_wire3; + wire sub_wire4 = inclk0; + wire [1:0] sub_wire5 = {sub_wire6, sub_wire4}; + + altpll altpll_component ( + .areset (areset), + .inclk (sub_wire5), + .clk (sub_wire0), + .locked (sub_wire2), + .activeclock (), + .clkbad (), + .clkena ({6{1'b1}}), + .clkloss (), + .clkswitch (1'b0), + .configupdate (1'b0), + .enable0 (), + .enable1 (), + .extclk (), + .extclkena ({4{1'b1}}), + .fbin (1'b1), + .fbmimicbidir (), + .fbout (), + .fref (), + .icdrclk (), + .pfdena (1'b1), + .phasecounterselect ({4{1'b1}}), + .phasedone (), + .phasestep (1'b1), + .phaseupdown (1'b1), + .pllena (1'b1), + .scanaclr (1'b0), + .scanclk (1'b0), + .scanclkena (1'b1), + .scandata (1'b0), + .scandataout (), + .scandone (), + .scanread (1'b0), + .scanwrite (1'b0), + .sclkout0 (), + .sclkout1 (), + .vcooverrange (), + .vcounderrange ()); + defparam + altpll_component.bandwidth_type = "AUTO", + altpll_component.clk0_divide_by = 105, + altpll_component.clk0_duty_cycle = 50, + altpll_component.clk0_multiply_by = 382, + altpll_component.clk0_phase_shift = "0", + altpll_component.clk1_divide_by = 105, + altpll_component.clk1_duty_cycle = 50, + altpll_component.clk1_multiply_by = 191, + altpll_component.clk1_phase_shift = "0", + altpll_component.compensate_clock = "CLK0", + altpll_component.inclk0_input_frequency = 37037, + altpll_component.intended_device_family = "Cyclone III", + altpll_component.lpm_hint = "CBX_MODULE_PREFIX=pll", + altpll_component.lpm_type = "altpll", + altpll_component.operation_mode = "NORMAL", + altpll_component.pll_type = "AUTO", + altpll_component.port_activeclock = "PORT_UNUSED", + altpll_component.port_areset = "PORT_USED", + altpll_component.port_clkbad0 = "PORT_UNUSED", + altpll_component.port_clkbad1 = "PORT_UNUSED", + altpll_component.port_clkloss = "PORT_UNUSED", + altpll_component.port_clkswitch = "PORT_UNUSED", + altpll_component.port_configupdate = "PORT_UNUSED", + altpll_component.port_fbin = "PORT_UNUSED", + altpll_component.port_inclk0 = "PORT_USED", + altpll_component.port_inclk1 = "PORT_UNUSED", + altpll_component.port_locked = "PORT_USED", + altpll_component.port_pfdena = "PORT_UNUSED", + altpll_component.port_phasecounterselect = "PORT_UNUSED", + altpll_component.port_phasedone = "PORT_UNUSED", + altpll_component.port_phasestep = "PORT_UNUSED", + altpll_component.port_phaseupdown = "PORT_UNUSED", + altpll_component.port_pllena = "PORT_UNUSED", + altpll_component.port_scanaclr = "PORT_UNUSED", + altpll_component.port_scanclk = "PORT_UNUSED", + altpll_component.port_scanclkena = "PORT_UNUSED", + altpll_component.port_scandata = "PORT_UNUSED", + altpll_component.port_scandataout = "PORT_UNUSED", + altpll_component.port_scandone = "PORT_UNUSED", + altpll_component.port_scanread = "PORT_UNUSED", + altpll_component.port_scanwrite = "PORT_UNUSED", + altpll_component.port_clk0 = "PORT_USED", + altpll_component.port_clk1 = "PORT_USED", + altpll_component.port_clk2 = "PORT_UNUSED", + altpll_component.port_clk3 = "PORT_UNUSED", + altpll_component.port_clk4 = "PORT_UNUSED", + altpll_component.port_clk5 = "PORT_UNUSED", + altpll_component.port_clkena0 = "PORT_UNUSED", + altpll_component.port_clkena1 = "PORT_UNUSED", + altpll_component.port_clkena2 = "PORT_UNUSED", + altpll_component.port_clkena3 = "PORT_UNUSED", + altpll_component.port_clkena4 = "PORT_UNUSED", + altpll_component.port_clkena5 = "PORT_UNUSED", + altpll_component.port_extclk0 = "PORT_UNUSED", + altpll_component.port_extclk1 = "PORT_UNUSED", + altpll_component.port_extclk2 = "PORT_UNUSED", + altpll_component.port_extclk3 = "PORT_UNUSED", + altpll_component.self_reset_on_loss_lock = "OFF", + altpll_component.width_clock = 5; + + +endmodule + +// ============================================================ +// CNX file retrieval info +// ============================================================ +// Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0" +// Retrieval info: PRIVATE: BANDWIDTH STRING "1.000" +// Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz" +// Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low" +// Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1" +// Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0" +// Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "0" +// Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0" +// Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0" +// Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0" +// Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0" +// Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0" +// Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "8" +// Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "105" +// Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "105" +// Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" +// Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "98.228569" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "49.114285" +// Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" +// Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" +// Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0" +// Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575" +// Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1" +// Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "27.000" +// Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +// Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1" +// Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "Not Available" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT1 STRING "ps" +// Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any" +// Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0" +// Retrieval info: PRIVATE: MIRROR_CLK1 STRING "0" +// Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "382" +// Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "191" +// Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "49.15200000" +// Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "14.31818000" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "0" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE1 STRING "0" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT1 STRING "MHz" +// Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT1 STRING "0.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT1 STRING "deg" +// Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "1" +// Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1" +// Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0" +// Retrieval info: PRIVATE: RECONFIG_FILE STRING "pll.mif" +// Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0" +// Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0" +// Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0" +// Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000" +// Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz" +// Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500" +// Retrieval info: PRIVATE: SPREAD_USE STRING "0" +// Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0" +// Retrieval info: PRIVATE: STICKY_CLK0 STRING "1" +// Retrieval info: PRIVATE: STICKY_CLK1 STRING "1" +// Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1" +// Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +// Retrieval info: PRIVATE: USE_CLK0 STRING "1" +// Retrieval info: PRIVATE: USE_CLK1 STRING "1" +// Retrieval info: PRIVATE: USE_CLKENA0 STRING "0" +// Retrieval info: PRIVATE: USE_CLKENA1 STRING "0" +// Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0" +// Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" +// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +// Retrieval info: CONSTANT: BANDWIDTH_TYPE STRING "AUTO" +// Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "105" +// Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "382" +// Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "105" +// Retrieval info: CONSTANT: CLK1_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK1_MULTIPLY_BY NUMERIC "191" +// Retrieval info: CONSTANT: CLK1_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0" +// Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "37037" +// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +// Retrieval info: CONSTANT: LPM_TYPE STRING "altpll" +// Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL" +// Retrieval info: CONSTANT: PLL_TYPE STRING "AUTO" +// Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: SELF_RESET_ON_LOSS_LOCK STRING "OFF" +// Retrieval info: CONSTANT: WIDTH_CLOCK NUMERIC "5" +// Retrieval info: USED_PORT: @clk 0 0 5 0 OUTPUT_CLK_EXT VCC "@clk[4..0]" +// Retrieval info: USED_PORT: areset 0 0 0 0 INPUT GND "areset" +// Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0" +// Retrieval info: USED_PORT: c1 0 0 0 0 OUTPUT_CLK_EXT VCC "c1" +// Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0" +// Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked" +// Retrieval info: CONNECT: @areset 0 0 0 0 areset 0 0 0 0 +// Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0 +// Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0 +// Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0 +// Retrieval info: CONNECT: c1 0 0 0 0 @clk 0 0 1 1 +// Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.ppf TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll_bb.v FALSE +// Retrieval info: LIB_FILE: altera_mf +// Retrieval info: CBX_MODULE_PREFIX: ON diff --git a/Arcade_MiST/Konami Jackal/rtl/sdram.sv b/Arcade_MiST/Konami Jackal/rtl/sdram.sv new file mode 100644 index 00000000..dee76185 --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/sdram.sv @@ -0,0 +1,363 @@ +// +// sdram.v +// +// sdram controller implementation for the MiST board +// https://github.com/mist-devel/mist-board +// +// Copyright (c) 2013 Till Harbaum +// Copyright (c) 2019 Gyorgy Szombathelyi +// +// This source file is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This source file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +module sdram ( + + // interface to the MT48LC16M16 chip + inout reg [15:0] SDRAM_DQ, // 16 bit bidirectional data bus + output reg [12:0] SDRAM_A, // 13 bit multiplexed address bus + output reg SDRAM_DQML, // two byte masks + output reg SDRAM_DQMH, // two byte masks + output reg [1:0] SDRAM_BA, // two banks + output SDRAM_nCS, // a single chip select + output SDRAM_nWE, // write enable + output SDRAM_nRAS, // row address select + output SDRAM_nCAS, // columns address select + + // cpu/chipset interface + input init_n, // init signal after FPGA config to initialize RAM + input clk, // sdram clock + + input port1_req, + output reg port1_ack, + input port1_we, + input [23:1] port1_a, + input [1:0] port1_ds, + input [15:0] port1_d, + output reg [15:0] port1_q, + + input [16:1] cpu1_addr, + output reg [15:0] cpu1_q, + input [16: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 [16:1] ch1_addr, + output reg [15:0] ch1_q, + input [16:1] ch2_addr, + output reg [15:0] ch2_q, + input sp1_req, + input [16:1] sp1_addr, + output reg [15:0] sp1_q, + output reg sp1_ack, + input sp2_req, + input [16: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 [16:1] addr_last[6]; +reg [16: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] = { 8'd0, cpu1_addr }; + end else if (cpu2_addr != addr_last[PORT_CPU2]) begin + next_port[0] = PORT_CPU2; + addr_latch_next[0] = { 8'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, 2'b00, 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, 2'b10, ch2_addr }; + end else if (sp1_req != sp1_ack) begin + next_port[1] = PORT_SP1; + addr_latch_next[1] = { 1'b1, 5'd0, 2'b01, sp1_addr }; + end else if (sp2_req != sp2_ack) begin + next_port[1] = PORT_SP2; + addr_latch_next[1] = { 1'b1, 5'd0, 2'b11, 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][16: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][16:1]; + if (next_port[1] == PORT_REQ) begin + { oe_latch[1], we_latch[1] } <= { ~port1_we, port1_we }; + ds[1] <= port2_ds; + din_latch[1] <= port2_d; + port2_state <= port2_req; + end else begin + { oe_latch[1], we_latch[1] } <= 2'b10; + ds[1] <= 2'b11; + end + end + + if (next_port[1] == PORT_NONE && need_refresh && !we_latch[0] && !oe_latch[0]) begin + refresh <= 1'b1; + refresh_cnt <= 0; + sd_cmd <= CMD_AUTO_REFRESH; + end + end + + // CAS phase + if(t == STATE_CAS0 && (we_latch[0] || oe_latch[0])) begin + sd_cmd <= we_latch[0]?CMD_WRITE:CMD_READ; + { SDRAM_DQMH, SDRAM_DQML } <= ~ds[0]; + if (we_latch[0]) begin + SDRAM_DQ <= din_latch[0]; + port1_ack <= port1_req; + end + SDRAM_A <= { 4'b0010, addr_latch[0][9:1] }; // auto precharge + SDRAM_BA <= addr_latch[0][24:23]; + end + + if(t == STATE_CAS1 && (we_latch[1] || oe_latch[1])) begin + sd_cmd <= we_latch[1]?CMD_WRITE:CMD_READ; + { SDRAM_DQMH, SDRAM_DQML } <= ~ds[1]; + if (we_latch[1]) begin + SDRAM_DQ <= din_latch[1]; + port2_ack <= port2_req; + end + SDRAM_A <= { 4'b0010, addr_latch[1][9:1] }; // auto precharge + SDRAM_BA <= addr_latch[1][24:23]; + end + + // Data returned + if(t == STATE_READ0 && oe_latch[0]) begin + case(port[0]) + PORT_REQ: begin port1_q <= sd_din; port1_ack <= port1_req; end + PORT_CPU1: begin cpu1_q <= sd_din; end + PORT_CPU2: begin cpu2_q <= sd_din; end + default: ; + endcase; + end + + if(t == STATE_READ1 && oe_latch[1]) begin + case(port[1]) + PORT_REQ: begin port2_q <= sd_din; port2_ack <= port2_req; end + PORT_CH1 : ch1_q <= sd_din; + PORT_CH2 : ch2_q <= sd_din; + PORT_SP1 : begin sp1_q <= sd_din; sp1_ack <= sp1_req; end + PORT_SP2 : begin sp2_q <= sd_din; sp2_ack <= sp2_req; end + default: ; + endcase; + end + + end +end + +endmodule diff --git a/Arcade_MiST/Konami Jackal/rtl/sound/Filter/audio_iir_filter.v b/Arcade_MiST/Konami Jackal/rtl/sound/Filter/audio_iir_filter.v new file mode 100644 index 00000000..ad324f04 --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/sound/Filter/audio_iir_filter.v @@ -0,0 +1,173 @@ +/*MIT License + +Copyright (c) 2019 Gregory Hogan (Soltan_G42) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ + +module iir_1st_order +#( + parameter COEFF_WIDTH = 18, + parameter COEFF_SCALE = 15, + parameter DATA_WIDTH = 16, + parameter COUNT_BITS = 10 +) +( + input clk, + input reset, + input [COUNT_BITS - 1 : 0] div, + input signed [COEFF_WIDTH - 1 : 0] A2, B1, B2, + input signed [DATA_WIDTH - 1 :0] in, + output [DATA_WIDTH - 1:0] out +); + + reg signed [DATA_WIDTH-1:0] x0,x1,y0; + reg signed [DATA_WIDTH + COEFF_WIDTH - 1 : 0] out32; + reg [COUNT_BITS - 1:0] count; + + // Usage: + // Design your 1st order iir low/high-pass with a tool that will give you the + // filter coefficients for the difference equation. Filter coefficients can + // be generated in Octave/matlab/scipy using a command similar to + // [B, A] = butter( 1, 3500/(106528/2), 'low') for a 3500 hz 1st order low-pass + // assuming 106528Hz sample rate. + // + // The Matlab output is: + // B = [0.093863 0.093863] + // A = [1.00000 -0.81227] + // + // Then scale coefficients by multiplying by 2^COEFF_SCALE and round to nearest integer + // + // B = [3076 3076] + // A = [32768 -26616] + // + // Discard A(1) because it is assumed 1.0 before scaling + // + // This leaves you with A2 = -26616 , B1 = 3076 , B2 = 3076 + // B1 + B2 - A2 should sum to 2^COEFF_SCALE = 32768 + // + // Sample frequency is "clk rate/div": for Genesis this is 53.69mhz/504 = 106528hz + // + // COEFF_WIDTH must be at least COEFF_SCALE+1 and must be large enough to + // handle temporary overflow during this computation: out32 <= (B1*x0 + B2*x1) - A2*y0 + + assign out = y0; + + always @ (*) begin + out32 <= (B1*x0 + B2*x1) - A2*y0; //Previous output is y0 not y1 + end + + always @ (posedge clk) begin + if(reset) begin + count <= 0; + x0 <= 0; + x1 <= 0; + y0 <= 0; + end + else begin + count <= count + 1'd1; + if (count == div - 1) begin + count <= 0; + y0 <= {out32[DATA_WIDTH + COEFF_WIDTH - 1] , out32[COEFF_SCALE + DATA_WIDTH - 2 : COEFF_SCALE]}; + x1 <= x0; + x0 <= in; + end + end + end + +endmodule //iir_1st_order + +module iir_2nd_order +#( + parameter COEFF_WIDTH = 18, + parameter COEFF_SCALE = 14, + parameter DATA_WIDTH = 16, + parameter COUNT_BITS = 10 +) +( + input clk, + input reset, + input [COUNT_BITS - 1 : 0] div, + input signed [COEFF_WIDTH - 1 : 0] A2, A3, B1, B2, B3, + input signed [DATA_WIDTH - 1 : 0] in, + output [DATA_WIDTH - 1 : 0] out +); + + reg signed [DATA_WIDTH-1 : 0] x0,x1,x2; + reg signed [DATA_WIDTH-1 : 0] y0,y1; + reg signed [(DATA_WIDTH + COEFF_WIDTH - 1) : 0] out32; + reg [COUNT_BITS : 0] count; + + + // Usage: + // Design your 1st order iir low/high-pass with a tool that will give you the + // filter coefficients for the difference equation. Filter coefficients can + // be generated in Octave/matlab/scipy using a command similar to + // [B, A] = butter( 2, 5000/(48000/2), 'low') for a 5000 hz 2nd order low-pass + // assuming 48000Hz sample rate. + // + // Output is: + // B = [ 0.072231 0.144462 0.072231] + // A = [1.00000 -1.10923 0.39815] + // + // Then scale coefficients by multiplying by 2^COEFF_SCALE and round to nearest integer + // Make sure your coefficients can be stored as a signed number with COEFF_WIDTH bits. + // + // B = [1183 2367 1183] + // A = [16384 -18174 6523] + // + // Discard A(1) because it is assumed 1.0 before scaling + // + // This leaves you with A2 = -18174 , A3 = 6523, B1 = 1183 , B2 = 2367 , B3 = 1183 + // B1 + B2 + B3 - A2 - A3 should sum to 2^COEFF_SCALE = 16384 + // + // Sample frequency is "clk rate/div" + // + // COEFF_WIDTH must be at least COEFF_SCALE+1 and must be large enough to + // handle temporary overflow during this computation: + // out32 <= (B1*x0 + B2*x1 + B3*x2) - (A2*y0 + A3*y1); + + assign out = y0; + + always @ (*) begin + out32 <= (B1*x0 + B2*x1 + B3*x2) - (A2*y0 + A3*y1); //Previous output is y0 not y1 + end + + always @ (posedge clk) begin + if(reset) begin + count <= 0; + x0 <= 0; + x1 <= 0; + x2 <= 0; + y0 <= 0; + y1 <= 0; + end + else begin + count <= count + 1'd1; + if (count == div - 1) begin + count <= 0; + y1 <= y0; + y0 <= {out32[DATA_WIDTH + COEFF_WIDTH - 1] , out32[(DATA_WIDTH + COEFF_SCALE - 2) : COEFF_SCALE]}; + x2 <= x1; + x1 <= x0; + x0 <= in; + end + end + end + +endmodule //iir_2nd_order \ No newline at end of file diff --git a/Arcade_MiST/Konami Jackal/rtl/sound/Filter/jackal_lpf.sv b/Arcade_MiST/Konami Jackal/rtl/sound/Filter/jackal_lpf.sv new file mode 100644 index 00000000..b9f5c51d --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/sound/Filter/jackal_lpf.sv @@ -0,0 +1,81 @@ +/*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 YM2151 on Jackal. + +module jackal_lpf( + input clk, + input reset, + input select, + input signed [15:0] in1, + input signed [15:0] in2, + output signed [15:0] out); + + localparam div = 10'd64; //Sample at 49.152MHz/64 = 768000Hz + + //Coefficients computed with Octave/Matlab/Online filter calculators. + //or with scipy.signal.bessel or similar tools + + //0.015398864, 0.015398864 + //1.0000000, -0.96920227 + reg signed [17:0] lpf1_A2; + reg signed [17:0] lpf1_B2; + reg signed [17:0] lpf1_B1; + + //0.018668513, 0.018668513 + //1.0000000, -0.96266297 + reg signed [17:0] lpf2_A2; + reg signed [17:0] lpf2_B2; + reg signed [17:0] lpf2_B1; + + wire signed [15:0] audio_pre_lpf1 = select ? in1 : in2; + wire signed [15:0] audio_post_lpf1, audio_post_lpf2; + + always @ (*) begin + lpf1_A2 = -18'd31758; + lpf1_B1 = 18'd505; + lpf1_B2 = 18'd505; + lpf2_A2 = -18'd31544; + lpf2_B1 = 18'd612; + lpf2_B2 = 18'd612; + end + + iir_1st_order lpf1_6db(.clk(clk), + .reset(reset), + .div(div), + .A2(lpf1_A2), + .B1(lpf1_B1), + .B2(lpf1_B2), + .in(audio_pre_lpf1), + .out(audio_post_lpf1)); + + iir_1st_order lpf2_6db(.clk(clk), + .reset(reset), + .div(div), + .A2(lpf2_A2), + .B1(lpf2_B1), + .B2(lpf2_B2), + .in(audio_post_lpf1), + .out(audio_post_lpf2)); + + assign out = select ? audio_post_lpf1 : audio_post_lpf2; + +endmodule diff --git a/Arcade_MiST/Konami Jackal/rtl/sound/Filter/jt49_dcrm2.v b/Arcade_MiST/Konami Jackal/rtl/sound/Filter/jt49_dcrm2.v new file mode 100644 index 00000000..4b434aec --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/sound/Filter/jt49_dcrm2.v @@ -0,0 +1,62 @@ +/* This file is part of JT49. + + JT49 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + JT49 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JT49. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 15-Jan-2019 + + */ + +// DC removal filter +// input is unsigned +// output is signed + +module jt49_dcrm2 #(parameter sw=8) ( + input clk, + input cen, + input rst, + input [sw-1:0] din, + output signed [sw-1:0] dout +); + +localparam dw=10; // widht of the decimal portion + +reg signed [sw+dw:0] integ, exact, error; +//reg signed [2*(9+dw)-1:0] mult; +// wire signed [sw+dw:0] plus1 = { {sw+dw{1'b0}},1'b1}; +reg signed [sw:0] pre_dout; +// reg signed [sw+dw:0] dout_ext; +reg signed [sw:0] q; + +always @(*) begin + exact = integ+error; + q = exact[sw+dw:dw]; + pre_dout = { 1'b0, din } - q; + //dout_ext = { pre_dout, {dw{1'b0}} }; + //mult = dout_ext; +end + +assign dout = pre_dout[sw-1:0]; + +always @(posedge clk) + if( rst ) begin + integ <= {sw+dw+1{1'b0}}; + error <= {sw+dw+1{1'b0}}; + end else if( cen ) begin + integ <= integ + pre_dout; //mult[sw+dw*2:dw]; + error <= exact-{q, {dw{1'b0}}}; + end + +endmodule \ No newline at end of file diff --git a/Arcade_MiST/Konami Jackal/rtl/sound/jackal_sound.qip b/Arcade_MiST/Konami Jackal/rtl/sound/jackal_sound.qip new file mode 100644 index 00000000..a2786f02 --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/sound/jackal_sound.qip @@ -0,0 +1,3 @@ +set_global_assignment -name SYSTEMVERILOG_FILE rtl/sound/Filter/jackal_lpf.sv +set_global_assignment -name VERILOG_FILE rtl/sound/Filter/jt49_dcrm2.v +set_global_assignment -name VERILOG_FILE rtl/sound/Filter/audio_iir_filter.v diff --git a/Arcade_MiST/Konami Jackal/rtl/spram.vhd b/Arcade_MiST/Konami Jackal/rtl/spram.vhd new file mode 100644 index 00000000..38302277 --- /dev/null +++ b/Arcade_MiST/Konami Jackal/rtl/spram.vhd @@ -0,0 +1,46 @@ +library ieee; +use IEEE.std_logic_1164.all; +use IEEE.std_logic_unsigned.ALL; +use IEEE.numeric_std.all; + +entity spram is + + generic + ( + DATA_WIDTH : natural := 8; + ADDR_WIDTH : natural := 10 + ); + + port + ( + clk : in std_logic; + addr : in std_logic_vector((ADDR_WIDTH - 1) downto 0); + data : in std_logic_vector((DATA_WIDTH - 1) downto 0); + q : out std_logic_vector((DATA_WIDTH - 1) downto 0); + we : in std_logic := '0' + ); + +end spram; + +architecture rtl of spram is + + subtype word_t is std_logic_vector((DATA_WIDTH-1) downto 0); + type memory_t is array(2**ADDR_WIDTH-1 downto 0) of word_t; + + shared variable ram : memory_t; + +begin + + process(clk) + begin + if(rising_edge(clk)) then + if(we = '1') then + ram(to_integer(unsigned(addr))) := data; + q <= data; + else + q <= ram(to_integer(unsigned(addr))); + end if; + end if; + end process; + +end rtl; diff --git a/common/CPU/MC6809/mc6809is.v b/common/CPU/MC6809/mc6809is.v index d0d2086e..fdb860e6 100644 --- a/common/CPU/MC6809/mc6809is.v +++ b/common/CPU/MC6809/mc6809is.v @@ -535,13 +535,12 @@ endgenerate /////////////////////////////////////////////////////////////////////// -always @(posedge CLK) +always @(posedge CLK or posedge wNMIClear) begin - reg old_sample; - old_sample <= NMISample2; - - if (wNMIClear == 1) NMILatched <= 1; - else if(old_sample & ~NMISample2) NMILatched <= NMIMask; + if (wNMIClear == 1) + NMILatched <= 1; + else if (fallE_en && ~NMISample & NMISample2) // falling edge of NMISample2 + NMILatched <= NMIMask; end //