diff --git a/Arcade_MiST/IremM72 Hardware/Readme.md b/Arcade_MiST/IremM72 Hardware/Readme.md
index 6eab9a76..4938a966 100644
--- a/Arcade_MiST/IremM72 Hardware/Readme.md
+++ b/Arcade_MiST/IremM72 Hardware/Readme.md
@@ -15,15 +15,15 @@ Implemention of the Irem M72 & M84 arcade hardware (https://www.system16.com/har
|[R-Type](https://en.wikipedia.org/wiki/R-Type)|Japan, US, World||
|[Ninja Spirit](https://en.wikipedia.org/wiki/Ninja_Spirit)|Japan||
|[Image Fight](https://en.wikipedia.org/wiki/Image_Fight)|Japan, World||
-|[Gallop - Armed Police Unit](https://en.wikipedia.org/wiki/Armed_Police_Unit_Gallop)|Japan|Emulated MCU|
+|[Gallop - Armed Police Unit](https://en.wikipedia.org/wiki/Armed_Police_Unit_Gallop)|Japan|Emulated MCU.|
|[Legend of Hero Tonma](https://en.wikipedia.org/wiki/Legend_of_Hero_Tonma)|Japan||
|[Mr. HELI no Daibouken](https://en.wikipedia.org/wiki/Mr._Heli)|Japan||
-|[Air Duel](https://en.wikipedia.org/wiki/Air_Duel)|Japan|Conversion from M81 hardware.|
+|[Air Duel](https://en.wikipedia.org/wiki/Air_Duel)|Japan, World|Conversion from M81 hardware.|
|[Dragon Breed](https://en.wikipedia.org/wiki/Dragon_Breed)|Japan|Conversion from M81 hardware.|
|[X-Multiply](https://en.wikipedia.org/wiki/X_Multiply)|Japan|Conversion from M81 hardware.|
-|[Daiku no Gensan](https://en.wikipedia.org/wiki/Hammerin%27_Harry)|Japan|Conversion from M81 hardware. Emulated MCU|
+|[Daiku no Gensan](https://en.wikipedia.org/wiki/Hammerin%27_Harry)|Japan|Conversion from M81 hardware. Emulated MCU.|
+|[Hammerin' Harry](https://en.wikipedia.org/wiki/Hammerin%27_Harry)|US, Japan|M84 Hardware.|
|[R-Type II](https://en.wikipedia.org/wiki/R-Type_II)|Japan,World|M84 hardware.|
-|[Hammerin' Harry](https://en.wikipedia.org/wiki/Hammerin%27_Harry)|US|M84 hardware.|
**Note:** Emulated MCU is not implemented on MiST (FPGA is full).
diff --git a/Arcade_MiST/IremM72 Hardware/meta/Air Duel (World, M72 hardware).mra b/Arcade_MiST/IremM72 Hardware/meta/Air Duel (World, M72 hardware).mra
new file mode 100644
index 00000000..1daf315b
--- /dev/null
+++ b/Arcade_MiST/IremM72 Hardware/meta/Air Duel (World, M72 hardware).mra
@@ -0,0 +1,74 @@
+
+ Air Duel (World, M72 hardware)
+ 0245
+ airduelm72
+ airduel
+ 1990
+ Irem
+ Shooter
+ IremM72
+ vertical (ccw)
+
+ 8-way
+ 2
+
+
+
+
+
+
+
+
+
+
+ 01
+
+
+ 09
+
+ 00 08 00 00
+
+
+
+
+
+
+
+
+
+
+ 01 08 00 00
+
+
+
+
+
+
+
+
+ 02 08 00 00
+
+
+
+
+
+
+
+
+ 03 08 00 00
+
+
+
+
+
+
+
+
+ 04 00 10 00
+
+
+
+ 05 02 00 00
+
+
+
diff --git a/Arcade_MiST/IremM72 Hardware/meta/Daiku no Gensan (Japan, M84 hardware).mra b/Arcade_MiST/IremM72 Hardware/meta/Daiku no Gensan (Japan, M84 hardware).mra
new file mode 100644
index 00000000..6484f33d
--- /dev/null
+++ b/Arcade_MiST/IremM72 Hardware/meta/Daiku no Gensan (Japan, M84 hardware).mra
@@ -0,0 +1,73 @@
+
+ Daiku no Gensan (Japan, M84 hardware)
+ 0247
+ hharry
+ dkgensan
+ 1990
+ Irem
+ Platformer
+ IremM72
+ horizontal
+
+ 8-way
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 14
+
+ 00 08 00 00
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 01 08 00 00
+
+
+
+
+
+
+
+
+ 02 08 00 00
+
+
+
+
+
+
+
+
+ 05 02 00 00
+
+
+
+ 08 01 00 00
+
+
+
+
diff --git a/Arcade_MiST/IremM72 Hardware/meta/Hammerin' Harry (US, M84 hardware).mra b/Arcade_MiST/IremM72 Hardware/meta/Hammerin' Harry (US, M84 hardware).mra
index c9914a43..a63e9a24 100644
--- a/Arcade_MiST/IremM72 Hardware/meta/Hammerin' Harry (US, M84 hardware).mra
+++ b/Arcade_MiST/IremM72 Hardware/meta/Hammerin' Harry (US, M84 hardware).mra
@@ -12,18 +12,15 @@
2
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.qpf b/Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.qpf
new file mode 100644
index 00000000..f3639673
--- /dev/null
+++ b/Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.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 = "Galivan"
+
diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.qsf b/Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.qsf
new file mode 100644
index 00000000..c7b626a0
--- /dev/null
+++ b/Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.qsf
@@ -0,0 +1,255 @@
+# -------------------------------------------------------------------------- #
+#
+# 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:
+# Galivan_assignment_defaults.qdf
+# If this file doesn't exist, see file:
+# assignment_defaults.qdf
+#
+# 2) Altera recommends that you do not modify this file. This
+# file is updated automatically by the Quartus II software
+# and any changes you make may be lost or overwritten.
+#
+# -------------------------------------------------------------------------- #
+
+
+
+# Project-Wide Assignments
+# ========================
+set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
+set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
+set_global_assignment -name LAST_QUARTUS_VERSION 13.1
+set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:rtl/build_id.tcl"
+
+# Pin & Location Assignments
+# ==========================
+set_location_assignment PIN_7 -to LED
+set_location_assignment PIN_54 -to CLOCK_27
+set_location_assignment PIN_144 -to VGA_R[5]
+set_location_assignment PIN_143 -to VGA_R[4]
+set_location_assignment PIN_142 -to VGA_R[3]
+set_location_assignment PIN_141 -to VGA_R[2]
+set_location_assignment PIN_137 -to VGA_R[1]
+set_location_assignment PIN_135 -to VGA_R[0]
+set_location_assignment PIN_133 -to VGA_B[5]
+set_location_assignment PIN_132 -to VGA_B[4]
+set_location_assignment PIN_125 -to VGA_B[3]
+set_location_assignment PIN_121 -to VGA_B[2]
+set_location_assignment PIN_120 -to VGA_B[1]
+set_location_assignment PIN_115 -to VGA_B[0]
+set_location_assignment PIN_114 -to VGA_G[5]
+set_location_assignment PIN_113 -to VGA_G[4]
+set_location_assignment PIN_112 -to VGA_G[3]
+set_location_assignment PIN_111 -to VGA_G[2]
+set_location_assignment PIN_110 -to VGA_G[1]
+set_location_assignment PIN_106 -to VGA_G[0]
+set_location_assignment PIN_136 -to VGA_VS
+set_location_assignment PIN_119 -to VGA_HS
+set_location_assignment PIN_65 -to AUDIO_L
+set_location_assignment PIN_80 -to AUDIO_R
+set_location_assignment PIN_105 -to SPI_DO
+set_location_assignment PIN_88 -to SPI_DI
+set_location_assignment PIN_126 -to SPI_SCK
+set_location_assignment PIN_127 -to SPI_SS2
+set_location_assignment PIN_91 -to SPI_SS3
+set_location_assignment PIN_13 -to CONF_DATA0
+set_location_assignment PIN_49 -to SDRAM_A[0]
+set_location_assignment PIN_44 -to SDRAM_A[1]
+set_location_assignment PIN_42 -to SDRAM_A[2]
+set_location_assignment PIN_39 -to SDRAM_A[3]
+set_location_assignment PIN_4 -to SDRAM_A[4]
+set_location_assignment PIN_6 -to SDRAM_A[5]
+set_location_assignment PIN_8 -to SDRAM_A[6]
+set_location_assignment PIN_10 -to SDRAM_A[7]
+set_location_assignment PIN_11 -to SDRAM_A[8]
+set_location_assignment PIN_28 -to SDRAM_A[9]
+set_location_assignment PIN_50 -to SDRAM_A[10]
+set_location_assignment PIN_30 -to SDRAM_A[11]
+set_location_assignment PIN_32 -to SDRAM_A[12]
+set_location_assignment PIN_83 -to SDRAM_DQ[0]
+set_location_assignment PIN_79 -to SDRAM_DQ[1]
+set_location_assignment PIN_77 -to SDRAM_DQ[2]
+set_location_assignment PIN_76 -to SDRAM_DQ[3]
+set_location_assignment PIN_72 -to SDRAM_DQ[4]
+set_location_assignment PIN_71 -to SDRAM_DQ[5]
+set_location_assignment PIN_69 -to SDRAM_DQ[6]
+set_location_assignment PIN_68 -to SDRAM_DQ[7]
+set_location_assignment PIN_86 -to SDRAM_DQ[8]
+set_location_assignment PIN_87 -to SDRAM_DQ[9]
+set_location_assignment PIN_98 -to SDRAM_DQ[10]
+set_location_assignment PIN_99 -to SDRAM_DQ[11]
+set_location_assignment PIN_100 -to SDRAM_DQ[12]
+set_location_assignment PIN_101 -to SDRAM_DQ[13]
+set_location_assignment PIN_103 -to SDRAM_DQ[14]
+set_location_assignment PIN_104 -to SDRAM_DQ[15]
+set_location_assignment PIN_58 -to SDRAM_BA[0]
+set_location_assignment PIN_51 -to SDRAM_BA[1]
+set_location_assignment PIN_85 -to SDRAM_DQMH
+set_location_assignment PIN_67 -to SDRAM_DQML
+set_location_assignment PIN_60 -to SDRAM_nRAS
+set_location_assignment PIN_64 -to SDRAM_nCAS
+set_location_assignment PIN_66 -to SDRAM_nWE
+set_location_assignment PIN_59 -to SDRAM_nCS
+set_location_assignment PIN_33 -to SDRAM_CKE
+set_location_assignment PIN_43 -to SDRAM_CLK
+set_location_assignment PLL_1 -to "pll:pll|altpll:altpll_component"
+
+# Classic Timing Assignments
+# ==========================
+set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
+set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
+
+# Analysis & Synthesis Assignments
+# ================================
+set_global_assignment -name FAMILY "Cyclone III"
+set_global_assignment -name TOP_LEVEL_ENTITY Galivan_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/cpu.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(Galivan_MiST)
+
+ # Pin & Location Assignments
+ # ==========================
+
+ # Fitter Assignments
+ # ==================
+
+ # start DESIGN_PARTITION(Top)
+ # ---------------------------
+
+ # Incremental Compilation Assignments
+ # ===================================
+
+ # end DESIGN_PARTITION(Top)
+ # -------------------------
+
+# end ENTITY(Galivan_MiST)
+# ----------------------------
+set_global_assignment -name SYNTH_TIMING_DRIVEN_SYNTHESIS ON
+set_global_assignment -name TIMEQUEST_MULTICORNER_ANALYSIS ON
+set_global_assignment -name SMART_RECOMPILE ON
+set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
+set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
+set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
+set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[*]
+set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_A[*]
+set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_BA[0]
+set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_BA[1]
+set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQMH
+set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQML
+set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nRAS
+set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nCAS
+set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nWE
+set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nCS
+set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[*]
+set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[*]
+set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_A[*]
+set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[*]
+set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_BA[*]
+set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQML
+set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQMH
+set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nRAS
+set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nCAS
+set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nWE
+set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nCS
+set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_CKE
+set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_CLK
+set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_R[*]
+set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_G[*]
+set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_B[*]
+set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_HS
+set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_VS
+set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to AUDIO_L
+set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to AUDIO_R
+set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SPI_DO
+set_global_assignment -name ALLOW_POWER_UP_DONT_CARE ON
+set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_RETIMING OFF
+set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_DUPLICATION ON
+set_global_assignment -name CYCLONEII_OPTIMIZATION_TECHNIQUE SPEED
+set_global_assignment -name OPTIMIZE_HOLD_TIMING "ALL PATHS"
+set_global_assignment -name OPTIMIZE_MULTI_CORNER_TIMING ON
+set_global_assignment -name FITTER_EFFORT "STANDARD FIT"
+set_global_assignment -name VERILOG_SHOW_LMF_MAPPING_MESSAGES OFF
+set_global_assignment -name VERILOG_MACRO "EXT_ROM="
+set_global_assignment -name FORCE_SYNCH_CLEAR ON
+set_global_assignment -name SYSTEMVERILOG_FILE rtl/Galivan_MiST.sv
+set_global_assignment -name QIP_FILE rtl/pll_mist.qip
+set_global_assignment -name VERILOG_FILE rtl/video.v
+set_global_assignment -name SYSTEMVERILOG_FILE rtl/spram.sv
+set_global_assignment -name SYSTEMVERILOG_FILE rtl/sdram.sv
+set_global_assignment -name VERILOG_FILE rtl/gfx.v
+set_global_assignment -name VERILOG_FILE rtl/dpram.v
+set_global_assignment -name VERILOG_FILE rtl/core.v
+set_global_assignment -name VERILOG_FILE rtl/clk_en.v
+set_global_assignment -name VERILOG_FILE rtl/build_id.v
+set_global_assignment -name QIP_FILE ../../common/mist/mist.qip
+set_global_assignment -name QIP_FILE ../../common/Sound/jtopl/jt26.qip
+set_global_assignment -name QIP_FILE ../../common/CPU/T80/T80.qip
+set_global_assignment -name SIGNALTAP_FILE output_files/cpu.stp
+set_global_assignment -name SIGNALTAP_FILE output_files/spri.stp
+set_global_assignment -name SIGNALTAP_FILE output_files/tx.stp
+set_global_assignment -name SIGNALTAP_FILE output_files/sh.stp
+set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
\ No newline at end of file
diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.sdc b/Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.sdc
new file mode 100644
index 00000000..4a373c09
--- /dev/null
+++ b/Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.sdc
@@ -0,0 +1,134 @@
+## Generated SDC file "vectrex_MiST.out.sdc"
+
+## Copyright (C) 1991-2013 Altera Corporation
+## Your use of Altera Corporation's design tools, logic functions
+## and other software and tools, and its AMPP partner logic
+## functions, and any output files from any of the foregoing
+## (including device programming or simulation files), and any
+## associated documentation or information are expressly subject
+## to the terms and conditions of the Altera Program License
+## Subscription Agreement, Altera MegaCore Function License
+## Agreement, or other applicable license agreement, including,
+## without limitation, that your use is for the sole purpose of
+## programming logic devices manufactured by Altera and sold by
+## Altera or its authorized distributors. Please refer to the
+## applicable agreement for further details.
+
+
+## VENDOR "Altera"
+## PROGRAM "Quartus II"
+## VERSION "Version 13.1.0 Build 162 10/23/2013 SJ Web Edition"
+
+## DATE "Sun Jun 24 12:53:00 2018"
+
+##
+## DEVICE "EP3C25E144C8"
+##
+
+# Clock constraints
+
+# Automatically constrain PLL and other generated clocks
+derive_pll_clocks -create_base_clocks
+
+# Automatically calculate clock uncertainty to jitter and other effects.
+derive_clock_uncertainty
+
+# tsu/th constraints
+
+# tco constraints
+
+# tpd constraints
+
+#**************************************************************
+# Time Information
+#**************************************************************
+
+set_time_format -unit ns -decimal_places 3
+
+
+
+#**************************************************************
+# Create Clock
+#**************************************************************
+
+create_clock -name {SPI_SCK} -period 41.666 -waveform { 20.8 41.666 } [get_ports {SPI_SCK}]
+
+set sdram_clk "pll|altpll_component|auto_generated|pll1|clk[0]"
+set sys_clk "pll|altpll_component|auto_generated|pll1|clk[1]"
+#**************************************************************
+# Create Generated Clock
+#**************************************************************
+
+
+#**************************************************************
+# Set Clock Latency
+#**************************************************************
+
+
+
+#**************************************************************
+# Set Clock Uncertainty
+#**************************************************************
+
+#**************************************************************
+# Set Input Delay
+#**************************************************************
+
+set_input_delay -add_delay -clock_fall -clock [get_clocks {CLOCK_27}] 1.000 [get_ports {CLOCK_27}]
+set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {CONF_DATA0}]
+set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_DI}]
+set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_SCK}]
+set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_SS2}]
+set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_SS3}]
+
+set_input_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -max 6.6 [get_ports SDRAM_DQ[*]]
+set_input_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -min 3.5 [get_ports SDRAM_DQ[*]]
+
+#**************************************************************
+# Set Output Delay
+#**************************************************************
+
+set_output_delay -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_DO}]
+set_output_delay -clock [get_clocks $sys_clk] 1.000 [get_ports {AUDIO_L}]
+set_output_delay -clock [get_clocks $sys_clk] 1.000 [get_ports {AUDIO_R}]
+set_output_delay -clock [get_clocks $sys_clk] 1.000 [get_ports {LED}]
+set_output_delay -clock [get_clocks $sys_clk] 1.000 [get_ports {VGA_*}]
+
+set_output_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -max 1.5 [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}]
+set_output_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -min -0.8 [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}]
+
+#**************************************************************
+# Set Clock Groups
+#**************************************************************
+
+set_clock_groups -asynchronous -group [get_clocks {SPI_SCK}] -group [get_clocks {pll|altpll_component|auto_generated|pll1|clk[*]}]
+
+#**************************************************************
+# Set False Path
+#**************************************************************
+
+
+
+#**************************************************************
+# Set Multicycle Path
+#**************************************************************
+
+set_multicycle_path -to {VGA_*[*]} -setup 2
+set_multicycle_path -to {VGA_*[*]} -hold 1
+
+#**************************************************************
+# Set Maximum Delay
+#**************************************************************
+
+
+
+#**************************************************************
+# Set Minimum Delay
+#**************************************************************
+
+
+
+#**************************************************************
+# Set Input Transition
+#**************************************************************
+
diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/LICENSE b/Arcade_MiST/Nichibutsu Galivan Hardware/LICENSE
new file mode 100644
index 00000000..d159169d
--- /dev/null
+++ b/Arcade_MiST/Nichibutsu Galivan Hardware/LICENSE
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ 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 2 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.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/Readme.md b/Arcade_MiST/Nichibutsu Galivan Hardware/Readme.md
new file mode 100644
index 00000000..148f7524
--- /dev/null
+++ b/Arcade_MiST/Nichibutsu Galivan Hardware/Readme.md
@@ -0,0 +1,5 @@
+# Cosmo Police Galivan & UFO Robo Dangar
+
+This core is an emulation of the GV-1412 PCB from Nichibutsu originally by [Pierco](https://github.com/pcornier). Two games are supported: Cosmo Police Galivan & UFO Robo Dangar. Use a vertically oriented CRT for the best gaming experience!
+
+SDRAM controller/gfx layers rewrite by Gyorgy Szombathelyi
diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/meta/Cosmo Police Galivan (12-26-1985).mra b/Arcade_MiST/Nichibutsu Galivan Hardware/meta/Cosmo Police Galivan (12-26-1985).mra
new file mode 100644
index 00000000..7a2f80d8
--- /dev/null
+++ b/Arcade_MiST/Nichibutsu Galivan Hardware/meta/Cosmo Police Galivan (12-26-1985).mra
@@ -0,0 +1,98 @@
+
+ Cosmo Police Galivan (12/26/1985)
+
+ no
+ no
+
+
+
+
+ 1985
+ Nichibutsu
+ Platform
+
+ galivan
+ 0246
+ galivan
+
+
+ 15kHz
+ vertical
+
+
+ 2
+ 8-way
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 202108231828
+
\ No newline at end of file
diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/meta/Ufo Robo Dangar (4-07-1987).mra b/Arcade_MiST/Nichibutsu Galivan Hardware/meta/Ufo Robo Dangar (4-07-1987).mra
new file mode 100644
index 00000000..8cbb1ad5
--- /dev/null
+++ b/Arcade_MiST/Nichibutsu Galivan Hardware/meta/Ufo Robo Dangar (4-07-1987).mra
@@ -0,0 +1,99 @@
+
+ Ufo Robo Dangar (4/07/1987)
+
+ no
+ no
+
+
+
+
+ 1985
+ Nichibutsu
+ Platform
+
+ dangar
+ 0246
+ galivan
+
+
+ 15kHz
+ vertical
+
+
+ 2
+ 8-way
+
+ 3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 202108231828
+
diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/Galivan_MiST.sv b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/Galivan_MiST.sv
new file mode 100644
index 00000000..e6e92cb6
--- /dev/null
+++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/Galivan_MiST.sv
@@ -0,0 +1,348 @@
+module Galivan_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 = {
+ "GALIVAN;;",
+ "O2,Rotate Controls,Off,On;",
+ "O34,Scanlines,Off,25%,50%,75%;",
+ "O5,Blend,Off,On;",
+ "O6,Joystick Swap,Off,On;",
+ "O8,Test mode,Off,On;",
+ "O1,Pause,Off,On;",
+ "DIP;",
+ "T0,Reset;",
+ "V,v1.00.",`BUILD_DATE
+};
+
+wire pause = status[1];
+wire rotate = status[2];
+wire [1:0] scanlines = status[4:3];
+wire blend = status[5];
+wire joyswap = status[6];
+wire service = status[8];
+
+wire flip;
+wire [1:0] orientation = {flip, 1'b1};
+
+wire [7:0] j1 = ~{ m_fire1[2], 1'b0, m_fire1[1], m_fire1[0], m_right1, m_left1, m_down1, m_up1 };
+wire [7:0] j2 = ~{ m_fire2[2], 1'b0, m_fire2[1], m_fire2[0], m_right2, m_left2, m_down2, m_up2 };
+wire [7:0] p1 = ~status[23:16]; // dsw1
+wire [7:0] p2 = ~status[31:24]; // dsw2
+
+wire [7:0] system = ~{ 3'b000, service, m_coin2, m_coin1, m_two_players, m_one_player };
+
+assign LED = ~ioctl_downl;
+assign SDRAM_CLK = clk_ram;
+assign SDRAM_CKE = 1;
+
+wire clk_sys, clk_ram, pll_locked;
+pll_mist pll(
+ .inclk0(CLOCK_27),
+ .c0(clk_ram),
+ .c1(clk_sys),
+ .locked(pll_locked)
+ );
+
+wire [31:0] status;
+wire [1:0] buttons;
+wire [1:0] switches;
+wire [19:0] joystick_0;
+wire [19:0] joystick_1;
+wire scandoublerD;
+wire ypbpr;
+wire no_csync;
+wire [6:0] core_mod;
+wire key_strobe;
+wire key_pressed;
+wire [7:0] key_code;
+
+
+user_io #(.STRLEN(($size(CONF_STR)>>3)))user_io(
+ .clk_sys (clk_sys ),
+ .conf_str (CONF_STR ),
+ .SPI_CLK (SPI_SCK ),
+ .SPI_SS_IO (CONF_DATA0 ),
+ .SPI_MISO (SPI_DO ),
+ .SPI_MOSI (SPI_DI ),
+ .buttons (buttons ),
+ .switches (switches ),
+ .scandoubler_disable (scandoublerD),
+ .ypbpr (ypbpr ),
+ .no_csync (no_csync ),
+ .core_mod (core_mod ),
+ .key_strobe (key_strobe ),
+ .key_pressed (key_pressed ),
+ .key_code (key_code ),
+ .joystick_0 (joystick_0 ),
+ .joystick_1 (joystick_1 ),
+ .status (status )
+ );
+
+wire [15:0] cpu1_rom_addr;
+wire [15:0] cpu1_rom_do;
+wire cpu1_rom_cs;
+wire cpu1_rom_valid;
+wire [15:0] cpu2_rom_addr;
+wire [15:0] cpu2_rom_do;
+wire cpu2_rom_cs;
+wire cpu2_rom_valid;
+
+wire [13:0] gfx1_rom_addr;
+wire [15:0] gfx1_rom_do;
+wire [16:0] gfx2_rom_addr;
+wire [15:0] gfx2_rom_do;
+wire [15:0] gfx3_rom_addr;
+wire [15:0] gfx3_rom_do;
+wire gfx3_rom_ready;
+
+wire ioctl_downl;
+wire ioctl_upl;
+wire [7:0] ioctl_index;
+wire ioctl_wr;
+wire [24:0] ioctl_addr;
+wire [7:0] ioctl_din;
+wire [7:0] ioctl_dout;
+
+data_io data_io(
+ .clk_sys ( clk_sys ),
+ .SPI_SCK ( SPI_SCK ),
+ .SPI_SS2 ( SPI_SS2 ),
+ .SPI_DI ( SPI_DI ),
+ .SPI_DO ( SPI_DO ),
+ .ioctl_download( ioctl_downl ),
+ .ioctl_upload ( ioctl_upl ),
+ .ioctl_index ( ioctl_index ),
+ .ioctl_wr ( ioctl_wr ),
+ .ioctl_addr ( ioctl_addr ),
+ .ioctl_din ( ioctl_din ),
+ .ioctl_dout ( ioctl_dout )
+);
+
+reg port1_req, port2_req;
+sdram #(96) sdram(
+ .*,
+ .init_n ( pll_locked ),
+ .clk ( clk_ram ),
+
+ // port1 for main and sound CPU
+ .port1_req ( port1_req ),
+ .port1_ack ( ),
+ .port1_a ( ioctl_addr[23:1] ),
+ .port1_ds ( {ioctl_addr[0], ~ioctl_addr[0]} ),
+ .port1_we ( rom_init ),
+ .port1_d ( {ioctl_dout, ioctl_dout} ),
+ .port1_q ( ),
+
+ .cpu1_cs ( cpu1_rom_cs ),
+ .cpu1_addr ( {1'b0, cpu1_rom_addr[15:1]} ),
+ .cpu1_q ( cpu1_rom_do ),
+ .cpu1_valid ( cpu1_rom_valid ),
+ .cpu2_cs ( cpu2_rom_cs ),
+ .cpu2_addr ( {1'b1, cpu2_rom_addr[15:1]} ),
+ .cpu2_q ( cpu2_rom_do ),
+ .cpu2_valid ( cpu2_rom_valid ),
+
+ // port2 for graphics
+ .port2_req ( port2_req ),
+ .port2_ack ( ),
+ .port2_a ( ioctl_addr[23:1] ),
+ .port2_ds ( {ioctl_addr[0], ~ioctl_addr[0]} ),
+ .port2_we ( rom_init ),
+ .port2_d ( {ioctl_dout, ioctl_dout} ),
+ .port2_q ( ),
+
+ .gfx1_addr ( 27'he000 + gfx1_rom_addr[13:1] ),
+ .gfx1_q ( gfx1_rom_do ),
+ .gfx2_addr ( 27'h10000 + gfx2_rom_addr[16:1] ),
+ .gfx2_q ( gfx2_rom_do ),
+ .gfx3_addr ( 27'h20000 + gfx3_rom_addr[15:1] ),
+ .gfx3_q ( gfx3_rom_do ),
+ .gfx3_ready ( gfx3_rom_ready )
+);
+
+// ROM download controller
+always @(posedge clk_sys) begin
+ reg ioctl_wr_last = 0;
+
+ ioctl_wr_last <= ioctl_wr;
+ if (rom_init) 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 clk_sys) begin
+ reg ioctl_downlD;
+ ioctl_downlD <= ioctl_downl;
+
+ if (ioctl_downlD & ~ioctl_downl) rom_loaded <= 1;
+ reset <= status[0] | buttons[1] | ~rom_loaded;
+end
+
+
+wire [15:0] sound;
+wire HBlank;
+wire HSync;
+wire VBlank;
+wire VSync;
+wire [8:0] hcount, vcount;
+reg [2:0] vred, vgreen;
+reg [1:0] vblue;
+
+wire ce_pix;
+
+video video(
+ .clk ( clk_sys ),
+ .ce_pix ( ce_pix ),
+ .hs ( HSync ),
+ .vs ( VSync ),
+ .hb ( HBlank ),
+ .vb ( VBlank ),
+ .hcount ( hcount ),
+ .vcount ( vcount ),
+ .hoffs (),
+ .voffs ()
+);
+
+wire rom_init = ioctl_downl && (ioctl_index==0);
+//wire nvram_init = ioctl_downl && (ioctl_index==8'hFF);
+
+core u_core(
+ .reset ( reset ),
+ .clk_sys ( clk_sys ),
+ .ce_pix ( ce_pix ),
+ .pause ( pause ),
+ .j1 ( j1 ),
+ .j2 ( j2 ),
+ .p1 ( p1 ),
+ .p2 ( p2 ),
+ .system ( system ),
+ .ioctl_index ( ioctl_index ),
+ .ioctl_download ( rom_init ),
+ .ioctl_addr ( ioctl_addr ),
+ .ioctl_dout ( ioctl_dout ),
+ .ioctl_wr ( ioctl_wr ),
+ .hh ( hcount ),
+ .vv ( vcount ),
+ .red ( vred ),
+ .green ( vgreen ),
+ .blue ( vblue ),
+ .vs ( VSync ),
+ .hb ( HBlank ),
+ .sound ( sound ),
+ .hflip ( flip ),
+ .bg_on ( 1'b1 ),
+ .tx_on ( 1'b1 ),
+ .sp_on ( 1'b1 ),
+ .fdiv ( 2'b0 ),
+
+ .cpu1_rom_cs ( cpu1_rom_cs ),
+ .cpu1_rom_addr ( cpu1_rom_addr ),
+ .cpu1_rom_q ( cpu1_rom_addr[0] ? cpu1_rom_do[15:8] : cpu1_rom_do[7:0] ),
+ .cpu1_rom_valid ( cpu1_rom_valid ),
+ .cpu2_rom_cs ( cpu2_rom_cs ),
+ .cpu2_rom_addr ( cpu2_rom_addr ),
+ .cpu2_rom_q ( cpu2_rom_addr[0] ? cpu2_rom_do[15:8] : cpu2_rom_do[7:0] ),
+ .cpu2_rom_valid ( cpu2_rom_valid ),
+
+ .gfx1_rom_addr ( gfx1_rom_addr ),
+ .gfx1_rom_q ( gfx1_rom_addr[0] ? gfx1_rom_do[15:8] : gfx1_rom_do[7:0] ),
+ .gfx2_rom_addr ( gfx2_rom_addr ),
+ .gfx2_rom_q ( gfx2_rom_addr[0] ? gfx2_rom_do[15:8] : gfx2_rom_do[7:0] ),
+ .gfx3_rom_addr ( gfx3_rom_addr ),
+ .gfx3_rom_q ( gfx3_rom_addr[0] ? gfx3_rom_do[15:8] : gfx3_rom_do[7:0] ),
+ .gfx3_rom_ready ( gfx3_rom_ready )
+);
+
+wire blankn = !(HBlank | VBlank);
+
+mist_video #(.COLOR_DEPTH(3), .SD_HCNT_WIDTH(10)) mist_video(
+ .clk_sys ( clk_sys ),
+ .SPI_SCK ( SPI_SCK ),
+ .SPI_SS3 ( SPI_SS3 ),
+ .SPI_DI ( SPI_DI ),
+ .R ( blankn ? vred : 0 ),
+ .G ( blankn ? vgreen : 0 ),
+ .B ( blankn ? {vblue, vblue[1]} : 0 ),
+ .HSync ( HSync ),
+ .VSync ( VSync ),
+ .VGA_R ( VGA_R ),
+ .VGA_G ( VGA_G ),
+ .VGA_B ( VGA_B ),
+ .VGA_VS ( VGA_VS ),
+ .VGA_HS ( VGA_HS ),
+ .ce_divider ( 1'b0 ),
+ .rotate ( { orientation[1], rotate } ),
+ .blend ( blend ),
+ .scandoubler_disable( scandoublerD ),
+ .scanlines ( scanlines ),
+ .ypbpr ( ypbpr ),
+ .no_csync ( no_csync )
+ );
+
+wire audio_out;
+assign AUDIO_L = audio_out;
+assign AUDIO_R = audio_out;
+
+dac #(.C_bits(16))dac(
+ .clk_i(clk_sys),
+ .res_n_i(1'b1),
+ .dac_i({~sound[15], sound[14:0]}),
+ .dac_o(audio_out)
+ );
+
+wire m_up1, m_down1, m_left1, m_right1, m_up1B, m_down1B, m_left1B, m_right1B;
+wire m_up2, m_down2, m_left2, m_right2, m_up2B, m_down2B, m_left2B, m_right2B;
+wire m_tilt, m_coin1, m_coin2, m_coin3, m_coin4, m_one_player, m_two_players, m_three_players, m_four_players;
+wire [11:0] m_fire1, m_fire2;
+
+arcade_inputs inputs (
+ .clk ( clk_sys ),
+ .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_up1B, m_down1B, m_left1B, m_right1B, m_fire1, m_up1, m_down1, m_left1, m_right1} ),
+ .player2 ( {m_up2B, m_down2B, m_left2B, m_right2B, m_fire2, m_up2, m_down2, m_left2, m_right2} )
+);
+
+endmodule
diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/build_id.tcl b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/build_id.tcl
new file mode 100644
index 00000000..938515d8
--- /dev/null
+++ b/Arcade_MiST/Nichibutsu Galivan Hardware/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/Nichibutsu Galivan Hardware/rtl/clk_en.v b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/clk_en.v
new file mode 100644
index 00000000..9eaf5b8d
--- /dev/null
+++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/clk_en.v
@@ -0,0 +1,29 @@
+
+module clk_en #(
+ parameter DIV=12,
+ parameter OFFSET=0
+)
+(
+ input ref_clk,
+ output reg cen,
+ input [15:0] div,
+ input [1:0] fdiv
+);
+
+reg [15:0] cnt = OFFSET;
+wire [15:0] cmax = div << { fdiv, 1'b0 };
+
+always @(posedge ref_clk) begin
+ if (fdiv != 2'b11) begin
+ if (cnt == cmax) begin
+ cnt <= 16'd0;
+ cen <= 1'b1;
+ end
+ else begin
+ cen <= 1'b0;
+ cnt <= cnt + 16'd1;
+ end
+ end
+end
+
+endmodule
diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/core.v b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/core.v
new file mode 100644
index 00000000..feafd69a
--- /dev/null
+++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/core.v
@@ -0,0 +1,662 @@
+//============================================================================
+//
+// Nichibutsu Galivan Hardware
+//
+// Original by (C) 2022 Pierre Cornier
+// Enhanced/optimized by (C) Gyorgy Szombathelyi
+//
+// 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 2 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.
+//
+//============================================================================
+module core(
+ input reset,
+ input clk_sys,
+ output ce_pix,
+ input pause,
+
+ input [7:0] j1,
+ input [7:0] j2,
+ input [7:0] p1,
+ input [7:0] p2,
+ input [7:0] system,
+
+ input [7:0] ioctl_index,
+ input ioctl_download,
+ input [26:0] ioctl_addr,
+ input [15:0] ioctl_dout,
+ input ioctl_wr,
+
+
+ output [2:0] red,
+ output [2:0] green,
+ output [1:0] blue,
+
+ output [15:0] sound,
+
+ input [8:0] hh,
+ input [8:0] vv,
+ input vs,
+ input hb,
+ output hflip,
+
+ input bg_on,
+ input tx_on,
+ input sp_on,
+
+ input [1:0] fdiv,
+
+ output cpu1_rom_cs,
+ output [15:0] cpu1_rom_addr,
+ input [7:0] cpu1_rom_q,
+ input cpu1_rom_valid,
+ output cpu2_rom_cs,
+ output [15:0] cpu2_rom_addr,
+ input [7:0] cpu2_rom_q,
+ input cpu2_rom_valid,
+
+ output [13:0] gfx1_rom_addr,
+ input [7:0] gfx1_rom_q,
+ output [16:0] gfx2_rom_addr,
+ input [7:0] gfx2_rom_q,
+ output [15:0] gfx3_rom_addr,
+ input [7:0] gfx3_rom_q,
+ input gfx3_rom_ready
+);
+
+
+/******** CLOCKS ********/
+
+wire clk_en_4, clk_en_6, acpu_irq_en;
+clk_en mcpu_clk_en(clk_sys, clk_en_6, 16'd7, fdiv);
+clk_en acpu_clk_en(clk_sys, clk_en_4, 16'd11);
+clk_en acpu_irq_cen(clk_sys, acpu_irq_en, 16'd6400);
+
+assign ce_pix = clk_en_6;
+
+/******** MCPU ********/
+
+wire [7:0] mcpu_din;
+wire [15:0] mcpu_addr;
+wire [7:0] mcpu_dout;
+wire mcpu_rd_n;
+wire mcpu_wr_n;
+wire mcpu_m1_n;
+wire mcpu_mreq_n;
+wire mcpu_iorq_n;
+wire mcpu_rfsh_n;
+reg mcpu_int_n;
+
+reg oldvs;
+always @(posedge clk_sys) begin
+ oldvs <= vs;
+ if (oldvs & ~vs) mcpu_int_n <= 1'b0;
+ if (~mcpu_iorq_n & ~mcpu_m1_n) mcpu_int_n <= 1'b1;
+end
+
+reg real_pause = 0;
+always @(posedge clk_sys)
+ if (~clk_en_6 & mcpu_mreq_n & mcpu_iorq_n) real_pause <= pause;
+
+
+t80s mcpu(
+ .reset_n ( ~reset ),
+ .clk ( clk_sys ),
+ .cen ( clk_en_6 & (!cpu1_rom_cs | cpu1_rom_valid) & !real_pause ),
+ .wait_n ( 1'b1 ),
+ .int_n ( mcpu_int_n ),
+ .nmi_n ( 1'b1 ),
+ .busrq_n ( 1'b1 ),
+ .m1_n ( mcpu_m1_n ),
+ .mreq_n ( mcpu_mreq_n ),
+ .iorq_n ( mcpu_iorq_n ),
+ .rd_n ( mcpu_rd_n ),
+ .wr_n ( mcpu_wr_n ),
+ .rfsh_n ( mcpu_rfsh_n ),
+ .halt_n ( ),
+ .busak_n ( ),
+ .A ( mcpu_addr ),
+ .di ( mcpu_din ),
+ .do ( mcpu_dout )
+);
+
+/******** MCPU MEMORY CS ********/
+
+wire mcpu_rom1_en = mcpu_iorq_n & ~mcpu_addr[15]; // (mcpu_addr < 16'h8000);
+wire mcpu_rom2_en = mcpu_iorq_n & mcpu_addr[15:14] == 2'b10; // ~mcpu_rom1_en & (mcpu_addr < 16'hc000);
+wire mcpu_rom_en = mcpu_iorq_n & (mcpu_rom1_en | mcpu_rom2_en);
+wire mcpu_bank_en = mcpu_iorq_n & /*mcpu_addr[15:13] == 3'b110; */ ~mcpu_rom_en & (mcpu_addr < 16'he000);
+wire mcpu_vram1_en = mcpu_iorq_n & /*mcpu_addr[15:10] == 5'b1101_10; */ ~mcpu_rom_en & mcpu_bank_en & (mcpu_addr >= 16'hd800 && mcpu_addr < 16'hdc00);
+wire mcpu_vram2_en = mcpu_iorq_n & /*mcpu_addr[15:10] == 5'b1101_11; */ ~mcpu_rom_en & mcpu_bank_en & (mcpu_addr >= 16'hdc00);
+wire mcpu_spr_en = mcpu_iorq_n & ~mcpu_rom_en & ~mcpu_bank_en & (mcpu_addr < 16'he100);
+wire mcpu_ram_en = mcpu_iorq_n & ~mcpu_rom_en & ~mcpu_bank_en & ~mcpu_spr_en;
+
+/******** MCPU MEMORIES ********/
+wire [9:0] gfx_vram_addr;
+wire [5:0] gfx_spr_addr;
+
+wire [7:0] mcpu_rom1_q;
+wire [7:0] mcpu_rom2_q;
+wire [7:0] mcpu_bank1_q;
+wire [7:0] mcpu_bank2_q;
+wire [7:0] mcpu_vram1_q;
+wire [7:0] mcpu_vram2_q;
+wire [7:0] mcpu_spr_q;
+wire [31:0] mcpu_spr_qb;
+wire [7:0] mcpu_ram_q;
+
+`ifndef EXT_ROM
+wire [7:0] mcpu_rom1_data = ioctl_dout[7:0];
+wire [14:0] mcpu_rom1_addr = ioctl_download ? ioctl_addr : mcpu_addr[14:0];
+wire mcpu_rom1_wren_a = ioctl_download && ioctl_addr < 27'h8000 ? ioctl_wr : 1'b0;
+wire [7:0] mcpu_rom2_data = ioctl_dout[7:0];
+wire [14:0] mcpu_rom2_addr = ioctl_download ? ioctl_addr - 27'h8000 : mcpu_addr[14:0];
+wire mcpu_rom2_wren_a = ioctl_download && ioctl_addr >= 27'h8000 && ioctl_addr < 27'hc000 ? ioctl_wr : 1'b0;
+wire [7:0] mcpu_bank1_data = ioctl_dout[7:0];
+wire [13:0] mcpu_bank1_addr = ioctl_download ? ioctl_addr - 27'hc000 : mcpu_addr[13:0];
+wire mcpu_bank1_wren_a = ioctl_download && ioctl_addr >= 27'hc000 && ioctl_addr < 27'he000 ? ioctl_wr : 1'b0;
+wire [7:0] mcpu_bank2_data = ioctl_dout[7:0];
+wire [13:0] mcpu_bank2_addr = ioctl_download ? ioctl_addr - 27'he000 : mcpu_addr[13:0];
+wire mcpu_bank2_wren_a = ioctl_download && ioctl_addr >= 27'he000 && ioctl_addr < 27'h10000 ? ioctl_wr : 1'b0;
+
+dpram #(15,8) mcpu_rom1(
+ .clock ( clk_sys ),
+ .address_a ( mcpu_rom1_addr ),
+ .data_a ( mcpu_rom1_data ),
+ .q_a ( mcpu_rom1_q ),
+ .rden_a ( 1'b1 ),
+ .wren_a ( mcpu_rom1_wren_a )
+);
+
+dpram #(14,8) mcpu_rom2(
+ .clock ( clk_sys ),
+ .address_a ( mcpu_rom2_addr ),
+ .data_a ( mcpu_rom2_data ),
+ .q_a ( mcpu_rom2_q ),
+ .rden_a ( 1'b1 ),
+ .wren_a ( mcpu_rom2_wren_a )
+);
+
+// 0xc000-0xdfff
+dpram #(14,8) mcpu_bank1(
+ .clock ( clk_sys ),
+ .address_a ( mcpu_bank1_addr ),
+ .data_a ( mcpu_bank1_data ),
+ .q_a ( mcpu_bank1_q ),
+ .rden_a ( 1'b1 ),
+ .wren_a ( mcpu_bank1_wren_a )
+);
+
+// 0xc000-0xdfff
+dpram #(14,8) mcpu_bank2(
+ .clock ( clk_sys ),
+ .address_a ( mcpu_bank2_addr ),
+ .data_a ( mcpu_bank2_data ),
+ .q_a ( mcpu_bank2_q ),
+ .rden_a ( 1'b1 ),
+ .wren_a ( mcpu_bank2_wren_a )
+);
+
+`else
+assign mcpu_rom1_q = cpu1_rom_q;
+assign mcpu_rom2_q = cpu1_rom_q;
+assign mcpu_bank1_q = cpu1_rom_q;
+assign mcpu_bank2_q = cpu1_rom_q;
+assign cpu1_rom_addr = mcpu_bank_en ? {bank ? 3'b111 : 3'b110, mcpu_addr[12:0]} : mcpu_addr;
+assign cpu1_rom_cs = (mcpu_rom_en | mcpu_bank_en) & mcpu_rfsh_n & ~mcpu_mreq_n;
+`endif
+
+// 0xd800-0xdbff (mcpu write only)
+dpram #(10,8) mcpu_vram1(
+ .clock ( clk_sys ),
+ .address_a ( mcpu_addr[9:0] ),
+ .address_b ( gfx_vram_addr ),
+ .data_a ( mcpu_dout ),
+ .q_b ( mcpu_vram1_q ),
+ .rden_b ( 1'b1 ),
+ .wren_a ( ~mcpu_wr_n & mcpu_vram1_en )
+);
+
+// 0xdc00-0xdfff (mcpu write only)
+dpram #(10,8) mcpu_vram2(
+ .clock ( clk_sys ),
+ .address_a ( mcpu_addr[9:0] ),
+ .address_b ( gfx_vram_addr ),
+ .data_a ( mcpu_dout ),
+ .q_b ( mcpu_vram2_q ),
+ .rden_b ( 1'b1 ),
+ .wren_a ( ~mcpu_wr_n & mcpu_vram2_en )
+);
+
+// 0xe000-0xe0ff
+// SPRAM is managed by the GFX module
+
+// 0xe100-0xffff
+dpram #(13,8) mcpu_ram(
+ .clock ( clk_sys ),
+ .address_a ( mcpu_addr[12:0] ),
+ .data_a ( mcpu_dout ),
+ .q_a ( mcpu_ram_q ),
+ .rden_a ( 1'b1 ),
+ .wren_a ( ~mcpu_wr_n & mcpu_ram_en )
+);
+
+/******** MCPU I/O ********/
+
+reg [7:0] mcpu_io_data;
+reg [10:0] scrollx;
+reg [10:0] scrolly;
+reg [2:0] layers;
+reg [7:0] snd_latch;
+reg clear_latch;
+reg bank;
+reg flip;
+assign hflip = flip;
+
+always @(posedge clk_sys) begin
+ reg [7:0] old_j1;
+ old_j1 <= j1;
+
+ if (clear_latch) snd_latch <= 8'd0;
+ if (~mcpu_iorq_n & mcpu_m1_n) begin
+ case (mcpu_addr[7:0])
+ 8'h00: mcpu_io_data <= j1;
+ 8'h01: mcpu_io_data <= j2;
+ 8'h02: mcpu_io_data <= system;
+ 8'h03: mcpu_io_data <= p1;
+ 8'h04: mcpu_io_data <= p2;
+ 8'h40: { bank, flip } <= { mcpu_dout[7], mcpu_dout[2] };
+ 8'h41: scrollx[7:0] <= mcpu_dout;
+ 8'h42: { layers, scrollx[10:8] } <= { mcpu_dout[7:5], mcpu_dout[2:0] };
+ 8'h43: scrolly[7:0] <= mcpu_dout;
+ 8'h44: scrolly[10:8] <= mcpu_dout[2:0];
+ 8'h45: snd_latch <= { mcpu_dout[6:0], 1'b1 };
+ 8'hc0: mcpu_io_data <= 8'h58;
+ endcase
+ end
+ // for scroll layer debug
+ if (real_pause) begin
+ if (~j1[0] & old_j1[0]) scrollx <= scrollx - 5'd16;
+ if (~j1[1] & old_j1[1]) scrollx <= scrollx + 5'd16;
+ if (~j1[2] & old_j1[2]) scrollx <= scrollx - 1'd1;
+ if (~j1[3] & old_j1[3]) scrollx <= scrollx + 1'd1;
+ end
+end
+
+/******** MCPU DATA BUS ********/
+
+assign mcpu_din =
+ ~mcpu_iorq_n ? mcpu_io_data :
+ mcpu_rom1_en ? mcpu_rom1_q :
+ mcpu_rom2_en ? mcpu_rom2_q :
+ mcpu_bank_en & ~bank ? mcpu_bank1_q :
+ mcpu_bank_en & bank ? mcpu_bank2_q :
+ mcpu_spr_en ? mcpu_spr_q :
+ mcpu_ram_en ? mcpu_ram_q : 8'd0;
+
+/******** ACPU ********/
+
+wire [7:0] acpu_din;
+wire [15:0] acpu_addr;
+wire [7:0] acpu_dout;
+wire acpu_rd_n;
+wire acpu_wr_n;
+wire acpu_m1_n;
+wire acpu_mreq_n;
+wire acpu_iorq_n;
+wire acpu_rfsh_n;
+reg acpu_int_n;
+
+reg old_acpu_irq_en;
+always @(posedge clk_sys) begin
+ old_acpu_irq_en <= acpu_irq_en;
+ if (~old_acpu_irq_en & acpu_irq_en) acpu_int_n <= 1'b0;
+ if (~acpu_iorq_n & ~acpu_m1_n) acpu_int_n <= 1'b1;
+end
+
+t80s acpu(
+ .reset_n ( ~reset ),
+ .clk ( clk_sys ),
+ .cen ( clk_en_4 & (!cpu2_rom_cs | cpu2_rom_valid) ),
+ .wait_n ( 1'b1 ),
+ .int_n ( acpu_int_n ),
+ .nmi_n ( 1'b1 ),
+ .busrq_n ( 1'b1 ),
+ .m1_n ( acpu_m1_n ),
+ .mreq_n ( acpu_mreq_n ),
+ .iorq_n ( acpu_iorq_n ),
+ .rd_n ( acpu_rd_n ),
+ .wr_n ( acpu_wr_n ),
+ .rfsh_n ( acpu_rfsh_n ),
+ .halt_n ( ),
+ .busak_n ( ),
+ .A ( acpu_addr ),
+ .di ( acpu_din ),
+ .do ( acpu_dout )
+);
+
+
+/******** ACPU MEMORY CS ********/
+
+wire acpu_rom1_en = acpu_iorq_n & ~acpu_addr[15]; // acpu_addr < 16'h8000;
+wire acpu_rom2_en = acpu_iorq_n & acpu_addr[15:14] == 2'b10; //~acpu_rom1_en & acpu_addr < 16'hc000;
+wire acpu_ram_en = acpu_iorq_n & acpu_addr[15:14] == 2'b11; //~acpu_rom1_en & ~acpu_rom2_en;
+
+/******** ACPU MEMORIES ********/
+wire [7:0] acpu_ram_q;
+wire [7:0] acpu_rom1_q;
+wire [7:0] acpu_rom2_q;
+
+`ifndef EXT_ROM
+wire [7:0] acpu_rom_data = ioctl_dout;
+wire [15:0] acpu_rom1_addr = ioctl_download ? ioctl_addr - 27'h10000 : acpu_addr;
+wire acpu_rom1_wren_a = ioctl_download && ioctl_addr >= 27'h10000 && ioctl_addr < 27'h18000 ? ioctl_wr : 1'b0;
+wire [15:0] acpu_rom2_addr = ioctl_download ? ioctl_addr - 27'h18000 : acpu_addr;
+wire acpu_rom2_wren_a = ioctl_download && ioctl_addr >= 27'h18000 && ioctl_addr < 27'h1c000 ? ioctl_wr : 1'b0;
+
+dpram #(15,8) acpu_rom1(
+ .clock ( clk_sys ),
+ .address_a ( acpu_rom1_addr ),
+ .data_a ( acpu_rom_data ),
+ .q_a ( acpu_rom1_q ),
+ .rden_a ( 1'b1 ),
+ .wren_a ( acpu_rom1_wren_a )
+);
+
+dpram #(14,8) acpu_rom2(
+ .clock ( clk_sys ),
+ .address_a ( acpu_rom2_addr ),
+ .data_a ( acpu_rom_data ),
+ .q_a ( acpu_rom2_q ),
+ .rden_a ( 1'b1 ),
+ .wren_a ( acpu_rom2_wren_a )
+);
+`else
+assign cpu2_rom_addr = acpu_addr;
+assign cpu2_rom_cs = (acpu_rom1_en | acpu_rom2_en) & acpu_rfsh_n & ~acpu_mreq_n;
+assign acpu_rom1_q = cpu2_rom_q;
+assign acpu_rom2_q = cpu2_rom_q;
+`endif
+
+dpram #(11,8) acpu_ram(
+ .clock ( clk_sys ),
+ .address_a ( acpu_addr[10:0] ),
+ .data_a ( acpu_dout ),
+ .q_a ( acpu_ram_q ),
+ .rden_a ( 1'b1 ),
+ .wren_a ( ~acpu_wr_n & acpu_ram_en )
+);
+
+/******** ACPU I/O ********/
+reg [7:0] dac1, dac2;
+always @(posedge clk_sys) begin
+ clear_latch <= 1'b0;
+ if (~acpu_iorq_n & acpu_m1_n & ~acpu_wr_n) begin
+ case (acpu_addr[7:0])
+ 8'h02: dac1 <= acpu_dout;
+ 8'h03: dac2 <= acpu_dout;
+ 8'h04: clear_latch <= 1'b1;
+ default: ;
+ endcase
+ end
+end
+wire snd_latch_cs = ~acpu_iorq_n & acpu_m1_n & acpu_addr[7:0] == 8'h06;
+
+/******** YM3526 ********/
+
+wire ym3526_addr = acpu_addr[0];
+wire ym3526_cs = ~acpu_iorq_n & acpu_m1_n & acpu_addr[7:1] == 0;
+
+jtopl ym3526(
+ .rst ( reset ),
+ .clk ( clk_sys ),
+ .cen ( clk_en_4 ),
+ .din ( acpu_dout ),
+ .addr ( ym3526_addr ),
+ .cs_n ( ~ym3526_cs ),
+ .wr_n ( acpu_wr_n ),
+ .dout ( ),
+ .irq_n ( ),
+ .snd ( ym_sound ),
+ .sample ( )
+);
+wire [15:0] ym_sound;
+assign sound = ym_sound + {dac1, 5'd0} + {dac2, 5'd0};
+
+/******** ACPU DATA BUS ********/
+
+assign acpu_din =
+ snd_latch_cs ? snd_latch :
+ acpu_ram_en ? acpu_ram_q :
+ acpu_rom1_en ? acpu_rom1_q :
+ acpu_rom2_en ? acpu_rom2_q :
+ 8'hFF; // RST38h - important, as the code mistakenly enables interrupts in IM0 mode
+
+/********* GFX ********/
+
+wire [13:0] gfx1_addr;
+wire [16:0] gfx2_addr;
+wire [15:0] gfx3_addr;
+wire [13:0] gfx4_addr;
+
+wire [7:0] gfx_rom1_q;
+wire [7:0] gfx_rom2_q;
+wire [7:0] gfx_rom3_q;
+wire [7:0] gfx_rom41_q;
+wire [7:0] gfx_rom42_q;
+
+wire [7:0] gfx_prom_addr;
+wire [7:0] gfx_prom4_addr;
+wire [7:0] gfx_sprom_addr;
+
+wire [3:0] prom1_q;
+wire [3:0] prom2_q;
+wire [3:0] prom3_q;
+wire [3:0] prom4_q;
+wire [3:0] sprom_q;
+
+wire [2:0] r;
+wire [2:0] g;
+wire [1:0] b;
+
+gfx gfx(
+
+ .clk ( clk_sys ),
+ .ce_pix ( ce_pix ),
+ .hh ( hh ),
+ .vv ( vv ),
+
+ .scrollx ( scrollx ),
+ .scrolly ( scrolly ),
+ .layers ( layers ),
+
+ .spram_addr ( mcpu_addr[7:0] ),
+ .spram_din ( mcpu_dout ),
+ .spram_dout ( mcpu_spr_q ),
+ .spram_wr ( ~mcpu_wr_n & mcpu_spr_en ),
+
+ .bg_map_addr ( gfx4_addr ),
+ .bg_map_data ( gfx_rom41_q ),
+ .bg_attr_data ( gfx_rom42_q ),
+ .bg_tile_addr ( gfx2_addr ),
+ .bg_tile_data ( gfx_rom2_q ),
+
+ .vram_addr ( gfx_vram_addr ),
+ .vram1_data ( mcpu_vram1_q ),
+ .vram2_data ( mcpu_vram2_q ),
+ .tx_tile_addr ( gfx1_addr ),
+ .tx_tile_data ( gfx_rom1_q ),
+
+
+ .spr_gfx_addr ( gfx3_addr ),
+ .spr_gfx_data ( gfx_rom3_q ),
+ .spr_gfx_rdy ( gfx3_rom_ready ),
+ .spr_bnk_addr ( gfx_sprom_addr ),
+ .spr_bnk_data ( sprom_q ),
+ .spr_lut_addr ( gfx_prom4_addr ),
+ .spr_lut_data ( prom4_q ),
+
+ .prom_addr ( gfx_prom_addr ),
+ .prom1_data ( prom1_q ),
+ .prom2_data ( prom2_q ),
+ .prom3_data ( prom3_q ),
+
+ .r ( red ),
+ .g ( green ),
+ .b ( blue ),
+ .h_flip ( flip ),
+ .v_flip ( flip ),
+
+ .hb ( hb ),
+
+ .bg_on ( bg_on ),
+ .tx_on ( tx_on ),
+ .sp_on ( sp_on )
+
+);
+
+/******** GFX ROMs ********/
+wire [7:0] gfx_rom_data = ioctl_dout;
+
+`ifndef EXT_ROM
+wire [13:0] gfx_rom1_addr = ioctl_download ? ioctl_addr - 27'h1c000 : gfx1_addr;
+wire gfx_rom1_wren_a = ioctl_download && ioctl_addr >= 27'h1c000 && ioctl_addr < 27'h20000 ? ioctl_wr : 1'b0;
+wire [16:0] gfx_rom2_addr = ioctl_download ? ioctl_addr - 27'h20000 : gfx2_addr;
+wire gfx_rom2_wren_a = ioctl_download && ioctl_addr >= 27'h20000 && ioctl_addr < 27'h40000 ? ioctl_wr : 1'b0;
+wire [15:0] gfx_rom3_addr = ioctl_download ? ioctl_addr - 27'h40000 : gfx3_addr;
+wire gfx_rom3_wren_a = ioctl_download && ioctl_addr >= 27'h40000 && ioctl_addr < 27'h50000 ? ioctl_wr : 1'b0;
+
+dpram #(14,8) gfx_rom1(
+ .clock ( clk_sys ),
+ .address_a ( gfx_rom1_addr ),
+ .data_a ( gfx_rom_data ),
+ .q_a ( gfx_rom1_q ),
+ .rden_a ( 1'b1 ),
+ .wren_a ( gfx_rom1_wren_a )
+);
+
+dpram #(17,8) gfx_rom2(
+ .clock ( clk_sys ),
+ .address_a ( gfx_rom2_addr ),
+ .data_a ( gfx_rom_data ),
+ .q_a ( gfx_rom2_q ),
+ .rden_a ( 1'b1 ),
+ .wren_a ( gfx_rom2_wren_a )
+);
+
+dpram #(16,8) gfx_rom3(
+ .clock ( clk_sys ),
+ .address_a ( gfx_rom3_addr ),
+ .data_a ( gfx_rom_data ),
+ .q_a ( gfx_rom3_q ),
+ .rden_a ( 1'b1 ),
+ .wren_a ( gfx_rom3_wren_a )
+);
+
+`else
+
+assign gfx1_rom_addr = gfx1_addr;
+assign gfx_rom1_q = gfx1_rom_q;
+assign gfx2_rom_addr = gfx2_addr;
+assign gfx_rom2_q = gfx2_rom_q;
+assign gfx3_rom_addr = gfx3_addr;
+assign gfx_rom3_q = gfx3_rom_q;
+
+`endif
+
+wire [13:0] gfx_rom41_addr = ioctl_download ? ioctl_addr - 27'h50000 : gfx4_addr;
+wire gfx_rom41_wren_a = ioctl_download && ioctl_addr >= 27'h50000 && ioctl_addr < 27'h54000 ? ioctl_wr : 1'b0;
+wire [13:0] gfx_rom42_addr = ioctl_download ? ioctl_addr - 27'h54000 : gfx4_addr;
+wire gfx_rom42_wren_a = ioctl_download && ioctl_addr >= 27'h54000 && ioctl_addr < 27'h58000 ? ioctl_wr : 1'b0;
+
+dpram #(14,8) gfx_rom41(
+ .clock ( clk_sys ),
+ .address_a ( gfx_rom41_addr ),
+ .data_a ( gfx_rom_data ),
+ .q_a ( gfx_rom41_q ),
+ .rden_a ( 1'b1 ),
+ .wren_a ( gfx_rom41_wren_a )
+);
+
+dpram #(14,8) gfx_rom42(
+ .clock ( clk_sys ),
+ .address_a ( gfx_rom42_addr ),
+ .data_a ( gfx_rom_data ),
+ .q_a ( gfx_rom42_q ),
+ .rden_a ( 1'b1 ),
+ .wren_a ( gfx_rom42_wren_a )
+);
+
+/******** COLOR ROMs ********/
+
+wire [7:0] prom1_addr = ioctl_download ? ioctl_addr - 27'h58000 : gfx_prom_addr;
+wire prom1_wren_a = ioctl_download && ioctl_addr >= 27'h58000 && ioctl_addr < 27'h58100 ? ioctl_wr : 1'b0;
+wire [7:0] prom2_addr = ioctl_download ? ioctl_addr - 27'h58100 : gfx_prom_addr;
+wire prom2_wren_a = ioctl_download && ioctl_addr >= 27'h58100 && ioctl_addr < 27'h58200 ? ioctl_wr : 1'b0;
+wire [7:0] prom3_addr = ioctl_download ? ioctl_addr - 27'h58200 : gfx_prom_addr;
+wire prom3_wren_a = ioctl_download && ioctl_addr >= 27'h58200 && ioctl_addr < 27'h58300 ? ioctl_wr : 1'b0;
+
+wire [7:0] prom4_addr = ioctl_download ? ioctl_addr - 27'h58300 : gfx_prom4_addr;
+wire prom4_wren_a = ioctl_download && ioctl_addr >= 27'h58300 && ioctl_addr < 27'h58400 ? ioctl_wr : 1'b0;
+wire [7:0] sprom_addr = ioctl_download ? ioctl_addr - 27'h58400 : gfx_sprom_addr;
+wire sprom_wren_a = ioctl_download && ioctl_addr >= 27'h58400 && ioctl_addr < 27'h58500 ? ioctl_wr : 1'b0;
+
+dpram #(8,4) prom1(
+ .clock ( clk_sys ),
+ .address_a ( prom1_addr ),
+ .data_a ( gfx_rom_data ),
+ .q_a ( prom1_q ),
+ .rden_a ( 1'b1 ),
+ .wren_a ( prom1_wren_a )
+);
+
+dpram #(8,4) prom2(
+ .clock ( clk_sys ),
+ .address_a ( prom2_addr ),
+ .data_a ( gfx_rom_data ),
+ .q_a ( prom2_q ),
+ .rden_a ( 1'b1 ),
+ .wren_a ( prom2_wren_a )
+);
+
+dpram #(8,4) prom3(
+ .clock ( clk_sys ),
+ .address_a ( prom3_addr ),
+ .data_a ( gfx_rom_data ),
+ .q_a ( prom3_q ),
+ .rden_a ( 1'b1 ),
+ .wren_a ( prom3_wren_a )
+);
+
+// sprite color lut
+dpram #(8,4) slookup(
+ .clock ( clk_sys ),
+ .address_a ( prom4_addr ),
+ .data_a ( gfx_rom_data ),
+ .q_a ( prom4_q ),
+ .rden_a ( 1'b1 ),
+ .wren_a ( prom4_wren_a )
+);
+
+// sprite color bank info
+dpram #(8,4) sprom(
+ .clock ( clk_sys ),
+ .address_a ( sprom_addr ),
+ .data_a ( gfx_rom_data ),
+ .q_a ( sprom_q ),
+ .rden_a ( 1'b1 ),
+ .wren_a ( sprom_wren_a )
+);
+
+endmodule
diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/dpram.v b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/dpram.v
new file mode 100644
index 00000000..e5e87fbc
--- /dev/null
+++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/dpram.v
@@ -0,0 +1,137 @@
+// megafunction wizard: %RAM: 2-PORT%
+// GENERATION: STANDARD
+// VERSION: WM1.0
+// MODULE: altsyncram
+
+// ============================================================
+// File Name: dpram.v
+// Megafunction Name(s):
+// altsyncram
+//
+// Simulation Library Files(s):
+// altera_mf
+// ============================================================
+// ************************************************************
+// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
+//
+// 17.0.0 Build 595 04/25/2017 SJ Lite Edition
+// ************************************************************
+
+
+//Copyright (C) 2017 Intel Corporation. All rights reserved.
+//Your use of Intel 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 Intel Program License
+//Subscription Agreement, the Intel Quartus Prime License Agreement,
+//the Intel 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 Intel and sold by Intel 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 dpram
+#(
+ parameter ADDRWIDTH=12,
+ parameter DATAWIDTH=8
+)
+(
+ address_a,
+ address_b,
+ clock,
+ data_a,
+ data_b,
+ wren_a,
+ wren_b,
+ rden_a,
+ rden_b,
+ q_a,
+ q_b);
+
+ input [ADDRWIDTH-1:0] address_a;
+ input [ADDRWIDTH-1:0] address_b;
+ input clock;
+ input [DATAWIDTH-1:0] data_a;
+ input [DATAWIDTH-1:0] data_b;
+ input wren_a;
+ input wren_b;
+ input rden_a;
+ input rden_b;
+ output [DATAWIDTH-1:0] q_a;
+ output [DATAWIDTH-1:0] q_b;
+`ifndef ALTERA_RESERVED_QIS
+// synopsys translate_off
+`endif
+ tri1 clock;
+ tri0 wren_a;
+ tri0 wren_b;
+`ifndef ALTERA_RESERVED_QIS
+// synopsys translate_on
+`endif
+
+ wire [DATAWIDTH-1:0] sub_wire0;
+ wire [DATAWIDTH-1:0] sub_wire1;
+ wire [DATAWIDTH-1:0] q_a = rden_a ? sub_wire0[DATAWIDTH-1:0] : {DATAWIDTH{1'b0}};
+ wire [DATAWIDTH-1:0] q_b = rden_b ? sub_wire1[DATAWIDTH-1:0] : {DATAWIDTH{1'b0}};
+
+ altsyncram altsyncram_component (
+ .address_a (address_a),
+ .address_b (address_b),
+ .clock0 (clock),
+ .data_a (data_a),
+ .data_b (data_b),
+ .wren_a (wren_a),
+ .wren_b (wren_b),
+ .q_a (sub_wire0),
+ .q_b (sub_wire1),
+ .aclr0 (1'b0),
+ .aclr1 (1'b0),
+ .addressstall_a (1'b0),
+ .addressstall_b (1'b0),
+ .byteena_a (1'b1),
+ .byteena_b (1'b1),
+ .clock1 (1'b1),
+ .clocken0 (1'b1),
+ .clocken1 (1'b1),
+ .clocken2 (1'b1),
+ .clocken3 (1'b1),
+ .eccstatus (),
+ .rden_a (1'b1),
+ .rden_b (1'b1));
+ defparam
+ altsyncram_component.address_reg_b = "CLOCK0",
+ altsyncram_component.clock_enable_input_a = "BYPASS",
+ altsyncram_component.clock_enable_input_b = "BYPASS",
+ altsyncram_component.clock_enable_output_a = "BYPASS",
+ altsyncram_component.clock_enable_output_b = "BYPASS",
+ altsyncram_component.indata_reg_b = "CLOCK0",
+ altsyncram_component.intended_device_family = "Cyclone V",
+ altsyncram_component.lpm_type = "altsyncram",
+ altsyncram_component.numwords_a = 2**ADDRWIDTH,
+ altsyncram_component.numwords_b = 2**ADDRWIDTH,
+ altsyncram_component.operation_mode = "BIDIR_DUAL_PORT",
+ altsyncram_component.outdata_aclr_a = "NONE",
+ altsyncram_component.outdata_aclr_b = "NONE",
+ altsyncram_component.outdata_reg_a = "CLOCK0",
+ altsyncram_component.outdata_reg_b = "CLOCK0",
+ altsyncram_component.power_up_uninitialized = "FALSE",
+ altsyncram_component.read_during_write_mode_mixed_ports = "DONT_CARE",
+ altsyncram_component.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ",
+ altsyncram_component.read_during_write_mode_port_b = "NEW_DATA_NO_NBE_READ",
+ altsyncram_component.widthad_a = ADDRWIDTH,
+ altsyncram_component.widthad_b = ADDRWIDTH,
+ altsyncram_component.width_a = DATAWIDTH,
+ altsyncram_component.width_b = DATAWIDTH,
+ altsyncram_component.width_byteena_a = 1,
+ altsyncram_component.width_byteena_b = 1,
+ altsyncram_component.wrcontrol_wraddress_reg_b = "CLOCK0";
+
+
+endmodule
diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/gfx.v b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/gfx.v
new file mode 100644
index 00000000..ed0cd099
--- /dev/null
+++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/gfx.v
@@ -0,0 +1,327 @@
+//============================================================================
+//
+// Nichibutsu Galivan Hardware
+//
+// Original by (C) 2022 Pierre Cornier
+// Enhanced/optimized by (C) Gyorgy Szombathelyi
+//
+// 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 2 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.
+//
+//============================================================================
+
+module gfx(
+ input clk,
+ input ce_pix,
+
+ input [8:0] hh,
+ input [8:0] vv,
+
+ input [10:0] scrollx,
+ input [10:0] scrolly,
+ input [2:0] layers,
+
+ // mcpu sprite ram interface
+ input [7:0] spram_addr,
+ input [7:0] spram_din,
+ output reg [7:0] spram_dout,
+ input spram_wr,
+
+ output reg [13:0] bg_map_addr,
+ input [7:0] bg_map_data,
+ input [7:0] bg_attr_data,
+
+ output reg [16:0] bg_tile_addr,
+ input [7:0] bg_tile_data,
+
+ output reg [10:0] vram_addr,
+ input [7:0] vram1_data,
+ input [7:0] vram2_data,
+
+ output reg [13:0] tx_tile_addr,
+ input [7:0] tx_tile_data,
+
+ output reg [7:0] prom_addr,
+ input [3:0] prom1_data,
+ input [3:0] prom2_data,
+ input [3:0] prom3_data,
+
+ output reg [15:0] spr_gfx_addr,
+ input [7:0] spr_gfx_data,
+ input spr_gfx_rdy,
+
+ output reg [7:0] spr_bnk_addr,
+ input [3:0] spr_bnk_data,
+
+ output reg [7:0] spr_lut_addr,
+ input [3:0] spr_lut_data,
+
+ output reg [2:0] r, g,
+ output reg [1:0] b,
+
+ input h_flip,
+ input v_flip,
+
+ input hb,
+
+ input bg_on,
+ input tx_on,
+ input sp_on
+
+);
+
+// object RAM
+// 4 bytes/sprite
+// offset 0 - Y
+// offset 1 - code[7:0]
+// offset 2 - attr
+// offset 3 - X
+
+reg [7:0] info[255:0];
+reg [7:0] smap[255:0]; // object ram copy
+
+wire [8:0] vh = v_flip ? {vv[8], ~vv[7:0]} : vv;
+wire [8:0] hr = h_flip ? {hh[8], ~hh[7:0]} : hh;
+
+// line buffers
+reg spbuf_wren_a;
+reg [8:0] spbuf_addr_a;
+reg [5:0] spbuf_data_a;
+wire [5:0] spbuf_q_b;
+wire [8:0] hr_sp = hr - (h_flip ? -4'd13 : 4'd13);
+
+dpram #(9,6) spbuf(
+ .clock ( clk ),
+ .address_a ( spbuf_addr_a ),
+ .data_a ( spbuf_data_a ),
+ .q_a ( ),
+ .rden_a ( 1'b0 ),
+ .wren_a ( spbuf_wren_a ),
+
+ .address_b ( { ~vh[0], hr_sp[7:0] } ),
+ .data_b ( 6'h3f ),
+ .q_b ( spbuf_q_b ),
+ .rden_b ( 1'b1 ),
+ .wren_b ( ce_pix & ~hr_sp[8] )
+);
+
+// sprite registers
+
+reg [3:0] sp_next;
+reg [3:0] sp_state;
+reg [7:0] spri;
+
+reg [7:0] attr;
+reg [8:0] spx;
+reg [7:0] spy;
+reg [8:0] code;
+
+wire [7:0] smap_q = smap[spri];
+wire [8:0] spy_next = v_flip ? smap_q - 1'd1 : 8'd239 - smap_q;
+wire [7:0] spxa = spx[7:0] - 8'd128;
+wire [7:0] sdy = vv - spy;
+wire [3:0] sdyf = (!v_flip ^ attr[7]) ? sdy[3:0] : 4'd15 - sdy[3:0];
+reg [3:0] sdx;
+wire [3:0] sdxf = attr[6] ? 4'd15 - sdx[3:0] : sdx[3:0];
+wire [3:0] sp_color_code = spr_gfx_data[sdx[0]*4+:4];
+
+// bg registers
+reg [10:0] scx_reg;
+reg [10:0] scy_reg;
+reg [7:0] bg_attr_data_d;
+reg [7:0] bg_attr_data_d2;
+reg [7:0] bg_tile_data_d;
+wire [10:0] sh = {h_flip & hr[8], h_flip & hr[8], hr} + scx_reg;
+wire [10:0] sv = vh + scy_reg;
+wire [3:0] bg_color_code = bg_tile_data_d[sh[0]*4+:4];
+
+// txt registers
+reg [7:0] vram2_data_d;
+reg [7:0] vram2_data_d2;
+reg [7:0] tx_tile_data_d;
+wire [3:0] tx_color_code = tx_tile_data_d[hr[0]*4+:4];
+
+reg color_ok;
+reg [3:0] rstate;
+reg [3:0] rnext;
+reg [5:0] bg, tx;
+
+reg [7:0] smap_addr;
+reg copied;
+
+// sprite rendering to dual-line buffer
+always @(posedge clk) begin
+
+ spram_dout <= info[spram_addr];
+ if (spram_wr) info[spram_addr] <= spram_din;
+
+ if (vv == 0 && hh == 0) begin
+ scx_reg <= scrollx;
+ scy_reg <= scrolly;
+ copied = 1'b0;
+ end
+
+ if (vv > 250 && ~copied) begin
+ smap[smap_addr] <= info[smap_addr];
+ smap_addr <= smap_addr + 8'd1;
+ if (smap_addr == 8'd255) copied <= 1'b1;
+ end
+
+ spbuf_wren_a <= 0;
+ case (sp_state)
+
+ 4'd0: begin
+ spri <= 8'd0;
+ sp_state <= (hh == 0 && vv < 256 && sp_on) ? 4'd1 : 4'd0;
+ end
+
+ 4'd1: begin
+ spy <= spy_next; // spri=0
+ if (vv >= spy_next && vv < (spy_next+16)) begin
+ // sprite is visible
+ sp_state <= 4'd2;
+ spri <= spri + 1'd1;
+ end
+ else begin
+ // not visible, check next or finish
+ if (spri == 8'd252) sp_state <= 4'd0;
+ else spri <= spri + 4'd4;
+ end
+ end
+
+ 4'd2: begin
+ code[7:0] <= smap_q; // spri=1
+ spri <= spri + 1'd1;
+ sp_state <= 4'd3;
+ end
+
+ 4'd3: begin
+ attr <= smap_q; // spri=2
+ spri <= spri + 1'd1;
+ sp_state <= 4'd4;
+ end
+
+ 4'd4: begin
+ spx <= { attr[0], smap_q }; // range is 0-511 visible area is 128-383 (spri=3)
+ code[8] <= attr[1];
+ spri <= spri + 1'd1;
+ sp_state <= 4'd5;
+ sdx <= 4'd0;
+ end
+
+ 4'd5: begin
+ spr_gfx_addr <= { sdx[1], code, sdyf[3:0], sdx[3:2] };
+ spr_bnk_addr <= code[8:2];
+`ifdef EXT_ROM
+ if (spr_gfx_rdy) sp_state <= 4'd6;
+`else
+ sp_state <= 4'd14; // for internal ROMs only
+ sp_next <= 4'd6;
+`endif
+ end
+
+ 4'd6: begin
+ spr_lut_addr <= { spr_bnk_data, sp_color_code };
+ sp_state <= 4'd14;
+ sp_next <= 4'd7;
+ end
+
+ 4'd7: begin
+ if (spx+sdxf > 128 && spx+sdxf < 256+128 && spr_lut_data != 4'hf) begin
+ spbuf_addr_a <= { vh[0], spxa+sdxf };
+ spbuf_data_a <= { (spr_lut_data[3] ? spr_bnk_data[3:2] : spr_bnk_data[1:0]), sp_color_code };
+ spbuf_wren_a <= 1;
+ end
+
+ sdx <= sdx + 4'd1;
+ sp_state <= sdx[0] ? 4'd5 : 4'd6;
+ if (sdx == 4'd15) begin
+ sp_state <= spri == 0 ? 4'd0 : 4'd1;
+ end
+ end
+
+ 4'd14: sp_state <= 4'd15;
+ 4'd15: sp_state <= sp_next;
+
+ endcase
+end
+
+// scrolling background layer
+always @(posedge clk) begin
+ if (ce_pix) begin
+ if(sh[2:0] == (3'b111 ^ {3{h_flip}}))
+ bg_map_addr <= {sv[10:4], sh[10:4]};
+ if(sh[0] ^ h_flip) begin
+ bg_tile_addr <= { bg_attr_data[1:0], bg_map_data, sv[3:0], ~sh[3], sh[2:1] };
+ bg_tile_data_d <= bg_tile_data;
+ bg_attr_data_d <= bg_attr_data;
+ bg_attr_data_d2 <= bg_attr_data_d;
+ end
+ bg <= { (bg_color_code[3] ? bg_attr_data_d2[6:5] : bg_attr_data_d2[4:3]), bg_color_code };
+ end
+end
+
+// text layer
+always @(posedge clk) begin
+ if (ce_pix) begin
+ if(hh[2:0] == 3'b111)
+ vram_addr <= { hr[7:3], vh[7:3] };
+ if(hh[0]) begin
+ tx_tile_addr <= { vram2_data[0], vram1_data, vh[2:0], hr[2:1] };
+ tx_tile_data_d <= tx_tile_data;
+ vram2_data_d <= vram2_data;
+ vram2_data_d2 <= vram2_data_d;
+ end
+ tx <= { (tx_color_code[3] ? vram2_data_d2[6:5] : vram2_data_d2[4:3]), tx_color_code };
+ end
+end
+
+// display output
+always @(posedge clk) begin
+ if (ce_pix) begin
+
+ color_ok <= 1'b0;
+
+ if (~layers[1]) begin
+ prom_addr <= { 2'b11, bg };
+ color_ok <= 1'b1;
+ end
+
+ if (spbuf_q_b[3:0] != 4'hf) begin
+ prom_addr <= { 2'b10, spbuf_q_b };
+ color_ok <= 1'b1;
+ end
+
+ if (~layers[2] && tx[3:0] != 4'hf) begin
+ prom_addr <= { 2'b00, tx };
+ color_ok <= 1'b1;
+ end
+
+ if (layers[0] && spbuf_q_b[3:0] != 4'hf) begin
+ prom_addr <= { 2'b10, spbuf_q_b };
+ color_ok <= 1'b1;
+ end
+
+ if (color_ok) begin
+ r <= prom1_data[3:1];
+ g <= prom2_data[3:1];
+ b <= prom3_data[3:2];
+ end
+ else begin
+ { r, g, b } <= 8'd0;
+ end
+ end
+end
+
+endmodule
diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/pll_mist.qip b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/pll_mist.qip
new file mode 100644
index 00000000..d4720390
--- /dev/null
+++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/pll_mist.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 VHDL_FILE [file join $::quartus(qip_path) "pll_mist.vhd"]
+set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll_mist.ppf"]
diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/pll_mist.vhd b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/pll_mist.vhd
new file mode 100644
index 00000000..76244b2d
--- /dev/null
+++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/pll_mist.vhd
@@ -0,0 +1,392 @@
+-- megafunction wizard: %ALTPLL%
+-- GENERATION: STANDARD
+-- VERSION: WM1.0
+-- MODULE: altpll
+
+-- ============================================================
+-- File Name: pll_mist.vhd
+-- 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 Web Edition
+-- ************************************************************
+
+
+--Copyright (C) 1991-2014 Altera Corporation
+--Your use of Altera Corporation's design tools, logic functions
+--and other software and tools, and its AMPP partner logic
+--functions, and any output files from any of the foregoing
+--(including device programming or simulation files), and any
+--associated documentation or information are expressly subject
+--to the terms and conditions of the Altera Program License
+--Subscription Agreement, Altera MegaCore Function License
+--Agreement, or other applicable license agreement, including,
+--without limitation, that your use is for the sole purpose of
+--programming logic devices manufactured by Altera and sold by
+--Altera or its authorized distributors. Please refer to the
+--applicable agreement for further details.
+
+
+LIBRARY ieee;
+USE ieee.std_logic_1164.all;
+
+LIBRARY altera_mf;
+USE altera_mf.all;
+
+ENTITY pll_mist IS
+ PORT
+ (
+ inclk0 : IN STD_LOGIC := '0';
+ c0 : OUT STD_LOGIC ;
+ c1 : OUT STD_LOGIC ;
+ locked : OUT STD_LOGIC
+ );
+END pll_mist;
+
+
+ARCHITECTURE SYN OF pll_mist IS
+
+ SIGNAL sub_wire0 : STD_LOGIC_VECTOR (4 DOWNTO 0);
+ SIGNAL sub_wire1 : STD_LOGIC ;
+ SIGNAL sub_wire2 : STD_LOGIC ;
+ SIGNAL sub_wire3 : STD_LOGIC ;
+ SIGNAL sub_wire4 : STD_LOGIC ;
+ SIGNAL sub_wire5 : STD_LOGIC_VECTOR (1 DOWNTO 0);
+ SIGNAL sub_wire6_bv : BIT_VECTOR (0 DOWNTO 0);
+ SIGNAL sub_wire6 : STD_LOGIC_VECTOR (0 DOWNTO 0);
+
+
+
+ COMPONENT altpll
+ GENERIC (
+ bandwidth_type : STRING;
+ clk0_divide_by : NATURAL;
+ clk0_duty_cycle : NATURAL;
+ clk0_multiply_by : NATURAL;
+ clk0_phase_shift : STRING;
+ clk1_divide_by : NATURAL;
+ clk1_duty_cycle : NATURAL;
+ clk1_multiply_by : NATURAL;
+ clk1_phase_shift : STRING;
+ compensate_clock : STRING;
+ inclk0_input_frequency : NATURAL;
+ intended_device_family : STRING;
+ lpm_hint : STRING;
+ lpm_type : STRING;
+ operation_mode : STRING;
+ pll_type : STRING;
+ port_activeclock : STRING;
+ port_areset : STRING;
+ port_clkbad0 : STRING;
+ port_clkbad1 : STRING;
+ port_clkloss : STRING;
+ port_clkswitch : STRING;
+ port_configupdate : STRING;
+ port_fbin : STRING;
+ port_inclk0 : STRING;
+ port_inclk1 : STRING;
+ port_locked : STRING;
+ port_pfdena : STRING;
+ port_phasecounterselect : STRING;
+ port_phasedone : STRING;
+ port_phasestep : STRING;
+ port_phaseupdown : STRING;
+ port_pllena : STRING;
+ port_scanaclr : STRING;
+ port_scanclk : STRING;
+ port_scanclkena : STRING;
+ port_scandata : STRING;
+ port_scandataout : STRING;
+ port_scandone : STRING;
+ port_scanread : STRING;
+ port_scanwrite : STRING;
+ port_clk0 : STRING;
+ port_clk1 : STRING;
+ port_clk2 : STRING;
+ port_clk3 : STRING;
+ port_clk4 : STRING;
+ port_clk5 : STRING;
+ port_clkena0 : STRING;
+ port_clkena1 : STRING;
+ port_clkena2 : STRING;
+ port_clkena3 : STRING;
+ port_clkena4 : STRING;
+ port_clkena5 : STRING;
+ port_extclk0 : STRING;
+ port_extclk1 : STRING;
+ port_extclk2 : STRING;
+ port_extclk3 : STRING;
+ self_reset_on_loss_lock : STRING;
+ width_clock : NATURAL
+ );
+ PORT (
+ clk : OUT STD_LOGIC_VECTOR (4 DOWNTO 0);
+ inclk : IN STD_LOGIC_VECTOR (1 DOWNTO 0);
+ locked : OUT STD_LOGIC
+ );
+ END COMPONENT;
+
+BEGIN
+ sub_wire6_bv(0 DOWNTO 0) <= "0";
+ sub_wire6 <= To_stdlogicvector(sub_wire6_bv);
+ sub_wire3 <= sub_wire0(0);
+ sub_wire1 <= sub_wire0(1);
+ c1 <= sub_wire1;
+ locked <= sub_wire2;
+ c0 <= sub_wire3;
+ sub_wire4 <= inclk0;
+ sub_wire5 <= sub_wire6(0 DOWNTO 0) & sub_wire4;
+
+ altpll_component : altpll
+ GENERIC MAP (
+ bandwidth_type => "AUTO",
+ clk0_divide_by => 9,
+ clk0_duty_cycle => 50,
+ clk0_multiply_by => 32,
+ clk0_phase_shift => "0",
+ clk1_divide_by => 9,
+ clk1_duty_cycle => 50,
+ clk1_multiply_by => 16,
+ clk1_phase_shift => "0",
+ compensate_clock => "CLK0",
+ inclk0_input_frequency => 37037,
+ intended_device_family => "Cyclone III",
+ lpm_hint => "CBX_MODULE_PREFIX=pll_mist",
+ lpm_type => "altpll",
+ operation_mode => "NORMAL",
+ pll_type => "AUTO",
+ port_activeclock => "PORT_UNUSED",
+ port_areset => "PORT_UNUSED",
+ port_clkbad0 => "PORT_UNUSED",
+ port_clkbad1 => "PORT_UNUSED",
+ port_clkloss => "PORT_UNUSED",
+ port_clkswitch => "PORT_UNUSED",
+ port_configupdate => "PORT_UNUSED",
+ port_fbin => "PORT_UNUSED",
+ port_inclk0 => "PORT_USED",
+ port_inclk1 => "PORT_UNUSED",
+ port_locked => "PORT_USED",
+ port_pfdena => "PORT_UNUSED",
+ port_phasecounterselect => "PORT_UNUSED",
+ port_phasedone => "PORT_UNUSED",
+ port_phasestep => "PORT_UNUSED",
+ port_phaseupdown => "PORT_UNUSED",
+ port_pllena => "PORT_UNUSED",
+ port_scanaclr => "PORT_UNUSED",
+ port_scanclk => "PORT_UNUSED",
+ port_scanclkena => "PORT_UNUSED",
+ port_scandata => "PORT_UNUSED",
+ port_scandataout => "PORT_UNUSED",
+ port_scandone => "PORT_UNUSED",
+ port_scanread => "PORT_UNUSED",
+ port_scanwrite => "PORT_UNUSED",
+ port_clk0 => "PORT_USED",
+ port_clk1 => "PORT_USED",
+ port_clk2 => "PORT_UNUSED",
+ port_clk3 => "PORT_UNUSED",
+ port_clk4 => "PORT_UNUSED",
+ port_clk5 => "PORT_UNUSED",
+ port_clkena0 => "PORT_UNUSED",
+ port_clkena1 => "PORT_UNUSED",
+ port_clkena2 => "PORT_UNUSED",
+ port_clkena3 => "PORT_UNUSED",
+ port_clkena4 => "PORT_UNUSED",
+ port_clkena5 => "PORT_UNUSED",
+ port_extclk0 => "PORT_UNUSED",
+ port_extclk1 => "PORT_UNUSED",
+ port_extclk2 => "PORT_UNUSED",
+ port_extclk3 => "PORT_UNUSED",
+ self_reset_on_loss_lock => "OFF",
+ width_clock => 5
+ )
+ PORT MAP (
+ inclk => sub_wire5,
+ clk => sub_wire0,
+ locked => sub_wire2
+ );
+
+
+
+END SYN;
+
+-- ============================================================
+-- 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 "30"
+-- Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "1"
+-- Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000"
+-- Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000"
+-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "96.000000"
+-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "48.000000"
+-- 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 "41"
+-- Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "1"
+-- Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1"
+-- Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "96.00000000"
+-- Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "48.00000000"
+-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "1"
+-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE1 STRING "1"
+-- 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 "ps"
+-- Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0"
+-- Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "0"
+-- 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_mist.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 "9"
+-- Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50"
+-- Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "32"
+-- Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0"
+-- Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "9"
+-- Retrieval info: CONSTANT: CLK1_DUTY_CYCLE NUMERIC "50"
+-- Retrieval info: CONSTANT: CLK1_MULTIPLY_BY NUMERIC "16"
+-- 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_UNUSED"
+-- 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: @inclk 0 0 2 0 INPUT_CLK_EXT VCC "@inclk[1..0]"
+-- 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: @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_mist.vhd TRUE
+-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_mist.ppf TRUE
+-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_mist.inc FALSE
+-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_mist.cmp FALSE
+-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_mist.bsf FALSE
+-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_mist_inst.vhd FALSE
+-- Retrieval info: LIB_FILE: altera_mf
+-- Retrieval info: CBX_MODULE_PREFIX: ON
diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/sdram.sv b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/sdram.sv
new file mode 100644
index 00000000..65dc05f9
--- /dev/null
+++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/sdram.sv
@@ -0,0 +1,363 @@
+//
+// sdram.v
+//
+// sdram controller implementation for the MiST board
+// https://github.com/mist-devel/mist-board
+//
+// Copyright (c) 2013 Till Harbaum
+// Copyright (c) 2019 Gyorgy Szombathelyi
+//
+// This source file is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published
+// by the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This source file is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+module sdram (
+
+ // interface to the MT48LC16M16 chip
+ inout reg [15:0] SDRAM_DQ, // 16 bit bidirectional data bus
+ output reg [12:0] SDRAM_A, // 13 bit multiplexed address bus
+ output reg SDRAM_DQML, // two byte masks
+ output reg SDRAM_DQMH, // two byte masks
+ output reg [1:0] SDRAM_BA, // two banks
+ output SDRAM_nCS, // a single chip select
+ output SDRAM_nWE, // write enable
+ output SDRAM_nRAS, // row address select
+ output SDRAM_nCAS, // columns address select
+
+ // cpu/chipset interface
+ input init_n, // init signal after FPGA config to initialize RAM
+ input clk, // sdram clock
+
+ input port1_req,
+ output reg port1_ack,
+ input port1_we,
+ input [23:1] port1_a,
+ input [1:0] port1_ds,
+ input [15:0] port1_d,
+ output reg [15:0] port1_q,
+
+ input cpu1_cs,
+ input [16:1] cpu1_addr,
+ output reg [15:0] cpu1_q,
+ output reg cpu1_valid,
+ input cpu2_cs,
+ input [16:1] cpu2_addr,
+ output reg [15:0] cpu2_q,
+ output reg cpu2_valid,
+
+ input port2_req,
+ output reg port2_ack,
+ input port2_we,
+ input [23:1] port2_a,
+ input [1:0] port2_ds,
+ input [15:0] port2_d,
+ output reg [15:0] port2_q,
+
+ input [22:1] gfx1_addr,
+ output reg [15:0] gfx1_q,
+ input [22:1] gfx2_addr,
+ output reg [15:0] gfx2_q,
+ input [22:1] gfx3_addr,
+ output reg [15:0] gfx3_q,
+ output gfx3_ready
+);
+parameter MHZ = 80; // 80 MHz default clock, adjust to calculate the refresh rate correctly
+
+localparam RASCAS_DELAY = 3'd2; // tRCD=20ns -> 2 cycles@<100MHz
+localparam BURST_LENGTH = 3'b000; // 000=1, 001=2, 010=4, 011=8
+localparam ACCESS_TYPE = 1'b0; // 0=sequential, 1=interleaved
+localparam CAS_LATENCY = 3'd2; // 2/3 allowed
+localparam OP_MODE = 2'b00; // only 00 (standard operation) allowed
+localparam NO_WRITE_BURST = 1'b1; // 0= write burst enabled, 1=only single access write
+
+localparam MODE = { 3'b000, NO_WRITE_BURST, OP_MODE, CAS_LATENCY, ACCESS_TYPE, BURST_LENGTH};
+
+// 64ms/8192 rows = 7.8us -> 842 cycles@108MHz
+localparam RFRSH_CYCLES = 16'd78*MHZ/10;
+
+// ---------------------------------------------------------------------
+// ------------------------ cycle state machine ------------------------
+// ---------------------------------------------------------------------
+
+/*
+ SDRAM state machine for 2 bank interleaved access
+ 1 word burst, CL2
+cmd issued registered
+ 0 RAS0 cas1
+ 1 ras0
+ 2 CAS0 data1 returned
+ 3 RAS1 cas0
+ 4 ras1
+ 5 CAS1 data0 returned
+*/
+
+localparam STATE_RAS0 = 3'd0; // first state in cycle
+localparam STATE_RAS1 = 3'd3; // Second ACTIVE command after RAS0 + tRRD (15ns)
+localparam STATE_CAS0 = STATE_RAS0 + RASCAS_DELAY; // CAS phase - 2
+localparam STATE_CAS1 = STATE_RAS1 + RASCAS_DELAY; // CAS phase - 5
+localparam STATE_READ0 = 3'd0;// STATE_CAS0 + CAS_LATENCY + 2'd2;
+localparam STATE_READ1 = 3'd3;
+localparam STATE_LAST = 3'd5;
+
+reg [2:0] t;
+
+always @(posedge clk) begin
+ t <= t + 1'd1;
+ if (t == STATE_LAST) t <= STATE_RAS0;
+end
+
+// ---------------------------------------------------------------------
+// --------------------------- startup/reset ---------------------------
+// ---------------------------------------------------------------------
+
+// wait 1ms (32 8Mhz cycles) after FPGA config is done before going
+// into normal operation. Initialize the ram in the last 16 reset cycles (cycles 15-0)
+reg [4:0] reset;
+reg init = 1'b1;
+always @(posedge clk, negedge init_n) begin
+ if(!init_n) begin
+ reset <= 5'h1f;
+ init <= 1'b1;
+ end else begin
+ if((t == STATE_LAST) && (reset != 0)) reset <= reset - 5'd1;
+ init <= !(reset == 0);
+ end
+end
+
+// ---------------------------------------------------------------------
+// ------------------ generate ram control signals ---------------------
+// ---------------------------------------------------------------------
+
+// all possible commands
+localparam CMD_INHIBIT = 4'b1111;
+localparam CMD_NOP = 4'b0111;
+localparam CMD_ACTIVE = 4'b0011;
+localparam CMD_READ = 4'b0101;
+localparam CMD_WRITE = 4'b0100;
+localparam CMD_BURST_TERMINATE = 4'b0110;
+localparam CMD_PRECHARGE = 4'b0010;
+localparam CMD_AUTO_REFRESH = 4'b0001;
+localparam CMD_LOAD_MODE = 4'b0000;
+
+reg [3:0] sd_cmd; // current command sent to sd ram
+reg [15:0] sd_din;
+// drive control signals according to current command
+assign SDRAM_nCS = sd_cmd[3];
+assign SDRAM_nRAS = sd_cmd[2];
+assign SDRAM_nCAS = sd_cmd[1];
+assign SDRAM_nWE = sd_cmd[0];
+
+reg [24:1] addr_latch[2];
+reg [24:1] addr_latch_next[2];
+reg [22:1] addr_last2[4];
+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;
+reg [1:0] gfx3_ok = 0;
+assign gfx3_ready = |gfx3_ok;
+
+localparam PORT_NONE = 3'd0;
+localparam PORT_CPU1 = 3'd1;
+localparam PORT_CPU2 = 3'd2;
+localparam PORT_GFX1 = 3'd1;
+localparam PORT_GFX2 = 3'd2;
+localparam PORT_GFX3 = 3'd3;
+localparam PORT_REQ = 3'd4;
+
+reg [2:0] next_port[2];
+reg [2:0] port[2];
+wire oe_next, we_next;
+wire [1:0] ds_next;
+wire [15:0] din_next;
+reg refresh;
+reg [10:0] refresh_cnt;
+wire need_refresh = (refresh_cnt >= RFRSH_CYCLES);
+
+// PORT1: bank 0,1
+always @(*) begin
+ next_port[0] = PORT_NONE;
+ addr_latch_next[0] = 0;
+ ds_next = 2'b00;
+ { oe_next, we_next } = 2'b00;
+ din_next = 0;
+
+ if (refresh) begin
+ // nothing
+ end else if (port1_req ^ port1_state) begin
+ next_port[0] = PORT_REQ;
+ addr_latch_next[0] = { 1'b0, port1_a };
+ ds_next = port1_ds;
+ { oe_next, we_next } = { ~port1_we, port1_we };
+ din_next = port1_d;
+ end else if (cpu1_cs & !cpu1_valid) begin
+ next_port[0] = PORT_CPU1;
+ addr_latch_next[0] = { 8'd0, cpu1_addr };
+ ds_next = 2'b11;
+ { oe_next, we_next } = { 2'b10 };
+ end else if (cpu2_cs & !cpu2_valid) begin
+ next_port[0] = PORT_CPU2;
+ addr_latch_next[0] = { 8'd0, cpu2_addr };
+ ds_next = 2'b11;
+ { oe_next, we_next } = { 2'b10 };
+ 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 (gfx1_addr != addr_last2[PORT_GFX1]) begin
+ next_port[1] = PORT_GFX1;
+ addr_latch_next[1] = { 2'b10, gfx1_addr };
+ end else if (gfx2_addr != addr_last2[PORT_GFX2]) begin
+ next_port[1] = PORT_GFX2;
+ addr_latch_next[1] = { 2'b10, gfx2_addr };
+ end else if (gfx3_addr != addr_last2[PORT_GFX3]) begin
+ next_port[1] = PORT_GFX3;
+ addr_latch_next[1] = { 2'b10, gfx3_addr };
+ end else begin
+ next_port[1] = PORT_NONE;
+ addr_latch_next[1] = addr_latch[1];
+ end
+end
+
+always @(posedge clk) begin
+ gfx3_ok <= {gfx3_ok[0], 1'b0};
+
+ // 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 (!cpu1_cs) cpu1_valid <= 0;
+ if (!cpu2_cs) cpu2_valid <= 0;
+
+ 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] } <= { oe_next, we_next };
+ ds[0] <= ds_next;
+ din_latch[0] <= din_next;
+ 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];
+ end
+ if (next_port[0] == PORT_REQ) port1_state <= port1_req;
+ 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][22:1];
+ if (next_port[1] == PORT_REQ) begin
+ { oe_latch[1], we_latch[1] } <= { ~port1_we, port1_we };
+ ds[1] <= port2_ds;
+ din_latch[1] <= port2_d;
+ port2_state <= port2_req;
+ end else begin
+ { oe_latch[1], we_latch[1] } <= 2'b10;
+ ds[1] <= 2'b11;
+ end
+ end
+
+ if (next_port[1] == PORT_NONE && need_refresh && !we_latch[0] && !oe_latch[0]) begin
+ refresh <= 1'b1;
+ refresh_cnt <= 0;
+ sd_cmd <= CMD_AUTO_REFRESH;
+ end
+ end
+
+ // CAS phase
+ if(t == STATE_CAS0 && (we_latch[0] || oe_latch[0])) begin
+ sd_cmd <= we_latch[0]?CMD_WRITE:CMD_READ;
+ { SDRAM_DQMH, SDRAM_DQML } <= ~ds[0];
+ if (we_latch[0]) begin
+ SDRAM_DQ <= din_latch[0];
+ port1_ack <= port1_req;
+ end
+ SDRAM_A <= { 4'b0010, addr_latch[0][9:1] }; // auto precharge
+ SDRAM_BA <= addr_latch[0][24:23];
+ end
+
+ if(t == STATE_CAS1 && (we_latch[1] || oe_latch[1])) begin
+ sd_cmd <= we_latch[1]?CMD_WRITE:CMD_READ;
+ { SDRAM_DQMH, SDRAM_DQML } <= ~ds[1];
+ if (we_latch[1]) begin
+ SDRAM_DQ <= din_latch[1];
+ port2_ack <= port2_req;
+ end
+ SDRAM_A <= { 4'b0010, addr_latch[1][9:1] }; // auto precharge
+ SDRAM_BA <= addr_latch[1][24:23];
+ end
+
+ // Data returned
+ if(t == STATE_READ0 && oe_latch[0]) begin
+ case(port[0])
+ PORT_REQ: begin port1_q <= sd_din; port1_ack <= port1_req; end
+ PORT_CPU1: begin cpu1_q <= sd_din; cpu1_valid <= 1; end
+ PORT_CPU2: begin cpu2_q <= sd_din; cpu2_valid <= 1; end
+ default: ;
+ endcase;
+ end
+
+ if(t == STATE_READ1 && oe_latch[1]) begin
+ case(port[1])
+ PORT_REQ: port2_q <= sd_din;
+ PORT_GFX1: gfx1_q <= sd_din;
+ PORT_GFX2: gfx2_q <= sd_din;
+ PORT_GFX3: begin gfx3_q <= sd_din; gfx3_ok <= 2'b01; end
+ default: ;
+ endcase;
+ end
+ end
+end
+
+endmodule
diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/spram.sv b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/spram.sv
new file mode 100644
index 00000000..0e87a779
--- /dev/null
+++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/spram.sv
@@ -0,0 +1,253 @@
+// megafunction wizard: %RAM: 2-PORT%
+// GENERATION: STANDARD
+// VERSION: WM1.0
+// MODULE: altsyncram
+
+// ============================================================
+// File Name: spram.v
+// Megafunction Name(s):
+// altsyncram
+//
+// Simulation Library Files(s):
+// altera_mf
+// ============================================================
+// ************************************************************
+// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
+//
+// 17.0.0 Build 595 04/25/2017 SJ Lite Edition
+// ************************************************************
+
+
+//Copyright (C) 2017 Intel Corporation. All rights reserved.
+//Your use of Intel 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 Intel Program License
+//Subscription Agreement, the Intel Quartus Prime License Agreement,
+//the Intel 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 Intel and sold by Intel 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 spram (
+ address_a,
+ address_b,
+ clock,
+ data_a,
+ data_b,
+ rden_a,
+ rden_b,
+ wren_a,
+ wren_b,
+ q_a,
+ q_b);
+
+ input [7:0] address_a;
+ input [5:0] address_b;
+ input clock;
+ input [7:0] data_a;
+ input [31:0] data_b;
+ input rden_a;
+ input rden_b;
+ input wren_a;
+ input wren_b;
+ output [7:0] q_a;
+ output [31:0] q_b;
+`ifndef ALTERA_RESERVED_QIS
+// synopsys translate_off
+`endif
+ tri1 clock;
+ tri1 rden_a;
+ tri1 rden_b;
+ tri0 wren_a;
+ tri0 wren_b;
+`ifndef ALTERA_RESERVED_QIS
+// synopsys translate_on
+`endif
+
+ wire [7:0] sub_wire0;
+ wire [31:0] sub_wire1;
+ wire [7:0] q_a = sub_wire0[7:0];
+ wire [31:0] q_b = sub_wire1[31:0];
+
+ altsyncram altsyncram_component (
+ .address_a (address_a),
+ .address_b (address_b),
+ .clock0 (clock),
+ .data_a (data_a),
+ .data_b (data_b),
+ .rden_a (rden_a),
+ .rden_b (rden_b),
+ .wren_a (wren_a),
+ .wren_b (wren_b),
+ .q_a (sub_wire0),
+ .q_b (sub_wire1),
+ .aclr0 (1'b0),
+ .aclr1 (1'b0),
+ .addressstall_a (1'b0),
+ .addressstall_b (1'b0),
+ .byteena_a (1'b1),
+ .byteena_b (1'b1),
+ .clock1 (1'b1),
+ .clocken0 (1'b1),
+ .clocken1 (1'b1),
+ .clocken2 (1'b1),
+ .clocken3 (1'b1),
+ .eccstatus ());
+ defparam
+ altsyncram_component.address_reg_b = "CLOCK0",
+ altsyncram_component.clock_enable_input_a = "BYPASS",
+ altsyncram_component.clock_enable_input_b = "BYPASS",
+ altsyncram_component.clock_enable_output_a = "BYPASS",
+ altsyncram_component.clock_enable_output_b = "BYPASS",
+ altsyncram_component.indata_reg_b = "CLOCK0",
+ altsyncram_component.intended_device_family = "Cyclone V",
+ altsyncram_component.lpm_type = "altsyncram",
+ altsyncram_component.numwords_a = 256,
+ altsyncram_component.numwords_b = 64,
+ altsyncram_component.operation_mode = "BIDIR_DUAL_PORT",
+ altsyncram_component.outdata_aclr_a = "NONE",
+ altsyncram_component.outdata_aclr_b = "NONE",
+ altsyncram_component.outdata_reg_a = "CLOCK0",
+ altsyncram_component.outdata_reg_b = "CLOCK0",
+ altsyncram_component.power_up_uninitialized = "FALSE",
+ altsyncram_component.read_during_write_mode_mixed_ports = "DONT_CARE",
+ altsyncram_component.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ",
+ altsyncram_component.read_during_write_mode_port_b = "NEW_DATA_NO_NBE_READ",
+ altsyncram_component.widthad_a = 8,
+ altsyncram_component.widthad_b = 6,
+ altsyncram_component.width_a = 8,
+ altsyncram_component.width_b = 32,
+ altsyncram_component.width_byteena_a = 1,
+ altsyncram_component.width_byteena_b = 1,
+ altsyncram_component.wrcontrol_wraddress_reg_b = "CLOCK0";
+
+
+endmodule
+
+// ============================================================
+// CNX file retrieval info
+// ============================================================
+// Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0"
+// Retrieval info: PRIVATE: ADDRESSSTALL_B NUMERIC "0"
+// Retrieval info: PRIVATE: BYTEENA_ACLR_A NUMERIC "0"
+// Retrieval info: PRIVATE: BYTEENA_ACLR_B NUMERIC "0"
+// Retrieval info: PRIVATE: BYTE_ENABLE_A NUMERIC "0"
+// Retrieval info: PRIVATE: BYTE_ENABLE_B NUMERIC "0"
+// Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8"
+// Retrieval info: PRIVATE: BlankMemory NUMERIC "1"
+// Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "0"
+// Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_B NUMERIC "0"
+// Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "0"
+// Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_B NUMERIC "0"
+// Retrieval info: PRIVATE: CLRdata NUMERIC "0"
+// Retrieval info: PRIVATE: CLRq NUMERIC "0"
+// Retrieval info: PRIVATE: CLRrdaddress NUMERIC "0"
+// Retrieval info: PRIVATE: CLRrren NUMERIC "0"
+// Retrieval info: PRIVATE: CLRwraddress NUMERIC "0"
+// Retrieval info: PRIVATE: CLRwren NUMERIC "0"
+// Retrieval info: PRIVATE: Clock NUMERIC "0"
+// Retrieval info: PRIVATE: Clock_A NUMERIC "0"
+// Retrieval info: PRIVATE: Clock_B NUMERIC "0"
+// Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0"
+// Retrieval info: PRIVATE: INDATA_ACLR_B NUMERIC "0"
+// Retrieval info: PRIVATE: INDATA_REG_B NUMERIC "1"
+// Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_A"
+// Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0"
+// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone V"
+// Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0"
+// Retrieval info: PRIVATE: JTAG_ID STRING "NONE"
+// Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0"
+// Retrieval info: PRIVATE: MEMSIZE NUMERIC "1024"
+// Retrieval info: PRIVATE: MEM_IN_BITS NUMERIC "0"
+// Retrieval info: PRIVATE: MIFfilename STRING ""
+// Retrieval info: PRIVATE: OPERATION_MODE NUMERIC "3"
+// Retrieval info: PRIVATE: OUTDATA_ACLR_B NUMERIC "0"
+// Retrieval info: PRIVATE: OUTDATA_REG_B NUMERIC "1"
+// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0"
+// Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_MIXED_PORTS NUMERIC "2"
+// Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_A NUMERIC "3"
+// Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_B NUMERIC "3"
+// Retrieval info: PRIVATE: REGdata NUMERIC "1"
+// Retrieval info: PRIVATE: REGq NUMERIC "1"
+// Retrieval info: PRIVATE: REGrdaddress NUMERIC "0"
+// Retrieval info: PRIVATE: REGrren NUMERIC "1"
+// Retrieval info: PRIVATE: REGwraddress NUMERIC "1"
+// Retrieval info: PRIVATE: REGwren NUMERIC "1"
+// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
+// Retrieval info: PRIVATE: USE_DIFF_CLKEN NUMERIC "0"
+// Retrieval info: PRIVATE: UseDPRAM NUMERIC "1"
+// Retrieval info: PRIVATE: VarWidth NUMERIC "1"
+// Retrieval info: PRIVATE: WIDTH_READ_A NUMERIC "8"
+// Retrieval info: PRIVATE: WIDTH_READ_B NUMERIC "32"
+// Retrieval info: PRIVATE: WIDTH_WRITE_A NUMERIC "8"
+// Retrieval info: PRIVATE: WIDTH_WRITE_B NUMERIC "32"
+// Retrieval info: PRIVATE: WRADDR_ACLR_B NUMERIC "0"
+// Retrieval info: PRIVATE: WRADDR_REG_B NUMERIC "1"
+// Retrieval info: PRIVATE: WRCTRL_ACLR_B NUMERIC "0"
+// Retrieval info: PRIVATE: enable NUMERIC "0"
+// Retrieval info: PRIVATE: rden NUMERIC "1"
+// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
+// Retrieval info: CONSTANT: ADDRESS_REG_B STRING "CLOCK0"
+// Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "BYPASS"
+// Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_B STRING "BYPASS"
+// Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "BYPASS"
+// Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_B STRING "BYPASS"
+// Retrieval info: CONSTANT: INDATA_REG_B STRING "CLOCK0"
+// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone V"
+// Retrieval info: CONSTANT: LPM_TYPE STRING "altsyncram"
+// Retrieval info: CONSTANT: NUMWORDS_A NUMERIC "256"
+// Retrieval info: CONSTANT: NUMWORDS_B NUMERIC "64"
+// Retrieval info: CONSTANT: OPERATION_MODE STRING "BIDIR_DUAL_PORT"
+// Retrieval info: CONSTANT: OUTDATA_ACLR_A STRING "NONE"
+// Retrieval info: CONSTANT: OUTDATA_ACLR_B STRING "NONE"
+// Retrieval info: CONSTANT: OUTDATA_REG_A STRING "CLOCK0"
+// Retrieval info: CONSTANT: OUTDATA_REG_B STRING "CLOCK0"
+// Retrieval info: CONSTANT: POWER_UP_UNINITIALIZED STRING "FALSE"
+// Retrieval info: CONSTANT: READ_DURING_WRITE_MODE_MIXED_PORTS STRING "DONT_CARE"
+// Retrieval info: CONSTANT: READ_DURING_WRITE_MODE_PORT_A STRING "NEW_DATA_NO_NBE_READ"
+// Retrieval info: CONSTANT: READ_DURING_WRITE_MODE_PORT_B STRING "NEW_DATA_NO_NBE_READ"
+// Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "8"
+// Retrieval info: CONSTANT: WIDTHAD_B NUMERIC "6"
+// Retrieval info: CONSTANT: WIDTH_A NUMERIC "8"
+// Retrieval info: CONSTANT: WIDTH_B NUMERIC "32"
+// Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1"
+// Retrieval info: CONSTANT: WIDTH_BYTEENA_B NUMERIC "1"
+// Retrieval info: CONSTANT: WRCONTROL_WRADDRESS_REG_B STRING "CLOCK0"
+// Retrieval info: USED_PORT: address_a 0 0 8 0 INPUT NODEFVAL "address_a[7..0]"
+// Retrieval info: USED_PORT: address_b 0 0 6 0 INPUT NODEFVAL "address_b[5..0]"
+// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT VCC "clock"
+// Retrieval info: USED_PORT: data_a 0 0 8 0 INPUT NODEFVAL "data_a[7..0]"
+// Retrieval info: USED_PORT: data_b 0 0 32 0 INPUT NODEFVAL "data_b[31..0]"
+// Retrieval info: USED_PORT: q_a 0 0 8 0 OUTPUT NODEFVAL "q_a[7..0]"
+// Retrieval info: USED_PORT: q_b 0 0 32 0 OUTPUT NODEFVAL "q_b[31..0]"
+// Retrieval info: USED_PORT: rden_a 0 0 0 0 INPUT VCC "rden_a"
+// Retrieval info: USED_PORT: rden_b 0 0 0 0 INPUT VCC "rden_b"
+// Retrieval info: USED_PORT: wren_a 0 0 0 0 INPUT GND "wren_a"
+// Retrieval info: USED_PORT: wren_b 0 0 0 0 INPUT GND "wren_b"
+// Retrieval info: CONNECT: @address_a 0 0 8 0 address_a 0 0 8 0
+// Retrieval info: CONNECT: @address_b 0 0 6 0 address_b 0 0 6 0
+// Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0
+// Retrieval info: CONNECT: @data_a 0 0 8 0 data_a 0 0 8 0
+// Retrieval info: CONNECT: @data_b 0 0 32 0 data_b 0 0 32 0
+// Retrieval info: CONNECT: @rden_a 0 0 0 0 rden_a 0 0 0 0
+// Retrieval info: CONNECT: @rden_b 0 0 0 0 rden_b 0 0 0 0
+// Retrieval info: CONNECT: @wren_a 0 0 0 0 wren_a 0 0 0 0
+// Retrieval info: CONNECT: @wren_b 0 0 0 0 wren_b 0 0 0 0
+// Retrieval info: CONNECT: q_a 0 0 8 0 @q_a 0 0 8 0
+// Retrieval info: CONNECT: q_b 0 0 32 0 @q_b 0 0 32 0
+// Retrieval info: GEN_FILE: TYPE_NORMAL spram.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL spram.inc FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL spram.cmp FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL spram.bsf FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL spram_inst.v FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL spram_bb.v FALSE
+// Retrieval info: LIB_FILE: altera_mf
diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/video.v b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/video.v
new file mode 100644
index 00000000..c84ed36f
--- /dev/null
+++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/video.v
@@ -0,0 +1,45 @@
+
+module video(
+ input clk,
+ input ce_pix,
+ output reg hs,
+ output reg vs,
+ output reg hb,
+ output reg vb,
+ output reg [8:0] hcount,
+ output reg [8:0] vcount,
+ output reg frame,
+ input [3:0] hoffs,
+ input [3:0] voffs
+);
+
+initial begin
+ hs <= 1'b1;
+ vs <= 1'b1;
+end
+
+always @(posedge clk) begin
+ frame <= 1'b0;
+ if (ce_pix) begin
+ hcount <= hcount + 9'd1;
+ case (hcount)
+ 16: hb <= 1'b0;
+ 271: hb <= 1'b1;
+ (308 - $signed(hoffs)): hs <= 1'b0;
+ (340 - $signed(hoffs)): hs <= 1'b1;
+ 383: begin
+ vcount <= vcount + 9'd1;
+ hcount <= 9'b0;
+ case (vcount)
+ 15: vb <= 1'b0;
+ 239: vb <= 1'b1;
+ (249 - $signed(voffs)) : vs <= 1'b0;
+ (252 - $signed(voffs)) : vs <= 1'b1;
+ 262: vcount <= 9'd0;
+ endcase
+ end
+ endcase
+ end
+end
+
+endmodule
diff --git a/common/mist/README.md b/common/mist/README.md
index 588d54cd..99157a20 100644
--- a/common/mist/README.md
+++ b/common/mist/README.md
@@ -7,8 +7,10 @@ The modules:
- user_io.v - communicating with the IO controller.
- data_io.v - handling file uploads from the IO controller.
- mist_video.v - a video pipeline, which gives an optional scandoubler, OSD and rgb2ypbpr conversion.
-- osd.v, scandoubler.v, rgb2ypbpr.sv, cofi.sv - these are used in mist_video, but can be used separately, too.
+- osd.v, scandoubler.v, rgb2ypbpr.v, cofi.sv - these are used in mist_video, but can be used separately, too.
- sd_card.v - gives an SPI interface with SD-Card commands towards the IO-Controller, accessing .VHD and other mounted files.
+- ide.v, ide_fifo.v - a bridge between a CPU and the data_io module for IDE/ATAPI disks.
+- cdda_fifo.v - a module which connects data_io with a DAC for CDDA playback.
- dac.vhd - a simple sigma-delta DAC for audio output.
- arcade_inputs.v - mostly for arcade-style games, gives access to the joysticks with MAME-style keyboard mapping.
- mist.vhd - VHDL component declarations for user_io and mist_video.
diff --git a/common/mist/cdda_fifo.v b/common/mist/cdda_fifo.v
new file mode 100644
index 00000000..d402930f
--- /dev/null
+++ b/common/mist/cdda_fifo.v
@@ -0,0 +1,107 @@
+//
+// cdda_fifo.v
+//
+// CDDA FIFO for the MiST board
+// https://github.com/mist-devel
+//
+// Copyright (c) 2022 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 cdda_fifo
+(
+ input clk_sys,
+ input clk_en, // set to 1 when using the stock data_io
+ input cen_44100, // 44100 HZ clock enable
+ input reset,
+
+ // data_io interface
+ output hdd_cdda_req,
+ input hdd_cdda_wr,
+ input [15:0] hdd_data_out,
+
+ // sample output
+ output reg [15:0] cdda_l,
+ output reg [15:0] cdda_r
+);
+
+// 4k x 16bit default FIFO size
+parameter FIFO_DEPTH = 12;
+reg [15:0] fifo[2**FIFO_DEPTH];
+reg [FIFO_DEPTH-1:0] inptr;
+reg [FIFO_DEPTH-1:0] outptr;
+reg [15:0] fifo_out;
+
+wire [FIFO_DEPTH:0] fifo_used = inptr >= outptr ?
+ inptr - outptr :
+ inptr - outptr + (2'd2**FIFO_DEPTH);
+
+assign hdd_cdda_req = fifo_used < ((2'd2**FIFO_DEPTH) - 16'd2352);
+
+always @(posedge clk_sys) begin
+ if (reset)
+ inptr <= 0;
+ else if (clk_en && hdd_cdda_wr) begin
+ fifo[inptr] <= {hdd_data_out[7:0], hdd_data_out[15:8]};
+ inptr <= inptr + 1'd1;
+ end
+end
+
+always @(posedge clk_sys) fifo_out <= fifo[outptr];
+
+reg left = 0;
+reg mute = 1;
+reg fifo_active = 0;
+
+always @(posedge clk_sys) begin
+ if (reset) begin
+ outptr <= 0;
+ fifo_active <= 0;
+ mute <= 1;
+ left <= 0;
+ cdda_l <= 0;
+ cdda_r <= 0;
+ end else begin
+ if (cen_44100) begin
+ if (fifo_used >= 2352)
+ fifo_active <= 1;
+ if (outptr + 2'd2 == inptr)
+ fifo_active <= 0;
+ if (fifo_active) begin
+ outptr <= outptr + 1'd1;
+ left <= 1;
+ mute <= 0;
+ end else
+ mute <= 1;
+ end
+ if (left) begin
+ outptr <= outptr + 1'd1;
+ left <= 0;
+ end
+
+ if (mute) begin
+ cdda_l <= 0;
+ cdda_r <= 0;
+ end else begin
+ if (left)
+ cdda_l <= fifo_out;
+ else
+ cdda_r <= fifo_out;
+ end
+ end
+end
+
+endmodule
diff --git a/common/mist/data_io.v b/common/mist/data_io.v
index 7e14f129..6862f1f4 100644
--- a/common/mist/data_io.v
+++ b/common/mist/data_io.v
@@ -2,7 +2,7 @@
// data_io.v
//
// data_io for the MiST board
-// http://code.google.com/p/mist-board/
+// https://github.com/mist-devel
//
// Copyright (c) 2014 Till Harbaum
//
@@ -30,6 +30,10 @@ module data_io
input SPI_DI,
inout SPI_DO,
+ input QCSn,
+ input QSCK,
+ input [3:0] QDAT,
+
input clkref_n, // assert ioctl_wr one cycle after clkref stobe (negative active)
// ARM -> FPGA download
@@ -43,52 +47,105 @@ module data_io
output reg [7:0] ioctl_dout,
input [7:0] ioctl_din,
output reg [23:0] ioctl_fileext, // file extension
- output reg [31:0] ioctl_filesize // file size
+ output reg [31:0] ioctl_filesize, // file size
+
+ // IDE interface
+ input hdd_clk,
+ input hdd_cmd_req,
+ input hdd_cdda_req,
+ input hdd_dat_req,
+ output hdd_cdda_wr,
+ output hdd_status_wr,
+ output [2:0] hdd_addr = 0,
+ output hdd_wr,
+
+ output [15:0] hdd_data_out,
+ input [15:0] hdd_data_in,
+ output hdd_data_rd,
+ output hdd_data_wr,
+
+ // IDE config
+ output [1:0] hdd0_ena,
+ output [1:0] hdd1_ena
);
parameter START_ADDR = 25'd0;
parameter ROM_DIRECT_UPLOAD = 0;
+parameter USE_QSPI = 0;
+parameter ENABLE_IDE = 0;
/////////////////////////////// DOWNLOADING ///////////////////////////////
+reg [6:0] sbuf;
reg [7:0] data_w;
reg [7:0] data_w2 = 0;
+reg [7:0] data_w3 = 0;
reg [3:0] cnt;
+reg [7:0] cmd;
+reg [6:0] bytecnt;
+
reg rclk = 0;
reg rclk2 = 0;
+reg rclk3 = 0;
reg addr_reset = 0;
reg downloading_reg = 0;
reg uploading_reg = 0;
reg reg_do;
-localparam DIO_FILE_TX = 8'h53;
-localparam DIO_FILE_TX_DAT = 8'h54;
-localparam DIO_FILE_INDEX = 8'h55;
-localparam DIO_FILE_INFO = 8'h56;
-localparam DIO_FILE_RX = 8'h57;
-localparam DIO_FILE_RX_DAT = 8'h58;
+localparam DIO_FILE_TX = 8'h53;
+localparam DIO_FILE_TX_DAT = 8'h54;
+localparam DIO_FILE_INDEX = 8'h55;
+localparam DIO_FILE_INFO = 8'h56;
+localparam DIO_FILE_RX = 8'h57;
+localparam DIO_FILE_RX_DAT = 8'h58;
+
+localparam QSPI_READ = 8'h40;
+localparam QSPI_WRITE = 8'h41;
+
+localparam CMD_IDE_REGS_RD = 8'h80;
+localparam CMD_IDE_REGS_WR = 8'h90;
+localparam CMD_IDE_DATA_WR = 8'hA0;
+localparam CMD_IDE_DATA_RD = 8'hB0;
+localparam CMD_IDE_CDDA_RD = 8'hC0;
+localparam CMD_IDE_CDDA_WR = 8'hD0;
+localparam CMD_IDE_STATUS_WR = 8'hF0;
+localparam CMD_IDE_CFG_WR = 8'hFA;
assign SPI_DO = reg_do;
// data_io has its own SPI interface to the io controller
+wire [7:0] cmdcode = { 4'h0, hdd_dat_req, hdd_cmd_req, 2'b00 };
+
always@(negedge SPI_SCK or posedge SPI_SS2) begin : SPI_TRANSMITTER
reg [7:0] dout_r;
if(SPI_SS2) begin
reg_do <= 1'bZ;
end else begin
- if (cnt == 15) dout_r <= ioctl_din;
+ if (cnt == 0) dout_r <= cmdcode;
+ if (cnt == 15) begin
+ case(cmd)
+ CMD_IDE_REGS_RD,
+ CMD_IDE_DATA_RD:
+ dout_r <= bytecnt[0] ? hdd_data_in[7:0] : hdd_data_in[15:8];
+
+ CMD_IDE_CDDA_RD:
+ dout_r <= {7'd0, hdd_cdda_req};
+
+ DIO_FILE_RX_DAT:
+ dout_r <= ioctl_din;
+
+ default:
+ dout_r <= 0;
+
+ endcase
+ end
reg_do <= dout_r[~cnt[2:0]];
end
end
always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER
- reg [6:0] sbuf;
- reg [24:0] addr;
- reg [7:0] cmd;
- reg [5:0] bytecnt;
-
if(SPI_SS2) begin
bytecnt <= 0;
cnt <= 0;
@@ -105,6 +162,9 @@ always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER
if(cnt == 7) cmd <= {sbuf, SPI_DI};
if(cnt == 15) begin
+ if (~&bytecnt) bytecnt <= bytecnt + 1'd1;
+ else bytecnt[0] <= ~bytecnt[0];
+
case (cmd)
// prepare/end transmission
DIO_FILE_TX: begin
@@ -140,7 +200,6 @@ always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER
// receiving FAT directory entry (mist-firmware/fat.h - DIRENTRY)
DIO_FILE_INFO: begin
- bytecnt <= bytecnt + 1'd1;
case (bytecnt)
8'h08: ioctl_fileext[23:16] <= {sbuf, SPI_DI};
8'h09: ioctl_fileext[15: 8] <= {sbuf, SPI_DI};
@@ -157,7 +216,7 @@ always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER
end
// direct SD Card->FPGA transfer
-generate if (ROM_DIRECT_UPLOAD == 1) begin
+generate if (ROM_DIRECT_UPLOAD || ENABLE_IDE) begin
always@(posedge SPI_SCK, posedge SPI_SS4) begin : SPI_DIRECT_RECEIVER
reg [6:0] sbuf2;
@@ -192,19 +251,50 @@ end
end
endgenerate
+// QSPI receiver
+generate if (USE_QSPI) begin
+
+always@(negedge QSCK, posedge QCSn) begin : QSPI_RECEIVER
+ reg nibble_lo;
+ reg cmd_got;
+ reg cmd_write;
+
+ if (QCSn) begin
+ cmd_got <= 0;
+ cmd_write <= 0;
+ nibble_lo <= 0;
+ end else begin
+ nibble_lo <= ~nibble_lo;
+ if (nibble_lo) begin
+ data_w3[3:0] <= QDAT;
+ if (!cmd_got) begin
+ cmd_got <= 1;
+ if ({data_w3[7:4], QDAT} == QSPI_WRITE) cmd_write <= 1;
+ end else begin
+ if (cmd_write) rclk3 <= ~rclk3;
+ end
+ end else
+ data_w3[7:4] <= QDAT;
+ end
+end
+end
+endgenerate
+
always@(posedge clk_sys) begin : DATA_OUT
// synchronisers
reg rclkD, rclkD2;
reg rclk2D, rclk2D2;
+ reg rclk3D, rclk3D2;
reg addr_resetD, addr_resetD2;
- reg wr_int, wr_int_direct, rd_int;
+ reg wr_int, wr_int_direct, wr_int_qspi, rd_int;
reg [24:0] addr;
reg [31:0] filepos;
// bring flags from spi clock domain into core clock domain
{ rclkD, rclkD2 } <= { rclk, rclkD };
{ rclk2D ,rclk2D2 } <= { rclk2, rclk2D };
+ { rclk3D ,rclk3D2 } <= { rclk3, rclk3D };
{ addr_resetD, addr_resetD2 } <= { addr_reset, addr_resetD };
ioctl_wr <= 0;
@@ -224,8 +314,9 @@ always@(posedge clk_sys) begin : DATA_OUT
rd_int <= 0;
wr_int <= 0;
wr_int_direct <= 0;
- if (wr_int || wr_int_direct) begin
- ioctl_dout <= wr_int ? data_w : data_w2;
+ wr_int_qspi <= 0;
+ if (wr_int || wr_int_direct || wr_int_qspi) begin
+ ioctl_dout <= wr_int ? data_w : wr_int_direct ? data_w2 : data_w3;
ioctl_wr <= 1;
addr <= addr + 1'd1;
ioctl_addr <= addr;
@@ -250,10 +341,203 @@ always@(posedge clk_sys) begin : DATA_OUT
rd_int <= uploading_reg;
end
// direct transfer receiver
- if (rclk2D ^ rclk2D2 && filepos != ioctl_filesize) begin
+ if (rclk2D ^ rclk2D2 && filepos != ioctl_filesize && downloading_reg) begin
filepos <= filepos + 1'd1;
wr_int_direct <= 1;
end
+ // QSPI transfer receiver
+ if (rclk3D ^ rclk3D2) begin
+ wr_int_qspi <= downloading_reg;
+ end
+
end
+// IDE handling
+generate if (ENABLE_IDE) begin
+
+reg [1:0] int_hdd0_ena;
+reg [1:0] int_hdd1_ena;
+reg int_hdd_cdda_wr;
+reg int_hdd_status_wr;
+reg [2:0] int_hdd_addr = 0;
+reg int_hdd_wr;
+reg [15:0] int_hdd_data_out;
+reg int_hdd_data_rd;
+reg int_hdd_data_wr;
+
+assign hdd0_ena = int_hdd0_ena;
+assign hdd1_ena = int_hdd1_ena;
+assign hdd_cdda_wr = int_hdd_cdda_wr;
+assign hdd_status_wr = int_hdd_status_wr;
+assign hdd_addr = int_hdd_addr;
+assign hdd_wr = int_hdd_wr;
+assign hdd_data_out = int_hdd_data_out;
+assign hdd_data_rd = int_hdd_data_rd;
+assign hdd_data_wr = int_hdd_data_wr;
+
+reg rst0 = 1;
+reg rst2 = 1;
+reg rclk_ide_stat = 0;
+reg rclk_ide_regs_rd = 0;
+reg rclk_ide_regs_wr = 0;
+reg rclk_ide_wr = 0;
+reg rclk_ide_rd = 0;
+reg rclk_cdda_wr = 0;
+reg [7:0] data_ide;
+
+always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER_IDE
+ if(SPI_SS2) begin
+ rst0 <= 1;
+ end else begin
+ rst0 <= 0;
+
+ if(cnt == 15) begin
+
+ case (cmd)
+ //IDE commands
+ CMD_IDE_CFG_WR:
+ if (bytecnt == 0) begin
+ int_hdd0_ena <= {sbuf[0], SPI_DI};
+ int_hdd1_ena <= sbuf[2:1];
+ end
+
+ CMD_IDE_STATUS_WR:
+ if (bytecnt == 0) begin
+ data_ide <= {sbuf, SPI_DI};
+ rclk_ide_stat <= ~rclk_ide_stat;
+ end
+
+ CMD_IDE_REGS_WR:
+ if (bytecnt >= 8 && bytecnt <= 18 && !bytecnt[0]) begin
+ data_ide <= {sbuf, SPI_DI};
+ rclk_ide_regs_wr <= ~rclk_ide_regs_wr;
+ end
+
+ CMD_IDE_REGS_RD:
+ if (bytecnt > 5 && !bytecnt[0]) begin
+ rclk_ide_regs_rd <= ~rclk_ide_regs_rd;
+ end
+
+ CMD_IDE_DATA_WR:
+ if (bytecnt > 4) begin
+ data_ide <= {sbuf, SPI_DI};
+ rclk_ide_wr <= ~rclk_ide_wr;
+ end
+
+ CMD_IDE_CDDA_WR:
+ if (bytecnt > 4) begin
+ data_ide <= {sbuf, SPI_DI};
+ rclk_cdda_wr <= ~rclk_cdda_wr;
+ end
+
+ CMD_IDE_DATA_RD:
+ if (bytecnt > 3) rclk_ide_rd <= ~rclk_ide_rd;
+
+ endcase
+ end
+ end
+end
+
+always@(posedge SPI_SCK, posedge SPI_SS4) begin : SPI_DIRECT_RECEIVER_IDE
+ if(SPI_SS4) begin
+ rst2 <= 1;
+ end else begin
+ rst2 <= 0;
+ end
+end
+
+always@(posedge hdd_clk) begin : IDE_OUT
+ reg loword;
+
+ // synchronisers
+ reg rclk2D, rclk2D2;
+ reg rclk_ide_statD, rclk_ide_statD2;
+ reg rclk_cdda_wrD, rclk_cdda_wrD2;
+ reg rclk_ide_wrD, rclk_ide_wrD2;
+ reg rclk_ide_rdD, rclk_ide_rdD2;
+ reg rclk_ide_regs_wrD, rclk_ide_regs_wrD2;
+ reg rclk_ide_regs_rdD, rclk_ide_regs_rdD2;
+ reg rst0D, rst0D2;
+ reg rst2D, rst2D2;
+
+ // bring flags from spi clock domain into core clock domain
+ { rclk2D ,rclk2D2 } <= { rclk2, rclk2D };
+ { rclk_ide_statD, rclk_ide_statD2 } <= { rclk_ide_stat, rclk_ide_statD };
+ { rclk_ide_rdD, rclk_ide_rdD2 } <= { rclk_ide_rd, rclk_ide_rdD };
+ { rclk_ide_wrD, rclk_ide_wrD2 } <= { rclk_ide_wr, rclk_ide_wrD };
+ { rclk_cdda_wrD, rclk_cdda_wrD2 } <= { rclk_cdda_wr, rclk_cdda_wrD };
+ { rclk_ide_regs_rdD, rclk_ide_regs_rdD2 } <= { rclk_ide_regs_rd, rclk_ide_regs_rdD };
+ { rclk_ide_regs_wrD, rclk_ide_regs_wrD2 } <= { rclk_ide_regs_wr, rclk_ide_regs_wrD };
+ { rst0D, rst0D2 } <= { rst0, rst0D };
+ { rst2D, rst2D2 } <= { rst2, rst2D };
+
+ // IDE receiver
+ int_hdd_wr <= 0;
+ int_hdd_status_wr <= 0;
+ int_hdd_data_wr <= 0;
+ int_hdd_data_rd <= 0;
+ int_hdd_cdda_wr <= 0;
+
+ if (rst0D2) int_hdd_addr <= 0;
+ if (rst0D2 && rst2D2) loword <= 0;
+
+ if (rclk_ide_statD ^ rclk_ide_statD2) begin
+ int_hdd_status_wr <= 1;
+ int_hdd_data_out <= {8'h00, data_ide};
+ end
+ if (rclk_ide_rdD ^ rclk_ide_rdD2) begin
+ loword <= ~loword;
+ if (loword)
+ int_hdd_data_rd <= 1;
+ end
+ if (rclk_ide_wrD ^ rclk_ide_wrD2) begin
+ loword <= ~loword;
+ if (!loword)
+ int_hdd_data_out[15:8] <= data_ide;
+ else begin
+ int_hdd_data_wr <= 1;
+ int_hdd_data_out[7:0] <= data_ide;
+ end
+ end
+ if (rclk_cdda_wrD ^ rclk_cdda_wrD2) begin
+ loword <= ~loword;
+ if (!loword)
+ int_hdd_data_out[15:8] <= data_ide;
+ else begin
+ int_hdd_cdda_wr <= 1;
+ int_hdd_data_out[7:0] <= data_ide;
+ end
+ end
+ if (rclk2D ^ rclk2D2 && !downloading_reg) begin
+ loword <= ~loword;
+ if (!loword)
+ int_hdd_data_out[15:8] <= data_w2;
+ else begin
+ int_hdd_data_wr <= 1;
+ int_hdd_data_out[7:0] <= data_w2;
+ end
+ end
+ if (rclk_ide_regs_wrD ^ rclk_ide_regs_wrD2) begin
+ int_hdd_wr <= 1;
+ int_hdd_data_out <= {8'h00, data_ide};
+ int_hdd_addr <= int_hdd_addr + 1'd1;
+ end
+ if (rclk_ide_regs_rdD ^ rclk_ide_regs_rdD2) begin
+ int_hdd_addr <= int_hdd_addr + 1'd1;
+ end
+end
+end else begin
+ assign hdd0_ena = 0;
+ assign hdd1_ena = 0;
+ assign hdd_cdda_wr = 0;
+ assign hdd_status_wr = 0;
+ assign hdd_addr = 0;
+ assign hdd_wr = 0;
+ assign hdd_data_out = 0;
+ assign hdd_data_rd = 0;
+ assign hdd_data_wr = 0;
+end
+
+endgenerate
+
endmodule
diff --git a/common/mist/ide.v b/common/mist/ide.v
new file mode 100644
index 00000000..393699c4
--- /dev/null
+++ b/common/mist/ide.v
@@ -0,0 +1,405 @@
+// Copyright 2008, 2009 by Jakub Bednarski
+//
+// Extracted from Minimig gayle.v
+//
+// Minimig 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.
+//
+// Minimig 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 .
+//
+//
+//
+// -- JB --
+//
+// 2008-10-06 - initial version
+// 2008-10-08 - interrupt controller implemented, kickstart boots
+// 2008-10-09 - working identify device command implemented (hdtoolbox detects our drive)
+// - read command reads data from hardfile (fixed size and name, only one sector read size supported, workbench sees hardfile partition)
+// 2008-10-10 - multiple sector transfer supported: works ok, sequential transfers with direct spi read and 28MHz CPU from 400 to 520 KB/s
+// - arm firmare seekfile function very slow: seeking from start to 20MB takes 144 ms (some software improvements required)
+// 2008-10-30 - write support added
+// 2008-12-31 - added hdd enable
+// 2009-05-24 - clean-up & renaming
+// 2009-08-11 - hdd_ena enables Master & Slave drives
+// 2009-11-18 - changed sector buffer size
+// 2010-04-13 - changed sector buffer size
+// 2010-08-10 - improved BSY signal handling
+// 2022-08-18 - added packet command handling
+
+module ide
+(
+ input clk,
+ input clk_en,
+ input reset,
+ input [2:0] address_in,
+ input sel_secondary,
+ input [15:0] data_in,
+ output [15:0] data_out,
+ output data_oe,
+ input rd,
+ input hwr,
+ input lwr,
+ input sel_ide,
+ output reg [1:0] intreq,
+ input [1:0] intreq_ack, // interrupt clear
+ output nrdy, // fifo is not ready for reading
+ input [1:0] hdd0_ena, // enables Master & Slave drives on primary channel
+ input [1:0] hdd1_ena, // enables Master & Slave drives on secondary channel
+ output fifo_rd,
+ output fifo_wr,
+
+ // connection to the IO-Controller
+ output hdd_cmd_req,
+ output hdd_dat_req,
+ input [2:0] hdd_addr,
+ input [15:0] hdd_data_out,
+ output [15:0] hdd_data_in,
+ input hdd_wr,
+ input hdd_status_wr,
+ input hdd_data_wr,
+ input hdd_data_rd
+);
+
+localparam VCC = 1'b1;
+localparam GND = 1'b0;
+
+/*
+0 Data
+1 Error | Feature
+2 SectorCount
+3 SectorNumber
+4 CylinderLow
+5 CylinderHigh
+6 Device/Head
+7 Status | Command
+
+command class:
+PI (PIO In)
+PO (PIO Out)
+ND (No Data)
+
+Status:
+#6 - DRDY - Drive Ready
+#7 - BSY - Busy
+#3 - DRQ - Data Request
+#0 - ERR - Error
+INTRQ - Interrupt Request
+
+*/
+
+
+// address decoding signals
+wire sel_tfr; // HDD task file registers select
+wire sel_fifo; // HDD data port select (FIFO buffer)
+wire sel_status /* synthesis keep */; // HDD status register select
+wire sel_command /* synthesis keep */;// HDD command register select
+
+// internal registers
+reg block_mark; // IDE multiple block start flag
+reg busy; // busy status (command processing state)
+reg pio_in; // pio in command type is being processed
+reg pio_out; // pio out command type is being processed
+reg error; // error status (command processing failed)
+
+reg [1:0] dev; // drive select (Primary/Secondary, Master/Slave)
+wire bsy; // busy
+wire drdy; // drive ready
+wire drq; // data request
+reg drq_d; // data request
+wire err; // error
+wire [7:0] status; // HDD status
+
+// FIFO control
+wire fifo_reset;
+wire [15:0] fifo_data_in;
+wire [15:0] fifo_data_out;
+wire fifo_full;
+wire fifo_empty;
+wire fifo_last_out; // last word of a sector is being read
+wire fifo_last_in; // last word of a sector is being written
+
+
+// HDD status register
+assign status = {bsy,drdy,2'b01,drq,2'b00,err};
+
+// packet states
+reg [1:0] packet_state;
+localparam PACKET_IDLE = 0;
+localparam PACKET_WAITCMD = 1;
+localparam PACKET_PROCESSCMD = 2;
+wire packet_state_change;
+reg [12:0] packet_count;
+wire packet_in_last;
+wire packet_in;
+wire packet_out;
+
+`ifdef IDE_DEBUG
+// cmd/status debug
+reg [7:0] status_dbg /* synthesis noprune */;
+reg [7:0] dbg_ide_cmd /* synthesis noprune */;
+reg [2:0] dbg_addr /* synthesis noprune */;
+reg dbg_wr /* synthesis noprune */;
+reg[15:0] dbg_data_in /* synthesis noprune */;
+reg[15:0] dbg_data_out /* synthesis noprune */;
+
+always @(posedge clk) begin
+ status_dbg <= status;
+ if (clk_en) begin
+ dbg_wr <= 0;
+ if (sel_command) // set when the CPU writes command register
+ dbg_ide_cmd <= data_in[15:8];
+ if (sel_ide) begin
+ dbg_addr <= address_in;
+ dbg_wr <= hwr | lwr;
+ if (rd) dbg_data_out <= data_out;
+ if (hwr | lwr) dbg_data_in <= data_in;
+ end
+ end
+end
+`endif
+
+// HDD status register bits
+assign bsy = busy & ~drq;
+assign drdy = ~(bsy|drq);
+assign err = error;
+
+// address decoding
+assign sel_tfr = sel_ide;
+assign sel_status = rd && sel_tfr && address_in==3'b111 ? VCC : GND;
+assign sel_command = hwr && sel_tfr && address_in==3'b111 ? VCC : GND;
+assign sel_fifo = sel_tfr && address_in==3'b000 ? VCC : GND;
+
+//===============================================================================================//
+
+// task file registers
+reg [7:0] tfr [7:0];
+wire [2:0] tfr_sel;
+wire [7:0] tfr_in;
+wire [7:0] tfr_out;
+wire tfr_we;
+
+reg [8:0] sector_count; // sector counter
+wire sector_count_dec_in; // decrease sector counter (reads)
+wire sector_count_dec_out; // decrease sector counter (writes)
+
+always @(posedge clk)
+ if (clk_en) begin
+ if (hwr && sel_tfr && address_in == 3'b010) begin // sector count register loaded by the host
+ sector_count <= {1'b0, data_in[15:8]};
+ if (data_in[15:8] == 0) sector_count <= 9'd256;
+ end else if (sector_count_dec_in || sector_count_dec_out)
+ sector_count <= sector_count - 8'd1;
+ end
+
+reg rd_old;
+reg wr_old;
+reg sel_fifo_old;
+always @(posedge clk)
+ if (clk_en) begin
+ rd_old <= rd;
+ wr_old <= hwr & lwr;
+ sel_fifo_old <= sel_fifo;
+ end
+
+assign sector_count_dec_in = pio_in & fifo_last_out & sel_fifo_old & ~rd & rd_old & packet_state == PACKET_IDLE;
+assign sector_count_dec_out = pio_out & fifo_last_in & sel_fifo_old & ~hwr & ~lwr & wr_old & packet_state == PACKET_IDLE;
+
+// task file register control
+assign tfr_we = packet_in_last ? 1'b1 : bsy ? hdd_wr : sel_tfr & hwr;
+assign tfr_sel = packet_in_last ? 3'd2 : bsy ? hdd_addr : address_in;
+assign tfr_in = packet_in_last ? 8'h03: bsy ? hdd_data_out[7:0] : data_in[15:8];
+
+// input multiplexer for SPI host
+assign hdd_data_in = tfr_sel==0 ? fifo_data_out : {7'h0, dev[1], tfr_out};
+
+// task file registers
+always @(posedge clk)
+ if (clk_en) begin
+ if (tfr_we)
+ tfr[tfr_sel] <= tfr_in;
+ end
+
+assign tfr_out = tfr[tfr_sel];
+
+// master/slave drive select
+always @(posedge clk)
+ if (clk_en) begin
+ if (reset)
+ dev <= 0;
+ else if (sel_tfr && address_in==6 && hwr)
+ dev <= {sel_secondary, data_in[12]};
+ end
+
+assign packet_state_change = busy && hdd_status_wr && hdd_data_out[5];
+
+// bytes count in a packet
+always @(posedge clk)
+ if (clk_en) begin
+ if (reset)
+ packet_count <= 0;
+ else if (hdd_wr && hdd_addr == 4)
+ packet_count[6:0] <= hdd_data_out[7:1];
+ else if (hdd_wr && hdd_addr == 5)
+ packet_count[12:7] <= hdd_data_out[5:0];
+ else if (packet_state_change && packet_state == PACKET_IDLE)
+ packet_count <= 13'd6; // IDLE->WAITCMD transition, expect 6 words of packet command
+ end
+
+// status register (write only from SPI host)
+// 7 - busy status (write zero to finish command processing: allow host access to task file registers)
+// 6
+// 5
+// 4 - intreq (used for writes only)
+// 3 - drq enable for pio in (PI) command type
+// 2 - drq enable for pio out (PO) command type
+// 1
+// 0 - error flag (remember about setting error task file register)
+
+// command busy status
+always @(posedge clk)
+ if (clk_en) begin
+ if (reset)
+ busy <= GND;
+ else if (hdd_status_wr && hdd_data_out[7] || (sector_count_dec_in && sector_count == 9'h01)) // reset by SPI host (by clearing BSY status bit)
+ busy <= GND;
+ else if (sel_command) // set when the CPU writes command register
+ busy <= VCC;
+ end
+
+// IDE interrupt request register
+always @(posedge clk)
+ if (clk_en) begin
+ drq_d <= drq;
+
+ if (reset) begin
+ intreq[0] <= GND;
+ intreq[1] <= GND;
+ block_mark <= GND;
+ end else begin
+ if (busy && hdd_status_wr && hdd_data_out[3])
+ block_mark <= VCC; // to handle IDENTIFY
+
+ if (pio_in) begin // reads
+ if (hdd_status_wr && hdd_data_out[4])
+ block_mark <= VCC;
+ if ((error | (!drq_d & drq)) & block_mark) begin
+ intreq[dev[1]] <= VCC;
+ block_mark <= GND;
+ end
+ if (packet_in_last) // read the last word from the packet command result
+ intreq[dev[1]] <= VCC;
+ end else if (pio_out) begin // writes
+ if (hdd_status_wr && hdd_data_out[4])
+ intreq[dev[1]] <= VCC;
+ end else if (hdd_status_wr && hdd_data_out[7]) // other command types completed
+ intreq[dev[1]] <= VCC;
+ else if (packet_state_change && packet_state == PACKET_IDLE) // ready to accept command packet
+ intreq[dev[1]] <= VCC;
+
+ if (intreq_ack[0]) intreq[0] <= GND; // cleared by the CPU
+ if (intreq_ack[1]) intreq[1] <= GND; // cleared by the CPU
+
+ end
+ end
+
+// pio in command type
+always @(posedge clk)
+ if (clk_en) begin
+ if (reset)
+ pio_in <= GND;
+ else if (drdy) // reset when processing of the current command ends
+ pio_in <= GND;
+ else if (busy && hdd_status_wr && hdd_data_out[3]) // set by SPI host
+ pio_in <= VCC;
+ end
+
+// pio out command type
+always @(posedge clk)
+ if (clk_en) begin
+ if (reset)
+ pio_out <= GND;
+ else if (busy && hdd_status_wr && hdd_data_out[7]) // reset by SPI host when command processing completes
+ pio_out <= GND;
+ else if (busy && hdd_status_wr && hdd_data_out[3]) // pio_in set by SPI host (during PACKET processing)
+ pio_out <= GND;
+ else if (busy && hdd_status_wr && hdd_data_out[2]) // set by SPI host
+ pio_out <= VCC;
+ end
+
+// packet command state machine
+always @(posedge clk)
+ if (clk_en) begin
+ if (reset)
+ packet_state <= PACKET_IDLE;
+ else if (drdy) // reset when processing of the current command ends
+ packet_state <= PACKET_IDLE;
+ else if (packet_state_change) // set by SPI host
+ packet_state <= packet_state == PACKET_IDLE ? PACKET_WAITCMD :
+ packet_state == PACKET_WAITCMD ? PACKET_PROCESSCMD : packet_state;
+ end
+
+assign drq = (fifo_full & pio_in) | (~fifo_full & pio_out & (sector_count != 0 || packet_out)); // HDD data request status bit
+
+// error status
+always @(posedge clk)
+ if (clk_en) begin
+ if (reset)
+ error <= GND;
+ else if (sel_command) // reset by the CPU when command register is written
+ error <= GND;
+ else if (busy && hdd_status_wr && hdd_data_out[0]) // set by SPI host
+ error <= VCC;
+ end
+
+assign hdd_cmd_req = bsy; // bsy is set when command register is written, tells the SPI host about new command
+assign hdd_dat_req = (fifo_full & pio_out); // the FIFO is full so SPI host may read it
+
+// FIFO in/out multiplexer
+assign fifo_reset = reset | sel_command | packet_state_change | packet_in_last;
+assign fifo_data_in = pio_in ? hdd_data_out : data_in;
+assign fifo_rd = pio_out ? hdd_data_rd : sel_fifo & rd;
+assign fifo_wr = pio_in ? hdd_data_wr : sel_fifo & hwr & lwr;
+
+assign packet_in = packet_state == PACKET_PROCESSCMD && pio_in;
+assign packet_out = packet_state == PACKET_WAITCMD || (packet_state == PACKET_PROCESSCMD && pio_out);
+
+//sector data buffer (FIFO)
+ide_fifo SECBUF1
+(
+ .clk(clk),
+ .clk_en(clk_en),
+ .reset(fifo_reset),
+ .data_in(fifo_data_in),
+ .data_out(fifo_data_out),
+ .rd(fifo_rd),
+ .wr(fifo_wr),
+ .packet_in(packet_in),
+ .packet_out(packet_out),
+ .packet_count(packet_count),
+ .packet_in_last(packet_in_last),
+ .full(fifo_full),
+ .empty(fifo_empty),
+ .last_out(fifo_last_out),
+ .last_in(fifo_last_in)
+);
+
+// fifo is not ready for reading
+assign nrdy = pio_in & sel_fifo & fifo_empty;
+
+assign data_oe = (!dev[1] && hdd0_ena[dev[0]]) || (dev[1] && hdd1_ena[dev[0]]);
+//data_out multiplexer
+assign data_out = sel_fifo && rd ? fifo_data_out :
+ sel_status ? data_oe ? {status,8'h00} : 16'h00_00 :
+ sel_tfr && rd ? {tfr_out,8'h00} : 16'h00_00;
+
+//===============================================================================================//
+
+endmodule
diff --git a/common/mist/ide_fifo.v b/common/mist/ide_fifo.v
new file mode 100644
index 00000000..24221efe
--- /dev/null
+++ b/common/mist/ide_fifo.v
@@ -0,0 +1,86 @@
+module ide_fifo
+(
+ input clk, // bus clock
+ input clk_en,
+ input reset, // reset
+ input [15:0] data_in, // data in
+ output reg [15:0] data_out, // data out
+ input rd, // read from fifo
+ input wr, // write to fifo
+ input packet_in,
+ input packet_out,
+ input [12:0] packet_count,
+ output packet_in_last, // last word is read in packet_in state
+ output full, // fifo is full
+ output empty, // fifo is empty
+ output last_out, // the last word of a sector is being read
+ output last_in // the last word of a sector is being written
+);
+
+// local signals and registers
+reg [15:0] mem [4095:0]; // 16 bit wide fifo memory
+reg [12:0] inptr; // fifo input pointer
+reg [12:0] outptr; // fifo output pointer
+wire empty_rd; // fifo empty flag (set immediately after reading the last word)
+reg empty_wr; // fifo empty flag (set one clock after writting the empty fifo)
+reg rd_old;
+reg wr_old;
+
+always @(posedge clk)
+ if (clk_en) begin
+ rd_old <= rd;
+ wr_old <= wr;
+ end
+
+// main fifo memory (implemented using synchronous block ram)
+always @(posedge clk)
+ if (clk_en) begin
+ if (wr)
+ mem[inptr[11:0]] <= data_in;
+ end
+
+always @(posedge clk)
+ if (clk_en)
+ data_out <= mem[outptr[11:0]];
+
+// fifo write pointer control
+always @(posedge clk)
+ if (clk_en) begin
+ if (reset)
+ inptr <= 0;
+ else if (wr_old & ~wr)
+ inptr <= inptr + 1'd1;
+ end
+
+// fifo read pointer control
+always @(posedge clk)
+ if (clk_en) begin
+ if (reset)
+ outptr <= 0;
+ else if (rd_old & ~rd)
+ outptr <= outptr + 1'd1;
+ end
+
+// the empty flag is set immediately after reading the last word from the fifo
+assign empty_rd = inptr==outptr ? 1'b1 : 1'b0;
+
+// after writting empty fifo the empty flag is delayed by one clock to handle ram write delay
+always @(posedge clk)
+ if (clk_en)
+ empty_wr <= empty_rd;
+
+assign empty = empty_rd | empty_wr;
+
+// at least 512 bytes are in FIFO
+// this signal is activated when 512th byte is written to the empty fifo
+// then it's deactivated when 512th byte is read from the fifo (hysteresis)
+// special handlig of packet commands
+assign full = (inptr[12:8] != outptr[12:8] && !packet_in && !packet_out) ||
+ (packet_in && inptr == packet_count && inptr != outptr) ||
+ (packet_out && inptr == packet_count /*&& inptr != outptr*/);
+assign packet_in_last = packet_in && inptr == packet_count && inptr == outptr && inptr != 0;
+
+assign last_out = outptr[7:0] == 8'hFF ? 1'b1 : 1'b0;
+assign last_in = inptr [7:0] == 8'hFF ? 1'b1 : 1'b0;
+
+endmodule
diff --git a/common/mist/mist.qip b/common/mist/mist.qip
index de360210..923b5289 100644
--- a/common/mist/mist.qip
+++ b/common/mist/mist.qip
@@ -7,4 +7,8 @@ set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) osd.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) arcade_inputs.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) rgb2ypbpr.v]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) cofi.sv]
+set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) sd_card.v]
+set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ide.v]
+set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ide_fifo.v]
+set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) cdda_fifo.v]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) dac.vhd]
diff --git a/common/mist/mist.vhd b/common/mist/mist.vhd
index d37c947c..2255c8b7 100644
--- a/common/mist/mist.vhd
+++ b/common/mist/mist.vhd
@@ -48,6 +48,7 @@ port (
sd_wr : in std_logic_vector(SD_IMAGES-1 downto 0) := (others => '0');
sd_ack : out std_logic;
sd_ack_conf : out std_logic;
+ sd_ack_x : out std_logic_vector(SD_IMAGES-1 downto 0);
sd_conf : in std_logic := '0';
sd_sdhc : in std_logic := '1';
img_size : out std_logic_vector(63 downto 0);
@@ -99,7 +100,7 @@ port (
SPI_DI : in std_logic;
scanlines : in std_logic_vector(1 downto 0);
- ce_divider : in std_logic := '0';
+ ce_divider : in std_logic_vector(2 downto 0) := "000";
scandoubler_disable : in std_logic;
ypbpr : in std_logic;
rotate : in std_logic_vector(1 downto 0);
diff --git a/common/mist/mist_video.v b/common/mist/mist_video.v
index 070ab50b..712b1dff 100644
--- a/common/mist/mist_video.v
+++ b/common/mist/mist_video.v
@@ -15,8 +15,9 @@ module mist_video
// scanlines (00-none 01-25% 10-50% 11-75%)
input [1:0] scanlines,
- // non-scandoubled pixel clock divider 0 - clk_sys/4, 1 - clk_sys/2
- input ce_divider,
+ // non-scandoubled pixel clock divider:
+ // 0 - clk_sys/4, 1 - clk_sys/2, 2 - clk_sys/3, 3 - clk_sys/4, etc
+ input [2:0] ce_divider,
// 0 = HVSync 31KHz, 1 = CSync 15KHz
input scandoubler_disable,
@@ -59,7 +60,7 @@ wire [5:0] SD_B_O;
wire SD_HS_O;
wire SD_VS_O;
-wire pixel_ena;
+wire pixel_ena;
scandoubler #(SD_HCNT_WIDTH, COLOR_DEPTH) scandoubler
(
diff --git a/common/mist/scandoubler.v b/common/mist/scandoubler.v
index c9f0d684..8c54632b 100644
--- a/common/mist/scandoubler.v
+++ b/common/mist/scandoubler.v
@@ -18,12 +18,25 @@
// TODO: Delay vsync one line
+// AMR - generates and output a pixel clock with a reliable phase relationship with
+// with the scandoubled hsync pulse. Allows the incoming data to be sampled more
+// sparsely, reducing block RAM usage. ce_x1/x2 are replaced with a ce_divider
+// which is the largest value the counter will reach before resetting - so 3'111 to
+// divide clk_sys by 8, 3'011 to divide by 4, 3'101 to divide by six.
+
+// Also now has a bypass mode, in which the incoming data will be scaled to the output
+// width but otherwise unmodified. Simplifies the rest of the video chain.
+
+
module scandoubler
(
// system interface
input clk_sys,
+
input bypass,
- input ce_divider,
+
+ // Pixelclock
+ input [2:0] ce_divider, // 0 - clk_sys/4, 1 - clk_sys/2, 2 - clk_sys/3, 3 - clk_sys/4, etc.
output pixel_ena,
// scanlines (00-none 01-25% 10-50% 11-75%)
@@ -37,41 +50,16 @@ module scandoubler
input [COLOR_DEPTH-1:0] b_in,
// output interface
- output reg hs_out,
- output reg vs_out,
- output reg [5:0] r_out,
- output reg [5:0] g_out,
- output reg [5:0] b_out
+ output hs_out,
+ output vs_out,
+ output [5:0] r_out,
+ output [5:0] g_out,
+ output [5:0] b_out
);
-parameter HCNT_WIDTH = 9;
-parameter COLOR_DEPTH = 6;
-
-// pixel clock divider
-reg [1:0] i_div;
-reg ce_x1, ce_x2;
-
-always @(posedge clk_sys) begin
- reg last_hs_in;
- last_hs_in <= hs_in;
- if(last_hs_in & !hs_in) begin
- i_div <= 2'b00;
- end else begin
- i_div <= i_div + 2'd1;
- end
-end
-
-always @(*) begin
- if (!ce_divider) begin
- ce_x1 = (i_div == 2'b01);
- ce_x2 = i_div[0];
- end else begin
- ce_x1 = i_div[0];
- ce_x2 = 1'b1;
- end
-end
-
-assign pixel_ena = bypass ? ce_x1 : ce_x2;
+parameter HCNT_WIDTH = 9; // Resolution of scandoubler buffer
+parameter COLOR_DEPTH = 6; // Bits per colour to be stored in the buffer
+parameter HSCNT_WIDTH = 12; // Resolution of hsync counters
// --------------------- create output signals -----------------
// latch everything once more to make it glitch free and apply scanline effect
@@ -80,74 +68,85 @@ reg [5:0] r;
reg [5:0] g;
reg [5:0] b;
+wire [5:0] r_o;
+wire [5:0] g_o;
+wire [5:0] b_o;
+reg hs_o;
+reg vs_o;
+
+wire [COLOR_DEPTH*3-1:0] sd_mux = bypass ? {r_in, g_in, b_in} : sd_out;
+
always @(*) begin
if (COLOR_DEPTH == 6) begin
- b = sd_out[5:0];
- g = sd_out[11:6];
- r = sd_out[17:12];
+ b = sd_mux[5:0];
+ g = sd_mux[11:6];
+ r = sd_mux[17:12];
end else if (COLOR_DEPTH == 2) begin
- b = {3{sd_out[1:0]}};
- g = {3{sd_out[3:2]}};
- r = {3{sd_out[5:4]}};
+ b = {3{sd_mux[1:0]}};
+ g = {3{sd_mux[3:2]}};
+ r = {3{sd_mux[5:4]}};
end else if (COLOR_DEPTH == 1) begin
- b = {6{sd_out[0]}};
- g = {6{sd_out[1]}};
- r = {6{sd_out[2]}};
+ b = {6{sd_mux[0]}};
+ g = {6{sd_mux[1]}};
+ r = {6{sd_mux[2]}};
end else begin
- b = { sd_out[COLOR_DEPTH-1:0], sd_out[COLOR_DEPTH-1 -:(6-COLOR_DEPTH)] };
- g = { sd_out[COLOR_DEPTH*2-1:COLOR_DEPTH], sd_out[COLOR_DEPTH*2-1 -:(6-COLOR_DEPTH)] };
- r = { sd_out[COLOR_DEPTH*3-1:COLOR_DEPTH*2], sd_out[COLOR_DEPTH*3-1 -:(6-COLOR_DEPTH)] };
+ b = { sd_mux[COLOR_DEPTH-1:0], sd_mux[COLOR_DEPTH-1 -:(6-COLOR_DEPTH)] };
+ g = { sd_mux[COLOR_DEPTH*2-1:COLOR_DEPTH], sd_mux[COLOR_DEPTH*2-1 -:(6-COLOR_DEPTH)] };
+ r = { sd_mux[COLOR_DEPTH*3-1:COLOR_DEPTH*2], sd_mux[COLOR_DEPTH*3-1 -:(6-COLOR_DEPTH)] };
end
end
+
+reg [12:0] r_mul;
+reg [12:0] g_mul;
+reg [12:0] b_mul;
+
+wire scanline_bypass = (!scanline) | (!(|scanlines)) | bypass;
+
+// More subtle variant of the scanlines effect.
+// 0 00 -> 1000000 0x40 - bypass / inert mode
+// 1 01 -> 0111010 0x3a - 25%
+// 2 10 -> 0101110 0x2e - 50%
+// 3 11 -> 0011010 0x1a - 75%
+
+wire [6:0] scanline_coeff = scanline_bypass ?
+ 7'b1000000 : {~(&scanlines),scanlines[0],1'b1,~scanlines[0],2'b10};
+
always @(posedge clk_sys) begin
- if(bypass) begin
- r_out <= r;
- g_out <= g;
- b_out <= b;
- hs_out <= hs_sd;
- vs_out <= vs_sd;
- end else if(ce_x2) begin
- hs_out <= hs_sd;
- vs_out <= vs_sd;
+ if(ce_x2) begin
+ hs_o <= hs_sd;
+ vs_o <= vs_in;
// reset scanlines at every new screen
- if(vs_out != vs_in) scanline <= 0;
+ if(vs_o != vs_in) scanline <= 0;
// toggle scanlines at begin of every hsync
- if(hs_out && !hs_sd) scanline <= !scanline;
+ if(hs_o && !hs_sd) scanline <= !scanline;
- // if no scanlines or not a scanline
- if(!scanline || !scanlines) begin
- r_out <= r;
- g_out <= g;
- b_out <= b;
- end else begin
- case(scanlines)
- 1: begin // reduce 25% = 1/2 + 1/4
- r_out <= {1'b0, r[5:1]} + {2'b00, r[5:2] };
- g_out <= {1'b0, g[5:1]} + {2'b00, g[5:2] };
- b_out <= {1'b0, b[5:1]} + {2'b00, b[5:2] };
- end
-
- 2: begin // reduce 50% = 1/2
- r_out <= {1'b0, r[5:1]};
- g_out <= {1'b0, g[5:1]};
- b_out <= {1'b0, b[5:1]};
- end
-
- 3: begin // reduce 75% = 1/4
- r_out <= {2'b00, r[5:2]};
- g_out <= {2'b00, g[5:2]};
- b_out <= {2'b00, b[5:2]};
- end
- endcase
- end
+ r_mul<=r*scanline_coeff;
+ g_mul<=g*scanline_coeff;
+ b_mul<=b*scanline_coeff;
end
end
+assign r_o = r_mul[11:6];
+assign g_o = g_mul[11:6];
+assign b_o = b_mul[11:6];
+
+
+// Output multiplexing
+
+assign r_out = bypass ? r : r_o;
+assign g_out = bypass ? g : g_o;
+assign b_out = bypass ? b : b_o;
+assign hs_out = bypass ? hs_in : hs_o;
+assign vs_out = bypass ? vs_in : vs_o;
+
+assign pixel_ena = bypass ? ce_x1 : ce_x2;
+
+
// scan doubler output register
-wire [COLOR_DEPTH*3-1:0] sd_out = bypass ? sd_bypass_out : sd_buffer_out;
+reg [COLOR_DEPTH*3-1:0] sd_out;
// ==================================================================
// ======================== the line buffers ========================
@@ -160,70 +159,104 @@ wire [COLOR_DEPTH*3-1:0] sd_out = bypass ? sd_bypass_out : sd_buffer_out;
reg line_toggle;
// total hsync time (in 16MHz cycles), hs_total reaches 1024
-reg [HCNT_WIDTH-1:0] hs_max;
-reg [HCNT_WIDTH-1:0] hs_rise;
reg [HCNT_WIDTH-1:0] hcnt;
+reg [HSCNT_WIDTH:0] hs_max;
+reg [HSCNT_WIDTH:0] hs_rise;
+reg [HSCNT_WIDTH:0] synccnt;
+
+// Input pixel clock, aligned with input sync:
+wire[2:0] ce_divider_adj = |ce_divider ? ce_divider : 3'd3; // 0 = clk/4 for compatiblity
+reg [2:0] ce_divider_in;
+reg [2:0] ce_divider_out;
+
+reg [2:0] i_div;
+wire ce_x1 = (i_div == ce_divider_in);
always @(posedge clk_sys) begin
reg hsD, vsD;
+ // Pixel logic on x1 clkena
if(ce_x1) begin
- hsD <= hs_in;
-
- // falling edge of hsync indicates start of line
- if(hsD && !hs_in) begin
- hs_max <= hcnt;
- hcnt <= 0;
- end else begin
- hcnt <= hcnt + 1'd1;
- end
-
- // save position of rising edge
- if(!hsD && hs_in) hs_rise <= hcnt;
-
- vsD <= vs_in;
- if(vsD != vs_in) line_toggle <= 0;
-
- // begin of incoming hsync
- if(hsD && !hs_in) line_toggle <= !line_toggle;
-
+ hcnt <= hcnt + 1'd1;
sd_buffer[{line_toggle, hcnt}] <= {r_in, g_in, b_in};
end
+
+ // Generate pixel clock
+ i_div <= i_div + 1'd1;
+
+ if (i_div==ce_divider_adj) i_div <= 3'b000;
+
+ synccnt <= synccnt + 1'd1;
+ hsD <= hs_in;
+ if(hsD && !hs_in) begin
+ // At hsync latch the ce_divider counter limit for the input clock
+ // and pass the previous input clock limit to the output stage.
+ // This should give correct output if the pixel clock changes mid-screen.
+ ce_divider_out <= ce_divider_in;
+ ce_divider_in <= ce_divider_adj;
+ hs_max <= {1'b0,synccnt[HSCNT_WIDTH:1]};
+ hcnt <= 0;
+ synccnt <= 0;
+ i_div <= 3'b000;
+ end
+
+ // save position of rising edge
+ if(!hsD && hs_in) hs_rise <= {1'b0,synccnt[HSCNT_WIDTH:1]};
+
+ // begin of incoming hsync
+ if(hsD && !hs_in) line_toggle <= !line_toggle;
+
+ vsD <= vs_in;
+ if(vsD != vs_in) line_toggle <= 0;
+
end
// ==================================================================
// ==================== output timing generation ====================
// ==================================================================
-reg [COLOR_DEPTH*3-1:0] sd_buffer_out, sd_bypass_out;
-reg [HCNT_WIDTH-1:0] sd_hcnt;
-reg hs_sd, vs_sd;
+reg [HSCNT_WIDTH:0] sd_synccnt;
+reg [HCNT_WIDTH-1:0] sd_hcnt;
+reg hs_sd;
+
+// Output pixel clock, aligned with output sync:
+reg [2:0] sd_i_div;
+wire ce_x2 = (sd_i_div == ce_divider_out) | (sd_i_div == {1'b0,ce_divider_out[2:1]});
// timing generation runs 32 MHz (twice the input signal analysis speed)
always @(posedge clk_sys) begin
reg hsD;
+ // Output logic on x2 clkena
if(ce_x2) begin
- hsD <= hs_in;
-
// output counter synchronous to input and at twice the rate
sd_hcnt <= sd_hcnt + 1'd1;
- if(hsD && !hs_in) sd_hcnt <= hs_max;
- if(sd_hcnt == hs_max) sd_hcnt <= 0;
-
- // replicate horizontal sync at twice the speed
- if(sd_hcnt == hs_max) hs_sd <= 0;
- if(sd_hcnt == hs_rise) hs_sd <= 1;
// read data from line sd_buffer
- sd_buffer_out <= sd_buffer[{~line_toggle, sd_hcnt}];
- vs_sd <= vs_in;
+ sd_out <= sd_buffer[{~line_toggle, sd_hcnt}];
end
- if(bypass) begin
- sd_bypass_out <= {r_in, g_in, b_in};
- hs_sd <= hs_in;
- vs_sd <= vs_in;
+
+ // Framing logic on sysclk
+ sd_synccnt <= sd_synccnt + 1'd1;
+ hsD <= hs_in;
+ if(hsD && !hs_in) sd_synccnt <= hs_max;
+
+ if(sd_synccnt == hs_max) begin
+ sd_synccnt <= 0;
+ sd_hcnt <= 0;
end
+
+ sd_i_div <= sd_i_div + 1'd1;
+ if (sd_i_div==ce_divider_adj) sd_i_div <= 3'b000;
+
+ // replicate horizontal sync at twice the speed
+ if(sd_synccnt == 0) begin
+ hs_sd <= 0;
+ sd_i_div <= 3'b000;
+ end
+
+ if(sd_synccnt == hs_rise) hs_sd <= 1;
+
end
endmodule
diff --git a/common/mist/sd_card.v b/common/mist/sd_card.v
index 0d1ff58d..88fcbb30 100644
--- a/common/mist/sd_card.v
+++ b/common/mist/sd_card.v
@@ -503,6 +503,9 @@ always@(posedge clk_sys) begin
reply_len <= 4'd4;
end
+ // CMD59: CRC_ON_OFF
+ 8'h7b: reply <= 0; // ok
+
endcase
end
end
diff --git a/common/mist/user_io.v b/common/mist/user_io.v
index 3d283918..05e114dd 100644
--- a/common/mist/user_io.v
+++ b/common/mist/user_io.v
@@ -2,7 +2,7 @@
// user_io.v
//
// user_io for the MiST board
-// http://code.google.com/p/mist-board/
+// https://github.com/mist-devel
//
// Copyright (c) 2014 Till Harbaum
//
@@ -57,14 +57,15 @@ module user_io (
input [31:0] sd_lba,
input [SD_IMAGES-1:0] sd_rd,
input [SD_IMAGES-1:0] sd_wr,
- output reg sd_ack,
- output reg sd_ack_conf,
+ output reg sd_ack = 0, // ack any transfer
+ output reg sd_ack_conf = 0,
+ output reg [SD_IMAGES-1:0] sd_ack_x = 0, // ack specific transfer
input sd_conf,
input sd_sdhc,
output reg [7:0] sd_dout, // valid on rising edge of sd_dout_strobe
- output reg sd_dout_strobe,
+ output reg sd_dout_strobe = 0,
input [7:0] sd_din,
- output reg sd_din_strobe,
+ output reg sd_din_strobe = 0,
output reg [8:0] sd_buff_addr,
output reg [SD_IMAGES-1:0] img_mounted, // rising edge if a new image is mounted
@@ -72,11 +73,11 @@ module user_io (
// ps2 keyboard/mouse emulation
output ps2_kbd_clk,
- output reg ps2_kbd_data,
+ output ps2_kbd_data,
input ps2_kbd_clk_i,
input ps2_kbd_data_i,
output ps2_mouse_clk,
- output reg ps2_mouse_data,
+ output ps2_mouse_data,
input ps2_mouse_clk_i,
input ps2_mouse_data_i,
@@ -86,6 +87,9 @@ module user_io (
output reg [7:0] key_code, // key scan code
output reg key_strobe, // key data valid
+ input [7:0] kbd_out_data, // for Archie
+ input kbd_out_strobe,
+
// mouse data
output reg [8:0] mouse_x,
output reg [8:0] mouse_y,
@@ -105,8 +109,10 @@ parameter ROM_DIRECT_UPLOAD=0; // direct upload used for file uploads from the A
parameter SD_IMAGES=2; // number of block-access images (max. 4 supported in current firmware)
parameter PS2BIDIR=0; // bi-directional PS2 interface
parameter FEATURES=0; // requested features from the firmware
+parameter ARCHIE=0;
localparam W = $clog2(SD_IMAGES);
+localparam PS2_FIFO_BITS = 4;
reg [6:0] sbuf;
reg [7:0] cmd;
@@ -123,9 +129,8 @@ assign no_csync = but_sw[6];
assign conf_addr = byte_cnt;
-// this variant of user_io is for 8 bit cores (type == a4) only
// bit 4 indicates ROM direct upload capability
-wire [7:0] core_type = ROM_DIRECT_UPLOAD ? 8'hb4 : 8'ha4;
+wire [7:0] core_type = ARCHIE ? 8'ha6 : ROM_DIRECT_UPLOAD ? 8'hb4 : 8'ha4;
reg [W:0] drive_sel;
always begin
@@ -140,9 +145,6 @@ wire [7:0] sd_cmd = { 4'h6, sd_conf, sd_sdhc, sd_wr[drive_sel], sd_rd[drive_sel]
wire spi_sck = SPI_CLK;
// ---------------- PS2 ---------------------
-// 16 byte fifos to store ps2 bytes
-localparam PS2_FIFO_BITS = 4;
-
reg ps2_clk;
always @(posedge clk_sys) begin
integer cnt;
@@ -154,237 +156,44 @@ always @(posedge clk_sys) begin
end
// keyboard
-reg [7:0] ps2_kbd_fifo [(2**PS2_FIFO_BITS)-1:0];
-reg [PS2_FIFO_BITS-1:0] ps2_kbd_wptr;
-reg [PS2_FIFO_BITS-1:0] ps2_kbd_rptr;
+reg ps2_kbd_tx_strobe;
+wire [7:0] ps2_kbd_rx_byte ;
+wire ps2_kbd_rx_strobe;
+wire ps2_kbd_fifo_ok;
-// ps2 transmitter state machine
-reg [3:0] ps2_kbd_tx_state;
-reg [7:0] ps2_kbd_tx_byte;
-reg ps2_kbd_parity;
-
-// ps2 receiver state machine
-reg [3:0] ps2_kbd_rx_state = 0;
-reg [1:0] ps2_kbd_rx_start = 0;
-reg [7:0] ps2_kbd_rx_byte = 0;
-reg ps2_kbd_rx_strobe = 0;
-
-assign ps2_kbd_clk = ps2_clk || (ps2_kbd_tx_state == 0 && ps2_kbd_rx_state == 0);
-
-// ps2 transmitter/receiver
-// Takes a byte from the FIFO and sends it in a ps2 compliant serial format.
-// Sends a command to the IO controller if bidirectional mode is enabled.
-always@(posedge clk_sys) begin : ps2_kbd
-
- reg ps2_clkD;
- reg ps2_clk_iD, ps2_dat_iD;
- reg ps2_kbd_r_inc;
-
- // send data
- ps2_clkD <= ps2_clk;
- if (~ps2_clkD & ps2_clk) begin
- ps2_kbd_r_inc <= 1'b0;
-
- if(ps2_kbd_r_inc)
- ps2_kbd_rptr <= ps2_kbd_rptr + 1'd1;
-
- // transmitter is idle?
- if(ps2_kbd_tx_state == 0) begin
- ps2_kbd_data <= 1;
- // data in fifo present?
- if(ps2_kbd_wptr != ps2_kbd_rptr && (ps2_kbd_clk_i | !PS2BIDIR)) begin
- // load tx register from fifo
- ps2_kbd_tx_byte <= ps2_kbd_fifo[ps2_kbd_rptr];
- ps2_kbd_r_inc <= 1'b1;
-
- // reset parity
- ps2_kbd_parity <= 1'b1;
-
- // start transmitter
- ps2_kbd_tx_state <= 4'd1;
-
- // put start bit on data line
- ps2_kbd_data <= 1'b0; // start bit is 0
- end
- end else begin
-
- // transmission of 8 data bits
- if((ps2_kbd_tx_state >= 1)&&(ps2_kbd_tx_state < 9)) begin
- ps2_kbd_data <= ps2_kbd_tx_byte[0]; // data bits
- ps2_kbd_tx_byte[6:0] <= ps2_kbd_tx_byte[7:1]; // shift down
- if(ps2_kbd_tx_byte[0])
- ps2_kbd_parity <= !ps2_kbd_parity;
- end
-
- // transmission of parity
- if(ps2_kbd_tx_state == 9)
- ps2_kbd_data <= ps2_kbd_parity;
-
- // transmission of stop bit
- if(ps2_kbd_tx_state == 10)
- ps2_kbd_data <= 1'b1; // stop bit is 1
-
- // advance state machine
- if(ps2_kbd_tx_state < 11)
- ps2_kbd_tx_state <= ps2_kbd_tx_state + 4'd1;
- else
- ps2_kbd_tx_state <= 4'd0;
- end
- end
-
- if (PS2BIDIR) begin
- ps2_clk_iD <= ps2_kbd_clk_i;
- ps2_dat_iD <= ps2_kbd_data_i;
-
- // receive command
- case (ps2_kbd_rx_start)
- 2'd0:
- // first: host pulls down the clock line
- if (ps2_clk_iD & ~ps2_kbd_clk_i) ps2_kbd_rx_start <= 1;
- 2'd1:
- // second: host pulls down the data line, while releasing the clock
- if (ps2_dat_iD && !ps2_kbd_data_i) ps2_kbd_rx_start <= 2'd2;
- // if it releases the clock without pulling down the data line: goto 0
- else if (ps2_kbd_clk_i) ps2_kbd_rx_start <= 0;
- 2'd2:
- if (ps2_clkD && ~ps2_clk) begin
- ps2_kbd_rx_state <= 4'd1;
- ps2_kbd_rx_start <= 0;
- end
- default: ;
- endcase
-
- // host data is valid after the rising edge of the clock
- if(ps2_kbd_rx_state != 0 && ~ps2_clkD && ps2_clk) begin
- ps2_kbd_rx_state <= ps2_kbd_rx_state + 1'd1;
- if (ps2_kbd_rx_state == 9) ;// parity
- else if (ps2_kbd_rx_state == 10) begin
- ps2_kbd_data <= 0; // ack the received byte
- end else if (ps2_kbd_rx_state == 11) begin
- ps2_kbd_rx_state <= 0;
- ps2_kbd_rx_strobe <= ~ps2_kbd_rx_strobe;
- end else begin
- ps2_kbd_rx_byte <= {ps2_kbd_data_i, ps2_kbd_rx_byte[7:1]};
- end
- end
- end
-end
+user_io_ps2 #(.PS2_BIDIR(PS2BIDIR), .PS2_FIFO_BITS(4)) ps2_kbd (
+ .clk_sys ( clk_sys ),
+ .ps2_clk ( ps2_clk ),
+ .ps2_clk_i ( ps2_kbd_clk_i ),
+ .ps2_clk_o ( ps2_kbd_clk ),
+ .ps2_data_i ( ps2_kbd_data_i ),
+ .ps2_data_o ( ps2_kbd_data ),
+ .ps2_tx_strobe ( ps2_kbd_tx_strobe ), // from IO controller
+ .ps2_tx_byte ( spi_byte_in ),
+ .ps2_rx_strobe ( ps2_kbd_rx_strobe ), // to IO controller
+ .ps2_rx_byte ( ps2_kbd_rx_byte ),
+ .ps2_fifo_ready( ps2_kbd_fifo_ok )
+);
// mouse
-reg [7:0] ps2_mouse_fifo [(2**PS2_FIFO_BITS)-1:0];
-reg [PS2_FIFO_BITS-1:0] ps2_mouse_wptr;
-reg [PS2_FIFO_BITS-1:0] ps2_mouse_rptr;
+reg ps2_mouse_tx_strobe;
+wire [7:0] ps2_mouse_rx_byte ;
+wire ps2_mouse_rx_strobe;
+wire ps2_mouse_fifo_ok;
-// ps2 transmitter state machine
-reg [3:0] ps2_mouse_tx_state;
-reg [7:0] ps2_mouse_tx_byte;
-reg ps2_mouse_parity;
-
-// ps2 receiver state machine
-reg [3:0] ps2_mouse_rx_state = 0;
-reg [1:0] ps2_mouse_rx_start = 0;
-reg [7:0] ps2_mouse_rx_byte = 0;
-reg ps2_mouse_rx_strobe = 0;
-
-assign ps2_mouse_clk = ps2_clk || (ps2_mouse_tx_state == 0 && ps2_mouse_rx_state == 0);
-
-// ps2 transmitter/receiver
-// Takes a byte from the FIFO and sends it in a ps2 compliant serial format.
-// Sends a command to the IO controller if bidirectional mode is enabled.
-always@(posedge clk_sys) begin : ps2_mouse
- reg ps2_clkD;
- reg ps2_clk_iD, ps2_dat_iD;
- reg ps2_mouse_r_inc;
-
- ps2_clkD <= ps2_clk;
- if (~ps2_clkD & ps2_clk) begin
- ps2_mouse_r_inc <= 1'b0;
-
- if(ps2_mouse_r_inc)
- ps2_mouse_rptr <= ps2_mouse_rptr + 1'd1;
-
- // transmitter is idle?
- if(ps2_mouse_tx_state == 0) begin
- ps2_mouse_data <= 1;
- // data in fifo present?
- if(ps2_mouse_wptr != ps2_mouse_rptr && (ps2_mouse_clk_i | !PS2BIDIR)) begin
- // load tx register from fifo
- ps2_mouse_tx_byte <= ps2_mouse_fifo[ps2_mouse_rptr];
- ps2_mouse_r_inc <= 1'b1;
-
- // reset parity
- ps2_mouse_parity <= 1'b1;
-
- // start transmitter
- ps2_mouse_tx_state <= 4'd1;
-
- // put start bit on data line
- ps2_mouse_data <= 1'b0; // start bit is 0
- end
- end else begin
-
- // transmission of 8 data bits
- if((ps2_mouse_tx_state >= 1)&&(ps2_mouse_tx_state < 9)) begin
- ps2_mouse_data <= ps2_mouse_tx_byte[0]; // data bits
- ps2_mouse_tx_byte[6:0] <= ps2_mouse_tx_byte[7:1]; // shift down
- if(ps2_mouse_tx_byte[0])
- ps2_mouse_parity <= !ps2_mouse_parity;
- end
-
- // transmission of parity
- if(ps2_mouse_tx_state == 9)
- ps2_mouse_data <= ps2_mouse_parity;
-
- // transmission of stop bit
- if(ps2_mouse_tx_state == 10)
- ps2_mouse_data <= 1'b1; // stop bit is 1
-
- // advance state machine
- if(ps2_mouse_tx_state < 11)
- ps2_mouse_tx_state <= ps2_mouse_tx_state + 4'd1;
- else
- ps2_mouse_tx_state <= 4'd0;
- end
- end
-
- if (PS2BIDIR) begin
-
- ps2_clk_iD <= ps2_mouse_clk_i;
- ps2_dat_iD <= ps2_mouse_data_i;
-
- // receive command
- case (ps2_mouse_rx_start)
- 2'd0:
- // first: host pulls down the clock line
- if (ps2_clk_iD & ~ps2_mouse_clk_i) ps2_mouse_rx_start <= 1;
- 2'd1:
- // second: host pulls down the data line, while releasing the clock
- if (ps2_dat_iD && !ps2_mouse_data_i) ps2_mouse_rx_start <= 2'd2;
- // if it releases the clock without pulling down the data line: goto 0
- else if (ps2_mouse_clk_i) ps2_mouse_rx_start <= 0;
- 2'd2:
- if (ps2_clkD && ~ps2_clk) begin
- ps2_mouse_rx_state <= 4'd1;
- ps2_mouse_rx_start <= 0;
- end
- default: ;
- endcase
-
- // host data is valid after the rising edge of the clock
- if(ps2_mouse_rx_state != 0 && ~ps2_clkD && ps2_clk) begin
- ps2_mouse_rx_state <= ps2_mouse_rx_state + 1'd1;
- if (ps2_mouse_rx_state == 9) ;// parity
- else if (ps2_mouse_rx_state == 10) begin
- ps2_mouse_data <= 0; // ack the received byte
- end else if (ps2_mouse_rx_state == 11) begin
- ps2_mouse_rx_state <= 0;
- ps2_mouse_rx_strobe <= ~ps2_mouse_rx_strobe;
- end else begin
- ps2_mouse_rx_byte <= {ps2_mouse_data_i, ps2_mouse_rx_byte[7:1]};
- end
- end
- end
-end
+user_io_ps2 #(.PS2_BIDIR(PS2BIDIR), .PS2_FIFO_BITS(3)) ps2_mouse (
+ .clk_sys ( clk_sys ),
+ .ps2_clk ( ps2_clk ),
+ .ps2_clk_i ( ps2_mouse_clk_i ),
+ .ps2_clk_o ( ps2_mouse_clk ),
+ .ps2_data_i ( ps2_mouse_data_i ),
+ .ps2_data_o ( ps2_mouse_data ),
+ .ps2_tx_strobe ( ps2_mouse_tx_strobe ), // from IO controller
+ .ps2_tx_byte ( spi_byte_in ),
+ .ps2_rx_strobe ( ps2_mouse_rx_strobe ), // to IO controller
+ .ps2_rx_byte ( ps2_mouse_rx_byte ),
+ .ps2_fifo_ready( ps2_mouse_fifo_ok )
+);
// fifo to receive serial data from core to be forwarded to io controller
@@ -446,6 +255,23 @@ always@(negedge spi_sck or posedge SPI_SS_IO) begin : spi_byteout
end
end
+generate if (ARCHIE) begin
+reg [7:0] kbd_out_status;
+reg [7:0] kbd_out_data_r;
+reg kbd_out_data_available = 0;
+
+always@(negedge spi_sck or posedge SPI_SS_IO) begin : archie_kbd_out
+ if(SPI_SS_IO == 1) begin
+ kbd_out_data_r <= 0;
+ kbd_out_status <= 0;
+ end else begin
+ kbd_out_status <= { 4'ha, 3'b000, kbd_out_data_available };
+ kbd_out_data_r <= kbd_out_data;
+ end
+end
+end
+endgenerate
+
always@(posedge spi_sck or posedge SPI_SS_IO) begin : spi_transmitter
reg [31:0] sd_lba_r;
reg [W:0] drive_sel_r;
@@ -461,6 +287,11 @@ always@(posedge spi_sck or posedge SPI_SS_IO) begin : spi_transmitter
spi_byte_out <= 0;
case({(!byte_cnt) ? {sbuf, SPI_MOSI} : cmd})
+ 8'h04: if (ARCHIE) begin
+ if(byte_cnt == 0) spi_byte_out <= kbd_out_status;
+ else spi_byte_out <= kbd_out_data_r;
+ end
+
// PS2 keyboard command
8'h0e: if (byte_cnt == 0) begin
ps2_kbd_rx_strobeD <= ps2_kbd_rx_strobe;
@@ -539,12 +370,14 @@ always @(posedge clk_sys) begin : cmd_block
reg spi_receiver_strobeD;
reg spi_transfer_endD;
reg [7:0] acmd;
- reg [7:0] abyte_cnt; // counts bytes
+ reg [3:0] abyte_cnt; // counts bytes
reg [7:0] mouse_flags_r;
reg [7:0] mouse_x_r;
reg [7:0] mouse_y_r;
+ reg mouse_fifo_ok;
+ reg kbd_fifo_ok;
reg key_pressed_r;
reg key_extended_r;
@@ -556,17 +389,46 @@ always @(posedge clk_sys) begin : cmd_block
key_strobe <= 0;
mouse_strobe <= 0;
+ ps2_kbd_tx_strobe <= 0;
+ ps2_mouse_tx_strobe <= 0;
+
+ if(ARCHIE) begin
+ if (kbd_out_strobe) kbd_out_data_available <= 1;
+ key_pressed <= 0;
+ key_extended <= 0;
+ mouse_x <= 0;
+ mouse_y <= 0;
+ mouse_z <= 0;
+ mouse_flags <= 0;
+ mouse_idx <= 0;
+ end
if (spi_transfer_end) begin
- abyte_cnt <= 8'd0;
+ abyte_cnt <= 0;
+ mouse_fifo_ok <= 0;
+ kbd_fifo_ok <= 0;
end else if (spi_receiver_strobeD ^ spi_receiver_strobe) begin
if(~&abyte_cnt)
- abyte_cnt <= abyte_cnt + 8'd1;
+ abyte_cnt <= abyte_cnt + 1'd1;
if(abyte_cnt == 0) begin
acmd <= spi_byte_in;
+ if (spi_byte_in == 8'h70 || spi_byte_in == 8'h71)
+ // accept the incoming mouse data only if there's place for the full packet
+ mouse_fifo_ok <= ps2_mouse_fifo_ok;
+ if (spi_byte_in == 8'h05)
+ // accept the incoming keyboard data only if there's place for the full packet
+ kbd_fifo_ok <= ps2_kbd_fifo_ok;
end else begin
+ if (ARCHIE) begin
+ if(acmd == 8'h04) kbd_out_data_available <= 0;
+ if(acmd == 8'h05) begin
+ key_strobe <= 1;
+ key_code <= spi_byte_in;
+ end
+ end
+
case(acmd)
// buttons and switches
8'h01: but_sw <= spi_byte_in;
@@ -575,11 +437,10 @@ always @(posedge clk_sys) begin : cmd_block
8'h62: if (abyte_cnt < 5) joystick_2[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
8'h63: if (abyte_cnt < 5) joystick_3[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
8'h64: if (abyte_cnt < 5) joystick_4[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
- 8'h70,8'h71: begin
+ 8'h70,8'h71: if (!ARCHIE) begin
// store incoming ps2 mouse bytes
- if (abyte_cnt < 4) begin
- ps2_mouse_fifo[ps2_mouse_wptr] <= spi_byte_in;
- ps2_mouse_wptr <= ps2_mouse_wptr + 1'd1;
+ if (abyte_cnt < 4 && mouse_fifo_ok) begin
+ ps2_mouse_tx_strobe <= 1;
end
if (abyte_cnt == 1) mouse_flags_r <= spi_byte_in;
@@ -595,10 +456,9 @@ always @(posedge clk_sys) begin : cmd_block
mouse_strobe <= 1;
end
end
- 8'h05: begin
- // store incoming ps2 keyboard bytes
- ps2_kbd_fifo[ps2_kbd_wptr] <= spi_byte_in;
- ps2_kbd_wptr <= ps2_kbd_wptr + 1'd1;
+ 8'h05: if (!ARCHIE) begin
+ // store incoming ps2 keyboard bytes
+ if (kbd_fifo_ok) ps2_kbd_tx_strobe <= 1;
if (abyte_cnt == 1) begin
key_extended_r <= 0;
key_pressed_r <= 1;
@@ -698,6 +558,7 @@ always @(posedge clk_sd) begin : sd_block
sd_ack <= 1'b0;
sd_ack_conf <= 1'b0;
sd_buff_addr <= 0;
+ if (acmd == 8'h17 || acmd == 8'h18) sd_ack_x <= 0;
end else if (spi_receiver_strobeD ^ spi_receiver_strobe) begin
if(~&abyte_cnt)
@@ -740,9 +601,160 @@ always @(posedge clk_sd) begin : sd_block
// send image info
8'h1d: if(abyte_cnt<9) img_size[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
+ // data transfer ack
+ 8'h23: sd_ack_x <= 1'b1 << spi_byte_in;
+
endcase
end
end
end
endmodule
+
+module user_io_ps2 (
+ input clk_sys,
+ input ps2_clk,
+ input ps2_clk_i,
+ output ps2_clk_o,
+ input ps2_data_i,
+ output reg ps2_data_o = 1,
+ input ps2_tx_strobe, // from IO controller
+ input [7:0] ps2_tx_byte,
+ output reg ps2_rx_strobe = 0, // to IO controller
+ output reg [7:0] ps2_rx_byte = 0,
+ output ps2_fifo_ready
+);
+
+parameter PS2_FIFO_BITS = 4;
+parameter PS2_BIDIR = 0;
+
+reg [7:0] ps2_fifo [(2**PS2_FIFO_BITS)-1:0];
+reg [PS2_FIFO_BITS-1:0] ps2_wptr;
+reg [PS2_FIFO_BITS-1:0] ps2_rptr;
+wire [PS2_FIFO_BITS:0] ps2_used = ps2_wptr >= ps2_rptr ?
+ ps2_wptr - ps2_rptr :
+ ps2_wptr - ps2_rptr + (2'd2**PS2_FIFO_BITS);
+wire [PS2_FIFO_BITS:0] ps2_free = (2'd2**PS2_FIFO_BITS) - ps2_used;
+
+assign ps2_fifo_ready = ps2_free[PS2_FIFO_BITS:2] != 0; // ps2_free > 3
+
+// ps2 transmitter state machine
+reg [3:0] ps2_tx_state;
+reg [7:0] ps2_tx_shift_reg;
+reg ps2_parity;
+
+// ps2 receiver state machine
+reg [3:0] ps2_rx_state = 0;
+reg [1:0] ps2_rx_start = 0;
+
+assign ps2_clk_o = ps2_clk || (ps2_tx_state == 0 && ps2_rx_state == 0);
+
+always@(posedge clk_sys) begin : ps2_fifo_wr
+ if (ps2_tx_strobe) begin
+ ps2_fifo[ps2_wptr] <= ps2_tx_byte;
+ ps2_wptr <= ps2_wptr + 1'd1;
+ end
+end
+
+// ps2 transmitter/receiver
+// Takes a byte from the FIFO and sends it in a ps2 compliant serial format.
+// Sends a command to the IO controller if bidirectional mode is enabled.
+always@(posedge clk_sys) begin : ps2_txrx
+ reg ps2_clkD;
+ reg ps2_clk_iD, ps2_dat_iD;
+ reg ps2_r_inc;
+
+ ps2_clkD <= ps2_clk;
+ if (~ps2_clkD & ps2_clk) begin
+ ps2_r_inc <= 1'b0;
+
+ if(ps2_r_inc)
+ ps2_rptr <= ps2_rptr + 1'd1;
+
+ // transmitter is idle?
+ if(ps2_tx_state == 0) begin
+ ps2_data_o <= 1;
+ // data in fifo present?
+ if(ps2_wptr != ps2_rptr && (ps2_clk_i | !PS2_BIDIR)) begin
+ // load tx register from fifo
+ ps2_tx_shift_reg <= ps2_fifo[ps2_rptr];
+ ps2_r_inc <= 1'b1;
+
+ // reset parity
+ ps2_parity <= 1'b1;
+
+ // start transmitter
+ ps2_tx_state <= 4'd1;
+
+ // put start bit on data line
+ ps2_data_o <= 1'b0; // start bit is 0
+ end
+ end else begin
+
+ // transmission of 8 data bits
+ if((ps2_tx_state >= 1)&&(ps2_tx_state < 9)) begin
+ ps2_data_o <= ps2_tx_shift_reg[0]; // data bits
+ ps2_tx_shift_reg[6:0] <= ps2_tx_shift_reg[7:1]; // shift down
+ if(ps2_tx_shift_reg[0])
+ ps2_parity <= !ps2_parity;
+ end
+
+ // transmission of parity
+ if(ps2_tx_state == 9)
+ ps2_data_o <= ps2_parity;
+
+ // transmission of stop bit
+ if(ps2_tx_state == 10)
+ ps2_data_o <= 1'b1; // stop bit is 1
+
+ // advance state machine
+ if(ps2_tx_state == 11)
+ ps2_tx_state <= 4'd0;
+ else
+ ps2_tx_state <= ps2_tx_state + 4'd1;
+ end
+ end
+
+ if (PS2_BIDIR) begin
+
+ ps2_clk_iD <= ps2_clk_i;
+ ps2_dat_iD <= ps2_data_i;
+
+ // receive command
+ case (ps2_rx_start)
+ 2'd0:
+ // first: host pulls down the clock line
+ if (ps2_clk_iD & ~ps2_clk_i) ps2_rx_start <= 1;
+ 2'd1:
+ // second: host pulls down the data line, while releasing the clock
+ if (ps2_dat_iD && !ps2_data_i) ps2_rx_start <= 2'd2;
+ // if it releases the clock without pulling down the data line: goto 0
+ else if (ps2_clk_i) ps2_rx_start <= 0;
+ 2'd2:
+ if (ps2_clkD && ~ps2_clk) begin
+ ps2_rx_state <= 4'd1;
+ ps2_rx_start <= 0;
+ end
+ default: ;
+ endcase
+
+ // host data is valid after the rising edge of the clock
+ if(ps2_rx_state != 0 && ~ps2_clkD && ps2_clk) begin
+ ps2_rx_state <= ps2_rx_state + 1'd1;
+ if (ps2_rx_state == 9) ;// parity
+ else if (ps2_rx_state == 10) begin
+ ps2_data_o <= 0; // ack the received byte
+ end else if (ps2_rx_state == 11) begin
+ ps2_rx_state <= 0;
+ ps2_rx_strobe <= ~ps2_rx_strobe;
+ end else begin
+ ps2_rx_byte <= {ps2_data_i, ps2_rx_byte[7:1]};
+ end
+ end
+ end else begin
+ ps2_rx_byte <= 0;
+ ps2_rx_strobe <= 0;
+ end
+end
+
+endmodule