commit 429dcabcbdfdd7c3f8005561024d75c6db9e5f4e Author: sorgelig Date: Fri Mar 19 23:42:15 2021 +0800 Initial commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f6925a --- /dev/null +++ b/.gitignore @@ -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 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..821d76a --- /dev/null +++ b/README.md @@ -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. + + diff --git a/ZXNext.qpf b/ZXNext.qpf new file mode 100644 index 0000000..7126f5e --- /dev/null +++ b/ZXNext.qpf @@ -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" diff --git a/ZXNext.qsf b/ZXNext.qsf new file mode 100644 index 0000000..3111633 --- /dev/null +++ b/ZXNext.qsf @@ -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 \ No newline at end of file diff --git a/ZXNext.sdc b/ZXNext.sdc new file mode 100644 index 0000000..771665f --- /dev/null +++ b/ZXNext.sdc @@ -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 diff --git a/ZXNext.srf b/ZXNext.srf new file mode 100644 index 0000000..5b0da0e --- /dev/null +++ b/ZXNext.srf @@ -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 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 ""} diff --git a/ZXNext.sv b/ZXNext.sv new file mode 100644 index 0000000..15d2cb6 --- /dev/null +++ b/ZXNext.sv @@ -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 diff --git a/clean.bat b/clean.bat new file mode 100644 index 0000000..1e6a801 --- /dev/null +++ b/clean.bat @@ -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 diff --git a/files.qip b/files.qip new file mode 100644 index 0000000..1b5b557 --- /dev/null +++ b/files.qip @@ -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 diff --git a/releases/boot.zip b/releases/boot.zip new file mode 100644 index 0000000..ce20c9a Binary files /dev/null and b/releases/boot.zip differ diff --git a/rtl/audio/audio_mixer.vhd b/rtl/audio/audio_mixer.vhd new file mode 100644 index 0000000..012a885 --- /dev/null +++ b/rtl/audio/audio_mixer.vhd @@ -0,0 +1,107 @@ + +-- Audio Mixer +-- Copyright 2020 Fabio Belavenuto and Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +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; diff --git a/rtl/audio/dac.vhd b/rtl/audio/dac.vhd new file mode 100644 index 0000000..614050d --- /dev/null +++ b/rtl/audio/dac.vhd @@ -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; diff --git a/rtl/audio/i2s.vhd b/rtl/audio/i2s.vhd new file mode 100644 index 0000000..6362ef1 --- /dev/null +++ b/rtl/audio/i2s.vhd @@ -0,0 +1,208 @@ + +-- I2S Pi0 + ZX Spectrum Next Interface +-- Copyright 2020 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- Reference: +-- +-- +-- 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; diff --git a/rtl/audio/i2s/i2s_master.vhd b/rtl/audio/i2s/i2s_master.vhd new file mode 100644 index 0000000..d4b6c48 --- /dev/null +++ b/rtl/audio/i2s/i2s_master.vhd @@ -0,0 +1,153 @@ + +-- I2S Master +-- Copyright 2020 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- Generates: +-- sck - master clock +-- ws - channel selection (0 = left, 1 = right) +-- wsp - one on falling edge of sck indicates channel change +-- +-- Reference: +-- +-- +-- 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; diff --git a/rtl/audio/i2s/i2s_receive.vhd b/rtl/audio/i2s/i2s_receive.vhd new file mode 100644 index 0000000..6c4a929 --- /dev/null +++ b/rtl/audio/i2s/i2s_receive.vhd @@ -0,0 +1,146 @@ + +-- I2S Receiver +-- Copyright 2020 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- 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; diff --git a/rtl/audio/i2s/i2s_slave.vhd b/rtl/audio/i2s/i2s_slave.vhd new file mode 100644 index 0000000..135191e --- /dev/null +++ b/rtl/audio/i2s/i2s_slave.vhd @@ -0,0 +1,74 @@ + +-- I2S Slave +-- Copyright 2020 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- Generates: +-- wsp - one on falling edge of sck indicates channel change +-- +-- Reference: +-- + +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; diff --git a/rtl/audio/i2s/i2s_transmit.vhd b/rtl/audio/i2s/i2s_transmit.vhd new file mode 100644 index 0000000..55bcc57 --- /dev/null +++ b/rtl/audio/i2s/i2s_transmit.vhd @@ -0,0 +1,103 @@ + +-- I2S Transmitter +-- Copyright 2020 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- Reference: +-- +-- +-- 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; diff --git a/rtl/audio/pwm.vhd b/rtl/audio/pwm.vhd new file mode 100644 index 0000000..7fcc15e --- /dev/null +++ b/rtl/audio/pwm.vhd @@ -0,0 +1,97 @@ + +-- Pulse Width Modulator DAC +-- Copyright 2020 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- 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; diff --git a/rtl/audio/soundrive.vhd b/rtl/audio/soundrive.vhd new file mode 100644 index 0000000..8f523a9 --- /dev/null +++ b/rtl/audio/soundrive.vhd @@ -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 +-- +-- +-- 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 +-- . + +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; diff --git a/rtl/audio/turbosound.vhd b/rtl/audio/turbosound.vhd new file mode 100644 index 0000000..39471f9 --- /dev/null +++ b/rtl/audio/turbosound.vhd @@ -0,0 +1,339 @@ + +-- TurboSound Next +-- Copyright 2020 Fabio Belavenuto and Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +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; diff --git a/rtl/audio/ym2149.vhd b/rtl/audio/ym2149.vhd new file mode 100644 index 0000000..a83c568 --- /dev/null +++ b/rtl/audio/ym2149.vhd @@ -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 +-- +-- +-- 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; diff --git a/rtl/cpu/t80n.vhd b/rtl/cpu/t80n.vhd new file mode 100644 index 0000000..b3fd553 --- /dev/null +++ b/rtl/cpu/t80n.vhd @@ -0,0 +1,1772 @@ +-- +-- 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 : +-- +-- 0208 : First complete release +-- +-- 0210 : Fixed wait and halt +-- +-- 0211 : Fixed Refresh addition and IM 1 +-- +-- 0214 : Fixed mostly flags, only the block instructions now fail the zex regression test +-- +-- 0232 : Removed refresh address output for Mode > 1 and added DJNZ M1_n fix by Mike Johnson +-- +-- 0235 : Added clock enable and IM 2 fix by Mike Johnson +-- +-- 0237 : Changed 8080 I/O address output, added IntE output +-- +-- 0238 : Fixed (IX/IY+d) timing and 16 bit ADC and SBC zero flag +-- +-- 0240 : Added interrupt ack fix by Mike Johnson, changed (IX/IY+d) timing and changed flags in GB mode +-- +-- 0242 : Added I/O wait, fixed refresh address, moved some registers to RAM +-- +-- 0247 : Fixed bus req/ack cycle +-- + +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 T80N is + 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 T80N; + +architecture rtl of T80N is + + constant aNone : std_logic_vector(2 downto 0) := "111"; + constant aBC : std_logic_vector(2 downto 0) := "000"; + constant aDE : std_logic_vector(2 downto 0) := "001"; + constant aXY : std_logic_vector(2 downto 0) := "010"; + constant aIOA : std_logic_vector(2 downto 0) := "100"; + constant aSP : std_logic_vector(2 downto 0) := "101"; + constant aZI : std_logic_vector(2 downto 0) := "110"; + + constant dBC : std_logic_vector(1 downto 0) := "00"; + constant dDE : std_logic_vector(1 downto 0) := "01"; + constant dHL : std_logic_vector(1 downto 0) := "10"; + + + -- Registers + signal ACC, F : std_logic_vector(7 downto 0); + signal Ap, Fp : std_logic_vector(7 downto 0); + signal I : std_logic_vector(7 downto 0); + signal R : unsigned(7 downto 0); + signal SP, PC : unsigned(15 downto 0); + signal RegDIH : std_logic_vector(7 downto 0); + signal RegDIL : std_logic_vector(7 downto 0); + signal RegBusA : std_logic_vector(15 downto 0); + signal RegBusB : std_logic_vector(15 downto 0); + signal RegBusC : std_logic_vector(15 downto 0); + signal RegAddrA_r : std_logic_vector(2 downto 0); + signal RegAddrA : std_logic_vector(2 downto 0); + signal RegAddrB_r : std_logic_vector(2 downto 0); + signal RegAddrB : std_logic_vector(2 downto 0); + signal RegAddrC : std_logic_vector(2 downto 0); + signal RegWEH : std_logic; + signal RegWEL : std_logic; + signal Alternate : std_logic; + + -- Help Registers + signal TmpAddr : std_logic_vector(15 downto 0); -- Temporary address register + signal IR : std_logic_vector(7 downto 0); -- Instruction register + signal ISet : std_logic_vector(1 downto 0); -- Instruction set selector + signal RegBusA_r : std_logic_vector(15 downto 0); + + signal ID16 : signed(15 downto 0); + signal Save_Mux : std_logic_vector(7 downto 0); + + signal TState : unsigned(2 downto 0); + signal MCycle : std_logic_vector(2 downto 0); + signal IntE_FF1 : std_logic; + signal IntE_FF2 : std_logic; + signal Halt_FF : std_logic; + signal BusReq_s : std_logic; + signal BusAck : std_logic; + signal ClkEn : std_logic; + signal NMI_s : std_logic; + signal INT_s : std_logic; + signal IStatus : std_logic_vector(1 downto 0); + + signal DI_Reg : std_logic_vector(7 downto 0); + signal T_Res : std_logic; + signal XY_State : std_logic_vector(1 downto 0); + signal Pre_XY_F_M : std_logic_vector(2 downto 0); + signal NextIs_XY_Fetch : std_logic; + signal XY_Ind : std_logic; + signal No_BTR : std_logic; + signal BTR_r : std_logic; + signal Auto_Wait : std_logic; + signal Auto_Wait_t1 : std_logic; + signal Auto_Wait_t2 : std_logic; + signal IncDecZ : std_logic; + + -- ALU signals + signal BusB : std_logic_vector(7 downto 0); + signal BusA : std_logic_vector(7 downto 0); + signal ALU_Q : std_logic_vector(7 downto 0); + signal F_Out : std_logic_vector(7 downto 0); + + -- Registered micro code outputs + signal Read_To_Reg_r : std_logic_vector(4 downto 0); + signal Arith16_r : std_logic; + signal Z16_r : std_logic; + signal ALU_Op_r : std_logic_vector(3 downto 0); + signal Save_ALU_r : std_logic; + signal PreserveC_r : std_logic; + signal MCycles : std_logic_vector(2 downto 0); + + -- Micro code outputs + signal MCycles_d : std_logic_vector(2 downto 0); + signal TStates : std_logic_vector(2 downto 0); + signal IntCycle : std_logic; + signal NMICycle : std_logic; + signal Inc_PC : std_logic; + signal Inc_WZ : std_logic; + signal IncDec_16 : std_logic_vector(3 downto 0); + signal Prefix : std_logic_vector(1 downto 0); + signal Read_To_Acc : std_logic; + signal Read_To_Reg : std_logic; + signal Set_BusB_To : std_logic_vector(3 downto 0); + signal Set_BusA_To : std_logic_vector(3 downto 0); + signal ALU_Op : std_logic_vector(3 downto 0); + signal Save_ALU : std_logic; + signal PreserveC : std_logic; + signal Arith16 : std_logic; + signal Set_Addr_To : std_logic_vector(2 downto 0); + signal Jump : std_logic; + signal JumpE : std_logic; + signal JumpXY : std_logic; + signal Call : std_logic; + signal RstP : std_logic; + signal LDZ : std_logic; + signal LDW : std_logic; + signal LDSPHL : std_logic; + signal IORQ_i : std_logic; + signal Special_LD : std_logic_vector(2 downto 0); + signal ExchangeDH : std_logic; + signal ExchangeRp : std_logic; + signal ExchangeAF : std_logic; + signal ExchangeRS : std_logic; + signal I_DJNZ : std_logic; + signal I_CPL : std_logic; + signal I_CCF : std_logic; + signal I_SCF : std_logic; + signal I_RETN : std_logic; + signal I_BT : std_logic; + signal I_BC : std_logic; + signal I_BTR : std_logic; + signal I_RLD : std_logic; + signal I_RRD : std_logic; + signal I_INRC : std_logic; + signal SetDI : std_logic; + signal SetEI : std_logic; + signal IMode : std_logic_vector(1 downto 0); + signal Halt : std_logic; + signal XYbit_undoc : std_logic; + + --------------------------------- + signal Z80N_data_s : std_logic_vector(7 downto 0); + signal Z80N_data_o_strobe_lo : std_logic; + signal Z80N_data_o_strobe_hi : std_logic; + signal Z80N_command_s : Z80N_seq; + signal debug_s : std_logic_vector(7 downto 0) := (others=>'0'); + + + signal ACC32 : std_logic_vector(31 downto 0); + + signal reg_direct_H_a : std_logic := '0'; + signal reg_direct_L_a : std_logic := '0'; + signal reg_direct_H_b : std_logic := '0'; + signal reg_direct_L_b : std_logic := '0'; + + signal reg_direct_add_H_a : std_logic_vector(2 downto 0); + signal reg_direct_add_L_a : std_logic_vector(2 downto 0); + signal reg_direct_add_H_b : std_logic_vector(2 downto 0); + signal reg_direct_add_L_b : std_logic_vector(2 downto 0); + signal reg_direct_add_H_c : std_logic_vector(2 downto 0); + signal reg_direct_add_L_c : std_logic_vector(2 downto 0); + + signal reg_direct_val_H_a: std_logic_vector(7 downto 0) := (others=>'0'); + signal reg_direct_val_H_b: std_logic_vector(7 downto 0) := (others=>'0'); + signal reg_direct_val_L_a: std_logic_vector(7 downto 0) := (others=>'0'); + signal reg_direct_val_L_b: std_logic_vector(7 downto 0) := (others=>'0'); + + signal temp1: std_logic_vector(7 downto 0) := (others=>'0'); + signal temp2: std_logic_vector(15 downto 0) := (others=>'0'); + + ------------------------------------ +-- REGS + + type Register_Image is array (integer range 0 to 7) of std_logic_vector(7 downto 0); + signal RegsH : Register_Image; + signal RegsL : Register_Image; + +begin + + Z80N_command_o <= Z80N_command_s; + + mcode : T80N_MCode + generic map( + Mode => Mode, + Flag_C => Flag_C, + Flag_N => Flag_N, + Flag_P => Flag_P, + Flag_X => Flag_X, + Flag_H => Flag_H, + Flag_Y => Flag_Y, + Flag_Z => Flag_Z, + Flag_S => Flag_S) + port map( + IR => IR, + ISet => ISet, + MCycle => MCycle, + F => F, + NMICycle => NMICycle, + IntCycle => IntCycle, + XY_State => XY_State, + MCycles => MCycles_d, + TStates => TStates, + Prefix => Prefix, + Inc_PC => Inc_PC, + Inc_WZ => Inc_WZ, + IncDec_16 => IncDec_16, + Read_To_Acc => Read_To_Acc, + Read_To_Reg => Read_To_Reg, + Set_BusB_To => Set_BusB_To, + Set_BusA_To => Set_BusA_To, + ALU_Op => ALU_Op, + Save_ALU => Save_ALU, + PreserveC => PreserveC, + Arith16 => Arith16, + Set_Addr_To => Set_Addr_To, + IORQ => IORQ_i, + Jump => Jump, + JumpE => JumpE, + JumpXY => JumpXY, + Call => Call, + RstP => RstP, + LDZ => LDZ, + LDW => LDW, + LDSPHL => LDSPHL, + Special_LD => Special_LD, + ExchangeDH => ExchangeDH, + ExchangeRp => ExchangeRp, + ExchangeAF => ExchangeAF, + ExchangeRS => ExchangeRS, + I_DJNZ => I_DJNZ, + I_CPL => I_CPL, + I_CCF => I_CCF, + I_SCF => I_SCF, + I_RETN => I_RETN, + I_BT => I_BT, + I_BC => I_BC, + I_BTR => I_BTR, + I_RLD => I_RLD, + I_RRD => I_RRD, + I_INRC => I_INRC, + SetDI => SetDI, + SetEI => SetEI, + IMode => IMode, + Halt => Halt, + NoRead => NoRead, + Write => Write, + XYbit_undoc => XYbit_undoc, + ext_ACC_i => ACC, + ext_Data_i => DI_Reg, + Z80N_dout_o => Z80N_dout_o, + Z80N_data_o => Z80N_data_s, + Z80N_data_o_strobe_lo => Z80N_data_o_strobe_lo, + Z80N_data_o_strobe_hi => Z80N_data_o_strobe_hi, + Z80N_command_o => Z80N_command_s +); + + alu : T80N_ALU + generic map( + Mode => Mode, + Flag_C => Flag_C, + Flag_N => Flag_N, + Flag_P => Flag_P, + Flag_X => Flag_X, + Flag_H => Flag_H, + Flag_Y => Flag_Y, + Flag_Z => Flag_Z, + Flag_S => Flag_S) + port map( + Arith16 => Arith16_r, + Z16 => Z16_r, + ALU_Op => ALU_Op_r, + IR => IR(5 downto 0), + ISet => ISet, + BusA => BusA, + BusB => BusB, + F_In => F, + Q => ALU_Q, + F_Out => F_Out); + + ClkEn <= CEN and not BusAck; + + T_Res <= '1' when TState = unsigned(TStates) else '0'; + + NextIs_XY_Fetch <= '1' when XY_State /= "00" and XY_Ind = '0' and + ((Set_Addr_To = aXY) or + (MCycle = "001" and IR = "11001011") or + (MCycle = "001" and IR = "00110110")) else '0'; + + Save_Mux <= BusB when ExchangeRp = '1' else + DI_Reg when Save_ALU_r = '0' else + ALU_Q; + + process (RESET_n, CLK_n) + variable reg_temp_t : std_logic_vector(31 downto 0); + begin + + if CLK_n'event and CLK_n = '1' then + + if RESET_n = '0' then + PC <= (others => '0'); -- Program Counter + A <= (others => '0'); + TmpAddr <= (others => '0'); + IR <= "00000000"; + ISet <= "00"; + XY_State <= "00"; + IStatus <= "00"; + MCycles <= "000"; + DO <= "00000000"; + + ACC <= (others => '1'); + F <= (others => '1'); + Ap <= (others => '1'); + Fp <= (others => '1'); + I <= (others => '0'); + R <= (others => '0'); + SP <= (others => '1'); + Alternate <= '0'; + + Read_To_Reg_r <= "00000"; + F <= (others => '1'); + Arith16_r <= '0'; + BTR_r <= '0'; + Z16_r <= '0'; + ALU_Op_r <= "0000"; + Save_ALU_r <= '0'; + PreserveC_r <= '0'; + XY_Ind <= '0'; + + + elsif ClkEn = '1' then + + + reg_direct_H_a <= '0'; + reg_direct_L_a <= '0'; + reg_direct_H_b <= '0'; + reg_direct_L_b <= '0'; + + ALU_Op_r <= "0000"; + Save_ALU_r <= '0'; + Read_To_Reg_r <= "00000"; + + MCycles <= MCycles_d; + + if IMode /= "11" then + IStatus <= IMode; + end if; + + Arith16_r <= Arith16; + PreserveC_r <= PreserveC; + if ISet = "10" and ALU_OP(2) = '0' and ALU_OP(0) = '1' and MCycle = "011" then + Z16_r <= '1'; + else + Z16_r <= '0'; + end if; + + if MCycle = "001" and TState(2) = '0' then + -- MCycle = 1 and TState = 1, 2, or 3 + + if TState = 2 and WAIT_n = '1' then + if Mode < 2 then -- set the Refresh address + A(7 downto 0) <= std_logic_vector(R); + A(15 downto 8) <= I; + R(6 downto 0) <= R(6 downto 0) + 1; + end if; + + if Jump = '0' and Call = '0' and NMICycle = '0' and IntCycle = '0' and not (Halt_FF = '1' or Halt = '1') then + PC <= PC + 1; + end if; + + if IntCycle = '1' and IStatus = "01" then + IR <= "11111111"; + elsif Halt_FF = '1' or (IntCycle = '1' and IStatus = "10") or NMICycle = '1' then + IR <= "00000000"; + else + IR <= DInst; + end if; + + ISet <= "00"; + if Prefix /= "00" then + if Prefix = "11" then + if IR(5) = '1' then + XY_State <= "10"; + else + XY_State <= "01"; + end if; + else + if Prefix = "10" then + XY_State <= "00"; + XY_Ind <= '0'; + end if; + ISet <= Prefix; + end if; + else + XY_State <= "00"; + XY_Ind <= '0'; + end if; + end if; + + else + -- either (MCycle > 1) OR (MCycle = 1 AND TState > 3) + + if MCycle = "110" then + XY_Ind <= '1'; + if Prefix = "01" then + ISet <= "01"; + end if; + end if; + + if T_Res = '1' then + BTR_r <= (I_BT or I_BC or I_BTR) and not No_BTR; + if Jump = '1' then + A(15 downto 8) <= DI_Reg; + A(7 downto 0) <= TmpAddr(7 downto 0); + PC(15 downto 8) <= unsigned(DI_Reg); + PC(7 downto 0) <= unsigned(TmpAddr(7 downto 0)); + elsif JumpXY = '1' then + A <= RegBusC; + PC <= unsigned(RegBusC); + elsif Call = '1' or RstP = '1' then + A <= TmpAddr; + PC <= unsigned(TmpAddr); + elsif MCycle = MCycles and NMICycle = '1' then + A <= "0000000001100110"; + PC <= "0000000001100110"; + elsif MCycle = "011" and IntCycle = '1' and IStatus = "10" then + A(15 downto 8) <= I; + A(7 downto 0) <= TmpAddr(7 downto 0); + PC(15 downto 8) <= unsigned(I); + PC(7 downto 0) <= unsigned(TmpAddr(7 downto 0)); + else + case Set_Addr_To is + when aXY => + if XY_State = "00" then + A <= RegBusC; + else + if NextIs_XY_Fetch = '1' then + A <= std_logic_vector(PC); + else + A <= TmpAddr; + end if; + end if; + when aIOA => + if Mode = 3 then + -- Memory map I/O on GBZ80 + A(15 downto 8) <= (others => '1'); + elsif Mode = 2 then + -- Duplicate I/O address on 8080 + A(15 downto 8) <= DI_Reg; + else + A(15 downto 8) <= ACC; + end if; + A(7 downto 0) <= DI_Reg; + when aSP => + A <= std_logic_vector(SP); + when aBC => + if Mode = 3 and IORQ_i = '1' then + -- Memory map I/O on GBZ80 + A(15 downto 8) <= (others => '1'); + A(7 downto 0) <= RegBusC(7 downto 0); + else + A <= RegBusC; + end if; + when aDE => + A <= RegBusC; + when aZI => + if Inc_WZ = '1' then + A <= std_logic_vector(unsigned(TmpAddr) + 1); + else + A(15 downto 8) <= DI_Reg; + A(7 downto 0) <= TmpAddr(7 downto 0); + end if; + when others => + A <= std_logic_vector(PC); + end case; + end if; + + Save_ALU_r <= Save_ALU; + ALU_Op_r <= ALU_Op; + + if I_CPL = '1' then + -- CPL + ACC <= not ACC; + F(Flag_Y) <= not ACC(5); + F(Flag_H) <= '1'; + F(Flag_X) <= not ACC(3); + F(Flag_N) <= '1'; + end if; + if I_CCF = '1' then + -- CCF + F(Flag_C) <= not F(Flag_C); + F(Flag_Y) <= ACC(5); + F(Flag_H) <= F(Flag_C); + F(Flag_X) <= ACC(3); + F(Flag_N) <= '0'; + end if; + if I_SCF = '1' then + -- SCF + F(Flag_C) <= '1'; + F(Flag_Y) <= ACC(5); + F(Flag_H) <= '0'; + F(Flag_X) <= ACC(3); + F(Flag_N) <= '0'; + end if; + end if; + + if TState = 2 and WAIT_n = '1' then + if ISet = "01" and MCycle = "111" then + IR <= DInst; + end if; + if JumpE = '1' then + PC <= unsigned(signed(PC) + signed(DI_Reg)); + elsif Inc_PC = '1' then + PC <= PC + 1; + end if; + if BTR_r = '1' then + PC <= PC - 2; + end if; + if RstP = '1' then + TmpAddr <= (others =>'0'); + TmpAddr(5 downto 3) <= IR(5 downto 3); + end if; + end if; + if TState = 3 and MCycle = "110" then + TmpAddr <= std_logic_vector(signed(RegBusC) + signed(DI_Reg)); + end if; + + if (TState = 2 and WAIT_n = '1') or (TState = 4 and MCycle = "001") then + if IncDec_16(2 downto 0) = "111" then + if IncDec_16(3) = '1' then + SP <= SP - 1; + else + SP <= SP + 1; + end if; + end if; + end if; + + + + if LDSPHL = '1' then + SP <= unsigned(RegBusC); + end if; + + if ExchangeAF = '1' then + Ap <= ACC; + ACC <= Ap; + Fp <= F; + F <= Fp; + end if; + if ExchangeRS = '1' then + Alternate <= not Alternate; + end if; + end if; + +--------------------------------------------- + + + if TState = 3 then + reg_temp_t := (others=>'0'); + + case Z80N_command_s is + + when SWAPNIB_A => + reg_temp_t(7 downto 0) := ACC; + ACC <= reg_temp_t(3 downto 0) & reg_temp_t(7 downto 4); + + when MIRROR_A => + reg_temp_t(7 downto 0) := ACC; + ACC <= reg_temp_t(0) & reg_temp_t(1) & reg_temp_t(2) & reg_temp_t(3) & reg_temp_t(4) & reg_temp_t(5) & reg_temp_t(6) & reg_temp_t(7); + + when others => null; + + end case; + + end if; + + if TState = 3 or TState = 4 then + + + + reg_direct_add_H_a <= Alternate & dDE; -- D + reg_direct_add_L_a <= Alternate & dDE; -- E + reg_direct_add_H_b <= Alternate & dHL; -- H + reg_direct_add_L_b <= Alternate & dHL; -- L + reg_direct_add_H_c <= Alternate & dBC; -- B + reg_direct_add_L_c <= Alternate & dBC; -- C + + case Z80N_command_s is + + when MUL_DE => + + + reg_temp_t(15 downto 0) := std_logic_vector( + unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_a)))) ) * + unsigned(unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_a)))) ) + ); + + reg_direct_val_H_a <= reg_temp_t(15 downto 8); -- D + reg_direct_val_L_a <= reg_temp_t(7 downto 0); -- E + + reg_direct_H_a <= '1'; -- write D + reg_direct_L_a <= '1'; -- write E + + + -- when MUL_DEHL => + -- + -- + -- reg_temp_t(31 downto 0) := std_logic_vector( + -- unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_a)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_a))))) * + -- unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_b)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_b))))) + -- ); + -- + -- + -- reg_direct_val_H_a <= reg_temp_t(31 downto 24); -- D + -- reg_direct_val_L_a <= reg_temp_t(23 downto 16); -- E + -- reg_direct_val_H_b <= reg_temp_t(15 downto 8); -- H + -- reg_direct_val_L_b <= reg_temp_t(7 downto 0); -- L + -- + -- reg_direct_H_a <= '1'; -- write D + -- reg_direct_L_a <= '1'; -- write E + -- reg_direct_H_b <= '1'; -- write H + -- reg_direct_L_b <= '1'; -- write L + + + when ADD_HL_A | ADD_DE_A | ADD_BC_A => + + + if Z80N_command_s = ADD_HL_A then + reg_direct_add_H_a <= Alternate & dHL; + reg_direct_add_L_a <= Alternate & dHL; + elsif Z80N_command_s = ADD_DE_A then + reg_direct_add_H_a <= Alternate & dDE; + reg_direct_add_L_a <= Alternate & dDE; + elsif Z80N_command_s = ADD_BC_A then + reg_direct_add_H_a <= Alternate & dBC; + reg_direct_add_L_a <= Alternate & dBC; + end if; + + reg_temp_t(15 downto 0) := std_logic_vector( + unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_a)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_a))))) + + unsigned(ACC) + ); + + F(Flag_C) <= reg_temp_t(16); + + reg_direct_val_H_a <= reg_temp_t(15 downto 8); + reg_direct_val_L_a <= reg_temp_t(7 downto 0); + + reg_direct_H_a <= '1'; -- write + reg_direct_L_a <= '1'; -- write + + -- + -- when LD_ACC32_DEHL | EXXACC32 => + -- + -- if tstate = 3 then + -- reg_temp_t(31 downto 0) := ACC32; + -- end if; + -- + -- + -- ACC32 <= std_logic_vector( + -- unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_a)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_a))))) & + -- unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_b)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_b))))) + -- ); + -- + -- if Z80N_command_s = EXXACC32 then + -- reg_direct_val_H_a <= reg_temp_t(31 downto 24); -- D + -- reg_direct_val_L_a <= reg_temp_t(23 downto 16); -- E + -- reg_direct_val_H_b <= reg_temp_t(15 downto 8); -- H + -- reg_direct_val_L_b <= reg_temp_t(7 downto 0); -- L + -- + -- reg_direct_H_a <= '1'; -- write D + -- reg_direct_L_a <= '1'; -- write E + -- reg_direct_H_b <= '1'; -- write H + -- reg_direct_L_b <= '1'; -- write L + -- end if; +-- + -- when LD_DEHL_ACC32 => + -- + -- reg_direct_val_H_a <= ACC32(31 downto 24); -- D + -- reg_direct_val_L_a <= ACC32(23 downto 16); -- E + -- reg_direct_val_H_b <= ACC32(15 downto 8); -- H + -- reg_direct_val_L_b <= ACC32(7 downto 0); -- L + -- + -- reg_direct_H_a <= '1'; -- write D + -- reg_direct_L_a <= '1'; -- write E + -- reg_direct_H_b <= '1'; -- write H + -- reg_direct_L_b <= '1'; -- write L + -- + -- -- reg_DE_temp_s <= ACC32(31 downto 16); + -- -- reg_HL_temp_s <= ACC32(15 downto 0); + -- -- reg_wr_s <= "001111"; -- write regs H L D E + -- + -- when INC_DEHL | DEC_DEHL | ADD_DEHL_A | SUB_DEHL_A | ADD_DEHL_BC | SUB_DEHL_BC => +-- + -- + -- reg_temp_t(31 downto 0) := std_logic_vector(unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_a)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_a))))) & + -- unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_b)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_b)))))); + -- + -- if Z80N_command_s = INC_DEHL then + -- reg_temp_t := std_logic_vector(unsigned(reg_temp_t) + 1); + -- + -- elsif Z80N_command_s = DEC_DEHL then + -- reg_temp_t := std_logic_vector(unsigned(reg_temp_t) - 1); + -- + -- elsif Z80N_command_s = ADD_DEHL_A then + -- reg_temp_t := std_logic_vector(unsigned(reg_temp_t) + unsigned (ACC)); + -- + -- + -- elsif Z80N_command_s = SUB_DEHL_A then + -- reg_temp_t := std_logic_vector(unsigned(reg_temp_t) - unsigned (ACC)); + -- + -- + -- elsif Z80N_command_s = ADD_DEHL_BC then + -- reg_temp_t := std_logic_vector(unsigned(reg_temp_t) + unsigned (unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_c)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_c))))))); + -- + -- elsif Z80N_command_s = SUB_DEHL_BC then + -- reg_temp_t := std_logic_vector(unsigned(reg_temp_t) - unsigned (unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_c)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_c))))))); + -- + -- end if; + -- + -- + -- reg_direct_val_H_a <= reg_temp_t(31 downto 24); -- D + -- reg_direct_val_L_a <= reg_temp_t(23 downto 16); -- E + -- reg_direct_val_H_b <= reg_temp_t(15 downto 8); -- H + -- reg_direct_val_L_b <= reg_temp_t(7 downto 0); -- L + -- + -- reg_direct_H_a <= '1'; -- write D + -- reg_direct_L_a <= '1'; -- write E + -- reg_direct_H_b <= '1'; -- write H + -- reg_direct_L_b <= '1'; -- write L + + + -- when MIRROR_DE => + -- + -- + -- reg_temp_t(15 downto 0) := std_logic_vector(unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_a)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_a)))))); + -- + -- reg_direct_val_H_a <= reg_temp_t(0) & reg_temp_t(1) & reg_temp_t(2) & reg_temp_t(3) & reg_temp_t(4) & reg_temp_t(5) & reg_temp_t(6) & reg_temp_t(7); + -- reg_direct_val_L_a <= reg_temp_t(8) & reg_temp_t(9) & reg_temp_t(10) & reg_temp_t(11) & reg_temp_t(12) & reg_temp_t(13) & reg_temp_t(14) & reg_temp_t(15); + -- + -- reg_direct_H_a <= '1'; -- write D + -- reg_direct_L_a <= '1'; -- write E + -- + -- -- reg_temp_t(15 downto 0) := reg_DE_s; + -- -- reg_DE_temp_s <= reg_temp_t(0) & reg_temp_t(1) & reg_temp_t(2) & reg_temp_t(3) & reg_temp_t(4) & reg_temp_t(5) & reg_temp_t(6) & reg_temp_t(7) & reg_temp_t(8) & reg_temp_t(9) & reg_temp_t(10) & reg_temp_t(11) & reg_temp_t(12) & reg_temp_t(13) & reg_temp_t(14) & reg_temp_t(15); + -- -- reg_wr_s <= "000011"; -- write regs D E + + -- when LD_HL_SP => + -- + -- reg_temp_t(15 downto 0) := std_logic_vector(SP); + -- reg_direct_val_H_b <= reg_temp_t(15 downto 8); + -- reg_direct_val_L_b <= reg_temp_t(7 downto 0); + -- + -- reg_direct_H_b <= '1'; -- write H + -- reg_direct_L_b <= '1'; -- write L + -- + -- --reg_HL_temp_s <= std_logic_vector(SP); + -- --reg_wr_s <= "001100"; -- write regs H L + + + when PIXELDN => -- Garry's version + + reg_temp_t(31 downto 16) := std_logic_vector(unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_b)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_b)))))); + + reg_temp_t(7 downto 0) := std_logic_vector(unsigned( + unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_b)))(4 downto 3)) & + unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_b)))(7 downto 5)) & + unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_b)))(2 downto 0)) + ) + 1); + + -- H4H3 L7L6L5 H2H1H0 + 1 + + if TState = 4 then + + reg_direct_val_H_b <= reg_temp_t(31 downto 29) & reg_temp_t(7 downto 6) & reg_temp_t(2 downto 0); + reg_direct_val_L_b <= reg_temp_t(5 downto 3) & reg_temp_t(20 downto 16); + + reg_direct_H_b <= '1'; -- write H + reg_direct_L_b <= '1'; -- write L + + + end if; + + when SET_A_E => + + reg_direct_add_L_a <= Alternate & dDE; -- E + + reg_temp_t(7 downto 0) := std_logic_vector(unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_a))))); + + if reg_temp_t(2 downto 0) = "000" then ACC <= "10000000"; + elsif reg_temp_t(2 downto 0) = "001" then ACC <= "01000000"; + elsif reg_temp_t(2 downto 0) = "010" then ACC <= "00100000"; + elsif reg_temp_t(2 downto 0) = "011" then ACC <= "00010000"; + elsif reg_temp_t(2 downto 0) = "100" then ACC <= "00001000"; + elsif reg_temp_t(2 downto 0) = "101" then ACC <= "00000100"; + elsif reg_temp_t(2 downto 0) = "110" then ACC <= "00000010"; + elsif reg_temp_t(2 downto 0) = "111" then ACC <= "00000001"; + end if; + + when PIXELAD => + + reg_temp_t(15 downto 0) := std_logic_vector(unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_a)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_a)))))); + + reg_direct_val_H_b <= "010" & reg_temp_t(15 downto 14) & reg_temp_t(10 downto 8); + reg_direct_val_L_b <= reg_temp_t(13 downto 11) & reg_temp_t(7 downto 3); + + reg_direct_H_b <= '1'; -- write H + reg_direct_L_b <= '1'; -- write L + + + --reg_HL_temp_s(15 downto 8) <= "010" & reg_DE_s(15 downto 14) & reg_DE_s(10 downto 8); + --reg_HL_temp_s(7 downto 0) <= reg_DE_s(13 downto 11) & reg_DE_s(7 downto 3); + --reg_wr_s <= "001100"; -- write regs H L + + -- when PIXELTOATTR => + -- reg_temp_t(15 downto 0) := std_logic_vector(unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_b)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_b)))))); + -- + -- reg_direct_val_H_b <= "010110" & reg_temp_t(12 downto 11); + -- reg_direct_val_L_b <= reg_temp_t(7 downto 0); + -- + -- reg_direct_H_b <= '1'; -- write H + -- reg_direct_L_b <= '1'; -- write L + -- + -- -- reg_HL_temp_s <= "010110" & reg_HL_s(12 downto 11) & reg_HL_s(7 downto 0); + -- -- reg_wr_s <= "001100"; -- write regs H L + -- + -- when ATTRTOPIXEL => + -- + -- reg_temp_t(15 downto 0) := std_logic_vector(unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_b)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_b)))))); + -- + -- reg_direct_val_H_b <= "010" & reg_temp_t(9 downto 8) & "000"; + -- reg_direct_val_L_b <= reg_temp_t(7 downto 0); + -- + -- reg_direct_H_b <= '1'; -- write H + -- reg_direct_L_b <= '1'; -- write L + -- + -- -- reg_HL_temp_s <= "010" & reg_HL_s(9 downto 8) & "000" & reg_HL_s(7 downto 0); + -- -- reg_wr_s <= "001100"; -- write regs H L + + when JP_C => + if IORQ_i = '1' then + PC(13 downto 6) <= unsigned(DI_Reg); + PC(5 downto 0) <= "000000"; + end if; + + + + when BSLA_DE_B => + + reg_temp_t(15 downto 0) := RegsH(to_integer(unsigned(reg_direct_add_H_a))) + & RegsL(to_integer(unsigned(reg_direct_add_L_a))); + + reg_temp_t(15 downto 0) := std_logic_vector(shift_left(unsigned(reg_temp_t(15 downto 0)), + to_integer(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_c)))(4 downto 0))) )); + + reg_direct_val_H_a <= reg_temp_t(15 downto 8); + reg_direct_val_L_a <= reg_temp_t(7 downto 0); + + reg_direct_H_a <= '1'; -- write + reg_direct_L_a <= '1'; -- write + + when BSRA_DE_B | BSRL_DE_B | BSRF_DE_B => + + reg_temp_t(15 downto 0) := RegsH(to_integer(unsigned(reg_direct_add_H_a))) + & RegsL(to_integer(unsigned(reg_direct_add_L_a))); + + if IR(1) = '0' then -- BSRA 0x29 %00101001 + reg_temp_t(16) := reg_temp_t(15); + else + reg_temp_t(16) := IR(0); -- BSRL 0x2A %00101010 + -- BSRF 0x2B %00101011 + end if; + + reg_temp_t(16 downto 0) := std_logic_vector(shift_right(signed(reg_temp_t(16 downto 0)), + to_integer(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_c)))(4 downto 0))) )); + + reg_direct_val_H_a <= reg_temp_t(15 downto 8); + reg_direct_val_L_a <= reg_temp_t(7 downto 0); + + reg_direct_H_a <= '1'; -- write + reg_direct_L_a <= '1'; -- write + + when BRLC_DE_B => + + reg_temp_t(15 downto 0) := RegsH(to_integer(unsigned(reg_direct_add_H_a))) + & RegsL(to_integer(unsigned(reg_direct_add_L_a))); + + reg_temp_t(15 downto 0) := std_logic_vector(rotate_left(unsigned(reg_temp_t(15 downto 0)), + to_integer(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_c)))(4 downto 0))) )); + + reg_direct_val_H_a <= reg_temp_t(15 downto 8); + reg_direct_val_L_a <= reg_temp_t(7 downto 0); + + reg_direct_H_a <= '1'; -- write + reg_direct_L_a <= '1'; -- write + + when others => null; + + + end case; + end if; + + + + + --any Tstate + case Z80N_command_s is + + -- when ADD_DEHL_nn => + -- +-- +-- + -- reg_temp_t(31 downto 0) := std_logic_vector(unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_a)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_a))))) & + -- unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_b)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_b)))))); + -- + -- + -- if (MCycle = "011" and Tstate = 4)then + -- reg_temp_t := std_logic_vector(unsigned(reg_temp_t) + unsigned (TmpAddr)); + -- + -- reg_direct_val_H_a <= reg_temp_t(31 downto 24); -- D + -- reg_direct_val_L_a <= reg_temp_t(23 downto 16); -- E + -- reg_direct_val_H_b <= reg_temp_t(15 downto 8); -- H + -- reg_direct_val_L_b <= reg_temp_t(7 downto 0); -- L + -- + -- reg_direct_H_a <= '1'; -- write D + -- reg_direct_L_a <= '1'; -- write E + -- reg_direct_H_b <= '1'; -- write H + -- reg_direct_L_b <= '1'; -- write L + -- + -- --reg_DE_temp_s <= reg_temp_t(31 downto 16); + -- --reg_HL_temp_s <= reg_temp_t(15 downto 0); + -- --reg_wr_s <= "001111"; -- write regs H L D E + -- --else + -- --reg_wr_s <= (others=>'0'); + -- end if; + -- + when ADD_DE_nn => + + reg_temp_t(15 downto 0) := std_logic_vector(unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_a)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_a)))))); + + if (MCycle = "011" and Tstate = 4)then + reg_temp_t(15 downto 0) := std_logic_vector(unsigned(reg_temp_t(15 downto 0)) + unsigned (TmpAddr)); + + reg_direct_val_H_a <= reg_temp_t(15 downto 8); -- D + reg_direct_val_L_a <= reg_temp_t(7 downto 0); -- E + + reg_direct_H_a <= '1'; -- write D + reg_direct_L_a <= '1'; -- write E + end if; + + when ADD_BC_nn => + reg_direct_add_H_a <= Alternate & dBC; + reg_direct_add_L_a <= Alternate & dBC; + reg_temp_t(15 downto 0) := std_logic_vector(unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_a)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_a)))))); + + if (MCycle = "011" and Tstate = 4)then + reg_temp_t(15 downto 0) := std_logic_vector(unsigned(reg_temp_t(15 downto 0)) + unsigned (TmpAddr)); + + reg_direct_val_H_a <= reg_temp_t(15 downto 8); -- B + reg_direct_val_L_a <= reg_temp_t(7 downto 0); -- C + + reg_direct_H_a <= '1'; -- write B + reg_direct_L_a <= '1'; -- write C + end if; + + when ADD_HL_nn => + reg_temp_t(15 downto 0) := std_logic_vector(unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_b)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_b)))))); + + if (MCycle = "011" and Tstate = 4)then + reg_temp_t(15 downto 0) := std_logic_vector(unsigned(reg_temp_t(15 downto 0)) + unsigned (TmpAddr)); + + reg_direct_val_H_b <= reg_temp_t(15 downto 8); -- H + reg_direct_val_L_b <= reg_temp_t(7 downto 0); -- L + + reg_direct_H_b <= '1'; -- write H + reg_direct_L_b <= '1'; -- write L + end if; + + + when LDPIRX => + reg_temp_t(31 downto 0) := std_logic_vector(unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_a)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_a))))) & + unsigned(unsigned(RegsH(to_integer(unsigned(reg_direct_add_H_b)))) & unsigned(RegsL(to_integer(unsigned(reg_direct_add_L_b)))))); + + + if (MCycle = "001" and Tstate = 4) or (MCycle = "010" and Tstate = 1) then + A <= reg_temp_t(15 downto 3) & reg_temp_t(18 downto 16); + -- A <= reg_HL_s(15 downto 3) & reg_DE_s(2 downto 0); + + end if; + + if MCycle = "010" then -- MCycle 2 +-- A <= reg_DE_s; + A <= reg_temp_t(31 downto 16); + + end if; + + when LDIRSCALE => + + --read byte from ( reg_HL_s (15 downto 0)) + --if byte != A put byte in ( reg_DE_s(15 downto 0)) + --add BC' ( from exx ) to HL_A' and store in HL_A' + --DE <= DE + DE' + --loop BC + + if (MCycle = "010" and Tstate = 4) then -- M2 + --add BC' to HL_A' and store in HL_A' + -- reg_HL_temp_s <= std_logic_vector(unsigned(reg_HL_s) + unsigned(ACC)); + -- reg_wr_s <= "001100"; -- write regs H L + + end if; + + if (MCycle = "011" and Tstate = 4) then -- M3 + --DE <= DE + DE' + -- reg_DE_temp_s <= std_logic_vector(unsigned(reg_DE_s) + unsigned(ACC)); + -- reg_wr_s <= "000011"; -- write regs D E + + end if; + + when others => null; + + + end case; + + + + +--------------------------------------------------- + + + + + + + + + if TState = 3 then + + + + + + if LDZ = '1' then + TmpAddr(7 downto 0) <= DI_Reg; + end if; + if LDW = '1' then + TmpAddr(15 downto 8) <= DI_Reg; + end if; + + if Special_LD(2) = '1' then + case Special_LD(1 downto 0) is + when "00" => + ACC <= I; + F(Flag_N) <= '0'; + F(Flag_P) <= IntE_FF2; + F(Flag_H) <= '0'; + F(Flag_S) <= I(7); + + if I = x"00" then + F(Flag_Z) <= '1'; + else + F(Flag_Z) <= '0'; + end if; + + when "01" => + ACC <= std_logic_vector(R); + F(Flag_N) <= '0'; + F(Flag_P) <= IntE_FF2; + F(Flag_H) <= '0'; + F(Flag_S) <= R(7); + + if R = x"00" then + F(Flag_Z) <= '1'; + else + F(Flag_Z) <= '0'; + end if; + + when "10" => + I <= ACC; + when others => + R <= unsigned(ACC); + end case; + end if; + end if; + + if (I_DJNZ = '0' and Save_ALU_r = '1') or ALU_Op_r = "1001" then + if Mode = 3 then + F(6) <= F_Out(6); + F(5) <= F_Out(5); + F(7) <= F_Out(7); + if PreserveC_r = '0' then + F(4) <= F_Out(4); + end if; + else + F(7 downto 1) <= F_Out(7 downto 1); + if PreserveC_r = '0' then + F(Flag_C) <= F_Out(0); + end if; + end if; + end if; + if T_Res = '1' and I_INRC = '1' then + F(Flag_H) <= '0'; + F(Flag_N) <= '0'; + if DI_Reg(7 downto 0) = "00000000" then + F(Flag_Z) <= '1'; + else + F(Flag_Z) <= '0'; + end if; + F(Flag_S) <= DI_Reg(7); + F(Flag_P) <= not (DI_Reg(0) xor DI_Reg(1) xor DI_Reg(2) xor DI_Reg(3) xor + DI_Reg(4) xor DI_Reg(5) xor DI_Reg(6) xor DI_Reg(7)); + end if; + + if TState = 1 and Auto_Wait_t1 = '0' then + DO <= BusB; + if I_RLD = '1' then + DO(3 downto 0) <= BusA(3 downto 0); + DO(7 downto 4) <= BusB(3 downto 0); + end if; + if I_RRD = '1' then + DO(3 downto 0) <= BusB(7 downto 4); + DO(7 downto 4) <= BusA(3 downto 0); + end if; + end if; + + if T_Res = '1' then + Read_To_Reg_r(3 downto 0) <= Set_BusA_To; + Read_To_Reg_r(4) <= Read_To_Reg; + if Read_To_Acc = '1' then + Read_To_Reg_r(3 downto 0) <= "0111"; + Read_To_Reg_r(4) <= '1'; + end if; + end if; + + if TState = 1 and I_BT = '1' then + F(Flag_X) <= ALU_Q(3); + F(Flag_Y) <= ALU_Q(1); + F(Flag_H) <= '0'; + F(Flag_N) <= '0'; + end if; + if I_BC = '1' or I_BT = '1' then + F(Flag_P) <= IncDecZ; + end if; + + if (TState = 1 and Save_ALU_r = '0' and Auto_Wait_t1 = '0') or + (Save_ALU_r = '1' and ALU_OP_r /= "0111") then + case Read_To_Reg_r is + when "10111" => + ACC <= Save_Mux; + when "10110" => + DO <= Save_Mux; + when "11000" => + SP(7 downto 0) <= unsigned(Save_Mux); + when "11001" => + SP(15 downto 8) <= unsigned(Save_Mux); + when "11011" => + F <= Save_Mux; + when others => + end case; + if XYbit_undoc='1' then + DO <= ALU_Q; + end if; + end if; + + end if; + + end if; + + end process; + +--------------------------------------------------------------------------- + process (CLK_n) + begin + if CLK_n'event and CLK_n = '1' then + if ClkEn = '1' then + if Z80N_data_o_strobe_lo = '1' then + Z80N_data_o(7 downto 0) <= Z80N_data_s; + end if; + if Z80N_data_o_strobe_hi = '1' then + Z80N_data_o(15 downto 8) <= Z80N_data_s; + end if; + end if; + end if; + end process; +--------------------------------------------------------------------------- +-- +-- BC('), DE('), HL('), IX and IY +-- +--------------------------------------------------------------------------- + process (CLK_n) + begin + if CLK_n'event and CLK_n = '1' then + if ClkEn = '1' then + -- Bus A / Write + RegAddrA_r <= Alternate & Set_BusA_To(2 downto 1); + if XY_Ind = '0' and XY_State /= "00" and Set_BusA_To(2 downto 1) = "10" then + RegAddrA_r <= XY_State(1) & "11"; + end if; + + -- Bus B + RegAddrB_r <= Alternate & Set_BusB_To(2 downto 1); + if XY_Ind = '0' and XY_State /= "00" and Set_BusB_To(2 downto 1) = "10" then + RegAddrB_r <= XY_State(1) & "11"; + end if; + + -- Address from register + RegAddrC <= Alternate & Set_Addr_To(1 downto 0); + -- Jump (HL), LD SP,HL + if (JumpXY = '1' or LDSPHL = '1') then + RegAddrC <= Alternate & "10"; + end if; + if ((JumpXY = '1' or LDSPHL = '1') and XY_State /= "00") or (MCycle = "110") then + RegAddrC <= XY_State(1) & "11"; + end if; + + if I_DJNZ = '1' and Save_ALU_r = '1' and Mode < 2 then + IncDecZ <= F_Out(Flag_Z); + end if; + if (TState = 2 or (TState = 3 and MCycle = "001")) and IncDec_16(2 downto 0) = "100" then + if ID16 = 0 then + IncDecZ <= '0'; + else + IncDecZ <= '1'; + end if; + end if; + + RegBusA_r <= RegBusA; + end if; + end if; + end process; + + RegAddrA <= + -- 16 bit increment/decrement + XY_State(1) & "11" when (TState = 2 or + (TState = 3 and MCycle = "001" and IncDec_16(2) = '1')) and IncDec_16(1 downto 0) = "10" and XY_State /= "00" else + Alternate & IncDec_16(1 downto 0) when (TState = 2 or + (TState = 3 and MCycle = "001" and IncDec_16(2) = '1')) else + -- EX HL,DL + Alternate & "10" when ExchangeDH = '1' and TState = 3 else + Alternate & "01" when ExchangeDH = '1' and TState = 4 else + -- Bus A / Write + RegAddrA_r; + + RegAddrB <= + -- EX HL,DL + Alternate & "01" when ExchangeDH = '1' and TState = 3 else + -- Bus B + RegAddrB_r; + + ID16 <= signed(RegBusA) - 1 when IncDec_16(3) = '1' else + signed(RegBusA) + 1; + + process (Save_ALU_r, Auto_Wait_t1, ALU_OP_r, Read_To_Reg_r, + ExchangeDH, IncDec_16, MCycle, TState, WAIT_n) + begin + RegWEH <= '0'; + RegWEL <= '0'; + if (TState = 1 and Save_ALU_r = '0' and Auto_Wait_t1 = '0') or + (Save_ALU_r = '1' and ALU_OP_r /= "0111") then + case Read_To_Reg_r is + when "10000" | "10001" | "10010" | "10011" | "10100" | "10101" => + RegWEH <= not Read_To_Reg_r(0); + RegWEL <= Read_To_Reg_r(0); + when others => + end case; + end if; + + if ExchangeDH = '1' and (TState = 3 or TState = 4) then + RegWEH <= '1'; + RegWEL <= '1'; + end if; + + if IncDec_16(2) = '1' and ((TState = 2 and WAIT_n = '1' and MCycle /= "001") or (TState = 3 and MCycle = "001")) then + case IncDec_16(1 downto 0) is + when "00" | "01" | "10" => + RegWEH <= '1'; + RegWEL <= '1'; + when others => + end case; + end if; + end process; + + process (Save_Mux, RegBusB, RegBusA_r, ID16, + ExchangeDH, IncDec_16, MCycle, TState, WAIT_n) + begin + RegDIH <= Save_Mux; + RegDIL <= Save_Mux; + + if ExchangeDH = '1' and TState = 3 then + RegDIH <= RegBusB(15 downto 8); + RegDIL <= RegBusB(7 downto 0); + end if; + if ExchangeDH = '1' and TState = 4 then + RegDIH <= RegBusA_r(15 downto 8); + RegDIL <= RegBusA_r(7 downto 0); + end if; + + if IncDec_16(2) = '1' and ((TState = 2 and MCycle /= "001") or (TState = 3 and MCycle = "001")) then + RegDIH <= std_logic_vector(ID16(15 downto 8)); + RegDIL <= std_logic_vector(ID16(7 downto 0)); + end if; + end process; + + +-- REGS + +-- Regs : T80_Reg +-- port map( +-- Clk => CLK_n, +-- CEN => ClkEn, +-- WEH => RegWEH, +-- WEL => RegWEL, +-- AddrA => RegAddrA, +-- AddrB => RegAddrB, +-- AddrC => RegAddrC, +-- DIH => RegDIH, +-- DIL => RegDIL, +-- DOAH => RegBusA(15 downto 8), +-- DOAL => RegBusA(7 downto 0), +-- DOBH => RegBusB(15 downto 8), +-- DOBL => RegBusB(7 downto 0), +-- DOCH => RegBusC(15 downto 8), +-- DOCL => RegBusC(7 downto 0), +-- +-- --extended +-- reg_wr_i => reg_wr_s, +-- reg_BC_i => reg_BC_temp_s, +-- reg_HL_i => reg_HL_temp_s, +-- reg_DE_i => reg_DE_temp_s, +-- reg_BC_o => reg_BC_s, +-- reg_HL_o => reg_HL_s, +-- reg_DE_o => reg_DE_s +-- +-- ); + + + + process (CLK_n) + begin + if CLK_n'event and CLK_n = '1' then + if ResET_n = '0' then + + + elsif ClkEn = '1' then + + if RegWEH = '1' then + RegsH(to_integer(unsigned(RegAddrA))) <= RegDIH; + end if; + + if RegWEL = '1' then + RegsL(to_integer(unsigned(RegAddrA))) <= RegDIL; + end if; + + if reg_direct_H_a = '1' then + RegsH(to_integer(unsigned(reg_direct_add_H_a))) <= reg_direct_val_H_a; + end if; + + if reg_direct_L_a = '1' then + RegsL(to_integer(unsigned(reg_direct_add_L_a))) <= reg_direct_val_L_a; + end if; + + if reg_direct_H_b = '1' then + RegsH(to_integer(unsigned(reg_direct_add_H_b))) <= reg_direct_val_H_b; + end if; + + if reg_direct_L_b = '1' then + RegsL(to_integer(unsigned(reg_direct_add_L_b))) <= reg_direct_val_L_b; + end if; + + end if; + + end if; + end process; + + RegBusA(15 downto 8) <= RegsH(to_integer(unsigned(RegAddrA))); + RegBusA(7 downto 0) <= RegsL(to_integer(unsigned(RegAddrA))); + RegBusB(15 downto 8) <= RegsH(to_integer(unsigned(RegAddrB))); + RegBusB(7 downto 0) <= RegsL(to_integer(unsigned(RegAddrB))); + RegBusC(15 downto 8) <= RegsH(to_integer(unsigned(RegAddrC))); + RegBusC(7 downto 0) <= RegsL(to_integer(unsigned(RegAddrC))); + + + + + + + + + + + + + + +--------------------------------------------------------------------------- +-- +-- Buses +-- +--------------------------------------------------------------------------- + process (CLK_n) + begin + if CLK_n'event and CLK_n = '1' then + if ClkEn = '1' then + case Set_BusB_To is + when "0111" => + BusB <= ACC; + when "0000" | "0001" | "0010" | "0011" | "0100" | "0101" => + if Set_BusB_To(0) = '1' then + BusB <= RegBusB(7 downto 0); + else + BusB <= RegBusB(15 downto 8); + end if; + when "0110" => + BusB <= DI_Reg; + when "1000" => + BusB <= std_logic_vector(SP(7 downto 0)); + when "1001" => + BusB <= std_logic_vector(SP(15 downto 8)); + when "1010" => + BusB <= "00000001"; + when "1011" => + BusB <= F; + when "1100" => + BusB <= std_logic_vector(PC(7 downto 0)); + when "1101" => + BusB <= std_logic_vector(PC(15 downto 8)); + when "1110" => + BusB <= "00000000"; + when others => + BusB <= "--------"; + end case; + + case Set_BusA_To is + when "0111" => + BusA <= ACC; + when "0000" | "0001" | "0010" | "0011" | "0100" | "0101" => + if Set_BusA_To(0) = '1' then + BusA <= RegBusA(7 downto 0); + else + BusA <= RegBusA(15 downto 8); + end if; + when "0110" => + BusA <= DI_Reg; + when "1000" => + BusA <= std_logic_vector(SP(7 downto 0)); + when "1001" => + BusA <= std_logic_vector(SP(15 downto 8)); + when "1010" => + BusA <= "00000000"; + when others => + BusB <= "--------"; + end case; + if XYbit_undoc='1' then + BusA <= DI_Reg; + BusB <= DI_Reg; + end if; + end if; + end if; + end process; + +--------------------------------------------------------------------------- +-- +-- Generate external control signals +-- +--------------------------------------------------------------------------- + process (RESET_n,CLK_n) + begin + if CLK_n'event and CLK_n = '1' then + if RESET_n = '0' then + RFSH_n <= '1'; + + elsif CEN = '1' then + if MCycle = "001" and ((TState = 2 and WAIT_n = '1') or TState = 3) then + RFSH_n <= '0'; + else + RFSH_n <= '1'; + end if; + end if; + end if; + end process; + + MC <= std_logic_vector(MCycle); + TS <= std_logic_vector(TState); + DI_Reg <= DI; + HALT_n <= not Halt_FF; + BUSAK_n <= not BusAck; + IntCycle_n <= not IntCycle; + IntE <= IntE_FF1; + IORQ <= IORQ_i; + Stop <= I_DJNZ; + +------------------------------------------------------------------------- +-- +-- Syncronise inputs +-- +------------------------------------------------------------------------- + process (RESET_n, CLK_n) + variable OldNMI_n : std_logic; + begin + if CLK_n'event and CLK_n = '1' then + + if RESET_n = '0' then + BusReq_s <= '0'; + INT_s <= '0'; + NMI_s <= '0'; + OldNMI_n := '0'; + + elsif CEN = '1' then + BusReq_s <= not BUSRQ_n; + INT_s <= not INT_n; + if NMICycle = '1' then + NMI_s <= '0'; + elsif NMI_n = '0' and OldNMI_n = '1' then + NMI_s <= '1'; + end if; + OldNMI_n := NMI_n; + end if; + + end if; + end process; + +------------------------------------------------------------------------- +-- +-- Main state machine +-- +------------------------------------------------------------------------- + process (RESET_n, CLK_n) + begin + + if CLK_n'event and CLK_n = '1' then + if RESET_n = '0' then + MCycle <= "001"; + TState <= "000"; + Pre_XY_F_M <= "000"; + Halt_FF <= '0'; + BusAck <= '0'; + NMICycle <= '0'; + IntCycle <= '0'; + IntE_FF1 <= '0'; + IntE_FF2 <= '0'; + No_BTR <= '0'; + Auto_Wait_t1 <= '0'; + Auto_Wait_t2 <= '0'; + M1_n <= '1'; + + elsif CEN = '1' then + if T_Res = '1' then + Auto_Wait_t1 <= '0'; + else + Auto_Wait_t1 <= Auto_Wait or IORQ_i; + end if; + Auto_Wait_t2 <= Auto_Wait_t1; + No_BTR <= (I_BT and (not IR(4) or not F(Flag_P))) or + (I_BC and (not IR(4) or F(Flag_Z) or not F(Flag_P))) or + (I_BTR and (not IR(4) or F(Flag_Z))); + if TState = 2 then + if SetEI = '1' then + IntE_FF1 <= '1'; + IntE_FF2 <= '1'; + end if; + if I_RETN = '1' then + IntE_FF1 <= IntE_FF2; + end if; + end if; + if TState = 3 then + if SetDI = '1' then + IntE_FF1 <= '0'; + IntE_FF2 <= '0'; + end if; + end if; + if IntCycle = '1' or NMICycle = '1' then + Halt_FF <= '0'; + end if; + if MCycle = "001" and TState = "010" and WAIT_n = '1' then -- 30/10/19 Charlie Ingley - Fixed M1_n (always finishes at end of T2) + M1_n <= '1'; + end if; +-- if MCycle = "001" and TState = 2 and WAIT_n = '1' and IntCycle = '0' then -- by Fabio Belavenuto: Fix IRQ Acnowledgment timing +-- M1_n <= '1'; +-- end if; +-- if MCycle = "001" and TState = 3 and WAIT_n = '1' and IntCycle = '1' then -- by Fabio Belavenuto: Fix IRQ Acnowledgment timing +-- M1_n <= '1'; +-- end if; + if BusReq_s = '1' and BusAck = '1' then + else + BusAck <= '0'; + if TState = 2 and WAIT_n = '0' then + elsif T_Res = '1' then + if Halt = '1' then + Halt_FF <= '1'; + end if; + if BusReq_s = '1' then + BusAck <= '1'; + else + TState <= "001"; + + if NextIs_XY_Fetch = '1' then + MCycle <= "110"; + Pre_XY_F_M <= MCycle; + if IR = "00110110" and Mode = 0 then + Pre_XY_F_M <= "010"; + end if; + elsif (MCycle = MCycles) or + No_BTR = '1' or + (MCycle = "010" and I_DJNZ = '1' and IncDecZ = '1') or + ( MCycle = "111" and MCycles= "001" and Pre_XY_F_M = "001" ) then + M1_n <= '0'; + MCycle <= "001"; + IntCycle <= '0'; + NMICycle <= '0'; + if NMI_s = '1' and Prefix = "00" then + NMICycle <= '1'; + IntE_FF1 <= '0'; + elsif (IntE_FF1 = '1' and INT_s = '1') and Prefix = "00" and SetEI = '0' then + IntCycle <= '1'; + IntE_FF1 <= '0'; + IntE_FF2 <= '0'; + end if; + elsif (MCycle = "111") or + (MCycle = "110" and Mode = 1 and ISet /= "01") then + MCycle <= std_logic_vector(unsigned(Pre_XY_F_M) + 1); + else + MCycle <= std_logic_vector(unsigned(MCycle) + 1); + end if; + end if; + else + if (Auto_Wait = '1' and Auto_Wait_t2 = '0') nor + (IOWait = 1 and IORQ_i = '1' and Auto_Wait_t1 = '0') then + TState <= TState + 1; + end if; + end if; + end if; + if TState = 0 then + M1_n <= '0'; + end if; + end if; + end if; + end process; + + process (IntCycle, NMICycle, MCycle) + begin + Auto_Wait <= '0'; + if IntCycle = '1' or NMICycle = '1' then + if MCycle = "001" then + Auto_Wait <= '1'; + end if; + end if; + end process; + +end; diff --git a/rtl/cpu/t80n_alu.vhd b/rtl/cpu/t80n_alu.vhd new file mode 100644 index 0000000..f9d3d8a --- /dev/null +++ b/rtl/cpu/t80n_alu.vhd @@ -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 +-- +-- +-- 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; diff --git a/rtl/cpu/t80n_mcode.vhd b/rtl/cpu/t80n_mcode.vhd new file mode 100644 index 0000000..f94f2a2 --- /dev/null +++ b/rtl/cpu/t80n_mcode.vhd @@ -0,0 +1,2610 @@ +-- +-- 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 : +-- +-- 0208 : First complete release +-- +-- 0211 : Fixed IM 1 +-- +-- 0214 : Fixed mostly flags, only the block instructions now fail the zex regression test +-- +-- 0235 : Added IM 2 fix by Mike Johnson +-- +-- 0238 : Added NoRead signal +-- +-- 0238b: Fixed instruction timing for POP and DJNZ +-- +-- 0240 : Added (IX/IY+d) states, removed op-codes from mode 2 and added all remaining mode 3 op-codes +-- +-- 0242 : Fixed I/O instruction timing, cleanup +-- + +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 T80N_MCode 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( + 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; + + -- extended 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 T80N_MCode; + +architecture rtl of T80N_MCode is + + constant aNone : std_logic_vector(2 downto 0) := "111"; + constant aBC : std_logic_vector(2 downto 0) := "000"; + constant aDE : std_logic_vector(2 downto 0) := "001"; + constant aXY : std_logic_vector(2 downto 0) := "010"; + constant aIOA : std_logic_vector(2 downto 0) := "100"; + constant aSP : std_logic_vector(2 downto 0) := "101"; + constant aZI : std_logic_vector(2 downto 0) := "110"; +-- constant aNone : std_logic_vector(2 downto 0) := "000"; +-- constant aXY : std_logic_vector(2 downto 0) := "001"; +-- constant aIOA : std_logic_vector(2 downto 0) := "010"; +-- constant aSP : std_logic_vector(2 downto 0) := "011"; +-- constant aBC : std_logic_vector(2 downto 0) := "100"; +-- constant aDE : std_logic_vector(2 downto 0) := "101"; +-- constant aZI : std_logic_vector(2 downto 0) := "110"; + +-- signal Z80N_data_s : std_logic_vector(15 downto 0) := (others=>'1'); + + function is_cc_true( + F : std_logic_vector(7 downto 0); + cc : bit_vector(2 downto 0) + ) return boolean is + begin + if Mode = 3 then + case cc is + when "000" => return F(7) = '0'; -- NZ + when "001" => return F(7) = '1'; -- Z + when "010" => return F(4) = '0'; -- NC + when "011" => return F(4) = '1'; -- C + when "100" => return false; + when "101" => return false; + when "110" => return false; + when "111" => return false; + end case; + else + case cc is + when "000" => return F(6) = '0'; -- NZ + when "001" => return F(6) = '1'; -- Z + when "010" => return F(0) = '0'; -- NC + when "011" => return F(0) = '1'; -- C + when "100" => return F(2) = '0'; -- PO + when "101" => return F(2) = '1'; -- PE + when "110" => return F(7) = '0'; -- P + when "111" => return F(7) = '1'; -- M + end case; + end if; + end; + +begin + + --Z80N_data_o <= Z80N_data_s; + + process (IR, ISet, MCycle, F, NMICycle, IntCycle, ext_Data_i, ext_ACC_i, XY_State) + variable DDD : std_logic_vector(2 downto 0); + variable SSS : std_logic_vector(2 downto 0); + variable DPair : std_logic_vector(1 downto 0); + variable IRB : bit_vector(7 downto 0); + begin + DDD := IR(5 downto 3); + SSS := IR(2 downto 0); + DPair := IR(5 downto 4); + IRB := to_bitvector(IR); + + MCycles <= "001"; + if MCycle = "001" then + TStates <= "100"; + else + TStates <= "011"; + end if; + Z80N_command_o <= NONE; + Z80N_data_o <= (others=>'0'); + Z80N_dout_o <= '0'; + Z80N_data_o_strobe_lo <= '0'; + Z80N_data_o_strobe_hi <= '0'; + Prefix <= "00"; + Inc_PC <= '0'; + Inc_WZ <= '0'; + IncDec_16 <= "0000"; + Read_To_Acc <= '0'; + Read_To_Reg <= '0'; + Set_BusB_To <= "0000"; + Set_BusA_To <= "0000"; + ALU_Op <= "0" & IR(5 downto 3); + Save_ALU <= '0'; + PreserveC <= '0'; + Arith16 <= '0'; + IORQ <= '0'; + Set_Addr_To <= aNone; + Jump <= '0'; + JumpE <= '0'; + JumpXY <= '0'; + Call <= '0'; + RstP <= '0'; + LDZ <= '0'; + LDW <= '0'; + LDSPHL <= '0'; + Special_LD <= "000"; + ExchangeDH <= '0'; + ExchangeRp <= '0'; + ExchangeAF <= '0'; + ExchangeRS <= '0'; + I_DJNZ <= '0'; + I_CPL <= '0'; + I_CCF <= '0'; + I_SCF <= '0'; + I_RETN <= '0'; + I_BT <= '0'; + I_BC <= '0'; + I_BTR <= '0'; + I_RLD <= '0'; + I_RRD <= '0'; + I_INRC <= '0'; + SetDI <= '0'; + SetEI <= '0'; + IMode <= "11"; + Halt <= '0'; + NoRead <= '0'; + Write <= '0'; + XYbit_undoc <= '0'; + + case ISet is + when "00" => + +------------------------------------------------------------------------------ +-- +-- Unprefixed instructions +-- +------------------------------------------------------------------------------ + + case IRB is +-- 8 BIT LOAD GROUP + when "01000000"|"01000001"|"01000010"|"01000011"|"01000100"|"01000101"|"01000111" + |"01001000"|"01001001"|"01001010"|"01001011"|"01001100"|"01001101"|"01001111" + |"01010000"|"01010001"|"01010010"|"01010011"|"01010100"|"01010101"|"01010111" + |"01011000"|"01011001"|"01011010"|"01011011"|"01011100"|"01011101"|"01011111" + |"01100000"|"01100001"|"01100010"|"01100011"|"01100100"|"01100101"|"01100111" + |"01101000"|"01101001"|"01101010"|"01101011"|"01101100"|"01101101"|"01101111" + |"01111000"|"01111001"|"01111010"|"01111011"|"01111100"|"01111101"|"01111111" => + -- LD r,r' + Set_BusB_To(2 downto 0) <= SSS; + ExchangeRp <= '1'; + Set_BusA_To(2 downto 0) <= DDD; + Read_To_Reg <= '1'; + when "00000110"|"00001110"|"00010110"|"00011110"|"00100110"|"00101110"|"00111110" => + -- LD r,n + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + Set_BusA_To(2 downto 0) <= DDD; + Read_To_Reg <= '1'; + when others => null; + end case; + when "01000110"|"01001110"|"01010110"|"01011110"|"01100110"|"01101110"|"01111110" => + -- LD r,(HL) + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + when 2 => + Set_BusA_To(2 downto 0) <= DDD; + Read_To_Reg <= '1'; + when others => null; + end case; + when "01110000"|"01110001"|"01110010"|"01110011"|"01110100"|"01110101"|"01110111" => + -- LD (HL),r + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + Set_BusB_To(2 downto 0) <= SSS; + Set_BusB_To(3) <= '0'; + when 2 => + Write <= '1'; + when others => null; + end case; + when "00110110" => + -- LD (HL),n + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + Set_Addr_To <= aXY; + Set_BusB_To(2 downto 0) <= SSS; + Set_BusB_To(3) <= '0'; + when 3 => + Write <= '1'; + when others => null; + end case; + when "00001010" => + -- LD A,(BC) + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aBC; + when 2 => + Read_To_Acc <= '1'; + when others => null; + end case; + when "00011010" => + -- LD A,(DE) + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aDE; + when 2 => + Read_To_Acc <= '1'; + when others => null; + end case; + when "00111010" => + if Mode = 3 then + -- LDD A,(HL) + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + when 2 => + Read_To_Acc <= '1'; + IncDec_16 <= "1110"; + when others => null; + end case; + else + -- LD A,(nn) + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + when 4 => + Read_To_Acc <= '1'; + when others => null; + end case; + end if; + when "00000010" => + -- LD (BC),A + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aBC; + Set_BusB_To <= "0111"; + when 2 => + Write <= '1'; + when others => null; + end case; + when "00010010" => + -- LD (DE),A + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aDE; + Set_BusB_To <= "0111"; + when 2 => + Write <= '1'; + when others => null; + end case; + when "00110010" => + if Mode = 3 then + -- LDD (HL),A + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + Set_BusB_To <= "0111"; + when 2 => + Write <= '1'; + IncDec_16 <= "1110"; + when others => null; + end case; + else + -- LD (nn),A + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + Set_BusB_To <= "0111"; + when 4 => + Write <= '1'; + when others => null; + end case; + end if; + +-- 16 BIT LOAD GROUP + when "00000001"|"00010001"|"00100001"|"00110001" => + -- LD dd,nn + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + Read_To_Reg <= '1'; + if DPAIR = "11" then + Set_BusA_To(3 downto 0) <= "1000"; + else + Set_BusA_To(2 downto 1) <= DPAIR; + Set_BusA_To(0) <= '1'; + end if; + when 3 => + Inc_PC <= '1'; + Read_To_Reg <= '1'; + if DPAIR = "11" then + Set_BusA_To(3 downto 0) <= "1001"; + else + Set_BusA_To(2 downto 1) <= DPAIR; + Set_BusA_To(0) <= '0'; + end if; + when others => null; + end case; + when "00101010" => --2A + if Mode = 3 then + -- LDI A,(HL) + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + when 2 => + Read_To_Acc <= '1'; + IncDec_16 <= "0110"; + when others => null; + end case; + else + -- LD HL,(nn) + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + LDW <= '1'; + when 4 => + Set_BusA_To(2 downto 0) <= "101"; -- L + Read_To_Reg <= '1'; + Inc_WZ <= '1'; + Set_Addr_To <= aZI; + when 5 => + Set_BusA_To(2 downto 0) <= "100"; -- H + Read_To_Reg <= '1'; + when others => null; + end case; + end if; + when "00100010" => + if Mode = 3 then + -- LDI (HL),A + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + Set_BusB_To <= "0111"; + when 2 => + Write <= '1'; + IncDec_16 <= "0110"; + when others => null; + end case; + else + -- LD (nn),HL + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + LDW <= '1'; + Set_BusB_To <= "0101"; -- L + when 4 => + Inc_WZ <= '1'; + Set_Addr_To <= aZI; + Write <= '1'; + Set_BusB_To <= "0100"; -- H + when 5 => + Write <= '1'; + when others => null; + end case; + end if; + when "11111001" => + -- LD SP,HL + TStates <= "110"; + LDSPHL <= '1'; + when "11000101"|"11010101"|"11100101"|"11110101" => + -- PUSH qq + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + TStates <= "101"; + IncDec_16 <= "1111"; + Set_Addr_TO <= aSP; + if DPAIR = "11" then + Set_BusB_To <= "0111"; + else + Set_BusB_To(2 downto 1) <= DPAIR; + Set_BusB_To(0) <= '0'; + Set_BusB_To(3) <= '0'; + end if; + when 2 => + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + if DPAIR = "11" then + Set_BusB_To <= "1011"; + else + Set_BusB_To(2 downto 1) <= DPAIR; + Set_BusB_To(0) <= '1'; + Set_BusB_To(3) <= '0'; + end if; + Write <= '1'; + when 3 => + Write <= '1'; + when others => null; + end case; + when "11000001"|"11010001"|"11100001"|"11110001" => + -- POP qq + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aSP; + when 2 => + IncDec_16 <= "0111"; + Set_Addr_To <= aSP; + Read_To_Reg <= '1'; + if DPAIR = "11" then + Set_BusA_To(3 downto 0) <= "1011"; + else + Set_BusA_To(2 downto 1) <= DPAIR; + Set_BusA_To(0) <= '1'; + end if; + when 3 => + IncDec_16 <= "0111"; + Read_To_Reg <= '1'; + if DPAIR = "11" then + Set_BusA_To(3 downto 0) <= "0111"; + else + Set_BusA_To(2 downto 1) <= DPAIR; + Set_BusA_To(0) <= '0'; + end if; + when others => null; + end case; + +-- EXCHANGE, BLOCK TRANSFER AND SEARCH GROUP + when "11101011" => + if Mode /= 3 then + -- EX DE,HL + ExchangeDH <= '1'; + end if; + when "00001000" => + if Mode = 3 then + -- LD (nn),SP + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + LDW <= '1'; + Set_BusB_To <= "1000"; + when 4 => + Inc_WZ <= '1'; + Set_Addr_To <= aZI; + Write <= '1'; + Set_BusB_To <= "1001"; + when 5 => + Write <= '1'; + when others => null; + end case; + elsif Mode < 2 then + -- EX AF,AF' + ExchangeAF <= '1'; + end if; + when "11011001" => + if Mode = 3 then + -- RETI + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_TO <= aSP; + when 2 => + IncDec_16 <= "0111"; + Set_Addr_To <= aSP; + LDZ <= '1'; + when 3 => + Jump <= '1'; + IncDec_16 <= "0111"; + I_RETN <= '1'; + SetEI <= '1'; + when others => null; + end case; + elsif Mode < 2 then + -- EXX + ExchangeRS <= '1'; + end if; + when "11100011" => + if Mode /= 3 then + -- EX (SP),HL + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aSP; + when 2 => + Read_To_Reg <= '1'; + Set_BusA_To <= "0101"; + Set_BusB_To <= "0101"; + Set_Addr_To <= aSP; + when 3 => + IncDec_16 <= "0111"; + Set_Addr_To <= aSP; + TStates <= "100"; + Write <= '1'; + when 4 => + Read_To_Reg <= '1'; + Set_BusA_To <= "0100"; + Set_BusB_To <= "0100"; + Set_Addr_To <= aSP; + when 5 => + IncDec_16 <= "1111"; + TStates <= "101"; + Write <= '1'; + when others => null; + end case; + end if; + +-- 8 BIT ARITHMETIC AND LOGICAL GROUP + when "10000000"|"10000001"|"10000010"|"10000011"|"10000100"|"10000101"|"10000111" + |"10001000"|"10001001"|"10001010"|"10001011"|"10001100"|"10001101"|"10001111" + |"10010000"|"10010001"|"10010010"|"10010011"|"10010100"|"10010101"|"10010111" + |"10011000"|"10011001"|"10011010"|"10011011"|"10011100"|"10011101"|"10011111" + |"10100000"|"10100001"|"10100010"|"10100011"|"10100100"|"10100101"|"10100111" + |"10101000"|"10101001"|"10101010"|"10101011"|"10101100"|"10101101"|"10101111" + |"10110000"|"10110001"|"10110010"|"10110011"|"10110100"|"10110101"|"10110111" + |"10111000"|"10111001"|"10111010"|"10111011"|"10111100"|"10111101"|"10111111" => + -- ADD A,r + -- ADC A,r + -- SUB A,r + -- SBC A,r + -- AND A,r + -- OR A,r + -- XOR A,r + -- CP A,r + Set_BusB_To(2 downto 0) <= SSS; + Set_BusA_To(2 downto 0) <= "111"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + when "10000110"|"10001110"|"10010110"|"10011110"|"10100110"|"10101110"|"10110110"|"10111110" => + -- ADD A,(HL) + -- ADC A,(HL) + -- SUB A,(HL) + -- SBC A,(HL) + -- AND A,(HL) + -- OR A,(HL) + -- XOR A,(HL) + -- CP A,(HL) + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + when 2 => + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_BusB_To(2 downto 0) <= SSS; + Set_BusA_To(2 downto 0) <= "111"; + when others => null; + end case; + when "11000110"|"11001110"|"11010110"|"11011110"|X"E6"|"11101110"|"11110110"|"11111110" => + -- ADD A,n + -- ADC A,n + -- SUB A,n + -- SBC A,n + -- AND A,n (0xE6) + -- OR A,n + -- XOR A,n + -- CP A,n + MCycles <= "010"; + if MCycle = "010" then + Inc_PC <= '1'; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_BusB_To(2 downto 0) <= SSS; + Set_BusA_To(2 downto 0) <= "111"; + end if; + + when "00000100"|"00001100"|"00010100"|"00011100"|"00100100"|"00101100"|"00111100" => + + -- INC r + Set_BusB_To <= "1010"; + Set_BusA_To(2 downto 0) <= DDD; -- DDD is IR(5 downto 3); + Read_To_Reg <= '1'; + Save_ALU <= '1'; + PreserveC <= '1'; + ALU_Op <= "0000"; + when "00110100" => + -- INC (HL) + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + when 2 => + TStates <= "100"; + Set_Addr_To <= aXY; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + PreserveC <= '1'; + ALU_Op <= "0000"; + Set_BusB_To <= "1010"; + Set_BusA_To(2 downto 0) <= DDD; + when 3 => + Write <= '1'; + when others => null; + end case; + when "00000101"|"00001101"|"00010101"|"00011101"|"00100101"|"00101101"|"00111101" => + -- DEC r + Set_BusB_To <= "1010"; + Set_BusA_To(2 downto 0) <= DDD; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + PreserveC <= '1'; + ALU_Op <= "0010"; + when "00110101" => + -- DEC (HL) + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + when 2 => + TStates <= "100"; + Set_Addr_To <= aXY; + ALU_Op <= "0010"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + PreserveC <= '1'; + Set_BusB_To <= "1010"; + Set_BusA_To(2 downto 0) <= DDD; + when 3 => + Write <= '1'; + when others => null; + end case; + +-- GENERAL PURPOSE ARITHMETIC AND CPU CONTROL GROUPS + when "00100111" => + -- DAA + Set_BusA_To(2 downto 0) <= "111"; + Read_To_Reg <= '1'; + ALU_Op <= "1100"; + Save_ALU <= '1'; + when "00101111" => + -- CPL + I_CPL <= '1'; + when "00111111" => + -- CCF + I_CCF <= '1'; + when "00110111" => + -- SCF + I_SCF <= '1'; + when "00000000" => + if NMICycle = '1' then + -- NMI + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + TStates <= "101"; + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + Set_BusB_To <= "1101"; + when 2 => + --TStates <= "100"; + Write <= '1'; + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + Set_BusB_To <= "1100"; + Z80N_command_o <= NMIACK_MSB; + when 3 => + --TStates <= "100"; + Write <= '1'; + Z80N_command_o <= NMIACK_LSB; + when others => null; + end case; + elsif IntCycle = '1' then + -- INT (IM 2) + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 1 => + LDZ <= '1'; + TStates <= "101"; + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + Set_BusB_To <= "1101"; + when 2 => + --TStates <= "100"; + Write <= '1'; + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + Set_BusB_To <= "1100"; + when 3 => + --TStates <= "100"; + Write <= '1'; + when 4 => + Inc_PC <= '1'; + LDZ <= '1'; + when 5 => + Jump <= '1'; + when others => null; + end case; + else + -- NOP + end if; + when "01110110" => + -- HALT + Halt <= '1'; + when "11110011" => + -- DI + SetDI <= '1'; + when "11111011" => + -- EI + SetEI <= '1'; + +-- 16 BIT ARITHMETIC GROUP + when "00001001"|"00011001"|"00101001"|"00111001" => + -- ADD HL,ss + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + NoRead <= '1'; + ALU_Op <= "0000"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_BusA_To(2 downto 0) <= "101"; + case to_integer(unsigned(IR(5 downto 4))) is + when 0|1|2 => + Set_BusB_To(2 downto 1) <= IR(5 downto 4); + Set_BusB_To(0) <= '1'; + when others => + Set_BusB_To <= "1000"; + end case; + TStates <= "100"; + Arith16 <= '1'; + when 3 => + NoRead <= '1'; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + ALU_Op <= "0001"; + Set_BusA_To(2 downto 0) <= "100"; + case to_integer(unsigned(IR(5 downto 4))) is + when 0|1|2 => + Set_BusB_To(2 downto 1) <= IR(5 downto 4); + when others => + Set_BusB_To <= "1001"; + end case; + Arith16 <= '1'; + when others => + end case; + when "00000011"|"00010011"|"00100011"|"00110011" => + -- INC ss + TStates <= "110"; + IncDec_16(3 downto 2) <= "01"; + IncDec_16(1 downto 0) <= DPair; + when "00001011"|"00011011"|"00101011"|"00111011" => + -- DEC ss + TStates <= "110"; + IncDec_16(3 downto 2) <= "11"; + IncDec_16(1 downto 0) <= DPair; + +-- ROTATE AND SHIFT GROUP + when "00000111" + -- RLCA + |"00010111" + -- RLA + |"00001111" + -- RRCA + |"00011111" => + -- RRA + Set_BusA_To(2 downto 0) <= "111"; + ALU_Op <= "1000"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + +-- JUMP GROUP + when "11000011" => + -- JP nn + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Inc_PC <= '1'; + Jump <= '1'; + when others => null; + end case; + when "11000010"|"11001010"|"11010010"|"11011010"|"11100010"|"11101010"|"11110010"|"11111010" => + if IR(5) = '1' and Mode = 3 then + case IRB(4 downto 3) is + when "00" => + -- LD ($FF00+C),A + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aBC; + Set_BusB_To <= "0111"; + when 2 => + Write <= '1'; + IORQ <= '1'; + when others => + end case; + when "01" => + -- LD (nn),A + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + Set_BusB_To <= "0111"; + when 4 => + Write <= '1'; + when others => null; + end case; + when "10" => + -- LD A,($FF00+C) + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aBC; + when 2 => + Read_To_Acc <= '1'; + IORQ <= '1'; + when others => + end case; + when "11" => + -- LD A,(nn) + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + when 4 => + Read_To_Acc <= '1'; + when others => null; + end case; + end case; + else + -- JP cc,nn + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Inc_PC <= '1'; + if is_cc_true(F, to_bitvector(IR(5 downto 3))) then + Jump <= '1'; + end if; + when others => null; + end case; + end if; + when "00011000" => + if Mode /= 2 then + -- JR e + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + when 3 => + NoRead <= '1'; + JumpE <= '1'; + TStates <= "101"; + when others => null; + end case; + end if; + when "00111000" => + if Mode /= 2 then + -- JR C,e + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + if F(Flag_C) = '0' then + MCycles <= "010"; + end if; + when 3 => + NoRead <= '1'; + JumpE <= '1'; + TStates <= "101"; + when others => null; + end case; + end if; + when "00110000" => + if Mode /= 2 then + -- JR NC,e + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + if F(Flag_C) = '1' then + MCycles <= "010"; + end if; + when 3 => + NoRead <= '1'; + JumpE <= '1'; + TStates <= "101"; + when others => null; + end case; + end if; + when "00101000" => + if Mode /= 2 then + -- JR Z,e + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + if F(Flag_Z) = '0' then + MCycles <= "010"; + end if; + when 3 => + NoRead <= '1'; + JumpE <= '1'; + TStates <= "101"; + when others => null; + end case; + end if; + when "00100000" => + if Mode /= 2 then + -- JR NZ,e + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + if F(Flag_Z) = '1' then + MCycles <= "010"; + end if; + when 3 => + NoRead <= '1'; + JumpE <= '1'; + TStates <= "101"; + when others => null; + end case; + end if; + when "11101001" => + -- JP (HL) + JumpXY <= '1'; + when "00010000" => + if Mode = 3 then + I_DJNZ <= '1'; + elsif Mode < 2 then + -- DJNZ,e + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + TStates <= "101"; + I_DJNZ <= '1'; + Set_BusB_To <= "1010"; + Set_BusA_To(2 downto 0) <= "000"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + ALU_Op <= "0010"; + when 2 => + I_DJNZ <= '1'; + Inc_PC <= '1'; + when 3 => + NoRead <= '1'; + JumpE <= '1'; + TStates <= "101"; + when others => null; + end case; + end if; + +-- CALL AND RETURN GROUP + when "11001101" => + -- CALL nn + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + IncDec_16 <= "1111"; + Inc_PC <= '1'; + TStates <= "100"; + Set_Addr_To <= aSP; + LDW <= '1'; + Set_BusB_To <= "1101"; + when 4 => + Write <= '1'; + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + Set_BusB_To <= "1100"; + when 5 => + Write <= '1'; + Call <= '1'; + when others => null; + end case; + when "11000100"|"11001100"|"11010100"|"11011100"|"11100100"|"11101100"|"11110100"|"11111100" => + if IR(5) = '0' or Mode /= 3 then + -- CALL cc,nn + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Inc_PC <= '1'; + LDW <= '1'; + if is_cc_true(F, to_bitvector(IR(5 downto 3))) then + IncDec_16 <= "1111"; + Set_Addr_TO <= aSP; + TStates <= "100"; + Set_BusB_To <= "1101"; + else + MCycles <= "011"; + end if; + when 4 => + Write <= '1'; + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + Set_BusB_To <= "1100"; + when 5 => + Write <= '1'; + Call <= '1'; + when others => null; + end case; + end if; + when "11001001" => + -- RET + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + --TStates <= "101"; + Set_Addr_TO <= aSP; + when 2 => + IncDec_16 <= "0111"; + Set_Addr_To <= aSP; + LDZ <= '1'; + when 3 => + Jump <= '1'; + IncDec_16 <= "0111"; + when others => null; + end case; + when "11000000"|"11001000"|"11010000"|"11011000"|"11100000"|"11101000"|"11110000"|"11111000" => + if IR(5) = '1' and Mode = 3 then + case IRB(4 downto 3) is + when "00" => + -- LD ($FF00+nn),A + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + Set_Addr_To <= aIOA; + Set_BusB_To <= "0111"; + when 3 => + Write <= '1'; + when others => null; + end case; + when "01" => + -- ADD SP,n + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + ALU_Op <= "0000"; + Inc_PC <= '1'; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_BusA_To <= "1000"; + Set_BusB_To <= "0110"; + when 3 => + NoRead <= '1'; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + ALU_Op <= "0001"; + Set_BusA_To <= "1001"; + Set_BusB_To <= "1110"; -- Incorrect unsigned !!!!!!!!!!!!!!!!!!!!! + when others => + end case; + when "10" => + -- LD A,($FF00+nn) + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + Set_Addr_To <= aIOA; + when 3 => + Read_To_Acc <= '1'; + when others => null; + end case; + when "11" => + -- LD HL,SP+n -- Not correct !!!!!!!!!!!!!!!!!!! + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + LDW <= '1'; + when 4 => + Set_BusA_To(2 downto 0) <= "101"; -- L + Read_To_Reg <= '1'; + Inc_WZ <= '1'; + Set_Addr_To <= aZI; + when 5 => + Set_BusA_To(2 downto 0) <= "100"; -- H + Read_To_Reg <= '1'; + when others => null; + end case; + end case; + else + -- RET cc + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + if is_cc_true(F, to_bitvector(IR(5 downto 3))) then + Set_Addr_TO <= aSP; + else + MCycles <= "001"; + end if; + TStates <= "101"; + when 2 => + IncDec_16 <= "0111"; + Set_Addr_To <= aSP; + LDZ <= '1'; + when 3 => + Jump <= '1'; + IncDec_16 <= "0111"; + when others => null; + end case; + end if; + when "11000111"|"11001111"|"11010111"|"11011111"|"11100111"|"11101111"|"11110111"|"11111111" => + -- RST p + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + TStates <= "101"; + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + Set_BusB_To <= "1101"; + when 2 => + Write <= '1'; + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + Set_BusB_To <= "1100"; + when 3 => + Write <= '1'; + RstP <= '1'; + when others => null; + end case; + +-- INPUT AND OUTPUT GROUP + when "11011011" => + if Mode /= 3 then + -- IN A,(n) + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + Set_Addr_To <= aIOA; + when 3 => + Read_To_Acc <= '1'; + IORQ <= '1'; + when others => null; + end case; + end if; + when "11010011" => + if Mode /= 3 then + -- OUT (n),A + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + Set_Addr_To <= aIOA; + Set_BusB_To <= "0111"; + when 3 => + Write <= '1'; + IORQ <= '1'; + when others => null; + end case; + end if; + +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +-- MULTIBYTE INSTRUCTIONS +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ + + when "11001011" => + if Mode /= 2 then + Prefix <= "01"; + end if; + + when "11101101" => + if Mode < 2 then + Prefix <= "10"; + end if; + + when "11011101"|"11111101" => + if Mode < 2 then + Prefix <= "11"; + end if; + + end case; + + when "01" => + +------------------------------------------------------------------------------ +-- +-- CB prefixed instructions +-- +------------------------------------------------------------------------------ + + Set_BusA_To(2 downto 0) <= IR(2 downto 0); + Set_BusB_To(2 downto 0) <= IR(2 downto 0); + + case IRB is + when "00000000"|"00000001"|"00000010"|"00000011"|"00000100"|"00000101"|"00000111" + |"00010000"|"00010001"|"00010010"|"00010011"|"00010100"|"00010101"|"00010111" + |"00001000"|"00001001"|"00001010"|"00001011"|"00001100"|"00001101"|"00001111" + |"00011000"|"00011001"|"00011010"|"00011011"|"00011100"|"00011101"|"00011111" + |"00100000"|"00100001"|"00100010"|"00100011"|"00100100"|"00100101"|"00100111" + |"00101000"|"00101001"|"00101010"|"00101011"|"00101100"|"00101101"|"00101111" + |"00110000"|"00110001"|"00110010"|"00110011"|"00110100"|"00110101"|"00110111" + |"00111000"|"00111001"|"00111010"|"00111011"|"00111100"|"00111101"|"00111111" => + -- RLC r + -- RL r + -- RRC r + -- RR r + -- SLA r + -- SRA r + -- SRL r + -- SLL r (Undocumented) / SWAP r + if XY_State="00" then + if MCycle = "001" or MCycle = "111" then + ALU_Op <= "1000"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + end if; + else + -- R/S (IX+d),Reg, undocumented + MCycles <= "011"; + XYbit_undoc <= '1'; + case to_integer(unsigned(MCycle)) is + when 1 | 7=> + Set_Addr_To <= aXY; + when 2 => + ALU_Op <= "1000"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_Addr_To <= aXY; + TStates <= "100"; + when 3 => + Write <= '1'; + when others => null; + end case; + end if; + when "00000110"|"00010110"|"00001110"|"00011110"|"00101110"|"00111110"|"00100110"|"00110110" => + -- RLC (HL) + -- RL (HL) + -- RRC (HL) + -- RR (HL) + -- SRA (HL) + -- SRL (HL) + -- SLA (HL) + -- SLL (HL) (Undocumented) / SWAP (HL) + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 | 7 => + Set_Addr_To <= aXY; + when 2 => + ALU_Op <= "1000"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_Addr_To <= aXY; + TStates <= "100"; + when 3 => + Write <= '1'; + when others => + end case; + when "01000000"|"01000001"|"01000010"|"01000011"|"01000100"|"01000101"|"01000111" + |"01001000"|"01001001"|"01001010"|"01001011"|"01001100"|"01001101"|"01001111" + |"01010000"|"01010001"|"01010010"|"01010011"|"01010100"|"01010101"|"01010111" + |"01011000"|"01011001"|"01011010"|"01011011"|"01011100"|"01011101"|"01011111" + |"01100000"|"01100001"|"01100010"|"01100011"|"01100100"|"01100101"|"01100111" + |"01101000"|"01101001"|"01101010"|"01101011"|"01101100"|"01101101"|"01101111" + |"01110000"|"01110001"|"01110010"|"01110011"|"01110100"|"01110101"|"01110111" + |"01111000"|"01111001"|"01111010"|"01111011"|"01111100"|"01111101"|"01111111" => + -- BIT b,r + if XY_State="00" then + if MCycle = "001" or MCycle = "111" then + Set_BusB_To(2 downto 0) <= IR(2 downto 0); + ALU_Op <= "1001"; + end if; + else + -- BIT b,(IX+d), undocumented + MCycles <= "010"; + XYbit_undoc <= '1'; + case to_integer(unsigned(MCycle)) is + when 1 | 7=> + Set_Addr_To <= aXY; + when 2 => + ALU_Op <= "1001"; + TStates <= "100"; + when others => null; + end case; + end if; + when "01000110"|"01001110"|"01010110"|"01011110"|"01100110"|"01101110"|"01110110"|"01111110" => + -- BIT b,(HL) + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 | 7 => + Set_Addr_To <= aXY; + when 2 => + ALU_Op <= "1001"; + TStates <= "100"; + when others => + end case; + when "11000000"|"11000001"|"11000010"|"11000011"|"11000100"|"11000101"|"11000111" + |"11001000"|"11001001"|"11001010"|"11001011"|"11001100"|"11001101"|"11001111" + |"11010000"|"11010001"|"11010010"|"11010011"|"11010100"|"11010101"|"11010111" + |"11011000"|"11011001"|"11011010"|"11011011"|"11011100"|"11011101"|"11011111" + |"11100000"|"11100001"|"11100010"|"11100011"|"11100100"|"11100101"|"11100111" + |"11101000"|"11101001"|"11101010"|"11101011"|"11101100"|"11101101"|"11101111" + |"11110000"|"11110001"|"11110010"|"11110011"|"11110100"|"11110101"|"11110111" + |"11111000"|"11111001"|"11111010"|"11111011"|"11111100"|"11111101"|"11111111" => + -- SET b,r + if XY_State="00" then + if MCycle = "001" then + ALU_Op <= "1010"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + else + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 7 => + Set_Addr_To <= aXY; + when 2 => + Set_BusB_To(2 downto 0) <= "110"; + ALU_Op <= "1010"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_Addr_To <= aXY; + TStates <= "100"; + when 3 => + Set_Addr_To <= aXY; + when 4 => + Write <= '1'; + when others => null; + end case; + end if; + else + -- SET b,(IX+d),Reg, undocumented + MCycles <= "011"; + XYbit_undoc <= '1'; + case to_integer(unsigned(MCycle)) is + when 1 | 7=> + Set_Addr_To <= aXY; + when 2 => + ALU_Op <= "1010"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_Addr_To <= aXY; + TStates <= "100"; + when 3 => + Write <= '1'; + when others => null; + end case; + end if; + when "11000110"|"11001110"|"11010110"|"11011110"|"11100110"|"11101110"|"11110110"|"11111110" => + -- SET b,(HL) + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 | 7 => + Set_Addr_To <= aXY; + when 2 => + ALU_Op <= "1010"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_Addr_To <= aXY; + TStates <= "100"; + when 3 => + Write <= '1'; + when others => + end case; + when "10000000"|"10000001"|"10000010"|"10000011"|"10000100"|"10000101"|"10000111" + |"10001000"|"10001001"|"10001010"|"10001011"|"10001100"|"10001101"|"10001111" + |"10010000"|"10010001"|"10010010"|"10010011"|"10010100"|"10010101"|"10010111" + |"10011000"|"10011001"|"10011010"|"10011011"|"10011100"|"10011101"|"10011111" + |"10100000"|"10100001"|"10100010"|"10100011"|"10100100"|"10100101"|"10100111" + |"10101000"|"10101001"|"10101010"|"10101011"|"10101100"|"10101101"|"10101111" + |"10110000"|"10110001"|"10110010"|"10110011"|"10110100"|"10110101"|"10110111" + |"10111000"|"10111001"|"10111010"|"10111011"|"10111100"|"10111101"|"10111111" => + -- RES b,r + if XY_State="00" then + if MCycle = "001" then + ALU_Op <= "1011"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + else + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 7 => + Set_Addr_To <= aXY; + when 2 => + Set_BusB_To(2 downto 0) <= "110"; + ALU_Op <= "1011"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_Addr_To <= aXY; + TStates <= "100"; + when 3 => + Set_Addr_To <= aXY; + when 4 => + Write <= '1'; + when others => null; + end case; + end if; + else + -- RES b,(IX+d),Reg, undocumented + MCycles <= "011"; + XYbit_undoc <= '1'; + case to_integer(unsigned(MCycle)) is + when 1 | 7=> + Set_Addr_To <= aXY; + when 2 => + ALU_Op <= "1011"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_Addr_To <= aXY; + TStates <= "100"; + when 3 => + Write <= '1'; + when others => null; + end case; + end if; + when "10000110"|"10001110"|"10010110"|"10011110"|"10100110"|"10101110"|"10110110"|"10111110" => + -- RES b,(HL) + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 | 7 => + Set_Addr_To <= aXY; + when 2 => + ALU_Op <= "1011"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_Addr_To <= aXY; + TStates <= "100"; + when 3 => + Write <= '1'; + when others => + end case; + end case; + + when others => + +------------------------------------------------------------------------------ +-- +-- ED prefixed instructions +-- +------------------------------------------------------------------------------ + + case IRB is + +-- 8 BIT LOAD GROUP + when "01010111" => + -- LD A,I + Special_LD <= "100"; + TStates <= "101"; + when "01011111" => + -- LD A,R + Special_LD <= "101"; + TStates <= "101"; + when "01000111" => + -- LD I,A + Special_LD <= "110"; + TStates <= "101"; + when "01001111" => + -- LD R,A + Special_LD <= "111"; + TStates <= "101"; + + when X"91" => + -- NEXTREGW rr,(nn) + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 1 => + Inc_PC <= '1'; + when 2 => + Inc_PC <= '1'; + Z80N_data_o <= ext_Data_i; + Z80N_data_o_strobe_hi <= '1'; + when 3 => + Z80N_data_o <= ext_Data_i; + Z80N_data_o_strobe_lo <= '1'; + when 4 => + Z80N_command_o <= NEXTREGW; + Z80N_dout_o <= '1'; + when 5 => + Inc_PC <= '1'; + Z80N_dout_o <= '0'; + when others => null; + end case; + + when X"92" => + -- NEXTREGWA rr + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 1 => + Inc_PC <= '1'; + Z80N_data_o <= ext_ACC_i; + Z80N_data_o_strobe_lo <= '1'; + when 2 => + Z80N_data_o <= ext_Data_i; + Z80N_data_o_strobe_hi <= '1'; + when 3 => + Z80N_command_o <= NEXTREGW; + Z80N_dout_o <= '1'; + when 4 => + Z80N_dout_o <= '0'; + Inc_PC <= '1'; + + when others => null; + end case; + + + when X"30" => + + -- MUL_DE + TStates <= "100"; + Z80N_command_o <= MUL_DE; + + when X"31" => + + -- ADD_HL_A + TStates <= "100"; + Z80N_command_o <= ADD_HL_A; + + when X"32" => + + -- ADD_DE_A + TStates <= "100"; + Z80N_command_o <= ADD_DE_A; + + when X"33" => + + -- ADD_BC_A + TStates <= "100"; + Z80N_command_o <= ADD_BC_A; + +-- when X"20" => + + -- LD_ACC32_HLDE +-- TStates <= "100"; +-- Z80N_command_o <= LD_ACC32_DEHL; + +-- when X"21" => + + -- LD_HLDE_ACC32 +-- TStates <= "100"; +-- Z80N_command_o <= LD_DEHL_ACC32; + +-- when X"22" => + + -- EXXACC32 +-- TStates <= "100"; +-- Z80N_command_o <= EXXACC32; + + when X"23" => + + -- SWAPNIB_A + TStates <= "100"; + Z80N_command_o <= SWAPNIB_A; + + when X"24" => + + -- MIRROR_A + TStates <= "100"; + Z80N_command_o <= MIRROR_A; + +-- when X"25" => + + -- LD_HL_SP +-- TStates <= "100"; +-- Z80N_command_o <= LD_HL_SP; + +-- when X"26" => + + -- MIRROR_DE +-- TStates <= "100"; +-- Z80N_command_o <= MIRROR_DE; + + when x"27" => + -- TEST_nn + MCycles <= "010"; + if MCycle = "010" then + Inc_PC <= '1'; + --Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_BusB_To(2 downto 0) <= "110"; -- SSS + Set_BusA_To(2 downto 0) <= "111"; + end if; + + when X"28" => + + -- BSLA DE,B + TStates <= "100"; + Z80N_command_o <= BSLA_DE_B; + + when X"29" => + + -- BSRA DE,B + TStates <= "100"; + Z80N_command_o <= BSRA_DE_B; + + when X"2A" => + + -- BSRL DE,B + TStates <= "100"; + Z80N_command_o <= BSRL_DE_B; + + when X"2B" => + + -- BSRF DE,B + TStates <= "100"; + Z80N_command_o <= BSRF_DE_B; + + when X"2C" => + + -- BRLC DE,B + TStates <= "100"; + Z80N_command_o <= BRLC_DE_B; + + when X"93" => + + -- PIXELDN + TStates <= "100"; + Z80N_command_o <= PIXELDN; + + when X"94" => + + -- PIXELAD + TStates <= "100"; + Z80N_command_o <= PIXELAD; + + when X"95" => + + -- SET_A_E + TStates <= "100"; + Z80N_command_o <= SET_A_E; + + when X"98" => + -- JP (C) + MCycles <= "010"; + TStates <= "100"; + Z80N_command_o <= JP_C; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aBC; + when 2 => + IORQ <= '1'; + when others => + end case; + + when X"34" | X"35" | X"36" => --X"3B" => + -- ADD_HL_nn, ADD_DE_nn, ADD_BC_nn, ADD_HLDE_nn + TStates <= "100"; + + case IRB is + when X"34" => + Z80N_command_o <= ADD_HL_nn; + when X"35" => + Z80N_command_o <= ADD_DE_nn; + when X"36" => + Z80N_command_o <= ADD_BC_nn; +-- when X"3B" => +-- Z80N_command_o <= ADD_DEHL_nn; + when others => null; + end case; + + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + + when 1 => + Inc_PC <= '1'; + + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + + when 3 => + Inc_PC <= '1'; + LDW <= '1'; + + + when others => null; + end case; + +-- when X"37" => + + -- INC_HLDE +-- TStates <= "100"; +-- Z80N_command_o <= INC_DEHL; + +-- when X"38" => + + -- DEC_HLDE +-- TStates <= "100"; +-- Z80N_command_o <= DEC_DEHL; + +-- when X"39" => + + -- ADD_HLDE_A +-- TStates <= "100"; +-- Z80N_command_o <= ADD_DEHL_A; + +-- when X"3A" => + + -- ADD_HLDE_BC +-- TStates <= "100"; +-- Z80N_command_o <= ADD_DEHL_BC; + + +-- when X"3C" => + + -- SUB_HLDE_A +-- TStates <= "100"; +-- Z80N_command_o <= SUB_DEHL_A; + +-- when X"3D" => + + -- SUB_HLDE_BC +-- TStates <= "100"; +-- Z80N_command_o <= SUB_DEHL_BC; + + when X"8A" => + -- PUSH VAL nn + + MCycles <= "110"; + case to_integer(unsigned(MCycle)) is + + when 1 => + Inc_PC <= '1'; + LDZ <= '1'; + + when 2 => + --TStates <= "101"; + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + Set_BusB_To <= "0110"; + when 3 => + Inc_PC <= '1'; + LDZ <= '1'; + Write <= '1'; + when 4 => + -- TStates <= "101"; + IncDec_16 <= "1111"; + Set_Addr_To <= aSP; + Set_BusB_To <= "0110"; + when 5 => + Write <= '1'; + + when others => null; + end case; + + + + when X"B7" => + -- LDPIRX + --get byte from ( reg_HL_s(15 downto 3) & reg_DE_s(2 downto 0) ) + --if byte != reg_A_s then + -- store byte in (reg_DE_s) + --reg_DE_temp_s <= reg_DE_s+1; + --reg_BC_temp_s <= reg_BC_s-1; + --loop if BC is not zero + + Z80N_command_o <= LDPIRX; + + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 1 => + LDZ <= '1'; + Set_Addr_To <= aXY; + IncDec_16 <= "1100"; -- decrement BC + + when 2 => + Set_BusB_To <= "0110"; + --Set_BusA_To(2 downto 0) <= "111"; + -- ALU_Op <= "0000"; + -- Set_Addr_To <= aDE; + + when 3 => + I_BT <= '1'; + TStates <= "101"; + + if ext_ACC_i /= ext_Data_i then + Write <= '1'; + end if; + + IncDec_16 <= "0101"; -- increment DE + + when 4 => + NoRead <= '1'; + TStates <= "101"; + when others => null; + end case; + + + +-- when X"b5" => + -- FILLDE + + -- MCycles <= "100"; + -- case to_integer(unsigned(MCycle)) is + -- + -- when 1 => + -- Set_Addr_To <= aXY; + -- IncDec_16 <= "1100"; -- decrement BC + -- + -- when 2 => + -- Set_Addr_To <= aDE; + -- Set_BusB_To <= "0111"; -- ACC + -- + -- when 3 => + -- I_BT <= '1'; + -- TStates <= "101"; + -- Write <= '1'; +-- + -- -- INC E + -- Set_BusB_To <= "1010"; + -- Set_BusA_To(2 downto 0) <= "011"; -- Reg E + -- Read_To_Reg <= '1'; + -- Save_ALU <= '1'; + -- PreserveC <= '1'; + -- ALU_Op <= "0000"; + -- + -- when 4 => + -- NoRead <= '1'; + -- TStates <= "101"; + -- when others => null; + -- end case; + + +-- 16 BIT LOAD GROUP + when "01001011"|"01011011"|"01101011"|"01111011" => + -- LD dd,(nn) + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + LDW <= '1'; + when 4 => + Read_To_Reg <= '1'; + if IR(5 downto 4) = "11" then + Set_BusA_To <= "1000"; + else + Set_BusA_To(2 downto 1) <= IR(5 downto 4); + Set_BusA_To(0) <= '1'; + end if; + Inc_WZ <= '1'; + Set_Addr_To <= aZI; + when 5 => + Read_To_Reg <= '1'; + if IR(5 downto 4) = "11" then + Set_BusA_To <= "1001"; + else + Set_BusA_To(2 downto 1) <= IR(5 downto 4); + Set_BusA_To(0) <= '0'; + end if; + when others => null; + end case; + when "01000011"|"01010011"|"01100011"|"01110011" => + -- LD (nn),dd + MCycles <= "101"; + case to_integer(unsigned(MCycle)) is + when 2 => + Inc_PC <= '1'; + LDZ <= '1'; + when 3 => + Set_Addr_To <= aZI; + Inc_PC <= '1'; + LDW <= '1'; + if IR(5 downto 4) = "11" then + Set_BusB_To <= "1000"; + else + Set_BusB_To(2 downto 1) <= IR(5 downto 4); + Set_BusB_To(0) <= '1'; + Set_BusB_To(3) <= '0'; + end if; + when 4 => + Inc_WZ <= '1'; + Set_Addr_To <= aZI; + Write <= '1'; + if IR(5 downto 4) = "11" then + Set_BusB_To <= "1001"; + else + Set_BusB_To(2 downto 1) <= IR(5 downto 4); + Set_BusB_To(0) <= '0'; + Set_BusB_To(3) <= '0'; + end if; + when 5 => + Write <= '1'; + when others => null; + end case; + + when "10100000" | "10101000" | "10110000" | "10111000" -- a0 a8 b0 b8 + -- LDI, LDD, LDIR, LDDR + + | X"A4" | X"B4" => + -- LDIX, LDIRX + + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + IncDec_16 <= "1100"; -- decrement BC + when 2 => + Set_BusB_To <= "0110"; + Set_BusA_To(2 downto 0) <= "111"; + ALU_Op <= "0000"; + Set_Addr_To <= aDE; + if IR(3) = '0' then + IncDec_16 <= "0110"; -- increment HL + else + IncDec_16 <= "1110"; -- decrement HL + end if; + when 3 => + I_BT <= '1'; + TStates <= "101"; + + -- if is a "X" instruction, test for the excluding byte + if (IRB = X"A4" or IRB = X"B4" ) then + if ext_ACC_i /= ext_Data_i then + Write <= '1'; + end if; + else + Write <= '1'; + end if; + + if IR(3) = '0' then + IncDec_16 <= "0101"; -- increment DE + else + IncDec_16 <= "1101"; -- decrement DE + end if; + when 4 => + NoRead <= '1'; + TStates <= "101"; + when others => null; + end case; + + when X"A5" => -- LDWS + -- LD (DE),(DL) + -- inc L + -- inc D + + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + + when 1 => + + Set_Addr_To <= aXY; + + -- INC L + Set_BusB_To <= "1010"; + Set_BusA_To(2 downto 0) <= "101"; -- Reg L + Read_To_Reg <= '1'; + Save_ALU <= '1'; + ALU_Op <= "0000"; + + when 2 => + + Set_Addr_To <= aDE; + + --get the (HL) value + Set_BusB_To <= "0110"; + Set_BusA_To(2 downto 0) <= "111"; + ALU_Op <= "0000"; + + when 3 => + + I_BT <= '1'; + TStates <= "011"; + Write <= '1'; + + -- INC D + Set_BusB_To <= "1010"; + Set_BusA_To(2 downto 0) <= "010"; -- Reg D + Read_To_Reg <= '1'; + Save_ALU <= '1'; + ALU_Op <= "0000"; + + --NoRead <= '1'; + + when others => null; + end case; + + + when X"B6" => + -- LDIRSCALE + + --read byte from ( reg_HL_s (15 downto 0)) + --if byte != A put byte in ( reg_DE_s(15 downto 0)) + --add BC' ( from exx ) to HL_A' and store in HL_A' + --DE <= DE + DE' + --loop BC + + Z80N_command_o <= LDIRSCALE; + + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + + when 1 => + Set_Addr_To <= aXY; + IncDec_16 <= "1100"; -- decrement BC + + when 2 => + Set_BusB_To <= "0110"; + Set_BusA_To(2 downto 0) <= "111"; + ALU_Op <= "0000"; + Set_Addr_To <= aDE; + IncDec_16 <= "0110"; -- increment HL + + when 3 => + I_BT <= '1'; + TStates <= "101"; + + if ext_ACC_i /= ext_Data_i then + Write <= '1'; + end if; + + IncDec_16 <= "0101"; -- increment DE + + when 4 => + NoRead <= '1'; + TStates <= "101"; + + when others => null; + end case; + + when X"AC" | X"BC" => + -- LDDX, LDDRX + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + IncDec_16 <= "1100"; -- decrement BC + when 2 => + Set_BusB_To <= "0110"; + Set_BusA_To(2 downto 0) <= "111"; + ALU_Op <= "0000"; + Set_Addr_To <= aDE; + IncDec_16 <= "1110"; -- decrement HL + + when 3 => + I_BT <= '1'; + TStates <= "101"; + if ext_ACC_i /= ext_Data_i then + Write <= '1'; + end if; + IncDec_16 <= "0101"; -- increment DE + + when 4 => + NoRead <= '1'; + TStates <= "101"; + when others => null; + end case; + + when "10100001" | "10101001" | "10110001" | "10111001" => + -- CPI, CPD, CPIR, CPDR + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aXY; + IncDec_16 <= "1100"; -- BC + when 2 => + Set_BusB_To <= "0110"; + Set_BusA_To(2 downto 0) <= "111"; + ALU_Op <= "0111"; + Save_ALU <= '1'; + PreserveC <= '1'; + if IR(3) = '0' then + IncDec_16 <= "0110"; + else + IncDec_16 <= "1110"; + end if; + when 3 => + NoRead <= '1'; + I_BC <= '1'; + TStates <= "101"; + when 4 => + NoRead <= '1'; + TStates <= "101"; + when others => null; + end case; + when "01000100"|"01001100"|"01010100"|"01011100"|"01100100"|"01101100"|"01110100"|"01111100" => + -- NEG + Alu_OP <= "0010"; + Set_BusB_To <= "0111"; + Set_BusA_To <= "1010"; + Read_To_Acc <= '1'; + Save_ALU <= '1'; + when "01000110"|"01001110"|"01100110"|"01101110" => + -- IM 0 + IMode <= "00"; + when "01010110"|"01110110" => + -- IM 1 + IMode <= "01"; + when "01011110"|"01111110" => + -- IM 2 + IMode <= "10"; +-- 16 bit arithmetic + when "01001010"|"01011010"|"01101010"|"01111010" => + -- ADC HL,ss + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + NoRead <= '1'; + ALU_Op <= "0001"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_BusA_To(2 downto 0) <= "101"; + case to_integer(unsigned(IR(5 downto 4))) is + when 0|1|2 => + Set_BusB_To(2 downto 1) <= IR(5 downto 4); + Set_BusB_To(0) <= '1'; + when others => + Set_BusB_To <= "1000"; + end case; + TStates <= "100"; + when 3 => + NoRead <= '1'; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + ALU_Op <= "0001"; + Set_BusA_To(2 downto 0) <= "100"; + case to_integer(unsigned(IR(5 downto 4))) is + when 0|1|2 => + Set_BusB_To(2 downto 1) <= IR(5 downto 4); + Set_BusB_To(0) <= '0'; + when others => + Set_BusB_To <= "1001"; + end case; + when others => + end case; + when "01000010"|"01010010"|"01100010"|"01110010" => + -- SBC HL,ss + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 2 => + NoRead <= '1'; + ALU_Op <= "0011"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_BusA_To(2 downto 0) <= "101"; + case to_integer(unsigned(IR(5 downto 4))) is + when 0|1|2 => + Set_BusB_To(2 downto 1) <= IR(5 downto 4); + Set_BusB_To(0) <= '1'; + when others => + Set_BusB_To <= "1000"; + end case; + TStates <= "100"; + when 3 => + NoRead <= '1'; + ALU_Op <= "0011"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + Set_BusA_To(2 downto 0) <= "100"; + case to_integer(unsigned(IR(5 downto 4))) is + when 0|1|2 => + Set_BusB_To(2 downto 1) <= IR(5 downto 4); + when others => + Set_BusB_To <= "1001"; + end case; + when others => + end case; + when "01101111" => + -- RLD + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 2 => + NoRead <= '1'; + Set_Addr_To <= aXY; + when 3 => + Read_To_Reg <= '1'; + Set_BusB_To(2 downto 0) <= "110"; + Set_BusA_To(2 downto 0) <= "111"; + ALU_Op <= "1101"; + TStates <= "100"; + Set_Addr_To <= aXY; + Save_ALU <= '1'; + when 4 => + I_RLD <= '1'; + Write <= '1'; + when others => + end case; + when "01100111" => + -- RRD + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 2 => + Set_Addr_To <= aXY; + when 3 => + Read_To_Reg <= '1'; + Set_BusB_To(2 downto 0) <= "110"; + Set_BusA_To(2 downto 0) <= "111"; + ALU_Op <= "1110"; + TStates <= "100"; + Set_Addr_To <= aXY; + Save_ALU <= '1'; + when 4 => + I_RRD <= '1'; + Write <= '1'; + when others => + end case; + when "01001101" => + -- RETI + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_TO <= aSP; + when 2 => + IncDec_16 <= "0111"; + Set_Addr_To <= aSP; + LDZ <= '1'; + when 3 => + Jump <= '1'; + IncDec_16 <= "0111"; + I_RETN <= '1'; + when others => null; + end case; + when "01000101"|"01010101"|"01011101"|"01100101"|"01101101"|"01110101"|"01111101" => + -- RETN + MCycles <= "011"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_TO <= aSP; + when 2 => + IncDec_16 <= "0111"; + Set_Addr_To <= aSP; + LDZ <= '1'; + Z80N_command_o <= RETN_LSB; + when 3 => + Jump <= '1'; + IncDec_16 <= "0111"; + I_RETN <= '1'; + Z80N_command_o <= RETN_MSB; + when others => null; + end case; + when "01000000"|"01001000"|"01010000"|"01011000"|"01100000"|"01101000"|"01110000"|"01111000" => + -- IN r,(C) + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aBC; + when 2 => + IORQ <= '1'; + if IR(5 downto 3) /= "110" then + Read_To_Reg <= '1'; + Set_BusA_To(2 downto 0) <= IR(5 downto 3); + end if; + I_INRC <= '1'; + when others => + end case; + when "01000001"|"01001001"|"01010001"|"01011001"|"01100001"|"01101001"|"01110001"|"01111001" => + -- OUT (C),r + -- OUT (C),0 + MCycles <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= aBC; + Set_BusB_To(2 downto 0) <= IR(5 downto 3); + if IR(5 downto 3) = "110" then + Set_BusB_To(3) <= '1'; + end if; + when 2 => + Write <= '1'; + IORQ <= '1'; + when others => + end case; + when "10100010" | "10101010" | "10110010" | "10111010" => + -- INI, IND, INIR, INDR + MCycles <= "100"; + case to_integer(unsigned(MCycle)) is + when 1 => + TStates <= "101"; + Set_Addr_To <= aBC; + Set_BusB_To <= "1010"; + Set_BusA_To <= "0000"; + Read_To_Reg <= '1'; + Save_ALU <= '1'; + ALU_Op <= "0010"; + when 2 => + IORQ <= '1'; + Set_BusB_To <= "0110"; + Set_Addr_To <= aXY; + when 3 => + if IR(3) = '0' then + IncDec_16 <= "0110"; + else + IncDec_16 <= "1110"; + end if; + TStates <= "011"; -- "100" + Write <= '1'; + I_BTR <= '1'; + when 4 => + NoRead <= '1'; + TStates <= "101"; + when others => null; + end case; + + when "10100011" | "10101011" | "10110011" | "10111011" + -- OUTI, OUTD, OTIR, OTDR + + | x"90" => -- OUTINB + + if IRB /= X"90" then --if not OUTINB + MCycles <= "100"; + else + MCycles <= "011"; + end if; + + case to_integer(unsigned(MCycle)) is + when 1 => + TStates <= "101"; + Set_Addr_To <= aXY; + Set_BusB_To <= "1010"; + Set_BusA_To <= "0000"; + + if IRB /= X"90" then --if not OUTINB, decrement B + Read_To_Reg <= '1'; + Save_ALU <= '1'; + ALU_Op <= "0010"; -- SUB d0,d1 + + end if; + + when 2 => + Set_BusB_To <= "0110"; + Set_Addr_To <= aBC; + when 3 => + if IR(3) = '0' then + IncDec_16 <= "0110"; -- increment HL + else + IncDec_16 <= "1110"; -- decrement HL + end if; + --TStates <= "100"; -- MIKEJ should be 4 for IO cycle + IORQ <= '1'; + Write <= '1'; + I_BTR <= '1'; + when 4 => + NoRead <= '1'; + TStates <= "101"; + when others => null; + end case; + +-- when x"90" => -- OUTINB +-- +-- MCycles <= "011"; +-- case to_integer(unsigned(MCycle)) is +-- when 1 => +-- TStates <= "101"; +-- Set_Addr_To <= aXY; +-- Set_BusB_To <= "1010"; +-- Set_BusA_To <= "0000"; -- get the (HL) +-- +-- when 2 => +-- Set_BusB_To <= "0110"; -- show the (HL) read on the bus +-- --Set_Addr_To <= aBC; +-- when 3 => +-- IncDec_16 <= "0110"; -- increment HL +-- TStates <= "100"; -- MIKEJ should be 4 for IO cycle +-- IORQ <= '1'; +-- Write <= '1'; +-- I_BTR <= '1'; +-- when 4 => +-- NoRead <= '1'; +-- TStates <= "101"; +-- when others => null; +-- end case; + + when others => null; + + end case; + + end case; + + if Mode = 1 then + if MCycle = "001" then +-- TStates <= "100"; + else + TStates <= "011"; + end if; + end if; + + if Mode = 3 then + if MCycle = "001" then +-- TStates <= "100"; + else + TStates <= "100"; + end if; + end if; + + if Mode < 2 then + if MCycle = "110" then + Inc_PC <= '1'; + if Mode = 1 then + Set_Addr_To <= aXY; + TStates <= "100"; + Set_BusB_To(2 downto 0) <= SSS; + Set_BusB_To(3) <= '0'; + end if; + if IRB = "00110110" or IRB = "11001011" then + Set_Addr_To <= aNone; + end if; + end if; + if MCycle = "111" then + if Mode = 0 then + TStates <= "101"; + end if; + if ISet /= "01" then + Set_Addr_To <= aXY; + end if; + Set_BusB_To(2 downto 0) <= SSS; + Set_BusB_To(3) <= '0'; + if IRB = "00110110" or ISet = "01" then + -- LD (HL),n + Inc_PC <= '1'; + else + NoRead <= '1'; + end if; + end if; + end if; + + end process; + +end; diff --git a/rtl/cpu/t80n_pack.vhd b/rtl/cpu/t80n_pack.vhd new file mode 100644 index 0000000..a61686b --- /dev/null +++ b/rtl/cpu/t80n_pack.vhd @@ -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 +-- +-- +-- 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; diff --git a/rtl/cpu/t80na.vhd b/rtl/cpu/t80na.vhd new file mode 100644 index 0000000..257734a --- /dev/null +++ b/rtl/cpu/t80na.vhd @@ -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: +-- +-- +-- 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 +-- +-- +-- 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; diff --git a/rtl/device/copper.vhd b/rtl/device/copper.vhd new file mode 100644 index 0000000..70f3aad --- /dev/null +++ b/rtl/device/copper.vhd @@ -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 +-- +-- +-- 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 +-- . + +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; diff --git a/rtl/device/ctc.vhd b/rtl/device/ctc.vhd new file mode 100644 index 0000000..8060ba1 --- /dev/null +++ b/rtl/device/ctc.vhd @@ -0,0 +1,169 @@ +-- Z80 CTC +-- Copyright 2020 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- 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; diff --git a/rtl/device/ctc_chan.vhd b/rtl/device/ctc_chan.vhd new file mode 100644 index 0000000..00d01bd --- /dev/null +++ b/rtl/device/ctc_chan.vhd @@ -0,0 +1,267 @@ +-- Z80 CTC Channel +-- Copyright 2020 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- 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; diff --git a/rtl/device/divmmc.vhd b/rtl/device/divmmc.vhd new file mode 100644 index 0000000..8c672dc --- /dev/null +++ b/rtl/device/divmmc.vhd @@ -0,0 +1,150 @@ + +-- ZXN Divmmc +-- Copyright 2020 Alvin Albrecht and Fabio Belavenuto +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +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; diff --git a/rtl/device/dma.vhd b/rtl/device/dma.vhd new file mode 100644 index 0000000..f616b7c --- /dev/null +++ b/rtl/device/dma.vhd @@ -0,0 +1,1148 @@ + +-- ZXN DMA +-- Copyright 2020 Victor Trucco and Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- ATTENTION: Loosely based on Zilog Z80C10. There are differences! + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; +use IEEE.STD_LOGIC_UNSIGNED.all; + +entity z80dma is + port + ( + reset_i : in std_logic; + clk_i : in std_logic; + turbo_i : in std_logic_vector(1 downto 0); -- 00 = 3.5MHz, 01 = 7MHz, 10 = 14MHz, 11 = 28MHz + dma_mode_i : in std_logic; -- 1 = z80 dma compatible + + dma_en_wr_s : in std_logic; + dma_en_rd_s : in std_logic; + + cpu_d_i : in std_logic_vector(7 downto 0); + wait_n_i : in std_logic := '1'; + dma_delay_i : in std_logic; + + bus_busreq_n_i : in std_logic; -- busreq in + cpu_busreq_n_o : out std_logic; -- busreq from dma + + cpu_bai_n : in std_logic; -- busak in daisy chain + cpu_bao_n : out std_logic; -- busak out daisy chain + + dma_a_o : out std_logic_vector(15 downto 0); + dma_d_o : out std_logic_vector(7 downto 0); + dma_d_i : in std_logic_vector(7 downto 0); + dma_rd_n_o : out std_logic; + dma_wr_n_o : out std_logic; + dma_mreq_n_o : out std_logic; + dma_iorq_n_o : out std_logic; + + cpu_d_o : out std_logic_vector(7 downto 0) + ); + +end z80dma; + +architecture z80dma_unit of z80dma is + + --type array_7x8 is array (0 to 6) of std_logic_vector(7 downto 0); + --signal reg : array_7x8; + + signal reg_temp : std_logic_vector(7 downto 0); + + signal R0_dir_AtoB_s : std_logic; -- direction - 0 = B -> A 1 = A -> B + --signal R0_tranfer_s : std_logic; + --signal R0_search_s : std_logic; + signal R0_start_addr_port_A_s : std_logic_vector (15 downto 0); + signal R0_block_len_s : std_logic_vector (15 downto 0); + + signal R1_portAisIO_s : std_logic; -- 0 = Port A is Memory 1 = Port A is IO + signal R1_portA_addrMode_s : std_logic_vector (1 downto 0); -- address mode - 00 = decrements, 01 = increments, 10 or 11 = fixed + signal R1_portA_timming_byte_s : std_logic_vector (1 downto 0) := "01"; + --signal R1_portA_preescaler_s : std_logic_vector (7 downto 0); + + signal R2_portBisIO_s : std_logic; -- 0 = Port B is Memory 1 = Port B is IO + signal R2_portB_addrMode_s : std_logic_vector (1 downto 0); -- address mode - 00 = decrements, 01 = increments, 10 or 11 = fixed + signal R2_portB_timming_byte_s : std_logic_vector (1 downto 0) := "01"; + signal R2_portB_preescaler_s : std_logic_vector (7 downto 0); + + signal R3_dma_en_s : std_logic; + --signal R3_int_en_s : std_logic; + --signal R3_stop_match_s : std_logic; + --signal R3_mask_s : std_logic_vector (7 downto 0); + --signal R3_match_s : std_logic_vector (7 downto 0); + + signal R4_mode_s : std_logic_vector (1 downto 0); -- 00 byte, 01 continuos, 10 burst + signal R4_start_addr_port_B_s : std_logic_vector (15 downto 0); + --signal R4_interrupt_control_s : std_logic_vector (7 downto 0); + --signal R4_pulse_control_s : std_logic_vector (7 downto 0); + --signal R4_interrupt_vector_s : std_logic_vector (7 downto 0); + + --signal R5_ready_act_hi_s : std_logic; -- 0 = READY activel low, 1 = READY active high + signal R5_ce_wait_s : std_logic;-- 0 = CE only, 1 = CE / WAIT multiplexed + signal R5_auto_restart_s : std_logic;-- 0 = stop on end, 1 = auto restart + + signal R6_read_mask_s : std_logic_vector (7 downto 0); + + signal status_atleastone : std_logic; + signal status_endofblock_n : std_logic; + + type dma_seq_t is ( IDLE, START_DMA, WAITING_ACK, TRANSFERING_READ_1, TRANSFERING_READ_2, TRANSFERING_READ_3, TRANSFERING_READ_4, TRANSFERING_WRITE_1, TRANSFERING_WRITE_2, TRANSFERING_WRITE_3, TRANSFERING_WRITE_4, WAITING_CYCLES, FINISH_DMA ); + signal dma_seq_s : dma_seq_t; + + signal dma_a_s : std_logic_vector(15 downto 0) := X"FF00"; -- X"00FF" --X"FF00"; -- X"FF00" X"00FF"; + signal dma_d_s : std_logic_vector(7 downto 0); + signal dma_d_n_s : std_logic_vector(7 downto 0); + signal dma_d_p_s : std_logic_vector(7 downto 0); + signal wait_n_s : std_logic; + signal dma_read_cycle : std_logic; + signal dma_write_cycle : std_logic; + signal dma_mreq_cycle : std_logic; + signal dma_rw_cancel : std_logic; + signal dma_rw_extend : std_logic; + signal dma_rd_s : std_logic; + signal dma_rd_n_s : std_logic; + signal dma_wr_s : std_logic; + signal dma_wr_n_s : std_logic; + + signal dma_src_s : std_logic_vector(15 downto 0); + signal dma_dest_s : std_logic_vector(15 downto 0); + signal dma_counter_s : std_logic_vector(15 downto 0); + + signal DMA_timer_s : std_logic_vector(13 downto 0); + + signal read_count_s : std_logic_vector(2 downto 0); + + signal cpu_busreq_n_s : std_logic; + +begin + + -- shape read / write cycles + -- what is done here to avoid 14MHz wait states is awful but should go away in a rewrite of the dma module + + process (clk_i) + begin + if falling_edge(clk_i) then + wait_n_s <= wait_n_i; + end if; + end process; + + dma_rw_cancel <= '1' when wait_n_i = '1' and (dma_seq_s = TRANSFERING_READ_4 or dma_seq_s = TRANSFERING_WRITE_4) else '0'; + + process (clk_i) + begin + if falling_edge(clk_i) then + dma_rd_s <= dma_read_cycle and not dma_rw_cancel; + dma_wr_s <= dma_write_cycle and not dma_rw_cancel; + end if; + end process; + + -- Avoid wait state for 14MHz + dma_rw_extend <= '1' when turbo_i = "10" and (dma_seq_s = TRANSFERING_READ_4 or dma_seq_s = TRANSFERING_WRITE_4) else '0'; + + dma_rd_n_s <= not (dma_rd_s or (dma_rw_extend and dma_read_cycle)); + dma_wr_n_s <= not (dma_wr_s or (dma_rw_extend and dma_write_cycle)); + + process (clk_i) + begin + if falling_edge(clk_i) then + if dma_read_cycle = '1' then + dma_d_n_s <= dma_d_i; + end if; + end if; + end process; + + process (clk_i) + begin + if rising_edge(clk_i) then + if dma_read_cycle = '1' then + dma_d_p_s <= dma_d_i; + end if; + end if; + end process; + + dma_d_s <= dma_d_n_s when turbo_i /= "10" else dma_d_p_s; + + dma_a_o <= dma_a_s; + dma_d_o <= dma_d_s; + + dma_mreq_n_o <= (not dma_mreq_cycle) or (dma_rd_n_s and dma_wr_n_s); + dma_iorq_n_o <= dma_mreq_cycle or (dma_rd_n_s and dma_wr_n_s) ; + + dma_rd_n_o <= dma_rd_n_s or not dma_read_cycle; + dma_wr_n_o <= dma_wr_n_s or not dma_write_cycle; + + -- dma state machine + + cpu_busreq_n_o <= cpu_busreq_n_s; + + process (clk_i) + + type reg_wr_seq_t is ( IDLE, R0_BYTE_0, R0_BYTE_1, R0_BYTE_2, R0_BYTE_3, R1_BYTE_0, R1_BYTE_1, R2_BYTE_0, R2_BYTE_1, R3_BYTE_0, R3_BYTE_1, R4_BYTE_0, R4_BYTE_1, R4_BYTE_2, R4_BYTE_3, R4_BYTE_4, R6_BYTE_0 ); + variable reg_wr_seq_s : reg_wr_seq_t; + + type reg_rd_seq_t is ( RD_STATUS, RD_COUNTER_HI, RD_COUNTER_LO, RD_PORT_A_LO, RD_PORT_A_HI, RD_PORT_B_LO, RD_PORT_B_HI ); + variable reg_rd_seq_s : reg_rd_seq_t; + + variable cs_wr_v : std_logic_vector(1 downto 0); + variable cs_rd_v : std_logic_vector(1 downto 0); + + + begin + if rising_edge(clk_i) then + + if reset_i = '1' then + + dma_seq_s <= IDLE; + + dma_a_s <= (others => '0'); + + dma_read_cycle <= '0'; + dma_write_cycle <= '0'; + dma_mreq_cycle <= '0'; + + dma_counter_s <= (others=>'0'); + + cpu_d_o <= (others=>'0'); + + cpu_busreq_n_s <= '1'; + cpu_bao_n <= cpu_bai_n; + --cpu_bao_n <= '1'; + + reg_wr_seq_s := IDLE; + + DMA_timer_s <= (others => '0'); + + R1_portA_timming_byte_s <= "01"; + R2_portB_timming_byte_s <= "01"; + R2_portB_preescaler_s <= X"00"; + R4_mode_s <= "01"; + R5_ce_wait_s <= '0'; + R5_auto_restart_s <= '0'; + R6_read_mask_s <= "01111111"; + + status_atleastone <= '0'; + status_endofblock_n <= '1'; + + read_count_s <= "000"; + reg_rd_seq_s := RD_STATUS; + + else + + --DMA prescalar counter + case turbo_i is + when "00" => DMA_timer_s <= DMA_timer_s + "00000000001000"; + when "01" => DMA_timer_s <= DMA_timer_s + "00000000000100"; + when "10" => DMA_timer_s <= DMA_timer_s + "00000000000010"; + when others => DMA_timer_s <= DMA_timer_s + "00000000000001"; + end case; + + --DMA transfer process + case dma_seq_s is + + when IDLE => + + cpu_busreq_n_s <= '1'; + cpu_bao_n <= cpu_bai_n; + + status_atleastone <= '0'; + + when START_DMA => + + if bus_busreq_n_i = '0' or cpu_bai_n = '0' or dma_delay_i = '1' then + + -- wait for other dma to finish + cpu_busreq_n_s <= '1'; + cpu_bao_n <= cpu_bai_n; + + else + + -- request the bus + cpu_busreq_n_s <= '0'; + cpu_bao_n <= '1'; + + dma_seq_s <= WAITING_ACK; + + end if; + + when WAITING_ACK => + + dma_a_s <= dma_src_s; + dma_write_cycle <= '0'; + + if (R0_dir_AtoB_s = '1' and R1_portAisIO_s = '0') or (R0_dir_AtoB_s = '0' and R2_portBisIO_s = '0') then + dma_mreq_cycle <= '1'; + else + dma_mreq_cycle <= '0'; + end if; + + if cpu_bai_n = '0' then + + dma_seq_s <= TRANSFERING_READ_1; + dma_read_cycle <= '1'; + + else + + dma_read_cycle <= '0'; + + end if; + + when TRANSFERING_READ_1 => + + DMA_timer_s <= (others => '0'); + + if R0_dir_AtoB_s = '1' then -- A -> B + case R1_portA_timming_byte_s(1 downto 0) is + when "00" => dma_seq_s <= TRANSFERING_READ_2; -- 4 cycles + when "01" => dma_seq_s <= TRANSFERING_READ_3; -- 3 cycles + when "10" => dma_seq_s <= TRANSFERING_READ_4; -- 2 cycles + when others => dma_seq_s <= TRANSFERING_READ_2; -- 4 cycles + end case; + else -- B -> A + case R2_portB_timming_byte_s(1 downto 0) is + when "00" => dma_seq_s <= TRANSFERING_READ_2; -- 4 cycles + when "01" => dma_seq_s <= TRANSFERING_READ_3; -- 3 cycles + when "10" => dma_seq_s <= TRANSFERING_READ_4; -- 2 cycles + when others => dma_seq_s <= TRANSFERING_READ_2; -- 4 cycles + end case; + end if; + + -- end if; + + when TRANSFERING_READ_2 => + -- dma_d_s <= dma_d_i; + dma_seq_s <= TRANSFERING_READ_3; + + when TRANSFERING_READ_3 => + -- dma_d_s <= dma_d_i; + dma_seq_s <= TRANSFERING_READ_4; + + when TRANSFERING_READ_4 => + + -- dma_d_s <= dma_d_i; + + -- if R5_ce_wait_s = '1' and wait_n_s = '0' then + if wait_n_s = '1' then + + dma_seq_s <= TRANSFERING_WRITE_1; + + dma_a_s <= dma_dest_s; + + dma_read_cycle <= '0'; + dma_write_cycle <= '1'; + + if (R0_dir_AtoB_s = '1' and R2_portBisIO_s = '0') or (R0_dir_AtoB_s = '0' and R1_portAisIO_s = '0') then + dma_mreq_cycle <= '1'; + else + dma_mreq_cycle <= '0'; + end if; + + end if; + + when TRANSFERING_WRITE_1 => + + dma_counter_s <= dma_counter_s + 1; + + if R0_dir_AtoB_s = '0' then -- B -> A + case R1_portA_timming_byte_s(1 downto 0) is + when "00" => dma_seq_s <= TRANSFERING_WRITE_2; -- 4 cycles + when "01" => dma_seq_s <= TRANSFERING_WRITE_3; -- 3 cycles + when "10" => dma_seq_s <= TRANSFERING_WRITE_4; -- 2 cycles + when others => dma_seq_s <= TRANSFERING_WRITE_2; -- 4 cycles + end case; + else -- A -> B + case R2_portB_timming_byte_s(1 downto 0) is + when "00" => dma_seq_s <= TRANSFERING_WRITE_2; -- 4 cycles + when "01" => dma_seq_s <= TRANSFERING_WRITE_3; -- 3 cycles + when "10" => dma_seq_s <= TRANSFERING_WRITE_4; -- 2 cycles + when others => dma_seq_s <= TRANSFERING_WRITE_2; -- 4 cycles + end case; + end if; + + if (R0_dir_AtoB_s = '1' and R1_portA_addrMode_s = "01") or + (R0_dir_AtoB_s = '0' and R2_portB_addrMode_s = "01") then + dma_src_s <= dma_src_s + 1; + end if; + + if (R0_dir_AtoB_s = '1' and R1_portA_addrMode_s = "00") or + (R0_dir_AtoB_s = '0' and R2_portB_addrMode_s = "00") then + dma_src_s <= dma_src_s - 1; + end if; + + if (R0_dir_AtoB_s = '1' and R2_portB_addrMode_s = "01") or + (R0_dir_AtoB_s = '0' and R1_portA_addrMode_s = "01") then + dma_dest_s <= dma_dest_s + 1; + end if; + + if (R0_dir_AtoB_s = '1' and R2_portB_addrMode_s = "00") or + (R0_dir_AtoB_s = '0' and R1_portA_addrMode_s = "00") then + dma_dest_s <= dma_dest_s - 1; + end if; + + when TRANSFERING_WRITE_2 => + + dma_seq_s <= TRANSFERING_WRITE_3; + + when TRANSFERING_WRITE_3 => + + dma_seq_s <= TRANSFERING_WRITE_4; + + when TRANSFERING_WRITE_4 => + + -- if R5_ce_wait_s = '1' and wait_n_s = '0' then + if wait_n_s = '1' then + + status_atleastone <= '1'; + + dma_a_s <= dma_src_s; + dma_write_cycle <= '0'; + + if (R0_dir_AtoB_s = '1' and R1_portAisIO_s = '0') or (R0_dir_AtoB_s = '0' and R2_portBisIO_s = '0') then + dma_mreq_cycle <= '1'; + else + dma_mreq_cycle <= '0'; + end if; + + -- check if we need to wait cycles before the next cycle + if (R2_portB_preescaler_s > 0) and (('0' & R2_portB_preescaler_s) > DMA_timer_s(13 downto 5)) then + dma_seq_s <= WAITING_CYCLES; + elsif dma_counter_s < R0_block_len_s then --TO DO: test for block len = 0 - check the datasheet! + if dma_delay_i = '1' then + dma_seq_s <= START_DMA; + else + dma_seq_s <= TRANSFERING_READ_1; + dma_read_cycle <= '1'; + end if; + else + dma_seq_s <= FINISH_DMA; + end if; + + end if; + + when WAITING_CYCLES => + + if R4_mode_s = "10" then -- burst mode + + --give time to CPU in burst mode + if ('0' & R2_portB_preescaler_s(7 downto 0)) > DMA_timer_s(13 downto 5) then + cpu_busreq_n_s <= '1'; --release bus + cpu_bao_n <= cpu_bai_n; --forward busak to other dma devices + end if; + + end if; + + if ('0' & R2_portB_preescaler_s) > DMA_timer_s(13 downto 5) then + dma_seq_s <= WAITING_CYCLES; + + elsif dma_counter_s < R0_block_len_s then --TO DO: test for block len = 0 - check the datasheet! + + if cpu_busreq_n_s = '1' then + -- bus was given up + dma_seq_s <= START_DMA; + else + dma_seq_s <= WAITING_ACK; + end if; + + else + dma_seq_s <= FINISH_DMA; + end if; + + + + when FINISH_DMA => + + status_endofblock_n <= '0'; + + if R5_auto_restart_s = '1' then --reload the values + if R0_dir_AtoB_s = '1' then -- direction - 0 = B -> A 1 = A -> B + dma_src_s <= R0_start_addr_port_A_s; + dma_dest_s <= R4_start_addr_port_B_s; + else + dma_src_s <= R4_start_addr_port_B_s; + dma_dest_s <= R0_start_addr_port_A_s; + end if; + + if dma_mode_i = '0' then + dma_counter_s <= (others=>'0'); + else + dma_counter_s <= (others=>'1'); -- z80 dma loads -1 + end if; + + if cpu_busreq_n_s = '1' then + dma_seq_s <= START_DMA; + else + dma_seq_s <= WAITING_ACK; + end if; + else + dma_seq_s <= IDLE; + end if; + + end case; + + --detect WR falling edge + cs_wr_v := cs_wr_v(0) & (not dma_en_wr_s); + + --detect RD falling edge + cs_rd_v := cs_rd_v(0) & (not dma_en_rd_s); + + if cs_wr_v = "10" then + --write in registers (only on falling edge of DMA CS and write) + + + case reg_wr_seq_s is + + when IDLE => + + -- Register 0 + if cpu_d_i(7) = '0' and (cpu_d_i(1) = '1' or cpu_d_i(0) = '1') then + + reg_temp <= cpu_d_i; + + R0_dir_AtoB_s <= cpu_d_i(2); + --R0_search_s <= cpu_d_i(1); + --R0_tranfer_s <= cpu_d_i(0); + + if cpu_d_i(3) = '1' then + reg_wr_seq_s := R0_BYTE_0; + elsif cpu_d_i(4) = '1' then + reg_wr_seq_s := R0_BYTE_1; + elsif cpu_d_i(5) = '1' then + reg_wr_seq_s := R0_BYTE_2; + elsif cpu_d_i(6) = '1' then + reg_wr_seq_s := R0_BYTE_3; + else + reg_wr_seq_s := IDLE; + end if; + + end if; + -- end of Register 0 + + -- Register 1 + if cpu_d_i(7) = '0' and cpu_d_i(2 downto 0) = "100" then + + reg_temp <= cpu_d_i; + + R1_portAisIO_s <= cpu_d_i(3); + R1_portA_addrMode_s <= cpu_d_i(5 downto 4); + + if cpu_d_i(6) = '0' then + reg_wr_seq_s := IDLE; + else + reg_wr_seq_s := R1_BYTE_0; + end if; + + end if; + -- end of Register 1 + + -- Register 2 + if cpu_d_i(7) = '0' and cpu_d_i(2 downto 0) = "000" then + + reg_temp <= cpu_d_i; + + R2_portBisIO_s <= cpu_d_i(3); + R2_portB_addrMode_s <= cpu_d_i(5 downto 4); + + if cpu_d_i(6) = '0' then + reg_wr_seq_s := IDLE; + else + reg_wr_seq_s := R2_BYTE_0; + end if; + + end if; + -- end of Register 2 + + -- Register 3 + if cpu_d_i(7) = '1' and cpu_d_i(1 downto 0) = "00" then + + reg_temp <= cpu_d_i; + + R3_dma_en_s <= cpu_d_i(6); + + if cpu_d_i(6) = '1' then + dma_seq_s <= START_DMA; + end if; + + --R3_int_en_s <= cpu_d_i(5); + --R3_stop_match_s <= cpu_d_i(2); + + if cpu_d_i(3) = '1' then + reg_wr_seq_s := R3_BYTE_0; + elsif cpu_d_i(4) = '1' then + reg_wr_seq_s := R3_BYTE_1; + else + reg_wr_seq_s := IDLE; + end if; + + end if; + -- end of Register 3 + + -- Register 4 + if cpu_d_i(7) = '1' and cpu_d_i(1 downto 0) = "01" then + + reg_temp <= cpu_d_i; + + R4_mode_s <= cpu_d_i(6 downto 5); + + if cpu_d_i(2) = '1' then + reg_wr_seq_s := R4_BYTE_0; + elsif cpu_d_i(3) = '1' then + reg_wr_seq_s := R4_BYTE_1; + elsif cpu_d_i(4) = '1' then + reg_wr_seq_s := R4_BYTE_2; + else + reg_wr_seq_s := IDLE; + end if; + + end if; + -- end of Register 4 + + -- Register 5 + if cpu_d_i(7 downto 6) = "10" and cpu_d_i(2 downto 0) = "010" then + + reg_temp <= cpu_d_i; + + -- R5_ready_act_hi_s <= cpu_d_i(3); + R5_ce_wait_s <= cpu_d_i(4); + R5_auto_restart_s <= cpu_d_i(5); + + reg_wr_seq_s := IDLE; + + end if; + -- end of Register 5 + + + -- Register 6 + if cpu_d_i(7) = '1' and cpu_d_i(1 downto 0) = "11" then + + reg_temp <= cpu_d_i; + reg_wr_seq_s := IDLE; + + if cpu_d_i(7 downto 0) = X"C3" then -- reset + dma_seq_s <= IDLE; + status_endofblock_n <= '1'; + status_atleastone <= '0'; + R1_portA_timming_byte_s <= "01"; + R2_portB_timming_byte_s <= "01"; + R2_portB_preescaler_s <= x"00"; + R5_ce_wait_s <= '0'; + R5_auto_restart_s <= '0'; + + elsif cpu_d_i(7 downto 0) = X"C7" then -- reset port A timming + R1_portA_timming_byte_s <= "01"; + + elsif cpu_d_i(7 downto 0) = X"CB" then -- reset port B timming + R2_portB_timming_byte_s <= "01"; + + elsif cpu_d_i(7 downto 0) = X"CF" then -- Load + status_endofblock_n <= '1'; + + if R0_dir_AtoB_s = '1' then -- direction - 0 = B -> A 1 = A -> B + dma_src_s <= R0_start_addr_port_A_s; + dma_dest_s <= R4_start_addr_port_B_s; + else + dma_src_s <= R4_start_addr_port_B_s; + dma_dest_s <= R0_start_addr_port_A_s; + end if; + + if dma_mode_i = '0' then + dma_counter_s <= (others=>'0'); + else + dma_counter_s <= (others=>'1'); -- z80 dma loads -1 + end if; + + elsif cpu_d_i(7 downto 0) = X"D3" then -- Continue + status_endofblock_n <= '1'; + + if dma_mode_i = '0' then + dma_counter_s <= (others=>'0'); + else + dma_counter_s <= (others=>'1'); -- z80 dma loads -1 + end if; + + elsif cpu_d_i(7 downto 0) = X"AF" then -- Disable Interrupts + + elsif cpu_d_i(7 downto 0) = X"AB" then -- Enable Interrupts + + elsif cpu_d_i(7 downto 0) = X"A3" then -- Reset and Disable Interrupts + + elsif cpu_d_i(7 downto 0) = X"B7" then -- Enable after RETI + + elsif cpu_d_i(7 downto 0) = X"BF" then -- Read Status byte + reg_rd_seq_s := RD_STATUS; + + elsif cpu_d_i(7 downto 0) = X"8B" then -- Reinitialize Status Byte + status_endofblock_n <= '1'; + status_atleastone <= '0'; + + elsif cpu_d_i(7 downto 0) = X"A7" then -- Initialize Read Sequence + + if R6_read_mask_s(0) = '1' then -- status byte + reg_rd_seq_s := RD_STATUS; + + elsif R6_read_mask_s(1) = '1' then -- byte counter LO + reg_rd_seq_s := RD_COUNTER_LO; + + elsif R6_read_mask_s(2) = '1' then -- byte counter HI + reg_rd_seq_s := RD_COUNTER_HI; + + elsif R6_read_mask_s(3) = '1' then -- port A address counter LO + reg_rd_seq_s := RD_PORT_A_LO; + + elsif R6_read_mask_s(4) = '1' then -- port A address counter HI + reg_rd_seq_s := RD_PORT_A_HI; + + elsif R6_read_mask_s(5) = '1' then -- port B address counter LO + reg_rd_seq_s := RD_PORT_B_LO; + + elsif R6_read_mask_s(6) = '1' then -- port B address counter HI + reg_rd_seq_s := RD_PORT_B_HI; + + else + reg_rd_seq_s := RD_STATUS; + + end if; + + elsif cpu_d_i(7 downto 0) = X"B3" then -- Force Ready + + elsif cpu_d_i(7 downto 0) = X"87" then -- Enable DMA + dma_seq_s <= START_DMA; + + elsif cpu_d_i(7 downto 0) = X"83" then -- Disable DMA + dma_seq_s <= IDLE; + + elsif cpu_d_i(7 downto 0) = X"BB" then -- Read mask follows + reg_wr_seq_s := R6_BYTE_0; + end if; + + end if; + -- end of Register 6 + + + when R0_BYTE_0 => + R0_start_addr_port_A_s(7 downto 0) <= cpu_d_i; + + if reg_temp(4) = '1' then + reg_wr_seq_s := R0_BYTE_1; + elsif reg_temp(5) = '1' then + reg_wr_seq_s := R0_BYTE_2; + elsif reg_temp(6) = '1' then + reg_wr_seq_s := R0_BYTE_3; + else + reg_wr_seq_s := IDLE; + end if; + + when R0_BYTE_1 => + R0_start_addr_port_A_s(15 downto 8) <= cpu_d_i; + + if reg_temp(5) = '1' then + reg_wr_seq_s := R0_BYTE_2; + elsif reg_temp(6) = '1' then + reg_wr_seq_s := R0_BYTE_3; + else + reg_wr_seq_s := IDLE; + end if; + + when R0_BYTE_2 => + R0_block_len_s(7 downto 0) <= cpu_d_i; + + if reg_temp(6) = '1' then + reg_wr_seq_s := R0_BYTE_3; + else + reg_wr_seq_s := IDLE; + end if; + + when R0_BYTE_3 => + R0_block_len_s(15 downto 8) <= cpu_d_i; + reg_wr_seq_s := IDLE; + + when R1_BYTE_0 => + R1_portA_timming_byte_s <= cpu_d_i(1 downto 0); + + if cpu_d_i(5) = '1' then + reg_wr_seq_s := R1_BYTE_1; + else + reg_wr_seq_s := IDLE; + end if; + + + when R1_BYTE_1 => + --R1_portA_preescaler_s <= cpu_d_i; + reg_wr_seq_s := IDLE; + + when R2_BYTE_0 => + R2_portB_timming_byte_s <= cpu_d_i(1 downto 0); + + if cpu_d_i(5) = '1' then + reg_wr_seq_s := R2_BYTE_1; + else + reg_wr_seq_s := IDLE; + end if; + + when R2_BYTE_1 => + R2_portB_preescaler_s <= cpu_d_i; + reg_wr_seq_s := IDLE; + + when R3_BYTE_0 => + --R3_mask_s <= cpu_d_i; + + if reg_temp(4) = '1' then + reg_wr_seq_s := R3_BYTE_1; + else + reg_wr_seq_s := IDLE; + end if; + + when R3_BYTE_1 => + --R3_match_s <= cpu_d_i; + reg_wr_seq_s := IDLE; + + when R4_BYTE_0 => + R4_start_addr_port_B_s(7 downto 0) <= cpu_d_i; + + if reg_temp(3) = '1' then + reg_wr_seq_s := R4_BYTE_1; + elsif reg_temp(4) = '1' then + reg_wr_seq_s := IDLE; --R4_BYTE_2; + else + reg_wr_seq_s := IDLE; + end if; + + when R4_BYTE_1 => + R4_start_addr_port_B_s(15 downto 8) <= cpu_d_i; + + -- if reg_temp(4) = '1' then + -- reg_wr_seq_s := R4_BYTE_2; + -- else + reg_wr_seq_s := IDLE; + -- end if; + + -- when R4_BYTE_2 => + -- R4_interrupt_control_s <= cpu_d_i; + -- + -- if cpu_d_i(3) = '1' then + -- reg_wr_seq_s := R4_BYTE_3; + -- elsif cpu_d_i(4) = '1' then + -- reg_wr_seq_s := R4_BYTE_4; + -- else + -- reg_wr_seq_s := IDLE; + -- end if; + -- + -- when R4_BYTE_3 => + -- R4_pulse_control_s <= cpu_d_i; + -- + -- if R4_interrupt_control_s(4) = '1' then + -- reg_wr_seq_s := R4_BYTE_4; + -- else + -- reg_wr_seq_s := IDLE; + -- end if; + -- + -- when R4_BYTE_4 => + -- R4_interrupt_vector_s <= cpu_d_i; + -- reg_wr_seq_s := IDLE; + + when R6_BYTE_0 => + R6_read_mask_s <= cpu_d_i; + + if cpu_d_i(0) = '1' then -- status byte + reg_rd_seq_s := RD_STATUS; + + elsif cpu_d_i(1) = '1' then -- byte counter LO + reg_rd_seq_s := RD_COUNTER_LO; + + elsif cpu_d_i(2) = '1' then -- byte counter HI + reg_rd_seq_s := RD_COUNTER_HI; + + elsif cpu_d_i(3) = '1' then -- port A address counter LO + reg_rd_seq_s := RD_PORT_A_LO; + + elsif cpu_d_i(4) = '1' then -- port A address counter HI + reg_rd_seq_s := RD_PORT_A_HI; + + elsif cpu_d_i(5) = '1' then -- port B address counter LO + reg_rd_seq_s := RD_PORT_B_LO; + + elsif cpu_d_i(6) = '1' then -- port B address counter HI + reg_rd_seq_s := RD_PORT_B_HI; + + else + reg_rd_seq_s := RD_STATUS; + + end if; + + reg_wr_seq_s := IDLE; + + + when others => null; + end case; + + + elsif cs_rd_v = "10" then + --read from registers (only on falling edge of DMA CS and RD) + + case reg_rd_seq_s is + + when RD_STATUS => + + cpu_d_o <= "00" & status_endofblock_n & "1101" & status_atleastone; + + if R6_read_mask_s(1) = '1' then -- byte counter LO + reg_rd_seq_s := RD_COUNTER_LO; + + elsif R6_read_mask_s(2) = '1' then -- byte counter HI + reg_rd_seq_s := RD_COUNTER_HI; + + elsif R6_read_mask_s(3) = '1' then -- port A address counter LO + reg_rd_seq_s := RD_PORT_A_LO; + + elsif R6_read_mask_s(4) = '1' then -- port A address counter HI + reg_rd_seq_s := RD_PORT_A_HI; + + elsif R6_read_mask_s(5) = '1' then -- port B address counter LO + reg_rd_seq_s := RD_PORT_B_LO; + + elsif R6_read_mask_s(6) = '1' then -- port B address counter HI + reg_rd_seq_s := RD_PORT_B_HI; + + --elsif R6_read_mask_s(0) = '1' then -- status byte + -- reg_rd_seq_s := RD_STATUS; + + else + reg_rd_seq_s := RD_STATUS; + + end if; + + + when RD_COUNTER_LO => + + cpu_d_o <= dma_counter_s(7 downto 0); + + if R6_read_mask_s(2) = '1' then -- byte counter HI + reg_rd_seq_s := RD_COUNTER_HI; + + elsif R6_read_mask_s(3) = '1' then -- port A address counter LO + reg_rd_seq_s := RD_PORT_A_LO; + + elsif R6_read_mask_s(4) = '1' then -- port A address counter HI + reg_rd_seq_s := RD_PORT_A_HI; + + elsif R6_read_mask_s(5) = '1' then -- port B address counter LO + reg_rd_seq_s := RD_PORT_B_LO; + + elsif R6_read_mask_s(6) = '1' then -- port B address counter HI + reg_rd_seq_s := RD_PORT_B_HI; + + elsif R6_read_mask_s(0) = '1' then -- status byte + reg_rd_seq_s := RD_STATUS; + + elsif R6_read_mask_s(1) = '1' then -- byte counter LO + reg_rd_seq_s := RD_COUNTER_LO; + + else + reg_rd_seq_s := RD_STATUS; + + end if; + + + when RD_COUNTER_HI => + + cpu_d_o <= dma_counter_s(15 downto 8); + + if R6_read_mask_s(3) = '1' then -- port A address counter LO + reg_rd_seq_s := RD_PORT_A_LO; + + elsif R6_read_mask_s(4) = '1' then -- port A address counter HI + reg_rd_seq_s := RD_PORT_A_HI; + + elsif R6_read_mask_s(5) = '1' then -- port B address counter LO + reg_rd_seq_s := RD_PORT_B_LO; + + elsif R6_read_mask_s(6) = '1' then -- port B address counter HI + reg_rd_seq_s := RD_PORT_B_HI; + + elsif R6_read_mask_s(0) = '1' then -- status byte + reg_rd_seq_s := RD_STATUS; + + elsif R6_read_mask_s(1) = '1' then -- byte counter LO + reg_rd_seq_s := RD_COUNTER_LO; + + elsif R6_read_mask_s(2) = '1' then -- byte counter HI + reg_rd_seq_s := RD_COUNTER_HI; + + else + reg_rd_seq_s := RD_STATUS; + + end if; + + + when RD_PORT_A_LO => + + + if R0_dir_AtoB_s = '1' then -- direction - 0 = B -> A 1 = A -> B + cpu_d_o <= dma_src_s(7 downto 0); + else + cpu_d_o <= dma_dest_s(7 downto 0); + end if; + + if R6_read_mask_s(4) = '1' then -- port A address counter HI + reg_rd_seq_s := RD_PORT_A_HI; + + elsif R6_read_mask_s(5) = '1' then -- port B address counter LO + reg_rd_seq_s := RD_PORT_B_LO; + + elsif R6_read_mask_s(6) = '1' then -- port B address counter HI + reg_rd_seq_s := RD_PORT_B_HI; + + elsif R6_read_mask_s(0) = '1' then -- status byte + reg_rd_seq_s := RD_STATUS; + + elsif R6_read_mask_s(1) = '1' then -- byte counter LO + reg_rd_seq_s := RD_COUNTER_LO; + + elsif R6_read_mask_s(2) = '1' then -- byte counter HI + reg_rd_seq_s := RD_COUNTER_HI; + + elsif R6_read_mask_s(3) = '1' then -- port A address counter LO + reg_rd_seq_s := RD_PORT_A_LO; + + else + reg_rd_seq_s := RD_STATUS; + + end if; + + + + when RD_PORT_A_HI => + + if R0_dir_AtoB_s = '1' then -- direction - 0 = B -> A 1 = A -> B + cpu_d_o <= dma_src_s(15 downto 8); + else + cpu_d_o <= dma_dest_s(15 downto 8); + end if; + + if R6_read_mask_s(5) = '1' then -- port B address counter LO + reg_rd_seq_s := RD_PORT_B_LO; + + elsif R6_read_mask_s(6) = '1' then -- port B address counter HI + reg_rd_seq_s := RD_PORT_B_HI; + + elsif R6_read_mask_s(0) = '1' then -- status byte + reg_rd_seq_s := RD_STATUS; + + elsif R6_read_mask_s(1) = '1' then -- byte counter LO + reg_rd_seq_s := RD_COUNTER_LO; + + elsif R6_read_mask_s(2) = '1' then -- byte counter HI + reg_rd_seq_s := RD_COUNTER_HI; + + elsif R6_read_mask_s(3) = '1' then -- port A address counter LO + reg_rd_seq_s := RD_PORT_A_LO; + + elsif R6_read_mask_s(4) = '1' then -- port A address counter HI + reg_rd_seq_s := RD_PORT_A_HI; + + else + reg_rd_seq_s := RD_STATUS; + + end if; + + + when RD_PORT_B_LO => + + if R0_dir_AtoB_s = '1' then -- direction - 0 = B -> A 1 = A -> B + cpu_d_o <= dma_dest_s(7 downto 0); + else + cpu_d_o <= dma_src_s(7 downto 0); + end if; + + if R6_read_mask_s(6) = '1' then -- port B address counter HI + reg_rd_seq_s := RD_PORT_B_HI; + + elsif R6_read_mask_s(0) = '1' then -- status byte + reg_rd_seq_s := RD_STATUS; + + elsif R6_read_mask_s(1) = '1' then -- byte counter LO + reg_rd_seq_s := RD_COUNTER_LO; + + elsif R6_read_mask_s(2) = '1' then -- byte counter HI + reg_rd_seq_s := RD_COUNTER_HI; + + elsif R6_read_mask_s(3) = '1' then -- port A address counter LO + reg_rd_seq_s := RD_PORT_A_LO; + + elsif R6_read_mask_s(4) = '1' then -- port A address counter HI + reg_rd_seq_s := RD_PORT_A_HI; + + elsif R6_read_mask_s(5) = '1' then -- port B address counter LO + reg_rd_seq_s := RD_PORT_B_LO; + + else + reg_rd_seq_s := RD_STATUS; + + end if; + + + when RD_PORT_B_HI => + + if R0_dir_AtoB_s = '1' then -- direction - 0 = B -> A 1 = A -> B + cpu_d_o <= dma_dest_s(15 downto 8); + else + cpu_d_o <= dma_src_s(15 downto 8); + end if; + + if R6_read_mask_s(0) = '1' then -- status byte + reg_rd_seq_s := RD_STATUS; + + elsif R6_read_mask_s(1) = '1' then -- byte counter LO + reg_rd_seq_s := RD_COUNTER_LO; + + elsif R6_read_mask_s(2) = '1' then -- byte counter HI + reg_rd_seq_s := RD_COUNTER_HI; + + elsif R6_read_mask_s(3) = '1' then -- port A address counter LO + reg_rd_seq_s := RD_PORT_A_LO; + + elsif R6_read_mask_s(4) = '1' then -- port A address counter HI + reg_rd_seq_s := RD_PORT_A_HI; + + elsif R6_read_mask_s(5) = '1' then -- port B address counter LO + reg_rd_seq_s := RD_PORT_B_LO; + + elsif R6_read_mask_s(6) = '1' then -- port B address counter HI + reg_rd_seq_s := RD_PORT_B_HI; + + else + reg_rd_seq_s := RD_STATUS; + + end if; + + + when others => + + cpu_d_o <= X"00"; + reg_rd_seq_s := RD_STATUS; + + end case; + + end if; + + end if; + end if; + end process; + +end z80dma_unit; diff --git a/rtl/device/im2_control.vhd b/rtl/device/im2_control.vhd new file mode 100644 index 0000000..3c9a566 --- /dev/null +++ b/rtl/device/im2_control.vhd @@ -0,0 +1,206 @@ +-- Z80 IM2 CONTROL BLOCK +-- Copyright 2020 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- +-- 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; diff --git a/rtl/device/im2_device.vhd b/rtl/device/im2_device.vhd new file mode 100644 index 0000000..46a9655 --- /dev/null +++ b/rtl/device/im2_device.vhd @@ -0,0 +1,164 @@ +-- Z80 IM2 DEVICE +-- Copyright 2020 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- +-- 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; diff --git a/rtl/device/im2_peripheral.vhd b/rtl/device/im2_peripheral.vhd new file mode 100644 index 0000000..782e7eb --- /dev/null +++ b/rtl/device/im2_peripheral.vhd @@ -0,0 +1,153 @@ +-- Z80 IM2 DEVICE +-- Copyright 2020 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- +-- 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; diff --git a/rtl/device/multiface.vhd b/rtl/device/multiface.vhd new file mode 100644 index 0000000..d5ff781 --- /dev/null +++ b/rtl/device/multiface.vhd @@ -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 +-- +-- +-- 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 +-- . + +-- 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; diff --git a/rtl/device/peripherals.vhd b/rtl/device/peripherals.vhd new file mode 100644 index 0000000..76ceb91 --- /dev/null +++ b/rtl/device/peripherals.vhd @@ -0,0 +1,180 @@ +-- INTERRUPTING PERIPHERALS +-- Copyright 2020 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- +-- 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; diff --git a/rtl/input/keyboard/keymaps.vhd b/rtl/input/keyboard/keymaps.vhd new file mode 100644 index 0000000..f1beffa --- /dev/null +++ b/rtl/input/keyboard/keymaps.vhd @@ -0,0 +1,188 @@ + +-- PS2 Keymap +-- Copyright 2020 Fabio Belavenuto +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +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; diff --git a/rtl/input/keyboard/ps2_iobase.vhd b/rtl/input/keyboard/ps2_iobase.vhd new file mode 100644 index 0000000..24d5e91 --- /dev/null +++ b/rtl/input/keyboard/ps2_iobase.vhd @@ -0,0 +1,282 @@ + +-- Copyright 2010 Thiago Borges Abdnur +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- 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; diff --git a/rtl/input/keyboard/ps2_keyb.vhd b/rtl/input/keyboard/ps2_keyb.vhd new file mode 100644 index 0000000..8babfc7 --- /dev/null +++ b/rtl/input/keyboard/ps2_keyb.vhd @@ -0,0 +1,364 @@ +-- PS2 Keyboard +-- Copyright 2020 Fabio Belavenuto +-- Copyright 2021 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- 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; diff --git a/rtl/input/md6_joystick_connector_x2.vhd b/rtl/input/md6_joystick_connector_x2.vhd new file mode 100644 index 0000000..c8348da --- /dev/null +++ b/rtl/input/md6_joystick_connector_x2.vhd @@ -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 +-- +-- +-- 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 +-- . + +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; diff --git a/rtl/input/membrane/emu_fnkeys.vhd b/rtl/input/membrane/emu_fnkeys.vhd new file mode 100644 index 0000000..471a8b1 --- /dev/null +++ b/rtl/input/membrane/emu_fnkeys.vhd @@ -0,0 +1,238 @@ + +-- Function Keys Emulation +-- Copyright 2020 Fabio Belavenuto and Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +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; diff --git a/rtl/input/membrane/membrane.vhd b/rtl/input/membrane/membrane.vhd new file mode 100644 index 0000000..ff77eb1 --- /dev/null +++ b/rtl/input/membrane/membrane.vhd @@ -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 +-- +-- +-- 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 +-- . + +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; diff --git a/rtl/input/membrane/membrane_stick.vhd b/rtl/input/membrane/membrane_stick.vhd new file mode 100644 index 0000000..5326add --- /dev/null +++ b/rtl/input/membrane/membrane_stick.vhd @@ -0,0 +1,200 @@ + +-- User Definable Keyboard Joystick +-- Copyright 2021 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +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; diff --git a/rtl/input/ps2_mouse.v b/rtl/input/ps2_mouse.v new file mode 100644 index 0000000..7f86d6b --- /dev/null +++ b/rtl/input/ps2_mouse.v @@ -0,0 +1,351 @@ + +// PS2 Mouse +// Copyright 2006, 2007 Dennis van Weeren +// +// This file is part of the ZX Spectrum Next Project +// +// +// 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 +// . +// +// 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 diff --git a/rtl/misc/asymmetrical_debounce.vhd b/rtl/misc/asymmetrical_debounce.vhd new file mode 100644 index 0000000..dac8d7d --- /dev/null +++ b/rtl/misc/asymmetrical_debounce.vhd @@ -0,0 +1,84 @@ + +-- Asymmetrical Button Debounce +-- Copyright 2020 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- 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; diff --git a/rtl/misc/debounce.vhd b/rtl/misc/debounce.vhd new file mode 100644 index 0000000..623b4e5 --- /dev/null +++ b/rtl/misc/debounce.vhd @@ -0,0 +1,87 @@ + +-- Button Debounce +-- Copyright 2020 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +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; diff --git a/rtl/misc/flashboot.vhd b/rtl/misc/flashboot.vhd new file mode 100644 index 0000000..2acfa60 --- /dev/null +++ b/rtl/misc/flashboot.vhd @@ -0,0 +1,182 @@ +-- Flashboot +-- Copyright 2020 Fabio Belavenuto and Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +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; diff --git a/rtl/misc/flashboot_old.vhd b/rtl/misc/flashboot_old.vhd new file mode 100644 index 0000000..6ff848c --- /dev/null +++ b/rtl/misc/flashboot_old.vhd @@ -0,0 +1,228 @@ + +-- Flashboot +-- Copyright 2020 Fabio Belavenuto +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +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; diff --git a/rtl/misc/synchronize.vhd b/rtl/misc/synchronize.vhd new file mode 100644 index 0000000..0b2f2a1 --- /dev/null +++ b/rtl/misc/synchronize.vhd @@ -0,0 +1,55 @@ + +-- Async Input Synchronization +-- Copyright 2020 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +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; diff --git a/rtl/mister/bram.vhd b/rtl/mister/bram.vhd new file mode 100644 index 0000000..f52e3ee --- /dev/null +++ b/rtl/mister/bram.vhd @@ -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; diff --git a/rtl/mister/keyjoy_sdpram_64_6.mif b/rtl/mister/keyjoy_sdpram_64_6.mif new file mode 100644 index 0000000..99f8af8 --- /dev/null +++ b/rtl/mister/keyjoy_sdpram_64_6.mif @@ -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; diff --git a/rtl/mister/ps2_keyb.vhd b/rtl/mister/ps2_keyb.vhd new file mode 100644 index 0000000..f30b3b7 --- /dev/null +++ b/rtl/mister/ps2_keyb.vhd @@ -0,0 +1,208 @@ +-- PS2 Keyboard +-- Copyright 2020 Fabio Belavenuto +-- Copyright 2021 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- 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; diff --git a/rtl/mister/sdram.sv b/rtl/mister/sdram.sv new file mode 100644 index 0000000..31acdc3 --- /dev/null +++ b/rtl/mister/sdram.sv @@ -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 diff --git a/rtl/mister/zxnext_top.vhd b/rtl/mister/zxnext_top.vhd new file mode 100644 index 0000000..a2e50f7 --- /dev/null +++ b/rtl/mister/zxnext_top.vhd @@ -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 +-- +-- +-- 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 +-- . + +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; diff --git a/rtl/pll.qip b/rtl/pll.qip new file mode 100644 index 0000000..ee13e21 --- /dev/null +++ b/rtl/pll.qip @@ -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" diff --git a/rtl/pll.v b/rtl/pll.v new file mode 100644 index 0000000..fbed763 --- /dev/null +++ b/rtl/pll.v @@ -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: +// +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// IPFS_FILES : pll.vo +// RELATED_FILES: pll.v, pll_0002.v diff --git a/rtl/pll/pll_0002.qip b/rtl/pll/pll_0002.qip new file mode 100644 index 0000000..aec45eb --- /dev/null +++ b/rtl/pll/pll_0002.qip @@ -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*|*" diff --git a/rtl/pll/pll_0002.v b/rtl/pll/pll_0002.v new file mode 100644 index 0000000..25d8a48 --- /dev/null +++ b/rtl/pll/pll_0002.v @@ -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 + diff --git a/rtl/rom/bootrom.vhd b/rtl/rom/bootrom.vhd new file mode 100644 index 0000000..46c39fe --- /dev/null +++ b/rtl/rom/bootrom.vhd @@ -0,0 +1,1055 @@ +-- generated with romgen v3.0 by MikeJ +-- (machine generated file) + +library ieee; + use ieee.std_logic_1164.all; + use ieee.std_logic_unsigned.all; + use ieee.numeric_std.all; + +entity bootrom is + port ( + CLK : in std_logic; + ADDR : in std_logic_vector(12 downto 0); + DATA : out std_logic_vector(7 downto 0) + ); +end; + +architecture RTL of bootrom is + + + type ROM_ARRAY is array(0 to 8191) of std_logic_vector(7 downto 0); + constant ROM : ROM_ARRAY := ( + x"F3",x"ED",x"56",x"C3",x"80",x"00",x"FF",x"FF", -- 0x0000 + x"ED",x"4D",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x0008 + x"ED",x"4D",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x0010 + x"ED",x"4D",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x0018 + x"ED",x"4D",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x0020 + x"ED",x"4D",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x0028 + x"ED",x"4D",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x0030 + x"ED",x"4D",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x0038 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x0040 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x0048 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x0050 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x0058 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"ED",x"45", -- 0x0060 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x0068 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x0070 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x0078 + x"31",x"FF",x"FF",x"CD",x"C7",x"1C",x"CD",x"45", -- 0x0080 + x"01",x"C3",x"00",x"01",x"FF",x"FF",x"FF",x"FF", -- 0x0088 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x0090 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x0098 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x00A0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x00A8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x00B0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x00B8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x00C0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x00C8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x00D0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x00D8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x00E0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x00E8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x00F0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x00F8 + x"76",x"18",x"FD",x"01",x"00",x"58",x"69",x"60", -- 0x0100 + x"36",x"47",x"03",x"78",x"D6",x"5B",x"38",x"F6", -- 0x0108 + x"3E",x"FF",x"D3",x"E7",x"C1",x"E1",x"E5",x"C5", -- 0x0110 + x"E5",x"CD",x"18",x"1B",x"F1",x"4D",x"CB",x"3C", -- 0x0118 + x"CB",x"19",x"21",x"01",x"F8",x"3E",x"10",x"91", -- 0x0120 + x"77",x"3E",x"02",x"D3",x"FE",x"3E",x"0C",x"F5", -- 0x0128 + x"33",x"3A",x"01",x"F8",x"F5",x"33",x"CD",x"F5", -- 0x0130 + x"19",x"F1",x"C1",x"E1",x"E5",x"C5",x"E5",x"CD", -- 0x0138 + x"05",x"1B",x"F1",x"18",x"FE",x"21",x"E5",x"FF", -- 0x0140 + x"39",x"F9",x"21",x"09",x"00",x"39",x"AF",x"77", -- 0x0148 + x"23",x"77",x"3E",x"00",x"D3",x"FE",x"3E",x"00", -- 0x0150 + x"01",x"3B",x"24",x"ED",x"79",x"3E",x"25",x"DB", -- 0x0158 + x"3B",x"FD",x"21",x"03",x"00",x"FD",x"39",x"FD", -- 0x0160 + x"77",x"00",x"3E",x"01",x"01",x"3B",x"24",x"ED", -- 0x0168 + x"79",x"3E",x"25",x"DB",x"3B",x"3E",x"02",x"01", -- 0x0170 + x"3B",x"24",x"ED",x"79",x"3E",x"25",x"DB",x"3B", -- 0x0178 + x"3E",x"10",x"01",x"3B",x"24",x"ED",x"79",x"3E", -- 0x0180 + x"25",x"DB",x"3B",x"E6",x"03",x"FD",x"21",x"02", -- 0x0188 + x"00",x"FD",x"39",x"FD",x"77",x"00",x"FD",x"21", -- 0x0190 + x"06",x"00",x"FD",x"39",x"FD",x"36",x"00",x"00", -- 0x0198 + x"3E",x"7F",x"DB",x"FE",x"0F",x"38",x"0A",x"FD", -- 0x01A0 + x"21",x"06",x"00",x"FD",x"39",x"FD",x"36",x"00", -- 0x01A8 + x"01",x"CD",x"84",x"18",x"21",x"00",x"F8",x"36", -- 0x01B0 + x"0A",x"3A",x"00",x"F8",x"B7",x"28",x"2D",x"CD", -- 0x01B8 + x"5F",x"04",x"7D",x"B7",x"20",x"08",x"21",x"D9", -- 0x01C0 + x"03",x"E5",x"CD",x"03",x"01",x"F1",x"CD",x"DD", -- 0x01C8 + x"07",x"7D",x"B7",x"20",x"17",x"21",x"00",x"F8", -- 0x01D0 + x"35",x"01",x"E8",x"FD",x"0B",x"78",x"B1",x"20", -- 0x01D8 + x"FB",x"21",x"09",x"00",x"39",x"36",x"E8",x"23", -- 0x01E0 + x"36",x"FD",x"18",x"CD",x"3A",x"00",x"F8",x"B7", -- 0x01E8 + x"20",x"08",x"21",x"F5",x"03",x"E5",x"CD",x"03", -- 0x01F0 + x"01",x"F1",x"FD",x"21",x"05",x"00",x"FD",x"39", -- 0x01F8 + x"FD",x"36",x"00",x"00",x"FD",x"21",x"04",x"00", -- 0x0200 + x"FD",x"39",x"FD",x"36",x"00",x"00",x"21",x"0B", -- 0x0208 + x"00",x"39",x"FD",x"21",x"19",x"00",x"FD",x"39", -- 0x0210 + x"FD",x"75",x"00",x"FD",x"74",x"01",x"FD",x"4E", -- 0x0218 + x"00",x"FD",x"46",x"01",x"2A",x"39",x"FC",x"E5", -- 0x0220 + x"C5",x"CD",x"3D",x"10",x"F1",x"F1",x"7D",x"B7", -- 0x0228 + x"28",x"0A",x"FD",x"21",x"05",x"00",x"FD",x"39", -- 0x0230 + x"FD",x"36",x"00",x"01",x"3E",x"DF",x"DB",x"FE", -- 0x0238 + x"E6",x"08",x"20",x"0A",x"FD",x"21",x"04",x"00", -- 0x0240 + x"FD",x"39",x"FD",x"36",x"00",x"01",x"21",x"03", -- 0x0248 + x"00",x"39",x"7E",x"D6",x"FA",x"20",x"25",x"21", -- 0x0250 + x"02",x"00",x"39",x"7E",x"D6",x"03",x"20",x"0C", -- 0x0258 + x"FD",x"21",x"04",x"00",x"FD",x"39",x"FD",x"36", -- 0x0260 + x"00",x"01",x"18",x"10",x"3E",x"10",x"01",x"3B", -- 0x0268 + x"24",x"ED",x"79",x"3E",x"80",x"01",x"3B",x"25", -- 0x0270 + x"ED",x"79",x"18",x"FE",x"21",x"19",x"00",x"39", -- 0x0278 + x"4E",x"23",x"46",x"2A",x"3B",x"FC",x"E5",x"C5", -- 0x0280 + x"CD",x"3D",x"10",x"F1",x"F1",x"7D",x"B7",x"20", -- 0x0288 + x"08",x"21",x"0D",x"04",x"E5",x"CD",x"03",x"01", -- 0x0290 + x"F1",x"11",x"02",x"F8",x"21",x"19",x"00",x"39", -- 0x0298 + x"4E",x"23",x"46",x"D5",x"C5",x"CD",x"EF",x"13", -- 0x02A0 + x"F1",x"F1",x"7D",x"B7",x"20",x"08",x"21",x"2A", -- 0x02A8 + x"04",x"E5",x"CD",x"03",x"01",x"F1",x"21",x"05", -- 0x02B0 + x"00",x"39",x"7E",x"3D",x"20",x"12",x"21",x"04", -- 0x02B8 + x"00",x"39",x"7E",x"3D",x"20",x"0A",x"FD",x"21", -- 0x02C0 + x"06",x"00",x"FD",x"39",x"FD",x"36",x"00",x"02", -- 0x02C8 + x"3E",x"FE",x"DB",x"FE",x"E6",x"08",x"20",x"0A", -- 0x02D0 + x"FD",x"21",x"06",x"00",x"FD",x"39",x"FD",x"36", -- 0x02D8 + x"00",x"03",x"FD",x"21",x"06",x"00",x"FD",x"39", -- 0x02E0 + x"FD",x"6E",x"00",x"26",x"00",x"29",x"29",x"EB", -- 0x02E8 + x"21",x"02",x"F8",x"19",x"4E",x"06",x"00",x"6B", -- 0x02F0 + x"62",x"23",x"3E",x"02",x"85",x"6F",x"3E",x"F8", -- 0x02F8 + x"8C",x"67",x"66",x"2E",x"00",x"09",x"FD",x"21", -- 0x0300 + x"17",x"00",x"FD",x"39",x"FD",x"75",x"00",x"FD", -- 0x0308 + x"74",x"01",x"4B",x"42",x"03",x"03",x"21",x"02", -- 0x0310 + x"F8",x"09",x"4E",x"06",x"00",x"13",x"13",x"13", -- 0x0318 + x"21",x"02",x"F8",x"19",x"66",x"2E",x"00",x"09", -- 0x0320 + x"FD",x"21",x"07",x"00",x"FD",x"39",x"FD",x"75", -- 0x0328 + x"00",x"FD",x"74",x"01",x"21",x"19",x"00",x"39", -- 0x0330 + x"4E",x"23",x"46",x"21",x"09",x"00",x"39",x"5E", -- 0x0338 + x"23",x"56",x"21",x"17",x"00",x"39",x"7B",x"96", -- 0x0340 + x"7A",x"23",x"9E",x"30",x"25",x"21",x"02",x"F8", -- 0x0348 + x"C5",x"FD",x"E1",x"C5",x"D5",x"E5",x"FD",x"E5", -- 0x0350 + x"CD",x"EF",x"13",x"F1",x"F1",x"D1",x"C1",x"7D", -- 0x0358 + x"B7",x"20",x"0C",x"C5",x"D5",x"21",x"2A",x"04", -- 0x0360 + x"E5",x"CD",x"03",x"01",x"F1",x"D1",x"C1",x"13", -- 0x0368 + x"18",x"D0",x"21",x"09",x"00",x"39",x"AF",x"77", -- 0x0370 + x"23",x"77",x"21",x"00",x"60",x"E3",x"21",x"07", -- 0x0378 + x"00",x"39",x"FD",x"21",x"09",x"00",x"FD",x"39", -- 0x0380 + x"FD",x"7E",x"00",x"96",x"FD",x"7E",x"01",x"23", -- 0x0388 + x"9E",x"30",x"39",x"21",x"19",x"00",x"39",x"4E", -- 0x0390 + x"23",x"46",x"E1",x"E5",x"E5",x"C5",x"CD",x"EF", -- 0x0398 + x"13",x"F1",x"F1",x"7D",x"B7",x"20",x"08",x"21", -- 0x03A0 + x"2A",x"04",x"E5",x"CD",x"03",x"01",x"F1",x"FD", -- 0x03A8 + x"21",x"09",x"00",x"FD",x"39",x"FD",x"34",x"00", -- 0x03B0 + x"20",x"03",x"FD",x"34",x"01",x"21",x"00",x"00", -- 0x03B8 + x"39",x"7E",x"C6",x"00",x"77",x"23",x"7E",x"CE", -- 0x03C0 + x"02",x"77",x"18",x"B2",x"3E",x"FF",x"D3",x"E7", -- 0x03C8 + x"C3",x"00",x"60",x"21",x"1B",x"00",x"39",x"F9", -- 0x03D0 + x"C9",x"45",x"72",x"72",x"6F",x"72",x"20",x"69", -- 0x03D8 + x"6E",x"69",x"74",x"69",x"61",x"6C",x"69",x"7A", -- 0x03E0 + x"69",x"6E",x"67",x"20",x"53",x"44",x"20",x"63", -- 0x03E8 + x"61",x"72",x"64",x"21",x"00",x"45",x"72",x"72", -- 0x03F0 + x"6F",x"72",x"20",x"6D",x"6F",x"75",x"6E",x"74", -- 0x03F8 + x"69",x"6E",x"67",x"20",x"53",x"44",x"20",x"63", -- 0x0400 + x"61",x"72",x"64",x"21",x"00",x"45",x"72",x"72", -- 0x0408 + x"6F",x"72",x"20",x"6F",x"70",x"65",x"6E",x"69", -- 0x0410 + x"6E",x"67",x"20",x"54",x"42",x"42",x"4C",x"55", -- 0x0418 + x"45",x"2E",x"46",x"57",x"20",x"66",x"69",x"6C", -- 0x0420 + x"65",x"00",x"45",x"72",x"72",x"6F",x"72",x"20", -- 0x0428 + x"72",x"65",x"61",x"64",x"69",x"6E",x"67",x"20", -- 0x0430 + x"54",x"42",x"42",x"4C",x"55",x"45",x"2E",x"46", -- 0x0438 + x"57",x"20",x"66",x"69",x"6C",x"65",x"00",x"54", -- 0x0440 + x"42",x"42",x"4C",x"55",x"45",x"20",x"20",x"54", -- 0x0448 + x"42",x"55",x"00",x"54",x"42",x"42",x"4C",x"55", -- 0x0450 + x"45",x"20",x"20",x"46",x"57",x"20",x"00",x"3E", -- 0x0458 + x"FF",x"D3",x"E7",x"06",x"0A",x"3E",x"FF",x"D3", -- 0x0460 + x"EB",x"10",x"FA",x"3E",x"FE",x"D3",x"E7",x"3E", -- 0x0468 + x"4C",x"CD",x"78",x"05",x"06",x"09",x"DB",x"EB", -- 0x0470 + x"10",x"FC",x"06",x"10",x"3E",x"40",x"11",x"00", -- 0x0478 + x"00",x"C5",x"CD",x"52",x"05",x"C1",x"D2",x"92", -- 0x0480 + x"04",x"10",x"F1",x"2E",x"00",x"3E",x"FF",x"D3", -- 0x0488 + x"E7",x"C9",x"3E",x"48",x"11",x"AA",x"01",x"CD", -- 0x0490 + x"5F",x"05",x"21",x"36",x"05",x"38",x"03",x"21", -- 0x0498 + x"44",x"05",x"01",x"78",x"00",x"C5",x"CD",x"B9", -- 0x04A0 + x"04",x"C1",x"D2",x"BA",x"04",x"10",x"F6",x"0D", -- 0x04A8 + x"20",x"F3",x"2E",x"00",x"3E",x"FF",x"D3",x"E7", -- 0x04B0 + x"C9",x"E9",x"3E",x"7A",x"11",x"00",x"00",x"CD", -- 0x04B8 + x"5F",x"05",x"DA",x"B2",x"04",x"78",x"E6",x"40", -- 0x04C0 + x"32",x"02",x"FA",x"CC",x"DD",x"04",x"3E",x"FF", -- 0x04C8 + x"D3",x"E7",x"3A",x"02",x"FA",x"2E",x"03",x"FE", -- 0x04D0 + x"40",x"C8",x"2E",x"02",x"C9",x"3E",x"50",x"01", -- 0x04D8 + x"00",x"00",x"11",x"00",x"02",x"C3",x"3D",x"05", -- 0x04E0 + x"FD",x"21",x"00",x"00",x"FD",x"39",x"FD",x"5E", -- 0x04E8 + x"02",x"FD",x"56",x"03",x"FD",x"4E",x"04",x"FD", -- 0x04F0 + x"46",x"05",x"FD",x"6E",x"06",x"FD",x"66",x"07", -- 0x04F8 + x"3E",x"FE",x"D3",x"E7",x"3A",x"02",x"FA",x"B7", -- 0x0500 + x"CC",x"2A",x"05",x"3E",x"51",x"CD",x"3D",x"05", -- 0x0508 + x"30",x"03",x"2E",x"00",x"C9",x"CD",x"9F",x"05", -- 0x0510 + x"38",x"F8",x"01",x"EB",x"00",x"ED",x"B2",x"ED", -- 0x0518 + x"B2",x"00",x"DB",x"EB",x"00",x"DB",x"EB",x"2E", -- 0x0520 + x"01",x"C9",x"41",x"4A",x"53",x"1E",x"00",x"CB", -- 0x0528 + x"22",x"CB",x"11",x"CB",x"10",x"C9",x"3E",x"41", -- 0x0530 + x"01",x"00",x"00",x"50",x"59",x"CD",x"78",x"05", -- 0x0538 + x"B7",x"C8",x"37",x"C9",x"3E",x"77",x"CD",x"38", -- 0x0540 + x"05",x"3E",x"69",x"01",x"00",x"40",x"51",x"59", -- 0x0548 + x"18",x"EB",x"01",x"00",x"00",x"CD",x"78",x"05", -- 0x0550 + x"47",x"E6",x"FE",x"78",x"20",x"E4",x"C9",x"CD", -- 0x0558 + x"52",x"05",x"D8",x"F5",x"CD",x"AD",x"05",x"67", -- 0x0560 + x"CD",x"AD",x"05",x"6F",x"CD",x"AD",x"05",x"57", -- 0x0568 + x"CD",x"AD",x"05",x"5F",x"44",x"4D",x"F1",x"C9", -- 0x0570 + x"D3",x"EB",x"F5",x"78",x"00",x"D3",x"EB",x"79", -- 0x0578 + x"00",x"D3",x"EB",x"7A",x"00",x"D3",x"EB",x"7B", -- 0x0580 + x"00",x"D3",x"EB",x"F1",x"FE",x"40",x"06",x"95", -- 0x0588 + x"28",x"08",x"FE",x"48",x"06",x"87",x"28",x"02", -- 0x0590 + x"06",x"FF",x"78",x"D3",x"EB",x"18",x"0E",x"06", -- 0x0598 + x"0A",x"C5",x"CD",x"AD",x"05",x"C1",x"FE",x"FE", -- 0x05A0 + x"C8",x"10",x"F6",x"37",x"C9",x"01",x"64",x"00", -- 0x05A8 + x"DB",x"EB",x"FE",x"FF",x"C0",x"10",x"F9",x"0D", -- 0x05B0 + x"20",x"F6",x"C9",x"F5",x"F5",x"F5",x"F5",x"FD", -- 0x05B8 + x"21",x"03",x"FA",x"FD",x"7E",x"01",x"FD",x"B6", -- 0x05C0 + x"00",x"28",x"5C",x"F5",x"21",x"0C",x"00",x"39", -- 0x05C8 + x"7E",x"FD",x"21",x"02",x"00",x"FD",x"39",x"FD", -- 0x05D0 + x"77",x"00",x"21",x"0D",x"00",x"39",x"7E",x"FD", -- 0x05D8 + x"21",x"02",x"00",x"FD",x"39",x"FD",x"77",x"01", -- 0x05E0 + x"21",x"0E",x"00",x"39",x"7E",x"FD",x"21",x"02", -- 0x05E8 + x"00",x"FD",x"39",x"FD",x"77",x"02",x"21",x"0F", -- 0x05F0 + x"00",x"39",x"7E",x"FD",x"21",x"02",x"00",x"FD", -- 0x05F8 + x"39",x"FD",x"77",x"03",x"F1",x"06",x"07",x"FD", -- 0x0600 + x"CB",x"03",x"3E",x"FD",x"CB",x"02",x"1E",x"FD", -- 0x0608 + x"CB",x"01",x"1E",x"FD",x"CB",x"00",x"1E",x"10", -- 0x0610 + x"EE",x"21",x"0A",x"00",x"39",x"5E",x"CB",x"BB", -- 0x0618 + x"16",x"00",x"01",x"00",x"00",x"18",x"58",x"F5", -- 0x0620 + x"21",x"0C",x"00",x"39",x"7E",x"FD",x"21",x"02", -- 0x0628 + x"00",x"FD",x"39",x"FD",x"77",x"00",x"21",x"0D", -- 0x0630 + x"00",x"39",x"7E",x"FD",x"21",x"02",x"00",x"FD", -- 0x0638 + x"39",x"FD",x"77",x"01",x"21",x"0E",x"00",x"39", -- 0x0640 + x"7E",x"FD",x"21",x"02",x"00",x"FD",x"39",x"FD", -- 0x0648 + x"77",x"02",x"21",x"0F",x"00",x"39",x"7E",x"FD", -- 0x0650 + x"21",x"02",x"00",x"FD",x"39",x"FD",x"77",x"03", -- 0x0658 + x"F1",x"06",x"08",x"FD",x"CB",x"03",x"3E",x"FD", -- 0x0660 + x"CB",x"02",x"1E",x"FD",x"CB",x"01",x"1E",x"FD", -- 0x0668 + x"CB",x"00",x"1E",x"10",x"EE",x"21",x"0A",x"00", -- 0x0670 + x"39",x"5E",x"16",x"00",x"01",x"00",x"00",x"21", -- 0x0678 + x"00",x"00",x"39",x"7E",x"FD",x"21",x"2D",x"FC", -- 0x0680 + x"FD",x"96",x"00",x"20",x"2A",x"21",x"01",x"00", -- 0x0688 + x"39",x"7E",x"FD",x"21",x"2D",x"FC",x"FD",x"96", -- 0x0690 + x"01",x"20",x"1C",x"21",x"02",x"00",x"39",x"7E", -- 0x0698 + x"FD",x"21",x"2D",x"FC",x"FD",x"96",x"02",x"20", -- 0x06A0 + x"0E",x"21",x"03",x"00",x"39",x"7E",x"FD",x"21", -- 0x06A8 + x"2D",x"FC",x"FD",x"96",x"03",x"28",x"6A",x"21", -- 0x06B0 + x"00",x"00",x"39",x"D5",x"FD",x"21",x"06",x"00", -- 0x06B8 + x"FD",x"39",x"FD",x"E5",x"D1",x"FD",x"21",x"05", -- 0x06C0 + x"FA",x"FD",x"7E",x"00",x"86",x"12",x"FD",x"7E", -- 0x06C8 + x"01",x"23",x"8E",x"13",x"12",x"FD",x"7E",x"02", -- 0x06D0 + x"23",x"8E",x"13",x"12",x"FD",x"7E",x"03",x"23", -- 0x06D8 + x"8E",x"13",x"12",x"D1",x"C5",x"D5",x"21",x"2B", -- 0x06E0 + x"FA",x"E5",x"FD",x"21",x"0A",x"00",x"FD",x"39", -- 0x06E8 + x"FD",x"6E",x"02",x"FD",x"66",x"03",x"E5",x"FD", -- 0x06F0 + x"6E",x"00",x"FD",x"66",x"01",x"E5",x"CD",x"E8", -- 0x06F8 + x"04",x"F1",x"F1",x"F1",x"D1",x"C1",x"7D",x"B7", -- 0x0700 + x"20",x"07",x"21",x"00",x"00",x"5D",x"54",x"18", -- 0x0708 + x"4D",x"D5",x"C5",x"11",x"2D",x"FC",x"21",x"04", -- 0x0710 + x"00",x"39",x"01",x"04",x"00",x"ED",x"B0",x"C1", -- 0x0718 + x"D1",x"FD",x"21",x"03",x"FA",x"FD",x"7E",x"01", -- 0x0720 + x"FD",x"B6",x"00",x"28",x"1D",x"21",x"2B",x"FA", -- 0x0728 + x"3E",x"02",x"CB",x"23",x"CB",x"12",x"CB",x"11", -- 0x0730 + x"CB",x"10",x"3D",x"20",x"F5",x"19",x"4E",x"23", -- 0x0738 + x"46",x"23",x"5E",x"23",x"7E",x"E6",x"0F",x"57", -- 0x0740 + x"18",x"12",x"21",x"2B",x"FA",x"CB",x"23",x"CB", -- 0x0748 + x"12",x"CB",x"11",x"CB",x"10",x"19",x"4E",x"23", -- 0x0750 + x"46",x"11",x"00",x"00",x"69",x"60",x"F1",x"F1", -- 0x0758 + x"F1",x"F1",x"C9",x"F5",x"F5",x"21",x"06",x"00", -- 0x0760 + x"39",x"4E",x"23",x"46",x"21",x"08",x"00",x"39", -- 0x0768 + x"7E",x"FD",x"21",x"02",x"00",x"FD",x"39",x"FD", -- 0x0770 + x"77",x"00",x"21",x"09",x"00",x"39",x"7E",x"FD", -- 0x0778 + x"21",x"02",x"00",x"FD",x"39",x"FD",x"77",x"01", -- 0x0780 + x"11",x"00",x"00",x"21",x"0A",x"00",x"39",x"7B", -- 0x0788 + x"96",x"7A",x"23",x"9E",x"E2",x"99",x"07",x"EE", -- 0x0790 + x"80",x"F2",x"D7",x"07",x"0A",x"FD",x"21",x"01", -- 0x0798 + x"00",x"FD",x"39",x"FD",x"77",x"00",x"03",x"FD", -- 0x07A0 + x"21",x"02",x"00",x"FD",x"39",x"FD",x"6E",x"00", -- 0x07A8 + x"FD",x"66",x"01",x"7E",x"33",x"F5",x"33",x"FD", -- 0x07B0 + x"34",x"00",x"20",x"03",x"FD",x"34",x"01",x"21", -- 0x07B8 + x"01",x"00",x"39",x"7E",x"FD",x"21",x"00",x"00", -- 0x07C0 + x"FD",x"39",x"FD",x"96",x"00",x"28",x"05",x"21", -- 0x07C8 + x"01",x"00",x"18",x"06",x"13",x"18",x"B4",x"21", -- 0x07D0 + x"00",x"00",x"F1",x"F1",x"C9",x"21",x"F5",x"FF", -- 0x07D8 + x"39",x"F9",x"FD",x"21",x"2D",x"FC",x"FD",x"36", -- 0x07E0 + x"00",x"FF",x"FD",x"36",x"01",x"FF",x"FD",x"36", -- 0x07E8 + x"02",x"FF",x"FD",x"36",x"03",x"FF",x"21",x"00", -- 0x07F0 + x"00",x"22",x"03",x"FA",x"21",x"2B",x"FA",x"E5", -- 0x07F8 + x"21",x"00",x"00",x"E5",x"21",x"00",x"00",x"E5", -- 0x0800 + x"CD",x"E8",x"04",x"F1",x"F1",x"F1",x"FD",x"21", -- 0x0808 + x"0A",x"00",x"FD",x"39",x"FD",x"75",x"00",x"21", -- 0x0810 + x"0A",x"00",x"39",x"7E",x"B7",x"20",x"04",x"6F", -- 0x0818 + x"C3",x"22",x"10",x"AF",x"FD",x"21",x"06",x"00", -- 0x0820 + x"FD",x"39",x"FD",x"77",x"00",x"FD",x"77",x"01", -- 0x0828 + x"FD",x"77",x"02",x"FD",x"77",x"03",x"21",x"01", -- 0x0830 + x"00",x"22",x"2B",x"FC",x"2E",x"08",x"E5",x"21", -- 0x0838 + x"2B",x"10",x"E5",x"21",x"61",x"FA",x"E5",x"CD", -- 0x0840 + x"63",x"07",x"F1",x"F1",x"F1",x"7C",x"B5",x"20", -- 0x0848 + x"06",x"21",x"00",x"00",x"22",x"2B",x"FC",x"21", -- 0x0850 + x"08",x"00",x"E5",x"21",x"34",x"10",x"E5",x"21", -- 0x0858 + x"7D",x"FA",x"E5",x"CD",x"63",x"07",x"F1",x"F1", -- 0x0860 + x"F1",x"7C",x"B5",x"20",x"06",x"21",x"00",x"00", -- 0x0868 + x"22",x"2B",x"FC",x"FD",x"21",x"2B",x"FC",x"FD", -- 0x0870 + x"7E",x"01",x"FD",x"B6",x"00",x"CA",x"FD",x"08", -- 0x0878 + x"01",x"2B",x"FA",x"33",x"33",x"C5",x"E1",x"E5", -- 0x0880 + x"11",x"C6",x"01",x"19",x"4E",x"23",x"46",x"23", -- 0x0888 + x"5E",x"23",x"56",x"FD",x"21",x"06",x"00",x"FD", -- 0x0890 + x"39",x"FD",x"71",x"00",x"FD",x"70",x"01",x"FD", -- 0x0898 + x"73",x"02",x"FD",x"72",x"03",x"E1",x"E5",x"C5", -- 0x08A0 + x"01",x"FE",x"01",x"09",x"C1",x"7E",x"23",x"66", -- 0x08A8 + x"6F",x"D6",x"AA",x"20",x"13",x"7C",x"D6",x"55", -- 0x08B0 + x"20",x"0E",x"FD",x"71",x"00",x"FD",x"70",x"01", -- 0x08B8 + x"FD",x"73",x"02",x"FD",x"72",x"03",x"18",x"0F", -- 0x08C0 + x"7D",x"D6",x"55",x"20",x"05",x"7C",x"D6",x"AA", -- 0x08C8 + x"28",x"05",x"2E",x"00",x"C3",x"22",x"10",x"21", -- 0x08D0 + x"2B",x"FA",x"E5",x"FD",x"21",x"08",x"00",x"FD", -- 0x08D8 + x"39",x"FD",x"6E",x"02",x"FD",x"66",x"03",x"E5", -- 0x08E0 + x"FD",x"6E",x"00",x"FD",x"66",x"01",x"E5",x"CD", -- 0x08E8 + x"E8",x"04",x"F1",x"F1",x"F1",x"7D",x"B7",x"20", -- 0x08F0 + x"04",x"6F",x"C3",x"22",x"10",x"21",x"08",x"00", -- 0x08F8 + x"E5",x"21",x"34",x"10",x"E5",x"21",x"7D",x"FA", -- 0x0900 + x"E5",x"CD",x"63",x"07",x"F1",x"F1",x"F1",x"7C", -- 0x0908 + x"B5",x"20",x"08",x"21",x"01",x"00",x"22",x"03", -- 0x0910 + x"FA",x"18",x"1B",x"21",x"08",x"00",x"E5",x"21", -- 0x0918 + x"2B",x"10",x"E5",x"21",x"61",x"FA",x"E5",x"CD", -- 0x0920 + x"63",x"07",x"F1",x"F1",x"F1",x"7C",x"B5",x"28", -- 0x0928 + x"05",x"2E",x"00",x"C3",x"22",x"10",x"3A",x"29", -- 0x0930 + x"FC",x"D6",x"55",x"20",x"07",x"3A",x"2A",x"FC", -- 0x0938 + x"D6",x"AA",x"28",x"05",x"2E",x"00",x"C3",x"22", -- 0x0940 + x"10",x"21",x"2B",x"FA",x"4E",x"79",x"FE",x"E9", -- 0x0948 + x"28",x"09",x"D6",x"EB",x"28",x"05",x"2E",x"00", -- 0x0950 + x"C3",x"22",x"10",x"3A",x"36",x"FA",x"B7",x"20", -- 0x0958 + x"07",x"3A",x"37",x"FA",x"D6",x"02",x"28",x"05", -- 0x0960 + x"2E",x"00",x"C3",x"22",x"10",x"3A",x"38",x"FA", -- 0x0968 + x"FD",x"21",x"1B",x"FA",x"FD",x"77",x"00",x"FD", -- 0x0970 + x"36",x"01",x"00",x"FD",x"36",x"02",x"00",x"FD", -- 0x0978 + x"36",x"03",x"00",x"21",x"1F",x"FA",x"FD",x"7E", -- 0x0980 + x"00",x"C6",x"FF",x"77",x"FD",x"7E",x"01",x"CE", -- 0x0988 + x"FF",x"23",x"77",x"FD",x"7E",x"02",x"CE",x"FF", -- 0x0990 + x"23",x"77",x"FD",x"7E",x"03",x"CE",x"FF",x"23", -- 0x0998 + x"77",x"3A",x"39",x"FA",x"FD",x"21",x"0A",x"00", -- 0x09A0 + x"FD",x"39",x"FD",x"77",x"00",x"FD",x"7E",x"00", -- 0x09A8 + x"FD",x"21",x"02",x"00",x"FD",x"39",x"FD",x"77", -- 0x09B0 + x"00",x"FD",x"36",x"01",x"00",x"FD",x"36",x"02", -- 0x09B8 + x"00",x"FD",x"36",x"03",x"00",x"21",x"02",x"00", -- 0x09C0 + x"39",x"FD",x"21",x"06",x"00",x"FD",x"39",x"FD", -- 0x09C8 + x"7E",x"00",x"86",x"77",x"FD",x"7E",x"01",x"23", -- 0x09D0 + x"8E",x"77",x"FD",x"7E",x"02",x"23",x"8E",x"77", -- 0x09D8 + x"FD",x"7E",x"03",x"23",x"8E",x"77",x"3A",x"3A", -- 0x09E0 + x"FA",x"FD",x"77",x"00",x"FD",x"7E",x"00",x"FD", -- 0x09E8 + x"77",x"00",x"FD",x"36",x"01",x"00",x"FD",x"7E", -- 0x09F0 + x"00",x"FD",x"77",x"01",x"FD",x"36",x"00",x"00", -- 0x09F8 + x"FD",x"7E",x"00",x"FD",x"77",x"00",x"FD",x"7E", -- 0x0A00 + x"01",x"FD",x"77",x"01",x"FD",x"7E",x"01",x"17", -- 0x0A08 + x"9F",x"FD",x"77",x"02",x"FD",x"77",x"03",x"21", -- 0x0A10 + x"06",x"00",x"39",x"D5",x"11",x"05",x"FA",x"FD", -- 0x0A18 + x"21",x"04",x"00",x"FD",x"39",x"FD",x"7E",x"00", -- 0x0A20 + x"86",x"12",x"FD",x"7E",x"01",x"23",x"8E",x"13", -- 0x0A28 + x"12",x"FD",x"7E",x"02",x"23",x"8E",x"13",x"12", -- 0x0A30 + x"FD",x"7E",x"03",x"23",x"8E",x"13",x"12",x"D1", -- 0x0A38 + x"3A",x"3B",x"FA",x"FD",x"21",x"19",x"FA",x"FD", -- 0x0A40 + x"77",x"00",x"FD",x"36",x"01",x"00",x"FD",x"21", -- 0x0A48 + x"03",x"FA",x"FD",x"7E",x"01",x"FD",x"B6",x"00", -- 0x0A50 + x"CA",x"0A",x"0E",x"21",x"08",x"00",x"E5",x"21", -- 0x0A58 + x"34",x"10",x"E5",x"21",x"7D",x"FA",x"E5",x"CD", -- 0x0A60 + x"63",x"07",x"F1",x"F1",x"F1",x"7C",x"B5",x"28", -- 0x0A68 + x"05",x"2E",x"00",x"C3",x"22",x"10",x"F5",x"3A", -- 0x0A70 + x"1B",x"FA",x"FD",x"21",x"23",x"FA",x"FD",x"77", -- 0x0A78 + x"00",x"3A",x"1C",x"FA",x"FD",x"21",x"23",x"FA", -- 0x0A80 + x"FD",x"77",x"01",x"3A",x"1D",x"FA",x"FD",x"21", -- 0x0A88 + x"23",x"FA",x"FD",x"77",x"02",x"3A",x"1E",x"FA", -- 0x0A90 + x"FD",x"21",x"23",x"FA",x"FD",x"77",x"03",x"F1", -- 0x0A98 + x"06",x"04",x"FD",x"CB",x"00",x"26",x"FD",x"CB", -- 0x0AA0 + x"01",x"16",x"FD",x"CB",x"02",x"16",x"FD",x"CB", -- 0x0AA8 + x"03",x"16",x"10",x"EE",x"11",x"15",x"FA",x"21", -- 0x0AB0 + x"1B",x"FA",x"01",x"04",x"00",x"ED",x"B0",x"3A", -- 0x0AB8 + x"4F",x"FA",x"FD",x"21",x"02",x"00",x"FD",x"39", -- 0x0AC0 + x"FD",x"77",x"00",x"3A",x"50",x"FA",x"FD",x"21", -- 0x0AC8 + x"06",x"00",x"FD",x"39",x"FD",x"77",x"00",x"FD", -- 0x0AD0 + x"7E",x"00",x"FD",x"77",x"00",x"FD",x"36",x"01", -- 0x0AD8 + x"00",x"FD",x"36",x"02",x"00",x"FD",x"36",x"03", -- 0x0AE0 + x"00",x"F5",x"F1",x"06",x"08",x"FD",x"CB",x"00", -- 0x0AE8 + x"26",x"FD",x"CB",x"01",x"16",x"FD",x"CB",x"02", -- 0x0AF0 + x"16",x"FD",x"CB",x"03",x"16",x"10",x"EE",x"FD", -- 0x0AF8 + x"21",x"02",x"00",x"FD",x"39",x"FD",x"7E",x"00", -- 0x0B00 + x"FD",x"77",x"00",x"FD",x"36",x"01",x"00",x"FD", -- 0x0B08 + x"36",x"02",x"00",x"FD",x"36",x"03",x"00",x"21", -- 0x0B10 + x"06",x"00",x"39",x"D5",x"FD",x"E5",x"D1",x"1A", -- 0x0B18 + x"86",x"12",x"13",x"1A",x"23",x"8E",x"12",x"13", -- 0x0B20 + x"1A",x"23",x"8E",x"12",x"13",x"1A",x"23",x"8E", -- 0x0B28 + x"12",x"D1",x"3A",x"51",x"FA",x"FD",x"21",x"06", -- 0x0B30 + x"00",x"FD",x"39",x"FD",x"77",x"00",x"FD",x"7E", -- 0x0B38 + x"00",x"FD",x"77",x"00",x"FD",x"36",x"01",x"00", -- 0x0B40 + x"FD",x"36",x"02",x"00",x"FD",x"36",x"03",x"00", -- 0x0B48 + x"F5",x"F1",x"06",x"10",x"FD",x"CB",x"00",x"26", -- 0x0B50 + x"FD",x"CB",x"01",x"16",x"FD",x"CB",x"02",x"16", -- 0x0B58 + x"FD",x"CB",x"03",x"16",x"10",x"EE",x"21",x"06", -- 0x0B60 + x"00",x"39",x"D5",x"FD",x"21",x"04",x"00",x"FD", -- 0x0B68 + x"39",x"FD",x"E5",x"D1",x"1A",x"86",x"12",x"13", -- 0x0B70 + x"1A",x"23",x"8E",x"12",x"13",x"1A",x"23",x"8E", -- 0x0B78 + x"12",x"13",x"1A",x"23",x"8E",x"12",x"D1",x"3A", -- 0x0B80 + x"52",x"FA",x"FD",x"21",x"06",x"00",x"FD",x"39", -- 0x0B88 + x"FD",x"77",x"00",x"FD",x"7E",x"00",x"FD",x"77", -- 0x0B90 + x"00",x"FD",x"36",x"01",x"00",x"FD",x"36",x"02", -- 0x0B98 + x"00",x"FD",x"36",x"03",x"00",x"F5",x"F1",x"06", -- 0x0BA0 + x"18",x"FD",x"CB",x"00",x"26",x"FD",x"CB",x"01", -- 0x0BA8 + x"16",x"FD",x"CB",x"02",x"16",x"FD",x"CB",x"03", -- 0x0BB0 + x"16",x"10",x"EE",x"21",x"06",x"00",x"39",x"D5", -- 0x0BB8 + x"11",x"27",x"FA",x"FD",x"21",x"04",x"00",x"FD", -- 0x0BC0 + x"39",x"FD",x"7E",x"00",x"86",x"12",x"FD",x"7E", -- 0x0BC8 + x"01",x"23",x"8E",x"13",x"12",x"FD",x"7E",x"02", -- 0x0BD0 + x"23",x"8E",x"13",x"12",x"FD",x"7E",x"03",x"23", -- 0x0BD8 + x"8E",x"13",x"12",x"D1",x"3A",x"19",x"FA",x"FD", -- 0x0BE0 + x"21",x"02",x"00",x"FD",x"39",x"FD",x"77",x"00", -- 0x0BE8 + x"3A",x"1A",x"FA",x"FD",x"21",x"02",x"00",x"FD", -- 0x0BF0 + x"39",x"FD",x"77",x"01",x"FD",x"36",x"02",x"00", -- 0x0BF8 + x"FD",x"36",x"03",x"00",x"2A",x"29",x"FA",x"E5", -- 0x0C00 + x"2A",x"27",x"FA",x"E5",x"FD",x"6E",x"02",x"FD", -- 0x0C08 + x"66",x"03",x"E5",x"FD",x"6E",x"00",x"FD",x"66", -- 0x0C10 + x"01",x"E5",x"CD",x"41",x"1B",x"F1",x"F1",x"F1", -- 0x0C18 + x"F1",x"FD",x"21",x"02",x"00",x"FD",x"39",x"FD", -- 0x0C20 + x"72",x"03",x"FD",x"73",x"02",x"FD",x"74",x"01", -- 0x0C28 + x"FD",x"75",x"00",x"21",x"02",x"00",x"39",x"D5", -- 0x0C30 + x"11",x"09",x"FA",x"FD",x"21",x"05",x"FA",x"FD", -- 0x0C38 + x"7E",x"00",x"86",x"12",x"FD",x"7E",x"01",x"23", -- 0x0C40 + x"8E",x"13",x"12",x"FD",x"7E",x"02",x"23",x"8E", -- 0x0C48 + x"13",x"12",x"FD",x"7E",x"03",x"23",x"8E",x"13", -- 0x0C50 + x"12",x"D1",x"3A",x"57",x"FA",x"FD",x"21",x"02", -- 0x0C58 + x"00",x"FD",x"39",x"FD",x"77",x"00",x"3A",x"58", -- 0x0C60 + x"FA",x"FD",x"21",x"06",x"00",x"FD",x"39",x"FD", -- 0x0C68 + x"77",x"00",x"FD",x"7E",x"00",x"FD",x"77",x"00", -- 0x0C70 + x"FD",x"36",x"01",x"00",x"FD",x"36",x"02",x"00", -- 0x0C78 + x"FD",x"36",x"03",x"00",x"F5",x"F1",x"06",x"08", -- 0x0C80 + x"FD",x"CB",x"00",x"26",x"FD",x"CB",x"01",x"16", -- 0x0C88 + x"FD",x"CB",x"02",x"16",x"FD",x"CB",x"03",x"16", -- 0x0C90 + x"10",x"EE",x"FD",x"21",x"02",x"00",x"FD",x"39", -- 0x0C98 + x"FD",x"7E",x"00",x"FD",x"77",x"00",x"FD",x"36", -- 0x0CA0 + x"01",x"00",x"FD",x"36",x"02",x"00",x"FD",x"36", -- 0x0CA8 + x"03",x"00",x"21",x"06",x"00",x"39",x"D5",x"FD", -- 0x0CB0 + x"E5",x"D1",x"1A",x"86",x"12",x"13",x"1A",x"23", -- 0x0CB8 + x"8E",x"12",x"13",x"1A",x"23",x"8E",x"12",x"13", -- 0x0CC0 + x"1A",x"23",x"8E",x"12",x"D1",x"3A",x"59",x"FA", -- 0x0CC8 + x"FD",x"21",x"06",x"00",x"FD",x"39",x"FD",x"77", -- 0x0CD0 + x"00",x"FD",x"7E",x"00",x"FD",x"77",x"00",x"FD", -- 0x0CD8 + x"36",x"01",x"00",x"FD",x"36",x"02",x"00",x"FD", -- 0x0CE0 + x"36",x"03",x"00",x"F5",x"F1",x"06",x"10",x"FD", -- 0x0CE8 + x"CB",x"00",x"26",x"FD",x"CB",x"01",x"16",x"FD", -- 0x0CF0 + x"CB",x"02",x"16",x"FD",x"CB",x"03",x"16",x"10", -- 0x0CF8 + x"EE",x"21",x"06",x"00",x"39",x"D5",x"FD",x"21", -- 0x0D00 + x"04",x"00",x"FD",x"39",x"FD",x"E5",x"D1",x"1A", -- 0x0D08 + x"86",x"12",x"13",x"1A",x"23",x"8E",x"12",x"13", -- 0x0D10 + x"1A",x"23",x"8E",x"12",x"13",x"1A",x"23",x"8E", -- 0x0D18 + x"12",x"D1",x"3A",x"5A",x"FA",x"FD",x"21",x"06", -- 0x0D20 + x"00",x"FD",x"39",x"FD",x"77",x"00",x"FD",x"7E", -- 0x0D28 + x"00",x"E6",x"0F",x"FD",x"77",x"00",x"FD",x"7E", -- 0x0D30 + x"00",x"FD",x"77",x"00",x"FD",x"36",x"01",x"00", -- 0x0D38 + x"FD",x"36",x"02",x"00",x"FD",x"36",x"03",x"00", -- 0x0D40 + x"F5",x"F1",x"06",x"18",x"FD",x"CB",x"00",x"26", -- 0x0D48 + x"FD",x"CB",x"01",x"16",x"FD",x"CB",x"02",x"16", -- 0x0D50 + x"FD",x"CB",x"03",x"16",x"10",x"EE",x"21",x"06", -- 0x0D58 + x"00",x"39",x"D5",x"11",x"0D",x"FA",x"FD",x"21", -- 0x0D60 + x"04",x"00",x"FD",x"39",x"FD",x"7E",x"00",x"86", -- 0x0D68 + x"12",x"FD",x"7E",x"01",x"23",x"8E",x"13",x"12", -- 0x0D70 + x"FD",x"7E",x"02",x"23",x"8E",x"13",x"12",x"FD", -- 0x0D78 + x"7E",x"03",x"23",x"8E",x"13",x"12",x"D1",x"21", -- 0x0D80 + x"02",x"00",x"39",x"FD",x"21",x"0D",x"FA",x"FD", -- 0x0D88 + x"7E",x"00",x"C6",x"FE",x"77",x"FD",x"7E",x"01", -- 0x0D90 + x"CE",x"FF",x"23",x"77",x"FD",x"7E",x"02",x"CE", -- 0x0D98 + x"FF",x"23",x"77",x"FD",x"7E",x"03",x"CE",x"FF", -- 0x0DA0 + x"23",x"77",x"2A",x"1D",x"FA",x"E5",x"2A",x"1B", -- 0x0DA8 + x"FA",x"E5",x"FD",x"21",x"06",x"00",x"FD",x"39", -- 0x0DB0 + x"FD",x"6E",x"02",x"FD",x"66",x"03",x"E5",x"FD", -- 0x0DB8 + x"6E",x"00",x"FD",x"66",x"01",x"E5",x"CD",x"41", -- 0x0DC0 + x"1B",x"F1",x"F1",x"F1",x"F1",x"FD",x"21",x"02", -- 0x0DC8 + x"00",x"FD",x"39",x"FD",x"72",x"03",x"FD",x"73", -- 0x0DD0 + x"02",x"FD",x"74",x"01",x"FD",x"75",x"00",x"21", -- 0x0DD8 + x"09",x"FA",x"D5",x"11",x"11",x"FA",x"FD",x"21", -- 0x0DE0 + x"04",x"00",x"FD",x"39",x"FD",x"7E",x"00",x"86", -- 0x0DE8 + x"12",x"FD",x"7E",x"01",x"23",x"8E",x"13",x"12", -- 0x0DF0 + x"FD",x"7E",x"02",x"23",x"8E",x"13",x"12",x"FD", -- 0x0DF8 + x"7E",x"03",x"23",x"8E",x"13",x"12",x"D1",x"C3", -- 0x0E00 + x"20",x"10",x"3A",x"3C",x"FA",x"FD",x"21",x"02", -- 0x0E08 + x"00",x"FD",x"39",x"FD",x"77",x"00",x"FD",x"36", -- 0x0E10 + x"01",x"00",x"3A",x"3D",x"FA",x"FD",x"21",x"06", -- 0x0E18 + x"00",x"FD",x"39",x"FD",x"77",x"00",x"FD",x"7E", -- 0x0E20 + x"00",x"FD",x"77",x"00",x"FD",x"36",x"01",x"00", -- 0x0E28 + x"FD",x"7E",x"00",x"FD",x"77",x"01",x"FD",x"36", -- 0x0E30 + x"00",x"00",x"21",x"06",x"00",x"39",x"D5",x"FD", -- 0x0E38 + x"21",x"04",x"00",x"FD",x"39",x"FD",x"E5",x"D1", -- 0x0E40 + x"FD",x"7E",x"00",x"86",x"12",x"FD",x"7E",x"01", -- 0x0E48 + x"23",x"8E",x"13",x"12",x"D1",x"FD",x"7E",x"00", -- 0x0E50 + x"32",x"23",x"FA",x"21",x"03",x"00",x"39",x"7E", -- 0x0E58 + x"32",x"24",x"FA",x"21",x"03",x"00",x"39",x"7E", -- 0x0E60 + x"17",x"9F",x"FD",x"21",x"23",x"FA",x"FD",x"77", -- 0x0E68 + x"02",x"FD",x"77",x"03",x"F5",x"FD",x"7E",x"00", -- 0x0E70 + x"FD",x"21",x"04",x"00",x"FD",x"39",x"FD",x"77", -- 0x0E78 + x"00",x"3A",x"24",x"FA",x"FD",x"21",x"04",x"00", -- 0x0E80 + x"FD",x"39",x"FD",x"77",x"01",x"3A",x"25",x"FA", -- 0x0E88 + x"FD",x"21",x"04",x"00",x"FD",x"39",x"FD",x"77", -- 0x0E90 + x"02",x"3A",x"26",x"FA",x"FD",x"21",x"04",x"00", -- 0x0E98 + x"FD",x"39",x"FD",x"77",x"03",x"F1",x"06",x"05", -- 0x0EA0 + x"FD",x"CB",x"00",x"26",x"FD",x"CB",x"01",x"16", -- 0x0EA8 + x"FD",x"CB",x"02",x"16",x"FD",x"CB",x"03",x"16", -- 0x0EB0 + x"10",x"EE",x"21",x"02",x"00",x"39",x"7E",x"C6", -- 0x0EB8 + x"FF",x"77",x"23",x"7E",x"CE",x"01",x"77",x"23", -- 0x0EC0 + x"7E",x"CE",x"00",x"77",x"23",x"7E",x"CE",x"00", -- 0x0EC8 + x"77",x"F5",x"FD",x"7E",x"00",x"32",x"15",x"FA", -- 0x0ED0 + x"21",x"05",x"00",x"39",x"7E",x"32",x"16",x"FA", -- 0x0ED8 + x"21",x"06",x"00",x"39",x"7E",x"32",x"17",x"FA", -- 0x0EE0 + x"21",x"07",x"00",x"39",x"7E",x"FD",x"21",x"15", -- 0x0EE8 + x"FA",x"FD",x"77",x"03",x"F1",x"06",x"09",x"FD", -- 0x0EF0 + x"CB",x"03",x"3E",x"FD",x"CB",x"02",x"1E",x"FD", -- 0x0EF8 + x"CB",x"01",x"1E",x"FD",x"CB",x"00",x"1E",x"10", -- 0x0F00 + x"EE",x"3A",x"41",x"FA",x"FD",x"21",x"02",x"00", -- 0x0F08 + x"FD",x"39",x"FD",x"77",x"00",x"FD",x"36",x"01", -- 0x0F10 + x"00",x"3A",x"42",x"FA",x"FD",x"21",x"06",x"00", -- 0x0F18 + x"FD",x"39",x"FD",x"77",x"00",x"FD",x"7E",x"00", -- 0x0F20 + x"FD",x"77",x"00",x"FD",x"36",x"01",x"00",x"FD", -- 0x0F28 + x"7E",x"00",x"FD",x"77",x"01",x"FD",x"36",x"00", -- 0x0F30 + x"00",x"21",x"06",x"00",x"39",x"D5",x"FD",x"21", -- 0x0F38 + x"04",x"00",x"FD",x"39",x"FD",x"E5",x"D1",x"FD", -- 0x0F40 + x"7E",x"00",x"86",x"12",x"FD",x"7E",x"01",x"23", -- 0x0F48 + x"8E",x"13",x"12",x"D1",x"FD",x"7E",x"00",x"32", -- 0x0F50 + x"27",x"FA",x"21",x"03",x"00",x"39",x"7E",x"32", -- 0x0F58 + x"28",x"FA",x"21",x"03",x"00",x"39",x"7E",x"17", -- 0x0F60 + x"9F",x"FD",x"21",x"27",x"FA",x"FD",x"77",x"02", -- 0x0F68 + x"FD",x"77",x"03",x"3A",x"19",x"FA",x"FD",x"21", -- 0x0F70 + x"02",x"00",x"FD",x"39",x"FD",x"77",x"00",x"3A", -- 0x0F78 + x"1A",x"FA",x"FD",x"21",x"02",x"00",x"FD",x"39", -- 0x0F80 + x"FD",x"77",x"01",x"FD",x"36",x"02",x"00",x"FD", -- 0x0F88 + x"36",x"03",x"00",x"2A",x"29",x"FA",x"E5",x"2A", -- 0x0F90 + x"27",x"FA",x"E5",x"FD",x"6E",x"02",x"FD",x"66", -- 0x0F98 + x"03",x"E5",x"FD",x"6E",x"00",x"FD",x"66",x"01", -- 0x0FA0 + x"E5",x"CD",x"41",x"1B",x"F1",x"F1",x"F1",x"F1", -- 0x0FA8 + x"FD",x"21",x"02",x"00",x"FD",x"39",x"FD",x"72", -- 0x0FB0 + x"03",x"FD",x"73",x"02",x"FD",x"74",x"01",x"FD", -- 0x0FB8 + x"75",x"00",x"21",x"02",x"00",x"39",x"D5",x"11", -- 0x0FC0 + x"11",x"FA",x"FD",x"21",x"05",x"FA",x"FD",x"7E", -- 0x0FC8 + x"00",x"86",x"12",x"FD",x"7E",x"01",x"23",x"8E", -- 0x0FD0 + x"13",x"12",x"FD",x"7E",x"02",x"23",x"8E",x"13", -- 0x0FD8 + x"12",x"FD",x"7E",x"03",x"23",x"8E",x"13",x"12", -- 0x0FE0 + x"D1",x"AF",x"FD",x"21",x"0D",x"FA",x"FD",x"77", -- 0x0FE8 + x"00",x"FD",x"77",x"01",x"FD",x"77",x"02",x"FD", -- 0x0FF0 + x"77",x"03",x"21",x"15",x"FA",x"D5",x"11",x"09", -- 0x0FF8 + x"FA",x"FD",x"21",x"11",x"FA",x"FD",x"7E",x"00", -- 0x1000 + x"86",x"12",x"FD",x"7E",x"01",x"23",x"8E",x"13", -- 0x1008 + x"12",x"FD",x"7E",x"02",x"23",x"8E",x"13",x"12", -- 0x1010 + x"FD",x"7E",x"03",x"23",x"8E",x"13",x"12",x"D1", -- 0x1018 + x"2E",x"01",x"FD",x"21",x"0B",x"00",x"FD",x"39", -- 0x1020 + x"FD",x"F9",x"C9",x"46",x"41",x"54",x"31",x"36", -- 0x1028 + x"20",x"20",x"20",x"00",x"46",x"41",x"54",x"33", -- 0x1030 + x"32",x"20",x"20",x"20",x"00",x"21",x"E0",x"FF", -- 0x1038 + x"39",x"F9",x"21",x"04",x"00",x"39",x"36",x"00", -- 0x1040 + x"23",x"36",x"00",x"FD",x"21",x"2D",x"FC",x"FD", -- 0x1048 + x"36",x"00",x"FF",x"FD",x"36",x"01",x"FF",x"FD", -- 0x1050 + x"36",x"02",x"FF",x"FD",x"36",x"03",x"FF",x"21", -- 0x1058 + x"0A",x"00",x"39",x"EB",x"21",x"0D",x"FA",x"01", -- 0x1060 + x"04",x"00",x"ED",x"B0",x"21",x"1A",x"00",x"39", -- 0x1068 + x"EB",x"21",x"11",x"FA",x"01",x"04",x"00",x"ED", -- 0x1070 + x"B0",x"FD",x"21",x"03",x"FA",x"FD",x"7E",x"01", -- 0x1078 + x"FD",x"B6",x"00",x"28",x"1E",x"F5",x"FD",x"21", -- 0x1080 + x"1B",x"FA",x"FD",x"5E",x"00",x"FD",x"56",x"01", -- 0x1088 + x"FD",x"6E",x"02",x"FD",x"66",x"03",x"F1",x"06", -- 0x1090 + x"04",x"CB",x"23",x"CB",x"12",x"ED",x"6A",x"10", -- 0x1098 + x"F8",x"18",x"1C",x"F5",x"FD",x"21",x"15",x"FA", -- 0x10A0 + x"FD",x"5E",x"00",x"FD",x"56",x"01",x"FD",x"6E", -- 0x10A8 + x"02",x"FD",x"66",x"03",x"F1",x"06",x"04",x"CB", -- 0x10B0 + x"23",x"CB",x"12",x"ED",x"6A",x"10",x"F8",x"FD", -- 0x10B8 + x"21",x"00",x"00",x"FD",x"39",x"FD",x"73",x"00", -- 0x10C0 + x"FD",x"72",x"01",x"FD",x"75",x"02",x"FD",x"74", -- 0x10C8 + x"03",x"21",x"14",x"00",x"39",x"EB",x"21",x"1A", -- 0x10D0 + x"00",x"39",x"01",x"04",x"00",x"ED",x"B0",x"AF", -- 0x10D8 + x"FD",x"21",x"06",x"00",x"FD",x"39",x"FD",x"77", -- 0x10E0 + x"00",x"FD",x"77",x"01",x"FD",x"77",x"02",x"FD", -- 0x10E8 + x"77",x"03",x"21",x"00",x"00",x"39",x"FD",x"21", -- 0x10F0 + x"06",x"00",x"FD",x"39",x"FD",x"7E",x"00",x"96", -- 0x10F8 + x"FD",x"7E",x"01",x"23",x"9E",x"FD",x"7E",x"02", -- 0x1100 + x"23",x"9E",x"FD",x"7E",x"03",x"23",x"9E",x"D2", -- 0x1108 + x"EA",x"12",x"FD",x"7E",x"00",x"E6",x"0F",x"20", -- 0x1110 + x"3B",x"FD",x"21",x"14",x"00",x"FD",x"39",x"FD", -- 0x1118 + x"4E",x"00",x"FD",x"46",x"01",x"FD",x"5E",x"02", -- 0x1120 + x"FD",x"56",x"03",x"FD",x"34",x"00",x"20",x"0D", -- 0x1128 + x"FD",x"34",x"01",x"20",x"08",x"FD",x"34",x"02", -- 0x1130 + x"20",x"03",x"FD",x"34",x"03",x"21",x"2B",x"FA", -- 0x1138 + x"E5",x"D5",x"C5",x"CD",x"E8",x"04",x"F1",x"F1", -- 0x1140 + x"F1",x"21",x"04",x"00",x"39",x"36",x"2B",x"23", -- 0x1148 + x"36",x"FA",x"18",x"0D",x"21",x"04",x"00",x"39", -- 0x1150 + x"7E",x"C6",x"20",x"77",x"23",x"7E",x"CE",x"00", -- 0x1158 + x"77",x"FD",x"21",x"04",x"00",x"FD",x"39",x"FD", -- 0x1160 + x"6E",x"00",x"FD",x"66",x"01",x"7E",x"B7",x"CA", -- 0x1168 + x"CC",x"12",x"D6",x"E5",x"CA",x"CC",x"12",x"FD", -- 0x1170 + x"6E",x"00",x"FD",x"66",x"01",x"11",x"0B",x"00", -- 0x1178 + x"19",x"7E",x"E6",x"18",x"C2",x"CC",x"12",x"21", -- 0x1180 + x"0B",x"00",x"E5",x"21",x"26",x"00",x"39",x"4E", -- 0x1188 + x"23",x"46",x"C5",x"21",x"08",x"00",x"39",x"4E", -- 0x1190 + x"23",x"46",x"C5",x"CD",x"63",x"07",x"F1",x"F1", -- 0x1198 + x"F1",x"7C",x"B5",x"C2",x"CC",x"12",x"21",x"22", -- 0x11A0 + x"00",x"39",x"7E",x"FD",x"21",x"1E",x"00",x"FD", -- 0x11A8 + x"39",x"FD",x"77",x"00",x"21",x"23",x"00",x"39", -- 0x11B0 + x"7E",x"FD",x"21",x"1E",x"00",x"FD",x"39",x"FD", -- 0x11B8 + x"77",x"01",x"21",x"0E",x"00",x"39",x"FD",x"7E", -- 0x11C0 + x"00",x"C6",x"04",x"77",x"FD",x"7E",x"01",x"CE", -- 0x11C8 + x"00",x"23",x"77",x"21",x"04",x"00",x"39",x"7E", -- 0x11D0 + x"23",x"66",x"6F",x"11",x"1C",x"00",x"19",x"4E", -- 0x11D8 + x"23",x"46",x"23",x"5E",x"23",x"56",x"21",x"0E", -- 0x11E0 + x"00",x"39",x"7E",x"23",x"66",x"6F",x"71",x"23", -- 0x11E8 + x"70",x"23",x"73",x"23",x"72",x"21",x"0E",x"00", -- 0x11F0 + x"39",x"FD",x"21",x"1E",x"00",x"FD",x"39",x"FD", -- 0x11F8 + x"7E",x"00",x"C6",x"08",x"77",x"FD",x"7E",x"01", -- 0x1200 + x"CE",x"00",x"23",x"77",x"FD",x"21",x"04",x"00", -- 0x1208 + x"FD",x"39",x"FD",x"6E",x"00",x"FD",x"66",x"01", -- 0x1210 + x"11",x"1A",x"00",x"19",x"7E",x"FD",x"21",x"18", -- 0x1218 + x"00",x"FD",x"39",x"FD",x"77",x"00",x"23",x"7E", -- 0x1220 + x"FD",x"77",x"01",x"FD",x"21",x"03",x"FA",x"FD", -- 0x1228 + x"7E",x"01",x"FD",x"B6",x"00",x"28",x"40",x"21", -- 0x1230 + x"04",x"00",x"39",x"7E",x"23",x"66",x"6F",x"11", -- 0x1238 + x"14",x"00",x"19",x"4E",x"23",x"7E",x"E6",x"0F", -- 0x1240 + x"47",x"11",x"00",x"00",x"F5",x"FD",x"21",x"12", -- 0x1248 + x"00",x"FD",x"39",x"FD",x"71",x"00",x"FD",x"70", -- 0x1250 + x"01",x"FD",x"73",x"02",x"FD",x"72",x"03",x"F1", -- 0x1258 + x"3E",x"10",x"FD",x"CB",x"00",x"26",x"FD",x"CB", -- 0x1260 + x"01",x"16",x"FD",x"CB",x"02",x"16",x"FD",x"CB", -- 0x1268 + x"03",x"16",x"3D",x"20",x"ED",x"18",x"13",x"AF", -- 0x1270 + x"FD",x"21",x"10",x"00",x"FD",x"39",x"FD",x"77", -- 0x1278 + x"00",x"FD",x"77",x"01",x"FD",x"77",x"02",x"FD", -- 0x1280 + x"77",x"03",x"21",x"18",x"00",x"39",x"4E",x"23", -- 0x1288 + x"46",x"11",x"00",x"00",x"79",x"21",x"10",x"00", -- 0x1290 + x"39",x"86",x"4F",x"78",x"23",x"8E",x"47",x"7B", -- 0x1298 + x"23",x"8E",x"5F",x"7A",x"23",x"8E",x"57",x"21", -- 0x12A0 + x"0E",x"00",x"39",x"7E",x"23",x"66",x"6F",x"71", -- 0x12A8 + x"23",x"70",x"23",x"73",x"23",x"72",x"21",x"1E", -- 0x12B0 + x"00",x"39",x"7E",x"23",x"66",x"6F",x"AF",x"77", -- 0x12B8 + x"23",x"77",x"23",x"AF",x"77",x"23",x"77",x"2E", -- 0x12C0 + x"01",x"C3",x"E6",x"13",x"FD",x"21",x"06",x"00", -- 0x12C8 + x"FD",x"39",x"FD",x"34",x"00",x"C2",x"F2",x"10", -- 0x12D0 + x"FD",x"34",x"01",x"C2",x"F2",x"10",x"FD",x"34", -- 0x12D8 + x"02",x"C2",x"F2",x"10",x"FD",x"34",x"03",x"C3", -- 0x12E0 + x"F2",x"10",x"FD",x"21",x"03",x"FA",x"FD",x"7E", -- 0x12E8 + x"01",x"FD",x"B6",x"00",x"CA",x"E4",x"13",x"FD", -- 0x12F0 + x"21",x"0A",x"00",x"FD",x"39",x"FD",x"6E",x"02", -- 0x12F8 + x"FD",x"66",x"03",x"E5",x"FD",x"6E",x"00",x"FD", -- 0x1300 + x"66",x"01",x"E5",x"CD",x"BB",x"05",x"F1",x"F1", -- 0x1308 + x"FD",x"21",x"10",x"00",x"FD",x"39",x"FD",x"72", -- 0x1310 + x"03",x"FD",x"73",x"02",x"FD",x"74",x"01",x"FD", -- 0x1318 + x"75",x"00",x"21",x"0A",x"00",x"39",x"EB",x"21", -- 0x1320 + x"10",x"00",x"39",x"01",x"04",x"00",x"ED",x"B0", -- 0x1328 + x"21",x"0A",x"00",x"39",x"7E",x"E6",x"F8",x"FD", -- 0x1330 + x"21",x"10",x"00",x"FD",x"39",x"FD",x"77",x"00", -- 0x1338 + x"21",x"0B",x"00",x"39",x"7E",x"FD",x"21",x"10", -- 0x1340 + x"00",x"FD",x"39",x"FD",x"77",x"01",x"21",x"0C", -- 0x1348 + x"00",x"39",x"7E",x"FD",x"21",x"10",x"00",x"FD", -- 0x1350 + x"39",x"FD",x"77",x"02",x"21",x"0D",x"00",x"39", -- 0x1358 + x"7E",x"E6",x"0F",x"FD",x"21",x"10",x"00",x"FD", -- 0x1360 + x"39",x"FD",x"77",x"03",x"FD",x"7E",x"00",x"D6", -- 0x1368 + x"F8",x"20",x"13",x"FD",x"7E",x"01",x"3C",x"20", -- 0x1370 + x"0D",x"FD",x"7E",x"02",x"3C",x"20",x"07",x"FD", -- 0x1378 + x"7E",x"03",x"D6",x"0F",x"28",x"5E",x"FD",x"21", -- 0x1380 + x"0A",x"00",x"FD",x"39",x"FD",x"7E",x"00",x"C6", -- 0x1388 + x"FE",x"4F",x"FD",x"7E",x"01",x"CE",x"FF",x"47", -- 0x1390 + x"FD",x"7E",x"02",x"CE",x"FF",x"5F",x"FD",x"7E", -- 0x1398 + x"03",x"CE",x"FF",x"57",x"D5",x"C5",x"2A",x"1D", -- 0x13A0 + x"FA",x"E5",x"2A",x"1B",x"FA",x"E5",x"CD",x"41", -- 0x13A8 + x"1B",x"F1",x"F1",x"F1",x"F1",x"4D",x"44",x"FD", -- 0x13B0 + x"21",x"09",x"FA",x"FD",x"7E",x"00",x"81",x"4F", -- 0x13B8 + x"FD",x"7E",x"01",x"88",x"47",x"FD",x"7E",x"02", -- 0x13C0 + x"8B",x"5F",x"FD",x"7E",x"03",x"8A",x"57",x"FD", -- 0x13C8 + x"21",x"1A",x"00",x"FD",x"39",x"FD",x"71",x"00", -- 0x13D0 + x"FD",x"70",x"01",x"FD",x"73",x"02",x"FD",x"72", -- 0x13D8 + x"03",x"C3",x"D1",x"10",x"2E",x"00",x"FD",x"21", -- 0x13E0 + x"20",x"00",x"FD",x"39",x"FD",x"F9",x"C9",x"21", -- 0x13E8 + x"F4",x"FF",x"39",x"F9",x"21",x"08",x"00",x"39", -- 0x13F0 + x"EB",x"21",x"09",x"FA",x"01",x"04",x"00",x"ED", -- 0x13F8 + x"B0",x"21",x"0E",x"00",x"39",x"7E",x"FD",x"21", -- 0x1400 + x"04",x"00",x"FD",x"39",x"FD",x"77",x"00",x"21", -- 0x1408 + x"0F",x"00",x"39",x"7E",x"FD",x"21",x"04",x"00", -- 0x1410 + x"FD",x"39",x"FD",x"77",x"01",x"21",x"06",x"00", -- 0x1418 + x"39",x"FD",x"7E",x"00",x"C6",x"08",x"77",x"FD", -- 0x1420 + x"7E",x"01",x"CE",x"00",x"23",x"77",x"21",x"06", -- 0x1428 + x"00",x"39",x"7E",x"23",x"66",x"6F",x"4E",x"23", -- 0x1430 + x"46",x"23",x"5E",x"23",x"56",x"79",x"C6",x"FE", -- 0x1438 + x"4F",x"78",x"CE",x"FF",x"47",x"7B",x"CE",x"FF", -- 0x1440 + x"5F",x"7A",x"CE",x"FF",x"57",x"D5",x"C5",x"2A", -- 0x1448 + x"1D",x"FA",x"E5",x"2A",x"1B",x"FA",x"E5",x"CD", -- 0x1450 + x"41",x"1B",x"F1",x"F1",x"F1",x"F1",x"4D",x"44", -- 0x1458 + x"FD",x"21",x"08",x"00",x"FD",x"39",x"FD",x"7E", -- 0x1460 + x"00",x"81",x"4F",x"FD",x"7E",x"01",x"88",x"47", -- 0x1468 + x"FD",x"7E",x"02",x"8B",x"5F",x"FD",x"7E",x"03", -- 0x1470 + x"8A",x"57",x"FD",x"21",x"00",x"00",x"FD",x"39", -- 0x1478 + x"FD",x"71",x"00",x"FD",x"70",x"01",x"FD",x"73", -- 0x1480 + x"02",x"FD",x"72",x"03",x"21",x"04",x"00",x"39", -- 0x1488 + x"7E",x"23",x"66",x"6F",x"4E",x"23",x"46",x"23", -- 0x1490 + x"5E",x"23",x"56",x"79",x"FD",x"21",x"1F",x"FA", -- 0x1498 + x"FD",x"A6",x"00",x"4F",x"78",x"FD",x"A6",x"01", -- 0x14A0 + x"47",x"7B",x"FD",x"A6",x"02",x"5F",x"7A",x"FD", -- 0x14A8 + x"A6",x"03",x"57",x"FD",x"21",x"00",x"00",x"FD", -- 0x14B0 + x"39",x"FD",x"7E",x"00",x"81",x"4F",x"FD",x"7E", -- 0x14B8 + x"01",x"88",x"47",x"FD",x"7E",x"02",x"8B",x"5F", -- 0x14C0 + x"FD",x"7E",x"03",x"8A",x"57",x"21",x"10",x"00", -- 0x14C8 + x"39",x"7E",x"23",x"66",x"6F",x"E5",x"D5",x"C5", -- 0x14D0 + x"CD",x"E8",x"04",x"F1",x"F1",x"F1",x"7D",x"B7", -- 0x14D8 + x"20",x"03",x"6F",x"18",x"6F",x"FD",x"21",x"04", -- 0x14E0 + x"00",x"FD",x"39",x"FD",x"6E",x"00",x"FD",x"66", -- 0x14E8 + x"01",x"4E",x"23",x"46",x"23",x"5E",x"23",x"56", -- 0x14F0 + x"0C",x"20",x"07",x"04",x"20",x"04",x"1C",x"20", -- 0x14F8 + x"01",x"14",x"FD",x"6E",x"00",x"FD",x"66",x"01", -- 0x1500 + x"71",x"23",x"70",x"23",x"73",x"23",x"72",x"79", -- 0x1508 + x"FD",x"21",x"1F",x"FA",x"FD",x"A6",x"00",x"4F", -- 0x1510 + x"78",x"FD",x"A6",x"01",x"47",x"7B",x"FD",x"A6", -- 0x1518 + x"02",x"5F",x"7A",x"FD",x"A6",x"03",x"B3",x"B0", -- 0x1520 + x"B1",x"20",x"27",x"21",x"06",x"00",x"39",x"7E", -- 0x1528 + x"23",x"66",x"6F",x"4E",x"23",x"46",x"23",x"5E", -- 0x1530 + x"23",x"56",x"D5",x"C5",x"CD",x"BB",x"05",x"F1", -- 0x1538 + x"F1",x"4D",x"44",x"21",x"06",x"00",x"39",x"7E", -- 0x1540 + x"23",x"66",x"6F",x"71",x"23",x"70",x"23",x"73", -- 0x1548 + x"23",x"72",x"2E",x"01",x"FD",x"21",x"0C",x"00", -- 0x1550 + x"FD",x"39",x"FD",x"F9",x"C9",x"3E",x"40",x"01", -- 0x1558 + x"3B",x"24",x"ED",x"79",x"3E",x"00",x"01",x"3B", -- 0x1560 + x"25",x"ED",x"79",x"3E",x"41",x"01",x"3B",x"24", -- 0x1568 + x"ED",x"79",x"01",x"00",x"00",x"C5",x"79",x"01", -- 0x1570 + x"3B",x"25",x"ED",x"79",x"C1",x"03",x"78",x"D6", -- 0x1578 + x"01",x"38",x"F2",x"C9",x"00",x"00",x"00",x"00", -- 0x1580 + x"00",x"00",x"00",x"00",x"00",x"10",x"10",x"10", -- 0x1588 + x"10",x"00",x"10",x"00",x"00",x"24",x"24",x"00", -- 0x1590 + x"00",x"00",x"00",x"00",x"00",x"24",x"7E",x"24", -- 0x1598 + x"24",x"7E",x"24",x"00",x"00",x"08",x"3E",x"28", -- 0x15A0 + x"3E",x"0A",x"3E",x"08",x"00",x"62",x"64",x"08", -- 0x15A8 + x"10",x"26",x"46",x"00",x"00",x"10",x"28",x"10", -- 0x15B0 + x"2A",x"44",x"3A",x"00",x"00",x"08",x"10",x"00", -- 0x15B8 + x"00",x"00",x"00",x"00",x"00",x"04",x"08",x"08", -- 0x15C0 + x"08",x"08",x"04",x"00",x"00",x"20",x"10",x"10", -- 0x15C8 + x"10",x"10",x"20",x"00",x"00",x"00",x"14",x"08", -- 0x15D0 + x"3E",x"08",x"14",x"00",x"00",x"00",x"08",x"08", -- 0x15D8 + x"3E",x"08",x"08",x"00",x"00",x"00",x"00",x"00", -- 0x15E0 + x"00",x"08",x"08",x"10",x"00",x"00",x"00",x"00", -- 0x15E8 + x"3E",x"00",x"00",x"00",x"00",x"00",x"00",x"00", -- 0x15F0 + x"00",x"18",x"18",x"00",x"00",x"00",x"02",x"04", -- 0x15F8 + x"08",x"10",x"20",x"00",x"00",x"3C",x"46",x"4A", -- 0x1600 + x"52",x"62",x"3C",x"00",x"00",x"18",x"28",x"08", -- 0x1608 + x"08",x"08",x"3E",x"00",x"00",x"3C",x"42",x"02", -- 0x1610 + x"3C",x"40",x"7E",x"00",x"00",x"3C",x"42",x"0C", -- 0x1618 + x"02",x"42",x"3C",x"00",x"00",x"08",x"18",x"28", -- 0x1620 + x"48",x"7E",x"08",x"00",x"00",x"7E",x"40",x"7C", -- 0x1628 + x"02",x"42",x"3C",x"00",x"00",x"3C",x"40",x"7C", -- 0x1630 + x"42",x"42",x"3C",x"00",x"00",x"7E",x"02",x"04", -- 0x1638 + x"08",x"10",x"10",x"00",x"00",x"3C",x"42",x"3C", -- 0x1640 + x"42",x"42",x"3C",x"00",x"00",x"3C",x"42",x"42", -- 0x1648 + x"3E",x"02",x"3C",x"00",x"00",x"00",x"00",x"10", -- 0x1650 + x"00",x"00",x"10",x"00",x"00",x"00",x"10",x"00", -- 0x1658 + x"00",x"10",x"10",x"20",x"00",x"00",x"04",x"08", -- 0x1660 + x"10",x"08",x"04",x"00",x"00",x"00",x"00",x"3E", -- 0x1668 + x"00",x"3E",x"00",x"00",x"00",x"00",x"20",x"10", -- 0x1670 + x"08",x"10",x"20",x"00",x"00",x"3C",x"42",x"04", -- 0x1678 + x"08",x"00",x"08",x"00",x"00",x"3C",x"4A",x"56", -- 0x1680 + x"5E",x"40",x"3C",x"00",x"00",x"3C",x"42",x"42", -- 0x1688 + x"7E",x"42",x"42",x"00",x"00",x"7C",x"42",x"7C", -- 0x1690 + x"42",x"42",x"7C",x"00",x"00",x"3C",x"42",x"40", -- 0x1698 + x"40",x"42",x"3C",x"00",x"00",x"78",x"44",x"42", -- 0x16A0 + x"42",x"44",x"78",x"00",x"00",x"7E",x"40",x"7C", -- 0x16A8 + x"40",x"40",x"7E",x"00",x"00",x"7E",x"40",x"7C", -- 0x16B0 + x"40",x"40",x"40",x"00",x"00",x"3C",x"42",x"40", -- 0x16B8 + x"4E",x"42",x"3C",x"00",x"00",x"42",x"42",x"7E", -- 0x16C0 + x"42",x"42",x"42",x"00",x"00",x"3E",x"08",x"08", -- 0x16C8 + x"08",x"08",x"3E",x"00",x"00",x"02",x"02",x"02", -- 0x16D0 + x"42",x"42",x"3C",x"00",x"00",x"44",x"48",x"70", -- 0x16D8 + x"48",x"44",x"42",x"00",x"00",x"40",x"40",x"40", -- 0x16E0 + x"40",x"40",x"7E",x"00",x"00",x"42",x"66",x"5A", -- 0x16E8 + x"42",x"42",x"42",x"00",x"00",x"42",x"62",x"52", -- 0x16F0 + x"4A",x"46",x"42",x"00",x"00",x"3C",x"42",x"42", -- 0x16F8 + x"42",x"42",x"3C",x"00",x"00",x"7C",x"42",x"42", -- 0x1700 + x"7C",x"40",x"40",x"00",x"00",x"3C",x"42",x"42", -- 0x1708 + x"52",x"4A",x"3C",x"00",x"00",x"7C",x"42",x"42", -- 0x1710 + x"7C",x"44",x"42",x"00",x"00",x"3C",x"40",x"3C", -- 0x1718 + x"02",x"42",x"3C",x"00",x"00",x"FE",x"10",x"10", -- 0x1720 + x"10",x"10",x"10",x"00",x"00",x"42",x"42",x"42", -- 0x1728 + x"42",x"42",x"3C",x"00",x"00",x"42",x"42",x"42", -- 0x1730 + x"42",x"24",x"18",x"00",x"00",x"42",x"42",x"42", -- 0x1738 + x"42",x"5A",x"24",x"00",x"00",x"42",x"24",x"18", -- 0x1740 + x"18",x"24",x"42",x"00",x"00",x"82",x"44",x"28", -- 0x1748 + x"10",x"10",x"10",x"00",x"00",x"7E",x"04",x"08", -- 0x1750 + x"10",x"20",x"7E",x"00",x"00",x"0E",x"08",x"08", -- 0x1758 + x"08",x"08",x"0E",x"00",x"00",x"00",x"40",x"20", -- 0x1760 + x"10",x"08",x"04",x"00",x"00",x"70",x"10",x"10", -- 0x1768 + x"10",x"10",x"70",x"00",x"00",x"10",x"38",x"54", -- 0x1770 + x"10",x"10",x"10",x"00",x"00",x"00",x"00",x"00", -- 0x1778 + x"00",x"00",x"00",x"FF",x"00",x"1C",x"22",x"78", -- 0x1780 + x"20",x"20",x"7E",x"00",x"00",x"00",x"38",x"04", -- 0x1788 + x"3C",x"44",x"3C",x"00",x"00",x"20",x"20",x"3C", -- 0x1790 + x"22",x"22",x"3C",x"00",x"00",x"00",x"1C",x"20", -- 0x1798 + x"20",x"20",x"1C",x"00",x"00",x"04",x"04",x"3C", -- 0x17A0 + x"44",x"44",x"3C",x"00",x"00",x"00",x"38",x"44", -- 0x17A8 + x"78",x"40",x"3C",x"00",x"00",x"0C",x"10",x"18", -- 0x17B0 + x"10",x"10",x"10",x"00",x"00",x"00",x"3C",x"44", -- 0x17B8 + x"44",x"3C",x"04",x"38",x"00",x"40",x"40",x"78", -- 0x17C0 + x"44",x"44",x"44",x"00",x"00",x"10",x"00",x"30", -- 0x17C8 + x"10",x"10",x"38",x"00",x"00",x"04",x"00",x"04", -- 0x17D0 + x"04",x"04",x"24",x"18",x"00",x"20",x"28",x"30", -- 0x17D8 + x"30",x"28",x"24",x"00",x"00",x"10",x"10",x"10", -- 0x17E0 + x"10",x"10",x"0C",x"00",x"00",x"00",x"68",x"54", -- 0x17E8 + x"54",x"54",x"54",x"00",x"00",x"00",x"78",x"44", -- 0x17F0 + x"44",x"44",x"44",x"00",x"00",x"00",x"38",x"44", -- 0x17F8 + x"44",x"44",x"38",x"00",x"00",x"00",x"78",x"44", -- 0x1800 + x"44",x"78",x"40",x"40",x"00",x"00",x"3C",x"44", -- 0x1808 + x"44",x"3C",x"04",x"06",x"00",x"00",x"1C",x"20", -- 0x1810 + x"20",x"20",x"20",x"00",x"00",x"00",x"38",x"40", -- 0x1818 + x"38",x"04",x"78",x"00",x"00",x"10",x"38",x"10", -- 0x1820 + x"10",x"10",x"0C",x"00",x"00",x"00",x"44",x"44", -- 0x1828 + x"44",x"44",x"38",x"00",x"00",x"00",x"44",x"44", -- 0x1830 + x"28",x"28",x"10",x"00",x"00",x"00",x"44",x"54", -- 0x1838 + x"54",x"54",x"28",x"00",x"00",x"00",x"44",x"28", -- 0x1840 + x"10",x"28",x"44",x"00",x"00",x"00",x"44",x"44", -- 0x1848 + x"44",x"3C",x"04",x"38",x"00",x"00",x"7C",x"08", -- 0x1850 + x"10",x"20",x"7C",x"00",x"00",x"0E",x"08",x"30", -- 0x1858 + x"08",x"08",x"0E",x"00",x"00",x"08",x"08",x"08", -- 0x1860 + x"08",x"08",x"08",x"00",x"00",x"70",x"10",x"0C", -- 0x1868 + x"10",x"10",x"70",x"00",x"00",x"14",x"28",x"00", -- 0x1870 + x"00",x"00",x"00",x"00",x"3C",x"42",x"99",x"A1", -- 0x1878 + x"A1",x"99",x"42",x"3C",x"3E",x"40",x"01",x"3B", -- 0x1880 + x"24",x"ED",x"79",x"3E",x"00",x"01",x"3B",x"25", -- 0x1888 + x"ED",x"79",x"3E",x"41",x"01",x"3B",x"24",x"ED", -- 0x1890 + x"79",x"01",x"00",x"00",x"C5",x"3E",x"00",x"01", -- 0x1898 + x"3B",x"25",x"ED",x"79",x"3E",x"02",x"01",x"3B", -- 0x18A0 + x"25",x"ED",x"79",x"3E",x"A0",x"01",x"3B",x"25", -- 0x18A8 + x"ED",x"79",x"3E",x"A2",x"01",x"3B",x"25",x"ED", -- 0x18B0 + x"79",x"3E",x"14",x"01",x"3B",x"25",x"ED",x"79", -- 0x18B8 + x"3E",x"16",x"01",x"3B",x"25",x"ED",x"79",x"3E", -- 0x18C0 + x"B4",x"01",x"3B",x"25",x"ED",x"79",x"3E",x"B6", -- 0x18C8 + x"01",x"3B",x"25",x"ED",x"79",x"3E",x"00",x"01", -- 0x18D0 + x"3B",x"25",x"ED",x"79",x"3E",x"03",x"01",x"3B", -- 0x18D8 + x"25",x"ED",x"79",x"3E",x"E0",x"01",x"3B",x"25", -- 0x18E0 + x"ED",x"79",x"3E",x"E7",x"01",x"3B",x"25",x"ED", -- 0x18E8 + x"79",x"3E",x"1C",x"01",x"3B",x"25",x"ED",x"79", -- 0x18F0 + x"3E",x"1F",x"01",x"3B",x"25",x"ED",x"79",x"3E", -- 0x18F8 + x"FC",x"01",x"3B",x"25",x"ED",x"79",x"3E",x"FF", -- 0x1900 + x"01",x"3B",x"25",x"ED",x"79",x"C1",x"03",x"79", -- 0x1908 + x"D6",x"10",x"78",x"DE",x"00",x"38",x"85",x"3E", -- 0x1910 + x"40",x"01",x"3B",x"24",x"ED",x"79",x"3E",x"80", -- 0x1918 + x"01",x"3B",x"25",x"ED",x"79",x"3E",x"41",x"01", -- 0x1920 + x"3B",x"24",x"ED",x"79",x"01",x"00",x"00",x"C5", -- 0x1928 + x"3E",x"00",x"01",x"3B",x"25",x"ED",x"79",x"3E", -- 0x1930 + x"02",x"01",x"3B",x"25",x"ED",x"79",x"3E",x"A0", -- 0x1938 + x"01",x"3B",x"25",x"ED",x"79",x"3E",x"A2",x"01", -- 0x1940 + x"3B",x"25",x"ED",x"79",x"3E",x"14",x"01",x"3B", -- 0x1948 + x"25",x"ED",x"79",x"3E",x"16",x"01",x"3B",x"25", -- 0x1950 + x"ED",x"79",x"3E",x"B4",x"01",x"3B",x"25",x"ED", -- 0x1958 + x"79",x"3E",x"B6",x"01",x"3B",x"25",x"ED",x"79", -- 0x1960 + x"3E",x"00",x"01",x"3B",x"25",x"ED",x"79",x"3E", -- 0x1968 + x"03",x"01",x"3B",x"25",x"ED",x"79",x"3E",x"E0", -- 0x1970 + x"01",x"3B",x"25",x"ED",x"79",x"3E",x"E7",x"01", -- 0x1978 + x"3B",x"25",x"ED",x"79",x"3E",x"1C",x"01",x"3B", -- 0x1980 + x"25",x"ED",x"79",x"3E",x"1F",x"01",x"3B",x"25", -- 0x1988 + x"ED",x"79",x"3E",x"FC",x"01",x"3B",x"25",x"ED", -- 0x1990 + x"79",x"3E",x"FF",x"01",x"3B",x"25",x"ED",x"79", -- 0x1998 + x"C1",x"03",x"79",x"D6",x"10",x"78",x"DE",x"00", -- 0x19A0 + x"38",x"85",x"3E",x"43",x"01",x"3B",x"24",x"ED", -- 0x19A8 + x"79",x"3E",x"10",x"01",x"3B",x"25",x"ED",x"79", -- 0x19B0 + x"CD",x"5D",x"15",x"3E",x"43",x"01",x"3B",x"24", -- 0x19B8 + x"ED",x"79",x"3E",x"20",x"01",x"3B",x"25",x"ED", -- 0x19C0 + x"79",x"CD",x"5D",x"15",x"21",x"38",x"FC",x"36", -- 0x19C8 + x"00",x"21",x"37",x"FC",x"36",x"00",x"3E",x"00", -- 0x19D0 + x"D3",x"FE",x"01",x"00",x"40",x"59",x"50",x"AF", -- 0x19D8 + x"12",x"03",x"78",x"D6",x"58",x"38",x"F6",x"01", -- 0x19E0 + x"00",x"58",x"59",x"50",x"AF",x"12",x"03",x"78", -- 0x19E8 + x"D6",x"5B",x"38",x"F6",x"C9",x"21",x"02",x"00", -- 0x19F0 + x"39",x"7E",x"E6",x"1F",x"32",x"37",x"FC",x"21", -- 0x19F8 + x"03",x"00",x"39",x"7E",x"FD",x"21",x"38",x"FC", -- 0x1A00 + x"FD",x"77",x"00",x"3E",x"17",x"FD",x"96",x"00", -- 0x1A08 + x"D0",x"FD",x"36",x"00",x"17",x"C9",x"F5",x"F5", -- 0x1A10 + x"21",x"06",x"00",x"39",x"7E",x"06",x"00",x"C6", -- 0x1A18 + x"E0",x"4F",x"78",x"CE",x"FF",x"47",x"CB",x"21", -- 0x1A20 + x"CB",x"10",x"CB",x"21",x"CB",x"10",x"CB",x"21", -- 0x1A28 + x"CB",x"10",x"ED",x"43",x"31",x"FC",x"3A",x"38", -- 0x1A30 + x"FC",x"FD",x"21",x"02",x"00",x"FD",x"39",x"FD", -- 0x1A38 + x"77",x"00",x"FD",x"36",x"01",x"00",x"FD",x"7E", -- 0x1A40 + x"00",x"FD",x"21",x"33",x"FC",x"FD",x"77",x"01", -- 0x1A48 + x"FD",x"36",x"00",x"00",x"0E",x"00",x"FD",x"7E", -- 0x1A50 + x"01",x"E6",x"18",x"47",x"FD",x"7E",x"00",x"E6", -- 0x1A58 + x"E0",x"6F",x"26",x"00",x"29",x"29",x"29",x"79", -- 0x1A60 + x"B5",x"4F",x"78",x"B4",x"47",x"1E",x"00",x"FD", -- 0x1A68 + x"7E",x"01",x"E6",x"07",x"57",x"3E",x"03",x"CB", -- 0x1A70 + x"3A",x"CB",x"1B",x"3D",x"20",x"F9",x"79",x"B3", -- 0x1A78 + x"FD",x"77",x"00",x"78",x"B2",x"FD",x"77",x"01", -- 0x1A80 + x"FD",x"7E",x"00",x"C6",x"00",x"5F",x"FD",x"7E", -- 0x1A88 + x"01",x"CE",x"40",x"57",x"21",x"37",x"FC",x"4E", -- 0x1A90 + x"06",x"00",x"33",x"33",x"C5",x"7B",x"21",x"00", -- 0x1A98 + x"00",x"39",x"FD",x"21",x"33",x"FC",x"86",x"FD", -- 0x1AA0 + x"77",x"00",x"7A",x"23",x"8E",x"FD",x"23",x"FD", -- 0x1AA8 + x"77",x"00",x"D1",x"E1",x"E5",x"D5",x"29",x"29", -- 0x1AB0 + x"29",x"29",x"29",x"5D",x"7C",x"C6",x"58",x"57", -- 0x1AB8 + x"7B",x"21",x"35",x"FC",x"81",x"77",x"7A",x"88", -- 0x1AC0 + x"23",x"77",x"0E",x"00",x"ED",x"5B",x"33",x"FC", -- 0x1AC8 + x"FD",x"21",x"84",x"15",x"C5",x"ED",x"4B",x"31", -- 0x1AD0 + x"FC",x"FD",x"09",x"C1",x"FD",x"7E",x"00",x"12", -- 0x1AD8 + x"21",x"33",x"FC",x"7E",x"C6",x"00",x"77",x"23", -- 0x1AE0 + x"7E",x"CE",x"01",x"77",x"FD",x"21",x"31",x"FC", -- 0x1AE8 + x"FD",x"34",x"00",x"20",x"03",x"FD",x"34",x"01", -- 0x1AF0 + x"0C",x"79",x"D6",x"08",x"38",x"CE",x"21",x"37", -- 0x1AF8 + x"FC",x"34",x"F1",x"F1",x"C9",x"D1",x"C1",x"C5", -- 0x1B00 + x"D5",x"0A",x"03",x"57",x"B7",x"C8",x"C5",x"D5", -- 0x1B08 + x"33",x"CD",x"16",x"1A",x"33",x"C1",x"18",x"F1", -- 0x1B10 + x"C1",x"E1",x"E5",x"C5",x"AF",x"47",x"4F",x"ED", -- 0x1B18 + x"B1",x"21",x"FF",x"FF",x"ED",x"42",x"C9",x"F1", -- 0x1B20 + x"C1",x"D1",x"D5",x"C5",x"F5",x"AF",x"6F",x"B0", -- 0x1B28 + x"06",x"10",x"20",x"04",x"06",x"08",x"79",x"29", -- 0x1B30 + x"CB",x"11",x"17",x"30",x"01",x"19",x"10",x"F7", -- 0x1B38 + x"C9",x"DD",x"E5",x"DD",x"21",x"00",x"00",x"DD", -- 0x1B40 + x"39",x"21",x"FA",x"FF",x"39",x"F9",x"21",x"0A", -- 0x1B48 + x"00",x"39",x"EB",x"4B",x"42",x"03",x"03",x"DD", -- 0x1B50 + x"71",x"FE",x"DD",x"70",x"FF",x"6B",x"62",x"23", -- 0x1B58 + x"23",x"4E",x"23",x"46",x"21",x"0E",x"00",x"39", -- 0x1B60 + x"DD",x"75",x"FC",x"DD",x"74",x"FD",x"DD",x"6E", -- 0x1B68 + x"FC",x"DD",x"66",x"FD",x"7E",x"23",x"66",x"6F", -- 0x1B70 + x"D5",x"E5",x"C5",x"CD",x"27",x"1B",x"F1",x"F1", -- 0x1B78 + x"4D",x"44",x"D1",x"DD",x"6E",x"FE",x"DD",x"66", -- 0x1B80 + x"FF",x"71",x"23",x"70",x"4B",x"42",x"03",x"03", -- 0x1B88 + x"DD",x"71",x"FE",x"DD",x"70",x"FF",x"6B",x"62", -- 0x1B90 + x"23",x"23",x"7E",x"DD",x"77",x"FA",x"23",x"7E", -- 0x1B98 + x"DD",x"77",x"FB",x"C1",x"E1",x"E5",x"C5",x"23", -- 0x1BA0 + x"23",x"4E",x"23",x"46",x"6B",x"62",x"7E",x"23", -- 0x1BA8 + x"66",x"6F",x"D5",x"E5",x"C5",x"CD",x"27",x"1B", -- 0x1BB0 + x"F1",x"F1",x"D1",x"DD",x"7E",x"FA",x"85",x"4F", -- 0x1BB8 + x"DD",x"7E",x"FB",x"8C",x"47",x"DD",x"6E",x"FE", -- 0x1BC0 + x"DD",x"66",x"FF",x"71",x"23",x"70",x"4B",x"42", -- 0x1BC8 + x"03",x"03",x"33",x"33",x"C5",x"6B",x"62",x"23", -- 0x1BD0 + x"23",x"4E",x"23",x"46",x"6B",x"62",x"23",x"7E", -- 0x1BD8 + x"DD",x"77",x"FE",x"DD",x"6E",x"FC",x"DD",x"66", -- 0x1BE0 + x"FD",x"23",x"66",x"D5",x"C5",x"DD",x"5E",x"FE", -- 0x1BE8 + x"2E",x"00",x"55",x"06",x"08",x"29",x"30",x"01", -- 0x1BF0 + x"19",x"10",x"FA",x"C1",x"D1",x"09",x"4D",x"44", -- 0x1BF8 + x"E1",x"E5",x"71",x"23",x"70",x"C1",x"E1",x"E5", -- 0x1C00 + x"C5",x"4E",x"6B",x"62",x"23",x"66",x"D5",x"59", -- 0x1C08 + x"2E",x"00",x"55",x"06",x"08",x"29",x"30",x"01", -- 0x1C10 + x"19",x"10",x"FA",x"D1",x"4D",x"44",x"DD",x"6E", -- 0x1C18 + x"FC",x"DD",x"66",x"FD",x"23",x"E5",x"FD",x"E1", -- 0x1C20 + x"6B",x"62",x"7E",x"DD",x"77",x"FA",x"DD",x"6E", -- 0x1C28 + x"FC",x"DD",x"66",x"FD",x"23",x"6E",x"D5",x"C5", -- 0x1C30 + x"5D",x"DD",x"66",x"FA",x"2E",x"00",x"55",x"06", -- 0x1C38 + x"08",x"29",x"30",x"01",x"19",x"10",x"FA",x"C1", -- 0x1C40 + x"D1",x"FD",x"75",x"00",x"FD",x"74",x"01",x"DD", -- 0x1C48 + x"6E",x"FC",x"DD",x"66",x"FD",x"23",x"23",x"23", -- 0x1C50 + x"E3",x"DD",x"6E",x"FC",x"DD",x"66",x"FD",x"23", -- 0x1C58 + x"E5",x"FD",x"E1",x"DD",x"6E",x"FC",x"DD",x"66", -- 0x1C60 + x"FD",x"23",x"7E",x"23",x"66",x"6F",x"09",x"FD", -- 0x1C68 + x"75",x"00",x"FD",x"74",x"01",x"BF",x"ED",x"42", -- 0x1C70 + x"3E",x"00",x"17",x"E1",x"E5",x"77",x"4B",x"42", -- 0x1C78 + x"1A",x"5F",x"DD",x"6E",x"FC",x"DD",x"66",x"FD", -- 0x1C80 + x"66",x"C5",x"2E",x"00",x"55",x"06",x"08",x"29", -- 0x1C88 + x"30",x"01",x"19",x"10",x"FA",x"C1",x"EB",x"7B", -- 0x1C90 + x"02",x"03",x"7A",x"02",x"D1",x"C1",x"C5",x"D5", -- 0x1C98 + x"AF",x"02",x"DD",x"7E",x"04",x"DD",x"86",x"08", -- 0x1CA0 + x"6F",x"DD",x"7E",x"05",x"DD",x"8E",x"09",x"67", -- 0x1CA8 + x"DD",x"7E",x"06",x"DD",x"8E",x"0A",x"5F",x"DD", -- 0x1CB0 + x"7E",x"07",x"DD",x"8E",x"0B",x"57",x"DD",x"F9", -- 0x1CB8 + x"DD",x"E1",x"C9",x"47",x"04",x"53",x"04",x"01", -- 0x1CC0 + x"04",x"00",x"78",x"B1",x"28",x"08",x"11",x"39", -- 0x1CC8 + x"FC",x"21",x"C3",x"1C",x"ED",x"B0",x"C9",x"FF", -- 0x1CD0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1CD8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1CE0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1CE8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1CF0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1CF8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D00 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D08 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D10 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D18 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D20 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D28 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D30 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D38 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D40 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D48 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D50 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D58 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D60 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D68 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D70 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D78 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D80 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D88 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D90 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1D98 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1DA0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1DA8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1DB0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1DB8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1DC0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1DC8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1DD0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1DD8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1DE0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1DE8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1DF0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1DF8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E00 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E08 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E10 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E18 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E20 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E28 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E30 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E38 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E40 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E48 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E50 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E58 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E60 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E68 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E70 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E78 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E80 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E88 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E90 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1E98 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1EA0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1EA8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1EB0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1EB8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1EC0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1EC8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1ED0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1ED8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1EE0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1EE8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1EF0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1EF8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F00 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F08 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F10 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F18 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F20 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F28 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F30 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F38 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F40 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F48 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F50 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F58 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F60 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F68 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F70 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F78 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F80 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F88 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F90 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1F98 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1FA0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1FA8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1FB0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1FB8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1FC0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1FC8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1FD0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1FD8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1FE0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1FE8 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF", -- 0x1FF0 + x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF" -- 0x1FF8 + ); + +begin + + p_rom : process + begin + wait until rising_edge(CLK); + DATA <= ROM(to_integer(unsigned(ADDR))); + end process; +end RTL; diff --git a/rtl/serial/fifop.vhd b/rtl/serial/fifop.vhd new file mode 100644 index 0000000..248bdc3 --- /dev/null +++ b/rtl/serial/fifop.vhd @@ -0,0 +1,151 @@ + +-- FIFO Manager +-- Copyright 2020 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +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; diff --git a/rtl/serial/spi_master.vhd b/rtl/serial/spi_master.vhd new file mode 100644 index 0000000..6fa5260 --- /dev/null +++ b/rtl/serial/spi_master.vhd @@ -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; diff --git a/rtl/serial/uart.vhd b/rtl/serial/uart.vhd new file mode 100644 index 0000000..115fbec --- /dev/null +++ b/rtl/serial/uart.vhd @@ -0,0 +1,818 @@ +-- ZX NEXT UARTS +-- Copyright 2020 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- 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; diff --git a/rtl/serial/uart_old.vhd b/rtl/serial/uart_old.vhd new file mode 100644 index 0000000..27cca98 --- /dev/null +++ b/rtl/serial/uart_old.vhd @@ -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 +-- +-- +-- 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 +-- . + +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; diff --git a/rtl/serial/uart_rx.vhd b/rtl/serial/uart_rx.vhd new file mode 100644 index 0000000..f5d931a --- /dev/null +++ b/rtl/serial/uart_rx.vhd @@ -0,0 +1,316 @@ +-- UART RX +-- Copyright 2020 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- 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; diff --git a/rtl/serial/uart_tx.vhd b/rtl/serial/uart_tx.vhd new file mode 100644 index 0000000..a5e2177 --- /dev/null +++ b/rtl/serial/uart_tx.vhd @@ -0,0 +1,247 @@ +-- UART TX +-- Copyright 2020 Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +-- 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; diff --git a/rtl/video/layer2.vhd b/rtl/video/layer2.vhd new file mode 100644 index 0000000..ef96a7a --- /dev/null +++ b/rtl/video/layer2.vhd @@ -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 +-- +-- +-- 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 +-- . + +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; diff --git a/rtl/video/lores.vhd b/rtl/video/lores.vhd new file mode 100644 index 0000000..17ba4cd --- /dev/null +++ b/rtl/video/lores.vhd @@ -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 +-- +-- +-- 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 +-- . + +-- 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 ) +-- 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; diff --git a/rtl/video/sprites.vhd b/rtl/video/sprites.vhd new file mode 100644 index 0000000..61962ec --- /dev/null +++ b/rtl/video/sprites.vhd @@ -0,0 +1,1088 @@ + +-- ZX Spectrum Next Hardware Sprites +-- Copyright 2020 Alvin Albrecht +-- +-- Sprites v1 +-- Theorical Model - Victor Trucco +-- VHDL - Fabio Belavenuto +-- +-- Sprites v2 +-- Rewritten and enhanced - Alvin Albrecht +-- Ideas - Spectrum Next Team, David Burton, Peter Ped Helcmanovsky +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.std_logic_unsigned.all; + +entity sprites is + port ( + + clock_master_i : in std_logic; + clock_master_180o_i : in std_logic; + clock_pixel_i : in std_logic; + reset_i : in std_logic; + zero_on_top_i : in std_logic; + border_clip_en_i : in std_logic; + over_border_i : in std_logic; + hcounter_i : in unsigned( 8 downto 0); + vcounter_i : in unsigned( 8 downto 0); + transp_colour_i : in std_logic_vector( 7 downto 0); + + -- CPU + + port57_w_en_s : in std_logic; + port5B_w_en_s : in std_logic; + port303b_r_en_s: in std_logic; + port303b_w_en_s: in std_logic; + cpu_d_i : in std_logic_vector( 7 downto 0); + cpu_d_o : out std_logic_vector( 7 downto 0); + + -- NEXTREG MIRROR + + mirror_tie_i : in std_logic; -- 1 = nextreg 0x34 and io port 0x303B tied together + mirror_we_i : in std_logic; + mirror_index_i : in std_logic_vector(2 downto 0); -- attributes 0-4, sprite number if 7 + mirror_data_i : in std_logic_vector(7 downto 0); + mirror_inc_i : in std_logic; -- one to increment sprite number + mirror_num_o : out std_logic_vector(6 downto 0); -- currently selected sprite number + + -- Out + + rgb_o : out std_logic_vector(7 downto 0); + pixel_en_o : out std_logic; + + -- 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 sprites is + + -- the implementation is not fully parameterized primarily because the memories were generated by coregen + + constant SPRITE_SIZE_BITS : integer := 4; -- sprites are 16x16 pixels + constant SPRITE_SIZE : integer := (2 ** SPRITE_SIZE_BITS); + +-- constant TOTAL_SPRITES_BITS : integer := 6; -- 64 sprites total + constant TOTAL_SPRITES_BITS : integer := 7; -- 128 sprites total + constant TOTAL_SPRITES : integer := (2 ** TOTAL_SPRITES_BITS); + + constant TOTAL_PATTERN_BITS : integer := 6; -- 64 different sprite patterns + constant TOTAL_PATTERNS : integer := (2 ** TOTAL_PATTERN_BITS); + + -- coregen + + component sdpram_128_8 is + PORT ( + + DPRA : IN STD_LOGIC_VECTOR(7-1 downto 0) := (OTHERS => '0'); + CLK : IN STD_LOGIC; + WE : IN STD_LOGIC; + DPO : OUT STD_LOGIC_VECTOR(8-1 downto 0); + A : IN STD_LOGIC_VECTOR(7-1-(4*0*boolean'pos(7>4)) downto 0) + := (OTHERS => '0'); + D : IN STD_LOGIC_VECTOR(8-1 downto 0) := (OTHERS => '0') + + ); + end component; + + component spram_320_9 is + PORT ( + + CLK : IN STD_LOGIC; + WE : IN STD_LOGIC; + SPO : OUT STD_LOGIC_VECTOR(9-1 downto 0); + A : IN STD_LOGIC_VECTOR(9-1-(4*0*boolean'pos(9>4)) downto 0) + := (OTHERS => '0'); + D : IN STD_LOGIC_VECTOR(9-1 downto 0) := (OTHERS => '0') + + ); + end component; + + component sdpbram_16k_8 is + PORT ( + --Port A + WEA : IN STD_LOGIC_VECTOR(0 DOWNTO 0); + ADDRA : IN STD_LOGIC_VECTOR(13 DOWNTO 0); + DINA : IN STD_LOGIC_VECTOR(7 DOWNTO 0); + CLKA : IN STD_LOGIC; + --Port B + ENB : IN STD_LOGIC; --opt port + ADDRB : IN STD_LOGIC_VECTOR(13 DOWNTO 0); + DOUTB : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); + CLKB : IN STD_LOGIC + + ); + end component; + + -- memory wiring + + signal attr_a : std_logic_vector((TOTAL_SPRITES_BITS-1) downto 0); + signal attr_id : std_logic_vector(2 downto 0); + signal attr_data : std_logic_vector(7 downto 0); + signal attr0_we : std_logic; + signal attr1_we : std_logic; + signal attr2_we : std_logic; + signal attr3_we : std_logic; + signal attr4_we : std_logic; + signal spr_attr_a : std_logic_vector((TOTAL_SPRITES_BITS-1) downto 0); + signal sprite_attr_0 : std_logic_vector(7 downto 0); + signal sprite_attr_1 : std_logic_vector(7 downto 0); + signal sprite_attr_2 : std_logic_vector(7 downto 0); + signal sprite_attr_3 : std_logic_vector(7 downto 0); + signal sprite_attr_4 : std_logic_vector(7 downto 0); + + signal l0_we : std_logic; + signal l0_a : std_logic_vector(8 downto 0); + signal l0_d : std_logic_vector(8 downto 0); + signal l0_spo : std_logic_vector(8 downto 0); + signal l1_we : std_logic; + signal l1_a : std_logic_vector(8 downto 0); + signal l1_d : std_logic_vector(8 downto 0); + signal l1_spo : std_logic_vector(8 downto 0); + signal line_buf_sel : std_logic; + + signal port5b_w_en_d : std_logic; + signal pattern_a : std_logic_vector((TOTAL_PATTERN_BITS+8-1) downto 0); + signal pattern_we : std_logic_vector(0 downto 0); + signal spr_pat_addr : std_logic_vector((TOTAL_PATTERN_BITS+8-1) downto 0); + signal spr_pat_re : std_logic; + signal spr_pat_data : std_logic_vector(7 downto 0); + + -- cpu port i/o + + signal attr_index : std_logic_vector((TOTAL_SPRITES_BITS+3-1) downto 0); + signal pattern_index : std_logic_vector((TOTAL_PATTERN_BITS+8-1) downto 0); + + signal index_inc_attr_by_8 : std_logic; + signal index_inc_in_s : std_logic_vector((TOTAL_PATTERN_BITS+8-1) downto 0); -- assumes pattern_index larger than attr_index + signal index_inc_out_s : std_logic_vector((TOTAL_PATTERN_BITS+8-1) downto 0); -- assumes pattern_index larger than attr_index + + signal attr_num_change : std_logic; + + signal io_port_access : std_logic; + signal io_port_access_d : std_logic; + signal io_port_re : std_logic; + signal cpu_request : std_logic; + signal cpu_served : std_logic; + signal cpu_sprite_q : std_logic_vector(TOTAL_SPRITES_BITS-1 downto 0); + signal cpu_index_q : std_logic_vector(2 downto 0); + signal cpu_data_q : std_logic_vector(7 downto 0); + + signal status_reg_s : std_logic_vector(7 downto 0); + signal status_reg_read : std_logic_vector(7 downto 0); + signal sprites_overtime : std_logic; + + -- mirror + + signal mirror_sprite_q : std_logic_vector(7 downto 0); + signal mirror_served : std_logic; + signal mirror_num_change : std_logic; + + -- load sprite line + + signal line_reset_s : std_logic; + signal line_reset_re : std_logic_vector(1 downto 0); + signal spr_cur_vcount : std_logic_vector(8 downto 0); + + signal anchor_rel_type : std_logic; + signal anchor_h : std_logic; + signal anchor_vis : std_logic; + signal anchor_x : std_logic_vector(8 downto 0); + signal anchor_y : std_logic_vector(8 downto 0); + signal anchor_pattern : std_logic_vector(6 downto 0); + signal anchor_paloff : std_logic_vector(3 downto 0); + signal anchor_rotate : std_logic; + signal anchor_xmirror : std_logic; + signal anchor_ymirror : std_logic; + signal anchor_xscale : std_logic_vector(1 downto 0); + signal anchor_yscale : std_logic_vector(1 downto 0); + + signal spr_rel_x0 : std_logic_vector(7 downto 0); + signal spr_rel_y0 : std_logic_vector(7 downto 0); + signal spr_rel_x1 : std_logic_vector(7 downto 0); + signal spr_rel_y1 : std_logic_vector(7 downto 0); + signal spr_rel_x2 : std_logic_vector(8 downto 0); + signal spr_rel_y2 : std_logic_vector(8 downto 0); + signal spr_rel_x3 : std_logic_vector(8 downto 0); + signal spr_rel_y3 : std_logic_vector(8 downto 0); + + signal spr_rel_paloff : std_logic_vector(3 downto 0); + signal spr_rel_xm : std_logic; + signal spr_rel_ym : std_logic; + + signal spr_rel_attr_0 : std_logic_vector(7 downto 0); + signal spr_rel_attr_1 : std_logic_vector(7 downto 0); + signal spr_rel_attr_2 : std_logic_vector(7 downto 0); + signal spr_rel_attr_3 : std_logic_vector(7 downto 0); + signal spr_rel_attr_4 : std_logic_vector(7 downto 0); + + signal spr_cur_attr_0 : std_logic_vector(7 downto 0); + signal spr_cur_attr_1 : std_logic_vector(7 downto 0); + signal spr_cur_attr_2 : std_logic_vector(7 downto 0); + signal spr_cur_attr_3 : std_logic_vector(7 downto 0); + signal spr_cur_attr_4 : std_logic_vector(7 downto 0); + + signal spr_cur_x : std_logic_vector(8 downto 0); + signal spr_cur_y : std_logic_vector(8 downto 0); + + signal spr_relative : std_logic; + signal spr_cur_h : std_logic; + signal spr_cur_n6 : std_logic; + signal spr_rel_pattern : std_logic_vector(6 downto 0); -- N5:N0,N6 + + signal spr_y8 : std_logic; + signal spr_y_offset : std_logic_vector(8 downto 0); + signal spr_y_offset_raw : std_logic_vector(8 downto 0); + signal spr_y_index : std_logic_vector((SPRITE_SIZE_BITS-1) downto 0); + signal spr_x_mirr_eff : std_logic; + signal spr_x_index : std_logic_vector((SPRITE_SIZE_BITS-1) downto 0); + + signal spr_pattern_addr_start : std_logic_vector((TOTAL_PATTERN_BITS+8-1) downto 0); + signal spr_pattern_addr_delta : std_logic_vector((TOTAL_PATTERN_BITS+8-1) downto 0); + + signal spr_cur_hcount_valid : std_logic; + signal spr_cur_notime_mask : std_logic_vector(4 downto 0); + signal spr_cur_notime : std_logic; + + signal spr_cur_index : std_logic_vector((TOTAL_SPRITES_BITS-1) downto 0); + signal spr_cur_index_is_zero : std_logic; + signal spr_width_count : std_logic_vector((SPRITE_SIZE_BITS-1+1+3) downto 0); + signal spr_width_count_next : std_logic_vector((SPRITE_SIZE_BITS-1+1+3) downto 0); + signal spr_width_count_delta : std_logic_vector(3 downto 0); + signal spr_cur_hcount : std_logic_vector(8 downto 0); + signal spr_cur_paloff : std_logic_vector(3 downto 0); + signal spr_cur_visible : std_logic; + signal spr_cur_yoff : std_logic_vector((8-SPRITE_SIZE_BITS) downto 0); + signal spr_cur_x_wrap : std_logic_vector(4 downto 0); + signal spr_cur_4bit : std_logic_vector(1 downto 0); + signal spr_cur_draw_it : std_logic; + + signal spr_cur_pattern_addr : std_logic_vector((TOTAL_PATTERN_BITS+8-1) downto 0); + signal spr_cur_pattern_delta : std_logic_vector((TOTAL_PATTERN_BITS+8-1) downto 0); + + type state_t is (S_IDLE, S_START, S_QUALIFY, S_PROCESS); + signal state_s : state_t; + signal state_next_s : state_t; + + signal spr_line_addr_s : std_logic_vector(8 downto 0); + signal spr_line_data_s : std_logic_vector(8 downto 0); + signal spr_nibble_data : std_logic_vector(3 downto 0); + signal spr_line_we : std_logic; + signal spr_line_we_s : std_logic; + signal spr_line_data_o : std_logic_vector(8 downto 0); + + -- video line generation + + signal hcounter_i_valid : std_logic; + signal vcounter_i_valid : std_logic; + + signal x_s_v : unsigned(8 downto 0); + signal x_e_v : unsigned(8 downto 0); + signal y_s_v : unsigned(8 downto 0); + signal y_e_v : unsigned(8 downto 0); + + signal over_border_s : std_logic; + + signal video_line_we_s : std_logic; + signal video_line_addr_s : std_logic_vector(8 downto 0); + signal video_line_data_s : std_logic_vector(8 downto 0); + signal video_line_rgb_s : std_logic_vector(8 downto 0); + signal video_line_rgb_load : std_logic_vector(8 downto 0); + + signal video_line_re : std_logic; + signal video_line_fe : std_logic; + signal video_line_flag : std_logic; + +begin + + ---------------------------- + -- SPRITE ATTRIBUTE MEMORIES + ---------------------------- + + -- simple dual port ram (sync write, async read) + -- X position (bits 7:0) + + attr0 : sdpram_128_8 + port map ( + DPRA => spr_attr_a, + CLK => clock_master_180o_i, + WE => attr0_we, + DPO => sprite_attr_0, + A => attr_a, + D => attr_data + ); + +-- attr0 : entity work.sdpram +-- generic map ( +-- addr_width_g => TOTAL_SPRITES_BITS, +-- data_width_g => 8 +-- ) +-- port map ( +-- clk_a_i => clock_master_180o_i, +-- we_a_i => attr0_we, +-- addr_a_i => attr_a, +-- data_a_i => attr_data, +-- -- +-- addr_b_i => spr_attr_a, +-- data_b_o => sprite_attr_0 +-- ); + + -- simple dual port ram (sync write, async read) + -- Y position (bits 7:0) + + attr1 : sdpram_128_8 + port map ( + DPRA => spr_attr_a, + CLK => clock_master_180o_i, + WE => attr1_we, + DPO => sprite_attr_1, + A => attr_a, + D => attr_data + ); + +-- attr1 : entity work.sdpram +-- generic map ( +-- addr_width_g => TOTAL_SPRITES_BITS, +-- data_width_g => 8 +-- ) +-- port map ( +-- clk_a_i => clock_master_180o_i, +-- we_a_i => attr1_we, +-- addr_a_i => attr_a, +-- data_a_i => attr_data, +-- -- +-- addr_b_i => spr_attr_a, +-- data_b_o => sprite_attr_1 +-- ); + + -- simple dual port ram (sync write, async read) + -- bits 7-4 is palette offset, bit 3 is X mirror, bit 2 is Y mirror, bit 1 is the rotate flag and bit 0 is X MSB + + attr2 : sdpram_128_8 + port map ( + DPRA => spr_attr_a, + CLK => clock_master_180o_i, + WE => attr2_we, + DPO => sprite_attr_2, + A => attr_a, + D => attr_data + ); + +-- attr2 : entity work.sdpram +-- generic map ( +-- addr_width_g => TOTAL_SPRITES_BITS, +-- data_width_g => 8 +-- ) +-- port map ( +-- clk_a_i => clock_master_180o_i, +-- we_a_i => attr2_we, +-- addr_a_i => attr_a, +-- data_a_i => attr_data, +-- -- +-- addr_b_i => spr_attr_a, +-- data_b_o => sprite_attr_2 +-- ); + + -- simple dual port ram (sync write, async read) + -- bit 7 is the visible flag, bit 6 set if fifth attr byte follows, bits 5-0 is Name (pattern index, 0-63) + + attr3 : sdpram_128_8 + port map ( + DPRA => spr_attr_a, + CLK => clock_master_180o_i, + WE => attr3_we, + DPO => sprite_attr_3, + A => attr_a, + D => attr_data + ); + +-- attr3 : entity work.sdpram +-- generic map ( +-- addr_width_g => TOTAL_SPRITES_BITS, +-- data_width_g => 8 +-- ) +-- port map ( +-- clk_a_i => clock_master_180o_i, +-- we_a_i => attr3_we, +-- addr_a_i => attr_a, +-- data_a_i => attr_data, +-- -- +-- addr_b_i => spr_attr_a, +-- data_b_o => sprite_attr_3 +-- ); + + -- simple dual port ram (sync write, async read) + -- bit 7 set for 4-bit patterns, bit 6 is Name(6), bit 5 is reserved at 0, bits(4:3) XX scale, bits(2:1) YY scale, bit 0 is Y MSB + + attr4 : sdpram_128_8 + port map ( + DPRA => spr_attr_a, + CLK => clock_master_180o_i, + WE => attr4_we, + DPO => sprite_attr_4, + A => attr_a, + D => attr_data + ); + +-- attr4 : entity work.sdpram +-- generic map ( +-- addr_width_g => TOTAL_SPRITES_BITS, +-- data_width_g => 8 +-- ) +-- port map ( +-- clk_a_i => clock_master_180o_i, +-- we_a_i => attr4_we, +-- addr_a_i => attr_a, +-- data_a_i => attr_data, +-- -- +-- addr_b_i => spr_attr_a, +-- data_b_o => sprite_attr_4 +-- ); + + ----------------------------- + -- VIDEO LINE BUFFER MEMORIES + ----------------------------- + + -- single port ram (sync write, async read) + + linebuf0 : spram_320_9 + port map ( + CLK => clock_master_180o_i, + WE => l0_we, + SPO => l0_spo, + A => l0_a, + D => l0_d + ); + +-- linebuf0 : entity work.spram_async +-- generic map ( +-- addr_width_g => 9, +-- data_width_g => 9 +-- ) +-- port map ( +-- clk_i => clock_master_180o_i, +-- we_i => l0_we, +-- addr_i => l0_a, +-- data_i => l0_d, +-- data_o => l0_spo +-- ); + + -- single port ram (sync write, async read) + + linebuf1 : spram_320_9 + port map ( + CLK => clock_master_180o_i, + WE => l1_we, + SPO => l1_spo, + A => l1_a, + D => l1_d + ); + +-- linebuf1 : entity work.spram_async +-- generic map ( +-- addr_width_g => 9, +-- data_width_g => 9 +-- ) +-- port map ( +-- clk_i => clock_master_180o_i, +-- we_i => l1_we, +-- addr_i => l1_a, +-- data_i => l1_d, +-- data_o => l1_spo +-- ); + + -- swap line buffers between sprite and video + + line_reset_s <= '1' when hcounter_i = "111111111" else '0'; + + process (clock_master_i) + begin + if rising_edge(clock_master_i) then + if reset_i = '1' then + line_reset_re <= "00"; + else + line_reset_re <= line_reset_re(0) & line_reset_s; + end if; + end if; + end process; + + process (clock_master_i) + begin + if rising_edge(clock_master_i) then + if reset_i = '1' then + line_buf_sel <= '0'; + spr_cur_vcount <= (others => '0'); + elsif line_reset_re = "01" then + line_buf_sel <= not line_buf_sel; + spr_cur_vcount <= std_logic_vector(vcounter_i + 1); + end if; + end if; + end process; + + l0_we <= video_line_we_s when line_buf_sel = '0' else spr_line_we_s; + l0_a <= video_line_addr_s when line_buf_sel = '0' else spr_line_addr_s; + l0_d <= video_line_data_s when line_buf_sel = '0' else spr_line_data_s; + + l1_we <= spr_line_we_s when line_buf_sel = '0' else video_line_we_s; + l1_a <= spr_line_addr_s when line_buf_sel = '0' else video_line_addr_s; + l1_d <= spr_line_data_s when line_buf_sel = '0' else video_line_data_s; + + spr_line_data_o <= l1_spo when line_buf_sel = '0' else l0_spo; + video_line_rgb_s <= l0_spo when line_buf_sel = '0' else l1_spo; + + ----------------- + -- PATTERN MEMORY + ----------------- + + -- simple dual port ram (sync write, sync read zero delay) + + pattern : sdpbram_16k_8 + port map ( + WEA => pattern_we, + ADDRA => pattern_a, + DINA => cpu_data_q, + CLKA => clock_master_180o_i, + -- + ENB => '1', + ADDRB => spr_pat_addr, + DOUTB => spr_pat_data, + CLKB => clock_master_i + ); + +-- pattern: entity work.dpram +-- generic map ( +-- addr_width_g => (TOTAL_SPRITES_BITS+8), +-- data_width_g => 8 +-- ) +-- port map ( +-- clk_a_i => clock_master_180o_i, +-- we_i => pattern_we, +-- addr_a_i => pattern_a, +-- data_a_i => cpu_data_q, +-- -- +-- clk_b_i => clock_master_i, +-- addr_b_i => spr_pat_addr, +-- data_b_o => spr_pat_data +-- ); + + ----------------- + -- NEXTREG MIRROR + ----------------- + + process (clock_master_i) + begin + if rising_edge(clock_master_i) then + mirror_num_change <= '0'; + if reset_i = '1' then + mirror_sprite_q <= (others => '0'); + elsif mirror_we_i = '1' and mirror_index_i = "111" then + mirror_sprite_q <= mirror_data_i; + mirror_num_change <= '1'; + elsif mirror_inc_i = '1' then + mirror_sprite_q(TOTAL_SPRITES_BITS-1 downto 0) <= mirror_sprite_q(TOTAL_SPRITES_BITS-1 downto 0) + 1; + mirror_sprite_q(7) <= pattern_index(7); + mirror_num_change <= '1'; + elsif attr_num_change = '1' and mirror_tie_i = '1' then + mirror_sprite_q(TOTAL_SPRITES_BITS-1 downto 0) <= attr_index((TOTAL_SPRITES_BITS+3-1) downto 3); + mirror_sprite_q(7) <= pattern_index(7); -- wear helmet + end if; + end if; + end process; + + mirror_num_o <= mirror_sprite_q(TOTAL_SPRITES_BITS-1 downto 0); + + ---------------------- + -- CPU SPRITE PORT I/O + ---------------------- + + -- rising edge detection + + io_port_access <= '1' when port57_w_en_s = '1' or port5B_w_en_s = '1' or port303b_r_en_s = '1' or port303b_w_en_s = '1' else '0'; + + process (clock_master_i) + begin + if rising_edge(clock_master_i) then + if reset_i = '1' then + io_port_access_d <= '0'; + else + io_port_access_d <= io_port_access; + end if; + end if; + end process; + + io_port_re <= io_port_access and not io_port_access_d; + + -- cpu ports 0x57, 0x5b, 0x303b + + index_inc_attr_by_8 <= '1' when attr_index(2) = '1' or (attr_index(2 downto 0) = "011" and cpu_d_i(6) = '0') else '0'; + + index_inc_in_s <= ("0000" & attr_index) when port57_w_en_s = '1' and index_inc_attr_by_8 = '0' else + ("0000000" & attr_index((TOTAL_SPRITES_BITS+3-1) downto 3)) when port57_w_en_s = '1' and index_inc_attr_by_8 = '1' else + pattern_index; + + index_inc_out_s <= index_inc_in_s + 1; + + process (clock_master_i) + begin + if rising_edge(clock_master_i) then + attr_num_change <= '0'; + if reset_i = '1' then + attr_index <= (others => '0'); + elsif mirror_num_change = '1' and mirror_tie_i = '1' then + attr_index <= mirror_sprite_q(TOTAL_SPRITES_BITS-1 downto 0) & "000"; + elsif port303b_w_en_s = '1' and io_port_re = '1' then + attr_index <= cpu_d_i(TOTAL_SPRITES_BITS-1 downto 0) & "000"; + attr_num_change <= '1'; + elsif port57_w_en_s = '1' and io_port_re = '1' then + if index_inc_attr_by_8 = '0' then + attr_index <= index_inc_out_s((TOTAL_SPRITES_BITS+3-1) downto 0); + else + attr_index <= index_inc_out_s((TOTAL_SPRITES_BITS-1) downto 0) & "000"; + attr_num_change <= '1'; + end if; + end if; + end if; + end process; + + process (clock_master_i) + begin + if rising_edge(clock_master_i) then + if reset_i = '1' then + cpu_sprite_q <= (others => '0'); + cpu_index_q <= (others => '0'); + elsif port57_w_en_s = '1' and io_port_re = '1' then + cpu_sprite_q <= attr_index((TOTAL_SPRITES_BITS+3-1) downto 3); + cpu_index_q <= attr_index(2 downto 0); + end if; + end if; + end process; + + process (clock_master_i) + begin + if rising_edge(clock_master_i) then + if io_port_re = '1' then + cpu_data_q <= cpu_d_i; + end if; + end if; + end process; + + process (clock_master_i) + begin + if rising_edge(clock_master_i) then + if reset_i = '1' then + cpu_request <= '0'; + elsif port57_w_en_s = '1' and io_port_re = '1' then + cpu_request <= '1'; + elsif cpu_served = '1' then + cpu_request <= '0'; + end if; + end if; + end process; + + mirror_served <= '1' when mirror_we_i = '1' and mirror_index_i <= "100" else '0'; + cpu_served <= '1' when mirror_served = '0' and cpu_request = '1' else '0'; + + attr_a <= cpu_sprite_q when mirror_served = '0' else mirror_sprite_q(TOTAL_SPRITES_BITS-1 downto 0); + attr_id <= cpu_index_q when mirror_served = '0' else mirror_index_i; + attr_data <= cpu_data_q when mirror_served = '0' else mirror_data_i; + + attr0_we <= '1' when (cpu_served = '1' or mirror_served = '1') and attr_id = "000" else '0'; + attr1_we <= '1' when (cpu_served = '1' or mirror_served = '1') and attr_id = "001" else '0'; + attr2_we <= '1' when (cpu_served = '1' or mirror_served = '1') and attr_id = "010" else '0'; + attr3_we <= '1' when (cpu_served = '1' or mirror_served = '1') and attr_id = "011" else '0'; + attr4_we <= '1' when (cpu_served = '1' or mirror_served = '1') and attr_id = "100" else '0'; + + process (clock_master_i) + begin + if rising_edge(clock_master_i) then + if reset_i = '1' then + port5b_w_en_d <= '0'; + else + port5b_w_en_d <= port5b_w_en_s and io_port_re; + end if; + end if; + end process; + + process (clock_master_i) + begin + if rising_edge(clock_master_i) then + if reset_i = '1' then + pattern_index <= (others => '0'); + elsif mirror_num_change = '1' and mirror_tie_i = '1' then + pattern_index <= mirror_sprite_q(TOTAL_PATTERN_BITS-1 downto 0) & mirror_sprite_q(7) & "0000000"; + elsif port303b_w_en_s = '1' and io_port_re = '1' then + pattern_index <= cpu_d_i(TOTAL_PATTERN_BITS-1 downto 0) & cpu_d_i(7) & "0000000"; + elsif port5b_w_en_d = '1' then + pattern_index <= index_inc_out_s; + end if; + end if; + end process; + + pattern_a <= pattern_index; + pattern_we(0) <= '1' when port5b_w_en_d = '1' else '0'; + + -- cpu port 0x303b read + + cpu_d_o <= status_reg_read; + + ------------------- + -- LOAD SPRITE LINE + ------------------- + + -- maybe there is a better way to do this + + spr_relative <= '1' when sprite_attr_3(6) = '1' and sprite_attr_4(7 downto 6) = "01" else '0'; + + -- sort out relative sprite characteristics + + spr_rel_x0 <= sprite_attr_0 when anchor_rotate = '0' else sprite_attr_1; + spr_rel_y0 <= sprite_attr_1 when anchor_rotate = '0' else sprite_attr_0; + spr_rel_x1 <= spr_rel_x0 when (anchor_rotate xor anchor_xmirror) = '0' else (not(spr_rel_x0) + 1); + spr_rel_y1 <= spr_rel_y0 when anchor_ymirror = '0' else (not(spr_rel_y0) + 1); + spr_rel_x2 <= (spr_rel_x1(7) & spr_rel_x1) when anchor_xscale = "00" else + (spr_rel_x1 & '0') when anchor_xscale = "01" else + (spr_rel_x1(6 downto 0) & "00") when anchor_xscale = "10" else + (spr_rel_x1(5 downto 0) & "000"); + spr_rel_y2 <= (spr_rel_y1(7) & spr_rel_y1) when anchor_yscale = "00" else + (spr_rel_y1 & '0') when anchor_yscale = "01" else + (spr_rel_y1(6 downto 0) & "00") when anchor_yscale = "10" else + (spr_rel_y1(5 downto 0) & "000"); + spr_rel_x3 <= anchor_x + spr_rel_x2; + spr_rel_y3 <= anchor_y + spr_rel_y2; + + spr_rel_paloff <= sprite_attr_2(7 downto 4) when sprite_attr_2(0) = '0' else (anchor_paloff + sprite_attr_2(7 downto 4)); + + spr_rel_xm <= sprite_attr_2(3) when anchor_rotate = '0' else sprite_attr_2(2) xor sprite_attr_2(1); + spr_rel_ym <= sprite_attr_2(2) when anchor_rotate = '0' else sprite_attr_2(3) xor sprite_attr_2(1); + + spr_rel_attr_0 <= spr_rel_x3(7 downto 0); + spr_rel_attr_1 <= spr_rel_y3(7 downto 0); + spr_rel_attr_2 <= (spr_rel_paloff & sprite_attr_2(3 downto 1) & spr_rel_x3(8)) when anchor_rel_type = '0' else + (spr_rel_paloff & (anchor_xmirror xor spr_rel_xm) & (anchor_ymirror xor spr_rel_ym) & (anchor_rotate xor sprite_attr_2(1)) & spr_rel_x3(8)); + spr_rel_attr_3 <= (anchor_vis and sprite_attr_3(7)) & '1' & sprite_attr_3(5 downto 0); + spr_rel_attr_4 <= (anchor_h & sprite_attr_4(5) & '0' & sprite_attr_4(4 downto 1) & spr_rel_y3(8)) when anchor_rel_type = '0' else + (anchor_h & sprite_attr_4(5) & '0' & anchor_xscale & anchor_yscale & spr_rel_y3(8)); + + spr_cur_attr_0 <= sprite_attr_0 when spr_relative = '0' else spr_rel_attr_0; + spr_cur_attr_1 <= sprite_attr_1 when spr_relative = '0' else spr_rel_attr_1; + spr_cur_attr_2 <= sprite_attr_2 when spr_relative = '0' else spr_rel_attr_2; + spr_cur_attr_3 <= sprite_attr_3 when spr_relative = '0' else spr_rel_attr_3; + spr_cur_attr_4 <= sprite_attr_4 when spr_relative = '0' else spr_rel_attr_4; + + -- sprite processing + + spr_y8 <= '0' when sprite_attr_3(6) = '0' else spr_cur_attr_4(0); + spr_cur_y <= spr_y8 & spr_cur_attr_1; + + spr_cur_x <= spr_cur_attr_2(0) & spr_cur_attr_0; + + spr_cur_h <= spr_cur_attr_4(7) and sprite_attr_3(6); + spr_cur_n6 <= spr_cur_attr_4(6) and spr_cur_h; + spr_rel_pattern <= ((sprite_attr_3((TOTAL_PATTERN_BITS-1) downto 0) & spr_cur_n6) + anchor_pattern) when (spr_relative = '1') and (sprite_attr_4(0) = '1') else + (sprite_attr_3((TOTAL_PATTERN_BITS-1) downto 0) & spr_cur_n6); + + spr_y_offset_raw <= spr_cur_vcount - spr_cur_y; + spr_y_offset <= spr_y_offset_raw when sprite_attr_3(6) = '0' or spr_cur_attr_4(2 downto 1) = "00" else + spr_y_offset_raw(8) & spr_y_offset_raw(8 downto 1) when spr_cur_attr_4(2 downto 1) = "01" else + spr_y_offset_raw(8) & spr_y_offset_raw(8) & spr_y_offset_raw(8 downto 2) when spr_cur_attr_4(2 downto 1) = "10" else + spr_y_offset_raw(8) & spr_y_offset_raw(8) & spr_y_offset_raw(8) & spr_y_offset_raw(8 downto 3); + spr_y_index <= spr_y_offset((SPRITE_SIZE_BITS-1) downto 0) when spr_cur_attr_2(2) = '0' else not(spr_y_offset((SPRITE_SIZE_BITS-1) downto 0)); -- complement for y mirror + + spr_x_mirr_eff <= spr_cur_attr_2(3) xor spr_cur_attr_2(1); -- rotation inverts x mirror + spr_x_index <= std_logic_vector(to_unsigned(0,spr_x_index'length)) when spr_x_mirr_eff = '0' else std_logic_vector(to_unsigned(65535,spr_x_index'length)); + + spr_pattern_addr_start <= (spr_rel_pattern(TOTAL_PATTERN_BITS downto 1) & spr_y_index & spr_x_index) when spr_cur_attr_2(1) = '0' else (spr_rel_pattern(TOTAL_PATTERN_BITS downto 1) & spr_x_index & spr_y_index); -- rotation + spr_pattern_addr_delta <= "11" & X"FF0" when spr_x_mirr_eff = '1' and spr_cur_attr_2(1) = '1' else -- x mirror and rotate: -16 + "11" & X"FFF" when spr_x_mirr_eff = '1' and spr_cur_attr_2(1) = '0' else -- x mirror and no rotate: -1 + "00" & X"010" when spr_x_mirr_eff = '0' and spr_cur_attr_2(1) = '1' else -- no x mirror and rotate: +16 + "00" & X"001"; + + spr_cur_hcount_valid <= '1' when spr_cur_hcount < 320 else '0'; + + spr_cur_notime_mask <= spr_cur_x_wrap(2 downto 0) & "00"; + spr_cur_notime <= '1' when hcounter_i_valid = '1' and hcounter_i(8) = '1' and hcounter_i(5) = '1' and ((std_logic_vector(hcounter_i(4 downto 0)) and spr_cur_notime_mask) = spr_cur_notime_mask) else '0'; + + -- state + + process (clock_master_i) + begin + if rising_edge(clock_master_i) then + if reset_i = '1' then + state_s <= S_IDLE; + elsif line_reset_re = "01" then + state_s <= S_START; + else + state_s <= state_next_s; + end if; + end if; + end process; + + -- next state combinatorial + + spr_cur_index_is_zero <= '1' when spr_cur_index = 0 else '0'; + spr_cur_draw_it <= '1' when spr_cur_visible = '1' and spr_cur_yoff = 0 else '0'; + + process (state_s, spr_cur_draw_it, spr_cur_index_is_zero, spr_width_count, spr_cur_hcount_valid, spr_cur_hcount, spr_cur_x_wrap, spr_cur_notime) + begin + case state_s is + when S_START => state_next_s <= S_QUALIFY; + when S_QUALIFY => if spr_cur_draw_it = '1' and spr_cur_notime = '1' then + state_next_s <= S_IDLE; + elsif spr_cur_draw_it = '1' then + state_next_s <= S_PROCESS; + elsif spr_cur_index_is_zero = '1' then + state_next_s <= S_IDLE; + else + state_next_s <= S_QUALIFY; + end if; + when S_PROCESS => if spr_width_count(SPRITE_SIZE_BITS-1+1+3) = '1' or (spr_cur_hcount_valid = '0' and ((spr_cur_hcount(8 downto 4) and spr_cur_x_wrap) /= spr_cur_x_wrap)) then -- allow x wrap-around + if spr_cur_index_is_zero = '1' then + state_next_s <= S_IDLE; + else + state_next_s <= S_QUALIFY; + end if; + else + state_next_s <= S_PROCESS; + end if; + when others => state_next_s <= S_IDLE; + end case; + end process; + + -- state machine variables + + spr_width_count_next <= spr_width_count + spr_width_count_delta; + + process (clock_master_180o_i) + begin + if rising_edge(clock_master_180o_i) then + if reset_i = '1' then + spr_cur_index <= (others => '0'); + spr_cur_hcount <= (others => '0'); + spr_cur_pattern_addr <= (others => '0'); + spr_cur_pattern_delta <= (others => '0'); + spr_width_count <= (others => '0'); + spr_cur_paloff <= (others => '0'); + spr_cur_visible <= '0'; + spr_cur_yoff <= (others => '0'); + spr_cur_x_wrap <= (others => '0'); + spr_cur_4bit <= (others => '0'); + anchor_rel_type <= '0'; + anchor_h <= '0'; + anchor_vis <= '0'; + anchor_x <= (others => '0'); + anchor_y <= (others => '0'); + anchor_pattern <= (others => '0'); + anchor_paloff <= (others => '0'); + anchor_rotate <= '0'; + anchor_xmirror <= '0'; + anchor_ymirror <= '0'; + anchor_xscale <= (others => '0'); + anchor_yscale <= (others => '0'); + elsif state_s = S_START then + spr_cur_index <= (others => '0'); + anchor_vis <= '0'; + elsif state_s = S_QUALIFY then + spr_cur_index <= spr_cur_index + 1; + spr_cur_hcount <= spr_cur_x; + spr_cur_pattern_addr <= spr_pattern_addr_start; + spr_cur_pattern_delta <= spr_pattern_addr_delta; + spr_width_count <= (others => '0'); + if sprite_attr_3(6) = '0' or spr_cur_attr_4(4 downto 3) = "00" then + spr_width_count_delta <= "1000"; + elsif spr_cur_attr_4(4 downto 3) = "01" then + spr_width_count_delta <= "0100"; + elsif spr_cur_attr_4(4 downto 3) = "10" then + spr_width_count_delta <= "0010"; + else + spr_width_count_delta <= "0001"; + end if; + spr_cur_paloff <= spr_cur_attr_2(7 downto 4); + spr_cur_visible <= spr_cur_attr_3(7); + spr_cur_yoff <= spr_y_offset(8 downto SPRITE_SIZE_BITS); + if sprite_attr_3(6) = '0' or spr_cur_attr_4(4 downto 3) = "00" then + spr_cur_x_wrap <= "11111"; + elsif spr_cur_attr_4(4 downto 3) = "01" then + spr_cur_x_wrap <= "11110"; + elsif spr_cur_attr_4(4 downto 3) = "10" then + spr_cur_x_wrap <= "11100"; + else + spr_cur_x_wrap <= "11000"; + end if; + spr_cur_4bit <= spr_cur_h & spr_rel_pattern(0); + if spr_relative = '0' then + anchor_rel_type <= sprite_attr_4(5) and sprite_attr_3(6); + anchor_h <= sprite_attr_4(7) and sprite_attr_3(6); + anchor_vis <= sprite_attr_3(7); + anchor_x <= spr_cur_x; + anchor_y <= spr_cur_y; + anchor_pattern <= spr_rel_pattern; + anchor_paloff <= sprite_attr_2(7 downto 4); + if sprite_attr_3(6) = '1' and sprite_attr_4(5) = '1' then + anchor_rotate <= sprite_attr_2(1); + anchor_xmirror <= sprite_attr_2(3); + anchor_ymirror <= sprite_attr_2(2); + anchor_xscale <= sprite_attr_4(4 downto 3); + anchor_yscale <= sprite_attr_4(2 downto 1); + else + anchor_rotate <= '0'; + anchor_xmirror <= '0'; + anchor_ymirror <= '0'; + anchor_xscale <= "00"; + anchor_yscale <= "00"; + end if; + end if; + elsif state_s = S_PROCESS then + spr_width_count <= spr_width_count_next; + spr_cur_hcount <= spr_cur_hcount + 1; + if spr_width_count_next(3) /= spr_width_count(3) then + spr_cur_pattern_addr <= spr_cur_pattern_addr + spr_cur_pattern_delta; + end if; + end if; + end if; + end process; + + spr_attr_a <= spr_cur_index; + spr_pat_addr <= spr_cur_pattern_addr when spr_cur_4bit(1) = '0' else + spr_cur_pattern_addr(13 downto 8) & spr_cur_4bit(0) & spr_cur_pattern_addr(7 downto 1); + + spr_line_addr_s <= spr_cur_hcount; + + spr_nibble_data <= spr_pat_data(7 downto 4) when spr_cur_pattern_addr(0) = '0' else spr_pat_data(3 downto 0); + spr_line_data_s(7 downto 0) <= ((spr_pat_data(7 downto 4) + spr_cur_paloff) & spr_pat_data(3 downto 0)) when spr_cur_4bit(1) = '0' else (spr_cur_paloff & spr_nibble_data(3 downto 0)); + spr_line_data_s(8) <= '1'; + + spr_line_we <= '1' when state_s = S_PROCESS and spr_cur_hcount_valid = '1' and ((spr_cur_4bit(1) = '0' and spr_pat_data(7 downto 0) /= transp_colour_i) or (spr_cur_4bit(1) = '1' and spr_nibble_data /= transp_colour_i(3 downto 0))) else '0'; + spr_line_we_s <= '1' when spr_line_we = '1' and (zero_on_top_i = '0' or spr_line_data_o(8) = '0') else '0'; + + -- status register + -- bits(7:2) = 0, bit 1 = max sprites per line, bit 0 = collision + + process (clock_master_i) + begin + if rising_edge(clock_master_i) then + if reset_i = '1' then + sprites_overtime <= '0'; + elsif (state_s /= S_IDLE and line_reset_re = "01") or (state_s = S_QUALIFY and spr_cur_notime = '1' and spr_cur_draw_it = '1') then + sprites_overtime <= '1'; + else + sprites_overtime <= '0'; + end if; + end if; + end process; + + process (clock_master_180o_i) + begin + if rising_edge(clock_master_180o_i) then + if (reset_i = '1') then + status_reg_s <= (others => '0'); + status_reg_read <= (others => '0'); + else + if port303b_r_en_s = '1' and io_port_re = '1' then + status_reg_read <= status_reg_s; + status_reg_s <= (others => '0'); + else + status_reg_s(1) <= status_reg_s(1) or sprites_overtime; + status_reg_s(0) <= status_reg_s(0) or (spr_line_data_o(8) and spr_line_we); + end if; + end if; + end if; + end process; + + ----------------------------- + -- GENERATE VIDEO LINE OUTPUT + ----------------------------- + + hcounter_i_valid <= '1' when hcounter_i < 320 else '0'; + vcounter_i_valid <= '1' when vcounter_i(8) = '0' else '0'; -- < 256 + + process (clock_pixel_i) + begin + if rising_edge(clock_pixel_i) then + if reset_i = '1' then + video_line_flag <= '0'; + else + video_line_flag <= not(video_line_flag); + end if; + end if; + end process; + + -- load video line pixel before clearing + + process (clock_pixel_i) + begin + if falling_edge(clock_pixel_i) then + if reset_i = '1' then + video_line_rgb_load <= (others => '0'); + else + video_line_rgb_load <= video_line_rgb_s; + video_line_fe <= video_line_flag; + end if; + end if; + end process; + + -- clear video line pixel after loaded + + video_line_we_s <= (video_line_fe xor video_line_re) and hcounter_i_valid; + video_line_addr_s <= std_logic_vector(hcounter_i); + video_line_data_s <= std_logic_vector(to_unsigned(0,video_line_data_s'length)); + + -- send video line pixel to display + + process (clock_pixel_i) + begin + if rising_edge(clock_pixel_i) then + + video_line_re <= video_line_flag; + + if over_border_i = '1' then + if border_clip_en_i = '0' then + x_s_v <= to_unsigned(0, 9); + x_e_v <= to_unsigned(319, 9); + y_s_v <= to_unsigned(0, 9); + y_e_v <= to_unsigned(255, 9); + else + x_s_v <= clip_x1_i & '0'; + x_e_v <= clip_x2_i & '1'; + y_s_v <= '0' & clip_y1_i; + y_e_v <= '0' & clip_y2_i; + end if; + else + x_s_v <= (('0' & clip_x1_i(7 downto 5)) + 1) & clip_x1_i(4 downto 0); + x_e_v <= (('0' & clip_x2_i(7 downto 5)) + 1) & clip_x2_i(4 downto 0); + y_s_v <= (('0' & clip_y1_i(7 downto 5)) + 1) & clip_y1_i(4 downto 0); + y_e_v <= (('0' & clip_y2_i(7 downto 5)) + 1) & clip_y2_i(4 downto 0); + end if; + + over_border_s <= over_border_i; + + end if; + end process; + + pixel_en_o <= video_line_rgb_load(8) when (vcounter_i >= y_s_v and vcounter_i <= y_e_v and (over_border_s = '1' or vcounter_i < 224) and hcounter_i >= x_s_v and hcounter_i <= x_e_v and hcounter_i_valid = '1' and vcounter_i_valid = '1') else '0'; + rgb_o <= video_line_rgb_load(7 downto 0); + +end architecture; diff --git a/rtl/video/tilemap.vhd b/rtl/video/tilemap.vhd new file mode 100644 index 0000000..987d57f --- /dev/null +++ b/rtl/video/tilemap.vhd @@ -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 +-- +-- +-- 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 +-- . + +-- 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; diff --git a/rtl/video/zxula.vhd b/rtl/video/zxula.vhd new file mode 100644 index 0000000..ed5a8ca --- /dev/null +++ b/rtl/video/zxula.vhd @@ -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 +-- +-- +-- 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 +-- . +-- + +-- 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; diff --git a/rtl/video/zxula_timing.vhd b/rtl/video/zxula_timing.vhd new file mode 100644 index 0000000..b3f579e --- /dev/null +++ b/rtl/video/zxula_timing.vhd @@ -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 +-- +-- +-- 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 +-- . +-- + +-- Original pal_sync_generator.v from the ZX UNO project: +-- + +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; diff --git a/rtl/zxnext.vhd b/rtl/zxnext.vhd new file mode 100644 index 0000000..849e092 --- /dev/null +++ b/rtl/zxnext.vhd @@ -0,0 +1,6939 @@ + +-- ZX Spectrum Next Implementation +-- Copyright 2020 Alvin Albrecht, Victor Trucco and Fabio Belavenuto +-- +-- TBBlue - Victor Trucco & Fabio Belavenuto +-- ZXNext Refactor - Alvin Albrecht +-- +-- This file is part of the ZX Spectrum Next Project +-- +-- +-- 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 +-- . + +library ieee; +use ieee.std_logic_1164.all; +use IEEE.NUMERIC_STD.ALL; +use IEEE.std_logic_unsigned.ALL; +use work.Z80N_pack.all; + +entity zxnext is + generic + ( + g_machine_id : unsigned(7 downto 0); + g_version : unsigned(7 downto 0); + g_sub_version : unsigned(7 downto 0) + ); + port ( + -- CLOCK + + i_CLK_28 : in std_logic; -- 28MHz for machine logic + i_CLK_28_n : in std_logic; -- 28MHz inverted + i_CLK_14 : in std_logic; -- 14MHz hi-res pixel clock + i_CLK_7 : in std_logic; -- 7MHz pixel clock + i_CLK_CPU : in std_logic; -- CPU clock adjusted for speed and contention + i_CLK_PSG_EN : in std_logic; -- 28MHz clock enable for PSG + + o_CPU_SPEED : out std_logic_vector(1 downto 0); -- cpu speed selection 00 = 3.5, 01 = 7, 10 = 14, 11 = 28 + o_CPU_CONTEND : out std_logic; -- indicates cpu is contended + o_CPU_CLK_LSB : out std_logic; -- the contended cpu clock is derived from the pixel counter lsb + + -- RESET + + i_RESET : in std_logic; -- asserted for some number of cycles + + o_RESET_SOFT : out std_logic; -- asserted for one cycle at 28MHz + o_RESET_HARD : out std_logic; -- asserted for one cycle at 28MHz + o_RESET_PERIPHERAL : out std_logic; -- asserted under sw control for esp / exp bus reset + + -- FLASH BOOT + + o_FLASH_BOOT : out std_logic; -- load new core + o_CORE_ID : out std_logic_vector(4 downto 0); -- core id 0-31 + + -- SPECIAL KEYS + + i_SPKEY_FUNCTION : in std_logic_vector(10 downto 1); -- F10 through F1 + i_SPKEY_BUTTONS : in std_logic_vector(1 downto 0); -- raw state of nmi buttons m1(0) & drive(1) + + -- MEMBRANE KEYBOARD + + o_KBD_CANCEL : out std_logic; -- cancel entering extended keys into standard 8x5 matrix + + o_KBD_ROW : out std_logic_vector(7 downto 0); -- A15:A8 in keyboard read + i_KBD_COL : in std_logic_vector(4 downto 0); -- D4:D0 in keyboard read (D6:D5 are the new keys) + + i_KBD_EXTENDED_KEYS : in std_logic_vector(15 downto 0); -- state of extended keys independent of matrix + + -- PS/2 KEYBOARD SETUP + + o_KEYMAP_ADDR : out std_logic_vector(8 downto 0); -- keymap address + o_KEYMAP_DATA : out std_logic_vector(7 downto 0); -- keymap data + o_KEYMAP_WE : out std_logic; -- write signal to ps2 keyboard + o_JOYMAP_WE : out std_logic; -- write signal to key joystick + + -- JOYSTICK + + i_JOY_LEFT : in std_logic_vector(10 downto 0); -- active high X Z Y START A C B U D L R + i_JOY_RIGHT : in std_logic_vector(10 downto 0); -- active high X Z Y START A C B U D L R + + o_JOY_IO_MODE_EN : out std_logic; -- joystick io mode enabled + o_JOY_IO_MODE_PIN_7 : out std_logic; -- state of pin 7 if in joystick io mode + + o_JOY_LEFT_TYPE : out std_logic_vector(2 downto 0); + o_JOY_RIGHT_TYPE : out std_logic_vector(2 downto 0); + + -- MOUSE + + i_MOUSE_X : in std_logic_vector(7 downto 0); + i_MOUSE_Y : in std_logic_vector(7 downto 0); + i_MOUSE_BUTTON : in std_logic_vector(2 downto 0); -- M, R, L + i_MOUSE_WHEEL : in std_logic_vector(3 downto 0); + + o_PS2_MODE : out std_logic; + o_MOUSE_CONTROL : out std_logic_vector(2 downto 0); -- Button reverse, DPI(1:0) + + -- I2C + + i_I2C_SCL_n : in std_logic; + i_I2C_SDA_n : in std_logic; + + o_I2C_SCL_n : out std_logic; -- 0 = assert, 1 = tristate + o_I2C_SDA_n : out std_logic; -- 0 = assert, 1 = tristate + + -- SPI + + o_SPI_SS_FLASH_n : out std_logic; + o_SPI_SS_SD1_n : out std_logic; + o_SPI_SS_SD0_n : out std_logic; + + o_SPI_SCK : out std_logic; + o_SPI_MOSI : out std_logic; + + i_SPI_SD_MISO : in std_logic; + i_SPI_FLASH_MISO : in std_logic; + + -- UART + + i_UART0_RX : in std_logic; + o_UART0_TX : out std_logic; + + -- VIDEO + -- synchronized to i_CLK_14 + + o_RGB : out std_logic_vector(8 downto 0); -- RGB333 + o_RGB_CS_n : out std_logic; -- csync + o_RGB_VS_n : out std_logic; -- vsync + o_RGB_HS_n : out std_logic; -- hsync + o_RGB_VB_n : out std_logic; -- vblank + o_RGB_HB_n : out std_logic; -- hblank + + o_VIDEO_50_60 : out std_logic; -- 0 = 50Hz, 1 = 60Hz + o_VIDEO_SCANLINES : out std_logic_vector(1 downto 0); -- + o_VIDEO_SCANDOUBLE : out std_logic; -- + + o_VIDEO_MODE : out std_logic_vector(2 downto 0); -- video mode: VGA 0-6, HDMI + o_MACHINE_TIMING : out std_logic_vector(2 downto 0); -- machine timing: 00X = 48k, 010 = 128k, 011 = +3, 100 = pentagon + + o_HDMI_RESET : out std_logic; + + -- AUDIO + + o_AUDIO_HDMI_AUDIO_EN : out std_logic; + + o_AUDIO_SPEAKER_EN : out std_logic; -- enable internal speaker + o_AUDIO_SPEAKER_BEEP : out std_logic; -- only beep to internal speaker + + i_AUDIO_EAR : in std_logic; -- tape in + o_AUDIO_MIC : out std_logic; -- tape out + + o_AUDIO_SPEAKER_EAR : out std_logic; + o_AUDIO_SPEAKER_MIC : out std_logic; + + o_AUDIO_L : out std_logic_vector(12 downto 0); -- pcm audio + o_AUDIO_R : out std_logic_vector(12 downto 0); -- pcm audio + + -- EXTERNAL SRAM (synchronized to i_CLK_28) + -- memory transactions complete after one cycle, data read is registered a cycle later but is available asap + + -- Port A is read/write and highest priority (CPU) + + o_RAM_A_ADDR : out std_logic_vector(20 downto 0); -- 2MB memory space + o_RAM_A_REQ : out std_logic; -- '1' indicates memory request on next rising edge + o_RAM_A_RD_n : out std_logic; -- '0' for read, '1' for write + i_RAM_A_DI : in std_logic_vector(7 downto 0); -- data read from memory + o_RAM_A_DO : out std_logic_vector(7 downto 0); -- data written to memory + i_RAM_A_WAIT : in std_logic := '0'; + + -- Port B is read only (LAYER 2) + + o_RAM_B_ADDR : out std_logic_vector(20 downto 0); -- 2MB memory space + o_RAM_B_REQ_T : out std_logic; -- toggle indicates memory request + i_RAM_B_DI : in std_logic_vector(7 downto 0); -- data read from memory + + -- EXPANSION BUS + + o_BUS_ADDR : out std_logic_vector(15 downto 0); -- unidirectional address bus = no external DMA for now + i_BUS_DI : in std_logic_vector(7 downto 0); -- data bus in from external connector + o_BUS_DO : out std_logic_vector(7 downto 0); -- data bus out to external connector + o_BUS_MREQ_n : out std_logic; + o_BUS_IORQ_n : out std_logic; + o_BUS_RD_n : out std_logic; + o_BUS_WR_n : out std_logic; + o_BUS_M1_n : out std_logic; + i_BUS_WAIT_n : in std_logic; + i_BUS_NMI_n : in std_logic; + i_BUS_INT_n : in std_logic; + o_BUS_INT_n : out std_logic; + i_BUS_BUSREQ_n : in std_logic; + o_BUS_BUSAK_n : out std_logic; + o_BUS_HALT_n : out std_logic; + o_BUS_RFSH_n : out std_logic; + o_BUS_IEO : out std_logic; + + i_BUS_ROMCS_n : in std_logic; -- 1 disables internal rom +-- i_BUS_RAMCS_n : in std_logic; + i_BUS_IORQULA_n : in std_logic; -- 1 disables port fe + + o_BUS_EN : out std_logic; -- enable the expansion bus, changes on rising edge of cpu clock + o_BUS_CLKEN : out std_logic; -- 1 to keep 3.5MHz clock on the expansion bus even when off + + o_BUS_NMI_DEBOUNCE_DISABLE : out std_logic; + + -- ESP GPIO + + i_ESP_GPIO_20 : in std_logic_vector(2 downto 0); + + o_ESP_GPIO_0 : out std_logic; + o_ESP_GPIO_0_EN : out std_logic; -- 0 = high Z + + -- PI GPIO + + i_GPIO : in std_logic_vector(27 downto 0); + + o_GPIO : out std_logic_vector(27 downto 0); + o_GPIO_EN : out std_logic_vector(27 downto 0) -- 0 = high Z + ); +end entity; + +architecture rtl of zxnext is + + -- RESET + + signal reset : std_logic; + + -- Z80 & DMA + + signal expbus_disable_int : std_logic; + + signal z80_wait_n : std_logic; + signal z80_int_n : std_logic; + signal z80_nmi_n : std_logic; + signal z80_busrq_n : std_logic; + signal z80_m1_n : std_logic; + signal z80_mreq_n : std_logic; + signal z80_iorq_n : std_logic; + signal z80_rd_n : std_logic; + signal z80_wr_n : std_logic; + signal z80_rfsh_n : std_logic; + signal z80_halt_n : std_logic; + signal z80_busak_n : std_logic; + signal z80_a : std_logic_vector(15 downto 0); + signal z80_do : std_logic_vector(7 downto 0); + signal Z80N_dout_s : std_logic; + signal Z80N_data_s : std_logic_vector(15 downto 0); + signal Z80N_command_s : Z80N_seq; + + signal dma_wait_n : std_logic; + signal dma_busrq_n : std_logic; + signal dma_a : std_logic_vector(15 downto 0); + signal dma_do : std_logic_vector(7 downto 0); + signal dma_rd_n : std_logic; + signal dma_wr_n : std_logic; + signal dma_mreq_n : std_logic; + signal dma_iorq_n : std_logic; + + signal port_dma_dat_0 : std_logic_vector(7 downto 0); + signal port_dma_dat : std_logic_vector(7 downto 0); + signal dma_mode : std_logic := '0'; + + signal dma_holds_bus : std_logic; + signal cpu_m1_n : std_logic; + signal cpu_mreq_n : std_logic; + signal cpu_iorq_n : std_logic; + signal cpu_rd_n : std_logic; + signal cpu_wr_n : std_logic; + signal cpu_rfsh_n : std_logic; + signal cpu_halt_n : std_logic; + signal cpu_a : std_logic_vector(15 downto 0); + signal cpu_di : std_logic_vector(7 downto 0); + signal cpu_do : std_logic_vector(7 downto 0); + + signal im2_ieo : std_logic; + signal im2_reti_decode : std_logic; + signal z80_reti_seen_t3 : std_logic; + signal z80_retn_seen_t3 : std_logic; + signal z80_retn_seen_28 : std_logic; + signal z80_retn_seen_28_d : std_logic; + signal dma_delay : std_logic; + signal im2_dma_delay : std_logic; + + signal im2_int_req : std_logic_vector(13 downto 0); + signal im2_int_en : std_logic_vector(13 downto 0); + signal im2_status_clear : std_logic_vector(13 downto 0); + signal im2_dma_int_en : std_logic_vector(13 downto 0); + signal im2_int_status : std_logic_vector(13 downto 0); + signal im2_int_n : std_logic; + signal pulse_int_en : std_logic; + signal im2_dma_int : std_logic; + signal im2_vec : std_logic_vector(3 downto 0); + signal im2_vector : std_logic_vector(7 downto 0); + + signal z80_stackless_nmi : std_logic; + signal z80_retn_address : std_logic_vector(7 downto 0); + signal z80_stackless_retn_en : std_logic; + + signal nmi_activated : std_logic; + signal nmi_expbus_en : std_logic; + signal nmi_assert_expbus : std_logic; + signal nmi_mf : std_logic := '0'; + signal nmi_divmmc : std_logic := '0'; + signal nmi_expbus : std_logic := '0'; + signal nmi_hold : std_logic; + + type nmi_state_t is (S_NMI_IDLE, S_NMI_ASSERT, S_NMI_OPUS, S_NMI_HOLD, S_NMI_END); + signal nmi_state : nmi_state_t := S_NMI_IDLE; + signal nmi_state_next : nmi_state_t; + signal nmi_holding : std_logic; + signal nmi_opus : std_logic; + signal nmi_generate_n : std_logic; + signal nmi_mf_button : std_logic; + signal nmi_divmmc_button : std_logic; + + -- EXPANSION BUS + + signal nr_80_expbus : std_logic_vector(7 downto 0) := X"00"; + + signal expbus_en : std_logic; + signal expbus_romcs_replace : std_logic; + signal expbus_disable_io : std_logic; + signal expbus_disable_mem : std_logic; + signal expbus_clken : std_logic; + signal expbus_speed : std_logic_vector(1 downto 0); + + signal expbus_eff_en : std_logic := '0'; + signal expbus_eff_disable_io : std_logic := '0'; + signal expbus_eff_disable_mem : std_logic := '0'; + signal expbus_eff_clken : std_logic := '0'; + + signal port_propagate_fe : std_logic; + signal port_propagate_7ffd : std_logic; + signal port_propagate_dffd : std_logic; + signal port_propagate_1ffd : std_logic; + signal port_propagate_ff : std_logic; + signal port_propagate_eff7 : std_logic; + + signal port_propagate : std_logic; + signal bus_iorq_n : std_logic; + signal bus_mreq_n : std_logic; + + -- ALTERNATIVE ROM + + signal nr_8c_altrom : std_logic_vector(7 downto 0) := X"00"; + + signal nr_8c_altrom_en : std_logic; + signal nr_8c_altrom_rw : std_logic; + signal nr_8c_altrom_lock_rom1 : std_logic; + signal nr_8c_altrom_lock_rom0 : std_logic; + + -- PI GPIO + + signal pi_gpio_en : std_logic_vector(27 downto 0); + signal pi_gpio_o : std_logic_vector(27 downto 0); + + signal pi_uart_rxtx : std_logic; + signal pi_uart_en : std_logic; + signal pi_i2c1_en : std_logic; + signal pi_spi0_en : std_logic; + + signal pi_i2s_en : std_logic; + signal pi_i2s_enL : std_logic; + signal pi_i2s_enR : std_logic; + signal pi_i2s_inout : std_logic; + signal pi_i2s_muteL : std_logic; + signal pi_i2s_muteR : std_logic; +-- signal pi_i2s_slave : std_logic; + signal pi_i2s_ear : std_logic; + + signal gpio_07_en : std_logic; + signal gpio_07 : std_logic; + signal gpio_08_en : std_logic; + signal gpio_08 : std_logic; + signal gpio_09_en : std_logic; + signal pi_spi0_miso : std_logic; + signal gpio_10_en : std_logic; + signal gpio_10 : std_logic; + signal gpio_11_en : std_logic; + signal gpio_11 : std_logic; + + signal gpio_02_en : std_logic; + signal gpio_02 : std_logic; + signal gpio_03_en : std_logic; + signal gpio_03 : std_logic; + signal pi_i2c1_sda : std_logic; + signal pi_i2c1_scl : std_logic; + + signal gpio_14_en : std_logic; + signal gpio_14 : std_logic; + signal gpio_15_en : std_logic; + signal gpio_15 : std_logic; + signal gpio_16_en : std_logic; + signal gpio_16 : std_logic; + signal gpio_17_en : std_logic; + signal gpio_17 : std_logic; + signal pi_uart_rx : std_logic; + signal pi_uart_cts_n : std_logic; + + signal gpio_18_en : std_logic; + signal gpio_18 : std_logic; + signal gpio_19_en : std_logic; + signal gpio_19 : std_logic; + signal gpio_20_en : std_logic; + signal gpio_20 : std_logic; + signal gpio_21_en : std_logic; + signal gpio_21 : std_logic; + + signal pi_audio_L : std_logic_vector(9 downto 0); + signal pi_audio_R : std_logic_vector(9 downto 0); + signal pi_fe_threshold : std_logic_vector(1 downto 0); + signal pi_fe_ear : std_logic; + + -- PORT DECODING + + signal internal_port_enable : std_logic_vector(27 downto 0); + + signal port_ff_io_en : std_logic; + signal port_7ffd_io_en : std_logic; + signal port_dffd_io_en : std_logic; + signal port_1ffd_io_en : std_logic; + signal port_p3_floating_bus_io_en : std_logic; + signal port_dma_6b_io_en : std_logic; + signal port_1f_io_en : std_logic; + signal port_37_io_en : std_logic; + signal port_divmmc_io_en : std_logic; + signal port_divmmc_io_en_diff : std_logic; + signal port_multiface_io_en : std_logic; + signal port_multiface_io_en_diff : std_logic; + signal port_i2c_io_en : std_logic; + signal port_spi_io_en : std_logic; + signal port_uart_io_en : std_logic; + signal port_mouse_io_en : std_logic; + signal port_sprite_io_en : std_logic; + signal port_layer2_io_en : std_logic; + signal port_ay_io_en : std_logic; + signal port_dac_sd1_ABCD_1f0f4f5f_io_en : std_logic; + signal port_dac_sd2_ABCD_f1f3f9fb_io_en : std_logic; + signal port_dac_stereo_AD_3f5f_io_en : std_logic; + signal port_dac_stereo_BC_0f4f_io_en : std_logic; + signal port_dac_mono_AD_fb_io_en : std_logic; + signal port_dac_mono_BC_b3_io_en : std_logic; + signal port_dac_mono_AD_df_io_en : std_logic; + signal port_ulap_io_en : std_logic; + signal port_dma_0b_io_en : std_logic; + signal port_eff7_io_en : std_logic; + signal port_ctc_io_en : std_logic; + + signal port_1f_hw_en : std_logic; + signal port_37_hw_en : std_logic; + signal p3_timing_hw_en : std_logic; + signal s128_timing_hw_en : std_logic; + signal dac_hw_en : std_logic; + + signal bus_iorq_ula : std_logic := '0'; + + signal port_00xx_msb : std_logic; + signal port_04xx_msb : std_logic; + signal port_05xx_msb : std_logic; + signal port_10xx_msb : std_logic; + signal port_11xx_msb : std_logic; + signal port_12xx_msb : std_logic; + signal port_1fxx_msb : std_logic; + signal port_24xx_msb : std_logic; + signal port_25xx_msb : std_logic; + signal port_30xx_msb : std_logic; + signal port_3dxx_msb : std_logic; + signal port_bfxx_msb : std_logic; + signal port_fexx_msb : std_logic; + signal port_ffxx_msb : std_logic; + + signal port_00_lsb : std_logic; + signal port_08_lsb : std_logic; + signal port_0b_lsb : std_logic; + signal port_0f_lsb : std_logic; + signal port_1f_lsb : std_logic; + signal port_37_lsb : std_logic; + signal port_38_lsb : std_logic; + signal port_3f_lsb : std_logic; + signal port_3b_lsb : std_logic; + signal port_4f_lsb : std_logic; + signal port_57_lsb : std_logic; + signal port_5b_lsb : std_logic; + signal port_5f_lsb : std_logic; + signal port_62_lsb : std_logic; + signal port_66_lsb : std_logic; + signal port_6a_lsb : std_logic; + signal port_6b_lsb : std_logic; + signal port_b3_lsb : std_logic; + signal port_c6_lsb : std_logic; + signal port_d7_lsb : std_logic; + signal port_df_lsb : std_logic; + signal port_e3_lsb : std_logic; + signal port_e7_lsb : std_logic; + signal port_eb_lsb : std_logic; + signal port_f1_lsb : std_logic; + signal port_f3_lsb : std_logic; + signal port_f7_lsb : std_logic; + signal port_f9_lsb : std_logic; + signal port_fb_lsb : std_logic; + signal port_ff_lsb : std_logic; + + signal port_fe : std_logic; + signal port_ff : std_logic; + signal port_fe_override : std_logic; + signal port_fd : std_logic; + signal port_p3_float : std_logic; +-- signal port_p3_float_active : std_logic; + signal port_7ffd : std_logic; + signal port_7ffd_active : std_logic; + signal port_7ffd_assert : std_logic; + signal port_dffd : std_logic; + signal port_1ffd : std_logic; +-- signal port_1ffd_active : std_logic; + signal port_1ffd_assert : std_logic; + signal port_eff7 : std_logic; + signal port_e3 : std_logic; + signal port_mf_enable_io_a : std_logic_vector(7 downto 0); + signal port_mf_disable_io_a : std_logic_vector(7 downto 0); + signal port_mf_enable : std_logic; + signal port_mf_disable : std_logic; + signal port_e7 : std_logic; + signal port_eb : std_logic; + signal port_243b : std_logic; + signal port_253b : std_logic; + signal port_103b : std_logic; + signal port_113b : std_logic; + signal port_123b : std_logic; + signal port_uart : std_logic; + signal port_dma : std_logic; + signal port_fffd : std_logic; + signal port_bffd : std_logic; + signal port_bff5 : std_logic; + signal port_dac_mono_AD : std_logic; + signal port_dac_mono_BC : std_logic; + signal port_dac_A : std_logic; + signal port_dac_B : std_logic; + signal port_dac_C : std_logic; + signal port_dac_D : std_logic; + signal port_fadf : std_logic; + signal port_fbdf : std_logic; + signal port_ffdf : std_logic; + signal port_1f : std_logic; + signal port_37 : std_logic; + signal port_57 : std_logic; + signal port_5b : std_logic; + signal port_303b : std_logic; + signal port_bf3b : std_logic; + signal port_ff3b : std_logic; + signal port_ctc : std_logic; + signal port_internal_response : std_logic; + + signal iord : std_logic; + signal iowr : std_logic; + + signal port_fd_conflict_wr : std_logic; + + signal port_fe_rd : std_logic; + signal port_fe_wr : std_logic; + signal port_ff_rd : std_logic; + signal port_ff_wr : std_logic; + signal port_p3_float_rd : std_logic; + signal port_7ffd_wr : std_logic; + signal port_dffd_wr : std_logic; + signal port_1ffd_wr : std_logic; + signal port_eff7_wr : std_logic; + signal port_e3_rd : std_logic; + signal port_e3_wr : std_logic; + signal port_mf_enable_rd : std_logic; + signal port_mf_enable_wr : std_logic; + signal port_mf_disable_rd : std_logic; + signal port_mf_disable_wr : std_logic; + signal port_e7_wr : std_logic; + signal port_eb_rd : std_logic; + signal port_eb_wr : std_logic; + signal port_243b_rd : std_logic; + signal port_243b_wr : std_logic; + signal port_253b_rd : std_logic; + signal port_253b_wr : std_logic; + signal port_103b_rd : std_logic; + signal port_103b_wr : std_logic; + signal port_113b_rd : std_logic; + signal port_113b_wr : std_logic; + signal port_123b_rd : std_logic; + signal port_123b_wr : std_logic; + signal port_uart_rd : std_logic; + signal port_uart_wr : std_logic; + signal port_dma_rd : std_logic; + signal port_dma_wr : std_logic; + signal port_fffd_rd : std_logic; + signal port_fffd_wr : std_logic; + signal port_bffd_wr : std_logic; + signal port_dac_A_wr : std_logic; + signal port_dac_B_wr : std_logic; + signal port_dac_C_wr : std_logic; + signal port_dac_D_wr : std_logic; + signal port_fadf_rd : std_logic; + signal port_fbdf_rd : std_logic; + signal port_ffdf_rd : std_logic; + signal port_1f_rd : std_logic; + signal port_37_rd : std_logic; + signal port_57_wr : std_logic; + signal port_5b_wr : std_logic; + signal port_303b_rd : std_logic; + signal port_303b_wr : std_logic; + signal port_bf3b_wr : std_logic; + signal port_ff3b_rd : std_logic; + signal port_ff3b_wr : std_logic; + signal port_ctc_wr : std_logic; + signal port_ctc_rd : std_logic; + + signal port_internal_rd_response : std_logic; + + signal port_fe_rd_dat : std_logic_vector(7 downto 0); + signal port_ff_rd_dat : std_logic_vector(7 downto 0); + signal port_p3_float_rd_dat : std_logic_vector(7 downto 0); + signal port_e3_rd_dat : std_logic_vector(7 downto 0); + signal port_mf_rd_dat : std_logic_vector(7 downto 0); + signal port_eb_rd_dat : std_logic_vector(7 downto 0); + signal port_243b_rd_dat : std_logic_vector(7 downto 0); + signal port_253b_rd_dat : std_logic_vector(7 downto 0); + signal port_103b_rd_dat : std_logic_vector(7 downto 0); + signal port_113b_rd_dat : std_logic_vector(7 downto 0); + signal port_123b_rd_dat : std_logic_vector(7 downto 0); + signal port_uart_rd_dat : std_logic_vector(7 downto 0); + signal port_dma_rd_dat : std_logic_vector(7 downto 0); + signal port_fffd_rd_dat : std_logic_vector(7 downto 0); + signal port_fadf_rd_dat : std_logic_vector(7 downto 0); + signal port_fbdf_rd_dat : std_logic_vector(7 downto 0); + signal port_ffdf_rd_dat : std_logic_vector(7 downto 0); + signal port_1f_rd_dat : std_logic_vector(7 downto 0); + signal port_37_rd_dat : std_logic_vector(7 downto 0); + signal port_303b_rd_dat : std_logic_vector(7 downto 0); + signal port_ff3b_rd_dat : std_logic_vector(7 downto 0); + signal port_ctc_rd_dat : std_logic_vector(7 downto 0); + + signal port_rd_dat : std_logic_vector(7 downto 0); + + -- MEMORY ADDRESSES + + signal divmmc_rst_ep : std_logic; + signal divmmc_rst_ep_valid : std_logic; + signal divmmc_rst_ep_timing : std_logic; + + signal divmmc_automap_instant_on : std_logic; + signal divmmc_automap_delayed_on : std_logic; + signal divmmc_automap_delayed_off : std_logic; + signal divmmc_automap_rom3_instant_on : std_logic; + signal divmmc_automap_rom3_delayed_on : std_logic; + signal divmmc_automap_nmi_instant_on : std_logic; + signal divmmc_automap_nmi_delayed_on : std_logic; + + signal divmmc_automap_instant_on_q : std_logic; + signal divmmc_automap_delayed_on_q : std_logic; + signal divmmc_automap_delayed_off_q : std_logic; + signal divmmc_automap_rom3_instant_on_q : std_logic; + signal divmmc_automap_rom3_delayed_on_q : std_logic; + signal divmmc_automap_nmi_instant_on_q : std_logic; + signal divmmc_automap_nmi_delayed_on_q : std_logic; + + signal mf_a_0066 : std_logic; + + -- MEMORY DECODING + + signal mem_active_page : std_logic_vector(7 downto 0); + + signal mem_active_bank5 : std_logic; + signal mem_active_bank7 : std_logic; + + signal mmu_A21_A13 : std_logic_vector(8 downto 0); + + signal layer2_active_bank_offset_pre : std_logic_vector(1 downto 0); + signal layer2_active_bank_offset : std_logic_vector(3 downto 0); + signal layer2_active_bank : std_logic_vector(6 downto 0); + signal layer2_active_page : std_logic_vector(8 downto 0); + + signal layer2_A21_A13 : std_logic_vector(8 downto 0); + + signal sram_rom : std_logic_vector(1 downto 0); + signal sram_rom3 : std_logic; + signal sram_alt_128_n : std_logic; + + signal sram_pre_romcs_replace : std_logic; + signal sram_pre_alt_en : std_logic; + signal sram_pre_alt_128_n : std_logic; + signal sram_pre_rom3 : std_logic; + signal sram_pre_layer2_rd_en : std_logic; + signal sram_pre_layer2_wr_en : std_logic; + signal sram_pre_layer2_A21_A13: std_logic_vector(8 downto 0); + + signal sram_pre_A20_A13 : std_logic_vector(7 downto 0); + signal sram_pre_active : std_logic; + signal sram_pre_bank5 : std_logic; + signal sram_pre_bank7 : std_logic; + signal sram_pre_rdonly : std_logic; + signal sram_pre_override : std_logic_vector(2 downto 0); + + signal sram_layer2_map_en : std_logic; + signal sram_altrom_en : std_logic; + + signal sram_A20_A13 : std_logic_vector(7 downto 0); + signal sram_active : std_logic; + signal sram_bank5 : std_logic; + signal sram_bank7 : std_logic; + signal sram_rdonly : std_logic; + signal sram_romcs_en : std_logic; + + signal sram_divmmc_automap_en : std_logic; + signal sram_divmmc_automap_rom3_en : std_logic; + + signal sram_memcycle : std_logic; + signal sram_romcs : std_logic; + + signal cpu_bank5_rd : std_logic; + signal cpu_bank5_we : std_logic; + signal cpu_bank7_we : std_logic; + + signal sram_addr : std_logic_vector(20 downto 0); + signal sram_rd_n : std_logic; + signal sram_req : std_logic; + signal sram_req_d : std_logic := '1'; + signal sram_req_t : std_logic; + signal sram_wait_n : std_logic := '1'; + + signal bootrom_do : std_logic_vector(7 downto 0); + + -- SERIAL COMMS + + signal i2c_scl_o : std_logic; + signal i2c_sda_o : std_logic; + signal port_103b_dat : std_logic_vector(7 downto 0) := X"FF"; + signal port_113b_dat : std_logic_vector(7 downto 0) := X"FF"; + + signal spi_ss_flash_n : std_logic; + signal spi_ss_rpi1_n : std_logic; + signal spi_ss_rpi0_n : std_logic; + signal spi_ss_sd1_n : std_logic; + signal spi_ss_sd0_n : std_logic; + signal spi_sck : std_logic; + signal spi_mosi : std_logic; + signal spi_miso : std_logic; + signal spi_wait_n : std_logic; + signal port_eb_dat : std_logic_vector(7 downto 0); + signal port_e7_reg : std_logic_vector(7 downto 0) := X"FF"; + + signal uart0_tx_esp : std_logic; + signal uart1_tx_pi : std_logic; + signal pi_uart_rtr_n : std_logic; + + signal uart_do : std_logic_vector(7 downto 0); + + signal uart0_hwflow_en : std_logic; + signal uart0_rx : std_logic; + signal uart0_rx_rtr_n : std_logic; + signal uart0_rx_avail : std_logic; + signal uart0_rx_near_full : std_logic; + signal uart0_tx : std_logic; + signal uart0_tx_cts_n : std_logic; + signal uart0_tx_empty : std_logic; + + signal uart1_hwflow_en : std_logic; + signal uart1_rx : std_logic; + signal uart1_rx_rtr_n : std_logic; + signal uart1_rx_avail : std_logic; + signal uart1_rx_near_full : std_logic; + signal uart1_tx : std_logic; + signal uart1_tx_cts_n : std_logic; + signal uart1_tx_empty : std_logic; + +-- signal joy_iomode_hwflen : std_logic; + + signal port_uart_dat : std_logic_vector(7 downto 0); + + -- KEYBOARD, JOYSTICKS & MOUSE + + signal keyrow : std_logic_vector(7 downto 0); + + signal port_fe_bus : std_logic_vector(7 downto 0); + signal port_fe_dat_0 : std_logic_vector(7 downto 0); + signal port_fe_dat : std_logic_vector(7 downto 0); + + signal mdL_1f_en : std_logic; + signal mdL_37_en : std_logic; + signal joyL_1f_en : std_logic; + signal joyL_37_en : std_logic; + signal joyL_1f : std_logic_vector(7 downto 0); + signal joyL_37 : std_logic_vector(7 downto 0); + + signal mdR_1f_en : std_logic; + signal mdR_37_en : std_logic; + signal joyR_1f_en : std_logic; + signal joyR_37_en : std_logic; + signal joyR_1f : std_logic_vector(7 downto 0); + signal joyR_37 : std_logic_vector(7 downto 0); + + signal joy_iomode_pin7 : std_logic := '1'; + signal joy_iomode_uart_en : std_logic; + signal joy_uart_rx : std_logic; + signal joy_uart_cts_n : std_logic; + + signal port_1f_dat : std_logic_vector(7 downto 0); + signal port_37_dat : std_logic_vector(7 downto 0); + signal port_fbdf_dat : std_logic_vector(7 downto 0); + signal port_ffdf_dat : std_logic_vector(7 downto 0); + signal port_fadf_dat : std_logic_vector(7 downto 0); + + -- DEVICES + + signal port_fe_reg : std_logic_vector(4 downto 0); + signal port_fe_ear : std_logic; + signal port_fe_mic : std_logic; + signal port_fe_border : std_logic_vector(2 downto 0) := "000"; + + signal port_ff_reg : std_logic_vector(7 downto 0); + signal port_ff_screen_mode : std_logic_vector(5 downto 0); + signal port_ff_interrupt_disable : std_logic; + + signal port_7ffd_reg : std_logic_vector(7 downto 0); + signal port_7ffd_dat : std_logic_vector(7 downto 0); + signal port_7ffd_bank : std_logic_vector(6 downto 0); + signal port_7ffd_shadow : std_logic; + signal port_7ffd_locked : std_logic; + + signal port_dffd_reg : std_logic_vector(4 downto 0); + signal port_dffd_reg_6 : std_logic; + + signal port_1ffd_reg : std_logic_vector(7 downto 0); + signal port_1ffd_dat : std_logic_vector(7 downto 0); + signal port_1ffd_special : std_logic; + signal port_1ffd_special_old : std_logic; + signal port_1ffd_rom : std_logic_vector(1 downto 0); + + signal port_eff7_reg_2 : std_logic; + signal port_eff7_reg_3 : std_logic; + + signal nr_8f_mapping_mode : std_logic_vector(1 downto 0) := (others => '0'); + signal nr_8f_mapping_mode_profi : std_logic; + signal nr_8f_mapping_mode_pentagon : std_logic; + signal nr_8f_mapping_mode_pentagon_1024 : std_logic; + signal nr_8f_mapping_mode_pentagon_1024_en: std_logic; + + signal port_memory_change_dly : std_logic := '0'; + signal port_memory_ram_change_dly : std_logic := '0'; + signal nr_8f_we_dly : std_logic := '0'; + + signal port_123b_dat : std_logic_vector(7 downto 0) := (others => '0'); + signal port_123b_layer2_en : std_logic; + signal port_123b_layer2_map_wr_en : std_logic; + signal port_123b_layer2_map_rd_en : std_logic; + signal port_123b_layer2_map_shadow : std_logic; + signal port_123b_layer2_map_segment : std_logic_vector(1 downto 0); + signal port_123b_layer2_offset : std_logic_vector(2 downto 0); + + signal copper_instr_addr : std_logic_vector(9 downto 0); + signal copper_dout_en : std_logic; + signal copper_dout : std_logic_vector(14 downto 0); + signal copper_instr_data : std_logic_vector(15 downto 0); + signal copper_msb_we : std_logic; + signal copper_msb_dat : std_logic_vector(7 downto 0); + signal copper_lsb_we : std_logic; + signal copper_lsb_dat : std_logic_vector(7 downto 0); + + signal ctc_do : std_logic_vector(7 downto 0); + signal port_ctc_dat : std_logic_vector(7 downto 0); + signal ctc_zc_to : std_logic_vector(7 downto 0); + signal ctc_int_en : std_logic_vector(7 downto 0); + + signal divmmc_rom_en : std_logic; + signal divmmc_ram_en : std_logic; + signal divmmc_rdonly : std_logic; + signal divmmc_bank : std_logic_vector(3 downto 0); + signal port_e3_reg : std_logic_vector(7 downto 0); + signal port_e3_dat : std_logic_vector(7 downto 0); + signal divmmc_nmi_hold : std_logic; + signal divmmc_automap_held : std_logic; + signal divmmc_retn_seen : std_logic; + signal divmmc_automap_reset : std_logic; + + signal layer2_addr : std_logic_vector(16 downto 0); + signal layer2_pixel_en : std_logic; + signal layer2_addr_eff : std_logic_vector(20 downto 0); + signal layer2_req_t : std_logic; + signal layer2_pixel : std_logic_vector(7 downto 0); + + signal lores_mode_0 : std_logic; + signal lores_dfile_0 : std_logic; + signal lores_palette_offset_0 : std_logic_vector(3 downto 0); + signal lores_addr : std_logic_vector(13 downto 0); + signal lores_vram_di : std_logic_vector(7 downto 0); + signal lores_pixel : std_logic_vector(7 downto 0); + signal lores_pixel_en : std_logic; + signal lores_scroll_x_0 : std_logic_vector(7 downto 0); + signal lores_scroll_y_0 : std_logic_vector(7 downto 0); +-- signal lores_clip_x1_0 : std_logic_vector(7 downto 0); +-- signal lores_clip_x2_0 : std_logic_vector(7 downto 0); +-- signal lores_clip_y1_0 : std_logic_vector(7 downto 0); +-- signal lores_clip_y2_0 : std_logic_vector(7 downto 0); + + signal mf_mem_en : std_logic; + signal mf_nmi_hold : std_logic; + signal mf_port_en : std_logic; + signal mf_port_dat : std_logic_vector(7 downto 0); + signal mf_is_active : std_logic; + + signal port_303b_dat : std_logic_vector(7 downto 0); + signal sprite_mirror_id : std_logic_vector(6 downto 0); + signal sprite_pixel : std_logic_vector(7 downto 0); + signal sprite_pixel_en : std_logic; + + signal sc : std_logic_vector(1 downto 0); + signal tm_mem_bank7 : std_logic; + signal tm_vram_a : std_logic_vector(13 downto 0); + signal tm_vram_rd : std_logic; + signal tm_vram_ack : std_logic; + signal tm_vram_di : std_logic_vector(7 downto 0); + signal tm_pixel : std_logic_vector(7 downto 0); + signal tm_pixel_en : std_logic; + signal tm_pixel_below : std_logic; + signal tm_pixel_textmode : std_logic; + + signal ula_wait_n : std_logic; + signal ula_cpu_contend : std_logic; + signal ula_floating_bus : std_logic_vector(7 downto 0); + signal ula_vram_shadow : std_logic; + signal ula_vram_rd : std_logic; + signal ula_vram_a : std_logic_vector(13 downto 0); + signal ula_vram_di : std_logic_vector(7 downto 0); + signal ula_clip_x1_0 : std_logic_vector(7 downto 0); + signal ula_clip_x2_0 : std_logic_vector(7 downto 0); + signal ula_clip_y1_0 : std_logic_vector(7 downto 0); + signal ula_clip_y2_0 : std_logic_vector(7 downto 0); + signal ula_border : std_logic; + signal ula_pixel : std_logic_vector(7 downto 0); + signal ula_select_bgnd : std_logic; + signal ula_clipped : std_logic; + + signal mem_contend : std_logic; + signal port_contend : std_logic; + signal p3_floating_bus_dat : std_logic_vector(7 downto 0); + signal port_ff_dat_ula : std_logic_vector(7 downto 0); + signal port_ff_dat_tmx : std_logic_vector(7 downto 0); + signal port_p3_floating_bus_dat : std_logic_vector(7 downto 0); + + signal port_bf3b_ulap_mode : std_logic_vector(1 downto 0); + signal port_bf3b_ulap_index : std_logic_vector(5 downto 0); + signal port_ff3b_ulap_en : std_logic; + signal ulap_palette_rd : std_logic; + signal ulap_palette_rd_dly : std_logic; + signal ulap_palette_rd_done : std_logic; + signal ulap_wait_n : std_logic; + signal port_ff3b_dat : std_logic_vector(7 downto 0); + + -- TBBLUE REGISTRY + + signal nr_register : std_logic_vector(7 downto 0); + signal port_243b_dat : std_logic_vector(7 downto 0); + + signal MMU0 : std_logic_vector(7 downto 0); + signal MMU1 : std_logic_vector(7 downto 0); + signal MMU2 : std_logic_vector(7 downto 0); + signal MMU3 : std_logic_vector(7 downto 0); + signal MMU4 : std_logic_vector(7 downto 0); + signal MMU5 : std_logic_vector(7 downto 0); + signal MMU6 : std_logic_vector(7 downto 0); + signal MMU7 : std_logic_vector(7 downto 0); + + signal copper_requester : std_logic; + signal copper_req_dly : std_logic; + signal copper_req : std_logic; + signal copper_nr_reg : std_logic_vector(7 downto 0); + signal copper_nr_dat : std_logic_vector(7 downto 0); + signal cpu_requester_0 : std_logic; + signal cpu_requester_1 : std_logic; + signal cpu_requester_2 : std_logic; + signal cpu_req_dly : std_logic; + signal cpu_req : std_logic; + signal cpu_nr_reg : std_logic_vector(7 downto 0); + signal cpu_nr_dat : std_logic_vector(7 downto 0); + signal nr_wr_en : std_logic; + signal nr_wr_reg : std_logic_vector(7 downto 0); + signal nr_wr_dat : std_logic_vector(7 downto 0); + signal cpu_served : std_logic; + + signal nr_02_we : std_logic; + signal nr_05_we : std_logic; + signal nr_07_we : std_logic; + signal nr_08_we : std_logic; + signal nr_09_we : std_logic; + signal nr_28_we : std_logic; + signal nr_29_we : std_logic; +-- signal nr_2a_we : std_logic; + signal nr_2b_we : std_logic; + signal nr_2c_we : std_logic; + signal nr_2d_we : std_logic; + signal nr_2e_we : std_logic; + signal nr_22_we : std_logic; + signal nr_41_we : std_logic; + signal nr_44_we : std_logic; + signal nr_sprite_mirror_we : std_logic; + signal nr_sprite_mirror_index : std_logic_vector(2 downto 0); + signal nr_sprite_mirror_inc : std_logic; + signal nr_palette_we : std_logic; + signal nr_palette_value : std_logic_vector(8 downto 0); + signal nr_palette_priority : std_logic_vector(1 downto 0); + signal nr_mmu_we : std_logic; + signal nr_mmu : std_logic_vector(2 downto 0); + signal nr_copper_we : std_logic; + signal nr_copper_write_8 : std_logic; + signal nr_68_we : std_logic; + signal nr_69_we : std_logic; + signal nr_80_we : std_logic; + signal nr_8c_we : std_logic; + signal nr_8e_we : std_logic; + signal nr_8f_we : std_logic; + signal nr_c2_we : std_logic; + signal nr_c3_we : std_logic; + signal nr_c4_we : std_logic; + signal nr_c5_we : std_logic; + signal nr_c8_we : std_logic; + signal nr_c9_we : std_logic; + signal nr_ca_we : std_logic; + signal nr_ff_we : std_logic; + + signal nr_02_bus_reset : std_logic := '0'; + signal nr_02_generate_mf_nmi : std_logic; + signal nr_02_generate_divmmc_nmi : std_logic; + signal nr_03_machine_timing : std_logic_vector(2 downto 0) := "000"; + signal nr_03_user_dt_lock : std_logic := '0'; + signal bootrom_en : std_logic := '1'; + signal nr_03_config_mode : std_logic := '1'; + signal nr_03_machine_type : std_logic_vector(2 downto 0) := "000"; + signal nr_04_romram_bank : std_logic_vector(6 downto 0) := (others => '0'); + signal nr_05_joy0 : std_logic_vector(2 downto 0) := "001"; + signal nr_05_joy1 : std_logic_vector(2 downto 0) := "000"; + signal nr_06_hotkey_cpu_speed_en : std_logic; + signal nr_06_hotkey_5060_en : std_logic; + signal nr_06_button_drive_nmi_en : std_logic := '0'; + signal nr_06_button_m1_nmi_en : std_logic := '0'; + signal nr_06_ps2_mode : std_logic := '1'; + signal nr_06_psg_mode : std_logic_vector(1 downto 0) := "00"; + signal nr_06_internal_speaker_beep : std_logic := '0'; + signal nr_08_contention_disable : std_logic := '0'; + signal nr_08_psg_stereo_mode : std_logic := '0'; + signal nr_08_internal_speaker_en : std_logic := '1'; + signal nr_08_dac_en : std_logic := '0'; + signal nr_08_port_ff_rd_en : std_logic := '0'; + signal nr_08_psg_turbosound_en : std_logic := '0'; + signal nr_08_keyboard_issue2 : std_logic := '0'; + signal nr_09_psg_mono : std_logic_vector(2 downto 0) := (others => '0'); + signal nr_09_hdmi_audio_disable : std_logic := '0'; + signal nr_09_sprite_tie : std_logic; + signal nr_0a_mf_type : std_logic_vector(1 downto 0) := "00"; + signal nr_0a_divmmc_automap_en : std_logic := '0'; + signal nr_0a_mouse_button_reverse : std_logic := '0'; + signal nr_0a_mouse_dpi : std_logic_vector(1 downto 0) := "01"; + signal nr_0b_joy_iomode_en : std_logic; + signal nr_0b_joy_iomode : std_logic_vector(1 downto 0); + signal nr_0b_joy_iomode_0 : std_logic; + signal nr_10_flashboot : std_logic := '0'; + signal nr_10_coreid : std_logic_vector(4 downto 0) := "00001"; + signal nr_11_video_timing : std_logic_vector(2 downto 0) := "000"; + signal nr_12_layer2_active_bank : std_logic_vector(6 downto 0); + signal nr_13_layer2_shadow_bank : std_logic_vector(6 downto 0); + signal nr_14_global_transparent_rgb : std_logic_vector(7 downto 0); + signal nr_15_lores_en : std_logic; + signal nr_15_sprite_priority : std_logic; + signal nr_15_sprite_border_clip_en : std_logic; + signal nr_15_layer_priority : std_logic_vector(2 downto 0); + signal nr_15_sprite_over_border_en : std_logic; + signal nr_15_sprite_en : std_logic; + signal nr_16_layer2_scrollx : std_logic_vector(7 downto 0); + signal nr_17_layer2_scrolly : std_logic_vector(7 downto 0); + signal nr_18_layer2_clip_x1 : std_logic_vector(7 downto 0); + signal nr_18_layer2_clip_x2 : std_logic_vector(7 downto 0); + signal nr_18_layer2_clip_y1 : std_logic_vector(7 downto 0); + signal nr_18_layer2_clip_y2 : std_logic_vector(7 downto 0); + signal nr_18_layer2_clip_idx : std_logic_vector(1 downto 0); + signal nr_19_sprite_clip_x1 : std_logic_vector(7 downto 0); + signal nr_19_sprite_clip_x2 : std_logic_vector(7 downto 0); + signal nr_19_sprite_clip_y1 : std_logic_vector(7 downto 0); + signal nr_19_sprite_clip_y2 : std_logic_vector(7 downto 0); + signal nr_19_sprite_clip_idx : std_logic_vector(1 downto 0); + signal nr_1a_ula_clip_x1 : std_logic_vector(7 downto 0); + signal nr_1a_ula_clip_x2 : std_logic_vector(7 downto 0); + signal nr_1a_ula_clip_y1 : std_logic_vector(7 downto 0); + signal nr_1a_ula_clip_y2 : std_logic_vector(7 downto 0); + signal nr_1a_ula_clip_idx : std_logic_vector(1 downto 0); + signal nr_1b_tm_clip_x1 : std_logic_vector(7 downto 0); + signal nr_1b_tm_clip_x2 : std_logic_vector(7 downto 0); + signal nr_1b_tm_clip_y1 : std_logic_vector(7 downto 0); + signal nr_1b_tm_clip_y2 : std_logic_vector(7 downto 0); + signal nr_1b_tm_clip_idx : std_logic_vector(1 downto 0); +-- signal nr_1c_clip_select : std_logic_vector(3 downto 0); +-- signal nr_1d_lores_clip_x1 : std_logic_vector(7 downto 0); +-- signal nr_1d_lores_clip_x2 : std_logic_vector(7 downto 0); +-- signal nr_1d_lores_clip_y1 : std_logic_vector(7 downto 0); +-- signal nr_1d_lores_clip_y2 : std_logic_vector(7 downto 0); +-- signal nr_1d_lores_clip_idx : std_logic_vector(1 downto 0); + signal nr_22_line_interrupt_en : std_logic; + signal nr_23_line_interrupt : std_logic_vector(8 downto 0); + signal nr_26_ula_scrollx : std_logic_vector(7 downto 0); + signal nr_27_ula_scrolly : std_logic_vector(7 downto 0); + signal nr_2d_i2s_sample : std_logic_vector(1 downto 0); + signal nr_30_tm_scrollx : std_logic_vector(9 downto 0); + signal nr_31_tm_scrolly : std_logic_vector(7 downto 0); + signal nr_32_lores_scrollx : std_logic_vector(7 downto 0); + signal nr_33_lores_scrolly : std_logic_vector(7 downto 0); + signal nr_palette_idx : std_logic_vector(7 downto 0); + signal nr_palette_sub_idx : std_logic; + signal nr_42_ulanext_format : std_logic_vector(7 downto 0); + signal nr_43_palette_autoinc_disable : std_logic; + signal nr_43_palette_write_select : std_logic_vector(2 downto 0); + signal nr_43_active_sprite_palette : std_logic; + signal nr_43_active_layer2_palette : std_logic; + signal nr_43_active_ula_palette : std_logic; + signal nr_43_ulanext_en : std_logic; + signal nr_stored_palette_value : std_logic_vector(7 downto 0); + signal nr_4a_fallback_rgb : std_logic_vector(7 downto 0); + signal nr_4b_sprite_transparent_index : std_logic_vector(7 downto 0); + signal nr_4c_tm_transparent_index : std_logic_vector(3 downto 0); + signal nr_copper_addr : std_logic_vector(10 downto 0); + signal nr_copper_data_stored : std_logic_vector(7 downto 0); + signal nr_62_copper_mode : std_logic_vector(1 downto 0); + signal nr_64_copper_offset : std_logic_vector(7 downto 0); + signal nr_68_ula_en : std_logic; + signal nr_68_blend_mode : std_logic_vector(1 downto 0); + signal nr_68_cancel_extended_keys : std_logic; + signal nr_68_ula_fine_scroll_x : std_logic; + signal nr_68_ula_stencil_mode : std_logic; + signal nr_6a_lores_radastan : std_logic; + signal nr_6a_lores_radastan_xor : std_logic; + signal nr_6a_lores_palette_offset : std_logic_vector(3 downto 0); + signal nr_6b_tm_en : std_logic; + signal nr_6b_tm_control : std_logic_vector(6 downto 0); + signal nr_6c_tm_default_attr : std_logic_vector(7 downto 0); + signal nr_6e_tilemap_base : std_logic_vector(5 downto 0); + signal nr_6e_tilemap_base_7 : std_logic; + signal nr_6f_tilemap_tiles : std_logic_vector(5 downto 0); + signal nr_6f_tilemap_tiles_7 : std_logic; + signal nr_70_layer2_resolution : std_logic_vector(1 downto 0); + signal nr_70_layer2_palette_offset : std_logic_vector(3 downto 0); + signal nr_71_layer2_scrollx_msb : std_logic; + signal nr_7f_user_register_0 : std_logic_vector(7 downto 0) := X"FF"; + signal nr_98_pi_gpio_o : std_logic_vector(7 downto 0); + signal nr_99_pi_gpio_o : std_logic_vector(7 downto 0); + signal nr_9a_pi_gpio_o : std_logic_vector(7 downto 0); + signal nr_9b_pi_gpio_o : std_logic_vector(3 downto 0); + signal nr_81_expbus_ula_override : std_logic := '0'; + signal nr_81_expbus_nmi_debounce_disable : std_logic := '0'; + signal nr_81_expbus_clken : std_logic := '0'; + signal nr_81_expbus_speed : std_logic_vector(1 downto 0) := "00"; + signal nr_82_internal_port_enable : std_logic_vector(7 downto 0) := (others => '1'); + signal nr_83_internal_port_enable : std_logic_vector(7 downto 0) := (others => '1'); + signal nr_84_internal_port_enable : std_logic_vector(7 downto 0) := (others => '1'); + signal nr_85_internal_port_enable : std_logic_vector(3 downto 0) := (others => '1'); + signal nr_85_internal_port_reset_type : std_logic := '1'; + signal nr_86_bus_port_enable : std_logic_vector(7 downto 0) := (others => '1'); + signal nr_87_bus_port_enable : std_logic_vector(7 downto 0) := (others => '1'); + signal nr_88_bus_port_enable : std_logic_vector(7 downto 0) := (others => '1'); + signal nr_89_bus_port_enable : std_logic_vector(3 downto 0) := (others => '1'); + signal nr_89_bus_port_reset_type : std_logic := '1'; + signal nr_8a_bus_port_propagate : std_logic_vector(5 downto 0) := (others => '0'); + signal nr_90_pi_gpio_o_en : std_logic_vector(7 downto 0) := (others => '0'); + signal nr_91_pi_gpio_o_en : std_logic_vector(7 downto 0) := (others => '0'); + signal nr_92_pi_gpio_o_en : std_logic_vector(7 downto 0) := (others => '0'); + signal nr_93_pi_gpio_o_en : std_logic_vector(3 downto 0) := (others => '0'); + signal nr_a0_pi_peripheral_en : std_logic_vector(7 downto 0); + signal nr_a2_pi_i2s_ctl : std_logic_vector(7 downto 0); +-- signal nr_a3_pi_i2s_clkdiv : std_logic_vector(7 downto 0); + signal nr_a8_esp_gpio0_en : std_logic := '0'; + signal nr_a9_esp_gpio0 : std_logic := '1'; + signal nr_b8_divmmc_ep_0 : std_logic_vector(7 downto 0); + signal nr_b9_divmmc_ep_valid_0 : std_logic_vector(7 downto 0); + signal nr_ba_divmmc_ep_timing_0 : std_logic_vector(7 downto 0); + signal nr_bb_divmmc_ep_1 : std_logic_vector(7 downto 0); + signal nr_c0_im2_vector : std_logic_vector(2 downto 0); + signal nr_c0_stackless_nmi : std_logic; + signal nr_c0_int_mode_pulse_0_im2_1 : std_logic; + signal nr_c2_retn_address_lsb : std_logic_vector(7 downto 0); + signal nr_c3_retn_address_msb : std_logic_vector(7 downto 0); + signal nr_c4_int_en_0_expbus : std_logic; + signal nr_c6_int_en_2_654 : std_logic_vector(2 downto 0); + signal nr_c6_int_en_2_210 : std_logic_vector(2 downto 0); + signal nr_cc_dma_int_en_0_10 : std_logic_vector(1 downto 0); + signal nr_cd_dma_int_en_1 : std_logic_vector(7 downto 0); + signal nr_ce_dma_int_en_2_654 : std_logic_vector(2 downto 0); + signal nr_ce_dma_int_en_2_210 : std_logic_vector(2 downto 0); + + signal machine_type_48 : std_logic; + signal machine_type_128 : std_logic; + signal machine_type_p3 : std_logic; + + signal machine_timing_48 : std_logic; + signal machine_timing_128 : std_logic; + signal machine_timing_p3 : std_logic; + signal machine_timing_pentagon : std_logic; + + signal hotkey_cpu_speed : std_logic; + signal hotkey_5060 : std_logic; + signal hotkey_scandouble : std_logic; + signal hotkey_scanlines : std_logic; + signal hotkey_hard_reset : std_logic; + signal hotkey_soft_reset : std_logic; + signal hotkey_expbus_enable : std_logic; + signal hotkey_expbus_disable : std_logic; + signal hotkey_expbus_freeze : std_logic; + signal hotkey_m1 : std_logic; + signal hotkey_drive : std_logic; + + signal nr_07_cpu_speed : std_logic_vector(1 downto 0); + signal cpu_speed : std_logic_vector(1 downto 0) := "00"; + + signal nr_05_5060 : std_logic := '0'; + signal nr_05_scandouble_en : std_logic := '1'; + signal nr_09_scanlines : std_logic_vector(1 downto 0) := "00"; + + signal nr_02_reset_type : std_logic_vector(2 downto 0) := "100"; + signal port_253b_dat : std_logic_vector(7 downto 0); + signal port_253b_dat_0 : std_logic_vector(7 downto 0); + + -- PS/2 KEYMAP & KEY JOYSTICK & HOT KEYS + + signal nr_keymap_sel : std_logic := '0'; + signal nr_keymap_addr : std_logic_vector(8 downto 0) := "000000000"; +-- signal nr_keymap_dat_msb : std_logic := '0'; + signal nr_keymap_we : std_logic; + signal nr_joymap_we : std_logic; + signal nr_keymap_dat : std_logic_vector(7 downto 0); + + signal hotkeys_1 : std_logic_vector(10 downto 1) := "0000000000"; + signal hotkeys_0 : std_logic_vector(10 downto 1) := "0000000000"; + signal nr_02_soft_reset : std_logic; + signal nr_02_hard_reset : std_logic; + + -- AUDIO + + signal audio_ay_reset : std_logic; + signal psg_dat : std_logic_vector(7 downto 0); + signal pcm_ay_L : std_logic_vector(11 downto 0); + signal pcm_ay_R : std_logic_vector(11 downto 0); + signal port_fffd_dat : std_logic_vector(7 downto 0); + + signal port_fe_mic_final : std_logic; + signal internal_speaker_beep_exclusive : std_logic; + + signal pcm_dac_L : std_logic_vector(8 downto 0); + signal pcm_dac_R : std_logic_vector(8 downto 0); + + signal pi_mi2s_sck : std_logic; + signal pi_mi2s_ws : std_logic; + signal pi_si2s_sck : std_logic; + signal pi_si2s_ws : std_logic; + signal pi_i2s_sd_o : std_logic; + signal pi_i2s_sd_i : std_logic; + signal pi_i2s_audio_L : std_logic_vector(9 downto 0); + signal pi_i2s_audio_R : std_logic_vector(9 downto 0); + + signal pcm_audio_L : std_logic_vector(12 downto 0); + signal pcm_audio_R : std_logic_vector(12 downto 0); + + -- VIDEO + + signal cpu_bank5_req : std_logic; + signal cpu_bank5_req_dly : std_logic; + signal cpu_bank5_sched_dly : std_logic; + signal cpu_bank5_sched : std_logic; + signal cpu_bank5_do : std_logic_vector(7 downto 0); + signal vram_bank5_do0 : std_logic_vector(7 downto 0); + signal vram_bank5_do1 : std_logic_vector(7 downto 0); + signal ula_bank_req : std_logic; + signal ula_bank_req_dly : std_logic; + signal ula_bank_sched_dly : std_logic; + signal ula_bank_sched : std_logic; + signal ula_bank_do : std_logic_vector(7 downto 0); + signal lores_vram_req : std_logic; + signal lores_vram_ack_dly : std_logic; + signal vram_bank5_a0 : std_logic_vector(13 downto 0); + signal vram_bank_a1 : std_logic_vector(13 downto 0); + signal lores_vram_ack : std_logic; + + signal cpu_bank7_do : std_logic_vector(7 downto 0); + signal vram_bank7_do : std_logic_vector(7 downto 0); + + signal video_timing_change : std_logic; + signal video_timing_change_d : std_logic := '1'; + + signal eff_nr_03_machine_timing : std_logic_vector(2 downto 0) := "000"; + signal eff_nr_05_5060 : std_logic; + signal eff_nr_05_scandouble_en : std_logic; + signal eff_nr_08_contention_disable : std_logic := '0'; + signal eff_nr_09_scanlines : std_logic_vector(1 downto 0); + + signal ula_int_en : std_logic_vector(1 downto 0); + signal hc : unsigned(8 downto 0); + signal vc : unsigned(8 downto 0); + signal phc : unsigned(8 downto 0); + signal whc : unsigned(8 downto 0); + signal wvc : unsigned(8 downto 0); + signal cvc : unsigned(8 downto 0); + signal rgb_hsync_n : std_logic; + signal rgb_vsync_n : std_logic; + signal rgb_hblank_n : std_logic; + signal rgb_vblank_n : std_logic; + + signal pulse_int_n : std_logic; + signal ula_int_pulse : std_logic; + signal line_int_pulse : std_logic; + signal pulse_count_end : std_logic; + signal pulse_count : std_logic_vector(4 downto 0); + + signal layer_priorities_0 : std_logic_vector(2 downto 0); + signal ula_en_0 : std_logic; + signal ula_stencil_mode_0 : std_logic; + signal ula_blend_mode_0 : std_logic_vector(1 downto 0); + signal ulanext_en_0 : std_logic; + signal ulanext_format_0 : std_logic_vector(7 downto 0); + signal ulap_en_0 : std_logic; + signal lores_en_0 : std_logic; + signal sprite_en_0 : std_logic; + signal tm_en_0 : std_logic; + signal transparent_rgb_0 : std_logic_vector(7 downto 0); + signal fallback_rgb_0 : std_logic_vector(7 downto 0); + signal ula_palette_select_0 : std_logic; + signal tm_palette_select_0 : std_logic; + signal layer2_palette_select_0 : std_logic; + signal sprite_palette_select_0 : std_logic; + + signal lores_pixel_1 : std_logic_vector(7 downto 0); + signal lores_pixel_en_1a : std_logic; + signal layer2_pixel_1 : std_logic_vector(7 downto 0); + signal sprite_pixel_1 : std_logic_vector(7 downto 0); + signal sprite_pixel_en_1a : std_logic; + signal ula_pixel_1 : std_logic_vector(7 downto 0); + signal ula_select_bgnd_1 : std_logic; + signal tm_pixel_1 : std_logic_vector(7 downto 0); + signal tm_pixel_en_1 : std_logic; + signal tm_pixel_below_1 : std_logic; + signal tm_pixel_textmode_1 : std_logic; + signal ula_border_1 : std_logic; + signal ula_clipped_1 : std_logic; + signal layer_priorities_1 : std_logic_vector(2 downto 0); + signal video_blank_n_1 : std_logic; + signal rgb_vsync_n_1 : std_logic; + signal rgb_vblank_n_1 : std_logic; + signal rgb_hblank_n_1 : std_logic; + signal rgb_hsync_n_1 : std_logic; + signal ula_en_1 : std_logic; + signal ula_en_1a : std_logic; + signal ula_stencil_mode_1 : std_logic; + signal ula_stencil_mode_1a : std_logic; + signal ula_blend_mode_1 : std_logic_vector(1 downto 0); + signal ula_blend_mode_1a : std_logic_vector(1 downto 0); + signal lores_en_1 : std_logic; + signal lores_en_1a : std_logic; + signal sprite_en_1 : std_logic; + signal sprite_en_1a : std_logic; + signal tm_en_1 : std_logic; + signal tm_en_1a : std_logic; + signal transparent_rgb_1 : std_logic_vector(7 downto 0); + signal transparent_rgb_1a : std_logic_vector(7 downto 0); + signal fallback_rgb_1 : std_logic_vector(7 downto 0); + signal fallback_rgb_1a : std_logic_vector(7 downto 0); + signal ula_palette_select_1 : std_logic; + signal ula_palette_select_1a : std_logic; + signal tm_palette_select_1 : std_logic; + signal tm_palette_select_1a : std_logic; + signal layer2_palette_select_1 : std_logic; + signal layer2_palette_select_1a : std_logic; + signal sprite_palette_select_1 : std_logic; + signal sprite_palette_select_1a : std_logic; + signal lores_pixel_en_1 : std_logic; + signal layer2_pixel_en_1 : std_logic; + signal sprite_pixel_en_1 : std_logic; + + signal nr_palette_index : std_logic_vector(9 downto 0); + signal nr_palette_index_utm : std_logic_vector(9 downto 0); + signal nr_palette_dat : std_logic_vector(10 downto 0); + signal nr_palette_rd : std_logic; + signal nr_ulatm_we : std_logic; + signal nr_ulatm_palette_dat : std_logic_vector(15 downto 0); + signal ulatm_rgb_1 : std_logic_vector(15 downto 0); + signal ulalores_pixel_1 : std_logic_vector(7 downto 0); + signal ulatm_pixel_1 : std_logic_vector(9 downto 0); + signal ula_rgb_1 : std_logic_vector(8 downto 0); + signal ula_rgb_2 : std_logic_vector(8 downto 0); + signal tm_rgb_2 : std_logic_vector(8 downto 0); +-- signal lores_rgb_2 : std_logic_vector(8 downto 0); + signal nr_l2s_palette_we : std_logic; + signal nr_l2s_palette_dat : std_logic_vector(15 downto 0); + signal l2s_prgb_1 : std_logic_vector(15 downto 0); + signal l2s_pixel_1 : std_logic_vector(9 downto 0); + signal layer2_prgb_1 : std_logic_vector(9 downto 0); + signal layer2_rgb_2 : std_logic_vector(8 downto 0); + signal layer2_priority_2 : std_logic; + signal sprite_rgb_2 : std_logic_vector(8 downto 0); + signal ula_en_2 : std_logic; + signal ula_border_2 : std_logic; + signal ula_clipped_2 : std_logic; + signal ula_stencil_mode_2 : std_logic; + signal ula_blend_mode_2 : std_logic_vector(1 downto 0); +-- signal lores_en_2 : std_logic; + signal tm_en_2 : std_logic; + signal tm_pixel_en_2 : std_logic; + signal tm_pixel_below_2 : std_logic; + signal tm_pixel_textmode_2 : std_logic; + signal layer2_pixel_en_2 : std_logic; + signal sprite_pixel_en_2 : std_logic; + signal transparent_rgb_2 : std_logic_vector(7 downto 0); + signal fallback_rgb_2 : std_logic_vector(7 downto 0); + signal layer_priorities_2 : std_logic_vector(2 downto 0); + signal video_blank_n_2 : std_logic; + signal rgb_vsync_n_2 : std_logic; + signal rgb_vblank_n_2 : std_logic; + signal rgb_hblank_n_2 : std_logic; + signal rgb_hsync_n_2 : std_logic; + + signal ula_mix_transparent : std_logic; + signal ula_mix_rgb : std_logic_vector(8 downto 0); + signal mix_top_transparent : std_logic; + signal mix_top_rgb : std_logic_vector(8 downto 0); + signal mix_bot_transparent : std_logic; + signal mix_bot_rgb : std_logic_vector(8 downto 0); + signal ula_transparent : std_logic; + signal ula_rgb : std_logic_vector(8 downto 0); +-- signal lores_transparent : std_logic; +-- signal lores_rgb : std_logic_vector(8 downto 0); + signal tm_transparent : std_logic; + signal tm_rgb : std_logic_vector(8 downto 0); + signal stencil_transparent : std_logic; + signal stencil_rgb : std_logic_vector(8 downto 0); + signal ulatm_transparent : std_logic; + signal ulatm_rgb : std_logic_vector(8 downto 0); + signal sprite_transparent : std_logic; + signal sprite_rgb : std_logic_vector(8 downto 0); + signal layer2_transparent : std_logic; + signal layer2_rgb : std_logic_vector(8 downto 0); + signal layer2_priority : std_logic; + signal ula_final_rgb : std_logic_vector(8 downto 0); + signal ula_final_transparent : std_logic; + signal mix_rgb : std_logic_vector(8 downto 0); + signal mix_rgb_transparent : std_logic; + signal rgb_out_2 : std_logic_vector(8 downto 0); + signal rgb_out_2a : std_logic_vector(8 downto 0); + + signal rgb_vsync_n_7 : std_logic; + signal rgb_vsync_n_6 : std_logic; + signal rgb_vsync_n_5 : std_logic; + signal rgb_vsync_n_4 : std_logic; + signal rgb_vsync_n_3 : std_logic; + signal rgb_vblank_n_7 : std_logic; + signal rgb_vblank_n_6 : std_logic; + signal rgb_vblank_n_5 : std_logic; + signal rgb_vblank_n_4 : std_logic; + signal rgb_vblank_n_3 : std_logic; + signal rgb_hblank_n_7 : std_logic; + signal rgb_hblank_n_6 : std_logic; + signal rgb_hblank_n_5 : std_logic; + signal rgb_hblank_n_4 : std_logic; + signal rgb_hblank_n_3 : std_logic; + signal rgb_hsync_n_7 : std_logic; + signal rgb_hsync_n_6 : std_logic; + signal rgb_hsync_n_5 : std_logic; + signal rgb_hsync_n_4 : std_logic; + signal rgb_hsync_n_3 : std_logic; + signal rgb_out_7 : std_logic_vector(8 downto 0); + signal rgb_out_6 : std_logic_vector(8 downto 0); + signal rgb_out_5 : std_logic_vector(8 downto 0); + signal rgb_out_4 : std_logic_vector(8 downto 0); + signal rgb_out_3 : std_logic_vector(8 downto 0); + + signal rgb_vsync_n_o : std_logic; + signal rgb_vblank_n_o : std_logic; + signal rgb_hblank_n_o : std_logic; + signal rgb_hsync_n_o : std_logic; + signal rgb_out_o : std_logic_vector(8 downto 0); + signal rgb_csync_n_o : std_logic; + +begin + + ------------------------------------------------------------ + -- OUTPUT -------------------------------------------------- + ------------------------------------------------------------ + + o_CPU_SPEED <= cpu_speed; + o_CPU_CONTEND <= ula_cpu_contend; + o_CPU_CLK_LSB <= hc(0); + + o_RESET_SOFT <= nr_02_soft_reset; + o_RESET_HARD <= nr_02_hard_reset; + o_RESET_PERIPHERAL <= nr_02_bus_reset; + + o_FLASH_BOOT <= nr_10_flashboot; + o_CORE_ID <= nr_10_coreid; + + o_KBD_CANCEL <= nr_68_cancel_extended_keys; + o_KBD_ROW <= keyrow; + + o_KEYMAP_ADDR <= nr_keymap_addr; + o_KEYMAP_DATA <= nr_keymap_dat; + o_KEYMAP_WE <= nr_keymap_we; + o_JOYMAP_WE <= nr_joymap_we; + + o_JOY_IO_MODE_EN <= nr_0b_joy_iomode_en; + o_JOY_IO_MODE_PIN_7 <= joy_iomode_pin7; + + o_JOY_LEFT_TYPE <= nr_05_joy0; + o_JOY_RIGHT_TYPE <= nr_05_joy1; + + o_PS2_MODE <= nr_06_ps2_mode; + o_MOUSE_CONTROL <= nr_0a_mouse_button_reverse & nr_0a_mouse_dpi; + + o_I2C_SCL_n <= i2c_scl_o; + o_I2C_SDA_n <= i2c_sda_o; + + o_SPI_SS_FLASH_n <= spi_ss_flash_n; + o_SPI_SS_SD1_n <= spi_ss_sd1_n; + o_SPI_SS_SD0_n <= spi_ss_sd0_n; + + o_SPI_SCK <= spi_sck; + o_SPI_MOSI <= spi_mosi; + + o_UART0_TX <= uart0_tx_esp; + + o_RGB <= rgb_out_o; + o_RGB_CS_n <= rgb_csync_n_o; + o_RGB_VS_n <= rgb_vsync_n_o; + o_RGB_HS_n <= rgb_hsync_n_o; + o_RGB_VB_n <= rgb_vblank_n_o; + o_RGB_HB_n <= rgb_hblank_n_o; + + o_VIDEO_50_60 <= eff_nr_05_5060; + o_VIDEO_SCANLINES <= eff_nr_09_scanlines; + o_VIDEO_SCANDOUBLE <= eff_nr_05_scandouble_en; + + o_VIDEO_MODE <= nr_11_video_timing; + o_MACHINE_TIMING <= eff_nr_03_machine_timing; + + o_HDMI_RESET <= video_timing_change_d; + + o_AUDIO_HDMI_AUDIO_EN <= not nr_09_hdmi_audio_disable; + + o_AUDIO_SPEAKER_EN <= nr_08_internal_speaker_en; + o_AUDIO_SPEAKER_BEEP <= internal_speaker_beep_exclusive; + + o_AUDIO_MIC <= port_fe_mic xor pi_fe_ear; + + o_AUDIO_SPEAKER_EAR <= port_fe_ear; + o_AUDIO_SPEAKER_MIC <= port_fe_mic_final; + + o_AUDIO_L <= pcm_audio_L; + o_AUDIO_R <= pcm_audio_R; + + o_RAM_A_ADDR <= sram_addr; + o_RAM_A_REQ <= sram_req_t; + o_RAM_A_RD_n <= sram_rd_n; + o_RAM_A_DO <= cpu_do; + + o_RAM_B_ADDR <= layer2_addr_eff; + o_RAM_B_REQ_T <= layer2_req_t; + + o_BUS_ADDR <= cpu_a; + o_BUS_DO <= cpu_do; + o_BUS_MREQ_n <= bus_mreq_n; + o_BUS_IORQ_n <= bus_iorq_n; + o_BUS_RD_n <= cpu_rd_n; + o_BUS_WR_n <= cpu_wr_n; + o_BUS_M1_n <= cpu_m1_n; + o_BUS_INT_n <= pulse_int_n; + o_BUS_BUSAK_n <= '1'; + o_BUS_HALT_n <= cpu_halt_n; + o_BUS_RFSH_n <= cpu_rfsh_n; + o_BUS_IEO <= im2_ieo; + + o_BUS_EN <= expbus_eff_en; + o_BUS_CLKEN <= expbus_eff_clken; + + o_BUS_NMI_DEBOUNCE_DISABLE <= nr_81_expbus_nmi_debounce_disable; + + o_ESP_GPIO_0 <= nr_a9_esp_gpio0; + o_ESP_GPIO_0_EN <= nr_a8_esp_gpio0_en; + + o_GPIO <= pi_gpio_o(27 downto 22) & gpio_21 & gpio_20 & gpio_19 & gpio_18 & gpio_17 & gpio_16 & gpio_15 & gpio_14 & pi_gpio_o(13 downto 12) & gpio_11 & gpio_10 & pi_gpio_o(9) & gpio_08 & gpio_07 & pi_gpio_o(6 downto 4) & gpio_03 & gpio_02 & pi_gpio_o(1 downto 0); + o_GPIO_EN <= pi_gpio_en(27 downto 22) & gpio_21_en & gpio_20_en & gpio_19_en & gpio_18_en & gpio_17_en & gpio_16_en & gpio_15_en & gpio_14_en & pi_gpio_en(13 downto 12) & gpio_11_en & gpio_10_en & gpio_09_en & gpio_08_en & gpio_07_en & pi_gpio_en(6 downto 4) & gpio_03_en & gpio_02_en & pi_gpio_en(1 downto 0); + + ------------------------------------------------------------ + -- RESET --------------------------------------------------- + ------------------------------------------------------------ + + -- incoming reset signals are asserted for some time by the top level module + + reset <= i_RESET; + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if nr_02_soft_reset = '1' then + nr_02_reset_type <= '0' & nr_02_reset_type(2) & (nr_02_reset_type(1) or nr_02_reset_type(0)); + end if; + end if; + end process; + + ------------------------------------------------------------ + -- Z80 & DMA ----------------------------------------------- + ------------------------------------------------------------ + + cpu_mod: entity work.T80na + generic map ( + Mode => 0 + ) + port map ( + RESET_n => not reset, -- in + CLK_n => i_CLK_CPU, -- in + WAIT_n => z80_wait_n, -- in + INT_n => z80_int_n, -- in + NMI_n => z80_nmi_n, -- in (detection is on rising edge of cpu clock) + BUSRQ_n => z80_busrq_n, -- in + M1_n => z80_m1_n, -- out + MREQ_n => z80_mreq_n, -- out + IORQ_n => z80_iorq_n, -- out + RD_n => z80_rd_n, -- out + WR_n => z80_wr_n, -- out + RFSH_n => z80_rfsh_n, -- out + HALT_n => z80_halt_n, -- out + BUSAK_n => z80_busak_n, -- out + A => z80_a, -- out + D_i => cpu_di, -- in + D_o => z80_do, -- out + -- extended functions + Z80N_dout_o => Z80N_dout_s, + Z80N_data_o => Z80N_data_s, + Z80N_command_o => Z80N_command_s + ); + + dma_mod: entity work.z80dma + port map ( + reset_i => reset, + clk_i => i_CLK_CPU, + turbo_i => cpu_speed, + dma_mode_i => dma_mode, -- 0 = zxn dma, 1 = z80 dma + + dma_en_wr_s => port_dma_wr, -- allow dma to program itself? ans: no + dma_en_rd_s => port_dma_rd, + + cpu_d_i => z80_do, + wait_n_i => dma_wait_n, + dma_delay_i => im2_dma_delay, + + bus_busreq_n_i => '1', -- busreq in daisy chain (i_BUS_BUSREQ_n) + cpu_busreq_n_o => dma_busrq_n, -- busreq out + + cpu_bai_n => z80_busak_n, -- busak in daisy chain + cpu_bao_n => open, -- busak out daisy chain + + dma_a_o => dma_a, + dma_d_o => dma_do, + dma_d_i => cpu_di, + dma_rd_n_o => dma_rd_n, + dma_wr_n_o => dma_wr_n, + dma_mreq_n_o => dma_mreq_n, + dma_iorq_n_o => dma_iorq_n, + + cpu_d_o => port_dma_dat_0 + ); + + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + port_dma_dat <= port_dma_dat_0; + end if; + end process; + + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + if reset = '1' then + dma_mode <= '0'; + elsif port_dma_rd = '1' or port_dma_wr = '1' then + dma_mode <= port_0b_lsb; + end if; + end if; + end process; + + -- no dma controller on the expansion bus at this time + +-- dma_holds_bus <= '1' when dma_busrq_n = '0' and z80_busak_n = '0' else '0'; + dma_holds_bus <= '1' when z80_busak_n = '0' else '0'; + + cpu_m1_n <= '1' when dma_holds_bus = '1' else z80_m1_n; + cpu_mreq_n <= dma_mreq_n when dma_holds_bus = '1' else (z80_mreq_n or z80_stackless_nmi); + cpu_iorq_n <= dma_iorq_n when dma_holds_bus = '1' else z80_iorq_n; + cpu_rd_n <= dma_rd_n when dma_holds_bus = '1' else z80_rd_n; + cpu_wr_n <= dma_wr_n when dma_holds_bus = '1' else z80_wr_n; + cpu_rfsh_n <= '1' when dma_holds_bus = '1' else z80_rfsh_n; + cpu_halt_n <= '1' when dma_holds_bus = '1' else z80_halt_n; + cpu_a <= dma_a when dma_holds_bus = '1' else z80_a; + cpu_do <= dma_do when dma_holds_bus = '1' else z80_do; + + expbus_disable_int <= '1' when expbus_eff_en = '0' or expbus_eff_disable_io = '1' or im2_ieo = '0' or nr_c4_int_en_0_expbus = '0' else '0'; + + z80_wait_n <= '0' when (ula_wait_n = '0') or (ulap_wait_n = '0') or (sram_wait_n = '0') or (i_BUS_WAIT_n = '0' and expbus_eff_en = '1') or (i_RAM_A_WAIT = '1') else '1'; + z80_int_n <= (pulse_int_n or not expbus_disable_int) and im2_int_n and (i_BUS_INT_n or expbus_disable_int); + z80_nmi_n <= nmi_generate_n; + z80_busrq_n <= dma_busrq_n; + + dma_wait_n <= z80_wait_n and spi_wait_n; + + process (z80_stackless_nmi, dma_holds_bus, z80_retn_address, cpu_mreq_n, cpu_rfsh_n, cpu_a, bootrom_en, bootrom_do, im2_ieo, + sram_romcs_en, sram_pre_romcs_replace, i_BUS_DI, sram_bank5, cpu_bank5_do, sram_bank7, cpu_bank7_do, i_RAM_A_DI, cpu_m1_n, + cpu_iorq_n, port_internal_rd_response, bus_iorq_ula, port_rd_dat, im2_vector, expbus_eff_en, expbus_eff_disable_io) + begin + if z80_stackless_nmi = '1' and dma_holds_bus = '0' then + + cpu_di <= z80_retn_address; + + elsif cpu_mreq_n = '0' and cpu_rfsh_n = '1' then + + if cpu_a(15 downto 14) = "00" and bootrom_en = '1' then + cpu_di <= bootrom_do; + elsif sram_romcs_en = '1' and sram_pre_romcs_replace = '0' then + cpu_di <= i_BUS_DI; + elsif sram_bank5 = '1' then + cpu_di <= cpu_bank5_do; + elsif sram_bank7 = '1' then + cpu_di <= cpu_bank7_do; + else + cpu_di <= i_RAM_A_DI; + end if; + + elsif cpu_iorq_n = '0' then + + if cpu_m1_n = '0' and im2_ieo = '0' then + cpu_di <= im2_vector; + elsif port_internal_rd_response = '1' and bus_iorq_ula = '0' then + cpu_di <= port_rd_dat; + elsif expbus_eff_en = '1' and expbus_eff_disable_io = '0' then + cpu_di <= i_BUS_DI; + else + cpu_di <= X"FF"; + end if; + + else + cpu_di <= X"FF"; + end if; + end process; + + -- + -- maskable interrupts + -- + + -- reti/retn decoder + + im2ctl_mod: entity work.im2_control + port map ( + i_CLK_CPU => i_CLK_CPU, + i_reset => reset, + + i_m1_n => cpu_m1_n, + i_mreq_n => cpu_mreq_n, + i_iorq_n => cpu_iorq_n, + + i_rd_n => cpu_rd_n, + i_wr_n => cpu_wr_n, + + i_cpu_d => cpu_di, + + o_reti_decode => im2_reti_decode, + o_reti_seen => z80_reti_seen_t3, + + o_retn_seen => z80_retn_seen_t3, + + o_dma_delay => dma_delay + ); + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + z80_retn_seen_28_d <= '0'; + else + z80_retn_seen_28_d <= z80_retn_seen_t3; + end if; + end if; + end process; + + z80_retn_seen_28 <= z80_retn_seen_t3 and not z80_retn_seen_28_d; + + -- peripheral interrupt handlers + + -- priority order is bit 0 (highest) to bit 13 (lowest) + -- priority number also corresponds to interrupt vector + -- + -- 0 = line + -- 1 = uart0 rx + -- 2 = uart1 rx + -- 3:10 = ctc 0-7 + -- 11 = ula + -- 12 = uart0 tx + -- 13 = uart1 tx + + im2_int_req <= uart1_tx_empty & uart0_tx_empty & ula_int_pulse & ctc_zc_to & + (uart1_rx_near_full or (uart1_rx_avail and not nr_c6_int_en_2_654(1))) & + (uart0_rx_near_full or (uart0_rx_avail and not nr_c6_int_en_2_210(1))) & + line_int_pulse; + + im2_int_en <= nr_c6_int_en_2_654(2) & nr_c6_int_en_2_210(2) & ula_int_en(0) & ctc_int_en & + (nr_c6_int_en_2_654(1) or nr_c6_int_en_2_654(0)) & (nr_c6_int_en_2_210(1) or nr_c6_int_en_2_210(0)) & ula_int_en(1); + + im2_status_clear <= (nr_ca_we and nr_wr_dat(6)) & (nr_ca_we and nr_wr_dat(2)) & (nr_c8_we and nr_wr_dat(0)) & + ((nr_c9_we & nr_c9_we & nr_c9_we & nr_c9_we & nr_c9_we & nr_c9_we & nr_c9_we & nr_c9_we) and nr_wr_dat) & + (nr_ca_we and (nr_wr_dat(5) or nr_wr_dat(4))) & (nr_ca_we and (nr_wr_dat(1) or nr_wr_dat(0))) & + (nr_c8_we and nr_wr_dat(1)); + + im2_dma_int_en <= nr_ce_dma_int_en_2_654(2) & nr_ce_dma_int_en_2_210(2) & nr_cc_dma_int_en_0_10(0) & nr_cd_dma_int_en_1 & + (nr_ce_dma_int_en_2_654(1) or nr_ce_dma_int_en_2_654(0)) & (nr_ce_dma_int_en_2_210(1) or nr_ce_dma_int_en_2_210(0)) & nr_cc_dma_int_en_0_10(1); + + im2per_mod: entity work.peripherals + generic map ( + NUM_PERIPH => 14, + VEC_BITS => 4 + ) + port map ( + i_CLK_28 => i_CLK_28, + i_CLK_CPU => i_CLK_CPU, + i_reset => reset, + + i_m1_n => cpu_m1_n, + i_iorq_n => cpu_iorq_n, + + i_mode_pulse_0_im2_1 => nr_c0_int_mode_pulse_0_im2_1, + + i_int_req => im2_int_req, + i_int_en => im2_int_en, + + o_int_status => im2_int_status, -- CLK_28 + i_int_status_clear => im2_status_clear, -- CLK_28 + + i_iei => '1', + o_ieo => im2_ieo, + + i_reti_decode => im2_reti_decode, + i_reti_seen => z80_reti_seen_t3, + + o_int_n => im2_int_n, + o_vector => im2_vec, + + i_dma_int_en => im2_dma_int_en, + o_dma_int => im2_dma_int, + + o_pulse_en => pulse_int_en + ); + + im2_vector <= nr_c0_im2_vector & im2_vec & '0'; + + process (i_CLK_CPU) + begin + if rising_edge(i_CLK_CPU) then + if reset = '1' then + im2_dma_delay <= '0'; + elsif dma_delay = '0' then -- tested in reti SRL_T3 + im2_dma_delay <= im2_dma_int and nr_c0_int_mode_pulse_0_im2_1; + end if; + end if; + end process; + + -- pulsed interrupt + -- duration is fixed at ~32 cpu cycles and must be asserted immediately + + process (i_CLK_28) + begin + -- int is sampled on rising edge of cpu clock + if falling_edge(i_CLK_28) then + if reset = '1' then + pulse_int_n <= '1'; + elsif pulse_int_n = '1' then + if pulse_int_en = '1' and nr_c0_int_mode_pulse_0_im2_1 = '0' then + pulse_int_n <= '0'; + end if; + elsif pulse_count_end = '1' then + pulse_int_n <= '1'; + end if; + end if; + end process; + + pulse_count_end <= '1' when pulse_count = "11111" else '0'; + + process (i_CLK_CPU) + begin + if rising_edge(i_CLK_CPU) then + if pulse_int_n = '1' then + pulse_count <= (others => '0'); + elsif pulse_count_end = '0' then + pulse_count <= pulse_count + 1; + end if; + end if; + end process; + + -- + -- nmi + -- + + -- stackless nmi response + + z80_stackless_nmi <= '1' when (nr_c0_stackless_nmi = '1' and (Z80N_command_s = NMIACK_LSB or Z80N_command_s = NMIACK_MSB)) or (z80_stackless_retn_en = '1' and (Z80N_command_s = RETN_LSB or Z80N_command_s = RETN_MSB)) else '0'; + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + nr_c2_retn_address_lsb <= (others => '0'); + nr_c3_retn_address_msb <= (others => '0'); + elsif (Z80N_command_s = NMIACK_LSB) and cpu_wr_n = '0' then + nr_c2_retn_address_lsb <= cpu_do; + elsif (Z80N_command_s = NMIACK_MSB) and cpu_wr_n = '0' then + nr_c3_retn_address_msb <= cpu_do; + elsif nr_c2_we = '1' then + nr_c2_retn_address_lsb <= nr_wr_dat; + elsif nr_c3_we = '1' then + nr_c3_retn_address_msb <= nr_wr_dat; + end if; + end if; + end process; + + process (i_CLK_CPU) + begin + if rising_edge(i_CLK_CPU) then + if reset = '1' or nr_c0_stackless_nmi = '0' then + z80_stackless_retn_en <= '0'; + elsif Z80N_command_s = NMIACK_LSB then + z80_stackless_retn_en <= '1'; + elsif Z80N_command_s = RETN_MSB and cpu_rd_n = '1' then + z80_stackless_retn_en <= '0'; + end if; + end if; + end process; + + z80_retn_address <= nr_c2_retn_address_lsb when Z80N_command_s = RETN_LSB else nr_c3_retn_address_msb; + + -- first come first serve + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + nmi_expbus_en <= '1'; + elsif nmi_expbus = '1' then + nmi_expbus_en <= '0'; + elsif i_BUS_NMI_n = '1' then + nmi_expbus_en <= '1'; + end if; + end if; + end process; + + nmi_assert_expbus <= '1' when expbus_eff_en = '1' and expbus_eff_disable_mem = '0' and i_BUS_NMI_n = '0' else '0'; + + nmi_activated <= nmi_mf or nmi_divmmc or nmi_expbus; + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' or nmi_state = S_NMI_END or nr_03_config_mode = '1' then + nmi_mf <= '0'; + nmi_divmmc <= '0'; + nmi_expbus <= '0'; + elsif nmi_activated = '0' then + if hotkey_m1 = '1' and nr_06_button_m1_nmi_en = '1' and port_e3_reg(7) = '0' and divmmc_nmi_hold = '0' then + nmi_mf <= '1'; + elsif hotkey_drive = '1' and nr_06_button_drive_nmi_en = '1' and mf_is_active = '0' then + nmi_divmmc <= '1'; + elsif nmi_expbus_en = '1' and nmi_assert_expbus = '1' then + nmi_expbus <= '1'; + end if; + end if; + end if; + end process; + + nmi_hold <= mf_nmi_hold when nmi_mf = '1' else divmmc_nmi_hold when nmi_divmmc = '1' else nmi_assert_expbus; + + -- nmi state machine + + nmi_holding <= '1' when nmi_hold = '1' or dma_holds_bus = '1' else '0'; + nmi_opus <= '1' when nmi_mf = '1' and nr_81_expbus_nmi_debounce_disable = '1' and nmi_assert_expbus = '1' else '0'; + + process (nmi_state, nmi_activated, nmi_holding, nmi_opus) + begin + case nmi_state is + when S_NMI_IDLE => + if nmi_activated = '1' then + nmi_state_next <= S_NMI_ASSERT; + else + nmi_state_next <= S_NMI_IDLE; + end if; + when S_NMI_ASSERT => + nmi_state_next <= S_NMI_HOLD; + when S_NMI_OPUS => -- separate to avoid button activation in multiface + if nmi_opus = '1' then + nmi_state_next <= S_NMI_OPUS; + else + nmi_state_next <= S_NMI_HOLD; + end if; + when S_NMI_HOLD => + if nmi_holding = '0' then + nmi_state_next <= S_NMI_END; + elsif nmi_opus = '1' then -- multiface + opus discovery + nmi_state_next <= S_NMI_OPUS; + else + nmi_state_next <= S_NMI_HOLD; + end if; +-- when S_NMI_END => +-- nmi_state_next <= S_NMI_IDLE; + when others => + nmi_state_next <= S_NMI_IDLE; + end case; + end process; + + process (i_CLK_CPU) + begin + if rising_edge(i_CLK_CPU) then + if reset = '1' or nr_03_config_mode = '1' then + nmi_state <= S_NMI_IDLE; + else + nmi_state <= nmi_state_next; + end if; + end if; + end process; + + nmi_generate_n <= '0' when nmi_state = S_NMI_ASSERT or (nmi_state = S_NMI_OPUS and nmi_assert_expbus = '1') else '1'; + nmi_mf_button <= '1' when nmi_mf = '1' and nmi_state = S_NMI_ASSERT else '0'; + nmi_divmmc_button <= '1' when nmi_divmmc = '1' and nmi_state = S_NMI_ASSERT else '0'; + + ------------------------------------------------------------ + -- EXPANSION BUS ------------------------------------------- + ------------------------------------------------------------ + + -- + -- expansion bus control (changed during iowr to port 253b or nextreg instruction) + -- + + hotkey_expbus_freeze <= '1' when (port_divmmc_io_en_diff = '1' and divmmc_automap_held = '1') or (port_multiface_io_en_diff = '1' and mf_mem_en = '1') else '0'; + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + nr_80_expbus(7 downto 4) <= nr_80_expbus(3 downto 0); + elsif nr_80_we = '1' then + nr_80_expbus <= nr_wr_dat; + elsif hotkey_expbus_enable = '1' and hotkey_expbus_freeze = '0' then + nr_80_expbus(7) <= '1'; + elsif hotkey_expbus_disable = '1' and hotkey_expbus_freeze = '0' then + nr_80_expbus(7) <= '0'; + end if; + end if; + end process; + + expbus_en <= nr_80_expbus(7); + expbus_romcs_replace <= nr_80_expbus(6); + expbus_disable_io <= nr_80_expbus(5); + expbus_disable_mem <= nr_80_expbus(4); + + expbus_clken <= nr_81_expbus_clken; + expbus_speed <= nr_81_expbus_speed; + + -- + -- expansion bus connection + -- + + -- filter io cycles + -- external devices should see port fe, memory paging + + port_propagate_fe <= port_fe and nr_8a_bus_port_propagate(0); + port_propagate_7ffd <= port_7ffd and nr_8a_bus_port_propagate(1); + port_propagate_dffd <= port_dffd and nr_8a_bus_port_propagate(2); + port_propagate_1ffd <= port_1ffd and nr_8a_bus_port_propagate(3); + port_propagate_ff <= port_ff and nr_8a_bus_port_propagate(4); + port_propagate_eff7 <= port_eff7 and nr_8a_bus_port_propagate(5); + + port_propagate <= port_propagate_fe or port_propagate_7ffd or port_propagate_dffd or port_propagate_1ffd or port_propagate_ff or port_propagate_eff7; + + bus_iorq_n <= cpu_iorq_n or (cpu_m1_n and ((port_internal_response or expbus_eff_disable_io) and not port_propagate)); + bus_mreq_n <= cpu_mreq_n or (cpu_rfsh_n and (expbus_eff_disable_mem or ((not cpu_a(15)) and (not cpu_a(14)) and not sram_pre_override(0)))); -- layer 2 / divmmc cannot be hidden + +-- o_BUS_ADDR <= cpu_a; +-- o_BUS_DO <= cpu_do; +-- o_BUS_MREQ_n <= bus_mreq_n; +-- o_BUS_IORQ_n <= bus_iorq_n; +-- o_BUS_RD_n <= cpu_rd_n; +-- o_BUS_WR_n <= cpu_wr_n; +-- o_BUS_M1_n <= cpu_m1_n; +-- o_BUS_INT_n <= pulse_int_n; +-- o_BUS_BUSAK_n <= '1'; +-- o_BUS_HALT_n <= cpu_halt_n; +-- o_BUS_RFSH_n <= cpu_rfsh_n; + + ------------------------------------------------------------ + -- ALTERNATE ROM ------------------------------------------- + ------------------------------------------------------------ + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + nr_8c_altrom(7 downto 4) <= nr_8c_altrom(3 downto 0); + elsif nr_8c_we = '1' then + nr_8c_altrom <= nr_wr_dat; + end if; + end if; + end process; + + nr_8c_altrom_en <= nr_8c_altrom(7); + nr_8c_altrom_rw <= nr_8c_altrom(6); + nr_8c_altrom_lock_rom1 <= nr_8c_altrom(5); + nr_8c_altrom_lock_rom0 <= nr_8c_altrom(4); + + ------------------------------------------------------------ + -- PI GPIO ------------------------------------------------- + ------------------------------------------------------------ + + -- https://elinux.org/RPi_BCM2835_GPIOs + + -- todo: video in, video out, memory mapping, z80 bus + + pi_gpio_en <= nr_93_pi_gpio_o_en & nr_92_pi_gpio_o_en & nr_91_pi_gpio_o_en & nr_90_pi_gpio_o_en; + pi_gpio_o <= nr_9b_pi_gpio_o & nr_9a_pi_gpio_o & nr_99_pi_gpio_o & nr_98_pi_gpio_o; + + pi_uart_rxtx <= nr_a0_pi_peripheral_en(5); + pi_uart_en <= nr_a0_pi_peripheral_en(4); + pi_i2c1_en <= nr_a0_pi_peripheral_en(3); + pi_spi0_en <= nr_a0_pi_peripheral_en(0); + + pi_i2s_en <= nr_a2_pi_i2s_ctl(7) or nr_a2_pi_i2s_ctl(6); + pi_i2s_enL <= nr_a2_pi_i2s_ctl(7); + pi_i2s_enR <= nr_a2_pi_i2s_ctl(6); + pi_i2s_inout <= nr_a2_pi_i2s_ctl(4); + pi_i2s_muteL <= nr_a2_pi_i2s_ctl(3); + pi_i2s_muteR <= nr_a2_pi_i2s_ctl(2); +-- pi_i2s_slave <= nr_a2_pi_i2s_ctl(1); + pi_i2s_ear <= nr_a2_pi_i2s_ctl(0); + + -- spi0 7,8,9,10,11 + + gpio_08_en <= '1' when pi_spi0_en = '1' else pi_gpio_en(8); + gpio_08 <= spi_ss_rpi0_n when pi_spi0_en = '1' else pi_gpio_o(8); + + gpio_07_en <= '1' when pi_spi0_en = '1' else pi_gpio_en(7); + gpio_07 <= spi_ss_rpi1_n when pi_spi0_en = '1' else pi_gpio_o(7); + + gpio_09_en <= '0' when pi_spi0_en = '1' else pi_gpio_en(9); + pi_spi0_miso <= i_GPIO(9) when pi_spi0_en = '1' else '1'; + + gpio_10_en <= '1' when pi_spi0_en = '1' else pi_gpio_en(10); + gpio_10 <= spi_mosi when pi_spi0_en = '1' else pi_gpio_o(10); + + gpio_11_en <= '1' when pi_spi0_en = '1' else pi_gpio_en(11); + gpio_11 <= spi_sck when pi_spi0_en = '1' else pi_gpio_o(11); + + -- i2c1 2,3 + + gpio_02_en <= not i2c_sda_o when pi_i2c1_en = '1' else pi_gpio_en(2); + gpio_02 <= '0' when pi_i2c1_en = '1' else pi_gpio_o(2); + + gpio_03_en <= not i2c_scl_o when pi_i2c1_en = '1' else pi_gpio_en(3); + gpio_03 <= '0' when pi_i2c1_en = '1' else pi_gpio_o(3); + + pi_i2c1_sda <= i_GPIO(2) when pi_i2c1_en = '1' else '1'; + pi_i2c1_scl <= i_GPIO(3) when pi_i2c1_en = '1' else '1'; + + -- uart 14,15(,16,17) (need to cross wires for pi!) + -- connect Rx to GPIO14 if pi_uart_rxtx = 1 + + gpio_14_en <= not pi_uart_rxtx when pi_uart_en = '1' else pi_gpio_en(14); + gpio_15_en <= pi_uart_rxtx when pi_uart_en = '1' else pi_gpio_en(15); + gpio_16_en <= pi_uart_rxtx when pi_uart_en = '1' and uart1_hwflow_en = '1' else pi_gpio_en(16); + gpio_17_en <= not pi_uart_rxtx when pi_uart_en = '1' and uart1_hwflow_en = '1' else pi_gpio_en(17); + + gpio_14 <= uart1_tx_pi when pi_uart_en = '1' else pi_gpio_o(14); + gpio_15 <= uart1_tx_pi when pi_uart_en = '1' else pi_gpio_o(15); + gpio_16 <= pi_uart_rtr_n when pi_uart_en = '1' and uart1_hwflow_en = '1' else pi_gpio_o(16); + gpio_17 <= pi_uart_rtr_n when pi_uart_en = '1' and uart1_hwflow_en = '1' else pi_gpio_o(17); + + pi_uart_rx <= (i_GPIO(14) and pi_uart_rxtx) or (i_GPIO(15) and not pi_uart_rxtx) when pi_uart_en = '1' else '1'; + pi_uart_cts_n <= (i_GPIO(17) and pi_uart_rxtx) or (i_GPIO(16) and not pi_uart_rxtx) when pi_uart_en = '1' and uart1_hwflow_en = '1' else '0'; + + -- i2s 18,19,20,21 + +-- gpio_18_en <= '1' when pi_i2s_en = '1' and pi_i2s_slave = '0' else '0' when pi_i2s_en = '1' and pi_i2s_slave = '1' else pi_gpio_en(18); +-- gpio_19_en <= '1' when pi_i2s_en = '1' and pi_i2s_slave = '0' else '0' when pi_i2s_en = '1' and pi_i2s_slave = '1' else pi_gpio_en(19); + gpio_18_en <= '0' when pi_i2s_en = '1' else pi_gpio_en(18); + gpio_19_en <= '0' when pi_i2s_en = '1' else pi_gpio_en(19); + gpio_20_en <= pi_i2s_inout when pi_i2s_en = '1' else pi_gpio_en(20); + gpio_21_en <= not pi_i2s_inout when pi_i2s_en = '1' else pi_gpio_en(21); + + gpio_18 <= pi_mi2s_sck when pi_i2s_en = '1' else pi_gpio_o(18); + gpio_19 <= pi_mi2s_ws when pi_i2s_en = '1' else pi_gpio_o(19); + gpio_20 <= pi_i2s_sd_o when pi_i2s_en = '1' else pi_gpio_o(20); + gpio_21 <= pi_i2s_sd_o when pi_i2s_en = '1' else pi_gpio_o(21); + + pi_i2s_sd_i <= ((i_GPIO(21) and pi_i2s_inout) or (i_GPIO(20) and not pi_i2s_inout)) and pi_i2s_en; + +-- pi_si2s_sck <= i_GPIO(18) and pi_i2s_en and pi_i2s_slave; +-- pi_si2s_ws <= i_GPIO(19) and pi_i2s_en and pi_i2s_slave; + + pi_si2s_sck <= i_GPIO(18) and pi_i2s_en; + pi_si2s_ws <= i_GPIO(19) and pi_i2s_en; + + pi_audio_L <= ("10" & X"00") when (pi_i2s_en = '0' or pi_i2s_muteL = '1' or pi_i2s_ear = '1') else pi_i2s_audio_L when pi_i2s_enL = '1' else pi_i2s_audio_R; + pi_audio_R <= ("10" & X"00") when (pi_i2s_en = '0' or pi_i2s_muteR = '1' or pi_i2s_ear = '1') else pi_i2s_audio_R when pi_i2s_enR = '1' else pi_i2s_audio_L; + + pi_fe_threshold <= pi_i2s_audio_L(9 downto 8) or pi_i2s_audio_R(9 downto 8); + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if pi_i2s_en = '0' or pi_i2s_ear = '0' then + pi_fe_ear <= '0'; + elsif pi_fe_ear = '1' and pi_fe_threshold = "00" then + pi_fe_ear <= '0'; + elsif pi_fe_ear = '0' and pi_fe_threshold = "11" then + pi_fe_ear <= '1'; + end if; + end if; + end process; + + -- + -- pi gpio output + -- + +-- o_GPIO <= ... +-- o_GPIO_EN <= ... + + + ------------------------------------------------------------ + -- PORT DECODING ------------------------------------------- + ------------------------------------------------------------ + + -- todo: investigate switching to pentagon method where decoding depends on instruction type "IN A,(n)" vs "IN r,(C)" + + -- + -- active port enables (changed during iowr to port 253b or nextreg instruction) + -- + + internal_port_enable <= (nr_85_internal_port_enable & nr_84_internal_port_enable & nr_83_internal_port_enable & nr_82_internal_port_enable) when expbus_eff_en = '0' else + ((nr_89_bus_port_enable and nr_85_internal_port_enable) & (nr_88_bus_port_enable and nr_84_internal_port_enable) & (nr_87_bus_port_enable and nr_83_internal_port_enable) & (nr_86_bus_port_enable and nr_82_internal_port_enable)); + + -- + + port_ff_io_en <= internal_port_enable(0); + + port_7ffd_io_en <= internal_port_enable(1); + port_dffd_io_en <= internal_port_enable(2); + port_1ffd_io_en <= internal_port_enable(3); + + port_p3_floating_bus_io_en <= internal_port_enable(4); + + port_dma_6b_io_en <= internal_port_enable(5); + + port_1f_io_en <= internal_port_enable(6); + port_37_io_en <= internal_port_enable(7); + + -- + + port_divmmc_io_en <= internal_port_enable(8); + port_divmmc_io_en_diff <= nr_83_internal_port_enable(0) xor nr_87_bus_port_enable(0); + + port_multiface_io_en <= internal_port_enable(9); + port_multiface_io_en_diff <= nr_83_internal_port_enable(1) xor nr_87_bus_port_enable(1); + + port_i2c_io_en <= internal_port_enable(10); + port_spi_io_en <= internal_port_enable(11); + port_uart_io_en <= internal_port_enable(12); + + port_mouse_io_en <= internal_port_enable(13); + port_sprite_io_en <= internal_port_enable(14); + port_layer2_io_en <= internal_port_enable(15); + + -- + + port_ay_io_en <= internal_port_enable(16); + port_dac_sd1_ABCD_1f0f4f5f_io_en <= internal_port_enable(17); -- soundrive mode 1 + port_dac_sd2_ABCD_f1f3f9fb_io_en <= internal_port_enable(18); -- soundrive mode 2 + port_dac_stereo_AD_3f5f_io_en <= internal_port_enable(19); -- profi covox + port_dac_stereo_BC_0f4f_io_en <= internal_port_enable(20); -- covox + port_dac_mono_AD_fb_io_en <= internal_port_enable(21) and not port_dac_sd2_ABCD_f1f3f9fb_io_en; -- pentagon / atm (when mode 2 is off) + port_dac_mono_BC_b3_io_en <= internal_port_enable(22); -- gs covox + port_dac_mono_AD_df_io_en <= internal_port_enable(23); -- specdrum + + -- + + port_ulap_io_en <= internal_port_enable(24); + port_dma_0b_io_en <= internal_port_enable(25); + port_eff7_io_en <= internal_port_enable(26); + port_ctc_io_en <= internal_port_enable(27); + + -- + -- peripheral disable + -- do not alter port decoding during an io cycle (nextreg changes can occur at any time) + -- + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if cpu_mreq_n = '0' then + + port_1f_hw_en <= joyL_1f_en or joyR_1f_en; + port_37_hw_en <= joyL_37_en or joyR_37_en; + + p3_timing_hw_en <= machine_timing_p3; + s128_timing_hw_en <= machine_timing_128; + + dac_hw_en <= nr_08_dac_en; + + end if; + end if; + end process; + + bus_iorq_ula <= expbus_eff_en and i_BUS_IORQULA_n and port_fe and cpu_m1_n and not expbus_eff_disable_io; + + -- + -- early decode of port addresses to allow filtering of io cycles to expansion bus + -- + + process (cpu_a(15 downto 8)) + begin + + port_00xx_msb <= '0'; + port_04xx_msb <= '0'; + port_05xx_msb <= '0'; + port_10xx_msb <= '0'; + port_11xx_msb <= '0'; + port_12xx_msb <= '0'; + port_1fxx_msb <= '0'; + port_24xx_msb <= '0'; + port_25xx_msb <= '0'; + port_30xx_msb <= '0'; + port_3dxx_msb <= '0'; + port_bfxx_msb <= '0'; + port_fexx_msb <= '0'; + port_ffxx_msb <= '0'; + + case cpu_a(15 downto 8) is + + when X"00" => port_00xx_msb <= '1'; + when X"04" => port_04xx_msb <= '1'; + when X"05" => port_05xx_msb <= '1'; + when X"10" => port_10xx_msb <= '1'; + when X"11" => port_11xx_msb <= '1'; + when X"12" => port_12xx_msb <= '1'; + when X"1F" => port_1fxx_msb <= '1'; + when X"24" => port_24xx_msb <= '1'; + when X"25" => port_25xx_msb <= '1'; + when X"30" => port_30xx_msb <= '1'; + when X"3D" => port_3dxx_msb <= '1'; + when X"BF" => port_bfxx_msb <= '1'; + when X"FE" => port_fexx_msb <= '1'; + when X"FF" => port_ffxx_msb <= '1'; + when others => null; + + end case; + + end process; + + process (cpu_a(7 downto 0)) + begin + + port_00_lsb <= '0'; + port_08_lsb <= '0'; + port_0b_lsb <= '0'; + port_0f_lsb <= '0'; + port_1f_lsb <= '0'; + port_37_lsb <= '0'; + port_38_lsb <= '0'; + port_3f_lsb <= '0'; + port_3b_lsb <= '0'; + port_4f_lsb <= '0'; + port_57_lsb <= '0'; + port_5b_lsb <= '0'; + port_5f_lsb <= '0'; + port_62_lsb <= '0'; + port_66_lsb <= '0'; + port_6a_lsb <= '0'; + port_6b_lsb <= '0'; + port_b3_lsb <= '0'; + port_c6_lsb <= '0'; + port_d7_lsb <= '0'; + port_df_lsb <= '0'; + port_e3_lsb <= '0'; + port_e7_lsb <= '0'; + port_eb_lsb <= '0'; + port_f1_lsb <= '0'; + port_f3_lsb <= '0'; + port_f7_lsb <= '0'; + port_f9_lsb <= '0'; + port_fb_lsb <= '0'; + port_ff_lsb <= '0'; + + case cpu_a(7 downto 0) is + + when X"00" => port_00_lsb <= '1'; + when X"08" => port_08_lsb <= '1'; + when X"0B" => port_0b_lsb <= '1'; + when X"0F" => port_0f_lsb <= '1'; + when X"1F" => port_1f_lsb <= '1'; + when X"37" => port_37_lsb <= '1'; + when X"38" => port_38_lsb <= '1'; + when X"3F" => port_3f_lsb <= '1'; + when X"4F" => port_4f_lsb <= '1'; + when X"57" => port_57_lsb <= '1'; + when X"5B" => port_5b_lsb <= '1'; + when X"5F" => port_5f_lsb <= '1'; + when X"3B" => port_3b_lsb <= '1'; + when X"62" => port_62_lsb <= '1'; + when X"66" => port_66_lsb <= '1'; + when X"6A" => port_6a_lsb <= '1'; + when X"6B" => port_6b_lsb <= '1'; + when X"B3" => port_b3_lsb <= '1'; + when X"C6" => port_c6_lsb <= '1'; + when X"D7" => port_d7_lsb <= '1'; + when X"DF" => port_df_lsb <= '1'; + when X"E3" => port_e3_lsb <= '1'; + when X"E7" => port_e7_lsb <= '1'; + when X"EB" => port_eb_lsb <= '1'; + when X"F1" => port_f1_lsb <= '1'; + when X"F3" => port_f3_lsb <= '1'; + when X"F7" => port_f7_lsb <= '1'; + when X"F9" => port_f9_lsb <= '1'; + when X"FB" => port_fb_lsb <= '1'; + when X"FF" => port_ff_lsb <= '1'; + when others => null; + + end case; + + end process; + + port_fd <= '1' when cpu_a(1 downto 0) = "01" else '0'; + + -- ula/scld + + port_fe <= '1' when cpu_a(0) = '0' else '0'; + port_ff <= '1' when port_ff_lsb = '1' else '0'; + + port_fe_override <= '1' when cpu_a(7 downto 4) = "0000" and nr_81_expbus_ula_override = '1' else '0'; + + -- +3 floating bus + +-- port_p3_float_active <= '1' when cpu_a(15 downto 12) = "0000" and port_fd = '1' and p3_timing_hw_en = '1' else '0'; +-- port_p3_float <= '1' when port_p3_float_active = '1' and port_p3_floating_bus_io_en = '1' else '0'; + port_p3_float <= '1' when cpu_a(15 downto 12) = "0000" and port_fd = '1' and p3_timing_hw_en = '1' and port_p3_floating_bus_io_en = '1' else '0'; + + -- original spectrum banking + + port_7ffd_assert <= '1' when cpu_a(15) = '0' and (cpu_a(14) = '1' or p3_timing_hw_en = '0') and port_fd = '1' and port_1ffd = '0' else '0'; + port_7ffd_active <= '1' when port_7ffd_assert = '1' and (s128_timing_hw_en = '1' or p3_timing_hw_en = '1') else '0'; + port_7ffd <= '1' when port_7ffd_assert = '1' and port_7ffd_io_en = '1' else '0'; + + port_dffd <= '1' when cpu_a(15 downto 12) = "1101" and port_fd = '1' and port_dffd_io_en = '1' else '0'; + + port_1ffd_assert <= '1' when cpu_a(15 downto 12) = "0001" and port_fd = '1' else '0'; +-- port_1ffd_active <= '1' when port_1ffd_assert = '1' and p3_timing_hw_en = '1' else '0'; + port_1ffd <= '1' when port_1ffd_assert = '1' and port_1ffd_io_en = '1' else '0'; + + port_eff7 <= '1' when cpu_a(15 downto 12) = "1110" and port_f7_lsb = '1' and port_eff7_io_en = '1' else '0'; + + -- divmmc control + + port_e3 <= '1' when port_e3_lsb = '1' and port_divmmc_io_en = '1' else '0'; + + -- multiface + + port_mf_enable_io_a <= X"9F" when nr_0a_mf_type(1) = '1' else X"BF" when nr_0a_mf_type(0) = '1' else X"3F"; + port_mf_disable_io_a <= X"1F" when nr_0a_mf_type(1) = '1' else X"3F" when nr_0a_mf_type(0) = '1' else X"BF"; + + port_mf_enable <= '1' when cpu_a(7 downto 0) = port_mf_enable_io_a and port_multiface_io_en = '1' else '0'; + port_mf_disable <= '1' when cpu_a(7 downto 0) = port_mf_disable_io_a and port_multiface_io_en = '1' else '0'; + + -- spi + + port_e7 <= '1' when port_e7_lsb = '1' and port_spi_io_en = '1' else '0'; + port_eb <= '1' when port_eb_lsb = '1' and port_spi_io_en = '1' else '0'; + + -- nextreg + + port_243b <= '1' when port_24xx_msb = '1' and port_3b_lsb = '1' else '0'; + port_253b <= '1' when port_25xx_msb = '1' and port_3b_lsb = '1' else '0'; + + -- i2c + + port_103b <= '1' when port_10xx_msb = '1' and port_3b_lsb = '1' and port_i2c_io_en = '1' else '0'; + port_113b <= '1' when port_11xx_msb = '1' and port_3b_lsb = '1' and port_i2c_io_en = '1' else '0'; + + -- layer 2 + + port_123b <= '1' when port_12xx_msb = '1' and port_3b_lsb = '1' and port_layer2_io_en = '1' else '0'; + + -- uart + + port_uart <= '1' when cpu_a(15 downto 11) = "00010" and (cpu_a(10) xor (cpu_a(9) and cpu_a(8))) = '1' and port_3b_lsb = '1' and port_uart_io_en = '1' else '0'; + + -- dma + + port_dma <= '1' when (port_6b_lsb = '1' and port_dma_6b_io_en = '1') or (port_0b_lsb = '1' and port_dma_0b_io_en = '1') else '0'; + + -- ay + + port_fffd <= '1' when cpu_a(15 downto 14) = "11" and cpu_a(2) = '1' and port_fd = '1' and port_ay_io_en = '1' else '0'; + port_bffd <= '1' when cpu_a(15 downto 14) = "10" and cpu_a(2) = '1' and port_fd = '1' and port_ay_io_en = '1' else '0'; + port_bff5 <= '1' when port_bffd = '1' and cpu_a(3) = '0' else '0'; + + -- audio dac + + -- A - FB DF 1F F1 - 3F + -- B B3 - - 0F F3 0F - + -- C B3 - - 4F F9 4F - + -- D - FB DF 5F FB - 5F + + port_dac_mono_AD <= '1' when (port_fb_lsb = '1' and port_dac_mono_AD_fb_io_en = '1') or (port_df_lsb = '1' and port_dac_mono_AD_df_io_en = '1') else '0'; + port_dac_mono_BC <= '1' when (port_b3_lsb = '1' and port_dac_mono_BC_b3_io_en = '1') else '0'; + + port_dac_A <= '1' when port_dac_mono_AD = '1' or (port_1f_lsb = '1' and port_dac_sd1_ABCD_1f0f4f5f_io_en = '1') or (port_f1_lsb = '1' and port_dac_sd2_ABCD_f1f3f9fb_io_en = '1') or (port_3f_lsb = '1' and port_dac_stereo_AD_3f5f_io_en = '1') else '0'; + port_dac_B <= '1' when port_dac_mono_BC = '1' or (port_0f_lsb = '1' and (port_dac_sd1_ABCD_1f0f4f5f_io_en = '1' or port_dac_stereo_BC_0f4f_io_en = '1')) or (port_f3_lsb = '1' and port_dac_sd2_ABCD_f1f3f9fb_io_en = '1') else '0'; + port_dac_C <= '1' when port_dac_mono_BC = '1' or (port_4f_lsb = '1' and (port_dac_sd1_ABCD_1f0f4f5f_io_en = '1' or port_dac_stereo_BC_0f4f_io_en = '1')) or (port_f9_lsb = '1' and port_dac_sd2_ABCD_f1f3f9fb_io_en = '1') else '0'; + port_dac_D <= '1' when port_dac_mono_AD = '1' or (port_5f_lsb = '1' and (port_dac_sd1_ABCD_1f0f4f5f_io_en = '1' or port_dac_stereo_AD_3f5f_io_en = '1')) or (port_fb_lsb = '1' and port_dac_sd2_ABCD_f1f3f9fb_io_en = '1') else '0'; + + -- kempston mouse + + port_fadf <= '1' when cpu_a(11 downto 8) = X"A" and port_df_lsb = '1' and port_mouse_io_en = '1' else '0'; + port_fbdf <= '1' when cpu_a(11 downto 8) = X"B" and port_df_lsb = '1' and port_mouse_io_en = '1' else '0'; + port_ffdf <= '1' when cpu_a(11 downto 8) = X"F" and port_df_lsb = '1' and port_mouse_io_en = '1' else '0'; + + -- joystick + + port_1f <= '1' when port_1f_lsb = '1' and port_1f_io_en = '1' and port_1f_hw_en = '1' else '0'; + port_37 <= '1' when port_37_lsb = '1' and port_37_io_en = '1' and port_37_hw_en = '1' else '0'; + + -- sprites + + port_57 <= '1' when port_57_lsb = '1' and port_sprite_io_en = '1' else '0'; + port_5b <= '1' when port_5b_lsb = '1' and port_sprite_io_en = '1' else '0'; + port_303b <= '1' when port_30xx_msb = '1' and port_3b_lsb = '1' and port_sprite_io_en = '1' else '0'; + + -- ula+ + + port_bf3b <= '1' when port_bfxx_msb = '1' and port_3b_lsb = '1' and port_ulap_io_en = '1' else '0'; + port_ff3b <= '1' when port_ffxx_msb = '1' and port_3b_lsb = '1' and port_ulap_io_en = '1' else '0'; + + -- z80 ctc + + port_ctc <= '1' when cpu_a(15 downto 11) = "00011" and port_3b_lsb = '1' and port_ctc_io_en = '1' else '0'; + + -- + + -- check if xst handles this well + + port_internal_response <= port_fe or port_ff or port_p3_float or port_7ffd or port_dffd or port_1ffd or port_eff7 or port_e3 or + port_mf_enable or port_mf_disable or port_e7 or port_eb or port_243b or port_253b or port_103b or port_113b or port_123b or port_uart or + port_dma or port_fffd or port_bffd or port_dac_A or port_dac_B or port_dac_C or port_dac_D or port_fadf or port_fbdf or port_ffdf or + port_1f or port_37 or port_57 or port_5b or port_303b or port_bf3b or port_ff3b or port_ctc; + + -- + -- complete port decode with iorq, rd, wr, m1 + -- + + iord <= '1' when cpu_iorq_n = '0' and cpu_m1_n = '1' and cpu_rd_n = '0' else '0'; + iowr <= '1' when cpu_iorq_n = '0' and cpu_m1_n = '1' and cpu_wr_n = '0' else '0'; + + port_fd_conflict_wr <= (port_f1_lsb and port_dac_sd2_ABCD_f1f3f9fb_io_en) or (port_f9_lsb and port_dac_sd2_ABCD_f1f3f9fb_io_en); + + port_fe_rd <= iord and port_fe; + port_fe_wr <= iowr and port_fe; + + port_ff_rd <= iord and port_ff; + port_ff_wr <= iowr and port_ff and port_ff_io_en; + + port_p3_float_rd <= iord and port_p3_float; + + port_7ffd_wr <= iowr and port_7ffd and not port_fd_conflict_wr; + port_dffd_wr <= iowr and port_dffd and not port_fd_conflict_wr; + port_1ffd_wr <= iowr and port_1ffd and not port_fd_conflict_wr; + port_eff7_wr <= iowr and port_eff7; + + port_e3_rd <= iord and port_e3; + port_e3_wr <= iowr and port_e3; + + port_mf_enable_rd <= iord and port_mf_enable; + port_mf_enable_wr <= iowr and port_mf_enable; + port_mf_disable_rd <= iord and port_mf_disable; + port_mf_disable_wr <= iowr and port_mf_disable; + + port_e7_wr <= iowr and port_e7; + port_eb_rd <= iord and port_eb; + port_eb_wr <= iowr and port_eb; + + port_243b_rd <= iord and port_243b; + port_243b_wr <= iowr and port_243b; + port_253b_rd <= iord and port_253b; + port_253b_wr <= iowr and port_253b; + + port_103b_rd <= iord and port_103b; + port_103b_wr <= iowr and port_103b; + port_113b_rd <= iord and port_113b; + port_113b_wr <= iowr and port_113b; + + port_123b_rd <= iord and port_123b; + port_123b_wr <= iowr and port_123b; + + port_uart_rd <= iord and port_uart; + port_uart_wr <= iowr and port_uart; + + port_dma_rd <= iord and port_dma and not dma_holds_bus; + port_dma_wr <= iowr and port_dma and not dma_holds_bus; + + port_fffd_rd <= iord and (port_fffd or (port_bffd and machine_timing_p3) or port_bff5); -- bffd is readable equivalent to fffd on +3 + port_fffd_wr <= iowr and port_fffd and not port_dffd; + port_bffd_wr <= iowr and port_bffd; + + port_dac_A_wr <= iowr and port_dac_A and dac_hw_en; + port_dac_B_wr <= iowr and port_dac_B and dac_hw_en; + port_dac_C_wr <= iowr and port_dac_C and dac_hw_en; + port_dac_D_wr <= iowr and port_dac_D and dac_hw_en; + + port_fadf_rd <= iord and port_fadf; + port_fbdf_rd <= iord and port_fbdf; + port_ffdf_rd <= iord and port_ffdf; + + port_1f_rd <= iord and port_1f; + port_37_rd <= iord and port_37; + + port_57_wr <= iowr and port_57; + port_5b_wr <= iowr and port_5b; + port_303b_rd <= iord and port_303b; + port_303b_wr <= iowr and port_303b; + + port_bf3b_wr <= iowr and port_bf3b; + port_ff3b_rd <= iord and port_ff3b; + port_ff3b_wr <= iowr and port_ff3b; + + port_ctc_wr <= iowr and port_ctc; + port_ctc_rd <= iord and port_ctc; + + -- + + -- check if xst handles this well + + port_internal_rd_response <= port_fe_rd or port_ff_rd or port_p3_float_rd or port_e3_rd or mf_port_en or + port_eb_rd or port_243b_rd or port_253b_rd or port_103b_rd or port_113b_rd or port_123b_rd or port_uart_rd or + port_dma_rd or port_fffd_rd or port_fadf_rd or port_fbdf_rd or port_ffdf_rd or port_1f_rd or port_37_rd or + port_303b_rd or port_ff3b_rd or port_ctc_rd; + + -- + -- Use wired-or logic to avoid expensive if-elsif-endif chain + -- + + port_fe_rd_dat <= port_fe_dat when port_fe_rd = '1' else X"00"; + port_ff_rd_dat <= port_ff_dat_tmx when nr_08_port_ff_rd_en = '1' and port_ff_io_en = '1' and port_ff_rd = '1' else port_ff_dat_ula when port_ff_rd = '1' else X"00"; + port_p3_float_rd_dat <= port_p3_floating_bus_dat when port_p3_float_rd = '1' else X"00"; + port_e3_rd_dat <= port_e3_dat when port_e3_rd = '1' else X"00"; + port_mf_rd_dat <= mf_port_dat when mf_port_en = '1' else X"00"; + port_eb_rd_dat <= port_eb_dat when port_eb_rd = '1' else X"00"; + port_243b_rd_dat <= port_243b_dat when port_243b_rd = '1' else X"00"; + port_253b_rd_dat <= port_253b_dat_0 when port_253b_rd = '1' else X"00"; + port_103b_rd_dat <= port_103b_dat when port_103b_rd = '1' else X"00"; + port_113b_rd_dat <= port_113b_dat when port_113b_rd = '1' else X"00"; + port_123b_rd_dat <= port_123b_dat when port_123b_rd = '1' else X"00"; + port_uart_rd_dat <= port_uart_dat when port_uart_rd = '1' else X"00"; + port_dma_rd_dat <= port_dma_dat when port_dma_rd = '1' else X"00"; + port_fffd_rd_dat <= port_fffd_dat when port_fffd_rd = '1' else X"00"; + port_fadf_rd_dat <= port_fadf_dat when port_fadf_rd = '1' else X"00"; + port_fbdf_rd_dat <= port_fbdf_dat when port_fbdf_rd = '1' else X"00"; + port_ffdf_rd_dat <= port_ffdf_dat when port_ffdf_rd = '1' else X"00"; + port_1f_rd_dat <= port_1f_dat when port_1f_rd = '1' else X"00"; + port_37_rd_dat <= port_37_dat when port_37_rd = '1' else X"00"; + port_303b_rd_dat <= port_303b_dat when port_303b_rd = '1' else X"00"; + port_ff3b_rd_dat <= port_ff3b_dat when port_ff3b_rd = '1' else X"00"; + port_ctc_rd_dat <= port_ctc_dat when port_ctc_rd = '1' else X"00"; + + -- check if xst handles this well + + port_rd_dat <= port_fe_rd_dat or port_ff_rd_dat or port_p3_float_rd_dat or port_e3_rd_dat or port_mf_rd_dat or + port_eb_rd_dat or port_243b_rd_dat or port_253b_rd_dat or port_103b_rd_dat or port_113b_rd_dat or port_123b_rd_dat or port_uart_rd_dat or + port_dma_rd_dat or port_fffd_rd_dat or port_fadf_rd_dat or port_fbdf_rd_dat or port_ffdf_rd_dat or port_1f_rd_dat or port_37_rd_dat or + port_303b_rd_dat or port_ff3b_rd_dat or port_ctc_rd_dat; + + ------------------------------------------------------------ + -- MEMORY ADDRESSES ---------------------------------------- + ------------------------------------------------------------ + + -- divmmc + + process (port_00xx_msb, cpu_a, nr_b8_divmmc_ep_0, nr_b9_divmmc_ep_valid_0, nr_ba_divmmc_ep_timing_0) + begin + if port_00xx_msb = '1' and cpu_a(7 downto 6) = "00" and cpu_a(2 downto 0) = "000" then + case cpu_a(5 downto 3) is + when "000" => + divmmc_rst_ep <= nr_b8_divmmc_ep_0(0); + divmmc_rst_ep_valid <= nr_b9_divmmc_ep_valid_0(0); + divmmc_rst_ep_timing <= nr_ba_divmmc_ep_timing_0(0); + when "001" => + divmmc_rst_ep <= nr_b8_divmmc_ep_0(1); + divmmc_rst_ep_valid <= nr_b9_divmmc_ep_valid_0(1); + divmmc_rst_ep_timing <= nr_ba_divmmc_ep_timing_0(1); + when "010" => + divmmc_rst_ep <= nr_b8_divmmc_ep_0(2); + divmmc_rst_ep_valid <= nr_b9_divmmc_ep_valid_0(2); + divmmc_rst_ep_timing <= nr_ba_divmmc_ep_timing_0(2); + when "011" => + divmmc_rst_ep <= nr_b8_divmmc_ep_0(3); + divmmc_rst_ep_valid <= nr_b9_divmmc_ep_valid_0(3); + divmmc_rst_ep_timing <= nr_ba_divmmc_ep_timing_0(3); + when "100" => + divmmc_rst_ep <= nr_b8_divmmc_ep_0(4); + divmmc_rst_ep_valid <= nr_b9_divmmc_ep_valid_0(4); + divmmc_rst_ep_timing <= nr_ba_divmmc_ep_timing_0(4); + when "101" => + divmmc_rst_ep <= nr_b8_divmmc_ep_0(5); + divmmc_rst_ep_valid <= nr_b9_divmmc_ep_valid_0(5); + divmmc_rst_ep_timing <= nr_ba_divmmc_ep_timing_0(5); + when "110" => + divmmc_rst_ep <= nr_b8_divmmc_ep_0(6); + divmmc_rst_ep_valid <= nr_b9_divmmc_ep_valid_0(6); + divmmc_rst_ep_timing <= nr_ba_divmmc_ep_timing_0(6); + when others => + divmmc_rst_ep <= nr_b8_divmmc_ep_0(7); + divmmc_rst_ep_valid <= nr_b9_divmmc_ep_valid_0(7); + divmmc_rst_ep_timing <= nr_ba_divmmc_ep_timing_0(7); + end case; + else + divmmc_rst_ep <= '0'; + divmmc_rst_ep_valid <= '0'; + divmmc_rst_ep_timing <= '0'; + end if; + end process; + + divmmc_automap_instant_on <= divmmc_rst_ep and divmmc_rst_ep_valid and divmmc_rst_ep_timing; + + divmmc_automap_delayed_on <= divmmc_rst_ep and divmmc_rst_ep_valid and not divmmc_rst_ep_timing; + + divmmc_automap_delayed_off <= '1' when port_1fxx_msb = '1' and cpu_a(7 downto 3) = "11111" and nr_bb_divmmc_ep_1(6) = '1' else '0'; + + divmmc_automap_rom3_instant_on <= (divmmc_rst_ep and (not divmmc_rst_ep_valid) and divmmc_rst_ep_timing) or + (port_3dxx_msb and nr_bb_divmmc_ep_1(7)); + + divmmc_automap_rom3_delayed_on <= (divmmc_rst_ep and (not divmmc_rst_ep_valid) and not divmmc_rst_ep_timing) or + (port_04xx_msb and port_c6_lsb and nr_bb_divmmc_ep_1(2)) or + (port_05xx_msb and port_62_lsb and nr_bb_divmmc_ep_1(3)) or + (port_04xx_msb and port_d7_lsb and nr_bb_divmmc_ep_1(4)) or + (port_05xx_msb and port_6a_lsb and nr_bb_divmmc_ep_1(5)); + + divmmc_automap_nmi_instant_on <= port_00xx_msb and port_66_lsb and nr_bb_divmmc_ep_1(1); + divmmc_automap_nmi_delayed_on <= port_00xx_msb and port_66_lsb and nr_bb_divmmc_ep_1(0); + + -- multiface + + mf_a_0066 <= port_00xx_msb and port_66_lsb; + + ------------------------------------------------------------ + -- MEMORY DECODING ----------------------------------------- + ------------------------------------------------------------ + + -- This is going to be a bit of a mind bender ... + + -- 0x000000 - 0x00FFFF (64K) => ZX Spectrum ROM A20:A16 = 00000 + -- 0x010000 - 0x011FFF ( 8K) => divMMC ROM A20:A16 = 00001,000 + -- 0x012000 - 0x013FFF ( 8K) => unused A20:A16 = 00001,001 + -- 0x014000 - 0x017FFF (16K) => Multiface ROM,RAM A20:A16 = 00001,01 + -- 0x018000 - 0x01BFFF (16K) => Alt ROM0 128k A20:A16 = 00001,10 + -- 0x01c000 - 0x01FFFF (16K) => Alt ROM1 48k A20:A16 = 00001,11 + -- 0x020000 - 0x03FFFF (128K) => divMMC RAM A20:A16 = 00010 + -- 0x040000 - 0x05FFFF (128K) => ZX Spectrum RAM A20:A16 = 00100 + -- 0x060000 - 0x07FFFF (128K) => Extra RAM + -- 0x080000 - 0x0FFFFF (512K) => 1st Extra IC RAM (if present) + -- 0x100000 - 0x17FFFF (512K) => 2nd Extra IC RAM (if present) + -- 0x180000 - 0x1FFFFF (512K) => 3rd Extra IC RAM (if present) + + -- memory decode order + -- + -- 0-16k: + -- 0. bootrom + -- 1. multiface + -- 2. divmmc + -- 3. layer 2 mapping + -- 4. mmu + -- 5. config + -- 6. romcs expansion bus + -- 7. rom + -- + -- 16k-48k: + -- 1. layer 2 mapping + -- 2. mmu + -- + -- 48k-64k: + -- 1. mmu + + mem_active_page <= MMU0 when cpu_a(15 downto 13) = "000" else + MMU1 when cpu_a(15 downto 13) = "001" else + MMU2 when cpu_a(15 downto 13) = "010" else + MMU3 when cpu_a(15 downto 13) = "011" else + MMU4 when cpu_a(15 downto 13) = "100" else + MMU5 when cpu_a(15 downto 13) = "101" else + MMU6 when cpu_a(15 downto 13) = "110" else + MMU7; + + mem_active_bank5 <= '1' when mem_active_page = X"0A" or mem_active_page = X"0B" else '0'; + mem_active_bank7 <= '1' when mem_active_page = X"0E" else '0'; + + mmu_A21_A13 <= ("0001" + ('0' & mem_active_page(7 downto 5))) & mem_active_page(4 downto 0); + + layer2_active_bank_offset_pre <= cpu_a(15 downto 14) when port_123b_layer2_map_segment = "11" else port_123b_layer2_map_segment; + layer2_active_bank_offset <= ("00" & layer2_active_bank_offset_pre) + ('0' & port_123b_layer2_offset); + layer2_active_bank <= nr_12_layer2_active_bank when port_123b_layer2_map_shadow = '0' else nr_13_layer2_shadow_bank; + layer2_active_page <= (('0' & layer2_active_bank) + ("0000" & layer2_active_bank_offset)) & cpu_a(13); + + layer2_A21_A13 <= ("0001" + ('0' & layer2_active_page(7 downto 5))) & layer2_active_page(4 downto 0); + + -- note that the copper can change mmu and the layer 2 base bank so these must be frozen during a memory access + + -- + -- early memory decode before assertion of mreq where possible + -- + + -- rom address computation + + process (machine_type_48, machine_type_p3, nr_8c_altrom_lock_rom1, nr_8c_altrom_lock_rom0, port_1ffd_rom) + begin + if machine_type_48 = '1' then + sram_rom <= "00"; + sram_rom3 <= '1'; + sram_alt_128_n <= not ((not nr_8c_altrom_lock_rom1) and nr_8c_altrom_lock_rom0); + elsif machine_type_p3 = '1' then + if nr_8c_altrom_lock_rom1 = '1' or nr_8c_altrom_lock_rom0 = '1' then + sram_rom <= nr_8c_altrom_lock_rom1 & nr_8c_altrom_lock_rom0; + sram_rom3 <= nr_8c_altrom_lock_rom1 and nr_8c_altrom_lock_rom0; + sram_alt_128_n <= nr_8c_altrom_lock_rom1; + else + sram_rom <= port_1ffd_rom; + sram_rom3 <= port_1ffd_rom(1) and port_1ffd_rom(0); + sram_alt_128_n <= port_1ffd_rom(0); -- behave like a 128k machine + end if; + else + if nr_8c_altrom_lock_rom1 = '1' or nr_8c_altrom_lock_rom0 = '1' then + sram_rom <= '0' & nr_8c_altrom_lock_rom1; + sram_rom3 <= nr_8c_altrom_lock_rom1; + sram_alt_128_n <= nr_8c_altrom_lock_rom1; + else + sram_rom <= '0' & port_1ffd_rom(0); + sram_rom3 <= port_1ffd_rom(0); + sram_alt_128_n <= port_1ffd_rom(0); + end if; + end if; + end process; + + -- early decode sram address computation and freeze parameters + +-- sram_pre_romcs_replace <= expbus_romcs_replace; +-- sram_pre_alt_en <= nr_8c_altrom_en; + + process (i_CLK_28) + begin + if falling_edge(i_CLK_28) then + + if cpu_mreq_n = '1' then + + sram_pre_romcs_replace <= expbus_romcs_replace; + + sram_pre_alt_en <= nr_8c_altrom_en; + sram_pre_alt_128_n <= sram_alt_128_n; + sram_pre_rom3 <= sram_rom3; + + sram_pre_layer2_rd_en <= port_123b_layer2_map_rd_en; + sram_pre_layer2_wr_en <= port_123b_layer2_map_wr_en; + sram_pre_layer2_A21_A13 <= layer2_A21_A13; + + if cpu_a(15 downto 14) = "00" then + if mf_mem_en = '1' then + sram_pre_A20_A13 <= "0000101" & cpu_a(13); + sram_pre_active <= '1'; + sram_pre_bank5 <= '0'; + sram_pre_bank7 <= '0'; + sram_pre_rdonly <= not cpu_a(13); + sram_pre_override <= "000"; -- divmmc & layer 2 & romcs + elsif mmu_A21_A13(8) = '0' then + sram_pre_A20_A13 <= mmu_A21_A13(7 downto 0); + sram_pre_active <= (not mem_active_bank5) and (not mem_active_bank7); + sram_pre_bank5 <= mem_active_bank5; + sram_pre_bank7 <= mem_active_bank7; + sram_pre_rdonly <= '0'; + sram_pre_override <= "110"; -- divmmc & layer 2 & romcs + elsif nr_03_config_mode = '1' then + sram_pre_A20_A13 <= nr_04_romram_bank & cpu_a(13); + sram_pre_active <= '1'; + sram_pre_bank5 <= '0'; + sram_pre_bank7 <= '0'; + sram_pre_rdonly <= '0'; + sram_pre_override <= "110"; -- divmmc & layer 2 & romcs + else + sram_pre_A20_A13 <= "00000" & sram_rom & cpu_a(13); + sram_pre_active <= '1'; + sram_pre_bank5 <= '0'; + sram_pre_bank7 <= '0'; + sram_pre_rdonly <= not (nr_8c_altrom_en and nr_8c_altrom_rw); + sram_pre_override <= "111"; -- divmmc & layer 2 & romcs + end if; + else + sram_pre_A20_A13 <= mmu_A21_A13(7 downto 0); + sram_pre_active <= (not mmu_A21_A13(8)) and (not mem_active_bank5) and (not mem_active_bank7); + sram_pre_bank5 <= mem_active_bank5; + sram_pre_bank7 <= mem_active_bank7; + sram_pre_rdonly <= '0'; + sram_pre_override <= '0' & (((not cpu_a(15)) or (not cpu_a(14))) and port_123b_layer2_map_segment(1) and port_123b_layer2_map_segment(0)) & '0'; -- divmmc & layer 2 & romcs + end if; + + end if; + + end if; + end process; + + -- + -- finish memory decode after mreq is asserted + -- + + sram_layer2_map_en <= sram_pre_override(1) and ((sram_pre_layer2_wr_en and cpu_rd_n) or (sram_pre_layer2_rd_en and not cpu_rd_n)); + sram_altrom_en <= '0' when (sram_pre_override(0) = '0') or (sram_pre_alt_en = '0') or (sram_pre_rdonly = '1' and cpu_rd_n = '1') or (sram_pre_rdonly = '0' and cpu_rd_n = '0') else '1'; + + process (sram_pre_override, divmmc_rom_en, divmmc_ram_en, divmmc_bank, divmmc_rdonly, sram_layer2_map_en, sram_pre_layer2_A21_A13, + sram_romcs, sram_pre_A20_A13, sram_altrom_en, sram_pre_alt_128_n, sram_pre_rdonly, sram_pre_active, sram_pre_bank5, sram_pre_bank7) + begin + if sram_pre_override(2) = '1' and divmmc_rom_en = '1' then + sram_A20_A13 <= "00001000"; + sram_active <= '1'; + sram_bank5 <= '0'; + sram_bank7 <= '0'; + sram_rdonly <= '1'; + sram_romcs_en <= '0'; + elsif sram_pre_override(2) = '1' and divmmc_ram_en = '1' then + sram_A20_A13 <= "0001" & divmmc_bank; + sram_active <= '1'; + sram_bank5 <= '0'; + sram_bank7 <= '0'; + sram_rdonly <= divmmc_rdonly; + sram_romcs_en <= '0'; + elsif sram_layer2_map_en = '1' then + sram_A20_A13 <= sram_pre_layer2_A21_A13(7 downto 0); + sram_active <= not sram_pre_layer2_A21_A13(8); + sram_bank5 <= '0'; + sram_bank7 <= '0'; + sram_rdonly <= '0'; + sram_romcs_en <= '0'; + elsif sram_romcs = '1' then + sram_A20_A13 <= "0001111" & sram_pre_A20_A13(0); -- divmmc banks 14 and 15 + sram_active <= '1'; + sram_bank5 <= '0'; + sram_bank7 <= '0'; + sram_rdonly <= '1'; + sram_romcs_en <= '1'; + elsif sram_altrom_en = '1' then + sram_A20_A13 <= "000011" & sram_pre_alt_128_n & sram_pre_A20_A13(0); + sram_active <= '1'; + sram_bank5 <= '0'; + sram_bank7 <= '0'; + sram_rdonly <= sram_pre_rdonly; + sram_romcs_en <= '0'; + else + sram_A20_A13 <= sram_pre_A20_A13; + sram_active <= sram_pre_active; + sram_bank5 <= sram_pre_bank5; + sram_bank7 <= sram_pre_bank7; + sram_rdonly <= sram_pre_rdonly; + sram_romcs_en <= '0'; + end if; + end process; + + -- divmmc automap disabled for most entry points if rom3 is not present + + sram_divmmc_automap_en <= sram_pre_override(2); + sram_divmmc_automap_rom3_en <= sram_pre_override(2) and sram_pre_override(0) and (not sram_layer2_map_en) and (not sram_romcs) and ((sram_altrom_en and sram_pre_alt_128_n) or (sram_pre_rom3 and not sram_altrom_en)); + + -- + -- generate memory cycle + -- + + sram_memcycle <= '1' when cpu_mreq_n = '0' and cpu_rfsh_n = '1' else '0'; + + -- memory cycle may go to expansion bus if the lower 16K is accessed and romcs is active + -- memory read of internal memory is harmless with cpu_di taken from internal memory or expansion bus depending on romcs at the end of the read cycle + -- memory write is potentially harmful however a write cycle gives much more time for romcs to be asserted so is fine to act on when /wr goes low + + sram_romcs <= sram_pre_override(0) and expbus_eff_en and i_BUS_ROMCS_n and not expbus_eff_disable_mem; + + -- memory signals + + cpu_bank5_rd <= sram_memcycle and sram_bank5 and not cpu_rd_n; + cpu_bank5_we <= sram_memcycle and sram_bank5 and not cpu_wr_n; + cpu_bank7_we <= sram_memcycle and sram_bank7 and not cpu_wr_n; + + sram_addr <= sram_A20_A13 & cpu_a(12 downto 0); + sram_rd_n <= cpu_rd_n; + sram_req <= sram_memcycle and sram_active and ((not cpu_rd_n) or ((not sram_rdonly) and not cpu_wr_n)); + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + sram_req_d <= '0'; + else + sram_req_d <= sram_req; + end if; + end if; + end process; + + sram_req_t <= sram_req and not sram_req_d; + + -- wait states on memory read cycles at 28MHz + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then +-- if sram_req_t = '1' and cpu_rd_n = '0' and cpu_speed = "11" and (cpu_m1_n = '0' or dma_holds_bus = '1') then + if (sram_req_t = '1' or cpu_bank5_sched = '1') and cpu_rd_n = '0' and cpu_speed = "11" then + sram_wait_n <= '0'; + else + sram_wait_n <= '1'; + end if; + end if; + end process; + +-- signals must be delivered before the next rising edge of i_CLK_28 +-- +-- o_RAM_A_ADDR <= sram_addr; +-- o_RAM_A_REQ <= sram_req_t; +-- o_RAM_A_RD_n <= sram_rd_n; +-- o_RAM_A_DO <= cpu_do; + + -- + -- BOOT ROM + -- + + bootrom_mod: entity work.bootrom + port map ( + clk => i_CLK_28, + addr => cpu_a(12 downto 0), + data => bootrom_do + ); + + ------------------------------------------------------------ + -- SERIAL COMMS -------------------------------------------- + ------------------------------------------------------------ + + -- + -- I2C MASTER (bit-banged) + -- + + -- write + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + i2c_scl_o <= '1'; + elsif port_103b_wr = '1' then + i2c_scl_o <= cpu_do(0); + end if; + end if; + end process; + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + i2c_sda_o <= '1'; + elsif port_113b_wr = '1' then + i2c_sda_o <= cpu_do(0); + end if; + end if; + end process; + + -- read + + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + port_103b_dat <= "1111111" & (i_I2C_SCL_n and pi_i2c1_scl); + end if; + end process; + + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + port_113b_dat <= "1111111" & (i_I2C_SDA_n and pi_i2c1_sda); + end if; + end process; + + -- + -- SPI MASTER (MODE 0 : CPOL = 0, CPHA = 0) + -- + + -- read/write to SPI must be separated by 16 cycles (dma has wait to guarantee this) + + -- note: do not AND together miso sources + + spi_miso <= i_SPI_FLASH_MISO when spi_ss_flash_n = '0' else + pi_spi0_miso when spi_ss_rpi1_n = '0' or spi_ss_rpi0_n = '0' else + i_SPI_SD_MISO when spi_ss_sd1_n = '0' or spi_ss_sd0_n = '0' else '1'; + + spi_master_mod: entity work.spi_master + port map ( + clock_i => i_CLK_CPU, + reset_i => '0', -- hard_reset done through core load + + spi_sck_o => spi_sck, + spi_mosi_o => spi_mosi, + spi_miso_i => spi_miso, + + spi_mosi_wr_i => port_eb_wr, + spi_mosi_dat_i => cpu_do, + + spi_miso_rd_i => port_eb_rd, + spi_miso_dat_o => port_eb_dat, + + spi_wait_n_o => spi_wait_n -- wait signal for dma only + ); + + -- slave select register + -- only one slave must be selected but esxdos may write garbage into bits other than 1:0 + + -- bit 7 = fpga flash, bit 3 = rpi1, bit 2 = rpi0, bit 1 = sd1, bit 0 = sd0 + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + port_e7_reg <= (others => '1'); + elsif port_e7_wr = '1' then + if cpu_do(1 downto 0) = "10" then + port_e7_reg <= X"FE"; + elsif cpu_do(1 downto 0) = "01" then + port_e7_reg <= X"FD"; + elsif cpu_do = X"FB" then + port_e7_reg <= X"FB"; + elsif cpu_do = X"F7" then + port_e7_reg <= X"F7"; + elsif cpu_do = X"7F" then + port_e7_reg <= X"7F"; + else + port_e7_reg <= (others => '1'); + end if; + end if; + end if; + end process; + + spi_ss_flash_n <= port_e7_reg(7); + spi_ss_rpi1_n <= port_e7_reg(3); + spi_ss_rpi0_n <= port_e7_reg(2); + spi_ss_sd1_n <= port_e7_reg(1); + spi_ss_sd0_n <= port_e7_reg(0); + + -- + -- UART x 2 (wifi, pi) + -- + + -- multiplex uart with joystick connector + + uart0_rx <= joy_uart_rx when joy_iomode_uart_en = '1' and nr_0b_joy_iomode_0 = '0' else i_UART0_RX; + uart1_rx <= joy_uart_rx when joy_iomode_uart_en = '1' and nr_0b_joy_iomode_0 = '1' else pi_uart_rx; + + uart0_tx_esp <= '1' when joy_iomode_uart_en = '1' and nr_0b_joy_iomode_0 = '0' else uart0_tx; + uart1_tx_pi <= '1' when joy_iomode_uart_en = '1' and nr_0b_joy_iomode_0 = '1' else uart1_tx; + + uart0_tx_cts_n <= joy_uart_cts_n when joy_iomode_uart_en = '1' and nr_0b_joy_iomode_0 = '0' else '0'; + uart1_tx_cts_n <= joy_uart_cts_n when joy_iomode_uart_en = '1' and nr_0b_joy_iomode_0 = '1' else pi_uart_cts_n; + + pi_uart_rtr_n <= '1' when joy_iomode_uart_en = '1' and nr_0b_joy_iomode_0 = '1' else uart1_rx_rtr_n; + +-- joy_iomode_hwflen <= '0' when joy_iomode_uart_en = '0' else uart0_hwflow_en when nr_0b_joy_iomode_0 = '0' else uart1_hwflow_en; + + -- uarts + + uart_mod: entity work.uart + generic map + ( + NOISE_REJECTION_BITS => 2 + ) + port map + ( + i_CLK => i_CLK_28, + i_CLK_n => i_CLK_28_n, + + i_reset => reset, + i_reset_hard => '0', -- hard_reset done by core load + + i_uart_reg => cpu_a(9 downto 8), + + -- read from uart registers to cpu + + i_uart_rd => port_uart_rd, + o_cpu_d => uart_do, + + -- write from cpu to uart registers + + i_uart_wr => port_uart_wr, + i_cpu_d => cpu_do, + + -- uart 0 (esp) + + o_uart0_hwflow => uart0_hwflow_en, + + i_Rx_0 => uart0_rx, + o_Rx_0_rtr_n => uart0_rx_rtr_n, + + o_Rx_0_avail => uart0_rx_avail, + o_Rx_0_near_full => uart0_rx_near_full, + + o_Rx_0_err => open, -- to ctc + o_Rx_0_err_break => open, -- to ctc + + o_Tx_0 => uart0_tx, + i_Tx_0_cts_n => uart0_tx_cts_n, + + o_Tx_0_empty => uart0_tx_empty, + + -- uart 1 (pi) + + o_uart1_hwflow => uart1_hwflow_en, -- to pi to select flow control pins + + i_Rx_1 => uart1_rx, + o_Rx_1_rtr_n => uart1_rx_rtr_n, + + o_Rx_1_avail => uart1_rx_avail, + o_Rx_1_near_full => uart1_rx_near_full, + + o_Rx_1_err => open, -- to ctc + o_Rx_1_err_break => open, -- to ctc + + o_Tx_1 => uart1_tx, + i_Tx_1_cts_n => uart1_tx_cts_n, + + o_Tx_1_empty => uart1_tx_empty + ); + + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + port_uart_dat <= uart_do; + end if; + end process; + + ------------------------------------------------------------ + -- KEYBOARD, JOYSTICKS & MOUSE ----------------------------- + ------------------------------------------------------------ + + -- Joystick modes: + -- + -- 000 = Sinclair 2 (67890) + -- 001 = Kempston 1 (port 0x1F) + -- 010 = Cursor (56780) + -- 011 = Sinclair 1 (12345) + -- 100 = Kempston 2 (port 0x37) + -- 101 = MD 1 (3 or 6 button joystick port 0x1F) + -- 110 = MD 2 (3 or 6 button joystick port 0x37) + -- 111 = Both joysticks in I/O Mode + -- + -- Joystick Signals: + -- X Z Y START A C(F2) B(F1) U D L R + -- 10 9 8 7 6 5 4 3 2 1 0 + + -- keyboard + + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + keyrow <= cpu_a(15 downto 8); + end if; + end process; + + port_fe_bus <= i_BUS_DI when expbus_eff_en = '1' and port_propagate_fe = '1' else X"FF"; + + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + if expbus_eff_en = '0' or port_propagate_fe = '0' or port_fe_override = '0' then + port_fe_dat_0 <= '1' & ((not i_AUDIO_EAR) xor pi_fe_ear xor (port_fe_ear or (port_fe_mic and nr_08_keyboard_issue2))) & '1' & i_KBD_COL; + else + port_fe_dat_0 <= X"FF"; + end if; + end if; + end process; + + -- legacy external peripherals are slow so we have to allow reading until the last moment + + port_fe_dat <= port_fe_dat_0 and port_fe_bus; + + -- kempston and md pad + + mdL_1f_en <= '1' when nr_05_joy0 = "101" else '0'; + mdL_37_en <= '1' when nr_05_joy0 = "110" else '0'; + + joyL_1f_en <= '1' when nr_05_joy0 = "001" or mdL_1f_en = '1' else '0'; + joyL_37_en <= '1' when nr_05_joy0 = "100" or mdL_37_en = '1' else '0'; + + joyL_1f(7 downto 6) <= i_JOY_LEFT(7 downto 6) when mdL_1f_en = '1' else (others => '0'); + joyL_1f(5 downto 0) <= i_JOY_LEFT(5 downto 0) when joyL_1f_en = '1' else (others => '0'); + + joyL_37(7 downto 6) <= i_JOY_LEFT(7 downto 6) when mdL_37_en = '1' else (others => '0'); + joyL_37(5 downto 0) <= i_JOY_LEFT(5 downto 0) when joyL_37_en = '1' else (others => '0'); + + mdR_1f_en <= '1' when nr_05_joy1 = "101" else '0'; + mdR_37_en <= '1' when nr_05_joy1 = "110" else '0'; + + joyR_1f_en <= '1' when nr_05_joy1 = "001" or mdR_1f_en = '1' else '0'; + joyR_37_en <= '1' when nr_05_joy1 = "100" or mdR_37_en = '1' else '0'; + + joyR_1f(7 downto 6) <= i_JOY_RIGHT(7 downto 6) when mdR_1f_en = '1' else (others => '0'); + joyR_1f(5 downto 0) <= i_JOY_RIGHT(5 downto 0) when joyR_1f_en = '1' else (others => '0'); + + joyR_37(7 downto 6) <= i_JOY_RIGHT(7 downto 6) when mdR_37_en = '1' else (others => '0'); + joyR_37(5 downto 0) <= i_JOY_RIGHT(5 downto 0) when joyR_37_en = '1' else (others => '0'); + + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + port_1f_dat <= joyL_1f or joyR_1f; + end if; + end process; + + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + port_37_dat <= joyL_37 or joyR_37; + end if; + end process; + + -- joystick io mode + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + joy_iomode_pin7 <= '1'; + else + case nr_0b_joy_iomode is + when "00" => + joy_iomode_pin7 <= nr_0b_joy_iomode_0; + when "01" => + if ctc_zc_to(3) = '1' and (nr_0b_joy_iomode_0 = '1' or joy_iomode_pin7 = '0') then + joy_iomode_pin7 <= not joy_iomode_pin7; + end if; + when others => + if nr_0b_joy_iomode_0 = '0' then + joy_iomode_pin7 <= uart0_tx; + else + joy_iomode_pin7 <= uart1_tx; + end if; + end case; + end if; + end if; + end process; + + joy_iomode_uart_en <= '1' when nr_0b_joy_iomode_en = '1' and nr_0b_joy_iomode(1) = '1' else '0'; + + joy_uart_rx <= ((not nr_0b_joy_iomode(0)) and not i_JOY_LEFT(5)) or (nr_0b_joy_iomode(0) and not i_JOY_RIGHT(5)); + joy_uart_cts_n <= ((not nr_0b_joy_iomode(0)) and not i_JOY_LEFT(4)) or (nr_0b_joy_iomode(0) and not i_JOY_RIGHT(4)); + + -- mouse + + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + port_fbdf_dat <= i_MOUSE_X; + end if; + end process; + + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + port_ffdf_dat <= i_MOUSE_Y; + end if; + end process; + + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + port_fadf_dat <= i_MOUSE_WHEEL & '1' & (not i_MOUSE_BUTTON(2)) & (not i_MOUSE_BUTTON(0)) & (not i_MOUSE_BUTTON(1)); + end if; + end process; + + ------------------------------------------------------------ + -- DEVICES ------------------------------------------------- + ------------------------------------------------------------ + + -- FE, FF : ULA/SCLD + -- 7FFD, DFFD, 1FFD : 128K MEMORY PAGING + -- 123B : LAYER 2 CONTROL + -- COPPER + -- CTC + -- DIVMMC + -- LAYER 2 + -- LORES + -- MULTIFACE + -- SPRITES + -- TILEMAP + -- ULA + -- ULA+ + + -- + -- PORTS FE (ULA) & FF (TIMEX SCLD) + -- + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + port_fe_reg <= (others => '0'); + elsif port_fe_wr = '1' and bus_iorq_ula = '0' then + port_fe_reg <= cpu_do(4 downto 0); + end if; + end if; + end process; + + port_fe_ear <= port_fe_reg(4); + port_fe_mic <= port_fe_reg(3); + + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + port_fe_border <= port_fe_reg(2 downto 0); + end if; + end process; + + -- port fe is read in KEYBOARD & JOYSTICK section + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + port_ff_reg <= (others => '0'); + elsif port_ff_wr = '1' then + port_ff_reg <= cpu_do; + elsif nr_69_we = '1' then + port_ff_reg(5 downto 0) <= nr_wr_dat(5 downto 0); + elsif nr_22_we = '1' then + port_ff_reg(6) <= nr_wr_dat(2); + elsif nr_c4_we = '1' then + port_ff_reg(6) <= not nr_wr_dat(0); + end if; + end if; + end process; + + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + port_ff_dat_tmx <= port_ff_reg; + end if; + end process; + + port_ff_screen_mode <= port_ff_dat_tmx(5 downto 0); + port_ff_interrupt_disable <= port_ff_reg(6); + + -- port ff is read through ula + + -- + -- 128K MEMORY PAGING + -- + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + + port_7ffd_reg <= (others => '0'); + + elsif port_7ffd_wr = '1' and port_7ffd_locked = '0' then + + port_7ffd_reg <= cpu_do; + + elsif nr_08_we = '1' and nr_wr_dat(7) = '1' then + + port_7ffd_reg(5) <= '0'; + + elsif nr_69_we = '1' then + + port_7ffd_reg(3) <= nr_wr_dat(6); + + elsif nr_8e_we = '1' then + + if nr_wr_dat(3) = '1' then + port_7ffd_reg(2 downto 0) <= nr_wr_dat(6 downto 4); + end if; + + if nr_wr_dat(2) = '0' then + port_7ffd_reg(4) <= nr_wr_dat(0); + end if; + + end if; + end if; + end process; + + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + port_7ffd_dat <= port_7ffd_reg; + end if; + end process; + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + + port_dffd_reg <= (others => '0'); + port_dffd_reg_6 <= '0'; + + elsif port_dffd_wr = '1' and (port_7ffd_locked = '0' or nr_8f_mapping_mode_profi = '1') then + + port_dffd_reg <= cpu_do(4 downto 0); + port_dffd_reg_6 <= cpu_do(6); + + elsif nr_8e_we = '1' then + + if nr_8f_mapping_mode_profi = '0' and nr_wr_dat(3) = '1' then + port_dffd_reg(3) <= '0'; + end if; + + if nr_wr_dat(3) = '1' then + port_dffd_reg(2 downto 0) <= "00" & nr_wr_dat(7); + end if; + + end if; + end if; + end process; + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + + port_1ffd_reg <= (others => '0'); + port_1ffd_special_old <= '0'; + + elsif port_1ffd_wr = '1' and port_7ffd_locked = '0' then + + if port_memory_change_dly = '0' then + port_1ffd_special_old <= port_1ffd_special; + end if; + + port_1ffd_reg <= cpu_do; + + elsif nr_8e_we = '1' then + + if port_memory_change_dly = '0' then + port_1ffd_special_old <= port_1ffd_special; + end if; + + port_1ffd_reg(2) <= nr_wr_dat(1); + port_1ffd_reg(1) <= nr_wr_dat(0); + port_1ffd_reg(0) <= nr_wr_dat(2); + + else + + port_1ffd_special_old <= '0'; + + end if; + end if; + end process; + + port_1ffd_dat <= port_1ffd_reg; + + port_7ffd_bank(2 downto 0) <= port_7ffd_reg(2 downto 0); + port_7ffd_bank(4 downto 3) <= port_7ffd_reg(7 downto 6) when nr_8f_mapping_mode_pentagon = '1' else port_dffd_reg(1 downto 0); + port_7ffd_bank(5) <= port_dffd_reg(2) when nr_8f_mapping_mode_pentagon = '0' else (nr_8f_mapping_mode_pentagon_1024_en and port_7ffd_reg(5)); + port_7ffd_bank(6) <= '0' when nr_8f_mapping_mode_pentagon = '1' or nr_8f_mapping_mode_profi = '1' else port_dffd_reg(3); + + port_7ffd_shadow <= port_7ffd_dat(3); + port_7ffd_locked <= '0' when (nr_8f_mapping_mode_pentagon_1024_en = '1') or (nr_8f_mapping_mode_profi = '1' and port_dffd_reg(4) = '1') else port_7ffd_reg(5); + + port_1ffd_special <= port_1ffd_reg(0); + port_1ffd_rom <= port_1ffd_reg(2) & port_7ffd_reg(4); + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + port_eff7_reg_2 <= '0'; + port_eff7_reg_3 <= '0'; + elsif port_eff7_wr = '1' then + port_eff7_reg_2 <= cpu_do(2); + port_eff7_reg_3 <= cpu_do(3); + end if; + end if; + end process; + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if nr_8f_we = '1' then + nr_8f_mapping_mode <= nr_wr_dat(1 downto 0); + end if; + end if; + end process; + +-- nr_8f_mapping_mode_profi <= '1' when nr_8f_mapping_mode = "01" else '0'; + nr_8f_mapping_mode_profi <= '0'; + nr_8f_mapping_mode_pentagon <= '1' when nr_8f_mapping_mode = "10" or nr_8f_mapping_mode_pentagon_1024_en = '1' else '0'; + nr_8f_mapping_mode_pentagon_1024 <= '1' when nr_8f_mapping_mode = "11" else '0'; + + nr_8f_mapping_mode_pentagon_1024_en <= '1' when nr_8f_mapping_mode_pentagon_1024 = '1' and port_eff7_reg_2 = '0' else '0'; + + -- communicate paging changes to mmu + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + port_memory_change_dly <= '0'; + port_memory_ram_change_dly <= '0'; + nr_8f_we_dly <= '0'; + else + port_memory_change_dly <= ((port_7ffd_wr or port_1ffd_wr) and not port_7ffd_locked) or (port_dffd_wr and (nr_8f_mapping_mode_profi or not port_7ffd_locked)) or port_eff7_wr or nr_8e_we or nr_8f_we_dly; + port_memory_ram_change_dly <= not (nr_8e_we and not nr_wr_dat(3)); + nr_8f_we_dly <= nr_8f_we; + end if; + end if; + end process; + + -- + -- PORT 123B LAYER 2 CONTROL + -- + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + port_123b_layer2_en <= '0'; + port_123b_layer2_map_wr_en <= '0'; + port_123b_layer2_map_rd_en <= '0'; + port_123b_layer2_map_shadow <= '0'; + port_123b_layer2_map_segment <= (others => '0'); + port_123b_layer2_offset <= (others => '0'); + elsif port_123b_wr = '1' then + if cpu_do(4) = '0' then + port_123b_layer2_en <= cpu_do(1); + port_123b_layer2_map_wr_en <= cpu_do(0); + port_123b_layer2_map_rd_en <= cpu_do(2); + port_123b_layer2_map_shadow <= cpu_do(3); + port_123b_layer2_map_segment <= cpu_do(7 downto 6); + else + port_123b_layer2_offset <= cpu_do(2 downto 0); + end if; + elsif nr_69_we = '1' then + port_123b_layer2_en <= nr_wr_dat(7); + end if; + end if; + end process; + + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + port_123b_dat <= port_123b_layer2_map_segment & "00" & port_123b_layer2_map_shadow & port_123b_layer2_map_rd_en & port_123b_layer2_en & port_123b_layer2_map_wr_en; + end if; + end process; + + -- + -- COPPER + -- simple co-processor synchronized with display generation + -- + + copper_mod: entity work.copper + port map ( + clock_i => i_CLK_28, + reset_i => reset, + + copper_en_i => nr_62_copper_mode, + + hcount_i => hc, + vcount_i => cvc, + + copper_list_addr_o => copper_instr_addr, + copper_list_data_i => copper_instr_data, + + copper_dout_o => copper_dout_en, + copper_data_o => copper_dout + ); + + copper_inst_msb_ram: entity work.dpram2 + generic map ( + addr_width_g => 10, + data_width_g => 8 + ) + port map ( + -- CPU port + clk_a_i => i_CLK_28, + we_i => copper_msb_we, + addr_a_i => nr_copper_addr(10 downto 1), + data_a_i => copper_msb_dat, + data_a_o => open, + -- Copper Instructions + clk_b_i => i_CLK_28_n, + addr_b_i => copper_instr_addr, + data_b_o => copper_instr_data(15 downto 8) + ); + + copper_msb_we <= '1' when nr_copper_we = '1' and ((nr_copper_write_8 = '0' and nr_copper_addr(0) = '1') or (nr_copper_write_8 = '1' and nr_copper_addr(0) = '0')) else '0'; + copper_msb_dat <= nr_wr_dat when nr_copper_write_8 = '1' else nr_copper_data_stored; + + copper_inst_lsb_ram: entity work.dpram2 + generic map ( + addr_width_g => 10, + data_width_g => 8 + ) + port map ( + -- CPU port + clk_a_i => i_CLK_28, + we_i => copper_lsb_we, + addr_a_i => nr_copper_addr(10 downto 1), + data_a_i => copper_lsb_dat, + data_a_o => open, + -- Copper Instructions + clk_b_i => i_CLK_28_n, + addr_b_i => copper_instr_addr, + data_b_o => copper_instr_data(7 downto 0) + ); + + copper_lsb_we <= '1' when nr_copper_we = '1' and nr_copper_addr(0) = '1' else '0'; + copper_lsb_dat <= nr_wr_dat; + + -- + -- CTC (COUNTER / TIMER CIRCUIT) + -- + +-- ctc_mod: entity work.ctc +-- generic map +-- ( +-- NUM_CTC => 8, +-- NUM_CTC_LOG2 => 3 +-- ) +-- port map +-- ( +-- i_CLK => i_CLK_28, +-- i_reset => reset, +-- +-- i_port_ctc_wr => port_ctc_wr, +-- i_port_ctc_sel => cpu_a(10 downto 8), +-- +-- i_int_en_wr => nr_c5_we, +-- i_int_en => nr_wr_dat, +-- +-- i_cpu_d => cpu_do, +-- o_cpu_d => ctc_do, +-- +-- i_clk_trg => ctc_zc_to(6 downto 0) & ctc_zc_to(7), +-- +-- o_im2_vector_wr => open, +-- +-- o_zc_to => ctc_zc_to, +-- o_int_en => ctc_int_en +-- ); + +-- ctc_mod: entity work.ctc +-- generic map +-- ( +-- NUM_CTC => 6, +-- NUM_CTC_LOG2 => 3 +-- ) +-- port map +-- ( +-- i_CLK => i_CLK_28, +-- i_reset => reset, +-- +-- i_port_ctc_wr => port_ctc_wr, +-- i_port_ctc_sel => cpu_a(10 downto 8), +-- +-- i_int_en_wr => nr_c5_we, +-- i_int_en => nr_wr_dat(5 downto 0), +-- +-- i_cpu_d => cpu_do, +-- o_cpu_d => ctc_do, +-- +-- i_clk_trg => ctc_zc_to(4 downto 0) & ctc_zc_to(5), +-- +-- o_im2_vector_wr => open, +-- +-- o_zc_to => ctc_zc_to(5 downto 0), +-- o_int_en => ctc_int_en(5 downto 0) +-- ); +-- +-- ctc_zc_to(7 downto 6) <= "00"; +-- ctc_int_en(7 downto 6) <= "00"; + + ctc_mod: entity work.ctc + generic map + ( + NUM_CTC => 4, + NUM_CTC_LOG2 => 3 + ) + port map + ( + i_CLK => i_CLK_28, + i_reset => reset, + + i_port_ctc_wr => port_ctc_wr, + i_port_ctc_sel => cpu_a(10 downto 8), + + i_int_en_wr => nr_c5_we, + i_int_en => nr_wr_dat(3 downto 0), + + i_cpu_d => cpu_do, + o_cpu_d => ctc_do, + + i_clk_trg => ctc_zc_to(2 downto 0) & ctc_zc_to(3), + + o_im2_vector_wr => open, + + o_zc_to => ctc_zc_to(3 downto 0), + o_int_en => ctc_int_en(3 downto 0) + ); + + ctc_zc_to(7 downto 4) <= "0000"; + ctc_int_en(7 downto 4) <= "0000"; + + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + port_ctc_dat <= ctc_do; + end if; + end process; + + -- + -- DIVMMC + -- + + -- divmmc normally includes an spi interface to the sd card but on the zx next + -- the spi interface is implemented separately + + -- todo: add sets of automap entry points for trapping different systems + + divmmc_retn_seen <= z80_retn_seen_28 and not mf_is_active; + divmmc_automap_reset <= '1' when port_divmmc_io_en = '0' or nr_0a_divmmc_automap_en = '0' else '0'; + + process (i_CLK_28) + begin + if falling_edge(i_CLK_28) then + if cpu_m1_n = '1' then + divmmc_automap_instant_on_q <= '0'; + divmmc_automap_delayed_on_q <= '0'; + divmmc_automap_delayed_off_q <= '0'; + divmmc_automap_rom3_instant_on_q <= '0'; + divmmc_automap_rom3_delayed_on_q <= '0'; + divmmc_automap_nmi_instant_on_q <= '0'; + divmmc_automap_nmi_delayed_on_q <= '0'; + elsif cpu_mreq_n = '1' then + divmmc_automap_instant_on_q <= divmmc_automap_instant_on; + divmmc_automap_delayed_on_q <= divmmc_automap_delayed_on; + divmmc_automap_delayed_off_q <= divmmc_automap_delayed_off; + divmmc_automap_rom3_instant_on_q <= divmmc_automap_rom3_instant_on; + divmmc_automap_rom3_delayed_on_q <= divmmc_automap_rom3_delayed_on; + divmmc_automap_nmi_instant_on_q <= divmmc_automap_nmi_instant_on; + divmmc_automap_nmi_delayed_on_q <= divmmc_automap_nmi_delayed_on; + end if; + end if; + end process; + + divmmc_mod: entity work.divmmc + port map + ( + i_CLK => i_CLK_28, + i_reset => reset, + + i_cpu_a_15_13 => cpu_a(15 downto 13), + i_cpu_mreq_n => cpu_mreq_n, + i_cpu_m1_n => cpu_m1_n, + + i_en => port_divmmc_io_en, + i_automap_reset => divmmc_automap_reset, + i_automap_active => sram_divmmc_automap_en, + i_automap_rom3_active=> sram_divmmc_automap_rom3_en, + i_retn_seen => divmmc_retn_seen, + + i_divmmc_button => nmi_divmmc_button, + i_divmmc_reg => port_e3_reg(7 downto 6) & "00" & port_e3_reg(3 downto 0), + + i_automap_instant_on => divmmc_automap_instant_on_q, + i_automap_delayed_on => divmmc_automap_delayed_on_q, + i_automap_delayed_off => divmmc_automap_delayed_off_q, + i_automap_rom3_instant_on => divmmc_automap_rom3_instant_on_q, + i_automap_rom3_delayed_on => divmmc_automap_rom3_delayed_on_q, + i_automap_nmi_instant_on => divmmc_automap_nmi_instant_on_q, + i_automap_nmi_delayed_on => divmmc_automap_nmi_delayed_on_q, + + o_divmmc_rom_en => divmmc_rom_en, -- 1 if divmmc rom is active + o_divmmc_ram_en => divmmc_ram_en, -- 1 if divmmc ram bank is active + o_divmmc_rdonly => divmmc_rdonly, -- 1 if active divmmc is read only + o_divmmc_ram_bank => divmmc_bank, -- active divmmc ram bank + + o_disable_nmi => divmmc_nmi_hold, + o_automap_held => divmmc_automap_held + ); + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + port_e3_reg <= (others => '0'); +-- elsif divmmc_retn_seen = '1' then +-- port_e3_reg(7) <= '0'; + elsif port_e3_wr = '1' then + port_e3_reg(7) <= cpu_do(7); + port_e3_reg(6) <= cpu_do(6) or port_e3_reg(6); + port_e3_reg(3 downto 0) <= cpu_do(3 downto 0); -- 16 pages of 8K = 128K allocated to divmmc + elsif nr_09_we = '1' and nr_wr_dat(3) = '1' then + port_e3_reg(6) <= '0'; + end if; + end if; + end process; + + port_e3_dat <= port_e3_reg(7 downto 6) & "00" & port_e3_reg(3 downto 0); + + -- + -- LAYER 2 + -- 256x192x8, 320x256x8, 640x256x4 in external sram + -- + + layer2_mod: entity work.layer2 + port map + ( + i_CLK_7 => i_CLK_7, + i_CLK_28 => i_CLK_28, + + i_sc => sc, + + i_phc => std_logic_vector(phc), + i_pvc => std_logic_vector(vc), + + i_whc => std_logic_vector(whc), + i_wvc => std_logic_vector(wvc), + + i_layer2_en => port_123b_layer2_en, + i_resolution => nr_70_layer2_resolution, + i_palette_offset => nr_70_layer2_palette_offset, + + i_scroll_x => nr_71_layer2_scrollx_msb & nr_16_layer2_scrollx, + i_scroll_y => nr_17_layer2_scrolly, + + i_clip_x1 => nr_18_layer2_clip_x1, + i_clip_x2 => nr_18_layer2_clip_x2, + i_clip_y1 => nr_18_layer2_clip_y1, + i_clip_y2 => nr_18_layer2_clip_y2, + + i_layer2_active_bank => nr_12_layer2_active_bank, + + o_layer2_sram_addr => layer2_addr_eff, + o_layer2_req_t => layer2_req_t, + i_layer2_sram_di => i_RAM_B_DI, + + o_layer2_en => layer2_pixel_en, + o_layer2_pixel => layer2_pixel + ); + +-- o_RAM_B_ADDR <= layer2_addr_eff; +-- o_RAM_B_REQ_T <= layer2_req_t; + + -- + -- LORES + -- 128 x 96 4-bit or 8-bit pixels in bank 5 + -- + + lores_mod: entity work.lores + port map + ( + mode_i => lores_mode_0, -- 0 = lores, 1 = radastan + dfile_i => lores_dfile_0, -- timex display file to use for radastan + ulap_en_i => ulap_en_0 and not ulanext_en_0, -- translate radastan pixel to ula+ palette + + lores_palette_offset_i => lores_palette_offset_0, + + hc_i => std_logic_vector(phc), -- current x coordinate + vc_i => std_logic_vector(vc), -- current y coordinate + +-- clip_x1_i => lores_clip_x1_0, +-- clip_x2_i => lores_clip_x2_0, +-- clip_y1_i => lores_clip_y1_0, +-- clip_y2_i => lores_clip_y2_0, + + clip_x1_i => ula_clip_x1_0, + clip_x2_i => ula_clip_x2_0, + clip_y1_i => ula_clip_y1_0, + clip_y2_i => ula_clip_y2_0, + + scroll_x_i => lores_scroll_x_0, + scroll_y_i => lores_scroll_y_0, + + lores_addr_o => lores_addr, -- bank 5 address + lores_data_i => lores_vram_di, -- read from bank 5 + + lores_pixel_o => lores_pixel, + lores_pixel_en_o => lores_pixel_en -- valid unclipped pixel + ); + + -- + -- MULTIFACE + -- + + multiface_mod: entity work.multiface + port map + ( + reset_i => reset, + clock_i => i_CLK_28, + + cpu_a_0066_i => mf_a_0066, + + cpu_mreq_n_i => cpu_mreq_n, + cpu_m1_n_i => cpu_m1_n, + cpu_retn_seen_i => z80_retn_seen_28, + + enable_i => port_multiface_io_en, + button_i => nmi_mf_button, + + mf_mode_i => nr_0a_mf_type, + + port_mf_enable_rd_i => port_mf_enable_rd, + port_mf_enable_wr_i => port_mf_enable_wr, + port_mf_disable_rd_i => port_mf_disable_rd, + port_mf_disable_wr_i => port_mf_disable_wr, + + nmi_disable_o => mf_nmi_hold, + mf_enabled_o => mf_mem_en, + + mf_port_en_o => mf_port_en + ); + + mf_is_active <= mf_mem_en or mf_nmi_hold; + +-- process (nr_0a_mf_type, cpu_a, port_1ffd_dat, port_7ffd_dat, port_dffd_reg_6, port_dffd_reg, port_eff7_reg_3, port_eff7_reg_2, port_fe_border) + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + if nr_0a_mf_type = "00" then -- mf +3 + case cpu_a(15 downto 12) is + when "0001" => mf_port_dat <= port_1ffd_reg; + when "0111" => mf_port_dat <= port_7ffd_reg; + when "1101" => mf_port_dat <= '0' & port_dffd_reg_6 & '0' & port_dffd_reg; + when "1110" => mf_port_dat <= "0000" & port_eff7_reg_3 & port_eff7_reg_2 & "00"; + when others => mf_port_dat <= "00000" & port_fe_reg(2 downto 0); + end case; + else + mf_port_dat <= port_7ffd_reg(3) & "1111111"; + end if; + end if; + end process; + + -- + -- SPRITES + -- + + sprite_mod: entity work.sprites + port map ( + clock_master_i => i_CLK_28, + clock_master_180o_i => i_CLK_28_n, + clock_pixel_i => i_CLK_7, + reset_i => reset, + zero_on_top_i => nr_15_sprite_priority, + border_clip_en_i => nr_15_sprite_border_clip_en, + over_border_i => nr_15_sprite_over_border_en, + hcounter_i => whc, + vcounter_i => wvc, + transp_colour_i => nr_4b_sprite_transparent_index, + + -- CPU + + port57_w_en_s => port_57_wr, + port5B_w_en_s => port_5b_wr, + port303b_r_en_s => port_303b_rd, + port303b_w_en_s => port_303b_wr, + cpu_d_i => cpu_do, + cpu_d_o => port_303b_dat, + + -- NEXTREG Mirror + + mirror_tie_i => nr_09_sprite_tie, -- 1 = nextreg and io port are tied + mirror_we_i => nr_sprite_mirror_we, + mirror_index_i => nr_sprite_mirror_index, + mirror_data_i => nr_wr_dat, + mirror_inc_i => nr_sprite_mirror_inc, + mirror_num_o => sprite_mirror_id, + + -- Video out + + rgb_o => sprite_pixel, + pixel_en_o => sprite_pixel_en, + + -- clip window + + clip_x1_i => unsigned(nr_19_sprite_clip_x1), + clip_x2_i => unsigned(nr_19_sprite_clip_x2), + clip_y1_i => unsigned(nr_19_sprite_clip_y1), + clip_y2_i => unsigned(nr_19_sprite_clip_y2) + ); + + -- + -- TILEMAP + -- tilemap display + -- + + tilemap_mod: entity work.tilemap + port map ( + reset_i => reset, + + clock_master_i => i_CLK_28, + clock_master_180o_i => i_CLK_28_n, + + hcounter_i => whc, + vcounter_i => wvc, + subpixel_i => sc, + + control_i => nr_6b_tm_control, + default_flags_i => nr_6c_tm_default_attr, + transp_colour_i => nr_4c_tm_transparent_index, + + -- ULA Bank 5 Memory Interface + + tm_mem_bank7_o => tm_mem_bank7, + tm_mem_addr_o => tm_vram_a, + tm_mem_rd_o => tm_vram_rd, + tm_mem_ack_i => tm_vram_ack, + tm_mem_data_i => tm_vram_di, + + -- Memory Map + + tm_map_base_i => nr_6e_tilemap_base_7 & nr_6e_tilemap_base, + tm_tile_base_i => nr_6f_tilemap_tiles_7 & nr_6f_tilemap_tiles, + + -- Out + + pixel_o => tm_pixel, + pixel_en_o => tm_pixel_en, + pixel_below_o => tm_pixel_below, + pixel_textmode_o => tm_pixel_textmode, + + -- Scroll + + tm_scroll_x_i => nr_30_tm_scrollx, + tm_scroll_y_i => nr_31_tm_scrolly, + + -- Clip Window + + clip_x1_i => unsigned(nr_1b_tm_clip_x1), + clip_x2_i => unsigned(nr_1b_tm_clip_x2), + clip_y1_i => unsigned(nr_1b_tm_clip_y1), + clip_y2_i => unsigned(nr_1b_tm_clip_y2) + ); + + -- + -- ULA + -- cpu contention, zx spectrum screen, timex video modes, floating bus + -- + + ula_mod: entity work.zxula + port map ( + i_CLK_7 => i_CLK_7, + i_CLK_14 => i_CLK_14, + i_CLK_CPU => i_CLK_CPU, + + i_cpu_mreq_n => cpu_mreq_n, + i_cpu_iorq_n => cpu_iorq_n, + + i_hc => std_logic_vector(hc), + i_vc => std_logic_vector(vc), + i_phc => std_logic_vector(phc), + + i_timing_pentagon => machine_timing_pentagon, + i_timing_p3 => machine_timing_p3, + + i_port_ff_reg => port_ff_screen_mode, + i_port_fe_border => port_fe_border, + i_ula_shadow_en => port_7ffd_shadow, + + i_ulanext_en => ulanext_en_0, + i_ulanext_format => ulanext_format_0, + i_ulap_en => ulap_en_0, + + o_ula_vram_a => ula_vram_a, + o_ula_shadow => ula_vram_shadow, + o_ula_vram_rd => ula_vram_rd, + i_ula_vram_d => ula_vram_di, + + o_ula_border => ula_border, + o_ula_pixel => ula_pixel, + o_ula_select_bgnd => ula_select_bgnd, + o_ula_clipped => ula_clipped, + + i_ula_clip_x1 => ula_clip_x1_0, + i_ula_clip_x2 => ula_clip_x2_0, + i_ula_clip_y1 => ula_clip_y1_0, + i_ula_clip_y2 => ula_clip_y2_0, + + i_ula_scroll_x => nr_26_ula_scrollx, + i_ula_scroll_y => nr_27_ula_scrolly, + i_ula_fine_scroll_x => nr_68_ula_fine_scroll_x, + + i_p3_floating_bus => p3_floating_bus_dat, + o_ula_floating_bus => ula_floating_bus, + + i_contention_en => (not eff_nr_08_contention_disable) and (not machine_timing_pentagon) and (not cpu_speed(1)) and (not cpu_speed(0)), + i_contention_port => port_contend, + i_contention_memory => mem_contend, + + o_cpu_wait_n => ula_wait_n, + o_cpu_contend => ula_cpu_contend + ); + + mem_contend <= '0' when mem_active_page(7 downto 4) /= "0000" else -- contention can only occur in 16k banks 0-7 + '1' when machine_timing_48 = '1' and mem_active_page(3 downto 1) = "101" else -- bank 5 only + '1' when machine_timing_128 = '1' and mem_active_page(1) = '1' else -- odd banks + '1' when machine_timing_p3 = '1' and mem_active_page(3) = '1' else -- banks >= 4 + '0'; + +-- port_contend <= (not cpu_a(0)) or port_7ffd_active or port_1ffd_active or port_p3_float_active or port_bf3b or port_ff3b; + port_contend <= (not cpu_a(0)) or port_7ffd_active or port_bf3b or port_ff3b; -- uno requires ula+ ports to be contended + + process (i_CLK_CPU) + begin + if rising_edge(i_CLK_CPU) then + if mem_contend = '1' and cpu_mreq_n = '0' then + if cpu_rd_n = '0' then + p3_floating_bus_dat <= cpu_di; + elsif cpu_wr_n = '0' then + p3_floating_bus_dat <= cpu_do; + end if; + end if; + end if; + end process; + + -- floating bus read through port ff + + port_ff_dat_ula <= ula_floating_bus when (machine_timing_48 = '1' or machine_timing_128 = '1') else X"FF"; + + -- +3 floating bus + + port_p3_floating_bus_dat <= ula_floating_bus when port_7ffd_locked = '0' else X"FF"; + + -- + -- ULA+ + -- + + -- port bf3b + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + port_bf3b_ulap_mode <= (others => '0'); + port_bf3b_ulap_index <= (others => '0'); + elsif port_bf3b_wr = '1' then + port_bf3b_ulap_mode <= cpu_do(7 downto 6); + if cpu_do(7 downto 6) = "00" then + port_bf3b_ulap_index <= cpu_do(5 downto 0); + end if; + end if; + end if; + end process; + + -- port ff3b write + -- mode group 00 palette writes handled by nextreg stream + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + port_ff3b_ulap_en <= '0'; + elsif port_ff3b_wr = '1' and port_bf3b_ulap_mode = "01" then + port_ff3b_ulap_en <= cpu_do(0); + elsif nr_68_we = '1' then + port_ff3b_ulap_en <= nr_wr_dat(3); + end if; + end if; + end process; + + -- port ff3b read + + process (i_CLK_28) + begin + if falling_edge(i_CLK_28) then + if port_bf3b_ulap_mode = "00" then + if ulap_palette_rd_dly = '1' then + port_ff3b_dat <= nr_ulatm_palette_dat(5 downto 3) & nr_ulatm_palette_dat(8 downto 6) & nr_ulatm_palette_dat(2 downto 1); + end if; + else + port_ff3b_dat <= "0000000" & port_ff3b_ulap_en; + end if; + end if; + end process; + + ulap_palette_rd <= '1' when port_ff3b_rd = '1' and port_bf3b_ulap_mode = "00" and nr_ulatm_we = '0' else '0'; + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + ulap_palette_rd_dly <= ulap_palette_rd; + ulap_palette_rd_done <= ulap_palette_rd or (port_ff3b_rd and ulap_palette_rd_done); + end if; + end process; + + -- At 28MHz, a copper write to the palette may delay a palette read past the end of an io cycle so insert a wait state for this case + + ulap_wait_n <= '0' when port_ff3b_rd = '1' and port_bf3b_ulap_mode = "00" and ulap_palette_rd_done = '0' else '1'; + + ------------------------------------------------------------ + -- TBBLUE REGISTRY ----------------------------------------- + ------------------------------------------------------------ + + -- Port 0x243B selects nextreg + -- Port 0x253B reads / writes selected nextreg + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + nr_register <= X"24"; -- protection against legacy programs accidentally hitting ports 0x243B, 0x253B + elsif port_243b_wr = '1' then + nr_register <= cpu_do; + end if; + end if; + end process; + + port_243b_dat <= nr_register; + + -- MMUs are set by nextreg and spectrum ports 1ffd, 7ffd, dffd, eff7 + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + MMU0 <= X"FF"; + MMU1 <= X"FF"; + MMU2 <= X"0A"; + MMU3 <= X"0B"; + MMU4 <= X"04"; + MMU5 <= X"05"; + MMU6 <= X"00"; + MMU7 <= X"01"; + elsif port_memory_change_dly = '1' then + + -- 1ffd, 7ffd, dffd, eff7 have been written to + + if port_1ffd_special = '1' then + + MMU0 <= X"0" & (port_1ffd_reg(2) or port_1ffd_reg(1)) & "00" & '0'; + MMU1 <= X"0" & (port_1ffd_reg(2) or port_1ffd_reg(1)) & "00" & '1'; + MMU2 <= X"0" & (port_1ffd_reg(2) or port_1ffd_reg(1)) & (port_1ffd_reg(2) and port_1ffd_reg(1)) & '1' & '0'; + MMU3 <= X"0" & (port_1ffd_reg(2) or port_1ffd_reg(1)) & (port_1ffd_reg(2) and port_1ffd_reg(1)) & '1' & '1'; + MMU4 <= X"0" & (port_1ffd_reg(2) or port_1ffd_reg(1)) & "10" & '0'; + MMU5 <= X"0" & (port_1ffd_reg(2) or port_1ffd_reg(1)) & "10" & '1'; + MMU6 <= X"0" & (not(port_1ffd_reg(2)) and port_1ffd_reg(1)) & "11" & '0'; + MMU7 <= X"0" & (not(port_1ffd_reg(2)) and port_1ffd_reg(1)) & "11" & '1'; + + else + + if port_eff7_reg_3 = '1' or (nr_8f_mapping_mode_profi = '1' and port_dffd_reg(4) = '1') then + + MMU0 <= X"00"; + MMU1 <= X"01"; + + else + + MMU0 <= X"FF"; + MMU1 <= X"FF"; + + end if; + + if nr_8f_mapping_mode_profi = '1' and port_dffd_reg(3) = '1' then + + MMU2 <= port_7ffd_bank & '0'; + MMU3 <= port_7ffd_bank & '1'; + + elsif nr_8f_mapping_mode_profi = '1' or port_1ffd_special_old = '1' then + + MMU2 <= X"0A"; + MMU3 <= X"0B"; + + end if; + + if nr_8f_mapping_mode_profi = '1' and port_dffd_reg_6 = '1' then + + MMU4 <= X"0C"; + MMU5 <= X"0D"; + + elsif nr_8f_mapping_mode_profi = '1' or port_1ffd_special_old = '1' then + + MMU4 <= X"04"; + MMU5 <= X"05"; + + end if; + + if nr_8f_mapping_mode_profi = '1' and port_dffd_reg(3) = '1' then + + MMU6 <= X"0E"; + MMU7 <= X"0F"; + + elsif port_1ffd_special_old = '1' or port_memory_ram_change_dly = '1' then + + MMU6 <= port_7ffd_bank & '0'; + MMU7 <= port_7ffd_bank & '1'; + + end if; + + end if; + + elsif nr_mmu_we = '1' then + case nr_mmu is + when "000" => MMU0 <= nr_wr_dat; + when "001" => MMU1 <= nr_wr_dat; + when "010" => MMU2 <= nr_wr_dat; + when "011" => MMU3 <= nr_wr_dat; + when "100" => MMU4 <= nr_wr_dat; + when "101" => MMU5 <= nr_wr_dat; + when "110" => MMU6 <= nr_wr_dat; + when others => MMU7 <= nr_wr_dat; + end case; + end if; + + end if; + end process; + + -- + -- Write Registry + -- + + -- Arbitrate access between cpu (out, nextreg) and copper + -- Must be mindful of 28MHz speed on cpu and dma; copper has highest priority + + copper_requester <= copper_dout_en; + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + copper_req_dly <= '0'; + else + copper_req_dly <= copper_requester; + end if; + end if; + end process; + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + copper_req <= '0'; + copper_nr_reg <= (others => '0'); + copper_nr_dat <= (others => '0'); + elsif copper_requester = '1' and copper_req_dly = '0' then + copper_req <= '1'; + copper_nr_reg <= '0' & copper_dout(14 downto 8); + copper_nr_dat <= copper_dout(7 downto 0); + else + copper_req <= '0'; + end if; + end if; + end process; + + cpu_requester_0 <= '1' when Z80N_dout_s = '1' and Z80N_command_s = NEXTREGW else '0'; + cpu_requester_1 <= port_253b_wr; + cpu_requester_2 <= '1' when port_ff3b_wr = '1' and port_bf3b_ulap_mode = "00" else '0'; + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + cpu_req_dly <= '0'; + else + cpu_req_dly <= cpu_requester_0 or cpu_requester_1 or cpu_requester_2 or (cpu_req and not cpu_served); + end if; + end if; + end process; + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + cpu_req <= '0'; + cpu_nr_reg <= (others => '0'); + cpu_nr_dat <= (others => '0'); + elsif cpu_served = '1' then + cpu_req <= '0'; + elsif cpu_req_dly = '0' and cpu_requester_0 = '1' then + cpu_req <= '1'; + cpu_nr_reg <= Z80N_data_s(15 downto 8); + cpu_nr_dat <= Z80N_data_s(7 downto 0); + elsif cpu_req_dly = '0' and cpu_requester_1 = '1' then + cpu_req <= '1'; + cpu_nr_reg <= nr_register; + cpu_nr_dat <= cpu_do; + elsif cpu_req_dly = '0' and cpu_requester_2 = '1' then + cpu_req <= '1'; + cpu_nr_reg <= X"FF"; -- shhh our little secret + cpu_nr_dat <= cpu_do(4 downto 2) & cpu_do(7 downto 5) & cpu_do(1 downto 0); + end if; + end if; + end process; + + nr_wr_en <= copper_req or cpu_req; + nr_wr_reg <= copper_nr_reg when copper_req = '1' else cpu_nr_reg; + nr_wr_dat <= copper_nr_dat when copper_req = '1' else cpu_nr_dat; + + cpu_served <= '1' when copper_req = '0' and cpu_req = '1' else '0'; + + -- Write Registers + + -- combinatorial + + process (nr_wr_en, nr_wr_reg) + begin + + nr_02_we <= '0'; + nr_05_we <= '0'; + nr_07_we <= '0'; + nr_08_we <= '0'; + nr_09_we <= '0'; + nr_22_we <= '0'; + nr_28_we <= '0'; + nr_29_we <= '0'; +-- nr_2a_we <= '0'; + nr_2b_we <= '0'; + nr_2c_we <= '0'; + nr_2d_we <= '0'; + nr_2e_we <= '0'; + nr_41_we <= '0'; + nr_44_we <= '0'; + nr_68_we <= '0'; + nr_69_we <= '0'; + nr_80_we <= '0'; + nr_8c_we <= '0'; + nr_8e_we <= '0'; + nr_8f_we <= '0'; + nr_c2_we <= '0'; + nr_c3_we <= '0'; + nr_c4_we <= '0'; + nr_c5_we <= '0'; + nr_c8_we <= '0'; + nr_c9_we <= '0'; + nr_ca_we <= '0'; + nr_ff_we <= '0'; + + nr_sprite_mirror_we <= '0'; + nr_sprite_mirror_index <= "111"; + + nr_mmu_we <= '0'; + + nr_copper_we <= '0'; + nr_copper_write_8 <= '0'; + + if nr_wr_en = '1' then + + case nr_wr_reg is + + when X"02" => nr_02_we <= '1'; + when X"05" => nr_05_we <= '1'; + when X"07" => nr_07_we <= '1'; + when X"08" => nr_08_we <= '1'; + when X"09" => nr_09_we <= '1'; + when X"22" => nr_22_we <= '1'; + when X"28" => nr_28_we <= '1'; + when X"29" => nr_29_we <= '1'; +-- when X"2A" => nr_2a_we <= '1'; + when X"2B" => nr_2b_we <= '1'; + when X"2C" => nr_2c_we <= '1'; + when X"2D" => nr_2d_we <= '1'; + when X"2E" => nr_2e_we <= '1'; + when X"34" => nr_sprite_mirror_we <= '1'; + + when X"35" | X"75" => + nr_sprite_mirror_we <= '1'; + nr_sprite_mirror_index <= "000"; + + when X"36" | X"76" => + nr_sprite_mirror_we <= '1'; + nr_sprite_mirror_index <= "001"; + + when X"37" | X"77" => + nr_sprite_mirror_we <= '1'; + nr_sprite_mirror_index <= "010"; + + when X"38" | X"78" => + nr_sprite_mirror_we <= '1'; + nr_sprite_mirror_index <= "011"; + + when X"39" | X"79" => + nr_sprite_mirror_we <= '1'; + nr_sprite_mirror_index <= "100"; + + when X"41" => nr_41_we <= '1'; + when X"44" => nr_44_we <= '1'; + + when X"50" | X"51" | X"52" | X"53" | X"54" | X"55" | X"56" | X"57" => + nr_mmu_we <= '1'; + + when X"60" => + nr_copper_we <= '1'; + nr_copper_write_8 <= '1'; + + when X"63" => nr_copper_we <= '1'; + when X"68" => nr_68_we <= '1'; + when X"69" => nr_69_we <= '1'; + when X"80" => nr_80_we <= '1'; + when X"8C" => nr_8c_we <= '1'; + when X"8E" => nr_8e_we <= '1'; + when X"8F" => nr_8f_we <= '1'; + when X"C2" => nr_c2_we <= '1'; + when X"C3" => nr_c3_we <= '1'; + when X"C4" => nr_c4_we <= '1'; + when X"C5" => nr_c5_we <= '1'; + when X"C8" => nr_c8_we <= '1'; + when X"C9" => nr_c9_we <= '1'; + when X"CA" => nr_ca_we <= '1'; + when X"FF" => nr_ff_we <= '1'; + + when others => null; + + end case; + + end if; + + end process; + + nr_sprite_mirror_inc <= nr_sprite_mirror_we and nr_wr_reg(6); + + nr_palette_we <= '1' when nr_41_we = '1' or (nr_44_we = '1' and nr_palette_sub_idx = '1') else '0'; + nr_palette_value <= (nr_wr_dat & (nr_wr_dat(1) or nr_wr_dat(0))) when (nr_41_we = '1' or nr_ff_we = '1') else (nr_stored_palette_value & nr_wr_dat(0)); + nr_palette_priority <= nr_wr_dat(7 downto 6) when nr_44_we = '1' else (others => '0'); + + nr_mmu <= nr_wr_reg(2 downto 0); + + -- state + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + + if reset = '1' then + + nr_02_generate_mf_nmi <= '0'; + nr_02_generate_divmmc_nmi <= '0'; + + nr_06_hotkey_cpu_speed_en <= '1'; + nr_06_hotkey_5060_en <= '1'; + + nr_08_contention_disable <= '0'; + + nr_09_sprite_tie <= '0'; + + nr_0b_joy_iomode_en <= '0'; + nr_0b_joy_iomode <= "00"; + nr_0b_joy_iomode_0 <= '1'; + + nr_12_layer2_active_bank <= "0001000"; + nr_13_layer2_shadow_bank <= "0001011"; + + nr_14_global_transparent_rgb <= X"E3"; + + nr_15_lores_en <= '0'; + nr_15_sprite_priority <= '0'; + nr_15_sprite_border_clip_en <= '0'; + nr_15_layer_priority <= (others => '0'); + nr_15_sprite_over_border_en <= '0'; + nr_15_sprite_en <= '0'; + + nr_16_layer2_scrollx <= (others => '0'); + + nr_17_layer2_scrolly <= (others => '0'); + + nr_18_layer2_clip_x1 <= X"00"; + nr_18_layer2_clip_x2 <= X"FF"; + nr_18_layer2_clip_y1 <= X"00"; + nr_18_layer2_clip_y2 <= X"BF"; + nr_18_layer2_clip_idx <= "00"; + + nr_19_sprite_clip_x1 <= X"00"; + nr_19_sprite_clip_x2 <= X"FF"; + nr_19_sprite_clip_y1 <= X"00"; + nr_19_sprite_clip_y2 <= X"BF"; + nr_19_sprite_clip_idx <= "00"; + + nr_1a_ula_clip_x1 <= X"00"; + nr_1a_ula_clip_x2 <= X"FF"; + nr_1a_ula_clip_y1 <= X"00"; + nr_1a_ula_clip_y2 <= X"BF"; + nr_1a_ula_clip_idx <= "00"; + + nr_1b_tm_clip_x1 <= X"00"; + nr_1b_tm_clip_x2 <= X"9F"; + nr_1b_tm_clip_y1 <= X"00"; + nr_1b_tm_clip_y2 <= X"FF"; + nr_1b_tm_clip_idx <= "00"; + + nr_22_line_interrupt_en <= '0'; + + nr_23_line_interrupt <= (others => '0'); + + nr_26_ula_scrollx <= X"00"; + + nr_27_ula_scrolly <= X"00"; + + nr_30_tm_scrollx <= (others => '0'); + + nr_31_tm_scrolly <= X"00"; + + nr_32_lores_scrollx <= X"00"; + + nr_33_lores_scrolly <= X"00"; + + nr_palette_idx <= X"00"; + nr_palette_sub_idx <= '0'; + + nr_42_ulanext_format <= X"07"; + + nr_43_palette_autoinc_disable <= '0'; + nr_43_palette_write_select <= "000"; + nr_43_active_sprite_palette <= '0'; + nr_43_active_layer2_palette <= '0'; + nr_43_active_ula_palette <= '0'; + nr_43_ulanext_en <= '0'; + + nr_stored_palette_value <= X"00"; + +-- nr_4a_fallback_rgb <= X"00"; + nr_4a_fallback_rgb <= X"E3"; + + nr_4b_sprite_transparent_index <= X"E3"; + + nr_4c_tm_transparent_index <= X"F"; + + nr_62_copper_mode <= "00"; + nr_copper_addr <= (others => '0'); + nr_copper_data_stored <= X"00"; + + nr_64_copper_offset <= (others => '0'); + + nr_68_ula_en <= '1'; + nr_68_blend_mode <= "00"; + nr_68_cancel_extended_keys <= '0'; + nr_68_ula_fine_scroll_x <= '0'; + nr_68_ula_stencil_mode <= '0'; + + nr_6a_lores_radastan <= '0'; + nr_6a_lores_palette_offset <= X"0"; + nr_6a_lores_radastan_xor <= '0'; + + nr_6b_tm_en <= '0'; + nr_6b_tm_control <= (others => '0'); + + nr_6c_tm_default_attr <= (others => '0'); + + nr_6e_tilemap_base_7 <= '0'; + nr_6e_tilemap_base <= "101100"; + + nr_6f_tilemap_tiles_7 <= '0'; + nr_6f_tilemap_tiles <= "001100"; + + nr_70_layer2_resolution <= "00"; + nr_70_layer2_palette_offset <= (others => '0'); + + nr_71_layer2_scrollx_msb <= '0'; + + if nr_85_internal_port_reset_type = '1' then + + nr_82_internal_port_enable <= (others => '1'); + nr_83_internal_port_enable <= (others => '1'); + nr_84_internal_port_enable <= (others => '1'); + nr_85_internal_port_enable <= (others => '1'); + + end if; + + if nr_89_bus_port_reset_type = '0' then + + nr_86_bus_port_enable <= (others => '1'); + nr_87_bus_port_enable <= (others => '1'); + nr_88_bus_port_enable <= (others => '1'); + nr_89_bus_port_enable <= (others => '1'); + + end if; + + nr_98_pi_gpio_o <= X"FF"; + nr_99_pi_gpio_o <= X"01"; + nr_9a_pi_gpio_o <= X"00"; + nr_9b_pi_gpio_o <= X"0"; + + nr_90_pi_gpio_o_en <= (others => '0'); + nr_91_pi_gpio_o_en <= (others => '0'); + nr_92_pi_gpio_o_en <= (others => '0'); + nr_93_pi_gpio_o_en <= (others => '0'); + + nr_a0_pi_peripheral_en <= (others => '0'); + nr_a2_pi_i2s_ctl <= (others => '0'); +-- nr_a3_pi_i2s_clkdiv <= X"0B"; -- ~44.1kHz + + nr_a8_esp_gpio0_en <= '0'; + nr_a9_esp_gpio0 <= '1'; + + nr_b8_divmmc_ep_0 <= X"83"; + nr_b9_divmmc_ep_valid_0 <= X"01"; + nr_ba_divmmc_ep_timing_0 <= X"00"; + nr_bb_divmmc_ep_1 <= X"CD"; + + nr_c0_im2_vector <= (others => '0'); + nr_c0_stackless_nmi <= '0'; + nr_c0_int_mode_pulse_0_im2_1 <= '0'; + + nr_c4_int_en_0_expbus <= '1'; + + nr_c6_int_en_2_654 <= (others => '0'); + nr_c6_int_en_2_210 <= (others => '0'); + + + nr_cc_dma_int_en_0_10 <= (others => '0'); + nr_cd_dma_int_en_1 <= (others => '0'); + nr_ce_dma_int_en_2_654 <= (others => '0'); + nr_ce_dma_int_en_2_210 <= (others => '0'); + + if nr_03_config_mode = '1' then + bootrom_en <= '1'; + end if; + + elsif nr_wr_en = '1' then + + case nr_wr_reg is + + when X"02" => +-- nr_02_we <= '1'; + nr_02_bus_reset <= nr_wr_dat(7); + nr_02_generate_mf_nmi <= nr_wr_dat(3); + nr_02_generate_divmmc_nmi <= nr_wr_dat(2); + + when X"03" => + bootrom_en <= '0'; + + if nr_wr_dat(7) = '1' and nr_03_user_dt_lock = '0' and nr_wr_dat(3) = '0' then + case nr_wr_dat(6 downto 4) is + when "000" => nr_03_machine_timing <= "001"; + when "001" => nr_03_machine_timing <= "001"; + when "010" => nr_03_machine_timing <= "010"; + when "011" => nr_03_machine_timing <= "011"; + when "100" => nr_03_machine_timing <= "100"; + when others => nr_03_machine_timing <= "011"; + end case; + end if; + + nr_03_user_dt_lock <= nr_03_user_dt_lock xor nr_wr_dat(3); + + if nr_03_config_mode = '1' then + case nr_wr_dat(2 downto 0) is + when "001" => nr_03_machine_type <= "001"; + when "010" => nr_03_machine_type <= "010"; + when "011" => nr_03_machine_type <= "011"; + when "100" => nr_03_machine_type <= "100"; + when others => nr_03_machine_type <= "000"; + end case; + end if; + + if nr_wr_dat(2 downto 0) = "111" then + nr_03_config_mode <= '1'; + elsif nr_wr_dat(2 downto 0) /= "000" then + nr_03_config_mode <= '0'; + end if; + + when X"04" => + nr_04_romram_bank <= nr_wr_dat(6 downto 0); + + when X"05" => + nr_05_joy0 <= nr_wr_dat(3) & nr_wr_dat(7 downto 6); + nr_05_joy1 <= nr_wr_dat(1) & nr_wr_dat(5 downto 4); +-- nr_05_we <= '1'; + + when X"06" => + nr_06_hotkey_cpu_speed_en <= nr_wr_dat(7); + nr_06_internal_speaker_beep <= nr_wr_dat(6); + nr_06_hotkey_5060_en <= nr_wr_dat(5); + nr_06_button_drive_nmi_en <= nr_wr_dat(4); + nr_06_button_m1_nmi_en <= nr_wr_dat(3); + if nr_03_config_mode = '1' then + nr_06_ps2_mode <= nr_wr_dat(2); + end if; + nr_06_psg_mode <= nr_wr_dat(1 downto 0); + +-- when X"07" => +-- nr_07_we <= '1'; + + when X"08" => + nr_08_contention_disable <= nr_wr_dat(6); + nr_08_psg_stereo_mode <= nr_wr_dat(5); + nr_08_internal_speaker_en <= nr_wr_dat(4); + nr_08_dac_en <= nr_wr_dat(3); + nr_08_port_ff_rd_en <= nr_wr_dat(2); + nr_08_psg_turbosound_en <= nr_wr_dat(1); + nr_08_keyboard_issue2 <= nr_wr_dat(0); +-- nr_08_we <= '1'; + + when X"09" => + nr_09_psg_mono <= nr_wr_dat(7 downto 5); + nr_09_sprite_tie <= nr_wr_dat(4); + nr_09_hdmi_audio_disable <= nr_09_hdmi_audio_disable or nr_wr_dat(2); +-- nr_09_we <= '1'; + + when X"0A" => + if nr_03_config_mode = '1' then + nr_0a_mf_type <= nr_wr_dat(7 downto 6); + end if; + nr_0a_divmmc_automap_en <= nr_wr_dat(4); + nr_0a_mouse_button_reverse <= nr_wr_dat(3); + nr_0a_mouse_dpi <= nr_wr_dat(1 downto 0); + + when X"0B" => + nr_0b_joy_iomode_en <= nr_wr_dat(7); + nr_0b_joy_iomode <= nr_wr_dat(5 downto 4); + nr_0b_joy_iomode_0 <= nr_wr_dat(0); + + when X"10" => + nr_10_flashboot <= nr_wr_dat(7); + if nr_03_config_mode = '1' then + nr_10_coreid <= nr_wr_dat(4 downto 0); + end if; + + when X"11" => + if nr_03_config_mode = '1' then + nr_11_video_timing <= nr_wr_dat(2 downto 0); + end if; + + when X"12" => + nr_12_layer2_active_bank <= nr_wr_dat(6 downto 0); + + when X"13" => + nr_13_layer2_shadow_bank <= nr_wr_dat(6 downto 0); + + when X"14" => + nr_14_global_transparent_rgb <= nr_wr_dat; + + when X"15" => + nr_15_lores_en <= nr_wr_dat(7); + nr_15_sprite_priority <= nr_wr_dat(6); + nr_15_sprite_border_clip_en <= nr_wr_dat(5); + nr_15_layer_priority <= nr_wr_dat(4 downto 2); + nr_15_sprite_over_border_en <= nr_wr_dat(1); + nr_15_sprite_en <= nr_wr_dat(0); + + when X"16" => + nr_16_layer2_scrollx <= nr_wr_dat; + + when X"17" => + nr_17_layer2_scrolly <= nr_wr_dat; + + when X"18" => + case nr_18_layer2_clip_idx is + when "00" => nr_18_layer2_clip_x1 <= nr_wr_dat; + when "01" => nr_18_layer2_clip_x2 <= nr_wr_dat; + when "10" => nr_18_layer2_clip_y1 <= nr_wr_dat; + when others => nr_18_layer2_clip_y2 <= nr_wr_dat; + end case; + nr_18_layer2_clip_idx <= nr_18_layer2_clip_idx + 1; + + when X"19" => + case nr_19_sprite_clip_idx is + when "00" => nr_19_sprite_clip_x1 <= nr_wr_dat; + when "01" => nr_19_sprite_clip_x2 <= nr_wr_dat; + when "10" => nr_19_sprite_clip_y1 <= nr_wr_dat; + when others => nr_19_sprite_clip_y2 <= nr_wr_dat; + end case; + nr_19_sprite_clip_idx <= nr_19_sprite_clip_idx + 1; + + when X"1A" => + case nr_1a_ula_clip_idx is + when "00" => nr_1a_ula_clip_x1 <= nr_wr_dat; + when "01" => nr_1a_ula_clip_x2 <= nr_wr_dat; + when "10" => nr_1a_ula_clip_y1 <= nr_wr_dat; + when others => nr_1a_ula_clip_y2 <= nr_wr_dat; + end case; + nr_1a_ula_clip_idx <= nr_1a_ula_clip_idx + 1; + + when X"1B" => + case nr_1b_tm_clip_idx is + when "00" => nr_1b_tm_clip_x1 <= nr_wr_dat; + when "01" => nr_1b_tm_clip_x2 <= nr_wr_dat; + when "10" => nr_1b_tm_clip_y1 <= nr_wr_dat; + when others => nr_1b_tm_clip_y2 <= nr_wr_dat; + end case; + nr_1b_tm_clip_idx <= nr_1b_tm_clip_idx + 1; + + when X"1C" => + if nr_wr_dat(0) = '1' then + nr_18_layer2_clip_idx <= "00"; + end if; + if nr_wr_dat(1) = '1' then + nr_19_sprite_clip_idx <= "00"; + end if; + if nr_wr_dat(2) = '1' then + nr_1a_ula_clip_idx <= "00"; + end if; + if nr_wr_dat(3) = '1' then + nr_1b_tm_clip_idx <= "00"; + end if; + + when X"22" => +-- nr_22_we <= '1'; + nr_22_line_interrupt_en <= nr_wr_dat(1); + nr_23_line_interrupt(8) <= nr_wr_dat(0); + + when X"23" => + nr_23_line_interrupt(7 downto 0) <= nr_wr_dat; + + when X"26" => + nr_26_ula_scrollx <= nr_wr_dat; + + when X"27" => + nr_27_ula_scrolly <= nr_wr_dat; + +-- when X"28" => +-- nr_28_we <= '1'; + +-- when X"29" => +-- nr_29_we <= '1'; + +-- when X"2A" => +-- nr_2a_we <= '1'; + +-- when X"2B" => +-- nr_2b_we <= '1'; + +-- when X"2C" => +-- nr_2c_we <= '1'; + +-- when X"2D" => +-- nr_2d_we <= '1'; + +-- when X"2E" => +-- nr_2e_we <= '1'; + + when X"2F" => + nr_30_tm_scrollx(9 downto 8) <= nr_wr_dat(1 downto 0); + + when X"30" => + nr_30_tm_scrollx(7 downto 0) <= nr_wr_dat; + + when X"31" => + nr_31_tm_scrolly <= nr_wr_dat; + + when X"32" => + nr_32_lores_scrollx <= nr_wr_dat; + + when X"33" => + nr_33_lores_scrolly <= nr_wr_dat; + +-- when X"34" => +-- nr_sprite_mirror_we <= '1'; +-- nr_sprite_mirror_index <= "111"; +-- +-- when X"35" | X"75" => +-- nr_sprite_mirror_we <= '1'; +-- nr_sprite_mirror_index <= "000"; +-- nr_sprite_mirror_inc <= nr_wr_reg(6); +-- +-- when X"36" | X"76" => +-- nr_sprite_mirror_we <= '1'; +-- nr_sprite_mirror_index <= "001"; +-- nr_sprite_mirror_inc <= nr_wr_reg(6); +-- +-- when X"37" | X"77" => +-- nr_sprite_mirror_we <= '1'; +-- nr_sprite_mirror_index <= "010"; +-- nr_sprite_mirror_inc <= nr_wr_reg(6); +-- +-- when X"38" | X"78" => +-- nr_sprite_mirror_we <= '1'; +-- nr_sprite_mirror_index <= "011"; +-- nr_sprite_mirror_inc <= nr_wr_reg(6); +-- +-- when X"39" | X"79" => +-- nr_sprite_mirror_we <= '1'; +-- nr_sprite_mirror_index <= "100"; +-- nr_sprite_mirror_inc <= nr_wr_reg(6); + + when X"40" => + nr_palette_idx <= nr_wr_dat; + nr_palette_sub_idx <= '0'; + + when X"41" => + if nr_43_palette_autoinc_disable = '0' then + nr_palette_idx <= nr_palette_idx + 1; + end if; + nr_palette_sub_idx <= '0'; +-- nr_41_we <= '1'; + + when X"42" => + nr_42_ulanext_format <= nr_wr_dat; + + when X"43" => + nr_43_palette_autoinc_disable <= nr_wr_dat(7); + nr_43_palette_write_select <= nr_wr_dat(6 downto 4); + nr_43_active_sprite_palette <= nr_wr_dat(3); + nr_43_active_layer2_palette <= nr_wr_dat(2); + nr_43_active_ula_palette <= nr_wr_dat(1); + nr_43_ulanext_en <= nr_wr_dat(0); + nr_palette_sub_idx <= '0'; + + when X"44" => + if nr_palette_sub_idx = '0' then + nr_stored_palette_value <= nr_wr_dat; + elsif nr_43_palette_autoinc_disable = '0' then + nr_palette_idx <= nr_palette_idx + 1; + end if; + nr_palette_sub_idx <= not nr_palette_sub_idx; +-- nr_44_we <= '1'; + + when X"4A" => + nr_4a_fallback_rgb <= nr_wr_dat; + + when X"4B" => + nr_4b_sprite_transparent_index <= nr_wr_dat; + + when X"4C" => + nr_4c_tm_transparent_index <= nr_wr_dat(3 downto 0); + +-- when X"50" | X"51" | X"52" | X"53" | X"54" | X"55" | X"56" | X"57" => +-- nr_mmu_we <= '1'; + + when X"60" => + if nr_copper_addr(0) = '0' then + nr_copper_data_stored <= nr_wr_dat; + end if; +-- nr_copper_we <= '1'; +-- nr_copper_write_8 <= '1'; + nr_copper_addr <= nr_copper_addr + 1; + + when X"61" => + nr_copper_addr(7 downto 0) <= nr_wr_dat; + + when X"62" => + nr_62_copper_mode <= nr_wr_dat(7 downto 6); + nr_copper_addr(10 downto 8) <= nr_wr_dat(2 downto 0); + + when X"63" => + if nr_copper_addr(0) = '0' then + nr_copper_data_stored <= nr_wr_dat; + end if; + nr_copper_addr <= nr_copper_addr + 1; +-- nr_copper_we <= '1'; +-- nr_copper_write_8 <= '0'; + + when X"64" => + nr_64_copper_offset <= nr_wr_dat; + + when X"68" => + nr_68_ula_en <= not nr_wr_dat(7); + nr_68_blend_mode <= nr_wr_dat(6 downto 5); + nr_68_cancel_extended_keys <= nr_wr_dat(4); +-- nr_68_ulap_en <= nr_wr_dat(3); + nr_68_ula_fine_scroll_x <= nr_wr_dat(2); + nr_68_ula_stencil_mode <= nr_wr_dat(0); + +-- when X"69" => +-- nr_69_we <= '1'; + + when X"6A" => + nr_6a_lores_radastan <= nr_wr_dat(5); + nr_6a_lores_radastan_xor <= nr_wr_dat(4); + nr_6a_lores_palette_offset <= nr_wr_dat(3 downto 0); + + when X"6B" => + nr_6b_tm_en <= nr_wr_dat(7); + nr_6b_tm_control <= nr_wr_dat(6 downto 0); + + when X"6C" => + nr_6c_tm_default_attr <= nr_wr_dat; + + when X"6E" => + nr_6e_tilemap_base_7 <= nr_wr_dat(7); + nr_6e_tilemap_base <= nr_wr_dat(5 downto 0); + + when X"6F" => + nr_6f_tilemap_tiles_7 <= nr_wr_dat(7); + nr_6f_tilemap_tiles <= nr_wr_dat(5 downto 0); + + when X"70" => + nr_70_layer2_resolution <= nr_wr_dat(5 downto 4); + nr_70_layer2_palette_offset <= nr_wr_dat(3 downto 0); + + when X"71" => + nr_71_layer2_scrollx_msb <= nr_wr_dat(0); + +-- when X"75" | X"76" | X"77" | X"78" | X"79" => +-- sprite mirror; + + when X"7F" => + nr_7f_user_register_0 <= nr_wr_dat; + +-- when X"80" => +-- nr_80_we <= '1'; + + when X"81" => + nr_81_expbus_ula_override <= nr_wr_dat(6); + nr_81_expbus_nmi_debounce_disable <= nr_wr_dat(5); + nr_81_expbus_clken <= nr_wr_dat(4); + nr_81_expbus_speed <= "00"; -- nr_wr_dat(1 downto 0); + + when X"82" => + nr_82_internal_port_enable <= nr_wr_dat; + + when X"83" => + nr_83_internal_port_enable <= nr_wr_dat; + + when X"84" => + nr_84_internal_port_enable <= nr_wr_dat; + + when X"85" => + nr_85_internal_port_enable <= nr_wr_dat(3 downto 0); + nr_85_internal_port_reset_type <= nr_wr_dat(7); + + when X"86" => + nr_86_bus_port_enable <= nr_wr_dat; + + when X"87" => + nr_87_bus_port_enable <= nr_wr_dat; + + when X"88" => + nr_88_bus_port_enable <= nr_wr_dat; + + when X"89" => + nr_89_bus_port_enable <= nr_wr_dat(3 downto 0); + nr_89_bus_port_reset_type <= nr_wr_dat(7); + + when X"8A" => + nr_8a_bus_port_propagate <= nr_wr_dat(5 downto 0); + +-- when X"8C" => +-- nr_8c_we <= '1'; + +-- when X"8E" => +-- nr_8e_we <= '1'; + +-- when X"8F" => +-- nr_8f_we <= '1'; + + when X"90" => + nr_90_pi_gpio_o_en <= nr_wr_dat(7 downto 2) & "00"; -- not enabling output on GPIO 1:0 + + when X"91" => + nr_91_pi_gpio_o_en <= nr_wr_dat; + + when X"92" => + nr_92_pi_gpio_o_en <= nr_wr_dat; + + when X"93" => + nr_93_pi_gpio_o_en <= nr_wr_dat(3 downto 0); + + when X"98" => + nr_98_pi_gpio_o <= nr_wr_dat; + + when X"99" => + nr_99_pi_gpio_o <= nr_wr_dat; + + when X"9A" => + nr_9a_pi_gpio_o <= nr_wr_dat; + + when X"9B" => + nr_9b_pi_gpio_o <= nr_wr_dat(3 downto 0); + + when X"A0" => + nr_a0_pi_peripheral_en <= nr_wr_dat; + + when X"A2" => + nr_a2_pi_i2s_ctl <= nr_wr_dat; + +-- when X"A3" => +-- nr_a3_pi_i2s_clkdiv <= nr_wr_dat; + + when X"A8" => + nr_a8_esp_gpio0_en <= nr_wr_dat(0); + + when X"A9" => + nr_a9_esp_gpio0 <= nr_wr_dat(0); + +-- when X"B0" => +-- read only extended keys + +-- when X"B1" => +-- read only extended keys + +-- when X"B2" => +-- read md pad extended buttons + + when X"B8" => + nr_b8_divmmc_ep_0 <= nr_wr_dat(7 downto 0); + + when X"B9" => + nr_b9_divmmc_ep_valid_0 <= nr_wr_dat(7 downto 0); + + when X"BA" => + nr_ba_divmmc_ep_timing_0 <= nr_wr_dat(7 downto 0); + + when X"BB" => + nr_bb_divmmc_ep_1 <= nr_wr_dat(7 downto 0); + + when X"C0" => + nr_c0_im2_vector <= nr_wr_dat(7 downto 5); + nr_c0_stackless_nmi <= nr_wr_dat(3); + nr_c0_int_mode_pulse_0_im2_1 <= nr_wr_dat(0); + +-- when X"C2" => +-- nr_c2_we <= '1'; + +-- when X"C3" => +-- nr_c3_we <= '1'; + + when X"C4" => +-- nr_c4_we <= '1'; + nr_c4_int_en_0_expbus <= nr_wr_dat(7); + nr_22_line_interrupt_en <= nr_wr_dat(1); + +-- when X"C5" => +-- nr_c5_we <= '1'; + + when X"C6" => + nr_c6_int_en_2_654 <= nr_wr_dat(6) & nr_wr_dat(5) & nr_wr_dat(4); + nr_c6_int_en_2_210 <= nr_wr_dat(2) & nr_wr_dat(1) & nr_wr_dat(0); + +-- when X"C8" => +-- nr_c8_we <= '1'; + +-- when X"C9" => +-- nr_c9_we <= '1'; + +-- when X"CA" => +-- nr_ca_we <= '1'; + + when X"CC" => + nr_cc_dma_int_en_0_10 <= nr_wr_dat(1 downto 0); + + when X"CD" => + nr_cd_dma_int_en_1 <= nr_wr_dat; + + when X"CE" => + nr_ce_dma_int_en_2_654 <= nr_wr_dat(6 downto 4); + nr_ce_dma_int_en_2_210 <= nr_wr_dat(2 downto 0); + +-- when X"FF" => +-- reserved for ula+ + + when others => + null; + + end case; + + end if; + + end if; + end process; + + -- Machine Type + + machine_type_48 <= '1' when nr_03_machine_type(2 downto 1) = "00" else '0'; -- 48k + machine_type_128 <= '1' when nr_03_machine_type = "010" or nr_03_machine_type = "100" else '0'; -- 128k or pentagon + machine_type_p3 <= '1' when nr_03_machine_type = "011" else '0'; -- +3 + + -- Machine Timing + + machine_timing_48 <= '1' when nr_03_machine_timing(2 downto 1) = "00" else '0'; + machine_timing_128 <= '1' when nr_03_machine_timing = "010" else '0'; + machine_timing_p3 <= '1' when nr_03_machine_timing = "011" else '0'; + machine_timing_pentagon <= '1' when nr_03_machine_timing = "100" else '0'; + + -- CPU Speed + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if reset = '1' then + nr_07_cpu_speed <= "00"; + elsif nr_07_we = '1' then + nr_07_cpu_speed <= nr_wr_dat(1 downto 0); + elsif hotkey_cpu_speed = '1' and nr_06_hotkey_cpu_speed_en = '1' then + nr_07_cpu_speed <= nr_07_cpu_speed + 1; + end if; + end if; + end process; + + process (i_CLK_CPU) + begin + if rising_edge(i_CLK_CPU) then + if reset = '1' then + + cpu_speed <= "00"; + eff_nr_08_contention_disable <= '0'; + + expbus_eff_en <= expbus_en; + expbus_eff_disable_io <= expbus_disable_io; + expbus_eff_disable_mem <= expbus_disable_mem; + expbus_eff_clken <= expbus_clken; + + elsif cpu_mreq_n = '1' and cpu_iorq_n = '1' and cpu_m1_n = '1' and dma_holds_bus = '0' then + + expbus_eff_en <= expbus_en; + expbus_eff_disable_io <= expbus_disable_io; + expbus_eff_disable_mem <= expbus_disable_mem; + expbus_eff_clken <= expbus_clken; + + if expbus_en = '0' then + cpu_speed <= nr_07_cpu_speed; + else + cpu_speed <= expbus_speed; + end if; + + if hc(8) = '1' then + eff_nr_08_contention_disable <= nr_08_contention_disable; + end if; + + end if; + end if; + end process; + + -- Various State + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if nr_05_we = '1' then + nr_05_5060 <= nr_wr_dat(2); + elsif hotkey_5060 = '1' and nr_06_hotkey_5060_en = '1' then + nr_05_5060 <= not nr_05_5060; + end if; + end if; + end process; + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if nr_05_we = '1' then + nr_05_scandouble_en <= nr_wr_dat(0); + elsif hotkey_scandouble = '1' then + nr_05_scandouble_en <= not nr_05_scandouble_en; + end if; + end if; + end process; + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if nr_09_we = '1' then + nr_09_scanlines <= nr_wr_dat(1 downto 0); + elsif hotkey_scanlines = '1' then + nr_09_scanlines <= nr_09_scanlines + 1; + end if; + end if; + end process; + + -- + -- Read Registry + -- + + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + port_253b_dat_0 <= port_253b_dat; + end if; + end process; + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + + case nr_register is + + when X"00" => + port_253b_dat <= std_logic_vector(g_machine_id); + + when X"01" => + port_253b_dat <= std_logic_vector(g_version); + + when X"02" => + port_253b_dat <= nr_02_bus_reset & "000" & nr_02_generate_mf_nmi & nr_02_generate_divmmc_nmi & nr_02_reset_type(1 downto 0); + + when X"03" => + port_253b_dat <= nr_palette_sub_idx & nr_03_machine_timing & nr_03_user_dt_lock & nr_03_machine_type; + + when X"05" => + port_253b_dat <= nr_05_joy0(1 downto 0) & nr_05_joy1(1 downto 0) & nr_05_joy0(2) & eff_nr_05_5060 & nr_05_joy1(2) & eff_nr_05_scandouble_en; + + when X"06" => + port_253b_dat <= nr_06_hotkey_cpu_speed_en & nr_06_internal_speaker_beep & nr_06_hotkey_5060_en & nr_06_button_drive_nmi_en & nr_06_button_m1_nmi_en & nr_06_ps2_mode & nr_06_psg_mode; + + when X"07" => + port_253b_dat <= "00" & cpu_speed & "00" & nr_07_cpu_speed; + + when X"08" => + port_253b_dat <= (not port_7ffd_locked) & eff_nr_08_contention_disable & nr_08_psg_stereo_mode & nr_08_internal_speaker_en & nr_08_dac_en & nr_08_port_ff_rd_en & nr_08_psg_turbosound_en & nr_08_keyboard_issue2; + + when X"09" => + port_253b_dat <= nr_09_psg_mono & nr_09_sprite_tie & '0' & nr_09_hdmi_audio_disable & eff_nr_09_scanlines; + + when X"0A" => + port_253b_dat <= nr_0a_mf_type & '0' & nr_0a_divmmc_automap_en & nr_0a_mouse_button_reverse & '0' & nr_0a_mouse_dpi; + + when X"0B" => + port_253b_dat <= nr_0b_joy_iomode_en & '0' & nr_0b_joy_iomode & "000" & nr_0b_joy_iomode_0; + + when X"0E" => + port_253b_dat <= std_logic_vector(g_sub_version); + + when X"10" => + port_253b_dat <= "000000" & i_SPKEY_BUTTONS(1 downto 0); + + when X"11" => + port_253b_dat <= "00000" & nr_11_video_timing; + + when X"12" => + port_253b_dat <= '0' & nr_12_layer2_active_bank; + + when X"13" => + port_253b_dat <= '0' & nr_13_layer2_shadow_bank; + + when X"14" => + port_253b_dat <= nr_14_global_transparent_rgb; + + when X"15" => + port_253b_dat <= nr_15_lores_en & nr_15_sprite_priority & nr_15_sprite_border_clip_en & nr_15_layer_priority & nr_15_sprite_over_border_en & nr_15_sprite_en; + + when X"16" => + port_253b_dat <= nr_16_layer2_scrollx; + + when X"17" => + port_253b_dat <= nr_17_layer2_scrolly; + + when X"18" => + case nr_18_layer2_clip_idx is + when "00" => port_253b_dat <= nr_18_layer2_clip_x1; + when "01" => port_253b_dat <= nr_18_layer2_clip_x2; + when "10" => port_253b_dat <= nr_18_layer2_clip_y1; + when others => port_253b_dat <= nr_18_layer2_clip_y2; + end case; + + when X"19" => + case nr_19_sprite_clip_idx is + when "00" => port_253b_dat <= nr_19_sprite_clip_x1; + when "01" => port_253b_dat <= nr_19_sprite_clip_x2; + when "10" => port_253b_dat <= nr_19_sprite_clip_y1; + when others => port_253b_dat <= nr_19_sprite_clip_y2; + end case; + + when X"1A" => + case nr_1a_ula_clip_idx is + when "00" => port_253b_dat <= nr_1a_ula_clip_x1; + when "01" => port_253b_dat <= nr_1a_ula_clip_x2; + when "10" => port_253b_dat <= nr_1a_ula_clip_y1; + when others => port_253b_dat <= nr_1a_ula_clip_y2; + end case; + + when X"1B" => + case nr_1b_tm_clip_idx is + when "00" => port_253b_dat <= nr_1b_tm_clip_x1; + when "01" => port_253b_dat <= nr_1b_tm_clip_x2; + when "10" => port_253b_dat <= nr_1b_tm_clip_y1; + when others => port_253b_dat <= nr_1b_tm_clip_y2; + end case; + + when X"1C" => + port_253b_dat <= nr_1b_tm_clip_idx & nr_1a_ula_clip_idx & nr_19_sprite_clip_idx & nr_18_layer2_clip_idx; + + when X"1E" => + port_253b_dat <= "0000000" & cvc(8); + + when X"1F" => + port_253b_dat <= std_logic_vector(cvc(7 downto 0)); + + when X"22" => + port_253b_dat <= (not pulse_int_n) & "0000" & port_ff_interrupt_disable & nr_22_line_interrupt_en & nr_23_line_interrupt(8); + + when X"23" => + port_253b_dat <= nr_23_line_interrupt(7 downto 0); + + when X"26" => + port_253b_dat <= nr_26_ula_scrollx; + + when X"27" => + port_253b_dat <= nr_27_ula_scrolly; + + when X"28" => + port_253b_dat <= nr_stored_palette_value; + + when X"2C" => + port_253b_dat <= pi_audio_L(9 downto 2); + nr_2d_i2s_sample <= pi_audio_L(1 downto 0); + + when X"2D" => + port_253b_dat <= nr_2d_i2s_sample & "000000"; + + when X"2E" => + port_253b_dat <= pi_audio_R(9 downto 2); + nr_2d_i2s_sample <= pi_audio_R(1 downto 0); + + when X"2F" => + port_253b_dat <= "000000" & nr_30_tm_scrollx(9 downto 8); + + when X"30" => + port_253b_dat <= nr_30_tm_scrollx(7 downto 0); + + when X"31" => + port_253b_dat <= nr_31_tm_scrolly; + + when X"32" => + port_253b_dat <= nr_32_lores_scrollx; + + when X"33" => + port_253b_dat <= nr_33_lores_scrolly; + + when X"34" => + port_253b_dat <= '0' & sprite_mirror_id; + + when X"40" => + port_253b_dat <= nr_palette_idx; + + when X"41" => + port_253b_dat <= nr_palette_dat(8 downto 1); + + when X"42" => + port_253b_dat <= nr_42_ulanext_format; + + when X"43" => + port_253b_dat <= nr_43_palette_autoinc_disable & nr_43_palette_write_select & nr_43_active_sprite_palette & nr_43_active_layer2_palette & nr_43_active_ula_palette & nr_43_ulanext_en; + + when X"44" => + port_253b_dat <= nr_palette_dat(10 downto 9) & "00000" & nr_palette_dat(0); + + when X"4A" => + port_253b_dat <= nr_4a_fallback_rgb; + + when X"4B" => + port_253b_dat <= nr_4b_sprite_transparent_index; + + when X"4C" => + port_253b_dat <= "0000" & nr_4c_tm_transparent_index; + + when X"50" => + port_253b_dat <= MMU0; + + when X"51" => + port_253b_dat <= MMU1; + + when X"52" => + port_253b_dat <= MMU2; + + when X"53" => + port_253b_dat <= MMU3; + + when X"54" => + port_253b_dat <= MMU4; + + when X"55" => + port_253b_dat <= MMU5; + + when X"56" => + port_253b_dat <= MMU6; + + when X"57" => + port_253b_dat <= MMU7; + + when X"61" => + port_253b_dat <= nr_copper_addr(7 downto 0); + + when X"62" => + port_253b_dat <= nr_62_copper_mode & "000" & nr_copper_addr(10 downto 8); + + when X"64"=> + port_253b_dat <= nr_64_copper_offset; + + when X"68" => + port_253b_dat <= (not nr_68_ula_en) & nr_68_blend_mode & nr_68_cancel_extended_keys & port_ff3b_ulap_en & nr_68_ula_fine_scroll_x & '0' & nr_68_ula_stencil_mode; + + when X"69" => + port_253b_dat <= port_123b_layer2_en & port_7ffd_shadow & port_ff_reg(5 downto 0); + + when X"6A" => + port_253b_dat <= "00" & nr_6a_lores_radastan & nr_6a_lores_radastan_xor & nr_6a_lores_palette_offset; + + when X"6B" => + port_253b_dat <= nr_6b_tm_en & nr_6b_tm_control; + + when X"6C" => + port_253b_dat <= nr_6c_tm_default_attr; + + when X"6E" => + port_253b_dat <= nr_6e_tilemap_base_7 & '0' & nr_6e_tilemap_base; + + when X"6F" => + port_253b_dat <= nr_6f_tilemap_tiles_7 & '0' & nr_6f_tilemap_tiles; + + when X"70" => + port_253b_dat <= "00" & nr_70_layer2_resolution & nr_70_layer2_palette_offset; + + when X"71" => + port_253b_dat <= "0000000" & nr_71_layer2_scrollx_msb; + + when X"7F" => + port_253b_dat <= nr_7f_user_register_0; + + when X"80" => + port_253b_dat <= nr_80_expbus; + + when X"81" => + port_253b_dat <= i_BUS_ROMCS_n & nr_81_expbus_ula_override & nr_81_expbus_nmi_debounce_disable & nr_81_expbus_clken & "00" & nr_81_expbus_speed; + + when X"82" => + port_253b_dat <= nr_82_internal_port_enable; + + when X"83" => + port_253b_dat <= nr_83_internal_port_enable; + + when X"84" => + port_253b_dat <= nr_84_internal_port_enable; + + when X"85" => + port_253b_dat <= nr_85_internal_port_reset_type & "000" & nr_85_internal_port_enable; + + when X"86" => + port_253b_dat <= nr_86_bus_port_enable; + + when X"87" => + port_253b_dat <= nr_87_bus_port_enable; + + when X"88" => + port_253b_dat <= nr_88_bus_port_enable; + + when X"89" => + port_253b_dat <= nr_89_bus_port_reset_type & "000" & nr_89_bus_port_enable; + + when X"8A" => + port_253b_dat <= "00" & nr_8a_bus_port_propagate; + + when X"8C" => + port_253b_dat <= nr_8c_altrom; + + when X"8E" => + port_253b_dat <= port_dffd_reg(0) & port_7ffd_reg(2 downto 0) & '1' & port_1ffd_reg(0) & port_1ffd_reg(2) & ((port_7ffd_reg(4) and not port_1ffd_reg(0)) or (port_1ffd_reg(1) and port_1ffd_reg(0))); + + when X"8F" => + port_253b_dat <= "000000" & nr_8f_mapping_mode; + + when X"90" => + port_253b_dat <= nr_90_pi_gpio_o_en; + + when X"91" => + port_253b_dat <= nr_91_pi_gpio_o_en; + + when X"92" => + port_253b_dat <= nr_92_pi_gpio_o_en; + + when X"93" => + port_253b_dat <= "0000" & nr_93_pi_gpio_o_en; + + when X"98" => + port_253b_dat <= i_GPIO(7 downto 0); + + when X"99" => + port_253b_dat <= i_GPIO(15 downto 8); + + when X"9A" => + port_253b_dat <= i_GPIO(23 downto 16); + + when X"9B" => + port_253b_dat <= "0000" & i_GPIO(27 downto 24); + + when X"A0" => + port_253b_dat <= "00" & nr_a0_pi_peripheral_en(5 downto 3) & "00" & nr_a0_pi_peripheral_en(0); + + when X"A2" => + port_253b_dat <= nr_a2_pi_i2s_ctl(7 downto 6) & '0' & nr_a2_pi_i2s_ctl(4 downto 2) & '1' & nr_a2_pi_i2s_ctl(0); + +-- when X"A3" => +-- port_253b_dat <= nr_a3_pi_i2s_clkdiv; + + when X"A8" => + port_253b_dat <= "0000000" & nr_a8_esp_gpio0_en; + + when X"A9" => + port_253b_dat <= "00000" & i_ESP_GPIO_20(2) & '0' & i_ESP_GPIO_20(0); + + -- i_KBD_EXTENDED_KEYS(15 downto 8) = DOWN LEFT RIGHT DELETE . , " ; + -- i_KBD_EXTENDED_KEYS( 7 downto 0) = EDIT BREAK INV TRU GRAPH CAPSLOCK UP EXTEND + + when X"B0" => + -- ; " , . UP DOWN LEFT RIGHT + port_253b_dat <= i_KBD_EXTENDED_KEYS(8) & i_KBD_EXTENDED_KEYS(9) & i_KBD_EXTENDED_KEYS(10) & i_KBD_EXTENDED_KEYS(11) & i_KBD_EXTENDED_KEYS(1) & i_KBD_EXTENDED_KEYS(15 downto 13); + + when X"B1" => + -- DELETE EDIT BREAK INV TRU GRAPH CAPSLOCK EXTEND + port_253b_dat <= i_KBD_EXTENDED_KEYS(12) & i_KBD_EXTENDED_KEYS(7 downto 2) & i_KBD_EXTENDED_KEYS(0); + + when X"B2" => + port_253b_dat <= i_JOY_RIGHT(10 downto 7) & i_JOY_LEFT(10 downto 7); + + when X"B8" => + port_253b_dat <= nr_b8_divmmc_ep_0; + + when X"B9" => + port_253b_dat <= nr_b9_divmmc_ep_valid_0; + + when X"BA" => + port_253b_dat <= nr_ba_divmmc_ep_timing_0; + + when X"BB" => + port_253b_dat <= nr_bb_divmmc_ep_1; + + when X"C0" => + port_253b_dat <= nr_c0_im2_vector & '0' & nr_c0_stackless_nmi & "00" & nr_c0_int_mode_pulse_0_im2_1; + + when X"C2" => + port_253b_dat <= nr_c2_retn_address_lsb; + + when X"C3" => + port_253b_dat <= nr_c3_retn_address_msb; + + when X"C4" => + port_253b_dat <= nr_c4_int_en_0_expbus & "00000" & ula_int_en; + + when X"C5" => + port_253b_dat <= ctc_int_en; + + when X"C6" => + port_253b_dat <= '0' & nr_c6_int_en_2_654 & '0' & nr_c6_int_en_2_210; + + when X"C8" => + port_253b_dat <= "000000" & im2_int_status(0) & im2_int_status(11); + + when X"C9" => + port_253b_dat <= im2_int_status(10 downto 3); + + when X"CA" => + port_253b_dat <= '0' & im2_int_status(13) & im2_int_status(2) & im2_int_status(2) & '0' & im2_int_status(12) & im2_int_status(1) & im2_int_status(1); + + when X"CC" => + port_253b_dat <= "000000" & nr_cc_dma_int_en_0_10; + + when X"CD" => + port_253b_dat <= nr_cd_dma_int_en_1; + + when X"CE" => + port_253b_dat <= '0' & nr_ce_dma_int_en_2_654 & '0' & nr_ce_dma_int_en_2_210; + + when others => + port_253b_dat <= (others => '0'); + + end case; + + end if; + end process; + + ------------------------------------------------------------ + -- PS/2 KEYMAP & KEY JOYSTICK & HOT KEYS ------------------- + ------------------------------------------------------------ + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if nr_28_we = '1' then + nr_keymap_sel <= nr_wr_dat(7); + nr_keymap_addr(8) <= nr_wr_dat(0); + elsif nr_29_we = '1' then + nr_keymap_addr(7 downto 0) <= nr_wr_dat; + elsif nr_2b_we = '1' then + nr_keymap_addr <= nr_keymap_addr + 1; + end if; + end if; + end process; + +-- process (i_CLK_28) +-- begin +-- if rising_edge(i_CLK_28) then +-- if nr_2a_we = '1' then +-- nr_keymap_dat_msb <= nr_wr_dat(0); +-- end if; +-- end if; +-- end process; + + nr_keymap_we <= nr_2b_we and not nr_keymap_sel; + nr_joymap_we <= nr_2b_we and nr_keymap_sel; +-- nr_keymap_dat <= nr_keymap_dat_msb & nr_wr_dat; + nr_keymap_dat <= nr_wr_dat; + + -- Hot Keys + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + hotkeys_1 <= hotkeys_0; + hotkeys_0 <= (i_SPKEY_FUNCTION(10) or nr_02_generate_divmmc_nmi) & (i_SPKEY_FUNCTION(9) or nr_02_generate_mf_nmi) & i_SPKEY_FUNCTION(8 downto 1); + end if; + end process; + + hotkey_hard_reset <= hotkeys_0(1) and not hotkeys_1(1); -- F1 + hotkey_scandouble <= hotkeys_0(2) and not hotkeys_1(2); -- F2 + hotkey_5060 <= hotkeys_0(3) and not hotkeys_1(3); -- F3 + hotkey_soft_reset <= hotkeys_0(4) and not hotkeys_1(4); -- F4 + hotkey_expbus_enable <= hotkeys_0(5) and not hotkeys_1(5); -- F5 + hotkey_expbus_disable <= hotkeys_0(6) and not hotkeys_1(6); -- F6 + hotkey_scanlines <= hotkeys_0(7) and not hotkeys_1(7); -- F7 + hotkey_cpu_speed <= hotkeys_0(8) and not hotkeys_1(8); -- F8 + hotkey_m1 <= hotkeys_0(9) and not hotkeys_1(9); -- F9 + hotkey_drive <= hotkeys_0(10) and not hotkeys_1(10) and port_divmmc_io_en; -- F10 + + nr_02_soft_reset <= (hotkey_soft_reset and not nr_03_config_mode) or (nr_02_we and nr_wr_dat(0)); + nr_02_hard_reset <= hotkey_hard_reset or (nr_02_we and nr_wr_dat(1)); + + ------------------------------------------------------------ + -- AUDIO --------------------------------------------------- + ------------------------------------------------------------ + + -- AY-8910 x 3 (turbosound) + + audio_ay_reset <= '1' when reset = '1' or nr_06_psg_mode = "11" else '0'; + + turbosound_mod: entity work.turbosound + port map + ( + clock_i => i_CLK_28, + clock_en_i => i_CLK_PSG_EN, + + reset_i => audio_ay_reset, + + aymode_i => nr_06_psg_mode(0), + turbosound_en_i => nr_08_psg_turbosound_en, + + psg_reg_addr_i => port_fffd_wr, + psg_reg_wr_i => port_bffd_wr, + psg_d_i => cpu_do, + psg_d_o_reg_i => port_bff5, + psg_d_o => psg_dat, + + mono_mode_i => nr_09_psg_mono, + stereo_mode_i => nr_08_psg_stereo_mode, + +-- port_a_i => (others => '1'), -- AYs have internal pullups +-- port_a_o => open, + + pcm_ay_L_o => pcm_ay_L, + pcm_ay_R_o => pcm_ay_R + ); + + process (i_CLK_CPU) + begin + if falling_edge(i_CLK_CPU) then + port_fffd_dat <= psg_dat; + end if; + end process; + + -- todo: bit-banged 128 serial? + -- for now only exposing R14 of AY#0 on port_a + -- + -- I/O Port A from AY chip is connected to rs232 / keypad on the 128 + -- http://www.matthew-wilson.net/spectrum/rom/128_ROM0.pdf + -- + -- Bit 0: KEYPAD CTS (out) - 0=Spectrum ready to receive, 1=Busy + -- Bit 1: KEYPAD RXD (out) - 0=Transmit high bit, 1=Transmit low bit + -- Bit 2: RS232 CTS (out) - 0=Spectrum ready to receive, 1=Busy + -- Bit 3: RS232 RXD (out) - 0=Transmit high bit, 1=Transmit low bit + -- Bit 4: KEYPAD DTR (in) - 0=Keypad ready for data, 1=Busy + -- Bit 5: KEYPAD TXD (in) - 0=Receive high bit, 1=Receive low bit + -- Bit 6: RS232 DTR (in) - 0=Device ready for data, 1=Busy + -- Bit 7: RS232 TXD (in) - 0=Receive high bit, 1=Receive low bit + + -- DAC x 4 (soundrive, covox, specdrum, etc) + + soundrive_mod: entity work.soundrive + port map + ( + clock_i => i_CLK_28, + reset_i => reset or not nr_08_dac_en, + + cpu_d_i => cpu_do, + + -- left + + chA_wr_i => port_dac_A_wr, + chB_wr_i => port_dac_B_wr, + + -- right + + chC_wr_i => port_dac_C_wr, + chD_wr_i => port_dac_D_wr, + + -- nextreg mirrors + + nr_mono_we_i => nr_2d_we, + nr_left_we_i => nr_2c_we, + nr_right_we_i => nr_2e_we, + + nr_audio_dat_i => nr_wr_dat, + + -- pcm audio out + + pcm_L_o => pcm_dac_L, + pcm_R_o => pcm_dac_R + ); + + -- i2s pi audio + + i2s_mod : entity work.i2s_transmitter + port map + ( + i_reset => reset or not pi_i2s_en, + + i_CLK => i_CLK_28, +-- i_CLK_DIV => nr_a3_pi_i2s_clkdiv, + +-- i_slave_mode => pi_i2s_slave, + + -- slave mode (incoming clock signals, synchronized) + + i_i2s_sck => pi_si2s_sck, + i_i2s_ws => pi_si2s_ws, + + -- outgoing clock signals (master or slave) + + o_i2s_sck => pi_mi2s_sck, + o_i2s_ws => pi_mi2s_ws, + o_i2s_wsp => open, + + -- zx next audio to pi + + i_audio_zxn_L => pcm_audio_L, + i_audio_zxn_R => pcm_audio_R, + o_i2s_sd_pi => pi_i2s_sd_o, + + -- pi audio to zx next + + i_i2s_sd_pi => pi_i2s_sd_i, + o_audio_pi_L => pi_i2s_audio_L, + o_audio_pi_R => pi_i2s_audio_R + ); + + -- todo: switch to signed audio + -- todo: power of two volume adjustment on all inputs (?) + + port_fe_mic_final <= port_fe_mic xor i_AUDIO_EAR xor pi_fe_ear; + internal_speaker_beep_exclusive <= nr_06_internal_speaker_beep and nr_08_internal_speaker_en; + + audio_mixer_mod: entity work.audio_mixer + port map + ( + clock_i => i_CLK_28, + reset_i => reset, + + -- beeper and tape + + ear_i => port_fe_ear and not internal_speaker_beep_exclusive, + mic_i => port_fe_mic_final and not internal_speaker_beep_exclusive, + + -- ay + + ay_L_i => pcm_ay_L, + ay_R_i => pcm_ay_R, + + -- dac + + dac_L_i => pcm_dac_L, + dac_R_i => pcm_dac_R, + + -- pi i2s audio + + pi_i2s_L_i => pi_audio_L, + pi_i2s_R_i => pi_audio_R, + + -- mixed pcm audio out + + pcm_L_o => pcm_audio_L, + pcm_R_o => pcm_audio_R + ); + + ------------------------------------------------------------ + -- VIDEO --------------------------------------------------- + ------------------------------------------------------------ + + -- The normal resolution pixel clock operates at 7MHz. On the rising edge of i_CLK_7, the horizontal and vertical pixel counters + -- are updated in the timing module. Video output for that pixel position is expected to be generated before the next rising edge. + -- + -- The high resolution pixel clock operates on the rising edge of the 14MHz clock i_CLK_14. i_CLK_14 and i_CLK_7 are generated + -- in phase by the top level pll module. This means the rising edge of i_CLK_7 aligns with a rising edge of i_CLK_14. + -- In hi-res, pixels are generated on every rising edge of i_CLK_14, ie two pixels are generated for every normal resolution pixel. + -- + -- Sub-pixel timing at 28MHz is synchronized with i_CLK_7. The sub-pixel counter counts 0-3 for each rising edge of i_CLK_28 inside + -- a single i_CLK_7 period. The transition from 3 to 0 corresponds to a rising edge of i_CLK_7. Transitions from 3 to 0 and from + -- 1 to 2 correspond to a rising edge of i_CLK_14. ("sc") + + -- + -- VIDEO MEMORY + -- + + -- ULA BANK 5 (16k) + -- the cpu/lores share access through one port and the ula/tilemap share the other + -- ula contention is implemented by holding the cpu clock high in clock generation in the top level module + + bank5_ram: entity work.dpram2 + generic map ( + addr_width_g => 14, + data_width_g => 8 + ) + port map ( + -- CPU port + clk_a_i => i_CLK_28, + we_i => cpu_bank5_sched and cpu_bank5_we, + addr_a_i => vram_bank5_a0, + data_a_i => cpu_do, + data_a_o => vram_bank5_do0, + -- ULA port + clk_b_i => i_CLK_28_n, + addr_b_i => vram_bank_a1, + data_b_o => vram_bank5_do1 + ); + + -- Arbitrate cpu,lores on first port + + cpu_bank5_req <= cpu_bank5_rd or cpu_bank5_we; + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + cpu_bank5_req_dly <= cpu_bank5_req; + cpu_bank5_sched_dly <= cpu_bank5_sched; + end if; + end process; + + cpu_bank5_sched <= '1' when cpu_bank5_req_dly = '0' and cpu_bank5_req = '1' else '0'; + + process (i_CLK_28) + begin + if falling_edge(i_CLK_28) then + if cpu_bank5_sched_dly = '1' then + cpu_bank5_do <= vram_bank5_do0; + end if; + end if; + end process; + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if sc = "00" then -- one 28MHz period past rising edge of i_CLK_7 + lores_vram_req <= '1'; + elsif lores_vram_ack = '1' then + lores_vram_req <= '0'; + end if; + end if; + end process; + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + lores_vram_ack_dly <= lores_vram_ack; + end if; + end process; + + process (i_CLK_28) + begin + if falling_edge(i_CLK_28) then + if lores_vram_ack_dly = '1' then + lores_vram_di <= vram_bank5_do0; + end if; + end if; + end process; + + lores_vram_ack <= '1' when cpu_bank5_sched = '0' and lores_vram_req = '1' else '0'; + vram_bank5_a0 <= (sram_A20_A13(0) & cpu_a(12 downto 0)) when cpu_bank5_sched = '1' else lores_addr; + + -- Arbitrate ula,tilemap on second port in both banks 5 and 7 + + ula_bank_req <= ula_vram_rd; + + process (i_CLK_28_n) + begin + if rising_edge(i_CLK_28_n) then + ula_bank_req_dly <= ula_bank_req; + ula_bank_sched_dly <= ula_bank_sched; + end if; + end process; + + ula_bank_sched <= '1' when ula_bank_req_dly = '0' and ula_bank_req = '1' else '0'; + + process (i_CLK_28_n) + begin + if falling_edge(i_CLK_28_n) then + if ula_bank_sched_dly = '1' then + if ula_vram_shadow = '0' then + ula_bank_do <= vram_bank5_do1; + else + ula_bank_do <= vram_bank7_do; + end if; + end if; + end if; + end process; + + vram_bank_a1 <= ula_vram_a when ula_bank_sched = '1' else tm_vram_a; + ula_vram_di <= ula_bank_do; + + tm_vram_di <= vram_bank5_do1 when tm_mem_bank7 = '0' else vram_bank7_do; + tm_vram_ack <= '1' when ula_bank_sched = '0' and tm_vram_rd = '1' else '0'; + + -- ULA BANK 7 (8k only due to limited bram resources) + -- cpu has access through one port and the ula/tilemap through the other. + -- A consequence of only having the first 8k here is that the timex video modes cannot be placed in bank 7. + + bank7_ram: entity work.dpram2 + generic map ( + addr_width_g => 13, + data_width_g => 8 + ) + port map ( + -- CPU port + clk_a_i => i_CLK_28, + we_i => cpu_bank7_we, + addr_a_i => cpu_a(12 downto 0), + data_a_i => cpu_do, + data_a_o => cpu_bank7_do, + -- ULA port + clk_b_i => i_CLK_28_n, + addr_b_i => vram_bank_a1(12 downto 0), + data_b_o => vram_bank7_do + ); + + -- + -- VIDEO TIMING & VBI/LINE INTERRUPT GENERATION + -- + + -- changes to video timing occur during vsync + + video_timing_change <= '1' when (eff_nr_05_5060 /= nr_05_5060) or (eff_nr_05_scandouble_en /= nr_05_scandouble_en) or ((eff_nr_03_machine_timing /= nr_03_machine_timing) and (nr_11_video_timing /= "111")) else '0'; + + process (i_CLK_7) + begin + if rising_edge(i_CLK_7) then + if rgb_vsync_n_o = '0' and video_timing_change = '1' then + eff_nr_05_5060 <= nr_05_5060; + eff_nr_05_scandouble_en <= nr_05_scandouble_en; + eff_nr_03_machine_timing <= nr_03_machine_timing; + video_timing_change_d <= '1'; + else + video_timing_change_d <= '0'; + end if; + end if; + end process; + + process (i_CLK_7) + begin + if rising_edge(i_CLK_7) then + if rgb_vsync_n_o = '0' then + eff_nr_09_scanlines <= nr_09_scanlines; + end if; + end if; + end process; + + ula_int_en <= nr_22_line_interrupt_en & (not port_ff_interrupt_disable); + + timing_mod: entity work.zxula_timing + port map ( + clock_i => i_CLK_7, + clock_x4_i => i_CLK_28, + reset_conter_i => video_timing_change_d, + mode_i => eff_nr_03_machine_timing, + video_timing_i => nr_11_video_timing, + vf50_60_i => eff_nr_05_5060, + cu_offset_i => nr_64_copper_offset, + hcount_o => hc, + vcount_o => vc, + phcount_o => phc, + whcount_o => whc, + wvcount_o => wvc, + cvcount_o => cvc, + sc_o => sc, + hsync_n_o => rgb_hsync_n, + vsync_n_o => rgb_vsync_n, + hblank_n_o => rgb_hblank_n, + vblank_n_o => rgb_vblank_n, + lint_ctrl_i => ula_int_en, + lint_line_i => nr_23_line_interrupt, + ula_int_o => ula_int_pulse, + line_int_o => line_int_pulse + ); + + -- + -- VIDEO PIPELINE STAGE 0 - gather pixels + -- Time = +0 (rising edge on i_CLK_7) + -- + + -- Hold pixel parameters constant for one pixel period + + process (i_CLK_7) + begin + if rising_edge(i_CLK_7) then + + lores_scroll_x_0 <= nr_32_lores_scrollx; + lores_scroll_y_0 <= nr_33_lores_scrolly; + + ula_clip_x1_0 <= nr_1a_ula_clip_x1; + ula_clip_x2_0 <= nr_1a_ula_clip_x2; + ula_clip_y1_0 <= nr_1a_ula_clip_y1; + + if nr_1a_ula_clip_y2(7 downto 6) = "11" then + ula_clip_y2_0 <= X"BF"; + else + ula_clip_y2_0 <= nr_1a_ula_clip_y2; + end if; + +-- lores_clip_x1_0 <= nr_1d_lores_clip_x1; +-- lores_clip_x2_0 <= nr_1d_lores_clip_x2; +-- lores_clip_y1_0 <= nr_1d_lores_clip_y1; +-- +-- if nr_1d_lores_clip_y2(7 downto 6) = "11" then +-- lores_clip_y2_0 <= X"BF"; +-- else +-- lores_clip_y2_0 <= nr_1d_lores_clip_y2; +-- end if; + + lores_mode_0 <= nr_6a_lores_radastan; + lores_dfile_0 <= port_ff_screen_mode(0) xor nr_6a_lores_radastan_xor; -- radastan can coexist with standard timex display files + lores_palette_offset_0 <= nr_6a_lores_palette_offset; + + layer_priorities_0 <= nr_15_layer_priority; + + end if; + end process; + + process (i_CLK_14) + begin + if rising_edge(i_CLK_14) then + if sc(0) = '1' then + + ula_en_0 <= nr_68_ula_en; + ula_stencil_mode_0 <= nr_68_ula_stencil_mode; + ula_blend_mode_0 <= nr_68_blend_mode; + + ulanext_en_0 <= nr_43_ulanext_en; + ulanext_format_0 <= nr_42_ulanext_format; + ulap_en_0 <= port_ff3b_ulap_en; + + lores_en_0 <= nr_15_lores_en; + + sprite_en_0 <= nr_15_sprite_en; + tm_en_0 <= nr_6b_tm_en; + + transparent_rgb_0 <= nr_14_global_transparent_rgb; + fallback_rgb_0 <= nr_4a_fallback_rgb; + + ula_palette_select_0 <= nr_43_active_ula_palette; + tm_palette_select_0 <= nr_6b_tm_control(4); + layer2_palette_select_0 <= nr_43_active_layer2_palette; + sprite_palette_select_0 <= nr_43_active_sprite_palette; + + end if; + end if; + end process; + + -- Pixels are generated by modules + -- ... + + -- Hold pixel values for next stage of pipeline + + process (i_CLK_7) + begin + if rising_edge(i_CLK_7) then + + lores_pixel_1 <= lores_pixel; + lores_pixel_en_1a <= lores_pixel_en; + + layer2_pixel_en_1 <= layer2_pixel_en; + + sprite_pixel_1 <= sprite_pixel; + sprite_pixel_en_1a <= sprite_pixel_en; + + end if; + end process; + + process (i_CLK_14) + begin + if rising_edge(i_CLK_14) then + + ula_pixel_1 <= ula_pixel; + ula_select_bgnd_1 <= ula_select_bgnd; + + tm_pixel_1 <= tm_pixel; + tm_pixel_en_1 <= tm_pixel_en; + tm_pixel_below_1 <= (tm_pixel_below and tm_en_1a) or ((not nr_6b_tm_control(0)) and not tm_en_1a); + tm_pixel_textmode_1 <= tm_pixel_textmode; + + layer2_pixel_1 <= layer2_pixel; + + end if; + end process; + + -- Hold video parameters for next stage of pipeline + + process (i_CLK_7) + begin + if rising_edge(i_CLK_7) then + + ula_border_1 <= ula_border; + ula_clipped_1 <= ula_clipped; + + layer_priorities_1 <= layer_priorities_0; + + rgb_vsync_n_1 <= rgb_vsync_n; + rgb_vblank_n_1 <= rgb_vblank_n; + rgb_hblank_n_1 <= rgb_hblank_n; + rgb_hsync_n_1 <= rgb_hsync_n; + + end if; + end process; + + process (i_CLK_14) + begin + if rising_edge(i_CLK_14) then + + ula_en_1 <= ula_en_1a; + ula_en_1a <= ula_en_0; + + ula_stencil_mode_1 <= ula_stencil_mode_1a; + ula_stencil_mode_1a <= ula_stencil_mode_0; + + ula_blend_mode_1 <= ula_blend_mode_1a; + ula_blend_mode_1a <= ula_blend_mode_0; + + lores_en_1 <= lores_en_1a; + lores_en_1a <= lores_en_0; + + sprite_en_1 <= sprite_en_1a; + sprite_en_1a <= sprite_en_0; + + tm_en_1 <= tm_en_1a; + tm_en_1a <= tm_en_0; + + transparent_rgb_1 <= transparent_rgb_1a; + transparent_rgb_1a <= transparent_rgb_0; + + fallback_rgb_1 <= fallback_rgb_1a; + fallback_rgb_1a <= fallback_rgb_0; + + ula_palette_select_1 <= ula_palette_select_1a; + ula_palette_select_1a <= ula_palette_select_0; + + tm_palette_select_1 <= tm_palette_select_1a; + tm_palette_select_1a <= tm_palette_select_0; + + layer2_palette_select_1 <= layer2_palette_select_1a; + layer2_palette_select_1a <= layer2_palette_select_0; + + sprite_palette_select_1 <= sprite_palette_select_1a; + sprite_palette_select_1a <= sprite_palette_select_0; + + end if; + end process; + + lores_pixel_en_1 <= lores_pixel_en_1a and lores_en_1; + sprite_pixel_en_1 <= sprite_pixel_en_1a and sprite_en_1; + + -- + -- VIDEO PIPELINE STAGE 1 - palette lookup + -- Time = +1 (i_CLK_7) + -- + + -- Pixel data from ula / lores, tilemap, sprites, layer 2 is passed through palette memory to + -- generate 9-bit rgb values. + -- + -- The ula / tilemap share one 1k x 9 memory to save on bram resources. These are hi-res pixels. + -- Sprites / layer 2 share one 1k x 16 memory to accommodate layer order promotion bits. These are lo-res pixels. + -- + -- Memory is edge triggered write, read edge triggered with data coming out a short time later + + -- todo: move extra bit in 1k x 16 memory to lut to free up a bram + -- todo: investigate giving every layer priority bits + + nr_palette_index <= nr_43_palette_write_select(1) & nr_43_palette_write_select(2) & nr_palette_idx; + nr_palette_dat <= (nr_ulatm_palette_dat(15 downto 14) & nr_ulatm_palette_dat(8 downto 0)) when (nr_43_palette_write_select(1) = nr_43_palette_write_select(0)) else (nr_l2s_palette_dat(15 downto 14) & nr_l2s_palette_dat(8 downto 0)); + + -- ULA / Tilemap palette + + nr_ulatm_we <= (nr_palette_we and not (nr_43_palette_write_select(1) xor nr_43_palette_write_select(0))) or nr_ff_we; + nr_palette_index_utm <= ('0' & nr_43_palette_write_select(2) & "11" & port_bf3b_ulap_index) when (ulap_palette_rd = '1' or nr_ff_we = '1') else nr_palette_index; + + palette_utm: entity work.dpram2 + generic map + ( + addr_width_g => 10, + data_width_g => 16 + ) + port map + ( + -- nextreg write + clk_a_i => i_CLK_28, + we_i => nr_ulatm_we, + addr_a_i => nr_palette_index_utm, + data_a_i => nr_palette_priority & "00000" & nr_palette_value, + data_a_o => nr_ulatm_palette_dat, + -- ula / tm + clk_b_i => i_CLK_28_n, + addr_b_i => ulatm_pixel_1, + data_b_o => ulatm_rgb_1 + ); + + ulalores_pixel_1 <= lores_pixel_1 when lores_pixel_en_1 = '1' else ula_pixel_1; + ulatm_pixel_1 <= ('0' & ula_palette_select_1 & ulalores_pixel_1) when sc(0) = '0' else ('1' & tm_palette_select_1 & tm_pixel_1); + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if sc(0) = '0' then + if lores_pixel_en_1 = '1' or ula_select_bgnd_1 = '0' then + ula_rgb_1 <= ulatm_rgb_1(8 downto 0); + else + ula_rgb_1 <= fallback_rgb_1 & (fallback_rgb_1(1) or fallback_rgb_1(0)); + end if; + end if; + end if; + end process; + + -- send rgb to next stage + + process (i_CLK_14) + begin + if rising_edge(i_CLK_14) then + ula_rgb_2 <= ula_rgb_1; + tm_rgb_2 <= ulatm_rgb_1(8 downto 0); + end if; + end process; + +-- lores_rgb_2 <= ula_rgb_2; + + -- Layer 2 / Sprite palette + -- move the extra layer priority bits to lut ram if possible + + nr_l2s_palette_we <= nr_palette_we and (nr_43_palette_write_select(1) xor nr_43_palette_write_select(0)); + + palette_l2s: entity work.dpram2 + generic map + ( + addr_width_g => 10, + data_width_g => 16 + ) + port map + ( + -- nextreg write + clk_a_i => i_CLK_28, + we_i => nr_l2s_palette_we, + addr_a_i => nr_palette_index, + data_a_i => nr_palette_priority & "00000" & nr_palette_value, + data_a_o => nr_l2s_palette_dat, + -- layer 2 / sprite + clk_b_i => i_CLK_28_n, + addr_b_i => l2s_pixel_1, + data_b_o => l2s_prgb_1 + ); + + l2s_pixel_1 <= ('0' & layer2_palette_select_1 & layer2_pixel_1) when sc(0) = '0' else ('1' & sprite_palette_select_1 & sprite_pixel_1); + + process (i_CLK_28) + begin + if rising_edge(i_CLK_28) then + if sc(0) = '0' then + layer2_prgb_1 <= l2s_prgb_1(15) & l2s_prgb_1(8 downto 0); + end if; + end if; + end process; + + -- send prgb to next stage + + process (i_CLK_14) + begin + if rising_edge(i_CLK_14) then + layer2_rgb_2 <= layer2_prgb_1(8 downto 0); + layer2_priority_2 <= layer2_prgb_1(9); + sprite_rgb_2 <= l2s_prgb_1(8 downto 0); + end if; + end process; + + -- Hold video parameters for next stage of pipeline + + process (i_CLK_14) + begin + if rising_edge(i_CLK_14) then + + ula_en_2 <= ula_en_1; + ula_border_2 <= ula_border_1; + ula_clipped_2 <= ula_clipped_1 and not lores_pixel_en_1; + ula_stencil_mode_2 <= ula_stencil_mode_1; + ula_blend_mode_2 <= ula_blend_mode_1; + +-- lores_en_2 <= lores_pixel_en_1; + + tm_en_2 <= tm_en_1; + tm_pixel_en_2 <= tm_pixel_en_1; + tm_pixel_below_2 <= tm_pixel_below_1; + tm_pixel_textmode_2 <= tm_pixel_textmode_1; + + layer2_pixel_en_2 <= layer2_pixel_en_1; + + sprite_pixel_en_2 <= sprite_pixel_en_1; + + transparent_rgb_2 <= transparent_rgb_1; + fallback_rgb_2 <= fallback_rgb_1; + + layer_priorities_2 <= layer_priorities_1; + + rgb_vsync_n_2 <= rgb_vsync_n_1; + rgb_vblank_n_2 <= rgb_vblank_n_1; + rgb_hblank_n_2 <= rgb_hblank_n_1; + rgb_hsync_n_2 <= rgb_hsync_n_1; + + end if; + end process; + + -- + -- VIDEO PIPELINE STAGE 2 - final pixel generation + -- Time = +1.5 (i_CLK_7) = +3 (i_CLK_14) + -- Now synchronized to i_CLK_14, important for retiming at next stage + -- + + -- stop pretending lores and ula are separate + -- only one of these can get a colour, the ula contains the lores colour when lores is active + + ula_mix_transparent <= '1' when (ula_rgb_2(8 downto 1) = transparent_rgb_2) or (ula_clipped_2 = '1') else '0'; + ula_mix_rgb <= ula_rgb_2 when ula_mix_transparent = '0' else "000000000"; + + ula_transparent <= '1' when (ula_mix_transparent = '1') or (ula_en_2 = '0') else '0'; + ula_rgb <= ula_rgb_2 when ula_transparent = '0' else "000000000"; + +-- lores_transparent <= '1' when (lores_rgb_2(8 downto 1) = transparent_rgb_2) or (ula_clipped_2 = '1') else '0'; +-- lores_rgb <= lores_rgb_2 when lores_transparent = '0' else "000000000"; + + tm_transparent <= '1' when (tm_pixel_en_2 = '0') or (tm_pixel_textmode_2 = '1' and tm_rgb_2(8 downto 1) = transparent_rgb_2) or (tm_en_2 = '0') else '0'; + tm_rgb <= tm_rgb_2 when tm_transparent = '0' else "000000000"; + + stencil_transparent <= '1' when (ula_transparent = '1') or (tm_transparent = '1') else '0'; + stencil_rgb <= (ula_rgb and tm_rgb) when stencil_transparent = '0' else "000000000"; + + ulatm_transparent <= '1' when (ula_transparent = '1') and (tm_transparent = '1') else '0'; + ulatm_rgb <= tm_rgb when (tm_transparent = '0') and (tm_pixel_below_2 = '0' or ula_transparent = '1') else ula_rgb; + + sprite_transparent <= not sprite_pixel_en_2; + sprite_rgb <= sprite_rgb_2 when sprite_transparent = '0' else "000000000"; + + layer2_transparent <= '1' when (layer2_rgb_2(8 downto 1) = transparent_rgb_2) or (layer2_pixel_en_2 = '0') else '0'; + layer2_rgb <= layer2_rgb_2 when layer2_transparent = '0' else "000000000"; + layer2_priority <= layer2_priority_2 when layer2_transparent = '0' else '0'; + + process (ula_stencil_mode_2, ula_en_2, tm_en_2, stencil_rgb, stencil_transparent, ulatm_rgb, ulatm_transparent) + begin +-- if lores_en_2 = '1' and lores_transparent = '0' then +-- ula_final_rgb <= lores_rgb; +-- ula_final_transparent <= lores_transparent; + if ula_stencil_mode_2 = '1' and ula_en_2 = '1' and tm_en_2 = '1' then + ula_final_rgb <= stencil_rgb; + ula_final_transparent <= stencil_transparent; + else + ula_final_rgb <= ulatm_rgb; + ula_final_transparent <= ulatm_transparent; + end if; + end process; + + process (ula_blend_mode_2, ula_mix_transparent, ula_mix_rgb, ula_final_transparent, ula_final_rgb, tm_transparent, tm_rgb, tm_pixel_below_2, ula_transparent, ula_rgb, layer_priorities_2) + begin + case ula_blend_mode_2 is + when "00" => + mix_rgb <= ula_mix_rgb; + mix_rgb_transparent <= ula_mix_transparent; + mix_top_transparent <= tm_transparent or tm_pixel_below_2; + mix_top_rgb <= tm_rgb; + mix_bot_transparent <= tm_transparent or not tm_pixel_below_2; + mix_bot_rgb <= tm_rgb; + when "10" => + mix_rgb <= ula_final_rgb; + mix_rgb_transparent <= ula_final_transparent; + mix_top_transparent <= '1'; + mix_top_rgb <= tm_rgb; + mix_bot_transparent <= '1'; + mix_bot_rgb <= tm_rgb; + when "11" => + mix_rgb <= tm_rgb; + mix_rgb_transparent <= tm_transparent; + mix_top_transparent <= ula_transparent or not tm_pixel_below_2; + mix_top_rgb <= ula_rgb; + mix_bot_transparent <= ula_transparent or tm_pixel_below_2; + mix_bot_rgb <= ula_rgb; + when others => + mix_rgb <= (others => '0'); + mix_rgb_transparent <= '1'; + if tm_pixel_below_2 = '1' then + mix_top_transparent <= ula_transparent; + mix_top_rgb <= ula_rgb; + mix_bot_transparent <= tm_transparent; + mix_bot_rgb <= tm_rgb; + else + mix_top_transparent <= tm_transparent; + mix_top_rgb <= tm_rgb; + mix_bot_transparent <= ula_transparent; + mix_bot_rgb <= ula_rgb; + end if; + end case; + end process; + + -- Implement SLU Ordering + -- todo: insert layer priority shuffle-memory + + -- in: + -- ula_final_rgb: layer U colour + -- ula_final_transparent: layer U transparent + -- mix_rgb: layer U colour for modes 6 & 7 + -- sprite_rgb: layer S colour + -- sprite_transparent: layer S transparent + -- layer2_rgb: layer L colour + -- layer2_transparent: layer L transparent + -- layer2_priority: layer L promotion bit and non-transparent + + process (layer2_rgb, mix_rgb, fallback_rgb_2, layer_priorities_2, layer2_priority, sprite_transparent, sprite_rgb, + layer2_transparent, ula_final_transparent, ula_final_rgb, ula_border_2, tm_transparent, + mix_top_transparent, mix_top_rgb, mix_bot_transparent, mix_bot_rgb, mix_rgb_transparent) + variable mixer_r_t : std_logic_vector(3 downto 0); + variable mixer_g_t : std_logic_vector(3 downto 0); + variable mixer_b_t : std_logic_vector(3 downto 0); + begin + + mixer_r_t := ('0' & layer2_rgb(8 downto 6)) + ('0' & mix_rgb(8 downto 6)); + mixer_g_t := ('0' & layer2_rgb(5 downto 3)) + ('0' & mix_rgb(5 downto 3)); + mixer_b_t := ('0' & layer2_rgb(2 downto 0)) + ('0' & mix_rgb(2 downto 0)); + + -- Layer priorities - nextreg 0x15 bits 4-2 + + -- 000 S L U + -- 001 L S U + -- 010 S U L + -- 011 L U S + -- 100 U S L + -- 101 U L S + + rgb_out_2 <= fallback_rgb_2 & (fallback_rgb_2(1) or fallback_rgb_2(0)); + + case layer_priorities_2 is + + when "000" => -- SLU + + if layer2_priority = '1' then + rgb_out_2 <= layer2_rgb; + elsif sprite_transparent = '0' then + rgb_out_2 <= sprite_rgb; + elsif layer2_transparent = '0' then + rgb_out_2 <= layer2_rgb; + elsif ula_final_transparent = '0' then + rgb_out_2 <= ula_final_rgb; + end if; + + when "001" => -- LSU + + if layer2_transparent = '0' then + rgb_out_2 <= layer2_rgb; + elsif sprite_transparent = '0' then + rgb_out_2 <= sprite_rgb; + elsif ula_final_transparent = '0' then + rgb_out_2 <= ula_final_rgb; + end if; + + when "010" => -- SUL + + if layer2_priority = '1' then + rgb_out_2 <= layer2_rgb; + elsif sprite_transparent = '0' then + rgb_out_2 <= sprite_rgb; + elsif ula_final_transparent = '0' then + rgb_out_2 <= ula_final_rgb; + elsif layer2_transparent = '0' then + rgb_out_2 <= layer2_rgb; + end if; + + when "011" => -- LUS + + if layer2_transparent = '0' then + rgb_out_2 <= layer2_rgb; + elsif ula_final_transparent = '0' and not (ula_border_2 = '1' and tm_transparent = '1' and sprite_transparent = '0') then + rgb_out_2 <= ula_final_rgb; + elsif sprite_transparent = '0' then + rgb_out_2 <= sprite_rgb; + end if; + + when "100" => -- USL + + if layer2_priority = '1' then + rgb_out_2 <= layer2_rgb; + elsif ula_final_transparent = '0' and not (ula_border_2 = '1' and tm_transparent = '1' and sprite_transparent = '0') then + rgb_out_2 <= ula_final_rgb; + elsif sprite_transparent = '0' then + rgb_out_2 <= sprite_rgb; + elsif layer2_transparent = '0' then + rgb_out_2 <= layer2_rgb; + end if; + + when "101" => -- ULS + + if layer2_priority = '1' then + rgb_out_2 <= layer2_rgb; + elsif ula_final_transparent = '0' and not (ula_border_2 = '1' and tm_transparent = '1' and sprite_transparent = '0') then + rgb_out_2 <= ula_final_rgb; + elsif layer2_transparent = '0' then + rgb_out_2 <= layer2_rgb; + elsif sprite_transparent = '0' then + rgb_out_2 <= sprite_rgb; + end if; + + when "110" => -- (U|T)S(T|U)(B+L) + + if mixer_r_t(3) = '1' then -- greater than 7 + mixer_r_t := "0111"; + end if; + + if mixer_g_t(3) = '1' then -- greater than 7 + mixer_g_t := "0111"; + end if; + + if mixer_b_t(3) = '1' then -- greater than 7 + mixer_b_t := "0111"; + end if; + + if layer2_priority = '1' then + rgb_out_2 <= mixer_r_t(2 downto 0) & mixer_g_t(2 downto 0) & mixer_b_t(2 downto 0); + elsif mix_top_transparent = '0' then + rgb_out_2 <= mix_top_rgb; + elsif sprite_transparent = '0' then + rgb_out_2 <= sprite_rgb; + elsif mix_bot_transparent = '0' then + rgb_out_2 <= mix_bot_rgb; + elsif layer2_transparent = '0' then + rgb_out_2 <= mixer_r_t(2 downto 0) & mixer_g_t(2 downto 0) & mixer_b_t(2 downto 0); + end if; + + when others => -- (U|T)S(T|U)(B+L-5) + + if mix_rgb_transparent = '0' then + + if mixer_r_t <= 4 then + mixer_r_t := "0000"; + elsif mixer_r_t(3 downto 2) = "11" then + mixer_r_t := "0111"; + else + mixer_r_t := mixer_r_t + "1011"; -- minus 5 + end if; + + if mixer_g_t <= 4 then + mixer_g_t := "0000"; + elsif mixer_g_t(3 downto 2) = "11" then + mixer_g_t := "0111"; + else + mixer_g_t := mixer_g_t + "1011"; -- minus 5 + end if; + + if mixer_b_t <= 4 then + mixer_b_t := "0000"; + elsif mixer_b_t(3 downto 2) = "11" then + mixer_b_t := "0111"; + else + mixer_b_t := mixer_b_t + "1011"; -- minus 5 + end if; + + end if; + + if layer2_priority = '1' then + rgb_out_2 <= mixer_r_t(2 downto 0) & mixer_g_t(2 downto 0) & mixer_b_t(2 downto 0); + elsif mix_top_transparent = '0' then + rgb_out_2 <= mix_top_rgb; + elsif sprite_transparent = '0' then + rgb_out_2 <= sprite_rgb; + elsif mix_bot_transparent = '0' then + rgb_out_2 <= mix_bot_rgb; + elsif layer2_transparent = '0' then + rgb_out_2 <= mixer_r_t(2 downto 0) & mixer_g_t(2 downto 0) & mixer_b_t(2 downto 0); + end if; + + end case; + + end process; + + rgb_out_2a <= (others => '0') when (rgb_vblank_n_2 = '0' or rgb_hblank_n_2 = '0') else rgb_out_2; + + -- + -- VIDEO PIPELINE STAGE 3 - generate rgb signals + -- Add three cycle delay so that xst can retime registers backward into stage 2 + -- + + process (i_CLK_14) + begin + if rising_edge(i_CLK_14) then + + rgb_vsync_n_6 <= rgb_vsync_n_5; + rgb_vsync_n_5 <= rgb_vsync_n_4; + rgb_vsync_n_4 <= rgb_vsync_n_3; + rgb_vsync_n_3 <= rgb_vsync_n_2; + + rgb_vblank_n_6 <= rgb_vblank_n_5; + rgb_vblank_n_5 <= rgb_vblank_n_4; + rgb_vblank_n_4 <= rgb_vblank_n_3; + rgb_vblank_n_3 <= rgb_vblank_n_2; + + rgb_hblank_n_6 <= rgb_hblank_n_5; + rgb_hblank_n_5 <= rgb_hblank_n_4; + rgb_hblank_n_4 <= rgb_hblank_n_3; + rgb_hblank_n_3 <= rgb_hblank_n_2; + + rgb_hsync_n_6 <= rgb_hsync_n_5; + rgb_hsync_n_5 <= rgb_hsync_n_4; + rgb_hsync_n_4 <= rgb_hsync_n_3; + rgb_hsync_n_3 <= rgb_hsync_n_2; + + rgb_out_6 <= rgb_out_5; + rgb_out_5 <= rgb_out_4; + rgb_out_4 <= rgb_out_3; + rgb_out_3 <= rgb_out_2a; + + end if; + end process; + + process (i_CLK_28) + begin + if falling_edge(i_CLK_28) then + + rgb_vsync_n_7 <= rgb_vsync_n_6; + rgb_vblank_n_7 <= rgb_vblank_n_6; + rgb_hblank_n_7 <= rgb_hblank_n_6; + rgb_hsync_n_7 <= rgb_hsync_n_6; + rgb_out_7 <= rgb_out_6; + + end if; + end process; + + rgb_vsync_n_o <= rgb_vsync_n_7; + rgb_vblank_n_o <= rgb_vblank_n_7; + rgb_hblank_n_o <= rgb_hblank_n_7; + rgb_hsync_n_o <= rgb_hsync_n_7; + rgb_out_o <= rgb_out_7; + rgb_csync_n_o <= rgb_vsync_n_7 and rgb_hsync_n_7; + +end architecture; diff --git a/sys/alsa.sv b/sys/alsa.sv new file mode 100644 index 0000000..9034389 --- /dev/null +++ b/sys/alsa.sv @@ -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 diff --git a/sys/arcade_video.v b/sys/arcade_video.v new file mode 100644 index 0000000..ff554a5 --- /dev/null +++ b/sys/arcade_video.v @@ -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 diff --git a/sys/ascal.vhd b/sys/ascal.vhd new file mode 100644 index 0000000..a65ccc1 --- /dev/null +++ b/sys/ascal.vhd @@ -0,0 +1,2561 @@ +-------------------------------------------------------------------------------- +-- AVALON SCALER +-------------------------------------------------------------------------------- +-- TEMLIB 2018 - 2020 +-------------------------------------------------------------------------------- +-- This code can be freely distributed and used for any purpose, but, if you +-- find any bug, or want to suggest an enhancement, you ought to send a mail +-- to info@temlib.org. +-------------------------------------------------------------------------------- + +-- Features +-- - Arbitrary output video format +-- - Autodetect input image size or fixed window +-- - Progressive and interlaced input +-- - Interpolation +-- Upscaling : Nearest, Bilinear, Sharp Bilinear, Bicubic, Polyphase +-- Downscaling : Nearest, Bilinear +-- - Avalon bus interface with 128 or 64 bits DATA +-- - Optional triple buffering +-- - Support for external low lag syntonization + +-------------------------------------------- +-- Downscaling +-- - Horizontal and vertical up-/down-scaling are independant. +-- - Downscaling, H and/or V, supports only nearest-neighbour and bilinear +-- filtering. +-- - For interlaced video, when the vertical size is lower than a deinterlaced +-- frame size (2x half-frame), the scaler processes only half-frames +-- and upscales (when the output size is between 1x an 2x) or downscales (size +-- below 1x) them. + +-------------------------------------------- +-- 5 clock domains +-- i_xxx : Input video +-- o_xxx : Output video +-- avl_xxx : Avalon memory bus +-- poly_xxx : Polyphase filters memory +-- pal_xxx : Framebuffer mode 8bpp palette. + +-------------------------------------------- +-- O_FB_FORMAT : Framebuffer 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) +-- [5] : TBD + +-------------------------------------------- +-- Image header. When HEADER = TRUE +-- Header Address = RAMBASE +-- Image Address = RAMBASE + HEADER_SIZE + +-- Header (Bytes. Big Endian.) +-- 0 : Type = 1 +-- 1 : Pixel format +-- 0 : 16 bits/pixel, RGB : RRRRRGGGGGGBBBBB +-- 1 : 24 bits/pixel, RGB +-- 2 : 32 bits/pixel, RGB0 + +-- 3:2 : Header size : Offset to start of picture (= N_BURST). 12 bits +-- 5:4 : Attributes +-- b0 ; Interlaced +-- b1 : Field number +-- b2 : Horizontal downscaled +-- b3 : Vertical downscaled +-- b4 : Triple buffered +-- b7-5 : Frame counter +-- 7:6 : Image width. Pixels. 12 bits +-- 9:8 : Image height. Pixels. 12 bits +-- 11:10 : Line length. Bytes. +-- 13:12 : Output width. Pixels. 12 bits +-- 15:14 : Output height. Pixels. 12 bits +-------------------------------------------- + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +-- MODE[2:0] +-- 000 : Nearest +-- 001 : Bilinear +-- 010 : Sharp Bilinear +-- 011 : Bicubic +-- 100 : Polyphase +-- 101 : TBD +-- 110 : TBD +-- 111 : TBD + +-- MODE[3] +-- 0 : Direct. Single framebuffer. +-- 1 : Triple buffering + +-- MODE[4] : TBD + +-- MASK : Enable / Disable selected interpoler +-- 0:Nearest 1:Bilinear 2:SharpBilinear 3:Bicubic 4:Polyphase +-- RAMBASE : RAM base address for framebuffer +-- RAMSIZE : RAM allocated for one framebuffer (needs x3 if triple-buffering) +-- Must be a power of two +-- INTER : True=Autodetect interlaced video False=Force progressive scan +-- HEADER : True=Add image properties header +-- PALETTE : Enable palette for framebuffer 8bpp mode +-- PALETTE2 : Enable palette for framebuffer 8bpp mode supplied by core +-- DOWNSCALE : True=Support downscaling False=Downscaling disabled +-- BYTESWAP : Little/Big endian byte swap +-- FRAC : Fractional bits, subpixel resolution +-- OHRES : Max. output horizontal resolution. Must be a power of two. +-- (Used for sizing line buffers) +-- IHRES : Max. input horizontal resolution. Must be a power of two. +-- (Used for sizing line buffers) +-- N_DW : Avalon data bus width. 64 or 128 bits +-- N_AW : Avalon address bus width +-- N_BURST : Burst size in bytes. Power of two. + +ENTITY ascal IS + GENERIC ( + MASK : unsigned(7 DOWNTO 0) :=x"FF"; + RAMBASE : unsigned(31 DOWNTO 0); + RAMSIZE : unsigned(31 DOWNTO 0) := x"0080_0000"; -- =8MB + INTER : boolean := true; + HEADER : boolean := true; + DOWNSCALE : boolean := true; + BYTESWAP : boolean := true; + PALETTE : boolean := true; + PALETTE2 : boolean := true; + FRAC : natural RANGE 4 TO 6 :=4; + OHRES : natural RANGE 1 TO 4096 :=2048; + IHRES : natural RANGE 1 TO 2048 :=2048; + N_DW : natural RANGE 64 TO 128 := 128; + N_AW : natural RANGE 8 TO 32 := 32; + N_BURST : natural := 256 -- 256 bytes per burst + ); + PORT ( + ------------------------------------ + -- Input video + i_r : IN unsigned(7 DOWNTO 0); + i_g : IN unsigned(7 DOWNTO 0); + i_b : IN unsigned(7 DOWNTO 0); + i_hs : IN std_logic; -- H sync + i_vs : IN std_logic; -- V sync + i_fl : IN std_logic; -- Interlaced field + i_de : IN std_logic; -- Display Enable + i_ce : IN std_logic; -- Clock Enable + i_clk : IN std_logic; -- Input clock + + ------------------------------------ + -- Output video + o_r : OUT unsigned(7 DOWNTO 0); + o_g : OUT unsigned(7 DOWNTO 0); + o_b : OUT unsigned(7 DOWNTO 0); + o_hs : OUT std_logic; -- H sync + o_vs : OUT std_logic; -- V sync + o_de : OUT std_logic; -- Display Enable + o_vbl : OUT std_logic; -- V blank + o_ce : IN std_logic; -- Clock Enable + o_clk : IN std_logic; -- Output clock + + -- Border colour R G B + o_border : IN unsigned(23 DOWNTO 0) := x"000000"; + + ------------------------------------ + -- Framebuffer mode + o_fb_ena : IN std_logic :='0'; -- Enable Framebuffer Mode + o_fb_hsize : IN natural RANGE 0 TO 4095 :=0; + o_fb_vsize : IN natural RANGE 0 TO 4095 :=0; + o_fb_format : IN unsigned(5 DOWNTO 0) :="000100"; + o_fb_base : IN unsigned(31 DOWNTO 0) :=x"0000_0000"; + o_fb_stride : IN unsigned(13 DOWNTO 0) :=(OTHERS =>'0'); + + -- Framebuffer palette in 8bpp mode + pal1_clk : IN std_logic :='0'; + pal1_dw : IN unsigned(47 DOWNTO 0) :=x"000000000000"; -- R1 G1 B1 R0 G0 B0 + pal1_dr : OUT unsigned(47 DOWNTO 0) :=x"000000000000"; + pal1_a : IN unsigned(6 DOWNTO 0) :="0000000"; -- Colour index/2 + pal1_wr : IN std_logic :='0'; + + pal_n : IN std_logic :='0'; + + pal2_clk : IN std_logic :='0'; + pal2_dw : IN unsigned(23 DOWNTO 0) :=x"000000"; -- R G B + pal2_dr : OUT unsigned(23 DOWNTO 0) :=x"000000"; + pal2_a : IN unsigned(7 DOWNTO 0) :="00000000"; -- Colour index + pal2_wr : IN std_logic :='0'; + + ------------------------------------ + -- Low lag PLL tuning + o_lltune : OUT unsigned(15 DOWNTO 0); + + ------------------------------------ + -- Input video parameters + iauto : IN std_logic :='1'; -- 1=Autodetect image size 0=Choose window + himin : IN natural RANGE 0 TO 4095 :=0; -- MIN < MAX, MIN >=0, MAX < DISP + himax : IN natural RANGE 0 TO 4095 :=0; + vimin : IN natural RANGE 0 TO 4095 :=0; + vimax : IN natural RANGE 0 TO 4095 :=0; + + -- Detected input image size + i_hdmax : OUT natural RANGE 0 TO 4095; + i_vdmax : OUT natural RANGE 0 TO 4095; + + -- Output video parameters + run : IN std_logic :='1'; -- 1=Enable output image. 0=No image + freeze : IN std_logic :='0'; -- 1=Disable framebuffer writes + mode : IN unsigned(4 DOWNTO 0); + -- SYNC |_________________________/"""""""""\_______| + -- DE |""""""""""""""""""\________________________| + -- RGB | <#IMAGE#> ^HDISP | + -- ^HMIN ^HMAX ^HSSTART ^HSEND ^HTOTAL + htotal : IN natural RANGE 0 TO 4095; + hsstart : IN natural RANGE 0 TO 4095; + hsend : IN natural RANGE 0 TO 4095; + hdisp : IN natural RANGE 0 TO 4095; + hmin : IN natural RANGE 0 TO 4095; + hmax : IN natural RANGE 0 TO 4095; -- 0 <= hmin < hmax < hdisp + vtotal : IN natural RANGE 0 TO 4095; + vsstart : IN natural RANGE 0 TO 4095; + vsend : IN natural RANGE 0 TO 4095; + vdisp : IN natural RANGE 0 TO 4095; + vmin : IN natural RANGE 0 TO 4095; + vmax : IN natural RANGE 0 TO 4095; -- 0 <= vmin < vmax < vdisp + + -- Scaler format. 00=16bpp 565, 01=24bpp 10=32bpp + format : IN unsigned(1 DOWNTO 0) :="01"; + + ------------------------------------ + -- Polyphase filter coefficients + -- Order : + -- [Horizontal] [Vertical] + -- [0]...[2**FRAC-1] + -- [-1][0][1][2] + poly_clk : IN std_logic; + poly_dw : IN unsigned(8 DOWNTO 0); + poly_a : IN unsigned(FRAC+2 DOWNTO 0); + poly_wr : IN std_logic; + + ------------------------------------ + -- Avalon + avl_clk : IN std_logic; -- Avalon clock + avl_waitrequest : IN std_logic; + avl_readdata : IN std_logic_vector(N_DW-1 DOWNTO 0); + avl_readdatavalid : IN std_logic; + avl_burstcount : OUT std_logic_vector(7 DOWNTO 0); + avl_writedata : OUT std_logic_vector(N_DW-1 DOWNTO 0); + avl_address : OUT std_logic_vector(N_AW-1 DOWNTO 0); + avl_write : OUT std_logic; + avl_read : OUT std_logic; + avl_byteenable : OUT std_logic_vector(N_DW/8-1 DOWNTO 0); + + ------------------------------------ + reset_na : IN std_logic + ); + +BEGIN + ASSERT N_DW=64 OR N_DW=128 REPORT "DW" SEVERITY failure; + +END ENTITY ascal; + +--############################################################################## + +ARCHITECTURE rtl OF ascal IS + + CONSTANT MASK_NEAREST : natural :=0; + CONSTANT MASK_BILINEAR : natural :=1; + CONSTANT MASK_SHARP_BILINEAR : natural :=2; + CONSTANT MASK_BICUBIC : natural :=3; + CONSTANT MASK_POLY : natural :=4; + + ---------------------------------------------------------- + FUNCTION ilog2 (CONSTANT v : natural) RETURN natural IS + VARIABLE r : natural := 1; + VARIABLE n : natural := 0; + BEGIN + WHILE v>r LOOP + n:=n+1; + r:=r*2; + END LOOP; + RETURN n; + END FUNCTION ilog2; + FUNCTION to_std_logic (a : boolean) RETURN std_logic IS + BEGIN + IF a THEN RETURN '1'; + ELSE RETURN '0'; + END IF; + END FUNCTION to_std_logic; + + ---------------------------------------------------------- + CONSTANT NB_BURST : natural :=ilog2(N_BURST); + CONSTANT NB_LA : natural :=ilog2(N_DW/8); -- Low address bits + CONSTANT BLEN : natural :=N_BURST / N_DW * 8; -- Burst length + + ---------------------------------------------------------- + TYPE arr_dw IS ARRAY (natural RANGE <>) OF unsigned(N_DW-1 DOWNTO 0); + + TYPE type_pix IS RECORD + r,g,b : unsigned(7 DOWNTO 0); -- 0.8 + END RECORD; + TYPE arr_pix IS ARRAY (natural RANGE <>) OF type_pix; + ATTRIBUTE ramstyle : string; + + SUBTYPE uint12 IS natural RANGE 0 TO 4095; + SUBTYPE uint13 IS natural RANGE 0 TO 8191; + + TYPE arr_uv48 IS ARRAY (natural RANGE <>) OF unsigned(47 DOWNTO 0); + TYPE arr_uv24 IS ARRAY (natural RANGE <>) OF unsigned(23 DOWNTO 0); + TYPE arr_uv36 IS ARRAY (natural RANGE <>) OF unsigned(35 DOWNTO 0); + TYPE arr_int9 IS ARRAY (natural RANGE <>) OF integer RANGE -256 TO 255; + TYPE arr_uint12 IS ARRAY (natural RANGE <>) OF uint12; + + ---------------------------------------------------------- + -- Input image + SIGNAL i_pvs,i_pfl,i_pde,i_pce : std_logic; + SIGNAL i_ppix : type_pix; + SIGNAL i_freeze : std_logic; + SIGNAL i_count : unsigned(2 DOWNTO 0); + SIGNAL i_hsize,i_hmin,i_hmax,i_hcpt : uint12; + SIGNAL i_hrsize,i_vrsize : uint12; + SIGNAL i_himax,i_vimax : uint12; + SIGNAL i_vsize,i_vmaxmin,i_vmin,i_vmax,i_vcpt : uint12; + SIGNAL i_iauto : std_logic; + SIGNAL i_mode : unsigned(4 DOWNTO 0); + SIGNAL i_format : unsigned(1 DOWNTO 0); + SIGNAL i_ven,i_sof : std_logic; + SIGNAL i_wr : std_logic; + SIGNAL i_divstart,i_divrun : std_logic; + SIGNAL i_de_pre,i_vs_pre,i_fl_pre : std_logic; + SIGNAL i_de_delay : natural RANGE 0 TO 31; + SIGNAL i_intercnt : natural RANGE 0 TO 3; + SIGNAL i_inter,i_half,i_flm : std_logic; + SIGNAL i_write,i_wreq,i_alt,i_line,i_wline,i_wline_mem : std_logic; + SIGNAL i_walt,i_walt_mem,i_wreq_mem : std_logic; + SIGNAL i_wdelay : natural RANGE 0 TO 7; + SIGNAL i_push,i_pushend,i_pushend2 : std_logic; + SIGNAL i_eol : std_logic; + SIGNAL i_pushhead,i_pushhead2,i_pushhead3 : std_logic; + SIGNAL i_hburst,i_hbcpt : natural RANGE 0 TO 31; + SIGNAL i_shift : unsigned(0 TO 119) := (OTHERS =>'0'); + SIGNAL i_head : unsigned(127 DOWNTO 0); + SIGNAL i_acpt : natural RANGE 0 TO 15; + SIGNAL i_dpram : arr_dw(0 TO BLEN*2-1); + ATTRIBUTE ramstyle OF i_dpram : SIGNAL IS "no_rw_check"; + SIGNAL i_endframe0,i_endframe1,i_vss : std_logic; + SIGNAL i_wad : natural RANGE 0 TO BLEN*2-1; + SIGNAL i_dw : unsigned(N_DW-1 DOWNTO 0); + SIGNAL i_adrs,i_adrsi,i_wadrs,i_wadrs_mem : unsigned(31 DOWNTO 0); + SIGNAL i_reset_na : std_logic; + SIGNAL i_hnp,i_vnp : std_logic; + SIGNAL i_mem : arr_pix(0 TO IHRES-1); -- Downscale line buffer + ATTRIBUTE ramstyle OF i_mem : SIGNAL IS "no_rw_check"; + SIGNAL i_ohsize,i_ovsize : uint12; + SIGNAL i_vdivi : unsigned(12 DOWNTO 0); + SIGNAL i_vdivr : unsigned(24 DOWNTO 0); + SIGNAL i_div : unsigned(16 DOWNTO 0); + SIGNAL i_dir : unsigned(11 DOWNTO 0); + SIGNAL i_h_frac,i_v_frac : unsigned(11 DOWNTO 0); + SIGNAL i_hacc,i_vacc : uint13; + SIGNAL i_hdown,i_vdown : std_logic; + SIGNAL i_divcpt : natural RANGE 0 TO 36; + SIGNAL i_lwad,i_lrad : natural RANGE 0 TO OHRES-1; + SIGNAL i_lwr,i_bil : std_logic; + SIGNAL i_ldw,i_ldrm : type_pix; + SIGNAL i_hpixp,i_hpix0,i_hpix1,i_hpix2,i_hpix3,i_hpix4 : type_pix; + SIGNAL i_hpix,i_pix : type_pix; + SIGNAL i_hnp1,i_hnp2,i_hnp3,i_hnp4 : std_logic; + SIGNAL i_ven1,i_ven2,i_ven3,i_ven4,i_ven5,i_ven6 : std_logic; + + ---------------------------------------------------------- + -- Avalon + TYPE type_avl_state IS (sIDLE,sWRITE,sREAD); + SIGNAL avl_state : type_avl_state; + SIGNAL avl_write_i,avl_write_sync,avl_write_sync2 : std_logic; + SIGNAL avl_read_i,avl_read_sync,avl_read_sync2 : std_logic; + SIGNAL avl_read_pulse,avl_write_pulse : std_logic; + SIGNAL avl_read_sr,avl_write_sr,avl_read_clr,avl_write_clr : std_logic; + SIGNAL avl_rad,avl_rad_c,avl_wad : natural RANGE 0 TO 2*BLEN-1; + SIGNAL avl_walt,avl_wline,avl_rline : std_logic; + SIGNAL avl_dw,avl_dr : unsigned(N_DW-1 DOWNTO 0); + SIGNAL avl_wr : std_logic; + SIGNAL avl_readdataack,avl_readack : std_logic; + SIGNAL avl_radrs,avl_wadrs : unsigned(31 DOWNTO 0); + SIGNAL avl_i_offset0,avl_o_offset0 : unsigned(31 DOWNTO 0); + SIGNAL avl_i_offset1,avl_o_offset1 : unsigned(31 DOWNTO 0); + SIGNAL avl_reset_na : std_logic; + SIGNAL avl_o_vs_sync,avl_o_vs : std_logic; + SIGNAL avl_fb_ena : std_logic; + + FUNCTION buf_next(a,b : natural RANGE 0 TO 2) RETURN natural IS + BEGIN + IF (a=0 AND b=1) OR (a=1 AND b=0) THEN RETURN 2; END IF; + IF (a=1 AND b=2) OR (a=2 AND b=1) THEN RETURN 0; END IF; + RETURN 1; + END FUNCTION; + FUNCTION buf_offset(b : natural RANGE 0 TO 2; + base : unsigned(31 DOWNTO 0); + size : unsigned(31 DOWNTO 0)) RETURN unsigned IS + BEGIN + IF b=1 THEN RETURN base+size; END IF; + IF b=2 THEN RETURN base+(size(30 DOWNTO 0) & '0'); END IF; + RETURN base; + END FUNCTION; + + ---------------------------------------------------------- + -- Output + SIGNAL o_run : std_logic; + SIGNAL o_mode,o_hmode,o_vmode : unsigned(4 DOWNTO 0); + SIGNAL o_format : unsigned(5 DOWNTO 0); + SIGNAL o_fb_pal_dr : unsigned(23 DOWNTO 0); + SIGNAL o_fb_pal_dr2 : unsigned(23 DOWNTO 0); + SIGNAL o_fb_pal_dr_x2 : unsigned(47 DOWNTO 0); + SIGNAL pal_idx: unsigned(7 DOWNTO 0); + SIGNAL pal_idx_lsb: std_logic; + SIGNAL pal1_mem : arr_uv48(0 TO 127); + SIGNAL pal2_mem : arr_uv24(0 TO 255); + ATTRIBUTE ramstyle of pal1_mem : signal is "no_rw_check"; + ATTRIBUTE ramstyle of pal2_mem : signal is "no_rw_check"; + SIGNAL o_htotal,o_hsstart,o_hsend : uint12; + SIGNAL o_hmin,o_hmax,o_hdisp : uint12; + SIGNAL o_hsize,o_vsize : uint12; + SIGNAL o_vtotal,o_vsstart,o_vsend : uint12; + SIGNAL o_vmin,o_vmax,o_vdisp : uint12; + SIGNAL o_divcpt : natural RANGE 0 TO 36; + SIGNAL o_iendframe0,o_iendframe02,o_iendframe1,o_iendframe12 : std_logic; + SIGNAL o_bufup0,o_bufup1,o_inter : std_logic; + SIGNAL o_ibuf0,o_ibuf1,o_obuf0,o_obuf1 : natural RANGE 0 TO 2; + TYPE enum_o_state IS (sDISP,sHSYNC,sREAD,sWAITREAD); + SIGNAL o_state : enum_o_state; + TYPE enum_o_copy IS (sWAIT,sSHIFT,sCOPY); + SIGNAL o_copy : enum_o_copy; + SIGNAL o_pshift : natural RANGE 0 TO 15; + SIGNAL o_readack,o_readack_sync,o_readack_sync2 : std_logic; + SIGNAL o_readdataack,o_readdataack_sync,o_readdataack_sync2 : std_logic; + SIGNAL o_copyv : unsigned(0 TO 8); + SIGNAL o_adrs : unsigned(31 DOWNTO 0); -- Avalon address + SIGNAL o_adrs_pre : natural RANGE 0 TO 2**24-1; + SIGNAL o_stride : unsigned(13 DOWNTO 0); + SIGNAL o_adrsa,o_adrsb,o_rline : std_logic; + SIGNAL o_ad,o_ad1,o_ad2,o_ad3 : natural RANGE 0 TO 2*BLEN-1; + SIGNAL o_adturn : std_logic; + SIGNAL o_dr : unsigned(N_DW-1 DOWNTO 0); + SIGNAL o_shift : unsigned(0 TO N_DW+15); + SIGNAL o_sh,o_sh1,o_sh2,o_sh3,o_sh4 : std_logic; + SIGNAL o_reset_na : std_logic; + SIGNAL o_dpram : arr_dw(0 TO BLEN*2-1); + ATTRIBUTE ramstyle OF o_dpram : SIGNAL IS "no_rw_check"; + SIGNAL o_line0,o_line1,o_line2,o_line3 : arr_pix(0 TO OHRES-1); + ATTRIBUTE ramstyle OF o_line0 : SIGNAL IS "no_rw_check"; + ATTRIBUTE ramstyle OF o_line1 : SIGNAL IS "no_rw_check"; + ATTRIBUTE ramstyle OF o_line2 : SIGNAL IS "no_rw_check"; + ATTRIBUTE ramstyle OF o_line3 : SIGNAL IS "no_rw_check"; + SIGNAL o_wadl,o_radl : natural RANGE 0 TO OHRES-1; + SIGNAL o_ldw,o_ldr0,o_ldr1,o_ldr2,o_ldr3 : type_pix; + SIGNAL o_wr : unsigned(3 DOWNTO 0); + SIGNAL o_hcpt,o_vcpt,o_vcpt_pre,o_vcpt_pre2,o_vcpt_pre3 : uint12; + SIGNAL o_ihsize,o_ihsizem,o_ivsize : uint12; + SIGNAL o_ihsize_temp, o_ihsize_temp2 : natural RANGE 0 TO 32767; + + SIGNAL o_vfrac,o_hfrac,o_hfrac1,o_hfrac2,o_hfrac3,o_hfrac4 : unsigned(11 DOWNTO 0); + SIGNAL o_hacc,o_hacc_ini,o_hacc_next,o_vacc,o_vacc_next,o_vacc_ini : natural RANGE 0 TO 4*OHRES-1; + SIGNAL o_hsv,o_vsv,o_dev,o_pev,o_end : unsigned(0 TO 5); + SIGNAL o_hsp,o_vss : std_logic; + SIGNAL o_read,o_read_pre : std_logic; + SIGNAL o_readlev,o_copylev : natural RANGE 0 TO 2; + SIGNAL o_hburst,o_hbcpt : natural RANGE 0 TO 31; + SIGNAL o_fload : natural RANGE 0 TO 3; + SIGNAL o_acpt,o_acpt1,o_acpt2,o_acpt3,o_acpt4 : natural RANGE 0 TO 15; -- Alternance pixels FIFO + SIGNAL o_dshi : natural RANGE 0 TO 3; + SIGNAL o_first,o_last,o_last1,o_last2 : std_logic; + SIGNAL o_lastt1,o_lastt2,o_lastt3,o_lastt4 : std_logic; + SIGNAL o_alt,o_altx : unsigned(3 DOWNTO 0); + SIGNAL o_hdown,o_vdown : std_logic; + SIGNAL o_primv,o_lastv,o_bibv : unsigned(0 TO 2); + TYPE arr_uint4 IS ARRAY (natural RANGE <>) OF natural RANGE 0 TO 15; + SIGNAL o_off : arr_uint4(0 TO 2); + SIGNAL o_bibu : std_logic :='0'; + SIGNAL o_dcptv : arr_uint12(1 TO 8); + SIGNAL o_dcpt : uint12; + SIGNAL o_hpixs,o_hpix0,o_hpix1,o_hpix2,o_hpix3 : type_pix; + SIGNAL o_hpixq,o_vpixq,o_vpixq1 : arr_pix(0 TO 3); + + SIGNAL o_vpe : std_logic; + SIGNAL o_div,o_div2 : unsigned(18 DOWNTO 0); --uint12; + SIGNAL o_dir,o_dir2 : unsigned(11 DOWNTO 0); + SIGNAL o_vdivi : unsigned(12 DOWNTO 0); + SIGNAL o_vdivr : unsigned(24 DOWNTO 0); + SIGNAL o_divstart : std_logic; + SIGNAL o_divrun : std_logic; + SIGNAL o_hacpt,o_vacpt : unsigned(11 DOWNTO 0); + + ----------------------------------------------------------------------------- + FUNCTION shift_ishift(shift : unsigned(0 TO 119); + pix : type_pix; + format : unsigned(1 DOWNTO 0)) RETURN unsigned IS + BEGIN + CASE format IS + WHEN "01" => -- 24bpp + RETURN shift(24 TO 119) & pix.r & pix.g & pix.b; + WHEN "10" => -- 32bpp + RETURN shift(32 TO 119) & pix.r & pix.g & pix.b & x"00"; + WHEN OTHERS => -- 16bpp 565 + RETURN shift(16 TO 119) & + pix.g(4 DOWNTO 2) & pix.r(7 DOWNTO 3) & + pix.b(7 DOWNTO 3) & pix.g(7 DOWNTO 5); + END CASE; + END FUNCTION; + + FUNCTION shift_ipack(i_dw : unsigned(N_DW-1 DOWNTO 0); + acpt : natural RANGE 0 TO 15; + shift : unsigned(0 TO 119); + pix : type_pix; + format : unsigned(1 DOWNTO 0)) RETURN unsigned IS + VARIABLE dw : unsigned(N_DW-1 DOWNTO 0); + BEGIN + dw:=i_dw; + CASE format IS + WHEN "01" => -- 24bpp + IF N_DW=128 THEN + IF acpt=5 THEN dw:=shift(0 TO 119) & pix.r; + ELSIF acpt=10 THEN dw:=shift(8 TO 119) & pix.r & pix.g; + ELSIF acpt=15 THEN dw:=shift(16 TO 119) & pix.r & pix.g & pix.b; + END IF; + ELSE -- N_DW=64 + IF (acpt MOD 8)=2 THEN dw:=shift(72 TO 119) & pix.r & pix.g; + ELSIF (acpt MOD 8)=5 THEN dw:=shift(64 TO 119) & pix.r; + ELSIF (acpt MOD 8)=7 THEN dw:=shift(80 TO 119) & pix.r & pix.g & pix.b; + END IF; + END IF; + WHEN "10" => -- 32bpp + IF (N_DW=128 AND (acpt MOD 4)=3) OR (N_DW=64 AND (acpt MOD 8)=7) THEN + dw:=shift(128-N_DW+24 TO 119) & pix.r & pix.g & pix.b & x"00"; + END IF; + WHEN OTHERS => -- 16bpp 565 + IF (N_DW=128 AND (acpt MOD 8)=7) OR (N_DW=64 AND (acpt MOD 4)=3) THEN + dw:=shift(128-N_DW+8 TO 119) & pix.g(4 DOWNTO 2) & pix.r(7 DOWNTO 3) & + pix.b(7 DOWNTO 3) & pix.g(7 DOWNTO 5); + END IF; + END CASE; + RETURN dw; + END FUNCTION; + + FUNCTION shift_inext (acpt : natural RANGE 0 TO 15; + format : unsigned(1 DOWNTO 0)) RETURN boolean IS + BEGIN + CASE format IS + WHEN "01" => -- 24bpp + RETURN (N_DW=128 AND (acpt=5 OR acpt=10 OR acpt=15)) OR + (N_DW=64 AND ((acpt MOD 8)=2 OR (acpt MOD 8)=5 OR (acpt MOD 8)=7)); + WHEN "10" => -- 32bpp + RETURN (N_DW=128 AND ((acpt MOD 4)=3)) OR + (N_DW=64 AND ((acpt MOD 2)=1)); + WHEN OTHERS => -- 16bpp + RETURN (N_DW=128 AND ((acpt MOD 8)=7)) OR + (N_DW=64 AND ((acpt MOD 4)=3)); + END CASE; + END FUNCTION; + + FUNCTION shift_opack(acpt : natural RANGE 0 TO 15; + shift : unsigned(0 TO N_DW+15); + dr : unsigned(N_DW-1 DOWNTO 0); + format : unsigned(5 DOWNTO 0)) RETURN unsigned IS + VARIABLE shift_v : unsigned(0 TO N_DW+15); + BEGIN + CASE format(2 DOWNTO 0) IS + WHEN "011" => -- 8bpp + IF (N_DW=128 AND acpt=0) OR (N_DW=64 AND (acpt MOD 8)=0) THEN + shift_v:=dr & dr(15 DOWNTO 0); + ELSE + shift_v:=shift(8 TO N_DW+15) & dr(7 DOWNTO 0); + END IF; + + WHEN "100" => -- 16bpp + IF (N_DW=128 AND (acpt MOD 8)=0) OR (N_DW=64 AND (acpt MOD 4)=0) THEN + shift_v:=dr & dr(15 DOWNTO 0); + ELSE + shift_v:=shift(16 TO N_DW+15) & dr(15 DOWNTO 0); + END IF; + + WHEN "101" => -- 24bpp + IF N_DW=128 THEN + IF acpt=0 THEN + shift_v:=dr & dr(15 DOWNTO 0); + ELSIF acpt=5 THEN + shift_v:=shift(24 TO 31) & dr & dr(7 DOWNTO 0); + ELSIF acpt=10 THEN + shift_v:=shift(24 TO 39) & dr; + ELSE + shift_v:=shift(24 TO N_DW+15) & dr(23 DOWNTO 0); + END IF; + ELSE -- N_DW=64 + IF (acpt MOD 8)=0 THEN + shift_v:=dr & dr(15 DOWNTO 0); + ELSIF (acpt MOD 8)=2 THEN + shift_v:=shift(24 TO 39) & dr; + ELSIF (acpt MOD 8)=5 THEN + shift_v:=shift(24 TO 31) & dr & dr(7 DOWNTO 0); + ELSE + shift_v:=shift(24 TO N_DW+15) & dr(23 DOWNTO 0); + END IF; + END IF; + WHEN OTHERS => -- 32bpp + IF (N_DW=128 AND (acpt MOD 4)=0) OR (N_DW=64 AND (acpt MOD 2)=0) THEN + shift_v:=dr & dr(15 DOWNTO 0); + ELSE + shift_v:=shift(32 TO N_DW+15) & dr(31 DOWNTO 0); + END IF; + END CASE; + RETURN shift_v; + END FUNCTION; + + FUNCTION shift_onext (acpt : natural RANGE 0 TO 15; + format : unsigned(5 DOWNTO 0)) RETURN boolean IS + BEGIN + CASE format(2 DOWNTO 0) IS + WHEN "011" => -- 8bpp + RETURN (N_DW=128 AND acpt=0) OR + (N_DW=64 AND ((acpt MOD 8)=0)); + WHEN "100" => -- 16bpp + RETURN (N_DW=128 AND ((acpt MOD 8)=0)) OR + (N_DW=64 AND ((acpt MOD 4)=0)); + WHEN "101" => -- 24bpp + RETURN (N_DW=128 AND (acpt=0 OR acpt=5 OR acpt=10)) OR + (N_DW=64 AND ((acpt MOD 8)=0 OR (acpt MOD 8)=2 OR (acpt MOD 8)=5)); + WHEN OTHERS => -- 32bpp + RETURN (N_DW=128 AND ((acpt MOD 4)=0)) OR + (N_DW=64 AND ((acpt MOD 2)=0)); + END CASE; + END FUNCTION; + + FUNCTION shift_opix (shift : unsigned(0 TO N_DW+15); + format : unsigned(5 DOWNTO 0)) RETURN type_pix IS + BEGIN + CASE format(3 DOWNTO 0) IS + WHEN "0100" => -- 16bpp 565 + RETURN (b=>shift(8 TO 12) & shift(8 TO 10), + g=>shift(13 TO 15) & shift(0 TO 2) & shift(13 TO 14), + r=>shift(3 TO 7) & shift(3 TO 5)); + WHEN "1100" => -- 16bpp 1555 + RETURN (b=>shift(9 TO 13) & shift(9 TO 11), + g=>shift(14 TO 15) & shift(0 TO 2) & shift(14 TO 15) & shift(0), + r=>shift(3 TO 7) & shift(3 TO 5)); + WHEN "0101" | "0110" => -- 24bpp / 32bpp + RETURN (r=>shift(0 TO 7),g=>shift(8 TO 15),b=>shift(16 TO 23)); + + WHEN OTHERS => + RETURN (r=>shift(0 TO 7),g=>shift(8 TO 15),b=>shift(16 TO 23)); + + END CASE; + END FUNCTION; + + FUNCTION pixoffset(adrs : unsigned(31 DOWNTO 0); + format : unsigned (5 DOWNTO 0)) RETURN natural IS + BEGIN + CASE format(2 DOWNTO 0) IS + WHEN "011" => -- 8bbp + RETURN to_integer(adrs(NB_LA-1 DOWNTO 0)); + WHEN "100" => -- 16bpp 565 + RETURN to_integer(adrs(NB_LA-1 DOWNTO 1)); + WHEN OTHERS => -- 32bpp + RETURN to_integer(adrs(NB_LA-1 DOWNTO 2)); + END CASE; + END FUNCTION; + + FUNCTION swap(d : unsigned(N_DW-1 DOWNTO 0)) RETURN unsigned IS + VARIABLE e : unsigned(N_DW-1 DOWNTO 0); + BEGIN + IF BYTESWAP THEN + FOR i IN 0 TO N_DW/8-1 LOOP + e(i*8+7 DOWNTO i*8):=d(N_DW-i*8-1 DOWNTO N_DW-i*8-8); + END LOOP; + RETURN e; + ELSE + RETURN d; + END IF; + END FUNCTION swap; + + ----------------------------------------------------------------------------- + FUNCTION altx (a : unsigned(1 DOWNTO 0)) RETURN unsigned IS + BEGIN + CASE a IS + WHEN "00" => RETURN "0001"; + WHEN "01" => RETURN "0010"; + WHEN "10" => RETURN "0100"; + WHEN OTHERS => RETURN "1000"; + END CASE; + END FUNCTION; + + ----------------------------------------------------------------------------- + FUNCTION bound(a : unsigned; + s : natural) RETURN unsigned IS + BEGIN + IF a(a'left)='1' THEN + RETURN x"00"; + ELSIF a(a'left DOWNTO s)/=0 THEN + RETURN x"FF"; + ELSE + RETURN a(s-1 DOWNTO s-8); + END IF; + END FUNCTION bound; + + ----------------------------------------------------------------------------- + -- Nearest + FUNCTION near_frac(f : unsigned) RETURN unsigned IS + VARIABLE x : unsigned(FRAC-1 DOWNTO 0); + BEGIN + x:=(OTHERS =>f(f'left)); + RETURN x; + END FUNCTION; + + SIGNAL o_h_frac2,o_v_frac : unsigned(FRAC-1 DOWNTO 0); + SIGNAL o_h_bil_pix,o_v_bil_pix : type_pix; + + ----------------------------------------------------------------------------- + -- Nearest + Bilinear + Sharp Bilinear + FUNCTION bil_frac(f : unsigned) RETURN unsigned IS + BEGIN + RETURN f(f'left DOWNTO f'left+1-FRAC); + END FUNCTION; + + TYPE type_bil_t IS RECORD + r,g,b : unsigned(8+FRAC DOWNTO 0); + END RECORD; + FUNCTION bil_calc(f : unsigned(FRAC-1 DOWNTO 0); + p : arr_pix(0 TO 3)) RETURN type_bil_t IS + VARIABLE fp,fn : unsigned(FRAC DOWNTO 0); + VARIABLE u : unsigned(8+FRAC DOWNTO 0); + VARIABLE x : type_bil_t; + CONSTANT Z : unsigned(FRAC-1 DOWNTO 0):=(OTHERS =>'0'); + BEGIN + fp:='0' & f; + fn:=('1' & Z) - fp; + u:=p(2).r * fp + p(1).r * fn; + x.r:=u; + u:=p(2).g * fp + p(1).g * fn; + x.g:=u; + u:=p(2).b * fp + p(1).b * fn; + x.b:=u; + RETURN x; + END FUNCTION; + SIGNAL o_h_bil_t,o_v_bil_t : type_bil_t; + SIGNAL i_h_bil_t : type_bil_t; + + ----------------------------------------------------------------------------- + -- Sharp Bilinear + -- <0.5 : x*x*x*4 + -- >0.5 : 1 - (1-x)*(1-x)*(1-x)*4 + + TYPE type_sbil_tt IS RECORD + f : unsigned(FRAC-1 DOWNTO 0); + s : unsigned(FRAC-1 DOWNTO 0); + END RECORD; + + SIGNAL o_h_sbil_t,o_v_sbil_t : type_sbil_tt; + + FUNCTION sbil_frac1(f : unsigned(11 DOWNTO 0)) RETURN type_sbil_tt IS + VARIABLE u : unsigned(FRAC-1 DOWNTO 0); + VARIABLE v : unsigned(2*FRAC-1 DOWNTO 0); + VARIABLE x : type_sbil_tt; + BEGIN + IF f(11)='0' THEN + u:=f(11 DOWNTO 12-FRAC); + ELSE + u:=NOT f(11 DOWNTO 12-FRAC); + END IF; + v:=u*u; + x.f:=u; + x.s:=v(2*FRAC-2 DOWNTO FRAC-1); + RETURN x; + END FUNCTION; + + FUNCTION sbil_frac2(f : unsigned(11 DOWNTO 0); + t : type_sbil_tt) RETURN unsigned IS + VARIABLE v : unsigned(2*FRAC-1 DOWNTO 0); + BEGIN + v:=t.f*t.s; + IF f(11)='0' THEN + RETURN v(2*FRAC-2 DOWNTO FRAC-1); + ELSE + RETURN NOT v(2*FRAC-2 DOWNTO FRAC-1); + END IF; + END FUNCTION; + + ----------------------------------------------------------------------------- + -- Bicubic + TYPE type_bic_abcd IS RECORD + a : unsigned(7 DOWNTO 0); -- 0.8 + b : signed(8 DOWNTO 0); -- 0.9 + c : signed(11 DOWNTO 0); -- 3.9 + d : signed(10 DOWNTO 0); -- 2.9 + xx : signed(8 DOWNTO 0); -- X.X 1.8 + END RECORD; + TYPE type_bic_pix_abcd IS RECORD + r,g,b : type_bic_abcd; + END RECORD; + TYPE type_bic_tt1 IS RECORD -- Intermediate result + r_bx,g_bx,b_bx : signed(8 DOWNTO 0); -- B.X 1.8 + r_cxx,g_cxx,b_cxx : signed(11 DOWNTO 0); -- C.XX 3.9 + r_dxx,g_dxx,b_dxx : signed(10 DOWNTO 0); -- D.XX 2.9 + END RECORD; + TYPE type_bic_tt2 IS RECORD -- Intermediate result + r_abxcxx,g_abxcxx,b_abxcxx : signed(9 DOWNTO 0); -- A + B.X + C.XX 2.8 + r_dxxx,g_dxxx,b_dxxx : signed(9 DOWNTO 0); -- D.X.X.X 2.8 + END RECORD; + + ---------------------------------------------------------- + -- Y = A + B.X + C.X.X + D.X.X.X = A + X.(B + X.(C + X.D)) + -- A = Y(0) 0 .. 1 unsigned + -- B = Y(1)/2 - Y(-1)/2 -1/2 .. +1/2 signed + -- C = Y(-1) - 5*Y(0)/2 + 2*Y(1) - Y(2)/2 -3 .. +3 signed + -- D = -Y(-1)/2 + 3*Y(0)/2 - 3*Y(1)/2 + Y(2)/2 -2 .. +2 signed + + FUNCTION bic_calc0(f : unsigned(11 DOWNTO 0); + pm,p0,p1,p2 : unsigned(7 DOWNTO 0)) RETURN type_bic_abcd IS + VARIABLE xx : signed(2*FRAC+1 DOWNTO 0); -- 2.(2*FRAC) + BEGIN + xx := signed('0' & f(11 DOWNTO 12-FRAC)) * + signed('0' & f(11 DOWNTO 12-FRAC)); -- 2.(2*FRAC) + RETURN type_bic_abcd'( + a=>p0,-- 0.8 + b=>signed(('0' & p1) - ('0' & pm)), -- 0.9 + c=>signed(("000" & pm & '0') - ("00" & p0 & "00") - ("0000" & p0) + + ("00" & p1 & "00") - ("0000" & p2)), -- 3.9 + d=>signed(("00" & p0 & '0') - ("00" & p1 & '0') - ("000" & p1) + + ("000" & p0) + ("000" & p2) - ("000" & pm)), -- 2.9 + xx=>xx(2*FRAC DOWNTO 2*FRAC-8)); -- 1.8 + END FUNCTION; + FUNCTION bic_calc0(f : unsigned(11 DOWNTO 0); + p : arr_pix(0 TO 3)) RETURN type_bic_pix_abcd IS + BEGIN + RETURN type_bic_pix_abcd'(r=>bic_calc0(f,p(0).r,p(1).r,p(2).r,p(3).r), + g=>bic_calc0(f,p(0).g,p(1).g,p(2).g,p(3).g), + b=>bic_calc0(f,p(0).b,p(1).b,p(2).b,p(3).b)); + END FUNCTION; + + ---------------------------------------------------------- + -- Calc : B.X, C.XX, D.XX + FUNCTION bic_calc1(f : unsigned(11 DOWNTO 0); + abcd : type_bic_pix_abcd) RETURN type_bic_tt1 IS + VARIABLE t : type_bic_tt1; + VARIABLE bx : signed(9+FRAC DOWNTO 0); -- 1.(FRAC+9) + VARIABLE cxx : signed(20 DOWNTO 0); -- 4.17 + VARIABLE dxx : signed(19 DOWNTO 0); -- 3.17 + BEGIN + bx := abcd.r.b * signed('0' & f(11 DOWNTO 12-FRAC)); -- 1.(FRAC+9) + t.r_bx:=bx(9+FRAC DOWNTO 9+FRAC-8); -- 1.8 + cxx:= abcd.r.c * abcd.r.xx; -- 3.9 * 1.8 = 4.17 + t.r_cxx:=cxx(19 DOWNTO 8); -- 3.9 + dxx:= abcd.r.d * abcd.r.xx; -- 2.9 * 1.8 = 3.17 + t.r_dxx:=dxx(18 DOWNTO 8); -- 2.9 + bx := abcd.g.b * signed('0' & f(11 DOWNTO 12-FRAC)); -- 1.(FRAC+9) + t.g_bx:=bx(9+FRAC DOWNTO 9+FRAC-8); -- 1.8 + cxx:= abcd.g.c * abcd.g.xx; -- 3.9 * 1.8 = 4.17 + t.g_cxx:=cxx(19 DOWNTO 8); -- 3.9 + dxx:= abcd.g.d * abcd.g.xx; -- 2.9 * 1.8 = 3.17 + t.g_dxx:=dxx(18 DOWNTO 8); -- 2.9 + bx := abcd.b.b * signed('0' & f(11 DOWNTO 12-FRAC)); -- 1.(FRAC+9) + t.b_bx:=bx(9+FRAC DOWNTO 9+FRAC-8); -- 1.8 + cxx:= abcd.b.c * abcd.b.xx; -- 3.9 * 1.8 = 4.17 + t.b_cxx:=cxx(19 DOWNTO 8); -- 3.9 + dxx:= abcd.b.d * abcd.b.xx; -- 2.9 * 1.8 = 3.17 + t.b_dxx:=dxx(18 DOWNTO 8); -- 2.9 + RETURN t; + END FUNCTION; + + ---------------------------------------------------------- + -- Calc A + BX + CXX , X.DXX + FUNCTION bic_calc2(f : unsigned(11 DOWNTO 0); + t : type_bic_tt1; + abcd : type_bic_pix_abcd) RETURN type_bic_tt2 IS + VARIABLE u : type_bic_tt2; + VARIABLE x : signed(11+FRAC DOWNTO 0); -- 3.(9+FRAC) + BEGIN + u.r_abxcxx:=(t.r_bx(8) & t.r_bx) + ("00" & signed(abcd.r.a)) + t.r_cxx(10 DOWNTO 1); -- 2.8 + u.g_abxcxx:=(t.g_bx(8) & t.g_bx) + ("00" & signed(abcd.g.a)) + t.g_cxx(10 DOWNTO 1); -- 2.8 + u.b_abxcxx:=(t.b_bx(8) & t.b_bx) + ("00" & signed(abcd.b.a)) + t.b_cxx(10 DOWNTO 1); -- 2.8 + + x:=t.r_dxx * signed('0' & f(11 DOWNTO 12-FRAC)); --2.9 * 1.FRAC =3.(9+FRAC) + u.r_dxxx:=x(10+FRAC DOWNTO 9+FRAC-8); -- 2.8 + x:=t.g_dxx * signed('0' & f(11 DOWNTO 12-FRAC)); --2.9 * 1.FRAC =3.(9+FRAC) + u.g_dxxx:=x(10+FRAC DOWNTO 9+FRAC-8); -- 2.8 + x:=t.b_dxx * signed('0' & f(11 DOWNTO 12-FRAC)); --2.9 * 1.FRAC =3.(9+FRAC) + u.b_dxxx:=x(10+FRAC DOWNTO 9+FRAC-8); -- 2.8 + RETURN u; + END FUNCTION; + + ---------------------------------------------------------- + -- Calc (A + BX + CXX) + (DXXX) + FUNCTION bic_calc3(f : unsigned(11 DOWNTO 0); + t : type_bic_tt2; + abcd : type_bic_pix_abcd) RETURN type_pix IS + VARIABLE x : type_pix; + VARIABLE v : signed(9 DOWNTO 0); -- 2.8 + BEGIN + v:=t.r_abxcxx + t.r_dxxx; + x.r:=bound(unsigned(v),8); + v:=t.g_abxcxx + t.g_dxxx; + x.g:=bound(unsigned(v),8); + v:=t.b_abxcxx + t.b_dxxx; + x.b:=bound(unsigned(v),8); + RETURN x; + END FUNCTION; + + ----------------------------------------------------------------------------- + SIGNAL o_h_bic_pix,o_v_bic_pix : type_pix; + SIGNAL o_h_bic_abcd1,o_h_bic_abcd2 : type_bic_pix_abcd; + SIGNAL o_v_bic_abcd1,o_v_bic_abcd2 : type_bic_pix_abcd; + SIGNAL o_h_bic_tt1,o_v_bic_tt1 : type_bic_tt1; + SIGNAL o_h_bic_tt2,o_v_bic_tt2 : type_bic_tt2; + + ----------------------------------------------------------------------------- + -- Polyphase + + CONSTANT POLY16 : arr_int9 := ( + -24,-21,-15,-9,-5,-1,4,8,6,8,5,4,3,1,0,0, + 176,174,169,160,150,131,115,85,58,27,4,-6,-20,-24,-26,-25, + -24,-25,-26,-24,-20,-6,4,27,58,85,115,131,150,160,169,174, + 0,0,0,1,3,4,5,8,6,8,4,-1,-5,-9,-15,-21); + + CONSTANT POLY32 : arr_int9 := ( + -24,-22,-20,-18,-16,-13,-11,-8,-6,-3,-1,0,2,3,5,5,6,6,6,5,5,4,4,3,2,1,1,0,0,0,0,0, + 176,175,174,172,169,164,160,153,147,138,129,119,109,96,84,71,58,40,22,12,3,-4,-12,-16,-20,-22,-25,-25,-26,-25,-25,-25, + -24,-25,-26,-26,-26,-24,-23,-19,-16,-10,-4,4,11,22,32,45,58,77,96,108,119,129,140,147,154,159,165,168,172,173,175,175, + 0,0,0,0,1,1,2,2,3,3,4,5,6,7,7,7,6,5,4,3,1,-1,-4,-6,-8,-10,-13,-15,-18,-20,-22,-22); + + FUNCTION init_poly RETURN arr_uv36 IS + VARIABLE m : arr_uv36(0 TO 2**FRAC-1) :=(OTHERS =>x"000000000"); + BEGIN + IF FRAC=4 THEN + FOR i IN 0 TO 15 LOOP + m(i):=unsigned(to_signed(POLY16(i),9) & to_signed(POLY16(i+16),9) & + to_signed(POLY16(i+32),9) & to_signed(POLY16(i+48),9)); + END LOOP; + ELSIF FRAC=5 THEN + FOR i IN 0 TO 31 LOOP + m(i):=unsigned(to_signed(POLY32(i),9) & to_signed(POLY32(i+32),9) & + to_signed(POLY32(i+64),9) & to_signed(POLY32(i+96),9)); + END LOOP; + END IF; + RETURN m; + END FUNCTION; + + SIGNAL o_h_poly : arr_uv36(0 TO 2**FRAC-1):=init_poly; + SIGNAL o_v_poly : arr_uv36(0 TO 2**FRAC-1):=init_poly; + ATTRIBUTE ramstyle OF o_h_poly : SIGNAL IS "no_rw_check"; + ATTRIBUTE ramstyle OF o_v_poly : SIGNAL IS "no_rw_check"; + SIGNAL o_h_poly_a,o_v_poly_a : integer RANGE 0 TO 2**FRAC-1; + SIGNAL o_h_poly_dr,o_h_poly_dr2,o_v_poly_dr,o_v_poly_dr2 : unsigned(35 DOWNTO 0); + SIGNAL o_h_poly_pix,o_v_poly_pix : type_pix; + SIGNAL poly_h_wr,poly_v_wr : std_logic; + SIGNAL poly_tdw : unsigned(35 DOWNTO 0); + SIGNAL poly_a2 : unsigned(FRAC-1 DOWNTO 0); + + TYPE type_poly_t IS RECORD + r0,r1,b0,b1,g0,g1 : signed(17 DOWNTO 0); + END RECORD; + + SIGNAL o_h_poly_t,o_v_poly_t : type_poly_t; + + FUNCTION poly_calc1(fi : unsigned(35 DOWNTO 0); + p : arr_pix(0 TO 3)) RETURN type_poly_t IS + VARIABLE t : type_poly_t; + BEGIN + -- 2.7 * 1.8 = 3.15 + t.r0:=(signed(fi(35 DOWNTO 27)) * signed('0' & p(0).r) + + signed(fi(26 DOWNTO 18)) * signed('0' & p(1).r)); + t.r1:=(signed(fi(17 DOWNTO 9)) * signed('0' & p(2).r) + + signed(fi( 8 DOWNTO 0)) * signed('0' & p(3).r)); + t.g0:=(signed(fi(35 DOWNTO 27)) * signed('0' & p(0).g) + + signed(fi(26 DOWNTO 18)) * signed('0' & p(1).g)); + t.g1:=(signed(fi(17 DOWNTO 9)) * signed('0' & p(2).g) + + signed(fi( 8 DOWNTO 0)) * signed('0' & p(3).g)); + t.b0:=(signed(fi(35 DOWNTO 27)) * signed('0' & p(0).b) + + signed(fi(26 DOWNTO 18)) * signed('0' & p(1).b)); + t.b1:=(signed(fi(17 DOWNTO 9)) * signed('0' & p(2).b) + + signed(fi( 8 DOWNTO 0)) * signed('0' & p(3).b)); + RETURN t; + END FUNCTION; + + FUNCTION poly_calc2(t : type_poly_t) RETURN type_pix IS + VARIABLE p : type_pix; + BEGIN + p.r:=bound(unsigned(t.r0+t.r1),15); + p.g:=bound(unsigned(t.g0+t.g1),15); + p.b:=bound(unsigned(t.b0+t.b1),15); + RETURN p; + END FUNCTION; + +BEGIN + + ----------------------------------------------------------------------------- + i_reset_na<='0' WHEN reset_na='0' ELSE '1' WHEN rising_edge(i_clk); + o_reset_na<='0' WHEN reset_na='0' ELSE '1' WHEN rising_edge(o_clk); + avl_reset_na<='0' WHEN reset_na='0' ELSE '1' WHEN rising_edge(avl_clk); + + ----------------------------------------------------------------------------- + -- Input pixels FIFO and shreg + InAT:PROCESS(i_clk,i_reset_na) IS + CONSTANT Z : unsigned(FRAC-1 DOWNTO 0):=(OTHERS =>'0'); + VARIABLE frac_v : unsigned(FRAC-1 DOWNTO 0); + VARIABLE div_v : unsigned(16 DOWNTO 0); + VARIABLE dir_v : unsigned(11 DOWNTO 0); + VARIABLE bil_t_v : type_bil_t; + BEGIN + IF i_reset_na='0' THEN + i_write<='0'; + + ELSIF rising_edge(i_clk) THEN + i_push<='0'; + i_pushhead<='0'; + i_eol<='0'; -- End Of Line + i_freeze <=freeze; -- + i_iauto<=iauto; -- + i_wreq<='0'; + i_wr<='0'; + + ------------------------------------------------------ + i_head(127 DOWNTO 120)<=x"01"; -- Header type + i_head(119 DOWNTO 112)<="000000" & i_format; -- Header format + i_head(111 DOWNTO 96)<="0000" & to_unsigned(N_BURST,12); -- Header size + i_head(95 DOWNTO 80)<=x"0000"; -- Attributes. TBD + i_head(80)<=i_inter; + i_head(81)<=i_flm; + i_head(82)<=i_hdown; + i_head(83)<=i_vdown; + i_head(84)<=i_mode(3); + i_head(87 DOWNTO 85)<=i_count; + i_head(79 DOWNTO 64)<="0000" & to_unsigned(i_hrsize,12); -- Image width + i_head(63 DOWNTO 48)<="0000" & to_unsigned(i_vrsize,12); -- Image height + i_head(47 DOWNTO 32)<= + to_unsigned(N_BURST * i_hburst,16); -- Line Length. Bytes + i_head(31 DOWNTO 16)<="0000" & to_unsigned(i_ohsize,12); + i_head(15 DOWNTO 0) <="0000" & to_unsigned(i_ovsize,12); + + ------------------------------------------------------ + i_ppix<=(i_r,i_g,i_b); + i_pvs<=i_vs; + i_pfl<=i_fl; + i_pde<=i_de; + i_pce<=i_ce; + + ------------------------------------------------------ + IF i_pce='1' THEN + ---------------------------------------------------- + i_vs_pre<=i_pvs; + i_de_pre<=i_pde; + i_fl_pre<=i_pfl; + + ---------------------------------------------------- + -- Detect interlaced video + IF NOT INTER THEN + i_intercnt<=0; + ELSIF i_pfl/=i_fl_pre THEN + i_intercnt<=3; + ELSIF i_pvs='1' AND i_vs_pre='0' AND i_intercnt>0 THEN + i_intercnt<=i_intercnt-1; + END IF; + i_inter<=to_std_logic(i_intercnt>0); + + ---------------------------------------------------- + IF i_pvs='1' AND i_vs_pre='0' THEN + i_sof<='1'; + END IF; + + IF i_pde='1' AND i_de_pre='0' THEN + i_flm<=i_pfl; + END IF; + + IF i_pde='1' AND i_sof='1' THEN + i_sof<='0'; + i_vcpt<=0; + IF i_inter='1' AND i_flm='0' AND i_half='0' AND INTER THEN + i_line<='1'; + i_adrsi<=to_unsigned(N_BURST * i_hburst,32) + + to_unsigned(N_BURST * to_integer( + unsigned'("00") & to_std_logic(HEADER)),32); + ELSE + i_line<='0'; + i_adrsi<=to_unsigned(N_BURST * to_integer( + unsigned'("00") & to_std_logic(HEADER)),32); + END IF; + END IF; + + i_ven<=to_std_logic(i_hcpt>=i_hmin AND i_hcpt<=i_hmax AND + i_vcpt>=i_vmin AND i_vcpt<=i_vmax); + + -- Detects end of frame for triple buffering. + i_endframe0<=i_vs AND (NOT i_inter OR i_flm); + i_endframe1<=i_vs AND (NOT i_inter OR NOT i_flm); + + i_vss<=to_std_logic(i_vcpt>=i_vmin AND i_vcpt<=i_vmax); + + ---------------------------------------------------- + IF i_pde='1' AND i_de_pre='0' THEN + i_vimax<=i_vcpt; + i_hcpt<=0; + ELSE + i_hcpt<=(i_hcpt+1) MOD 4096; + END IF; + + IF i_pde='0' AND i_de_pre='1' THEN + i_himax<=i_hcpt; + END IF; + + IF i_iauto='1' THEN + -- Auto-size + i_hmin<=0; + i_hmax<=i_himax; + i_vmin<=0; + IF i_pvs='1' AND i_vs_pre='0' AND (i_inter='0' OR i_pfl='0') THEN + i_vmax<=i_vimax; + END IF; + ELSE + -- Forced image + i_hmin<=himin; -- + i_hmax<=himax; -- + i_vmin<=vimin; -- + IF i_pvs='1' AND i_vs_pre='0' AND (i_inter='0' OR i_pfl='0') THEN + i_vmax<=vimax; -- + END IF; + END IF; + + IF i_pvs='1' AND i_vs_pre='0' AND (i_inter='0' OR i_pfl='0') THEN + i_vdmax<=i_vimax; + END IF; + i_hdmax<=i_himax; + + IF i_format="00" OR i_format="11" THEN -- 16bpp + i_hburst<=(i_hrsize*2 + N_BURST - 1) / N_BURST; + ELSIF i_format="01" THEN -- 24bpp + i_hburst<=(i_hrsize*3 + N_BURST - 1) / N_BURST; + ELSE -- 32bpp + i_hburst<=(i_hrsize*4 + N_BURST - 1) / N_BURST; + END IF; + ---------------------------------------------------- + i_mode<=mode; -- + i_format<=format; -- + + -- Downscaling : Nearest or bilinear + i_bil<=to_std_logic(i_mode(2 DOWNTO 0)/="000" AND DOWNSCALE); + + i_hdown<=to_std_logic(i_hsize>i_ohsize AND DOWNSCALE); --H downscale + i_vdown<=to_std_logic(i_vsize>i_ovsize AND DOWNSCALE); --V downscale + + ---------------------------------------------------- + i_hsize <=(4096+i_hmax-i_hmin+1) MOD 4096; + i_vmaxmin<=(4096+i_vmax-i_vmin+1) MOD 4096; + + IF i_inter='0' THEN + -- Non interlaced + i_vsize<=i_vmaxmin; + i_half <='0'; + ELSIF i_ovsize<2*i_vmaxmin THEN + -- Interlaced, but downscaling, use only half frames + i_vsize<=i_vmaxmin; + i_half <='1'; + ELSE + -- Interlaced : Double image height + i_vsize<=2*i_vmaxmin; + i_half <='0'; + END IF; + + i_ohsize<=o_hsize; -- + i_ovsize<=o_vsize; -- + + ---------------------------------------------------- + -- Downscaling vertical + i_divstart<='0'; + IF i_de_delay=16 THEN + IF (i_vacc + 2*i_ovsize) < 2*i_vsize THEN + i_vacc<=(i_vacc + 2*i_ovsize) MOD 8192; + i_vnp<='0'; + ELSE + i_vacc<=(i_vacc + 2*i_ovsize - 2*i_vsize + 8192) MOD 8192; + i_vnp<='1'; + END IF; + i_divstart<='1'; + + IF i_vcpt=i_vmin THEN + i_vacc<=(i_vsize - i_ovsize + 8192) MOD 8192; + i_vnp<='1'; -- + END IF; + END IF; + + IF i_vdown='0' THEN + i_vnp<='1'; + END IF; + + -- Downscaling horizontal + IF i_ven='1' THEN + IF i_hacc + 2*i_ohsize < 2*i_hsize THEN + i_hacc<=(i_hacc + 2*i_ohsize) MOD 8192; + i_hnp<='0'; -- Skip. pix. + ELSE + i_hacc<=(i_hacc + 2*i_ohsize - 2*i_hsize + 8192) MOD 8192; + i_hnp<='1'; + END IF; + END IF; + IF i_hdown='0' THEN + i_hnp<='1'; + END IF; + + ---------------------------------------------------- + -- Downscaling interpolation + i_hpixp<=i_ppix; + i_hpix0<=i_hpixp; + i_hpix1<=i_hpix0; + i_hpix2<=i_hpix1; + i_hpix3<=i_hpix2; + i_hpix4<=i_hpix3; + + i_hnp1<=i_hnp; i_hnp2<=i_hnp1; i_hnp3<=i_hnp2; i_hnp4<=i_hnp3; + i_ven1<=i_ven; i_ven2<=i_ven1; i_ven3<=i_ven2; i_ven4<=i_ven3; + i_ven5<=i_ven4; i_ven6<=i_ven5; + + -- C1 : DIV 1. Pipelined 4 bits non-restoring divider + dir_v:=x"000"; + div_v:=to_unsigned(i_hacc * 16,17); + + div_v:=div_v-to_unsigned(i_hsize*16,17); + dir_v(11):=NOT div_v(16); + IF div_v(16)='0' THEN + div_v:=div_v-to_unsigned(i_hsize*8,17); + ELSE + div_v:=div_v+to_unsigned(i_hsize*8,17); + END IF; + dir_v(10):=NOT div_v(16); + i_div<=div_v; + i_dir<=dir_v; + + -- C2 : DIV 2. + div_v:=i_div; + dir_v:=i_dir; + IF div_v(16)='0' THEN + div_v:=div_v-to_unsigned(i_hsize*4,17); + ELSE + div_v:=div_v+to_unsigned(i_hsize*4,17); + END IF; + dir_v(9):=NOT div_v(16); + + IF div_v(16)='0' THEN + div_v:=div_v-to_unsigned(i_hsize*2,17); + ELSE + div_v:=div_v+to_unsigned(i_hsize*2,17); + END IF; + dir_v(8):=NOT div_v(16); + i_h_frac<=dir_v; + + -- C4 : Horizontal Bilinear + IF i_bil='0' THEN + frac_v:=near_frac(i_h_frac); + ELSE + frac_v:=bil_frac(i_h_frac); + END IF; + + i_h_bil_t<=bil_calc(frac_v,(i_hpix2,i_hpix2,i_hpix3,i_hpix3)); + i_hpix.r<=bound(i_h_bil_t.r,8+FRAC); + i_hpix.g<=bound(i_h_bil_t.g,8+FRAC); + i_hpix.b<=bound(i_h_bil_t.b,8+FRAC); + + IF i_hdown='0' THEN + i_hpix<=i_hpix4; + END IF; + + -- C5 : Vertical Bilinear + IF i_bil='0' THEN + frac_v:=near_frac(i_v_frac(11 DOWNTO 0)); + ELSE + frac_v:=bil_frac(i_v_frac(11 DOWNTO 0)); + END IF; + + bil_t_v:=bil_calc(frac_v,(i_hpix,i_hpix,i_ldrm,i_ldrm)); + i_pix.r<=bound(bil_t_v.r,8+FRAC); + i_pix.g<=bound(bil_t_v.g,8+FRAC); + i_pix.b<=bound(bil_t_v.b,8+FRAC); + + IF i_vdown='0' THEN + i_pix<=i_hpix; + END IF; + + ---------------------------------------------------- + -- VNP : Vert. downscaling line enable + -- HNP : Horiz. downscaling pix. enable + -- VEN : Enable pixel within displayed window + + IF (i_hnp4='1' AND i_ven6='1') OR i_pushend='1' THEN + i_shift<=shift_ishift(i_shift,i_pix,i_format); + i_dw<=shift_ipack(i_dw,i_acpt,i_shift,i_pix,i_format); + + IF shift_inext(i_acpt,i_format) AND i_vnp='1' THEN + i_push<='1'; + i_pushend<='0'; + END IF; + i_acpt<=(i_acpt+1) MOD 16; + END IF; + + IF i_ven6='1' AND i_ven5='0' AND i_vnp='1' THEN + i_pushend<='1'; + END IF; + i_pushend2<=i_pushend; + + IF i_pushend2='1' AND i_pushend='0' THEN + i_eol<='1'; + END IF; + + IF i_pde='0' AND i_de_pre='1' THEN + i_de_delay<=0; + ELSIF i_de_delay<18 THEN + i_de_delay<=i_de_delay+1; + END IF; + + IF i_de_delay=16 THEN + i_lwad<=0; + i_lrad<=0; + i_vcpt<=i_vcpt+1; + i_hacc<=(i_hsize - i_ohsize + 8192) MOD 8192; + i_hbcpt<=0; + END IF; + IF i_de_delay=17 THEN + i_acpt<=0; + i_wad<=2*BLEN-1; + END IF; + + IF i_pvs='0' AND i_vs_pre='1' THEN + -- Push header + i_pushhead<=to_std_logic(HEADER); + END IF; + + END IF; -- IF i_pce='1' + + ------------------------------------------------------ + -- Push pixels to downscaling line buffer + i_lwr<=i_hnp4 AND i_ven5 AND i_pce; + IF i_lwr='1' THEN + i_lwad<=(i_lwad+1) MOD OHRES; + END IF; + i_ldw<=i_hpix; + + IF i_hnp3='1' AND i_ven4='1' AND i_pce='1' THEN + i_lrad<=(i_lrad+1) MOD OHRES; + END IF; + + ------------------------------------------------------ + -- Write image properties header + i_pushhead2<=i_pushhead; i_pushhead3<=i_pushhead2; + + IF i_pushhead='1' AND i_freeze='0' THEN + i_dw<=i_head(127 DOWNTO 128-N_DW); + i_count<=i_count+1; + i_wr<='1'; + i_wad<=0; + IF N_DW=128 THEN + i_alt<='0'; + i_wreq<=NOT i_freeze; + i_adrs<=(OTHERS =>'0'); + END IF; + END IF; + + IF i_pushhead2='1' AND i_freeze='0' AND N_DW=64 THEN + i_dw<=i_head(N_DW-1 DOWNTO 0); + i_wr<='1'; + i_wad<=1; + i_wreq<=NOT i_freeze; + i_alt<='0'; + i_adrs<=(OTHERS =>'0'); + END IF; + IF i_pushhead3='1' THEN + i_wad<=BLEN-1; + END IF; + + ------------------------------------------------------ + -- Push pixels to DPRAM + IF i_push='1' AND i_freeze='0' THEN + i_wr<='1'; + i_wad<=(i_wad+1) MOD (BLEN*2); + IF (i_wad+1) MOD BLEN=BLEN-1 AND i_hbcpt 12 + IDividers:PROCESS (i_clk,i_reset_na) IS + BEGIN + IF i_reset_na='0' THEN +--pragma synthesis_off + i_v_frac<=x"000"; +--pragma synthesis_on + NULL; + ELSIF rising_edge(i_clk) THEN + i_vdivi<=to_unsigned(2*i_vsize,13); + i_vdivr<=to_unsigned(i_vacc*4096,25); + + ------------------------------------------------------ + IF i_divstart='1' THEN + i_divcpt<=0; + i_divrun<='1'; + + ELSIF i_divrun='1' THEN + ---------------------------------------------------- + IF i_divcpt=6 THEN + i_divrun<='0'; + i_v_frac<=i_vdivr(4 DOWNTO 0) & NOT i_vdivr(24) & "000000"; + ELSE + i_divcpt<=i_divcpt+1; + END IF; + + IF i_vdivr(24)='0' THEN + i_vdivr(24 DOWNTO 12)<=i_vdivr(23 DOWNTO 11) - i_vdivi; + ELSE + i_vdivr(24 DOWNTO 12)<=i_vdivr(23 DOWNTO 11) + i_vdivi; + END IF; + i_vdivr(11 DOWNTO 0)<=i_vdivr(10 DOWNTO 0) & NOT i_vdivr(24); + + ---------------------------------------------------- + END IF; + END IF; + END PROCESS IDividers; + + ----------------------------------------------------------------------------- + -- DPRAM Input. Double buffer for RAM bursts. + PROCESS (i_clk) IS + BEGIN + IF rising_edge(i_clk) THEN + IF i_wr='1' THEN + i_dpram(i_wad)<=i_dw; + END IF; + END IF; + END PROCESS; + + avl_dr<=i_dpram(avl_rad_c) WHEN rising_edge(avl_clk); + + -- Line buffer for downscaling with interpolation + DownLine:IF DOWNSCALE GENERATE + ILBUF:PROCESS(i_clk) IS + BEGIN + IF rising_edge(i_clk) THEN + IF i_lwr='1' THEN + i_mem(i_lwad MOD IHRES)<=i_ldw; + END IF; + IF i_pce='1' THEN + i_ldrm<=i_mem(i_lrad MOD IHRES); + END IF; + END IF; + END PROCESS ILBUF; + END GENERATE DownLine; + + ----------------------------------------------------------------------------- + -- AVALON interface + Avaloir:PROCESS(avl_clk,avl_reset_na) IS + VARIABLE adr_v : unsigned(31 DOWNTO 0); + BEGIN + IF avl_reset_na='0' THEN + avl_state<=sIDLE; + avl_write_sr<='0'; + avl_read_sr<='0'; + avl_readdataack<='0'; + avl_readack<='0'; + + ELSIF rising_edge(avl_clk) THEN + ---------------------------------- + avl_write_sync<=i_write; -- + avl_write_sync2<=avl_write_sync; + avl_write_pulse<=avl_write_sync XOR avl_write_sync2; + IF avl_write_pulse='1' THEN + avl_wadrs <=i_wadrs AND (RAMSIZE - 1); -- + avl_wline <=i_wline; -- + avl_walt <=i_walt; -- + END IF; + + ---------------------------------- + avl_read_sync<=o_read; -- + avl_read_sync2<=avl_read_sync; + avl_read_pulse<=avl_read_sync XOR avl_read_sync2; + avl_radrs <=o_adrs; -- + avl_rline <=o_rline; -- + + -------------------------------------------- + avl_o_vs_sync<=o_vsv(0); -- + avl_o_vs<=avl_o_vs_sync; + + avl_fb_ena<=o_fb_ena; -- + IF avl_fb_ena='0' THEN + IF HEADER THEN + avl_o_offset0<=buf_offset(o_obuf0,RAMBASE,RAMSIZE) + N_BURST; -- + avl_o_offset1<=buf_offset(o_obuf1,RAMBASE,RAMSIZE) + N_BURST; -- + ELSE + avl_o_offset0<=buf_offset(o_obuf0,RAMBASE,RAMSIZE); -- + avl_o_offset1<=buf_offset(o_obuf1,RAMBASE,RAMSIZE); -- + END IF; + ELSIF avl_o_vs_sync='0' AND avl_o_vs='1' THEN + -- Copy framebuffer base address at VS falling edge + avl_o_offset0<=o_fb_base; -- + avl_o_offset1<=o_fb_base; -- + END IF; + + avl_i_offset0<=buf_offset(o_ibuf0,RAMBASE,RAMSIZE); -- + avl_i_offset1<=buf_offset(o_ibuf1,RAMBASE,RAMSIZE); -- + + -------------------------------------------- + avl_dw<=swap(unsigned(avl_readdata)); + avl_read_i<='0'; + avl_write_i<='0'; + + avl_write_sr<=(avl_write_sr OR avl_write_pulse) AND NOT avl_write_clr; + avl_read_sr <=(avl_read_sr OR avl_read_pulse) AND NOT avl_read_clr; + avl_write_clr<='0'; + avl_read_clr <='0'; + + avl_rad<=avl_rad_c; + + -------------------------------------------- + CASE avl_state IS + WHEN sIDLE => + IF avl_write_sr='1' THEN + avl_state<=sWRITE; + avl_write_clr<='1'; + IF avl_walt='0' THEN + avl_rad<=0; + ELSE + avl_rad<=BLEN; + END IF; + IF avl_wline='0' THEN + avl_address<=std_logic_vector( + avl_wadrs(N_AW+NB_LA-1 DOWNTO NB_LA) + + avl_i_offset0(N_AW+NB_LA-1 DOWNTO NB_LA)); + ELSE + avl_address<=std_logic_vector( + avl_wadrs(N_AW+NB_LA-1 DOWNTO NB_LA) + + avl_i_offset1(N_AW+NB_LA-1 DOWNTO NB_LA)); + END IF; + ELSIF avl_read_sr='1' THEN + avl_state<=sREAD; + avl_read_clr<='1'; + END IF; + + WHEN sWRITE => + avl_write_i<='1'; + IF avl_write_i='1' AND avl_waitrequest='0' THEN + IF (avl_rad MOD BLEN)=BLEN-1 THEN + avl_write_i<='0'; + avl_state<=sIDLE; + END IF; + END IF; + + WHEN sREAD => + IF avl_rline='0' THEN + adr_v:=avl_radrs + avl_o_offset0; + ELSE + adr_v:=avl_radrs + avl_o_offset1; + END IF; + avl_address<=std_logic_vector(adr_v(N_AW+NB_LA-1 DOWNTO NB_LA)); + + avl_read_i<='1'; + IF avl_read_i='1' AND avl_waitrequest='0' THEN + avl_state<=sIDLE; + avl_read_i<='0'; + avl_readack<=NOT avl_readack; + END IF; + END CASE; + + -------------------------------------------- + -- Pipelined data read + avl_wr<='0'; + IF avl_readdatavalid='1' THEN + avl_wr<='1'; + avl_wad<=(avl_wad+1) MOD (2*BLEN); + IF (avl_wad MOD BLEN)=BLEN-2 THEN + avl_readdataack<=NOT avl_readdataack; + END IF; + END IF; + + IF avl_o_vs_sync='0' AND avl_o_vs='1' THEN + avl_wad<=2*BLEN-1; + END IF; + + -------------------------------------------- + END IF; + END PROCESS Avaloir; + + avl_read<=avl_read_i; + avl_write<=avl_write_i; + avl_writedata<=std_logic_vector(swap(avl_dr)); + avl_burstcount<=std_logic_vector(to_unsigned(BLEN,8)); + avl_byteenable<=(OTHERS =>'1'); + + avl_rad_c<=(avl_rad+1) MOD (2*BLEN) + WHEN avl_write_i='1' AND avl_waitrequest='0' ELSE avl_rad; + + ----------------------------------------------------------------------------- + -- DPRAM Output. Double buffer for RAM bursts. + PROCESS (avl_clk) IS + BEGIN + IF rising_edge(avl_clk) THEN + IF avl_wr='1' THEN + o_dpram(avl_wad)<=avl_dw; + END IF; + END IF; + END PROCESS; + + o_dr<=o_dpram(o_ad3) WHEN rising_edge(o_clk); + + ----------------------------------------------------------------------------- + -- Output Vertical Divider + -- Vfrac = Vacc / Vsize + ODivider:PROCESS (o_clk,o_reset_na) IS + BEGIN + IF o_reset_na='0' THEN +--pragma synthesis_off + o_vfrac<=x"000"; +--pragma synthesis_on + ELSIF rising_edge(o_clk) THEN + o_vdivi<=to_unsigned(2*o_vsize,13); + o_vdivr<=to_unsigned(o_vacc*4096,25); + ------------------------------------------------------ + IF o_divstart='1' THEN + o_divcpt<=0; + o_divrun<='1'; + + ELSIF o_divrun='1' THEN + ---------------------------------------------------- + IF o_divcpt=12 THEN + o_divrun<='0'; + o_vfrac<=o_vdivr(10 DOWNTO 0) & NOT o_vdivr(24); + ELSE + o_divcpt<=o_divcpt+1; + END IF; + + IF o_vdivr(24)='0' THEN + o_vdivr(24 DOWNTO 12)<=o_vdivr(23 DOWNTO 11) - o_vdivi; + ELSE + o_vdivr(24 DOWNTO 12)<=o_vdivr(23 DOWNTO 11) + o_vdivi; + END IF; + o_vdivr(11 DOWNTO 0)<=o_vdivr(10 DOWNTO 0) & NOT o_vdivr(24); + ---------------------------------------------------- + END IF; + END IF; + END PROCESS ODivider; + + ----------------------------------------------------------------------------- + Scalaire:PROCESS (o_clk,o_reset_na) IS + VARIABLE lev_inc_v,lev_dec_v : std_logic; + VARIABLE prim_v,last_v,bib_v : std_logic; + VARIABLE shift_v : unsigned(0 TO N_DW+15); + VARIABLE hpix_v : type_pix; + VARIABLE hcarry_v,vcarry_v : boolean; + VARIABLE dif_v : natural RANGE 0 TO 8*OHRES-1; + VARIABLE off_v : natural RANGE 0 TO 15; + BEGIN + IF o_reset_na='0' THEN + o_copy<=sWAIT; + o_state<=sDISP; + o_read_pre<='0'; + o_readlev<=0; + o_copylev<=0; + o_hsp<='0'; + + ELSIF rising_edge(o_clk) THEN + ------------------------------------------------------ + o_mode <=mode; -- ? + o_format <="0001" & format; -- ? + + o_run <=run; -- ? + + o_htotal <=htotal; -- ? + o_hsstart<=hsstart; -- ? + o_hsend <=hsend; -- ? + o_hdisp <=hdisp; -- ? + o_hmin <=hmin; -- ? + o_hmax <=hmax; -- ? + + o_vtotal <=vtotal; -- ? + o_vsstart<=vsstart; -- ? + o_vsend <=vsend; -- ? + o_vdisp <=vdisp; -- ? + o_vmin <=vmin; -- ? + o_vmax <=vmax; -- ? + + o_hsize <=o_hmax - o_hmin + 1; + o_vsize <=o_vmax - o_vmin + 1; + + -------------------------------------------- + -- Triple buffering. + -- For intelaced video, half frames are updated independently + -- Input : Toggle buffer at end of input frame + o_inter <=i_inter; -- + o_iendframe0<=i_endframe0; -- + o_iendframe02<=o_iendframe0; + IF o_iendframe0='1' AND o_iendframe02='0' THEN + o_ibuf0<=buf_next(o_ibuf0,o_obuf0); + o_bufup0<='1'; + END IF; + o_iendframe1<=i_endframe1; -- + o_iendframe12<=o_iendframe1; + IF o_iendframe1='1' AND o_iendframe12='0' THEN + o_ibuf1<=buf_next(o_ibuf1,o_obuf1); + o_bufup1<='1'; + END IF; + -- Output : Change framebuffer, and image properties, at VS falling edge + IF o_vsv(1)='1' AND o_vsv(0)='0' AND o_bufup1='1' THEN + o_obuf1<=buf_next(o_obuf1,o_ibuf1); + o_bufup1<='0'; + o_ihsize<=i_hrsize; -- + o_ivsize<=i_vrsize; -- + o_hdown<=i_hdown; -- + o_vdown<=i_vdown; -- + END IF; + -- Framebuffer mode. + IF o_fb_ena='1' THEN + o_ihsize<=o_fb_hsize; + o_ivsize<=o_fb_vsize; + o_format<=o_fb_format; + o_hdown<='0'; + o_vdown<='0'; + END IF; + + o_ihsize_temp <= o_ihsize * to_integer(o_format(2 DOWNTO 0) - 2); + o_ihsize_temp2 <= (o_ihsize_temp + N_BURST - 1); + o_hburst <= o_ihsize_temp2 / N_BURST; + + IF o_fb_ena='1' AND o_fb_stride /= 0 THEN + o_stride<=o_fb_stride; + ELSE + o_stride<=to_unsigned(o_ihsize_temp2,14); + o_stride(NB_BURST-1 DOWNTO 0)<=(OTHERS =>'0'); + END IF; + + IF o_vsv(1)='1' AND o_vsv(0)='0' AND o_bufup0='1' THEN + o_obuf0<=buf_next(o_obuf0,o_ibuf0); + o_bufup0<='0'; + END IF; + + IF o_inter='0' THEN + o_ibuf1<=o_ibuf0; + o_obuf1<=o_obuf0; + END IF; + + -- Triple buffer disabled + IF o_mode(3)='0' THEN + o_obuf0<=0; + o_obuf1<=0; + o_ibuf0<=0; + o_ibuf1<=0; + END IF; + + ------------------------------------------------------ + o_hmode<=o_mode; + IF o_hdown='1' AND DOWNSCALE THEN + -- Force nearest if downscaling : Downscaled framebuffer + o_hmode(2 DOWNTO 0)<="000"; + END IF; + + o_vmode<=o_mode; + IF o_vdown='1' AND DOWNSCALE THEN + -- Force nearest if downscaling : Downscaled framebuffer + o_vmode(2 DOWNTO 0)<="000"; + END IF; + + ------------------------------------------------------ + -- End DRAM READ + o_readack_sync<=avl_readack; -- + o_readack_sync2<=o_readack_sync; + o_readack<=o_readack_sync XOR o_readack_sync2; + + o_readdataack_sync<=avl_readdataack; -- + o_readdataack_sync2<=o_readdataack_sync; + o_readdataack<=o_readdataack_sync XOR o_readdataack_sync2; + + ------------------------------------------------------ + lev_inc_v:='0'; + lev_dec_v:='0'; + + -- acpt : Pixel position within current data word + -- dcpt : Destination image position + + -- Force preload 2 lines at top of screen + IF o_hsv(0)='1' AND o_hsv(1)='0' THEN + IF o_vcpt_pre3=o_vmin THEN + o_fload<=2; + o_bibu<='0'; + END IF; + o_hsp<='1'; + END IF; + + o_vpe<=to_std_logic(o_vcpt_pre=o_vmin); + o_divstart<='0'; + o_adrsa<='0'; + o_adrsb<=o_adrsa; + + o_vacc_ini<=(o_vsize - o_ivsize + 8192) MOD 8192; + o_hacc_ini<=(o_hsize + o_ihsize + 8192) MOD 8192; + + --Alternate phase + --o_vacc_ini<=o_ivsize; + --o_hacc_ini<=(2*o_hsize - o_ihsize + 8192) MOD 8192; + + CASE o_state IS + -------------------------------------------------- + WHEN sDISP => + IF o_hsp='1' THEN + o_state<=sHSYNC; + o_hsp<='0'; + END IF; + + -------------------------------------------------- + WHEN sHSYNC => + dif_v:=(o_vacc_next - 2*o_vsize + 16384) MOD 16384; + IF dif_v>=8192 THEN + o_vacc <=o_vacc_next; + o_vacc_next<=(o_vacc_next + 2*o_ivsize) MOD 8192; + vcarry_v:=false; + ELSE + o_vacc <=dif_v; + o_vacc_next<=(dif_v + 2*o_ivsize + 8192) MOD 8192; + vcarry_v:=true; + END IF; + o_divstart<='1'; + IF o_vcpt_pre2=o_vmin THEN + o_vacc <=o_vacc_ini; + o_vacc_next<=o_vacc_ini + 2*o_ivsize; + o_vacpt<=x"001"; + vcarry_v:=false; + END IF; + + IF vcarry_v THEN + o_vacpt<=o_vacpt+1; + END IF; + o_hbcpt<=0; -- Clear burst counter on line + IF (o_vpe='1' AND vcarry_v) OR o_fload>0 THEN + o_state<=sREAD; + ELSE + o_state<=sDISP; + END IF; + + WHEN sREAD => + -- Read a block + IF o_readlev<2 AND o_adrsb='1' THEN + lev_inc_v:='1'; + o_read_pre<=NOT o_read_pre; + o_state <=sWAITREAD; + o_bibu<=NOT o_bibu; + END IF; + prim_v:=to_std_logic(o_hbcpt=0); + last_v:=to_std_logic(o_hbcpt=o_hburst-1); + bib_v :=o_bibu; + off_v :=pixoffset(o_adrs + o_fb_base(NB_LA-1 DOWNTO 0),o_fb_format); + IF o_fb_ena='0' THEN + off_v:=0; + END IF; + o_adrsa<='1'; + + WHEN sWAITREAD => + IF o_readack='1' THEN + o_hbcpt<=o_hbcpt+1; + IF o_hbcpt=1 THEN + o_fload<=o_fload-1; + END IF; + END IF; + END IF; + + -------------------------------------------------- + END CASE; + + o_read<=o_read_pre AND o_run; + o_rline<=o_vacpt(0); -- Even/Odd line for interlaced video + + o_adrs_pre<=to_integer(o_vacpt) * to_integer(o_stride); + IF o_adrsa='1' THEN + IF o_fload=2 THEN + o_adrs<=to_unsigned(o_hbcpt * N_BURST,32); + o_alt<="1111"; + ELSIF o_fload=1 THEN + o_adrs<=to_unsigned(o_hbcpt * N_BURST,32) + o_stride; + o_alt<="0100"; + ELSE + o_adrs<=to_unsigned(o_adrs_pre + (o_hbcpt * N_BURST),32); + o_alt<=altx(o_vacpt(1 DOWNTO 0) + 1); + END IF; + END IF; + + ------------------------------------------------------ + -- Copy from buffered memory to pixel lines + o_sh<='0'; + CASE o_copy IS + WHEN sWAIT => + o_copyv(0)<='0'; + IF o_copylev>0 AND o_copyv(0)='0' THEN + o_copy<=sCOPY; + IF o_off(0)>0 AND o_primv(0)='1' THEN + o_copy<=sSHIFT; + END IF; + o_altx<=o_alt; + END IF; + o_adturn<='0'; + o_pshift<=o_off(0) -1; + IF o_primv(0)='1' THEN + -- First memcopy of a horizontal line, carriage return ! + o_ihsizem<=o_ihsize + o_off(0) - 2; + o_hacc <=o_hacc_ini; + o_hacc_next<=o_hacc_ini + 2*o_ihsize; + o_hacpt <=x"000"; + o_dcpt<=0; + o_dshi<=2; + o_acpt<=0; + o_first<='1'; + o_last<='0'; + END IF; + + IF o_bibv(0)='0' THEN + o_ad<=0; + ELSE + o_ad<=BLEN; + END IF; + + WHEN sSHIFT => + o_hacpt<=o_hacpt+1; + o_sh<='1'; + o_acpt<=(o_acpt+1) MOD 16; + IF shift_onext(o_acpt,o_format) THEN + o_ad<=(o_ad+1) MOD (2*BLEN); + END IF; + o_pshift<=o_pshift-1; + IF o_pshift=0 THEN + o_copy<=sCOPY; + END IF; + + WHEN sCOPY => + -- dshi : Force shift first two or three pixels of each line + IF o_dshi=0 THEN + dif_v:=(o_hacc_next - 2*o_hsize + (8*OHRES)) MOD (8*OHRES); + IF dif_v>=4*OHRES THEN + o_hacc<=o_hacc_next; + o_hacc_next<=o_hacc_next + 2*o_ihsize; + hcarry_v:=false; + ELSE + o_hacc<=dif_v; + o_hacc_next<=(dif_v + 2*o_ihsize + (4*OHRES)) MOD (4*OHRES); + hcarry_v:=true; + END IF; + o_dcpt<=(o_dcpt+1) MOD 4096; + ELSE + o_dshi<=o_dshi-1; + hcarry_v:=false; + END IF; + IF o_dshi<=1 THEN + o_copyv(0)<='1'; + END IF; + IF hcarry_v THEN + o_hacpt<=o_hacpt+1; + o_last <=to_std_logic(o_hacpt>=o_ihsizem); + END IF; + + IF hcarry_v OR o_dshi>0 THEN + o_sh<='1'; + o_acpt<=(o_acpt+1) MOD 16; + + -- Shift two more pixels to the right before ending line. + o_last1<=o_last; + o_last2<=o_last1; + + IF shift_onext(o_acpt,o_format) THEN + o_ad<=(o_ad+1) MOD (2*BLEN); + END IF; + + IF o_adturn='1' AND (shift_onext((o_acpt+1) MOD 16,o_format)) AND + (((o_ad MOD BLEN=0) AND o_lastv(0)='0') OR o_last2='1') THEN + o_copy<=sWAIT; + lev_dec_v:='1'; + END IF; + + IF o_ad MOD BLEN=4 THEN + o_adturn<='1'; + END IF; + END IF; + END CASE; + + o_acpt1<=o_acpt; o_acpt2<=o_acpt1; o_acpt3<=o_acpt2; o_acpt4<=o_acpt3; + o_ad1<=o_ad; o_ad2<=o_ad1; o_ad3<=o_ad2; + o_sh1<=o_sh; o_sh2<=o_sh1; o_sh3<=o_sh2; o_sh4<=o_sh3; + o_lastt1<=o_last; o_lastt2<=o_lastt1; + o_lastt3<=o_lastt2; o_lastt4<=o_lastt3; + + ------------------------------------------------------ + IF o_sh3='1' THEN + shift_v:=shift_opack(o_acpt4,o_shift,o_dr,o_format); + o_shift<=shift_v; + o_hpixs<=shift_opix(shift_v,o_format); + END IF; + + IF o_sh4='1' THEN + hpix_v:=o_hpixs; + IF o_format(4)='1' THEN -- Swap B <-> R + hpix_v:=(r=>o_hpixs.b,g=>o_hpixs.g,b=>o_hpixs.r); + END IF; + IF o_format(2 DOWNTO 0)="011" THEN + -- 8bpp indexed colour mode + hpix_v:=(r=>o_fb_pal_dr(23 DOWNTO 16),g=>o_fb_pal_dr(15 DOWNTO 8), + b=>o_fb_pal_dr(7 DOWNTO 0)); + END IF; + o_hpix0<=hpix_v; + o_hpix1<=o_hpix0; + o_hpix2<=o_hpix1; + o_hpix3<=o_hpix2; + + IF o_first='1' THEN + -- Left edge. Duplicate first pixel + o_hpix1<=hpix_v; + o_hpix2<=hpix_v; + o_first<='0'; + END IF; + IF o_lastt4='1' THEN + -- Right edge. Keep last pixel. + o_hpix0<=o_hpix0; + END IF; + END IF; + + ------------------------------------------------------ + -- lev_inc : read start + -- lev_dec : end of copy + -- READLEV : Number of ongoing Avalon Reads + IF lev_dec_v='0' AND lev_inc_v='1' THEN + o_readlev<=o_readlev+1; + ELSIF lev_dec_v='1' AND lev_inc_v='0' THEN + o_readlev<=o_readlev-1; + END IF; + + -- COPYLEV : Number of ongoing copies to line buffers + IF lev_dec_v='1' AND o_readdataack='0' THEN + o_copylev<=o_copylev-1; + ELSIF lev_dec_v='0' AND o_readdataack='1' THEN + o_copylev<=o_copylev+1; + END IF; + + -- FIFOs + IF lev_dec_v='1' THEN + o_primv(0 TO 1)<=o_primv(1 TO 2); -- First buffer of line + o_lastv(0 TO 1)<=o_lastv(1 TO 2); -- Last buffer of line + o_bibv (0 TO 1)<=o_bibv (1 TO 2); -- Double buffer select + o_off (0 TO 1)<=o_off (1 TO 2); -- Start offset + END IF; + + IF lev_inc_v='1' THEN + IF o_readlev=0 OR (o_readlev=1 AND lev_dec_v='1') THEN + o_primv(0)<=prim_v; + o_lastv(0)<=last_v; + o_bibv (0)<=bib_v; + o_off (0)<=off_v; + ELSIF (o_readlev=1 AND lev_dec_v='0') OR + (o_readlev=2 AND lev_dec_v='1') THEN + o_primv(1)<=prim_v; + o_lastv(1)<=last_v; + o_bibv (1)<=bib_v; + o_off (1)<=off_v; + END IF; + o_primv(2)<=prim_v; + o_lastv(2)<=last_v; + o_bibv (2)<=bib_v; + o_off (2)<=off_v; + END IF; + + ------------------------------------------------------ + END IF; + END PROCESS Scalaire; + + o_h_poly_a<=to_integer(o_hfrac1(11 DOWNTO 12-FRAC)); + o_v_poly_a<=to_integer(o_vfrac(11 DOWNTO 12-FRAC)); + + o_h_poly_dr<=o_h_poly(o_h_poly_a) WHEN rising_edge(o_clk); + o_v_poly_dr<=o_v_poly(o_v_poly_a) WHEN rising_edge(o_clk); + + -- Framebuffer palette + GenPal1:IF PALETTE GENERATE + Tempera1:PROCESS(pal1_clk) IS + BEGIN + IF rising_edge(pal1_clk) THEN + IF pal1_wr='1' THEN + pal1_mem(to_integer(pal1_a))<=pal1_dw; + END IF; + pal1_dr<=pal1_mem(to_integer(pal1_a)); + END IF; + END PROCESS; + + pal_idx <= shift_opack(o_acpt4,o_shift,o_dr,o_format)(0 TO 7); + pal_idx_lsb <= pal_idx(0) WHEN rising_edge(o_clk); + o_fb_pal_dr_x2 <= pal1_mem(to_integer(pal_idx(7 DOWNTO 1))) WHEN rising_edge(o_clk); + END GENERATE GenPal1; + + GenPal2:IF PALETTE and PALETTE2 GENERATE + Tempera2:PROCESS(pal2_clk) IS + BEGIN + IF rising_edge(pal2_clk) THEN + IF pal2_wr='1' THEN + pal2_mem(to_integer(pal2_a))<=pal2_dw; + END IF; + pal2_dr<=pal2_mem(to_integer(pal2_a)); + END IF; + END PROCESS; + + o_fb_pal_dr2 <= pal2_mem(to_integer(pal_idx(7 DOWNTO 0))) WHEN rising_edge(o_clk); + o_fb_pal_dr <= o_fb_pal_dr2 when pal_n = '1' else o_fb_pal_dr_x2(47 DOWNTO 24) WHEN pal_idx_lsb = '1' ELSE o_fb_pal_dr_x2(23 DOWNTO 0); + END GENERATE GenPal2; + + GenPal1not2:IF PALETTE and not PALETTE2 GENERATE + o_fb_pal_dr <= o_fb_pal_dr_x2(47 DOWNTO 24) WHEN pal_idx_lsb = '1' ELSE o_fb_pal_dr_x2(23 DOWNTO 0); + END GENERATE GenPal1not2; + + GenNoPal:IF NOT PALETTE GENERATE + o_fb_pal_dr<=x"000000"; + END GENERATE GenNoPal; + + ----------------------------------------------------------------------------- + -- Polyphase ROMs + Polikarpov:PROCESS(poly_clk) IS + BEGIN + IF rising_edge(poly_clk) THEN + IF poly_wr='1' THEN + poly_tdw(8+9*(3-to_integer(poly_a(1 DOWNTO 0))) DOWNTO + 9*(3-to_integer(poly_a(1 DOWNTO 0))))<=poly_dw; + END IF; + + poly_h_wr<=poly_wr AND NOT poly_a(FRAC+2); + poly_v_wr<=poly_wr AND poly_a(FRAC+2); + poly_a2<=poly_a(FRAC+1 DOWNTO 2); + + IF poly_h_wr='1' THEN + o_h_poly(to_integer(poly_a2))<=poly_tdw; + END IF; + IF poly_v_wr='1' THEN + o_v_poly(to_integer(poly_a2))<=poly_tdw; + END IF; + END IF; + END PROCESS Polikarpov; + + ----------------------------------------------------------------------------- + -- Horizontal Scaler + HSCAL:PROCESS(o_clk) IS + VARIABLE div_v : unsigned(18 DOWNTO 0); + VARIABLE dir_v : unsigned(11 DOWNTO 0); + BEGIN + IF rising_edge(o_clk) THEN + -- Pipeline signals + ----------------------------------- + -- Pipelined 6 bits non-restoring divider. Cycle 1 + dir_v:=x"000"; + div_v:=to_unsigned(o_hacc * 64,19); + + div_v:=div_v-to_unsigned(o_hsize*64,19); + dir_v(11):=NOT div_v(18); + IF div_v(18)='0' THEN + div_v:=div_v-to_unsigned(o_hsize*32,19); + ELSE + div_v:=div_v+to_unsigned(o_hsize*32,19); + END IF; + dir_v(10):=NOT div_v(18); + o_div<=div_v; + o_dir<=dir_v; + + -- Cycle 2 + div_v:=o_div; + dir_v:=o_dir; + IF div_v(18)='0' THEN + div_v:=div_v-to_unsigned(o_hsize*16,19); + ELSE + div_v:=div_v+to_unsigned(o_hsize*16,19); + END IF; + dir_v( 9):=NOT div_v(18); + + IF div_v(18)='0' THEN + div_v:=div_v-to_unsigned(o_hsize*8,19); + ELSE + div_v:=div_v+to_unsigned(o_hsize*8,19); + END IF; + dir_v(8):=NOT div_v(18); + o_div2<=div_v; + o_dir2<=dir_v; + + -- Cycle 3 + div_v:=o_div2; + dir_v:=o_dir2; + IF FRAC>4 THEN + IF div_v(18)='0' THEN + div_v:=div_v-to_unsigned(o_hsize*4,19); + ELSE + div_v:=div_v+to_unsigned(o_hsize*4,19); + END IF; + dir_v(7):=NOT div_v(18); + IF div_v(18)='0' THEN + div_v:=div_v-to_unsigned(o_hsize*2,19); + ELSE + div_v:=div_v+to_unsigned(o_hsize*2,19); + END IF; + dir_v(6):=NOT div_v(18); + END IF; + + ----------------------------------- + o_hfrac<=dir_v; + o_hfrac1<=o_hfrac; o_hfrac2<=o_hfrac1; + o_hfrac3<=o_hfrac2; o_hfrac4<=o_hfrac3; + + o_copyv(1 TO 8)<=o_copyv(0 TO 7); + + o_dcptv(1)<=o_dcpt; + IF o_dcptv(1)>=o_hsize THEN + o_copyv(2)<='0'; + END IF; + o_dcptv(2)<=o_dcptv(1) MOD OHRES; + o_dcptv(3 TO 8)<=o_dcptv(2 TO 7); + + o_hpixq<=(o_hpix3,o_hpix2,o_hpix1,o_hpix0); + + -- NEAREST / BILINEAR / SHARP BILINEAR --------------- + -- C1 : Pre-calc Sharp Bilinear + o_h_sbil_t<=sbil_frac1(o_hfrac1); + + -- C2 : Select + o_h_frac2<=(OTHERS =>'0'); + CASE o_hmode(1 DOWNTO 0) IS + WHEN "00" => -- Nearest + IF MASK(MASK_NEAREST)='1' THEN + o_h_frac2<=near_frac(o_hfrac2); + END IF; + WHEN "01" => -- Bilinear + IF MASK(MASK_BILINEAR)='1' THEN + o_h_frac2<=bil_frac(o_hfrac2); + END IF; + WHEN "10" => -- Sharp Bilinear + IF MASK(MASK_SHARP_BILINEAR)='1' THEN + o_h_frac2<=sbil_frac2(o_hfrac2,o_h_sbil_t); + END IF; + WHEN OTHERS => + NULL; + END CASE; + + -- C3 : Opposite frac + o_h_bil_t<=bil_calc(o_h_frac2,o_hpixq); + + -- C4 : Nearest / Bilinear / Sharp Bilinear + o_h_bil_pix.r<=bound(o_h_bil_t.r,8+FRAC); + o_h_bil_pix.g<=bound(o_h_bil_t.g,8+FRAC); + o_h_bil_pix.b<=bound(o_h_bil_t.b,8+FRAC); + + -- BICUBIC ------------------------------------------- + -- C1 : Bicubic coefficients A,B,C,D + + -- C2 : Bicubic calc T1 = X.D + C + o_h_bic_abcd1<=bic_calc0(o_hfrac2,(o_hpix3,o_hpix2,o_hpix1,o_hpix0)); + o_h_bic_tt1<=bic_calc1(o_hfrac2, + bic_calc0(o_hfrac2,(o_hpix3,o_hpix2,o_hpix1,o_hpix0))); + + -- C3 : Bicubic calc T2 = X.T1 + B + o_h_bic_abcd2<=o_h_bic_abcd1; + o_h_bic_tt2<=bic_calc2(o_hfrac3,o_h_bic_tt1,o_h_bic_abcd1); + + -- C4 : Bicubic final Y = X.T2 + A + o_h_bic_pix<=bic_calc3(o_hfrac4,o_h_bic_tt2,o_h_bic_abcd2); + + -- POLYPHASE ----------------------------------------- + -- C1 : Read memory + + -- C2 : Filter calc + o_h_poly_dr2<=o_h_poly_dr; + + -- C3 : Add + o_h_poly_t<=poly_calc1(o_h_poly_dr2,o_hpixq); + + -- C4 : Bounding + o_h_poly_pix<=poly_calc2(o_h_poly_t); + + -- C5 : Select interpoler ---------------------------- + o_wadl<=o_dcptv(8); + o_wr<=o_altx AND (o_copyv(8) & o_copyv(8) & o_copyv(8) & o_copyv(8)); + o_ldw<=(x"00",x"00",x"00"); + + CASE o_hmode(2 DOWNTO 0) IS + WHEN "000" | "001" | "010" => -- Nearest | Bilinear | Sharp Bilinear + IF MASK(MASK_NEAREST)='1' OR + MASK(MASK_BILINEAR)='1' OR + MASK(MASK_SHARP_BILINEAR)='1' THEN + o_ldw<=o_h_bil_pix; + END IF; + WHEN "011" => -- BiCubic + IF MASK(MASK_BICUBIC)='1' THEN + o_ldw<=o_h_bic_pix; + END IF; + WHEN OTHERS => -- PolyPhase + IF MASK(MASK_POLY)='1' THEN + o_ldw<=o_h_poly_pix; + END IF; + END CASE; + ------------------------------------------------------ + END IF; + END PROCESS HSCAL; + + ----------------------------------------------------------------------------- + -- Line buffers 4 x OHRES x (R+G+B) + OLBUF:PROCESS(o_clk) IS + BEGIN + IF rising_edge(o_clk) THEN + -- WRITES + IF o_wr(0)='1' THEN o_line0(o_wadl)<=o_ldw; END IF; + IF o_wr(1)='1' THEN o_line1(o_wadl)<=o_ldw; END IF; + IF o_wr(2)='1' THEN o_line2(o_wadl)<=o_ldw; END IF; + IF o_wr(3)='1' THEN o_line3(o_wadl)<=o_ldw; END IF; + + -- READS + o_ldr0<=o_line0(o_radl); + o_ldr1<=o_line1(o_radl); + o_ldr2<=o_line2(o_radl); + o_ldr3<=o_line3(o_radl); + END IF; + END PROCESS OLBUF; + + ----------------------------------------------------------------------------- + -- Output video sweep + OSWEEP:PROCESS(o_clk) IS + BEGIN + IF rising_edge(o_clk) THEN + IF o_ce='1' THEN + -- Output pixels count + IF o_hcpt+1=o_vtotal THEN + o_vcpt_pre3<=0; + ELSE + o_vcpt_pre3<=(o_vcpt_pre3+1) MOD 4096; + END IF; + o_vcpt_pre2<=o_vcpt_pre3; + o_vcpt_pre<=o_vcpt_pre2; + o_vcpt<=o_vcpt_pre; + END IF; + + o_end(0)<=to_std_logic(o_vcpt>=o_vdisp); + o_dev(0)<=to_std_logic(o_hcpt=o_hmin AND o_hcpt<=o_hmax AND + o_vcpt>=o_vmin AND o_vcpt<=o_vmax); + o_hsv(0)<=to_std_logic(o_hcpt>=o_hsstart AND o_hcpt=o_hsstart) OR + (o_vcpt>o_vsstart AND o_vcpt=o_vmin AND o_vcpt_pre2<=o_vmax); + o_hsv(1 TO 5)<=o_hsv(0 TO 4); + o_vsv(1 TO 5)<=o_vsv(0 TO 4); + o_dev(1 TO 5)<=o_dev(0 TO 4); + o_pev(1 TO 5)<=o_pev(0 TO 4); + o_end(1 TO 5)<=o_end(0 TO 4); + + IF o_run='0' THEN + o_hsv(2)<='0'; + o_vsv(2)<='0'; + o_dev(2)<='0'; + o_pev(2)<='0'; + o_end(2)<='0'; + END IF; + + END IF; + END IF; + + END PROCESS OSWEEP; + + ----------------------------------------------------------------------------- + -- Vertical Scaler + VSCAL:PROCESS(o_clk) IS + VARIABLE pixq_v : arr_pix(0 TO 3); + BEGIN + IF rising_edge(o_clk) THEN + IF o_ce='1' THEN + -- CYCLE 1 ----------------------------------------- + -- Read mem + o_radl<=(o_hcpt - o_hmin + OHRES) MOD OHRES; + + -- CYCLE 2 ----------------------------------------- + -- Lines reordering + CASE o_vacpt(1 DOWNTO 0) IS + WHEN "10" => pixq_v:=(o_ldr0,o_ldr1,o_ldr2,o_ldr3); + WHEN "11" => pixq_v:=(o_ldr1,o_ldr2,o_ldr3,o_ldr0); + WHEN "00" => pixq_v:=(o_ldr2,o_ldr3,o_ldr0,o_ldr1); + WHEN OTHERS => pixq_v:=(o_ldr3,o_ldr0,o_ldr1,o_ldr2); + END CASE; + + o_vpixq<=pixq_v; + + -- Bottom edge : replicate last line + IF to_integer(o_vacpt)=o_ivsize THEN + o_vpixq(2)<=pixq_v(2); + END IF; + IF to_integer(o_vacpt)>=o_ivsize+1 THEN + o_vpixq(2)<=pixq_v(1); + o_vpixq(1)<=pixq_v(1); + END IF; + + o_vpixq1<=o_vpixq; + + -- NEAREST / BILINEAR / SHARP BILINEAR ------------- + -- C3 : Pre-calc Sharp Bilinear + o_v_sbil_t<=sbil_frac1(o_vfrac); + + -- C4 : Select + o_v_frac<=(OTHERS =>'0'); + CASE o_vmode(1 DOWNTO 0) IS + WHEN "00" => -- Nearest + IF MASK(MASK_NEAREST)='1' THEN + o_v_frac<=near_frac(o_vfrac); + END IF; + WHEN "01" => -- Bilinear + IF MASK(MASK_BILINEAR)='1' THEN + o_v_frac<=bil_frac(o_vfrac); + END IF; + WHEN "10" => -- Sharp Bilinear + IF MASK(MASK_SHARP_BILINEAR)='1' THEN + o_v_frac<=sbil_frac2(o_vfrac,o_v_sbil_t); + END IF; + WHEN OTHERS => NULL; + END CASE; + + o_v_bil_t<=bil_calc(o_v_frac,o_vpixq1); + + -- C6 : Nearest / Bilinear / Sharp Bilinear + o_v_bil_pix.r<=bound(o_v_bil_t.r,8+FRAC); + o_v_bil_pix.g<=bound(o_v_bil_t.g,8+FRAC); + o_v_bil_pix.b<=bound(o_v_bil_t.b,8+FRAC); + + -- BICUBIC ----------------------------------------- + -- C3 : Bicubic coefficients A,B,C,D + + -- C4 : Bicubic calc T1 = X.D + C + o_v_bic_abcd1<=bic_calc0(o_vfrac,o_vpixq); + o_v_bic_tt1<=bic_calc1(o_vfrac,bic_calc0(o_vfrac,o_vpixq)); + + -- C5 : Bicubic calc T2 = X.T1 + B + o_v_bic_abcd2<=o_v_bic_abcd1; + o_v_bic_tt2<=bic_calc2(o_vfrac,o_v_bic_tt1,o_v_bic_abcd1); + + -- C6 : Bicubic final Y = X.T2 + A + o_v_bic_pix<=bic_calc3(o_vfrac,o_v_bic_tt2,o_v_bic_abcd2); + + -- POLYPHASE --------------------------------------- + -- C3 : Read memory + + -- C4 : Filter calc + o_v_poly_dr2<=o_v_poly_dr; + + -- C5 : Add + o_v_poly_t<=poly_calc1(o_v_poly_dr2,o_vpixq1); + + -- C6 : Bounding + o_v_poly_pix<=poly_calc2(o_v_poly_t); + + -- CYCLE 6 ----------------------------------------- + o_hs<=o_hsv(5); + o_vs<=o_vsv(5); + o_de<=o_dev(5); + o_vbl<=o_end(5); + o_r<=x"00"; + o_g<=x"00"; + o_b<=x"00"; + + CASE o_vmode(2 DOWNTO 0) IS + WHEN "000" | "001" | "010" => -- Nearest | Bilinear | Sharp Bilinear + IF MASK(MASK_NEAREST)='1' OR + MASK(MASK_BILINEAR)='1' OR + MASK(MASK_SHARP_BILINEAR)='1' THEN + o_r<=o_v_bil_pix.r; + o_g<=o_v_bil_pix.g; + o_b<=o_v_bil_pix.b; + END IF; + WHEN "011" => -- BiCubic + IF MASK(MASK_BICUBIC)='1' THEN + o_r<=o_v_bic_pix.r; + o_g<=o_v_bic_pix.g; + o_b<=o_v_bic_pix.b; + END IF; + + WHEN OTHERS => -- Polyphase + IF MASK(MASK_POLY)='1' THEN + o_r<=o_v_poly_pix.r; + o_g<=o_v_poly_pix.g; + o_b<=o_v_poly_pix.b; + END IF; + END CASE; + + IF o_pev(5)='0' THEN + o_r<=o_border(23 DOWNTO 16); -- Copy border colour + o_g<=o_border(15 DOWNTO 8); + o_b<=o_border(7 DOWNTO 0); + END IF; + + ---------------------------------------------------- + END IF; + END IF; + + END PROCESS VSCAL; + + ----------------------------------------------------------------------------- + -- Low Lag syntoniser interface + o_lltune<=(0 => i_vss, + 1 => i_pde, + 2 => i_inter, + 3 => i_flm, + 4 => o_vss, + 5 => i_pce, + 6 => i_clk, + 7 => o_clk, + OTHERS =>'0'); + + ---------------------------------------------------------------------------- +END ARCHITECTURE rtl; diff --git a/sys/audio_out.v b/sys/audio_out.v new file mode 100644 index 0000000..0f748e0 --- /dev/null +++ b/sys/audio_out.v @@ -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 diff --git a/sys/build_id.tcl b/sys/build_id.tcl new file mode 100644 index 0000000..b43b9d9 --- /dev/null +++ b/sys/build_id.tcl @@ -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 diff --git a/sys/ddr_svc.sv b/sys/ddr_svc.sv new file mode 100644 index 0000000..ed24d4e --- /dev/null +++ b/sys/ddr_svc.sv @@ -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 . +// +// ------------------------------------------ +// + +// 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 diff --git a/sys/f2sdram_safe_terminator.sv b/sys/f2sdram_safe_terminator.sv new file mode 100644 index 0000000..3586365 --- /dev/null +++ b/sys/f2sdram_safe_terminator.sv @@ -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 diff --git a/sys/gamma_corr.sv b/sys/gamma_corr.sv new file mode 100644 index 0000000..321b83f --- /dev/null +++ b/sys/gamma_corr.sv @@ -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 diff --git a/sys/hdmi_config.sv b/sys/hdmi_config.sv new file mode 100644 index 0000000..4a0a13d --- /dev/null +++ b/sys/hdmi_config.sv @@ -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 \ No newline at end of file diff --git a/sys/hps_io.v b/sys/hps_io.v new file mode 100644 index 0000000..9431c95 --- /dev/null +++ b/sys/hps_io.v @@ -0,0 +1,938 @@ +// +// hps_io.v +// +// Copyright (c) 2014 Till Harbaum +// 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 . +// +/////////////////////////////////////////////////////////////////////// +// 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<= 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 diff --git a/sys/hq2x.sv b/sys/hq2x.sv new file mode 100644 index 0000000..f5fcc71 --- /dev/null +++ b/sys/hq2x.sv @@ -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 diff --git a/sys/i2c.v b/sys/i2c.v new file mode 100644 index 0000000..9ccba93 --- /dev/null +++ b/sys/i2c.v @@ -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 diff --git a/sys/i2s.v b/sys/i2s.v new file mode 100644 index 0000000..7d4517b --- /dev/null +++ b/sys/i2s.v @@ -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 diff --git a/sys/iir_filter.v b/sys/iir_filter.v new file mode 100644 index 0000000..b8bcf4f --- /dev/null +++ b/sys/iir_filter.v @@ -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 diff --git a/sys/ltc2308.sv b/sys/ltc2308.sv new file mode 100644 index 0000000..33134fd --- /dev/null +++ b/sys/ltc2308.sv @@ -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_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 diff --git a/sys/math.sv b/sys/math.sv new file mode 100644 index 0000000..e7c0144 --- /dev/null +++ b/sys/math.sv @@ -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 diff --git a/sys/mcp23009.sv b/sys/mcp23009.sv new file mode 100644 index 0000000..40cbf5e --- /dev/null +++ b/sys/mcp23009.sv @@ -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 diff --git a/sys/mt32pi.sv b/sys/mt32pi.sv new file mode 100644 index 0000000..6704807 --- /dev/null +++ b/sys/mt32pi.sv @@ -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 diff --git a/sys/osd.v b/sys/osd.v new file mode 100644 index 0000000..a4fbdde --- /dev/null +++ b/sys/osd.v @@ -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<> (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 diff --git a/sys/pll.13.qip b/sys/pll.13.qip new file mode 100644 index 0000000..a6a1dca --- /dev/null +++ b/sys/pll.13.qip @@ -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" diff --git a/sys/pll_audio.13.qip b/sys/pll_audio.13.qip new file mode 100644 index 0000000..e987931 --- /dev/null +++ b/sys/pll_audio.13.qip @@ -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" diff --git a/sys/pll_audio.qip b/sys/pll_audio.qip new file mode 100644 index 0000000..abb013b --- /dev/null +++ b/sys/pll_audio.qip @@ -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" diff --git a/sys/pll_audio.v b/sys/pll_audio.v new file mode 100644 index 0000000..185a94c --- /dev/null +++ b/sys/pll_audio.v @@ -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: +// +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// IPFS_FILES : pll_audio.vo +// RELATED_FILES: pll_audio.v, pll_audio_0002.v diff --git a/sys/pll_audio/pll_audio_0002.qip b/sys/pll_audio/pll_audio_0002.qip new file mode 100644 index 0000000..dadd4b8 --- /dev/null +++ b/sys/pll_audio/pll_audio_0002.qip @@ -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*|*" diff --git a/sys/pll_audio/pll_audio_0002.v b/sys/pll_audio/pll_audio_0002.v new file mode 100644 index 0000000..7898914 --- /dev/null +++ b/sys/pll_audio/pll_audio_0002.v @@ -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 + diff --git a/sys/pll_cfg.qip b/sys/pll_cfg.qip new file mode 100644 index 0000000..c3394be --- /dev/null +++ b/sys/pll_cfg.qip @@ -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" diff --git a/sys/pll_cfg.v b/sys/pll_cfg.v new file mode 100644 index 0000000..0adc36f --- /dev/null +++ b/sys/pll_cfg.v @@ -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: +// +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// IPFS_FILES : pll_cfg.vo +// RELATED_FILES: pll_cfg.v, altera_pll_reconfig_top.v, altera_pll_reconfig_core.v, altera_std_synchronizer.v diff --git a/sys/pll_cfg/altera_pll_reconfig_core.v b/sys/pll_cfg/altera_pll_reconfig_core.v new file mode 100644 index 0000000..4bc1fbb --- /dev/null +++ b/sys/pll_cfg/altera_pll_reconfig_core.v @@ -0,0 +1,2184 @@ +// (C) 2001-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 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, 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. + + +`timescale 1ps/1ps + +module altera_pll_reconfig_core +#( + parameter reconf_width = 64, + parameter device_family = "Stratix V", + // MIF Streaming parameters + parameter RECONFIG_ADDR_WIDTH = 6, + parameter RECONFIG_DATA_WIDTH = 32, + parameter ROM_ADDR_WIDTH = 9, + parameter ROM_DATA_WIDTH = 32, + parameter ROM_NUM_WORDS = 512 +) ( + + //input + input wire mgmt_clk, + input wire mgmt_reset, + + + //conduits + output wire [reconf_width-1:0] reconfig_to_pll, + input wire [reconf_width-1:0] reconfig_from_pll, + + // user data (avalon-MM slave interface) + output wire [31:0] mgmt_readdata, + output wire mgmt_waitrequest, + input wire [5:0] mgmt_address, + input wire mgmt_read, + input wire mgmt_write, + input wire [31:0] mgmt_writedata, + + //other + output wire mif_start_out, + output reg [ROM_ADDR_WIDTH-1:0] mif_base_addr +); + localparam mode_WR = 1'b0; + localparam mode_POLL = 1'b1; + localparam MODE_REG = 6'b000000; + localparam STATUS_REG = 6'b000001; + localparam START_REG = 6'b000010; + localparam N_REG = 6'b000011; + localparam M_REG = 6'b000100; + localparam C_COUNTERS_REG = 6'b000101; + localparam DPS_REG = 6'b000110; + localparam DSM_REG = 6'b000111; + localparam BWCTRL_REG = 6'b001000; + localparam CP_CURRENT_REG = 6'b001001; + localparam ANY_DPRIO = 6'b100000; + localparam CNT_BASE = 5'b001010; + localparam VCO_REG = 6'b011100; + localparam MIF_REG = 6'b011111; + + //C Counters + localparam number_of_counters = 5'd18; + localparam CNT_0 = 1'd0, CNT_1 = 5'd1, CNT_2 = 5'd2, + CNT_3 = 5'd3, CNT_4 = 5'd4, CNT_5 = 5'd5, + CNT_6 = 5'd6, CNT_7 = 5'd7, CNT_8 = 5'd8, + CNT_9 = 5'd9, CNT_10 = 5'd10, CNT_11 = 5'd11, + CNT_12 = 5'd12, CNT_13 = 5'd13, CNT_14 = 5'd14, + CNT_15 = 5'd15, CNT_16 = 5'd16, CNT_17 = 5'd17; + //C counter addresses + localparam C_CNT_0_DIV_ADDR = 5'h00; + localparam C_CNT_0_DIV_ADDR_DPRIO_1 = 5'h11; + localparam C_CNT_0_3_BYPASS_EN_ADDR = 5'h15; + localparam C_CNT_0_3_ODD_DIV_EN_ADDR = 5'h17; + localparam C_CNT_4_17_BYPASS_EN_ADDR = 5'h14; + localparam C_CNT_4_17_ODD_DIV_EN_ADDR = 5'h16; + //N counter addresses + localparam N_CNT_DIV_ADDR = 5'h13; + localparam N_CNT_BYPASS_EN_ADDR = 5'h15; + localparam N_CNT_ODD_DIV_EN_ADDR = 5'h17; + //M counter addresses + localparam M_CNT_DIV_ADDR = 5'h12; + localparam M_CNT_BYPASS_EN_ADDR = 5'h15; + localparam M_CNT_ODD_DIV_EN_ADDR = 5'h17; + + //DSM address + localparam DSM_K_FRACTIONAL_DIVISION_ADDR_0 = 5'h18; + localparam DSM_K_FRACTIONAL_DIVISION_ADDR_1 = 5'h19; + localparam DSM_K_READY_ADDR = 5'h17; + localparam DSM_K_DITHER_ADDR = 5'h17; + localparam DSM_OUT_SEL_ADDR = 6'h30; + + //Other DSM params + localparam DSM_K_READY_BIT_INDEX = 4'd11; + //BWCTRL address + //Bit 0-3 of addr + localparam BWCTRL_ADDR = 6'h30; + //CP_CURRENT address + //Bit 0-2 of addr + localparam CP_CURRENT_ADDR = 6'h31; + + // VCODIV address + localparam VCO_ADDR = 5'h17; + + localparam DPRIO_IDLE = 3'd0, ONE = 3'd1, TWO = 3'd2, THREE = 3'd3, FOUR = 3'd4, + FIVE = 3'd5, SIX = 3'd6, SEVEN = 3'd7, EIGHT = 4'd8, NINE = 4'd9, TEN = 4'd10, + ELEVEN = 4'd11, TWELVE = 4'd12, THIRTEEN = 4'd13, FOURTEEN = 4'd14, DPRIO_DONE = 4'd15; + localparam IDLE = 2'b00, WAIT_ON_LOCK = 2'b01, LOCKED = 2'b10; + + wire clk; + wire reset; + wire gnd; + + wire [5: 0] slave_address; + wire slave_read; + wire slave_write; + wire [31: 0] slave_writedata; + + reg [31: 0] slave_readdata_d; + reg [31: 0] slave_readdata_q; + wire slave_waitrequest; + reg slave_mode; + + assign clk = mgmt_clk; + + assign slave_address = mgmt_address; + assign slave_read = mgmt_read; + assign slave_write = mgmt_write; + assign slave_writedata = mgmt_writedata; + + reg read_waitrequest; + // Outputs + assign mgmt_readdata = slave_readdata_q; + assign mgmt_waitrequest = slave_waitrequest | read_waitrequest; //Read waitrequest asserted in polling mode + + //internal signals + wire locked_orig; + wire locked; + + wire pll_start; + wire pll_start_valid; + reg status_read; + wire read_slave_mode_asserted; + + wire pll_start_asserted; + + reg [1:0] current_state; + reg [1:0] next_state; + + reg status;//0=busy, 1=ready + //user_mode_init user_mode_init_inst (clk, reset, dprio_mdio_dis, ser_shift_load); + //declaring the init wires. These will have 0 on them for 64 clk cycles + wire [ 5:0] init_dprio_address; + wire init_dprio_read; + wire [ 1:0] init_dprio_byteen; + wire init_dprio_write; + wire [15:0] init_dprio_writedata; + + wire init_atpgmode; + wire init_mdio_dis; + wire init_scanen; + wire init_ser_shift_load; + wire dprio_init_done; + + //DPRIO output signals after initialization is done + wire dprio_clk; + reg avmm_dprio_write; + reg avmm_dprio_read; + reg [5:0] avmm_dprio_address; + reg [15:0] avmm_dprio_writedata; + reg [1:0] avmm_dprio_byteen; + wire avmm_atpgmode; + wire avmm_mdio_dis; + wire avmm_scanen; + + //Final output wires that are muxed between the init and avmm wires. + wire dprio_init_reset; + wire [5:0] dprio_address /*synthesis keep*/; + wire dprio_read/*synthesis keep*/; + wire [1:0] dprio_byteen/*synthesis keep*/; + wire dprio_write/*synthesis keep*/; + wire [15:0] dprio_writedata/*synthesis keep*/; + wire dprio_mdio_dis/*synthesis keep*/; + wire dprio_ser_shift_load/*synthesis keep*/; + wire dprio_atpgmode/*synthesis keep*/; + wire dprio_scanen/*synthesis keep*/; + + + //other PLL signals for dyn ph shift + wire phase_done/*synthesis keep*/; + wire phase_en/*synthesis keep*/; + wire up_dn/*synthesis keep*/; + wire [4:0] cnt_sel; + + //DPRIO input signals + wire [15:0] dprio_readdata; + + //internal logic signals + //storage registers for user sent data + reg dprio_temp_read_1; + reg dprio_temp_read_2; + reg dprio_start; + reg mif_start_assert; + reg dps_start_assert; + wire usr_valid_changes; + reg [3:0] dprio_cur_state; + reg [3:0] dprio_next_state; + reg [15:0] dprio_temp_m_n_c_readdata_1_d; + reg [15:0] dprio_temp_m_n_c_readdata_2_d; + reg [15:0] dprio_temp_m_n_c_readdata_1_q; + reg [15:0] dprio_temp_m_n_c_readdata_2_q; + reg dprio_write_done; + //C counters signals + reg [7:0] usr_c_cnt_lo; + reg [7:0] usr_c_cnt_hi; + reg usr_c_cnt_bypass_en; + reg usr_c_cnt_odd_duty_div_en; + reg [7:0] temp_c_cnt_lo [0:17]; + reg [7:0] temp_c_cnt_hi [0:17]; + reg temp_c_cnt_bypass_en [0:17]; + reg temp_c_cnt_odd_duty_div_en [0:17]; + reg any_c_cnt_changed; + reg all_c_cnt_done_q; + reg all_c_cnt_done_d; + reg [17:0] c_cnt_changed; + reg [17:0] c_cnt_done_d; + reg [17:0] c_cnt_done_q; + //N counter signals + reg [7:0] usr_n_cnt_lo; + reg [7:0] usr_n_cnt_hi; + reg usr_n_cnt_bypass_en; + reg usr_n_cnt_odd_duty_div_en; + reg n_cnt_changed; + reg n_cnt_done_d; + reg n_cnt_done_q; + //M counter signals + reg [7:0] usr_m_cnt_lo; + reg [7:0] usr_m_cnt_hi; + reg usr_m_cnt_bypass_en; + reg usr_m_cnt_odd_duty_div_en; + reg m_cnt_changed; + reg m_cnt_done_d; + reg m_cnt_done_q; + //dyn phase regs + reg [15:0] usr_num_shifts; + reg [4:0] usr_cnt_sel /*synthesis preserve*/; + reg usr_up_dn; + reg dps_changed; + wire dps_changed_valid; + wire dps_done; + + //DSM Signals + reg [31:0] usr_k_value; + reg dsm_k_changed; + reg dsm_k_done_d; + reg dsm_k_done_q; + reg dsm_k_ready_false_done_d; + //BW signals + reg [3:0] usr_bwctrl_value; + reg bwctrl_changed; + reg bwctrl_done_d; + reg bwctrl_done_q; + //CP signals + reg [2:0] usr_cp_current_value; + reg cp_current_changed; + reg cp_current_done_d; + reg cp_current_done_q; + //VCO signals + reg usr_vco_value; + reg vco_changed; + reg vco_done_d; + reg vco_done_q; + //Manual DPRIO signals + reg manual_dprio_done_q; + reg manual_dprio_done_d; + reg manual_dprio_changed; + reg [5:0] usr_dprio_address; + reg [15:0] usr_dprio_writedata_0; + reg usr_r_w; + //keeping track of which operation happened last + reg [5:0] operation_address; + // Address wires for all C_counter DPRIO registers + // These are outputs of LUTS, changing depending + // on whether PLL_0 or PLL_1 being used + + + //Fitter will tell if FPLL1 is being used + wire fpll_1; + + // other + reg mif_reg_asserted; + // MAIN FSM + + // Synchronize locked signal + altera_std_synchronizer #( + .depth(3) + ) altera_std_synchronizer_inst ( + .clk(mgmt_clk), + .reset_n(~mgmt_reset), + .din(locked_orig), + .dout(locked) + ); + + always @(posedge clk) + begin + if (reset) + begin + dprio_cur_state <= DPRIO_IDLE; + current_state <= IDLE; + end + else + begin + current_state <= next_state; + dprio_cur_state <= dprio_next_state; + end + end + + always @(*) + begin + case(current_state) + IDLE: + begin + if (pll_start & !slave_waitrequest & usr_valid_changes) + next_state = WAIT_ON_LOCK; + else + next_state = IDLE; + end + WAIT_ON_LOCK: + begin + if (locked & dps_done & dprio_write_done) // received locked high from PLL + begin + if (slave_mode==mode_WR) //if the mode is waitrequest, then + // goto IDLE state directly + next_state = IDLE; + else + next_state = LOCKED; //otherwise go the locked state + end + else + next_state = WAIT_ON_LOCK; + end + + LOCKED: + begin + if (status_read) // stay in LOCKED until user reads status + next_state = IDLE; + else + next_state = LOCKED; + end + + default: next_state = 2'bxx; + + endcase + end + + + // ask the pll to start reconfig + assign pll_start = (pll_start_asserted & (current_state==IDLE)) ; + assign pll_start_valid = (pll_start & (next_state==WAIT_ON_LOCK)) ; + + + + // WRITE OPERATIONS + assign pll_start_asserted = slave_write & (slave_address == START_REG); + assign mif_start_out = pll_start & mif_reg_asserted; + + //reading the mode register to determine what mode the slave will operate + //in. + always @(posedge clk) + begin + if (reset) + slave_mode <= mode_WR; + else if (slave_write & (slave_address == MODE_REG) & !slave_waitrequest) + slave_mode <= slave_writedata[0]; + end + + //record which values user wants to change. + + //reading in the actual values that need to be reconfigged and sending + //them to the PLL + always @(posedge clk) + begin + if (reset) + begin + //reset all regs here + //BW signals reset + usr_bwctrl_value <= 0; + bwctrl_changed <= 0; + bwctrl_done_q <= 0; + //CP signals reset + usr_cp_current_value <= 0; + cp_current_changed <= 0; + cp_current_done_q <= 0; + //VCO signals reset + usr_vco_value <= 0; + vco_changed <= 0; + vco_done_q <= 0; + //DSM signals reset + usr_k_value <= 0; + dsm_k_changed <= 0; + dsm_k_done_q <= 0; + //N counter signals reset + usr_n_cnt_lo <= 0; + usr_n_cnt_hi <= 0; + usr_n_cnt_bypass_en <= 0; + usr_n_cnt_odd_duty_div_en <= 0; + n_cnt_changed <= 0; + n_cnt_done_q <= 0; + //M counter signals reset + usr_m_cnt_lo <= 0; + usr_m_cnt_hi <= 0; + usr_m_cnt_bypass_en <= 0; + usr_m_cnt_odd_duty_div_en <= 0; + m_cnt_changed <= 0; + m_cnt_done_q <= 0; + //C counter signals reset + usr_c_cnt_lo <= 0; + usr_c_cnt_hi <= 0; + usr_c_cnt_bypass_en <= 0; + usr_c_cnt_odd_duty_div_en <= 0; + any_c_cnt_changed <= 0; + all_c_cnt_done_q <= 0; + c_cnt_done_q <= 0; + //generic signals + dprio_start <= 0; + mif_start_assert <= 0; + dps_start_assert <= 0; + dprio_temp_m_n_c_readdata_1_q <= 0; + dprio_temp_m_n_c_readdata_2_q <= 0; + c_cnt_done_q <= 0; + //DPS signals + usr_up_dn <= 0; + usr_cnt_sel <= 0; + usr_num_shifts <= 0; + dps_changed <= 0; + //manual DPRIO signals + manual_dprio_changed <= 0; + usr_dprio_address <= 0; + usr_dprio_writedata_0 <= 0; + usr_r_w <= 0; + operation_address <= 0; + mif_reg_asserted <= 0; + mif_base_addr <= 0; + end + else + begin + if (dprio_temp_read_1) + begin + dprio_temp_m_n_c_readdata_1_q <= dprio_temp_m_n_c_readdata_1_d; + end + if (dprio_temp_read_2) + begin + dprio_temp_m_n_c_readdata_2_q <= dprio_temp_m_n_c_readdata_2_d; + end + if ((dps_done)) dps_changed <= 0; + if (dsm_k_done_d) dsm_k_done_q <= dsm_k_done_d; + if (n_cnt_done_d) n_cnt_done_q <= n_cnt_done_d; + if (m_cnt_done_d) m_cnt_done_q <= m_cnt_done_d; + if (all_c_cnt_done_d) all_c_cnt_done_q <= all_c_cnt_done_d; + if (c_cnt_done_d != 0) c_cnt_done_q <= c_cnt_done_q | c_cnt_done_d; + if (bwctrl_done_d) bwctrl_done_q <= bwctrl_done_d; + if (cp_current_done_d) cp_current_done_q <= cp_current_done_d; + if (vco_done_d) vco_done_q <= vco_done_d; + if (manual_dprio_done_d) manual_dprio_done_q <= manual_dprio_done_d; + + if (mif_start_out == 1'b1) + mif_start_assert <= 0; // Signaled MIF block to start, so deassert on next cycle + + if (dps_done != 1'b1) + dps_start_assert <= 0; // DPS has started, so dessert its start signal on next cycle + + if (dprio_next_state == ONE) + dprio_start <= 0; + if (dprio_write_done) + begin + bwctrl_done_q <= 0; + cp_current_done_q <= 0; + vco_done_q <= 0; + dsm_k_done_q <= 0; + dsm_k_done_q <= 0; + n_cnt_done_q <= 0; + m_cnt_done_q <= 0; + all_c_cnt_done_q <= 0; + c_cnt_done_q <= 0; + dsm_k_changed <= 0; + n_cnt_changed <= 0; + m_cnt_changed <= 0; + any_c_cnt_changed <= 0; + bwctrl_changed <= 0; + cp_current_changed <= 0; + vco_changed <= 0; + manual_dprio_changed <= 0; + manual_dprio_done_q <= 0; + if (dps_changed | dps_changed_valid | !dps_done ) + begin + usr_cnt_sel <= usr_cnt_sel; + end + else + begin + usr_cnt_sel <= 0; + end + mif_reg_asserted <= 0; + end + else + begin + dsm_k_changed <= dsm_k_changed; + n_cnt_changed <= n_cnt_changed; + m_cnt_changed <= m_cnt_changed; + any_c_cnt_changed <= any_c_cnt_changed; + manual_dprio_changed <= manual_dprio_changed; + mif_reg_asserted <= mif_reg_asserted; + usr_cnt_sel <= usr_cnt_sel; + end + + + if(slave_write & !slave_waitrequest) + begin + case(slave_address) + //read in the values here from the user and act on them + DSM_REG: + begin + operation_address <= DSM_REG; + usr_k_value <= slave_writedata[31:0]; + dsm_k_changed <= 1'b1; + dsm_k_done_q <= 0; + dprio_start <= 1'b1; + end + N_REG: + begin + operation_address <= N_REG; + usr_n_cnt_lo <= slave_writedata[7:0]; + usr_n_cnt_hi <= slave_writedata[15:8]; + usr_n_cnt_bypass_en <= slave_writedata[16]; + usr_n_cnt_odd_duty_div_en <= slave_writedata[17]; + n_cnt_changed <= 1'b1; + n_cnt_done_q <= 0; + dprio_start <= 1'b1; + end + M_REG: + begin + operation_address <= M_REG; + usr_m_cnt_lo <= slave_writedata[7:0]; + usr_m_cnt_hi <= slave_writedata[15:8]; + usr_m_cnt_bypass_en <= slave_writedata[16]; + usr_m_cnt_odd_duty_div_en <= slave_writedata[17]; + m_cnt_changed <= 1'b1; + m_cnt_done_q <= 0; + dprio_start <= 1'b1; + end + DPS_REG: + begin + operation_address <= DPS_REG; + usr_num_shifts <= slave_writedata[15:0]; + usr_cnt_sel <= slave_writedata[20:16]; + usr_up_dn <= slave_writedata[21]; + dps_changed <= 1; + dps_start_assert <= 1; + end + C_COUNTERS_REG: + begin + operation_address <= C_COUNTERS_REG; + usr_c_cnt_lo <= slave_writedata[7:0]; + usr_c_cnt_hi <= slave_writedata[15:8]; + usr_c_cnt_bypass_en <= slave_writedata[16]; + usr_c_cnt_odd_duty_div_en <= slave_writedata[17]; + usr_cnt_sel <= slave_writedata[22:18]; + any_c_cnt_changed <= 1'b1; + all_c_cnt_done_q <= 0; + dprio_start <= 1'b1; + end + BWCTRL_REG: + begin + usr_bwctrl_value <= slave_writedata[3:0]; + bwctrl_changed <= 1'b1; + bwctrl_done_q <= 0; + dprio_start <= 1'b1; + operation_address <= BWCTRL_REG; + end + CP_CURRENT_REG: + begin + usr_cp_current_value <= slave_writedata[2:0]; + cp_current_changed <= 1'b1; + cp_current_done_q <= 0; + dprio_start <= 1'b1; + operation_address <= CP_CURRENT_REG; + end + VCO_REG: + begin + usr_vco_value <= slave_writedata[0]; + vco_changed <= 1'b1; + vco_done_q <= 0; + dprio_start <= 1'b1; + operation_address <= VCO_REG; + end + ANY_DPRIO: + begin + operation_address <= ANY_DPRIO; + manual_dprio_changed <= 1'b1; + usr_dprio_address <= slave_writedata[5:0]; + usr_dprio_writedata_0 <= slave_writedata[21:6]; + usr_r_w <= slave_writedata[22]; + manual_dprio_done_q <= 0; + dprio_start <= 1'b1; + end + MIF_REG: + begin + mif_reg_asserted <= 1'b1; + mif_base_addr <= slave_writedata[ROM_ADDR_WIDTH-1:0]; + mif_start_assert <= 1'b1; + end + endcase + end + end + end + //C Counter assigning values to the 2-d array of values for each C counter + + reg [4:0] j; + always @(posedge clk) + begin + + if (reset) + begin + c_cnt_changed[17:0] <= 0; + for (j = 0; j < number_of_counters; j = j + 1'b1) + begin : c_cnt_reset + temp_c_cnt_bypass_en[j] <= 0; + temp_c_cnt_odd_duty_div_en[j] <= 0; + temp_c_cnt_lo[j][7:0] <= 0; + temp_c_cnt_hi[j][7:0] <= 0; + end + end + else + begin + if (dprio_write_done) + begin + c_cnt_changed <= 0; + end + if (any_c_cnt_changed && (operation_address == C_COUNTERS_REG)) + begin + case (cnt_sel) + CNT_0: + begin + temp_c_cnt_lo [0] <= usr_c_cnt_lo; + temp_c_cnt_hi [0] <= usr_c_cnt_hi; + temp_c_cnt_bypass_en [0] <= usr_c_cnt_bypass_en; + temp_c_cnt_odd_duty_div_en [0] <= usr_c_cnt_odd_duty_div_en; + c_cnt_changed [0] <= 1'b1; + end + CNT_1: + begin + temp_c_cnt_lo [1] <= usr_c_cnt_lo; + temp_c_cnt_hi [1] <= usr_c_cnt_hi; + temp_c_cnt_bypass_en [1] <= usr_c_cnt_bypass_en; + temp_c_cnt_odd_duty_div_en [1] <= usr_c_cnt_odd_duty_div_en; + c_cnt_changed [1] <= 1'b1; + end + CNT_2: + begin + temp_c_cnt_lo [2] <= usr_c_cnt_lo; + temp_c_cnt_hi [2] <= usr_c_cnt_hi; + temp_c_cnt_bypass_en [2] <= usr_c_cnt_bypass_en; + temp_c_cnt_odd_duty_div_en [2] <= usr_c_cnt_odd_duty_div_en; + c_cnt_changed [2] <= 1'b1; + end + CNT_3: + begin + temp_c_cnt_lo [3] <= usr_c_cnt_lo; + temp_c_cnt_hi [3] <= usr_c_cnt_hi; + temp_c_cnt_bypass_en [3] <= usr_c_cnt_bypass_en; + temp_c_cnt_odd_duty_div_en [3] <= usr_c_cnt_odd_duty_div_en; + c_cnt_changed [3] <= 1'b1; + end + CNT_4: + begin + temp_c_cnt_lo [4] <= usr_c_cnt_lo; + temp_c_cnt_hi [4] <= usr_c_cnt_hi; + temp_c_cnt_bypass_en [4] <= usr_c_cnt_bypass_en; + temp_c_cnt_odd_duty_div_en [4] <= usr_c_cnt_odd_duty_div_en; + c_cnt_changed [4] <= 1'b1; + end + CNT_5: + begin + temp_c_cnt_lo [5] <= usr_c_cnt_lo; + temp_c_cnt_hi [5] <= usr_c_cnt_hi; + temp_c_cnt_bypass_en [5] <= usr_c_cnt_bypass_en; + temp_c_cnt_odd_duty_div_en [5] <= usr_c_cnt_odd_duty_div_en; + c_cnt_changed [5] <= 1'b1; + end + CNT_6: + begin + temp_c_cnt_lo [6] <= usr_c_cnt_lo; + temp_c_cnt_hi [6] <= usr_c_cnt_hi; + temp_c_cnt_bypass_en [6] <= usr_c_cnt_bypass_en; + temp_c_cnt_odd_duty_div_en [6] <= usr_c_cnt_odd_duty_div_en; + c_cnt_changed [6] <= 1'b1; + end + CNT_7: + begin + temp_c_cnt_lo [7] <= usr_c_cnt_lo; + temp_c_cnt_hi [7] <= usr_c_cnt_hi; + temp_c_cnt_bypass_en [7] <= usr_c_cnt_bypass_en; + temp_c_cnt_odd_duty_div_en [7] <= usr_c_cnt_odd_duty_div_en; + c_cnt_changed [7] <= 1'b1; + end + CNT_8: + begin + temp_c_cnt_lo [8] <= usr_c_cnt_lo; + temp_c_cnt_hi [8] <= usr_c_cnt_hi; + temp_c_cnt_bypass_en [8] <= usr_c_cnt_bypass_en; + temp_c_cnt_odd_duty_div_en [8] <= usr_c_cnt_odd_duty_div_en; + c_cnt_changed [8] <= 1'b1; + end + CNT_9: + begin + temp_c_cnt_lo [9] <= usr_c_cnt_lo; + temp_c_cnt_hi [9] <= usr_c_cnt_hi; + temp_c_cnt_bypass_en [9] <= usr_c_cnt_bypass_en; + temp_c_cnt_odd_duty_div_en [9] <= usr_c_cnt_odd_duty_div_en; + c_cnt_changed [9] <= 1'b1; + end + CNT_10: + begin + temp_c_cnt_lo [10] <= usr_c_cnt_lo; + temp_c_cnt_hi [10] <= usr_c_cnt_hi; + temp_c_cnt_bypass_en [10] <= usr_c_cnt_bypass_en; + temp_c_cnt_odd_duty_div_en [10] <= usr_c_cnt_odd_duty_div_en; + c_cnt_changed [10] <= 1'b1; + end + CNT_11: + begin + temp_c_cnt_lo [11] <= usr_c_cnt_lo; + temp_c_cnt_hi [11] <= usr_c_cnt_hi; + temp_c_cnt_bypass_en [11] <= usr_c_cnt_bypass_en; + temp_c_cnt_odd_duty_div_en [11] <= usr_c_cnt_odd_duty_div_en; + c_cnt_changed [11] <= 1'b1; + end + CNT_12: + begin + temp_c_cnt_lo [12] <= usr_c_cnt_lo; + temp_c_cnt_hi [12] <= usr_c_cnt_hi; + temp_c_cnt_bypass_en [12] <= usr_c_cnt_bypass_en; + temp_c_cnt_odd_duty_div_en [12] <= usr_c_cnt_odd_duty_div_en; + c_cnt_changed [12] <= 1'b1; + end + CNT_13: + begin + temp_c_cnt_lo [13] <= usr_c_cnt_lo; + temp_c_cnt_hi [13] <= usr_c_cnt_hi; + temp_c_cnt_bypass_en [13] <= usr_c_cnt_bypass_en; + temp_c_cnt_odd_duty_div_en [13] <= usr_c_cnt_odd_duty_div_en; + c_cnt_changed [13] <= 1'b1; + end + CNT_14: + begin + temp_c_cnt_lo [14] <= usr_c_cnt_lo; + temp_c_cnt_hi [14] <= usr_c_cnt_hi; + temp_c_cnt_bypass_en [14] <= usr_c_cnt_bypass_en; + temp_c_cnt_odd_duty_div_en [14] <= usr_c_cnt_odd_duty_div_en; + c_cnt_changed [14] <= 1'b1; + end + CNT_15: + begin + temp_c_cnt_lo [15] <= usr_c_cnt_lo; + temp_c_cnt_hi [15] <= usr_c_cnt_hi; + temp_c_cnt_bypass_en [15] <= usr_c_cnt_bypass_en; + temp_c_cnt_odd_duty_div_en [15] <= usr_c_cnt_odd_duty_div_en; + c_cnt_changed [15] <= 1'b1; + end + CNT_16: + begin + temp_c_cnt_lo [16] <= usr_c_cnt_lo; + temp_c_cnt_hi [16] <= usr_c_cnt_hi; + temp_c_cnt_bypass_en [16] <= usr_c_cnt_bypass_en; + temp_c_cnt_odd_duty_div_en [16] <= usr_c_cnt_odd_duty_div_en; + c_cnt_changed [16] <= 1'b1; + end + CNT_17: + begin + temp_c_cnt_lo [17] <= usr_c_cnt_lo; + temp_c_cnt_hi [17] <= usr_c_cnt_hi; + temp_c_cnt_bypass_en [17] <= usr_c_cnt_bypass_en; + temp_c_cnt_odd_duty_div_en [17] <= usr_c_cnt_odd_duty_div_en; + c_cnt_changed [17] <= 1'b1; + end + endcase + + end + end + end + + + //logic to handle which writes the user indicated and wants to start. + assign usr_valid_changes =dsm_k_changed| any_c_cnt_changed |n_cnt_changed | m_cnt_changed | dps_changed_valid |manual_dprio_changed |cp_current_changed|bwctrl_changed|vco_changed; + + + //start the reconfig operations by writing to the DPRIO + reg break_loop; + reg [4:0] i; + always @(*) + begin + dprio_temp_read_1 = 0; + dprio_temp_read_2 = 0; + dprio_temp_m_n_c_readdata_1_d = 0; + dprio_temp_m_n_c_readdata_2_d = 0; + break_loop = 0; + dprio_next_state = DPRIO_IDLE; + avmm_dprio_write = 0; + avmm_dprio_read = 0; + avmm_dprio_address = 0; + avmm_dprio_writedata = 0; + avmm_dprio_byteen = 0; + dprio_write_done = 1; + manual_dprio_done_d = 0; + n_cnt_done_d = 0; + dsm_k_done_d = 0; + dsm_k_ready_false_done_d = 0; + m_cnt_done_d = 0; + c_cnt_done_d[17:0] = 0; + all_c_cnt_done_d = 0; + bwctrl_done_d = 0; + cp_current_done_d = 0; + vco_done_d = 0; + i = 0; + + // Deassert dprio_write_done so it doesn't reset mif_reg_asserted (toggled writes) + if (dprio_start | mif_start_assert) + dprio_write_done = 0; + + if (current_state == WAIT_ON_LOCK) + begin + case (dprio_cur_state) + ONE: + begin + if (n_cnt_changed & !n_cnt_done_q) + begin + dprio_write_done = 0; + avmm_dprio_write = 1'b1; + avmm_dprio_byteen = 2'b11; + dprio_next_state = TWO; + avmm_dprio_address = N_CNT_DIV_ADDR; + avmm_dprio_writedata[7:0] = usr_n_cnt_lo; + avmm_dprio_writedata[15:8] = usr_n_cnt_hi; + end + else if (m_cnt_changed & !m_cnt_done_q) + begin + dprio_write_done = 0; + avmm_dprio_write = 1'b1; + avmm_dprio_byteen = 2'b11; + dprio_next_state = TWO; + avmm_dprio_address = M_CNT_DIV_ADDR; + avmm_dprio_writedata[7:0] = usr_m_cnt_lo; + avmm_dprio_writedata[15:8] = usr_m_cnt_hi; + end + else if (any_c_cnt_changed & !all_c_cnt_done_q) + begin + + for (i = 0; (i < number_of_counters) & !break_loop; i = i + 1'b1) + begin : c_cnt_write_hilo + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + dprio_write_done = 0; + avmm_dprio_write = 1'b1; + avmm_dprio_byteen = 2'b11; + dprio_next_state = TWO; + if (fpll_1) avmm_dprio_address = C_CNT_0_DIV_ADDR + C_CNT_0_DIV_ADDR_DPRIO_1 - i; + else avmm_dprio_address = C_CNT_0_DIV_ADDR + i; + avmm_dprio_writedata[7:0] = temp_c_cnt_lo[i]; + avmm_dprio_writedata[15:8] = temp_c_cnt_hi[i]; + //To break from the loop, since only one counter + //is addressed at a time + break_loop = 1'b1; + end + end + end + else if (dsm_k_changed & !dsm_k_done_q) + begin + dprio_write_done = 0; + avmm_dprio_write = 0; + dprio_next_state = TWO; + end + else if (bwctrl_changed & !bwctrl_done_q) + begin + dprio_write_done = 0; + avmm_dprio_write = 0; + dprio_next_state = TWO; + end + else if (cp_current_changed & !cp_current_done_q) + begin + dprio_write_done = 0; + avmm_dprio_write = 0; + dprio_next_state = TWO; + end + else if (vco_changed & !vco_done_q) + begin + dprio_write_done = 0; + avmm_dprio_write = 0; + dprio_next_state = TWO; + end + else if (manual_dprio_changed & !manual_dprio_done_q) + begin + dprio_write_done = 0; + avmm_dprio_byteen = 2'b11; + dprio_next_state = TWO; + avmm_dprio_write = usr_r_w; + avmm_dprio_address = usr_dprio_address; + avmm_dprio_writedata[15:0] = usr_dprio_writedata_0; + end + else dprio_next_state = DPRIO_IDLE; + end + + TWO: + begin + //handle reading the two setting bits on n_cnt, then + //writing them back while preserving other bits. + //Issue two consecutive reads then wait; readLatency=3 + dprio_write_done = 0; + dprio_next_state = THREE; + avmm_dprio_byteen = 2'b11; + avmm_dprio_read = 1'b1; + if (n_cnt_changed & !n_cnt_done_q) + begin + avmm_dprio_address = N_CNT_BYPASS_EN_ADDR; + end + else if (m_cnt_changed & !m_cnt_done_q) + begin + avmm_dprio_address = M_CNT_BYPASS_EN_ADDR; + end + + else if (any_c_cnt_changed & !all_c_cnt_done_q) + begin + for (i = 0; (i < number_of_counters) & !break_loop; i = i + 1'b1) + begin : c_cnt_read_bypass + if (fpll_1) + begin + if (i > 13) + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_0_3_BYPASS_EN_ADDR; + break_loop = 1'b1; + end + end + else + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_4_17_BYPASS_EN_ADDR; + break_loop = 1'b1; + end + end + end + else + begin + if (i < 4) + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_0_3_BYPASS_EN_ADDR; + break_loop = 1'b1; + end + end + else + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_4_17_BYPASS_EN_ADDR; + break_loop = 1'b1; + end + end + end + end + end + //reading the K ready 16 bit word. Need to write 0 to it + //afterwards to indicate that K has not been done writing + else if (dsm_k_changed & !dsm_k_done_q) + begin + avmm_dprio_address = DSM_K_READY_ADDR; + dprio_next_state = FOUR; + end + else if (bwctrl_changed & !bwctrl_done_q) + begin + avmm_dprio_address = BWCTRL_ADDR; + dprio_next_state = FOUR; + end + else if (cp_current_changed & !cp_current_done_q) + begin + avmm_dprio_address = CP_CURRENT_ADDR; + dprio_next_state = FOUR; + end + else if (vco_changed & !vco_done_q) + begin + avmm_dprio_address = VCO_ADDR; + dprio_next_state = FOUR; + end + else if (manual_dprio_changed & !manual_dprio_done_q) + begin + avmm_dprio_read = ~usr_r_w; + avmm_dprio_address = usr_dprio_address; + dprio_next_state = DPRIO_DONE; + end + else dprio_next_state = DPRIO_IDLE; + end + THREE: + begin + dprio_write_done = 0; + avmm_dprio_byteen = 2'b11; + avmm_dprio_read = 1'b1; + dprio_next_state = FOUR; + if (n_cnt_changed & !n_cnt_done_q) + begin + avmm_dprio_address = N_CNT_ODD_DIV_EN_ADDR; + end + else if (m_cnt_changed & !m_cnt_done_q) + begin + avmm_dprio_address = M_CNT_ODD_DIV_EN_ADDR; + end + else if (any_c_cnt_changed & !all_c_cnt_done_q) + begin + for (i = 0; (i < number_of_counters) & !break_loop; i = i + 1'b1) + begin : c_cnt_read_odd_div + if (fpll_1) + begin + if (i > 13) + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_0_3_ODD_DIV_EN_ADDR; + break_loop = 1'b1; + end + end + else + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_4_17_ODD_DIV_EN_ADDR; + break_loop = 1'b1; + end + end + end + else + begin + if (i < 4) + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_0_3_ODD_DIV_EN_ADDR; + break_loop = 1'b1; + end + end + else + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_4_17_ODD_DIV_EN_ADDR; + break_loop = 1'b1; + end + end + end + end + end + else dprio_next_state = DPRIO_IDLE; + end + FOUR: + begin + dprio_temp_read_1 = 1'b1; + dprio_write_done = 0; + if (vco_changed|cp_current_changed|bwctrl_changed|dsm_k_changed|n_cnt_changed|m_cnt_changed|any_c_cnt_changed) + begin + dprio_temp_m_n_c_readdata_1_d = dprio_readdata; + dprio_next_state = FIVE; + end + else dprio_next_state = DPRIO_IDLE; + end + FIVE: + begin + dprio_write_done = 0; + dprio_temp_read_2 = 1'b1; + if (vco_changed|cp_current_changed|bwctrl_changed|dsm_k_changed|n_cnt_changed|m_cnt_changed|any_c_cnt_changed) + begin + //this is where DSM ready value comes. + //Need to store in a register to be used later + dprio_temp_m_n_c_readdata_2_d = dprio_readdata; + dprio_next_state = SIX; + end + else dprio_next_state = DPRIO_IDLE; + end + SIX: + begin + dprio_write_done = 0; + avmm_dprio_write = 1'b1; + avmm_dprio_byteen = 2'b11; + dprio_next_state = SEVEN; + avmm_dprio_writedata = dprio_temp_m_n_c_readdata_1_q; + if (n_cnt_changed & !n_cnt_done_q) + begin + avmm_dprio_address = N_CNT_BYPASS_EN_ADDR; + avmm_dprio_writedata[5] = usr_n_cnt_bypass_en; + end + else if (m_cnt_changed & !m_cnt_done_q) + begin + avmm_dprio_address = M_CNT_BYPASS_EN_ADDR; + avmm_dprio_writedata[4] = usr_m_cnt_bypass_en; + end + else if (any_c_cnt_changed & !all_c_cnt_done_q) + begin + for (i = 0; (i < number_of_counters) & !break_loop; i = i + 1'b1) + begin : c_cnt_write_bypass + if (fpll_1) + begin + if (i > 13) + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_0_3_BYPASS_EN_ADDR; + avmm_dprio_writedata[i-14] = temp_c_cnt_bypass_en[i]; + break_loop = 1'b1; + end + end + else + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_4_17_BYPASS_EN_ADDR; + avmm_dprio_writedata[i] = temp_c_cnt_bypass_en[i]; + break_loop = 1'b1; + end + end + end + else + begin + if (i < 4) + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_0_3_BYPASS_EN_ADDR; + avmm_dprio_writedata[3-i] = temp_c_cnt_bypass_en[i]; + break_loop = 1'b1; + end + end + else + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_4_17_BYPASS_EN_ADDR; + avmm_dprio_writedata[17-i] = temp_c_cnt_bypass_en[i]; + break_loop = 1'b1; + end + end + end + end + end + else if (dsm_k_changed & !dsm_k_done_q) + begin + avmm_dprio_write = 0; + end + else if (bwctrl_changed & !bwctrl_done_q) + begin + avmm_dprio_write = 0; + end + else if (cp_current_changed & !cp_current_done_q) + begin + avmm_dprio_write = 0; + end + else if (vco_changed & !vco_done_q) + begin + avmm_dprio_write = 0; + end + else dprio_next_state = DPRIO_IDLE; + end + SEVEN: + begin + dprio_write_done = 0; + dprio_next_state = EIGHT; + avmm_dprio_write = 1'b1; + avmm_dprio_byteen = 2'b11; + avmm_dprio_writedata = dprio_temp_m_n_c_readdata_2_q; + if (n_cnt_changed & !n_cnt_done_q) + begin + avmm_dprio_address = N_CNT_ODD_DIV_EN_ADDR; + avmm_dprio_writedata[5] = usr_n_cnt_odd_duty_div_en; + n_cnt_done_d = 1'b1; + end + else if (m_cnt_changed & !m_cnt_done_q) + begin + avmm_dprio_address = M_CNT_ODD_DIV_EN_ADDR; + avmm_dprio_writedata[4] = usr_m_cnt_odd_duty_div_en; + m_cnt_done_d = 1'b1; + end + + else if (any_c_cnt_changed & !all_c_cnt_done_q) + begin + for (i = 0; (i < number_of_counters) & !break_loop; i = i + 1'b1) + begin : c_cnt_write_odd_div + if (fpll_1) + begin + if (i > 13) + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_0_3_ODD_DIV_EN_ADDR; + avmm_dprio_writedata[i-14] = temp_c_cnt_odd_duty_div_en[i]; + c_cnt_done_d[i] = 1'b1; + //have to OR the signals to prevent + //overwriting of previous dones + c_cnt_done_d = c_cnt_done_d | c_cnt_done_q; + break_loop = 1'b1; + end + end + else + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_4_17_ODD_DIV_EN_ADDR; + avmm_dprio_writedata[i] = temp_c_cnt_odd_duty_div_en[i]; + c_cnt_done_d[i] = 1'b1; + c_cnt_done_d = c_cnt_done_d | c_cnt_done_q; + break_loop = 1'b1; + end + end + end + else + begin + if (i < 4) + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_0_3_ODD_DIV_EN_ADDR; + avmm_dprio_writedata[3-i] = temp_c_cnt_odd_duty_div_en[i]; + c_cnt_done_d[i] = 1'b1; + //have to OR the signals to prevent + //overwriting of previous dones + c_cnt_done_d = c_cnt_done_d | c_cnt_done_q; + break_loop = 1'b1; + end + end + else + begin + if (c_cnt_changed[i] & !c_cnt_done_q[i]) + begin + avmm_dprio_address = C_CNT_4_17_ODD_DIV_EN_ADDR; + avmm_dprio_writedata[17-i] = temp_c_cnt_odd_duty_div_en[i]; + c_cnt_done_d[i] = 1'b1; + c_cnt_done_d = c_cnt_done_d | c_cnt_done_q; + break_loop = 1'b1; + end + end + end + end + end + else if (dsm_k_changed & !dsm_k_done_q) + begin + avmm_dprio_address = DSM_K_READY_ADDR; + avmm_dprio_writedata[DSM_K_READY_BIT_INDEX] = 1'b0; + dsm_k_ready_false_done_d = 1'b1; + end + else if (bwctrl_changed & !bwctrl_done_q) + begin + avmm_dprio_address = BWCTRL_ADDR; + avmm_dprio_writedata[3:0] = usr_bwctrl_value; + bwctrl_done_d = 1'b1; + end + else if (cp_current_changed & !cp_current_done_q) + begin + avmm_dprio_address = CP_CURRENT_ADDR; + avmm_dprio_writedata[2:0] = usr_cp_current_value; + cp_current_done_d = 1'b1; + end + else if (vco_changed & !vco_done_q) + begin + avmm_dprio_address = VCO_ADDR; + avmm_dprio_writedata[8] = usr_vco_value; + vco_done_d = 1'b1; + end + + + //if all C_cnt that were changed are done, then assert all_c_cnt_done + if (c_cnt_done_d == c_cnt_changed) + all_c_cnt_done_d = 1'b1; + if (n_cnt_changed & n_cnt_done_d) + dprio_next_state = DPRIO_DONE; + if (any_c_cnt_changed & !all_c_cnt_done_d & !all_c_cnt_done_q) + dprio_next_state = ONE; + else if (m_cnt_changed & !m_cnt_done_d & !m_cnt_done_q) + dprio_next_state = ONE; + else if (dsm_k_changed & !dsm_k_ready_false_done_d) + dprio_next_state = TWO; + else if (dsm_k_changed & !dsm_k_done_q) + dprio_next_state = EIGHT; + else if (bwctrl_changed & !bwctrl_done_d) + dprio_next_state = TWO; + else if (cp_current_changed & !cp_current_done_d) + dprio_next_state = TWO; + else if (vco_changed & !vco_done_d) + dprio_next_state = TWO; + else + begin + dprio_next_state = DPRIO_DONE; + dprio_write_done = 1'b1; + end + end + //finish the rest of the DSM reads/writes + //writing k value, writing k_ready to 1. + EIGHT: + begin + dprio_write_done = 0; + dprio_next_state = NINE; + avmm_dprio_write = 1'b1; + avmm_dprio_byteen = 2'b11; + if (dsm_k_changed & !dsm_k_done_q) + begin + avmm_dprio_address = DSM_K_FRACTIONAL_DIVISION_ADDR_0; + avmm_dprio_writedata[15:0] = usr_k_value[15:0]; + end + end + NINE: + begin + dprio_write_done = 0; + dprio_next_state = TEN; + avmm_dprio_write = 1'b1; + avmm_dprio_byteen = 2'b11; + if (dsm_k_changed & !dsm_k_done_q) + begin + avmm_dprio_address = DSM_K_FRACTIONAL_DIVISION_ADDR_1; + avmm_dprio_writedata[15:0] = usr_k_value[31:16]; + end + end + TEN: + begin + dprio_write_done = 0; + dprio_next_state = ONE; + avmm_dprio_write = 1'b1; + avmm_dprio_byteen = 2'b11; + if (dsm_k_changed & !dsm_k_done_q) + begin + avmm_dprio_address = DSM_K_READY_ADDR; + //already have the readdata for DSM_K_READY_ADDR since we read it + //earlier. Just reuse here + avmm_dprio_writedata = dprio_temp_m_n_c_readdata_2_q; + avmm_dprio_writedata[DSM_K_READY_BIT_INDEX] = 1'b1; + dsm_k_done_d = 1'b1; + end + end + DPRIO_DONE: + begin + dprio_write_done = 1'b1; + if (dprio_start) dprio_next_state = DPRIO_IDLE; + else dprio_next_state = DPRIO_DONE; + end + DPRIO_IDLE: + begin + if (dprio_start) dprio_next_state = ONE; + else dprio_next_state = DPRIO_IDLE; + end + default: dprio_next_state = 4'bxxxx; + endcase + end + + end + + + //assert the waitreq signal according to the state of the slave + assign slave_waitrequest = (slave_mode==mode_WR) ? ((locked === 1'b1) ? (((current_state==WAIT_ON_LOCK) & !dprio_write_done) | !dps_done |reset|!dprio_init_done) : 1'b1) : 1'b0; + + // Read operations + always @(*) + begin + status = 0; + if (slave_mode == mode_POLL) + //asserting status to 1 if the slave is done. + status = (current_state == LOCKED); + end + //************************************************************// + //************************************************************// + //******************** READ STATE MACHINE ********************// + //************************************************************// + //************************************************************// + reg [1:0] current_read_state; + reg [1:0] next_read_state; + reg [5:0] slave_address_int_d; + reg [5:0] slave_address_int_q; + reg dprio_read_1; + reg [5:0] dprio_address_1; + reg [1:0] dprio_byteen_1; + reg [4:0] usr_cnt_sel_1; + localparam READ = 2'b00, READ_WAIT = 2'b01, READ_IDLE = 2'b10, READ_POST_WAIT = 2'b11; + + always @(*) + begin + if(next_read_state == READ_IDLE) + begin + read_waitrequest <= 1'b0; + end + else + begin + read_waitrequest <= 1'b1; + end + end + + always @(posedge clk) + begin + if (reset) + begin + current_read_state <= READ_IDLE; + slave_address_int_q <= 0; + slave_readdata_q <= 0; + end + else + begin + current_read_state <= next_read_state; + slave_address_int_q <= slave_address_int_d; + slave_readdata_q <= slave_readdata_d; + end + end + always @(*) + begin + dprio_read_1 = 0; + dprio_address_1 = 0; + dprio_byteen_1 = 0; + slave_address_int_d = 0; + slave_readdata_d = 0; + status_read = 0; + usr_cnt_sel_1 = 0; + case(current_read_state) + READ_IDLE: + begin + slave_address_int_d = 0; + next_read_state = READ_IDLE; + if ((current_state != WAIT_ON_LOCK) && slave_read) + begin + slave_address_int_d = slave_address; + if ((slave_address >= CNT_BASE) && (slave_address < CNT_BASE+18)) + begin + next_read_state = READ_WAIT; + dprio_byteen_1 = 2'b11; + dprio_read_1 = 1'b1; + usr_cnt_sel_1 = (slave_address[4:0] - CNT_BASE); + if (fpll_1) dprio_address_1 = C_CNT_0_DIV_ADDR + C_CNT_0_DIV_ADDR_DPRIO_1 - cnt_sel; + else dprio_address_1 = C_CNT_0_DIV_ADDR + cnt_sel; + end + else + begin + case (slave_address) + MODE_REG: + begin + next_read_state = READ_WAIT; + slave_readdata_d = slave_mode; + end + STATUS_REG: + begin + next_read_state = READ_WAIT; + status_read = 1'b1; + slave_readdata_d = status; + end + N_REG: + begin + dprio_byteen_1 = 2'b11; + dprio_read_1 = 1'b1; + dprio_address_1 = N_CNT_DIV_ADDR; + next_read_state = READ_WAIT; + end + M_REG: + begin + dprio_byteen_1 = 2'b11; + dprio_read_1 = 1'b1; + dprio_address_1 = M_CNT_DIV_ADDR; + next_read_state = READ_WAIT; + end + BWCTRL_REG: + begin + dprio_byteen_1 = 2'b11; + dprio_read_1 = 1'b1; + dprio_address_1 = BWCTRL_ADDR; + next_read_state = READ_WAIT; + end + CP_CURRENT_REG: + begin + dprio_byteen_1 = 2'b11; + dprio_read_1 = 1'b1; + dprio_address_1 = CP_CURRENT_ADDR; + next_read_state = READ_WAIT; + end + VCO_REG: + begin + dprio_byteen_1 = 2'b11; + dprio_read_1 = 1'b1; + dprio_address_1 = VCO_ADDR; + next_read_state = READ_WAIT; + end + ANY_DPRIO: + begin + dprio_byteen_1 = 2'b11; + dprio_read_1 = ~slave_writedata[22]; + dprio_address_1 = slave_writedata[5:0]; + next_read_state = READ_WAIT; + end + default : next_read_state = READ_IDLE; + endcase + end + end + else + next_read_state = READ_IDLE; + end + READ_WAIT: + begin + next_read_state = READ; + slave_address_int_d = slave_address_int_q; + case (slave_address_int_q) + MODE_REG: + begin + slave_readdata_d = slave_readdata_q; + end + STATUS_REG: + begin + slave_readdata_d = slave_readdata_q; + end + endcase + end + READ: + begin + next_read_state = READ_POST_WAIT; + slave_address_int_d = slave_address_int_q; + slave_readdata_d = dprio_readdata; + case (slave_address_int_q) + MODE_REG: + begin + slave_readdata_d = slave_readdata_q; + end + STATUS_REG: + begin + slave_readdata_d = slave_readdata_q; + end + BWCTRL_REG: + begin + slave_readdata_d = dprio_readdata[3:0]; + end + CP_CURRENT_REG: + begin + slave_readdata_d = dprio_readdata[2:0]; + end + VCO_REG: + begin + slave_readdata_d = dprio_readdata[8]; + end + ANY_DPRIO: + begin + slave_readdata_d = dprio_readdata; + end + endcase + end + READ_POST_WAIT: + begin + next_read_state = READ_IDLE; + end + default: next_read_state = 2'bxx; + endcase + end + + + dyn_phase_shift dyn_phase_shift_inst ( + .clk(clk), + .reset(reset), + .phase_done(phase_done), + .pll_start_valid(pll_start_valid), + .dps_changed(dps_changed), + .dps_changed_valid(dps_changed_valid), + .dprio_write_done(dprio_write_done), + .usr_num_shifts(usr_num_shifts), + .usr_cnt_sel(usr_cnt_sel|usr_cnt_sel_1), + .usr_up_dn(usr_up_dn), + .locked(locked), + .dps_done(dps_done), + .phase_en(phase_en), + .up_dn(up_dn), + .cnt_sel(cnt_sel)); + defparam dyn_phase_shift_inst.device_family = device_family; + + assign dprio_clk = clk; + self_reset self_reset_inst (mgmt_reset, clk, reset, dprio_init_reset); + + dprio_mux dprio_mux_inst ( + .init_dprio_address(init_dprio_address), + .init_dprio_read(init_dprio_read), + .init_dprio_byteen(init_dprio_byteen), + .init_dprio_write(init_dprio_write), + .init_dprio_writedata(init_dprio_writedata), + + + .init_atpgmode(init_atpgmode), + .init_mdio_dis(init_mdio_dis), + .init_scanen(init_scanen), + .init_ser_shift_load(init_ser_shift_load), + .dprio_init_done(dprio_init_done), + + // Inputs from avmm master + .avmm_dprio_address(avmm_dprio_address | dprio_address_1), + .avmm_dprio_read(avmm_dprio_read | dprio_read_1), + .avmm_dprio_byteen(avmm_dprio_byteen | dprio_byteen_1), + .avmm_dprio_write(avmm_dprio_write), + .avmm_dprio_writedata(avmm_dprio_writedata), + + .avmm_atpgmode(avmm_atpgmode), + .avmm_mdio_dis(avmm_mdio_dis), + .avmm_scanen(avmm_scanen), + + // Outputs to fpll + .dprio_address(dprio_address), + .dprio_read(dprio_read), + .dprio_byteen(dprio_byteen), + .dprio_write(dprio_write), + .dprio_writedata(dprio_writedata), + + .atpgmode(dprio_atpgmode), + .mdio_dis(dprio_mdio_dis), + .scanen(dprio_scanen), + .ser_shift_load(dprio_ser_shift_load) + ); + + + fpll_dprio_init fpll_dprio_init_inst ( + .clk(clk), + .reset_n(~reset), + .locked(locked), + + //outputs + .dprio_address(init_dprio_address), + .dprio_read(init_dprio_read), + .dprio_byteen(init_dprio_byteen), + .dprio_write(init_dprio_write), + .dprio_writedata(init_dprio_writedata), + + .atpgmode(init_atpgmode), + .mdio_dis(init_mdio_dis), + .scanen(init_scanen), + .ser_shift_load(init_ser_shift_load), + .dprio_init_done(dprio_init_done)); + + //address luts, to be reconfigged by the Fitter + //FPLL_1 or 0 address lut + generic_lcell_comb lcell_fpll_0_1 ( + .dataa(1'b0), + .combout (fpll_1)); + defparam lcell_fpll_0_1.lut_mask = 64'hAAAAAAAAAAAAAAAA; + defparam lcell_fpll_0_1.dont_touch = "on"; + defparam lcell_fpll_0_1.family = device_family; + + + wire dprio_read_combout; + generic_lcell_comb lcell_dprio_read ( + .dataa(fpll_1), + .datab(dprio_read), + .datac(1'b0), + .datad(1'b0), + .datae(1'b0), + .dataf(1'b0), + .combout (dprio_read_combout)); + defparam lcell_dprio_read.lut_mask = 64'hCCCCCCCCCCCCCCCC; + defparam lcell_dprio_read.dont_touch = "on"; + defparam lcell_dprio_read.family = device_family; + + + + + + //assign reconfig_to_pll signals + assign reconfig_to_pll[0] = dprio_clk; + assign reconfig_to_pll[1] = ~dprio_init_reset; + assign reconfig_to_pll[2] = dprio_write; + assign reconfig_to_pll[3] = dprio_read_combout; + assign reconfig_to_pll[9:4] = dprio_address; + assign reconfig_to_pll[25:10] = dprio_writedata; + assign reconfig_to_pll[27:26] = dprio_byteen; + assign reconfig_to_pll[28] = dprio_ser_shift_load; + assign reconfig_to_pll[29] = dprio_mdio_dis; + assign reconfig_to_pll[30] = phase_en; + assign reconfig_to_pll[31] = up_dn; + assign reconfig_to_pll[36:32] = cnt_sel; + assign reconfig_to_pll[37] = dprio_scanen; + assign reconfig_to_pll[38] = dprio_atpgmode; + //assign reconfig_to_pll[40:37] = clken; + assign reconfig_to_pll[63:39] = 0; + + //assign reconfig_from_pll signals + assign dprio_readdata = reconfig_from_pll [15:0]; + assign locked_orig = reconfig_from_pll [16]; + assign phase_done = reconfig_from_pll [17]; + +endmodule +module self_reset (input wire mgmt_reset, input wire clk, output wire reset, output wire init_reset); + + localparam RESET_COUNTER_VALUE = 3'd2; + localparam INITIAL_WAIT_VALUE = 9'd340; + reg [9:0]counter; + reg local_reset; + reg usr_mode_init_wait; + initial + begin + local_reset = 1'b1; + counter = 0; + usr_mode_init_wait = 0; + end + + always @(posedge clk) + begin + if (mgmt_reset) + begin + counter <= 0; + end + else + begin + if (!usr_mode_init_wait) + begin + if (counter == INITIAL_WAIT_VALUE) + begin + local_reset <= 0; + usr_mode_init_wait <= 1'b1; + counter <= 0; + end + else + begin + counter <= counter + 1'b1; + end + end + else + begin + if (counter == RESET_COUNTER_VALUE) + local_reset <= 0; + else + counter <= counter + 1'b1; + end + end + end + assign reset = mgmt_reset | local_reset; + assign init_reset = local_reset; +endmodule + +module dprio_mux ( + // Inputs from init block + input [ 5:0] init_dprio_address, + input init_dprio_read, + input [ 1:0] init_dprio_byteen, + input init_dprio_write, + input [15:0] init_dprio_writedata, + + input init_atpgmode, + input init_mdio_dis, + input init_scanen, + input init_ser_shift_load, + input dprio_init_done, + + // Inputs from avmm master + input [ 5:0] avmm_dprio_address, + input avmm_dprio_read, + input [ 1:0] avmm_dprio_byteen, + input avmm_dprio_write, + input [15:0] avmm_dprio_writedata, + + input avmm_atpgmode, + input avmm_mdio_dis, + input avmm_scanen, + input avmm_ser_shift_load, + + // Outputs to fpll + output [ 5:0] dprio_address, + output dprio_read, + output [ 1:0] dprio_byteen, + output dprio_write, + output [15:0] dprio_writedata, + + output atpgmode, + output mdio_dis, + output scanen, + output ser_shift_load +); + + assign dprio_address = dprio_init_done ? avmm_dprio_address : init_dprio_address; + assign dprio_read = dprio_init_done ? avmm_dprio_read : init_dprio_read; + assign dprio_byteen = dprio_init_done ? avmm_dprio_byteen : init_dprio_byteen; + assign dprio_write = dprio_init_done ? avmm_dprio_write : init_dprio_write; + assign dprio_writedata = dprio_init_done ? avmm_dprio_writedata : init_dprio_writedata; + + assign atpgmode = init_atpgmode; + assign scanen = init_scanen; + assign mdio_dis = init_mdio_dis; + assign ser_shift_load = init_ser_shift_load ; +endmodule +module fpll_dprio_init ( + input clk, + input reset_n, + input locked, + + output [ 5:0] dprio_address, + output dprio_read, + output [ 1:0] dprio_byteen, + output dprio_write, + output [15:0] dprio_writedata, + + output reg atpgmode, + output reg mdio_dis, + output reg scanen, + output reg ser_shift_load, + output reg dprio_init_done +); + + reg [1:0] rst_n = 2'b00; + reg [6:0] count = 7'd0; + reg init_done_forever; + + // Internal versions of control signals + wire int_mdio_dis; + wire int_ser_shift_load; + wire int_dprio_init_done; + wire int_atpgmode/*synthesis keep*/; + wire int_scanen/*synthesis keep*/; + + + assign dprio_address = count[6] ? 5'b0 : count[5:0] ; + assign dprio_byteen = 2'b11; // always enabled + assign dprio_write = ~count[6] & reset_n ; // write for first 64 cycles + assign dprio_read = 1'b0; + assign dprio_writedata = 16'd0; + + assign int_ser_shift_load = count[6] ? |count[2:1] : 1'b1; + assign int_mdio_dis = count[6] ? ~count[2] : 1'b1; + assign int_dprio_init_done = ~init_done_forever ? (count[6] ? &count[2:0] : 1'b0) + : 1'b1; + assign int_atpgmode = 0; + assign int_scanen = 0; + + initial begin + count = 7'd0; + init_done_forever = 0; + mdio_dis = 1'b1; + ser_shift_load = 1'b1; + dprio_init_done = 1'b0; + scanen = 1'b0; + atpgmode = 1'b0; + end + + // reset synch. + always @(posedge clk or negedge reset_n) + if(!reset_n) rst_n <= 2'b00; + else rst_n <= {rst_n[0],1'b1}; + + // counter + always @(posedge clk) + begin + if (!rst_n[1]) + init_done_forever <= 1'b0; + else + begin + if (count[6] && &count[1:0]) + init_done_forever <= 1'b1; + end + end + always @(posedge clk or negedge rst_n[1]) + begin + if(!rst_n[1]) + begin + count <= 7'd0; + end + else if(~int_dprio_init_done) + begin + count <= count + 7'd1; + end + else + begin + count <= count; + end + end + + // outputs + always @(posedge clk) begin + mdio_dis <= int_mdio_dis; + ser_shift_load <= int_ser_shift_load; + dprio_init_done <= int_dprio_init_done; + atpgmode <= int_atpgmode; + scanen <= int_scanen; + end + +endmodule +module dyn_phase_shift +#( + parameter device_family = "Stratix V" +) ( + + input wire clk, + input wire reset, + input wire phase_done, + input wire pll_start_valid, + input wire dps_changed, + input wire dprio_write_done, + input wire [15:0] usr_num_shifts, + input wire [4:0] usr_cnt_sel, + input wire usr_up_dn, + input wire locked, + + //output + output wire dps_done, + output reg phase_en, + output wire up_dn, + output wire dps_changed_valid, + output wire [4:0] cnt_sel); + + + + reg first_phase_shift_d; + reg first_phase_shift_q; + reg [15:0] phase_en_counter; + reg [3:0] dps_current_state; + reg [3:0] dps_next_state; + localparam DPS_START = 4'd0, DPS_WAIT_PHASE_DONE = 4'd1, DPS_DONE = 4'd2, DPS_WAIT_PHASE_EN = 4'd3, DPS_WAIT_DPRIO_WRITING = 4'd4, DPS_CHANGED = 4'd5; + localparam PHASE_EN_WAIT_COUNTER = 5'd1; + + reg [15:0] shifts_done_counter; + reg phase_done_final; + wire gnd /*synthesis keep*/; + + //fsm + //always block controlling the state regs + always @(posedge clk) + begin + if (reset) + begin + dps_current_state <= DPS_DONE; + end + else + begin + dps_current_state <= dps_next_state; + end + end + //the combinational part. assigning the next state + //this turns on the phase_done_final signal when phase_done does this: + //_____ ______ + // |______| + always @(*) + begin + phase_done_final = 0; + first_phase_shift_d = 0; + phase_en = 0; + dps_next_state = DPS_DONE; + case (dps_current_state) + DPS_START: + begin + phase_en = 1'b1; + dps_next_state = DPS_WAIT_PHASE_EN; + end + DPS_WAIT_PHASE_EN: + begin + phase_en = 1'b1; + if (first_phase_shift_q) + begin + first_phase_shift_d = 1'b1; + dps_next_state = DPS_WAIT_PHASE_EN; + end + else + begin + if (phase_en_counter == PHASE_EN_WAIT_COUNTER) + dps_next_state = DPS_WAIT_PHASE_DONE; + else dps_next_state = DPS_WAIT_PHASE_EN; + end + end + DPS_WAIT_PHASE_DONE: + begin + if (!phase_done | !locked) + begin + dps_next_state = DPS_WAIT_PHASE_DONE; + end + else + begin + if ((usr_num_shifts != shifts_done_counter) & (usr_num_shifts != 0)) + begin + dps_next_state = DPS_START; + phase_done_final = 1'b1; + end + else + begin + dps_next_state = DPS_DONE; + end + + end + end + DPS_DONE: + begin + phase_done_final = 0; + if (dps_changed) + dps_next_state = DPS_CHANGED; + else dps_next_state = DPS_DONE; + + end + DPS_CHANGED: + begin + if (pll_start_valid) + dps_next_state = DPS_WAIT_DPRIO_WRITING; + else + dps_next_state = DPS_CHANGED; + end + DPS_WAIT_DPRIO_WRITING: + begin + if (dprio_write_done) + dps_next_state = DPS_START; + else + dps_next_state = DPS_WAIT_DPRIO_WRITING; + end + + default: dps_next_state = 4'bxxxx; + endcase + + + end + + always @(posedge clk) + begin + + + if (dps_current_state == DPS_WAIT_PHASE_DONE) + phase_en_counter <= 0; + else if (dps_current_state == DPS_WAIT_PHASE_EN) + phase_en_counter <= phase_en_counter + 1'b1; + + if (reset) + begin + phase_en_counter <= 0; + shifts_done_counter <= 1'b1; + first_phase_shift_q <= 1; + end + else + begin + if (first_phase_shift_d) + first_phase_shift_q <= 0; + if (dps_done) + begin + shifts_done_counter <= 1'b1; + end + else + begin + if (phase_done_final & (dps_next_state!= DPS_DONE)) + shifts_done_counter <= shifts_done_counter + 1'b1; + else + shifts_done_counter <= shifts_done_counter; + end + end + end + + assign dps_changed_valid = (dps_current_state == DPS_CHANGED); + assign dps_done =(dps_current_state == DPS_DONE) | (dps_current_state == DPS_CHANGED); + assign up_dn = usr_up_dn; + assign gnd = 1'b0; + + //cnt select luts (5) + generic_lcell_comb lcell_cnt_sel_0 ( + .dataa(usr_cnt_sel[0]), + .datab(usr_cnt_sel[1]), + .datac(usr_cnt_sel[2]), + .datad(usr_cnt_sel[3]), + .datae(usr_cnt_sel[4]), + .dataf(gnd), + .combout (cnt_sel[0])); + defparam lcell_cnt_sel_0.lut_mask = 64'hAAAAAAAAAAAAAAAA; + defparam lcell_cnt_sel_0.dont_touch = "on"; + defparam lcell_cnt_sel_0.family = device_family; + generic_lcell_comb lcell_cnt_sel_1 ( + .dataa(usr_cnt_sel[0]), + .datab(usr_cnt_sel[1]), + .datac(usr_cnt_sel[2]), + .datad(usr_cnt_sel[3]), + .datae(usr_cnt_sel[4]), + .dataf(gnd), + .combout (cnt_sel[1])); + defparam lcell_cnt_sel_1.lut_mask = 64'hCCCCCCCCCCCCCCCC; + defparam lcell_cnt_sel_1.dont_touch = "on"; + defparam lcell_cnt_sel_1.family = device_family; + generic_lcell_comb lcell_cnt_sel_2 ( + .dataa(usr_cnt_sel[0]), + .datab(usr_cnt_sel[1]), + .datac(usr_cnt_sel[2]), + .datad(usr_cnt_sel[3]), + .datae(usr_cnt_sel[4]), + .dataf(gnd), + .combout (cnt_sel[2])); + defparam lcell_cnt_sel_2.lut_mask = 64'hF0F0F0F0F0F0F0F0; + defparam lcell_cnt_sel_2.dont_touch = "on"; + defparam lcell_cnt_sel_2.family = device_family; + generic_lcell_comb lcell_cnt_sel_3 ( + .dataa(usr_cnt_sel[0]), + .datab(usr_cnt_sel[1]), + .datac(usr_cnt_sel[2]), + .datad(usr_cnt_sel[3]), + .datae(usr_cnt_sel[4]), + .dataf(gnd), + .combout (cnt_sel[3])); + defparam lcell_cnt_sel_3.lut_mask = 64'hFF00FF00FF00FF00; + defparam lcell_cnt_sel_3.dont_touch = "on"; + defparam lcell_cnt_sel_3.family = device_family; + generic_lcell_comb lcell_cnt_sel_4 ( + .dataa(usr_cnt_sel[0]), + .datab(usr_cnt_sel[1]), + .datac(usr_cnt_sel[2]), + .datad(usr_cnt_sel[3]), + .datae(usr_cnt_sel[4]), + .dataf(gnd), + .combout (cnt_sel[4])); + defparam lcell_cnt_sel_4.lut_mask = 64'hFFFF0000FFFF0000; + defparam lcell_cnt_sel_4.dont_touch = "on"; + defparam lcell_cnt_sel_4.family = device_family; + + +endmodule + +module generic_lcell_comb +#( + //parameter + parameter family = "Stratix V", + parameter lut_mask = 64'hAAAAAAAAAAAAAAAA, + parameter dont_touch = "on" +) ( + + input dataa, + input datab, + input datac, + input datad, + input datae, + input dataf, + + output combout +); + + generate + if (family == "Stratix V") + begin + stratixv_lcell_comb lcell_inst ( + .dataa(dataa), + .datab(datab), + .datac(datac), + .datad(datad), + .datae(datae), + .dataf(dataf), + .combout (combout)); + defparam lcell_inst.lut_mask = lut_mask; + defparam lcell_inst.dont_touch = dont_touch; + end + else if (family == "Arria V") + begin + arriav_lcell_comb lcell_inst ( + .dataa(dataa), + .datab(datab), + .datac(datac), + .datad(datad), + .datae(datae), + .dataf(dataf), + .combout (combout)); + defparam lcell_inst.lut_mask = lut_mask; + defparam lcell_inst.dont_touch = dont_touch; + end + else if (family == "Arria V GZ") + begin + arriavgz_lcell_comb lcell_inst ( + .dataa(dataa), + .datab(datab), + .datac(datac), + .datad(datad), + .datae(datae), + .dataf(dataf), + .combout (combout)); + defparam lcell_inst.lut_mask = lut_mask; + defparam lcell_inst.dont_touch = dont_touch; + end + else if (family == "Cyclone V") + begin + cyclonev_lcell_comb lcell_inst ( + .dataa(dataa), + .datab(datab), + .datac(datac), + .datad(datad), + .datae(datae), + .dataf(dataf), + .combout (combout)); + defparam lcell_inst.lut_mask = lut_mask; + defparam lcell_inst.dont_touch = dont_touch; + end + endgenerate +endmodule diff --git a/sys/pll_cfg/altera_pll_reconfig_top.v b/sys/pll_cfg/altera_pll_reconfig_top.v new file mode 100644 index 0000000..c1bfa8b --- /dev/null +++ b/sys/pll_cfg/altera_pll_reconfig_top.v @@ -0,0 +1,428 @@ +// (C) 2001-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 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, 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. + + +`timescale 1ps/1ps + +module altera_pll_reconfig_top +#( + parameter reconf_width = 64, + parameter device_family = "Stratix V", + parameter RECONFIG_ADDR_WIDTH = 6, + parameter RECONFIG_DATA_WIDTH = 32, + + parameter ROM_ADDR_WIDTH = 9, + parameter ROM_DATA_WIDTH = 32, + parameter ROM_NUM_WORDS = 512, + + parameter ENABLE_MIF = 0, + parameter MIF_FILE_NAME = "", + + parameter ENABLE_BYTEENABLE = 0, + parameter BYTEENABLE_WIDTH = 4, + parameter WAIT_FOR_LOCK = 1 +) ( + + //input + input wire mgmt_clk, + input wire mgmt_reset, + + + //conduits + output wire [reconf_width-1:0] reconfig_to_pll, + input wire [reconf_width-1:0] reconfig_from_pll, + + // user data (avalon-MM slave interface) + output wire [RECONFIG_DATA_WIDTH-1:0] mgmt_readdata, + output wire mgmt_waitrequest, + input wire [RECONFIG_ADDR_WIDTH-1:0] mgmt_address, + input wire mgmt_read, + input wire mgmt_write, + input wire [RECONFIG_DATA_WIDTH-1:0] mgmt_writedata, + + //conditional input + input wire [BYTEENABLE_WIDTH-1:0] mgmt_byteenable +); + +localparam NM28_START_REG = 6'b000010; +localparam NM20_START_REG = 9'b000000000; +localparam NM20_MIFSTART_ADDR = 9'b000010000; + +localparam MIF_STATE_DONE = 2'b00; +localparam MIF_STATE_START = 2'b01; +localparam MIF_STATE_BUSY = 2'b10; + +wire mgmt_byteenable_write; +assign mgmt_byteenable_write = (ENABLE_BYTEENABLE == 1) ? + ((mgmt_byteenable == {BYTEENABLE_WIDTH{1'b1}}) ? mgmt_write : 1'b0) : + mgmt_write; + +generate +if (device_family == "Arria 10") +begin:nm20_reconfig + if(ENABLE_MIF == 1) + begin:mif_reconfig_20nm // Generate Reconfig with MIF + + // MIF-related regs/wires + reg [RECONFIG_ADDR_WIDTH-1:0] reconfig_mgmt_addr; + reg reconfig_mgmt_read; + reg reconfig_mgmt_write; + reg [RECONFIG_DATA_WIDTH-1:0] reconfig_mgmt_writedata; + wire reconfig_mgmt_waitrequest; + wire [RECONFIG_DATA_WIDTH-1:0] reconfig_mgmt_readdata; + + wire [RECONFIG_ADDR_WIDTH-1:0] mif2reconfig_addr; + wire mif_busy; + wire mif2reconfig_read; + wire mif2reconfig_write; + wire [RECONFIG_DATA_WIDTH-1:0] mif2reconfig_writedata; + wire [ROM_ADDR_WIDTH-1:0] mif_base_addr; + reg mif_select; + //wire mif_user_start; // start signal provided by user to start mif + //reg user_start; + + reg [1:0] mif_curstate; + reg [1:0] mif_nextstate; + + wire mif_start; //start signal to mif reader + + assign mgmt_waitrequest = reconfig_mgmt_waitrequest | mif_busy;// | user_start; + // Don't output readdata if MIF streaming is taking place + assign mgmt_readdata = (mif_select) ? 32'b0 : reconfig_mgmt_readdata; + + //user must lower this by the time mif streaming is done - suggest to lower after 1 cycle + assign mif_start = mgmt_byteenable_write & (mgmt_address == NM20_MIFSTART_ADDR); + + //mif base addr is initially specified by the user + assign mif_base_addr = mgmt_writedata[ROM_ADDR_WIDTH-1:0]; + + //MIF statemachine + always @(posedge mgmt_clk) + begin + if(mgmt_reset) + mif_curstate <= MIF_STATE_DONE; + else + mif_curstate <= mif_nextstate; + end + + always @(*) + begin + case (mif_curstate) + MIF_STATE_DONE: + begin + if(mif_start) + mif_nextstate <= MIF_STATE_START; + else + mif_nextstate <= MIF_STATE_DONE; + end + MIF_STATE_START: + begin + mif_nextstate <= MIF_STATE_BUSY; + end + MIF_STATE_BUSY: + begin + if(mif_busy) + mif_nextstate <= MIF_STATE_BUSY; + else + mif_nextstate <= MIF_STATE_DONE; + end + endcase + end + + //Mif muxes + always @(*) + begin + if (mgmt_reset) + begin + reconfig_mgmt_addr <= 0; + reconfig_mgmt_read <= 0; + reconfig_mgmt_write <= 0; + reconfig_mgmt_writedata <= 0; + //user_start <= 0; + end + else + begin + reconfig_mgmt_addr <= (mif_select) ? mif2reconfig_addr : mgmt_address; + reconfig_mgmt_read <= (mif_select) ? mif2reconfig_read : mgmt_read; + reconfig_mgmt_write <= (mif_select) ? mif2reconfig_write : mgmt_byteenable_write; + reconfig_mgmt_writedata <= (mif_select) ? mif2reconfig_writedata : mgmt_writedata; + //user_start <= (mgmt_address == NM20_START_REG && mgmt_write == 1'b1) ? 1'b1 : 1'b0; + end + end + + always @(*) + begin + if (mgmt_reset) + begin + mif_select <= 0; + end + else + begin + mif_select <= (mif_start || mif_busy) ? 1'b1 : 1'b0; + end + end + + twentynm_pll_reconfig_mif_reader + #( + .RECONFIG_ADDR_WIDTH(RECONFIG_ADDR_WIDTH), + .RECONFIG_DATA_WIDTH(RECONFIG_DATA_WIDTH), + .ROM_ADDR_WIDTH(ROM_ADDR_WIDTH), + .ROM_DATA_WIDTH(ROM_DATA_WIDTH), + .ROM_NUM_WORDS(ROM_NUM_WORDS), + .DEVICE_FAMILY(device_family), + .ENABLE_MIF(ENABLE_MIF), + .MIF_FILE_NAME(MIF_FILE_NAME) + ) twentynm_pll_reconfig_mif_reader_inst0 ( + .mif_clk(mgmt_clk), + .mif_rst(mgmt_reset), + + //Altera_PLL Reconfig interface + //inputs + .reconfig_waitrequest(reconfig_mgmt_waitrequest), + //.reconfig_read_data(reconfig_mgmt_readdata), + //outputs + .reconfig_write_data(mif2reconfig_writedata), + .reconfig_addr(mif2reconfig_addr), + .reconfig_write(mif2reconfig_write), + .reconfig_read(mif2reconfig_read), + + //MIF Ctrl Interface + //inputs + .mif_base_addr(mif_base_addr), + .mif_start(mif_start), + //outputs + .mif_busy(mif_busy) + ); + + // ------ END MIF-RELATED MANAGEMENT ------ + + twentynm_iopll_reconfig_core + #( + .WAIT_FOR_LOCK(WAIT_FOR_LOCK) + ) twentynm_iopll_reconfig_core_inst ( + // Inputs + .mgmt_clk(mgmt_clk), + .mgmt_rst_n(~mgmt_reset), + .mgmt_read(reconfig_mgmt_read), + .mgmt_write(reconfig_mgmt_write), + .mgmt_address(reconfig_mgmt_addr), + .mgmt_writedata(reconfig_mgmt_writedata), + + // Outputs + .mgmt_readdata(reconfig_mgmt_readdata), + .mgmt_waitrequest(reconfig_mgmt_waitrequest), + + // PLL Conduits + .reconfig_to_pll(reconfig_to_pll), + .reconfig_from_pll(reconfig_from_pll) + ); + + end // End generate reconfig with MIF + else + begin:reconfig_core_20nm + twentynm_iopll_reconfig_core + #( + .WAIT_FOR_LOCK(WAIT_FOR_LOCK) + ) twentynm_iopll_reconfig_core_inst ( + // Inputs + .mgmt_clk(mgmt_clk), + .mgmt_rst_n(~mgmt_reset), + .mgmt_read(mgmt_read), + .mgmt_write(mgmt_byteenable_write), + .mgmt_address(mgmt_address), + .mgmt_writedata(mgmt_writedata), + + // Outputs + .mgmt_readdata(mgmt_readdata), + .mgmt_waitrequest(mgmt_waitrequest), + + // PLL Conduits + .reconfig_to_pll(reconfig_to_pll), + .reconfig_from_pll(reconfig_from_pll) + ); + end +end // 20nm reconfig +else +begin:NM28_reconfig + if (ENABLE_MIF == 1) + begin:mif_reconfig // Generate Reconfig with MIF + + // MIF-related regs/wires + reg [RECONFIG_ADDR_WIDTH-1:0] reconfig_mgmt_addr; + reg reconfig_mgmt_read; + reg reconfig_mgmt_write; + reg [RECONFIG_DATA_WIDTH-1:0] reconfig_mgmt_writedata; + wire reconfig_mgmt_waitrequest; + wire [RECONFIG_DATA_WIDTH-1:0] reconfig_mgmt_readdata; + + wire [RECONFIG_ADDR_WIDTH-1:0] mif2reconfig_addr; + wire mif2reconfig_busy; + wire mif2reconfig_read; + wire mif2reconfig_write; + wire [RECONFIG_DATA_WIDTH-1:0] mif2reconfig_writedata; + wire [ROM_ADDR_WIDTH-1:0] mif_base_addr; + reg mif_select; + reg user_start; + + wire reconfig2mif_start_out; + + assign mgmt_waitrequest = reconfig_mgmt_waitrequest | mif2reconfig_busy | user_start; + // Don't output readdata if MIF streaming is taking place + assign mgmt_readdata = (mif_select) ? 32'b0 : reconfig_mgmt_readdata; + + always @(posedge mgmt_clk) + begin + if (mgmt_reset) + begin + reconfig_mgmt_addr <= 0; + reconfig_mgmt_read <= 0; + reconfig_mgmt_write <= 0; + reconfig_mgmt_writedata <= 0; + user_start <= 0; + end + else + begin + reconfig_mgmt_addr <= (mif_select) ? mif2reconfig_addr : mgmt_address; + reconfig_mgmt_read <= (mif_select) ? mif2reconfig_read : mgmt_read; + reconfig_mgmt_write <= (mif_select) ? mif2reconfig_write : mgmt_byteenable_write; + reconfig_mgmt_writedata <= (mif_select) ? mif2reconfig_writedata : mgmt_writedata; + user_start <= (mgmt_address == NM28_START_REG && mgmt_byteenable_write == 1'b1) ? 1'b1 : 1'b0; + end + end + + always @(*) + begin + if (mgmt_reset) + begin + mif_select <= 0; + end + else + begin + mif_select <= (reconfig2mif_start_out || mif2reconfig_busy) ? 1'b1 : 1'b0; + end + end + + altera_pll_reconfig_mif_reader + #( + .RECONFIG_ADDR_WIDTH(RECONFIG_ADDR_WIDTH), + .RECONFIG_DATA_WIDTH(RECONFIG_DATA_WIDTH), + .ROM_ADDR_WIDTH(ROM_ADDR_WIDTH), + .ROM_DATA_WIDTH(ROM_DATA_WIDTH), + .ROM_NUM_WORDS(ROM_NUM_WORDS), + .DEVICE_FAMILY(device_family), + .ENABLE_MIF(ENABLE_MIF), + .MIF_FILE_NAME(MIF_FILE_NAME) + ) altera_pll_reconfig_mif_reader_inst0 ( + .mif_clk(mgmt_clk), + .mif_rst(mgmt_reset), + + //Altera_PLL Reconfig interface + //inputs + .reconfig_busy(reconfig_mgmt_waitrequest), + .reconfig_read_data(reconfig_mgmt_readdata), + //outputs + .reconfig_write_data(mif2reconfig_writedata), + .reconfig_addr(mif2reconfig_addr), + .reconfig_write(mif2reconfig_write), + .reconfig_read(mif2reconfig_read), + + //MIF Ctrl Interface + //inputs + .mif_base_addr(mif_base_addr), + .mif_start(reconfig2mif_start_out), + //outputs + .mif_busy(mif2reconfig_busy) + ); + + // ------ END MIF-RELATED MANAGEMENT ------ + + + altera_pll_reconfig_core + #( + .reconf_width(reconf_width), + .device_family(device_family), + .RECONFIG_ADDR_WIDTH(RECONFIG_ADDR_WIDTH), + .RECONFIG_DATA_WIDTH(RECONFIG_DATA_WIDTH), + .ROM_ADDR_WIDTH(ROM_ADDR_WIDTH), + .ROM_DATA_WIDTH(ROM_DATA_WIDTH), + .ROM_NUM_WORDS(ROM_NUM_WORDS) + ) altera_pll_reconfig_core_inst0 ( + //inputs + .mgmt_clk(mgmt_clk), + .mgmt_reset(mgmt_reset), + + //PLL interface conduits + .reconfig_to_pll(reconfig_to_pll), + .reconfig_from_pll(reconfig_from_pll), + + //User data outputs + .mgmt_readdata(reconfig_mgmt_readdata), + .mgmt_waitrequest(reconfig_mgmt_waitrequest), + + //User data inputs + .mgmt_address(reconfig_mgmt_addr), + .mgmt_read(reconfig_mgmt_read), + .mgmt_write(reconfig_mgmt_write), + .mgmt_writedata(reconfig_mgmt_writedata), + + // other + .mif_start_out(reconfig2mif_start_out), + .mif_base_addr(mif_base_addr) + ); + + end // End generate reconfig with MIF + else + begin:reconfig_core // Generate Reconfig core only + + wire reconfig2mif_start_out; + wire [ROM_ADDR_WIDTH-1:0] mif_base_addr; + + altera_pll_reconfig_core + #( + .reconf_width(reconf_width), + .device_family(device_family), + .RECONFIG_ADDR_WIDTH(RECONFIG_ADDR_WIDTH), + .RECONFIG_DATA_WIDTH(RECONFIG_DATA_WIDTH), + .ROM_ADDR_WIDTH(ROM_ADDR_WIDTH), + .ROM_DATA_WIDTH(ROM_DATA_WIDTH), + .ROM_NUM_WORDS(ROM_NUM_WORDS) + ) altera_pll_reconfig_core_inst0 ( + //inputs + .mgmt_clk(mgmt_clk), + .mgmt_reset(mgmt_reset), + + //PLL interface conduits + .reconfig_to_pll(reconfig_to_pll), + .reconfig_from_pll(reconfig_from_pll), + + //User data outputs + .mgmt_readdata(mgmt_readdata), + .mgmt_waitrequest(mgmt_waitrequest), + + //User data inputs + .mgmt_address(mgmt_address), + .mgmt_read(mgmt_read), + .mgmt_write(mgmt_byteenable_write), + .mgmt_writedata(mgmt_writedata), + + // other + .mif_start_out(reconfig2mif_start_out), + .mif_base_addr(mif_base_addr) + ); + + + end // End generate reconfig core only +end // End 28nm Reconfig +endgenerate + +endmodule + diff --git a/sys/pll_hdmi.13.qip b/sys/pll_hdmi.13.qip new file mode 100644 index 0000000..76def89 --- /dev/null +++ b/sys/pll_hdmi.13.qip @@ -0,0 +1,17 @@ +set_global_assignment -entity "pll_hdmi" -library "pll_hdmi" -name IP_TOOL_NAME "altera_pll" +set_global_assignment -entity "pll_hdmi" -library "pll_hdmi" -name IP_TOOL_VERSION "13.1" +set_global_assignment -entity "pll_hdmi" -library "pll_hdmi" -name IP_TOOL_ENV "mwpim" +set_global_assignment -library "pll_hdmi" -name MISC_FILE [file join $::quartus(qip_path) "pll_hdmi.cmp"] +set_global_assignment -name SYNTHESIS_ONLY_QIP ON + +set_global_assignment -library "pll_hdmi" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_hdmi.v"] +set_global_assignment -library "pll_hdmi" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_hdmi/pll_hdmi_0002.v"] + +set_instance_assignment -name PLL_COMPENSATION_MODE DIRECT -to "*pll_hdmi_0002*|altera_pll:altera_pll_i*|*" +set_instance_assignment -name PLL_CHANNEL_SPACING "0.0 KHz" -to "*pll_hdmi_0002*|altera_pll:altera_pll_i*|*" +set_instance_assignment -name PLL_AUTO_RESET ON -to "*pll_hdmi_0002*|altera_pll:altera_pll_i*|*" +set_instance_assignment -name PLL_BANDWIDTH_PRESET AUTO -to "*pll_hdmi_0002*|altera_pll:altera_pll_i*|*" + +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_TOOL_NAME "altera_pll" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_TOOL_VERSION "13.1" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_TOOL_ENV "mwpim" diff --git a/sys/pll_hdmi.qip b/sys/pll_hdmi.qip new file mode 100644 index 0000000..be34aeb --- /dev/null +++ b/sys/pll_hdmi.qip @@ -0,0 +1,483 @@ +set_global_assignment -entity "pll_hdmi" -library "pll_hdmi" -name IP_TOOL_NAME "altera_pll" +set_global_assignment -entity "pll_hdmi" -library "pll_hdmi" -name IP_TOOL_VERSION "17.0" +set_global_assignment -entity "pll_hdmi" -library "pll_hdmi" -name IP_TOOL_ENV "mwpim" +set_global_assignment -library "pll_hdmi" -name MISC_FILE [file join $::quartus(qip_path) "pll_hdmi.cmp"] +set_global_assignment -entity "pll_hdmi" -library "pll_hdmi" -name IP_TARGETED_DEVICE_FAMILY "Cyclone V" +set_global_assignment -entity "pll_hdmi" -library "pll_hdmi" -name IP_GENERATED_DEVICE_FAMILY "{Cyclone V}" +set_global_assignment -entity "pll_hdmi" -library "pll_hdmi" -name IP_QSYS_MODE "UNKNOWN" +set_global_assignment -name SYNTHESIS_ONLY_QIP ON +set_global_assignment -entity "pll_hdmi" -library "pll_hdmi" -name IP_COMPONENT_NAME "cGxsX2hkbWk=" +set_global_assignment -entity "pll_hdmi" -library "pll_hdmi" -name IP_COMPONENT_DISPLAY_NAME "QWx0ZXJhIFBMTA==" +set_global_assignment -entity "pll_hdmi" -library "pll_hdmi" -name IP_COMPONENT_REPORT_HIERARCHY "Off" +set_global_assignment -entity "pll_hdmi" -library "pll_hdmi" -name IP_COMPONENT_INTERNAL "Off" +set_global_assignment -entity "pll_hdmi" -library "pll_hdmi" -name IP_COMPONENT_AUTHOR "QWx0ZXJhIENvcnBvcmF0aW9u" +set_global_assignment -entity "pll_hdmi" -library "pll_hdmi" -name IP_COMPONENT_VERSION "MTcuMA==" +set_global_assignment -entity "pll_hdmi" -library "pll_hdmi" -name IP_COMPONENT_DESCRIPTION "QWx0ZXJhIFBoYXNlLUxvY2tlZCBMb29wIChBTFRFUkFfUExMKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_NAME "cGxsX2hkbWlfMDAwMg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_DISPLAY_NAME "QWx0ZXJhIFBMTA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_REPORT_HIERARCHY "Off" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_INTERNAL "Off" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_AUTHOR "QWx0ZXJhIENvcnBvcmF0aW9u" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_VERSION "MTcuMA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_DESCRIPTION "QWx0ZXJhIFBoYXNlLUxvY2tlZCBMb29wIChBTFRFUkFfUExMKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZGVidWdfcHJpbnRfb3V0cHV0::ZmFsc2U=::ZGVidWdfcHJpbnRfb3V0cHV0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZGVidWdfdXNlX3JiY190YWZfbWV0aG9k::ZmFsc2U=::ZGVidWdfdXNlX3JiY190YWZfbWV0aG9k" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZGV2aWNl::NUNFQkEyRjE3QTc=::ZGV2aWNl" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BsbF9tb2Rl::RnJhY3Rpb25hbC1OIFBMTA==::UExMIE1vZGU=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZnJhY3Rpb25hbF92Y29fbXVsdGlwbGllcg==::dHJ1ZQ==::ZnJhY3Rpb25hbF92Y29fbXVsdGlwbGllcg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3JlZmVyZW5jZV9jbG9ja19mcmVxdWVuY3k=::NTAuMA==::UmVmZXJlbmNlIENsb2NrIEZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cmVmZXJlbmNlX2Nsb2NrX2ZyZXF1ZW5jeQ==::NTAuMCBNSHo=::cmVmZXJlbmNlX2Nsb2NrX2ZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2NoYW5uZWxfc3BhY2luZw==::MC4w::Q2hhbm5lbCBTcGFjaW5n" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX29wZXJhdGlvbl9tb2Rl::ZGlyZWN0::T3BlcmF0aW9uIE1vZGU=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2ZlZWRiYWNrX2Nsb2Nr::R2xvYmFsIENsb2Nr::RmVlZGJhY2sgQ2xvY2s=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2ZyYWN0aW9uYWxfY291dA==::MzI=::RnJhY3Rpb25hbCBjYXJyeSBvdXQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGxsX2ZyYWN0aW9uYWxfY291dA==::MzI=::cGxsX2ZyYWN0aW9uYWxfY291dA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RzbV9vdXRfc2Vs::MXN0X29yZGVy::RFNNIE9yZGVy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGxsX2RzbV9vdXRfc2Vs::MXN0X29yZGVy::cGxsX2RzbV9vdXRfc2Vs" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "b3BlcmF0aW9uX21vZGU=::ZGlyZWN0::b3BlcmF0aW9uX21vZGU=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3VzZV9sb2NrZWQ=::ZmFsc2U=::RW5hYmxlIGxvY2tlZCBvdXRwdXQgcG9ydA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2VuX2Fkdl9wYXJhbXM=::ZmFsc2U=::RW5hYmxlIHBoeXNpY2FsIG91dHB1dCBjbG9jayBwYXJhbWV0ZXJz" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX251bWJlcl9vZl9jbG9ja3M=::MQ==::TnVtYmVyIE9mIENsb2Nrcw==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "bnVtYmVyX29mX2Nsb2Nrcw==::MQ==::bnVtYmVyX29mX2Nsb2Nrcw==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX211bHRpcGx5X2ZhY3Rvcg==::MQ==::TXVsdGlwbHkgRmFjdG9yIChNLUNvdW50ZXIp" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2ZyYWNfbXVsdGlwbHlfZmFjdG9y::MQ==::RnJhY3Rpb25hbCBNdWx0aXBseSBGYWN0b3IgKEsp" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3Jfbg==::MQ==::RGl2aWRlIEZhY3RvciAoTi1Db3VudGVyKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjA=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kw::MTQ4LjU=::RGVzaXJlZCBGcmVxdWVuY3k=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzA=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3Iw::OA==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjA=::MzkwODQyMDE1Mw==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMA==::Mw==::QWN0dWFsIERpdmlkZSBGYWN0b3I=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MA==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMA==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MA==::MA==::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzA=::MC4w::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDA=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUw::NTA=::RHV0eSBDeWNsZQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kx::NjUuMA==::RGVzaXJlZCBGcmVxdWVuY3k=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3Ix::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMQ==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MQ==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMQ==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MQ==::MA==::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE=::MC4w::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUx::NTA=::RHV0eSBDeWNsZQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjI=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3ky::MjcuMA==::RGVzaXJlZCBGcmVxdWVuY3k=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzI=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3Iy::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjI=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMg==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5Mg==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMg==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0Mg==::MA==::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzI=::MC4w::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDI=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUy::NTA=::RHV0eSBDeWNsZQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjM=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kz::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzM=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3Iz::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjM=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMw==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5Mw==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMw==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0Mw==::MA==::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzM=::MC4w::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDM=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUz::NTA=::RHV0eSBDeWNsZQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjQ=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k0::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzQ=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I0::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjQ=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yNA==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5NA==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzNA==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0NA==::MA==::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzQ=::MC4w::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDQ=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU0::NTA=::RHV0eSBDeWNsZQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjU=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k1::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzU=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I1::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjU=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yNQ==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5NQ==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzNQ==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0NQ==::MA==::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzU=::MC4w::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDU=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU1::NTA=::RHV0eSBDeWNsZQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjY=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k2::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzY=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I2::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjY=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yNg==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5Ng==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzNg==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0Ng==::MA==::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzY=::MC4w::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDY=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU2::NTA=::RHV0eSBDeWNsZQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjc=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k3::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzc=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I3::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3Rvcjc=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yNw==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5Nw==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzNw==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0Nw==::MA==::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzc=::MC4w::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDc=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU3::NTA=::RHV0eSBDeWNsZQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjg=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k4::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzg=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I4::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3Rvcjg=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yOA==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5OA==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzOA==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0OA==::MA==::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzg=::MC4w::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDg=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU4::NTA=::RHV0eSBDeWNsZQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjk=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k5::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzk=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I5::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3Rvcjk=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yOQ==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5OQ==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzOQ==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0OQ==::MA==::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzk=::MC4w::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDk=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU5::NTA=::RHV0eSBDeWNsZQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjEw::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxMA==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzEw::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxMA==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjEw::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTA=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTA=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTA=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTA=::MA==::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzEw::MC4w::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDEw::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxMA==::NTA=::RHV0eSBDeWNsZQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjEx::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxMQ==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzEx::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxMQ==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjEx::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTE=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTE=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTE=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTE=::MA==::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzEx::MC4w::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDEx::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxMQ==::NTA=::RHV0eSBDeWNsZQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjEy::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxMg==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzEy::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxMg==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjEy::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTI=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTI=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTI=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTI=::MA==::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzEy::MC4w::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDEy::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxMg==::NTA=::RHV0eSBDeWNsZQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjEz::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxMw==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzEz::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxMw==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjEz::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTM=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTM=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTM=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTM=::MA==::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzEz::MC4w::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDEz::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxMw==::NTA=::RHV0eSBDeWNsZQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE0::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxNA==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE0::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxNA==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE0::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTQ=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTQ=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTQ=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTQ=::MA==::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE0::MC4w::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE0::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxNA==::NTA=::RHV0eSBDeWNsZQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE1::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxNQ==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE1::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxNQ==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE1::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTU=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTU=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTU=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTU=::MA==::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE1::MC4w::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE1::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxNQ==::NTA=::RHV0eSBDeWNsZQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE2::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxNg==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE2::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxNg==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE2::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTY=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTY=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTY=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTY=::MA==::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE2::MC4w::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE2::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxNg==::NTA=::RHV0eSBDeWNsZQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE3::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxNw==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE3::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxNw==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE3::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTc=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTc=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTc=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTc=::MA==::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE3::MC4w::UGhhc2UgU2hpZnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE3::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxNw==::NTA=::RHV0eSBDeWNsZQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTA=::MTQ4LjUwMDAwMCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTA=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQw::MCBwcw==::cGhhc2Vfc2hpZnQw" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTA=::NTA=::ZHV0eV9jeWNsZTA=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQx::MCBwcw==::cGhhc2Vfc2hpZnQx" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE=::NTA=::ZHV0eV9jeWNsZTE=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTI=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTI=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQy::MCBwcw==::cGhhc2Vfc2hpZnQy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTI=::NTA=::ZHV0eV9jeWNsZTI=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTM=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQz::MCBwcw==::cGhhc2Vfc2hpZnQz" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTM=::NTA=::ZHV0eV9jeWNsZTM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTQ=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ0::MCBwcw==::cGhhc2Vfc2hpZnQ0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTQ=::NTA=::ZHV0eV9jeWNsZTQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTU=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTU=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ1::MCBwcw==::cGhhc2Vfc2hpZnQ1" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTU=::NTA=::ZHV0eV9jeWNsZTU=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTY=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTY=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ2::MCBwcw==::cGhhc2Vfc2hpZnQ2" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTY=::NTA=::ZHV0eV9jeWNsZTY=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTc=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTc=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ3::MCBwcw==::cGhhc2Vfc2hpZnQ3" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTc=::NTA=::ZHV0eV9jeWNsZTc=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTg=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTg=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ4::MCBwcw==::cGhhc2Vfc2hpZnQ4" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTg=::NTA=::ZHV0eV9jeWNsZTg=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTk=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTk=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ5::MCBwcw==::cGhhc2Vfc2hpZnQ5" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTk=::NTA=::ZHV0eV9jeWNsZTk=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEw::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEw" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxMA==::MCBwcw==::cGhhc2Vfc2hpZnQxMA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTEw::NTA=::ZHV0eV9jeWNsZTEw" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEx::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEx" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxMQ==::MCBwcw==::cGhhc2Vfc2hpZnQxMQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTEx::NTA=::ZHV0eV9jeWNsZTEx" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEy::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxMg==::MCBwcw==::cGhhc2Vfc2hpZnQxMg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTEy::NTA=::ZHV0eV9jeWNsZTEy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEz::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEz" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxMw==::MCBwcw==::cGhhc2Vfc2hpZnQxMw==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTEz::NTA=::ZHV0eV9jeWNsZTEz" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE0::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxNA==::MCBwcw==::cGhhc2Vfc2hpZnQxNA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE0::NTA=::ZHV0eV9jeWNsZTE0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE1::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE1" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxNQ==::MCBwcw==::cGhhc2Vfc2hpZnQxNQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE1::NTA=::ZHV0eV9jeWNsZTE1" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE2::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE2" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxNg==::MCBwcw==::cGhhc2Vfc2hpZnQxNg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE2::NTA=::ZHV0eV9jeWNsZTE2" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE3::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE3" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxNw==::MCBwcw==::cGhhc2Vfc2hpZnQxNw==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE3::NTA=::ZHV0eV9jeWNsZTE3" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BsbF9hdXRvX3Jlc2V0::T24=::UExMIEF1dG8gUmVzZXQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BsbF9iYW5kd2lkdGhfcHJlc2V0::QXV0bw==::UExMIEJhbmR3aWR0aCBQcmVzZXQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2VuX3JlY29uZg==::dHJ1ZQ==::RW5hYmxlIGR5bmFtaWMgcmVjb25maWd1cmF0aW9uIG9mIFBMTA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2VuX2Rwc19wb3J0cw==::ZmFsc2U=::RW5hYmxlIGFjY2VzcyB0byBkeW5hbWljIHBoYXNlIHNoaWZ0IHBvcnRz" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2VuX3Bob3V0X3BvcnRz::ZmFsc2U=::RW5hYmxlIGFjY2VzcyB0byBQTEwgRFBBIG91dHB1dCBwb3J0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGxsX3R5cGU=::Q3ljbG9uZSBW::UExMIFRZUEU=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGxsX3N1YnR5cGU=::UmVjb25maWd1cmFibGU=::UExMIFNVQlRZUEU=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "bV9jbnRfaGlfZGl2::NA==::bV9jbnRfaGlfZGl2" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "bV9jbnRfbG9fZGl2::NA==::bV9jbnRfbG9fZGl2" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "bl9jbnRfaGlfZGl2::MjU2::bl9jbnRfaGlfZGl2" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "bl9jbnRfbG9fZGl2::MjU2::bl9jbnRfbG9fZGl2" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "bV9jbnRfYnlwYXNzX2Vu::ZmFsc2U=::bV9jbnRfYnlwYXNzX2Vu" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "bl9jbnRfYnlwYXNzX2Vu::dHJ1ZQ==::bl9jbnRfYnlwYXNzX2Vu" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "bV9jbnRfb2RkX2Rpdl9kdXR5X2Vu::ZmFsc2U=::bV9jbnRfb2RkX2Rpdl9kdXR5X2Vu" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "bl9jbnRfb2RkX2Rpdl9kdXR5X2Vu::ZmFsc2U=::bl9jbnRfb2RkX2Rpdl9kdXR5X2Vu" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaGlfZGl2MA==::Mg==::Y19jbnRfaGlfZGl2MA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfbG9fZGl2MA==::MQ==::Y19jbnRfbG9fZGl2MA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcHJzdDA=::MQ==::Y19jbnRfcHJzdDA=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcGhfbXV4X3Byc3Qw::MA==::Y19jbnRfcGhfbXV4X3Byc3Qw" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaW5fc3JjMA==::cGhfbXV4X2Nsaw==::Y19jbnRfaW5fc3JjMA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfYnlwYXNzX2VuMA==::ZmFsc2U=::Y19jbnRfYnlwYXNzX2VuMA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMA==::dHJ1ZQ==::Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaGlfZGl2MQ==::MQ==::Y19jbnRfaGlfZGl2MQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfbG9fZGl2MQ==::MQ==::Y19jbnRfbG9fZGl2MQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcHJzdDE=::MQ==::Y19jbnRfcHJzdDE=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcGhfbXV4X3Byc3Qx::MA==::Y19jbnRfcGhfbXV4X3Byc3Qx" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaW5fc3JjMQ==::cGhfbXV4X2Nsaw==::Y19jbnRfaW5fc3JjMQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfYnlwYXNzX2VuMQ==::dHJ1ZQ==::Y19jbnRfYnlwYXNzX2VuMQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMQ==::ZmFsc2U=::Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaGlfZGl2Mg==::MQ==::Y19jbnRfaGlfZGl2Mg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfbG9fZGl2Mg==::MQ==::Y19jbnRfbG9fZGl2Mg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcHJzdDI=::MQ==::Y19jbnRfcHJzdDI=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcGhfbXV4X3Byc3Qy::MA==::Y19jbnRfcGhfbXV4X3Byc3Qy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaW5fc3JjMg==::cGhfbXV4X2Nsaw==::Y19jbnRfaW5fc3JjMg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfYnlwYXNzX2VuMg==::dHJ1ZQ==::Y19jbnRfYnlwYXNzX2VuMg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMg==::ZmFsc2U=::Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaGlfZGl2Mw==::MQ==::Y19jbnRfaGlfZGl2Mw==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfbG9fZGl2Mw==::MQ==::Y19jbnRfbG9fZGl2Mw==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcHJzdDM=::MQ==::Y19jbnRfcHJzdDM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcGhfbXV4X3Byc3Qz::MA==::Y19jbnRfcGhfbXV4X3Byc3Qz" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaW5fc3JjMw==::cGhfbXV4X2Nsaw==::Y19jbnRfaW5fc3JjMw==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfYnlwYXNzX2VuMw==::dHJ1ZQ==::Y19jbnRfYnlwYXNzX2VuMw==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMw==::ZmFsc2U=::Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMw==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaGlfZGl2NA==::MQ==::Y19jbnRfaGlfZGl2NA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfbG9fZGl2NA==::MQ==::Y19jbnRfbG9fZGl2NA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcHJzdDQ=::MQ==::Y19jbnRfcHJzdDQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcGhfbXV4X3Byc3Q0::MA==::Y19jbnRfcGhfbXV4X3Byc3Q0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaW5fc3JjNA==::cGhfbXV4X2Nsaw==::Y19jbnRfaW5fc3JjNA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfYnlwYXNzX2VuNA==::dHJ1ZQ==::Y19jbnRfYnlwYXNzX2VuNA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfb2RkX2Rpdl9kdXR5X2VuNA==::ZmFsc2U=::Y19jbnRfb2RkX2Rpdl9kdXR5X2VuNA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaGlfZGl2NQ==::MQ==::Y19jbnRfaGlfZGl2NQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfbG9fZGl2NQ==::MQ==::Y19jbnRfbG9fZGl2NQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcHJzdDU=::MQ==::Y19jbnRfcHJzdDU=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcGhfbXV4X3Byc3Q1::MA==::Y19jbnRfcGhfbXV4X3Byc3Q1" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaW5fc3JjNQ==::cGhfbXV4X2Nsaw==::Y19jbnRfaW5fc3JjNQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfYnlwYXNzX2VuNQ==::dHJ1ZQ==::Y19jbnRfYnlwYXNzX2VuNQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfb2RkX2Rpdl9kdXR5X2VuNQ==::ZmFsc2U=::Y19jbnRfb2RkX2Rpdl9kdXR5X2VuNQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaGlfZGl2Ng==::MQ==::Y19jbnRfaGlfZGl2Ng==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfbG9fZGl2Ng==::MQ==::Y19jbnRfbG9fZGl2Ng==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcHJzdDY=::MQ==::Y19jbnRfcHJzdDY=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcGhfbXV4X3Byc3Q2::MA==::Y19jbnRfcGhfbXV4X3Byc3Q2" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaW5fc3JjNg==::cGhfbXV4X2Nsaw==::Y19jbnRfaW5fc3JjNg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfYnlwYXNzX2VuNg==::dHJ1ZQ==::Y19jbnRfYnlwYXNzX2VuNg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfb2RkX2Rpdl9kdXR5X2VuNg==::ZmFsc2U=::Y19jbnRfb2RkX2Rpdl9kdXR5X2VuNg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaGlfZGl2Nw==::MQ==::Y19jbnRfaGlfZGl2Nw==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfbG9fZGl2Nw==::MQ==::Y19jbnRfbG9fZGl2Nw==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcHJzdDc=::MQ==::Y19jbnRfcHJzdDc=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcGhfbXV4X3Byc3Q3::MA==::Y19jbnRfcGhfbXV4X3Byc3Q3" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaW5fc3JjNw==::cGhfbXV4X2Nsaw==::Y19jbnRfaW5fc3JjNw==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfYnlwYXNzX2VuNw==::dHJ1ZQ==::Y19jbnRfYnlwYXNzX2VuNw==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfb2RkX2Rpdl9kdXR5X2VuNw==::ZmFsc2U=::Y19jbnRfb2RkX2Rpdl9kdXR5X2VuNw==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaGlfZGl2OA==::MQ==::Y19jbnRfaGlfZGl2OA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfbG9fZGl2OA==::MQ==::Y19jbnRfbG9fZGl2OA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcHJzdDg=::MQ==::Y19jbnRfcHJzdDg=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcGhfbXV4X3Byc3Q4::MA==::Y19jbnRfcGhfbXV4X3Byc3Q4" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaW5fc3JjOA==::cGhfbXV4X2Nsaw==::Y19jbnRfaW5fc3JjOA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfYnlwYXNzX2VuOA==::dHJ1ZQ==::Y19jbnRfYnlwYXNzX2VuOA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfb2RkX2Rpdl9kdXR5X2VuOA==::ZmFsc2U=::Y19jbnRfb2RkX2Rpdl9kdXR5X2VuOA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaGlfZGl2OQ==::MQ==::Y19jbnRfaGlfZGl2OQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfbG9fZGl2OQ==::MQ==::Y19jbnRfbG9fZGl2OQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcHJzdDk=::MQ==::Y19jbnRfcHJzdDk=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcGhfbXV4X3Byc3Q5::MA==::Y19jbnRfcGhfbXV4X3Byc3Q5" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaW5fc3JjOQ==::cGhfbXV4X2Nsaw==::Y19jbnRfaW5fc3JjOQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfYnlwYXNzX2VuOQ==::dHJ1ZQ==::Y19jbnRfYnlwYXNzX2VuOQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfb2RkX2Rpdl9kdXR5X2VuOQ==::ZmFsc2U=::Y19jbnRfb2RkX2Rpdl9kdXR5X2VuOQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaGlfZGl2MTA=::MQ==::Y19jbnRfaGlfZGl2MTA=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfbG9fZGl2MTA=::MQ==::Y19jbnRfbG9fZGl2MTA=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcHJzdDEw::MQ==::Y19jbnRfcHJzdDEw" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcGhfbXV4X3Byc3QxMA==::MA==::Y19jbnRfcGhfbXV4X3Byc3QxMA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaW5fc3JjMTA=::cGhfbXV4X2Nsaw==::Y19jbnRfaW5fc3JjMTA=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfYnlwYXNzX2VuMTA=::dHJ1ZQ==::Y19jbnRfYnlwYXNzX2VuMTA=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMTA=::ZmFsc2U=::Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMTA=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaGlfZGl2MTE=::MQ==::Y19jbnRfaGlfZGl2MTE=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfbG9fZGl2MTE=::MQ==::Y19jbnRfbG9fZGl2MTE=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcHJzdDEx::MQ==::Y19jbnRfcHJzdDEx" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcGhfbXV4X3Byc3QxMQ==::MA==::Y19jbnRfcGhfbXV4X3Byc3QxMQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaW5fc3JjMTE=::cGhfbXV4X2Nsaw==::Y19jbnRfaW5fc3JjMTE=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfYnlwYXNzX2VuMTE=::dHJ1ZQ==::Y19jbnRfYnlwYXNzX2VuMTE=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMTE=::ZmFsc2U=::Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMTE=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaGlfZGl2MTI=::MQ==::Y19jbnRfaGlfZGl2MTI=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfbG9fZGl2MTI=::MQ==::Y19jbnRfbG9fZGl2MTI=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcHJzdDEy::MQ==::Y19jbnRfcHJzdDEy" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcGhfbXV4X3Byc3QxMg==::MA==::Y19jbnRfcGhfbXV4X3Byc3QxMg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaW5fc3JjMTI=::cGhfbXV4X2Nsaw==::Y19jbnRfaW5fc3JjMTI=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfYnlwYXNzX2VuMTI=::dHJ1ZQ==::Y19jbnRfYnlwYXNzX2VuMTI=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMTI=::ZmFsc2U=::Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMTI=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaGlfZGl2MTM=::MQ==::Y19jbnRfaGlfZGl2MTM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfbG9fZGl2MTM=::MQ==::Y19jbnRfbG9fZGl2MTM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcHJzdDEz::MQ==::Y19jbnRfcHJzdDEz" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcGhfbXV4X3Byc3QxMw==::MA==::Y19jbnRfcGhfbXV4X3Byc3QxMw==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaW5fc3JjMTM=::cGhfbXV4X2Nsaw==::Y19jbnRfaW5fc3JjMTM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfYnlwYXNzX2VuMTM=::dHJ1ZQ==::Y19jbnRfYnlwYXNzX2VuMTM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMTM=::ZmFsc2U=::Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMTM=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaGlfZGl2MTQ=::MQ==::Y19jbnRfaGlfZGl2MTQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfbG9fZGl2MTQ=::MQ==::Y19jbnRfbG9fZGl2MTQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcHJzdDE0::MQ==::Y19jbnRfcHJzdDE0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcGhfbXV4X3Byc3QxNA==::MA==::Y19jbnRfcGhfbXV4X3Byc3QxNA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaW5fc3JjMTQ=::cGhfbXV4X2Nsaw==::Y19jbnRfaW5fc3JjMTQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfYnlwYXNzX2VuMTQ=::dHJ1ZQ==::Y19jbnRfYnlwYXNzX2VuMTQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMTQ=::ZmFsc2U=::Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMTQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaGlfZGl2MTU=::MQ==::Y19jbnRfaGlfZGl2MTU=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfbG9fZGl2MTU=::MQ==::Y19jbnRfbG9fZGl2MTU=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcHJzdDE1::MQ==::Y19jbnRfcHJzdDE1" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcGhfbXV4X3Byc3QxNQ==::MA==::Y19jbnRfcGhfbXV4X3Byc3QxNQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaW5fc3JjMTU=::cGhfbXV4X2Nsaw==::Y19jbnRfaW5fc3JjMTU=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfYnlwYXNzX2VuMTU=::dHJ1ZQ==::Y19jbnRfYnlwYXNzX2VuMTU=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMTU=::ZmFsc2U=::Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMTU=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaGlfZGl2MTY=::MQ==::Y19jbnRfaGlfZGl2MTY=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfbG9fZGl2MTY=::MQ==::Y19jbnRfbG9fZGl2MTY=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcHJzdDE2::MQ==::Y19jbnRfcHJzdDE2" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcGhfbXV4X3Byc3QxNg==::MA==::Y19jbnRfcGhfbXV4X3Byc3QxNg==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaW5fc3JjMTY=::cGhfbXV4X2Nsaw==::Y19jbnRfaW5fc3JjMTY=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfYnlwYXNzX2VuMTY=::dHJ1ZQ==::Y19jbnRfYnlwYXNzX2VuMTY=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMTY=::ZmFsc2U=::Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMTY=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaGlfZGl2MTc=::MQ==::Y19jbnRfaGlfZGl2MTc=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfbG9fZGl2MTc=::MQ==::Y19jbnRfbG9fZGl2MTc=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcHJzdDE3::MQ==::Y19jbnRfcHJzdDE3" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfcGhfbXV4X3Byc3QxNw==::MA==::Y19jbnRfcGhfbXV4X3Byc3QxNw==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfaW5fc3JjMTc=::cGhfbXV4X2Nsaw==::Y19jbnRfaW5fc3JjMTc=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfYnlwYXNzX2VuMTc=::dHJ1ZQ==::Y19jbnRfYnlwYXNzX2VuMTc=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMTc=::ZmFsc2U=::Y19jbnRfb2RkX2Rpdl9kdXR5X2VuMTc=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGxsX3Zjb19kaXY=::Mg==::cGxsX3Zjb19kaXY=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGxsX2NwX2N1cnJlbnQ=::MjA=::cGxsX2NwX2N1cnJlbnQ=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGxsX2J3Y3RybA==::NDAwMA==::cGxsX2J3Y3RybA==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGxsX291dHB1dF9jbGtfZnJlcXVlbmN5::NDQ1LjQ5OTk5OSBNSHo=::cGxsX291dHB1dF9jbGtfZnJlcXVlbmN5" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGxsX2ZyYWN0aW9uYWxfZGl2aXNpb24=::MzkwODQyMDE1Mw==::cGxsX2ZyYWN0aW9uYWxfZGl2aXNpb24=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "bWltaWNfZmJjbGtfdHlwZQ==::bm9uZQ==::bWltaWNfZmJjbGtfdHlwZQ==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGxsX2ZiY2xrX211eF8x::Z2xi::cGxsX2ZiY2xrX211eF8x" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGxsX2ZiY2xrX211eF8y::bV9jbnQ=::cGxsX2ZiY2xrX211eF8y" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGxsX21fY250X2luX3NyYw==::cGhfbXV4X2Nsaw==::cGxsX21fY250X2luX3NyYw==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "cGxsX3NsZl9yc3Q=::dHJ1ZQ==::cGxsX3NsZl9yc3Q=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BhcmFtZXRlcl9saXN0::TS1Db3VudGVyIEhpIERpdmlkZSxNLUNvdW50ZXIgTG93IERpdmlkZSxOLUNvdW50ZXIgSGkgRGl2aWRlLE4tQ291bnRlciBMb3cgRGl2aWRlLE0tQ291bnRlciBCeXBhc3MgRW5hYmxlLE4tQ291bnRlciBCeXBhc3MgRW5hYmxlLE0tQ291bnRlciBPZGQgRGl2aWRlIEVuYWJsZSxOLUNvdW50ZXIgT2RkIERpdmlkZSBFbmFibGUsQy1Db3VudGVyLTAgSGkgRGl2aWRlLEMtQ291bnRlci0wIExvdyBEaXZpZGUsQy1Db3VudGVyLTAgQ29hcnNlIFBoYXNlIFNoaWZ0LEMtQ291bnRlci0wIFZDTyBQaGFzZSBUYXAsQy1Db3VudGVyLTAgSW5wdXQgU291cmNlLEMtQ291bnRlci0wIEJ5cGFzcyBFbmFibGUsQy1Db3VudGVyLTAgT2RkIERpdmlkZSBFbmFibGUsVkNPIFBvc3QgRGl2aWRlIENvdW50ZXIgRW5hYmxlLENoYXJnZSBQdW1wIGN1cnJlbnQgKHVBKSxMb29wIEZpbHRlciBCYW5kd2lkdGggUmVzaXN0b3IgKE9obXMpICxQTEwgT3V0cHV0IFZDTyBGcmVxdWVuY3ksSy1GcmFjdGlvbmFsIERpdmlzaW9uIFZhbHVlIChEU00pLEZlZWRiYWNrIENsb2NrIFR5cGUsRmVlZGJhY2sgQ2xvY2sgTVVYIDEsRmVlZGJhY2sgQ2xvY2sgTVVYIDIsTSBDb3VudGVyIFNvdXJjZSBNVVgsUExMIEF1dG8gUmVzZXQ=::UGFyYW1ldGVyIE5hbWVz" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3BhcmFtZXRlcl92YWx1ZXM=::NCw0LDI1NiwyNTYsZmFsc2UsdHJ1ZSxmYWxzZSxmYWxzZSwyLDEsMSwwLHBoX211eF9jbGssZmFsc2UsdHJ1ZSwyLDIwLDQwMDAsNDQ1LjQ5OTk5OSBNSHosMzkwODQyMDE1Myxub25lLGdsYixtX2NudCxwaF9tdXhfY2xrLHRydWU=::UGFyYW1ldGVyIFZhbHVlcw==" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX21pZl9nZW5lcmF0ZQ==::ZmFsc2U=::R2VuZXJhdGUgTUlGIGZpbGU=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9taWZfZHBz::ZmFsc2U=::RW5hYmxlIER5bmFtaWMgUGhhc2UgU2hpZnQgZm9yIE1JRiBzdHJlYW1pbmc=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Rwc19jbnRy::QzA=::RFBTIENvdW50ZXIgU2VsZWN0aW9u" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Rwc19udW0=::MQ==::TnVtYmVyIG9mIER5bmFtaWMgUGhhc2UgU2hpZnRz" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2Rwc19kaXI=::UG9zaXRpdmU=::RHluYW1pYyBQaGFzZSBTaGlmdCBEaXJlY3Rpb24=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX3JlZmNsa19zd2l0Y2g=::ZmFsc2U=::Q3JlYXRlIGEgc2Vjb25kIGlucHV0IGNsayAncmVmY2xrMSc=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9jYXNjYWRlX291dA==::ZmFsc2U=::Q3JlYXRlIGEgJ2Nhc2NhZGVfb3V0JyBzaWduYWwgdG8gY29ubmVjdCB3aXRoIGEgZG93bnN0cmVhbSBQTEw=" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9jYXNjYWRlX2lu::ZmFsc2U=::Q3JlYXRlIGFuIGFkanBsbGluIG9yIGNjbGsgc2lnbmFsIHRvIGNvbm5lY3Qgd2l0aCBhbiB1cHN0cmVhbSBQTEw=" + +set_global_assignment -library "pll_hdmi" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_hdmi.v"] +set_global_assignment -library "pll_hdmi" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_hdmi/pll_hdmi_0002.v"] +set_global_assignment -library "pll_hdmi" -name QIP_FILE [file join $::quartus(qip_path) "pll_hdmi/pll_hdmi_0002.qip"] + +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_TOOL_NAME "altera_pll" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_TOOL_VERSION "17.0" +set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_TOOL_ENV "mwpim" diff --git a/sys/pll_hdmi.v b/sys/pll_hdmi.v new file mode 100644 index 0000000..0cefd25 --- /dev/null +++ b/sys/pll_hdmi.v @@ -0,0 +1,256 @@ +// megafunction wizard: %Altera PLL v17.0% +// GENERATION: XML +// pll_hdmi.v + +// Generated using ACDS version 17.0 598 + +`timescale 1 ps / 1 ps +module pll_hdmi ( + input wire refclk, // refclk.clk + input wire rst, // reset.reset + output wire outclk_0, // outclk0.clk + input wire [63:0] reconfig_to_pll, // reconfig_to_pll.reconfig_to_pll + output wire [63:0] reconfig_from_pll // reconfig_from_pll.reconfig_from_pll + ); + + pll_hdmi_0002 pll_hdmi_inst ( + .refclk (refclk), // refclk.clk + .rst (rst), // reset.reset + .outclk_0 (outclk_0), // outclk0.clk + .reconfig_to_pll (reconfig_to_pll), // reconfig_to_pll.reconfig_to_pll + .reconfig_from_pll (reconfig_from_pll), // reconfig_from_pll.reconfig_from_pll + .locked () // (terminated) + ); + +endmodule +// Retrieval info: +// +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// Retrieval info: +// IPFS_FILES : pll_hdmi.vo +// RELATED_FILES: pll_hdmi.v, pll_hdmi_0002.v diff --git a/sys/pll_hdmi/pll_hdmi_0002.qip b/sys/pll_hdmi/pll_hdmi_0002.qip new file mode 100644 index 0000000..3cb7073 --- /dev/null +++ b/sys/pll_hdmi/pll_hdmi_0002.qip @@ -0,0 +1,2 @@ +set_instance_assignment -name PLL_COMPENSATION_MODE DIRECT -to "*pll_hdmi_0002*|altera_pll:altera_pll_i*|*" +set_instance_assignment -name UNFORCE_MERGE_PLL_OUTPUT_COUNTER ON -to "*pll_hdmi_0002*|altera_pll:altera_pll_i*|*" diff --git a/sys/pll_hdmi/pll_hdmi_0002.v b/sys/pll_hdmi/pll_hdmi_0002.v new file mode 100644 index 0000000..9347c76 --- /dev/null +++ b/sys/pll_hdmi/pll_hdmi_0002.v @@ -0,0 +1,241 @@ +`timescale 1ns/10ps +module pll_hdmi_0002( + + // interface 'refclk' + input wire refclk, + + // interface 'reset' + input wire rst, + + // interface 'outclk0' + output wire outclk_0, + + // interface 'locked' + output wire locked, + + // interface 'reconfig_to_pll' + input wire [63:0] reconfig_to_pll, + + // interface 'reconfig_from_pll' + output wire [63:0] reconfig_from_pll +); + + altera_pll #( + .fractional_vco_multiplier("true"), + .reference_clock_frequency("50.0 MHz"), + .pll_fractional_cout(32), + .pll_dsm_out_sel("1st_order"), + .operation_mode("direct"), + .number_of_clocks(1), + .output_clock_frequency0("148.500000 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("Cyclone V"), + .pll_subtype("Reconfigurable"), + .m_cnt_hi_div(4), + .m_cnt_lo_div(4), + .n_cnt_hi_div(256), + .n_cnt_lo_div(256), + .m_cnt_bypass_en("false"), + .n_cnt_bypass_en("true"), + .m_cnt_odd_div_duty_en("false"), + .n_cnt_odd_div_duty_en("false"), + .c_cnt_hi_div0(2), + .c_cnt_lo_div0(1), + .c_cnt_prst0(1), + .c_cnt_ph_mux_prst0(0), + .c_cnt_in_src0("ph_mux_clk"), + .c_cnt_bypass_en0("false"), + .c_cnt_odd_div_duty_en0("true"), + .c_cnt_hi_div1(1), + .c_cnt_lo_div1(1), + .c_cnt_prst1(1), + .c_cnt_ph_mux_prst1(0), + .c_cnt_in_src1("ph_mux_clk"), + .c_cnt_bypass_en1("true"), + .c_cnt_odd_div_duty_en1("false"), + .c_cnt_hi_div2(1), + .c_cnt_lo_div2(1), + .c_cnt_prst2(1), + .c_cnt_ph_mux_prst2(0), + .c_cnt_in_src2("ph_mux_clk"), + .c_cnt_bypass_en2("true"), + .c_cnt_odd_div_duty_en2("false"), + .c_cnt_hi_div3(1), + .c_cnt_lo_div3(1), + .c_cnt_prst3(1), + .c_cnt_ph_mux_prst3(0), + .c_cnt_in_src3("ph_mux_clk"), + .c_cnt_bypass_en3("true"), + .c_cnt_odd_div_duty_en3("false"), + .c_cnt_hi_div4(1), + .c_cnt_lo_div4(1), + .c_cnt_prst4(1), + .c_cnt_ph_mux_prst4(0), + .c_cnt_in_src4("ph_mux_clk"), + .c_cnt_bypass_en4("true"), + .c_cnt_odd_div_duty_en4("false"), + .c_cnt_hi_div5(1), + .c_cnt_lo_div5(1), + .c_cnt_prst5(1), + .c_cnt_ph_mux_prst5(0), + .c_cnt_in_src5("ph_mux_clk"), + .c_cnt_bypass_en5("true"), + .c_cnt_odd_div_duty_en5("false"), + .c_cnt_hi_div6(1), + .c_cnt_lo_div6(1), + .c_cnt_prst6(1), + .c_cnt_ph_mux_prst6(0), + .c_cnt_in_src6("ph_mux_clk"), + .c_cnt_bypass_en6("true"), + .c_cnt_odd_div_duty_en6("false"), + .c_cnt_hi_div7(1), + .c_cnt_lo_div7(1), + .c_cnt_prst7(1), + .c_cnt_ph_mux_prst7(0), + .c_cnt_in_src7("ph_mux_clk"), + .c_cnt_bypass_en7("true"), + .c_cnt_odd_div_duty_en7("false"), + .c_cnt_hi_div8(1), + .c_cnt_lo_div8(1), + .c_cnt_prst8(1), + .c_cnt_ph_mux_prst8(0), + .c_cnt_in_src8("ph_mux_clk"), + .c_cnt_bypass_en8("true"), + .c_cnt_odd_div_duty_en8("false"), + .c_cnt_hi_div9(1), + .c_cnt_lo_div9(1), + .c_cnt_prst9(1), + .c_cnt_ph_mux_prst9(0), + .c_cnt_in_src9("ph_mux_clk"), + .c_cnt_bypass_en9("true"), + .c_cnt_odd_div_duty_en9("false"), + .c_cnt_hi_div10(1), + .c_cnt_lo_div10(1), + .c_cnt_prst10(1), + .c_cnt_ph_mux_prst10(0), + .c_cnt_in_src10("ph_mux_clk"), + .c_cnt_bypass_en10("true"), + .c_cnt_odd_div_duty_en10("false"), + .c_cnt_hi_div11(1), + .c_cnt_lo_div11(1), + .c_cnt_prst11(1), + .c_cnt_ph_mux_prst11(0), + .c_cnt_in_src11("ph_mux_clk"), + .c_cnt_bypass_en11("true"), + .c_cnt_odd_div_duty_en11("false"), + .c_cnt_hi_div12(1), + .c_cnt_lo_div12(1), + .c_cnt_prst12(1), + .c_cnt_ph_mux_prst12(0), + .c_cnt_in_src12("ph_mux_clk"), + .c_cnt_bypass_en12("true"), + .c_cnt_odd_div_duty_en12("false"), + .c_cnt_hi_div13(1), + .c_cnt_lo_div13(1), + .c_cnt_prst13(1), + .c_cnt_ph_mux_prst13(0), + .c_cnt_in_src13("ph_mux_clk"), + .c_cnt_bypass_en13("true"), + .c_cnt_odd_div_duty_en13("false"), + .c_cnt_hi_div14(1), + .c_cnt_lo_div14(1), + .c_cnt_prst14(1), + .c_cnt_ph_mux_prst14(0), + .c_cnt_in_src14("ph_mux_clk"), + .c_cnt_bypass_en14("true"), + .c_cnt_odd_div_duty_en14("false"), + .c_cnt_hi_div15(1), + .c_cnt_lo_div15(1), + .c_cnt_prst15(1), + .c_cnt_ph_mux_prst15(0), + .c_cnt_in_src15("ph_mux_clk"), + .c_cnt_bypass_en15("true"), + .c_cnt_odd_div_duty_en15("false"), + .c_cnt_hi_div16(1), + .c_cnt_lo_div16(1), + .c_cnt_prst16(1), + .c_cnt_ph_mux_prst16(0), + .c_cnt_in_src16("ph_mux_clk"), + .c_cnt_bypass_en16("true"), + .c_cnt_odd_div_duty_en16("false"), + .c_cnt_hi_div17(1), + .c_cnt_lo_div17(1), + .c_cnt_prst17(1), + .c_cnt_ph_mux_prst17(0), + .c_cnt_in_src17("ph_mux_clk"), + .c_cnt_bypass_en17("true"), + .c_cnt_odd_div_duty_en17("false"), + .pll_vco_div(2), + .pll_cp_current(20), + .pll_bwctrl(4000), + .pll_output_clk_frequency("445.499999 MHz"), + .pll_fractional_division("3908420153"), + .mimic_fbclk_type("none"), + .pll_fbclk_mux_1("glb"), + .pll_fbclk_mux_2("m_cnt"), + .pll_m_cnt_in_src("ph_mux_clk"), + .pll_slf_rst("true") + ) altera_pll_i ( + .rst (rst), + .outclk ({outclk_0}), + .locked (locked), + .reconfig_to_pll (reconfig_to_pll), + .fboutclk ( ), + .fbclk (1'b0), + .refclk (refclk), + .reconfig_from_pll (reconfig_from_pll) + ); +endmodule + diff --git a/sys/pll_hdmi_adj.vhd b/sys/pll_hdmi_adj.vhd new file mode 100644 index 0000000..67287cb --- /dev/null +++ b/sys/pll_hdmi_adj.vhd @@ -0,0 +1,433 @@ +-------------------------------------------------------------------------------- +-- HDMI PLL Adjust +-------------------------------------------------------------------------------- + +-- Changes the HDMI PLL frequency according to the scaler suggestions. +-------------------------------------------- +-- LLTUNE : +-- 0 : Input Display Enable +-- 1 : Input Vsync +-- 2 : Input Interlaced mode +-- 3 : Input Interlaced field +-- 4 : Output Image frame +-- 5 : +-- 6 : Input clock +-- 7 : Output clock + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY pll_hdmi_adj IS + PORT ( + -- Scaler + llena : IN std_logic; -- 0=Disabled 1=Enabled + lltune : IN unsigned(15 DOWNTO 0); -- Outputs from scaler + + locked : OUT std_logic; + + -- Signals from reconfig commands + i_waitrequest : OUT std_logic; + i_write : IN std_logic; + i_address : IN unsigned(5 DOWNTO 0); + i_writedata : IN unsigned(31 DOWNTO 0); + + -- Outputs to PLL_HDMI_CFG + o_waitrequest : IN std_logic; + o_write : OUT std_logic; + o_address : OUT unsigned(5 DOWNTO 0); + o_writedata : OUT unsigned(31 DOWNTO 0); + + ------------------------------------ + clk : IN std_logic; + reset_na : IN std_logic + ); + +BEGIN + + +END ENTITY pll_hdmi_adj; + +--############################################################################## + +ARCHITECTURE rtl OF pll_hdmi_adj IS + + SIGNAL i_clk,i_de,i_de2,i_vss,i_vss2,i_vss_delay,i_ce : std_logic; + SIGNAL i_linecpt,i_line : natural RANGE 0 TO 2**12-1; + SIGNAL i_delay : natural RANGE 0 TO 2**14-1; + + SIGNAL pwrite : std_logic; + SIGNAL paddress : unsigned(5 DOWNTO 0); + SIGNAL pdata : unsigned(31 DOWNTO 0); + TYPE enum_state IS (sIDLE,sW1,sW2,sW3,sW4,sW5,sW6); + SIGNAL state : enum_state; + SIGNAL tune_freq,tune_phase : unsigned(5 DOWNTO 0); + SIGNAL lltune_sync,lltune_sync2,lltune_sync3 : unsigned(15 DOWNTO 0); + SIGNAL mfrac,mfrac_mem,mfrac_ref,diff : unsigned(40 DOWNTO 0); + SIGNAL mul : unsigned(15 DOWNTO 0); + SIGNAL sign,sign_pre : std_logic; + SIGNAL expand : boolean; + SIGNAL up,modo,phm,dir : std_logic; + SIGNAL cpt : natural RANGE 0 TO 3; + SIGNAL col : natural RANGE 0 TO 15; + + SIGNAL icpt,ocpt,o2cpt,ssh,ofsize,ifsize : natural RANGE 0 TO 2**24-1; + SIGNAL ivss,ivss2,itog : std_logic; + SIGNAL ovss,ovss2,otog : std_logic; + SIGNAL sync,pulse,los,lop : std_logic; + SIGNAL osize,offset,osizep,offsetp : signed(23 DOWNTO 0); + SIGNAL logcpt : natural RANGE 0 TO 31; + SIGNAL udiff : integer RANGE -2**23 TO 2**23-1 :=0; + +BEGIN + + ---------------------------------------------------------------------------- + -- 4 lines delay to input + i_vss<=lltune(0); + i_de <=lltune(1); + i_ce <=lltune(5); + i_clk<=lltune(6); + + Delay:PROCESS(i_clk) IS + BEGIN + IF rising_edge(i_clk) THEN + IF i_ce='1' THEN + -- Measure input line time. + i_de2<=i_de; + + IF i_de='1' AND i_de2='0' THEN + i_linecpt<=0; + IF i_vss='1' THEN + i_line<=i_linecpt; + END IF; + ELSE + i_linecpt<=i_linecpt+1; + END IF; + + -- Delay 4 lines + i_vss2<=i_vss; + IF i_vss/=i_vss2 THEN + i_delay<=0; + ELSIF i_delay=i_line * 4 THEN + i_vss_delay<=i_vss; + ELSE + i_delay<=i_delay+1; + END IF; + END IF; + END IF; + END PROCESS Delay; + + ---------------------------------------------------------------------------- + -- Sample image sizes + Sampler:PROCESS(clk,reset_na) IS + BEGIN + IF reset_na='0' THEN +--pragma synthesis_off + otog<='0'; + itog<='0'; + ivss<='0'; + ivss2<='0'; + ovss<='0'; + ovss2<='0'; +--pragma synthesis_on + + ELSIF rising_edge(clk) THEN + -- Clock domain crossing + + ivss<=i_vss_delay; -- + ivss2<=ivss; + + ovss<=lltune(4); -- + ovss2<=ovss; + + otog<=otog XOR (ovss AND NOT ovss2); + + -- Measure output frame time + IF ovss='1' AND ovss2='0' AND otog='1' THEN + ocpt<=0; + osizep<=to_signed(ocpt,24); + ELSE + ocpt<=ocpt+1; + END IF; + IF ovss='0' AND ovss2='1' AND otog='0' THEN + o2cpt<=0; + ELSE + o2cpt<=o2cpt+1; + END IF; + + -- Measure output image time + IF ovss='0' AND ovss2='1' AND otog='0' THEN + ofsize<=ocpt; + END IF; + + itog<=itog XOR (ivss AND NOT ivss2); + + -- Measure input frame time + IF ivss='1' AND ivss2='0' AND itog='1' THEN + icpt<=0; + osize<=osizep; + udiff<=integer(to_integer(osizep)) - integer(icpt); + sync<='1'; + ELSE + icpt<=icpt+1; + sync<='0'; + END IF; + + -- Measure input image time + IF ivss='0' AND ivss2='1' AND itog='0' THEN + ifsize<=icpt; + END IF; + + expand<=(ofsize>=ifsize); + -- IN | ######### | EXPAND = 1 + -- OUT | ############# | + + -- IN | ######### | EXPAND = 0 + -- OUT | ###### | + + IF expand THEN + IF ivss='1' AND ivss2='0' AND itog='1' THEN + offset<=to_signed(ocpt,24); + END IF; + ELSE + IF ivss='0' AND ivss2='1' AND itog='0' THEN + offset<=to_signed(o2cpt,24); + END IF; + END IF; + + -------------------------------------------- + pulse<='0'; + IF sync='1' THEN + logcpt<=0; + ssh<=to_integer(osize); + los<='0'; + lop<='0'; + + ELSIF logcpt<24 THEN + -- Frequency difference + IF udiff>0 AND ssh=osize/2 AND ssh<(osize-offset) AND lop='0' THEN + tune_phase<='1' & to_unsigned(logcpt,5); + lop<='1'; + END IF; + ssh<=ssh/2; + logcpt<=logcpt+1; + + ELSIF logcpt=24 THEN + pulse<='1'; + ssh<=ssh/2; + logcpt<=logcpt+1; + END IF; + + END IF; + END PROCESS Sampler; + + ---------------------------------------------------------------------------- + -- 000010 : Start reg "Write either 0 or 1 to start fractional PLL reconf. + -- 000100 : M counter + -- 000111 : M counter Fractional Value K + + Comb:PROCESS(i_write,i_address, + i_writedata,pwrite,paddress,pdata) IS + BEGIN + IF i_write='1' THEN + o_write <=i_write; + o_address <=i_address; + o_writedata <=i_writedata; + ELSE + o_write <=pwrite; + o_address <=paddress; + o_writedata<=pdata; + END IF; + END PROCESS Comb; + + i_waitrequest<=o_waitrequest WHEN state=sIDLE ELSE '0'; + + ---------------------------------------------------------------------------- + Schmurtz:PROCESS(clk,reset_na) IS + VARIABLE off_v,ofp_v : natural RANGE 0 TO 63; + VARIABLE diff_v : unsigned(40 DOWNTO 0); + VARIABLE mulco : unsigned(15 DOWNTO 0); + VARIABLE up_v,sign_v : std_logic; + BEGIN + IF reset_na='0' THEN + modo<='0'; + state<=sIDLE; + ELSIF rising_edge(clk) THEN + ------------------------------------------------------ + -- Snoop accesses to PLL reconfiguration + IF i_address="000100" AND i_write='1' THEN + mfrac (40 DOWNTO 32)<=('0' & i_writedata(15 DOWNTO 8)) + + ('0' & i_writedata(7 DOWNTO 0)); + mfrac_ref(40 DOWNTO 32)<=('0' & i_writedata(15 DOWNTO 8)) + + ('0' & i_writedata(7 DOWNTO 0)); + mfrac_mem(40 DOWNTO 32)<=('0' & i_writedata(15 DOWNTO 8)) + + ('0' & i_writedata(7 DOWNTO 0)); + mul<=i_writedata(15 DOWNTO 0); + modo<='1'; + END IF; + + IF i_address="000111" AND i_write='1' THEN + mfrac (31 DOWNTO 0)<=i_writedata; + mfrac_ref(31 DOWNTO 0)<=i_writedata; + mfrac_mem(31 DOWNTO 0)<=i_writedata; + modo<='1'; + END IF; + + ------------------------------------------------------ + -- Tuning + off_v:=to_integer('0' & tune_freq(4 DOWNTO 0)); + ofp_v:=to_integer('0' & tune_phase(4 DOWNTO 0)); + --IF off_v<8 THEN off_v:=8; END IF; + --IF ofp_v<7 THEN ofp_v:=7; END IF; + IF off_v<4 THEN off_v:=4; END IF; + IF ofp_v<4 THEN ofp_v:=4; END IF; + + IF off_v>=18 AND ofp_v>=18 THEN + locked<=llena; + ELSE + locked<='0'; + END IF; + + up_v:='0'; + IF pulse='1' THEN + cpt<=(cpt+1) MOD 4; + IF llena='0' THEN + -- Recover original freq when disabling low lag mode + cpt<=0; + col<=0; + IF modo='1' THEN + mfrac<=mfrac_mem; + mfrac_ref<=mfrac_mem; + up<='1'; + modo<='0'; + END IF; + + ELSIF phm='0' AND cpt=0 THEN + -- Frequency adjust + sign_v:=tune_freq(5); + IF col<10 THEN col<=col+1; END IF; + IF off_v>=16 AND col>=10 THEN + phm<='1'; + col<=0; + ELSE + off_v:=off_v+1; + IF off_v>17 THEN + off_v:=off_v + 3; + END IF; + up_v:='1'; + up<='1'; + END IF; + + ELSIF cpt=0 THEN + -- Phase adjust + sign_v:=NOT tune_phase(5); + col<=col+1; + IF col>=10 THEN + phm<='0'; + up_v:='1'; + off_v:=31; + col<=0; + ELSE + off_v:=ofp_v + 1; + IF ofp_v>7 THEN + off_v:=off_v + 1; + END IF; + IF ofp_v>14 THEN + off_v:=off_v + 2; + END IF; + IF ofp_v>17 THEN + off_v:=off_v + 3; + END IF; + up_v:='1'; + END IF; + up<='1'; + END IF; + END IF; + + diff_v:=shift_right(mfrac_ref,off_v); + IF sign_v='0' THEN + diff_v:=mfrac_ref + diff_v; + ELSE + diff_v:=mfrac_ref - diff_v; + END IF; + + IF up_v='1' THEN + mfrac<=diff_v; + END IF; + + IF up_v='1' AND phm='0' THEN + mfrac_ref<=diff_v; + END IF; + + ------------------------------------------------------ + -- Update PLL registers + mulco:=mfrac(40 DOWNTO 33) & (mfrac(40 DOWNTO 33) + ('0' & mfrac(32))); + + CASE state IS + WHEN sIDLE => + pwrite<='0'; + IF up='1' THEN + up<='0'; + IF mulco/=mul THEN + state<=sW1; + ELSE + state<=sW3; + END IF; + END IF; + + WHEN sW1 => -- Change M multiplier + mul<=mulco; + pdata<=x"0000" & mulco; + paddress<="000100"; + pwrite<='1'; + state<=sW2; + + WHEN sW2 => + IF pwrite='1' AND o_waitrequest='0' THEN + state<=sW3; + pwrite<='0'; + END IF; + + WHEN sW3 => -- Change M fractional value + pdata<=mfrac(31 DOWNTO 0); + paddress<="000111"; + pwrite<='1'; + state<=sW4; + + WHEN sW4 => + IF pwrite='1' AND o_waitrequest='0' THEN + state<=sW5; + pwrite<='0'; + END IF; + + WHEN sW5 => + pdata<=x"0000_0001"; + paddress<="000010"; + pwrite<='1'; + state<=sW6; + + WHEN sW6 => + IF pwrite='1' AND o_waitrequest='0' THEN + pwrite<='0'; + state<=sIDLE; + END IF; + END CASE; + + END IF; + END PROCESS Schmurtz; + + ---------------------------------------------------------------------------- + +END ARCHITECTURE rtl; + diff --git a/sys/pll_q13.qip b/sys/pll_q13.qip new file mode 100644 index 0000000..13a7ed4 --- /dev/null +++ b/sys/pll_q13.qip @@ -0,0 +1,6 @@ +set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll.13.qip ] +set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll_hdmi.13.qip ] +set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll_audio.13.qip ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) pll_cfg.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) pll_cfg/altera_pll_reconfig_core.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) pll_cfg/altera_pll_reconfig_top.v ] diff --git a/sys/pll_q17.qip b/sys/pll_q17.qip new file mode 100644 index 0000000..85cc84b --- /dev/null +++ b/sys/pll_q17.qip @@ -0,0 +1,4 @@ +set_global_assignment -name QIP_FILE rtl/pll.qip +set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll_hdmi.qip ] +set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll_audio.qip ] +set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll_cfg.qip ] diff --git a/sys/scandoubler.v b/sys/scandoubler.v new file mode 100644 index 0000000..81e7c3f --- /dev/null +++ b/sys/scandoubler.v @@ -0,0 +1,211 @@ +// +// scandoubler.v +// +// Copyright (c) 2015 Till Harbaum +// Copyright (c) 2017-2021 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 . + +// TODO: Delay vsync one line + +module scandoubler #(parameter LENGTH, parameter HALF_DEPTH) +( + // system interface + input clk_vid, + input hq2x, + + // shifter video interface + input ce_pix, + input hs_in, + input vs_in, + input hb_in, + input vb_in, + input [DWIDTH:0] r_in, + input [DWIDTH:0] g_in, + input [DWIDTH:0] b_in, + + // output interface + output ce_pix_out, + output reg hs_out, + output vs_out, + output hb_out, + output vb_out, + output [DWIDTH:0] r_out, + output [DWIDTH:0] g_out, + output [DWIDTH:0] b_out +); + +localparam DWIDTH = HALF_DEPTH ? 3 : 7; + +reg [7:0] pix_len = 0; +wire [7:0] pl = pix_len + 1'b1; + +reg [7:0] pix_in_cnt = 0; +wire [7:0] pc_in = pix_in_cnt + 1'b1; +reg [7:0] pixsz, pixsz2, pixsz4 = 0; + +reg ce_x4i, ce_x1i; +always @(posedge clk_vid) begin + reg old_ce, valid, hs; + + if(~&pix_len) pix_len <= pl; + if(~&pix_in_cnt) pix_in_cnt <= pc_in; + + ce_x4i <= 0; + ce_x1i <= 0; + + // use such odd comparison to place ce_x4 evenly if master clock isn't multiple of 4. + if((pc_in == pixsz4) || (pc_in == pixsz2) || (pc_in == (pixsz2+pixsz4))) ce_x4i <= 1; + + old_ce <= ce_pix; + if(~old_ce & ce_pix) begin + if(valid & ~hb_in & ~vb_in) begin + pixsz <= pl; + pixsz2 <= {1'b0, pl[7:1]}; + pixsz4 <= {2'b00, pl[7:2]}; + end + pix_len <= 0; + valid <= 1; + end + + hs <= hs_in; + if((~hs & hs_in) || (pc_in >= pixsz)) begin + ce_x4i <= 1; + ce_x1i <= 1; + pix_in_cnt <= 0; + end + + if(hb_in | vb_in) valid <= 0; +end + +reg req_line_reset; +reg [DWIDTH:0] r_d, g_d, b_d; +always @(posedge clk_vid) begin + if(ce_x1i) begin + req_line_reset <= hb_in; + r_d <= r_in; + g_d <= g_in; + b_d <= b_in; + end +end + +Hq2x #(.LENGTH(LENGTH), .HALF_DEPTH(HALF_DEPTH)) Hq2x +( + .clk(clk_vid), + + .ce_in(ce_x4i), + .inputpixel({b_d,g_d,r_d}), + .disable_hq2x(~hq2x), + .reset_frame(vb_in), + .reset_line(req_line_reset), + + .ce_out(ce_x4o), + .read_y(sd_line), + .hblank(hbo[0]&hbo[8]), + .outpixel({b_out,g_out,r_out}) +); + +reg [7:0] pix_out_cnt = 0; +wire [7:0] pc_out = pix_out_cnt + 1'b1; + +reg ce_x4o, ce_x2o; +always @(posedge clk_vid) begin + reg hs; + + if(~&pix_out_cnt) pix_out_cnt <= pc_out; + + ce_x4o <= 0; + ce_x2o <= 0; + + // use such odd comparison to place ce_x4 evenly if master clock isn't multiple of 4. + if((pc_out == pixsz4) || (pc_out == pixsz2) || (pc_out == (pixsz2+pixsz4))) ce_x4o <= 1; + if( pc_out == pixsz2) ce_x2o <= 1; + + hs <= hs_out; + if((~hs & hs_out) || (pc_out >= pixsz)) begin + ce_x2o <= 1; + ce_x4o <= 1; + pix_out_cnt <= 0; + end +end + +reg [1:0] sd_line; +reg [3:0] vbo; +reg [3:0] vso; +reg [8:0] hbo; +always @(posedge clk_vid) begin + + reg [31:0] hcnt; + reg [30:0] sd_hcnt; + reg [30:0] hs_start, hs_end; + reg [30:0] hde_start, hde_end; + + reg hs, hb; + + if(ce_x4o) begin + hbo[8:1] <= hbo[7:0]; + end + + // output counter synchronous to input and at twice the rate + sd_hcnt <= sd_hcnt + 1'd1; + if(sd_hcnt == hde_start) begin + sd_hcnt <= 0; + vbo[3:1] <= vbo[2:0]; + end + + if(sd_hcnt == hs_end) begin + sd_line <= sd_line + 1'd1; + if(&vbo[3:2]) sd_line <= 1; + vso[3:1] <= vso[2:0]; + end + + if(sd_hcnt == hde_start)hbo[0] <= 0; + if(sd_hcnt == hde_end) hbo[0] <= 1; + + // replicate horizontal sync at twice the speed + if(sd_hcnt == hs_end) hs_out <= 0; + if(sd_hcnt == hs_start) hs_out <= 1; + + hs <= hs_in; + hb <= hb_in; + + hcnt <= hcnt + 1'd1; + if(hb && !hb_in) begin + hde_start <= hcnt[31:1]; + hbo[0] <= 0; + hcnt <= 0; + sd_hcnt <= 0; + vbo <= {vbo[2:0],vb_in}; + end + + if(!hb && hb_in) hde_end <= hcnt[31:1]; + + // falling edge of hsync indicates start of line + if(hs && !hs_in) begin + hs_end <= hcnt[31:1]; + vso[0] <= vs_in; + end + + // save position of rising edge + if(!hs && hs_in) hs_start <= hcnt[31:1]; +end + +assign vs_out = vso[3]; +assign ce_pix_out = hq2x ? ce_x4o : ce_x2o; + +//Compensate picture shift after HQ2x +assign vb_out = vbo[3]; +assign hb_out = hbo[6]; + +endmodule diff --git a/sys/scanlines.v b/sys/scanlines.v new file mode 100644 index 0000000..59d29bd --- /dev/null +++ b/sys/scanlines.v @@ -0,0 +1,67 @@ +module scanlines #(parameter v2=0) +( + input clk, + + input [1:0] scanlines, + input [23:0] din, + input hs_in,vs_in, + input de_in, + + output reg [23:0] dout, + output reg hs_out,vs_out, + output reg de_out +); + +reg [1:0] scanline; +always @(posedge clk) begin + reg old_hs, old_vs; + + old_hs <= hs_in; + old_vs <= vs_in; + + if(old_hs && ~hs_in) begin + if(v2) begin + scanline <= scanline + 1'd1; + if (scanline == scanlines) scanline <= 0; + end + else scanline <= scanline ^ scanlines; + end + if(old_vs && ~vs_in) scanline <= 0; +end + +wire [7:0] r,g,b; +assign {r,g,b} = din; + +reg [23:0] d; +always @(*) begin + case(scanline) + 1: // reduce 25% = 1/2 + 1/4 + d = {{1'b0, r[7:1]} + {2'b00, r[7:2]}, + {1'b0, g[7:1]} + {2'b00, g[7:2]}, + {1'b0, b[7:1]} + {2'b00, b[7:2]}}; + + 2: // reduce 50% = 1/2 + d = {{1'b0, r[7:1]}, + {1'b0, g[7:1]}, + {1'b0, b[7:1]}}; + + 3: // reduce 75% = 1/4 + d = {{2'b00, r[7:2]}, + {2'b00, g[7:2]}, + {2'b00, b[7:2]}}; + + default: d = {r,g,b}; + endcase +end + +always @(posedge clk) begin + reg [23:0] dout1, dout2; + reg de1,de2,vs1,vs2,hs1,hs2; + + dout <= dout2; dout2 <= dout1; dout1 <= d; + vs_out <= vs2; vs2 <= vs1; vs1 <= vs_in; + hs_out <= hs2; hs2 <= hs1; hs1 <= hs_in; + de_out <= de2; de2 <= de1; de1 <= de_in; +end + +endmodule diff --git a/sys/sd_card.sv b/sys/sd_card.sv new file mode 100644 index 0000000..a2aad7e --- /dev/null +++ b/sys/sd_card.sv @@ -0,0 +1,537 @@ +// +// sd_card.v +// +// Copyright (c) 2014 Till Harbaum +// Copyright (c) 2015-2018 Sorgelig +// +// This source file is free software: you can redistribute it and/or modify +// it under the terms of the Lesser 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://elm-chan.org/docs/mmc/mmc_e.html +// +///////////////////////////////////////////////////////////////////////// + +// +// Made module syncrhronous. Total code refactoring. (Sorgelig) +// clk_spi must be at least 4 x sck for proper work. + +module sd_card #(parameter WIDE = 0) +( + input clk_sys, + input reset, + + input sdhc, + + output [31:0] sd_lba, + output reg sd_rd, + output reg sd_wr, + input sd_ack, + input sd_ack_conf, + + input [AW:0] sd_buff_addr, + input [DW:0] sd_buff_dout, + output [DW:0] sd_buff_din, + input sd_buff_wr, + + // SPI interface + input clk_spi, + + input ss, + input sck, + input mosi, + output reg miso +); + +localparam AW = WIDE ? 7 : 8; +localparam DW = WIDE ? 15 : 7; + +assign sd_lba = sdhc ? lba : {9'd0, lba[31:9]}; + +wire[31:0] OCR = { 1'b1, sdhc, 30'd0 }; // bit30 = 1 -> high capaciry card (sdhc) // bit31 = 0 -> card power up finished +wire [7:0] READ_DATA_TOKEN = 8'hfe; +wire [7:0] WRITE_DATA_RESPONSE = 8'h05; + +// number of bytes to wait after a command before sending the reply +localparam NCR=3; + +localparam RD_STATE_IDLE = 0; +localparam RD_STATE_WAIT_IO = 1; +localparam RD_STATE_SEND_TOKEN = 2; +localparam RD_STATE_SEND_DATA = 3; +localparam RD_STATE_WAIT_M = 4; + +localparam WR_STATE_IDLE = 0; +localparam WR_STATE_EXP_DTOKEN = 1; +localparam WR_STATE_RECV_DATA = 2; +localparam WR_STATE_RECV_CRC0 = 3; +localparam WR_STATE_RECV_CRC1 = 4; +localparam WR_STATE_SEND_DRESP = 5; +localparam WR_STATE_BUSY = 6; + +sdbuf #(WIDE) buffer +( + .clock_a(clk_sys), + .address_a(sd_buff_addr), + .data_a(sd_buff_dout), + .wren_a(sd_ack & sd_buff_wr), + .q_a(sd_buff_din), + + .clock_b(clk_spi), + .address_b(buffer_ptr), + .data_b(buffer_din), + .wren_b(buffer_wr), + .q_b(buffer_dout) +); + +sdbuf #(WIDE) conf +( + .clock_a(clk_sys), + .address_a(sd_buff_addr), + .data_a(sd_buff_dout), + .wren_a(sd_ack_conf & sd_buff_wr), + + .clock_b(clk_spi), + .address_b(buffer_ptr), + .q_b(config_dout) +); + +reg [31:0] lba, new_lba; +reg [8:0] buffer_ptr; +reg [7:0] buffer_din; +wire [7:0] buffer_dout; +wire [7:0] config_dout; +reg buffer_wr; + +always @(posedge clk_spi) begin + reg [2:0] read_state; + reg [2:0] write_state; + reg [6:0] sbuf; + reg cmd55; + reg [7:0] cmd; + reg [2:0] bit_cnt; + reg [3:0] byte_cnt; + reg [7:0] reply; + reg [7:0] reply0, reply1, reply2, reply3; + reg [3:0] reply_len; + reg tx_finish; + reg rx_finish; + reg old_sck; + reg synced; + reg [5:0] ack; + reg io_ack; + reg [4:0] idle_cnt = 0; + reg [2:0] wait_m_cnt; + + if(buffer_wr & ~&buffer_ptr) buffer_ptr <= buffer_ptr + 1'd1; + buffer_wr <= 0; + + ack <= {ack[4:0], sd_ack}; + if(ack[5:4] == 2'b10) io_ack <= 1; + if(ack[5:4] == 2'b01) {sd_rd,sd_wr} <= 0; + + old_sck <= sck; + + if(~ss) idle_cnt <= 31; + else if(~old_sck && sck && idle_cnt) idle_cnt <= idle_cnt - 1'd1; + + if(reset || !idle_cnt) begin + bit_cnt <= 0; + byte_cnt <= 15; + synced <= 0; + miso <= 1; + sbuf <= 7'b1111111; + tx_finish <= 0; + rx_finish <= 0; + read_state <= RD_STATE_IDLE; + write_state <= WR_STATE_IDLE; + end + + if(old_sck & ~sck & ~ss) begin + tx_finish <= 0; + miso <= 1; // default: send 1's (busy/wait) + + if(byte_cnt == 5+NCR) begin + miso <= reply[~bit_cnt]; + + if(bit_cnt == 7) begin + // these three commands all have a reply_len of 0 and will thus + // not send more than a single reply byte + + // CMD9: SEND_CSD + // CMD10: SEND_CID + if((cmd == 'h49) | (cmd == 'h4a)) + read_state <= RD_STATE_SEND_TOKEN; // jump directly to data transmission + + // CMD17/CMD18 + if((cmd == 'h51) | (cmd == 'h52)) begin + io_ack <= 0; + read_state <= RD_STATE_WAIT_IO; // start waiting for data from io controller + lba <= new_lba; + sd_rd <= 1; // trigger request to io controller + end + end + end + else if((reply_len > 0) && (byte_cnt == 5+NCR+1)) miso <= reply0[~bit_cnt]; + else if((reply_len > 1) && (byte_cnt == 5+NCR+2)) miso <= reply1[~bit_cnt]; + else if((reply_len > 2) && (byte_cnt == 5+NCR+3)) miso <= reply2[~bit_cnt]; + else if((reply_len > 3) && (byte_cnt == 5+NCR+4)) miso <= reply3[~bit_cnt]; + else begin + if(byte_cnt > 5+NCR && read_state==RD_STATE_IDLE && write_state==WR_STATE_IDLE) tx_finish <= 1; + end + + // ---------- read state machine processing ------------- + + case(read_state) + RD_STATE_IDLE: ; // do nothing + + + // waiting for io controller to return data + RD_STATE_WAIT_IO: begin + if(io_ack & (bit_cnt == 7)) read_state <= RD_STATE_SEND_TOKEN; + end + + // send data token + RD_STATE_SEND_TOKEN: begin + miso <= READ_DATA_TOKEN[~bit_cnt]; + + if(bit_cnt == 7) begin + read_state <= RD_STATE_SEND_DATA; // next: send data + buffer_ptr <= 0; + if(cmd == 'h49) buffer_ptr <= 16; + end + end + + // send data + RD_STATE_SEND_DATA: begin + + miso <= ((cmd == 'h49) | (cmd == 'h4A)) ? config_dout[~bit_cnt] : buffer_dout[~bit_cnt]; + + if(bit_cnt == 7) begin + + // sent 512 sector data bytes? + if((cmd == 'h51) & &buffer_ptr) read_state <= RD_STATE_IDLE; + else if((cmd == 'h52) & &buffer_ptr) begin + read_state <= RD_STATE_WAIT_M; + wait_m_cnt <= 0; + end + + // sent 16 cid/csd data bytes? + else if(((cmd == 'h49) | (cmd == 'h4a)) & (&buffer_ptr[3:0])) read_state <= RD_STATE_IDLE; + + // not done yet -> trigger read of next data byte + else buffer_ptr <= buffer_ptr + 1'd1; + end + end + + RD_STATE_WAIT_M: begin + if(bit_cnt == 7) begin + wait_m_cnt <= wait_m_cnt + 1'd1; + if(&wait_m_cnt) begin + lba <= lba + 1; + io_ack <= 0; + sd_rd <= 1; + read_state <= RD_STATE_WAIT_IO; + end + end + end + endcase + + // ------------------ write support ---------------------- + // send write data response + if(write_state == WR_STATE_SEND_DRESP) miso <= WRITE_DATA_RESPONSE[~bit_cnt]; + + // busy after write until the io controller sends ack + if(write_state == WR_STATE_BUSY) miso <= 0; + end + + if(~old_sck & sck & ~ss) begin + + if(synced) bit_cnt <= bit_cnt + 1'd1; + + // assemble byte + if(bit_cnt != 7) begin + sbuf[6:0] <= { sbuf[5:0], mosi }; + + // resync while waiting for token + if(write_state==WR_STATE_EXP_DTOKEN) begin + if(cmd == 'h58) begin + if({sbuf,mosi} == 8'hfe) begin + write_state <= WR_STATE_RECV_DATA; + buffer_ptr <= 0; + bit_cnt <= 0; + end + end + else begin + if({sbuf,mosi} == 8'hfc) begin + write_state <= WR_STATE_RECV_DATA; + buffer_ptr <= 0; + bit_cnt <= 0; + end + if({sbuf,mosi} == 8'hfd) begin + write_state <= WR_STATE_IDLE; + rx_finish <= 1; + bit_cnt <= 0; + end + end + end + end + else begin + // finished reading one byte + // byte counter runs against 15 byte boundary + if(byte_cnt != 15) byte_cnt <= byte_cnt + 1'd1; + + // byte_cnt > 6 -> complete command received + // first byte of valid command is 01xxxxxx + // don't accept new commands once a write or read command has been accepted + if((byte_cnt > 5) & (write_state == WR_STATE_IDLE) & (read_state == RD_STATE_IDLE) && !rx_finish) begin + byte_cnt <= 0; + cmd <= { sbuf, mosi}; + + // set cmd55 flag if previous command was 55 + cmd55 <= (cmd == 'h77); + end + + if((byte_cnt > 5) & (read_state == RD_STATE_WAIT_M) && ({sbuf, mosi} == 8'h4c)) begin + byte_cnt <= 0; + rx_finish <= 0; + cmd <= {sbuf, mosi}; + read_state <= RD_STATE_IDLE; + end + + // parse additional command bytes + if(byte_cnt == 0) new_lba[31:24] <= { sbuf, mosi}; + if(byte_cnt == 1) new_lba[23:16] <= { sbuf, mosi}; + if(byte_cnt == 2) new_lba[15:8] <= { sbuf, mosi}; + if(byte_cnt == 3) new_lba[7:0] <= { sbuf, mosi}; + + // last byte (crc) received, evaluate + if(byte_cnt == 4) begin + + // default: + reply <= 4; // illegal command + reply_len <= 0; // no extra reply bytes + rx_finish <= 1; + + case(cmd) + // CMD0: GO_IDLE_STATE + 'h40: reply <= 1; // ok, busy + + // CMD1: SEND_OP_COND + 'h41: reply <= 0; // ok, not busy + + // CMD8: SEND_IF_COND (V2 only) + 'h48: begin + reply <= 1; // ok, busy + + reply0 <= 'h00; + reply1 <= 'h00; + reply2 <= 'h01; + reply3 <= 'hAA; + reply_len <= 4; + end + + // CMD9: SEND_CSD + 'h49: reply <= 0; // ok + + // CMD10: SEND_CID + 'h4a: reply <= 0; // ok + + // CMD12: STOP_TRANSMISSION + 'h4c: reply <= 0; // ok + + // CMD13: SEND_STATUS + 'h4d: begin + reply <= 'h00; // ok + reply0 <='h00; + reply_len <= 1; + end + + // CMD16: SET_BLOCKLEN + 'h50: begin + // we only support a block size of 512 + if(new_lba == 512) reply <= 0; // ok + else reply <= 'h40; // parmeter error + end + + // CMD17: READ_SINGLE_BLOCK + 'h51: reply <= 0; // ok + + // CMD18: READ_MULTIPLE + 'h52: reply <= 0; // ok + // ACMD23: SET_WR_BLK_ERASE_COUNT + 'h57: reply <= 0; //ok + + // CMD24: WRITE_BLOCK + 'h58, + // CMD25: WRITE_MULTIPLE + 'h59: begin + reply <= 0; // ok + write_state <= WR_STATE_EXP_DTOKEN; // expect data token + rx_finish <=0; + lba <= new_lba; + end + + // ACMD41: APP_SEND_OP_COND + 'h69: if(cmd55) reply <= 0; // ok, not busy + + // CMD55: APP_COND + 'h77: reply <= 1; // ok, busy + + // CMD58: READ_OCR + 'h7a: begin + reply <= 0; // ok + + reply0 <= OCR[31:24]; // bit 30 = 1 -> high capacity card + reply1 <= OCR[23:16]; + reply2 <= OCR[15:8]; + reply3 <= OCR[7:0]; + reply_len <= 4; + end + + // CMD59: CRC_ON_OFF + 'h7b: reply <= 0; // ok + endcase + end + + // ---------- handle write ----------- + case(write_state) + // do nothing in idle state + WR_STATE_IDLE: ; + + // waiting for data token + WR_STATE_EXP_DTOKEN: begin + buffer_ptr <= 0; + if(cmd == 'h58) begin + if({sbuf,mosi} == 8'hfe) write_state <= WR_STATE_RECV_DATA; + end + else begin + if({sbuf,mosi} == 8'hfc) write_state <= WR_STATE_RECV_DATA; + if({sbuf,mosi} == 8'hfd) begin + write_state <= WR_STATE_IDLE; + rx_finish <= 1; + end + end + end + + // transfer 512 bytes + WR_STATE_RECV_DATA: begin + // push one byte into local buffer + buffer_wr <= 1; + buffer_din <= {sbuf, mosi}; + + // all bytes written? + if(&buffer_ptr) write_state <= WR_STATE_RECV_CRC0; + end + + // transfer 1st crc byte + WR_STATE_RECV_CRC0: + write_state <= WR_STATE_RECV_CRC1; + + // transfer 2nd crc byte + WR_STATE_RECV_CRC1: + write_state <= WR_STATE_SEND_DRESP; + + // send data response + WR_STATE_SEND_DRESP: begin + write_state <= WR_STATE_BUSY; + io_ack <= 0; + sd_wr <= 1; + end + + // wait for io controller to accept data + WR_STATE_BUSY: + if(io_ack) begin + if(cmd == 'h59) begin + write_state <= WR_STATE_EXP_DTOKEN; + lba <= lba + 1; + end + else begin + write_state <= WR_STATE_IDLE; + rx_finish <= 1; + end + end + endcase + end + + // wait for first 0 bit until start counting bits + if(!synced && !mosi) begin + synced <= 1; + bit_cnt <= 1; // byte assembly prepare for next time loop + sbuf <= 7'b1111110; // byte assembly prepare for next time loop + rx_finish<= 0; + end else if (synced && tx_finish && rx_finish ) begin + synced <= 0; + bit_cnt <= 0; + rx_finish<= 0; + end + end +end + +endmodule + +module sdbuf #(parameter WIDE) +( + input clock_a, + input [AW:0] address_a, + input [DW:0] data_a, + input wren_a, + output reg [DW:0] q_a, + + input clock_b, + input [8:0] address_b, + input [7:0] data_b, + input wren_b, + output reg [7:0] q_b +); + +localparam AW = WIDE ? 7 : 8; +localparam DW = WIDE ? 15 : 7; + +always@(posedge clock_a) begin + if(wren_a) begin + ram[address_a] <= data_a; + q_a <= data_a; + end + else begin + q_a <= ram[address_a]; + end +end + +generate + if(WIDE) begin + reg [1:0][7:0] ram[1<<8]; + always@(posedge clock_b) begin + if(wren_b) begin + ram[address_b[8:1]][address_b[0]] <= data_b; + q_b <= data_b; + end + else begin + q_b <= ram[address_b[8:1]][address_b[0]]; + end + end + end + else begin + reg [7:0] ram[1<<9]; + always@(posedge clock_b) begin + if(wren_b) begin + ram[address_b] <= data_b; + q_b <= data_b; + end + else begin + q_b <= ram[address_b]; + end + end + end +endgenerate + +endmodule diff --git a/sys/sigma_delta_dac.v b/sys/sigma_delta_dac.v new file mode 100644 index 0000000..d0d6be0 --- /dev/null +++ b/sys/sigma_delta_dac.v @@ -0,0 +1,33 @@ +// +// PWM DAC +// +// MSBI is the highest bit number. NOT amount of bits! +// +module sigma_delta_dac #(parameter MSBI=7, parameter INV=1'b1) +( + output reg DACout, //Average Output feeding analog lowpass + input [MSBI:0] DACin, //DAC input (excess 2**MSBI) + input CLK, + input RESET +); + +reg [MSBI+2:0] DeltaAdder; //Output of Delta Adder +reg [MSBI+2:0] SigmaAdder; //Output of Sigma Adder +reg [MSBI+2:0] SigmaLatch; //Latches output of Sigma Adder +reg [MSBI+2:0] DeltaB; //B input of Delta Adder + +always @(*) DeltaB = {SigmaLatch[MSBI+2], SigmaLatch[MSBI+2]} << (MSBI+1); +always @(*) DeltaAdder = DACin + DeltaB; +always @(*) SigmaAdder = DeltaAdder + SigmaLatch; + +always @(posedge CLK or posedge RESET) begin + if(RESET) begin + SigmaLatch <= 1'b1 << (MSBI+1); + DACout <= INV; + end else begin + SigmaLatch <= SigmaAdder; + DACout <= SigmaLatch[MSBI+2] ^ INV; + end +end + +endmodule diff --git a/sys/spdif.v b/sys/spdif.v new file mode 100644 index 0000000..eee2b08 --- /dev/null +++ b/sys/spdif.v @@ -0,0 +1,320 @@ +//----------------------------------------------------------------- +// SPDIF Transmitter +// V0.1 +// Ultra-Embedded.com +// Copyright 2012 +// +// Email: admin@ultra-embedded.com +// +// License: GPL +// If you would like a version with a more permissive license for +// use in closed source commercial applications please contact me +// for details. +//----------------------------------------------------------------- +// +// This file is open source HDL; 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 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 file; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA +//----------------------------------------------------------------- +// altera message_off 10762 +// altera message_off 10240 + +module spdif +( + input clk_i, + input rst_i, + + // SPDIF bit output enable + // Single cycle pulse synchronous to clk_i which drives + // the output bit rate. + // For 44.1KHz, 44100×32×2×2 = 5,644,800Hz + // For 48KHz, 48000×32×2×2 = 6,144,000Hz + input bit_out_en_i, + + // Output + output spdif_o, + + // Audio interface (16-bit x 2 = RL) + input [31:0] sample_i, + output reg sample_req_o +); + +//----------------------------------------------------------------- +// Registers +//----------------------------------------------------------------- +reg [15:0] audio_sample_q; +reg [8:0] subframe_count_q; + +reg load_subframe_q; +reg [7:0] preamble_q; +wire [31:0] subframe_w; + +reg [5:0] bit_count_q; +reg bit_toggle_q; + +reg spdif_out_q; + +reg [5:0] parity_count_q; + +reg channel_status_bit_q; + +//----------------------------------------------------------------- +// Subframe Counter +//----------------------------------------------------------------- +always @ (posedge rst_i or posedge clk_i ) +begin + if (rst_i == 1'b1) + subframe_count_q <= 9'd0; + else if (load_subframe_q) + begin + // 192 frames (384 subframes) in an audio block + if (subframe_count_q == 9'd383) + subframe_count_q <= 9'd0; + else + subframe_count_q <= subframe_count_q + 9'd1; + end +end + +//----------------------------------------------------------------- +// Sample capture +//----------------------------------------------------------------- +reg [15:0] sample_buf_q; + +always @ (posedge rst_i or posedge clk_i ) +begin + if (rst_i == 1'b1) + begin + audio_sample_q <= 16'h0000; + sample_buf_q <= 16'h0000; + sample_req_o <= 1'b0; + end + else if (load_subframe_q) + begin + // Start of frame (first subframe)? + if (subframe_count_q[0] == 1'b0) + begin + // Use left sample + audio_sample_q <= sample_i[15:0]; + + // Store right sample + sample_buf_q <= sample_i[31:16]; + + // Request next sample + sample_req_o <= 1'b1; + end + else + begin + // Use right sample + audio_sample_q <= sample_buf_q; + + sample_req_o <= 1'b0; + end + end + else + sample_req_o <= 1'b0; +end + +// Timeslots 3 - 0 = Preamble +assign subframe_w[3:0] = 4'b0000; + +// Timeslots 7 - 4 = 24-bit audio LSB +assign subframe_w[7:4] = 4'b0000; + +// Timeslots 11 - 8 = 20-bit audio LSB +assign subframe_w[11:8] = 4'b0000; + +// Timeslots 27 - 12 = 16-bit audio +assign subframe_w[27:12] = audio_sample_q; + +// Timeslots 28 = Validity +assign subframe_w[28] = 1'b0; // Valid + +// Timeslots 29 = User bit +assign subframe_w[29] = 1'b0; + +// Timeslots 30 = Channel status bit +assign subframe_w[30] = channel_status_bit_q ; //was constant 1'b0 enabling copy-bit; + +// Timeslots 31 = Even Parity bit (31:4) +assign subframe_w[31] = 1'b0; + +//----------------------------------------------------------------- +// Preamble and Channel status bit +//----------------------------------------------------------------- +localparam PREAMBLE_Z = 8'b00010111; // "B" channel A data at start of block +localparam PREAMBLE_Y = 8'b00100111; // "W" channel B data +localparam PREAMBLE_X = 8'b01000111; // "M" channel A data not at start of block + +reg [7:0] preamble_r; +reg channel_status_bit_r; + +always @ * +begin + // Start of audio block? + // Z(B) - Left channel + if (subframe_count_q == 9'd0) + preamble_r = PREAMBLE_Z; // Z(B) + // Right Channel? + else if (subframe_count_q[0] == 1'b1) + preamble_r = PREAMBLE_Y; // Y(W) + // Left Channel (but not start of block)? + else + preamble_r = PREAMBLE_X; // X(M) + + if (subframe_count_q[8:1] == 8'd2) // frame 2 => subframes 4 and 5 => 0 = copy inhibited, 1 = copy permitted + channel_status_bit_r = 1'b1; + else if (subframe_count_q[8:1] == 8'd15) // frame 15 => 0 = no indication, 1 = original media + channel_status_bit_r = 1'b1; + else if (subframe_count_q[8:1] == 8'd25) // frame 24 to 27 => sample frequency, 0100 = 48kHz, 0000 = 44kHz (l2r) + channel_status_bit_r = 1'b1; + else + channel_status_bit_r = 1'b0; // everything else defaults to 0 +end + +always @ (posedge rst_i or posedge clk_i ) +begin + if (rst_i == 1'b1) + begin + preamble_q <= 8'h00; + channel_status_bit_q <= 1'b0; + end + else if (load_subframe_q) + begin + preamble_q <= preamble_r; + channel_status_bit_q <= channel_status_bit_r; + end +end + +//----------------------------------------------------------------- +// Parity Counter +//----------------------------------------------------------------- +always @ (posedge rst_i or posedge clk_i ) +begin + if (rst_i == 1'b1) + begin + parity_count_q <= 6'd0; + end + // Time to output a bit? + else if (bit_out_en_i) + begin + // Preamble bits? + if (bit_count_q < 6'd8) + begin + parity_count_q <= 6'd0; + end + // Normal timeslots + else if (bit_count_q < 6'd62) + begin + // On first pass through this timeslot, count number of high bits + if (bit_count_q[0] == 0 && subframe_w[bit_count_q / 2] == 1'b1) + parity_count_q <= parity_count_q + 6'd1; + end + end +end + +//----------------------------------------------------------------- +// Bit Counter +//----------------------------------------------------------------- +always @ (posedge rst_i or posedge clk_i) +begin + if (rst_i == 1'b1) + begin + bit_count_q <= 6'b0; + load_subframe_q <= 1'b1; + end + // Time to output a bit? + else if (bit_out_en_i) + begin + // 32 timeslots (x2 for double frequency) + if (bit_count_q == 6'd63) + begin + bit_count_q <= 6'd0; + load_subframe_q <= 1'b1; + end + else + begin + bit_count_q <= bit_count_q + 6'd1; + load_subframe_q <= 1'b0; + end + end + else + load_subframe_q <= 1'b0; +end + +//----------------------------------------------------------------- +// Bit half toggle +//----------------------------------------------------------------- +always @ (posedge rst_i or posedge clk_i) +if (rst_i == 1'b1) + bit_toggle_q <= 1'b0; +// Time to output a bit? +else if (bit_out_en_i) + bit_toggle_q <= ~bit_toggle_q; + +//----------------------------------------------------------------- +// Output bit (BMC encoded) +//----------------------------------------------------------------- +reg bit_r; + +always @ * +begin + bit_r = spdif_out_q; + + // Time to output a bit? + if (bit_out_en_i) + begin + // Preamble bits? + if (bit_count_q < 6'd8) + begin + bit_r = preamble_q[bit_count_q[2:0]]; + end + // Normal timeslots + else if (bit_count_q < 6'd62) + begin + if (subframe_w[bit_count_q / 2] == 1'b0) + begin + if (bit_toggle_q == 1'b0) + bit_r = ~spdif_out_q; + else + bit_r = spdif_out_q; + end + else + bit_r = ~spdif_out_q; + end + // Parity timeslot + else + begin + // Even number of high bits, make odd + if (parity_count_q[0] == 1'b0) + begin + if (bit_toggle_q == 1'b0) + bit_r = ~spdif_out_q; + else + bit_r = spdif_out_q; + end + else + bit_r = ~spdif_out_q; + end + end +end + +always @ (posedge rst_i or posedge clk_i ) +if (rst_i == 1'b1) + spdif_out_q <= 1'b0; +else + spdif_out_q <= bit_r; + +assign spdif_o = spdif_out_q; + +endmodule diff --git a/sys/sys.qip b/sys/sys.qip new file mode 100644 index 0000000..eeae907 --- /dev/null +++ b/sys/sys.qip @@ -0,0 +1,32 @@ +set_global_assignment -name QIP_FILE [join [list $::quartus(qip_path) pll_q [regexp -inline {[0-9]+} $quartus(version)] .qip] {}] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) sys_top.v ] +set_global_assignment -name SDC_FILE [file join $::quartus(qip_path) sys_top.sdc ] +set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) ascal.vhd ] +set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) pll_hdmi_adj.vhd ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) math.sv ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) hq2x.sv ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scandoubler.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scanlines.v ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_cleaner.sv ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) gamma_corr.sv ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_mixer.sv ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_freak.sv ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) arcade_video.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) osd.v ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) vga_out.sv ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) i2c.v ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) alsa.sv ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) i2s.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) spdif.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) audio_out.v ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) iir_filter.v ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) ltc2308.sv ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) sigma_delta_dac.v ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) mt32pi.sv ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) hdmi_config.sv ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) mcp23009.sv ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) f2sdram_safe_terminator.sv ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) ddr_svc.sv ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) sysmem.sv ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) sd_card.sv ] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) hps_io.v ] diff --git a/sys/sys.tcl b/sys/sys.tcl new file mode 100644 index 0000000..ce83683 --- /dev/null +++ b/sys/sys.tcl @@ -0,0 +1,227 @@ +set_global_assignment -name FAMILY "Cyclone V" +set_global_assignment -name DEVICE 5CSEBA6U23I7 +set_global_assignment -name DEVICE_FILTER_PACKAGE UFBGA +set_global_assignment -name DEVICE_FILTER_PIN_COUNT 672 +set_global_assignment -name DEVICE_FILTER_SPEED_GRADE 7 + +#============================================================ +# ADC +#============================================================ +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ADC_CONVST +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ADC_SCK +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ADC_SDI +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ADC_SDO +set_location_assignment PIN_U9 -to ADC_CONVST +set_location_assignment PIN_V10 -to ADC_SCK +set_location_assignment PIN_AC4 -to ADC_SDI +set_location_assignment PIN_AD4 -to ADC_SDO + +#============================================================ +# ARDUINO +#============================================================ +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ARDUINO_IO[*] +set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to ARDUINO_IO[*] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to ARDUINO_IO[*] + +#============================================================ +# I2C LEDS/BUTTONS +#============================================================ +set_location_assignment PIN_U14 -to IO_SCL +set_location_assignment PIN_AG9 -to IO_SDA +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to IO_S* +set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to IO_S* +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to IO_S* + +#============================================================ +# USER PORT +#============================================================ +set_location_assignment PIN_AF17 -to USER_IO[6] +set_location_assignment PIN_AF15 -to USER_IO[5] +set_location_assignment PIN_AG16 -to USER_IO[4] +set_location_assignment PIN_AH11 -to USER_IO[3] +set_location_assignment PIN_AH12 -to USER_IO[2] +set_location_assignment PIN_AH9 -to USER_IO[1] +set_location_assignment PIN_AG11 -to USER_IO[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to USER_IO[*] +set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to USER_IO[*] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to USER_IO[*] + +#============================================================ +# SDIO_CD or SPDIF_OUT +#============================================================ +set_location_assignment PIN_AH7 -to SDCD_SPDIF +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDCD_SPDIF +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDCD_SPDIF +set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to SDCD_SPDIF + +#============================================================ +# SDRAM +#============================================================ +set_location_assignment PIN_Y11 -to SDRAM_A[0] +set_location_assignment PIN_AA26 -to SDRAM_A[1] +set_location_assignment PIN_AA13 -to SDRAM_A[2] +set_location_assignment PIN_AA11 -to SDRAM_A[3] +set_location_assignment PIN_W11 -to SDRAM_A[4] +set_location_assignment PIN_Y19 -to SDRAM_A[5] +set_location_assignment PIN_AB23 -to SDRAM_A[6] +set_location_assignment PIN_AC23 -to SDRAM_A[7] +set_location_assignment PIN_AC22 -to SDRAM_A[8] +set_location_assignment PIN_C12 -to SDRAM_A[9] +set_location_assignment PIN_AB26 -to SDRAM_A[10] +set_location_assignment PIN_AD17 -to SDRAM_A[11] +set_location_assignment PIN_D12 -to SDRAM_A[12] +set_location_assignment PIN_Y17 -to SDRAM_BA[0] +set_location_assignment PIN_AB25 -to SDRAM_BA[1] +set_location_assignment PIN_E8 -to SDRAM_DQ[0] +set_location_assignment PIN_V12 -to SDRAM_DQ[1] +set_location_assignment PIN_D11 -to SDRAM_DQ[2] +set_location_assignment PIN_W12 -to SDRAM_DQ[3] +set_location_assignment PIN_AH13 -to SDRAM_DQ[4] +set_location_assignment PIN_D8 -to SDRAM_DQ[5] +set_location_assignment PIN_AH14 -to SDRAM_DQ[6] +set_location_assignment PIN_AF7 -to SDRAM_DQ[7] +set_location_assignment PIN_AE24 -to SDRAM_DQ[8] +set_location_assignment PIN_AD23 -to SDRAM_DQ[9] +set_location_assignment PIN_AE6 -to SDRAM_DQ[10] +set_location_assignment PIN_AE23 -to SDRAM_DQ[11] +set_location_assignment PIN_AG14 -to SDRAM_DQ[12] +set_location_assignment PIN_AD5 -to SDRAM_DQ[13] +set_location_assignment PIN_AF4 -to SDRAM_DQ[14] +set_location_assignment PIN_AH3 -to SDRAM_DQ[15] +set_location_assignment PIN_AG13 -to SDRAM_DQML +set_location_assignment PIN_AF13 -to SDRAM_DQMH +set_location_assignment PIN_AD20 -to SDRAM_CLK +set_location_assignment PIN_AG10 -to SDRAM_CKE +set_location_assignment PIN_AA19 -to SDRAM_nWE +set_location_assignment PIN_AA18 -to SDRAM_nCAS +set_location_assignment PIN_Y18 -to SDRAM_nCS +set_location_assignment PIN_W14 -to SDRAM_nRAS + +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_* +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_* +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_* +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[*] +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[*] +set_instance_assignment -name ALLOW_SYNCH_CTRL_USAGE OFF -to *|SDRAM_* + +#============================================================ +# SPI SD +#============================================================ +set_location_assignment PIN_AE15 -to SD_SPI_CS +set_location_assignment PIN_AH8 -to SD_SPI_MISO +set_location_assignment PIN_AG8 -to SD_SPI_CLK +set_location_assignment PIN_U13 -to SD_SPI_MOSI +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SD_SPI* +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SD_SPI* +set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to SD_SPI* + + +#============================================================ +# CLOCK +#============================================================ +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FPGA_CLK1_50 +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FPGA_CLK2_50 +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FPGA_CLK3_50 +set_location_assignment PIN_V11 -to FPGA_CLK1_50 +set_location_assignment PIN_Y13 -to FPGA_CLK2_50 +set_location_assignment PIN_E11 -to FPGA_CLK3_50 + +#============================================================ +# HDMI +#============================================================ +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HDMI_I2C_* +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HDMI_I2S +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HDMI_LRCLK +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HDMI_MCLK +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HDMI_SCLK +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HDMI_TX_* +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to HDMI_TX_D[*] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to HDMI_TX_DE +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to HDMI_TX_HS +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to HDMI_TX_VS +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to HDMI_TX_CLK +set_location_assignment PIN_U10 -to HDMI_I2C_SCL +set_location_assignment PIN_AA4 -to HDMI_I2C_SDA +set_location_assignment PIN_T13 -to HDMI_I2S +set_location_assignment PIN_T11 -to HDMI_LRCLK +set_location_assignment PIN_U11 -to HDMI_MCLK +set_location_assignment PIN_T12 -to HDMI_SCLK +set_location_assignment PIN_AG5 -to HDMI_TX_CLK +set_location_assignment PIN_AD19 -to HDMI_TX_DE +set_location_assignment PIN_AD12 -to HDMI_TX_D[0] +set_location_assignment PIN_AE12 -to HDMI_TX_D[1] +set_location_assignment PIN_W8 -to HDMI_TX_D[2] +set_location_assignment PIN_Y8 -to HDMI_TX_D[3] +set_location_assignment PIN_AD11 -to HDMI_TX_D[4] +set_location_assignment PIN_AD10 -to HDMI_TX_D[5] +set_location_assignment PIN_AE11 -to HDMI_TX_D[6] +set_location_assignment PIN_Y5 -to HDMI_TX_D[7] +set_location_assignment PIN_AF10 -to HDMI_TX_D[8] +set_location_assignment PIN_Y4 -to HDMI_TX_D[9] +set_location_assignment PIN_AE9 -to HDMI_TX_D[10] +set_location_assignment PIN_AB4 -to HDMI_TX_D[11] +set_location_assignment PIN_AE7 -to HDMI_TX_D[12] +set_location_assignment PIN_AF6 -to HDMI_TX_D[13] +set_location_assignment PIN_AF8 -to HDMI_TX_D[14] +set_location_assignment PIN_AF5 -to HDMI_TX_D[15] +set_location_assignment PIN_AE4 -to HDMI_TX_D[16] +set_location_assignment PIN_AH2 -to HDMI_TX_D[17] +set_location_assignment PIN_AH4 -to HDMI_TX_D[18] +set_location_assignment PIN_AH5 -to HDMI_TX_D[19] +set_location_assignment PIN_AH6 -to HDMI_TX_D[20] +set_location_assignment PIN_AG6 -to HDMI_TX_D[21] +set_location_assignment PIN_AF9 -to HDMI_TX_D[22] +set_location_assignment PIN_AE8 -to HDMI_TX_D[23] +set_location_assignment PIN_T8 -to HDMI_TX_HS +set_location_assignment PIN_AF11 -to HDMI_TX_INT +set_location_assignment PIN_V13 -to HDMI_TX_VS + +#============================================================ +# KEY +#============================================================ +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to KEY[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to KEY[1] +set_location_assignment PIN_AH17 -to KEY[0] +set_location_assignment PIN_AH16 -to KEY[1] + +#============================================================ +# LED +#============================================================ +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[2] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[3] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[4] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[5] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[6] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[7] +set_location_assignment PIN_W15 -to LED[0] +set_location_assignment PIN_AA24 -to LED[1] +set_location_assignment PIN_V16 -to LED[2] +set_location_assignment PIN_V15 -to LED[3] +set_location_assignment PIN_AF26 -to LED[4] +set_location_assignment PIN_AE26 -to LED[5] +set_location_assignment PIN_Y16 -to LED[6] +set_location_assignment PIN_AA23 -to LED[7] + +#============================================================ +# SW +#============================================================ +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[2] +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[3] +set_location_assignment PIN_Y24 -to SW[0] +set_location_assignment PIN_W24 -to SW[1] +set_location_assignment PIN_W21 -to SW[2] +set_location_assignment PIN_W20 -to SW[3] + +set_instance_assignment -name HPS_LOCATION HPSINTERFACEPERIPHERALSPIMASTER_X52_Y72_N111 -entity sys_top -to spi +set_instance_assignment -name HPS_LOCATION HPSINTERFACEPERIPHERALUART_X52_Y67_N111 -entity sys_top -to uart +set_instance_assignment -name HPS_LOCATION HPSINTERFACEPERIPHERALI2C_X52_Y60_N111 -entity sys_top -to hdmi_i2c + +set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:sys/build_id.tcl" + +set_global_assignment -name CDF_FILE jtag.cdf +set_global_assignment -name QIP_FILE sys/sys.qip + diff --git a/sys/sys_analog.tcl b/sys/sys_analog.tcl new file mode 100644 index 0000000..692043f --- /dev/null +++ b/sys/sys_analog.tcl @@ -0,0 +1,71 @@ +#============================================================ +# SDIO +#============================================================ +set_location_assignment PIN_AF25 -to SDIO_DAT[0] +set_location_assignment PIN_AF23 -to SDIO_DAT[1] +set_location_assignment PIN_AD26 -to SDIO_DAT[2] +set_location_assignment PIN_AF28 -to SDIO_DAT[3] +set_location_assignment PIN_AF27 -to SDIO_CMD +set_location_assignment PIN_AH26 -to SDIO_CLK +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDIO_* + +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDIO_* +set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to SDIO_DAT[*] +set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to SDIO_CMD + +#============================================================ +# VGA +#============================================================ +set_location_assignment PIN_AE17 -to VGA_R[0] +set_location_assignment PIN_AE20 -to VGA_R[1] +set_location_assignment PIN_AF20 -to VGA_R[2] +set_location_assignment PIN_AH18 -to VGA_R[3] +set_location_assignment PIN_AH19 -to VGA_R[4] +set_location_assignment PIN_AF21 -to VGA_R[5] + +set_location_assignment PIN_AE19 -to VGA_G[0] +set_location_assignment PIN_AG15 -to VGA_G[1] +set_location_assignment PIN_AF18 -to VGA_G[2] +set_location_assignment PIN_AG18 -to VGA_G[3] +set_location_assignment PIN_AG19 -to VGA_G[4] +set_location_assignment PIN_AG20 -to VGA_G[5] + +set_location_assignment PIN_AG21 -to VGA_B[0] +set_location_assignment PIN_AA20 -to VGA_B[1] +set_location_assignment PIN_AE22 -to VGA_B[2] +set_location_assignment PIN_AF22 -to VGA_B[3] +set_location_assignment PIN_AH23 -to VGA_B[4] +set_location_assignment PIN_AH21 -to VGA_B[5] + +set_location_assignment PIN_AH22 -to VGA_HS +set_location_assignment PIN_AG24 -to VGA_VS + +set_location_assignment PIN_AH27 -to VGA_EN +set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to VGA_EN + +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_* +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_* + +#============================================================ +# AUDIO +#============================================================ +set_location_assignment PIN_AC24 -to AUDIO_L +set_location_assignment PIN_AE25 -to AUDIO_R +set_location_assignment PIN_AG26 -to AUDIO_SPDIF +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to AUDIO_* +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to AUDIO_* + +#============================================================ +# I/O #1 +#============================================================ +set_location_assignment PIN_Y15 -to LED_USER +set_location_assignment PIN_AA15 -to LED_HDD +set_location_assignment PIN_AG28 -to LED_POWER + +set_location_assignment PIN_AH24 -to BTN_USER +set_location_assignment PIN_AG25 -to BTN_OSD +set_location_assignment PIN_AG23 -to BTN_RESET + +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED_* +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to BTN_* +set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to BTN_* diff --git a/sys/sys_dual_sdram.tcl b/sys/sys_dual_sdram.tcl new file mode 100644 index 0000000..bffcdf4 --- /dev/null +++ b/sys/sys_dual_sdram.tcl @@ -0,0 +1,50 @@ +#============================================================ +# Secondary SDRAM +#============================================================ +set_location_assignment PIN_Y15 -to SDRAM2_DQ[0] +set_location_assignment PIN_AC24 -to SDRAM2_DQ[1] +set_location_assignment PIN_AA15 -to SDRAM2_DQ[2] +set_location_assignment PIN_AD26 -to SDRAM2_DQ[3] +set_location_assignment PIN_AG28 -to SDRAM2_DQ[4] +set_location_assignment PIN_AF28 -to SDRAM2_DQ[5] +set_location_assignment PIN_AE25 -to SDRAM2_DQ[6] +set_location_assignment PIN_AF27 -to SDRAM2_DQ[7] +set_location_assignment PIN_AG26 -to SDRAM2_DQ[14] +set_location_assignment PIN_AH27 -to SDRAM2_DQ[15] + +set_location_assignment PIN_AG25 -to SDRAM2_DQ[13] +set_location_assignment PIN_AH26 -to SDRAM2_DQ[12] +set_location_assignment PIN_AH24 -to SDRAM2_DQ[11] +set_location_assignment PIN_AF25 -to SDRAM2_DQ[10] +set_location_assignment PIN_AG23 -to SDRAM2_DQ[9] +set_location_assignment PIN_AF23 -to SDRAM2_DQ[8] +set_location_assignment PIN_AG24 -to SDRAM2_A[12] +set_location_assignment PIN_AH22 -to SDRAM2_CLK +set_location_assignment PIN_AH21 -to SDRAM2_A[9] +set_location_assignment PIN_AG21 -to SDRAM2_A[11] +set_location_assignment PIN_AH23 -to SDRAM2_A[7] +set_location_assignment PIN_AA20 -to SDRAM2_A[8] +set_location_assignment PIN_AF22 -to SDRAM2_A[5] +set_location_assignment PIN_AE22 -to SDRAM2_A[6] +set_location_assignment PIN_AG20 -to SDRAM2_nWE +set_location_assignment PIN_AF21 -to SDRAM2_A[4] + +set_location_assignment PIN_AG19 -to SDRAM2_nCAS +set_location_assignment PIN_AH19 -to SDRAM2_nRAS +set_location_assignment PIN_AG18 -to SDRAM2_nCS +set_location_assignment PIN_AH18 -to SDRAM2_BA[0] +set_location_assignment PIN_AF18 -to SDRAM2_BA[1] +set_location_assignment PIN_AF20 -to SDRAM2_A[10] +set_location_assignment PIN_AG15 -to SDRAM2_A[0] +set_location_assignment PIN_AE20 -to SDRAM2_A[1] +set_location_assignment PIN_AE19 -to SDRAM2_A[2] +set_location_assignment PIN_AE17 -to SDRAM2_A[3] + +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM2_* +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM2_* +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM2_* +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM2_DQ[*] +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM2_DQ[*] +set_instance_assignment -name ALLOW_SYNCH_CTRL_USAGE OFF -to *|SDRAM2_* + +set_global_assignment -name VERILOG_MACRO "DUAL_SDRAM=1" diff --git a/sys/sys_top.sdc b/sys/sys_top.sdc new file mode 100644 index 0000000..cf2d492 --- /dev/null +++ b/sys/sys_top.sdc @@ -0,0 +1,71 @@ +# Specify root clocks +create_clock -period "50.0 MHz" [get_ports FPGA_CLK1_50] +create_clock -period "50.0 MHz" [get_ports FPGA_CLK2_50] +create_clock -period "50.0 MHz" [get_ports FPGA_CLK3_50] +create_clock -period "100.0 MHz" [get_pins -compatibility_mode *|h2f_user0_clk] +create_clock -period "100.0 MHz" [get_pins -compatibility_mode spi|sclk_out] -name spi_sck +create_clock -period "10.0 MHz" [get_pins -compatibility_mode hdmi_i2c|out_clk] -name hdmi_sck + +derive_pll_clocks +derive_clock_uncertainty + +# Decouple different clock groups (to simplify routing) +set_clock_groups -exclusive \ + -group [get_clocks { *|pll|pll_inst|altera_pll_i|*[*].*|divclk}] \ + -group [get_clocks { pll_hdmi|pll_hdmi_inst|altera_pll_i|*[0].*|divclk}] \ + -group [get_clocks { pll_audio|pll_audio_inst|altera_pll_i|*[0].*|divclk}] \ + -group [get_clocks { spi_sck}] \ + -group [get_clocks { hdmi_sck}] \ + -group [get_clocks { *|h2f_user0_clk}] \ + -group [get_clocks { FPGA_CLK1_50 }] \ + -group [get_clocks { FPGA_CLK2_50 }] \ + -group [get_clocks { FPGA_CLK3_50 }] + +set_false_path -from [get_ports {KEY*}] +set_false_path -from [get_ports {BTN_*}] +set_false_path -to [get_ports {LED_*}] +set_false_path -to [get_ports {VGA_*}] +set_false_path -to [get_ports {AUDIO_SPDIF}] +set_false_path -to [get_ports {AUDIO_L}] +set_false_path -to [get_ports {AUDIO_R}] +set_false_path -to {cfg[*]} +set_false_path -from {cfg[*]} +set_false_path -from {VSET[*]} +set_false_path -to {wcalc[*] hcalc[*]} +set_false_path -to {hdmi_width[*] hdmi_height[*]} + +set_multicycle_path -to {*_osd|osd_vcnt*} -setup 2 +set_multicycle_path -to {*_osd|osd_vcnt*} -hold 1 + +set_false_path -to {*_osd|v_cnt*} +set_false_path -to {*_osd|v_osd_start*} +set_false_path -to {*_osd|v_info_start*} +set_false_path -to {*_osd|h_osd_start*} +set_false_path -from {*_osd|v_osd_start*} +set_false_path -from {*_osd|v_info_start*} +set_false_path -from {*_osd|h_osd_start*} +set_false_path -from {*_osd|rot*} +set_false_path -from {*_osd|dsp_width*} +set_false_path -to {*_osd|half} + +set_false_path -to {WIDTH[*] HFP[*] HS[*] HBP[*] HEIGHT[*] VFP[*] VS[*] VBP[*]} +set_false_path -from {WIDTH[*] HFP[*] HS[*] HBP[*] HEIGHT[*] VFP[*] VS[*] VBP[*]} +set_false_path -to {FB_BASE[*] FB_BASE[*] FB_WIDTH[*] FB_HEIGHT[*] LFB_HMIN[*] LFB_HMAX[*] LFB_VMIN[*] LFB_VMAX[*]} +set_false_path -from {FB_BASE[*] FB_BASE[*] FB_WIDTH[*] FB_HEIGHT[*] LFB_HMIN[*] LFB_HMAX[*] LFB_VMIN[*] LFB_VMAX[*]} +set_false_path -to {vol_att[*] scaler_flt[*] led_overtake[*] led_state[*]} +set_false_path -from {vol_att[*] scaler_flt[*] led_overtake[*] led_state[*]} +set_false_path -from {aflt_* acx* acy* areset* arc*} +set_false_path -from {vs_line*} + +set_false_path -from {ascal|o_ihsize*} +set_false_path -from {ascal|o_ivsize*} +set_false_path -from {ascal|o_format*} +set_false_path -from {ascal|o_hdown} +set_false_path -from {ascal|o_vdown} +set_false_path -from {ascal|o_hmin* ascal|o_hmax* ascal|o_vmin* ascal|o_vmax*} +set_false_path -from {ascal|o_hdisp* ascal|o_vdisp*} +set_false_path -from {ascal|o_htotal* ascal|o_vtotal*} +set_false_path -from {ascal|o_hsstart* ascal|o_vsstart* ascal|o_hsend* ascal|o_vsend*} +set_false_path -from {ascal|o_hsize* ascal|o_vsize*} + +set_false_path -from {mcp23009|sd_cd} diff --git a/sys/sys_top.v b/sys/sys_top.v new file mode 100644 index 0000000..8f0043c --- /dev/null +++ b/sys/sys_top.v @@ -0,0 +1,1729 @@ +//============================================================================ +// +// MiSTer hardware abstraction module +// (c)2017-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. +// +//============================================================================ + +`ifndef ARCADE_SYS + `define USE_DDRAM + `define USE_SDRAM +`endif + +`ifndef USE_DDRAM + `ifdef USE_FB + `define USE_DDRAM + `endif +`endif + + +module sys_top +( + /////////// CLOCK ////////// + input FPGA_CLK1_50, + input FPGA_CLK2_50, + input FPGA_CLK3_50, + + //////////// HDMI ////////// + output HDMI_I2C_SCL, + inout HDMI_I2C_SDA, + + output HDMI_MCLK, + output HDMI_SCLK, + output HDMI_LRCLK, + output HDMI_I2S, + + output HDMI_TX_CLK, + output HDMI_TX_DE, + output [23:0] HDMI_TX_D, + output HDMI_TX_HS, + output HDMI_TX_VS, + + input HDMI_TX_INT, + + //////////// SDR /////////// + output [12:0] SDRAM_A, + inout [15:0] SDRAM_DQ, + output SDRAM_DQML, + output SDRAM_DQMH, + output SDRAM_nWE, + output SDRAM_nCAS, + output SDRAM_nRAS, + output SDRAM_nCS, + output [1:0] SDRAM_BA, + output SDRAM_CLK, + output SDRAM_CKE, + +`ifdef DUAL_SDRAM + ////////// SDR #2 ////////// + output [12:0] SDRAM2_A, + inout [15:0] SDRAM2_DQ, + output SDRAM2_nWE, + output SDRAM2_nCAS, + output SDRAM2_nRAS, + output SDRAM2_nCS, + output [1:0] SDRAM2_BA, + output SDRAM2_CLK, + +`else + //////////// VGA /////////// + output [5:0] VGA_R, + output [5:0] VGA_G, + output [5:0] VGA_B, + inout VGA_HS, // VGA_HS is secondary SD card detect when VGA_EN = 1 (inactive) + output VGA_VS, + input VGA_EN, // active low + + /////////// AUDIO ////////// + output AUDIO_L, + output AUDIO_R, + output AUDIO_SPDIF, + + //////////// SDIO /////////// + inout [3:0] SDIO_DAT, + inout SDIO_CMD, + output SDIO_CLK, + + //////////// I/O /////////// + output LED_USER, + output LED_HDD, + output LED_POWER, + input BTN_USER, + input BTN_OSD, + input BTN_RESET, +`endif + + ////////// I/O ALT ///////// + output SD_SPI_CS, + input SD_SPI_MISO, + output SD_SPI_CLK, + output SD_SPI_MOSI, + + inout SDCD_SPDIF, + output IO_SCL, + inout IO_SDA, + + ////////// ADC ////////////// + output ADC_SCK, + input ADC_SDO, + output ADC_SDI, + output ADC_CONVST, + + ////////// MB KEY /////////// + input [1:0] KEY, + + ////////// MB SWITCH //////// + input [3:0] SW, + + ////////// MB LED /////////// + output [7:0] LED, + + ///////// USER IO /////////// + inout [6:0] USER_IO +); + +////////////////////// Secondary SD /////////////////////////////////// +wire SD_CS, SD_CLK, SD_MOSI; + +`ifdef ARCADE_SYS + assign SD_CS = 1'bZ; + assign SD_CLK = 1'bZ; + assign SD_MOSI = 1'bZ; +`else + `ifndef DUAL_SDRAM + wire sd_miso = SW[3] | SDIO_DAT[0]; + `else + wire sd_miso = 1; + `endif + wire SD_MISO = mcp_sdcd ? sd_miso : SD_SPI_MISO; +`endif + +`ifndef DUAL_SDRAM + assign SDIO_DAT[2:1]= 2'bZZ; + assign SDIO_DAT[3] = SW[3] ? 1'bZ : SD_CS; + assign SDIO_CLK = SW[3] ? 1'bZ : SD_CLK; + assign SDIO_CMD = SW[3] ? 1'bZ : SD_MOSI; + assign SD_SPI_CS = mcp_sdcd ? ((~VGA_EN & sog & ~cs1) ? 1'b1 : 1'bZ) : SD_CS; +`else + assign SD_SPI_CS = mcp_sdcd ? 1'bZ : SD_CS; +`endif + +assign SD_SPI_CLK = mcp_sdcd ? 1'bZ : SD_CLK; +assign SD_SPI_MOSI = mcp_sdcd ? 1'bZ : SD_MOSI; + +////////////////////// LEDs/Buttons /////////////////////////////////// + +reg [7:0] led_overtake = 0; +reg [7:0] led_state = 0; + +wire led_p = led_power[1] ? ~led_power[0] : 1'b0; +wire led_d = led_disk[1] ? ~led_disk[0] : ~(led_disk[0] | gp_out[29]); +wire led_u = ~led_user; +wire led_locked; + +`ifndef DUAL_SDRAM + assign LED_POWER = (SW[3] | led_p) ? 1'bZ : 1'b0; + assign LED_HDD = (SW[3] | led_d) ? 1'bZ : 1'b0; + assign LED_USER = (SW[3] | led_u) ? 1'bZ : 1'b0; +`endif + +//LEDs on main board +assign LED = (led_overtake & led_state) | (~led_overtake & {1'b0,led_locked,1'b0, ~led_p, 1'b0, ~led_d, 1'b0, ~led_u}); + +wire btn_r, btn_o, btn_u; +`ifdef DUAL_SDRAM + assign {btn_r,btn_o,btn_u} = {mcp_btn[1],mcp_btn[2],mcp_btn[0]}; +`else + assign {btn_r,btn_o,btn_u} = ~{BTN_RESET,BTN_OSD,BTN_USER} | {mcp_btn[1],mcp_btn[2],mcp_btn[0]}; +`endif + +wire [2:0] mcp_btn; +wire mcp_sdcd; +mcp23009 mcp23009 +( + .clk(FPGA_CLK2_50), + + .btn(mcp_btn), + .led({led_p, led_d, led_u}), + .sd_cd(mcp_sdcd), + + .scl(IO_SCL), + .sda(IO_SDA) +); + + +reg btn_user, btn_osd; +always @(posedge FPGA_CLK2_50) begin + integer div; + reg [7:0] deb_user; + reg [7:0] deb_osd; + + div <= div + 1'b1; + if(div > 100000) div <= 0; + + if(!div) begin + deb_user <= {deb_user[6:0], btn_u | ~KEY[1]}; + if(&deb_user) btn_user <= 1; + if(!deb_user) btn_user <= 0; + + deb_osd <= {deb_osd[6:0], btn_o | ~KEY[0]}; + if(&deb_osd) btn_osd <= 1; + if(!deb_osd) btn_osd <= 0; + end +end + +///////////////////////// HPS I/O ///////////////////////////////////// + +// gp_in[31] = 0 - quick flag that FPGA is initialized (HPS reads 1 when FPGA is not in user mode) +// used to avoid lockups while JTAG loading +wire [31:0] gp_in = {1'b0, btn_user | btn[1], btn_osd | btn[0], SW[3], 8'd0, io_ver, io_ack, io_wide, io_dout}; +wire [31:0] gp_out; + +wire [1:0] io_ver = 1; // 0 - standard MiST I/O (for quick porting of complex MiST cores). 1 - optimized HPS I/O. 2,3 - reserved for future. +wire io_wait; +wire io_wide; +wire [15:0] io_dout; +wire [15:0] io_din = gp_outr[15:0]; +wire io_clk = gp_outr[17]; +wire io_ss0 = gp_outr[18]; +wire io_ss1 = gp_outr[19]; +wire io_ss2 = gp_outr[20]; + +`ifndef DEBUG_NOHDMI +wire io_osd_hdmi = io_ss1 & ~io_ss0; +`endif + +wire io_fpga = ~io_ss1 & io_ss0; +wire io_uio = ~io_ss1 & io_ss2; + +reg io_ack; +reg rack; +wire io_strobe = ~rack & io_clk; + +always @(posedge clk_sys) begin + if(~(io_wait | vs_wait) | io_strobe) begin + rack <= io_clk; + io_ack <= rack; + end +end + +reg [31:0] gp_outr; +always @(posedge clk_sys) begin + reg [31:0] gp_outd; + gp_outr <= gp_outd; + gp_outd <= gp_out; +end + +`ifdef DUAL_SDRAM + wire [7:0] core_type = 'hA8; // generic core, dual SDRAM. +`else + wire [7:0] core_type = 'hA4; // generic core. +`endif + +// HPS will not communicate to core if magic is different +wire [31:0] core_magic = {24'h5CA623, core_type}; + +cyclonev_hps_interface_mpu_general_purpose h2f_gp +( + .gp_in({~gp_out[31] ? core_magic : gp_in}), + .gp_out(gp_out) +); + + +reg [15:0] cfg; + +reg cfg_set = 0; +wire vga_fb = cfg[12] | vga_force_scaler; +wire [1:0] hdmi_limited = {cfg[11],cfg[8]}; + +`ifdef DEBUG_NOHDMI +wire direct_video = 1; +`else +wire direct_video = cfg[10]; +`endif + +wire dvi_mode = cfg[7]; +wire audio_96k = cfg[6]; +wire csync_en = cfg[3]; +wire ypbpr_en = cfg[5]; +wire io_osd_vga = io_ss1 & ~io_ss2; +`ifndef DUAL_SDRAM + wire sog = cfg[9]; + wire vga_scaler = cfg[2] | vga_force_scaler; +`endif + +reg cfg_custom_t = 0; +reg [5:0] cfg_custom_p1; +reg [31:0] cfg_custom_p2; + +reg [4:0] vol_att = 0; + +reg [6:0] coef_addr; +reg [8:0] coef_data; +reg coef_wr = 0; + +wire[12:0] ARX, ARY; +reg [11:0] VSET = 0, HSET = 0; +reg FREESCALE = 0; +reg [2:0] scaler_flt; +reg lowlat = 0; +reg cfg_dis = 0; + +reg vs_wait = 0; +reg [11:0] vs_line = 0; + +reg scaler_out = 0; + +reg [31:0] aflt_rate = 7056000; +reg [39:0] acx = 4258969; +reg [7:0] acx0 = 3; +reg [7:0] acx1 = 3; +reg [7:0] acx2 = 1; +reg [23:0] acy0 = -24'd6216759; +reg [23:0] acy1 = 24'd6143386; +reg [23:0] acy2 = -24'd2023767; +reg areset = 0; +reg [12:0] arc1x = 0; +reg [12:0] arc1y = 0; +reg [12:0] arc2x = 0; +reg [12:0] arc2y = 0; + +always@(posedge clk_sys) begin + reg [7:0] cmd; + reg has_cmd; + reg old_strobe; + reg [7:0] cnt = 0; + reg vs_d0,vs_d1,vs_d2; + reg [4:0] acx_att; + + old_strobe <= io_strobe; + coef_wr <= 0; + + if(~io_uio) begin + has_cmd <= 0; + cmd <= 0; + areset <= 0; + acx_att <= 0; + acx <= acx >> acx_att; + end + else + if(~old_strobe & io_strobe) begin + if(!has_cmd) begin + has_cmd <= 1; + cmd <= io_din[7:0]; + cnt <= 0; + if(io_din[7:0] == 'h30) vs_wait <= 1; + if(io_din[7:0] == 'h39) begin + aflt_rate <= 7056000; + acx <= 4258969; + acx0 <= 3; + acx1 <= 3; + acx2 <= 1; + acy0 <= -24'd6216759; + acy1 <= 24'd6143386; + acy2 <= -24'd2023767; + areset <= 1; + end + end + else begin + if(cmd == 1) begin + cfg <= io_din; + cfg_set <= 1; + scaler_out <= 1; + end + if(cmd == 'h20) begin + cfg_set <= 0; + cnt <= cnt + 1'd1; + if(cnt<8) begin + case(cnt[2:0]) + 0: if(WIDTH != io_din[11:0]) WIDTH <= io_din[11:0]; + 1: if(HFP != io_din[11:0]) HFP <= io_din[11:0]; + 2: if(HS != io_din[11:0]) HS <= io_din[11:0]; + 3: if(HBP != io_din[11:0]) HBP <= io_din[11:0]; + 4: if(HEIGHT != io_din[11:0]) HEIGHT <= io_din[11:0]; + 5: if(VFP != io_din[11:0]) VFP <= io_din[11:0]; + 6: if(VS != io_din[11:0]) VS <= io_din[11:0]; + 7: if(VBP != io_din[11:0]) VBP <= io_din[11:0]; + endcase +`ifndef DEBUG_NOHDMI + if(cnt == 1) begin + cfg_custom_p1 <= 0; + cfg_custom_p2 <= 0; + cfg_custom_t <= ~cfg_custom_t; + end + end + else begin + if(cnt[1:0]==0) cfg_custom_p1 <= io_din[5:0]; + if(cnt[1:0]==1) cfg_custom_p2[15:0] <= io_din; + if(cnt[1:0]==2) begin + cfg_custom_p2[31:16] <= io_din; + cfg_custom_t <= ~cfg_custom_t; + cnt[2:0] <= 3'b100; + end + if(cnt == 8) {lowlat,cfg_dis} <= io_din[15:14]; +`endif + end + end + if(cmd == 'h2F) begin + cnt <= cnt + 1'd1; + case(cnt[3:0]) + 0: {LFB_EN,LFB_FLT,LFB_FMT} <= {io_din[15], io_din[14], io_din[5:0]}; + 1: LFB_BASE[15:0] <= io_din[15:0]; + 2: LFB_BASE[31:16] <= io_din[15:0]; + 3: LFB_WIDTH <= io_din[11:0]; + 4: LFB_HEIGHT <= io_din[11:0]; + 5: LFB_HMIN <= io_din[11:0]; + 6: LFB_HMAX <= io_din[11:0]; + 7: LFB_VMIN <= io_din[11:0]; + 8: LFB_VMAX <= io_din[11:0]; + 9: LFB_STRIDE <= io_din[13:0]; + endcase + end + if(cmd == 'h25) {led_overtake, led_state} <= io_din; + if(cmd == 'h26) vol_att <= io_din[4:0]; + if(cmd == 'h27) VSET <= io_din[11:0]; + if(cmd == 'h2A) {coef_wr,coef_addr,coef_data} <= {1'b1,io_din}; + if(cmd == 'h2B) scaler_flt <= io_din[2:0]; + if(cmd == 'h37) {FREESCALE,HSET} <= {io_din[15],io_din[11:0]}; + if(cmd == 'h38) vs_line <= io_din[11:0]; + if(cmd == 'h39) begin + cnt <= cnt + 1'd1; + case(cnt[3:0]) + 0: acx_att <= io_din[4:0]; + 1: aflt_rate[15:0] <= io_din; + 2: aflt_rate[31:16] <= io_din; + 3: acx[15:0] <= io_din; + 4: acx[31:16] <= io_din; + 5: acx[39:32] <= io_din[7:0]; + 6: acx0 <= io_din[7:0]; + 7: acx1 <= io_din[7:0]; + 8: acx2 <= io_din[7:0]; + 9: acy0[15:0] <= io_din; + 10: acy0[23:16] <= io_din[7:0]; + 11: acy1[15:0] <= io_din; + 12: acy1[23:16] <= io_din[7:0]; + 13: acy2[15:0] <= io_din; + 14: acy2[23:16] <= io_din[7:0]; + endcase + end + if(cmd == 'h3A) begin + cnt <= cnt + 1'd1; + case(cnt[3:0]) + 0: arc1x <= io_din[12:0]; + 1: arc1y <= io_din[12:0]; + 2: arc2x <= io_din[12:0]; + 3: arc2y <= io_din[12:0]; + endcase + end + end + end + + vs_d0 <= HDMI_TX_VS; + if(vs_d0 == HDMI_TX_VS) vs_d1 <= vs_d0; + + vs_d2 <= vs_d1; + if(~vs_d2 & vs_d1) vs_wait <= 0; +end + +cyclonev_hps_interface_peripheral_uart uart +( + .ri(0) +`ifndef ARCADE_SYS + , + .dsr(uart_dsr), + .dcd(uart_dsr), + .dtr(uart_dtr), + + .cts(uart_cts), + .rts(uart_rts), + .rxd(uart_rxd), + .txd(uart_txd) +`endif +); + +wire aspi_sck,aspi_mosi,aspi_ss,aspi_miso; +cyclonev_hps_interface_peripheral_spi_master spi +( + .sclk_out(aspi_sck), + .txd(aspi_mosi), // mosi + .rxd(aspi_miso), // miso + + .ss_0_n(aspi_ss), + .ss_in_n(1) +); + +wire [63:0] f2h_irq = {video_sync,HDMI_TX_VS}; +cyclonev_hps_interface_interrupts interrupts +( + .irq(f2h_irq) +); + +/////////////////////////// RESET /////////////////////////////////// + +reg reset_req = 0; +always @(posedge FPGA_CLK2_50) begin + reg [1:0] resetd, resetd2; + reg old_reset; + + //latch the reset + old_reset <= reset; + if(~old_reset & reset) reset_req <= 1; + + //special combination to set/clear the reset + //preventing of accidental reset control + if(resetd==1) reset_req <= 1; + if(resetd==2 && resetd2==0) reset_req <= 0; + + resetd <= gp_out[31:30]; + resetd2 <= resetd; +end + +//////////////////// SYSTEM MEMORY & SCALER ///////////////////////// + +wire reset; +wire clk_100m; + +sysmem_lite sysmem +( + //Reset/Clock + .reset_core_req(reset_req), + .reset_out(reset), + .clock(clk_100m), + + //DE10-nano has no reset signal on GPIO, so core has to emulate cold reset button. + .reset_hps_cold_req(btn_r), + +`ifdef USE_DDRAM + //64-bit DDR3 RAM access + .ram1_clk(ram_clk), + .ram1_address(ram_address), + .ram1_burstcount(ram_burstcount), + .ram1_waitrequest(ram_waitrequest), + .ram1_readdata(ram_readdata), + .ram1_readdatavalid(ram_readdatavalid), + .ram1_read(ram_read), + .ram1_writedata(ram_writedata), + .ram1_byteenable(ram_byteenable), + .ram1_write(ram_write), +`endif + + //64-bit DDR3 RAM access + .ram2_clk(clk_audio), + .ram2_address(ram2_address), + .ram2_burstcount(ram2_burstcount), + .ram2_waitrequest(ram2_waitrequest), + .ram2_readdata(ram2_readdata), + .ram2_readdatavalid(ram2_readdatavalid), + .ram2_read(ram2_read), + .ram2_writedata(ram2_writedata), + .ram2_byteenable(ram2_byteenable), + .ram2_write(ram2_write), + + //128-bit DDR3 RAM access + // HDMI frame buffer + .vbuf_clk(clk_100m), + .vbuf_address(vbuf_address), + .vbuf_burstcount(vbuf_burstcount), + .vbuf_waitrequest(vbuf_waitrequest), + .vbuf_writedata(vbuf_writedata), + .vbuf_byteenable(vbuf_byteenable), + .vbuf_write(vbuf_write), + .vbuf_readdata(vbuf_readdata), + .vbuf_readdatavalid(vbuf_readdatavalid), + .vbuf_read(vbuf_read) +); + +wire [28:0] ram2_address; +wire [7:0] ram2_burstcount; +wire [7:0] ram2_byteenable; +wire ram2_waitrequest; +wire [63:0] ram2_readdata; +wire [63:0] ram2_writedata; +wire ram2_readdatavalid; +wire ram2_read; +wire ram2_write; +wire [7:0] ram2_bcnt; + +ddr_svc ddr_svc +( + .clk(clk_audio), + + .ram_waitrequest(ram2_waitrequest), + .ram_burstcnt(ram2_burstcount), + .ram_addr(ram2_address), + .ram_readdata(ram2_readdata), + .ram_read_ready(ram2_readdatavalid), + .ram_read(ram2_read), + .ram_writedata(ram2_writedata), + .ram_byteenable(ram2_byteenable), + .ram_write(ram2_write), + .ram_bcnt(ram2_bcnt), + + .ch0_addr(alsa_address), + .ch0_burst(1), + .ch0_data(alsa_readdata), + .ch0_req(alsa_req), + .ch0_ready(alsa_ready), + + .ch1_addr(pal_addr), + .ch1_burst(128), + .ch1_data(pal_data), + .ch1_req(pal_req), + .ch1_ready(pal_wr) +); + +wire clk_pal = clk_audio; + + +wire [27:0] vbuf_address; +wire [7:0] vbuf_burstcount; +wire vbuf_waitrequest; +wire [127:0] vbuf_readdata; +wire vbuf_readdatavalid; +wire vbuf_read; +wire [127:0] vbuf_writedata; +wire [15:0] vbuf_byteenable; +wire vbuf_write; + +wire [23:0] hdmi_data; +wire hdmi_vs, hdmi_hs, hdmi_de, hdmi_vbl; + +`ifndef DEBUG_NOHDMI +wire clk_hdmi = hdmi_clk_out; + +ascal +#( + .RAMBASE(32'h20000000), +`ifndef USE_FB + .PALETTE2("false"), +`endif + .N_DW(128), + .N_AW(28) +) +ascal +( + .reset_na (~reset_req), + .run (1), + .freeze (0), + + .i_clk (clk_ihdmi), + .i_ce (ce_hpix), + .i_r (hr_out), + .i_g (hg_out), + .i_b (hb_out), + .i_hs (hhs_fix), + .i_vs (hvs_fix), + .i_fl (f1), + .i_de (hde_emu), + .iauto (1), + .himin (0), + .himax (0), + .vimin (0), + .vimax (0), + + .o_clk (clk_hdmi), + .o_ce (scaler_out), + .o_r (hdmi_data[23:16]), + .o_g (hdmi_data[15:8]), + .o_b (hdmi_data[7:0]), + .o_hs (hdmi_hs), + .o_vs (hdmi_vs), + .o_de (hdmi_de), + .o_vbl (hdmi_vbl), + .o_lltune (lltune), + .htotal (WIDTH + HFP + HBP + HS), + .hsstart (WIDTH + HFP), + .hsend (WIDTH + HFP + HS), + .hdisp (WIDTH), + .hmin (hmin), + .hmax (hmax), + .vtotal (HEIGHT + VFP + VBP + VS), + .vsstart (HEIGHT + VFP), + .vsend (HEIGHT + VFP + VS), + .vdisp (HEIGHT), + .vmin (vmin), + .vmax (vmax), + + .mode ({~lowlat,LFB_EN ? LFB_FLT : |scaler_flt,2'b00}), + .poly_clk (clk_sys), + .poly_a (coef_addr), + .poly_dw (coef_data), + .poly_wr (coef_wr), + + .pal1_clk (clk_pal), + .pal1_dw (pal_d), + .pal1_a (pal_a), + .pal1_wr (pal_wr), + +`ifdef USE_FB + .pal2_clk (fb_pal_clk), + .pal2_dw (fb_pal_d), + .pal2_dr (fb_pal_q), + .pal2_a (fb_pal_a), + .pal2_wr (fb_pal_wr), + .pal_n (fb_en), +`endif + + .o_fb_ena (FB_EN), + .o_fb_hsize (FB_WIDTH), + .o_fb_vsize (FB_HEIGHT), + .o_fb_format (FB_FMT), + .o_fb_base (FB_BASE), + .o_fb_stride (FB_STRIDE), + + .avl_clk (clk_100m), + .avl_waitrequest (vbuf_waitrequest), + .avl_readdata (vbuf_readdata), + .avl_readdatavalid(vbuf_readdatavalid), + .avl_burstcount (vbuf_burstcount), + .avl_writedata (vbuf_writedata), + .avl_address (vbuf_address), + .avl_write (vbuf_write), + .avl_read (vbuf_read), + .avl_byteenable (vbuf_byteenable) +); +`endif + +reg LFB_EN = 0; +reg LFB_FLT = 0; +reg [5:0] LFB_FMT = 0; +reg [11:0] LFB_WIDTH = 0; +reg [11:0] LFB_HEIGHT = 0; +reg [11:0] LFB_HMIN = 0; +reg [11:0] LFB_HMAX = 0; +reg [11:0] LFB_VMIN = 0; +reg [11:0] LFB_VMAX = 0; +reg [31:0] LFB_BASE = 0; +reg [13:0] LFB_STRIDE = 0; + +reg FB_EN = 0; +reg [5:0] FB_FMT = 0; +reg [11:0] FB_WIDTH = 0; +reg [11:0] FB_HEIGHT = 0; +reg [31:0] FB_BASE = 0; +reg [13:0] FB_STRIDE = 0; + +always @(posedge clk_sys) begin + FB_EN <= LFB_EN | fb_en; + if(LFB_EN) begin + FB_FMT <= LFB_FMT; + FB_WIDTH <= LFB_WIDTH; + FB_HEIGHT <= LFB_HEIGHT; + FB_BASE <= LFB_BASE; + FB_STRIDE <= LFB_STRIDE; + end + else begin + FB_FMT <= fb_fmt; + FB_WIDTH <= fb_width; + FB_HEIGHT <= fb_height; + FB_BASE <= fb_base; + FB_STRIDE <= fb_stride; + end +end + +`ifdef USE_FB +reg fb_vbl; +always @(posedge clk_vid) fb_vbl <= hdmi_vbl; +`endif + +reg ar_md_start; +wire ar_md_busy; +reg [11:0] ar_md_mul1, ar_md_mul2, ar_md_div; +wire [11:0] ar_md_res; + +sys_umuldiv #(12,12,12) ar_muldiv +( + .clk(clk_vid), + .start(ar_md_start), + .busy(ar_md_busy), + + .mul1(ar_md_mul1), + .mul2(ar_md_mul2), + .div(ar_md_div), + .result(ar_md_res) +); + +reg [11:0] hmin; +reg [11:0] hmax; +reg [11:0] vmin; +reg [11:0] vmax; +reg [11:0] hdmi_height; +reg [11:0] hdmi_width; + +always @(posedge clk_vid) begin + reg [11:0] hmini,hmaxi,vmini,vmaxi; + reg [11:0] wcalc,videow,arx; + reg [11:0] hcalc,videoh,ary; + reg [2:0] state; + reg xy; + + hdmi_height <= (VSET && (VSET < HEIGHT)) ? VSET : HEIGHT; + hdmi_width <= (HSET && (HSET < WIDTH)) ? HSET : WIDTH; + + if(!ARY) begin + if(ARX == 1) begin + arx <= arc1x[11:0]; + ary <= arc1y[11:0]; + xy <= arc1x[12] | arc1y[12]; + end + else if(ARX == 2) begin + arx <= arc2x[11:0]; + ary <= arc2y[11:0]; + xy <= arc2x[12] | arc2y[12]; + end + else begin + arx <= 0; + ary <= 0; + xy <= 0; + end + end + else begin + arx <= ARX[11:0]; + ary <= ARY[11:0]; + xy <= ARX[12] | ARY[12]; + end + + ar_md_start <= 0; + state <= state + 1'd1; + case(state) + 0: if(LFB_EN) begin + hmini <= LFB_HMIN; + vmini <= LFB_VMIN; + hmaxi <= LFB_HMAX; + vmaxi <= LFB_VMAX; + state <= 0; + end + else if(FREESCALE || !arx || !ary) begin + wcalc <= hdmi_width; + hcalc <= hdmi_height; + state <= 6; + end + else if(xy) begin + wcalc <= arx; + hcalc <= ary; + state <= 6; + end + + 1: begin + ar_md_mul1 <= hdmi_height; + ar_md_mul2 <= arx; + ar_md_div <= ary; + ar_md_start<= 1; + end + 2: begin + wcalc <= ar_md_res; + if(ar_md_start | ar_md_busy) state <= 2; + end + + 3: begin + ar_md_mul1 <= hdmi_width; + ar_md_mul2 <= ary; + ar_md_div <= arx; + ar_md_start<= 1; + end + 4: begin + hcalc <= ar_md_res; + if(ar_md_start | ar_md_busy) state <= 4; + end + + 6: begin + videow <= (wcalc > hdmi_width) ? hdmi_width : wcalc[11:0]; + videoh <= (hcalc > hdmi_height) ? hdmi_height : hcalc[11:0]; + end + + 7: begin + hmini <= ((WIDTH - videow)>>1); + hmaxi <= ((WIDTH - videow)>>1) + videow - 1'd1; + vmini <= ((HEIGHT - videoh)>>1); + vmaxi <= ((HEIGHT - videoh)>>1) + videoh - 1'd1; + end + endcase + + hmin <= hmini; + hmax <= hmaxi; + vmin <= vmini; + vmax <= vmaxi; +end + +`ifndef DEBUG_NOHDMI +wire [15:0] lltune; +pll_hdmi_adj pll_hdmi_adj +( + .clk(FPGA_CLK1_50), + .reset_na(~reset_req), + + .llena(lowlat), + .lltune({16{hdmi_config_done | cfg_dis}} & lltune), + .locked(led_locked), + .i_waitrequest(adj_waitrequest), + .i_write(adj_write), + .i_address(adj_address), + .i_writedata(adj_data), + .o_waitrequest(cfg_waitrequest), + .o_write(cfg_write), + .o_address(cfg_address), + .o_writedata(cfg_data) +); +`else + assign led_locked = 0; +`endif + +wire [63:0] pal_data; +wire [47:0] pal_d = {pal_data[55:32], pal_data[23:0]}; +wire [6:0] pal_a = ram2_bcnt[6:0]; +wire pal_wr; + +reg [28:0] pal_addr; +reg pal_req = 0; +always @(posedge clk_pal) begin + reg old_vs1, old_vs2; + + pal_addr <= LFB_BASE[31:3] - 29'd512; + + old_vs1 <= hdmi_vs; + old_vs2 <= old_vs1; + + if(~old_vs2 & old_vs1 & ~FB_FMT[2] & FB_FMT[1] & FB_FMT[0] & FB_EN) pal_req <= ~pal_req; +end + + +///////////////////////// HDMI output ///////////////////////////////// +`ifndef DEBUG_NOHDMI +wire hdmi_clk_out; +pll_hdmi pll_hdmi +( + .refclk(FPGA_CLK1_50), + .rst(reset_req), + .reconfig_to_pll(reconfig_to_pll), + .reconfig_from_pll(reconfig_from_pll), + .outclk_0(hdmi_clk_out) +); +`endif + +//1920x1080@60 PCLK=148.5MHz CEA +reg [11:0] WIDTH = 1920; +reg [11:0] HFP = 88; +reg [11:0] HS = 48; +reg [11:0] HBP = 148; +reg [11:0] HEIGHT = 1080; +reg [11:0] VFP = 4; +reg [11:0] VS = 5; +reg [11:0] VBP = 36; + +wire [63:0] reconfig_to_pll; +wire [63:0] reconfig_from_pll; +wire cfg_waitrequest,adj_waitrequest; +wire cfg_write; +wire [5:0] cfg_address; +wire [31:0] cfg_data; +reg adj_write; +reg [5:0] adj_address; +reg [31:0] adj_data; + +`ifndef DEBUG_NOHDMI +pll_cfg pll_cfg +( + .mgmt_clk(FPGA_CLK1_50), + .mgmt_reset(reset_req), + .mgmt_waitrequest(cfg_waitrequest), + .mgmt_read(0), + .mgmt_readdata(), + .mgmt_write(cfg_write), + .mgmt_address(cfg_address), + .mgmt_writedata(cfg_data), + .reconfig_to_pll(reconfig_to_pll), + .reconfig_from_pll(reconfig_from_pll) +); + +reg cfg_got = 0; +always @(posedge clk_sys) begin + reg vsd, vsd2; + if(~cfg_ready || ~cfg_set) cfg_got <= cfg_set; + else begin + vsd <= HDMI_TX_VS; + vsd2 <= vsd; + if(~vsd2 & vsd) cfg_got <= cfg_set; + end +end + +reg cfg_ready = 0; +always @(posedge FPGA_CLK1_50) begin + reg gotd = 0, gotd2 = 0; + reg custd = 0, custd2 = 0; + reg old_wait = 0; + + gotd <= cfg_got; + gotd2 <= gotd; + + adj_write <= 0; + + custd <= cfg_custom_t; + custd2 <= custd; + if(custd2 != custd & ~gotd) begin + adj_address <= cfg_custom_p1; + adj_data <= cfg_custom_p2; + adj_write <= 1; + end + + if(~gotd2 & gotd) begin + adj_address <= 2; + adj_data <= 0; + adj_write <= 1; + end + + old_wait <= adj_waitrequest; + if(old_wait & ~adj_waitrequest & gotd) cfg_ready <= 1; +end + +`else + +wire cfg_ready = 1; + +`endif + +wire hdmi_config_done; +hdmi_config hdmi_config +( + .iCLK(FPGA_CLK1_50), + .iRST_N(cfg_ready & ~HDMI_TX_INT & ~cfg_dis), + .done(hdmi_config_done), + + .I2C_SCL(HDMI_I2C_SCL), + .I2C_SDA(HDMI_I2C_SDA), + + .dvi_mode(dvi_mode), + .audio_96k(audio_96k), + .limited(hdmi_limited), + .ypbpr(ypbpr_en & direct_video) +); + +assign HDMI_I2C_SCL = hdmi_scl_en ? 1'b0 : 1'bZ; +assign HDMI_I2C_SDA = hdmi_sda_en ? 1'b0 : 1'bZ; + +wire hdmi_scl_en, hdmi_sda_en; +cyclonev_hps_interface_peripheral_i2c hdmi_i2c +( + .out_clk(hdmi_scl_en), + .scl(HDMI_I2C_SCL), + .out_data(hdmi_sda_en), + .sda(HDMI_I2C_SDA) +); + +`ifndef DEBUG_NOHDMI +wire [23:0] hdmi_data_sl; +wire hdmi_de_sl, hdmi_vs_sl, hdmi_hs_sl; + +`ifdef USE_FB +reg dis_output; +always @(posedge clk_hdmi) begin + reg dis; + dis <= fb_force_blank; + dis_output <= dis; +end +`else +wire dis_output = 0; +`endif + +scanlines #(1) HDMI_scanlines +( + .clk(clk_hdmi), + + .scanlines(scanlines), + .din(dis_output ? 24'd0 : hdmi_data), + .hs_in(hdmi_hs), + .vs_in(hdmi_vs), + .de_in(hdmi_de), + + .dout(hdmi_data_sl), + .hs_out(hdmi_hs_sl), + .vs_out(hdmi_vs_sl), + .de_out(hdmi_de_sl) +); + +wire [23:0] hdmi_data_osd; +wire hdmi_de_osd, hdmi_vs_osd, hdmi_hs_osd; + +osd hdmi_osd +( + .clk_sys(clk_sys), + + .io_osd(io_osd_hdmi), + .io_strobe(io_strobe), + .io_din(io_din), + + .clk_video(clk_hdmi), + .din(hdmi_data_sl), + .hs_in(hdmi_hs_sl), + .vs_in(hdmi_vs_sl), + .de_in(hdmi_de_sl), + + .dout(hdmi_data_osd), + .hs_out(hdmi_hs_osd), + .vs_out(hdmi_vs_osd), + .de_out(hdmi_de_osd) +`ifndef ARCADE_SYS + , + .osd_status(osd_status) +`endif +); +`endif + +wire hdmi_cs_osd; +csync csync_hdmi(clk_hdmi, hdmi_hs_osd, hdmi_vs_osd, hdmi_cs_osd); + +reg [23:0] dv_data; +reg dv_hs, dv_vs, dv_de; +always @(posedge clk_vid) begin + reg [23:0] dv_d1, dv_d2; + reg dv_de1, dv_de2, dv_hs1, dv_hs2, dv_vs1, dv_vs2; + reg [12:0] vsz, vcnt; + reg old_hs, old_vs; + reg vde; + reg [3:0] hss; + + if(ce_pix) begin + hss <= (hss << 1) | vga_hs_osd; + + old_hs <= vga_hs_osd; + if(~old_hs && vga_hs_osd) begin + old_vs <= vga_vs_osd; + if(~&vcnt) vcnt <= vcnt + 1'd1; + if(~old_vs & vga_vs_osd & ~f1) vsz <= vcnt; + if(old_vs & ~vga_vs_osd) vcnt <= 0; + + if(vcnt == 1) vde <= 1; + if(vcnt == vsz - 3) vde <= 0; + end + + dv_de1 <= !{hss,vga_hs_osd} && vde; + dv_hs1 <= csync_en ? vga_cs_osd : vga_hs_osd; + dv_vs1 <= vga_vs_osd; + end + + dv_d1 <= vga_data_osd; + dv_d2 <= dv_d1; + dv_de2 <= dv_de1; + dv_hs2 <= dv_hs1; + dv_vs2 <= dv_vs1; + + dv_data<= dv_d2; + dv_de <= dv_de2; + dv_hs <= dv_hs2; + dv_vs <= dv_vs2; +end + +wire hdmi_tx_clk; +`ifndef DEBUG_NOHDMI +cyclonev_clkselect hdmi_clk_sw +( + .clkselect({1'b1, ~vga_fb & direct_video}), + .inclk({clk_vid, hdmi_clk_out, 2'b00}), + .outclk(hdmi_tx_clk) +); +`else +assign hdmi_tx_clk = clk_vid; +`endif + +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) +) +hdmiclk_ddr +( + .datain_h(1'b0), + .datain_l(1'b1), + .outclock(hdmi_tx_clk), + .dataout(HDMI_TX_CLK), + .aclr(1'b0), + .aset(1'b0), + .oe(1'b1), + .outclocken(1'b1), + .sclr(1'b0), + .sset(1'b0) +); + +reg hdmi_out_hs; +reg hdmi_out_vs; +reg hdmi_out_de; +reg [23:0] hdmi_out_d; + +always @(posedge hdmi_tx_clk) begin + reg hs,vs,de; + reg [23:0] d; + + hs <= (~vga_fb & direct_video) ? dv_hs : (direct_video & csync_en) ? hdmi_cs_osd : hdmi_hs_osd; + vs <= (~vga_fb & direct_video) ? dv_vs : hdmi_vs_osd; + de <= (~vga_fb & direct_video) ? dv_de : hdmi_de_osd; + d <= (~vga_fb & direct_video) ? dv_data : hdmi_data_osd; + + hdmi_out_hs <= hs; + hdmi_out_vs <= vs; + hdmi_out_de <= de; + hdmi_out_d <= d; +end + +assign HDMI_TX_HS = hdmi_out_hs; +assign HDMI_TX_VS = hdmi_out_vs; +assign HDMI_TX_DE = hdmi_out_de; +assign HDMI_TX_D = hdmi_out_d; + +///////////////////////// VGA output ////////////////////////////////// + +wire [23:0] vga_data_sl; +wire vga_de_sl, vga_vs_sl, vga_hs_sl; +scanlines #(0) VGA_scanlines +( + .clk(clk_vid), + + .scanlines(scanlines), + .din(de_emu ? {r_out, g_out, b_out} : 24'd0), + .hs_in(hs_fix), + .vs_in(vs_fix), + .de_in(de_emu), + + .dout(vga_data_sl), + .hs_out(vga_hs_sl), + .vs_out(vga_vs_sl), + .de_out(vga_de_sl) +); + +wire [23:0] vga_data_osd; +wire vga_vs_osd, vga_hs_osd; +osd vga_osd +( + .clk_sys(clk_sys), + + .io_osd(io_osd_vga), + .io_strobe(io_strobe), + .io_din(io_din), + + .clk_video(clk_vid), + .din(vga_data_sl), + .hs_in(vga_hs_sl), + .vs_in(vga_vs_sl), + .de_in(vga_de_sl), + + .dout(vga_data_osd), + .hs_out(vga_hs_osd), + .vs_out(vga_vs_osd) +); + +wire vga_cs_osd; +csync csync_vga(clk_vid, vga_hs_osd, vga_vs_osd, vga_cs_osd); + +`ifndef DUAL_SDRAM + wire [23:0] vgas_o; + wire vgas_hs, vgas_vs, vgas_cs; + vga_out vga_scaler_out + ( + .clk(clk_hdmi), + .ypbpr_en(ypbpr_en), + .hsync(hdmi_hs_osd), + .vsync(hdmi_vs_osd), + .csync(hdmi_cs_osd), + .dout(vgas_o), + .din({24{hdmi_de_osd}} & hdmi_data_osd), + .hsync_o(vgas_hs), + .vsync_o(vgas_vs), + .csync_o(vgas_cs) + ); + + wire [23:0] vga_o; + wire vga_hs, vga_vs, vga_cs; + vga_out vga_out + ( + .clk(clk_vid), + .ypbpr_en(ypbpr_en), + .hsync(vga_hs_osd), + .vsync(vga_vs_osd), + .csync(vga_cs_osd), + .dout(vga_o), + .din(vga_data_osd), + .hsync_o(vga_hs), + .vsync_o(vga_vs), + .csync_o(vga_cs) + ); + + wire cs1 = (vga_fb | vga_scaler) ? vgas_cs : vga_cs; + + assign VGA_VS = (VGA_EN | SW[3]) ? 1'bZ : ((vga_fb | vga_scaler) ? ~vgas_vs : ~vga_vs) | csync_en; + assign VGA_HS = (VGA_EN | SW[3]) ? 1'bZ : (vga_fb | vga_scaler) ? (csync_en ? ~vgas_cs : ~vgas_hs) : (csync_en ? ~vga_cs : ~vga_hs); + assign VGA_R = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[23:18] : vga_o[23:18]; + assign VGA_G = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[15:10] : vga_o[15:10]; + assign VGA_B = (VGA_EN | SW[3]) ? 6'bZZZZZZ : (vga_fb | vga_scaler) ? vgas_o[7:2] : vga_o[7:2] ; +`endif + +reg video_sync = 0; +always @(posedge clk_vid) begin + reg [11:0] line_cnt = 0; + reg [11:0] sync_line = 0; + reg [1:0] hs_cnt = 0; + reg old_hs; + + old_hs <= hs_fix; + if(~old_hs & hs_fix) begin + + video_sync <= (sync_line == line_cnt); + + line_cnt <= line_cnt + 1'd1; + if(~hs_cnt[1]) begin + hs_cnt <= hs_cnt + 1'd1; + if(hs_cnt[0]) begin + sync_line <= (line_cnt - vs_line); + line_cnt <= 0; + end + end + end + + if(de_emu) hs_cnt <= 0; +end + +///////////////////////// Audio output //////////////////////////////// + +assign SDCD_SPDIF =(SW[3] & ~spdif) ? 1'b0 : 1'bZ; + +`ifndef DUAL_SDRAM + wire analog_l, analog_r; + + assign AUDIO_SPDIF = SW[3] ? 1'bZ : SW[0] ? HDMI_LRCLK : spdif; + assign AUDIO_R = SW[3] ? 1'bZ : SW[0] ? HDMI_I2S : analog_r; + assign AUDIO_L = SW[3] ? 1'bZ : SW[0] ? HDMI_SCLK : analog_l; +`endif + +assign HDMI_MCLK = clk_audio; +wire clk_audio; + +pll_audio pll_audio +( + .refclk(FPGA_CLK3_50), + .rst(0), + .outclk_0(clk_audio) +); + +wire spdif; +audio_out audio_out +( + .reset(reset | areset), + .clk(clk_audio), + + .att(vol_att), + .mix(audio_mix), + .sample_rate(audio_96k), + + .flt_rate(aflt_rate), + .cx(acx), + .cx0(acx0), + .cx1(acx1), + .cx2(acx2), + .cy0(acy0), + .cy1(acy1), + .cy2(acy2), + + .is_signed(audio_s), + .core_l(audio_l), + .core_r(audio_r), + + .alsa_l(alsa_l), + .alsa_r(alsa_r), + + .i2s_bclk(HDMI_SCLK), + .i2s_lrclk(HDMI_LRCLK), + .i2s_data(HDMI_I2S), +`ifndef DUAL_SDRAM + .dac_l(analog_l), + .dac_r(analog_r), +`endif + .spdif(spdif) +); + + +wire [28:0] alsa_address; +wire [63:0] alsa_readdata; +wire alsa_ready; +wire alsa_req; +wire alsa_late; + +wire [15:0] alsa_l, alsa_r; + +alsa alsa +( + .reset(reset), + .clk(clk_audio), + + .ram_address(alsa_address), + .ram_data(alsa_readdata), + .ram_req(alsa_req), + .ram_ready(alsa_ready), + + .spi_ss(aspi_ss), + .spi_sck(aspi_sck), + .spi_mosi(aspi_mosi), + .spi_miso(aspi_miso), + + .pcm_l(alsa_l), + .pcm_r(alsa_r) +); + +//////////////// User I/O (USB 3.0 connector) ///////////////////////// + +assign USER_IO[0] = !user_out[0] ? 1'b0 : 1'bZ; +assign USER_IO[1] = !user_out[1] ? 1'b0 : 1'bZ; +assign USER_IO[2] = !(SW[1] ? HDMI_I2S : user_out[2]) ? 1'b0 : 1'bZ; +assign USER_IO[3] = !user_out[3] ? 1'b0 : 1'bZ; +assign USER_IO[4] = !(SW[1] ? HDMI_SCLK : user_out[4]) ? 1'b0 : 1'bZ; +assign USER_IO[5] = !(SW[1] ? HDMI_LRCLK : user_out[5]) ? 1'b0 : 1'bZ; +assign USER_IO[6] = !user_out[6] ? 1'b0 : 1'bZ; + +assign user_in[0] = USER_IO[0]; +assign user_in[1] = USER_IO[1]; +assign user_in[2] = SW[1] | USER_IO[2]; +assign user_in[3] = USER_IO[3]; +assign user_in[4] = SW[1] | USER_IO[4]; +assign user_in[5] = SW[1] | USER_IO[5]; +assign user_in[6] = USER_IO[6]; + + +/////////////////// User module connection //////////////////////////// + +wire clk_sys; +wire [15:0] audio_l, audio_r; +wire audio_s; +wire [1:0] audio_mix; +wire [1:0] scanlines; +wire [7:0] r_out, g_out, b_out, hr_out, hg_out, hb_out; +wire vs_fix, hs_fix, de_emu, vs_emu, hs_emu, f1; +wire hvs_fix, hhs_fix, hde_emu; +wire clk_vid, ce_pix, clk_ihdmi, ce_hpix; +wire vga_force_scaler; + +`ifdef USE_DDRAM + wire ram_clk; + wire [28:0] ram_address; + wire [7:0] ram_burstcount; + wire ram_waitrequest; + wire [63:0] ram_readdata; + wire ram_readdatavalid; + wire ram_read; + wire [63:0] ram_writedata; + wire [7:0] ram_byteenable; + wire ram_write; +`endif + +wire led_user; +wire [1:0] led_power; +wire [1:0] led_disk; +wire [1:0] btn; + +sync_fix sync_v(clk_vid, vs_emu, vs_fix); +sync_fix sync_h(clk_vid, hs_emu, hs_fix); + +wire [6:0] user_out, user_in; + +`ifndef USE_SDRAM +assign {SDRAM_DQ, SDRAM_A, SDRAM_BA, SDRAM_CLK, SDRAM_CKE, SDRAM_DQML, SDRAM_DQMH, SDRAM_nWE, SDRAM_nCAS, SDRAM_nRAS, SDRAM_nCS} = {39'bZ}; +`endif + +assign clk_ihdmi= clk_vid; +assign ce_hpix = ce_pix; +assign hr_out = r_out; +assign hg_out = g_out; +assign hb_out = b_out; +assign hhs_fix = hs_fix; +assign hvs_fix = vs_fix; +assign hde_emu = de_emu; + +`ifdef ARCADE_SYS + assign audio_mix = 0; + assign {ADC_SCK, ADC_SDI, ADC_CONVST} = 0; + assign btn = 0; +`else + wire uart_dtr; + wire uart_dsr; + wire uart_cts; + wire uart_rts; + wire uart_rxd; + wire uart_txd; + wire osd_status; +`endif + +wire fb_en; +wire [4:0] fb_fmt; +wire [11:0] fb_width; +wire [11:0] fb_height; +wire [31:0] fb_base; +wire [13:0] fb_stride; + +`ifdef USE_FB + wire fb_pal_clk; + wire [7:0] fb_pal_a; + wire [23:0] fb_pal_d; + wire [23:0] fb_pal_q; + wire fb_pal_wr; + wire fb_force_blank; +`else + assign fb_en = 0; + assign fb_fmt = 0; + assign fb_width = 0; + assign fb_height = 0; + assign fb_base = 0; + assign fb_stride = 0; +`endif + +emu emu +( + .CLK_50M(FPGA_CLK2_50), + .RESET(reset), + .HPS_BUS({f1, HDMI_TX_VS, + clk_100m, clk_ihdmi, + ce_hpix, hde_emu, hhs_fix, hvs_fix, + io_wait, clk_sys, io_fpga, io_uio, io_strobe, io_wide, io_din, io_dout}), + + .VGA_R(r_out), + .VGA_G(g_out), + .VGA_B(b_out), + .VGA_HS(hs_emu), + .VGA_VS(vs_emu), + .VGA_DE(de_emu), + .VGA_F1(f1), + .VGA_SCALER(vga_force_scaler), + + .HDMI_WIDTH(direct_video ? 12'd0 : hdmi_width), + .HDMI_HEIGHT(direct_video ? 12'd0 : hdmi_height), + + .CLK_VIDEO(clk_vid), + .CE_PIXEL(ce_pix), + .VGA_SL(scanlines), + .VIDEO_ARX(ARX), + .VIDEO_ARY(ARY), + +`ifdef USE_FB + .FB_EN(fb_en), + .FB_FORMAT(fb_fmt), + .FB_WIDTH(fb_width), + .FB_HEIGHT(fb_height), + .FB_BASE(fb_base), + .FB_STRIDE(fb_stride), + .FB_VBL(fb_vbl), + .FB_LL(lowlat), + .FB_FORCE_BLANK(fb_force_blank), + + .FB_PAL_CLK (fb_pal_clk), + .FB_PAL_ADDR(fb_pal_a), + .FB_PAL_DOUT(fb_pal_d), + .FB_PAL_DIN (fb_pal_q), + .FB_PAL_WR (fb_pal_wr), +`endif + + .LED_USER(led_user), + .LED_POWER(led_power), + .LED_DISK(led_disk), + + .CLK_AUDIO(clk_audio), + .AUDIO_L(audio_l), + .AUDIO_R(audio_r), + .AUDIO_S(audio_s), + +`ifndef ARCADE_SYS + .AUDIO_MIX(audio_mix), + .ADC_BUS({ADC_SCK,ADC_SDO,ADC_SDI,ADC_CONVST}), +`endif + +`ifdef USE_DDRAM + .DDRAM_CLK(ram_clk), + .DDRAM_ADDR(ram_address), + .DDRAM_BURSTCNT(ram_burstcount), + .DDRAM_BUSY(ram_waitrequest), + .DDRAM_DOUT(ram_readdata), + .DDRAM_DOUT_READY(ram_readdatavalid), + .DDRAM_RD(ram_read), + .DDRAM_DIN(ram_writedata), + .DDRAM_BE(ram_byteenable), + .DDRAM_WE(ram_write), +`endif + +`ifdef USE_SDRAM + .SDRAM_DQ(SDRAM_DQ), + .SDRAM_A(SDRAM_A), + .SDRAM_DQML(SDRAM_DQML), + .SDRAM_DQMH(SDRAM_DQMH), + .SDRAM_BA(SDRAM_BA), + .SDRAM_nCS(SDRAM_nCS), + .SDRAM_nWE(SDRAM_nWE), + .SDRAM_nRAS(SDRAM_nRAS), + .SDRAM_nCAS(SDRAM_nCAS), + .SDRAM_CLK(SDRAM_CLK), + .SDRAM_CKE(SDRAM_CKE), +`endif + +`ifdef DUAL_SDRAM + .SDRAM2_DQ(SDRAM2_DQ), + .SDRAM2_A(SDRAM2_A), + .SDRAM2_BA(SDRAM2_BA), + .SDRAM2_nCS(SDRAM2_nCS), + .SDRAM2_nWE(SDRAM2_nWE), + .SDRAM2_nRAS(SDRAM2_nRAS), + .SDRAM2_nCAS(SDRAM2_nCAS), + .SDRAM2_CLK(SDRAM2_CLK), + .SDRAM2_EN(SW[3]), +`endif + +`ifndef ARCADE_SYS + .BUTTONS(btn), + .OSD_STATUS(osd_status), + .SD_SCK(SD_CLK), + .SD_MOSI(SD_MOSI), + .SD_MISO(SD_MISO), + .SD_CS(SD_CS), +`ifdef DUAL_SDRAM + .SD_CD(mcp_sdcd), +`else + .SD_CD(mcp_sdcd & (SW[0] ? VGA_HS : (SW[3] | SDCD_SPDIF))), +`endif + + .UART_CTS(uart_rts), + .UART_RTS(uart_cts), + .UART_RXD(uart_txd), + .UART_TXD(uart_rxd), + .UART_DTR(uart_dsr), + .UART_DSR(uart_dtr), +`endif + + .USER_OUT(user_out), + .USER_IN(user_in) +); + +endmodule + +///////////////////////////////////////////////////////////////////// + +module sync_fix +( + input clk, + + input sync_in, + output sync_out +); + +assign sync_out = sync_in ^ pol; + +reg pol; +always @(posedge clk) begin + integer pos = 0, neg = 0, cnt = 0; + reg s1,s2; + + s1 <= sync_in; + s2 <= s1; + + if(~s2 & s1) neg <= cnt; + if(s2 & ~s1) pos <= cnt; + + cnt <= cnt + 1; + if(s2 != s1) cnt <= 0; + + pol <= pos > neg; +end + +endmodule + +///////////////////////////////////////////////////////////////////// + +// CSync generation +// Shifts HSync left by 1 HSync period during VSync + +module csync +( + input clk, + input hsync, + input vsync, + + output csync +); + +assign csync = (csync_vs ^ csync_hs); + +reg csync_hs, csync_vs; +always @(posedge clk) begin + reg prev_hs; + reg [15:0] h_cnt, line_len, hs_len; + + // Count line/Hsync length + h_cnt <= h_cnt + 1'd1; + + prev_hs <= hsync; + if (prev_hs ^ hsync) begin + h_cnt <= 0; + if (hsync) begin + line_len <= h_cnt - hs_len; + csync_hs <= 0; + end + else hs_len <= h_cnt; + end + + if (~vsync) csync_hs <= hsync; + else if(h_cnt == line_len) csync_hs <= 1; + + csync_vs <= vsync; +end + +endmodule diff --git a/sys/sysmem.sv b/sys/sysmem.sv new file mode 100644 index 0000000..8c17e86 --- /dev/null +++ b/sys/sysmem.sv @@ -0,0 +1,570 @@ +`timescale 1 ps / 1 ps +module sysmem_lite +( + output clock, + output reset_out, + + input reset_hps_cold_req, + input reset_hps_warm_req, + input reset_core_req, + + input ram1_clk, + input [28:0] ram1_address, + input [7:0] ram1_burstcount, + output ram1_waitrequest, + output [63:0] ram1_readdata, + output ram1_readdatavalid, + input ram1_read, + input [63:0] ram1_writedata, + input [7:0] ram1_byteenable, + input ram1_write, + + input ram2_clk, + input [28:0] ram2_address, + input [7:0] ram2_burstcount, + output ram2_waitrequest, + output [63:0] ram2_readdata, + output ram2_readdatavalid, + input ram2_read, + input [63:0] ram2_writedata, + input [7:0] ram2_byteenable, + input ram2_write, + + input vbuf_clk, + input [27:0] vbuf_address, + input [7:0] vbuf_burstcount, + output vbuf_waitrequest, + output [127:0] vbuf_readdata, + output vbuf_readdatavalid, + input vbuf_read, + input [127:0] vbuf_writedata, + input [15:0] vbuf_byteenable, + input vbuf_write +); + +assign reset_out = ~init_reset_n | ~hps_h2f_reset_n | reset_core_req; + +//////////////////////////////////////////////////////// +//// f2sdram_safe_terminator_ram1 //// +//////////////////////////////////////////////////////// +wire [28:0] f2h_ram1_address; +wire [7:0] f2h_ram1_burstcount; +wire f2h_ram1_waitrequest; +wire [63:0] f2h_ram1_readdata; +wire f2h_ram1_readdatavalid; +wire f2h_ram1_read; +wire [63:0] f2h_ram1_writedata; +wire [7:0] f2h_ram1_byteenable; +wire f2h_ram1_write; + +(* altera_attribute = {"-name SYNCHRONIZER_IDENTIFICATION FORCED_IF_ASYNCHRONOUS"} *) reg ram1_reset_0 = 1'b1; +(* altera_attribute = {"-name SYNCHRONIZER_IDENTIFICATION FORCED_IF_ASYNCHRONOUS"} *) reg ram1_reset_1 = 1'b1; +always @(posedge ram1_clk) begin + ram1_reset_0 <= reset_out; + ram1_reset_1 <= ram1_reset_0; +end + +f2sdram_safe_terminator #(64, 8) f2sdram_safe_terminator_ram1 +( + .clk (ram1_clk), + .rst_req_sync (ram1_reset_1), + + .waitrequest_slave (ram1_waitrequest), + .burstcount_slave (ram1_burstcount), + .address_slave (ram1_address), + .readdata_slave (ram1_readdata), + .readdatavalid_slave (ram1_readdatavalid), + .read_slave (ram1_read), + .writedata_slave (ram1_writedata), + .byteenable_slave (ram1_byteenable), + .write_slave (ram1_write), + + .waitrequest_master (f2h_ram1_waitrequest), + .burstcount_master (f2h_ram1_burstcount), + .address_master (f2h_ram1_address), + .readdata_master (f2h_ram1_readdata), + .readdatavalid_master (f2h_ram1_readdatavalid), + .read_master (f2h_ram1_read), + .writedata_master (f2h_ram1_writedata), + .byteenable_master (f2h_ram1_byteenable), + .write_master (f2h_ram1_write) +); + +//////////////////////////////////////////////////////// +//// f2sdram_safe_terminator_ram2 //// +//////////////////////////////////////////////////////// +wire [28:0] f2h_ram2_address; +wire [7:0] f2h_ram2_burstcount; +wire f2h_ram2_waitrequest; +wire [63:0] f2h_ram2_readdata; +wire f2h_ram2_readdatavalid; +wire f2h_ram2_read; +wire [63:0] f2h_ram2_writedata; +wire [7:0] f2h_ram2_byteenable; +wire f2h_ram2_write; + +(* altera_attribute = {"-name SYNCHRONIZER_IDENTIFICATION FORCED_IF_ASYNCHRONOUS"} *) reg ram2_reset_0 = 1'b1; +(* altera_attribute = {"-name SYNCHRONIZER_IDENTIFICATION FORCED_IF_ASYNCHRONOUS"} *) reg ram2_reset_1 = 1'b1; +always @(posedge ram2_clk) begin + ram2_reset_0 <= reset_out; + ram2_reset_1 <= ram2_reset_0; +end + +f2sdram_safe_terminator #(64, 8) f2sdram_safe_terminator_ram2 +( + .clk (ram2_clk), + .rst_req_sync (ram2_reset_1), + + .waitrequest_slave (ram2_waitrequest), + .burstcount_slave (ram2_burstcount), + .address_slave (ram2_address), + .readdata_slave (ram2_readdata), + .readdatavalid_slave (ram2_readdatavalid), + .read_slave (ram2_read), + .writedata_slave (ram2_writedata), + .byteenable_slave (ram2_byteenable), + .write_slave (ram2_write), + + .waitrequest_master (f2h_ram2_waitrequest), + .burstcount_master (f2h_ram2_burstcount), + .address_master (f2h_ram2_address), + .readdata_master (f2h_ram2_readdata), + .readdatavalid_master (f2h_ram2_readdatavalid), + .read_master (f2h_ram2_read), + .writedata_master (f2h_ram2_writedata), + .byteenable_master (f2h_ram2_byteenable), + .write_master (f2h_ram2_write) +); + +//////////////////////////////////////////////////////// +//// f2sdram_safe_terminator_vbuf //// +//////////////////////////////////////////////////////// +wire [27:0] f2h_vbuf_address; +wire [7:0] f2h_vbuf_burstcount; +wire f2h_vbuf_waitrequest; +wire [127:0] f2h_vbuf_readdata; +wire f2h_vbuf_readdatavalid; +wire f2h_vbuf_read; +wire [127:0] f2h_vbuf_writedata; +wire [15:0] f2h_vbuf_byteenable; +wire f2h_vbuf_write; + +(* altera_attribute = {"-name SYNCHRONIZER_IDENTIFICATION FORCED_IF_ASYNCHRONOUS"} *) reg vbuf_reset_0 = 1'b1; +(* altera_attribute = {"-name SYNCHRONIZER_IDENTIFICATION FORCED_IF_ASYNCHRONOUS"} *) reg vbuf_reset_1 = 1'b1; +always @(posedge vbuf_clk) begin + vbuf_reset_0 <= reset_out; + vbuf_reset_1 <= vbuf_reset_0; +end + +f2sdram_safe_terminator #(128, 8) f2sdram_safe_terminator_vbuf +( + .clk (vbuf_clk), + .rst_req_sync (vbuf_reset_1), + + .waitrequest_slave (vbuf_waitrequest), + .burstcount_slave (vbuf_burstcount), + .address_slave (vbuf_address), + .readdata_slave (vbuf_readdata), + .readdatavalid_slave (vbuf_readdatavalid), + .read_slave (vbuf_read), + .writedata_slave (vbuf_writedata), + .byteenable_slave (vbuf_byteenable), + .write_slave (vbuf_write), + + .waitrequest_master (f2h_vbuf_waitrequest), + .burstcount_master (f2h_vbuf_burstcount), + .address_master (f2h_vbuf_address), + .readdata_master (f2h_vbuf_readdata), + .readdatavalid_master (f2h_vbuf_readdatavalid), + .read_master (f2h_vbuf_read), + .writedata_master (f2h_vbuf_writedata), + .byteenable_master (f2h_vbuf_byteenable), + .write_master (f2h_vbuf_write) +); + +//////////////////////////////////////////////////////// +//// HPS <> FPGA interfaces //// +//////////////////////////////////////////////////////// +sysmem_HPS_fpga_interfaces fpga_interfaces ( + .f2h_cold_rst_req_n (~reset_hps_cold_req), + .f2h_warm_rst_req_n (~reset_hps_warm_req), + .h2f_user0_clk (clock), + .h2f_rst_n (hps_h2f_reset_n), + .f2h_sdram0_clk (vbuf_clk), + .f2h_sdram0_ADDRESS (f2h_vbuf_address), + .f2h_sdram0_BURSTCOUNT (f2h_vbuf_burstcount), + .f2h_sdram0_WAITREQUEST (f2h_vbuf_waitrequest), + .f2h_sdram0_READDATA (f2h_vbuf_readdata), + .f2h_sdram0_READDATAVALID (f2h_vbuf_readdatavalid), + .f2h_sdram0_READ (f2h_vbuf_read), + .f2h_sdram0_WRITEDATA (f2h_vbuf_writedata), + .f2h_sdram0_BYTEENABLE (f2h_vbuf_byteenable), + .f2h_sdram0_WRITE (f2h_vbuf_write), + .f2h_sdram1_clk (ram1_clk), + .f2h_sdram1_ADDRESS (f2h_ram1_address), + .f2h_sdram1_BURSTCOUNT (f2h_ram1_burstcount), + .f2h_sdram1_WAITREQUEST (f2h_ram1_waitrequest), + .f2h_sdram1_READDATA (f2h_ram1_readdata), + .f2h_sdram1_READDATAVALID (f2h_ram1_readdatavalid), + .f2h_sdram1_READ (f2h_ram1_read), + .f2h_sdram1_WRITEDATA (f2h_ram1_writedata), + .f2h_sdram1_BYTEENABLE (f2h_ram1_byteenable), + .f2h_sdram1_WRITE (f2h_ram1_write), + .f2h_sdram2_clk (ram2_clk), + .f2h_sdram2_ADDRESS (f2h_ram2_address), + .f2h_sdram2_BURSTCOUNT (f2h_ram2_burstcount), + .f2h_sdram2_WAITREQUEST (f2h_ram2_waitrequest), + .f2h_sdram2_READDATA (f2h_ram2_readdata), + .f2h_sdram2_READDATAVALID (f2h_ram2_readdatavalid), + .f2h_sdram2_READ (f2h_ram2_read), + .f2h_sdram2_WRITEDATA (f2h_ram2_writedata), + .f2h_sdram2_BYTEENABLE (f2h_ram2_byteenable), + .f2h_sdram2_WRITE (f2h_ram2_write) +); + +wire hps_h2f_reset_n; + +reg init_reset_n = 0; +always @(posedge clock) begin + integer timeout = 0; + + if(timeout < 2000000) begin + init_reset_n <= 0; + timeout <= timeout + 1; + end + else init_reset_n <= 1; +end + +endmodule + + +module sysmem_HPS_fpga_interfaces +( + // h2f_reset + output wire [1 - 1 : 0 ] h2f_rst_n + + // f2h_cold_reset_req + ,input wire [1 - 1 : 0 ] f2h_cold_rst_req_n + + // f2h_warm_reset_req + ,input wire [1 - 1 : 0 ] f2h_warm_rst_req_n + + // h2f_user0_clock + ,output wire [1 - 1 : 0 ] h2f_user0_clk + + // f2h_sdram0_data + ,input wire [28 - 1 : 0 ] f2h_sdram0_ADDRESS + ,input wire [8 - 1 : 0 ] f2h_sdram0_BURSTCOUNT + ,output wire [1 - 1 : 0 ] f2h_sdram0_WAITREQUEST + ,output wire [128 - 1 : 0 ] f2h_sdram0_READDATA + ,output wire [1 - 1 : 0 ] f2h_sdram0_READDATAVALID + ,input wire [1 - 1 : 0 ] f2h_sdram0_READ + ,input wire [128 - 1 : 0 ] f2h_sdram0_WRITEDATA + ,input wire [16 - 1 : 0 ] f2h_sdram0_BYTEENABLE + ,input wire [1 - 1 : 0 ] f2h_sdram0_WRITE + + // f2h_sdram0_clock + ,input wire [1 - 1 : 0 ] f2h_sdram0_clk + + // f2h_sdram1_data + ,input wire [29 - 1 : 0 ] f2h_sdram1_ADDRESS + ,input wire [8 - 1 : 0 ] f2h_sdram1_BURSTCOUNT + ,output wire [1 - 1 : 0 ] f2h_sdram1_WAITREQUEST + ,output wire [64 - 1 : 0 ] f2h_sdram1_READDATA + ,output wire [1 - 1 : 0 ] f2h_sdram1_READDATAVALID + ,input wire [1 - 1 : 0 ] f2h_sdram1_READ + ,input wire [64 - 1 : 0 ] f2h_sdram1_WRITEDATA + ,input wire [8 - 1 : 0 ] f2h_sdram1_BYTEENABLE + ,input wire [1 - 1 : 0 ] f2h_sdram1_WRITE + + // f2h_sdram1_clock + ,input wire [1 - 1 : 0 ] f2h_sdram1_clk + + // f2h_sdram2_data + ,input wire [29 - 1 : 0 ] f2h_sdram2_ADDRESS + ,input wire [8 - 1 : 0 ] f2h_sdram2_BURSTCOUNT + ,output wire [1 - 1 : 0 ] f2h_sdram2_WAITREQUEST + ,output wire [64 - 1 : 0 ] f2h_sdram2_READDATA + ,output wire [1 - 1 : 0 ] f2h_sdram2_READDATAVALID + ,input wire [1 - 1 : 0 ] f2h_sdram2_READ + ,input wire [64 - 1 : 0 ] f2h_sdram2_WRITEDATA + ,input wire [8 - 1 : 0 ] f2h_sdram2_BYTEENABLE + ,input wire [1 - 1 : 0 ] f2h_sdram2_WRITE + + // f2h_sdram2_clock + ,input wire [1 - 1 : 0 ] f2h_sdram2_clk +); + + +wire [29 - 1 : 0] intermediate; +assign intermediate[0:0] = ~intermediate[1:1]; +assign intermediate[8:8] = intermediate[4:4]|intermediate[7:7]; +assign intermediate[2:2] = intermediate[9:9]; +assign intermediate[3:3] = intermediate[9:9]; +assign intermediate[5:5] = intermediate[9:9]; +assign intermediate[6:6] = intermediate[9:9]; +assign intermediate[10:10] = intermediate[9:9]; +assign intermediate[11:11] = ~intermediate[12:12]; +assign intermediate[17:17] = intermediate[14:14]|intermediate[16:16]; +assign intermediate[13:13] = intermediate[18:18]; +assign intermediate[15:15] = intermediate[18:18]; +assign intermediate[19:19] = intermediate[18:18]; +assign intermediate[20:20] = ~intermediate[21:21]; +assign intermediate[26:26] = intermediate[23:23]|intermediate[25:25]; +assign intermediate[22:22] = intermediate[27:27]; +assign intermediate[24:24] = intermediate[27:27]; +assign intermediate[28:28] = intermediate[27:27]; +assign f2h_sdram0_WAITREQUEST[0:0] = intermediate[0:0]; +assign f2h_sdram1_WAITREQUEST[0:0] = intermediate[11:11]; +assign f2h_sdram2_WAITREQUEST[0:0] = intermediate[20:20]; +assign intermediate[4:4] = f2h_sdram0_READ[0:0]; +assign intermediate[7:7] = f2h_sdram0_WRITE[0:0]; +assign intermediate[9:9] = f2h_sdram0_clk[0:0]; +assign intermediate[14:14] = f2h_sdram1_READ[0:0]; +assign intermediate[16:16] = f2h_sdram1_WRITE[0:0]; +assign intermediate[18:18] = f2h_sdram1_clk[0:0]; +assign intermediate[23:23] = f2h_sdram2_READ[0:0]; +assign intermediate[25:25] = f2h_sdram2_WRITE[0:0]; +assign intermediate[27:27] = f2h_sdram2_clk[0:0]; + +cyclonev_hps_interface_clocks_resets clocks_resets( + .f2h_warm_rst_req_n({ + f2h_warm_rst_req_n[0:0] // 0:0 + }) +,.f2h_pending_rst_ack({ + 1'b1 // 0:0 + }) +,.f2h_dbg_rst_req_n({ + 1'b1 // 0:0 + }) +,.h2f_rst_n({ + h2f_rst_n[0:0] // 0:0 + }) +,.f2h_cold_rst_req_n({ + f2h_cold_rst_req_n[0:0] // 0:0 + }) +,.h2f_user0_clk({ + h2f_user0_clk[0:0] // 0:0 + }) +); + + +cyclonev_hps_interface_dbg_apb debug_apb( + .DBG_APB_DISABLE({ + 1'b0 // 0:0 + }) +,.P_CLK_EN({ + 1'b0 // 0:0 + }) +); + + +cyclonev_hps_interface_tpiu_trace tpiu( + .traceclk_ctl({ + 1'b1 // 0:0 + }) +); + + +cyclonev_hps_interface_boot_from_fpga boot_from_fpga( + .boot_from_fpga_ready({ + 1'b0 // 0:0 + }) +,.boot_from_fpga_on_failure({ + 1'b0 // 0:0 + }) +,.bsel_en({ + 1'b0 // 0:0 + }) +,.csel_en({ + 1'b0 // 0:0 + }) +,.csel({ + 2'b01 // 1:0 + }) +,.bsel({ + 3'b001 // 2:0 + }) +); + + +cyclonev_hps_interface_fpga2hps fpga2hps( + .port_size_config({ + 2'b11 // 1:0 + }) +); + + +cyclonev_hps_interface_hps2fpga hps2fpga( + .port_size_config({ + 2'b11 // 1:0 + }) +); + + +cyclonev_hps_interface_fpga2sdram f2sdram( + .cfg_rfifo_cport_map({ + 16'b0010000100000000 // 15:0 + }) +,.cfg_wfifo_cport_map({ + 16'b0010000100000000 // 15:0 + }) +,.rd_ready_3({ + 1'b1 // 0:0 + }) +,.cmd_port_clk_2({ + intermediate[28:28] // 0:0 + }) +,.rd_ready_2({ + 1'b1 // 0:0 + }) +,.cmd_port_clk_1({ + intermediate[19:19] // 0:0 + }) +,.rd_ready_1({ + 1'b1 // 0:0 + }) +,.cmd_port_clk_0({ + intermediate[10:10] // 0:0 + }) +,.rd_ready_0({ + 1'b1 // 0:0 + }) +,.wrack_ready_2({ + 1'b1 // 0:0 + }) +,.wrack_ready_1({ + 1'b1 // 0:0 + }) +,.wrack_ready_0({ + 1'b1 // 0:0 + }) +,.cmd_ready_2({ + intermediate[21:21] // 0:0 + }) +,.cmd_ready_1({ + intermediate[12:12] // 0:0 + }) +,.cmd_ready_0({ + intermediate[1:1] // 0:0 + }) +,.cfg_port_width({ + 12'b000000010110 // 11:0 + }) +,.rd_valid_3({ + f2h_sdram2_READDATAVALID[0:0] // 0:0 + }) +,.rd_valid_2({ + f2h_sdram1_READDATAVALID[0:0] // 0:0 + }) +,.rd_valid_1({ + f2h_sdram0_READDATAVALID[0:0] // 0:0 + }) +,.rd_clk_3({ + intermediate[22:22] // 0:0 + }) +,.rd_data_3({ + f2h_sdram2_READDATA[63:0] // 63:0 + }) +,.rd_clk_2({ + intermediate[13:13] // 0:0 + }) +,.rd_data_2({ + f2h_sdram1_READDATA[63:0] // 63:0 + }) +,.rd_clk_1({ + intermediate[3:3] // 0:0 + }) +,.rd_data_1({ + f2h_sdram0_READDATA[127:64] // 63:0 + }) +,.rd_clk_0({ + intermediate[2:2] // 0:0 + }) +,.rd_data_0({ + f2h_sdram0_READDATA[63:0] // 63:0 + }) +,.cfg_axi_mm_select({ + 6'b000000 // 5:0 + }) +,.cmd_valid_2({ + intermediate[26:26] // 0:0 + }) +,.cmd_valid_1({ + intermediate[17:17] // 0:0 + }) +,.cmd_valid_0({ + intermediate[8:8] // 0:0 + }) +,.cfg_cport_rfifo_map({ + 18'b000000000011010000 // 17:0 + }) +,.wr_data_3({ + 2'b00 // 89:88 + ,f2h_sdram2_BYTEENABLE[7:0] // 87:80 + ,16'b0000000000000000 // 79:64 + ,f2h_sdram2_WRITEDATA[63:0] // 63:0 + }) +,.wr_data_2({ + 2'b00 // 89:88 + ,f2h_sdram1_BYTEENABLE[7:0] // 87:80 + ,16'b0000000000000000 // 79:64 + ,f2h_sdram1_WRITEDATA[63:0] // 63:0 + }) +,.wr_data_1({ + 2'b00 // 89:88 + ,f2h_sdram0_BYTEENABLE[15:8] // 87:80 + ,16'b0000000000000000 // 79:64 + ,f2h_sdram0_WRITEDATA[127:64] // 63:0 + }) +,.cfg_cport_type({ + 12'b000000111111 // 11:0 + }) +,.wr_data_0({ + 2'b00 // 89:88 + ,f2h_sdram0_BYTEENABLE[7:0] // 87:80 + ,16'b0000000000000000 // 79:64 + ,f2h_sdram0_WRITEDATA[63:0] // 63:0 + }) +,.cfg_cport_wfifo_map({ + 18'b000000000011010000 // 17:0 + }) +,.wr_clk_3({ + intermediate[24:24] // 0:0 + }) +,.wr_clk_2({ + intermediate[15:15] // 0:0 + }) +,.wr_clk_1({ + intermediate[6:6] // 0:0 + }) +,.wr_clk_0({ + intermediate[5:5] // 0:0 + }) +,.cmd_data_2({ + 18'b000000000000000000 // 59:42 + ,f2h_sdram2_BURSTCOUNT[7:0] // 41:34 + ,3'b000 // 33:31 + ,f2h_sdram2_ADDRESS[28:0] // 30:2 + ,intermediate[25:25] // 1:1 + ,intermediate[23:23] // 0:0 + }) +,.cmd_data_1({ + 18'b000000000000000000 // 59:42 + ,f2h_sdram1_BURSTCOUNT[7:0] // 41:34 + ,3'b000 // 33:31 + ,f2h_sdram1_ADDRESS[28:0] // 30:2 + ,intermediate[16:16] // 1:1 + ,intermediate[14:14] // 0:0 + }) +,.cmd_data_0({ + 18'b000000000000000000 // 59:42 + ,f2h_sdram0_BURSTCOUNT[7:0] // 41:34 + ,4'b0000 // 33:30 + ,f2h_sdram0_ADDRESS[27:0] // 29:2 + ,intermediate[7:7] // 1:1 + ,intermediate[4:4] // 0:0 + }) +); + +endmodule diff --git a/sys/vga_out.sv b/sys/vga_out.sv new file mode 100644 index 0000000..43927b2 --- /dev/null +++ b/sys/vga_out.sv @@ -0,0 +1,51 @@ + +module vga_out +( + input clk, + input ypbpr_en, + + input hsync, + input vsync, + input csync, + + input [23:0] din, + output [23:0] dout, + + output reg hsync_o, + output reg vsync_o, + output reg csync_o +); + +wire [5:0] red = din[23:18]; +wire [5:0] green = din[15:10]; +wire [5:0] blue = din[7:2]; + +// http://marsee101.blog19.fc2.com/blog-entry-2311.html +// Y = 16 + 0.257*R + 0.504*G + 0.098*B (Y = 0.299*R + 0.587*G + 0.114*B) +// Pb = 128 - 0.148*R - 0.291*G + 0.439*B (Pb = -0.169*R - 0.331*G + 0.500*B) +// Pr = 128 + 0.439*R - 0.368*G - 0.071*B (Pr = 0.500*R - 0.419*G - 0.081*B) + +reg [18:0] y_2, pb_2, pr_2; +reg [7:0] y, pb, pr; +reg [23:0] din2, din3; +reg hsync2, vsync2, csync2; +always @(posedge clk) begin + y_2 <= 19'd04096 + ({red, 8'd0} + {red, 3'd0}) + ({green, 9'd0} + {green, 2'd0}) + ({blue, 6'd0} + {blue, 5'd0} + {blue, 2'd0}); + pb_2 <= 19'd32768 - ({red, 7'd0} + {red, 4'd0} + {red, 3'd0}) - ({green, 8'd0} + {green, 5'd0} + {green, 3'd0}) + ({blue, 8'd0} + {blue, 7'd0} + {blue, 6'd0}); + pr_2 <= 19'd32768 + ({red, 8'd0} + {red, 7'd0} + {red, 6'd0}) - ({green, 8'd0} + {green, 6'd0} + {green, 5'd0} + {green, 4'd0} + {green, 3'd0}) - ({blue, 6'd0} + {blue , 3'd0}); + + y <= ( y_2[18] || !y_2[17:12]) ? 8'd16 : (y_2[17:8] > 235) ? 8'd235 : y_2[15:8]; + pb <= (pb_2[18] || !pb_2[17:12]) ? 8'd16 : (&pb_2[17:12]) ? 8'd240 : pb_2[15:8]; + pr <= (pr_2[18] || !pr_2[17:12]) ? 8'd16 : (&pr_2[17:12]) ? 8'd240 : pr_2[15:8]; + + hsync_o <= hsync2; hsync2 <= hsync; + vsync_o <= vsync2; vsync2 <= vsync; + csync_o <= csync2; csync2 <= csync; + + din2 <= din; + din3 <= din2; +end + +assign dout = ypbpr_en ? {pr, y, pb} : din3; + +endmodule diff --git a/sys/video_cleaner.sv b/sys/video_cleaner.sv new file mode 100644 index 0000000..b0acbc3 --- /dev/null +++ b/sys/video_cleaner.sv @@ -0,0 +1,99 @@ +// +// +// Copyright (c) 2018 Sorgelig +// +// This program is GPL Licensed. See COPYING for the full license. +// +// +//////////////////////////////////////////////////////////////////////////////////////////////////////// + +`timescale 1ns / 1ps + +module video_cleaner +( + input clk_vid, + input ce_pix, + + input [7:0] R, + input [7:0] G, + input [7:0] B, + + input HSync, + input VSync, + input HBlank, + input VBlank, + + //optional de + input DE_in, + + // video output signals + output reg [7:0] VGA_R, + output reg [7:0] VGA_G, + output reg [7:0] VGA_B, + output reg VGA_VS, + output reg VGA_HS, + output VGA_DE, + + // optional aligned blank + output reg HBlank_out, + output reg VBlank_out, + + // optional aligned de + output reg DE_out +); + +wire hs, vs; +s_fix sync_v(clk_vid, HSync, hs); +s_fix sync_h(clk_vid, VSync, vs); + +wire hbl = hs | HBlank; +wire vbl = vs | VBlank; + +assign VGA_DE = ~(HBlank_out | VBlank_out); + +always @(posedge clk_vid) begin + if(ce_pix) begin + HBlank_out <= hbl; + + VGA_HS <= hs; + if(~VGA_HS & hs) VGA_VS <= vs; + + VGA_R <= R; + VGA_G <= G; + VGA_B <= B; + DE_out <= DE_in; + + if(HBlank_out & ~hbl) VBlank_out <= vbl; + end +end + +endmodule + +module s_fix +( + input clk, + + input sync_in, + output sync_out +); + +assign sync_out = sync_in ^ pol; + +reg pol; +always @(posedge clk) begin + integer pos = 0, neg = 0, cnt = 0; + reg s1,s2; + + s1 <= sync_in; + s2 <= s1; + + if(~s2 & s1) neg <= cnt; + if(s2 & ~s1) pos <= cnt; + + cnt <= cnt + 1; + if(s2 != s1) cnt <= 0; + + pol <= pos > neg; +end + +endmodule diff --git a/sys/video_freak.sv b/sys/video_freak.sv new file mode 100644 index 0000000..18beb03 --- /dev/null +++ b/sys/video_freak.sv @@ -0,0 +1,278 @@ +// +// +// Video crop +// Copyright (c) 2020 Grabulosaure, (c) 2021 Alexey Melnikov +// +// Integer scaling +// Copyright (c) 2021 Alexey Melnikov +// +// This program is GPL Licensed. See COPYING for the full license. +// +// +//////////////////////////////////////////////////////////////////////////////////////////////////////// + +`timescale 1ns / 1ps + +module video_freak +( + input CLK_VIDEO, + input CE_PIXEL, + input VGA_VS, + input [11:0] HDMI_WIDTH, + input [11:0] HDMI_HEIGHT, + output VGA_DE, + output reg [12:0] VIDEO_ARX, + output reg [12:0] VIDEO_ARY, + + input VGA_DE_IN, + input [11:0] ARX, + input [11:0] ARY, + input [11:0] CROP_SIZE, + input [4:0] CROP_OFF, // -16...+15 + input [2:0] SCALE //0 - normal, 1 - V-integer, 2 - HV-Integer-, 3 - HV-Integer+, 4 - HV-Integer +); + +reg mul_start; +wire mul_run; +reg [11:0] mul_arg1, mul_arg2; +wire [23:0] mul_res; +sys_umul #(12,12) mul(CLK_VIDEO,mul_start,mul_run, mul_arg1,mul_arg2,mul_res); + +reg vde; +reg [11:0] arxo,aryo; +reg [11:0] vsize; +reg [11:0] hsize; + +always @(posedge CLK_VIDEO) begin + reg old_de, old_vs,ovde; + reg [11:0] vtot,vcpt,vcrop,voff; + reg [11:0] hcpt; + reg [11:0] vadj; + reg [23:0] ARXG,ARYG; + reg [11:0] arx,ary; + reg [1:0] vcalc; + + if (CE_PIXEL) begin + old_de <= VGA_DE_IN; + old_vs <= VGA_VS; + if (VGA_VS & ~old_vs) begin + vcpt <= 0; + vtot <= vcpt; + vcalc <= 1; + vcrop <= (CROP_SIZE >= vcpt) ? 12'd0 : CROP_SIZE; + end + + if (VGA_DE_IN) hcpt <= hcpt + 1'd1; + if (~VGA_DE_IN & old_de) begin + vcpt <= vcpt + 1'd1; + if(!vcpt) hsize <= hcpt; + hcpt <= 0; + end + end + + arx <= ARX; + ary <= ARY; + + vsize <= vcrop ? vcrop : vtot; + + mul_start <= 0; + + if(!vcrop || !ary || !arx) begin + arxo <= arx; + aryo <= ary; + end + else if (vcalc) begin + if(~mul_start & ~mul_run) begin + vcalc <= vcalc + 1'd1; + case(vcalc) + 1: begin + mul_arg1 <= arx; + mul_arg2 <= vtot; + mul_start <= 1; + end + + 2: begin + ARXG <= mul_res; + mul_arg1 <= ary; + mul_arg2 <= vcrop; + mul_start <= 1; + end + + 3: begin + ARYG <= mul_res; + end + endcase + end + end + else if (ARXG[23] | ARYG[23]) begin + arxo <= ARXG[23:12]; + aryo <= ARYG[23:12]; + end + else begin + ARXG <= ARXG << 1; + ARYG <= ARYG << 1; + end + + vadj <= (vtot-vcrop) + {{6{CROP_OFF[4]}},CROP_OFF,1'b0}; + voff <= vadj[11] ? 12'd0 : ((vadj[11:1] + vcrop) > vtot) ? vtot-vcrop : vadj[11:1]; + ovde <= ((vcpt >= voff) && (vcpt < (vcrop + voff))) || !vcrop; + vde <= ovde; +end + +assign VGA_DE = vde & VGA_DE_IN; + +video_scale_int scale +( + .CLK_VIDEO(CLK_VIDEO), + .HDMI_WIDTH(HDMI_WIDTH), + .HDMI_HEIGHT(HDMI_HEIGHT), + .SCALE(SCALE), + .hsize(hsize), + .vsize(vsize), + .arx_i(arxo), + .ary_i(aryo), + .arx_o(VIDEO_ARX), + .ary_o(VIDEO_ARY) +); + +endmodule + + +module video_scale_int +( + input CLK_VIDEO, + + input [11:0] HDMI_WIDTH, + input [11:0] HDMI_HEIGHT, + + input [2:0] SCALE, + + input [11:0] hsize, + input [11:0] vsize, + + input [11:0] arx_i, + input [11:0] ary_i, + + output reg [12:0] arx_o, + output reg [12:0] ary_o +); + +reg div_start; +wire div_run; +reg [23:0] div_num; +reg [11:0] div_den; +wire [23:0] div_res; +sys_udiv #(24,12) div(CLK_VIDEO,div_start,div_run, div_num,div_den,div_res); + +reg mul_start; +wire mul_run; +reg [11:0] mul_arg1, mul_arg2; +wire [23:0] mul_res; +sys_umul #(12,12) mul(CLK_VIDEO,mul_start,mul_run, mul_arg1,mul_arg2,mul_res); + +wire [11:0] wideres = mul_res[11:0] + hsize; + +always @(posedge CLK_VIDEO) begin + reg [11:0] oheight,wres; + reg [12:0] arxf,aryf; + reg [3:0] cnt; + reg narrow; + + div_start <= 0; + mul_start <= 0; + + if (!SCALE || (!ary_i && arx_i)) begin + arxf <= arx_i; + aryf <= ary_i; + end + else if(~div_start & ~div_run & ~mul_start & ~mul_run) begin + cnt <= cnt + 1'd1; + case(cnt) + 0: begin + div_num <= HDMI_HEIGHT; + div_den <= vsize; + div_start <= 1; + end + + 1: if(!div_res[11:0]) begin + // screen resolution is lower than video resolution. + // Integer scaling is impossible. + arxf <= arx_i; + aryf <= ary_i; + cnt <= 0; + end + else begin + mul_arg1 <= vsize; + mul_arg2 <= div_res[11:0]; + mul_start <= 1; + end + + 2: begin + oheight <= mul_res[11:0]; + if(!ary_i) begin + cnt <= 8; + end + end + + 3: begin + mul_arg1 <= mul_res[11:0]; + mul_arg2 <= arx_i; + mul_start <= 1; + end + + 4: begin + div_num <= mul_res; + div_den <= ary_i; + div_start <= 1; + end + + 5: begin + div_num <= div_res; + div_den <= hsize; + div_start <= 1; + end + + 6: begin + mul_arg1 <= hsize; + mul_arg2 <= div_res[11:0] ? div_res[11:0] : 12'd1; + mul_start <= 1; + end + + 7: if(mul_res <= HDMI_WIDTH) begin + cnt <= 10; + end + + 8: begin + div_num <= HDMI_WIDTH; + div_den <= hsize; + div_start <= 1; + end + + 9: begin + mul_arg1 <= hsize; + mul_arg2 <= div_res[11:0] ? div_res[11:0] : 12'd1; + mul_start <= 1; + end + + 10: begin + narrow <= ((div_num[11:0] - mul_res[11:0]) <= (wideres - div_num[11:0])) || (wideres > HDMI_WIDTH); + wres <= wideres; + end + + 11: begin + case(SCALE) + 2: arxf <= {1'b1, mul_res[11:0]}; + 3: arxf <= {1'b1, (wres > HDMI_WIDTH) ? mul_res[11:0] : wres}; + 4: arxf <= {1'b1, narrow ? mul_res[11:0] : wres}; + default: arxf <= {1'b1, div_num[11:0]}; + endcase + aryf <= {1'b1, oheight}; + end + endcase + end + + arx_o <= arxf; + ary_o <= aryf; +end + +endmodule diff --git a/sys/video_mixer.sv b/sys/video_mixer.sv new file mode 100644 index 0000000..93b106e --- /dev/null +++ b/sys/video_mixer.sv @@ -0,0 +1,192 @@ +// +// +// Copyright (c) 2017,2021 Alexey Melnikov +// +// This program is GPL Licensed. See COPYING for the full license. +// +// +//////////////////////////////////////////////////////////////////////////////////////////////////////// + +`timescale 1ns / 1ps + +// +// LINE_LENGTH: Length of display line in pixels +// Usually it's length from HSync to HSync. +// May be less if line_start is used. +// +// HALF_DEPTH: If =1 then color dept is 4 bits per component +// +// altera message_off 10720 +// altera message_off 12161 + +module video_mixer +#( + parameter LINE_LENGTH = 768, + parameter HALF_DEPTH = 0, + parameter GAMMA = 0 +) +( + input CLK_VIDEO, // should be multiple by (ce_pix*4) + output reg CE_PIXEL, // output pixel clock enable + + input ce_pix, // input pixel clock or clock_enable + + input scandoubler, + input hq2x, // high quality 2x scaling + + inout [21:0] gamma_bus, + + // color + input [DWIDTH:0] R, + input [DWIDTH:0] G, + input [DWIDTH:0] B, + + // Positive pulses. + input HSync, + input VSync, + input HBlank, + input VBlank, + + // video output signals + output reg [7:0] VGA_R, + output reg [7:0] VGA_G, + output reg [7:0] VGA_B, + output reg VGA_VS, + output reg VGA_HS, + output reg VGA_DE +); + +localparam DWIDTH = HALF_DEPTH ? 3 : 7; +localparam DWIDTH_SD = GAMMA ? 7 : DWIDTH; +localparam HALF_DEPTH_SD = GAMMA ? 0 : HALF_DEPTH; + +generate + if(GAMMA && HALF_DEPTH) begin + wire [7:0] R_in = {R,R}; + wire [7:0] G_in = {G,G}; + wire [7:0] B_in = {B,B}; + end else begin + wire [DWIDTH:0] R_in = R; + wire [DWIDTH:0] G_in = G; + wire [DWIDTH:0] B_in = B; + end +endgenerate + + +wire hs_g, vs_g; +wire hb_g, vb_g; +wire [DWIDTH_SD:0] R_gamma, G_gamma, B_gamma; + +generate + if(GAMMA) begin + assign gamma_bus[21] = 1; + gamma_corr gamma( + .clk_sys(gamma_bus[20]), + .clk_vid(CLK_VIDEO), + .ce_pix(ce_pix), + + .gamma_en(gamma_bus[19]), + .gamma_wr(gamma_bus[18]), + .gamma_wr_addr(gamma_bus[17:8]), + .gamma_value(gamma_bus[7:0]), + + .HSync(HSync), + .VSync(VSync), + .HBlank(HBlank), + .VBlank(VBlank), + .RGB_in({R_in,G_in,B_in}), + + .HSync_out(hs_g), + .VSync_out(vs_g), + .HBlank_out(hb_g), + .VBlank_out(vb_g), + .RGB_out({R_gamma,G_gamma,B_gamma}) + ); + end else begin + assign gamma_bus[21] = 0; + assign {R_gamma,G_gamma,B_gamma} = {R_in,G_in,B_in}; + assign {hs_g, vs_g, hb_g, vb_g} = {HSync, VSync, HBlank, VBlank}; + end +endgenerate + +wire [DWIDTH_SD:0] R_sd; +wire [DWIDTH_SD:0] G_sd; +wire [DWIDTH_SD:0] B_sd; +wire hs_sd, vs_sd, hb_sd, vb_sd, ce_pix_sd; + +scandoubler #(.LENGTH(LINE_LENGTH), .HALF_DEPTH(HALF_DEPTH_SD)) sd +( + .clk_vid(CLK_VIDEO), + .hq2x(hq2x), + + .ce_pix(ce_pix), + .hs_in(hs_g), + .vs_in(vs_g), + .hb_in(hb_g), + .vb_in(vb_g), + .r_in(R_gamma), + .g_in(G_gamma), + .b_in(B_gamma), + + .ce_pix_out(ce_pix_sd), + .hs_out(hs_sd), + .vs_out(vs_sd), + .hb_out(hb_sd), + .vb_out(vb_sd), + .r_out(R_sd), + .g_out(G_sd), + .b_out(B_sd) +); + +wire [DWIDTH_SD:0] rt = (scandoubler ? R_sd : R_gamma); +wire [DWIDTH_SD:0] gt = (scandoubler ? G_sd : G_gamma); +wire [DWIDTH_SD:0] bt = (scandoubler ? B_sd : B_gamma); + +always @(posedge CLK_VIDEO) begin + reg [7:0] r,g,b; + reg hde,vde,hs,vs, old_vs; + reg old_hde; + reg old_ce; + reg ce_osc, fs_osc; + + old_ce <= ce_pix; + ce_osc <= ce_osc | (old_ce ^ ce_pix); + + old_vs <= vs; + if(~old_vs & vs) begin + fs_osc <= ce_osc; + ce_osc <= 0; + end + + CE_PIXEL <= scandoubler ? ce_pix_sd : fs_osc ? (~old_ce & ce_pix) : ce_pix; + + if(!GAMMA && HALF_DEPTH) begin + r <= {rt,rt}; + g <= {gt,gt}; + b <= {bt,bt}; + end + else begin + r <= rt; + g <= gt; + b <= bt; + end + + hde <= scandoubler ? ~hb_sd : ~hb_g; + vde <= scandoubler ? ~vb_sd : ~vb_g; + vs <= scandoubler ? vs_sd : vs_g; + hs <= scandoubler ? hs_sd : hs_g; + + if(CE_PIXEL) begin + VGA_R <= r; + VGA_G <= g; + VGA_B <= b; + + VGA_VS <= vs; + VGA_HS <= hs; + + old_hde <= hde; + if(old_hde ^ hde) VGA_DE <= vde & hde; + end +end + +endmodule