1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-02-28 09:07:40 +00:00

Jaleco Blue Print add Files

This commit is contained in:
Marcel
2026-02-19 13:51:11 +01:00
parent 275e792b2d
commit 7dcaed2c15
23 changed files with 3051 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
# -------------------------------------------------------------------------- #
#
# 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 = 17:44:51 March 04, 2019
#
# -------------------------------------------------------------------------- #
QUARTUS_VERSION = "13.1"
DATE = "17:44:51 March 04, 2019"
# Revisions
PROJECT_REVISION = "BluePrint"

View File

@@ -0,0 +1,271 @@
# -------------------------------------------------------------------------- #
#
# Copyright (C) 1991-2013 Altera Corporation
# Your use of Altera Corporation's design tools, logic functions
# and other software and tools, and its AMPP partner logic
# functions, and any output files from any of the foregoing
# (including device programming or simulation files), and any
# associated documentation or information are expressly subject
# to the terms and conditions of the Altera Program License
# Subscription Agreement, Altera MegaCore Function License
# Agreement, or other applicable license agreement, including,
# without limitation, that your use is for the sole purpose of
# programming logic devices manufactured by Altera and sold by
# Altera or its authorized distributors. Please refer to the
# applicable agreement for further details.
#
# -------------------------------------------------------------------------- #
#
# Quartus II 64-Bit
# Version 13.1.0 Build 162 10/23/2013 SJ Web Edition
# Date created = 13:46:56 February 19, 2026
#
# -------------------------------------------------------------------------- #
#
# Notes:
#
# 1) The default values for assignments are stored in the file:
# BluePrint_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.1
set_global_assignment -name PROJECT_CREATION_TIME_DATE "23:59:05 MARCH 16, 2017"
set_global_assignment -name LAST_QUARTUS_VERSION 13.1
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:rtl/build_id.tcl"
set_global_assignment -name SYSTEMVERILOG_FILE rtl/BluePrint.sv
set_global_assignment -name SYSTEMVERILOG_FILE rtl/BluePrint_Top.sv
set_global_assignment -name SYSTEMVERILOG_FILE rtl/BluePrint_CPU.sv
set_global_assignment -name SYSTEMVERILOG_FILE rtl/BluePrint_SND.sv
set_global_assignment -name VHDL_FILE rtl/dpram_dc.vhd
set_global_assignment -name VHDL_FILE rtl/spram.vhd
set_global_assignment -name VERILOG_FILE rtl/Filters/jt49_dcrm2.v
set_global_assignment -name VERILOG_FILE rtl/jtframe_frac_cen.v
set_global_assignment -name SYSTEMVERILOG_FILE rtl/rom_loader.sv
set_global_assignment -name VHDL_FILE rtl/pll.vhd
set_global_assignment -name QIP_FILE ../../common/mist/mist.qip
set_global_assignment -name QIP_FILE ../../common/CPU/T80/T80.qip
set_global_assignment -name QIP_FILE ../../common/Sound/JT49/jt49.qip
# Pin & Location Assignments
# ==========================
set_location_assignment PIN_54 -to CLOCK_27
set_location_assignment PIN_7 -to LED
set_location_assignment PIN_144 -to VGA_R[5]
set_location_assignment PIN_143 -to VGA_R[4]
set_location_assignment PIN_142 -to VGA_R[3]
set_location_assignment PIN_141 -to VGA_R[2]
set_location_assignment PIN_137 -to VGA_R[1]
set_location_assignment PIN_135 -to VGA_R[0]
set_location_assignment PIN_133 -to VGA_B[5]
set_location_assignment PIN_132 -to VGA_B[4]
set_location_assignment PIN_125 -to VGA_B[3]
set_location_assignment PIN_121 -to VGA_B[2]
set_location_assignment PIN_120 -to VGA_B[1]
set_location_assignment PIN_115 -to VGA_B[0]
set_location_assignment PIN_114 -to VGA_G[5]
set_location_assignment PIN_113 -to VGA_G[4]
set_location_assignment PIN_112 -to VGA_G[3]
set_location_assignment PIN_111 -to VGA_G[2]
set_location_assignment PIN_110 -to VGA_G[1]
set_location_assignment PIN_106 -to VGA_G[0]
set_location_assignment PIN_136 -to VGA_VS
set_location_assignment PIN_119 -to VGA_HS
set_location_assignment PIN_65 -to AUDIO_L
set_location_assignment PIN_80 -to AUDIO_R
set_location_assignment PIN_105 -to SPI_DO
set_location_assignment PIN_88 -to SPI_DI
set_location_assignment PIN_126 -to SPI_SCK
set_location_assignment PIN_127 -to SPI_SS2
set_location_assignment PIN_91 -to SPI_SS3
set_location_assignment PIN_90 -to SPI_SS4
set_location_assignment PIN_13 -to CONF_DATA0
set_location_assignment PIN_49 -to SDRAM_A[0]
set_location_assignment PIN_44 -to SDRAM_A[1]
set_location_assignment PIN_42 -to SDRAM_A[2]
set_location_assignment PIN_39 -to SDRAM_A[3]
set_location_assignment PIN_4 -to SDRAM_A[4]
set_location_assignment PIN_6 -to SDRAM_A[5]
set_location_assignment PIN_8 -to SDRAM_A[6]
set_location_assignment PIN_10 -to SDRAM_A[7]
set_location_assignment PIN_11 -to SDRAM_A[8]
set_location_assignment PIN_28 -to SDRAM_A[9]
set_location_assignment PIN_50 -to SDRAM_A[10]
set_location_assignment PIN_30 -to SDRAM_A[11]
set_location_assignment PIN_32 -to SDRAM_A[12]
set_location_assignment PIN_83 -to SDRAM_DQ[0]
set_location_assignment PIN_79 -to SDRAM_DQ[1]
set_location_assignment PIN_77 -to SDRAM_DQ[2]
set_location_assignment PIN_76 -to SDRAM_DQ[3]
set_location_assignment PIN_72 -to SDRAM_DQ[4]
set_location_assignment PIN_71 -to SDRAM_DQ[5]
set_location_assignment PIN_69 -to SDRAM_DQ[6]
set_location_assignment PIN_68 -to SDRAM_DQ[7]
set_location_assignment PIN_86 -to SDRAM_DQ[8]
set_location_assignment PIN_87 -to SDRAM_DQ[9]
set_location_assignment PIN_98 -to SDRAM_DQ[10]
set_location_assignment PIN_99 -to SDRAM_DQ[11]
set_location_assignment PIN_100 -to SDRAM_DQ[12]
set_location_assignment PIN_101 -to SDRAM_DQ[13]
set_location_assignment PIN_103 -to SDRAM_DQ[14]
set_location_assignment PIN_104 -to SDRAM_DQ[15]
set_location_assignment PIN_58 -to SDRAM_BA[0]
set_location_assignment PIN_51 -to SDRAM_BA[1]
set_location_assignment PIN_85 -to SDRAM_DQMH
set_location_assignment PIN_67 -to SDRAM_DQML
set_location_assignment PIN_60 -to SDRAM_nRAS
set_location_assignment PIN_64 -to SDRAM_nCAS
set_location_assignment PIN_66 -to SDRAM_nWE
set_location_assignment PIN_59 -to SDRAM_nCS
set_location_assignment PIN_33 -to SDRAM_CKE
set_location_assignment PIN_43 -to SDRAM_CLK
set_location_assignment PIN_31 -to UART_RX
set_location_assignment PIN_46 -to UART_TX
set_location_assignment PLL_1 -to pll|altpll_component|auto_generated|pll1
# Classic Timing Assignments
# ==========================
set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
set_global_assignment -name TIMEQUEST_MULTICORNER_ANALYSIS ON
# Analysis & Synthesis Assignments
# ================================
set_global_assignment -name FAMILY "Cyclone III"
set_global_assignment -name DEVICE_FILTER_PACKAGE TQFP
set_global_assignment -name DEVICE_FILTER_PIN_COUNT 144
set_global_assignment -name DEVICE_FILTER_SPEED_GRADE 8
set_global_assignment -name VERILOG_INPUT_VERSION SYSTEMVERILOG_2005
set_global_assignment -name VERILOG_SHOW_LMF_MAPPING_MESSAGES OFF
set_global_assignment -name TOP_LEVEL_ENTITY BluePrint
set_global_assignment -name CYCLONEII_OPTIMIZATION_TECHNIQUE SPEED
set_global_assignment -name SYNTH_TIMING_DRIVEN_SYNTHESIS ON
set_global_assignment -name ALLOW_SYNCH_CTRL_USAGE OFF
set_global_assignment -name VHDL_INPUT_VERSION VHDL_2008
set_global_assignment -name VHDL_SHOW_LMF_MAPPING_MESSAGES OFF
# Fitter Assignments
# ==================
set_global_assignment -name DEVICE EP3C25E144C8
set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 1
set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "3.3-V LVTTL"
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"
set_global_assignment -name OPTIMIZE_HOLD_TIMING "ALL PATHS"
set_global_assignment -name OPTIMIZE_MULTI_CORNER_TIMING ON
set_global_assignment -name FITTER_EFFORT "STANDARD FIT"
set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC OFF
set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_RETIMING OFF
set_global_assignment -name PHYSICAL_SYNTHESIS_ASYNCHRONOUS_SIGNAL_PIPELINING OFF
set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_DUPLICATION OFF
set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC_FOR_AREA OFF
set_global_assignment -name PHYSICAL_SYNTHESIS_MAP_LOGIC_TO_MEMORY_FOR_AREA OFF
# EDA Netlist Writer Assignments
# ==============================
set_global_assignment -name EDA_SIMULATION_TOOL "<None>"
# 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/custom.stp
# Power Estimation Assignments
# ============================
set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "NO HEAT SINK WITH STILL AIR"
set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)"
# Advanced I/O Timing Assignments
# ===============================
set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -rise
set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -fall
set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -rise
set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -fall
# start EDA_TOOL_SETTINGS(eda_simulation)
# ---------------------------------------
# EDA Netlist Writer Assignments
# ==============================
set_global_assignment -name EDA_OUTPUT_DATA_FORMAT NONE -section_id eda_simulation
# end EDA_TOOL_SETTINGS(eda_simulation)
# -------------------------------------
# -----------------------
# start ENTITY(BluePrint)
# Pin & Location Assignments
# ==========================
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[*]
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_A[*]
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_BA[0]
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_BA[1]
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQMH
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQML
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nRAS
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nCAS
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nWE
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nCS
set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[*]
set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[*]
# Fitter Assignments
# ==================
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_A[*]
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[*]
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_BA[*]
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQML
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQMH
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nRAS
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nCAS
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nWE
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nCS
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_CKE
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_CLK
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_R[*]
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_G[*]
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_B[*]
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_HS
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_VS
set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to AUDIO_L
set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to AUDIO_R
set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SPI_DO
# start DESIGN_PARTITION(Top)
# ---------------------------
# Incremental Compilation Assignments
# ===================================
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
# end DESIGN_PARTITION(Top)
# -------------------------
# end ENTITY(BluePrint)
# ---------------------
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

View File

@@ -0,0 +1,53 @@
#************************************************************
# THIS IS A WIZARD-GENERATED FILE.
#
# Version 13.1.4 Build 182 03/12/2014 SJ Full Version
#
#************************************************************
# Copyright (C) 1991-2014 Altera Corporation
# Your use of Altera Corporation's design tools, logic functions
# and other software and tools, and its AMPP partner logic
# functions, and any output files from any of the foregoing
# (including device programming or simulation files), and any
# associated documentation or information are expressly subject
# to the terms and conditions of the Altera Program License
# Subscription Agreement, Altera MegaCore Function License
# Agreement, or other applicable license agreement, including,
# without limitation, that your use is for the sole purpose of
# programming logic devices manufactured by Altera and sold by
# Altera or its authorized distributors. Please refer to the
# applicable agreement for further details.
# Clock constraints
create_clock -name {SPI_SCK} -period 41.666 -waveform { 20.8 41.666 } [get_ports {SPI_SCK}]
# Automatically constrain PLL and other generated clocks
derive_pll_clocks -create_base_clocks
# Automatically calculate clock uncertainty to jitter and other effects.
derive_clock_uncertainty
set_clock_groups -asynchronous -group [get_clocks {SPI_SCK}] -group [get_clocks {pll|altpll_component|auto_generated|pll1|clk[*]}]
set sys_clk "pll|altpll_component|auto_generated|pll1|clk[0]"
set sdram_clk "pll|altpll_component|auto_generated|pll1|clk[1]"
set_output_delay -add_delay -clock_fall -clock [get_clocks $sys_clk] 1.000 [get_ports {AUDIO_L}]
set_output_delay -add_delay -clock_fall -clock [get_clocks $sys_clk] 1.000 [get_ports {AUDIO_R}]
set_output_delay -add_delay -clock_fall -clock [get_clocks $sys_clk] 1.000 [get_ports {LED}]
set_output_delay -add_delay -clock_fall -clock [get_clocks $sys_clk] 1.000 [get_ports {VGA_*}]
# SDRAM delays
set_input_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -max 6.6 [get_ports SDRAM_DQ[*]]
set_input_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -min 3.5 [get_ports SDRAM_DQ[*]]
set_output_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -max 1.5 [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}]
set_output_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -min -0.8 [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}]
set_multicycle_path -to {VGA_*[*]} -setup 2
set_multicycle_path -to {VGA_*[*]} -hold 1

