Initial commit.

This commit is contained in:
sorgelig
2021-03-19 23:42:15 +08:00
commit 429dcabcbd
126 changed files with 45297 additions and 0 deletions

39
.gitignore vendored Normal file
View File

@@ -0,0 +1,39 @@
db
greybox_tmp
incremental_db
output_files
simulation
hc_output
scaler
hps_isw_handoff
vip
*_sim
.qsys_edit
PLLJ_PLLSPE_INFO.txt
*.bak
*.orig
*.rej
*.qdf
*.rpt
*.smsg
*.summary
*.done
*.jdi
*.pin
*.sof
*.qws
*.ppf
*.ddb
build_id.v
c5_pin_model_dump.txt
*.sopcinfo
*.csv
*.f
*.cmp
*.sip
*.spd
*.bsf
*~
*.xml
*_netlist
*.cdf

339
LICENSE Normal file
View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

59
README.md Normal file
View File

@@ -0,0 +1,59 @@
# [ZX Spectrum Next](https://www.specnext.com/) port for MiSTer
## MiSTer specifics
- Uses SDRAM instead of SRAM. Some wait states are added in 14MHz and 28MHz modes.
- Bootstrap option to load other cores is not supported (obviously).
- Video modes for VGA and HDMI aren't supported (MiSTer uses its own HDMI settings).
- Added standard wide screen video crop and HV-Integer scaling for HDMI.
Note: in latest version of Next sources hardreset has beed removed. So to get into
boot configuration you have to re-load the core.
## Installation
- Place rbf into root of SD card.
- Unpack and place boot.vhd into `/Games/ZXNext` folder. Alternatively you can rename it to ZXNext.vhd and place into root of SD card.
## Hotkeys
* F1 - reset
* F3 - toggle 50Hz/60Hz modes
* F8 - change CPU speed: 3.5MHz, 7MHz, 14MHz, 28MHz
* F10 - DivMMC NMI
* F11 - NMI/Multiface
## Original specs:
A brief summary of the current machine specifications:
* **CPU** : Z80N (z80 compatible with some additional instructions) operable at software selectable speeds of 3.5 MHz, 7 MHz, 14 MHz or 28 MHz with wait states.
* **COPPER** : A co-processor running independently of the cpu executes simple instructions that can modify the nextreg state. For example, it can change palettes, alter the display mode or play stereo music. The copper is synchronized with the display generation so it is able to make these changes at precise locations in the display.
* **DMA** : The ZXN DMA, compatible with a subset of the Z80 DMA chip, is able to perform transfers between memory and/or io using short two cycle reads and writes. In burst mode, the zxn dma can send bytes at programmable rates allowing it to play sampled music while returning control to the cpu between transfers. At this time the zxn dma and the cpu share the bus and the dma operates at the currently set cpu speed.
* **RAM MEMORY** : 768K of RAM in the unexpanded machine or 1792K of RAM in the expanded machine. This memory is available in 16K banks as in the original 128K Spectrums and can be mapped as usual using the standard ports 0x7ffd and 0x1ffd. An additional port 0xdffd adds bits to port 0x7ffd to reach all memory banks. The native bankswitching scheme in the zx next is called MMU. This scheme divides the same memory into 8K pages and allows any page to be mapped into any 8K slot of the Z80's 64K address space.
* **ROM MEMORY** : 64K of ROM is reserved for ROMs 0-3 as in the Spectrum +3. Also available is 32K of Alt ROM that can replace the normal ROMs; this ROM is user programmable.
* **GRAPHICS** : The display is composed of layers with programmable priority. Layers are listed below.
* ULA : Compatible timing, contention and floating bus behaviour with the 48k, 128k, +3 and Pentagon. Supports hardware pixel scrolling in the X and Y directions and these resolutions:
* 256x192 pixel 32x24 attributes in bank 5 (48k / 128k)
* 256x192 pixel 32x24 attributes in bank 7 (128k second display)
* 256x192 pixel 32x24 attributes at 0x6000 in bank 5 (timex second display)
* 256x192 pixel 32x192 attributes at 0x4000 and 0x6000 in bank 5 (timex hi-colour)
* 512x192 pixel monochrome at 0x4000 and 0x6000 in bank 5 (timex hi-res)
* LoRes : Occupies the same layer as the ULA with LoRes replacing the ULA where it is enabled. Supports hardware pixel scrolling in the X and Y directions. Two resolutions are available:
* 128x96 4-bit colour per pixel at either 0x4000 or 0x6000 in bank 5 (Radastan mode originating on the ZX UNO)
* 128x96 8-bit colour per pixel occupying 0x4000 and 0x6000 in bank 5
* Layer 2 : A pixel mapped display without colour clash. Supports hardware pixel scrolling in the X and Y directions. Can be mapped to any location in memory starting at a 16K boundary. Available resolutions are:
* 256x192 8-bit colour per pixel
* 320x256 8-bit colour per pixel
* 640x256 4-bit colour per pixel
* Sprites : Up to 128 hardware sprites of size 16x16 pixels with either 8-bits or 4-bits of colour per pixel. A minimum of 100 sprites per line can be display at this size. Sprites can be scaled 1x 2x 4x 8x, rotated, mirrored and linked together.
* Tilemap : A hardware character display coming in two resolutions (80x32 = 640x256 pixels, 40x32 = 320x256). Supports hardware pixel scrolling in the X and Y directions. The character map and glyphs are stored at programmable locations in bank 5. Individual characters can be independently rotated and mirrored. Each glyph is 8x8 pixels in size with 4-bits of colour per pixel. Another mode eliminates rotation and mirroring in favour of 8x8 pixel glyphs defined as monochrome UDGs but with more colour information stored in the character map.
Some layer priority modes allow layer 2 to be highlighted or darkened by the ULA. Another setting allows the tilemap and ULA to stencil each other.
* **SOUND** : Stereo sound is played through HDMI, 3.5mm audio jack or optional internal speaker. Sound sources:
* Beeper : Beeps and tape sound.
* 3 x AY 8910 : Arranged to be compatible with the dual arrangement turbosound. AY instances can be programmed as mono or either ABC or ACB stereo mode.
* 4 x 8-bit DACs : Two DACs are assigned to the left channel and two are assigned to the right channel. Common 8-bit dac peripherals in the spectrum community such as specdrum and soundrive are mapped to these dacs.
* Raspberry PI I2S : Audio generated by an optional Pi accelerator can be mixed into the internal next audio stream or can be mapped to ear for tape loading.

33
ZXNext.qpf Normal file
View File

@@ -0,0 +1,33 @@
# -------------------------------------------------------------------------- #
#
# Copyright (C) 2017 Intel Corporation. All rights reserved.
# Your use of Intel Corporation's design tools, logic functions
# and other software and tools, and its AMPP partner logic
# functions, and any output files from any of the foregoing
# (including device programming or simulation files), and any
# associated documentation or information are expressly subject
# to the terms and conditions of the Intel Program License
# Subscription Agreement, the Intel Quartus Prime License Agreement,
# the Intel MegaCore Function License Agreement, or other
# applicable license agreement, including, without limitation,
# that your use is for the sole purpose of programming logic
# devices manufactured by Intel and sold by Intel or its
# authorized distributors. Please refer to the applicable
# agreement for further details.
#
# -------------------------------------------------------------------------- #
#
# Quartus Prime
# Version 17.0.2 Build 602 07/19/2017 SJ Lite Edition
# Date created = 00:23:38 September 19, 2020
#
# -------------------------------------------------------------------------- #
QUARTUS_VERSION = "17.0"
DATE = "00:23:38 September 19, 2020"
# Revisions
PROJECT_REVISION = "ZXNext"
PROJECT_REVISION = "200919"
PROJECT_REVISION = "200918"

64
ZXNext.qsf Normal file
View File

@@ -0,0 +1,64 @@
# --------------------------------------------------------------------------
#
# MiSTer project
#
# WARNING WARNING WARNING:
# Do not add files to project in Quartus IDE! It will mess this file!
# Add the files manually to files.qip file.
#
# --------------------------------------------------------------------------
set_global_assignment -name TOP_LEVEL_ENTITY sys_top
set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
set_global_assignment -name LAST_QUARTUS_VERSION "17.0.2 Standard Edition"
set_global_assignment -name GENERATE_RBF_FILE ON
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
set_global_assignment -name SAVE_DISK_SPACE OFF
set_global_assignment -name SMART_RECOMPILE ON
set_global_assignment -name MIN_CORE_JUNCTION_TEMP "-40"
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 100
set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW"
set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)"
set_global_assignment -name TIMEQUEST_MULTICORNER_ANALYSIS OFF
set_global_assignment -name OPTIMIZE_POWER_DURING_FITTING OFF
set_global_assignment -name FINAL_PLACEMENT_OPTIMIZATION ALWAYS
set_global_assignment -name FITTER_EFFORT "STANDARD FIT"
set_global_assignment -name OPTIMIZATION_MODE "AGGRESSIVE PERFORMANCE"
set_global_assignment -name ALLOW_POWER_UP_DONT_CARE ON
set_global_assignment -name QII_AUTO_PACKED_REGISTERS "SPARSE AUTO"
set_global_assignment -name ROUTER_LCELL_INSERTION_AND_LOGIC_DUPLICATION ON
set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC ON
set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_DUPLICATION ON
set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_RETIMING ON
set_global_assignment -name OPTIMIZATION_TECHNIQUE SPEED
set_global_assignment -name MUX_RESTRUCTURE ON
set_global_assignment -name REMOVE_REDUNDANT_LOGIC_CELLS ON
set_global_assignment -name AUTO_DELAY_CHAINS_FOR_HIGH_FANOUT_INPUT_PINS ON
set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC_FOR_AREA ON
set_global_assignment -name ADV_NETLIST_OPT_SYNTH_WYSIWYG_REMAP ON
set_global_assignment -name SYNTH_GATED_CLOCK_CONVERSION ON
set_global_assignment -name PRE_MAPPING_RESYNTHESIS ON
set_global_assignment -name ROUTER_CLOCKING_TOPOLOGY_ANALYSIS ON
set_global_assignment -name ECO_OPTIMIZE_TIMING ON
set_global_assignment -name PERIPHERY_TO_CORE_PLACEMENT_AND_ROUTING_OPTIMIZATION ON
set_global_assignment -name PHYSICAL_SYNTHESIS_ASYNCHRONOUS_SIGNAL_PIPELINING ON
set_global_assignment -name ALM_REGISTER_PACKING_EFFORT LOW
set_global_assignment -name SEED 1
#set_global_assignment -name VERILOG_MACRO "ARCADE_SYS=1"
#set_global_assignment -name VERILOG_MACRO "USE_FB=1"
#set_global_assignment -name VERILOG_MACRO "USE_SDRAM=1"
#set_global_assignment -name VERILOG_MACRO "USE_DDRAM=1"
#do not enable DEBUG_NOHDMI in release!
#set_global_assignment -name VERILOG_MACRO "DEBUG_NOHDMI=1"
source sys/sys.tcl
source sys/sys_analog.tcl
source files.qip
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

23
ZXNext.sdc Normal file
View File

@@ -0,0 +1,23 @@
derive_pll_clocks
derive_clock_uncertainty
create_generated_clock -source [get_pins {emu|pll|pll_inst|altera_pll_i|general[0].gpll~PLL_OUTPUT_COUNTER|divclk}] \
-name CLK_i0 -divide_by 2 -duty_cycle 50 [get_nets {emu|zxnext_top|CLK_i0}]
create_generated_clock -source [get_pins {emu|pll|pll_inst|altera_pll_i|general[0].gpll~PLL_OUTPUT_COUNTER|divclk}] \
-name CLK_CPU -divide_by 1 -duty_cycle 50 [get_nets {emu|zxnext_top|CLK_CPU}]
set clk_sys {*|pll|pll_inst|altera_pll_i|*[0].*|divclk}
set clk_56m {*|pll|pll_inst|altera_pll_i|*[1].*|divclk}
set clk_14m {*|pll|pll_inst|altera_pll_i|*[2].*|divclk}
set clk_7m {*|pll|pll_inst|altera_pll_i|*[3].*|divclk}
set clk_mem {*|pll|pll_inst|altera_pll_i|*[4].*|divclk}
set_multicycle_path -from [get_clocks $clk_sys] -to [get_clocks $clk_7m] -start -setup 2
set_multicycle_path -from [get_clocks $clk_sys] -to [get_clocks $clk_7m] -start -hold 1
set_multicycle_path -from [get_clocks $clk_56m] -to [get_clocks CLK_CPU] -start -setup 2
set_multicycle_path -from [get_clocks $clk_56m] -to [get_clocks CLK_CPU] -start -hold 1
set_multicycle_path -from [get_clocks $clk_mem] -to [get_clocks CLK_CPU] -start -setup 2
set_multicycle_path -from [get_clocks $clk_mem] -to [get_clocks CLK_CPU] -start -hold 1
set_multicycle_path -from [get_clocks CLK_CPU] -to [get_clocks $clk_mem] -setup 2
set_multicycle_path -from [get_clocks CLK_CPU] -to [get_clocks $clk_mem] -hold 1

28
ZXNext.srf Normal file
View File

@@ -0,0 +1,28 @@
{ "" "" "" "Inferred RAM node \"emu:emu\|mister_io:mister_io\|ps2_kbd_fifo_rtl_0\" from synchronous design logic. Pass-through logic has been added to match the read-during-write behavior of the original design." { } { } 0 276020 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Inferred RAM node \"emu:emu\|mister_io:mister_io\|ps2_mouse_fifo_rtl_0\" from synchronous design logic. Pass-through logic has been added to match the read-during-write behavior of the original design." { } { } 0 276020 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Synthesized away node \"emu:emu\|pll:pll\|pll_0002:pll_inst\|altera_pll:altera_pll_i\|outclk_wire\[2\]\"" { } { } 0 14320 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "RST port on the PLL is not properly connected on instance emu:emu\|pll:pll\|pll_0002:pll_inst\|altera_pll:altera_pll_i\|general\[1\].gpll. The reset port on the PLL should be connected. If the PLL loses lock for any reason, you might need to manually reset the PLL in order to re-establish lock to the reference clock." { } { } 0 0 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "RST port on the PLL is not properly connected on instance emu:emu\|pll:pll\|pll_0002:pll_inst\|altera_pll:altera_pll_i\|general\[0\].gpll. The reset port on the PLL should be connected. If the PLL loses lock for any reason, you might need to manually reset the PLL in order to re-establish lock to the reference clock." { } { } 0 0 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Ignored locations or region assignments to the following nodes" { } { } 0 15705 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "RST port on the PLL is not properly connected on instance emu:emu\|pll:pll\|pll_0002:pll_inst\|altera_pll:altera_pll_i\|general\[2\].gpll. The reset port on the PLL should be connected. If the PLL loses lock for any reason, you might need to manually reset the PLL in order to re-establish lock to the reference clock." { } { } 0 0 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Verilog HDL or VHDL warning at de10_top.v(129): object \"io_win\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Verilog HDL or VHDL warning at de10_top.v(134): object \"io_sdd\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Verilog HDL or VHDL warning at de10_top.v(97): object \"io_win\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Verilog HDL or VHDL warning at de10_top.v(102): object \"io_sdd\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Some pins have incomplete I/O assignments. Refer to the I/O Assignment Warnings report for details" { } { } 0 15714 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "LOCKED port on the PLL is not properly connected on instance \"pll_hdmi:pll_hdmi\|pll_hdmi_0002:pll_hdmi_inst\|altera_pll:altera_pll_i\|general\[0\].gpll\". The LOCKED port on the PLL should be connected when the FBOUTCLK port is connected. Although it is unnecessary to connect the LOCKED signal, any logic driven off of an output clock of the PLL will not know when the PLL is locked and ready." { } { } 0 21300 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Found combinational loop of 47 nodes" { } { } 0 332125 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "LOCKED port on the PLL is not properly connected on instance \"emu:emu\|pll:pll\|pll_0002:pll_inst\|altera_pll:altera_pll_i\|general\[0\].gpll\". The LOCKED port on the PLL should be connected when the FBOUTCLK port is connected. Although it is unnecessary to connect the LOCKED signal, any logic driven off of an output clock of the PLL will not know when the PLL is locked and ready." { } { } 0 21300 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Verilog HDL or VHDL warning at sys_top.v(209): object \"vip_newcfg\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Verilog HDL or VHDL warning at sys_top.v(594): object \"VSET\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Ignored filter at sys_top.sdc(17): vip\|output_inst\|vid_clk could not be matched with a net" { } { } 0 332174 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Ignored create_generated_clock at sys_top.sdc(16): Argument <targets> is an empty collection" { } { } 0 332049 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "Ignored filter at sys_top.sdc(37): VID_CLK could not be matched with a clock" { } { } 0 332174 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "*" { } { } 0 21074 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "*" { } { } 0 276020 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "*" { } { } 0 276027 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "RST" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "altera_pll.v" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "altera_cyclonev_pll.v" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "altera_pll_reconfig_core.v" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""}
{ "" "" "" "cyclonev_pll" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""}

504
ZXNext.sv Normal file
View File

@@ -0,0 +1,504 @@
//============================================================================
// ZX Spectrum Next
// port for MiSTer
// Copyright (C) 2021 Alexey Melnikov
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
//============================================================================
module emu
(
//Master input clock
input CLK_50M,
//Async reset from top-level module.
//Can be used as initial reset.
input RESET,
//Must be passed to hps_io module
inout [45:0] HPS_BUS,
//Base video clock. Usually equals to CLK_SYS.
output CLK_VIDEO,
//Multiple resolutions are supported using different CE_PIXEL rates.
//Must be based on CLK_VIDEO
output CE_PIXEL,
//Video aspect ratio for HDMI. Most retro systems have ratio 4:3.
//if VIDEO_ARX[12] or VIDEO_ARY[12] is set then [11:0] contains scaled size instead of aspect ratio.
output [12:0] VIDEO_ARX,
output [12:0] VIDEO_ARY,
output [7:0] VGA_R,
output [7:0] VGA_G,
output [7:0] VGA_B,
output VGA_HS,
output VGA_VS,
output VGA_DE, // = ~(VBlank | HBlank)
output VGA_F1,
output [1:0] VGA_SL,
output VGA_SCALER, // Force VGA scaler
input [11:0] HDMI_WIDTH,
input [11:0] HDMI_HEIGHT,
`ifdef USE_FB
// Use framebuffer in DDRAM (USE_FB=1 in qsf)
// FB_FORMAT:
// [2:0] : 011=8bpp(palette) 100=16bpp 101=24bpp 110=32bpp
// [3] : 0=16bits 565 1=16bits 1555
// [4] : 0=RGB 1=BGR (for 16/24/32 modes)
//
// FB_STRIDE either 0 (rounded to 256 bytes) or multiple of pixel size (in bytes)
output FB_EN,
output [4:0] FB_FORMAT,
output [11:0] FB_WIDTH,
output [11:0] FB_HEIGHT,
output [31:0] FB_BASE,
output [13:0] FB_STRIDE,
input FB_VBL,
input FB_LL,
output FB_FORCE_BLANK,
// Palette control for 8bit modes.
// Ignored for other video modes.
output FB_PAL_CLK,
output [7:0] FB_PAL_ADDR,
output [23:0] FB_PAL_DOUT,
input [23:0] FB_PAL_DIN,
output FB_PAL_WR,
`endif
output LED_USER, // 1 - ON, 0 - OFF.
// b[1]: 0 - LED status is system status OR'd with b[0]
// 1 - LED status is controled solely by b[0]
// hint: supply 2'b00 to let the system control the LED.
output [1:0] LED_POWER,
output [1:0] LED_DISK,
// I/O board button press simulation (active high)
// b[1]: user button
// b[0]: osd button
output [1:0] BUTTONS,
input CLK_AUDIO, // 24.576 MHz
output [15:0] AUDIO_L,
output [15:0] AUDIO_R,
output AUDIO_S, // 1 - signed audio samples, 0 - unsigned
output [1:0] AUDIO_MIX, // 0 - no mix, 1 - 25%, 2 - 50%, 3 - 100% (mono)
//ADC
inout [3:0] ADC_BUS,
//SD-SPI
output SD_SCK,
output SD_MOSI,
input SD_MISO,
output SD_CS,
input SD_CD,
`ifdef USE_DDRAM
//High latency DDR3 RAM interface
//Use for non-critical time purposes
output DDRAM_CLK,
input DDRAM_BUSY,
output [7:0] DDRAM_BURSTCNT,
output [28:0] DDRAM_ADDR,
input [63:0] DDRAM_DOUT,
input DDRAM_DOUT_READY,
output DDRAM_RD,
output [63:0] DDRAM_DIN,
output [7:0] DDRAM_BE,
output DDRAM_WE,
`endif
`ifdef USE_SDRAM
//SDRAM interface with lower latency
output SDRAM_CLK,
output SDRAM_CKE,
output [12:0] SDRAM_A,
output [1:0] SDRAM_BA,
inout [15:0] SDRAM_DQ,
output SDRAM_DQML,
output SDRAM_DQMH,
output SDRAM_nCS,
output SDRAM_nCAS,
output SDRAM_nRAS,
output SDRAM_nWE,
`endif
`ifdef DUAL_SDRAM
//Secondary SDRAM
input SDRAM2_EN,
output SDRAM2_CLK,
output [12:0] SDRAM2_A,
output [1:0] SDRAM2_BA,
inout [15:0] SDRAM2_DQ,
output SDRAM2_nCS,
output SDRAM2_nCAS,
output SDRAM2_nRAS,
output SDRAM2_nWE,
`endif
input UART_CTS,
output UART_RTS,
input UART_RXD,
output UART_TXD,
output UART_DTR,
input UART_DSR,
// Open-drain User port.
// 0 - D+/RX
// 1 - D-/TX
// 2..6 - USR2..USR6
// Set USER_OUT to 1 to read from USER_IN.
input [6:0] USER_IN,
output [6:0] USER_OUT,
input OSD_STATUS
);
assign USER_OUT = '1;
assign {DDRAM_CLK, DDRAM_BURSTCNT, DDRAM_ADDR, DDRAM_DIN, DDRAM_BE, DDRAM_RD, DDRAM_WE} = '0;
assign AUDIO_S = 0; // 1 - signed audio samples, 0 - unsigned
assign AUDIO_MIX = status[4:3];
assign LED_DISK = 0;
assign LED_POWER = 0;
assign LED_USER = sd_act & ~vsd_sel;
assign BUTTONS = 0;
assign UART_RTS = 0;
assign UART_DTR = 0;
assign VGA_SCALER = 0;
assign VGA_F1 = 0;
// Status Bit Map:
// Upper Lower
// 0 1 2 3 4 5 6
// 01234567890123456789012345678901 23456789012345678901234567890123
// 0123456789ABCDEFGHIJKLMNOPQRSTUV 0123456789ABCDEFGHIJKLMNOPQRSTUV
// XXXXXXXXX XXXX
`include "build_id.v"
localparam CONF_STR = {
"ZXNext;;",
"-;",
"S,VHD;",
"O1,Reset after Mount,No,Yes;",
"-;",
"O78,Aspect Ratio,Original,Full Screen,[ARC1],[ARC2];",
"O56,Scandoubler Fx,None,HQ2x,CRT 25%,CRT 50%;",
"H2d1OS,Vertical Crop,No,Yes;",
"h2d1OST,Vertical Crop,No,270,216;",
"OQR,Scale,Normal,V-Integer,Narrower HV-Integer,Wider HV-Integer;",
"-;",
"O34,Stereo mix,none,25%,50%,100%;",
"-;",
"O2,Joysticks Swap,No,Yes;",
"-;",
"R0,Reset;",
"J,A,B,C,X,Y,Z,Start;",
"V,v",`BUILD_DATE
};
wire clk_sys, CLK_14, CLK_7, CLK_56, CLK_112;
wire pll_locked;
pll pll
(
.refclk(CLK_50M),
.outclk_0(clk_sys),
.outclk_1(CLK_56),
.outclk_2(CLK_14),
.outclk_3(CLK_7),
.outclk_4(CLK_112),
.locked(pll_locked)
);
reg reset = 0;
always @(posedge clk_sys) reset <= RESET | status[0] | buttons[1] | (status[1] && img_mounted);
wire forced_scandoubler;
wire [1:0] buttons;
wire [63:0] status;
wire [10:0] ps2_key;
wire [24:0] ps2_mouse;
wire [7:0] ps2_mouse_ext;
wire [15:0] joy_0, joy_1;
wire [31:0] sd_lba;
wire sd_rd;
wire sd_wr;
wire sd_ack;
wire [8:0] sd_buff_addr;
wire [7:0] sd_buff_dout;
wire [7:0] sd_buff_din;
wire sd_buff_wr;
wire img_mounted;
wire img_readonly;
wire [63:0] img_size;
wire sd_ack_conf;
wire [21:0] gamma_bus;
hps_io #(.STRLEN($size(CONF_STR)>>3)) hps_io
(
.clk_sys(clk_sys),
.HPS_BUS(HPS_BUS),
.conf_str(CONF_STR),
.forced_scandoubler(forced_scandoubler),
.joystick_0(joy_0),
.joystick_1(joy_1),
.buttons(buttons),
.status(status),
.status_menumask({en1080p,|vcrop,1'b0}),
.sd_lba(sd_lba),
.sd_rd(sd_rd),
.sd_wr(sd_wr),
.sd_ack(sd_ack),
.sd_ack_conf(sd_ack_conf),
.sd_buff_addr(sd_buff_addr),
.sd_buff_dout(sd_buff_dout),
.sd_buff_din(sd_buff_din),
.sd_buff_wr(sd_buff_wr),
.img_mounted(img_mounted),
.img_readonly(img_readonly),
.img_size(img_size),
.ps2_key(ps2_key),
.ps2_mouse(ps2_mouse),
.ps2_mouse_ext(ps2_mouse_ext),
.gamma_bus(gamma_bus)
);
wire [20:0] RAM_A_ADDR;
wire RAM_A_REQ;
wire RAM_A_RD_n;
wire [7:0] RAM_A_DI;
wire [7:0] RAM_A_DO;
wire RAM_A_WAIT;
wire [20:0] RAM_B_ADDR;
wire RAM_B_REQ;
wire [7:0] RAM_B_DO;
sdram sdram(.*, .clk(CLK_112), .init(~pll_locked));
wire [11:0] aud_l, aud_r;
// active high = X Z Y START A C B U D L R
wire [10:0] j0 = {joy_0[7],joy_0[9],joy_0[8],joy_0[10],joy_0[4],joy_0[6],joy_0[5],joy_0[3:0]};
wire [10:0] j1 = {joy_1[7],joy_1[9],joy_1[8],joy_1[10],joy_1[4],joy_1[6],joy_1[5],joy_1[3:0]};
zxnext_top zxnext_top
(
.CLK_28 (clk_sys),
.CLK_14 (CLK_14),
.CLK_7 (CLK_7),
.HW_RESET (reset),
.RAM_A_ADDR (RAM_A_ADDR),
.RAM_A_REQ (RAM_A_REQ),
.RAM_A_RD_n (RAM_A_RD_n),
.RAM_A_DO (RAM_A_DI),
.RAM_A_DI (RAM_A_DO),
.RAM_A_WAIT (RAM_A_WAIT),
.RAM_B_ADDR (RAM_B_ADDR),
.RAM_B_REQ (RAM_B_REQ),
.RAM_B_DI (RAM_B_DO),
.ps2_key (ps2_key),
.ps2_mouse (ps2_mouse),
.ps2_mouse_ext (ps2_mouse_ext),
.sd_cs0_n_o (sdss),
.sd_sclk_o (sdclk),
.sd_mosi_o (sdmosi),
.sd_miso_i (sdmiso),
.audio_L (aud_l),
.audio_R (aud_r),
.ear_port_i (~tape_in),
.joy_left (status[2] ? j1: j0),
.joy_right (status[2] ? j0: j1),
.uart_rx_i (UART_RXD),
.uart_tx_o (UART_TXD),
.RGB ({rgb_r,rgb_g,rgb_b}),
.RGB_VS_n (VSync_n),
.RGB_HS_n (HSync_n),
.RGB_VB_n (VBlank_n),
.RGB_HB_n (HBlank_n),
.RGB_NTSC (ntsc)
);
assign AUDIO_L = {aud_l, 4'b0000};
assign AUDIO_R = {aud_r, 4'b0000};
assign CLK_VIDEO = CLK_56;
wire [2:0] scale = status[6:5];
assign VGA_SL = scale ? scale[1:0] - 1'd1 : 2'd0;
wire HBlank_n, VBlank_n;
wire HSync_n, VSync_n;
wire ntsc;
wire [2:0] rgb_r;
wire [2:0] rgb_g;
wire [2:0] rgb_b;
reg ce_pix;
always @(posedge CLK_VIDEO) begin
reg [1:0] div;
div <= div + 1'd1;
ce_pix <= !div;
end
reg narrow_hbl;
always @(posedge CLK_VIDEO) begin
reg [10:0] hcnt;
if(ce_pix) begin
hcnt <= hcnt + 1'd1;
if(~HBlank_n) hcnt <= 0;
narrow_hbl <= narrow && ((hcnt < 20) || (hcnt >= 700));
end
end
video_mixer #(.LINE_LENGTH(740), .GAMMA(1)) video_mixer
(
.*,
.hq2x(scale == 1),
.scandoubler(scale || forced_scandoubler),
.VSync(~VSync_n),
.HSync(~HSync_n),
.VBlank(~VBlank_n),
.HBlank(~HBlank_n | narrow_hbl),
.R({rgb_r,rgb_r,rgb_r[2:1]}),
.G({rgb_g,rgb_g,rgb_g[2:1]}),
.B({rgb_b,rgb_b,rgb_b[2:1]}),
.VGA_DE(vga_de)
);
reg [9:0] vcrop;
reg narrow;
always @(posedge CLK_VIDEO) begin
vcrop <= 0;
narrow <= 0;
if(HDMI_WIDTH >= (HDMI_HEIGHT + HDMI_HEIGHT[11:1]) && !forced_scandoubler && !scale) begin
if(HDMI_HEIGHT == 480) vcrop <= 240;
if(HDMI_HEIGHT == 600) begin vcrop <= 200; narrow <= 1; end
if(HDMI_HEIGHT == 720) vcrop <= 240;
if(HDMI_HEIGHT == 768) vcrop <= 256;
if(HDMI_HEIGHT == 800) begin vcrop <= 200; narrow <= 1; end
if(HDMI_HEIGHT == 1080) vcrop <= status[29] ? 10'd216 : 10'd270;
if(HDMI_HEIGHT == 1200) vcrop <= 240;
end
end
reg en1080p;
always @(posedge CLK_VIDEO) en1080p <= (HDMI_WIDTH == 1920) && (HDMI_HEIGHT == 1080);
wire [1:0] ar = status[8:7];
wire vcrop_en = en1080p ? |status[29:28] : status[28];
wire vga_de;
video_freak video_freak
(
.*,
.VGA_DE_IN(vga_de),
.ARX((!ar) ? (narrow ? 12'd340 : 12'd360) : (ar - 1'd1)),
.ARY((!ar) ? (ntsc ? 12'd256 : 12'd303) : 12'd0),
.CROP_SIZE(vcrop_en ? vcrop : 10'd0),
.CROP_OFF(0),
.SCALE(status[27:26])
);
wire sdclk;
wire sdmosi;
wire sdmiso = vsd_sel ? vsdmiso : SD_MISO;
wire sdss;
reg vsd_sel = 0;
always @(posedge clk_sys) if(img_mounted) vsd_sel <= |img_size;
wire vsdmiso;
sd_card sd_card
(
.*,
.clk_spi(CLK_56),
.sdhc(1),
.sck(sdclk),
.ss(sdss | ~vsd_sel),
.mosi(sdmosi),
.miso(vsdmiso)
);
assign SD_CS = sdss | vsd_sel;
assign SD_SCK = sdclk & ~vsd_sel;
assign SD_MOSI = sdmosi & ~vsd_sel;
reg sd_act;
always @(posedge CLK_56) begin
reg old_mosi, old_miso;
integer timeout = 0;
old_mosi <= sdmosi;
old_miso <= sdmiso;
sd_act <= 0;
if(timeout < 1000000) begin
timeout <= timeout + 1;
sd_act <= 1;
end
if((old_mosi ^ sdmosi) || (old_miso ^ sdmiso)) timeout <= 0;
end
wire tape_in;
wire tape_adc, tape_adc_act;
assign tape_in = tape_adc_act & tape_adc;
ltc2308_tape #(.CLK_RATE(28000000)) ltc2308_tape
(
.clk(clk_sys),
.ADC_BUS(ADC_BUS),
.dout(tape_adc),
.active(tape_adc_act)
);
endmodule

36
clean.bat Normal file
View File

@@ -0,0 +1,36 @@
@echo off
del /s *.bak
del /s *.orig
del /s *.rej
del /s *~
rmdir /s /q db
rmdir /s /q incremental_db
rmdir /s /q output_files
rmdir /s /q simulation
rmdir /s /q greybox_tmp
rmdir /s /q hc_output
rmdir /s /q .qsys_edit
rmdir /s /q hps_isw_handoff
rmdir /s /q sys\.qsys_edit
rmdir /s /q sys\vip
for /d %%i in (sys\*_sim) do rmdir /s /q "%%i"
for /d %%i in (rtl\*_sim) do rmdir /s /q "%%i"
del build_id.v
del c5_pin_model_dump.txt
del PLLJ_PLLSPE_INFO.txt
del /s *.qws
del /s *.ppf
del /s *.ddb
del /s *.csv
del /s *.cmp
del /s *.sip
del /s *.spd
del /s *.bsf
del /s *.f
del /s *.sopcinfo
del /s *.xml
del *.cdf
del *.rpt
del /s new_rtl_netlist
del /s old_rtl_netlist
pause

47
files.qip Normal file
View File

@@ -0,0 +1,47 @@
set_global_assignment -name VHDL_FILE rtl/audio/ym2149.vhd
set_global_assignment -name VHDL_FILE rtl/audio/turbosound.vhd
set_global_assignment -name VHDL_FILE rtl/audio/soundrive.vhd
set_global_assignment -name VHDL_FILE rtl/audio/i2s.vhd
set_global_assignment -name VHDL_FILE rtl/audio/audio_mixer.vhd
set_global_assignment -name VHDL_FILE rtl/audio/i2s/i2s_transmit.vhd
set_global_assignment -name VHDL_FILE rtl/audio/i2s/i2s_slave.vhd
set_global_assignment -name VHDL_FILE rtl/audio/i2s/i2s_receive.vhd
set_global_assignment -name VHDL_FILE rtl/audio/i2s/i2s_master.vhd
set_global_assignment -name VHDL_FILE rtl/cpu/t80na.vhd
set_global_assignment -name VHDL_FILE rtl/cpu/t80n_pack.vhd
set_global_assignment -name VHDL_FILE rtl/cpu/t80n_mcode.vhd
set_global_assignment -name VHDL_FILE rtl/cpu/t80n_alu.vhd
set_global_assignment -name VHDL_FILE rtl/cpu/t80n.vhd
set_global_assignment -name VHDL_FILE rtl/device/multiface.vhd
set_global_assignment -name VHDL_FILE rtl/device/dma.vhd
set_global_assignment -name VHDL_FILE rtl/device/divmmc.vhd
set_global_assignment -name VHDL_FILE rtl/device/copper.vhd
set_global_assignment -name VHDL_FILE rtl/device/im2_control.vhd
set_global_assignment -name VHDL_FILE rtl/device/im2_device.vhd
set_global_assignment -name VHDL_FILE rtl/device/im2_peripheral.vhd
set_global_assignment -name VHDL_FILE rtl/device/peripherals.vhd
set_global_assignment -name VHDL_FILE rtl/input/membrane/membrane.vhd
set_global_assignment -name VHDL_FILE rtl/input/membrane/membrane_stick.vhd
set_global_assignment -name VHDL_FILE rtl/input/keyboard/keymaps.vhd
set_global_assignment -name VHDL_FILE rtl/misc/debounce.vhd
set_global_assignment -name VHDL_FILE rtl/video/zxula_timing.vhd
set_global_assignment -name VHDL_FILE rtl/video/zxula.vhd
set_global_assignment -name VHDL_FILE rtl/video/tilemap.vhd
set_global_assignment -name VHDL_FILE rtl/video/sprites.vhd
set_global_assignment -name VHDL_FILE rtl/video/lores.vhd
set_global_assignment -name VHDL_FILE rtl/video/layer2.vhd
set_global_assignment -name VHDL_FILE rtl/serial/uart.vhd
set_global_assignment -name VHDL_FILE rtl/serial/uart_rx.vhd
set_global_assignment -name VHDL_FILE rtl/serial/uart_tx.vhd
set_global_assignment -name VHDL_FILE rtl/serial/spi_master.vhd
set_global_assignment -name VHDL_FILE rtl/serial/fifop.vhd
set_global_assignment -name VHDL_FILE rtl/rom/bootrom.vhd
set_global_assignment -name VHDL_FILE rtl/device/ctc_chan.vhd
set_global_assignment -name VHDL_FILE rtl/device/ctc.vhd
set_global_assignment -name VHDL_FILE rtl/zxnext.vhd
set_global_assignment -name VHDL_FILE rtl/mister/ps2_keyb.vhd
set_global_assignment -name VHDL_FILE rtl/mister/bram.vhd
set_global_assignment -name SYSTEMVERILOG_FILE rtl/mister/sdram.sv
set_global_assignment -name VHDL_FILE rtl/mister/zxnext_top.vhd
set_global_assignment -name SYSTEMVERILOG_FILE ZXNext.sv
set_global_assignment -name SDC_FILE ZXNext.sdc

BIN
releases/boot.zip Normal file

Binary file not shown.

107
rtl/audio/audio_mixer.vhd Normal file
View File

@@ -0,0 +1,107 @@
-- Audio Mixer
-- Copyright 2020 Fabio Belavenuto and Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity audio_mixer is
port
(
clock_i : in std_logic;
reset_i : in std_logic;
-- beeper and tape
ear_i : in std_logic;
mic_i : in std_logic;
-- ay
ay_L_i : in std_logic_vector(11 downto 0);
ay_R_i : in std_logic_vector(11 downto 0);
-- dac
dac_L_i : in std_logic_vector(8 downto 0);
dac_R_i : in std_logic_vector(8 downto 0);
-- pi i2s audio
pi_i2s_L_i : in std_logic_vector(9 downto 0);
pi_i2s_R_i : in std_logic_vector(9 downto 0);
-- mixed pcm audio
pcm_L_o : out std_logic_vector(12 downto 0);
pcm_R_o : out std_logic_vector(12 downto 0)
);
end entity;
architecture rtl of audio_mixer is
constant ear_volume : std_logic_vector(12 downto 0) := "0001000000000";
constant mic_volume : std_logic_vector(12 downto 0) := "0000010000000";
signal ear : std_logic_vector(12 downto 0);
signal mic : std_logic_vector(12 downto 0);
signal ay_L : std_logic_vector(12 downto 0);
signal ay_R : std_logic_vector(12 downto 0);
signal dac_L : std_logic_vector(12 downto 0);
signal dac_R : std_logic_vector(12 downto 0);
signal i2s_L : std_logic_vector(12 downto 0);
signal i2s_R : std_logic_vector(12 downto 0);
signal pcm_L : std_logic_vector(12 downto 0); -- 0 - 8191
signal pcm_R : std_logic_vector(12 downto 0); -- 0 - 8191
begin
ear <= ear_volume when ear_i = '1' else (others => '0'); -- 0 / 512
mic <= mic_volume when mic_i = '1' else (others => '0'); -- 0 / 128
ay_L <= '0' & ay_L_i; -- 0 - 2295
ay_R <= '0' & ay_R_i; -- 0 - 2295
dac_L <= "00" & dac_L_i & "00"; -- 0 - 510 => 0 - 2040
dac_R <= "00" & dac_R_i & "00"; -- 0 - 510 => 0 - 2040
i2s_L <= "000" & pi_i2s_L_i; -- 0 - 1023
i2s_R <= "000" & pi_i2s_R_i; -- 0 - 1023
process (clock_i)
begin
if rising_edge(clock_i) then
if reset_i = '1' then
pcm_L <= (others => '0');
pcm_R <= (others => '0');
else
pcm_L <= ear + mic + ay_L + dac_L + i2s_L; -- 0 - 5998
pcm_R <= ear + mic + ay_R + dac_R + i2s_R; -- 0 - 5998
end if;
end if;
end process;
pcm_L_o <= pcm_L;
pcm_R_o <= pcm_R;
end architecture;

70
rtl/audio/dac.vhd Normal file
View File

@@ -0,0 +1,70 @@
-------------------------------------------------------------------------------
--
-- Delta-Sigma DAC
--
-- Refer to Xilinx Application Note XAPP154.
--
-- This DAC requires an external RC low-pass filter:
--
-- dac_o 0---XXXXX---+---0 analog audio
-- 3k3 |
-- === 4n7
-- |
-- GND
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity dac is
generic (
msbi_g : integer := 7
);
port (
clk_i : in std_logic;
res_i : in std_logic;
dac_i : in std_logic_vector(msbi_g downto 0);
dac_o : out std_logic
);
end dac;
library ieee;
use ieee.numeric_std.all;
architecture rtl of dac is
signal DACout_q : std_logic;
signal DeltaAdder_s,
SigmaAdder_s,
SigmaLatch_q,
DeltaB_s : unsigned(msbi_g+2 downto 0);
begin
DeltaB_s(msbi_g+2 downto msbi_g+1) <= SigmaLatch_q(msbi_g+2) &
SigmaLatch_q(msbi_g+2);
DeltaB_s(msbi_g downto 0) <= (others => '0');
DeltaAdder_s <= unsigned('0' & '0' & dac_i) + DeltaB_s;
SigmaAdder_s <= DeltaAdder_s + SigmaLatch_q;
seq: process (clk_i)
begin
if clk_i'event and clk_i = '1' then
if res_i = '1' then
SigmaLatch_q <= to_unsigned(2**(msbi_g+1), SigmaLatch_q'length);
DACout_q <= '0';
else
SigmaLatch_q <= SigmaAdder_s;
DACout_q <= SigmaLatch_q(msbi_g+2);
end if;
end if;
end process seq;
dac_o <= DACout_q;
end rtl;

208
rtl/audio/i2s.vhd Normal file
View File

@@ -0,0 +1,208 @@
-- I2S Pi0 + ZX Spectrum Next Interface
-- Copyright 2020 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
-- Reference:
-- <https://web.archive.org/web/20070102004400/http://www.nxp.com/acrobat_download/various/I2SBUS.pdf>
--
-- Sample Rate = SR = i_CLK / 2^(CLK_DIV_PRE) / (i_CLK_DIV+1) / LR_WIDTH / 4
-- = 538461 / (i_CLK_DIV+1)
--
-- i_CLK_DIV = (i_CLK / 2^(CLK_DIV_PRE) / SR / LR_WIDTH / 4) - 1
-- = 538461 / SR - 1
--
-- This is a two-way interface allowing the exchange of stereo audio between
-- the zx next and the pi.
--
-- Audio from the pi is given the same loudness as a single 8-bit dac channel.
-- The unsigned range of pcm therefore covers 10 bits per stereo channel.
--
-- Audio generated by the zx next is unsigned 13 bits per stereo channel.
--
-- i2s exchanges signed audio.
-- Note: Restricted to slave mode only
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity i2s_transmitter is
port
(
i_reset : in std_logic;
i_CLK : in std_logic;
-- i_CLK_DIV : in std_logic_vector(7 downto 0);
-- i_slave_mode : in std_logic; -- 1 = slave, external clock used
-- slave mode (incoming clock signals, synchronized)
i_i2s_sck : in std_logic;
i_i2s_ws : in std_logic;
-- outgoing clock signals (master or slave)
o_i2s_sck : out std_logic;
o_i2s_ws : out std_logic;
o_i2s_wsp : out std_logic;
-- zx next audio to pi
i_audio_zxn_L : in std_logic_vector(12 downto 0);
i_audio_zxn_R : in std_logic_vector(12 downto 0);
o_i2s_sd_pi : out std_logic;
-- pi audio to zx next
i_i2s_sd_pi : in std_logic;
o_audio_pi_L : out std_logic_vector(9 downto 0);
o_audio_pi_R : out std_logic_vector(9 downto 0)
);
end entity;
architecture rtl of i2s_transmitter is
signal i2s_sck : std_logic;
signal i2s_ws : std_logic;
signal i2s_wsp : std_logic;
signal m_i2s_sck : std_logic;
signal m_i2s_ws : std_logic;
signal m_i2s_wsp : std_logic;
signal s_i2s_sck : std_logic;
signal s_i2s_ws : std_logic;
signal s_i2s_wsp : std_logic;
signal audio_pi_L : std_logic_vector(12 downto 0);
signal audio_pi_R : std_logic_vector(12 downto 0);
signal audio_zxn_L : std_logic_vector(12 downto 0);
signal audio_zxn_R : std_logic_vector(12 downto 0);
begin
-- -- i2s master
-- i2s_master_mod : entity work.i2s_master
-- generic map
-- (
-- CLK_DIV_PRE => 0,
-- CLK_DIV_MBIT => 7,
-- LR_WIDTH => 13,
-- LR_WIDTH_MBIT => 3
-- )
-- port map
-- (
-- i_reset => i_reset or i_slave_mode,
--
-- i_CLK => i_CLK,
-- i_CLK_DIV => i_CLK_DIV,
--
-- o_i2s_sck => m_i2s_sck,
-- o_i2s_ws => m_i2s_ws,
-- o_i2s_wsp => m_i2s_wsp
-- );
-- i2s slave
i2s_slave_mod : entity work.i2s_slave
port map
(
-- i_reset => i_reset or not i_slave_mode,
--
-- i_CLK => i_CLK,
--
i_i2s_sck => i_i2s_sck,
i_i2s_ws => i_i2s_ws,
o_i2s_sck => s_i2s_sck,
o_i2s_ws => s_i2s_ws,
o_i2s_wsp => s_i2s_wsp
);
-- master or slave
i2s_sck <= s_i2s_sck; -- when i_slave_mode = '1' else m_i2s_sck;
i2s_ws <= s_i2s_ws; -- when i_slave_mode = '1' else m_i2s_ws;
i2s_wsp <= s_i2s_wsp; -- when i_slave_mode = '1' else m_i2s_wsp;
o_i2s_sck <= i2s_sck;
o_i2s_ws <= i2s_ws;
o_i2s_wsp <= i2s_wsp;
-- i2s receive from pi
i2s_receiver_mod : entity work.i2s_receive
generic map
(
LR_WIDTH => 13,
LR_WIDTH_MBIT => 3
)
port map
(
i_reset => i_reset,
i_CLK => i_CLK,
i_i2s_sck => i2s_sck,
i_i2s_ws => i2s_ws,
i_i2s_wsp => i2s_wsp,
i_i2s_sd => i_i2s_sd_pi,
o_i2s_L => audio_pi_L,
o_i2s_R => audio_pi_R
);
process (i_CLK)
begin
if rising_edge(i_CLK) then
o_audio_pi_L <= (not audio_pi_L(12)) & audio_pi_L(11 downto 3);
o_audio_pi_R <= (not audio_pi_R(12)) & audio_pi_R(11 downto 3);
end if;
end process;
-- i2s transmit to pi
audio_zxn_L <= (not i_audio_zxn_L(12)) & i_audio_zxn_L(11 downto 0);
audio_zxn_R <= (not i_audio_zxn_R(12)) & i_audio_zxn_R(11 downto 0);
i2s_transmit_mod : entity work.i2s_transmit
generic map
(
LR_WIDTH => 13
)
port map
(
i_reset => i_reset,
i_CLK => i_CLK,
i_i2s_sck => i2s_sck,
i_i2s_ws => i2s_ws,
i_i2s_wsp => i2s_wsp,
o_i2s_sd => o_i2s_sd_pi,
i_i2s_L => audio_zxn_L,
i_i2s_R => audio_zxn_R
);
end architecture;

View File

@@ -0,0 +1,153 @@
-- I2S Master
-- Copyright 2020 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
-- Generates:
-- sck - master clock
-- ws - channel selection (0 = left, 1 = right)
-- wsp - one on falling edge of sck indicates channel change
--
-- Reference:
-- <https://web.archive.org/web/20070102004400/http://www.nxp.com/acrobat_download/various/I2SBUS.pdf>
--
-- Sample Rate = SR = i_CLK / 2^(CLK_DIV_PRE) / (i_CLK_DIV+1) / LR_WIDTH / 4
-- i_CLK_DIV = (i_CLK / 2^(CLK_DIV_PRE) / SR / LR_WIDTH / 4) - 1
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity i2s_master is
generic
(
constant CLK_DIV_PRE : natural := 0; -- divide clock by 2^(CLK_DIV_PRE)
constant CLK_DIV_MBIT : positive := 7; -- size of programmable divider (7 downto 0)
constant LR_WIDTH : positive := 8; -- number of bits in the left and right channels (8: 7 downto 0)
constant LR_WIDTH_MBIT : positive := 2 -- number of bits needed to represent LR_WIDTH-1 (2 downto 0)
);
port
(
i_reset : in std_logic;
i_CLK : in std_logic;
i_CLK_DIV : in std_logic_vector(CLK_DIV_MBIT downto 0);
o_i2s_sck : out std_logic;
o_i2s_ws : out std_logic;
o_i2s_wsp : out std_logic
);
end entity;
architecture rtl of i2s_master is
signal sck : std_logic;
signal sck_count : std_logic_vector((CLK_DIV_PRE + CLK_DIV_MBIT) downto 0);
signal clk_div : std_logic_vector(CLK_DIV_MBIT downto 0);
signal sck_edge : std_logic;
signal sck_fe : std_logic;
signal sck_re : std_logic;
signal ws : std_logic;
signal ws_d : std_logic;
signal wsp : std_logic;
signal width_count : std_logic_vector(LR_WIDTH_MBIT downto 0);
begin
-- sck
sck_edge <= '1' when (sck_count((CLK_DIV_PRE + CLK_DIV_MBIT) downto CLK_DIV_PRE) = clk_div) else '0';
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
sck <= '0';
sck_count <= (others => '0');
clk_div <= i_CLK_DIV;
elsif sck_edge = '1' then
if sck = '1' and wsp = '1' then
clk_div <= i_CLK_DIV;
end if;
sck <= not sck;
sck_count <= (others => '0');
else
sck_count <= sck_count + 1;
end if;
end if;
end process;
sck_re <= sck_edge and not sck;
sck_fe <= sck_edge and sck;
-- channel selection
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
ws <= '1';
width_count <= std_logic_vector(to_unsigned(LR_WIDTH-1, width_count'length));
elsif sck_fe = '1' then
if width_count = std_logic_vector(to_unsigned(LR_WIDTH-1, width_count'length)) then
ws <= not ws;
width_count <= (others => '0');
else
width_count <= width_count + 1;
end if;
end if;
end if;
end process;
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
ws_d <= '1';
elsif sck_fe = '1' then
ws_d <= ws;
end if;
end if;
end process;
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
wsp <= '0';
elsif sck_re = '1' then
if ws /= ws_d then
wsp <= '1';
else
wsp <= '0';
end if;
end if;
end if;
end process;
-- output
o_i2s_sck <= sck;
o_i2s_ws <= ws;
o_i2s_wsp <= wsp;
end architecture;

View File

@@ -0,0 +1,146 @@
-- I2S Receiver
-- Copyright 2020 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
-- Reference:
-- https://web.archive.org/web/20070102004400/http://www.nxp.com/acrobat_download/various/I2SBUS.pdf
-- Signals are already synchronized
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity i2s_receive is
generic
(
constant LR_WIDTH : positive := 8; -- number of bits in the left and right channels (8: 7 downto 0)
constant LR_WIDTH_MBIT : positive := 2 -- number of bits needed to represent LR_WIDTH-1 (2 downto 0)
);
port
(
i_CLK : in std_logic;
i_reset : in std_logic;
i_i2s_sck : in std_logic;
i_i2s_ws : in std_logic;
i_i2s_wsp : in std_logic;
i_i2s_sd : in std_logic;
o_i2s_L : out std_logic_vector(LR_WIDTH-1 downto 0);
o_i2s_R : out std_logic_vector(LR_WIDTH-1 downto 0)
);
end entity;
architecture rtl of i2s_receive is
signal sck_d : std_logic;
signal sck_re : std_logic;
signal sck_fe : std_logic;
signal wsp_e : std_logic;
signal receiver : std_logic_vector(LR_WIDTH downto 0);
signal recv_count : std_logic_vector(LR_WIDTH_MBIT downto 0);
signal recv_L : std_logic_vector(LR_WIDTH-1 downto 0);
signal recv_R : std_logic_vector(LR_WIDTH-1 downto 0);
begin
-- i2s clock
-- (accepting a slip of one fast clock period)
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
sck_d <= '0';
else
sck_d <= i_i2s_sck;
end if;
end if;
end process;
sck_re <= i_i2s_sck and not sck_d;
sck_fe <= sck_d and not i_i2s_sck;
-- change activation edge for wsp
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
wsp_e <= '0';
elsif sck_fe = '1' then
wsp_e <= i_i2s_wsp;
end if;
end if;
end process;
-- bit receiver
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
receiver <= (others => '0');
recv_count <= std_logic_vector(to_unsigned(LR_WIDTH-1, recv_count'length));
elsif sck_re = '1' then
if wsp_e = '1' then
receiver(LR_WIDTH) <= i_i2s_sd;
receiver(LR_WIDTH-1 downto 0) <= (others => '0');
recv_count <= std_logic_vector(to_unsigned(LR_WIDTH-1, recv_count'length));
else
receiver(to_integer(unsigned(recv_count))) <= i_i2s_sd;
if recv_count /= std_logic_vector(to_unsigned(0, recv_count'length)) then
recv_count <= recv_count - 1;
end if;
end if;
end if;
end if;
end process;
-- LR load
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
recv_L <= (others => '0');
recv_R <= (others => '0');
elsif sck_fe = '1' and i_i2s_wsp = '1' then
if i_i2s_ws = '0' then
recv_R <= receiver(LR_WIDTH downto 1);
else
recv_L <= receiver(LR_WIDTH downto 1);
end if;
end if;
end if;
end process;
-- output
o_i2s_L <= recv_L;
o_i2s_R <= recv_R;
end architecture;

View File

@@ -0,0 +1,74 @@
-- I2S Slave
-- Copyright 2020 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
-- Generates:
-- wsp - one on falling edge of sck indicates channel change
--
-- Reference:
-- <https://web.archive.org/web/20070102004400/http://www.nxp.com/acrobat_download/various/I2SBUS.pdf>
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity i2s_slave is
port
(
i_i2s_sck : in std_logic;
i_i2s_ws : in std_logic;
o_i2s_sck : out std_logic;
o_i2s_ws : out std_logic;
o_i2s_wsp : out std_logic
);
end entity;
architecture rtl of i2s_slave is
signal ws_d : std_logic;
begin
o_i2s_sck <= i_i2s_sck;
o_i2s_ws <= i_i2s_ws;
-- generate wsp
process (i_i2s_sck)
begin
if rising_edge(i_i2s_sck) then
ws_d <= i_i2s_ws;
end if;
end process;
process (i_i2s_sck)
begin
if rising_edge(i_i2s_sck) then
if i_i2s_ws /= ws_d then
o_i2s_wsp <= '1';
else
o_i2s_wsp <= '0';
end if;
end if;
end process;
end architecture;

View File

@@ -0,0 +1,103 @@
-- I2S Transmitter
-- Copyright 2020 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
-- Reference:
-- <https://web.archive.org/web/20070102004400/http://www.nxp.com/acrobat_download/various/I2SBUS.pdf>
--
-- Signals are already synchronized
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity i2s_transmit is
generic
(
constant LR_WIDTH : positive := 8 -- number of bits in the left and right channels (8: 7 downto 0)
);
port
(
i_CLK : in std_logic;
i_reset : in std_logic;
i_i2s_sck : in std_logic;
i_i2s_ws : in std_logic;
i_i2s_wsp : in std_logic;
o_i2s_sd : out std_logic;
i_i2s_L : in std_logic_vector(LR_WIDTH-1 downto 0);
i_i2s_R : in std_logic_vector(LR_WIDTH-1 downto 0)
);
end entity;
architecture rtl of i2s_transmit is
signal sck_d : std_logic;
signal sck_fe : std_logic;
signal transmitter : std_logic_vector(LR_WIDTH-1 downto 0);
begin
-- i2s clock
-- (accepting a slip of one fast clock period)
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
sck_d <= '0';
else
sck_d <= i_i2s_sck;
end if;
end if;
end process;
sck_fe <= sck_d and not i_i2s_sck;
-- bit transmitter
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
transmitter(LR_WIDTH-1) <= '1';
transmitter(LR_WIDTH-2 downto 0) <= (others => '0');
elsif sck_fe = '1' then
if i_i2s_wsp = '1' then
if i_i2s_ws = '0' then
transmitter <= i_i2s_L;
else
transmitter <= i_i2s_R;
end if;
else
transmitter <= transmitter(LR_WIDTH-2 downto 0) & '0';
end if;
end if;
end if;
end process;
-- output
o_i2s_sd <= transmitter(LR_WIDTH-1);
end architecture;

97
rtl/audio/pwm.vhd Normal file
View File

@@ -0,0 +1,97 @@
-- Pulse Width Modulator DAC
-- Copyright 2020 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
-- Generates N/M output on a sample period of M
-- Sample rate = i_CLK / M
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity pwm is
generic
(
M : integer := 255;
M_bit : integer := 7 -- highest bit number to represent M
);
port
(
i_CLK : in std_logic;
i_reset : in std_logic;
i_pcm : in std_logic_vector(M_bit downto 0);
o_pwm : out std_logic
);
end entity;
architecture rtl of pwm is
signal sample : std_logic_vector(M_bit downto 0);
signal period : std_logic_vector(M_bit downto 0);
signal tally : std_logic_vector(M_bit+1 downto 0);
signal delta : std_logic_vector(M_bit+1 downto 0);
signal pwm_one : std_logic;
begin
-- period counter
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
period <= (others => '0');
elsif period = M then
period <= (others => '0');
else
period <= period + 1;
end if;
end if;
end process;
-- pwm output
pwm_one <= '1' when tally >= ('0' & std_logic_vector(to_unsigned(M, M_bit+1))) else '0';
delta <= ('0' & sample) when pwm_one = '0' else (('0' & sample) - ('0' & std_logic_vector(to_unsigned(M, M_bit+1))));
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
tally <= (others => '0');
sample <= (others => '0');
elsif period = M then
tally <= '0' & i_pcm;
sample <= i_pcm;
else
tally <= tally + delta;
end if;
end if;
end process;
-- output
o_pwm <= pwm_one;
end architecture;

117
rtl/audio/soundrive.vhd Normal file
View File

@@ -0,0 +1,117 @@
-- ZX Spectrum Next 4 x 8-bit DAC
-- Copyright 2020 Victor Trucco
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity soundrive is
port
(
clock_i : in std_logic;
reset_i : in std_logic;
cpu_d_i : in std_logic_vector(7 downto 0);
-- left
chA_wr_i : in std_logic;
chB_wr_i : in std_logic;
-- right
chC_wr_i : in std_logic;
chD_wr_i : in std_logic;
-- nextreg mirrors
nr_mono_we_i : in std_logic;
nr_left_we_i : in std_logic;
nr_right_we_i : in std_logic;
nr_audio_dat_i : in std_logic_vector(7 downto 0);
-- pcm audio out
pcm_L_o : out std_logic_vector(8 downto 0);
pcm_R_o : out std_logic_vector(8 downto 0)
);
end entity;
architecture rtl of soundrive is
signal chA : std_logic_vector(7 downto 0);
signal chB : std_logic_vector(7 downto 0);
signal chC : std_logic_vector(7 downto 0);
signal chD : std_logic_vector(7 downto 0);
begin
process (clock_i)
begin
if rising_edge(clock_i) then
if reset_i = '1' then
chA <= X"80";
chB <= X"80";
chC <= X"80";
chD <= X"80";
else
if chA_wr_i = '1' then
chA <= cpu_d_i;
elsif nr_mono_we_i = '1' then
chA <= nr_audio_dat_i;
end if;
if chB_wr_i = '1' then
chB <= cpu_d_i;
elsif nr_left_we_i = '1' then
chB <= nr_audio_dat_i;
end if;
if chC_wr_i = '1' then
chC <= cpu_d_i;
elsif nr_right_we_i = '1' then
chC <= nr_audio_dat_i;
end if;
if chD_wr_i = '1' then
chD <= cpu_d_i;
elsif nr_mono_we_i = '1' then
chD <= nr_audio_dat_i;
end if;
end if;
end if;
end process;
process (clock_i)
begin
if rising_edge(clock_i) then
pcm_L_o <= ('0' & chA) + ('0' & chB);
pcm_R_o <= ('0' & chC) + ('0' & chD);
end if;
end process;
end architecture;

339
rtl/audio/turbosound.vhd Normal file
View File

@@ -0,0 +1,339 @@
-- TurboSound Next
-- Copyright 2020 Fabio Belavenuto and Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity turbosound is
port
(
clock_i : in std_logic;
clock_en_i : in std_logic;
reset_i : in std_logic;
aymode_i : in std_logic; -- 0 = YM, 1 = AY
turbosound_en_i : in std_logic; -- 0 = use one AY, 1 = enable all AY
psg_reg_addr_i : in std_logic; -- select a new ay register
psg_reg_wr_i : in std_logic; -- write to selected register
psg_d_i : in std_logic_vector(7 downto 0); -- data in
psg_d_o_reg_i : in std_logic; -- output selected register rather than contents
psg_d_o : out std_logic_vector(7 downto 0); -- selected register's contents
mono_mode_i : in std_logic_vector(2 downto 0); -- 0 = stereo, 1 = mono for each psg
stereo_mode_i : in std_logic; -- 0 = ABC, 1 = ACB for all psg
-- port_a_i : in std_logic_vector(7 downto 0); -- IO Port A input on default AY
-- port_a_o : out std_logic_vector(7 downto 0); -- current R14 state
pcm_ay_L_o : out std_logic_vector(11 downto 0);
pcm_ay_R_o : out std_logic_vector(11 downto 0)
);
end entity;
architecture rtl of turbosound is
signal ay_select : std_logic_vector(1 downto 0);
signal psg0_pan : std_logic_vector(1 downto 0);
signal psg1_pan : std_logic_vector(1 downto 0);
signal psg2_pan : std_logic_vector(1 downto 0);
signal psg_addr : std_logic;
signal psg0_addr : std_logic;
signal psg0_we : std_logic;
signal psg1_addr : std_logic;
signal psg1_we : std_logic;
signal psg2_addr : std_logic;
signal psg2_we : std_logic;
signal psg0_do : std_logic_vector(7 downto 0);
signal psg0_A : std_logic_vector(7 downto 0);
signal psg0_B : std_logic_vector(7 downto 0);
signal psg0_C : std_logic_vector(7 downto 0);
signal psg0_L_mux : std_logic_vector(7 downto 0);
signal psg0_L_sum : std_logic_vector(8 downto 0);
signal psg0_R_mux : std_logic_vector(8 downto 0);
signal psg0_R_sum : std_logic_vector(9 downto 0);
signal psg0_L_fin : std_logic_vector(9 downto 0);
signal psg0_L : std_logic_vector(9 downto 0);
signal psg0_R : std_logic_vector(9 downto 0);
signal psg1_do : std_logic_vector(7 downto 0);
signal psg1_A : std_logic_vector(7 downto 0);
signal psg1_B : std_logic_vector(7 downto 0);
signal psg1_C : std_logic_vector(7 downto 0);
signal psg1_L_mux : std_logic_vector(7 downto 0);
signal psg1_L_sum : std_logic_vector(8 downto 0);
signal psg1_R_mux : std_logic_vector(8 downto 0);
signal psg1_R_sum : std_logic_vector(9 downto 0);
signal psg1_L_fin : std_logic_vector(9 downto 0);
signal psg1_L : std_logic_vector(9 downto 0);
signal psg1_R : std_logic_vector(9 downto 0);
signal psg2_do : std_logic_vector(7 downto 0);
signal psg2_A : std_logic_vector(7 downto 0);
signal psg2_B : std_logic_vector(7 downto 0);
signal psg2_C : std_logic_vector(7 downto 0);
signal psg2_L_mux : std_logic_vector(7 downto 0);
signal psg2_L_sum : std_logic_vector(8 downto 0);
signal psg2_R_mux : std_logic_vector(8 downto 0);
signal psg2_R_sum : std_logic_vector(9 downto 0);
signal psg2_L_fin : std_logic_vector(9 downto 0);
signal psg2_L : std_logic_vector(9 downto 0);
signal psg2_R : std_logic_vector(9 downto 0);
signal psg0_L_pan : std_logic_vector(9 downto 0);
signal psg1_L_pan : std_logic_vector(9 downto 0);
signal psg2_L_pan : std_logic_vector(9 downto 0);
signal psg0_R_pan : std_logic_vector(9 downto 0);
signal psg1_R_pan : std_logic_vector(9 downto 0);
signal psg2_R_pan : std_logic_vector(9 downto 0);
begin
--
-- AY Select & Panning
--
process (clock_i)
begin
if rising_edge(clock_i) then
if reset_i = '1' then
ay_select <= "11";
psg0_pan <= "11";
psg1_pan <= "11";
psg2_pan <= "11";
elsif turbosound_en_i = '1' and psg_reg_addr_i = '1' and psg_d_i(7) = '1' and psg_d_i(4 downto 2) = "111" then
case psg_d_i(1 downto 0) is
when "10" => psg1_pan <= psg_d_i(6 downto 5); ay_select <= "10";
when "01" => psg2_pan <= psg_d_i(6 downto 5); ay_select <= "01";
when others => psg0_pan <= psg_d_i(6 downto 5); ay_select <= "11";
end case;
end if;
end if;
end process;
psg_addr <= '1' when psg_reg_addr_i = '1' and psg_d_i(7 downto 5) = "000" else '0';
psg0_addr <= '1' when ay_select = "11" and psg_addr = '1' else '0';
psg0_we <= '1' when ay_select = "11" and psg_reg_wr_i = '1' else '0';
psg1_addr <= '1' when ay_select = "10" and psg_addr = '1' else '0';
psg1_we <= '1' when ay_select = "10" and psg_reg_wr_i = '1' else '0';
psg2_addr <= '1' when ay_select = "01" and psg_addr = '1' else '0';
psg2_we <= '1' when ay_select = "01" and psg_reg_wr_i = '1' else '0';
--
-- AY #0
--
psg0 : entity work.ym2149
generic map (
AY_ID => "11"
)
port map (
CLK => clock_i, -- master clock more than 6MHz
ENA => clock_en_i, -- gated clock signal used by ym2149
RESET_H => reset_i,
I_SEL_L => '1', -- 1 for compatible counting with ay8910
-- data bus
I_DA => psg_d_i,
O_DA => psg0_do, -- read from currently selected register
I_REG => psg_d_o_reg_i,
-- control
busctrl_addr => psg0_addr, -- 1 to change selected register
busctrl_we => psg0_we, -- 1 to write to selected register
ctrl_aymode => aymode_i, -- 0 = YM, 1 = AY
-- I/O ports
port_a_i => (others => '1'), -- external input to IO Port A (reg 14) AY#0
port_a_o => open, -- last byte written to reg 14 (not the same as reading from reg 14) AY#0
port_b_i => (others => '1'),
port_b_o => open,
-- audio channels out
O_AUDIO_A => psg0_A,
O_AUDIO_B => psg0_B,
O_AUDIO_C => psg0_C
);
-- stereo / mono mix
psg0_L_mux <= psg0_C when stereo_mode_i = '1' or mono_mode_i(0) = '1' else psg0_B;
psg0_L_sum <= ('0' & psg0_L_mux) + ('0' & psg0_A);
psg0_R_mux <= psg0_L_sum when mono_mode_i(0) = '1' else ('0' & psg0_C);
psg0_R_sum <= ('0' & psg0_R_mux) + ("00" & psg0_B);
psg0_L_fin <= psg0_R_sum when mono_mode_i(0) = '1' else ('0' & psg0_L_sum);
process (clock_i)
begin
if rising_edge(clock_i) then
if ay_select = "11" or turbosound_en_i = '1' then
psg0_L <= psg0_L_fin;
psg0_R <= psg0_R_sum;
else
psg0_L <= (others => '0');
psg0_R <= (others => '0');
end if;
end if;
end process;
--
-- AY #1
--
psg1 : entity work.ym2149
generic map (
AY_ID => "10"
)
port map (
CLK => clock_i,
ENA => clock_en_i,
RESET_H => reset_i,
I_SEL_L => '1',
-- data bus
I_DA => psg_d_i,
O_DA => psg1_do,
I_REG => psg_d_o_reg_i,
-- control
busctrl_addr => psg1_addr,
busctrl_we => psg1_we,
ctrl_aymode => aymode_i,
-- I/O ports
port_a_i => (others => '1'),
port_a_o => open,
port_b_i => (others => '1'),
port_b_o => open,
-- audio channels out
O_AUDIO_A => psg1_A,
O_AUDIO_B => psg1_B,
O_AUDIO_C => psg1_C
);
-- stereo / mono mix
psg1_L_mux <= psg1_C when stereo_mode_i = '1' or mono_mode_i(1) = '1' else psg1_B;
psg1_L_sum <= ('0' & psg1_L_mux) + ('0' & psg1_A);
psg1_R_mux <= psg1_L_sum when mono_mode_i(1) = '1' else ('0' & psg1_C);
psg1_R_sum <= ('0' & psg1_R_mux) + ("00" & psg1_B);
psg1_L_fin <= psg1_R_sum when mono_mode_i(1) = '1' else ('0' & psg1_L_sum);
process (clock_i)
begin
if rising_edge(clock_i) then
if ay_select = "10" or turbosound_en_i = '1' then
psg1_L <= psg1_L_fin;
psg1_R <= psg1_R_sum;
else
psg1_L <= (others => '0');
psg1_R <= (others => '0');
end if;
end if;
end process;
--
-- AY #2
--
psg2 : entity work.ym2149
generic map (
AY_ID => "01"
)
port map (
CLK => clock_i,
ENA => clock_en_i,
RESET_H => reset_i,
I_SEL_L => '1',
-- data bus
I_DA => psg_d_i,
O_DA => psg2_do,
I_REG => psg_d_o_reg_i,
-- control
busctrl_addr => psg2_addr,
busctrl_we => psg2_we,
ctrl_aymode => aymode_i,
-- I/O ports
port_a_i => (others => '1'),
port_a_o => open,
port_b_i => (others => '1'),
port_b_o => open,
-- audio channels out
O_AUDIO_A => psg2_A,
O_AUDIO_B => psg2_B,
O_AUDIO_C => psg2_C
);
-- stereo / mono mix
psg2_L_mux <= psg2_C when stereo_mode_i = '1' or mono_mode_i(2) = '1' else psg2_B;
psg2_L_sum <= ('0' & psg2_L_mux) + ('0' & psg2_A);
psg2_R_mux <= psg2_L_sum when mono_mode_i(2) = '1' else ('0' & psg2_C);
psg2_R_sum <= ('0' & psg2_R_mux) + ("00" & psg2_B);
psg2_L_fin <= psg2_R_sum when mono_mode_i(2) = '1' else ('0' & psg2_L_sum);
process (clock_i)
begin
if rising_edge(clock_i) then
if ay_select = "01" or turbosound_en_i = '1' then
psg2_L <= psg2_L_fin;
psg2_R <= psg2_R_sum;
else
psg2_L <= (others => '0');
psg2_R <= (others => '0');
end if;
end if;
end process;
--
-- Turbosound Output
--
psg_d_o <= psg1_do when ay_select = "10" else psg2_do when ay_select = "01" else psg0_do;
psg0_L_pan <= psg0_L when psg0_pan(1) = '1' else (others => '0');
psg1_L_pan <= psg1_L when psg1_pan(1) = '1' else (others => '0');
psg2_L_pan <= psg2_L when psg2_pan(1) = '1' else (others => '0');
psg0_R_pan <= psg0_R when psg0_pan(0) = '1' else (others => '0');
psg1_R_pan <= psg1_R when psg1_pan(0) = '1' else (others => '0');
psg2_R_pan <= psg2_R when psg2_pan(0) = '1' else (others => '0');
process (clock_i)
begin
if rising_edge(clock_i) then
pcm_ay_L_o <= ("00" & psg0_L_pan) + ("00" & psg1_L_pan) + ("00" & psg2_L_pan);
pcm_ay_R_o <= ("00" & psg0_R_pan) + ("00" & psg1_R_pan) + ("00" & psg2_R_pan);
end if;
end process;
end architecture;

543
rtl/audio/ym2149.vhd Normal file
View File

@@ -0,0 +1,543 @@
--
-- A simulation model of YM2149 (AY-3-8910 with bells on)
--
-- Copyright (c) MikeJ - Jan 2005
--
-- All rights reserved
--
-- Redistribution and use in source and synthezised forms, with or without
-- modification, are permitted provided that the following conditions are met:
--
-- Redistributions of source code must retain the above copyright notice,
-- this list of conditions and the following disclaimer.
--
-- Redistributions in synthesized form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in the
-- documentation and/or other materials provided with the distribution.
--
-- Neither the name of the author nor the names of other contributors may
-- be used to endorse or promote products derived from this software without
-- specific prior written permission.
--
-- THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-- POSSIBILITY OF SUCH DAMAGE.
--
-- You are responsible for any legal issues arising from your use of this code.
--
-- The latest version of this file can be found at: www.fpgaarcade.com
--
-- Email support@fpgaarcade.com
--
-- Revision list
--
-- version 001 initial release
--
-- Clues from MAME sound driver and Kazuhiro TSUJIKAWA
--
-- These are the measured outputs from a real chip for a single Isolated channel into a 1K load (V)
-- vol 15 .. 0
-- 3.27 2.995 2.741 2.588 2.452 2.372 2.301 2.258 2.220 2.198 2.178 2.166 2.155 2.148 2.141 2.132
-- As the envelope volume is 5 bit, I have fitted a curve to the not quite log shape in order
-- to produced all the required values.
-- (The first part of the curve is a bit steeper and the last bit is more linear than expected)
--
-- Modifications made for the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- 1. Bus addressing moved out of module
-- 2. Channel mixing moved out of module
-- 3. Eliminate unnecessary busctrl_re
-- 4. Make zero volume actually zero volume in the tables.
-- (Not how the real hw works but it makes audio out of the zx next cleaner)
-- 5. Add differences in how registers are read back on YM and AY
-- 6. Fix bug where envelope period counter was not reset on envelope reset
-- 7. Export currently selected register
library ieee;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity YM2149 is
generic (
constant AY_ID : std_logic_vector(1 downto 0) := "00"
);
port (
CLK : in std_logic; -- note 6 Mhz
ENA : in std_logic; -- clock enable for higher speed operation
RESET_H : in std_logic;
I_SEL_L : in std_logic;
-- data bus
I_DA : in std_logic_vector(7 downto 0);
O_DA : out std_logic_vector(7 downto 0);
I_REG : in std_logic;
-- control
busctrl_addr : in std_logic;
busctrl_we : in std_logic;
ctrl_aymode : in std_logic; -- 0 = YM, 1 = AY
-- I/O ports
port_a_i : in std_logic_vector(7 downto 0);
port_a_o : out std_logic_vector(7 downto 0);
port_b_i : in std_logic_vector(7 downto 0);
port_b_o : out std_logic_vector(7 downto 0);
-- audio channels out
O_AUDIO_A : out std_logic_vector(7 downto 0);
O_AUDIO_B : out std_logic_vector(7 downto 0);
O_AUDIO_C : out std_logic_vector(7 downto 0)
);
end;
architecture RTL of YM2149 is
-- signals
type array_16x8 is array (0 to 15) of std_logic_vector(7 downto 0);
type array_3x12 is array (1 to 3) of std_logic_vector(11 downto 0);
signal cnt_div : std_logic_vector(3 downto 0) := (others => '0');
signal noise_div : std_logic := '0';
signal ena_div : std_logic;
signal ena_div_noise : std_logic;
signal noise_gen_comp : std_logic_vector(4 downto 0);
signal poly17_zero : std_logic;
signal poly17 : std_logic_vector(16 downto 0) := (others => '0');
-- registers
signal addr : std_logic_vector(4 downto 0);
signal reg : array_16x8;
signal env_reset : std_logic;
signal noise_gen_cnt : std_logic_vector(4 downto 0);
signal noise_gen_op : std_logic;
signal tone_gen_freq : array_3x12;
signal tone_gen_comp : array_3x12;
signal tone_gen_cnt : array_3x12 := (others => (others => '0'));
signal tone_gen_op : std_logic_vector(3 downto 1) := "000";
signal is_zero : std_logic;
signal is_ones : std_logic;
signal is_bot : std_logic;
signal is_bot_p1 : std_logic;
signal is_top_m1 : std_logic;
signal is_top : std_logic;
signal env_gen_freq : std_logic_vector(15 downto 0);
signal env_gen_comp : std_logic_vector(15 downto 0);
signal env_gen_cnt : std_logic_vector(15 downto 0);
signal env_ena : std_logic;
signal env_hold : std_logic;
signal env_inc : std_logic;
signal env_vol : std_logic_vector(4 downto 0);
signal chan_mixed : std_logic_vector(2 downto 0);
signal A : std_logic_vector(4 downto 0);
signal B : std_logic_vector(4 downto 0);
signal C : std_logic_vector(4 downto 0);
type volTableType32 is array (0 to 31) of unsigned(7 downto 0);
type volTableType16 is array (0 to 15) of unsigned(7 downto 0);
constant volTableAy : volTableType16 :=(
x"00", x"03", x"04", x"06",
x"0a", x"0f", x"15", x"22",
x"28", x"41", x"5b", x"72",
x"90", x"b5", x"d7", x"ff"
);
constant volTableYm : volTableType32 :=(
x"00", x"01", x"01", x"02", x"02", x"03", x"03", x"04",
x"06", x"07", x"09", x"0a", x"0c", x"0e", x"11", x"13",
x"17", x"1b", x"20", x"25", x"2c", x"35", x"3e", x"47",
x"54", x"66", x"77", x"88", x"a1", x"c0", x"e0", x"ff"
);
begin
--p_waddr : process(RESET_H, busctrl_addr)
process(clk)
begin
if clk'event and clk = '1' then
if (RESET_H = '1') then
addr <= (others => '0');
elsif busctrl_addr = '1' then -- yuk
addr <= I_DA(4 downto 0);
end if;
end if;
end process;
--p_wdata : process(RESET_H, busctrl_we, addr)
process(clk)
begin
if clk'event and clk = '1' then
env_reset <= '0';
if RESET_H = '1' then
reg <= (others => (others => '0'));
reg(7) <= x"ff";
elsif busctrl_we = '1' and addr(4) = '0' then -- bits 7:5 are checked for 0 outside this module
case addr(3 downto 0) is
when x"0" => reg(0) <= I_DA;
when x"1" => reg(1) <= I_DA;
when x"2" => reg(2) <= I_DA;
when x"3" => reg(3) <= I_DA;
when x"4" => reg(4) <= I_DA;
when x"5" => reg(5) <= I_DA;
when x"6" => reg(6) <= I_DA;
when x"7" => reg(7) <= I_DA;
when x"8" => reg(8) <= I_DA;
when x"9" => reg(9) <= I_DA;
when x"A" => reg(10) <= I_DA;
when x"B" => reg(11) <= I_DA;
when x"C" => reg(12) <= I_DA;
when x"D" => reg(13) <= I_DA;
when x"E" => reg(14) <= I_DA;
when x"F" => reg(15) <= I_DA;
when others => null;
end case;
if addr(3 downto 0) = x"D" then
env_reset <= '1';
end if;
end if;
end if;
end process;
--p_rdata : process(busctrl_re, addr, reg)
process(clk)
begin
if clk'event and clk = '1' then
if I_REG = '1' then
O_DA <= AY_ID & '0' & addr;
elsif addr(4) = '1' and ctrl_aymode = '0' then
O_DA <= x"FF";
else
case addr(3 downto 0) is
when x"0" => O_DA <= reg(0) ;
when x"1" => O_DA <= (reg(1)(7) and not ctrl_aymode) & (reg(1)(6) and not ctrl_aymode) & (reg(1)(5) and not ctrl_aymode) & (reg(1)(4) and not ctrl_aymode) & reg(1)(3 downto 0) ;
when x"2" => O_DA <= reg(2) ;
when x"3" => O_DA <= (reg(3)(7) and not ctrl_aymode) & (reg(3)(6) and not ctrl_aymode) & (reg(3)(5) and not ctrl_aymode) & (reg(3)(4) and not ctrl_aymode) & reg(3)(3 downto 0) ;
when x"4" => O_DA <= reg(4) ;
when x"5" => O_DA <= (reg(5)(7) and not ctrl_aymode) & (reg(5)(6) and not ctrl_aymode) & (reg(5)(5) and not ctrl_aymode) & (reg(5)(4) and not ctrl_aymode) & reg(5)(3 downto 0) ;
when x"6" => O_DA <= (reg(6)(7) and not ctrl_aymode) & (reg(6)(6) and not ctrl_aymode) & (reg(6)(5) and not ctrl_aymode) & reg(6)(4 downto 0) ;
when x"7" => O_DA <= reg(7) ;
when x"8" => O_DA <= (reg(8)(7) and not ctrl_aymode) & (reg(8)(6) and not ctrl_aymode) & (reg(8)(5) and not ctrl_aymode) & reg(8)(4 downto 0) ;
when x"9" => O_DA <= (reg(9)(7) and not ctrl_aymode) & (reg(9)(6) and not ctrl_aymode) & (reg(9)(5) and not ctrl_aymode) & reg(9)(4 downto 0) ;
when x"A" => O_DA <= (reg(10)(7) and not ctrl_aymode) & (reg(10)(6) and not ctrl_aymode) & (reg(10)(5) and not ctrl_aymode) & reg(10)(4 downto 0) ;
when x"B" => O_DA <= reg(11);
when x"C" => O_DA <= reg(12);
when x"D" => O_DA <= (reg(13)(7) and not ctrl_aymode) & (reg(13)(6) and not ctrl_aymode) & (reg(13)(5) and not ctrl_aymode) & (reg(13)(4) and not ctrl_aymode) & reg(13)(3 downto 0) ;
when x"E" => if (reg(7)(6) = '0') then -- input
O_DA <= port_a_i;
else
O_DA <= reg(14) and port_a_i;
end if;
when x"F" => if (Reg(7)(7) = '0') then
O_DA <= port_b_i;
else
O_DA <= reg(15) and port_b_i;
end if;
when others => null;
end case;
end if;
end if;
end process;
port_a_o <= reg(14);
port_b_o <= reg(15);
-- p_divider : process
process(clk)
begin
if clk'event and clk = '1' then
if ENA = '1' then
ena_div <= '0';
ena_div_noise <= '0';
if (cnt_div = "0000") then
cnt_div <= (not I_SEL_L) & "111";
ena_div <= '1';
noise_div <= not noise_div;
if (noise_div = '1') then
ena_div_noise <= '1';
end if;
else
cnt_div <= std_logic_vector(unsigned(cnt_div) - 1);
end if;
end if;
end if;
end process;
-- p_noise_gen : process
noise_gen_comp <= (std_logic_vector(unsigned(reg(6)(4 downto 0)) - 1)) when (reg(6)(4 downto 1) /= "0000") else (others => '0');
poly17_zero <= '1' when (poly17 = "00000000000000000") else '0';
process(clk)
begin
if clk'event and clk = '1' then
if (ENA = '1') then
if (ena_div_noise = '1') then -- divider ena
if (noise_gen_cnt >= noise_gen_comp) then
noise_gen_cnt <= "00000";
poly17 <= (poly17(0) xor poly17(2) xor poly17_zero) & poly17(16 downto 1);
else
noise_gen_cnt <= std_logic_vector(unsigned(noise_gen_cnt) + 1);
end if;
end if;
end if;
end if;
end process;
noise_gen_op <= poly17(0);
--p_tone_gens : process
tone_gen_freq(1) <= reg(1)(3 downto 0) & reg(0);
tone_gen_freq(2) <= reg(3)(3 downto 0) & reg(2);
tone_gen_freq(3) <= reg(5)(3 downto 0) & reg(4);
tone_gen_comp(1) <= (std_logic_vector(unsigned(tone_gen_freq(1)) - 1)) when (tone_gen_freq(1)(11 downto 1) /= (x"00" & "000")) else (others => '0');
tone_gen_comp(2) <= (std_logic_vector(unsigned(tone_gen_freq(2)) - 1)) when (tone_gen_freq(2)(11 downto 1) /= (x"00" & "000")) else (others => '0');
tone_gen_comp(3) <= (std_logic_vector(unsigned(tone_gen_freq(3)) - 1)) when (tone_gen_freq(3)(11 downto 1) /= (x"00" & "000")) else (others => '0');
process(clk)
begin
if clk'event and clk = '1' then
if (ENA = '1') then
for i in 1 to 3 loop
if (ena_div = '1') then -- divider ena
if (tone_gen_cnt(i) >= tone_gen_comp(i)) then
tone_gen_cnt(i) <= x"000";
tone_gen_op(i) <= not tone_gen_op(i);
else
tone_gen_cnt(i) <= std_logic_vector(unsigned(tone_gen_cnt(i)) + 1);
end if;
end if;
end loop;
end if;
end if;
end process;
--p_envelope_freq : process
env_gen_freq <= reg(12) & reg(11);
env_gen_comp <= (std_logic_vector(unsigned(env_gen_freq) - 1)) when (env_gen_freq(15 downto 1) /= (x"000" & "000")) else (others => '0');
process(clk)
begin
if clk'event and clk = '1' then
if env_reset = '1' then
env_gen_cnt <= x"0000";
env_ena <= '1';
elsif (ENA = '1') then
if (ena_div = '1') then -- divider ena
if (env_gen_cnt >= env_gen_comp) then
env_gen_cnt <= x"0000";
env_ena <= '1';
else
env_gen_cnt <= std_logic_vector( unsigned( env_gen_cnt ) + 1 );
env_ena <= '0';
end if;
else
env_ena <= '0';
end if;
end if;
end if;
end process;
--p_envelope_shape : process(env_reset, CLK)
is_zero <= '1' when env_vol(4 downto 1) = "0000" else '0';
is_ones <= '1' when env_vol(4 downto 1) = "1111" else '0';
is_bot <= '1' when is_zero = '1' and env_vol(0) = '0' else '0';
is_bot_p1 <= '1' when is_zero ='1' and env_vol(0) = '1' else '0';
is_top_m1 <= '1' when is_ones = '1' and env_vol(0) = '0' else '0';
is_top <= '1' when is_ones = '1' and env_vol(0) = '1' else '0';
process(clk)
begin
-- envelope shapes
-- C AtAlH
-- 0 0 x x \___
--
-- 0 1 x x /___
--
-- 1 0 0 0 \\\\
--
-- 1 0 0 1 \___
--
-- 1 0 1 0 \/\/
-- ___
-- 1 0 1 1 \
--
-- 1 1 0 0 ////
-- ___
-- 1 1 0 1 /
--
-- 1 1 1 0 /\/\
--
-- 1 1 1 1 /___
if clk'event and clk = '1' then
if env_reset = '1' then
-- load initial state
if (reg(13)(2) = '0') then -- attack
env_vol <= "11111";
env_inc <= '0'; -- -1
else
env_vol <= "00000";
env_inc <= '1'; -- +1
end if;
env_hold <= '0';
elsif (ENA = '1') and (env_ena = '1') then
if (env_hold = '0') then
if (env_inc = '1') then
env_vol <= std_logic_vector( unsigned( env_vol ) + "00001");
else
env_vol <= std_logic_vector( unsigned( env_vol ) + "11111");
end if;
end if;
-- envelope shape control.
if (reg(13)(3) = '0') then
if (env_inc = '0') then -- down
if is_bot_p1 = '1' then
env_hold <= '1';
end if;
else
if is_top = '1' then
env_hold <= '1';
end if;
end if;
elsif (reg(13)(0) = '1') then -- hold = 1
if (env_inc = '0') then -- down
if (reg(13)(1) = '1') then -- alt
if is_bot = '1' then
env_hold <= '1';
end if;
else
if is_bot_p1 = '1' then
env_hold <= '1';
end if;
end if;
else
if (reg(13)(1) = '1') then -- alt
if is_top = '1' then
env_hold <= '1';
end if;
else
if is_top_m1 = '1' then
env_hold <= '1';
end if;
end if;
end if;
elsif (reg(13)(1) = '1') then -- alternate
if (env_inc = '0') then -- down
if is_bot_p1 = '1' then
env_hold <= '1';
end if;
if is_bot = '1' then
env_hold <= '0';
env_inc <= '1';
end if;
else
if is_top_m1 = '1' then
env_hold <= '1';
end if;
if is_top = '1' then
env_hold <= '0';
env_inc <= '0';
end if;
end if;
end if;
end if;
end if;
end process;
--p_chan_mixer_table : process
chan_mixed(0) <= (reg(7)(0) or tone_gen_op(1)) and (reg(7)(3) or noise_gen_op);
chan_mixed(1) <= (reg(7)(1) or tone_gen_op(2)) and (reg(7)(4) or noise_gen_op);
chan_mixed(2) <= (reg(7)(2) or tone_gen_op(3)) and (reg(7)(5) or noise_gen_op);
process(clk)
begin
if clk'event and clk = '1' then
if (ENA = '1') then
A <= "00000";
B <= "00000";
C <= "00000";
if (chan_mixed(0) = '1') then
if (reg(8)(4) = '0') then
if (reg(8)(3 downto 0) = "0000") then
A <= "00000";
else
A <= reg(8)(3 downto 0) & "1";
end if;
else
A <= env_vol(4 downto 0);
end if;
end if;
if (chan_mixed(1) = '1') then
if (reg(9)(4) = '0') then
if (reg(9)(3 downto 0) = "0000") then
B <= "00000";
else
B <= reg(9)(3 downto 0) & "1";
end if;
else
B <= env_vol(4 downto 0);
end if;
end if;
if (chan_mixed(2) = '1') then
if (reg(10)(4) = '0') then
if (reg(10)(3 downto 0) = "0000") then
C <= "00000";
else
C <= reg(10)(3 downto 0) & "1";
end if;
else
C <= env_vol(4 downto 0);
end if;
end if;
end if;
end if;
end process;
process(clk)
begin
if clk'event and clk = '1' then
if RESET_H = '1' then
O_AUDIO_A <= x"00";
O_AUDIO_B <= x"00";
O_AUDIO_C <= x"00";
else
if(ctrl_aymode = '0') then
O_AUDIO_A <= std_logic_vector( volTableYm( to_integer( unsigned( A ) ) ) );
O_AUDIO_B <= std_logic_vector( volTableYm( to_integer( unsigned( B ) ) ) );
O_AUDIO_C <= std_logic_vector( volTableYm( to_integer( unsigned( C ) ) ) );
else
O_AUDIO_A <= std_logic_vector( volTableAy( to_integer( unsigned( A(4 downto 1) ) ) ) );
O_AUDIO_B <= std_logic_vector( volTableAy( to_integer( unsigned( B(4 downto 1) ) ) ) );
O_AUDIO_C <= std_logic_vector( volTableAy( to_integer( unsigned( C(4 downto 1) ) ) ) );
end if;
end if;
end if;
end process;
end architecture RTL;

1772
rtl/cpu/t80n.vhd Normal file

File diff suppressed because it is too large Load Diff

364
rtl/cpu/t80n_alu.vhd Normal file
View File

@@ -0,0 +1,364 @@
--
-- Z80 compatible microprocessor core
--
-- Version : 0247
--
-- Copyright (c) 2001-2002 Daniel Wallner (jesus@opencores.org)
--
-- Modifications for the ZX Spectrum Next Project
-- Copyright 2020 Fabio Belavenuto, Victor Trucco, Charlie Ingley, Garry Lancaster, ACX
--
-- All rights reserved
--
-- Redistribution and use in source and synthezised forms, with or without
-- modification, are permitted provided that the following conditions are met:
--
-- Redistributions of source code must retain the above copyright notice,
-- this list of conditions and the following disclaimer.
--
-- Redistributions in synthesized form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in the
-- documentation and/or other materials provided with the distribution.
--
-- Neither the name of the author nor the names of other contributors may
-- be used to endorse or promote products derived from this software without
-- specific prior written permission.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-- POSSIBILITY OF SUCH DAMAGE.
--
-- Please report bugs to the author, but before you do so, please
-- make sure that this is not a derivative work and that
-- you have the latest version of this file.
--
-- The latest version of this file can be found at:
-- http://www.opencores.org/cvsweb.shtml/t80/
--
-- Limitations :
--
-- File history :
--
-- 0214 : Fixed mostly flags, only the block instructions now fail the zex regression test
--
-- 0238 : Fixed zero flag for 16 bit SBC and ADC
--
-- 0240 : Added GB operations
--
-- 0242 : Cleanup
--
-- 0247 : Cleanup
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- Modifications for the ZX Spectrum Next were made by:
--
-- Fabio Belavenuto : partial fix of wait bug
-- Victor Trucco, Fabio Belavenuto, Garry Lancaster : additional instructions
-- Charlie Ingley : complete fix of wait logic
-- ACX : implement undocumented flags for SLI r,(IY+s)
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity T80N_ALU is
generic(
Mode : integer := 0;
Flag_C : integer := 0;
Flag_N : integer := 1;
Flag_P : integer := 2;
Flag_X : integer := 3;
Flag_H : integer := 4;
Flag_Y : integer := 5;
Flag_Z : integer := 6;
Flag_S : integer := 7
);
port(
Arith16 : in std_logic;
Z16 : in std_logic;
ALU_Op : in std_logic_vector(3 downto 0);
IR : in std_logic_vector(5 downto 0);
ISet : in std_logic_vector(1 downto 0);
BusA : in std_logic_vector(7 downto 0);
BusB : in std_logic_vector(7 downto 0);
F_In : in std_logic_vector(7 downto 0);
Q : out std_logic_vector(7 downto 0);
F_Out : out std_logic_vector(7 downto 0)
);
end T80N_ALU;
architecture rtl of T80N_ALU is
procedure AddSub(A : std_logic_vector;
B : std_logic_vector;
Sub : std_logic;
Carry_In : std_logic;
signal Res : out std_logic_vector;
signal Carry : out std_logic) is
variable B_i : unsigned(A'length - 1 downto 0);
variable Res_i : unsigned(A'length + 1 downto 0);
begin
if Sub = '1' then
B_i := not unsigned(B);
else
B_i := unsigned(B);
end if;
Res_i := unsigned("0" & A & Carry_In) + unsigned("0" & B_i & "1");
Carry <= Res_i(A'length + 1);
Res <= std_logic_vector(Res_i(A'length downto 1));
end;
-- AddSub variables (temporary signals)
signal UseCarry : std_logic;
signal Carry7_v : std_logic;
signal Overflow_v : std_logic;
signal HalfCarry_v : std_logic;
signal Carry_v : std_logic;
signal Q_v : std_logic_vector(7 downto 0);
signal BitMask : std_logic_vector(7 downto 0);
begin
with IR(5 downto 3) select BitMask <= "00000001" when "000",
"00000010" when "001",
"00000100" when "010",
"00001000" when "011",
"00010000" when "100",
"00100000" when "101",
"01000000" when "110",
"10000000" when others;
UseCarry <= not ALU_Op(2) and ALU_Op(0);
AddSub(BusA(3 downto 0), BusB(3 downto 0), ALU_Op(1), ALU_Op(1) xor (UseCarry and F_In(Flag_C)), Q_v(3 downto 0), HalfCarry_v);
AddSub(BusA(6 downto 4), BusB(6 downto 4), ALU_Op(1), HalfCarry_v, Q_v(6 downto 4), Carry7_v);
AddSub(BusA(7 downto 7), BusB(7 downto 7), ALU_Op(1), Carry7_v, Q_v(7 downto 7), Carry_v);
OverFlow_v <= Carry_v xor Carry7_v;
process (Arith16, ALU_OP, F_In, BusA, BusB, IR, Q_v, Carry_v, HalfCarry_v, OverFlow_v, BitMask, ISet, Z16)
variable Q_t : std_logic_vector(7 downto 0);
variable DAA_Q : unsigned(8 downto 0);
begin
Q_t := "--------";
F_Out <= F_In;
DAA_Q := "---------";
case ALU_Op is
when "0000" | "0001" | "0010" | "0011" | "0100" | "0101" | "0110" | "0111" =>
F_Out(Flag_N) <= '0';
F_Out(Flag_C) <= '0';
case ALU_OP(2 downto 0) is
when "000" | "001" => -- ADD, ADC
Q_t := Q_v;
F_Out(Flag_C) <= Carry_v;
F_Out(Flag_H) <= HalfCarry_v;
F_Out(Flag_P) <= OverFlow_v;
when "010" | "011" | "111" => -- SUB, SBC, CP
Q_t := Q_v;
F_Out(Flag_N) <= '1';
F_Out(Flag_C) <= not Carry_v;
F_Out(Flag_H) <= not HalfCarry_v;
F_Out(Flag_P) <= OverFlow_v;
when "100" => -- AND
Q_t(7 downto 0) := BusA and BusB;
F_Out(Flag_H) <= '1';
when "101" => -- XOR
Q_t(7 downto 0) := BusA xor BusB;
F_Out(Flag_H) <= '0';
when others => -- OR "110"
Q_t(7 downto 0) := BusA or BusB;
F_Out(Flag_H) <= '0';
end case;
if ALU_Op(2 downto 0) = "111" then -- CP
F_Out(Flag_X) <= BusB(3);
F_Out(Flag_Y) <= BusB(5);
else
F_Out(Flag_X) <= Q_t(3);
F_Out(Flag_Y) <= Q_t(5);
end if;
if Q_t(7 downto 0) = "00000000" then
F_Out(Flag_Z) <= '1';
if Z16 = '1' then
F_Out(Flag_Z) <= F_In(Flag_Z); -- 16 bit ADC,SBC
end if;
else
F_Out(Flag_Z) <= '0';
end if;
F_Out(Flag_S) <= Q_t(7);
case ALU_Op(2 downto 0) is
when "000" | "001" | "010" | "011" | "111" => -- ADD, ADC, SUB, SBC, CP
when others =>
F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor
Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7));
end case;
if Arith16 = '1' then
F_Out(Flag_S) <= F_In(Flag_S);
F_Out(Flag_Z) <= F_In(Flag_Z);
F_Out(Flag_P) <= F_In(Flag_P);
end if;
when "1100" =>
-- DAA
F_Out(Flag_H) <= F_In(Flag_H);
F_Out(Flag_C) <= F_In(Flag_C);
DAA_Q(7 downto 0) := unsigned(BusA);
DAA_Q(8) := '0';
if F_In(Flag_N) = '0' then
-- After addition
-- Alow > 9 or H = 1
if DAA_Q(3 downto 0) > 9 or F_In(Flag_H) = '1' then
if (DAA_Q(3 downto 0) > 9) then
F_Out(Flag_H) <= '1';
else
F_Out(Flag_H) <= '0';
end if;
DAA_Q := DAA_Q + 6;
end if;
-- new Ahigh > 9 or C = 1
if DAA_Q(8 downto 4) > 9 or F_In(Flag_C) = '1' then
DAA_Q := DAA_Q + 96; -- 0x60
end if;
else
-- After subtraction
if DAA_Q(3 downto 0) > 9 or F_In(Flag_H) = '1' then
if DAA_Q(3 downto 0) > 5 then
F_Out(Flag_H) <= '0';
end if;
DAA_Q(7 downto 0) := DAA_Q(7 downto 0) - 6;
end if;
if unsigned(BusA) > 153 or F_In(Flag_C) = '1' then
DAA_Q := DAA_Q - 352; -- 0x160
end if;
end if;
F_Out(Flag_X) <= DAA_Q(3);
F_Out(Flag_Y) <= DAA_Q(5);
F_Out(Flag_C) <= F_In(Flag_C) or DAA_Q(8);
Q_t := std_logic_vector(DAA_Q(7 downto 0));
if DAA_Q(7 downto 0) = "00000000" then
F_Out(Flag_Z) <= '1';
else
F_Out(Flag_Z) <= '0';
end if;
F_Out(Flag_S) <= DAA_Q(7);
F_Out(Flag_P) <= not (DAA_Q(0) xor DAA_Q(1) xor DAA_Q(2) xor DAA_Q(3) xor
DAA_Q(4) xor DAA_Q(5) xor DAA_Q(6) xor DAA_Q(7));
when "1101" | "1110" =>
-- RLD, RRD
Q_t(7 downto 4) := BusA(7 downto 4);
if ALU_Op(0) = '1' then
Q_t(3 downto 0) := BusB(7 downto 4);
else
Q_t(3 downto 0) := BusB(3 downto 0);
end if;
F_Out(Flag_H) <= '0';
F_Out(Flag_N) <= '0';
F_Out(Flag_X) <= Q_t(3);
F_Out(Flag_Y) <= Q_t(5);
if Q_t(7 downto 0) = "00000000" then
F_Out(Flag_Z) <= '1';
else
F_Out(Flag_Z) <= '0';
end if;
F_Out(Flag_S) <= Q_t(7);
F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor
Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7));
when "1001" =>
-- BIT
Q_t(7 downto 0) := BusB and BitMask;
F_Out(Flag_S) <= Q_t(7);
if Q_t(7 downto 0) = "00000000" then
F_Out(Flag_Z) <= '1';
F_Out(Flag_P) <= '1';
else
F_Out(Flag_Z) <= '0';
F_Out(Flag_P) <= '0';
end if;
F_Out(Flag_H) <= '1';
F_Out(Flag_N) <= '0';
F_Out(Flag_X) <= '0';
F_Out(Flag_Y) <= '0';
if IR(2 downto 0) /= "110" then
F_Out(Flag_X) <= BusB(3);
F_Out(Flag_Y) <= BusB(5);
end if;
when "1010" =>
-- SET
Q_t(7 downto 0) := BusB or BitMask;
when "1011" =>
-- RES
Q_t(7 downto 0) := BusB and not BitMask;
when "1000" =>
-- ROT
case IR(5 downto 3) is
when "000" => -- RLC
Q_t(7 downto 1) := BusA(6 downto 0);
Q_t(0) := BusA(7);
F_Out(Flag_C) <= BusA(7);
when "010" => -- RL
Q_t(7 downto 1) := BusA(6 downto 0);
Q_t(0) := F_In(Flag_C);
F_Out(Flag_C) <= BusA(7);
when "001" => -- RRC
Q_t(6 downto 0) := BusA(7 downto 1);
Q_t(7) := BusA(0);
F_Out(Flag_C) <= BusA(0);
when "011" => -- RR
Q_t(6 downto 0) := BusA(7 downto 1);
Q_t(7) := F_In(Flag_C);
F_Out(Flag_C) <= BusA(0);
when "100" => -- SLA
Q_t(7 downto 1) := BusA(6 downto 0);
Q_t(0) := '0';
F_Out(Flag_C) <= BusA(7);
when "110" => -- SLL (Undocumented) / SWAP
if Mode = 3 then
Q_t(7 downto 4) := BusA(3 downto 0);
Q_t(3 downto 0) := BusA(7 downto 4);
F_Out(Flag_C) <= '0';
else
Q_t(7 downto 1) := BusA(6 downto 0);
Q_t(0) := '1';
F_Out(Flag_C) <= BusA(7);
end if;
when "101" => -- SRA
Q_t(6 downto 0) := BusA(7 downto 1);
Q_t(7) := BusA(7);
F_Out(Flag_C) <= BusA(0);
when others => -- SRL
Q_t(6 downto 0) := BusA(7 downto 1);
Q_t(7) := '0';
F_Out(Flag_C) <= BusA(0);
end case;
F_Out(Flag_H) <= '0';
F_Out(Flag_N) <= '0';
F_Out(Flag_X) <= Q_t(3);
F_Out(Flag_Y) <= Q_t(5);
F_Out(Flag_S) <= Q_t(7);
if Q_t(7 downto 0) = "00000000" then
F_Out(Flag_Z) <= '1';
else
F_Out(Flag_Z) <= '0';
end if;
F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor
Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7));
if ISet = "00" then
F_Out(Flag_P) <= F_In(Flag_P);
F_Out(Flag_S) <= F_In(Flag_S);
F_Out(Flag_Z) <= F_In(Flag_Z);
end if;
when others =>
null;
end case;
Q <= Q_t;
end process;
end;

2610
rtl/cpu/t80n_mcode.vhd Normal file

File diff suppressed because it is too large Load Diff

265
rtl/cpu/t80n_pack.vhd Normal file
View File

@@ -0,0 +1,265 @@
--
-- Z80 compatible microprocessor core
--
-- Version : 0242
--
-- Copyright (c) 2001-2002 Daniel Wallner (jesus@opencores.org)
--
-- Modifications for the ZX Spectrum Next Project
-- Copyright 2020 Fabio Belavenuto, Victor Trucco, Charlie Ingley, Garry Lancaster, ACX
--
-- All rights reserved
--
-- Redistribution and use in source and synthezised forms, with or without
-- modification, are permitted provided that the following conditions are met:
--
-- Redistributions of source code must retain the above copyright notice,
-- this list of conditions and the following disclaimer.
--
-- Redistributions in synthesized form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in the
-- documentation and/or other materials provided with the distribution.
--
-- Neither the name of the author nor the names of other contributors may
-- be used to endorse or promote products derived from this software without
-- specific prior written permission.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-- POSSIBILITY OF SUCH DAMAGE.
--
-- Please report bugs to the author, but before you do so, please
-- make sure that this is not a derivative work and that
-- you have the latest version of this file.
--
-- The latest version of this file can be found at:
-- http://www.opencores.org/cvsweb.shtml/t80/
--
-- Limitations :
--
-- File history :
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- Modifications for the ZX Spectrum Next were made by:
--
-- Fabio Belavenuto : partial fix of wait bug
-- Victor Trucco, Fabio Belavenuto, Garry Lancaster : additional instructions
-- Charlie Ingley : complete fix of wait logic
-- ACX : implement undocumented flags for SLI r,(IY+s)
library ieee;
use ieee.std_logic_1164.std_logic_vector;
package Z80N_pack is
type Z80N_seq is ( NONE, MMU, NEXTREGW, MUL_DE, ADD_HL_A, ADD_DE_A, ADD_BC_A, SWAPNIB_A,
PIXELDN, SET_A_E, PIXELAD, MIRROR_A, PUSH_nn, LDPIRX, ADD_HL_nn, ADD_DE_nn,
ADD_BC_nn, LDIRSCALE, BSLA_DE_B, BSRA_DE_B, BSRL_DE_B, BSRF_DE_B, BRLC_DE_B,
JP_C, NMIACK_LSB, NMIACK_MSB, RETN_LSB, RETN_MSB );
signal Z80N_seq_s : Z80N_seq;
end package;
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_1164.all;
use work.Z80N_pack.all;
package T80N_Pack is
component T80N
generic(
Mode : integer := 0; -- 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB
IOWait : integer := 0; -- 1 => Single cycle I/O, 1 => Std I/O cycle
Flag_C : integer := 0;
Flag_N : integer := 1;
Flag_P : integer := 2;
Flag_X : integer := 3;
Flag_H : integer := 4;
Flag_Y : integer := 5;
Flag_Z : integer := 6;
Flag_S : integer := 7
);
port(
RESET_n : in std_logic;
CLK_n : in std_logic;
CEN : in std_logic;
WAIT_n : in std_logic;
INT_n : in std_logic;
NMI_n : in std_logic;
BUSRQ_n : in std_logic;
M1_n : out std_logic;
IORQ : out std_logic;
NoRead : out std_logic;
Write : out std_logic;
RFSH_n : out std_logic;
HALT_n : out std_logic;
BUSAK_n : out std_logic;
A : out std_logic_vector(15 downto 0);
DInst : in std_logic_vector(7 downto 0);
DI : in std_logic_vector(7 downto 0);
DO : out std_logic_vector(7 downto 0);
MC : out std_logic_vector(2 downto 0);
TS : out std_logic_vector(2 downto 0);
IntCycle_n : out std_logic;
IntE : out std_logic;
Stop : out std_logic;
-- extended functions
Z80N_dout_o : out std_logic := '0';
Z80N_data_o : out std_logic_vector(15 downto 0);
Z80N_command_o : out Z80N_seq
);
end component;
component T80N_Reg
port(
Clk : in std_logic;
CEN : in std_logic;
WEH : in std_logic;
WEL : in std_logic;
AddrA : in std_logic_vector(2 downto 0);
AddrB : in std_logic_vector(2 downto 0);
AddrC : in std_logic_vector(2 downto 0);
DIH : in std_logic_vector(7 downto 0);
DIL : in std_logic_vector(7 downto 0);
DOAH : out std_logic_vector(7 downto 0);
DOAL : out std_logic_vector(7 downto 0);
DOBH : out std_logic_vector(7 downto 0);
DOBL : out std_logic_vector(7 downto 0);
DOCH : out std_logic_vector(7 downto 0);
DOCL : out std_logic_vector(7 downto 0);
--extended
reg_wr_i : in std_logic_vector(5 downto 0) := (others=>'0');
reg_BC_i : in std_logic_vector(15 downto 0);
reg_HL_i : in std_logic_vector(15 downto 0);
reg_DE_i : in std_logic_vector(15 downto 0);
reg_BC_o : out std_logic_vector(15 downto 0);
reg_HL_o : out std_logic_vector(15 downto 0);
reg_DE_o : out std_logic_vector(15 downto 0)
);
end component;
component T80N_MCode
generic(
Mode : integer := 0;
Flag_C : integer := 0;
Flag_N : integer := 1;
Flag_P : integer := 2;
Flag_X : integer := 3;
Flag_H : integer := 4;
Flag_Y : integer := 5;
Flag_Z : integer := 6;
Flag_S : integer := 7
);
port(
IR : in std_logic_vector(7 downto 0);
ISet : in std_logic_vector(1 downto 0);
MCycle : in std_logic_vector(2 downto 0);
F : in std_logic_vector(7 downto 0);
NMICycle : in std_logic;
IntCycle : in std_logic;
XY_State : in std_logic_vector(1 downto 0);
MCycles : out std_logic_vector(2 downto 0);
TStates : out std_logic_vector(2 downto 0);
Prefix : out std_logic_vector(1 downto 0); -- None,BC,ED,DD/FD
Inc_PC : out std_logic;
Inc_WZ : out std_logic;
IncDec_16 : out std_logic_vector(3 downto 0); -- BC,DE,HL,SP 0 is inc
Read_To_Reg : out std_logic;
Read_To_Acc : out std_logic;
Set_BusA_To : out std_logic_vector(3 downto 0); -- B,C,D,E,H,L,DI/DB,A,SP(L),SP(M),0,F
Set_BusB_To : out std_logic_vector(3 downto 0); -- B,C,D,E,H,L,DI,A,SP(L),SP(M),1,F,PC(L),PC(M),0
ALU_Op : out std_logic_vector(3 downto 0);
-- ADD, ADC, SUB, SBC, AND, XOR, OR, CP, ROT, BIT, SET, RES, DAA, RLD, RRD, None
Save_ALU : out std_logic;
PreserveC : out std_logic;
Arith16 : out std_logic;
Set_Addr_To : out std_logic_vector(2 downto 0); -- aNone,aXY,aIOA,aSP,aBC,aDE,aZI
IORQ : out std_logic;
Jump : out std_logic;
JumpE : out std_logic;
JumpXY : out std_logic;
Call : out std_logic;
RstP : out std_logic;
LDZ : out std_logic;
LDW : out std_logic;
LDSPHL : out std_logic;
Special_LD : out std_logic_vector(2 downto 0); -- A,I;A,R;I,A;R,A;None
ExchangeDH : out std_logic;
ExchangeRp : out std_logic;
ExchangeAF : out std_logic;
ExchangeRS : out std_logic;
I_DJNZ : out std_logic;
I_CPL : out std_logic;
I_CCF : out std_logic;
I_SCF : out std_logic;
I_RETN : out std_logic;
I_BT : out std_logic;
I_BC : out std_logic;
I_BTR : out std_logic;
I_RLD : out std_logic;
I_RRD : out std_logic;
I_INRC : out std_logic;
SetDI : out std_logic;
SetEI : out std_logic;
IMode : out std_logic_vector(1 downto 0);
Halt : out std_logic;
NoRead : out std_logic;
Write : out std_logic;
XYbit_undoc : out std_logic;
-- entended functions
ext_ACC_i : in std_logic_vector(7 downto 0);
ext_Data_i : in std_logic_vector(7 downto 0);
Z80N_dout_o : out std_logic := '0';
Z80N_data_o : out std_logic_vector(7 downto 0);
Z80N_data_o_strobe_lo : out std_logic;
Z80N_data_o_strobe_hi : out std_logic;
Z80N_command_o : out Z80N_seq
);
end component;
component T80N_ALU
generic(
Mode : integer := 0;
Flag_C : integer := 0;
Flag_N : integer := 1;
Flag_P : integer := 2;
Flag_X : integer := 3;
Flag_H : integer := 4;
Flag_Y : integer := 5;
Flag_Z : integer := 6;
Flag_S : integer := 7
);
port(
Arith16 : in std_logic;
Z16 : in std_logic;
ALU_Op : in std_logic_vector(3 downto 0);
IR : in std_logic_vector(5 downto 0);
ISet : in std_logic_vector(1 downto 0);
BusA : in std_logic_vector(7 downto 0);
BusB : in std_logic_vector(7 downto 0);
F_In : in std_logic_vector(7 downto 0);
Q : out std_logic_vector(7 downto 0);
F_Out : out std_logic_vector(7 downto 0)
);
end component;
end;

342
rtl/cpu/t80na.vhd Normal file
View File

@@ -0,0 +1,342 @@
--
-- Z80 compatible microprocessor core, asynchronous top level
--
-- Version : 0247
--
-- Copyright 2001-2002 Daniel Wallner (jesus@opencores.org)
--
-- Modifications for the ZX Spectrum Next Project
-- Copyright 2020 Fabio Belavenuto, Victor Trucco, Charlie Ingley, Garry Lancaster, ACX
--
-- All rights reserved
--
-- Redistribution and use in source and synthezised forms, with or without
-- modification, are permitted provided that the following conditions are met:
--
-- Redistributions of source code must retain the above copyright notice,
-- this list of conditions and the following disclaimer.
--
-- Redistributions in synthesized form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in the
-- documentation and/or other materials provided with the distribution.
--
-- Neither the name of the author nor the names of other contributors may
-- be used to endorse or promote products derived from this software without
-- specific prior written permission.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-- POSSIBILITY OF SUCH DAMAGE.
--
-- Please report bugs to the author, but before you do so, please make sure that
-- this is not a derivative work and that you have the latest version of this file.
--
-- The latest version of this file can be found at:
-- <http://www.opencores.org/cvsweb.shtml/t80/>
--
-- Limitations :
--
-- File history :
--
-- 0208 : First complete release
--
-- 0211 : Fixed interrupt cycle
--
-- 0235 : Updated for T80 interface change
--
-- 0238 : Updated for T80 interface change
--
-- 0240 : Updated for T80 interface change
--
-- 0242 : Updated for T80 interface change
--
-- 0247 : Fixed bus req/ack cycle
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- Modifications for the ZX Spectrum Next were made by:
--
-- Fabio Belavenuto : partial fix of wait bug
-- Victor Trucco, Fabio Belavenuto, Garry Lancaster : additional instructions
-- Charlie Ingley : complete fix of wait logic
-- ACX : implement undocumented flags for SLI r,(IY+s)
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.T80N_Pack.all;
use work.Z80N_pack.all;
entity T80Na is
generic(
Mode : integer := 0 -- 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB
);
port(
RESET_n : in std_logic;
CLK_n : in std_logic;
WAIT_n : in std_logic;
INT_n : in std_logic;
NMI_n : in std_logic;
BUSRQ_n : in std_logic;
M1_n : out std_logic;
MREQ_n : out std_logic;
IORQ_n : out std_logic;
RD_n : out std_logic;
WR_n : out std_logic;
RFSH_n : out std_logic;
HALT_n : out std_logic;
BUSAK_n : out std_logic;
A : out std_logic_vector(15 downto 0);
-- D : inout std_logic_vector( 7 downto 0);
D_i : in std_logic_vector( 7 downto 0);
D_o : out std_logic_vector( 7 downto 0);
-- extended functions
Z80N_dout_o : out std_logic := '0';
Z80N_data_o : out std_logic_vector(15 downto 0);
Z80N_command_o : out Z80N_seq
);
end T80Na;
architecture rtl of T80Na is
signal CEN : std_logic;
signal Reset_s : std_logic;
signal IntCycle_n : std_logic;
signal IORQ : std_logic;
signal NoRead : std_logic;
signal Write : std_logic;
signal MREQ : std_logic;
signal MReq_Inhibit : std_logic;
signal Req_Inhibit : std_logic;
signal RD : std_logic;
signal MREQ_n_i : std_logic;
signal MREQ_rw : std_logic; -- 30/10/19 Charlie Ingley-- add MREQ control
signal IORQ_n_i : std_logic;
signal IORQ_t1 : std_logic; -- 30/10/19 Charlie Ingley-- add IORQ control
signal IORQ_t2 : std_logic; -- 30/10/19 Charlie Ingley-- add IORQ control
signal IORQ_rw : std_logic; -- 30/10/19 Charlie Ingley-- add IORQ control
signal IORQ_int : std_logic; -- 30/10/19 Charlie Ingley-- add IORQ interrupt control
signal RD_n_i : std_logic;
signal WR_n_i : std_logic;
signal WR_t2 : std_logic; -- 30/10/19 Charlie Ingley-- add WR control
signal RFSH_n_i : std_logic;
signal BUSAK_n_i : std_logic;
signal A_i : std_logic_vector(15 downto 0);
signal DO : std_logic_vector(7 downto 0);
signal DI_Reg : std_logic_vector (7 downto 0); -- Input synchroniser
signal MCycle : std_logic_vector(2 downto 0);
signal TState : std_logic_vector(2 downto 0);
begin
CEN <= '1';
BUSAK_n <= BUSAK_n_i; -- 30/10/19 Charlie Ingley - IORQ/RD/WR changes
MREQ_rw <= MREQ and (Req_Inhibit or MReq_Inhibit); -- added MREQ timing control
MREQ_n_i <= not MREQ_rw; -- changed MREQ generation
IORQ_rw <= IORQ and not (IORQ_t1 or IORQ_t2); -- added IORQ generation timing control
IORQ_n_i <= not (IORQ_int or IORQ_rw); -- changed IORQ generation
RD_n_i <= not (RD and (MREQ_rw or IORQ_rw)); -- changed RD/IORQ generation
WR_n_i <= not (Write and ((WR_t2 and MREQ_rw) or IORQ_rw)); -- added WR/IORQ timing control
-- MREQ_n <= MREQ_n_i when BUSAK_n_i = '1' else 'Z';
-- IORQ_n <= IORQ_n_i when BUSAK_n_i = '1' else 'Z';
-- RD_n <= RD_n_i when BUSAK_n_i = '1' else 'Z';
-- WR_n <= WR_n_i when BUSAK_n_i = '1' else 'Z';
-- RFSH_n <= RFSH_n_i when BUSAK_n_i = '1' else 'Z';
-- A <= A_i when BUSAK_n_i = '1' else (others => 'Z');
-- D <= DO when Write = '1' and BUSAK_n_i = '1' else (others => 'Z');
MREQ_n <= MREQ_n_i;
IORQ_n <= IORQ_n_i;
RD_n <= RD_n_i;
WR_n <= WR_n_i;
RFSH_n <= RFSH_n_i;
A <= A_i;
D_o <= DO;
process (RESET_n, CLK_n)
begin
if RESET_n = '0' then
Reset_s <= '0';
elsif CLK_n'event and CLK_n = '1' then
Reset_s <= '1';
end if;
end process;
z80n : T80N
generic map(
Mode => Mode,
IOWait => 1)
port map(
CEN => CEN,
M1_n => M1_n,
IORQ => IORQ,
NoRead => NoRead,
Write => Write,
RFSH_n => RFSH_n_i,
HALT_n => HALT_n,
WAIT_n => Wait_n,
INT_n => INT_n,
NMI_n => NMI_n,
RESET_n => Reset_s,
BUSRQ_n => BUSRQ_n,
BUSAK_n => BUSAK_n_i,
CLK_n => CLK_n,
A => A_i,
-- DInst => D,
DInst => D_i,
DI => DI_Reg,
DO => DO,
MC => MCycle,
TS => TState,
IntCycle_n => IntCycle_n,
Z80N_dout_o => Z80N_dout_o,
Z80N_data_o => Z80N_data_o,
Z80N_command_o => Z80N_command_o
);
process (CLK_n)
begin
if CLK_n'event and CLK_n = '0' then
if TState = "011" and BUSAK_n_i = '1' then
-- DI_Reg <= to_x01(D);
DI_Reg <= D_i;
end if;
end if;
end process;
-- 30/10/19 Charlie Ingley - Generate WR_t2 to correct MREQ/WR timing
process (Reset_s,CLK_n)
begin
if Reset_s = '0' then
WR_t2 <= '0';
elsif CLK_n'event and CLK_n = '0' then
if MCycle /= "001" then
if TState = "010" then -- WR starts on falling edge of T2 for MREQ
WR_t2 <= Write;
end if;
end if;
if TState = "011" then -- end WR
WR_t2 <= '0';
end if;
end if;
end process;
-- Generate Req_Inhibit
process (Reset_s,CLK_n)
begin
if Reset_s = '0' then
Req_Inhibit <= '1'; -- Charlie Ingley 30/10/19 - changed Req_Inhibit polarity
elsif CLK_n'event and CLK_n = '1' then
if MCycle = "001" and TState = "010" and WAIT_n = '1' then -- by Fabio Belavenuto - fix behavior of Wait_n
Req_Inhibit <= '0';
else
Req_Inhibit <= '1';
end if;
end if;
end process;
-- Generate MReq_Inhibit
process (Reset_s, CLK_n)
begin
if Reset_s = '0' then
MReq_Inhibit <= '1'; -- Charlie Ingley 30/10/19 - changed Req_Inhibit polarity
elsif CLK_n'event and CLK_n = '0' then
if MCycle = "001" and TState = "010" and WAIT_n = '1' then -- by Fabio Belavenuto - fix behavior of Wait_n
MReq_Inhibit <= '0';
else
MReq_Inhibit <= '1';
end if;
end if;
end process;
-- Generate RD for MREQ
process(Reset_s,CLK_n)
begin
if Reset_s = '0' then
RD <= '0';
MREQ <= '0';
elsif CLK_n'event and CLK_n = '0' then
if MCycle = "001" then
if TState = "001" then
RD <= IntCycle_n;
MREQ <= IntCycle_n;
end if;
if TState = "011" then
RD <= '0';
MREQ <= '1';
end if;
if TState = "100" then
MREQ <= '0';
end if;
else
if TState = "001" and NoRead = '0' then
RD <= not Write;
MREQ <= not IORQ;
end if;
if TState = "011" then
RD <= '0';
MREQ <= '0';
end if;
end if;
end if;
end process;
-- 30/10/19 Charlie Ingley - Generate IORQ_int for IORQ interrupt timing control
process(Reset_s,CLK_n)
begin
if Reset_s = '0' then
IORQ_int <= '0';
elsif CLK_n'event and CLK_n = '1' then
if MCycle = "001" then
if TState = "001" then
IORQ_int <= not IntCycle_n;
end if;
if TState = "010" then
IORQ_int <= '0';
end if;
end if;
end if;
end process;
-- 30/10/19 Charlie Ingley - Generate IORQ_t1 for IORQ timing control
process(Reset_s, CLK_n)
begin
if Reset_s = '0' then
IORQ_t1 <= '1';
elsif CLK_n'event and CLK_n = '0' then
if TState = "001" then
IORQ_t1 <= not IntCycle_n;
end if;
if TState = "011" then
IORQ_t1 <= '1';
end if;
end if;
end process;
-- 30/10/19 Charlie Ingley - Generate IORQ_t2 for IORQ timing control
process (RESET_n, CLK_n)
begin
if RESET_n = '0' then
IORQ_t2 <= '1';
elsif CLK_n'event and CLK_n = '1' then
IORQ_t2 <= IORQ_t1;
end if;
end process;
end;

125
rtl/device/copper.vhd Normal file
View File

@@ -0,0 +1,125 @@
-- ZX Spectrum Next Copper Coprocessor
-- Copyright 2020 Victor Trucco
-- Theoretical Model - Mike Dailly
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use IEEE.std_logic_unsigned.ALL;
entity copper is
port (
clock_i : in std_logic;
reset_i : in std_logic;
copper_en_i : in std_logic_vector(1 downto 0);
hcount_i : in unsigned(8 downto 0);
vcount_i : in unsigned(8 downto 0);
copper_list_addr_o : out std_logic_vector(9 downto 0);
copper_list_data_i : in std_logic_vector(15 downto 0);
copper_dout_o : out std_logic;
copper_data_o : out std_logic_vector(14 downto 0)
);
end entity;
architecture rtl of copper is
signal copper_list_addr_s : std_logic_vector(9 downto 0);
signal copper_dout_s : std_logic := '0';
signal last_state_s : std_logic_vector(1 downto 0) := "00";
begin
process (clock_i)
variable line_v : unsigned(8 downto 0);
begin
if rising_edge(clock_i) then
if reset_i = '1' then
copper_list_addr_s <= (others => '0');
copper_dout_s <= '0';
copper_data_o <= (others => '0');
else
-- check if we are entering on "01" or "11" mode and reset the address to 0000
if last_state_s /= copper_en_i then
last_state_s <= copper_en_i;
if copper_en_i = "01" or copper_en_i = "11" then
copper_list_addr_s <= (others=>'0');
end if;
copper_dout_s <= '0';
elsif copper_en_i = "11" and vcount_i = 0 and hcount_i = 0 then --restart at frame start
copper_list_addr_s <= (others=>'0');
copper_dout_s <= '0';
elsif copper_en_i /= "00" then
if copper_dout_s = '1' then --if we are on MOVE, clear the output for the next cycle
copper_dout_s <= '0';
-- command WAIT
elsif copper_list_data_i(15) = '1' then
if vcount_i = unsigned(copper_list_data_i(8 downto 0)) and hcount_i >= unsigned(copper_list_data_i(14 downto 9)&"000") + 12 then
copper_list_addr_s <= copper_list_addr_s + 1; -- if it's time, load the next copper command
end if;
copper_dout_s <= '0';
else -- command MOVE
copper_data_o <= copper_list_data_i(14 downto 0);
if copper_list_data_i(14 downto 8) /= "0000000" then -- dont generate the write pulse if its a NOP (MOVE 0,0)
copper_dout_s <= '1';
end if;
copper_list_addr_s <= copper_list_addr_s + 1;
end if;
else
copper_dout_s <= '0';
end if;
end if;
end if;
end process;
copper_list_addr_o <= copper_list_addr_s;
copper_dout_o <= copper_dout_s;
end architecture;

169
rtl/device/ctc.vhd Normal file
View File

@@ -0,0 +1,169 @@
-- Z80 CTC
-- Copyright 2020 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
-- Reference:
-- http://www.zilog.com/docs/z80/ps0181.pdf
--
-- The im2 vector and im2 interrupt are not implemented here. Instead
-- relevant signals are exported so that im2 mode can be optionally
-- implemented by the instantiating module.
--
-- Clarifications per CTC channel:
--
-- 1. Hard reset requires a control word to be written with D2 = 1
-- (time constant follows) otherwise the channel effectively
-- ignores the control word and will remain in the hard reset state.
--
-- 2. Soft reset is generated when the control word's D1 = 1. if
-- D2 = 0, the channel will enter the hard reset state. If D2 = 1
-- the channel expects a time constant to be written next and after
-- that the counter/timer will run as expected.
--
-- 3. Changing the trigger edge selection in bit 4 counts as a clock edge.
-- A timer waiting for a clock edge to start will start and in counter
-- mode, the count will be decremented.
--
-- 4. ZC/TO is asserted for one clock cycle and not for the entire
-- duration that the count is at zero.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity ctc is
generic (
constant NUM_CTC : positive := 4;
constant NUM_CTC_LOG2 : positive := 2
);
port (
i_CLK : in std_logic;
i_reset : in std_logic;
i_port_ctc_wr : in std_logic; -- one of the ctc channel ports is being written
i_port_ctc_sel : in std_logic_vector(NUM_CTC_LOG2-1 downto 0); -- which one, numbered
i_int_en_wr : in std_logic; -- separately write interrupt enable bits, must not overlap port_ctc_wr
i_int_en : in std_logic_vector(NUM_CTC-1 downto 0); -- interrupt enable bits
i_cpu_d : in std_logic_vector(7 downto 0);
o_cpu_d : out std_logic_vector(7 downto 0); -- data read from ctc port
i_clk_trg : in std_logic_vector(NUM_CTC-1 downto 0); -- clock/trigger signals for each ctc channel, must be synchronized
o_im2_vector_wr : out std_logic; -- im2 vector is being written (not handled in this module)
o_zc_to : out std_logic_vector(NUM_CTC-1 downto 0); -- zc/to for each ctc channel, asserted for one i_CLK cycle
o_int_en : out std_logic_vector(NUM_CTC-1 downto 0) -- interrupt enable for each channel
);
end entity;
architecture rtl of ctc is
type dout_t is array (NUM_CTC-1 downto 0) of std_logic_vector(7 downto 0);
signal dout : dout_t;
signal sel : std_logic_vector(NUM_CTC-1 downto 0);
signal iowr : std_logic_vector(NUM_CTC-1 downto 0);
signal iowr_tc : std_logic_vector(NUM_CTC-1 downto 0);
begin
-- CTC Channels
gen_ctc:
for I in 0 to NUM_CTC-1 generate
ctc: entity work.ctc_chan
port map (
i_CLK => i_CLK,
i_reset => i_reset,
i_iowr => iowr(I),
o_iowr_tc => iowr_tc(I),
i_int_en_wr => i_int_en_wr,
i_int_en => i_int_en(I),
i_cpu_d => i_cpu_d,
o_cpu_d => dout(I),
i_clk_trg => i_clk_trg(I),
o_zc_to => o_zc_to(I),
o_int_en => o_int_en(I)
);
end generate;
-- Select CTC
process (i_port_ctc_sel)
begin
for I in 0 to NUM_CTC-1 loop
if I = unsigned(i_port_ctc_sel) then
sel(I) <= '1';
else
sel(I) <= '0';
end if;
end loop;
end process;
-- Route Signals
process (i_port_ctc_wr, sel)
begin
for I in 0 to NUM_CTC-1 loop
iowr(I) <= i_port_ctc_wr and sel(I);
end loop;
end process;
-- Output
process (iowr_tc, sel, i_port_ctc_wr, i_cpu_d)
variable tmp_iowr_tc : std_logic;
begin
tmp_iowr_tc := iowr_tc(0) and sel(0);
for I in 1 to NUM_CTC-1 loop
tmp_iowr_tc := tmp_iowr_tc or (iowr_tc(I) and sel(I));
end loop;
o_im2_vector_wr <= i_port_ctc_wr and (not i_cpu_d(0)) and (not tmp_iowr_tc);
end process;
process (dout, sel)
variable tmp_dout : std_logic_vector(7 downto 0);
begin
tmp_dout := (dout(0)(7) and sel(0)) & (dout(0)(6) and sel(0)) & (dout(0)(5) and sel(0)) & (dout(0)(4) and sel(0)) &
(dout(0)(3) and sel(0)) & (dout(0)(2) and sel(0)) & (dout(0)(1) and sel(0)) & (dout(0)(0) and sel(0));
for I in 1 to NUM_CTC-1 loop
tmp_dout := tmp_dout or ((dout(I)(7) and sel(I)) & (dout(I)(6) and sel(I)) & (dout(I)(5) and sel(I)) & (dout(I)(4) and sel(I)) &
(dout(I)(3) and sel(I)) & (dout(I)(2) and sel(I)) & (dout(I)(1) and sel(I)) & (dout(I)(0) and sel(I)) );
end loop;
o_cpu_d <= tmp_dout;
end process;
end architecture;

267
rtl/device/ctc_chan.vhd Normal file
View File

@@ -0,0 +1,267 @@
-- Z80 CTC Channel
-- Copyright 2020 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
-- One channel of a Z80 CTC (counter/timer circuit)
-- http://www.zilog.com/docs/z80/ps0181.pdf
--
-- Clarifications:
--
-- 1. Hard reset requires a control word to be written with D2 = 1
-- (time constant follows) otherwise the channel effectively
-- ignores the control word and will remain in the hard reset state.
--
-- 2. Soft reset is generated when the control word's D1 = 1. if
-- D2 = 0, the channel will enter the hard reset state. If D2 = 1
-- the channel expects a time constant to be written next and after
-- that the counter/timer will run as expected.
--
-- 3. Changing the trigger edge selection in bit 4 counts as a clock edge.
-- A timer waiting for a clock edge to start will start and in counter
-- mode, the count will be decremented.
--
-- 4. ZC/TO is asserted for one clock cycle and not for the entire
-- duration that the count is at zero.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity ctc_chan is
port (
i_CLK : in std_logic;
i_reset : in std_logic; -- hard reset
i_iowr : in std_logic; -- write to this channel
o_iowr_tc : out std_logic; -- channel expects time constant next (ignore vector write)
i_int_en_wr : in std_logic; -- separately write interrupt enable, must not overlap iowr
i_int_en : in std_logic;
i_cpu_d : in std_logic_vector(7 downto 0);
o_cpu_d : out std_logic_vector(7 downto 0); -- current count
i_clk_trg : in std_logic; -- external clock / trigger, must be synchronized with rising edge of i_CLK
o_zc_to : out std_logic; -- asserted for one i_CLK cycle
o_int_en : out std_logic -- set if interrupt is enabled
);
end entity;
architecture rtl of ctc_chan is
signal reset_hard : std_logic;
signal reset_soft : std_logic;
signal clk_trg_d : std_logic;
signal clk_trg_edge : std_logic;
signal p_count : std_logic_vector(7 downto 0);
signal p_count_lo : std_logic;
signal p_count_hi : std_logic;
signal prescaler_clk : std_logic;
signal t_count_en : std_logic;
signal t_count_zero : std_logic;
signal t_count : std_logic_vector(7 downto 0);
signal t_count_zero_d : std_logic;
signal zc_to : std_logic;
type state_t is (S_CONTROL_WORD, S_TIME_CONSTANT, S_WAIT, S_RUNNING);
signal state : state_t;
signal state_next : state_t;
signal iowr_d : std_logic;
signal iowr : std_logic;
signal iowr_tc_exp : std_logic;
signal iowr_tc : std_logic;
signal iowr_cr : std_logic;
signal control_reg : std_logic_vector(5 downto 0);
signal time_constant_reg : std_logic_vector(7 downto 0);
signal reset_soft_trigger : std_logic;
signal clk_edge_change : std_logic;
begin
-- RESET
reset_hard <= i_reset;
reset_soft <= '1' when state /= S_RUNNING else '0';
-- CLOCK / TRIGGER
process (i_CLK)
begin
if rising_edge(i_CLK) then
clk_trg_d <= i_clk_trg;
end if;
end process;
clk_trg_edge <= ((clk_trg_d and not i_clk_trg) or clk_edge_change) when control_reg(4-2) = '0' else ((i_clk_trg and not clk_trg_d) or clk_edge_change); -- one cycle
-- PRESCALER
process (i_CLK)
begin
if rising_edge(i_CLK) then
if reset_soft = '1' then
p_count <= (others => '0');
else
p_count <= p_count + 1;
end if;
end if;
end process;
p_count_lo <= '1' when p_count(3 downto 0) = "1111" else '0';
p_count_hi <= '1' when p_count(7 downto 4) = "1111" else '0';
prescaler_clk <= (p_count_lo) when control_reg(5-2) = '0' else (p_count_lo and p_count_hi); -- one cycle
-- COUNTER
t_count_en <= prescaler_clk when control_reg(6-2) = '0' else clk_trg_edge;
t_count_zero <= '1' when t_count = X"00" else '0';
process (i_CLK)
begin
if rising_edge(i_CLK) then
if reset_soft = '1' then
t_count <= time_constant_reg;
elsif zc_to = '1' then
t_count <= time_constant_reg;
elsif t_count_en = '1' then
t_count <= t_count - 1;
end if;
end if;
end process;
o_cpu_d <= t_count;
process (i_CLK)
begin
if rising_edge(i_CLK) then
t_count_zero_d <= t_count_zero;
end if;
end process;
zc_to <= '1' when t_count_zero = '1' and t_count_zero_d = '0' and state = S_RUNNING else '0'; -- one cycle
o_zc_to <= zc_to;
-- STATE MACHINE
process (i_CLK)
begin
if rising_edge(i_CLK) then
if reset_hard = '1' then
state <= S_CONTROL_WORD;
else
state <= state_next;
end if;
end if;
end process;
process (reset_soft_trigger, i_cpu_d, state, iowr_cr, iowr_tc, control_reg, clk_trg_edge)
begin
if reset_soft_trigger = '1' then
if i_cpu_d(2) = '0' then
state_next <= S_CONTROL_WORD;
else
state_next <= S_TIME_CONSTANT;
end if;
else
case state is
when S_CONTROL_WORD =>
if iowr_cr = '1' and i_cpu_d(2) = '1' then
state_next <= S_TIME_CONSTANT;
else
state_next <= S_CONTROL_WORD;
end if;
when S_TIME_CONSTANT =>
if iowr_tc = '1' then
state_next <= S_WAIT;
else
state_next <= S_TIME_CONSTANT;
end if;
when S_WAIT =>
if control_reg(6-2) = '0' and control_reg(3-2) = '1' and clk_trg_edge = '0' then
state_next <= S_WAIT;
else
state_next <= S_RUNNING;
end if;
when S_RUNNING =>
state_next <= S_RUNNING;
when others =>
state_next <= S_CONTROL_WORD;
end case;
end if;
end process;
-- REGISTERS
process (i_CLK)
begin
if rising_edge(i_CLK) then
iowr_d <= i_iowr;
end if;
end process;
iowr <= i_iowr and not iowr_d;
iowr_tc_exp <= '1' when (control_reg(2-2) = '1' and state /= S_CONTROL_WORD) else '0';
o_iowr_tc <= iowr_tc_exp;
iowr_tc <= '1' when iowr = '1' and iowr_tc_exp = '1' else '0';
iowr_cr <= '1' when iowr = '1' and iowr_tc_exp = '0' and i_cpu_d(0) = '1' else '0';
process (i_CLK)
begin
if rising_edge(i_CLK) then
if reset_hard = '1' then
control_reg <= (others => '0');
elsif iowr_cr = '1' then
control_reg <= i_cpu_d(7 downto 2);
elsif iowr_tc = '1' then
control_reg(2-2) <= '0';
elsif i_int_en_wr = '1' then
control_reg(7-2) <= i_int_en;
end if;
end if;
end process;
o_int_en <= control_reg(7-2);
process (i_CLK)
begin
if rising_edge(i_CLK) then
if reset_hard = '1' then
time_constant_reg <= (others => '0');
elsif iowr_tc = '1' then
time_constant_reg <= i_cpu_d;
end if;
end if;
end process;
reset_soft_trigger <= '1' when iowr_cr = '1' and i_cpu_d(1) = '1' else '0';
clk_edge_change <= '1' when iowr_cr = '1' and (i_cpu_d(4) /= control_reg(4-2)) else '0';
end architecture;

150
rtl/device/divmmc.vhd Normal file
View File

@@ -0,0 +1,150 @@
-- ZXN Divmmc
-- Copyright 2020 Alvin Albrecht and Fabio Belavenuto
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity divmmc is
port (
i_CLK : in std_logic;
i_reset : in std_logic;
i_cpu_a_15_13 : in std_logic_vector(2 downto 0);
i_cpu_mreq_n : in std_logic;
i_cpu_m1_n : in std_logic;
i_en : in std_logic;
i_automap_reset : in std_logic;
i_automap_active : in std_logic;
i_automap_rom3_active: in std_logic;
i_retn_seen : in std_logic;
i_divmmc_button : in std_logic;
i_divmmc_reg : in std_logic_vector(7 downto 0);
i_automap_instant_on : in std_logic;
i_automap_delayed_on : in std_logic;
i_automap_delayed_off : in std_logic;
i_automap_rom3_instant_on : in std_logic;
i_automap_rom3_delayed_on : in std_logic;
i_automap_nmi_instant_on : in std_logic;
i_automap_nmi_delayed_on : in std_logic;
o_divmmc_rom_en : out std_logic;
o_divmmc_ram_en : out std_logic;
o_divmmc_rdonly : out std_logic;
o_divmmc_ram_bank : out std_logic_vector(3 downto 0);
o_disable_nmi : out std_logic;
o_automap_held : out std_logic
);
end entity;
architecture rtl of divmmc is
signal conmem : std_logic;
signal mapram : std_logic;
signal page0 : std_logic;
signal page1 : std_logic;
signal rom_en : std_logic;
signal ram_en : std_logic;
signal ram_bank : std_logic_vector(3 downto 0);
signal button_nmi : std_logic;
signal automap_nmi_instant_on : std_logic;
signal automap_nmi_delayed_on : std_logic;
signal automap_hold : std_logic;
signal automap_held : std_logic;
signal automap : std_logic;
begin
-- DIVMMC Paging
conmem <= i_divmmc_reg(7);
mapram <= i_divmmc_reg(6);
page0 <= '1' when i_cpu_a_15_13 = "000" else '0';
page1 <= '1' when i_cpu_a_15_13 = "001" else '0';
rom_en <= '1' when (page0 = '1' and (conmem = '1' or (mapram = '0' and automap = '1'))) else '0';
ram_en <= '1' when (page0 = '1' and conmem = '0' and mapram = '1' and automap = '1') or (page1 = '1' and (conmem = '1' or automap = '1')) else '0';
ram_bank <= X"3" when page0 = '1' else i_divmmc_reg(3 downto 0);
o_divmmc_rom_en <= rom_en and i_en;
o_divmmc_ram_en <= ram_en and i_en;
o_divmmc_rdonly <= page0;
o_divmmc_ram_bank <= ram_bank;
-- NMI
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or i_automap_reset = '1' or i_retn_seen = '1' then
button_nmi <= '0';
elsif i_divmmc_button = '1' then
button_nmi <= '1';
elsif automap_held = '1' then
button_nmi <= '0';
end if;
end if;
end process;
-- Automap
automap_nmi_instant_on <= i_automap_nmi_instant_on and button_nmi;
automap_nmi_delayed_on <= i_automap_nmi_delayed_on and button_nmi;
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or i_automap_reset = '1' or i_retn_seen = '1' then
automap_hold <= '0';
elsif i_cpu_mreq_n = '0' and i_cpu_m1_n = '0' then
automap_hold <= (i_automap_active and (i_automap_instant_on or i_automap_delayed_on or automap_nmi_instant_on or automap_nmi_delayed_on)) or
(i_automap_rom3_active and (i_automap_rom3_instant_on or i_automap_rom3_delayed_on)) or
(automap_held and not (i_automap_active and i_automap_delayed_off));
end if;
end if;
end process;
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or i_automap_reset = '1' or i_retn_seen = '1' then
automap_held <= '0';
elsif i_cpu_mreq_n = '1' then
automap_held <= automap_hold;
end if;
end if;
end process;
-- automap <= (not i_automap_reset) and (automap_held or (i_automap_active and (i_automap_instant_on or automap_nmi_instant_on) and not i_cpu_m1_n) or (i_automap_rom3_active and i_automap_rom3_instant_on and not i_cpu_m1_n));
automap <= (not i_automap_reset) and (automap_held or (i_automap_active and (i_automap_instant_on or automap_nmi_instant_on)) or (i_automap_rom3_active and i_automap_rom3_instant_on));
o_disable_nmi <= automap or button_nmi;
o_automap_held <= automap_held;
end architecture;

1148
rtl/device/dma.vhd Normal file

File diff suppressed because it is too large Load Diff

206
rtl/device/im2_control.vhd Normal file
View File

@@ -0,0 +1,206 @@
-- Z80 IM2 CONTROL BLOCK
-- Copyright 2020 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
--
-- This control block is responsible for recognizing the reti instruction
-- (opcode bytes ED 4D only, which is compatible with Zilog peripherals) and
-- for indicating when a reti instruction may be decoded so that IEO is
-- only asserted by already acknowledged interrupters. It also decodes the
-- retn instruction ED 45.
--
-- IM2 peripherals should use the output signals as follows:
--
-- o_reti_decode : When asserted, peripherals must only make IEO low
-- if the peripheral's interrupt has already been acknowledged or if
-- IEI is low. Synchronized to the rising edge of CLK.
--
-- o_reti_seen : When asserted, the peripheral with its IEI signal high
-- and whose interrupt has already been acknowledged should reset its
-- interrupt logic since its interrupt routine is terminating. Asserted
-- for exactly one cycle and synchronized to the rising edge of CLK.
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity im2_control is
port (
i_CLK_CPU : in std_logic;
i_reset : in std_logic;
i_m1_n : in std_logic;
i_mreq_n : in std_logic;
i_iorq_n : in std_logic;
i_rd_n : in std_logic;
i_wr_n : in std_logic;
i_cpu_d : in std_logic_vector(7 downto 0);
o_reti_decode : out std_logic; -- reti is being decoded, only acknowledged interrupters should deassert IEO
o_reti_seen : out std_logic; -- reti instruction has been detected active in T3 for rising edge of T4
o_retn_seen : out std_logic; -- retn instruction has been detected active in T3 for rising edge of T4
o_dma_delay : out std_logic -- delay dma busak through reti pop
);
end entity;
architecture rtl of im2_control is
signal ifetch : std_logic;
signal ifetch_cancel : std_logic;
signal ifetch_d : std_logic;
signal ifetch_fe_t3 : std_logic;
signal cpu_opcode : std_logic_vector(7 downto 0);
signal opcode_ed : std_logic;
signal opcode_4d : std_logic;
signal opcode_cb : std_logic;
signal opcode_45 : std_logic;
type state_t is (S_0, S_ED_T4, S_ED4D_T4, S_ED45_T4, S_CB_T4, S_SRL_T1, S_SRL_T2);
signal state : state_t;
signal state_next : state_t;
begin
-- detect instruction fetch cycles
ifetch <= '1' when i_m1_n = '0' and i_mreq_n = '0' else '0';
-- ifetch_cancel <= '1' when (i_m1_n = '1' and i_mreq_n = '0' and i_rfsh_n = '1') or i_iorq_n = '0' else '0'; -- includes dma operations
ifetch_cancel <= '1' when ((i_m1_n = '1' or i_mreq_n = '1') and (i_rd_n = '0' or i_wr_n = '0')) or i_iorq_n = '0' else '0';
process (i_CLK_CPU)
begin
if rising_edge(i_CLK_CPU) then
if i_reset = '1' then
ifetch_d <= '0';
else
ifetch_d <= ifetch;
end if;
end if;
end process;
ifetch_fe_t3 <= ifetch_d and not ifetch;
-- hold opcode read by cpu
process (i_CLK_CPU)
begin
if rising_edge(i_CLK_CPU) then
if i_reset = '1' then
cpu_opcode <= (others => '0');
elsif ifetch = '1' then
cpu_opcode <= i_cpu_d;
end if;
end if;
end process;
-- recognize important opcodes ED 4D CB 45
process (cpu_opcode)
begin
opcode_ed <= '0';
opcode_4d <= '0';
opcode_cb <= '0';
opcode_45 <= '0';
case cpu_opcode is
when X"ED" => opcode_ed <= '1';
when X"4D" => opcode_4d <= '1';
when X"CB" => opcode_cb <= '1';
when X"45" => opcode_45 <= '1';
when others => null;
end case;
end process;
-- state machine
process (i_CLK_CPU)
begin
if rising_edge(i_CLK_CPU) then
if i_reset = '1' then
state <= S_0;
else
state <= state_next;
end if;
end if;
end process;
process (state, ifetch_fe_t3, opcode_ed, opcode_cb, opcode_4d, opcode_45, ifetch_cancel) -- , i_busak_n)
begin
case state is
when S_0 =>
if ifetch_fe_t3 = '1' and opcode_ed = '1' then
state_next <= S_ED_T4;
elsif ifetch_fe_t3 = '1' and opcode_cb = '1' then
state_next <= S_CB_T4;
else
state_next <= S_0;
end if;
when S_ED_T4 =>
if ifetch_cancel = '1' or (ifetch_fe_t3 = '1' and opcode_4d = '0' and opcode_45 = '0') then
state_next <= S_0;
elsif ifetch_fe_t3 = '1' and opcode_4d = '1' then
state_next <= S_ED4D_T4;
elsif ifetch_fe_t3 = '1' and opcode_45 = '1' then
state_next <= S_ED45_T4;
else
state_next <= S_ED_T4;
end if;
when S_ED4D_T4 =>
-- state_next <= S_0;
state_next <= S_SRL_T1;
-- On the zx next, the dma can be interrupted by devices and this
-- prevents an accumulation of return addresses on the stack.
when S_SRL_T1 =>
state_next <= S_SRL_T2;
when S_SRL_T2 =>
state_next <= S_0;
--
when S_ED45_T4 =>
state_next <= S_0;
when S_CB_T4 =>
if ifetch_cancel = '1' or ifetch_fe_t3 = '1' then
state_next <= S_0;
else
state_next <= S_CB_T4;
end if;
when others =>
state_next <= S_0;
end case;
end process;
-- output signals
o_reti_decode <= '1' when state = S_ED_T4 else '0';
o_reti_seen <= '1' when state_next = S_ED4D_T4 else '0'; -- zilog peripherals require im2 reset on rising edge of T4
o_retn_seen <= '1' when state_next = S_ED45_T4 else '0';
o_dma_delay <= '1' when state = S_ED_T4 or state = S_ED4D_T4 or state = S_SRL_T1 or state = S_SRL_T2 else '0';
end architecture;

164
rtl/device/im2_device.vhd Normal file
View File

@@ -0,0 +1,164 @@
-- Z80 IM2 DEVICE
-- Copyright 2020 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
--
-- This module handles the im2 logic for an interrupting peripheral.
--
-- The input is (i_int) which is active high and indicates that the
-- peripheral wants to interrupt. The signal will be seen on the
-- rising edge of the cpu clock and could be held high until the module
-- indicates that the isr has been serviced (o_isr_serviced).
--
-- The daisy chain logic is implemented through (i_iei) and (o_ieo).
-- The highest priority device should have its iei signal set to '1'
-- and lower priority devices should have their iei connected to the
-- next higher priority device's ieo.
--
-- The variable width interrupt vector is output normally as all zeroes
-- unless the device must output its vector during an interrupt ack
-- cycle. This allows multiple modules to have their vector outputs
-- logically ORed together to easily form the correct vector
-- presented to the z80. This resulting vector should be output only
-- while /m1 and /iorq are both low.
--
-- The signal (o_isr_serviced) should be used to reset any other
-- interrupt logic outside this module. The signal is held high for
-- one clock cycle.
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity im2_device is
generic (
constant VEC_BITS : positive := 8
);
port (
i_CLK_CPU : in std_logic;
i_reset_n : in std_logic;
i_m1_n : in std_logic;
i_iorq_n : in std_logic;
i_int_req : in std_logic; -- peripheral wants to generate an interrupt
o_int_n : out std_logic; -- interrupt signal for z80
i_reti_decode : in std_logic;
i_reti_seen : in std_logic;
o_isr_serviced : out std_logic;
i_iei : in std_logic; -- im2 daisy chain logic
o_ieo : out std_logic; -- im2 daisy chain logic
i_vec : in std_logic_vector(VEC_BITS-1 downto 0); -- peripheral im2 vector
o_vec : out std_logic_vector(VEC_BITS-1 downto 0) -- generated im2 vector, must be qualified by /m1 * /iorq
);
end entity;
architecture rtl of im2_device is
type state_t is (S_0, S_PEND, S_REQ, S_ACK, S_ISR);
signal state : state_t;
signal state_next : state_t;
begin
-- state machine
process (i_CLK_CPU)
begin
if rising_edge(i_CLK_CPU) then
if i_reset_n = '0' then
state <= S_0;
else
state <= state_next;
end if;
end if;
end process;
process (state, i_m1_n, i_iorq_n, i_int_req, i_iei, i_reti_seen)
begin
case state is
when S_0 =>
if i_m1_n = '1' and i_int_req = '1' then
state_next <= S_REQ;
elsif i_int_req = '1' then
state_next <= S_PEND;
else
state_next <= S_0;
end if;
when S_PEND =>
if i_m1_n = '1' then
state_next <= S_REQ;
else
state_next <= S_PEND;
end if;
when S_REQ =>
if i_m1_n = '0' and i_iorq_n = '0' and i_iei = '1' then
state_next <= S_ACK;
else
state_next <= S_REQ;
end if;
when S_ACK =>
if i_m1_n = '1' then
state_next <= S_ISR;
else
state_next <= S_ACK;
end if;
when S_ISR =>
if i_reti_seen = '1' and i_iei = '1' then
state_next <= S_0;
else
state_next <= S_ISR;
end if;
when others =>
state_next <= S_0;
end case;
end process;
-- output daisy chain
process (state, i_iei, i_reti_decode)
begin
case state is
when S_0 | S_PEND =>
o_ieo <= i_iei;
when S_REQ =>
o_ieo <= i_iei and i_reti_decode;
when others =>
o_ieo <= '0';
end case;
end process;
-- output z80 interrupt request
o_int_n <= '0' when state = S_REQ and i_iei = '1' else '1';
-- output interrupt vector
o_vec <= i_vec when state = S_ACK or state_next = S_ACK else (others => '0'); -- qualify with /m1 * /iorq
-- indicate isr was serviced
o_isr_serviced <= '1' when state = S_ISR and state_next = S_0 else '0';
end architecture;

View File

@@ -0,0 +1,153 @@
-- Z80 IM2 DEVICE
-- Copyright 2020 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
--
-- This module completely handles interrupt logic for zxn peripherals.
-- It also implements "pulsed" interrupt logic so is somewhat specific
-- to the zx spectrum architecture.
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity im2_peripheral is
generic (
constant VEC_BITS : positive := 4
);
port (
i_CLK_28 : in std_logic;
i_CLK_CPU : in std_logic;
i_reset : in std_logic;
i_m1_n : in std_logic;
i_iorq_n : in std_logic;
i_mode_pulse_0_im2_1 : in std_logic; -- select standard pulsed zx mode or im2 vector mode
i_iei : in std_logic; -- im2 daisy chain
o_ieo : out std_logic; -- im2 daisy chain
i_reti_decode : in std_logic; -- reti opcode decode in progress
i_reti_seen : in std_logic; -- reti opcode found
i_int_en : in std_logic; -- enable interrupts from this device
i_int_req : in std_logic; -- interrupt request from this device (level active, must not persist through im2_isr_serviced signal)
i_int_status_clear : in std_logic; -- clear interrupt status bit if 1 (i_CLK_28)
o_int_status : out std_logic; -- current state of interrupt status bit (i_CLK_28)
o_int_n : out std_logic; -- active low interrupt signal to z80 if in im2 mode
o_pulse_en : out std_logic; -- active high signal for pulse interrupt, same duration as i_int_req (active regardless of pulse/im2 mode)
i_vector : in std_logic_vector(VEC_BITS-1 downto 0);
o_vector : out std_logic_vector(VEC_BITS-1 downto 0);
i_dma_int_en : in std_logic;
o_dma_int : out std_logic -- set if dma operation should be interrupted, must qualify with im2 mode
);
end entity;
architecture rtl of im2_peripheral is
signal im2_reset_n : std_logic;
signal isr_serviced : std_logic;
signal isr_serviced_d : std_logic;
signal im2_isr_serviced : std_logic;
signal int_status : std_logic;
signal next_int_status : std_logic;
signal im2_int_req : std_logic;
begin
im2_reset_n <= i_mode_pulse_0_im2_1 and i_int_en and not i_reset;
-- im2 device logic
im2_logic: entity work.im2_device
generic map (
VEC_BITS => VEC_BITS
)
port map (
i_CLK_CPU => i_CLK_CPU,
i_reset_n => im2_reset_n,
i_m1_n => i_m1_n,
i_iorq_n => i_iorq_n,
i_int_req => im2_int_req,
o_int_n => o_int_n,
i_reti_decode => i_reti_decode,
i_reti_seen => i_reti_seen,
o_isr_serviced => isr_serviced,
i_iei => i_iei,
o_ieo => o_ieo,
i_vec => i_vector,
o_vec => o_vector
);
process (i_CLK_28)
begin
if rising_edge(i_CLK_28) then
if i_reset = '1' then
isr_serviced_d <= '0';
else
isr_serviced_d <= isr_serviced;
end if;
end if;
end process;
im2_isr_serviced <= isr_serviced and not isr_serviced_d;
-- interrupt status register
-- record of whether interrupt occurred, only cleared by write or im2 reset
next_int_status <= i_int_req or (int_status and (im2_reset_n or not i_int_status_clear) and (not im2_isr_serviced));
process (i_CLK_28)
begin
if rising_edge(i_CLK_28) then
if i_reset = '1' then
int_status <= '0';
else
int_status <= next_int_status;
end if;
end if;
end process;
o_int_status <= int_status;
-- im2 interrupt logic
im2_int_req <= int_status; -- im2 device is held in reset if interrupt is not enabled
o_dma_int <= int_status and i_int_en and i_dma_int_en; -- should be qualified by im2 mode
-- pulse interrupt logic
o_pulse_en <= i_int_req and i_int_en;
end architecture;

197
rtl/device/multiface.vhd Normal file
View File

@@ -0,0 +1,197 @@
-- ZXN Multiface
-- Copyright 2020 Victor Trucco, Fabio Belavenuto and Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
-- Multiface 1 schematics:
-- http://www.worldofspectrum.org/pub/sinclair/technical-docs/Multiface1_Schematics.png
-- https://worldofspectrum.net/pub/sinclair/technical-docs/Multiface1_Schematics.gif
--
-- Port write 1F,9F: NMI_ACTIVE off
-- Port read 1F: MF_ENABLE off
-- Port read 9F: MF_ENABLE on
-- NMI_ACTIVE: 0=on holds /nmi low and prevents further button activations
-- MF_ENABLE: 0=on asserts /romcs and pages in multiface memory
-- 0x66 instruction fetch: immediate MF_ENABLE on if NMI_ACTIVE on
-- NMI_ACTIVE off and button press: NMI_ACTIVE on
-- Multiface 128 schematics:
-- http://projectspeccy.com/wp-content/uploads/2017/09/Spectrum_Multiface_128_v1.00-1.jpg
-- Multiface 3:
--
-- Port write BF,3F: NMI_ACTIVE off
-- Port write BF: INVISIBLE on
-- Port read BF: MF_ENABLE off
-- Port read 3F: if INVISIBLE off, MF_ENABLE on else MF_ENABLE off
-- Port read 1F3F: if INVISIBLE off, return port 1ffd
-- Port read 7F3F: if INVISIBLE off, return port 7ffd
-- NMI_ACTIVE: 0=on holds /nmi low and prevents further button activations
-- MF_ENABLE: 0=on asserts /romcs and pages in multiface memory
-- 0x66 instruction fetch: immediate MF_ENABLE on if NMI_ACTIVE on
-- NMI_ACTIVE off and button press: INVISIBLE off, NMI_ACTIVE on
library ieee;
use ieee.std_logic_1164.all;
entity multiface is
port (
reset_i : in std_logic;
clock_i : in std_logic;
cpu_a_0066_i : in std_logic;
cpu_mreq_n_i : in std_logic;
cpu_m1_n_i : in std_logic;
cpu_retn_seen_i : in std_logic;
enable_i : in std_logic;
button_i : in std_logic;
mf_mode_i : in std_logic_vector(1 downto 0); -- 00 = mf +3, 11 = mf 48, else mf 128
port_mf_enable_rd_i : in std_logic;
port_mf_enable_wr_i : in std_logic;
port_mf_disable_rd_i : in std_logic;
port_mf_disable_wr_i : in std_logic;
nmi_disable_o : out std_logic;
mf_enabled_o : out std_logic;
mf_port_en_o : out std_logic
);
end entity;
architecture rtl of multiface is
signal reset : std_logic;
signal mode_48 : std_logic;
signal mode_128 : std_logic;
signal mode_p3 : std_logic;
signal port_io_dly : std_logic;
signal button_pulse : std_logic;
signal nmi_active : std_logic;
signal invisible : std_logic;
signal invisible_eff : std_logic;
signal fetch_66 : std_logic;
signal mf_enable : std_logic;
signal mf_enable_eff : std_logic;
begin
reset <= reset_i or not enable_i;
process (mf_mode_i)
begin
mode_48 <= '0';
mode_128 <= '0';
mode_p3 <= '0';
case mf_mode_i is
when "00" => mode_p3 <= '1';
when "11" => mode_48 <= '1';
when others => mode_128 <= '1';
end case;
end process;
-- edge detection on port io
process (clock_i)
begin
if rising_edge(clock_i) then
if reset = '1' then
port_io_dly <= '0';
else
port_io_dly <= port_mf_enable_rd_i or port_mf_enable_wr_i or port_mf_disable_rd_i or port_mf_disable_wr_i;
end if;
end if;
end process;
-- nmi_active (1 = nmi asserted)
button_pulse <= button_i and not nmi_active;
process (clock_i)
begin
if rising_edge(clock_i) then
if reset = '1' then
nmi_active <= '0';
elsif button_pulse = '1' then
nmi_active <= '1';
elsif cpu_retn_seen_i = '1' or ((port_mf_enable_wr_i = '1' or port_mf_disable_wr_i = '1' or (port_mf_disable_rd_i = '1' and mode_p3 = '1')) and port_io_dly = '0') then
nmi_active <= '0';
end if;
end if;
end process;
-- invisible (1 = invisible)
process (clock_i)
begin
if rising_edge(clock_i) then
if reset = '1' then
invisible <= '1';
elsif button_pulse = '1' then
invisible <= '0';
elsif ((port_mf_disable_wr_i = '1' and mode_p3 = '0') or (port_mf_enable_wr_i = '1' and mode_p3 = '1')) and port_io_dly = '0' then
invisible <= '1';
end if;
end if;
end process;
invisible_eff <= invisible and not mode_48;
-- mf_enable (1 = memory paged in)
fetch_66 <= '1' when cpu_a_0066_i = '1' and cpu_m1_n_i = '0' and nmi_active = '1' else '0';
process (clock_i)
begin
if rising_edge(clock_i) then
if reset = '1' then
mf_enable <= '0';
elsif fetch_66 = '1' and cpu_mreq_n_i = '0' then
mf_enable <= '1';
elsif port_mf_disable_rd_i = '1' or cpu_retn_seen_i = '1' then
mf_enable <= '0';
elsif port_mf_enable_rd_i = '1' then
mf_enable <= not invisible_eff;
end if;
end if;
end process;
mf_enable_eff <= mf_enable or fetch_66;
-- multiface memory
mf_enabled_o <= mf_enable_eff;
nmi_disable_o <= nmi_active;
-- port read
mf_port_en_o <= '1' when port_mf_enable_rd_i = '1' and invisible_eff = '0' and (mode_128 = '1' or mode_p3 = '1') else '0';
end architecture;

180
rtl/device/peripherals.vhd Normal file
View File

@@ -0,0 +1,180 @@
-- INTERRUPTING PERIPHERALS
-- Copyright 2020 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
--
-- Instantiate interrupt handling for all peripherals.
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity peripherals is
generic (
constant NUM_PERIPH : positive := 14;
constant VEC_BITS : positive := 4
);
port (
i_CLK_28 : in std_logic;
i_CLK_CPU : in std_logic;
i_reset : in std_logic;
i_m1_n : in std_logic;
i_iorq_n : in std_logic;
i_mode_pulse_0_im2_1 : in std_logic;
i_int_req : in std_logic_vector(NUM_PERIPH downto 1);
i_int_en : in std_logic_vector(NUM_PERIPH downto 1);
o_int_status : out std_logic_vector(NUM_PERIPH downto 1);
i_int_status_clear : in std_logic_vector(NUM_PERIPH downto 1);
i_iei : in std_logic;
o_ieo : out std_logic;
i_reti_decode : in std_logic;
i_reti_seen : in std_logic;
o_int_n : out std_logic;
o_vector : out std_logic_vector(VEC_BITS-1 downto 0);
i_dma_int_en : in std_logic_vector(NUM_PERIPH downto 1);
o_dma_int : out std_logic;
o_pulse_en : out std_logic
);
end entity;
architecture rtl of peripherals is
type vector_t is array (NUM_PERIPH downto 1) of std_logic_vector(VEC_BITS-1 downto 0);
signal vec : vector_t;
signal ie : std_logic_vector(NUM_PERIPH downto 0);
signal int_n : std_logic_vector(NUM_PERIPH downto 1);
signal pulse_en : std_logic_vector(NUM_PERIPH downto 1);
signal dma_int : std_logic_vector(NUM_PERIPH downto 1);
begin
ie(0) <= i_iei;
-- instantiate interrupt handler for each device
gen_per:
for I in 1 to NUM_PERIPH generate
peripheral: entity work.im2_peripheral
generic map (
VEC_BITS => VEC_BITS
)
port map (
i_CLK_28 => i_CLK_28,
i_CLK_CPU => i_CLK_CPU,
i_reset => i_reset,
i_m1_n => i_m1_n,
i_iorq_n => i_iorq_n,
i_mode_pulse_0_im2_1 => i_mode_pulse_0_im2_1,
i_iei => ie(I-1),
o_ieo => ie(I),
i_reti_decode => i_reti_decode,
i_reti_seen => i_reti_seen,
i_int_en => i_int_en(I),
i_int_req => i_int_req(I),
i_int_status_clear => i_int_status_clear(I),
o_int_status => o_int_status(I),
o_int_n => int_n(I),
o_pulse_en => pulse_en(I),
i_vector => std_logic_vector(to_unsigned(I-1,VEC_BITS)),
o_vector => vec(I),
i_dma_int_en => i_dma_int_en(I),
o_dma_int => dma_int(I)
);
end generate;
-- im2 signals
o_ieo <= ie(NUM_PERIPH);
process (vec)
variable tmp_vec : std_logic_vector(VEC_BITS-1 downto 0);
begin
tmp_vec := vec(1);
for I in 2 to NUM_PERIPH loop
tmp_vec := tmp_vec or vec(I);
end loop;
o_vector <= tmp_vec;
end process;
process (int_n)
variable tmp_int_n : std_logic;
begin
tmp_int_n := int_n(1);
for I in 2 to NUM_PERIPH loop
tmp_int_n := tmp_int_n and int_n(I);
end loop;
o_int_n <= tmp_int_n;
end process;
-- pulse mode
process (pulse_en)
variable tmp_pulse_en : std_logic;
begin
tmp_pulse_en := pulse_en(1);
for I in 2 to NUM_PERIPH loop
tmp_pulse_en := tmp_pulse_en or pulse_en(I);
end loop;
o_pulse_en <= tmp_pulse_en; -- and not i_mode_pulse_0_im2_1;
end process;
-- interrupt dma operation
process (dma_int)
variable tmp_dma_int : std_logic;
begin
tmp_dma_int := dma_int(1);
for I in 2 to NUM_PERIPH loop
tmp_dma_int := tmp_dma_int or dma_int(I);
end loop;
o_dma_int <= tmp_dma_int; -- and i_mode_pulse_0_im2_1;
end process;
end architecture;

View File

@@ -0,0 +1,188 @@
-- PS2 Keymap
-- Copyright 2020 Fabio Belavenuto
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity keymaps is
port (
clock_i : in std_logic;
addr_wr_i : in std_logic_vector(8 downto 0);
data_i : in std_logic_vector(8 downto 0);
we_i : in std_logic;
addr_rd_i : in std_logic_vector(8 downto 0);
data_o : out std_logic_vector(8 downto 0)
);
end entity;
architecture Behavior of keymaps is
-- Speccy keymaps
-- col 0 1 2 3 4 5 6
-- row ------------------------------------------
-- 0 | CAPS Z X C V EXTEND UP
-- 1 | A S D F G CAPS LOCK GRAPH
-- 2 | Q W E R T TRUE VID INV VID
-- 3 | 1 2 3 4 5 BREAK EDIT
-- 4 | 0 9 8 7 6 ; "
-- 5 | P O I U Y , .
-- 6 | RET L K J H DELETE RIGHT
-- 7 | SPC SYM M N B LEFT DOWN
type ram_t is array (0 to 511) of std_logic_vector(8 downto 0);
-- keycode set 2 us keyboard
signal ram_q : ram_t := (
-- Format:
-- bit 8 = (reserved)
-- bit 7 = SYMBOL
-- bit 6 = CAPS
-- bits 5-3 = row
-- bits 2-0 = col (only 0-6)
-- No extended
-- Left / Right Shift = CAPS SHIFT
-- Left / Right Ctl = SYM SHIFT
-- Left Alt = EXTEND
-- Right Alt = GRAPH
-- ;",. mapped to appropriate keys
-- Arrows mapped to ARROWS
-- Caps lock to CAPS LOCK
-- Backspace to DELETE
-- Esc = BREAK
-- ` = EDIT (to left of 1)
-- Tab = TRUE VIDEO
-- \ = INV VIDEO (right side of same row as tab)
-- F9 F5 F3 F1 F2 F12
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 00..07
-- F10 F8 F6 F4 Tab ` ~
"000000111", "000000111", "000000111", "000000111", "000000111", "000010101", "000011110", "000000111", -- 08..0F
-- LAlt LShft LCtrl Q 1 !
"000000111", "000000101", "001000111", "000000111", "010000111", "000010000", "000011000", "000000111", -- 10..17
-- Z S A W 2 @
"000000111", "000000111", "000000001", "000001001", "000001000", "000010001", "000011001", "000000111", -- 18..1F
-- C X D E 4 $ 3 #
"000000111", "000000011", "000000010", "000001010", "000010010", "000011011", "000011010", "000000111", -- 20..27
-- Space V F T R 5 %
"000000111", "000111000", "000000100", "000001011", "000010100", "000010011", "000011100", "000000111", -- 28..2F
-- N B H G Y 6 ¨
"000000111", "000111011", "000111100", "000110100", "000001100", "000101100", "000100100", "000000111", -- 30..37
-- M J U 7 & 8 *
"000000111", "000000111", "000111010", "000110011", "000101011", "000100011", "000100010", "000000111", -- 38..3F
-- , < K I O 0 ) 9 (
"000000111", "000101101", "000110010", "000101010", "000101001", "000100000", "000100001", "000000111", -- 40..47
-- . > / ? L ; : P - _
"000000111", "000101110", "010000100", "000110001", "000100101", "000101000", "010110011", "000000111", -- 48..4F
-- ' " [ { = +
"000000111", "000000111", "000100110", "000000111", "000000111", "010110001", "000000111", "000000111", -- 50..57
-- CapsLock R Shift Enter ] } \ |
"000001101", "001000111", "000110000", "000000111", "000000111", "000010110", "000000111", "000000111", -- 58..5F
-- BackSpace
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000110101", "000000111", -- 60..67
-- [1] [4] [7]
"000000111", "000011000", "000000111", "000011011", "000100011", "000000111", "000000111", "000000111", -- 68..6F
-- [0] [.] [2] [5] [6] [8] Esc NumLock
"000100000", "000101110", "000011001", "000011100", "000100100", "000100010", "000011101", "000000111", -- 70..77
-- F11 [+] [3] [-] [*] [9] ScrLk
"000000111", "010110010", "000011010", "010110011", "010111100", "000100001", "000000111", "000000111", -- 78..7F
-- F7
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 80..87
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 88..8F
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 90..97
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 98..9F
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- A0..A7
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- A8..AF
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- B0..B7
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- B8..BF
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- C0..C7
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- C8..CF
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- D0..D7
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- D8..DF
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- E0..E7
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- E8..EF
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- F0..F7
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- F8..FF
-- Extended
--
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 00..07
--
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 08..0F
-- RAlt PrtSc RCtrl
"000000111", "000001110", "000000111", "000000111", "010000111", "000000111", "000000111", "000000111", -- 10..17
-- LWin
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 18..1F
-- RWin
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 20..27
-- Menu
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 28..2F
-- Power
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 30..37
-- Sleep
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 38..3F
--
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 40..47
-- [/]
"000000111", "000000111", "010000100", "000000111", "000000111", "000000111", "000000111", "000000111", -- 48..4F
--
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 50..57
-- [Enter] Wake
"000000111", "000000111", "000110000", "000000111", "000000111", "000000111", "000000111", "000000111", -- 58..5F
--
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 60..67
-- End Left Home
"000000111", "000000111", "000000111", "000111101", "000000111", "000000111", "000000111", "000000111", -- 68..6F
-- Ins Delete Down Right Up
"000000111", "000000111", "000111110", "000000111", "000110110", "000000110", "000000111", "000000111", -- 70..77
-- PDown PUp
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 78..7F
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 80..87
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 88..8F
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 90..97
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- 98..9F
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- A0..A7
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- A8..AF
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- B0..B7
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- B8..BF
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- C0..C7
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- C8..CF
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- D0..D7
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- D8..DF
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- E0..E7
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- E8..EF
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", -- F0..F7
"000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111", "000000111" -- F8..FF
);
begin
process (clock_i)
begin
if rising_edge(clock_i) then
if we_i = '1' then
ram_q(to_integer(unsigned(addr_wr_i))) <= data_i;
end if;
data_o <= ram_q(to_integer(unsigned(addr_rd_i)));
end if;
end process;
end architecture;

View File

@@ -0,0 +1,282 @@
-- Copyright 2010 Thiago Borges Abdnur
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
-- Original file traced to:
-- https://github.com/tiagochst/cmp613/blob/master/Lab4/Doc/ps2_iobase.vhd
--
-- License traced to:
-- https://code.google.com/archive/p/cmp613/source/default/source?page=20
-- https://code.google.com/archive/p/cmp613/
--
-------------------------------------------------------------------------------
-- Title : MC613
-- Project : PS2 Basic Protocol
-- Details : www.ic.unicamp.br/~corte/mc613/
-- www.computer-engineering.org/ps2protocol/
-------------------------------------------------------------------------------
-- File : ps2_base.vhd
-- Author : Thiago Borges Abdnur
-- Company : IC - UNICAMP
-- Last update: 2010/04/12
-------------------------------------------------------------------------------
-- Description:
-- PS2 basic control
-------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
entity ps2_iobase is
generic (
clkfreq_g : integer -- This is the system clock value in kHz
);
port(
clock_i : in std_logic; -- system clock (same frequency as defined in 'clkfreq_g' generic)
reset_i : in std_logic; -- Reset when '1'
enable_i : in std_logic; -- Enable
ps2_data_i : in std_logic; -- PS2 data pin
ps2_clk_i : in std_logic; -- PS2 clock pin
ps2_data_o : out std_logic; -- PS2 data pin
ps2_clk_o : out std_logic; -- PS2 clock pin
ps2_data_out : out std_logic; -- "1" when data is set
ps2_clk_out : out std_logic; -- "1" when clock is set
data_rdy_i : in std_logic; -- Rise this to signal data is ready to be sent to device
data_i : in std_logic_vector(7 downto 0); -- Data to be sent to device
send_rdy_o : out std_logic; -- '1' if data can be sent to device (wait for this before rising 'data_rdy_i'
data_rdy_o : out std_logic; -- '1' when data from device has arrived
data_o : out std_logic_vector(7 downto 0); -- Data from device
sigsending_o : out std_logic
);
end;
architecture rtl of ps2_iobase is
constant CLKSSTABLE : integer := clkfreq_g / 150;
signal sdata, hdata : std_logic_vector(7 downto 0);
signal sigtrigger : std_logic;
signal parchecked : std_logic;
signal sigsending : std_logic;
signal sigsendend : std_logic;
signal sigclkreleased : std_logic;
signal sigclkheld : std_logic;
begin
-- Trigger for state change to eliminate noise
process(clock_i, ps2_clk_i, enable_i, reset_i)
variable fcount, rcount : integer range CLKSSTABLE downto 0;
begin
if(rising_edge(clock_i) and enable_i = '1') then
if reset_i = '1' then
fcount := 0;
rcount := 0;
sigtrigger <= '0';
-- Falling edge noise
elsif ps2_clk_i = '0' then
rcount := 0;
if fcount >= CLKSSTABLE then
sigtrigger <= '1';
else
fcount := fcount + 1;
end if;
-- Rising edge noise
elsif ps2_clk_i = '1' then
fcount := 0;
if rcount >= CLKSSTABLE then
sigtrigger <= '0';
else
rcount := rcount + 1;
end if;
end if;
end if;
end process;
FROMPS2:
process(sigtrigger, sigsending, reset_i)
variable count : integer range 0 to 11;
begin
if reset_i = '1' or sigsending = '1' then
sdata <= (others => '0');
parchecked <= '0';
count := 0;
elsif rising_edge(sigtrigger) then
if count = 0 then
-- Idle state, check for start bit (0) only and don't
-- start counting bits until we get it
if ps2_data_i = '0' then
-- This is a start bit
count := count + 1;
end if;
else
-- Running. 8-bit data comes in LSb first followed by
-- a single stop bit (1)
if count < 9 then
sdata(count - 1) <= ps2_data_i;
end if;
if count = 9 then
if (not (sdata(0) xor sdata(1) xor sdata(2) xor sdata(3)
xor sdata(4) xor sdata(5) xor sdata(6) xor sdata(7))) = ps2_data_i then
parchecked <= '1';
else
parchecked <= '0';
end if;
end if;
count := count + 1;
if count = 11 then
count := 0;
parchecked <= '0';
end if;
end if;
end if;
end process;
data_rdy_o <= enable_i and parchecked;
data_o <= sdata;
-- Edge triggered send register
process(data_rdy_i, sigsendend, reset_i)
begin
if(rising_edge(data_rdy_i)) then
sigsending <= '1';
end if;
if reset_i = '1' or sigsendend = '1' then
sigsending <= '0';
end if;
end process;
-- Wait for at least 11ms before allowing to send again
process(clock_i, sigsending, reset_i)
-- clkfreq_g is the number of clocks within a milisecond
variable countclk : integer range 0 to (12 * clkfreq_g);
begin
if(rising_edge(clock_i) and sigsending = '0') then
if countclk = (11 * clkfreq_g) then
send_rdy_o <= '1';
else
countclk := countclk + 1;
end if;
end if;
if sigsending = '1' then
send_rdy_o <= '0';
countclk := 0;
end if;
if reset_i = '1' then
send_rdy_o <= '1';
countclk := 0;
end if;
end process;
-- Host input data register
process(data_rdy_i, sigsendend, reset_i)
begin
if(rising_edge(data_rdy_i)) then
hdata <= data_i;
end if;
if reset_i = '1' or sigsendend = '1' then
hdata <= (others => '0');
end if;
end process;
-- PS2 clock control
process(enable_i, clock_i, sigsendend, reset_i, sigsending)
constant US100CNT : integer := clkfreq_g / 10;
variable count : integer range 0 to US100CNT + 101;
begin
if(rising_edge(clock_i) and sigsending = '1') then
if count < US100CNT + 50 then
count := count + 1;
ps2_clk_o <= '0';
ps2_clk_out <= '1';
sigclkreleased <= '0';
sigclkheld <= '0';
elsif count < US100CNT + 100 then
count := count + 1;
ps2_clk_o <= '0';
ps2_clk_out <= '1';
sigclkreleased <= '0';
sigclkheld <= '1';
else
ps2_clk_o <= '1';
ps2_clk_out <= '0';
sigclkreleased <= '1';
sigclkheld <= '0';
end if;
end if;
if enable_i = '0' or reset_i = '1' or sigsendend = '1' then
ps2_clk_o <= '1';
ps2_clk_out <= '0';
sigclkreleased <= '1';
sigclkheld <= '0';
count := 0;
end if;
end process;
-- Sending control
TOPS2:
process(enable_i, sigtrigger, sigsending, sigclkheld, sigclkreleased, reset_i)
variable count : integer range 0 to 11;
begin
if(rising_edge(sigtrigger) and sigclkreleased = '1' and sigsending = '1') then
if count >= 0 and count < 8 then
ps2_data_o <= hdata(count);
sigsendend <= '0';
ps2_data_out <= '1';
end if;
if count = 8 then
ps2_data_o <= (not (hdata(0) xor hdata(1) xor hdata(2) xor hdata(3)
xor hdata(4) xor hdata(5) xor hdata(6) xor hdata(7)));
sigsendend <= '0';
ps2_data_out <= '1';
end if;
if count = 9 then
ps2_data_o <= '1';
ps2_data_out <= '0';
sigsendend <= '0';
end if;
if count = 10 then
ps2_data_o <= '1';
ps2_data_out <= '0';
sigsendend <= '1';
count := 0;
end if;
count := count + 1;
end if;
if sigclkheld = '1' then
ps2_data_o <= '0';
ps2_data_out <= '1';
sigsendend <= '0';
count := 0;
end if;
if enable_i = '0' or reset_i = '1' or sigsending = '0' then
ps2_data_o <= '1';
ps2_data_out <= '0';
sigsendend <= '0';
count := 0;
end if;
end process;
sigsending_o <= sigsending;
end rtl;

View File

@@ -0,0 +1,364 @@
-- PS2 Keyboard
-- Copyright 2020 Fabio Belavenuto
-- Copyright 2021 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
-- ps2 button state is represented in an 8x7 matrix
-- when the physical membrane is scanned, the ps2 inserts column data
-- caps + sym shift presses are counted; shifts are not lost in multiple keys
-- typematic filtered so that shift counts remain accurate
-- F11 = multiface nmi button, F12 = divmmc nmi button
-- function keys work as on membrane: F11 + number
-- pause/break resets the ps2 matrix state
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity ps2_keyb is
generic
(
CLK_KHZ : integer
);
port
(
i_CLK : in std_logic;
i_CLK_n : in std_logic;
i_CLK_PS2 : in std_logic;
i_reset : in std_logic;
-- ps2 interface
i_ps2_clk_in : in std_logic;
i_ps2_data_in : in std_logic;
o_ps2_clk_out_en : out std_logic;
o_ps2_clk_out : out std_logic;
o_ps2_data_out_en : out std_logic;
o_ps2_data_out : out std_logic;
-- membrane interaction
o_mf_nmi_n : out std_logic;
o_divmmc_nmi_n : out std_logic;
i_membrane_row : in std_logic_vector(2 downto 0);
o_membrane_col : out std_logic_vector(6 downto 0);
-- programmable keymap
i_keymap_addr : in std_logic_vector(8 downto 0);
i_keymap_data : in std_logic_vector(7 downto 0);
i_keymap_we : in std_logic
);
end entity;
architecture rtl of ps2_keyb is
signal capshift_count_zero : std_logic;
signal capshift_count : std_logic_vector(2 downto 0);
signal symshift_count_zero : std_logic;
signal symshift_count : std_logic_vector(2 downto 0);
type key_matrix_t is array (7 downto 0) of std_logic_vector(6 downto 0);
signal matrix_state : key_matrix_t := ((others => (others => '1')));
signal row_0_n : std_logic;
signal row_7_n : std_logic;
signal ps2_keymap_data : std_logic_vector(8 downto 0);
signal ps2_current_keycode : std_logic_vector(9 downto 0);
signal ps2_last_keycode : std_logic_vector(9 downto 0);
signal ps2_key_valid : std_logic;
signal ps2_matrix_reset : std_logic;
signal ps2_receive_valid : std_logic;
signal ps2_receive_valid_d : std_logic;
signal ps2_receive_valid_re : std_logic;
signal ps2_receive_data : std_logic_vector(7 downto 0);
signal ps2_send_valid : std_logic;
signal ps2_data_07 : std_logic;
signal ps2_data_78 : std_logic;
signal ps2_data_aa : std_logic;
signal ps2_data_e0 : std_logic;
signal ps2_data_e1 : std_logic;
signal ps2_data_f0 : std_logic;
signal clk_ps2_d : std_logic;
signal clk_ps2_re : std_logic;
type state_t is (KM_IDLE, KM_READ, KM_END);
signal state : state_t;
signal state_next : state_t;
signal ps2_key_extend : std_logic;
signal ps2_key_release : std_logic;
begin
-- nmi buttons simulated via F11 and F12
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or ps2_matrix_reset = '1' then
o_mf_nmi_n <= '1';
elsif ps2_key_valid = '1' and ps2_key_extend = '0' and ps2_data_78 = '1' then
o_mf_nmi_n <= ps2_key_release;
end if;
end if;
end process;
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or ps2_matrix_reset = '1' then
o_divmmc_nmi_n <= '1';
elsif ps2_key_valid = '1' and ps2_key_extend = '0' and ps2_data_07 = '1' then
o_divmmc_nmi_n <= ps2_key_release;
end if;
end if;
end process;
-- matrix representation
capshift_count_zero <= '1' when capshift_count = std_logic_vector(to_unsigned(0,capshift_count'length)) else '0';
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or ps2_matrix_reset = '1' then
capshift_count <= (others => '0');
elsif ps2_key_valid = '1' and ps2_keymap_data(6) = '1' then
if ps2_key_release = '0' then
capshift_count <= capshift_count + 1;
elsif capshift_count_zero = '0' then
capshift_count <= capshift_count - 1;
end if;
end if;
end if;
end process;
symshift_count_zero <= '1' when symshift_count = std_logic_vector(to_unsigned(0,symshift_count'length)) else '0';
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or ps2_matrix_reset = '1' then
symshift_count <= (others => '0');
elsif ps2_key_valid = '1' and ps2_keymap_data(7) = '1' then
if ps2_key_release = '0' then
symshift_count <= symshift_count + 1;
elsif symshift_count_zero = '0' then
symshift_count <= symshift_count - 1;
end if;
end if;
end if;
end process;
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or ps2_matrix_reset = '1' then
matrix_state <= ((others => (others => '1')));
elsif ps2_key_valid = '1' and ps2_keymap_data(2 downto 0) /= "111" then
matrix_state(to_integer(unsigned(ps2_keymap_data(5 downto 3))))(to_integer(unsigned(ps2_keymap_data(2 downto 0)))) <= ps2_key_release;
end if;
end if;
end process;
-- membrane scan
row_0_n <= '0' when i_membrane_row = "000" else '1';
row_7_n <= '0' when i_membrane_row = "111" else '1';
o_membrane_col <= (matrix_state(to_integer(unsigned(i_membrane_row)))(6 downto 2)) &
(matrix_state(to_integer(unsigned(i_membrane_row)))(1) and (row_7_n or symshift_count_zero)) &
(matrix_state(to_integer(unsigned(i_membrane_row)))(0) and (row_0_n or capshift_count_zero));
-- ps2 keymap
keymap: entity work.keymaps
port map
(
clock_i => i_CLK_n,
addr_wr_i => i_keymap_addr,
data_i => '0' & i_keymap_data,
we_i => i_keymap_we,
--
addr_rd_i => ps2_key_extend & ps2_receive_data,
data_o => ps2_keymap_data
);
ps2_current_keycode <= ps2_key_release & ps2_key_extend & ps2_receive_data;
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or ps2_matrix_reset = '1' then
ps2_last_keycode <= (others => '1');
elsif ps2_key_valid = '1' then
ps2_last_keycode <= ps2_current_keycode; -- eliminate typematic
end if;
end if;
end process;
ps2_key_valid <= '1' when (state = KM_READ) and ((ps2_last_keycode /= ps2_current_keycode) or ps2_key_release = '1') else '0';
ps2_matrix_reset <= ps2_key_valid and ps2_data_e1;
-- ps2 interface
-- The reset may not be seen inside this module because it operates on a much slower clock.
-- The module needs to be rewritten and replaced, possibly merging keyboard and mouse.
ps2_alt0: entity work.ps2_iobase
generic map (
clkfreq_g => CLK_KHZ
)
port map (
clock_i => i_CLK_PS2,
reset_i => i_reset,
enable_i => '1',
ps2_clk_i => i_ps2_clk_in,
ps2_data_i => i_ps2_data_in,
ps2_clk_o => o_ps2_clk_out,
ps2_data_o => o_ps2_data_out,
ps2_data_out => o_ps2_data_out_en,
ps2_clk_out => o_ps2_clk_out_en,
data_rdy_i => ps2_send_valid,
data_i => X"55",
send_rdy_o => open,
data_rdy_o => ps2_receive_valid,
data_o => ps2_receive_data,
sigsending_o => open
);
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or (clk_ps2_re = '1' and ps2_send_valid = '1') then
ps2_send_valid <= '0';
elsif ps2_receive_valid_re = '1' and ps2_data_aa = '1' then
ps2_send_valid <= '1';
end if;
end if;
end process;
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
clk_ps2_d <= '1';
else
clk_ps2_d <= i_CLK_PS2;
end if;
end if;
end process;
clk_ps2_re <= i_CLK_PS2 and not clk_ps2_d;
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
ps2_receive_valid_d <= '0';
else
ps2_receive_valid_d <= ps2_receive_valid;
end if;
end if;
end process;
ps2_receive_valid_re <= ps2_receive_valid and not ps2_receive_valid_d;
process (ps2_receive_data)
begin
ps2_data_07 <= '0';
ps2_data_78 <= '0';
ps2_data_aa <= '0';
ps2_data_e0 <= '0';
ps2_data_e1 <= '0';
ps2_data_f0 <= '0';
case ps2_receive_data is
when X"07" => ps2_data_07 <= '1';
when X"78" => ps2_data_78 <= '1';
when X"AA" => ps2_data_aa <= '1';
when X"E0" => ps2_data_e0 <= '1';
when X"E1" => ps2_data_e1 <= '1';
when X"F0" => ps2_data_f0 <= '1';
when others => null;
end case;
end process;
-- ps2 state machine
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
state <= KM_IDLE;
else
state <= state_next;
end if;
end if;
end process;
process (state, ps2_receive_valid_re, ps2_data_aa, ps2_data_e0, ps2_data_f0)
begin
case state is
when KM_IDLE =>
if ps2_receive_valid_re = '1' then
if ps2_data_aa = '1' then
state_next <= KM_END;
elsif ps2_data_e0 = '1' or ps2_data_f0 = '1' then
state_next <= KM_IDLE;
else
state_next <= KM_READ;
end if;
else
state_next <= KM_IDLE;
end if;
when KM_READ =>
state_next <= KM_END;
when KM_END =>
state_next <= KM_IDLE;
when others =>
state_next <= KM_IDLE;
end case;
end process;
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or state = KM_END then
ps2_key_extend <= '0';
elsif ps2_receive_valid_re = '1' and ps2_data_e0 = '1' then
ps2_key_extend <= '1';
end if;
end if;
end process;
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or state = KM_END then
ps2_key_release <= '0';
elsif ps2_receive_valid_re = '1' and ps2_data_f0 = '1' then
ps2_key_release <= '1';
end if;
end if;
end process;
end architecture;

View File

@@ -0,0 +1,198 @@
-- Sega Mega Drive Pads x 2
-- Copyright 2020 Victor Trucco and Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity md6_joystick_connector_x2 is
port
(
i_reset : in std_logic;
i_CLK_28 : in std_logic;
i_CLK_EN : in std_logic; -- every ~4.57us
i_joy_1_n : in std_logic;
i_joy_2_n : in std_logic;
i_joy_3_n : in std_logic;
i_joy_4_n : in std_logic;
i_joy_6_n : in std_logic;
i_joy_9_n : in std_logic;
i_io_mode_en : in std_logic;
i_io_mode_pin_7 : in std_logic;
o_joy_7 : out std_logic;
o_joy_select : out std_logic; -- 0 = left connector, 1 = right connector
o_joy_left : out std_logic_vector(10 downto 0); -- active high X Z Y START A C B U D L R
o_joy_right : out std_logic_vector(10 downto 0) -- active high X Z Y START A C B U D L R
);
end entity;
architecture rtl of md6_joystick_connector_x2 is
signal io_mode : std_logic := '0';
signal io_mode_change : std_logic;
-- https://github.com/jonthysell/SegaController/wiki/How-To-Read-Sega-Controllers
-- The state machine consists of 512 states for a period of ~2.34ms
-- 496 states are padding to allow the md controllers time to reset between reads ~2.26ms
-- Pulse width of the select signal must be < ~15us otherwise 6-button controllers won't work
-- Here it's ~9.14us
signal state : std_logic_vector(8 downto 0);
signal state_next : std_logic_vector(8 downto 0);
-- X X X X X S S 7 J
--
-- X = padding for md pad reset
-- SS7 = eight states in state machine, 7 = select on pin 7
-- J = connector being read: left = 0, right = 1
signal state_rest : std_logic;
signal joy_left_six_button_n : std_logic;
signal joy_left_n : std_logic_vector(10 downto 0);
signal joy_right_six_button_n : std_logic;
signal joy_right_n : std_logic_vector(10 downto 0);
signal joy_raw : std_logic_vector(5 downto 0);
begin
-- io mode
process (i_CLK_28)
begin
if rising_edge(i_CLK_28) then
io_mode <= i_io_mode_en;
end if;
end process;
io_mode_change <= io_mode xor i_io_mode_en;
-- md pad state machine
state_rest <= state(8) or state(7) or state(6) or state(5) or state(4);
state_next <= state + 1;
process (i_CLK_28)
begin
if rising_edge(i_CLK_28) then
if i_reset = '1' or io_mode_change = '1' then
state <= "111110000";
elsif io_mode = '1' then
state <= "1111100" & state_next(1 downto 0);
elsif i_CLK_EN = '1' then
state <= state_next;
end if;
end if;
end process;
o_joy_7 <= (state_rest or state(1)) when io_mode = '0' else i_io_mode_pin_7;
o_joy_select <= state(0) when io_mode = '0' else state(1);
-- build md pad state
joy_raw <= i_joy_9_n & i_joy_6_n & i_joy_1_n & i_joy_2_n & i_joy_3_n & i_joy_4_n;
process (i_CLK_28)
begin
if rising_edge(i_CLK_28) then
if i_reset = '1' or io_mode_change = '1' then
joy_left_n <= (others => '1');
joy_right_n <= (others => '1');
elsif i_CLK_EN = '1' and state_rest = '0' then
case state(3 downto 0) is
when "000" & '0' =>
joy_left_six_button_n <= '1';
joy_left_n <= (others => '1');
joy_right_six_button_n <= '1';
joy_right_n <= (others => '1');
when "010" & '0' =>
if i_joy_3_n = '0' and i_joy_4_n = '0' then
joy_left_n(7 downto 6) <= i_joy_9_n & i_joy_6_n;
end if;
when "010" & '1' =>
if i_joy_3_n = '0' and i_joy_4_n = '0' then
joy_right_n(7 downto 6) <= i_joy_9_n & i_joy_6_n;
end if;
when "011" & '0' =>
joy_left_n(5 downto 0) <= joy_raw;
when "011" & '1' =>
joy_right_n(5 downto 0) <= joy_raw;
when "100" & '0' =>
joy_left_six_button_n <= i_joy_1_n or i_joy_2_n;
when "100" & '1' =>
joy_right_six_button_n <= i_joy_1_n or i_joy_2_n;
when "101" & '0' =>
if joy_left_six_button_n = '0' then
joy_left_n(10 downto 8) <= i_joy_3_n & i_joy_1_n & i_joy_2_n;
end if;
when "101" & '1' =>
if joy_right_six_button_n = '0' then
joy_right_n(10 downto 8) <= i_joy_3_n & i_joy_1_n & i_joy_2_n;
end if;
when others => null;
end case;
end if;
end if;
end process;
process (i_CLK_28)
begin
if rising_edge(i_CLK_28) then
if i_reset = '1' or io_mode_change = '1' then
o_joy_left <= (others => '0');
o_joy_right <= (others => '0');
elsif io_mode = '1' and state(1 downto 0) = "01" then
o_joy_left <= "00000" & not joy_raw;
elsif io_mode = '1' and state(1 downto 0) = "11" then
o_joy_right <= "00000" & not joy_raw;
elsif io_mode = '0' and state_rest = '1' then
o_joy_left <= not joy_left_n;
o_joy_right <= not joy_right_n;
end if;
end if;
end process;
end architecture;

View File

@@ -0,0 +1,238 @@
-- Function Keys Emulation
-- Copyright 2020 Fabio Belavenuto and Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity emu_fnkeys is
generic
(
CLOCK_EN_PERIOD_MS : natural;
BUTTON_PERIOD_MS : natural
);
port
(
i_CLK : in std_logic;
i_CLK_EN : in std_logic;
i_reset : in std_logic;
i_rows : in std_logic_vector(7 downto 0);
o_rows_filtered : out std_logic_vector(7 downto 0);
i_cols : in std_logic_vector(4 downto 0);
o_cols_filtered : out std_logic_vector(4 downto 0);
i_button_m1_n : in std_logic;
i_button_reset_n : in std_logic;
o_fnkeys : out std_logic_vector(10 downto 1)
);
end entity;
architecture rtl of emu_fnkeys is
constant PERIOD : natural := BUTTON_PERIOD_MS / CLOCK_EN_PERIOD_MS;
signal timer_count : natural range 0 to PERIOD := 0;
signal timer_set : std_logic;
signal timer_expired : std_logic;
signal button_m1_n_edge : std_logic_vector(1 downto 0) := "00";
signal button_m1_n_assert : std_logic;
signal button_reset_n_edge : std_logic_vector(1 downto 0) := "00";
signal button_reset_n_assert : std_logic;
type state_t is (S_IDLE, S_MF_ROW_A11, S_MF_ROW_A12, S_MF_CHECK, S_MF_DONE, S_RESET_CHECK, S_RESET_DONE);
signal state : state_t;
signal next_state : state_t;
signal local_rows : std_logic_vector(7 downto 0);
signal local_cols : std_logic_vector(4 downto 0);
signal cancel_nmi : std_logic := '0';
signal local_fnkeys : std_logic_vector(10 downto 1) := (others => '0');
begin
o_rows_filtered <= local_rows;
o_cols_filtered <= local_cols;
o_fnkeys <= local_fnkeys;
--
-- timer
--
timer_set <= '1' when state = S_IDLE and (button_reset_n_assert = '1' or button_m1_n_assert = '1') else '0';
timer_expired <= '1' when timer_count = 0 else '0';
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
timer_count <= 0;
elsif timer_set = '1' then
timer_count <= PERIOD;
elsif i_CLK_EN = '1' and timer_expired = '0' then
timer_count <= timer_count - 1;
end if;
end if;
end process;
--
-- button edge detection
--
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
button_m1_n_edge <= (others => '0');
else
button_m1_n_edge <= button_m1_n_edge(0) & i_button_m1_n;
end if;
end if;
end process;
button_m1_n_assert <= '1' when button_m1_n_edge = "10" else '0';
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
button_reset_n_edge <= (others => '0');
else
button_reset_n_edge <= button_reset_n_edge(0) & i_button_reset_n;
end if;
end if;
end process;
button_reset_n_assert <= '1' when button_reset_n_edge = "10" else '0';
--
-- state machine
--
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
state <= S_IDLE;
else
state <= next_state;
end if;
end if;
end process;
process (state, button_m1_n_assert, button_m1_n_edge, button_reset_n_assert, button_reset_n_edge)
begin
case state is
when S_IDLE =>
if button_reset_n_assert = '1' then
next_state <= S_RESET_CHECK;
elsif button_m1_n_assert = '1' then
next_state <= S_MF_ROW_A11;
else
next_state <= S_IDLE;
end if;
when S_MF_ROW_A11 =>
next_state <= S_MF_ROW_A12;
when S_MF_ROW_A12 =>
next_state <= S_MF_CHECK;
when S_MF_CHECK =>
if button_m1_n_edge(0) = '1' then
next_state <= S_MF_DONE;
else
next_state <= S_MF_ROW_A11;
end if;
when S_MF_DONE =>
next_state <= S_IDLE;
when S_RESET_CHECK =>
if button_reset_n_edge(0) = '1' then
next_state <= S_RESET_DONE;
else
next_state <= S_RESET_CHECK;
end if;
when S_RESET_DONE =>
next_state <= S_IDLE;
when others =>
next_state <= S_IDLE;
end case;
end process;
local_rows <= i_rows when state = S_IDLE else "11110111" when state = S_MF_ROW_A11 else "11101111";
local_cols <= i_cols when state = S_IDLE else (others => '1');
--
-- function keys
--
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
cancel_nmi <= '0';
elsif state = S_IDLE then
cancel_nmi <= '0';
else
cancel_nmi <= cancel_nmi or not (i_cols(4) and i_cols(3) and i_cols(2) and i_cols(1) and i_cols(0));
end if;
end if;
end process;
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
local_fnkeys <= (others => '0');
elsif state = S_MF_ROW_A11 then
local_fnkeys(5 downto 1) <= not i_cols(4 downto 0);
elsif state = S_MF_ROW_A12 then
local_fnkeys(10 downto 6) <= not (i_cols(0) & i_cols(1) & i_cols(2) & i_cols(3) & i_cols(4));
elsif state = S_MF_DONE then
local_fnkeys <= '0' & (not timer_expired and not cancel_nmi) & "00000000"; -- F9 = multiface nmi on short press
elsif state = S_RESET_DONE then
if timer_expired = '1' then
local_fnkeys <= "0000000001"; -- F1 = hard reset on long press
else
local_fnkeys <= "0000001000"; -- F4 = soft reset on short press
end if;
elsif state = S_IDLE then
local_fnkeys <= (others => '0');
end if;
end if;
end process;
end architecture;

View File

@@ -0,0 +1,256 @@
-- Keyboard Membrane Scan
-- Copyright 2020 Victor Trucco and Alvin Albrecht
--
-- Membrane state machine - Victor Trucco
-- Refactor & modify for 8x7 matrix - Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity membrane is
port
(
i_CLK : in std_logic;
i_CLK_EN : in std_logic;
i_reset : in std_logic;
i_rows : in std_logic_vector(7 downto 0); -- key rows being read
o_cols : out std_logic_vector(4 downto 0); -- key cols returned for read
o_membrane_rows : out std_logic_vector(7 downto 0); -- physical membrane rows 0 = active, 1 = Z
o_membrane_ridx : out std_logic_vector(2 downto 0); -- physical membrane row by number 0-7
i_membrane_cols : in std_logic_vector(6 downto 0); -- physical membrane cols returned, 6:5 are extra columns
i_cancel_extended_entries : in std_logic; -- cancel making entries in the standard 8x5 matrix for the extra keys
o_extended_keys : out std_logic_vector(15 downto 0)
);
end entity;
architecture rtl of membrane is
type key_matrix_t is array (7 downto 0) of std_logic_vector(6 downto 0);
signal state : std_logic_vector(8 downto 0) := '1' & X"FE";
signal index : natural range 0 to 7;
signal matrix_state : key_matrix_t := ((others => (others => '1')));
signal matrix_work : key_matrix_t := ((others => (others => '1')));
signal matrix_state_ex : std_logic_vector(16 downto 0);
signal matrix_work_ex : std_logic_vector(16 downto 0);
signal matrix_state_ex_0 : std_logic_vector(18 downto 0);
signal matrix_state_ex_1 : std_logic_vector(18 downto 0);
signal matrix_state_0 : std_logic_vector(4 downto 0);
signal matrix_state_3 : std_logic_vector(4 downto 0);
signal matrix_state_4 : std_logic_vector(4 downto 0);
signal matrix_state_5 : std_logic_vector(4 downto 0);
signal matrix_state_7 : std_logic_vector(4 downto 0);
signal r0 : std_logic_vector(4 downto 0);
signal r1 : std_logic_vector(4 downto 0);
signal r2 : std_logic_vector(4 downto 0);
signal r3 : std_logic_vector(4 downto 0);
signal r4 : std_logic_vector(4 downto 0);
signal r5 : std_logic_vector(4 downto 0);
signal r6 : std_logic_vector(4 downto 0);
signal r7 : std_logic_vector(4 downto 0);
begin
--
-- physical membrane row scan
--
-- one-hot state machine
-- 0 = START
-- 1 = A8
-- 2 = A9
-- 3 = A10
-- 4 = A11
-- 5 = A12
-- 6 = A13
-- 7 = A14
-- 8 = A15
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
state <= '1' & X"FE";
elsif i_CLK_EN = '1' then
state <= state(7 downto 0) & state(8);
end if;
end if;
end process;
o_membrane_rows <= state(8 downto 1);
-- store physical membrane scan into matrix
process (state)
begin
if state(1) = '0' then
index <= 0;
elsif state(2) = '0' then
index <= 1;
elsif state(3) = '0' then
index <= 2;
elsif state(4) = '0' then
index <= 3;
elsif state(5) = '0' then
index <= 4;
elsif state(6) = '0' then
index <= 5;
elsif state(7) = '0' then
index <= 6;
else
index <= 7;
end if;
end process;
o_membrane_ridx <= std_logic_vector(to_unsigned(index,3));
-- 8 x 5
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
matrix_state <= ((others => (others => '1')));
matrix_work <= ((others => (others => '1')));
elsif i_CLK_EN = '1' then
if state(0) = '0' then
for I in 0 to 7 loop
matrix_state(I) <= matrix_work(I);
end loop;
else
matrix_work(index) <= i_membrane_cols;
end if;
end if;
end if;
end process;
-- extra two columns
-- ex registers contain keypresses for:
--
-- key CPR SMR | N M SYM SPC O P 6 7 8 9 0 5 4 3 2 1 CAP
-- bit 18 17 | 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
-- column bits 6:5 arranged on rows as follows:
--
-- bit 6 bit 5
--
-- row 0 UP EXTEND
-- row 1 GRAPH CAPS LOCK
-- row 2 INV VIDEO TRUE VIDEO
-- row 3 EDIT BREAK
-- row 4 " ;
-- row 5 . ,
-- row 6 RIGHT DELETE
-- row 7 DOWN LEFT
-- Make it harder for naive software to incorrectly read composite keys by
-- advancing shift key state one scan and holding shift key state an extra scan.
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or i_cancel_extended_entries = '1' then
matrix_state_ex_1 <= (others => '1');
matrix_state_ex_0 <= (others => '1');
matrix_work_ex <= (others => '1');
elsif i_CLK_EN = '1' then
if state(0) = '0' then
matrix_state_ex_1 <= matrix_state_ex_0;
matrix_state_ex_0 <= matrix_work_ex(0) & matrix_work_ex(14) & matrix_work_ex(16 downto 15) & (matrix_work_ex(14) and matrix_state_ex_1(17)) & matrix_work_ex(13 downto 1) & (matrix_work_ex(0) and matrix_state_ex_1(18));
matrix_work_ex <= (others => '1');
else
case index is
when 0 =>
matrix_work_ex(0) <= matrix_work_ex(0) and i_membrane_cols(6) and i_membrane_cols(5);
matrix_work_ex(9) <= i_membrane_cols(6);
matrix_work_ex(14) <= matrix_work_ex(14) and i_membrane_cols(5);
when 1 =>
matrix_work_ex(0) <= matrix_work_ex(0) and i_membrane_cols(6) and i_membrane_cols(5);
matrix_work_ex(7) <= i_membrane_cols(6);
matrix_work_ex(2) <= i_membrane_cols(5);
when 2 =>
matrix_work_ex(0) <= matrix_work_ex(0) and i_membrane_cols(6) and i_membrane_cols(5);
matrix_work_ex(4) <= i_membrane_cols(6);
matrix_work_ex(3) <= i_membrane_cols(5);
when 3 =>
matrix_work_ex(0) <= matrix_work_ex(0) and i_membrane_cols(6) and i_membrane_cols(5);
matrix_work_ex(1) <= i_membrane_cols(6);
matrix_work_ex(13) <= i_membrane_cols(5);
when 4 =>
matrix_work_ex(14) <= matrix_work_ex(14) and i_membrane_cols(6) and i_membrane_cols(5);
matrix_work_ex(11) <= i_membrane_cols(6);
matrix_work_ex(12) <= i_membrane_cols(5);
when 5 =>
matrix_work_ex(14) <= matrix_work_ex(14) and i_membrane_cols(6) and i_membrane_cols(5);
matrix_work_ex(15) <= i_membrane_cols(6);
matrix_work_ex(16) <= i_membrane_cols(5);
when 6 =>
matrix_work_ex(0) <= matrix_work_ex(0) and i_membrane_cols(6) and i_membrane_cols(5);
matrix_work_ex(8) <= i_membrane_cols(6);
matrix_work_ex(6) <= i_membrane_cols(5);
when others =>
matrix_work_ex(0) <= matrix_work_ex(0) and i_membrane_cols(6) and i_membrane_cols(5);
matrix_work_ex(10) <= i_membrane_cols(6);
matrix_work_ex(5) <= i_membrane_cols(5);
end case;
end if;
end if;
end if;
end process;
matrix_state_ex <= matrix_state_ex_1(16 downto 15) & (matrix_state_ex_1(14) and matrix_state_ex_0(14)) & matrix_state_ex_1(13 downto 1) & (matrix_state_ex_1(0) and matrix_state_ex_0(0));
-- read matrix state
matrix_state_0 <= matrix_state(0)(4 downto 1) & (matrix_state(0)(0) and matrix_state_ex(0));
matrix_state_3 <= matrix_state(3)(4 downto 0) and matrix_state_ex(5 downto 1);
matrix_state_4 <= matrix_state(4)(4 downto 0) and matrix_state_ex(10 downto 6);
matrix_state_5 <= matrix_state(5)(4 downto 2) & (matrix_state(5)(1 downto 0) and matrix_state_ex(12 downto 11));
matrix_state_7 <= matrix_state(7)(4) & (matrix_state(7)(3 downto 0) and matrix_state_ex(16 downto 13));
r0 <= matrix_state_0 when i_rows(0) = '0' else (others => '1');
r1 <= matrix_state(1)(4 downto 0) when i_rows(1) = '0' else (others => '1');
r2 <= matrix_state(2)(4 downto 0) when i_rows(2) = '0' else (others => '1');
r3 <= matrix_state_3 when i_rows(3) = '0' else (others => '1');
r4 <= matrix_state_4 when i_rows(4) = '0' else (others => '1');
r5 <= matrix_state_5 when i_rows(5) = '0' else (others => '1');
r6 <= matrix_state(6)(4 downto 0) when i_rows(6) = '0' else (others => '1');
r7 <= matrix_state_7 when i_rows(7) = '0' else (others => '1');
o_cols <= r0 and r1 and r2 and r3 and r4 and r5 and r6 and r7;
o_extended_keys <= not (matrix_state(7)(6 downto 5) & matrix_state(6)(6 downto 5) & matrix_state(5)(6 downto 5) & matrix_state(4)(6 downto 5) &
matrix_state(3)(6 downto 5) & matrix_state(2)(6 downto 5) & matrix_state(1)(6 downto 5) & matrix_state(0)(6 downto 5));
end architecture;

View File

@@ -0,0 +1,200 @@
-- User Definable Keyboard Joystick
-- Copyright 2021 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity membrane_stick is
port
(
i_CLK : in std_logic;
i_CLK_EN : in std_logic; -- scanning a new keyboard row, at least 25x slower than clock
i_reset : in std_logic;
i_joy_en_n : in std_logic;
i_joy_left : in std_logic_vector(10 downto 0);
i_joy_left_type : in std_logic_vector(2 downto 0);
i_joy_right : in std_logic_vector(10 downto 0);
i_joy_right_type : in std_logic_vector(2 downto 0);
i_membrane_row : in std_logic_vector(2 downto 0);
o_membrane_col : out std_logic_vector(6 downto 0);
i_keymap_addr : in std_logic_vector(4 downto 0); -- left/right (4), button number (3:0)
i_keymap_data : in std_logic_vector(5 downto 0); -- membrane row (5:3), membrane col (2:0)
i_keymap_we : in std_logic
);
end entity;
architecture rtl of membrane_stick is
component keyjoy_sdpram_64_6 is
PORT (
DPRA : IN STD_LOGIC_VECTOR(6-1 downto 0) := (OTHERS => '0');
CLK : IN STD_LOGIC;
WE : IN STD_LOGIC;
DPO : OUT STD_LOGIC_VECTOR(6-1 downto 0);
A : IN STD_LOGIC_VECTOR(6-1-(4*0*boolean'pos(7>4)) downto 0) := (OTHERS => '0');
D : IN STD_LOGIC_VECTOR(6-1 downto 0) := (OTHERS => '0')
);
end component;
signal state : std_logic := '0';
signal state_next : std_logic;
signal joy_state : std_logic_vector(10 downto 0);
signal joy_type : std_logic_vector(2 downto 0);
signal joy_addr_start : std_logic_vector(4 downto 0);
signal joy_bit_count_start : std_logic_vector(3 downto 0);
signal joy_bit_count_end : std_logic_vector(3 downto 0);
signal bit_count_end : std_logic;
signal joy_sel : std_logic;
signal sram_addr : std_logic_vector(4 downto 0);
signal bit_count : std_logic_vector(3 downto 0);
signal bit_count_max : std_logic_vector(3 downto 0);
signal joy_keymap_do : std_logic_vector(5 downto 0);
signal membrane_col : std_logic_vector(7 downto 0);
begin
-- state machine
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
state <= '0';
else
state <= state_next;
end if;
end if;
end process;
process (state, i_CLK_EN, joy_sel, bit_count_end)
begin
case state is
when '0' =>
if i_CLK_EN = '1' then
state_next <= '1';
else
state_next <= '0';
end if;
when others =>
if joy_sel = '1' and bit_count_end = '1' then
state_next <= '0';
else
state_next <= '1';
end if;
end case;
end process;
-- joystick parameter selection
joy_state <= i_joy_left when joy_sel = '0' else i_joy_right;
joy_type <= i_joy_left_type when bit_count_end = '0' else i_joy_right_type;
process (joy_type)
begin
case joy_type is
when "011" => -- Sinclair 1
joy_addr_start <= "00000";
joy_bit_count_start <= "0000";
joy_bit_count_end <= "0100";
when "000" => -- Sinclair 2
joy_addr_start <= "00101";
joy_bit_count_start <= "0000";
joy_bit_count_end <= "0100";
when "010" => -- Cursor
joy_addr_start <= "01010";
joy_bit_count_start <= "0000";
joy_bit_count_end <= "0100";
when "111" => -- User Defined
joy_addr_start <= "10000";
joy_bit_count_start <= "0000";
joy_bit_count_end <= "1010";
when "001" | "100" => -- Kempston
joy_addr_start <= "10101";
joy_bit_count_start <= "0101";
joy_bit_count_end <= "1010";
when others => -- MD Pad
joy_addr_start <= "11000";
joy_bit_count_start <= "1000";
joy_bit_count_end <= "1010";
end case;
end process;
-- joystick address generation
bit_count_end <= '1' when bit_count = bit_count_max else '0';
process (i_CLK)
begin
if rising_edge(i_CLK) then
if state = '0' or bit_count_end = '1' then
joy_sel <= bit_count_end;
sram_addr <= joy_addr_start;
bit_count <= joy_bit_count_start;
bit_count_max <= joy_bit_count_end;
elsif state = '1' then
sram_addr <= sram_addr + 1;
bit_count <= bit_count + 1;
end if;
end if;
end process;
-- joystick bit to key assignment lookup
udk_map: keyjoy_sdpram_64_6 -- initialized with sinclair / cursor mappings
port map -- src/ram/init/keyjoy_64_6.coe
(
-- async read (keymap)
DPRA => joy_sel & sram_addr,
DPO => joy_keymap_do,
-- sync write (cpu)
CLK => i_CLK,
WE => i_keymap_we,
A => i_keymap_addr(4) & '1' & i_keymap_addr(3 downto 0),
D => i_keymap_data
);
-- membrane column bits computation
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or (state = '0' and state_next = '1') or i_joy_en_n = '1' then
membrane_col <= (others => '1');
elsif state = '1' and joy_keymap_do(5 downto 3) = i_membrane_row and joy_state(to_integer(unsigned(bit_count))) = '1' then
membrane_col(to_integer(unsigned(joy_keymap_do(2 downto 0)))) <= '0';
end if;
end if;
end process;
o_membrane_col <= membrane_col(6 downto 0);
end architecture;

351
rtl/input/ps2_mouse.v Normal file
View File

@@ -0,0 +1,351 @@
// PS2 Mouse
// Copyright 2006, 2007 Dennis van Weeren
//
// This file is part of the ZX Spectrum Next Project
// <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
//
// The ZX Spectrum Next FPGA source code 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.
//
// The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
// <https://www.gnu.org/licenses/>.
//
// Original:
// https://github.com/rkrajnc/minimig-mist/blob/master/rtl/minimig/userio_ps2mouse.v
// Modifed for the zx next project by Alvin Albrecht
// * Add controls to adjust dpi and mouse button swap (operate on returned result)
//PS2 mouse controller.
//This module decodes the standard 3 byte packet of an PS/2 compatible 2 or 3 button mouse.
//The module also automatically handles power-up initailzation of the mouse.
module ps2_mouse
(
input clk, //bus clock
input reset, //reset
input ps2mdat_i, //mouse PS/2 data
input ps2mclk_i, //mouse PS/2 clk
output ps2mdat_o, //mouse PS/2 data
output ps2mclk_o, //mouse PS/2 clk
input [2:0] control_i, // button reverse, dpi
// input [5:0] mou_emu,
// input sof,
output reg [7:0]zcount, // mouse Z counter
output reg [7:0]ycount, //mouse Y counter
output reg [7:0]xcount, //mouse X counter
output reg mleft, //left mouse button output
output reg mthird, //third(middle) mouse button output
output reg mright //right mouse button output
// input test_load, //load test value to mouse counter
// input [15:0] test_data //mouse counter test value
);
reg mclkout;
wire mdatout;
reg [ 2-1:0] mdatr;
reg [ 3-1:0] mclkr;
reg [11-1:0] mreceive;
reg [12-1:0] msend;
reg [16-1:0] mtimer;
reg [ 3-1:0] mstate;
reg [ 3-1:0] mnext;
reg mreverse;
reg [1:0] mdpi;
reg [7:0] xydelta;
reg [2:0] mbutton;
wire mclkneg;
reg mrreset;
wire mrready;
reg msreset;
wire msready;
reg mtreset;
wire mtready;
wire mthalf;
reg [ 3-1:0] mpacket;
reg intellimouse=0;
wire mcmd_done;
reg [ 4-1:0] mcmd_cnt=1;
reg mcmd_inc=0;
reg [12-1:0] mcmd;
// bidirectional open collector IO buffers
//assign ps2mdat_o = (mdatout) ? 1'b1 : 1'b0;
//assign ps2mclk_o = (mclkout) ? 1'b1 : 1'b0;
assign ps2mdat_o = mdatout;
assign ps2mclk_o = mclkout;
// input synchronization of external signals
always @ (posedge clk) begin
mdatr[1:0] <= #1 {mdatr[0], ps2mdat_i};
mclkr[2:0] <= #1 {mclkr[1:0], ps2mclk_i};
end
// detect mouse clock negative edge
assign mclkneg = mclkr[2] & !mclkr[1];
// PS2 mouse input shifter
always @ (posedge clk) begin
if (mrreset)
mreceive[10:0] <= #1 11'b11111111111;
else if (mclkneg)
mreceive[10:0] <= #1 {mdatr[1],mreceive[10:1]};
end
assign mrready = !mreceive[0];
// PS2 mouse data counter
always @ (posedge clk) begin
if (reset)
mcmd_cnt <= #1 4'd0;
else if (mcmd_inc && !mcmd_done)
mcmd_cnt <= #1 mcmd_cnt + 4'd1;
end
assign mcmd_done = (mcmd_cnt == 4'd9);
// mouse init commands
always @ (*) begin
case (mcmd_cnt)
// GUARD STOP PARITY DATA START
4'h0 : mcmd = {1'b1, 1'b1, 1'b1, 8'hff, 1'b0}; // reset
4'h1 : mcmd = {1'b1, 1'b1, 1'b1, 8'hf3, 1'b0}; // set sample rate
4'h2 : mcmd = {1'b1, 1'b1, 1'b0, 8'hc8, 1'b0}; // sample rate = 200
4'h3 : mcmd = {1'b1, 1'b1, 1'b1, 8'hf3, 1'b0}; // set sample rate
4'h4 : mcmd = {1'b1, 1'b1, 1'b0, 8'h64, 1'b0}; // sample rate = 100
4'h5 : mcmd = {1'b1, 1'b1, 1'b1, 8'hf3, 1'b0}; // set sample rate
4'h6 : mcmd = {1'b1, 1'b1, 1'b1, 8'h50, 1'b0}; // sample rate = 80
4'h7 : mcmd = {1'b1, 1'b1, 1'b0, 8'hf2, 1'b0}; // read device type
4'h8 : mcmd = {1'b1, 1'b1, 1'b0, 8'hf4, 1'b0}; // enable data reporting
default : mcmd = {1'b1, 1'b1, 1'b0, 8'hf4, 1'b0}; // enable data reporting
endcase
end
// PS2 mouse send shifter
always @ (posedge clk) begin
if (msreset)
msend[11:0] <= #1 mcmd;
else if (!msready && mclkneg)
msend[11:0] <= #1 {1'b0,msend[11:1]};
end
assign msready = (msend[11:0]==12'b000000000001);
assign mdatout = msend[0];
// PS2 mouse timer
always @(posedge clk) begin
if (mtreset)
mtimer[15:0] <= #1 16'h0000;
else
mtimer[15:0] <= #1 mtimer[15:0] + 16'd1;
end
assign mtready = (mtimer[15:0]==16'hffff);
assign mthalf = mtimer[11];
always @ (posedge clk) begin
mreverse <= #1 control_i[2];
mdpi <= #1 control_i[1:0];
end
always @ (*) begin
case(mdpi)
2'b00 : xydelta = {mreceive[7:1],1'b0};
2'b01 : xydelta = mreceive[8:1];
2'b10 : xydelta = {mreceive[8],mreceive[8:2]};
default : xydelta = {mreceive[8],mreceive[8],mreceive[8:3]};
endcase
end
always @ (*) begin
if (mreverse)
mbutton = {mreceive[3],mreceive[1],mreceive[2]};
else
mbutton = {mreceive[3],mreceive[2],mreceive[1]};
end
// PS2 mouse packet decoding and handling
always @ (posedge clk) begin
if (reset) begin
{mthird,mright,mleft} <= #1 3'b000;
xcount[7:0] <= #1 8'h00;
ycount[7:0] <= #1 8'h00;
zcount[7:0] <= #1 8'h00;
end else begin
// if (test_load) // test value preload
// {ycount[7:2],xcount[7:2]} <= #1 {test_data[15:10],test_data[7:2]};
if (mpacket == 3'd1) // buttons
{mthird,mright,mleft} <= #1 mbutton;
else if (mpacket == 3'd2) // delta X movement
xcount[7:0] <= #1 xcount[7:0] + xydelta;
else if (mpacket == 3'd3) // delta Y movement
ycount[7:0] <= #1 ycount[7:0] + xydelta;
else if (mpacket == 3'd4) // delta Z movement
zcount[7:0] <= #1 zcount[7:0] + {{4{mreceive[4]}}, mreceive[4:1]};
// else if (sof) begin
// if (mou_emu[3]) ycount <= #1 ycount - 1'b1;
// else if (mou_emu[2]) ycount <= #1 ycount + 1'b1;
// if (mou_emu[1]) xcount <= #1 xcount - 1'b1;
// else if (mou_emu[0]) xcount <= #1 xcount + 1'b1;
// end
end
end
// PS2 intellimouse flag
always @ (posedge clk) begin
if (reset)
intellimouse <= #1 1'b0;
else if ((mpacket==3'd5) && (mreceive[2:1] == 2'b11))
intellimouse <= #1 1'b1;
end
// PS2 mouse state machine
always @ (posedge clk) begin
if (reset || mtready)
mstate <= #1 0;
else
mstate <= #1 mnext;
end
always @ (*) begin
mclkout = 1'b1;
mtreset = 1'b1;
mrreset = 1'b0;
msreset = 1'b0;
mpacket = 3'd0;
mcmd_inc = 1'b0;
case(mstate)
0 : begin
// initialize mouse phase 0, start timer
mtreset=1;
mnext=1;
end
1 : begin
//initialize mouse phase 1, hold clk low and reset send logic
mclkout=0;
mtreset=0;
msreset=1;
if (mthalf) begin
// clk was low long enough, go to next state
mnext=2;
end else begin
mnext=1;
end
end
2 : begin
// initialize mouse phase 2, send command/data to mouse
mrreset=1;
mtreset=0;
if (msready) begin
// command sent
mcmd_inc = 1;
case (mcmd_cnt)
0 : mnext = 4;
1 : mnext = 6;
2 : mnext = 6;
3 : mnext = 6;
4 : mnext = 6;
5 : mnext = 6;
6 : mnext = 6;
7 : mnext = 5;
8 : mnext = 6;
default : mnext = 6;
endcase
end else begin
mnext=2;
end
end
3 : begin
// get first packet byte
mtreset=1;
if (mrready) begin
// we got our first packet byte
mpacket=1;
mrreset=1;
mnext=4;
end else begin
// we are still waiting
mnext=3;
end
end
4 : begin
// get second packet byte
mtreset=1;
if (mrready) begin
// we got our second packet byte
mpacket=2;
mrreset=1;
mnext=5;
end else begin
// we are still waiting
mnext=4;
end
end
5 : begin
// get third packet byte
mtreset=1;
if (mrready) begin
// we got our third packet byte
mpacket=3;
mrreset=1;
mnext = (intellimouse || !mcmd_done) ? 6 : 3;
end else begin
// we are still waiting
mnext=5;
end
end
6 : begin
// get fourth packet byte
mtreset=1;
if (mrready) begin
// we got our fourth packet byte
mpacket = (mcmd_cnt == 8) ? 5 : 4;
mrreset=1;
mnext = !mcmd_done ? 0 : 3;
end else begin
// we are still waiting
mnext=6;
end
end
default : begin
//we should never come here
mclkout=1'bx;
mrreset=1'bx;
mtreset=1'bx;
msreset=1'bx;
mpacket=3'bxxx;
mnext=0;
end
endcase
end
endmodule

View File

@@ -0,0 +1,84 @@
-- Asymmetrical Button Debounce
-- Copyright 2020 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
-- Allow an immediate transtion to the not initial state but the input must
-- hold the initial state for the time to transition back to the initial state.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity asymmetrical_debounce is
generic
(
INITIAL_STATE : std_logic := '0';
COUNTER_SIZE : positive := 4
);
port
(
clk_i : in std_logic;
clk_en_i : in std_logic;
reset_i : in std_logic;
button_i : in std_logic;
button_o : out std_logic
);
end entity;
architecture rtl of asymmetrical_debounce is
signal counter : std_logic_vector(COUNTER_SIZE downto 0) := (others => '0');
signal button_db : std_logic := INITIAL_STATE;
begin
-- counter
process (clk_i)
begin
if rising_edge(clk_i) then
if reset_i = '1' or button_i /= INITIAL_STATE or button_db = INITIAL_STATE then
counter <= (others => '0');
elsif clk_en_i = '1' and counter(COUNTER_SIZE) = '0' then
counter <= counter + 1;
end if;
end if;
end process;
-- output
process (clk_i)
begin
if rising_edge(clk_i) then
if reset_i = '1' then
button_db <= INITIAL_STATE;
else
if button_db = INITIAL_STATE then
button_db <= button_i;
elsif counter(COUNTER_SIZE) = '1' then
button_db <= INITIAL_STATE;
end if;
end if;
end if;
end process;
button_o <= button_db;
end architecture;

87
rtl/misc/debounce.vhd Normal file
View File

@@ -0,0 +1,87 @@
-- Button Debounce
-- Copyright 2020 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity debounce is
generic
(
INITIAL_STATE : std_logic := '0';
COUNTER_SIZE : positive := 4
);
port
(
clk_i : in std_logic;
clk_en_i : in std_logic;
button_i : in std_logic;
button_o : out std_logic
);
end entity;
architecture rtl of debounce is
signal button : std_logic_vector(1 downto 0) := "10";
signal button_noise : std_logic;
signal counter : std_logic_vector(COUNTER_SIZE downto 0) := (others => '0');
signal button_db : std_logic := INITIAL_STATE;
begin
-- button
process (clk_i)
begin
if rising_edge(clk_i) then
button <= button(0) & button_i;
end if;
end process;
button_noise <= button(0) xor button(1);
-- counter
process (clk_i)
begin
if rising_edge(clk_i) then
if button_noise = '1' then
counter <= (others => '0');
elsif clk_en_i = '1' and counter(COUNTER_SIZE) = '0' then
counter <= counter + 1;
end if;
end if;
end process;
-- output
process (clk_i)
begin
if rising_edge(clk_i) then
if counter(COUNTER_SIZE) = '1' then
button_db <= button(1);
end if;
end if;
end process;
button_o <= button_db;
end architecture;

182
rtl/misc/flashboot.vhd Normal file
View File

@@ -0,0 +1,182 @@
-- Flashboot
-- Copyright 2020 Fabio Belavenuto and Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
library UNISIM;
use UNISIM.VComponents.all;
entity flashboot is
port
(
i_CLK : in std_logic;
i_reset : in std_logic;
i_start : in std_logic;
i_coreid : in std_logic_vector(4 downto 0);
i_failid : in std_logic_vector(4 downto 0)
);
end entity;
architecture rtl of flashboot is
-- icap program
type command_list_t is array(0 to 13) of std_logic_vector(17 downto 0);
constant command_list : command_list_t := (
"11" & X"FFFF", -- dummy word (looped, inactive)
"00" & X"AA99", -- sync word
"00" & X"5566", -- sync word
"00" & X"30A1", -- type 1 write one word to CMD
"00" & X"0000", -- null
-- "00" & X"31E1", -- type 1 write one word to CWDT
-- "00" & X"FFFF", -- wait 64K cycles for sync
"00" & X"3261", -- type 1 write one word to GENERAL_1
"10" & X"0000", -- multiboot start address 15:0
"00" & X"3281", -- type 1 write one word to GENERAL_2
"10" & X"0001", -- multiboot opcode and start address 23:16
-- "00" & X"32A1", -- type 1 write one word to GENERAL_3
-- "10" & X"0002", -- multiboot fallback start address 15:0
-- "00" & X"32C1", -- type 1 write one word to GENERAL_4
-- "10" & X"0003", -- multiboot fallback opcode and start address 23:16
-- "00" & X"30A1", -- type 1 write one word to CMD
-- "00" & X"0000", -- null
"00" & X"3301", -- type 1 write one word to MODE
"00" & X"3100", -- bitstream spi x 4
-- "00" & X"3201", -- type 1 write one word to HC_OPT_REG
-- "00" & X"001F", -- do not skip initialization
"00" & X"30A1", -- type 1 write one word to CMD
"00" & X"000E", -- IPROG
"00" & X"2000" -- type 1 nop (looped)
);
-- ^ ce_n,wr_n = 10 indicates data comes from source other than command 15:0
signal command_res : std_logic_vector(15 downto 0);
signal swizzle : std_logic_vector(15 downto 0);
signal coreid : std_logic_vector(4 downto 0);
signal spi_address : std_logic_vector(31 downto 0);
type state_t is (S_0, S_1, S_LOAD);
signal state : state_t := S_0;
signal state_next : state_t;
signal ip : std_logic_vector(3 downto 0) := (others => '0'); -- command_list'length
signal command : std_logic_vector(17 downto 0);
begin
-- ICAP Configuration Functions
icap: ICAP_SPARTAN6
port map
(
CLK => i_CLK, -- input clock < 20 MHz
CE => command(17) and command(16), -- active low select
WRITE => command(16), -- 0 = write, 1 = read
I => swizzle -- 16-bit input
);
process (command, spi_address)
begin
case command(17 downto 16) is
when "10" =>
if command(0) = '0' then
command_res <= spi_address(15 downto 0);
else
command_res <= spi_address(31 downto 16);
end if;
when others =>
command_res <= command(15 downto 0);
end case;
end process;
process (command_res)
begin
for I in 0 to 7 loop
swizzle(I) <= command_res(7-I);
swizzle(I+8) <= command_res(7-I+8);
end loop;
end process;
-- SPI Offsets
-- coreid <= i_coreid when command(1) = '0' else i_failid;
coreid <= i_coreid;
spi_address <= X"6B" & coreid & "000" & X"0000"; -- core images every 512K
-- spi_address <= X"0B" & coreid & "000" & X"0000"; -- core images every 512K
-- State Machine
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
state <= S_0;
else
state <= state_next;
end if;
end if;
end process;
process (state, i_start)
begin
case state is
when S_0 =>
if i_start = '0' then
state_next <= S_1;
else
state_next <= S_0;
end if;
when S_1 =>
if i_start = '1' then
state_next <= S_LOAD;
else
state_next <= S_1;
end if;
when S_LOAD =>
state_next <= S_LOAD;
when others =>
state_next <= S_0;
end case;
end process;
-- instruction pointer
process (i_CLK)
begin
if rising_edge(i_CLK) then
if (state /= S_LOAD) then
ip <= (others => '0');
elsif ip /= (command_list'length - 1) then
ip <= ip + 1;
end if;
end if;
end process;
command <= command_list(to_integer(unsigned(ip))); -- ce_n, wr_n, command
end architecture;

228
rtl/misc/flashboot_old.vhd Normal file
View File

@@ -0,0 +1,228 @@
-- Flashboot
-- Copyright 2020 Fabio Belavenuto
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library UNISIM;
use UNISIM.VComponents.all;
entity flashboot is
port(
reset_i : in std_logic;
clock_i : in std_logic;
start_i : in std_logic;
spiaddr_i : in std_logic_vector(31 downto 0)
);
end entity;
architecture Behavioral of flashboot is
----------------------------------------------------------------------------
-- ICAP configuration data codes
----------------------------------------------------------------------------
-- For custom data codes like the ones for reading back, take a look to:
-- [OPCODES] UG380 page 88 table 5-23
-- [CFG PACKETS] UG380 page 89 tables 5-{24, 25}
-- [CG REGISTERS] UG380 page 90 table 5-30
----------------------------------------------------------------------------
constant DUMMY_C : std_logic_vector(15 downto 0) := X"FFFF"; --
constant NOOP_C : std_logic_vector(15 downto 0) := X"2000"; --
constant NULL1_C : std_logic_vector(15 downto 0) := X"0000"; --
constant NULL2_C : std_logic_vector(15 downto 0) := X"1111"; --
constant SYNCH_C : std_logic_vector(15 downto 0) := X"AA99"; --
constant SYNCL_C : std_logic_vector(15 downto 0) := X"5566"; --
constant CMD_WR_GEN1_C : std_logic_vector(15 downto 0) := X"3261"; --
constant CMD_WR_GEN2_C : std_logic_vector(15 downto 0) := X"3281"; --
constant CMD_WR_CMD_C : std_logic_vector(15 downto 0) := X"30A1"; --
constant CMD_WR_MOD_C : std_logic_vector(15 downto 0) := X"3301"; --
constant CMD_IPROG_C : std_logic_vector(15 downto 0) := X"000E"; --
constant BIT4X_C : std_logic_vector(15 downto 0) := X"3100"; --
type states_t is (IDLE, SYNC_H, SYNC_L, GEN1_H, GEN1_L, GEN2_H, GEN2_L, NUL_H,
NUL_L, MOD_H, MOD_L, RBT_H, RBT_L, NOOP_0, NOOP_1, NOOP_2, NOOP_3);
signal state_s : states_t;
signal next_state_s : states_t;
signal icap_ce_r_s : std_logic;
signal icap_wr_r_s : std_logic;
signal icap_ce_s : std_logic;
signal icap_wr_s : std_logic;
signal icap_i_r_s : std_logic_vector(15 downto 0);
signal icap_i_s : std_logic_vector(15 downto 0);
-- signal spi_addr_s : std_logic_vector(31 downto 0) := X"6B000000"; -- 0B = Fast Read, 3B = Dual Fast Read, 6B = Quad Fast Read
begin
ICAP_SPARTAN6_inst : ICAP_SPARTAN6
port map (
CLK => clock_i, -- 1-bit input: Clock input
CE => icap_ce_s, -- 1-bit input: Active-Low ICAP Enable input
I => icap_i_s, -- 16-bit input: Configuration data input bus
WRITE => icap_wr_s -- 1-bit input: Read/Write control input
);
-- assign values
process(clock_i)
begin
if rising_edge(clock_i) then
-- First we order the bits according to UG380 Table2-5 page 37, as specified in page 126
icap_i_s(0) <= icap_i_r_s(7);
icap_i_s(1) <= icap_i_r_s(6);
icap_i_s(2) <= icap_i_r_s(5);
icap_i_s(3) <= icap_i_r_s(4);
icap_i_s(4) <= icap_i_r_s(3);
icap_i_s(5) <= icap_i_r_s(2);
icap_i_s(6) <= icap_i_r_s(1);
icap_i_s(7) <= icap_i_r_s(0);
icap_i_s(8) <= icap_i_r_s(15);
icap_i_s(9) <= icap_i_r_s(14);
icap_i_s(10) <= icap_i_r_s(13);
icap_i_s(11) <= icap_i_r_s(12);
icap_i_s(12) <= icap_i_r_s(11);
icap_i_s(13) <= icap_i_r_s(10);
icap_i_s(14) <= icap_i_r_s(9);
icap_i_s(15) <= icap_i_r_s(8);
icap_wr_s <= icap_wr_r_s;
icap_ce_s <= icap_ce_r_s;
end if;
end process;
-- next state
process(clock_i)
begin
if rising_edge(clock_i) then
if reset_i = '1' then
state_s <= IDLE;
else
state_s <= next_state_s;
end if;
end if;
end process;
-- FSM
process (state_s, start_i, spiaddr_i)
begin
case state_s is
when IDLE =>
if start_i = '1' then
next_state_s <= SYNC_H;
icap_ce_r_s <= '0';
icap_wr_r_s <= '0';
icap_i_r_s <= SYNCH_C;
else
next_state_s <= IDLE;
icap_ce_r_s <= '1';
icap_wr_r_s <= '1';
icap_i_r_s <= DUMMY_C;
end if;
when SYNC_H =>
next_state_s <= SYNC_L;
icap_ce_r_s <= '0';
icap_wr_r_s <= '0';
icap_i_r_s <= SYNCL_C;
when SYNC_L =>
next_state_s <= NUL_H;
icap_ce_r_s <= '0';
icap_wr_r_s <= '0';
icap_i_r_s <= CMD_WR_CMD_C;
when NUL_H =>
next_state_s <= GEN1_H;
icap_ce_r_s <= '0';
icap_wr_r_s <= '0';
icap_i_r_s <= NULL1_C;
when GEN1_H =>
next_state_s <= GEN1_L;
icap_ce_r_s <= '0';
icap_wr_r_s <= '0';
icap_i_r_s <= CMD_WR_GEN1_C;
when GEN1_L =>
next_state_s <= GEN2_H;
icap_ce_r_s <= '0';
icap_wr_r_s <= '0';
icap_i_r_s <= spiaddr_i(15 downto 0);
when GEN2_H =>
next_state_s <= GEN2_L;
icap_ce_r_s <= '0';
icap_wr_r_s <= '0';
icap_i_r_s <= CMD_WR_GEN2_C;
when GEN2_L =>
next_state_s <= MOD_H;
icap_ce_r_s <= '0';
icap_wr_r_s <= '0';
icap_i_r_s <= spiaddr_i(31 downto 16);
when MOD_H =>
next_state_s <= MOD_L;
icap_ce_r_s <= '0';
icap_wr_r_s <= '0';
icap_i_r_s <= CMD_WR_MOD_C;
when MOD_L =>
next_state_s <= NUL_L;
icap_ce_r_s <= '0';
icap_wr_r_s <= '0';
icap_i_r_s <= BIT4X_C;
when NUL_L =>
next_state_s <= RBT_H;
icap_ce_r_s <= '0';
icap_wr_r_s <= '0';
icap_i_r_s <= CMD_WR_CMD_C;
when RBT_H =>
next_state_s <= RBT_L;
icap_ce_r_s <= '0';
icap_wr_r_s <= '0';
icap_i_r_s <= CMD_IPROG_C;
when RBT_L =>
next_state_s <= NOOP_0;
icap_ce_r_s <= '0';
icap_wr_r_s <= '0';
icap_i_r_s <= NOOP_C;
when NOOP_0 =>
next_state_s <= NOOP_1;
icap_ce_r_s <= '0';
icap_wr_r_s <= '0';
icap_i_r_s <= NOOP_C;
when NOOP_1 =>
next_state_s <= NOOP_2;
icap_ce_r_s <= '0';
icap_wr_r_s <= '0';
icap_i_r_s <= NOOP_C;
when NOOP_2 =>
next_state_s <= NOOP_3;
icap_ce_r_s <= '0';
icap_wr_r_s <= '0';
icap_i_r_s <= NOOP_C;
when NOOP_3 =>
next_state_s <= IDLE;
icap_ce_r_s <= '0';
icap_wr_r_s <= '0';
icap_i_r_s <= NULL2_C;
when others =>
next_state_s <= IDLE;
icap_ce_r_s <= '1';
icap_wr_r_s <= '1';
icap_i_r_s <= NULL2_C;
end case;
end process;
end architecture;

55
rtl/misc/synchronize.vhd Normal file
View File

@@ -0,0 +1,55 @@
-- Async Input Synchronization
-- Copyright 2020 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity synchronize is
port
(
i_CLK : in std_logic;
i_signal : in std_logic;
o_signal : out std_logic
);
end entity;
architecture rtl of synchronize is
signal sig : std_logic;
begin
process (i_CLK)
begin
if falling_edge(i_CLK) then
sig <= i_signal;
end if;
end process;
process (i_CLK)
begin
if rising_edge(i_CLK) then
o_signal <= sig;
end if;
end process;
end architecture;

496
rtl/mister/bram.vhd Normal file
View File

@@ -0,0 +1,496 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity keyjoy_sdpram_64_6 is
port
(
DPRA : in std_logic_vector(5 downto 0);
DPO : out std_logic_vector(5 downto 0);
CLK : in std_logic;
WE : in std_logic;
A : in std_logic_vector(5 downto 0);
D : in std_logic_vector(5 downto 0)
);
end entity;
architecture rtl of keyjoy_sdpram_64_6 is
begin
ram: work.dpram
generic map
(
addr_width_a => 6,
data_width_a => 6,
addr_width_b => 6,
data_width_b => 6,
mem_init_file => "rtl/mister/keyjoy_sdpram_64_6.mif"
)
port map
(
clock0 => CLK,
address_a => DPRA,
q_a => DPO,
clock1 => CLK,
wren_b => WE,
address_b => A,
data_b => D
);
end rtl;
------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity sdpram_128_8 is
port
(
DPRA : in std_logic_vector(6 downto 0);
DPO : out std_logic_vector(7 downto 0);
CLK : in std_logic;
WE : in std_logic;
A : in std_logic_vector(6 downto 0);
D : in std_logic_vector(7 downto 0)
);
end entity;
architecture rtl of sdpram_128_8 is
begin
ram : work.mlab
generic map
(
addr_width => 7,
data_width => 8
)
port map
(
clk => CLK,
rdaddress => DPRA,
q => DPO,
wraddress => A,
data => D,
wren => WE
);
end rtl;
------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity spram_320_9 is
port
(
CLK : in std_logic;
WE : in std_logic;
SPO : out std_logic_vector(8 downto 0);
A : in std_logic_vector(8 downto 0);
D : in std_logic_vector(8 downto 0)
);
end entity;
architecture rtl of spram_320_9 is
begin
ram : work.mlab
generic map
(
addr_width => 9,
data_width => 9
)
port map
(
clk => CLK,
rdaddress => A,
q => SPO,
wraddress => A,
data => D,
wren => WE
);
end rtl;
------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity sdpbram_16k_8 is
port
(
WEA : in std_logic;
ADDRA : in std_logic_vector(13 downto 0);
DINA : in std_logic_vector(7 downto 0);
CLKA : in std_logic;
--
ENB : in std_logic;
ADDRB : in std_logic_vector(13 downto 0);
DOUTB : out std_logic_vector(7 downto 0);
CLKB : in std_logic
);
end entity;
architecture rtl of sdpbram_16k_8 is
begin
ram: work.dpram
generic map (
addr_width_a => 14,
data_width_a => 8,
addr_width_b => 14,
data_width_b => 8
)
port map
(
clock0 => CLKA,
clock1 => CLKB,
address_a => ADDRA,
data_a => DINA,
wren_a => WEA,
address_b => ADDRB,
q_b => DOUTB
);
end rtl;
------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity sdpram_16_9 is
port
(
DPRA : in std_logic_vector(3 downto 0);
DPO : out std_logic_vector(8 downto 0);
CLK : in std_logic;
WE : in std_logic;
A : in std_logic_vector(3 downto 0);
D : in std_logic_vector(8 downto 0)
);
end entity;
architecture rtl of sdpram_16_9 is
begin
ram : work.mlab
generic map
(
addr_width => 4,
data_width => 9
)
port map
(
clk => CLK,
rdaddress => DPRA,
q => DPO,
wraddress => A,
data => D,
wren => WE
);
end rtl;
------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity sdpram_64_9 is
port
(
DPRA : IN STD_LOGIC_VECTOR(5 downto 0);
CLK : IN STD_LOGIC;
WE : IN STD_LOGIC;
DPO : OUT STD_LOGIC_VECTOR(8 downto 0);
A : IN STD_LOGIC_VECTOR(5 downto 0);
D : IN STD_LOGIC_VECTOR(8 downto 0)
);
end entity;
architecture rtl of sdpram_64_9 is
begin
ram : work.mlab
generic map
(
addr_width => 6,
data_width => 9
)
port map
(
clk => CLK,
rdaddress => DPRA,
q => DPO,
wraddress => A,
data => D,
wren => WE
);
end rtl;
------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity tdpram is
generic (
addr_width_g : integer := 8;
data_width_g : integer := 8
);
port (
clk_a_i : in std_logic;
we_a_i : in std_logic;
addr_a_i : in std_logic_vector(addr_width_g-1 downto 0);
data_a_i : in std_logic_vector(data_width_g-1 downto 0);
data_a_o : out std_logic_vector(data_width_g-1 downto 0);
--
clk_b_i : in std_logic;
we_b_i : in std_logic;
addr_b_i : in std_logic_vector(addr_width_g-1 downto 0);
data_b_i : in std_logic_vector(data_width_g-1 downto 0);
data_b_o : out std_logic_vector(data_width_g-1 downto 0)
);
end entity;
architecture rtl of tdpram is
begin
ram: work.dpram
generic map (
addr_width_a => addr_width_g,
data_width_a => data_width_g,
addr_width_b => addr_width_g,
data_width_b => data_width_g
)
port map
(
clock0 => clk_a_i,
clock1 => clk_b_i,
address_a => addr_a_i,
data_a => data_a_i,
wren_a => we_a_i,
q_a => data_a_o,
address_b => addr_b_i,
data_b => data_b_i,
wren_b => we_b_i,
q_b => data_b_o
);
end architecture;
------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity dpram2 is
generic (
addr_width_g : integer := 8;
data_width_g : integer := 8;
init_file_g : string := " "
);
port (
clk_a_i : in std_logic;
we_i : in std_logic;
addr_a_i : in std_logic_vector(addr_width_g-1 downto 0);
data_a_i : in std_logic_vector(data_width_g-1 downto 0);
data_a_o : out std_logic_vector(data_width_g-1 downto 0);
--
clk_b_i : in std_logic;
addr_b_i : in std_logic_vector(addr_width_g-1 downto 0);
data_b_o : out std_logic_vector(data_width_g-1 downto 0)
);
end entity;
architecture rtl of dpram2 is
begin
ram: work.dpram
generic map (
addr_width_a => addr_width_g,
data_width_a => data_width_g,
addr_width_b => addr_width_g,
data_width_b => data_width_g,
mem_init_file => init_file_g
)
port map
(
clock0 => clk_a_i,
clock1 => clk_b_i,
address_a => addr_a_i,
data_a => data_a_i,
wren_a => we_i,
q_a => data_a_o,
address_b => addr_b_i,
q_b => data_b_o
);
end rtl;
----------------------
-- Dual port Block RAM different parameters and clocks on ports
--------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.all;
LIBRARY altera_mf;
USE altera_mf.altera_mf_components.all;
entity dpram is
generic (
addr_width_a : integer := 8;
data_width_a : integer := 8;
addr_width_b : integer := 8;
data_width_b : integer := 8;
mem_init_file : string := " "
);
PORT
(
clock0 : in STD_LOGIC;
clock1 : in STD_LOGIC;
address_a : in STD_LOGIC_VECTOR (addr_width_a-1 DOWNTO 0);
data_a : in STD_LOGIC_VECTOR (data_width_a-1 DOWNTO 0) := (others => '0');
enable_a : in STD_LOGIC := '1';
wren_a : in STD_LOGIC := '0';
q_a : out STD_LOGIC_VECTOR (data_width_a-1 DOWNTO 0);
cs_a : in std_logic := '1';
address_b : in STD_LOGIC_VECTOR (addr_width_b-1 DOWNTO 0) := (others => '0');
data_b : in STD_LOGIC_VECTOR (data_width_b-1 DOWNTO 0) := (others => '0');
enable_b : in STD_LOGIC := '1';
wren_b : in STD_LOGIC := '0';
q_b : out STD_LOGIC_VECTOR (data_width_b-1 DOWNTO 0);
cs_b : in std_logic := '1'
);
end entity;
ARCHITECTURE SYN OF dpram IS
signal q0 : std_logic_vector((data_width_a - 1) downto 0);
signal q1 : std_logic_vector((data_width_b - 1) downto 0);
BEGIN
q_a<= q0 when cs_a = '1' else (others => '1');
q_b<= q1 when cs_b = '1' else (others => '1');
altsyncram_component : altsyncram
GENERIC MAP (
address_reg_b => "CLOCK1",
clock_enable_input_a => "NORMAL",
clock_enable_input_b => "NORMAL",
clock_enable_output_a => "BYPASS",
clock_enable_output_b => "BYPASS",
indata_reg_b => "CLOCK1",
intended_device_family => "Cyclone V",
lpm_type => "altsyncram",
numwords_a => 2**addr_width_a,
numwords_b => 2**addr_width_b,
operation_mode => "BIDIR_DUAL_PORT",
outdata_aclr_a => "NONE",
outdata_aclr_b => "NONE",
outdata_reg_a => "UNREGISTERED",
outdata_reg_b => "UNREGISTERED",
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",
init_file => mem_init_file,
widthad_a => addr_width_a,
widthad_b => addr_width_b,
width_a => data_width_a,
width_b => data_width_b,
width_byteena_a => 1,
width_byteena_b => 1,
wrcontrol_wraddress_reg_b => "CLOCK1"
)
PORT MAP (
address_a => address_a,
address_b => address_b,
clock0 => clock0,
clock1 => clock1,
clocken0 => enable_a,
clocken1 => enable_b,
data_a => data_a,
data_b => data_b,
wren_a => wren_a and cs_a,
wren_b => wren_b and cs_b,
q_a => q0,
q_b => q1
);
END SYN;
------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity mlab is
generic (
addr_width : integer := 8;
data_width : integer := 8
);
port
(
clk : in std_logic;
rdaddress : in std_logic_vector(addr_width-1 downto 0);
q : out std_logic_vector(data_width-1 downto 0);
wraddress : in std_logic_vector(addr_width-1 downto 0);
data : in std_logic_vector(data_width-1 downto 0);
wren : in std_logic
);
end entity;
LIBRARY altera_mf;
USE altera_mf.altera_mf_components.all;
architecture rtl of mlab is
begin
altdpram_component : altdpram
GENERIC MAP (
indata_aclr => "OFF",
indata_reg => "INCLOCK",
intended_device_family => "Cyclone V",
lpm_type => "altdpram",
outdata_aclr => "OFF",
outdata_reg => "UNREGISTERED",
ram_block_type => "MLAB",
rdaddress_aclr => "OFF",
rdaddress_reg => "UNREGISTERED",
rdcontrol_aclr => "OFF",
rdcontrol_reg => "UNREGISTERED",
width => data_width,
widthad => addr_width,
width_byteena => 1,
wraddress_aclr => "OFF",
wraddress_reg => "INCLOCK",
wrcontrol_aclr => "OFF",
wrcontrol_reg => "INCLOCK"
)
PORT MAP (
data => data,
inclock => clk,
rdaddress => rdaddress,
wraddress => wraddress,
wren => wren,
q => q
);
end rtl;

View File

@@ -0,0 +1,16 @@
DEPTH = 64;
WIDTH = 6;
ADDRESS_RADIX = UNS;
DATA_RADIX = BIN;
CONTENT BEGIN
0: 100011 100100 100010 100001 100000 011001 011000 011010;
8: 011011 011100 100010 011100 100100 100011 100000 111111;
16: 000111 000111 000111 000111 000111 000111 000111 000111;
24: 000111 000111 000111 000111 000111 000111 000111 000111;
32: 100011 100100 100010 100001 100000 011001 011000 011010;
40: 011011 011100 100010 011100 100100 100011 100000 111111;
48: 000111 000111 000111 000111 000111 000111 000111 000111;
56: 000111 000111 000111 000111 000111 000111 000111 000111;
END;

208
rtl/mister/ps2_keyb.vhd Normal file
View File

@@ -0,0 +1,208 @@
-- PS2 Keyboard
-- Copyright 2020 Fabio Belavenuto
-- Copyright 2021 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
-- ps2 button state is represented in an 8x7 matrix
-- when the physical membrane is scanned, the ps2 inserts column data
-- caps + sym shift presses are counted; shifts are not lost in multiple keys
-- typematic filtered so that shift counts remain accurate
-- F11 = multiface nmi button, F12 = divmmc nmi button
-- function keys work as on membrane: F11 + number
-- pause/break resets the ps2 matrix state
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity ps2_keyb is
port
(
i_CLK : in std_logic;
i_reset : in std_logic;
-- ps2 interface
ps2_key : in std_logic_vector(10 downto 0);
-- membrane interaction
i_membrane_row : in std_logic_vector(2 downto 0);
o_membrane_col : out std_logic_vector(6 downto 0);
-- programmable keymap
i_keymap_addr : in std_logic_vector(8 downto 0);
i_keymap_data : in std_logic_vector(7 downto 0);
i_keymap_we : in std_logic;
fn : out std_logic_vector(11 downto 1)
);
end entity;
architecture rtl of ps2_keyb is
signal capshift_count_zero : std_logic;
signal capshift_count : std_logic_vector(2 downto 0);
signal symshift_count_zero : std_logic;
signal symshift_count : std_logic_vector(2 downto 0);
type key_matrix_t is array (7 downto 0) of std_logic_vector(6 downto 0);
signal matrix_state : key_matrix_t := ((others => (others => '1')));
signal row_0_n : std_logic;
signal row_7_n : std_logic;
signal ps2_keymap_data : std_logic_vector(8 downto 0);
signal ps2_current_keycode : std_logic_vector(9 downto 0);
signal ps2_key_valid : std_logic;
signal ps2_matrix_reset : std_logic;
signal ps2_stb1, ps2_stb2 : std_logic;
signal ps2_receive_data : std_logic_vector(7 downto 0);
signal ps2_key_extend : std_logic;
signal ps2_key_release : std_logic;
begin
process (i_CLK)
begin
if rising_edge(i_CLK) then
ps2_stb1 <= ps2_key(10);
ps2_stb2 <= ps2_stb1;
ps2_key_valid <= ps2_stb2 xor ps2_stb1;
end if;
end process;
ps2_key_release <= not ps2_key(9);
ps2_key_extend <= ps2_key(8);
ps2_receive_data <= ps2_key(7 downto 0);
ps2_current_keycode <= ps2_key_release & ps2_key_extend & ps2_receive_data;
ps2_matrix_reset <= '1' when ps2_key_valid = '1' and ps2_key_extend = '1' and ps2_receive_data = X"77" else '0';
-- F1..F11
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or ps2_matrix_reset = '1' then
fn <= (others => '0');
elsif ps2_key_valid = '1' and ps2_key_extend = '0' then
if ps2_receive_data = X"05" then -- F1
fn(1) <= not ps2_key_release;
elsif ps2_receive_data = X"06" then -- F2
fn(2) <= not ps2_key_release;
elsif ps2_receive_data = X"04" then -- F3
fn(3) <= not ps2_key_release;
elsif ps2_receive_data = X"0C" then -- F4
fn(4) <= not ps2_key_release;
elsif ps2_receive_data = X"03" then -- F5
fn(5) <= not ps2_key_release;
elsif ps2_receive_data = X"0B" then -- F6
fn(6) <= not ps2_key_release;
elsif ps2_receive_data = X"83" then -- F7
fn(7) <= not ps2_key_release;
elsif ps2_receive_data = X"0A" then -- F8
fn(8) <= not ps2_key_release;
elsif ps2_receive_data = X"01" then -- F9
fn(9) <= not ps2_key_release;
elsif ps2_receive_data = X"09" then -- F10
fn(10) <= not ps2_key_release;
elsif ps2_receive_data = X"78" then -- F11
fn(11) <= not ps2_key_release;
end if;
end if;
end if;
end process;
-- matrix representation
capshift_count_zero <= '1' when capshift_count = std_logic_vector(to_unsigned(0,capshift_count'length)) else '0';
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or ps2_matrix_reset = '1' then
capshift_count <= (others => '0');
elsif ps2_key_valid = '1' and ps2_keymap_data(6) = '1' then
if ps2_key_release = '0' then
capshift_count <= capshift_count + 1;
elsif capshift_count_zero = '0' then
capshift_count <= capshift_count - 1;
end if;
end if;
end if;
end process;
symshift_count_zero <= '1' when symshift_count = std_logic_vector(to_unsigned(0,symshift_count'length)) else '0';
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or ps2_matrix_reset = '1' then
symshift_count <= (others => '0');
elsif ps2_key_valid = '1' and ps2_keymap_data(7) = '1' then
if ps2_key_release = '0' then
symshift_count <= symshift_count + 1;
elsif symshift_count_zero = '0' then
symshift_count <= symshift_count - 1;
end if;
end if;
end if;
end process;
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or ps2_matrix_reset = '1' then
matrix_state <= ((others => (others => '1')));
elsif ps2_key_valid = '1' and ps2_keymap_data(2 downto 0) /= "111" then
matrix_state(to_integer(unsigned(ps2_keymap_data(5 downto 3))))(to_integer(unsigned(ps2_keymap_data(2 downto 0)))) <= ps2_key_release;
end if;
end if;
end process;
-- membrane scan
row_0_n <= '0' when i_membrane_row = "000" else '1';
row_7_n <= '0' when i_membrane_row = "111" else '1';
o_membrane_col <= (matrix_state(to_integer(unsigned(i_membrane_row)))(6 downto 2)) &
(matrix_state(to_integer(unsigned(i_membrane_row)))(1) and (row_7_n or symshift_count_zero)) &
(matrix_state(to_integer(unsigned(i_membrane_row)))(0) and (row_0_n or capshift_count_zero));
-- ps2 keymap
keymap: entity work.keymaps
port map
(
clock_i => i_CLK,
addr_wr_i => i_keymap_addr,
data_i => '0' & i_keymap_data,
we_i => i_keymap_we,
--
addr_rd_i => ps2_key_extend & ps2_receive_data,
data_o => ps2_keymap_data
);
end architecture;

244
rtl/mister/sdram.sv Normal file
View File

@@ -0,0 +1,244 @@
//============================================================================
//
// SDRAM controller
// Copyright (C) 2021 Alexey Melnikov
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
//============================================================================
module sdram
(
input clk,
input init,
output reg [12:0] SDRAM_A,
inout reg [15:0] SDRAM_DQ,
output reg [1:0] SDRAM_BA,
output reg SDRAM_DQML,
output reg SDRAM_DQMH,
output reg SDRAM_nWE,
output reg SDRAM_nCAS,
output reg SDRAM_nRAS,
output SDRAM_nCS,
output SDRAM_CKE,
output SDRAM_CLK,
input [20:0] RAM_A_ADDR,
input RAM_A_REQ,
input RAM_A_RD_n,
input [7:0] RAM_A_DI,
output reg [7:0] RAM_A_DO,
output reg RAM_A_WAIT,
input [20:0] RAM_B_ADDR,
input RAM_B_REQ,
output reg [7:0] RAM_B_DO
);
assign SDRAM_nCS = 0;
assign SDRAM_CKE = 1;
assign {SDRAM_DQMH,SDRAM_DQML} = SDRAM_A[12:11];
localparam RASCAS_DELAY = 3'd2; // tRCD=20ns -> 2 cycles@85MHz
localparam BURST_LENGTH = 3'd0; // 0=1, 1=2, 2=4, 3=8, 7=full page
localparam ACCESS_TYPE = 1'd0; // 0=sequential, 1=interleaved
localparam CAS_LATENCY = 3'd2; // 2/3 allowed
localparam OP_MODE = 2'd0; // only 0 (standard operation) allowed
localparam NO_WRITE_BURST = 1'd1; // 0=write burst enabled, 1=only single access write
localparam MODE = { 3'b000, NO_WRITE_BURST, OP_MODE, CAS_LATENCY, ACCESS_TYPE, BURST_LENGTH};
localparam STATE_IDLE = 3'd0; // state to check the requests
localparam STATE_START = STATE_IDLE+1'd1; // state in which a new command is started
localparam STATE_CONT = STATE_START+RASCAS_DELAY;
localparam STATE_READY = STATE_CONT+CAS_LATENCY+2'd2;
localparam STATE_LAST = STATE_READY; // last state in cycle
reg [2:0] state;
reg [22:0] a;
reg [1:0] bank;
reg [15:0] data;
reg we;
reg ram_req=0;
// access manager
always @(posedge clk) begin
reg old_ref;
reg old_req;
reg [20:1] last_a[2] = '{'1,'1};
reg [15:0] last_data[2];
reg [15:0] data_reg;
reg ch0_busy;
reg ch1_busy;
reg [8:0] rfsh_cnt;
data_reg <= SDRAM_DQ;
if(RAM_A_REQ) RAM_A_WAIT <= 1;
if(~&rfsh_cnt) rfsh_cnt <= rfsh_cnt + 1'd1;
if((old_req ^ RAM_B_REQ) && (last_a[1] == RAM_B_ADDR[20:1])) begin
old_req <= RAM_B_REQ;
RAM_B_DO <= RAM_B_ADDR[0] ? last_data[1][15:8] : last_data[1][7:0];
end
if(state == STATE_IDLE && mode == MODE_NORMAL) begin
ram_req <= 0;
we <= 0;
ch0_busy <= 0;
ch1_busy <= 0;
if((old_req ^ RAM_B_REQ) && (last_a[1] != RAM_B_ADDR[20:1])) begin
old_req <= RAM_B_REQ;
{bank,a} <= RAM_B_ADDR;
ram_req <= 1;
last_a[1] <= RAM_B_ADDR[20:1];
ch1_busy <= 1;
state <= STATE_START;
end
else if(RAM_A_REQ | RAM_A_WAIT) begin
we <= RAM_A_RD_n;
{bank,a} <= RAM_A_ADDR;
data <= {RAM_A_DI,RAM_A_DI};
ram_req <= RAM_A_RD_n || (last_a[0] != RAM_A_ADDR[20:1]);
last_a[0] <= RAM_A_RD_n ? '1 : RAM_A_ADDR[20:1];
ch0_busy <= 1;
state <= STATE_START;
end
else if(&rfsh_cnt) begin
state <= STATE_START;
end
end
if(state == STATE_READY) begin
if(~ram_req) rfsh_cnt <= 0;
if(ch0_busy) begin
ch0_busy <= 0;
RAM_A_WAIT <= 0;
if(ram_req) begin
if(we) RAM_A_DO <= data[7:0];
else begin
RAM_A_DO <= a[0] ? data_reg[15:8] : data_reg[7:0];
last_data[0] <= data_reg;
end
end
else RAM_A_DO <= a[0] ? last_data[0][15:8] : last_data[0][7:0];
end
if(ch1_busy) begin
ch1_busy <= 0;
RAM_B_DO <= a[0] ? data_reg[15:8] : data_reg[7:0];
last_data[1] <= data_reg;
end
end
if(mode != MODE_NORMAL || state != STATE_IDLE || reset) begin
state <= state + 1'd1;
if(state == STATE_LAST) state <= STATE_IDLE;
end
end
localparam MODE_NORMAL = 2'b00;
localparam MODE_RESET = 2'b01;
localparam MODE_LDM = 2'b10;
localparam MODE_PRE = 2'b11;
initial reset = 5'h1f;
// initialization
reg [1:0] mode;
reg [4:0] reset=5'h1f;
always @(posedge clk) begin
reg init_old=0;
init_old <= init;
if(init_old & ~init) reset <= 5'h1f;
else if(state == STATE_LAST) begin
if(reset != 0) begin
reset <= reset - 5'd1;
if(reset == 14) mode <= MODE_PRE;
else if(reset == 3) mode <= MODE_LDM;
else mode <= MODE_RESET;
end
else mode <= MODE_NORMAL;
end
end
localparam CMD_NOP = 3'b111;
localparam CMD_ACTIVE = 3'b011;
localparam CMD_READ = 3'b101;
localparam CMD_WRITE = 3'b100;
localparam CMD_BURST_TERMINATE = 3'b110;
localparam CMD_PRECHARGE = 3'b010;
localparam CMD_AUTO_REFRESH = 3'b001;
localparam CMD_LOAD_MODE = 3'b000;
// SDRAM state machines
always @(posedge clk) begin
if(state == STATE_START) SDRAM_BA <= (mode == MODE_NORMAL) ? bank : 2'b00;
SDRAM_DQ <= 'Z;
casex({ram_req,we,mode,state})
{2'b1X, MODE_NORMAL, STATE_START}: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE} <= CMD_ACTIVE;
{2'b11, MODE_NORMAL, STATE_CONT }: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE, SDRAM_DQ} <= {CMD_WRITE, data};
{2'b10, MODE_NORMAL, STATE_CONT }: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE} <= CMD_READ;
{2'b0X, MODE_NORMAL, STATE_START}: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE} <= CMD_AUTO_REFRESH;
// init
{2'bXX, MODE_LDM, STATE_START}: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE} <= CMD_LOAD_MODE;
{2'bXX, MODE_PRE, STATE_START}: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE} <= CMD_PRECHARGE;
default: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE} <= CMD_NOP;
endcase
casex({ram_req,mode,state})
{1'b1, MODE_NORMAL, STATE_START}: SDRAM_A <= a[13:1];
{1'b1, MODE_NORMAL, STATE_CONT }: SDRAM_A <= {we & ~a[0], we & a[0], 2'b10, a[22:14]};
// init
{1'bX, MODE_LDM, STATE_START}: SDRAM_A <= MODE;
{1'bX, MODE_PRE, STATE_START}: SDRAM_A <= 13'b0010000000000;
default: SDRAM_A <= 13'b0000000000000;
endcase
end
altddio_out
#(
.extend_oe_disable("OFF"),
.intended_device_family("Cyclone V"),
.invert_output("OFF"),
.lpm_hint("UNUSED"),
.lpm_type("altddio_out"),
.oe_reg("UNREGISTERED"),
.power_up_high("OFF"),
.width(1)
)
sdramclk_ddr
(
.datain_h(1'b0),
.datain_l(1'b1),
.outclock(clk),
.dataout(SDRAM_CLK),
.aclr(1'b0),
.aset(1'b0),
.oe(1'b1),
.outclocken(1'b1),
.sclr(1'b0),
.sset(1'b0)
);
endmodule

539
rtl/mister/zxnext_top.vhd Normal file
View File

@@ -0,0 +1,539 @@
-- ZX Spectrum Next Issue 2 FPGA Top Level
-- Copyright 2020 Alvin Albrecht and Fabio Belavenuto
--
-- TBBLUE Issue 2 Top - Fabio Belavenuto
-- ZXNext Refactor - Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity zxnext_top is
generic (
g_machine_id : unsigned(7 downto 0) := X"DA"; -- MiSTer
g_version : unsigned(7 downto 0) := X"31"; -- 3.01
g_sub_version : unsigned(7 downto 0) := X"0A" -- .10
);
port (
-- Clocks
CLK_28 : in std_logic;
CLK_14 : in std_logic;
CLK_7 : in std_logic;
HW_RESET : in std_logic;
RAM_A_ADDR : out std_logic_vector(20 downto 0); -- 2MB memory space
RAM_A_REQ : out std_logic; -- '1' indicates memory request on next rising edge
RAM_A_RD_n : out std_logic; -- '0' for read, '1' for write
RAM_A_DI : in std_logic_vector(7 downto 0); -- data read from memory
RAM_A_DO : out std_logic_vector(7 downto 0); -- data written to memory
RAM_A_WAIT : in std_logic := '0';
RAM_B_ADDR : out std_logic_vector(20 downto 0); -- 2MB memory space
RAM_B_REQ : out std_logic; -- toggle indicates memory request
RAM_B_DI : in std_logic_vector(7 downto 0); -- data read from memory
-- PS2
ps2_key : in std_logic_vector(10 downto 0);
ps2_mouse : in std_logic_vector(24 downto 0);
ps2_mouse_ext : in std_logic_vector(7 downto 0);
-- SD Card
sd_cs0_n_o : out std_logic;
sd_cs1_n_o : out std_logic;
sd_sclk_o : out std_logic;
sd_mosi_o : out std_logic;
sd_miso_i : in std_logic := '1';
-- Joystick
joy_left : in std_logic_vector(10 downto 0); -- active high X Z Y START A C B U D L R
joy_right : in std_logic_vector(10 downto 0); -- active high X Z Y START A C B U D L R
-- Audio
audio_L : out std_logic_vector(11 downto 0);
audio_R : out std_logic_vector(11 downto 0);
-- K7
ear_port_i : in std_logic := '1';
mic_port_o : out std_logic;
-- VGA
RGB : out std_logic_vector(8 downto 0); -- RGB333
RGB_VS_n : out std_logic; -- vsync
RGB_HS_n : out std_logic; -- hsync
RGB_VB_n : out std_logic; -- vblank
RGB_HB_n : out std_logic; -- hblank
RGB_NTSC : out std_logic;
-- I2C (RTC)
i2c_scl_o : out std_logic;
i2c_sda_o : out std_logic;
i2c_sda_i : in std_logic := '1';
uart_rx_i : in std_logic;
uart_tx_o : out std_logic
);
end entity;
architecture rtl of zxnext_top is
-- resets
signal zxn_video_mode : std_logic_vector(2 downto 0);
signal actual_video_mode : std_logic_vector(2 downto 0) := "000";
signal reset_counter : std_logic_vector(9 downto 0);
signal reset : std_logic;
signal zxn_reset_hard : std_logic;
signal zxn_reset_soft : std_logic;
-- clocks
signal CLK_i0 : std_logic;
signal CLK_CPU : std_logic;
signal q0 : std_logic;
signal q0_enable : std_logic;
signal q1 : std_logic;
signal q1_enable : std_logic;
signal clk_28_div : std_logic_vector(17 downto 0);
signal CLK_28_PSG_EN : std_logic;
signal CLK_28_JOY_EN : std_logic;
signal CLK_28_MEMBRANE_EN : std_logic;
signal zxn_clock_contend : std_logic;
signal zxn_clock_lsb : std_logic;
signal zxn_cpu_speed : std_logic_vector(1 downto 0);
signal zxn_cpu_speed2 : std_logic_vector(1 downto 0);
-- serial communication
signal zxn_i2c_scl : std_logic;
-- audio
signal zxn_audio_L_pre : std_logic_vector(12 downto 0);
signal zxn_audio_R_pre : std_logic_vector(12 downto 0);
-- buttons, joystick, mouse, keyboard
signal zxn_joy_io_mode_en : std_logic;
signal zxn_joy_io_mode_pin_7 : std_logic;
signal zxn_joy_left_type : std_logic_vector(2 downto 0);
signal zxn_joy_right_type : std_logic_vector(2 downto 0);
signal zxn_mouse_control : std_logic_vector(2 downto 0);
signal zxn_mouse_x : std_logic_vector(7 downto 0);
signal zxn_mouse_y : std_logic_vector(7 downto 0);
signal zxn_mouse_wheel : std_logic_vector(7 downto 0);
signal zxn_mouse_button : std_logic_vector(2 downto 0);
signal zxn_mouse_stb : std_logic;
signal ps2_kbd_col : std_logic_vector(6 downto 0);
signal ps2_kbd_fn : std_logic_vector(11 downto 1);
signal zxn_keymap_addr : std_logic_vector(8 downto 0);
signal zxn_keymap_dat : std_logic_vector(7 downto 0);
signal zxn_keymap_we : std_logic;
signal zxn_joymap_we : std_logic;
signal zxn_key_row : std_logic_vector(7 downto 0);
signal zxn_key_col : std_logic_vector(4 downto 0);
signal zxn_cancel_extended_entries : std_logic;
signal zxn_extended_keys : std_logic_vector(15 downto 0);
signal membrane_index : std_logic_vector(2 downto 0);
signal membrane_stick_col : std_logic_vector(6 downto 0);
function mouse_scale(off : std_logic_vector(7 downto 0); scale : std_logic_vector(1 downto 0)) return std_logic_vector is
begin
-- avoid -1 value if negative off is less than scale
case(scale) is
when "00" =>
return off;
when "01" =>
if off <= X"FE" then
return off(7) & off(7 downto 1);
end if;
when "10" =>
if off <= X"FC" then
return off(7) & off(7) & off(7 downto 2);
end if;
when "11" =>
if off <= X"F8" then
return off(7) & off(7) & off(7) & off(7 downto 3);
end if;
end case;
return (others => '0');
end function;
begin
------------------------------------------------------------
-- RESETS --------------------------------------------------
------------------------------------------------------------
process (CLK_28)
begin
if rising_edge(CLK_28) then
if zxn_video_mode /= actual_video_mode or (zxn_reset_soft or zxn_reset_hard or HW_RESET) = '1' then
actual_video_mode <= zxn_video_mode;
reset_counter <= (others => '1');
reset <= '1';
elsif reset_counter /= "0000000000" then
reset_counter <= reset_counter - 1;
else
reset <= '0';
end if;
end if;
end process;
------------------------------------------------------------
-- CLOCKS --------------------------------------------------
------------------------------------------------------------
-- cpu clock selection
process (CLK_28)
begin
if rising_edge(CLK_28) then
case(zxn_cpu_speed2) is
when "00" =>
if clk_28_div(1 downto 0) = "00" then
if zxn_clock_lsb = '1' and zxn_clock_contend = '0' then
CLK_i0 <= '0';
elsif zxn_clock_lsb = '0' then
CLK_i0 <= '1';
end if;
end if;
when "01" =>
CLK_i0 <= clk_28_div(1);
when others =>
CLK_i0 <= clk_28_div(0);
end case;
if clk_28_div(1 downto 0) = "11" and zxn_cpu_speed /= "11" then
zxn_cpu_speed2 <= zxn_cpu_speed;
end if;
end if;
end process;
process(q1, CLK_i0)
begin
if (q1 = '1') then
q0_enable <= '0';
elsif falling_edge(CLK_i0) then
q0_enable <= '1';
end if;
end process;
process(q0, CLK_28)
begin
if (q0 = '1') then
q1_enable <= '0';
elsif falling_edge(CLK_28) then
q1_enable <= '1';
end if;
end process;
q0 <= not (zxn_cpu_speed(1) and zxn_cpu_speed(0)) and q0_enable when rising_edge(CLK_i0);
q1 <= (zxn_cpu_speed(1) and zxn_cpu_speed(0)) and q1_enable when rising_edge(CLK_28);
CLK_CPU <= CLK_i0 when q0 = '1' else CLK_28 when q1 = '1' else '1';
-- Clock Enables
clk_28_div <= clk_28_div + 1 when rising_edge(CLK_28);
CLK_28_PSG_EN <= '1' when clk_28_div(3 downto 0) = "1110" else '0'; -- AY clock enable @ 1.75MHz
CLK_28_JOY_EN <= '1' when clk_28_div(6 downto 0) = ("111" & X"F") else '0'; -- stick step every 4.57us (pulse width = 9.14us for each side)
CLK_28_MEMBRANE_EN <= '1' when clk_28_div(8 downto 7) = "11" and CLK_28_JOY_EN = '1' else '0'; -- complete scan every 2.5 scanlines (0.018ms per row)
------------------------------------------------------------
-- BUTTONS, JOYSTICKS, MOUSE, KEYBOARD ---------------------
------------------------------------------------------------
-- ps2 mouse
process (CLK_28)
begin
if rising_edge(CLK_28) then
zxn_mouse_stb <= ps2_mouse(24);
if (zxn_mouse_stb xor ps2_mouse(24)) = '1' then
zxn_mouse_x <= zxn_mouse_x + mouse_scale(ps2_mouse(15 downto 8), zxn_mouse_control(1 downto 0));
zxn_mouse_y <= zxn_mouse_y + mouse_scale(ps2_mouse(23 downto 16), zxn_mouse_control(1 downto 0));
zxn_mouse_wheel<= zxn_mouse_wheel + ps2_mouse_ext;
end if;
if zxn_mouse_control(2) = '0' then
zxn_mouse_button <= ps2_mouse(2 downto 0);
else
zxn_mouse_button <= (ps2_mouse(2) & ps2_mouse(0) & ps2_mouse(1));
end if;
end if;
end process;
-- ps2 keyboard
ps2_kbd_mod : entity work.ps2_keyb
port map
(
i_CLK => CLK_28,
i_reset => reset,
ps2_key => ps2_key,
-- membrane interaction
i_membrane_row => membrane_index,
o_membrane_col => ps2_kbd_col,
-- programmable keymap
i_keymap_addr => zxn_keymap_addr,
i_keymap_data => zxn_keymap_dat,
i_keymap_we => zxn_keymap_we,
fn => ps2_kbd_fn -- F11:F1
);
-- membrane keyboard
membrane_mod : entity work.membrane
port map
(
i_CLK => CLK_28,
i_CLK_EN => CLK_28_MEMBRANE_EN,
i_reset => reset,
i_rows => zxn_key_row,
o_cols => zxn_key_col,
o_membrane_ridx => membrane_index,
i_membrane_cols => membrane_stick_col and ps2_kbd_col,
i_cancel_extended_entries => zxn_cancel_extended_entries,
o_extended_keys => zxn_extended_keys
);
-- membrane joystick
membrane_stick_mod : entity work.membrane_stick
port map
(
i_CLK => CLK_28,
i_CLK_EN => CLK_28_MEMBRANE_EN,
i_reset => reset,
i_joy_en_n => zxn_joy_io_mode_en,
i_joy_left => joy_left,
i_joy_left_type => zxn_joy_left_type,
i_joy_right => joy_right,
i_joy_right_type => zxn_joy_right_type,
i_membrane_row => membrane_index,
o_membrane_col => membrane_stick_col,
i_keymap_addr => zxn_keymap_addr(4 downto 0),
i_keymap_data => zxn_keymap_dat(5 downto 0),
i_keymap_we => zxn_joymap_we
);
------------------------------------------------------------
-- SERIAL COMMUNICATION ------------------------------------
------------------------------------------------------------
-- i2c
i2c_scl_o <= zxn_i2c_scl;
------------------------------------------------------------
-- TBBLUE / ZXNEXT -----------------------------------------
------------------------------------------------------------
-- F1 = hard reset (it seems removed and acts as soft reset now)
-- F2 =
-- F3 = toggle 50Hz / 60Hz display
-- F4 =
-- F5 =
-- F6 =
-- F7 =
-- F8 = change cpu speed
-- F9 =
-- F10 = drive button (divmmc nmi)
-- F11 = m1 button (multiface nmi)
zxnext : entity work.zxnext
generic map
(
g_machine_id => g_machine_id,
g_version => g_version,
g_sub_version => g_sub_version
)
port map
(
-- CLOCK
i_CLK_28 => CLK_28,
i_CLK_28_n => not CLK_28,
i_CLK_14 => CLK_14,
i_CLK_7 => CLK_7,
i_CLK_CPU => CLK_CPU,
i_CLK_PSG_EN => CLK_28_PSG_EN,
o_CPU_SPEED => zxn_cpu_speed,
o_CPU_CONTEND => zxn_clock_contend,
o_CPU_CLK_LSB => zxn_clock_lsb,
-- RESET
i_RESET => reset,
o_RESET_HARD => zxn_reset_hard,
o_RESET_SOFT => zxn_reset_soft,
-- SPECIAL KEYS
i_SPKEY_FUNCTION => ps2_kbd_fn(10) & ps2_kbd_fn(11) & ps2_kbd_fn(8) & "0000" & ps2_kbd_fn(3) & '0' & ps2_kbd_fn(1),
i_SPKEY_BUTTONS => ps2_kbd_fn(10) & ps2_kbd_fn(11),
-- MEMBRANE KEYBOARD
o_KBD_CANCEL => zxn_cancel_extended_entries,
o_KBD_ROW => zxn_key_row,
i_KBD_COL => zxn_key_col,
i_KBD_EXTENDED_KEYS => zxn_extended_keys,
-- PS/2 KEYBOARD AND KEY JOYSTICK SETUP
o_KEYMAP_ADDR => zxn_keymap_addr,
o_KEYMAP_DATA => zxn_keymap_dat,
o_KEYMAP_WE => zxn_keymap_we,
o_JOYMAP_WE => zxn_joymap_we,
-- JOYSTICK
i_JOY_LEFT => joy_left,
i_JOY_RIGHT => joy_right,
o_JOY_IO_MODE_EN => zxn_joy_io_mode_en,
o_JOY_LEFT_TYPE => zxn_joy_left_type,
o_JOY_RIGHT_TYPE => zxn_joy_right_type,
-- MOUSE
i_MOUSE_X => zxn_mouse_x,
i_MOUSE_Y => zxn_mouse_y,
i_MOUSE_BUTTON => zxn_mouse_button,
i_MOUSE_WHEEL => zxn_mouse_wheel(3 downto 0),
o_MOUSE_CONTROL => zxn_mouse_control,
-- I2C
i_I2C_SCL_n => zxn_i2c_scl,
i_I2C_SDA_n => i2c_sda_i,
o_I2C_SCL_n => zxn_i2c_scl,
o_I2C_SDA_n => i2c_sda_o,
-- SPI
o_SPI_SS_SD1_n => sd_cs1_n_o,
o_SPI_SS_SD0_n => sd_cs0_n_o,
o_SPI_SCK => sd_sclk_o,
o_SPI_MOSI => sd_mosi_o,
i_SPI_SD_MISO => sd_miso_i,
i_SPI_FLASH_MISO => '1',
-- UART
i_UART0_RX => uart_rx_i,
o_UART0_TX => uart_tx_o,
-- VIDEO
-- synchronized to i_CLK_14
o_RGB => RGB,
o_RGB_VS_n => RGB_VS_n,
o_RGB_HS_n => RGB_HS_n,
o_RGB_VB_n => RGB_VB_n,
o_RGB_HB_n => RGB_HB_n,
o_VIDEO_MODE => zxn_video_mode,
o_VIDEO_50_60 => RGB_NTSC,
-- AUDIO
i_AUDIO_EAR => ear_port_i,
o_AUDIO_MIC => mic_port_o,
o_AUDIO_L => zxn_audio_L_pre,
o_AUDIO_R => zxn_audio_R_pre,
-- EXTERNAL SRAM (synchronized to i_CLK_28)
-- memory transactions complete in one cycle, data read is registered but available asap
o_RAM_A_ADDR => RAM_A_ADDR,
o_RAM_A_REQ => RAM_A_REQ,
o_RAM_A_RD_n => RAM_A_RD_n,
i_RAM_A_DI => RAM_A_DI,
o_RAM_A_DO => RAM_A_DO,
i_RAM_A_WAIT => RAM_A_WAIT,
o_RAM_B_ADDR => RAM_B_ADDR,
o_RAM_B_REQ_T => RAM_B_REQ,
i_RAM_B_DI => RAM_B_DI,
-- EXPANSION BUS
i_BUS_DI => (others => '1'),
i_BUS_WAIT_n => '1',
i_BUS_NMI_n => '1',
i_BUS_INT_n => '1',
i_BUS_BUSREQ_n => '1',
i_BUS_ROMCS_n => '1',
i_BUS_IORQULA_n => '1',
-- ESP GPIO
i_ESP_GPIO_20 => (others => '1'),
o_ESP_GPIO_0 => open,
o_ESP_GPIO_0_EN => open,
-- PI GPIO
i_GPIO => (others => '1'),
o_GPIO => open,
o_GPIO_EN => open
);
audio_L <= (others => '1') when zxn_audio_L_pre(12) = '1' else zxn_audio_L_pre(11 downto 0);
audio_R <= (others => '1') when zxn_audio_R_pre(12) = '1' else zxn_audio_R_pre(11 downto 0);
end architecture;

337
rtl/pll.qip Normal file
View File

@@ -0,0 +1,337 @@
set_global_assignment -entity "pll" -library "pll" -name IP_TOOL_NAME "altera_pll"
set_global_assignment -entity "pll" -library "pll" -name IP_TOOL_VERSION "17.0"
set_global_assignment -entity "pll" -library "pll" -name IP_TOOL_ENV "mwpim"
set_global_assignment -library "pll" -name MISC_FILE [file join $::quartus(qip_path) "pll.cmp"]
set_global_assignment -entity "pll" -library "pll" -name IP_TARGETED_DEVICE_FAMILY "Cyclone V"
set_global_assignment -entity "pll" -library "pll" -name IP_GENERATED_DEVICE_FAMILY "{Cyclone V}"
set_global_assignment -entity "pll" -library "pll" -name IP_QSYS_MODE "UNKNOWN"
set_global_assignment -name SYNTHESIS_ONLY_QIP ON
set_global_assignment -entity "pll" -library "pll" -name IP_COMPONENT_NAME "cGxs"
set_global_assignment -entity "pll" -library "pll" -name IP_COMPONENT_DISPLAY_NAME "QWx0ZXJhIFBMTA=="
set_global_assignment -entity "pll" -library "pll" -name IP_COMPONENT_REPORT_HIERARCHY "Off"
set_global_assignment -entity "pll" -library "pll" -name IP_COMPONENT_INTERNAL "Off"
set_global_assignment -entity "pll" -library "pll" -name IP_COMPONENT_AUTHOR "QWx0ZXJhIENvcnBvcmF0aW9u"
set_global_assignment -entity "pll" -library "pll" -name IP_COMPONENT_VERSION "MTcuMA=="
set_global_assignment -entity "pll" -library "pll" -name IP_COMPONENT_DESCRIPTION "QWx0ZXJhIFBoYXNlLUxvY2tlZCBMb29wIChBTFRFUkFfUExMKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_NAME "cGxsXzAwMDI="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_DISPLAY_NAME "QWx0ZXJhIFBMTA=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_REPORT_HIERARCHY "Off"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_INTERNAL "Off"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_AUTHOR "QWx0ZXJhIENvcnBvcmF0aW9u"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_VERSION "MTcuMA=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_DESCRIPTION "QWx0ZXJhIFBoYXNlLUxvY2tlZCBMb29wIChBTFRFUkFfUExMKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZGVidWdfcHJpbnRfb3V0cHV0::ZmFsc2U=::ZGVidWdfcHJpbnRfb3V0cHV0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZGVidWdfdXNlX3JiY190YWZfbWV0aG9k::ZmFsc2U=::ZGVidWdfdXNlX3JiY190YWZfbWV0aG9k"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZGV2aWNl::NUNFQkEyRjE3QTc=::ZGV2aWNl"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BsbF9tb2Rl::SW50ZWdlci1OIFBMTA==::UExMIE1vZGU="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZnJhY3Rpb25hbF92Y29fbXVsdGlwbGllcg==::ZmFsc2U=::ZnJhY3Rpb25hbF92Y29fbXVsdGlwbGllcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3JlZmVyZW5jZV9jbG9ja19mcmVxdWVuY3k=::NTAuMA==::UmVmZXJlbmNlIENsb2NrIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cmVmZXJlbmNlX2Nsb2NrX2ZyZXF1ZW5jeQ==::NTAuMCBNSHo=::cmVmZXJlbmNlX2Nsb2NrX2ZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2NoYW5uZWxfc3BhY2luZw==::MC4w::Q2hhbm5lbCBTcGFjaW5n"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX29wZXJhdGlvbl9tb2Rl::ZGlyZWN0::T3BlcmF0aW9uIE1vZGU="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2ZlZWRiYWNrX2Nsb2Nr::R2xvYmFsIENsb2Nr::RmVlZGJhY2sgQ2xvY2s="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2ZyYWN0aW9uYWxfY291dA==::MzI=::RnJhY3Rpb25hbCBjYXJyeSBvdXQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RzbV9vdXRfc2Vs::MXN0X29yZGVy::RFNNIE9yZGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3BlcmF0aW9uX21vZGU=::ZGlyZWN0::b3BlcmF0aW9uX21vZGU="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3VzZV9sb2NrZWQ=::dHJ1ZQ==::RW5hYmxlIGxvY2tlZCBvdXRwdXQgcG9ydA=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2VuX2Fkdl9wYXJhbXM=::ZmFsc2U=::RW5hYmxlIHBoeXNpY2FsIG91dHB1dCBjbG9jayBwYXJhbWV0ZXJz"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX251bWJlcl9vZl9jbG9ja3M=::NQ==::TnVtYmVyIE9mIENsb2Nrcw=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "bnVtYmVyX29mX2Nsb2Nrcw==::NQ==::bnVtYmVyX29mX2Nsb2Nrcw=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX211bHRpcGx5X2ZhY3Rvcg==::MQ==::TXVsdGlwbHkgRmFjdG9yIChNLUNvdW50ZXIp"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2ZyYWNfbXVsdGlwbHlfZmFjdG9y::MQ==::RnJhY3Rpb25hbCBNdWx0aXBseSBGYWN0b3IgKEsp"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3Jfbg==::MQ==::RGl2aWRlIEZhY3RvciAoTi1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjA=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kw::MjguMA==::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzA=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3Iw::NTY=::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjA=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMA==::MTAw::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MA==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMA==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MA==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzA=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDA=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUw::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kx::NTYuMA==::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3Ix::NTY=::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMQ==::NTA=::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MQ==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMQ==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MQ==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE=::MTgwLjA=::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUx::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjI=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3ky::MTQuMA==::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzI=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3Iy::NTY=::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjI=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMg==::MjAw::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5Mg==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMg==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0Mg==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzI=::MTgwLjA=::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDI=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUy::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjM=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kz::Ny4w::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzM=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3Iz::NTY=::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjM=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMw==::NDAw::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5Mw==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMw==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0Mw==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzM=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDM=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUz::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjQ=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k0::MTEyLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzQ=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I0::NTY=::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjQ=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yNA==::MjU=::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5NA==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzNA==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0NA==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzQ=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDQ=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU0::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjU=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k1::NTYuMA==::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzU=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I1::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjU=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yNQ==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5NQ==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzNQ==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0NQ==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzU=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDU=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU1::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjY=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k2::MTEyLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzY=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I2::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjY=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yNg==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5Ng==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzNg==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0Ng==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzY=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDY=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU2::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjc=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k3::MTEyLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzc=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I3::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3Rvcjc=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yNw==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5Nw==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzNw==::ZGVncmVlcw==::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0Nw==::LTQzNTA=::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzc=::LTkwLjA=::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDc=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU3::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjg=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k4::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzg=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I4::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3Rvcjg=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yOA==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5OA==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzOA==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0OA==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzg=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDg=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU4::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjk=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k5::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzk=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I5::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3Rvcjk=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yOQ==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5OQ==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzOQ==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0OQ==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzk=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDk=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU5::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjEw::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxMA==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzEw::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxMA==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjEw::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTA=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTA=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTA=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTA=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzEw::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDEw::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxMA==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjEx::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxMQ==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzEx::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxMQ==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjEx::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTE=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTE=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTE=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTE=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzEx::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDEx::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxMQ==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjEy::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxMg==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzEy::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxMg==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjEy::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTI=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTI=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTI=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTI=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzEy::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDEy::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxMg==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjEz::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxMw==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzEz::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxMw==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjEz::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTM=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTM=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTM=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTM=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzEz::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDEz::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxMw==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE0::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxNA==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE0::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxNA==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE0::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTQ=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTQ=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTQ=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTQ=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE0::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE0::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxNA==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE1::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxNQ==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE1::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxNQ==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE1::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTU=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTU=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTU=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTU=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE1::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE1::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxNQ==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE2::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxNg==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE2::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxNg==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE2::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTY=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTY=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTY=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTY=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE2::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE2::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxNg==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE3::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxNw==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE3::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxNw==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE3::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTc=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTc=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTc=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTc=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE3::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE3::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxNw==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTA=::MjguMDAwMDAwIE1Ieg==::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTA="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQw::MCBwcw==::cGhhc2Vfc2hpZnQw"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTA=::NTA=::ZHV0eV9jeWNsZTA="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE=::NTYuMDAwMDAwIE1Ieg==::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQx::MCBwcw==::cGhhc2Vfc2hpZnQx"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE=::NTA=::ZHV0eV9jeWNsZTE="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTI=::MTQuMDAwMDAwIE1Ieg==::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTI="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQy::MCBwcw==::cGhhc2Vfc2hpZnQy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTI=::NTA=::ZHV0eV9jeWNsZTI="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTM=::Ny4wMDAwMDAgTUh6::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQz::MCBwcw==::cGhhc2Vfc2hpZnQz"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTM=::NTA=::ZHV0eV9jeWNsZTM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTQ=::MTEyLjAwMDAwMCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ0::MCBwcw==::cGhhc2Vfc2hpZnQ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTQ=::NTA=::ZHV0eV9jeWNsZTQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTU=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTU="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ1::MCBwcw==::cGhhc2Vfc2hpZnQ1"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTU=::NTA=::ZHV0eV9jeWNsZTU="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTY=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTY="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ2::MCBwcw==::cGhhc2Vfc2hpZnQ2"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTY=::NTA=::ZHV0eV9jeWNsZTY="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTc=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTc="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ3::MCBwcw==::cGhhc2Vfc2hpZnQ3"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTc=::NTA=::ZHV0eV9jeWNsZTc="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTg=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTg="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ4::MCBwcw==::cGhhc2Vfc2hpZnQ4"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTg=::NTA=::ZHV0eV9jeWNsZTg="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTk=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTk="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ5::MCBwcw==::cGhhc2Vfc2hpZnQ5"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTk=::NTA=::ZHV0eV9jeWNsZTk="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEw::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEw"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxMA==::MCBwcw==::cGhhc2Vfc2hpZnQxMA=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTEw::NTA=::ZHV0eV9jeWNsZTEw"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEx::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEx"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxMQ==::MCBwcw==::cGhhc2Vfc2hpZnQxMQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTEx::NTA=::ZHV0eV9jeWNsZTEx"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEy::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxMg==::MCBwcw==::cGhhc2Vfc2hpZnQxMg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTEy::NTA=::ZHV0eV9jeWNsZTEy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEz::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEz"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxMw==::MCBwcw==::cGhhc2Vfc2hpZnQxMw=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTEz::NTA=::ZHV0eV9jeWNsZTEz"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE0::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxNA==::MCBwcw==::cGhhc2Vfc2hpZnQxNA=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE0::NTA=::ZHV0eV9jeWNsZTE0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE1::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE1"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxNQ==::MCBwcw==::cGhhc2Vfc2hpZnQxNQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE1::NTA=::ZHV0eV9jeWNsZTE1"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE2::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE2"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxNg==::MCBwcw==::cGhhc2Vfc2hpZnQxNg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE2::NTA=::ZHV0eV9jeWNsZTE2"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE3::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE3"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxNw==::MCBwcw==::cGhhc2Vfc2hpZnQxNw=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE3::NTA=::ZHV0eV9jeWNsZTE3"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BsbF9hdXRvX3Jlc2V0::T24=::UExMIEF1dG8gUmVzZXQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BsbF9iYW5kd2lkdGhfcHJlc2V0::QXV0bw==::UExMIEJhbmR3aWR0aCBQcmVzZXQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2VuX3JlY29uZg==::ZmFsc2U=::RW5hYmxlIGR5bmFtaWMgcmVjb25maWd1cmF0aW9uIG9mIFBMTA=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2VuX2Rwc19wb3J0cw==::ZmFsc2U=::RW5hYmxlIGFjY2VzcyB0byBkeW5hbWljIHBoYXNlIHNoaWZ0IHBvcnRz"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2VuX3Bob3V0X3BvcnRz::ZmFsc2U=::RW5hYmxlIGFjY2VzcyB0byBQTEwgRFBBIG91dHB1dCBwb3J0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGxsX3R5cGU=::R2VuZXJhbA==::UExMIFRZUEU="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGxsX3N1YnR5cGU=::R2VuZXJhbA==::UExMIFNVQlRZUEU="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BhcmFtZXRlcl9saXN0::TS1Db3VudGVyIEhpIERpdmlkZSxNLUNvdW50ZXIgTG93IERpdmlkZSxOLUNvdW50ZXIgSGkgRGl2aWRlLE4tQ291bnRlciBMb3cgRGl2aWRlLE0tQ291bnRlciBCeXBhc3MgRW5hYmxlLE4tQ291bnRlciBCeXBhc3MgRW5hYmxlLE0tQ291bnRlciBPZGQgRGl2aWRlIEVuYWJsZSxOLUNvdW50ZXIgT2RkIERpdmlkZSBFbmFibGUsQy1Db3VudGVyLTAgSGkgRGl2aWRlLEMtQ291bnRlci0wIExvdyBEaXZpZGUsQy1Db3VudGVyLTAgQ29hcnNlIFBoYXNlIFNoaWZ0LEMtQ291bnRlci0wIFZDTyBQaGFzZSBUYXAsQy1Db3VudGVyLTAgSW5wdXQgU291cmNlLEMtQ291bnRlci0wIEJ5cGFzcyBFbmFibGUsQy1Db3VudGVyLTAgT2RkIERpdmlkZSBFbmFibGUsQy1Db3VudGVyLTEgSGkgRGl2aWRlLEMtQ291bnRlci0xIExvdyBEaXZpZGUsQy1Db3VudGVyLTEgQ29hcnNlIFBoYXNlIFNoaWZ0LEMtQ291bnRlci0xIFZDTyBQaGFzZSBUYXAsQy1Db3VudGVyLTEgSW5wdXQgU291cmNlLEMtQ291bnRlci0xIEJ5cGFzcyBFbmFibGUsQy1Db3VudGVyLTEgT2RkIERpdmlkZSBFbmFibGUsQy1Db3VudGVyLTIgSGkgRGl2aWRlLEMtQ291bnRlci0yIExvdyBEaXZpZGUsQy1Db3VudGVyLTIgQ29hcnNlIFBoYXNlIFNoaWZ0LEMtQ291bnRlci0yIFZDTyBQaGFzZSBUYXAsQy1Db3VudGVyLTIgSW5wdXQgU291cmNlLEMtQ291bnRlci0yIEJ5cGFzcyBFbmFibGUsQy1Db3VudGVyLTIgT2RkIERpdmlkZSBFbmFibGUsQy1Db3VudGVyLTMgSGkgRGl2aWRlLEMtQ291bnRlci0zIExvdyBEaXZpZGUsQy1Db3VudGVyLTMgQ29hcnNlIFBoYXNlIFNoaWZ0LEMtQ291bnRlci0zIFZDTyBQaGFzZSBUYXAsQy1Db3VudGVyLTMgSW5wdXQgU291cmNlLEMtQ291bnRlci0zIEJ5cGFzcyBFbmFibGUsQy1Db3VudGVyLTMgT2RkIERpdmlkZSBFbmFibGUsQy1Db3VudGVyLTQgSGkgRGl2aWRlLEMtQ291bnRlci00IExvdyBEaXZpZGUsQy1Db3VudGVyLTQgQ29hcnNlIFBoYXNlIFNoaWZ0LEMtQ291bnRlci00IFZDTyBQaGFzZSBUYXAsQy1Db3VudGVyLTQgSW5wdXQgU291cmNlLEMtQ291bnRlci00IEJ5cGFzcyBFbmFibGUsQy1Db3VudGVyLTQgT2RkIERpdmlkZSBFbmFibGUsVkNPIFBvc3QgRGl2aWRlIENvdW50ZXIgRW5hYmxlLENoYXJnZSBQdW1wIGN1cnJlbnQgKHVBKSxMb29wIEZpbHRlciBCYW5kd2lkdGggUmVzaXN0b3IgKE9obXMpICxQTEwgT3V0cHV0IFZDTyBGcmVxdWVuY3ksSy1GcmFjdGlvbmFsIERpdmlzaW9uIFZhbHVlIChEU00pLEZlZWRiYWNrIENsb2NrIFR5cGUsRmVlZGJhY2sgQ2xvY2sgTVVYIDEsRmVlZGJhY2sgQ2xvY2sgTVVYIDIsTSBDb3VudGVyIFNvdXJjZSBNVVgsUExMIEF1dG8gUmVzZXQ=::UGFyYW1ldGVyIE5hbWVz"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BhcmFtZXRlcl92YWx1ZXM=::MjgsMjgsMywyLGZhbHNlLGZhbHNlLGZhbHNlLHRydWUsMTAsMTAsMSwwLHBoX211eF9jbGssZmFsc2UsZmFsc2UsNSw1LDEsMCxwaF9tdXhfY2xrLGZhbHNlLGZhbHNlLDIwLDIwLDEsMCxwaF9tdXhfY2xrLGZhbHNlLGZhbHNlLDQwLDQwLDEsMCxwaF9tdXhfY2xrLGZhbHNlLGZhbHNlLDMsMiwxLDAscGhfbXV4X2NsayxmYWxzZSx0cnVlLDIsMjAsMTAwMDAsNTYwLjAgTUh6LDEsbm9uZSxnbGIsbV9jbnQscGhfbXV4X2Nsayx0cnVl::UGFyYW1ldGVyIFZhbHVlcw=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX21pZl9nZW5lcmF0ZQ==::ZmFsc2U=::R2VuZXJhdGUgTUlGIGZpbGU="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9taWZfZHBz::ZmFsc2U=::RW5hYmxlIER5bmFtaWMgUGhhc2UgU2hpZnQgZm9yIE1JRiBzdHJlYW1pbmc="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Rwc19jbnRy::QzA=::RFBTIENvdW50ZXIgU2VsZWN0aW9u"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Rwc19udW0=::MQ==::TnVtYmVyIG9mIER5bmFtaWMgUGhhc2UgU2hpZnRz"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Rwc19kaXI=::UG9zaXRpdmU=::RHluYW1pYyBQaGFzZSBTaGlmdCBEaXJlY3Rpb24="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3JlZmNsa19zd2l0Y2g=::ZmFsc2U=::Q3JlYXRlIGEgc2Vjb25kIGlucHV0IGNsayAncmVmY2xrMSc="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9jYXNjYWRlX291dA==::ZmFsc2U=::Q3JlYXRlIGEgJ2Nhc2NhZGVfb3V0JyBzaWduYWwgdG8gY29ubmVjdCB3aXRoIGEgZG93bnN0cmVhbSBQTEw="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9jYXNjYWRlX2lu::ZmFsc2U=::Q3JlYXRlIGFuIGFkanBsbGluIG9yIGNjbGsgc2lnbmFsIHRvIGNvbm5lY3Qgd2l0aCBhbiB1cHN0cmVhbSBQTEw="
set_global_assignment -library "pll" -name VERILOG_FILE [file join $::quartus(qip_path) "pll.v"]
set_global_assignment -library "pll" -name VERILOG_FILE [file join $::quartus(qip_path) "pll/pll_0002.v"]
set_global_assignment -library "pll" -name QIP_FILE [file join $::quartus(qip_path) "pll/pll_0002.qip"]
set_global_assignment -entity "pll_0002" -library "pll" -name IP_TOOL_NAME "altera_pll"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_TOOL_VERSION "17.0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_TOOL_ENV "mwpim"

261
rtl/pll.v Normal file
View File

@@ -0,0 +1,261 @@
// megafunction wizard: %Altera PLL v17.0%
// GENERATION: XML
// pll.v
// Generated using ACDS version 17.0 602
`timescale 1 ps / 1 ps
module pll (
input wire refclk, // refclk.clk
input wire rst, // reset.reset
output wire outclk_0, // outclk0.clk
output wire outclk_1, // outclk1.clk
output wire outclk_2, // outclk2.clk
output wire outclk_3, // outclk3.clk
output wire outclk_4, // outclk4.clk
output wire locked // locked.export
);
pll_0002 pll_inst (
.refclk (refclk), // refclk.clk
.rst (rst), // reset.reset
.outclk_0 (outclk_0), // outclk0.clk
.outclk_1 (outclk_1), // outclk1.clk
.outclk_2 (outclk_2), // outclk2.clk
.outclk_3 (outclk_3), // outclk3.clk
.outclk_4 (outclk_4), // outclk4.clk
.locked (locked) // locked.export
);
endmodule
// Retrieval info: <?xml version="1.0"?>
//<!--
// Generated by Altera MegaWizard Launcher Utility version 1.0
// ************************************************************
// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
// ************************************************************
// Copyright (C) 1991-2021 Altera Corporation
// Any megafunction design, and related net list (encrypted or decrypted),
// support information, device programming or simulation file, and any other
// associated documentation or information provided by Altera or a partner
// under Altera's Megafunction Partnership Program may be used only to
// program PLD devices (but not masked PLD devices) from Altera. Any other
// use of such megafunction design, net list, support information, device
// programming or simulation file, or any other related documentation or
// information is prohibited for any other purpose, including, but not
// limited to modification, reverse engineering, de-compiling, or use with
// any other silicon devices, unless such use is explicitly licensed under
// a separate agreement with Altera or a megafunction partner. Title to
// the intellectual property, including patents, copyrights, trademarks,
// trade secrets, or maskworks, embodied in any such megafunction design,
// net list, support information, device programming or simulation file, or
// any other related documentation or information provided by Altera or a
// megafunction partner, remains with Altera, the megafunction partner, or
// their respective licensors. No other licenses, including any licenses
// needed under any third party's intellectual property, are provided herein.
//-->
// Retrieval info: <instance entity-name="altera_pll" version="17.0" >
// Retrieval info: <generic name="debug_print_output" value="false" />
// Retrieval info: <generic name="debug_use_rbc_taf_method" value="false" />
// Retrieval info: <generic name="device_family" value="Cyclone V" />
// Retrieval info: <generic name="device" value="5CEBA2F17A7" />
// Retrieval info: <generic name="gui_device_speed_grade" value="2" />
// Retrieval info: <generic name="gui_pll_mode" value="Integer-N PLL" />
// Retrieval info: <generic name="gui_reference_clock_frequency" value="50.0" />
// Retrieval info: <generic name="gui_channel_spacing" value="0.0" />
// Retrieval info: <generic name="gui_operation_mode" value="direct" />
// Retrieval info: <generic name="gui_feedback_clock" value="Global Clock" />
// Retrieval info: <generic name="gui_fractional_cout" value="32" />
// Retrieval info: <generic name="gui_dsm_out_sel" value="1st_order" />
// Retrieval info: <generic name="gui_use_locked" value="true" />
// Retrieval info: <generic name="gui_en_adv_params" value="false" />
// Retrieval info: <generic name="gui_number_of_clocks" value="5" />
// Retrieval info: <generic name="gui_multiply_factor" value="1" />
// Retrieval info: <generic name="gui_frac_multiply_factor" value="1" />
// Retrieval info: <generic name="gui_divide_factor_n" value="1" />
// Retrieval info: <generic name="gui_cascade_counter0" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency0" value="28.0" />
// Retrieval info: <generic name="gui_divide_factor_c0" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency0" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units0" value="ps" />
// Retrieval info: <generic name="gui_phase_shift0" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg0" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift0" value="0" />
// Retrieval info: <generic name="gui_duty_cycle0" value="50" />
// Retrieval info: <generic name="gui_cascade_counter1" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency1" value="56.0" />
// Retrieval info: <generic name="gui_divide_factor_c1" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency1" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units1" value="ps" />
// Retrieval info: <generic name="gui_phase_shift1" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg1" value="180.0" />
// Retrieval info: <generic name="gui_actual_phase_shift1" value="0" />
// Retrieval info: <generic name="gui_duty_cycle1" value="50" />
// Retrieval info: <generic name="gui_cascade_counter2" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency2" value="14.0" />
// Retrieval info: <generic name="gui_divide_factor_c2" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency2" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units2" value="ps" />
// Retrieval info: <generic name="gui_phase_shift2" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg2" value="180.0" />
// Retrieval info: <generic name="gui_actual_phase_shift2" value="0" />
// Retrieval info: <generic name="gui_duty_cycle2" value="50" />
// Retrieval info: <generic name="gui_cascade_counter3" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency3" value="7.0" />
// Retrieval info: <generic name="gui_divide_factor_c3" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency3" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units3" value="ps" />
// Retrieval info: <generic name="gui_phase_shift3" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg3" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift3" value="0" />
// Retrieval info: <generic name="gui_duty_cycle3" value="50" />
// Retrieval info: <generic name="gui_cascade_counter4" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency4" value="112.0" />
// Retrieval info: <generic name="gui_divide_factor_c4" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency4" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units4" value="ps" />
// Retrieval info: <generic name="gui_phase_shift4" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg4" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift4" value="0" />
// Retrieval info: <generic name="gui_duty_cycle4" value="50" />
// Retrieval info: <generic name="gui_cascade_counter5" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency5" value="56.0" />
// Retrieval info: <generic name="gui_divide_factor_c5" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency5" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units5" value="ps" />
// Retrieval info: <generic name="gui_phase_shift5" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg5" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift5" value="0" />
// Retrieval info: <generic name="gui_duty_cycle5" value="50" />
// Retrieval info: <generic name="gui_cascade_counter6" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency6" value="112.0" />
// Retrieval info: <generic name="gui_divide_factor_c6" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency6" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units6" value="ps" />
// Retrieval info: <generic name="gui_phase_shift6" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg6" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift6" value="0" />
// Retrieval info: <generic name="gui_duty_cycle6" value="50" />
// Retrieval info: <generic name="gui_cascade_counter7" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency7" value="112.0" />
// Retrieval info: <generic name="gui_divide_factor_c7" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency7" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units7" value="degrees" />
// Retrieval info: <generic name="gui_phase_shift7" value="-4350" />
// Retrieval info: <generic name="gui_phase_shift_deg7" value="-90.0" />
// Retrieval info: <generic name="gui_actual_phase_shift7" value="0" />
// Retrieval info: <generic name="gui_duty_cycle7" value="50" />
// Retrieval info: <generic name="gui_cascade_counter8" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency8" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c8" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency8" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units8" value="ps" />
// Retrieval info: <generic name="gui_phase_shift8" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg8" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift8" value="0" />
// Retrieval info: <generic name="gui_duty_cycle8" value="50" />
// Retrieval info: <generic name="gui_cascade_counter9" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency9" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c9" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency9" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units9" value="ps" />
// Retrieval info: <generic name="gui_phase_shift9" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg9" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift9" value="0" />
// Retrieval info: <generic name="gui_duty_cycle9" value="50" />
// Retrieval info: <generic name="gui_cascade_counter10" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency10" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c10" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency10" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units10" value="ps" />
// Retrieval info: <generic name="gui_phase_shift10" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg10" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift10" value="0" />
// Retrieval info: <generic name="gui_duty_cycle10" value="50" />
// Retrieval info: <generic name="gui_cascade_counter11" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency11" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c11" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency11" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units11" value="ps" />
// Retrieval info: <generic name="gui_phase_shift11" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg11" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift11" value="0" />
// Retrieval info: <generic name="gui_duty_cycle11" value="50" />
// Retrieval info: <generic name="gui_cascade_counter12" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency12" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c12" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency12" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units12" value="ps" />
// Retrieval info: <generic name="gui_phase_shift12" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg12" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift12" value="0" />
// Retrieval info: <generic name="gui_duty_cycle12" value="50" />
// Retrieval info: <generic name="gui_cascade_counter13" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency13" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c13" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency13" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units13" value="ps" />
// Retrieval info: <generic name="gui_phase_shift13" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg13" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift13" value="0" />
// Retrieval info: <generic name="gui_duty_cycle13" value="50" />
// Retrieval info: <generic name="gui_cascade_counter14" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency14" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c14" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency14" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units14" value="ps" />
// Retrieval info: <generic name="gui_phase_shift14" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg14" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift14" value="0" />
// Retrieval info: <generic name="gui_duty_cycle14" value="50" />
// Retrieval info: <generic name="gui_cascade_counter15" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency15" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c15" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency15" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units15" value="ps" />
// Retrieval info: <generic name="gui_phase_shift15" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg15" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift15" value="0" />
// Retrieval info: <generic name="gui_duty_cycle15" value="50" />
// Retrieval info: <generic name="gui_cascade_counter16" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency16" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c16" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency16" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units16" value="ps" />
// Retrieval info: <generic name="gui_phase_shift16" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg16" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift16" value="0" />
// Retrieval info: <generic name="gui_duty_cycle16" value="50" />
// Retrieval info: <generic name="gui_cascade_counter17" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency17" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c17" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency17" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units17" value="ps" />
// Retrieval info: <generic name="gui_phase_shift17" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg17" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift17" value="0" />
// Retrieval info: <generic name="gui_duty_cycle17" value="50" />
// Retrieval info: <generic name="gui_pll_auto_reset" value="On" />
// Retrieval info: <generic name="gui_pll_bandwidth_preset" value="Auto" />
// Retrieval info: <generic name="gui_en_reconf" value="false" />
// Retrieval info: <generic name="gui_en_dps_ports" value="false" />
// Retrieval info: <generic name="gui_en_phout_ports" value="false" />
// Retrieval info: <generic name="gui_phout_division" value="1" />
// Retrieval info: <generic name="gui_mif_generate" value="false" />
// Retrieval info: <generic name="gui_enable_mif_dps" value="false" />
// Retrieval info: <generic name="gui_dps_cntr" value="C0" />
// Retrieval info: <generic name="gui_dps_num" value="1" />
// Retrieval info: <generic name="gui_dps_dir" value="Positive" />
// Retrieval info: <generic name="gui_refclk_switch" value="false" />
// Retrieval info: <generic name="gui_refclk1_frequency" value="100.0" />
// Retrieval info: <generic name="gui_switchover_mode" value="Automatic Switchover" />
// Retrieval info: <generic name="gui_switchover_delay" value="0" />
// Retrieval info: <generic name="gui_active_clk" value="false" />
// Retrieval info: <generic name="gui_clk_bad" value="false" />
// Retrieval info: <generic name="gui_enable_cascade_out" value="false" />
// Retrieval info: <generic name="gui_cascade_outclk_index" value="0" />
// Retrieval info: <generic name="gui_enable_cascade_in" value="false" />
// Retrieval info: <generic name="gui_pll_cascading_mode" value="Create an adjpllin signal to connect with an upstream PLL" />
// Retrieval info: </instance>
// IPFS_FILES : pll.vo
// RELATED_FILES: pll.v, pll_0002.v

4
rtl/pll/pll_0002.qip Normal file
View File

@@ -0,0 +1,4 @@
set_instance_assignment -name PLL_COMPENSATION_MODE DIRECT -to "*pll_0002*|altera_pll:altera_pll_i*|*"
set_instance_assignment -name PLL_AUTO_RESET ON -to "*pll_0002*|altera_pll:altera_pll_i*|*"
set_instance_assignment -name PLL_BANDWIDTH_PRESET AUTO -to "*pll_0002*|altera_pll:altera_pll_i*|*"

99
rtl/pll/pll_0002.v Normal file
View File

@@ -0,0 +1,99 @@
`timescale 1ns/10ps
module pll_0002(
// interface 'refclk'
input wire refclk,
// interface 'reset'
input wire rst,
// interface 'outclk0'
output wire outclk_0,
// interface 'outclk1'
output wire outclk_1,
// interface 'outclk2'
output wire outclk_2,
// interface 'outclk3'
output wire outclk_3,
// interface 'outclk4'
output wire outclk_4,
// interface 'locked'
output wire locked
);
altera_pll #(
.fractional_vco_multiplier("false"),
.reference_clock_frequency("50.0 MHz"),
.operation_mode("direct"),
.number_of_clocks(5),
.output_clock_frequency0("28.000000 MHz"),
.phase_shift0("0 ps"),
.duty_cycle0(50),
.output_clock_frequency1("56.000000 MHz"),
.phase_shift1("0 ps"),
.duty_cycle1(50),
.output_clock_frequency2("14.000000 MHz"),
.phase_shift2("0 ps"),
.duty_cycle2(50),
.output_clock_frequency3("7.000000 MHz"),
.phase_shift3("0 ps"),
.duty_cycle3(50),
.output_clock_frequency4("112.000000 MHz"),
.phase_shift4("0 ps"),
.duty_cycle4(50),
.output_clock_frequency5("0 MHz"),
.phase_shift5("0 ps"),
.duty_cycle5(50),
.output_clock_frequency6("0 MHz"),
.phase_shift6("0 ps"),
.duty_cycle6(50),
.output_clock_frequency7("0 MHz"),
.phase_shift7("0 ps"),
.duty_cycle7(50),
.output_clock_frequency8("0 MHz"),
.phase_shift8("0 ps"),
.duty_cycle8(50),
.output_clock_frequency9("0 MHz"),
.phase_shift9("0 ps"),
.duty_cycle9(50),
.output_clock_frequency10("0 MHz"),
.phase_shift10("0 ps"),
.duty_cycle10(50),
.output_clock_frequency11("0 MHz"),
.phase_shift11("0 ps"),
.duty_cycle11(50),
.output_clock_frequency12("0 MHz"),
.phase_shift12("0 ps"),
.duty_cycle12(50),
.output_clock_frequency13("0 MHz"),
.phase_shift13("0 ps"),
.duty_cycle13(50),
.output_clock_frequency14("0 MHz"),
.phase_shift14("0 ps"),
.duty_cycle14(50),
.output_clock_frequency15("0 MHz"),
.phase_shift15("0 ps"),
.duty_cycle15(50),
.output_clock_frequency16("0 MHz"),
.phase_shift16("0 ps"),
.duty_cycle16(50),
.output_clock_frequency17("0 MHz"),
.phase_shift17("0 ps"),
.duty_cycle17(50),
.pll_type("General"),
.pll_subtype("General")
) altera_pll_i (
.rst (rst),
.outclk ({outclk_4, outclk_3, outclk_2, outclk_1, outclk_0}),
.locked (locked),
.fboutclk ( ),
.fbclk (1'b0),
.refclk (refclk)
);
endmodule

1055
rtl/rom/bootrom.vhd Normal file

File diff suppressed because it is too large Load Diff

151
rtl/serial/fifop.vhd Normal file
View File

@@ -0,0 +1,151 @@
-- FIFO Manager
-- Copyright 2020 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity fifop is
generic (
constant DEPTH_BITS : positive := 9
);
port (
i_CLK : in std_logic;
i_reset : in std_logic;
o_empty : out std_logic; -- held
o_full_near : out std_logic; -- held (3/4)
o_full_almost : out std_logic; -- held (full - 2 bytes)
o_full : out std_logic; -- held
i_rd : in std_logic;
o_raddr : out std_logic_vector(DEPTH_BITS-1 downto 0);
i_wr : in std_logic;
o_waddr : out std_logic_vector(DEPTH_BITS-1 downto 0)
);
end entity;
architecture rtl of fifop is
signal stored : std_logic_vector(DEPTH_BITS downto 0);
signal stored_delta : std_logic_vector(DEPTH_BITS downto 0);
signal empty : std_logic;
signal full : std_logic;
signal rd_dly : std_logic;
signal wr_dly : std_logic;
signal rd_advance : std_logic;
signal wr_advance : std_logic;
signal rd_addr : std_logic_vector(DEPTH_BITS-1 downto 0);
signal wr_addr : std_logic_vector(DEPTH_BITS-1 downto 0);
begin
-- read from fifo
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
rd_dly <= '0';
else
rd_dly <= i_rd;
end if;
end if;
end process;
rd_advance <= rd_dly and (not i_rd) and (not empty);
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
rd_addr <= (others => '0');
elsif rd_advance = '1' then
rd_addr <= rd_addr + 1;
end if;
end if;
end process;
-- write to fifo
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
wr_dly <= '0';
else
wr_dly <= i_wr;
end if;
end if;
end process;
wr_advance <= wr_dly and (not i_wr) and (not full);
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
wr_addr <= (others => '0');
elsif wr_advance = '1' then
wr_addr <= wr_addr + 1;
end if;
end if;
end process;
-- track number of stored bytes
stored_delta <= std_logic_vector(to_unsigned(1,stored_delta'length)) when (rd_advance = '0' and wr_advance = '1') else
std_logic_vector(to_unsigned(-1,stored_delta'length)) when (rd_advance = '1' and wr_advance = '0') else
std_logic_vector(to_unsigned(0,stored_delta'length));
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
stored <= (others => '0');
else
stored <= stored + stored_delta;
end if;
end if;
end process;
-- flags
empty <= '1' when stored = std_logic_vector(to_unsigned(0,stored'length)) else '0';
full <= stored(DEPTH_BITS);
-- output
o_empty <= empty;
o_full_near <= stored(DEPTH_BITS) or (stored(DEPTH_BITS-1) and stored(DEPTH_BITS-2));
o_full_almost <= '1' when stored(DEPTH_BITS) = '1' or (stored(DEPTH_BITS-1 downto 1) = std_logic_vector(to_unsigned(-1,stored'length-1))) else '0';
o_full <= full;
o_raddr <= rd_addr;
o_waddr <= wr_addr;
end architecture;

146
rtl/serial/spi_master.vhd Normal file
View File

@@ -0,0 +1,146 @@
-- SPI Master
--
-- Copyright 2009-2010 Mike Stirling
-- Copyright 2020 Alvin Albrecht and Fabio Belavenuto
--
-- All rights reserved
--
-- Redistribution and use in source and synthezised forms, with or without
-- modification, are permitted provided that the following conditions are met:
--
-- * Redistributions of source code must retain the above copyright notice,
-- this list of conditions and the following disclaimer.
--
-- * Redistributions in synthesized form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in the
-- documentation and/or other materials provided with the distribution.
--
-- * Neither the name of the author nor the names of other contributors may
-- be used to endorse or promote products derived from this software without
-- specific prior written permission.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-- POSSIBILITY OF SUCH DAMAGE.
--
-- Mike Stirling's original implementation:
-- https://github.com/mikestir/fpga-spectrum/blob/master/spi.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity spi_master is
port (
clock_i : in std_logic;
reset_i : in std_logic;
spi_sck_o : out std_logic;
spi_mosi_o : out std_logic;
spi_miso_i : in std_logic;
spi_mosi_wr_i : in std_logic;
spi_mosi_dat_i : in std_logic_vector(7 downto 0);
spi_miso_rd_i : in std_logic;
spi_miso_dat_o : out std_logic_vector(7 downto 0);
spi_wait_n_o : out std_logic -- wait signal for dma
);
end entity;
architecture rtl of spi_master is
signal spi_begin : std_logic;
signal counter_is_zero : std_logic;
signal counter : std_logic_vector(3 downto 0) := (others => '0');
signal sck : std_logic := '0';
signal shift : std_logic_vector(8 downto 0) := (others => '1');
signal miso_dat : std_logic_vector(7 downto 0);
begin
-- start condition
spi_begin <= '1' when (spi_miso_rd_i = '1' or spi_mosi_wr_i = '1') and counter_is_zero = '1' else '0';
-- spi bit counter
counter_is_zero <= '1' when counter = X"0" else '0';
process (clock_i)
begin
if falling_edge(clock_i) then
if reset_i = '1' then
counter <= (others => '0');
elsif counter_is_zero = '0' or spi_begin = '1' then
counter <= counter + 1;
end if;
end if;
end process;
process (clock_i)
begin
if falling_edge(clock_i) then
if reset_i = '1' then
sck <= '0';
else
sck <= counter(0);
end if;
end if;
end process;
-- spi shift register
process (clock_i)
begin
if falling_edge(clock_i) then
if reset_i = '1' then
shift <= (others => '1');
elsif spi_begin = '1' then
if spi_miso_rd_i = '1' then
shift <= (others => '1');
else
shift <= spi_mosi_dat_i & '1';
end if;
elsif counter_is_zero = '0' then
if sck = '0' then
shift(0) <= spi_miso_i;
else
shift <= shift(7 downto 0) & '1';
end if;
end if;
end if;
end process;
-- miso data
process (clock_i)
begin
if rising_edge(clock_i) then
if counter_is_zero = '1' then
miso_dat <= shift(7 downto 0);
end if;
end if;
end process;
-- connect pins
spi_sck_o <= sck;
spi_mosi_o <= shift(8);
spi_miso_dat_o <= miso_dat;
spi_wait_n_o <= '1' when counter_is_zero = '1' else '0';
end architecture;

818
rtl/serial/uart.vhd Normal file
View File

@@ -0,0 +1,818 @@
-- ZX NEXT UARTS
-- Copyright 2020 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
-- Implements both uarts in the ZX Next. The uarts share four registers,
-- one of which is used to select which uart to communicate with.
--
-- Both uarts have a 512 byte Rx buffer and a 64 byte Tx buffer
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity uart is
generic
(
NOISE_REJECTION_BITS : positive := 2 -- pulse widths less than 2^NOISE_REJECTION_BITS / i_CLK will be rejected
);
port
(
i_CLK : in std_logic;
i_CLK_n : in std_logic;
i_reset : in std_logic;
i_reset_hard : in std_logic;
i_uart_reg : in std_logic_vector(1 downto 0); -- 00 = Rx, 01 = select, 10 = frame, 11 = tx
-- read from uart registers to cpu
i_uart_rd : in std_logic;
o_cpu_d : out std_logic_vector(7 downto 0);
-- write from cpu to uart registers
i_uart_wr : in std_logic;
i_cpu_d : in std_logic_vector(7 downto 0);
-- uart 0
o_uart0_hwflow : out std_logic; -- 1 = hardware flow control enabled
i_Rx_0 : in std_logic;
o_Rx_0_rtr_n : out std_logic; -- 0 = ready to receive bytes
o_Rx_0_avail : out std_logic; -- 1 = at least one byte in the Rx buffer
o_Rx_0_near_full : out std_logic; -- 1 = Rx buffer is at least 3/4 full
o_Rx_0_err : out std_logic; -- 1 = framing or parity error
o_Rx_0_err_break : out std_logic; -- 1 = break condition detected
o_Tx_0 : out std_logic;
i_Tx_0_cts_n : in std_logic; -- 0 = clear to send bytes
o_Tx_0_empty : out std_logic; -- 1 = Tx buffer is empty
-- uart 1
o_uart1_hwflow : out std_logic; -- 1 = hardware flow control enabled
i_Rx_1 : in std_logic;
o_Rx_1_rtr_n : out std_logic; -- 0 = ready to receive bytes
o_Rx_1_avail : out std_logic; -- 1 = at least one byte in the Rx buffer
o_Rx_1_near_full : out std_logic; -- 1 = Rx buffer is at least 3/4 full
o_Rx_1_err : out std_logic; -- 1 = framing or parity error
o_Rx_1_err_break : out std_logic; -- 1 = break condition detected
o_Tx_1 : out std_logic;
i_Tx_1_cts_n : in std_logic; -- 1 = clear to send bytes
o_Tx_1_empty : out std_logic -- 1 = Tx buffer is empty
);
end entity;
architecture rtl of uart is
component sdpram_64_9 is
PORT (
DPRA : IN STD_LOGIC_VECTOR(6-1 downto 0) := (OTHERS => '0');
CLK : IN STD_LOGIC;
WE : IN STD_LOGIC;
DPO : OUT STD_LOGIC_VECTOR(9-1 downto 0);
A : IN STD_LOGIC_VECTOR(6-1-(4*0*boolean'pos(6>4)) downto 0) := (OTHERS => '0');
D : IN STD_LOGIC_VECTOR(9-1 downto 0) := (OTHERS => '0')
);
end component;
signal uart_select_wr : std_logic;
signal uart_frame_wr : std_logic;
signal uart_tx_wr : std_logic;
signal uart_tx_rd : std_logic;
signal uart_rx_wr : std_logic;
signal uart_rx_rd : std_logic;
signal uart0_tx_rd : std_logic;
signal uart1_tx_rd : std_logic;
signal uart0_tx_rd_d : std_logic;
signal uart1_tx_rd_d : std_logic;
signal uart0_tx_rd_fe : std_logic;
signal uart1_tx_rd_fe : std_logic;
signal uart_select_r : std_logic;
signal uart0_prescalar_msb_r : std_logic_vector(2 downto 0) := (others => '0');
signal uart1_prescalar_msb_r : std_logic_vector(2 downto 0) := (others => '0');
signal uart0_framing_r : std_logic_vector(7 downto 0) := X"18";
signal uart1_framing_r : std_logic_vector(7 downto 0) := X"18";
signal uart0_prescalar_lsb_r : std_logic_vector(13 downto 0) := "00000011110011";
signal uart1_prescalar_lsb_r : std_logic_vector(13 downto 0) := "00000011110011";
signal uart0_fifo_reset : std_logic;
signal uart0_rx_rd : std_logic;
signal uart0_tx_wr : std_logic;
signal uart0_rx_avail : std_logic;
signal uart0_rx_byte : std_logic_vector(7 downto 0);
signal uart0_rx_err_framing : std_logic;
signal uart0_rx_err_parity : std_logic;
signal uart0_rx_err_break : std_logic;
signal uart0_rx_fifo_empty : std_logic;
signal uart0_rx_fifo_full_near : std_logic;
signal uart0_rx_fifo_full_almost : std_logic;
signal uart0_rx_fifo_full : std_logic;
signal uart0_rx_fifo_raddr : std_logic_vector(8 downto 0);
signal uart0_rx_fifo_waddr : std_logic_vector(8 downto 0);
signal uart0_tx_busy : std_logic;
signal uart0_tx_fifo_empty : std_logic;
signal uart0_tx_fifo_full : std_logic;
signal uart0_tx_fifo_raddr : std_logic_vector(5 downto 0);
signal uart0_tx_fifo_waddr : std_logic_vector(5 downto 0);
signal uart0_tx_byte : std_logic_vector(8 downto 0);
signal uart0_tx_en : std_logic;
signal uart0_tx_wr_d : std_logic;
signal uart0_tx_fifo_we : std_logic;
signal Tx_0 : std_logic;
signal uart0_status_rx_err_overflow : std_logic;
signal uart0_status_rx_err_framing : std_logic;
signal uart0_status_rx_near_full : std_logic;
signal uart0_status_rx_avail : std_logic;
signal uart0_status_tx_full : std_logic;
signal uart0_status_tx_empty : std_logic;
signal uart0_status_rx_err_break : std_logic;
signal uart0_status_rx_err : std_logic;
signal uart1_fifo_reset : std_logic;
signal uart1_rx_rd : std_logic;
signal uart1_tx_wr : std_logic;
signal uart1_rx_avail : std_logic;
signal uart1_rx_byte : std_logic_vector(7 downto 0);
signal uart1_rx_err_framing : std_logic;
signal uart1_rx_err_parity : std_logic;
signal uart1_rx_err_break : std_logic;
signal uart1_rx_fifo_empty : std_logic;
signal uart1_rx_fifo_full_near : std_logic;
signal uart1_rx_fifo_full_almost : std_logic;
signal uart1_rx_fifo_full : std_logic;
signal uart1_rx_fifo_raddr : std_logic_vector(8 downto 0);
signal uart1_rx_fifo_waddr : std_logic_vector(8 downto 0);
signal uart1_tx_busy : std_logic;
signal uart1_tx_fifo_empty : std_logic;
signal uart1_tx_fifo_full : std_logic;
signal uart1_tx_fifo_raddr : std_logic_vector(5 downto 0);
signal uart1_tx_fifo_waddr : std_logic_vector(5 downto 0);
signal uart1_tx_byte : std_logic_vector(8 downto 0);
signal uart1_tx_en : std_logic;
signal uart1_tx_wr_d : std_logic;
signal uart1_tx_fifo_we : std_logic;
signal Tx_1 : std_logic;
signal uart1_status_rx_err_overflow : std_logic;
signal uart1_status_rx_err_framing : std_logic;
signal uart1_status_rx_near_full : std_logic;
signal uart1_status_rx_avail : std_logic;
signal uart1_status_tx_full : std_logic;
signal uart1_status_tx_empty : std_logic;
signal uart1_status_rx_err_break : std_logic;
signal uart1_status_rx_err : std_logic;
signal uart0_rx_o : std_logic_vector(8 downto 0);
signal uart1_rx_o : std_logic_vector(8 downto 0);
signal uart0_rx_avail_d : std_logic;
signal uart0_rx_byte_d : std_logic_vector(8 downto 0);
signal uart0_rx_fifo_addr : std_logic_vector(8 downto 0);
signal uart0_rx_fifo_we : std_logic;
signal uart1_rx_avail_d : std_logic;
signal uart1_rx_byte_d : std_logic_vector(8 downto 0);
signal uart1_rx_fifo_addr : std_logic_vector(8 downto 0);
signal uart1_rx_fifo_we : std_logic;
begin
-----------------
-- UART REGISTERS
-----------------
process (i_uart_reg, i_uart_rd, i_uart_wr)
begin
uart_select_wr <= '0';
uart_frame_wr <= '0';
uart_tx_wr <= '0';
uart_tx_rd <= '0';
uart_rx_wr <= '0';
uart_rx_rd <= '0';
case i_uart_reg is
when "00" =>
uart_rx_wr <= i_uart_wr;
uart_rx_rd <= i_uart_rd;
when "01" =>
uart_select_wr <= i_uart_wr;
when "10" =>
uart_frame_wr <= i_uart_wr;
when others =>
uart_tx_wr <= i_uart_wr;
uart_tx_rd <= i_uart_rd;
end case;
end process;
uart0_tx_rd <= uart_tx_rd and not uart_select_r;
uart1_tx_rd <= uart_tx_rd and uart_select_r;
process(i_CLK)
begin
if rising_edge(i_CLK) then
uart0_tx_rd_d <= uart0_tx_rd;
uart1_tx_rd_d <= uart1_tx_rd;
end if;
end process;
uart0_tx_rd_fe <= uart0_tx_rd_d and not uart_tx_rd;
uart1_tx_rd_fe <= uart1_tx_rd_d and not uart_tx_rd;
-- uart select
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' then
uart_select_r <= '0';
if i_reset_hard = '1' then
uart0_prescalar_msb_r <= (others => '0');
uart1_prescalar_msb_r <= (others => '0');
end if;
elsif uart_select_wr = '1' then
uart_select_r <= i_cpu_d(6);
if i_cpu_d(4) = '1' then
if i_cpu_d(6) = '0' then
uart0_prescalar_msb_r <= i_cpu_d(2 downto 0);
else
uart1_prescalar_msb_r <= i_cpu_d(2 downto 0);
end if;
end if;
end if;
end if;
end process;
-- uart frame
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset_hard = '1' then
uart0_framing_r <= X"18";
uart1_framing_r <= X"18";
elsif uart_frame_wr = '1' then
if uart_select_r = '0' then
uart0_framing_r <= i_cpu_d; -- reset, tx break, flow control, # bits (2), parity en, parity odd, stop bits
else
uart1_framing_r <= i_cpu_d; -- reset, tx break, flow control, # bits (2), parity en, parity odd, stop bits
end if;
end if;
end if;
end process;
o_uart0_hwflow <= uart0_framing_r(5);
o_uart1_hwflow <= uart1_framing_r(5);
-- uart prescaler lsb
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset_hard = '1' then
uart0_prescalar_lsb_r <= "00000011110011"; -- 115200 @ 28MHz system clock
uart1_prescalar_lsb_r <= "00000011110011"; -- 115200 @ 28MHz system clock
elsif uart_rx_wr = '1' then
if uart_select_r = '0' then
if i_cpu_d(7) = '0' then
uart0_prescalar_lsb_r(6 downto 0) <= i_cpu_d(6 downto 0);
else
uart0_prescalar_lsb_r(13 downto 7) <= i_cpu_d(6 downto 0);
end if;
else
if i_cpu_d(7) = '0' then
uart1_prescalar_lsb_r(6 downto 0) <= i_cpu_d(6 downto 0);
else
uart1_prescalar_lsb_r(13 downto 7) <= i_cpu_d(6 downto 0);
end if;
end if;
end if;
end if;
end process;
-- read registers
process (uart_select_r, i_uart_reg, uart0_rx_o, uart0_prescalar_msb_r, uart0_framing_r, uart0_status_rx_err_break, uart0_status_rx_err_framing,
uart0_status_tx_empty, uart0_status_rx_near_full, uart0_status_rx_err_overflow, uart0_status_tx_full, uart0_status_rx_avail,
uart1_rx_o, uart1_prescalar_msb_r, uart1_framing_r, uart1_status_rx_err_break, uart1_status_rx_err_framing, uart1_status_tx_empty,
uart1_status_rx_near_full, uart1_status_rx_err_overflow, uart1_status_tx_full, uart1_status_rx_avail)
begin
if uart_select_r = '0' then
case i_uart_reg is
when "00" =>
if uart0_status_rx_avail = '1' then
o_cpu_d <= uart0_rx_o(7 downto 0);
else
o_cpu_d <= (others => '0');
end if;
when "01" =>
o_cpu_d <= "00000" & uart0_prescalar_msb_r;
when "10" =>
o_cpu_d <= uart0_framing_r;
when others =>
o_cpu_d <= uart0_status_rx_err_break & uart0_status_rx_err_framing & (uart0_rx_o(8) and uart0_status_rx_avail) & uart0_status_tx_empty &
uart0_status_rx_near_full & uart0_status_rx_err_overflow & uart0_status_tx_full & uart0_status_rx_avail;
end case;
else
case i_uart_reg is
when "00" =>
if uart1_status_rx_avail = '1' then
o_cpu_d <= uart1_rx_o(7 downto 0);
else
o_cpu_d <= (others => '0');
end if;
when "01" =>
o_cpu_d <= "01000" & uart1_prescalar_msb_r;
when "10" =>
o_cpu_d <= uart1_framing_r;
when others =>
o_cpu_d <= uart1_status_rx_err_break & uart1_status_rx_err_framing & (uart1_rx_o(8) and uart1_status_rx_avail) & uart1_status_tx_empty &
uart1_status_rx_near_full & uart1_status_rx_err_overflow & uart1_status_tx_full & uart1_status_rx_avail;
end case;
end if;
end process;
---------
-- UART 0
---------
uart0_fifo_reset <= i_reset or uart0_framing_r(7);
uart0_rx_rd <= uart_rx_rd and not uart_select_r;
uart0_tx_wr <= uart_tx_wr and not uart_select_r;
-- uart rx
uart0_rx_mod: entity work.uart_rx
generic map
(
PRESCALER_BITS => 17,
NOISE_REJECTION_BITS => NOISE_REJECTION_BITS
)
port map
(
i_CLK => i_CLK,
i_reset => i_reset,
i_frame => uart0_framing_r(7) & "00" & uart0_framing_r(4 downto 0), -- reset, pause, flow control (n/a here), # bits (2), parity en, parity odd, stop bits
i_prescaler => uart0_prescalar_msb_r & uart0_prescalar_lsb_r,
o_Rx_avail => uart0_rx_avail, -- 1 = Rx has byte (one cycle)
o_Rx_byte => uart0_rx_byte,
o_err_framing => uart0_rx_err_framing, -- one cycle
o_err_parity => uart0_rx_err_parity, -- one cycle
o_err_break => uart0_rx_err_break, -- held
i_Rx => i_Rx_0
);
uart0_rx_fifop: entity work.fifop
generic map
(
DEPTH_BITS => 9
)
port map
(
i_CLK => i_CLK,
i_reset => uart0_fifo_reset,
o_empty => uart0_rx_fifo_empty, -- held
o_full_near => uart0_rx_fifo_full_near, -- held (3/4)
o_full_almost => uart0_rx_fifo_full_almost, -- held (full - 2 bytes)
o_full => uart0_rx_fifo_full, -- held
i_rd => uart0_rx_rd, -- read address adjusted on falling edge if not empty
o_raddr => uart0_rx_fifo_raddr,
i_wr => uart0_rx_fifo_we, -- write address adjusted on falling edge if not full
o_waddr => uart0_rx_fifo_waddr
);
process (i_CLK)
begin
if rising_edge(i_CLK) then
if uart0_fifo_reset = '1' then
o_Rx_0_rtr_n <= uart0_framing_r(5);
else
o_Rx_0_rtr_n <= uart0_framing_r(5) and uart0_rx_fifo_full_almost;
end if;
end if;
end process;
-- uart0 rx fifo memory is shared with uart1 rx in a single bram block due to size (below)
-- uart tx
uart0_tx_mod: entity work.uart_tx
generic map
(
PRESCALER_BITS => 17
)
port map
(
i_CLK => i_CLK,
i_reset => i_reset,
i_frame => uart0_framing_r, -- reset, break, flow control, # bits (2), parity en, parity odd, stop bits
i_prescaler => uart0_prescalar_msb_r & uart0_prescalar_lsb_r,
o_busy => uart0_tx_busy, -- '0' if Tx is ready for another byte
i_Tx_en => uart0_tx_en,
i_Tx_byte => uart0_tx_byte(7 downto 0),
i_cts_n => i_Tx_0_cts_n, -- '0' if receiver is ready (only if flow control is enabled)
o_Tx => Tx_0
);
process (i_CLK)
begin
if rising_edge(i_CLK) then
o_Tx_0 <= Tx_0;
end if;
end process;
uart0_tx_fifop: entity work.fifop
generic map
(
DEPTH_BITS => 6
)
port map
(
i_CLK => i_CLK,
i_reset => uart0_fifo_reset,
o_empty => uart0_tx_fifo_empty, -- held
o_full_near => open,
o_full_almost => open,
o_full => uart0_tx_fifo_full, -- held
i_rd => uart0_tx_en, -- read address adjusted on falling edge if not empty
o_raddr => uart0_tx_fifo_raddr,
i_wr => uart0_tx_fifo_we, -- write address adjusted on falling edge if not full
o_waddr => uart0_tx_fifo_waddr
);
-- cpu write, uart read
uart0_tx_fifo: sdpram_64_9 -- 64x8 needed but the natural size for xilinx is 64x9
port map
(
-- async read (uart)
DPRA => uart0_tx_fifo_raddr,
DPO => uart0_tx_byte,
-- sync write (cpu)
CLK => i_CLK_n,
WE => uart0_tx_fifo_we,
A => uart0_tx_fifo_waddr,
D => '0' & i_cpu_d
);
uart0_tx_en <= '1' when uart0_tx_busy = '0' and uart0_tx_fifo_empty = '0' else '0';
process (i_CLK)
begin
if rising_edge(i_CLK) then
uart0_tx_wr_d <= uart0_tx_wr;
end if;
end process;
uart0_tx_fifo_we <= uart0_tx_wr and (not uart0_tx_wr_d) and not uart0_tx_fifo_full;
-- uart status
process (i_CLK)
begin
if rising_edge(i_CLK) then
if uart0_fifo_reset = '1' or uart0_tx_rd_fe = '1' then
uart0_status_rx_err_overflow <= '0';
uart0_status_rx_err_framing <= '0';
else
uart0_status_rx_err_overflow <= uart0_status_rx_err_overflow or (uart0_rx_avail and uart0_rx_avail_d);
uart0_status_rx_err_framing <= uart0_status_rx_err_framing or uart0_rx_err_framing or uart0_rx_err_parity;
end if;
end if;
end process;
uart0_status_rx_near_full <= uart0_rx_fifo_full_near;
uart0_status_rx_avail <= not uart0_rx_fifo_empty;
uart0_status_tx_full <= uart0_tx_fifo_full;
uart0_status_tx_empty <= uart0_tx_fifo_empty and not uart0_tx_busy;
uart0_status_rx_err_break <= uart0_rx_err_break;
uart0_status_rx_err <= uart0_status_rx_err_overflow or uart0_status_rx_err_framing;
process (i_CLK)
begin
if rising_edge(i_CLK) then
o_Rx_0_near_full <= uart0_status_rx_near_full;
o_Rx_0_avail <= uart0_status_rx_avail;
o_Rx_0_err_break <= uart0_status_rx_err_break;
o_Rx_0_err <= uart0_status_rx_err;
o_Tx_0_empty <= uart0_tx_fifo_empty;
end if;
end process;
---------
-- UART 1
---------
uart1_fifo_reset <= i_reset or uart1_framing_r(7);
uart1_rx_rd <= uart_rx_rd and uart_select_r;
uart1_tx_wr <= uart_tx_wr and uart_select_r;
-- uart rx
uart1_rx_mod: entity work.uart_rx
generic map
(
PRESCALER_BITS => 17,
NOISE_REJECTION_BITS => NOISE_REJECTION_BITS
)
port map
(
i_CLK => i_CLK,
i_reset => i_reset,
i_frame => uart1_framing_r(7) & "00" & uart1_framing_r(4 downto 0), -- reset, pause, flow control (n/a here), # bits (2), parity en, parity odd, stop bits
i_prescaler => uart1_prescalar_msb_r & uart1_prescalar_lsb_r,
o_Rx_avail => uart1_rx_avail, -- 1 = Rx has byte (one cycle)
o_Rx_byte => uart1_rx_byte,
o_err_framing => uart1_rx_err_framing, -- one cycle
o_err_parity => uart1_rx_err_parity, -- one cycle
o_err_break => uart1_rx_err_break, -- held
i_Rx => i_Rx_1
);
uart1_rx_fifop: entity work.fifop
generic map
(
DEPTH_BITS => 9
)
port map
(
i_CLK => i_CLK,
i_reset => uart1_fifo_reset,
o_empty => uart1_rx_fifo_empty, -- held
o_full_near => uart1_rx_fifo_full_near, -- held (3/4)
o_full_almost => uart1_rx_fifo_full_almost, -- held (full - 2 bytes)
o_full => uart1_rx_fifo_full, -- held
i_rd => uart1_rx_rd, -- read address adjusted on falling edge if not empty
o_raddr => uart1_rx_fifo_raddr,
i_wr => uart1_rx_fifo_we, -- write address adjusted on falling edge if not full
o_waddr => uart1_rx_fifo_waddr
);
process (i_CLK)
begin
if rising_edge(i_CLK) then
if uart1_fifo_reset = '1' then
o_Rx_1_rtr_n <= uart1_framing_r(5);
else
o_Rx_1_rtr_n <= uart1_framing_r(5) and uart1_rx_fifo_full_almost;
end if;
end if;
end process;
-- uart1 rx fifo memory is shared with uart0 rx in a single bram block due to size (below)
-- uart tx
uart1_tx_mod: entity work.uart_tx
generic map
(
PRESCALER_BITS => 17
)
port map
(
i_CLK => i_CLK,
i_reset => i_reset,
i_frame => uart1_framing_r, -- reset, break, flow control, # bits (2), parity en, parity odd, stop bits
i_prescaler => uart1_prescalar_msb_r & uart1_prescalar_lsb_r,
o_busy => uart1_tx_busy, -- '0' if Tx is ready for another byte
i_Tx_en => uart1_tx_en,
i_Tx_byte => uart1_tx_byte(7 downto 0),
i_cts_n => i_Tx_1_cts_n, -- '0' if receiver is ready (only if flow control is enabled)
o_Tx => Tx_1
);
process (i_CLK)
begin
if rising_edge(i_CLK) then
o_Tx_1 <= Tx_1;
end if;
end process;
uart1_tx_fifop: entity work.fifop
generic map
(
DEPTH_BITS => 6
)
port map
(
i_CLK => i_CLK,
i_reset => uart1_fifo_reset,
o_empty => uart1_tx_fifo_empty, -- held
o_full_near => open,
o_full_almost => open,
o_full => uart1_tx_fifo_full, -- held
i_rd => uart1_tx_en, -- read address adjusted on falling edge if not empty
o_raddr => uart1_tx_fifo_raddr,
i_wr => uart1_tx_fifo_we, -- write address adjusted on falling edge if not full
o_waddr => uart1_tx_fifo_waddr
);
-- cpu write, uart read
uart1_tx_fifo: sdpram_64_9 -- 64x8 needed but the natural size for xilinx is 64x9
port map
(
-- async read (uart)
DPRA => uart1_tx_fifo_raddr,
DPO => uart1_tx_byte,
-- sync write (cpu)
CLK => i_CLK_n,
WE => uart1_tx_fifo_we,
A => uart1_tx_fifo_waddr,
D => '0' & i_cpu_d
);
uart1_tx_en <= '1' when uart1_tx_busy = '0' and uart1_tx_fifo_empty = '0' else '0';
process (i_CLK)
begin
if rising_edge(i_CLK) then
uart1_tx_wr_d <= uart1_tx_wr;
end if;
end process;
uart1_tx_fifo_we <= uart1_tx_wr and (not uart1_tx_wr_d) and not uart1_tx_fifo_full;
-- uart status
process (i_CLK)
begin
if rising_edge(i_CLK) then
if uart1_fifo_reset = '1' or uart1_tx_rd_fe = '1' then
uart1_status_rx_err_overflow <= '0';
uart1_status_rx_err_framing <= '0';
else
uart1_status_rx_err_overflow <= uart1_status_rx_err_overflow or (uart1_rx_avail and uart1_rx_avail_d);
uart1_status_rx_err_framing <= uart1_status_rx_err_framing or uart1_rx_err_framing or uart1_rx_err_parity;
end if;
end if;
end process;
uart1_status_rx_near_full <= uart1_rx_fifo_full_near;
uart1_status_rx_avail <= not uart1_rx_fifo_empty;
uart1_status_tx_full <= uart1_tx_fifo_full;
uart1_status_tx_empty <= uart1_tx_fifo_empty and not uart1_tx_busy;
uart1_status_rx_err_break <= uart1_rx_err_break;
uart1_status_rx_err <= uart1_status_rx_err_overflow or uart1_status_rx_err_framing;
process (i_CLK)
begin
if rising_edge(i_CLK) then
o_Rx_1_near_full <= uart1_status_rx_near_full;
o_Rx_1_avail <= uart1_status_rx_avail;
o_Rx_1_err_break <= uart1_status_rx_err_break;
o_Rx_1_err <= uart1_status_rx_err;
o_Tx_1_empty <= uart1_tx_fifo_empty;
end if;
end process;
--------------------------
-- UART 0/1 RX FIFO MEMORY
--------------------------
-- cpu read, uart write
uart_fifo_rx: entity work.tdpram
generic map
(
addr_width_g => 10,
data_width_g => 9
)
port map
(
-- uart 0
clk_a_i => i_CLK,
we_a_i => uart0_rx_fifo_we,
addr_a_i => '0' & uart0_rx_fifo_addr,
data_a_i => uart0_rx_byte_d,
data_a_o => uart0_rx_o,
-- uart 1
clk_b_i => i_CLK,
we_b_i => uart1_rx_fifo_we,
addr_b_i => '1' & uart1_rx_fifo_addr,
data_b_i => uart1_rx_byte_d,
data_b_o => uart1_rx_o
);
-- share a single bram unit, the two ports are independent
-- cpu read must have priority because response must be within two cycles for dma
-- uart 0
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or uart0_rx_fifo_we = '1' then
uart0_rx_avail_d <= '0';
uart0_rx_byte_d <= (others => '0');
elsif uart0_rx_avail = '1' and uart0_rx_avail_d = '0' then
uart0_rx_avail_d <= '1';
uart0_rx_byte_d <= uart0_status_rx_err & uart0_rx_byte;
end if;
end if;
end process;
uart0_rx_fifo_addr <= uart0_rx_fifo_waddr when uart0_rx_fifo_we = '1' else uart0_rx_fifo_raddr;
uart0_rx_fifo_we <= uart0_rx_avail_d and (not uart0_rx_fifo_full) and (not uart0_rx_rd) and (not uart0_tx_rd);
-- uart 1
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or uart1_rx_fifo_we = '1' then
uart1_rx_avail_d <= '0';
uart1_rx_byte_d <= (others => '0');
elsif uart1_rx_avail = '1' and uart1_rx_avail_d = '0' then
uart1_rx_avail_d <= '1';
uart1_rx_byte_d <= uart1_status_rx_err & uart1_rx_byte;
end if;
end if;
end process;
uart1_rx_fifo_addr <= uart1_rx_fifo_waddr when uart1_rx_fifo_we = '1' else uart1_rx_fifo_raddr;
uart1_rx_fifo_we <= uart1_rx_avail_d and (not uart1_rx_fifo_full) and (not uart1_rx_rd) and (not uart1_tx_rd);
end architecture;

346
rtl/serial/uart_old.vhd Normal file
View File

@@ -0,0 +1,346 @@
-- UART 8/1/N
-- Copyright 2020 Victor Trucco and Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity uart is
port
(
uart_prescaler_i : in std_logic_vector(16 downto 0);
clock_i : in std_logic;
reset_i : in std_logic;
TX_start_i : in std_logic;
TX_byte_i : in std_logic_vector(7 downto 0);
TX_active_o : out std_logic;
TX_out_o : out std_logic;
TX_byte_finished_o : out std_logic;
RX_in_i : in std_logic;
RX_byte_finished_o : out std_logic;
RX_byte_o : out std_logic_vector(7 downto 0)
);
end uart;
architecture rtl of uart is
type tx_states is (STATE_TX_IDLE, STATE_TX_START, STATE_TX_DATA, STATE_TX_STOP, STATE_TX_FINISH);
type rx_states is (STATE_RX_IDLE, STATE_RX_START, STATE_RX_DATA, STATE_RX_STOP, STATE_RX_FINISH);
signal rx_current_state_s : rx_states := STATE_RX_IDLE;
signal tx_current_state_s : tx_states := STATE_TX_IDLE;
signal tx_clock_counter_s : integer range 0 to 131071; -- range 0 to 3000 := 0; -- ATTENTION: MAXIMUM OF TICKS TO WAIT!!!! 2916 for 9600 bps at 28mhz change here to slow speeds
signal tx_bit_index_s : integer range 0 to 7 := 0;
signal tx_data_s : std_logic_vector(7 downto 0) := (others => '0');
signal tx_clock_period_expire : std_logic;
signal tx_done_s : std_logic := '0';
signal rx_clock_counter_s : integer range 0 to 131071; -- range 0 to 3000 := 0; -- ATTENTION: MAXIMUM OF TICKS TO WAIT!!!! 2916 for 9600 bps at 28mhz change here to slow speeds
signal rx_bit_index_s : integer range 0 to 7 := 0;
signal rx_byte_s : std_logic_vector(7 downto 0) := (others => '0');
signal rx_byte_finished_s : std_logic := '0';
signal rx_data_s : std_logic;
signal rx_clock_period_expire : std_logic;
signal rx_clock_half_period_expire : std_logic;
signal Rx_in_db : std_logic;
signal ticks_per_bit_i : integer range 0 to 131071;
signal ticks_per_bit_rx : integer range 0 to 131071;
signal ticks_per_bit_tx : integer range 0 to 131071;
begin
ticks_per_bit_i <= to_integer(unsigned(uart_prescaler_i)) - 1;
-- OUTs
TX_byte_finished_o <= tx_done_s;
RX_byte_finished_o <= rx_byte_finished_s;
RX_byte_o <= rx_byte_s;
-- RX process
db : entity work.debounce
generic map
(
INITIAL_STATE => '1',
COUNTER_SIZE => 2 -- reject noise < 142ns
)
port map
(
clk_i => clock_i,
clk_en_i => '1',
button_i => RX_in_i,
button_o => Rx_in_db
);
rx_data_s <= Rx_in_db;
rx_clock_period_expire <= '1' when rx_clock_counter_s = ticks_per_bit_rx else '0';
rx_clock_half_period_expire <= '1' when rx_clock_counter_s = ticks_per_bit_rx / 2 else '0';
process (clock_i)
begin
if rising_edge(clock_i) then
if reset_i = '1' then
rx_current_state_s <= STATE_RX_IDLE;
else
case rx_current_state_s is
when STATE_RX_IDLE =>
ticks_per_bit_rx <= ticks_per_bit_i;
rx_byte_finished_s <= '0';
rx_clock_counter_s <= 0;
rx_bit_index_s <= 0;
if rx_data_s = '0' then -- Wait for start bit
rx_current_state_s <= STATE_RX_START;
else
rx_current_state_s <= STATE_RX_IDLE;
end if;
when STATE_RX_START =>
--wait for the middle of start bit
if rx_data_s = '1' then
rx_current_state_s <= STATE_RX_IDLE;
elsif rx_clock_half_period_expire = '1' then
rx_clock_counter_s <= 0;
rx_current_state_s <= STATE_RX_DATA;
else
rx_clock_counter_s <= rx_clock_counter_s + 1;
rx_current_state_s <= STATE_RX_START;
end if;
when STATE_RX_DATA =>
-- Wait for the correct number of cycles
if rx_clock_period_expire = '1' then
rx_clock_counter_s <= 0;
rx_byte_s(rx_bit_index_s) <= rx_data_s;
-- Check if all the byte was sent
if rx_bit_index_s = 7 then
rx_current_state_s <= STATE_RX_STOP;
else
rx_bit_index_s <= rx_bit_index_s + 1;
rx_current_state_s <= STATE_RX_DATA;
end if;
else
rx_clock_counter_s <= rx_clock_counter_s + 1;
rx_current_state_s <= STATE_RX_DATA;
end if;
-- Stop bit = 1
when STATE_RX_STOP =>
-- Wait for the correct number of cycles
if rx_clock_period_expire = '1' then
if rx_data_s = '0' then
rx_current_state_s <= STATE_RX_IDLE;
else
rx_byte_finished_s <= '1';
rx_current_state_s <= STATE_RX_FINISH;
end if;
else
rx_clock_counter_s <= rx_clock_counter_s + 1;
rx_current_state_s <= STATE_RX_STOP;
end if;
when STATE_RX_FINISH =>
rx_current_state_s <= STATE_RX_IDLE;
rx_byte_finished_s <= '0';
when others =>
rx_current_state_s <= STATE_RX_IDLE;
end case;
end if;
end if;
end process;
-- end RX process
-- TX process
tx_clock_period_expire <= '1' when tx_clock_counter_s = ticks_per_bit_tx else '0';
process (clock_i)
begin
if rising_edge(clock_i) then
if reset_i = '1' then
tx_current_state_s <= STATE_TX_IDLE;
else
case tx_current_state_s is
when STATE_TX_IDLE =>
ticks_per_bit_tx <= ticks_per_bit_i;
TX_active_o <= '0';
TX_out_o <= '1'; -- Idle
tx_done_s <= '0';
tx_clock_counter_s <= 0;
tx_bit_index_s <= 0;
if TX_start_i = '1' then
tx_data_s <= TX_byte_i;
tx_current_state_s <= STATE_TX_START;
else
tx_current_state_s <= STATE_TX_IDLE;
end if;
-- Start bit = 0
when STATE_TX_START =>
TX_active_o <= '1';
TX_out_o <= '0';
-- Wait for the correct number of cycles
if tx_clock_period_expire = '1' then
tx_clock_counter_s <= 0;
tx_current_state_s <= STATE_TX_DATA;
else
tx_clock_counter_s <= tx_clock_counter_s + 1;
tx_current_state_s <= STATE_TX_START;
end if;
when STATE_TX_DATA =>
TX_out_o <= tx_data_s(tx_bit_index_s);
-- Wait for the correct number of cycles
if tx_clock_period_expire = '1' then
tx_clock_counter_s <= 0;
-- Send all bit from the byte
if tx_bit_index_s = 7 then
tx_current_state_s <= STATE_TX_STOP;
else
tx_bit_index_s <= tx_bit_index_s + 1;
tx_current_state_s <= STATE_TX_DATA;
end if;
else
tx_clock_counter_s <= tx_clock_counter_s + 1;
tx_current_state_s <= STATE_TX_DATA;
end if;
-- Stop bit = 1
when STATE_TX_STOP =>
TX_out_o <= '1';
-- Wait for the correct number of cycles
if tx_clock_period_expire = '1' then
tx_current_state_s <= STATE_TX_FINISH;
else
tx_clock_counter_s <= tx_clock_counter_s + 1;
tx_current_state_s <= STATE_TX_STOP;
end if;
when STATE_TX_FINISH =>
TX_active_o <= '0';
tx_done_s <= '1';
tx_current_state_s <= STATE_TX_IDLE;
when others =>
tx_current_state_s <= STATE_TX_IDLE;
end case;
end if;
end if;
end process;
--end of TX process
end rtl;

316
rtl/serial/uart_rx.vhd Normal file
View File

@@ -0,0 +1,316 @@
-- UART RX
-- Copyright 2020 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
-- UART Receiver
--
-- Receiving:
--
-- Byte is available on o_Rx_byte when o_Rx_avail = 1 for one cycle.
--
-- Errors:
--
-- 1. o_err_framing = 1 for one cycle if expected stop bits are not present
-- 2. o_err_parity = 1 for one cycle if there is a parity mismatch
-- 3. o_err_break = 1 while a break condition exists
--
-- A received byte that is accompanied by an error is thrown away.
--
-- Prescaler:
--
-- One bit period is i_CLK divided by i_prescaler
--
-- Framing:
--
-- i_frame holds framing information:
--
-- bit 7 = 1 to immediately reset Rx to idle
-- bit 6 = pause when in idle state
-- bit 5 = enable hw flow control (not applicable here)
-- bits 4:3 = # bits in frame (11 = 8, 10 = 7, 01 = 6, 00 = 5)
-- bit 2 = parity enable
-- bit 1 = 1 for odd parity, 0 for even parity
-- bit 0 = 0 for one stop bit, 1 for two stop bits
--
-- The prescaler and frame bits 4:0 are sampled when the start bit is seen so
-- that the Rx parameters remain constant through the receive.
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity uart_rx is
generic (
PRESCALER_BITS : positive := 17; -- number of bits in bit period divisor
NOISE_REJECTION_BITS : positive := 2 -- pulse widths less than 2^NOISE_REJECTION_BITS / i_CLK will be rejected
);
port
(
i_CLK : in std_logic;
i_reset : in std_logic;
-- configuration
i_frame : in std_logic_vector(7 downto 0); -- reset, pause, flow control (n/a here), # bits (2), parity en, parity odd, stop bits
i_prescaler : in std_logic_vector(PRESCALER_BITS-1 downto 0); -- baud rate divisor
-- receive byte
o_Rx_avail : out std_logic; -- 1 = Rx has byte (one cycle)
o_Rx_byte : out std_logic_vector(7 downto 0);
o_err_framing : out std_logic; -- one cycle
o_err_parity : out std_logic; -- one cycle
o_err_break : out std_logic; -- held as long as condition exists
-- serial in
i_Rx : in std_logic
);
end entity;
architecture rtl of uart_rx is
signal Rx : std_logic;
signal Rx_d : std_logic;
signal Rx_e : std_logic;
signal rx_frame_bits : std_logic_vector(1 downto 0);
signal rx_frame_parity_en : std_logic;
signal rx_frame_stop_bits : std_logic;
signal rx_prescaler : std_logic_vector(PRESCALER_BITS-1 downto 0);
signal rx_shift : std_logic_vector(7 downto 0);
signal rx_timer_expired : std_logic;
signal rx_timer : std_logic_vector(PRESCALER_BITS-1 downto 0);
signal rx_timer_updated : std_logic;
signal rx_bit_count_expired : std_logic;
signal rx_bit_count : std_logic_vector(2 downto 0);
signal rx_parity : std_logic;
type state_t is (S_IDLE, S_START, S_BITS, S_PARITY, S_STOP_1, S_STOP_2, S_ERROR, S_PAUSE);
signal state : state_t;
signal state_next : state_t;
begin
-- NOISE REJECTION
db : entity work.debounce
generic map
(
INITIAL_STATE => '1',
COUNTER_SIZE => NOISE_REJECTION_BITS
)
port map
(
clk_i => i_CLK,
clk_en_i => '1',
button_i => i_Rx,
button_o => Rx
);
process (i_CLK)
begin
if rising_edge(i_CLK) then
Rx_d <= Rx;
end if;
end process;
Rx_e <= Rx xor Rx_d;
-- RECEIVE VARIABLES
process (i_CLK)
begin
if falling_edge(i_CLK) then
if state = S_IDLE then
rx_frame_bits <= i_frame(4 downto 3);
rx_frame_parity_en <= i_frame(2);
rx_frame_stop_bits <= i_frame(0);
rx_prescaler <= i_prescaler;
end if;
end if;
end process;
-- shift register
process (i_CLK)
begin
if rising_edge(i_CLK) then
if state = S_START or state_next = S_ERROR then
rx_shift <= (others => '1');
elsif (state = S_BITS or state = S_ERROR) and rx_timer_expired = '1' then
rx_shift <= Rx & rx_shift(7 downto 1);
elsif state = S_STOP_1 and rx_timer_expired = '1' then
case rx_frame_bits is
when "10" => rx_shift <= '0' & rx_shift(7 downto 1);
when "01" => rx_shift <= "00" & rx_shift(7 downto 2);
when "00" => rx_shift <= "000" & rx_shift(7 downto 3);
when others => rx_shift <= rx_shift;
end case;
end if;
end if;
end process;
-- baud rate timer
rx_timer_expired <= '1' when rx_timer(PRESCALER_BITS-1 downto 1) = std_logic_vector(to_unsigned(0,PRESCALER_BITS-1)) else '0';
process (i_CLK)
begin
if rising_edge(i_CLK) then
if state = S_IDLE then
rx_timer <= '0' & rx_prescaler(PRESCALER_BITS-1 downto 1);
elsif rx_timer_expired = '1' then
rx_timer <= rx_prescaler;
rx_timer_updated <= '0';
elsif state /= S_START and Rx_e = '1' and rx_timer_updated = '0' then
rx_timer <= '0' & rx_prescaler(PRESCALER_BITS-1 downto 1);
rx_timer_updated <= '1';
else
rx_timer <= rx_timer - 1;
end if;
end if;
end process;
-- bit counter & parity calculation
rx_bit_count_expired <= '1' when rx_bit_count = "000" else '0';
process (i_CLK)
begin
if rising_edge(i_CLK) then
if state = S_IDLE then
rx_bit_count <= '1' & rx_frame_bits;
rx_parity <= i_frame(1);
elsif state = S_BITS and rx_timer_expired = '1' then
rx_bit_count <= rx_bit_count - 1;
rx_parity <= rx_parity xor Rx;
end if;
end if;
end process;
-- STATE MACHINE
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or i_frame(7) = '1' then
state <= S_PAUSE;
else
state <= state_next;
end if;
end if;
end process;
process (state, Rx, rx_timer_expired, rx_bit_count_expired, rx_frame_parity_en, rx_parity, rx_frame_stop_bits, i_frame)
begin
case state is
when S_IDLE =>
if i_frame(6) = '1' then
state_next <= S_PAUSE;
elsif Rx = '0' then
state_next <= S_START;
else
state_next <= S_IDLE;
end if;
when S_START =>
if Rx = '1' then
state_next <= S_IDLE;
elsif rx_timer_expired = '1' then
state_next <= S_BITS;
else
state_next <= S_START;
end if;
when S_BITS =>
if rx_bit_count_expired = '0' or rx_timer_expired = '0' then
state_next <= S_BITS;
elsif rx_frame_parity_en = '1' then
state_next <= S_PARITY;
else
state_next <= S_STOP_1;
end if;
when S_PARITY =>
if rx_timer_expired = '0' then
state_next <= S_PARITY;
elsif Rx = rx_parity then
state_next <= S_STOP_1;
else
state_next <= S_ERROR;
end if;
when S_STOP_1 =>
if rx_timer_expired = '0' then
state_next <= S_STOP_1;
elsif Rx = '0' then
state_next <= S_ERROR;
elsif rx_frame_stop_bits = '1' then
state_next <= S_STOP_2;
else
state_next <= S_IDLE;
end if;
when S_STOP_2 =>
if rx_timer_expired = '0' then
state_next <= S_STOP_2;
elsif Rx = '0' then
state_next <= S_ERROR;
else
state_next <= S_IDLE;
end if;
when S_ERROR =>
if Rx = '0' then
state_next <= S_ERROR;
else
state_next <= S_IDLE;
end if;
when S_PAUSE =>
if i_frame(6) = '1' or Rx = '0' then
state_next <= S_PAUSE;
else
state_next <= S_IDLE;
end if;
when others =>
state_next <= S_IDLE;
end case;
end process;
-- OUTPUT
process (i_CLK)
begin
if rising_edge(i_CLK) then
if (state = S_STOP_1 or state = S_STOP_2) and state_next = S_IDLE then
o_Rx_avail <= '1';
else
o_Rx_avail <= '0';
end if;
end if;
end process;
o_Rx_byte <= rx_shift;
o_err_parity <= '1' when state = S_PARITY and state_next = S_ERROR else '0';
o_err_framing <= '1' when (state = S_STOP_1 or state = S_STOP_2) and state_next = S_ERROR else '0';
o_err_break <= '1' when state = S_ERROR and rx_shift = "00000000" else '0';
end architecture;

247
rtl/serial/uart_tx.vhd Normal file
View File

@@ -0,0 +1,247 @@
-- UART TX
-- Copyright 2020 Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
-- UART Transmitter
--
-- Sending:
--
-- 1. Wait for o_busy = 0 (break state will hold o_busy = 1)
-- 2. Set i_Tx_byte = byte to send, i_Tx_en = 1 for one cycle
--
-- Prescaler:
--
-- One bit period is i_CLK divided by i_prescaler
--
-- Framing:
--
-- i_frame holds framing information:
--
-- bit 7 = 1 to immediately reset Tx to idle; any in flight byte is ended prematurely
-- bit 6 = 1 to hold break (o_Tx = 0) while Tx is idle (cannot send in break state)
-- bit 5 = 1 to enable flow control signal i_rdr (1 = receiver ready)
-- bits 4:3 = # bits in frame (11 = 8, 10 = 7, 01 = 6, 00 = 5)
-- bit 2 = parity enable
-- bit 1 = 1 for odd parity, 0 for even parity
-- bit 0 = 0 for one stop bit, 1 for two stop bits
--
-- The prescaler and frame bits 4:0 are sampled at the time a byte is sent to hold
-- Tx parameters constant through a transmission.
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity uart_tx is
generic (
PRESCALER_BITS : positive := 17 -- number of bits in bit period divisor
);
port
(
i_CLK : in std_logic;
i_reset : in std_logic;
-- configuration
i_frame : in std_logic_vector(7 downto 0); -- reset, break, flow control, # bits (2), parity en, parity odd, stop bits
i_prescaler : in std_logic_vector(PRESCALER_BITS-1 downto 0); -- baud rate divisor
-- send byte
o_busy : out std_logic; -- 0 = Tx ready for next byte
i_Tx_en : in std_logic; -- 1 = byte is being written (one cycle)
i_Tx_byte : in std_logic_vector(7 downto 0);
i_cts_n : in std_logic; -- 0 = receiver is ready for Tx (if flow control is enabled)
-- serial out
o_Tx : out std_logic
);
end entity;
architecture rtl of uart_tx is
signal tx_frame_parity_en : std_logic;
signal tx_frame_stop_bits : std_logic;
signal tx_prescaler : std_logic_vector(PRESCALER_BITS-1 downto 0);
signal tx_shift : std_logic_vector(7 downto 0);
signal tx_timer_expired : std_logic;
signal tx_timer : std_logic_vector(PRESCALER_BITS-1 downto 0);
signal tx_bit_count_expired : std_logic;
signal tx_bit_count : std_logic_vector(2 downto 0);
signal tx_parity : std_logic;
type state_t is (S_IDLE, S_RTR, S_START, S_BITS, S_PARITY, S_STOP_1, S_STOP_2);
signal state : state_t;
signal state_next : state_t;
begin
-- TRANSMISSION VARIABLES
process (i_CLK)
begin
if falling_edge(i_CLK) then
if state = S_IDLE then
tx_frame_parity_en <= i_frame(2);
tx_frame_stop_bits <= i_frame(0);
tx_prescaler <= i_prescaler;
end if;
end if;
end process;
-- shift register
process (i_CLK)
begin
if rising_edge(i_CLK) then
if state = S_IDLE then
tx_shift <= i_Tx_byte;
elsif state = S_BITS and tx_timer_expired = '1' then
tx_shift <= '0' & tx_shift(7 downto 1);
end if;
end if;
end process;
-- baud rate timer
tx_timer_expired <= '1' when tx_timer(PRESCALER_BITS-1 downto 1) = std_logic_vector(to_unsigned(0,PRESCALER_BITS-1)) else '0';
process (i_CLK)
begin
if rising_edge(i_CLK) then
if (state /= state_next) or tx_timer_expired = '1' then
tx_timer <= tx_prescaler;
else
tx_timer <= tx_timer - 1;
end if;
end if;
end process;
-- bit counter & parity calculation
tx_bit_count_expired <= '1' when tx_bit_count = "000" else '0';
process (i_CLK)
begin
if rising_edge(i_CLK) then
if state = S_IDLE then
tx_bit_count <= '1' & i_frame(4 downto 3);
tx_parity <= i_frame(1);
elsif state = S_BITS and tx_timer_expired = '1' then
tx_bit_count <= tx_bit_count - 1;
tx_parity <= tx_parity xor tx_shift(0);
end if;
end if;
end process;
-- STATE MACHINE
process (i_CLK)
begin
if rising_edge(i_CLK) then
if i_reset = '1' or i_frame(7) = '1' then
state <= S_IDLE;
else
state <= state_next;
end if;
end if;
end process;
process (state, i_frame, i_Tx_en, i_cts_n, tx_timer_expired, tx_bit_count_expired, tx_frame_parity_en, tx_frame_stop_bits)
begin
case state is
when S_IDLE =>
if i_frame(6) = '1' or i_Tx_en = '0' then
state_next <= S_IDLE;
elsif i_Tx_en = '1' and (i_cts_n = '0' or i_frame(5) = '0') then
state_next <= S_START;
elsif i_Tx_en = '1' and (i_cts_n = '1' and i_frame(5) = '1') then
state_next <= S_RTR;
else
state_next <= S_IDLE;
end if;
when S_RTR =>
if i_cts_n = '1' and i_frame(5) = '1' then
state_next <= S_RTR;
else
state_next <= S_START;
end if;
when S_START =>
if tx_timer_expired = '1' then
state_next <= S_BITS;
else
state_next <= S_START;
end if;
when S_BITS =>
if tx_bit_count_expired = '0' or tx_timer_expired = '0' then
state_next <= S_BITS;
elsif tx_frame_parity_en = '1' then
state_next <= S_PARITY;
else
state_next <= S_STOP_1;
end if;
when S_PARITY =>
if tx_timer_expired = '1' then
state_next <= S_STOP_1;
else
state_next <= S_PARITY;
end if;
when S_STOP_1 =>
if tx_timer_expired = '0' then
state_next <= S_STOP_1;
elsif tx_frame_stop_bits = '1' then
state_next <= S_STOP_2;
else
state_next <= S_IDLE;
end if;
when S_STOP_2 =>
if tx_timer_expired = '0' then
state_next <= S_STOP_2;
else
state_next <= S_IDLE;
end if;
when others =>
state_next <= S_IDLE;
end case;
end process;
-- OUTPUT
o_busy <= '1' when state /= S_IDLE or i_frame(7) = '1' or i_frame(6) = '1' else '0';
process (state, i_frame, tx_shift, tx_parity)
begin
case state is
when S_IDLE => o_Tx <= not i_frame(6);
when S_START => o_Tx <= '0';
when S_BITS => o_Tx <= tx_shift(0);
when S_PARITY => o_Tx <= tx_parity;
when others => o_Tx <= '1';
end case;
end process;
end architecture;

216
rtl/video/layer2.vhd Normal file
View File

@@ -0,0 +1,216 @@
-- ZX Spectrum Next Layer 2 Bitmap Display
-- Copyright 2020 Alvin Albrecht and Victor Trucco
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity layer2 is
port (
i_CLK_7 : in std_logic; -- pixel clock
i_CLK_28 : in std_logic;
i_sc : in std_logic_vector(1 downto 0); -- 28MHz subcount
i_phc : in std_logic_vector(8 downto 0); -- current x coordinate
i_pvc : in std_logic_vector(8 downto 0); -- current y coordinate
i_whc : in std_logic_vector(8 downto 0); -- current wide x coordinate
i_wvc : in std_logic_vector(8 downto 0); -- current wide y coordinate
i_layer2_en : in std_logic;
i_resolution : in std_logic_vector(1 downto 0); -- 00 = 256x192, 01 = 320x256, 1X = 640x256x4
i_palette_offset : in std_logic_vector(3 downto 0);
i_scroll_x : in std_logic_vector(8 downto 0);
i_scroll_y : in std_logic_vector(7 downto 0);
i_clip_x1 : in std_logic_vector(7 downto 0);
i_clip_x2 : in std_logic_vector(7 downto 0);
i_clip_y1 : in std_logic_vector(7 downto 0);
i_clip_y2 : in std_logic_vector(7 downto 0);
i_layer2_active_bank : in std_logic_vector(6 downto 0); -- starting 16K bank
o_layer2_sram_addr : out std_logic_vector(20 downto 0);
o_layer2_req_t : out std_logic;
i_layer2_sram_di : in std_logic_vector(7 downto 0);
o_layer2_en : out std_logic;
o_layer2_pixel : out std_logic_vector(7 downto 0)
);
end entity;
architecture rtl of layer2 is
signal layer2_en_q : std_logic;
signal layer2_resolution_q : std_logic_vector(1 downto 0);
signal layer2_scroll_x_q : std_logic_vector(8 downto 0);
signal layer2_scroll_y_q : std_logic_vector(7 downto 0);
signal layer2_palette_offset_q : std_logic_vector(3 downto 0);
signal layer2_active_bank_q : std_logic_vector(6 downto 0);
signal clip_x1_q : std_logic_vector(8 downto 0);
signal clip_x2_q : std_logic_vector(8 downto 0);
signal clip_y1_q : std_logic_vector(7 downto 0);
signal clip_y2_q : std_logic_vector(7 downto 0);
signal layer2_wide_res : std_logic;
signal hc : std_logic_vector(8 downto 0);
signal hc_eff : std_logic_vector(8 downto 0);
signal vc_eff : std_logic_vector(8 downto 0);
signal x_pre : std_logic_vector(9 downto 0);
signal x : std_logic_vector(8 downto 0);
signal y_pre : std_logic_vector(8 downto 0);
signal y : std_logic_vector(7 downto 0);
signal layer2_addr : std_logic_vector(16 downto 0);
signal hc_valid : std_logic;
signal vc_valid : std_logic;
signal layer2_clip_en : std_logic;
signal layer2_bank_eff : std_logic_vector(7 downto 0);
signal layer2_addr_eff : std_logic_vector(21 downto 0);
signal layer2_en : std_logic;
signal layer2_req_t : std_logic;
signal layer2_sram_addr : std_logic_vector(20 downto 0);
signal layer2_pixel_qq : std_logic_vector(7 downto 0);
signal layer2_en_qq : std_logic;
signal layer2_hires_qq : std_logic;
signal layer2_pixel_pre : std_logic_vector(7 downto 0);
signal layer2_pixel : std_logic_vector(7 downto 0);
begin
-- capture settings for pixel period
process (i_CLK_7)
begin
if rising_edge(i_CLK_7) then
layer2_en_q <= i_layer2_en;
layer2_resolution_q <= i_resolution;
layer2_scroll_x_q <= i_scroll_x;
layer2_scroll_y_q <= i_scroll_y;
layer2_palette_offset_q <= i_palette_offset;
layer2_active_bank_q <= i_layer2_active_bank;
end if;
end process;
process (i_CLK_7)
begin
if rising_edge(i_CLK_7) then
if i_resolution = "00" then
clip_x1_q <= '0' & i_clip_x1;
clip_x2_q <= '0' & i_clip_x2;
else
clip_x1_q <= i_clip_x1 & '0';
clip_x2_q <= i_clip_x2 & '1';
end if;
clip_y1_q <= i_clip_y1;
clip_y2_q <= i_clip_y2;
end if;
end process;
-- generate layer 2 address one x pixel ahead
layer2_wide_res <= '0' when layer2_resolution_q = "00" else '1';
hc <= i_phc when layer2_wide_res = '0' else i_whc;
hc_eff <= hc + 1;
vc_eff <= i_pvc when layer2_wide_res = '0' else i_wvc;
x_pre <= ('0' & hc_eff) + ('0' & layer2_scroll_x_q);
x(8 downto 6) <= x_pre(8 downto 6) when (layer2_wide_res = '0' or (x_pre(9) = '0' and (x_pre(8) = '0' or x_pre(7 downto 6) = "00"))) else (x_pre(8 downto 6) + "011");
x(5 downto 0) <= x_pre(5 downto 0);
y_pre <= vc_eff + ('0' & layer2_scroll_y_q);
y(7 downto 6) <= y_pre(7 downto 6) when (layer2_wide_res = '1' or (y_pre(8) = '0' and y_pre(7 downto 6) /= "11")) else (y_pre(7 downto 6) + 1);
y(5 downto 0) <= y_pre(5 downto 0);
layer2_addr <= ('0' & y & x(7 downto 0)) when layer2_wide_res = '0' else (x & y);
-- clip
hc_valid <= '1' when (layer2_wide_res = '0' and hc_eff(8) = '0') or (layer2_wide_res = '1' and (hc_eff(8) = '0' or hc_eff(7 downto 6) = "00")) else '0';
vc_valid <= '1' when (layer2_wide_res = '1' and vc_eff(8) = '0') or (layer2_wide_res = '0' and (vc_eff(8) = '0' and vc_eff(7 downto 6) /= "11")) else '0';
layer2_clip_en <= '1' when (hc_eff >= clip_x1_q) and (hc_eff <= clip_x2_q) and (vc_eff >= ('0' & clip_y1_q)) and (vc_eff <= ('0' & clip_y2_q)) and (hc_valid = '1') and (vc_valid = '1') else '0';
-- generate sram cycle
-- 0x040000 - 0x05FFFF (128K) => ZX Spectrum RAM A20:A16 = 00100,BB max 11011,11
layer2_bank_eff <= (('0' & layer2_active_bank_q(6 downto 4)) + 1) & layer2_active_bank_q(3 downto 0);
layer2_addr_eff <= (layer2_bank_eff + ("00000" & layer2_addr(16 downto 14))) & layer2_addr(13 downto 0);
layer2_en <= '1' when layer2_en_q = '1' and layer2_clip_en = '1' and layer2_addr_eff(21) = '0' and layer2_addr_eff(20 downto 18) /= "111" else '0';
process (i_CLK_28)
begin
if rising_edge(i_CLK_28) then
if i_sc = "00" then
if layer2_en = '1' then
layer2_req_t <= not layer2_req_t;
end if;
layer2_sram_addr <= layer2_addr_eff(20 downto 0);
layer2_pixel_qq <= i_layer2_sram_di;
end if;
end if;
end process;
o_layer2_sram_addr <= layer2_sram_addr;
o_layer2_req_t <= layer2_req_t;
-- generate pixels
process (i_CLK_7) begin
if rising_edge(i_CLK_7) then
layer2_en_qq <= layer2_en;
layer2_hires_qq <= layer2_resolution_q(1);
end if;
end process;
layer2_pixel_pre <= layer2_pixel_qq when layer2_hires_qq = '0' else ("0000" & layer2_pixel_qq(7 downto 4)) when i_sc(1) = '0' else ("0000" & layer2_pixel_qq(3 downto 0));
layer2_pixel <= (layer2_pixel_pre(7 downto 4) + layer2_palette_offset_q) & layer2_pixel_pre(3 downto 0);
process (i_CLK_28)
begin
if rising_edge(i_CLK_28) then
if i_sc(0) = '1' then
o_layer2_pixel <= layer2_pixel;
end if;
end if;
end process;
o_layer2_en <= layer2_en_qq;
end architecture;

117
rtl/video/lores.vhd Normal file
View File

@@ -0,0 +1,117 @@
-- ZX Spectrum Next LoRes Display
-- Copyright 2020 Victor Trucco and Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
-- LoRes video mode
-- 128 x 96, 8-bit colour
-- $4000-$57FF for top half
-- $6000-$77FF for bottom half
--
-- LoRes radastan (original mode from zx uno <http://zxuno.speccy.org/>)
-- 128 x 96, 4-bit colour
-- $4000 - $57ff if timex dfile 0 active
-- $6000 - $77ff if timex dfile 1 active
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity lores is
port (
mode_i : in std_logic; -- 0 = lores, 1 = radastan
dfile_i : in std_logic; -- timex display file to use for radastan
ulap_en_i : in std_logic; -- 1 = ula plus enabled
lores_palette_offset_i : in std_logic_vector(3 downto 0);
hc_i : in std_logic_vector(8 downto 0); -- current x coordinate
vc_i : in std_logic_vector(8 downto 0); -- current y coordinate
clip_x1_i : in std_logic_vector(7 downto 0);
clip_x2_i : in std_logic_vector(7 downto 0);
clip_y1_i : in std_logic_vector(7 downto 0);
clip_y2_i : in std_logic_vector(7 downto 0);
scroll_x_i : in std_logic_vector(7 downto 0);
scroll_y_i : in std_logic_vector(7 downto 0);
lores_addr_o : out std_logic_vector(13 downto 0); -- bank 5 offset
lores_data_i : in std_logic_vector(7 downto 0);
lores_pixel_o : out std_logic_vector(7 downto 0);
lores_pixel_en_o : out std_logic -- 1 = valid pixel
);
end entity;
architecture rtl of lores is
signal x : std_logic_vector(7 downto 0);
signal y : std_logic_vector(7 downto 0);
signal y_pre : std_logic_vector(8 downto 0);
signal lores_addr : std_logic_vector(13 downto 0);
signal lores_addr_pre : std_logic_vector(13 downto 0);
signal lores_addr_rad : std_logic_vector(13 downto 0);
signal pixel_lores_nib_H : std_logic_vector(3 downto 0);
signal pixel_rad_nib_L : std_logic_vector(3 downto 0);
signal pixel_rad_nib_H : std_logic_vector(3 downto 0);
begin
-- generate pixel coordinate
x <= hc_i(7 downto 0) + scroll_x_i;
y_pre <= vc_i + ('0' & scroll_y_i);
y(7 downto 6) <= (y_pre(7 downto 6) + 1) when y_pre >= 192 else y_pre(7 downto 6);
y(5 downto 0) <= y_pre(5 downto 0);
-- generate pixel address
lores_addr_pre <= y(7 downto 1) & x(7 downto 1);
lores_addr(13 downto 11) <= (lores_addr_pre(13 downto 11) + 1) when y >= 96 else lores_addr_pre(13 downto 11);
lores_addr(10 downto 0) <= lores_addr_pre(10 downto 0);
lores_addr_rad <= dfile_i & y(7 downto 1) & x(7 downto 2);
lores_addr_o <= lores_addr when mode_i = '0' else lores_addr_rad;
-- generate pixel out lores
pixel_lores_nib_H <= lores_data_i(7 downto 4) + lores_palette_offset_i;
-- generate pixel out lores radastan
pixel_rad_nib_L <= lores_data_i(7 downto 4) when x(1) = '0' else lores_data_i(3 downto 0);
pixel_rad_nib_H <= lores_palette_offset_i when ulap_en_i = '0' else ("11" & lores_palette_offset_i(1 downto 0));
-- pixel out
lores_pixel_o <= (pixel_rad_nib_H & pixel_rad_nib_L) when mode_i = '1' else (pixel_lores_nib_H & lores_data_i(3 downto 0));
-- clip
lores_pixel_en_o <= '1' when (hc_i >= '0' & clip_x1_i) and (hc_i <= '0' & clip_x2_i) and (vc_i >= '0' & clip_y1_i) and (vc_i <= '0' & clip_y2_i) else '0';
end architecture;

1088
rtl/video/sprites.vhd Normal file

File diff suppressed because it is too large Load Diff

448
rtl/video/tilemap.vhd Normal file
View File

@@ -0,0 +1,448 @@
-- ZX Spectrum Next Tilemap Display
-- Copyright 2020 Alvin Albrecht
--
-- Ideas - Spectrum Next Team
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
-- Currently the hi-res pixel fetch requires 26/32 cycles at 28MHz to accommodate
-- a scrolling screen but this can be improved to 23 cycles. -- AA
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity tilemap is
port (
reset_i : in std_logic;
clock_master_i : in std_logic; -- 28MHz synchronized with 7MHz pixel clock
clock_master_180o_i : in std_logic; -- 28MHz inverted
hcounter_i : in unsigned(8 downto 0); -- sprite counter 0-319 visible area
vcounter_i : in unsigned(8 downto 0); -- sprite counter 0-255 visible area
subpixel_i : in std_logic_vector(1 downto 0); -- 28MHz subpixel count
control_i : in std_logic_vector(6 downto 0);
default_flags_i : in std_logic_vector(7 downto 0); -- default flags if tilemap flags are eliminated
transp_colour_i : in std_logic_vector(3 downto 0);
-- ULA Memory Interface
tm_mem_bank7_o : out std_logic;
tm_mem_addr_o : out std_logic_vector(13 downto 0);
tm_mem_rd_o : out std_logic;
tm_mem_ack_i : in std_logic;
tm_mem_data_i : in std_logic_vector(7 downto 0);
-- Memory Map
tm_map_base_i : in std_logic_vector(6 downto 0); -- bit 6 is bank selector, 5:0 are offsets into 16K
tm_tile_base_i : in std_logic_vector(6 downto 0); -- bit 6 is bank selector, 5:0 are offsets into 16K
-- Out
pixel_o : out std_logic_vector(7 downto 0); -- tilemap pixel
pixel_en_o : out std_logic; -- tilemap pixel is valid
pixel_below_o : out std_logic; -- tilemap pixel should cover ula pixel
pixel_textmode_o : out std_logic; -- tilemap pixel is a textmode pixel
-- Scroll
tm_scroll_x_i : in std_logic_vector(9 downto 0);
tm_scroll_y_i : in std_logic_vector(7 downto 0);
-- Clip Window
clip_x1_i : in unsigned(7 downto 0);
clip_x2_i : in unsigned(7 downto 0);
clip_y1_i : in unsigned(7 downto 0);
clip_y2_i : in unsigned(7 downto 0)
);
end entity;
architecture rtl of tilemap is
-- coregen
component sdpram_16_9 is
port (
DPRA : IN STD_LOGIC_VECTOR(4-1 downto 0) := (OTHERS => '0');
CLK : IN STD_LOGIC;
WE : IN STD_LOGIC;
DPO : OUT STD_LOGIC_VECTOR(9-1 downto 0);
A : IN STD_LOGIC_VECTOR(4-1-(4*0*boolean'pos(4>4)) downto 0) := (OTHERS => '0');
D : IN STD_LOGIC_VECTOR(9-1 downto 0) := (OTHERS => '0')
);
end component;
--
signal mode_i : std_logic; -- 1 = 80x32, 0 = 40x32
signal strip_flags_i : std_logic; -- 1 = eliminate flags from tilemap
signal textmode_i : std_logic; -- 1 = extend palette offset to 7 bits at expense of rotations and mirrors
-- signal reduced_tm_i : std_logic; -- 1 = tilemap area reduced to 64x24 / 32x24
-- signal split_addr_i : std_logic; -- 1 = tilemap flags and tiles split between two 8k halves
signal mode_512_i : std_logic; -- 1 = 512 tile mode
signal tm_on_top_i : std_logic; -- 1 = tilemap is always on top
signal tm_mem_fetch : std_logic;
signal tm_pixel_half_wr : std_logic;
signal tm_pixel_half_rd : std_logic;
signal tm_mode : std_logic;
signal hcount : std_logic_vector(10 downto 0);
signal hcount_eff : std_logic_vector(9 downto 0);
signal hcount_effsub : std_logic_vector(9 downto 0);
signal tm_mem_ack_d : std_logic;
-- tilemap pixel loader
type state_t is (S_IDLE, S_READ_TILE_0, S_READ_TILE_1, S_READ_PIXELS);
signal state_s : state_t;
signal next_state_s : state_t;
signal tm_abs_x : std_logic_vector(9 downto 0);
signal tm_abs_y : std_logic_vector(11 downto 0);
signal tm_pixel : std_logic_vector(2 downto 0);
signal tm_tilemap_0 : std_logic_vector(7 downto 0);
signal tm_tilemap_1 : std_logic_vector(7 downto 0);
signal tm_tile_base_q : std_logic_vector(6 downto 0);
signal tm_map_base_q : std_logic_vector(6 downto 0);
signal tm_strip_flags_q : std_logic;
signal textmode_q : std_logic;
signal mode_512_q : std_logic;
signal tm_on_top_q : std_logic;
signal textmode_0 : std_logic;
signal textmode_1 : std_logic;
signal tm_next_pixel : std_logic_vector(2 downto 0);
signal tm_x_addend_0 : std_logic_vector(9 downto 0);
signal tm_x_addend_1 : std_logic_vector(9 downto 0);
signal tm_x_sum : std_logic_vector(10 downto 0);
signal tm_x_correction : std_logic_vector(3 downto 0);
signal tm_next_abs_x : std_logic_vector(9 downto 0);
signal tm_abs_y_s : std_logic_vector(7 downto 0);
signal tm_abs_y_mult_sub : std_logic_vector(7 downto 0);
signal tm_abs_y_mult : std_logic_vector(8 downto 0);
signal tm_effective_x_mirror : std_logic;
signal tm_effective_x : std_logic_vector(2 downto 0);
signal tm_effective_y : std_logic_vector(2 downto 0);
signal tm_transformed_x : std_logic_vector(2 downto 0);
signal tm_transformed_y : std_logic_vector(2 downto 0);
signal tm_tilemap_pixel_waddr : std_logic_vector(3 downto 0);
signal tm_tilemap_pixel_we : std_logic;
signal tm_tilemap_pixel_data_standard : std_logic_vector(7 downto 0);
signal tm_tilemap_pixel_data_textmode_shift : std_logic_vector(7 downto 0);
signal tm_tilemap_pixel_data_textmode : std_logic_vector(7 downto 0);
signal tm_tilemap_pixel_wdata : std_logic_vector(8 downto 0);
signal tm_mem_addr_pix_sub_sub : std_logic_vector(8 downto 0);
signal tm_mem_addr_pix_sub : std_logic_vector(13 downto 0);
signal tm_mem_addr_tile_sub : std_logic_vector(13 downto 0);
signal tm_mem_addr_tile_sub_sub : std_logic_vector(11 downto 0);
signal tm_mem_addr_sub : std_logic_vector(13 downto 0);
signal tm_mem_addr_offset : std_logic_vector(6 downto 0);
-- VIDEO OUT
signal video_addr : std_logic_vector(3 downto 0);
signal video_data : std_logic_vector(8 downto 0);
signal xsv : unsigned(8 downto 0);
signal xev : unsigned(8 downto 0);
signal ysv : unsigned(7 downto 0);
signal yev : unsigned(7 downto 0);
signal pixel_en_s : std_logic;
signal pixel_en_f : std_logic;
signal pixel_textmode_s : std_logic;
signal pixel_en_standard_s : std_logic;
signal video_data_q : std_logic_vector(10 downto 0);
begin
--------------------------
-- TILEMAP CONTROL ALIASES
--------------------------
mode_i <= control_i(6); -- 0 = 40x32, 1 = 80x32
strip_flags_i <= control_i(5); -- 1 = eliminate tilemap flags
textmode_i <= control_i(3); -- 1 = extend palette offset to 7 bits at expense of rotations and mirrors
-- reduced_tm_i <= control_i(3); -- 1 = select reduced tilemap area (32x24 or 64x24) NOT IMPLEMENTED
-- split_addr_i <= control_i(2); -- 1 = select split addressing NOT IMPLEMENTED
mode_512_i <= control_i(1); -- 1 = select 512 tile mode
tm_on_top_i <= control_i(0); -- 1 = tilemap always on top of ula
-----------------------
-- TILEMAP PIXEL MEMORY
-----------------------
tilemem : sdpram_16_9
port map (
DPRA => video_addr,
CLK => clock_master_i,
WE => tm_tilemap_pixel_we,
DPO => video_data,
A => tm_tilemap_pixel_waddr,
D => tm_tilemap_pixel_wdata
);
-------------
-- SCHEDULING
-------------
hcount <= std_logic_vector(hcounter_i(8 downto 0)) & subpixel_i;
process (clock_master_i)
begin
if rising_edge(clock_master_i) then
if reset_i = '1' then
tm_mode <= '0';
elsif hcount(4 downto 0) = "11111" then
tm_mode <= mode_i;
end if;
end if;
end process;
hcount_effsub <= hcount(10 downto 1) when tm_mode = '1' else ((hcount(10) and hcount(9)) & hcount(10 downto 2)); -- sign extend
hcount_eff <= (hcount_effsub(9 downto 3) + 1) & hcount_effsub(2 downto 0); -- one character ahead
tm_mem_fetch <= '1' when hcount_eff(2 downto 0) = "000" else '0';
process (clock_master_i)
begin
if rising_edge(clock_master_i) then
if reset_i = '1' then
tm_pixel_half_wr <= '0';
elsif hcount_eff(2 downto 0) = "111" and hcount(1 downto 0) = "11" then
tm_pixel_half_wr <= not tm_pixel_half_wr;
end if;
end if;
end process;
tm_pixel_half_rd <= not tm_pixel_half_wr;
process (clock_master_180o_i)
begin
if rising_edge(clock_master_180o_i) then
tm_mem_ack_d <= tm_mem_ack_i;
end if;
end process;
-----------------------
-- TILEMAP PIXEL LOADER
-----------------------
-- state
process (clock_master_i)
begin
if rising_edge(clock_master_i) then
if reset_i = '1' then
state_s <= S_IDLE;
elsif hcount_eff(2 downto 0) = "111" and hcount(1 downto 0) = "11" then
state_s <= S_IDLE;
else
state_s <= next_state_s;
end if;
end if;
end process;
-- next state combinatorial
process (state_s, tm_mem_fetch, tm_mem_ack_d, tm_next_pixel, tm_abs_x, tm_next_abs_x)
begin
case state_s is
when S_IDLE => if tm_mem_fetch = '1' then
next_state_s <= S_READ_TILE_0;
else
next_state_s <= S_IDLE;
end if;
when S_READ_TILE_0 => if tm_mem_ack_d = '1' then
next_state_s <= S_READ_TILE_1;
else
next_state_s <= S_READ_TILE_0;
end if;
when S_READ_TILE_1 => if tm_mem_ack_d = '1' then
next_state_s <= S_READ_PIXELS;
else
next_state_s <= S_READ_TILE_1;
end if;
when S_READ_PIXELS => if tm_mem_ack_d = '0' then
next_state_s <= S_READ_PIXELS;
elsif tm_next_pixel = "000" then
next_state_s <= S_IDLE;
elsif tm_next_abs_x(3) /= tm_abs_x(3) then
next_state_s <= S_READ_TILE_0;
else
next_state_s <= S_READ_PIXELS;
end if;
when others => next_state_s <= S_IDLE;
end case;
end process;
-- state machine variables
tm_next_pixel <= tm_pixel + 1;
tm_x_addend_0 <= tm_scroll_x_i when state_s = S_IDLE else tm_abs_x;
tm_x_addend_1 <= hcount_eff when state_s = S_IDLE else "0000000001";
tm_x_sum <= ('0' & tm_x_addend_0) + ('0' & tm_x_addend_1);
tm_x_correction <= "1100" when tm_x_sum >= 1280 else
"0001" when tm_x_sum >= 960 and tm_mode = '0' else
"0110" when tm_x_sum >= 640 else
"1011" when tm_x_sum >= 320 and tm_mode = '0' else
"0000";
tm_next_abs_x(9 downto 6) <= tm_x_sum(9 downto 6) + tm_x_correction;
tm_next_abs_x(5 downto 0) <= tm_x_sum(5 downto 0);
tm_effective_x_mirror <= tm_tilemap_1(3) xor tm_tilemap_1(1); -- rotation inverts x mirror
tm_effective_x <= tm_abs_x(2 downto 0) when tm_effective_x_mirror = '0' else not (tm_abs_x(2 downto 0)); -- x mirror inverts x coord
tm_effective_y <= tm_abs_y(2 downto 0) when tm_tilemap_1(2) = '0' else not (tm_abs_y(2 downto 0)); -- y mirror inverts y coord
tm_transformed_x <= tm_effective_x when tm_tilemap_1(1) = '0' else tm_effective_y; -- rotation exchanges x and y
tm_transformed_y <= tm_effective_y when tm_tilemap_1(1) = '0' else tm_effective_x;
tm_abs_y_s <= tm_scroll_y_i + std_logic_vector(vcounter_i(7 downto 0));
tm_abs_y_mult_sub <= ('0' & tm_abs_y_s(7 downto 3) & "00") + ("000" & tm_abs_y_s(7 downto 3)); -- * 5
tm_abs_y_mult <= '0' & tm_abs_y_mult_sub when tm_mode = '0' else tm_abs_y_mult_sub & '0';
process (clock_master_i)
begin
if rising_edge(clock_master_i) then
if reset_i = '1' then
tm_abs_x <= (others => '0');
tm_abs_y <= (others => '0');
tm_pixel <= (others => '0');
tm_tilemap_0 <= (others => '0');
tm_tilemap_1 <= (others => '0');
tm_map_base_q <= (others => '0');
tm_tile_base_q <= (others => '0');
tm_strip_flags_q <= '0';
textmode_q <= '0';
mode_512_q <= '0';
tm_on_top_q <= '0';
elsif state_s = S_IDLE then
tm_abs_x <= tm_next_abs_x;
tm_abs_y <= tm_abs_y_mult & tm_abs_y_s(2 downto 0);
tm_pixel <= (others => '0');
tm_map_base_q <= tm_map_base_i;
tm_tile_base_q <= tm_tile_base_i;
tm_strip_flags_q <= strip_flags_i;
textmode_q <= textmode_i;
mode_512_q <= mode_512_i;
tm_on_top_q <= tm_on_top_i;
elsif state_s = S_READ_TILE_0 then
tm_tilemap_0 <= tm_mem_data_i;
if tm_pixel_half_wr = '0' then
textmode_0 <= textmode_q;
else
textmode_1 <= textmode_q;
end if;
elsif state_s = S_READ_TILE_1 then
if tm_strip_flags_q = '0' then
tm_tilemap_1 <= tm_mem_data_i;
else
tm_tilemap_1 <= default_flags_i;
end if;
elsif state_s = S_READ_PIXELS then
if tm_mem_ack_d = '1' then
tm_pixel <= tm_next_pixel;
tm_abs_x <= tm_next_abs_x;
end if;
end if;
end if;
end process;
-- write pixel data to local memory
tm_tilemap_pixel_waddr <= tm_pixel_half_wr & tm_pixel;
tm_tilemap_pixel_we <= '1' when state_s = S_READ_PIXELS else '0';
tm_tilemap_pixel_data_standard(7 downto 4) <= tm_tilemap_1(7 downto 4);
tm_tilemap_pixel_data_standard(3 downto 0) <= tm_mem_data_i(7 downto 4) when tm_transformed_x(0) = '0' else tm_mem_data_i(3 downto 0);
tm_tilemap_pixel_data_textmode_shift <= std_logic_vector(shift_left(unsigned(tm_mem_data_i), to_integer(unsigned(tm_abs_x(2 downto 0)))));
tm_tilemap_pixel_data_textmode <= tm_tilemap_1(7 downto 1) & tm_tilemap_pixel_data_textmode_shift(7);
tm_tilemap_pixel_wdata(8) <= (tm_tilemap_1(0) or mode_512_q) and not tm_on_top_q;
tm_tilemap_pixel_wdata(7 downto 0) <= tm_tilemap_pixel_data_standard when textmode_q = '0' else tm_tilemap_pixel_data_textmode;
-- read from external memory
tm_mem_addr_pix_sub_sub <= (mode_512_q and tm_tilemap_1(0)) & tm_tilemap_0;
tm_mem_addr_pix_sub <= (tm_mem_addr_pix_sub_sub & tm_transformed_y & tm_transformed_x(2 downto 1)) when textmode_q = '0' else ("00" & tm_mem_addr_pix_sub_sub & tm_abs_y(2 downto 0));
tm_mem_addr_tile_sub_sub <= (tm_abs_y(11 downto 3) + ("00000" & tm_abs_x(9 downto 6))) & tm_abs_x(5 downto 3);
tm_mem_addr_tile_sub <= '0' & tm_mem_addr_tile_sub_sub & '0' when state_s = S_READ_TILE_0 and tm_strip_flags_q = '0' else
'0' & tm_mem_addr_tile_sub_sub & '1' when tm_strip_flags_q = '0' else
"00" & tm_mem_addr_tile_sub_sub;
tm_mem_addr_sub <= tm_mem_addr_pix_sub when state_s = S_READ_PIXELS else tm_mem_addr_tile_sub;
tm_mem_addr_offset <= tm_tile_base_q when state_s = S_READ_PIXELS else tm_map_base_q;
tm_mem_bank7_o <= tm_mem_addr_offset(6);
tm_mem_addr_o <= (tm_mem_addr_sub(13 downto 8) + tm_mem_addr_offset(5 downto 0)) & tm_mem_addr_sub(7 downto 0);
tm_mem_rd_o <= '0' when state_s = S_IDLE else '1';
------------------------
-- GENERATE VIDEO OUTPUT
------------------------
video_addr <= tm_pixel_half_rd & hcount_eff(2 downto 0);
process (clock_master_i)
begin
if rising_edge(clock_master_i) then
if hcount(1 downto 0) = "11" then -- rising edge of 7MHz
xsv <= clip_x1_i & '0';
xev <= clip_x2_i & '1';
ysv <= clip_y1_i;
yev <= clip_y2_i;
end if;
end if;
end process;
pixel_en_s <= '1' when (hcounter_i < 320) and (vcounter_i(8) = '0') and (hcounter_i >= xsv) and (hcounter_i <= xev) and (vcounter_i >= ysv) and (vcounter_i <= yev) else '0';
pixel_textmode_s <= (textmode_0 and not tm_pixel_half_rd) or (textmode_1 and tm_pixel_half_rd);
pixel_en_standard_s <= '1' when pixel_en_s = '1' and (video_data(3 downto 0) /= transp_colour_i) else '0';
pixel_en_f <= (pixel_en_standard_s and not pixel_textmode_s) or (pixel_en_s and pixel_textmode_s);
process (clock_master_i)
begin
if rising_edge(clock_master_i) then
if reset_i = '1' then
video_data_q <= (others => '0');
elsif hcount(0) = '1' then -- rising edge of 14MHz
video_data_q(10) <= pixel_textmode_s;
video_data_q(9 downto 0) <= pixel_en_f & video_data;
end if;
end if;
end process;
pixel_textmode_o <= video_data_q(10);
pixel_en_o <= video_data_q(9);
pixel_below_o <= video_data_q(8);
pixel_o <= video_data_q(7 downto 0);
end architecture;

603
rtl/video/zxula.vhd Normal file
View File

@@ -0,0 +1,603 @@
-- ZX Spectrum Next ULA
-- Copyright 2020 Alvin Albrecht, Fabio Belavenuto and Victor Trucco
-- Thanks to Kev Brady for creating tests comparing original hardware
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
--
-- Features of this implementation:
--
-- * compatible with 48k, 128k, +3, pentagon ula including contention and floating bus
-- * hardware pixel scrolling in X and Y
-- * implements timex hi-res, hi-colour and dual screen
-- * dynamic choice of ULAnext, ULA+ and standard ula palette
--
-- References:
--
-- "The ZX Spectrum ULA: How to Design a Microcomputer", (c) 2010 Chris Smith
-- https://faqwiki.zxnet.co.uk/wiki/Contended_memory Emulator Reference
-- https://zxnet.co.uk/spectrum/schematics/Z70830.pdf +3 Schematic
-- http://sky.relative-path.com/zx/floating_bus.html by Ast A Moore
-- http://sblive.narod.ru/ZX-Spectrum/Pentagon128k/Pentagon128k.htm by Z.A.N.
--
-- The implementation was simplified somewhat from Chris Smith's description and then
-- was complicated by the addition of pixel scrolling and re-interpretation of the
-- attribute byte. It's likely possible to reduce the number of registers used
-- but only at the expense of clarity.
--
-- The display position as seen by the ULA and as described in Chris' book is held
-- in i_vc and i_hc. There is a second horizontal counter i_phc which is a practical
-- counter in that 0 corresponds to when the system is actually generating pixel 0.
-- This position corresponds to ULA count i_hc = 0xC.
--
-- Because display memory is held in dual port bram, there is no real contention in
-- the zx next. Instead contention is simulated at the exact moments it would occur
-- on the original machine. And because there is no shortage of memory bandwidth to
-- bram, this implementation may continually access bram even outside the display area
-- with no detrimental impact on the system.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity zxula is
port (
i_CLK_7 : in std_logic;
i_CLK_14 : in std_logic;
i_CLK_CPU : in std_logic;
i_cpu_mreq_n : in std_logic;
i_cpu_iorq_n : in std_logic;
i_hc : in std_logic_vector(8 downto 0);
i_vc : in std_logic_vector(8 downto 0);
i_phc : in std_logic_vector(8 downto 0);
i_timing_pentagon : in std_logic;
i_timing_p3 : in std_logic;
i_port_ff_reg : in std_logic_vector(5 downto 0);
i_port_fe_border : in std_logic_vector(2 downto 0);
i_ula_shadow_en : in std_logic;
i_ulanext_en : in std_logic;
i_ulanext_format : in std_logic_vector(7 downto 0);
i_ulap_en : in std_logic;
o_ula_vram_a : out std_logic_vector(13 downto 0);
o_ula_shadow : out std_logic;
o_ula_vram_rd : out std_logic;
i_ula_vram_d : in std_logic_vector(7 downto 0);
o_ula_border : out std_logic;
o_ula_pixel : out std_logic_vector(7 downto 0);
o_ula_select_bgnd : out std_logic;
o_ula_clipped : out std_logic;
i_ula_clip_x1 : in std_logic_vector(7 downto 0);
i_ula_clip_x2 : in std_logic_vector(7 downto 0);
i_ula_clip_y1 : in std_logic_vector(7 downto 0);
i_ula_clip_y2 : in std_logic_vector(7 downto 0);
i_ula_scroll_x : in std_logic_vector(7 downto 0);
i_ula_scroll_y : in std_logic_vector(7 downto 0);
i_ula_fine_scroll_x : in std_logic;
i_p3_floating_bus : in std_logic_vector(7 downto 0);
o_ula_floating_bus : out std_logic_vector(7 downto 0);
i_contention_en : in std_logic;
i_contention_port : in std_logic;
i_contention_memory : in std_logic;
o_cpu_wait_n : out std_logic;
o_cpu_contend : out std_logic
);
end entity;
architecture rtl of zxula is
signal screen_mode_s : std_logic_vector(2 downto 0);
signal screen_mode : std_logic_vector(2 downto 0);
signal py_s : std_logic_vector(8 downto 0);
signal py : std_logic_vector(7 downto 0);
signal px : std_logic_vector(8 downto 0);
signal px_1 : std_logic_vector(8 downto 0);
signal ula_shadow : std_logic;
signal addr_p_spc_12_5 : std_logic_vector(7 downto 0);
signal addr_a_spc_12_5 : std_logic_vector(7 downto 0);
signal vram_rd : std_logic;
signal vram_a : std_logic_vector(13 downto 0);
signal pbyte00 : std_logic_vector(7 downto 0);
signal pbyte01 : std_logic_vector(7 downto 0);
signal abyte00 : std_logic_vector(7 downto 0);
signal abyte01 : std_logic_vector(7 downto 0);
signal pbyte10 : std_logic_vector(7 downto 0);
signal pbyte11 : std_logic_vector(7 downto 0);
signal abyte10 : std_logic_vector(7 downto 0);
signal abyte11 : std_logic_vector(7 downto 0);
signal floating_bus_r : std_logic_vector(7 downto 0);
signal floating_bus_en : std_logic;
signal screen_mode_0 : std_logic_vector(2 downto 0);
signal screen_mode_1 : std_logic_vector(2 downto 0);
signal scroll_0 : std_logic_vector(3 downto 0);
signal scroll_1 : std_logic_vector(3 downto 0);
signal sload_0 : std_logic;
signal sload_1 : std_logic;
signal sload_x : std_logic;
signal sload_d : std_logic;
signal sload : std_logic;
signal shift_pbyte : std_logic_vector(15 downto 0);
signal shift_abyte : std_logic_vector(15 downto 0);
signal shift_screen_mode : std_logic_vector(2 downto 0);
signal shift_scroll : std_logic_vector(3 downto 0);
signal shift_reg_32 : std_logic_vector(31 downto 0);
signal shift_reg_ld : std_logic_vector(31 downto 0);
signal shift_reg : std_logic_vector(15 downto 0);
signal border_active_v : std_logic;
signal border_active : std_logic;
signal border_active_d : std_logic;
signal border_active_ula : std_logic;
signal border_clr : std_logic_vector(7 downto 0);
signal border_clr_tmx : std_logic_vector(7 downto 0);
signal attr_reg : std_logic_vector(15 downto 0);
signal attr_scroll_r : std_logic_vector(4 downto 0);
signal screen_mode_r : std_logic_vector(2 downto 0);
signal attr_active : std_logic_vector(7 downto 0);
signal pixel_en : std_logic;
signal flash_cnt : std_logic_vector(4 downto 0);
signal ula_select_bgnd : std_logic;
signal ula_pixel : std_logic_vector(7 downto 0);
signal hc_adj : std_logic_vector(3 downto 0);
signal wait_s : std_logic;
signal mreq23_n : std_logic;
signal ioreqtw3_n : std_logic;
begin
--
-- MEMORY FETCH
--
-- Sample Display Mode and Scroll Amount Prior to Address Generation
screen_mode_s <= i_port_ff_reg(2 downto 0) when i_ula_shadow_en = '0' else "000"; -- limit timex modes to bank 5 as bank 7 only has 8k bram
py_s <= i_vc + ('0' & i_ula_scroll_y);
process (i_CLK_7)
begin
if falling_edge(i_CLK_7) then
if i_hc(3 downto 0) = X"3" or i_hc(3 downto 0) = X"B" then
px <= i_ula_fine_scroll_x & (i_hc(7 downto 3) + i_ula_scroll_x(7 downto 3)) & i_ula_scroll_x(2 downto 0);
if py_s(8 downto 7) = "11" then
py <= (not py_s(7)) & py_s(6 downto 0);
elsif py_s(8) = '1' or py_s(7 downto 6) = "11" then
py <= (py_s(7 downto 6) + 1) & py_s(5 downto 0);
else
py <= py_s(7 downto 0);
end if;
screen_mode <= screen_mode_s;
ula_shadow <= i_ula_shadow_en;
end if;
end if;
end process;
px_1 <= px(8) & (px(7 downto 3) + 1) & px(2 downto 0);
-- Generate memory read cycles
-- Cycles 0x8,0x9 and 0xC,0xD read pixel bytes
-- Cycles 0xA,0xB and 0xE,0xF read attribute bytes
addr_p_spc_12_5 <= py(7 downto 6) & py(2 downto 0) & py(5 downto 3);
addr_a_spc_12_5 <= "110" & py(7 downto 3);
process (i_CLK_7)
begin
if rising_edge(i_CLK_7) then
vram_rd <= '0';
case i_hc(3 downto 0) is
when X"F" | X"3" =>
vram_a <= screen_mode(0) & addr_p_spc_12_5 & px_1(7 downto 3);
when X"1" | X"5" =>
if screen_mode(1) = '1' then
vram_a <= '1' & addr_p_spc_12_5 & px_1(7 downto 3);
else
vram_a <= screen_mode(0) & addr_a_spc_12_5 & px_1(7 downto 3);
end if;
when X"7" | X"B" =>
vram_a <= screen_mode(0) & addr_p_spc_12_5 & px(7 downto 3);
when X"9" | X"D" =>
if screen_mode(1) = '1' then
vram_a <= '1' & addr_p_spc_12_5 & px(7 downto 3);
else
vram_a <= screen_mode(0) & addr_a_spc_12_5 & px(7 downto 3);
end if;
when X"0" | X"2" | X"4" | X"6" | X"8" | X"A" | X"C" | X"E" =>
vram_rd <= '1';
when others =>
null;
end case;
end if;
end process;
o_ula_vram_a <= vram_a;
o_ula_vram_rd <= vram_rd;
o_ula_shadow <= ula_shadow;
-- Record bytes read from memory and associated mode information
process (i_CLK_7)
begin
if falling_edge(i_CLK_7) then
case i_hc(3 downto 0) is
when X"1" =>
pbyte11 <= i_ula_vram_d;
when X"3" =>
abyte11 <= i_ula_vram_d;
when X"5" =>
pbyte01 <= i_ula_vram_d;
when X"7" =>
abyte01 <= i_ula_vram_d;
when X"9" =>
pbyte00 <= i_ula_vram_d;
when X"B" =>
abyte00 <= i_ula_vram_d;
when X"D" =>
pbyte10 <= i_ula_vram_d;
when X"F" =>
abyte10 <= i_ula_vram_d;
when others => null;
end case;
end if;
end process;
process (i_CLK_7)
begin
if falling_edge(i_CLK_7) then
if border_active_ula = '1' then
floating_bus_r <= X"FF";
floating_bus_en <= '0';
else
case i_hc(3 downto 0) is
when X"1" =>
floating_bus_r <= X"FF";
floating_bus_en <= '0';
when X"9" =>
floating_bus_r <= i_ula_vram_d;
floating_bus_en <= '1';
when X"B" =>
floating_bus_r <= i_ula_vram_d;
when X"D" =>
floating_bus_r <= i_ula_vram_d;
when X"F" =>
floating_bus_r <= i_ula_vram_d;
when others => null;
end case;
end if;
end if;
end process;
process (i_CLK_7)
begin
if rising_edge(i_CLK_7) then
if i_hc(3 downto 0) = X"7" then
screen_mode_0 <= screen_mode;
scroll_0 <= px(2 downto 0) & px(8);
end if;
if i_hc(3 downto 0) = X"B" then
screen_mode_1 <= screen_mode;
scroll_1 <= px(2 downto 0) & px(8);
end if;
end if;
end process;
--
-- PIXEL SHIFT REGISTER
--
sload_0 <= '1' when i_hc(3 downto 0) = X"C" else '0';
sload_1 <= '1' when i_hc(3 downto 0) = X"4" else '0';
sload_x <= sload_0 or sload_1;
process (i_CLK_14)
begin
if rising_edge(i_CLK_14) then
sload_d <= sload_x;
end if;
end process;
sload <= sload_x and not sload_d;
-- Shifted pixel load
shift_pbyte <= (pbyte00 & pbyte01) when sload_0 = '1' else (pbyte10 & pbyte11);
shift_abyte <= (abyte00 & abyte01) when sload_0 = '1' else (abyte10 & abyte11);
shift_screen_mode <= screen_mode_0 when sload_0 = '1' else screen_mode_1;
shift_scroll <= scroll_0 when sload_0 = '1' else scroll_1;
shift_reg_32 <= (shift_pbyte(15 downto 8) & shift_abyte(15 downto 8) & shift_pbyte(7 downto 0) & shift_abyte(7 downto 0)) when shift_screen_mode(2) = '1' else
(shift_pbyte(15) & shift_pbyte(15) & shift_pbyte(14) & shift_pbyte(14) & shift_pbyte(13) & shift_pbyte(13) & shift_pbyte(12) & shift_pbyte(12) &
shift_pbyte(11) & shift_pbyte(11) & shift_pbyte(10) & shift_pbyte(10) & shift_pbyte(9) & shift_pbyte(9) & shift_pbyte(8) & shift_pbyte(8) &
shift_pbyte(7) & shift_pbyte(7) & shift_pbyte(6) & shift_pbyte(6) & shift_pbyte(5) & shift_pbyte(5) & shift_pbyte(4) & shift_pbyte(4) &
shift_pbyte(3) & shift_pbyte(3) & shift_pbyte(2) & shift_pbyte(2) & shift_pbyte(1) & shift_pbyte(1) & shift_pbyte(0) & shift_pbyte(0));
shift_reg_ld <= std_logic_vector(shift_left(unsigned(shift_reg_32), to_integer(unsigned(shift_scroll))));
process (i_CLK_14)
begin
if rising_edge(i_CLK_14) then
if sload = '1' then
shift_reg <= shift_reg_ld(31 downto 16);
else
shift_reg <= shift_reg(14 downto 0) & '0';
end if;
end if;
end process;
--
-- ATTRIBUTE REGISTER
--
-- Indicate when second attribute byte should be used
border_active_v <= i_vc(8) or (i_vc(7) and i_vc(6));
border_active <= i_phc(8) or border_active_v;
border_active_ula <= i_hc(8) or border_active_v;
border_clr <= "00" & i_port_fe_border & i_port_fe_border;
border_clr_tmx <= "01" & (not i_port_ff_reg(5 downto 3)) & i_port_ff_reg(5 downto 3);
process (i_CLK_14)
begin
if rising_edge(i_CLK_14) then
if sload = '1' then
if shift_screen_mode(2) = '1' then
attr_reg <= border_clr_tmx & border_clr_tmx;
elsif border_active = '1' then
attr_reg <= border_clr & border_clr;
else
attr_reg <= shift_abyte;
end if;
attr_scroll_r <= '0' & shift_scroll;
screen_mode_r <= shift_screen_mode;
else
if attr_scroll_r(4) = '0' then
attr_scroll_r <= attr_scroll_r + 1;
end if;
if i_timing_pentagon = '1' and border_active = '1' then
if screen_mode_r(2) = '1' then
attr_reg <= border_clr_tmx & border_clr_tmx;
else
attr_reg <= border_clr & border_clr;
end if;
end if;
end if;
end if;
end process;
attr_active <= attr_reg(15 downto 8) when attr_scroll_r(4) = '0' else attr_reg(7 downto 0);
--
-- GENERATE RGB PIXEL OUT
--
-- Delay border turn off signal by half a pixel
process (i_CLK_14)
begin
if rising_edge(i_CLK_14) then
border_active_d <= border_active;
end if;
end process;
pixel_en <= (shift_reg(15) xor (attr_active(7) and flash_cnt(4) and (not i_ulanext_en) and not i_ulap_en)) and not border_active_d;
-- Flash Counter
process (i_CLK_7)
begin
if rising_edge(i_CLK_7) then
if i_hc = ('0' & X"00") and i_vc = ('0' & X"00") then
flash_cnt <= flash_cnt + 1;
end if;
end if;
end process;
-- Standard ULA, ULAnext, ULA+
process (i_CLK_14)
constant paper_base_index : std_logic_vector(7 downto 0) := "10000000";
begin
if falling_edge(i_CLK_14) then
ula_select_bgnd <= '0';
if i_ulanext_en = '1' then
-- ULAnext
if border_active_d = '1' then
-- border
if i_ulanext_format = X"FF" then
ula_select_bgnd <= '1';
end if;
ula_pixel <= paper_base_index(7 downto 3) & attr_active(5 downto 3);
elsif pixel_en = '1' then
-- ink
ula_pixel <= attr_active and i_ulanext_format;
else
-- paper
case i_ulanext_format is
when X"01" => ula_pixel <= paper_base_index(7) & attr_active(7 downto 1);
when X"03" => ula_pixel <= paper_base_index(7 downto 6) & attr_active(7 downto 2);
when X"07" => ula_pixel <= paper_base_index(7 downto 5) & attr_active(7 downto 3);
when X"0F" => ula_pixel <= paper_base_index(7 downto 4) & attr_active(7 downto 4);
when X"1F" => ula_pixel <= paper_base_index(7 downto 3) & attr_active(7 downto 5);
when X"3F" => ula_pixel <= paper_base_index(7 downto 2) & attr_active(7 downto 6);
when X"7F" => ula_pixel <= paper_base_index(7 downto 1) & attr_active(7);
when others => ula_select_bgnd <= '1';
end case;
end if;
elsif i_ulap_en = '1' then
-- ULA+
ula_pixel(7 downto 3) <= "11" & attr_active(7 downto 6) & (screen_mode_r(2) or not pixel_en);
if pixel_en = '1' then
ula_pixel(2 downto 0) <= attr_active(2 downto 0);
else
ula_pixel(2 downto 0) <= attr_active(5 downto 3);
end if;
else
-- Standard ULA
ula_pixel(7 downto 3) <= "000" & not pixel_en & attr_active(6);
if pixel_en = '1' then
ula_pixel(2 downto 0) <= attr_active(2 downto 0);
else
ula_pixel(2 downto 0) <= attr_active(5 downto 3);
end if;
end if;
end if;
end process;
-- Pixel Out
o_ula_clipped <= '0' when (i_phc >= i_ula_clip_x1 and i_phc <= i_ula_clip_x2 and i_vc >= i_ula_clip_y1 and i_vc <= i_ula_clip_y2) or border_active = '1' else '1';
o_ula_pixel <= ula_pixel;
o_ula_select_bgnd <= ula_select_bgnd;
o_ula_border <= border_active; -- border_active_d ??
--
-- FLOATING BUS
--
o_ula_floating_bus <= (floating_bus_r(7 downto 1) & (floating_bus_r(0) or i_timing_p3)) when (border_active_ula = '0' and floating_bus_en = '1') else i_p3_floating_bus when i_timing_p3 = '1' else X"FF";
--
-- CPU CONTENTION
--
-- the zx next is a synchronous machine and decides whether the z80 clock will be allowed to go low in the previous i_hc cycle (contend 3-14)
-- the original spectrums are combinatorial, they will OR a one into the clock in the current cycle (contend 4-15)
hc_adj <= i_hc(3 downto 0) + 1;
wait_s <= '1' when ((hc_adj(3 downto 2) /= "00") or (hc_adj(3 downto 1) = "000" and i_timing_p3 = '1')) and i_hc(8) = '0' and border_active_v = '0' and i_contention_en = '1' else '0';
-- 48k / 128k
process (i_CLK_CPU)
begin
if rising_edge(i_CLK_CPU) then
mreq23_n <= i_cpu_mreq_n;
ioreqtw3_n <= i_cpu_iorq_n;
end if;
end process;
o_cpu_contend <= '1' when ((i_contention_memory = '1' and mreq23_n = '1') or (i_contention_port = '1' and i_cpu_iorq_n = '0' and ioreqtw3_n = '1')) and i_timing_p3 = '0' and wait_s = '1' else '0';
-- +3
-- o_cpu_wait_n <= '0' when ((i_cpu_mreq_n = '0' and i_contention_memory = '1') or (i_cpu_iorq_n = '0' and i_contention_port = '1')) and i_timing_p3 = '1' and wait_s = '1' else '1';
o_cpu_wait_n <= '0' when (i_cpu_mreq_n = '0' and i_contention_memory = '1') and i_timing_p3 = '1' and wait_s = '1' else '1';
end architecture;

471
rtl/video/zxula_timing.vhd Normal file
View File

@@ -0,0 +1,471 @@
-- ZX Spectrum Next Video Timing Module
--
-- Copyright 2017 superfo, mcleod, avillena (ZX UNO Project)
-- Copyright 2020 Fabio Belavenuto, Alvin Albrecht
--
-- This file is part of the ZX Spectrum Next Project
-- <https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/tree/master/cores>
--
-- The ZX Spectrum Next FPGA source code 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.
--
-- The ZX Spectrum Next FPGA source code 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 the ZX Spectrum Next FPGA source code. If not, see
-- <https://www.gnu.org/licenses/>.
--
-- Original pal_sync_generator.v from the ZX UNO project:
-- <https://github.com/yomboprime/zxuno-addons/blob/master/test24_uart/common/pal_sync_generator.v>
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity zxula_timing is
port (
clock_i : in std_logic;
clock_x4_i : in std_logic;
reset_conter_i : in std_logic;
mode_i : in std_logic_vector(2 downto 0);
video_timing_i : in std_logic_vector(2 downto 0);
vf50_60_i : in std_logic;
cu_offset_i : in std_logic_vector(7 downto 0);
hcount_o : out unsigned(8 downto 0);
vcount_o : out unsigned(8 downto 0);
phcount_o : out unsigned(8 downto 0);
whcount_o : out unsigned(8 downto 0);
wvcount_o : out unsigned(8 downto 0);
cvcount_o : out unsigned(8 downto 0);
sc_o : out std_logic_vector(1 downto 0);
hsync_n_o : out std_logic;
vsync_n_o : out std_logic;
hblank_n_o : out std_logic;
vblank_n_o : out std_logic;
lint_ctrl_i : in std_logic_vector(1 downto 0);
lint_line_i : in std_logic_vector(8 downto 0);
ula_int_o : out std_logic;
line_int_o : out std_logic
);
end entity;
architecture Behavior of zxula_timing is
signal hc_s : unsigned(8 downto 0);
signal vc_s : unsigned(8 downto 0);
signal phc_s : unsigned(8 downto 0);
signal whc_s : unsigned(8 downto 0);
signal wvc_s : unsigned(8 downto 0);
signal cvc_s : unsigned(8 downto 0);
signal whc_lsb_d : std_logic;
signal sc_s : std_logic_vector(1 downto 0);
signal max_hc_s : std_logic;
signal max_vc_s : std_logic;
signal max_cvc_s : std_logic;
signal max_whc_s : std_logic;
signal int_ula_s : std_logic;
signal int_lint_s : std_logic;
signal c_max_hc_s : unsigned(8 downto 0);
signal c_max_vc_s : unsigned(8 downto 0);
signal c_vblank_min_s : unsigned(8 downto 0);
signal c_vblank_max_s : unsigned(8 downto 0);
signal c_hblank_min_s : unsigned(8 downto 0);
signal c_hblank_max_s : unsigned(8 downto 0);
signal c_vsync_min_s : unsigned(8 downto 0);
signal c_vsync_max_s : unsigned(8 downto 0);
signal c_hsync_min_s : unsigned(8 downto 0);
signal c_hsync_max_s : unsigned(8 downto 0);
signal c_int_h_s : unsigned(8 downto 0);
signal c_int_v_s : unsigned(8 downto 0);
signal vblank_top_cancel : std_logic;
signal vblank_bottom_cancel : std_logic;
begin
--
process (mode_i, vf50_60_i, video_timing_i)
begin
-- Modeline "720x576x50hz" 27 720 732 796 864 576 581 586 625
-- 360 366 398 432 288 290 293 312
-- ModeLine "720x480@60" 27 720 736 798 858 480 489 495 525
-- 360 368 399 429 240 244 247 262
if video_timing_i = "111" then
-- HDMI
-- Investigate later.. these numbers were chosen to agree with most hdmi tvs.
if vf50_60_i = '0' then
-- 50 Hz
c_hblank_min_s <= to_unsigned(360-37, 9); -- -37 ok
c_hsync_min_s <= to_unsigned(366-37, 9);
c_hsync_max_s <= to_unsigned(398-37, 9);
c_hblank_max_s <= to_unsigned(431-37, 9);
c_int_h_s <= to_unsigned(4, 9);
c_max_hc_s <= to_unsigned(431, 9);
c_vblank_min_s <= to_unsigned(248+8-1, 9);-- +8 ok
c_vsync_min_s <= to_unsigned(248+8, 9);
c_vsync_max_s <= to_unsigned(251+8, 9);
c_vblank_max_s <= to_unsigned(255+8, 9);
c_int_v_s <= to_unsigned(248+8, 9);
c_max_vc_s <= to_unsigned(311, 9);
else
-- 60 Hz
c_hblank_min_s <= to_unsigned(360-37, 9); -- -37 ok
c_hsync_min_s <= to_unsigned(368-37, 9);
c_hsync_max_s <= to_unsigned(399-37, 9);
c_hblank_max_s <= to_unsigned(428-37, 9);
c_int_h_s <= to_unsigned(4, 9);
c_max_hc_s <= to_unsigned(428, 9);
c_vblank_min_s <= to_unsigned(240-9-1, 9); -- -9 ok
c_vsync_min_s <= to_unsigned(244-9, 9);
c_vsync_max_s <= to_unsigned(247-9, 9);
c_vblank_max_s <= to_unsigned(247-9, 9);
c_int_v_s <= to_unsigned(244-9, 9);
c_max_vc_s <= to_unsigned(261, 9);
end if;
elsif mode_i = "000" or mode_i = "001" then
-- 48k
c_hblank_min_s <= to_unsigned(320, 9);
c_hsync_min_s <= to_unsigned(344, 9);
c_hsync_max_s <= to_unsigned(375, 9);
c_hblank_max_s <= to_unsigned(415, 9);
c_int_h_s <= to_unsigned(0, 9);
c_max_hc_s <= to_unsigned(447, 9);
if vf50_60_i = '0' then
-- 50 Hz
c_vblank_min_s <= to_unsigned(248-1, 9);
c_vblank_max_s <= to_unsigned(255, 9);
c_vsync_min_s <= to_unsigned(248, 9);
c_vsync_max_s <= to_unsigned(251, 9);
c_int_v_s <= to_unsigned(248, 9);
c_max_vc_s <= to_unsigned(311, 9);
else
-- 60 Hz
c_vblank_min_s <= to_unsigned(224-1, 9);
c_vsync_min_s <= to_unsigned(224, 9);
c_vsync_max_s <= to_unsigned(227, 9);
c_vblank_max_s <= to_unsigned(231, 9);
c_int_v_s <= to_unsigned(224, 9);
c_max_vc_s <= to_unsigned(263, 9);
end if;
elsif mode_i = "010" or mode_i = "011" then
-- 128k, +3
c_hblank_min_s <= to_unsigned(320, 9);
c_hsync_min_s <= to_unsigned(344, 9);
c_hsync_max_s <= to_unsigned(375, 9);
c_hblank_max_s <= to_unsigned(415, 9);
if mode_i = "010" then
-- 128k
c_int_h_s <= to_unsigned(4, 9); -- 8
else
-- +3
c_int_h_s <= to_unsigned(2, 9);
end if;
c_max_hc_s <= to_unsigned(455, 9);
if vf50_60_i = '0' then
-- 50 Hz
c_vblank_min_s <= to_unsigned(248-1, 9);
c_vsync_min_s <= to_unsigned(248, 9);
c_vsync_max_s <= to_unsigned(251, 9);
c_vblank_max_s <= to_unsigned(255, 9);
c_int_v_s <= to_unsigned(248, 9);
c_max_vc_s <= to_unsigned(310, 9);
else
-- 60 Hz
c_vblank_min_s <= to_unsigned(224-1, 9);
c_vsync_min_s <= to_unsigned(224, 9);
c_vsync_max_s <= to_unsigned(227, 9);
c_vblank_max_s <= to_unsigned(231, 9);
c_int_v_s <= to_unsigned(224, 9);
c_max_vc_s <= to_unsigned(263, 9);
end if;
else
-- Pentagon
c_hblank_min_s <= to_unsigned(336, 9); -- 336, 320
c_hsync_min_s <= to_unsigned(336, 9); -- 336, 320
c_hsync_max_s <= to_unsigned(367, 9); -- 367, 351
c_hblank_max_s <= to_unsigned(399, 9); -- 399, 383
c_int_h_s <= to_unsigned(323, 9); -- 323, 320
c_max_hc_s <= to_unsigned(447, 9); -- 447, 447
-- There is no 60Hz Pentagon
c_vblank_min_s <= to_unsigned(240-1, 9);
c_vsync_min_s <= to_unsigned(240, 9);
c_vsync_max_s <= to_unsigned(255, 9);
c_vblank_max_s <= to_unsigned(256, 9); -- 271
c_int_v_s <= to_unsigned(239, 9); -- 240, 239
c_max_vc_s <= to_unsigned(319, 9);
end if;
end process;
-- Signals generation
vblank_top_cancel <= '1' when vc_s = c_vblank_max_s and hc_s >= c_hblank_min_s else '0';
vblank_bottom_cancel <= '1' when vc_s = c_vblank_min_s and hc_s < c_hblank_min_s else '0';
process (hc_s, vc_s, c_hblank_min_s, c_hblank_max_s, c_vblank_min_s, c_vblank_max_s,
c_hsync_min_s, c_hsync_max_s, c_vsync_min_s, c_vsync_max_s, vblank_top_cancel, vblank_bottom_cancel)
begin
hblank_n_o <= '1';
vblank_n_o <= '1';
hsync_n_o <= '1';
vsync_n_o <= '1';
-- HBlank
if hc_s >= c_hblank_min_s and hc_s <= c_hblank_max_s then
hblank_n_o <= '0';
end if;
-- VBlank
if vc_s >= c_vblank_min_s and vc_s <= c_vblank_max_s then
vblank_n_o <= vblank_top_cancel or vblank_bottom_cancel;
end if;
-- HSync
if hc_s >= c_hsync_min_s and hc_s <= c_hsync_max_s then
hsync_n_o <= '0';
end if;
-- VSync
if vc_s >= c_vsync_min_s and vc_s <= c_vsync_max_s then
vsync_n_o <= '0';
end if;
end process;
-- INT pulse generation, lasts one 7MHz period
process (hc_s, vc_s, cvc_s, c_int_v_s, c_int_h_s, max_cvc_s, lint_line_i, lint_ctrl_i)
variable lint_minus_one_v : unsigned(8 downto 0);
begin
int_ula_s <= '0';
int_lint_s <= '0';
lint_minus_one_v := unsigned(lint_line_i) - 1;
if lint_ctrl_i(0) = '1' then
if vc_s = c_int_v_s and hc_s = c_int_h_s then
int_ula_s <= '1';
end if;
end if;
if lint_ctrl_i(1) = '1' and hc_s = 256 then
if lint_line_i = 0 then
if max_cvc_s = '1' then
int_lint_s <= '1';
end if;
elsif cvc_s = lint_minus_one_v then
int_lint_s <= '1';
end if;
end if;
end process;
ula_int_o <= int_ula_s;
line_int_o <= int_lint_s;
-- Pixel position counters
-- All timing refers to the ULA counter as implemented in the original hardware.
-- The ULA produces its first pixel in the 256 pixel wide area during count 12.
-- Practical counters are generated for other modules that count the actual pixel
-- position being generated in the current cycle as well as delivering negative values
-- leading up to pixel zero.
-- ULA counter, pixel 0 is generated in cycle 12
max_hc_s <= '1' when hc_s = c_max_hc_s else '0';
process (clock_i)
begin
if rising_edge(clock_i) then
if reset_conter_i = '1' then
hc_s <= (others => '0');
elsif max_hc_s = '1' then
hc_s <= (others => '0');
else
hc_s <= hc_s + 1;
end if;
end if;
end process;
max_vc_s <= '1' when vc_s = c_max_vc_s else '0';
process (clock_i)
begin
if rising_edge(clock_i) then
if reset_conter_i = '1' then
vc_s <= c_vsync_min_s;
elsif max_hc_s = '1' then
if max_vc_s = '1' then
vc_s <= (others => '0');
else
vc_s <= vc_s + 1;
end if;
end if;
end if;
end process;
-- Copper offset vertical counter
max_cvc_s <= '1' when cvc_s = c_max_vc_s else '0';
process (clock_i)
begin
if rising_edge(clock_i) then
if reset_conter_i = '1' then
cvc_s <= c_vsync_min_s;
elsif max_hc_s = '1' then
if max_vc_s = '1' then
cvc_s <= unsigned('0' & cu_offset_i);
elsif max_cvc_s = '1' then
cvc_s <= (others => '0');
else
cvc_s <= cvc_s + 1;
end if;
end if;
end if;
end process;
-- Practical wide counters. (0,0) corresponds to (-32,-32) for the 320 x 256 surface
max_whc_s <= '1' when hc_s = (c_max_hc_s - 32+12-16) else '0';
process (clock_i)
begin
if rising_edge(clock_i) then
if reset_conter_i = '1' then
whc_s <= (others => '0');
elsif max_whc_s = '1' then
whc_s <= "111110000"; -- starting at -16
else
whc_s <= whc_s + 1;
end if;
end if;
end process;
process (clock_i)
begin
if rising_edge(clock_i) then
if reset_conter_i = '1' then
wvc_s <= to_unsigned(256, 9);
elsif max_whc_s = '1' then
if vc_s = (c_max_vc_s - 32-2) then
wvc_s <= "111111110"; -- starting at -2
else
wvc_s <= wvc_s + 1;
end if;
end if;
end if;
end process;
-- Practical 256 horizontal counter. 0 corresponds to pixel x=0 on the 256 x 192 surface
process (clock_i)
begin
if rising_edge(clock_i) then
if reset_conter_i = '1' then
phc_s <= (others => '0');
elsif max_whc_s = '1' then
phc_s <= "111010000"; -- starting at -48
else
phc_s <= phc_s + 1;
end if;
end if;
end process;
-- 28MHZ sub-pixel counter
process (clock_x4_i)
begin
if rising_edge(clock_x4_i) then
if reset_conter_i = '1' then
whc_lsb_d <= '0';
else
whc_lsb_d <= whc_s(0);
end if;
end if;
end process;
process (clock_x4_i)
begin
if rising_edge(clock_x4_i) then
if reset_conter_i = '1' then
sc_s <= (others => '0');
elsif whc_s(0) /= whc_lsb_d then
sc_s <= "01";
else
sc_s <= sc_s + 1;
end if;
end if;
end process;
--
hcount_o <= hc_s;
vcount_o <= vc_s;
phcount_o <= phc_s;
whcount_o <= whc_s;
wvcount_o <= wvc_s;
cvcount_o <= cvc_s;
sc_o <= sc_s;
end architecture;

6939
rtl/zxnext.vhd Normal file

File diff suppressed because it is too large Load Diff

157
sys/alsa.sv Normal file
View File

@@ -0,0 +1,157 @@
//============================================================================
//
// ALSA sound support for MiSTer
// (c)2019,2020 Alexey Melnikov
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
//============================================================================
module alsa
#(
parameter CLK_RATE = 24576000
)
(
input reset,
input clk,
output reg [31:3] ram_address,
input [63:0] ram_data,
output reg ram_req = 0,
input ram_ready,
input spi_ss,
input spi_sck,
input spi_mosi,
output spi_miso,
output reg [15:0] pcm_l,
output reg [15:0] pcm_r
);
reg [60:0] buf_info;
reg [6:0] spicnt = 0;
always @(posedge spi_sck, posedge spi_ss) begin
reg [95:0] spi_data;
if(spi_ss) spicnt <= 0;
else begin
spi_data[{spicnt[6:3],~spicnt[2:0]}] <= spi_mosi;
if(&spicnt) buf_info <= {spi_data[82:67],spi_data[50:35],spi_data[31:3]};
spicnt <= spicnt + 1'd1;
end
end
assign spi_miso = spi_out[{spicnt[4:3],~spicnt[2:0]}];
reg [31:0] spi_out = 0;
always @(posedge clk) if(spi_ss) spi_out <= {buf_rptr, hurryup, 8'h00};
reg [31:3] buf_addr;
reg [18:3] buf_len;
reg [18:3] buf_wptr = 0;
always @(posedge clk) begin
reg [60:0] data1,data2;
data1 <= buf_info;
data2 <= data1;
if(data2 == data1) {buf_wptr,buf_len,buf_addr} <= data2;
end
reg [2:0] hurryup = 0;
reg [18:3] buf_rptr = 0;
always @(posedge clk) begin
reg [18:3] len = 0;
reg [1:0] ready = 0;
reg [63:0] readdata;
reg got_first = 0;
reg [7:0] ce_cnt = 0;
reg [1:0] state = 0;
if(reset) begin
ready <= 0;
ce_cnt <= 0;
state <= 0;
got_first <= 0;
len <= 0;
end
else begin
//ramp up
if(len[18:14] && (hurryup < 1)) hurryup <= 1;
if(len[18:16] && (hurryup < 2)) hurryup <= 2;
if(len[18:17] && (hurryup < 4)) hurryup <= 4;
//ramp down
if(!len[18:15] && (hurryup > 2)) hurryup <= 2;
if(!len[18:13] && (hurryup > 1)) hurryup <= 1;
if(!len[18:10]) hurryup <= 0;
if(ce_sample && ~&ce_cnt) ce_cnt <= ce_cnt + 1'd1;
case(state)
0: if(!ce_sample) begin
if(ready) begin
if(ce_cnt) begin
{readdata[31:0],pcm_r,pcm_l} <= readdata;
ready <= ready - 1'd1;
ce_cnt <= ce_cnt - 1'd1;
end
end
else if(buf_rptr != buf_wptr) begin
if(~got_first) begin
buf_rptr <= buf_wptr;
got_first <= 1;
end
else begin
ram_address <= buf_addr + buf_rptr;
ram_req <= ~ram_req;
buf_rptr <= buf_rptr + 1'd1;
len <= (buf_wptr < buf_rptr) ? (buf_len + buf_wptr - buf_rptr) : (buf_wptr - buf_rptr);
state <= 1;
end
end
else begin
len <= 0;
ce_cnt <= 0;
hurryup <= 0;
end
end
1: if(ram_ready) begin
ready <= 2;
readdata <= ram_data;
if(buf_rptr >= buf_len) buf_rptr <= buf_rptr - buf_len;
state <= 0;
end
endcase
end
end
reg ce_sample;
always @(posedge clk) begin
reg [31:0] acc = 0;
ce_sample <= 0;
acc <= acc + 48000 + {hurryup,6'd0};
if(acc >= CLK_RATE) begin
acc <= acc - CLK_RATE;
ce_sample <= 1;
end
end
endmodule

302
sys/arcade_video.v Normal file
View File

@@ -0,0 +1,302 @@
//============================================================================
//
// Copyright (C) 2017-2020 Sorgelig
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
//============================================================================
//////////////////////////////////////////////////////////
// DW:
// 6 : 2R 2G 2B
// 8 : 3R 3G 2B
// 9 : 3R 3G 3B
// 12 : 4R 4G 4B
// 24 : 8R 8G 8B
module arcade_video #(parameter WIDTH=320, DW=8, GAMMA=1)
(
input clk_video,
input ce_pix,
input[DW-1:0] RGB_in,
input HBlank,
input VBlank,
input HSync,
input VSync,
output CLK_VIDEO,
output CE_PIXEL,
output [7:0] VGA_R,
output [7:0] VGA_G,
output [7:0] VGA_B,
output VGA_HS,
output VGA_VS,
output VGA_DE,
output [1:0] VGA_SL,
input [2:0] fx,
input forced_scandoubler,
inout [21:0] gamma_bus
);
assign CLK_VIDEO = clk_video;
wire hs_fix,vs_fix;
sync_fix sync_v(CLK_VIDEO, HSync, hs_fix);
sync_fix sync_h(CLK_VIDEO, VSync, vs_fix);
reg [DW-1:0] RGB_fix;
reg CE,HS,VS,HBL,VBL;
always @(posedge CLK_VIDEO) begin
reg old_ce;
old_ce <= ce_pix;
CE <= 0;
if(~old_ce & ce_pix) begin
CE <= 1;
HS <= hs_fix;
if(~HS & hs_fix) VS <= vs_fix;
RGB_fix <= RGB_in;
HBL <= HBlank;
if(HBL & ~HBlank) VBL <= VBlank;
end
end
wire [7:0] R,G,B;
generate
if(DW == 6) begin
assign R = {RGB_fix[5:4],RGB_fix[5:4],RGB_fix[5:4],RGB_fix[5:4]};
assign G = {RGB_fix[3:2],RGB_fix[3:2],RGB_fix[3:2],RGB_fix[3:2]};
assign B = {RGB_fix[1:0],RGB_fix[1:0],RGB_fix[1:0],RGB_fix[1:0]};
end
else if(DW == 8) begin
assign R = {RGB_fix[7:5],RGB_fix[7:5],RGB_fix[7:6]};
assign G = {RGB_fix[4:2],RGB_fix[4:2],RGB_fix[4:3]};
assign B = {RGB_fix[1:0],RGB_fix[1:0],RGB_fix[1:0],RGB_fix[1:0]};
end
else if(DW == 9) begin
assign R = {RGB_fix[8:6],RGB_fix[8:6],RGB_fix[8:7]};
assign G = {RGB_fix[5:3],RGB_fix[5:3],RGB_fix[5:4]};
assign B = {RGB_fix[2:0],RGB_fix[2:0],RGB_fix[2:1]};
end
else if(DW == 12) begin
assign R = {RGB_fix[11:8],RGB_fix[11:8]};
assign G = {RGB_fix[7:4],RGB_fix[7:4]};
assign B = {RGB_fix[3:0],RGB_fix[3:0]};
end
else begin // 24
assign R = RGB_fix[23:16];
assign G = RGB_fix[15:8];
assign B = RGB_fix[7:0];
end
endgenerate
assign VGA_SL = sl[1:0];
wire [2:0] sl = fx ? fx - 1'd1 : 3'd0;
wire scandoubler = fx || forced_scandoubler;
video_mixer #(.LINE_LENGTH(WIDTH+4), .HALF_DEPTH(DW!=24), .GAMMA(GAMMA)) video_mixer
(
.CLK_VIDEO(CLK_VIDEO),
.ce_pix(CE),
.CE_PIXEL(CE_PIXEL),
.scandoubler(scandoubler),
.hq2x(fx==1),
.gamma_bus(gamma_bus),
.R((DW!=24) ? R[7:4] : R),
.G((DW!=24) ? G[7:4] : G),
.B((DW!=24) ? B[7:4] : B),
.HSync (HS),
.VSync (VS),
.HBlank(HBL),
.VBlank(VBL),
.VGA_R(VGA_R),
.VGA_G(VGA_G),
.VGA_B(VGA_B),
.VGA_VS(VGA_VS),
.VGA_HS(VGA_HS),
.VGA_DE(VGA_DE)
);
endmodule
//============================================================================
//
// Screen +90/-90 deg. rotation
// Copyright (C) 2020 Sorgelig
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
//============================================================================
module screen_rotate
(
input CLK_VIDEO,
input CE_PIXEL,
input [7:0] VGA_R,
input [7:0] VGA_G,
input [7:0] VGA_B,
input VGA_HS,
input VGA_VS,
input VGA_DE,
input rotate_ccw,
input no_rotate,
output FB_EN,
output [4:0] FB_FORMAT,
output [11:0] FB_WIDTH,
output [11:0] FB_HEIGHT,
output [31:0] FB_BASE,
output [13:0] FB_STRIDE,
input FB_VBL,
input FB_LL,
output DDRAM_CLK,
input DDRAM_BUSY,
output [7:0] DDRAM_BURSTCNT,
output [28:0] DDRAM_ADDR,
output [63:0] DDRAM_DIN,
output [7:0] DDRAM_BE,
output DDRAM_WE,
output DDRAM_RD
);
parameter MEM_BASE = 7'b0010010; // buffer at 0x24000000, 3x8MB
assign DDRAM_CLK = CLK_VIDEO;
assign DDRAM_BURSTCNT = 1;
assign DDRAM_ADDR = {MEM_BASE, i_fb, ram_addr[22:3]};
assign DDRAM_BE = ram_addr[2] ? 8'hF0 : 8'h0F;
assign DDRAM_DIN = {ram_data,ram_data};
assign DDRAM_WE = ram_wr;
assign DDRAM_RD = 0;
assign FB_EN = fb_en[2];
assign FB_FORMAT = 5'b00110;
assign FB_BASE = {MEM_BASE,o_fb,23'd0};
assign FB_WIDTH = vsz;
assign FB_HEIGHT = hsz;
assign FB_STRIDE = stride;
function [1:0] buf_next;
input [1:0] a,b;
begin
buf_next = 1;
if ((a==0 && b==1) || (a==1 && b==0)) buf_next = 2;
if ((a==1 && b==2) || (a==2 && b==1)) buf_next = 0;
end
endfunction
reg [1:0] i_fb,o_fb;
always @(posedge CLK_VIDEO) begin
reg old_vbl,old_vs;
old_vbl <= FB_VBL;
old_vs <= VGA_VS;
if(FB_LL) begin
if(~old_vbl & FB_VBL) o_fb<={1'b0,~i_fb[0]};
if(~old_vs & VGA_VS) i_fb<={1'b0,~i_fb[0]};
end
else begin
if(~old_vbl & FB_VBL) o_fb<=buf_next(o_fb,i_fb);
if(~old_vs & VGA_VS) i_fb<=buf_next(i_fb,o_fb);
end
end
initial begin
fb_en = 0;
end
reg [2:0] fb_en = 0;
reg [11:0] hsz = 320, vsz = 240;
reg [11:0] bwidth;
reg [22:0] bufsize;
always @(posedge CLK_VIDEO) begin
reg [11:0] hcnt = 0, vcnt = 0;
reg old_vs, old_de;
if(CE_PIXEL) begin
old_vs <= VGA_VS;
old_de <= VGA_DE;
hcnt <= hcnt + 1'd1;
if(~old_de & VGA_DE) begin
hcnt <= 1;
vcnt <= vcnt + 1'd1;
end
if(old_de & ~VGA_DE) hsz <= hcnt;
if(~old_vs & VGA_VS) begin
vsz <= vcnt;
bwidth <= vcnt + 2'd3;
vcnt <= 0;
fb_en <= {fb_en[1:0], ~no_rotate};
end
if(old_vs & ~VGA_VS) bufsize <= hsz * stride;
end
end
wire [13:0] stride = {bwidth[11:2], 4'd0};
reg [22:0] ram_addr, next_addr;
reg [31:0] ram_data;
reg ram_wr;
always @(posedge CLK_VIDEO) begin
reg [13:0] hcnt = 0;
reg old_vs, old_de;
ram_wr <= 0;
if(CE_PIXEL) begin
old_vs <= VGA_VS;
old_de <= VGA_DE;
if(~old_vs & VGA_VS) begin
next_addr <= rotate_ccw ? (bufsize - stride) : {vsz-1'd1, 2'b00};
hcnt <= rotate_ccw ? 3'd4 : {vsz-2'd2, 2'b00};
end
if(VGA_DE) begin
ram_wr <= 1;
ram_data <= {VGA_B,VGA_G,VGA_R};
ram_addr <= next_addr;
next_addr <= rotate_ccw ? (next_addr - stride) : (next_addr + stride);
end
if(old_de & ~VGA_DE) begin
next_addr <= rotate_ccw ? (bufsize - stride + hcnt) : hcnt;
hcnt <= rotate_ccw ? (hcnt + 3'd4) : (hcnt - 3'd4);
end
end
end
endmodule

2561
sys/ascal.vhd Normal file

File diff suppressed because it is too large Load Diff

296
sys/audio_out.v Normal file
View File

@@ -0,0 +1,296 @@
module audio_out
#(
parameter CLK_RATE = 24576000
)
(
input reset,
input clk,
//0 - 48KHz, 1 - 96KHz
input sample_rate,
input [31:0] flt_rate,
input [39:0] cx,
input [7:0] cx0,
input [7:0] cx1,
input [7:0] cx2,
input [23:0] cy0,
input [23:0] cy1,
input [23:0] cy2,
input [4:0] att,
input [1:0] mix,
input is_signed,
input [15:0] core_l,
input [15:0] core_r,
input [15:0] alsa_l,
input [15:0] alsa_r,
// I2S
output i2s_bclk,
output i2s_lrclk,
output i2s_data,
// SPDIF
output spdif,
// Sigma-Delta DAC
output dac_l,
output dac_r
);
localparam AUDIO_RATE = 48000;
localparam AUDIO_DW = 16;
localparam CE_RATE = AUDIO_RATE*AUDIO_DW*8;
localparam FILTER_DIV = (CE_RATE/(AUDIO_RATE*32))-1;
wire [31:0] real_ce = sample_rate ? {CE_RATE[30:0],1'b0} : CE_RATE[31:0];
reg mclk_ce;
always @(posedge clk) begin
reg [31:0] cnt;
mclk_ce = 0;
cnt = cnt + real_ce;
if(cnt >= CLK_RATE) begin
cnt = cnt - CLK_RATE;
mclk_ce = 1;
end
end
reg i2s_ce;
always @(posedge clk) begin
reg div;
i2s_ce <= 0;
if(mclk_ce) begin
div <= ~div;
i2s_ce <= div;
end
end
i2s i2s
(
.reset(reset),
.clk(clk),
.ce(i2s_ce),
.sclk(i2s_bclk),
.lrclk(i2s_lrclk),
.sdata(i2s_data),
.left_chan(al),
.right_chan(ar)
);
spdif toslink
(
.rst_i(reset),
.clk_i(clk),
.bit_out_en_i(mclk_ce),
.sample_i({ar,al}),
.spdif_o(spdif)
);
sigma_delta_dac #(15) sd_l
(
.CLK(clk),
.RESET(reset),
.DACin({~al[15], al[14:0]}),
.DACout(dac_l)
);
sigma_delta_dac #(15) sd_r
(
.CLK(clk),
.RESET(reset),
.DACin({~ar[15], ar[14:0]}),
.DACout(dac_r)
);
reg sample_ce;
always @(posedge clk) begin
reg [8:0] div = 0;
reg [1:0] add = 0;
div <= div + add;
if(!div) begin
div <= 2'd1 << sample_rate;
add <= 2'd1 << sample_rate;
end
sample_ce <= !div;
end
reg flt_ce;
always @(posedge clk) begin
reg [31:0] cnt = 0;
flt_ce = 0;
cnt = cnt + {flt_rate[30:0],1'b0};
if(cnt >= CLK_RATE) begin
cnt = cnt - CLK_RATE;
flt_ce = 1;
end
end
reg [15:0] cl,cr;
always @(posedge clk) begin
reg [15:0] cl1,cl2;
reg [15:0] cr1,cr2;
cl1 <= core_l; cl2 <= cl1;
if(cl2 == cl1) cl <= cl2;
cr1 <= core_r; cr2 <= cr1;
if(cr2 == cr1) cr <= cr2;
end
reg a_en1 = 0, a_en2 = 0;
always @(posedge clk, posedge reset) begin
reg [1:0] dly1 = 0;
reg [14:0] dly2 = 0;
if(reset) begin
dly1 <= 0;
dly2 <= 0;
a_en1 <= 0;
a_en2 <= 0;
end
else begin
if(flt_ce) begin
if(~&dly1) dly1 <= dly1 + 1'd1;
else a_en1 <= 1;
end
if(sample_ce) begin
if(!dly2[13+sample_rate]) dly2 <= dly2 + 1'd1;
else a_en2 <= 1;
end
end
end
wire [15:0] acl, acr;
IIR_filter #(.use_params(0)) IIR_filter
(
.clk(clk),
.reset(reset),
.ce(flt_ce & a_en1),
.sample_ce(sample_ce),
.cx(cx),
.cx0(cx0),
.cx1(cx1),
.cx2(cx2),
.cy0(cy0),
.cy1(cy1),
.cy2(cy2),
.input_l({~is_signed ^ cl[15], cl[14:0]}),
.input_r({~is_signed ^ cr[15], cr[14:0]}),
.output_l(acl),
.output_r(acr)
);
wire [15:0] adl;
DC_blocker dcb_l
(
.clk(clk),
.ce(sample_ce),
.sample_rate(sample_rate),
.mute(~a_en2),
.din(acl),
.dout(adl)
);
wire [15:0] adr;
DC_blocker dcb_r
(
.clk(clk),
.ce(sample_ce),
.sample_rate(sample_rate),
.mute(~a_en2),
.din(acr),
.dout(adr)
);
wire [15:0] al, audio_l_pre;
aud_mix_top audmix_l
(
.clk(clk),
.ce(sample_ce),
.att(att),
.mix(mix),
.core_audio(adl),
.pre_in(audio_r_pre),
.linux_audio(alsa_l),
.pre_out(audio_l_pre),
.out(al)
);
wire [15:0] ar, audio_r_pre;
aud_mix_top audmix_r
(
.clk(clk),
.ce(sample_ce),
.att(att),
.mix(mix),
.core_audio(adr),
.pre_in(audio_l_pre),
.linux_audio(alsa_r),
.pre_out(audio_r_pre),
.out(ar)
);
endmodule
module aud_mix_top
(
input clk,
input ce,
input [4:0] att,
input [1:0] mix,
input [15:0] core_audio,
input [15:0] linux_audio,
input [15:0] pre_in,
output reg [15:0] pre_out = 0,
output reg [15:0] out = 0
);
reg signed [16:0] a1, a2, a3, a4;
always @(posedge clk) if (ce) begin
a1 <= {core_audio[15],core_audio};
a2 <= a1 + {linux_audio[15],linux_audio};
pre_out <= a2[16:1];
case(mix)
0: a3 <= a2;
1: a3 <= $signed(a2) - $signed(a2[16:3]) + $signed(pre_in[15:2]);
2: a3 <= $signed(a2) - $signed(a2[16:2]) + $signed(pre_in[15:1]);
3: a3 <= {a2[16],a2[16:1]} + {pre_in[15],pre_in};
endcase
if(att[4]) a4 <= 0;
else a4 <= a3 >>> att[3:0];
//clamping
out <= ^a4[16:15] ? {a4[16],{15{a4[15]}}} : a4[15:0];
end
endmodule

73
sys/build_id.tcl Normal file
View File

@@ -0,0 +1,73 @@
# Build TimeStamp Verilog Module
# Jeff Wiencrot - 8/1/2011
# Sorgelig - 02/11/2019
proc generateBuildID_Verilog {} {
# Get the timestamp (see: http://www.altera.com/support/examples/tcl/tcl-date-time-stamp.html)
set buildDate "`define BUILD_DATE \"[clock format [ clock seconds ] -format %y%m%d]\""
# Create a Verilog file for output
set outputFileName "build_id.v"
set fileData ""
if { [file exists $outputFileName]} {
set outputFile [open $outputFileName "r"]
set fileData [read $outputFile]
close $outputFile
}
if {$buildDate ne $fileData} {
set outputFile [open $outputFileName "w"]
puts -nonewline $outputFile $buildDate
close $outputFile
# Send confirmation message to the Messages window
post_message "Generated: [pwd]/$outputFileName: $buildDate"
}
}
# Build CDF file
# Sorgelig - 17/2/2018
proc generateCDF {revision device outpath} {
set outputFileName "jtag.cdf"
set outputFile [open $outputFileName "w"]
puts $outputFile "JedecChain;"
puts $outputFile " FileRevision(JESD32A);"
puts $outputFile " DefaultMfr(6E);"
puts $outputFile ""
puts $outputFile " P ActionCode(Ign)"
puts $outputFile " Device PartName(SOCVHPS) MfrSpec(OpMask(0));"
puts $outputFile " P ActionCode(Cfg)"
puts $outputFile " Device PartName($device) Path(\"$outpath/\") File(\"$revision.sof\") MfrSpec(OpMask(1));"
puts $outputFile "ChainEnd;"
puts $outputFile ""
puts $outputFile "AlteraBegin;"
puts $outputFile " ChainType(JTAG);"
puts $outputFile "AlteraEnd;"
}
set project_name [lindex $quartus(args) 1]
set revision [lindex $quartus(args) 2]
if {[project_exists $project_name]} {
if {[string equal "" $revision]} {
project_open $project_name -revision [get_current_revision $project_name]
} else {
project_open $project_name -revision $revision
}
} else {
post_message -type error "Project $project_name does not exist"
exit
}
set device [get_global_assignment -name DEVICE]
set outpath [get_global_assignment -name PROJECT_OUTPUT_DIRECTORY]
if [is_project_open] {
project_close
}
generateBuildID_Verilog
generateCDF $revision $device $outpath

108
sys/ddr_svc.sv Normal file
View File

@@ -0,0 +1,108 @@
//
// Copyright (c) 2020 Alexey Melnikov
//
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ------------------------------------------
//
// 16-bit version
module ddr_svc
(
input clk,
input ram_waitrequest,
output [7:0] ram_burstcnt,
output [28:0] ram_addr,
input [63:0] ram_readdata,
input ram_read_ready,
output reg ram_read,
output [63:0] ram_writedata,
output [7:0] ram_byteenable,
output reg ram_write,
output [7:0] ram_bcnt,
input [31:3] ch0_addr,
input [7:0] ch0_burst,
output [63:0] ch0_data,
input ch0_req,
output ch0_ready,
input [31:3] ch1_addr,
input [7:0] ch1_burst,
output [63:0] ch1_data,
input ch1_req,
output ch1_ready
);
assign ram_burstcnt = ram_burst;
assign ram_byteenable = 8'hFF;
assign ram_addr = ram_address;
assign ram_writedata = 0;
assign ch0_data = ram_q[0];
assign ch1_data = ram_q[1];
assign ch0_ready = ready[0];
assign ch1_ready = ready[1];
reg [7:0] ram_burst;
reg [63:0] ram_q[2];
reg [31:3] ram_address;
reg [1:0] ack = 0;
reg [1:0] ready;
reg state = 0;
reg ch = 0;
always @(posedge clk) begin
ready <= 0;
if(!ram_waitrequest) begin
ram_read <= 0;
ram_write <= 0;
case(state)
0: if(ch0_req != ack[0]) begin
ack[0] <= ch0_req;
ram_address <= ch0_addr;
ram_burst <= ch0_burst;
ram_read <= 1;
ch <= 0;
ram_bcnt <= 8'hFF;
state <= 1;
end
else if(ch1_req != ack[1]) begin
ack[1] <= ch1_req;
ram_address <= ch1_addr;
ram_burst <= ch1_burst;
ram_read <= 1;
ch <= 1;
ram_bcnt <= 8'hFF;
state <= 1;
end
1: begin
if(ram_read_ready) begin
ram_bcnt <= ram_bcnt + 1'd1;
ram_q[ch] <= ram_readdata;
ready[ch] <= 1;
if ((ram_bcnt+2'd2) == ram_burst) state <= 0;
end
end
endcase
end
end
endmodule

View File

@@ -0,0 +1,250 @@
// ============================================================================
//
// f2sdram_safe_terminator for MiSTer platform
//
// ============================================================================
// Copyright (c) 2021 bellwood420
//
// Background:
//
// Terminating a transaction of burst writing(/reading) in its midstream
// seems to cause an illegal state to f2sdram interface.
//
// Forced reset request that occurs when loading other core is inevitable.
//
// So if it happens exactly within the transaction period,
// unexpected issues with accessing to f2sdram interface will be caused
// in next loaded core.
//
// It seems that only way to reset broken f2sdram interface is to reset
// whole SDRAM Controller Subsystem from HPS via permodrst register
// in Reset Manager.
// But it cannot be done safely while Linux is running.
// It is usually done when cold or warm reset is issued in HPS.
//
// Main_MiSTer is issuing reset for FPGA <> HPS bridges
// via brgmodrst register in Reset Manager when loading rbf.
// But it has no effect on f2sdram interface.
// f2sdram interface seems to belong to SDRAM Controller Subsystem
// rather than FPGA-to-HPS bridge.
//
// Main_MiSTer is also trying to issuing reset for f2sdram ports
// via fpgaportrst register in SDRAM Controller Subsystem when loading rbf.
// But according to the Intel's document, fpgaportrst register can be
// used to stretch the port reset.
// It seems that it cannot be used to assert the port reset.
//
// According to the Intel's document, there seems to be a reset port on
// Avalon-MM slave interface, but it cannot be found in Qsys generated HDL.
//
// To conclude, the only thing FPGA can do is not to break the transaction.
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
// Purpose:
// To prevent the issue, this module completes ongoing transaction
// on behalf of user logic, when reset is asserted.
//
// Usage:
// Insert this module into the bus line between
// f2sdram (Avalon-MM slave) and user logic (Avalon-MM master).
//
// Notice:
// Asynchronous reset request is not supported.
// Please feed reset request synchronized to clock.
//
module f2sdram_safe_terminator #(
parameter DATA_WIDTH = 64,
parameter BURSTCOUNT_WIDTH = 8
) (
// clk should be the same as one provided to f2sdram port
// clk should not be stop when reset is asserted
input clk,
// rst_req_sync should be synchronized to clk
// Asynchronous reset request is not supported
input rst_req_sync,
// Master port: connecting to Alavon-MM slave(f2sdram)
input waitrequest_master,
output [BURSTCOUNT_WIDTH-1:0] burstcount_master,
output [ADDRESS_WITDH-1:0] address_master,
input [DATA_WIDTH-1:0] readdata_master,
input readdatavalid_master,
output read_master,
output [DATA_WIDTH-1:0] writedata_master,
output [BYTEENABLE_WIDTH-1:0] byteenable_master,
output write_master,
// Slave port: connecting to Alavon-MM master(user logic)
output waitrequest_slave,
input [BURSTCOUNT_WIDTH-1:0] burstcount_slave,
input [ADDRESS_WITDH-1:0] address_slave,
output [DATA_WIDTH-1:0] readdata_slave,
output readdatavalid_slave,
input read_slave,
input [DATA_WIDTH-1:0] writedata_slave,
input [BYTEENABLE_WIDTH-1:0] byteenable_slave,
input write_slave
);
localparam BYTEENABLE_WIDTH = DATA_WIDTH/8;
localparam ADDRESS_WITDH = 32-$clog2(BYTEENABLE_WIDTH);
/*
* Capture init reset deaseert
*/
reg init_reset_deasserted = 1'b0;
always_ff @(posedge clk) begin
if (!rst_req_sync) begin
init_reset_deasserted <= 1'b1;
end
end
/*
* Lock stage
*/
reg lock_stage = 1'b0;
always_ff @(posedge clk) begin
if (rst_req_sync) begin
// Reset assert
if (init_reset_deasserted) begin
lock_stage <= 1'b1;
end
end
else begin
// Reset deassert
lock_stage <= 1'b0;
end
end
/*
* Write burst transaction observer
*/
reg state_write = 1'b0;
wire next_state_write;
wire burst_write_start = !state_write && next_state_write;
wire valid_write_data = state_write && !waitrequest_master;
wire burst_write_end = state_write && (write_burstcounter == write_burstcount_latch - 1'd1);
wire valid_non_burst_write = !state_write && write_slave && (burstcount_slave == 1) && !waitrequest_master;
reg [BURSTCOUNT_WIDTH-1:0] write_burstcounter = 0;
reg [BURSTCOUNT_WIDTH-1:0] write_burstcount_latch = 0;
reg [ADDRESS_WITDH-1:0] write_address_latch = 0;
always_ff @(posedge clk) begin
state_write <= next_state_write;
if (burst_write_start) begin
write_burstcounter <= waitrequest_master ? 1'd0 : 1'd1;
write_burstcount_latch <= burstcount_slave;
write_address_latch <= address_slave;
end
else if (valid_write_data) begin
write_burstcounter <= write_burstcounter + 1'd1;
end
end
always_comb begin
if (!state_write) begin
if (valid_non_burst_write)
next_state_write = 1'b0;
else if (write_slave)
next_state_write = 1'b1;
else
next_state_write = 1'b0;
end
else begin
if (burst_write_end)
next_state_write = 1'b0;
else
next_state_write = 1'b1;
end
end
reg [BURSTCOUNT_WIDTH-1:0] write_terminate_counter = 0;
reg [BURSTCOUNT_WIDTH-1:0] burstcount_latch = 0;
reg [ADDRESS_WITDH-1:0] address_latch = 0;
reg terminating = 0;
reg read_terminating = 0;
reg write_terminating = 0;
wire on_write_transaction = state_write && next_state_write;
wire on_start_write_transaction = !state_write && next_state_write;
always_ff @(posedge clk) begin
if (rst_req_sync) begin
// Reset assert
if (init_reset_deasserted) begin
if (!lock_stage) begin
// Even not knowing reading is in progress or not,
// if it is in progress, it will finish at some point, and no need to do anything.
// Assume that reading is in progress when we are not on write transaction.
burstcount_latch <= burstcount_slave;
address_latch <= address_slave;
terminating <= 1;
if (on_write_transaction) begin
write_terminating <= 1;
burstcount_latch <= write_burstcount_latch;
address_latch <= write_address_latch;
write_terminate_counter <= waitrequest_master ? write_burstcounter : write_burstcounter + 1'd1;
end
else if (on_start_write_transaction) begin
if (!valid_non_burst_write) begin
write_terminating <= 1;
write_terminate_counter <= waitrequest_master ? 1'd0 : 1'd1;
end
end
else if (read_slave && waitrequest_master) begin
// Need to keep read signal, burstcount and address until waitrequest_master deasserted
read_terminating <= 1;
end
end
else if (!waitrequest_master) begin
read_terminating <= 0;
end
end
end
else begin
// Reset deassert
if (!write_terminating) terminating <= 0;
read_terminating <= 0;
end
if (write_terminating) begin
// Continue write transaction until the end
if (!waitrequest_master) write_terminate_counter <= write_terminate_counter + 1'd1;
if (write_terminate_counter == burstcount_latch - 1'd1) write_terminating <= 0;
end
end
/*
* Bus mux depending on the stage.
*/
always_comb begin
if (terminating) begin
burstcount_master = burstcount_latch;
address_master = address_latch;
read_master = read_terminating;
write_master = write_terminating;
byteenable_master = 0;
end
else begin
burstcount_master = burstcount_slave;
address_master = address_slave;
read_master = read_slave;
byteenable_master = byteenable_slave;
write_master = write_slave;
end
end
// Just passing master <-> slave
assign writedata_master = writedata_slave;
assign readdata_slave = readdata_master;
assign readdatavalid_slave = readdatavalid_master;
assign waitrequest_slave = waitrequest_master;
endmodule

124
sys/gamma_corr.sv Normal file
View File

@@ -0,0 +1,124 @@
module gamma_corr
(
input clk_sys,
input clk_vid,
input ce_pix,
input gamma_en,
input gamma_wr,
input [9:0] gamma_wr_addr,
input [7:0] gamma_value,
input HSync,
input VSync,
input HBlank,
input VBlank,
input [23:0] RGB_in,
output reg HSync_out,
output reg VSync_out,
output reg HBlank_out,
output reg VBlank_out,
output reg [23:0] RGB_out
);
(* ramstyle="no_rw_check" *) reg [7:0] gamma_curve[768];
always @(posedge clk_sys) if (gamma_wr) gamma_curve[gamma_wr_addr] <= gamma_value;
always @(posedge clk_vid) gamma <= gamma_curve[gamma_index];
reg [9:0] gamma_index;
reg [7:0] gamma;
always @(posedge clk_vid) begin
reg [7:0] R_in, G_in, B_in;
reg [7:0] R_gamma, G_gamma;
reg hs,vs,hb,vb;
reg [1:0] ctr = 0;
reg old_ce;
old_ce <= ce_pix;
if(~old_ce & ce_pix) begin
{R_in,G_in,B_in} <= RGB_in;
hs <= HSync; vs <= VSync;
hb <= HBlank; vb <= VBlank;
RGB_out <= gamma_en ? {R_gamma,G_gamma,gamma} : {R_in,G_in,B_in};
HSync_out <= hs; VSync_out <= vs;
HBlank_out <= hb; VBlank_out <= vb;
ctr <= 1;
gamma_index <= {2'b00,RGB_in[23:16]};
end
if (|ctr) ctr <= ctr + 1'd1;
case(ctr)
1: begin gamma_index <= {2'b01,G_in}; end
2: begin R_gamma <= gamma; gamma_index <= {2'b10,B_in}; end
3: begin G_gamma <= gamma; end
endcase
end
endmodule
module gamma_fast
(
input clk_vid,
input ce_pix,
inout [21:0] gamma_bus,
input HSync,
input VSync,
input HBlank,
input VBlank,
input DE,
input [23:0] RGB_in,
output reg HSync_out,
output reg VSync_out,
output reg HBlank_out,
output reg VBlank_out,
output reg DE_out,
output reg [23:0] RGB_out
);
(* ramstyle="no_rw_check" *) reg [7:0] gamma_curve_r[256];
(* ramstyle="no_rw_check" *) reg [7:0] gamma_curve_g[256];
(* ramstyle="no_rw_check" *) reg [7:0] gamma_curve_b[256];
assign gamma_bus[21] = 1;
wire clk_sys = gamma_bus[20];
wire gamma_en = gamma_bus[19];
wire gamma_wr = gamma_bus[18];
wire [9:0] gamma_wr_addr = gamma_bus[17:8];
wire [7:0] gamma_value = gamma_bus[7:0];
always @(posedge clk_sys) if (gamma_wr) begin
case(gamma_wr_addr[9:8])
0: gamma_curve_r[gamma_wr_addr[7:0]] <= gamma_value;
1: gamma_curve_g[gamma_wr_addr[7:0]] <= gamma_value;
2: gamma_curve_b[gamma_wr_addr[7:0]] <= gamma_value;
endcase
end
reg [7:0] gamma_index_r,gamma_index_g,gamma_index_b;
always @(posedge clk_vid) begin
reg [7:0] R_in, G_in, B_in;
reg [7:0] R_gamma, G_gamma;
reg hs,vs,hb,vb,de;
if(ce_pix) begin
{gamma_index_r,gamma_index_g,gamma_index_b} <= RGB_in;
hs <= HSync; vs <= VSync;
hb <= HBlank; vb <= VBlank;
de <= DE;
RGB_out <= gamma_en ? {gamma_curve_r[gamma_index_r],gamma_curve_g[gamma_index_g],gamma_curve_b[gamma_index_b]}
: {gamma_index_r,gamma_index_g,gamma_index_b};
HSync_out <= hs; VSync_out <= vs;
HBlank_out <= hb; VBlank_out <= vb;
DE_out <= de;
end
end
endmodule

239
sys/hdmi_config.sv Normal file
View File

@@ -0,0 +1,239 @@
module hdmi_config
(
// Host Side
input iCLK,
input iRST_N,
input dvi_mode,
input audio_96k,
input [1:0] limited,
input ypbpr,
output reg done,
// I2C Side
output I2C_SCL,
inout I2C_SDA
);
// Internal Registers/Wires
reg mI2C_GO = 0;
wire mI2C_END;
wire mI2C_ACK;
reg [15:0] LUT_DATA;
reg [7:0] LUT_INDEX = 0;
i2c #(50_000_000, 20_000) i2c_av
(
.CLK(iCLK),
.I2C_SCL(I2C_SCL), // I2C CLOCK
.I2C_SDA(I2C_SDA), // I2C DATA
.I2C_ADDR('h39), // 0x39 is the Slave Address of the ADV7513 chip!
.I2C_WLEN(1),
.I2C_WDATA1(init_data[LUT_INDEX][15:8]), // SUB_ADDR
.I2C_WDATA2(init_data[LUT_INDEX][7:0]), // DATA
.START(mI2C_GO), // START transfer
.READ(0),
.END(mI2C_END), // END transfer
.ACK(mI2C_ACK) // ACK
);
////////////////////// Config Control ////////////////////////////
always@(posedge iCLK or negedge iRST_N) begin
reg [1:0] mSetup_ST = 0;
if(!iRST_N) begin
LUT_INDEX <= 0;
mSetup_ST <= 0;
mI2C_GO <= 0;
done <= 0;
end else begin
if(init_data[LUT_INDEX] != 16'hFFFF) begin
case(mSetup_ST)
0: begin
mI2C_GO <= 1;
mSetup_ST <= 1;
end
1: if(~mI2C_END) mSetup_ST <= 2;
2: begin
mI2C_GO <= 0;
if(mI2C_END) begin
mSetup_ST <= 0;
if(!mI2C_ACK) LUT_INDEX <= LUT_INDEX + 8'd1;
end
end
endcase
end
else done <= 1;
end
end
////////////////////////////////////////////////////////////////////
///////////////////// Config Data LUT //////////////////////////
wire [15:0] init_data[82] =
'{
16'h9803, // ADI required Write.
{8'hD6, 8'b1100_0000}, // [7:6] HPD Control...
// 00 = HPD is from both HPD pin or CDC HPD
// 01 = HPD is from CDC HPD
// 10 = HPD is from HPD pin
// 11 = HPD is always high
16'h4110, // Power Down control
16'h9A70, // ADI required Write.
16'h9C30, // ADI required Write.
{8'h9D, 8'b0110_0001}, // [7:4] must be b0110!.
// [3:2] b00 = Input clock not divided. b01 = Clk divided by 2. b10 = Clk divided by 4. b11 = invalid!
// [1:0] must be b01!
16'hA2A4, // ADI required Write.
16'hA3A4, // ADI required Write.
16'hE0D0, // ADI required Write.
16'h35_40,
16'h36_D9,
16'h37_0A,
16'h38_00,
16'h39_2D,
16'h3A_00,
{8'h16, 8'b0011_1000}, // Output Format 444 [7]=0.
// [6] must be 0!
// Colour Depth for Input Video data [5:4] b11 = 8-bit.
// Input Style [3:2] b10 = Style 1 (ignored when using 444 input).
// DDR Input Edge falling [1]=0 (not using DDR atm).
// Output Colour Space RGB [0]=0.
{8'h17, 8'b01100010}, // Aspect ratio 16:9 [1]=1, 4:3 [1]=0
{8'h18, ypbpr ? 8'h86 : limited[0] ? 8'h8D : limited[1] ? 8'h8E : 8'h00}, // CSC Scaling Factors and Coefficients for RGB Full->Limited.
{8'h19, ypbpr ? 8'hDF : limited[0] ? 8'hBC : 8'hFE}, // Taken from table in ADV7513 Programming Guide.
{8'h1A, ypbpr ? 8'h1A : 8'h00}, // CSC Channel A.
{8'h1B, ypbpr ? 8'h3F : 8'h00},
{8'h1C, ypbpr ? 8'h1E : 8'h00},
{8'h1D, ypbpr ? 8'hE2 : 8'h00},
{8'h1E, ypbpr ? 8'h07 : 8'h01},
{8'h1F, ypbpr ? 8'hE7 : 8'h00},
{8'h20, ypbpr ? 8'h04 : 8'h00}, // CSC Channel B.
{8'h21, ypbpr ? 8'h1C : 8'h00},
{8'h22, ypbpr ? 8'h08 : limited[0] ? 8'h0D : 8'h0E},
{8'h23, ypbpr ? 8'h11 : limited[0] ? 8'hBC : 8'hFE},
{8'h24, ypbpr ? 8'h01 : 8'h00},
{8'h25, ypbpr ? 8'h91 : 8'h00},
{8'h26, ypbpr ? 8'h01 : 8'h01},
{8'h27, 8'h00},
{8'h28, ypbpr ? 8'h1D : 8'h00}, // CSC Channel C.
{8'h29, ypbpr ? 8'hAE : 8'h00},
{8'h2A, ypbpr ? 8'h1B : 8'h00},
{8'h2B, ypbpr ? 8'h73 : 8'h00},
{8'h2C, ypbpr ? 8'h06 : limited[0] ? 8'h0D : 8'h0E},
{8'h2D, ypbpr ? 8'hDF : limited[0] ? 8'hBC : 8'hFE},
{8'h2E, ypbpr ? 8'h07 : 8'h01},
{8'h2F, ypbpr ? 8'hE7 : 8'h00},
{8'h3B, 8'b0000_0000}, // Pixel repetition [6:5] b00 AUTO. [4:3] b00 x1 mult of input clock. [2:1] b00 x1 pixel rep to send to HDMI Rx.
16'h4000, // General Control Packet Enable
{8'h48, 8'b0000_1000}, // [6]=0 Normal bus order!
// [5] DDR Alignment.
// [4:3] b01 Data right justified (for YCbCr 422 input modes).
16'h49A8, // ADI required Write.
16'h4C00, // ADI required Write.
{8'h55, 8'b0001_0000}, // [7] must be 0!. Set RGB444 in AVinfo Frame [6:5], Set active format [4].
// AVI InfoFrame Valid [4].
// Bar Info [3:2] b00 Bars invalid. b01 Bars vertical. b10 Bars horizontal. b11 Bars both.
// Scan Info [1:0] b00 (No data). b01 TV. b10 PC. b11 None.
{8'h57, 1'b0, // [7] IT Content. 0 - No. 1 - Yes (type set in register h59).
3'b000, // [6:4] Color space (ignored for RGB)
(ypbpr | limited) ? 2'b01 : 2'b10, // [3:2] RGB Quantization range
2'b00}, // [1:0] Non-Uniform Scaled: 00 - None. 01 - Horiz. 10 - Vert. 11 - Both.
16'h7301,
{8'h94, 8'b1000_0000}, // [7]=1 HPD Interrupt ENabled.
16'h9902, // ADI required Write.
16'h9B18, // ADI required Write.
16'h9F00, // ADI required Write.
{8'hA1, 8'b0000_0000}, // [6]=1 Monitor Sense Power Down DISabled.
16'hA408, // ADI required Write.
16'hA504, // ADI required Write.
16'hA600, // ADI required Write.
16'hA700, // ADI required Write.
16'hA800, // ADI required Write.
16'hA900, // ADI required Write.
16'hAA00, // ADI required Write.
16'hAB40, // ADI required Write.
{8'hAF, 6'b0000_01,~dvi_mode,1'b0}, // [7]=0 HDCP Disabled.
// [6:5] must be b00!
// [4]=0 Current frame is unencrypted
// [3:2] must be b01!
// [1]=1 HDMI Mode.
// [0] must be b0!
16'hB900, // ADI required Write.
{8'hBA, 8'b0110_0000}, // [7:5] Input Clock delay...
// b000 = -1.2ns.
// b001 = -0.8ns.
// b010 = -0.4ns.
// b011 = No delay.
// b100 = 0.4ns.
// b101 = 0.8ns.
// b110 = 1.2ns.
// b111 = 1.6ns.
16'hBB00, // ADI required Write.
16'hDE9C, // ADI required Write.
16'hE460, // ADI required Write.
16'hFA7D, // Nbr of times to search for good phase
// (Audio stuff on Programming Guide, Page 66)...
{8'h0A, 8'b0000_0000}, // [6:4] Audio Select. b000 = I2S.
// [3:2] Audio Mode. (HBR stuff, leave at 00!).
{8'h0B, 8'b0000_1110}, //
{8'h0C, 8'b0000_0100}, // [7] 0 = Use sampling rate from I2S stream. 1 = Use samp rate from I2C Register.
// [6] 0 = Use Channel Status bits from stream. 1 = Use Channel Status bits from I2C register.
// [2] 1 = I2S0 Enable.
// [1:0] I2S Format: 00 = Standard. 01 = Right Justified. 10 = Left Justified. 11 = AES.
{8'h0D, 8'b0001_0000}, // [4:0] I2S Bit (Word) Width for Right-Justified.
{8'h14, 8'b0000_0010}, // [3:0] Audio Word Length. b0010 = 16 bits.
{8'h15, audio_96k, 7'b010_0000}, // I2S Sampling Rate [7:4]. b0000 = (44.1KHz). b0010 = 48KHz.
// Input ID [3:1] b000 (0) = 24-bit RGB 444 or YCrCb 444 with Separate Syncs.
// Audio Clock Config
16'h0100, //
audio_96k ? 16'h0230 : 16'h0218, // Set N Value 12288/6144
16'h0300, //
16'h0701, //
16'h0822, // Set CTS Value 74250
16'h090A, //
16'hFFFF // END
};
////////////////////////////////////////////////////////////////////
endmodule

938
sys/hps_io.v Normal file
View File

@@ -0,0 +1,938 @@
//
// hps_io.v
//
// Copyright (c) 2014 Till Harbaum <till@harbaum.org>
// Copyright (c) 2017-2020 Alexey Melnikov
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////
// altera message_off 10665
//
// Use buffer to access SD card. It's time-critical part.
//
// WIDE=1 for 16 bit file I/O
// VDNUM 1-4
module hps_io #(parameter STRLEN=0, PS2DIV=0, WIDE=0, VDNUM=1, PS2WE=0)
(
input clk_sys,
inout [45:0] HPS_BUS,
// parameter STRLEN and the actual length of conf_str have to match
input [(8*STRLEN)-1:0] conf_str,
// buttons up to 32
output reg [31:0] joystick_0,
output reg [31:0] joystick_1,
output reg [31:0] joystick_2,
output reg [31:0] joystick_3,
output reg [31:0] joystick_4,
output reg [31:0] joystick_5,
// analog -127..+127, Y: [15:8], X: [7:0]
output reg [15:0] joystick_analog_0,
output reg [15:0] joystick_analog_1,
output reg [15:0] joystick_analog_2,
output reg [15:0] joystick_analog_3,
output reg [15:0] joystick_analog_4,
output reg [15:0] joystick_analog_5,
// paddle 0..255
output reg [7:0] paddle_0,
output reg [7:0] paddle_1,
output reg [7:0] paddle_2,
output reg [7:0] paddle_3,
output reg [7:0] paddle_4,
output reg [7:0] paddle_5,
// spinner [7:0] -128..+127, [8] - toggle with every update
output reg [8:0] spinner_0,
output reg [8:0] spinner_1,
output reg [8:0] spinner_2,
output reg [8:0] spinner_3,
output reg [8:0] spinner_4,
output reg [8:0] spinner_5,
output [1:0] buttons,
output forced_scandoubler,
output direct_video,
output reg [63:0] status,
input [63:0] status_in,
input status_set,
input [15:0] status_menumask,
input info_req,
input [7:0] info,
//toggle to force notify of video mode change
input new_vmode,
// SD config
output reg [VD:0] img_mounted, // signaling that new image has been mounted
output reg img_readonly, // mounted as read only. valid only for active bit in img_mounted
output reg [63:0] img_size, // size of image in bytes. valid only for active bit in img_mounted
// SD block level access
input [31:0] sd_lba,
input [VD:0] sd_rd, // only single sd_rd can be active at any given time
input [VD:0] sd_wr, // only single sd_wr can be active at any given time
output reg sd_ack,
// do not use in new projects.
// CID and CSD are fake except CSD image size field.
input sd_conf,
output reg sd_ack_conf,
// SD byte level access. Signals for 2-PORT altsyncram.
output reg [AW:0] sd_buff_addr,
output reg [DW:0] sd_buff_dout,
input [DW:0] sd_buff_din,
output reg sd_buff_wr,
input [15:0] sd_req_type,
// ARM -> FPGA download
output reg ioctl_download = 0, // signal indicating an active download
output reg [15:0] ioctl_index, // menu index used to upload the file
output reg ioctl_wr,
output reg [26:0] ioctl_addr, // in WIDE mode address will be incremented by 2
output reg [DW:0] ioctl_dout,
output reg ioctl_upload = 0, // signal indicating an active upload
input [DW:0] ioctl_din,
output reg ioctl_rd,
output reg [31:0] ioctl_file_ext,
input ioctl_wait,
// [15]: 0 - unset, 1 - set. [1:0]: 0 - none, 1 - 32MB, 2 - 64MB, 3 - 128MB
// [14]: debug mode: [8]: 1 - phase up, 0 - phase down. [7:0]: amount of shift.
output reg [15:0] sdram_sz,
// RTC MSM6242B layout
output reg [64:0] RTC,
// Seconds since 1970-01-01 00:00:00
output reg [32:0] TIMESTAMP,
// UART flags
output reg [7:0] uart_mode,
output reg [31:0] uart_speed,
// ps2 keyboard emulation
output ps2_kbd_clk_out,
output ps2_kbd_data_out,
input ps2_kbd_clk_in,
input ps2_kbd_data_in,
input [2:0] ps2_kbd_led_status,
input [2:0] ps2_kbd_led_use,
output ps2_mouse_clk_out,
output ps2_mouse_data_out,
input ps2_mouse_clk_in,
input ps2_mouse_data_in,
// ps2 alternative interface.
// [8] - extended, [9] - pressed, [10] - toggles with every press/release
output reg [10:0] ps2_key = 0,
// [24] - toggles with every event
output reg [24:0] ps2_mouse = 0,
output reg [15:0] ps2_mouse_ext = 0, // 15:8 - reserved(additional buttons), 7:0 - wheel movements
inout [21:0] gamma_bus,
// for core-specific extensions
inout [35:0] EXT_BUS
);
assign EXT_BUS[31:16] = HPS_BUS[31:16];
assign EXT_BUS[35:33] = HPS_BUS[35:33];
localparam MAX_W = $clog2((512 > (STRLEN+1)) ? 512 : (STRLEN+1))-1;
localparam DW = (WIDE) ? 15 : 7;
localparam AW = (WIDE) ? 7 : 8;
localparam VD = VDNUM-1;
wire io_strobe= HPS_BUS[33];
wire io_enable= HPS_BUS[34];
wire fp_enable= HPS_BUS[35];
wire io_wide = (WIDE) ? 1'b1 : 1'b0;
wire [15:0] io_din = HPS_BUS[31:16];
reg [15:0] io_dout;
assign HPS_BUS[37] = ioctl_wait;
assign HPS_BUS[36] = clk_sys;
assign HPS_BUS[32] = io_wide;
assign HPS_BUS[15:0] = EXT_BUS[32] ? EXT_BUS[15:0] : fp_enable ? fp_dout : io_dout;
reg [15:0] cfg;
assign buttons = cfg[1:0];
//cfg[2] - vga_scaler handled in sys_top
//cfg[3] - csync handled in sys_top
assign forced_scandoubler = cfg[4];
//cfg[5] - ypbpr handled in sys_top
assign direct_video = cfg[10];
// command byte read by the io controller
wire [15:0] sd_cmd =
{
2'b00,
(VDNUM>=4) ? sd_wr[3] : 1'b0,
(VDNUM>=3) ? sd_wr[2] : 1'b0,
(VDNUM>=2) ? sd_wr[1] : 1'b0,
(VDNUM>=4) ? sd_rd[3] : 1'b0,
(VDNUM>=3) ? sd_rd[2] : 1'b0,
(VDNUM>=2) ? sd_rd[1] : 1'b0,
4'h5, sd_conf, 1'b1,
sd_wr[0],
sd_rd[0]
};
/////////////////////////////////////////////////////////
wire [15:0] vc_dout;
video_calc video_calc
(
.clk_100(HPS_BUS[43]),
.clk_vid(HPS_BUS[42]),
.clk_sys(clk_sys),
.ce_pix(HPS_BUS[41]),
.de(HPS_BUS[40]),
.hs(HPS_BUS[39]),
.vs(HPS_BUS[38]),
.vs_hdmi(HPS_BUS[44]),
.f1(HPS_BUS[45]),
.new_vmode(new_vmode),
.par_num(byte_cnt[3:0]),
.dout(vc_dout)
);
/////////////////////////////////////////////////////////
assign gamma_bus[20:0] = {clk_sys, gamma_en, gamma_wr, gamma_wr_addr, gamma_value};
reg gamma_en;
reg gamma_wr;
reg [9:0] gamma_wr_addr;
reg [7:0] gamma_value;
reg [31:0] ps2_key_raw = 0;
wire pressed = (ps2_key_raw[15:8] != 8'hf0);
wire extended = (~pressed ? (ps2_key_raw[23:16] == 8'he0) : (ps2_key_raw[15:8] == 8'he0));
reg [MAX_W:0] byte_cnt;
always@(posedge clk_sys) begin : uio_block
reg [15:0] cmd;
reg [2:0] b_wr;
reg [3:0] stick_idx;
reg [3:0] pdsp_idx;
reg ps2skip = 0;
reg [3:0] stflg = 0;
reg [63:0] status_req;
reg old_status_set = 0;
reg old_info = 0;
reg [7:0] info_n = 0;
reg [15:0] tmp1;
reg [7:0] tmp2;
old_status_set <= status_set;
if(~old_status_set & status_set) begin
stflg <= stflg + 1'd1;
status_req <= status_in;
end
old_info <= info_req;
if(~old_info & info_req) info_n <= info;
sd_buff_wr <= b_wr[0];
if(b_wr[2] && (~&sd_buff_addr)) sd_buff_addr <= sd_buff_addr + 1'b1;
b_wr <= (b_wr<<1);
if(PS2DIV) {kbd_rd,kbd_we,mouse_rd,mouse_we} <= 0;
gamma_wr <= 0;
if(~io_enable) begin
if(cmd == 4 && !ps2skip) ps2_mouse[24] <= ~ps2_mouse[24];
if(cmd == 5 && !ps2skip) begin
ps2_key <= {~ps2_key[10], pressed, extended, ps2_key_raw[7:0]};
if(ps2_key_raw == 'hE012E07C) ps2_key[9:0] <= 'h37C; // prnscr pressed
if(ps2_key_raw == 'h7CE0F012) ps2_key[9:0] <= 'h17C; // prnscr released
if(ps2_key_raw == 'hF014F077) ps2_key[9:0] <= 'h377; // pause pressed
end
if(cmd == 'h22) RTC[64] <= ~RTC[64];
if(cmd == 'h24) TIMESTAMP[32] <= ~TIMESTAMP[32];
cmd <= 0;
byte_cnt <= 0;
sd_ack <= 0;
sd_ack_conf <= 0;
io_dout <= 0;
ps2skip <= 0;
img_mounted <= 0;
end
else if(io_strobe) begin
io_dout <= 0;
if(~&byte_cnt) byte_cnt <= byte_cnt + 1'd1;
if(byte_cnt == 0) begin
cmd <= io_din;
case(io_din)
'h19: sd_ack_conf <= 1;
'h17,
'h18: sd_ack <= 1;
'h29: io_dout <= {4'hA, stflg};
'h2B: io_dout <= 1;
'h2F: io_dout <= 1;
'h32: io_dout <= gamma_bus[21];
'h36: begin io_dout <= info_n; info_n <= 0; end
'h39: io_dout <= 1;
endcase
sd_buff_addr <= 0;
if(io_din == 5) ps2_key_raw <= 0;
end else begin
case(cmd)
// buttons and switches
'h01: cfg <= io_din;
'h02: if(byte_cnt==1) joystick_0[15:0] <= io_din; else joystick_0[31:16] <= io_din;
'h03: if(byte_cnt==1) joystick_1[15:0] <= io_din; else joystick_1[31:16] <= io_din;
'h10: if(byte_cnt==1) joystick_2[15:0] <= io_din; else joystick_2[31:16] <= io_din;
'h11: if(byte_cnt==1) joystick_3[15:0] <= io_din; else joystick_3[31:16] <= io_din;
'h12: if(byte_cnt==1) joystick_4[15:0] <= io_din; else joystick_4[31:16] <= io_din;
'h13: if(byte_cnt==1) joystick_5[15:0] <= io_din; else joystick_5[31:16] <= io_din;
// store incoming ps2 mouse bytes
'h04: begin
if(PS2DIV) begin
mouse_data <= io_din[7:0];
mouse_we <= 1;
end
if(&io_din[15:8]) ps2skip <= 1;
if(~&io_din[15:8] && ~ps2skip && !byte_cnt[MAX_W:2]) begin
case(byte_cnt[1:0])
1: ps2_mouse[7:0] <= io_din[7:0];
2: ps2_mouse[15:8] <= io_din[7:0];
3: ps2_mouse[23:16] <= io_din[7:0];
endcase
case(byte_cnt[1:0])
1: ps2_mouse_ext[7:0] <= {io_din[14], io_din[14:8]};
2: ps2_mouse_ext[11:8] <= io_din[11:8];
3: ps2_mouse_ext[15:12]<= io_din[11:8];
endcase
end
end
// store incoming ps2 keyboard bytes
'h05: begin
if(&io_din[15:8]) ps2skip <= 1;
if(~&io_din[15:8] & ~ps2skip) ps2_key_raw[31:0] <= {ps2_key_raw[23:0], io_din[7:0]};
if(PS2DIV) begin
kbd_data <= io_din[7:0];
kbd_we <= 1;
end
end
// reading config string, returning a byte from string
'h14: if(byte_cnt < STRLEN + 1) io_dout[7:0] <= conf_str[(STRLEN - byte_cnt)<<3 +:8];
// reading sd card status
'h16: if(!byte_cnt[MAX_W:3]) begin
case(byte_cnt[2:0])
1: io_dout <= sd_cmd;
2: io_dout <= sd_lba[15:0];
3: io_dout <= sd_lba[31:16];
4: io_dout <= sd_req_type;
endcase
end
// send SD config IO -> FPGA
// flag that download begins
// sd card knows data is config if sd_dout_strobe is asserted
// with sd_ack still being inactive (low)
'h19,
// send sector IO -> FPGA
// flag that download begins
'h17: begin
sd_buff_dout <= io_din[DW:0];
b_wr <= 1;
end
// reading sd card write data
'h18: begin
if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1;
io_dout <= sd_buff_din;
end
// joystick analog
'h1a: if(!byte_cnt[MAX_W:2]) begin
case(byte_cnt[1:0])
1: {pdsp_idx,stick_idx} <= io_din[7:0]; // first byte is joystick index
2: case(stick_idx)
0: joystick_analog_0 <= io_din;
1: joystick_analog_1 <= io_din;
2: joystick_analog_2 <= io_din;
3: joystick_analog_3 <= io_din;
4: joystick_analog_4 <= io_din;
5: joystick_analog_5 <= io_din;
15: case(pdsp_idx)
0: paddle_0 <= io_din[7:0];
1: paddle_1 <= io_din[7:0];
2: paddle_2 <= io_din[7:0];
3: paddle_3 <= io_din[7:0];
4: paddle_4 <= io_din[7:0];
5: paddle_5 <= io_din[7:0];
8: spinner_0 <= {~spinner_0[8],io_din[7:0]};
9: spinner_1 <= {~spinner_1[8],io_din[7:0]};
10: spinner_2 <= {~spinner_2[8],io_din[7:0]};
11: spinner_3 <= {~spinner_3[8],io_din[7:0]};
12: spinner_4 <= {~spinner_4[8],io_din[7:0]};
13: spinner_5 <= {~spinner_5[8],io_din[7:0]};
endcase
endcase
endcase
end
// notify image selection
'h1c: begin
img_mounted <= io_din[VD:0] ? io_din[VD:0] : 1'b1;
img_readonly <= io_din[7];
end
// send image info
'h1d: if(byte_cnt<5) img_size[{byte_cnt-1'b1, 4'b0000} +:16] <= io_din;
// status, 64bit version
'h1e: if(!byte_cnt[MAX_W:3]) begin
case(byte_cnt[2:0])
1: status[15:00] <= io_din;
2: status[31:16] <= io_din;
3: status[47:32] <= io_din;
4: status[63:48] <= io_din;
endcase
end
// reading keyboard LED status
'h1f: io_dout <= {|PS2WE, 2'b01, ps2_kbd_led_status[2], ps2_kbd_led_use[2], ps2_kbd_led_status[1], ps2_kbd_led_use[1], ps2_kbd_led_status[0], ps2_kbd_led_use[0]};
// reading ps2 keyboard/mouse control
'h21: if(PS2DIV) begin
if(byte_cnt == 1) begin
io_dout <= kbd_data_host;
kbd_rd <= 1;
end
else
if(byte_cnt == 2) begin
io_dout <= mouse_data_host;
mouse_rd <= 1;
end
end
//RTC
'h22: RTC[(byte_cnt-6'd1)<<4 +:16] <= io_din;
//Video res.
'h23: if(!byte_cnt[MAX_W:4]) io_dout <= vc_dout;
//RTC
'h24: TIMESTAMP[(byte_cnt-6'd1)<<4 +:16] <= io_din;
//status set
'h29: if(!byte_cnt[MAX_W:3]) begin
case(byte_cnt[2:0])
1: io_dout <= status_req[15:00];
2: io_dout <= status_req[31:16];
3: io_dout <= status_req[47:32];
4: io_dout <= status_req[63:48];
endcase
end
//menu mask
'h2E: if(byte_cnt == 1) io_dout <= status_menumask;
//sdram size set
'h31: if(byte_cnt == 1) sdram_sz <= io_din;
// Gamma
'h32: gamma_en <= io_din[0];
'h33: begin
gamma_wr_addr <= {(byte_cnt[1:0]-1'b1),io_din[15:8]};
{gamma_wr, gamma_value} <= {1'b1,io_din[7:0]};
if (byte_cnt[1:0] == 3) byte_cnt <= 1;
end
// UART
'h3b: if(!byte_cnt[MAX_W:2]) begin
case(byte_cnt[1:0])
1: tmp2 <= io_din[7:0];
2: tmp1 <= io_din;
3: {uart_speed, uart_mode} <= {io_din, tmp1, tmp2};
endcase
end
endcase
end
end
end
/////////////////////////////// PS2 ///////////////////////////////
generate
if(PS2DIV) begin
reg clk_ps2;
always @(posedge clk_sys) begin
integer cnt;
cnt <= cnt + 1'd1;
if(cnt == PS2DIV) begin
clk_ps2 <= ~clk_ps2;
cnt <= 0;
end
end
reg [7:0] kbd_data;
reg kbd_we;
wire [8:0] kbd_data_host;
reg kbd_rd;
ps2_device keyboard
(
.clk_sys(clk_sys),
.wdata(kbd_data),
.we(kbd_we),
.ps2_clk(clk_ps2),
.ps2_clk_out(ps2_kbd_clk_out),
.ps2_dat_out(ps2_kbd_data_out),
.ps2_clk_in(ps2_kbd_clk_in || !PS2WE),
.ps2_dat_in(ps2_kbd_data_in || !PS2WE),
.rdata(kbd_data_host),
.rd(kbd_rd)
);
reg [7:0] mouse_data;
reg mouse_we;
wire [8:0] mouse_data_host;
reg mouse_rd;
ps2_device mouse
(
.clk_sys(clk_sys),
.wdata(mouse_data),
.we(mouse_we),
.ps2_clk(clk_ps2),
.ps2_clk_out(ps2_mouse_clk_out),
.ps2_dat_out(ps2_mouse_data_out),
.ps2_clk_in(ps2_mouse_clk_in || !PS2WE),
.ps2_dat_in(ps2_mouse_data_in || !PS2WE),
.rdata(mouse_data_host),
.rd(mouse_rd)
);
end
else begin
assign ps2_kbd_clk_out = 0;
assign ps2_kbd_data_out = 0;
assign ps2_mouse_clk_out = 0;
assign ps2_mouse_data_out = 0;
end
endgenerate
/////////////////////////////// DOWNLOADING ///////////////////////////////
localparam FIO_FILE_TX = 8'h53;
localparam FIO_FILE_TX_DAT = 8'h54;
localparam FIO_FILE_INDEX = 8'h55;
localparam FIO_FILE_INFO = 8'h56;
reg [15:0] fp_dout;
always@(posedge clk_sys) begin : fio_block
reg [15:0] cmd;
reg [2:0] cnt;
reg has_cmd;
reg [26:0] addr;
reg wr;
ioctl_rd <= 0;
ioctl_wr <= wr;
wr <= 0;
if(~fp_enable) has_cmd <= 0;
else begin
if(io_strobe) begin
if(!has_cmd) begin
cmd <= io_din;
has_cmd <= 1;
cnt <= 0;
end else begin
case(cmd)
FIO_FILE_INFO:
if(~cnt[1]) begin
case(cnt)
0: ioctl_file_ext[31:16] <= io_din;
1: ioctl_file_ext[15:00] <= io_din;
endcase
cnt <= cnt + 1'd1;
end
FIO_FILE_INDEX:
begin
ioctl_index <= io_din[15:0];
end
FIO_FILE_TX:
begin
cnt <= cnt + 1'd1;
case(cnt)
0: if(io_din[7:0] == 8'hAA) begin
ioctl_addr <= 0;
ioctl_upload <= 1;
ioctl_rd <= 1;
end
else if(io_din[7:0]) begin
addr <= 0;
ioctl_download <= 1;
end
else begin
if(ioctl_download) ioctl_addr <= addr;
ioctl_download <= 0;
ioctl_upload <= 0;
end
1: begin
ioctl_addr[15:0] <= io_din;
addr[15:0] <= io_din;
end
2: begin
ioctl_addr[26:16] <= io_din[10:0];
addr[26:16] <= io_din[10:0];
end
endcase
end
FIO_FILE_TX_DAT:
if(ioctl_download) begin
ioctl_addr <= addr;
ioctl_dout <= io_din[DW:0];
wr <= 1;
addr <= addr + (WIDE ? 2'd2 : 2'd1);
end
else begin
ioctl_addr <= ioctl_addr + (WIDE ? 2'd2 : 2'd1);
fp_dout <= ioctl_din;
ioctl_rd <= 1;
end
endcase
end
end
end
end
endmodule
//////////////////////////////////////////////////////////////////////////////////
module ps2_device #(parameter PS2_FIFO_BITS=5)
(
input clk_sys,
input [7:0] wdata,
input we,
input ps2_clk,
output reg ps2_clk_out,
output reg ps2_dat_out,
output reg tx_empty,
input ps2_clk_in,
input ps2_dat_in,
output [8:0] rdata,
input rd
);
(* ramstyle = "logic" *) reg [7:0] fifo[1<<PS2_FIFO_BITS];
reg [PS2_FIFO_BITS-1:0] wptr;
reg [PS2_FIFO_BITS-1:0] rptr;
reg [2:0] rx_state = 0;
reg [3:0] tx_state = 0;
reg has_data;
reg [7:0] data;
assign rdata = {has_data, data};
always@(posedge clk_sys) begin
reg [7:0] tx_byte;
reg parity;
reg r_inc;
reg old_clk;
reg [1:0] timeout;
reg [3:0] rx_cnt;
reg c1,c2,d1;
tx_empty <= ((wptr == rptr) && (tx_state == 0));
if(we && !has_data) begin
fifo[wptr] <= wdata;
wptr <= wptr + 1'd1;
end
if(rd) has_data <= 0;
c1 <= ps2_clk_in;
c2 <= c1;
d1 <= ps2_dat_in;
if(!rx_state && !tx_state && ~c2 && c1 && ~d1) begin
rx_state <= rx_state + 1'b1;
ps2_dat_out <= 1;
end
old_clk <= ps2_clk;
if(~old_clk & ps2_clk) begin
if(rx_state) begin
case(rx_state)
1: begin
rx_state <= rx_state + 1'b1;
rx_cnt <= 0;
end
2: begin
if(rx_cnt <= 7) data <= {d1, data[7:1]};
else rx_state <= rx_state + 1'b1;
rx_cnt <= rx_cnt + 1'b1;
end
3: if(d1) begin
rx_state <= rx_state + 1'b1;
ps2_dat_out <= 0;
end
4: begin
ps2_dat_out <= 1;
has_data <= 1;
rx_state <= 0;
rptr <= 0;
wptr <= 0;
end
endcase
end else begin
// transmitter is idle?
if(tx_state == 0) begin
// data in fifo present?
if(c2 && c1 && d1 && wptr != rptr) begin
timeout <= timeout - 1'd1;
if(!timeout) begin
tx_byte <= fifo[rptr];
rptr <= rptr + 1'd1;
// reset parity
parity <= 1;
// start transmitter
tx_state <= 1;
// put start bit on data line
ps2_dat_out <= 0; // start bit is 0
end
end
end else begin
// transmission of 8 data bits
if((tx_state >= 1)&&(tx_state < 9)) begin
ps2_dat_out <= tx_byte[0]; // data bits
tx_byte[6:0] <= tx_byte[7:1]; // shift down
if(tx_byte[0])
parity <= !parity;
end
// transmission of parity
if(tx_state == 9) ps2_dat_out <= parity;
// transmission of stop bit
if(tx_state == 10) ps2_dat_out <= 1; // stop bit is 1
// advance state machine
if(tx_state < 11) tx_state <= tx_state + 1'd1;
else tx_state <= 0;
end
end
end
if(~old_clk & ps2_clk) ps2_clk_out <= 1;
if(old_clk & ~ps2_clk) ps2_clk_out <= ((tx_state == 0) && (rx_state<2));
end
endmodule
///////////////// calc video parameters //////////////////
module video_calc
(
input clk_100,
input clk_vid,
input clk_sys,
input ce_pix,
input de,
input hs,
input vs,
input vs_hdmi,
input f1,
input new_vmode,
input [3:0] par_num,
output reg [15:0] dout
);
always @(posedge clk_sys) begin
case(par_num)
1: dout <= {|vid_int, vid_nres};
2: dout <= vid_hcnt[15:0];
3: dout <= vid_hcnt[31:16];
4: dout <= vid_vcnt[15:0];
5: dout <= vid_vcnt[31:16];
6: dout <= vid_htime[15:0];
7: dout <= vid_htime[31:16];
8: dout <= vid_vtime[15:0];
9: dout <= vid_vtime[31:16];
10: dout <= vid_pix[15:0];
11: dout <= vid_pix[31:16];
12: dout <= vid_vtime_hdmi[15:0];
13: dout <= vid_vtime_hdmi[31:16];
default dout <= 0;
endcase
end
reg [31:0] vid_hcnt = 0;
reg [31:0] vid_vcnt = 0;
reg [7:0] vid_nres = 0;
reg [1:0] vid_int = 0;
always @(posedge clk_vid) begin
integer hcnt;
integer vcnt;
reg old_vs= 0, old_de = 0, old_vmode = 0;
reg [3:0] resto = 0;
reg calch = 0;
if(ce_pix) begin
old_vs <= vs;
old_de <= de;
if(~vs & ~old_de & de) vcnt <= vcnt + 1;
if(calch & de) hcnt <= hcnt + 1;
if(old_de & ~de) calch <= 0;
if(old_vs & ~vs) begin
vid_int <= {vid_int[0],f1};
if(~f1) begin
if(hcnt && vcnt) begin
old_vmode <= new_vmode;
//report new resolution after timeout
if(resto) resto <= resto + 1'd1;
if(vid_hcnt != hcnt || vid_vcnt != vcnt || old_vmode != new_vmode) resto <= 1;
if(&resto) vid_nres <= vid_nres + 1'd1;
vid_hcnt <= hcnt;
vid_vcnt <= vcnt;
end
vcnt <= 0;
hcnt <= 0;
calch <= 1;
end
end
end
end
reg [31:0] vid_htime = 0;
reg [31:0] vid_vtime = 0;
reg [31:0] vid_pix = 0;
always @(posedge clk_100) begin
integer vtime, htime, hcnt;
reg old_vs, old_hs, old_vs2, old_hs2, old_de, old_de2;
reg calch = 0;
old_vs <= vs;
old_hs <= hs;
old_vs2 <= old_vs;
old_hs2 <= old_hs;
vtime <= vtime + 1'd1;
htime <= htime + 1'd1;
if(~old_vs2 & old_vs) begin
vid_pix <= hcnt;
vid_vtime <= vtime;
vtime <= 0;
hcnt <= 0;
end
if(old_vs2 & ~old_vs) calch <= 1;
if(~old_hs2 & old_hs) begin
vid_htime <= htime;
htime <= 0;
end
old_de <= de;
old_de2 <= old_de;
if(calch & old_de) hcnt <= hcnt + 1;
if(old_de2 & ~old_de) calch <= 0;
end
reg [31:0] vid_vtime_hdmi;
always @(posedge clk_100) begin
integer vtime;
reg old_vs, old_vs2;
old_vs <= vs_hdmi;
old_vs2 <= old_vs;
vtime <= vtime + 1'd1;
if(~old_vs2 & old_vs) begin
vid_vtime_hdmi <= vtime;
vtime <= 0;
end
end
endmodule

371
sys/hq2x.sv Normal file
View File

@@ -0,0 +1,371 @@
//
//
// Copyright (c) 2012-2013 Ludvig Strigeus
// Copyright (c) 2017,2018 Sorgelig
//
// This program is GPL Licensed. See COPYING for the full license.
//
//
////////////////////////////////////////////////////////////////////////////////////////////////////////
// altera message_off 10030
module Hq2x #(parameter LENGTH, parameter HALF_DEPTH)
(
input clk,
input ce_in,
input [DWIDTH:0] inputpixel,
input mono,
input disable_hq2x,
input reset_frame,
input reset_line,
input ce_out,
input [1:0] read_y,
input hblank,
output [DWIDTH:0] outpixel
);
localparam AWIDTH = $clog2(LENGTH)-1;
localparam DWIDTH = HALF_DEPTH ? 11 : 23;
localparam DWIDTH1 = DWIDTH+1;
(* romstyle = "MLAB" *) reg [5:0] hqTable[256];
initial begin
hqTable = '{
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 47, 35, 23, 15, 55, 39,
19, 19, 26, 58, 19, 19, 26, 58, 23, 15, 35, 35, 23, 15, 7, 35,
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 55, 39, 23, 15, 51, 43,
19, 19, 26, 58, 19, 19, 26, 58, 23, 15, 51, 35, 23, 15, 7, 43,
19, 19, 26, 11, 19, 19, 26, 11, 23, 61, 35, 35, 23, 61, 51, 35,
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 51, 35,
19, 19, 26, 11, 19, 19, 26, 11, 23, 61, 7, 35, 23, 61, 7, 43,
19, 19, 26, 11, 19, 19, 26, 58, 23, 15, 51, 35, 23, 61, 7, 43,
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 47, 35, 23, 15, 55, 39,
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 51, 35,
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 55, 39, 23, 15, 51, 43,
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 39, 23, 15, 7, 43,
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 51, 39,
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 7, 35,
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 7, 43,
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 7, 35, 23, 15, 7, 43
};
end
wire [5:0] hqrule = hqTable[nextpatt];
reg [23:0] Prev0, Prev1, Prev2, Curr0, Curr1, Curr2, Next0, Next1, Next2;
reg [23:0] A, B, D, F, G, H;
reg [7:0] pattern, nextpatt;
reg [1:0] cyc;
reg curbuf;
reg prevbuf = 0;
wire iobuf = !curbuf;
wire diff0, diff1;
DiffCheck diffcheck0(Curr1, (cyc == 0) ? Prev0 : (cyc == 1) ? Curr0 : (cyc == 2) ? Prev2 : Next1, diff0);
DiffCheck diffcheck1(Curr1, (cyc == 0) ? Prev1 : (cyc == 1) ? Next0 : (cyc == 2) ? Curr2 : Next2, diff1);
wire [7:0] new_pattern = {diff1, diff0, pattern[7:2]};
wire [23:0] X = (cyc == 0) ? A : (cyc == 1) ? Prev1 : (cyc == 2) ? Next1 : G;
wire [23:0] blend_result_pre;
Blend blender(clk, ce_in, disable_hq2x ? 6'd0 : hqrule, Curr0, X, B, D, F, H, blend_result_pre);
wire [DWIDTH:0] Curr20tmp;
wire [23:0] Curr20 = HALF_DEPTH ? h2rgb(Curr20tmp) : Curr20tmp;
wire [DWIDTH:0] Curr21tmp;
wire [23:0] Curr21 = HALF_DEPTH ? h2rgb(Curr21tmp) : Curr21tmp;
reg [AWIDTH:0] wrin_addr2;
reg [DWIDTH:0] wrpix;
reg wrin_en;
function [23:0] h2rgb;
input [11:0] v;
begin
h2rgb = mono ? {v[7:0], v[7:0], v[7:0]} : {v[11:8],v[11:8],v[7:4],v[7:4],v[3:0],v[3:0]};
end
endfunction
function [11:0] rgb2h;
input [23:0] v;
begin
rgb2h = mono ? {4'b0000, v[23:20], v[19:16]} : {v[23:20], v[15:12], v[7:4]};
end
endfunction
hq2x_in #(.LENGTH(LENGTH), .DWIDTH(DWIDTH)) hq2x_in
(
.clk(clk),
.rdaddr(offs),
.rdbuf0(prevbuf),
.rdbuf1(curbuf),
.q0(Curr20tmp),
.q1(Curr21tmp),
.wraddr(wrin_addr2),
.wrbuf(iobuf),
.data(wrpix),
.wren(wrin_en)
);
reg [AWIDTH+1:0] read_x;
reg [AWIDTH+1:0] wrout_addr;
reg wrout_en;
reg [DWIDTH1*4-1:0] wrdata, wrdata_pre;
wire [DWIDTH1*4-1:0] outpixel_x4;
reg [DWIDTH1*2-1:0] outpixel_x2;
assign outpixel = read_x[0] ? outpixel_x2[DWIDTH1*2-1:DWIDTH1] : outpixel_x2[DWIDTH:0];
hq2x_buf #(.NUMWORDS(LENGTH*2), .AWIDTH(AWIDTH+1), .DWIDTH(DWIDTH1*4-1)) hq2x_out
(
.clock(clk),
.rdaddress({read_x[AWIDTH+1:1],read_y[1]}),
.q(outpixel_x4),
.data(wrdata),
.wraddress(wrout_addr),
.wren(wrout_en)
);
always @(posedge clk) begin
if(ce_out) begin
if(read_x[0]) outpixel_x2 <= read_y[0] ? outpixel_x4[DWIDTH1*4-1:DWIDTH1*2] : outpixel_x4[DWIDTH1*2-1:0];
if(~hblank & ~&read_x) read_x <= read_x + 1'd1;
if(hblank) read_x <= 0;
end
end
wire [DWIDTH:0] blend_result = HALF_DEPTH ? rgb2h(blend_result_pre) : blend_result_pre[DWIDTH:0];
reg [AWIDTH:0] offs;
always @(posedge clk) begin
reg old_reset_line;
reg old_reset_frame;
reg [3:0] wrdata_finished;
reg [AWIDTH+1:0] waddr;
wrout_en <= 0;
wrin_en <= 0;
if(ce_in) begin
// blend_result has been delayed by 4 cycles
case(cyc)
0: wrdata[DWIDTH:0] <= blend_result;
1: wrdata[DWIDTH1+DWIDTH:DWIDTH1] <= blend_result;
2: wrdata[DWIDTH1*3+DWIDTH:DWIDTH1*3] <= blend_result;
3: wrdata[DWIDTH1*2+DWIDTH:DWIDTH1*2] <= blend_result;
endcase
wrdata_finished <= wrdata_finished << 1;
if(wrdata_finished[3]) begin
wrout_en <= 1;
wrout_addr <= waddr;
end
if(~&offs) begin
if (cyc == 1) begin
Prev2 <= Curr20;
Curr2 <= Curr21;
Next2 <= HALF_DEPTH ? h2rgb(inputpixel) : inputpixel;
wrpix <= inputpixel;
wrin_addr2 <= offs;
wrin_en <= 1;
end
if(cyc==3) begin
offs <= offs + 1'd1;
waddr <= {offs, curbuf};
wrdata_finished[0] <= 1;
end
end
pattern <= new_pattern;
if(cyc==3) begin
nextpatt <= {new_pattern[7:6], new_pattern[3], new_pattern[5], new_pattern[2], new_pattern[4], new_pattern[1:0]};
{A, G} <= {Prev0, Next0};
{B, F, H, D} <= {Prev1, Curr2, Next1, Curr0};
{Prev0, Prev1} <= {Prev1, Prev2};
{Curr0, Curr1} <= {Curr1, Curr2};
{Next0, Next1} <= {Next1, Next2};
end else begin
nextpatt <= {nextpatt[5], nextpatt[3], nextpatt[0], nextpatt[6], nextpatt[1], nextpatt[7], nextpatt[4], nextpatt[2]};
{B, F, H, D} <= {F, H, D, B};
end
cyc <= cyc + 1'b1;
if(old_reset_line && ~reset_line) begin
old_reset_frame <= reset_frame;
offs <= 0;
cyc <= 0;
curbuf <= ~curbuf;
prevbuf <= curbuf;
{Prev0, Prev1, Prev2, Curr0, Curr1, Curr2, Next0, Next1, Next2} <= '0;
if(old_reset_frame & ~reset_frame) begin
curbuf <= 0;
prevbuf <= 0;
end
end
old_reset_line <= reset_line;
end
end
endmodule
////////////////////////////////////////////////////////////////////////////////////////////////////////
module hq2x_in #(parameter LENGTH, parameter DWIDTH)
(
input clk,
input [AWIDTH:0] rdaddr,
input rdbuf0, rdbuf1,
output[DWIDTH:0] q0,q1,
input [AWIDTH:0] wraddr,
input wrbuf,
input [DWIDTH:0] data,
input wren
);
localparam AWIDTH = $clog2(LENGTH)-1;
wire [DWIDTH:0] out[2];
assign q0 = out[rdbuf0];
assign q1 = out[rdbuf1];
hq2x_buf #(.NUMWORDS(LENGTH), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf0(clk,data,rdaddr,wraddr,wren && (wrbuf == 0),out[0]);
hq2x_buf #(.NUMWORDS(LENGTH), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf1(clk,data,rdaddr,wraddr,wren && (wrbuf == 1),out[1]);
endmodule
module hq2x_buf #(parameter NUMWORDS, parameter AWIDTH, parameter DWIDTH)
(
input clock,
input [DWIDTH:0] data,
input [AWIDTH:0] rdaddress,
input [AWIDTH:0] wraddress,
input wren,
output reg [DWIDTH:0] q
);
reg [DWIDTH:0] ram[0:NUMWORDS-1];
always_ff@(posedge clock) begin
if(wren) ram[wraddress] <= data;
q <= ram[rdaddress];
end
endmodule
////////////////////////////////////////////////////////////////////////////////////////////////////////
module DiffCheck
(
input [23:0] rgb1,
input [23:0] rgb2,
output result
);
wire [7:0] r = rgb1[7:1] - rgb2[7:1];
wire [7:0] g = rgb1[15:9] - rgb2[15:9];
wire [7:0] b = rgb1[23:17] - rgb2[23:17];
wire [8:0] t = $signed(r) + $signed(b);
wire [9:0] y = $signed(t) + $signed({g[7], g});
wire [8:0] u = $signed(r) - $signed(b);
wire [9:0] v = $signed({g, 1'b0}) - $signed(t);
// if y is inside (-96..96)
wire y_inside = (y < 10'h60 || y >= 10'h3a0);
// if u is inside (-16, 16)
wire u_inside = (!u[8:4] || &u[8:4]); //(u < 9'h10 || u >= 9'h1f0);
// if v is inside (-24, 24)
wire v_inside = (v < 10'h18 || v >= 10'h3e8);
assign result = !(y_inside && u_inside && v_inside);
endmodule
module Blend
(
input clk,
input clk_en,
input [5:0] rule,
input [23:0] E,
input [23:0] A,
input [23:0] B,
input [23:0] D,
input [23:0] F,
input [23:0] H,
output [23:0] Result
);
localparam BLEND1 = 7'b110_10_00; // (A * 12 + B * 4 ) >> 4
localparam BLEND2 = 7'b100_10_10; // (A * 8 + B * 4 + C * 4) >> 4
localparam BLEND3 = 7'b101_10_01; // (A * 10 + B * 4 + C * 2) >> 4
localparam BLEND4 = 7'b110_01_01; // (A * 12 + B * 2 + C * 2) >> 4
localparam BLEND5 = 7'b010_11_11; // (A * 4 + B * 6 + C * 6) >> 4
localparam BLEND6 = 7'b111_00_00; // (A * 14 + B * 1 + C * 1) >> 4
reg [23:0] a,b,d,e,h,f;
reg [3:0] bl_rule;
reg [1:0] df_rule;
always @(posedge clk) if (clk_en) begin
{bl_rule,df_rule} <= rule;
a <= A; b <= B; d <= D; e <= E; f <= F; h <= H;
end
wire is_diff;
DiffCheck diff_checker(df_rule[1] ? b : h, df_rule[0] ? d : f, is_diff);
reg [23:0] i10,i20,i30;
reg [6:0] op0;
always @(posedge clk) if (clk_en) begin
i10 <= e;
case({!is_diff, bl_rule})
1,11,12,13,17: {op0, i20, i30} <= {BLEND1, a, 24'd0};
2,14,18: {op0, i20, i30} <= {BLEND1, d, 24'd0};
3,15,19: {op0, i20, i30} <= {BLEND1, b, 24'd0};
4,20,24,27: {op0, i20, i30} <= {BLEND2, d, b};
5,21: {op0, i20, i30} <= {BLEND2, a, b};
6,22: {op0, i20, i30} <= {BLEND2, a, d};
25,29: {op0, i20, i30} <= {BLEND5, d, b};
26: {op0, i20, i30} <= {BLEND6, d, b};
28: {op0, i20, i30} <= {BLEND4, d, b};
30: {op0, i20, i30} <= {BLEND3, b, d};
31: {op0, i20, i30} <= {BLEND3, d, b};
default: {op0, i20, i30} <= {BLEND1, e, 24'd0};
endcase
end
reg [23:0] i1,i2,i3;
reg [6:0] op;
always @(posedge clk) if (clk_en) begin
op <= op0; i1 <= i10; i2 <= i20; i3 <= i30;
end
function [34:0] mul24x3;
input [23:0] op1;
input [2:0] op2;
begin
mul24x3 = 0;
if(op2[0]) mul24x3 = mul24x3 + {op1[23:16], 4'b0000, op1[15:8], 4'b0000, op1[7:0]};
if(op2[1]) mul24x3 = mul24x3 + {op1[23:16], 4'b0000, op1[15:8], 4'b0000, op1[7:0], 1'b0};
if(op2[2]) mul24x3 = mul24x3 + {op1[23:16], 4'b0000, op1[15:8], 4'b0000, op1[7:0], 2'b00};
end
endfunction
wire [35:0] res = {mul24x3(i1, op[6:4]), 1'b0} + mul24x3(i2, {op[3:2], !op[3:2]}) + mul24x3(i3, {op[1:0], !op[3:2]});
always @(posedge clk) if (clk_en) Result <= {res[35:28],res[23:16],res[11:4]};
endmodule

103
sys/i2c.v Normal file
View File

@@ -0,0 +1,103 @@
module i2c
(
input CLK,
input START,
input READ,
input [6:0] I2C_ADDR,
input I2C_WLEN, // 0 - one byte, 1 - two bytes
input [7:0] I2C_WDATA1,
input [7:0] I2C_WDATA2,
output [7:0] I2C_RDATA,
output reg END = 1,
output reg ACK = 0,
//I2C bus
output I2C_SCL,
inout I2C_SDA
);
// Clock Setting
parameter CLK_Freq = 50_000_000; // 50 MHz
parameter I2C_Freq = 400_000; // 400 KHz
localparam I2C_FreqX2 = I2C_Freq*2;
reg I2C_CLOCK;
reg [31:0] cnt;
wire [31:0] cnt_next = cnt + I2C_FreqX2;
always @(posedge CLK) begin
cnt <= cnt_next;
if(cnt_next >= CLK_Freq) begin
cnt <= cnt_next - CLK_Freq;
I2C_CLOCK <= ~I2C_CLOCK;
end
end
assign I2C_SCL = (SCLK | I2C_CLOCK) ? 1'bZ : 1'b0;
assign I2C_SDA = SDO[3] ? 1'bz : 1'b0;
reg SCLK;
reg [3:0] SDO;
reg [0:7] rdata;
reg [5:0] SD_COUNTER;
reg [0:31] SD;
initial begin
SD_COUNTER = 'b111111;
SD = 'hFFFF;
SCLK = 1;
SDO = 4'b1111;
end
assign I2C_RDATA = rdata;
always @(posedge CLK) begin
reg old_clk;
reg old_st;
reg rd,len;
old_clk <= I2C_CLOCK;
old_st <= START;
// delay to make sure SDA changed while SCL is stabilized at low
if(old_clk && ~I2C_CLOCK && ~SD_COUNTER[5]) SDO[0] <= SD[SD_COUNTER[4:0]];
SDO[3:1] <= SDO[2:0];
if(~old_st && START) begin
SCLK <= 1;
SDO <= 4'b1111;
ACK <= 0;
END <= 0;
rd <= READ;
len <= I2C_WLEN;
if(READ) SD <= {2'b10, I2C_ADDR, 1'b1, 1'b1, 8'b11111111, 1'b0, 3'b011, 9'b111111111};
else SD <= {2'b10, I2C_ADDR, 1'b0, 1'b1, I2C_WDATA1, 1'b1, I2C_WDATA2, 4'b1011};
SD_COUNTER <= 0;
end else begin
if(~old_clk && I2C_CLOCK && ~&SD_COUNTER) begin
SD_COUNTER <= SD_COUNTER + 6'd1;
case(SD_COUNTER)
01: SCLK <= 0;
10: ACK <= ACK | I2C_SDA;
19: if(~rd) begin
ACK <= ACK | I2C_SDA;
if(~len) SD_COUNTER <= 29;
end
20: if(rd) SCLK <= 1;
23: if(rd) END <= 1;
28: if(~rd) ACK <= ACK | I2C_SDA;
29: if(~rd) SCLK <= 1;
32: if(~rd) END <= 1;
endcase
if(SD_COUNTER >= 11 && SD_COUNTER <= 18) rdata[SD_COUNTER[4:0]-11] <= I2C_SDA;
end
end
end
endmodule

54
sys/i2s.v Normal file
View File

@@ -0,0 +1,54 @@
module i2s
#(
parameter AUDIO_DW = 16
)
(
input reset,
input clk,
input ce,
output reg sclk,
output reg lrclk,
output reg sdata,
input [AUDIO_DW-1:0] left_chan,
input [AUDIO_DW-1:0] right_chan
);
always @(posedge clk) begin
reg [7:0] bit_cnt;
reg msclk;
reg [AUDIO_DW-1:0] left;
reg [AUDIO_DW-1:0] right;
if (reset) begin
bit_cnt <= 1;
lrclk <= 1;
sclk <= 1;
msclk <= 1;
end
else begin
sclk <= msclk;
if(ce) begin
msclk <= ~msclk;
if(msclk) begin
if(bit_cnt >= AUDIO_DW) begin
bit_cnt <= 1;
lrclk <= ~lrclk;
if(lrclk) begin
left <= left_chan;
right <= right_chan;
end
end
else begin
bit_cnt <= bit_cnt + 1'd1;
end
sdata <= lrclk ? right[AUDIO_DW - bit_cnt] : left[AUDIO_DW - bit_cnt];
end
end
end
end
endmodule

213
sys/iir_filter.v Normal file
View File

@@ -0,0 +1,213 @@
// 3-tap IIR filter for 2 channels.
// Copyright (C) 2020 Sorgelig
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Can be converted to 2-tap (coeff_x2 = 0, coeff_y2 = 0) or 1-tap (coeff_x1,2 = 0, coeff_y1,2 = 0)
//
module IIR_filter
#(
parameter use_params = 1, // set to 1 to use following parameters, 0 for input port variables.
parameter stereo = 1, // 0 for mono (input_l)
parameter coeff_x = 0.00000774701983513660, // Base gain value for X. Float. Range: 0.0 ... 0.999(9)
parameter coeff_x0 = 3, // Gain scale factor for X0. Integer. Range -7 ... +7
parameter coeff_x1 = 3, // Gain scale factor for X1. Integer. Range -7 ... +7
parameter coeff_x2 = 1, // Gain scale factor for X2. Integer. Range -7 ... +7
parameter coeff_y0 = -2.96438150626551080000, // Coefficient for Y0. Float. Range -3.999(9) ... 3.999(9)
parameter coeff_y1 = 2.92939452735121100000, // Coefficient for Y1. Float. Range -3.999(9) ... 3.999(9)
parameter coeff_y2 = -0.96500747158831091000 // Coefficient for Y2. Float. Range -3.999(9) ... 3.999(9)
)
(
input clk,
input reset,
input ce, // must be double of calculated rate for stereo!
input sample_ce, // desired output sample rate
input [39:0] cx,
input [7:0] cx0,
input [7:0] cx1,
input [7:0] cx2,
input [23:0] cy0,
input [23:0] cy1,
input [23:0] cy2,
input [15:0] input_l, input_r, // signed samples
output [15:0] output_l, output_r // signed samples
);
localparam [39:0] pcoeff_x = coeff_x * 40'h8000000000;
localparam [31:0] pcoeff_y0 = coeff_y0 * 24'h200000;
localparam [31:0] pcoeff_y1 = coeff_y1 * 24'h200000;
localparam [31:0] pcoeff_y2 = coeff_y2 * 24'h200000;
wire [39:0] vcoeff = use_params ? pcoeff_x : cx;
wire [23:0] vcoeff_y0 = use_params ? pcoeff_y0[23:0] : cy0;
wire [23:0] vcoeff_y1 = use_params ? pcoeff_y1[23:0] : cy1;
wire [23:0] vcoeff_y2 = use_params ? pcoeff_y2[23:0] : cy2;
wire [59:0] inp_mul = $signed(inp) * $signed(vcoeff);
wire [39:0] x = inp_mul[59:20];
wire [39:0] y = x + tap0;
wire [39:0] tap0;
iir_filter_tap iir_tap_0
(
.clk(clk),
.reset(reset),
.ce(ce),
.ch(ch),
.cx(use_params ? coeff_x0[7:0] : cx0),
.cy(vcoeff_y0),
.x(x),
.y(y),
.z(tap1),
.tap(tap0)
);
wire [39:0] tap1;
iir_filter_tap iir_tap_1
(
.clk(clk),
.reset(reset),
.ce(ce),
.ch(ch),
.cx(use_params ? coeff_x1[7:0] : cx1),
.cy(vcoeff_y1),
.x(x),
.y(y),
.z(tap2),
.tap(tap1)
);
wire [39:0] tap2;
iir_filter_tap iir_tap_2
(
.clk(clk),
.reset(reset),
.ce(ce),
.ch(ch),
.cx(use_params ? coeff_x2[7:0] : cx2),
.cy(vcoeff_y2),
.x(x),
.y(y),
.z(0),
.tap(tap2)
);
wire [15:0] y_clamp = (~y[39] & |y[38:35]) ? 16'h7FFF : (y[39] & ~&y[38:35]) ? 16'h8000 : y[35:20];
reg ch = 0;
reg [15:0] out_l, out_r, out_m;
reg [15:0] inp, inp_m;
always @(posedge clk) if (ce) begin
if(!stereo) begin
ch <= 0;
inp <= input_l;
out_l <= y_clamp;
out_r <= y_clamp;
end
else begin
ch <= ~ch;
if(ch) begin
out_m <= y_clamp;
inp <= inp_m;
end
else begin
out_l <= out_m;
out_r <= y_clamp;
inp <= input_l;
inp_m <= input_r;
end
end
end
reg [31:0] out;
always @(posedge clk) if (sample_ce) out <= {out_l, out_r};
assign {output_l, output_r} = out;
endmodule
module iir_filter_tap
(
input clk,
input reset,
input ce,
input ch,
input [7:0] cx,
input [23:0] cy,
input [39:0] x,
input [39:0] y,
input [39:0] z,
output [39:0] tap
);
wire signed [60:0] y_mul = $signed(y[36:0]) * $signed(cy);
function [39:0] x_mul;
input [39:0] x;
begin
x_mul = 0;
if(cx[0]) x_mul = x_mul + {{4{x[39]}}, x[39:4]};
if(cx[1]) x_mul = x_mul + {{3{x[39]}}, x[39:3]};
if(cx[2]) x_mul = x_mul + {{2{x[39]}}, x[39:2]};
if(cx[7]) x_mul = ~x_mul; //cheap NEG
end
endfunction
(* ramstyle = "logic" *) reg [39:0] intreg[2];
always @(posedge clk, posedge reset) begin
if(reset) {intreg[0],intreg[1]} <= 80'd0;
else if(ce) intreg[ch] <= x_mul(x) - y_mul[60:21] + z;
end
assign tap = intreg[ch];
endmodule
// simplified IIR 1-tap.
module DC_blocker
(
input clk,
input ce, // 48/96 KHz
input mute,
input sample_rate,
input [15:0] din,
output [15:0] dout
);
wire [39:0] x = {din[15], din, 23'd0};
wire [39:0] x0 = x - (sample_rate ? {{11{x[39]}}, x[39:11]} : {{10{x[39]}}, x[39:10]});
wire [39:0] y1 = y - (sample_rate ? {{10{y[39]}}, y[39:10]} : {{09{y[39]}}, y[39:09]});
wire [39:0] y0 = x0 - x1 + y1;
reg [39:0] x1, y;
always @(posedge clk) if(ce) begin
x1 <= x0;
y <= ^y0[39:38] ? {{2{y0[39]}},{38{y0[38]}}} : y0;
end
assign dout = mute ? 16'd0 : y[38:23];
endmodule

162
sys/ltc2308.sv Normal file
View File

@@ -0,0 +1,162 @@
//============================================================================
//
// LTC2308 controller
// Copyright (C) 2019 Sorgelig
//
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
//============================================================================
// NUM_CH 1..8
// Sampling rate = ADC_RATE/NUM_CH
// ADC_RATE max is ~500KHz
// CLK_RATE max is ~80MHz
module ltc2308 #(parameter NUM_CH = 2, ADC_RATE = 96000, CLK_RATE = 50000000)
(
input reset,
input clk,
inout [3:0] ADC_BUS,
output reg dout_sync, // toggle with every ADC round
output reg [(NUM_CH*12)-1:0] dout // 12 bits per channel (unsigned)
);
localparam TCONV = CLK_RATE/625000;
reg sck;
wire sdo = cfg[5];
assign ADC_BUS[3] = sck;
wire sdi = ADC_BUS[2];
assign ADC_BUS[1] = sdo;
assign ADC_BUS[0] = convst;
reg convst;
reg [5:0] cfg;
reg [31:0] sum;
wire [31:0] next_sum = sum + ADC_RATE;
reg [2:0] pin;
wire [2:0] next_pin = (pin == (NUM_CH-1)) ? 3'd0 : (pin + 1'd1);
always @(posedge clk) begin
reg [7:0] tconv;
reg [3:0] bitcnt;
reg [10:0] adcin;
convst <= 0;
if(reset) begin
sum <= 0;
tconv <= 0;
bitcnt <= 0;
sck <= 0;
cfg <= 0;
dout <= 0;
pin <= NUM_CH[2:0]-1'd1;
end
else begin
sum <= next_sum;
if(next_sum >= CLK_RATE) begin
sum <= next_sum - CLK_RATE;
tconv <= TCONV[7:0];
convst <= 1;
bitcnt <= 12;
cfg <= {1'b1, next_pin[0], next_pin[2:1], 1'b1, 1'b0};
if(!next_pin) dout_sync <= ~dout_sync;
end
if(tconv) tconv <= tconv - 1'd1;
else if(bitcnt) begin
sck <= ~sck;
if(sck) cfg <= cfg<<1;
else begin
adcin <= {adcin[9:0],sdi};
bitcnt <= bitcnt - 1'd1;
if(bitcnt == 1) begin
dout[pin*12 +:12] <= {adcin,sdi};
pin <= next_pin;
end
end
end
else sck <= 0;
end
end
endmodule
module ltc2308_tape #(parameter HIST_LOW = 16, HIST_HIGH = 64, ADC_RATE = 48000, CLK_RATE = 50000000)
(
input reset,
input clk,
inout [3:0] ADC_BUS,
output reg dout,
output active
);
wire [11:0] adc_data;
wire adc_sync;
ltc2308 #(1, ADC_RATE, CLK_RATE) adc
(
.reset(reset),
.clk(clk),
.ADC_BUS(ADC_BUS),
.dout(adc_data),
.dout_sync(adc_sync)
);
always @(posedge clk) begin
reg [13:0] data1,data2,data3,data4, sum;
reg adc_sync_d;
adc_sync_d<=adc_sync;
if(adc_sync_d ^ adc_sync) begin
data1 <= data2;
data2 <= data3;
data3 <= data4;
data4 <= adc_data;
sum <= data1+data2+data3+data4;
if(sum[13:2]<HIST_LOW) dout <= 0;
if(sum[13:2]>HIST_HIGH) dout <= 1;
end
end
assign active = |act;
reg [1:0] act;
always @(posedge clk) begin
reg [31:0] onesec;
reg old_dout;
onesec <= onesec + 1;
if(onesec>CLK_RATE) begin
onesec <= 0;
if(act) act <= act - 1'd1;
end
old_dout <= dout;
if(old_dout ^ dout) act <= 2;
end
endmodule

109
sys/math.sv Normal file
View File

@@ -0,0 +1,109 @@
// result = num/div
module sys_udiv
#(
parameter NB_NUM,
parameter NB_DIV
)
(
input clk,
input start,
output busy,
input [NB_NUM-1:0] num,
input [NB_DIV-1:0] div,
output reg [NB_NUM-1:0] result,
output reg [NB_DIV-1:0] remainder
);
reg run;
assign busy = run;
always @(posedge clk) begin
reg [5:0] cpt;
reg [NB_NUM+NB_DIV+1:0] rem;
if (start) begin
cpt <= 0;
run <= 1;
rem <= num;
end
else if (run) begin
cpt <= cpt + 1'd1;
run <= (cpt != NB_NUM + 1'd1);
remainder <= rem[NB_NUM+NB_DIV:NB_NUM+1];
if (!rem[NB_DIV + NB_NUM + 1'd1])
rem <= {rem[NB_DIV+NB_NUM:0] - (div << NB_NUM),1'b0};
else
rem <= {rem[NB_DIV+NB_NUM:0] + (div << NB_NUM),1'b0};
result <= {result[NB_NUM-2:0], !rem[NB_DIV + NB_NUM + 1'd1]};
end
end
endmodule
// result = mul1*mul2
module sys_umul
#(
parameter NB_MUL1,
parameter NB_MUL2
)
(
input clk,
input start,
output busy,
input [NB_MUL1-1:0] mul1,
input [NB_MUL2-1:0] mul2,
output reg [NB_MUL1+NB_MUL2-1:0] result
);
reg run;
assign busy = run;
always @(posedge clk) begin
reg [NB_MUL1+NB_MUL2-1:0] add;
reg [NB_MUL2-1:0] map;
if (start) begin
run <= 1;
result <= 0;
add <= mul1;
map <= mul2;
end
else if (run) begin
if(!map) run <= 0;
if(map[0]) result <= result + add;
add <= add << 1;
map <= map >> 1;
end
end
endmodule
// result = (mul1*mul2)/div
module sys_umuldiv
#(
parameter NB_MUL1,
parameter NB_MUL2,
parameter NB_DIV
)
(
input clk,
input start,
output busy,
input [NB_MUL1-1:0] mul1,
input [NB_MUL2-1:0] mul2,
input [NB_DIV-1:0] div,
output [NB_MUL1+NB_MUL2-1:0] result,
output [NB_DIV-1:0] remainder
);
wire mul_run;
wire [NB_MUL1+NB_MUL2-1:0] mul_res;
sys_umul #(NB_MUL1,NB_MUL2) umul(clk,start,mul_run,mul1,mul2,mul_res);
sys_udiv #(NB_MUL1+NB_MUL2,NB_DIV) udiv(clk,start|mul_run,busy,mul_res,div,result,remainder);
endmodule

113
sys/mcp23009.sv Normal file
View File

@@ -0,0 +1,113 @@
//
// MCP23009
// (C) 2019 Alexey Melnikov
//
module mcp23009
(
input clk,
output reg [2:0] btn,
input [2:0] led,
output reg sd_cd,
output scl,
inout sda
);
reg start = 0;
wire ready;
wire error;
reg rw;
wire [7:0] dout;
reg [15:0] din;
i2c #(50_000_000, 500_000) i2c
(
.CLK(clk),
.START(start),
.READ(rw),
.I2C_ADDR('h20),
.I2C_WLEN(1),
.I2C_WDATA1(din[15:8]),
.I2C_WDATA2(din[7:0]),
.I2C_RDATA(dout),
.END(ready),
.ACK(error),
.I2C_SCL(scl),
.I2C_SDA(sda)
);
always@(posedge clk) begin
reg [3:0] idx = 0;
reg [1:0] state = 0;
reg [15:0] timeout = 0;
if(~&timeout) begin
timeout <= timeout + 1'd1;
start <= 0;
state <= 0;
idx <= 0;
btn <= 0;
rw <= 0;
sd_cd <= 1;
end
else begin
if(~&init_data[idx]) begin
case(state)
0: begin
start <= 1;
state <= 1;
din <= init_data[idx];
end
1: if(~ready) state <= 2;
2: begin
start <= 0;
if(ready) begin
state <= 0;
if(!error) idx <= idx + 1'd1;
end
end
endcase
end
else begin
case(state)
0: begin
start <= 1;
state <= 1;
din <= {8'h09,5'b00000,led};
end
1: if(~ready) state <= 2;
2: begin
start <= 0;
if(ready) begin
state <= 0;
rw <= 0;
if(!error) begin
if(rw) {sd_cd, btn} <= {dout[7], dout[5:3]};
rw <= ~rw;
end
end
end
endcase
end
end
end
wire [15:0] init_data[12] =
'{
16'h00F8,
16'h0138,
16'h0200,
16'h0300,
16'h0400,
16'h0524,
16'h06FF,
16'h0700,
16'h0800,
16'h0900,
16'h0A00,
16'hFFFF
};
endmodule

283
sys/mt32pi.sv Normal file
View File

@@ -0,0 +1,283 @@
//
// Communication module to MT32-pi (external MIDI emulator on RPi)
// (C) 2020 Sorgelig, Kitrinx
//
// https://github.com/dwhinham/mt32-pi
//
module mt32pi
(
input CLK_AUDIO,
input CLK_VIDEO,
input CE_PIXEL,
input VGA_VS,
input VGA_DE,
input [6:0] USER_IN,
output [6:0] USER_OUT,
input reset,
input midi_tx,
output midi_rx,
output reg [15:0] mt32_i2s_r,
output reg [15:0] mt32_i2s_l,
output reg mt32_available,
input mt32_mode_req,
input [1:0] mt32_rom_req,
input [7:0] mt32_sf_req,
output reg [7:0] mt32_mode,
output reg [7:0] mt32_rom,
output reg [7:0] mt32_sf,
output reg mt32_newmode,
output reg mt32_lcd_en,
output reg mt32_lcd_pix,
output reg mt32_lcd_update
);
//
// Pin | USB Name | Signal
// ----+----------+--------------
// 0 | D+ | I/O I2C_SDA / RX (midi in)
// 1 | D- | O TX (midi out)
// 2 | TX- | I I2S_WS (1 == right)
// 3 | GND_d | I I2C_SCL
// 4 | RX+ | I I2S_BCLK
// 5 | RX- | I I2S_DAT
// 6 | TX+ | - none
//
assign USER_OUT[0] = sda_out;
assign USER_OUT[1] = midi_tx;
assign USER_OUT[6:2] = '1;
//
// crossed/straight cable selection
//
generate
genvar i;
for(i = 0; i<2; i++) begin : clk_rate
wire clk_in = i ? USER_IN[6] : USER_IN[4];
reg [4:0] cnt;
always @(posedge CLK_AUDIO) begin : clkr
reg clk_sr, clk, old_clk;
reg [4:0] cnt_tmp;
clk_sr <= clk_in;
if (clk_sr == clk_in) clk <= clk_sr;
if(~&cnt_tmp) cnt_tmp <= cnt_tmp + 1'd1;
else cnt <= '1;
old_clk <= clk;
if(~old_clk & clk) begin
cnt <= cnt_tmp;
cnt_tmp <= 0;
end
end
end
reg crossed;
always @(posedge CLK_AUDIO) crossed <= (clk_rate[0].cnt <= clk_rate[1].cnt);
endgenerate
wire i2s_ws = crossed ? USER_IN[2] : USER_IN[5];
wire i2s_data = crossed ? USER_IN[5] : USER_IN[2];
wire i2s_bclk = crossed ? USER_IN[4] : USER_IN[6];
assign midi_rx = ~mt32_available ? USER_IN[0] : crossed ? USER_IN[6] : USER_IN[4];
//
// i2s receiver
//
always @(posedge CLK_AUDIO) begin : i2s_proc
reg [15:0] i2s_buf = 0;
reg [4:0] i2s_cnt = 0;
reg clk_sr;
reg i2s_clk = 0;
reg old_clk, old_ws;
reg i2s_next = 0;
// Debounce clock
clk_sr <= i2s_bclk;
if (clk_sr == i2s_bclk) i2s_clk <= clk_sr;
// Latch data and ws on rising edge
old_clk <= i2s_clk;
if (i2s_clk && ~old_clk) begin
if (~i2s_cnt[4]) begin
i2s_cnt <= i2s_cnt + 1'd1;
i2s_buf[~i2s_cnt[3:0]] <= i2s_data;
end
// Word Select will change 1 clock before the new word starts
old_ws <= i2s_ws;
if (old_ws != i2s_ws) i2s_next <= 1;
end
if (i2s_next) begin
i2s_next <= 0;
i2s_cnt <= 0;
i2s_buf <= 0;
if (i2s_ws) mt32_i2s_l <= i2s_buf;
else mt32_i2s_r <= i2s_buf;
end
if (reset) begin
i2s_buf <= 0;
mt32_i2s_l <= 0;
mt32_i2s_r <= 0;
end
end
//
// i2c slave
//
reg sda_out;
reg [7:0] lcd_data[1024];
reg lcd_sz;
reg reset_r = 0;
wire [7:0] mode_req = reset_r ? 8'hA0 : mt32_mode_req ? 8'hA2 : 8'hA1;
wire [7:0] rom_req = {6'd0, mt32_rom_req};
always @(posedge CLK_AUDIO) begin : i2c_slave
reg sda_sr, scl_sr;
reg old_sda, old_scl;
reg sda, scl;
reg [7:0] tmp;
reg [3:0] cnt = 0;
reg [10:0] bcnt = 0;
reg ack;
reg i2c_rw;
reg disp, dispdata;
reg [2:0] div;
reg old_reset;
old_reset <= reset;
if(old_reset & ~reset) sda_out <= 1;
div <= div + 1'd1;
if(!div) begin
sda_sr <= USER_IN[0];
if(sda_sr == USER_IN[0]) sda <= sda_sr;
old_sda <= sda;
scl_sr <= USER_IN[3];
if(scl_sr == USER_IN[3]) scl <= scl_sr;
old_scl <= scl;
//start
if(old_scl & scl & old_sda & ~sda) begin
cnt <= 9;
bcnt <= 0;
ack <= 0;
i2c_rw <= 0;
disp <= 0;
dispdata <= 0;
end
//stop
if(old_scl & scl & ~old_sda & sda) begin
cnt <= 0;
if(dispdata) begin
lcd_sz <= ~bcnt[9];
mt32_lcd_update <= ~mt32_lcd_update;
end
end
//data latch
if(~old_scl && scl && cnt) begin
tmp <= {tmp[6:0], sda};
cnt <= cnt - 1'd1;
end
if(!cnt) sda_out <= 1;
//data set
if(old_scl && ~scl) begin
sda_out <= 1;
if(cnt == 1) begin
if(!bcnt) begin
if(tmp[7:1] == 'h45 || tmp[7:1] == 'h3c) begin
disp <= (tmp[7:1] == 'h3c);
sda_out <= 0;
mt32_available <= 1;
ack <= 1;
i2c_rw <= tmp[0];
bcnt <= bcnt + 1'd1;
cnt <= 10;
end
else begin
// wrong address, stop
cnt <= 0;
end
end
else if(ack) begin
if(~i2c_rw) begin
if(disp) begin
if(bcnt == 1) dispdata <= (tmp[7:6] == 2'b01);
else if(dispdata) lcd_data[bcnt[9:0] - 2'd2] <= tmp;
end
else begin
if(bcnt == 1) mt32_mode <= tmp;
if(bcnt == 2) mt32_rom <= tmp;
if(bcnt == 3) mt32_sf <= tmp;
if(bcnt == 3) mt32_newmode <= ~mt32_newmode;
end
end
if(~&bcnt) bcnt <= bcnt + 1'd1;
sda_out <= 0;
cnt <= 10;
end
end
else if(i2c_rw && ack && cnt && ~disp) begin
if(bcnt == 1) sda_out <= mode_req[cnt[2:0] - 2'd2];
if(bcnt == 2) sda_out <= rom_req[cnt[2:0] - 2'd2];
if(bcnt == 3) sda_out <= mt32_sf_req[cnt[2:0] - 2'd2];
if(bcnt == 3) reset_r <= 0;
end
end
end
if(reset) begin
reset_r <= 1;
mt32_available <= 0;
end
end
always @(posedge CLK_VIDEO) begin
reg old_de, old_vs;
reg [7:0] hcnt;
reg [6:0] vcnt;
reg [7:0] sh;
if(CE_PIXEL) begin
old_de <= VGA_DE;
old_vs <= VGA_VS;
if(~&hcnt) hcnt <= hcnt + 1'd1;
sh <= (sh << 1) | (~old_de & VGA_DE);
if(sh[7]) hcnt <= 0;
if(old_de & ~VGA_DE & ~&vcnt) vcnt <= vcnt + 1'd1;
if(~old_vs & VGA_VS) vcnt <= 0;
mt32_lcd_en <= mt32_available & ~hcnt[7] && (lcd_sz ? !vcnt[6] : !vcnt[6:5]);
mt32_lcd_pix <= lcd_data[{vcnt[5:3],hcnt[6:0]}][vcnt[2:0]];
end
end
endmodule

286
sys/osd.v Normal file
View File

@@ -0,0 +1,286 @@
// A simple OSD implementation. Can be hooked up between a cores
// VGA output and the physical VGA pins
module osd
(
input clk_sys,
input io_osd,
input io_strobe,
input [15:0] io_din,
input clk_video,
input [23:0] din,
input de_in,
input vs_in,
input hs_in,
output [23:0] dout,
output reg de_out,
output reg vs_out,
output reg hs_out,
output reg osd_status
);
parameter OSD_COLOR = 3'd4;
localparam OSD_WIDTH = 12'd256;
localparam OSD_HEIGHT = 12'd64;
`ifdef OSD_HEADER
localparam OSD_HDR = 12'd24;
`else
localparam OSD_HDR = 12'd0;
`endif
reg osd_enable;
(* ramstyle="no_rw_check" *) reg [7:0] osd_buffer[OSD_HDR ? (4096+1024) : 4096];
reg info = 0;
reg [8:0] infoh;
reg [8:0] infow;
reg [21:0] infox;
reg [21:0] infoy;
reg [21:0] osd_h;
reg [21:0] osd_t;
reg [21:0] osd_w;
reg [1:0] rot = 0;
always@(posedge clk_sys) begin
reg [12:0] bcnt;
reg [7:0] cmd;
reg has_cmd;
reg old_strobe;
reg highres = 0;
osd_t <= rot[0] ? OSD_WIDTH : (OSD_HEIGHT<<1);
osd_h <= rot[0] ? (info ? infow : OSD_WIDTH) : info ? infoh : (OSD_HEIGHT<<highres);
osd_w <= rot[0] ? (info ? infoh : (OSD_HEIGHT<<highres)) : (info ? infow : OSD_WIDTH);
old_strobe <= io_strobe;
if(~io_osd) begin
bcnt <= 0;
has_cmd <= 0;
cmd <= 0;
if(cmd[7:4] == 4) osd_enable <= cmd[0];
end else begin
if(~old_strobe & io_strobe) begin
if(!has_cmd) begin
has_cmd <= 1;
cmd <= io_din[7:0];
// command 0x40: OSDCMDENABLE, OSDCMDDISABLE
if(io_din[7:4] == 4) begin
if(!io_din[0]) {osd_status,highres} <= 0;
else {osd_status,info} <= {~io_din[2],io_din[2]};
bcnt <= 0;
end
// command 0x20: OSDCMDWRITE
if(io_din[7:5] == 'b001) begin
if(io_din[3]) highres <= 1;
bcnt <= {io_din[4:0], 8'h00};
end
end else begin
// command 0x40: OSDCMDENABLE, OSDCMDDISABLE
if(cmd[7:4] == 4) begin
if(bcnt == 0) infox <= io_din[11:0];
if(bcnt == 1) infoy <= io_din[11:0];
if(bcnt == 2) infow <= {io_din[5:0], 3'b000};
if(bcnt == 3) infoh <= {io_din[5:0], 3'b000};
if(bcnt == 4) rot <= io_din[1:0];
end
// command 0x20: OSDCMDWRITE
if(cmd[7:5] == 'b001) osd_buffer[bcnt] <= io_din[7:0];
bcnt <= bcnt + 1'd1;
end
end
end
end
(* direct_enable *) reg ce_pix;
always @(posedge clk_video) begin
reg [21:0] cnt = 0;
reg [21:0] pixsz, pixcnt;
reg deD;
cnt <= cnt + 1'd1;
deD <= de_in;
pixcnt <= pixcnt + 1'd1;
if(pixcnt == pixsz) pixcnt <= 0;
ce_pix <= !pixcnt;
if(~deD && de_in) cnt <= 0;
if(deD && ~de_in) begin
pixsz <= (((cnt+1'b1) >> (9-rot[0])) > 1) ? (((cnt+1'b1) >> (9-rot[0])) - 1'd1) : 22'd0;
pixcnt <= 0;
end
end
reg [2:0] osd_de;
reg osd_pixel;
reg [21:0] v_cnt;
reg v_cnt_h, v_cnt_1, v_cnt_2, v_cnt_3, v_cnt_4;
reg [21:0] v_osd_start_h, v_osd_start_1, v_osd_start_2, v_osd_start_3, v_osd_start_4, v_osd_start_5;
reg [21:0] v_info_start_h, v_info_start_1, v_info_start_2, v_info_start_3, v_info_start_4, v_info_start_5;
wire [21:0] osd_h_hdr = (info || rot) ? osd_h : (osd_h + OSD_HDR);
// pipeline the comparisons a bit
always @(posedge clk_video) if(ce_pix) begin
v_cnt_h <= v_cnt < osd_t;
v_cnt_1 <= v_cnt < 320;
v_cnt_2 <= v_cnt < 640;
v_cnt_3 <= v_cnt < 960;
v_cnt_4 <= v_cnt < 1280;
v_osd_start_h <= (v_cnt-(osd_h_hdr>>1))>>1;
v_osd_start_1 <= (v_cnt-osd_h_hdr)>>1;
v_osd_start_2 <= (v_cnt-(osd_h_hdr<<1))>>1;
v_osd_start_3 <= (v_cnt-(osd_h_hdr + (osd_h_hdr<<1)))>>1;
v_osd_start_4 <= (v_cnt-(osd_h_hdr<<2))>>1;
v_osd_start_5 <= (v_cnt-(osd_h_hdr + (osd_h_hdr<<2)))>>1;
v_info_start_h <= rot[0] ? infox : infoy;
v_info_start_1 <= rot[0] ? infox : infoy;
v_info_start_2 <= rot[0] ? (infox<<1) : (infoy<<1);
v_info_start_3 <= rot[0] ? (infox + (infox << 1)) : (infoy + (infoy << 1));
v_info_start_4 <= rot[0] ? (infox << 2) : (infoy << 2);
v_info_start_5 <= rot[0] ? (infox + (infox << 2)) : (infoy + (infoy << 2));
end
always @(posedge clk_video) begin
reg deD;
reg [2:0] osd_div;
reg [2:0] multiscan;
reg [7:0] osd_byte;
reg [23:0] h_cnt;
reg [21:0] dsp_width;
reg [21:0] osd_vcnt;
reg [21:0] h_osd_start;
reg [21:0] v_osd_start;
reg [21:0] osd_hcnt;
reg [21:0] osd_hcnt2;
reg osd_de1,osd_de2;
reg [1:0] osd_en;
reg f1;
reg half;
if(ce_pix) begin
deD <= de_in;
if(~&h_cnt) h_cnt <= h_cnt + 1'd1;
if(~&osd_hcnt) osd_hcnt <= osd_hcnt + 1'd1;
if(~&osd_hcnt2) osd_hcnt2 <= osd_hcnt2 + 1'd1;
if (h_cnt == h_osd_start) begin
osd_de[0] <= osd_en[1] && osd_h && (
osd_vcnt[11] ? (osd_vcnt[7] && (osd_vcnt[6:0] >= 4) && (osd_vcnt[6:0] < 19)) :
(info && (rot == 3)) ? !osd_vcnt[21:8] :
(osd_vcnt < osd_h)
);
osd_hcnt <= 0;
osd_hcnt2 <= 0;
if(info && rot == 1) osd_hcnt2 <= 22'd128-infoh;
end
if (osd_hcnt+1 == osd_w) osd_de[0] <= 0;
// falling edge of de
if(!de_in && deD) dsp_width <= h_cnt[21:0];
// rising edge of de
if(de_in && !deD) begin
h_cnt <= 0;
v_cnt <= v_cnt + 1'd1;
h_osd_start <= info ? (rot[0] ? infoy : infox) : (((dsp_width - osd_w)>>1) - 2'd2);
if(h_cnt > {dsp_width, 2'b00}) begin
v_cnt <= 1;
f1 <= ~f1; // skip every other frame for interlace compatibility.
if(~f1) begin
osd_en <= (osd_en << 1) | osd_enable;
if(~osd_enable) osd_en <= 0;
half <= 0;
if(v_cnt_h) begin
multiscan <= 0;
v_osd_start <= info ? v_info_start_h : v_osd_start_h;
half <= 1;
end
else if(v_cnt_1 | (rot[0] & v_cnt_2)) begin
multiscan <= 0;
v_osd_start <= info ? v_info_start_1 : v_osd_start_1;
end
else if(rot[0] ? v_cnt_3 : v_cnt_2) begin
multiscan <= 1;
v_osd_start <= info ? v_info_start_2 : v_osd_start_2;
end
else if(rot[0] ? v_cnt_4 : v_cnt_3) begin
multiscan <= 2;
v_osd_start <= info ? v_info_start_3 : v_osd_start_3;
end
else if(rot[0] | v_cnt_4) begin
multiscan <= 3;
v_osd_start <= info ? v_info_start_4 : v_osd_start_4;
end
else begin
multiscan <= 4;
v_osd_start <= info ? v_info_start_5 : v_osd_start_5;
end
end
end
osd_div <= osd_div + 1'd1;
if(osd_div == multiscan) begin
osd_div <= 0;
if(~osd_vcnt[10]) osd_vcnt <= osd_vcnt + 1'd1 + half;
if(osd_vcnt == 'b100010011111 && ~info) osd_vcnt <= 0;
end
if(v_osd_start == v_cnt) begin
{osd_div,osd_vcnt} <= 0;
if(info && rot == 3) osd_vcnt <= 22'd256-infow;
else if(OSD_HDR && !rot) osd_vcnt <= {~info, 3'b000, ~info, 7'b0000000};
end
end
osd_byte <= osd_buffer[rot[0] ? ({osd_hcnt2[6:3], osd_vcnt[7:0]} ^ { {4{~rot[1]}}, {8{rot[1]}} }) : {osd_vcnt[7:3], osd_hcnt[7:0]}];
osd_pixel <= osd_byte[rot[0] ? ((osd_hcnt2[2:0]-1'd1) ^ {3{~rot[1]}}) : osd_vcnt[2:0]];
osd_de[2:1] <= osd_de[1:0];
end
end
reg [23:0] rdout;
assign dout = rdout;
always @(posedge clk_video) begin
reg [23:0] ordout1, nrdout1, rdout2, rdout3;
reg de1,de2,de3;
reg osd_mux;
reg vs1,vs2,vs3;
reg hs1,hs2,hs3;
nrdout1 <= din;
ordout1 <= {{osd_pixel, osd_pixel, OSD_COLOR[2], din[23:19]},// 23:16
{osd_pixel, osd_pixel, OSD_COLOR[1], din[15:11]},// 15:8
{osd_pixel, osd_pixel, OSD_COLOR[0], din[7:3]}}; // 7:0
osd_mux <= ~osd_de[2];
rdout2 <= osd_mux ? nrdout1 : ordout1;
rdout3 <= rdout2;
de1 <= de_in; de2 <= de1; de3 <= de2;
hs1 <= hs_in; hs2 <= hs1; hs3 <= hs2;
vs1 <= vs_in; vs2 <= vs1; vs3 <= vs2;
rdout <= rdout3;
de_out <= de3;
hs_out <= hs3;
vs_out <= vs3;
end
endmodule

17
sys/pll.13.qip Normal file
View File

@@ -0,0 +1,17 @@
set_global_assignment -entity "pll" -library "pll" -name IP_TOOL_NAME "altera_pll"
set_global_assignment -entity "pll" -library "pll" -name IP_TOOL_VERSION "13.1"
set_global_assignment -entity "pll" -library "pll" -name IP_TOOL_ENV "mwpim"
set_global_assignment -library "pll" -name MISC_FILE [file join $::quartus(qip_path) "pll.cmp"]
set_global_assignment -name SYNTHESIS_ONLY_QIP ON
set_global_assignment -library "pll" -name VERILOG_FILE rtl/pll.v
set_global_assignment -library "pll" -name VERILOG_FILE rtl/pll/pll_0002.v
set_instance_assignment -name PLL_COMPENSATION_MODE DIRECT -to "*pll_0002*|altera_pll:altera_pll_i*|*"
set_instance_assignment -name PLL_CHANNEL_SPACING "0.0 KHz" -to "*pll_0002*|altera_pll:altera_pll_i*|*"
set_instance_assignment -name PLL_AUTO_RESET ON -to "*pll_0002*|altera_pll:altera_pll_i*|*"
set_instance_assignment -name PLL_BANDWIDTH_PRESET AUTO -to "*pll_0002*|altera_pll:altera_pll_i*|*"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_TOOL_NAME "altera_pll"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_TOOL_VERSION "13.1"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_TOOL_ENV "mwpim"

17
sys/pll_audio.13.qip Normal file
View File

@@ -0,0 +1,17 @@
set_global_assignment -entity "pll_audio" -library "pll_audio" -name IP_TOOL_NAME "altera_pll"
set_global_assignment -entity "pll_audio" -library "pll_audio" -name IP_TOOL_VERSION "13.1"
set_global_assignment -entity "pll_audio" -library "pll_audio" -name IP_TOOL_ENV "mwpim"
set_global_assignment -library "pll_audio" -name MISC_FILE [file join $::quartus(qip_path) "pll_audio.cmp"]
set_global_assignment -name SYNTHESIS_ONLY_QIP ON
set_global_assignment -library "pll_audio" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_audio.v"]
set_global_assignment -library "pll_audio" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_audio/pll_audio_0002.v"]
set_instance_assignment -name PLL_COMPENSATION_MODE DIRECT -to "*pll_audio_0002*|altera_pll:altera_pll_i*|*"
set_instance_assignment -name PLL_CHANNEL_SPACING "0.0 KHz" -to "*pll_audio_0002*|altera_pll:altera_pll_i*|*"
set_instance_assignment -name PLL_AUTO_RESET ON -to "*pll_audio_0002*|altera_pll:altera_pll_i*|*"
set_instance_assignment -name PLL_BANDWIDTH_PRESET AUTO -to "*pll_audio_0002*|altera_pll:altera_pll_i*|*"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_TOOL_NAME "altera_pll"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_TOOL_VERSION "13.1"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_TOOL_ENV "mwpim"

337
sys/pll_audio.qip Normal file
View File

@@ -0,0 +1,337 @@
set_global_assignment -entity "pll_audio" -library "pll_audio" -name IP_TOOL_NAME "altera_pll"
set_global_assignment -entity "pll_audio" -library "pll_audio" -name IP_TOOL_VERSION "17.0"
set_global_assignment -entity "pll_audio" -library "pll_audio" -name IP_TOOL_ENV "mwpim"
set_global_assignment -library "pll_audio" -name MISC_FILE [file join $::quartus(qip_path) "pll_audio.cmp"]
set_global_assignment -entity "pll_audio" -library "pll_audio" -name IP_TARGETED_DEVICE_FAMILY "Cyclone V"
set_global_assignment -entity "pll_audio" -library "pll_audio" -name IP_GENERATED_DEVICE_FAMILY "{Cyclone V}"
set_global_assignment -entity "pll_audio" -library "pll_audio" -name IP_QSYS_MODE "UNKNOWN"
set_global_assignment -name SYNTHESIS_ONLY_QIP ON
set_global_assignment -entity "pll_audio" -library "pll_audio" -name IP_COMPONENT_NAME "cGxsX2F1ZGlv"
set_global_assignment -entity "pll_audio" -library "pll_audio" -name IP_COMPONENT_DISPLAY_NAME "QWx0ZXJhIFBMTA=="
set_global_assignment -entity "pll_audio" -library "pll_audio" -name IP_COMPONENT_REPORT_HIERARCHY "Off"
set_global_assignment -entity "pll_audio" -library "pll_audio" -name IP_COMPONENT_INTERNAL "Off"
set_global_assignment -entity "pll_audio" -library "pll_audio" -name IP_COMPONENT_AUTHOR "QWx0ZXJhIENvcnBvcmF0aW9u"
set_global_assignment -entity "pll_audio" -library "pll_audio" -name IP_COMPONENT_VERSION "MTcuMA=="
set_global_assignment -entity "pll_audio" -library "pll_audio" -name IP_COMPONENT_DESCRIPTION "QWx0ZXJhIFBoYXNlLUxvY2tlZCBMb29wIChBTFRFUkFfUExMKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_NAME "cGxsX2F1ZGlvXzAwMDI="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_DISPLAY_NAME "QWx0ZXJhIFBMTA=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_REPORT_HIERARCHY "Off"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_INTERNAL "Off"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_AUTHOR "QWx0ZXJhIENvcnBvcmF0aW9u"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_VERSION "MTcuMA=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_DESCRIPTION "QWx0ZXJhIFBoYXNlLUxvY2tlZCBMb29wIChBTFRFUkFfUExMKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZGVidWdfcHJpbnRfb3V0cHV0::ZmFsc2U=::ZGVidWdfcHJpbnRfb3V0cHV0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZGVidWdfdXNlX3JiY190YWZfbWV0aG9k::ZmFsc2U=::ZGVidWdfdXNlX3JiY190YWZfbWV0aG9k"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZGV2aWNl::NUNFQkEyRjE3QTc=::ZGV2aWNl"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BsbF9tb2Rl::RnJhY3Rpb25hbC1OIFBMTA==::UExMIE1vZGU="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZnJhY3Rpb25hbF92Y29fbXVsdGlwbGllcg==::dHJ1ZQ==::ZnJhY3Rpb25hbF92Y29fbXVsdGlwbGllcg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3JlZmVyZW5jZV9jbG9ja19mcmVxdWVuY3k=::NTAuMA==::UmVmZXJlbmNlIENsb2NrIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cmVmZXJlbmNlX2Nsb2NrX2ZyZXF1ZW5jeQ==::NTAuMCBNSHo=::cmVmZXJlbmNlX2Nsb2NrX2ZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2NoYW5uZWxfc3BhY2luZw==::MC4w::Q2hhbm5lbCBTcGFjaW5n"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX29wZXJhdGlvbl9tb2Rl::ZGlyZWN0::T3BlcmF0aW9uIE1vZGU="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2ZlZWRiYWNrX2Nsb2Nr::R2xvYmFsIENsb2Nr::RmVlZGJhY2sgQ2xvY2s="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2ZyYWN0aW9uYWxfY291dA==::MzI=::RnJhY3Rpb25hbCBjYXJyeSBvdXQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RzbV9vdXRfc2Vs::MXN0X29yZGVy::RFNNIE9yZGVy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "b3BlcmF0aW9uX21vZGU=::ZGlyZWN0::b3BlcmF0aW9uX21vZGU="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3VzZV9sb2NrZWQ=::ZmFsc2U=::RW5hYmxlIGxvY2tlZCBvdXRwdXQgcG9ydA=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2VuX2Fkdl9wYXJhbXM=::ZmFsc2U=::RW5hYmxlIHBoeXNpY2FsIG91dHB1dCBjbG9jayBwYXJhbWV0ZXJz"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX251bWJlcl9vZl9jbG9ja3M=::MQ==::TnVtYmVyIE9mIENsb2Nrcw=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "bnVtYmVyX29mX2Nsb2Nrcw==::MQ==::bnVtYmVyX29mX2Nsb2Nrcw=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX211bHRpcGx5X2ZhY3Rvcg==::MQ==::TXVsdGlwbHkgRmFjdG9yIChNLUNvdW50ZXIp"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2ZyYWNfbXVsdGlwbHlfZmFjdG9y::MQ==::RnJhY3Rpb25hbCBNdWx0aXBseSBGYWN0b3IgKEsp"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3Jfbg==::MQ==::RGl2aWRlIEZhY3RvciAoTi1Db3VudGVyKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjA=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kw::MjQuNTc2::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzA=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3Iw::OA==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjA=::MTUyODMyMTE2Mw==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMA==::MTc=::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MA==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMA==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MA==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzA=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDA=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUw::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kx::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3Ix::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMQ==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MQ==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMQ==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MQ==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUx::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjI=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3ky::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzI=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3Iy::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjI=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMg==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5Mg==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMg==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0Mg==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzI=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDI=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUy::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjM=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kz::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzM=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3Iz::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjM=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMw==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5Mw==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMw==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0Mw==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzM=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDM=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUz::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjQ=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k0::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzQ=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I0::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjQ=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yNA==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5NA==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzNA==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0NA==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzQ=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDQ=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU0::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjU=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k1::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzU=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I1::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjU=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yNQ==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5NQ==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzNQ==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0NQ==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzU=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDU=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU1::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjY=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k2::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzY=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I2::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjY=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yNg==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5Ng==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzNg==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0Ng==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzY=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDY=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU2::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjc=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k3::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzc=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I3::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3Rvcjc=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yNw==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5Nw==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzNw==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0Nw==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzc=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDc=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU3::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjg=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k4::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzg=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I4::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3Rvcjg=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yOA==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5OA==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzOA==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0OA==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzg=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDg=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU4::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjk=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k5::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzk=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I5::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3Rvcjk=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yOQ==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5OQ==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzOQ==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0OQ==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzk=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDk=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU5::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjEw::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxMA==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzEw::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxMA==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjEw::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTA=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTA=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTA=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTA=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzEw::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDEw::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxMA==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjEx::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxMQ==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzEx::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxMQ==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjEx::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTE=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTE=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTE=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTE=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzEx::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDEx::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxMQ==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjEy::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxMg==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzEy::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxMg==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjEy::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTI=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTI=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTI=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTI=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzEy::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDEy::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxMg==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjEz::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxMw==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzEz::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxMw==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjEz::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTM=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTM=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTM=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTM=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzEz::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDEz::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxMw==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE0::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxNA==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE0::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxNA==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE0::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTQ=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTQ=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTQ=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTQ=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE0::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE0::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxNA==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE1::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxNQ==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE1::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxNQ==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE1::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTU=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTU=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTU=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTU=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE1::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE1::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxNQ==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE2::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxNg==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE2::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxNg==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE2::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTY=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTY=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTY=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTY=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE2::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE2::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxNg==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE3::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxNw==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE3::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxNw==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE3::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTc=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTc=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTc=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTc=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE3::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE3::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxNw==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTA=::MjQuNTc2MDAwIE1Ieg==::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTA="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQw::MCBwcw==::cGhhc2Vfc2hpZnQw"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTA=::NTA=::ZHV0eV9jeWNsZTA="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQx::MCBwcw==::cGhhc2Vfc2hpZnQx"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE=::NTA=::ZHV0eV9jeWNsZTE="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTI=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTI="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQy::MCBwcw==::cGhhc2Vfc2hpZnQy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTI=::NTA=::ZHV0eV9jeWNsZTI="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTM=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQz::MCBwcw==::cGhhc2Vfc2hpZnQz"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTM=::NTA=::ZHV0eV9jeWNsZTM="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTQ=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ0::MCBwcw==::cGhhc2Vfc2hpZnQ0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTQ=::NTA=::ZHV0eV9jeWNsZTQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTU=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTU="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ1::MCBwcw==::cGhhc2Vfc2hpZnQ1"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTU=::NTA=::ZHV0eV9jeWNsZTU="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTY=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTY="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ2::MCBwcw==::cGhhc2Vfc2hpZnQ2"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTY=::NTA=::ZHV0eV9jeWNsZTY="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTc=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTc="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ3::MCBwcw==::cGhhc2Vfc2hpZnQ3"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTc=::NTA=::ZHV0eV9jeWNsZTc="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTg=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTg="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ4::MCBwcw==::cGhhc2Vfc2hpZnQ4"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTg=::NTA=::ZHV0eV9jeWNsZTg="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTk=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTk="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ5::MCBwcw==::cGhhc2Vfc2hpZnQ5"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTk=::NTA=::ZHV0eV9jeWNsZTk="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEw::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEw"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxMA==::MCBwcw==::cGhhc2Vfc2hpZnQxMA=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTEw::NTA=::ZHV0eV9jeWNsZTEw"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEx::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEx"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxMQ==::MCBwcw==::cGhhc2Vfc2hpZnQxMQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTEx::NTA=::ZHV0eV9jeWNsZTEx"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEy::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxMg==::MCBwcw==::cGhhc2Vfc2hpZnQxMg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTEy::NTA=::ZHV0eV9jeWNsZTEy"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEz::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEz"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxMw==::MCBwcw==::cGhhc2Vfc2hpZnQxMw=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTEz::NTA=::ZHV0eV9jeWNsZTEz"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE0::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxNA==::MCBwcw==::cGhhc2Vfc2hpZnQxNA=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE0::NTA=::ZHV0eV9jeWNsZTE0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE1::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE1"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxNQ==::MCBwcw==::cGhhc2Vfc2hpZnQxNQ=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE1::NTA=::ZHV0eV9jeWNsZTE1"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE2::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE2"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxNg==::MCBwcw==::cGhhc2Vfc2hpZnQxNg=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE2::NTA=::ZHV0eV9jeWNsZTE2"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE3::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE3"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxNw==::MCBwcw==::cGhhc2Vfc2hpZnQxNw=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE3::NTA=::ZHV0eV9jeWNsZTE3"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BsbF9hdXRvX3Jlc2V0::T24=::UExMIEF1dG8gUmVzZXQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BsbF9iYW5kd2lkdGhfcHJlc2V0::QXV0bw==::UExMIEJhbmR3aWR0aCBQcmVzZXQ="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2VuX3JlY29uZg==::ZmFsc2U=::RW5hYmxlIGR5bmFtaWMgcmVjb25maWd1cmF0aW9uIG9mIFBMTA=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2VuX2Rwc19wb3J0cw==::ZmFsc2U=::RW5hYmxlIGFjY2VzcyB0byBkeW5hbWljIHBoYXNlIHNoaWZ0IHBvcnRz"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2VuX3Bob3V0X3BvcnRz::ZmFsc2U=::RW5hYmxlIGFjY2VzcyB0byBQTEwgRFBBIG91dHB1dCBwb3J0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGxsX3R5cGU=::R2VuZXJhbA==::UExMIFRZUEU="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "cGxsX3N1YnR5cGU=::R2VuZXJhbA==::UExMIFNVQlRZUEU="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BhcmFtZXRlcl9saXN0::TS1Db3VudGVyIEhpIERpdmlkZSxNLUNvdW50ZXIgTG93IERpdmlkZSxOLUNvdW50ZXIgSGkgRGl2aWRlLE4tQ291bnRlciBMb3cgRGl2aWRlLE0tQ291bnRlciBCeXBhc3MgRW5hYmxlLE4tQ291bnRlciBCeXBhc3MgRW5hYmxlLE0tQ291bnRlciBPZGQgRGl2aWRlIEVuYWJsZSxOLUNvdW50ZXIgT2RkIERpdmlkZSBFbmFibGUsQy1Db3VudGVyLTAgSGkgRGl2aWRlLEMtQ291bnRlci0wIExvdyBEaXZpZGUsQy1Db3VudGVyLTAgQ29hcnNlIFBoYXNlIFNoaWZ0LEMtQ291bnRlci0wIFZDTyBQaGFzZSBUYXAsQy1Db3VudGVyLTAgSW5wdXQgU291cmNlLEMtQ291bnRlci0wIEJ5cGFzcyBFbmFibGUsQy1Db3VudGVyLTAgT2RkIERpdmlkZSBFbmFibGUsVkNPIFBvc3QgRGl2aWRlIENvdW50ZXIgRW5hYmxlLENoYXJnZSBQdW1wIGN1cnJlbnQgKHVBKSxMb29wIEZpbHRlciBCYW5kd2lkdGggUmVzaXN0b3IgKE9obXMpICxQTEwgT3V0cHV0IFZDTyBGcmVxdWVuY3ksSy1GcmFjdGlvbmFsIERpdmlzaW9uIFZhbHVlIChEU00pLEZlZWRiYWNrIENsb2NrIFR5cGUsRmVlZGJhY2sgQ2xvY2sgTVVYIDEsRmVlZGJhY2sgQ2xvY2sgTVVYIDIsTSBDb3VudGVyIFNvdXJjZSBNVVgsUExMIEF1dG8gUmVzZXQ=::UGFyYW1ldGVyIE5hbWVz"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3BhcmFtZXRlcl92YWx1ZXM=::NCw0LDI1NiwyNTYsZmFsc2UsdHJ1ZSxmYWxzZSxmYWxzZSw5LDgsMSwwLHBoX211eF9jbGssZmFsc2UsdHJ1ZSwyLDIwLDQwMDAsNDE3Ljc5MiBNSHosMTUyODMyMTE2Myxub25lLGdsYixtX2NudCxwaF9tdXhfY2xrLHRydWU=::UGFyYW1ldGVyIFZhbHVlcw=="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX21pZl9nZW5lcmF0ZQ==::ZmFsc2U=::R2VuZXJhdGUgTUlGIGZpbGU="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9taWZfZHBz::ZmFsc2U=::RW5hYmxlIER5bmFtaWMgUGhhc2UgU2hpZnQgZm9yIE1JRiBzdHJlYW1pbmc="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Rwc19jbnRy::QzA=::RFBTIENvdW50ZXIgU2VsZWN0aW9u"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Rwc19udW0=::MQ==::TnVtYmVyIG9mIER5bmFtaWMgUGhhc2UgU2hpZnRz"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2Rwc19kaXI=::UG9zaXRpdmU=::RHluYW1pYyBQaGFzZSBTaGlmdCBEaXJlY3Rpb24="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX3JlZmNsa19zd2l0Y2g=::ZmFsc2U=::Q3JlYXRlIGEgc2Vjb25kIGlucHV0IGNsayAncmVmY2xrMSc="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9jYXNjYWRlX291dA==::ZmFsc2U=::Q3JlYXRlIGEgJ2Nhc2NhZGVfb3V0JyBzaWduYWwgdG8gY29ubmVjdCB3aXRoIGEgZG93bnN0cmVhbSBQTEw="
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9jYXNjYWRlX2lu::ZmFsc2U=::Q3JlYXRlIGFuIGFkanBsbGluIG9yIGNjbGsgc2lnbmFsIHRvIGNvbm5lY3Qgd2l0aCBhbiB1cHN0cmVhbSBQTEw="
set_global_assignment -library "pll_audio" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_audio.v"]
set_global_assignment -library "pll_audio" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_audio/pll_audio_0002.v"]
set_global_assignment -library "pll_audio" -name QIP_FILE [file join $::quartus(qip_path) "pll_audio/pll_audio_0002.qip"]
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_TOOL_NAME "altera_pll"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_TOOL_VERSION "17.0"
set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_TOOL_ENV "mwpim"

252
sys/pll_audio.v Normal file
View File

@@ -0,0 +1,252 @@
// megafunction wizard: %Altera PLL v17.0%
// GENERATION: XML
// pll_audio.v
// Generated using ACDS version 17.0 602
`timescale 1 ps / 1 ps
module pll_audio (
input wire refclk, // refclk.clk
input wire rst, // reset.reset
output wire outclk_0 // outclk0.clk
);
pll_audio_0002 pll_audio_inst (
.refclk (refclk), // refclk.clk
.rst (rst), // reset.reset
.outclk_0 (outclk_0), // outclk0.clk
.locked () // (terminated)
);
endmodule
// Retrieval info: <?xml version="1.0"?>
//<!--
// Generated by Altera MegaWizard Launcher Utility version 1.0
// ************************************************************
// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
// ************************************************************
// Copyright (C) 1991-2020 Altera Corporation
// Any megafunction design, and related net list (encrypted or decrypted),
// support information, device programming or simulation file, and any other
// associated documentation or information provided by Altera or a partner
// under Altera's Megafunction Partnership Program may be used only to
// program PLD devices (but not masked PLD devices) from Altera. Any other
// use of such megafunction design, net list, support information, device
// programming or simulation file, or any other related documentation or
// information is prohibited for any other purpose, including, but not
// limited to modification, reverse engineering, de-compiling, or use with
// any other silicon devices, unless such use is explicitly licensed under
// a separate agreement with Altera or a megafunction partner. Title to
// the intellectual property, including patents, copyrights, trademarks,
// trade secrets, or maskworks, embodied in any such megafunction design,
// net list, support information, device programming or simulation file, or
// any other related documentation or information provided by Altera or a
// megafunction partner, remains with Altera, the megafunction partner, or
// their respective licensors. No other licenses, including any licenses
// needed under any third party's intellectual property, are provided herein.
//-->
// Retrieval info: <instance entity-name="altera_pll" version="17.0" >
// Retrieval info: <generic name="debug_print_output" value="false" />
// Retrieval info: <generic name="debug_use_rbc_taf_method" value="false" />
// Retrieval info: <generic name="device_family" value="Cyclone V" />
// Retrieval info: <generic name="device" value="5CEBA2F17A7" />
// Retrieval info: <generic name="gui_device_speed_grade" value="1" />
// Retrieval info: <generic name="gui_pll_mode" value="Fractional-N PLL" />
// Retrieval info: <generic name="gui_reference_clock_frequency" value="50.0" />
// Retrieval info: <generic name="gui_channel_spacing" value="0.0" />
// Retrieval info: <generic name="gui_operation_mode" value="direct" />
// Retrieval info: <generic name="gui_feedback_clock" value="Global Clock" />
// Retrieval info: <generic name="gui_fractional_cout" value="32" />
// Retrieval info: <generic name="gui_dsm_out_sel" value="1st_order" />
// Retrieval info: <generic name="gui_use_locked" value="false" />
// Retrieval info: <generic name="gui_en_adv_params" value="false" />
// Retrieval info: <generic name="gui_number_of_clocks" value="1" />
// Retrieval info: <generic name="gui_multiply_factor" value="1" />
// Retrieval info: <generic name="gui_frac_multiply_factor" value="1" />
// Retrieval info: <generic name="gui_divide_factor_n" value="1" />
// Retrieval info: <generic name="gui_cascade_counter0" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency0" value="24.576" />
// Retrieval info: <generic name="gui_divide_factor_c0" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency0" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units0" value="ps" />
// Retrieval info: <generic name="gui_phase_shift0" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg0" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift0" value="0" />
// Retrieval info: <generic name="gui_duty_cycle0" value="50" />
// Retrieval info: <generic name="gui_cascade_counter1" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency1" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c1" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency1" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units1" value="ps" />
// Retrieval info: <generic name="gui_phase_shift1" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg1" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift1" value="0" />
// Retrieval info: <generic name="gui_duty_cycle1" value="50" />
// Retrieval info: <generic name="gui_cascade_counter2" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency2" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c2" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency2" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units2" value="ps" />
// Retrieval info: <generic name="gui_phase_shift2" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg2" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift2" value="0" />
// Retrieval info: <generic name="gui_duty_cycle2" value="50" />
// Retrieval info: <generic name="gui_cascade_counter3" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency3" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c3" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency3" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units3" value="ps" />
// Retrieval info: <generic name="gui_phase_shift3" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg3" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift3" value="0" />
// Retrieval info: <generic name="gui_duty_cycle3" value="50" />
// Retrieval info: <generic name="gui_cascade_counter4" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency4" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c4" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency4" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units4" value="ps" />
// Retrieval info: <generic name="gui_phase_shift4" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg4" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift4" value="0" />
// Retrieval info: <generic name="gui_duty_cycle4" value="50" />
// Retrieval info: <generic name="gui_cascade_counter5" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency5" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c5" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency5" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units5" value="ps" />
// Retrieval info: <generic name="gui_phase_shift5" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg5" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift5" value="0" />
// Retrieval info: <generic name="gui_duty_cycle5" value="50" />
// Retrieval info: <generic name="gui_cascade_counter6" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency6" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c6" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency6" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units6" value="ps" />
// Retrieval info: <generic name="gui_phase_shift6" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg6" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift6" value="0" />
// Retrieval info: <generic name="gui_duty_cycle6" value="50" />
// Retrieval info: <generic name="gui_cascade_counter7" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency7" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c7" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency7" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units7" value="ps" />
// Retrieval info: <generic name="gui_phase_shift7" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg7" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift7" value="0" />
// Retrieval info: <generic name="gui_duty_cycle7" value="50" />
// Retrieval info: <generic name="gui_cascade_counter8" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency8" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c8" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency8" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units8" value="ps" />
// Retrieval info: <generic name="gui_phase_shift8" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg8" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift8" value="0" />
// Retrieval info: <generic name="gui_duty_cycle8" value="50" />
// Retrieval info: <generic name="gui_cascade_counter9" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency9" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c9" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency9" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units9" value="ps" />
// Retrieval info: <generic name="gui_phase_shift9" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg9" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift9" value="0" />
// Retrieval info: <generic name="gui_duty_cycle9" value="50" />
// Retrieval info: <generic name="gui_cascade_counter10" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency10" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c10" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency10" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units10" value="ps" />
// Retrieval info: <generic name="gui_phase_shift10" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg10" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift10" value="0" />
// Retrieval info: <generic name="gui_duty_cycle10" value="50" />
// Retrieval info: <generic name="gui_cascade_counter11" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency11" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c11" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency11" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units11" value="ps" />
// Retrieval info: <generic name="gui_phase_shift11" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg11" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift11" value="0" />
// Retrieval info: <generic name="gui_duty_cycle11" value="50" />
// Retrieval info: <generic name="gui_cascade_counter12" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency12" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c12" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency12" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units12" value="ps" />
// Retrieval info: <generic name="gui_phase_shift12" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg12" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift12" value="0" />
// Retrieval info: <generic name="gui_duty_cycle12" value="50" />
// Retrieval info: <generic name="gui_cascade_counter13" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency13" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c13" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency13" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units13" value="ps" />
// Retrieval info: <generic name="gui_phase_shift13" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg13" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift13" value="0" />
// Retrieval info: <generic name="gui_duty_cycle13" value="50" />
// Retrieval info: <generic name="gui_cascade_counter14" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency14" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c14" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency14" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units14" value="ps" />
// Retrieval info: <generic name="gui_phase_shift14" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg14" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift14" value="0" />
// Retrieval info: <generic name="gui_duty_cycle14" value="50" />
// Retrieval info: <generic name="gui_cascade_counter15" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency15" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c15" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency15" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units15" value="ps" />
// Retrieval info: <generic name="gui_phase_shift15" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg15" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift15" value="0" />
// Retrieval info: <generic name="gui_duty_cycle15" value="50" />
// Retrieval info: <generic name="gui_cascade_counter16" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency16" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c16" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency16" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units16" value="ps" />
// Retrieval info: <generic name="gui_phase_shift16" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg16" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift16" value="0" />
// Retrieval info: <generic name="gui_duty_cycle16" value="50" />
// Retrieval info: <generic name="gui_cascade_counter17" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency17" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c17" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency17" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units17" value="ps" />
// Retrieval info: <generic name="gui_phase_shift17" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg17" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift17" value="0" />
// Retrieval info: <generic name="gui_duty_cycle17" value="50" />
// Retrieval info: <generic name="gui_pll_auto_reset" value="On" />
// Retrieval info: <generic name="gui_pll_bandwidth_preset" value="Auto" />
// Retrieval info: <generic name="gui_en_reconf" value="false" />
// Retrieval info: <generic name="gui_en_dps_ports" value="false" />
// Retrieval info: <generic name="gui_en_phout_ports" value="false" />
// Retrieval info: <generic name="gui_phout_division" value="1" />
// Retrieval info: <generic name="gui_mif_generate" value="false" />
// Retrieval info: <generic name="gui_enable_mif_dps" value="false" />
// Retrieval info: <generic name="gui_dps_cntr" value="C0" />
// Retrieval info: <generic name="gui_dps_num" value="1" />
// Retrieval info: <generic name="gui_dps_dir" value="Positive" />
// Retrieval info: <generic name="gui_refclk_switch" value="false" />
// Retrieval info: <generic name="gui_refclk1_frequency" value="100.0" />
// Retrieval info: <generic name="gui_switchover_mode" value="Automatic Switchover" />
// Retrieval info: <generic name="gui_switchover_delay" value="0" />
// Retrieval info: <generic name="gui_active_clk" value="false" />
// Retrieval info: <generic name="gui_clk_bad" value="false" />
// Retrieval info: <generic name="gui_enable_cascade_out" value="false" />
// Retrieval info: <generic name="gui_cascade_outclk_index" value="0" />
// Retrieval info: <generic name="gui_enable_cascade_in" value="false" />
// Retrieval info: <generic name="gui_pll_cascading_mode" value="Create an adjpllin signal to connect with an upstream PLL" />
// Retrieval info: </instance>
// IPFS_FILES : pll_audio.vo
// RELATED_FILES: pll_audio.v, pll_audio_0002.v

View File

@@ -0,0 +1,4 @@
set_instance_assignment -name PLL_COMPENSATION_MODE DIRECT -to "*pll_audio_0002*|altera_pll:altera_pll_i*|*"
set_instance_assignment -name PLL_CHANNEL_SPACING "0.0 KHz" -to "*pll_audio_0002*|altera_pll:altera_pll_i*|*"
set_instance_assignment -name PLL_AUTO_RESET ON -to "*pll_audio_0002*|altera_pll:altera_pll_i*|*"
set_instance_assignment -name PLL_BANDWIDTH_PRESET AUTO -to "*pll_audio_0002*|altera_pll:altera_pll_i*|*"

View File

@@ -0,0 +1,87 @@
`timescale 1ns/10ps
module pll_audio_0002(
// interface 'refclk'
input wire refclk,
// interface 'reset'
input wire rst,
// interface 'outclk0'
output wire outclk_0,
// interface 'locked'
output wire locked
);
altera_pll #(
.fractional_vco_multiplier("true"),
.reference_clock_frequency("50.0 MHz"),
.operation_mode("direct"),
.number_of_clocks(1),
.output_clock_frequency0("24.576000 MHz"),
.phase_shift0("0 ps"),
.duty_cycle0(50),
.output_clock_frequency1("0 MHz"),
.phase_shift1("0 ps"),
.duty_cycle1(50),
.output_clock_frequency2("0 MHz"),
.phase_shift2("0 ps"),
.duty_cycle2(50),
.output_clock_frequency3("0 MHz"),
.phase_shift3("0 ps"),
.duty_cycle3(50),
.output_clock_frequency4("0 MHz"),
.phase_shift4("0 ps"),
.duty_cycle4(50),
.output_clock_frequency5("0 MHz"),
.phase_shift5("0 ps"),
.duty_cycle5(50),
.output_clock_frequency6("0 MHz"),
.phase_shift6("0 ps"),
.duty_cycle6(50),
.output_clock_frequency7("0 MHz"),
.phase_shift7("0 ps"),
.duty_cycle7(50),
.output_clock_frequency8("0 MHz"),
.phase_shift8("0 ps"),
.duty_cycle8(50),
.output_clock_frequency9("0 MHz"),
.phase_shift9("0 ps"),
.duty_cycle9(50),
.output_clock_frequency10("0 MHz"),
.phase_shift10("0 ps"),
.duty_cycle10(50),
.output_clock_frequency11("0 MHz"),
.phase_shift11("0 ps"),
.duty_cycle11(50),
.output_clock_frequency12("0 MHz"),
.phase_shift12("0 ps"),
.duty_cycle12(50),
.output_clock_frequency13("0 MHz"),
.phase_shift13("0 ps"),
.duty_cycle13(50),
.output_clock_frequency14("0 MHz"),
.phase_shift14("0 ps"),
.duty_cycle14(50),
.output_clock_frequency15("0 MHz"),
.phase_shift15("0 ps"),
.duty_cycle15(50),
.output_clock_frequency16("0 MHz"),
.phase_shift16("0 ps"),
.duty_cycle16(50),
.output_clock_frequency17("0 MHz"),
.phase_shift17("0 ps"),
.duty_cycle17(50),
.pll_type("General"),
.pll_subtype("General")
) altera_pll_i (
.rst (rst),
.outclk ({outclk_0}),
.locked (locked),
.fboutclk ( ),
.fbclk (1'b0),
.refclk (refclk)
);
endmodule

44
sys/pll_cfg.qip Normal file
View File

@@ -0,0 +1,44 @@
set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_TOOL_NAME "altera_pll_reconfig"
set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_TOOL_VERSION "17.0"
set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_TOOL_ENV "mwpim"
set_global_assignment -library "pll_cfg" -name MISC_FILE [file join $::quartus(qip_path) "pll_cfg.cmp"]
set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_TARGETED_DEVICE_FAMILY "Cyclone V"
set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_GENERATED_DEVICE_FAMILY "{Cyclone V}"
set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_QSYS_MODE "UNKNOWN"
set_global_assignment -name SYNTHESIS_ONLY_QIP ON
set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_NAME "cGxsX2hkbWlfY2Zn"
set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_DISPLAY_NAME "QWx0ZXJhIFBMTCBSZWNvbmZpZw=="
set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_REPORT_HIERARCHY "Off"
set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_INTERNAL "Off"
set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_AUTHOR "QWx0ZXJhIENvcnBvcmF0aW9u"
set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_VERSION "MTcuMA=="
set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_DESCRIPTION "QWx0ZXJhIFBoYXNlLUxvY2tlZCBMb29wIFJlY29uZmlndXJhdGlvbiBCbG9jayhBTFRFUkFfUExMX1JFQ09ORklHKQ=="
set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "RU5BQkxFX0JZVEVFTkFCTEU=::ZmFsc2U=::QWRkIGJ5dGVlbmFibGUgcG9ydA=="
set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "QllURUVOQUJMRV9XSURUSA==::NA==::QllURUVOQUJMRV9XSURUSA=="
set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "UkVDT05GSUdfQUREUl9XSURUSA==::Ng==::UkVDT05GSUdfQUREUl9XSURUSA=="
set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "UkVDT05GSUdfREFUQV9XSURUSA==::MzI=::UkVDT05GSUdfREFUQV9XSURUSA=="
set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "cmVjb25mX3dpZHRo::NjQ=::cmVjb25mX3dpZHRo"
set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "V0FJVF9GT1JfTE9DSw==::dHJ1ZQ==::V0FJVF9GT1JfTE9DSw=="
set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_NAME "YWx0ZXJhX3BsbF9yZWNvbmZpZ190b3A="
set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_DISPLAY_NAME "QWx0ZXJhIFBMTCBSZWNvbmZpZw=="
set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_REPORT_HIERARCHY "Off"
set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_INTERNAL "Off"
set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_AUTHOR "QWx0ZXJhIENvcnBvcmF0aW9u"
set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_VERSION "MTcuMA=="
set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_DESCRIPTION "QWx0ZXJhIFBoYXNlLUxvY2tlZCBMb29wIFJlY29uZmlndXJhdGlvbiBCbG9jayhBTFRFUkFfUExMX1JFQ09ORklHKQ=="
set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "ZGV2aWNlX2ZhbWlseQ==::Q3ljbG9uZSBW::ZGV2aWNlX2ZhbWlseQ=="
set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "RU5BQkxFX01JRg==::ZmFsc2U=::RW5hYmxlIE1JRiBTdHJlYW1pbmc="
set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "RU5BQkxFX0JZVEVFTkFCTEU=::ZmFsc2U=::QWRkIGJ5dGVlbmFibGUgcG9ydA=="
set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "QllURUVOQUJMRV9XSURUSA==::NA==::QllURUVOQUJMRV9XSURUSA=="
set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "UkVDT05GSUdfQUREUl9XSURUSA==::Ng==::UkVDT05GSUdfQUREUl9XSURUSA=="
set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "UkVDT05GSUdfREFUQV9XSURUSA==::MzI=::UkVDT05GSUdfREFUQV9XSURUSA=="
set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "cmVjb25mX3dpZHRo::NjQ=::cmVjb25mX3dpZHRo"
set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "V0FJVF9GT1JfTE9DSw==::dHJ1ZQ==::V0FJVF9GT1JfTE9DSw=="
set_global_assignment -library "pll_cfg" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_cfg.v"]
set_global_assignment -library "pll_cfg" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_cfg/altera_pll_reconfig_top.v"]
set_global_assignment -library "pll_cfg" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_cfg/altera_pll_reconfig_core.v"]
set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_TOOL_NAME "altera_pll_reconfig"
set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_TOOL_VERSION "17.0"
set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_TOOL_ENV "mwpim"

86
sys/pll_cfg.v Normal file
View File

@@ -0,0 +1,86 @@
// megafunction wizard: %Altera PLL Reconfig v17.0%
// GENERATION: XML
// pll_cfg.v
// Generated using ACDS version 17.0 598
`timescale 1 ps / 1 ps
module pll_cfg #(
parameter ENABLE_BYTEENABLE = 0,
parameter BYTEENABLE_WIDTH = 4,
parameter RECONFIG_ADDR_WIDTH = 6,
parameter RECONFIG_DATA_WIDTH = 32,
parameter reconf_width = 64,
parameter WAIT_FOR_LOCK = 1
) (
input wire mgmt_clk, // mgmt_clk.clk
input wire mgmt_reset, // mgmt_reset.reset
output wire mgmt_waitrequest, // mgmt_avalon_slave.waitrequest
input wire mgmt_read, // .read
input wire mgmt_write, // .write
output wire [31:0] mgmt_readdata, // .readdata
input wire [5:0] mgmt_address, // .address
input wire [31:0] mgmt_writedata, // .writedata
output wire [63:0] reconfig_to_pll, // reconfig_to_pll.reconfig_to_pll
input wire [63:0] reconfig_from_pll // reconfig_from_pll.reconfig_from_pll
);
altera_pll_reconfig_top #(
.device_family ("Cyclone V"),
.ENABLE_MIF (0),
.MIF_FILE_NAME ("sys/pll_cfg.mif"),
.ENABLE_BYTEENABLE (ENABLE_BYTEENABLE),
.BYTEENABLE_WIDTH (BYTEENABLE_WIDTH),
.RECONFIG_ADDR_WIDTH (RECONFIG_ADDR_WIDTH),
.RECONFIG_DATA_WIDTH (RECONFIG_DATA_WIDTH),
.reconf_width (reconf_width),
.WAIT_FOR_LOCK (WAIT_FOR_LOCK)
) pll_cfg_inst (
.mgmt_clk (mgmt_clk), // mgmt_clk.clk
.mgmt_reset (mgmt_reset), // mgmt_reset.reset
.mgmt_waitrequest (mgmt_waitrequest), // mgmt_avalon_slave.waitrequest
.mgmt_read (mgmt_read), // .read
.mgmt_write (mgmt_write), // .write
.mgmt_readdata (mgmt_readdata), // .readdata
.mgmt_address (mgmt_address), // .address
.mgmt_writedata (mgmt_writedata), // .writedata
.reconfig_to_pll (reconfig_to_pll), // reconfig_to_pll.reconfig_to_pll
.reconfig_from_pll (reconfig_from_pll), // reconfig_from_pll.reconfig_from_pll
.mgmt_byteenable (4'b0000) // (terminated)
);
endmodule
// Retrieval info: <?xml version="1.0"?>
//<!--
// Generated by Altera MegaWizard Launcher Utility version 1.0
// ************************************************************
// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
// ************************************************************
// Copyright (C) 1991-2018 Altera Corporation
// Any megafunction design, and related net list (encrypted or decrypted),
// support information, device programming or simulation file, and any other
// associated documentation or information provided by Altera or a partner
// under Altera's Megafunction Partnership Program may be used only to
// program PLD devices (but not masked PLD devices) from Altera. Any other
// use of such megafunction design, net list, support information, device
// programming or simulation file, or any other related documentation or
// information is prohibited for any other purpose, including, but not
// limited to modification, reverse engineering, de-compiling, or use with
// any other silicon devices, unless such use is explicitly licensed under
// a separate agreement with Altera or a megafunction partner. Title to
// the intellectual property, including patents, copyrights, trademarks,
// trade secrets, or maskworks, embodied in any such megafunction design,
// net list, support information, device programming or simulation file, or
// any other related documentation or information provided by Altera or a
// megafunction partner, remains with Altera, the megafunction partner, or
// their respective licensors. No other licenses, including any licenses
// needed under any third party's intellectual property, are provided herein.
//-->
// Retrieval info: <instance entity-name="altera_pll_reconfig" version="17.0" >
// Retrieval info: <generic name="device_family" value="Cyclone V" />
// Retrieval info: <generic name="ENABLE_MIF" value="false" />
// Retrieval info: <generic name="MIF_FILE_NAME" value="sys/pll_cfg.mif" />
// Retrieval info: <generic name="ENABLE_BYTEENABLE" value="false" />
// Retrieval info: </instance>
// IPFS_FILES : pll_cfg.vo
// RELATED_FILES: pll_cfg.v, altera_pll_reconfig_top.v, altera_pll_reconfig_core.v, altera_std_synchronizer.v

Some files were not shown because too many files have changed in this diff Show More