├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── README.md ├── assets ├── Arcade.aseprite └── pong.png ├── dist ├── Cores │ └── agg23.Pong │ │ ├── audio.json │ │ ├── core.json │ │ ├── data.json │ │ ├── icon.bin │ │ ├── info.txt │ │ ├── input.json │ │ ├── interact.json │ │ ├── variants.json │ │ └── video.json └── Platforms │ ├── _images │ └── pong.bin │ └── pong.json └── src └── fpga ├── .gitignore ├── ap_core.qpf ├── ap_core.qsf ├── ap_core_assignment_defaults.qdf ├── apf ├── apf.qip ├── apf_constraints.sdc ├── apf_top.v ├── build_id.mif ├── build_id_gen.tcl ├── common.v ├── io_bridge_peripheral.v ├── io_pad_controller.v ├── mf_datatable.qip ├── mf_datatable.v ├── mf_ddio_bidir_12.qip └── mf_ddio_bidir_12.v └── core ├── core_bridge_cmd.v ├── core_constraints.sdc ├── core_top.v ├── mf_pllbase.bsf ├── mf_pllbase.ppf ├── mf_pllbase.qip ├── mf_pllbase.sip ├── mf_pllbase.spd ├── mf_pllbase.v ├── mf_pllbase ├── mf_pllbase_0002.qip └── mf_pllbase_0002.v ├── mf_pllbase_sim.f ├── mf_pllbase_sim ├── aldec │ └── rivierapro_setup.tcl ├── cadence │ ├── cds.lib │ ├── hdl.var │ └── ncsim_setup.sh ├── mentor │ └── msim_setup.tcl ├── mf_pllbase.vo └── synopsys │ ├── vcs │ └── vcs_setup.sh │ └── vcsmx │ ├── synopsys_sim.setup │ └── vcsmx_setup.sh ├── pin_ddio_clk.ppf ├── pin_ddio_clk.qip ├── pin_ddio_clk.v ├── pong ├── ball │ ├── horizontal.vhd │ ├── horizontal_direction.vhd │ ├── horizontal_position.vhd │ ├── move.vhd │ └── vertical.vhd ├── game_control.vhd ├── ic │ ├── 555_timer.vhd │ ├── 74107_neg_flip_flop.vhd │ ├── 74153_double_mux.vhd │ ├── 74153_mux.vhd │ ├── 7448_bcd_7_segment.vhd │ ├── 7474_sync.vhd │ ├── 7483_full_adder_without_carry.vhd │ ├── 7490_decade_counter.vhd │ ├── 7493_4bit_counter.vhd │ ├── 9316_internal.vhd │ ├── 9316_sync_4bit_counter.vhd │ ├── sr_nand.vhd │ ├── sr_nor.vhd │ ├── synchronizer.vhd │ └── test │ │ ├── 7474_tb.vhd │ │ ├── 7493_tb.vhd │ │ └── 9316_tb.vhd ├── net.vhd ├── paddle.vhd ├── pong.vhd ├── score │ ├── bcd.vhd │ ├── counter.vhd │ ├── score.vhd │ └── segments.vhd ├── sound.vhd ├── test │ └── pong_tb.vhd └── video │ ├── hcounter.vhd │ ├── hsync.vhd │ ├── test │ ├── hcounter_tb.vhd │ ├── hsync_tb.vhd │ └── vcounter_tb.vhd │ ├── vcounter.vhd │ ├── video.vhd │ └── vsync.vhd └── stp1.stp /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: agg23 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | tools/reverse.exe 2 | bitstream.rbf_r -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Adam Gastineau 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Atari's 1972 Pong 2 | 3 | A FPGA implementation of Atari's 1972 arcade game, Pong. This implementation is packaged for running on the Analogue Pocket. 4 | 5 | ## Controls 6 | 7 | Pong is a two player game that uses potentiometers (rotary dials) for control of each player's paddle. As the Pocket doesn't have rotary dials, we have to make due with its face buttons. 8 | 9 | | Action | Player 1 | Player 2 | 10 | |-----------------|---------------|------------------------------| 11 | | Paddle Movement | D Pad Up/Down | Face Button Top/Bottom (X/B) | 12 | | Fine Movement | Left Trigger | Right Trigger | 13 | 14 | Pong also supports the Analogue Pocket Dock, so you can play with two separate controllers. I suggest using the `Use Ctrl 2 for P2` setting described below for the best two controller experience. 15 | 16 | To insert a coin to start the game, press the button to the right of the Analogue button (considered to be the "Plus" button). Please note that the game will restart when an additional coin is inserted, so you can start a new game by pressing "Plus" at any time. 17 | 18 | ## Settings 19 | 20 | The original hardware only has one configurable setting available via a toggle switch: whether the game stops after 11 or 15 points. This core exposes this setting and a few "cheats" via the APF core settings. 21 | 22 | | Setting | Action | 23 | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------| 24 | | Win at 11/15 points | Configures the game to end at either 11 or 15 points. When set (the checkbox is white), the game will end after 15 points | 25 | | Prevent coin reset | Pong resets by default when a coin is inserted, no matter the play state. This prevents the reset unless the game is over | 26 | | Cheat: Extended paddles | Doubles the height of the paddles. This modification was performed to many machines to make it easier | 27 | | Cheat: Training mode | Configures the Player 2 paddle to fill most of the side of the screen. The only way to score is to hit the ball above the paddle | 28 | 29 | ## Implementation 30 | 31 | This is a gate-level implementation of Pong, derived from the original schematic. All bugs and oddities with the original hardware should be represented in the synthesized hardware (if you find something that isn't, please open an issue). 32 | 33 | As Pong was implemented using 74-series TTL logic chips, driven in an asynchronous manner (outputs from one chip may clock another), certain steps had to be taken to ensure accurate synthesis. 34 | 35 | 1. In addition to the 7.159 MHz primary clock used by Pong, a 28.636 MHz clock (4x the primary clock) is used to synchronize the various async parts of the ciruit. We take advantage of the time it takes logic gates to stablize in the original ciruit to gate updating values until an edge (typically rising) of the 28 MHz clock. This makes the logic formally synchronous, and avoids a series of problems that may arise during synthesis (see [dc5953b](https://github.com/agg23/analogue-pong/commit/dc5953be54613d9eeb33aa888bffc915d3f99dce) for an example of how changing synthesis can make or break the operation of async logic). 36 | 2. Several instances of combinational logic are converted to be synchronous to prevent the creation of combinational loops. These are denoted with a comment. In `paddle.vhd` in particular, leaving the output of the NAND `a7b` as a combinational expression resulted in the undefined clocking of the paddle height counter, resulting in flickering graphics and strange functionality. 37 | 3. 555 timers are simulated as counters based off of the primary clock, with timing approximating those found in testing. Implementation based off of https://github.com/MiSTer-devel/Arcade-Pong_MiSTer/blob/master/rtl/paddle.v 38 | 4. Horizontal sync timing in the original ciruit relies on a long ripple counter, which has the odd effect of ending `h_blank` _after_ the next rising edge of the clock (count is incremented on falling edge, and `h_blank` doesn't fall until after the rising edge). This is solved for by using the inverted primary clock as the synchronization clock for `h_blank`. 39 | 40 | ## References 41 | 42 | * [Edwards 2012 - Reconstructing Pong on an FPGA](http://www1.cs.columbia.edu/~sedwards/papers/edwards2012reconstructing.pdf) - The primary explanations of Pong's circuitry, along with nicely reformated schematics. 43 | * [Holden - Atari Pong E Circuit Analysis & Lawn Tennis](http://www.pong-story.com/LAWN_TENNIS.pdf) - Discussion about Pong's history, circuit explanation, and common defects/mistakes in the circuit. -------------------------------------------------------------------------------- /assets/Arcade.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agg23/openfpga-pong/bf4d17e8cb6159d4457126c45f43a5df15e4779e/assets/Arcade.aseprite -------------------------------------------------------------------------------- /assets/pong.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agg23/openfpga-pong/bf4d17e8cb6159d4457126c45f43a5df15e4779e/assets/pong.png -------------------------------------------------------------------------------- /dist/Cores/agg23.Pong/audio.json: -------------------------------------------------------------------------------- 1 | { 2 | "audio": { 3 | "magic": "APF_VER_1" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /dist/Cores/agg23.Pong/core.json: -------------------------------------------------------------------------------- 1 | { 2 | "core": { 3 | "magic": "APF_VER_1", 4 | "metadata": { 5 | "platform_ids": ["pong"], 6 | "shortname": "Pong", 7 | "description": "Atari Pong arcade machine. 1972", 8 | "author": "agg23", 9 | "url": "https://github.com/agg23/analogue-pong/", 10 | "version": "1.2.0", 11 | "date_release": "2022-09-08" 12 | }, 13 | "framework": { 14 | "target_product": "Analogue Pocket", 15 | "version_required": "1.1", 16 | "sleep_supported": false, 17 | "dock": { 18 | "supported": true, 19 | "analog_output": false 20 | }, 21 | "hardware": { 22 | "link_port": false, 23 | "cartridge_adapter": -1 24 | } 25 | }, 26 | "cores": [ 27 | { 28 | "name": "default", 29 | "id": 0, 30 | "filename": "bitstream.rbf_r" 31 | } 32 | ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /dist/Cores/agg23.Pong/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "magic": "APF_VER_1", 4 | "data_slots": [] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /dist/Cores/agg23.Pong/icon.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agg23/openfpga-pong/bf4d17e8cb6159d4457126c45f43a5df15e4779e/dist/Cores/agg23.Pong/icon.bin -------------------------------------------------------------------------------- /dist/Cores/agg23.Pong/info.txt: -------------------------------------------------------------------------------- 1 | The arcade game classic, Pong, in its original form. Video, sound, and bugs are reproduced from the original schematic. 2 | 3 | Features additional "cheats": 4 | * Extended paddles 5 | * Training mode -------------------------------------------------------------------------------- /dist/Cores/agg23.Pong/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "input": { 3 | "magic": "APF_VER_1", 4 | "controllers": [ 5 | { 6 | "type": "default", 7 | "mappings": [ 8 | { 9 | "id": 30, 10 | "name": "P1 Fine Control", 11 | "key": "pad_trig_l" 12 | }, 13 | { 14 | "id": 10, 15 | "name": "P2 Paddle Up", 16 | "key": "pad_btn_x" 17 | }, 18 | { 19 | "id": 11, 20 | "name": "P2 Paddle Down", 21 | "key": "pad_btn_b" 22 | }, 23 | { 24 | "id": 31, 25 | "name": "P2 Fine Control", 26 | "key": "pad_trig_r" 27 | }, 28 | { 29 | "id": 20, 30 | "name": "Insert coin", 31 | "key": "pad_btn_start" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /dist/Cores/agg23.Pong/interact.json: -------------------------------------------------------------------------------- 1 | { 2 | "interact": { 3 | "magic": "APF_VER_1", 4 | "variables": [ 5 | { 6 | "id": 1, 7 | "name": "Win at 11/15 points", 8 | "type": "check", 9 | "enabled": true, 10 | "persist": true, 11 | "writeonly": true, 12 | "address": "0x0", 13 | "defaultval": 0, 14 | "value": 1 15 | }, 16 | { 17 | "id": 6, 18 | "name": "Prevent coin reset", 19 | "type": "check", 20 | "enabled": true, 21 | "persist": true, 22 | "writeonly": true, 23 | "address": "0xC", 24 | "defaultval": 1, 25 | "value": 1 26 | }, 27 | { 28 | "id": 10, 29 | "name": "Cheats", 30 | "type": "action", 31 | "enabled": false, 32 | "persist": false, 33 | "writeonly": true, 34 | "address": "0x10000", 35 | "value": 0 36 | }, 37 | { 38 | "id": 11, 39 | "name": "Extended paddles", 40 | "type": "check", 41 | "enabled": true, 42 | "persist": true, 43 | "writeonly": true, 44 | "address": "0x14", 45 | "defaultval": 0, 46 | "value": 1 47 | }, 48 | { 49 | "id": 12, 50 | "name": "Training mode", 51 | "type": "check", 52 | "enabled": true, 53 | "persist": true, 54 | "writeonly": true, 55 | "address": "0x18", 56 | "defaultval": 0, 57 | "value": 1 58 | } 59 | ], 60 | "messages": [] 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /dist/Cores/agg23.Pong/variants.json: -------------------------------------------------------------------------------- 1 | { 2 | "variants": { 3 | "magic": "APF_VER_1", 4 | "variant_list": [] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /dist/Cores/agg23.Pong/video.json: -------------------------------------------------------------------------------- 1 | { 2 | "video": { 3 | "magic": "APF_VER_1", 4 | "scaler_modes": [ 5 | { 6 | "width": 360, 7 | "height": 240, 8 | "aspect_w": 4, 9 | "aspect_h": 3, 10 | "rotation": 0, 11 | "mirror": 0 12 | } 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /dist/Platforms/_images/pong.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agg23/openfpga-pong/bf4d17e8cb6159d4457126c45f43a5df15e4779e/dist/Platforms/_images/pong.bin -------------------------------------------------------------------------------- /dist/Platforms/pong.json: -------------------------------------------------------------------------------- 1 | { 2 | "platform": { 3 | "category": "Arcade", 4 | "name": "Pong", 5 | "manufacturer": "Atari", 6 | "year": 1972 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/fpga/.gitignore: -------------------------------------------------------------------------------- 1 | */db/ 2 | */incremental_db/ 3 | */simulation/ 4 | */greybox_tmp/ 5 | output_files/ 6 | incremental_db/ 7 | db/ 8 | PLLJ_PLLSPE_INFO.txt 9 | c5_pin_model_dump.txt 10 | cr_ie_info.json 11 | *.pin 12 | *.pof 13 | *.ptf.* 14 | *.qar 15 | *.qarlog 16 | *.qws 17 | *.rpt 18 | *.smsg 19 | *.sof 20 | *.sopc_builder 21 | *.summary 22 | *.txt 23 | *.bak 24 | *.cmp 25 | *.done 26 | *.xml 27 | *.sld 28 | *.cdf 29 | 30 | -------------------------------------------------------------------------------- /src/fpga/ap_core.qpf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------- # 2 | # 3 | # Copyright (C) 2019 Intel Corporation. All rights reserved. 4 | # Your use of Intel Corporation's design tools, logic functions 5 | # and other software and tools, and any partner logic 6 | # functions, and any output files from any of the foregoing 7 | # (including device programming or simulation files), and any 8 | # associated documentation or information are expressly subject 9 | # to the terms and conditions of the Intel Program License 10 | # Subscription Agreement, the Intel Quartus Prime License Agreement, 11 | # the Intel FPGA IP License Agreement, or other applicable license 12 | # agreement, including, without limitation, that your use is for 13 | # the sole purpose of programming logic devices manufactured by 14 | # Intel and sold by Intel or its authorized distributors. Please 15 | # refer to the applicable agreement for further details, at 16 | # https://fpgasoftware.intel.com/eula. 17 | # 18 | # -------------------------------------------------------------------------- # 19 | # 20 | # Quartus Prime 21 | # Version 18.1.1 Build 646 04/11/2019 SJ Lite Edition 22 | # Date created = 21:31:36 January 22, 2020 23 | # 24 | # -------------------------------------------------------------------------- # 25 | 26 | QUARTUS_VERSION = "18.1" 27 | DATE = "21:31:36 January 22, 2020" 28 | 29 | # Revisions 30 | 31 | PROJECT_REVISION = "ap_core" 32 | -------------------------------------------------------------------------------- /src/fpga/apf/apf.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "apf_top.v"] 2 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "common.v"] 3 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "io_bridge_peripheral.v"] 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "io_pad_controller.v"] 5 | set_global_assignment -name SDC_FILE [file join $::quartus(qip_path) "apf_constraints.sdc"] 6 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) "mf_ddio_bidir_12.qip"] 7 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) "mf_datatable.qip"] 8 | -------------------------------------------------------------------------------- /src/fpga/apf/apf_constraints.sdc: -------------------------------------------------------------------------------- 1 | # 2 | # APF constraints 3 | # Do not edit this file. 4 | # 5 | # Add your own constraints in the \core_constraints.sdc in the core directory, which will also be loaded. 6 | 7 | create_clock -name clk_74a -period 13.468 [get_ports clk_74a] 8 | create_clock -name clk_74b -period 13.468 [get_ports clk_74b] 9 | create_clock -name bridge_spiclk -period 13.468 [get_ports bridge_spiclk] 10 | 11 | # autogenerate PLL clock names for use down below 12 | derive_pll_clocks 13 | 14 | 15 | # io constraints go here 16 | # 17 | 18 | 19 | # load in user constraints 20 | read_sdc "core/core_constraints.sdc" -------------------------------------------------------------------------------- /src/fpga/apf/build_id.mif: -------------------------------------------------------------------------------- 1 | -- Build ID Memory Initialization File 2 | -- 3 | 4 | DEPTH = 256; 5 | WIDTH = 32; 6 | ADDRESS_RADIX = HEX; 7 | DATA_RADIX = HEX; 8 | 9 | CONTENT 10 | BEGIN 11 | 12 | 0E0 : 20221009; 13 | 0E1 : 00074046; 14 | 0E2 : 4f62b4d0; 15 | 16 | END; 17 | -------------------------------------------------------------------------------- /src/fpga/apf/build_id_gen.tcl: -------------------------------------------------------------------------------- 1 | # ================================================================================ 2 | # (c) 2011 Altera Corporation. All rights reserved. 3 | # Altera products are protected under numerous U.S. and foreign patents, maskwork 4 | # rights, copyrights and other intellectual property laws. 5 | # 6 | # This reference design file, and your use thereof, is subject to and governed 7 | # by the terms and conditions of the applicable Altera Reference Design License 8 | # Agreement (either as signed by you, agreed by you upon download or as a 9 | # "click-through" agreement upon installation andor found at www.altera.com). 10 | # By using this reference design file, you indicate your acceptance of such terms 11 | # and conditions between you and Altera Corporation. In the event that you do 12 | # not agree with such terms and conditions, you may not use the reference design 13 | # file and please promptly destroy any copies you have made. 14 | # 15 | # This reference design file is being provided on an "as-is" basis and as an 16 | # accommodation and therefore all warranties, representations or guarantees of 17 | # any kind (whether express, implied or statutory) including, without limitation, 18 | # warranties of merchantability, non-infringement, or fitness for a particular 19 | # purpose, are specifically disclaimed. By making this reference design file 20 | # available, Altera expressly does not recommend, suggest or require that this 21 | # reference design file be used in combination with any other product not 22 | # provided by Altera. 23 | # ================================================================================ 24 | # 25 | # Build ID Verilog Module Script 26 | # Jeff Wiencrot - 8/1/2011 27 | # 28 | # Generates a Verilog module that contains a timestamp, physical address, and host name 29 | # from the current build. These values are available from the build_date, build_time, 30 | # physical_address, and host_name output ports of the build_id module in the build_id.v 31 | # Verilog source file. 32 | # 33 | # The format for each value is as follows: 34 | # Date - 32-bit decimal number of the format mmddyyyy 35 | # Time - 32-bit decimal number of the format hhmmss 36 | # Phyiscal Address - 48-bit hexadecimal number 37 | # Host name - 120-bit hexadecimal number with pairs of digits equal to the 38 | # hexadecimal code for the first 15 ASCII characters of the host 39 | # name. For added clarity, host names that have fewer than 30 40 | # hexadecimal digits (15 characters) are padded on the left with 41 | # zeros. 42 | # 43 | # Usage: 44 | # 45 | # To manually execute this script, source this file using the following Tcl commands: 46 | # source build_id_verilog.tcl 47 | # 48 | # To have this script automatically execute each time your project is built, use the 49 | # following command (see: http://www.altera.com/support/examples/tcl/auto_processing.html): 50 | # set_global_assignment -name PRE_FLOW_SCRIPT_FILE quartus_sh:build_id_verilog.tcl 51 | # 52 | # Comment out the last line to prevent the process from automatically executing when 53 | # the file is sourced. The process can then be executed with the following command: 54 | # generateBuildID_Verilog 55 | # 56 | # 57 | # For more information, see "build_identification.pdf" 58 | # 59 | # ================================================================================ 60 | # 61 | # 2021-01-21 Analogue 62 | # 63 | # Only care about generating build date/time, so the rest was removed. 64 | # The original can be downloaded from the Intel resource page 65 | # 66 | 67 | proc generateBuildID_Verilog {} { 68 | 69 | # Get the timestamp (see: http://www.altera.com/support/examples/tcl/tcl-date-time-stamp.html) 70 | set buildDate [ clock format [ clock seconds ] -format %Y%m%d ] 71 | set buildTime [ clock format [ clock seconds ] -format %H%M%S ] 72 | 73 | # Create a Verilog file for output 74 | set outputFileName "apf/build_id.v" 75 | set outputFile [open $outputFileName "w"] 76 | 77 | # Output the Verilog source 78 | puts $outputFile "// Build ID Verilog Module" 79 | puts $outputFile "//" 80 | puts $outputFile "// Note - these are stored as binary coded decimal" 81 | puts $outputFile "// Date: $buildDate" 82 | puts $outputFile "// Time: $buildTime" 83 | puts $outputFile "" 84 | puts $outputFile "module build_id" 85 | puts $outputFile "(" 86 | puts $outputFile " output \[31:0\] build_date," 87 | puts $outputFile " output \[31:0\] build_time" 88 | puts $outputFile ");" 89 | puts $outputFile "" 90 | puts $outputFile " assign build_date = 32'h$buildDate;" 91 | puts $outputFile " assign build_time = 32'h$buildTime;" 92 | puts $outputFile "" 93 | puts $outputFile "endmodule" 94 | close $outputFile 95 | 96 | 97 | 98 | # Send confirmation message to the Messages window 99 | #post_message "APF core build date/time generated: [pwd]/$outputFileName" 100 | #post_message "Date: $buildDate" 101 | #post_message "Time: $buildTime" 102 | } 103 | 104 | 105 | proc generateBuildID_MIF {} { 106 | 107 | # Get the timestamp (see: http://www.altera.com/support/examples/tcl/tcl-date-time-stamp.html) 108 | set buildDate [ clock format [ clock seconds ] -format %Y%m%d ] 109 | set buildTime [ clock format [ clock seconds ] -format %H%M%S ] 110 | set buildUnique [expr {int(rand()*(4294967295))}] 111 | 112 | set buildDateNoLeadingZeros [string trimleft $buildDate "0"] 113 | set buildTimeNoLeadingZeros [string trimleft $buildTime "0"] 114 | set buildDate4Byte [format "%08d" $buildDateNoLeadingZeros] 115 | set buildTime4Byte [format "%08d" $buildTimeNoLeadingZeros] 116 | set buildUnique4Byte [format "%08x" $buildUnique] 117 | 118 | #set buildDate4Byte \ 119 | [concat [string range $buildDate 0 1] \ 120 | [string range $buildDate 2 3] \ 121 | [string range $buildDate 4 5] \ 122 | [string range $buildDate 6 7] ] 123 | 124 | 125 | set buildDateNumBytes 4 126 | set buildTimeNumBytes 4 127 | 128 | # Calculate depth of the memory (8-bit) words 129 | set memoryDepth [expr $buildDateNumBytes + $buildTimeNumBytes] 130 | 131 | # Create a Memory Initialization File for output 132 | set outputFileName "apf/build_id.mif" 133 | set outputFile [open $outputFileName "w"] 134 | 135 | # Output the MIF header (see: http://quartushelp.altera.com/current/mergedProjects/reference/glossary/def_mif.htm) 136 | puts $outputFile "-- Build ID Memory Initialization File" 137 | puts $outputFile "--" 138 | puts $outputFile "" 139 | puts $outputFile "DEPTH = 256;" 140 | puts $outputFile "WIDTH = 32;" 141 | puts $outputFile "ADDRESS_RADIX = HEX;" 142 | puts $outputFile "DATA_RADIX = HEX;" 143 | puts $outputFile "" 144 | puts $outputFile "CONTENT" 145 | puts $outputFile "BEGIN" 146 | puts $outputFile "" 147 | puts $outputFile " 0E0 : $buildDate4Byte;" 148 | puts $outputFile " 0E1 : $buildTime4Byte;" 149 | puts $outputFile " 0E2 : $buildUnique4Byte;" 150 | puts $outputFile "" 151 | puts $outputFile "END;" 152 | 153 | # Close file to complete write 154 | close $outputFile 155 | 156 | # Send confirmation message to the Messages window 157 | post_message "APF core build date/time generated: [pwd]/$outputFileName" 158 | } 159 | 160 | generateBuildID_MIF 161 | 162 | # 2021-01-21 Analogue 163 | # 164 | # There are some circumstances where you want all parts of a FPGA flow to be deterministic, especially 165 | # when trying to hash out timing issues. 166 | # You should comment this line out and temporarily bypass buildid generation so that synthesis/par 167 | # have consistent working input. MIF bram contents like above won't affect the random seed or trigger 168 | # recompilation. 169 | # Don't forget to re-enable before you release. 170 | # 171 | # generateBuildID_Verilog 172 | -------------------------------------------------------------------------------- /src/fpga/apf/common.v: -------------------------------------------------------------------------------- 1 | // Software License Agreement 2 | 3 | // The software supplied herewith by Analogue Enterprises Limited (the "Company”), 4 | // the Analogue Pocket Framework (“APF”), is provided and licensed to you, the 5 | // Company's customer, solely for use in designing, testing and creating 6 | // applications for use with Company's Products or Services. The software is 7 | // owned by the Company and/or its licensors, and is protected under applicable 8 | // laws, including, but not limited to, U.S. copyright law. All rights are 9 | // reserved. By using the APF code you are agreeing to the terms of the End User 10 | // License Agreement (“EULA”) located at [https://www.analogue.link/pocket-eula] 11 | // and incorporated herein by reference. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS-IS" AND WE EXPRESSLY DISCLAIM ANY IMPLIED 14 | // WARRANTIES TO THE FULLEST EXTENT PROVIDED BY LAW, INCLUDING BUT NOT LIMITED TO, 15 | // ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE OR 16 | // NON-INFRINGEMENT. TO THE EXTENT APPLICABLE LAWS PROHIBIT TERMS OF USE FROM 17 | // DISCLAIMING ANY IMPLIED WARRANTY, SUCH IMPLIED WARRANTY SHALL BE LIMITED TO THE 18 | // MINIMUM WARRANTY PERIOD REQUIRED BY LAW, AND IF NO SUCH PERIOD IS REQUIRED, 19 | // THEN THIRTY (30) DAYS FROM FIRST USE OF THE SOFTWARE. WE CANNOT GUARANTEE AND 20 | // DO NOT PROMISE ANY SPECIFIC RESULTS FROM USE OF THE SOFTWARE. WITHOUT LIMITING 21 | // THE FOREGOING, WE DO NOT WARRANT THAT THE SOFTWARE WILL BE UNINTERRUPTED OR 22 | // ERROR-FREE. IN NO EVENT WILL WE BE LIABLE TO YOU OR ANY OTHER PERSON FOR ANY 23 | // INDIRECT, CONSEQUENTIAL, EXEMPLARY, INCIDENTAL, SPECIAL OR PUNITIVE DAMAGES, 24 | // INCLUDING BUT NOT LIMITED TO, LOST PROFITS ARISING OUT OF YOUR USE, OR 25 | // INABILITY TO USE, THE SOFTWARE, EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY 26 | // OF SUCH DAMAGES. UNDER NO CIRCUMSTANCES SHALL OUR LIABILITY TO YOU FOR ANY 27 | // CLAIM OR CAUSE OF ACTION WHATSOEVER, AND REGARDLESS OF THE FORM OF THE ACTION, 28 | // WHETHER ARISING IN CONTRACT, TORT OR OTHERWISE, EXCEED THE AMOUNT PAID BY YOU 29 | // TO US, IF ANY, DURING THE 90 DAY PERIOD IMMEDIATELY PRECEDING THE DATE ON WHICH 30 | // YOU FIRST ASSERT ANY SUCH CLAIM. THE FOREGOING LIMITATIONS SHALL APPLY TO THE 31 | // FULLEST EXTENT PERMITTED BY APPLICABLE LAW. 32 | // 33 | // 2-stage synchronizer 34 | // 35 | module synch_2 #(parameter WIDTH = 1) ( 36 | input wire [WIDTH-1:0] i, // input signal 37 | output reg [WIDTH-1:0] o, // synchronized output 38 | input wire clk, // clock to synchronize on 39 | output wire rise, // one-cycle rising edge pulse 40 | output wire fall // one-cycle falling edge pulse 41 | ); 42 | 43 | reg [WIDTH-1:0] stage_1; 44 | reg [WIDTH-1:0] stage_2; 45 | reg [WIDTH-1:0] stage_3; 46 | 47 | assign rise = (WIDTH == 1) ? (o & ~stage_2) : 1'b0; 48 | assign fall = (WIDTH == 1) ? (~o & stage_2) : 1'b0; 49 | always @(posedge clk) 50 | {stage_2, o, stage_1} <= {o, stage_1, i}; 51 | 52 | endmodule 53 | 54 | 55 | // 56 | // 3-stage synchronizer 57 | // 58 | module synch_3 #(parameter WIDTH = 1) ( 59 | input wire [WIDTH-1:0] i, // input signal 60 | output reg [WIDTH-1:0] o, // synchronized output 61 | input wire clk, // clock to synchronize on 62 | output wire rise, // one-cycle rising edge pulse 63 | output wire fall // one-cycle falling edge pulse 64 | ); 65 | 66 | reg [WIDTH-1:0] stage_1; 67 | reg [WIDTH-1:0] stage_2; 68 | reg [WIDTH-1:0] stage_3; 69 | 70 | assign rise = (WIDTH == 1) ? (o & ~stage_3) : 1'b0; 71 | assign fall = (WIDTH == 1) ? (~o & stage_3) : 1'b0; 72 | always @(posedge clk) 73 | {stage_3, o, stage_2, stage_1} <= {o, stage_2, stage_1, i}; 74 | 75 | endmodule 76 | 77 | 78 | module bram_block_dp #( 79 | parameter DATA = 32, 80 | parameter ADDR = 7 81 | ) ( 82 | input wire a_clk, 83 | input wire a_wr, 84 | input wire [ADDR-1:0] a_addr, 85 | input wire [DATA-1:0] a_din, 86 | output reg [DATA-1:0] a_dout, 87 | 88 | input wire b_clk, 89 | input wire b_wr, 90 | input wire [ADDR-1:0] b_addr, 91 | input wire [DATA-1:0] b_din, 92 | output reg [DATA-1:0] b_dout 93 | ); 94 | 95 | reg [DATA-1:0] mem [(2**ADDR)-1:0]; 96 | 97 | always @(posedge a_clk) begin 98 | if(a_wr) begin 99 | a_dout <= a_din; 100 | mem[a_addr] <= a_din; 101 | end else 102 | a_dout <= mem[a_addr]; 103 | end 104 | 105 | always @(posedge b_clk) begin 106 | if(b_wr) begin 107 | b_dout <= b_din; 108 | mem[b_addr] <= b_din; 109 | end else 110 | b_dout <= mem[b_addr]; 111 | end 112 | 113 | endmodule 114 | 115 | 116 | module bram_block_dp_nonstd #( 117 | parameter DATA = 32, 118 | parameter ADDR = 7, 119 | parameter DEPTH = 128 120 | ) ( 121 | input wire a_clk, 122 | input wire a_wr, 123 | input wire [ADDR-1:0] a_addr, 124 | input wire [DATA-1:0] a_din, 125 | output reg [DATA-1:0] a_dout, 126 | 127 | input wire b_clk, 128 | input wire b_wr, 129 | input wire [ADDR-1:0] b_addr, 130 | input wire [DATA-1:0] b_din, 131 | output reg [DATA-1:0] b_dout 132 | ); 133 | 134 | reg [DATA-1:0] mem [DEPTH-1:0]; 135 | 136 | always @(posedge a_clk) begin 137 | if(a_wr) begin 138 | a_dout <= a_din; 139 | mem[a_addr] <= a_din; 140 | end else 141 | a_dout <= mem[a_addr]; 142 | end 143 | 144 | always @(posedge b_clk) begin 145 | if(b_wr) begin 146 | b_dout <= b_din; 147 | mem[b_addr] <= b_din; 148 | end else 149 | b_dout <= mem[b_addr]; 150 | end 151 | 152 | endmodule 153 | -------------------------------------------------------------------------------- /src/fpga/apf/io_bridge_peripheral.v: -------------------------------------------------------------------------------- 1 | // Software License Agreement 2 | 3 | // The software supplied herewith by Analogue Enterprises Limited (the "Company”), 4 | // the Analogue Pocket Framework (“APF”), is provided and licensed to you, the 5 | // Company's customer, solely for use in designing, testing and creating 6 | // applications for use with Company's Products or Services. The software is 7 | // owned by the Company and/or its licensors, and is protected under applicable 8 | // laws, including, but not limited to, U.S. copyright law. All rights are 9 | // reserved. By using the APF code you are agreeing to the terms of the End User 10 | // License Agreement (“EULA”) located at [https://www.analogue.link/pocket-eula] 11 | // and incorporated herein by reference. To the extent any use of the APF requires 12 | // application of the MIT License or the GNU General Public License and terms of 13 | // this APF Software License Agreement and EULA are inconsistent with such license, 14 | // the applicable terms of the MIT License or the GNU General Public License, as 15 | // applicable, will prevail. 16 | 17 | // THE SOFTWARE IS PROVIDED "AS-IS" AND WE EXPRESSLY DISCLAIM ANY IMPLIED 18 | // WARRANTIES TO THE FULLEST EXTENT PROVIDED BY LAW, INCLUDING BUT NOT LIMITED TO, 19 | // ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE OR 20 | // NON-INFRINGEMENT. TO THE EXTENT APPLICABLE LAWS PROHIBIT TERMS OF USE FROM 21 | // DISCLAIMING ANY IMPLIED WARRANTY, SUCH IMPLIED WARRANTY SHALL BE LIMITED TO THE 22 | // MINIMUM WARRANTY PERIOD REQUIRED BY LAW, AND IF NO SUCH PERIOD IS REQUIRED, 23 | // THEN THIRTY (30) DAYS FROM FIRST USE OF THE SOFTWARE. WE CANNOT GUARANTEE AND 24 | // DO NOT PROMISE ANY SPECIFIC RESULTS FROM USE OF THE SOFTWARE. WITHOUT LIMITING 25 | // THE FOREGOING, WE DO NOT WARRANT THAT THE SOFTWARE WILL BE UNINTERRUPTED OR 26 | // ERROR-FREE. IN NO EVENT WILL WE BE LIABLE TO YOU OR ANY OTHER PERSON FOR ANY 27 | // INDIRECT, CONSEQUENTIAL, EXEMPLARY, INCIDENTAL, SPECIAL OR PUNITIVE DAMAGES, 28 | // INCLUDING BUT NOT LIMITED TO, LOST PROFITS ARISING OUT OF YOUR USE, OR 29 | // INABILITY TO USE, THE SOFTWARE, EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY 30 | // OF SUCH DAMAGES. UNDER NO CIRCUMSTANCES SHALL OUR LIABILITY TO YOU FOR ANY 31 | // CLAIM OR CAUSE OF ACTION WHATSOEVER, AND REGARDLESS OF THE FORM OF THE ACTION, 32 | // WHETHER ARISING IN CONTRACT, TORT OR OTHERWISE, EXCEED THE AMOUNT PAID BY YOU 33 | // TO US, IF ANY, DURING THE 90 DAY PERIOD IMMEDIATELY PRECEDING THE DATE ON WHICH 34 | // YOU FIRST ASSERT ANY SUCH CLAIM. THE FOREGOING LIMITATIONS SHALL APPLY TO THE 35 | // FULLEST EXTENT PERMITTED BY APPLICABLE LAW. 36 | // 37 | // bridge peripheral for socrates PMP bridge to heraclitus+aristotle 38 | // 2020-2022 Analogue 39 | // 40 | // please note that while writes are immediate, 41 | // reads are buffered by 1 word. this is necessary to maintain 42 | // data throughput while reading from slower data sources like 43 | // sdram. 44 | // reads should always return the current bus value, and kickstart 45 | // into the next read immediately. this way, you have the entire 46 | // next word time to retrieve the data, instead of just a few 47 | // cycles. 48 | // 49 | // the worst-case read/write timing is every 88 cycles @ 74.25mhz 50 | // which is about 1180ns. 51 | 52 | module io_bridge_peripheral ( 53 | 54 | input wire clk, 55 | input wire reset_n, 56 | 57 | input wire endian_little, 58 | 59 | output reg [31:0] pmp_addr, 60 | output reg pmp_addr_valid, 61 | output reg pmp_rd, 62 | input wire [31:0] pmp_rd_data, 63 | output reg pmp_wr, 64 | output reg [31:0] pmp_wr_data, 65 | 66 | inout reg phy_spimosi, 67 | inout reg phy_spimiso, 68 | inout reg phy_spiclk, 69 | input wire phy_spiss 70 | 71 | ); 72 | 73 | // 74 | // clock domain: clk (74.25mhz) rising edge 75 | // 76 | wire reset_n_s; 77 | synch_3 s00(reset_n, reset_n_s, clk); 78 | 79 | wire endian_little_s; 80 | synch_3 s01(endian_little, endian_little_s, clk); 81 | 82 | wire phy_spiss_s, phy_spiss_r, phy_spiss_f; 83 | synch_3 s02(phy_spiss, phy_spiss_s, clk, phy_spiss_r, phy_spiss_f); 84 | 85 | 86 | reg [4:0] state; 87 | localparam ST_RESET = 'd0; 88 | localparam ST_IDLE = 'd1; 89 | localparam ST_READ_0 = 'd2; 90 | localparam ST_READ_1 = 'd3; 91 | localparam ST_READ_2 = 'd4; 92 | localparam ST_READ_3 = 'd5; 93 | localparam ST_WRITE_0 = 'd6; 94 | localparam ST_WRITE_1 = 'd7; 95 | localparam ST_WRITE_2 = 'd8; 96 | localparam ST_ADDR_0 = 'd9; 97 | 98 | reg [1:0] addr_cnt; 99 | reg [1:0] data_cnt; 100 | reg [6:0] read_cnt; 101 | 102 | // synchronize rd byte flag's rising edge into clk 103 | wire rx_byte_done_s, rx_byte_done_r; 104 | synch_3 s03(rx_byte_done, rx_byte_done_s, clk, rx_byte_done_r); 105 | 106 | reg [4:0] spis; 107 | localparam ST_SIDLE = 'd1; 108 | localparam ST_SEND_N = 'd6; 109 | localparam ST_SEND_0 = 'd2; 110 | localparam ST_SEND_1 = 'd3; 111 | localparam ST_SEND_2 = 'd4; 112 | localparam ST_SEND_3 = 'd5; 113 | reg spis_tx; 114 | reg [31:0] spis_word_tx; 115 | reg [31:0] spis_word; 116 | reg [4:0] spis_count; 117 | reg spis_done; 118 | 119 | reg rx_byte_done_r_1, rx_byte_done_r_2; 120 | reg [7:0] rx_byte_1, rx_byte_2; 121 | 122 | // handle reversing endianness on both ports 123 | reg [31:0] pmp_wr_data_latch; 124 | reg [31:0] pmp_rd_data_e; // asynchronous 125 | reg [31:0] pmp_rd_data_buf; // buffer the last word for immediate response 126 | always @(*) begin 127 | pmp_wr_data <= endian_little_s ? { pmp_wr_data_latch[7:0], 128 | pmp_wr_data_latch[15:8], 129 | pmp_wr_data_latch[23:16], 130 | pmp_wr_data_latch[31:24] 131 | } : pmp_wr_data_latch; 132 | 133 | pmp_rd_data_e <= endian_little_s ? {pmp_rd_data[7:0], 134 | pmp_rd_data[15:8], 135 | pmp_rd_data[23:16], 136 | pmp_rd_data[31:24] 137 | } : pmp_rd_data; 138 | end 139 | 140 | always @(posedge clk) begin 141 | 142 | rx_byte_2 <= rx_byte_1; 143 | rx_byte_1 <= rx_byte; 144 | 145 | rx_byte_done_r_1 <= rx_byte_done_r; 146 | rx_byte_done_r_2 <= rx_byte_done_r_1; 147 | 148 | case(state) 149 | ST_RESET: begin 150 | addr_cnt <= 0; 151 | data_cnt <= 0; 152 | pmp_wr <= 0; 153 | pmp_rd <= 0; 154 | pmp_addr_valid <= 0; 155 | spis_tx <= 0; 156 | 157 | state <= ST_ADDR_0; 158 | end 159 | ST_ADDR_0: begin 160 | // transaction has started 161 | 162 | if(rx_byte_done_r_2) begin 163 | case(addr_cnt) 164 | 0: pmp_addr[31:24] <= rx_byte_2; 165 | 1: pmp_addr[23:16] <= rx_byte_2; 166 | 2: pmp_addr[15: 8] <= rx_byte_2; 167 | 3: begin 168 | pmp_addr[ 7: 0] <= {rx_byte_2[7:2], 2'b00}; 169 | // address is latched 170 | if( rx_byte_2[0] ) begin 171 | data_cnt <= 0; 172 | state <= ST_WRITE_0; 173 | end else begin 174 | data_cnt <= 0; 175 | read_cnt <= 0; 176 | state <= ST_READ_0; 177 | end 178 | end 179 | endcase 180 | 181 | addr_cnt <= addr_cnt + 1'b1; 182 | end 183 | end 184 | ST_WRITE_0: begin 185 | // give notice, address has become valid 186 | pmp_addr_valid <= 1; 187 | 188 | if(rx_byte_done_r_2) begin 189 | case(data_cnt) 190 | 0: pmp_wr_data_latch[31:24] <= rx_byte_2; 191 | 1: pmp_wr_data_latch[23:16] <= rx_byte_2; 192 | 2: pmp_wr_data_latch[15: 8] <= rx_byte_2; 193 | 3: begin 194 | pmp_wr_data_latch[ 7: 0] <= rx_byte_2; 195 | state <= ST_WRITE_1; 196 | end 197 | endcase 198 | data_cnt <= data_cnt + 1'b1; 199 | end 200 | end 201 | ST_WRITE_1: begin 202 | pmp_wr <= 1; 203 | state <= ST_WRITE_2; 204 | end 205 | ST_WRITE_2: begin 206 | // exited upon new transaction 207 | pmp_wr <= 0; 208 | end 209 | ST_READ_0: begin 210 | pmp_addr_valid <= 1; 211 | 212 | // delay a few cycles 213 | read_cnt <= read_cnt + 1'b1; 214 | if(read_cnt == 4-1) begin 215 | // load the buffer with the current data 216 | // and give the current buffer contents to bridge 217 | spis_word_tx <= pmp_rd_data_e; 218 | spis_tx <= 1; 219 | 220 | state <= ST_READ_1; 221 | end 222 | end 223 | ST_READ_1: begin 224 | pmp_rd <= 1; 225 | state <= ST_READ_2; 226 | end 227 | ST_READ_2: begin 228 | pmp_rd <= 0; 229 | if(spis_done) begin 230 | spis_tx <= 0; 231 | state <= ST_READ_3; 232 | end 233 | end 234 | ST_READ_3: begin 235 | // exited upon new transaction 236 | end 237 | endcase 238 | 239 | 240 | 241 | 242 | // 243 | // word transmit 244 | // 245 | spis_done <= 0; 246 | case(spis) 247 | ST_SIDLE: begin 248 | spis_count <= 0; 249 | 250 | phy_spiclk <= 1'bZ; 251 | phy_spimosi <= 1'bZ; 252 | phy_spimiso <= 1'bZ; 253 | 254 | if(spis_tx) begin 255 | spis_word <= spis_word_tx; 256 | spis <= ST_SEND_N; 257 | end 258 | end 259 | // drive high first 260 | ST_SEND_N: begin 261 | phy_spiclk <= 1'b1; 262 | phy_spimosi <= 1'b1; 263 | phy_spimiso <= 1'b1; 264 | spis <= ST_SEND_0; 265 | end 266 | // tx, shift out bits 267 | ST_SEND_0: begin 268 | phy_spiclk <= 0; 269 | spis <= ST_SEND_1; 270 | phy_spimosi <= spis_word[31]; 271 | phy_spimiso <= spis_word[30]; 272 | spis_word <= {spis_word[29:0], 2'b00}; 273 | end 274 | ST_SEND_1: begin 275 | phy_spiclk <= 1; 276 | spis <= ST_SEND_0; 277 | spis_count <= spis_count + 1'b1; 278 | if(spis_count == 15) spis <= ST_SEND_2; 279 | end 280 | ST_SEND_2: begin 281 | phy_spiclk <= 1'b1; 282 | phy_spimosi <= 1'b1; 283 | phy_spimiso <= 1'b1; 284 | spis <= ST_SEND_3; 285 | spis_done <= 1; 286 | end 287 | ST_SEND_3: begin 288 | spis <= ST_SIDLE; 289 | end 290 | endcase 291 | 292 | if(phy_spiss_s) begin 293 | // select is high, go back to reset 294 | state <= ST_RESET; 295 | spis <= ST_SIDLE; 296 | end 297 | 298 | end 299 | 300 | 301 | // 302 | // clock domain: phy_spiclk rising edge 303 | // 304 | reg [1:0] rx_latch_idx; 305 | reg [7:0] rx_dat; 306 | reg [7:0] rx_byte; // latched by clk, but upon a synchronized trigger 307 | reg rx_byte_done; 308 | 309 | always @(posedge phy_spiclk or posedge phy_spiss) begin 310 | 311 | if(phy_spiss) begin 312 | // reset 313 | rx_byte_done <= 0; 314 | rx_latch_idx <= 0; 315 | 316 | end else begin 317 | // spiclk rising edge, latch data 318 | rx_byte_done <= 0; 319 | 320 | case(rx_latch_idx) 321 | 0: begin rx_dat[7:6] <= {phy_spimosi, phy_spimiso}; rx_latch_idx <= 1; end 322 | 1: begin rx_dat[5:4] <= {phy_spimosi, phy_spimiso}; rx_latch_idx <= 2; end 323 | 2: begin rx_dat[3:2] <= {phy_spimosi, phy_spimiso}; rx_latch_idx <= 3; end 324 | 3: begin 325 | // final 2 bits 326 | rx_byte <= {rx_dat[7:2], phy_spimosi, phy_spimiso}; 327 | rx_latch_idx <= 0; 328 | rx_byte_done <= 1; 329 | end 330 | endcase 331 | end 332 | end 333 | 334 | endmodule -------------------------------------------------------------------------------- /src/fpga/apf/io_pad_controller.v: -------------------------------------------------------------------------------- 1 | // Software License Agreement 2 | 3 | // The software supplied herewith by Analogue Enterprises Limited (the "Company”), 4 | // the Analogue Pocket Framework (“APF”), is provided and licensed to you, the 5 | // Company's customer, solely for use in designing, testing and creating 6 | // applications for use with Company's Products or Services. The software is 7 | // owned by the Company and/or its licensors, and is protected under applicable 8 | // laws, including, but not limited to, U.S. copyright law. All rights are 9 | // reserved. By using the APF code you are agreeing to the terms of the End User 10 | // License Agreement (“EULA”) located at [https://www.analogue.link/pocket-eula] 11 | // and incorporated herein by reference. To the extent any use of the APF requires 12 | // application of the MIT License or the GNU General Public License and terms of 13 | // this APF Software License Agreement and EULA are inconsistent with such license, 14 | // the applicable terms of the MIT License or the GNU General Public License, as 15 | // applicable, will prevail. 16 | 17 | // THE SOFTWARE IS PROVIDED "AS-IS" AND WE EXPRESSLY DISCLAIM ANY IMPLIED 18 | // WARRANTIES TO THE FULLEST EXTENT PROVIDED BY LAW, INCLUDING BUT NOT LIMITED TO, 19 | // ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE OR 20 | // NON-INFRINGEMENT. TO THE EXTENT APPLICABLE LAWS PROHIBIT TERMS OF USE FROM 21 | // DISCLAIMING ANY IMPLIED WARRANTY, SUCH IMPLIED WARRANTY SHALL BE LIMITED TO THE 22 | // MINIMUM WARRANTY PERIOD REQUIRED BY LAW, AND IF NO SUCH PERIOD IS REQUIRED, 23 | // THEN THIRTY (30) DAYS FROM FIRST USE OF THE SOFTWARE. WE CANNOT GUARANTEE AND 24 | // DO NOT PROMISE ANY SPECIFIC RESULTS FROM USE OF THE SOFTWARE. WITHOUT LIMITING 25 | // THE FOREGOING, WE DO NOT WARRANT THAT THE SOFTWARE WILL BE UNINTERRUPTED OR 26 | // ERROR-FREE. IN NO EVENT WILL WE BE LIABLE TO YOU OR ANY OTHER PERSON FOR ANY 27 | // INDIRECT, CONSEQUENTIAL, EXEMPLARY, INCIDENTAL, SPECIAL OR PUNITIVE DAMAGES, 28 | // INCLUDING BUT NOT LIMITED TO, LOST PROFITS ARISING OUT OF YOUR USE, OR 29 | // INABILITY TO USE, THE SOFTWARE, EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY 30 | // OF SUCH DAMAGES. UNDER NO CIRCUMSTANCES SHALL OUR LIABILITY TO YOU FOR ANY 31 | // CLAIM OR CAUSE OF ACTION WHATSOEVER, AND REGARDLESS OF THE FORM OF THE ACTION, 32 | // WHETHER ARISING IN CONTRACT, TORT OR OTHERWISE, EXCEED THE AMOUNT PAID BY YOU 33 | // TO US, IF ANY, DURING THE 90 DAY PERIOD IMMEDIATELY PRECEDING THE DATE ON WHICH 34 | // YOU FIRST ASSERT ANY SUCH CLAIM. THE FOREGOING LIMITATIONS SHALL APPLY TO THE 35 | // FULLEST EXTENT PERMITTED BY APPLICABLE LAW. 36 | // 37 | // pad controller 38 | // 2020-08-17 Analogue 39 | // 40 | 41 | module io_pad_controller ( 42 | 43 | input wire clk, 44 | input wire reset_n, 45 | 46 | inout reg pad_1wire, 47 | 48 | output reg [31:0] cont1_key, 49 | output reg [31:0] cont2_key, 50 | output reg [31:0] cont3_key, 51 | output reg [31:0] cont4_key, 52 | output reg [31:0] cont1_joy, 53 | output reg [31:0] cont2_joy, 54 | output reg [31:0] cont3_joy, 55 | output reg [31:0] cont4_joy, 56 | output reg [15:0] cont1_trig, 57 | output reg [15:0] cont2_trig, 58 | output reg [15:0] cont3_trig, 59 | output reg [15:0] cont4_trig, 60 | 61 | output reg rx_timed_out 62 | ); 63 | 64 | wire reset_n_s; 65 | synch_3 s00(reset_n, reset_n_s, clk); 66 | 67 | wire pad_1wire_s, pad_1wire_r, pad_1wire_f; 68 | synch_3 s01(pad_1wire, pad_1wire_s, clk, pad_1wire_r, pad_1wire_f); 69 | 70 | 71 | // 72 | // protocol fsm 73 | // 74 | 75 | reg [20:0] rx_timeout; // ~28ms 76 | 77 | reg [15:0] auto_poll_cnt; // 882us 78 | reg auto_poll_queue; 79 | 80 | reg [18:0] heartbeat_cnt; // 7ms 81 | reg heartbeat_queue; 82 | 83 | 84 | localparam ST_RESET = 'd0; 85 | localparam ST_IDLE = 'd1; 86 | localparam ST_RX_BUTTON_1 = 'd2; 87 | localparam ST_RX_BUTTON_2 = 'd3; 88 | localparam ST_TX_SCALER = 'd4; 89 | localparam ST_END_TX = 'd5; 90 | 91 | reg [3:0] state; 92 | reg [3:0] cnt; 93 | 94 | always @(posedge clk) begin 95 | tx_word_start <= 0; 96 | 97 | auto_poll_cnt <= auto_poll_cnt + 1'b1; 98 | heartbeat_cnt <= heartbeat_cnt + 1'b1; 99 | 100 | // increment rx timeout, override and reset when idle below 101 | rx_timeout <= rx_timeout + 1'b1; 102 | 103 | case(state) 104 | ST_RESET: begin 105 | reset_tr_n <= 0; 106 | rx_timed_out <= 0; 107 | 108 | if(&rx_timeout[19:0]) begin 109 | state <= ST_IDLE; 110 | end 111 | end 112 | ST_IDLE: begin 113 | // idle state 114 | reset_tr_n <= 1; 115 | rx_timeout <= 0; 116 | cnt <= 0; 117 | if(auto_poll_queue) begin 118 | auto_poll_queue <= 0; 119 | 120 | tx_word_start <= 1; 121 | tx_word <= 32'h4A10000C; 122 | 123 | state <= ST_RX_BUTTON_1; 124 | end else if(heartbeat_queue) begin 125 | heartbeat_queue <= 0; 126 | 127 | tx_word_start <= 1; 128 | tx_word <= 32'h4AFE0000; 129 | 130 | state <= ST_END_TX; 131 | end 132 | end 133 | // receive button words 134 | ST_RX_BUTTON_1: begin 135 | if(tx_word_done) begin 136 | state <= ST_RX_BUTTON_2; 137 | end 138 | end 139 | ST_RX_BUTTON_2: begin 140 | if(rx_word_done) begin 141 | cnt <= cnt + 1'b1; 142 | case(cnt) 143 | 0: cont1_key <= rx_word; 144 | 1: cont1_joy <= rx_word; 145 | 2: cont1_trig <= rx_word[15:0]; 146 | 147 | 3: cont2_key <= rx_word; 148 | 4: cont2_joy <= rx_word; 149 | 5: cont2_trig <= rx_word[15:0]; 150 | 151 | 6: cont3_key <= rx_word; 152 | 7: cont3_joy <= rx_word; 153 | 8: cont3_trig <= rx_word[15:0]; 154 | 155 | 9: cont4_key <= rx_word; 156 | 10: cont4_joy <= rx_word; 157 | 11: begin 158 | cont4_trig <= rx_word[15:0]; 159 | state <= ST_IDLE; 160 | end 161 | endcase 162 | end 163 | end 164 | // do nothing 165 | ST_END_TX: begin 166 | // done sending, idle again 167 | if(tx_word_done) begin 168 | state <= ST_IDLE; 169 | end 170 | end 171 | endcase 172 | 173 | 174 | if(&auto_poll_cnt) begin 175 | auto_poll_queue <= 1; 176 | end 177 | if(&heartbeat_cnt) begin 178 | heartbeat_queue <= 1; 179 | end 180 | 181 | if(&rx_timeout) begin 182 | // reset protocol FSM which will also reset t/r engine 183 | rx_timed_out <= 1; 184 | rx_timeout <= 0; 185 | state <= ST_RESET; 186 | end 187 | 188 | if(~reset_n_s) begin 189 | state <= ST_RESET; 190 | end 191 | end 192 | 193 | 194 | 195 | 196 | 197 | // 198 | // word receive/transmit engine 199 | // 200 | reg reset_tr_n; 201 | localparam BITLEN = 60; 202 | 203 | reg rx_word_done; 204 | reg [31:0] rx_word_shift; 205 | reg [31:0] rx_word; 206 | 207 | reg tx_word_start, tx_word_start_1; 208 | reg tx_word_done; 209 | reg [31:0] tx_word; 210 | reg [31:0] tx_word_shift; 211 | 212 | reg [7:0] tr_cnt; 213 | reg [5:0] tr_bit; 214 | 215 | localparam TR_IDLE = 'd1; 216 | localparam TR_TX_START = 'd2; 217 | localparam TR_TX_CONTINUE = 'd3; 218 | localparam TR_TX_DONE = 'd4; 219 | localparam TR_RX_START = 'd5; 220 | localparam TR_RX_WAITEDGE = 'd6; 221 | localparam TR_RX_DONE = 'd7; 222 | 223 | reg [3:0] tr_state; 224 | 225 | always @(posedge clk) begin 226 | 227 | rx_word_done <= 0; 228 | tx_word_done <= 0; 229 | 230 | tx_word_start_1 <= tx_word_start; 231 | 232 | case(tr_state) 233 | TR_IDLE: begin 234 | tr_bit <= 0; 235 | tr_cnt <= 0; 236 | 237 | pad_1wire <= 1'bZ; 238 | 239 | if(tx_word_start & ~tx_word_start_1) begin 240 | // transmit word 241 | tx_word_shift <= tx_word; 242 | tr_state <= TR_TX_START; 243 | end 244 | 245 | if(pad_1wire_f) begin 246 | // receive word 247 | tr_state <= TR_RX_START; 248 | end 249 | end 250 | 251 | // transmit 32bit 252 | TR_TX_START: begin 253 | // insert delay 254 | tr_cnt <= tr_cnt + 1'b1; 255 | if(&tr_cnt) begin 256 | // drive from tristate(high) to explicitly high to prevent glitching 257 | pad_1wire <= 1'b1; 258 | tr_state <= TR_TX_CONTINUE; 259 | end 260 | end 261 | TR_TX_CONTINUE: begin 262 | tr_cnt <= tr_cnt + 1'b1; 263 | case(tr_cnt) 264 | 0: begin 265 | pad_1wire <= 1'b0; 266 | end 267 | (BITLEN/3): begin 268 | pad_1wire <= tx_word_shift[31]; 269 | end 270 | (BITLEN*2/3): begin 271 | pad_1wire <= 1'b1; 272 | end 273 | (BITLEN-1): begin 274 | tr_cnt <= 0; 275 | tx_word_shift <= {tx_word_shift[30:0], 1'b1}; 276 | 277 | tr_bit <= tr_bit + 1'b1; 278 | if(tr_bit == 31) begin 279 | tr_state <= TR_TX_DONE; 280 | end 281 | end 282 | endcase 283 | end 284 | TR_TX_DONE: begin 285 | tx_word_done <= 1; 286 | tr_state <= TR_IDLE; 287 | end 288 | 289 | // receive 32bit 290 | TR_RX_START: begin 291 | tr_cnt <= tr_cnt + 1'b1; 292 | case(tr_cnt) 293 | (BITLEN/2-4): begin 294 | rx_word_shift <= {rx_word_shift[30:0], pad_1wire_s}; 295 | end 296 | (BITLEN*5/6): begin 297 | tr_cnt <= 0; 298 | 299 | // wait for next falling edge 300 | tr_state <= TR_RX_WAITEDGE; 301 | tr_bit <= tr_bit + 1'b1; 302 | if(tr_bit == 31) begin 303 | // if this is bit32, don't wait and finish 304 | tr_state <= TR_RX_DONE; 305 | end 306 | end 307 | endcase 308 | end 309 | TR_RX_WAITEDGE: begin 310 | if(pad_1wire_f) begin 311 | tr_state <= TR_RX_START; 312 | end 313 | end 314 | TR_RX_DONE: begin 315 | rx_word <= rx_word_shift; 316 | rx_word_done <= 1; 317 | tr_state <= TR_IDLE; 318 | end 319 | 320 | default: begin 321 | tr_state <= TR_IDLE; 322 | end 323 | endcase 324 | 325 | if(~reset_n_s | ~reset_tr_n) tr_state <= TR_IDLE; 326 | end 327 | 328 | endmodule -------------------------------------------------------------------------------- /src/fpga/apf/mf_datatable.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name IP_TOOL_NAME "RAM: 2-PORT" 2 | set_global_assignment -name IP_TOOL_VERSION "18.1" 3 | set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone V}" 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "mf_datatable.v"] 5 | -------------------------------------------------------------------------------- /src/fpga/apf/mf_datatable.v: -------------------------------------------------------------------------------- 1 | // megafunction wizard: %RAM: 2-PORT% 2 | // GENERATION: STANDARD 3 | // VERSION: WM1.0 4 | // MODULE: altsyncram 5 | 6 | // ============================================================ 7 | // File Name: mf_datatable.v 8 | // Megafunction Name(s): 9 | // altsyncram 10 | // 11 | // Simulation Library Files(s): 12 | // altera_mf 13 | // ============================================================ 14 | // ************************************************************ 15 | // THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! 16 | // 17 | // 18.1.1 Build 646 04/11/2019 SJ Lite Edition 18 | // ************************************************************ 19 | 20 | 21 | //Copyright (C) 2019 Intel Corporation. All rights reserved. 22 | //Your use of Intel Corporation's design tools, logic functions 23 | //and other software and tools, and any partner logic 24 | //functions, and any output files from any of the foregoing 25 | //(including device programming or simulation files), and any 26 | //associated documentation or information are expressly subject 27 | //to the terms and conditions of the Intel Program License 28 | //Subscription Agreement, the Intel Quartus Prime License Agreement, 29 | //the Intel FPGA IP License Agreement, or other applicable license 30 | //agreement, including, without limitation, that your use is for 31 | //the sole purpose of programming logic devices manufactured by 32 | //Intel and sold by Intel or its authorized distributors. Please 33 | //refer to the applicable agreement for further details, at 34 | //https://fpgasoftware.intel.com/eula. 35 | 36 | 37 | // synopsys translate_off 38 | `timescale 1 ps / 1 ps 39 | // synopsys translate_on 40 | module mf_datatable ( 41 | address_a, 42 | address_b, 43 | clock_a, 44 | clock_b, 45 | data_a, 46 | data_b, 47 | wren_a, 48 | wren_b, 49 | q_a, 50 | q_b); 51 | 52 | input [7:0] address_a; 53 | input [7:0] address_b; 54 | input clock_a; 55 | input clock_b; 56 | input [31:0] data_a; 57 | input [31:0] data_b; 58 | input wren_a; 59 | input wren_b; 60 | output [31:0] q_a; 61 | output [31:0] q_b; 62 | `ifndef ALTERA_RESERVED_QIS 63 | // synopsys translate_off 64 | `endif 65 | tri1 clock_a; 66 | tri0 wren_a; 67 | tri0 wren_b; 68 | `ifndef ALTERA_RESERVED_QIS 69 | // synopsys translate_on 70 | `endif 71 | 72 | wire [31:0] sub_wire0; 73 | wire [31:0] sub_wire1; 74 | wire [31:0] q_a = sub_wire0[31:0]; 75 | wire [31:0] q_b = sub_wire1[31:0]; 76 | 77 | altsyncram altsyncram_component ( 78 | .address_a (address_a), 79 | .address_b (address_b), 80 | .clock0 (clock_a), 81 | .clock1 (clock_b), 82 | .data_a (data_a), 83 | .data_b (data_b), 84 | .wren_a (wren_a), 85 | .wren_b (wren_b), 86 | .q_a (sub_wire0), 87 | .q_b (sub_wire1), 88 | .aclr0 (1'b0), 89 | .aclr1 (1'b0), 90 | .addressstall_a (1'b0), 91 | .addressstall_b (1'b0), 92 | .byteena_a (1'b1), 93 | .byteena_b (1'b1), 94 | .clocken0 (1'b1), 95 | .clocken1 (1'b1), 96 | .clocken2 (1'b1), 97 | .clocken3 (1'b1), 98 | .eccstatus (), 99 | .rden_a (1'b1), 100 | .rden_b (1'b1)); 101 | defparam 102 | altsyncram_component.address_reg_b = "CLOCK1", 103 | altsyncram_component.clock_enable_input_a = "BYPASS", 104 | altsyncram_component.clock_enable_input_b = "BYPASS", 105 | altsyncram_component.clock_enable_output_a = "BYPASS", 106 | altsyncram_component.clock_enable_output_b = "BYPASS", 107 | altsyncram_component.indata_reg_b = "CLOCK1", 108 | altsyncram_component.init_file = "./apf/build_id.mif", 109 | altsyncram_component.intended_device_family = "Cyclone V", 110 | altsyncram_component.lpm_type = "altsyncram", 111 | altsyncram_component.numwords_a = 256, 112 | altsyncram_component.numwords_b = 256, 113 | altsyncram_component.operation_mode = "BIDIR_DUAL_PORT", 114 | altsyncram_component.outdata_aclr_a = "NONE", 115 | altsyncram_component.outdata_aclr_b = "NONE", 116 | altsyncram_component.outdata_reg_a = "CLOCK0", 117 | altsyncram_component.outdata_reg_b = "CLOCK1", 118 | altsyncram_component.power_up_uninitialized = "FALSE", 119 | altsyncram_component.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ", 120 | altsyncram_component.read_during_write_mode_port_b = "NEW_DATA_NO_NBE_READ", 121 | altsyncram_component.widthad_a = 8, 122 | altsyncram_component.widthad_b = 8, 123 | altsyncram_component.width_a = 32, 124 | altsyncram_component.width_b = 32, 125 | altsyncram_component.width_byteena_a = 1, 126 | altsyncram_component.width_byteena_b = 1, 127 | altsyncram_component.wrcontrol_wraddress_reg_b = "CLOCK1"; 128 | 129 | 130 | endmodule 131 | 132 | // ============================================================ 133 | // CNX file retrieval info 134 | // ============================================================ 135 | // Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0" 136 | // Retrieval info: PRIVATE: ADDRESSSTALL_B NUMERIC "0" 137 | // Retrieval info: PRIVATE: BYTEENA_ACLR_A NUMERIC "0" 138 | // Retrieval info: PRIVATE: BYTEENA_ACLR_B NUMERIC "0" 139 | // Retrieval info: PRIVATE: BYTE_ENABLE_A NUMERIC "0" 140 | // Retrieval info: PRIVATE: BYTE_ENABLE_B NUMERIC "0" 141 | // Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8" 142 | // Retrieval info: PRIVATE: BlankMemory NUMERIC "0" 143 | // Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "0" 144 | // Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_B NUMERIC "0" 145 | // Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "0" 146 | // Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_B NUMERIC "0" 147 | // Retrieval info: PRIVATE: CLRdata NUMERIC "0" 148 | // Retrieval info: PRIVATE: CLRq NUMERIC "0" 149 | // Retrieval info: PRIVATE: CLRrdaddress NUMERIC "0" 150 | // Retrieval info: PRIVATE: CLRrren NUMERIC "0" 151 | // Retrieval info: PRIVATE: CLRwraddress NUMERIC "0" 152 | // Retrieval info: PRIVATE: CLRwren NUMERIC "0" 153 | // Retrieval info: PRIVATE: Clock NUMERIC "5" 154 | // Retrieval info: PRIVATE: Clock_A NUMERIC "0" 155 | // Retrieval info: PRIVATE: Clock_B NUMERIC "0" 156 | // Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0" 157 | // Retrieval info: PRIVATE: INDATA_ACLR_B NUMERIC "0" 158 | // Retrieval info: PRIVATE: INDATA_REG_B NUMERIC "1" 159 | // Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_A" 160 | // Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0" 161 | // Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone V" 162 | // Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0" 163 | // Retrieval info: PRIVATE: JTAG_ID STRING "NONE" 164 | // Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0" 165 | // Retrieval info: PRIVATE: MEMSIZE NUMERIC "8192" 166 | // Retrieval info: PRIVATE: MEM_IN_BITS NUMERIC "0" 167 | // Retrieval info: PRIVATE: MIFfilename STRING "./apf/build_id.mif" 168 | // Retrieval info: PRIVATE: OPERATION_MODE NUMERIC "3" 169 | // Retrieval info: PRIVATE: OUTDATA_ACLR_B NUMERIC "0" 170 | // Retrieval info: PRIVATE: OUTDATA_REG_B NUMERIC "1" 171 | // Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0" 172 | // Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_MIXED_PORTS NUMERIC "2" 173 | // Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_A NUMERIC "3" 174 | // Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_B NUMERIC "3" 175 | // Retrieval info: PRIVATE: REGdata NUMERIC "1" 176 | // Retrieval info: PRIVATE: REGq NUMERIC "1" 177 | // Retrieval info: PRIVATE: REGrdaddress NUMERIC "0" 178 | // Retrieval info: PRIVATE: REGrren NUMERIC "0" 179 | // Retrieval info: PRIVATE: REGwraddress NUMERIC "1" 180 | // Retrieval info: PRIVATE: REGwren NUMERIC "1" 181 | // Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" 182 | // Retrieval info: PRIVATE: USE_DIFF_CLKEN NUMERIC "0" 183 | // Retrieval info: PRIVATE: UseDPRAM NUMERIC "1" 184 | // Retrieval info: PRIVATE: VarWidth NUMERIC "0" 185 | // Retrieval info: PRIVATE: WIDTH_READ_A NUMERIC "32" 186 | // Retrieval info: PRIVATE: WIDTH_READ_B NUMERIC "32" 187 | // Retrieval info: PRIVATE: WIDTH_WRITE_A NUMERIC "32" 188 | // Retrieval info: PRIVATE: WIDTH_WRITE_B NUMERIC "32" 189 | // Retrieval info: PRIVATE: WRADDR_ACLR_B NUMERIC "0" 190 | // Retrieval info: PRIVATE: WRADDR_REG_B NUMERIC "1" 191 | // Retrieval info: PRIVATE: WRCTRL_ACLR_B NUMERIC "0" 192 | // Retrieval info: PRIVATE: enable NUMERIC "0" 193 | // Retrieval info: PRIVATE: rden NUMERIC "0" 194 | // Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all 195 | // Retrieval info: CONSTANT: ADDRESS_REG_B STRING "CLOCK1" 196 | // Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "BYPASS" 197 | // Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_B STRING "BYPASS" 198 | // Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "BYPASS" 199 | // Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_B STRING "BYPASS" 200 | // Retrieval info: CONSTANT: INDATA_REG_B STRING "CLOCK1" 201 | // Retrieval info: CONSTANT: INIT_FILE STRING "./apf/build_id.mif" 202 | // Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone V" 203 | // Retrieval info: CONSTANT: LPM_TYPE STRING "altsyncram" 204 | // Retrieval info: CONSTANT: NUMWORDS_A NUMERIC "256" 205 | // Retrieval info: CONSTANT: NUMWORDS_B NUMERIC "256" 206 | // Retrieval info: CONSTANT: OPERATION_MODE STRING "BIDIR_DUAL_PORT" 207 | // Retrieval info: CONSTANT: OUTDATA_ACLR_A STRING "NONE" 208 | // Retrieval info: CONSTANT: OUTDATA_ACLR_B STRING "NONE" 209 | // Retrieval info: CONSTANT: OUTDATA_REG_A STRING "CLOCK0" 210 | // Retrieval info: CONSTANT: OUTDATA_REG_B STRING "CLOCK1" 211 | // Retrieval info: CONSTANT: POWER_UP_UNINITIALIZED STRING "FALSE" 212 | // Retrieval info: CONSTANT: READ_DURING_WRITE_MODE_PORT_A STRING "NEW_DATA_NO_NBE_READ" 213 | // Retrieval info: CONSTANT: READ_DURING_WRITE_MODE_PORT_B STRING "NEW_DATA_NO_NBE_READ" 214 | // Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "8" 215 | // Retrieval info: CONSTANT: WIDTHAD_B NUMERIC "8" 216 | // Retrieval info: CONSTANT: WIDTH_A NUMERIC "32" 217 | // Retrieval info: CONSTANT: WIDTH_B NUMERIC "32" 218 | // Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1" 219 | // Retrieval info: CONSTANT: WIDTH_BYTEENA_B NUMERIC "1" 220 | // Retrieval info: CONSTANT: WRCONTROL_WRADDRESS_REG_B STRING "CLOCK1" 221 | // Retrieval info: USED_PORT: address_a 0 0 8 0 INPUT NODEFVAL "address_a[7..0]" 222 | // Retrieval info: USED_PORT: address_b 0 0 8 0 INPUT NODEFVAL "address_b[7..0]" 223 | // Retrieval info: USED_PORT: clock_a 0 0 0 0 INPUT VCC "clock_a" 224 | // Retrieval info: USED_PORT: clock_b 0 0 0 0 INPUT NODEFVAL "clock_b" 225 | // Retrieval info: USED_PORT: data_a 0 0 32 0 INPUT NODEFVAL "data_a[31..0]" 226 | // Retrieval info: USED_PORT: data_b 0 0 32 0 INPUT NODEFVAL "data_b[31..0]" 227 | // Retrieval info: USED_PORT: q_a 0 0 32 0 OUTPUT NODEFVAL "q_a[31..0]" 228 | // Retrieval info: USED_PORT: q_b 0 0 32 0 OUTPUT NODEFVAL "q_b[31..0]" 229 | // Retrieval info: USED_PORT: wren_a 0 0 0 0 INPUT GND "wren_a" 230 | // Retrieval info: USED_PORT: wren_b 0 0 0 0 INPUT GND "wren_b" 231 | // Retrieval info: CONNECT: @address_a 0 0 8 0 address_a 0 0 8 0 232 | // Retrieval info: CONNECT: @address_b 0 0 8 0 address_b 0 0 8 0 233 | // Retrieval info: CONNECT: @clock0 0 0 0 0 clock_a 0 0 0 0 234 | // Retrieval info: CONNECT: @clock1 0 0 0 0 clock_b 0 0 0 0 235 | // Retrieval info: CONNECT: @data_a 0 0 32 0 data_a 0 0 32 0 236 | // Retrieval info: CONNECT: @data_b 0 0 32 0 data_b 0 0 32 0 237 | // Retrieval info: CONNECT: @wren_a 0 0 0 0 wren_a 0 0 0 0 238 | // Retrieval info: CONNECT: @wren_b 0 0 0 0 wren_b 0 0 0 0 239 | // Retrieval info: CONNECT: q_a 0 0 32 0 @q_a 0 0 32 0 240 | // Retrieval info: CONNECT: q_b 0 0 32 0 @q_b 0 0 32 0 241 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_datatable.v TRUE 242 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_datatable.inc FALSE 243 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_datatable.cmp FALSE 244 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_datatable.bsf FALSE 245 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_datatable_inst.v FALSE 246 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_datatable_bb.v FALSE 247 | // Retrieval info: LIB_FILE: altera_mf 248 | -------------------------------------------------------------------------------- /src/fpga/apf/mf_ddio_bidir_12.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name IP_TOOL_NAME "ALTDDIO_BIDIR" 2 | set_global_assignment -name IP_TOOL_VERSION "18.1" 3 | set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone V}" 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "mf_ddio_bidir_12.v"] 5 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "mf_ddio_bidir_12.ppf"] 6 | -------------------------------------------------------------------------------- /src/fpga/apf/mf_ddio_bidir_12.v: -------------------------------------------------------------------------------- 1 | // megafunction wizard: %ALTDDIO_BIDIR% 2 | // GENERATION: STANDARD 3 | // VERSION: WM1.0 4 | // MODULE: ALTDDIO_BIDIR 5 | 6 | // ============================================================ 7 | // File Name: mf_ddio_bidir_12.v 8 | // Megafunction Name(s): 9 | // ALTDDIO_BIDIR 10 | // 11 | // Simulation Library Files(s): 12 | // altera_mf 13 | // ============================================================ 14 | // ************************************************************ 15 | // THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! 16 | // 17 | // 18.1.1 Build 646 04/11/2019 SJ Lite Edition 18 | // ************************************************************ 19 | 20 | 21 | //Copyright (C) 2019 Intel Corporation. All rights reserved. 22 | //Your use of Intel Corporation's design tools, logic functions 23 | //and other software and tools, and any partner logic 24 | //functions, and any output files from any of the foregoing 25 | //(including device programming or simulation files), and any 26 | //associated documentation or information are expressly subject 27 | //to the terms and conditions of the Intel Program License 28 | //Subscription Agreement, the Intel Quartus Prime License Agreement, 29 | //the Intel FPGA IP License Agreement, or other applicable license 30 | //agreement, including, without limitation, that your use is for 31 | //the sole purpose of programming logic devices manufactured by 32 | //Intel and sold by Intel or its authorized distributors. Please 33 | //refer to the applicable agreement for further details, at 34 | //https://fpgasoftware.intel.com/eula. 35 | 36 | 37 | // synopsys translate_off 38 | `timescale 1 ps / 1 ps 39 | // synopsys translate_on 40 | module mf_ddio_bidir_12 ( 41 | datain_h, 42 | datain_l, 43 | inclock, 44 | oe, 45 | outclock, 46 | dataout_h, 47 | dataout_l, 48 | padio); 49 | 50 | input [11:0] datain_h; 51 | input [11:0] datain_l; 52 | input inclock; 53 | input oe; 54 | input outclock; 55 | output [11:0] dataout_h; 56 | output [11:0] dataout_l; 57 | inout [11:0] padio; 58 | 59 | wire [11:0] sub_wire0; 60 | wire [11:0] sub_wire1; 61 | wire [11:0] dataout_h = sub_wire0[11:0]; 62 | wire [11:0] dataout_l = sub_wire1[11:0]; 63 | 64 | altddio_bidir ALTDDIO_BIDIR_component ( 65 | .datain_h (datain_h), 66 | .datain_l (datain_l), 67 | .inclock (inclock), 68 | .oe (oe), 69 | .outclock (outclock), 70 | .padio (padio), 71 | .dataout_h (sub_wire0), 72 | .dataout_l (sub_wire1), 73 | .aclr (1'b0), 74 | .aset (1'b0), 75 | .combout (), 76 | .dqsundelayedout (), 77 | .inclocken (1'b1), 78 | .oe_out (), 79 | .outclocken (1'b1), 80 | .sclr (1'b0), 81 | .sset (1'b0)); 82 | defparam 83 | ALTDDIO_BIDIR_component.extend_oe_disable = "OFF", 84 | ALTDDIO_BIDIR_component.implement_input_in_lcell = "OFF", 85 | ALTDDIO_BIDIR_component.intended_device_family = "Cyclone V", 86 | ALTDDIO_BIDIR_component.invert_output = "OFF", 87 | ALTDDIO_BIDIR_component.lpm_hint = "UNUSED", 88 | ALTDDIO_BIDIR_component.lpm_type = "altddio_bidir", 89 | ALTDDIO_BIDIR_component.oe_reg = "UNREGISTERED", 90 | ALTDDIO_BIDIR_component.power_up_high = "OFF", 91 | ALTDDIO_BIDIR_component.width = 12; 92 | 93 | 94 | endmodule 95 | 96 | // ============================================================ 97 | // CNX file retrieval info 98 | // ============================================================ 99 | // Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all 100 | // Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone V" 101 | // Retrieval info: CONSTANT: EXTEND_OE_DISABLE STRING "OFF" 102 | // Retrieval info: CONSTANT: IMPLEMENT_INPUT_IN_LCELL STRING "OFF" 103 | // Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone V" 104 | // Retrieval info: CONSTANT: INVERT_OUTPUT STRING "OFF" 105 | // Retrieval info: CONSTANT: LPM_HINT STRING "UNUSED" 106 | // Retrieval info: CONSTANT: LPM_TYPE STRING "altddio_bidir" 107 | // Retrieval info: CONSTANT: OE_REG STRING "UNREGISTERED" 108 | // Retrieval info: CONSTANT: POWER_UP_HIGH STRING "OFF" 109 | // Retrieval info: CONSTANT: WIDTH NUMERIC "12" 110 | // Retrieval info: USED_PORT: datain_h 0 0 12 0 INPUT NODEFVAL "datain_h[11..0]" 111 | // Retrieval info: CONNECT: @datain_h 0 0 12 0 datain_h 0 0 12 0 112 | // Retrieval info: USED_PORT: datain_l 0 0 12 0 INPUT NODEFVAL "datain_l[11..0]" 113 | // Retrieval info: CONNECT: @datain_l 0 0 12 0 datain_l 0 0 12 0 114 | // Retrieval info: USED_PORT: dataout_h 0 0 12 0 OUTPUT NODEFVAL "dataout_h[11..0]" 115 | // Retrieval info: CONNECT: dataout_h 0 0 12 0 @dataout_h 0 0 12 0 116 | // Retrieval info: USED_PORT: dataout_l 0 0 12 0 OUTPUT NODEFVAL "dataout_l[11..0]" 117 | // Retrieval info: CONNECT: dataout_l 0 0 12 0 @dataout_l 0 0 12 0 118 | // Retrieval info: USED_PORT: inclock 0 0 0 0 INPUT_CLK_EXT NODEFVAL "inclock" 119 | // Retrieval info: CONNECT: @inclock 0 0 0 0 inclock 0 0 0 0 120 | // Retrieval info: USED_PORT: oe 0 0 0 0 INPUT NODEFVAL "oe" 121 | // Retrieval info: CONNECT: @oe 0 0 0 0 oe 0 0 0 0 122 | // Retrieval info: USED_PORT: outclock 0 0 0 0 INPUT_CLK_EXT NODEFVAL "outclock" 123 | // Retrieval info: CONNECT: @outclock 0 0 0 0 outclock 0 0 0 0 124 | // Retrieval info: USED_PORT: padio 0 0 12 0 BIDIR NODEFVAL "padio[11..0]" 125 | // Retrieval info: CONNECT: padio 0 0 12 0 @padio 0 0 12 0 126 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_ddio_bidir_12.v TRUE FALSE 127 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_ddio_bidir_12.qip TRUE FALSE 128 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_ddio_bidir_12.bsf FALSE TRUE 129 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_ddio_bidir_12_inst.v FALSE TRUE 130 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_ddio_bidir_12_bb.v FALSE TRUE 131 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_ddio_bidir_12.inc FALSE TRUE 132 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_ddio_bidir_12.cmp FALSE TRUE 133 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_ddio_bidir_12.ppf TRUE FALSE 134 | // Retrieval info: LIB_FILE: altera_mf 135 | -------------------------------------------------------------------------------- /src/fpga/core/core_constraints.sdc: -------------------------------------------------------------------------------- 1 | # 2 | # user core constraints 3 | # 4 | # put your clock groups in here as well as any net assignments 5 | # 6 | 7 | set_clock_groups -asynchronous \ 8 | -group { bridge_spiclk } \ 9 | -group { clk_74a } \ 10 | -group { clk_74b } \ 11 | -group { ic|mp1|mf_pllbase_inst|altera_pll_i|general[0].gpll~PLL_OUTPUT_COUNTER|divclk } \ 12 | -group { ic|mp1|mf_pllbase_inst|altera_pll_i|general[1].gpll~PLL_OUTPUT_COUNTER|divclk } \ 13 | -group { ic|mp1|mf_pllbase_inst|altera_pll_i|general[2].gpll~PLL_OUTPUT_COUNTER|divclk } \ 14 | -group { ic|mp1|mf_pllbase_inst|altera_pll_i|general[3].gpll~PLL_OUTPUT_COUNTER|divclk } 15 | -------------------------------------------------------------------------------- /src/fpga/core/mf_pllbase.bsf: -------------------------------------------------------------------------------- 1 | /* 2 | WARNING: Do NOT edit the input and output ports in this file in a text 3 | editor if you plan to continue editing the block that represents it in 4 | the Block Editor! File corruption is VERY likely to occur. 5 | */ 6 | /* 7 | Copyright (C) 2022 Intel Corporation. All rights reserved. 8 | Your use of Intel Corporation's design tools, logic functions 9 | and other software and tools, and any partner logic 10 | functions, and any output files from any of the foregoing 11 | (including device programming or simulation files), and any 12 | associated documentation or information are expressly subject 13 | to the terms and conditions of the Intel Program License 14 | Subscription Agreement, the Intel Quartus Prime License Agreement, 15 | the Intel FPGA IP License Agreement, or other applicable license 16 | agreement, including, without limitation, that your use is for 17 | the sole purpose of programming logic devices manufactured by 18 | Intel and sold by Intel or its authorized distributors. Please 19 | refer to the applicable agreement for further details, at 20 | https://fpgasoftware.intel.com/eula. 21 | */ 22 | (header "symbol" (version "1.1")) 23 | (symbol 24 | (rect 0 0 160 304) 25 | (text "mf_pllbase" (rect 48 -1 91 11)(font "Arial" (font_size 10))) 26 | (text "inst" (rect 8 288 20 300)(font "Arial" )) 27 | (port 28 | (pt 0 72) 29 | (input) 30 | (text "refclk" (rect 0 0 22 12)(font "Arial" (font_size 8))) 31 | (text "refclk" (rect 4 61 40 72)(font "Arial" (font_size 8))) 32 | (line (pt 0 72)(pt 48 72)(line_width 1)) 33 | ) 34 | (port 35 | (pt 0 112) 36 | (input) 37 | (text "rst" (rect 0 0 10 12)(font "Arial" (font_size 8))) 38 | (text "rst" (rect 4 101 22 112)(font "Arial" (font_size 8))) 39 | (line (pt 0 112)(pt 48 112)(line_width 1)) 40 | ) 41 | (port 42 | (pt 160 72) 43 | (output) 44 | (text "outclk_0" (rect 0 0 33 12)(font "Arial" (font_size 8))) 45 | (text "outclk_0" (rect 117 61 165 72)(font "Arial" (font_size 8))) 46 | (line (pt 160 72)(pt 112 72)(line_width 1)) 47 | ) 48 | (port 49 | (pt 160 112) 50 | (output) 51 | (text "outclk_1" (rect 0 0 31 12)(font "Arial" (font_size 8))) 52 | (text "outclk_1" (rect 119 101 167 112)(font "Arial" (font_size 8))) 53 | (line (pt 160 112)(pt 112 112)(line_width 1)) 54 | ) 55 | (port 56 | (pt 160 152) 57 | (output) 58 | (text "outclk_2" (rect 0 0 33 12)(font "Arial" (font_size 8))) 59 | (text "outclk_2" (rect 117 141 165 152)(font "Arial" (font_size 8))) 60 | (line (pt 160 152)(pt 112 152)(line_width 1)) 61 | ) 62 | (port 63 | (pt 160 192) 64 | (output) 65 | (text "outclk_3" (rect 0 0 33 12)(font "Arial" (font_size 8))) 66 | (text "outclk_3" (rect 117 181 165 192)(font "Arial" (font_size 8))) 67 | (line (pt 160 192)(pt 112 192)(line_width 1)) 68 | ) 69 | (port 70 | (pt 160 232) 71 | (output) 72 | (text "outclk_4" (rect 0 0 34 12)(font "Arial" (font_size 8))) 73 | (text "outclk_4" (rect 117 221 165 232)(font "Arial" (font_size 8))) 74 | (line (pt 160 232)(pt 112 232)(line_width 1)) 75 | ) 76 | (port 77 | (pt 160 272) 78 | (output) 79 | (text "locked" (rect 0 0 24 12)(font "Arial" (font_size 8))) 80 | (text "locked" (rect 127 261 163 272)(font "Arial" (font_size 8))) 81 | (line (pt 160 272)(pt 112 272)(line_width 1)) 82 | ) 83 | (drawing 84 | (text "refclk" (rect 16 43 68 99)(font "Arial" (color 128 0 0)(font_size 9))) 85 | (text "clk" (rect 53 67 124 144)(font "Arial" (color 0 0 0))) 86 | (text "reset" (rect 19 83 68 179)(font "Arial" (color 128 0 0)(font_size 9))) 87 | (text "reset" (rect 53 107 136 224)(font "Arial" (color 0 0 0))) 88 | (text "outclk0" (rect 113 43 268 99)(font "Arial" (color 128 0 0)(font_size 9))) 89 | (text "clk" (rect 97 67 212 144)(font "Arial" (color 0 0 0))) 90 | (text "outclk1" (rect 113 83 268 179)(font "Arial" (color 128 0 0)(font_size 9))) 91 | (text "clk" (rect 97 107 212 224)(font "Arial" (color 0 0 0))) 92 | (text "outclk2" (rect 113 123 268 259)(font "Arial" (color 128 0 0)(font_size 9))) 93 | (text "clk" (rect 97 147 212 304)(font "Arial" (color 0 0 0))) 94 | (text "outclk3" (rect 113 163 268 339)(font "Arial" (color 128 0 0)(font_size 9))) 95 | (text "clk" (rect 97 187 212 384)(font "Arial" (color 0 0 0))) 96 | (text "outclk4" (rect 113 203 268 419)(font "Arial" (color 128 0 0)(font_size 9))) 97 | (text "clk" (rect 97 227 212 464)(font "Arial" (color 0 0 0))) 98 | (text "locked" (rect 113 243 262 499)(font "Arial" (color 128 0 0)(font_size 9))) 99 | (text "export" (rect 82 267 200 544)(font "Arial" (color 0 0 0))) 100 | (text " altera_pll " (rect 118 288 308 586)(font "Arial" )) 101 | (line (pt 48 32)(pt 112 32)(line_width 1)) 102 | (line (pt 112 32)(pt 112 288)(line_width 1)) 103 | (line (pt 48 288)(pt 112 288)(line_width 1)) 104 | (line (pt 48 32)(pt 48 288)(line_width 1)) 105 | (line (pt 49 52)(pt 49 76)(line_width 1)) 106 | (line (pt 50 52)(pt 50 76)(line_width 1)) 107 | (line (pt 49 92)(pt 49 116)(line_width 1)) 108 | (line (pt 50 92)(pt 50 116)(line_width 1)) 109 | (line (pt 111 52)(pt 111 76)(line_width 1)) 110 | (line (pt 110 52)(pt 110 76)(line_width 1)) 111 | (line (pt 111 92)(pt 111 116)(line_width 1)) 112 | (line (pt 110 92)(pt 110 116)(line_width 1)) 113 | (line (pt 111 132)(pt 111 156)(line_width 1)) 114 | (line (pt 110 132)(pt 110 156)(line_width 1)) 115 | (line (pt 111 172)(pt 111 196)(line_width 1)) 116 | (line (pt 110 172)(pt 110 196)(line_width 1)) 117 | (line (pt 111 212)(pt 111 236)(line_width 1)) 118 | (line (pt 110 212)(pt 110 236)(line_width 1)) 119 | (line (pt 111 252)(pt 111 276)(line_width 1)) 120 | (line (pt 110 252)(pt 110 276)(line_width 1)) 121 | (line (pt 0 0)(pt 160 0)(line_width 1)) 122 | (line (pt 160 0)(pt 160 304)(line_width 1)) 123 | (line (pt 0 304)(pt 160 304)(line_width 1)) 124 | (line (pt 0 0)(pt 0 304)(line_width 1)) 125 | ) 126 | ) 127 | -------------------------------------------------------------------------------- /src/fpga/core/mf_pllbase.ppf: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/fpga/core/mf_pllbase.sip: -------------------------------------------------------------------------------- 1 | set_global_assignment -entity "mf_pllbase" -library "lib_mf_pllbase" -name IP_TOOL_NAME "altera_pll" 2 | set_global_assignment -entity "mf_pllbase" -library "lib_mf_pllbase" -name IP_TOOL_VERSION "21.1" 3 | set_global_assignment -entity "mf_pllbase" -library "lib_mf_pllbase" -name IP_TOOL_ENV "mwpim" 4 | set_global_assignment -library "lib_mf_pllbase" -name SPD_FILE [file join $::quartus(sip_path) "mf_pllbase.spd"] 5 | 6 | set_global_assignment -library "lib_mf_pllbase" -name MISC_FILE [file join $::quartus(sip_path) "mf_pllbase_sim/mf_pllbase.vo"] 7 | -------------------------------------------------------------------------------- /src/fpga/core/mf_pllbase.spd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/fpga/core/mf_pllbase/mf_pllbase_0002.qip: -------------------------------------------------------------------------------- 1 | set_instance_assignment -name PLL_COMPENSATION_MODE NORMAL -to "*mf_pllbase_0002*|altera_pll:altera_pll_i*|*" 2 | set_instance_assignment -name PLL_CHANNEL_SPACING "0.0 KHz" -to "*mf_pllbase_0002*|altera_pll:altera_pll_i*|*" 3 | set_instance_assignment -name PLL_AUTO_RESET OFF -to "*mf_pllbase_0002*|altera_pll:altera_pll_i*|*" 4 | set_instance_assignment -name PLL_BANDWIDTH_PRESET AUTO -to "*mf_pllbase_0002*|altera_pll:altera_pll_i*|*" 5 | -------------------------------------------------------------------------------- /src/fpga/core/mf_pllbase/mf_pllbase_0002.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/10ps 2 | module mf_pllbase_0002( 3 | 4 | // interface 'refclk' 5 | input wire refclk, 6 | 7 | // interface 'reset' 8 | input wire rst, 9 | 10 | // interface 'outclk0' 11 | output wire outclk_0, 12 | 13 | // interface 'outclk1' 14 | output wire outclk_1, 15 | 16 | // interface 'outclk2' 17 | output wire outclk_2, 18 | 19 | // interface 'outclk3' 20 | output wire outclk_3, 21 | 22 | // interface 'outclk4' 23 | output wire outclk_4, 24 | 25 | // interface 'locked' 26 | output wire locked 27 | ); 28 | 29 | altera_pll #( 30 | .fractional_vco_multiplier("true"), 31 | .reference_clock_frequency("74.25 MHz"), 32 | .operation_mode("normal"), 33 | .number_of_clocks(5), 34 | .output_clock_frequency0("7.158999 MHz"), 35 | .phase_shift0("0 ps"), 36 | .duty_cycle0(50), 37 | .output_clock_frequency1("7.158999 MHz"), 38 | .phase_shift1("34921 ps"), 39 | .duty_cycle1(50), 40 | .output_clock_frequency2("28.635997 MHz"), 41 | .phase_shift2("0 ps"), 42 | .duty_cycle2(50), 43 | .output_clock_frequency3("132.766896 MHz"), 44 | .phase_shift3("6590 ps"), 45 | .duty_cycle3(50), 46 | .output_clock_frequency4("132.766892 MHz"), 47 | .phase_shift4("5649 ps"), 48 | .duty_cycle4(50), 49 | .output_clock_frequency5("0 MHz"), 50 | .phase_shift5("0 ps"), 51 | .duty_cycle5(50), 52 | .output_clock_frequency6("0 MHz"), 53 | .phase_shift6("0 ps"), 54 | .duty_cycle6(50), 55 | .output_clock_frequency7("0 MHz"), 56 | .phase_shift7("0 ps"), 57 | .duty_cycle7(50), 58 | .output_clock_frequency8("0 MHz"), 59 | .phase_shift8("0 ps"), 60 | .duty_cycle8(50), 61 | .output_clock_frequency9("0 MHz"), 62 | .phase_shift9("0 ps"), 63 | .duty_cycle9(50), 64 | .output_clock_frequency10("0 MHz"), 65 | .phase_shift10("0 ps"), 66 | .duty_cycle10(50), 67 | .output_clock_frequency11("0 MHz"), 68 | .phase_shift11("0 ps"), 69 | .duty_cycle11(50), 70 | .output_clock_frequency12("0 MHz"), 71 | .phase_shift12("0 ps"), 72 | .duty_cycle12(50), 73 | .output_clock_frequency13("0 MHz"), 74 | .phase_shift13("0 ps"), 75 | .duty_cycle13(50), 76 | .output_clock_frequency14("0 MHz"), 77 | .phase_shift14("0 ps"), 78 | .duty_cycle14(50), 79 | .output_clock_frequency15("0 MHz"), 80 | .phase_shift15("0 ps"), 81 | .duty_cycle15(50), 82 | .output_clock_frequency16("0 MHz"), 83 | .phase_shift16("0 ps"), 84 | .duty_cycle16(50), 85 | .output_clock_frequency17("0 MHz"), 86 | .phase_shift17("0 ps"), 87 | .duty_cycle17(50), 88 | .pll_type("General"), 89 | .pll_subtype("General") 90 | ) altera_pll_i ( 91 | .rst (rst), 92 | .outclk ({outclk_4, outclk_3, outclk_2, outclk_1, outclk_0}), 93 | .locked (locked), 94 | .fboutclk ( ), 95 | .fbclk (1'b0), 96 | .refclk (refclk) 97 | ); 98 | endmodule 99 | 100 | -------------------------------------------------------------------------------- /src/fpga/core/mf_pllbase_sim.f: -------------------------------------------------------------------------------- 1 | mf_pllbase_sim/mf_pllbase.vo 2 | -------------------------------------------------------------------------------- /src/fpga/core/mf_pllbase_sim/aldec/rivierapro_setup.tcl: -------------------------------------------------------------------------------- 1 | 2 | # (C) 2001-2022 Altera Corporation. All rights reserved. 3 | # Your use of Altera Corporation's design tools, logic functions and 4 | # other software and tools, and its AMPP partner logic functions, and 5 | # any output files any of the foregoing (including device programming 6 | # or simulation files), and any associated documentation or information 7 | # are expressly subject to the terms and conditions of the Altera 8 | # Program License Subscription Agreement, Altera MegaCore Function 9 | # License Agreement, or other applicable license agreement, including, 10 | # without limitation, that your use is for the sole purpose of 11 | # programming logic devices manufactured by Altera and sold by Altera 12 | # or its authorized distributors. Please refer to the applicable 13 | # agreement for further details. 14 | 15 | # ACDS 21.1 850 win32 2022.08.17.10:52:31 16 | # ---------------------------------------- 17 | # Auto-generated simulation script rivierapro_setup.tcl 18 | # ---------------------------------------- 19 | # This script provides commands to simulate the following IP detected in 20 | # your Quartus project: 21 | # mf_pllbase 22 | # 23 | # Altera recommends that you source this Quartus-generated IP simulation 24 | # script from your own customized top-level script, and avoid editing this 25 | # generated script. 26 | # 27 | # To write a top-level script that compiles Altera simulation libraries and 28 | # the Quartus-generated IP in your project, along with your design and 29 | # testbench files, copy the text from the TOP-LEVEL TEMPLATE section below 30 | # into a new file, e.g. named "aldec.do", and modify the text as directed. 31 | # 32 | # ---------------------------------------- 33 | # # TOP-LEVEL TEMPLATE - BEGIN 34 | # # 35 | # # QSYS_SIMDIR is used in the Quartus-generated IP simulation script to 36 | # # construct paths to the files required to simulate the IP in your Quartus 37 | # # project. By default, the IP script assumes that you are launching the 38 | # # simulator from the IP script location. If launching from another 39 | # # location, set QSYS_SIMDIR to the output directory you specified when you 40 | # # generated the IP script, relative to the directory from which you launch 41 | # # the simulator. 42 | # # 43 | # set QSYS_SIMDIR