View File

@@ -0,0 +1 @@
# Arcade-BluePrint_MiSTer-

View File

@@ -0,0 +1,15 @@
@echo off
del /s *.bak
del /s *.orig
del /s *.rej
rmdir /s /q db
rmdir /s /q incremental_db
rmdir /s /q output_files
rmdir /s /q simulation
rmdir /s /q greybox_tmp
del PLLJ_PLLSPE_INFO.txt
del *.qws
del *.ppf
del *.qip
del *.ddb
pause

View File

@@ -0,0 +1,63 @@
<misterromdescription>
<n>Blue Print (Jaleco)</n>
<region>Japan</region>
<homebrew>no</homebrew>
<bootleg>no</bootleg>
<version></version>
<alternative></alternative>
<platform></platform>
<series></series>
<year>1982</year>
<manufacturer>Zilec Electronics / Bally Midway</manufacturer>
<category>Maze</category>
<setname>blueprnt</setname>
<parent>blueprnt</parent>
<mameversion>0220</mameversion>
<rbf>BluePrint</rbf>
<about></about>
<resolution>15kHz</resolution>
<rotation>vertical (ccw)</rotation>
<flip>no</flip>
<players>2 (alternating)</players>
<joystick>4-way</joystick>
<special_controls></special_controls>
<num_buttons>1</num_buttons>
<button_names></button_names>
<switches default="00,00">
<!-- DIP Switch 1 -->
<dip bits="4,5" name="Bonus Life" ids="20K/100K+,40K/200K+,80K/400K+,120K/600K+"/>
<dip bits="6,7" name="Lives" ids="2,3,4,5"/>
<!-- DIP Switch 2 -->
<dip bits="8,9" name="Coinage" ids="2c/1cr,1c/1cr,1c/2cr,1c/3cr"/>
<dip bits="11" name="Cabinet" ids="Upright,Cocktail"/>
<dip bits="12,13" name="Difficulty" ids="Level 1,Level 2,Level 3,Level 4"/>
</switches>
<rom index="0" md5="none" zip="blueprnt.zip|blueprntj.zip">
<!-- Main CPU ROMs (5× 4KB = 20KB) -->
<part crc="2e746693" name="bp-1j.1m"/>
<part crc="a0eb0b8e" name="bp-2j.1n"/>
<part crc="c34981bb" name="bp-3j.1p"/>
<part crc="525e77b5" name="bp-4j.1r"/>
<part crc="431a015f" name="bp-5j.1s"/>
<!-- Tile ROMs (2× 4KB = 8KB) -->
<part crc="43718c34" name="bg-1j.3c"/>
<part crc="d3ce077d" name="bg-2j.3d"/>
<!-- Sprite ROMs (3× 4KB = 12KB, R/B/G bitplanes) -->
<part crc="83da108f" name="redj.17d"/>
<part crc="b440f32f" name="bluej.18d"/>
<part crc="23026765" name="greenj.20d"/>
</rom>
<rom index="1" md5="none" zip="blueprnt.zip|blueprntj.zip">
<!-- Sound CPU ROMs (2× 4KB = 8KB) -->
<part crc="fd38777a" name="snd-1.3u"/>
<part crc="33d5bf5b" name="snd-2.3v"/>
</rom>
<remark></remark>
<mratimestamp>20260213000000</mratimestamp>
</misterromdescription>

View File

@@ -0,0 +1,63 @@
<misterromdescription>
<n>Blue Print (Midway)</n>
<region>World</region>
<homebrew>no</homebrew>
<bootleg>no</bootleg>
<version></version>
<alternative></alternative>
<platform></platform>
<series></series>
<year>1982</year>
<manufacturer>Zilec Electronics / Bally Midway</manufacturer>
<category>Maze</category>
<setname>blueprnt</setname>
<parent>blueprnt</parent>
<mameversion>0220</mameversion>
<rbf>BluePrint</rbf>
<about></about>
<resolution>15kHz</resolution>
<rotation>vertical (ccw)</rotation>
<flip>no</flip>
<players>2 (alternating)</players>
<joystick>4-way</joystick>
<special_controls></special_controls>
<num_buttons>1</num_buttons>
<button_names></button_names>
<switches default="00,00">
<!-- DIP Switch 1 -->
<dip bits="4,5" name="Bonus Life" ids="20K/100K+,40K/200K+,80K/400K+,120K/600K+"/>
<dip bits="6,7" name="Lives" ids="2,3,4,5"/>
<!-- DIP Switch 2 -->
<dip bits="8,9" name="Coinage" ids="2c/1cr,1c/1cr,1c/2cr,1c/3cr"/>
<dip bits="11" name="Cabinet" ids="Upright,Cocktail"/>
<dip bits="12,13" name="Difficulty" ids="Level 1,Level 2,Level 3,Level 4"/>
</switches>
<rom index="0" md5="none" zip="blueprnt.zip">
<!-- Main CPU ROMs (5× 4KB = 20KB) -->
<part crc="b20069a6" name="bp-1.1m"/>
<part crc="4a30302e" name="bp-2.1n"/>
<part crc="6866ca07" name="bp-3.1p"/>
<part crc="5d3cfac3" name="bp-4.1r"/>
<part crc="a556cac4" name="bp-5.1s"/>
<!-- Tile ROMs (2× 4KB = 8KB) -->
<part crc="ac2a61bc" name="bg-1.3c"/>
<part crc="81fe85d7" name="bg-2.3d"/>
<!-- Sprite ROMs (3× 4KB = 12KB, R/B/G bitplanes) -->
<part crc="a73b6483" name="red.17d"/>
<part crc="7d622550" name="blue.18d"/>
<part crc="09c7a518" name="green.20d"/>
</rom>
<rom index="1" md5="none" zip="blueprnt.zip">
<!-- Sound CPU ROMs (2× 4KB = 8KB) -->
<part crc="fd38777a" name="snd-1.3u"/>
<part crc="33d5bf5b" name="snd-2.3v"/>
</rom>
<remark></remark>
<mratimestamp>20260213000000</mratimestamp>
</misterromdescription>

View File

