From 4e0548a1387997e9bc49c0dbd238c5c801410709 Mon Sep 17 00:00:00 2001 From: gehstock Date: Sun, 3 Jun 2018 07:59:37 +0200 Subject: [PATCH] New Code --- .../Custom Hardware/UltraTank_MiST/clean.bat | 37 + .../UltraTank_MiST/rtl/EngineSound.vhd | 165 +++ .../UltraTank_MiST/rtl/T65/T65.vhd | 551 +++++++++ .../UltraTank_MiST/rtl/T65/T65_ALU.vhd | 260 ++++ .../UltraTank_MiST/rtl/T65/T65_MCode.vhd | 1050 +++++++++++++++++ .../UltraTank_MiST/rtl/T65/T65_Pack.vhd | 117 ++ .../UltraTank_MiST/rtl/build_id.sv | 2 + .../UltraTank_MiST/rtl/build_id.tcl | 35 + .../UltraTank_MiST/rtl/collision.vhd | 105 ++ .../UltraTank_MiST/rtl/cpu_mem.vhd | 460 ++++++++ .../Custom Hardware/UltraTank_MiST/rtl/dac.sv | 33 + .../UltraTank_MiST/rtl/hq2x.sv | 454 +++++++ .../UltraTank_MiST/rtl/inputs.vhd | 140 +++ .../UltraTank_MiST/rtl/keyboard.sv | 84 ++ .../UltraTank_MiST/rtl/mist_io.sv | 491 ++++++++ .../UltraTank_MiST/rtl/motion.vhd | 330 ++++++ .../Custom Hardware/UltraTank_MiST/rtl/osd.sv | 179 +++ .../UltraTank_MiST/rtl/playfield.vhd | 265 +++++ .../Custom Hardware/UltraTank_MiST/rtl/pll.v | 337 ++++++ .../UltraTank_MiST/rtl/roms/030180n1.hex | 129 ++ .../UltraTank_MiST/rtl/roms/030181k1.hex | 129 ++ .../UltraTank_MiST/rtl/roms/030182m1.hex | 129 ++ .../UltraTank_MiST/rtl/roms/030183l1.hex | 129 ++ .../UltraTank_MiST/rtl/roms/30024-01p8.hex | 33 + .../UltraTank_MiST/rtl/roms/30172-01j6.hex | 33 + .../UltraTank_MiST/rtl/roms/30173-01h6.hex | 33 + .../UltraTank_MiST/rtl/roms/30174-01n6.hex | 65 + .../UltraTank_MiST/rtl/roms/30175-01m6.hex | 65 + .../UltraTank_MiST/rtl/roms/30176-01l6.hex | 65 + .../UltraTank_MiST/rtl/roms/30177-01k6.hex | 65 + .../UltraTank_MiST/rtl/roms/30218-01j10.hex | 3 + .../UltraTank_MiST/rtl/scandoubler.sv | 195 +++ .../UltraTank_MiST/rtl/screech.vhd | 73 ++ .../UltraTank_MiST/rtl/sound.vhd | 244 ++++ .../UltraTank_MiST/rtl/spram.vhd | 90 ++ .../UltraTank_MiST/rtl/sprom.vhd | 82 ++ .../UltraTank_MiST/rtl/sync.vhd | 197 ++++ .../UltraTank_MiST/rtl/ultra_tank.vhd | 288 +++++ .../UltraTank_MiST/rtl/ultratank_mist.sv | 165 +++ .../UltraTank_MiST/rtl/video_mixer.sv | 242 ++++ .../UltraTank_MiST/snapshot/ultratank.rbf | Bin 0 -> 246046 bytes .../UltraTank_MiST/ultratank.qpf | 30 + .../UltraTank_MiST/ultratank.qsf | 174 +++ 43 files changed, 7753 insertions(+) create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/clean.bat create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/EngineSound.vhd create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/T65/T65.vhd create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/T65/T65_ALU.vhd create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/T65/T65_MCode.vhd create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/T65/T65_Pack.vhd create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/build_id.sv create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/build_id.tcl create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/collision.vhd create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/cpu_mem.vhd create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/dac.sv create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/hq2x.sv create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/inputs.vhd create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/keyboard.sv create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/mist_io.sv create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/motion.vhd create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/osd.sv create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/playfield.vhd create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/pll.v create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/030180n1.hex create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/030181k1.hex create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/030182m1.hex create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/030183l1.hex create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30024-01p8.hex create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30172-01j6.hex create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30173-01h6.hex create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30174-01n6.hex create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30175-01m6.hex create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30176-01l6.hex create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30177-01k6.hex create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30218-01j10.hex create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/scandoubler.sv create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/screech.vhd create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/sound.vhd create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/spram.vhd create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/sprom.vhd create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/sync.vhd create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/ultra_tank.vhd create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/ultratank_mist.sv create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/video_mixer.sv create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/snapshot/ultratank.rbf create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/ultratank.qpf create mode 100644 Arcade_MiST/Custom Hardware/UltraTank_MiST/ultratank.qsf diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/clean.bat b/Arcade_MiST/Custom Hardware/UltraTank_MiST/clean.bat new file mode 100644 index 00000000..b3b7c3b5 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/clean.bat @@ -0,0 +1,37 @@ +@echo off +del /s *.bak +del /s *.orig +del /s *.rej +del /s *~ +rmdir /s /q db +rmdir /s /q incremental_db +rmdir /s /q output_files +rmdir /s /q simulation +rmdir /s /q greybox_tmp +rmdir /s /q hc_output +rmdir /s /q .qsys_edit +rmdir /s /q hps_isw_handoff +rmdir /s /q sys\.qsys_edit +rmdir /s /q sys\vip +cd sys +for /d %%i in (*_sim) do rmdir /s /q "%%~nxi" +cd .. +for /d %%i in (*_sim) do rmdir /s /q "%%~nxi" +del build_id.v +del c5_pin_model_dump.txt +del PLLJ_PLLSPE_INFO.txt +del /s *.qws +del /s *.ppf +del /s *.ddb +del /s *.csv +del /s *.cmp +del /s *.sip +del /s *.spd +del /s *.bsf +del /s *.f +del /s *.sopcinfo +del /s *.xml +del /s new_rtl_netlist +del /s old_rtl_netlist + +pause diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/EngineSound.vhd b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/EngineSound.vhd new file mode 100644 index 00000000..51056dcc --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/EngineSound.vhd @@ -0,0 +1,165 @@ +-- Motor sound generator for Kee Games Ultra Tank +-- This was originally created for Sprint 2 - Identical circuit +-- Similar circuits are used in a number of other games +-- (c) 2017 James Sweet +-- +-- Original circuit used a 555 configured as an astable oscillator with the frequency controlled by +-- a four bit binary value. The output of this oscillator drives a counter configured to produce an +-- irregular thumping simulating the sound of an engine. +-- +-- This 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 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. + +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use IEEE.STD_LOGIC_ARITH.all; +use IEEE.STD_LOGIC_UNSIGNED.all; + +entity EngineSound is +generic( + constant Freq_tune : integer := 50 -- Value from 0-100 used to tune the overall engine sound frequency + ); +port( + Clk_6 : in std_logic; + Reset : in std_logic; + Ena_3k : in std_logic; + EngineData : in std_logic_vector(3 downto 0); + Motor : out std_logic_vector(5 downto 0) + ); +end EngineSound; + +architecture rtl of EngineSound is + +signal RPM_val : integer range 1 to 350; +signal Ramp_term_unfilt : integer range 1 to 80000; +signal Ramp_Count : integer range 0 to 80000; +signal Ramp_term : integer range 1 to 80000; +signal Freq_mod : integer range 0 to 400; +signal Motor_Clk : std_logic; + +signal Counter_A : std_logic; +signal Counter_B : unsigned(2 downto 0); +signal Counter_A_clk : std_logic; + +signal Motor_prefilter : unsigned(1 downto 0); +signal Motor_filter_t1 : unsigned(3 downto 0); +signal Motor_filter_t2 : unsigned(3 downto 0); +signal Motor_filter_t3 : unsigned(3 downto 0); +signal Motor_filtered : unsigned(5 downto 0); + + +begin + +-- The frequency of the oscillator is set by a 4 bit binary value controlled by the game CPU +-- in the real hardware this is a 555 coupled to a 4 bit resistor DAC used to pull the frequency. +-- The output of this DAC has a capacitor to smooth out the frequency variation. +-- The constants assigned to RPM_val can be tweaked to adjust the frequency curve + +Speed_select: process(Clk_6) +begin + if rising_edge(Clk_6) then + case EngineData is + when "0000" => RPM_val <= 280; + when "0001" => RPM_val <= 245; + when "0010" => RPM_val <= 230; + when "0011" => RPM_val <= 205; + when "0100" => RPM_val <= 190; + when "0101" => RPM_val <= 175; + when "0110" => RPM_val <= 160; + when "0111" => RPM_val <= 145; + when "1000" => RPM_val <= 130; + when "1001" => RPM_val <= 115; + when "1010" => RPM_val <= 100; + when "1011" => RPM_val <= 85; + when "1100" => RPM_val <= 70; + when "1101" => RPM_val <= 55; + when "1110" => RPM_val <= 40; + when "1111" => RPM_val <= 25; + end case; + end if; +end process; + + +-- There is a RC filter between the frequency control DAC and the 555 to smooth out the transitions between the +-- 16 possible states. We can simulate a reasonable approximation of that behavior using a linear slope which is +-- not truly accurate but should be close enough. +RC_filt: process(clk_6, ena_3k, ramp_term_unfilt) +begin + if rising_edge(clk_6) then + if ena_3k = '1' then + if ramp_term_unfilt > ramp_term then + ramp_term <= ramp_term + 10; + elsif ramp_term_unfilt = ramp_term then + ramp_term <= ramp_term; + else + ramp_term <= ramp_term - 8; + end if; + end if; + end if; +end process; + + +-- Ramp_term terminates the ramp count, the higher this value, the longer the ramp will count up and the lower +-- the frequency. RPM_val is multiplied by a constant which can be adjusted by changing the value of freq_tune +-- to simulate the function of the frequency adjustment pot in the original hardware. +ramp_term_unfilt <= ((200 - freq_tune) * RPM_val); + +-- Variable frequency oscillator roughly approximating the function of a 555 astable oscillator +Ramp_osc: process(clk_6) +begin + if rising_edge(clk_6) then + motor_clk <= '1'; + ramp_count <= ramp_count + 1; + if ramp_count > ramp_term then + ramp_count <= 0; + motor_clk <= '0'; + end if; + end if; +end process; + + +-- 7492 counter with XOR on two of the outputs creates lumpy engine sound from smooth pulse train +-- 7492 has two sections, one div-by-2 and one div-by-6. +Engine_counter: process(motor_clk, counter_A_clk, counter_B, reset) +begin + if reset = '1' then + Counter_B <= (others => '0'); + elsif rising_edge(motor_clk) then + Counter_B <= Counter_B + '1'; + end if; + Counter_A_clk <= Counter_B(0) xor Counter_B(2); + if reset = '1' then + Counter_A <= '0'; + elsif rising_edge(counter_A_clk) then + Counter_A <= (not Counter_A); + end if; +end process; +motor_prefilter <= ('0' & Counter_B(2)) + ('0' & Counter_B(1)) + ('0' & Counter_A); + +-- Very simple low pass filter, borrowed from MikeJ's Asteroids code +Engine_filter: process(clk_6) +begin + if rising_edge(clk_6) then + if (ena_3k = '1') then + motor_filter_t1 <= ("00" & motor_prefilter) + ("00" & motor_prefilter); + motor_filter_t2 <= motor_filter_t1; + motor_filter_t3 <= motor_filter_t2; + end if; + motor_filtered <= ("00" & motor_filter_t1) + + ('0' & motor_filter_t2 & '0') + + ("00" & motor_filter_t3); + end if; +end process; + +motor <= std_logic_vector(motor_filtered); + +end rtl; \ No newline at end of file diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/T65/T65.vhd b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/T65/T65.vhd new file mode 100644 index 00000000..161debea --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/T65/T65.vhd @@ -0,0 +1,551 @@ +-- **** +-- T65(b) core. In an effort to merge and maintain bug fixes .... +-- +-- +-- Ver 301 more merging +-- Ver 300 Bugfixes by ehenciak added, started tidyup *bust* +-- MikeJ March 2005 +-- Latest version from www.fpgaarcade.com (original www.opencores.org) +-- +-- **** +-- +-- 65xx compatible microprocessor core +-- +-- Version : 0246 +-- +-- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- The latest version of this file can be found at: +-- http://www.opencores.org/cvsweb.shtml/t65/ +-- +-- Limitations : +-- +-- 65C02 and 65C816 modes are incomplete +-- Undocumented instructions are not supported +-- Some interface signals behaves incorrect +-- +-- File history : +-- +-- 0246 : First release +-- + +library IEEE; + use IEEE.std_logic_1164.all; + use IEEE.numeric_std.all; + use work.T65_Pack.all; + +-- ehenciak 2-23-2005 : Added the enable signal so that one doesn't have to use +-- the ready signal to limit the CPU. +entity T65 is + port( + Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816 + Res_n : in std_logic; + Enable : in std_logic; + Clk : in std_logic; + Rdy : in std_logic; + Abort_n : in std_logic; + IRQ_n : in std_logic; + NMI_n : in std_logic; + SO_n : in std_logic; + R_W_n : out std_logic; + Sync : out std_logic; + EF : out std_logic; + MF : out std_logic; + XF : out std_logic; + ML_n : out std_logic; + VP_n : out std_logic; + VDA : out std_logic; + VPA : out std_logic; + A : out std_logic_vector(23 downto 0); + DI : in std_logic_vector(7 downto 0); + DO : out std_logic_vector(7 downto 0) + ); +end T65; + +architecture rtl of T65 is + + -- Registers + signal ABC, X, Y, D : std_logic_vector(15 downto 0); + signal P, AD, DL : std_logic_vector(7 downto 0) := x"00"; + signal BAH : std_logic_vector(7 downto 0); + signal BAL : std_logic_vector(8 downto 0); + signal PBR : std_logic_vector(7 downto 0); + signal DBR : std_logic_vector(7 downto 0); + signal PC : unsigned(15 downto 0); + signal S : unsigned(15 downto 0); + signal EF_i : std_logic; + signal MF_i : std_logic; + signal XF_i : std_logic; + + signal IR : std_logic_vector(7 downto 0); + signal MCycle : std_logic_vector(2 downto 0); + + signal Mode_r : std_logic_vector(1 downto 0); + signal ALU_Op_r : std_logic_vector(3 downto 0); + signal Write_Data_r : std_logic_vector(2 downto 0); + signal Set_Addr_To_r : std_logic_vector(1 downto 0); + signal PCAdder : unsigned(8 downto 0); + + signal RstCycle : std_logic; + signal IRQCycle : std_logic; + signal NMICycle : std_logic; + + signal B_o : std_logic; + signal SO_n_o : std_logic; + signal IRQ_n_o : std_logic; + signal NMI_n_o : std_logic; + signal NMIAct : std_logic; + + signal Break : std_logic; + + -- ALU signals + signal BusA : std_logic_vector(7 downto 0); + signal BusA_r : std_logic_vector(7 downto 0); + signal BusB : std_logic_vector(7 downto 0); + signal ALU_Q : std_logic_vector(7 downto 0); + signal P_Out : std_logic_vector(7 downto 0); + + -- Micro code outputs + signal LCycle : std_logic_vector(2 downto 0); + signal ALU_Op : std_logic_vector(3 downto 0); + signal Set_BusA_To : std_logic_vector(2 downto 0); + signal Set_Addr_To : std_logic_vector(1 downto 0); + signal Write_Data : std_logic_vector(2 downto 0); + signal Jump : std_logic_vector(1 downto 0); + signal BAAdd : std_logic_vector(1 downto 0); + signal BreakAtNA : std_logic; + signal ADAdd : std_logic; + signal AddY : std_logic; + signal PCAdd : std_logic; + signal Inc_S : std_logic; + signal Dec_S : std_logic; + signal LDA : std_logic; + signal LDP : std_logic; + signal LDX : std_logic; + signal LDY : std_logic; + signal LDS : std_logic; + signal LDDI : std_logic; + signal LDALU : std_logic; + signal LDAD : std_logic; + signal LDBAL : std_logic; + signal LDBAH : std_logic; + signal SaveP : std_logic; + signal Write : std_logic; + + signal really_rdy : std_logic; + signal R_W_n_i : std_logic; + +begin + -- ehenciak : gate Rdy with read/write to make an "OK, it's + -- really OK to stop the processor now if Rdy is + -- deasserted" signal + really_rdy <= Rdy or not(R_W_n_i); + + -- ehenciak : Drive R_W_n_i off chip. + R_W_n <= R_W_n_i; + + Sync <= '1' when MCycle = "000" else '0'; + EF <= EF_i; + MF <= MF_i; + XF <= XF_i; + ML_n <= '0' when IR(7 downto 6) /= "10" and IR(2 downto 1) = "11" and MCycle(2 downto 1) /= "00" else '1'; + VP_n <= '0' when IRQCycle = '1' and (MCycle = "101" or MCycle = "110") else '1'; + VDA <= '1' when Set_Addr_To_r /= "000" else '0'; -- Incorrect !!!!!!!!!!!! + VPA <= '1' when Jump(1) = '0' else '0'; -- Incorrect !!!!!!!!!!!! + + mcode : T65_MCode + port map( + Mode => Mode_r, + IR => IR, + MCycle => MCycle, + P => P, + LCycle => LCycle, + ALU_Op => ALU_Op, + Set_BusA_To => Set_BusA_To, + Set_Addr_To => Set_Addr_To, + Write_Data => Write_Data, + Jump => Jump, + BAAdd => BAAdd, + BreakAtNA => BreakAtNA, + ADAdd => ADAdd, + AddY => AddY, + PCAdd => PCAdd, + Inc_S => Inc_S, + Dec_S => Dec_S, + LDA => LDA, + LDP => LDP, + LDX => LDX, + LDY => LDY, + LDS => LDS, + LDDI => LDDI, + LDALU => LDALU, + LDAD => LDAD, + LDBAL => LDBAL, + LDBAH => LDBAH, + SaveP => SaveP, + Write => Write + ); + + alu : T65_ALU + port map( + Mode => Mode_r, + Op => ALU_Op_r, + BusA => BusA_r, + BusB => BusB, + P_In => P, + P_Out => P_Out, + Q => ALU_Q + ); + + process (Res_n, Clk) + begin + if Res_n = '0' then + PC <= (others => '0'); -- Program Counter + IR <= "00000000"; + S <= (others => '0'); -- Dummy !!!!!!!!!!!!!!!!!!!!! + D <= (others => '0'); + PBR <= (others => '0'); + DBR <= (others => '0'); + + Mode_r <= (others => '0'); + ALU_Op_r <= "1100"; + Write_Data_r <= "000"; + Set_Addr_To_r <= "00"; + + R_W_n_i <= '1'; + EF_i <= '1'; + MF_i <= '1'; + XF_i <= '1'; + + elsif Clk'event and Clk = '1' then + if (Enable = '1') then + if (really_rdy = '1') then + R_W_n_i <= not Write or RstCycle; + + D <= (others => '1'); -- Dummy + PBR <= (others => '1'); -- Dummy + DBR <= (others => '1'); -- Dummy + EF_i <= '0'; -- Dummy + MF_i <= '0'; -- Dummy + XF_i <= '0'; -- Dummy + + if MCycle = "000" then + Mode_r <= Mode; + + if IRQCycle = '0' and NMICycle = '0' then + PC <= PC + 1; + end if; + + if IRQCycle = '1' or NMICycle = '1' then + IR <= "00000000"; + else + IR <= DI; + end if; + end if; + + ALU_Op_r <= ALU_Op; + Write_Data_r <= Write_Data; + if Break = '1' then + Set_Addr_To_r <= "00"; + else + Set_Addr_To_r <= Set_Addr_To; + end if; + + if Inc_S = '1' then + S <= S + 1; + end if; + if Dec_S = '1' and RstCycle = '0' then + S <= S - 1; + end if; + if LDS = '1' then + S(7 downto 0) <= unsigned(ALU_Q); + end if; + + if IR = "00000000" and MCycle = "001" and IRQCycle = '0' and NMICycle = '0' then + PC <= PC + 1; + end if; + -- + -- jump control logic + -- + case Jump is + when "01" => + PC <= PC + 1; + + when "10" => + PC <= unsigned(DI & DL); + + when "11" => + if PCAdder(8) = '1' then + if DL(7) = '0' then + PC(15 downto 8) <= PC(15 downto 8) + 1; + else + PC(15 downto 8) <= PC(15 downto 8) - 1; + end if; + end if; + PC(7 downto 0) <= PCAdder(7 downto 0); + + when others => null; + end case; + end if; + end if; + end if; + end process; + + PCAdder <= resize(PC(7 downto 0),9) + resize(unsigned(DL(7) & DL),9) when PCAdd = '1' + else "0" & PC(7 downto 0); + + process (Clk) + begin + if Clk'event and Clk = '1' then + if (Enable = '1') then + if (really_rdy = '1') then + if MCycle = "000" then + if LDA = '1' then + ABC(7 downto 0) <= ALU_Q; + end if; + if LDX = '1' then + X(7 downto 0) <= ALU_Q; + end if; + if LDY = '1' then + Y(7 downto 0) <= ALU_Q; + end if; + if (LDA or LDX or LDY) = '1' then + P <= P_Out; + end if; + end if; + if SaveP = '1' then + P <= P_Out; + end if; + if LDP = '1' then + P <= ALU_Q; + end if; + if IR(4 downto 0) = "11000" then + case IR(7 downto 5) is + when "000" => + P(Flag_C) <= '0'; + when "001" => + P(Flag_C) <= '1'; + when "010" => + P(Flag_I) <= '0'; + when "011" => + P(Flag_I) <= '1'; + when "101" => + P(Flag_V) <= '0'; + when "110" => + P(Flag_D) <= '0'; + when "111" => + P(Flag_D) <= '1'; + when others => + end case; + end if; + if IR = "00000000" and MCycle = "011" and RstCycle = '0' and NMICycle = '0' and IRQCycle = '0' then + P(Flag_B) <= '1'; + end if; + if IR = "00000000" and MCycle = "100" and RstCycle = '0' and (NMICycle = '1' or IRQCycle = '1') then + P(Flag_I) <= '1'; + P(Flag_B) <= B_o; + end if; + if SO_n_o = '1' and SO_n = '0' then + P(Flag_V) <= '1'; + end if; + if RstCycle = '1' and Mode_r /= "00" then + P(Flag_1) <= '1'; + P(Flag_D) <= '0'; + P(Flag_I) <= '1'; + end if; + P(Flag_1) <= '1'; + + B_o <= P(Flag_B); + SO_n_o <= SO_n; + IRQ_n_o <= IRQ_n; + NMI_n_o <= NMI_n; + end if; + end if; + end if; + end process; + +--------------------------------------------------------------------------- +-- +-- Buses +-- +--------------------------------------------------------------------------- + + process (Res_n, Clk) + begin + if Res_n = '0' then + BusA_r <= (others => '0'); + BusB <= (others => '0'); + AD <= (others => '0'); + BAL <= (others => '0'); + BAH <= (others => '0'); + DL <= (others => '0'); + elsif Clk'event and Clk = '1' then + if (Enable = '1') then + if (Rdy = '1') then + BusA_r <= BusA; + BusB <= DI; + + case BAAdd is + when "01" => + -- BA Inc + AD <= std_logic_vector(unsigned(AD) + 1); + BAL <= std_logic_vector(unsigned(BAL) + 1); + when "10" => + -- BA Add + BAL <= std_logic_vector(resize(unsigned(BAL(7 downto 0)),9) + resize(unsigned(BusA),9)); + when "11" => + -- BA Adj + if BAL(8) = '1' then + BAH <= std_logic_vector(unsigned(BAH) + 1); + end if; + when others => + end case; + + -- ehenciak : modified to use Y register as well (bugfix) + if ADAdd = '1' then + if (AddY = '1') then + AD <= std_logic_vector(unsigned(AD) + unsigned(Y(7 downto 0))); + else + AD <= std_logic_vector(unsigned(AD) + unsigned(X(7 downto 0))); + end if; + end if; + + if IR = "00000000" then + BAL <= (others => '1'); + BAH <= (others => '1'); + if RstCycle = '1' then + BAL(2 downto 0) <= "100"; + elsif NMICycle = '1' then + BAL(2 downto 0) <= "010"; + else + BAL(2 downto 0) <= "110"; + end if; + if Set_addr_To_r = "11" then + BAL(0) <= '1'; + end if; + end if; + + + if LDDI = '1' then + DL <= DI; + end if; + if LDALU = '1' then + DL <= ALU_Q; + end if; + if LDAD = '1' then + AD <= DI; + end if; + if LDBAL = '1' then + BAL(7 downto 0) <= DI; + end if; + if LDBAH = '1' then + BAH <= DI; + end if; + end if; + end if; + end if; + end process; + + Break <= (BreakAtNA and not BAL(8)) or (PCAdd and not PCAdder(8)); + + + with Set_BusA_To select + BusA <= DI when "000", + ABC(7 downto 0) when "001", + X(7 downto 0) when "010", + Y(7 downto 0) when "011", + std_logic_vector(S(7 downto 0)) when "100", + P when "101", + (others => '-') when others; + + with Set_Addr_To_r select + A <= "0000000000000001" & std_logic_vector(S(7 downto 0)) when "01", + DBR & "00000000" & AD when "10", + "00000000" & BAH & BAL(7 downto 0) when "11", + PBR & std_logic_vector(PC(15 downto 8)) & std_logic_vector(PCAdder(7 downto 0)) when others; + + with Write_Data_r select + DO <= DL when "000", + ABC(7 downto 0) when "001", + X(7 downto 0) when "010", + Y(7 downto 0) when "011", + std_logic_vector(S(7 downto 0)) when "100", + P when "101", + std_logic_vector(PC(7 downto 0)) when "110", + std_logic_vector(PC(15 downto 8)) when others; + +------------------------------------------------------------------------- +-- +-- Main state machine +-- +------------------------------------------------------------------------- + + process (Res_n, Clk) + begin + if Res_n = '0' then + MCycle <= "001"; + RstCycle <= '1'; + IRQCycle <= '0'; + NMICycle <= '0'; + NMIAct <= '0'; + elsif Clk'event and Clk = '1' then + if (Enable = '1') then + if (really_rdy = '1') then + if MCycle = LCycle or Break = '1' then + MCycle <= "000"; + RstCycle <= '0'; + IRQCycle <= '0'; + NMICycle <= '0'; + if NMIAct = '1' then + NMICycle <= '1'; + elsif IRQ_n_o = '0' and P(Flag_I) = '0' then + IRQCycle <= '1'; + end if; + else + MCycle <= std_logic_vector(unsigned(MCycle) + 1); + end if; + + if NMICycle = '1' then + NMIAct <= '0'; + end if; + if NMI_n_o = '1' and NMI_n = '0' then + NMIAct <= '1'; + end if; + end if; + end if; + end if; + end process; + +end; diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/T65/T65_ALU.vhd b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/T65/T65_ALU.vhd new file mode 100644 index 00000000..b1f6d632 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/T65/T65_ALU.vhd @@ -0,0 +1,260 @@ +-- **** +-- T65(b) core. In an effort to merge and maintain bug fixes .... +-- +-- +-- Ver 300 Bugfixes by ehenciak added +-- MikeJ March 2005 +-- Latest version from www.fpgaarcade.com (original www.opencores.org) +-- +-- **** +-- +-- 6502 compatible microprocessor core +-- +-- Version : 0245 +-- +-- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- The latest version of this file can be found at: +-- http://www.opencores.org/cvsweb.shtml/t65/ +-- +-- Limitations : +-- +-- File history : +-- +-- 0245 : First version +-- + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; +use work.T65_Pack.all; + +entity T65_ALU is + port( + Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65816 + Op : in std_logic_vector(3 downto 0); + BusA : in std_logic_vector(7 downto 0); + BusB : in std_logic_vector(7 downto 0); + P_In : in std_logic_vector(7 downto 0); + P_Out : out std_logic_vector(7 downto 0); + Q : out std_logic_vector(7 downto 0) + ); +end T65_ALU; + +architecture rtl of T65_ALU is + + -- AddSub variables (temporary signals) + signal ADC_Z : std_logic; + signal ADC_C : std_logic; + signal ADC_V : std_logic; + signal ADC_N : std_logic; + signal ADC_Q : std_logic_vector(7 downto 0); + signal SBC_Z : std_logic; + signal SBC_C : std_logic; + signal SBC_V : std_logic; + signal SBC_N : std_logic; + signal SBC_Q : std_logic_vector(7 downto 0); + +begin + + process (P_In, BusA, BusB) + variable AL : unsigned(6 downto 0); + variable AH : unsigned(6 downto 0); + variable C : std_logic; + begin + AL := resize(unsigned(BusA(3 downto 0) & P_In(Flag_C)), 7) + resize(unsigned(BusB(3 downto 0) & "1"), 7); + AH := resize(unsigned(BusA(7 downto 4) & AL(5)), 7) + resize(unsigned(BusB(7 downto 4) & "1"), 7); + +-- pragma translate_off + if is_x(std_logic_vector(AL)) then AL := "0000000"; end if; + if is_x(std_logic_vector(AH)) then AH := "0000000"; end if; +-- pragma translate_on + + if AL(4 downto 1) = 0 and AH(4 downto 1) = 0 then + ADC_Z <= '1'; + else + ADC_Z <= '0'; + end if; + + if AL(5 downto 1) > 9 and P_In(Flag_D) = '1' then + AL(6 downto 1) := AL(6 downto 1) + 6; + end if; + + C := AL(6) or AL(5); + AH := resize(unsigned(BusA(7 downto 4) & C), 7) + resize(unsigned(BusB(7 downto 4) & "1"), 7); + + ADC_N <= AH(4); + ADC_V <= (AH(4) xor BusA(7)) and not (BusA(7) xor BusB(7)); + +-- pragma translate_off + if is_x(std_logic_vector(AH)) then AH := "0000000"; end if; +-- pragma translate_on + + if AH(5 downto 1) > 9 and P_In(Flag_D) = '1' then + AH(6 downto 1) := AH(6 downto 1) + 6; + end if; + + ADC_C <= AH(6) or AH(5); + + ADC_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1)); + end process; + + process (Op, P_In, BusA, BusB) + variable AL : unsigned(6 downto 0); + variable AH : unsigned(5 downto 0); + variable C : std_logic; + begin + C := P_In(Flag_C) or not Op(0); + AL := resize(unsigned(BusA(3 downto 0) & C), 7) - resize(unsigned(BusB(3 downto 0) & "1"), 6); + AH := resize(unsigned(BusA(7 downto 4) & "0"), 6) - resize(unsigned(BusB(7 downto 4) & AL(5)), 6); + +-- pragma translate_off + if is_x(std_logic_vector(AL)) then AL := "0000000"; end if; + if is_x(std_logic_vector(AH)) then AH := "000000"; end if; +-- pragma translate_on + + if AL(4 downto 1) = 0 and AH(4 downto 1) = 0 then + SBC_Z <= '1'; + else + SBC_Z <= '0'; + end if; + + SBC_C <= not AH(5); + SBC_V <= (AH(4) xor BusA(7)) and (BusA(7) xor BusB(7)); + SBC_N <= AH(4); + + if P_In(Flag_D) = '1' then + if AL(5) = '1' then + AL(5 downto 1) := AL(5 downto 1) - 6; + end if; + AH := resize(unsigned(BusA(7 downto 4) & "0"), 6) - resize(unsigned(BusB(7 downto 4) & AL(6)), 6); + if AH(5) = '1' then + AH(5 downto 1) := AH(5 downto 1) - 6; + end if; + end if; + + SBC_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1)); + end process; + + process (Op, P_In, BusA, BusB, + ADC_Z, ADC_C, ADC_V, ADC_N, ADC_Q, + SBC_Z, SBC_C, SBC_V, SBC_N, SBC_Q) + variable Q_t : std_logic_vector(7 downto 0); + begin + -- ORA, AND, EOR, ADC, NOP, LD, CMP, SBC + -- ASL, ROL, LSR, ROR, BIT, LD, DEC, INC + P_Out <= P_In; + Q_t := BusA; + case Op(3 downto 0) is + when "0000" => + -- ORA + Q_t := BusA or BusB; + when "0001" => + -- AND + Q_t := BusA and BusB; + when "0010" => + -- EOR + Q_t := BusA xor BusB; + when "0011" => + -- ADC + P_Out(Flag_V) <= ADC_V; + P_Out(Flag_C) <= ADC_C; + Q_t := ADC_Q; + when "0101" | "1101" => + -- LDA + when "0110" => + -- CMP + P_Out(Flag_C) <= SBC_C; + when "0111" => + -- SBC + P_Out(Flag_V) <= SBC_V; + P_Out(Flag_C) <= SBC_C; + Q_t := SBC_Q; + when "1000" => + -- ASL + Q_t := BusA(6 downto 0) & "0"; + P_Out(Flag_C) <= BusA(7); + when "1001" => + -- ROL + Q_t := BusA(6 downto 0) & P_In(Flag_C); + P_Out(Flag_C) <= BusA(7); + when "1010" => + -- LSR + Q_t := "0" & BusA(7 downto 1); + P_Out(Flag_C) <= BusA(0); + when "1011" => + -- ROR + Q_t := P_In(Flag_C) & BusA(7 downto 1); + P_Out(Flag_C) <= BusA(0); + when "1100" => + -- BIT + P_Out(Flag_V) <= BusB(6); + when "1110" => + -- DEC + Q_t := std_logic_vector(unsigned(BusA) - 1); + when "1111" => + -- INC + Q_t := std_logic_vector(unsigned(BusA) + 1); + when others => + end case; + + case Op(3 downto 0) is + when "0011" => + P_Out(Flag_N) <= ADC_N; + P_Out(Flag_Z) <= ADC_Z; + when "0110" | "0111" => + P_Out(Flag_N) <= SBC_N; + P_Out(Flag_Z) <= SBC_Z; + when "0100" => + when "1100" => + P_Out(Flag_N) <= BusB(7); + if (BusA and BusB) = "00000000" then + P_Out(Flag_Z) <= '1'; + else + P_Out(Flag_Z) <= '0'; + end if; + when others => + P_Out(Flag_N) <= Q_t(7); + if Q_t = "00000000" then + P_Out(Flag_Z) <= '1'; + else + P_Out(Flag_Z) <= '0'; + end if; + end case; + + Q <= Q_t; + end process; + +end; diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/T65/T65_MCode.vhd b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/T65/T65_MCode.vhd new file mode 100644 index 00000000..06229751 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/T65/T65_MCode.vhd @@ -0,0 +1,1050 @@ +-- **** +-- T65(b) core. In an effort to merge and maintain bug fixes .... +-- +-- +-- Ver 301 Jump timing fixed +-- Ver 300 Bugfixes by ehenciak added +-- MikeJ March 2005 +-- Latest version from www.fpgaarcade.com (original www.opencores.org) +-- +-- **** +-- +-- 65xx compatible microprocessor core +-- +-- Version : 0246 + fix +-- +-- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- The latest version of this file can be found at: +-- http://www.opencores.org/cvsweb.shtml/t65/ +-- +-- Limitations : +-- +-- 65C02 +-- supported : inc, dec, phx, plx, phy, ply +-- missing : bra, ora, lda, cmp, sbc, tsb*2, trb*2, stz*2, bit*2, wai, stp, jmp, bbr*8, bbs*8 +-- +-- File history : +-- +-- 0246 : First release +-- + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; +use work.T65_Pack.all; + +entity T65_MCode is + port( + Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65816 + IR : in std_logic_vector(7 downto 0); + MCycle : in std_logic_vector(2 downto 0); + P : in std_logic_vector(7 downto 0); + LCycle : out std_logic_vector(2 downto 0); + ALU_Op : out std_logic_vector(3 downto 0); + Set_BusA_To : out std_logic_vector(2 downto 0); -- DI,A,X,Y,S,P + Set_Addr_To : out std_logic_vector(1 downto 0); -- PC Adder,S,AD,BA + Write_Data : out std_logic_vector(2 downto 0); -- DL,A,X,Y,S,P,PCL,PCH + Jump : out std_logic_vector(1 downto 0); -- PC,++,DIDL,Rel + BAAdd : out std_logic_vector(1 downto 0); -- None,DB Inc,BA Add,BA Adj + BreakAtNA : out std_logic; + ADAdd : out std_logic; + AddY : out std_logic; + PCAdd : out std_logic; + Inc_S : out std_logic; + Dec_S : out std_logic; + LDA : out std_logic; + LDP : out std_logic; + LDX : out std_logic; + LDY : out std_logic; + LDS : out std_logic; + LDDI : out std_logic; + LDALU : out std_logic; + LDAD : out std_logic; + LDBAL : out std_logic; + LDBAH : out std_logic; + SaveP : out std_logic; + Write : out std_logic + ); +end T65_MCode; + +architecture rtl of T65_MCode is + + signal Branch : std_logic; + +begin + + with IR(7 downto 5) select + Branch <= not P(Flag_N) when "000", + P(Flag_N) when "001", + not P(Flag_V) when "010", + P(Flag_V) when "011", + not P(Flag_C) when "100", + P(Flag_C) when "101", + not P(Flag_Z) when "110", + P(Flag_Z) when others; + + process (IR, MCycle, P, Branch, Mode) + begin + LCycle <= "001"; + Set_BusA_To <= "001"; -- A + Set_Addr_To <= (others => '0'); + Write_Data <= (others => '0'); + Jump <= (others => '0'); + BAAdd <= "00"; + BreakAtNA <= '0'; + ADAdd <= '0'; + PCAdd <= '0'; + Inc_S <= '0'; + Dec_S <= '0'; + LDA <= '0'; + LDP <= '0'; + LDX <= '0'; + LDY <= '0'; + LDS <= '0'; + LDDI <= '0'; + LDALU <= '0'; + LDAD <= '0'; + LDBAL <= '0'; + LDBAH <= '0'; + SaveP <= '0'; + Write <= '0'; + AddY <= '0'; + + case IR(7 downto 5) is + when "100" => + --{{{ + case IR(1 downto 0) is + when "00" => + Set_BusA_To <= "011"; -- Y + Write_Data <= "011"; -- Y + when "10" => + Set_BusA_To <= "010"; -- X + Write_Data <= "010"; -- X + when others => + Write_Data <= "001"; -- A + end case; + --}}} + when "101" => + --{{{ + case IR(1 downto 0) is + when "00" => + if IR(4) /= '1' or IR(2) /= '0' then + LDY <= '1'; + end if; + when "10" => + LDX <= '1'; + when others => + LDA <= '1'; + end case; + Set_BusA_To <= "000"; -- DI + --}}} + when "110" => + --{{{ + case IR(1 downto 0) is + when "00" => + if IR(4) = '0' then + LDY <= '1'; + end if; + Set_BusA_To <= "011"; -- Y + when others => + Set_BusA_To <= "001"; -- A + end case; + --}}} + when "111" => + --{{{ + case IR(1 downto 0) is + when "00" => + if IR(4) = '0' then + LDX <= '1'; + end if; + Set_BusA_To <= "010"; -- X + when others => + Set_BusA_To <= "001"; -- A + end case; + --}}} + when others => + end case; + + if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then + Set_BusA_To <= "000"; -- DI + end if; + + case IR(4 downto 0) is + when "00000" | "01000" | "01010" | "11000" | "11010" => + --{{{ + -- Implied + case IR is + when "00000000" => + -- BRK + LCycle <= "110"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= "01"; -- S + Write_Data <= "111"; -- PCH + Write <= '1'; + when 2 => + Dec_S <= '1'; + Set_Addr_To <= "01"; -- S + Write_Data <= "110"; -- PCL + Write <= '1'; + when 3 => + Dec_S <= '1'; + Set_Addr_To <= "01"; -- S + Write_Data <= "101"; -- P + Write <= '1'; + when 4 => + Dec_S <= '1'; + Set_Addr_To <= "11"; -- BA + when 5 => + LDDI <= '1'; + Set_Addr_To <= "11"; -- BA + when 6 => + Jump <= "10"; -- DIDL + when others => + end case; + when "00100000" => + -- JSR + LCycle <= "101"; + case to_integer(unsigned(MCycle)) is + when 1 => + Jump <= "01"; + LDDI <= '1'; + Set_Addr_To <= "01"; -- S + when 2 => + Set_Addr_To <= "01"; -- S + Write_Data <= "111"; -- PCH + Write <= '1'; + when 3 => + Dec_S <= '1'; + Set_Addr_To <= "01"; -- S + Write_Data <= "110"; -- PCL + Write <= '1'; + when 4 => + Dec_S <= '1'; + when 5 => + Jump <= "10"; -- DIDL + when others => + end case; + when "01000000" => + -- RTI + LCycle <= "101"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= "01"; -- S + when 2 => + Inc_S <= '1'; + Set_Addr_To <= "01"; -- S + when 3 => + Inc_S <= '1'; + Set_Addr_To <= "01"; -- S + Set_BusA_To <= "000"; -- DI + when 4 => + LDP <= '1'; + Inc_S <= '1'; + LDDI <= '1'; + Set_Addr_To <= "01"; -- S + when 5 => + Jump <= "10"; -- DIDL + when others => + end case; + when "01100000" => + -- RTS + LCycle <= "101"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= "01"; -- S + when 2 => + Inc_S <= '1'; + Set_Addr_To <= "01"; -- S + when 3 => + Inc_S <= '1'; + LDDI <= '1'; + Set_Addr_To <= "01"; -- S + when 4 => + Jump <= "10"; -- DIDL + when 5 => + Jump <= "01"; + when others => + end case; + when "00001000" | "01001000" | "01011010" | "11011010" => + -- PHP, PHA, PHY*, PHX* + LCycle <= "010"; + if Mode = "00" and IR(1) = '1' then + LCycle <= "001"; + end if; + case to_integer(unsigned(MCycle)) is + when 1 => + case IR(7 downto 4) is + when "0000" => + Write_Data <= "101"; -- P + when "0100" => + Write_Data <= "001"; -- A + when "0101" => + Write_Data <= "011"; -- Y + when "1101" => + Write_Data <= "010"; -- X + when others => + end case; + Write <= '1'; + Set_Addr_To <= "01"; -- S + when 2 => + Dec_S <= '1'; + when others => + end case; + when "00101000" | "01101000" | "01111010" | "11111010" => + -- PLP, PLA, PLY*, PLX* + LCycle <= "011"; + if Mode = "00" and IR(1) = '1' then + LCycle <= "001"; + end if; + case IR(7 downto 4) is + when "0010" => + LDP <= '1'; + when "0110" => + LDA <= '1'; + when "0111" => + if Mode /= "00" then + LDY <= '1'; + end if; + when "1111" => + if Mode /= "00" then + LDX <= '1'; + end if; + when others => + end case; + case to_integer(unsigned(MCycle)) is + when 0 => + SaveP <= '1'; + when 1 => + Set_Addr_To <= "01"; -- S + when 2 => + Inc_S <= '1'; + Set_Addr_To <= "01"; -- S + when 3 => + Set_BusA_To <= "000"; -- DI + when others => + end case; + when "10100000" | "11000000" | "11100000" => + -- LDY, CPY, CPX + -- Immediate + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Jump <= "01"; + when others => + end case; + when "10001000" => + -- DEY + LDY <= '1'; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Set_BusA_To <= "011"; -- Y + when others => + end case; + when "11001010" => + -- DEX + LDX <= '1'; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Set_BusA_To <= "010"; -- X + when others => + end case; + when "00011010" | "00111010" => + -- INC*, DEC* + if Mode /= "00" then + LDA <= '1'; -- A + end if; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Set_BusA_To <= "100"; -- S + when others => + end case; + when "00001010" | "00101010" | "01001010" | "01101010" => + -- ASL, ROL, LSR, ROR + LDA <= '1'; -- A + Set_BusA_To <= "001"; -- A + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + when others => + end case; + when "10001010" | "10011000" => + -- TYA, TXA + LDA <= '1'; -- A + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + when others => + end case; + when "10101010" | "10101000" => + -- TAX, TAY + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Set_BusA_To <= "001"; -- A + when others => + end case; + when "10011010" => + -- TXS + case to_integer(unsigned(MCycle)) is + when 0 => + LDS <= '1'; + when 1 => + when others => + end case; + when "10111010" => + -- TSX + LDX <= '1'; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Set_BusA_To <= "100"; -- S + when others => + end case; + + -- when "00011000" | "00111000" | "01011000" | "01111000" | "10111000" | "11011000" | "11111000" | "11001000" | "11101000" => + -- -- CLC, SEC, CLI, SEI, CLV, CLD, SED, INY, INX + -- case to_integer(unsigned(MCycle)) is + -- when 1 => + -- when others => + -- end case; + when others => + case to_integer(unsigned(MCycle)) is + when 0 => + when others => + end case; + end case; + --}}} + + when "00001" | "00011" => + --{{{ + -- Zero Page Indexed Indirect (d,x) + LCycle <= "101"; + if IR(7 downto 6) /= "10" then + LDA <= '1'; + end if; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= "10"; -- AD + when 2 => + ADAdd <= '1'; + Set_Addr_To <= "10"; -- AD + when 3 => + BAAdd <= "01"; -- DB Inc + LDBAL <= '1'; + Set_Addr_To <= "10"; -- AD + when 4 => + LDBAH <= '1'; + if IR(7 downto 5) = "100" then + Write <= '1'; + end if; + Set_Addr_To <= "11"; -- BA + when 5 => + when others => + end case; + --}}} + + when "01001" | "01011" => + --{{{ + -- Immediate + LDA <= '1'; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Jump <= "01"; + when others => + end case; + + --}}} + + when "00010" | "10010" => + --{{{ + -- Immediate, KIL + LDX <= '1'; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + if IR = "10100010" then + -- LDX + Jump <= "01"; + else + -- KIL !!!!!!!!!!!!!!!!!!!!!!!!!!!!! + end if; + when others => + end case; + --}}} + + when "00100" => + --{{{ + -- Zero Page + LCycle <= "010"; + case to_integer(unsigned(MCycle)) is + when 0 => + if IR(7 downto 5) = "001" then + SaveP <= '1'; + end if; + when 1 => + Jump <= "01"; + LDAD <= '1'; + if IR(7 downto 5) = "100" then + Write <= '1'; + end if; + Set_Addr_To <= "10"; -- AD + when 2 => + when others => + end case; + --}}} + + when "00101" | "00110" | "00111" => + --{{{ + -- Zero Page + if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then + -- Read-Modify-Write + LCycle <= "100"; + case to_integer(unsigned(MCycle)) is + when 1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= "10"; -- AD + when 2 => + LDDI <= '1'; + Write <= '1'; + Set_Addr_To <= "10"; -- AD + when 3 => + LDALU <= '1'; + SaveP <= '1'; + Write <= '1'; + Set_Addr_To <= "10"; -- AD + when 4 => + when others => + end case; + else + LCycle <= "010"; + if IR(7 downto 6) /= "10" then + LDA <= '1'; + end if; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Jump <= "01"; + LDAD <= '1'; + if IR(7 downto 5) = "100" then + Write <= '1'; + end if; + Set_Addr_To <= "10"; -- AD + when 2 => + when others => + end case; + end if; + --}}} + + when "01100" => + --{{{ + -- Absolute + if IR(7 downto 6) = "01" and IR(4 downto 0) = "01100" then + -- JMP + if IR(5) = '0' then + --LCycle <= "011"; + LCycle <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Jump <= "01"; + LDDI <= '1'; + when 2 => + Jump <= "10"; -- DIDL + when others => + end case; + else + LCycle <= "101"; + case to_integer(unsigned(MCycle)) is + when 2 => + Jump <= "01"; + LDDI <= '1'; + LDBAL <= '1'; + when 3 => + LDBAH <= '1'; + if Mode /= "00" then + Jump <= "10"; -- DIDL + end if; + if Mode = "00" then + Set_Addr_To <= "11"; -- BA + end if; + when 4 => + LDDI <= '1'; + if Mode = "00" then + Set_Addr_To <= "11"; -- BA + BAAdd <= "01"; -- DB Inc + else + Jump <= "01"; + end if; + when 5 => + Jump <= "10"; -- DIDL + when others => + end case; + end if; + else + LCycle <= "011"; + case to_integer(unsigned(MCycle)) is + when 0 => + if IR(7 downto 5) = "001" then + SaveP <= '1'; + end if; + when 1 => + Jump <= "01"; + LDBAL <= '1'; + when 2 => + Jump <= "01"; + LDBAH <= '1'; + if IR(7 downto 5) = "100" then + Write <= '1'; + end if; + Set_Addr_To <= "11"; -- BA + when 3 => + when others => + end case; + end if; + --}}} + + when "01101" | "01110" | "01111" => + --{{{ + -- Absolute + if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then + -- Read-Modify-Write + LCycle <= "101"; + case to_integer(unsigned(MCycle)) is + when 1 => + Jump <= "01"; + LDBAL <= '1'; + when 2 => + Jump <= "01"; + LDBAH <= '1'; + Set_Addr_To <= "11"; -- BA + when 3 => + LDDI <= '1'; + Write <= '1'; + Set_Addr_To <= "11"; -- BA + when 4 => + Write <= '1'; + LDALU <= '1'; + SaveP <= '1'; + Set_Addr_To <= "11"; -- BA + when 5 => + SaveP <= '0'; -- MIKEJ was 1 + when others => + end case; + else + LCycle <= "011"; + if IR(7 downto 6) /= "10" then + LDA <= '1'; + end if; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Jump <= "01"; + LDBAL <= '1'; + when 2 => + Jump <= "01"; + LDBAH <= '1'; + if IR(7 downto 5) = "100" then + Write <= '1'; + end if; + Set_Addr_To <= "11"; -- BA + when 3 => + when others => + end case; + end if; + --}}} + + when "10000" => + --{{{ + -- Relative + + -- This circuit dictates when the last + -- microcycle occurs for the branch depending on + -- whether or not the branch is taken and if a page + -- is crossed... + if (Branch = '1') then + + LCycle <= "011"; -- We're done @ T3 if branching...upper + -- level logic will stop at T2 if no page cross + -- (See the Break signal) + else + + LCycle <= "001"; + + end if; + + -- This decodes the current microcycle and takes the + -- proper course of action... + case to_integer(unsigned(MCycle)) is + + -- On the T1 microcycle, increment the program counter + -- and instruct the upper level logic to fetch the offset + -- from the Din bus and store it in the data latches. This + -- will be the last microcycle if the branch isn't taken. + when 1 => + + Jump <= "01"; -- Increments the PC by one (PC will now be PC+2) + -- from microcycle T0. + + LDDI <= '1'; -- Tells logic in top level (T65.vhd) to route + -- the Din bus to the memory data latch (DL) + -- so that the branch offset is fetched. + + -- In microcycle T2, tell the logic in the top level to + -- add the offset. If the most significant byte of the + -- program counter (i.e. the current "page") does not need + -- updating, we are done here...the Break signal at the + -- T65.vhd level takes care of that... + when 2 => + + Jump <= "11"; -- Tell the PC Jump logic to use relative mode. + + PCAdd <= '1'; -- This tells the PC adder to update itself with + -- the current offset recently fetched from + -- memory. + + -- The following is microcycle T3 : + -- The program counter should be completely updated + -- on this cycle after the page cross is detected. + -- We don't need to do anything here... + when 3 => + + + when others => null; -- Do nothing. + + end case; + --}}} + + when "10001" | "10011" => + --{{{ + -- Zero Page Indirect Indexed (d),y + LCycle <= "101"; + if IR(7 downto 6) /= "10" then + LDA <= '1'; + end if; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= "10"; -- AD + when 2 => + LDBAL <= '1'; + BAAdd <= "01"; -- DB Inc + Set_Addr_To <= "10"; -- AD + when 3 => + Set_BusA_To <= "011"; -- Y + BAAdd <= "10"; -- BA Add + LDBAH <= '1'; + Set_Addr_To <= "11"; -- BA + when 4 => + BAAdd <= "11"; -- BA Adj + if IR(7 downto 5) = "100" then + Write <= '1'; + else + BreakAtNA <= '1'; + end if; + Set_Addr_To <= "11"; -- BA + when 5 => + when others => + end case; + --}}} + + when "10100" | "10101" | "10110" | "10111" => + --{{{ + -- Zero Page, X + if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then + -- Read-Modify-Write + LCycle <= "101"; + case to_integer(unsigned(MCycle)) is + when 1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= "10"; -- AD + when 2 => + ADAdd <= '1'; + Set_Addr_To <= "10"; -- AD + when 3 => + LDDI <= '1'; + Write <= '1'; + Set_Addr_To <= "10"; -- AD + when 4 => + LDALU <= '1'; + SaveP <= '1'; + Write <= '1'; + Set_Addr_To <= "10"; -- AD + when 5 => + when others => + end case; + else + LCycle <= "011"; + if IR(7 downto 6) /= "10" then + LDA <= '1'; + end if; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= "10"; -- AD + when 2 => + ADAdd <= '1'; + -- Added this check for Y reg. use... + if (IR(3 downto 0) = "0110") then + AddY <= '1'; + end if; + + if IR(7 downto 5) = "100" then + Write <= '1'; + end if; + Set_Addr_To <= "10"; -- AD + when 3 => null; + when others => + end case; + end if; + --}}} + + when "11001" | "11011" => + --{{{ + -- Absolute Y + LCycle <= "100"; + if IR(7 downto 6) /= "10" then + LDA <= '1'; + end if; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Jump <= "01"; + LDBAL <= '1'; + when 2 => + Jump <= "01"; + Set_BusA_To <= "011"; -- Y + BAAdd <= "10"; -- BA Add + LDBAH <= '1'; + Set_Addr_To <= "11"; -- BA + when 3 => + BAAdd <= "11"; -- BA adj + if IR(7 downto 5) = "100" then + Write <= '1'; + else + BreakAtNA <= '1'; + end if; + Set_Addr_To <= "11"; -- BA + when 4 => + when others => + end case; + --}}} + + when "11100" | "11101" | "11110" | "11111" => + --{{{ + -- Absolute X + + if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then + -- Read-Modify-Write + LCycle <= "110"; + case to_integer(unsigned(MCycle)) is + when 1 => + Jump <= "01"; + LDBAL <= '1'; + when 2 => + Jump <= "01"; + Set_BusA_To <= "010"; -- X + BAAdd <= "10"; -- BA Add + LDBAH <= '1'; + Set_Addr_To <= "11"; -- BA + when 3 => + BAAdd <= "11"; -- BA adj + Set_Addr_To <= "11"; -- BA + when 4 => + LDDI <= '1'; + Write <= '1'; + Set_Addr_To <= "11"; -- BA + when 5 => + LDALU <= '1'; + SaveP <= '1'; + Write <= '1'; + Set_Addr_To <= "11"; -- BA + when 6 => + when others => + end case; + else + LCycle <= "100"; + if IR(7 downto 6) /= "10" then + LDA <= '1'; + end if; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Jump <= "01"; + LDBAL <= '1'; + when 2 => + Jump <= "01"; + -- mikej + -- special case 0xBE which uses Y reg as index!! + if (IR = "10111110") then + Set_BusA_To <= "011"; -- Y + else + Set_BusA_To <= "010"; -- X + end if; + BAAdd <= "10"; -- BA Add + LDBAH <= '1'; + Set_Addr_To <= "11"; -- BA + when 3 => + BAAdd <= "11"; -- BA adj + if IR(7 downto 5) = "100" then + Write <= '1'; + else + BreakAtNA <= '1'; + end if; + Set_Addr_To <= "11"; -- BA + when 4 => + when others => + end case; + end if; + --}}} + when others => + end case; + end process; + + process (IR, MCycle) + begin + -- ORA, AND, EOR, ADC, NOP, LD, CMP, SBC + -- ASL, ROL, LSR, ROR, BIT, LD, DEC, INC + case IR(1 downto 0) is + when "00" => + --{{{ + case IR(4 downto 2) is + when "000" | "001" | "011" => + case IR(7 downto 5) is + when "110" | "111" => + -- CP + ALU_Op <= "0110"; + when "101" => + -- LD + ALU_Op <= "0101"; + when "001" => + -- BIT + ALU_Op <= "1100"; + when others => + -- NOP/ST + ALU_Op <= "0100"; + end case; + when "010" => + case IR(7 downto 5) is + when "111" | "110" => + -- IN + ALU_Op <= "1111"; + when "100" => + -- DEY + ALU_Op <= "1110"; + when others => + -- LD + ALU_Op <= "1101"; + end case; + when "110" => + case IR(7 downto 5) is + when "100" => + -- TYA + ALU_Op <= "1101"; + when others => + ALU_Op <= "----"; + end case; + when others => + case IR(7 downto 5) is + when "101" => + -- LD + ALU_Op <= "1101"; + when others => + ALU_Op <= "0100"; + end case; + end case; + --}}} + when "01" => -- OR + --{{{ + ALU_Op(3) <= '0'; + ALU_Op(2 downto 0) <= IR(7 downto 5); + --}}} + when "10" => + --{{{ + ALU_Op(3) <= '1'; + ALU_Op(2 downto 0) <= IR(7 downto 5); + case IR(7 downto 5) is + when "000" => + if IR(4 downto 2) = "110" then + -- INC + ALU_Op <= "1111"; + end if; + when "001" => + if IR(4 downto 2) = "110" then + -- DEC + ALU_Op <= "1110"; + end if; + when "100" => + if IR(4 downto 2) = "010" then + -- TXA + ALU_Op <= "0101"; + else + ALU_Op <= "0100"; + end if; + when others => + end case; + --}}} + when others => + --{{{ + case IR(7 downto 5) is + when "100" => + ALU_Op <= "0100"; + when others => + if MCycle = "000" then + ALU_Op(3) <= '0'; + ALU_Op(2 downto 0) <= IR(7 downto 5); + else + ALU_Op(3) <= '1'; + ALU_Op(2 downto 0) <= IR(7 downto 5); + end if; + end case; + --}}} + end case; + end process; + +end; diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/T65/T65_Pack.vhd b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/T65/T65_Pack.vhd new file mode 100644 index 00000000..e025e1bf --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/T65/T65_Pack.vhd @@ -0,0 +1,117 @@ +-- **** +-- T65(b) core. In an effort to merge and maintain bug fixes .... +-- +-- +-- Ver 300 Bugfixes by ehenciak added +-- MikeJ March 2005 +-- Latest version from www.fpgaarcade.com (original www.opencores.org) +-- +-- **** +-- +-- 65xx compatible microprocessor core +-- +-- Version : 0246 +-- +-- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- The latest version of this file can be found at: +-- http://www.opencores.org/cvsweb.shtml/t65/ +-- +-- Limitations : +-- +-- File history : +-- + +library IEEE; +use IEEE.std_logic_1164.all; + +package T65_Pack is + + constant Flag_C : integer := 0; + constant Flag_Z : integer := 1; + constant Flag_I : integer := 2; + constant Flag_D : integer := 3; + constant Flag_B : integer := 4; + constant Flag_1 : integer := 5; + constant Flag_V : integer := 6; + constant Flag_N : integer := 7; + + component T65_MCode + port( + Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65816 + IR : in std_logic_vector(7 downto 0); + MCycle : in std_logic_vector(2 downto 0); + P : in std_logic_vector(7 downto 0); + LCycle : out std_logic_vector(2 downto 0); + ALU_Op : out std_logic_vector(3 downto 0); + Set_BusA_To : out std_logic_vector(2 downto 0); -- DI,A,X,Y,S,P + Set_Addr_To : out std_logic_vector(1 downto 0); -- PC Adder,S,AD,BA + Write_Data : out std_logic_vector(2 downto 0); -- DL,A,X,Y,S,P,PCL,PCH + Jump : out std_logic_vector(1 downto 0); -- PC,++,DIDL,Rel + BAAdd : out std_logic_vector(1 downto 0); -- None,DB Inc,BA Add,BA Adj + BreakAtNA : out std_logic; + ADAdd : out std_logic; + AddY : out std_logic; + PCAdd : out std_logic; + Inc_S : out std_logic; + Dec_S : out std_logic; + LDA : out std_logic; + LDP : out std_logic; + LDX : out std_logic; + LDY : out std_logic; + LDS : out std_logic; + LDDI : out std_logic; + LDALU : out std_logic; + LDAD : out std_logic; + LDBAL : out std_logic; + LDBAH : out std_logic; + SaveP : out std_logic; + Write : out std_logic + ); + end component; + + component T65_ALU + port( + Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816 + Op : in std_logic_vector(3 downto 0); + BusA : in std_logic_vector(7 downto 0); + BusB : in std_logic_vector(7 downto 0); + P_In : in std_logic_vector(7 downto 0); + P_Out : out std_logic_vector(7 downto 0); + Q : out std_logic_vector(7 downto 0) + ); + end component; + +end; diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/build_id.sv b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/build_id.sv new file mode 100644 index 00000000..1d53a3f2 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/build_id.sv @@ -0,0 +1,2 @@ +`define BUILD_DATE "171221" +`define BUILD_TIME "172231" diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/build_id.tcl b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/build_id.tcl new file mode 100644 index 00000000..be673dac --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/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.sv" + 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/Custom Hardware/UltraTank_MiST/rtl/collision.vhd b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/collision.vhd new file mode 100644 index 00000000..1425281a --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/collision.vhd @@ -0,0 +1,105 @@ +-- Collision detection logic for for Kee Games Ultra Tank +-- This is called the "Tank/Shell Comparator" in the manual and works by comparing the +-- video signals representing tanks, shells and playfield objects generating +-- collision signals when multiple objects appear at the same time (location) in the video. +-- +-- (c) 2017 James Sweet +-- +-- This 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 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. + +library IEEE; +use IEEE.STD_LOGIC_1164.all; + +entity collision_detect is +port( + Clk6 : in std_logic; + Adr : in std_logic_vector(2 downto 0); + Object_n : in std_logic_vector(4 downto 1); + Playfield_n : in std_logic; + CollisionReset_n : in std_logic_vector(4 downto 1); + Slam_n : in std_logic; -- Slam switch is read by collision detection mux + Collision_n : out std_logic + ); +end collision_detect; + +architecture rtl of collision_detect is + +signal Col_latch_Q : std_logic_vector(4 downto 1) := (others => '0'); +signal S1_n : std_logic_vector(4 downto 1); +signal R_n : std_logic_vector(4 downto 1); + + +begin + +-- Glue logic - This can be re-written to incorporate into the latch process +R_n <= CollisionReset_n; +S1_n(1) <= Object_n(1) or Playfield_n; +S1_n(2) <= Object_n(2) or Playfield_n; +S1_n(3) <= Object_n(3) or Playfield_n; +S1_n(4) <= Object_n(4) or Playfield_n; + + +-- 74LS279 quad SR latch at L11, all inputs are active low +H6: process(Clk6, S1_n, R_n, Col_latch_Q) +begin + if rising_edge(Clk6) then +-- Units 1 and 3 each have an extra Set element but these are not used in this game +-- Ordered from top to bottom as drawn in the schematic + if R_n(1) = '0' then + Col_latch_Q(1) <= '0'; + elsif S1_n(1) = '0' then + Col_latch_Q(1) <= '1'; + else + Col_latch_Q(1) <= Col_latch_Q(1); + end if; + if R_n(2) = '0' then + Col_latch_Q(2) <= '0'; + elsif S1_n(2) = '0' then + Col_latch_Q(2) <= '1'; + else + Col_latch_Q(2) <= Col_latch_Q(2); + end if; + if R_n(4) = '0' then + Col_latch_Q(4) <= '0'; + elsif S1_n(4) = '0' then + Col_latch_Q(4) <= '1'; + else + Col_latch_Q(4) <= Col_latch_Q(4); + end if; + if R_n(3) = '0' then + Col_latch_Q(3) <= '0'; + elsif S1_n(3) = '0' then + Col_latch_Q(3) <= '1'; + else + Col_latch_Q(3) <= Col_latch_Q(3); + end if; + end if; +end process; + +-- 9312 Data Selector/Multiplexer at L12 +L12: process(Adr, Slam_n, Col_latch_Q) +begin + case Adr(2 downto 0) is + when "000" => Collision_n <= '1'; + when "001" => Collision_n <= Col_latch_Q(1); + when "010" => Collision_n <= '1'; + when "011" => Collision_n <= Col_latch_Q(2); + when "100" => Collision_n <= '1'; + when "101" => Collision_n <= Col_latch_Q(3); + when "110" => Collision_n <= Slam_n; + when "111" => Collision_n <= Col_latch_Q(4); + when others => Collision_n <= '1'; + end case; +end process; + +end rtl; \ No newline at end of file diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/cpu_mem.vhd b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/cpu_mem.vhd new file mode 100644 index 00000000..2683463a --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/cpu_mem.vhd @@ -0,0 +1,460 @@ +-- CPU, RAM, ROM and address decoder for Kee Games Ultra Tank +-- (c) 2017 James Sweet +-- +-- This 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 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. + +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use IEEE.STD_LOGIC_ARITH.all; +use IEEE.STD_LOGIC_UNSIGNED.all; + +entity CPU_mem is +port( + CLK12 : in std_logic; + CLK6 : in std_logic; -- 6MHz on schematic + Reset_n : in std_logic; + VCount : in std_logic_vector(7 downto 0); + HCount : in std_logic_vector(8 downto 0); + Vblank_n_s : in std_logic; -- Vblank* on schematic + Test_n : in std_logic; + Collision_n : in std_logic; + DB_in : in std_logic_vector(7 downto 0); -- CPU data bus + DBus : buffer std_logic_vector(7 downto 0); + DBuS_n : buffer std_logic_vector(7 downto 0); + PRAM : buffer std_logic_vector(7 downto 0); + ABus : out std_logic_vector(15 downto 0); + Attract : buffer std_logic; + Attract_n : out std_logic; + CollReset_n : out std_logic_vector(4 downto 1); + Barrier_Read_n : out std_logic; + Throttle_Read_n : out std_logic; + Coin_Read_n : out std_logic; + Options_Read_n : out std_logic; + Wr_DA_Latch_n : out std_logic; + Wr_Explosion_n : out std_logic; + Fire1 : out std_logic; + Fire2 : out std_logic; + LED1 : out std_logic; + LED2 : out std_logic; + Lockout_n : out std_logic; + PHI1_O : out std_logic; + PHI2_O : out std_logic; + DMA : out std_logic_vector(7 downto 0); + DMA_n : out std_logic_vector(7 downto 0) + ); +end CPU_mem; + +architecture rtl of CPU_mem is +-- Clock signals +signal cpu_clk : std_logic; +signal PHI1 : std_logic; +signal PHI2 : std_logic; + +-- Video scan signals +signal H256 : std_logic; +signal H256_n : std_logic; +signal H128 : std_logic; +signal H64 : std_logic; +signal H32 : std_logic; +signal H16 : std_logic; +signal H8 : std_logic; +signal H4 : std_logic; +signal H2 : std_logic; +signal H1 : std_logic; +signal V128 : std_logic; +signal V64 : std_logic; +signal V32 : std_logic; +signal V16 : std_logic; +signal V8 : std_logic; + +-- CPU signals +signal NMI_n : std_logic := '1'; +signal RW_n : std_logic; +signal RnW : std_logic; +signal A : std_logic_vector(15 downto 0); +signal ADR : std_logic_vector(15 downto 0); +signal cpuDin : std_logic_vector(7 downto 0); +signal cpuDout : std_logic_vector(7 downto 0); + +-- Address decoder signals +signal N10_in : std_logic_vector(3 downto 0) := (others => '0'); +signal N10_out : std_logic_vector(9 downto 0) := (others => '1'); +signal M10_out_A : std_logic_vector(3 downto 0) := (others => '1'); +signal M10_out_B : std_logic_vector(3 downto 0) := (others => '1'); +signal B2_in : std_logic_vector(3 downto 0) := (others => '0'); +signal B2_out : std_logic_vector(9 downto 0) := (others => '1'); +signal R10_Q : std_logic := '0'; +signal D4_8 : std_logic := '1'; + +-- Buses and chip enables +signal cpuRAM_dout : std_logic_vector(7 downto 0) := (others => '0'); +signal AddRAM_dout : std_logic_vector(7 downto 0) := (others => '0'); +signal Vram_dout : std_logic_vector(7 downto 0) := (others => '0'); +signal RAM_din : std_logic_vector(7 downto 0) := (others => '0'); +signal RAM_addr : std_logic_vector(9 downto 0) := (others => '0'); +signal Vram_addr : std_logic_vector(9 downto 0) := (others => '0'); +signal RAM_dout : std_logic_vector(7 downto 0) := (others => '0'); +signal RAM_we : std_logic; +signal RAM_n : std_logic := '1'; +signal WRAM : std_logic; +signal WRITE_n : std_logic := '1'; +signal ROM_mux_in : std_logic_vector(1 downto 0) := (others => '0'); +signal ROM3_dout : std_logic_vector(7 downto 0) := (others => '0'); +signal ROM4_dout : std_logic_vector(7 downto 0) := (others => '0'); +signal ROM_dout : std_logic_vector(7 downto 0) := (others => '0'); +signal ROM3_n : std_logic := '1'; +signal ROM4_n : std_logic := '1'; +signal ROMCE_n : std_logic := '1'; +signal ADDRAM_n : std_logic := '1'; +signal Display_n : std_logic := '1'; +signal VBlank_Read_n : std_logic := '1'; +signal Timer_Reset_n : std_logic := '1'; +signal Collision_Read_n : std_logic := '1'; +signal Inputs_n : std_logic := '1'; +signal Test : std_logic := '0'; + +begin + +Test <= (not Test_n); + +H1 <= HCount(0); +H2 <= HCount(1); +H4 <= HCount(2); +H8 <= HCount(3); +H16 <= HCount(4); +H32 <= HCount(5); +H64 <= HCount(6); +H128 <= HCount(7); +H256 <= HCount(8); +H256_n <= (not HCount(8)); + +V8 <= VCount(3); +V16 <= VCount(4); +V32 <= VCount(5); +V64 <= VCount(6); +V128 <= VCount(7); + + +CPU: entity work.T65 +port map( + Enable => '1', + Mode => "00", + Res_n => reset_n, + Clk => phi1, + Rdy => '1', + Abort_n => '1', + IRQ_n => '1', + NMI_n => NMI_n, + SO_n => '1', + R_W_n => RW_n, + A(15 downto 0) => A, + DI => cpuDin, + DO => cpuDout + ); + +DBus_n <= (not cpuDout); -- Data bus to video RAM is inverted +DBus <= cpuDout; +ABus <= ADR; +ADR(15 downto 10) <= A(15 downto 10); +ADR(9 downto 8) <= (A(9) or WRAM) & (A(8) or WRAM); +ADR(7 downto 0) <= A(7 downto 0); +RnW <= (not RW_n); + +NMI_n <= ((not V32) or Test); + +-- DFF and logic used to generate the Write_n signal +R10: process(H1, H2) +begin + if rising_edge(H1) then + R10_Q <= (not H2); + end if; +end process; +Write_n <= (phi2 and R10_Q) nand RnW; + + +-- CPU clock and phase 2 clock output +Phi2 <= H4; +Phi1 <= (not PHI2); +Phi1_O <= PHI1; +Phi2_O <= PHI2; + + +-- Program ROMs +N1: entity work.sprom +generic map( + init_file => "rtl/roms/030180n1.hex", + widthad_a => 11, + width_a => 4) +port map( + clock => clk6, + address => ADR(10 downto 0), + q => rom3_dout(3 downto 0) + ); + +K1: entity work.sprom +generic map( + init_file => "rtl/roms/030181k1.hex", + widthad_a => 11, + width_a => 4) +port map( + clock => clk6, + address => ADR(10 downto 0), + q => rom3_dout(7 downto 4) + ); + +M1: entity work.sprom +generic map( + init_file => "rtl/roms/030182m1.hex", + widthad_a => 11, + width_a => 4) +port map( + clock => clk6, + address => ADR(10 downto 0), + q => rom4_dout(3 downto 0) + ); + +L1: entity work.sprom +generic map( + init_file => "rtl/roms/030183l1.hex", + widthad_a => 11, + width_a => 4) +port map( + clock => clk6, + address => ADR(10 downto 0), + q => rom4_dout(7 downto 4) + ); + +-- ROM data mux +ROM_mux_in <= (ROM4_n & ROM3_n); +ROM_mux: process(ROM_mux_in, rom3_dout, rom4_dout) + begin + ROM_dout <= (others => '0'); + case ROM_mux_in is + when "10" => rom_dout <= rom3_dout; + when "01" => rom_dout <= rom4_dout; + when others => null; + end case; +end process; +ROMCE_n <= (ROM3_n and ROM4_n); + + +-- Additional CPU RAM - Many earlier games use only a single RAM as both CPU and video RAM. This hardware has a separate 128 byte RAM +A1: entity work.spram +generic map( + widthad_a => 7, + width_a => 8) +port map( + clock => clk6, + address => Adr(6 downto 0), + wren => (not Write_n) and (not ADDRAM_n) and (not Adr(7)), + data => cpuDout, + q => AddRAM_dout + ); + +--A1: entity work.ram128 +--port map( +-- clock => clk6, +-- address => Adr(6 downto 0), +-- wren => (not Write_n) and (not ADDRAM_n) and (not Adr(7)), +-- data => cpuDout, +-- q => AddRAM_dout +-- ); + + +-- Video RAM +RAM: entity work.spram +generic map( + widthad_a => 10, + width_a => 8) +port map( + clock => clk6, + address => RAM_addr, + wren => RAM_we, + data => DBus_n, + q => RAM_dout + ); + +--RAM: entity work.ram1k +--port map( +-- clock => clk6, +-- address => RAM_addr, +-- wren => RAM_we, +-- data => DBus_n, +-- q => RAM_dout +-- ); + + +-- Altera block RAM has active high WE, original RAM had active low WE +ram_we <= (not Write_n) and (not Display_n); + +Vram_addr <= (V128 or H256_n) & (V64 or H256_n) & (V32 or H256_n) & (V16 and H256) & (V8 and H256) & H128 & H64 & H32 & H16 & H8; + +RAM_addr <= Vram_addr when phi2 = '0' else Adr(9 downto 0); + +PRAM <= (not RAM_dout); + + +-- Rising edge of phi2 clock latches inverted and non-inverted output of VRAM data bus into DMA and DMA_n complementary buses +F5: process(phi2, PRAM) +begin + if rising_edge(phi2) then + DMA <= PRAM; + DMA_n <= (not PRAM); + end if; +end process; + + +-- Address decoder +B2_in <= '0' & Adr(13 downto 11); -- AND gate C4 is involved with Adr(15), function unknown +B2: process(B2_in) +begin + case B2_in is + when "0000" => + B2_out <= "1111111110"; + when "0001" => + B2_out <= "1111111101"; + when "0010" => + B2_out <= "1111111011"; + when "0011" => + B2_out <= "1111110111"; + when "0100" => + B2_out <= "1111101111"; + when "0110" => + B2_out <= "1110111111"; + when "0111" => + B2_out <= "1101111111"; + when others => + B2_out <= "1111111111"; + end case; +end process; +ADDRAM_n <= B2_out(0); +VBlank_Read_n <= B2_out(2); +Barrier_Read_n <= B2_out(3); +ROM3_n <= B2_out(6); +ROM4_n <= B2_out(7); +WRAM <= not ((not Adr(7)) or B2_out(0)); +Display_n <= (not WRAM) and B2_out(1); +RAM_n <= (Display_n or RnW); + + +D4_8 <= not ( (not B2_out(4)) and (not Adr(7)) and (Write_n nand (Phi2 nand RW_n))); + +N10_in <= D4_8 & RnW & Adr(6 downto 5); +N10: process(N10_in) +begin + case N10_in is + when "0000" => + N10_out <= "1111111110"; + when "0001" => + N10_out <= "1111111101"; + when "0010" => + N10_out <= "1111111011"; + when "0011" => + N10_out <= "1111110111"; + when "0100" => + N10_out <= "1111101111"; + when "0101" => + N10_out <= "1111011111"; + when "0110" => + N10_out <= "1110111111"; + when "0111" => + N10_out <= "1101111111"; + when "1000" => + N10_out <= "1011111111"; + when "1001" => + N10_out <= "0111111111"; + when others => + N10_out <= "1111111111"; + end case; +end process; +Throttle_Read_n <= N10_out(0); +Coin_Read_n <= N10_out(1); +Collision_Read_n <= N10_out(2); +Options_Read_n <= N10_out(3); + +-- Used for CPU data-in mux, asserts to read inputs +Inputs_n <= B2_out(3) and N10_out(0) and N10_out(1) and N10_out(2) and N10_out(3) and B2_out(3); + +-- DFF that creates the Attract and Attract_n signals +R_10: process(N10_out, DBus_n, Attract) +begin + if rising_edge(N10_out(4)) then + Attract <= DBus_n(0); + end if; + Attract_n <= (not Attract); +end process; + +-- 9321 dual decoder at M10 creates collision reset, watchdog reset, explosion sound and input DA latch signals +M10: process(N10_out, Adr) +begin + if N10_out(5) = '1' then + M10_out_A <= "1111"; + else + case Adr(2 downto 1) is + when "00" => M10_out_A <= "1110"; + when "01" => M10_out_A <= "1101"; + when "10" => M10_out_A <= "1011"; + when "11" => M10_out_A <= "0111"; + when others => M10_out_A <= "1111"; + end case; + end if; + if N10_out(6) = '1' then + M10_out_B <= "1111"; + else + case Adr(2 downto 1) is + when "00" => M10_out_B <= "1110"; + when "01" => M10_out_B <= "1101"; + when "10" => M10_out_B <= "1011"; + when "11" => M10_out_B <= "0111"; + when others => M10_out_B <= "1111"; + end case; + end if; +end process; +CollReset_n <= M10_out_A; +Timer_Reset_n <= M10_out_B(2); +Wr_Explosion_n <= M10_out_B(1); +Wr_DA_Latch_n <= M10_out_B(0); + + +-- E11 9334 addressable latch drives shell fire sound triggers, player start button LEDs and coin mech lockout coil +E11: process(clk6, N10_out, Adr) +begin +if rising_edge(clk6) then + if (N10_out(7) = '0') then + case Adr(3 downto 1) is + when "000" => null; + when "001" => null; + when "010" => null; + when "011" => Lockout_n <= Adr(0); + when "100" => LED1 <= Adr(0); + when "101" => LED2 <= Adr(0); + when "110" => Fire2 <= Adr(0); + when "111" => Fire1 <= Adr(0); + when others => null; + end case; + end if; + end if; +end process; + + +-- CPU Din mux, no tristate logic in modern FPGAs so this mux is used to select the source to the CPU data-in bus +cpuDin <= + PRAM when (RAM_n = '0') and (Display_n = '0') else -- Video RAM + AddRAM_dout when (ADDRAM_n or Adr(7)) = '0' else -- Additional RAM + ROM_dout when ROMCE_n = '0' else -- Program ROM + VBlank_n_s & Test_n & "111111" when Vblank_Read_n = '0' else -- VBlank and Self Test switch + Collision_n & "1111111" when Collision_Read_n = '0' else -- Collision Detection + DB_in when Inputs_n = '0' else -- Inputs + x"FF"; +end rtl; + diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/dac.sv b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/dac.sv new file mode 100644 index 00000000..22ae8f07 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/dac.sv @@ -0,0 +1,33 @@ +// +// PWM DAC +// +// MSBI is the highest bit number. NOT amount of bits! +// +module dac #(parameter MSBI=6, parameter INV=1'b1) +( + output reg DACout, //Average Output feeding analog lowpass + input [MSBI:0] DACin, //DAC input (excess 2**MSBI) + input CLK, + input RESET +); + +reg [MSBI+2:0] DeltaAdder; //Output of Delta Adder +reg [MSBI+2:0] SigmaAdder; //Output of Sigma Adder +reg [MSBI+2:0] SigmaLatch; //Latches output of Sigma Adder +reg [MSBI+2:0] DeltaB; //B input of Delta Adder + +always @(*) DeltaB = {SigmaLatch[MSBI+2], SigmaLatch[MSBI+2]} << (MSBI+1); +always @(*) DeltaAdder = DACin + DeltaB; +always @(*) SigmaAdder = DeltaAdder + SigmaLatch; + +always @(posedge CLK or posedge RESET) begin + if(RESET) begin + SigmaLatch <= 1'b1 << (MSBI+1); + DACout <= INV; + end else begin + SigmaLatch <= SigmaAdder; + DACout <= SigmaLatch[MSBI+2] ^ INV; + end +end + +endmodule diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/hq2x.sv b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/hq2x.sv new file mode 100644 index 00000000..f17732b6 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/hq2x.sv @@ -0,0 +1,454 @@ +// +// +// Copyright (c) 2012-2013 Ludvig Strigeus +// Copyright (c) 2017 Sorgelig +// +// This program is GPL Licensed. See COPYING for the full license. +// +// +//////////////////////////////////////////////////////////////////////////////////////////////////////// + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on + +`define BITS_TO_FIT(N) ( \ + N <= 2 ? 0 : \ + N <= 4 ? 1 : \ + N <= 8 ? 2 : \ + N <= 16 ? 3 : \ + N <= 32 ? 4 : \ + N <= 64 ? 5 : \ + N <= 128 ? 6 : \ + N <= 256 ? 7 : \ + N <= 512 ? 8 : \ + N <=1024 ? 9 : 10 ) + +module hq2x_in #(parameter LENGTH, parameter DWIDTH) +( + input clk, + + input [AWIDTH:0] rdaddr, + input rdbuf, + output[DWIDTH:0] q, + + input [AWIDTH:0] wraddr, + input wrbuf, + input [DWIDTH:0] data, + input wren +); + + localparam AWIDTH = `BITS_TO_FIT(LENGTH); + wire [DWIDTH:0] out[2]; + assign q = out[rdbuf]; + + hq2x_buf #(.NUMWORDS(LENGTH), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf0(clk,data,rdaddr,wraddr,wren && (wrbuf == 0),out[0]); + hq2x_buf #(.NUMWORDS(LENGTH), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf1(clk,data,rdaddr,wraddr,wren && (wrbuf == 1),out[1]); +endmodule + + +module hq2x_out #(parameter LENGTH, parameter DWIDTH) +( + input clk, + + input [AWIDTH:0] rdaddr, + input [1:0] rdbuf, + output[DWIDTH:0] q, + + input [AWIDTH:0] wraddr, + input [1:0] wrbuf, + input [DWIDTH:0] data, + input wren +); + + localparam AWIDTH = `BITS_TO_FIT(LENGTH*2); + wire [DWIDTH:0] out[4]; + assign q = out[rdbuf]; + + hq2x_buf #(.NUMWORDS(LENGTH*2), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf0(clk,data,rdaddr,wraddr,wren && (wrbuf == 0),out[0]); + hq2x_buf #(.NUMWORDS(LENGTH*2), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf1(clk,data,rdaddr,wraddr,wren && (wrbuf == 1),out[1]); + hq2x_buf #(.NUMWORDS(LENGTH*2), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf2(clk,data,rdaddr,wraddr,wren && (wrbuf == 2),out[2]); + hq2x_buf #(.NUMWORDS(LENGTH*2), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf3(clk,data,rdaddr,wraddr,wren && (wrbuf == 3),out[3]); +endmodule + + +module hq2x_buf #(parameter NUMWORDS, parameter AWIDTH, parameter DWIDTH) +( + input clock, + input [DWIDTH:0] data, + input [AWIDTH:0] rdaddress, + input [AWIDTH:0] wraddress, + input wren, + output [DWIDTH:0] q +); + + altsyncram altsyncram_component ( + .address_a (wraddress), + .clock0 (clock), + .data_a (data), + .wren_a (wren), + .address_b (rdaddress), + .q_b(q), + .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), + .data_b ({(DWIDTH+1){1'b1}}), + .eccstatus (), + .q_a (), + .rden_a (1'b1), + .rden_b (1'b1), + .wren_b (1'b0)); + defparam + altsyncram_component.address_aclr_b = "NONE", + 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_b = "BYPASS", + altsyncram_component.intended_device_family = "Cyclone III", + altsyncram_component.lpm_type = "altsyncram", + altsyncram_component.numwords_a = NUMWORDS, + altsyncram_component.numwords_b = NUMWORDS, + altsyncram_component.operation_mode = "DUAL_PORT", + altsyncram_component.outdata_aclr_b = "NONE", + altsyncram_component.outdata_reg_b = "UNREGISTERED", + altsyncram_component.power_up_uninitialized = "FALSE", + altsyncram_component.read_during_write_mode_mixed_ports = "DONT_CARE", + altsyncram_component.widthad_a = AWIDTH+1, + altsyncram_component.widthad_b = AWIDTH+1, + altsyncram_component.width_a = DWIDTH+1, + altsyncram_component.width_b = DWIDTH+1, + altsyncram_component.width_byteena_a = 1; + +endmodule + +//////////////////////////////////////////////////////////////////////////////////////////////////////// + +module DiffCheck +( + input [17:0] rgb1, + input [17:0] rgb2, + output result +); + + wire [5:0] r = rgb1[5:1] - rgb2[5:1]; + wire [5:0] g = rgb1[11:7] - rgb2[11:7]; + wire [5:0] b = rgb1[17:13] - rgb2[17:13]; + wire [6:0] t = $signed(r) + $signed(b); + wire [6:0] gx = {g[5], g}; + wire [7:0] y = $signed(t) + $signed(gx); + wire [6:0] u = $signed(r) - $signed(b); + wire [7:0] v = $signed({g, 1'b0}) - $signed(t); + + // if y is inside (-24..24) + wire y_inside = (y < 8'h18 || y >= 8'he8); + + // if u is inside (-4, 4) + wire u_inside = (u < 7'h4 || u >= 7'h7c); + + // if v is inside (-6, 6) + wire v_inside = (v < 8'h6 || v >= 8'hfA); + assign result = !(y_inside && u_inside && v_inside); +endmodule + +module InnerBlend +( + input [8:0] Op, + input [5:0] A, + input [5:0] B, + input [5:0] C, + output [5:0] O +); + + function [8:0] mul6x3; + input [5:0] op1; + input [2:0] op2; + begin + mul6x3 = 9'd0; + if(op2[0]) mul6x3 = mul6x3 + op1; + if(op2[1]) mul6x3 = mul6x3 + {op1, 1'b0}; + if(op2[2]) mul6x3 = mul6x3 + {op1, 2'b00}; + end + endfunction + + wire OpOnes = Op[4]; + wire [8:0] Amul = mul6x3(A, Op[7:5]); + wire [8:0] Bmul = mul6x3(B, {Op[3:2], 1'b0}); + wire [8:0] Cmul = mul6x3(C, {Op[1:0], 1'b0}); + wire [8:0] At = Amul; + wire [8:0] Bt = (OpOnes == 0) ? Bmul : {3'b0, B}; + wire [8:0] Ct = (OpOnes == 0) ? Cmul : {3'b0, C}; + wire [9:0] Res = {At, 1'b0} + Bt + Ct; + assign O = Op[8] ? A : Res[9:4]; +endmodule + +module Blend +( + input [5:0] rule, + input disable_hq2x, + input [17:0] E, + input [17:0] A, + input [17:0] B, + input [17:0] D, + input [17:0] F, + input [17:0] H, + output [17:0] Result +); + + reg [1:0] input_ctrl; + reg [8:0] op; + localparam BLEND0 = 9'b1_xxx_x_xx_xx; // 0: A + localparam BLEND1 = 9'b0_110_0_10_00; // 1: (A * 12 + B * 4) >> 4 + localparam BLEND2 = 9'b0_100_0_10_10; // 2: (A * 8 + B * 4 + C * 4) >> 4 + localparam BLEND3 = 9'b0_101_0_10_01; // 3: (A * 10 + B * 4 + C * 2) >> 4 + localparam BLEND4 = 9'b0_110_0_01_01; // 4: (A * 12 + B * 2 + C * 2) >> 4 + localparam BLEND5 = 9'b0_010_0_11_11; // 5: (A * 4 + (B + C) * 6) >> 4 + localparam BLEND6 = 9'b0_111_1_xx_xx; // 6: (A * 14 + B + C) >> 4 + localparam AB = 2'b00; + localparam AD = 2'b01; + localparam DB = 2'b10; + localparam BD = 2'b11; + wire is_diff; + DiffCheck diff_checker(rule[1] ? B : H, rule[0] ? D : F, is_diff); + + always @* begin + case({!is_diff, rule[5:2]}) + 1,17: {op, input_ctrl} = {BLEND1, AB}; + 2,18: {op, input_ctrl} = {BLEND1, DB}; + 3,19: {op, input_ctrl} = {BLEND1, BD}; + 4,20: {op, input_ctrl} = {BLEND2, DB}; + 5,21: {op, input_ctrl} = {BLEND2, AB}; + 6,22: {op, input_ctrl} = {BLEND2, AD}; + + 8: {op, input_ctrl} = {BLEND0, 2'bxx}; + 9: {op, input_ctrl} = {BLEND0, 2'bxx}; + 10: {op, input_ctrl} = {BLEND0, 2'bxx}; + 11: {op, input_ctrl} = {BLEND1, AB}; + 12: {op, input_ctrl} = {BLEND1, AB}; + 13: {op, input_ctrl} = {BLEND1, AB}; + 14: {op, input_ctrl} = {BLEND1, DB}; + 15: {op, input_ctrl} = {BLEND1, BD}; + + 24: {op, input_ctrl} = {BLEND2, DB}; + 25: {op, input_ctrl} = {BLEND5, DB}; + 26: {op, input_ctrl} = {BLEND6, DB}; + 27: {op, input_ctrl} = {BLEND2, DB}; + 28: {op, input_ctrl} = {BLEND4, DB}; + 29: {op, input_ctrl} = {BLEND5, DB}; + 30: {op, input_ctrl} = {BLEND3, BD}; + 31: {op, input_ctrl} = {BLEND3, DB}; + default: {op, input_ctrl} = 11'bx; + endcase + + // Setting op[8] effectively disables HQ2X because blend will always return E. + if (disable_hq2x) op[8] = 1; + end + + // Generate inputs to the inner blender. Valid combinations. + // 00: E A B + // 01: E A D + // 10: E D B + // 11: E B D + wire [17:0] Input1 = E; + wire [17:0] Input2 = !input_ctrl[1] ? A : + !input_ctrl[0] ? D : B; + + wire [17:0] Input3 = !input_ctrl[0] ? B : D; + InnerBlend inner_blend1(op, Input1[5:0], Input2[5:0], Input3[5:0], Result[5:0]); + InnerBlend inner_blend2(op, Input1[11:6], Input2[11:6], Input3[11:6], Result[11:6]); + InnerBlend inner_blend3(op, Input1[17:12], Input2[17:12], Input3[17:12], Result[17:12]); +endmodule + + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +module Hq2x #(parameter LENGTH, parameter HALF_DEPTH) +( + input clk, + input ce_x4, + input [DWIDTH:0] inputpixel, + input mono, + input disable_hq2x, + input reset_frame, + input reset_line, + input [1:0] read_y, + input [AWIDTH+1:0] read_x, + output [DWIDTH:0] outpixel +); + + +localparam AWIDTH = `BITS_TO_FIT(LENGTH); +localparam DWIDTH = HALF_DEPTH ? 8 : 17; + +wire [5:0] hqTable[256] = '{ + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 47, 35, 23, 15, 55, 39, + 19, 19, 26, 58, 19, 19, 26, 58, 23, 15, 35, 35, 23, 15, 7, 35, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 55, 39, 23, 15, 51, 43, + 19, 19, 26, 58, 19, 19, 26, 58, 23, 15, 51, 35, 23, 15, 7, 43, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 61, 35, 35, 23, 61, 51, 35, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 51, 35, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 61, 7, 35, 23, 61, 7, 43, + 19, 19, 26, 11, 19, 19, 26, 58, 23, 15, 51, 35, 23, 61, 7, 43, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 47, 35, 23, 15, 55, 39, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 51, 35, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 55, 39, 23, 15, 51, 43, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 39, 23, 15, 7, 43, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 51, 39, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 7, 35, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 7, 43, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 7, 35, 23, 15, 7, 43 +}; + +reg [17:0] Prev0, Prev1, Prev2, Curr0, Curr1, Next0, Next1, Next2; +reg [17:0] A, B, D, F, G, H; +reg [7:0] pattern, nextpatt; +reg [1:0] i; +reg [7:0] y; + +wire curbuf = y[0]; +reg prevbuf = 0; +wire iobuf = !curbuf; + +wire diff0, diff1; +DiffCheck diffcheck0(Curr1, (i == 0) ? Prev0 : (i == 1) ? Curr0 : (i == 2) ? Prev2 : Next1, diff0); +DiffCheck diffcheck1(Curr1, (i == 0) ? Prev1 : (i == 1) ? Next0 : (i == 2) ? Curr2 : Next2, diff1); + +wire [7:0] new_pattern = {diff1, diff0, pattern[7:2]}; + +wire [17:0] X = (i == 0) ? A : (i == 1) ? Prev1 : (i == 2) ? Next1 : G; +wire [17:0] blend_result; +Blend blender(hqTable[nextpatt], disable_hq2x, Curr0, X, B, D, F, H, blend_result); + +reg Curr2_addr1; +reg [AWIDTH:0] Curr2_addr2; +wire [17:0] Curr2 = HALF_DEPTH ? h2rgb(Curr2tmp) : Curr2tmp; +wire [DWIDTH:0] Curr2tmp; + +reg [AWIDTH:0] wrin_addr2; +reg [DWIDTH:0] wrpix; +reg wrin_en; + +function [17:0] h2rgb; + input [8:0] v; +begin + h2rgb = mono ? {v[5:3],v[2:0], v[5:3],v[2:0], v[5:3],v[2:0]} : {v[8:6],v[8:6],v[5:3],v[5:3],v[2:0],v[2:0]}; +end +endfunction + +function [8:0] rgb2h; + input [17:0] v; +begin + rgb2h = mono ? {3'b000, v[17:15], v[14:12]} : {v[17:15], v[11:9], v[5:3]}; +end +endfunction + +hq2x_in #(.LENGTH(LENGTH), .DWIDTH(DWIDTH)) hq2x_in +( + .clk(clk), + + .rdaddr(Curr2_addr2), + .rdbuf(Curr2_addr1), + .q(Curr2tmp), + + .wraddr(wrin_addr2), + .wrbuf(iobuf), + .data(wrpix), + .wren(wrin_en) +); + +reg [1:0] wrout_addr1; +reg [AWIDTH+1:0] wrout_addr2; +reg wrout_en; +reg [DWIDTH:0] wrdata; + +hq2x_out #(.LENGTH(LENGTH), .DWIDTH(DWIDTH)) hq2x_out +( + .clk(clk), + + .rdaddr(read_x), + .rdbuf(read_y), + .q(outpixel), + + .wraddr(wrout_addr2), + .wrbuf(wrout_addr1), + .data(wrdata), + .wren(wrout_en) +); + +always @(posedge clk) begin + reg [AWIDTH:0] offs; + reg old_reset_line; + reg old_reset_frame; + + wrout_en <= 0; + wrin_en <= 0; + + if(ce_x4) begin + + pattern <= new_pattern; + + if(~&offs) begin + if (i == 0) begin + Curr2_addr1 <= prevbuf; + Curr2_addr2 <= offs; + end + if (i == 1) begin + Prev2 <= Curr2; + Curr2_addr1 <= curbuf; + Curr2_addr2 <= offs; + end + if (i == 2) begin + Next2 <= HALF_DEPTH ? h2rgb(inputpixel) : inputpixel; + wrpix <= inputpixel; + wrin_addr2 <= offs; + wrin_en <= 1; + end + if (i == 3) begin + offs <= offs + 1'd1; + end + + if(HALF_DEPTH) wrdata <= rgb2h(blend_result); + else wrdata <= blend_result; + + wrout_addr1 <= {curbuf, i[1]}; + wrout_addr2 <= {offs, i[1]^i[0]}; + wrout_en <= 1; + end + + if(i==3) begin + nextpatt <= {new_pattern[7:6], new_pattern[3], new_pattern[5], new_pattern[2], new_pattern[4], new_pattern[1:0]}; + {A, G} <= {Prev0, Next0}; + {B, F, H, D} <= {Prev1, Curr2, Next1, Curr0}; + {Prev0, Prev1} <= {Prev1, Prev2}; + {Curr0, Curr1} <= {Curr1, Curr2}; + {Next0, Next1} <= {Next1, Next2}; + end else begin + nextpatt <= {nextpatt[5], nextpatt[3], nextpatt[0], nextpatt[6], nextpatt[1], nextpatt[7], nextpatt[4], nextpatt[2]}; + {B, F, H, D} <= {F, H, D, B}; + end + + i <= i + 1'b1; + if(old_reset_line && ~reset_line) begin + old_reset_frame <= reset_frame; + offs <= 0; + i <= 0; + y <= y + 1'd1; + prevbuf <= curbuf; + if(old_reset_frame & ~reset_frame) begin + y <= 0; + prevbuf <= 0; + end + end + + old_reset_line <= reset_line; + end +end + +endmodule // Hq2x diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/inputs.vhd b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/inputs.vhd new file mode 100644 index 00000000..98aefa4e --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/inputs.vhd @@ -0,0 +1,140 @@ +-- Input module for Kee Games Ultra Tank +-- 2017 James Sweet +-- +-- This 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 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. + +library IEEE; +use IEEE.STD_LOGIC_1164.all; + +entity control_inputs is +port( + clk6 : in std_logic; + DipSw : in std_logic_vector(7 downto 0); + Coin1_n : in std_logic; + Coin2_n : in std_logic; + Start1_n : in std_logic; + Start2_n : in std_logic; + Invisible_n : in std_logic; + Rebound_n : in std_logic; + Barrier_n : in std_logic; + JoyW_Fw : in std_logic; + JoyW_Bk : in std_logic; + JoyY_Fw : in std_logic; + JoyY_Bk : in std_logic; + JoyX_Fw : in std_logic; + JoyX_Bk : in std_logic; + JoyZ_Fw : in std_logic; + JoyZ_Bk : in std_logic; + FireA_n : in std_logic; + FireB_n : in std_logic; + Throttle_Read_n : in std_logic; + Coin_Read_n : in std_logic; + Options_Read_n : in std_logic; + Barrier_Read_n : in std_logic; + Wr_DA_Latch_n : in std_logic; + Adr : in std_logic_vector(2 downto 0); + DBus : in std_logic_vector(3 downto 0); + Dout : out std_logic_vector(7 downto 0) + ); +end control_inputs; + +architecture rtl of control_inputs is + + +signal Coin : std_logic := '1'; +signal Coin1 : std_logic := '0'; +signal Coin2 : std_logic := '0'; +signal Options : std_logic_vector(1 downto 0) := "11"; +signal Throttle : std_logic := '1'; +signal DA_latch : std_logic_vector(3 downto 0) := (others => '0'); +signal JoyW : std_logic; +signal JoyX : std_logic; +signal JoyY : std_logic; +signal JoyZ : std_logic; + + +begin + +-- Joysticks use a clever analog multiplexing in the real hardware in order to reduce the pins required +-- in the wiring harness to the board. For an FPGA this would require additional hardware and complexity +-- so this has been re-worked to provide individual active-low inputs + +--- E6 is a quad synchronous latch driving a 4 bit resistor DAC +E6: process(Clk6, Wr_DA_Latch_n, DBus) +begin + if falling_edge(Wr_DA_Latch_n) then + DA_latch <= (not DBus); + end if; +end process; + +-- Each joystick input goes to a comparator that compares it with a reference voltage coming from the DAC +-- Here we dispense with the DAC and use separate inputs for each of the two switches in each joystick +JoyW <= JoyW_Fw and (JoyW_Bk or DA_latch(0)); +JoyY <= JoyY_Fw and (JoyY_Bk or DA_latch(0)); +JoyX <= JoyX_Fw and (JoyX_Bk or DA_latch(1)); +JoyZ <= JoyZ_Fw and (JoyZ_Bk or DA_latch(1)); + +-- 9312 Data Selector/Multiplexer at K11 +K11: process(Adr, Start1_n, Start2_n, FireA_n, FireB_n, JoyW, JoyY, JoyX, JoyZ) +begin + case Adr(2 downto 0) is + when "000" => Throttle <= Start1_n; + when "001" => Throttle <= JoyW; + when "010" => Throttle <= Start2_n; + when "011" => Throttle <= JoyY; + when "100" => Throttle <= FireA_n; + when "101" => Throttle <= JoyX; + when "110" => Throttle <= FireB_n; + when "111" => Throttle <= JoyZ; + when others => Throttle <= '0'; + end case; +end process; + +-- 9312 Data Selector/Multiplexer at F10 +F10: process(Adr, Coin1_n, Coin2_n, Invisible_n, Rebound_n) +begin + case Adr(2 downto 0) is + when "000" => Coin <= (not Coin1_n); + when "001" => Coin <= '1'; + when "010" => Coin <= (not Coin2_n); + when "011" => Coin <= '1'; + when "100" => Coin <= (not Invisible_n); + when "101" => Coin <= '1'; + when "110" => Coin <= (not Rebound_n); + when "111" => Coin <= '1'; + when others => Coin <= '0'; + end case; +end process; + + +-- Configuration DIP switches +N9: process(Adr(1 downto 0), DipSw) +begin + case Adr(1 downto 0) is + when "00" => Options <= DipSw(0) & DipSw(1); + when "01" => Options <= DipSw(2) & DipSw(3); + when "10" => Options <= DipSw(4) & DipSw(5); + when "11" => Options <= DipSw(6) & DipSw(7); + when others => Options <= "11"; + end case; +end process; + + +-- Inputs data mux +Dout <= Throttle & "1111111" when Throttle_Read_n = '0' else + Coin & "1111111" when Coin_Read_n = '0' else + Barrier_n & "1111111" when Barrier_Read_n = '0' else + "111111" & Options when Options_Read_n = '0' else + x"FF"; + +end rtl; \ No newline at end of file diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/keyboard.sv b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/keyboard.sv new file mode 100644 index 00000000..ce182b0a --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/keyboard.sv @@ -0,0 +1,84 @@ + + +module keyboard +( + input clk, + input reset, + input ps2_kbd_clk, + input ps2_kbd_data, + + output reg[11:0] joystick +); + +reg [11:0] shift_reg = 12'hFFF; +wire[11:0] kdata = {ps2_kbd_data,shift_reg[11:1]}; +wire [7:0] kcode = kdata[9:2]; +reg release_btn = 0; + +reg [7:0] code; +reg input_strobe = 0; + +always @(negedge clk) begin + reg old_reset = 0; + + old_reset <= reset; + + if(~old_reset & reset)begin + joystick <= 0; + end + + if(input_strobe) begin + case(code) + 'h75: joystick[3] <= ~release_btn; // arrow up + 'h72: joystick[2] <= ~release_btn; // arrow down + 'h6B: joystick[1] <= ~release_btn; // arrow left + 'h74: joystick[0] <= ~release_btn; // arrow right + + 'h29: joystick[4] <= ~release_btn; // Space + 'h05: joystick[5] <= ~release_btn; // F1 + 'h06: joystick[6] <= ~release_btn; // F2 + 'h76: joystick[7] <= ~release_btn; // Escape + + 'h69: joystick[8] <= ~release_btn; // 1 + 'h72: joystick[9] <= ~release_btn; // 2 + 'h7A: joystick[10] <= ~release_btn; // 3 + 'h6B: joystick[11] <= ~release_btn; // 4 + endcase + end +end + +always @(posedge clk) begin + reg [3:0] prev_clk = 0; + reg old_reset = 0; + reg action = 0; + + old_reset <= reset; + input_strobe <= 0; + + if(~old_reset & reset)begin + prev_clk <= 0; + shift_reg <= 12'hFFF; + end else begin + prev_clk <= {ps2_kbd_clk,prev_clk[3:1]}; + if(prev_clk == 1) begin + if (kdata[11] & ^kdata[10:2] & ~kdata[1] & kdata[0]) begin + shift_reg <= 12'hFFF; + if (kcode == 8'he0) ; + // Extended key code follows + else if (kcode == 8'hf0) + // Release code follows + action <= 1; + else begin + // Cancel extended/release flags for next time + action <= 0; + release_btn <= action; + code <= kcode; + input_strobe <= 1; + end + end else begin + shift_reg <= kdata; + end + end + end +end +endmodule diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/mist_io.sv b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/mist_io.sv new file mode 100644 index 00000000..dcc7ecde --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/mist_io.sv @@ -0,0 +1,491 @@ +// +// mist_io.v +// +// mist_io for the MiST board +// http://code.google.com/p/mist-board/ +// +// Copyright (c) 2014 Till Harbaum +// +// 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 . +// +/////////////////////////////////////////////////////////////////////// + +// +// Use buffer to access SD card. It's time-critical part. +// Made module synchroneous with 2 clock domains: clk_sys and SPI_SCK +// (Sorgelig) +// +// for synchronous projects default value for PS2DIV is fine for any frequency of system clock. +// clk_ps2 = clk_sys/(PS2DIV*2) +// + +module mist_io #(parameter STRLEN=0, parameter PS2DIV=100) +( + + // parameter STRLEN and the actual length of conf_str have to match + input [(8*STRLEN)-1:0] conf_str, + + // Global clock. It should be around 100MHz (higher is better). + input clk_sys, + + // Global SPI clock from ARM. 24MHz + input SPI_SCK, + + input CONF_DATA0, + input SPI_SS2, + output SPI_DO, + input SPI_DI, + + output reg [7:0] joystick_0, + output reg [7:0] joystick_1, + output reg [15:0] joystick_analog_0, + output reg [15:0] joystick_analog_1, + output [1:0] buttons, + output [1:0] switches, + output scandoubler_disable, + output ypbpr, + + output reg [31:0] status, + + // SD config + input sd_conf, + input sd_sdhc, + output img_mounted, // signaling that new image has been mounted + output reg [31:0] img_size, // size of image in bytes + + // SD block level access + input [31:0] sd_lba, + input sd_rd, + input sd_wr, + output reg sd_ack, + output reg sd_ack_conf, + + // SD byte level access. Signals for 2-PORT altsyncram. + output reg [8:0] sd_buff_addr, + output reg [7:0] sd_buff_dout, + input [7:0] sd_buff_din, + output reg sd_buff_wr, + + // ps2 keyboard emulation + output ps2_kbd_clk, + output reg ps2_kbd_data, + output ps2_mouse_clk, + output reg ps2_mouse_data, + input ps2_caps_led, + + // ARM -> FPGA download + output reg ioctl_download = 0, // signal indicating an active download + output reg [7:0] ioctl_index, // menu index used to upload the file + output ioctl_wr, + output reg [23:0] ioctl_addr, + output reg [7:0] ioctl_dout +); + +reg [7:0] b_data; +reg [6:0] sbuf; +reg [7:0] cmd; +reg [2:0] bit_cnt; // counts bits 0-7 0-7 ... +reg [9:0] byte_cnt; // counts bytes +reg [7:0] but_sw; +reg [2:0] stick_idx; + +reg mount_strobe = 0; +assign img_mounted = mount_strobe; + +assign buttons = but_sw[1:0]; +assign switches = but_sw[3:2]; +assign scandoubler_disable = but_sw[4]; +assign ypbpr = but_sw[5]; + +wire [7:0] spi_dout = { sbuf, SPI_DI}; + +// this variant of user_io is for 8 bit cores (type == a4) only +wire [7:0] core_type = 8'ha4; + +// command byte read by the io controller +wire [7:0] sd_cmd = { 4'h5, sd_conf, sd_sdhc, sd_wr, sd_rd }; + +reg spi_do; +assign SPI_DO = CONF_DATA0 ? 1'bZ : spi_do; + +wire [7:0] kbd_led = { 2'b01, 4'b0000, ps2_caps_led, 1'b1}; + +// drive MISO only when transmitting core id +always@(negedge SPI_SCK) begin + if(!CONF_DATA0) begin + // first byte returned is always core type, further bytes are + // command dependent + if(byte_cnt == 0) begin + spi_do <= core_type[~bit_cnt]; + + end else begin + case(cmd) + // reading config string + 8'h14: begin + // returning a byte from string + if(byte_cnt < STRLEN + 1) spi_do <= conf_str[{STRLEN - byte_cnt,~bit_cnt}]; + else spi_do <= 0; + end + + // reading sd card status + 8'h16: begin + if(byte_cnt == 1) spi_do <= sd_cmd[~bit_cnt]; + else if((byte_cnt >= 2) && (byte_cnt < 6)) spi_do <= sd_lba[{5-byte_cnt, ~bit_cnt}]; + else spi_do <= 0; + end + + // reading sd card write data + 8'h18: + spi_do <= b_data[~bit_cnt]; + + // reading keyboard LED status + 8'h1f: + spi_do <= kbd_led[~bit_cnt]; + + default: + spi_do <= 0; + endcase + end + end +end + +reg b_wr2,b_wr3; +always @(negedge clk_sys) begin + b_wr3 <= b_wr2; + sd_buff_wr <= b_wr3; +end + +// SPI receiver +always@(posedge SPI_SCK or posedge CONF_DATA0) begin + + if(CONF_DATA0) begin + b_wr2 <= 0; + bit_cnt <= 0; + byte_cnt <= 0; + sd_ack <= 0; + sd_ack_conf <= 0; + end else begin + b_wr2 <= 0; + + sbuf <= spi_dout[6:0]; + bit_cnt <= bit_cnt + 1'd1; + if(bit_cnt == 5) begin + if (byte_cnt == 0) sd_buff_addr <= 0; + if((byte_cnt != 0) & (sd_buff_addr != 511)) sd_buff_addr <= sd_buff_addr + 1'b1; + if((byte_cnt == 1) & ((cmd == 8'h17) | (cmd == 8'h19))) sd_buff_addr <= 0; + end + + // finished reading command byte + if(bit_cnt == 7) begin + if(~&byte_cnt) byte_cnt <= byte_cnt + 8'd1; + if(byte_cnt == 0) begin + cmd <= spi_dout; + + if(spi_dout == 8'h19) begin + sd_ack_conf <= 1; + sd_buff_addr <= 0; + end + if((spi_dout == 8'h17) || (spi_dout == 8'h18)) begin + sd_ack <= 1; + sd_buff_addr <= 0; + end + if(spi_dout == 8'h18) b_data <= sd_buff_din; + + mount_strobe <= 0; + + end else begin + + case(cmd) + // buttons and switches + 8'h01: but_sw <= spi_dout; + 8'h02: joystick_0 <= spi_dout; + 8'h03: joystick_1 <= spi_dout; + + // store incoming ps2 mouse bytes + 8'h04: begin + ps2_mouse_fifo[ps2_mouse_wptr] <= spi_dout; + ps2_mouse_wptr <= ps2_mouse_wptr + 1'd1; + end + + // store incoming ps2 keyboard bytes + 8'h05: begin + ps2_kbd_fifo[ps2_kbd_wptr] <= spi_dout; + ps2_kbd_wptr <= ps2_kbd_wptr + 1'd1; + end + + 8'h15: status[7:0] <= spi_dout; + + // send SD config IO -> FPGA + // flag that download begins + // sd card knows data is config if sd_dout_strobe is asserted + // with sd_ack still being inactive (low) + 8'h19, + // send sector IO -> FPGA + // flag that download begins + 8'h17: begin + sd_buff_dout <= spi_dout; + b_wr2 <= 1; + end + + 8'h18: b_data <= sd_buff_din; + + // joystick analog + 8'h1a: begin + // first byte is joystick index + if(byte_cnt == 1) stick_idx <= spi_dout[2:0]; + else if(byte_cnt == 2) begin + // second byte is x axis + if(stick_idx == 0) joystick_analog_0[15:8] <= spi_dout; + else if(stick_idx == 1) joystick_analog_1[15:8] <= spi_dout; + end else if(byte_cnt == 3) begin + // third byte is y axis + if(stick_idx == 0) joystick_analog_0[7:0] <= spi_dout; + else if(stick_idx == 1) joystick_analog_1[7:0] <= spi_dout; + end + end + + // notify image selection + 8'h1c: mount_strobe <= 1; + + // send image info + 8'h1d: if(byte_cnt<5) img_size[(byte_cnt-1)<<3 +:8] <= spi_dout; + + // status, 32bit version + 8'h1e: if(byte_cnt<5) status[(byte_cnt-1)<<3 +:8] <= spi_dout; + default: ; + endcase + end + end + end +end + + +/////////////////////////////// PS2 /////////////////////////////// +// 8 byte fifos to store ps2 bytes +localparam PS2_FIFO_BITS = 3; + +reg clk_ps2; +always @(negedge clk_sys) begin + integer cnt; + cnt <= cnt + 1'd1; + if(cnt == PS2DIV) begin + clk_ps2 <= ~clk_ps2; + cnt <= 0; + end +end + +// keyboard +reg [7:0] ps2_kbd_fifo[1<= 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; // stop bit is 1 + + // advance state machine + if(ps2_kbd_tx_state < 11) ps2_kbd_tx_state <= ps2_kbd_tx_state + 1'd1; + else ps2_kbd_tx_state <= 0; + end + end +end + +// mouse +reg [7:0] ps2_mouse_fifo[1<= 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; // stop bit is 1 + + // advance state machine + if(ps2_mouse_tx_state < 11) ps2_mouse_tx_state <= ps2_mouse_tx_state + 1'd1; + else ps2_mouse_tx_state <= 0; + end + end +end + + +/////////////////////////////// DOWNLOADING /////////////////////////////// + +reg [7:0] data_w; +reg [23:0] addr_w; +reg rclk = 0; + +localparam UIO_FILE_TX = 8'h53; +localparam UIO_FILE_TX_DAT = 8'h54; +localparam UIO_FILE_INDEX = 8'h55; + +// data_io has its own SPI interface to the io controller +always@(posedge SPI_SCK, posedge SPI_SS2) begin + reg [6:0] sbuf; + reg [7:0] cmd; + reg [4:0] cnt; + reg [23:0] addr; + + if(SPI_SS2) cnt <= 0; + else begin + rclk <= 0; + + // don't shift in last bit. It is evaluated directly + // when writing to ram + if(cnt != 15) sbuf <= { sbuf[5:0], SPI_DI}; + + // increase target address after write + if(rclk) addr <= addr + 1'd1; + + // count 0-7 8-15 8-15 ... + if(cnt < 15) cnt <= cnt + 1'd1; + else cnt <= 8; + + // finished command byte + if(cnt == 7) cmd <= {sbuf, SPI_DI}; + + // prepare/end transmission + if((cmd == UIO_FILE_TX) && (cnt == 15)) begin + // prepare + if(SPI_DI) begin + addr <= 0; + ioctl_download <= 1; + end else begin + addr_w <= addr; + ioctl_download <= 0; + end + end + + // command 0x54: UIO_FILE_TX + if((cmd == UIO_FILE_TX_DAT) && (cnt == 15)) begin + addr_w <= addr; + data_w <= {sbuf, SPI_DI}; + rclk <= 1; + end + + // expose file (menu) index + if((cmd == UIO_FILE_INDEX) && (cnt == 15)) ioctl_index <= {sbuf, SPI_DI}; + end +end + +assign ioctl_wr = |ioctl_wrd; +reg [1:0] ioctl_wrd; + +always@(negedge clk_sys) begin + reg rclkD, rclkD2; + + rclkD <= rclk; + rclkD2 <= rclkD; + ioctl_wrd<= {ioctl_wrd[0],1'b0}; + + if(rclkD & ~rclkD2) begin + ioctl_dout <= data_w; + ioctl_addr <= addr_w; + ioctl_wrd <= 2'b11; + end +end + +endmodule diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/motion.vhd b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/motion.vhd new file mode 100644 index 00000000..80ceb836 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/motion.vhd @@ -0,0 +1,330 @@ +-- Motion object generation circuitry for Kee Games Ultra Tank +-- This generates the four motion objects in the game consisting +-- of two tanks and two shells +-- (c) 2017 James Sweet +-- +-- This 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 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. + +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use IEEE.STD_LOGIC_UNSIGNED.all; + +entity motion is +port( + CLK6 : in std_logic; -- 6MHz* on schematic + PHI2 : in std_logic; + DMA_n : in std_logic_vector(7 downto 0); + PRAM : in std_logic_vector(7 downto 0); + H256_s : in std_logic; -- 256H* on schematic + VCount : in std_logic_vector(7 downto 0); + HCount : in std_logic_vector(8 downto 0); + Load_n : buffer std_logic_vector(8 downto 1); + Object : out std_logic_vector(4 downto 1); + Object_n : out std_logic_vector(4 downto 1) + ); +end motion; + +architecture rtl of motion is + +signal phi1 : std_logic; + +signal H256_n : std_logic; +signal H64 : std_logic; +signal H32 : std_logic; +signal H16 : std_logic; +signal H8 : std_logic; + +signal P6_R5sum : std_logic_vector(7 downto 0); +signal Match_n : std_logic := '1'; +signal R6_8 : std_logic := '1'; + +signal P7_in : std_logic_vector(3 downto 0) := (others => '0'); +signal P7_out : std_logic_vector(9 downto 0) := (others => '1'); +signal R4_in : std_logic_vector(3 downto 0) := (others => '0'); +signal R4_out : std_logic_vector(9 downto 0) := (others => '1'); + +signal Object1_Hpos : std_logic_vector(7 downto 0) := (others => '0'); +signal Object2_Hpos : std_logic_vector(7 downto 0) := (others => '0'); +signal Object3_Hpos : std_logic_vector(7 downto 0) := (others => '0'); +signal Object4_Hpos : std_logic_vector(7 downto 0) := (others => '0'); + +signal Object1_reg : std_logic_vector(15 downto 0) := (others => '0'); +signal Object2_reg : std_logic_vector(15 downto 0) := (others => '0'); +signal Object3_reg : std_logic_vector(15 downto 0) := (others => '0'); +signal Object4_reg : std_logic_vector(15 downto 0) := (others => '0'); + +signal Object1_Inh : std_logic := '1'; +signal Object2_Inh : std_logic := '1'; +signal Object3_Inh : std_logic := '1'; +signal Object4_Inh : std_logic := '1'; + +signal Vid : std_logic_vector(15 downto 1) := (others => '0'); + + +begin +phi1 <= (not phi2); + +H8 <= Hcount(3); +H16 <= Hcount(4); +H32 <= Hcount(5); +H64 <= Hcount(6); +H256_n <= not(Hcount(8)); + +-- Vertical line comparator +P6_R5sum <= DMA_n + VCount; + +-- Motion object PROMs +N6: entity work.sprom +generic map( + init_file => "rtl/roms/30174-01n6.hex", + widthad_a => 10, + width_a => 4) +port map( + clock => clk6, + address => PRAM(2) & PRAM(7 downto 3) & P6_R5sum(3 downto 0), + q => Vid(4 downto 1) + ); + +--N6: entity work.n6_prom +--port map( +-- clock => clk6, +-- address => PRAM(2) & PRAM(7 downto 3) & P6_R5sum(3 downto 0), +-- q => Vid(4 downto 1) +-- ); + +M6: entity work.sprom +generic map( + init_file => "rtl/roms/30175-01m6.hex", + widthad_a => 10, + width_a => 4) +port map( + clock => clk6, + address => PRAM(2) & PRAM(7 downto 3) & P6_R5sum(3 downto 0), + q => Vid(8 downto 5) + ); + +--M6: entity work.m6_prom +--port map( +-- clock => clk6, +-- address => PRAM(2) & PRAM(7 downto 3) & P6_R5sum(3 downto 0), +-- q => Vid(8 downto 5) +-- ); + +L6: entity work.sprom +generic map( + init_file => "rtl/roms/30176-01l6.hex", + widthad_a => 10, + width_a => 4) +port map( + clock => clk6, + address => PRAM(2) & PRAM(7 downto 3) & P6_R5sum(3 downto 0), + q => Vid(12 downto 9) + ); + +--L6: entity work.l6_prom +--port map( +-- clock => clk6, +-- address => PRAM(2) & PRAM(7 downto 3) & P6_R5sum(3 downto 0), +-- q => Vid(12 downto 9) +-- ); + +K6: entity work.sprom +generic map( + init_file => "rtl/roms/30177-01k6.hex", + widthad_a => 10, + width_a => 4) +port map( + clock => clk6, + address => PRAM(2) & PRAM(7 downto 3) & P6_R5sum(3 downto 0), + q(2 downto 0) => Vid(15 downto 13) + ); + +--K6: entity work.k6_prom +--port map( +-- clock => clk6, +-- address => PRAM(2) & PRAM(7 downto 3) & P6_R5sum(3 downto 0), +-- q(2 downto 0) => Vid(15 downto 13) +-- ); + +-- Some glue logic +Match_n <= not(P6_R5sum(7) and P6_R5sum(6) and P6_R5sum(5) and P6_R5sum(4)); +R6_8 <= not(H256_n and H8 and Phi1 and (H64 nand Match_n)); + + +R4_in <= R6_8 & H64 & H32 & H16; +R4: process(R4_in) +begin + case R4_in is + when "0000" => + R4_out <= "1111111110"; + when "0001" => + R4_out <= "1111111101"; + when "0010" => + R4_out <= "1111111011"; + when "0011" => + R4_out <= "1111110111"; + when "0100" => + R4_out <= "1111101111"; + when "0101" => + R4_out <= "1111011111"; + when "0110" => + R4_out <= "1110111111"; + when "0111" => + R4_out <= "1101111111"; + when others => + R4_out <= "1111111111"; + end case; +end process; +Load_n(8) <= R4_out(7); +Load_n(7) <= R4_out(6); +Load_n(6) <= R4_out(5); +Load_n(5) <= R4_out(4); +Load_n(4) <= R4_out(3); +Load_n(3) <= R4_out(2); +Load_n(2) <= R4_out(1); +Load_n(1) <= R4_out(0); + + +-- Object 1 Horizontal position counter +-- This combines two 74163s at locations P5 and P6 on the PCB +P5_4: process(clk6, H256_s, Load_n, DMA_n) +begin + if rising_edge(clk6) then + if Load_n(1) = '0' then -- preload the counter + Object1_Hpos <= DMA_n; + elsif H256_s = '1' then -- increment the counter + Object1_Hpos <= Object1_Hpos + '1'; + end if; + if Object1_Hpos(7 downto 4) = "1111" then + Object1_Inh <= '0'; + else + Object1_Inh <= '1'; + end if; + end if; +end process; + +-- Object 1 video shift register +-- This combines two 74165s at locations N7 and N8 on the PCB +N7_8: process(clk6, Object1_Inh, Load_n, Vid) +begin + if Load_n(5) = '0' then + Object1_reg <= Vid & '0'; -- Preload the register + elsif rising_edge(clk6) then + if Object1_Inh = '0' then + Object1_reg <= '0' & Object1_reg(15 downto 1); + end if; + end if; +end process; +Object(1) <= Object1_reg(0); +Object_n(1) <= (not Object1_reg(0)); + + +-- Object 2 Horizontal position counter +-- This combines two 74LS163s at locations P5 and P6 on the PCB +P5_6: process(clk6, H256_s, Load_n, DMA_n) +begin + if rising_edge(clk6) then + if Load_n(2) = '0' then -- preload the counter + Object2_Hpos <= DMA_n; + elsif H256_s = '1' then -- increment the counter + Object2_Hpos <= Object2_Hpos + '1'; + end if; + if Object2_Hpos(7 downto 4) = "1111" then + Object2_Inh <= '0'; + else + Object2_Inh <= '1'; + end if; + end if; +end process; + +-- Object 2 video shift register +M7_8: process(clk6, Load_n, Vid) +begin + if Load_n(6) = '0' then + Object2_reg <= Vid & '0'; -- Preload the register + elsif rising_edge(clk6) then + if Object2_Inh = '0' then + Object2_reg <= '0' & Object2_reg(15 downto 1); + end if; + end if; +end process; +Object(2) <= Object2_reg(0); +Object_n(2) <= (not Object2_reg(0)); + + +-- Object 3 Horizontal position counter +-- This combines two 74LS163s at locations M5 and M4 on the PCB +M5_4: process(clk6, H256_s, Load_n, DMA_n) +begin + if rising_edge(clk6) then + if Load_n(3) = '0' then -- preload the counter + Object3_Hpos <= DMA_n; + elsif H256_s = '1' then -- increment the counter + Object3_Hpos <= Object3_Hpos + '1'; + end if; + if Object3_Hpos(7 downto 4) = "1111" then + Object3_Inh <= '0'; + else + Object3_Inh <= '1'; + end if; + end if; +end process; + +-- Object 3 video shift register +L7_8: process(clk6, Object3_Inh, Load_n, Vid) +begin + if Load_n(7) = '0' then + Object3_reg <= Vid & '0'; -- Preload the register + elsif rising_edge(clk6) then + if Object3_Inh = '0' then + Object3_reg <= '0' & Object3_reg(15 downto 1); + end if; + end if; +end process; +Object(3) <= Object3_reg(0); +Object_n(3) <= (not Object3_reg(0)); + + +-- Object 4 Horizontal position counter +-- This combines two 74LS163s at locations L5 and L4on the PCB +L5_4: process(clk6, H256_s, Load_n, DMA_n) +begin + if rising_edge(clk6) then + if Load_n(4) = '0' then -- preload the counter + Object4_Hpos <= DMA_n; + elsif H256_s = '1' then -- increment the counter + Object4_Hpos <= Object4_Hpos + '1'; + end if; + if Object4_Hpos(7 downto 4) = "1111" then + Object4_Inh <= '0'; + else + Object4_Inh <= '1'; + end if; + end if; +end process; + +-- Object 4 video shift register +K7_8: process(clk6, Object4_Inh, Load_n, Vid) +begin + if Load_n(8) = '0' then + Object4_reg <= Vid & '0'; -- Preload the register + elsif rising_edge(clk6) then + if Object4_Inh = '0' then + Object4_reg <= '0' & Object4_reg(15 downto 1); + end if; + end if; +end process; +Object(4) <= Object4_reg(0); +Object_n(4) <= (not Object4_reg(0)); + +end rtl; diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/osd.sv b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/osd.sv new file mode 100644 index 00000000..c62c10af --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/osd.sv @@ -0,0 +1,179 @@ +// A simple OSD implementation. Can be hooked up between a cores +// VGA output and the physical VGA pins + +module osd ( + // OSDs pixel clock, should be synchronous to cores pixel clock to + // avoid jitter. + input clk_sys, + + // SPI interface + input SPI_SCK, + input SPI_SS3, + input SPI_DI, + + // VGA signals coming from core + input [5:0] R_in, + input [5:0] G_in, + input [5:0] B_in, + input HSync, + input VSync, + + // VGA signals going to video connector + output [5:0] R_out, + output [5:0] G_out, + output [5:0] B_out +); + +parameter OSD_X_OFFSET = 10'd0; +parameter OSD_Y_OFFSET = 10'd0; +parameter OSD_COLOR = 3'd0; + +localparam OSD_WIDTH = 10'd256; +localparam OSD_HEIGHT = 10'd128; + +// ********************************************************************************* +// spi client +// ********************************************************************************* + +// this core supports only the display related OSD commands +// of the minimig +reg osd_enable; +(* ramstyle = "no_rw_check" *) reg [7:0] osd_buffer[2047:0]; // the OSD buffer itself + +// the OSD has its own SPI interface to the io controller +always@(posedge SPI_SCK, posedge SPI_SS3) begin + reg [4:0] cnt; + reg [10:0] bcnt; + reg [7:0] sbuf; + reg [7:0] cmd; + + if(SPI_SS3) begin + cnt <= 0; + bcnt <= 0; + end else begin + sbuf <= {sbuf[6:0], SPI_DI}; + + // 0:7 is command, rest payload + if(cnt < 15) cnt <= cnt + 1'd1; + else cnt <= 8; + + if(cnt == 7) begin + cmd <= {sbuf[6:0], SPI_DI}; + + // lower three command bits are line address + bcnt <= {sbuf[1:0], SPI_DI, 8'h00}; + + // command 0x40: OSDCMDENABLE, OSDCMDDISABLE + if(sbuf[6:3] == 4'b0100) osd_enable <= SPI_DI; + end + + // command 0x20: OSDCMDWRITE + if((cmd[7:3] == 5'b00100) && (cnt == 15)) begin + osd_buffer[bcnt] <= {sbuf[6:0], SPI_DI}; + bcnt <= bcnt + 1'd1; + end + end +end + +// ********************************************************************************* +// video timing and sync polarity anaylsis +// ********************************************************************************* + +// horizontal counter +reg [9:0] h_cnt; +reg [9:0] hs_low, hs_high; +wire hs_pol = hs_high < hs_low; +wire [9:0] dsp_width = hs_pol ? hs_low : hs_high; + +// vertical counter +reg [9:0] v_cnt; +reg [9:0] vs_low, vs_high; +wire vs_pol = vs_high < vs_low; +wire [9:0] dsp_height = vs_pol ? vs_low : vs_high; + +wire doublescan = (dsp_height>350); + +reg ce_pix; +always @(negedge clk_sys) begin + integer cnt = 0; + integer pixsz, pixcnt; + reg hs; + + cnt <= cnt + 1; + hs <= HSync; + + pixcnt <= pixcnt + 1; + if(pixcnt == pixsz) pixcnt <= 0; + ce_pix <= !pixcnt; + + if(hs && ~HSync) begin + cnt <= 0; + pixsz <= (cnt >> 9) - 1; + pixcnt <= 0; + ce_pix <= 1; + end +end + +always @(posedge clk_sys) begin + reg hsD, hsD2; + reg vsD, vsD2; + + if(ce_pix) begin + // bring hsync into local clock domain + hsD <= HSync; + hsD2 <= hsD; + + // falling edge of HSync + if(!hsD && hsD2) begin + h_cnt <= 0; + hs_high <= h_cnt; + end + + // rising edge of HSync + else if(hsD && !hsD2) begin + h_cnt <= 0; + hs_low <= h_cnt; + v_cnt <= v_cnt + 1'd1; + end else begin + h_cnt <= h_cnt + 1'd1; + end + + vsD <= VSync; + vsD2 <= vsD; + + // falling edge of VSync + if(!vsD && vsD2) begin + v_cnt <= 0; + vs_high <= v_cnt; + end + + // rising edge of VSync + else if(vsD && !vsD2) begin + v_cnt <= 0; + vs_low <= v_cnt; + end + end +end + +// area in which OSD is being displayed +wire [9:0] h_osd_start = ((dsp_width - OSD_WIDTH)>> 1) + OSD_X_OFFSET; +wire [9:0] h_osd_end = h_osd_start + OSD_WIDTH; +wire [9:0] v_osd_start = ((dsp_height- (OSD_HEIGHT<> 1) + OSD_Y_OFFSET; +wire [9:0] v_osd_end = v_osd_start + (OSD_HEIGHT<= h_osd_start) && (h_cnt < h_osd_end) && + (VSync != vs_pol) && (v_cnt >= v_osd_start) && (v_cnt < v_osd_end); + +reg [7:0] osd_byte; +always @(posedge clk_sys) if(ce_pix) osd_byte <= osd_buffer[{doublescan ? osd_vcnt[7:5] : osd_vcnt[6:4], osd_hcnt[7:0]}]; + +wire osd_pixel = osd_byte[doublescan ? osd_vcnt[4:2] : osd_vcnt[3:1]]; + +assign R_out = !osd_de ? R_in : {osd_pixel, osd_pixel, OSD_COLOR[2], R_in[5:3]}; +assign G_out = !osd_de ? G_in : {osd_pixel, osd_pixel, OSD_COLOR[1], G_in[5:3]}; +assign B_out = !osd_de ? B_in : {osd_pixel, osd_pixel, OSD_COLOR[0], B_in[5:3]}; + +endmodule diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/playfield.vhd b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/playfield.vhd new file mode 100644 index 00000000..8fbfff26 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/playfield.vhd @@ -0,0 +1,265 @@ +-- Playfield generation and video mixing circuitry for Kee Games Ultra Tank +-- (c) 2017 James Sweet +-- +-- This 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 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. + +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use IEEE.STD_LOGIC_ARITH.all; +use IEEE.STD_LOGIC_UNSIGNED.all; + +entity playfield is +port( + Clk6 : in std_logic; + DMA : in std_logic_vector(7 downto 0); + PRAM : in std_logic_vector(7 downto 0); + Load_n : in std_logic_vector(8 downto 1); + Object : in std_logic_vector(4 downto 1); + HCount : in std_logic_vector(8 downto 0); + VCount : in std_logic_vector(7 downto 0); + HBlank : in std_logic; + VBlank : in std_logic; + VBlank_n_s : in std_logic; -- VBLANK* on the schematic + HSync : in std_logic; + VSync : in std_logic; + H256_s : out std_logic; + CC3_n : out std_logic; + CC2 : out std_logic; + CC1 : out std_logic; + CC0 : out std_logic; + CompBlank : buffer std_logic; + CompSync_n : out std_logic; + Playfield_n : out std_logic; + White : out std_logic; + PF_Vid1 : out std_logic; + PF_Vid2 : out std_logic + ); +end playfield; + +architecture rtl of playfield is + +signal H1 : std_logic; +signal H2 : std_logic; +signal H4 : std_logic; +signal H256 : std_logic; +signal H256_n : std_logic; + +signal V1 : std_logic; +signal V2 : std_logic; +signal V4 : std_logic; + +signal char_addr : std_logic_vector(8 downto 0) := (others => '0'); +signal char_data : std_logic_vector(7 downto 0) := (others => '0'); +signal shift_data : std_logic_vector(7 downto 0) := (others => '0'); +signal QH : std_logic := '0'; +signal H8_reg : std_logic_vector(3 downto 0) := (others => '0'); +signal H9_in : std_logic_vector(3 downto 0) := (others => '0'); +signal H9_out : std_logic_vector(9 downto 0) := (others => '0'); +signal H10_Q : std_logic_vector(7 downto 0) := (others => '0'); +signal Numeral_n : std_logic; +signal Color0 : std_logic; +signal Color1 : std_logic; +signal J10_addr : std_logic_vector(4 downto 0) := (others => '0'); +signal J10_Q : std_logic_vector(7 downto 0) := (others => '0'); +signal Obj_bus : std_logic_vector(4 downto 1) := (others => '0'); +signal CharLoad_n : std_logic := '1'; +signal K9 : std_logic_vector(4 downto 1) := (others => '0'); + +-- These signals are based off the schematic and are formatted as Designator_PinNumber +-- they really ought to have more descriptive names +signal R3_3 : std_logic; +signal P2_13 : std_logic; +signal P3_6 : std_logic; +signal A6_6 : std_logic; +signal A6_3 : std_logic; + + +begin + +-- Video synchronization signals +H1 <= Hcount(0); +H2 <= Hcount(1); +H4 <= Hcount(2); +H256 <= Hcount(8); +H256_n <= not(Hcount(8)); + +V1 <= Vcount(0); +V2 <= Vcount(1); +V4 <= Vcount(2); + +-- Some glue logic, may be re-written later to be cleaner and easier to follow without referring to schematic +CharLoad_n <= not(H1 and H2 and H4); +R3_3 <= (H256_n or CharLoad_n); +Char_Addr <= DMA(5 downto 0) & V4 & V2 & V1; + + +-- Background character ROMs +H6: entity work.sprom +generic map( + init_file => "rtl/roms/30173-01h6.hex", + widthad_a => 9, + width_a => 4) +port map( + clock => clk6, + Address => char_addr, + q => char_data(3 downto 0) + ); + +--H6: entity work.Char_MSB +--port map( +-- clock => clk6, +-- Address => char_addr, +-- q => char_data(3 downto 0) +-- ); + +J6: entity work.sprom +generic map( + init_file => "rtl/roms/30172-01j6.hex", + widthad_a => 9, + width_a => 4) +port map( + clock => clk6, + Address => char_addr, + q => char_data(7 downto 4) + ); + +--J6: entity work.Char_LSB +--port map( +-- clock => clk6, +-- Address => char_addr, +-- q => char_data(7 downto 4) +-- ); + + +-- 74LS166 video shift register +R3: process(clk6, R3_3, VBlank_n_s, char_data, shift_data) +begin + if VBlank_n_s = '0' then -- Connected Clear input + shift_data <= (others => '0'); + elsif rising_edge(clk6) then + if R3_3 = '0' then -- Parallel load + shift_data <= char_data(7 downto 0); + else + shift_data <= shift_data(6 downto 0) & '0'; + end if; + end if; + QH <= shift_data(7); +end process; + + +-- 9316 counter at H8 +-- CEP and CET tied to ground, counter is used only as a synchronous latch +H8: process(clk6, CharLoad_n, DMA, H256) +begin + if rising_edge(clk6) then + if CharLoad_n = '0' then + H8_reg <= (((not DMA(5)) or (not DMA(7))) & ((not DMA(5)) or (not DMA(6))) & (not DMA(5)) & H256); -- A bit hard to follow, see schematic + end if; + end if; +end process; + +Color0 <= H8_reg(3); +Color1 <= H8_reg(2); +Numeral_n <= H8_reg(1); +H256_s <= H8_reg(0); + +Playfield_n <= (not QH); + +H9_in <= (not QH) & Numeral_n & Color1 & Color0; + +H9: process(H9_in) +begin + case H9_in is + when "0000" => + H9_out <= "1111111110"; + when "0001" => + H9_out <= "1111111101"; + when "0010" => + H9_out <= "1111111011"; + when "0011" => + H9_out <= "1111110111"; + when "0111" => + H9_out <= "1101111111"; + when others => + H9_out <= "1111111111"; + end case; +end process; + + +LK9_10: process(Load_n, PRAM) +begin + if rising_edge(Load_n(1)) then + Obj_bus(1) <= (not PRAM(7)); + end if; + + if rising_edge(Load_n(2)) then + Obj_bus(2) <= (not PRAM(7)); + end if; + + if rising_edge(Load_n(3)) then + Obj_bus(3) <= (not PRAM(7)); + end if; + + if rising_edge(Load_n(4)) then + Obj_bus(4) <= (not PRAM(7)); + end if; +end process; + +K9(4) <= Obj_bus(4) nand Object(4); +K9(3) <= Obj_bus(3) nand Object(3); +K9(2) <= Obj_bus(2) nand Object(2); +K9(1) <= Obj_bus(1) nand Object(1); + +J10_addr <= (not H9_out(7)) & (K9(1) nand H9_out(0)) & (K9(2) nand H9_out(1)) & (K9(3) nand H9_out(2)) & (K9(4) nand H9_out(3)); + +J10: entity work.sprom +generic map( + init_file => "rtl/roms/30218-01j10.hex", + widthad_a => 5, + width_a => 8) +port map( + clock => clk6, + address => J10_addr, + q => J10_Q + ); + +--J10: entity work.J10_PROM +--port map( +-- clock => clk6, +-- address => J10_addr, +-- q => J10_Q +-- ); + +-- 74LS273 octal flip-flop with asynchronous clear at H10 +H10: process(clk6, J10_Q, CompBlank) +begin + if CompBlank = '0' then + H10_Q <= (others => '0'); + elsif rising_edge(clk6) then + H10_Q <= J10_Q; + end if; +end process; + +CompBlank <= HBlank nor VBlank; +CompSync_n <= HSync nor VSync; + +White <= H10_Q(1); +CC3_n <= (not CompBlank); +CC2 <= H10_Q(4); +CC1 <= H10_Q(3); +CC0 <= H10_Q(2); + +PF_Vid1 <= H10_Q(1); +PF_Vid2 <= H10_Q(0); + +end rtl; \ No newline at end of file diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/pll.v b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/pll.v new file mode 100644 index 00000000..6a352243 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/pll.v @@ -0,0 +1,337 @@ +// megafunction wizard: %ALTPLL% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altpll + +// ============================================================ +// File Name: pll.v +// Megafunction Name(s): +// altpll +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 13.1.4 Build 182 03/12/2014 SJ Web Edition +// ************************************************************ + + +//Copyright (C) 1991-2014 Altera Corporation +//Your use of Altera Corporation's design tools, logic functions +//and other software and tools, and its AMPP partner logic +//functions, and any output files from any of the foregoing +//(including device programming or simulation files), and any +//associated documentation or information are expressly subject +//to the terms and conditions of the Altera Program License +//Subscription Agreement, Altera MegaCore Function License +//Agreement, or other applicable license agreement, including, +//without limitation, that your use is for the sole purpose of +//programming logic devices manufactured by Altera and sold by +//Altera or its authorized distributors. Please refer to the +//applicable agreement for further details. + + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on +module pll ( + inclk0, + c0, + c1, + locked); + + input inclk0; + output c0; + output c1; + output locked; + + wire [4:0] sub_wire0; + wire sub_wire2; + wire [0:0] sub_wire6 = 1'h0; + wire [0:0] sub_wire3 = sub_wire0[0:0]; + wire [1:1] sub_wire1 = sub_wire0[1:1]; + wire c1 = sub_wire1; + wire locked = sub_wire2; + wire c0 = sub_wire3; + wire sub_wire4 = inclk0; + wire [1:0] sub_wire5 = {sub_wire6, sub_wire4}; + + altpll altpll_component ( + .inclk (sub_wire5), + .clk (sub_wire0), + .locked (sub_wire2), + .activeclock (), + .areset (1'b0), + .clkbad (), + .clkena ({6{1'b1}}), + .clkloss (), + .clkswitch (1'b0), + .configupdate (1'b0), + .enable0 (), + .enable1 (), + .extclk (), + .extclkena ({4{1'b1}}), + .fbin (1'b1), + .fbmimicbidir (), + .fbout (), + .fref (), + .icdrclk (), + .pfdena (1'b1), + .phasecounterselect ({4{1'b1}}), + .phasedone (), + .phasestep (1'b1), + .phaseupdown (1'b1), + .pllena (1'b1), + .scanaclr (1'b0), + .scanclk (1'b0), + .scanclkena (1'b1), + .scandata (1'b0), + .scandataout (), + .scandone (), + .scanread (1'b0), + .scanwrite (1'b0), + .sclkout0 (), + .sclkout1 (), + .vcooverrange (), + .vcounderrange ()); + defparam + altpll_component.bandwidth_type = "AUTO", + altpll_component.clk0_divide_by = 125, + altpll_component.clk0_duty_cycle = 50, + altpll_component.clk0_multiply_by = 224, + altpll_component.clk0_phase_shift = "0", + altpll_component.clk1_divide_by = 125, + altpll_component.clk1_duty_cycle = 50, + altpll_component.clk1_multiply_by = 56, + altpll_component.clk1_phase_shift = "0", + altpll_component.compensate_clock = "CLK0", + altpll_component.inclk0_input_frequency = 37037, + altpll_component.intended_device_family = "Cyclone III", + altpll_component.lpm_hint = "CBX_MODULE_PREFIX=pll", + altpll_component.lpm_type = "altpll", + altpll_component.operation_mode = "NORMAL", + altpll_component.pll_type = "AUTO", + altpll_component.port_activeclock = "PORT_UNUSED", + altpll_component.port_areset = "PORT_UNUSED", + altpll_component.port_clkbad0 = "PORT_UNUSED", + altpll_component.port_clkbad1 = "PORT_UNUSED", + altpll_component.port_clkloss = "PORT_UNUSED", + altpll_component.port_clkswitch = "PORT_UNUSED", + altpll_component.port_configupdate = "PORT_UNUSED", + altpll_component.port_fbin = "PORT_UNUSED", + altpll_component.port_inclk0 = "PORT_USED", + altpll_component.port_inclk1 = "PORT_UNUSED", + altpll_component.port_locked = "PORT_USED", + altpll_component.port_pfdena = "PORT_UNUSED", + altpll_component.port_phasecounterselect = "PORT_UNUSED", + altpll_component.port_phasedone = "PORT_UNUSED", + altpll_component.port_phasestep = "PORT_UNUSED", + altpll_component.port_phaseupdown = "PORT_UNUSED", + altpll_component.port_pllena = "PORT_UNUSED", + altpll_component.port_scanaclr = "PORT_UNUSED", + altpll_component.port_scanclk = "PORT_UNUSED", + altpll_component.port_scanclkena = "PORT_UNUSED", + altpll_component.port_scandata = "PORT_UNUSED", + altpll_component.port_scandataout = "PORT_UNUSED", + altpll_component.port_scandone = "PORT_UNUSED", + altpll_component.port_scanread = "PORT_UNUSED", + altpll_component.port_scanwrite = "PORT_UNUSED", + altpll_component.port_clk0 = "PORT_USED", + altpll_component.port_clk1 = "PORT_USED", + altpll_component.port_clk2 = "PORT_UNUSED", + altpll_component.port_clk3 = "PORT_UNUSED", + altpll_component.port_clk4 = "PORT_UNUSED", + altpll_component.port_clk5 = "PORT_UNUSED", + altpll_component.port_clkena0 = "PORT_UNUSED", + altpll_component.port_clkena1 = "PORT_UNUSED", + altpll_component.port_clkena2 = "PORT_UNUSED", + altpll_component.port_clkena3 = "PORT_UNUSED", + altpll_component.port_clkena4 = "PORT_UNUSED", + altpll_component.port_clkena5 = "PORT_UNUSED", + altpll_component.port_extclk0 = "PORT_UNUSED", + altpll_component.port_extclk1 = "PORT_UNUSED", + altpll_component.port_extclk2 = "PORT_UNUSED", + altpll_component.port_extclk3 = "PORT_UNUSED", + altpll_component.self_reset_on_loss_lock = "OFF", + altpll_component.width_clock = 5; + + +endmodule + +// ============================================================ +// CNX file retrieval info +// ============================================================ +// Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0" +// Retrieval info: PRIVATE: BANDWIDTH STRING "1.000" +// Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz" +// Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low" +// Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1" +// Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0" +// Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "0" +// Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0" +// Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0" +// Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0" +// Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0" +// Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0" +// Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "8" +// Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "125" +// Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "125" +// Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" +// Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "48.383999" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "12.096000" +// 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 "224" +// Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "56" +// Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "48.38400000" +// Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "12.09600000" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "0" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE1 STRING "0" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT1 STRING "MHz" +// Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT1 STRING "0.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT1 STRING "deg" +// Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "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.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 "125" +// Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "224" +// Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "125" +// Retrieval info: CONSTANT: CLK1_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK1_MULTIPLY_BY NUMERIC "56" +// 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: 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.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.ppf TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll_bb.v FALSE +// Retrieval info: LIB_FILE: altera_mf +// Retrieval info: CBX_MODULE_PREFIX: ON diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/030180n1.hex b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/030180n1.hex new file mode 100644 index 00000000..c3e443e6 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/030180n1.hex @@ -0,0 +1,129 @@ +:10000000030C000000030C030E06090004050C009D +:1000100006000000000501000503050E05010003B0 +:10002000000F000506000A000F0109010506000186 +:1000300005080A00030D03000903000C080207006D +:1000400003010208000301080A0900050F0A050759 +:100050000D0B0000010C08010206040A000B060A41 +:100060000004050E000F0C03010602050E05020038 +:100070000D0000000608000F0000060A000C0B002F +:10008000030005010004050005020802040901003F +:1000900002020000030102050003010C0F000D0124 +:1000A0000009030A000D0003010508000E06030005 +:1000B0000A0900050300060A0C0C0B0009020B05D7 +:1000C000000805010401000A080A0A0A09000900DB +:1000D00008050504050A000300060A050C00030CC8 +:1000E000030000020E05050002020D000301020BD1 +:1000F00004050002020C000301020905050A0002C2 +:10010000020A0C03010401000A05000A05020A0A9A +:10011000090308000D0C000405000A05020A0A097B +:100120000309030809000002090105000900050E82 +:100130000D01000903000108050809000001080875 +:100140000002090305040500000405080A000D0665 +:1001500000000904040900050D0C080A05000A093D +:10016000000A0A0A09010D0708020F0C0301000228 +:10017000020D0401050F0C0501090F05070502001A +:1001800008010900000B010A0A0006020005000030 +:100190000C00030102010502000F0C030102050916 +:1001A000000D01080A000A000B020509000D0908EC +:1001B0000A000A0000090002050009000507040200 +:1001C00000060B0800060B0804020500000E0108DB +:1001D000080C0901080A0A0A0A000E010808090F9A +:1001E0000004040700050809000607090F050F09A8 +:1001F0000008000D00080906000A0D0108090200A8 +:10020000030C02080C0A020D0C020A090E02090076 +:10021000090F0D00080808000200030B0D0F010074 +:100220000507040701010101010102020707070791 +:10023000070A070A0D08080808080808020900024A +:1002400005030300030401020404070F00000C016E +:1002500009030000050200030F090E0100030F0946 +:100260000E0000050200000C010905020002000357 +:100270000F090E030000050200000C010905020031 +:10028000000003020504090400060F02000100003B +:1002900000000003050C050304000F0004090F0E05 +:1002A000030000000000000007010D05000F060517 +:1002B0000200000000050804050E04050400000CFF +:1002C0000109060F020F00050E000609050C0407C0 +:1002D000010C0C0300010E04000D090E05030006BD +:1002E000090309020C050004010E0B0300000009BC +:1002F0000E06090309020C050004010E0B0300039E +:100300000405050201020C05000308050C0C03029C +:100310000F050E03090E07000308050C0C0300006F +:100320000305030F0E040300040F00000C01090075 +:10033000020F020F04000A030202000803000E036A +:1003400000080405030A0A0001000201050F050860 +:1003500008050A0004090F09010A000008050F003A +:1003600002090F0901050F000002050C00060A0929 +:1003700002080502080902000002090000030A0041 +:100380000308000A090A03050E0000010307000024 +:10039000040F0509080508080A0809020A050908E2 +:1003A00005080A0805030006090F090108080503E6 +:1003B000080805040005090F0901080404050300E5 +:1003C000040008000F0805000503000A0501000AE3 +:1003D0000B0A04000000000E000B000400050600DC +:1003E0000A000405010003050108080001060004D5 +:1003F0000006010501080900000C000009030400C3 +:1004000003080008040308040400090003000509A8 +:1004100000080503080904040A0A0504080A080874 +:100420000805070001090C0004090C000404080079 +:10043000050A060F060F0902050E00010A050A0546 +:100440000E080A0A0A0A040C00020501040100024F +:100450000601000002030507090B0D0003080E0743 +:100460000500020F0000000005030402000406025C +:10047000000B050E0508000C0A05030000090F0813 +:1004800009060500050F050E0A0805070A0A0A0AEB +:100490000A090009070805090509050805080208F1 +:1004A000000D0B0808090109070A000E04000E04DC +:1004B000000E04080A040E090E0400030C0F0508C0 +:1004C000090808050B000209000A0A0A0A050F08B4 +:1004D00000090908040F0003080901040D000E04B7 +:1004E00001000A08050B050A080002090F000C0CA0 +:1004F000070A0002020701000A0A0A060E000001AC +:1005000000010300030002010101060103010601CD +:10051000030103030303000800080404000408099E +:1005200000050205080A0A0A090209010005010876 +:10053000050008050208050308060A000305000B6C +:100540000802020000070008050A0A000602060069 +:1005500007080A0A0009080503080502080500083B +:10056000050100060B000C0D020009030A0D04052D +:10057000050B050C0009050D000608080901080512 +:100580000D0900000A000D0C000509030504000F09 +:10059000050D00000D0300090300090A0C0B0008FB +:1005A00008020204000009080A09020808090200FA +:1005B000000E0903050D050D02070003010C0F05D0 +:1005C0000A0A000F020F060C0908050A08060105B1 +:1005D0000D0000040F00000407000F0004010900D3 +:1005E0000900080003050709050C0002050E050AAD +:1005F0000500000D050C040C0004040000020503B6 +:100600000A08050D00090808050D0003000D08087B +:10061000090F0901000B08090F060500090006056E +:1006200001090105090A000C060C02060C00000D68 +:100630000609060A0601060B0602060C0608060154 +:10064000060004060506080900050600020607095B +:100650000700080509090F05090501090005090535 +:10066000010507050A0004050A0405000209080837 +:1006700000070C050F08000A0C050E000004060C0C +:100680000D060004060C0B06000C06090008050EFA +:1006900008090008050F0C0206000C0605060809EB +:1006A00000050600020607090700000C06050E08F3 +:1006B000050F0805030908000408090000080800E0 +:1006C00000080800010808050A050A08050C050CC1 +:1006D0000809000A08050A050A08050C050C0000AF +:1006E000080800010808050B050B08050D050D0895 +:1006F00009000A08050B050B08050D050D09040086 +:100700000000050400050002070001050E000108B5 +:1007100005030009080603090C050300070507097E +:10072000080C09070A0908090C050908000804054E +:100730000004050B000209000A0501090F00020967 +:10074000000501000C05030008050C0508050D0552 +:1007500009000A080809040A000D0B0208090F081D +:100760000C0C0701000900000A080005000707003B +:10077000010A080A000A08000D0A0C0C070100090A +:100780000A000608080A040C000406020606090FFF +:10079000050309000100080A00000F0502080D0EFC +:1007A00007000108000200010808000F0503080DFA +:1007B0000507000108000200010A05020A080805F1 +:1007C0000C050C0808050D050D08000001020202C9 +:1007D00001000000010008080800080808000808D7 +:1007E00000080808000800080A080D0E070805029E +:1007F000080900080D050708050308090008090095 +:00000001FF diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/030181k1.hex b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/030181k1.hex new file mode 100644 index 00000000..777c7929 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/030181k1.hex @@ -0,0 +1,129 @@ +:100000000E0200010700040E0B0400090F0A000194 +:100010000002030B02000B02030B0A07000A0F0089 +:10002000020B0B0A050D0D02060B0A0008050D0D4B +:100030000A000409020A060202000F01040A000273 +:100040000F0B0A00020F0B060A0A0408000008053D +:100050000B0B0B0A07040B0B0A000A060F000C0619 +:100060000D000A070D00040F0B0A0A0A07080A0F01 +:10007000020E000D0104020B0B020F0B02070B0214 +:100080000E0B0A0A0D0008080808060A000C000FEB +:10009000000A00020F0B0A00020F0B040B0B0A06EA +:1000A0000202000A0F0E020F0B0A000D00040A0DD7 +:1000B000000A08080A020F0B04070B060103040AD2 +:1000C000070A040708070F0109040606020C0600C8 +:1000D0000A04080808040900020F0B0A00010004C2 +:1000E0000E0B060A000A0801000A00020F0B0A00A4 +:1000F000020807000A00020F0B0A000A08040900A0 +:100100000A00040F0B0A0A0F000A08000A0802027C +:1001100002000A02020B09010A08000A0802020290 +:10012000000C000A0A0F09000A00080A0A000C075E +:100130000A060202000D00010A0002010D00030977 +:100140000B00000008080A0A0F020A00040B000C4A +:100150000A0D0008080A0A080804030B0A0A02022A +:100160000C0202020603080A000A00040F0B060A2A +:10017000000B0B0B08000B0B0B0A0F08050B0502FD +:100180000B0B0003020E0B0C0C010E0A010A0803F4 +:1001900000020F0B0A010A080300040F0B0A000AF1 +:1001A000000904000C010F030E0A000A00090500F3 +:1001B0000C010F0608030C0208010A0808050800D4 +:1001C000020D0B04020D0B040A000A01020D0B06BE +:1001D0000C040D0B0404040404020D0B060C0200B5 +:1001E0000D000205030001060304050203000009D7 +:1001F0000000060A00020C040D000A00020C050DA6 +:10020000000400020B010B0B020B0A0B030B0C0882 +:1002100002030904000C0E090F0605000102040088 +:1002200006070808090A0B0D0C0E0F0F040404043E +:1002300004060400020A0A0C0C0E0E060001050555 +:1002400004050504050504050D050504040504045D +:10025000050504050405040404040C030404040453 +:100260000404050405040504040504050C03040442 +:1002700004040405040504050405040405040D0430 +:10028000040404050404040504040405040304042C +:100290000C04040504040404050404050504040412 +:1002A00005040C0404040404040404040404050404 +:1002B000050404040C0405050404040404040504F2 +:1002C000040D04040D0405040404040404040C05D2 +:1002D00004040405040404040404040404050C05D3 +:1002E00004050404040404050404040504040C04C3 +:1002F00004050405040404040405040404050C05B1 +:1003000005040405040404040405040404040D04A1 +:1003100004050404040404040504040404050C0492 +:100320000504040404040504050404050404050C80 +:10033000050404040D02040B0A0002060B02080B5C +:1003400002060B09070C0C010F060A0008080B0334 +:10035000030F030B00040F06000C010F0106080930 +:10036000000A0F00000808060A000A00030108043A +:10037000000A0B05030F05000B000A000A00040F1A +:1003800000080D0F0B080B090406000000000A000E +:1003900009040B03040B0304080404000A0B030400 +:1003A0000B030B030F000B00040F06000C0C0900DD +:1003B00006030F000B00040F06000C09000D000DD2 +:1003C000000A000D030308010B000F000801020DD5 +:1003D0000B020A010C010A0F0B010A000D000201B9 +:1003E000020B000C0109000E0103080D0F02010AA7 +:1003F0000104010C010906000B0D0A010D050B0B90 +:100400000008010F0900090B000F000C000F000A83 +:1004100001030F000107060B00000900060A06068B +:10042000030F010F01020F0F000C0F09000A000D4E +:10043000000003040F040A000D040B000409040B60 +:100440000403020000000B050F0009080B080F0051 +:100450000D0806000000000000000001010101027B +:1004600003050A0F010002030B070B010F000D012A +:100470000D070B0402000F00040B070B0702000A14 +:100480000B010B060B04080808040B010404040408 +:100490000406000200040B0308040B0308040A000E +:1004A000020E0B0601060002000A020E0B020E0BE2 +:1004B000020E0B060A0A080B0F0B010004010B04C5 +:1004C0000A00030F040B000A00000000000C0806DD +:1004D00009000A040B040F000900040B0601000BBD +:1004E000080D00040B010D04060B000200060B0CA6 +:1004F0000B0C01000A000B000000000208060404B7 +:100500000C04040C040C0404040404040404040493 +:100510000404040404040404040404040404040A95 +:100520000309010A0000020202000004060A000496 +:100530000A00040A00040A00040E0002060B020767 +:100540000B0A0002000B020E0B0C0C010F0A00023A +:100550000F0B0C0C010F0608000608000608000629 +:100560000800040C0001070A060202000A0B0E0B29 +:1005700008000A0003050A080F010F030E000D080A +:10058000080C08090402020B09040A0008080D03FC +:100590000A000D030A060202000F020A0B0B0B08E9 +:1005A000090A000B080101040804000A060D0500F1 +:1005B0000B000A03080808000A00020F0B040C0BCA +:1005C0000C0C010D0A0F08000A0708060E080A0A9B +:1005D000080A0408000A0808050A00020D0B0003B7 +:1005E00009000006020304050A000F000A070006BE +:1005F000000A0D050B060A0003000B0803000B0799 +:10060000000405060100060409060300020A0B06A1 +:1006100002010C010B030A0B020B08000B030B0871 +:10062000000A0008060402020B04050B0600000A7B +:100630000B090B0A0B040B080B080B070B080B0527 +:100640000B02040B0B01030E0C09010B000D010A38 +:100650000006010606020708060B09020800060943 +:10066000090B010D010F01090102080100020F042D +:1006700002050B09010602050B09010602040B0421 +:100680000A0B02040B04080B02090B0A00030F01FA +:100690000A0A00030F01040B0B02090B0B010106F0 +:1006A0000C090109000F010A000602090B0B010ADF +:1006B0000B01040B010C020900060A000609040ADA +:1006C00000060401000801070209020907030903E3 +:1006D000060C0806010702090209070309030A00BC +:1006E00006040100080107020902090703090306BD +:1006F0000C0806010702090209070309030A00069C +:100700000A000B07010002050B0A000A0001000C99 +:100710000B010F000C0D0102030D010D000B010276 +:100720000F04020B00020304030909090D0002086B +:1007300007000B010F000A08000B0902070B00005D +:1007400008090903000B0503000B0309030B030948 +:1007500003060804030E000A020E0B0A000A0F0427 +:100760000B0C0B0B0002020F00060300020E0B091C +:100770000008040C010E0603010A0B0C0B0B000C05 +:10078000070D0106040A020003000F0504050A0311 +:1007900009010A000900060A060A0F0A0001070DEE +:1007A0000B0D000A01000A0009040A0F0A000107E4 +:1007B0000D0B0D000A01000A000B0B000A090107CE +:1007C00003090306010703090306060200000204E9 +:1007D000040402000200000000000F0F0F000F0FC2 +:1007E00000000000000F000408040B0D0B010600C0 +:1007F000010602040B0D0B010600010602040A02A9 +:00000001FF diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/030182m1.hex b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/030182m1.hex new file mode 100644 index 00000000..74bfef88 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/030182m1.hex @@ -0,0 +1,129 @@ +:1000000008000F080A05020805040A0D0E07080576 +:1000100002080900080D050708050308090008097A +:100020000008000F080A0503080808080A08000865 +:100030000A0808080A05010805060004090F090155 +:100040000900000D08090B08050105030805070054 +:1000500004090F09010900000808090B080501003F +:1000600002090F05030808080A0800000104090036 +:100070000904010001040900090401050C08050D2B +:1000800008050E040F000F08090408080900000AFB +:100090000200050C050E0A000309020A060C0902FB +:1000A0000A060C02010A000A0900050E000A0809E6 +:1000B0000208090300000D050E08050F0005050FD5 +:1000C0000800070C080A09020A05010008050500D6 +:1000D00000080808080401080500080503080502CF +:1000E000040500040900050F080A000F040C060BA4 +:1000F00000080808080A00050100010005000003C7 +:100100000C01090502040500000A09020902080998 +:100110000F0008090E000C0E09050308050205036F +:100120000A000206020A0602040500010805030887 +:10013000090004030002090F050205020808050E64 +:10014000050E0502050005000A0A0008090005025F +:100150000808000A0A000D0B0100090A000C0C0B2C +:10016000070007060F000A0C0B090A0809020A001B +:10017000070C0808080A05030A05000401000F0817 +:1001800009010808080A0001000809020A040C0015 +:100190000406020606090F05030A09020A05080AF1 +:1001A00009080002090808050705070900050B08EA +:1001B0000A05000004090F050006000002000309FB +:1001C0000005010A08090209020A060B060B080AC3 +:1001D000000A0E0B0F05050D070E0B090F0809018C +:1001E00009040200040A0A0A0A040300020A0A09AE +:1001F00000000905020503000D05030502000705BF +:10020000080A090000020900000209000A000E089D +:10021000050305020006090005030503080A000C92 +:100220000502050300060900050205020A08090285 +:100230000A090E050B080A00000C0B00060A000C48 +:100240000B090F050608080002000A00030D000B49 +:100250000D00080D00090D000A0A000F0606020035 +:100260000C030B060A060A08000008000C08000F21 +:1002700000000F0F0F0F0F0F0505050505050506FB +:100280000A0A0A0A0A0800080508000C010D000302 +:100290000C0A0E0D0A0309030105000A0C0A0102EB +:1002A0000B070F0C0B0506050A0D04000C030306D3 +:1002B0000F0005070A0A00070900080002060605E4 +:1002C00007050201050602060200040A0A000600EC +:1002D00000020A08090805080901050700020A06C4 +:1002E000070607050705070003090F0007050809AA +:1002F0000B000100080000080A050509010A0001B9 +:100300000002020D030A05050D040A05060000049B +:100310000700000A000800020A050408090102009B +:10032000010700010B00020A050400070902090089 +:100330000002090502000107000100010700010B8E +:100340000C050B0A05040A000B0A0809010200014A +:10035000070C010B0A0A0A050406040A0D0D0B001E +:10036000030E03080200010700010B0C050B00003F +:100370000A0008090A0200010700030005050A092E +:100380000808000409080008050D040F0904050EFB +:10039000090005090908050C090005070000000708 +:1003A00008000006090908000006070000010F0008 +:1003B000000604090005040D0D0B000206040805E3 +:1003C0000705070504050805080604000900020CD6 +:1003D00005000A000B00090A0501000809000600D3 +:1003E0000A050100020501080004060000090205D3 +:1003F000010900080501080A06010A0601090005AD +:100400000008090708090405020900080500080A90 +:100410000A0A050005000809070809040503000188 +:1004200000040D080C0A0C040D08050C000202085B +:100430000D010009030004050E000B050100020573 +:10044000000900050C000B0601090F0500060E0649 +:1004500006080A0A000A00080900080A080A050234 +:100460000A0A0A0D0D0C0A0502080A0800000D0907 +:1004700005010C07010B030A01060A0E0F0F0F0EF0 +:100480000A06010A030B01070C0105090D00030709 +:100490000B0F04090F050D060F0A060201010102E8 +:1004A000060A0F060D050F09040F0B07030D0400C4 +:1004B0000406000100080A080A08080805050900E2 +:1004C000090000030C030E0D0000000C05080A02D1 +:1004D00002050C0500050D050805000401000405D2 +:1004E0000404050809080002090F090000020900B8 +:1004F00008050408050C00090400000204040904AE +:100500000D0904050D0D010005040D00000A0A0087 +:1005100000000A02020800000E0A0A000806080984 +:1005200000050A0609000F0E00040D000A0D000563 +:100530000E050A00090A050309040002000A08085A +:10054000080A080000080808080000000808080059 +:10055000000008080900080E00080001080A0E063D +:10056000000001080A0E04000001080A0204000E3F +:100570000D020200080D000E0D020000080D080516 +:10058000070407040805080409050705020507050F +:100590000805090502050C0009050D000000000D05 +:1005A0000100000108090A0D00000D01000001080A +:1005B00009070D080D050000020808080C040000DA +:1005C0000209000C0000000209000009050D0000EE +:1005D0000D0500000600030003060202000A0E0AD1 +:1005E0000A000909060508000205080A0D01000AAB +:1005F000080900050F00050508050E000508050F90 +:100600000007050F0508080002060E060E0904057E +:100610000E0002050E0508000A000D000009000A80 +:10062000060705070008090E00020908090005076A +:100630000D0600090000060507050A050B00000E5F +:10064000060A060B000E0608090E050B050000043D +:100650000900050000050C0A09010D00000A090047 +:100660000004050D050B050C050E060B0900080915 +:100670000C00090E00000202080A08060B0001081F +:10068000090C0005030A0A080808090F0E040C08E3 +:100690000005040C090F0E0400090F0E0404090FD5 +:1006A0000E0A0A0003090F0002090F0D02000000E4 +:1006B0000101020202030304050607080A0B0D02EA +:1006C000020D0100090300060901050E0A0A0D04C6 +:1006D00000050402030D08000A0A00030D08000AC1 +:1006E000000300060608020F0A0802000A05000AB5 +:1006F000000B0C0000000A00080A090F050C0C0191 +:100700000002000A05000D0008080008000F05009F +:10071000000904000A000702090002020600060D93 +:10072000030F0908080A0800060200090005000D69 +:1007300000090A0D000A0D000B0A000F090005014F +:100740000900050002050601080A010008000B0A5D +:1007500006010907040100010A090F00050D040044 +:10076000060106010A090000050D04000601050145 +:100770000900000C020000050501090F0004020930 +:1007800000050D0908020600060D0D0F0901080AF3 +:10079000080006090305040505050E000F0E0C00F0 +:1007A00000000B0C0000000B00040D00050E0C00F7 +:1007B0000000030C030E0D00000A0D02000D0600E0 +:1007C0000900050C08050E0500000E050A000204CC +:1007D0000B040C050A0D020009030809010D0008AD +:1007E0000C0E0F0201040002010D000F0B020104A8 +:1007F00000020F0D000F0B0000000D0C060E0D0582 +:00000001FF diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/030183l1.hex b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/030183l1.hex new file mode 100644 index 00000000..75ae0064 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/030183l1.hex @@ -0,0 +1,129 @@ +:100000000A02020B0B0900060B000A0B0D0B01067E +:1000100000010602040B0D0B010600010602040A92 +:10002000020A02020B0B0D00060606060A0606046B +:10003000080409040B0B00030F000B00040F06005B +:100040000C010B010A0B060B09000B00030F000B40 +:1000500000040F06000C010B000A0B060B07000939 +:10006000000A0F0900060A060A0606000000000141 +:1000700001020304050607090A0C0E0A03040A0319 +:10008000040A030A0302020B0C0C06060A000B0109 +:100090000A000B030D0308090004000A0D03040005 +:1000A0000A0F030A0004090E0A08080006080404DF +:1000B000000A0B01000D030B010401010F030B01EA +:1000C0000402020B040804000A0B040F000B040DC9 +:1000D000020E0E0E0E0904060904060902060902A4 +:1000E000020801000A010905060A0A0009050F01B4 +:1000F00006060606060A060B040D00060B060F0090 +:10010000040B0B08000208030108020004000A0B9C +:100110000100040B010004010B0B02040B02080098 +:100120000009000C0000020002080301030E000495 +:100130000A00020003000A0F060008000601070279 +:1001400009020A000704090408040B000A00080059 +:10015000060E0D0C0C020E0B0B000C070F00020C10 +:100160000B0F0005050F04040D0B080402000A0222 +:10017000020B0409040B0B000A0B040B0402020B14 +:100180000C050606060A0900060402000A0200031E +:10019000000F0504050A0309010804000A0A00000B +:1001A0000A0109000A0E01070109010A00090406F3 +:1001B0000A0B060D000A0009060D060F0006090AC3 +:1001C0000009040804020004000A0F040501060ADD +:1001D000060A0E0B050F050B0E070D02000A0B0D8C +:1001E0000B02000300000000000200030000000CEE +:1001F0000C09010A00050201000A00050201000ABB +:1002000000040A0803000A0C0B00040C0009000497 +:100210000B02040001000A000F0209020600090097 +:100220000B02040001000A000F0209020804020088 +:100230000A0A0F0905060A06020C0B020F0B020739 +:100240000B0A0F08080D05060A0008030009000044 +:100250000900000900000900000C0D0E04050A0049 +:1002600004000B060B080B0100000A000000000050 +:100270000C000F0F0F0F0F0F0505050505050505F0 +:100280000A0A0A0A0A0A00030C0008040F03000EF7 +:100290000E0508060F08010A000A000B06060F0CDF +:1002A00003010E0F0802010D0C00080B0403010CE2 +:1002B0000F0F0A0004040D000A0C0C0D000E0008BC +:1002C0000008000300040004000F000404010F06EE +:1002D000020B0B01060008060A000806020B0B00C1 +:1002E00006000600060806090F0C0F0D000A060C92 +:1002F000000D0006010602040B0A08020C040B00A4 +:10030000060A000B060B08000B060B08000A000883 +:1003100000020D0B0B05020B0B08000106020A0080 +:100320000806020B0B020B0B0C000D010C000A025D +:1003300009000A020A000C060D00060806020B0B53 +:1003400004020B0A0400040D00080106020A00085A +:100350000604010B080000000008000A0B090B0D41 +:10036000000800000A000806020B0B04020B020D35 +:100370000B0B000A070A0008060F0F060A08040AFA +:10038000070A0B000A040A0A080308030A0D0803F7 +:100390000A0C08010A0308030A0408010600000207 +:1003A00002000002020202000002020000000F0E22 +:1003B000020A000A0008000B0A0B01000C000106EB +:1003C0000608060A00060608060800060A000A06CD +:1003D00009000C0D0F060A0008010A000A000201BC +:1003E000020C0109000E01080D0F0201060A0008A7 +:1003F000000A0F01070404000200000200020E08B8 +:1004000000060200030E0008000A0F01070404049E +:10041000040400000800060200030E0008000A029F +:10042000060B030C04020B0B03080B03060A000166 +:100430000A060202000F000A070F010A0A0F000B4A +:10044000080408030601000E0A0A0F09080C070435 +:1004500005030C0C010D06030E040408040B0B002D +:1004600004040A0B060B0B0900060A06060000012D +:100470000203030405050606070707070707070722 +:1004800007070706060505040303020100000F0E17 +:100490000D0C0C0B0A0A09090808080808080808C6 +:1004A00008080809090A0A0B0C0C0D0E0F080402B3 +:1004B00002080300040408040B09040D0B00020FDA +:1004C0000C0B0F00040E0B0A000103050A00040ABE +:1004D000000B0309090B0309090B040B040B000BA8 +:1004E000040B04000C000B000A0F0C010B000A01A6 +:1004F0000209090909090F000B060B000B060B0482 +:100500000B040809090B040209070902020C0C017B +:100510000C0B000A000102040B0C0C010F0E000A68 +:100520000008000E00020B0B02050B020D0B02056A +:100530000B0A000D000B0B0002000D00000E060A56 +:10054000060A06040808080808090909090909092A +:10055000090908080A00010A0001010003020A0251 +:1005600002010003020A0202030003020A0002075A +:100570000B0A0002090B02070B0A0002090B0A0B07 +:100580000809080B0809080805030808070B0801F3 +:1005900008020500070906060A000804020A000B03 +:1005A000000201000C0A000804020B000201000C0A +:1005B0000B0D0B0A0B000201010C0C090B000201D0 +:1005C0000000040B000203000008060A00080402F1 +:1005D0000B0002010E030E0000000A0002010B0CCA +:1005E0000C010F0A000C070B0008070402060204A6 +:1005F0000A060008070D0008070807060A070C0787 +:1006000009010E070807090D000E070E070A000C66 +:10061000070B0008070A070D0C060B02020408006E +:1006200007070B070F01020F0B000C0F060009074D +:100630000A040202080D0009070907090706090E46 +:100640000307030709000E070A0F08060A0A0F002E +:100650000A0F080A060A00000600080002040A0041 +:100660000B010805080508050805040606000A0927 +:100670000602090602060A0004080A050509000C1C +:100680000906020B0104040A0601070A0B0B050800 +:1006900003000905070A0B0B06070A0B0B06070ADE +:1006A0000B0C0C010D0C0009000A000804020600E6 +:1006B0000000000000000000000000000000000A30 +:1006C000000A060202000F000A000C07020A0906CF +:1006D000020A080A000906020C040B000906020CB3 +:1006E000010F060408070A0F090D0A000809000C8B +:1006F0000D0F020001050002030B0A0F08000400A1 +:100700000B0A000A09000900000E0D0F0A0F0D0068 +:100710000D0009000C0D0F0A000D000A000A000B65 +:100720000E0B0902000C08010F0A000A000900095B +:100730000000080900000900000C0D0E0A0B08005B +:100740000A0008000A05000A0A0805000C0D0F0A35 +:100750000E000A0002000D0F0802000F000804023C +:100760000E0A000A08020F0F000804020E0A0A000F +:100770000C0C090C0A000A030A0A02000D000A0008 +:100780000D000803000A000A000B0E0B0903000C01 +:1007900008010F0A08080808080807020B0B0200E6 +:1007A00001010F020001030F02050B02050B0200FD +:1007B000010500040E0B0A0202000A0202040402F0 +:1007C0000208060601060606070A0F0C050F0008B8 +:1007D00006080008050A06020200010607080500CF +:1007E00004090B00000000010000000000000000F0 +:1007F000000100000000000000000A0B0E0B020BBD +:00000001FF diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30024-01p8.hex b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30024-01p8.hex new file mode 100644 index 00000000..43303fd0 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30024-01p8.hex @@ -0,0 +1,33 @@ +:1000000000000000000000000000000000000000F0 +:1000100000000000000000000000000000000000E0 +:1000200000000000000000000000000000000000D0 +:1000300000000000000000000000000000000000C0 +:1000400000000000000000000000000000000000B0 +:1000500000000000000000000000000000000000A0 +:100060000000000000000000000000000000000090 +:100070000800000000000000000000000000000078 +:100080000A0A0A0A0A0A0A0A0B0B0A0A0A0A0A0ACE +:100090000A0A0A0A0A0A0A0A0A0A0A0A0A060000D8 +:1000A0000000000000000000000000000000000050 +:1000B0000000000000000000000000000000000040 +:1000C0000000000000000000000000000000000030 +:1000D0000000000000000000000000000000000020 +:1000E0000000000000000000000000000000000010 +:1000F00008080808080808080A0A0A0A0A0A0A0A70 +:1001000000000000000000000000000000000000EF +:1001100000000000000000000000000000000000DF +:1001200000000000000000000000000000000000CF +:1001300000000000000000000000000000000000BF +:1001400000000000000000000000000000000000AF +:10015000000000000000000000000000000000009F +:10016000000000000000000000000000000000008F +:100170000800000000000000000000000000000077 +:100180000A0A0A060000000000000000000000004B +:10019000000000000000000000000000000000005F +:1001A000000000000000000000000000000000004F +:1001B000000000000000000000000000000000003F +:1001C000000000000000000000000000000000002F +:1001D000000000000000000000000000000000001F +:1001E000000000000000000000000000000000000F +:1001F00008080808080808080A0A0B0B0A0A0A0A6D +:00000001FF diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30172-01j6.hex b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30172-01j6.hex new file mode 100644 index 00000000..5d788741 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30172-01j6.hex @@ -0,0 +1,33 @@ +:1000000000000000000000000003060C0C0F0C0CA8 +:10001000000F0C0C0F0C0C0F0003060C0C0C06034D +:10002000000F0C0C0C0C0C0F000F0C0C0F0C0C0F19 +:10003000000F0C0C0F0C0C0C0003060C0C0C060330 +:10004000000C0C0C0F0C0C0C000F03030303030F2C +:100050000000000000000C07000C0C0D0F0F0D0C31 +:10006000000C0C0C0C0C0C0F000C0E0F0F0D0C0CDC +:10007000000C0E0F0F0D0C0C00070C0C0C0C0C07D9 +:10008000000F0C0C0C0F0C0C00070C0C0C0D0C07CB +:10009000000F0C0C0C0F0D0C00070C0C07000C07CC +:1000A000000F030303030303000C0C0C0C0C0C07E0 +:1000B000000C0C0C0E070301000C0C0D0F0F0E0CA6 +:1000C000000C0E0703070E0C000C0C0C07030303B7 +:1000D000000F000103070E0F0000000000000000E9 +:1000E0000000000000000000000000000000000010 +:1000F0000000000000000000000000000000000000 +:100100000F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0FFF +:100110000F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0FEF +:100120000F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0FDF +:100130000F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0FCF +:100140000F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0FBF +:10015000000000000000000000000000000000009F +:10016000000000000000000000000000000000008F +:10017000000000000000000000000000000000007F +:100180000003040C0C0C0603000307030303030F16 +:1001900000070C0003070E0F0007000103000C0707 +:1001A000000103060C0F0000000F0C0F00000C07ED +:1001B0000003060C0F0C0C07000F0C0001030303D7 +:1001C00000070C0E0709080700070C0C07000007C2 +:1001D000000002010102000000020103030102000D +:1001E00000000103070301000000010306030100F2 +:1001F00000010E0602060E010000030207020300C2 +:00000001FF diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30173-01h6.hex b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30173-01h6.hex new file mode 100644 index 00000000..f5a78ae4 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30173-01h6.hex @@ -0,0 +1,33 @@ +:10000000000000000000000000080C06060E0606B6 +:10001000000C06060C06060C000C06000000060C80 +:1000200000080C0606060C08000C00000800000E74 +:10003000000E00000C000000000E00000E06060E70 +:10004000000606060E060606000C00000000000C66 +:10005000000606060606060C00060C0800080C0E34 +:10006000000000000000000C00060E0E0E06060642 +:10007000000606060E0E0E06000C06060606060C08 +:10008000000C0606060C0000000C0606060E0C0A04 +:10009000000C06060E080C0E00080C000C06060CE0 +:1000A000000C000000000000000606060606060C14 +:1000B000000606060E0C0800000606060E0E0E06CA +:1000C00000060E0C080C0E06000C0C0C08000000BC +:1000D000000E0E0C0800000E0000000000000000E2 +:1000E0000000000000000000000000000000000010 +:1000F0000000000000000000000000000000000000 +:100100000F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0FFF +:100110000F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0FEF +:100120000F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0FDF +:100130000F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0FCF +:100140000F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0FBF +:10015000000000000000000000000000000000009F +:10016000000000000000000000000000000000008F +:10017000000000000000000000000000000000007F +:1001800000080C0606060408000000000000000C31 +:10019000000C060E0C08000E000E0C080C06060CD7 +:1001A000000C0C0C0C0E0C0C000C000C0606060CC3 +:1001B000000C00000C06060C000E060C08000000E7 +:1001C00000080404080E060C000C06060E060C08B7 +:1001D00000000408080400000004080C0C080400D7 +:1001E00000080C0E0F0E0C0800080C060B060C087D +:1001F00000000E0C080C0E0000080E0A0F0A0E0874 +:00000001FF diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30174-01n6.hex b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30174-01n6.hex new file mode 100644 index 00000000..849c86ac --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30174-01n6.hex @@ -0,0 +1,65 @@ +:100000000000000000000E0E0E0E0E0E0E0000008E +:1000100000000000000C0C0C0E0E0E0E0000000084 +:1000200000000008080C0C0E0E0E0C000000000072 +:100030000000000008080C0C0E0E0C000000000070 +:100040000000080C0E0F0F0600000000000000006A +:1000500000080C0E0F0F0E08080000000000000042 +:1000600000080E0E0E080808000000000000000046 +:1000700000000E0E0E08080808000008080800001E +:10008000000C0C0C0000080800000C0C0C00000018 +:10009000000808080000080808080E0E0E000000FE +:1000A000000000000000000808080E0E0F08000005 +:1000B00000000000000008080E0F0F0E0C080000E2 +:1000C00000000000000000060F0F0E0C08000000EA +:1000D000000000000C0E0E0C0C08080000000000D0 +:1000E000000000000C0E0E0E0C0C080800000000B2 +:1000F0000000000E0E0E0E0C0C0C000000000000A4 +:1001000000000E0E0E0E0E0E0E000000000000008D +:10011000000C0C0C0E0E0E0E000000000000000083 +:10012000000C0C0E0E0F0F06000008080C0C080047 +:1001300000080C0E0F0F06000008080E0E0C000041 +:100140000000080C0E0F0C000000080E0E0C000042 +:1001500000000000080800000000080E0E0C00005F +:10016000000000080800000000080F0F0600000053 +:1001700000000000000000060F0F06000000000055 +:100180000000000000060E0E060000000000000047 +:1001900000000000060E0E06000000000000000037 +:1001A0000000060F0F080000000008080000000013 +:1001B000000C0E0E080000000008080000000000FF +:1001C000000C0E0E080000000C0E0E0C08000000C3 +:1001D000000C0E0E08080000060F0F0E0C080000A1 +:1001E000080C0C08080000060F0F0E0E0C0C000087 +:1001F000000000000000000E0E0E0E0C0C0C0000A3 +:1002000000000000000000000000000000000000EE +:1002100000000000000000000000000000000000DE +:1002200000000000000000000000000000000000CE +:1002300000000000000000040000000000000000BA +:1002400000000000000000040400000000000000A6 +:10025000000200080800000606000008080002006E +:10026000000606000000000606000000000606006A +:10027000000200060600020000020006060002005E +:10028000000000000E0202020200000A0A020A0038 +:10029000000000080C0A0A0A0408000A0507050005 +:1002A00000000008040A0A0A040800040A0E0A00F2 +:1002B000000000000000000000000000000000003E +:1002C000000000000000000000000000000000002E +:1002D000000000000000000000000000000000001E +:1002E000000000000000000000000000000000000E +:1002F00000000000000000000000000000000000FE +:1003000000000000000000000000000000000000ED +:1003100000000000000000000000000000000000DD +:1003200000000000000000000000000000000000CD +:1003300000000000000000000000000000000000BD +:1003400000000000000000000000000000000000AD +:10035000000000000000000000000000000000009D +:10036000000000000000000000000000000000008D +:10037000000000000000000000000000000000007D +:10038000000000000000000000000000000000006D +:10039000000000000000000000000000000000005D +:1003A000000000000000000000000000000000004D +:1003B000000000000000000000000000000000003D +:1003C000000000000000000000000000000000002D +:1003D000000000000000000000000000000000001D +:1003E000000000000000000000000000000000000D +:1003F00000000000000000000000000000000000FD +:00000001FF diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30175-01m6.hex b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30175-01m6.hex new file mode 100644 index 00000000..92150794 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30175-01m6.hex @@ -0,0 +1,65 @@ +:10000000000E0E0C0C0E0E0F0F0F0F0C0000000058 +:100010000008080008090D0F0F0F0F0C000000006A +:1000200000000001030D0F0F0F0F0C08000000006F +:100030000000000307070F0F0F0E0E0C000000005A +:1000400000030707070F0F0E0E0C00000808000042 +:10005000030707030F0F0F0F0F0F0E0F0F06000000 +:10006000060F0F070F0F0F0F0F0E0E0F0F0E0000D2 +:10007000000F0F0F070F0F0F0F0F0F0F0F070000CD +:10008000000F0F0F0F0F0F0F0F0F0F0F0F000000BC +:1000900000070F0F0F0F0F0F0F0F070F0F0F0000AD +:1000A000000E0F0F0E0E0F0F0F0F0F070F0F060092 +:1000B00000060F0F0C0F0F0F0F0F0F0307070300A2 +:1000C00000080800000C0E0E0F0F070707030000C2 +:1000D0000000000C0E0F0F0F0F07070300000000B9 +:1000E000000000080C0F0F0F0F0B030100000000B1 +:1000F0000000000C0F0F0F0F0D090800080800008A +:100100000000000C0F0F0F0F0E0E0C0C0E0E000057 +:100110000001010F0F0F0F0E0E0E0E060F0F000045 +:100120000001010F0F0F0F0F0F0F07030101010057 +:100130000307070F0F0F0F0F0F0703010000000049 +:10014000060F0F0707070F0E0F0F07010000000033 +:1001500000000C0F0F0F0F0C0E0F0F03000000001C +:1001600000080E0F0F0F0C0E0F0F0F0108080000F4 +:1001700000000E0E0E080C0F0F0F000808080000FC +:10018000000C0C0C080E0F0F0E080C0C0C000000DD +:1001900000080808000F0F0F0C080E0E0E000000DC +:1001A000000808010F0F0F0E0C0F0F0F0E080000B4 +:1001B000000000030F0F0E0C0F0F0F0F0C000000BC +:1001C00000000001070F0F0E0F0F07070F0F0600AB +:1001D0000000000103070F0F0F0F0F0F07070300A9 +:1001E00001010103070F0F0F0F0F0F0F0101000097 +:1001F000000F0F060E0E0E0E0F0F0F0F0101000065 +:1002000000000000000000080800000000000000DE +:1002100000000000000004000004000000000000D6 +:1002200000000000000200040400020000000000C2 +:1002300000000000040002000002000400000000B2 +:100240000008080003030008080003030008080072 +:100250000000080101000400000400010108000082 +:100260000008080003030008080003030008080052 +:1002700000080B030008000303000800030B08003C +:10028000000000000E0202020200000B060F060032 +:1002900000000001020504050201000B050D050028 +:1002A0000000000102050405020100070A0A0A0015 +:1002B000000000000000000000000000000000003E +:1002C000000000000000000000000000000000002E +:1002D000000000000000000000000000000000001E +:1002E000000000000000000000000000000000000E +:1002F00000000000000000000000000000000000FE +:1003000000000000000000000000000000000000ED +:1003100000000000000000000000000000000000DD +:1003200000000000000000000000000000000000CD +:1003300000000000000000000000000000000000BD +:1003400000000000000000000000000000000000AD +:10035000000000000000000000000000000000009D +:10036000000000000000000000000000000000008D +:10037000000000000000000000000000000000007D +:10038000000000000000000000000000000000006D +:10039000000000000000000000000000000000005D +:1003A000000000000000000000000000000000004D +:1003B000000000000000000000000000000000003D +:1003C000000000000000000000000000000000002D +:1003D000000000000000000000000000000000001D +:1003E000000000000000000000000000000000000D +:1003F00000000000000000000000000000000000FD +:00000001FF diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30176-01l6.hex b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30176-01l6.hex new file mode 100644 index 00000000..eef8d817 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30176-01l6.hex @@ -0,0 +1,65 @@ +:100000000001010000010D0F0F0F0F0C0C0000008C +:10001000000707030303030B0F0F0F0F0C0C000067 +:100020000C0C0C0E0F0707070F0F0F0F0C0C000026 +:100030000008080C0E0F0707070F0F0F0F0F060021 +:100040000008080C0F0707030F0F0F0F0F0703001F +:100050000008080E0F070301070F0F07010000003B +:100060000000000C0F0F070301070F0F0300000033 +:1000700000000000000F0F07010003030300000051 +:100080000001010100030F0F030001010100000046 +:1000900000000303030001070F0F00000000000031 +:1000A0000000030F0F070103070F0F0C00000000F3 +:1000B000000001070F0F070103070F0E08080000DB +:1000C00003070F0F0F0F0F0307070F0C080800009F +:1000D000060F0F0F0F0F0707070F0E0C0808000081 +:1000E000000C0C0F0F0F0F0707070F0E0C0C0C0066 +:1000F000000C0C0F0F0F0F0B030303030707000087 +:1001000000000C0C0F0F0F0F0D010000010100008B +:10011000000000090F0F0F0F0D0C00000000000081 +:1001200000000000090F0F0F0F0E0E0C0000000062 +:10013000000000010B0B0F0F0F0F0F060000000057 +:1001400000000000000103030F0F0F0F0F06000057 +:100150000003070703070F0F0F0F0F0E0F0F060007 +:10016000000307070303070F0F0F0F0F0F0F030005 +:10017000000F0F0F07070F0F0F0F0F0F0F070000D4 +:10018000000F0F0F07070F0F07070F0F0F000000DB +:1001900000070F0F0F0F0F0F0F07070F0F0F0000B4 +:1001A000030F0F0F0F0F0F0F0703030707030000C5 +:1001B000060F0F0E0F0F0F0F0F07010707030000A9 +:1001C00000060F0F0F0F0F030301000000000000D7 +:1001D000000000060F0F0F0F0F0F0B0100000000B3 +:1001E0000000000C0E0E0F0F0F0F090000000000A2 +:1001F00000000000000C0D0F0F0F0F0900000000A1 +:1002000000000000000000010100000000000000EC +:1002100000000000000002000002000000000000DA +:1002200000000000000400020200040000000000C2 +:1002300000000000020004000004000200000000B2 +:10024000000101000C0C000101000C0C0001010078 +:100250000000010808000200000200080801000078 +:10026000000101000C0C000101000C0C0001010058 +:1002700000010D0C0001000C0C0001000C0D010030 +:1002800000000008040A020A0408000E0505050023 +:1002900000000000070404040400000C050D050024 +:1002A00000000000070404040400000D060F06000F +:1002B000000000000000000000000000000000003E +:1002C000000000000000000000000000000000002E +:1002D000000000000000000000000000000000001E +:1002E000000000000000000000000000000000000E +:1002F00000000000000000000000000000000000FE +:1003000000000000000000000000000000000000ED +:1003100000000000000000000000000000000000DD +:1003200000000000000000000000000000000000CD +:1003300000000000000000000000000000000000BD +:1003400000000000000000000000000000000000AD +:10035000000000000000000000000000000000009D +:10036000000000000000000000000000000000008D +:10037000000000000000000000000000000000007D +:10038000000000000000000000000000000000006D +:10039000000000000000000000000000000000005D +:1003A000000000000000000000000000000000004D +:1003B000000000000000000000000000000000003D +:1003C000000000000000000000000000000000002D +:1003D000000000000000000000000000000000001D +:1003E000000000000000000000000000000000000D +:1003F00000000000000000000000000000000000FD +:00000001FF diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30177-01k6.hex b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30177-01k6.hex new file mode 100644 index 00000000..559365c5 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30177-01k6.hex @@ -0,0 +1,65 @@ +:1000000000000000000001010101010101000000E9 +:1000100000000000000000030303030101010000D1 +:1000200000010100000000030707030301010000B5 +:1000300000010303000000000307070301000000A4 +:1000400000010303000000000103030100000000A1 +:100050000001030300000000000000000000000099 +:10006000000003070700000000000000000000007F +:100070000000000003030303000000000000000074 +:100080000000000000030303030000000000000064 +:100090000000000000000003030303000000000054 +:1000A000000000000000000000000707030000003F +:1000B0000000000000000000000000030301000039 +:1000C0000000000103030100000000030301000021 +:1000D0000000010307070300000000030301000004 +:1000E00000010103030707030000000001010000F5 +:1000F00000010101030303030000000000000000F1 +:1001000000000101010101010100000000000000E8 +:1001100000000003030303010101000000000000D0 +:1001200000000000010303030101000000000000C3 +:1001300000000000010303010100000000000000B6 +:10014000000000000000000307070301000000009A +:10015000000000000000000003070703010000008A +:100160000000000000000000000003030300000086 +:100170000000000000000000000003030300000076 +:100180000001010100000000000001010100000069 +:100190000000030303000000000000000000000056 +:1001A0000000030303000000000000000000000046 +:1001B000000001030707030000000000000000002A +:1001C000000000010307070300000000000000001A +:1001D0000000000000000101030301000000000016 +:1001E0000000000000010103030301000000000003 +:1001F00000000000000101010303030300000000F0 +:1002000000000000000000000000000000000000EE +:1002100000000000000000000000000000000000DE +:1002200000000000000000000000000000000000CE +:1002300000000000000000020000000000000000BC +:1002400000000000000000020200000000000000AA +:100250000004000101000006060000010100040086 +:10026000000606000000000606000000000606006A +:100270000004000606000400000400060600040056 +:100280000000000102050505020100020507050046 +:100290000000000007040404040000050504050034 +:1002A0000000000007040404040000050504050024 +:1002B000000000000000000000000000000000003E +:1002C000000000000000000000000000000000002E +:1002D000000000000000000000000000000000001E +:1002E000000000000000000000000000000000000E +:1002F00000000000000000000000000000000000FE +:1003000000000000000000000000000000000000ED +:1003100000000000000000000000000000000000DD +:1003200000000000000000000000000000000000CD +:1003300000000000000000000000000000000000BD +:1003400000000000000000000000000000000000AD +:10035000000000000000000000000000000000009D +:10036000000000000000000000000000000000008D +:10037000000000000000000000000000000000007D +:10038000000000000000000000000000000000006D +:10039000000000000000000000000000000000005D +:1003A000000000000000000000000000000000004D +:1003B000000000000000000000000000000000003D +:1003C000000000000000000000000000000000002D +:1003D000000000000000000000000000000000001D +:1003E000000000000000000000000000000000000D +:1003F00000000000000000000000000000000000FD +:00000001FF diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30218-01j10.hex b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30218-01j10.hex new file mode 100644 index 00000000..29a92430 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/roms/30218-01j10.hex @@ -0,0 +1,3 @@ +:100000000A07000114151415131311111111111100 +:1000100001010101010101010101010101010101D0 +:00000001FF diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/scandoubler.sv b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/scandoubler.sv new file mode 100644 index 00000000..0213d20c --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/scandoubler.sv @@ -0,0 +1,195 @@ +// +// scandoubler.v +// +// Copyright (c) 2015 Till Harbaum +// Copyright (c) 2017 Sorgelig +// +// 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 . + +// TODO: Delay vsync one line + +module scandoubler #(parameter LENGTH, parameter HALF_DEPTH) +( + // system interface + input clk_sys, + input ce_pix, + input ce_pix_actual, + + input hq2x, + + // shifter video interface + input hs_in, + input vs_in, + input line_start, + + input [DWIDTH:0] r_in, + input [DWIDTH:0] g_in, + input [DWIDTH:0] b_in, + input mono, + + // output interface + output reg hs_out, + output vs_out, + output [DWIDTH:0] r_out, + output [DWIDTH:0] g_out, + output [DWIDTH:0] b_out +); + + +localparam DWIDTH = HALF_DEPTH ? 2 : 5; + +assign vs_out = vs_in; + +reg [2:0] phase; +reg [2:0] ce_div; +reg [7:0] pix_len = 0; +wire [7:0] pl = pix_len + 1'b1; + +reg ce_x1, ce_x4; +reg req_line_reset; +wire ls_in = hs_in | line_start; +always @(negedge clk_sys) begin + reg old_ce; + reg [2:0] ce_cnt; + + reg [7:0] pixsz2, pixsz4 = 0; + + old_ce <= ce_pix; + if(~&pix_len) pix_len <= pix_len + 1'd1; + + ce_x4 <= 0; + ce_x1 <= 0; + + // use such odd comparison to place c_x4 evenly if master clock isn't multiple 4. + if((pl == pixsz4) || (pl == pixsz2) || (pl == (pixsz2+pixsz4))) begin + phase <= phase + 1'd1; + ce_x4 <= 1; + end + + if(~old_ce & ce_pix) begin + pixsz2 <= {1'b0, pl[7:1]}; + pixsz4 <= {2'b00, pl[7:2]}; + ce_x1 <= 1; + ce_x4 <= 1; + pix_len <= 0; + phase <= phase + 1'd1; + + ce_cnt <= ce_cnt + 1'd1; + if(ce_pix_actual) begin + phase <= 0; + ce_div <= ce_cnt + 1'd1; + ce_cnt <= 0; + req_line_reset <= 0; + end + + if(ls_in) req_line_reset <= 1; + end +end + +reg ce_sd; +always @(*) begin + case(ce_div) + 2: ce_sd = !phase[0]; + 4: ce_sd = !phase[1:0]; + default: ce_sd <= 1; + endcase +end + +`define BITS_TO_FIT(N) ( \ + N <= 2 ? 0 : \ + N <= 4 ? 1 : \ + N <= 8 ? 2 : \ + N <= 16 ? 3 : \ + N <= 32 ? 4 : \ + N <= 64 ? 5 : \ + N <= 128 ? 6 : \ + N <= 256 ? 7 : \ + N <= 512 ? 8 : \ + N <=1024 ? 9 : 10 ) + +localparam AWIDTH = `BITS_TO_FIT(LENGTH); +Hq2x #(.LENGTH(LENGTH), .HALF_DEPTH(HALF_DEPTH)) Hq2x +( + .clk(clk_sys), + .ce_x4(ce_x4 & ce_sd), + .inputpixel({b_in,g_in,r_in}), + .mono(mono), + .disable_hq2x(~hq2x), + .reset_frame(vs_in), + .reset_line(req_line_reset), + .read_y(sd_line), + .read_x(sd_h_actual), + .outpixel({b_out,g_out,r_out}) +); + +reg [10:0] sd_h_actual; +always @(*) begin + case(ce_div) + 2: sd_h_actual = sd_h[10:1]; + 4: sd_h_actual = sd_h[10:2]; + default: sd_h_actual = sd_h; + endcase +end + +reg [10:0] sd_h; +reg [1:0] sd_line; +always @(posedge clk_sys) begin + + reg [11:0] hs_max,hs_rise,hs_ls; + reg [10:0] hcnt; + reg [11:0] sd_hcnt; + + reg hs, hs2, vs, ls; + + if(ce_x1) begin + hs <= hs_in; + ls <= ls_in; + + if(ls && !ls_in) hs_ls <= {hcnt,1'b1}; + + // falling edge of hsync indicates start of line + if(hs && !hs_in) begin + hs_max <= {hcnt,1'b1}; + hcnt <= 0; + if(ls && !ls_in) hs_ls <= {10'd0,1'b1}; + end else begin + hcnt <= hcnt + 1'd1; + end + + // save position of rising edge + if(!hs && hs_in) hs_rise <= {hcnt,1'b1}; + + vs <= vs_in; + if(vs && ~vs_in) sd_line <= 0; + end + + if(ce_x4) begin + hs2 <= hs_in; + + // output counter synchronous to input and at twice the rate + sd_hcnt <= sd_hcnt + 1'd1; + sd_h <= sd_h + 1'd1; + if(hs2 && !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_out <= 0; + if(sd_hcnt == hs_rise) hs_out <= 1; + + if(sd_hcnt == hs_ls) sd_h <= 0; + if(sd_hcnt == hs_ls) sd_line <= sd_line + 1'd1; + end +end + +endmodule diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/screech.vhd b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/screech.vhd new file mode 100644 index 00000000..35380721 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/screech.vhd @@ -0,0 +1,73 @@ +-- Shell fire sound generator for Kee Games Ultra Tank +-- This was originally created as tire screech sound for Sprint 2 - Identical circuit +-- (c) 2017 James Sweet +-- +-- Original circuit used a 7414 Schmitt trigger oscillator operating at approximately +-- 1.2kHz producing a sawtooth with the frequency modulated slightly by the pseudo-random +-- noise generator. This is an extension of work initially done in Verilog by Jonas Elofsson. +-- +-- This 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 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. + +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use IEEE.STD_LOGIC_ARITH.all; +use IEEE.STD_LOGIC_UNSIGNED.all; + +entity screech is +generic( + constant Inc1 : integer := 24; -- These constants can be adjusted to tune the frequency and modulation + constant Inc2 : integer := 34; + constant Dec1 : integer := 23; + constant Dec2 : integer := 12 + ); +port( + Clk : in std_logic; -- 750kHz from the horizontal line counter chain works well here + Noise : in std_logic; -- Output from LFSR pseudo-random noise generator + Screech_out : out std_logic -- Screech output - single bit + ); +end screech; + +architecture rtl of screech is + +signal Screech_count : integer range 1000 to 11000; +signal Screech_state : std_logic; + +begin + +Screech: process(Clk, Screech_state) +begin + if rising_edge(Clk) then + if screech_state = '1' then -- screech_state is 1, counter is rising + if noise = '1' then -- Noise signal from LFSR, when high increases the slope of the rising ramp + screech_count <= screech_count + inc2; + else -- When Noise is low, decreas the slope of the ramp + screech_count <= screech_count + inc1; + end if; + if screech_count > 10000 then -- Reverse the ramp direction when boundary value of 10,000 is reached + screech_state <= '0'; + end if; + elsif screech_state = '0' then -- screech_state is now low, decrement the counter (ramp down) + if noise = '1' then + screech_count <= screech_count - dec2; -- Slope is influenced by the Noise signal + else + screech_count <= screech_count - dec1; + end if; + if screech_count < 1000 then -- Reverse the ramp direction again when the lower boundary of 1,000 is crossed + screech_state <= '1'; + end if; + end if; + end if; +screech_out <= screech_state; +end process; + +end rtl; \ No newline at end of file diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/sound.vhd b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/sound.vhd new file mode 100644 index 00000000..2b576900 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/sound.vhd @@ -0,0 +1,244 @@ +-- Audio for Kee Games Ultra Tank +-- First attempt at modeling the analog sound circuits used in Ultra Tank, may be room for improvement as +-- I do not have a real board to compare. +-- (c) 2017 James Sweet +-- +-- This 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 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. + +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use IEEE.STD_LOGIC_UNSIGNED.all; + +entity audio is +port( + Clk_6 : in std_logic; + Reset_n : in std_logic; + Load_n : in std_logic_vector(8 downto 1); + Fire1 : in std_logic; + Fire2 : in std_logic; + Write_Explosion_n : in std_logic; + Attract : in std_logic; + Attract_n : in std_logic; + PRAM : in std_logic_vector(7 downto 0); + DBus_n : in std_logic_vector(7 downto 0); + HCount : in std_logic_vector(8 downto 0); + VCount : in std_logic_vector(7 downto 0); + Audio1 : out std_logic_vector(6 downto 0); + Audio2 : out std_logic_vector(6 downto 0)); +end audio; + +architecture rtl of audio is + +signal reset : std_logic; + +signal H4 : std_logic; +signal V2 : std_logic; + +signal Noise : std_logic; +signal Noise_Shift : std_logic_vector(15 downto 0); +signal Shift_in : std_logic; + +signal Crash : std_logic_vector(3 downto 0); +signal Explosion : std_logic_vector(3 downto 0); + +signal Mtr1_Freq : std_logic_vector(3 downto 0); +signal Mtr2_Freq : std_logic_vector(3 downto 0); +signal Motor1_speed : std_logic_vector(3 downto 0); +signal Motor1_snd : std_logic_vector(5 downto 0); +signal Motor2_speed : std_logic_vector(3 downto 0); +signal Motor2_snd : std_logic_vector(5 downto 0); + +signal Screech1 : std_logic := '0'; +signal Screech2 : std_logic := '0'; +signal Shell_fire1 : std_logic_vector(3 downto 0) := (others => '0'); +signal Shell_fire2 : std_logic_vector(3 downto 0) := (others => '0'); + +signal ena_count : std_logic_vector(10 downto 0) := (others => '0'); +signal ena_3k : std_logic := '0'; + +signal explosion_prefilter : std_logic_vector(3 downto 0); +signal explosion_filter_t1 : std_logic_vector(3 downto 0); +signal explosion_filter_t2 : std_logic_vector(3 downto 0); +signal explosion_filter_t3 : std_logic_vector(3 downto 0); +signal explosion_filtered : std_logic_vector(5 downto 0); + + +begin + +-- HCount +-- (0) 1H 3 MHz +-- (1) 2H 1.5MHz +-- (2) 4H 750 kHz +-- (3) 8H 375 kHz +-- (4) 16H 187 kHz +-- (5) 32H 93 kHz +-- (6) 64H 46 kHz +-- (7) 128H 23 kHz +-- (8) 256H 12 kHz + +reset <= (not reset_n); + +H4 <= HCount(2); +V2 <= VCount(1); + +-- Generate the 3kHz clock enable used by the filter +Enable: process(clk_6) +begin + if rising_edge(CLK_6) then + ena_count <= ena_count + "1"; + ena_3k <= '0'; + if (ena_count(10 downto 0) = "00000000000") then + ena_3k <= '1'; + end if; + end if; +end process; + + +-- LFSR that generates pseudo-random noise +Noise_gen: process(Attract_n, V2) +begin + if (attract_n = '0') then + noise_shift <= (others => '0'); + noise <= '0'; + elsif rising_edge(V2) then + shift_in <= not(noise_shift(6) xor noise_shift(8)); + noise_shift <= shift_in & noise_shift(15 downto 1); + noise <= noise_shift(0); + end if; +end process; + + +-- Screech sound used for shell fire. These can be tuned slightly differently to model variations in analog sound hardware. +ShellFire1: entity work.screech +generic map( -- These values can be tweaked to tune the screech sound + Inc1 => 24, -- Ramp increase rate when noise = 0 + Inc2 => 33, -- Ramp increase rate when noise = 1 + Dec1 => 29, -- Ramp decrease rate when noise = 0 + Dec2 => 16 -- Ramp decrease rate when noise = 1 + ) +port map( + Clk => H4, + Noise => noise, + Screech_out => screech1 + ); + + +ShellFire2: entity work.screech +generic map( -- These values can be tweaked to tune the screech sound + Inc1 => 24, -- Ramp increase rate when noise = 0 + Inc2 => 34, -- Ramp increase rate when noise = 1 + Dec1 => 23, -- Ramp decrease rate when noise = 0 + Dec2 => 12 -- Ramp decrease rate when noise = 1 + ) +port map( + Clk => H4, + Noise => noise, + Screech_out => screech2 + ); + +-- Convert shell fire screech sound from 1 bit to 4 bits wide and enable via fire1 and fire2 signals +Fire_ctrl: process(fire1, fire2, screech1, screech2) +begin + if (fire1 and screech1) = '1' then + shell_fire1 <= "1111"; + else + shell_fire1 <= "0000"; + end if; + + if (fire2 and screech2) = '1' then + shell_fire2 <= "1111"; + else + shell_fire2 <= "0000"; + end if; +end process; + + +Explosion_sound: process(Clk_6, DBus_n, Write_Explosion_n, Explosion, noise) +begin + if rising_edge(clk_6) then + if Write_Explosion_n = '0' then + explosion <= not DBus_n(3 downto 0); + end if; + if noise = '1' then + explosion_prefilter <= explosion; + else + explosion_prefilter <= "0000"; + end if; + end if; +end process; + +---- Very simple low pass filter, borrowed from MikeJ's Asteroids code +Crash_filter: process(clk_6) +begin + if rising_edge(clk_6) then + if (ena_3k = '1') then + explosion_filter_t1 <= explosion_prefilter; + explosion_filter_t2 <= explosion_filter_t1; + explosion_filter_t3 <= explosion_filter_t2; + end if; + explosion_filtered <= ("00" & explosion_filter_t1) + + ('0' & explosion_filter_t2 & '0') + + ("00" & explosion_filter_t3); + end if; +end process; + + +Motor1_latch: process(Load_n, PRAM) +begin + if Load_n(1) = '0' then + Motor1_speed <= PRAM(3 downto 0); + end if; +end process; + +Motor1: entity work.EngineSound +generic map( + Freq_tune => 50 -- Tuning pot for engine sound frequency + ) +port map( + Clk_6 => clk_6, + Reset => Attract, + Ena_3k => ena_3k, + EngineData => motor1_speed, + Motor => motor1_snd + ); + + +Motor2_latch: process(Load_n, PRAM) +begin + if Load_n(2) = '0' then + Motor2_speed <= PRAM(3 downto 0); + end if; +end process; + +Motor2: entity work.EngineSound +generic map( + Freq_tune => 48 -- Tuning pot for engine sound frequency + ) +port map( + Clk_6 => clk_6, + Reset => Attract, + Ena_3k => ena_3k, + EngineData => motor2_speed, + Motor => motor2_snd + ); + + +-- Audio mixer, also mutes sound in attract mode +Audio1 <= ('0' & motor1_snd) + ("00" & shell_fire1) + ('0' & explosion_filtered); -- when attract = '0' + --else "0000000"; + +Audio2 <= ('0' & motor2_snd) + ("00" & shell_fire2) + ('0' & explosion_filtered); -- when attract = '0' + --else "0000000"; + + +end rtl; \ No newline at end of file diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/spram.vhd b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/spram.vhd new file mode 100644 index 00000000..d4e8dd90 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/spram.vhd @@ -0,0 +1,90 @@ +LIBRARY ieee; +USE ieee.std_logic_1164.all; + +LIBRARY altera_mf; +USE altera_mf.all; + +ENTITY spram IS + GENERIC + ( + init_file : string := ""; + widthad_a : natural; + width_a : natural := 8; + outdata_reg_a : string := "UNREGISTERED" + ); + PORT + ( + address : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0); + clock : IN STD_LOGIC ; + data : IN STD_LOGIC_VECTOR (width_a-1 DOWNTO 0); + wren : IN STD_LOGIC ; + q : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0) + ); +END spram; + + +ARCHITECTURE SYN OF spram IS + + SIGNAL sub_wire0 : STD_LOGIC_VECTOR (width_a-1 DOWNTO 0); + + + + COMPONENT altsyncram + GENERIC ( + clock_enable_input_a : STRING; + clock_enable_output_a : STRING; + init_file : STRING; + intended_device_family : STRING; + lpm_hint : STRING; + lpm_type : STRING; + numwords_a : NATURAL; + operation_mode : STRING; + outdata_aclr_a : STRING; + outdata_reg_a : STRING; + power_up_uninitialized : STRING; + read_during_write_mode_port_a : STRING; + widthad_a : NATURAL; + width_a : NATURAL; + width_byteena_a : NATURAL + ); + PORT ( + wren_a : IN STD_LOGIC ; + clock0 : IN STD_LOGIC ; + address_a : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0); + q_a : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0); + data_a : IN STD_LOGIC_VECTOR (width_a-1 DOWNTO 0) + ); + END COMPONENT; + +BEGIN + q <= sub_wire0(width_a-1 DOWNTO 0); + + altsyncram_component : altsyncram + GENERIC MAP ( + clock_enable_input_a => "BYPASS", + clock_enable_output_a => "BYPASS", + init_file => init_file, + intended_device_family => "Cyclone III", + lpm_hint => "ENABLE_RUNTIME_MOD=NO", + lpm_type => "altsyncram", + numwords_a => 2**widthad_a, + operation_mode => "SINGLE_PORT", + outdata_aclr_a => "NONE", + outdata_reg_a => outdata_reg_a, + power_up_uninitialized => "FALSE", + read_during_write_mode_port_a => "NEW_DATA_NO_NBE_READ", + widthad_a => widthad_a, + width_a => width_a, + width_byteena_a => 1 + ) + PORT MAP ( + wren_a => wren, + clock0 => clock, + address_a => address, + data_a => data, + q_a => sub_wire0 + ); + + + +END SYN; diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/sprom.vhd b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/sprom.vhd new file mode 100644 index 00000000..a81ac959 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/sprom.vhd @@ -0,0 +1,82 @@ +LIBRARY ieee; +USE ieee.std_logic_1164.all; + +LIBRARY altera_mf; +USE altera_mf.all; + +ENTITY sprom IS + GENERIC + ( + init_file : string := ""; + widthad_a : natural; + width_a : natural := 8; + outdata_reg_a : string := "UNREGISTERED" + ); + PORT + ( + address : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0); + clock : IN STD_LOGIC ; + q : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0) + ); +END sprom; + + +ARCHITECTURE SYN OF sprom IS + + SIGNAL sub_wire0 : STD_LOGIC_VECTOR (width_a-1 DOWNTO 0); + + + + COMPONENT altsyncram + GENERIC ( + address_aclr_a : STRING; + clock_enable_input_a : STRING; + clock_enable_output_a : STRING; + init_file : STRING; + intended_device_family : STRING; + lpm_hint : STRING; + lpm_type : STRING; + numwords_a : NATURAL; + operation_mode : STRING; + outdata_aclr_a : STRING; + outdata_reg_a : STRING; + widthad_a : NATURAL; + width_a : NATURAL; + width_byteena_a : NATURAL + ); + PORT ( + clock0 : IN STD_LOGIC ; + address_a : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0); + q_a : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0) + ); + END COMPONENT; + +BEGIN + q <= sub_wire0(width_a-1 DOWNTO 0); + + altsyncram_component : altsyncram + GENERIC MAP ( + address_aclr_a => "NONE", + clock_enable_input_a => "BYPASS", + clock_enable_output_a => "BYPASS", + init_file => init_file, + intended_device_family => "Cyclone III", + lpm_hint => "ENABLE_RUNTIME_MOD=NO", + lpm_type => "altsyncram", + numwords_a => 2**widthad_a, + operation_mode => "ROM", + outdata_aclr_a => "NONE", + outdata_reg_a => outdata_reg_a, + widthad_a => widthad_a, + width_a => width_a, + width_byteena_a => 1 + ) + PORT MAP ( + clock0 => clock, + address_a => address, + q_a => sub_wire0 + ); + + + +END SYN; diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/sync.vhd b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/sync.vhd new file mode 100644 index 00000000..eddf924a --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/sync.vhd @@ -0,0 +1,197 @@ +-- Video synchronizer circuit for Ultra Tank +-- Similar circuit used in many other Atari and Kee Games arcade games +-- (c) 2017 James Sweet +-- +-- This 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 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. + +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use IEEE.STD_LOGIC_UNSIGNED.all; + +entity synchronizer is +port( + clk_12 : in std_logic; + clk_6 : buffer std_logic; + hcount : out std_logic_vector(8 downto 0); + vcount : out std_logic_vector(7 downto 0); + hsync : out std_logic; + hblank : out std_logic; + vblank_s : out std_logic; + vblank_n_s : out std_logic; + vblank : out std_logic; + vsync : out std_logic; + vreset : out std_logic); +end synchronizer; + +architecture rtl of synchronizer is + +signal h_counter : std_logic_vector(8 downto 0) := (others => '0'); +signal H256 : std_logic; +signal H256_n : std_logic; +signal H128 : std_logic; +signal H64 : std_logic; +signal H32 : std_logic; +signal H16 : std_logic; +signal H8 : std_logic; +signal H8_n : std_logic; +signal H4 : std_logic; +signal H4_n : std_logic; +signal H2 : std_logic; +signal H1 : std_logic; + +signal v_counter : std_logic_vector(7 downto 0) := (others => '0'); +signal V128 : std_logic; +signal V64 : std_logic; +signal V32 : std_logic; +signal V16 : std_logic; +signal V8 : std_logic; +signal V4 : std_logic; +signal V2 : std_logic; +signal V1 : std_logic; + +signal sync_bus : std_logic_vector(3 downto 0) := (others => '0'); +signal sync_reg : std_logic_vector(3 downto 0) := (others => '0'); +signal vblank_int : std_logic := '0'; +signal vreset_n : std_logic := '0'; + +signal hblank_int : std_logic := '0'; +signal hsync_int : std_logic := '0'; +signal hsync_n : std_logic := '1'; +signal hsync_reset : std_logic := '0'; + + +begin + +Divider: process(clk_12) +begin + if rising_edge(clk_12) then + Clk_6 <= (not Clk_6); + end if; +end process; + + +-- Horizontal counter is 8 bits long plus additional flip flop. The last 4 bit IC in the chain resets to 0010 so total count resets to 128 +-- using only the last three count states +H_count: process(clk_6) +begin + if rising_edge(clk_6) then + if h_counter = "111111111" then + h_counter <= "010000000"; + else + h_counter <= h_counter + 1; + end if; + end if; +end process; + +-- Vertical counter is 8 bits, clocked by the rising edge of HSync at the end of each horizontal line +V_count: process(hsync_int) +begin + if rising_edge(Hsync_int) then + if vreset_n = '0' then + v_counter <= (others => '0'); + else + v_counter <= v_counter + '1'; + end if; + end if; +end process; + +-- Many Atari raster games use a prom to decode vertical sync signals +-- This could be replaced by combinatorial logic +P8: entity work.sprom +generic map( + init_file => "rtl/roms/30024-01p8.hex", + widthad_a => 9, + width_a => 4) +port map( + clock => clk_12, + address => '1' & sync_reg(3) & V128 & V64 & V32 & V16 & V8 & V4 & V2, + q => sync_bus + ); + +--P8: entity work.sync_prom +--port map( +-- clock => clk_12, +-- address => '1' & sync_reg(3) & V128 & V64 & V32 & V16 & V8 & V4 & V2, +-- q => sync_bus +-- ); + +-- Register fed by the sync PROM, in the original hardware this also creates the complements of these signals +sync_register: process(hsync_n) +begin + if rising_edge(hsync_n) then + sync_reg <= sync_bus; + end if; +end process; + +-- Outputs of sync PROM +vblank_s <= sync_reg(3); +vblank_n_s <= not sync_reg(3); +vreset <= sync_reg(2); +vreset_n <= not sync_reg(2); +vblank <= sync_reg(1); +vsync <= sync_reg(0); + +-- A pair of D type flip-flops that generate the HBlank and HSync signals +HBlank_gen: process(H256_n, H32) +begin + if H256_n = '0' then + hblank_int <= '0'; + else + if rising_edge(H32) then + hblank_int <= not H64; + end if; + end if; +end process; + +HSync_gen: process(hblank_int, H8) +begin + if hblank_int = '0' then + hsync_int <= '0'; + hsync_n <= '1'; + else + if rising_edge(H8) then + hsync_int <= H32; + hsync_n <= (not H32); + end if; + end if; +end process; + +-- Assign various signals +H1 <= h_counter(0); +H2 <= h_counter(1); +H4 <= h_counter(2); +H8 <= h_counter(3); +H16 <= h_counter(4); +H32 <= h_counter(5); +H64 <= h_counter(6); +H128 <= h_counter(7); +H256 <= h_counter(8); +H4_n <= not H4; +H8_n <= not H8; +H256_n <= not H256; + +V1 <= v_counter(0); +V2 <= v_counter(1); +V4 <= v_counter(2); +V8 <= v_counter(3); +V16 <= v_counter(4); +V32 <= v_counter(5); +V64 <= v_counter(6); +V128 <= v_counter(7); + +hcount <= h_counter; +vcount <= v_counter; +hsync <= hsync_int; +hblank <= hblank_int; + +end rtl; \ No newline at end of file diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/ultra_tank.vhd b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/ultra_tank.vhd new file mode 100644 index 00000000..11a82e92 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/ultra_tank.vhd @@ -0,0 +1,288 @@ +-- Top level file for Kee Games Ultra Tank +-- (c) 2017 James Sweet +-- +-- This 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 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. + +-- Targeted to EP2C5T144C8 mini board but porting to nearly any FPGA should be fairly simple +-- See Ultra Tank manual for video output details. Resistor values listed here have been scaled +-- for 3.3V logic. + + +library IEEE; +use IEEE.STD_LOGIC_1164.all; + + +entity ultra_tank is +port( + clk_12 : in std_logic; -- 50MHz input clock + Reset_n : in std_logic; -- Reset button (Active low) + Video1_O : out std_logic; -- White video output (680 Ohm) + Video2_O : out std_logic; -- Black video output (1.2k) + Sync_O : out std_logic; -- Composite sync output (1.2k) + Blank_O : out std_logic; -- Composite blank output + HS : out std_logic; + VS : out std_logic; + HB : out std_logic; + VB : out std_logic; + CC3_n_O : out std_logic; -- Not sure what these are, color monitor? (not connected in real game) + CC2_O : out std_logic; + CC1_O : out std_logic; + CC0_O : out std_logic; + White_O : out std_logic; + Audio1_O : out std_logic_vector(6 downto 0); -- Ideally these should have a simple low pass filter + Audio2_O : out std_logic_vector(6 downto 0); + Coin1_I : in std_logic; -- Coin switches (Active low) + Coin2_I : in std_logic; + Start1_I : in std_logic; -- Start buttons + Start2_I : in std_logic; + Invisible_I : in std_logic; -- Invisible tanks switch + Rebound_I : in std_logic; -- Rebounding shells switch + Barrier_I : in std_logic; -- Barriers switch + JoyW_Fw_I : in std_logic; -- Joysticks, these are all active low + JoyW_Bk_I : in std_logic; + JoyY_Fw_I : in std_logic; + JoyY_Bk_I : in std_logic; + JoyX_Fw_I : in std_logic; + JoyX_Bk_I : in std_logic; + JoyZ_Fw_I : in std_logic; + JoyZ_Bk_I : in std_logic; + FireA_I : in std_logic; -- Fire buttons + FireB_I : in std_logic; + Test_I : in std_logic; -- Self-test switch + Slam_I : in std_logic; -- Slam switch + LED1_O : out std_logic; -- Player 1 and 2 start button LEDs + LED2_O : out std_logic; + Lockout_O : out std_logic -- Coin mech lockout coil + ); +end ultra_tank; + +architecture rtl of ultra_tank is + +signal Clk_6 : std_logic; +signal Phi1 : std_logic; +signal Phi2 : std_logic; + +signal Hcount : std_logic_vector(8 downto 0); +signal Vcount : std_logic_vector(7 downto 0) := (others => '0'); +signal H256_s : std_logic; +signal Hsync : std_logic; +signal Vsync : std_logic; +signal Vblank : std_logic; +signal Vblank_n_s : std_logic; +signal HBlank : std_logic; +signal CompBlank_s : std_logic; +signal CompSync_n_s : std_logic; + +signal DMA : std_logic_vector(7 downto 0); +signal DMA_n : std_logic_vector(7 downto 0); +signal PRAM : std_logic_vector(7 downto 0); +signal Load_n : std_logic_vector(8 downto 1); +signal Object : std_logic_vector(4 downto 1); +signal Object_n : std_logic_vector(4 downto 1); +signal Playfield_n : std_logic; + +signal CPU_Din : std_logic_vector(7 downto 0); +signal CPU_Dout : std_logic_vector(7 downto 0); +signal DBus_n : std_logic_vector(7 downto 0); +signal BA : std_logic_vector(15 downto 0); + +signal Barrier_Read_n : std_logic; +signal Throttle_Read_n : std_logic; +signal Coin_Read_n : std_logic; +signal Collision_Read_n : std_logic; +signal Collision_n : std_logic; +signal CollisionReset_n : std_logic_vector(4 downto 1); +signal Options_Read_n : std_logic; +signal Wr_DA_Latch_n : std_logic; +signal Wr_Explosion_n : std_logic; +signal Fire1 : std_logic; +signal Fire2 : std_logic; +signal Attract : std_logic; +signal Attract_n : std_logic; + +signal SW1 : std_logic_vector(7 downto 0); + + +begin +-- Configuration DIP switches, these can be brought out to external switches if desired +-- See Ultra Tank manual page 6 for complete information. Active low (0 = On, 1 = Off) +-- 1 2 Extended Play (11 - 75pts, 01 - 50pts, 10 - 25pts, 00 - None) +-- 3 4 Game Length (11 - 60sec, 10 - 90sec, 01 - 120sec, 00 - 150sec) +-- 5 6 Game Cost (10 - 1 Coin, 1 Play, 01 - 2 Plays, 1 Coin, 11 - 2 Coins, 1 Play) +-- 7 8 Unused? +SW1 <= "10010100"; -- Config dip switches + + + +Vid_sync: entity work.synchronizer +port map( + Clk_12 => Clk_12, + Clk_6 => Clk_6, + HCount => HCount, + VCount => VCount, + HSync => HSync, + HBlank => HBlank, + VBlank_n_s => VBlank_n_s, + VBlank => VBlank, + VSync => VSync + ); + + +Background: entity work.playfield +port map( + Clk6 => Clk_6, + DMA => DMA, + PRAM => PRAM, + Load_n => Load_n, + Object => Object, + HCount => HCount, + VCount => VCount, + HBlank => HBlank, + VBlank => VBlank, + VBlank_n_s => VBlank_n_s, + HSync => Hsync, + VSync => VSync, + H256_s => H256_s, + Playfield_n => Playfield_n, + CC3_n => CC3_n_O, + CC2 => CC2_O, + CC1 => CC1_O, + CC0 => CC0_O, + White => White_O, + PF_Vid1 => Video1_O, + PF_Vid2 => Video2_O + ); + + +Tank_Shells: entity work.motion +port map( + CLK6 => Clk_6, + PHI2 => Phi2, + DMA_n => DMA_n, + PRAM => PRAM, + H256_s => H256_s, + VCount => VCount, + HCount => HCount, + Load_n => Load_n, + Object => Object, + Object_n => Object_n + ); + + +Tank_Shell_Comparator: entity work.collision_detect +port map( + Clk6 => Clk_6, + Adr => BA(2 downto 0), + Object_n => Object_n, + Playfield_n => Playfield_n, + CollisionReset_n => CollisionReset_n, + Slam_n => Slam_I, + Collision_n => Collision_n + ); + + +CPU: entity work.cpu_mem +port map( + Clk12 => clk_12, + Clk6 => clk_6, + Reset_n => reset_n, + VCount => VCount, + HCount => HCount, + Vblank_n_s => Vblank_n_s, + Test_n => Test_I, + Collision_n => Collision_n, + DB_in => CPU_Din, + DBus => CPU_Dout, + DBus_n => DBus_n, + PRAM => PRAM, + ABus => BA, + Attract => Attract, + Attract_n => Attract_n, + CollReset_n => CollisionReset_n, + Barrier_Read_n => Barrier_Read_n, + Throttle_Read_n => Throttle_Read_n, + Coin_Read_n => Coin_Read_n, + Options_Read_n => Options_Read_n, + Wr_DA_Latch_n => Wr_DA_Latch_n, + Wr_Explosion_n => Wr_Explosion_n, + Fire1 => Fire1, + Fire2 => Fire2, + LED1 => LED1_O, + LED2 => LED2_O, + Lockout_n => Lockout_O, + Phi1_o => Phi1, + Phi2_o => Phi2, + DMA => DMA, + DMA_n => DMA_n + ); + + +Input: entity work.Control_Inputs +port map( + Clk6 => Clk_6, + DipSw => SW1, -- DIP switches + Coin1_n => Coin1_I, + Coin2_n => Coin2_I, + Start1_n => Start1_I, + Start2_n => Start2_I, + Invisible_n => Invisible_I, + Rebound_n => Rebound_I, + Barrier_n => Barrier_I, + JoyW_Fw => JoyW_Fw_I, + JoyW_Bk => JoyW_Bk_I, + JoyY_Fw => JoyY_Fw_I, + JoyY_Bk => JoyY_Bk_I, + JoyX_Fw => JoyX_Fw_I, + JoyX_Bk => JoyX_Bk_I, + JoyZ_Fw => JoyZ_Fw_I, + JoyZ_Bk => JoyZ_Bk_I, + FireA_n => FireA_I, + FireB_n => FireB_I, + Throttle_Read_n => Throttle_Read_n, + Coin_Read_n => Coin_Read_n, + Options_Read_n => Options_Read_n, + Barrier_Read_n => Barrier_Read_n, + Wr_DA_Latch_n => Wr_DA_Latch_n, + Adr => BA(2 downto 0), + DBus => CPU_Dout(3 downto 0), + Dout => CPU_Din + ); + + +Sound: entity work.audio +port map( + Clk_6 => Clk_6, + Reset_n => Reset_n, + Load_n => Load_n, + Fire1 => Fire1, + Fire2 => Fire2, + Write_Explosion_n => Wr_Explosion_n, + Attract => Attract, + Attract_n => Attract_n, + PRAM => PRAM, + DBus_n => not CPU_Dout, + HCount => HCount, + VCount => VCount, + Audio1 => Audio1_O, + Audio2 => Audio2_O + ); + +Sync_O <= HSync nor VSync; +Blank_O <= HBlank nor VBlank; + +HS <= HSync; +VS <= VSync; +HB <= HBlank; +VB <= VBlank; + +end rtl; \ No newline at end of file diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/ultratank_mist.sv b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/ultratank_mist.sv new file mode 100644 index 00000000..1b8a482d --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/ultratank_mist.sv @@ -0,0 +1,165 @@ +module ultratank_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 +); + +`include "rtl\build_id.sv" + +localparam CONF_STR = { + "Ultra Tank;;", + "O1,Test Mode,Off,On;", + "O34,Scandoubler Fx,None,HQ2x,CRT 25%,CRT 50%;", + "T6,Reset;", + "V,v1.00.",`BUILD_DATE +}; + +wire [31:0] status; +wire [1:0] buttons; +wire [1:0] switches; +wire [11:0] kbjoy; +wire [7:0] joystick_0; +wire [7:0] joystick_1; +wire scandoubler_disable; +wire ypbpr; +wire ps2_kbd_clk, ps2_kbd_data; +wire [6:0] audio1, audio2; +wire video1, video2; + +wire clk_48, clk_12; +wire locked; +pll pll +( + .inclk0(CLOCK_27), + .c0(clk_48),//48.384 + .c1(clk_12),//12.096 + .locked(locked) +); + +ultra_tank ultra_tank ( + .clk_12(clk_12), + .Reset_n(~(status[0] | status[6] | buttons[1])), + .Video1_O(video1),// White video output (680 Ohm) + .Video2_O(video2),// Black video output (1.2k) + .Sync_O(), + .Blank_O(), + .HS(hs), + .VS(vs), + .HB(vb), + .VB(hb), + .CC3_n_O(),// Not sure what these are, color monitor? (not connected in real game) + .CC2_O(), + .CC1_O(), + .CC0_O(), + .White_O(), + .Audio1_O(audio1), + .Audio2_O(audio2), + .Coin1_I(~kbjoy[7]), + .Coin2_I(~kbjoy[7]), + .Start1_I(~kbjoy[5]), + .Start2_I(~kbjoy[6]), + .Invisible_I(),// Invisible tanks switch + .Rebound_I(),// Rebounding shells switch + .Barrier_I(),// Barriers switch + .JoyW_Fw_I(~kbjoy[3]), + .JoyW_Bk_I(~kbjoy[2]), + .JoyY_Fw_I(~kbjoy[1]), + .JoyY_Bk_I(~kbjoy[0]), + .JoyX_Fw_I(), + .JoyX_Bk_I(), + .JoyZ_Fw_I(), + .JoyZ_Bk_I(), + .FireA_I(~kbjoy[4]), + .FireB_I(), + .Test_I(~status[1]), + .Slam_I(), + .LED1_O(), + .LED2_O(), + .Lockout_O() +); + +dac dac1 ( + .CLK(clk_48), + .RESET(1'b0), + .DACin(audio1), + .DACout(AUDIO_L) + ); + +dac dac2 ( + .CLK(clk_48), + .RESET(1'b0), + .DACin(audio2), + .DACout(AUDIO_R) + ); + +wire hs, vs; +wire hb, vb; +wire blankn = ~(hb | vb); +video_mixer #(.LINE_LENGTH(480), .HALF_DEPTH(1)) video_mixer +( + .clk_sys(clk_48), + .ce_pix(clk_12), + .ce_pix_actual(clk_12), + .SPI_SCK(SPI_SCK), + .SPI_SS3(SPI_SS3), + .SPI_DI(SPI_DI), + .R(blankn ? {video1&video2,video1&video2,video1&video2} : "000"), + .G(blankn ? {video1&video2,video1&video2,video1&video2} : "000"), + .B(blankn ? {video1&video2,video1&video2,video1&video2} : "000"), + .HSync(hs), + .VSync(vs), + .VGA_R(VGA_R), + .VGA_G(VGA_G), + .VGA_B(VGA_B), + .VGA_VS(VGA_VS), + .VGA_HS(VGA_HS), + .scandoubler_disable(scandoubler_disable), + .scanlines(scandoubler_disable ? 2'b00 : {status[4:3] == 3, status[4:3] == 2}), + .hq2x(status[4:3]==1), + .ypbpr_full(1), + .line_start(0), + .mono(0) +); + +mist_io #(.STRLEN(($size(CONF_STR)>>3))) mist_io +( + .clk_sys (clk_48 ), + .conf_str (CONF_STR ), + .SPI_SCK (SPI_SCK ), + .CONF_DATA0 (CONF_DATA0 ), + .SPI_SS2 (SPI_SS2 ), + .SPI_DO (SPI_DO ), + .SPI_DI (SPI_DI ), + .buttons (buttons ), + .switches (switches ), + .scandoubler_disable(scandoubler_disable), + .ypbpr (ypbpr ), + .ps2_kbd_clk (ps2_kbd_clk ), + .ps2_kbd_data (ps2_kbd_data ), + .joystick_0 (joystick_0 ), + .joystick_1 (joystick_1 ), + .status (status ) +); + +keyboard keyboard( + .clk(clk_48), + .reset(), + .ps2_kbd_clk(ps2_kbd_clk), + .ps2_kbd_data(ps2_kbd_data), + .joystick(kbjoy) + ); + + +endmodule diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/video_mixer.sv b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/video_mixer.sv new file mode 100644 index 00000000..04cfd4ba --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/rtl/video_mixer.sv @@ -0,0 +1,242 @@ +// +// +// Copyright (c) 2017 Sorgelig +// +// This program is GPL Licensed. See COPYING for the full license. +// +// +//////////////////////////////////////////////////////////////////////////////////////////////////////// + +`timescale 1ns / 1ps + +// +// LINE_LENGTH: Length of display line in pixels +// Usually it's length from HSync to HSync. +// May be less if line_start is used. +// +// HALF_DEPTH: If =1 then color dept is 3 bits per component +// For half depth 6 bits monochrome is available with +// mono signal enabled and color = {G, R} + +module video_mixer +#( + parameter LINE_LENGTH = 768, + parameter HALF_DEPTH = 0, + + parameter OSD_COLOR = 3'd4, + parameter OSD_X_OFFSET = 10'd0, + parameter OSD_Y_OFFSET = 10'd0 +) +( + // master clock + // it should be multiple by (ce_pix*4). + input clk_sys, + + // Pixel clock or clock_enable (both are accepted). + input ce_pix, + + // Some systems have multiple resolutions. + // ce_pix_actual should match ce_pix where every second or fourth pulse is enabled, + // thus half or qurter resolutions can be used without brake video sync while switching resolutions. + // For fixed single resolution (or when video sync stability isn't required) ce_pix_actual = ce_pix. + input ce_pix_actual, + + // OSD SPI interface + input SPI_SCK, + input SPI_SS3, + input SPI_DI, + + // scanlines (00-none 01-25% 10-50% 11-75%) + input [1:0] scanlines, + + // 0 = HVSync 31KHz, 1 = CSync 15KHz + input scandoubler_disable, + + // High quality 2x scaling + input hq2x, + + // YPbPr always uses composite sync + input ypbpr, + + // 0 = 16-240 range. 1 = 0-255 range. (only for YPbPr color space) + input ypbpr_full, + + // color + input [DWIDTH:0] R, + input [DWIDTH:0] G, + input [DWIDTH:0] B, + + // Monochrome mode (for HALF_DEPTH only) + input mono, + + // interlace sync. Positive pulses. + input HSync, + input VSync, + + // Falling of this signal means start of informative part of line. + // It can be horizontal blank signal. + // This signal can be used to reduce amount of required FPGA RAM for HQ2x scan doubler + // If FPGA RAM is not an issue, then simply set it to 0 for whole line processing. + // Keep in mind: due to algo first and last pixels of line should be black to avoid side artefacts. + // Thus, if blank signal is used to reduce the line, make sure to feed at least one black (or paper) pixel + // before first informative pixel. + input line_start, + + // MiST video output signals + output [5:0] VGA_R, + output [5:0] VGA_G, + output [5:0] VGA_B, + output VGA_VS, + output VGA_HS +); + +localparam DWIDTH = HALF_DEPTH ? 2 : 5; + +wire [DWIDTH:0] R_sd; +wire [DWIDTH:0] G_sd; +wire [DWIDTH:0] B_sd; +wire hs_sd, vs_sd; + +scandoubler #(.LENGTH(LINE_LENGTH), .HALF_DEPTH(HALF_DEPTH)) scandoubler +( + .*, + .hs_in(HSync), + .vs_in(VSync), + .r_in(R), + .g_in(G), + .b_in(B), + + .hs_out(hs_sd), + .vs_out(vs_sd), + .r_out(R_sd), + .g_out(G_sd), + .b_out(B_sd) +); + +wire [DWIDTH:0] rt = (scandoubler_disable ? R : R_sd); +wire [DWIDTH:0] gt = (scandoubler_disable ? G : G_sd); +wire [DWIDTH:0] bt = (scandoubler_disable ? B : B_sd); + +generate + if(HALF_DEPTH) begin + wire [5:0] r = mono ? {gt,rt} : {rt,rt}; + wire [5:0] g = mono ? {gt,rt} : {gt,gt}; + wire [5:0] b = mono ? {gt,rt} : {bt,bt}; + end else begin + wire [5:0] r = rt; + wire [5:0] g = gt; + wire [5:0] b = bt; + end +endgenerate + +wire hs = (scandoubler_disable ? HSync : hs_sd); +wire vs = (scandoubler_disable ? VSync : vs_sd); + +reg scanline = 0; +always @(posedge clk_sys) begin + reg old_hs, old_vs; + + old_hs <= hs; + old_vs <= vs; + + if(old_hs && ~hs) scanline <= ~scanline; + if(old_vs && ~vs) scanline <= 0; +end + +wire [5:0] r_out, g_out, b_out; +always @(*) begin + case(scanlines & {scanline, scanline}) + 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 + + default: begin + r_out = r; + g_out = g; + b_out = b; + end + endcase +end + +wire [5:0] red, green, blue; +osd #(OSD_X_OFFSET, OSD_Y_OFFSET, OSD_COLOR) osd +( + .*, + + .R_in(r_out), + .G_in(g_out), + .B_in(b_out), + .HSync(hs), + .VSync(vs), + + .R_out(red), + .G_out(green), + .B_out(blue) +); + +wire [5:0] yuv_full[225] = '{ + 6'd0, 6'd0, 6'd0, 6'd0, 6'd1, 6'd1, 6'd1, 6'd1, + 6'd2, 6'd2, 6'd2, 6'd3, 6'd3, 6'd3, 6'd3, 6'd4, + 6'd4, 6'd4, 6'd5, 6'd5, 6'd5, 6'd5, 6'd6, 6'd6, + 6'd6, 6'd7, 6'd7, 6'd7, 6'd7, 6'd8, 6'd8, 6'd8, + 6'd9, 6'd9, 6'd9, 6'd9, 6'd10, 6'd10, 6'd10, 6'd11, + 6'd11, 6'd11, 6'd11, 6'd12, 6'd12, 6'd12, 6'd13, 6'd13, + 6'd13, 6'd13, 6'd14, 6'd14, 6'd14, 6'd15, 6'd15, 6'd15, + 6'd15, 6'd16, 6'd16, 6'd16, 6'd17, 6'd17, 6'd17, 6'd17, + 6'd18, 6'd18, 6'd18, 6'd19, 6'd19, 6'd19, 6'd19, 6'd20, + 6'd20, 6'd20, 6'd21, 6'd21, 6'd21, 6'd21, 6'd22, 6'd22, + 6'd22, 6'd23, 6'd23, 6'd23, 6'd23, 6'd24, 6'd24, 6'd24, + 6'd25, 6'd25, 6'd25, 6'd25, 6'd26, 6'd26, 6'd26, 6'd27, + 6'd27, 6'd27, 6'd27, 6'd28, 6'd28, 6'd28, 6'd29, 6'd29, + 6'd29, 6'd29, 6'd30, 6'd30, 6'd30, 6'd31, 6'd31, 6'd31, + 6'd31, 6'd32, 6'd32, 6'd32, 6'd33, 6'd33, 6'd33, 6'd33, + 6'd34, 6'd34, 6'd34, 6'd35, 6'd35, 6'd35, 6'd35, 6'd36, + 6'd36, 6'd36, 6'd36, 6'd37, 6'd37, 6'd37, 6'd38, 6'd38, + 6'd38, 6'd38, 6'd39, 6'd39, 6'd39, 6'd40, 6'd40, 6'd40, + 6'd40, 6'd41, 6'd41, 6'd41, 6'd42, 6'd42, 6'd42, 6'd42, + 6'd43, 6'd43, 6'd43, 6'd44, 6'd44, 6'd44, 6'd44, 6'd45, + 6'd45, 6'd45, 6'd46, 6'd46, 6'd46, 6'd46, 6'd47, 6'd47, + 6'd47, 6'd48, 6'd48, 6'd48, 6'd48, 6'd49, 6'd49, 6'd49, + 6'd50, 6'd50, 6'd50, 6'd50, 6'd51, 6'd51, 6'd51, 6'd52, + 6'd52, 6'd52, 6'd52, 6'd53, 6'd53, 6'd53, 6'd54, 6'd54, + 6'd54, 6'd54, 6'd55, 6'd55, 6'd55, 6'd56, 6'd56, 6'd56, + 6'd56, 6'd57, 6'd57, 6'd57, 6'd58, 6'd58, 6'd58, 6'd58, + 6'd59, 6'd59, 6'd59, 6'd60, 6'd60, 6'd60, 6'd60, 6'd61, + 6'd61, 6'd61, 6'd62, 6'd62, 6'd62, 6'd62, 6'd63, 6'd63, + 6'd63 +}; + +// http://marsee101.blog19.fc2.com/blog-entry-2311.html +// Y = 16 + 0.257*R + 0.504*G + 0.098*B (Y = 0.299*R + 0.587*G + 0.114*B) +// Pb = 128 - 0.148*R - 0.291*G + 0.439*B (Pb = -0.169*R - 0.331*G + 0.500*B) +// Pr = 128 + 0.439*R - 0.368*G - 0.071*B (Pr = 0.500*R - 0.419*G - 0.081*B) + +wire [18:0] y_8 = 19'd04096 + ({red, 8'd0} + {red, 3'd0}) + ({green, 9'd0} + {green, 2'd0}) + ({blue, 6'd0} + {blue, 5'd0} + {blue, 2'd0}); +wire [18:0] pb_8 = 19'd32768 - ({red, 7'd0} + {red, 4'd0} + {red, 3'd0}) - ({green, 8'd0} + {green, 5'd0} + {green, 3'd0}) + ({blue, 8'd0} + {blue, 7'd0} + {blue, 6'd0}); +wire [18:0] pr_8 = 19'd32768 + ({red, 8'd0} + {red, 7'd0} + {red, 6'd0}) - ({green, 8'd0} + {green, 6'd0} + {green, 5'd0} + {green, 4'd0} + {green, 3'd0}) - ({blue, 6'd0} + {blue , 3'd0}); + +wire [7:0] y = ( y_8[17:8] < 16) ? 8'd16 : ( y_8[17:8] > 235) ? 8'd235 : y_8[15:8]; +wire [7:0] pb = (pb_8[17:8] < 16) ? 8'd16 : (pb_8[17:8] > 240) ? 8'd240 : pb_8[15:8]; +wire [7:0] pr = (pr_8[17:8] < 16) ? 8'd16 : (pr_8[17:8] > 240) ? 8'd240 : pr_8[15:8]; + +assign VGA_R = ypbpr ? (ypbpr_full ? yuv_full[pr-8'd16] : pr[7:2]) : red; +assign VGA_G = ypbpr ? (ypbpr_full ? yuv_full[y -8'd16] : y[7:2]) : green; +assign VGA_B = ypbpr ? (ypbpr_full ? yuv_full[pb-8'd16] : pb[7:2]) : blue; +assign VGA_VS = (scandoubler_disable | ypbpr) ? 1'b1 : ~vs_sd; +assign VGA_HS = scandoubler_disable ? ~(HSync ^ VSync) : ypbpr ? ~(hs_sd ^ vs_sd) : ~hs_sd; + +endmodule diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/snapshot/ultratank.rbf b/Arcade_MiST/Custom Hardware/UltraTank_MiST/snapshot/ultratank.rbf new file mode 100644 index 0000000000000000000000000000000000000000..1dbe331a1554bf6caf2efa4cad74dbc2697e6175 GIT binary patch literal 246046 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
oVkFCeB)aN&;4 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 literal 0 HcmV?d00001 diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/ultratank.qpf b/Arcade_MiST/Custom Hardware/UltraTank_MiST/ultratank.qpf new file mode 100644 index 00000000..d63a5af5 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/ultratank.qpf @@ -0,0 +1,30 @@ +# -------------------------------------------------------------------------- # +# +# 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.0.1 Build 232 06/12/2013 Service Pack 1 SJ Web Edition +# Date created = 19:51:47 November 12, 2017 +# +# -------------------------------------------------------------------------- # + +QUARTUS_VERSION = "13.0" +DATE = "19:51:47 November 12, 2017" + +# Revisions + +PROJECT_REVISION = "ultratank" diff --git a/Arcade_MiST/Custom Hardware/UltraTank_MiST/ultratank.qsf b/Arcade_MiST/Custom Hardware/UltraTank_MiST/ultratank.qsf new file mode 100644 index 00000000..f175df88 --- /dev/null +++ b/Arcade_MiST/Custom Hardware/UltraTank_MiST/ultratank.qsf @@ -0,0 +1,174 @@ +# -------------------------------------------------------------------------- # +# +# 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 Web Edition +# Date created = 15:18:38 May 31, 2018 +# +# -------------------------------------------------------------------------- # +# +# Notes: +# +# 1) The default values for assignments are stored in the file: +# sprint1_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 ORIGINAL_QUARTUS_VERSION "13.0 SP1" +set_global_assignment -name PROJECT_CREATION_TIME_DATE "19:52:16 OCTOBER 10, 2017" +set_global_assignment -name LAST_QUARTUS_VERSION 13.1 +set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files + +# Analysis & Synthesis Assignments +# ================================ +set_global_assignment -name FAMILY "Cyclone III" +set_global_assignment -name ALLOW_POWER_UP_DONT_CARE OFF +set_global_assignment -name SYNTH_TIMING_DRIVEN_SYNTHESIS OFF +set_global_assignment -name DEVICE_FILTER_PIN_COUNT 144 +set_global_assignment -name DEVICE_FILTER_SPEED_GRADE 8 +set_global_assignment -name TOP_LEVEL_ENTITY ultratank_mist + +# Fitter Assignments +# ================== +set_global_assignment -name DEVICE EP3C25E144C8 +set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "3.3-V LVTTL" +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 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 USE_CONFIGURATION_DEVICE OFF +set_global_assignment -name GENERATE_RBF_FILE ON + +# SignalTap II Assignments +# ======================== +set_global_assignment -name ENABLE_SIGNALTAP OFF +set_global_assignment -name USE_SIGNALTAP_FILE output_files/stp3.stp + +# 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(sprint1) +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_46 -to UART_TX +set_location_assignment PIN_31 -to UART_RX +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_90 -to SPI_SS4 +set_location_assignment PIN_13 -to CONF_DATA0 +# end ENTITY(sprint1) +# ------------------- + +# -------------------------- +# start ENTITY(sprint1_mist) + + # start DESIGN_PARTITION(Top) + # --------------------------- + + # Incremental Compilation Assignments + # =================================== + + # end DESIGN_PARTITION(Top) + # ------------------------- + +# end ENTITY(sprint1_mist) +# ------------------------ +set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 +set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85 +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)" +set_global_assignment -name SYSTEMVERILOG_FILE rtl/ultratank_mist.sv +set_global_assignment -name VHDL_FILE rtl/ultra_tank.vhd +set_global_assignment -name VERILOG_FILE rtl/pll.v +set_global_assignment -name VHDL_FILE rtl/sync.vhd +set_global_assignment -name VHDL_FILE rtl/collision.vhd +set_global_assignment -name VHDL_FILE rtl/screech.vhd +set_global_assignment -name VHDL_FILE rtl/cpu_mem.vhd +set_global_assignment -name VHDL_FILE rtl/playfield.vhd +set_global_assignment -name VHDL_FILE rtl/EngineSound.vhd +set_global_assignment -name VHDL_FILE rtl/Inputs.vhd +set_global_assignment -name VHDL_FILE rtl/motion.vhd +set_global_assignment -name SYSTEMVERILOG_FILE rtl/video_mixer.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/scandoubler.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/osd.sv +set_global_assignment -name VHDL_FILE rtl/sprom.vhd +set_global_assignment -name SYSTEMVERILOG_FILE rtl/mist_io.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/keyboard.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/hq2x.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/dac.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/build_id.sv +set_global_assignment -name VHDL_FILE rtl/T65/T65_Pack.vhd +set_global_assignment -name VHDL_FILE rtl/T65/T65_MCode.vhd +set_global_assignment -name VHDL_FILE rtl/T65/T65_ALU.vhd +set_global_assignment -name VHDL_FILE rtl/T65/T65.vhd +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_global_assignment -name VHDL_FILE rtl/spram.vhd +set_global_assignment -name VHDL_FILE rtl/sound.vhd +set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file