From 6c0a02220fa1ce3222bdbbb14a9e29037c0fb6e1 Mon Sep 17 00:00:00 2001 From: Gyorgy Szombathelyi Date: Thu, 22 Jul 2021 14:53:17 +0200 Subject: [PATCH] Gyruss: a quick port --- Arcade_MiST/Konami Gyruss/Gyruss.qpf | 31 + Arcade_MiST/Konami Gyruss/Gyruss.qsf | 253 + Arcade_MiST/Konami Gyruss/Gyruss.sdc | 136 + Arcade_MiST/Konami Gyruss/README.md | 11 + Arcade_MiST/Konami Gyruss/meta/Gyruss.mra | 75 + .../rtl/Filters/audio_iir_filter.v | 173 + .../Konami Gyruss/rtl/Filters/gyruss_lpf.v | 60 + .../rtl/Filters/gyruss_lpf_heavy.v | 60 + .../rtl/Filters/gyruss_lpf_light.v | 60 + .../rtl/Filters/gyruss_lpf_medium.v | 60 + Arcade_MiST/Konami Gyruss/rtl/Gyruss.sv | 192 + Arcade_MiST/Konami Gyruss/rtl/Gyruss_CPU.sv | 996 ++++ Arcade_MiST/Konami Gyruss/rtl/Gyruss_MiST.sv | 277 ++ Arcade_MiST/Konami Gyruss/rtl/Gyruss_SND.sv | 762 +++ Arcade_MiST/Konami Gyruss/rtl/build_id.tcl | 35 + .../rtl/custom/KONAMI-1/KONAMI1.sv | 79 + .../rtl/custom/KONAMI-1/mc6809isk.v | 4162 +++++++++++++++++ .../rtl/custom/gyruss_custom.qip | 7 + Arcade_MiST/Konami Gyruss/rtl/custom/k082.sv | 168 + Arcade_MiST/Konami Gyruss/rtl/custom/k083.sv | 101 + Arcade_MiST/Konami Gyruss/rtl/custom/k501.sv | 101 + Arcade_MiST/Konami Gyruss/rtl/custom/k502.sv | 162 + Arcade_MiST/Konami Gyruss/rtl/custom/k503.sv | 119 + Arcade_MiST/Konami Gyruss/rtl/hiscore.v | 602 +++ Arcade_MiST/Konami Gyruss/rtl/jt49_dcrm2.v | 64 + .../Konami Gyruss/rtl/jtframe_frac_cen.v | 58 + Arcade_MiST/Konami Gyruss/rtl/pll.qip | 4 + Arcade_MiST/Konami Gyruss/rtl/pll.v | 348 ++ .../Konami Gyruss/rtl/ram_rom/dpram_dc.vhd | 136 + .../rtl/ram_rom/gyruss_ram_rom.qip | 3 + .../Konami Gyruss/rtl/ram_rom/rom_loader.sv | 452 ++ .../Konami Gyruss/rtl/ram_rom/spram.vhd | 46 + Arcade_MiST/Konami Gyruss/rtl/sdram.sv | 357 ++ 33 files changed, 10150 insertions(+) create mode 100644 Arcade_MiST/Konami Gyruss/Gyruss.qpf create mode 100644 Arcade_MiST/Konami Gyruss/Gyruss.qsf create mode 100644 Arcade_MiST/Konami Gyruss/Gyruss.sdc create mode 100644 Arcade_MiST/Konami Gyruss/README.md create mode 100644 Arcade_MiST/Konami Gyruss/meta/Gyruss.mra create mode 100644 Arcade_MiST/Konami Gyruss/rtl/Filters/audio_iir_filter.v create mode 100644 Arcade_MiST/Konami Gyruss/rtl/Filters/gyruss_lpf.v create mode 100644 Arcade_MiST/Konami Gyruss/rtl/Filters/gyruss_lpf_heavy.v create mode 100644 Arcade_MiST/Konami Gyruss/rtl/Filters/gyruss_lpf_light.v create mode 100644 Arcade_MiST/Konami Gyruss/rtl/Filters/gyruss_lpf_medium.v create mode 100644 Arcade_MiST/Konami Gyruss/rtl/Gyruss.sv create mode 100644 Arcade_MiST/Konami Gyruss/rtl/Gyruss_CPU.sv create mode 100644 Arcade_MiST/Konami Gyruss/rtl/Gyruss_MiST.sv create mode 100644 Arcade_MiST/Konami Gyruss/rtl/Gyruss_SND.sv create mode 100644 Arcade_MiST/Konami Gyruss/rtl/build_id.tcl create mode 100644 Arcade_MiST/Konami Gyruss/rtl/custom/KONAMI-1/KONAMI1.sv create mode 100644 Arcade_MiST/Konami Gyruss/rtl/custom/KONAMI-1/mc6809isk.v create mode 100644 Arcade_MiST/Konami Gyruss/rtl/custom/gyruss_custom.qip create mode 100644 Arcade_MiST/Konami Gyruss/rtl/custom/k082.sv create mode 100644 Arcade_MiST/Konami Gyruss/rtl/custom/k083.sv create mode 100644 Arcade_MiST/Konami Gyruss/rtl/custom/k501.sv create mode 100644 Arcade_MiST/Konami Gyruss/rtl/custom/k502.sv create mode 100644 Arcade_MiST/Konami Gyruss/rtl/custom/k503.sv create mode 100644 Arcade_MiST/Konami Gyruss/rtl/hiscore.v create mode 100644 Arcade_MiST/Konami Gyruss/rtl/jt49_dcrm2.v create mode 100644 Arcade_MiST/Konami Gyruss/rtl/jtframe_frac_cen.v create mode 100644 Arcade_MiST/Konami Gyruss/rtl/pll.qip create mode 100644 Arcade_MiST/Konami Gyruss/rtl/pll.v create mode 100644 Arcade_MiST/Konami Gyruss/rtl/ram_rom/dpram_dc.vhd create mode 100644 Arcade_MiST/Konami Gyruss/rtl/ram_rom/gyruss_ram_rom.qip create mode 100644 Arcade_MiST/Konami Gyruss/rtl/ram_rom/rom_loader.sv create mode 100644 Arcade_MiST/Konami Gyruss/rtl/ram_rom/spram.vhd create mode 100644 Arcade_MiST/Konami Gyruss/rtl/sdram.sv diff --git a/Arcade_MiST/Konami Gyruss/Gyruss.qpf b/Arcade_MiST/Konami Gyruss/Gyruss.qpf new file mode 100644 index 00000000..12667bc5 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/Gyruss.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 = "Gyruss" + diff --git a/Arcade_MiST/Konami Gyruss/Gyruss.qsf b/Arcade_MiST/Konami Gyruss/Gyruss.qsf new file mode 100644 index 00000000..88e7856c --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/Gyruss.qsf @@ -0,0 +1,253 @@ +# -------------------------------------------------------------------------- # +# +# 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: +# Gyruss_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 Gyruss_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/sndcpu.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(Gyruss_MiST) + + # Pin & Location Assignments + # ========================== + + # Fitter Assignments + # ================== + + # start DESIGN_PARTITION(Top) + # --------------------------- + + # Incremental Compilation Assignments + # =================================== + + # end DESIGN_PARTITION(Top) + # ------------------------- + +# end ENTITY(Gyruss_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 SYSTEMVERILOG_FILE rtl/Gyruss_MiST.sv +set_global_assignment -name QIP_FILE rtl/pll.qip +set_global_assignment -name SYSTEMVERILOG_FILE rtl/Gyruss.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/sdram.sv +set_global_assignment -name VERILOG_FILE rtl/jtframe_frac_cen.v +set_global_assignment -name VERILOG_FILE rtl/jt49_dcrm2.v +set_global_assignment -name VERILOG_FILE rtl/hiscore.v +set_global_assignment -name SYSTEMVERILOG_FILE rtl/Gyruss_SND.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/Gyruss_CPU.sv +set_global_assignment -name VERILOG_FILE rtl/Filters/gyruss_lpf.v +set_global_assignment -name VERILOG_FILE rtl/Filters/gyruss_lpf_medium.v +set_global_assignment -name VERILOG_FILE rtl/Filters/gyruss_lpf_light.v +set_global_assignment -name VERILOG_FILE rtl/Filters/gyruss_lpf_heavy.v +set_global_assignment -name VERILOG_FILE rtl/Filters/audio_iir_filter.v +set_global_assignment -name QIP_FILE rtl/custom/gyruss_custom.qip +set_global_assignment -name VHDL_FILE rtl/ram_rom/spram.vhd +set_global_assignment -name SYSTEMVERILOG_FILE rtl/ram_rom/rom_loader.sv +set_global_assignment -name QIP_FILE rtl/ram_rom/gyruss_ram_rom.qip +set_global_assignment -name VHDL_FILE rtl/ram_rom/dpram_dc.vhd +set_global_assignment -name QIP_FILE ../../common/mist/mist.qip +set_global_assignment -name QIP_FILE ../../common/CPU/T80/T80.qip +set_global_assignment -name QIP_FILE ../../common/CPU/t48/i8039.qip +set_global_assignment -name QIP_FILE ../../common/Sound/JT49/jt49.qip +set_global_assignment -name SIGNALTAP_FILE output_files/sndcpu.stp +set_global_assignment -name ALLOW_POWER_UP_DONT_CARE ON +set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/Arcade_MiST/Konami Gyruss/Gyruss.sdc b/Arcade_MiST/Konami Gyruss/Gyruss.sdc new file mode 100644 index 00000000..a28c4467 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/Gyruss.sdc @@ -0,0 +1,136 @@ +## 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 sys_clk "pll|altpll_component|auto_generated|pll1|clk[0]" +set sdram_clk "pll|altpll_component|auto_generated|pll1|clk[0]" +set aud_clk "pll|altpll_component|auto_generated|pll1|clk[0]" +#************************************************************** +# 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 $aud_clk] 1.000 [get_ports {AUDIO_L}] +set_output_delay -clock [get_clocks $aud_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_clock_groups -asynchronous -group [get_clocks $sys_clk] -group [get_clocks $aud_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 Gyruss/README.md b/Arcade_MiST/Konami Gyruss/README.md new file mode 100644 index 00000000..16c55805 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/README.md @@ -0,0 +1,11 @@ +# MiST port of Konami Gyruss by ACE + +https://github.com/MiSTer-devel/Arcade-Gyruss_MiSTer + +## Usage + +- Create ROM and ARC files from the MRA files using the MRA utility. + Example: mra -A -z /path/to/mame/roms "Gyruss.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 Gyruss/meta/Gyruss.mra b/Arcade_MiST/Konami Gyruss/meta/Gyruss.mra new file mode 100644 index 00000000..2eef1d3e --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/meta/Gyruss.mra @@ -0,0 +1,75 @@ + + Gyruss + + no + no + + + + + 1983 + Konami + Shooter - Tube + + gyruss + gyruss + 0218 + Gyruss + + + + 15kHz + vertical (cw) + no + + 2 (alternating) + 4-way + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 01 00 00 00 00 FF 00 02 00 02 00 01 00 FF 00 00 + 00 00 94 88 00 28 00 83 + 00 00 94 0B 00 03 00 01 + + + + + + + + + 20210430005030 + diff --git a/Arcade_MiST/Konami Gyruss/rtl/Filters/audio_iir_filter.v b/Arcade_MiST/Konami Gyruss/rtl/Filters/audio_iir_filter.v new file mode 100644 index 00000000..ad324f04 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/Filters/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 Gyruss/rtl/Filters/gyruss_lpf.v b/Arcade_MiST/Konami Gyruss/rtl/Filters/gyruss_lpf.v new file mode 100644 index 00000000..cb4ef070 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/Filters/gyruss_lpf.v @@ -0,0 +1,60 @@ +/*MIT License + +Copyright (c) 2019 Gregory Hogan (Soltan_G42) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ + +//This is a variation of Gregory Hogan's MISTer Genesis core low-pass filter +//tuned to remove aliasing on Gyruss. + +module gyruss_lpf( + input clk, + input reset, + input signed [15:0] in, + output signed [15:0] out); + + localparam div = 10'd220; //Sample at 49.152/220 = 223418Hz + + //Coefficients computed with Octave/Matlab/Online filter calculators. + //or with scipy.signal.bessel or similar tools + + //0.045425748, 0.045425748 + //1.0000000, -0.90914850 + reg signed [17:0] A2; + reg signed [17:0] B2; + reg signed [17:0] B1; + + wire signed [15:0] audio_post_lpf1; + + always @ (*) begin + A2 = -18'd18211; + B1 = 18'd7278; + B2 = 18'd7278; + end + + iir_1st_order lpf6db(.clk(clk), + .reset(reset), + .div(div), + .A2(A2), + .B1(B1), + .B2(B2), + .in(in), + .out(audio_post_lpf1)); + + assign out = audio_post_lpf1; + +endmodule diff --git a/Arcade_MiST/Konami Gyruss/rtl/Filters/gyruss_lpf_heavy.v b/Arcade_MiST/Konami Gyruss/rtl/Filters/gyruss_lpf_heavy.v new file mode 100644 index 00000000..e90bd881 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/Filters/gyruss_lpf_heavy.v @@ -0,0 +1,60 @@ +/*MIT License + +Copyright (c) 2019 Gregory Hogan (Soltan_G42) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ + +//This is a variation of Gregory Hogan's MISTer Genesis core low-pass filter +//tuned to match the heaviest low-pass filter on Gyruss. + +module gyruss_lpf_heavy( + input clk, + input reset, + input signed [15:0] in, + output signed [15:0] out); + + localparam div = 10'd220; //Sample at 49.152/220 = 223418Hz + + //Coefficients computed with Octave/Matlab/Online filter calculators. + //or with scipy.signal.bessel or similar tools + + //0.0041276697, 0.0041276697 + //1.0000000, -0.99174466 + reg signed [17:0] A2; + reg signed [17:0] B2; + reg signed [17:0] B1; + + wire signed [15:0] audio_post_lpf1; + + always @ (*) begin + A2 = -18'd32498; + B1 = 18'd135; + B2 = 18'd135; + end + + iir_1st_order lpf6db(.clk(clk), + .reset(reset), + .div(div), + .A2(A2), + .B1(B1), + .B2(B2), + .in(in), + .out(audio_post_lpf1)); + + assign out = audio_post_lpf1; + +endmodule diff --git a/Arcade_MiST/Konami Gyruss/rtl/Filters/gyruss_lpf_light.v b/Arcade_MiST/Konami Gyruss/rtl/Filters/gyruss_lpf_light.v new file mode 100644 index 00000000..1129e712 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/Filters/gyruss_lpf_light.v @@ -0,0 +1,60 @@ +/*MIT License + +Copyright (c) 2019 Gregory Hogan (Soltan_G42) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ + +//This is a variation of Gregory Hogan's MISTer Genesis core low-pass filter +//tuned to match the lightest low-pass filter on Gyruss. + +module gyruss_lpf_light( + input clk, + input reset, + input signed [15:0] in, + output signed [15:0] out); + + localparam div = 10'd220; //Sample at 49.152/220 = 223418Hz + + //Coefficients computed with Octave/Matlab/Online filter calculators. + //or with scipy.signal.bessel or similar tools + + //0.017174022, 0.017174022 + //1.0000000, -0.96565196 + reg signed [17:0] A2; + reg signed [17:0] B2; + reg signed [17:0] B1; + + wire signed [15:0] audio_post_lpf1; + + always @ (*) begin + A2 = -18'd31642; + B1 = 18'd563; + B2 = 18'd563; + end + + iir_1st_order lpf6db(.clk(clk), + .reset(reset), + .div(div), + .A2(A2), + .B1(B1), + .B2(B2), + .in(in), + .out(audio_post_lpf1)); + + assign out = audio_post_lpf1; + +endmodule diff --git a/Arcade_MiST/Konami Gyruss/rtl/Filters/gyruss_lpf_medium.v b/Arcade_MiST/Konami Gyruss/rtl/Filters/gyruss_lpf_medium.v new file mode 100644 index 00000000..603eba2b --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/Filters/gyruss_lpf_medium.v @@ -0,0 +1,60 @@ +/*MIT License + +Copyright (c) 2019 Gregory Hogan (Soltan_G42) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ + +//This is a variation of Gregory Hogan's MISTer Genesis core low-pass filter +//tuned to match the middle low-pass filter on Gyruss. + +module gyruss_lpf_medium( + input clk, + input reset, + input signed [15:0] in, + output signed [15:0] out); + + localparam div = 10'd220; //Sample at 49.152/220 = 223418Hz + + //Coefficients computed with Octave/Matlab/Online filter calculators. + //or with scipy.signal.bessel or similar tools + + //0.0053024160, 0.0053024160 + //1.0000000, -0.98939517 + reg signed [17:0] A2; + reg signed [17:0] B2; + reg signed [17:0] B1; + + wire signed [15:0] audio_post_lpf1; + + always @ (*) begin + A2 = -18'd32420; + B1 = 18'd174; + B2 = 18'd174; + end + + iir_1st_order lpf6db(.clk(clk), + .reset(reset), + .div(div), + .A2(A2), + .B1(B1), + .B2(B2), + .in(in), + .out(audio_post_lpf1)); + + assign out = audio_post_lpf1; + +endmodule diff --git a/Arcade_MiST/Konami Gyruss/rtl/Gyruss.sv b/Arcade_MiST/Konami Gyruss/rtl/Gyruss.sv new file mode 100644 index 00000000..038c637c --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/Gyruss.sv @@ -0,0 +1,192 @@ +//============================================================================ +// +// Gyruss top-level module +// 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. +// +//============================================================================ + +//Module declaration, I/O ports +module Gyruss +( + input reset, + input clk_49m, //Actual frequency: 49.152MHz + input [1:0] coin, //0 = coin 1, 1 = coin 2 + input [1:0] start_buttons, //0 = Player 1, 1 = Player 2 + input [3:0] p1_joystick, p2_joystick, //0 = up, 1 = down, 2 = left, 3 = right + input p1_fire, + input p2_fire, + input btn_service, + input [23:0] dip_sw, + output video_hsync, video_vsync, video_csync, + output video_hblank, video_vblank, + output ce_pix, + output [2:0] video_r, video_g, + output [1:0] video_b, + output signed [15:0] sound_l, sound_r, + + //Screen centering (alters HSync, VSync and VBlank timing in the Konami 082 to reposition the video output) + input [3:0] h_center, v_center, + + input [24:0] ioctl_addr, + input [7:0] ioctl_data, + input ioctl_wr, + + input pause, + + input [10:0] hs_address, + input [7:0] hs_data_in, + output [7:0] hs_data_out, + input hs_write, + input hs_access, + + output [15:0] main_cpu_rom_addr, + input [7:0] main_cpu_rom_do, + output [12:0] sub_cpu_rom_addr, + input [7:0] sub_cpu_rom_do, + output [12:0] sp_rom_addr, + input [31:0] sp_rom_do +); + +//Linking signals between PCBs +wire A5, A6, irq_trigger, cs_sounddata, cs_controls_dip1, cs_dip2, cs_dip3; +wire [7:0] controls_dip, cpubrd_D; + +//ROM loader signals for MISTer (loads ROMs from SD card) +wire ep1_cs_i, ep2_cs_i, ep3_cs_i, ep4_cs_i, ep5_cs_i, ep6_cs_i, ep7_cs_i, ep8_cs_i, ep9_cs_i, + ep10_cs_i, ep11_cs_i, ep12_cs_i; +wire cp_cs_i, tl_cs_i, sl_cs_i; + +//MiSTer data write selector +selector DLSEL +( + .ioctl_addr(ioctl_addr), + .ep1_cs(ep1_cs_i), + .ep2_cs(ep2_cs_i), + .ep3_cs(ep3_cs_i), + .ep4_cs(ep4_cs_i), + .ep5_cs(ep5_cs_i), + .ep6_cs(ep6_cs_i), + .ep7_cs(ep7_cs_i), + .ep8_cs(ep8_cs_i), + .ep9_cs(ep9_cs_i), + .ep10_cs(ep10_cs_i), + .ep11_cs(ep11_cs_i), + .ep12_cs(ep12_cs_i), + .cp_cs(cp_cs_i), + .tl_cs(tl_cs_i), + .sl_cs(sl_cs_i) +); + +//Instantiate main PCB +Gyruss_CPU main_pcb +( + .reset(reset), + .clk_49m(clk_49m), + .red(video_r), + .green(video_g), + .blue(video_b), + .video_hsync(video_hsync), + .video_vsync(video_vsync), + .video_csync(video_csync), + .video_hblank(video_hblank), + .video_vblank(video_vblank), + .ce_pix(ce_pix), + + .h_center(h_center), + .v_center(v_center), + + .controls_dip(controls_dip), + .cpubrd_Dout(cpubrd_D), + .cpubrd_A5(A5), + .cpubrd_A6(A6), + .cs_sounddata(cs_sounddata), + .irq_trigger(irq_trigger), + .cs_dip2(cs_dip2), + .cs_dip3(cs_dip3), + .cs_controls_dip1(cs_controls_dip1), + + .ep1_cs_i(ep1_cs_i), + .ep2_cs_i(ep2_cs_i), + .ep3_cs_i(ep3_cs_i), + .ep4_cs_i(ep4_cs_i), + .ep5_cs_i(ep5_cs_i), + .ep6_cs_i(ep6_cs_i), + .ep7_cs_i(ep7_cs_i), + .ep8_cs_i(ep8_cs_i), + .ep9_cs_i(ep9_cs_i), + .cp_cs_i(cp_cs_i), + .tl_cs_i(tl_cs_i), + .sl_cs_i(sl_cs_i), + .ioctl_addr(ioctl_addr), + .ioctl_wr(ioctl_wr), + .ioctl_data(ioctl_data), + + .pause(pause), + + .hs_address(hs_address), + .hs_data_in(hs_data_in), + .hs_data_out(hs_data_out), + .hs_write(hs_write), + .hs_access(hs_access), + + .main_cpu_rom_addr(main_cpu_rom_addr), + .main_cpu_rom_do(main_cpu_rom_do), + .sub_cpu_rom_addr(sub_cpu_rom_addr), + .sub_cpu_rom_do(sub_cpu_rom_do), + .sp_rom_addr(sp_rom_addr), + .sp_rom_do(sp_rom_do) +); + +//Instantiate sound PCB +Gyruss_SND sound_pcb +( + .reset(reset), + .clk_49m(clk_49m), + .irq_trigger(irq_trigger), + .cs_sounddata(cs_sounddata), + .dip_sw(dip_sw), + .coin(coin), + .start_buttons(start_buttons), + .p1_joystick(p1_joystick), + .p2_joystick(p2_joystick), + .p1_fire(p1_fire), + .p2_fire(p2_fire), + .btn_service(btn_service), + + .cs_controls_dip1(cs_controls_dip1), + .cs_dip2(cs_dip2), + .cs_dip3(cs_dip3), + .cpubrd_A5(A5), + .cpubrd_A6(A6), + .cpubrd_Din(cpubrd_D), + .controls_dip(controls_dip), + .sound_l(sound_l), + .sound_r(sound_r), + + .ep10_cs_i(ep10_cs_i), + .ep11_cs_i(ep11_cs_i), + .ep12_cs_i(ep12_cs_i), + .ioctl_addr(ioctl_addr), + .ioctl_wr(ioctl_wr), + .ioctl_data(ioctl_data) +); + +endmodule diff --git a/Arcade_MiST/Konami Gyruss/rtl/Gyruss_CPU.sv b/Arcade_MiST/Konami Gyruss/rtl/Gyruss_CPU.sv new file mode 100644 index 00000000..3fc12647 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/Gyruss_CPU.sv @@ -0,0 +1,996 @@ +//============================================================================ +// +// Gyruss main PCB model +// 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. +// +//============================================================================ + +//Module declaration, I/O ports +module Gyruss_CPU +( + input reset, + input clk_49m, //Actual frequency: 49.152MHz + output [2:0] red, green, //8-bit RGB, 3 bits per color for red and green, + output [1:0] blue, //2 bits for blue + output video_hsync, video_vsync, video_csync, //CSync not needed for MISTer + output video_hblank, video_vblank, + output ce_pix, + + input [7:0] controls_dip, + output [7:0] cpubrd_Dout, + output cpubrd_A5, cpubrd_A6, + output cs_sounddata, irq_trigger, + output cs_dip3, cs_dip2, cs_controls_dip1, + + //Screen centering (alters HSync, VSync and VBlank timing in the Konami 082 to reposition the video output) + input [3:0] h_center, v_center, + + input ep1_cs_i, + input ep2_cs_i, + input ep3_cs_i, + input ep4_cs_i, + input ep5_cs_i, + input ep6_cs_i, + input ep7_cs_i, + input ep8_cs_i, + input ep9_cs_i, + input cp_cs_i, + input tl_cs_i, + input sl_cs_i, + 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, + + output [15:0] main_cpu_rom_addr, + input [7:0] main_cpu_rom_do, + output [12:0] sub_cpu_rom_addr, + input [7:0] sub_cpu_rom_do, + output [12:0] sp_rom_addr, + input [31:0] sp_rom_do +); + +//------------------------------------------------------- Signal outputs -------------------------------------------------------// + +//Assign active high HBlank and VBlank outputs +assign video_hblank = hblk; +assign video_vblank = vblk; + +//Output pixel clock enable +assign ce_pix = cen_6m; + +//Output select lines for player inputs and DIP switches to sound board +assign cs_controls_dip1 = (~n_k501_enable & z80_A[14]) & (z80_A[8:7] == 2'b01) & n_ram_write; +assign cs_dip2 = (~n_k501_enable & z80_A[14]) & (z80_A[8:7] == 2'b00) & n_ram_write; +assign cs_dip3 = (~n_k501_enable & z80_A[14]) & (z80_A[8:7] == 2'b10) & n_ram_write; + +//Output primary MC6809E address lines A5 and A6 to sound board +assign cpubrd_A5 = z80_A[5]; +assign cpubrd_A6 = z80_A[6]; + +//Assign CPU board data output to sound board +assign cpubrd_Dout = z80_Dout; + +//Generate and output chip select for latching sound data to sound CPU +assign cs_sounddata = (~n_k501_enable & z80_A[14]) & (z80_A[8:7] == 2'b10) & ~n_ram_write; + +//Generate sound IRQ trigger +wire cs_soundirq = (~n_k501_enable & z80_A[14]) & (z80_A[8:7] == 2'b01) & ~n_ram_write; +reg sound_irq = 1; +always_ff @(posedge clk_49m) begin + if(n_cen_3m) begin + if(cs_soundirq) + sound_irq <= 1; + else + sound_irq <= 0; + end +end +assign irq_trigger = sound_irq; + +//------------------------------------------------------- Clock division -------------------------------------------------------// + +//Generate 12.288MHz, 6.144MHz, 3.072MHz and 1.576MHz clock enables +reg [4:0] div = 5'd0; +always_ff @(posedge clk_49m) begin + div <= div + 5'd1; +end +reg [3:0] n_div = 4'd0; +always_ff @(negedge clk_49m) begin + n_div <= n_div + 4'd1; +end +wire cen_12m = !div[1:0]; +wire cen_6m = !div[2:0]; +wire cen_3m = !div[3:0]; +wire n_cen_3m = !n_div; +wire cen_1m5 = !div; + +//Generate E and Q clock enables for KONAMI-1 (code adapted from Sorgelig's phase generator used in the MiSTer Vectrex core) +reg k1_E, k1_Q; +always_ff @(posedge clk_49m) begin + reg [1:0] clk_phase = 0; + k1_E <= 0; + k1_Q <= 0; + if(cen_6m) begin + clk_phase <= clk_phase + 1'd1; + case(clk_phase) + 2'b01: k1_Q <= 1; + 2'b10: k1_E <= 1; + endcase + end +end + +//------------------------------------------------------------ CPUs ------------------------------------------------------------// + +//Primary CPU - Zilog Z80 (uses T80s version of the T80 soft core) +wire [15:0] z80_A; +wire [7:0] z80_Dout; +wire n_mreq, n_rd, n_rfsh; +T80s u13G +( + .RESET_n(reset), + .CLK(clk_49m), + .CEN(n_cen_3m & ~pause), + .NMI_n(z80_nmi), + .WAIT_n(n_wait), + .MREQ_n(n_mreq), + .RD_n(n_rd), + .RFSH_n(n_rfsh), + .A(z80_A), + .DI(z80_Din), + .DO(z80_Dout) +); +//Address decoding for Z80 +wire cs_rom1 = ~n_mreq & n_rfsh & (z80_A[15:13] == 3'b000); +wire cs_rom2 = ~n_mreq & n_rfsh & (z80_A[15:13] == 3'b001); +wire cs_rom3 = ~n_mreq & n_rfsh & (z80_A[15:13] == 3'b010); +wire n_cs_k501 = ~(~n_mreq & n_rfsh & z80_A[15]); +wire cs_mainlatch = (~n_k501_enable & z80_A[14]) & (z80_A[8:7] == 2'b11) & ~n_ram_write; +wire cs_z80sharedram = (z80_A[14:13] == 2'b01) & ~n_k501_enable; +wire n_cs_vram_wram = ~((z80_A[14:13] == 2'b00) & ~n_k501_enable); +//Part of the RAM decoding is handled by the Konami 501 custom chip - instantiate an instance of this IC here +wire n_wait, n_ram_write, n_k501_enable; +wire [7:0] k501_D, k501_Dout; +k501 u11E +( + .CLK(clk_49m), + .CEN(cen_12m), + .H1(h_cnt[0]), + .H2(h_cnt[1]), + .RAM(n_cs_k501), + .RD(n_rd), + .WAIT(n_wait), + .WRITE(n_ram_write), + .ENABLE(n_k501_enable), + .Di(z80_Dout), + .XDi(k501_Din), + .Do(k501_Dout), + .XDo(k501_D) +); +//Multiplex data inputs to Z80 +wire [7:0] z80_Din = cs_rom1 ? eprom1_D: + cs_rom2 ? eprom2_D: + cs_rom3 ? eprom3_D: + ~n_cs_k501 ? k501_Dout: + 8'hFF; + +assign main_cpu_rom_addr = z80_A[14:0]; +//Z80 ROMs +//ROM 1/3 +wire [7:0] eprom1_D = main_cpu_rom_do; +/* +eprom_1 u11J +( + .ADDR(z80_A[12:0]), + .CLK(clk_49m), + .DATA(eprom1_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(ep1_cs_i), + .WR(ioctl_wr) +);*/ +//ROM 2/3 +wire [7:0] eprom2_D = main_cpu_rom_do; +/* +eprom_2 u12J +( + .ADDR(z80_A[12:0]), + .CLK(clk_49m), + .DATA(eprom2_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(ep2_cs_i), + .WR(ioctl_wr) +);*/ +//ROM 3/3 +wire [7:0] eprom3_D = main_cpu_rom_do; +/* +eprom_3 u13J +( + .ADDR(z80_A[12:0]), + .CLK(clk_49m), + .DATA(eprom3_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(ep3_cs_i), + .WR(ioctl_wr) +);*/ + +//Multiplex data input to Konami 501 data bus passthrough +wire [7:0] k501_Din = (~n_cs_vram_wram & cs_wram0 & n_vram_wram_wr) ? wram0_D: + (~n_cs_vram_wram & cs_wram1 & n_vram_wram_wr) ? wram1_D: + (~n_cs_vram_wram & ~n_cs_vram & n_vram_wram_wr) ? vram_D: + (cs_z80sharedram & n_z80_sharedram_wr) ? z80_sharedram_D: + (cs_controls_dip1 | cs_dip2 | cs_dip3) ? controls_dip: + 8'hFF; + +//Main latch +reg z80_nmi_mask = 0; +reg flip = 0; +always_ff @(posedge clk_49m) begin + if(!reset) begin + z80_nmi_mask <= 0; + flip <= 0; + end + else if(n_cen_3m) begin + if(cs_mainlatch) + case(z80_A[2:0]) + 3'b000: z80_nmi_mask <= k501_D[0]; + 3'b101: flip <= k501_D[0]; + default:; + endcase + end +end + +//Generate VBlank NMI for Z80 +reg z80_nmi = 1; +always_ff @(posedge clk_49m) begin + if(cen_6m) begin + if(!z80_nmi_mask) + z80_nmi <= 1; + else if(vblank_irq_en) + z80_nmi <= 0; + end +end + +//VRAM +wire [7:0] vram_D; +spram #(8, 11) u5J +( + .clk(clk_49m), + .we(~n_cs_vram_wram & ~n_cs_vram & ~n_vram_wram_wr), + .addr(vram_wram_A), + .data(k501_D), + .q(vram_D) +); +//Z80 work RAM +//Bank 0 + +// Hiscore mux +wire [10:0] u3J_addr = hs_access ? hs_address[10:0] : vram_wram_A; +wire [7:0] u3J_din = hs_access ? hs_data_in : k501_D; +wire u3J_wren = hs_access ? hs_write : (~n_cs_vram_wram & cs_wram0 & ~n_vram_wram_wr); +wire [7:0] u3J_dout; +assign wram0_D = hs_access ? 8'h00 : u3J_dout; +assign hs_data_out = hs_access ? u3J_dout : 8'h00; + +wire [7:0] wram0_D; +spram #(8, 11) u3J +( + .clk(clk_49m), + .we(u3J_wren), + .addr(u3J_addr), + .data(u3J_din), + .q(u3J_dout) +); +//Bank 1 +wire [7:0] wram1_D; +spram #(8, 11) u2J +( + .clk(clk_49m), + .we(~n_cs_vram_wram & cs_wram1 & ~n_vram_wram_wr), + .addr(vram_wram_A), + .data(k501_D), + .q(wram1_D) +); +//Generate select lines and write enable for work RAM and VRAM +wire n_cs_vram = z80_A[12] & ~h_cnt[1]; +wire cs_wram0 = n_cs_vram & ~z80_A[11]; +wire cs_wram1 = n_cs_vram & z80_A[11]; +wire n_vram_wram_wr = n_cs_vram_wram | n_ram_write; + +//Shared RAM +wire [7:0] z80_sharedram_D, k1_sharedram_D; +dpram_dc #(.widthad_a(11)) u17C +( + .clock_a(clk_49m), + .address_a(z80_A[10:0]), + .data_a(k501_D), + .q_a(z80_sharedram_D), + .wren_a(cs_z80sharedram & ~n_z80_sharedram_wr), + + .clock_b(clk_49m), + .address_b(k1_A[10:0]), + .data_b(k1_Dout), + .q_b(k1_sharedram_D), + .wren_b(cs_k1sharedram & ~k1_rw & h_cnt[1]) +); +//Generate write enable for Z80 section of shared RAM (active low) +wire n_z80_sharedram_wr = ~cs_z80sharedram | n_ram_write; + +//Secondary CPU - KONAMI-1 custom encrypted MC6809E (uses synchronous version of Greg Miller's cycle-accurate MC6809E made by +//Sorgelig with a wrapper to decrypt XOR/XNOR-encrypted opcodes and a further modification to Greg's MC6809E to directly +//accept the opcodes) +wire k1_rw; +wire [15:0] k1_A; +wire [7:0] k1_Dout; +KONAMI1 u18F +( + .CLK(clk_49m), + .fallE_en(k1_E), + .fallQ_en(k1_Q), + .D(k1_Din), + .DOut(k1_Dout), + .ADDR(k1_A), + .RnW(k1_rw), + .nIRQ(k1_irq), + .nFIRQ(1), + .nNMI(1), + .nHALT(1), + .nRESET(reset) +); + +//Address decoding for KONAMI-1 +wire cs_beam = (k1_A[15:13] == 3'b000) & k1_rw; +wire cs_k1irqmask = (k1_A[15:13] == 3'b001) & ~k1_rw; +wire cs_spriteram = (k1_A[15:13] == 3'b010); +wire cs_k1sharedram = (k1_A[15:13] == 3'b011); +wire cs_rom4 = (k1_A[15:13] == 3'b111); +//Multiplex data inputs to KONAMI-1 +wire [7:0] k1_Din = cs_beam ? v_cnt: + (cs_spriteram & cs_spriteram0 & ~spriteram0_wr) ? spriteram_D[7:0]: + (cs_spriteram & cs_spriteram1 & ~spriteram1_wr) ? spriteram_D[15:8]: + (cs_k1sharedram & k1_rw & h_cnt[1]) ? k1_sharedram_D: + cs_rom4 ? eprom4_D: + 8'hFF; + +assign sub_cpu_rom_addr = k1_A[12:0]; +//KONAMI-1 ROM +wire [7:0] eprom4_D = sub_cpu_rom_do; +/* +eprom_4 u19E +( + .ADDR(k1_A[12:0]), + .CLK(clk_49m), + .DATA(eprom4_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(ep4_cs_i), + .WR(ioctl_wr) +); +*/ +//Generate write enable for all KONAMI-1 RAM (active low) +wire k1_rw1 = h1d | k1_rw; + +//Generate IRQ mask for KONAMI-1 +reg k1_irq_mask; +always_ff @(posedge clk_49m) begin + if(!reset) + k1_irq_mask <= 0; + else if(cen_3m && cs_k1irqmask) + k1_irq_mask <= k1_Dout[0]; +end + +//Generate VBlank IRQ for KONAMI-1 +reg k1_irq = 1; +always_ff @(posedge clk_49m) begin + if(cen_6m) begin + if(!k1_irq_mask) + k1_irq <= 1; + else if(vblank_irq_en) + k1_irq <= 0; + end +end + +//-------------------------------------------------------- Video timing --------------------------------------------------------// + +//Konami 082 custom chip - responsible for all video timings +wire vblk, vblank_irq_en; +wire [8:0] h_cnt; +wire [7:0] v_cnt; +k082 u11G +( + .reset(1), + .clk(clk_49m), + .cen(cen_6m), + .h_center(h_center), + .v_center(v_center), + .n_vsync(video_vsync), + .sync(video_csync), + .n_hsync(video_hsync), + .vblk(vblk), + .vblk_irq_en(vblank_irq_en), + .h1(h_cnt[0]), + .h2(h_cnt[1]), + .h4(h_cnt[2]), + .h8(h_cnt[3]), + .h16(h_cnt[4]), + .h32(h_cnt[5]), + .h64(h_cnt[6]), + .h128(h_cnt[7]), + .n_h256(h_cnt[8]), + .v1(v_cnt[0]), + .v2(v_cnt[1]), + .v4(v_cnt[2]), + .v8(v_cnt[3]), + .v16(v_cnt[4]), + .v32(v_cnt[5]), + .v64(v_cnt[6]), + .v128(v_cnt[7]) +); + +//Latch vertical counter from 082 custom chip when the horizontal counter hits 256 +reg [7:0] vcnt_lat = 8'd0; +always_ff @(posedge clk_49m) begin + if(cen_6m && h_cnt == 9'd256) + vcnt_lat <= v_cnt; +end + +//Latch least significant bit of horizontal counter (to be used for sprite RAM logic) +reg h1d; +always_ff @(posedge clk_49m) begin + if(cen_6m) + h1d <= h_cnt[0]; +end + +//XOR horizontal counter bits [7:2] with HFLIP flag +wire [7:2] hcnt_x = h_cnt[7:2] ^ {6{flip}}; + +//XOR latched vertical counter bits with VFLIP flag +wire [7:0] vcnt_x = vcnt_lat ^ {8{flip}}; + +//--------------------------------------------------------- Tile layer ---------------------------------------------------------// + +//Generate addresses for VRAM +wire [10:0] vram_wram_A = h_cnt[1] ? {h_cnt[2], vcnt_x[7:3], hcnt_x[7:3]} : z80_A[10:0]; + +//LDO, labelled D1 in the Time Pilot schematics, signals to the tilemap logic when to latch tilemap codes from VRAM. It pulses +//low when the lower 3 bits of the horizontal counter are all 1, then on the rising edge, tilemap codes are latched. +//Set LDO as a register and latch a 0 when the 3 least significant bits of the horizontal counter are set to 1, otherwise latch +//a 1 +reg ldo = 1; +always_ff @(posedge clk_49m) begin + if(h_cnt[2:0] == 3'b111) + ldo <= 0; + else + ldo <= 1; +end + +//Latch tilemap code from VRAM at every rising edge of LDO (equivalent to when LDO is low and the 3 least significant bits of +//the horizontal counter are all set to 0) +reg [7:0] tile_code = 8'd0; +always_ff @(posedge clk_49m) begin + if(!ldo && h_cnt[2:0] == 3'b000) + tile_code <= vram_D; +end + +//Latch tilemap attributes from VRAM at the rising edge of bit 2 of the horizontal counter when !H256 is high +reg tile_attrib_latch = 1; +always_ff @(posedge clk_49m) begin + if(h_cnt[2:0] == 3'b011) + tile_attrib_latch <= 0; + else + tile_attrib_latch <= 1; +end +reg [7:0] tile_attrib = 8'd0; +always_ff @(posedge clk_49m) begin + if(h_cnt[8] && !tile_attrib_latch && h_cnt[2:0] == 3'b100) + tile_attrib <= vram_D; +end + +//Latch tile color information, tilemap enable and flip signal for tilemap 083 custom chip every 8 pixels +wire tile_flip = tile_hflip ^ ~flip; +reg tile_083_flip = 0; +reg tilemap_en = 0; +reg [3:0] tile_color = 4'd0; +always_ff @(posedge clk_49m) begin + if(cen_6m) begin + if(h_cnt[2:0] == 3'b011) begin + tile_083_flip <= tile_flip; + tile_color <= tile_attrib[3:0]; + tilemap_en <= tile_attrib[4]; + end + else begin + tile_083_flip <= tile_083_flip; + tile_color <= tile_color; + tilemap_en <= tilemap_en; + end + end +end + +//Generate address lines A1 - A3 of tilemap ROMs, CRA and tile flip attributes on the falling edge of horizontal +//counter bit 2 +reg v1l, v2l, v4l, cra, tile_hflip, tile_vflip; +reg old_h4; +always_ff @(posedge clk_49m) begin + old_h4 <= h_cnt[2]; + if(old_h4 && !h_cnt[2]) begin + v1l <= vcnt_x[0]; + v2l <= vcnt_x[1]; + v4l <= vcnt_x[2]; + tile_hflip <= tile_attrib[6]; + tile_vflip <= tile_attrib[7]; + cra <= tile_attrib[5]; + end +end + +//Address tilemap ROMs +assign tilerom_A[12] = cra; +assign tilerom_A[11:4] = tile_code; +assign tilerom_A[3:0] = {hcnt_x[2] ^ tile_hflip, v4l ^ tile_vflip, v2l ^ tile_vflip, v1l ^ tile_vflip}; + +//Tilemap ROM +wire [12:0] tilerom_A; +wire [7:0] eprom5_D; + +eprom_5 u2H +( + .ADDR(tilerom_A), + .CLK(clk_49m), + .DATA(eprom5_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(ep5_cs_i), + .WR(ioctl_wr) +); + +//Konami 083 custom chip 1/2 - this one shifts the pixel data from tilemap ROMs +k083 u3G +( + .CK(clk_49m), + .CEN(cen_6m), + .LOAD(h_cnt[1:0] == 2'b11), + .FLIP(tile_083_flip), + .DB0i(eprom5_D), + .DSH0(tile_lut_A[1:0]) +); + +//Tilemap lookup PROM +wire [7:0] tile_lut_A; +assign tile_lut_A[7:6] = 2'b00; +assign tile_lut_A[5:2] = tile_color; +wire [3:0] tile_D; +tile_lut_prom u3E +( + .ADDR(tile_lut_A), + .CLK(clk_49m), + .DATA(tile_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(tl_cs_i), + .WR(ioctl_wr) +); + +//-------------------------------------------------------- Sprite layer --------------------------------------------------------// + +//Generate sprite RAM enables (both active low) +wire n_cs_spriteram = ~cs_spriteram | ~h_cnt[1]; +wire cs_spriteram0 = ~n_cs_spriteram & k1_A[1]; +wire cs_spriteram1 = ~n_cs_spriteram & ~k1_A[1]; + +//Generate write enables for sprite RAM (active low) +wire spriteram0_wr = ~n_cs_spriteram & ~k1_rw1 & k1_A[1]; +wire spriteram1_wr = ~n_cs_spriteram & ~k1_rw1 & ~k1_A[1]; + +//Sprite RAM +wire [15:0] spriteram_D; +wire [9:0] spriteram_A; +assign spriteram_A = h_cnt[1] ? {k1_A[10:2], k1_A[0]} : {3'b000, h_cnt[7], (h_cnt[8] ^ h_cnt[7]), h_cnt[6], h_cnt[3], h_cnt[4], h_cnt[5], h_cnt[2]}; +//Bank 0 (lower 4 bits) +spram #(4, 10) u13A +( + .clk(clk_49m), + .we(cs_spriteram & cs_spriteram0 & spriteram0_wr), + .addr(spriteram_A), + .data(k1_Dout[3:0]), + .q(spriteram_D[3:0]) +); +//Bank 0 (upper 4 bits) +spram #(4, 10) u14A +( + .clk(clk_49m), + .we(cs_spriteram & cs_spriteram0 & spriteram0_wr), + .addr(spriteram_A), + .data(k1_Dout[7:4]), + .q(spriteram_D[7:4]) +); +//Bank 1 (lower 4 bits) +spram #(4, 10) u11A +( + .clk(clk_49m), + .we(cs_spriteram & cs_spriteram1 & spriteram1_wr), + .addr(spriteram_A), + .data(k1_Dout[3:0]), + .q(spriteram_D[11:8]) +); +//Bank 1 (upper 4 bits) +spram #(4, 10) u12A +( + .clk(clk_49m), + .we(cs_spriteram & cs_spriteram1 & spriteram1_wr), + .addr(spriteram_A), + .data(k1_Dout[7:4]), + .q(spriteram_D[15:12]) +); + +//Latch all data output from sprite RAM at 1/4 of the pixel clock +reg [15:0] spriteram_reg = 16'd0; +always_ff @(posedge clk_49m) begin + if(cen_1m5) + spriteram_reg <= spriteram_D; +end + +//Konami 503 custom chip - generates sprite addresses for lower half of sprite ROMs, sprite line buffer control, enable for +//sprite write and sprite flip for 083 custom chip. +wire cs_linebuffer, sprite_flip; +wire [5:0] k503_R; +k503 u9F +( + .OB(spriteram_reg[7:0]), + .VCNT(vcnt_lat), + .H4(h_cnt[2]), + .H8(0), + .LD(h_cnt[1:0] != 2'b11), + .OCS(cs_linebuffer), + .OFLP(sprite_flip), + .R(k503_R) +); +assign spriterom_A[5] = k503_R[5]; +assign spriterom_A[3:0] = k503_R[3:0]; + +//Latch sprite code from sprite RAM bank 1 every 8 pixels +reg [7:0] sprite_code = 8'd0; +always_ff @(posedge clk_49m) begin + if(h_cnt[2:0] == 3'b000) + sprite_code <= spriteram_reg[15:8]; +end + +//Assign sprite code to address the upper 7 bits and bit 4 of the sprite ROMs +assign spriterom_A[12:6] = sprite_code[7:1]; +assign spriterom_A[4] = sprite_code[0]; + +assign sp_rom_addr = spriterom_A; +//Sprite ROMs +wire [12:0] spriterom_A; +//ROM 1/4 +wire [7:0] eprom6_D = sp_rom_do[7:0]; +/* +eprom_6 u9C +( + .ADDR(spriterom_A), + .CLK(clk_49m), + .DATA(eprom6_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(ep6_cs_i), + .WR(ioctl_wr) +); +*/ +//ROM 2/4 +wire [7:0] eprom7_D = sp_rom_do[15:8]; +/* +eprom_7 u8C +( + .ADDR(spriterom_A), + .CLK(clk_49m), + .DATA(eprom7_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(ep7_cs_i), + .WR(ioctl_wr) +); +*/ +//ROM 3/4 +wire [7:0] eprom8_D = sp_rom_do[23:16]; +/* +eprom_8 u7C +( + .ADDR(spriterom_A), + .CLK(clk_49m), + .DATA(eprom8_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(ep8_cs_i), + .WR(ioctl_wr) +);*/ +//ROM 4/4 +wire [7:0] eprom9_D = sp_rom_do[31:24]; +/* +eprom_9 u6C +( + .ADDR(spriterom_A), + .CLK(clk_49m), + .DATA(eprom9_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(ep9_cs_i), + .WR(ioctl_wr) +); +*/ +//Latch sprite attributes and horizontal position every 8 pixels +reg [4:0] sprite_attrib = 5'd0; +reg [7:0] sprite_hpos = 8'd0; +always_ff @(posedge clk_49m) begin + if(h_cnt[2:0] == 3'b100) begin + sprite_attrib <= {spriteram_reg[5], spriteram_reg[3:0]}; + sprite_hpos <= spriteram_reg[15:8]; + end +end + +//Multiplex sprite ROM data outputs based on the state of sprite attribute bit 4 +reg spriterom_sel = 0; +always_ff @(posedge clk_49m) begin + if(h_cnt[2:0] == 3'b000) + spriterom_sel <= sprite_attrib[4]; +end +wire [15:0] spriterom_D = spriterom_sel ? {eprom9_D, eprom7_D} : {eprom8_D, eprom6_D}; + +//Konami 083 custom chip 2/2 - shifts the pixel data from sprite ROMs +k083 u7F +( + .CK(clk_49m), + .CEN(cen_6m), + .LOAD(h_cnt[1:0] == 2'b11), + .FLIP(sprite_k083_flip), + .DB0i(spriterom_D[7:0]), + .DB1i(spriterom_D[15:8]), + .DSH0(sprite_lut_A[1:0]), + .DSH1(sprite_lut_A[3:2]) +); + +//Latch sprite color information, enable for sprite line buffer, sprite 083 flip at every 8 pixels +reg [3:0] sprite_color = 4'd0; +reg sprite_lbuff_en, sprite_k083_flip; +always_ff @(posedge clk_49m) begin + if(cen_6m) begin + if(h_cnt[2:0] == 3'b011) begin + sprite_color <= sprite_attrib[3:0]; + sprite_lbuff_en <= cs_linebuffer; + sprite_k083_flip <= sprite_flip; + end + end +end + +//Assign sprite color information to the upper 4 bits of the sprite lookup PROM +assign sprite_lut_A[7:4] = sprite_color; + +//Sprite lookup PROM +wire [7:0] sprite_lut_A; +wire [3:0] sprite_lut_D; +sprite_lut_prom u6F +( + .ADDR(sprite_lut_A), + .CLK(clk_49m), + .DATA(sprite_lut_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(sl_cs_i), + .WR(ioctl_wr) +); + +//Konami 502 custom chip, responsible for generating sprites (sits between sprite ROMs and the sprite line buffer) +wire [7:0] sprite_lbuff_Do; +wire [4:0] sprite_D; +wire sprite_lbuff_sel, sprite_lbuff_dec0, sprite_lbuff_dec1; +k502 u6B +( + .RESET(1), + .CK1(clk_49m), + .CK2(clk_49m), + .CEN(cen_6m), + .LD0(h_cnt[2:0] == 3'b000), + .H2(h_cnt[1]), + .H256(h_cnt[8]), + .SPAL(sprite_lut_D), + .SPLBi({sprite_lbuff1_D, sprite_lbuff0_D}), + .SPLBo(sprite_lbuff_Do), + .OSEL(sprite_lbuff_sel), + .OLD(sprite_lbuff_dec1), + .OCLR(sprite_lbuff_dec0), + .COL(sprite_D) +); + +//----------------------------------------------------- Sprite line buffer -----------------------------------------------------// + +//Generate load and clear signals for counters generating addresses to sprite line buffer +reg sprite_lbuff0_ld, sprite_lbuff1_ld, sprite_lbuff0_clr, sprite_lbuff1_clr; +always_ff @(posedge clk_49m) begin + if(h_cnt[1:0] == 2'b11) begin + if(sprite_lbuff_dec0 && !sprite_lbuff_dec1) begin + sprite_lbuff0_clr <= 0; + sprite_lbuff1_clr <= 1; + end + else if(!sprite_lbuff_dec0 && sprite_lbuff_dec1) begin + sprite_lbuff0_clr <= 1; + sprite_lbuff1_clr <= 0; + end + else begin + sprite_lbuff0_clr <= 0; + sprite_lbuff1_clr <= 0; + end + end + else begin + sprite_lbuff0_clr <= 0; + sprite_lbuff1_clr <= 0; + end + if(h_cnt[2:0] == 3'b011) begin + if(!sprite_lbuff_dec1) begin + sprite_lbuff0_ld <= 1; + sprite_lbuff1_ld <= 0; + end + else begin + sprite_lbuff0_ld <= 0; + sprite_lbuff1_ld <= 1; + end + end + else begin + sprite_lbuff0_ld <= 0; + sprite_lbuff1_ld <= 0; + end +end + +//Generate addresses for sprite line buffer +//Bank 0, lower 4 bits +reg [3:0] linebuffer0_l = 4'd0; +always_ff @(posedge clk_49m) begin + if(cen_6m) begin + if(sprite_lbuff0_clr) + linebuffer0_l <= 4'd0; + else + if(sprite_lbuff0_ld) + linebuffer0_l <= sprite_hpos[3:0]; + else + linebuffer0_l <= linebuffer0_l + 4'd1; + end +end +//Bank 0, upper 4 bits +reg [3:0] linebuffer0_h = 4'd0; +always_ff @(posedge clk_49m) begin + if(cen_6m) begin + if(sprite_lbuff0_clr) + linebuffer0_h <= 4'd0; + else + if(sprite_lbuff0_ld) + linebuffer0_h <= sprite_hpos[7:4]; + else if(linebuffer0_l == 4'hF) + linebuffer0_h <= linebuffer0_h + 4'd1; + end +end +wire [7:0] sprite_lbuff0_A = {linebuffer0_h, linebuffer0_l}; +//Bank 1, lower 4 bits +reg [3:0] linebuffer1_l = 4'd0; +always_ff @(posedge clk_49m) begin + if(cen_6m) begin + if(sprite_lbuff1_clr) + linebuffer1_l <= 4'd0; + else + if(sprite_lbuff1_ld) + linebuffer1_l <= sprite_hpos[3:0]; + else + linebuffer1_l <= linebuffer1_l + 4'd1; + end +end +//Bank 1, upper 4 bits +reg [3:0] linebuffer1_h = 4'd0; +always_ff @(posedge clk_49m) begin + if(cen_6m) begin + if(sprite_lbuff1_clr) + linebuffer1_h <= 4'd0; + else + if(sprite_lbuff1_ld) + linebuffer1_h <= sprite_hpos[7:4]; + else if(linebuffer1_l == 4'hF) + linebuffer1_h <= linebuffer1_h + 4'd1; + end +end +wire [7:0] sprite_lbuff1_A = {linebuffer1_h, linebuffer1_l}; + +//Generate chip select signals for sprite line buffer +wire cs_sprite_lbuff0 = ~(sprite_lbuff_en & sprite_lbuff_sel); +wire cs_sprite_lbuff1 = ~(sprite_lbuff_en & ~sprite_lbuff_sel); + +//Sprite line buffer bank 0 +wire [3:0] sprite_lbuff0_D; +spram #(4, 8) u7A +( + .clk(clk_49m), + .we(cen_6m & cs_sprite_lbuff0), + .addr(sprite_lbuff0_A), + .data(sprite_lbuff_Do[3:0]), + .q(sprite_lbuff0_D) +); + +//Sprite line buffer bank 1 +wire [3:0] sprite_lbuff1_D; +spram #(4, 8) u7B +( + .clk(clk_49m), + .we(cen_6m & cs_sprite_lbuff1), + .addr(sprite_lbuff1_A), + .data(sprite_lbuff_Do[7:4]), + .q(sprite_lbuff1_D) +); + +//----------------------------------------------------- Final video output -----------------------------------------------------// + +//Generate HBlank (active high) while the horizontal counter is between 141 and 268 +wire hblk = (h_cnt > 140 && h_cnt < 269); + +//Multiplex tile and sprite data +wire tile_sprite_sel = (tilemap_en | sprite_D[4]); +wire [3:0] tile_sprite_D = tile_sprite_sel ? tile_D[3:0] : sprite_D[3:0]; + +//Latch pixel data for color PROM +reg [4:0] pixel_D; +always_ff @(posedge clk_49m) begin + if(cen_6m) + pixel_D <= {tile_sprite_sel, tile_sprite_D}; +end + +//Color PROM +wire [4:0] color_A = pixel_D; +wire [2:0] prom_red, prom_green; +wire [1:0] prom_blue; +color_prom u2A +( + .ADDR(color_A), + .CLK(clk_49m), + .DATA({prom_blue, prom_green, prom_red}), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(cp_cs_i), + .WR(ioctl_wr) +); + +//Output video signal from color PROMs, otherwise output black if in HBlank or VBlank +assign red = (hblk | vblk) ? 3'h0 : prom_red; +assign green = (hblk | vblk) ? 3'h0 : prom_green; +assign blue = (hblk | vblk) ? 2'h0 : prom_blue; + +endmodule diff --git a/Arcade_MiST/Konami Gyruss/rtl/Gyruss_MiST.sv b/Arcade_MiST/Konami Gyruss/rtl/Gyruss_MiST.sv new file mode 100644 index 00000000..6e232bb5 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/Gyruss_MiST.sv @@ -0,0 +1,277 @@ +module Gyruss_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 = { + "GYRUSS;;", + "O2,Rotate Controls,Off,On;", + "O34,Scanlines,Off,25%,50%,75%;", + "O5,Blend,Off,On;", + "O6,Joystick Swap,Off,On;", + "O7,Service,Off,On;", + "DIP;", + "T0,Reset;", + "V,v1.00.",`BUILD_DATE +}; + +wire rotate = status[2]; +wire [1:0] scanlines = status[4:3]; +wire blend = status[5]; +wire joyswap = status[6]; +wire service = status[7]; +wire [1:0] orientation = 2'b11; +wire [23:0] dip_sw = ~status[31:8]; + +assign LED = ~ioctl_downl; +assign SDRAM_CLK = clock_49; +assign SDRAM_CKE = 1; + +wire clock_49, pll_locked; +pll pll( + .inclk0(CLOCK_27), + .c0(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 [2:0] r, g; +wire [1:0] b; +wire key_strobe; +wire key_pressed; +wire [7:0] key_code; + +wire [15:0] main_rom_addr; +wire [15:0] main_rom_do; +wire [12:0] sub_rom_addr; +wire [15:0] sub_rom_do; +wire [12:0] sp_addr; +wire [31:0] sp_do; + +wire ioctl_downl; +wire [7:0] ioctl_index; +wire ioctl_wr; +wire [24:0] ioctl_addr; +wire [7:0] ioctl_dout; + +data_io data_io( + .clk_sys ( clock_49 ), + .SPI_SCK ( SPI_SCK ), + .SPI_SS2 ( SPI_SS2 ), + .SPI_DI ( SPI_DI ), + .ioctl_download( ioctl_downl ), + .ioctl_index ( ioctl_index ), + .ioctl_wr ( ioctl_wr ), + .ioctl_addr ( ioctl_addr ), + .ioctl_dout ( ioctl_dout ) +); +wire [24:0] bg_ioctl_addr = ioctl_addr - 16'hA000; + +reg port1_req, port2_req; +sdram #(49) sdram( + .*, + .init_n ( pll_locked ), + .clk ( clock_49 ), + + .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'hffff : {2'b00, main_rom_addr[14:1]} ), + .cpu1_q ( main_rom_do ), + .cpu2_addr ( ioctl_downl ? 16'hffff : sub_rom_addr[12:1] + 16'h3000 ), + .cpu2_q ( sub_rom_do ), + .cpu3_addr ( ), + .cpu3_q ( ), + + // port2 for sprite graphics + .port2_req ( port2_req ), + .port2_ack ( ), + .port2_a ( {bg_ioctl_addr[23:15], bg_ioctl_addr[12:0], bg_ioctl_addr[14]} ), // merge sprite roms to 32-bit wide words + .port2_ds ( {bg_ioctl_addr[13], ~bg_ioctl_addr[13]} ), + .port2_we ( ioctl_downl ), + .port2_d ( {ioctl_dout, ioctl_dout} ), + .port2_q ( ), + + .sp_addr ( ioctl_downl ? 16'hffff : sp_addr ), + .sp_q ( sp_do ) +); + +// ROM download controller +always @(posedge clock_49) begin + reg ioctl_wr_last = 0; + + ioctl_wr_last <= ioctl_wr; + if (ioctl_downl) begin + if (~ioctl_wr_last && ioctl_wr) begin + port1_req <= ~port1_req; + port2_req <= ~port2_req; + end + end +end + +reg reset = 1; +reg rom_loaded = 0; +always @(posedge clock_49) begin + reg ioctl_downlD; + ioctl_downlD <= ioctl_downl; + if (ioctl_downlD & ~ioctl_downl) rom_loaded <= 1; + reset <= status[0] | buttons[1] | ~rom_loaded; +end + +Gyruss Gyruss( + .reset(~reset), + .clk_49m(clock_49), + .coin({~m_coin2,~m_coin1}), + .start_buttons({~m_two_players,~m_one_player}), + .p1_joystick({~m_right, ~m_left, ~m_down, ~m_up}), + .p2_joystick({~m_right2, ~m_left2, ~m_down2, ~m_up2}), + .p1_fire(~m_fireA), + .p2_fire(~m_fire2A), + .btn_service(~service), + .dip_sw(dip_sw), + .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), + .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]), + .sp_rom_addr(sp_addr), + .sp_rom_do(sp_do) +); + +mist_video #(.COLOR_DEPTH(3), .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, b[1]} : 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) + ); + +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 Gyruss/rtl/Gyruss_SND.sv b/Arcade_MiST/Konami Gyruss/rtl/Gyruss_SND.sv new file mode 100644 index 00000000..9de01f7e --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/Gyruss_SND.sv @@ -0,0 +1,762 @@ +//============================================================================ +// +// Gyruss sound PCB model +// 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. +// +//============================================================================ + +module Gyruss_SND +( + input reset, + input clk_49m, //Actual frequency: 49.152MHz + input [23:0] dip_sw, + input [1:0] coin, //0 = coin 1, 1 = coin 2 + input [1:0] start_buttons, //0 = Player 1, 1 = Player 2 + input [3:0] p1_joystick, p2_joystick, //0 = up, 1 = down, 2 = left, 3 = right + input p1_fire, + input p2_fire, + input btn_service, + input cpubrd_A5, cpubrd_A6, + input cs_controls_dip1, cs_dip2, cs_dip3, + input irq_trigger, cs_sounddata, + input [7:0] cpubrd_Din, + + output [7:0] controls_dip, + output signed [15:0] sound_l, sound_r, + + input ep10_cs_i, + input ep11_cs_i, + input ep12_cs_i, + input [24:0] ioctl_addr, + input [7:0] ioctl_data, + input ioctl_wr + //The sound board contains a video passthrough but video will instead be tapped + //straight from the CPU board implementation (this passthrough is redundant for + //an FPGA implementation) +); + +//------------------------------------------------------- Signal outputs -------------------------------------------------------// + +//Multiplex controls and DIP switches to be output to CPU board +assign controls_dip = cs_controls_dip1 ? controls_dip1: + cs_dip2 ? dip_sw[15:8]: + cs_dip3 ? dip_sw[23:16]: + 8'hFF; + +//------------------------------------------------------- Clock division -------------------------------------------------------// + +//Generate clock enables for sound data and IRQ logic, and DC offset removal +reg [8:0] div = 9'd0; +always_ff @(posedge clk_49m) begin + div <= div + 9'd1; +end +reg [3:0] n_div = 4'd0; +always_ff @(negedge clk_49m) begin + n_div <= n_div + 4'd1; +end +wire n_cen_3m = !n_div; +wire cen_dcrm = !div; + +//Generate 3.579545MHz clock enable for Z80, 1.789772MHz clock enable for AY-3-8910s, clock enable for AY-3-8910 timer +//(uses Jotego's fractional clock divider from JTFRAME) +wire cen_3m58, cen_1m79, cen_timer; +jtframe_frac_cen #(11) sound_cen +( + .clk(clk_49m), + .n(10'd60), + .m(10'd824), + .cen({cen_timer, 8'bZZZZZZZZ, cen_1m79, cen_3m58}) +); + +//Also use Jotego's fractional clock divider to generate an 8MHz clock enable for the i8039 MCU +wire cen_8m; +jtframe_frac_cen #(2) i8039_cen +( + .clk(clk_49m), + .n(10'd42), + .m(10'd258), + .cen({1'bZ, cen_8m}) +); + +//------------------------------------------------------------ CPU -------------------------------------------------------------// + +//Sound CPU - Zilog Z80 (uses T80s version of the T80 soft core) +wire [15:0] sound_A; +wire [7:0] sound_Dout; +wire n_m1, n_mreq, n_iorq, n_rd, n_wr, n_rfsh; +T80s u6B +( + .RESET_n(reset), + .CLK(clk_49m), + .CEN(cen_3m58), + .INT_n(n_irq), + .M1_n(n_m1), + .MREQ_n(n_mreq), + .IORQ_n(n_iorq), + .RD_n(n_rd), + .WR_n(n_wr), + .RFSH_n(n_rfsh), + .A(sound_A), + .DI(sound_Din), + .DO(sound_Dout) +); +//Address decoding for Z80 +wire n_rw = n_rd & n_wr; +wire cs_soundrom0 = (~n_rw & ~n_mreq & n_rfsh & (sound_A[15:13] == 3'b000)); +wire cs_soundrom1 = (~n_rw & ~n_mreq & n_rfsh & (sound_A[15:13] == 3'b001)); +wire cs_soundram = (~n_rw & ~n_mreq & n_rfsh & (sound_A[15:13] == 3'b011)); +wire cs_sound = (~n_rw & ~n_mreq & n_rfsh & (sound_A[15:13] == 3'b100)); +wire cs_ay1 = (~n_iorq & n_m1 & (sound_A[4:2] == 3'b000)); +wire cs_ay2 = (~n_iorq & n_m1 & (sound_A[4:2] == 3'b001)); +wire cs_ay3 = (~n_iorq & n_m1 & (sound_A[4:2] == 3'b010)); +wire cs_ay4 = (~n_iorq & n_m1 & (sound_A[4:2] == 3'b011)); +wire cs_ay5 = (~n_iorq & n_m1 & (sound_A[4:2] == 3'b100)); +wire cs_i8039_irq = (~n_iorq & n_m1 & (sound_A[4:2] == 3'b101)); +wire cs_i8039_latch = (~n_iorq & n_m1 & (sound_A[4:2] == 3'b110)); +//Multiplex data input to Z80 +wire [7:0] sound_Din = cs_soundrom0 ? eprom10_D: + cs_soundrom1 ? eprom11_D: + (cs_soundram & n_wr) ? sndram_D: + cs_sound ? sound_D: + (~ay1_bdir & ay1_bc1) ? ay1_D: + (~ay2_bdir & ay2_bc1) ? ay2_D: + (~ay3_bdir & ay3_bc1) ? ay3_D: + (~ay4_bdir & ay4_bc1) ? ay4_D: + (~ay5_bdir & ay5_bc1) ? ay5_D: + 8'hFF; + +//Sound ROMs +//ROM 1/2 +wire [7:0] eprom10_D; +eprom_10 u6A +( + .ADDR(sound_A[12:0]), + .CLK(clk_49m), + .DATA(eprom10_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(ep10_cs_i), + .WR(ioctl_wr) +); +//ROM 2/2 +wire [7:0] eprom11_D; +eprom_11 u8A +( + .ADDR(sound_A[12:0]), + .CLK(clk_49m), + .DATA(eprom11_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(ep11_cs_i), + .WR(ioctl_wr) +); + +//Sound RAM (lower 4 bits) +wire [7:0] sndram_D; +spram #(4, 10) u4A +( + .clk(clk_49m), + .we(cs_soundram & ~n_wr), + .addr(sound_A[9:0]), + .data(sound_Dout[3:0]), + .q(sndram_D[3:0]) +); + +//Sound RAM (upper 4 bits) +spram #(4, 10) u5A +( + .clk(clk_49m), + .we(cs_soundram & ~n_wr), + .addr(sound_A[9:0]), + .data(sound_Dout[7:4]), + .q(sndram_D[7:4]) +); + +//Latch sound data coming in from CPU board +reg [7:0] sound_D = 8'd0; +always_ff @(posedge clk_49m) begin + if(n_cen_3m && cs_sounddata) + sound_D <= cpubrd_Din; +end + +//Generate Z80 interrupts +wire irq_clr = (~reset | ~(n_iorq | n_m1)); +reg n_irq = 1; +always_ff @(posedge clk_49m or posedge irq_clr) begin + if(irq_clr) + n_irq <= 1; + else if(n_cen_3m && irq_trigger) + n_irq <= 0; +end + +//--------------------------------------------------- Controls & DIP switches --------------------------------------------------// + +//Multiplex player inputs and DIP switch bank 1 +wire [7:0] controls_dip1 = ({cpubrd_A6, cpubrd_A5} == 2'b00) ? {3'b111, start_buttons, btn_service, coin}: + ({cpubrd_A6, cpubrd_A5} == 2'b01) ? {3'b111, p1_fire, p1_joystick[1:0], p1_joystick[3:2]}: + ({cpubrd_A6, cpubrd_A5} == 2'b10) ? {3'b111, p2_fire, p2_joystick[1:0], p2_joystick[3:2]}: + ({cpubrd_A6, cpubrd_A5} == 2'b11) ? dip_sw[7:0]: + 8'hFF; + +//--------------------------------------------------------- Sound chips --------------------------------------------------------// + +//Generate BC1 and BDIR signals for the five AY-3-8910s +wire ay1_bdir = ~(~cs_ay1 | sound_A[0]); +wire ay1_bc1 = ~(~cs_ay1 | sound_A[1]); +wire ay2_bdir = ~(~cs_ay2 | sound_A[0]); +wire ay2_bc1 = ~(~cs_ay2 | sound_A[1]); +wire ay3_bdir = ~(~cs_ay3 | sound_A[0]); +wire ay3_bc1 = ~(~cs_ay3 | sound_A[1]); +wire ay4_bdir = ~(~cs_ay4 | sound_A[0]); +wire ay4_bc1 = ~(~cs_ay4 | sound_A[1]); +wire ay5_bdir = ~(~cs_ay5 | sound_A[0]); +wire ay5_bc1 = ~(~cs_ay5 | sound_A[1]); + +//AY-3-8910 timer (code adapted from MiSTer-X's Gyruss core) +reg [3:0] timer_sel; +wire [3:0] timer_val; +always_comb begin + case(timer_sel) + 0: timer_val = 4'h0; + 1: timer_val = 4'h1; + 2: timer_val = 4'h2; + 3: timer_val = 4'h3; + 4: timer_val = 4'h4; + 5: timer_val = 4'h9; + 6: timer_val = 4'hA; + 7: timer_val = 4'hB; + 8: timer_val = 4'hA; + 9: timer_val = 4'hD; + default: timer_val = 0; + endcase +end +reg [3:0] timer = 4'd0; +always_ff @(posedge clk_49m) begin + if(cen_timer) begin + timer <= timer_val; + timer_sel <= (timer_sel == 4'd9) ? 4'd0 : (timer_sel + 4'd1); + end +end + +//Sound chip 1 (AY-3-8910 - uses JT49 by Jotego) +wire [7:0] ay1_D; +wire [7:0] ay1A_raw, ay1B_raw, ay1C_raw; +wire [5:0] ay1_filter; +jt49_bus #(.COMP(3'b100)) u11D +( + .rst_n(reset), + .clk(clk_49m), + .clk_en(cen_1m79), + .bdir(ay1_bdir), + .bc1(ay1_bc1), + .din(sound_Dout), + .sel(1), + .dout(ay1_D), + .A(ay1A_raw), + .B(ay1B_raw), + .C(ay1C_raw), + .IOB_out({2'bZZ, ay1_filter}) +); + +//Sound chip 2 (AY-3-8910 - uses JT49 by Jotego) +wire [7:0] ay2_D; +wire [7:0] ay2A_raw, ay2B_raw, ay2C_raw; +wire [5:0] ay2_filter; +jt49_bus #(.COMP(3'b100)) u12D +( + .rst_n(reset), + .clk(clk_49m), + .clk_en(cen_1m79), + .bdir(ay2_bdir), + .bc1(ay2_bc1), + .din(sound_Dout), + .sel(1), + .dout(ay2_D), + .A(ay2A_raw), + .B(ay2B_raw), + .C(ay2C_raw), + .IOB_out({2'bZZ, ay2_filter}) +); + +//Sound chip 3 (AY-3-8910 - uses JT49 by Jotego) +wire [7:0] ay3_D; +wire [7:0] ay3A_raw, ay3B_raw, ay3C_raw; +jt49_bus #(.COMP(3'b100)) u10B +( + .rst_n(reset), + .clk(clk_49m), + .clk_en(cen_1m79), + .bdir(ay3_bdir), + .bc1(ay3_bc1), + .din(sound_Dout), + .sel(1), + .dout(ay3_D), + .A(ay3A_raw), + .B(ay3B_raw), + .C(ay3C_raw), + .IOA_in({4'b0000, timer}) +); + +//Sound chip 4 (AY-3-8910 - uses JT49 by Jotego) +wire [7:0] ay4_D; +wire [7:0] ay4A_raw, ay4B_raw, ay4C_raw; +jt49_bus #(.COMP(3'b100)) u9B +( + .rst_n(reset), + .clk(clk_49m), + .clk_en(cen_1m79), + .bdir(ay4_bdir), + .bc1(ay4_bc1), + .din(sound_Dout), + .sel(1), + .dout(ay4_D), + .A(ay4A_raw), + .B(ay4B_raw), + .C(ay4C_raw) +); + +//Sound chip 5 (AY-3-8910 - uses JT49 by Jotego) +wire [7:0] ay5_D; +wire [7:0] ay5A_raw, ay5B_raw, ay5C_raw; +jt49_bus #(.COMP(3'b100)) u8B +( + .rst_n(reset), + .clk(clk_49m), + .clk_en(cen_1m79), + .bdir(ay5_bdir), + .bc1(ay5_bc1), + .din(sound_Dout), + .sel(1), + .dout(ay5_D), + .A(ay5A_raw), + .B(ay5B_raw), + .C(ay5C_raw) +); + +//Sound chip 6 (Intel 8039 MCU - uses t8039_notri variant of T48) +wire [7:0] i8039_raw; +wire [7:0] i8039_Dout; +wire i8039_ale, n_i8039_psen, n_i8039_rd, n_i8039_irq_clr; +t8039_notri u7H +( + .xtal_i(clk_49m), + .xtal_en_i(cen_8m), + .reset_n_i(reset), + .int_n_i(n_i8039_irq), + .ea_i(1), + .rd_n_o(n_i8039_rd), + .psen_n_o(n_i8039_psen), + .ale_o(i8039_ale), + .db_i(i8039_Din), + .db_o(i8039_Dout), + .p2_o({n_i8039_irq_clr, 3'bZZZ, eprom12_A[11:8]}), + .p1_o(i8039_raw) +); +//Multiplex data into i8039 +wire [7:0] i8039_Din = ~n_i8039_psen ? eprom12_D: + ~n_i8039_rd ? i8039_latch: + 8'hFF; + +//i8039 ROM +wire [11:0] eprom12_A; +wire [7:0] eprom12_D; +eprom_12 u11H +( + .ADDR(eprom12_A), + .CLK(clk_49m), + .DATA(eprom12_D), + .ADDR_DL(ioctl_addr), + .CLK_DL(clk_49m), + .DATA_IN(ioctl_data), + .CS_DL(ep12_cs_i), + .WR(ioctl_wr) +); + +//Latch data from Z80 to i8039 +reg [7:0] i8039_latch = 8'd0; +always_ff @(posedge clk_49m) begin + if(cen_3m58 && cs_i8039_latch) + i8039_latch <= sound_Dout; +end + +//Latch address lines A[7:0] for MCU ROM +reg [7:0] i8039_rom_lat = 8'd0; +always_ff @(negedge i8039_ale) begin + i8039_rom_lat <= i8039_Dout; +end +assign eprom12_A[7:0] = i8039_rom_lat; + +//Generate i8039 IRQ +reg n_i8039_irq = 1; +always_ff @(posedge clk_49m) begin + if(!n_i8039_irq_clr) + n_i8039_irq <= 1; + else if(cen_3m58 && cs_i8039_irq) + n_i8039_irq <= 0; +end + +//----------------------------------------------------- Final audio output -----------------------------------------------------// + +//Apply gain and remove DC offset from AY-3-8910s and i8039 (uses jt49_dcrm2 from JT49 by Jotego for DC offset removal) +wire signed [15:0] ay1A_dcrm, ay1B_dcrm, ay1C_dcrm, ay2A_dcrm, ay2B_dcrm, ay2C_dcrm; +wire signed [15:0] ay3A_sound, ay3B_sound, ay3C_sound, ay4A_sound, ay4B_sound, ay4C_sound, ay5A_sound, ay5B_sound, ay5C_sound; +wire signed [15:0] i8039_sound; +jt49_dcrm2 #(16) dcrm_ay1A +( + .clk(clk_49m), + .cen(cen_dcrm), + .rst(~reset), + .din({4'd0, ay1A_raw, 4'd0}), + .dout(ay1A_dcrm) +); +jt49_dcrm2 #(16) dcrm_ay1B +( + .clk(clk_49m), + .cen(cen_dcrm), + .rst(~reset), + .din({4'd0, ay1B_raw, 4'd0}), + .dout(ay1B_dcrm) +); +jt49_dcrm2 #(16) dcrm_ay1C +( + .clk(clk_49m), + .cen(cen_dcrm), + .rst(~reset), + .din({4'd0, ay1C_raw, 4'd0}), + .dout(ay1C_dcrm) +); + +jt49_dcrm2 #(16) dcrm_ay2A +( + .clk(clk_49m), + .cen(cen_dcrm), + .rst(~reset), + .din({4'd0, ay2A_raw, 4'd0}), + .dout(ay2A_dcrm) +); +jt49_dcrm2 #(16) dcrm_ay2B +( + .clk(clk_49m), + .cen(cen_dcrm), + .rst(~reset), + .din({4'd0, ay2B_raw, 4'd0}), + .dout(ay2B_dcrm) +); +jt49_dcrm2 #(16) dcrm_ay2C +( + .clk(clk_49m), + .cen(cen_dcrm), + .rst(~reset), + .din({4'd0, ay2C_raw, 4'd0}), + .dout(ay2C_dcrm) +); + +jt49_dcrm2 #(16) dcrm_ay3A +( + .clk(clk_49m), + .cen(cen_dcrm), + .rst(~reset), + .din({4'd0, ay3A_raw, 4'd0}), + .dout(ay3A_sound) +); +jt49_dcrm2 #(16) dcrm_ay3B +( + .clk(clk_49m), + .cen(cen_dcrm), + .rst(~reset), + .din({4'd0, ay3B_raw, 4'd0}), + .dout(ay3B_sound) +); +jt49_dcrm2 #(16) dcrm_ay3C +( + .clk(clk_49m), + .cen(cen_dcrm), + .rst(~reset), + .din({4'd0, ay3C_raw, 4'd0}), + .dout(ay3C_sound) +); + +jt49_dcrm2 #(16) dcrm_ay4A +( + .clk(clk_49m), + .cen(cen_dcrm), + .rst(~reset), + .din({4'd0, ay4A_raw, 4'd0}), + .dout(ay4A_sound) +); +jt49_dcrm2 #(16) dcrm_ay4B +( + .clk(clk_49m), + .cen(cen_dcrm), + .rst(~reset), + .din({4'd0, ay4B_raw, 4'd0}), + .dout(ay4B_sound) +); +jt49_dcrm2 #(16) dcrm_ay4C +( + .clk(clk_49m), + .cen(cen_dcrm), + .rst(~reset), + .din({4'd0, ay4C_raw, 4'd0}), + .dout(ay4C_sound) +); + +jt49_dcrm2 #(16) dcrm_ay5A +( + .clk(clk_49m), + .cen(cen_dcrm), + .rst(~reset), + .din({4'd0, ay5A_raw, 4'd0}), + .dout(ay5A_sound) +); +jt49_dcrm2 #(16) dcrm_ay5B +( + .clk(clk_49m), + .cen(cen_dcrm), + .rst(~reset), + .din({4'd0, ay5B_raw, 4'd0}), + .dout(ay5B_sound) +); +jt49_dcrm2 #(16) dcrm_ay5C +( + .clk(clk_49m), + .cen(cen_dcrm), + .rst(~reset), + .din({4'd0, ay5C_raw, 4'd0}), + .dout(ay5C_sound) +); + +jt49_dcrm2 #(16) dcrm_i8039 +( + .clk(clk_49m), + .cen(cen_dcrm), + .rst(~reset), + .din({2'd0, i8039_raw, 6'd0}), + .dout(i8039_sound) +); + +//Two of Gyruss's AY-3-8910s contain selectable low-pass filters with the following cutoff frequencies: +//3386.28Hz, 723.43Hz, 596.09Hz +//Model this here (the PCB handles this via 3 74HC4066 switching ICs located at 9E, 9F and 10F) +wire signed [15:0] ay1A_light, ay1A_med, ay1A_heavy, ay1B_light, ay1B_med, ay1B_heavy, ay1C_light, ay1C_med, ay1C_heavy; +wire signed [15:0] ay2A_light, ay2A_med, ay2A_heavy, ay2B_light, ay2B_med, ay2B_heavy, ay2C_light, ay2C_med, ay2C_heavy; +wire signed [15:0] ay1A_sound, ay1B_sound, ay1C_sound, ay2A_sound, ay2B_sound, ay2C_sound; +gyruss_lpf_light ay1A_lpf_light +( + .clk(clk_49m), + .reset(~reset), + .in(ay1A_dcrm), + .out(ay1A_light) +); +gyruss_lpf_medium ay1A_lpf_medium +( + .clk(clk_49m), + .reset(~reset), + .in(ay1A_dcrm), + .out(ay1A_med) +); +gyruss_lpf_heavy ay1A_lpf_heavy +( + .clk(clk_49m), + .reset(~reset), + .in(ay1A_dcrm), + .out(ay1A_heavy) +); +gyruss_lpf_light ay1B_lpf_light +( + .clk(clk_49m), + .reset(~reset), + .in(ay1B_dcrm), + .out(ay1B_light) +); +gyruss_lpf_medium ay1B_lpf_medium +( + .clk(clk_49m), + .reset(~reset), + .in(ay1B_dcrm), + .out(ay1B_med) +); +gyruss_lpf_heavy ay1B_lpf_heavy +( + .clk(clk_49m), + .reset(~reset), + .in(ay1B_dcrm), + .out(ay1B_heavy) +); +gyruss_lpf_light ay1C_lpf_light +( + .clk(clk_49m), + .reset(~reset), + .in(ay1C_dcrm), + .out(ay1C_light) +); +gyruss_lpf_medium ay1C_lpf_medium +( + .clk(clk_49m), + .reset(~reset), + .in(ay1C_dcrm), + .out(ay1C_med) +); +gyruss_lpf_heavy ay1C_lpf_heavy +( + .clk(clk_49m), + .reset(~reset), + .in(ay1C_dcrm), + .out(ay1C_heavy) +); + +gyruss_lpf_light ay2A_lpf_light +( + .clk(clk_49m), + .reset(~reset), + .in(ay2A_dcrm), + .out(ay2A_light) +); +gyruss_lpf_medium ay2A_lpf_medium +( + .clk(clk_49m), + .reset(~reset), + .in(ay2A_dcrm), + .out(ay2A_med) +); +gyruss_lpf_heavy ay2A_lpf_heavy +( + .clk(clk_49m), + .reset(~reset), + .in(ay2A_dcrm), + .out(ay2A_heavy) +); +gyruss_lpf_light ay2B_lpf_light +( + .clk(clk_49m), + .reset(~reset), + .in(ay2B_dcrm), + .out(ay2B_light) +); +gyruss_lpf_medium ay2B_lpf_medium +( + .clk(clk_49m), + .reset(~reset), + .in(ay2B_dcrm), + .out(ay2B_med) +); +gyruss_lpf_heavy ay2B_lpf_heavy +( + .clk(clk_49m), + .reset(~reset), + .in(ay2B_dcrm), + .out(ay2B_heavy) +); +gyruss_lpf_light ay2C_lpf_light +( + .clk(clk_49m), + .reset(~reset), + .in(ay2C_dcrm), + .out(ay2C_light) +); +gyruss_lpf_medium ay2C_lpf_medium +( + .clk(clk_49m), + .reset(~reset), + .in(ay2C_dcrm), + .out(ay2C_med) +); +gyruss_lpf_heavy ay2C_lpf_heavy +( + .clk(clk_49m), + .reset(~reset), + .in(ay2C_dcrm), + .out(ay2C_heavy) +); + +//Apply audio filtering based on the state of the low-pass filter controls +always_comb begin + case(ay1_filter[1:0]) + 2'b00: ay1A_sound = ay1A_dcrm; + 2'b01: ay1A_sound = ay1A_light <<< 1; + 2'b10: ay1A_sound = ay1A_med <<< 1; + 2'b11: ay1A_sound = ay1A_heavy <<< 1; + endcase + case(ay1_filter[3:2]) + 2'b00: ay1B_sound = ay1B_dcrm; + 2'b01: ay1B_sound = ay1B_light <<< 1; + 2'b10: ay1B_sound = ay1B_med <<< 1; + 2'b11: ay1B_sound = ay1B_heavy <<< 1; + endcase + case(ay1_filter[5:4]) + 2'b00: ay1C_sound = ay1C_dcrm; + 2'b01: ay1C_sound = ay1C_light <<< 1; + 2'b10: ay1C_sound = ay1C_med <<< 1; + 2'b11: ay1C_sound = ay1C_heavy <<< 1; + endcase + case(ay2_filter[1:0]) + 2'b00: ay2A_sound = ay2A_dcrm; + 2'b01: ay2A_sound = ay2A_light <<< 1; + 2'b10: ay2A_sound = ay2A_med <<< 1; + 2'b11: ay2A_sound = ay2A_heavy <<< 1; + endcase + case(ay2_filter[3:2]) + 2'b00: ay2B_sound = ay2B_dcrm; + 2'b01: ay2B_sound = ay2B_light <<< 1; + 2'b10: ay2B_sound = ay2B_med <<< 1; + 2'b11: ay2B_sound = ay2B_heavy <<< 1; + endcase + case(ay2_filter[5:4]) + 2'b00: ay2C_sound = ay2C_dcrm; + 2'b01: ay2C_sound = ay2C_light <<< 1; + 2'b10: ay2C_sound = ay2C_med <<< 1; + 2'b11: ay2C_sound = ay2C_heavy <<< 1; + endcase +end + +//Mix the left and right outputs, then apply an antialiasing low-pass filter to eliminate ringing noise from the +//AY-3-8910s and output the final result (this game has variable low-pass filtering based on how loud the PCB's volume dials +//are set and will be modeled externally) +wire signed [15:0] left_mix = (ay2A_sound + ay2B_sound + ay2C_sound + ay5A_sound + ay5B_sound + ay5C_sound + i8039_sound); +wire signed [15:0] right_mix = (ay1A_sound + ay1B_sound + ay1C_sound + ay3A_sound + ay3B_sound + ay3C_sound + ay4A_sound + + ay4B_sound + ay4C_sound); + +wire signed [15:0] left_lpf, right_lpf; +gyruss_lpf aalpf_l +( + .clk(clk_49m), + .reset(~reset), + .in(left_mix), + .out(left_lpf) +); + +gyruss_lpf aalpf_r +( + .clk(clk_49m), + .reset(~reset), + .in(right_mix), + .out(right_lpf) +); + +assign sound_l = (ay2A_sound + ay2B_sound + ay2C_sound + ay5A_sound + ay5B_sound + ay5C_sound + i8039_sound); +assign sound_r = (ay1A_sound + ay1B_sound + ay1C_sound + ay3A_sound + ay3B_sound + ay3C_sound + ay4A_sound + + ay4B_sound + ay4C_sound); +//assign sound_l = left_lpf; +//assign sound_r = right_lpf; + +endmodule diff --git a/Arcade_MiST/Konami Gyruss/rtl/build_id.tcl b/Arcade_MiST/Konami Gyruss/rtl/build_id.tcl new file mode 100644 index 00000000..938515d8 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/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 Gyruss/rtl/custom/KONAMI-1/KONAMI1.sv b/Arcade_MiST/Konami Gyruss/rtl/custom/KONAMI-1/KONAMI1.sv new file mode 100644 index 00000000..9126e795 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/custom/KONAMI-1/KONAMI1.sv @@ -0,0 +1,79 @@ +//============================================================================ +// +// SystemVerilog implementation of the KONAMI-1 custom chip, a custom MC6809E +// variant with XOR/XNOR encryption +// Implements MC6809E core by Greg Miller (synchronous version modified by +// Sorgelig with further modifications to allow direct injection of opcodes) +// 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. +// +//============================================================================ + +module KONAMI1 +( + input CLK, + input fallE_en, + input fallQ_en, + + input [7:0] D, + output [7:0] DOut, + output [15:0] ADDR, + output RnW, + output BS, + output BA, + input nIRQ, + input nFIRQ, + input nNMI, + output AVMA, + output BUSY, + output LIC, + input nHALT, + input nRESET +); + +//Decrypt XOR/XNOR encrypted opcode +wire [7:0] opcode = D ^ {ADDR[1], 1'b0, ~ADDR[1], 1'b0, ADDR[3], 1'b0, ~ADDR[3], 1'b0}; + +//Passthrough to modified MC6809is core with direct opcode injection and IS_KONAMI1 parameter set +//to TRUE +mc6809is #(.IS_KONAMI1("TRUE")) cpucore +( + .CLK(CLK), + .fallE_en(fallE_en), + .fallQ_en(fallQ_en), + .OP(opcode), + .nHALT(nHALT), + .nRESET(nRESET), + .D(D), + .DOut(DOut), + .ADDR(ADDR), + .RnW(RnW), + .BS(BS), + .BA(BA), + .nIRQ(nIRQ), + .nFIRQ(nFIRQ), + .nNMI(nNMI), + .AVMA(AVMA), + .BUSY(BUSY), + .LIC(LIC), + .nDMABREQ(1) +); + +endmodule diff --git a/Arcade_MiST/Konami Gyruss/rtl/custom/KONAMI-1/mc6809isk.v b/Arcade_MiST/Konami Gyruss/rtl/custom/KONAMI-1/mc6809isk.v new file mode 100644 index 00000000..18467022 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/custom/KONAMI-1/mc6809isk.v @@ -0,0 +1,4162 @@ +`timescale 1ns / 1ns +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: Greg Miller +// Copyright (c) 2016, Greg Miller +// +// Create Date: 14:26:59 08/13/2016 +// Design Name: +// Module Name: mc6809 +// Project Name: Cycle-Accurate 6809 Core +// Target Devices: +// Tool versions: +// Description: +// +// Dependencies: Intended to be standalone Vanilla Verilog. +// +// Revision: +// Revision 1.0 - Initial Release +// Revision 1.0s - Sinchronous version (by Sorgelig) +// Revision 1.0sk - Add direct injection of KONAMI-1 encrypted opcodes (by Ace) +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +// +// The 6809 has incomplete instruction decoding. A collection of instructions, if met, end up actually behaving like +// a binary-adjacent neighbor. +// +// The soft core permits three different behaviors for this situation, controlled by the instantiation parameter +// ILLEGAL_INSTRUCTIONS +// +// "GHOST" - Mimic the 6809's incomplete decoding. This is as similar to a hard 6809 as is practical. [DEFAULT] +// +// "STOP" - Cause the soft core to cease execution, placing $DEAD on the address bus and R/W to 'read'. Interrupts, +// bus control (/HALT, /DMABREQ), etc. are ignored. The core intentionally seizes in this instance. +// (Frankly, this is useful when making changes to the core and you have a logic analyzer connected.) +// +// "IGNORE"- Cause the soft core to merely ignore illegal instructions. It will consider them 1-byte instructions and +// attempt to fetch and run an exception 1 byte later. +// + +module mc6809is +#( + parameter ILLEGAL_INSTRUCTIONS="GHOST", + parameter IS_KONAMI1="FALSE" +) +( + input CLK, + input fallE_en, + input fallQ_en, + input [7:0] OP, + + input [7:0] D, + output [7:0] DOut, + output [15:0] ADDR, + output RnW, + output BS, + output BA, + input nIRQ, + input nFIRQ, + input nNMI, + output AVMA, + output BUSY, + output LIC, + input nHALT, + input nRESET, + input nDMABREQ, + output [111:0] RegData +); + +reg [7:0] DOutput; + +assign DOut = DOutput; + +reg RnWOut; // Combinatorial + +reg rLIC; +assign LIC = rLIC; + +reg rAVMA; +assign AVMA = rAVMA; + +reg rBUSY; +assign BUSY = rBUSY; + +// Bus control +// BS BA +// 0 0 normal (CPU running, CPU is master) +// 0 1 Interrupt Ack +// 1 0 Sync Ack +// 1 1 CPU has gone high-Z on A, D, R/W +// + +assign RnW = RnWOut; + + +///////////////////////////////////////////////// +// Vectors +`define RESET_VECTOR 16'HFFFE +`define NMI_VECTOR 16'HFFFC +`define SWI_VECTOR 16'HFFFA +`define IRQ_VECTOR 16'HFFF8 +`define FIRQ_VECTOR 16'HFFF6 +`define SWI2_VECTOR 16'HFFF4 +`define SWI3_VECTOR 16'HFFF2 +`define Reserved_VECTOR 16'HFFF0 + +////////////////////////////////////////////////////// +// Latched registers +// + +// The last-latched copy. +reg [7:0] a; +reg [7:0] b; +reg [15:0] x; +reg [15:0] y; +reg [15:0] u; +reg [15:0] s; +reg [15:0] pc; +reg [7:0] dp; +reg [7:0] cc; +reg [15:0] tmp; +reg [15:0] addr; +reg [15:0] ea; + + +// Debug ability to export register contents +assign RegData[7:0] = a; +assign RegData[15:8] = b; +assign RegData[31:16] = x; +assign RegData[47:32] = y; +assign RegData[63:48] = s; +assign RegData[79:64] = u; +assign RegData[87:80] = cc; +assign RegData[95:88] = dp; +assign RegData[111:96] = pc; + + + +// The values as being calculated +reg [7:0] a_nxt; +reg [7:0] b_nxt; +reg [15:0] x_nxt; +reg [15:0] y_nxt; +reg [15:0] u_nxt; +reg [15:0] s_nxt; +reg [15:0] pc_nxt; +reg [7:0] dp_nxt; +reg [7:0] cc_nxt; +reg [15:0] addr_nxt; +reg [15:0] ea_nxt; +reg [15:0] tmp_nxt; + +reg BS_nxt; +reg BA_nxt; + +// for ADDR, BS/BA, assign them to the flops +assign BS = BS_nxt; +assign BA = BA_nxt; +assign ADDR=addr_nxt; + +localparam CC_E= 8'H80; +localparam CC_F= 8'H40; +localparam CC_H= 8'H20; +localparam CC_I= 8'H10; +localparam CC_N= 8'H08; +localparam CC_Z= 8'H04; +localparam CC_V= 8'H02; +localparam CC_C= 8'H01; + +localparam CC_E_BIT= 3'd7; +localparam CC_F_BIT= 3'd6; +localparam CC_H_BIT= 3'd5; +localparam CC_I_BIT= 3'd4; +localparam CC_N_BIT= 3'd3; +localparam CC_Z_BIT= 3'd2; +localparam CC_V_BIT= 3'd1; +localparam CC_C_BIT= 3'd0; + +// Convenience calculations +reg [15:0] pc_p1; +reg [15:0] pc_p2; +reg [15:0] pc_p3; +reg [15:0] s_p1; +reg [15:0] s_m1; +reg [15:0] u_p1; +reg [15:0] u_m1; +reg [15:0] addr_p1; +reg [15:0] ea_p1; + +////////////////////////////////////////////////////// +// NMI Mask +// +// NMI is supposed to be masked - despite the name - until the 6809 loads a value into S. +// Frankly, I'm cheating slightly. If someone does a LDS #$0, it won't disable the mask. Pretty much anything else +// that changes the value of S from the default (which is currently $0) will clear the mask. A reset will set the mask again. +reg NMIMask; + +reg NMILatched; +reg NMISample; +reg NMISample2; +reg NMIClear; +reg NMIClear_nxt; +wire wNMIClear = NMIClear; + +reg IRQLatched; + +reg IRQSample; +reg IRQSample2; +reg FIRQLatched; +reg FIRQSample; +reg FIRQSample2; +reg HALTLatched; +reg HALTSample; +reg HALTSample2; +reg DMABREQLatched; +reg DMABREQSample; +reg DMABREQSample2; + +// Interrupt types +localparam INTTYPE_NMI = 3'H0 ; +localparam INTTYPE_IRQ = 3'H1 ; +localparam INTTYPE_FIRQ = 3'H2 ; +localparam INTTYPE_SWI = 3'H3 ; +localparam INTTYPE_SWI2 = 3'H4 ; +localparam INTTYPE_SWI3 = 3'H5 ; + +reg [2:0] IntType; +reg [2:0] IntType_nxt; + +////////////////////////////////////////////////////// +// Instruction Fetch Details +// +reg InstPage2; +reg InstPage3; +reg InstPage2_nxt; +reg InstPage3_nxt; + +reg [7:0] Inst1; +reg [7:0] Inst2; +reg [7:0] Inst3; +reg [7:0] Inst1_nxt; +reg [7:0] Inst2_nxt; +reg [7:0] Inst3_nxt; + + +localparam CPUSTATE_RESET = 7'd0; +localparam CPUSTATE_RESET0 = 7'd1; + +localparam CPUSTATE_RESET2 = 7'd3; +localparam CPUSTATE_FETCH_I1 = 7'd4; +localparam CPUSTATE_FETCH_I1V2 = 7'd5; +localparam CPUSTATE_FETCH_I2 = 7'd8; + +localparam CPUSTATE_LBRA_OFFSETLOW = 7'd17; +localparam CPUSTATE_LBRA_DONTCARE = 7'd18; +localparam CPUSTATE_LBRA_DONTCARE2 = 7'd19; + + + +localparam CPUSTATE_BRA_DONTCARE = 7'd20; + +localparam CPUSTATE_BSR_DONTCARE1 = 7'd21; +localparam CPUSTATE_BSR_DONTCARE2 = 7'd22; +localparam CPUSTATE_BSR_RETURNLOW = 7'd23; +localparam CPUSTATE_BSR_RETURNHIGH = 7'd24; + +localparam CPUSTATE_TFR_DONTCARE1 = 7'd26; +localparam CPUSTATE_TFR_DONTCARE2 = 7'd27; +localparam CPUSTATE_TFR_DONTCARE3 = 7'd28; +localparam CPUSTATE_TFR_DONTCARE4 = 7'd29; + +localparam CPUSTATE_EXG_DONTCARE1 = 7'd30; +localparam CPUSTATE_EXG_DONTCARE2 = 7'd31; +localparam CPUSTATE_EXG_DONTCARE3 = 7'd32; +localparam CPUSTATE_EXG_DONTCARE4 = 7'd33; +localparam CPUSTATE_EXG_DONTCARE5 = 7'd34; +localparam CPUSTATE_EXG_DONTCARE6 = 7'd35; + +localparam CPUSTATE_ABX_DONTCARE = 7'd36; + +localparam CPUSTATE_RTS_HI = 7'd38; +localparam CPUSTATE_RTS_LO = 7'd39; +localparam CPUSTATE_RTS_DONTCARE2 = 7'd40; + +localparam CPUSTATE_16IMM_LO = 7'd41; +localparam CPUSTATE_ALU16_DONTCARE = 7'd42; +localparam CPUSTATE_DIRECT_DONTCARE = 7'd43; + +localparam CPUSTATE_ALU_EA = 7'd44; + +localparam CPUSTATE_ALU_DONTCARE = 7'd46; +localparam CPUSTATE_ALU_WRITEBACK = 7'd47; + +localparam CPUSTATE_LD16_LO = 7'd48; + +localparam CPUSTATE_ST16_LO = 7'd49; +localparam CPUSTATE_ALU16_LO = 7'd50; + + + + +localparam CPUSTATE_JSR_DONTCARE = 7'd53; +localparam CPUSTATE_JSR_RETLO = 7'd54; +localparam CPUSTATE_JSR_RETHI = 7'd55; +localparam CPUSTATE_EXTENDED_ADDRLO = 7'd56; +localparam CPUSTATE_EXTENDED_DONTCARE = 7'd57; +localparam CPUSTATE_INDEXED_BASE = 7'd58; + + +localparam CPUSTATE_IDX_DONTCARE3 = 7'd60; + +localparam CPUSTATE_IDX_OFFSET_LO = 7'd61; +localparam CPUSTATE_IDX_16OFFSET_LO = 7'd62; + +localparam CPUSTATE_IDX_16OFF_DONTCARE0= 7'd63; +localparam CPUSTATE_IDX_16OFF_DONTCARE1= 7'd64; +localparam CPUSTATE_IDX_16OFF_DONTCARE2= 7'd65; +localparam CPUSTATE_IDX_16OFF_DONTCARE3= 7'd66; + +localparam CPUSTATE_IDX_DOFF_DONTCARE1 = 7'd68; +localparam CPUSTATE_IDX_DOFF_DONTCARE2 = 7'd69; +localparam CPUSTATE_IDX_DOFF_DONTCARE3 = 7'd70; +localparam CPUSTATE_IDX_PC16OFF_DONTCARE = 7'd71; + +localparam CPUSTATE_IDX_EXTIND_LO = 7'd72; +localparam CPUSTATE_IDX_EXTIND_DONTCARE = 7'd73; + +localparam CPUSTATE_INDIRECT_HI = 7'd74; +localparam CPUSTATE_INDIRECT_LO = 7'd75; +localparam CPUSTATE_INDIRECT_DONTCARE = 7'd76; +localparam CPUSTATE_MUL_ACTION = 7'd77; + +localparam CPUSTATE_PSH_DONTCARE1 = 7'd80; +localparam CPUSTATE_PSH_DONTCARE2 = 7'd81; +localparam CPUSTATE_PSH_DONTCARE3 = 7'd82; +localparam CPUSTATE_PSH_ACTION = 7'd83; + +localparam CPUSTATE_PUL_DONTCARE1 = 7'd84; +localparam CPUSTATE_PUL_DONTCARE2 = 7'd85; +localparam CPUSTATE_PUL_ACTION = 7'd86; + +localparam CPUSTATE_NMI_START = 7'd87; +localparam CPUSTATE_IRQ_DONTCARE = 7'd88; +localparam CPUSTATE_IRQ_START = 7'd89; +localparam CPUSTATE_IRQ_DONTCARE2 = 7'd90; +localparam CPUSTATE_IRQ_VECTOR_HI = 7'd91; +localparam CPUSTATE_IRQ_VECTOR_LO = 7'd92; +localparam CPUSTATE_FIRQ_START = 7'd93; +localparam CPUSTATE_CC_DONTCARE = 7'd94; +localparam CPUSTATE_SWI_START = 7'd95; + +localparam CPUSTATE_TST_DONTCARE1 = 7'd96; +localparam CPUSTATE_TST_DONTCARE2 = 7'd97; + +localparam CPUSTATE_DEBUG = 7'd98; + +localparam CPUSTATE_16IMM_DONTCARE = 7'd99; + +localparam CPUSTATE_HALTED = 7'd100; + +localparam CPUSTATE_HALT_EXIT2 = 7'd102; +localparam CPUSTATE_STOP = 7'd105; +localparam CPUSTATE_STOP2 = 7'd106; +localparam CPUSTATE_STOP3 = 7'd107; + + +localparam CPUSTATE_CWAI = 7'd108; +localparam CPUSTATE_CWAI_DONTCARE1 = 7'd109; +localparam CPUSTATE_CWAI_POST = 7'd110; + +localparam CPUSTATE_DMABREQ = 7'd111; +localparam CPUSTATE_DMABREQ_EXIT = 7'd112; +localparam CPUSTATE_SYNC = 7'd113; +localparam CPUSTATE_SYNC_EXIT = 7'd114; + +localparam CPUSTATE_INT_DONTCARE = 7'd115; + + +reg [6:0] CpuState = CPUSTATE_RESET; +reg [6:0] CpuState_nxt = CPUSTATE_RESET; + +reg [6:0] NextState = CPUSTATE_RESET; +reg [6:0] NextState_nxt = CPUSTATE_RESET; + +wire [6:0] PostIllegalState; + +// If we encounter something like an illegal addressing mode (an index mode that's illegal for instance) +// What state should we go to? +generate +if (ILLEGAL_INSTRUCTIONS=="STOP") +begin : postillegal + assign PostIllegalState = CPUSTATE_STOP; +end +else +begin + assign PostIllegalState = CPUSTATE_FETCH_I1; +end +endgenerate + + + +/////////////////////////////////////////////////////////////////////// + +// +// MapInstruction - Considering how the core was instantiated, this +// will either directly return D[7:0] *or* remap values from D[7:0] +// that relate to undefined instructions in the 6809 to the instructions +// that the 6809 actually executed when these were encountered, due to +// incomplete decoding. +// +// NEG, COM, LSR, DEC - these four instructions, in Direct, Inherent (A or B) +// Indexed, or Extended addressing do not actually decode bit 0 on the instruction. +// Thus, for instance, a $51 encountered will be executed as a $50, which is a NEGB. +// + +// Specifically, the input is an instruction; if it matches an unknown instruction that the +// 6809 is known to ghost to another instruction, the output of the function +// is the the instruction that actually gets executed. Otherwise, the output is the +// input. + +function [7:0] MapInstruction(input [7:0] i); +reg [3:0] topnyb; +reg [3:0] btmnyb; +reg [7:0] newinst; +begin + newinst = i; + + topnyb = i[7:4]; + btmnyb = i[3:0]; + + if ( (topnyb == 4'H0) || + (topnyb == 4'H4) || + (topnyb == 4'H5) || + (topnyb == 4'H6) || + (topnyb == 4'H7) + ) + begin + if (btmnyb == 4'H1) + newinst = {topnyb, 4'H0}; + if (btmnyb == 4'H2) + newinst = {topnyb, 4'H3}; + if (btmnyb == 4'H5) + newinst = {topnyb, 4'H4}; + if (btmnyb == 4'HB) + newinst = {topnyb, 4'HA}; + end + MapInstruction = newinst; +end +endfunction + + +wire [7:0] MappedInstruction; +generate +if (ILLEGAL_INSTRUCTIONS=="GHOST") +begin : ghost + if(IS_KONAMI1=="FALSE") //Modification by Ace: accept opcodes directly for KONAMI-1 CPU + assign MappedInstruction = MapInstruction(D); + else + assign MappedInstruction = MapInstruction(OP); +end +else +begin + assign MappedInstruction = D; +end +endgenerate + + + +/////////////////////////////////////////////////////////////////////// + +function IllegalInstruction(input [7:0] i); +reg [3:0] hi; +reg [3:0] lo; +reg illegal; +begin + illegal = 1'b0; + hi = i[7:4]; + lo = i[3:0]; + if ( (hi == 4'H0) || (hi == 4'H4) || (hi == 4'H5) || (hi == 4'H6) || (hi == 4'H7) ) + begin + if ( (lo == 4'H1) || (lo == 4'H2) || (lo == 4'H5) || (lo == 4'HB) ) + illegal = 1'b1; + if (lo == 4'HE) + if ( (hi == 4'H4) || (hi == 4'H5) ) + illegal = 1'b1; + end + if (hi == 4'H3) + begin + if ( (lo == 4'H8) || (lo == 4'HE) ) + illegal = 1'b1; + end + if (hi == 4'H1) + begin + if ( (lo == 4'H4) || (lo == 4'H5) || (lo == 4'H8) || (lo == 4'HB) ) + illegal = 1'b1; + end + if ( (hi == 4'H8) || (hi == 4'HC) ) + begin + if ( (lo == 4'H7) || (lo == 4'HF) ) + illegal = 1'b1; + if ( lo == 4'HD ) + if (hi == 4'HC) + illegal = 1'b1; + end + IllegalInstruction = illegal; +end +endfunction + +wire IsIllegalInstruction; + +generate +if (ILLEGAL_INSTRUCTIONS=="GHOST") +begin : never_illegal + assign IsIllegalInstruction = 1'b0; +end +else +begin + assign IsIllegalInstruction = IllegalInstruction(Inst1); +end +endgenerate + +wire [6:0] IllegalInstructionState; +generate +if (ILLEGAL_INSTRUCTIONS=="IGNORE") +begin : illegal_state + assign IllegalInstructionState = CPUSTATE_FETCH_I1; +end +else if (ILLEGAL_INSTRUCTIONS=="STOP") +begin + assign IllegalInstructionState = CPUSTATE_STOP; +end +else +begin + assign IllegalInstructionState = 7'd0; +end +endgenerate + + +/////////////////////////////////////////////////////////////////////// + + +always @(posedge CLK) +begin + reg old_sample; + old_sample <= NMISample2; + + if (wNMIClear == 1) NMILatched <= 1; + else if(old_sample & ~NMISample2) NMILatched <= NMIMask; +end + +// +// The 6809 specs say that the CPU control signals are sampled on the falling edge of Q. +// It also says that the interrupts require 1 cycle of synchronization time. +// That's vague, as it doesn't say where "1 cycle" starts or ends. Starting from the +// falling edge of Q, the next cycle notices an assertion. From checking a hard 6809 on +// an analyzer, what they really mean is that it's sampled on the falling edge of Q, +// but there's a one cycle delay from the falling edge of E (0.25 clocks from the falling edge of Q +// where the signals were sampled) before it can be noticed. +// So, SIGNALSample is the latched value at the falling edge of Q +// SIGNALSample2 is the latched value at the falling edge of E (0.25 clocks after the line above) +// SIGNALLatched is the latched value at the falling edge of E (1 cycle after the line above) +// +// /HALT and /DMABREQ are delayed one cycle less than interrupts. The 6809 specs infer these details, +// but don't list the point-of-reference they're written from (for instance, they say that an interrupt requires +// a cycle for synchronization; however, it isn't clear whether that's from the falling Q to the next falling Q, +// a complete intermediate cycle, the falling E to the next falling E, etc.) - which, in the end, required an +// analyzer on the 6809 to determine how many cycles before a new instruction an interrupt (or /HALT & /DMABREQ) +// had to be asserted to be noted instead of the next instruction running start to finish. +// +always @(posedge CLK) +begin + if(fallQ_en) begin + NMISample <= nNMI; + IRQSample <= nIRQ; + FIRQSample <= nFIRQ; + HALTSample <= nHALT; + DMABREQSample <= nDMABREQ; + end +end + + +reg rnRESET=0; // The latched version of /RESET, useful 1 clock after it's latched +always @(posedge CLK) +begin + if(fallE_en) begin + rnRESET <= nRESET; + + NMISample2 <= NMISample; + + IRQSample2 <= IRQSample; + IRQLatched <= IRQSample2; + + FIRQSample2 <= FIRQSample; + FIRQLatched <= FIRQSample2; + + HALTSample2 <= HALTSample; + HALTLatched <= HALTSample2; + + DMABREQSample2 <= DMABREQSample; + DMABREQLatched <= DMABREQSample2; + + + if (rnRESET == 1) + begin + CpuState <= CpuState_nxt; + + // Don't interpret this next item as "The Next State"; it's a special case 'after this + // generic state, go to this programmable state', so that a single state + // can be shared for many tasks. [Specifically, the stack push/pull code, which is used + // for PSH, PUL, Interrupts, RTI, etc. + NextState <= NextState_nxt; + + // CPU registers latch from the combinatorial circuit + a <= a_nxt; + b <= b_nxt; + x <= x_nxt; + y <= y_nxt; + s <= s_nxt; + u <= u_nxt; + cc <= cc_nxt; + dp <= dp_nxt; + pc <= pc_nxt; + tmp <= tmp_nxt; + addr <= addr_nxt; + ea <= ea_nxt; + + InstPage2 <= InstPage2_nxt; + InstPage3 <= InstPage3_nxt; + Inst1 <= Inst1_nxt; + Inst2 <= Inst2_nxt; + Inst3 <= Inst3_nxt; + NMIClear <= NMIClear_nxt; + + IntType <= IntType_nxt; + + // Once S changes at all (default is '0'), release the NMI Mask. + if (s != s_nxt) NMIMask <= 1'b0; + end + else + begin + CpuState <= CPUSTATE_RESET; + NMIMask <= 1'b1; // Mask NMI until S is loaded. + NMIClear <= 1'b0; // Mark us as not having serviced NMI + end + end +end + + +///////////////////////////////////////////////////////////////// +// Decode the Index byte + +localparam IDX_REG_X = 3'd0; +localparam IDX_REG_Y = 3'd1; +localparam IDX_REG_U = 3'd2; +localparam IDX_REG_S = 3'd3; +localparam IDX_REG_PC = 3'd4; + +localparam IDX_MODE_POSTINC1 = 4'd0; +localparam IDX_MODE_POSTINC2 = 4'd1; +localparam IDX_MODE_PREDEC1 = 4'd2; +localparam IDX_MODE_PREDEC2 = 4'd3; +localparam IDX_MODE_NOOFFSET = 4'd4; +localparam IDX_MODE_B_OFFSET = 4'd5; +localparam IDX_MODE_A_OFFSET = 4'd6; +localparam IDX_MODE_5BIT_OFFSET= 4'd7; // Special case, not bit pattern 7; the offset sits in the bit pattern +localparam IDX_MODE_8BIT_OFFSET= 4'd8; +localparam IDX_MODE_16BIT_OFFSET = 4'd9; +localparam IDX_MODE_D_OFFSET = 4'd11; +localparam IDX_MODE_8BIT_OFFSET_PC = 4'd12; +localparam IDX_MODE_16BIT_OFFSET_PC= 4'd13; +localparam IDX_MODE_EXTENDED_INDIRECT = 4'd15; + +// Return: +// Register base [3 bits] +// Indirect [1 bit] +// Mode [4 bits] + +function [7:0] IndexDecode(input [7:0] postbyte); +reg [2:0] regnum; +reg indirect; +reg [3:0] mode; +begin + indirect = 0; + mode = 0; + + if (postbyte[7] == 0) // 5-bit + begin + mode = IDX_MODE_5BIT_OFFSET; + end + else + begin + mode = postbyte[3:0]; + indirect = postbyte[4]; + end + if ((mode != IDX_MODE_8BIT_OFFSET_PC) && (mode != IDX_MODE_16BIT_OFFSET_PC)) + regnum[2:0] = postbyte[6:5]; + else + regnum[2:0] = IDX_REG_PC; + + IndexDecode = {indirect, mode, regnum}; +end +endfunction + +wire [3:0] IndexedMode; +wire IndexedIndirect; +wire [2:0] IndexedRegister; + +assign {IndexedIndirect, IndexedMode, IndexedRegister} = IndexDecode(Inst2); + +///////////////////////////////////////////////////////////////// +// Is this a JMP instruction? (irrespective of addressing mode) +function IsJMP(input [7:0] inst); +reg [3:0] hi; +reg [3:0] lo; +begin + hi = inst[7:4]; + lo = inst[3:0]; + + IsJMP = 0; + if ((hi == 4'H0) || (hi == 4'H6) || (hi == 4'H7)) + if (lo == 4'HE) + IsJMP = 1; +end +endfunction + +/////////////////////////////////////////////////////////////////// +// Is this an 8-bit Store? + +localparam ST8_REG_A = 1'b0; +localparam ST8_REG_B = 1'b1; + +function [1:0] IsST8(input [7:0] inst); +reg regnum; +reg IsStore; +begin + + IsStore = 1'b0; + regnum = 1'b1; + + if ( (Inst1 == 8'H97) || (Inst1 == 8'HA7) || (Inst1 == 8'HB7) ) + begin + IsStore = 1'b1; + regnum = 1'b0; + end + else if ( (Inst1 == 8'HD7) || (Inst1 == 8'HE7) || (Inst1 == 8'HF7) ) + begin + IsStore = 1'b1; + regnum = 1'b1; + end + IsST8 = {IsStore, regnum}; +end +endfunction + +wire IsStore8; +wire Store8RegisterNum; + +assign {IsStore8, Store8RegisterNum} = IsST8(Inst1); + + +///////////////////////////////////////////////////////////////// +// Is this a 16-bit Store? + +localparam ST16_REG_X = 3'd0; +localparam ST16_REG_Y = 3'd1; +localparam ST16_REG_U = 3'd2; +localparam ST16_REG_S = 3'd3; +localparam ST16_REG_D = 3'd4; + + +function [3:0] IsST16(input [7:0] inst); +reg [3:0] hi; +reg [3:0] lo; +reg [2:0] regnum; +reg IsStore; +begin + hi = inst[7:4]; + lo = inst[3:0]; + IsStore = 1'b0; + regnum = 3'b111; + + if ((inst == 8'H9F) || (inst == 8'HAF) || (inst == 8'HBF)) + begin + IsStore = 1; + if (~InstPage2) + regnum = ST16_REG_X; + else + regnum = ST16_REG_Y; + end + else if ((inst == 8'HDF) || (inst == 8'HEF) || (inst == 8'HFF)) + begin + IsStore = 1; + if (~InstPage2) + regnum = ST16_REG_U; + else + regnum = ST16_REG_S; + end + else if ((inst == 8'HDD) || (inst == 8'HED) || (inst == 8'HFD)) + begin + IsStore = 1; + regnum = ST16_REG_D; + end + + IsST16 = {IsStore, regnum}; +end +endfunction + +wire IsStore16; +wire [2:0] StoreRegisterNum; + +assign {IsStore16, StoreRegisterNum} = IsST16(Inst1); + +///////////////////////////////////////////////////////////////// +// Is this a special Immediate mode instruction, ala +// PSH, PUL, EXG, TFR, ANDCC, ORCC +function IsSpecialImm(input [7:0] inst); +reg is; +reg [3:0] hi; +reg [3:0] lo; +begin + hi = inst[7:4]; + lo = inst[3:0]; + is = 0; + + if (hi == 4'H1) + begin + if ( (lo == 4'HA) || (lo == 4'HC) || (lo == 4'HE) || (lo == 4'HF) ) // ORCC, ANDCC, EXG, TFR + is = 1; + end + else if (hi == 4'H3) + begin + if ( (lo >= 4'H3) && (lo <= 4'H7) ) // PSHS, PULS, PSHU, PULU + is = 1; + end + else + is = 0; + + IsSpecialImm = is; +end +endfunction +wire IsSpecialImmediate = IsSpecialImm(Inst1); + +///////////////////////////////////////////////////////////////// +// Is this a one-byte instruction? [The 6809 reads 2 bytes for every instruction, minimum (it can read more). On a one-byte, we have to ensure that we haven't skipped the PC ahead. +function IsOneByteInstruction(input [7:0] inst); +reg is; +reg [3:0] hi; +reg [3:0] lo; +begin + hi = inst[7:4]; + lo = inst[3:0]; + is = 1'b0; + + if ( (hi == 4'H4) || (hi == 4'H5) ) + is = 1'b1; + else if ( hi == 4'H1) + begin + if ( (lo == 4'H2) || (lo == 4'H3) || (lo == 4'H9) || (lo == 4'HD) ) + is = 1'b1; + end + else if (hi == 4'H3) + begin + if ( (lo >= 4'H9) && (lo != 4'HC) ) + is = 1'b1; + end + else + is = 1'b0; + + IsOneByteInstruction = is; +end +endfunction + +///////////////////////////////////////////////////////////////// +// ALU16 - Simpler than the 8 bit ALU + +localparam ALU16_REG_X = 3'd0; +localparam ALU16_REG_Y = 3'd1; +localparam ALU16_REG_U = 3'd2; +localparam ALU16_REG_S = 3'd3; +localparam ALU16_REG_D = 3'd4; + +function [2:0] ALU16RegFromInst(input Page2, input Page3, input [7:0] inst); +reg [2:0] srcreg; +begin + srcreg = 3'b111; // default + casex ({Page2, Page3, inst}) // Note pattern for the matching below + 10'b1010xx0011: // 1083, 1093, 10A3, 10B3 CMPD + srcreg = ALU16_REG_D; + 10'b1010xx1100: // 108C, 109C, 10AC, 10BC CMPY + srcreg = ALU16_REG_Y; + 10'b0110xx0011: // 1183, 1193, 11A3, 11B3 CMPU + srcreg = ALU16_REG_U; + 10'b0110xx1100: // 118C, 119C, 11AC, 11BC CMPS + srcreg = ALU16_REG_S; + 10'b0010xx1100: // 8C,9C,AC,BC CMPX + srcreg = ALU16_REG_X; + + 10'b0011xx0011: // C3, D3, E3, F3 ADDD + srcreg = ALU16_REG_D; + + 10'b0011xx1100: // CC, DC, EC, FC LDD + srcreg = ALU16_REG_D; + 10'b0010xx1110: // 8E LDX, 9E LDX, AE LDX, BE LDX + srcreg = ALU16_REG_X; + 10'b0011xx1110: // CE LDU, DE LDU, EE LDU, FE LDU + srcreg = ALU16_REG_U; + 10'b1010xx1110: // 108E LDY, 109E LDY, 10AE LDY, 10BE LDY + srcreg = ALU16_REG_Y; + 10'b1011xx1110: // 10CE LDS, 10DE LDS, 10EE LDS, 10FE LDS + srcreg = ALU16_REG_S; + 10'b0010xx0011: // 83, 93, A3, B3 SUBD + srcreg = ALU16_REG_D; + + 10'H03A: // 3A ABX + srcreg = ALU16_REG_X; + 10'H030: // 30 LEAX + srcreg = ALU16_REG_X; + 10'H031: // 31 LEAY + srcreg = ALU16_REG_Y; + 10'H032: // 32 LEAS + srcreg = ALU16_REG_S; + 10'H033: // 32 LEAU + srcreg = ALU16_REG_U; + default: + srcreg = 3'b111; + endcase + ALU16RegFromInst = srcreg; +end +endfunction + +wire [2:0] ALU16Reg = ALU16RegFromInst(InstPage2, InstPage3, Inst1); + +localparam ALUOP16_SUB = 3'H0; +localparam ALUOP16_ADD = 3'H1; +localparam ALUOP16_LD = 3'H2; +localparam ALUOP16_CMP = 3'H3; +localparam ALUOP16_LEA = 3'H4; +localparam ALUOP16_INVALID = 3'H7; + +function [3:0] ALU16OpFromInst(input Page2, input Page3, input [7:0] inst); +reg [2:0] aluop; +reg writeback; +begin + aluop = 3'b111; + writeback = 1'b1; + casex ({Page2, Page3, inst}) + 10'b1010xx0011: // 1083, 1093, 10A3, 10B3 CMPD + begin + aluop = ALUOP16_CMP; + writeback = 1'b0; + end + 10'b1010xx1100: // 108C, 109C, 10AC, 10BC CMPY + begin + aluop = ALUOP16_CMP; + writeback = 1'b0; + end + 10'b0110xx0011: // 1183, 1193, 11A3, 11B3 CMPU + begin + aluop = ALUOP16_CMP; + writeback = 1'b0; + end + 10'b0110xx1100: // 118C, 119C, 11AC, 11BC CMPS + begin + aluop = ALUOP16_CMP; + writeback = 1'b0; + end + 10'b0010xx1100: // 8C,9C,AC,BC CMPX + begin + aluop = ALUOP16_CMP; + writeback = 1'b0; + end + + 10'b0011xx0011: // C3, D3, E3, F3 ADDD + aluop = ALUOP16_ADD; + + 10'b0011xx1100: // CC, DC, EC, FC LDD + aluop = ALUOP16_LD; + 10'b001xxx1110: // 8E LDX, 9E LDX, AE LDX, BE LDX, CE LDU, DE LDU, EE LDU, FE LDU + aluop = ALUOP16_LD; + 10'b101xxx1110: // 108E LDY, 109E LDY, 10AE LDY, 10BE LDY, 10CE LDS, 10DE LDS, 10EE LDS, 10FE LDS + aluop = ALUOP16_LD; + + 10'b0010xx0011: // 83, 93, A3, B3 SUBD + aluop = ALUOP16_SUB; + + 10'H03A: // 3A ABX + aluop = ALUOP16_ADD; + + 10'b00001100xx: // $30-$33, LEAX, LEAY, LEAS, LEAU + aluop = ALUOP16_LEA; + + default: + aluop = ALUOP16_INVALID; + endcase + ALU16OpFromInst = {writeback, aluop}; +end +endfunction + +wire ALU16OpWriteback; +wire [2:0] ALU16Opcode; + +assign {ALU16OpWriteback, ALU16Opcode} = ALU16OpFromInst(InstPage2, InstPage3, Inst1); + +wire IsALU16Opcode = (ALU16Opcode != 3'b111); + +function [23:0] ALU16Inst(input [2:0] operation16, input [15:0] a_arg, input [15:0] b_arg, input [7:0] cc_arg); +reg [7:0] cc_out; +reg [15:0] ALUFn; +reg carry; +reg borrow; +begin + cc_out = cc_arg; + case (operation16) + ALUOP16_ADD: + begin + {cc_out[CC_C_BIT], ALUFn} = {1'b0, a_arg} + b_arg; + cc_out[CC_V_BIT] = (a_arg[15] & b_arg[15] & ~ALUFn[15]) | (~a_arg[15] & ~b_arg[15] & ALUFn[15]); + end + + ALUOP16_SUB: + begin + {cc_out[CC_C_BIT], ALUFn} = {1'b0, a_arg} - {1'b0, b_arg}; + cc_out[CC_V_BIT] = (a_arg[15] & ~b_arg[15] & ~ALUFn[15]) | (~a_arg[15] & b_arg[15] & ALUFn[15]); + end + + ALUOP16_LD: + begin + ALUFn = b_arg; + cc_out[CC_V_BIT] = 1'b0; + end + + ALUOP16_CMP: + begin + {cc_out[CC_C_BIT], ALUFn} = {1'b0, a_arg} - {1'b0, b_arg}; + cc_out[CC_V_BIT] = (a_arg[15] & ~b_arg[15] & ~ALUFn[15]) | (~a_arg[15] & b_arg[15] & ALUFn[15]); + end + + ALUOP16_LEA: + begin + ALUFn = a_arg; + end + + default: + ALUFn = 16'H0000; + + endcase + cc_out[CC_Z_BIT] = (ALUFn[15:0] == 16'H0000); + if (operation16 != ALUOP16_LEA) + cc_out[CC_N_BIT] = ALUFn[15]; + ALU16Inst = {cc_out, ALUFn}; +end +endfunction + +reg [2:0] ALU16_OP; +reg [15:0] ALU16_A; +reg [15:0] ALU16_B; +reg [7:0] ALU16_CC; + +// Top 8 bits == CC, bottom 8 bits = output value +wire [23:0] ALU16 = ALU16Inst(ALU16_OP, ALU16_A, ALU16_B, ALU16_CC); + + +///////////////////////////////////////////////////////////////// +// ALU + +// The ops are organized from the 4 low-order bits of the instructions for the first set of ops, then 16-31 are the second set - even though bit 4 isn't representative. +localparam ALUOP_NEG = 5'd0; +localparam ALUOP_COM = 5'd3; +localparam ALUOP_LSR = 5'd4; +localparam ALUOP_ROR = 5'd6; +localparam ALUOP_ASR = 5'd7; +localparam ALUOP_ASL = 5'd8; +localparam ALUOP_LSL = 5'd8; +localparam ALUOP_ROL = 5'd9; +localparam ALUOP_DEC = 5'd10; +localparam ALUOP_INC = 5'd12; +localparam ALUOP_TST = 5'd13; +localparam ALUOP_CLR = 5'd15; + +localparam ALUOP_SUB = 5'd16; +localparam ALUOP_CMP = 5'd17; +localparam ALUOP_SBC = 5'd18; +localparam ALUOP_AND = 5'd20; +localparam ALUOP_BIT = 5'd21; +localparam ALUOP_LD = 5'd22; +localparam ALUOP_EOR = 5'd24; +localparam ALUOP_ADC = 5'd25; +localparam ALUOP_OR = 5'd26; +localparam ALUOP_ADD = 5'd27; + +function [5:0] ALUOpFromInst(input [7:0] inst); +reg [4:0] op; +reg writeback; +begin + // Okay, this turned out to be simpler than I expected ... + op = {inst[7], inst[3:0]}; + case (op) + ALUOP_CMP: + writeback = 0; + ALUOP_TST: + writeback = 0; + ALUOP_BIT: + writeback = 0; + default: + writeback = 1; + endcase + ALUOpFromInst = {writeback, op}; +end +endfunction + +wire [4:0] ALU8Op; +wire ALU8Writeback; + +assign {ALU8Writeback, ALU8Op} = ALUOpFromInst(Inst1); + +reg [7:0] ALU_A; +reg [7:0] ALU_B; +reg [7:0] ALU_CC; +reg [4:0] ALU_OP; + + +function [15:0] ALUInst(input [4:0] operation, input [7:0] a_arg, input [7:0] b_arg, input [7:0] cc_arg); +reg [7:0] cc_out; +reg [7:0] ALUFn; +reg borrow; +begin + cc_out = cc_arg; + case (operation) + ALUOP_NEG: + begin + ALUFn = ~a_arg + 1'b1; + cc_out[CC_C_BIT] = (ALUFn != 8'H00); + cc_out[CC_V_BIT] = (a_arg == 8'H80); + end + + ALUOP_LSL: + begin + {cc_out[CC_C_BIT], ALUFn} = {a_arg, 1'b0}; + cc_out[CC_V_BIT] = a_arg[7] ^ a_arg[6]; + end + + ALUOP_LSR: + begin + {ALUFn, cc_out[CC_C_BIT]} = {1'b0, a_arg}; + end + + ALUOP_ASR: + begin + {ALUFn, cc_out[CC_C_BIT]} = {a_arg[7], a_arg}; + end + + ALUOP_ROL: + begin + {cc_out[CC_C_BIT], ALUFn} = {a_arg, cc_arg[CC_C_BIT]}; + cc_out[CC_V_BIT] = a_arg[7] ^ a_arg[6]; + end + + ALUOP_ROR: + begin + {ALUFn, cc_out[CC_C_BIT]} = {cc_arg[CC_C_BIT], a_arg}; + end + + ALUOP_OR: + begin + ALUFn = (a_arg | b_arg); + cc_out[CC_V_BIT] = 0; + end + + ALUOP_ADD: + begin + {cc_out[CC_C_BIT], ALUFn} = {1'b0, a_arg} + {1'b0, b_arg}; + cc_out[CC_V_BIT] = (a_arg[7] & b_arg[7] & ~ALUFn[7]) | (~a_arg[7] & ~b_arg[7] & ALUFn[7]); + cc_out[CC_H_BIT] = a_arg[4] ^ b_arg[4] ^ ALUFn[4]; + end + + ALUOP_SUB: + begin + {cc_out[CC_C_BIT], ALUFn} = {1'b0, a_arg} - {1'b0, b_arg}; + cc_out[CC_V_BIT] = (a_arg[7] & ~b_arg[7] & ~ALUFn[7]) | (~a_arg[7] & b_arg[7] & ALUFn[7]); + end + + ALUOP_AND: + begin + ALUFn = (a_arg & b_arg); + cc_out[CC_V_BIT] = 0; + end + + ALUOP_BIT: + begin + ALUFn = (a_arg & b_arg); + cc_out[CC_V_BIT] = 0; + end + + ALUOP_EOR: + begin + ALUFn = (a_arg ^ b_arg); + cc_out[CC_V_BIT] = 0; + end + + ALUOP_CMP: + begin + {cc_out[CC_C_BIT], ALUFn} = {1'b0, a_arg} - {1'b0, b_arg}; + cc_out[CC_V_BIT] = (a_arg[7] & ~b_arg[7] & ~ALUFn[7]) | (~a_arg[7] & b_arg[7] & ALUFn[7]); + end + + ALUOP_COM: + begin + ALUFn = ~a_arg; + cc_out[CC_V_BIT] = 0; + cc_out[CC_C_BIT] = 1; + end + + ALUOP_ADC: + begin + {cc_out[CC_C_BIT], ALUFn} = {1'b0, a_arg} + {1'b0, b_arg} + cc_arg[CC_C_BIT]; + cc_out[CC_V_BIT] = (a_arg[7] & b_arg[7] & ~ALUFn[7]) | (~a_arg[7] & ~b_arg[7] & ALUFn[7]); + cc_out[CC_H_BIT] = a_arg[4] ^ b_arg[4] ^ ALUFn[4]; + end + + ALUOP_LD: + begin + ALUFn = b_arg; + cc_out[CC_V_BIT] = 0; + end + + ALUOP_INC: + begin + ALUFn = a_arg + 1'b1; + cc_out[CC_V_BIT] = (~a_arg[7] & ALUFn[7]); + end + + ALUOP_DEC: + begin + ALUFn = a_arg - 1'b1; + cc_out[CC_V_BIT] = (a_arg[7] & ~ALUFn[7]); + end + + ALUOP_CLR: + begin + ALUFn = 0; + cc_out[CC_V_BIT] = 0; + cc_out[CC_C_BIT] = 0; + end + + ALUOP_TST: + begin + ALUFn = a_arg; + cc_out[CC_V_BIT] = 0; + end + + ALUOP_SBC: + begin + {cc_out[CC_C_BIT], ALUFn} = {1'b0, a_arg} - {1'b0, b_arg} - cc_arg[CC_C_BIT]; + cc_out[CC_V_BIT] = (a_arg[7] & ~b_arg[7] & ~ALUFn[7]) | (~a_arg[7] & b_arg[7] & ALUFn[7]); + end + + default: + ALUFn = 0; + + endcase + + cc_out[CC_N_BIT] = ALUFn[7]; + cc_out[CC_Z_BIT] = !ALUFn; + ALUInst = {cc_out[7:0], ALUFn}; +end +endfunction + + +// Top 8 bits == CC, bottom 8 bits = output value +wire [15:0] ALU = ALUInst(ALU_OP, ALU_A, ALU_B, ALU_CC); + +//////////////////////////////////////////////////////////// + +localparam TYPE_INHERENT = 3'd0; +localparam TYPE_IMMEDIATE = 3'd1; +localparam TYPE_DIRECT = 3'd2; +localparam TYPE_RELATIVE = 3'd3; +localparam TYPE_INDEXED = 3'd4; +localparam TYPE_EXTENDED = 3'd5; + +localparam TYPE_INVALID = 3'd7; + +// Function to decode the addressing mode the instruction uses +function [2:0] addressing_mode_type(input [7:0] inst); +begin + casex (inst) + 8'b0000???? : addressing_mode_type = TYPE_DIRECT; + 8'b0001???? : + begin + casex (inst[3:0]) + 4'b0010: + addressing_mode_type = TYPE_INHERENT; + + 4'b0011: + addressing_mode_type = TYPE_INHERENT; + + 4'b1001: + addressing_mode_type = TYPE_INHERENT; + + 4'b1101: + addressing_mode_type = TYPE_INHERENT; + + 4'b0110: + addressing_mode_type = TYPE_RELATIVE; + + 4'b0111: + addressing_mode_type = TYPE_RELATIVE; + + 4'b1010: + addressing_mode_type = TYPE_IMMEDIATE; + + 4'b1100: + addressing_mode_type = TYPE_IMMEDIATE; + + 4'b1110: + addressing_mode_type = TYPE_IMMEDIATE; + + 4'b1111: + addressing_mode_type = TYPE_IMMEDIATE; + + default: + addressing_mode_type = TYPE_INVALID; + endcase + end + + 8'b0010????: addressing_mode_type = TYPE_RELATIVE; + 8'b0011????: + begin + casex(inst[3:0]) + 4'b00??: + addressing_mode_type = TYPE_INDEXED; + + 4'b01??: + addressing_mode_type = TYPE_IMMEDIATE; + + 4'b1001: + addressing_mode_type = TYPE_INHERENT; + + 4'b101?: + addressing_mode_type = TYPE_INHERENT; + + 4'b1100: + addressing_mode_type = TYPE_INHERENT; + + 4'b1101: + addressing_mode_type = TYPE_INHERENT; + + 4'b1111: + addressing_mode_type = TYPE_INHERENT; + + default: + addressing_mode_type = TYPE_INVALID; + endcase + end + + 8'b010?????: addressing_mode_type = TYPE_INHERENT; + + 8'b0110????: addressing_mode_type = TYPE_INDEXED; + + 8'b0111????: addressing_mode_type = TYPE_EXTENDED; + + 8'b1000????: + begin + casex (inst[3:0]) + 4'b0111: addressing_mode_type = TYPE_INVALID; + 4'b1111: addressing_mode_type = TYPE_INVALID; + 4'b1101: addressing_mode_type = TYPE_RELATIVE; + default: addressing_mode_type = TYPE_IMMEDIATE; + endcase + end + + 8'b1001????: addressing_mode_type = TYPE_DIRECT; + 8'b1010????: addressing_mode_type = TYPE_INDEXED; + 8'b1011????: addressing_mode_type = TYPE_EXTENDED; + 8'b1100????: addressing_mode_type = TYPE_IMMEDIATE; + 8'b1101????: addressing_mode_type = TYPE_DIRECT; + 8'b1110????: addressing_mode_type = TYPE_INDEXED; + 8'b1111????: addressing_mode_type = TYPE_EXTENDED; + + endcase +end +endfunction + +wire [2:0] AddrModeType = addressing_mode_type(Inst1); + +////////////////////////////////////////////////// + +// Individual opcodes that are the top of a column of states. + +localparam OPCODE_INH_ABX = 8'H3A; +localparam OPCODE_INH_RTS = 8'H39; +localparam OPCODE_INH_RTI = 8'H3B; +localparam OPCODE_INH_CWAI = 8'H3C; +localparam OPCODE_INH_MUL = 8'H3D; +localparam OPCODE_INH_SWI = 8'H3F; +localparam OPCODE_INH_SEX = 8'H1D; +localparam OPCODE_INH_NOP = 8'H12; +localparam OPCODE_INH_SYNC = 8'H13; +localparam OPCODE_INH_DAA = 8'H19; + +localparam OPCODE_IMM_ORCC = 8'H1A; +localparam OPCODE_IMM_ANDCC = 8'H1C; +localparam OPCODE_IMM_EXG = 8'H1E; +localparam OPCODE_IMM_TFR = 8'H1F; +localparam OPCODE_IMM_PSHS = 8'H34; +localparam OPCODE_IMM_PULS = 8'H35; +localparam OPCODE_IMM_PSHU = 8'H36; +localparam OPCODE_IMM_PULU = 8'H37; + +localparam OPCODE_IMM_SUBD = 8'H83; +localparam OPCODE_IMM_CMPX = 8'H8C; +localparam OPCODE_IMM_LDX = 8'H8E; +localparam OPCODE_IMM_ADDD = 8'HC3; +localparam OPCODE_IMM_LDD = 8'HCC; +localparam OPCODE_IMM_LDU = 8'HCE; +localparam OPCODE_IMM_CMPD = 8'H83; // Page2 +localparam OPCODE_IMM_CMPY = 8'H8C; // Page2 +localparam OPCODE_IMM_LDY = 8'H8E; // Page2 +localparam OPCODE_IMM_LDS = 8'HCE; // Page2 +localparam OPCODE_IMM_CMPU = 8'H83; // Page3 +localparam OPCODE_IMM_CMPS = 8'H8C; // Page3 + +localparam EXGTFR_REG_D = 4'H0; +localparam EXGTFR_REG_X = 4'H1; +localparam EXGTFR_REG_Y = 4'H2; +localparam EXGTFR_REG_U = 4'H3; +localparam EXGTFR_REG_S = 4'H4; +localparam EXGTFR_REG_PC = 4'H5; +localparam EXGTFR_REG_A = 4'H8; +localparam EXGTFR_REG_B = 4'H9; +localparam EXGTFR_REG_CC = 4'HA; +localparam EXGTFR_REG_DP = 4'HB; + +function IsALU8Set0(input [7:0] instr); +reg result; +reg [3:0] hi; +reg [3:0] lo; +begin + hi = instr[7:4]; + lo = instr[3:0]; + if ( (hi == 4'H0) || (hi == 4'H4) || (hi == 4'H5) || (hi == 4'H6) || (hi == 4'H7) ) + begin + if ( (lo != 4'H1) && (lo != 4'H2) && (lo != 4'H5) && (lo != 4'HB) && (lo != 4'HE) ) // permit NEG, COM, LSR, ROR, ASR, ASL/LSL, ROL, DEC, INC, TST, CLR + result = 1; + else + result = 0; + end + else + result = 0; + IsALU8Set0 = result; +end +endfunction + +function IsALU8Set1(input [7:0] instr); +reg result; +reg [3:0] hi; +reg [3:0] lo; +begin + hi = instr[7:4]; + lo = instr[3:0]; + if ( (hi >= 4'H8) ) + begin + if ( (lo <= 4'HB) && (lo != 4'H3) && (lo != 4'H7) ) // 8-bit SUB, CMP, SBC, AND, BIT, LD, EOR, ADC, OR, ADD + result = 1; + else + result = 0; + end + else + result = 0; + IsALU8Set1 = result; +end +endfunction + +// Determine if the instruction is performing an 8-bit op (ALU only) +function ALU8BitOp(input [7:0] instr); +begin + ALU8BitOp = IsALU8Set0(instr) | IsALU8Set1(instr); +end +endfunction + +wire Is8BitInst = ALU8BitOp(Inst1); + +function IsRegA(input [7:0] instr); +reg result; +reg [3:0] hi; +begin + hi = instr[7:4]; + if ((hi == 4'H4) || (hi == 4'H8) || (hi == 4'H9) || (hi == 4'HA) || (hi == 4'HB) ) + result = 1; + else + result = 0; + IsRegA = result; +end +endfunction + +wire IsTargetRegA = IsRegA(Inst1); + +// +// +// Decode +// 00-0F = DIRECT +// 10-1F = INHERENT, RELATIVE, IMMEDIATE +// 20-2F = RELATIVE +// 30-3F = INDEXED, IMMEDIATE (pus, pul), INHERENT +// 40-4F = INHERENT +// 50-5F = INHERENT +// 60-6F = INDEXED +// 70-7F = EXTENDED +// 80-8F = IMMEDIATE, RELATIVE (BSR) +// 90-9F = DIRECT +// A0-AF = INDEXED +// B0-BF = EXTENDED +// C0-CF = IMMEDIATE +// D0-DF = DIRECT +// E0-EF = INDEXED +// F0-FF = EXTENDED + +// DIRECT; 00-0F, 90-9F, D0-DF +// INHERENT; 10-1F (12, 13, 19, 1D), 30-3F (39-3F), 40-4F, 50-5F, +// RELATIVE: 10-1F (16, 17), 20-2F, 80-8F (8D) +// IMMEDIATE: 10-1F (1A, 1C, 1E, 1F), 30-3F (34-37), 80-8F (80-8C, 8E), C0-CF +// INDEXED: 60-6F, A0-AF, E0-EF +// EXTENDED: 70-7F, B0-Bf, F0-FF + +localparam INST_LBRA = 8'H16; // always -- shitty numbering, damnit +localparam INST_LBSR = 8'H17; // + +localparam INST_BRA = 8'H20; // always +localparam INST_BRN = 8'H21; // never +localparam INST_BHI = 8'H22; // CC.Z = 0 && CC.C = 0 +localparam INST_BLS = 8'H23; // CC.Z != 0 && CC.C != 0 +localparam INST_BCC = 8'H24; // CC.C = 0 +localparam INST_BHS = 8'H24; // same as BCC +localparam INST_BCS = 8'H25; // CC.C = 1 +localparam INST_BLO = 8'H25; // same as BCS +localparam INST_BNE = 8'H26; // CC.Z = 0 +localparam INST_BEQ = 8'H27; // CC.Z = 1 +localparam INST_BVC = 8'H28; // V = 1 +localparam INST_BVS = 8'H29; // V = 0 +localparam INST_BPL = 8'H2A; // CC.N = 0 +localparam INST_BMI = 8'H2B; // CC.N = 1 +localparam INST_BGE = 8'H2C; // CC.N = CC.V +localparam INST_BLT = 8'H2D; // CC.N != CC.V +localparam INST_BGT = 8'H2E; // CC.N = CC.V && CC.Z = 0 +localparam INST_BLE = 8'H2F; // CC.N != CC.V && CC.Z = 1 +localparam INST_BSR = 8'H8D; // always + +localparam NYB_BRA = 4'H0; // always +localparam NYB_BRN = 4'H1; // never +localparam NYB_BHI = 4'H2; // CC.Z = 0 && CC.C = 0 +localparam NYB_BLS = 4'H3; // CC.Z != 0 && CC.C != 0 +localparam NYB_BCC = 4'H4; // CC.C = 0 +localparam NYB_BHS = 4'H4; // same as BCC +localparam NYB_BCS = 4'H5; // CC.C = 1 +localparam NYB_BLO = 4'H5; // same as BCS +localparam NYB_BNE = 4'H6; // CC.Z = 0 +localparam NYB_BEQ = 4'H7; // CC.Z = 1 +localparam NYB_BVC = 4'H8; // V = 0 +localparam NYB_BVS = 4'H9; // V = 1 +localparam NYB_BPL = 4'HA; // CC.N = 0 +localparam NYB_BMI = 4'HB; // CC.N = 1 +localparam NYB_BGE = 4'HC; // CC.N = CC.V +localparam NYB_BLT = 4'HD; // CC.N != CC.V +localparam NYB_BGT = 4'HE; // CC.N = CC.V && CC.Z = 0 +localparam NYB_BLE = 4'HF; // CC.N != CC.V && CC.Z = 1 + + + +function take_branch(input [7:0] Inst1, input [7:0] cc); +begin + take_branch = 0; //default + if ( (Inst1 == INST_BSR) || (Inst1 == INST_LBSR) || (Inst1 == INST_LBRA) ) + take_branch = 1; + else + case (Inst1[3:0]) + NYB_BRA: + take_branch = 1; + NYB_BRN: + take_branch = 0; + NYB_BHI: + if ( ( cc[CC_Z_BIT] | cc[CC_C_BIT] ) == 0) + take_branch = 1; + NYB_BLS: + if ( cc[CC_Z_BIT] | cc[CC_C_BIT] ) + take_branch = 1; + NYB_BCC: + if ( cc[CC_C_BIT] == 0 ) + take_branch = 1; + NYB_BCS: + if ( cc[CC_C_BIT] == 1 ) + take_branch = 1; + NYB_BNE: + if ( cc[CC_Z_BIT] == 0 ) + take_branch = 1; + NYB_BEQ: + if ( cc[CC_Z_BIT] == 1 ) + take_branch = 1; + NYB_BVC: + if ( cc[CC_V_BIT] == 0) + take_branch = 1; + NYB_BVS: + if ( cc[CC_V_BIT] == 1) + take_branch = 1; + NYB_BPL: + if ( cc[CC_N_BIT] == 0 ) + take_branch = 1; + NYB_BMI: + if (cc[CC_N_BIT] == 1) + take_branch = 1; + NYB_BGE: + if ((cc[CC_N_BIT] ^ cc[CC_V_BIT]) == 0) + take_branch = 1; + NYB_BLT: + if ((cc[CC_N_BIT] ^ cc[CC_V_BIT]) == 1) + take_branch = 1; + NYB_BGT: + if ( ((cc[CC_N_BIT] ^ cc[CC_V_BIT]) == 0) & (cc[CC_Z_BIT] == 0) ) + take_branch = 1; + NYB_BLE: + if ( ((cc[CC_N_BIT] ^ cc[CC_V_BIT]) == 1) | (cc[CC_Z_BIT] == 1) ) + take_branch = 1; + endcase +end +endfunction + +wire TakeBranch = take_branch(Inst1, cc); + +///////////////////////////////////////////////////////////////////// +// Convenience function for knowing the contents for TFR, EXG +function [15:0] EXGTFRRegister(input [3:0] regid); +begin + case (regid) + EXGTFR_REG_D: + EXGTFRRegister = {a, b}; + EXGTFR_REG_X: + EXGTFRRegister = x; + EXGTFR_REG_Y: + EXGTFRRegister = y; + EXGTFR_REG_U: + EXGTFRRegister = u; + EXGTFR_REG_S: + EXGTFRRegister = s; + EXGTFR_REG_PC: + EXGTFRRegister = pc_p1; // For both EXG and TFR, this is used on the 2nd byte in the instruction's cycle. The PC intended to transfer is actually the next byte. + EXGTFR_REG_DP: + EXGTFRRegister = {8'HFF, dp}; + EXGTFR_REG_A: + EXGTFRRegister = {8'HFF, a}; + EXGTFR_REG_B: + EXGTFRRegister = {8'HFF, b}; + EXGTFR_REG_CC: + EXGTFRRegister = {8'HFF, cc}; + default: + EXGTFRRegister = 16'H0; + endcase +end +endfunction +wire [15:0] EXGTFRRegA = EXGTFRRegister(D[7:4]); +wire [15:0] EXGTFRRegB = EXGTFRRegister(D[3:0]); + +// CPU state machine +always @(*) +begin + rLIC = 1'b0; + rAVMA = 1'b1; + rBUSY = 1'b0; + + addr_nxt = 16'HFFFF; + pc_p1 = (pc+16'H1); + pc_p2 = (pc+16'H2); + pc_p3 = (pc+16'H3); + s_p1 = (s+16'H1); + s_m1 = (s-16'H1); + u_p1 = (u+16'H1); + u_m1 = (u-16'H1); + addr_p1 = (addr+16'H1); + ea_p1 = (ea+16'H1); + BS_nxt = 1'b0; + BA_nxt = 1'b0; + + // These may be overridden below, but the "next" version by default should be + // the last latched version. + IntType_nxt = IntType; + NMIClear_nxt = NMIClear; + NextState_nxt = NextState; + a_nxt = a; + b_nxt = b; + x_nxt = x; + y_nxt = y; + s_nxt = s; + u_nxt = u; + cc_nxt = cc; + dp_nxt = dp; + pc_nxt = pc; + tmp_nxt = tmp; + ea_nxt = ea; + + ALU_A = 8'H00; + ALU_B = 8'H00; + ALU_CC = 8'H00; + ALU_OP = 5'H00; + + ALU16_OP = 3'H0; + ALU16_A = 16'H0000; + ALU16_B = 16'H0000; + ALU16_CC = 8'H00; + + DOutput = 8'H00; + RnWOut = 1'b1; // read + + Inst1_nxt = Inst1; + Inst2_nxt = Inst2; + Inst3_nxt = Inst3; + InstPage2_nxt = InstPage2; + InstPage3_nxt = InstPage3; + + CpuState_nxt = CpuState; + + case (CpuState) + CPUSTATE_RESET: + begin + addr_nxt = 16'HFFFF; + a_nxt = 0; + b_nxt = 0; + x_nxt = 0; + y_nxt = 0; + s_nxt = 16'HFFFD; // Take care about removing the reset of S. There's logic depending on the delta between s and s_nxt to clear NMIMask. + u_nxt = 0; + cc_nxt = CC_F | CC_I; // reset disables interrupts + dp_nxt = 0; + ea_nxt = 16'HFFFF; + + RnWOut = 1; // read + rLIC = 1'b0; // Instruction incomplete + NMIClear_nxt= 1'b0; + IntType_nxt = 3'b111; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_RESET0; + end + + CPUSTATE_RESET0: + begin + addr_nxt = `RESET_VECTOR; + rBUSY = 1'b1; + pc_nxt[15:8] = D[7:0]; + BS_nxt = 1'b1; // ACK RESET + rAVMA = 1'b1; + rLIC = 1'b1; + CpuState_nxt = CPUSTATE_RESET2; + end + + CPUSTATE_RESET2: + begin + addr_nxt = addr_p1; + BS_nxt = 1'b1; // ACK RESET + pc_nxt[7:0] = D[7:0]; + rAVMA = 1'b1; + rLIC = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + CPUSTATE_FETCH_I1: + begin + if (~DMABREQLatched) + begin + addr_nxt = pc; + RnWOut = 1'b1; + rAVMA = 1'b0; + tmp_nxt = {tmp[15:4], 4'b1111}; + BS_nxt = 1'b1; + BA_nxt = 1'b1; + rLIC = 1'b1; + CpuState_nxt = CPUSTATE_DMABREQ; + end + else if (~HALTLatched) + begin + addr_nxt = pc; + RnWOut = 1'b1; + rAVMA = 1'b0; + BS_nxt = 1'b1; + BA_nxt = 1'b1; + rLIC = 1'b1; + CpuState_nxt = CPUSTATE_HALTED; + end + else // not halting, run the inst byte fetch + begin + addr_nxt = pc; // Set the address bus for the next instruction, first byte + pc_nxt = pc_p1; + RnWOut = 1; // Set for a READ + Inst1_nxt = MappedInstruction; + InstPage2_nxt = 0; + InstPage3_nxt = 0; + + // New instruction fetch; service interrupts pending + if (NMILatched == 0) + begin + pc_nxt = pc; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_NMI_START; + end + else if ((FIRQLatched == 0) && (cc[CC_F_BIT] == 0)) + begin + pc_nxt = pc; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FIRQ_START; + end + else if ((IRQLatched == 0) && (cc[CC_I_BIT] == 0)) + begin + pc_nxt = pc; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_IRQ_START; + end + + // The actual 1st byte checks + else if (Inst1_nxt == 8'H10) // Page 2 Note, like the 6809, $10 $10 $10 $10 has the same effect as a single $10. + begin + InstPage2_nxt = 1; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1V2; + end + else if (Inst1_nxt == 8'H11) // Page 3 + begin + InstPage3_nxt = 1; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1V2; + end + else + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I2; + end + end // if not halting + end + + CPUSTATE_FETCH_I1V2: + begin + addr_nxt = pc; // Set the address bus for the next instruction, first byte + pc_nxt = pc_p1; + RnWOut = 1; // Set for a READ + Inst1_nxt = MappedInstruction; + + if (Inst1_nxt == 8'H10) // Page 2 Note, like the 6809, $10 $10 $10 $10 has the same effect as a single $10. + begin + if (InstPage3 == 0) // $11 $11 $11 $11 ... $11 $10 still = Page 3 + InstPage2_nxt = 1; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1V2; + end + else if (Inst1_nxt == 8'H11) // Page 3 + begin + if (InstPage2 == 0) // $10 $10 ... $10 $11 still = Page 2 + InstPage3_nxt = 1; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1V2; + end + else + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I2; + end + end + + + CPUSTATE_FETCH_I2: // We've fetched the first byte. If a $10 or $11 (page select), mark those flags and fetch the next byte as instruction byte 1. + begin + addr_nxt = addr_p1; // Address bus++ + pc_nxt = pc_p1; + Inst2_nxt = D[7:0]; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + + if (IsIllegalInstruction) // Skip illegal instructions + begin + + rAVMA = 1'b1; + CpuState_nxt = IllegalInstructionState; + rLIC = 1'b1; + end + else + begin + // First byte Decode for this stage + case (AddrModeType) + TYPE_INDEXED: + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_INDEXED_BASE; + end + + + TYPE_EXTENDED: + begin + ea_nxt[15:8] = Inst2_nxt; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_EXTENDED_ADDRLO; + end + TYPE_DIRECT: + begin + ea_nxt = {dp, Inst2_nxt}; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_DIRECT_DONTCARE; + end + + TYPE_INHERENT: + begin + if (Inst1 == OPCODE_INH_NOP) + begin + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + else if (Inst1 == OPCODE_INH_DAA) // Bcd lunacy + begin + if ( ((cc[CC_C_BIT]) || (a[7:4] > 4'H9)) || + ((a[7:4] > 4'H8) && (a[3:0] > 4'H9)) ) + tmp_nxt[7:4] = 4'H6; + else + tmp_nxt[7:4] = 4'H0; + + if ((cc[CC_H_BIT]) || (a[3:0] > 4'H9)) + tmp_nxt[3:0] = 4'H6; + else + tmp_nxt[3:0] = 4'H0; + + // DAA handles carry in the weirdest way. + // If it's already set, it remains set, even if carry-out is 0. + // If it wasn't set, but the output of the operation is set, carry-out gets set. + {tmp_nxt[8], a_nxt} = {1'b0, a} + tmp_nxt[7:0]; + + cc_nxt[CC_C_BIT] = cc_nxt[CC_C_BIT] | tmp_nxt[8]; + + cc_nxt[CC_N_BIT] = a_nxt[7]; + cc_nxt[CC_Z_BIT] = (a_nxt == 8'H00); + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + else if (Inst1 == OPCODE_INH_SYNC) + begin + CpuState_nxt = CPUSTATE_SYNC; + rLIC = 1'b1; + rAVMA = 1'b0; + end + else if (Inst1 == OPCODE_INH_MUL) + begin + tmp_nxt = 16'H0000; + ea_nxt[15:8] = 8'H00; + ea_nxt[7:0] = a; + a_nxt = 8; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_MUL_ACTION; + end + else if (Inst1 == OPCODE_INH_RTS) + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_RTS_HI; + end + else if (Inst1 == OPCODE_INH_RTI) + begin + rAVMA = 1'b1; + tmp_nxt = 16'H1001; // Set tmp[12] to indicate an RTI being processed, and at least pull CC. + CpuState_nxt = CPUSTATE_PUL_ACTION; + NextState_nxt = CPUSTATE_FETCH_I1; + end + else if (Inst1 == OPCODE_INH_SWI) + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_SWI_START; + end + else if (Inst1 == OPCODE_INH_CWAI) + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_CWAI; + end + else if (Inst1 == OPCODE_INH_SEX) + begin + a_nxt = {8{b[7]}}; + cc_nxt[CC_N_BIT] = b[7]; + cc_nxt[CC_Z_BIT] = {b == 8'H00}; + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + else if (Inst1 == OPCODE_INH_ABX) + begin + x_nxt = x + b; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_ABX_DONTCARE; + end + else + begin + ALU_OP = ALU8Op; + if (IsTargetRegA) + ALU_A = a; + else + ALU_A = b; + + ALU_B = 0; + ALU_CC = cc; + cc_nxt = ALU[15:8]; + + if (ALU8Writeback) + begin + if (IsTargetRegA) + a_nxt = ALU[7:0]; + else + b_nxt = ALU[7:0]; + end + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + if (IsOneByteInstruction(Inst1)) // This check is probably superfluous. Every inherent instruction is 1 byte on the 6809. + pc_nxt = pc; // The 6809 auto-reads 2 bytes for every instruction. :( Adjust by not incrementing PC on the 2nd byte read. + end + + TYPE_IMMEDIATE: + begin + if (IsSpecialImmediate) + begin + if (Inst1 == OPCODE_IMM_ANDCC) + begin + pc_nxt = pc_p1; + cc_nxt = cc & D; //cc_nxt & Inst2_nxt; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_CC_DONTCARE; + end + else if (Inst1 == OPCODE_IMM_ORCC) + begin + pc_nxt = pc_p1; + cc_nxt = cc | D; //cc_nxt | Inst2_nxt; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_CC_DONTCARE; + end + else if ( (Inst1 == OPCODE_IMM_PSHS) | (Inst1 == OPCODE_IMM_PSHU) ) + begin + pc_nxt = pc_p1; + tmp_nxt[15] = 1'b0; + tmp_nxt[14] = Inst1[1]; // Mark whether to save to U or S. + tmp_nxt[13] = 1'b0; // Not pushing due to an interrupt. + tmp_nxt[13:8] = 6'H00; + tmp_nxt[7:0] = Inst2_nxt; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_PSH_DONTCARE1; + NextState_nxt = CPUSTATE_FETCH_I1; + end + else if ( (Inst1 == OPCODE_IMM_PULS) | (Inst1 == OPCODE_IMM_PULU) ) + begin + pc_nxt = pc_p1; + tmp_nxt[15] = 1'b0; + tmp_nxt[14] = Inst1[1]; // S (0) or U (1) stack in use. + tmp_nxt[13:8] = 6'H00; + tmp_nxt[7:0] = Inst2_nxt; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_PUL_DONTCARE1; + NextState_nxt = CPUSTATE_FETCH_I1; + end + else if (Inst1 == OPCODE_IMM_TFR) + begin + // The second byte lists the registers; Top nybble is reg #1, bottom is reg #2. + + case (Inst2_nxt[3:0]) + EXGTFR_REG_D: + {a_nxt,b_nxt} = EXGTFRRegA; + EXGTFR_REG_X: + x_nxt = EXGTFRRegA; + EXGTFR_REG_Y: + y_nxt = EXGTFRRegA; + EXGTFR_REG_U: + u_nxt = EXGTFRRegA; + EXGTFR_REG_S: + s_nxt = EXGTFRRegA; + EXGTFR_REG_PC: + pc_nxt = EXGTFRRegA; + EXGTFR_REG_DP: + dp_nxt = EXGTFRRegA[7:0]; + EXGTFR_REG_A: + a_nxt = EXGTFRRegA[7:0]; + EXGTFR_REG_B: + b_nxt = EXGTFRRegA[7:0]; + EXGTFR_REG_CC: + cc_nxt = EXGTFRRegA[7:0]; + default: + begin + end + endcase + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_TFR_DONTCARE1; + + end + else if (Inst1 == OPCODE_IMM_EXG) + begin + // The second byte lists the registers; Top nybble is reg #1, bottom is reg #2. + + case (Inst2_nxt[7:4]) + EXGTFR_REG_D: + {a_nxt,b_nxt} = EXGTFRRegB; + EXGTFR_REG_X: + x_nxt = EXGTFRRegB; + EXGTFR_REG_Y: + y_nxt = EXGTFRRegB; + EXGTFR_REG_U: + u_nxt = EXGTFRRegB; + EXGTFR_REG_S: + s_nxt = EXGTFRRegB; + EXGTFR_REG_PC: + pc_nxt = EXGTFRRegB; + EXGTFR_REG_DP: + dp_nxt = EXGTFRRegB[7:0]; + EXGTFR_REG_A: + a_nxt = EXGTFRRegB[7:0]; + EXGTFR_REG_B: + b_nxt = EXGTFRRegB[7:0]; + EXGTFR_REG_CC: + cc_nxt = EXGTFRRegB[7:0]; + default: + begin + end + endcase + case (Inst2_nxt[3:0]) + EXGTFR_REG_D: + {a_nxt,b_nxt} = EXGTFRRegA; + EXGTFR_REG_X: + x_nxt = EXGTFRRegA; + EXGTFR_REG_Y: + y_nxt = EXGTFRRegA; + EXGTFR_REG_U: + u_nxt = EXGTFRRegA; + EXGTFR_REG_S: + s_nxt = EXGTFRRegA; + EXGTFR_REG_PC: + pc_nxt = EXGTFRRegA; + EXGTFR_REG_DP: + dp_nxt = EXGTFRRegA[7:0]; + EXGTFR_REG_A: + a_nxt = EXGTFRRegA[7:0]; + EXGTFR_REG_B: + b_nxt = EXGTFRRegA[7:0]; + EXGTFR_REG_CC: + cc_nxt = EXGTFRRegA[7:0]; + default: + begin + end + endcase + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_EXG_DONTCARE1; + end + end + // Determine if this is an 8-bit ALU operation. + else if (Is8BitInst) + begin + ALU_OP = ALU8Op; + if (IsTargetRegA) + ALU_A = a; + else + ALU_A = b; + + ALU_B = Inst2_nxt; + ALU_CC = cc; + cc_nxt = ALU[15:8]; + + if (ALU8Writeback) + begin + if (IsTargetRegA) + a_nxt = ALU[7:0]; + else + b_nxt = ALU[7:0]; + end + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + else // Then it must be a 16 bit instruction + begin + // 83 SUBD + // 8C CMPX + // 8E LDX + // C3 ADDD + // CC LDD + // CE LDU + // 108E CMPD + // 108C CMPY + // 108E LDY + // 10CE LDS + // 1183 CMPU + // 118C CMPS + // Wow, they were just stuffing them in willy-nilly ... + + // LD* 16 bit immediate + if (IsALU16Opcode) + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_16IMM_LO; + end + // there's a dead zone here; I need an else to take us back to CPUSTATE_FETCHI1 if we want to ignore illegal instructions, to CPUSTATE_DEAD if we want to catch them. + + end + + end + + TYPE_RELATIVE: + begin + // Is this a LB** or a B**? + // If InstPage2 is set, it's a long branch; if clear, a normal branch. + if ( (InstPage2) || (Inst1 == INST_LBRA) || (Inst1 == INST_LBSR) ) + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_LBRA_OFFSETLOW; + end + else + begin + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_BRA_DONTCARE; + end + + end + default: + begin + CpuState_nxt = CPUSTATE_FETCH_I1; + end + endcase + end + end + + + CPUSTATE_LBRA_OFFSETLOW: + begin + addr_nxt = pc; + pc_nxt = pc_p1; + Inst3_nxt = D[7:0]; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_LBRA_DONTCARE; + end + + CPUSTATE_LBRA_DONTCARE: + begin + addr_nxt = 16'HFFFF; + if ( TakeBranch ) + begin + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_LBRA_DONTCARE2; + end + else + begin + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + end + + CPUSTATE_BRA_DONTCARE: + begin + addr_nxt = 16'HFFFF; + tmp_nxt = pc; + if (TakeBranch) + begin + pc_nxt = pc + { {8{Inst2[7]}}, Inst2[7:0]}; // Sign-extend the 8 bit offset to 16. + + if (Inst1 == INST_BSR) + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_BSR_DONTCARE1; + end + else + begin + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + end + else + begin + rLIC = 1'b1; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + end + + CPUSTATE_LBRA_DONTCARE2: + begin + tmp_nxt= pc; + addr_nxt = 16'HFFFF; + + // Take branch + pc_nxt = pc + {Inst2[7:0], Inst3[7:0]}; + if (Inst1 == INST_LBSR) + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_BSR_DONTCARE1; + end + else + begin + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + end + + CPUSTATE_BSR_DONTCARE1: + begin + addr_nxt = pc; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_BSR_DONTCARE2; + end + + CPUSTATE_BSR_DONTCARE2: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_BSR_RETURNLOW; + end + + CPUSTATE_BSR_RETURNLOW: + begin + addr_nxt = s_m1; + s_nxt = s_m1; + DOutput[7:0] = tmp[7:0]; + RnWOut = 0; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_BSR_RETURNHIGH; + end + + CPUSTATE_BSR_RETURNHIGH: + begin + addr_nxt = s_m1; + s_nxt = s_m1; + DOutput[7:0] = tmp[15:8]; + RnWOut = 0; + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; // after this, RnWOut must go to 1, and the bus needs the PC placed on it. + end + + CPUSTATE_TFR_DONTCARE1: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_TFR_DONTCARE2; + end + + CPUSTATE_TFR_DONTCARE2: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_TFR_DONTCARE3; + end + + CPUSTATE_TFR_DONTCARE3: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_TFR_DONTCARE4; + end + + CPUSTATE_TFR_DONTCARE4: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b1; + rLIC = 1'b1; // Instruction done! + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + CPUSTATE_EXG_DONTCARE1: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_EXG_DONTCARE2; + end + + CPUSTATE_EXG_DONTCARE2: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_EXG_DONTCARE3; + end + + CPUSTATE_EXG_DONTCARE3: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_EXG_DONTCARE4; + end + + CPUSTATE_EXG_DONTCARE4: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_EXG_DONTCARE5; + end + + CPUSTATE_EXG_DONTCARE5: + begin + rAVMA = 1'b0; + addr_nxt = 16'HFFFF; + CpuState_nxt = CPUSTATE_EXG_DONTCARE6; + end + + CPUSTATE_EXG_DONTCARE6: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b1; + rLIC = 1'b1; // Instruction done! + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + CPUSTATE_ABX_DONTCARE: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b1; + rLIC = 1'b1; // Instruction done! + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + CPUSTATE_RTS_HI: + begin + addr_nxt = s; + s_nxt = s_p1; + pc_nxt[15:8] = D[7:0]; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_RTS_LO; + end + + CPUSTATE_RTS_LO: + begin + addr_nxt = s; + s_nxt = s_p1; + pc_nxt[7:0] = D[7:0]; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_RTS_DONTCARE2; + end + + CPUSTATE_RTS_DONTCARE2: + begin + addr_nxt = 16'HFFFF; + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + CPUSTATE_16IMM_LO: + begin + addr_nxt = pc; + pc_nxt = pc_p1; + + ALU16_OP = ALU16Opcode; + ALU16_CC = cc; + ALU16_B = {Inst2, D[7:0]}; + + case (ALU16Reg) + ALU16_REG_X: + ALU16_A = x; + ALU16_REG_D: + ALU16_A = {a, b}; + ALU16_REG_Y: + ALU16_A = y; + ALU16_REG_U: + ALU16_A = u; + ALU16_REG_S: + ALU16_A = s; + default: + ALU16_A = 16'H0; + endcase + + if (ALU16OpWriteback) + begin + case (ALU16Reg) + ALU16_REG_X: + {cc_nxt, x_nxt} = ALU16; + ALU16_REG_D: + {cc_nxt, a_nxt, b_nxt} = ALU16; + ALU16_REG_Y: + {cc_nxt, y_nxt} = ALU16; + ALU16_REG_U: + {cc_nxt, u_nxt} = ALU16; + ALU16_REG_S: + {cc_nxt, s_nxt} = ALU16; + default: + begin + end + endcase + end + else + cc_nxt = ALU16[23:16]; + + if (ALU16_OP == ALUOP16_LD) + begin + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + else + begin + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_16IMM_DONTCARE; + end + end + + CPUSTATE_DIRECT_DONTCARE: + begin + addr_nxt = 16'HFFFF; + + if (IsJMP(Inst1)) + begin + pc_nxt = ea; + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + else + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_ALU_EA; + end + end + + CPUSTATE_ALU_EA: + begin + + // Is Figure 18/5 Column 2? JMP (not Immediate Mode) + // This actually isn't done here. All checks passing in to ALU_EA should check for a JMP; FIXME EVERYWHERE + + // Is Figure 18/5 Column 8? TST (not immediate mode) + // THIS IS BURIED IN THE COLUMN 3 section with comparisons to ALUOP_TST. + + // Is Figure 18/5 Column 3? + if (IsALU8Set1(Inst1)) + begin + addr_nxt = ea; + + ALU_OP = ALU8Op; + ALU_B = D[7:0]; + ALU_CC = cc; + + if (IsTargetRegA) + ALU_A = a; + else + ALU_A = b; + + cc_nxt = ALU[15:8]; + + if ( (ALU8Writeback) ) + begin + if (IsTargetRegA) + a_nxt = ALU[7:0]; + else + b_nxt = ALU[7:0]; + end + + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + // Is Figure 18/5 Column 4? (Store, 8 bits) + else if (IsStore8) + begin + addr_nxt = ea; + RnWOut = 0; // write + + ALU_OP = ALUOP_LD; // load has the same CC characteristics as store + ALU_A = 8'H00; + ALU_CC = cc; + + case (Store8RegisterNum) + ST8_REG_A: + begin + DOutput = a; + ALU_B = a; + end + ST8_REG_B: + begin + DOutput = b; + ALU_B = b; + end + + + endcase + + cc_nxt = ALU[15:8]; + + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + // Is Figure 18/5 Column 5? (Load, 16 bits) + else if (IsALU16Opcode & (ALU16Opcode == ALUOP16_LD)) + begin + addr_nxt = ea; + ea_nxt = ea_p1; + + case (ALU16Reg) + ALU16_REG_X: + x_nxt[15:8] = D[7:0]; + ALU16_REG_D: + a_nxt = D[7:0]; + ALU16_REG_Y: + y_nxt[15:8] = D[7:0]; + ALU16_REG_S: + s_nxt[15:8] = D[7:0]; + ALU16_REG_U: + u_nxt[15:8] = D[7:0]; + default: + begin + end + endcase + rAVMA = 1'b1; + rBUSY = 1'b1; + CpuState_nxt = CPUSTATE_LD16_LO; + + end + + // Is Figure 18/5 Column 6? (Store, 16 bits) + else if (IsStore16) + begin + addr_nxt = ea; + ea_nxt = ea_p1; + + ALU16_OP = ALUOP16_LD; // LD and ST have the same CC characteristics + ALU16_CC = cc; + ALU16_A = 8'H00; + + case (StoreRegisterNum) + ST16_REG_X: + begin + DOutput[7:0] = x[15:8]; + ALU16_B = x; + end + ST16_REG_Y: + begin + DOutput[7:0] = y[15:8]; + ALU16_B = y; + end + ST16_REG_U: + begin + DOutput[7:0] = u[15:8]; + ALU16_B = u; + end + ST16_REG_S: + begin + DOutput[7:0] = s[15:8]; + ALU16_B = s; + end + ST16_REG_D: + begin + DOutput[7:0] = a[7:0]; + ALU16_B = {a,b}; + end + default: + begin + end + endcase + + cc_nxt = ALU16[23:16]; + + RnWOut = 0; // Write + rAVMA = 1'b1; + rBUSY = 1'b1; + CpuState_nxt = CPUSTATE_ST16_LO; + end + + // Is Figure 18/5 Column 7? + else if (IsALU8Set0(Inst1)) + begin + // These are registerless instructions, ala + // ASL, ASR, CLR, COM, DEC, INC, (LSL), LSR, NEG, ROL, ROR + // and TST (special!) + // They require READ, Modify (the operation above), WRITE. Between the Read and the Write cycles, there's actually a /VMA + // cycle where the 6809 likely did the operation. We'll include a /VMA cycle for accuracy, but we'll do the work primarily in the first cycle. + addr_nxt = ea; + + ALU_OP = ALU8Op; + ALU_A = D[7:0]; + ALU_CC = cc; + tmp_nxt[15:8] = cc; // for debug only + tmp_nxt[7:0] = ALU[7:0]; + cc_nxt = ALU[15:8]; + if (ALU8Op == ALUOP_TST) + begin + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_TST_DONTCARE1; + end + else + begin + rAVMA = 1'b0; + rBUSY = 1'b1; + CpuState_nxt = CPUSTATE_ALU_DONTCARE; + end + + end + + // Is Figure 18/5 Column 8? TST + // NOTE: + // THIS IS BURIED IN THE COLUMN 3 section with comparisons to ALUOP_TST. [Directly above.] + + + // Is Figure 18/5 Column 9? (16-bit ALU ops, non-load) + else if (IsALU16Opcode && (ALU16Opcode != ALUOP16_LD) && ((Inst1 < 8'H30) || (Inst1 > 8'H33)) ) // 30-33 = LEAX, LEAY, LEAS, LEAU; don't include them here. + begin + addr_nxt = ea; + ea_nxt = ea_p1; + + tmp_nxt[15:8] = D[7:0]; + rAVMA = 1'b1; + rBUSY = 1'b1; + CpuState_nxt = CPUSTATE_ALU16_LO; + + end + + // Is Figure 18/5 Column 10? JSR (not Immediate Mode) + else if ((Inst1 == 8'H9D) || (Inst1 == 8'HAD) || (Inst1 == 8'HBD)) // JSR + begin + pc_nxt = ea; + addr_nxt = ea; + tmp_nxt = pc; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_JSR_DONTCARE; + end + // Is Figure 18/5 Column 11? LEA(X,Y,S,U) + else if ((Inst1 >= 8'H30) && (Inst1<= 8'H33)) + begin + addr_nxt = 16'HFFFF; // Ack, actually a valid cycle, this isn't a dontcare (/VMA) cycle! + + ALU16_OP = ALU16Opcode; + ALU16_CC = cc; + ALU16_A = ea; + + case (ALU16Reg) + ALU16_REG_X: + {cc_nxt, x_nxt} = ALU16; + ALU16_REG_Y: + {cc_nxt, y_nxt} = ALU16; + ALU16_REG_U: + u_nxt = ALU16[15:0]; + ALU16_REG_S: + s_nxt = ALU16[15:0]; + default: + begin + end + endcase + + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + + end + + end + + + CPUSTATE_ALU_DONTCARE: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b1; + rBUSY = 1'b1; // We do nothing here, but on the real 6809, they did the modify phase here. :| + CpuState_nxt = CPUSTATE_ALU_WRITEBACK; + end + + CPUSTATE_ALU_WRITEBACK: + begin + addr_nxt = ea; + RnWOut = 0; // Write + DOutput = tmp[7:0]; + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + CPUSTATE_LD16_LO: + begin + addr_nxt = ea; + + case (ALU16Reg) + ALU16_REG_X: + begin + x_nxt[7:0] = D[7:0]; + ALU16_B[15:8] = x[15:8]; + end + ALU16_REG_D: + begin + b_nxt = D[7:0]; + ALU16_B[15:8] = a; + end + ALU16_REG_Y: + begin + y_nxt[7:0] = D[7:0]; + ALU16_B[15:8] = y[15:8]; + end + ALU16_REG_S: + begin + s_nxt[7:0] = D[7:0]; + ALU16_B[15:8] = s[15:8]; + end + ALU16_REG_U: + begin + u_nxt[7:0] = D[7:0]; + ALU16_B[15:8] = u[15:8]; + end + default: + begin + end + + endcase + + ALU16_OP = ALU16Opcode; + ALU16_CC = cc; + ALU16_A = 8'H00; + ALU16_B[7:0] = D[7:0]; + cc_nxt = ALU16[23:16]; + + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + CPUSTATE_ST16_LO: + begin + addr_nxt = ea; + ea_nxt = ea_p1; + case (StoreRegisterNum) + ST16_REG_X: + DOutput[7:0] = x[7:0]; + ST16_REG_Y: + DOutput[7:0] = y[7:0]; + ST16_REG_U: + DOutput[7:0] = u[7:0]; + ST16_REG_S: + DOutput[7:0] = s[7:0]; + ST16_REG_D: + DOutput[7:0] = b[7:0]; + default: + begin + end + endcase + RnWOut = 0; // write + + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + CPUSTATE_ALU16_LO: + begin + addr_nxt = ea; + + ALU16_OP = ALU16Opcode; + ALU16_CC = cc; + + ALU16_B = {tmp[15:8], D[7:0]}; + + case (ALU16Reg) + ALU16_REG_X: + ALU16_A = x; + ALU16_REG_D: + ALU16_A = {a, b}; + ALU16_REG_Y: + ALU16_A = y; + ALU16_REG_S: + ALU16_A = s; + ALU16_REG_U: + ALU16_A = u; + default: + ALU16_A = 16'H0; + + endcase + + if (ALU16OpWriteback) + begin + case (ALU16Reg) + ALU16_REG_X: + {cc_nxt, x_nxt} = ALU16; + ALU16_REG_D: + {cc_nxt, a_nxt, b_nxt} = ALU16; + ALU16_REG_Y: + {cc_nxt, y_nxt} = ALU16; + ALU16_REG_U: + {cc_nxt, u_nxt} = ALU16; + ALU16_REG_S: + {cc_nxt, s_nxt} = ALU16; + default: + begin + end + endcase + end + else + cc_nxt = ALU16[23:16]; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_ALU16_DONTCARE; + end + + CPUSTATE_ALU16_DONTCARE: + begin + addr_nxt = 16'HFFFF; + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + + CPUSTATE_JSR_DONTCARE: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_JSR_RETLO; + end + + CPUSTATE_JSR_RETLO: + begin + addr_nxt = s_m1; + s_nxt = s_m1; + RnWOut = 0; + DOutput = tmp[7:0]; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_JSR_RETHI; + end + + CPUSTATE_JSR_RETHI: + begin + addr_nxt = s_m1; + s_nxt = s_m1; + RnWOut = 0; + DOutput = tmp[15:8]; + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + CPUSTATE_EXTENDED_ADDRLO: + begin + addr_nxt = pc; + pc_nxt = pc_p1; + ea_nxt[7:0] = D[7:0]; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_EXTENDED_DONTCARE; + end + + CPUSTATE_EXTENDED_DONTCARE: + begin + addr_nxt = 16'HFFFF; + if (IsJMP(Inst1)) + begin + pc_nxt = ea; + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + else + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_ALU_EA; + end + end + + CPUSTATE_INDEXED_BASE: + begin + addr_nxt = pc; + + Inst3_nxt = D[7:0]; + + case (IndexedRegister) + IDX_REG_X: + ALU16_A = x; + IDX_REG_Y: + ALU16_A = y; + IDX_REG_U: + ALU16_A = u; + IDX_REG_S: + ALU16_A = s; + IDX_REG_PC: + ALU16_A = pc_p1; + default: + ALU16_A = 16'H0; + endcase + ALU16_OP = ALUOP16_ADD; + + case (IndexedMode) + IDX_MODE_NOOFFSET: + begin + case (IndexedRegister) + IDX_REG_X: + ea_nxt = x; + IDX_REG_Y: + ea_nxt = y; + IDX_REG_U: + ea_nxt = u; + IDX_REG_S: + ea_nxt = s; + default: + ea_nxt = 16'H0; + endcase + + if (IndexedIndirect) + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_INDIRECT_HI; + end + else + begin + if (IsJMP(Inst1)) + begin + pc_nxt = ea_nxt; + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + else + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_ALU_EA; + end + end + end + + IDX_MODE_5BIT_OFFSET: + begin + // The offset is the bottom 5 bits of the Index Postbyte, which is Inst2 here. + // We'll sign-extend it to 16 bits. + ALU16_B = { {11{Inst2[4]}}, Inst2[4:0] }; + ea_nxt = ALU16[15:0]; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_IDX_DONTCARE3; + end + + + IDX_MODE_8BIT_OFFSET_PC: + begin + ALU16_B = { {8{D[7]}}, D[7:0] }; + pc_nxt = pc_p1; + ea_nxt = ALU16[15:0]; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_IDX_DONTCARE3; + end + + IDX_MODE_8BIT_OFFSET: + begin + ALU16_B = { {8{D[7]}}, D[7:0] }; + pc_nxt = pc_p1; + ea_nxt = ALU16[15:0]; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_IDX_DONTCARE3; + end + + IDX_MODE_A_OFFSET: + begin + ALU16_B = { {8{a[7]}}, a[7:0] }; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_IDX_DONTCARE3; + ea_nxt = ALU16[15:0]; + end + + IDX_MODE_B_OFFSET: + begin + ALU16_B = { {8{b[7]}}, b[7:0] }; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_IDX_DONTCARE3; + ea_nxt = ALU16[15:0]; + end + + IDX_MODE_D_OFFSET: + begin + ALU16_B = {a, b}; + + ea_nxt = ALU16[15:0]; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_IDX_DOFF_DONTCARE1; + end + + IDX_MODE_POSTINC1: + begin + ALU16_B = 16'H1; + ea_nxt = ALU16_A; + case (IndexedRegister) + IDX_REG_X: + x_nxt = ALU16[15:0]; + IDX_REG_Y: + y_nxt = ALU16[15:0]; + IDX_REG_U: + u_nxt = ALU16[15:0]; + IDX_REG_S: + s_nxt = ALU16[15:0]; + default: + begin + end + endcase + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE2; + end + + IDX_MODE_POSTINC2: + begin + ALU16_B = 16'H2; + ea_nxt = ALU16_A; + case (IndexedRegister) + IDX_REG_X: + x_nxt = ALU16[15:0]; + IDX_REG_Y: + y_nxt = ALU16[15:0]; + IDX_REG_U: + u_nxt = ALU16[15:0]; + IDX_REG_S: + s_nxt = ALU16[15:0]; + default: + begin + end + endcase + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE0; + end + + IDX_MODE_PREDEC1: + begin + ALU16_B = 16'HFFFF; // -1 + case (IndexedRegister) + IDX_REG_X: + x_nxt = ALU16[15:0]; + IDX_REG_Y: + y_nxt = ALU16[15:0]; + IDX_REG_U: + u_nxt = ALU16[15:0]; + IDX_REG_S: + s_nxt = ALU16[15:0]; + default: + begin + end + endcase + ea_nxt = ALU16[15:0]; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE2; + end + + IDX_MODE_PREDEC2: + begin + ALU16_B = 16'HFFFE; // -2 + case (IndexedRegister) + IDX_REG_X: + x_nxt = ALU16[15:0]; + IDX_REG_Y: + y_nxt = ALU16[15:0]; + IDX_REG_U: + u_nxt = ALU16[15:0]; + IDX_REG_S: + s_nxt = ALU16[15:0]; + default: + begin + end + endcase + ea_nxt = ALU16[15:0]; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE0; + end + + IDX_MODE_16BIT_OFFSET_PC: + begin + tmp_nxt[15:8] = D[7:0]; + pc_nxt = pc_p1; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_IDX_16OFFSET_LO; + end + + IDX_MODE_16BIT_OFFSET: + begin + tmp_nxt[15:8] = D[7:0]; + pc_nxt = pc_p1; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_IDX_16OFFSET_LO; + end + + IDX_MODE_EXTENDED_INDIRECT: + begin + ea_nxt[15:8] = D[7:0]; + pc_nxt = pc_p1; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_IDX_EXTIND_LO; + end + + default: + begin + rLIC = 1'b1; + CpuState_nxt = PostIllegalState; + end + + endcase + end + + CPUSTATE_IDX_OFFSET_LO: + begin + tmp_nxt[7:0] = D[7:0]; + addr_nxt = pc; + pc_nxt = pc_p1; + ALU16_B = tmp_nxt; + + case (IndexedRegister) + IDX_REG_X: + ALU16_A = x; + IDX_REG_Y: + ALU16_A = y; + IDX_REG_U: + ALU16_A = u; + IDX_REG_S: + ALU16_A = s; + IDX_REG_PC: + ALU16_A = pc; + default: + ALU16_A = 16'H0; + endcase + ALU16_OP = ALUOP16_ADD; + + ea_nxt = ALU16[15:0]; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE1; + end + + + CPUSTATE_IDX_DONTCARE3: + begin + addr_nxt = 16'HFFFF; + if (IndexedIndirect) + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_INDIRECT_HI; + end + else + begin + if (IsJMP(Inst1)) + begin + pc_nxt = ea; + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + else + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_ALU_EA; + end + end + + end + + CPUSTATE_IDX_16OFFSET_LO: + begin + addr_nxt = pc; + pc_nxt = pc_p1; + + case (IndexedRegister) + IDX_REG_X: + ALU16_A = x; + IDX_REG_Y: + ALU16_A = y; + IDX_REG_U: + ALU16_A = u; + IDX_REG_S: + ALU16_A = s; + IDX_REG_PC: + ALU16_A = pc_nxt; // Whups; tricky; not part of the actual pattern + default: + ALU16_A = x; // Default to something + endcase + + ALU16_OP = ALUOP16_ADD; + + ALU16_B = {tmp[15:8], D[7:0]}; + + ea_nxt = ALU16[15:0]; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE1; + end + + CPUSTATE_IDX_16OFF_DONTCARE1: + begin + addr_nxt = pc; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE2; + end + + CPUSTATE_IDX_16OFF_DONTCARE0: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE2; + end + + CPUSTATE_IDX_16OFF_DONTCARE2: + begin + addr_nxt = 16'HFFFF; + if (IndexedRegister == IDX_REG_PC) + begin + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_IDX_PC16OFF_DONTCARE; + end + else + begin + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE3; + end + end + + CPUSTATE_IDX_PC16OFF_DONTCARE: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE3; + end + + + CPUSTATE_IDX_16OFF_DONTCARE3: + begin + addr_nxt = 16'HFFFF; + if (IndexedIndirect) + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_INDIRECT_HI; + end + else + begin + if (IsJMP(Inst1)) + begin + pc_nxt = ea; + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + else + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_ALU_EA; + end + end + end + + CPUSTATE_IDX_DOFF_DONTCARE1: + begin + addr_nxt = pc_p1; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_IDX_DOFF_DONTCARE2; + end + + CPUSTATE_IDX_DOFF_DONTCARE2: + begin + addr_nxt = pc_p2; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE2; + end + + CPUSTATE_IDX_DOFF_DONTCARE3: + begin + addr_nxt = pc_p3; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_IDX_DOFF_DONTCARE2; + end + + CPUSTATE_IDX_EXTIND_LO: + begin + ea_nxt[7:0] = D[7:0]; + addr_nxt = pc; + pc_nxt = pc_p1; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_IDX_EXTIND_DONTCARE; + end + + CPUSTATE_IDX_EXTIND_DONTCARE: + begin + addr_nxt = pc; + if (IndexedIndirect) + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_INDIRECT_HI; + end + else + begin + if (IsJMP(Inst1)) + begin + pc_nxt = ea; + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + else + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_ALU_EA; + end + end + end + + CPUSTATE_INDIRECT_HI: + begin + addr_nxt = ea; + tmp_nxt[15:8] = D[7:0]; + rAVMA = 1'b1; + rBUSY = 1'b1; + CpuState_nxt = CPUSTATE_INDIRECT_LO; + end + + CPUSTATE_INDIRECT_LO: + begin + addr_nxt = ea_p1; + ea_nxt[15:8] = tmp_nxt[15:8]; + ea_nxt[7:0] = D[7:0]; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_INDIRECT_DONTCARE; + end + + CPUSTATE_INDIRECT_DONTCARE: + begin + addr_nxt = 16'HFFFF; + if (IsJMP(Inst1)) + begin + pc_nxt = ea; + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + else + begin + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_ALU_EA; + end + end + + CPUSTATE_MUL_ACTION: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b0; + // tmp = result + // ea = additor (the shifted multiplicand) + // a = counter + // b is the multiplier (which gets shifted right) + if (a != 8'H00) + begin + if (b[0]) + begin + tmp_nxt = tmp + ea; + end + ea_nxt = {ea[14:0], 1'b0}; + b_nxt = {1'b0, b[7:1]}; + a_nxt = a - 8'H1; + end + else + begin + {a_nxt, b_nxt} = tmp; + + cc_nxt[CC_Z_BIT] = (tmp == 0); + cc_nxt[CC_C_BIT] = tmp[7]; + rLIC = 1'b1; // Instruction done! + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + end + + CPUSTATE_PSH_DONTCARE1: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_PSH_DONTCARE2; + end + + CPUSTATE_PSH_DONTCARE2: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_PSH_DONTCARE3; + end + + CPUSTATE_PSH_DONTCARE3: + begin + addr_nxt = (Inst1[1]) ? u : s; + + CpuState_nxt = CPUSTATE_PSH_ACTION; + end + + CPUSTATE_PSH_ACTION: + begin + rAVMA = 1'b1; + if (tmp[7] & ~(tmp[15])) // PC_LO + begin + addr_nxt = (tmp[14]) ? u_m1 : s_m1; + if (tmp[14]) + u_nxt = u_m1; + else + s_nxt = s_m1; + DOutput = pc[7:0]; + RnWOut = 1'b0; // write + tmp_nxt[15] = 1'b1; + end + else if (tmp[7] & (tmp[15])) // PC_HI + begin + addr_nxt = (tmp[14]) ? u_m1 : s_m1; + if (tmp[14]) + u_nxt = u_m1; + else + s_nxt = s_m1; + DOutput = pc[15:8]; + RnWOut = 1'b0; // write + tmp_nxt[7] = 1'b0; + tmp_nxt[15] = 1'b0; + end + else if (tmp[6] & ~(tmp[15])) // U/S_LO + begin + addr_nxt = (tmp[14]) ? u_m1 : s_m1; + if (tmp[14]) + u_nxt = u_m1; + else + s_nxt = s_m1; + DOutput = (tmp[14]) ? s[7:0] : u[7:0]; + RnWOut = 1'b0; // write + tmp_nxt[15] = 1'b1; + end + else if (tmp[6] & (tmp[15])) // U/S_HI + begin + addr_nxt = (tmp[14]) ? u_m1 : s_m1; + if (tmp[14]) + u_nxt = u_m1; + else + s_nxt = s_m1; + DOutput = (tmp[14]) ? s[15:8] : u[15:8]; + RnWOut = 1'b0; // write + tmp_nxt[6] = 1'b0; + tmp_nxt[15] = 1'b0; + end + else if (tmp[5] & ~(tmp[15])) // Y_LO + begin + addr_nxt = (tmp[14]) ? u_m1 : s_m1; + if (tmp[14]) + u_nxt = u_m1; + else + s_nxt = s_m1; + DOutput = y[7:0]; + RnWOut = 1'b0; // write + tmp_nxt[15] = 1'b1; + end + else if (tmp[5] & (tmp[15])) // Y_HI + begin + addr_nxt = (tmp[14]) ? u_m1 : s_m1; + if (tmp[14]) + u_nxt = u_m1; + else + s_nxt = s_m1; + DOutput = y[15:8]; + RnWOut = 1'b0; // write + tmp_nxt[5] = 1'b0; + tmp_nxt[15] = 1'b0; + end + else if (tmp[4] & ~(tmp[15])) // X_LO + begin + addr_nxt = (tmp[14]) ? u_m1 : s_m1; + if (tmp[14]) + u_nxt = u_m1; + else + s_nxt = s_m1; + DOutput = x[7:0]; + RnWOut = 1'b0; // write + tmp_nxt[15] = 1'b1; + end + else if (tmp[4] & (tmp[15])) // X_HI + begin + addr_nxt = (tmp[14]) ? u_m1 : s_m1; + if (tmp[14]) + u_nxt = u_m1; + else + s_nxt = s_m1; + DOutput = x[15:8]; + RnWOut = 1'b0; // write + tmp_nxt[4] = 1'b0; + tmp_nxt[15] = 1'b0; + end + else if (tmp[3]) // DP + begin + addr_nxt = (tmp[14]) ? u_m1 : s_m1; + if (tmp[14]) + u_nxt = u_m1; + else + s_nxt = s_m1; + DOutput = dp; + RnWOut = 1'b0; // write + tmp_nxt[3] = 1'b0; + end + else if (tmp[2]) // B + begin + addr_nxt = (tmp[14]) ? u_m1 : s_m1; + if (tmp[14]) + u_nxt = u_m1; + else + s_nxt = s_m1; + DOutput = b; + RnWOut = 1'b0; // write + tmp_nxt[2] = 1'b0; + end + else if (tmp[1]) // A + begin + addr_nxt = (tmp[14]) ? u_m1 : s_m1; + if (tmp[14]) + u_nxt = u_m1; + else + s_nxt = s_m1; + DOutput = a; + RnWOut = 1'b0; // write + tmp_nxt[1] = 1'b0; + end + else if (tmp[0]) // CC + begin + addr_nxt = (tmp[14]) ? u_m1 : s_m1; + if (tmp[14]) + u_nxt = u_m1; + else + s_nxt = s_m1; + DOutput = cc; + RnWOut = 1'b0; // write + tmp_nxt[0] = 1'b0; + end + if (tmp[13]) // Then we're pushing for an IRQ, and LIC is supposed to be set. + rLIC = 1'b1; + if (tmp_nxt[7:0] == 8'H00) + begin + if (NextState == CPUSTATE_FETCH_I1) + begin + rAVMA = 1'b1; + rLIC = 1'b1; + end + else + rAVMA = 1'b0; + CpuState_nxt = NextState; + end + end + + CPUSTATE_PUL_DONTCARE1: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_PUL_DONTCARE2; + end + + CPUSTATE_PUL_DONTCARE2: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_PUL_ACTION; + end + + CPUSTATE_PUL_ACTION: + begin + rAVMA = 1'b1; + if (tmp[0]) // CC + begin + addr_nxt = (tmp[14]) ? u : s; + if (tmp[14]) + u_nxt = u_p1; + else + s_nxt = s_p1; + cc_nxt = D[7:0]; + if (tmp[12] == 1'b1) // This pull is from an RTI, the E flag comes from the retrieved CC, and set the tmp_nxt accordingly, indicating what other registers to retrieve + begin + if (D[CC_E_BIT]) + tmp_nxt[7:0] = 8'HFE; // Retrieve all registers (ENTIRE) [CC is already retrieved] + else + tmp_nxt[7:0] = 8'H80; // Retrieve PC and CC [CC is already retrieved] + end + else + tmp_nxt[0] = 1'b0; + end + else if (tmp[1]) // A + begin + addr_nxt = (tmp[14]) ? u : s; + if (tmp[14]) + u_nxt = u_p1; + else + s_nxt = s_p1; + a_nxt = D[7:0]; + tmp_nxt[1] = 1'b0; + end + else if (tmp[2]) // B + begin + addr_nxt = (tmp[14]) ? u : s; + if (tmp[14]) + u_nxt = u_p1; + else + s_nxt = s_p1; + b_nxt = D[7:0]; + tmp_nxt[2] = 1'b0; + end + else if (tmp[3]) // DP + begin + addr_nxt = (tmp[14]) ? u : s; + if (tmp[14]) + u_nxt = u_p1; + else + s_nxt = s_p1; + dp_nxt = D[7:0]; + tmp_nxt[3] = 1'b0; + end + else if (tmp[4] & (~tmp[15])) // X_HI + begin + addr_nxt = (tmp[14]) ? u : s; + if (tmp[14]) + u_nxt = u_p1; + else + s_nxt = s_p1; + x_nxt[15:8] = D[7:0]; + tmp_nxt[15] = 1'b1; + end + else if (tmp[4] & tmp[15]) // X_LO + begin + addr_nxt = (tmp[14]) ? u : s; + if (tmp[14]) + u_nxt = u_p1; + else + s_nxt = s_p1; + x_nxt[7:0] = D[7:0]; + tmp_nxt[4] = 1'b0; + tmp_nxt[15] = 1'b0; + end + else if (tmp[5] & (~tmp[15])) // Y_HI + begin + addr_nxt = (tmp[14]) ? u : s; + if (tmp[14]) + u_nxt = u_p1; + else + s_nxt = s_p1; + y_nxt[15:8] = D[7:0]; + tmp_nxt[15] = 1'b1; + end + else if (tmp[5] & tmp[15]) // Y_LO + begin + addr_nxt = (tmp[14]) ? u : s; + if (tmp[14]) + u_nxt = u_p1; + else + s_nxt = s_p1; + y_nxt[7:0] = D[7:0]; + tmp_nxt[5] = 1'b0; + tmp_nxt[15] = 1'b0; + end + else if (tmp[6] & (~tmp[15])) // U/S_HI + begin + addr_nxt = (tmp[14]) ? u : s; + if (tmp[14]) + u_nxt = u_p1; + else + s_nxt = s_p1; + if (tmp[14]) + s_nxt[15:8] = D[7:0]; + else + u_nxt[15:8] = D[7:0]; + tmp_nxt[15] = 1'b1; + end + else if (tmp[6] & tmp[15]) // U/S_LO + begin + addr_nxt = (tmp[14]) ? u : s; + if (tmp[14]) + u_nxt = u_p1; + else + s_nxt = s_p1; + if (tmp[14]) + s_nxt[7:0] = D[7:0]; + else + u_nxt[7:0] = D[7:0]; + tmp_nxt[6] = 1'b0; + tmp_nxt[15] = 1'b0; + end + else if (tmp[7] & (~tmp[15])) // PC_HI + begin + addr_nxt = (tmp[14]) ? u : s; + if (tmp[14]) + u_nxt = u_p1; + else + s_nxt = s_p1; + pc_nxt[15:8] = D[7:0]; + tmp_nxt[15] = 1'b1; + end + else if (tmp[7] & tmp[15]) // PC_LO + begin + addr_nxt = (tmp[14]) ? u : s; + if (tmp[14]) + u_nxt = u_p1; + else + s_nxt = s_p1; + pc_nxt[7:0] = D[7:0]; + tmp_nxt[7] = 1'b0; + tmp_nxt[15] = 1'b0; + end + else + begin + addr_nxt = (tmp[14]) ? u : s; + if (NextState == CPUSTATE_FETCH_I1) + begin + rAVMA = 1'b1; + rLIC = 1'b1; + end + else + rAVMA = 1'b0; + CpuState_nxt = NextState; + end + end + + CPUSTATE_NMI_START: + begin + NMIClear_nxt = 1'b1; + addr_nxt = pc; + // tmp stands as the bits to push to the stack + tmp_nxt = 16'H20FF; // Save to the S stack, PC, U, Y, X, DP, B, A, CC; set LIC on every push + NextState_nxt = CPUSTATE_IRQ_DONTCARE2; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_IRQ_DONTCARE; + IntType_nxt = INTTYPE_NMI; + cc_nxt[CC_E_BIT] = 1'b1; + end + + CPUSTATE_IRQ_START: + begin + addr_nxt = pc; + tmp_nxt = 16'H20FF; // Save to the S stack, PC, U, Y, X, DP, B, A, CC; set LIC on every push + NextState_nxt = CPUSTATE_IRQ_DONTCARE2; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_IRQ_DONTCARE; + IntType_nxt = INTTYPE_IRQ; + cc_nxt[CC_E_BIT] = 1'b1; + end + + CPUSTATE_FIRQ_START: + begin + addr_nxt = pc; + tmp_nxt = 16'H2081; // Save to the S stack, PC, CC; set LIC on every push + NextState_nxt = CPUSTATE_IRQ_DONTCARE2; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_IRQ_DONTCARE; + IntType_nxt = INTTYPE_FIRQ; + cc_nxt[CC_E_BIT] = 1'b0; + end + + CPUSTATE_SWI_START: + begin + addr_nxt = pc; + tmp_nxt = 16'H00FF; // Save to the S stack, PC, U, Y, X, DP, B, A, CC + + NextState_nxt = CPUSTATE_IRQ_DONTCARE2; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_IRQ_DONTCARE; + if (InstPage3) + IntType_nxt = INTTYPE_SWI3; + if (InstPage2) + IntType_nxt = INTTYPE_SWI2; + else + IntType_nxt = INTTYPE_SWI; + + cc_nxt[CC_E_BIT] = 1'b1; + end + + CPUSTATE_IRQ_DONTCARE: + begin + NMIClear_nxt = 1'b0; + addr_nxt = 16'HFFFF; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_PSH_ACTION; + end + + + CPUSTATE_IRQ_DONTCARE2: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_IRQ_VECTOR_HI; + rLIC = 1'b1; + end + + CPUSTATE_IRQ_VECTOR_HI: + begin + case (IntType) + INTTYPE_NMI: + begin + addr_nxt = `NMI_VECTOR; + BS_nxt = 1'b1; // ACK Interrupt + end + INTTYPE_IRQ: + begin + addr_nxt = `IRQ_VECTOR; + BS_nxt = 1'b1; // ACK Interrupt + end + INTTYPE_SWI: + begin + addr_nxt = `SWI_VECTOR; + end + INTTYPE_FIRQ: + begin + addr_nxt = `FIRQ_VECTOR; + BS_nxt = 1'b1; // ACK Interrupt + end + INTTYPE_SWI2: + begin + addr_nxt = `SWI2_VECTOR; + end + INTTYPE_SWI3: + begin + addr_nxt = `SWI3_VECTOR; + end + default: // make the default an IRQ, even though it really should never happen + begin + addr_nxt = `IRQ_VECTOR; + BS_nxt = 1'b1; // ACK Interrupt + end + endcase + + pc_nxt[15:8] = D[7:0]; + rAVMA = 1'b1; + rBUSY = 1'b1; + rLIC = 1'b1; + CpuState_nxt = CPUSTATE_IRQ_VECTOR_LO; + + + end + + CPUSTATE_IRQ_VECTOR_LO: + begin + case (IntType) + INTTYPE_NMI: + begin + addr_nxt = `NMI_VECTOR+16'H1; + cc_nxt[CC_I_BIT] = 1'b1; + cc_nxt[CC_F_BIT] = 1'b1; + BS_nxt = 1'b1; // ACK Interrupt + end + INTTYPE_IRQ: + begin + addr_nxt = `IRQ_VECTOR+16'H1; + cc_nxt[CC_I_BIT] = 1'b1; + BS_nxt = 1'b1; // ACK Interrupt + end + INTTYPE_SWI: + begin + addr_nxt = `SWI_VECTOR+16'H1; + cc_nxt[CC_F_BIT] = 1'b1; + cc_nxt[CC_I_BIT] = 1'b1; + rLIC = 1'b1; + end + INTTYPE_FIRQ: + begin + addr_nxt = `FIRQ_VECTOR+16'H1; + cc_nxt[CC_F_BIT] = 1'b1; + cc_nxt[CC_I_BIT] = 1'b1; + BS_nxt = 1'b1; // ACK Interrupt + end + INTTYPE_SWI2: + begin + addr_nxt = `SWI2_VECTOR+16'H1; + rLIC = 1'b1; + end + INTTYPE_SWI3: + begin + addr_nxt = `SWI3_VECTOR+16'H1; + rLIC = 1'b1; + end + default: + begin + end + endcase + + pc_nxt[7:0] = D[7:0]; + rAVMA = 1'b1; + rLIC = 1'b1; + CpuState_nxt = CPUSTATE_INT_DONTCARE; + end + + CPUSTATE_INT_DONTCARE: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b1; + rLIC = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + CPUSTATE_CC_DONTCARE: + begin + addr_nxt = pc; + rLIC = 1'b1; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + CPUSTATE_TST_DONTCARE1: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_TST_DONTCARE2; + end + + CPUSTATE_TST_DONTCARE2: + begin + addr_nxt = 16'HFFFF; + rLIC = 1'b1; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + CPUSTATE_DEBUG: + begin + addr_nxt = tmp; + rLIC = 1'b1; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + CPUSTATE_16IMM_DONTCARE: + begin + addr_nxt = 16'HFFFF; + rLIC = 1'b1; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + CPUSTATE_SYNC: + begin + addr_nxt = 16'HFFFF; + BA_nxt = 1'b1; + rLIC = 1'b1; + rAVMA = 1'b0; + + if (~(NMILatched & FIRQLatched & IRQLatched)) + begin + CpuState_nxt = CPUSTATE_SYNC_EXIT; + end + end + + CPUSTATE_SYNC_EXIT: + begin + addr_nxt = 16'HFFFF; + BA_nxt = 1'b1; + rLIC = 1'b1; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + + CPUSTATE_DMABREQ: + begin + rAVMA = 1'b0; + addr_nxt = 16'HFFFF; + BS_nxt = 1'b1; + BA_nxt = 1'b1; + rLIC = 1'b1; + tmp_nxt[3:0] = tmp[3:0] - 1'b1; + if ( (tmp[3:0] == 4'H0) | (DMABREQSample2) ) + begin + CpuState_nxt = CPUSTATE_DMABREQ_EXIT; + end + end + + CPUSTATE_DMABREQ_EXIT: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + CPUSTATE_HALTED: + begin + rAVMA = 1'b0; + addr_nxt = 16'HFFFF; + BS_nxt = 1'b1; + BA_nxt = 1'b1; + rLIC = 1'b1; + if (HALTSample2) + begin + CpuState_nxt = CPUSTATE_HALT_EXIT2; + end + end + + + CPUSTATE_HALT_EXIT2: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_FETCH_I1; + end + + CPUSTATE_STOP: + begin + addr_nxt = 16'HDEAD; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_STOP2; + end + + CPUSTATE_STOP2: + begin + addr_nxt = pc; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_STOP3; + end + + CPUSTATE_STOP3: + begin + addr_nxt = 16'H0000; //{Inst1, Inst2}; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_STOP; + end + + // The otherwise critically useful Figure 18 in the 6809 datasheet contains an error; + // it lists that CWAI has a tri-stated bus while it waits for an interrupt. + // That is not true. SYNC tristates the bus, as do things like /HALT and /DMABREQ. + // CWAI does not. It waits with /VMA cycles on the bus until an interrupt occurs. + // The implementation here fits with the 6809 Programming Manual and other Motorola + // sources, not with that typo in Figure 18. + CPUSTATE_CWAI: + begin + addr_nxt = pc; + cc_nxt = {1'b1, (cc[6:0] & Inst2[6:0])}; // Set E flag, AND CC with CWAI argument + tmp_nxt = 16'H00FF; // Save to the S stack, PC, U, Y, X, DP, B, A, CC + + NextState_nxt = CPUSTATE_CWAI_POST; + rAVMA = 1'b0; + CpuState_nxt = CPUSTATE_CWAI_DONTCARE1; + end + + CPUSTATE_CWAI_DONTCARE1: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b1; + CpuState_nxt = CPUSTATE_PSH_ACTION; + end + + CPUSTATE_CWAI_POST: + begin + addr_nxt = 16'HFFFF; + rAVMA = 1'b0; + + CpuState_nxt = CPUSTATE_CWAI_POST; + + // Wait for an interrupt + if (NMILatched == 0) + begin + rAVMA = 1'b1; + IntType_nxt = INTTYPE_NMI; + cc_nxt[CC_F_BIT] = 1'b1; + cc_nxt[CC_I_BIT] = 1'b1; + CpuState_nxt = CPUSTATE_IRQ_VECTOR_HI; + end + else if ((FIRQLatched == 0) && (cc[CC_F_BIT] == 0)) + begin + rAVMA = 1'b1; + cc_nxt[CC_F_BIT] = 1'b1; + cc_nxt[CC_I_BIT] = 1'b1; + IntType_nxt = INTTYPE_FIRQ; + CpuState_nxt = CPUSTATE_IRQ_VECTOR_HI; + end + else if ((IRQLatched == 0) && (cc[CC_I_BIT] == 0)) + begin + rAVMA = 1'b1; + cc_nxt[CC_I_BIT] = 1'b1; + IntType_nxt = INTTYPE_IRQ; + CpuState_nxt = CPUSTATE_IRQ_VECTOR_HI; + end + end + + default: // Picky darned Verilog. + begin + CpuState_nxt = PostIllegalState; + end + + endcase +end + +endmodule + diff --git a/Arcade_MiST/Konami Gyruss/rtl/custom/gyruss_custom.qip b/Arcade_MiST/Konami Gyruss/rtl/custom/gyruss_custom.qip new file mode 100644 index 00000000..67c0410c --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/custom/gyruss_custom.qip @@ -0,0 +1,7 @@ +set_global_assignment -name SYSTEMVERILOG_FILE rtl/custom/k082.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/custom/k083.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/custom/k501.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/custom/k502.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/custom/k503.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/custom/KONAMI-1/KONAMI1.sv +set_global_assignment -name VERILOG_FILE rtl/custom/KONAMI-1/mc6809isk.v diff --git a/Arcade_MiST/Konami Gyruss/rtl/custom/k082.sv b/Arcade_MiST/Konami Gyruss/rtl/custom/k082.sv new file mode 100644 index 00000000..9dd391f8 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/custom/k082.sv @@ -0,0 +1,168 @@ +//============================================================================ +// +// SystemVerilog implementation of the Konami 082 custom chip, used by +// several Konami arcade PCBs to generate video timings +// 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. +// +//============================================================================ + +//Chip pinout: +/* _____________ + _| |_ +reset |_|1 28|_| VCC + _| |_ +h1 |_|2 27|_| GND + _| |_ +h2 |_|3 26|_| v1 + _| |_ +h4 |_|4 25|_| v2 + _| |_ +h8 |_|5 24|_| v4 + _| |_ +h16 |_|6 23|_| v8 + _| |_ +h32 |_|7 22|_| v16 + _| |_ +h64 |_|8 21|_| v32 + _| |_ +h128 |_|9 20|_| v64 + _| |_ +n_h256 |_|10 19|_| v128 + _| |_ +h256 |_|11 18|_| n_vsync + _| |_ +VCC |_|12 17|_| sync + _| |_ +clk |_|13 16|_| vblk + _| |_ +GND |_|14 15|_| n_vblk + |_____________| + +Note: Pins 12 and 27 may control other features of the 082 - these, if any, have not +been modelled yet. +*/ + +module k082 +( + input reset, //Active low + input clk, + input cen, //Set to 1 if using this code to replace a real 082 + input [3:0] h_center, v_center, //These inputs are additions for screen centering and don't exist on the actual 082 + output n_vsync, sync, + output n_hsync, //Not exposed on the original chip + output reg vblk = 1, + output n_vblk, + output reg vblk_irq_en = 0, //This is an extra output not present on the real 082 to signal when to + //trigger a VBlank IRQ (signal is active high) + output h1, h2, h4, h8, h16, h32, h64, h128, h256, n_h256, + output v1, v2, v4, v8, v16, v32, v64, v128 +); + +//The horizontal and vertical counters are 9 bits wide - delcare them here +reg [8:0] h_cnt = 9'd0; +reg [8:0] v_cnt = 9'd0; + +//Define the range of values the vertical counter will count between based on the additional vertical center signal +//Shift the screen up by 1 line when horizontal centering shifts the screen left +wire [8:0] vcnt_start = 9'd248 - v_center; +wire [8:0] vcnt_end = 9'd511 - v_center; + +//The horizontal and vertical counters behave as follows at every rising edge of the pixel clock: +//-Start at 0, then count to 511 (both counters increment by 1 when the horizontal counter is set to 48) +//-Horizontal counter resets to 128 for a total of 383 horizontal lines +//-Vertical counter resets to 248 for a total of 263 vertical lines (adjustable with added vertical center signal) +//-Vertical counter increments when the horizontal counter equals 176 +//-VBlank is active when the horizontal counter is between 495 - 511 and 248 - 270 +//Model this behavior here +always_ff @(posedge clk or negedge reset) begin + if(!reset) begin + h_cnt <= 9'd0; + v_cnt <= 9'd0; + end + else if(cen) begin + case(h_cnt) + 48: begin + v_cnt <= v_cnt + 9'd1; + h_cnt <= h_cnt + 9'd1; + end + 176: begin + h_cnt <= h_cnt + 9'd1; + case(v_cnt) + 16: begin + vblk <= 0; + v_cnt <= v_cnt + 9'd1; + end + 271: begin + vblk <= 0; + v_cnt <= v_cnt + 9'd1; + end + 495: begin + vblk <= 1; + vblk_irq_en <= 1; + v_cnt <= v_cnt + 9'd1; + end + vcnt_end: v_cnt <= vcnt_start; + default: v_cnt <= v_cnt + 9'd1; + endcase + end + 177: begin + vblk_irq_en <= 0; + h_cnt <= h_cnt + 9'd1; + end + 511: h_cnt <= 9'd128; + default: h_cnt <= h_cnt + 9'd1; + endcase + end +end + +//The Konami 082 has both an active low VBlank and an active high VBlank - generate the active low VBlank by inverting +//the active high VBlank generated in the previous sequential block +assign n_vblk = ~vblk; + +//Generate active low HSync, VSync and composite sync +assign n_hsync = h_center[3] ? ~(h_cnt > (182 - h_center[2:0]) && h_cnt < (215 - h_center[2:0])): + ~(h_cnt > (175 - h_center[2:0]) && h_cnt < (208 - h_center[2:0])); +assign n_vsync = h_center[3] ? ~(v_cnt >= vcnt_start + 9'd1 && v_cnt <= vcnt_start + 9'd9) : ~(v_cnt >= vcnt_start && v_cnt <= vcnt_start + 9'd8); +assign sync = n_hsync ^ n_vsync; + +//Assign the individual horizontal counter bits to their respective outputs (also invert bit 8 of the horizontal counter for H256) +assign h1 = h_cnt[0]; +assign h2 = h_cnt[1]; +assign h4 = h_cnt[2]; +assign h8 = h_cnt[3]; +assign h16 = h_cnt[4]; +assign h32 = h_cnt[5]; +assign h64 = h_cnt[6]; +assign h128 = h_cnt[7]; +assign h256 = ~h_cnt[8]; +assign n_h256 = h_cnt[8]; + +//Assign the individual vertical counter bits to their respective outputs +assign v1 = v_cnt[0]; +assign v2 = v_cnt[1]; +assign v4 = v_cnt[2]; +assign v8 = v_cnt[3]; +assign v16 = v_cnt[4]; +assign v32 = v_cnt[5]; +assign v64 = v_cnt[6]; +assign v128 = v_cnt[7]; + +endmodule diff --git a/Arcade_MiST/Konami Gyruss/rtl/custom/k083.sv b/Arcade_MiST/Konami Gyruss/rtl/custom/k083.sv new file mode 100644 index 00000000..f025b63f --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/custom/k083.sv @@ -0,0 +1,101 @@ +//============================================================================ +// +// SystemVerilog implementation of the Konami 083 custom chip, a custom +// shift register used on many early Konami arcade PCBs for handling graphics +// ROMs +// Copyright (C) 2020, 2021 Ace & ElectronAsh +// +// 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: +/* _____________ + _| |_ +CK |_|1 28|_| VCC + _| |_ +FLIP |_|2 27|_| LOAD + _| |_ +DB1i(4) |_|3 26|_| DB1i(6) + _| |_ +DB1i(0) |_|4 25|_| DB1i(2) + _| |_ +DB0i(4) |_|5 24|_| DB0i(6) + _| |_ +DB0i(6) |_|6 23|_| DB0i(2) + _| |_ +DB1i(5) |_|7 22|_| DB1i(7) + _| |_ +DB1i(1) |_|8 21|_| DB1i(3) + _| |_ +DB0i(5) |_|9 20|_| DB0i(7) + _| |_ +DB0i(1) |_|10 19|_| DB0i(3) + _| |_ +NC |_|11 18|_| NC + _| |_ +DSH1(1) |_|12 17|_| DSH1(0) + _| |_ +DSH0(1) |_|13 16|_| DSH0(0) + _| |_ +GND |_|14 15|_| NC + |_____________| +*/ + +module k083 +( + input CK, + input CEN, //Set to 1 if using this code to replace a real 083 + input FLIP, + input LOAD, + input [7:0] DB0i, DB1i, + output [1:0] DSH0, DSH1 +); + +//Internal registers (shift right and shift left) +reg [7:0] pixel_D0_l, pixel_D0_r; +reg [7:0] pixel_D1_l, pixel_D1_r; + +//Latch and shift pixel data +always_ff @(posedge CK) begin + if(CEN) begin + if(LOAD) begin + pixel_D0_l <= DB0i; + pixel_D1_l <= DB1i; + pixel_D0_r <= DB0i; + pixel_D1_r <= DB1i; + end + else begin + pixel_D0_l[3:0] <= {pixel_D0_l[2:0], 1'b0}; + pixel_D0_l[7:4] <= {pixel_D0_l[6:4], 1'b0}; + pixel_D1_l[3:0] <= {pixel_D1_l[2:0], 1'b0}; + pixel_D1_l[7:4] <= {pixel_D1_l[6:4], 1'b0}; + pixel_D0_r[3:0] <= {1'b0, pixel_D0_r[3:1]}; + pixel_D0_r[7:4] <= {1'b0, pixel_D0_r[7:5]}; + pixel_D1_r[3:0] <= {1'b0, pixel_D1_r[3:1]}; + pixel_D1_r[7:4] <= {1'b0, pixel_D1_r[7:5]}; + end + end +end + +//Output shifted pixel data (reverse the bits if FLIP is low) +assign DSH0 = FLIP ? {pixel_D0_l[3], pixel_D0_l[7]} : {pixel_D0_r[0], pixel_D0_r[4]}; +assign DSH1 = FLIP ? {pixel_D1_l[3], pixel_D1_l[7]} : {pixel_D1_r[0], pixel_D1_r[4]}; + +endmodule diff --git a/Arcade_MiST/Konami Gyruss/rtl/custom/k501.sv b/Arcade_MiST/Konami Gyruss/rtl/custom/k501.sv new file mode 100644 index 00000000..8bbd3afb --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/custom/k501.sv @@ -0,0 +1,101 @@ +//============================================================================ +// +// SystemVerilog implementation of the Konami 501 custom chip, used by some +// Konami arcade PCBs for partial address decoding and obfuscation of data +// I/O +// 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: +/* _____________ + _| |_ +D[7] |_|1 28|_| VCC + _| |_ +D[6] |_|2 27|_| XD[7] + _| |_ +D[5] |_|3 26|_| XD[6] + _| |_ +D[4] |_|4 25|_| XD[5] + _| |_ +D[3] |_|5 24|_| XD[4] + _| |_ +D[2] |_|6 23|_| XD[3] + _| |_ +D[1] |_|7 22|_| XD[2] + _| |_ +D[0] |_|8 21|_| XD[1] + _| |_ +H2 |_|9 20|_| XD[0] + _| |_ +H1 |_|10 19|_| WAIT + _| |_ +CLK |_|11 18|_| ENABLE + _| |_ +RAM |_|12 17|_| WRITE + _| |_ +RD |_|13 16|_| NC + _| |_ +GND |_|14 15|_| NC + |_____________| + +Note: The data bus is bidirectional - this model splits these pins into separate data I/O +*/ + +module k501 +( + input CLK, //Clock input (add a PLL to multiply the 6.144MHz pixel clock if replacing a real 501) + input CEN, //Clock enable at 12.288MHz + input H1, H2, //Bits 0 and 1 of the horizontal counter + input RAM, //Chip select (active low) + input RD, //Z80 read input + output WAIT, //Z80 wait output + output WRITE, //Write output + output ENABLE, //Enable output + input [7:0] Di, XDi, //Inputs from data busses + output [7:0] Do, XDo //Outputs to data busses +); + +//Data bus passthrough +assign XDo = Di; +assign Do = XDi; + +//Latch bit 0 of the horizontal counter on each edge of the clock and preset to 1 if bit 1 of the horizontal counter +//is high +reg [1:0] h1_reg = 2'd0; +always_ff @(posedge CLK) begin + if(H2) + h1_reg[0] <= 1; + else if(CEN) + h1_reg <= {h1_reg[0], H1}; +end + +//AND both latched instances of H1 +wire h1_lat = &h1_reg; + +//Generate WAIT output +assign WAIT = ~H2 | RAM; + +//Generate WRITE and ENABLE outputs +assign WRITE = ~RD | ENABLE; +assign ENABLE = h1_lat | RAM; + +endmodule diff --git a/Arcade_MiST/Konami Gyruss/rtl/custom/k502.sv b/Arcade_MiST/Konami Gyruss/rtl/custom/k502.sv new file mode 100644 index 00000000..717c4cee --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/custom/k502.sv @@ -0,0 +1,162 @@ +//============================================================================ +// +// SystemVerilog implementation of the Konami 502 custom chip, used for +// generating sprites on a number of '80s Konami arcade PCBs +// 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. +// +//============================================================================ + +//Chip pinout: +/* _____________ + _| |_ +SPLB(0) |_|1 28|_| VCC + _| |_ +SPLB(1) |_|2 27|_| RESET + _| |_ +SPLB(2) |_|3 26|_| SPLB(4) + _| |_ +SPLB(3) |_|4 25|_| SPLB(5) + _| |_ +CK1 |_|5 24|_| SPLB(6) + _| |_ +CK2 |_|6 23|_| SPLB(7) + _| |_ +H2 |_|7 22|_| OLD + _| |_ +LD0 |_|8 21|_| OCLR + _| |_ +H256 |_|9 20|_| OSEL + _| |_ +SPAL(3) |_|10 19|_| COL(4) + _| |_ +SPAL(2) |_|11 18|_| COL(3) + _| |_ +SPAL(1) |_|12 17|_| COL(2) + _| |_ +SPAL(0) |_|13 16|_| COL(1) + _| |_ +GND |_|14 15|_| COL(0) + |_____________| + +Note: The SPLB pins are bidirectional - this model splits these pins into separate + data I/O +*/ + +module k502 +( + input RESET, + input CK1, + input CK2, + input CEN, //Set to 1 if using this code to replace a real 502 + input LD0, + input H2, + input H256, + input [3:0] SPAL, + input [7:0] SPLBi, + output OSEL, + output OLD, + output OCLR, + output [7:0] SPLBo, + output [4:0] COL +); + +//As the Konami 502 doesn't have a dedicated input for bit 2 of the horizontal counter (H4), generate +//this signal internally by dividing H2 by 2 +reg h2_div = 0; +always_ff @(posedge H2) begin + h2_div <= ~h2_div; +end +wire h4 = h2_div; + +//Latch H256 on rising edge of LD0 and delay by one cycle (set to 0 if 502 is held in reset) +reg h256_lat = 0; +always_ff @(posedge LD0 or negedge RESET) begin + if(!RESET) + h256_lat <= 0; + else + h256_lat <= H256; +end +reg h256_dly = 0; +always_ff @(posedge h256_lat or negedge RESET) begin + if(!RESET) + h256_dly <= 0; + else + h256_dly <= ~h256_dly; +end + +//Generate OSEL, OLD and OCLR +reg [1:0] osel_reg; +always_ff @(negedge H2 or negedge RESET) begin + if(!RESET) + osel_reg <= 2'b00; + else begin + if(!h4) + osel_reg[1] <= h256_dly; + else + osel_reg[0] <= osel_reg[1]; + end +end +assign OLD = ~osel_reg[1]; +assign OSEL = osel_reg[0]; +assign OCLR = ~osel_reg[0]; + +//Multiplex incoming line buffer RAM data +wire [3:0] lbuff_Dmux = OCLR ? SPLBi[3:0] : SPLBi[7:4]; + +//Latch incoming line buffer RAM data on the falling edge of CK1 +reg [7:0] lbuff_lat; +always_ff @(negedge CK1) begin + if(!RESET) + lbuff_lat <= 8'd0; + else if(CEN) + lbuff_lat <= SPLBi; +end + +//Latch multiplexed line buffer RAM data on the falling edge of CK2 +reg [3:0] lbuff_mux_lat; +always_ff @(negedge CK2) begin + if(!RESET) + lbuff_mux_lat <= 4'd0; + else if(CEN) + lbuff_mux_lat <= lbuff_Dmux; +end + +//Assign sprite data output +assign COL[4] = ~(|lbuff_mux_lat[3:0]); +assign COL[3:0] = lbuff_mux_lat[3:0]; + +//Select sprite or palette data based on a 4-way AND of the inverted latched line buffer data +//(upper 4 bits and lower 4 bits produce separate select signals) +wire sprite_pal_sel2 = (~lbuff_lat[7] & ~lbuff_lat[6] & ~lbuff_lat[5] & ~lbuff_lat[4]); +wire sprite_pal_sel1 = (~lbuff_lat[3] & ~lbuff_lat[2] & ~lbuff_lat[1] & ~lbuff_lat[0]); + +//Multiplex sprite data from line buffer with palette data (lower 4 bits) +wire [7:0] sprite_pal_mux; +assign sprite_pal_mux[3:0] = osel_reg[0] ? (sprite_pal_sel1 ? SPAL : SPLBi[3:0]) : 4'h0; + +//Multiplex sprite data from line buffer with palette data (upper 4 bits) +assign sprite_pal_mux[7:4] = ~osel_reg[0] ? (sprite_pal_sel2 ? SPAL : SPLBi[7:4]) : 4'h0; + +//Output data to sprite line buffer +assign SPLBo = sprite_pal_mux; + +endmodule + diff --git a/Arcade_MiST/Konami Gyruss/rtl/custom/k503.sv b/Arcade_MiST/Konami Gyruss/rtl/custom/k503.sv new file mode 100644 index 00000000..bf464503 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/custom/k503.sv @@ -0,0 +1,119 @@ +//============================================================================ +// +// SystemVerilog implementation of the Konami 503 custom chip, used by +// several Konami arcade PCBs for handling sprite data +// 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. +// +//============================================================================ + +//Chip pinout: +/* _____________ + _| |_ +OB(7) |_|1 40|_| VCC + _| |_ +OB(6) |_|2 39|_| VCNT(7) + _| |_ +OB(5) |_|3 38|_| VCNT(6) + _| |_ +OB(4) |_|4 37|_| VCNT(5) + _| |_ +OB(3) |_|5 36|_| VCNT(4) + _| |_ +OB(2) |_|6 35|_| VCNT(3) + _| |_ +OB(1) |_|7 34|_| VCNT(2) + _| |_ +OB(0) |_|8 33|_| VCNT(1) + _| |_ +R(5) |_|9 32|_| VCNT(0) + _| |_ +R(4) |_|10 31|_| NC + _| |_ +R(3) |_|11 30|_| OFLP + _| |_ +R(2) |_|12 29|_| OCS + _| |_ +R(1) |_|13 28|_| NC + _| |_ +R(0) |_|14 27|_| NC + _| |_ +LD |_|15 26|_| NC + _| |_ +H4 |_|16 25|_| NC + _| |_ +H8 |_|17 24|_| NC + _| |_ +OCOL |_|18 23|_| NC + _| |_ +ODAT |_|19 22|_| NC + _| |_ +GND |_|20 21|_| NC + |_____________| +*/ + +module k503 +( + input [7:0] OB, //Sprite data input + input [7:0] VCNT, //Vertical counter input + input H4, H8, //Horizontal counter bits 2 (H4) and 3 (H8) + input LD, //LD input (pulses low when bits 0 and 1 of the horizontal counter are both 1) + output OCS, //Sprite line buffer chip select output + output OFLP, //Sprite flip output + output ODAT, //Signal to latch upper bits of sprite address + output OCOL, //Signal to load addresses for sprite line buffer + output [5:0] R //Lower 6 bits of sprite address +); + +//Sum sprite bits with vertical counter +wire [7:0] sprite_sum = OB + VCNT; + +//Sprite select signal +wire sprite_sel = ~(&sprite_sum[7:4]); + +//Sprite flip control +reg hflip, vflip; +always_ff @(posedge H4) begin + hflip <= OB[6]; + vflip <= OB[7]; +end + +//Latch sprite information +reg [6:0] sprite; +always_ff @(negedge H4) begin + sprite <= {sprite_sel, hflip, vflip, sprite_sum[3:0]}; +end +wire sprite_vflip = sprite[4]; +assign OFLP = sprite[5]; +assign OCS = sprite[6]; + +//Assign OCOL (sprite color) and ODAT (sprite data) outputs +assign OCOL = ({H8, H4, LD} != 3'b100); +assign ODAT = ({H8, H4, LD} != 3'b010); + +//XOR final output for R +assign R[5] = (sprite[3] ^ sprite_vflip); +assign R[4] = (OFLP ^ H8); +assign R[3] = (OFLP ^ ~H4); +assign R[2] = (sprite[2] ^ sprite_vflip); +assign R[1] = (sprite[1] ^ sprite_vflip); +assign R[0] = (sprite[0] ^ sprite_vflip); + +endmodule diff --git a/Arcade_MiST/Konami Gyruss/rtl/hiscore.v b/Arcade_MiST/Konami Gyruss/rtl/hiscore.v new file mode 100644 index 00000000..0fd1ef66 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/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 Gyruss/rtl/jt49_dcrm2.v b/Arcade_MiST/Konami Gyruss/rtl/jt49_dcrm2.v new file mode 100644 index 00000000..6646a305 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/jt49_dcrm2.v @@ -0,0 +1,64 @@ +/* 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; // width of the decimal portion + +reg signed [sw+dw:0] integ, exact, error; +//reg signed [2*(9+dw)-1:0] mult; +// wire signed [sw+dw:0] plus1 = { {sw+dw{1'b0}},1'b1}; +reg signed [sw: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 + /* verilator lint_off WIDTH */ + integ <= integ + pre_dout; //mult[sw+dw*2:dw]; + /* verilator lint_on WIDTH */ + error <= exact-{q, {dw{1'b0}}}; + end + +endmodule \ No newline at end of file diff --git a/Arcade_MiST/Konami Gyruss/rtl/jtframe_frac_cen.v b/Arcade_MiST/Konami Gyruss/rtl/jtframe_frac_cen.v new file mode 100644 index 00000000..8707e766 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/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 Gyruss/rtl/pll.qip b/Arcade_MiST/Konami Gyruss/rtl/pll.qip new file mode 100644 index 00000000..afd958be --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/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 Gyruss/rtl/pll.v b/Arcade_MiST/Konami Gyruss/rtl/pll.v new file mode 100644 index 00000000..900c0e3a --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/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 SJ Full Version +// ************************************************************ + + +//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 = 191, + altpll_component.clk0_phase_shift = "0", + altpll_component.clk1_divide_by = 360, + 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 "360" +// Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" +// Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "49.114285" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "14.325000" +// 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 "191" +// 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 "191" +// Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "360" +// 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 Gyruss/rtl/ram_rom/dpram_dc.vhd b/Arcade_MiST/Konami Gyruss/rtl/ram_rom/dpram_dc.vhd new file mode 100644 index 00000000..69d4c5fb --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/ram_rom/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 Gyruss/rtl/ram_rom/gyruss_ram_rom.qip b/Arcade_MiST/Konami Gyruss/rtl/ram_rom/gyruss_ram_rom.qip new file mode 100644 index 00000000..5ba746d2 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/ram_rom/gyruss_ram_rom.qip @@ -0,0 +1,3 @@ +set_global_assignment -name SYSTEMVERILOG_FILE rtl/ram_rom/rom_loader.sv +set_global_assignment -name VHDL_FILE rtl/ram_rom/spram.vhd +set_global_assignment -name VHDL_FILE rtl/ram_rom/dpram_dc.vhd diff --git a/Arcade_MiST/Konami Gyruss/rtl/ram_rom/rom_loader.sv b/Arcade_MiST/Konami Gyruss/rtl/ram_rom/rom_loader.sv new file mode 100644 index 00000000..a0132d0d --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/ram_rom/rom_loader.sv @@ -0,0 +1,452 @@ +//============================================================================ +// +// SD card ROM loader and ROM selector for MISTer. +// Copyright (C) 2019, 2020 Kitrinx (aka Rysha) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +//============================================================================ + +// Rom layout for Gyruss: +// 0x0000 - 0x1FFF = eprom_1 +// 0x2000 - 0x3FFF = eprom_2 +// 0x4000 - 0x5FFF = eprom_3 +// 0x6000 - 0x7FFF = eprom_4 +// 0x8000 - 0x9FFF = eprom_5 +// 0xA000 - 0xBFFF = eprom_6 +// 0xC000 - 0xDFFF = eprom_7 +// 0xE000 - 0xFFFF = eprom_8 +// 0x10000 - 0x11FFF = eprom_9 +// 0x12000 - 0x13FFF = eprom_10 +// 0x14000 - 0x15FFF = eprom_11 +// 0x16000 - 0x16FFF = eprom_12 +// 0x17000 - 0x170FF = tile_lut_prom +// 0x17100 - 0x171FF = sprite_lut_prom +// 0x17200 - 0x1721F = color_prom + +module selector +( + input logic [24:0] ioctl_addr, + output logic ep1_cs, ep2_cs, ep3_cs, ep4_cs, ep5_cs, ep6_cs, ep7_cs, ep8_cs, + ep9_cs, ep10_cs, ep11_cs, ep12_cs, cp_cs, tl_cs, sl_cs +); + + always_comb begin + {ep1_cs, ep2_cs, ep3_cs, ep4_cs, ep5_cs, ep6_cs, ep7_cs, ep8_cs, ep9_cs, + ep10_cs, ep11_cs, ep12_cs, cp_cs, tl_cs, sl_cs} = 0; + if(ioctl_addr < 'h2000) + ep1_cs = 1; // 0x2000 13 + else if(ioctl_addr < 'h4000) + ep2_cs = 1; // 0x2000 13 + else if(ioctl_addr < 'h6000) + ep3_cs = 1; // 0x2000 13 + else if(ioctl_addr < 'h8000) + ep4_cs = 1; // 0x2000 13 + else if(ioctl_addr < 'hA000) + ep5_cs = 1; // 0x2000 13 + else if(ioctl_addr < 'hC000) + ep6_cs = 1; // 0x2000 13 + else if(ioctl_addr < 'hE000) + ep7_cs = 1; // 0x2000 13 + else if(ioctl_addr < 'h10000) + ep8_cs = 1; // 0x2000 13 + else if(ioctl_addr < 'h12000) + ep9_cs = 1; // 0x2000 13 + else if(ioctl_addr < 'h14000) + ep10_cs = 1; // 0x2000 13 + else if(ioctl_addr < 'h16000) + ep11_cs = 1; // 0x2000 13 + else if(ioctl_addr < 'h17000) + ep12_cs = 1; // 0x1000 12 + else if(ioctl_addr < 'h17100) + tl_cs = 1; // 0x100 8 + else if(ioctl_addr < 'h17200) + sl_cs = 1; // 0x100 8 + else + cp_cs = 1; // 0x20 5 + end +endmodule + +//////////// +// EPROMS // +//////////// + +module eprom_1 +( + input logic CLK, + input logic CLK_DL, + input logic [12:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(13)) eprom_1 + ( + .clock_a(CLK), + .address_a(ADDR[12:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[12:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module eprom_2 +( + input logic CLK, + input logic CLK_DL, + input logic [12:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(13)) eprom_2 + ( + .clock_a(CLK), + .address_a(ADDR[12:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[12:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module eprom_3 +( + input logic CLK, + input logic CLK_DL, + input logic [12:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(13)) eprom_3 + ( + .clock_a(CLK), + .address_a(ADDR[12:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[12:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module eprom_4 +( + input logic CLK, + input logic CLK_DL, + input logic [12:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(13)) eprom_4 + ( + .clock_a(CLK), + .address_a(ADDR[12:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[12:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module eprom_5 +( + input logic CLK, + input logic CLK_DL, + input logic [12:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(13)) eprom_5 + ( + .clock_a(CLK), + .address_a(ADDR[12:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[12:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module eprom_6 +( + input logic CLK, + input logic CLK_DL, + input logic [12:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(13)) eprom_6 + ( + .clock_a(CLK), + .address_a(ADDR[12:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[12:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module eprom_7 +( + input logic CLK, + input logic CLK_DL, + input logic [12:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(13)) eprom_7 + ( + .clock_a(CLK), + .address_a(ADDR[12:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[12:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module eprom_8 +( + input logic CLK, + input logic CLK_DL, + input logic [12:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(13)) eprom_8 + ( + .clock_a(CLK), + .address_a(ADDR[12:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[12:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module eprom_9 +( + input logic CLK, + input logic CLK_DL, + input logic [12:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(13)) eprom_9 + ( + .clock_a(CLK), + .address_a(ADDR[12:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[12:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module eprom_10 +( + input logic CLK, + input logic CLK_DL, + input logic [12:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(13)) eprom_10 + ( + .clock_a(CLK), + .address_a(ADDR[12:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[12:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module eprom_11 +( + input logic CLK, + input logic CLK_DL, + input logic [12:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(13)) eprom_11 + ( + .clock_a(CLK), + .address_a(ADDR[12:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[12:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module eprom_12 +( + input logic CLK, + input logic CLK_DL, + input logic [11:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(12)) eprom_12 + ( + .clock_a(CLK), + .address_a(ADDR[11:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[11:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +/////////// +// PROMS // +/////////// + +module color_prom +( + input logic CLK, + input logic CLK_DL, + input logic [4:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [7:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [7:0] DATA +); + dpram_dc #(.widthad_a(5)) color_prom_1 + ( + .clock_a(CLK), + .address_a(ADDR[4:0]), + .q_a(DATA[7:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[4:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module tile_lut_prom +( + input logic CLK, + input logic CLK_DL, + input logic [7:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [3:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [3:0] DATA +); + dpram_dc #(.widthad_a(8)) tile_lut_prom + ( + .clock_a(CLK), + .address_a(ADDR[7:0]), + .q_a(DATA[3:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[7:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule + +module sprite_lut_prom +( + input logic CLK, + input logic CLK_DL, + input logic [7:0] ADDR, + input logic [24:0] ADDR_DL, + input logic [3:0] DATA_IN, + input logic CS_DL, + input logic WR, + output logic [3:0] DATA +); + dpram_dc #(.widthad_a(8)) sprite_lut_prom + ( + .clock_a(CLK), + .address_a(ADDR[7:0]), + .q_a(DATA[3:0]), + + .clock_b(CLK_DL), + .address_b(ADDR_DL[7:0]), + .data_b(DATA_IN), + .wren_b(WR & CS_DL) + ); +endmodule diff --git a/Arcade_MiST/Konami Gyruss/rtl/ram_rom/spram.vhd b/Arcade_MiST/Konami Gyruss/rtl/ram_rom/spram.vhd new file mode 100644 index 00000000..38302277 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/ram_rom/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/Arcade_MiST/Konami Gyruss/rtl/sdram.sv b/Arcade_MiST/Konami Gyruss/rtl/sdram.sv new file mode 100644 index 00000000..7fa4a0a2 --- /dev/null +++ b/Arcade_MiST/Konami Gyruss/rtl/sdram.sv @@ -0,0 +1,357 @@ +// +// 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 [16:1] cpu3_addr, + output reg [15:0] cpu3_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 [31:0] port2_q, + + input [16:2] sp_addr, + output reg [31:0] sp_q +); + +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'b001; // 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 + 2 words burst, CL2 +cmd issued registered + 0 RAS0 cas1 - data0 read burst terminated + 1 ras0 + 2 data1 returned + 3 CAS0 data1 returned + 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_DS1b = 3'd0; +localparam STATE_READ1b = 3'd4; +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[3]; +reg [24:1] addr_latch_next[2]; +reg [16:1] addr_last[4]; +reg [16:2] addr_last2[2]; +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_CPU3 = 3'd3; +localparam PORT_SP = 3'd1; +localparam PORT_REQ = 3'd4; + +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 if (cpu3_addr != addr_last[PORT_CPU3]) begin + next_port[0] = PORT_CPU3; + addr_latch_next[0] = { 8'd0, cpu3_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 (sp_addr != addr_last2[PORT_SP]) begin + next_port[1] = PORT_SP; + addr_latch_next[1] = { 1'b1, 7'd0, sp_addr, 1'b0 }; + 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:2]; + 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 + PORT_CPU3: begin cpu3_q <= sd_din; end + default: ; + endcase; + end + + if(t == STATE_READ1 && oe_latch[1]) begin + case(port[1]) + PORT_REQ: port2_q[15:0] <= sd_din; + PORT_SP : sp_q[15:0] <= sd_din; + default: ; + endcase; + end + + if(t == STATE_DS1b && oe_latch[1]) { SDRAM_DQMH, SDRAM_DQML } <= ~ds[1]; + + if(t == STATE_READ1b && oe_latch[1]) begin + case(port[1]) + PORT_REQ: begin port2_q[31:16] <= sd_din; port2_ack <= port2_req; end + PORT_SP : begin sp_q[31:16] <= sd_din; end + default: ; + endcase; + end + end +end + +endmodule