@@ -0,0 +1,249 @@
// Port to MiST
// Copyright (C) 2026 Rodimus
//
// Blue Print for MiST
// Based on Time Pilot port, original design Copyright (C) 2017 Dar
// Initial port to MiSTer Copyright (C) 2017 Sorgelig
// Updated port to MiSTer Copyright (C) 2021, 2022 Ace,
// Ash Evans (aka ElectronAsh/OzOnE), Artemio Urbina and Kitrinx (aka Rysha)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
//============================================================================
module BluePrint(
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.v"
localparam CONF_STR = {
"BluePrint;rom;",
"O1,Blend,Off,On;",
"O2,Rotate Controls,Off,On;",
"O34,Scanlines,Off,25%,50%,75%;",
"OOR,CRT H adjust,0,+1,+2,+3,+4,+5,+6,+7,-8,-7,-6,-5,-4,-3,-2,-1;",
"OSV,CRT V adjust,0,+1,+2,+3,+4,+5,+6,+7,-8,-7,-6,-5,-4,-3,-2,-1;",
// "O58,H Center,0,-1,-2,-3,-4,-5,-6,-7,+7,+6,+5,+4,+3,+2,+1;",
// "O9C,V Center,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12;",
"DIP;",
"T0,Reset;",
"V,v1.0.",`BUILD_DATE
};
wire blend = status[1];
wire rotate = status[2];
wire [1:0] orientation = 2'b10;
wire [1:0] scanlines = status[4:3];
//wire service = status[7];
assign LED = ~ioctl_downl;
assign AUDIO_R = AUDIO_L;
wire clk_sys;
wire pll_locked;
pll pll(
.inclk0(CLOCK_27),
.areset(0),
.c0(clk_sys),//49.152000
.locked(pll_locked)
);
wire [63:0] status;
wire [1:0] buttons;
wire [1:0] switches;
wire [31:0] joystick_0;
wire [31:0] joystick_1;
wire scandoublerD;
wire ypbpr;
wire no_csync;
wire key_pressed;
wire [7:0] key_code;
wire key_strobe;
wire ioctl_downl;
wire [7:0] ioctl_index;
wire ioctl_wr;
wire [24:0] ioctl_addr;
wire [7:0] ioctl_dout;
wire [15:0] audio;
wire hs, vs, cs, hb, vb;
wire blankn = ~(hb | vb);
wire [4:0] r, g, b;
wire [ 3:0] hoffset, voffset;
assign { voffset, hoffset } = status[31:24];
// DIP SWITCHES
reg [7:0] dip_sw[8]; // Active-LOW
always @(posedge clk_sys) begin
if(ioctl_wr && (ioctl_index==254) && !ioctl_addr[24:3])
dip_sw[ioctl_addr[2:0]] <= ioctl_dout;
end
wire [7:0] p1_controls = {m_down, m_up, m_right, m_left, m_fireA, 1'b0, m_one_player, m_coin1};
wire [7:0] p2_controls = {m_down2, m_up2, m_right2, m_left2, m_fire2A, 1'b0, m_two_players, m_coin2};
user_io #(
.STRLEN(($size(CONF_STR)>>3)))
user_io(
.clk_sys (clk_sys ),
.conf_str (CONF_STR ),
.SPI_CLK (SPI_SCK ),
.SPI_SS_IO (CONF_DATA0 ),
.SPI_MISO (SPI_DO ),
.SPI_MOSI (SPI_DI ),
.buttons (buttons ),
.switches (switches ),
.scandoubler_disable (scandoublerD ),
.ypbpr (ypbpr ),
.no_csync (no_csync ),
.key_strobe (key_strobe ),
.key_pressed (key_pressed ),
.key_code (key_code ),
.joystick_0 (joystick_0 ),
.joystick_1 (joystick_1 ),
.status (status )
);
data_io data_io (
.clk_sys ( clk_sys ),
.SPI_SCK ( SPI_SCK ),
.SPI_SS2 ( SPI_SS2 ),
.SPI_DI ( SPI_DI ),
.ioctl_download( ioctl_downl ),
.ioctl_index ( ioctl_index ),
.ioctl_wr ( ioctl_wr ),
.ioctl_addr ( ioctl_addr ),
.ioctl_dout ( ioctl_dout )
);
reg reset = 1;
reg rom_loaded = 0;
always @(posedge clk_sys) begin
reg ioctl_downlD;
ioctl_downlD <= ioctl_downl;
if (ioctl_downlD & ~ioctl_downl) rom_loaded <= 1;
reset <= status[0] | buttons[1] | ~rom_loaded;
end
BluePrint_Top BluePrint_Top(
.reset (~reset),
.clk_49m (clk_sys),
.p1_controls (p1_controls),
.p2_controls (p2_controls),
.dip_sw ({dip_sw[1], dip_sw[0]}),
.video_hsync (hs),
.video_vsync (vs),
.video_csync (cs),
.video_hblank (hb),
.video_vblank (vb),
.ce_pix (),
.video_r (r),
.video_g (g),
.video_b (b),
.sound (audio),
.h_center (hoffset),
.v_center (voffset),
// ROM loading
.ioctl_addr (ioctl_addr),
.ioctl_data (ioctl_dout),
.ioctl_wr (ioctl_wr),
.ioctl_index (ioctl_index),
.pause (0),
// Hiscore interface
.hs_address (),
.hs_data_in (),
.hs_data_out (),
.hs_write ()
);
mist_video #(.COLOR_DEPTH(5), .SD_HCNT_WIDTH(11)) mist_video(
.clk_sys ( clk_sys ),
.SPI_SCK ( SPI_SCK ),
.SPI_SS3 ( SPI_SS3 ),
.SPI_DI ( SPI_DI ),
.R ( blankn ? r : 0 ),
.G ( blankn ? g : 0 ),
.B ( blankn ? b : 0 ),
.HSync ( ~hs ),
.VSync ( ~vs ),
.VGA_R ( VGA_R ),
.VGA_G ( VGA_G ),
.VGA_B ( VGA_B ),
.VGA_VS ( VGA_VS ),
.VGA_HS ( VGA_HS ),
.scandoubler_disable( scandoublerD ),
.rotate ( { orientation[1], rotate } ),
.scanlines ( scanlines ),
.ypbpr ( ypbpr ),
.no_csync ( no_csync ),
.ce_divider ( 1'b0 ),
.blend ( blend )
);
dac #(
.C_bits(16))
dac(
.clk_i(clk_sys),
.res_n_i(1'b1),
.dac_i(audio),
.dac_o(AUDIO_L)
);
wire m_up, m_down, m_left, m_right, m_fireA, m_fireB, m_fireC, m_fireD, m_fireE, m_fireF;
wire m_up2, m_down2, m_left2, m_right2, m_fire2A, m_fire2B, m_fire2C, m_fire2D, m_fire2E, m_fire2F;
wire m_tilt, m_coin1, m_coin2, m_coin3, m_coin4, m_one_player, m_two_players, m_three_players, m_four_players;
arcade_inputs inputs (
.clk ( clk_sys ),
.key_strobe ( key_strobe ),
.key_pressed ( key_pressed ),
.key_code ( key_code ),
.joystick_0 ( joystick_0 ),
.joystick_1 ( joystick_1 ),
.rotate ( rotate ),
.orientation ( orientation ),
.joyswap ( 1'b0 ),
.oneplayer ( 1'b0 ),
.controls ( {m_tilt, m_coin4, m_coin3, m_coin2, m_coin1, m_four_players, m_three_players, m_two_players, m_one_player} ),
.player1 ( {m_fireF, m_fireE, m_fireD, m_fireC, m_fireB, m_fireA, m_up, m_down, m_left, m_right} ),
.player2 ( {m_fire2F, m_fire2E, m_fire2D, m_fire2C, m_fire2B, m_fire2A, m_up2, m_down2, m_left2, m_right2} )
);
endmodule

View File

@@ -0,0 +1,653 @@
//============================================================================
//
// Blue Print main CPU board model
// Copyright (C) 2026 Rodimus
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
//============================================================================
module BluePrint_CPU
(
input reset,
input clk_49m,
// Video outputs
output [4:0] red, green, blue,
output video_hsync, video_vsync, video_csync,
output video_hblank, video_vblank,
output ce_pix,
// Player controls (active HIGH, directly from MiSTer)
input [7:0] p1_controls, // {coin, start2, start1, btn1, left, down, right, up}
input [7:0] p2_controls, // {3'b111, btn1, left, down, right, up}
// DIP switch readback from sound board
input [7:0] dipsw_readback, // from sound board AY1 port A
// Sound interface (directly to sound board)
output [7:0] sound_cmd,
output sound_cmd_wr,
// Screen centering
input [3:0] h_center, v_center,
// ROM loading
input main1_cs_i, main2_cs_i, main3_cs_i, main4_cs_i, main5_cs_i,
input tile0_cs_i, tile1_cs_i,
input spr_r_cs_i, spr_b_cs_i, spr_g_cs_i,
input [24:0] ioctl_addr,
input [7:0] ioctl_data,
input ioctl_wr,
input pause,
// Hiscore interface
input [15:0] hs_address,
input [7:0] hs_data_in,
output [7:0] hs_data_out,
input hs_write
);
//------------------------------------------------------- Clock enables -------------------------------------------------------//
// Generate ~5 MHz pixel clock enable from 49.152 MHz
// 49.152 * 89/875 ≈ 4.997 MHz
wire [1:0] pix_cen_o;
jtframe_frac_cen #(2) pix_cen
(
.clk(clk_49m),
.n(10'd89),
.m(10'd875),
.cen(pix_cen_o),
.cenb()
);
wire cen_5m = pix_cen_o[0];
// Generate ~3.5 MHz CPU clock enable from 49.152 MHz
// 49.152 * 5/70 ≈ 3.511 MHz
wire [1:0] cpu_cen_o;
jtframe_frac_cen #(2) cpu_cen
(
.clk(clk_49m),
.n(10'd5),
.m(10'd70),
.cen(cpu_cen_o),
.cenb()
);
wire cen_3m5 = cpu_cen_o[0];
assign ce_pix = cen_5m;
//-------------------------------------------------------- Video timing --------------------------------------------------------//
// H counter 0-319, V counter 0-263
// From MAME: set_raw(5MHz, 320, 0, 256, 264, 16, 240)
reg [8:0] h_cnt = 9'd0;
reg [8:0] v_cnt = 9'd0;
always_ff @(posedge clk_49m) begin
if (cen_5m) begin
if (h_cnt == 9'd319) begin
h_cnt <= 9'd0;
v_cnt <= (v_cnt == 9'd263) ? 9'd0 : v_cnt + 9'd1;
end else
h_cnt <= h_cnt + 9'd1;
end
end
// Blanking
wire hblk = (h_cnt >= 9'd256);
wire vblk = (v_cnt < 9'd16) | (v_cnt >= 9'd240);
assign video_hblank = hblk;
assign video_vblank = vblk;
// Sync generation with screen centering offsets
wire [8:0] hs_start = 9'd280 + {5'd0, h_center};
wire [8:0] hs_end = hs_start + 9'd32;
wire [8:0] vs_start = 9'd248 + {5'd0, v_center};
wire [8:0] vs_end = vs_start + 9'd4;
assign video_hsync = (h_cnt >= hs_start && h_cnt < hs_end);
assign video_vsync = (v_cnt >= vs_start && v_cnt < vs_end);
assign video_csync = ~(video_hsync ^ video_vsync);
//------------------------------------------------------------ CPU -------------------------------------------------------------//
// Main CPU - Zilog Z80 (T80s soft core)
wire [15:0] z80_A;
wire [7:0] z80_Dout;
wire n_mreq, n_iorq, n_rd, n_wr, n_rfsh, n_m1;
T80s cpu
(
.RESET_n(reset),
.CLK(clk_49m),
.CEN(cen_3m5 & ~pause),
.INT_n(n_irq),
.NMI_n(1'b1),
.WAIT_n(1'b1),
.MREQ_n(n_mreq),
.IORQ_n(n_iorq),
.RD_n(n_rd),
.WR_n(n_wr),
.RFSH_n(n_rfsh),
.M1_n(n_m1),
.A(z80_A),
.DI(z80_Din),
.DO(z80_Dout)
);
//--------------------------------------------------------- Interrupts ---------------------------------------------------------//
// VBlank IRQ (irq0_line_hold style): assert on VBlank rising edge, clear on IORQ+M1
reg n_irq = 1'b1;
reg vblk_last = 1'b0;
wire irq_ack = ~n_iorq & ~n_m1;
always_ff @(posedge clk_49m) begin
if (!reset) begin
n_irq <= 1'b1;
vblk_last <= 1'b0;
end else begin
if (irq_ack)
n_irq <= 1'b1;
else if (vblk && !vblk_last)
n_irq <= 1'b0;
vblk_last <= vblk;
end
end
//------------------------------------------------------ Address decoding ------------------------------------------------------//
wire mem_valid = ~n_mreq & n_rfsh;
wire cs_rom = mem_valid & ~z80_A[15] & (z80_A[14:13] != 2'b11); // 0x0000-0x5FFF
wire cs_wram = mem_valid & (z80_A[15:11] == 5'b10000); // 0x8000-0x87FF
wire cs_vram = mem_valid & (z80_A[15:12] == 4'h9); // 0x9000-0x9FFF
wire cs_scroll = mem_valid & (z80_A[15:8] == 8'hA0); // 0xA000-0xA0FF
wire cs_sprite = mem_valid & (z80_A[15:8] == 8'hB0); // 0xB000-0xB0FF
wire cs_io_c = mem_valid & (z80_A[15:12] == 4'hC); // 0xC000-0xCFFF
wire cs_sndcmd = mem_valid & (z80_A[15:12] == 4'hD) & ~n_wr; // 0xD000 write
wire cs_e000 = mem_valid & (z80_A[15:12] == 4'hE); // 0xE000
wire cs_cram = mem_valid & (z80_A[15:12] == 4'hF); // 0xF000-0xFFFF
//------------------------------------------------------------ ROMs ------------------------------------------------------------//
// Main program ROMs (5x 4KB)
wire [7:0] rom1_D, rom2_D, rom3_D, rom4_D, rom5_D;
eprom_4k main_rom1(.CLK(clk_49m), .ADDR(z80_A[11:0]), .CLK_DL(clk_49m), .ADDR_DL(ioctl_addr), .DATA_IN(ioctl_data), .CS_DL(main1_cs_i), .WR(ioctl_wr), .DATA(rom1_D));
eprom_4k main_rom2(.CLK(clk_49m), .ADDR(z80_A[11:0]), .CLK_DL(clk_49m), .ADDR_DL(ioctl_addr), .DATA_IN(ioctl_data), .CS_DL(main2_cs_i), .WR(ioctl_wr), .DATA(rom2_D));
eprom_4k main_rom3(.CLK(clk_49m), .ADDR(z80_A[11:0]), .CLK_DL(clk_49m), .ADDR_DL(ioctl_addr), .DATA_IN(ioctl_data), .CS_DL(main3_cs_i), .WR(ioctl_wr), .DATA(rom3_D));
eprom_4k main_rom4(.CLK(clk_49m), .ADDR(z80_A[11:0]), .CLK_DL(clk_49m), .ADDR_DL(ioctl_addr), .DATA_IN(ioctl_data), .CS_DL(main4_cs_i), .WR(ioctl_wr), .DATA(rom4_D));
eprom_4k main_rom5(.CLK(clk_49m), .ADDR(z80_A[11:0]), .CLK_DL(clk_49m), .ADDR_DL(ioctl_addr), .DATA_IN(ioctl_data), .CS_DL(main5_cs_i), .WR(ioctl_wr), .DATA(rom5_D));
// ROM data mux based on address
wire [7:0] rom_D = (z80_A[14:12] == 3'd0) ? rom1_D :
(z80_A[14:12] == 3'd1) ? rom2_D :
(z80_A[14:12] == 3'd2) ? rom3_D :
(z80_A[14:12] == 3'd3) ? rom4_D :
(z80_A[14:12] == 3'd4) ? rom5_D :
8'hFF;
// Tile ROMs (2x 4KB) — addressed by rendering pipeline
wire [7:0] tile0_D, tile1_D;
reg [11:0] tile_render_addr;
eprom_4k tile_rom0(.CLK(clk_49m), .ADDR(tile_render_addr), .CLK_DL(clk_49m), .ADDR_DL(ioctl_addr), .DATA_IN(ioctl_data), .CS_DL(tile0_cs_i), .WR(ioctl_wr), .DATA(tile0_D));
eprom_4k tile_rom1(.CLK(clk_49m), .ADDR(tile_render_addr), .CLK_DL(clk_49m), .ADDR_DL(ioctl_addr), .DATA_IN(ioctl_data), .CS_DL(tile1_cs_i), .WR(ioctl_wr), .DATA(tile1_D));
// Sprite ROMs (3x 4KB) — addressed by sprite scanner
wire [7:0] spr_r_D, spr_b_D, spr_g_D;
reg [11:0] spr_render_addr;
eprom_4k spr_rom_r(.CLK(clk_49m), .ADDR(spr_render_addr), .CLK_DL(clk_49m), .ADDR_DL(ioctl_addr), .DATA_IN(ioctl_data), .CS_DL(spr_r_cs_i), .WR(ioctl_wr), .DATA(spr_r_D));
eprom_4k spr_rom_b(.CLK(clk_49m), .ADDR(spr_render_addr), .CLK_DL(clk_49m), .ADDR_DL(ioctl_addr), .DATA_IN(ioctl_data), .CS_DL(spr_b_cs_i), .WR(ioctl_wr), .DATA(spr_b_D));
eprom_4k spr_rom_g(.CLK(clk_49m), .ADDR(spr_render_addr), .CLK_DL(clk_49m), .ADDR_DL(ioctl_addr), .DATA_IN(ioctl_data), .CS_DL(spr_g_cs_i), .WR(ioctl_wr), .DATA(spr_g_D));
//-------------------------------------------------------------- RAM -----------------------------------------------------------//
// Work RAM (2KB, dual-port for hiscore)
wire [7:0] wram_D;
dpram_dc #(.widthad_a(11)) work_ram
(
.clock_a(clk_49m),
.wren_a(cs_wram & ~n_wr),
.address_a(z80_A[10:0]),
.data_a(z80_Dout),
.q_a(wram_D),
.clock_b(clk_49m),
.wren_b(hs_write),
.address_b(hs_address[10:0]),
.data_b(hs_data_in),
.q_b(hs_data_out)
);
// Video RAM (1KB) — port A: CPU, port B: video rendering
wire [7:0] vram_cpu_D, vram_render_D;
reg [9:0] vram_render_addr;
dpram_dc #(.widthad_a(10)) video_ram
(
.clock_a(clk_49m), .wren_a(cs_vram & ~n_wr),
.address_a(z80_A[9:0]), .data_a(z80_Dout), .q_a(vram_cpu_D),
.clock_b(clk_49m), .wren_b(1'b0),
.address_b(vram_render_addr), .data_b(8'd0), .q_b(vram_render_D)
);
// Color RAM (1KB) — port A: CPU, port B: video rendering
wire [7:0] cram_cpu_D, cram_render_D;
reg [9:0] cram_render_addr;
dpram_dc #(.widthad_a(10)) color_ram
(
.clock_a(clk_49m), .wren_a(cs_cram & ~n_wr),
.address_a(z80_A[9:0]), .data_a(z80_Dout), .q_a(cram_cpu_D),
.clock_b(clk_49m), .wren_b(1'b0),
.address_b(cram_render_addr), .data_b(8'd0), .q_b(cram_render_D)
);
// Scroll RAM (256 bytes) — port A: CPU, port B: video rendering
wire [7:0] scroll_cpu_D, scroll_render_D;
reg [7:0] scroll_render_addr;
dpram_dc #(.widthad_a(8)) scroll_ram
(
.clock_a(clk_49m), .wren_a(cs_scroll & ~n_wr),
.address_a(z80_A[7:0]), .data_a(z80_Dout), .q_a(scroll_cpu_D),
.clock_b(clk_49m), .wren_b(1'b0),
.address_b(scroll_render_addr), .data_b(8'd0), .q_b(scroll_render_D)
);
// Sprite RAM (256 bytes) — port A: CPU, port B: sprite scanner
wire [7:0] sprite_cpu_D, sprite_scan_D;
reg [7:0] sprite_scan_addr;
dpram_dc #(.widthad_a(8)) sprite_ram
(
.clock_a(clk_49m), .wren_a(cs_sprite & ~n_wr),
.address_a(z80_A[7:0]), .data_a(z80_Dout), .q_a(sprite_cpu_D),
.clock_b(clk_49m), .wren_b(1'b0),
.address_b(sprite_scan_addr), .data_b(8'd0), .q_b(sprite_scan_D)
);
//-------------------------------------------------------- I/O registers -------------------------------------------------------//
// Flip screen and gfx_bank (0xE000 write)
reg flip = 1'b0;
reg gfx_bank = 1'b0;
always_ff @(posedge clk_49m) begin
if (!reset) begin
flip <= 1'b0;
gfx_bank <= 1'b0;
end else if (cen_3m5 && cs_e000 && ~n_wr) begin
flip <= ~z80_Dout[1];
gfx_bank <= z80_Dout[2];
end
end
// Sound command (0xD000 write)
reg [7:0] snd_cmd_reg = 8'd0;
reg snd_cmd_wr_reg = 1'b0;
always_ff @(posedge clk_49m) begin
snd_cmd_wr_reg <= 1'b0;
if (cen_3m5 && cs_sndcmd) begin
snd_cmd_reg <= z80_Dout;
snd_cmd_wr_reg <= 1'b1;
end
end
assign sound_cmd = snd_cmd_reg;
assign sound_cmd_wr = snd_cmd_wr_reg;
//---------------------------------------------------- CPU data input mux -----------------------------------------------------//
wire [7:0] z80_Din = cs_rom ? rom_D :
(cs_wram & n_wr) ? wram_D :
(cs_vram & n_wr) ? vram_cpu_D :
(cs_cram & n_wr) ? cram_cpu_D :
(cs_scroll & n_wr) ? scroll_cpu_D :
(cs_sprite & n_wr) ? sprite_cpu_D :
(cs_io_c & ~n_rd & (z80_A[1:0] == 2'b00)) ? p1_controls :
(cs_io_c & ~n_rd & (z80_A[1:0] == 2'b01)) ? p2_controls :
(cs_io_c & ~n_rd & (z80_A[1:0] == 2'b11)) ? dipsw_readback :
8'hFF;
//--- Tilemap rendering pipeline ---
//
// TILEMAP_SCAN_COLS_FLIP_X layout: tile_index = (31 - col) * 32 + row
// VRAM/CRAM address: {(31 - screen_col), tile_row} (column-major, X-flipped)
//
// Timeline (all on cen_5m):
// fine_x=0: Transfer pipe→shifts. Start fetch for current col: set scroll_render_addr.
// fine_x=1: Scroll data ready. Compute scrolled_y. Set vram/cram addr.
// fine_x=2: Wait for VRAM/CRAM.
// fine_x=3: VRAM/CRAM data ready. Compute tile ROM addr. Update prev_bank_bit.
// fine_x=4: Tile ROM data ready. Latch into pipe_tile0/pipe_tile1.
// fine_x=5,6,7: Shift pixels out (MSB first).
reg [7:0] tile_shift0, tile_shift1; // Active shift registers (bit7 = current pixel)
reg [6:0] tile_color_latch; // Color byte latched for active column
reg tile_priority_latch; // Priority bit for active column
reg prev_bank_bit; // cram[6] from previous column (bank quirk)
reg [4:0] latched_col; // screen_col captured at fine_x=0
reg [7:0] pipe_tile0, pipe_tile1; // Pre-fetched tile ROM bytes
reg [6:0] pipe_color; // Pre-fetched color byte
reg pipe_priority; // Pre-fetched priority bit
reg [2:0] pipe_fine_y; // Fine Y for ROM address
wire [4:0] screen_col = h_cnt[7:3];
wire [2:0] fine_x = h_cnt[2:0];
wire [7:0] screen_y = v_cnt[7:0];
wire visible_line = (v_cnt >= 9'd16) && (v_cnt < 9'd240);
always_ff @(posedge clk_49m) begin
if (!reset) begin
tile_shift0 <= 8'd0;
tile_shift1 <= 8'd0;
tile_color_latch <= 7'd0;
tile_priority_latch <= 1'b0;
prev_bank_bit <= 1'b0;
latched_col <= 5'd0;
pipe_tile0 <= 8'd0;
pipe_tile1 <= 8'd0;
pipe_color <= 7'd0;
pipe_priority <= 1'b0;
pipe_fine_y <= 3'd0;
end else if (cen_5m) begin
if (!visible_line) begin
tile_shift0 <= 8'd0;
tile_shift1 <= 8'd0;
if (v_cnt == 9'd15 && h_cnt == 9'd0)
prev_bank_bit <= 1'b0;
end else begin
case (fine_x)
// fine_x=0: Transfer pipe to shift registers.
// Begin fetch for current column.
3'd0: begin
tile_shift0 <= pipe_tile0;
tile_shift1 <= pipe_tile1;
tile_color_latch <= pipe_color;
tile_priority_latch <= pipe_priority;
latched_col <= screen_col;
// scroll_ram[(30 - scr_col) & 0xFF]
scroll_render_addr <= 8'd30 - {3'd0, screen_col};
end
// fine_x=1: Scroll data ready. Compute scrolled Y, set VRAM/CRAM addr.
3'd1: begin
begin
reg [7:0] scrolled_y;
scrolled_y = screen_y + scroll_render_D;
pipe_fine_y <= scrolled_y[2:0];
// TILEMAP_SCAN_COLS_FLIP_X: VRAM col 0 = rightmost screen col (31)
vram_render_addr <= {(5'd31 - latched_col), scrolled_y[7:3]};
cram_render_addr <= {(5'd31 - latched_col), scrolled_y[7:3]};
end
tile_shift0 <= {tile_shift0[6:0], 1'b0};
tile_shift1 <= {tile_shift1[6:0], 1'b0};
end
// fine_x=2: Wait for VRAM/CRAM output to settle.
3'd2: begin
tile_shift0 <= {tile_shift0[6:0], 1'b0};
tile_shift1 <= {tile_shift1[6:0], 1'b0};
end
// fine_x=3: VRAM/CRAM data ready. Compute tile ROM address.
3'd3: begin
pipe_color <= cram_render_D[6:0];
pipe_priority <= cram_render_D[7];
// Bank bit from PREVIOUS column's cram[6], gated by gfx_bank register
tile_render_addr <= {prev_bank_bit & gfx_bank, vram_render_D, pipe_fine_y};
prev_bank_bit <= cram_render_D[6];
tile_shift0 <= {tile_shift0[6:0], 1'b0};
tile_shift1 <= {tile_shift1[6:0], 1'b0};
end
// fine_x=4: Tile ROM data ready. Latch into pipe.
3'd4: begin
pipe_tile0 <= tile0_D;
pipe_tile1 <= tile1_D;
tile_shift0 <= {tile_shift0[6:0], 1'b0};
tile_shift1 <= {tile_shift1[6:0], 1'b0};
end
// fine_x=5,6,7: Shift only.
default: begin
tile_shift0 <= {tile_shift0[6:0], 1'b0};
tile_shift1 <= {tile_shift1[6:0], 1'b0};
end
endcase
end
end
end
//--- Tile palette computation ---
// Shift left, MSB out first: tile_shift[7] = current pixel bit.
// Color bits are RBG order: cram bit0=R, bit1=B, bit2=G.
wire [1:0] tile_pixel = {tile_shift1[7], tile_shift0[7]};
wire tile_transparent = (tile_pixel == 2'b00);
wire tile_intensity = tile_color_latch[6];
wire [2:0] color_lo = tile_color_latch[2:0]; // RBG for pixel==01
wire [2:0] color_hi = tile_color_latch[5:3]; // RBG for pixel==10
wire [2:0] pen_rbg = (tile_pixel == 2'b01) ? color_lo :
(tile_pixel == 2'b10) ? color_hi :
(tile_pixel == 2'b11) ? (color_lo | color_hi) :
3'b000;
wire [4:0] r_tile = pen_rbg[0] ? (tile_intensity ? 5'd24 : 5'd31) : 5'd0;
wire [4:0] g_tile = pen_rbg[2] ? (tile_intensity ? 5'd24 : 5'd31) : 5'd0;
wire [4:0] b_tile = pen_rbg[1] ? (tile_intensity ? 5'd24 : 5'd31) : 5'd0;
//--- Sprite line buffers (double-buffered, 256×3-bit, 0 = transparent) ---
reg [2:0] linebuf0 [0:255];
reg [2:0] linebuf1 [0:255];
reg linebuf_sel = 1'b0; // 0: display buf0/write buf1; 1: display buf1/write buf0
// Swap at the start of each active line
always_ff @(posedge clk_49m) begin
if (!reset)
linebuf_sel <= 1'b0;
else if (cen_5m && h_cnt == 9'd0)
linebuf_sel <= ~linebuf_sel;
end
//--- Sprite scanner state machine (runs at clk_49m during HBlank) ---
// Sprites are 8×16. ROM address: {tile_code[7:0], line_in_sprite[3:0]}.
// flipY for sprite N comes from sprite N-1's byte2[7] (previous-sprite quirk).
reg [3:0] spr_state;
reg [5:0] spr_idx;
reg [7:0] spr_byte0; // Y position
reg [7:0] spr_byte1; // Tile code
reg [7:0] spr_byte2; // Flags: bit6=flipX, bit7=NEXT sprite's flipY
reg [7:0] spr_byte3; // X position
reg spr_flipy; // flipY for current sprite (from previous sprite's byte2[7])
reg prev_sprite_flipy; // Carry flipY forward
reg [7:0] spr_rom_r_lat, spr_rom_b_lat, spr_rom_g_lat;
reg [2:0] spr_pix_cnt;
reg [7:0] spr_clear_addr;
reg [7:0] next_scanline; // v_cnt of the line being prepared
localparam SPR_IDLE = 4'd0;
localparam SPR_CLEAR = 4'd1;
localparam SPR_INIT_RD = 4'd2;
localparam SPR_INIT_LAT = 4'd3;
localparam SPR_RD_B0 = 4'd4;
localparam SPR_RD_B1 = 4'd5;
localparam SPR_RD_B2 = 4'd6;
localparam SPR_RD_B3 = 4'd7;
localparam SPR_ROMADDR = 4'd8;
localparam SPR_ROMWAIT = 4'd9;
localparam SPR_PIXELS = 4'd10;
localparam SPR_NEXT = 4'd11;
always_ff @(posedge clk_49m) begin
if (!reset) begin
spr_state <= SPR_IDLE;
spr_idx <= 6'd0;
prev_sprite_flipy <= 1'b0;
spr_clear_addr <= 8'd0;
end else begin
case (spr_state)
SPR_IDLE: begin
if (cen_5m && h_cnt == 9'd256) begin
next_scanline <= v_cnt[7:0] + 8'd1;
spr_clear_addr <= 8'd0;
spr_state <= SPR_CLEAR;
end
end
SPR_CLEAR: begin
if (~linebuf_sel)
linebuf1[spr_clear_addr] <= 3'd0;
else
linebuf0[spr_clear_addr] <= 3'd0;
if (spr_clear_addr == 8'd255) begin
sprite_scan_addr <= 8'hFE; // sprite 63, byte 2
spr_state <= SPR_INIT_RD;
end else
spr_clear_addr <= spr_clear_addr + 8'd1;
end
SPR_INIT_RD: begin
spr_state <= SPR_INIT_LAT;
end
SPR_INIT_LAT: begin
prev_sprite_flipy <= sprite_scan_D[7];
spr_idx <= 6'd0;
sprite_scan_addr <= 8'd0; // sprite 0, byte 0
spr_state <= SPR_RD_B0;
end
SPR_RD_B0: begin
// RAM address already set; request byte 1 for next cycle
sprite_scan_addr <= {spr_idx, 2'd1};
spr_state <= SPR_RD_B1;
end
SPR_RD_B1: begin
// byte 0 (Y) now on bus; request byte 2
spr_byte0 <= sprite_scan_D;
sprite_scan_addr <= {spr_idx, 2'd2};
spr_state <= SPR_RD_B2;
end
SPR_RD_B2: begin
// byte 1 (tile code) now on bus; request byte 3
spr_byte1 <= sprite_scan_D;
sprite_scan_addr <= {spr_idx, 2'd3};
spr_state <= SPR_RD_B3;
end
SPR_RD_B3: begin
// byte 2 (flags) now on bus
spr_byte2 <= sprite_scan_D;
spr_flipy <= prev_sprite_flipy;
spr_state <= SPR_ROMADDR;
end
SPR_ROMADDR: begin
// byte 3 (X) now on bus
spr_byte3 <= sprite_scan_D;
prev_sprite_flipy <= spr_byte2[7];
begin
reg [8:0] raw_line;
// line_in_sprite = next_scanline - (sy - 1) = next_scanline - 239 + byte0
raw_line = {1'b0, next_scanline} - 9'd239 + {1'b0, spr_byte0};
if (raw_line[8] || raw_line[7:4] != 4'd0) begin
spr_state <= SPR_NEXT; // not on this scanline
end else begin
reg [3:0] line_in_sprite;
line_in_sprite = spr_flipy ? (4'd15 - raw_line[3:0]) : raw_line[3:0];
spr_render_addr <= {spr_byte1, line_in_sprite};
spr_state <= SPR_ROMWAIT;
end
end
end
SPR_ROMWAIT: begin
// ROM data valid this cycle; latch all three planes
spr_rom_r_lat <= spr_r_D;
spr_rom_b_lat <= spr_b_D;
spr_rom_g_lat <= spr_g_D;
spr_pix_cnt <= 3'd0;
spr_state <= SPR_PIXELS;
end
SPR_PIXELS: begin
begin
reg [2:0] bit_pos;
reg [2:0] pixel_val;
reg [7:0] x_pos;
// flipX: bit0 first (pixel 0 = LSB); normal: bit7 first (pixel 0 = MSB)
bit_pos = spr_byte2[6] ? spr_pix_cnt : (3'd7 - spr_pix_cnt);
pixel_val = {spr_rom_g_lat[bit_pos], spr_rom_b_lat[bit_pos], spr_rom_r_lat[bit_pos]};
x_pos = spr_byte3 + {5'd0, spr_pix_cnt} + 8'd2;
if (pixel_val != 3'd0) begin
if (~linebuf_sel)
linebuf1[x_pos] <= pixel_val;
else
linebuf0[x_pos] <= pixel_val;
end
if (spr_pix_cnt == 3'd7)
spr_state <= SPR_NEXT;
else
spr_pix_cnt <= spr_pix_cnt + 3'd1;
end
end
SPR_NEXT: begin
if (spr_idx == 6'd63)
spr_state <= SPR_IDLE;
else begin
spr_idx <= spr_idx + 6'd1;
sprite_scan_addr <= {spr_idx + 6'd1, 2'd0};
spr_state <= SPR_RD_B0;
end
end
default: spr_state <= SPR_IDLE;
endcase
end
end
//--- Sprite pixel readout ---
wire [2:0] sprite_pixel = linebuf_sel ? linebuf1[h_cnt[7:0]] : linebuf0[h_cnt[7:0]];
wire sprite_transparent = (sprite_pixel == 3'b000);
// Sprite pixel bits: bit0=R, bit1=B, bit2=G (full brightness only)
wire [4:0] r_sprite = sprite_pixel[0] ? 5'd31 : 5'd0;
wire [4:0] g_sprite = sprite_pixel[2] ? 5'd31 : 5'd0;
wire [4:0] b_sprite = sprite_pixel[1] ? 5'd31 : 5'd0;
//--- Compositing: priority-1 tiles > sprites > priority-0 tiles > black ---
wire [4:0] r_final = (tile_priority_latch && !tile_transparent) ? r_tile :
(!sprite_transparent) ? r_sprite :
r_tile;
wire [4:0] g_final = (tile_priority_latch && !tile_transparent) ? g_tile :
(!sprite_transparent) ? g_sprite :
g_tile;
wire [4:0] b_final = (tile_priority_latch && !tile_transparent) ? b_tile :
(!sprite_transparent) ? b_sprite :
b_tile;
assign red = (hblk | vblk) ? 5'd0 : r_final;
assign green = (hblk | vblk) ? 5'd0 : g_final;
assign blue = (hblk | vblk) ? 5'd0 : b_final;
endmodule

View File

@@ -0,0 +1,334 @@
//============================================================================
//
// Blue Print sound PCB model
// Copyright (C) 2026 Rodimus
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
//============================================================================
module BluePrint_SND
(
input reset,
input pause,
input clk_49m, // Master clock: 49.152MHz
// Sound command interface from main CPU
input [7:0] sound_cmd, // Sound command byte from main CPU latch
input sound_cmd_wr, // Pulse: main CPU wrote to 0xD000
// DIP switches (directly from MiSTer OSD)
input [15:0] dip_sw, // [7:0] = bank 1, [15:8] = bank 2
// DIP switch readback to main CPU
output [7:0] dipsw_readback, // Value main CPU reads at 0xC003
// Audio output
output signed [15:0] sound,
// VBlank input for IRQ generation (directly from video timing)
input vblank,
// ROM loading
input snd_rom1_cs_i, // Directly from ioctl for sound ROM 1
input snd_rom2_cs_i, // Directly from ioctl for sound ROM 2
input [24:0] ioctl_addr,
input [7:0] ioctl_data,
input ioctl_wr
);
//------------------------------------------------------- Clock division -------------------------------------------------------//
// Generate 1.25 MHz clock enable for sound Z80 and AY1, and 0.625 MHz for AY2
// 49.152 MHz * 25/983 ≈ 1.2489 MHz ≈ 1.25 MHz
// W=2: cen[0] = 1.25 MHz, cen[1] = 0.625 MHz
wire cen_1m25, cen_0m625;
jtframe_frac_cen #(2) sound_cen
(
.clk(clk_49m),
.n(10'd25),
.m(10'd983),
.cen({cen_0m625, cen_1m25})
);
// DC removal filter clock
reg [8:0] div = 9'd0;
always_ff @(posedge clk_49m) begin
div <= div + 9'd1;
end
wire cen_dcrm = !div;
//------------------------------------------------------------ CPU -------------------------------------------------------------//
// Sound CPU - Zilog Z80 (uses T80s version of the T80 soft core)
wire [15:0] sound_A;
wire [7:0] sound_Dout;
wire n_m1, n_mreq, n_iorq, n_rd, n_wr, n_rfsh;
T80s C8
(
.RESET_n(reset),
.CLK(clk_49m),
.CEN(cen_1m25 & ~pause),
.INT_n(n_irq),
.NMI_n(n_nmi),
.M1_n(n_m1),
.MREQ_n(n_mreq),
.IORQ_n(n_iorq),
.RD_n(n_rd),
.WR_n(n_wr),
.RFSH_n(n_rfsh),
.A(sound_A),
.DI(sound_Din),
.DO(sound_Dout)
);
// Address decoding for Z80
// ROM1: 0x0000-0x1FFF (A[15:13] = 000)
wire cs_rom1 = ~n_mreq & n_rfsh & ~sound_A[15] & ~sound_A[14] & ~sound_A[13];
// ROM2: 0x2000-0x3FFF (A[15:13] = 001)
wire cs_rom2 = ~n_mreq & n_rfsh & ~sound_A[15] & ~sound_A[14] & sound_A[13];
// RAM: 0x4000-0x5FFF (A[15:13] = 010)
wire cs_ram = ~n_mreq & n_rfsh & ~sound_A[15] & sound_A[14] & ~sound_A[13];
// AY1: 0x6000-0x7FFF (A[15:13] = 011)
wire cs_ay1_w = ~n_mreq & n_rfsh & ~sound_A[15] & sound_A[14] & sound_A[13] & ~n_wr;
wire cs_ay1_r = ~n_mreq & n_rfsh & ~sound_A[15] & sound_A[14] & sound_A[13] & ~n_rd;
// AY2: 0x8000-0x9FFF (A[15:13] = 100)
wire cs_ay2_w = ~n_mreq & n_rfsh & sound_A[15] & ~sound_A[14] & ~sound_A[13] & ~n_wr;
wire cs_ay2_r = ~n_mreq & n_rfsh & sound_A[15] & ~sound_A[14] & ~sound_A[13] & ~n_rd;
// AY bus control signals
// AY1: 0x6000/0x6001 write (address_data_w), 0x6002 read (data_r)
wire ay1_bdir = cs_ay1_w & (sound_A[1:0] != 2'b10); // write to 0x6000 or 0x6001
wire ay1_bc1 = (cs_ay1_w & ~sound_A[0] & ~sound_A[1]) | // address select: write to 0x6000
(cs_ay1_r & sound_A[1]); // data read: read from 0x6002
// AY2: 0x8000/0x8001 write (address_data_w), 0x8002 read (data_r)
wire ay2_bdir = cs_ay2_w & (sound_A[1:0] != 2'b10);
wire ay2_bc1 = (cs_ay2_w & ~sound_A[0] & ~sound_A[1]) |
(cs_ay2_r & sound_A[1]);
// Data reading flags for mux
wire ay1_reading = ~ay1_bdir & ay1_bc1;
wire ay2_reading = ~ay2_bdir & ay2_bc1;
// Multiplex data input to Z80
wire [7:0] sound_Din = cs_rom1 ? rom1_D :
cs_rom2 ? rom2_D :
(cs_ram & n_wr) ? sndram_D :
ay1_reading ? ay1_D :
ay2_reading ? ay2_D :
8'hFF;
//-------------------------------------------------------------- ROMs ----------------------------------------------------------//
// Sound ROM 1 (0x0000-0x0FFF, mirrored at 0x1000-0x1FFF)
wire [7:0] rom1_D;
eprom_4k snd_rom1
(
.CLK(clk_49m),
.ADDR(sound_A[11:0]),
.CLK_DL(clk_49m),
.ADDR_DL(ioctl_addr),
.DATA_IN(ioctl_data),
.CS_DL(snd_rom1_cs_i),
.WR(ioctl_wr),
.DATA(rom1_D)
);
// Sound ROM 2 (0x2000-0x2FFF, mirrored at 0x3000-0x3FFF)
wire [7:0] rom2_D;
eprom_4k snd_rom2
(
.CLK(clk_49m),
.ADDR(sound_A[11:0]),
.CLK_DL(clk_49m),
.ADDR_DL(ioctl_addr),
.DATA_IN(ioctl_data),
.CS_DL(snd_rom2_cs_i),
.WR(ioctl_wr),
.DATA(rom2_D)
);
//-------------------------------------------------------------- RAM -----------------------------------------------------------//
// Sound RAM (lower 4 bits) - 1KB at 0x4000-0x43FF
wire [7:0] sndram_D;
spram #(4, 10) A2
(
.clk(clk_49m),
.we(cs_ram & ~n_wr),
.addr(sound_A[9:0]),
.data(sound_Dout[3:0]),
.q(sndram_D[3:0])
);
// Sound RAM (upper 4 bits)
spram #(4, 10) A3
(
.clk(clk_49m),
.we(cs_ram & ~n_wr),
.addr(sound_A[9:0]),
.data(sound_Dout[7:4]),
.q(sndram_D[7:4])
);
//--------------------------------------------------------- Interrupts ---------------------------------------------------------//
// IRQ generation - 240 Hz periodic (4x per frame at 60 Hz)
// 1,250,000 Hz / 240 Hz = 5208.3 cycles
reg [12:0] irq_cnt = 13'd0;
reg irq_pulse = 1'b0;
always_ff @(posedge clk_49m) begin
if (cen_1m25) begin
if (irq_cnt == 13'd5207) begin
irq_cnt <= 13'd0;
irq_pulse <= 1'b1;
end else begin
irq_cnt <= irq_cnt + 13'd1;
irq_pulse <= 1'b0;
end
end else
irq_pulse <= 1'b0;
end
// IRQ latch - cleared by interrupt acknowledge
wire irq_clr = (~reset | ~(n_iorq | n_m1));
reg n_irq = 1'b1;
always_ff @(posedge clk_49m or posedge irq_clr) begin
if (irq_clr)
n_irq <= 1'b1;
else if (irq_pulse)
n_irq <= 1'b0;
end
// NMI generation - pulse triggered by main CPU writing to 0xD000
reg n_nmi = 1'b1;
reg sound_cmd_wr_last = 1'b0;
always_ff @(posedge clk_49m) begin
sound_cmd_wr_last <= sound_cmd_wr;
if (!sound_cmd_wr_last && sound_cmd_wr)
n_nmi <= 1'b0; // Assert NMI on rising edge of write
else if (cen_1m25)
n_nmi <= 1'b1; // Release after one CPU cycle
end
//--------------------------------------------------------- Sound chips --------------------------------------------------------//
// Sound chip 1 (AY-3-8910 @ 1.25 MHz - uses JT49 by Jotego)
// Port A = output: DIP switch data written by sound CPU → main CPU reads at 0xC003
// Port B = input: sound command latch from main CPU
wire [7:0] ay1_D;
wire [7:0] ay1A_raw, ay1B_raw, ay1C_raw;
jt49_bus #(.COMP(3'b100)) ay1_chip
(
.rst_n(reset),
.clk(clk_49m),
.clk_en(cen_1m25 & ~pause),
.bdir(ay1_bdir),
.bc1(ay1_bc1),
.din(sound_Dout),
.sel(1),
.dout(ay1_D),
.A(ay1A_raw),
.B(ay1B_raw),
.C(ay1C_raw),
.IOA_out(dipsw_readback),
.IOB_in(sound_cmd)
);
// Sound chip 2 (AY-3-8910 @ 0.625 MHz - HALF RATE - uses JT49 by Jotego)
// Port A = input: DIP switch bank 1
// Port B = input: DIP switch bank 2
wire [7:0] ay2_D;
wire [7:0] ay2A_raw, ay2B_raw, ay2C_raw;
jt49_bus #(.COMP(3'b100)) ay2_chip
(
.rst_n(reset),
.clk(clk_49m),
.clk_en(cen_0m625 & ~pause),
.bdir(ay2_bdir),
.bc1(ay2_bc1),
.din(sound_Dout),
.sel(1),
.dout(ay2_D),
.A(ay2A_raw),
.B(ay2B_raw),
.C(ay2C_raw),
.IOA_in(dip_sw[7:0]),
.IOB_in(dip_sw[15:8])
);
//----------------------------------------------------- Final audio output -----------------------------------------------------//
// Apply gain and remove DC offset from AY-3-8910s (uses jt49_dcrm2 from JT49 by Jotego)
wire signed [15:0] ay1A_dcrm, ay1B_dcrm, ay1C_dcrm, ay2A_dcrm, ay2B_dcrm, ay2C_dcrm;
jt49_dcrm2 #(16) dcrm_ay1A
(
.clk(clk_49m),
.cen(cen_dcrm),
.rst(~reset),
.din({3'd0, ay1A_raw, 5'd0}),
.dout(ay1A_dcrm)
);
jt49_dcrm2 #(16) dcrm_ay1B
(
.clk(clk_49m),
.cen(cen_dcrm),
.rst(~reset),
.din({3'd0, ay1B_raw, 5'd0}),
.dout(ay1B_dcrm)
);
jt49_dcrm2 #(16) dcrm_ay1C
(
.clk(clk_49m),
.cen(cen_dcrm),
.rst(~reset),
.din({3'd0, ay1C_raw, 5'd0}),
.dout(ay1C_dcrm)
);
jt49_dcrm2 #(16) dcrm_ay2A
(
.clk(clk_49m),
.cen(cen_dcrm),
.rst(~reset),
.din({3'd0, ay2A_raw, 5'd0}),
.dout(ay2A_dcrm)
);
jt49_dcrm2 #(16) dcrm_ay2B
(
.clk(clk_49m),
.cen(cen_dcrm),
.rst(~reset),
.din({3'd0, ay2B_raw, 5'd0}),
.dout(ay2B_dcrm)
);
jt49_dcrm2 #(16) dcrm_ay2C
(
.clk(clk_49m),
.cen(cen_dcrm),
.rst(~reset),
.din({3'd0, ay2C_raw, 5'd0}),
.dout(ay2C_dcrm)
);
// Mix all AY-3-8910 channels (no per-channel filters for Blue Print)
// Invert phase as the original PCB uses an inverting amplifier prior to the power amp
assign sound = 16'hFFFF - (ay1A_dcrm + ay1B_dcrm + ay1C_dcrm + ay2A_dcrm + ay2B_dcrm + ay2C_dcrm);
endmodule

View File

@@ -0,0 +1,170 @@
//============================================================================
//
// Port to MiSTer.
// Copyright (C) 2026 Rodimus
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
//============================================================================
module BluePrint_Top
(
input reset,
input clk_49m,
// Player controls (active HIGH, assembled from MiSTer inputs)
input [7:0] p1_controls,
input [7:0] p2_controls,
// DIP switches (directly from MiSTer OSD)
input [15:0] dip_sw,
// Video outputs
output video_hsync, video_vsync, video_csync,
output video_hblank, video_vblank,
output ce_pix,
output [4:0] video_r, video_g, video_b,
// Audio output
output signed [15:0] sound,
// Screen centering
input [3:0] h_center, v_center,
// ROM loading
input [24:0] ioctl_addr,
input [7:0] ioctl_data,
input ioctl_wr,
input [7:0] ioctl_index,
input pause,
// Hiscore interface
input [15:0] hs_address,
input [7:0] hs_data_in,
output [7:0] hs_data_out,
input hs_write
);
// Sound interface between CPU and sound board
wire [7:0] sound_cmd;
wire sound_cmd_wr;
// TEMPORARY: bypass sound board DIP readback until sound is verified working.
// The sound CPU reads dip_sw[7:0] from AY2 Port A and writes it to AY1 Port A
// which main CPU reads at 0xC003. Short-circuit this path for testing.
wire [7:0] dipsw_readback_from_snd;
wire [7:0] dipsw_readback = dipsw_readback_from_snd;
// ROM loader signals for MISTer (loads ROMs from SD card)
wire main1_cs_i, main2_cs_i, main3_cs_i, main4_cs_i, main5_cs_i;
wire tile0_cs_i, tile1_cs_i;
wire spr_r_cs_i, spr_b_cs_i, spr_g_cs_i;
// Filter ioctl_wr for index 0 (CPU board ROMs) and index 1 (sound ROMs)
wire ioctl_wr_cpu = ioctl_wr && (ioctl_index == 8'd0);
wire ioctl_wr_snd = ioctl_wr && (ioctl_index == 8'd1);
// Sound ROM chip selects (within index 1's address space)
wire snd_rom1_cs_i = (ioctl_addr < 25'h1000);
wire snd_rom2_cs_i = (ioctl_addr >= 25'h1000) && (ioctl_addr < 25'h2000);
// MiSTer data write selector (active for ROM index 0 only)
selector DLSEL
(
.ioctl_addr(ioctl_addr),
.main1_cs(main1_cs_i),
.main2_cs(main2_cs_i),
.main3_cs(main3_cs_i),
.main4_cs(main4_cs_i),
.main5_cs(main5_cs_i),
.tile0_cs(tile0_cs_i),
.tile1_cs(tile1_cs_i),
.spr_r_cs(spr_r_cs_i),
.spr_b_cs(spr_b_cs_i),
.spr_g_cs(spr_g_cs_i)
);
// Instantiate main CPU board
BluePrint_CPU main_pcb
(
.reset(reset),
.clk_49m(clk_49m),
.red(video_r),
.green(video_g),
.blue(video_b),
.video_hsync(video_hsync),
.video_vsync(video_vsync),
.video_csync(video_csync),
.video_hblank(video_hblank),
.video_vblank(video_vblank),
.ce_pix(ce_pix),
.p1_controls(p1_controls),
.p2_controls(p2_controls),
.dipsw_readback(dipsw_readback),
.sound_cmd(sound_cmd),
.sound_cmd_wr(sound_cmd_wr),
.h_center(h_center),
.v_center(v_center),
.main1_cs_i(main1_cs_i),
.main2_cs_i(main2_cs_i),
.main3_cs_i(main3_cs_i),
.main4_cs_i(main4_cs_i),
.main5_cs_i(main5_cs_i),
.tile0_cs_i(tile0_cs_i),
.tile1_cs_i(tile1_cs_i),
.spr_r_cs_i(spr_r_cs_i),
.spr_b_cs_i(spr_b_cs_i),
.spr_g_cs_i(spr_g_cs_i),
.ioctl_addr(ioctl_addr),
.ioctl_data(ioctl_data),
.ioctl_wr(ioctl_wr_cpu),
.pause(pause),
.hs_address(hs_address),
.hs_data_out(hs_data_out),
.hs_data_in(hs_data_in),
.hs_write(hs_write)
);
// Instantiate sound PCB
BluePrint_SND sound_pcb
(
.reset(reset),
.pause(pause),
.clk_49m(clk_49m),
.sound_cmd(sound_cmd),
.sound_cmd_wr(sound_cmd_wr),
.dip_sw(dip_sw),
.dipsw_readback(dipsw_readback_from_snd),
.sound(sound),
.vblank(video_vblank),
.snd_rom1_cs_i(snd_rom1_cs_i),
.snd_rom2_cs_i(snd_rom2_cs_i),
.ioctl_addr(ioctl_addr),
.ioctl_data(ioctl_data),
.ioctl_wr(ioctl_wr_snd)
);
endmodule

View File

@@ -0,0 +1,173 @@
/*MIT License
Copyright (c) 2019 Gregory Hogan (Soltan_G42)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.*/
module iir_1st_order
#(
parameter COEFF_WIDTH = 18,
parameter COEFF_SCALE = 15,
parameter DATA_WIDTH = 16,
parameter COUNT_BITS = 10
)
(
input clk,
input reset,
input [COUNT_BITS - 1 : 0] div,
input signed [COEFF_WIDTH - 1 : 0] A2, B1, B2,
input signed [DATA_WIDTH - 1 :0] in,
output [DATA_WIDTH - 1:0] out
);
reg signed [DATA_WIDTH-1:0] x0,x1,y0;
reg signed [DATA_WIDTH + COEFF_WIDTH - 1 : 0] out32;
reg [COUNT_BITS - 1:0] count;
// Usage:
// Design your 1st order iir low/high-pass with a tool that will give you the
// filter coefficients for the difference equation. Filter coefficients can
// be generated in Octave/matlab/scipy using a command similar to
// [B, A] = butter( 1, 3500/(106528/2), 'low') for a 3500 hz 1st order low-pass
// assuming 106528Hz sample rate.
//
// The Matlab output is:
// B = [0.093863 0.093863]
// A = [1.00000 -0.81227]
//
// Then scale coefficients by multiplying by 2^COEFF_SCALE and round to nearest integer
//
// B = [3076 3076]
// A = [32768 -26616]
//
// Discard A(1) because it is assumed 1.0 before scaling
//
// This leaves you with A2 = -26616 , B1 = 3076 , B2 = 3076
// B1 + B2 - A2 should sum to 2^COEFF_SCALE = 32768
//
// Sample frequency is "clk rate/div": for Genesis this is 53.69mhz/504 = 106528hz
//
// COEFF_WIDTH must be at least COEFF_SCALE+1 and must be large enough to
// handle temporary overflow during this computation: out32 <= (B1*x0 + B2*x1) - A2*y0
assign out = y0;
always @ (*) begin
out32 <= (B1*x0 + B2*x1) - A2*y0; //Previous output is y0 not y1
end
always @ (posedge clk) begin
if(reset) begin
count <= 0;
x0 <= 0;
x1 <= 0;
y0 <= 0;
end
else begin
count <= count + 1'd1;
if (count == div - 1) begin
count <= 0;
y0 <= {out32[DATA_WIDTH + COEFF_WIDTH - 1] , out32[COEFF_SCALE + DATA_WIDTH - 2 : COEFF_SCALE]};
x1 <= x0;
x0 <= in;
end
end
end
endmodule //iir_1st_order
module iir_2nd_order
#(
parameter COEFF_WIDTH = 18,
parameter COEFF_SCALE = 14,
parameter DATA_WIDTH = 16,
parameter COUNT_BITS = 10
)
(
input clk,
input reset,
input [COUNT_BITS - 1 : 0] div,
input signed [COEFF_WIDTH - 1 : 0] A2, A3, B1, B2, B3,
input signed [DATA_WIDTH - 1 : 0] in,
output [DATA_WIDTH - 1 : 0] out
);
reg signed [DATA_WIDTH-1 : 0] x0,x1,x2;
reg signed [DATA_WIDTH-1 : 0] y0,y1;
reg signed [(DATA_WIDTH + COEFF_WIDTH - 1) : 0] out32;
reg [COUNT_BITS : 0] count;
// Usage:
// Design your 1st order iir low/high-pass with a tool that will give you the
// filter coefficients for the difference equation. Filter coefficients can
// be generated in Octave/matlab/scipy using a command similar to
// [B, A] = butter( 2, 5000/(48000/2), 'low') for a 5000 hz 2nd order low-pass
// assuming 48000Hz sample rate.
//
// Output is:
// B = [ 0.072231 0.144462 0.072231]
// A = [1.00000 -1.10923 0.39815]
//
// Then scale coefficients by multiplying by 2^COEFF_SCALE and round to nearest integer
// Make sure your coefficients can be stored as a signed number with COEFF_WIDTH bits.
//
// B = [1183 2367 1183]
// A = [16384 -18174 6523]
//
// Discard A(1) because it is assumed 1.0 before scaling
//
// This leaves you with A2 = -18174 , A3 = 6523, B1 = 1183 , B2 = 2367 , B3 = 1183
// B1 + B2 + B3 - A2 - A3 should sum to 2^COEFF_SCALE = 16384
//
// Sample frequency is "clk rate/div"
//
// COEFF_WIDTH must be at least COEFF_SCALE+1 and must be large enough to
// handle temporary overflow during this computation:
// out32 <= (B1*x0 + B2*x1 + B3*x2) - (A2*y0 + A3*y1);
assign out = y0;
always @ (*) begin
out32 <= (B1*x0 + B2*x1 + B3*x2) - (A2*y0 + A3*y1); //Previous output is y0 not y1
end
always @ (posedge clk) begin
if(reset) begin
count <= 0;
x0 <= 0;
x1 <= 0;
x2 <= 0;
y0 <= 0;
y1 <= 0;
end
else begin
count <= count + 1'd1;
if (count == div - 1) begin
count <= 0;
y1 <= y0;
y0 <= {out32[DATA_WIDTH + COEFF_WIDTH - 1] , out32[(DATA_WIDTH + COEFF_SCALE - 2) : COEFF_SCALE]};
x2 <= x1;
x1 <= x0;
x0 <= in;
end
end
end
endmodule //iir_2nd_order

View File

@@ -0,0 +1,62 @@
/* This file is part of JT49.
JT49 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT49 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT49. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 15-Jan-2019
*/
// DC removal filter
// input is unsigned
// output is signed
module jt49_dcrm2 #(parameter sw=8) (
input clk,
input cen,
input rst,
input [sw-1:0] din,
output signed [sw-1:0] dout
);
localparam dw=10; // widht of the decimal portion
reg signed [sw+dw:0] integ, exact, error;
//reg signed [2*(9+dw)-1:0] mult;
// wire signed [sw+dw:0] plus1 = { {sw+dw{1'b0}},1'b1};
reg signed [sw:0] pre_dout;
// reg signed [sw+dw:0] dout_ext;
reg signed [sw:0] q;
always @(*) begin
exact = integ+error;
q = exact[sw+dw:dw];
pre_dout = { 1'b0, din } - q;
//dout_ext = { pre_dout, {dw{1'b0}} };
//mult = dout_ext;
end
assign dout = pre_dout[sw-1:0];
always @(posedge clk)
if( rst ) begin
integ <= {sw+dw+1{1'b0}};
error <= {sw+dw+1{1'b0}};
end else if( cen ) begin
integ <= integ + pre_dout; //mult[sw+dw*2:dw];
error <= exact-{q, {dw{1'b0}}};
end
endmodule

View File

@@ -0,0 +1,60 @@
/*MIT License
Copyright (c) 2019 Gregory Hogan (Soltan_G42)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.*/
//This is a variation of Gregory Hogan's MISTer Genesis core low-pass filter
//tuned to match the heaviest low-pass filter on Time Pilot.
module tp_lpf_heavy(
input clk,
input reset,
input signed [15:0] in,
output signed [15:0] out);
reg [9:0] div = 220; //Sample at 49.152/220 = 223418Hz
//Coefficients computed with Octave/Matlab/Online filter calculators.
//or with scipy.signal.bessel or similar tools
//0.0041276697, 0.0041276697
//1.0000000, -0.99174466
reg signed [17:0] A2;
reg signed [17:0] B2;
reg signed [17:0] B1;
wire signed [15:0] audio_post_lpf1;
always @ (*) begin
A2 = -18'd32498;
B1 = 18'd135;
B2 = 18'd135;
end
iir_1st_order lpf6db(.clk(clk),
.reset(reset),
.div(div),
.A2(A2),
.B1(B1),
.B2(B2),
.in(in),
.out(audio_post_lpf1));
assign out = audio_post_lpf1;
endmodule

View File

@@ -0,0 +1,60 @@
/*MIT License
Copyright (c) 2019 Gregory Hogan (Soltan_G42)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.*/
//This is a variation of Gregory Hogan's MISTer Genesis core low-pass filter
//tuned to match the lightest low-pass filter on Time Pilot.
module tp_lpf_light(
input clk,
input reset,
input signed [15:0] in,
output signed [15:0] out);
reg [9:0] div = 220; //Sample at 49.152/220 = 223418Hz
//Coefficients computed with Octave/Matlab/Online filter calculators.
//or with scipy.signal.bessel or similar tools
//0.017174022, 0.017174022
//1.0000000, -0.96565196
reg signed [17:0] A2;
reg signed [17:0] B2;
reg signed [17:0] B1;
wire signed [15:0] audio_post_lpf1;
always @ (*) begin
A2 = -18'd31642;
B1 = 18'd563;
B2 = 18'd563;
end
iir_1st_order lpf6db(.clk(clk),
.reset(reset),
.div(div),
.A2(A2),
.B1(B1),
.B2(B2),
.in(in),
.out(audio_post_lpf1));
assign out = audio_post_lpf1;
endmodule

View File

@@ -0,0 +1,60 @@
/*MIT License
Copyright (c) 2019 Gregory Hogan (Soltan_G42)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.*/
//This is a variation of Gregory Hogan's MISTer Genesis core low-pass filter
//tuned to match the middle low-pass filter on Time Pilot.
module tp_lpf_medium(
input clk,
input reset,
input signed [15:0] in,
output signed [15:0] out);
reg [9:0] div = 220; //Sample at 49.152/220 = 223418Hz
//Coefficients computed with Octave/Matlab/Online filter calculators.
//or with scipy.signal.bessel or similar tools
//0.0053024160, 0.0053024160
//1.0000000, -0.98939517
reg signed [17:0] A2;
reg signed [17:0] B2;
reg signed [17:0] B1;
wire signed [15:0] audio_post_lpf1;
always @ (*) begin
A2 = -18'd32420;
B1 = 18'd174;
B2 = 18'd174;
end
iir_1st_order lpf6db(.clk(clk),
.reset(reset),
.div(div),
.A2(A2),
.B1(B1),
.B2(B2),
.in(in),
.out(audio_post_lpf1));
assign out = audio_post_lpf1;
endmodule

View File

@@ -0,0 +1,35 @@
# ================================================================================
#
# Build ID Verilog Module Script
# Jeff Wiencrot - 8/1/2011
#
# Generates a Verilog module that contains a timestamp,
# from the current build. These values are available from the build_date, build_time,
# physical_address, and host_name output ports of the build_id module in the build_id.v
# Verilog source file.
#
# ================================================================================
proc generateBuildID_Verilog {} {
# Get the timestamp (see: http://www.altera.com/support/examples/tcl/tcl-date-time-stamp.html)
set buildDate [ clock format [ clock seconds ] -format %y%m%d ]
set buildTime [ clock format [ clock seconds ] -format %H%M%S ]
# Create a Verilog file for output
set outputFileName "rtl/build_id.v"
set outputFile [open $outputFileName "w"]
# Output the Verilog source
puts $outputFile "`define BUILD_DATE \"$buildDate\""
puts $outputFile "`define BUILD_TIME \"$buildTime\""
close $outputFile
# Send confirmation message to the Messages window
post_message "Generated build identification Verilog module: [pwd]/$outputFileName"
post_message "Date: $buildDate"
post_message "Time: $buildTime"
}
# Comment out this line to prevent the process from automatically executing when the file is sourced:
generateBuildID_Verilog

View File

@@ -0,0 +1,136 @@
LIBRARY ieee;
USE ieee.std_logic_1164.all;
LIBRARY altera_mf;
USE altera_mf.all;
ENTITY dpram_dc IS
GENERIC
(
init_file : string := " ";
widthad_a : natural;
width_a : natural := 8;
outdata_reg_a : string := "UNREGISTERED";
outdata_reg_b : string := "UNREGISTERED"
);
PORT
(
address_a : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0);
address_b : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0) := (others => '0');
clock_a : IN STD_LOGIC ;
clock_b : IN STD_LOGIC ;
data_a : IN STD_LOGIC_VECTOR (width_a-1 DOWNTO 0) := (others => '0');
data_b : IN STD_LOGIC_VECTOR (width_a-1 DOWNTO 0) := (others => '0');
wren_a : IN STD_LOGIC := '0';
wren_b : IN STD_LOGIC := '0';
byteena_a : IN STD_LOGIC_VECTOR (width_a/8-1 DOWNTO 0) := (others => '1');
byteena_b : IN STD_LOGIC_VECTOR (width_a/8-1 DOWNTO 0) := (others => '1');
q_a : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0);
q_b : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0)
);
END dpram_dc;
ARCHITECTURE SYN OF dpram_dc IS
SIGNAL sub_wire0 : STD_LOGIC_VECTOR (width_a-1 DOWNTO 0);
SIGNAL sub_wire1 : STD_LOGIC_VECTOR (width_a-1 DOWNTO 0);
COMPONENT altsyncram
GENERIC (
address_reg_b : STRING;
clock_enable_input_a : STRING;
clock_enable_input_b : STRING;
clock_enable_output_a : STRING;
clock_enable_output_b : STRING;
indata_reg_b : STRING;
init_file : STRING;
intended_device_family : STRING;
lpm_type : STRING;
numwords_a : NATURAL;
numwords_b : NATURAL;
operation_mode : STRING;
outdata_aclr_a : STRING;
outdata_aclr_b : STRING;
outdata_reg_a : STRING;
outdata_reg_b : STRING;
power_up_uninitialized : STRING;
read_during_write_mode_port_a : STRING;
read_during_write_mode_port_b : STRING;
widthad_a : NATURAL;
widthad_b : NATURAL;
width_a : NATURAL;
width_b : NATURAL;
width_byteena_a : NATURAL;
width_byteena_b : NATURAL;
wrcontrol_wraddress_reg_b : STRING
);
PORT (
wren_a : IN STD_LOGIC ;
clock0 : IN STD_LOGIC ;
wren_b : IN STD_LOGIC ;
clock1 : IN STD_LOGIC ;
address_a : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0);
address_b : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0);
q_a : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0);
q_b : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0);
byteena_a : IN STD_LOGIC_VECTOR (width_a/8-1 DOWNTO 0) ;
byteena_b : IN STD_LOGIC_VECTOR (width_a/8-1 DOWNTO 0) ;
data_a : IN STD_LOGIC_VECTOR (width_a-1 DOWNTO 0);
data_b : IN STD_LOGIC_VECTOR (width_a-1 DOWNTO 0)
);
END COMPONENT;
BEGIN
q_a <= sub_wire0(width_a-1 DOWNTO 0);
q_b <= sub_wire1(width_a-1 DOWNTO 0);
altsyncram_component : altsyncram
GENERIC MAP (
address_reg_b => "CLOCK1",
clock_enable_input_a => "BYPASS",
clock_enable_input_b => "BYPASS",
clock_enable_output_a => "BYPASS",
clock_enable_output_b => "BYPASS",
indata_reg_b => "CLOCK1",
init_file => init_file,
intended_device_family => "Cyclone III",
lpm_type => "altsyncram",
numwords_a => 2**widthad_a,
numwords_b => 2**widthad_a,
operation_mode => "BIDIR_DUAL_PORT",
outdata_aclr_a => "NONE",
outdata_aclr_b => "NONE",
outdata_reg_a => outdata_reg_a,
outdata_reg_b => outdata_reg_b,
power_up_uninitialized => "FALSE",
read_during_write_mode_port_a => "NEW_DATA_NO_NBE_READ",
read_during_write_mode_port_b => "NEW_DATA_NO_NBE_READ",
widthad_a => widthad_a,
widthad_b => widthad_a,
width_a => width_a,
width_b => width_a,
width_byteena_a => width_a/8,
width_byteena_b => width_a/8,
wrcontrol_wraddress_reg_b => "CLOCK1"
)
PORT MAP (
wren_a => wren_a,
clock0 => clock_a,
wren_b => wren_b,
clock1 => clock_b,
address_a => address_a,
address_b => address_b,
data_a => data_a,
data_b => data_b,
q_a => sub_wire0,
q_b => sub_wire1,
byteena_a => byteena_a,
byteena_b => byteena_b
);
END SYN;

View File

@@ -0,0 +1,58 @@
///////////////////////////////////////////////////////////////////////////
// Fractional clock enable signal
// W refers to the number of divided down cen signals available
// each one is divided by 2
module jtframe_frac_cen #(parameter W=2)(
input clk,
input [9:0] n, // numerator
input [9:0] m, // denominator
output reg [W-1:0] cen,
output reg [W-1:0] cenb // 180 shifted
);
wire [10:0] step={1'b0,n};
wire [10:0] lim ={1'b0,m};
wire [10:0] absmax = lim+step;
reg [10:0] cencnt=11'd0;
reg [10:0] next;
reg [10:0] next2;
always @(*) begin
next = cencnt+step;
next2 = next-lim;
end
reg half = 1'b0;
wire over = next>=lim;
wire halfway = next >= (lim>>1) && !half;
reg [W-1:0] edgecnt = {W{1'b0}};
wire [W-1:0] next_edgecnt = edgecnt + 1'b1;
wire [W-1:0] toggle = next_edgecnt & ~edgecnt;
always @(posedge clk) begin
cen <= {W{1'b0}};
cenb <= {W{1'b0}};
if( cencnt >= absmax ) begin
// something went wrong: restart
cencnt <= 11'd0;
end else
if( halfway ) begin
half <= 1'b1;
cenb[0] <= 1'b1;
end
if( over ) begin
cencnt <= next2;
half <= 1'b0;
edgecnt <= next_edgecnt;
cen <= { toggle[W-2:0], 1'b1 };
end else begin
cencnt <= next;
end
end
endmodule

View File

@@ -0,0 +1,4 @@
set_global_assignment -name IP_TOOL_NAME "ALTPLL"
set_global_assignment -name IP_TOOL_VERSION "13.1"
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "pll.vhd"]
set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll.ppf"]

View File

@@ -0,0 +1,365 @@
-- megafunction wizard: %ALTPLL%
-- GENERATION: STANDARD
-- VERSION: WM1.0
-- MODULE: altpll
-- ============================================================
-- File Name: pll.vhd
-- Megafunction Name(s):
-- altpll
--
-- Simulation Library Files(s):
-- altera_mf
-- ============================================================
-- ************************************************************
-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
--
-- 13.1.0 Build 162 10/23/2013 SJ Web Edition
-- ************************************************************
--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.
LIBRARY ieee;
USE ieee.std_logic_1164.all;
LIBRARY altera_mf;
USE altera_mf.all;
ENTITY pll IS
PORT
(
areset : IN STD_LOGIC := '0';
inclk0 : IN STD_LOGIC := '0';
c0 : OUT STD_LOGIC ;
locked : OUT STD_LOGIC
);
END pll;
ARCHITECTURE SYN OF pll IS
SIGNAL sub_wire0 : STD_LOGIC ;
SIGNAL sub_wire1 : STD_LOGIC_VECTOR (4 DOWNTO 0);
SIGNAL sub_wire2 : STD_LOGIC ;
SIGNAL sub_wire3 : STD_LOGIC ;
SIGNAL sub_wire4 : STD_LOGIC_VECTOR (1 DOWNTO 0);
SIGNAL sub_wire5_bv : BIT_VECTOR (0 DOWNTO 0);
SIGNAL sub_wire5 : STD_LOGIC_VECTOR (0 DOWNTO 0);
COMPONENT altpll
GENERIC (
bandwidth_type : STRING;
clk0_divide_by : NATURAL;
clk0_duty_cycle : NATURAL;
clk0_multiply_by : NATURAL;
clk0_phase_shift : STRING;
compensate_clock : STRING;
inclk0_input_frequency : NATURAL;
intended_device_family : STRING;
lpm_hint : STRING;
lpm_type : STRING;
operation_mode : STRING;
pll_type : STRING;
port_activeclock : STRING;
port_areset : STRING;
port_clkbad0 : STRING;
port_clkbad1 : STRING;
port_clkloss : STRING;
port_clkswitch : STRING;
port_configupdate : STRING;
port_fbin : STRING;
port_inclk0 : STRING;
port_inclk1 : STRING;
port_locked : STRING;
port_pfdena : STRING;
port_phasecounterselect : STRING;
port_phasedone : STRING;
port_phasestep : STRING;
port_phaseupdown : STRING;
port_pllena : STRING;
port_scanaclr : STRING;
port_scanclk : STRING;
port_scanclkena : STRING;
port_scandata : STRING;
port_scandataout : STRING;
port_scandone : STRING;
port_scanread : STRING;
port_scanwrite : STRING;
port_clk0 : STRING;
port_clk1 : STRING;
port_clk2 : STRING;
port_clk3 : STRING;
port_clk4 : STRING;
port_clk5 : STRING;
port_clkena0 : STRING;
port_clkena1 : STRING;
port_clkena2 : STRING;
port_clkena3 : STRING;
port_clkena4 : STRING;
port_clkena5 : STRING;
port_extclk0 : STRING;
port_extclk1 : STRING;
port_extclk2 : STRING;
port_extclk3 : STRING;
self_reset_on_loss_lock : STRING;
width_clock : NATURAL
);
PORT (
areset : IN STD_LOGIC ;
clk : OUT STD_LOGIC_VECTOR (4 DOWNTO 0);
inclk : IN STD_LOGIC_VECTOR (1 DOWNTO 0);
locked : OUT STD_LOGIC
);
END COMPONENT;
BEGIN
sub_wire5_bv(0 DOWNTO 0) <= "0";
sub_wire5 <= To_stdlogicvector(sub_wire5_bv);
locked <= sub_wire0;
sub_wire2 <= sub_wire1(0);
c0 <= sub_wire2;
sub_wire3 <= inclk0;
sub_wire4 <= sub_wire5(0 DOWNTO 0) & sub_wire3;
altpll_component : altpll
GENERIC MAP (
bandwidth_type => "AUTO",
clk0_divide_by => 39,
clk0_duty_cycle => 50,
clk0_multiply_by => 71,
clk0_phase_shift => "0",
compensate_clock => "CLK0",
inclk0_input_frequency => 37037,
intended_device_family => "Cyclone III",
lpm_hint => "CBX_MODULE_PREFIX=pll",
lpm_type => "altpll",
operation_mode => "NORMAL",
pll_type => "AUTO",
port_activeclock => "PORT_UNUSED",
port_areset => "PORT_USED",
port_clkbad0 => "PORT_UNUSED",
port_clkbad1 => "PORT_UNUSED",
port_clkloss => "PORT_UNUSED",
port_clkswitch => "PORT_UNUSED",
port_configupdate => "PORT_UNUSED",
port_fbin => "PORT_UNUSED",
port_inclk0 => "PORT_USED",
port_inclk1 => "PORT_UNUSED",
port_locked => "PORT_USED",
port_pfdena => "PORT_UNUSED",
port_phasecounterselect => "PORT_UNUSED",
port_phasedone => "PORT_UNUSED",
port_phasestep => "PORT_UNUSED",
port_phaseupdown => "PORT_UNUSED",
port_pllena => "PORT_UNUSED",
port_scanaclr => "PORT_UNUSED",
port_scanclk => "PORT_UNUSED",
port_scanclkena => "PORT_UNUSED",
port_scandata => "PORT_UNUSED",
port_scandataout => "PORT_UNUSED",
port_scandone => "PORT_UNUSED",
port_scanread => "PORT_UNUSED",
port_scanwrite => "PORT_UNUSED",
port_clk0 => "PORT_USED",
port_clk1 => "PORT_UNUSED",
port_clk2 => "PORT_UNUSED",
port_clk3 => "PORT_UNUSED",
port_clk4 => "PORT_UNUSED",
port_clk5 => "PORT_UNUSED",
port_clkena0 => "PORT_UNUSED",
port_clkena1 => "PORT_UNUSED",
port_clkena2 => "PORT_UNUSED",
port_clkena3 => "PORT_UNUSED",
port_clkena4 => "PORT_UNUSED",
port_clkena5 => "PORT_UNUSED",
port_extclk0 => "PORT_UNUSED",
port_extclk1 => "PORT_UNUSED",
port_extclk2 => "PORT_UNUSED",
port_extclk3 => "PORT_UNUSED",
self_reset_on_loss_lock => "OFF",
width_clock => 5
)
PORT MAP (
areset => areset,
inclk => sub_wire4,
locked => sub_wire0,
clk => sub_wire1
);
END SYN;
-- ============================================================
-- CNX file retrieval info
-- ============================================================
-- Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0"
-- Retrieval info: PRIVATE: BANDWIDTH STRING "1.000"
-- Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "1"
-- Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz"
-- Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low"
-- Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1"
-- Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0"
-- Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0"
-- Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0"
-- Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "0"
-- Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0"
-- Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0"
-- Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0"
-- Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0"
-- Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0"
-- Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "8"
-- Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "39"
-- Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000"
-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "49.153847"
-- 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: MIG_DEVICE_SPEED_GRADE STRING "Any"
-- Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0"
-- Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "71"
-- Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1"
-- Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "49.15200000"
-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "0"
-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 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_SHIFT_STEP_ENABLED_CHECK STRING "0"
-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg"
-- Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0"
-- Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "1"
-- Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1"
-- Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0"
-- Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0"
-- Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0"
-- Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0"
-- Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0"
-- Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0"
-- Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0"
-- Retrieval info: PRIVATE: RECONFIG_FILE STRING "pll.mif"
-- Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0"
-- Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "1"
-- Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0"
-- Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0"
-- Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0"
-- Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000"
-- Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz"
-- Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500"
-- Retrieval info: PRIVATE: SPREAD_USE STRING "0"
-- Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0"
-- Retrieval info: PRIVATE: STICKY_CLK0 STRING "1"
-- Retrieval info: PRIVATE: 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_CLKENA0 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 "39"
-- Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50"
-- Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "71"
-- Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0"
-- Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0"
-- Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "37037"
-- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone III"
-- Retrieval info: CONSTANT: LPM_TYPE STRING "altpll"
-- Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL"
-- Retrieval info: CONSTANT: PLL_TYPE STRING "AUTO"
-- Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_USED"
-- Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED"
-- Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED"
-- Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED"
-- Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: SELF_RESET_ON_LOSS_LOCK STRING "OFF"
-- Retrieval info: CONSTANT: WIDTH_CLOCK NUMERIC "5"
-- Retrieval info: USED_PORT: @clk 0 0 5 0 OUTPUT_CLK_EXT VCC "@clk[4..0]"
-- Retrieval info: USED_PORT: @inclk 0 0 2 0 INPUT_CLK_EXT VCC "@inclk[1..0]"
-- Retrieval info: USED_PORT: areset 0 0 0 0 INPUT GND "areset"
-- Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0"
-- Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0"
-- Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked"
-- Retrieval info: CONNECT: @areset 0 0 0 0 areset 0 0 0 0
-- Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0
-- Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0
-- Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0
-- Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0
-- Retrieval info: GEN_FILE: TYPE_NORMAL pll.vhd 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.vhd FALSE
-- Retrieval info: LIB_FILE: altera_mf
-- Retrieval info: CBX_MODULE_PREFIX: ON

View File

@@ -0,0 +1,90 @@
//============================================================================
//
// SD card ROM loader and ROM selector for MISTer.
// Copyright (C) 2019, 2020 Kitrinx (aka Rysha)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
//============================================================================
// ROM layout for Blue Print (index 0 - main CPU board + graphics):
// 0x0000 - 0x0FFF = main_rom1 (bp-1.1m)
// 0x1000 - 0x1FFF = main_rom2 (bp-2.1n)
// 0x2000 - 0x2FFF = main_rom3 (bp-3.1p)
// 0x3000 - 0x3FFF = main_rom4 (bp-4.1r)
// 0x4000 - 0x4FFF = main_rom5 (bp-5.1s)
// 0x5000 - 0x5FFF = tile_rom0 (bg-1.3c)
// 0x6000 - 0x6FFF = tile_rom1 (bg-2.3d)
// 0x7000 - 0x7FFF = spr_rom_r (red.17d)
// 0x8000 - 0x8FFF = spr_rom_b (blue.18d)
// 0x9000 - 0x9FFF = spr_rom_g (green.20d)
// Sound board ROMs loaded separately via index 1
module selector
(
input logic [24:0] ioctl_addr,
output logic main1_cs, main2_cs, main3_cs, main4_cs, main5_cs,
output logic tile0_cs, tile1_cs,
output logic spr_r_cs, spr_b_cs, spr_g_cs
);
always_comb begin
{main1_cs, main2_cs, main3_cs, main4_cs, main5_cs,
tile0_cs, tile1_cs, spr_r_cs, spr_b_cs, spr_g_cs} = 0;
if(ioctl_addr < 'h1000) main1_cs = 1;
else if(ioctl_addr < 'h2000) main2_cs = 1;
else if(ioctl_addr < 'h3000) main3_cs = 1;
else if(ioctl_addr < 'h4000) main4_cs = 1;
else if(ioctl_addr < 'h5000) main5_cs = 1;
else if(ioctl_addr < 'h6000) tile0_cs = 1;
else if(ioctl_addr < 'h7000) tile1_cs = 1;
else if(ioctl_addr < 'h8000) spr_r_cs = 1;
else if(ioctl_addr < 'h9000) spr_b_cs = 1;
else if(ioctl_addr < 'hA000) spr_g_cs = 1;
end
endmodule
////////////
// EPROMS //
////////////
// Generic 4KB ROM module (12-bit address)
module eprom_4k
(
input logic CLK,
input logic CLK_DL,
input logic [11:0] ADDR,
input logic [24:0] ADDR_DL,
input logic [7:0] DATA_IN,
input logic CS_DL,
input logic WR,
output logic [7:0] DATA
);
dpram_dc #(.widthad_a(12)) rom
(
.clock_a(CLK),
.address_a(ADDR[11:0]),
.q_a(DATA[7:0]),
.clock_b(CLK_DL),
.address_b(ADDR_DL[11:0]),
.data_b(DATA_IN),
.wren_b(WR & CS_DL)
);
endmodule

View File

@@ -0,0 +1,46 @@
library ieee;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.ALL;
use IEEE.numeric_std.all;
entity spram is
generic
(
DATA_WIDTH : natural := 8;
ADDR_WIDTH : natural := 10
);
port
(
clk : in std_logic;
addr : in std_logic_vector((ADDR_WIDTH - 1) downto 0);
data : in std_logic_vector((DATA_WIDTH - 1) downto 0);
q : out std_logic_vector((DATA_WIDTH - 1) downto 0);
we : in std_logic := '0'
);
end spram;
architecture rtl of spram is
subtype word_t is std_logic_vector((DATA_WIDTH-1) downto 0);
type memory_t is array(2**ADDR_WIDTH-1 downto 0) of word_t;
shared variable ram : memory_t;
begin
process(clk)
begin
if(rising_edge(clk)) then
if(we = '1') then
ram(to_integer(unsigned(addr))) := data;
q <= data;
else
q <= ram(to_integer(unsigned(addr)));
end if;
end if;
end process;
end rtl;