From bc616fd3bf217268aaab55de395786cdf7c6a753 Mon Sep 17 00:00:00 2001 From: Fischer Moseley <42497969+fischermoseley@users.noreply.github.com> Date: Thu, 28 Dec 2023 14:22:29 -0800 Subject: [PATCH] inital source, imported from splat --- .DS_Store | Bin 0 -> 6148 bytes .github/workflows/build_docs.yml | 4 +- .github/workflows/build_examples.yml | 25 - .github/workflows/functional_simulation.yml | 29 - ...{formal_verification.yml => run_tests.yml} | 22 +- .gitignore | 35 +- Makefile | 121 +--- README.md | 4 +- examples/icestick/io_core/manta.yaml | 16 - examples/icestick/io_core/run_io_core.py | 45 -- examples/icestick/io_core/top_level.pcf | 67 -- examples/icestick/io_core/top_level.sv | 32 - .../nexys_a7/block_mem_uart/api_example.py | 18 - examples/nexys_a7/block_mem_uart/manta.yaml | 11 - .../nexys_a7/block_mem_uart/src/top_level.sv | 24 - .../nexys_a7/block_mem_uart/xdc/top_level.xdc | 254 -------- examples/nexys_a7/build.tcl | 37 -- .../nexys_a7/io_core_ether/api_example.py | 40 -- examples/nexys_a7/io_core_ether/manta.yaml | 25 - .../nexys_a7/io_core_ether/src/divider.sv | 193 ------ .../nexys_a7/io_core_ether/src/top_level.sv | 61 -- .../nexys_a7/io_core_ether/xdc/top_level.xdc | 254 -------- examples/nexys_a7/io_core_uart/api_example.py | 40 -- examples/nexys_a7/io_core_uart/manta.yaml | 26 - .../nexys_a7/io_core_uart/src/top_level.sv | 48 -- .../nexys_a7/io_core_uart/xdc/top_level.xdc | 254 -------- .../nexys_a7/large_io_core_uart/manta.yaml | 23 - .../large_io_core_uart/src/top_level.sv | 32 - examples/nexys_a7/large_io_core_uart/test.py | 26 - .../large_io_core_uart/xdc/top_level.xdc | 254 -------- .../nexys_a7/logic_analyzer_uart/manta.yaml | 20 - .../logic_analyzer_uart/sim/playback.v | 58 -- .../logic_analyzer_uart/sim/playback_tb.sv | 38 -- .../logic_analyzer_uart/src/top_level.sv | 28 - .../logic_analyzer_uart/xdc/top_level.xdc | 254 -------- .../nexys_a7/ps2_logic_analyzer/manta.yaml | 18 - .../ps2_logic_analyzer/sim/playback.v | 52 -- .../ps2_logic_analyzer/sim/playback_tb.sv | 80 --- .../ps2_logic_analyzer/src/top_level.sv | 25 - .../ps2_logic_analyzer/xdc/top_level.xdc | 254 -------- .../video_sprite_ether/img/buff_doge.png | Bin 69692 -> 0 bytes .../video_sprite_ether/img/no_testbenches.png | Bin 94971 -> 0 bytes .../video_sprite_ether/img/pop_cat.png | Bin 59936 -> 0 bytes .../nexys_a7/video_sprite_ether/manta.yaml | 10 - .../nexys_a7/video_sprite_ether/send_image.py | 37 -- .../nexys_a7/video_sprite_ether/src/clk_gen.v | 207 ------- .../video_sprite_ether/src/top_level.sv | 108 ---- .../nexys_a7/video_sprite_ether/src/vga.sv | 68 -- .../video_sprite_ether/xdc/top_level.xdc | 253 -------- .../video_sprite_uart/img/buff_doge.png | Bin 69692 -> 0 bytes .../video_sprite_uart/img/no_testbenches.png | Bin 94971 -> 0 bytes .../video_sprite_uart/img/pop_cat.png | Bin 59936 -> 0 bytes .../nexys_a7/video_sprite_uart/manta.yaml | 11 - .../nexys_a7/video_sprite_uart/send_image.py | 37 -- .../nexys_a7/video_sprite_uart/src/clk_gen.v | 207 ------- .../video_sprite_uart/src/top_level.sv | 96 --- .../nexys_a7/video_sprite_uart/src/vga.sv | 68 -- .../video_sprite_uart/xdc/top_level.xdc | 253 -------- pyproject.toml | 16 +- src/manta/__init__.py | 384 +----------- src/manta/__main__.py | 4 +- src/manta/block_mem_core/__init__.py | 77 --- src/manta/block_mem_core/block_memory.v | 114 ---- .../block_mem_core/block_memory_inst_tmpl.v | 21 - src/manta/block_mem_core/dual_port_bram.v | 60 -- src/manta/cli.py | 126 ++++ src/manta/ether_iface/__init__.py | 208 ------- src/manta/ether_iface/aggregate.v | 46 -- src/manta/ether_iface/bitorder.v | 114 ---- src/manta/ether_iface/cksum.v | 80 --- src/manta/ether_iface/crc32.v | 70 --- src/manta/ether_iface/ether.v | 77 --- src/manta/ether_iface/ethernet_rx.v | 41 -- src/manta/ether_iface/ethernet_rx_inst_tmpl.v | 13 - src/manta/ether_iface/ethernet_tx.v | 40 -- src/manta/ether_iface/ethernet_tx_inst_tmpl.v | 13 - src/manta/ether_iface/firewall.v | 80 --- src/manta/ether_iface/mac_rx.v | 106 ---- src/manta/ether_iface/mac_tx.v | 242 -------- src/manta/io_core.py | 260 ++++++++ src/manta/io_core/__init__.py | 213 ------- src/manta/io_core/io_core_def_tmpl.v | 77 --- src/manta/io_core/io_core_inst_tmpl.v | 18 - src/manta/la_core/__init__.py | 463 -------------- src/manta/la_core/logic_analyzer_controller.v | 92 --- src/manta/la_core/logic_analyzer_def_tmpl.v | 142 ----- .../la_core/logic_analyzer_fsm_registers.v | 75 --- src/manta/la_core/logic_analyzer_inst_tmpl.v | 14 - .../la_core/logic_analyzer_playback_tmpl.v | 50 -- src/manta/la_core/trigger.v | 45 -- src/manta/la_core/trigger_block_def_tmpl.v | 62 -- src/manta/la_core/trigger_block_inst_tmpl.v | 11 - src/manta/logic_analyzer_core.py | 558 +++++++++++++++++ src/manta/manta.py | 170 +++++ src/manta/manta_def_tmpl.v | 34 - src/manta/memory_core.py | 205 ++++++ src/manta/uart.py | 583 ++++++++++++++++++ src/manta/uart_iface/__init__.py | 186 ------ src/manta/uart_iface/bridge_rx.v | 150 ----- src/manta/uart_iface/bridge_tx.v | 70 --- src/manta/uart_iface/uart_rx.v | 62 -- .../uart_iface/uart_rx_bridge_rx_inst_tmpl.v | 20 - src/manta/uart_iface/uart_tx.v | 61 -- .../uart_iface/uart_tx_bridge_tx_inst_tmpl.v | 23 - src/manta/utils.py | 223 +++---- .../invalid_configs/0_mangled_yaml.yaml | 26 - .../invalid_configs/1_mangled_yaml.yaml | 26 - .../invalid_configs/2_mangled_yaml.yaml | 26 - test/auto_gen/run_tests.py | 56 -- test/auto_gen/valid_configs/0_io_core.yaml | 26 - .../valid_configs/1_logic_analyzer.yaml | 19 - test/formal_verification/bridge_rx.sby | 29 - test/functional_sim/block_memory_tb.sv | 182 ------ test/functional_sim/bridge_rx_tb.sv | 185 ------ test/functional_sim/bridge_tx_tb.sv | 116 ---- test/functional_sim/ethernet_rx_tb.sv | 98 --- test/functional_sim/ethernet_tx_tb.sv | 121 ---- test/functional_sim/io_core_tb/io_core.v | 118 ---- test/functional_sim/io_core_tb/io_core_tb.sv | 277 --------- .../logic_analyzer_tb/logic_analyzer_tb.sv | 257 -------- .../logic_analyzer_tb/manta.yaml | 19 - test/functional_sim/mac_tb.sv | 86 --- test/functional_sim/uart_rx_tb.sv | 94 --- test/functional_sim/uart_tx_tb.sv | 99 --- test/test_bridge_rx_sim.py | 120 ++++ test/test_bridge_tx_sim.py | 67 ++ test/test_io_core_hw.py | 129 ++++ test/test_io_core_sim.py | 155 +++++ test/test_logic_analyzer_hw.py | 84 +++ test/test_logic_analyzer_sim.py | 140 +++++ test/test_mem_core_hw.py | 114 ++++ test/test_mem_core_sim.py | 45 ++ test/test_toolchains.py | 15 + test/test_uart_rx_sim.py | 65 ++ test/test_uart_tx_sim.py | 57 ++ test/test_verilog_gen.py | 14 + .../manta.yaml => test_verilog_gen.yaml} | 15 +- 137 files changed, 3071 insertions(+), 9810 deletions(-) create mode 100644 .DS_Store delete mode 100644 .github/workflows/build_examples.yml delete mode 100644 .github/workflows/functional_simulation.yml rename .github/workflows/{formal_verification.yml => run_tests.yml} (53%) delete mode 100644 examples/icestick/io_core/manta.yaml delete mode 100644 examples/icestick/io_core/run_io_core.py delete mode 100644 examples/icestick/io_core/top_level.pcf delete mode 100644 examples/icestick/io_core/top_level.sv delete mode 100644 examples/nexys_a7/block_mem_uart/api_example.py delete mode 100644 examples/nexys_a7/block_mem_uart/manta.yaml delete mode 100644 examples/nexys_a7/block_mem_uart/src/top_level.sv delete mode 100644 examples/nexys_a7/block_mem_uart/xdc/top_level.xdc delete mode 100644 examples/nexys_a7/build.tcl delete mode 100644 examples/nexys_a7/io_core_ether/api_example.py delete mode 100644 examples/nexys_a7/io_core_ether/manta.yaml delete mode 100644 examples/nexys_a7/io_core_ether/src/divider.sv delete mode 100644 examples/nexys_a7/io_core_ether/src/top_level.sv delete mode 100644 examples/nexys_a7/io_core_ether/xdc/top_level.xdc delete mode 100644 examples/nexys_a7/io_core_uart/api_example.py delete mode 100644 examples/nexys_a7/io_core_uart/manta.yaml delete mode 100644 examples/nexys_a7/io_core_uart/src/top_level.sv delete mode 100644 examples/nexys_a7/io_core_uart/xdc/top_level.xdc delete mode 100644 examples/nexys_a7/large_io_core_uart/manta.yaml delete mode 100644 examples/nexys_a7/large_io_core_uart/src/top_level.sv delete mode 100644 examples/nexys_a7/large_io_core_uart/test.py delete mode 100644 examples/nexys_a7/large_io_core_uart/xdc/top_level.xdc delete mode 100644 examples/nexys_a7/logic_analyzer_uart/manta.yaml delete mode 100644 examples/nexys_a7/logic_analyzer_uart/sim/playback.v delete mode 100644 examples/nexys_a7/logic_analyzer_uart/sim/playback_tb.sv delete mode 100644 examples/nexys_a7/logic_analyzer_uart/src/top_level.sv delete mode 100644 examples/nexys_a7/logic_analyzer_uart/xdc/top_level.xdc delete mode 100644 examples/nexys_a7/ps2_logic_analyzer/manta.yaml delete mode 100644 examples/nexys_a7/ps2_logic_analyzer/sim/playback.v delete mode 100644 examples/nexys_a7/ps2_logic_analyzer/sim/playback_tb.sv delete mode 100644 examples/nexys_a7/ps2_logic_analyzer/src/top_level.sv delete mode 100644 examples/nexys_a7/ps2_logic_analyzer/xdc/top_level.xdc delete mode 100644 examples/nexys_a7/video_sprite_ether/img/buff_doge.png delete mode 100644 examples/nexys_a7/video_sprite_ether/img/no_testbenches.png delete mode 100644 examples/nexys_a7/video_sprite_ether/img/pop_cat.png delete mode 100644 examples/nexys_a7/video_sprite_ether/manta.yaml delete mode 100644 examples/nexys_a7/video_sprite_ether/send_image.py delete mode 100644 examples/nexys_a7/video_sprite_ether/src/clk_gen.v delete mode 100644 examples/nexys_a7/video_sprite_ether/src/top_level.sv delete mode 100644 examples/nexys_a7/video_sprite_ether/src/vga.sv delete mode 100644 examples/nexys_a7/video_sprite_ether/xdc/top_level.xdc delete mode 100644 examples/nexys_a7/video_sprite_uart/img/buff_doge.png delete mode 100644 examples/nexys_a7/video_sprite_uart/img/no_testbenches.png delete mode 100644 examples/nexys_a7/video_sprite_uart/img/pop_cat.png delete mode 100644 examples/nexys_a7/video_sprite_uart/manta.yaml delete mode 100644 examples/nexys_a7/video_sprite_uart/send_image.py delete mode 100644 examples/nexys_a7/video_sprite_uart/src/clk_gen.v delete mode 100644 examples/nexys_a7/video_sprite_uart/src/top_level.sv delete mode 100644 examples/nexys_a7/video_sprite_uart/src/vga.sv delete mode 100644 examples/nexys_a7/video_sprite_uart/xdc/top_level.xdc delete mode 100644 src/manta/block_mem_core/__init__.py delete mode 100644 src/manta/block_mem_core/block_memory.v delete mode 100644 src/manta/block_mem_core/block_memory_inst_tmpl.v delete mode 100644 src/manta/block_mem_core/dual_port_bram.v create mode 100644 src/manta/cli.py delete mode 100644 src/manta/ether_iface/__init__.py delete mode 100644 src/manta/ether_iface/aggregate.v delete mode 100644 src/manta/ether_iface/bitorder.v delete mode 100644 src/manta/ether_iface/cksum.v delete mode 100644 src/manta/ether_iface/crc32.v delete mode 100644 src/manta/ether_iface/ether.v delete mode 100644 src/manta/ether_iface/ethernet_rx.v delete mode 100644 src/manta/ether_iface/ethernet_rx_inst_tmpl.v delete mode 100644 src/manta/ether_iface/ethernet_tx.v delete mode 100644 src/manta/ether_iface/ethernet_tx_inst_tmpl.v delete mode 100644 src/manta/ether_iface/firewall.v delete mode 100644 src/manta/ether_iface/mac_rx.v delete mode 100644 src/manta/ether_iface/mac_tx.v create mode 100644 src/manta/io_core.py delete mode 100644 src/manta/io_core/__init__.py delete mode 100644 src/manta/io_core/io_core_def_tmpl.v delete mode 100644 src/manta/io_core/io_core_inst_tmpl.v delete mode 100644 src/manta/la_core/__init__.py delete mode 100644 src/manta/la_core/logic_analyzer_controller.v delete mode 100644 src/manta/la_core/logic_analyzer_def_tmpl.v delete mode 100644 src/manta/la_core/logic_analyzer_fsm_registers.v delete mode 100644 src/manta/la_core/logic_analyzer_inst_tmpl.v delete mode 100644 src/manta/la_core/logic_analyzer_playback_tmpl.v delete mode 100644 src/manta/la_core/trigger.v delete mode 100644 src/manta/la_core/trigger_block_def_tmpl.v delete mode 100644 src/manta/la_core/trigger_block_inst_tmpl.v create mode 100644 src/manta/logic_analyzer_core.py create mode 100644 src/manta/manta.py delete mode 100644 src/manta/manta_def_tmpl.v create mode 100644 src/manta/memory_core.py create mode 100644 src/manta/uart.py delete mode 100644 src/manta/uart_iface/__init__.py delete mode 100644 src/manta/uart_iface/bridge_rx.v delete mode 100644 src/manta/uart_iface/bridge_tx.v delete mode 100644 src/manta/uart_iface/uart_rx.v delete mode 100644 src/manta/uart_iface/uart_rx_bridge_rx_inst_tmpl.v delete mode 100644 src/manta/uart_iface/uart_tx.v delete mode 100644 src/manta/uart_iface/uart_tx_bridge_tx_inst_tmpl.v delete mode 100644 test/auto_gen/invalid_configs/0_mangled_yaml.yaml delete mode 100644 test/auto_gen/invalid_configs/1_mangled_yaml.yaml delete mode 100644 test/auto_gen/invalid_configs/2_mangled_yaml.yaml delete mode 100644 test/auto_gen/run_tests.py delete mode 100644 test/auto_gen/valid_configs/0_io_core.yaml delete mode 100644 test/auto_gen/valid_configs/1_logic_analyzer.yaml delete mode 100644 test/formal_verification/bridge_rx.sby delete mode 100644 test/functional_sim/block_memory_tb.sv delete mode 100644 test/functional_sim/bridge_rx_tb.sv delete mode 100644 test/functional_sim/bridge_tx_tb.sv delete mode 100644 test/functional_sim/ethernet_rx_tb.sv delete mode 100644 test/functional_sim/ethernet_tx_tb.sv delete mode 100644 test/functional_sim/io_core_tb/io_core.v delete mode 100644 test/functional_sim/io_core_tb/io_core_tb.sv delete mode 100644 test/functional_sim/logic_analyzer_tb/logic_analyzer_tb.sv delete mode 100644 test/functional_sim/logic_analyzer_tb/manta.yaml delete mode 100644 test/functional_sim/mac_tb.sv delete mode 100644 test/functional_sim/uart_rx_tb.sv delete mode 100644 test/functional_sim/uart_tx_tb.sv create mode 100644 test/test_bridge_rx_sim.py create mode 100644 test/test_bridge_tx_sim.py create mode 100644 test/test_io_core_hw.py create mode 100644 test/test_io_core_sim.py create mode 100644 test/test_logic_analyzer_hw.py create mode 100644 test/test_logic_analyzer_sim.py create mode 100644 test/test_mem_core_hw.py create mode 100644 test/test_mem_core_sim.py create mode 100644 test/test_toolchains.py create mode 100644 test/test_uart_rx_sim.py create mode 100644 test/test_uart_tx_sim.py create mode 100644 test/test_verilog_gen.py rename test/{functional_sim/io_core_tb/manta.yaml => test_verilog_gen.yaml} (53%) diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..81229e8d26382bd3469cb3d9bb2de3f1954844ac GIT binary patch literal 6148 zcmeH~Jqp4=5QS&dB4Cr!avKle4VIuM@B*S@B?yZB9^E%TjnP_yyn&f-XEsBUS7b9H zqQmpN5$Q#wgBxXSVPuMYE)TiO>2iLYjtb*@FJ*K=2U&T%hcRwa*e@u>x3=Er<$CqZN!+^)bZi z-VT<$t|nVB+C_8t(7dzS6a&*}7cEF&S{)2jfC`Khm`C2*`M-mIoBu~GOsN1B_%j7` zvE6S6yi}g8AFpTiLso6w;GkcQ@b(jc#E#+>+ztE17GO=bASy8a2)GOkRN$uyya2`( B5q1Co literal 0 HcmV?d00001 diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index 3c0d632..ef4ca38 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -1,4 +1,4 @@ -name: build_docs +name: docs_site on: push: branches: @@ -17,5 +17,5 @@ jobs: with: key: ${{ github.ref }} path: .cache - - run: pip install mkdocs-material + - run: pip install mkdocs-material - run: mkdocs gh-deploy --force diff --git a/.github/workflows/build_examples.yml b/.github/workflows/build_examples.yml deleted file mode 100644 index a9c0598..0000000 --- a/.github/workflows/build_examples.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: build_examples -on: [push] -jobs: - examples: - runs-on: self-hosted - steps: - - uses: actions/checkout@v3 - - name: Install Manta from source - run: | - pip install setuptools --upgrade - - # omitting the following commmand causes the version of setuptools - # used by python to get confused, and it doesn't detect the name - # or version of the package from pyproject.toml - so the following - # workaround is used: - # https://github.com/pypa/setuptools/issues/3269#issuecomment-1254507377 - export DEB_PYTHON_INSTALL_LAYOUT=deb_system - - python3 -m pip install . - - - name: Build Nexys A7 examples - run: make nexys_a7 - - - name: Build Icestick examples - run: make icestick diff --git a/.github/workflows/functional_simulation.yml b/.github/workflows/functional_simulation.yml deleted file mode 100644 index 1232960..0000000 --- a/.github/workflows/functional_simulation.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: functional_simulation -on: [push] -jobs: - all: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Install Manta from Source - run: | - pip install setuptools --upgrade - - # omitting the following commmand causes the version of setuptools - # used by python to get confused, and it doesn't detect the name - # or version of the package from pyproject.toml - so the following - # workaround is used: - # https://github.com/pypa/setuptools/issues/3269#issuecomment-1254507377 - export DEB_PYTHON_INSTALL_LAYOUT=deb_system - - python3 -m pip install . - - - name: Install oss-cad-suite - run: | - wget --no-verbose https://github.com/YosysHQ/oss-cad-suite-build/releases/download/2023-02-23/oss-cad-suite-linux-x64-20230223.tgz - tar -xzf oss-cad-suite-linux-x64-20230223.tgz - echo "$(pwd)/oss-cad-suite/bin" >> $GITHUB_PATH - - - name: Run functional simulations - run: make sim \ No newline at end of file diff --git a/.github/workflows/formal_verification.yml b/.github/workflows/run_tests.yml similarity index 53% rename from .github/workflows/formal_verification.yml rename to .github/workflows/run_tests.yml index 3b548cc..331fb58 100644 --- a/.github/workflows/formal_verification.yml +++ b/.github/workflows/run_tests.yml @@ -1,4 +1,4 @@ -name: formal_verification +name: run_tests on: [push] jobs: all: @@ -8,7 +8,7 @@ jobs: - name: Install Manta from Source run: | - pip install setuptools --upgrade + python -m pip install -U pip # omitting the following commmand causes the version of setuptools # used by python to get confused, and it doesn't detect the name @@ -17,13 +17,15 @@ jobs: # https://github.com/pypa/setuptools/issues/3269#issuecomment-1254507377 export DEB_PYTHON_INSTALL_LAYOUT=deb_system - python3 -m pip install . + python -m pip install ".[dev]" - - name: Install oss-cad-suite - run: | - wget --no-verbose https://github.com/YosysHQ/oss-cad-suite-build/releases/download/2023-02-23/oss-cad-suite-linux-x64-20230223.tgz - tar -xzf oss-cad-suite-linux-x64-20230223.tgz - echo "$(pwd)/oss-cad-suite/bin" >> $GITHUB_PATH + # export tool paths + export VIVADO=/tools/Xilinx/Vivado/2023.1/bin/vivado + export YOSYS=/tools/oss-cad-suite/bin/yosys + export NEXTPNR_ICE40=/tools/oss-cad-suite/bin/nextpnr_ice40 + export ICEPACK=/tools/oss-cad-suite/bin/icepack + export ICEPROG=/tools/oss-cad-suite/bin/iceprog - - name: Run formal verification - run: make formal \ No newline at end of file + + - name: Run tests + run: make test \ No newline at end of file diff --git a/.gitignore b/.gitignore index 39837fb..8fb17e5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,33 +1,10 @@ -# Hidden files -.DS_Store -*.vscode/ - -# Python outputs venv/ -dist/ -build/ -*.egg-info +manta.egg-info/ +.pytest_cache __pycache__/ +build/ -# Vivado output products -*.Xil/ -*.log -*.jou -*.rpt -*.bit -cpu_impl_netlist.v - -# IceStorm output products -*.bin - -# iVerilog output products +*.v +*.sv *.vcd -*.out - -# Formal outputs -test/formal_verification/*_basic -test/formal_verification/*_cover - -# Manta output products -manta.v -*.mem \ No newline at end of file +*.out \ No newline at end of file diff --git a/Makefile b/Makefile index b0ecfe5..c22f0d1 100644 --- a/Makefile +++ b/Makefile @@ -1,123 +1,12 @@ -# Tool Paths -VIVADO=/tools/Xilinx/Vivado/2023.1/bin/vivado -YOSYS=/tools/oss-cad-suite/bin/yosys -NEXTPNR_ICE40=/tools/oss-cad-suite/bin/nextpnr-ice40 -ICEPACK=/tools/oss-cad-suite/bin/icepack +.PHONY: test format clean serve_docs +test: + pytest -test: auto_gen sim formal - -examples: icestick nexys_a7 +format: + black . clean: - @echo "Deleting everything matched by .gitignore" git clean -Xdf serve_docs: mkdocs serve - -# Python Operations -python_build: - python3 -m build - -pypi_upload: build - python3 -m twine upload --repository testpypi dist/* - -python_lint: - python3 -m black src/manta/__init__.py - python3 -m black src/manta/__main__.py - -# API Generation Tests -auto_gen: - python3 test/auto_gen/run_tests.py - -# Build Examples -NEXYS_A7_EXAMPLES := io_core_ether io_core_uart ps2_logic_analyzer video_sprite_ether video_sprite_uart block_mem_uart logic_analyzer_uart large_io_core_uart - -.PHONY: nexys_a7 $(NEXYS_A7_EXAMPLES) -nexys_a7: $(NEXYS_A7_EXAMPLES) - -$(NEXYS_A7_EXAMPLES): - cd examples/nexys_a7/$@; \ - python3 -m manta gen manta.yaml src/manta.v; \ - rm -rf obj; \ - mkdir -p obj; \ - $(VIVADO) -mode batch \ - -source ../build.tcl \ - -log obj/build.log \ - -jou obj/build.jou; \ - rm -rf .Xil; - -ICESTICK_EXAMPLES := io_core - -.PHONY: icestick $(ICESTICK_EXAMPLES) -icestick: $(ICESTICK_EXAMPLES) - -$(ICESTICK_EXAMPLES): - cd examples/icestick/$@; \ - python3 -m manta gen manta.yaml manta.v; \ - $(YOSYS) -p 'synth_ice40 -top top_level -json top_level.json' top_level.sv; \ - $(NEXTPNR_ICE40) --hx1k --json top_level.json --pcf top_level.pcf --asc top_level.asc; \ - $(ICEPACK) top_level.asc top_level.bin; \ - rm -f *.json; \ - rm -f *.asc; - -# Formal Verification -formal: - sby -f test/formal_verification/bridge_rx.sby - -# Functional Simulation -sim: ethernet_tx_tb ethernet_rx_tb mac_tb block_memory_tb io_core_tb logic_analyzer_tb bridge_rx_tb bridge_tx_tb block_memory_tb - -ethernet_tx_tb: - iverilog -g2012 -o sim.out -y src/manta/ether_iface test/functional_sim/ethernet_tx_tb.sv - vvp sim.out - rm sim.out - -ethernet_rx_tb: - iverilog -g2012 -o sim.out -y src/manta/ether_iface test/functional_sim/ethernet_rx_tb.sv - vvp sim.out - rm sim.out - -mac_tb: - iverilog -g2012 -o sim.out -y src/manta/ether_iface test/functional_sim/mac_tb.sv - vvp sim.out - rm sim.out - -block_memory_tb: - iverilog -g2012 -o sim.out -y src/manta/block_mem_core test/functional_sim/block_memory_tb.sv - vvp sim.out - rm sim.out - -io_core_tb: - iverilog -g2012 -o sim.out \ - test/functional_sim/io_core_tb/io_core_tb.sv \ - test/functional_sim/io_core_tb/io_core.v - vvp sim.out - rm sim.out - -logic_analyzer_tb: - cd test/functional_sim/logic_analyzer_tb; \ - python3 -m manta gen manta.yaml manta.v; \ - iverilog -g2012 -o sim.out logic_analyzer_tb.sv manta.v; \ - vvp sim.out; \ - rm sim.out - -bridge_rx_tb: - iverilog -g2012 -o sim.out -y src/manta/uart_iface test/functional_sim/bridge_rx_tb.sv - vvp sim.out - rm sim.out - -bridge_tx_tb: - iverilog -g2012 -o sim.out -y src/manta/uart_iface test/functional_sim/bridge_tx_tb.sv - vvp sim.out - rm sim.out - -uart_rx_tb: - iverilog -g2012 -o sim.out -y src/manta/uart_iface test/functional_sim/uart_rx_tb.sv - vvp sim.out - rm sim.out - -uart_tx_tb: - iverilog -g2012 -o sim.out -y src/manta/uart_iface test/functional_sim/uart_tx_tb.sv - vvp sim.out - rm sim.out diff --git a/README.md b/README.md index 3a02d2b..e49515c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,7 @@ ![](doc/assets/logo.png) ## Manta: An In-Situ Debugging Tool for Programmable Hardware -![functional_simulation](https://github.com/fischermoseley/manta/actions/workflows/functional_simulation.yml/badge.svg) -![formal_verification](https://github.com/fischermoseley/manta/actions/workflows/formal_verification.yml/badge.svg) -![build_examples](https://github.com/fischermoseley/manta/actions/workflows/build_examples.yml/badge.svg) +![run_tests](https://github.com/fischermoseley/manta/actions/workflows/run_tests.yml/badge.svg) ![build_docs](https://github.com/fischermoseley/manta/actions/workflows/build_docs.yml/badge.svg) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) diff --git a/examples/icestick/io_core/manta.yaml b/examples/icestick/io_core/manta.yaml deleted file mode 100644 index 80757ae..0000000 --- a/examples/icestick/io_core/manta.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -cores: - my_io_core: - type: io - - outputs: - LED0: 1 - LED1: 1 - LED2: 1 - LED3: 1 - LED4: 1 - -uart: - port: "auto" - baudrate: 115200 - clock_freq: 12000000 \ No newline at end of file diff --git a/examples/icestick/io_core/run_io_core.py b/examples/icestick/io_core/run_io_core.py deleted file mode 100644 index 36cc4dd..0000000 --- a/examples/icestick/io_core/run_io_core.py +++ /dev/null @@ -1,45 +0,0 @@ -from manta import Manta -from time import sleep - -m = Manta('manta.yaml') - -i = 0 -while True: - i = (i+1) % 5 - - if(i==0): - m.my_io_core.LED0.set(1) - m.my_io_core.LED1.set(0) - m.my_io_core.LED2.set(0) - m.my_io_core.LED3.set(0) - m.my_io_core.LED4.set(0) - - if(i==1): - m.my_io_core.LED0.set(0) - m.my_io_core.LED1.set(1) - m.my_io_core.LED2.set(0) - m.my_io_core.LED3.set(0) - m.my_io_core.LED4.set(0) - - if(i==2): - m.my_io_core.LED0.set(0) - m.my_io_core.LED1.set(0) - m.my_io_core.LED2.set(1) - m.my_io_core.LED3.set(0) - m.my_io_core.LED4.set(0) - - if(i==3): - m.my_io_core.LED0.set(0) - m.my_io_core.LED1.set(0) - m.my_io_core.LED2.set(0) - m.my_io_core.LED3.set(1) - m.my_io_core.LED4.set(0) - - if(i==4): - m.my_io_core.LED0.set(0) - m.my_io_core.LED1.set(0) - m.my_io_core.LED2.set(0) - m.my_io_core.LED3.set(0) - m.my_io_core.LED4.set(1) - - sleep(0.1) \ No newline at end of file diff --git a/examples/icestick/io_core/top_level.pcf b/examples/icestick/io_core/top_level.pcf deleted file mode 100644 index d042aa0..0000000 --- a/examples/icestick/io_core/top_level.pcf +++ /dev/null @@ -1,67 +0,0 @@ -# Generic iCEstick placement constraints file - -# Red LEDs -set_io LED0 99 -set_io LED1 98 -set_io LED2 97 -set_io LED3 96 - -# Green LED -set_io LED4 95 - -# IrDA port -#set_io RXD 106 -#set_io TXD 105 -#set_io SD 107 - -# Pmod connector -#set_io PIO1_02 78 # Pin 1 -#set_io PIO1_03 79 # Pin 2 -#set_io PIO1_04 80 # Pin 3 -#set_io PIO1_05 81 # Pin 4 -#set_io PIO1_06 87 # Pin 7 -#set_io PIO1_07 88 # Pin 8 -#set_io PIO1_08 90 # Pin 9 -#set_io PIO1_09 91 # Pin 10 - -# Connector J1 -#set_io PIO0_02 112 # Pin 3 -#set_io PIO0_03 113 # Pin 4 -#set_io PIO0_04 114 # Pin 5 -#set_io PIO0_05 115 # Pin 6 -#set_io PIO0_06 116 # Pin 7 -#set_io PIO0_07 117 # Pin 8 -#set_io PIO0_08 118 # Pin 9 -#set_io PIO0_09 119 # Pin 10 - -# Connector J3 -#set_io PIO2_17 62 # Pin 3 -#set_io PIO2_16 61 # Pin 4 -#set_io PIO2_15 60 # Pin 5 -#set_io PIO2_14 56 # Pin 6 -#set_io PIO2_13 48 # Pin 7 -#set_io PIO2_12 47 # Pin 8 -#set_io PIO2_11 45 # Pin 9 -#set_io PIO2_10 44 # Pin 10 - -# FTDI Port B UART -#set_io DCDn 1 -#set_io DSRn 2 -#set_io DTRn 3 -#set_io CTSn 4 -#set_io RTSn 7 -set_io rs232_tx_ttl 8 -set_io rs232_rx_ttl 9 - -# SPI -#set_io SPI_SCK 70 -#set_io SPI_SI 68 -#set_io SPI_SO 67 -#set_io SPI_SS_B 71 - -# Configuration pins -#set_io CDONE 65 -#set_io CRESET_B 66 - -# 12 MHz clock -set_io clk 21 diff --git a/examples/icestick/io_core/top_level.sv b/examples/icestick/io_core/top_level.sv deleted file mode 100644 index c8a1711..0000000 --- a/examples/icestick/io_core/top_level.sv +++ /dev/null @@ -1,32 +0,0 @@ -`default_nettype none -`timescale 1ns / 1ps - -`include "manta.v" - -module top_level ( - input wire clk, - - output logic LED0, - output logic LED1, - output logic LED2, - output logic LED3, - output logic LED4, - - input wire rs232_rx_ttl, - output logic rs232_tx_ttl - ); - - manta manta_inst ( - .clk(clk), - - .rx(rs232_rx_ttl), - .tx(rs232_tx_ttl), - - .LED0(LED0), - .LED1(LED1), - .LED2(LED2), - .LED3(LED3), - .LED4(LED4)); -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/examples/nexys_a7/block_mem_uart/api_example.py b/examples/nexys_a7/block_mem_uart/api_example.py deleted file mode 100644 index 6323e75..0000000 --- a/examples/nexys_a7/block_mem_uart/api_example.py +++ /dev/null @@ -1,18 +0,0 @@ -from manta import Manta -from time import sleep -from random import randint - -m = Manta('manta.yaml') - -for addr in range(1024): - number = randint(0,65535) - m.my_block_memory.write(addr, number) - - readback = m.my_block_memory.read(addr) - - if readback == number: - print(f"Success! Wrote and read back {hex(number)} from {hex(addr)}") - - else: - print(f"Failure! Wrote {hex(number)} to {hex(addr)}, but received {hex(readback)}") - exit() diff --git a/examples/nexys_a7/block_mem_uart/manta.yaml b/examples/nexys_a7/block_mem_uart/manta.yaml deleted file mode 100644 index 756dab7..0000000 --- a/examples/nexys_a7/block_mem_uart/manta.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -cores: - my_block_memory: - type: block_memory - width: 16 - depth: 1024 - -uart: - port: "/dev/ttyUSB1" - baudrate: 2000000 - clock_freq: 100000000 \ No newline at end of file diff --git a/examples/nexys_a7/block_mem_uart/src/top_level.sv b/examples/nexys_a7/block_mem_uart/src/top_level.sv deleted file mode 100644 index bb5cd1a..0000000 --- a/examples/nexys_a7/block_mem_uart/src/top_level.sv +++ /dev/null @@ -1,24 +0,0 @@ -`default_nettype none -`timescale 1ns / 1ps - -module top_level ( - input wire clk, - - input wire uart_txd_in, - output logic uart_rxd_out); - - manta manta_inst ( - .clk(clk), - - .rx(uart_txd_in), - .tx(uart_rxd_out), - - .my_block_memory_clk(clk), - .my_block_memory_addr(0), - .my_block_memory_din(0), - .my_block_memory_dout(), - .my_block_memory_we(0)); - -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/examples/nexys_a7/block_mem_uart/xdc/top_level.xdc b/examples/nexys_a7/block_mem_uart/xdc/top_level.xdc deleted file mode 100644 index df10467..0000000 --- a/examples/nexys_a7/block_mem_uart/xdc/top_level.xdc +++ /dev/null @@ -1,254 +0,0 @@ -## This file is a general .xdc for the Nexys4 DDR Rev. C -## To use it in a project: -## - uncomment the lines corresponding to used pins -## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project - -## This file has been modified from the default .xdc provided by Digilent for the Nexys A7 - -## Clock signal - uncomment _both_ of these lines to create clk_100mhz -set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { clk }]; #IO_L12P_T1_MRCC_35 Sch=clk -create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {clk}]; - -##Switches - -#set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { sw[0] }]; #IO_L24N_T3_RS0_15 Sch=sw[0] -#set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 } [get_ports { sw[1] }]; #IO_L3N_T0_DQS_EMCCLK_14 Sch=sw[1] -#set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { sw[2] }]; #IO_L6N_T0_D08_VREF_14 Sch=sw[2] -#set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { sw[3] }]; #IO_L13N_T2_MRCC_14 Sch=sw[3] -#set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { sw[4] }]; #IO_L12N_T1_MRCC_14 Sch=sw[4] -#set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { sw[5] }]; #IO_L7N_T1_D10_14 Sch=sw[5] -#set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { sw[6] }]; #IO_L17N_T2_A13_D29_14 Sch=sw[6] -#set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { sw[7] }]; #IO_L5N_T0_D07_14 Sch=sw[7] -#set_property -dict { PACKAGE_PIN T8 IOSTANDARD LVCMOS18 } [get_ports { sw[8] }]; #IO_L24N_T3_34 Sch=sw[8] -#set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS18 } [get_ports { sw[9] }]; #IO_25_34 Sch=sw[9] -#set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { sw[10] }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=sw[10] -#set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { sw[11] }]; #IO_L23P_T3_A03_D19_14 Sch=sw[11] -#set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { sw[12] }]; #IO_L24P_T3_35 Sch=sw[12] -#set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { sw[13] }]; #IO_L20P_T3_A08_D24_14 Sch=sw[13] -#set_property -dict { PACKAGE_PIN U11 IOSTANDARD LVCMOS33 } [get_ports { sw[14] }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=sw[14] -#set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { sw[15] }]; #IO_L21P_T3_DQS_14 Sch=sw[15] - - -## LEDs - -#set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { led[0] }]; #IO_L18P_T2_A24_15 Sch=led[0] -#set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { led[1] }]; #IO_L24P_T3_RS1_15 Sch=led[1] -#set_property -dict { PACKAGE_PIN J13 IOSTANDARD LVCMOS33 } [get_ports { led[2] }]; #IO_L17N_T2_A25_15 Sch=led[2] -#set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { led[3] }]; #IO_L8P_T1_D11_14 Sch=led[3] -#set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { led[4] }]; #IO_L7P_T1_D09_14 Sch=led[4] -#set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { led[5] }]; #IO_L18N_T2_A11_D27_14 Sch=led[5] -#set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { led[6] }]; #IO_L17P_T2_A14_D30_14 Sch=led[6] -#set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { led[7] }]; #IO_L18P_T2_A12_D28_14 Sch=led[7] -#set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { led[8] }]; #IO_L16N_T2_A15_D31_14 Sch=led[8] -#set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { led[9] }]; #IO_L14N_T2_SRCC_14 Sch=led[9] -#set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { led[10] }]; #IO_L22P_T3_A05_D21_14 Sch=led[10] -#set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { led[11] }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=led[11] -#set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { led[12] }]; #IO_L16P_T2_CSI_B_14 Sch=led[12] -#set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { led[13] }]; #IO_L22N_T3_A04_D20_14 Sch=led[13] -#set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { led[14] }]; #IO_L20N_T3_A07_D23_14 Sch=led[14] -#set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { led[15] }]; #IO_L21N_T3_DQS_A06_D22_14 Sch=led[15] - -#set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { led16_b }]; #IO_L5P_T0_D06_14 Sch=led16_b -#set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { led16_g }]; #IO_L10P_T1_D14_14 Sch=led16_g -#set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { led16_r }]; #IO_L11P_T1_SRCC_14 Sch=led16_r -#set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { led17_b }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=led17_b -#set_property -dict { PACKAGE_PIN R11 IOSTANDARD LVCMOS33 } [get_ports { led17_g }]; #IO_0_14 Sch=led17_g -#set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { led17_r }]; #IO_L11N_T1_SRCC_14 Sch=led17_r - - -##7 segment display - -#set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { ca }]; #IO_L24N_T3_A00_D16_14 Sch=ca -#set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { cb }]; #IO_25_14 Sch=cb -#set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { cc }]; #IO_25_15 Sch=cc -#set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { cd }]; #IO_L17P_T2_A26_15 Sch=cd -#set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ce }]; #IO_L13P_T2_MRCC_14 Sch=ce -#set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { cf }]; #IO_L19P_T3_A10_D26_14 Sch=cf -#set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { cg }]; #IO_L4P_T0_D04_14 Sch=cg - -#set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { dp }]; #IO_L19N_T3_A21_VREF_15 Sch=dp - -#set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { an[0] }]; #IO_L23P_T3_FOE_B_15 Sch=an[0] -#set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { an[1] }]; #IO_L23N_T3_FWE_B_15 Sch=an[1] -#set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { an[2] }]; #IO_L24P_T3_A01_D17_14 Sch=an[2] -#set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { an[3] }]; #IO_L19P_T3_A22_15 Sch=an[3] -#set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { an[4] }]; #IO_L8N_T1_D12_14 Sch=an[4] -#set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { an[5] }]; #IO_L14P_T2_SRCC_14 Sch=an[5] -#set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { an[6] }]; #IO_L23P_T3_35 Sch=an[6] -#set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { an[7] }]; #IO_L23N_T3_A02_D18_14 Sch=an[7] - - -##Buttons - -#set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { cpu_resetn }]; #IO_L3P_T0_DQS_AD1P_15 Sch=cpu_resetn - -#set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { btnc }]; #IO_L9P_T1_DQS_14 Sch=btnc -#set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { btnu }]; #IO_L4N_T0_D05_14 Sch=btnu -#set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { btnl }]; #IO_L12P_T1_MRCC_14 Sch=btnl -#set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { btnr }]; #IO_L10N_T1_D15_14 Sch=btnr -#set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { btnd }]; #IO_L9N_T1_DQS_D13_14 Sch=btnd - - -##Pmod Headers - - -##Pmod Header JA - -#set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { ja[0] }]; #IO_L20N_T3_A19_15 Sch=ja[1] -#set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { ja[1] }]; #IO_L21N_T3_DQS_A18_15 Sch=ja[2] -#set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { ja[2] }]; #IO_L21P_T3_DQS_15 Sch=ja[3] -#set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { ja[3] }]; #IO_L18N_T2_A23_15 Sch=ja[4] -#set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L16N_T2_A27_15 Sch=ja[7] -#set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L16P_T2_A28_15 Sch=ja[8] -#set_property -dict { PACKAGE_PIN F18 IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L22N_T3_A16_15 Sch=ja[9] -#set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_L22P_T3_A17_15 Sch=ja[10] - - -##Pmod Header JB - -#set_property -dict { PACKAGE_PIN D14 IOSTANDARD LVCMOS33 } [get_ports { jb[0] }]; #IO_L1P_T0_AD0P_15 Sch=jb[1] -#set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { jb[1] }]; #IO_L14N_T2_SRCC_15 Sch=jb[2] -#set_property -dict { PACKAGE_PIN G16 IOSTANDARD LVCMOS33 } [get_ports { jb[2] }]; #IO_L13N_T2_MRCC_15 Sch=jb[3] -#set_property -dict { PACKAGE_PIN H14 IOSTANDARD LVCMOS33 } [get_ports { jb[3] }]; #IO_L15P_T2_DQS_15 Sch=jb[4] -#set_property -dict { PACKAGE_PIN E16 IOSTANDARD LVCMOS33 } [get_ports { jb[4] }]; #IO_L11N_T1_SRCC_15 Sch=jb[7] -#set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { jb[5] }]; #IO_L5P_T0_AD9P_15 Sch=jb[8] -#set_property -dict { PACKAGE_PIN G13 IOSTANDARD LVCMOS33 } [get_ports { jb[6] }]; #IO_0_15 Sch=jb[9] -#set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { jb[7] }]; #IO_L13P_T2_MRCC_15 Sch=jb[10] - - -##Pmod Header JC - -#set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { jc[0] }]; #IO_L23N_T3_35 Sch=jc[1] -#set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { jc[1] }]; #IO_L19N_T3_VREF_35 Sch=jc[2] -#set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { jc[2] }]; #IO_L22N_T3_35 Sch=jc[3] -#set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { jc[3] }]; #IO_L19P_T3_35 Sch=jc[4] -#set_property -dict { PACKAGE_PIN E7 IOSTANDARD LVCMOS33 } [get_ports { jc[4] }]; #IO_L6P_T0_35 Sch=jc[7] -#set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { jc[5] }]; #IO_L22P_T3_35 Sch=jc[8] -#set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { jc[6] }]; #IO_L21P_T3_DQS_35 Sch=jc[9] -#set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { jc[7] }]; #IO_L5P_T0_AD13P_35 Sch=jc[10] - - -##Pmod Header JD - -#set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { jd[0] }]; #IO_L21N_T3_DQS_35 Sch=jd[1] -#set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports { jd[1] }]; #IO_L17P_T2_35 Sch=jd[2] -#set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { jd[2] }]; #IO_L17N_T2_35 Sch=jd[3] -#set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { jd[3] }]; #IO_L20N_T3_35 Sch=jd[4] -#set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { jd[4] }]; #IO_L15P_T2_DQS_35 Sch=jd[7] -#set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { jd[5] }]; #IO_L20P_T3_35 Sch=jd[8] -#set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { jd[6] }]; #IO_L15N_T2_DQS_35 Sch=jd[9] -#set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { jd[7] }]; #IO_L13N_T2_MRCC_35 Sch=jd[10] - - -##Pmod Header JXADC - -#set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVDS } [get_ports { xa_n[0] }]; #IO_L9N_T1_DQS_AD3N_15 Sch=xa_n[1] -#set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVDS } [get_ports { xa_p[0] }]; #IO_L9P_T1_DQS_AD3P_15 Sch=xa_p[1] -#set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVDS } [get_ports { xa_n[1] }]; #IO_L8N_T1_AD10N_15 Sch=xa_n[2] -#set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVDS } [get_ports { xa_p[1] }]; #IO_L8P_T1_AD10P_15 Sch=xa_p[2] -#set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVDS } [get_ports { xa_n[2] }]; #IO_L7N_T1_AD2N_15 Sch=xa_n[3] -#set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVDS } [get_ports { xa_p[2] }]; #IO_L7P_T1_AD2P_15 Sch=xa_p[3] -#set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVDS } [get_ports { xa_n[3] }]; #IO_L10N_T1_AD11N_15 Sch=xa_n[4] -#set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVDS } [get_ports { xa_p[3] }]; #IO_L10P_T1_AD11P_15 Sch=xa_p[4] - - -##VGA Connector - -#set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { vga_r[0] }]; #IO_L8N_T1_AD14N_35 Sch=vga_r[0] -#set_property -dict { PACKAGE_PIN B4 IOSTANDARD LVCMOS33 } [get_ports { vga_r[1] }]; #IO_L7N_T1_AD6N_35 Sch=vga_r[1] -#set_property -dict { PACKAGE_PIN C5 IOSTANDARD LVCMOS33 } [get_ports { vga_r[2] }]; #IO_L1N_T0_AD4N_35 Sch=vga_r[2] -#set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { vga_r[3] }]; #IO_L8P_T1_AD14P_35 Sch=vga_r[3] -# -#set_property -dict { PACKAGE_PIN C6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[0] }]; #IO_L1P_T0_AD4P_35 Sch=vga_g[0] -#set_property -dict { PACKAGE_PIN A5 IOSTANDARD LVCMOS33 } [get_ports { vga_g[1] }]; #IO_L3N_T0_DQS_AD5N_35 Sch=vga_g[1] -#set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[2] }]; #IO_L2N_T0_AD12N_35 Sch=vga_g[2] -#set_property -dict { PACKAGE_PIN A6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[3] }]; #IO_L3P_T0_DQS_AD5P_35 Sch=vga_g[3] -# -#set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[0] }]; #IO_L2P_T0_AD12P_35 Sch=vga_b[0] -#set_property -dict { PACKAGE_PIN C7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[1] }]; #IO_L4N_T0_35 Sch=vga_b[1] -#set_property -dict { PACKAGE_PIN D7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[2] }]; #IO_L6N_T0_VREF_35 Sch=vga_b[2] -#set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { vga_b[3] }]; #IO_L4P_T0_35 Sch=vga_b[3] - -#set_property -dict { PACKAGE_PIN B11 IOSTANDARD LVCMOS33 } [get_ports { vga_hs }]; #IO_L4P_T0_15 Sch=vga_hs -#set_property -dict { PACKAGE_PIN B12 IOSTANDARD LVCMOS33 } [get_ports { vga_vs }]; #IO_L3N_T0_DQS_AD1N_15 Sch=vga_vs - -##Micro SD Connector - -#set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { sd_reset }]; #IO_L14P_T2_SRCC_35 Sch=sd_reset -#set_property -dict { PACKAGE_PIN A1 IOSTANDARD LVCMOS33 } [get_ports { sd_cd }]; #IO_L9N_T1_DQS_AD7N_35 Sch=sd_cd -#set_property -dict { PACKAGE_PIN B1 IOSTANDARD LVCMOS33 } [get_ports { sd_sck }]; #IO_L9P_T1_DQS_AD7P_35 Sch=sd_sck -#set_property -dict { PACKAGE_PIN C1 IOSTANDARD LVCMOS33 } [get_ports { sd_cmd }]; #IO_L16N_T2_35 Sch=sd_cmd -#set_property -dict { PACKAGE_PIN C2 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[0] }]; #IO_L16P_T2_35 Sch=sd_dat[0] -#set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[1] }]; #IO_L18N_T2_35 Sch=sd_dat[1] -#set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[2] }]; #IO_L18P_T2_35 Sch=sd_dat[2] -#set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[3] }]; #IO_L14N_T2_SRCC_35 Sch=sd_dat[3] - - -##Accelerometer - -#set_property -dict { PACKAGE_PIN E15 IOSTANDARD LVCMOS33 } [get_ports { acl_miso }]; #IO_L11P_T1_SRCC_15 Sch=acl_miso -#set_property -dict { PACKAGE_PIN F14 IOSTANDARD LVCMOS33 } [get_ports { acl_mosi }]; #IO_L5N_T0_AD9N_15 Sch=acl_mosi -#set_property -dict { PACKAGE_PIN F15 IOSTANDARD LVCMOS33 } [get_ports { acl_sclk }]; #IO_L14P_T2_SRCC_15 Sch=acl_sclk -#set_property -dict { PACKAGE_PIN D15 IOSTANDARD LVCMOS33 } [get_ports { acl_csn }]; #IO_L12P_T1_MRCC_15 Sch=acl_csn -#set_property -dict { PACKAGE_PIN B13 IOSTANDARD LVCMOS33 } [get_ports { acl_int[1] }]; #IO_L2P_T0_AD8P_15 Sch=acl_int[1] -#set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 } [get_ports { acl_int[2] }]; #IO_L20P_T3_A20_15 Sch=acl_int[2] - - -##Temperature Sensor - -#set_property -dict { PACKAGE_PIN C14 IOSTANDARD LVCMOS33 } [get_ports { tmp_scl }]; #IO_L1N_T0_AD0N_15 Sch=tmp_scl -#set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS33 } [get_ports { tmp_sda }]; #IO_L12N_T1_MRCC_15 Sch=tmp_sda -#set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 } [get_ports { tmp_int }]; #IO_L6N_T0_VREF_15 Sch=tmp_int -#set_property -dict { PACKAGE_PIN B14 IOSTANDARD LVCMOS33 } [get_ports { tmp_ct }]; #IO_L2N_T0_AD8N_15 Sch=tmp_ct - -##Omnidirectional Microphone - -#set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { m_clk }]; #IO_25_35 Sch=m_clk -#set_property -dict { PACKAGE_PIN H5 IOSTANDARD LVCMOS33 } [get_ports { m_data }]; #IO_L24N_T3_35 Sch=m_data -#set_property -dict { PACKAGE_PIN F5 IOSTANDARD LVCMOS33 } [get_ports { m_lrsel }]; #IO_0_35 Sch=m_lrsel - - -##PWM Audio Amplifier - -#set_property -dict { PACKAGE_PIN A11 IOSTANDARD LVCMOS33 } [get_ports { aud_pwm }]; #IO_L4N_T0_15 Sch=aud_pwm -#set_property -dict { PACKAGE_PIN D12 IOSTANDARD LVCMOS33 } [get_ports { aud_sd }]; #IO_L6P_T0_15 Sch=aud_sd - - -##USB-RS232 Interface - -set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { uart_txd_in }]; #IO_L7P_T1_AD6P_35 Sch=uart_txd_in -set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { uart_rxd_out }]; #IO_L11N_T1_SRCC_35 Sch=uart_rxd_out -#set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { uart_cts }]; #IO_L12N_T1_MRCC_35 Sch=uart_cts -#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { uart_rts }]; #IO_L5N_T0_AD13N_35 Sch=uart_rts - -##USB HID (PS/2) - -#set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { ps2_clk }]; #IO_L13P_T2_MRCC_35 Sch=ps2_clk -#set_property -dict { PACKAGE_PIN B2 IOSTANDARD LVCMOS33 } [get_ports { ps2_data }]; #IO_L10N_T1_AD15N_35 Sch=ps2_data - - -##SMSC Ethernet PHY - -#set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { eth_mdc }]; #IO_L11P_T1_SRCC_16 Sch=eth_mdc -#set_property -dict { PACKAGE_PIN A9 IOSTANDARD LVCMOS33 } [get_ports { eth_mdio }]; #IO_L14N_T2_SRCC_16 Sch=eth_mdio -#set_property -dict { PACKAGE_PIN B3 IOSTANDARD LVCMOS33 } [get_ports { eth_rstn }]; #IO_L10P_T1_AD15P_35 Sch=eth_rstn -#set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { eth_crsdv }]; #IO_L6N_T0_VREF_16 Sch=eth_crs/udv -#set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { eth_rxerr }]; #IO_L13N_T2_MRCC_16 Sch=eth_rxerr -#set_property -dict { PACKAGE_PIN C11 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[0] }]; #IO_L13P_T2_MRCC_16 Sch=eth_rxd[0] -#set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[1] }]; #IO_L19N_T3_VREF_16 Sch=eth_rxd[1] -#set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { eth_txen }]; #IO_L11N_T1_SRCC_16 Sch=eth_txen -#set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[0] }]; #IO_L14P_T2_SRCC_16 Sch=eth_txd[0] -#set_property -dict { PACKAGE_PIN A8 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[1] }]; #IO_L12N_T1_MRCC_16 Sch=eth_txd[1] -#set_property -dict { PACKAGE_PIN D5 IOSTANDARD LVCMOS33 } [get_ports { eth_refclk }]; #IO_L11P_T1_SRCC_35 Sch=eth_refclk -#set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { eth_intn }]; #IO_L12P_T1_MRCC_16 Sch=eth_intn - - -##Quad SPI Flash - -#set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[0] }]; #IO_L1P_T0_D00_MOSI_14 Sch=qspi_dq[0] -#set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[1] }]; #IO_L1N_T0_D01_DIN_14 Sch=qspi_dq[1] -#set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[2] }]; #IO_L2P_T0_D02_14 Sch=qspi_dq[2] -#set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[3] }]; #IO_L2N_T0_D03_14 Sch=qspi_dq[3] -#set_property -dict { PACKAGE_PIN L13 IOSTANDARD LVCMOS33 } [get_ports { qspi_csn }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_csn - - diff --git a/examples/nexys_a7/build.tcl b/examples/nexys_a7/build.tcl deleted file mode 100644 index 810232a..0000000 --- a/examples/nexys_a7/build.tcl +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/tclsh - -set partNum xc7a100tcsg324-1 -set outputDir obj - -read_verilog -sv [ glob ./src/*.{sv,v,svh,vh} ] -read_xdc ./xdc/top_level.xdc - -set_part $partNum - -# synth -synth_design -top top_level -part $partNum -verbose -report_utilization -file $outputDir/post_synth_util.rpt -report_timing_summary -file $outputDir/post_synth_timing_summary.rpt -report_timing -file $outputDir/post_synth_timing.rpt - -# place -opt_design -place_design -phys_opt_design -report_utilization -file $outputDir/post_place_util.rpt - -report_clock_utilization -file $outputDir/clock_util.rpt -report_timing_summary -file $outputDir/post_place_timing_summary.rpt -report_timing -file $outputDir/post_place_timing.rpt - -# route design and generate bitstream - -route_design -directive Explore -write_bitstream -force $outputDir/out.bit - -report_route_status -file $outputDir/post_route_status.rpt -report_timing_summary -file $outputDir/post_route_timing_summary.rpt -report_timing -file $outputDir/post_route_timing.rpt -report_power -file $outputDir/post_route_power.rpt -report_drc -file $outputDir/post_imp_drc.rpt -write_verilog -force $outputDir/cpu_impl_netlist.v -mode timesim -sdf_anno true diff --git a/examples/nexys_a7/io_core_ether/api_example.py b/examples/nexys_a7/io_core_ether/api_example.py deleted file mode 100644 index d9d03b4..0000000 --- a/examples/nexys_a7/io_core_ether/api_example.py +++ /dev/null @@ -1,40 +0,0 @@ -from manta import Manta -from time import sleep - -m = Manta('manta.yaml') - -i = 0 -direction = "left" - -while True: - if direction == "left": - if i == 15: - direction = "right" - i = i - 1 - m.my_io_core.led16_r.set(1) - m.my_io_core.led16_g.set(0) - m.my_io_core.led16_b.set(1) - else: - i = i + 1 - - if direction == "right": - if i == 0: - direction = "left" - i = i + 1 - m.my_io_core.led16_r.set(0) - m.my_io_core.led16_g.set(1) - m.my_io_core.led16_b.set(0) - - else: - i = i - 1 - - m.my_io_core.led.set(2**i) - print(f"Input Ports:") - print(f" btnu: {m.my_io_core.btnu.get()}") - print(f" btnd: {m.my_io_core.btnd.get()}") - print(f" btnr: {m.my_io_core.btnr.get()}") - print(f" btnl: {m.my_io_core.btnl.get()}") - print(f" btnc: {m.my_io_core.btnc.get()}") - print(f" sw: {m.my_io_core.sw.get()}\n") - sleep(0.5) - diff --git a/examples/nexys_a7/io_core_ether/manta.yaml b/examples/nexys_a7/io_core_ether/manta.yaml deleted file mode 100644 index 4ca285e..0000000 --- a/examples/nexys_a7/io_core_ether/manta.yaml +++ /dev/null @@ -1,25 +0,0 @@ ---- -cores: - my_io_core: - type: io - - inputs: - btnu: 1 - btnd: 1 - btnl: 1 - btnr: 1 - btnc: 1 - sw: 16 - - outputs: - led: 16 - led16_b: 1 - led16_g: 1 - led16_r: 1 - led17_b: 1 - led17_g: 1 - led17_r: 1 - -ethernet: - interface: "en8" - host_mac: "12:34:56:78:90:ab" \ No newline at end of file diff --git a/examples/nexys_a7/io_core_ether/src/divider.sv b/examples/nexys_a7/io_core_ether/src/divider.sv deleted file mode 100644 index 55aada8..0000000 --- a/examples/nexys_a7/io_core_ether/src/divider.sv +++ /dev/null @@ -1,193 +0,0 @@ -`default_nettype wire - -// file: divider.sv -// -// (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved. -// -// This file contains confidential and proprietary information -// of Xilinx, Inc. and is protected under U.S. and -// international copyright and other intellectual property -// laws. -// -// DISCLAIMER -// This disclaimer is not a license and does not grant any -// rights to the materials distributed herewith. Except as -// otherwise provided in a valid license issued to you by -// Xilinx, and to the maximum extent permitted by applicable -// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND -// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES -// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING -// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- -// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and -// (2) Xilinx shall not be liable (whether in contract or tort, -// including negligence, or under any other theory of -// liability) for any loss or damage of any kind or nature -// related to, arising under or in connection with these -// materials, including for any direct, or any indirect, -// special, incidental, or consequential loss or damage -// (including loss of data, profits, goodwill, or any type of -// loss or damage suffered as a result of any action brought -// by a third party) even if such damage or loss was -// reasonably foreseeable or Xilinx had been advised of the -// possibility of the same. -// -// CRITICAL APPLICATIONS -// Xilinx products are not designed or intended to be fail- -// safe, or for use in any application requiring fail-safe -// performance, such as life-support or safety devices or -// systems, Class III medical devices, nuclear facilities, -// applications related to the deployment of airbags, or any -// other applications that could lead to death, personal -// injury, or severe property or environmental damage -// (individually and collectively, "Critical -// Applications"). Customer assumes the sole risk and -// liability of any use of Xilinx products in Critical -// Applications, subject only to applicable laws and -// regulations governing limitations on product liability. -// -// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS -// PART OF THIS FILE AT ALL TIMES. -// -//---------------------------------------------------------------------------- -// User entered comments -//---------------------------------------------------------------------------- -// popopopopopopopopopopop -// -//---------------------------------------------------------------------------- -// Output Output Phase Duty Cycle Pk-to-Pk Phase -// Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps) -//---------------------------------------------------------------------------- -// __ethclk__50.00000______0.000______50.0______151.636_____98.575 -// -//---------------------------------------------------------------------------- -// Input Clock Freq (MHz) Input Jitter (UI) -//---------------------------------------------------------------------------- -// __primary_________100.000____________0.010 - -`timescale 1ps/1ps - -module divider - - (// Clock in ports - // Clock out ports - output ethclk, - input clk - ); - // Input buffering - //------------------------------------ -wire clk_divider; -wire clk_in2_divider; - IBUF clkin1_ibufg - (.O (clk_divider), - .I (clk)); - - - - - // Clocking PRIMITIVE - //------------------------------------ - - // Instantiation of the MMCM PRIMITIVE - // * Unused inputs are tied off - // * Unused outputs are labeled unused - - wire ethclk_divider; - wire clk_out2_divider; - wire clk_out3_divider; - wire clk_out4_divider; - wire clk_out5_divider; - wire clk_out6_divider; - wire clk_out7_divider; - - wire [15:0] do_unused; - wire drdy_unused; - wire psdone_unused; - wire locked_int; - wire clkfbout_divider; - wire clkfbout_buf_divider; - wire clkfboutb_unused; - wire clkout0b_unused; - wire clkout1_unused; - wire clkout1b_unused; - wire clkout2_unused; - wire clkout2b_unused; - wire clkout3_unused; - wire clkout3b_unused; - wire clkout4_unused; - wire clkout5_unused; - wire clkout6_unused; - wire clkfbstopped_unused; - wire clkinstopped_unused; - - MMCME2_ADV - #(.BANDWIDTH ("OPTIMIZED"), - .CLKOUT4_CASCADE ("FALSE"), - .COMPENSATION ("ZHOLD"), - .STARTUP_WAIT ("FALSE"), - .DIVCLK_DIVIDE (1), - .CLKFBOUT_MULT_F (10.000), - .CLKFBOUT_PHASE (0.000), - .CLKFBOUT_USE_FINE_PS ("FALSE"), - .CLKOUT0_DIVIDE_F (20.000), - .CLKOUT0_PHASE (0.000), - .CLKOUT0_DUTY_CYCLE (0.500), - .CLKOUT0_USE_FINE_PS ("FALSE"), - .CLKIN1_PERIOD (10.000)) - mmcm_adv_inst - // Output clocks - ( - .CLKFBOUT (clkfbout_divider), - .CLKFBOUTB (clkfboutb_unused), - .CLKOUT0 (ethclk_divider), - .CLKOUT0B (clkout0b_unused), - .CLKOUT1 (clkout1_unused), - .CLKOUT1B (clkout1b_unused), - .CLKOUT2 (clkout2_unused), - .CLKOUT2B (clkout2b_unused), - .CLKOUT3 (clkout3_unused), - .CLKOUT3B (clkout3b_unused), - .CLKOUT4 (clkout4_unused), - .CLKOUT5 (clkout5_unused), - .CLKOUT6 (clkout6_unused), - // Input clock control - .CLKFBIN (clkfbout_buf_divider), - .CLKIN1 (clk_divider), - .CLKIN2 (1'b0), - // Tied to always select the primary input clock - .CLKINSEL (1'b1), - // Ports for dynamic reconfiguration - .DADDR (7'h0), - .DCLK (1'b0), - .DEN (1'b0), - .DI (16'h0), - .DO (do_unused), - .DRDY (drdy_unused), - .DWE (1'b0), - // Ports for dynamic phase shift - .PSCLK (1'b0), - .PSEN (1'b0), - .PSINCDEC (1'b0), - .PSDONE (psdone_unused), - // Other control and status signals - .LOCKED (locked_int), - .CLKINSTOPPED (clkinstopped_unused), - .CLKFBSTOPPED (clkfbstopped_unused), - .PWRDWN (1'b0), - .RST (1'b0)); - -// Clock Monitor clock assigning -//-------------------------------------- - // Output buffering - //----------------------------------- - - BUFG clkf_buf - (.O (clkfbout_buf_divider), - .I (clkfbout_divider)); - - BUFG clkout1_buf - (.O (ethclk), - .I (ethclk_divider)); - -endmodule - -`default_nettype none diff --git a/examples/nexys_a7/io_core_ether/src/top_level.sv b/examples/nexys_a7/io_core_ether/src/top_level.sv deleted file mode 100644 index 913faca..0000000 --- a/examples/nexys_a7/io_core_ether/src/top_level.sv +++ /dev/null @@ -1,61 +0,0 @@ -`default_nettype none -`timescale 1ns / 1ps - -module top_level ( - input wire clk, - - input wire eth_crsdv, - input wire [1:0] eth_rxd, - output logic [1:0] eth_txd, - output logic eth_txen, - output logic eth_refclk, - output logic eth_rstn, - - input wire btnu, - input wire btnd, - input wire btnl, - input wire btnr, - input wire btnc, - input wire [15:0] sw, - output logic [15:0] led, - output logic led16_b, - output logic led16_g, - output logic led16_r, - output logic led17_b, - output logic led17_g, - output logic led17_r); - - // 50MHz clock generation for the RMII - logic ethclk; - divider div ( - .clk(clk), - .ethclk(ethclk)); - - assign eth_rstn = 1; - assign eth_refclk = ethclk; - - manta manta_inst ( - .clk(ethclk), - - .crsdv(eth_crsdv), - .rxd(eth_rxd), - .txen(eth_txen), - .txd(eth_txd), - - .btnu(btnu), - .btnd(btnd), - .btnl(btnl), - .btnr(btnr), - .btnc(btnc), - .sw(sw), - .led(led), - .led16_b(led16_b), - .led16_g(led16_g), - .led16_r(led16_r), - .led17_b(led17_b), - .led17_g(led17_g), - .led17_r(led17_r)); - -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/examples/nexys_a7/io_core_ether/xdc/top_level.xdc b/examples/nexys_a7/io_core_ether/xdc/top_level.xdc deleted file mode 100644 index 119c5d3..0000000 --- a/examples/nexys_a7/io_core_ether/xdc/top_level.xdc +++ /dev/null @@ -1,254 +0,0 @@ -## This file is a general .xdc for the Nexys4 DDR Rev. C -## To use it in a project: -## - uncomment the lines corresponding to used pins -## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project - -## This file has been modified from the default .xdc provided by Digilent for the Nexys A7 - -## Clock signal - uncomment _both_ of these lines to create clk_100mhz -set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { clk }]; #IO_L12P_T1_MRCC_35 Sch=clk -create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {clk}]; - -##Switches - -set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { sw[0] }]; #IO_L24N_T3_RS0_15 Sch=sw[0] -set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 } [get_ports { sw[1] }]; #IO_L3N_T0_DQS_EMCCLK_14 Sch=sw[1] -set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { sw[2] }]; #IO_L6N_T0_D08_VREF_14 Sch=sw[2] -set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { sw[3] }]; #IO_L13N_T2_MRCC_14 Sch=sw[3] -set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { sw[4] }]; #IO_L12N_T1_MRCC_14 Sch=sw[4] -set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { sw[5] }]; #IO_L7N_T1_D10_14 Sch=sw[5] -set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { sw[6] }]; #IO_L17N_T2_A13_D29_14 Sch=sw[6] -set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { sw[7] }]; #IO_L5N_T0_D07_14 Sch=sw[7] -set_property -dict { PACKAGE_PIN T8 IOSTANDARD LVCMOS18 } [get_ports { sw[8] }]; #IO_L24N_T3_34 Sch=sw[8] -set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS18 } [get_ports { sw[9] }]; #IO_25_34 Sch=sw[9] -set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { sw[10] }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=sw[10] -set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { sw[11] }]; #IO_L23P_T3_A03_D19_14 Sch=sw[11] -set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { sw[12] }]; #IO_L24P_T3_35 Sch=sw[12] -set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { sw[13] }]; #IO_L20P_T3_A08_D24_14 Sch=sw[13] -set_property -dict { PACKAGE_PIN U11 IOSTANDARD LVCMOS33 } [get_ports { sw[14] }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=sw[14] -set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { sw[15] }]; #IO_L21P_T3_DQS_14 Sch=sw[15] - - -## LEDs - -set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { led[0] }]; #IO_L18P_T2_A24_15 Sch=led[0] -set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { led[1] }]; #IO_L24P_T3_RS1_15 Sch=led[1] -set_property -dict { PACKAGE_PIN J13 IOSTANDARD LVCMOS33 } [get_ports { led[2] }]; #IO_L17N_T2_A25_15 Sch=led[2] -set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { led[3] }]; #IO_L8P_T1_D11_14 Sch=led[3] -set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { led[4] }]; #IO_L7P_T1_D09_14 Sch=led[4] -set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { led[5] }]; #IO_L18N_T2_A11_D27_14 Sch=led[5] -set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { led[6] }]; #IO_L17P_T2_A14_D30_14 Sch=led[6] -set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { led[7] }]; #IO_L18P_T2_A12_D28_14 Sch=led[7] -set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { led[8] }]; #IO_L16N_T2_A15_D31_14 Sch=led[8] -set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { led[9] }]; #IO_L14N_T2_SRCC_14 Sch=led[9] -set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { led[10] }]; #IO_L22P_T3_A05_D21_14 Sch=led[10] -set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { led[11] }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=led[11] -set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { led[12] }]; #IO_L16P_T2_CSI_B_14 Sch=led[12] -set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { led[13] }]; #IO_L22N_T3_A04_D20_14 Sch=led[13] -set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { led[14] }]; #IO_L20N_T3_A07_D23_14 Sch=led[14] -set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { led[15] }]; #IO_L21N_T3_DQS_A06_D22_14 Sch=led[15] - -set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { led16_b }]; #IO_L5P_T0_D06_14 Sch=led16_b -set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { led16_g }]; #IO_L10P_T1_D14_14 Sch=led16_g -set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { led16_r }]; #IO_L11P_T1_SRCC_14 Sch=led16_r -set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { led17_b }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=led17_b -set_property -dict { PACKAGE_PIN R11 IOSTANDARD LVCMOS33 } [get_ports { led17_g }]; #IO_0_14 Sch=led17_g -set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { led17_r }]; #IO_L11N_T1_SRCC_14 Sch=led17_r - - -##7 segment display - -#set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { ca }]; #IO_L24N_T3_A00_D16_14 Sch=ca -#set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { cb }]; #IO_25_14 Sch=cb -#set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { cc }]; #IO_25_15 Sch=cc -#set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { cd }]; #IO_L17P_T2_A26_15 Sch=cd -#set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ce }]; #IO_L13P_T2_MRCC_14 Sch=ce -#set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { cf }]; #IO_L19P_T3_A10_D26_14 Sch=cf -#set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { cg }]; #IO_L4P_T0_D04_14 Sch=cg - -#set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { dp }]; #IO_L19N_T3_A21_VREF_15 Sch=dp - -#set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { an[0] }]; #IO_L23P_T3_FOE_B_15 Sch=an[0] -#set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { an[1] }]; #IO_L23N_T3_FWE_B_15 Sch=an[1] -#set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { an[2] }]; #IO_L24P_T3_A01_D17_14 Sch=an[2] -#set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { an[3] }]; #IO_L19P_T3_A22_15 Sch=an[3] -#set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { an[4] }]; #IO_L8N_T1_D12_14 Sch=an[4] -#set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { an[5] }]; #IO_L14P_T2_SRCC_14 Sch=an[5] -#set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { an[6] }]; #IO_L23P_T3_35 Sch=an[6] -#set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { an[7] }]; #IO_L23N_T3_A02_D18_14 Sch=an[7] - - -##Buttons - -#set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { cpu_resetn }]; #IO_L3P_T0_DQS_AD1P_15 Sch=cpu_resetn - -set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { btnc }]; #IO_L9P_T1_DQS_14 Sch=btnc -set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { btnu }]; #IO_L4N_T0_D05_14 Sch=btnu -set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { btnl }]; #IO_L12P_T1_MRCC_14 Sch=btnl -set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { btnr }]; #IO_L10N_T1_D15_14 Sch=btnr -set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { btnd }]; #IO_L9N_T1_DQS_D13_14 Sch=btnd - - -##Pmod Headers - - -##Pmod Header JA - -#set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { ja[0] }]; #IO_L20N_T3_A19_15 Sch=ja[1] -#set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { ja[1] }]; #IO_L21N_T3_DQS_A18_15 Sch=ja[2] -#set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { ja[2] }]; #IO_L21P_T3_DQS_15 Sch=ja[3] -#set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { ja[3] }]; #IO_L18N_T2_A23_15 Sch=ja[4] -#set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L16N_T2_A27_15 Sch=ja[7] -#set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L16P_T2_A28_15 Sch=ja[8] -#set_property -dict { PACKAGE_PIN F18 IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L22N_T3_A16_15 Sch=ja[9] -#set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_L22P_T3_A17_15 Sch=ja[10] - - -##Pmod Header JB - -#set_property -dict { PACKAGE_PIN D14 IOSTANDARD LVCMOS33 } [get_ports { jb[0] }]; #IO_L1P_T0_AD0P_15 Sch=jb[1] -#set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { jb[1] }]; #IO_L14N_T2_SRCC_15 Sch=jb[2] -#set_property -dict { PACKAGE_PIN G16 IOSTANDARD LVCMOS33 } [get_ports { jb[2] }]; #IO_L13N_T2_MRCC_15 Sch=jb[3] -#set_property -dict { PACKAGE_PIN H14 IOSTANDARD LVCMOS33 } [get_ports { jb[3] }]; #IO_L15P_T2_DQS_15 Sch=jb[4] -#set_property -dict { PACKAGE_PIN E16 IOSTANDARD LVCMOS33 } [get_ports { jb[4] }]; #IO_L11N_T1_SRCC_15 Sch=jb[7] -#set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { jb[5] }]; #IO_L5P_T0_AD9P_15 Sch=jb[8] -#set_property -dict { PACKAGE_PIN G13 IOSTANDARD LVCMOS33 } [get_ports { jb[6] }]; #IO_0_15 Sch=jb[9] -#set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { jb[7] }]; #IO_L13P_T2_MRCC_15 Sch=jb[10] - - -##Pmod Header JC - -#set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { jc[0] }]; #IO_L23N_T3_35 Sch=jc[1] -#set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { jc[1] }]; #IO_L19N_T3_VREF_35 Sch=jc[2] -#set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { jc[2] }]; #IO_L22N_T3_35 Sch=jc[3] -#set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { jc[3] }]; #IO_L19P_T3_35 Sch=jc[4] -#set_property -dict { PACKAGE_PIN E7 IOSTANDARD LVCMOS33 } [get_ports { jc[4] }]; #IO_L6P_T0_35 Sch=jc[7] -#set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { jc[5] }]; #IO_L22P_T3_35 Sch=jc[8] -#set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { jc[6] }]; #IO_L21P_T3_DQS_35 Sch=jc[9] -#set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { jc[7] }]; #IO_L5P_T0_AD13P_35 Sch=jc[10] - - -##Pmod Header JD - -#set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { jd[0] }]; #IO_L21N_T3_DQS_35 Sch=jd[1] -#set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports { jd[1] }]; #IO_L17P_T2_35 Sch=jd[2] -#set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { jd[2] }]; #IO_L17N_T2_35 Sch=jd[3] -#set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { jd[3] }]; #IO_L20N_T3_35 Sch=jd[4] -#set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { jd[4] }]; #IO_L15P_T2_DQS_35 Sch=jd[7] -#set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { jd[5] }]; #IO_L20P_T3_35 Sch=jd[8] -#set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { jd[6] }]; #IO_L15N_T2_DQS_35 Sch=jd[9] -#set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { jd[7] }]; #IO_L13N_T2_MRCC_35 Sch=jd[10] - - -##Pmod Header JXADC - -#set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVDS } [get_ports { xa_n[0] }]; #IO_L9N_T1_DQS_AD3N_15 Sch=xa_n[1] -#set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVDS } [get_ports { xa_p[0] }]; #IO_L9P_T1_DQS_AD3P_15 Sch=xa_p[1] -#set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVDS } [get_ports { xa_n[1] }]; #IO_L8N_T1_AD10N_15 Sch=xa_n[2] -#set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVDS } [get_ports { xa_p[1] }]; #IO_L8P_T1_AD10P_15 Sch=xa_p[2] -#set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVDS } [get_ports { xa_n[2] }]; #IO_L7N_T1_AD2N_15 Sch=xa_n[3] -#set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVDS } [get_ports { xa_p[2] }]; #IO_L7P_T1_AD2P_15 Sch=xa_p[3] -#set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVDS } [get_ports { xa_n[3] }]; #IO_L10N_T1_AD11N_15 Sch=xa_n[4] -#set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVDS } [get_ports { xa_p[3] }]; #IO_L10P_T1_AD11P_15 Sch=xa_p[4] - - -##VGA Connector - -#set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { vga_r[0] }]; #IO_L8N_T1_AD14N_35 Sch=vga_r[0] -#set_property -dict { PACKAGE_PIN B4 IOSTANDARD LVCMOS33 } [get_ports { vga_r[1] }]; #IO_L7N_T1_AD6N_35 Sch=vga_r[1] -#set_property -dict { PACKAGE_PIN C5 IOSTANDARD LVCMOS33 } [get_ports { vga_r[2] }]; #IO_L1N_T0_AD4N_35 Sch=vga_r[2] -#set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { vga_r[3] }]; #IO_L8P_T1_AD14P_35 Sch=vga_r[3] -# -#set_property -dict { PACKAGE_PIN C6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[0] }]; #IO_L1P_T0_AD4P_35 Sch=vga_g[0] -#set_property -dict { PACKAGE_PIN A5 IOSTANDARD LVCMOS33 } [get_ports { vga_g[1] }]; #IO_L3N_T0_DQS_AD5N_35 Sch=vga_g[1] -#set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[2] }]; #IO_L2N_T0_AD12N_35 Sch=vga_g[2] -#set_property -dict { PACKAGE_PIN A6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[3] }]; #IO_L3P_T0_DQS_AD5P_35 Sch=vga_g[3] -# -#set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[0] }]; #IO_L2P_T0_AD12P_35 Sch=vga_b[0] -#set_property -dict { PACKAGE_PIN C7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[1] }]; #IO_L4N_T0_35 Sch=vga_b[1] -#set_property -dict { PACKAGE_PIN D7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[2] }]; #IO_L6N_T0_VREF_35 Sch=vga_b[2] -#set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { vga_b[3] }]; #IO_L4P_T0_35 Sch=vga_b[3] - -#set_property -dict { PACKAGE_PIN B11 IOSTANDARD LVCMOS33 } [get_ports { vga_hs }]; #IO_L4P_T0_15 Sch=vga_hs -#set_property -dict { PACKAGE_PIN B12 IOSTANDARD LVCMOS33 } [get_ports { vga_vs }]; #IO_L3N_T0_DQS_AD1N_15 Sch=vga_vs - -##Micro SD Connector - -#set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { sd_reset }]; #IO_L14P_T2_SRCC_35 Sch=sd_reset -#set_property -dict { PACKAGE_PIN A1 IOSTANDARD LVCMOS33 } [get_ports { sd_cd }]; #IO_L9N_T1_DQS_AD7N_35 Sch=sd_cd -#set_property -dict { PACKAGE_PIN B1 IOSTANDARD LVCMOS33 } [get_ports { sd_sck }]; #IO_L9P_T1_DQS_AD7P_35 Sch=sd_sck -#set_property -dict { PACKAGE_PIN C1 IOSTANDARD LVCMOS33 } [get_ports { sd_cmd }]; #IO_L16N_T2_35 Sch=sd_cmd -#set_property -dict { PACKAGE_PIN C2 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[0] }]; #IO_L16P_T2_35 Sch=sd_dat[0] -#set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[1] }]; #IO_L18N_T2_35 Sch=sd_dat[1] -#set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[2] }]; #IO_L18P_T2_35 Sch=sd_dat[2] -#set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[3] }]; #IO_L14N_T2_SRCC_35 Sch=sd_dat[3] - - -##Accelerometer - -#set_property -dict { PACKAGE_PIN E15 IOSTANDARD LVCMOS33 } [get_ports { acl_miso }]; #IO_L11P_T1_SRCC_15 Sch=acl_miso -#set_property -dict { PACKAGE_PIN F14 IOSTANDARD LVCMOS33 } [get_ports { acl_mosi }]; #IO_L5N_T0_AD9N_15 Sch=acl_mosi -#set_property -dict { PACKAGE_PIN F15 IOSTANDARD LVCMOS33 } [get_ports { acl_sclk }]; #IO_L14P_T2_SRCC_15 Sch=acl_sclk -#set_property -dict { PACKAGE_PIN D15 IOSTANDARD LVCMOS33 } [get_ports { acl_csn }]; #IO_L12P_T1_MRCC_15 Sch=acl_csn -#set_property -dict { PACKAGE_PIN B13 IOSTANDARD LVCMOS33 } [get_ports { acl_int[1] }]; #IO_L2P_T0_AD8P_15 Sch=acl_int[1] -#set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 } [get_ports { acl_int[2] }]; #IO_L20P_T3_A20_15 Sch=acl_int[2] - - -##Temperature Sensor - -#set_property -dict { PACKAGE_PIN C14 IOSTANDARD LVCMOS33 } [get_ports { tmp_scl }]; #IO_L1N_T0_AD0N_15 Sch=tmp_scl -#set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS33 } [get_ports { tmp_sda }]; #IO_L12N_T1_MRCC_15 Sch=tmp_sda -#set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 } [get_ports { tmp_int }]; #IO_L6N_T0_VREF_15 Sch=tmp_int -#set_property -dict { PACKAGE_PIN B14 IOSTANDARD LVCMOS33 } [get_ports { tmp_ct }]; #IO_L2N_T0_AD8N_15 Sch=tmp_ct - -##Omnidirectional Microphone - -#set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { m_clk }]; #IO_25_35 Sch=m_clk -#set_property -dict { PACKAGE_PIN H5 IOSTANDARD LVCMOS33 } [get_ports { m_data }]; #IO_L24N_T3_35 Sch=m_data -#set_property -dict { PACKAGE_PIN F5 IOSTANDARD LVCMOS33 } [get_ports { m_lrsel }]; #IO_0_35 Sch=m_lrsel - - -##PWM Audio Amplifier - -#set_property -dict { PACKAGE_PIN A11 IOSTANDARD LVCMOS33 } [get_ports { aud_pwm }]; #IO_L4N_T0_15 Sch=aud_pwm -#set_property -dict { PACKAGE_PIN D12 IOSTANDARD LVCMOS33 } [get_ports { aud_sd }]; #IO_L6P_T0_15 Sch=aud_sd - - -##USB-RS232 Interface - -#set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { uart_txd_in }]; #IO_L7P_T1_AD6P_35 Sch=uart_txd_in -#set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { uart_rxd_out }]; #IO_L11N_T1_SRCC_35 Sch=uart_rxd_out -#set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { uart_cts }]; #IO_L12N_T1_MRCC_35 Sch=uart_cts -#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { uart_rts }]; #IO_L5N_T0_AD13N_35 Sch=uart_rts - -##USB HID (PS/2) - -#set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { ps2_clk }]; #IO_L13P_T2_MRCC_35 Sch=ps2_clk -#set_property -dict { PACKAGE_PIN B2 IOSTANDARD LVCMOS33 } [get_ports { ps2_data }]; #IO_L10N_T1_AD15N_35 Sch=ps2_data - - -##SMSC Ethernet PHY - -#set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { eth_mdc }]; #IO_L11P_T1_SRCC_16 Sch=eth_mdc -#set_property -dict { PACKAGE_PIN A9 IOSTANDARD LVCMOS33 } [get_ports { eth_mdio }]; #IO_L14N_T2_SRCC_16 Sch=eth_mdio -set_property -dict { PACKAGE_PIN B3 IOSTANDARD LVCMOS33 } [get_ports { eth_rstn }]; #IO_L10P_T1_AD15P_35 Sch=eth_rstn -set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { eth_crsdv }]; #IO_L6N_T0_VREF_16 Sch=eth_crs/udv -#set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { eth_rxerr }]; #IO_L13N_T2_MRCC_16 Sch=eth_rxerr -set_property -dict { PACKAGE_PIN C11 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[0] }]; #IO_L13P_T2_MRCC_16 Sch=eth_rxd[0] -set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[1] }]; #IO_L19N_T3_VREF_16 Sch=eth_rxd[1] -set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { eth_txen }]; #IO_L11N_T1_SRCC_16 Sch=eth_txen -set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[0] }]; #IO_L14P_T2_SRCC_16 Sch=eth_txd[0] -set_property -dict { PACKAGE_PIN A8 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[1] }]; #IO_L12N_T1_MRCC_16 Sch=eth_txd[1] -set_property -dict { PACKAGE_PIN D5 IOSTANDARD LVCMOS33 } [get_ports { eth_refclk }]; #IO_L11P_T1_SRCC_35 Sch=eth_refclk -#set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { eth_intn }]; #IO_L12P_T1_MRCC_16 Sch=eth_intn - - -##Quad SPI Flash - -#set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[0] }]; #IO_L1P_T0_D00_MOSI_14 Sch=qspi_dq[0] -#set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[1] }]; #IO_L1N_T0_D01_DIN_14 Sch=qspi_dq[1] -#set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[2] }]; #IO_L2P_T0_D02_14 Sch=qspi_dq[2] -#set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[3] }]; #IO_L2N_T0_D03_14 Sch=qspi_dq[3] -#set_property -dict { PACKAGE_PIN L13 IOSTANDARD LVCMOS33 } [get_ports { qspi_csn }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_csn - - diff --git a/examples/nexys_a7/io_core_uart/api_example.py b/examples/nexys_a7/io_core_uart/api_example.py deleted file mode 100644 index d9d03b4..0000000 --- a/examples/nexys_a7/io_core_uart/api_example.py +++ /dev/null @@ -1,40 +0,0 @@ -from manta import Manta -from time import sleep - -m = Manta('manta.yaml') - -i = 0 -direction = "left" - -while True: - if direction == "left": - if i == 15: - direction = "right" - i = i - 1 - m.my_io_core.led16_r.set(1) - m.my_io_core.led16_g.set(0) - m.my_io_core.led16_b.set(1) - else: - i = i + 1 - - if direction == "right": - if i == 0: - direction = "left" - i = i + 1 - m.my_io_core.led16_r.set(0) - m.my_io_core.led16_g.set(1) - m.my_io_core.led16_b.set(0) - - else: - i = i - 1 - - m.my_io_core.led.set(2**i) - print(f"Input Ports:") - print(f" btnu: {m.my_io_core.btnu.get()}") - print(f" btnd: {m.my_io_core.btnd.get()}") - print(f" btnr: {m.my_io_core.btnr.get()}") - print(f" btnl: {m.my_io_core.btnl.get()}") - print(f" btnc: {m.my_io_core.btnc.get()}") - print(f" sw: {m.my_io_core.sw.get()}\n") - sleep(0.5) - diff --git a/examples/nexys_a7/io_core_uart/manta.yaml b/examples/nexys_a7/io_core_uart/manta.yaml deleted file mode 100644 index 867efbe..0000000 --- a/examples/nexys_a7/io_core_uart/manta.yaml +++ /dev/null @@ -1,26 +0,0 @@ ---- -cores: - my_io_core: - type: io - - inputs: - btnu: 1 - btnd: 1 - btnl: 1 - btnr: 1 - btnc: 1 - sw: 16 - - outputs: - led: 16 - led16_b: 1 - led16_g: 1 - led16_r: 1 - led17_b: 1 - led17_g: 1 - led17_r: 1 - -uart: - port: "auto" - baudrate: 115200 - clock_freq: 100000000 \ No newline at end of file diff --git a/examples/nexys_a7/io_core_uart/src/top_level.sv b/examples/nexys_a7/io_core_uart/src/top_level.sv deleted file mode 100644 index d6e0f8c..0000000 --- a/examples/nexys_a7/io_core_uart/src/top_level.sv +++ /dev/null @@ -1,48 +0,0 @@ -`default_nettype none -`timescale 1ns / 1ps - -module top_level ( - input wire clk, - - input wire uart_txd_in, - output logic uart_rxd_out, - - input wire btnu, - input wire btnd, - input wire btnl, - input wire btnr, - input wire btnc, - - input wire [15:0] sw, - - output logic [15:0] led, - output logic led16_b, - output logic led16_g, - output logic led16_r, - output logic led17_b, - output logic led17_g, - output logic led17_r); - - manta manta_inst ( - .clk(clk), - - .rx(uart_txd_in), - .tx(uart_rxd_out), - - .btnu(btnu), - .btnd(btnd), - .btnl(btnl), - .btnr(btnr), - .btnc(btnc), - .sw(sw), - .led(led), - .led16_b(led16_b), - .led16_g(led16_g), - .led16_r(led16_r), - .led17_b(led17_b), - .led17_g(led17_g), - .led17_r(led17_r)); - -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/examples/nexys_a7/io_core_uart/xdc/top_level.xdc b/examples/nexys_a7/io_core_uart/xdc/top_level.xdc deleted file mode 100644 index 82c04c3..0000000 --- a/examples/nexys_a7/io_core_uart/xdc/top_level.xdc +++ /dev/null @@ -1,254 +0,0 @@ -## This file is a general .xdc for the Nexys4 DDR Rev. C -## To use it in a project: -## - uncomment the lines corresponding to used pins -## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project - -## This file has been modified from the default .xdc provided by Digilent for the Nexys A7 - -## Clock signal - uncomment _both_ of these lines to create clk_100mhz -set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { clk }]; #IO_L12P_T1_MRCC_35 Sch=clk -create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {clk}]; - -##Switches - -set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { sw[0] }]; #IO_L24N_T3_RS0_15 Sch=sw[0] -set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 } [get_ports { sw[1] }]; #IO_L3N_T0_DQS_EMCCLK_14 Sch=sw[1] -set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { sw[2] }]; #IO_L6N_T0_D08_VREF_14 Sch=sw[2] -set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { sw[3] }]; #IO_L13N_T2_MRCC_14 Sch=sw[3] -set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { sw[4] }]; #IO_L12N_T1_MRCC_14 Sch=sw[4] -set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { sw[5] }]; #IO_L7N_T1_D10_14 Sch=sw[5] -set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { sw[6] }]; #IO_L17N_T2_A13_D29_14 Sch=sw[6] -set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { sw[7] }]; #IO_L5N_T0_D07_14 Sch=sw[7] -set_property -dict { PACKAGE_PIN T8 IOSTANDARD LVCMOS18 } [get_ports { sw[8] }]; #IO_L24N_T3_34 Sch=sw[8] -set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS18 } [get_ports { sw[9] }]; #IO_25_34 Sch=sw[9] -set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { sw[10] }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=sw[10] -set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { sw[11] }]; #IO_L23P_T3_A03_D19_14 Sch=sw[11] -set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { sw[12] }]; #IO_L24P_T3_35 Sch=sw[12] -set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { sw[13] }]; #IO_L20P_T3_A08_D24_14 Sch=sw[13] -set_property -dict { PACKAGE_PIN U11 IOSTANDARD LVCMOS33 } [get_ports { sw[14] }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=sw[14] -set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { sw[15] }]; #IO_L21P_T3_DQS_14 Sch=sw[15] - - -## LEDs - -set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { led[0] }]; #IO_L18P_T2_A24_15 Sch=led[0] -set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { led[1] }]; #IO_L24P_T3_RS1_15 Sch=led[1] -set_property -dict { PACKAGE_PIN J13 IOSTANDARD LVCMOS33 } [get_ports { led[2] }]; #IO_L17N_T2_A25_15 Sch=led[2] -set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { led[3] }]; #IO_L8P_T1_D11_14 Sch=led[3] -set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { led[4] }]; #IO_L7P_T1_D09_14 Sch=led[4] -set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { led[5] }]; #IO_L18N_T2_A11_D27_14 Sch=led[5] -set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { led[6] }]; #IO_L17P_T2_A14_D30_14 Sch=led[6] -set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { led[7] }]; #IO_L18P_T2_A12_D28_14 Sch=led[7] -set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { led[8] }]; #IO_L16N_T2_A15_D31_14 Sch=led[8] -set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { led[9] }]; #IO_L14N_T2_SRCC_14 Sch=led[9] -set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { led[10] }]; #IO_L22P_T3_A05_D21_14 Sch=led[10] -set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { led[11] }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=led[11] -set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { led[12] }]; #IO_L16P_T2_CSI_B_14 Sch=led[12] -set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { led[13] }]; #IO_L22N_T3_A04_D20_14 Sch=led[13] -set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { led[14] }]; #IO_L20N_T3_A07_D23_14 Sch=led[14] -set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { led[15] }]; #IO_L21N_T3_DQS_A06_D22_14 Sch=led[15] - -set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { led16_b }]; #IO_L5P_T0_D06_14 Sch=led16_b -set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { led16_g }]; #IO_L10P_T1_D14_14 Sch=led16_g -set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { led16_r }]; #IO_L11P_T1_SRCC_14 Sch=led16_r -set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { led17_b }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=led17_b -set_property -dict { PACKAGE_PIN R11 IOSTANDARD LVCMOS33 } [get_ports { led17_g }]; #IO_0_14 Sch=led17_g -set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { led17_r }]; #IO_L11N_T1_SRCC_14 Sch=led17_r - - -##7 segment display - -#set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { ca }]; #IO_L24N_T3_A00_D16_14 Sch=ca -#set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { cb }]; #IO_25_14 Sch=cb -#set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { cc }]; #IO_25_15 Sch=cc -#set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { cd }]; #IO_L17P_T2_A26_15 Sch=cd -#set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ce }]; #IO_L13P_T2_MRCC_14 Sch=ce -#set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { cf }]; #IO_L19P_T3_A10_D26_14 Sch=cf -#set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { cg }]; #IO_L4P_T0_D04_14 Sch=cg - -#set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { dp }]; #IO_L19N_T3_A21_VREF_15 Sch=dp - -#set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { an[0] }]; #IO_L23P_T3_FOE_B_15 Sch=an[0] -#set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { an[1] }]; #IO_L23N_T3_FWE_B_15 Sch=an[1] -#set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { an[2] }]; #IO_L24P_T3_A01_D17_14 Sch=an[2] -#set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { an[3] }]; #IO_L19P_T3_A22_15 Sch=an[3] -#set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { an[4] }]; #IO_L8N_T1_D12_14 Sch=an[4] -#set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { an[5] }]; #IO_L14P_T2_SRCC_14 Sch=an[5] -#set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { an[6] }]; #IO_L23P_T3_35 Sch=an[6] -#set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { an[7] }]; #IO_L23N_T3_A02_D18_14 Sch=an[7] - - -##Buttons - -#set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { cpu_resetn }]; #IO_L3P_T0_DQS_AD1P_15 Sch=cpu_resetn - -set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { btnc }]; #IO_L9P_T1_DQS_14 Sch=btnc -set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { btnu }]; #IO_L4N_T0_D05_14 Sch=btnu -set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { btnl }]; #IO_L12P_T1_MRCC_14 Sch=btnl -set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { btnr }]; #IO_L10N_T1_D15_14 Sch=btnr -set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { btnd }]; #IO_L9N_T1_DQS_D13_14 Sch=btnd - - -##Pmod Headers - - -##Pmod Header JA - -#set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { ja[0] }]; #IO_L20N_T3_A19_15 Sch=ja[1] -#set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { ja[1] }]; #IO_L21N_T3_DQS_A18_15 Sch=ja[2] -#set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { ja[2] }]; #IO_L21P_T3_DQS_15 Sch=ja[3] -#set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { ja[3] }]; #IO_L18N_T2_A23_15 Sch=ja[4] -#set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L16N_T2_A27_15 Sch=ja[7] -#set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L16P_T2_A28_15 Sch=ja[8] -#set_property -dict { PACKAGE_PIN F18 IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L22N_T3_A16_15 Sch=ja[9] -#set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_L22P_T3_A17_15 Sch=ja[10] - - -##Pmod Header JB - -#set_property -dict { PACKAGE_PIN D14 IOSTANDARD LVCMOS33 } [get_ports { jb[0] }]; #IO_L1P_T0_AD0P_15 Sch=jb[1] -#set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { jb[1] }]; #IO_L14N_T2_SRCC_15 Sch=jb[2] -#set_property -dict { PACKAGE_PIN G16 IOSTANDARD LVCMOS33 } [get_ports { jb[2] }]; #IO_L13N_T2_MRCC_15 Sch=jb[3] -#set_property -dict { PACKAGE_PIN H14 IOSTANDARD LVCMOS33 } [get_ports { jb[3] }]; #IO_L15P_T2_DQS_15 Sch=jb[4] -#set_property -dict { PACKAGE_PIN E16 IOSTANDARD LVCMOS33 } [get_ports { jb[4] }]; #IO_L11N_T1_SRCC_15 Sch=jb[7] -#set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { jb[5] }]; #IO_L5P_T0_AD9P_15 Sch=jb[8] -#set_property -dict { PACKAGE_PIN G13 IOSTANDARD LVCMOS33 } [get_ports { jb[6] }]; #IO_0_15 Sch=jb[9] -#set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { jb[7] }]; #IO_L13P_T2_MRCC_15 Sch=jb[10] - - -##Pmod Header JC - -#set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { jc[0] }]; #IO_L23N_T3_35 Sch=jc[1] -#set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { jc[1] }]; #IO_L19N_T3_VREF_35 Sch=jc[2] -#set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { jc[2] }]; #IO_L22N_T3_35 Sch=jc[3] -#set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { jc[3] }]; #IO_L19P_T3_35 Sch=jc[4] -#set_property -dict { PACKAGE_PIN E7 IOSTANDARD LVCMOS33 } [get_ports { jc[4] }]; #IO_L6P_T0_35 Sch=jc[7] -#set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { jc[5] }]; #IO_L22P_T3_35 Sch=jc[8] -#set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { jc[6] }]; #IO_L21P_T3_DQS_35 Sch=jc[9] -#set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { jc[7] }]; #IO_L5P_T0_AD13P_35 Sch=jc[10] - - -##Pmod Header JD - -#set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { jd[0] }]; #IO_L21N_T3_DQS_35 Sch=jd[1] -#set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports { jd[1] }]; #IO_L17P_T2_35 Sch=jd[2] -#set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { jd[2] }]; #IO_L17N_T2_35 Sch=jd[3] -#set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { jd[3] }]; #IO_L20N_T3_35 Sch=jd[4] -#set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { jd[4] }]; #IO_L15P_T2_DQS_35 Sch=jd[7] -#set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { jd[5] }]; #IO_L20P_T3_35 Sch=jd[8] -#set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { jd[6] }]; #IO_L15N_T2_DQS_35 Sch=jd[9] -#set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { jd[7] }]; #IO_L13N_T2_MRCC_35 Sch=jd[10] - - -##Pmod Header JXADC - -#set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVDS } [get_ports { xa_n[0] }]; #IO_L9N_T1_DQS_AD3N_15 Sch=xa_n[1] -#set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVDS } [get_ports { xa_p[0] }]; #IO_L9P_T1_DQS_AD3P_15 Sch=xa_p[1] -#set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVDS } [get_ports { xa_n[1] }]; #IO_L8N_T1_AD10N_15 Sch=xa_n[2] -#set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVDS } [get_ports { xa_p[1] }]; #IO_L8P_T1_AD10P_15 Sch=xa_p[2] -#set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVDS } [get_ports { xa_n[2] }]; #IO_L7N_T1_AD2N_15 Sch=xa_n[3] -#set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVDS } [get_ports { xa_p[2] }]; #IO_L7P_T1_AD2P_15 Sch=xa_p[3] -#set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVDS } [get_ports { xa_n[3] }]; #IO_L10N_T1_AD11N_15 Sch=xa_n[4] -#set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVDS } [get_ports { xa_p[3] }]; #IO_L10P_T1_AD11P_15 Sch=xa_p[4] - - -##VGA Connector - -#set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { vga_r[0] }]; #IO_L8N_T1_AD14N_35 Sch=vga_r[0] -#set_property -dict { PACKAGE_PIN B4 IOSTANDARD LVCMOS33 } [get_ports { vga_r[1] }]; #IO_L7N_T1_AD6N_35 Sch=vga_r[1] -#set_property -dict { PACKAGE_PIN C5 IOSTANDARD LVCMOS33 } [get_ports { vga_r[2] }]; #IO_L1N_T0_AD4N_35 Sch=vga_r[2] -#set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { vga_r[3] }]; #IO_L8P_T1_AD14P_35 Sch=vga_r[3] -# -#set_property -dict { PACKAGE_PIN C6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[0] }]; #IO_L1P_T0_AD4P_35 Sch=vga_g[0] -#set_property -dict { PACKAGE_PIN A5 IOSTANDARD LVCMOS33 } [get_ports { vga_g[1] }]; #IO_L3N_T0_DQS_AD5N_35 Sch=vga_g[1] -#set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[2] }]; #IO_L2N_T0_AD12N_35 Sch=vga_g[2] -#set_property -dict { PACKAGE_PIN A6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[3] }]; #IO_L3P_T0_DQS_AD5P_35 Sch=vga_g[3] -# -#set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[0] }]; #IO_L2P_T0_AD12P_35 Sch=vga_b[0] -#set_property -dict { PACKAGE_PIN C7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[1] }]; #IO_L4N_T0_35 Sch=vga_b[1] -#set_property -dict { PACKAGE_PIN D7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[2] }]; #IO_L6N_T0_VREF_35 Sch=vga_b[2] -#set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { vga_b[3] }]; #IO_L4P_T0_35 Sch=vga_b[3] - -#set_property -dict { PACKAGE_PIN B11 IOSTANDARD LVCMOS33 } [get_ports { vga_hs }]; #IO_L4P_T0_15 Sch=vga_hs -#set_property -dict { PACKAGE_PIN B12 IOSTANDARD LVCMOS33 } [get_ports { vga_vs }]; #IO_L3N_T0_DQS_AD1N_15 Sch=vga_vs - -##Micro SD Connector - -#set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { sd_reset }]; #IO_L14P_T2_SRCC_35 Sch=sd_reset -#set_property -dict { PACKAGE_PIN A1 IOSTANDARD LVCMOS33 } [get_ports { sd_cd }]; #IO_L9N_T1_DQS_AD7N_35 Sch=sd_cd -#set_property -dict { PACKAGE_PIN B1 IOSTANDARD LVCMOS33 } [get_ports { sd_sck }]; #IO_L9P_T1_DQS_AD7P_35 Sch=sd_sck -#set_property -dict { PACKAGE_PIN C1 IOSTANDARD LVCMOS33 } [get_ports { sd_cmd }]; #IO_L16N_T2_35 Sch=sd_cmd -#set_property -dict { PACKAGE_PIN C2 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[0] }]; #IO_L16P_T2_35 Sch=sd_dat[0] -#set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[1] }]; #IO_L18N_T2_35 Sch=sd_dat[1] -#set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[2] }]; #IO_L18P_T2_35 Sch=sd_dat[2] -#set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[3] }]; #IO_L14N_T2_SRCC_35 Sch=sd_dat[3] - - -##Accelerometer - -#set_property -dict { PACKAGE_PIN E15 IOSTANDARD LVCMOS33 } [get_ports { acl_miso }]; #IO_L11P_T1_SRCC_15 Sch=acl_miso -#set_property -dict { PACKAGE_PIN F14 IOSTANDARD LVCMOS33 } [get_ports { acl_mosi }]; #IO_L5N_T0_AD9N_15 Sch=acl_mosi -#set_property -dict { PACKAGE_PIN F15 IOSTANDARD LVCMOS33 } [get_ports { acl_sclk }]; #IO_L14P_T2_SRCC_15 Sch=acl_sclk -#set_property -dict { PACKAGE_PIN D15 IOSTANDARD LVCMOS33 } [get_ports { acl_csn }]; #IO_L12P_T1_MRCC_15 Sch=acl_csn -#set_property -dict { PACKAGE_PIN B13 IOSTANDARD LVCMOS33 } [get_ports { acl_int[1] }]; #IO_L2P_T0_AD8P_15 Sch=acl_int[1] -#set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 } [get_ports { acl_int[2] }]; #IO_L20P_T3_A20_15 Sch=acl_int[2] - - -##Temperature Sensor - -#set_property -dict { PACKAGE_PIN C14 IOSTANDARD LVCMOS33 } [get_ports { tmp_scl }]; #IO_L1N_T0_AD0N_15 Sch=tmp_scl -#set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS33 } [get_ports { tmp_sda }]; #IO_L12N_T1_MRCC_15 Sch=tmp_sda -#set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 } [get_ports { tmp_int }]; #IO_L6N_T0_VREF_15 Sch=tmp_int -#set_property -dict { PACKAGE_PIN B14 IOSTANDARD LVCMOS33 } [get_ports { tmp_ct }]; #IO_L2N_T0_AD8N_15 Sch=tmp_ct - -##Omnidirectional Microphone - -#set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { m_clk }]; #IO_25_35 Sch=m_clk -#set_property -dict { PACKAGE_PIN H5 IOSTANDARD LVCMOS33 } [get_ports { m_data }]; #IO_L24N_T3_35 Sch=m_data -#set_property -dict { PACKAGE_PIN F5 IOSTANDARD LVCMOS33 } [get_ports { m_lrsel }]; #IO_0_35 Sch=m_lrsel - - -##PWM Audio Amplifier - -#set_property -dict { PACKAGE_PIN A11 IOSTANDARD LVCMOS33 } [get_ports { aud_pwm }]; #IO_L4N_T0_15 Sch=aud_pwm -#set_property -dict { PACKAGE_PIN D12 IOSTANDARD LVCMOS33 } [get_ports { aud_sd }]; #IO_L6P_T0_15 Sch=aud_sd - - -##USB-RS232 Interface - -set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { uart_txd_in }]; #IO_L7P_T1_AD6P_35 Sch=uart_txd_in -set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { uart_rxd_out }]; #IO_L11N_T1_SRCC_35 Sch=uart_rxd_out -#set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { uart_cts }]; #IO_L12N_T1_MRCC_35 Sch=uart_cts -#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { uart_rts }]; #IO_L5N_T0_AD13N_35 Sch=uart_rts - -##USB HID (PS/2) - -#set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { ps2_clk }]; #IO_L13P_T2_MRCC_35 Sch=ps2_clk -#set_property -dict { PACKAGE_PIN B2 IOSTANDARD LVCMOS33 } [get_ports { ps2_data }]; #IO_L10N_T1_AD15N_35 Sch=ps2_data - - -##SMSC Ethernet PHY - -#set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { eth_mdc }]; #IO_L11P_T1_SRCC_16 Sch=eth_mdc -#set_property -dict { PACKAGE_PIN A9 IOSTANDARD LVCMOS33 } [get_ports { eth_mdio }]; #IO_L14N_T2_SRCC_16 Sch=eth_mdio -#set_property -dict { PACKAGE_PIN B3 IOSTANDARD LVCMOS33 } [get_ports { eth_rstn }]; #IO_L10P_T1_AD15P_35 Sch=eth_rstn -#set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { eth_crsdv }]; #IO_L6N_T0_VREF_16 Sch=eth_crs/udv -#set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { eth_rxerr }]; #IO_L13N_T2_MRCC_16 Sch=eth_rxerr -#set_property -dict { PACKAGE_PIN C11 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[0] }]; #IO_L13P_T2_MRCC_16 Sch=eth_rxd[0] -#set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[1] }]; #IO_L19N_T3_VREF_16 Sch=eth_rxd[1] -#set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { eth_txen }]; #IO_L11N_T1_SRCC_16 Sch=eth_txen -#set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[0] }]; #IO_L14P_T2_SRCC_16 Sch=eth_txd[0] -#set_property -dict { PACKAGE_PIN A8 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[1] }]; #IO_L12N_T1_MRCC_16 Sch=eth_txd[1] -#set_property -dict { PACKAGE_PIN D5 IOSTANDARD LVCMOS33 } [get_ports { eth_refclk }]; #IO_L11P_T1_SRCC_35 Sch=eth_refclk -#set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { eth_intn }]; #IO_L12P_T1_MRCC_16 Sch=eth_intn - - -##Quad SPI Flash - -#set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[0] }]; #IO_L1P_T0_D00_MOSI_14 Sch=qspi_dq[0] -#set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[1] }]; #IO_L1N_T0_D01_DIN_14 Sch=qspi_dq[1] -#set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[2] }]; #IO_L2P_T0_D02_14 Sch=qspi_dq[2] -#set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[3] }]; #IO_L2N_T0_D03_14 Sch=qspi_dq[3] -#set_property -dict { PACKAGE_PIN L13 IOSTANDARD LVCMOS33 } [get_ports { qspi_csn }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_csn - - diff --git a/examples/nexys_a7/large_io_core_uart/manta.yaml b/examples/nexys_a7/large_io_core_uart/manta.yaml deleted file mode 100644 index 25047eb..0000000 --- a/examples/nexys_a7/large_io_core_uart/manta.yaml +++ /dev/null @@ -1,23 +0,0 @@ ---- -cores: - io_core: - type: io - - inputs: - probe0: 1 - probe1: 2 - probe2: 8 - probe3: 20 - - outputs: - probe4: - width: 1 - initial_value: 1 - probe5: 2 - probe6: 8 - probe7: 20 - -uart: - port: "auto" - baudrate: 3000000 - clock_freq: 100000000 diff --git a/examples/nexys_a7/large_io_core_uart/src/top_level.sv b/examples/nexys_a7/large_io_core_uart/src/top_level.sv deleted file mode 100644 index 1664a41..0000000 --- a/examples/nexys_a7/large_io_core_uart/src/top_level.sv +++ /dev/null @@ -1,32 +0,0 @@ -`default_nettype none -`timescale 1ns / 1ps - -module top_level ( - input wire clk, - - input wire uart_txd_in, - output logic uart_rxd_out); - - logic probe0; - logic [1:0] probe1; - logic [7:0] probe2; - logic [19:0] probe3; - - manta manta_inst ( - .clk(clk), - - .rx(uart_txd_in), - .tx(uart_rxd_out), - - .probe0(probe0), - .probe1(probe1), - .probe2(probe2), - .probe3(probe3), - .probe4(probe0), - .probe5(probe1), - .probe6(probe2), - .probe7(probe3)); - -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/examples/nexys_a7/large_io_core_uart/test.py b/examples/nexys_a7/large_io_core_uart/test.py deleted file mode 100644 index f9bee51..0000000 --- a/examples/nexys_a7/large_io_core_uart/test.py +++ /dev/null @@ -1,26 +0,0 @@ -from manta import Manta -from random import randint -m = Manta('manta.yaml') - -n_tests = 100 -for i in range(n_tests): - print(f"-> Beginning test {i} of {n_tests}") - probe4 = randint(0, 1) - m.io_core.probe4.set(probe4) - assert m.io_core.probe4.get() == probe4 - assert m.io_core.probe0.get() == probe4 - - probe5 = randint(0, 3) - m.io_core.probe5.set(probe5) - assert m.io_core.probe5.get() == probe5 - assert m.io_core.probe1.get() == probe5 - - probe6 = randint(0, 255) - m.io_core.probe6.set(probe6) - assert m.io_core.probe6.get() == probe6 - assert m.io_core.probe2.get() == probe6 - - probe7 = randint(0, (2**20)-1) - m.io_core.probe7.set(probe7) - assert m.io_core.probe7.get() == probe7 - assert m.io_core.probe3.get() == probe7 diff --git a/examples/nexys_a7/large_io_core_uart/xdc/top_level.xdc b/examples/nexys_a7/large_io_core_uart/xdc/top_level.xdc deleted file mode 100644 index c23f104..0000000 --- a/examples/nexys_a7/large_io_core_uart/xdc/top_level.xdc +++ /dev/null @@ -1,254 +0,0 @@ -## This file is a general .xdc for the Nexys4 DDR Rev. C -## To use it in a project: -## - uncomment the lines corresponding to used pins -## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project - -## This file has been modified from the default .xdc provided by Digilent for the Nexys A7 - -## Clock signal - uncomment _both_ of these lines to create clk_100mhz -set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { clk }]; #IO_L12P_T1_MRCC_35 Sch=clk -create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {clk}]; - -##Switches - -#set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { sw[0] }]; #IO_L24N_T3_RS0_15 Sch=sw[0] -#set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 } [get_ports { sw[1] }]; #IO_L3N_T0_DQS_EMCCLK_14 Sch=sw[1] -#set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { sw[2] }]; #IO_L6N_T0_D08_VREF_14 Sch=sw[2] -#set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { sw[3] }]; #IO_L13N_T2_MRCC_14 Sch=sw[3] -#set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { sw[4] }]; #IO_L12N_T1_MRCC_14 Sch=sw[4] -#set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { sw[5] }]; #IO_L7N_T1_D10_14 Sch=sw[5] -#set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { sw[6] }]; #IO_L17N_T2_A13_D29_14 Sch=sw[6] -#set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { sw[7] }]; #IO_L5N_T0_D07_14 Sch=sw[7] -#set_property -dict { PACKAGE_PIN T8 IOSTANDARD LVCMOS18 } [get_ports { sw[8] }]; #IO_L24N_T3_34 Sch=sw[8] -#set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS18 } [get_ports { sw[9] }]; #IO_25_34 Sch=sw[9] -#set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { sw[10] }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=sw[10] -#set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { sw[11] }]; #IO_L23P_T3_A03_D19_14 Sch=sw[11] -#set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { sw[12] }]; #IO_L24P_T3_35 Sch=sw[12] -#set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { sw[13] }]; #IO_L20P_T3_A08_D24_14 Sch=sw[13] -#set_property -dict { PACKAGE_PIN U11 IOSTANDARD LVCMOS33 } [get_ports { sw[14] }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=sw[14] -#set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { sw[15] }]; #IO_L21P_T3_DQS_14 Sch=sw[15] - - -## LEDs - -#set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { led[0] }]; #IO_L18P_T2_A24_15 Sch=led[0] -#set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { led[1] }]; #IO_L24P_T3_RS1_15 Sch=led[1] -#set_property -dict { PACKAGE_PIN J13 IOSTANDARD LVCMOS33 } [get_ports { led[2] }]; #IO_L17N_T2_A25_15 Sch=led[2] -#set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { led[3] }]; #IO_L8P_T1_D11_14 Sch=led[3] -#set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { led[4] }]; #IO_L7P_T1_D09_14 Sch=led[4] -#set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { led[5] }]; #IO_L18N_T2_A11_D27_14 Sch=led[5] -#set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { led[6] }]; #IO_L17P_T2_A14_D30_14 Sch=led[6] -#set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { led[7] }]; #IO_L18P_T2_A12_D28_14 Sch=led[7] -#set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { led[8] }]; #IO_L16N_T2_A15_D31_14 Sch=led[8] -#set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { led[9] }]; #IO_L14N_T2_SRCC_14 Sch=led[9] -#set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { led[10] }]; #IO_L22P_T3_A05_D21_14 Sch=led[10] -#set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { led[11] }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=led[11] -#set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { led[12] }]; #IO_L16P_T2_CSI_B_14 Sch=led[12] -#set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { led[13] }]; #IO_L22N_T3_A04_D20_14 Sch=led[13] -#set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { led[14] }]; #IO_L20N_T3_A07_D23_14 Sch=led[14] -#set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { led[15] }]; #IO_L21N_T3_DQS_A06_D22_14 Sch=led[15] -# -#set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { led16_b }]; #IO_L5P_T0_D06_14 Sch=led16_b -#set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { led16_g }]; #IO_L10P_T1_D14_14 Sch=led16_g -#set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { led16_r }]; #IO_L11P_T1_SRCC_14 Sch=led16_r -#set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { led17_b }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=led17_b -#set_property -dict { PACKAGE_PIN R11 IOSTANDARD LVCMOS33 } [get_ports { led17_g }]; #IO_0_14 Sch=led17_g -#set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { led17_r }]; #IO_L11N_T1_SRCC_14 Sch=led17_r - - -##7 segment display - -#set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { ca }]; #IO_L24N_T3_A00_D16_14 Sch=ca -#set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { cb }]; #IO_25_14 Sch=cb -#set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { cc }]; #IO_25_15 Sch=cc -#set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { cd }]; #IO_L17P_T2_A26_15 Sch=cd -#set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ce }]; #IO_L13P_T2_MRCC_14 Sch=ce -#set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { cf }]; #IO_L19P_T3_A10_D26_14 Sch=cf -#set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { cg }]; #IO_L4P_T0_D04_14 Sch=cg - -#set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { dp }]; #IO_L19N_T3_A21_VREF_15 Sch=dp - -#set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { an[0] }]; #IO_L23P_T3_FOE_B_15 Sch=an[0] -#set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { an[1] }]; #IO_L23N_T3_FWE_B_15 Sch=an[1] -#set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { an[2] }]; #IO_L24P_T3_A01_D17_14 Sch=an[2] -#set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { an[3] }]; #IO_L19P_T3_A22_15 Sch=an[3] -#set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { an[4] }]; #IO_L8N_T1_D12_14 Sch=an[4] -#set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { an[5] }]; #IO_L14P_T2_SRCC_14 Sch=an[5] -#set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { an[6] }]; #IO_L23P_T3_35 Sch=an[6] -#set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { an[7] }]; #IO_L23N_T3_A02_D18_14 Sch=an[7] - - -##Buttons - -#set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { cpu_resetn }]; #IO_L3P_T0_DQS_AD1P_15 Sch=cpu_resetn - -#set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { btnc }]; #IO_L9P_T1_DQS_14 Sch=btnc -#set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { btnu }]; #IO_L4N_T0_D05_14 Sch=btnu -#set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { btnl }]; #IO_L12P_T1_MRCC_14 Sch=btnl -#set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { btnr }]; #IO_L10N_T1_D15_14 Sch=btnr -#set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { btnd }]; #IO_L9N_T1_DQS_D13_14 Sch=btnd - - -##Pmod Headers - - -##Pmod Header JA - -#set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { ja[0] }]; #IO_L20N_T3_A19_15 Sch=ja[1] -#set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { ja[1] }]; #IO_L21N_T3_DQS_A18_15 Sch=ja[2] -#set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { ja[2] }]; #IO_L21P_T3_DQS_15 Sch=ja[3] -#set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { ja[3] }]; #IO_L18N_T2_A23_15 Sch=ja[4] -#set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L16N_T2_A27_15 Sch=ja[7] -#set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L16P_T2_A28_15 Sch=ja[8] -#set_property -dict { PACKAGE_PIN F18 IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L22N_T3_A16_15 Sch=ja[9] -#set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_L22P_T3_A17_15 Sch=ja[10] - - -##Pmod Header JB - -#set_property -dict { PACKAGE_PIN D14 IOSTANDARD LVCMOS33 } [get_ports { jb[0] }]; #IO_L1P_T0_AD0P_15 Sch=jb[1] -#set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { jb[1] }]; #IO_L14N_T2_SRCC_15 Sch=jb[2] -#set_property -dict { PACKAGE_PIN G16 IOSTANDARD LVCMOS33 } [get_ports { jb[2] }]; #IO_L13N_T2_MRCC_15 Sch=jb[3] -#set_property -dict { PACKAGE_PIN H14 IOSTANDARD LVCMOS33 } [get_ports { jb[3] }]; #IO_L15P_T2_DQS_15 Sch=jb[4] -#set_property -dict { PACKAGE_PIN E16 IOSTANDARD LVCMOS33 } [get_ports { jb[4] }]; #IO_L11N_T1_SRCC_15 Sch=jb[7] -#set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { jb[5] }]; #IO_L5P_T0_AD9P_15 Sch=jb[8] -#set_property -dict { PACKAGE_PIN G13 IOSTANDARD LVCMOS33 } [get_ports { jb[6] }]; #IO_0_15 Sch=jb[9] -#set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { jb[7] }]; #IO_L13P_T2_MRCC_15 Sch=jb[10] - - -##Pmod Header JC - -#set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { jc[0] }]; #IO_L23N_T3_35 Sch=jc[1] -#set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { jc[1] }]; #IO_L19N_T3_VREF_35 Sch=jc[2] -#set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { jc[2] }]; #IO_L22N_T3_35 Sch=jc[3] -#set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { jc[3] }]; #IO_L19P_T3_35 Sch=jc[4] -#set_property -dict { PACKAGE_PIN E7 IOSTANDARD LVCMOS33 } [get_ports { jc[4] }]; #IO_L6P_T0_35 Sch=jc[7] -#set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { jc[5] }]; #IO_L22P_T3_35 Sch=jc[8] -#set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { jc[6] }]; #IO_L21P_T3_DQS_35 Sch=jc[9] -#set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { jc[7] }]; #IO_L5P_T0_AD13P_35 Sch=jc[10] - - -##Pmod Header JD - -#set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { jd[0] }]; #IO_L21N_T3_DQS_35 Sch=jd[1] -#set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports { jd[1] }]; #IO_L17P_T2_35 Sch=jd[2] -#set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { jd[2] }]; #IO_L17N_T2_35 Sch=jd[3] -#set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { jd[3] }]; #IO_L20N_T3_35 Sch=jd[4] -#set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { jd[4] }]; #IO_L15P_T2_DQS_35 Sch=jd[7] -#set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { jd[5] }]; #IO_L20P_T3_35 Sch=jd[8] -#set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { jd[6] }]; #IO_L15N_T2_DQS_35 Sch=jd[9] -#set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { jd[7] }]; #IO_L13N_T2_MRCC_35 Sch=jd[10] - - -##Pmod Header JXADC - -#set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVDS } [get_ports { xa_n[0] }]; #IO_L9N_T1_DQS_AD3N_15 Sch=xa_n[1] -#set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVDS } [get_ports { xa_p[0] }]; #IO_L9P_T1_DQS_AD3P_15 Sch=xa_p[1] -#set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVDS } [get_ports { xa_n[1] }]; #IO_L8N_T1_AD10N_15 Sch=xa_n[2] -#set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVDS } [get_ports { xa_p[1] }]; #IO_L8P_T1_AD10P_15 Sch=xa_p[2] -#set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVDS } [get_ports { xa_n[2] }]; #IO_L7N_T1_AD2N_15 Sch=xa_n[3] -#set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVDS } [get_ports { xa_p[2] }]; #IO_L7P_T1_AD2P_15 Sch=xa_p[3] -#set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVDS } [get_ports { xa_n[3] }]; #IO_L10N_T1_AD11N_15 Sch=xa_n[4] -#set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVDS } [get_ports { xa_p[3] }]; #IO_L10P_T1_AD11P_15 Sch=xa_p[4] - - -##VGA Connector - -#set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { vga_r[0] }]; #IO_L8N_T1_AD14N_35 Sch=vga_r[0] -#set_property -dict { PACKAGE_PIN B4 IOSTANDARD LVCMOS33 } [get_ports { vga_r[1] }]; #IO_L7N_T1_AD6N_35 Sch=vga_r[1] -#set_property -dict { PACKAGE_PIN C5 IOSTANDARD LVCMOS33 } [get_ports { vga_r[2] }]; #IO_L1N_T0_AD4N_35 Sch=vga_r[2] -#set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { vga_r[3] }]; #IO_L8P_T1_AD14P_35 Sch=vga_r[3] -# -#set_property -dict { PACKAGE_PIN C6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[0] }]; #IO_L1P_T0_AD4P_35 Sch=vga_g[0] -#set_property -dict { PACKAGE_PIN A5 IOSTANDARD LVCMOS33 } [get_ports { vga_g[1] }]; #IO_L3N_T0_DQS_AD5N_35 Sch=vga_g[1] -#set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[2] }]; #IO_L2N_T0_AD12N_35 Sch=vga_g[2] -#set_property -dict { PACKAGE_PIN A6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[3] }]; #IO_L3P_T0_DQS_AD5P_35 Sch=vga_g[3] -# -#set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[0] }]; #IO_L2P_T0_AD12P_35 Sch=vga_b[0] -#set_property -dict { PACKAGE_PIN C7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[1] }]; #IO_L4N_T0_35 Sch=vga_b[1] -#set_property -dict { PACKAGE_PIN D7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[2] }]; #IO_L6N_T0_VREF_35 Sch=vga_b[2] -#set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { vga_b[3] }]; #IO_L4P_T0_35 Sch=vga_b[3] - -#set_property -dict { PACKAGE_PIN B11 IOSTANDARD LVCMOS33 } [get_ports { vga_hs }]; #IO_L4P_T0_15 Sch=vga_hs -#set_property -dict { PACKAGE_PIN B12 IOSTANDARD LVCMOS33 } [get_ports { vga_vs }]; #IO_L3N_T0_DQS_AD1N_15 Sch=vga_vs - -##Micro SD Connector - -#set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { sd_reset }]; #IO_L14P_T2_SRCC_35 Sch=sd_reset -#set_property -dict { PACKAGE_PIN A1 IOSTANDARD LVCMOS33 } [get_ports { sd_cd }]; #IO_L9N_T1_DQS_AD7N_35 Sch=sd_cd -#set_property -dict { PACKAGE_PIN B1 IOSTANDARD LVCMOS33 } [get_ports { sd_sck }]; #IO_L9P_T1_DQS_AD7P_35 Sch=sd_sck -#set_property -dict { PACKAGE_PIN C1 IOSTANDARD LVCMOS33 } [get_ports { sd_cmd }]; #IO_L16N_T2_35 Sch=sd_cmd -#set_property -dict { PACKAGE_PIN C2 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[0] }]; #IO_L16P_T2_35 Sch=sd_dat[0] -#set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[1] }]; #IO_L18N_T2_35 Sch=sd_dat[1] -#set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[2] }]; #IO_L18P_T2_35 Sch=sd_dat[2] -#set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[3] }]; #IO_L14N_T2_SRCC_35 Sch=sd_dat[3] - - -##Accelerometer - -#set_property -dict { PACKAGE_PIN E15 IOSTANDARD LVCMOS33 } [get_ports { acl_miso }]; #IO_L11P_T1_SRCC_15 Sch=acl_miso -#set_property -dict { PACKAGE_PIN F14 IOSTANDARD LVCMOS33 } [get_ports { acl_mosi }]; #IO_L5N_T0_AD9N_15 Sch=acl_mosi -#set_property -dict { PACKAGE_PIN F15 IOSTANDARD LVCMOS33 } [get_ports { acl_sclk }]; #IO_L14P_T2_SRCC_15 Sch=acl_sclk -#set_property -dict { PACKAGE_PIN D15 IOSTANDARD LVCMOS33 } [get_ports { acl_csn }]; #IO_L12P_T1_MRCC_15 Sch=acl_csn -#set_property -dict { PACKAGE_PIN B13 IOSTANDARD LVCMOS33 } [get_ports { acl_int[1] }]; #IO_L2P_T0_AD8P_15 Sch=acl_int[1] -#set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 } [get_ports { acl_int[2] }]; #IO_L20P_T3_A20_15 Sch=acl_int[2] - - -##Temperature Sensor - -#set_property -dict { PACKAGE_PIN C14 IOSTANDARD LVCMOS33 } [get_ports { tmp_scl }]; #IO_L1N_T0_AD0N_15 Sch=tmp_scl -#set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS33 } [get_ports { tmp_sda }]; #IO_L12N_T1_MRCC_15 Sch=tmp_sda -#set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 } [get_ports { tmp_int }]; #IO_L6N_T0_VREF_15 Sch=tmp_int -#set_property -dict { PACKAGE_PIN B14 IOSTANDARD LVCMOS33 } [get_ports { tmp_ct }]; #IO_L2N_T0_AD8N_15 Sch=tmp_ct - -##Omnidirectional Microphone - -#set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { m_clk }]; #IO_25_35 Sch=m_clk -#set_property -dict { PACKAGE_PIN H5 IOSTANDARD LVCMOS33 } [get_ports { m_data }]; #IO_L24N_T3_35 Sch=m_data -#set_property -dict { PACKAGE_PIN F5 IOSTANDARD LVCMOS33 } [get_ports { m_lrsel }]; #IO_0_35 Sch=m_lrsel - - -##PWM Audio Amplifier - -#set_property -dict { PACKAGE_PIN A11 IOSTANDARD LVCMOS33 } [get_ports { aud_pwm }]; #IO_L4N_T0_15 Sch=aud_pwm -#set_property -dict { PACKAGE_PIN D12 IOSTANDARD LVCMOS33 } [get_ports { aud_sd }]; #IO_L6P_T0_15 Sch=aud_sd - - -##USB-RS232 Interface - -set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { uart_txd_in }]; #IO_L7P_T1_AD6P_35 Sch=uart_txd_in -set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { uart_rxd_out }]; #IO_L11N_T1_SRCC_35 Sch=uart_rxd_out -#set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { uart_cts }]; #IO_L12N_T1_MRCC_35 Sch=uart_cts -#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { uart_rts }]; #IO_L5N_T0_AD13N_35 Sch=uart_rts - -##USB HID (PS/2) - -#set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { ps2_clk }]; #IO_L13P_T2_MRCC_35 Sch=ps2_clk -#set_property -dict { PACKAGE_PIN B2 IOSTANDARD LVCMOS33 } [get_ports { ps2_data }]; #IO_L10N_T1_AD15N_35 Sch=ps2_data - - -##SMSC Ethernet PHY - -#set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { eth_mdc }]; #IO_L11P_T1_SRCC_16 Sch=eth_mdc -#set_property -dict { PACKAGE_PIN A9 IOSTANDARD LVCMOS33 } [get_ports { eth_mdio }]; #IO_L14N_T2_SRCC_16 Sch=eth_mdio -#set_property -dict { PACKAGE_PIN B3 IOSTANDARD LVCMOS33 } [get_ports { eth_rstn }]; #IO_L10P_T1_AD15P_35 Sch=eth_rstn -#set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { eth_crsdv }]; #IO_L6N_T0_VREF_16 Sch=eth_crs/udv -#set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { eth_rxerr }]; #IO_L13N_T2_MRCC_16 Sch=eth_rxerr -#set_property -dict { PACKAGE_PIN C11 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[0] }]; #IO_L13P_T2_MRCC_16 Sch=eth_rxd[0] -#set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[1] }]; #IO_L19N_T3_VREF_16 Sch=eth_rxd[1] -#set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { eth_txen }]; #IO_L11N_T1_SRCC_16 Sch=eth_txen -#set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[0] }]; #IO_L14P_T2_SRCC_16 Sch=eth_txd[0] -#set_property -dict { PACKAGE_PIN A8 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[1] }]; #IO_L12N_T1_MRCC_16 Sch=eth_txd[1] -#set_property -dict { PACKAGE_PIN D5 IOSTANDARD LVCMOS33 } [get_ports { eth_refclk }]; #IO_L11P_T1_SRCC_35 Sch=eth_refclk -#set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { eth_intn }]; #IO_L12P_T1_MRCC_16 Sch=eth_intn - - -##Quad SPI Flash - -#set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[0] }]; #IO_L1P_T0_D00_MOSI_14 Sch=qspi_dq[0] -#set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[1] }]; #IO_L1N_T0_D01_DIN_14 Sch=qspi_dq[1] -#set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[2] }]; #IO_L2P_T0_D02_14 Sch=qspi_dq[2] -#set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[3] }]; #IO_L2N_T0_D03_14 Sch=qspi_dq[3] -#set_property -dict { PACKAGE_PIN L13 IOSTANDARD LVCMOS33 } [get_ports { qspi_csn }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_csn - - diff --git a/examples/nexys_a7/logic_analyzer_uart/manta.yaml b/examples/nexys_a7/logic_analyzer_uart/manta.yaml deleted file mode 100644 index ccb1bea..0000000 --- a/examples/nexys_a7/logic_analyzer_uart/manta.yaml +++ /dev/null @@ -1,20 +0,0 @@ ---- -cores: - my_logic_analyzer: - type: logic_analyzer - sample_depth: 1024 - - probes: - spike: 1 - jet: 2 - valentine: 3 - ed: 4 - ein: 5 - - triggers: - - ein EQ 3 - -uart: - port: "auto" - baudrate: 115200 - clock_freq: 100000000 \ No newline at end of file diff --git a/examples/nexys_a7/logic_analyzer_uart/sim/playback.v b/examples/nexys_a7/logic_analyzer_uart/sim/playback.v deleted file mode 100644 index 9aa7a47..0000000 --- a/examples/nexys_a7/logic_analyzer_uart/sim/playback.v +++ /dev/null @@ -1,58 +0,0 @@ -/* -This playback module was generated with Manta v0.0.5 on 23 Aug 2023 at 11:25:46 by fischerm - -If this breaks or if you've got dank formal verification memes, contact fischerm [at] mit.edu - -Provided under a GNU GPLv3 license. Go wild. - -Here's an example instantiation of the Manta module you configured, feel free to copy-paste -this into your source! - -my_logic_analyzer_playback #(.MEM_FILE("capture.mem")) my_logic_analyzer_playback_inst ( - .clk(clk), - .enable(1'b1), - - .spike(spike), - .jet(jet), - .valentine(valentine), - .ed(ed), - .ein(ein)); - -*/ - - -module my_logic_analyzer_playback ( - input wire clk, - - input wire enable, - output reg done, - - output reg spike, - output reg [1:0] jet, - output reg [2:0] valentine, - output reg [3:0] ed, - output reg [4:0] ein); - - parameter MEM_FILE = ""; - localparam SAMPLE_DEPTH = 1024; - localparam TOTAL_PROBE_WIDTH = 15; - - reg [TOTAL_PROBE_WIDTH-1:0] capture [SAMPLE_DEPTH-1:0]; - reg [$clog2(SAMPLE_DEPTH)-1:0] addr; - reg [TOTAL_PROBE_WIDTH-1:0] sample; - - assign done = (addr >= SAMPLE_DEPTH); - - initial begin - $readmemb(MEM_FILE, capture, 0, SAMPLE_DEPTH-1); - addr = 0; - end - - always @(posedge clk) begin - if (enable && !done) begin - addr = addr + 1; - sample = capture[addr]; - {ein, ed, valentine, jet, spike} = sample; - end - end -endmodule \ No newline at end of file diff --git a/examples/nexys_a7/logic_analyzer_uart/sim/playback_tb.sv b/examples/nexys_a7/logic_analyzer_uart/sim/playback_tb.sv deleted file mode 100644 index d89ace9..0000000 --- a/examples/nexys_a7/logic_analyzer_uart/sim/playback_tb.sv +++ /dev/null @@ -1,38 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -module playback_tb(); - logic clk; - - always begin - #5; - clk = !clk; - end - - logic spike; - logic [1:0] jet; - logic [2:0] valentine; - logic [3:0] ed; - logic [4:0] ein; - - my_logic_analyzer_playback #(.MEM_FILE("capture.mem")) my_logic_analyzer_playback_inst ( - .clk(clk), - .enable(1'b1), - - .spike(spike), - .jet(jet), - .valentine(valentine), - .ed(ed), - .ein(ein)); - - initial begin - clk = 0; - $dumpfile("playback_tb.vcd"); - $dumpvars(0, playback_tb); - - #(450000*5); - $finish(); - end - -endmodule -`default_nettype wire \ No newline at end of file diff --git a/examples/nexys_a7/logic_analyzer_uart/src/top_level.sv b/examples/nexys_a7/logic_analyzer_uart/src/top_level.sv deleted file mode 100644 index 2127b3d..0000000 --- a/examples/nexys_a7/logic_analyzer_uart/src/top_level.sv +++ /dev/null @@ -1,28 +0,0 @@ -`default_nettype none -`timescale 1ns / 1ps - -module top_level ( - input wire clk, - - input wire uart_txd_in, - output logic uart_rxd_out - ); - - logic [4:0] counter = 0; - always @(posedge clk) counter <= counter + 1; - - manta manta_inst ( - .clk(clk), - - .rx(uart_txd_in), - .tx(uart_rxd_out), - - .spike(counter[0]), - .jet(counter[1:0]), - .valentine(counter[2:0]), - .ed(counter[3:0]), - .ein(counter)); - -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/examples/nexys_a7/logic_analyzer_uart/xdc/top_level.xdc b/examples/nexys_a7/logic_analyzer_uart/xdc/top_level.xdc deleted file mode 100644 index 81c1998..0000000 --- a/examples/nexys_a7/logic_analyzer_uart/xdc/top_level.xdc +++ /dev/null @@ -1,254 +0,0 @@ -## This file is a general .xdc for the Nexys4 DDR Rev. C -## To use it in a project: -## - uncomment the lines corresponding to used pins -## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project - -## This file has been modified from the default .xdc provided by Digilent for the Nexys A7 - -## Clock signal - uncomment _both_ of these lines to create clk_100mhz -set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { clk }]; #IO_L12P_T1_MRCC_35 Sch=clk -create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {clk}]; - -##Switches - -#set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { sw[0] }]; #IO_L24N_T3_RS0_15 Sch=sw[0] -#set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 } [get_ports { sw[1] }]; #IO_L3N_T0_DQS_EMCCLK_14 Sch=sw[1] -#set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { sw[2] }]; #IO_L6N_T0_D08_VREF_14 Sch=sw[2] -#set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { sw[3] }]; #IO_L13N_T2_MRCC_14 Sch=sw[3] -#set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { sw[4] }]; #IO_L12N_T1_MRCC_14 Sch=sw[4] -#set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { sw[5] }]; #IO_L7N_T1_D10_14 Sch=sw[5] -#set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { sw[6] }]; #IO_L17N_T2_A13_D29_14 Sch=sw[6] -#set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { sw[7] }]; #IO_L5N_T0_D07_14 Sch=sw[7] -#set_property -dict { PACKAGE_PIN T8 IOSTANDARD LVCMOS18 } [get_ports { sw[8] }]; #IO_L24N_T3_34 Sch=sw[8] -#set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS18 } [get_ports { sw[9] }]; #IO_25_34 Sch=sw[9] -#set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { sw[10] }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=sw[10] -#set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { sw[11] }]; #IO_L23P_T3_A03_D19_14 Sch=sw[11] -#set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { sw[12] }]; #IO_L24P_T3_35 Sch=sw[12] -#set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { sw[13] }]; #IO_L20P_T3_A08_D24_14 Sch=sw[13] -#set_property -dict { PACKAGE_PIN U11 IOSTANDARD LVCMOS33 } [get_ports { sw[14] }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=sw[14] -#set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { sw[15] }]; #IO_L21P_T3_DQS_14 Sch=sw[15] - - -## LEDs - -#set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { led[0] }]; #IO_L18P_T2_A24_15 Sch=led[0] -#set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { led[1] }]; #IO_L24P_T3_RS1_15 Sch=led[1] -#set_property -dict { PACKAGE_PIN J13 IOSTANDARD LVCMOS33 } [get_ports { led[2] }]; #IO_L17N_T2_A25_15 Sch=led[2] -#set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { led[3] }]; #IO_L8P_T1_D11_14 Sch=led[3] -#set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { led[4] }]; #IO_L7P_T1_D09_14 Sch=led[4] -#set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { led[5] }]; #IO_L18N_T2_A11_D27_14 Sch=led[5] -#set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { led[6] }]; #IO_L17P_T2_A14_D30_14 Sch=led[6] -#set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { led[7] }]; #IO_L18P_T2_A12_D28_14 Sch=led[7] -#set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { led[8] }]; #IO_L16N_T2_A15_D31_14 Sch=led[8] -#set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { led[9] }]; #IO_L14N_T2_SRCC_14 Sch=led[9] -#set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { led[10] }]; #IO_L22P_T3_A05_D21_14 Sch=led[10] -#set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { led[11] }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=led[11] -#set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { led[12] }]; #IO_L16P_T2_CSI_B_14 Sch=led[12] -#set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { led[13] }]; #IO_L22N_T3_A04_D20_14 Sch=led[13] -#set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { led[14] }]; #IO_L20N_T3_A07_D23_14 Sch=led[14] -#set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { led[15] }]; #IO_L21N_T3_DQS_A06_D22_14 Sch=led[15] - -#set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { led16_b }]; #IO_L5P_T0_D06_14 Sch=led16_b -#set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { led16_g }]; #IO_L10P_T1_D14_14 Sch=led16_g -#set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { led16_r }]; #IO_L11P_T1_SRCC_14 Sch=led16_r -#set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { led17_b }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=led17_b -#set_property -dict { PACKAGE_PIN R11 IOSTANDARD LVCMOS33 } [get_ports { led17_g }]; #IO_0_14 Sch=led17_g -#set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { led17_r }]; #IO_L11N_T1_SRCC_14 Sch=led17_r - - -##7 segment display - -#set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { ca }]; #IO_L24N_T3_A00_D16_14 Sch=ca -#set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { cb }]; #IO_25_14 Sch=cb -#set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { cc }]; #IO_25_15 Sch=cc -#set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { cd }]; #IO_L17P_T2_A26_15 Sch=cd -#set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ce }]; #IO_L13P_T2_MRCC_14 Sch=ce -#set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { cf }]; #IO_L19P_T3_A10_D26_14 Sch=cf -#set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { cg }]; #IO_L4P_T0_D04_14 Sch=cg - -#set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { dp }]; #IO_L19N_T3_A21_VREF_15 Sch=dp - -#set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { an[0] }]; #IO_L23P_T3_FOE_B_15 Sch=an[0] -#set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { an[1] }]; #IO_L23N_T3_FWE_B_15 Sch=an[1] -#set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { an[2] }]; #IO_L24P_T3_A01_D17_14 Sch=an[2] -#set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { an[3] }]; #IO_L19P_T3_A22_15 Sch=an[3] -#set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { an[4] }]; #IO_L8N_T1_D12_14 Sch=an[4] -#set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { an[5] }]; #IO_L14P_T2_SRCC_14 Sch=an[5] -#set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { an[6] }]; #IO_L23P_T3_35 Sch=an[6] -#set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { an[7] }]; #IO_L23N_T3_A02_D18_14 Sch=an[7] - - -##Buttons - -#set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { cpu_resetn }]; #IO_L3P_T0_DQS_AD1P_15 Sch=cpu_resetn - -#set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { btnc }]; #IO_L9P_T1_DQS_14 Sch=btnc -#set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { btnu }]; #IO_L4N_T0_D05_14 Sch=btnu -#set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { btnl }]; #IO_L12P_T1_MRCC_14 Sch=btnl -#set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { btnr }]; #IO_L10N_T1_D15_14 Sch=btnr -#set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { btnd }]; #IO_L9N_T1_DQS_D13_14 Sch=btnd - - -##Pmod Headers - - -##Pmod Header JA - -#set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { ja[0] }]; #IO_L20N_T3_A19_15 Sch=ja[1] -#set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { ja[1] }]; #IO_L21N_T3_DQS_A18_15 Sch=ja[2] -#set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { ja[2] }]; #IO_L21P_T3_DQS_15 Sch=ja[3] -#set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { ja[3] }]; #IO_L18N_T2_A23_15 Sch=ja[4] -#set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L16N_T2_A27_15 Sch=ja[7] -#set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L16P_T2_A28_15 Sch=ja[8] -#set_property -dict { PACKAGE_PIN F18 IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L22N_T3_A16_15 Sch=ja[9] -#set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_L22P_T3_A17_15 Sch=ja[10] - - -##Pmod Header JB - -#set_property -dict { PACKAGE_PIN D14 IOSTANDARD LVCMOS33 } [get_ports { jb[0] }]; #IO_L1P_T0_AD0P_15 Sch=jb[1] -#set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { jb[1] }]; #IO_L14N_T2_SRCC_15 Sch=jb[2] -#set_property -dict { PACKAGE_PIN G16 IOSTANDARD LVCMOS33 } [get_ports { jb[2] }]; #IO_L13N_T2_MRCC_15 Sch=jb[3] -#set_property -dict { PACKAGE_PIN H14 IOSTANDARD LVCMOS33 } [get_ports { jb[3] }]; #IO_L15P_T2_DQS_15 Sch=jb[4] -#set_property -dict { PACKAGE_PIN E16 IOSTANDARD LVCMOS33 } [get_ports { jb[4] }]; #IO_L11N_T1_SRCC_15 Sch=jb[7] -#set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { jb[5] }]; #IO_L5P_T0_AD9P_15 Sch=jb[8] -#set_property -dict { PACKAGE_PIN G13 IOSTANDARD LVCMOS33 } [get_ports { jb[6] }]; #IO_0_15 Sch=jb[9] -#set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { jb[7] }]; #IO_L13P_T2_MRCC_15 Sch=jb[10] - - -##Pmod Header JC - -#set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { jc[0] }]; #IO_L23N_T3_35 Sch=jc[1] -#set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { jc[1] }]; #IO_L19N_T3_VREF_35 Sch=jc[2] -#set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { jc[2] }]; #IO_L22N_T3_35 Sch=jc[3] -#set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { jc[3] }]; #IO_L19P_T3_35 Sch=jc[4] -#set_property -dict { PACKAGE_PIN E7 IOSTANDARD LVCMOS33 } [get_ports { jc[4] }]; #IO_L6P_T0_35 Sch=jc[7] -#set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { jc[5] }]; #IO_L22P_T3_35 Sch=jc[8] -#set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { jc[6] }]; #IO_L21P_T3_DQS_35 Sch=jc[9] -#set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { jc[7] }]; #IO_L5P_T0_AD13P_35 Sch=jc[10] - - -##Pmod Header JD - -#set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { jd[0] }]; #IO_L21N_T3_DQS_35 Sch=jd[1] -#set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports { jd[1] }]; #IO_L17P_T2_35 Sch=jd[2] -#set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { jd[2] }]; #IO_L17N_T2_35 Sch=jd[3] -#set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { jd[3] }]; #IO_L20N_T3_35 Sch=jd[4] -#set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { jd[4] }]; #IO_L15P_T2_DQS_35 Sch=jd[7] -#set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { jd[5] }]; #IO_L20P_T3_35 Sch=jd[8] -#set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { jd[6] }]; #IO_L15N_T2_DQS_35 Sch=jd[9] -#set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { jd[7] }]; #IO_L13N_T2_MRCC_35 Sch=jd[10] - - -##Pmod Header JXADC - -#set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVDS } [get_ports { xa_n[0] }]; #IO_L9N_T1_DQS_AD3N_15 Sch=xa_n[1] -#set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVDS } [get_ports { xa_p[0] }]; #IO_L9P_T1_DQS_AD3P_15 Sch=xa_p[1] -#set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVDS } [get_ports { xa_n[1] }]; #IO_L8N_T1_AD10N_15 Sch=xa_n[2] -#set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVDS } [get_ports { xa_p[1] }]; #IO_L8P_T1_AD10P_15 Sch=xa_p[2] -#set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVDS } [get_ports { xa_n[2] }]; #IO_L7N_T1_AD2N_15 Sch=xa_n[3] -#set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVDS } [get_ports { xa_p[2] }]; #IO_L7P_T1_AD2P_15 Sch=xa_p[3] -#set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVDS } [get_ports { xa_n[3] }]; #IO_L10N_T1_AD11N_15 Sch=xa_n[4] -#set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVDS } [get_ports { xa_p[3] }]; #IO_L10P_T1_AD11P_15 Sch=xa_p[4] - - -##VGA Connector - -#set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { vga_r[0] }]; #IO_L8N_T1_AD14N_35 Sch=vga_r[0] -#set_property -dict { PACKAGE_PIN B4 IOSTANDARD LVCMOS33 } [get_ports { vga_r[1] }]; #IO_L7N_T1_AD6N_35 Sch=vga_r[1] -#set_property -dict { PACKAGE_PIN C5 IOSTANDARD LVCMOS33 } [get_ports { vga_r[2] }]; #IO_L1N_T0_AD4N_35 Sch=vga_r[2] -#set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { vga_r[3] }]; #IO_L8P_T1_AD14P_35 Sch=vga_r[3] -# -#set_property -dict { PACKAGE_PIN C6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[0] }]; #IO_L1P_T0_AD4P_35 Sch=vga_g[0] -#set_property -dict { PACKAGE_PIN A5 IOSTANDARD LVCMOS33 } [get_ports { vga_g[1] }]; #IO_L3N_T0_DQS_AD5N_35 Sch=vga_g[1] -#set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[2] }]; #IO_L2N_T0_AD12N_35 Sch=vga_g[2] -#set_property -dict { PACKAGE_PIN A6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[3] }]; #IO_L3P_T0_DQS_AD5P_35 Sch=vga_g[3] -# -#set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[0] }]; #IO_L2P_T0_AD12P_35 Sch=vga_b[0] -#set_property -dict { PACKAGE_PIN C7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[1] }]; #IO_L4N_T0_35 Sch=vga_b[1] -#set_property -dict { PACKAGE_PIN D7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[2] }]; #IO_L6N_T0_VREF_35 Sch=vga_b[2] -#set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { vga_b[3] }]; #IO_L4P_T0_35 Sch=vga_b[3] - -#set_property -dict { PACKAGE_PIN B11 IOSTANDARD LVCMOS33 } [get_ports { vga_hs }]; #IO_L4P_T0_15 Sch=vga_hs -#set_property -dict { PACKAGE_PIN B12 IOSTANDARD LVCMOS33 } [get_ports { vga_vs }]; #IO_L3N_T0_DQS_AD1N_15 Sch=vga_vs - -##Micro SD Connector - -#set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { sd_reset }]; #IO_L14P_T2_SRCC_35 Sch=sd_reset -#set_property -dict { PACKAGE_PIN A1 IOSTANDARD LVCMOS33 } [get_ports { sd_cd }]; #IO_L9N_T1_DQS_AD7N_35 Sch=sd_cd -#set_property -dict { PACKAGE_PIN B1 IOSTANDARD LVCMOS33 } [get_ports { sd_sck }]; #IO_L9P_T1_DQS_AD7P_35 Sch=sd_sck -#set_property -dict { PACKAGE_PIN C1 IOSTANDARD LVCMOS33 } [get_ports { sd_cmd }]; #IO_L16N_T2_35 Sch=sd_cmd -#set_property -dict { PACKAGE_PIN C2 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[0] }]; #IO_L16P_T2_35 Sch=sd_dat[0] -#set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[1] }]; #IO_L18N_T2_35 Sch=sd_dat[1] -#set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[2] }]; #IO_L18P_T2_35 Sch=sd_dat[2] -#set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[3] }]; #IO_L14N_T2_SRCC_35 Sch=sd_dat[3] - - -##Accelerometer - -#set_property -dict { PACKAGE_PIN E15 IOSTANDARD LVCMOS33 } [get_ports { acl_miso }]; #IO_L11P_T1_SRCC_15 Sch=acl_miso -#set_property -dict { PACKAGE_PIN F14 IOSTANDARD LVCMOS33 } [get_ports { acl_mosi }]; #IO_L5N_T0_AD9N_15 Sch=acl_mosi -#set_property -dict { PACKAGE_PIN F15 IOSTANDARD LVCMOS33 } [get_ports { acl_sclk }]; #IO_L14P_T2_SRCC_15 Sch=acl_sclk -#set_property -dict { PACKAGE_PIN D15 IOSTANDARD LVCMOS33 } [get_ports { acl_csn }]; #IO_L12P_T1_MRCC_15 Sch=acl_csn -#set_property -dict { PACKAGE_PIN B13 IOSTANDARD LVCMOS33 } [get_ports { acl_int[1] }]; #IO_L2P_T0_AD8P_15 Sch=acl_int[1] -#set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 } [get_ports { acl_int[2] }]; #IO_L20P_T3_A20_15 Sch=acl_int[2] - - -##Temperature Sensor - -#set_property -dict { PACKAGE_PIN C14 IOSTANDARD LVCMOS33 } [get_ports { tmp_scl }]; #IO_L1N_T0_AD0N_15 Sch=tmp_scl -#set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS33 } [get_ports { tmp_sda }]; #IO_L12N_T1_MRCC_15 Sch=tmp_sda -#set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 } [get_ports { tmp_int }]; #IO_L6N_T0_VREF_15 Sch=tmp_int -#set_property -dict { PACKAGE_PIN B14 IOSTANDARD LVCMOS33 } [get_ports { tmp_ct }]; #IO_L2N_T0_AD8N_15 Sch=tmp_ct - -##Omnidirectional Microphone - -#set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { m_clk }]; #IO_25_35 Sch=m_clk -#set_property -dict { PACKAGE_PIN H5 IOSTANDARD LVCMOS33 } [get_ports { m_data }]; #IO_L24N_T3_35 Sch=m_data -#set_property -dict { PACKAGE_PIN F5 IOSTANDARD LVCMOS33 } [get_ports { m_lrsel }]; #IO_0_35 Sch=m_lrsel - - -##PWM Audio Amplifier - -#set_property -dict { PACKAGE_PIN A11 IOSTANDARD LVCMOS33 } [get_ports { aud_pwm }]; #IO_L4N_T0_15 Sch=aud_pwm -#set_property -dict { PACKAGE_PIN D12 IOSTANDARD LVCMOS33 } [get_ports { aud_sd }]; #IO_L6P_T0_15 Sch=aud_sd - - -##USB-RS232 Interface - -set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { uart_txd_in }]; #IO_L7P_T1_AD6P_35 Sch=uart_txd_in -set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { uart_rxd_out }]; #IO_L11N_T1_SRCC_35 Sch=uart_rxd_out -#set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { uart_cts }]; #IO_L12N_T1_MRCC_35 Sch=uart_cts -#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { uart_rts }]; #IO_L5N_T0_AD13N_35 Sch=uart_rts - -##USB HID (PS/2) - -set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { ps2_clk }]; #IO_L13P_T2_MRCC_35 Sch=ps2_clk -set_property -dict { PACKAGE_PIN B2 IOSTANDARD LVCMOS33 } [get_ports { ps2_data }]; #IO_L10N_T1_AD15N_35 Sch=ps2_data - - -##SMSC Ethernet PHY - -#set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { eth_mdc }]; #IO_L11P_T1_SRCC_16 Sch=eth_mdc -#set_property -dict { PACKAGE_PIN A9 IOSTANDARD LVCMOS33 } [get_ports { eth_mdio }]; #IO_L14N_T2_SRCC_16 Sch=eth_mdio -#set_property -dict { PACKAGE_PIN B3 IOSTANDARD LVCMOS33 } [get_ports { eth_rstn }]; #IO_L10P_T1_AD15P_35 Sch=eth_rstn -#set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { eth_crsdv }]; #IO_L6N_T0_VREF_16 Sch=eth_crs/udv -#set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { eth_rxerr }]; #IO_L13N_T2_MRCC_16 Sch=eth_rxerr -#set_property -dict { PACKAGE_PIN C11 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[0] }]; #IO_L13P_T2_MRCC_16 Sch=eth_rxd[0] -#set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[1] }]; #IO_L19N_T3_VREF_16 Sch=eth_rxd[1] -#set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { eth_txen }]; #IO_L11N_T1_SRCC_16 Sch=eth_txen -#set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[0] }]; #IO_L14P_T2_SRCC_16 Sch=eth_txd[0] -#set_property -dict { PACKAGE_PIN A8 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[1] }]; #IO_L12N_T1_MRCC_16 Sch=eth_txd[1] -#set_property -dict { PACKAGE_PIN D5 IOSTANDARD LVCMOS33 } [get_ports { eth_refclk }]; #IO_L11P_T1_SRCC_35 Sch=eth_refclk -#set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { eth_intn }]; #IO_L12P_T1_MRCC_16 Sch=eth_intn - - -##Quad SPI Flash - -#set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[0] }]; #IO_L1P_T0_D00_MOSI_14 Sch=qspi_dq[0] -#set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[1] }]; #IO_L1N_T0_D01_DIN_14 Sch=qspi_dq[1] -#set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[2] }]; #IO_L2P_T0_D02_14 Sch=qspi_dq[2] -#set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[3] }]; #IO_L2N_T0_D03_14 Sch=qspi_dq[3] -#set_property -dict { PACKAGE_PIN L13 IOSTANDARD LVCMOS33 } [get_ports { qspi_csn }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_csn - - diff --git a/examples/nexys_a7/ps2_logic_analyzer/manta.yaml b/examples/nexys_a7/ps2_logic_analyzer/manta.yaml deleted file mode 100644 index c2d1e5f..0000000 --- a/examples/nexys_a7/ps2_logic_analyzer/manta.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -cores: - my_logic_analyzer: - type: logic_analyzer - sample_depth: 64000 - trigger_location: 15000 - - probes: - ps2_clk: 1 - ps2_data: 1 - - triggers: - - ps2_data FALLING - -uart: - port: "auto" - baudrate: 115200 - clock_freq: 50000000 \ No newline at end of file diff --git a/examples/nexys_a7/ps2_logic_analyzer/sim/playback.v b/examples/nexys_a7/ps2_logic_analyzer/sim/playback.v deleted file mode 100644 index acf7d73..0000000 --- a/examples/nexys_a7/ps2_logic_analyzer/sim/playback.v +++ /dev/null @@ -1,52 +0,0 @@ -/* -This playback module was generated with Manta v0.0.5 on 19 Jul 2023 at 18:52:11 by fischerm - -If this breaks or if you've got dank formal verification memes, contact fischerm [at] mit.edu - -Provided under a GNU GPLv3 license. Go wild. - -Here's an example instantiation of the Manta module you configured, feel free to copy-paste -this into your source! - -my_logic_analyzer_playback #(.MEM_FILE("capture.mem")) my_logic_analyzer_playback_inst ( - .clk(clk), - .enable(1'b1), - - .ps2_clk(ps2_clk), - .ps2_data(ps2_data)); - -*/ - - -module my_logic_analyzer_playback ( - input wire clk, - - input wire enable, - output reg done, - - output reg ps2_clk, - output reg ps2_data); - - parameter MEM_FILE = ""; - localparam SAMPLE_DEPTH = 64000; - localparam TOTAL_PROBE_WIDTH = 2; - - reg [TOTAL_PROBE_WIDTH-1:0] capture [SAMPLE_DEPTH-1:0]; - reg [$clog2(SAMPLE_DEPTH)-1:0] addr; - reg [TOTAL_PROBE_WIDTH-1:0] sample; - - assign done = (addr >= SAMPLE_DEPTH); - - initial begin - $readmemb(MEM_FILE, capture, 0, SAMPLE_DEPTH-1); - addr = 0; - end - - always @(posedge clk) begin - if (enable && !done) begin - addr = addr + 1; - sample = capture[addr]; - {ps2_data, ps2_clk} = sample; - end - end -endmodule \ No newline at end of file diff --git a/examples/nexys_a7/ps2_logic_analyzer/sim/playback_tb.sv b/examples/nexys_a7/ps2_logic_analyzer/sim/playback_tb.sv deleted file mode 100644 index 7116fb8..0000000 --- a/examples/nexys_a7/ps2_logic_analyzer/sim/playback_tb.sv +++ /dev/null @@ -1,80 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -module ps2_decoder( - input wire clk, - - input wire ps2_clk, - input wire ps2_data, - - output logic [7:0] data - ); - - reg prev_clk; - reg [10:0] buffer = 0; - reg [3:0] counter = 0; - - always @(posedge clk) begin - prev_clk <= ps2_clk; - - if (!prev_clk && ps2_clk) begin - buffer <= {buffer[9:0], ps2_data}; - counter <= counter + 1; - end - - if (counter == 11) begin - if (!buffer[10] && buffer[0]) begin - counter <= 0; - data <= {buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7], buffer[8], buffer[9]}; - end - end - - end - -endmodule - -module playback_tb(); - logic clk; - - always begin - #5; - clk = !clk; - end - - logic ps2_clk; - logic ps2_data; - - my_logic_analyzer_playback #(.MEM_FILE("capture.mem")) my_logic_analyzer_playback_inst ( - .clk(clk), - .enable(1'b1), - - .ps2_clk(ps2_clk), - .ps2_data(ps2_data)); - - logic [7:0] data; - - ps2_decoder decoder( - .clk(clk), - - .ps2_clk(ps2_clk), - .ps2_data(ps2_data), - - .data(data) - ); - - initial begin - clk = 0; - $dumpfile("playback_tb.vcd"); - $dumpvars(0, playback_tb); - - #(450000*5); - $finish(); - end - -endmodule - - - - - -`default_nettype wire \ No newline at end of file diff --git a/examples/nexys_a7/ps2_logic_analyzer/src/top_level.sv b/examples/nexys_a7/ps2_logic_analyzer/src/top_level.sv deleted file mode 100644 index b54ef17..0000000 --- a/examples/nexys_a7/ps2_logic_analyzer/src/top_level.sv +++ /dev/null @@ -1,25 +0,0 @@ -`default_nettype none -`timescale 1ns / 1ps - -module top_level ( - input wire clk, - - input wire ps2_clk, - input wire ps2_data, - - input wire uart_txd_in, - output logic uart_rxd_out - ); - - manta manta_inst ( - .clk(clk), - - .rx(uart_txd_in), - .tx(uart_rxd_out), - - .ps2_clk(ps2_clk), - .ps2_data(ps2_data)); - -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/examples/nexys_a7/ps2_logic_analyzer/xdc/top_level.xdc b/examples/nexys_a7/ps2_logic_analyzer/xdc/top_level.xdc deleted file mode 100644 index 81c1998..0000000 --- a/examples/nexys_a7/ps2_logic_analyzer/xdc/top_level.xdc +++ /dev/null @@ -1,254 +0,0 @@ -## This file is a general .xdc for the Nexys4 DDR Rev. C -## To use it in a project: -## - uncomment the lines corresponding to used pins -## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project - -## This file has been modified from the default .xdc provided by Digilent for the Nexys A7 - -## Clock signal - uncomment _both_ of these lines to create clk_100mhz -set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { clk }]; #IO_L12P_T1_MRCC_35 Sch=clk -create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {clk}]; - -##Switches - -#set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { sw[0] }]; #IO_L24N_T3_RS0_15 Sch=sw[0] -#set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 } [get_ports { sw[1] }]; #IO_L3N_T0_DQS_EMCCLK_14 Sch=sw[1] -#set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { sw[2] }]; #IO_L6N_T0_D08_VREF_14 Sch=sw[2] -#set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { sw[3] }]; #IO_L13N_T2_MRCC_14 Sch=sw[3] -#set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { sw[4] }]; #IO_L12N_T1_MRCC_14 Sch=sw[4] -#set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { sw[5] }]; #IO_L7N_T1_D10_14 Sch=sw[5] -#set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { sw[6] }]; #IO_L17N_T2_A13_D29_14 Sch=sw[6] -#set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { sw[7] }]; #IO_L5N_T0_D07_14 Sch=sw[7] -#set_property -dict { PACKAGE_PIN T8 IOSTANDARD LVCMOS18 } [get_ports { sw[8] }]; #IO_L24N_T3_34 Sch=sw[8] -#set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS18 } [get_ports { sw[9] }]; #IO_25_34 Sch=sw[9] -#set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { sw[10] }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=sw[10] -#set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { sw[11] }]; #IO_L23P_T3_A03_D19_14 Sch=sw[11] -#set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { sw[12] }]; #IO_L24P_T3_35 Sch=sw[12] -#set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { sw[13] }]; #IO_L20P_T3_A08_D24_14 Sch=sw[13] -#set_property -dict { PACKAGE_PIN U11 IOSTANDARD LVCMOS33 } [get_ports { sw[14] }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=sw[14] -#set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { sw[15] }]; #IO_L21P_T3_DQS_14 Sch=sw[15] - - -## LEDs - -#set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { led[0] }]; #IO_L18P_T2_A24_15 Sch=led[0] -#set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { led[1] }]; #IO_L24P_T3_RS1_15 Sch=led[1] -#set_property -dict { PACKAGE_PIN J13 IOSTANDARD LVCMOS33 } [get_ports { led[2] }]; #IO_L17N_T2_A25_15 Sch=led[2] -#set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { led[3] }]; #IO_L8P_T1_D11_14 Sch=led[3] -#set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { led[4] }]; #IO_L7P_T1_D09_14 Sch=led[4] -#set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { led[5] }]; #IO_L18N_T2_A11_D27_14 Sch=led[5] -#set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { led[6] }]; #IO_L17P_T2_A14_D30_14 Sch=led[6] -#set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { led[7] }]; #IO_L18P_T2_A12_D28_14 Sch=led[7] -#set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { led[8] }]; #IO_L16N_T2_A15_D31_14 Sch=led[8] -#set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { led[9] }]; #IO_L14N_T2_SRCC_14 Sch=led[9] -#set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { led[10] }]; #IO_L22P_T3_A05_D21_14 Sch=led[10] -#set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { led[11] }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=led[11] -#set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { led[12] }]; #IO_L16P_T2_CSI_B_14 Sch=led[12] -#set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { led[13] }]; #IO_L22N_T3_A04_D20_14 Sch=led[13] -#set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { led[14] }]; #IO_L20N_T3_A07_D23_14 Sch=led[14] -#set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { led[15] }]; #IO_L21N_T3_DQS_A06_D22_14 Sch=led[15] - -#set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { led16_b }]; #IO_L5P_T0_D06_14 Sch=led16_b -#set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { led16_g }]; #IO_L10P_T1_D14_14 Sch=led16_g -#set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { led16_r }]; #IO_L11P_T1_SRCC_14 Sch=led16_r -#set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { led17_b }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=led17_b -#set_property -dict { PACKAGE_PIN R11 IOSTANDARD LVCMOS33 } [get_ports { led17_g }]; #IO_0_14 Sch=led17_g -#set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { led17_r }]; #IO_L11N_T1_SRCC_14 Sch=led17_r - - -##7 segment display - -#set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { ca }]; #IO_L24N_T3_A00_D16_14 Sch=ca -#set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { cb }]; #IO_25_14 Sch=cb -#set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { cc }]; #IO_25_15 Sch=cc -#set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { cd }]; #IO_L17P_T2_A26_15 Sch=cd -#set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ce }]; #IO_L13P_T2_MRCC_14 Sch=ce -#set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { cf }]; #IO_L19P_T3_A10_D26_14 Sch=cf -#set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { cg }]; #IO_L4P_T0_D04_14 Sch=cg - -#set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { dp }]; #IO_L19N_T3_A21_VREF_15 Sch=dp - -#set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { an[0] }]; #IO_L23P_T3_FOE_B_15 Sch=an[0] -#set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { an[1] }]; #IO_L23N_T3_FWE_B_15 Sch=an[1] -#set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { an[2] }]; #IO_L24P_T3_A01_D17_14 Sch=an[2] -#set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { an[3] }]; #IO_L19P_T3_A22_15 Sch=an[3] -#set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { an[4] }]; #IO_L8N_T1_D12_14 Sch=an[4] -#set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { an[5] }]; #IO_L14P_T2_SRCC_14 Sch=an[5] -#set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { an[6] }]; #IO_L23P_T3_35 Sch=an[6] -#set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { an[7] }]; #IO_L23N_T3_A02_D18_14 Sch=an[7] - - -##Buttons - -#set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { cpu_resetn }]; #IO_L3P_T0_DQS_AD1P_15 Sch=cpu_resetn - -#set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { btnc }]; #IO_L9P_T1_DQS_14 Sch=btnc -#set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { btnu }]; #IO_L4N_T0_D05_14 Sch=btnu -#set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { btnl }]; #IO_L12P_T1_MRCC_14 Sch=btnl -#set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { btnr }]; #IO_L10N_T1_D15_14 Sch=btnr -#set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { btnd }]; #IO_L9N_T1_DQS_D13_14 Sch=btnd - - -##Pmod Headers - - -##Pmod Header JA - -#set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { ja[0] }]; #IO_L20N_T3_A19_15 Sch=ja[1] -#set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { ja[1] }]; #IO_L21N_T3_DQS_A18_15 Sch=ja[2] -#set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { ja[2] }]; #IO_L21P_T3_DQS_15 Sch=ja[3] -#set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { ja[3] }]; #IO_L18N_T2_A23_15 Sch=ja[4] -#set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L16N_T2_A27_15 Sch=ja[7] -#set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L16P_T2_A28_15 Sch=ja[8] -#set_property -dict { PACKAGE_PIN F18 IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L22N_T3_A16_15 Sch=ja[9] -#set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_L22P_T3_A17_15 Sch=ja[10] - - -##Pmod Header JB - -#set_property -dict { PACKAGE_PIN D14 IOSTANDARD LVCMOS33 } [get_ports { jb[0] }]; #IO_L1P_T0_AD0P_15 Sch=jb[1] -#set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { jb[1] }]; #IO_L14N_T2_SRCC_15 Sch=jb[2] -#set_property -dict { PACKAGE_PIN G16 IOSTANDARD LVCMOS33 } [get_ports { jb[2] }]; #IO_L13N_T2_MRCC_15 Sch=jb[3] -#set_property -dict { PACKAGE_PIN H14 IOSTANDARD LVCMOS33 } [get_ports { jb[3] }]; #IO_L15P_T2_DQS_15 Sch=jb[4] -#set_property -dict { PACKAGE_PIN E16 IOSTANDARD LVCMOS33 } [get_ports { jb[4] }]; #IO_L11N_T1_SRCC_15 Sch=jb[7] -#set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { jb[5] }]; #IO_L5P_T0_AD9P_15 Sch=jb[8] -#set_property -dict { PACKAGE_PIN G13 IOSTANDARD LVCMOS33 } [get_ports { jb[6] }]; #IO_0_15 Sch=jb[9] -#set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { jb[7] }]; #IO_L13P_T2_MRCC_15 Sch=jb[10] - - -##Pmod Header JC - -#set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { jc[0] }]; #IO_L23N_T3_35 Sch=jc[1] -#set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { jc[1] }]; #IO_L19N_T3_VREF_35 Sch=jc[2] -#set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { jc[2] }]; #IO_L22N_T3_35 Sch=jc[3] -#set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { jc[3] }]; #IO_L19P_T3_35 Sch=jc[4] -#set_property -dict { PACKAGE_PIN E7 IOSTANDARD LVCMOS33 } [get_ports { jc[4] }]; #IO_L6P_T0_35 Sch=jc[7] -#set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { jc[5] }]; #IO_L22P_T3_35 Sch=jc[8] -#set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { jc[6] }]; #IO_L21P_T3_DQS_35 Sch=jc[9] -#set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { jc[7] }]; #IO_L5P_T0_AD13P_35 Sch=jc[10] - - -##Pmod Header JD - -#set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { jd[0] }]; #IO_L21N_T3_DQS_35 Sch=jd[1] -#set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports { jd[1] }]; #IO_L17P_T2_35 Sch=jd[2] -#set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { jd[2] }]; #IO_L17N_T2_35 Sch=jd[3] -#set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { jd[3] }]; #IO_L20N_T3_35 Sch=jd[4] -#set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { jd[4] }]; #IO_L15P_T2_DQS_35 Sch=jd[7] -#set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { jd[5] }]; #IO_L20P_T3_35 Sch=jd[8] -#set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { jd[6] }]; #IO_L15N_T2_DQS_35 Sch=jd[9] -#set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { jd[7] }]; #IO_L13N_T2_MRCC_35 Sch=jd[10] - - -##Pmod Header JXADC - -#set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVDS } [get_ports { xa_n[0] }]; #IO_L9N_T1_DQS_AD3N_15 Sch=xa_n[1] -#set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVDS } [get_ports { xa_p[0] }]; #IO_L9P_T1_DQS_AD3P_15 Sch=xa_p[1] -#set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVDS } [get_ports { xa_n[1] }]; #IO_L8N_T1_AD10N_15 Sch=xa_n[2] -#set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVDS } [get_ports { xa_p[1] }]; #IO_L8P_T1_AD10P_15 Sch=xa_p[2] -#set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVDS } [get_ports { xa_n[2] }]; #IO_L7N_T1_AD2N_15 Sch=xa_n[3] -#set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVDS } [get_ports { xa_p[2] }]; #IO_L7P_T1_AD2P_15 Sch=xa_p[3] -#set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVDS } [get_ports { xa_n[3] }]; #IO_L10N_T1_AD11N_15 Sch=xa_n[4] -#set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVDS } [get_ports { xa_p[3] }]; #IO_L10P_T1_AD11P_15 Sch=xa_p[4] - - -##VGA Connector - -#set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { vga_r[0] }]; #IO_L8N_T1_AD14N_35 Sch=vga_r[0] -#set_property -dict { PACKAGE_PIN B4 IOSTANDARD LVCMOS33 } [get_ports { vga_r[1] }]; #IO_L7N_T1_AD6N_35 Sch=vga_r[1] -#set_property -dict { PACKAGE_PIN C5 IOSTANDARD LVCMOS33 } [get_ports { vga_r[2] }]; #IO_L1N_T0_AD4N_35 Sch=vga_r[2] -#set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { vga_r[3] }]; #IO_L8P_T1_AD14P_35 Sch=vga_r[3] -# -#set_property -dict { PACKAGE_PIN C6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[0] }]; #IO_L1P_T0_AD4P_35 Sch=vga_g[0] -#set_property -dict { PACKAGE_PIN A5 IOSTANDARD LVCMOS33 } [get_ports { vga_g[1] }]; #IO_L3N_T0_DQS_AD5N_35 Sch=vga_g[1] -#set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[2] }]; #IO_L2N_T0_AD12N_35 Sch=vga_g[2] -#set_property -dict { PACKAGE_PIN A6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[3] }]; #IO_L3P_T0_DQS_AD5P_35 Sch=vga_g[3] -# -#set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[0] }]; #IO_L2P_T0_AD12P_35 Sch=vga_b[0] -#set_property -dict { PACKAGE_PIN C7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[1] }]; #IO_L4N_T0_35 Sch=vga_b[1] -#set_property -dict { PACKAGE_PIN D7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[2] }]; #IO_L6N_T0_VREF_35 Sch=vga_b[2] -#set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { vga_b[3] }]; #IO_L4P_T0_35 Sch=vga_b[3] - -#set_property -dict { PACKAGE_PIN B11 IOSTANDARD LVCMOS33 } [get_ports { vga_hs }]; #IO_L4P_T0_15 Sch=vga_hs -#set_property -dict { PACKAGE_PIN B12 IOSTANDARD LVCMOS33 } [get_ports { vga_vs }]; #IO_L3N_T0_DQS_AD1N_15 Sch=vga_vs - -##Micro SD Connector - -#set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { sd_reset }]; #IO_L14P_T2_SRCC_35 Sch=sd_reset -#set_property -dict { PACKAGE_PIN A1 IOSTANDARD LVCMOS33 } [get_ports { sd_cd }]; #IO_L9N_T1_DQS_AD7N_35 Sch=sd_cd -#set_property -dict { PACKAGE_PIN B1 IOSTANDARD LVCMOS33 } [get_ports { sd_sck }]; #IO_L9P_T1_DQS_AD7P_35 Sch=sd_sck -#set_property -dict { PACKAGE_PIN C1 IOSTANDARD LVCMOS33 } [get_ports { sd_cmd }]; #IO_L16N_T2_35 Sch=sd_cmd -#set_property -dict { PACKAGE_PIN C2 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[0] }]; #IO_L16P_T2_35 Sch=sd_dat[0] -#set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[1] }]; #IO_L18N_T2_35 Sch=sd_dat[1] -#set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[2] }]; #IO_L18P_T2_35 Sch=sd_dat[2] -#set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[3] }]; #IO_L14N_T2_SRCC_35 Sch=sd_dat[3] - - -##Accelerometer - -#set_property -dict { PACKAGE_PIN E15 IOSTANDARD LVCMOS33 } [get_ports { acl_miso }]; #IO_L11P_T1_SRCC_15 Sch=acl_miso -#set_property -dict { PACKAGE_PIN F14 IOSTANDARD LVCMOS33 } [get_ports { acl_mosi }]; #IO_L5N_T0_AD9N_15 Sch=acl_mosi -#set_property -dict { PACKAGE_PIN F15 IOSTANDARD LVCMOS33 } [get_ports { acl_sclk }]; #IO_L14P_T2_SRCC_15 Sch=acl_sclk -#set_property -dict { PACKAGE_PIN D15 IOSTANDARD LVCMOS33 } [get_ports { acl_csn }]; #IO_L12P_T1_MRCC_15 Sch=acl_csn -#set_property -dict { PACKAGE_PIN B13 IOSTANDARD LVCMOS33 } [get_ports { acl_int[1] }]; #IO_L2P_T0_AD8P_15 Sch=acl_int[1] -#set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 } [get_ports { acl_int[2] }]; #IO_L20P_T3_A20_15 Sch=acl_int[2] - - -##Temperature Sensor - -#set_property -dict { PACKAGE_PIN C14 IOSTANDARD LVCMOS33 } [get_ports { tmp_scl }]; #IO_L1N_T0_AD0N_15 Sch=tmp_scl -#set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS33 } [get_ports { tmp_sda }]; #IO_L12N_T1_MRCC_15 Sch=tmp_sda -#set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 } [get_ports { tmp_int }]; #IO_L6N_T0_VREF_15 Sch=tmp_int -#set_property -dict { PACKAGE_PIN B14 IOSTANDARD LVCMOS33 } [get_ports { tmp_ct }]; #IO_L2N_T0_AD8N_15 Sch=tmp_ct - -##Omnidirectional Microphone - -#set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { m_clk }]; #IO_25_35 Sch=m_clk -#set_property -dict { PACKAGE_PIN H5 IOSTANDARD LVCMOS33 } [get_ports { m_data }]; #IO_L24N_T3_35 Sch=m_data -#set_property -dict { PACKAGE_PIN F5 IOSTANDARD LVCMOS33 } [get_ports { m_lrsel }]; #IO_0_35 Sch=m_lrsel - - -##PWM Audio Amplifier - -#set_property -dict { PACKAGE_PIN A11 IOSTANDARD LVCMOS33 } [get_ports { aud_pwm }]; #IO_L4N_T0_15 Sch=aud_pwm -#set_property -dict { PACKAGE_PIN D12 IOSTANDARD LVCMOS33 } [get_ports { aud_sd }]; #IO_L6P_T0_15 Sch=aud_sd - - -##USB-RS232 Interface - -set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { uart_txd_in }]; #IO_L7P_T1_AD6P_35 Sch=uart_txd_in -set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { uart_rxd_out }]; #IO_L11N_T1_SRCC_35 Sch=uart_rxd_out -#set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { uart_cts }]; #IO_L12N_T1_MRCC_35 Sch=uart_cts -#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { uart_rts }]; #IO_L5N_T0_AD13N_35 Sch=uart_rts - -##USB HID (PS/2) - -set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { ps2_clk }]; #IO_L13P_T2_MRCC_35 Sch=ps2_clk -set_property -dict { PACKAGE_PIN B2 IOSTANDARD LVCMOS33 } [get_ports { ps2_data }]; #IO_L10N_T1_AD15N_35 Sch=ps2_data - - -##SMSC Ethernet PHY - -#set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { eth_mdc }]; #IO_L11P_T1_SRCC_16 Sch=eth_mdc -#set_property -dict { PACKAGE_PIN A9 IOSTANDARD LVCMOS33 } [get_ports { eth_mdio }]; #IO_L14N_T2_SRCC_16 Sch=eth_mdio -#set_property -dict { PACKAGE_PIN B3 IOSTANDARD LVCMOS33 } [get_ports { eth_rstn }]; #IO_L10P_T1_AD15P_35 Sch=eth_rstn -#set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { eth_crsdv }]; #IO_L6N_T0_VREF_16 Sch=eth_crs/udv -#set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { eth_rxerr }]; #IO_L13N_T2_MRCC_16 Sch=eth_rxerr -#set_property -dict { PACKAGE_PIN C11 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[0] }]; #IO_L13P_T2_MRCC_16 Sch=eth_rxd[0] -#set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[1] }]; #IO_L19N_T3_VREF_16 Sch=eth_rxd[1] -#set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { eth_txen }]; #IO_L11N_T1_SRCC_16 Sch=eth_txen -#set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[0] }]; #IO_L14P_T2_SRCC_16 Sch=eth_txd[0] -#set_property -dict { PACKAGE_PIN A8 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[1] }]; #IO_L12N_T1_MRCC_16 Sch=eth_txd[1] -#set_property -dict { PACKAGE_PIN D5 IOSTANDARD LVCMOS33 } [get_ports { eth_refclk }]; #IO_L11P_T1_SRCC_35 Sch=eth_refclk -#set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { eth_intn }]; #IO_L12P_T1_MRCC_16 Sch=eth_intn - - -##Quad SPI Flash - -#set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[0] }]; #IO_L1P_T0_D00_MOSI_14 Sch=qspi_dq[0] -#set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[1] }]; #IO_L1N_T0_D01_DIN_14 Sch=qspi_dq[1] -#set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[2] }]; #IO_L2P_T0_D02_14 Sch=qspi_dq[2] -#set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[3] }]; #IO_L2N_T0_D03_14 Sch=qspi_dq[3] -#set_property -dict { PACKAGE_PIN L13 IOSTANDARD LVCMOS33 } [get_ports { qspi_csn }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_csn - - diff --git a/examples/nexys_a7/video_sprite_ether/img/buff_doge.png b/examples/nexys_a7/video_sprite_ether/img/buff_doge.png deleted file mode 100644 index d504d022b1fbe9896a43e008ec41ffbad202d00d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69692 zcmeFZWl&t*wl>;0!5at=v}r5^clX9!gS$2E?(PH$Zb5@XaMuJva1HJf++8m3yZ6~= z@A|%~Tc_&Ye}^iHwdNe-8FM^CdabTeL@FsrqN5O^0001VX(@;b008rP2?Iceef=|q zCBy;%kXw1FX}YKwxq}>>?9HJzW*`?&2Q!eF2hB=@%z2qDp?9cvk z$FZ{7vwL%MQ+;}MqqyoW^!)BF<2FN3$nyHC>f|ImmvOUi&0rf7-|FB1>0+1c^6`#v zkqJL4mr0s#vg>9p^nNZ>>VZ~Xdh^YWve5Yt1`OEttE z|2WB*pO$iLmG=7>Y~nK{74c>7apdJxbPN@diQ{>+)K@Pi;882f?{U9k&#LrJ(crS_ z+tm}(jdi2bqnGqO)!_B!L9X9w==m?q$@qtUp%tDcGPCoko9NIdJxL*P1OMaYqfUz* zS_w{3TLa9ir}rlY?RHM6%dI>q=AGvy4w3hM?tWZlUdkwoOhR`ZqL>LT%b)r%D3%;n z=HBAT4xcq^-bu#L72k}cSRFbhbO_JhlGs(4x|T@j&&hf#oDFFAw%OkN>S*IQZii!v z4U9(k+$;2S^!$hDSe-6pZ82W6wu<1bP0E+yKlb_(61`6-R-Q1=&rb(T+Z+i!`R~ic zc>}X^Wrwk!L*f5W@t*be&M9JswRSNIM>M+{v5+Uge8W?DgXa@l8zu}QdP7JrP)tno z4!Nj*1Z<-4b5K6ImBYSty@Nevu!&?9X?PIwrRzh>mlG+C(a`(S7G<%5!bDkG4J&9- zs?pDHZ`sPJm54cJ4y{TxtZf_SCRBb^vRgMa%r5TL(g@eN95ghoJP<57J8bu~Au$n{ z{75&?`7WR7+Bm{@EX3@22`G$L4NrooZ>2P{VL1KH6GuA_>wlAF!=|DD z{RB)-{rXTDD?98SYcY}$c7?sjYm}wx{&f$d3+WHfZa=TAPC1e5^eD#iMs}%2$~zhQ zwnh@gVcUz4gi!Wh72Fk`qh;YkMp}RBS?yx4YU=l@Mrt;>*?zauJC$r$Xh-|crj5RP z8g}#igYK(r#=o!YWhmV8AeMg=B1^IjY_CKc&t5a1A`1B)MAQ2FZghjr14XO>uQeLACMFhRE=*Aqfbn zE-52;Uu$%^mKC33e~PK|va0J7zkwP=EKRjlhZIhBOsya=HH8w1jfGFHbXKYa%CK(7 z)WCi$nnu}}kZgg^fYO81UJ{3%_zad;eb*nfA39vzVG_jz8a)>pK3KxW*p%4>H<%nw z6|X{*1*Z@?eUaoC2Qjp`Usz~t9?oUEia8gex%taXfp^jgMmi0A0!DJ724iU_8971fsu$EBty zPpOrn6^kAtP$CcQq*f%fWmw4#c;ybOOjshNPYcqRtA}{fo;VgMEr_{(=CwvSlw3jt|{13 zL$TZN1eAJDgUGlLC{lGrJ6k9D9`lB%8Tp!uIk~YoZExCblYVBN_X3XAMgH_9%;EXz z<4r14z66oRz}I}XdmnisQqT-Pn1UA|nKwhxew}0kXQQM&)ESxL zm8l_q*C7`|2tY4;Yn`5Vu^>~808xb1^H_2Y#M<KhS=afIT}|(+so|hATl`(;EFOTNh~)c4VnZ_@K`+hdWK;i=t z->A{9D~U3rO~<&F(nyfb!96<$Teo1qGoXHX04|ApNGGN!U(?o09KpA4yitVeK@iFs zK&tDrLne6LWC0LI(S^1KX8!l})ZNVFylOfp?dr|NWiVgrCg>G&Rv26*D#sZJgbHsV z9d7S!TpU$MZOQPN;3gocn-*45=psiz6nxp)Ph=VFM_(Q zDegHFc`My4(OBQkO7I+n_Cqf+7JWCqEy8zQ zG-Ih~1ZaFYWrk5h<=Hgl72HTxj+>A950y|a*~z<li#>RWO6b1?eB zLHPV9R*}wPDGx(fY{5kAu%g*R><%gQ1AXLGpX0i9P@vqYqZmUtVK_4s&WAq2BoA{Y z59v43N*H~Gm7WVdsWru9P5+0%-`NKJb;|L3qxu1O&B5k?d%6Jl^T8Q>UKT5vDGvJN zT%<8TEYG$Amfs!soemR=7$!a${NWm#24HG2!s1N$3sYj}${YdXIl&k9uNKBahlfQK z8Jiq$tbV>vMZr&Glee%W*jK1oxsOYad5ilNZ@FMRpp#ruVTpo18)#6#%}n_C<@cZY zH?4W1RsrsxzV6d_-_wvSAP*Vj^&G1N;EKoPkwuF)oM&Ok@IemAb^_1^(Lh1A=pc@8S8x}7iQueJmu)}!+v zxmcVvBqte3OAmypw8^2LA_z#wi%Cj*h!`Eeg$L+AfB1q-EiPO>Vh)QgmGo^XEf@Gp z9A^4Z0*+^DyZGyyhTv2=pukx#GhS$ZJ~*o9MuO)Xq0GB?fnN~iu1PMf<{sb2fJKDq zc|UH8^2DCiW<|6=C+!lKM(dpt)E}3;CwdEbZ2n&Pk-Z|bver|gtPIKH_6r7odcxa6 ze4UMaGM$ihC_M22b3n}MBmL^f%nOH+eEZVt-J zbSn2xRX`r*RIy@(Eey-heI!Ocj+nwE1<}1N!~lq;G^<^=AIq@F9B#$&CW)0XEOsAp zekN;vv-2S?+CCTnBH;3zlQGCAZ$fO5-^tHEDli{=B*2Tyzi8z^b?i~pC1CHuK368K zCBya8@DMBgT9&ZhMsZlMB@#ua6Er-8<0R>3G16LA;PvO5bd^I&#A=~9x#eE$X}W}N zjDt$)V*agHF?$}P1J5}L_GD?1#_~cE1kBchODjE@&E5u@hM=J5ruxwI{3r-c>I~kN z`oo#W^II3iNfLJv+*z0(i4u3nbWFN-otQoS4#Y>EzajsGl#D%z`rrnK`JofK^(KAz zK>G(=Da|gr?{qK=|Azf4>^v^FvKZ<|40iHN ze;(ZILi7~-^Y6(BBfax!aN;FVoFx?vf#q&4(M z!PbeWS2(&0+*EV*rRndTFNVDkZFF?cgyHVg1-Z{d!E*(;=f=iinK_qn2{W(+;w{Ey zANLrELy-z+#d^)x-()zzv}D(bOuzjcg+C6fNt4~uX0^n0NLFNOx?~{r4${q&I1?_9 zu~szXQTSCdLzDZIpjbFU_>om%5XfvB$Tv*@pUhD{y%v+A#QFhcAOIN4{1uxNRS&b; zl?SwsUj_5#r?kIq#5u}mD>yfH?fhzyMlD`uDGfWvQ`H;m3`+IHr0?V@;I;0N9}&^4 zwAnu!PCpS9z+#P#K_Xy-dO4a&mi1!M5{A{5)Wrhu^i-8XXg#+R90&z^-|J2LIQJlW zwFbazp}zlPqNu^Mc8TU<-S9y`K3*V0#K{FxV189DR@013A9MItO^Mw#kbr1BY8&C3 zfE9f4_6tjzr9>I$7pJ{JE^__LE9%ze(=+kTh#1K-@}2~&BzE(7dQ>MTL5bqLX@Sw( zIzTFN_vR~{Q?+APv7+WyoG`btmA@i3ohXverV-2-7QYj6g*u zwF#up%pn8kegh*+=OnCGK>*7|Vo7L2e$5Zxk2^0meA@gCLB-UPpBcU!x}0Df14Hc| z%wx}%b)^8WF!{KOYKmcX23>+3wS2^$&Qu|xl#tPlI1J#!qbu$;as24vA>XPwMaF{_ zV~ZnTzENUrJsKC5+R0KzSwIQpGcHUgemRfag^0k#77U|2(p0}8GlTzTSdM<0kDB^O zUCxjpwOz;L8=9G|i~JQF3x{xQ&{J@jgrvY62am8@0Z)z2Ew}O_< z&I7HZN|ROjNIy3&Y0i8bfpjRd{`z32~-l33Ijs*%WJ1 zCnU6F@ZSPt6u42@L@op6d9f_Ewqn(L&I#B07wT5j2w5;1hO6XNX;Cl&)fN|H2Xt)>M_bI?-WNjOMLVS%f<0gVofzu zAr9@jLtaO3p%LY)$$iu}Va@__RzG6xej*i8Es0Mby3q_fA{Q6<;A^Z}WGg>ysVB?X z-aC$AfCR`wnXB4K4+85+Vl7>M!et>BVf^?qLxmi0y0<5{LDkS6gcoNYW5|sjE3L!>8!gT7B21e6@9Bd^kQW= zG7Xr}o{uD2D%()OqERSK(*Uj#bD>mJ(*6_TCzQOX|5r66>Z z6W(nczeY-auePIJ)|W4;lZRhp+$Sw$3Yr*|?x8Gvj;QorH}b2957sUmno|GA$%wGQ zuiNjyUa&z<>}N%(FbC8|QgdoDEhlfVgiO-Q9Ad!jNM?EI!?seJcT};!XM58F!O1i( zbrd@2xE@xtTArr2+R?dMEKK$3hQe`lKjvrZd|rI2ux8<1BKc_9cSM*NCL+V6rSlxK zfZjL3!bZ?0uE4tm^wCBK_Q_UMU@by8?xoDJv7+S+jt5wYi->azC!AW(%tdHH<+;+D z9R|(YRx;RJ^WDNXyc7ay|6zM3Qz^ThK(XR3yak)as-H@5P3y8pm^AVH64K)a{WwIm zkR0_H9#jTc6(Jp`jXtu{%?P@^KYutvh`J-`^P{D9m!~TYB&uajEK=YqhhllA*P`0t=r70iqK)RtsM%<;Zgd~;WakX3#Pb}eW@a%L#VS~10N3*vl(&jvC;?101|yjShv z6Q;=D$2^C}C$TM?HEc3v-w-DfHCg6Xj0tv{&H7Q()r<8Uulj@H|Wv!#voy!zhuUP};6vNS0 zL^}0N(o*bbW(KcOa#bMbO!lZ8&^)3W<|4*mw?v%Eb+%AlWrM!gP0YPELSk=E{W$pJXLg21zHJPESywv$a!FRTkS$UN^IE2w( zJY4|!Pzpp1I;!D2ZQ|C*9vy|aAB9aN3JTr)?-rvzv1t*YMOQpWNl2{;=8z9*^dyT- z6XoiZp?Z3Ex>;5AY`-iNh%HnEsVUr%q;a$E&4R2?ABbK0ZSDP{AR&=MDVhDmCM`ir z2--N8bRYC$pC>vI@B}^+=6x=K*WT9;iq8p9mQg<_V%Kl}sr@~2;~V?iZUxFh?^Lvb zC==?y_&1b2zcuFain&fooaCJwIOggUDPLTWsy+uh!N+=wpHF}XGUj%O-)*E1UymC~ znQ;0yVWi51^!E^2cDk?}r(U%bC)Vo1A8Z>3hhKLve|aaIpdK?lCVI}VB_g^Kj6Wa`Mhe1?9v_4GaJK>WIa%t@4!nf5 z#$#v5Qc+hhjn~TG7=-KbimB^Q)F`~rA3tOi;w5+>po7s!SEuiJ(bvDK6Ougn&}KFc zN(EF>;o2XVhB3Qc^onL;FTasiKwY?YE>$X0i|HWe4vMNkB#Xh#nZ`x34 zV)#~2;9GeQQpp1PDRW+W3_o!AiW^*U=T*H0ppZ9#PV*6hd2M-0I2x8c}(LP0Rc8DGbZv=eX1WJmlti4kjrj z0b`0uYWX6+uMUPN4HY8;r7-)U$|*#I_TTo3X{%yzo+yvQ${O%#3zKfoNvdXAaCGze zUDjVa9x+yTIsXu z*Ej{lhSwEwg`Na%DSsPeuq{QLS!h0G6*9_J7n2B(3IFs*lW9?cLf1q+qgI}Spa>J& zB%R~5xkliSj6)vLX?x^pX5zC{rno?y8&=)u9w|w5NDj#(?2lgp$uXQ<9|%{*dD0`e zio`wqpw%TdSn_S+B$b=RcjQ8?5V(?UQ*Fl>?2!e@soFlu)mXtVu#+0aKNd};^^qjl zQNCOM0jLD*^1aiV)IApE%DDc*L@V!FINoA%hcub=ext31ae)p{9*sy3_i;eXYYj#= zZUlfisEydRUM^)%G)A7Obf&_qof0VIAuXm-wQd`Q>e`OlAW+plh^H(vRo;rzQS8W0 zQ#O+E!(LSGvI`?^wjJ38wVE)hQ3l#T@JUO|LW8;m;iCRwe+A=IrFv*Vj6&^AMaVKv z^I=4IKNHoEm(bU+20Lq0A)-{J8F`~smkb7SH(>Y&7dq6%f^mkA)e7z|TF(Xi}AKtpPwcY|v6tBz%(RN1>;b2rJsIfAD#xJu!qJ63K zYF_pzjC-o;OPO|V;rn#FLi{Vo$Z>Xo%kcy^n1uIkjO~fa65T9dobZt&fx7|!Za%?3Xqj4uCE6SqhvJ->s3lr^38jAS7M0KGVm4rtQLwS-+z5G zL5X7(?&~%eFc8@0V2Q!2;?vz*JY~rn#N|2($Bi_|bQq~)JC;RxWIG93I1k5l%_t28 zei|TLL|H(iUno=27PP6JN<^LrEthvaNR;1YWDb;SLL)Sncep6TZ0>g}qR)=^MsmQr zF(Bkwm2V;fV;);dxVfce^g?B&iJt0@btoTIRA;^rYlNt5Rf-MB_Mm5=$yYf~P9+qGlhJ7;DCRhY`5-sk5dRtZ zW_ct=HVK$bH=nGD3Dj9v7YKdXO68m4fCZz{j&%|g8OhF-9`fO1;A96}LifAu>r0Fs z0PssCAXfN*r;!7D1nPYYAu=Uf)^3A(AXkHA9m0~QrX?v8!z?vnuyTSzoISYJkcML0 z5lG4=Ao6VhT+WqmO6{s-qP3;c_}Y*G@7c&dD$c2sz1l6564N4fAdcjU3#BP-eL+!kwVt_>$;pfU#{gwW63Kj|0Iyb~o4tHa zL*=_%495|-8fb5#{!8@wF}^DT5|#`J#%zVK1x$x|;cv@sr9O_jDEcT!^exx%8q!d1 zF%I!72KEDDPZ|5h-YO zl#i~(yaQh;wA7IZ+@@VZ?HC9vCqCE~Pjs@k8a>vR1k_DP6ebidht-pVlqOuL&699$Ha<>x= z2y@KS0qFLWcz-*yY}9}eN1($Z@1>rHL8Btks&U#rIZOUFYEto(|1-8M^-RR1L$TT_ z7dVb@v{!Kq>#_>;O)C1zYhE-}!)yCKhsRY9Z|>$C(mn3C@v=StE%AJLb4 z+tZbzs#ZwSs7}zqnH@S^WjCi4%z9;nkB2D7drG;FBk~v$ew8tF!2Ml4Sc>u4;OOjW z=E>}ZJyDZA8sQ3gdg6T^bv0W;p>)Y8UAC|qnm2LuMMmTwN|=;D6l5zF}dLnKQB9g^jr z{;BVp`(GKq1tN)$>}fuo>xv+Gb|^gH^e3A{jI*^Ga%&pn4L0}-(j=CyblsI=+DVSI zz99IF=nUcxJMg}aV1z)$#FV7P#QtmQ;&s*{%Qrzls!y2syMbzv_6H0+pyQwtpBC0z z$LSBaUqrvY)pliWxkSxir=(?!3$pI%iT_>}99>t1Q56Kbh1uBKD%=B8Ju}hPM_jEn zlbsw39IwELb_}zZTN97FEXq-B7*n@>K-8az7JCj zaK0?%iG~qO@JM-AEZ;7|-vK4cx{2(ocwgSX+iyax_vtp_AZoxq3zZR-pUtLN^`hU% zxOV)93{hQvDNqq8sU~0IL%vx%3k-sq3V=Uy$TQ13 zh?!YJrM#TXRJ|0`OuVd3cuc`Uf++kRysrSZW-dk`4_g~MXI>8h@ZY$+uh)MqGl4;W zi?~<|fHmcnKw|bzW*~M(c1C6faSx~)D_9T(#P4Kk&Z`2E_$S2codDR<#l?Y_iOJpF zozb0*(cZ~|iG_!Uhl!b$iItV%Rf56U)6T`ngTc<3;xCAQU_i{AO`M<(E>L?r&|jEF z#`dl*0$}j#KIp&BXX_v@|1Wqu=YO*B$_JB&kpmM8BQuk&Ez`eiIJ=0uy@LGnK>t?_ zXSLU1A|@3xXM0yC6Ekr)GdmZGe}^zN`Io+ftCP*&?wFb|nc0}xzKS}(T4nhUlakW% zO8?UMivkO%t;641uVnv+qzlyizsdTKv;DR6w>$rSkXQA8;r@s8fBF8m@T-)(JTJuF z#PzS^Nkas{f7$0XwKsv9^8S6v%+11V#A0I1z`@MT#lX&H%F1BG!D+(4X3B16!fIw} zV#aCmZ&1>9&MroFCT4#@y@E4BUvZduxJ*qsxJ((?IE_si*tyM28MxU@Ss0AjxS5TN zP1!hj%((vzLeUBOnw3U2|9+~!piEz(xHwpij5s*B88~@Z%o*6tShyK@OwHLCSXsBR%ET|S%~V~C{$i7blaq~`jfI(+n}d^`hwC4P{>IZVb8>#o#J@0Em>Jnv z|5pDiEWEGIyb^2lSDwBC{Js9_3$K`ynURaVlbXG~jR5#B2+&`e|Js&+EhkeW7bA#~ zi`gqEGb`&WiM*_=YRqiBES$XT+zia@yv+Y5Z*K}U_xyj8{;POE{Qn5K6x8|EzUSXd z|EMTcGsl12{o~dK`gbXTKz|nnuaU_=TyQpWGc*1BoUd5_*fOy+va>LI?H>P3*Z*3F z{$Emo)5yroh|}mb_Uxu64D807uc^SyX2ihF&CSZf$!>1S#%cba=+5@$F78H7W+E1^ zJic=Enx21i1$zH?plJV7+TGIZuPD3{#=y+O@P87<^iPMG{^}Y3a{Qvm#&shBbXyFz5e~tW)`2AnH{+F)*5d;4t;s4F9 z|E24H#K8YZ_uZntf2Tum1%j2+QYrI?MFZ_i{h9UN6`@t#=ohdzbk#bAI|= zhz7AeCrhBUqxCZX`TpfO=|Lg+7I;bCTMFnMhZ~;)^Ri2G{ISZRdltVx9_#} zymxzCN%nkPkl7V~Dikc{dE?#Xy!-GnkdIpM8I|0oY4FvK@ziQv=IU+N1cSCzk)3zF zt;J4)BH3!|)3O1N_vOyZYU_B?V)f%%(=$>mLoEtaBfzw2_*GA|(zdB@$Ff7abmwT^ z!Oy9aXTD~jp5$cJ@8&64 zE$sLZHkqs1C`wFwyezwid9QkJ9~jUrK6K~eqIxb0K0lMa>A2rnpEvAEXsfekdc3Ol((fl(V7L)y zlMUkw3BN$nFHYjC?z}ng$|CJjJz)M^d+<=9^6RT-gU%KSK(M88nHc7WXp6zJ*U1XE zU}yW>jK#gWd&9wbWhSP+HvhxkRW(`1nO^*OXyXFJsSc9WD(>GoKl}6gx}^Ym)Mw@2 zpe1E6Cu37I>$r!1P_m-B2xDlW$bitOagA}!VIghapJ|**Wzgx=@GG*pi;LgK;o$Pl z;+j;@@2F_3L#n_^ak#KUQ?9#Ns$fuUnBBD$XT54yz@pLC^X7;P({%YJdileNQ-ETH z@-en`lH9V&^?iM%D^ZUYdaQct)5_WAru%A#>rv>gJWpcbcR%f_;86HknFdGJdTdvE zF=!G}NzOyZ_WJgi|5-H8)MmK-;jK6y=IPIdr@n*J#=}a(22H8ayPb!D+!nW@DM4c~ z-C3lk)Xv-VZJF2(^2Q<-9ALO)b6ZmC&yLR#(+pDH1hpu#+IrfQb(z(Vqx+Nii~=t> zZNiqjFoKb84$U;Jt5NhRPqDkzhfLmF&p+H(21^tn^IxaYANplV{9~hMBwwAo=*PS%%Y^Z{T}1y= zR6}mDN(NF%a_T~Lp+TLS*2Z@_r^kJvmvyqo0u4nsy1yz`gj3M-qUWH?aWh>u71JJG z!0n2u^LM4|$@%BZ4;Qf3_rYOi$zz_W(&S|{K>ZfV_w&SIfq{W6&!0#V7m zABN|f6OKBidwBYDchhyFgXwo@@siY0Zty!)?6q_rHAcx+9*>3Q+h2zI+M4KEe}xZi zd86K^=lYm8tmstYWtc5u4-)8CdPZxP^TCnCsCMn+XM5XjdR`3KQYOx7v*Z8VF|zyc zjmMt0)OhE-9EQxG0b;QH4SiFmpN@TU|c4_Jw^n zWmR*w8u2A4;pBkDaj2OySlCT&ge=y84%+POYuznHOroJ5GLP=u_%s<*O9z6{+b5r_ zEjBG-&f#~TMvpts4$M5-7elgp~RLxH1FNa1SA7d{2Rjp%^r^An3Yn*179tZfosX4X{F6I2QU(lBx*W91iDy#iB zW0`!$h9o zm!0WHeiqQ;1Vx63Kx?h2D&iIc$>i_+9~Y`SoiFxE{Ev72&Si6-)`gxvzD%s%4$aJP z9`J-7Rbt4NKdD?JXVzUfdf&&|cV)EBxH(_Dzib-t+h-miWp`-Ts2 z2slk3^~+UQ@qAi*0XJ69Uxy4%26^iNZ}O2o^U~mxGvgYABs86cwPqztHeb#a{ck!X zk52FK3x63r4=ING{_%erc-gamxl-)771d_KrPFrvZa~*#DmUwb-cDLvcU|oC{lxRM z-^MKrU((aR`ZdMrCT~bVd33$CYIiQ%bt&7X?x8(foW#|6)`gB~fX9^?#>j#y+eCIZ z-X^Y1Qf$Z2x>1kuN1E;Cpo(u#g{DPE-?M6BW8&xa-rnWJ(*y9Rr0Y@D;9=pVQ?9*w zYFj|-@W{GpG~;K6B>ny4-I(9~6CY;S&uZcwe0yDOdZ%Lz%4}ex8({%)qUwjSz` zV#P{eF9|R|O7w94<$H|xbaxj! zqAmZt<}qFw35PE4lF*XLK3;5E<@@p-KYF-vH=TC4?r^{7@Qa%<(#|8ZO}sexAT9Pf zM}ipM?;0rrZQdMVtVvCV2r-$Np`Omp82bCHyRUNw-8z$RAz3j?k+2^Mvt@S^noLS_ zPI7II+h20DYKDx-4eriU4elQsHq_H9MmWat?E2dnR$$h|1fFgATb@S#oarb_x+8mY z6PISpsN_*N)f$!4>K4`~s*Fu0P#KEC*D^sD`2?=;d-v*L9wGb4-?-Eni|$ed${wt(s`?G-L3j<9{I3?9=>J z^-9~QQh{h9+ou23Xoe?G$IC34oMcmnop!brgB(f%$Q9GsgcBl5i%^(B6xHxUm!Il5 ztH@-+9C^pkNXa@@Y6(sRD3=VN<;X(T8gU^w+NzM!7v%Bn!d*-mqLs}pTR&&x(q=2J z=Mg|93jP{n(#7}knkEr*FLzG^C;qF&G?nsG+!^m8twyEhqt&A6EgNcQmR#2(0(7iL zobq7T2$Q*8^)#xB(mB{b{O_fU4KLD0xyUCG+3ZH;+k8P)`W;zs8@?CGBFVx3{#>5= zGG*`>IyF@gyiLmDw4d%d5c+^)D;fTL5%O}jb^XgCezlReL1lRZ{$-}t1HP^+9zkGWzp7A7;5v0&_Zn)TPmftiXw~^(R8Ot?Vnj`*uUFn zIBk*DhS&xDlnR0?FfnE~*TxLGuAi?SD({}W;}_Hdf9q7~-%m$pUL5`Tc~{@C}CIVCL9^ak)O4aDG_#s2U=u*vBi|Iptr^tDzs3jBq&IQa1ki) zTUMI=d|MP3%mv0Xc2#3zno4O$X+y!MgRt9-DsXZtxa^MFf+^}{kz}oNc>SL5XHK2G z9=UULm~K+_2KvlHPB^WQ0x$;}OHPD3pT7P64O@Y&&?}c1^fpnG!!QFg>?p|`%eiSx|gc~$x6mZ5g2-|);(CS66c6h~fR zOL!lnO+aqZ`;FKzdt;-VrGj*~#OKhL4P7o@6xG)!v@HM*Qd4%kUMQ_b>6u!ecYO z!1`6&84Q5pY8cIlK>Hnu9bAAR4JC4dX$mg=F%WG6k}!FmSAPNJV|-APL{Sfx9AxH( z5uyBWsDF?wUU<;BOJs~yvzIz1;CwXNP~d-sB-HGEbL`Bd`?9nv`1GC0_d1rW<8I&j zq~qfHs5Y|jyOV#%;kj1=_5;4)%jDH=Rba~ub;S0{TWLPbzoL%yBGmF!>Gdr9NghUR z8%>1*juMqJz2!aBnHSTYr^FKONY%^L<`^bcdOmcxVEKbuzu5k(}*n0Gk2UQG!- zr9Zj)-hkyNm?PYr~cs}2?_u1FpZ}_EGKSW!N zQH67qGxqu*1=X2f@^`ukC;nVykDCX;mWsg9Oy`L}cEB1ODLBBG^po4Y`TBV$Q|=A8 z^Z>%)y6n~lZBX*4#0f>xf}|m-y6EwH7frP;Wc`}PK)Wj%)AjUl@vCV%>2H|1xIhPA zYy8T6*vB{U`h)05r$9mz=dd-i;@mc}0JB!Q`t0ZTa@E?Q2;RZi5AjBgkO2jAYo@&$ z9(KUS1HVmiO%{uaMBY&^yfBw`hEmhENz%RrGEiU5>NG2+x>ZA{QsTlgz)yX~p z#xhpjqxM*J?06!Jn4YrytzMg3&2pTc-}U{~L8&4xGFP#oxwYnr0Oo@2@oSdd-8Us6 z2@%BEwP*zh%k&nax^po>D2EMUXd{-btWzj~1pSi?>C3}bnhX?QBh6=tA$qAWU_(Nr zGLtmagiOgiuR5iC;pQmj8tuyvO$JOUwcDuTVfsQDL-zs=^27(%eWs&EYove@8(UsJ z@5dDR0pKV-NaEAhN@fxpFoD{b91mVB-$Y%WbX{0D*y-X+gA}dW?`482$Sh$U{P;G# zrk!t$b_lL02IP}>4do6z7eSC%s5mS}S-*HQj zkW6c#lrs5WvFCh@8$c)(PS-i;(zK95P$+85whAT>=@nkRs{^9Fb&~`1+~o zX9h#-XeBTyy+@2a7~H##r&i)sr%EX=#z_&N3}H5w#F_ zWEcr%I3pkowHqdC-E2feL>f;}Br*g;K`;L}-r#wi5mp(o<*qxLeLV&NKx0>_6eRA(IP&lTU1Q{hbq~wBYo~w437OZfY+!}~)UikRU;Np1bq_#hJD?0FiWsT;AW2vG)*ar2K*C&_$5V-* zJv}H>emw<3wcTm3H4|uUkBye{oTsC=cy##6-iS}L`^zlX+FK}$>kgW+sIVGDb#&$f z3tKc2P$Z3F3rq^8MgYoBajr>AakNM_Xjsetyzl&|LQX0vn*kpQR84!g{XK`d#12Xd z&yEBzB5g`S+0KgKxS~7K_(V(z9){qx%L3d09#I2b9gpEJ#{AyyKeK}wWJF77--$aD zODJ4EqA||LxNujR;CVQ90TCbyEp>>@t78#d+#b1Xb2ASHGs1FjtdAG93PlYd8DAzI zSru$YcS!TR8(Y*?UVnx)mL_t400l9Se(g|y;nK9pkq^KhyVqrB=eL<_x`LeE#xkMX z@g>63sVHSZTMPuYVt`QQLwYOHTy5Yc&;kof8$cVg!^7I;{YJA9UuXC201(REEN2B; zAW(P**biZ4s}P^3kf}5&1)9bIi1R=}Y0l0UUgx*h?!{9&8Vcr^b#;2kmlpMP1ve|+ z+XjrSq9OtF2uR4F8tkBv46$xGNZH0Q5CUonc>UKNm5tirM~x?ZDW*G>4YL^^+Qd{b z;*)vVOw7Z&v-q)k;Eh-$ufiOpWh8(-Xd@)Ok#8u0hhYxkEi5gc`geNxPO?_oe6K>s zb~|?QkeFmvpm0ZkQwt{mP5jC)Cq%4qV6>EmyvQ(lKb8W|RaPp7ePxO<4=P(rTezgA zwJl*7G>hMd=?KZ0L{gdK=AG0C1uXDKpp`0xQ+2;62%PQtmN+7UnFa*_jP0i1!ZQTG zpkU(IJFwuKYmXk^%@;^+OS}L1-f?E?=^=K}xixbr;noP(oeRFojvGDhc(^8ey68vG z3Z54Melau?vBY{!IoVx>^w)~}uI-%D!%Xf|tNC@`sX;WPjmw&r28?(?oQc&p3^P*jv{1f6UtPb2^k5By8t3xsh`k_Mfn4ipYqmY(A$WY%RMTeaNjE5pdhm$}MRo05I zw9oFuj)JP9;TX+~uMEsMsKtQgZ|^Dd=5{oCOYoy0oU6d@ zC3YTW?FHSr0wWXpu(maN(6sXWJimEUzeHt(u_%kJFOUW6tg8^vuyY&$tW9s?jHE1v z$431I3a?0c;JK>AnBvBgWeX22rrhXdN2dS+WtokOB>*GDz+)f?D_n<;Dv>v9sV_<# z2WZr2u7v%?^Er$vfzlC71+H^CHalPIPmdgqF*5T$Sy@y(-&{^KBm2d{c?bF6-v>wvGU<(4v~CJOn|YUx0`el=^_K0G_p{@z}+cx18?X#2~(gHxAnuBL#3 zHxnbKKGsNE*gOph!0t2F4h}*@VMAnk$V^2R>8c*Rnq?2P$oWe!LDoy<+*1utr~CD3 zrMtmH!4w~ps({1?SS>R=>?YIE!rtLZxrpKqY`IBB5K>FIiXjCDMC4;&gXm7$%JRqv zNo=~7YUyX7Xw0dG?3^o45tM);2uccDpz;3zaX^m0s)&Rc5k&-%5S$Pf1UV)TX90p8 zAV7#ogl0Mr@%-;fspex6VnE;oCq}JRHHoU3Lqcq_;r^W;oo>#Kp8fRCwDBzOUtO-Q z{S|*f;}i1b!>vUaA^?wwaD!JX=Wdgm!A5Hp;edzRI1L?-KYH`Ki%u9hT=x&Jbc=mX z{qoXt(qBvcK8uj_h`KpDy8HI)SFf(OPj20Q?duQkyp_0-P3um$lY%}hn8X3j!YQ$+ zNSvM?5rQJz8bZ8Pvvbk~wFX2;$B-a|xrdn*fLm*3MnnW|tyXWfmT*&wGEL?Un);lV z%VjBrh{o+!bEm3q7VZ%d5z{ozPK9Pq1!55aTC2<=k|St-VVj7VMMMbf?o0rJ1I=q4 zwh(4jvq}in1cYOOn8>ClcU~{s?K3xiT+0`uwblN068+%Q2oZ3f!3h?)&6TE$3esP? z4zqr|$KJh`@i@YwPTnT+0$3^A@M3KkPLGvryE(O1!rC-$`o3#roW`wi%{Ij7rG<=y2{b+?=p!P79Lu4|*KD2TV4 zZI|;fZo4j(Qo>q9 z%ySW`S#*mfAS9yQGK^SqK&ad2nQ=`F5QzRFmRTv{<7pOJ9qMpoZHzXSaT{&0vK`Kk zMf~XKj&RttspBbHAu_WNMyrK6C?cXoptUK9xJ7scH4A7`vna(D-O8MavwK_h%V8YP zPM-ilnM6oQh$2E$&P@o8uwYFQ91#j1&W~c+uuTXLWdv)#(A)=QaMIjC`VfV#_AfnW zq=r!KML5EyX|z&6Am)o(+%2U%O;b>e+p$j5YPpDrsg!V^uW@Epm2n(JqfV2xM((O& zaBpL)Q`dEUzZU7L2aDvcPpQwj2eE3Z;fCwe! zQns}fgx6Ln4DN&oQ56vqA~8>rJFrI(D1ii|qA6IJRnr38?d@Lz<@Kc(G%vfwzIJ=0 zed;eU>t7UK@iBM+w=!-|ylmQV)TSeE+wzV{?sYl`NJNNun2O~7%5%@T`?xs`Vi7S1llVN;k~G}ij6lq6 z<8d3##EZ2`BINAK#LAqAGguf1a*zeuIE<86oKl3xOa%p{#R7oUI+fAAF>|RkX*W&V znf zR*QQq77N`!1WRjPn}Y;Q;ch;soI*_QZM!*lH*sfX1F0m*ed<@DT?B(@4*LnvEQ@6q zqVtRx+<_nlymPL1Q7`ZF^#3o zzjgB8PGR7>^$er}s~f?vPhuo+kzYSU6K< z)p@vtNQjFmW^n)jAOJ~3K~xAr0hDn|F=q}=1daf?Rf}*Ya<4OA4dE1+=MjlmQi>2w z8O#7!l4uH&W)Mv?%v!T>cW+oQXR##RA>_$WsF`u(mYl&7jn@!i}^Ye2i(Ufw(Ff$@1kh`;Rgo{WWCwEg}vo^nIK`?I>a3L`H z`F6;;%iWqJsiu^3&fT0K=iEm?bJExhNB6d;$5y6cI1O+3pvD<)Krj=C3Ea#s=+oXJ zf`ZN2NmK4;aj#j~C4yMh+=wp39%r>LB7z4H;RqHeA71O1SMuVSes!5e|H^rQ@%-_$J!<2o4##DCck}q&qxI;FeD-f5pIkiTolwrbAUw{AcRp=R0mOF zg&9~Sbu8R!6AzoB>pOKJ*C6G7rQM42!aabHtN;j15D&nu)q+Gsj35vRQyHgm97-7- zq`6DEU#%sj#6)0rcWcHh%-qaC>}DyaI)%H7aJZ$Ua0D6v^XB0>cU`yiK)4eDh*~FR z6(YCBA`FMuT8CDKI!#2gKt(VR0f`vIN43X73Ry zOoRvuny(cH2Z0*^hI??WEDXv{b8EuX_k9@$B6w?Ng~>fiR<%Iit%Jw{L=Z_SB^F`U zlsjRTXh#pB_No{BRq&Cbx8>ZI3#OM)f`p)0KByVQip(;m?F4=Bq@ssBFL;(c)*Q_0$|J!OV0iQ2pHf2W?>SM&LiAP zIJMxE7n+u=85#~EmW!5k0PJ;~LKaqsRyMV5P>X8P3GQy; zE-HdV0YVb(f`y2jiNOgHpkM^TYlAyriJ2U5^BH}h)p}1v%)MDtRTiIz6`4sz-5nH3 zWtt`y2C)ZN5(`Awth6vvipC(Ml-;IMOUEqiOpS==+Gez3VWL?y3)3{5nzg=LgAk-3 z3Nr!`gqTTm4qPtM4-m5w&x_r|BU%G|9xU@AG##}zP19iG zqwV8&-hcDEzJ0Vz!D-E^oH|G^+Bq?1O0s+zRZw9OY)KWw>BA8{qr2@>7NHpAM`5tp~pDRfWXI2tUAU1PO6hQ&D z*^>)E0RsRAS#yA`)#@#!EJHBoBH~~*Gvbu{6<9>n0Ffl3?qSw|i$>l>L5)HPpl}dKH1);| zC9W)5r(qmV?|B{SWM!(K`>Fp>borMG0HvId!)co)E9WvjesJ@9_ul#DDupaWbP;Jm zqQn{`P6A?gFSV-9ss>Cf?z4uJxX%S2a+>Ru>TU){fF!3*oJ*U^R7d_`EX#v}10aJp zvm}bSk>+9KW+Snvrn&haL~sL$Sw(1mPbeZH;1?C}@GwyFz+4FNY9b&}xA1_Qw+M!G zNg~{831%W87(AHR%)PZ1-fCr$l#{qcAXAXv_hW_Nb$B zZnaW9ogTe)ByIcYpWVCkaRT5eC&6Vp8OQTBjlbrphcLb3OU?=kW@_fRAaNML7H}{HGePx&1S(AMi@;`1mjU)>gjr)WgayP77Uwc; z&yVhPVjyuavl@#7#MDY5!rbY0bBkaESP%pf$q5&;G#7sZ;*>d*JFL!6pTI-=6-f#g z4v5w<*jloZN#hM1>j=*eJpQ@@R>Pgkd7A7pg&ESj0@nuyXX^ zUZN5Ju@IOw5$EO(K!j)A3Q^7dqBeJPQ6&;<^RjV7V^Jc?S&1m%6&V!Ey=R&k2oWF^ zW&tCSgnMZdW^q*FdD96}S`*^ASN(xsn3)smhMC{XJX3kugCup5GN#bhYu8a@p0BvTSMa(4pZ0@S6s>D1;|6uAwbXn@=IHs}B zS#yFgivZ%yBh1X^GDy%2E;u5Z5d|PZ3V(sY^NiKh(WTuV!189W>@+?fso|BOflwU>PJHmXK(G z1#*KX4J>;64SpUyx(H}k!WPKjS5>85RF$hL>t^0(#5w2Nd(Alqjk)$0rwW9TipqO4 z8j+E4BjTKI@3rP*%rVCFG3SvLW?C8AgArk|RGZd@Aek6>|Nh&rCGYxlOLGEa>?Ip9 zZnu#UGwvn^(~4q+n49lvmYGr0%&Jn{rOOu;vMQ@8qDqQv3rLgFWQI~RAW)%7gQ)1T zM~Wz;r~nn`NfuaYEtAli$9Mni5B`t;;qUzC|IH6#()0h% z1<1Ic=iB}MQmbxg^EBqyxy3 z3K}FMGIQHp)v79&a0CC z3NhU@vd3g#mUmrrlZwv8d9z?_kciZJttXi4#K zClM8urK*q#l$#i~Dn=FrWApPkwr%v5$u5=%Rk1!IR`dIBzK-MdwvP_~I(FNh#rHEr zY#YAel#B^b)GHxS0Ijl@hfB3tC)k2yW<*f?)3K_w<4U#zdx@y2il|t}2Z*4m)Vu>) zMTtm8WoEJ=E*ZP6ZS`7xW2(w+u!{1*s1kQX{)_+RzyEjsqrZ3i@bCV%UVyiczn;fO zsn=irtAG6RC;#MG&++^_v3()i2i=~t%xsuoam5IQ0y2h(Xv9gf-9+HpemErEydvE_ zb9PnG7o+dMjLz~9bwWgihhLxqS)5sOHYz72|i znPgiaIX!JkVv5m(pO`>|~s zp=w*iDUd{=C72|D@eb|k-?`uKeG|+FNwP$&3ak`a#XZ}x8U&m|5os`}szkMV*#5a7 zRx@>P$+D@c5DjKDP=uDyDaQVjO%NZy|J{G^-~HXc|K9@JZ{G#TI5Up({_*(sk3W9- zi<_T5o^1axp8p1XFIr{wUI?JFN<ZuJ1!J4XNm}`thY-5C^3;z2ZhOuyxqoe+({X3s!FCS$*L$33P!Xi ze-#J?hP!Rb$~g~#RR#)XK&6?-JOtWAq0O8Xc}7-Bu@E2&X%K@Jvp9#zZepl2S)`ap zl$*Pef`mXtbtIvpL*@SRX}-M-*D;3JD5}s^cftsT%Ghq10T>v7Mg}QV$c5nm=%2Id zJWrCosHSadtt)c^B=Wr5Z~$47MR$jmin35lRaG@W0I6P8Qy^hBY`Cgwugx@D+>_NM z1WEPXAceDX?%T^RfAJ6g{r~j8{Mo<#pZxY+fO&t(xYvCB`j@|l{LXH}zW6!zpQ!C( z8?#iUDj@|h0TZgIxib?`$KF;@svRj-p|7e^RMjeJ3aFX6J0P)aW&5o6w4i(+C<>^m zk)di;OQ=hd5vrP1!@a5iNy<568#lFGH8PVVnK93nwy-kM%SS;<)9XbYVlx6FP`6Ea zLKUdfTC}cONg;0TZJ8*<=9`Epia?$R!Q*(dv5jHvH&;v>8z==;)hbd9BBg>zaW@fV z#{C8JK8E^mh`=0h(a~knJnm+WnpH66HZ*2-@TI_Ybn?X7*VKfccAHZ(i%d~@01q?f zW*+k{*u@MmQIp1DMN5_qu(@YlPY)E)jOn|XdGFDoH1DK(bjTvBx|kaKE#xNJQx^`*Up{pu37e#G0{g3PBgyYSs}5 zDinyhYQz6jNKb9dy=OIxnG4_RnWzFpG80GtYaSZ>TA#W;WR~o1yUDu(ldWov?)_e7Agaqm4?Jfjh`1;YkmWh%foEZl}clR;6 zTPuLl+zC17jF=>aqM`)HzWKJRnw$AHR7_0^jLNziJZX4Z9JF<3)}!2#TthO6WN=6J{ebzPQ~=bk2!N z#(9r(jD|a@WJM6Q$(a;vPapjD;h8>@yl&DiHMNCB?5N0FUB3f)m7wKuR z7624`SI$r~HA4|aGi^c(s+W8#psFTdutd#uD|-r`xAFQ1|KuP2hyU4s{hKsv@xO8g z0C3(vefjdupKfE*v5W5or7UV-$LxscezbvzE)W-8ht+eajLa$lCg&JKfEfu;K!rqP zW73f+B02^Goq00?BJNsM?xyg}VD|*>{Z$AQ;bVYsZ$*{9yu9ex_H8rY=6SEGnB`-r zDWf2gL9kX%mRDt-0x>6xS!gNltp$j|Qs;Of0*%mp$-M8VR=b|Ny0BG_O^W(GynyfT;t%6U$AsCA2)k9@77bIwWb z+g_3tHO59Vz%j-m6m`9ef(Qtxslc{6Y9J$>i{Gzs5!i8sjuQ+(_!{sm=Uu_OyQ-Y$%q$TlF@`r(p8Gg`2Rg{z}&)LG2BI5hL- z4=xIVh`Q~!eT{irWDXJZqQ#5AnA!2HZx@&3MciGA!cs^9QS9Z^=XtV9T3y`X2QtPm z^X38w>VAK1hgw2Jdz>j`YXr9D5)%sXtY%WG>$Z)jZTrIXNo5B{i9t<$F9?|PctK7V zm^7=WPzf?(wq~s&GC~R{C`Ae^7)&dN%4nKWoHfswcT_@^vT;1=?Wg1E=eB)8XjMhb zIcHX_k3h~jTP-ajx7)2-rfW>wWCd~WS6~m2pfmG4&UqdYvo|1A23UfO<1Q6d+1P*c zrbHxTRwS!f9jx5URL$KNyQD)~MiWu{JIt&(XJ&MVVm_!wb&ip5U;X-z{uwi54k`xhynyqM~;_gt12vt+`6zOup0?bTQ9b{CIqGp2C8TX{@ zF@6`d;UFqQWf=fMah~Vc_P!yiZPCLSb04EOjn;Z`md$-=&D6X*%WWImCLts*0TjgT zW)`QN=QMF)HLyby5hbmKvRaWDkRjVoY8LV&^FGsxV|!||^X?iA0thoJDI$TpWSEqS z09JFFIfW`4E0}ji5FsK|*X_CVCeI&|S~DU;MReQLM`hk_H+PQ+R5hB}aUml5`A4t~ zxJ0zMP7&1?;3{RIiej0oKonZkLfZ~RoaeB;fgVvKB<958?UBM6F&wTw%uAAhiS}1F zwM7^0O&>&&DpWyM$(lz9$GC0#AN<}w{F{I0zmVV5ru)C@1(>hj{ptVtPlqUE5M-5B z*)WQM^vPVjva|IGb<}Avuj61QBB-7NEVBkBuw;-Q%xRomaZ>--x_plM_Dvb zO3d?g_Z}CBz{kjl%!ruhah9%k&`=B+4aqgp-+idsJf{eonnkLJ=>QT1sY(RFDpvF0 zGRvih+zR!g>Gpx=M=+NvdYVFZ;3{~hAP&$Q1tTI)55?`x<%JqaP z0%3{B%<$HQRb@m2#bUaR4I-+lkYde@b~-Y5%T(2--SC zk_C4IRHPLgrk4i-No}+WuI81^EAFdh>fQslnMtIIi#mqy+de-@9xsAvf-3sHRe?33 z0E9v;y_HHD5fBASgeuc2DP`PEC1xg4#?8hDZXf*lr^m}no%i8BMT<;|mH>|t9wTCm zF*DnFnyik&03zlXW7|e=Wa=5#iqNK=C9<~`Kq||6xgSg=Mc5?s5}s$65kQepBWatd z+O;8&Sw$3J1t}7$P-*%Q7FI-6A+;m{nmdm}Du6N7>f;~3ef;*r@BFRbf(tN@m+!y% zB_QU*$0#9TV;h+XqWQ^yDWn*Te6(C#4ws7dCFs$5Rp&>N3P8|olvW${vFjed%z~Af zS!HUODOAWBmSwF%MGcj8zrVS=iv9d&eO)j1y zQqmP#x?7&enWZ^&)$d~r0fE|gk4UO^?LM~W-n`T+#^#(kkIYcTdENo+`@TRYh?#fK z)ut@{VY?5m>Y1=4t3y6n5CTZ1GJq5rkMY?WEgLct#mbC+bWM|MtFSho5NS3Su8N?l zpj5M(%lC{dNU8eQfA%kaJ1&4?#{DbPP1LeTHL;;GWj9tj3+ujWA*Wf*;%eWN%yjo{j5AV1BIdsD=Q$(N-AS0))6-M` zv9WFEc@#^<0XgT~Ro{IrzMGPcx7Q;wBdP7pCPILbm8ohXP&0z(3>9;`?LXOG^PVx) zhS)AX1Qfc+WMSJ}L_uQSNu@wtn0JvwMW9~oX(RwkG88nkc^p}F+Xm1HP%~%iDDL;RARj*R{k`@UzUnE~ZK`qv~Hm44jwt3`&YRWyI3ms^&!Fs@QW+=q@KS8;!- zprRtyI~5g$e3nVCU5e@<2J_j_Gb7FEs2R$8u^v01k6*u6;gA?8$5-=cWVC`et1O8>3%JbUPC=3@*( zq06yL)wli0$EG&a2Gk-5F&noK-+uBt6NT_2J;2F` zDeZhF?&?r=AAj)A{~@lq!H+rvynO#9@)Pt{AhQa*>4>fk6@)d5GoxIUMAdp65BRdX zC{^!aS!Ae~s~n0Z-@O>rZob}}NW%$ce$Ht=R5fP?JN8$^R70&Bhk4F- zv@n8retH&>^E}V{-7d05%U}BPu&kuNDd|pwl-un&D_=f+@0*Ks-me)^1<~8~G%~_` z&lFZrWZO4^o#*K;?pvObpqRU9){*l~SY-5h79Aof%#3NQZR{j%47X9_ahzk@hYtYm zPO{k|5#jFO>=poxr4^&46cm7SMnnQ^?C5ctFJ<9V{RM>zV~i1j8zderB!r!-rXS zwQ5G87akhB%&ZEN(KoGs=c1!Fq~_|Lr=VHi%D8_u-@Y2p|JINC0x-_+zx+coM4;vg zG2cafm`fHIOT;8nU8R_bh(EX}01M5gH*Z#t0%~R=l@+MExI+-ti0Czm7xkVR+*<$u zAOJ~3K~!y1?cPzU{p`txTur-VrmA(FV5Y@7kJEjqYGrTgjcwbSD{&n6r>EzxjGv#M z=bRDoxTs`-3F$eMws6@@GENnrImdPbHM5#dbALNTW$c?8U^61kHWA(SEh3~#dC|yZ zdlW)?zyKg4V5U|qs5`VdAF+#iYik4$x$U>(JTHJB>~$DsEir`3Z9qc0EF_&( z88OYgXDNMu8qx*LOjw0#rHtWP-UKKLVv?DcFr)Dz%`4CMoUyXV>^38_{bsOjql$CR z{#u(GOlKqnY8J$d{!dkL&w2mN7{~n;N}&4q^`HJ@&_x95>d&w-BSpkb+lAmlcm=9w zL{_0vSV%}Ox&?cosI?4SK&=#%P?ahf^IliFAR}V-+3j#uf&^jOX_#zpT;`mp+K2bj zlsM;Y?3<6id+vVQwtbBL{(39v+uLikPSTvBqMli*HpXbo9Xy(SnKHiagFYA{)T%>X}tSFi#UGgeaA^i!eyBh@z^sM>Z=(U^-g5 zus=N);A6BZWzO@M_hcqCDcO?Tm1&ce%k_v^nKkG6_QuL$iJO>~;8BY%X}<_iDM;HU zr1!HDRTWj)A*g!;RTH#t9EO>jF_W2#u%01RTIHfZWyYLGRfy0`+Lw-^O#^Aoht?S& zBP!;Py##uD`B=xRLPQO23tw+cgse*9fdk+Ie;Oxn73(!HyefN;5s`%<+pOp%5ZwmG zadI2(9zii{*r+3Sw*>EI@49443m#$9CC>BQ_ubu(h{)`2gg{pd5wY*v>&t7$LZF_W zp5}SZi-WCVXahmCvRsQjRAywDS$F5801k?~w>8l1b`!yVyXB0$=m*y7;C5soOsy!b z_Y_e;+ta^4h=^zb23x@FnyWOmbA3#*iV>kYs@e^Ewl$oYJ$BFFDk-0C&r#erdlc@- z8qJwQb(_VqsuDHPp_CpCRu!taqWf}!h(-e1Go}i~B7NAhm@|_Fu=2egttZk@-OW^x z^Dbg&BS1k$%y&)pkMsh3`|CeP9A%l5vFuDJf|v&cEY`AdmIqs5#>^$^T|d`FUy%!# zn{zgAfh`dPz?>7Tk_7~9W<3R7vm4LR8?g#GtW7mRKco5 zRSHQ~WJAeS)uQZe+f;S9XO@mdScvAXiF63N_Lo7`U^{27rB$RrYMxyPE{dp>Ex@9u ziz{RZ`a7s@j3VOEVfP&<5mRxujG0+#PKHvMfzIJS@(WP;QE{{n6e%hyYoH@&U?+Q4 zx~7coo|T;&d!Sy61M!)(XgB~7wwV>vO<9QZ?7y{bTUDv8F`0;( z0mSWgJC5V=++SW^ZeKi`Sw^VJ+w0ryc2j~G71V*8sbDn3s4A+WIy3jNRc14adJJdo zs%kKbfb8+J`v9`1ORCxfU^eUz9YYJuD_Ay4;`>jzBI|^s0`s0=NipW(qerVIf{Z(u zW_HZEncQDr#uycG9LMc;+n%04nKR5N!ZvY%z|2H2=gdr1sHmw&NIGSpoI64oQpxRf(vU-L-D?B3AIh1X~nfTZD)uIA))sh}mQfqYf=) zl|egU{-}F^?|%J)ZY9&Z0uLF*0Iak>=ZPzjODer<SuA zRZMpK6Z1IF`!G|Lj~_pN`|Yo&s#l_|GjClL>(Z+KTW8Z$h4^=f+4T!R$++0P@^SEqI8oKG# z7`knHQ6SlQme6nS0?Ua}OKgG;>icTHYd)bi#SC7pLWKuA0&tt!t_-((r`x)mFG`T-LJ^65GF|#5SQjsY3$VrHpp`H3w zecO(CW_2@b+3W#iG`@}AWhSQPqM1xG$zt~H9b@0duIdmK-Be74%9A+@6zDLQN>-ZK z*q+Qb)2))j_x3evC-a_7i5RoB(R0QLRaI{_vkx~j1#=#8PG%x6qZDaxfwrnCg4fAZ zQF8_JWJOgLs)SKBv$~I$i|Sm>!r2s1SQhd(!3py5i?ob zw#~%O^N7rr(mxJLHKV;^So4j`%^=puZ#x|=)~dT)+WaN5Csp;rxEAwbbB#GO)6CU9 z?q@Lp6|%j=1k$T%nq^S1b}DL0;p5e8+rYz|t-7X{N&;*SLeDX(D%)`Q2nbBww>_$|N>#RP zYergg*-e{DFfIa8d$pHAz%mmRLE$!rk{Q!fT=aodsu=}p>SL(c!;eSawMt#`H+>*j zknXPY`f~saOcj`lDFh_~(`7MIRn74vX=VT~*8y`IW~QcMn!PwpwU>o;ceIF!i=g#B zhvT84Y2t@k|0(PI+^-Dp4)EWgRMtzBz9B1oRILI0V<6ltQC5H4Dw>TSYaw`!6nSdt`3(I4KGk=G1HqVm1I^$ zWmE(*BWBDqb3w~l)z;4V%w$$POrXG~7b)m!rj|t=J~NKD*W>NZo@TdCe@qcp&PPZa z+vtn>UUs;8K7qUUkO4sCteVnFv`8sRF$5L9_vd&iSh2Zj7mEf*wzV?25CMS* zD$bbqvzJ88Gc%fhc^xcX9X1JOw)JO|y)}cZ*71NuR`np|@#FED9?13e^MlmcZhfmZ zY8#u+oY22;OsaEL=fkYJMwxtY@A}wZZZxf%H>N1fAkSm|7%#x_{U6=G`Nh|N_6v!( zVm7o*04#lH4E7Mty>I*<*W*2nq`R?soSi0Q*$WrRTvJe(x%4zXqX(3NQgF^wfNRUN zlW6ks!#Cye3W*}hOdw^Z4Ow&~W1gs-=W!l)R9X9dRG3mhX58Oi=XsJGV>CCe&!>u1 z#UjC1sA^_JoZIHItQIt{A06|m*6Pv+CFT)uS#=&q57GahGBG z`&(4)N6!aD@yHbothKuG{SOf#gjHanj<3J`!^-o=bpeh~Uw-pvzhB4K-+%Qd?skE_ zO&ZYUgOeJ+~fYH(uuTb z%sm;G=GZ(=SfjD~e(SH>oxpYS-b)?O*K$TYBx4KUS`odE?|O@MCFb^E?UlnF<{lXT zUs^Y@A|TlQ!;c{NJ{ms$V#~$JQ!&5!^IyFD`uE?rH$U(Nm~Y>F{b#?&`OWJ$e}r?XlE)z5mK2kS%yBao>SCfRJ3JSyg9&V z{t&m@&9)upbFNIT>gv`rzB7)9>88mV`)%8wvM?j-VOY0Z*i6+8QklK^SO8m30>u({ zs8J2VWr<>E1>Klo?AsUvy~=7%xdbs-Os^hyu^HX?+(T zLQ{kK%Tf6H=l}fp=8r4mM{xmI`Q2B4g!shx_~kGE2#j8?AlH)+{p67X<$8mpcf>lKLjl@MMbyu_HHLwhHh2W!gUR0lknO5n$ zKIuDr{Nlquc#?dy+Qmh)W5#5@<@x=`um06vcM|yjbOG+4zRb6;5#N6MApd=z+wsuMP{&O z<`mF+;d3{#V8qOMMrI#7QD%i|U)us|xIt>pLoU6DTs12wq%_mGxkIL(Sv1?WH9Nl5 z2%Ygn%v9fAU$b>sxYmC(fAu)K2k>Q#!*|`0EODslwa3l{hLW5C1~T4Zh^wA_jFTUZ z*=A$0NYvWX#nk&G_h)K6s$2OhLozGLigS9~#h7l}-mAnGNkynqWU@di#j1dJ9G1sT zuBw(IHEeYSyU&;@7tE!Pdbk;{kB@<(pceeiV0?P{^sDc`{^N?{2fhHTd3^en@b&)k z)wjR?*Wdw2lm#p(gcPeI-{m_~i|fnJilN8Uy<<45gw!=7v*BA8*_o71>elF@w5KB3 zAk9!w1uH|yRpB$QnObJ1sEo0XvCRk{W83!vO)Mjh_tr49){JOA97UiF z#a8sHCR0;s4n#e$%SUhX{wBP`dH5b6dbA4bnNZM{!;3s!s6ZxQrlTt2_=NcM^4*{Q zz!%_r`RaW8Hsd&6KjwTB@SH_^vhjtCTZu)p8M!_f05b3QduHJs4)9P9eYR+7mIUOT zXH$Pq(p25`Km{y{n!2;4(~PxK6kVD>t0DWD>b8As&VMrsXrklePdCj$>;M(r&XGdPlrnk{~0)bywIL+7Oz*{uab-t zg!ZUI?Ks}N;`QUNGXEMOQU5oE|G0npRi2+def!nR$8Y0&Q;{kgeuEBGstw{{+7m#J zgmH~R*S)7)$x2nT7JxR! zSQxyDyG1kyb8({DmG%NCi-rDgRoNm3tcsijd$o=ft3pVrl3{us?#INlw=6er%1np5 zT)nS8tk~BeqxXeXZ!l@J>rosFSvdvQOi2Cp(|0P2^HZEJ_Vn`~CIhhMeEXj9TIaX- z*RMp=Y}}qcn6|~23yf9T3Or;x1VdCz+aI7J3etump<*J|meHzay^p9M@Xog|TYG^_BPY;Xy8i-4zvs}XVuqlY zDJ1d~23R27AG+@o(J_1* zV%H{&s)roA!(_YU_J$U+hTHJw_lL9)3Az@?Re{TYbe^ZmvRix1bUr(Wjt!zdwzlc^ zHU0U#mDS81IQrtfU`42ELr;MST6KP&$IHu$nYJp;RL2-?OF^tr(Qt19u-fu7J?Ht* zo3Cb(s47z%?z(n>B$+6-dw{79H*>u9`NDV;PEiFEW>_@%D}&`! z8NJYfms;gL^XG9Z9vT1f>-T`#W$hN7B`dQsgu*&2Pa#+Z_gd5=0>&&6LMr0C-G)Hh zkTEi3HEIe`Q!lCFqWG&)RJ)MsZ>{~(9zcz$oO3ojqGGC-j+t;9H6CMBHnUQp?FPO$ zze@>e2Fj3k2+6u^`@Wl5uMS|%oTpT1J5e#g%ACx?`j<+?E@EgtC>~}?RyW9|)=%^8 zAUr;bXj>M zmK`A$Sb4&pR4j{Q=*6H~&nq8flA`H))(wLR&>kcYE=p8^G}U=TsX)n0Whz1O^+Yp8 z6-E&@5j1mVOtU9#=UQRLGEEVcBGo<5s3Ns>n>}Qf_cI!jZByE#TQNqW5*T99I&eGi(|$!n?PY65^o=pb@NL=WaatBtc>G4Uzi1m`vy^BO)9(0hag!^VgWek?Dc~^J6srOPji5_yy`k9 ztK=PU)+LIH_S>2f5HeG+42fHsJ+@mhn*-hEiJ66p^SlF7F2WJ6g<@H2>fRP~eAj(F ztP1-7`WUSpF&!;B>6IAQ8G`%h0U3d}x3{;qw~oY_$;(r*tCPAyKxW#42ffXf$Jn~+ zn{!r%EbEi#8mx`;S=Zz@BU_@oRF+aj$Y(|A177So-P6<4I}WU7L^nE_(Ku31b~94d zRzY&@{Lqe zR_VogsF&JJAn>L@i(#2ls@P>ZxmFEylJ3va6+c#gE}&FVC}Q#$#IDK*sLZ*@n>Hh6 zaS#G+k9||8sS5A+ySIVLd2HJbHGnRfnHlrQ!$7GrK~}9!LWM=ZMNynmUA2@HrJzp( zYEk8`W(sue5tkyP1v+G=xo@ML?M{)@9;dwP-Y7WY%$nv~8~%U9Al;Edz# z`(OR!XaAlk2$3J81ezHt$a$=oBLI?hs#zA)cJndMR25OpDnO3oY(J?nM)U}&vO$u} zSo!qP8l&1Y&dhlElZlF!xw~vIkvUK8S?@ZmXhV@nwiyTLIjvnO+-gnr(X+53 z*OHD)zBK1tF2-Coa#f{n%~`tKd-z__*5h7+3Ntg=w#ze3BD0-$6TQw%E2q1=Xz$Yo z(p^Y=`t;o@`Ff#Urd&9VszrN)vMQ63WG|y`6>bgHhp+!TCD+=A(1MZ&2t!_ut3YHj zxdyuH;}mo4QSL>QnNv{O)YA+TK($DNiYTjZRzFByRMTsQvxvJZMl{ZrwP+*Fj1rOk zw)bJEg248DN6oBg@4W|L6_qv5+ikBZCFQTJ2KqN#fHB4tiFsbr7*%N$dkQviwRBy+ zskn&D^G-Ggc-iH#RyULxZp$*E)xnV$f3V|mv1wlr8RnumkGr64Gx`~m#j$PUHX^d} zG(!6R-CQyzyDCy-Lt5~mI68TvC*7l!V z(+;5?=Xu*UqM$nG>~j#LM6mKv6g7hw4`)n3RoqM)G!O!CLzauGS}&`kcG_$BDAuya z&miM9WiLLQIBI>Xm1`Yx=CYK`GVNu7)v%JRiY0|rkt!_G46FoFyOCA*vCG(`yd_B; z0WzB#yE>dMe$L})##D9CR%w)hq;CVdn1!oUDu@b-(TXT}*g-G$w3z(-XFr{&)=B>W z7l2^0Y-m-pQpL<{?X?3n7p81_ZKW1fZ!udR7adN(+!_RQH)hNV)z-M=He6VY*#?D; z{)en&Xe!6s-8g%YqMd4?Nuqr0PdutA&LX^2UkOU&Yt>NSsCLc(<#xM?NY%_tK$qjg zQV%aRS+|watRGo`{WTo@JdS-#L7P_)GtTH`tUWv}Gs`)*ZBrZUde%T{#F-hY)|Taf zsS;UYFwsN-s=j;Otdb&?^C6e&!77EO(#AyZGC*od=1B^xtrz8CFMfUVFw-6}7J>Cb z7q@{CV6q4)CQzx&Ugp?qPf3Z$MlVH4`ekZ~ho8z{5EHX2)@5Z}Rj#`4`$HL99h1n& zw(wd)sLM^OdmjGkSHJxE-}>8x{PkI-|G#DcA}bwiPKrQPOrRnLWS{9?`j^!b#D#D4 zFv!ei#9EtE*}*unchh=RZJV2~jM-l3YYycmAQ-6H+$yq3x>z<%3Q_S*8OS5&WChAs z5bVHH5LV?m{0YOdQ;>pHJ`89mr7wWAvrW@x%&f`u{fQecd}o@#CH66GSVKj6LkCnV zlUdugANTtMCjU&SI?t-Kru1p+AFD~tO~F@IM5t`d*_lZedUM1zSZq_7Rra`h%;=`M za`uTQAB_Kp*VPi9*D_V55-L}Qa_wP(7^0ZQA?Vu2Nv z)l!FRkN0PkWKe_c^PF2{7L{gt#P(jbkcFUt|yh{T+Tg@w)hk}#y8 z1ar-Hi`&jBt@qxSODK)zR{l~wnMspbBAcnh2z!TW4bQOpyI2?GM(M)YRhXHWw|&bj zqPk&j|DAG*l|1J7tD=N6yjW`*P!XS)CqBB41~mw(pQp&uB{{#8ax!9gSOv+5aX3Ex zP+>SM%k`W6jM%7_d`PFklLeGPfebLsH%Py1kyHw&jEt&iFte8mK{#v_0w5AB!lV}} z1kUHPyOC4ZMocVeInpERr>-!vJ9uOo%NmW^nq$AG@=*&><=`o6LP{C7oxoC>HvuzP zMF6qkkpxi?ZTr@mXEw7b6oSsLiY{B83ktmKV}=aoM#-u=cK6tO>r||1kwlv9%_cAl=Qzp!CV*%1iv=5^B^UsAv;mkz%6YVK4C@%Xnyo z6Ol)hw76bGwP|aeXvUB(Q9TAtXEj}F>Gc4d7&aDFnPWlGdIXBLWnERDYclXzP=wqZuj-71xZHxWPG}6a>`$Q$=DpKO< zR=~21+_vrF&Uk>S2$%L{jCx)nX<9TheHbO#%$VfEJIUCG2v?A{K0LK0^LdsdW(D~1 z)8{H(wSBM)Ky@__%uhgtWH?C(!nOB`ER{$Zbl&-ek}9kIFsFNX0zN#}-HFlOFHF`4 zu4@Y)F-~FId|jKw2Y^C3l$`y{oU$Aoi?)MkqxnZQkX{D{o_vm^^s#LhvQW5L#291u z7zJpn+334X+D%GPR+Xsbn<)VpvjInRX1l8z$Mv`j8)S4Ctqhi%& z0}x?lmP{1kG%1kvYMAE9JVTTo#L~1MQ2DieZv=$dc6Qs`_K8$*C$}m?qXgX%73-r2 zDy&;1hjTdjAUl%}@*TNT4$NlXygkIQ@+~ys)~j$w51ysVXE!p+he86$Ovyw9J$&x} z@Fk&m)S}8N@vadUM9vffYNAAd$gjRYkF{=qzs|}JwNwScvo)!Keck{@i zc|Lq%YR3Nn2#N^E+^{hV2o+A7Bcsb-5$U^yZOEP8QG#m{LQ;nJH1b{bI#k0N_k)DH z2g>M+beg@&^3sMIQ)ufG88Y7s*<%;3c__^wd+lJEW-RDEe)79&pU4G4MPvARv%a*Z zTGgC%H`;mLBLdUa4j|1&M6@PEvF)3MXTox{`JhO*5##Kq`;0-C=D_)MI$Spfv?)_6 z)7Z`)=9FfmT3XYBT_4{f6e2*Lm*z2MMj`6L$Q)tkv~vx$DWj>@Ylg5836UhhtuEt{ z;Y)8($56sUUzh>6Nwf`jcT<(j2#*K4#0-N0#mt|zis@@AvSI*<^!nx#P;TwMUa?k7 z^8;M~($;<7xw7*)X`cxu2-=$5Mc1heQm$uM-OJZy$w*JDHtoLel_MzlHZE;2cdJ>o zs?NtNz(fi*-w~CriR)W1LX#2G>mk6?-+Uk9@Y zw39BZ3m{2c;Z|WTG*!(>Xl~A=uso{DA{30Qd)=sc+j;B{RoV0T99gIKt&qEyAGu_D zSwuR}h&g>vKZWmJ*4@6gzE&)+5Gh_FAfj-Wq69e?Vfj8E|TSN$mOc4Qdz1;#7IaELy9(Jibp_a$>YZV4-j6swhSq+|uBuZ`Clzp6i zocGhI1n%0}vNQoPC~f$5vh%IbF7U9;_ATodLLHPM!^n-3IEgbj9O0Z!Il?V$OCK3~ z`kpb%&^(duEYiVk7LQe{m{CYFWmXY)tHxhux{Zt&`*_IE9u9}zg~&6*eb9UmI1yRd zxi8%YVa}ZQL7MxMyl}%RrpU~!tv`MKW0wBGo&Xdfx~eRrAm5diLEnO!XRWWnXrd9h zG)=ioyD}m#9o(cOY`cjFrIC*qyNF6suvYvYgyYo}M3aIu7%@$?M1)8VVaH?{j#o1njV14WWEqY;*+3bvrNFQOR z99w#d9?%a^orK8NiG^q&g_5gSP8mL&wMk8!!YYfMWb+S;>ZLs*gTi6PWDHJBd05f) z2ujklT}L=^vT#z`#ahP|ry2uGC+^5Vx-uah+?WdSEh2^Oic4NPFF@F&aMWC{o`ImE zSgQzp&soCE1UV7`unJ2;dHvJ6BLBGyfK`_zm>3z-k~;;*z7v9^Bh$k~#K{YP^lu}Zs=<>0w{4CNiP zBxDbAg)pakkT6>7hp?UYk?E-`kzeX#Nr|wr-G^!yX;g<3OG;O1H53#Exe*MIq$C!w zRO5tI_I*!~_Qr(tY)!@($W&1Zvuz_cAynRm(U@BjXHsjjk9`|wRgLffF@#vk5)>2+ zLWbEn&i7$sjFFJG93ahO(xkPuKym2Z(;pJ7nHeKlIBZL^%FR)xi27V;R3Ow5p6)>j znc#9ycMoo>wywHtL0)^;Oy4$&NCYPU_VDyr=4`Xrtj5xoR$m=G0E6D^;!$O@A6}xW zr}n_DVCIZSq+H&VK_t_lmD+kgJmx>;`R89yiqFt>g|0l#!JMKD_U(?CV(i?ZdSK-- zoIz6!^d9qPLY^~=NJH-?aL(}X;U}X_NLDNd8(SB+ZBo*ra8%4JA##wzqpPPsy1IJw z)$jfx{Eg-y41r8K1Ze`6Dd?>q;dk!4#Wpb%K{?$`lwr1qW3-;C4WRT4a)wMXUF?(w zT_%u(g_BA{@9s-q>N+n5a@Y_iq`U8wLpYfJH*+=0) z07Dx{JGX^cA$qofwp@t3a5Iz%W*&ObdR8;5lsPJj8Hz9EbG;muzkWg>EAtmYnIWRv zb{1(lTRfrMXS^${-ZN_>$p!pK^y4##e#i>|+}5k7q({iTN+ZU;6-dB9;pZ~?D zfA-&g`j^|^|IPn=`u1;H?i?o-rPe$}8>b^sGe!4%qqK4_&pKflY3d_LzMVbWBHCHz zH6X&2!PW5e9avaeriUd8PzR)2MtGTQJZ>OlEm0HZoCI zn4iIrzL0y`AV2$dm$p$Ri83{omJ}4u+(h7Mh2EcBz4>lblYfsWIA7Mlf)ErAszwSj zvl8{m>S?}~*N6U4hjN?~qWTZDY1Xxa$dfe1hCx8C}S$cH5*z{Cua<#6-l zlfS(A=o2h2^!ihg_SgUY^S}Qaee?OhReMWukA9SXXsUxfL&qMv+;F&VrwET2bH^U+ zAb^Rra(zCw@FA^p>qKxX4JrgOb{BD?@Ue#{NQH$dYzziwy#`#Klnf8sk?w9D`y7;$ zM944^ZeTP{PfvG2F$$>+xiNx>$hX+fWalu;Bybbyt#^+-B0!O8Ofo~U7bZ_8Rr5XT z0;oa>I3qwj*X&V%Sps=wii;b<+ zW=Vx~4?r)5*&MrN&OY?a?&d?#uy!eOA-SiBxCiUv8BCHCa%^^rS0jSvI3f5N(?uGRP>{EUhi86AO80Ps(>JrlqAVrnnqHPXE?{c zpSB>@-e>zSlZZ+B;pQV=AD_KHfAn!hP4)2XFaMkW>8q=!pa1-S@wnqSk*HaK)e@-- zh*!bchwsIE^4T^DB~YZ7=N&A_Fn8>`wx*3EYl&C)s-%)jdkANQMMhc`tET4J#{j$_ zjTGUwhYuEv2+Z<6t1g&17blR#1*2DDR9yu^KKy+0G0Y;F8A=7Bs!kO$-4Ze9o7E4- z)RY29lv4xmv^x`E81qe(km;E$(g{q$qHA!ANMR-k$yBKdepb4rkU*I}9bVxC53A+- zBBF6ArPZoiwYfWUCCr5=D=C$ks{F7yF7wC(;4$hl>I*{6HYzNg6A{|su^yg(_zNJC z+wnT!+v&cEh^{1Sl0*f%>-2(8me}z<>-T5pAA|d@i!K~zClMLTZ zV>|2d$OM24a(MKE>yQ4TJ^J|i$qyfW^wW1=_wmIK{`!CL^xypQe~o=~@;wRIJ#*WQ z4{PHiFV~9Aw|mU&yGNR8BMM5d@O4ygGs3o!&e{a%l{*TzCR*6zba+^LR-%anLX0nMDXCkVQ zY4|40l$AoC73oaGe94K{l!z!zQ8V8y2?=6eSQ@vZ10zWyn@DCAo4PJN7=Ai8H9p^` zpGMKME;v1A58p(kF_!|xVlYUxn;DV12Ux-!35c?2wFQOCc~!c-OK6f%(67k!5ll`{ zU~`5 zLL>=5!~$|p4v(ExZS3RzuJ;AJE{CVjfB3JT{qV1^pM8S<5zF!i1FC-gZuQx3mGuph&lHkFX2y$ECKg%;Xjsh-67XJf)I3wew>LD9tRx`?3U! zr!b@*f6^C$?b~K<0EG`>1|h42BziemN|Cn;P(OoAz=cH*a1(9X4#cYyU;f-80MgF= zD1GJDgNR(OZq~Oizdpa+847qH=4~z=#1Z?p-RknlGi;2*x;la(^RkC!ju{p90MEsJ zA@oWyUm}&LrD+il`=gvWcuB zJ-LarO29IUyAd?QjVtOQfD#cn!%5n)>w&iO82cPd5MPq^@Ni~QT}9dqVrDWj(f~0V zB8`}j#~bQPknSUi1RzF$hD9p()Foxv1LnqhTn$bG2uI6h zJ@mu6`6dZ?k`JQobb8HLr7xmdf^O#rAa+3sQi?5^wdaovk1^7Xlo^_2(yp$qKK|47 zVE!Lm02sHYyRY2#wk*;Q&cY&+;=l_C$Ezpb+gdpM;Kfh=&F??|59x1(KwS4^4r1;LnGUPr zJR@V+DBfEQs#OSxSq<=<*a+Xut%|`-n_HzjvobTFq&T^|?=H-BQU)$IP3qnT0Nm$lZ)k#_H}7F~v3w4ArH#uBwzIqGqOJ7u5(NmSBKMVuJOG?2zeZo11$b zX_zUMkVNdD2xJIUC&@yRSTYFA=inCH*Hsu@b&Nf1_pv8ACFy!C+7}8M;bKHdZZUSV z0bZ+Q7nx04>xai5{piixk&5f*Ki$ST-;{;eivyC8WS%~fH|RlChC4^t`7M$8*vNyq zrF(KPCjqUs($~^OV^v}EF_KvUKs3Q1h_?3kDFOlcp!;$BfCAl z`p>`phrj#F|LPOg_5Clc_oLecXKO#c_~fT|-~K-RJZuMPZ;OWkZCJErWfkAgL?bg* z8fA~MlZKDGxg5<@Y0OB5dtUNznGxnAgbOLo;3T+Qv2rURJJ8xv@4UhinT5S5Z?R_* z!AYcbh1l2$MCs&_7U@-o4Io8i4x% z2W5rKCmG9qixWliA{03?Hl$bIj+lvwMYJ!Bxe>eg$EMuL%ym%$n{AWoE}W5wP+6aS z^iu#I{sP$Uzkc=2FIR5St`a?>u(py(6sD>+Sw<2O8P39!m^W2|JRt}S23G@5lC(|^ z1rsMJLO{*LD$0V^fMX6x9};&f-R-x(U;pqS0I;_CTFmI{@mXJv``x#`ZA1o6k)8yC zn3KpNo!#z1P6^5&1p_3&e#+R$Yw`^$f|V8HTB3@A+WOVP+_Wv_BaX3$@8sq&XlBUf z;Jsd{V?r$IK9?2|#u$jnRb3d6wF*(vz8iFiT&rpFMx^o0q>9 zvbL;F05>8Kb4Hklo3-kofr3(H2@1kdbRipV!xJpp*W-G;X6P91CAdr3w(aWClQE1L z0@yeuvYdPwne0qlndgUcdZL_j1WGOmvX2bk-H`#xNS9|T1wI<-V8AoCVG95z?F!}quZNr9 z{sZEi;UpE>OW`0o@8`P$R!_L3YVw3{U!M5se&PGR z#|-bw@^Cz^Ahfhj>8EXb{?YY%^^89J6Cl&>U)uQ%QPBc`3&YUEMYSRiB2w`tcX|+@ zUu?`ix8*9BTtDB(-n3U>uFMpdatXT?yjCv|2WL$m+x@Hm{MB#&Z96=^{`kLOJ$`3( zvmc*bJ$|8j$kR8;ptiWDXe%zb+n&TDvgt|@mGrM=4S~3Y5K*FOCzU}6rvO7(L@7nl zE%>yL_yHh2Qmb?dTA#R?@ zS!GNk)`u)leeSCbSDOWzM`%VSSV7%!c8Y$uraxr_`d@khgq_~L`pwwhFb)J}X-P~o z>qZx-j%P+|n&}bg9=)roPF3(F*v&}*Jlt%!hl&)W8O(HHlmipkHtQVVq)3a*9prDm z_|@U~d_6wxkAL=^!-27l`7hqwxg?8jL9pj|?tqdw9Y?B;b+%|B{fyPUG|q z!bCV@+@J25leDp@Xiw3ACP~plXu=0jaFmA$_~i(c`@Z*e@o?s%Br~A}&XKOVO1t{- z7XW44zy1<52uA|fg_=Zv5X22{ttS;5f_Zv`^x_1{3c>2d`Gv_ZERA(MaL$;SatdQ2 zjkyN|)G0$7MQ%Lay!!m#wd3PYu3oTy2PU8&9>v;kKK|+P_rDyspOYm-Qka>^leLLz zaX(?WoIJpD8eJ>0%0UX3rHPm>Ku~2wMC&?i4|h(F@Tz?iKqN)SB%T)T6em!+GYAos z1ALK6KnMU@y}MAN`tK|n0Lh{v!nB>7F2iPey2DvjP zFe4)}#&)`AP``R)=|N;;|K_W&U;N-xKq5nh%{{_E$+|{>1C$&jtcSzRM}IhJz;gI_ zIec`ydhyMAm7p&_`@dxSCd2lzfl1mL)EPZ_A=WGh4r@IGtAPoUO4&X@@+L7U-S&|T z6$!5kqm^X9h6(t?UjV09pWVLxQiY*Qh!7-Vil10H#wco%d!#$3)7|O zud0Y7%805>b@Tb2Obo^B3^Y}K^-NOHCU0JS^T4kAkQc!D?Pufkt@A3( zV4+BIXH`HZ5tgwo%lUjSq!}4eFGCrTf!y~^Tc^y%>N!A8x!c%@c|9EF_WnKpjR%1h zOmGVi=E68|N;BVrd-I?-zy9`jfA{Ru|C-y)cYe(`Pk(m$_RGW5&u_o_kMQ9UO^Muy z*ct35GacrvGDaD`5bj78ZFMBg1W3X|%j!+=Oob#RhZlbWNI?<>GQ8OLS;Mg?9tj>? zx#5*aNce;n0znKp@ZnLvdJ1OVHn4JEN#L1*eth)N>Go@n-S=CJGxpmd&6leP8sjd) zg(WtsbDoH2+BU{|e7qbVWvK?jE9ZT4^N5&&V`hs003ZNKL_t(pT1DgF=k#5d1M#K% z){e)UXIGDZ0{-sL!*+ffb~?X(dHeD=jkSxetSUgHaSGSlvKuEdd=gEFDT^!}$ROKC>;T9I<_?k~ zBO`apU_D$tIbJ_Y7LVQCg#2{6TbJY2lV`5SAYtX!*ZbR74a8t#AtVdSa=g0vSiYY= z^7^Y^eD?SM+v)57MB5vOuy*KyWg#eG+RYQf7bWCF_~qezTknb@{7@UHZ}!7Kd7%li zutb=TvwY|az_-(D3JVesQ!Ecs`+9_V3`&q&YeKW}Efy9|t#!{>mi2tzwJRuW?6vqW zKUlbtTU2W{CMKZ7y7OZMMRQ7e3G>6RBa_?-L#NY9`L`4@nI z0%dnWMT6<$Ds8&fk4Eg<=~hI^Ju4Q*B?TL~-6K6`uqR3{JI?2lXGhelbM?KFMEkNX z$0vkd-Y?`hpKjB3y?VA@J=vidA~3E*jK}X}DhP^5L!@k?-lp=k)KLPlO&mSEAa(d~A391784s zKHa~fFi4Bb)0{5IGyuxV6rR)i$BJQlBm=Frwx3SDqxVKr873K4Z^ccNCI>e}l%cf> zc-R}Ta4iL^W*{QM8cxg-W9M=E?H514`Sh=sCx8COe`d_Q96vfN`r^mm{KHqj@cmZ% zmc)S$q(`b~Qo1=aSGK>9Rm{BCCUp#=T$X;JpHShz0g?+Oq#UP&iNGk-I2Ex4SzM1f z<^l^#L2`%^kSc2d>9)g>VmY`*R>@lFNW^aY9mv7cYEcZH3M14)#v2D}dCR1M&7j8JSq}c?!Mr2UazS}r&+ae9jms1tL z&z;@2jX4%xYhq$PvVMq#l9(H4|Mr_-KYR6Azxni!9|Bd+qxOTx&wujd#m~O_&EH~d zy{}g405hk^BzG6-lu(UR);kYbEK$8Fx zZoOzoKF&(M-Mu;8eoK(U<7e&oD2aq(qQ^6@u5WJNzOF%gBtL%o>DBco(vIKxDcJ75 zJiYqW{j1;jX%ID62FXPPT;skOxh_Lq?^@;QhbnC0051UjiPC)dZkt(Q)62R?q?f7q zhrR&zecaxC%S;R;k=bavWK2>?X*nt4VKrRSeQhm*Y>fJC*M8G&nor$}oo`+qh!VvK ziVa#Rk=`4T7c-+!O7-8Ynr=bFncL~x``2F`-+Zw?`6=PM&x*%KpFIEJU%me7mt=R+ zBT;RXN#v?qPPuDqB^BY9(|?65=Zh_u<3}XjGCbWWE>6V@L$LHwv#uVLnVyzOB-M4* zEU!oZIPz7R+2^oR)CwtZQaB1X(b-gFhWhnB3zLo}$K5+D+C&IpeWeF1RB zvaY9l0;Nn>h7ojG)&zM3$AsleZx8{cNMjaCA7igEu$wX1BeXFBZbMsJmW8Sln#svy z>>^s5es>e$NN{muDDy%YLdn#SWa;tNPp{s7{SUG}X@~D-XSem))w4f8Jbtmg{JEGB zc`^bbkkV@>88|aWBFAumwYBMUPp7OJAr+ZLh43pZ(i! zzxV~PB_U}cI;6DeMW}nZaHe0BaZ-1Bj}d8^N)Q4kWkfKM@Eng)dgYsHWRh73rI`Bp zB#-R_UjW1$^Es&^F~m^m@KHS3 zx*2fwED9@7^O$`*mjeP!^-*+lfK5N{yPOIzw0Z=B9${E(vXup zidhZKOlKm>K_Dj%H0a^@}8nS@nJFhF3{R)d9Ke&U|n%jLm z95AX1Ii1n9IzR*x+^-*hvL2tw;c+DU*zNANfWAx-Zs0Pzc&XUPwsa2^Nx|ICcPD%F z{Dtu zUXvFRg)oS#B3xs%352{n0f4y+>nafg&P;&F%*nEpLU&ynWrSH@9$J3v0gkyh-nab& zUjP#}Fb{h znZ=%#o?u8&Dzon|g$ZOd%BC`wf1hS+_-&v1Sx4U-b0(8L=&IFUdX zKhQhz+vRRKDS!kb9_XU1+K)HS+WLg`ih_onbHAr?)*OHlG1s(&3+1V?+c2*c+wgNH zWysCbPuJt)$aLE%4B9fFB19e;e0eNVRW6CbO_|rj^&juliD=w^`R42Y54ms5F!oJA7s#Ye!P{y!6;lZ_-DMyVLEftEb-=oPw-RA3yt7w_pBZ(H!nM zj7ci+kYi++`(TE7@JwaRkv*`IcK;tFl@Mkg@Y1IV1zq)ag9Fo6QCH* zkiqp@mz0!E*(_?#Sv3H6S8ZlaNb}+DeJNNC!c7Eaztg6>jmV(%ss!*uq(X$D<&dk@ z5;G{tihv2K?_G|aF2)HN=Ln+43q$OC(6O33t)X zXb>sUXe7vzn;|1o%=XMN_AQ8rG%?wR^?N6xfHMiWYrpD;o4y|T@QB-$2l+nk-n{gKbZdVi(kjM4U33Y(8!p3NiO@&1$LJ7 zo8kQA-r&elHL6izde@LZ(baqzIgk^%QZ7a+)f!g6T;GyDI)+DO%Z2F zN+1CDZ~$bdaZ4bJ$l|$!5`fzf)tuY=M6I})RU1R4ExN3L5XpQ=O|x+}+sjo!#0jmQ zR}y)IC?ct`WT0{Ee)jDalunip6pKUI38^(#Un7Kj)CN54_{NlI&F7`K^EsH!9Bu!Xq#+#MpR&5tIF1yb~ z3Z+GEglr8<;3}Xem@}okj!E5FbAcN zP=ScLk7Aou{Ek&9Qka|a=8^VKzb#=oJUu@Co+P z6fvBwdZ82{kPLRa8+JaQP98JooRB)ts2mQ*M~ACNZFvgT1Uw^iM3~ZIdAhy*LUpLF zkqaT_(5bW^_2Dm8Xx8sVh+>TUKf*8Pe)s$1!W(fAn3d|Yo;3EsDk55j@bh_d3%RNw z%oP0Ch?)tV&*#4M3b0h5SG1KMPqdkBrGr}ANmLcJzhU)%Q0e) z7<}QIx>wefAC#udTp^H{QZO~!sglp!0gmvQvW!xr6;8DkB?icc6wn2s!R5y-L3$P2>$|(#rMC*P~Fpx)O~eTARuM&NNKA7(qX)?@)GLyBU;jLZ999qpjpnHyzN zj!YV6i0$p`Zy)?jVD0_T`cc{udT8y6`Wn&+2#+!jsY2rP^5s`c>(}e?{_d0k2&X%N zBD1NMKVz==V`Ng9sZRH=(>H4C`^g{Q-t6bsmx^UJ)k<)Hh|2^Rkx43|tPB($VVYYR z?zC?^3p4Am5NY8_f~n6UYN{TVWR*%376N+fZX?rx1YdUVAMgU`%ke(i2ymjbb4fJ> zovp~JIuvmqaWV6V2%}WN1VRvOcxzom_I)Fo@xU=gwVxQmjAdEOrb16dYIZ)!GHxR8 z!U&k=kRHUhr}OpW=lO2Z@;#5TeyxW`%hluDzTD5}Fi27r-ZPm%ktU=RzBC4VxMdKx zRiy6@kp|(`xgU;{dAfT`$SC{;g0+F9tB(6U(=gwah$3j%7-z6BwAO+l>Rw9OSqVh6 zz~JT}&$O|PZP<$+{u#&q^7p^8^IKt6Q57W!P?}6T$14Dw!o-vodwl!)i>B9CSI@#u zr|q?N&R_=Wi3wIJ>u6e}Z|AK#S#XPSANwm>AHVnFm*?BB-@g2u%%M_ITuMub)-1n5 zPF(Lk7-LlWwO#;fELeTt0z@;jnP2|o_+bmgEH#}fMg? zM_6yk6htH-_Hfmp@gg!GVBS+e}id5Dl@5B6{>!J8n5GVlR ztFOFh{T@4+YLI}LP?1vH9U`a{N^j7x90+g`$V1Yd1kz6_3n7Y3JygV)4~L-)BBG{9 zlukhr!IYc`OyI+{Ggo}q6=8Kcoy%r>a<;$sz+xTM7Ftj9-dh?TWfvbukJjYajN`a0 z-AtLKmO9TfATTkkUb%^*Is`CrU`EJ5o+rKc`EaPUFyR{lgEiMNv(C{yfJLMLa-FVy z&6{MD`LGOBGTrdle!v>xMuoYo5BV^#RIlWdkXU)O60$N1RnVFg)krW0800$Iv zg_SjNh5bAF5hOufM*}$B=9zBuDIr2jGTpj)gV- z?C<~PE(*O7;49a^vFu3*-a3LKsTPL!OEx+l5E~M14*MEFu6A1`@?kr&!0R zD+r;Z=bYIgIjxcMng~aT-e&jAR7KxE@GmDG_ulpJdH^+4 zvH>MBo5MOvsR(Fhn2}8)0N8quRTL9QxUxNvfeMm<17Ny$fqP8TaCvz-PDPs{CaI3h zEcs?(7A+`d(D9v`gZ(imkW}E2>!zEb&NZgI#cWawVU{ilcjgo@gWkYhWJrdfxtSUh z=Ev>emft&Z##3i7$*L(@1@(;U!-ZPbOf~Rq1JaI20FoyM0dII?z4iBRYV%<}uV^CD ztc#Rz?_GznAWC=~<@^qa>WTn;St{+z#DHOK@d#o;B#)AY$41>P93_XFL}JznA)PRg z$URMQ0Mi^QBXE;K0VyY7;&B?bWjx{GL}-9W2MMF&ww;;0;0h}#UER<)6^->Z&EWdhaXGF)R%eTB+KI|B*q+RE^*});0y8*2zfVQnjR1uSz{4$>#;|$?=bUIofwFDt zy(3minIMvfu9>H10YQabi73W#9LL?ln_>DIAtFdZ2;mx`fNTJOjLb!9Ai1lVkpmHj z8zAHm5&>+vtV|y0(F3UP#tm3FlYeC3D~lTdkYV)00&W=V=K?Iug2ae|tKZOh!-p%7B!lg$p8 zgxO7@&1uSR+5wyh+#+1V`_aJVssy?~jAVNQn3)0@bIp8g60+6xgAv)>L}(pcLVD!9 z5hU&&B%F)^Rb`gs3%Q4{Z~V$a5Y61f2^_-5?KS#V@CBMq9@?Hh#JuG=Ah_wmoPgR2 zR$jTjTqPi7C`OKlb2CWUfSI~uE#mG(+?wV54}kor3_99O6g(zu=9T~vm|~JpKxa;p zG&SYZN8eJ)^hb1(nPLxtOcIin2@{d)4B%=?4iF(Cm8+QvaoD0W1fXHmapSHA6y_o& zq6CqQqiJ{d43iDK1yM%5u&gaeaVUoOwdx@vdr1fE7I zUrvKtQk5q{kRBIFM6`%CFOyTVf`nK0ojqfKkGb$y^oKzzQv%$p@@bkT!1P$piG*F* z$RVPey4g7G_$^rO@8|+3!*<+0v^%}i?*Bn}2Wt@{5l1v+E?faZM8ZwAmr{Jqhf7I> zi->`**sxkDC62~XB8-^wUq5m}*Q=D`2`+dCcgm{MI`Z1OSsjY`+MmN&wz1(mLj-A9o<6 zakIOzJ-bCRv}HD1ki0J!7}#S8Qww8|K+QrlJf_{0jVXhJF8hn~wm%0~T@LO&5N@1a z&#vrEsPS0@<`)}&m3IzE6vTwAX4&|XJF#%)8yrmz0au;01C&y-1v1rAgjNK_MbOri z@>Mdg+E-4IbqL&?o^kmWH~|ppt_=l|B#F((Auc5C+a25uEYe#+ zdj|wJ&B`~=NnK~=v>vIeYq zHaC!mX5irv{o?!*gHBGb7l8TlybwWnZygYYg)`Kz%|g_=&uy{3P=vMay#;hA!_7O7 zEQiHi>1c=&5aYBRqR(N(nfjTcehl~SZthZQcu?Ur1=Y;10=FTA$Rk-WVs4eFd&p2T zTb!B96+BkI0OjP)aQbMoU#?Qo#T$5d8Fowz1ikm1WhBSd zQ!ZdR?Q(ZrO>l>SN^x^_gCzZ>={?d>nV#mEA;O3xgbtZw7hwy<0;mWb$h!8h;J{|E zx%TMWyvZ!u%?)Beky!TD=fy6W#UZ#J}bB9(5R_hzJW>=>E{s=2w}Z z%}cx7hb@R2WoI&lYgmKh0w}{!rki&DI!ldk2o|K2a#FD@R8!(eLQ;elL<0MjnOT*ckOfF*bely8XzKr-FD_3Vr8uD!4# zGOk(I771S>9~=1q0zPVgBMgx|BGGy^XJ%wX3?dN`fR#GS$7EHam2D9oh{?4PH3DRh zZatHfnVF1mck_MY>DvuZ;Iga3&^ZEvN$M~h^bpaOdCr6qw=^d#ZJ7}d#b<~Fycg)7$*hJ87BZ$uVufv`J$2w)80H&302$M-z{kxzg8cd_q@CKL+93?>Mq zTE*A7O|;e$2A~Wyuwy{zaU`0>TdX-ZrmC&A%``EyhXJ9R6Laq>!kF$*gwyusxVWEy%x$oUNGcyt=I47IiPk#j7_OMXOgj51tRS_~5v49(Z3L~ZH zVcCm}BuvcVJs=!Pw&iY4#Kdd>06~l!8MBZ}_HRTuaD<%Qdi4A?>WBNQNqU}i5R^$+ z(Yxlk??DLRfQ*3}5y(=Kk*XMn<>KV*_PD(hIGN7N z{&hW^Yu8~M$K8%t%*?t61XI~e&Ajd}001BWNkl%@Oqcw64dxAtV%Y*V4lP_)NN4t9hV)tMULUQo!cFRn? z9|x<<0O)2xB+QviwcFkrcejz~TV(;r=Ip)S@uRQ&{x1?Pfq}pdlzUaSW-QgCo25Yur2w#$ zl!v34b?XEmSWm9so(1R2yMCpaJqDN}Gz7v3h8%5&Mj$ZrP=;L{PLN0U)htlcQ3ipS z0L*m(bTbX$lih8pJ49BU`{8cef5{w%?N;hwz$g{SgldGET3D!cQ*&$9JBAXu47-!F zCqj0>(=hG+X!OqM<0m)Y(_jCj8HgZ6csPS+NHZZNMResqualY7aD$mbL@6c1V2X$v zLL@%|P$WnGX(p1p@;KyG3+;6D9hJdwBGHjqC zcy@qmJ&*=zk(uRdPZ%Jx z;o;#Yp8t`zgMPlz&6kao4Fpkia3QV{7}3j606a`9RKg%s3=05PXRZ)nZAKzN>dS0_ zfLv+;NAo}=w+1L&3K3QoLV;B+NXSxM&&fXbvf_LqWcHBEW^neO6h?j1$hXY=Vh;LL3H#WByu8Rc2nKTg2)YhJ;|IW+r7<##4BwuD8`{OsBW5Kl<%2eePctB(4J% zNr;Y+k_Spe9xDV+h`Ze`aYg{kVlmwUTkCQpKIC{205BuT&C_`l5e>mT5GdVj0Hh3O z=lgqyi+i_kJ^ak`e{Os2nXmIU@uA1wd+)`MW1MR{aM=J!j$eqPw*|w)8ictTl)_vx zM#u$$sEUVVkTiqU=~2p zjWEz0!-<>(3Q9-Wo;^ykg)$ABv+4BqSAb^q?8cL?4L8hQVPfRfz5`q{@XIsG9hrrr z>+03$z5<{Is+}mO#n4*Irl4yp;67^7MEA zwY#r=DlWfdZmLU>foiqB`r0}`ta4_OI%Fx|+QJBGy_957)3n*S8)fKK3O0xkgP7gi z%pH*csPG^|nD^ep{rth@tFOOatn%h$c;x-ppZPxc`l*5^+lR~cA?x=;=hls<9hU+C zs>XGUjMp-)T#PCrn+K7DExvC-09d7rp$j5;7;~X83<|Sa1^_U}2vcq3HVnJ@@~(PM zk~0FJ0}=tCvGXxytT4CU5~W9Aa0Ck|ZV}`JhRns$NhXo845w1IRHi`ocCdN2zVEHk zFwwL#h$)Aq)<$#DHEhv(DHr|Ql3 z9KP@}6vMEv1|H^J>O@h}*B*%hqt-$Qh?K#C$8;`T3V#|B@qivTpqB2Y;;8=^MDu7)~E~ z>V2QN_=3&%!!7}Q>0=oRaq)1eJHz7II|P>s>*j^MS?gUYjbrhMQ1j5tUi8q)#Uol< zlFSQeHWkqL@f<$AVjxh7@%7M z{0Qs(Z=DRx%RzhZOPi)m@20-E_QX80C?cfZEj*6%a8xxCgn-Na{&0DD*zbpN5{P9! zxZ3@@_fBrbH_#ykk2IV<^5pwp_~gg9&ta-X-9{cj>VPaoMg(9+SxX>tfRyPVV^?zr zKolf%Un5XGz!&dJt%ES9xkVOl}TN7!Chtpe6+<5c@^W9HnHea|oXeosYBOe24B2{8Xy7dZb2U57Zsk<4A z^uF@vDFBJm9nn49R0IKCbw*#%7UfeJ-?{qd>skN+$j^WGPyYPxeX^8&sYG=`mem;5 zD8i6QHM2ti5nF4?_#4KNn3*I17y%KRu6;8QQgC3DQZhir-7%uI)>;F^Qmb~=WkHWh z{7e7%@BVu?|IX=+N50DXS?>ze%diXJGHx6w zh)K-*fZkyH;NeDu6$uU`h^Z0j-x1N8iER3s07^jEtJoz1;z5iJ^JuF(rX($`2lY?MTxC!j3)fBUfFcAl=u4r%!*jouX+S8stNsMN8IP90mO8BiCx(sfe>3s(n{ z8IbC3nzjSd{`^asuOY%HxXhR20A?+$j3;H>1QIhsbTfnicXeIJ8-%-cu!dm(SjsSN zPs?;|*jzuo`Rs7|Dk%_xt_fFsC$(h(u%@M`R*lV38`@@$}VK ze&hV!7ry=`z|qXL?+*u-Ds=#a-Vfl7z`z&wPPULW*Ezz6p^}JsAdzbqra{sURtbVI z?I5%-2WvBU3sY@}J|DnZQfKP08>ef;1J|((6U#_aNeW3Vb*kfrr6LvLfn^k~h*Y?2 z&u;9l-K^8uu)Q8KKpkW}Qylh-12Qmlomqxq+61OgYr{~}#eMO~2I2;bEApk@wiG>Rg0S|;UU4Qb{qtC!QdwtytfN1!hANr{WGeNs> zSHNy=&D8pl(1*w(4&mU!l6FaMYF)#OgoB7hNZ3-?5i!q)WjWlxe=ovB@TjLgo~nQ% zECrd1hn-aT^rwEozs?M)`N0?ae2&EKM#xM9b1Ah*WhSF&1U;;~YO-1KXJA6X5D^bR z6c0GehwdHI&@Y*E83&dyfX!wH?FWh=9){g@-d=-Yi)9iyVHuG}mJLuv9=Hs{u#@q$ zY;KIF4-K1}o3q-EaXXDWa1MncW7(WWiaEnwd)v>ZJyg*;Cov5O zs34EQ^{_0je(9zA_g}ia_nP3~s6cPicNS&3xqbK>78 z2d+K+BNs3J?~_bH*Ne7-wePyCiGay|=iwc{z9Gg1(ue=Te~8m_cK-P|ybiF) zQREt$Huoq}N*P%SGp~(5QVPcj))^^yn69Yknx6TlVeoNSMnpK(TFW4H!{ZJhwmg68 zmwx8;mtT0h+yCY3eR)9W)@Rq2?o1AhSP&vT44IgTF{1;tMZ17@VTT88f4?o4eLlD@ z;XMWCp?$2?-MLm7CJWXS!lDpMgqx{{vQ*{?Xrmy`j51IeAmxG{8s4=#Kr^?MGXd`2 zwOe=qOBo}IAbIc0{=5{%GT^vPpXcy!H`A`#-DWo>VlKnDIhDEr8K8_nWtDDq?aTh& z-7mT|3muPpt1)(f1? zTASy~+>IcRiH}K!LBzGz1f(+zI02vBHa45hFbui7WN$#sNR(F6BE>u~Ow}C(xrDXd zfFJw$pYcAw%>{s{1o7bBYi+)4%c34gMTQNR9m&MJAsoXvj2MD!@#S1E@9N=h^a~8t zegN+j3ZdYN5Lw-t2e1UO1po?{F@ge6O-*}mO9Zf#I&2&yr~)!Wg7%JPrHaTJfC!qo@@!4FI9?mY8n-ZB2qpR@$Z>yf8Fc>jC$WYhOl`YB+PpRIC2#pZYMsKLT2ykK5Op?21pbmI1tPLVco-l zkh(S^G*=`x01RX)7${{3kKT>az^W@aI4Y8ejK!h#1A?{rJlcFbN?n(VToENJ#znho zb6vpARl|eHsZ6vxb(C600#xfo7>Ux%lb=-xl|tN--3fAyb?9ARFDp%ej13!F^QS)(j6+p4wwG;Q(>_cx^;r9W;dHQcrL zI*z?7bNXWubMX?;_7|_;fA2^B#>jVL1s6>!K zV5>h36nU0{^gvH&uX6GO>c(|JsAwV@3Da*1<-5s)HJ^JQp-?F5sru=T$tQUn1spQTWbKx=tgEj zKsO~ob7KOw`Q9sEeBbx}_0!wWyju(4Pbxe+yY-%L`~JWA`G5WQPxwKliDiNq3_F0C z#hb+Lc#MJ3^i<4h2N8SIWR^4YFsvxSG01u~Z(EH%0-!={LwiR&4O__eQrd6*%KyB* zcJjdw|NHnBI=XQ>d4O^M^)Fy(DeOjwj3@vCOp<(oWVV=U?-7yNtVkkN9CF73Qgt&V z2n_QGipuN(hr?kQ3IdvY<~FXwBH|=d2&IoS0t(2sP(hw;Idqb155I@Ek6gd?bg5g5 z3`4fp{$RTQ^6#5kaHiD@aP>756^L`5jvf{ff(YTR7J!H$g(I9iV?Gv)EJQ03x@_y_ z=37E%5np)m|M}Rz_=oHVGi|-qT2=K5k-L(=U7BX1+;*bBQ^wnmZ$hC;H{ap-Y7Ulvh0OaY8=nNP{WUgjPfXt||8a74*N)2H5KpqIy z-I$<`ghb4ut&QUdVF1BIS-E8l7&9Sq2A@I1ssTdms@P_LUbnZmHy-2NlP7nc4W2y0 zy!�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".format(sys.argv[0])) - - else: - input_fname = sys.argv[1] - image_in = Image.open(input_fname) - image_in = image_in.convert('RGB') - - # Resize the image - image_in = image_in.resize((128, 128)) - image_out = image_in.copy() - w, h = image_in.size - - # Take input image and divide each color channel's value by 16 - for y in range(h): - for x in range(w): - r, g, b = image_in.getpixel((x, y)) - image_out.putpixel((x,y), (r//16, g//16, b//16)) - - - # Save the image itself - pixels = [] - for y in range(h): - for x in range(w): - (r, g, b) = image_out.getpixel((x,y)) - color = (r*16*16) + (g*16) + (b) - pixels.append(color) - - from manta import Manta - m = Manta('manta.yaml') - - addrs = list(range(len(pixels))) - m.image_mem.write(addrs, pixels) \ No newline at end of file diff --git a/examples/nexys_a7/video_sprite_uart/src/clk_gen.v b/examples/nexys_a7/video_sprite_uart/src/clk_gen.v deleted file mode 100644 index 91d4265..0000000 --- a/examples/nexys_a7/video_sprite_uart/src/clk_gen.v +++ /dev/null @@ -1,207 +0,0 @@ - -// file: clk_gen.v -// -// (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved. -// -// This file contains confidential and proprietary information -// of Xilinx, Inc. and is protected under U.S. and -// international copyright and other intellectual property -// laws. -// -// DISCLAIMER -// This disclaimer is not a license and does not grant any -// rights to the materials distributed herewith. Except as -// otherwise provided in a valid license issued to you by -// Xilinx, and to the maximum extent permitted by applicable -// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND -// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES -// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING -// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- -// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and -// (2) Xilinx shall not be liable (whether in contract or tort, -// including negligence, or under any other theory of -// liability) for any loss or damage of any kind or nature -// related to, arising under or in connection with these -// materials, including for any direct, or any indirect, -// special, incidental, or consequential loss or damage -// (including loss of data, profits, goodwill, or any type of -// loss or damage suffered as a result of any action brought -// by a third party) even if such damage or loss was -// reasonably foreseeable or Xilinx had been advised of the -// possibility of the same. -// -// CRITICAL APPLICATIONS -// Xilinx products are not designed or intended to be fail- -// safe, or for use in any application requiring fail-safe -// performance, such as life-support or safety devices or -// systems, Class III medical devices, nuclear facilities, -// applications related to the deployment of airbags, or any -// other applications that could lead to death, personal -// injury, or severe property or environmental damage -// (individually and collectively, "Critical -// Applications"). Customer assumes the sole risk and -// liability of any use of Xilinx products in Critical -// Applications, subject only to applicable laws and -// regulations governing limitations on product liability. -// -// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS -// PART OF THIS FILE AT ALL TIMES. -// -//---------------------------------------------------------------------------- -// User entered comments -//---------------------------------------------------------------------------- -// None -// -//---------------------------------------------------------------------------- -// Output Output Phase Duty Cycle Pk-to-Pk Phase -// Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps) -//---------------------------------------------------------------------------- -// clk_50mhz__50.00000______0.000______50.0______150.541_____99.281 -// clk_65mhz__65.00000______0.000______50.0______142.278_____99.281 -// -//---------------------------------------------------------------------------- -// Input Clock Freq (MHz) Input Jitter (UI) -//---------------------------------------------------------------------------- -// __primary_________100.000____________0.010 - -`timescale 1ps/1ps - -module clk_gen - - (// Clock in ports - // Clock out ports - output clk_50mhz, - output clk_65mhz, - input clk_100mhz - ); - // Input buffering - //------------------------------------ -wire clk_100mhz_clk_gen; -wire clk_in2_clk_gen; - IBUF clkin1_ibufg - (.O (clk_100mhz_clk_gen), - .I (clk_100mhz)); - - - - - // Clocking PRIMITIVE - //------------------------------------ - - // Instantiation of the MMCM PRIMITIVE - // * Unused inputs are tied off - // * Unused outputs are labeled unused - - wire clk_50mhz_clk_gen; - wire clk_65mhz_clk_gen; - wire clk_out3_clk_gen; - wire clk_out4_clk_gen; - wire clk_out5_clk_gen; - wire clk_out6_clk_gen; - wire clk_out7_clk_gen; - - wire [15:0] do_unused; - wire drdy_unused; - wire psdone_unused; - wire locked_int; - wire clkfbout_clk_gen; - wire clkfbout_buf_clk_gen; - wire clkfboutb_unused; - wire clkout0b_unused; - wire clkout1b_unused; - wire clkout2_unused; - wire clkout2b_unused; - wire clkout3_unused; - wire clkout3b_unused; - wire clkout4_unused; - wire clkout5_unused; - wire clkout6_unused; - wire clkfbstopped_unused; - wire clkinstopped_unused; - - MMCME2_ADV - #(.BANDWIDTH ("OPTIMIZED"), - .CLKOUT4_CASCADE ("FALSE"), - .COMPENSATION ("ZHOLD"), - .STARTUP_WAIT ("FALSE"), - .DIVCLK_DIVIDE (1), - .CLKFBOUT_MULT_F (9.750), - .CLKFBOUT_PHASE (0.000), - .CLKFBOUT_USE_FINE_PS ("FALSE"), - .CLKOUT0_DIVIDE_F (19.500), - .CLKOUT0_PHASE (0.000), - .CLKOUT0_DUTY_CYCLE (0.500), - .CLKOUT0_USE_FINE_PS ("FALSE"), - .CLKOUT1_DIVIDE (15), - .CLKOUT1_PHASE (0.000), - .CLKOUT1_DUTY_CYCLE (0.500), - .CLKOUT1_USE_FINE_PS ("FALSE"), - .CLKIN1_PERIOD (10.000)) - mmcm_adv_inst - // Output clocks - ( - .CLKFBOUT (clkfbout_clk_gen), - .CLKFBOUTB (clkfboutb_unused), - .CLKOUT0 (clk_50mhz_clk_gen), - .CLKOUT0B (clkout0b_unused), - .CLKOUT1 (clk_65mhz_clk_gen), - .CLKOUT1B (clkout1b_unused), - .CLKOUT2 (clkout2_unused), - .CLKOUT2B (clkout2b_unused), - .CLKOUT3 (clkout3_unused), - .CLKOUT3B (clkout3b_unused), - .CLKOUT4 (clkout4_unused), - .CLKOUT5 (clkout5_unused), - .CLKOUT6 (clkout6_unused), - // Input clock control - .CLKFBIN (clkfbout_buf_clk_gen), - .CLKIN1 (clk_100mhz_clk_gen), - .CLKIN2 (1'b0), - // Tied to always select the primary input clock - .CLKINSEL (1'b1), - // Ports for dynamic reconfiguration - .DADDR (7'h0), - .DCLK (1'b0), - .DEN (1'b0), - .DI (16'h0), - .DO (do_unused), - .DRDY (drdy_unused), - .DWE (1'b0), - // Ports for dynamic phase shift - .PSCLK (1'b0), - .PSEN (1'b0), - .PSINCDEC (1'b0), - .PSDONE (psdone_unused), - // Other control and status signals - .LOCKED (locked_int), - .CLKINSTOPPED (clkinstopped_unused), - .CLKFBSTOPPED (clkfbstopped_unused), - .PWRDWN (1'b0), - .RST (1'b0)); - -// Clock Monitor clock assigning -//-------------------------------------- - // Output buffering - //----------------------------------- - - BUFG clkf_buf - (.O (clkfbout_buf_clk_gen), - .I (clkfbout_clk_gen)); - - - - - - - BUFG clkout1_buf - (.O (clk_50mhz), - .I (clk_50mhz_clk_gen)); - - - BUFG clkout2_buf - (.O (clk_65mhz), - .I (clk_65mhz_clk_gen)); - - - -endmodule diff --git a/examples/nexys_a7/video_sprite_uart/src/top_level.sv b/examples/nexys_a7/video_sprite_uart/src/top_level.sv deleted file mode 100644 index 01645fd..0000000 --- a/examples/nexys_a7/video_sprite_uart/src/top_level.sv +++ /dev/null @@ -1,96 +0,0 @@ -`timescale 1ns / 1ps -`default_nettype none - -module top_level ( - input wire clk_100mhz, - - input wire uart_txd_in, - output logic uart_rxd_out, - - output logic [3:0] vga_r, vga_g, vga_b, - output logic vga_hs, vga_vs); - - // Clock generation - logic clk_65mhz; - - clk_gen gen( - .clk_100mhz(clk_100mhz), - .clk_50mhz(), - .clk_65mhz(clk_65mhz)); - - // VGA signals - logic [10:0] hcount; - logic [9:0] vcount; - logic hsync, vsync, blank; - - vga vga_gen( - .pixel_clk_in(clk_65mhz), - .hcount_out(hcount), - .vcount_out(vcount), - .hsync_out(hsync), - .vsync_out(vsync), - .blank_out(blank)); - - // VGA Pipelining - reg[1:0][10:0] hcount_pipe; - reg[1:0][10:0] vcount_pipe; - reg[1:0] hsync_pipe; - reg[1:0] vsync_pipe; - reg[1:0] blank_pipe; - - always_ff @(posedge clk_65mhz)begin - hcount_pipe[0] <= hcount; - vcount_pipe[0] <= vcount; - hsync_pipe[0] <= hsync; - vsync_pipe[0] <= vsync; - blank_pipe[0] <= blank; - for (int i=1; i<2; i = i+1)begin - hcount_pipe[i] <= hcount_pipe[i-1]; - vcount_pipe[i] <= vcount_pipe[i-1]; - hsync_pipe[i] <= hsync_pipe[i-1]; - vsync_pipe[i] <= vsync_pipe[i-1]; - blank_pipe[i] <= blank_pipe[i-1]; - end - end - - localparam WIDTH = 128; - localparam HEIGHT = 128; - - localparam X = 0; - localparam Y = 0; - - // calculate rom address - logic [$clog2(WIDTH*HEIGHT)-1:0] image_addr; - assign image_addr = (hcount - X) + ((vcount - Y) * WIDTH); - - logic in_sprite; - assign in_sprite = ((hcount_pipe[1] >= X && hcount_pipe[1] < (X + WIDTH)) && - (vcount_pipe[1] >= Y && vcount_pipe[1] < (Y + HEIGHT))); - - manta manta_inst ( - .clk(clk_65mhz), - - .rx(uart_txd_in), - .tx(uart_rxd_out), - - .image_mem_clk(clk_65mhz), - .image_mem_addr(image_addr), - .image_mem_din(), - .image_mem_dout(sprite_color), - .image_mem_we(1'b0)); - - logic [11:0] sprite_color; - logic [11:0] color; - assign color = in_sprite ? sprite_color : 12'h0; - - // the following lines are required for the Nexys4 VGA circuit - do not change - assign vga_r = ~blank_pipe[1] ? color[11:8]: 0; - assign vga_g = ~blank_pipe[1] ? color[7:4] : 0; - assign vga_b = ~blank_pipe[1] ? color[3:0] : 0; - - assign vga_hs = ~hsync_pipe[1]; - assign vga_vs = ~vsync_pipe[1]; - - -endmodule -`default_nettype wire diff --git a/examples/nexys_a7/video_sprite_uart/src/vga.sv b/examples/nexys_a7/video_sprite_uart/src/vga.sv deleted file mode 100644 index 3fa787f..0000000 --- a/examples/nexys_a7/video_sprite_uart/src/vga.sv +++ /dev/null @@ -1,68 +0,0 @@ - -/* vga: Generate VGA display signals (1024 x 768 @ 60Hz) - * - * ---- HORIZONTAL ----- ------VERTICAL ----- - * Active Active - * Freq Video FP Sync BP Video FP Sync BP - * 640x480, 60Hz 25.175 640 16 96 48 480 11 2 31 - * 800x600, 60Hz 40.000 800 40 128 88 600 1 4 23 - * 1024x768, 60Hz 65.000 1024 24 136 160 768 3 6 29 - * 1280x1024, 60Hz 108.00 1280 48 112 248 768 1 3 38 - * 1280x720p 60Hz 75.25 1280 72 80 216 720 3 5 30 - * 1920x1080 60Hz 148.5 1920 88 44 148 1080 4 5 36 - * - * change the clock frequency, front porches, sync's, and back porches to create - * other screen resolutions - */ - -module vga( - input wire pixel_clk_in, - output logic [10:0] hcount_out, // pixel number on current line - output logic [9:0] vcount_out, // line number - output logic vsync_out, hsync_out, - output logic blank_out); - - parameter DISPLAY_WIDTH = 1024; // display width - parameter DISPLAY_HEIGHT = 768; // number of lines - - parameter H_FP = 24; // horizontal front porch - parameter H_SYNC_PULSE = 136; // horizontal sync - parameter H_BP = 160; // horizontal back porch - - parameter V_FP = 3; // vertical front porch - parameter V_SYNC_PULSE = 6; // vertical sync - parameter V_BP = 29; // vertical back porch - - // horizontal: 1344 pixels total - // display 1024 pixels per line - logic hblank,vblank; - logic hsyncon,hsyncoff,hreset,hblankon; - assign hblankon = (hcount_out == (DISPLAY_WIDTH -1)); - assign hsyncon = (hcount_out == (DISPLAY_WIDTH + H_FP - 1)); //1047 - assign hsyncoff = (hcount_out == (DISPLAY_WIDTH + H_FP + H_SYNC_PULSE - 1)); // 1183 - assign hreset = (hcount_out == (DISPLAY_WIDTH + H_FP + H_SYNC_PULSE + H_BP - 1)); //1343 - - // vertical: 806 lines total - // display 768 lines - logic vsyncon,vsyncoff,vreset,vblankon; - assign vblankon = hreset & (vcount_out == (DISPLAY_HEIGHT - 1)); // 767 - assign vsyncon = hreset & (vcount_out == (DISPLAY_HEIGHT + V_FP - 1)); // 771 - assign vsyncoff = hreset & (vcount_out == (DISPLAY_HEIGHT + V_FP + V_SYNC_PULSE - 1)); // 777 - assign vreset = hreset & (vcount_out == (DISPLAY_HEIGHT + V_FP + V_SYNC_PULSE + V_BP - 1)); // 805 - - // sync and blanking - logic next_hblank,next_vblank; - assign next_hblank = hreset ? 0 : hblankon ? 1 : hblank; - assign next_vblank = vreset ? 0 : vblankon ? 1 : vblank; - always_ff @(posedge pixel_clk_in) begin - hcount_out <= hreset ? 0 : hcount_out + 1; - hblank <= next_hblank; - hsync_out <= hsyncon ? 0 : hsyncoff ? 1 : hsync_out; // active low - - vcount_out <= hreset ? (vreset ? 0 : vcount_out + 1) : vcount_out; - vblank <= next_vblank; - vsync_out <= vsyncon ? 0 : vsyncoff ? 1 : vsync_out; // active low - - blank_out <= next_vblank | (next_hblank & ~hreset); - end -endmodule \ No newline at end of file diff --git a/examples/nexys_a7/video_sprite_uart/xdc/top_level.xdc b/examples/nexys_a7/video_sprite_uart/xdc/top_level.xdc deleted file mode 100644 index 817beb0..0000000 --- a/examples/nexys_a7/video_sprite_uart/xdc/top_level.xdc +++ /dev/null @@ -1,253 +0,0 @@ -## This file is a general .xdc for the Nexys4 DDR Rev. C -## To use it in a project: -## - uncomment the lines corresponding to used pins -## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project - -## This file has been modified from the default .xdc provided by Digilent for the Nexys A7 - -## Clock signal -set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { clk_100mhz }]; #IO_L12P_T1_MRCC_35 Sch=clk_100mhz -create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {clk_100mhz}]; - - -##Switches - -#set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { sw[0] }]; #IO_L24N_T3_RS0_15 Sch=sw[0] -#set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 } [get_ports { sw[1] }]; #IO_L3N_T0_DQS_EMCCLK_14 Sch=sw[1] -#set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { sw[2] }]; #IO_L6N_T0_D08_VREF_14 Sch=sw[2] -#set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { sw[3] }]; #IO_L13N_T2_MRCC_14 Sch=sw[3] -#set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { sw[4] }]; #IO_L12N_T1_MRCC_14 Sch=sw[4] -#set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { sw[5] }]; #IO_L7N_T1_D10_14 Sch=sw[5] -#set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { sw[6] }]; #IO_L17N_T2_A13_D29_14 Sch=sw[6] -#set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { sw[7] }]; #IO_L5N_T0_D07_14 Sch=sw[7] -#set_property -dict { PACKAGE_PIN T8 IOSTANDARD LVCMOS18 } [get_ports { sw[8] }]; #IO_L24N_T3_34 Sch=sw[8] -#set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS18 } [get_ports { sw[9] }]; #IO_25_34 Sch=sw[9] -#set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { sw[10] }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=sw[10] -#set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { sw[11] }]; #IO_L23P_T3_A03_D19_14 Sch=sw[11] -#set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { sw[12] }]; #IO_L24P_T3_35 Sch=sw[12] -#set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { sw[13] }]; #IO_L20P_T3_A08_D24_14 Sch=sw[13] -#set_property -dict { PACKAGE_PIN U11 IOSTANDARD LVCMOS33 } [get_ports { sw[14] }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=sw[14] -#set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { sw[15] }]; #IO_L21P_T3_DQS_14 Sch=sw[15] - - -## LEDs - -#set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { led[0] }]; #IO_L18P_T2_A24_15 Sch=led[0] -#set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { led[1] }]; #IO_L24P_T3_RS1_15 Sch=led[1] -#set_property -dict { PACKAGE_PIN J13 IOSTANDARD LVCMOS33 } [get_ports { led[2] }]; #IO_L17N_T2_A25_15 Sch=led[2] -#set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { led[3] }]; #IO_L8P_T1_D11_14 Sch=led[3] -#set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { led[4] }]; #IO_L7P_T1_D09_14 Sch=led[4] -#set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { led[5] }]; #IO_L18N_T2_A11_D27_14 Sch=led[5] -#set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { led[6] }]; #IO_L17P_T2_A14_D30_14 Sch=led[6] -#set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { led[7] }]; #IO_L18P_T2_A12_D28_14 Sch=led[7] -#set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { led[8] }]; #IO_L16N_T2_A15_D31_14 Sch=led[8] -#set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { led[9] }]; #IO_L14N_T2_SRCC_14 Sch=led[9] -#set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { led[10] }]; #IO_L22P_T3_A05_D21_14 Sch=led[10] -#set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { led[11] }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=led[11] -#set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { led[12] }]; #IO_L16P_T2_CSI_B_14 Sch=led[12] -#set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { led[13] }]; #IO_L22N_T3_A04_D20_14 Sch=led[13] -#set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { led[14] }]; #IO_L20N_T3_A07_D23_14 Sch=led[14] -#set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { led[15] }]; #IO_L21N_T3_DQS_A06_D22_14 Sch=led[15] - -#set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { led16_b }]; #IO_L5P_T0_D06_14 Sch=led16_b -#set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { led16_g }]; #IO_L10P_T1_D14_14 Sch=led16_g -#set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { led16_r }]; #IO_L11P_T1_SRCC_14 Sch=led16_r -#set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { led17_b }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=led17_b -#set_property -dict { PACKAGE_PIN R11 IOSTANDARD LVCMOS33 } [get_ports { led17_g }]; #IO_0_14 Sch=led17_g -#set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { led17_r }]; #IO_L11N_T1_SRCC_14 Sch=led17_r - - -##7 segment display - -#set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { ca }]; #IO_L24N_T3_A00_D16_14 Sch=ca -#set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { cb }]; #IO_25_14 Sch=cb -#set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { cc }]; #IO_25_15 Sch=cc -#set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { cd }]; #IO_L17P_T2_A26_15 Sch=cd -#set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ce }]; #IO_L13P_T2_MRCC_14 Sch=ce -#set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { cf }]; #IO_L19P_T3_A10_D26_14 Sch=cf -#set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { cg }]; #IO_L4P_T0_D04_14 Sch=cg - -#set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { dp }]; #IO_L19N_T3_A21_VREF_15 Sch=dp - -#set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { an[0] }]; #IO_L23P_T3_FOE_B_15 Sch=an[0] -#set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { an[1] }]; #IO_L23N_T3_FWE_B_15 Sch=an[1] -#set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { an[2] }]; #IO_L24P_T3_A01_D17_14 Sch=an[2] -#set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { an[3] }]; #IO_L19P_T3_A22_15 Sch=an[3] -#set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { an[4] }]; #IO_L8N_T1_D12_14 Sch=an[4] -#set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { an[5] }]; #IO_L14P_T2_SRCC_14 Sch=an[5] -#set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { an[6] }]; #IO_L23P_T3_35 Sch=an[6] -#set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { an[7] }]; #IO_L23N_T3_A02_D18_14 Sch=an[7] - - -##Buttons - -#set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { cpu_resetn }]; #IO_L3P_T0_DQS_AD1P_15 Sch=cpu_resetn - -#set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { btnc }]; #IO_L9P_T1_DQS_14 Sch=btnc -#set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { btnu }]; #IO_L4N_T0_D05_14 Sch=btnu -#set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { btnl }]; #IO_L12P_T1_MRCC_14 Sch=btnl -#set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { btnr }]; #IO_L10N_T1_D15_14 Sch=btnr -#set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { btnd }]; #IO_L9N_T1_DQS_D13_14 Sch=btnd - - -##Pmod Headers - - -##Pmod Header JA - -#set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { ja[0] }]; #IO_L20N_T3_A19_15 Sch=ja[1] -#set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { ja[1] }]; #IO_L21N_T3_DQS_A18_15 Sch=ja[2] -#set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { ja[2] }]; #IO_L21P_T3_DQS_15 Sch=ja[3] -#set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { ja[3] }]; #IO_L18N_T2_A23_15 Sch=ja[4] -#set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L16N_T2_A27_15 Sch=ja[7] -#set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L16P_T2_A28_15 Sch=ja[8] -#set_property -dict { PACKAGE_PIN F18 IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L22N_T3_A16_15 Sch=ja[9] -#set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_L22P_T3_A17_15 Sch=ja[10] - - -##Pmod Header JB - -#set_property -dict { PACKAGE_PIN D14 IOSTANDARD LVCMOS33 } [get_ports { jb[0] }]; #IO_L1P_T0_AD0P_15 Sch=jb[1] -#set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { jb[1] }]; #IO_L14N_T2_SRCC_15 Sch=jb[2] -#set_property -dict { PACKAGE_PIN G16 IOSTANDARD LVCMOS33 } [get_ports { jb[2] }]; #IO_L13N_T2_MRCC_15 Sch=jb[3] -#set_property -dict { PACKAGE_PIN H14 IOSTANDARD LVCMOS33 } [get_ports { jb[3] }]; #IO_L15P_T2_DQS_15 Sch=jb[4] -#set_property -dict { PACKAGE_PIN E16 IOSTANDARD LVCMOS33 } [get_ports { jb[4] }]; #IO_L11N_T1_SRCC_15 Sch=jb[7] -#set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { jb[5] }]; #IO_L5P_T0_AD9P_15 Sch=jb[8] -#set_property -dict { PACKAGE_PIN G13 IOSTANDARD LVCMOS33 } [get_ports { jb[6] }]; #IO_0_15 Sch=jb[9] -#set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { jb[7] }]; #IO_L13P_T2_MRCC_15 Sch=jb[10] - - -##Pmod Header JC - -#set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { jc[0] }]; #IO_L23N_T3_35 Sch=jc[1] -#set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { jc[1] }]; #IO_L19N_T3_VREF_35 Sch=jc[2] -#set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { jc[2] }]; #IO_L22N_T3_35 Sch=jc[3] -#set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { jc[3] }]; #IO_L19P_T3_35 Sch=jc[4] -#set_property -dict { PACKAGE_PIN E7 IOSTANDARD LVCMOS33 } [get_ports { jc[4] }]; #IO_L6P_T0_35 Sch=jc[7] -#set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { jc[5] }]; #IO_L22P_T3_35 Sch=jc[8] -#set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { jc[6] }]; #IO_L21P_T3_DQS_35 Sch=jc[9] -#set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { jc[7] }]; #IO_L5P_T0_AD13P_35 Sch=jc[10] - - -##Pmod Header JD - -#set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { jd[0] }]; #IO_L21N_T3_DQS_35 Sch=jd[1] -#set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports { jd[1] }]; #IO_L17P_T2_35 Sch=jd[2] -#set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { jd[2] }]; #IO_L17N_T2_35 Sch=jd[3] -#set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { jd[3] }]; #IO_L20N_T3_35 Sch=jd[4] -#set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { jd[4] }]; #IO_L15P_T2_DQS_35 Sch=jd[7] -#set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { jd[5] }]; #IO_L20P_T3_35 Sch=jd[8] -#set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { jd[6] }]; #IO_L15N_T2_DQS_35 Sch=jd[9] -#set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { jd[7] }]; #IO_L13N_T2_MRCC_35 Sch=jd[10] - - -##Pmod Header JXADC - -#set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVDS } [get_ports { xa_n[0] }]; #IO_L9N_T1_DQS_AD3N_15 Sch=xa_n[1] -#set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVDS } [get_ports { xa_p[0] }]; #IO_L9P_T1_DQS_AD3P_15 Sch=xa_p[1] -#set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVDS } [get_ports { xa_n[1] }]; #IO_L8N_T1_AD10N_15 Sch=xa_n[2] -#set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVDS } [get_ports { xa_p[1] }]; #IO_L8P_T1_AD10P_15 Sch=xa_p[2] -#set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVDS } [get_ports { xa_n[2] }]; #IO_L7N_T1_AD2N_15 Sch=xa_n[3] -#set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVDS } [get_ports { xa_p[2] }]; #IO_L7P_T1_AD2P_15 Sch=xa_p[3] -#set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVDS } [get_ports { xa_n[3] }]; #IO_L10N_T1_AD11N_15 Sch=xa_n[4] -#set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVDS } [get_ports { xa_p[3] }]; #IO_L10P_T1_AD11P_15 Sch=xa_p[4] - - -##VGA Connector - -set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { vga_r[0] }]; #IO_L8N_T1_AD14N_35 Sch=vga_r[0] -set_property -dict { PACKAGE_PIN B4 IOSTANDARD LVCMOS33 } [get_ports { vga_r[1] }]; #IO_L7N_T1_AD6N_35 Sch=vga_r[1] -set_property -dict { PACKAGE_PIN C5 IOSTANDARD LVCMOS33 } [get_ports { vga_r[2] }]; #IO_L1N_T0_AD4N_35 Sch=vga_r[2] -set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { vga_r[3] }]; #IO_L8P_T1_AD14P_35 Sch=vga_r[3] - -set_property -dict { PACKAGE_PIN C6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[0] }]; #IO_L1P_T0_AD4P_35 Sch=vga_g[0] -set_property -dict { PACKAGE_PIN A5 IOSTANDARD LVCMOS33 } [get_ports { vga_g[1] }]; #IO_L3N_T0_DQS_AD5N_35 Sch=vga_g[1] -set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[2] }]; #IO_L2N_T0_AD12N_35 Sch=vga_g[2] -set_property -dict { PACKAGE_PIN A6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[3] }]; #IO_L3P_T0_DQS_AD5P_35 Sch=vga_g[3] - -set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[0] }]; #IO_L2P_T0_AD12P_35 Sch=vga_b[0] -set_property -dict { PACKAGE_PIN C7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[1] }]; #IO_L4N_T0_35 Sch=vga_b[1] -set_property -dict { PACKAGE_PIN D7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[2] }]; #IO_L6N_T0_VREF_35 Sch=vga_b[2] -set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { vga_b[3] }]; #IO_L4P_T0_35 Sch=vga_b[3] - -set_property -dict { PACKAGE_PIN B11 IOSTANDARD LVCMOS33 } [get_ports { vga_hs }]; #IO_L4P_T0_15 Sch=vga_hs -set_property -dict { PACKAGE_PIN B12 IOSTANDARD LVCMOS33 } [get_ports { vga_vs }]; #IO_L3N_T0_DQS_AD1N_15 Sch=vga_vs - -##Micro SD Connector - -#set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { sd_reset }]; #IO_L14P_T2_SRCC_35 Sch=sd_reset -#set_property -dict { PACKAGE_PIN A1 IOSTANDARD LVCMOS33 } [get_ports { sd_cd }]; #IO_L9N_T1_DQS_AD7N_35 Sch=sd_cd -#set_property -dict { PACKAGE_PIN B1 IOSTANDARD LVCMOS33 } [get_ports { sd_sck }]; #IO_L9P_T1_DQS_AD7P_35 Sch=sd_sck -#set_property -dict { PACKAGE_PIN C1 IOSTANDARD LVCMOS33 } [get_ports { sd_cmd }]; #IO_L16N_T2_35 Sch=sd_cmd -#set_property -dict { PACKAGE_PIN C2 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[0] }]; #IO_L16P_T2_35 Sch=sd_dat[0] -#set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[1] }]; #IO_L18N_T2_35 Sch=sd_dat[1] -#set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[2] }]; #IO_L18P_T2_35 Sch=sd_dat[2] -#set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[3] }]; #IO_L14N_T2_SRCC_35 Sch=sd_dat[3] - - -##Accelerometer - -#set_property -dict { PACKAGE_PIN E15 IOSTANDARD LVCMOS33 } [get_ports { acl_miso }]; #IO_L11P_T1_SRCC_15 Sch=acl_miso -#set_property -dict { PACKAGE_PIN F14 IOSTANDARD LVCMOS33 } [get_ports { acl_mosi }]; #IO_L5N_T0_AD9N_15 Sch=acl_mosi -#set_property -dict { PACKAGE_PIN F15 IOSTANDARD LVCMOS33 } [get_ports { acl_sclk }]; #IO_L14P_T2_SRCC_15 Sch=acl_sclk -#set_property -dict { PACKAGE_PIN D15 IOSTANDARD LVCMOS33 } [get_ports { acl_csn }]; #IO_L12P_T1_MRCC_15 Sch=acl_csn -#set_property -dict { PACKAGE_PIN B13 IOSTANDARD LVCMOS33 } [get_ports { acl_int[1] }]; #IO_L2P_T0_AD8P_15 Sch=acl_int[1] -#set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 } [get_ports { acl_int[2] }]; #IO_L20P_T3_A20_15 Sch=acl_int[2] - - -##Temperature Sensor - -#set_property -dict { PACKAGE_PIN C14 IOSTANDARD LVCMOS33 } [get_ports { tmp_scl }]; #IO_L1N_T0_AD0N_15 Sch=tmp_scl -#set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS33 } [get_ports { tmp_sda }]; #IO_L12N_T1_MRCC_15 Sch=tmp_sda -#set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 } [get_ports { tmp_int }]; #IO_L6N_T0_VREF_15 Sch=tmp_int -#set_property -dict { PACKAGE_PIN B14 IOSTANDARD LVCMOS33 } [get_ports { tmp_ct }]; #IO_L2N_T0_AD8N_15 Sch=tmp_ct - -##Omnidirectional Microphone - -#set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { m_clk }]; #IO_25_35 Sch=m_clk -#set_property -dict { PACKAGE_PIN H5 IOSTANDARD LVCMOS33 } [get_ports { m_data }]; #IO_L24N_T3_35 Sch=m_data -#set_property -dict { PACKAGE_PIN F5 IOSTANDARD LVCMOS33 } [get_ports { m_lrsel }]; #IO_0_35 Sch=m_lrsel - - -##PWM Audio Amplifier - -#set_property -dict { PACKAGE_PIN A11 IOSTANDARD LVCMOS33 } [get_ports { aud_pwm }]; #IO_L4N_T0_15 Sch=aud_pwm -#set_property -dict { PACKAGE_PIN D12 IOSTANDARD LVCMOS33 } [get_ports { aud_sd }]; #IO_L6P_T0_15 Sch=aud_sd - - -##USB-RS232 Interface - -set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { uart_txd_in }]; #IO_L7P_T1_AD6P_35 Sch=uart_txd_in -set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { uart_rxd_out }]; #IO_L11N_T1_SRCC_35 Sch=uart_rxd_out -#set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { uart_cts }]; #IO_L12N_T1_MRCC_35 Sch=uart_cts -#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { uart_rts }]; #IO_L5N_T0_AD13N_35 Sch=uart_rts - -##USB HID (PS/2) - -#set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { ps2_clk }]; #IO_L13P_T2_MRCC_35 Sch=ps2_clk -#set_property -dict { PACKAGE_PIN B2 IOSTANDARD LVCMOS33 } [get_ports { ps2_data }]; #IO_L10N_T1_AD15N_35 Sch=ps2_data - - -##SMSC Ethernet PHY - -#set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { eth_mdc }]; #IO_L11P_T1_SRCC_16 Sch=eth_mdc -#set_property -dict { PACKAGE_PIN A9 IOSTANDARD LVCMOS33 } [get_ports { eth_mdio }]; #IO_L14N_T2_SRCC_16 Sch=eth_mdio -#set_property -dict { PACKAGE_PIN B3 IOSTANDARD LVCMOS33 } [get_ports { eth_rstn }]; #IO_L10P_T1_AD15P_35 Sch=eth_rstn -#set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { eth_crsdv }]; #IO_L6N_T0_VREF_16 Sch=eth_crsdv -#set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { eth_rxerr }]; #IO_L13N_T2_MRCC_16 Sch=eth_rxerr -#set_property -dict { PACKAGE_PIN C11 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[0] }]; #IO_L13P_T2_MRCC_16 Sch=eth_rxd[0] -#set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[1] }]; #IO_L19N_T3_VREF_16 Sch=eth_rxd[1] -#set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { eth_txen }]; #IO_L11N_T1_SRCC_16 Sch=eth_txen -#set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[0] }]; #IO_L14P_T2_SRCC_16 Sch=eth_txd[0] -#set_property -dict { PACKAGE_PIN A8 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[1] }]; #IO_L12N_T1_MRCC_16 Sch=eth_txd[1] -#set_property -dict { PACKAGE_PIN D5 IOSTANDARD LVCMOS33 } [get_ports { eth_refclk }]; #IO_L11P_T1_SRCC_35 Sch=eth_refclk -#set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { eth_intn }]; #IO_L12P_T1_MRCC_16 Sch=eth_intn - - -##Quad SPI Flash - -#set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[0] }]; #IO_L1P_T0_D00_MOSI_14 Sch=qspi_dq[0] -#set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[1] }]; #IO_L1N_T0_D01_DIN_14 Sch=qspi_dq[1] -#set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[2] }]; #IO_L2P_T0_D02_14 Sch=qspi_dq[2] -#set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[3] }]; #IO_L2N_T0_D03_14 Sch=qspi_dq[3] -#set_property -dict { PACKAGE_PIN L13 IOSTANDARD LVCMOS33 } [get_ports { qspi_csn }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_csn \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 949089d..8e9b9e9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,12 +1,13 @@ [project] -name = "mantaray" -version = "0.0.5" +name = "manta" +version = "0.1.0" authors = [ { name="Fischer Moseley", email="fischerm@mit.edu" }, ] description = "An In-Situ Debugging Tool for Programmable Hardware" readme = "README.md" dependencies = [ + "amaranth[builtin-yosys]@git+https://github.com/amaranth-lang/amaranth", "PyYAML", "pyserial", "pyvcd", @@ -15,6 +16,14 @@ dependencies = [ requires-python = ">=3.7" +[project.optional-dependencies] +dev = [ + "pytest", + "black", + "mkdocs-material", + "amaranth_boards@git+https://github.com/amaranth-lang/amaranth-boards" +] + [project.urls] "Homepage" = "https://github.com/fischermoseley/manta" @@ -24,9 +33,6 @@ manta = "manta:main" [tool.setuptools.packages.find] where = ["src"] -[tool.setuptools.package-data] -manta = ["**/*.v"] - [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" \ No newline at end of file diff --git a/src/manta/__init__.py b/src/manta/__init__.py index 587e4d8..60b9f60 100644 --- a/src/manta/__init__.py +++ b/src/manta/__init__.py @@ -1,385 +1,5 @@ -# Internal Dependencies -from .utils import * -from .la_core import * -from .io_core import * -from .block_mem_core import * - -# External Dependencies -from sys import argv -import os -from datetime import datetime -from pkg_resources import get_distribution - -class Manta: - def __init__(self, config_filepath): - config = self.read_config_file(config_filepath) - - # set interface - if "uart" in config: - from .uart_iface import UARTInterface - self.interface = UARTInterface(config["uart"]) - - elif "ethernet" in config: - from .ether_iface import EthernetInterface - self.interface = EthernetInterface(config["ethernet"]) - - else: - raise ValueError("Unrecognized interface specified.") - - # check that cores were provided - assert "cores" in config, "No cores found." - assert len(config["cores"]) > 0, "Must specify at least one core." - - # add cores to self - base_addr = 0 - self.cores = [] - for i, core_name in enumerate(config["cores"]): - core = config["cores"][core_name] - - # make sure a type was specified for this core - assert "type" in core, f"No type specified for core {core_name}." - - # add the core to ourself - if core["type"] == "logic_analyzer": - new_core = LogicAnalyzerCore(core, core_name, base_addr, self.interface) - - elif core["type"] == "io": - new_core = IOCore(core, core_name, base_addr, self.interface) - - elif core["type"] == "block_memory": - new_core = BlockMemoryCore(core, core_name, base_addr, self.interface) - - else: - raise ValueError(f"Unrecognized core type specified for {core_name}.") - - # make sure we're not out of address space - assert new_core.max_addr < (2**16)-1, f"Ran out of address space to allocate to core {core_name}." - - # make the next core's base address start one address after the previous one's - base_addr = new_core.max_addr + 1 - - # add friendly name, so users can do Manta.my_logic_analyzer.read() for example - setattr(self, core_name, new_core) - self.cores.append(new_core) - - def read_config_file(self, path): - """Take path to configuration file, and retun the configuration as a python list/dict object.""" - extension = path.split(".")[-1] - - if "json" in extension: - with open(path, "r") as f: - import json - - config = json.load(f) - - elif "yaml" in extension or "yml" in extension: - with open(path, "r") as f: - import yaml - - config = yaml.safe_load(f) - - else: - raise ValueError("Unable to recognize configuration file extension.") - - return config - - def gen_connections(self): - # generates hdl for registers that connect two modules together - - # make pairwise cores - core_pairs = [(self.cores[i - 1], self.cores[i]) for i in range(1, len(self.cores))] - - conns = [] - for core_pair in core_pairs: - src = core_pair[0].name - dst = core_pair[1].name - - hdl = f"reg [15:0] {src}_{dst}_addr;\n" - hdl += f"reg [15:0] {src}_{dst}_data;\n" - hdl += f"reg {src}_{dst}_rw;\n" - hdl += f"reg {src}_{dst}_valid;\n" - conns.append(hdl) - - return conns - - def gen_instances(self): - # generates hdl for modules that need to be connected together - - insts = [] - for i, core in enumerate(self.cores): - # should probably check if core is LogicAnalyzerCore or IOCore - - hdl = core.hdl_inst() - - # connect input - if (i == 0): - src_name = "brx" - - else: - src_name = self.cores[i-1].name - - hdl = hdl.replace(".addr_i()", f".addr_i({src_name}_{core.name}_addr)") - hdl = hdl.replace(".data_i()", f".data_i({src_name}_{core.name}_data)") - hdl = hdl.replace(".rw_i()", f".rw_i({src_name}_{core.name}_rw)") - hdl = hdl.replace(".valid_i()", f".valid_i({src_name}_{core.name}_valid)") - - - - # connect output - if (i < len(self.cores)-1): - dst_name = self.cores[i+1].name - hdl = hdl.replace(".addr_o()", f".addr_o({core.name}_{dst_name}_addr)") - - else: - dst_name = "btx" - - hdl = hdl.replace(".data_o()", f".data_o({core.name}_{dst_name}_data)") - hdl = hdl.replace(".rw_o()", f".rw_o({core.name}_{dst_name}_rw)") - hdl = hdl.replace(".valid_o()", f".valid_o({core.name}_{dst_name}_valid)") - - insts.append(hdl) - - return insts - - def gen_core_chain(self): - insts = self.gen_instances() - conns = self.gen_connections() - core_chain = [] - for i, inst in enumerate(insts): - core_chain.append(inst) - - if (i != len(insts)-1): - core_chain.append(conns[i]) - - return '\n'.join(core_chain) - - def gen_example_inst_ports(self): - # this is a C-style block comment that contains an instantiation - # of the configured manta instance - the idea is that a user - # can copy-paste that into their design instead of trying to spot - # the difference between their code and the autogenerated code. - - # hopefully this saves time! - - - # this turns a list like ['input wire foo', 'output reg bar'] into - # a nice string like ".foo(foo),\n .bar(bar)" - interface_ports = self.interface.hdl_top_level_ports() - interface_ports = [port.split(',')[0] for port in interface_ports] - interface_ports = [port.split(' ')[-1] for port in interface_ports] - interface_ports = [f".{port}({port}),\n" for port in interface_ports] - interface_ports = "".join(interface_ports) - - core_chain_ports = [] - for core in self.cores: - ports = [port.split(',')[0] for port in core.hdl_top_level_ports()] - ports = [port.split(' ')[-1] for port in ports] - ports = [f".{port}({port}), \n" for port in ports] - ports = "".join(ports) - ports = "\n" + ports - core_chain_ports.append(ports) - - core_chain_ports = "\n".join(core_chain_ports) - - ports = interface_ports + core_chain_ports - - # remove trailing comma - ports = ports.rstrip() - if ports[-1] == ",": - ports = ports[:-1] - - return ports - - def gen_top_level_ports(self): - # get all the top level connections for each module. - - interface_ports = self.interface.hdl_top_level_ports() - interface_ports = [f"{port},\n" for port in interface_ports] - interface_ports = "".join(interface_ports) + "\n" - - core_chain_ports = [] - for core in self.cores: - ports = [f"{port},\n" for port in core.hdl_top_level_ports()] - ports = "".join(ports) - core_chain_ports.append(ports) - - core_chain_ports = "\n".join(core_chain_ports) - - ports = interface_ports + core_chain_ports - - # remove trailing comma - ports = ports.rstrip() - if ports[-1] == ",": - ports = ports[:-1] - - return ports - - def gen_interface_rx(self): - # instantiate interface_rx, substitute in register names - interface_rx_inst = self.interface.rx_hdl_inst() - - interface_rx_inst = interface_rx_inst.replace("addr_o()", f"addr_o(brx_{self.cores[0].name}_addr)") - interface_rx_inst = interface_rx_inst.replace("data_o()", f"data_o(brx_{self.cores[0].name}_data)") - interface_rx_inst = interface_rx_inst.replace("rw_o()", f"rw_o(brx_{self.cores[0].name}_rw)") - interface_rx_inst = interface_rx_inst.replace("valid_o()", f"valid_o(brx_{self.cores[0].name}_valid)") - - # connect interface_rx to core_chain - interface_rx_conn= f""" -reg [15:0] brx_{self.cores[0].name}_addr; -reg [15:0] brx_{self.cores[0].name}_data; -reg brx_{self.cores[0].name}_rw; -reg brx_{self.cores[0].name}_valid;\n""" - - return interface_rx_inst + interface_rx_conn - - def gen_interface_tx(self): - - # connect core_chain to interface_tx - interface_tx_conn = f""" -reg [15:0] {self.cores[-1].name}_btx_data; -reg {self.cores[-1].name}_btx_rw; -reg {self.cores[-1].name}_btx_valid;\n""" - - # instantiate interface_tx, substitute in register names - interface_tx_inst = self.interface.tx_hdl_inst() - - interface_tx_inst = interface_tx_inst.replace("addr_i()", f"addr_i({self.cores[-1].name}_btx_addr)") - interface_tx_inst = interface_tx_inst.replace("data_i()", f"data_i({self.cores[-1].name}_btx_data)") - interface_tx_inst = interface_tx_inst.replace("rw_i()", f"rw_i({self.cores[-1].name}_btx_rw)") - interface_tx_inst = interface_tx_inst.replace("valid_i()", f"valid_i({self.cores[-1].name}_btx_valid)") - - return interface_tx_conn + interface_tx_inst - - def gen_module_defs(self): - # aggregate module definitions and remove duplicates - module_defs_with_dups = [self.interface.rx_hdl_def()] + [core.hdl_def() for core in self.cores] + [self.interface.tx_hdl_def()] - module_defs = [] - module_defs = [m_def for m_def in module_defs_with_dups if m_def not in module_defs] - module_defs = [m_def.strip() for m_def in module_defs] - return '\n\n'.join(module_defs) - - def generate_hdl(self, output_filepath): - manta = VerilogManipulator("manta_def_tmpl.v") - - version = "v" + get_distribution('mantaray').version - manta.sub(version, "/* VERSION */") - - timestamp = datetime.now().strftime("%d %b %Y at %H:%M:%S") - manta.sub(timestamp, "/* TIMESTAMP */") - - user = os.environ.get("USER", os.environ.get("USERNAME")) - manta.sub(user, "/* USER */") - - ex_inst_ports = self.gen_example_inst_ports() - manta.sub(ex_inst_ports, "/* EX_INST_PORTS */") - - top_level_ports = self.gen_top_level_ports() - manta.sub(top_level_ports, "/* TOP_LEVEL_PORTS */") - - interface_rx = self.gen_interface_rx() - manta.sub(interface_rx, "/* INTERFACE_RX */") - - core_chain = self.gen_core_chain() - manta.sub(core_chain, "/* CORE_CHAIN */") - - interface_tx = self.gen_interface_tx() - manta.sub(interface_tx, "/* INTERFACE_TX */") - - module_defs = self.gen_module_defs() - manta.sub(module_defs, "/* MODULE_DEFS */") - - manta.hdl = "`timescale 1ns/1ps\n" + manta.hdl - manta.hdl = "`default_nettype none\n"+ manta.hdl - manta.hdl = manta.hdl + "\n`default_nettype wire" - - return manta.get_hdl() - -def main(): - # print help menu if no args passed or help menu requested - - if len(argv) == 1 or argv[1] == "help" or argv[1] == "ray" or argv[1] == "bae": - version = "v" + get_distribution('mantaray').version - print( - f""" -\033[96m (\.-./) -\033[96m / \\ -\033[96m .' : '. -\033[96m _.-'` ' `'-._ \033[34;49;1m | \033[34;49;1m Manta {version} \033[00m -\033[96m .-' : '-. \033[34;49;1m | \033[34;49;3m An In-Situ Debugging Tool for Programmable Hardware \033[00m -\033[96m ,'_.._ . _.._', \033[34;49;1m | \033[34;49m https://github.com/fischermoseley/manta \033[00m -\033[96m '` `'-. ' .-'` -\033[96m '. : .' \033[34;49;1m | \033[34;49;3m fischerm [at] mit.edu \033[00m -\033[96m \_. ._/ -\033[96m \ |^| -\033[96m | | ; -\033[96m \\'.___.' / -\033[96m '-....-' \033[00m - -Supported commands: - gen [config_file] [verilog_file] generate a verilog file specifying the Manta module from a given configuration file, and save to the provided path - capture [config_file] [LA_core_name] [vcd_file] [mem_file] start a capture on the specified core, and save the results to a .mem or .vcd file at the provided path(s) - playback [config file] [LA_core_name] [verilog_file] generate a verilog module that plays back a capture from a given logic analyzer core, and save to the provided path - ports list all available serial ports - help, ray display this splash screen (hehe...splash screen) -""" - ) - - # list available serial ports - elif argv[1] == "ports": - import serial.tools.list_ports - for port in serial.tools.list_ports.comports(): - print(port) - - # sometimes macOS will enumerate non-serial devices as serial ports, - # in which case the PID/VID/serial/location/etc are all None - pid = f"0x{port.vid:04X}" if port.pid is not None else "None" - vid = f"0x{port.vid:04X}" if port.vid is not None else "None" - - print(f" -> pid: {pid}") - print(f" -> vid: {vid}") - print(f" -> ser: {port.serial_number}") - print(f" -> loc: {port.location}") - print(f" -> mftr: {port.manufacturer}") - print(f" -> prod: {port.product}") - print(f" -> desc: {port.description}\n") - - # generate the specified configuration - elif argv[1] == "gen": - assert len(argv) == 4, "Wrong number of arguments, run 'manta help' for proper usage." - - m = Manta(argv[2]) - hdl = m.generate_hdl(argv[3]) - with open(argv[3], "w") as f: - f.write(hdl) - - # run the specified core - elif argv[1] == "capture": - assert len(argv) >= 5, "Wrong number of arguments, run 'manta help' for proper usage." - - m = Manta(argv[2]) - la = getattr(m, argv[3]) - data = la.capture() - - for path in argv[4:]: - if ".vcd" in path: - la.export_vcd(data, path) - - elif ".mem" in path: - la.export_mem(data, path) - - else: - print(f"Warning: Unknown output file format for {path}, skipping...") - - elif argv[1] == "playback": - assert len(argv) == 5, "Wrong number of arguments, run 'manta help' for proper usage." - - m = Manta(argv[2]) - la = getattr(m, argv[3]) - la.export_playback_module(argv[4]) - - else: - print("Option not recognized, run 'manta help' for proper usage.") - +from .manta import Manta +from .cli import main if __name__ == "__main__": main() diff --git a/src/manta/__main__.py b/src/manta/__main__.py index b23d9a5..4e28416 100644 --- a/src/manta/__main__.py +++ b/src/manta/__main__.py @@ -1,3 +1,3 @@ -import manta +from .cli import main -manta.main() +main() diff --git a/src/manta/block_mem_core/__init__.py b/src/manta/block_mem_core/__init__.py deleted file mode 100644 index dbe841c..0000000 --- a/src/manta/block_mem_core/__init__.py +++ /dev/null @@ -1,77 +0,0 @@ -from ..utils import * - -from math import ceil, log2 - -class BlockMemoryCore: - def __init__(self, config, name, base_addr, interface): - self.name = name - self.base_addr = base_addr - self.interface = interface - - # Warn if unrecognized options have been given - for option in config: - if option not in ["type", "depth", "width", "expose_port"]: - print(f"Warning: Ignoring unrecognized option '{option}' in Block Memory core '{self.name}'") - - # Determine if we expose the BRAM's second port to the top of the module - if "expose_port" in config: - assert isinstance(config["expose_port"], bool), "Configuring BRAM exposure must be done with a boolean." - self.expose_port = config["expose_port"] - - else: - self.expose_port = True - - # Get depth - assert "depth" in config, "Depth not specified for Block Memory core." - assert config["depth"] > 0, "Block Memory core must have positive depth." - assert isinstance(config["depth"], int), "Block Memory core must have integer depth." - self.depth = config["depth"] - - # Get width - assert "width" in config, "Width not specified for Block Memory core." - assert config["width"] > 0, "Block Memory core must have positive width." - assert isinstance(config["width"], int), "Block Memory core must have integer width." - self.width = config["width"] - - self.addr_width = ceil(log2(self.depth)) - self.n_brams = ceil(self.width / 16) - self.max_addr = self.base_addr + (self.depth * self.n_brams) - - def hdl_inst(self): - inst = VerilogManipulator("block_mem_core/block_memory_inst_tmpl.v") - inst.sub(self.name, "/* INST_NAME */") - inst.sub(self.depth, "/* DEPTH */") - inst.sub(self.width, "/* WIDTH */") - return inst.get_hdl() - - def hdl_def(self): - block_memory = VerilogManipulator("block_mem_core/block_memory.v").get_hdl() - dual_port_bram = VerilogManipulator("block_mem_core/dual_port_bram.v").get_hdl() - return block_memory + "\n" + dual_port_bram - - def hdl_top_level_ports(self): - if not self.expose_port: - return "" - - tlp = [] - tlp.append(f"input wire {self.name}_clk") - tlp.append(f"input wire [{self.addr_width-1}:0] {self.name}_addr") - tlp.append(f"input wire [{self.width-1}:0] {self.name}_din") - tlp.append(f"output reg [{self.width-1}:0] {self.name}_dout") - tlp.append(f"input wire {self.name}_we") - return tlp - - def get_physical_addr(self, addr): - if isinstance(addr, int): - return addr + self.base_addr - - elif isinstance(addr, list): - return [a + self.base_addr for a in addr] - - raise ValueError("Read address must be integer or list of integers.") - - def read(self, addr): - return self.interface.read(self.get_physical_addr(addr)) - - def write(self, addr, data): - return self.interface.write(self.get_physical_addr(addr), data) \ No newline at end of file diff --git a/src/manta/block_mem_core/block_memory.v b/src/manta/block_mem_core/block_memory.v deleted file mode 100644 index ae00f17..0000000 --- a/src/manta/block_mem_core/block_memory.v +++ /dev/null @@ -1,114 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -module block_memory ( - input wire clk, - - // input port - input wire [15:0] addr_i, - input wire [15:0] data_i, - input wire rw_i, - input wire valid_i, - - // output port - output reg [15:0] addr_o, - output reg [15:0] data_o, - output reg rw_o, - output reg valid_o, - - // BRAM itself - input wire user_clk, - input wire [ADDR_WIDTH-1:0] user_addr, - input wire [WIDTH-1:0] user_din, - output reg [WIDTH-1:0] user_dout, - input wire user_we); - - parameter BASE_ADDR = 0; - parameter WIDTH = 0; - parameter DEPTH = 0; - localparam ADDR_WIDTH = $clog2(DEPTH); - - // ugly typecasting, but just computes ceil(WIDTH / 16) - localparam N_BRAMS = int'($ceil(real'(WIDTH) / 16.0)); - localparam MAX_ADDR = BASE_ADDR + (DEPTH * N_BRAMS); - - // Port A of BRAMs - reg [N_BRAMS-1:0][ADDR_WIDTH-1:0] addra = 0; - reg [N_BRAMS-1:0][15:0] dina = 0; - reg [N_BRAMS-1:0][15:0] douta; - reg [N_BRAMS-1:0] wea = 0; - - // Port B of BRAMs - reg [N_BRAMS-1:0][15:0] dinb; - reg [N_BRAMS-1:0][15:0] doutb; - assign dinb = user_din; - - // kind of a hack to part select from a 2d array that's been flattened to 1d - reg [(N_BRAMS*16)-1:0] doutb_flattened; - assign doutb_flattened = doutb; - assign user_dout = doutb_flattened[WIDTH-1:0]; - - // Pipelining - reg [2:0][15:0] addr_pipe = 0; - reg [2:0][15:0] data_pipe = 0; - reg [2:0] valid_pipe = 0; - reg [2:0] rw_pipe = 0; - - always @(posedge clk) begin - addr_pipe[0] <= addr_i; - data_pipe[0] <= data_i; - valid_pipe[0] <= valid_i; - rw_pipe[0] <= rw_i; - - addr_o <= addr_pipe[2]; - data_o <= data_pipe[2]; - valid_o <= valid_pipe[2]; - rw_o <= rw_pipe[2]; - - for(int i=1; i<3; i=i+1) begin - addr_pipe[i] <= addr_pipe[i-1]; - data_pipe[i] <= data_pipe[i-1]; - valid_pipe[i] <= valid_pipe[i-1]; - rw_pipe[i] <= rw_pipe[i-1]; - end - - // throw BRAM operations into the front of the pipeline - wea <= 0; - if( (valid_i) && (addr_i >= BASE_ADDR) && (addr_i <= MAX_ADDR)) begin - wea[(addr_i - BASE_ADDR) % N_BRAMS] <= rw_i; - addra[(addr_i - BASE_ADDR) % N_BRAMS] <= (addr_i - BASE_ADDR) / N_BRAMS; - dina[(addr_i - BASE_ADDR) % N_BRAMS] <= data_i; - end - - // pull BRAM reads from the back of the pipeline - if( (valid_pipe[2]) && (addr_pipe[2] >= BASE_ADDR) && (addr_pipe[2] <= MAX_ADDR)) begin - data_o <= douta[(addr_pipe[2] - BASE_ADDR) % N_BRAMS]; - end - end - - // generate the BRAMs - genvar i; - generate - for(i=0; i pid: {pid}") + print(f" -> vid: {vid}") + print(f" -> ser: {port.serial_number}") + print(f" -> loc: {port.location}") + print(f" -> mftr: {port.manufacturer}") + print(f" -> prod: {port.product}") + print(f" -> desc: {port.description}\n") + + +def main(): + if len(argv) == 1: + help() + + elif argv[1] in ["help", "-h", "-help", "--help", "ray"]: + help() + + elif argv[1] == "gen": + if len(argv) != 4: + wrong_args() + gen(argv[2], argv[3]) + + elif argv[1] == "capture": + if len(argv) < 5: + wrong_args() + capture(argv[2], argv[3], argv[4]) + + elif argv[1] == "playback": + if len(argv) != 5: + wrong_args() + playback(argv[2], argv[3], argv[4]) + + elif argv[1] == "mmap": + if len(argv) != 3: + wrong_args() + mmap(argv[2]) + + elif argv[1] == "ports": + ports() + + else: + wrong_args() + + +if __name__ == "__main__": + main() diff --git a/src/manta/ether_iface/__init__.py b/src/manta/ether_iface/__init__.py deleted file mode 100644 index 042bffe..0000000 --- a/src/manta/ether_iface/__init__.py +++ /dev/null @@ -1,208 +0,0 @@ -from ..utils import * - -# Lazy and selective imports for quick builds! -from scapy.interfaces import get_if_list -from scapy.arch import get_if_hwaddr -from scapy.layers.l2 import Ether -from scapy.sendrecv import AsyncSniffer, sendp, sendpfast -from time import sleep - -from scapy.all import * - -class EthernetInterface: - def __init__(self, config): - # Warn if unrecognized options have been given - for option in config: - if option not in ["interface", "host_mac", "fpga_mac", "ethertype", "tcpreplay", "verbose"]: - print(f"Warning: Ignoring unrecognized option '{option}' in Ethernet interface.") - - # Obtain interface. - assert "interface" in config, "No interface provided for Ethernet core." - if config["interface"] not in get_if_list(): - print(f"Warning: Interface specified is not detected by the host.") - self.iface = config["interface"] - - # Obtain Host MAC address - if self.iface in get_if_list(): - self.host_mac = get_if_hwaddr(self.iface) - else: - assert "host_mac" in config, \ - "Can't automatically detect host mac address from interface, host_mac must be manually provided" - self.host_mac = config["host_mac"] - - # Obtain FPGA MAC address - # - the default address is a locally administered unicast address, - # which is an important distinction. please refer to: - # https://en.wikipedia.org/wiki/MAC_address#Ranges_of_group_and_locally_administered_addresses - self.fpga_mac = "12:34:56:78:9A:BC" - if "fpga_mac" in config: - self.fpga_mac = config["fpga_mac"] - - # Obtain Ethertype - # - the default ethertype being used is reserved for local - # experimentation by the IEEE - and might not make it beyond - # your NIC as a result. - self.ethertype = 0x88B5 - if "ethertype" in config: - self.ethertype = int(config["ethertype"], 16) - - # Set whether we use tcpreplay for faster packet blasting - if "tcpreplay" in config: - assert isinstance(config["tcpreplay"], bool), \ - "tcpreplay configuration option must be boolean!" - - if config["tcpreplay"]: - self.send_packets = lambda p: sendpfast(p, iface=self.iface) - - else: - self.send_packets = lambda p: sendp(p, iface=self.iface, verbose=0) - - else: - self.send_packets = lambda p: sendp(p, iface=self.iface, verbose=0) - - - self.verbose = False - if "verbose" in config: - assert isinstance(config["verbose"], bool), \ - "verbose configuration option must be boolean!" - self.verbose = config["verbose"] - - def read(self, addr): - # Perform type checks, output list of addresses - if isinstance(addr, int): - addrs = [addr] - - elif isinstance(addr, list): - assert all(isinstance(a, int) for a in addr), \ - "Read addresses must be integer or list of integers." - addrs = addr - - else: - raise ValueError("Read addresses must be integer or list of integers.") - - # Prepare packets with read requests - request_pkts = [] - for a in addrs: - pkt = Ether() - pkt.src = self.host_mac - pkt.dst = self.fpga_mac - pkt.type = self.ethertype - - # one byte of rw, two bytes of address, and 44 of padding - # makes the 46 byte minimum length - msg = b'\x00' + a.to_bytes(2, 'big') + 43*b'\x00' - - pkt = pkt / msg - pkt.load = msg - request_pkts.append(pkt) - - # Start sniffer in another thread, send packets, grab responses - sniffer = AsyncSniffer(iface = self.iface, count = len(addrs), filter=f"ether src {self.fpga_mac}") - sniffer.start() - sleep(0.5) - self.send_packets(request_pkts) - sniffer.join() - response_pkts = sniffer.results - assert len(response_pkts) == len(request_pkts), "Received wrong number of packets!" - - # Get read data by pulling bytes 3 and 4 from the returned packets - # payload, and interpreting it as big endian - get_read_data = lambda x: int.from_bytes(bytes(x.payload)[3:5], 'big') - read_data = [get_read_data(pkt) for pkt in response_pkts] - - if len(read_data) == 1: - return read_data[0] - - else: - return read_data - - def write(self, addr, data): - # Perform type checks, output list of addresses - if isinstance(addr, int): - assert isinstance(data, int), \ - "Data must also be integer if address is integer." - addrs = [addr] - datas = [data] - - elif isinstance(addr, list): - assert all(isinstance(a, int) for a in addr), \ - "Write addresses must be integer or list of integers." - - assert all(isinstance(d, int) for d in data), \ - "Write data must be integer or list of integers." - - assert len(addr) == len(data), \ - "There must be equal number of write addresses and data." - - addrs = addr - datas = data - - else: - raise ValueError("Write addresses and data must be integer or list of integers.") - - # Prepare packets with write requests - request_pkts = [] - for a, d in zip(addrs, datas): - pkt = Ether() - pkt.src = self.host_mac - pkt.dst = self.fpga_mac - pkt.type = self.ethertype - - # one byte of rw, two bytes of address, two bytes of data, and 42 of padding - # makes the 46 byte minimum length - msg = b'\x01' + a.to_bytes(2, 'big') + d.to_bytes(2, 'big') + 41*b'\x00' - - pkt = pkt / msg - pkt.load = msg - request_pkts.append(pkt) - - self.send_packets(request_pkts) - - def hdl_top_level_ports(self): - return ["input wire crsdv", \ - "input wire [1:0] rxd", \ - "output reg txen", \ - "output reg [1:0] txd"] - - def rx_hdl_def(self): - tx = VerilogManipulator("ether_iface/ethernet_rx.v").get_hdl() + "\n" - tx += VerilogManipulator("ether_iface/mac_rx.v").get_hdl() + "\n" - tx += VerilogManipulator("ether_iface/ether.v").get_hdl() + "\n" - tx += VerilogManipulator("ether_iface/bitorder.v").get_hdl() + "\n" - tx += VerilogManipulator("ether_iface/firewall.v").get_hdl() + "\n" - tx += VerilogManipulator("ether_iface/aggregate.v").get_hdl() + "\n" - tx += VerilogManipulator("ether_iface/crc32.v").get_hdl() + "\n" - tx += VerilogManipulator("ether_iface/cksum.v").get_hdl() + "\n" - return tx - - def tx_hdl_def(self): - tx = VerilogManipulator("ether_iface/ethernet_tx.v").get_hdl() + "\n" - tx += VerilogManipulator("ether_iface/mac_tx.v").get_hdl() + "\n" - tx += VerilogManipulator("ether_iface/bitorder.v").get_hdl() + "\n" - tx += VerilogManipulator("ether_iface/crc32.v").get_hdl() + "\n" - return tx - - def rx_hdl_inst(self): - rx = VerilogManipulator("ether_iface/ethernet_rx_inst_tmpl.v") - - fpga_mac_verilog_literal = "48'h" + self.fpga_mac.replace(":", "_").upper() - rx.sub(fpga_mac_verilog_literal, "/* FPGA_MAC */") - - ethertype_verilog_literal = f"16'h{self.ethertype:02X}" - rx.sub(ethertype_verilog_literal, "/* ETHERTYPE */") - - return rx.get_hdl() - - def tx_hdl_inst(self): - tx = VerilogManipulator("ether_iface/ethernet_tx_inst_tmpl.v") - - fpga_mac_verilog_literal = "48'h" + self.fpga_mac.replace(":", "_").upper() - tx.sub(fpga_mac_verilog_literal, "/* FPGA_MAC */") - - host_mac_verilog_literal = "48'h" + self.host_mac.replace(":", "_").upper() - tx.sub(host_mac_verilog_literal, "/* HOST_MAC */") - - ethertype_verilog_literal = f"16'h{self.ethertype:02X}" - tx.sub(ethertype_verilog_literal, "/* ETHERTYPE */") - - return tx.get_hdl() \ No newline at end of file diff --git a/src/manta/ether_iface/aggregate.v b/src/manta/ether_iface/aggregate.v deleted file mode 100644 index aad4e53..0000000 --- a/src/manta/ether_iface/aggregate.v +++ /dev/null @@ -1,46 +0,0 @@ -`default_nettype none -`timescale 1ns / 1ps - -/* Aggregates the first 64 bits of an incoming - * Ethernet transmission (thus shedding the FCS - * and anything else extraneous) and outputs the - * first 32 bits on an AXI bus for a single cycle. - * If the packet is not at least 64 bits long, - * nothing happens - */ - -`define AGR_MAX 56 -`define AGR_SHOW 64 - -module aggregate ( - input wire clk, - input wire [1:0] axiid, - input wire axiiv, - - output reg [55:0] axiod, - output reg axiov); - - /* A quick and dirty counter. As long as this is below - * 32, we'll dump packets into the AXI output data buffer. - * Once the counter gets to AGR_MAX, we'll assert AXI valid. - * Then we'll hang until axiiv drops - */ - - reg [31:0] counter; - - assign axiov = counter == `AGR_SHOW; - - always @(posedge clk) begin: COUNTER - if (!axiiv) counter <= 32'b0; - else counter <= counter + 2; - end - - always @(posedge clk) begin: AXIOD - if (!axiiv) axiod <= 32'b0; - else if (counter < `AGR_MAX && axiiv) - axiod[`AGR_MAX - counter - 2 +: 2] <= axiid; - end - -endmodule - -`default_nettype wire diff --git a/src/manta/ether_iface/bitorder.v b/src/manta/ether_iface/bitorder.v deleted file mode 100644 index e7ca283..0000000 --- a/src/manta/ether_iface/bitorder.v +++ /dev/null @@ -1,114 +0,0 @@ -`default_nettype none -`timescale 1ns / 1ps - -`define BO_SENDA 2'b00 -`define BO_SENDB 2'b01 -`define BO_EMPTYA 2'b10 -`define BO_EMPTYB 2'b11 - -module bitorder ( - input wire clk, - - input wire axiiv, - input wire [1:0] axiid, - - output reg [1:0] axiod, - output reg axiov); - - /* Two registers to hold data coming in off the wire, - * byte by byte. This is where we'll buffer until - * we've received a byte of data, at which point - * we'll start sending out the byte in the correct - * order using one register. Meanwhile, we'll start - * receiving into the other register - dual buffers. - */ - reg [7:0] bufa = 8'b0; - reg [7:0] bufb = 8'b0; - - /* A counter. This indicates what 'stage' we're in, - * and always refers to the index we're reading into - * in the receiving buffer or sending out of in the - * sending buffer - */ - reg [2:0] countera = 3'b0; - reg [2:0] counterb = 3'b0; - - /* Which state we're in - should we be using buffer - * A to send, buffer B to send, or neither because - * we've just come out of reset? - */ - reg [1:0] state = `BO_EMPTYB; - initial axiov = 0; - initial axiod = 0; - - always @(*) begin: AXIOV - if (state == `BO_SENDA || state == `BO_SENDB) axiov = 1'b1; - else axiov = 1'b0; - end - - always @(*) begin: AXIOD - if (state == `BO_SENDA) axiod = bufa[countera +: 2]; - else if (state == `BO_SENDB) axiod = bufb[counterb +: 2]; - else axiod = 1'b0; - end - - always @(posedge clk) begin: BUFFERIN - if (axiiv) begin - case (state) - `BO_EMPTYB, `BO_SENDB: - bufa[countera +: 2] <= axiid; - `BO_EMPTYA, `BO_SENDA: - bufb[counterb +: 2] <= axiid; - endcase - end - - else if (state == `BO_EMPTYB || state == `BO_EMPTYA) begin - bufa <= 8'b0; - bufb <= 8'b0; - end - end - - always @(posedge clk) begin: STATES - case (state) - `BO_EMPTYB: begin - if (axiiv) begin - if (countera == 3'h6) - state <= `BO_SENDA; - else countera <= countera + 2; - end else countera <= 3'b0; - end - - `BO_EMPTYA: begin - if (axiiv) begin - if (counterb == 3'h6) - state <= `BO_SENDB; - else counterb <= counterb + 2; - end else counterb <= 3'b0; - end - - `BO_SENDB: begin - if (counterb == 3'h0) state <= `BO_EMPTYB; - else counterb <= counterb - 2; - - if (axiiv) begin - if (countera == 3'h6) - state <= `BO_SENDA; - else countera <= countera + 2; - end - end - - `BO_SENDA: begin - if (countera == 3'h0) state <= `BO_EMPTYA; - else countera <= countera - 2; - - if (axiiv) begin - if (counterb == 3'h6) - state <= `BO_SENDB; - else counterb <= counterb + 2; - end - end - endcase - end -endmodule - -`default_nettype wire diff --git a/src/manta/ether_iface/cksum.v b/src/manta/ether_iface/cksum.v deleted file mode 100644 index a1b823b..0000000 --- a/src/manta/ether_iface/cksum.v +++ /dev/null @@ -1,80 +0,0 @@ -`default_nettype none -`timescale 1ns / 1ps - -/* Computes the ethernet checksum - * The following combinations of `done` and `kill` - * represent the state of the module: - * - * - done = 0, kill = 0: processing data or freshly reset - * - done = 1, kill = 0: correct ethernet checksum verified - * - done = 1, kill = 1: data valid set to zero before correct - * checksum value computed, therefore bad checksum - * - done = 0, kill = 1: never asserted - * - * the done and/or kill signals are asserted high beginning - * the cycle after input data ceases, and until new data - * is received via the AXI input - */ - -`define CK_FRESH 2'b00 -`define CK_COMPUTING 2'b01 -`define CK_DONE 2'b10 - -`define MAGIC_CHECK 32'h38_fb_22_84 - -module cksum ( - input wire clk, - input wire [1:0] axiid, - input wire axiiv, - - output reg done, - output reg kill); - - reg [31:0] crcd; - reg crcv; - - /* Decoupled logic to reset the CRC module independently - * Used to compute multiple CRCs back to back - */ - reg crcrst; - - reg [1:0] state = `CK_FRESH; - initial done = 0; - initial kill = 0; - initial crcrst = 0; - - crc32 cksum( - .clk(clk), - .rst(crcrst), - .axiiv(axiiv), - .axiid(axiid), - .axiov(crcv), - .axiod(crcd)); - - always @(posedge clk) begin: OUTPUTS - if (axiiv) begin - done <= 1'b0; - kill <= 1'b0; - crcrst <= 1'b0; - end else begin - if (state == `CK_COMPUTING && !axiiv) begin - done <= 1'b1; - crcrst <= 1'b1; - kill <= (crcd != `MAGIC_CHECK); - end - - else crcrst <= 1'b0; - end - end - - always @(posedge clk) begin: FSM - case (state) - `CK_FRESH: if (axiiv) state <= `CK_COMPUTING; - `CK_COMPUTING: if (!axiiv) state <= `CK_DONE; - `CK_DONE: if (axiiv) state <= `CK_COMPUTING; - endcase - end - -endmodule - -`default_nettype wire diff --git a/src/manta/ether_iface/crc32.v b/src/manta/ether_iface/crc32.v deleted file mode 100644 index 51e4397..0000000 --- a/src/manta/ether_iface/crc32.v +++ /dev/null @@ -1,70 +0,0 @@ -`default_nettype none -`timescale 1ns / 1ps - -`define LAGGING_SHIFT_IN (caxiod[30] ^ axiid[1]) -`define LEADING_SHIFT_IN (caxiod[31] ^ axiid[0]) -`define DOUBLED_SHIFT_IN (`LEADING_SHIFT_IN ^ `LAGGING_SHIFT_IN) - -`define LAGGING_TAPS 4, 7, 10, 16, 22, 26 -`define DOUBLED_TAPS 2, 5, 8, 11, 12, 23 -`define LEADING_TAPS 3, 6, 9, 13, 17, 24, 27 - -/* this module implements CRC32-BZIP2, with a two bit input: - * - poly 0x04C11DB7 - * - init 0xFFFFFFFF - * - NEW: XOR outputs - * - * == check: 0xfc891918 == - * - * this is the ethernet checksum!! - */ - -module crc32( - input wire clk, - input wire rst, - input wire axiiv, - input wire [1:0] axiid, - - output reg axiov, - output reg [31:0] axiod); - - reg [31:0] caxiod, saxiod; - initial caxiod = 32'hFFFF_FFFF; - integer i; - - assign axiov = 1; - assign axiod = ~caxiod; - - always @(*) begin - for (i = 0; i < 32; i = i + 1) begin - case (i) - 0: saxiod[i] = `LAGGING_SHIFT_IN; - 1: saxiod[i] = `DOUBLED_SHIFT_IN; - - `LAGGING_TAPS: - saxiod[i] = caxiod[i - 2] ^ `LAGGING_SHIFT_IN; - `DOUBLED_TAPS: - saxiod[i] = caxiod[i - 2] ^ `DOUBLED_SHIFT_IN; - `LEADING_TAPS: - saxiod[i] = caxiod[i - 2] ^ `LEADING_SHIFT_IN; - - default: saxiod[i] = caxiod[i - 2]; - endcase - end - end - - always @(posedge clk) begin - if (rst) caxiod <= 32'hFFFF_FFFF; - - /* our output validity hinges on whether - * we are calculating anything or not - * on this clock cycle. if there is no - * valid input for us, don't do a shift - * this cycle - */ - else caxiod <= (axiiv) ? saxiod : caxiod; - end - -endmodule - -`default_nettype wire diff --git a/src/manta/ether_iface/ether.v b/src/manta/ether_iface/ether.v deleted file mode 100644 index 56ad986..0000000 --- a/src/manta/ether_iface/ether.v +++ /dev/null @@ -1,77 +0,0 @@ -`default_nettype none -`timescale 1ns / 1ps - -`define EF_IDLE 3'b000 -`define EF_PREAM 3'b001 -`define EF_DATA 3'b011 -`define EF_BAD 3'b101 - -`define PREAM_BITS 64 -`define PREAM_SIZE (`PREAM_BITS / 2) - -`define PREAM_FIRST 2'b00 -`define PREAM_EXPECT 2'b01 -`define PREAM_LAST 2'b11 -`define PREAM_BAD 2'b10 - -module ether ( - input wire clk, - input wire [1:0] rxd, - input wire crsdv, - - output reg axiov, - output reg [1:0] axiod); - - reg [4:0] count; - reg [2:0] state; - - reg [1:0] preamex; - reg preamok, start; - - always @(*) begin: PREAM - if (count == `PREAM_SIZE - 1) preamex = `PREAM_LAST; - else preamex = `PREAM_EXPECT; - - preamok = crsdv && rxd == preamex; - end - - always @(*) start = crsdv && rxd != `PREAM_FIRST; - - always @(posedge clk) begin: COUNT - if (state == `EF_PREAM) count <= count + 1; - else if (state == `EF_IDLE && start) count <= count + 1; - else count <= 0; - end - - initial begin - axiod = 2'b0; - axiov = 1'b0; - state = 3'b0; - end - - always @(posedge clk) begin: FSM - case (state) - `EF_BAD: if (!crsdv) state <= `EF_IDLE; - `EF_IDLE: if (start) state <= `EF_PREAM; - - `EF_PREAM: begin - if (!preamok || !crsdv) state <= `EF_BAD; - else if (count == `PREAM_SIZE - 1) - state <= `EF_DATA; - end - - `EF_DATA: begin - if (crsdv) begin - axiov <= 1'b1; - axiod <= rxd; - end else begin - axiov <= 1'b0; - axiod <= 2'b0; - state <= `EF_IDLE; - end - end - endcase - end -endmodule - -`default_nettype wire diff --git a/src/manta/ether_iface/ethernet_rx.v b/src/manta/ether_iface/ethernet_rx.v deleted file mode 100644 index ba36ec7..0000000 --- a/src/manta/ether_iface/ethernet_rx.v +++ /dev/null @@ -1,41 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -module ethernet_rx ( - input wire clk, - - input wire crsdv, - input wire [1:0] rxd, - - output reg [15:0] addr_o, - output reg [15:0] data_o, - output reg rw_o, - output reg valid_o - ); - - parameter FPGA_MAC = 0; - parameter ETHERTYPE = 0; - - reg [55:0] payload; - reg valid; - - mac_rx #( - .FPGA_MAC(FPGA_MAC), - .ETHERTYPE(ETHERTYPE) - ) mrx ( - .clk(clk), - - .crsdv(crsdv), - .rxd(rxd), - - .payload(payload), - .valid(valid)); - - assign rw_o = (payload[39:32] == 8'd1); - assign addr_o = payload[31:16]; - assign data_o = payload[15:0]; - assign valid_o = valid && ( payload[39:32] == 8'd0 || payload[39:32] == 8'd1) && (payload[55:40] == 16'h88B5); - -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/src/manta/ether_iface/ethernet_rx_inst_tmpl.v b/src/manta/ether_iface/ethernet_rx_inst_tmpl.v deleted file mode 100644 index 7eae02b..0000000 --- a/src/manta/ether_iface/ethernet_rx_inst_tmpl.v +++ /dev/null @@ -1,13 +0,0 @@ -ethernet_rx #( - .FPGA_MAC(/* FPGA_MAC */), - .ETHERTYPE(/* ETHERTYPE */) -) erx ( - .clk(clk), - - .crsdv(crsdv), - .rxd(rxd), - - .addr_o(), - .data_o(), - .rw_o(), - .valid_o()); \ No newline at end of file diff --git a/src/manta/ether_iface/ethernet_tx.v b/src/manta/ether_iface/ethernet_tx.v deleted file mode 100644 index 318b3ba..0000000 --- a/src/manta/ether_iface/ethernet_tx.v +++ /dev/null @@ -1,40 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -module ethernet_tx ( - input wire clk, - - input wire [15:0] data_i, - input wire rw_i, - input wire valid_i, - - output reg txen, - output reg [1:0] txd - ); - - parameter FPGA_MAC = 0; - parameter HOST_MAC = 0; - parameter ETHERTYPE = 0; - - reg [15:0] data_buf = 0; - - always @(posedge clk) - if(~rw_i && valid_i) data_buf <= data_i; - - mac_tx #( - .SRC_MAC(FPGA_MAC), - .DST_MAC(HOST_MAC), - .ETHERTYPE(ETHERTYPE), - .PAYLOAD_LENGTH_BYTES(5) - ) mtx ( - .clk(clk), - - .payload({24'd0, data_buf}), - .start(~rw_i && valid_i), - - .txen(txen), - .txd(txd)); - -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/src/manta/ether_iface/ethernet_tx_inst_tmpl.v b/src/manta/ether_iface/ethernet_tx_inst_tmpl.v deleted file mode 100644 index 6082910..0000000 --- a/src/manta/ether_iface/ethernet_tx_inst_tmpl.v +++ /dev/null @@ -1,13 +0,0 @@ -ethernet_tx #( - .FPGA_MAC(/* FPGA_MAC */), - .HOST_MAC(/* HOST_MAC */), - .ETHERTYPE(/* ETHERTYPE */) -) etx ( - .clk(clk), - - .data_i(), - .rw_i(), - .valid_i(), - - .txen(txen), - .txd(txd)); \ No newline at end of file diff --git a/src/manta/ether_iface/firewall.v b/src/manta/ether_iface/firewall.v deleted file mode 100644 index 611e310..0000000 --- a/src/manta/ether_iface/firewall.v +++ /dev/null @@ -1,80 +0,0 @@ -`default_nettype none -`timescale 1ns / 1ps - -`define FW_DESTSTART 0 -`define FW_DESTEND (`FW_DESTSTART + 48) - -`define FW_DATASTART (48 + 48) - -module firewall ( - input wire clk, - input wire axiiv, - input wire [1:0] axiid, - - output reg axiov, - output reg [1:0] axiod); - - parameter ETHERTYPE = 0; - parameter FPGA_MAC = 0; - - /* Buffers to hold our MAC address in the reverse order, - * to make comparison easier than it otherwise would be - */ - reg [0:47] me; - - /* A counter, to determine whether we should be comparing - * with a MAC address or stripping off data - */ - reg [31:0] counter; - - /* An internal set of flags to mark whether the currently - * traversing packet is valid, i.e we should forward data, - * or not. One of these flags tracks whether the destination - * MAC address matches _our_ (FW_ME) mac address, the other - * tracks whether the destination matches the broadcast - * (FW_BCAST) MAC. If either one of these is high once the - * destination MAC finishes rolling through, the packet - * is forwarded. - */ - reg matchme, matchbcast; - - assign me = FPGA_MAC; - - always @(posedge clk) begin: MATCH - if (counter == 32'b0) begin - matchme <= 1'b1; - matchbcast <= 1'b1; - end - - /* could overwrite the above, which is ideal if - * FW_DESTSTART == 0 (it is) and we have a mismatch - * out the gate - */ - if (counter >= `FW_DESTSTART && counter < `FW_DESTEND) begin - if (axiiv) begin - if (axiid != {me[counter], me[counter + 1]}) - matchme <= 1'b0; - if (axiid != 2'b11) - matchbcast <= 1'b0; - end - end - end - - always @(*) begin: AXIOUT - if (counter >= `FW_DATASTART && (matchme | matchbcast)) begin - axiod = axiid; - axiov = axiiv; - end else begin - axiod = 2'b00; - axiov = 1'b0; - end - end - - always @(posedge clk) begin: COUNTER - if (axiiv) counter <= counter + 2; - else counter <= 32'b0; - end - -endmodule - -`default_nettype wire diff --git a/src/manta/ether_iface/mac_rx.v b/src/manta/ether_iface/mac_rx.v deleted file mode 100644 index 46ff330..0000000 --- a/src/manta/ether_iface/mac_rx.v +++ /dev/null @@ -1,106 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -module mac_rx ( - input wire clk, - - input wire crsdv, - input wire [1:0] rxd, - - output reg [55:0] payload, - output reg valid); - - parameter FPGA_MAC = 0; - parameter ETHERTYPE = 0; - - reg [1:0] ether_axiod; - reg ether_axiov; - - ether e ( - .clk(clk), - .rxd(rxd), - .crsdv(crsdv), - .axiov(ether_axiov), - .axiod(ether_axiod)); - - reg [1:0] bitorder_axiod; - reg bitorder_axiov; - - bitorder b ( - .clk(clk), - .axiiv(ether_axiov), - .axiid(ether_axiod), - .axiov(bitorder_axiov), - .axiod(bitorder_axiod)); - - reg [1:0] firewall_axiod; - reg firewall_axiov; - - firewall #( - .FPGA_MAC(FPGA_MAC), - .ETHERTYPE(ETHERTYPE) - ) f ( - .clk(clk), - .axiiv(bitorder_axiov), - .axiid(bitorder_axiod), - .axiov(firewall_axiov), - .axiod(firewall_axiod)); - - reg [55:0] aggregate_axiod; - reg aggregate_axiov; - - aggregate a ( - .clk(clk), - .axiiv(firewall_axiov), - .axiid(firewall_axiod), - .axiov(aggregate_axiov), - .axiod(aggregate_axiod)); - - reg cksum_done; - reg cksum_kill; - - cksum c ( - .clk(clk), - .axiiv(ether_axiov), - .axiid(ether_axiod), - .done(cksum_done), - .kill(cksum_kill)); - - // state machine - localparam IDLE = 0; - localparam WAIT_FOR_DATA = 1; - localparam WAIT_FOR_FCS = 2; - - reg [1:0] state = IDLE; - - initial valid = 0; - initial payload = 0; - - always @(posedge clk) begin - valid <= 0; - - if(state == IDLE) begin - if(crsdv) state <= WAIT_FOR_DATA; - end - - else if(state == WAIT_FOR_DATA) begin - if(aggregate_axiov) begin - state <= WAIT_FOR_FCS; - payload <= aggregate_axiod; - end - - // if aggregate never gives us data, - // go back to idle when the packet ends - else if(cksum_done) state <= IDLE; - end - - else if(state == WAIT_FOR_FCS) begin - if(cksum_done) begin - state <= IDLE; - valid <= ~cksum_kill; - end - end - end -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/src/manta/ether_iface/mac_tx.v b/src/manta/ether_iface/mac_tx.v deleted file mode 100644 index 812c078..0000000 --- a/src/manta/ether_iface/mac_tx.v +++ /dev/null @@ -1,242 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -module mac_tx ( - input wire clk, - - input wire [(8 * PAYLOAD_LENGTH_BYTES)-1:0] payload, - input wire start, - - output reg txen, - output reg [1:0] txd); - - // packet magic numbers - localparam PREAMBLE = {7{8'b01010101}}; - localparam SFD = 8'b11010101; - parameter [47:0] SRC_MAC = 0; - parameter [47:0] DST_MAC = 0; - parameter [15:0] ETHERTYPE = 0; - parameter PAYLOAD_LENGTH_BYTES = 0; - - // all lengths are in units of dibits, hence all the mulitplies by four - localparam PREAMBLE_LEN = 7 * 4; - localparam SFD_LEN = 1 * 4; - localparam SRC_MAC_LEN = 6 * 4; - localparam DST_MAC_LEN = 6 * 4; - localparam ETHERTYPE_LEN = 2 * 4; - localparam PAYLOAD_LEN = PAYLOAD_LENGTH_BYTES * 4; - localparam ZERO_PAD_LEN = (46 * 4) - PAYLOAD_LEN + 4; // minimum payload size is 46 bytes - localparam FCS_LEN = 4 * 4; - localparam IPG_LEN = 96 / 2; - - reg [1:0] bitorder_axiid; - reg [1:0] bitorder_axiod; - reg bitorder_axiiv; - reg bitorder_axiov; - - bitorder bitorder ( - .clk(clk), - - .axiiv(bitorder_axiiv), - .axiid(bitorder_axiid), - - .axiov(bitorder_axiov), - .axiod(bitorder_axiod)); - - reg crc_rst = 1; - reg crc_axiiv = 0; - reg [31:0] crc_axiod; - - crc32 crc ( - .clk(clk), - .rst(crc_rst), - - .axiiv(crc_axiiv), - .axiid(bitorder_axiod), - - // TODO: remove axiov from crc32 module, it's always valid - .axiov(), - .axiod(crc_axiod)); - - - // state machine - reg [8:0] counter = 0; - reg [3:0] state = 0; - - localparam IDLE_STATE = 0; - localparam PREAMBLE_STATE = 1; - localparam SFD_STATE = 2; - localparam DST_MAC_STATE = 3; - localparam SRC_MAC_STATE = 4; - localparam ETHERTYPE_STATE = 5; - localparam PAYLOAD_STATE = 6; - localparam ZERO_PAD_STATE = 7; - localparam FCS_STATE = 8; - localparam IPG_STATE = 9; - - - // sequential logic manages the state machine - always @(posedge clk) begin - counter <= counter + 1; - crc_rst <= 0; - - if(state == IDLE_STATE) begin - counter <= 0; - crc_axiiv <= 0; - if(start) state <= PREAMBLE_STATE; - end - - else if(state == PREAMBLE_STATE) begin - if(counter == PREAMBLE_LEN - 1) begin - counter <= 0; - state <= SFD_STATE; - end - end - - else if(state == SFD_STATE) begin - if(counter == SFD_LEN - 1) begin - counter <= 0; - state <= DST_MAC_STATE; - end - end - - else if(state == DST_MAC_STATE) begin - // this is because the crc module lags behind the FSM, - // as it has to go through bitorder first - if(counter == 3) crc_axiiv <= 1; - - if(counter == DST_MAC_LEN - 1) begin - counter <= 0; - state <= SRC_MAC_STATE; - end - end - - else if(state == SRC_MAC_STATE) begin - if(counter == SRC_MAC_LEN - 1) begin - counter <= 0; - state <= ETHERTYPE_STATE; - end - end - - else if(state == ETHERTYPE_STATE) begin - if(counter == ETHERTYPE_LEN - 1) begin - counter <= 0; - state <= PAYLOAD_STATE; - end - end - - else if(state == PAYLOAD_STATE) begin - if(counter == PAYLOAD_LEN - 1) begin - counter <= 0; - state <= ZERO_PAD_STATE; - end - end - - else if(state == ZERO_PAD_STATE) begin - if(counter == ZERO_PAD_LEN - 1) begin - crc_axiiv <= 0; - counter <= 0; - state <= FCS_STATE; - end - end - - else if(state == FCS_STATE) begin - if(counter == FCS_LEN - 1) begin - counter <= 0; - state <= IPG_STATE; - end - end - - else if(state == IPG_STATE) begin - if(counter == IPG_LEN - 1) begin - crc_rst <= 1; - counter <= 0; - state <= IDLE_STATE; - end - end - end - - // combinational logic handles the pipeline - always @(*) begin - case (state) - IDLE_STATE: begin - bitorder_axiiv = 0; - bitorder_axiid = 0; - txen = 0; - txd = 0; - end - - PREAMBLE_STATE: begin - bitorder_axiiv = 1; - bitorder_axiid = PREAMBLE[2*(PREAMBLE_LEN-counter)-1-:2]; - txen = bitorder_axiov; - txd = bitorder_axiod; - end - - SFD_STATE: begin - bitorder_axiiv = 1; - bitorder_axiid = SFD[2*(SFD_LEN-counter)-1-:2]; - txen = bitorder_axiov; - txd = bitorder_axiod; - end - - DST_MAC_STATE: begin - bitorder_axiiv = 1; - bitorder_axiid = DST_MAC[2*(DST_MAC_LEN-counter)-1-:2]; - txen = bitorder_axiov; - txd = bitorder_axiod; - end - - SRC_MAC_STATE: begin - bitorder_axiiv = 1; - bitorder_axiid = SRC_MAC[2*(SRC_MAC_LEN-counter)-1-:2]; - txen = bitorder_axiov; - txd = bitorder_axiod; - end - - ETHERTYPE_STATE: begin - bitorder_axiiv = 1; - bitorder_axiid = ETHERTYPE[2*(ETHERTYPE_LEN-counter)-1-:2]; - txen = bitorder_axiov; - txd = bitorder_axiod; - end - - PAYLOAD_STATE: begin - bitorder_axiiv = 1; - bitorder_axiid = payload[2*(PAYLOAD_LEN-counter)-1-:2]; - txen = bitorder_axiov; - txd = bitorder_axiod; - end - - ZERO_PAD_STATE: begin - bitorder_axiiv = 1; - bitorder_axiid = 0; - txen = bitorder_axiov; - txd = bitorder_axiod; - end - - FCS_STATE: begin - bitorder_axiiv = 0; - bitorder_axiid = 0; - txen = 1; - txd = {crc_axiod[2*(FCS_LEN-counter)-2], crc_axiod[2*(FCS_LEN-counter)-1]}; - end - - IPG_STATE: begin - bitorder_axiiv = 0; - bitorder_axiid = 0; - txen = 0; - txd = 0; - end - - default: begin - bitorder_axiiv = 0; - bitorder_axiid = 0; - txen = 0; - txd = 0; - end - endcase - end -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/src/manta/io_core.py b/src/manta/io_core.py new file mode 100644 index 0000000..97d869f --- /dev/null +++ b/src/manta/io_core.py @@ -0,0 +1,260 @@ +from amaranth import * +from warnings import warn +from .utils import * +from math import ceil + + +class IOCore(Elaboratable): + """ + Contains the HDL to instantiate an IO core on a FPGA, and the functions to interact with it. For + more information on the core itself, check out the IO core documentation. + """ + + def __init__(self, config, base_addr, interface): + self.config = config + self.base_addr = base_addr + self.interface = interface + + self.check_config(self.config) + self.define_signals() + self.mmap, self.max_addr = self.assign_memory() + + def check_config(self, config): + # make sure ports are defined + if "inputs" not in config and "outputs" not in config: + raise ValueError("No input or output ports specified.") + + # check for unrecognized options + valid_options = ["type", "inputs", "outputs", "user_clock"] + for option in config: + if option not in valid_options: + warn(f"Ignoring unrecognized option '{option}' in IO core.'") + + # check that user_clock is a bool + if "user_clock" in config: + if not isinstance(config["user_clock"], bool): + raise ValueError("Option user_clock must be a boolean.") + + # check that inputs is only dicts of format name:width + if "inputs" in config: + for name, attrs in config["inputs"].items(): + if not isinstance(name, str): + raise ValueError( + f'Input probe "{name}" has invalid name, names must be strings.' + ) + + if not isinstance(attrs, int): + raise ValueError(f'Input probe "{name}" must have integer width.') + + if not attrs > 0: + raise ValueError(f'Input probe "{name}" must have positive width.') + + if "outputs" in config: + for name, attrs in config["outputs"].items(): + if not isinstance(name, str): + raise ValueError( + f'Output probe "{name}" has invalid name, names must be strings.' + ) + + if not isinstance(attrs, int) and not isinstance(attrs, dict): + raise ValueError(f'Unrecognized format for output probe "{name}".') + + if isinstance(attrs, int): + if not attrs > 0: + raise ValueError( + f'Output probe "{name}" must have positive width.' + ) + + if isinstance(attrs, dict): + # check that each output probe has only recognized options + valid_options = ["width", "initial_value"] + for option in attrs: + if option not in valid_options: + warn(f'Ignoring unrecognized option "{option}" in IO core.') + + # check that widths are appropriate + if "width" not in attrs: + raise ValueError(f"No width specified for output probe {name}.") + + if not isinstance(attrs["width"], int): + raise ValueError( + f'Output probe "{name}" must have integer width.' + ) + + if not attrs["width"] > 0: + raise ValueError( + f'Input probe "{name}" must have positive width.' + ) + + def define_signals(self): + # Bus Ports + self.addr_i = Signal(16) + self.data_i = Signal(16) + self.rw_i = Signal() + self.valid_i = Signal() + + self.addr_o = Signal(16) + self.data_o = Signal(16) + self.rw_o = Signal() + self.valid_o = Signal() + + # Input Probes (and buffers) + if "inputs" in self.config: + for name, width in self.config["inputs"].items(): + setattr(self, name, Signal(width, name=name)) + setattr(self, name + "_buf", Signal(width, name=name + "_buf")) + + # Output Probes (and buffers) + if "outputs" in self.config: + for name, attrs in self.config["outputs"].items(): + if isinstance(attrs, dict): + width = attrs["width"] + initial_value = attrs["initial_value"] + else: + width = attrs + initial_value = 0 + + setattr(self, name, Signal(width, name=name, reset=initial_value)) + setattr( + self, + name + "_buf", + Signal(width, name=name + "_buf", reset=initial_value), + ) + + # Strobe Register + self.strobe = Signal(reset=0) + + def assign_memory(self): + """ + the memory map is a dict that maps registers (in memory) to their locations (in memory) + as well as their Signals (from Amaranth). This looks like the following: + + { + strobe: + addrs: [0x0000] + signals: [self.strobe] + probe0_buf: + addrs: [0x0001] + signals: [self.probe0_buf] + probe1_buf: + addrs: [0x0002] + signals: [self.probe1_buf] + probe2_buf: + addrs: [0x0003] + signals: [self.probe2_buf] + probe3_buf: + addrs: [0x0004, 0x0005] + signals: [self.probe3_buf[0:15], self.probe3_buf[16:19]] + ... and so on + } + + """ + mmap = {} + + # Add strobe register first + mmap["strobe"] = dict(addrs=[self.base_addr], signals=[self.strobe]) + + # Add all input and output probes + all_probes = {} + if "inputs" in self.config: + all_probes = {**all_probes, **self.config["inputs"]} + + if "outputs" in self.config: + all_probes = {**all_probes, **self.config["outputs"]} + + for name, attrs in all_probes.items(): + # Handle output probes that might have initial value specified in addition to width + if isinstance(attrs, dict): + width = attrs["width"] + else: + width = attrs + + # Assign addresses + last_used_addr = list(mmap.values())[-1]["addrs"][-1] + addrs = [last_used_addr + 1 + i for i in range(ceil(width / 16))] + + # Slice signal into 16-bit chunks + signal = getattr(self, name + "_buf") + signals = [signal[16 * i : 16 * (i + 1)] for i in range(ceil(width / 16))] + + mmap[name + "_buf"] = {"addrs": addrs, "signals": signals} + + # Compute maximum address used by the core + max_addr = list(mmap.values())[-1]["addrs"][-1] + return mmap, max_addr + + def elaborate(self, platform): + m = Module() + + # Shuffle bus transactions along + m.d.sync += self.addr_o.eq(self.addr_i) + m.d.sync += self.data_o.eq(self.data_i) + m.d.sync += self.rw_o.eq(self.rw_i) + m.d.sync += self.valid_o.eq(self.valid_i) + + # Update buffers from probes + with m.If(self.strobe): + # Input buffers + if "inputs" in self.config: + for name in self.config["inputs"]: + input_probe = getattr(self, name) + input_probe_buf = getattr(self, name + "_buf") + m.d.sync += input_probe_buf.eq(input_probe) + + # Output buffers + if "outputs" in self.config: + for name in self.config["outputs"]: + output_probe = getattr(self, name) + output_probe_buf = getattr(self, name + "_buf") + m.d.sync += output_probe.eq(output_probe_buf) + + # Handle register reads and writes + with m.If((self.addr_i >= self.base_addr)): + with m.If((self.addr_o <= self.max_addr)): + for entry in self.mmap.values(): + for addr, signal in zip(entry["addrs"], entry["signals"]): + with m.If(self.rw_i): + with m.If(self.addr_i == addr): + m.d.sync += signal.eq(self.data_i) + + with m.Else(): + with m.If(self.addr_i == addr): + m.d.sync += self.data_o.eq(signal) + + return m + + def get_top_level_ports(self): + ports = [] + for name in self.config["inputs"].keys(): + ports.append(getattr(self, name)) + + for name in self.config["outputs"].keys(): + ports.append(getattr(self, name)) + + return ports + + def get_max_addr(self): + return self.max_addr + + def set_probe(self, probe_name, value): + # set value in buffer + addrs = self.mmap[probe_name + "_buf"]["addrs"] + datas = value_to_words(value, len(addrs)) + self.interface.write(addrs, datas) + + # pulse strobe register + strobe_addr = self.mmap["strobe"]["addrs"][0] + self.interface.write(strobe_addr, 0) + self.interface.write(strobe_addr, 1) + self.interface.write(strobe_addr, 0) + + def get_probe(self, probe_name): + # pulse strobe register + strobe_addr = self.mmap["strobe"]["addrs"][0] + self.interface.write(strobe_addr, 0) + self.interface.write(strobe_addr, 1) + self.interface.write(strobe_addr, 0) + + # get value from buffer + addrs = self.mmap[probe_name + "_buf"]["addrs"] + return words_to_value(self.interface.read(addrs)) diff --git a/src/manta/io_core/__init__.py b/src/manta/io_core/__init__.py deleted file mode 100644 index 8e33562..0000000 --- a/src/manta/io_core/__init__.py +++ /dev/null @@ -1,213 +0,0 @@ -from ..utils import * -from math import ceil - -class InputProbe: - def __init__(self, name, width, base_addr, strobe_addr, interface): - assert isinstance(width, int), f"Probe {name} must have integer width." - assert width > 0, f"Probe {name} must have positive width." - - self.name = name - self.width = width - self.strobe_addr = strobe_addr - self.interface = interface - - n_addrs = ceil(self.width / 16) - self.addrs = list(range(base_addr, base_addr + n_addrs)) - self.brackets = "" if self.width == 1 else f"[{self.width-1}:0] " - - def pulse_strobe_register(self): - # pulse the strobe register - self.interface.write(self.strobe_addr, 1) - self.interface.write(self.strobe_addr, 0) - strobe = self.interface.read(self.strobe_addr) - if strobe != 0: - raise ValueError("Unable to set strobe register to zero!") - - def get(self): - self.pulse_strobe_register() - return pack_16bit_words(self.interface.read(self.addrs)) - -class OutputProbe(InputProbe): - def __init__(self, name, width, base_addr, strobe_addr, interface, initial_value): - super().__init__(name, width, base_addr, strobe_addr, interface) - self.initial_value = initial_value - - def set(self, value): - # check that value is an integer - assert isinstance(value, int), "Value must be an integer." - - # check that value is within range for the width of the probe - if value > 0: - assert value <= (2**self.width) - 1, f"Unsigned value too large for probe of width {self.width}" - - elif value < 0: - assert abs(value) <= (2**(self.width-1))-1, f"Signed value too large for probe of width {self.width}" - - self.interface.write(self.addrs, unpack_16bit_words(value, len(self.addrs))) - self.pulse_strobe_register() - -class IOCore: - def __init__(self, config, name, base_addr, interface): - self.name = name - self.base_addr = base_addr - self.interface = interface - - # make sure we have ports defined - assert ('inputs' in config) or ('outputs' in config), "No input or output ports specified." - - # check for unrecognized options - for option in config: - if option not in ["type", "inputs", "outputs", "user_clock"]: - print(f"Warning: Ignoring unrecognized option '{option}' in IO core '{name}'") - - # add user clock - self.user_clock = False - if "user_clock" in config: - assert isinstance(config["user_clock"], bool), "Option user_clock must be a boolean." - self.user_clock = config["user_clock"] - - # add input probes to core - self.input_probes = [] - last_used_addr = self.base_addr # start at one since strobe register is at BASE_ADDR - if 'inputs' in config: - for name, width in config["inputs"].items(): - probe = InputProbe(name, width, last_used_addr + 1, self.base_addr, interface) - last_used_addr = probe.addrs[-1] - self.input_probes.append(probe) - - # add output probes to core - self.output_probes = [] - if 'outputs' in config: - for name, params in config["outputs"].items(): - # get width and initial value from config - if isinstance(params, int): - width = params - initial_value = 0 - - elif "width" in params and "initial_value" in params: - width = params["width"] - initial_value = params["initial_value"] - - else: - raise ValueError(f"Unable to determine probe width and initial value for {name}") - - # add probe to core - probe = OutputProbe(name, width, last_used_addr + 1, self.base_addr, interface, initial_value) - last_used_addr = probe.addrs[-1] - self.output_probes.append(probe) - - self.max_addr = last_used_addr - - # add friendly names to each probe - # (so users can do io_core.probe.set() and get() for instance) - for probe in self.input_probes + self.output_probes: - setattr(self, probe.name, probe) - - def hdl_top_level_ports(self): - ports = [] - - if self.user_clock: - ports.append(f"input wire {self.name}_user_clock") - - for probe in self.input_probes: - ports.append(f"input wire {probe.brackets}{probe.name}") - - for probe in self.output_probes: - ports.append(f"output reg {probe.brackets}{probe.name}") - - return ports - - def hdl_inst(self): - inst = VerilogManipulator("io_core/io_core_inst_tmpl.v") - inst.sub(self.name, "/* MODULE_NAME */") - inst.sub(self.name + "_inst", "/* INST_NAME */") - - # tie user_clock to bus_clk if external clock is not being used - if not self.user_clock: - inst.sub("clk", "/* USER_CLK */") - - else: - inst.sub(f"{self.name}_user_clk", "/* USER_CLK */") - - probes = {p.name:p.width for p in self.input_probes + self.output_probes} - inst_ports = inst.net_conn(probes, trailing_comma=True) - inst.sub(inst_ports, "/* INST_PORTS */") - - return inst.get_hdl() - - def hdl_def(self): - io_core = VerilogManipulator("io_core/io_core_def_tmpl.v") - io_core.sub(self.name, "/* MODULE_NAME */") - io_core.sub(self.max_addr, "/* MAX_ADDR */") - - # generate declaration - top_level_ports = ',\n'.join(self.hdl_top_level_ports()) - top_level_ports += ',' - io_core.sub(top_level_ports, "/* TOP_LEVEL_PORTS */") - - # generate memory handling - io_core.sub(self.gen_read_case_statement_body(), "/* READ_CASE_STATEMENT_BODY */") - io_core.sub(self.gen_write_case_statement_body(), "/* WRITE_CASE_STATEMENT_BODY */") - - # generate input and output probe buffers with initial values - io_core.sub(self.gen_input_probe_bufs(), "/* INPUT_PROBE_BUFFERS */") - io_core.sub(self.gen_output_probe_bufs(), "/* OUTPUT_PROBE_BUFFERS */") - io_core.sub(self.gen_output_probe_initial_values(), "/* OUTPUT_PROBE_INITIAL_VALUES */") - io_core.sub(self.gen_update_input_buffers(), "/* UPDATE_INPUT_BUFFERS */") - io_core.sub(self.gen_update_output_buffers(), "/* UPDATE_OUTPUT_BUFFERS */") - - return io_core.get_hdl() - - def gen_read_case_statement_body(self): - lines = [] - for probe in self.input_probes + self.output_probes: - if probe.width <= 16: - lines.append(f"BASE_ADDR + {probe.addrs[0]}: data_o <= {probe.name}_buf;") - - # assign 16-bit slices of each probe's buffer to each address taken by the probe - else: - for i in range(ceil(probe.width/16)): - top = ((i + 1) * 16) - 1 - btm = i * 16 - if top > probe.width - 1: - top = probe.width - 1 - lines.append(f"BASE_ADDR + {probe.addrs[i]}: data_o <= {probe.name}_buf[{top}:{btm}];") - - return '\n'.join(lines) - - def gen_write_case_statement_body(self): - lines = [] - for probe in self.output_probes: - if probe.width <= 16: - lines.append(f"BASE_ADDR + {probe.addrs[0]}: {probe.name}_buf <= data_i;") - - else: - for i in range(ceil(probe.width/16)): - top = ((i + 1) * 16) - 1 - btm = i * 16 - if top > probe.width - 1: - top = probe.width - 1 - - lines.append(f"BASE_ADDR + {probe.addrs[i]}: {probe.name}_buf[{top}:{btm}] <= data_i;") - - return '\n'.join(lines) - - def gen_input_probe_bufs(self): - lines = [f"reg {p.brackets}{p.name}_buf = 0;" for p in self.input_probes] - return '\n'.join(lines) - - def gen_output_probe_bufs(self): - lines = [f"reg {p.brackets}{p.name}_buf = {p.initial_value};" for p in self.output_probes] - return '\n'.join(lines) - - def gen_output_probe_initial_values(self): - lines = [f"{p.name} = {p.initial_value};" for p in self.output_probes] - return '\n'.join(lines) - - def gen_update_input_buffers(self): - lines = [f"{p.name}_buf <= {p.name};" for p in self.input_probes] - return '\n'.join(lines) - - def gen_update_output_buffers(self): - lines = [f"{p.name} <= {p.name}_buf;" for p in self.output_probes] - return '\n'.join(lines) diff --git a/src/manta/io_core/io_core_def_tmpl.v b/src/manta/io_core/io_core_def_tmpl.v deleted file mode 100644 index 5803486..0000000 --- a/src/manta/io_core/io_core_def_tmpl.v +++ /dev/null @@ -1,77 +0,0 @@ -module /* MODULE_NAME */ ( - input wire bus_clk, - input wire user_clk, - - // ports - /* TOP_LEVEL_PORTS */ - - // input port - input wire [15:0] addr_i, - input wire [15:0] data_i, - input wire rw_i, - input wire valid_i, - - // output port - output reg [15:0] addr_o, - output reg [15:0] data_o, - output reg rw_o, - output reg valid_o - ); - - parameter BASE_ADDR = 0; - - reg strobe = 0; - - // input probe buffers - /* INPUT_PROBE_BUFFERS */ - - // output probe buffers - /* OUTPUT_PROBE_BUFFERS */ - - // output probe initial values - initial begin - /* OUTPUT_PROBE_INITIAL_VALUES */ - end - - // synchronize buffers and probes on strobe - always @(posedge user_clk) begin - if(strobe) begin - // update input buffers from input probes - /* UPDATE_INPUT_BUFFERS */ - - // update output buffers from output probes - /* UPDATE_OUTPUT_BUFFERS */ - end - end - - // handle bus operations - always @(posedge bus_clk) begin - addr_o <= addr_i; - data_o <= data_i; - rw_o <= rw_i; - valid_o <= valid_i; - - // check if address is valid - if( (valid_i) && (addr_i >= BASE_ADDR) && (addr_i <= BASE_ADDR + /* MAX_ADDR */)) begin - - // reads - if(!rw_i) begin - case (addr_i) - BASE_ADDR + 0: data_o <= strobe; - - /* READ_CASE_STATEMENT_BODY */ - endcase - end - - // writes - else begin - case (addr_i) - BASE_ADDR + 0: strobe <= data_i; - - /* WRITE_CASE_STATEMENT_BODY */ - endcase - end - end - end - -endmodule \ No newline at end of file diff --git a/src/manta/io_core/io_core_inst_tmpl.v b/src/manta/io_core/io_core_inst_tmpl.v deleted file mode 100644 index 4568ef0..0000000 --- a/src/manta/io_core/io_core_inst_tmpl.v +++ /dev/null @@ -1,18 +0,0 @@ -/* MODULE_NAME */ /* INST_NAME */ ( - .bus_clk(clk), - .user_clk(/* USER_CLK */), - - // ports - /* INST_PORTS */ - - // input port - .addr_i(), - .data_i(), - .rw_i(), - .valid_i(), - - // output port - .addr_o(), - .data_o(), - .rw_o(), - .valid_o()); \ No newline at end of file diff --git a/src/manta/la_core/__init__.py b/src/manta/la_core/__init__.py deleted file mode 100644 index a33c307..0000000 --- a/src/manta/la_core/__init__.py +++ /dev/null @@ -1,463 +0,0 @@ -from ..utils import * - -from datetime import datetime -from pkg_resources import get_distribution -import math -import os - -class LogicAnalyzerCore: - def __init__(self, config, name, base_addr, interface): - self.name = name - self.base_addr = base_addr - self.interface = interface - - # Warn if unrecognized options have been given - valid_options = ["type", "sample_depth", "probes", "triggers", "trigger_loc", "trigger_mode"] - for option in config: - if option not in valid_options: - print(f"Warning: Ignoring unrecognized option '{option}' in Logic Analyzer core '{self.name}'") - - # Load sample depth - assert "sample_depth" in config, \ - "Sample depth not found for Logic Analyzer core {self.name}." - - assert isinstance(config["sample_depth"], int), \ - "Sample depth must be an integer." - - self.sample_depth = config["sample_depth"] - - # Add probes - assert "probes" in config, "No probe definitions found." - assert len(config["probes"]) > 0, "Must specify at least one probe." - - for probe_name, probe_width in config["probes"].items(): - assert probe_width > 0, f"Probe {probe_name} is of invalid width - it must be of at least width one." - - self.probes = config["probes"] - - # Add triggers - assert "triggers" in config, "No triggers found." - assert len(config["triggers"]) > 0, "Must specify at least one trigger." - self.triggers = config["triggers"] - - # Add trigger location - self.trigger_loc = self.sample_depth // 2 - if "trigger_loc" in config: - assert isinstance(config["trigger_loc"], int), \ - "Trigger location must be an integer." - - assert config["trigger_loc"] >= 0, \ - "Trigger location cannot be negative." - - assert config["trigger_loc"] <= self.sample_depth, \ - "Trigger location cannot exceed sample depth." - - self.trigger_loc = config["trigger_loc"] - - # Add trigger mode - self.SINGLE_SHOT = 0 - self.INCREMENTAL = 1 - self.IMMEDIATE = 2 - - self.trigger_mode = self.SINGLE_SHOT - if "trigger_mode" in config: - assert config["trigger_mode"] in ["single_shot", "incremental", "immediate"], \ - "Unrecognized trigger mode provided." - - if config["trigger_mode"] == "single_shot": - self.trigger_mode = self.SINGLE_SHOT - - elif config["trigger_mode"] == "incremental": - self.trigger_mode = self.INCREMENTAL - - elif config["trigger_mode"] == "immediate": - self.trigger_mode = self.IMMEDIATE - - # compute base addresses - self.fsm_base_addr = self.base_addr - self.trigger_block_base_addr = self.fsm_base_addr + 7 - - self.total_probe_width = sum(self.probes.values()) - self.n_brams = math.ceil(self.total_probe_width / 16) - self.block_memory_base_addr = self.trigger_block_base_addr + (2*len(self.probes)) - self.max_addr = self.block_memory_base_addr + (self.n_brams * self.sample_depth) - - # build out self register map: - # these are also defined in logic_analyzer_fsm_registers.v, and should match - self.state_reg_addr = self.base_addr - self.trigger_mode_reg_addr = self.base_addr + 1 - self.trigger_loc_reg_addr = self.base_addr + 2 - self.request_start_reg_addr = self.base_addr + 3 - self.request_stop_reg_addr = self.base_addr + 4 - self.read_pointer_reg_addr = self.base_addr + 5 - self.write_pointer_reg_addr = self.base_addr + 6 - - self.IDLE = 0 - self.MOVE_TO_POSITION = 1 - self.IN_POSITION = 2 - self.CAPTURING = 3 - self.CAPTURED = 4 - - def hdl_inst(self): - la_inst = VerilogManipulator("la_core/logic_analyzer_inst_tmpl.v") - - # add module name to instantiation - la_inst.sub(self.name, "/* INST_NAME */") - - # add net connections to instantiation - conns = la_inst.net_conn(self.probes, trailing_comma=True) - la_inst.sub(conns, "/* NET_CONNS */") - return la_inst.get_hdl() - - def gen_trigger_block_def(self): - trigger_block = VerilogManipulator("la_core/trigger_block_def_tmpl.v") - - # add probe ports to module declaration - # these ports belong to the logic analyzer, but - # need to be included in the trigger_block module declaration - probe_ports = trigger_block.net_dec(self.probes, "input wire", trailing_comma=True) - trigger_block.sub(probe_ports, "/* PROBE_PORTS */") - - - # add trigger cores to module definition - # these are instances of the trigger module, of which one gets wired - # into each probe - trigger_module_insts = [] - for name, width in self.probes.items(): - trig_inst = VerilogManipulator("la_core/trigger_block_inst_tmpl.v") - trig_inst.sub(width, "/* INPUT_WIDTH */") - trig_inst.sub(f"{name}_trigger", "/* NAME */") - - trig_inst.sub(f"reg [3:0] {name}_op = 0;", "/* OP_DEC */") - trig_inst.sub(f"reg {name}_trig;", "/* TRIG_DEC */") - - if width == 1: - trig_inst.sub(f"reg {name}_arg = 0;", "/* ARG_DEC */") - - else: - trig_inst.sub(f"reg [{width-1}:0] {name}_arg = 0;", "/* ARG_DEC */") - - trig_inst.sub(name, "/* PROBE */") - trig_inst.sub(f"{name}_op", "/* OP */") - trig_inst.sub(f"{name}_arg", "/* ARG */") - trig_inst.sub(f"{name}_trig", "/* TRIG */") - - trigger_module_insts.append(trig_inst.get_hdl()) - - trigger_module_insts = "\n".join(trigger_module_insts) - trigger_block.sub(trigger_module_insts, "/* TRIGGER_MODULE_INSTS */") - - # add combined individual triggers - cit = [f"{name}_trig" for name in self.probes] - cit = " || ".join(cit) - cit = f"assign trig = {cit};" - trigger_block.sub(cit, " /* COMBINE_INDIV_TRIGGERS */") - - # add read and write block case statement bodies - rcsb = "" # read case statement body - wcsb = "" # write case statement body - addr = 0 - for i, name in enumerate(self.probes): - addr = 2 * i - rcsb += f"BASE_ADDR + {addr}: data_o <= {name}_op;\n" - wcsb += f"BASE_ADDR + {addr}: {name}_op <= data_i;\n" - - addr = (2 * i) + 1 - rcsb += f"BASE_ADDR + {addr}: data_o <= {name}_arg;\n" - wcsb += f"BASE_ADDR + {addr}: {name}_arg <= data_i;\n" - - rcsb = rcsb.strip() - wcsb = wcsb.strip() - - trigger_block.sub(rcsb, "/* READ_CASE_STATEMENT_BODY */") - trigger_block.sub(wcsb, "/* WRITE_CASE_STATEMENT_BODY */") - trigger_block.sub(self.trigger_block_base_addr + addr + 1, "/* MAX_ADDR */") - - return trigger_block.get_hdl() - - def gen_logic_analyzer_def(self): - la = VerilogManipulator("la_core/logic_analyzer_def_tmpl.v") - - # add top level probe ports to module declaration - ports = la.net_dec(self.probes, "input wire", trailing_comma=True) - la.sub(ports, "/* TOP_LEVEL_PROBE_PORTS */") - - # assign base addresses to the FSM, trigger block, and sample mem - la.sub(self.fsm_base_addr, "/* FSM_BASE_ADDR */") - la.sub(self.trigger_block_base_addr, "/* TRIGGER_BLOCK_BASE_ADDR */") - la.sub(self.block_memory_base_addr, "/* BLOCK_MEMORY_BASE_ADDR */") - - # set sample depth - la.sub(self.sample_depth, "/* SAMPLE_DEPTH */") - - # set probe ports for the trigger block and sample mem - probe_ports = la.net_conn(self.probes, trailing_comma=True) - la.sub(probe_ports, "/* TRIGGER_BLOCK_PROBE_PORTS */") - - la.sub(self.total_probe_width, "/* TOTAL_PROBE_WIDTH */") - - # concatenate the probes together to make one big register, - # but do so such that the first probe in the config file - # is at the least-significant position in that big register. - # - # this makes part-selecting out from the memory easier to - # implement in python, and because verilog and python conventions - # are different, we would have had to reverse it somwehere anyway - probes_concat = list(self.probes.keys())[::-1] - probes_concat = '{' + ', '.join(probes_concat) + '}' - la.sub(probes_concat, "/* PROBES_CONCAT */") - - return la.get_hdl() - - def hdl_def(self): - # Return an autogenerated verilog module definition for the core. - # load source files - hdl = self.gen_logic_analyzer_def() + "\n" - hdl += VerilogManipulator("la_core/logic_analyzer_controller.v").get_hdl() + "\n" - hdl += VerilogManipulator("la_core/logic_analyzer_fsm_registers.v").get_hdl() + "\n" - hdl += VerilogManipulator("block_mem_core/block_memory.v").get_hdl() + "\n" - hdl += VerilogManipulator("block_mem_core/dual_port_bram.v").get_hdl() + "\n" - hdl += self.gen_trigger_block_def() + "\n" - hdl += VerilogManipulator("la_core/trigger.v").get_hdl() + "\n" - - return hdl - - def hdl_top_level_ports(self): - # the probes that we want as ports on the top-level manta module - ports = [] - for name, width in self.probes.items(): - if width == 1: - ports.append(f"input wire {name}") - - else: - ports.append(f"input wire [{width-1}:0] {name}") - return ports - #return VerilogManipulator().net_dec(self.probes, "input wire") - - def set_trigger_conditions(self): - - operations = { - "DISABLE" : 0, - "RISING" : 1, - "FALLING" : 2, - "CHANGING" : 3, - "GT" : 4, - "LT" : 5, - "GEQ" : 6, - "LEQ" : 7, - "EQ" : 8, - "NEQ" : 9 - } - - ops_with_no_args = ["DISABLE", "RISING" , "FALLING", "CHANGING"] - - # reset all the other triggers - for addr in range(self.trigger_block_base_addr, self.block_memory_base_addr): - self.interface.write(addr, 0) - - for trigger in self.triggers: - # determine if the trigger is good - - # most triggers will have 3 parts - the trigger, the operation, and the argument - # this is true unless the argument is RISING, FALLING, or CHANGING - - statement = trigger.split(' ') - if len(statement) == 2: - assert statement[1] in ops_with_no_args, "Invalid operation in trigger statement." - probe_name, op = statement - - op_register = 2*(list(self.probes.keys()).index(probe_name)) + self.trigger_block_base_addr - - self.interface.write(op_register, operations[op]) - - else: - assert len(statement) == 3, "Missing information in trigger statement." - probe_name, op, arg = statement - - op_register = 2*(list(self.probes.keys()).index(probe_name)) + self.trigger_block_base_addr - arg_register = op_register + 1 - - self.interface.write(op_register, operations[op]) - self.interface.write(arg_register, int(arg)) - - - - # functions for actually using the core: - def capture(self): - # Check state - if it's in anything other than IDLE, - # request to stop the existing capture - - print(" -> Resetting core...") - state = self.interface.read(self.state_reg_addr) - if state != self.IDLE: - self.interface.write(self.request_stop_reg_addr, 0) - self.interface.write(self.request_stop_reg_addr, 1) - self.interface.write(self.request_stop_reg_addr, 0) - - state = self.interface.read(self.state_reg_addr) - assert state == self.IDLE, "Logic analyzer did not reset to correct state when requested to." - - # Configure trigger conditions - print(" -> Set trigger conditions...") - self.set_trigger_conditions() - - # Configure the trigger_mode - print(" -> Setting trigger mode") - self.interface.write(self.trigger_mode_reg_addr, self.trigger_mode) - - # Configure the trigger_loc - print(" -> Setting trigger location...") - self.interface.write(self.trigger_loc_reg_addr, self.trigger_loc) - - # Start the capture by pulsing request_start - print(" -> Starting capture...") - self.interface.write(self.request_start_reg_addr, 1) - self.interface.write(self.request_start_reg_addr, 0) - - # Wait for core to finish capturing data - print(" -> Waiting for capture to complete...") - state = self.interface.read(self.state_reg_addr) - while(state != self.CAPTURED): - state = self.interface.read(self.state_reg_addr) - - # Read out contents from memory - print(" -> Reading sample memory contents...") - addrs = list(range(self.block_memory_base_addr, self.max_addr)) - block_mem_contents = self.interface.read(addrs) - - # Revolve BRAM contents around so the data pointed to by the read_pointer - # is at the beginning - print(" -> Reading read_pointer and revolving memory...") - read_pointer = self.interface.read(self.read_pointer_reg_addr) - - # when the total probe width is >16 bits and multiple BRAMs are used, - # then a single sample is stored across multiple locations in memory, - # so we must combine the data from n_brams addresses to get the value - # of the sample at that time - - # convert the sample number at read_pointer to memory address - read_address = self.n_brams * read_pointer - sample_mem = block_mem_contents[read_address:] + block_mem_contents[:read_address] - - # split sample memory into chunks of size n_brams - chunks = [sample_mem[i: i + self.n_brams] for i in range(0, len(sample_mem), self.n_brams)] - - # concat them in little-endian order (ie, chunk[0] is LSB) - concat = lambda x: int( ''.join([f'{i:016b}' for i in x[::-1]]), 2) - return [concat(c) for c in chunks] - - - def export_vcd(self, capture_data, path): - from vcd import VCDWriter - vcd_file = open(path, "w") - - # Use the same datetime format that iVerilog uses - timestamp = datetime.now().strftime("%a %b %w %H:%M:%S %Y") - - with VCDWriter(vcd_file, '10 ns', timestamp, "manta") as writer: - - # each probe has a name, width, and writer associated with it - signals = [] - for name, width in self.probes.items(): - signal = { - "name" : name, - "width" : width, - "data" : self.part_select_capture_data(capture_data, name), - "var": writer.register_var("manta", name, "wire", size=width) - } - signals.append(signal) - - clock = writer.register_var("manta", "clk", "wire", size=1) - trigger = writer.register_var("manta", "trigger", "wire", size=1) - - # add the data to each probe in the vcd file - for timestamp in range(0, 2*len(capture_data)): - - # run the clock - writer.change(clock, timestamp, timestamp % 2 == 0) - - # set the trigger - triggered = (timestamp // 2) >= self.trigger_loc - writer.change(trigger, timestamp, triggered) - - # add other signals - for signal in signals: - var = signal["var"] - sample = signal["data"][timestamp // 2] - - writer.change(var, timestamp, sample) - - vcd_file.close() - - def export_mem(self, capture_data, path): - with open(path, "w") as f: - # a wee bit of cursed string formatting, but just - # outputs each sample as binary, padded to a fixed length - w = self.total_probe_width - f.writelines([f'{s:0{w}b}\n' for s in capture_data]) - - def export_playback_module(self, path): - playback = VerilogManipulator("la_core/logic_analyzer_playback_tmpl.v") - - module_name = f"{self.name}_playback" - playback.sub(module_name, "/* MODULE_NAME */") - - version = "v" + get_distribution('mantaray').version - playback.sub(version, "/* VERSION */") - - timestamp = datetime.now().strftime("%d %b %Y at %H:%M:%S") - playback.sub(timestamp, "/* TIMESTAMP */") - - user = os.environ.get("USER", os.environ.get("USERNAME")) - playback.sub(user, "/* USER */") - - ports = [f".{name}({name})" for name in self.probes.keys()] - ports = ",\n".join(ports) - playback.sub(ports, "/* PORTS */") - - playback.sub(self.sample_depth, "/* SAMPLE_DEPTH */") - playback.sub(self.total_probe_width, "/* TOTAL_PROBE_WIDTH */") - - # see the note in generate_logic_analyzer_def about why we do this - probes_concat = list(self.probes.keys())[::-1] - probes_concat = '{' + ', '.join(probes_concat) + '}' - playback.sub(probes_concat, "/* PROBES_CONCAT */") - - - probe_dec = playback.net_dec(self.probes, "output reg") - playback.sub(probe_dec, "/* PROBE_DEC */") - - with open(path, "w") as f: - f.write(playback.get_hdl()) - - - def part_select_capture_data(self, capture_data, probe_name): - """Given the name of the probe, part-select the appropriate bits of capture data, - and return as an integer. Accepts capture_data as an integer or a list of integers.""" - - # sum up the widths of the probes below this one - lower = 0 - for name, width in self.probes.items(): - if name == probe_name: - break - - lower += width - - upper = lower + (self.probes[probe_name] - 1) - - # define the part select - mask = 2 ** (upper - lower + 1) - 1 - part_select = lambda x: (x >> lower) & mask - - # apply the part_select function depending on type - if isinstance(capture_data, int): - return part_select(capture_data) - - elif isinstance(capture_data, list): - for i in capture_data: - assert isinstance(i, int), "Can only part select on integers and list of integers." - - return [part_select(sample) for sample in capture_data] - - else: - raise ValueError("Can only part select on integers and lists of integers.") diff --git a/src/manta/la_core/logic_analyzer_controller.v b/src/manta/la_core/logic_analyzer_controller.v deleted file mode 100644 index 50c90bf..0000000 --- a/src/manta/la_core/logic_analyzer_controller.v +++ /dev/null @@ -1,92 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -module logic_analyzer_controller ( - input wire clk, - - // from register file - output reg [3:0] state, - input wire [15:0] trigger_loc, - input wire [1:0] trigger_mode, - input wire request_start, - input wire request_stop, - output reg [ADDR_WIDTH-1:0] read_pointer, - output reg [ADDR_WIDTH-1:0] write_pointer, - - // from trigger block - input wire trig, - - // block memory user port - output reg [ADDR_WIDTH-1:0] bram_addr, - output reg bram_we - ); - - assign bram_addr = write_pointer; - - parameter SAMPLE_DEPTH= 0; - localparam ADDR_WIDTH = $clog2(SAMPLE_DEPTH); - - /* ----- FIFO ----- */ - initial read_pointer = 0; - initial write_pointer = 0; - - /* ----- FSM ----- */ - localparam IDLE = 0; - localparam MOVE_TO_POSITION = 1; - localparam IN_POSITION = 2; - localparam CAPTURING = 3; - localparam CAPTURED = 4; - - initial state = IDLE; - - // rising edge detection for start/stop requests - reg prev_request_start; - always @(posedge clk) prev_request_start <= request_start; - - reg prev_request_stop; - always @(posedge clk) prev_request_stop <= request_stop; - - always @(posedge clk) begin - // don't do anything to the FIFO unless told to - - if(state == IDLE) begin - write_pointer <= 0; - read_pointer <= 0; - bram_we <= 0; - - if(request_start && ~prev_request_start) begin - state <= MOVE_TO_POSITION; - end - end - - else if(state == MOVE_TO_POSITION) begin - write_pointer <= write_pointer + 1; - bram_we <= 1; - - if(write_pointer == trigger_loc) begin - if(trig) state <= CAPTURING; - else state <= IN_POSITION; - end - end - - else if(state == IN_POSITION) begin - write_pointer <= (write_pointer + 1) % SAMPLE_DEPTH; - read_pointer <= (read_pointer + 1) % SAMPLE_DEPTH; - bram_we <= 1; - if(trig) state <= CAPTURING; - end - - else if(state == CAPTURING) begin - if(write_pointer == read_pointer) begin - bram_we <= 0; - state <= CAPTURED; - end - - else write_pointer <= (write_pointer + 1) % SAMPLE_DEPTH; - end - - if(request_stop && ~prev_request_stop) state <= IDLE; - end -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/src/manta/la_core/logic_analyzer_def_tmpl.v b/src/manta/la_core/logic_analyzer_def_tmpl.v deleted file mode 100644 index cbb0ef9..0000000 --- a/src/manta/la_core/logic_analyzer_def_tmpl.v +++ /dev/null @@ -1,142 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -module logic_analyzer ( - input wire clk, - - // probes - /* TOP_LEVEL_PROBE_PORTS */ - - // input port - input wire [15:0] addr_i, - input wire [15:0] data_i, - input wire rw_i, - input wire valid_i, - - // output port - output reg [15:0] addr_o, - output reg [15:0] data_o, - output reg rw_o, - output reg valid_o - ); - localparam SAMPLE_DEPTH = /* SAMPLE_DEPTH */; - localparam ADDR_WIDTH = $clog2(SAMPLE_DEPTH); - - reg [3:0] state; - reg [15:0] trigger_loc; - reg [1:0] trigger_mode; - reg request_start; - reg request_stop; - reg [ADDR_WIDTH-1:0] read_pointer; - reg [ADDR_WIDTH-1:0] write_pointer; - - reg trig; - - reg [ADDR_WIDTH-1:0] bram_addr; - reg bram_we; - - localparam TOTAL_PROBE_WIDTH = /* TOTAL_PROBE_WIDTH */; - reg [TOTAL_PROBE_WIDTH-1:0] probes_concat; - assign probes_concat = /* PROBES_CONCAT */; - - logic_analyzer_controller #(.SAMPLE_DEPTH(SAMPLE_DEPTH)) la_controller ( - .clk(clk), - - // from register file - .state(state), - .trigger_loc(trigger_loc), - .trigger_mode(trigger_mode), - .request_start(request_start), - .request_stop(request_stop), - .read_pointer(read_pointer), - .write_pointer(write_pointer), - - // from trigger block - .trig(trig), - - // from block memory user port - .bram_addr(bram_addr), - .bram_we(bram_we) - ); - - logic_analyzer_fsm_registers #( - .BASE_ADDR(/* FSM_BASE_ADDR */), - .SAMPLE_DEPTH(SAMPLE_DEPTH) - ) fsm_registers ( - .clk(clk), - - .addr_i(addr_i), - .data_i(data_i), - .rw_i(rw_i), - .valid_i(valid_i), - - .addr_o(fsm_reg_trig_blk_addr), - .data_o(fsm_reg_trig_blk_data), - .rw_o(fsm_reg_trig_blk_rw), - .valid_o(fsm_reg_trig_blk_valid), - - .state(state), - .trigger_loc(trigger_loc), - .trigger_mode(trigger_mode), - .request_start(request_start), - .request_stop(request_stop), - .read_pointer(read_pointer), - .write_pointer(write_pointer)); - - reg [15:0] fsm_reg_trig_blk_addr; - reg [15:0] fsm_reg_trig_blk_data; - reg fsm_reg_trig_blk_rw; - reg fsm_reg_trig_blk_valid; - - // trigger block - trigger_block #(.BASE_ADDR(/* TRIGGER_BLOCK_BASE_ADDR */)) trig_blk ( - .clk(clk), - - /* TRIGGER_BLOCK_PROBE_PORTS */ - - .trig(trig), - - .addr_i(fsm_reg_trig_blk_addr), - .data_i(fsm_reg_trig_blk_data), - .rw_i(fsm_reg_trig_blk_rw), - .valid_i(fsm_reg_trig_blk_valid), - - .addr_o(trig_blk_block_mem_addr), - .data_o(trig_blk_block_mem_data), - .rw_o(trig_blk_block_mem_rw), - .valid_o(trig_blk_block_mem_valid)); - - reg [15:0] trig_blk_block_mem_addr; - reg [15:0] trig_blk_block_mem_data; - reg trig_blk_block_mem_rw; - reg trig_blk_block_mem_valid; - - // sample memory - block_memory #( - .BASE_ADDR(/* BLOCK_MEMORY_BASE_ADDR */), - .WIDTH(TOTAL_PROBE_WIDTH), - .DEPTH(SAMPLE_DEPTH) - ) block_mem ( - .clk(clk), - - // input port - .addr_i(trig_blk_block_mem_addr), - .data_i(trig_blk_block_mem_data), - .rw_i(trig_blk_block_mem_rw), - .valid_i(trig_blk_block_mem_valid), - - // output port - .addr_o(addr_o), - .data_o(data_o), - .rw_o(rw_o), - .valid_o(valid_o), - - // BRAM itself - .user_clk(clk), - .user_addr(bram_addr), - .user_din(probes_concat), - .user_dout(), - .user_we(bram_we)); -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/src/manta/la_core/logic_analyzer_fsm_registers.v b/src/manta/la_core/logic_analyzer_fsm_registers.v deleted file mode 100644 index d35bcfb..0000000 --- a/src/manta/la_core/logic_analyzer_fsm_registers.v +++ /dev/null @@ -1,75 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -module logic_analyzer_fsm_registers( - input wire clk, - - // input port - input wire [15:0] addr_i, - input wire [15:0] data_i, - input wire rw_i, - input wire valid_i, - - // output port - output reg [15:0] addr_o, - output reg [15:0] data_o, - output reg rw_o, - output reg valid_o, - - // registers - input wire [3:0] state, - output reg [15:0] trigger_loc, - output reg [1:0] trigger_mode, - output reg request_start, - output reg request_stop, - input wire [ADDR_WIDTH-1:0] read_pointer, - input wire [ADDR_WIDTH-1:0] write_pointer - ); - - initial trigger_loc = 0; - initial trigger_mode = 0; - initial request_start = 0; - initial request_stop = 0; - - parameter BASE_ADDR = 0; - localparam MAX_ADDR = BASE_ADDR + 5; - parameter SAMPLE_DEPTH = 0; - parameter ADDR_WIDTH = $clog2(SAMPLE_DEPTH); - - always @(posedge clk) begin - addr_o <= addr_i; - data_o <= data_i; - rw_o <= rw_i; - valid_o <= valid_i; - - // check if address is valid - if( (valid_i) && (addr_i >= BASE_ADDR) && (addr_i <= MAX_ADDR)) begin - - // reads - if(!rw_i) begin - case (addr_i) - BASE_ADDR + 0: data_o <= state; - BASE_ADDR + 1: data_o <= trigger_mode; - BASE_ADDR + 2: data_o <= trigger_loc; - BASE_ADDR + 3: data_o <= request_start; - BASE_ADDR + 4: data_o <= request_stop; - BASE_ADDR + 5: data_o <= read_pointer; - BASE_ADDR + 6: data_o <= write_pointer; - endcase - end - - // writes - else begin - case (addr_i) - BASE_ADDR + 1: trigger_mode <= data_i; - BASE_ADDR + 2: trigger_loc <= data_i; - BASE_ADDR + 3: request_start <= data_i; - BASE_ADDR + 4: request_stop <= data_i; - endcase - end - end - end - - -endmodule -`default_nettype wire \ No newline at end of file diff --git a/src/manta/la_core/logic_analyzer_inst_tmpl.v b/src/manta/la_core/logic_analyzer_inst_tmpl.v deleted file mode 100644 index eebb872..0000000 --- a/src/manta/la_core/logic_analyzer_inst_tmpl.v +++ /dev/null @@ -1,14 +0,0 @@ -logic_analyzer /* INST_NAME */ ( - .clk(clk), - - .addr_i(), - .data_i(), - .rw_i(), - .valid_i(), - - /* NET_CONNS */ - - .addr_o(), - .data_o(), - .rw_o(), - .valid_o()); \ No newline at end of file diff --git a/src/manta/la_core/logic_analyzer_playback_tmpl.v b/src/manta/la_core/logic_analyzer_playback_tmpl.v deleted file mode 100644 index e87228f..0000000 --- a/src/manta/la_core/logic_analyzer_playback_tmpl.v +++ /dev/null @@ -1,50 +0,0 @@ -/* -This playback module was generated with Manta /* VERSION */ on /* TIMESTAMP */ by /* USER */ - -If this breaks or if you've got dank formal verification memes, contact fischerm [at] mit.edu - -Provided under a GNU GPLv3 license. Go wild. - -Here's an example instantiation of the Manta module you configured, feel free to copy-paste -this into your source! - -/* MODULE_NAME */ #(.MEM_FILE("capture.mem")) /* MODULE_NAME */_inst ( - .clk(clk), - .enable(1'b1), - - /* PORTS */); - -*/ - - -module /* MODULE_NAME */ ( - input wire clk, - - input wire enable, - output reg done, - - /* PROBE_DEC */); - - parameter MEM_FILE = ""; - localparam SAMPLE_DEPTH = /* SAMPLE_DEPTH */; - localparam TOTAL_PROBE_WIDTH = /* TOTAL_PROBE_WIDTH */; - - reg [TOTAL_PROBE_WIDTH-1:0] capture [SAMPLE_DEPTH-1:0]; - reg [$clog2(SAMPLE_DEPTH)-1:0] addr; - reg [TOTAL_PROBE_WIDTH-1:0] sample; - - assign done = (addr >= SAMPLE_DEPTH); - - initial begin - $readmemb(MEM_FILE, capture, 0, SAMPLE_DEPTH-1); - addr = 0; - end - - always @(posedge clk) begin - if (enable && !done) begin - addr = addr + 1; - sample = capture[addr]; - /* PROBES_CONCAT */ = sample; - end - end -endmodule \ No newline at end of file diff --git a/src/manta/la_core/trigger.v b/src/manta/la_core/trigger.v deleted file mode 100644 index 05939e1..0000000 --- a/src/manta/la_core/trigger.v +++ /dev/null @@ -1,45 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -module trigger ( - input wire clk, - - input wire [INPUT_WIDTH-1:0] probe, - input wire [3:0] op, - input wire [INPUT_WIDTH-1:0] arg, - - output reg trig); - - parameter INPUT_WIDTH = 0; - - localparam DISABLE = 0; - localparam RISING = 1; - localparam FALLING = 2; - localparam CHANGING = 3; - localparam GT = 4; - localparam LT = 5; - localparam GEQ = 6; - localparam LEQ = 7; - localparam EQ = 8; - localparam NEQ = 9; - - reg [INPUT_WIDTH-1:0] probe_prev = 0; - always @(posedge clk) probe_prev <= probe; - - always @(*) begin - case (op) - RISING : trig = (probe > probe_prev); - FALLING : trig = (probe < probe_prev); - CHANGING : trig = (probe != probe_prev); - GT: trig = (probe > arg); - LT: trig = (probe < arg); - GEQ: trig = (probe >= arg); - LEQ: trig = (probe <= arg); - EQ: trig = (probe == arg); - NEQ: trig = (probe != arg); - default: trig = 0; - endcase - end -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/src/manta/la_core/trigger_block_def_tmpl.v b/src/manta/la_core/trigger_block_def_tmpl.v deleted file mode 100644 index 39af04f..0000000 --- a/src/manta/la_core/trigger_block_def_tmpl.v +++ /dev/null @@ -1,62 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -module trigger_block ( - input wire clk, - - // probes - /* PROBE_PORTS */ - - // trigger - output reg trig, - - // input port - input wire [15:0] addr_i, - input wire [15:0] data_i, - input wire rw_i, - input wire valid_i, - - // output port - output reg [15:0] addr_o, - output reg [15:0] data_o, - output reg rw_o, - output reg valid_o); - - parameter BASE_ADDR = 0; - localparam MAX_ADDR = /* MAX_ADDR */; - - // trigger configuration registers - // - each probe gets an operation and a compare register - // - at the end we OR them all together. along with any custom probes the user specs - - /* TRIGGER_MODULE_INSTS */ - - /* COMBINE_INDIV_TRIGGERS */ - - // perform register operations - always @(posedge clk) begin - addr_o <= addr_i; - data_o <= data_i; - rw_o <= rw_i; - valid_o <= valid_i; - - if( (addr_i >= BASE_ADDR) && (addr_i <= BASE_ADDR + MAX_ADDR) ) begin - - // reads - if(valid_i && !rw_i) begin - case (addr_i) - /* READ_CASE_STATEMENT_BODY */ - endcase - end - - // writes - else if(valid_i && rw_i) begin - case (addr_i) - /* WRITE_CASE_STATEMENT_BODY */ - endcase - end - end - end -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/src/manta/la_core/trigger_block_inst_tmpl.v b/src/manta/la_core/trigger_block_inst_tmpl.v deleted file mode 100644 index f796fa2..0000000 --- a/src/manta/la_core/trigger_block_inst_tmpl.v +++ /dev/null @@ -1,11 +0,0 @@ -/* OP_DEC */ -/* ARG_DEC */ -/* TRIG_DEC */ - -trigger #(.INPUT_WIDTH(/* INPUT_WIDTH */)) /* NAME */ ( - .clk(clk), - - .probe(/* PROBE */), - .op(/* OP */), - .arg(/* ARG */), - .trig(/* TRIG */)); diff --git a/src/manta/logic_analyzer_core.py b/src/manta/logic_analyzer_core.py new file mode 100644 index 0000000..4acedd5 --- /dev/null +++ b/src/manta/logic_analyzer_core.py @@ -0,0 +1,558 @@ +from amaranth import * +from warnings import warn +from .utils import * +from .io_core import IOCore +from .memory_core import ReadOnlyMemoryCore +from math import ceil, log2 + + +class LogicAnalyzerCore(Elaboratable): + """ """ + + def __init__(self, config, base_addr, interface): + self.config = config + self.base_addr = base_addr + self.interface = interface + + self.check_config(config) + + # State Machine Values + self.states = { + "IDLE": 0, + "MOVE_TO_POSITION": 1, + "IN_POSITION": 2, + "CAPTURING": 3, + "CAPTURED": 4, + } + + # Trigger Modes + self.trigger_modes = {"SINGLE_SHOT": 0, "INCREMENTAL": 1, "IMMEDIATE": 2} + + # Trigger operations + self.operations = { + "DISABLE": 0, + "RISING": 1, + "FALLING": 2, + "CHANGING": 3, + "GT": 4, + "LT": 5, + "GEQ": 6, + "LEQ": 7, + "EQ": 8, + "NEQ": 9, + } + + self.registers = self.make_registers(self.base_addr) + self.sample_mem = self.make_sample_mem(self.registers.max_addr) + self.define_signals() + + def check_config(self, config): + # Check for unrecognized options + valid_options = [ + "type", + "sample_depth", + "probes", + "triggers", + "trigger_loc", + "trigger_mode", + ] + for option in config: + if option not in valid_options: + warn(f"Ignoring unrecognized option '{option}' in Logic Analyzer.") + + # Check sample depth is provided and positive + if "sample_depth" not in config: + raise ValueError("Logic Analyzer must have sample_depth specified.") + + if not isinstance(config["sample_depth"], int): + raise ValueError("Logic Analyzer sample_depth must be an integer.") + + if config["sample_depth"] <= 0: + raise ValueError("Logic Analyzer sample_depth must be positive.") + + # Check probes + if "probes" not in config: + raise ValueError("Logic Analyzer must have at least one probe specified.") + + if len(config["probes"]) == 0: + raise ValueError("Logic Analyzer must have at least one probe specified.") + + for name, width in config["probes"].items(): + if width < 0: + raise ValueError(f"Width of probe {name} must be positive.") + + # Check triggers + if "triggers" not in config: + raise ValueError("Logic Analyzer must have at least one trigger specified.") + + if len(config["triggers"]) == 0: + raise ValueError("Logic Analyzer must have at least one trigger specified.") + + # Check trigger location + if "trigger_loc" in config: + if not isinstance(config["trigger_loc"], int): + raise ValueError("Trigger location must be an integer.") + + if config["trigger_loc"] < 0: + raise ValueError("Trigger location must be positive.") + + if config["trigger_loc"] > config["sample_depth"]: + raise ValueError("Trigger location cannot exceed sample depth.") + + # Check trigger mode + if "trigger_mode" in config: + valid_modes = ["single_shot", "incremental", "immediate"] + if config["trigger_mode"] not in valid_modes: + raise ValueError( + f"Unrecognized trigger mode {config['trigger_mode']} provided." + ) + + # Check triggers themselves + for trigger in config["triggers"]: + if not isinstance(trigger, str): + raise ValueError("Trigger must be specified with a string.") + + # Trigger conditions may be composed of either two or three components, + # depending on the operation specified. In the case of operations that + # don't need an argument (like DISABLE, RISING, FALLING, CHANGING) or + # three statements in + + # Check the trigger operations + components = trigger.strip().split(" ") + if len(components) == 2: + name, op = components + if op not in ["DISABLE", "RISING", "FALLING", "CHANGING"]: + raise ValueError( + f"Unable to interpret trigger condition '{trigger}'." + ) + + elif len(components) == 3: + name, op, arg = components + if op not in ["GT", "LT", "GEQ", "LEQ", "EQ", "NEQ"]: + raise ValueError( + f"Unable to interpret trigger condition '{trigger}'." + ) + + else: + raise ValueError(f"Unable to interpret trigger condition '{trigger}'.") + + # Check probe names + if components[0] not in config["probes"]: + raise ValueError(f"Unknown probe name '{components[0]}' specified.") + + def define_signals(self): + # Bus Input + self.addr_i = Signal(16) + self.data_i = Signal(16) + self.rw_i = Signal(1) + self.valid_i = Signal(1) + + # Bus Output + self.addr_o = Signal(16) + self.data_o = Signal(16) + self.rw_o = Signal(1) + self.valid_o = Signal(1) + + # Probes + self.probe_signals = {} + for name, width in self.config["probes"].items(): + self.probe_signals[name] = { + "top_level": Signal(width), + "prev": Signal(width), + "trigger_arg": getattr(self.registers, f"{name}_arg"), + "trigger_op": getattr(self.registers, f"{name}_op"), + "triggered": Signal(1), + } + + # Global trigger. High if any probe is triggered. + self.trig = Signal(1) + + def make_registers(self, base_addr): + # The logic analyzer uses an IO core to handle inputs to the FSM and trigger comparators + register_config = { + "inputs": { + "state": 4, + "read_pointer": ceil(log2(self.config["sample_depth"])), + "write_pointer": ceil(log2(self.config["sample_depth"])), + }, + "outputs": { + "trigger_loc": ceil(log2(self.config["sample_depth"])), + "trigger_mode": 2, + "request_start": 1, + "request_stop": 1, + }, + } + + for name, width in self.config["probes"].items(): + register_config["outputs"][name + "_arg"] = width + register_config["outputs"][name + "_op"] = 4 + + return IOCore(register_config, base_addr, self.interface) + + def make_sample_mem(self, base_addr): + sample_mem_config = { + "width": sum(self.config["probes"].values()), + "depth": self.config["sample_depth"], + } + + return ReadOnlyMemoryCore(sample_mem_config, base_addr, self.interface) + + def run_triggers(self, m): + # Run the trigger for each individual probe + for name, attrs in self.probe_signals.items(): + top_level = attrs["top_level"] + prev = attrs["prev"] + trigger_arg = attrs["trigger_arg"] + trigger_op = attrs["trigger_op"] + triggered = attrs["triggered"] + + # Save the previous value to a register so we can do rising/falling edge detection later! + m.d.sync += prev.eq(top_level) + + with m.If(trigger_op == self.operations["DISABLE"]): + m.d.comb += triggered.eq(0) + + with m.Elif(trigger_op == self.operations["RISING"]): + m.d.comb += triggered.eq((top_level) & (~prev)) + + with m.Elif(trigger_op == self.operations["FALLING"]): + m.d.comb += triggered.eq((~top_level) & (prev)) + + with m.Elif(trigger_op == self.operations["CHANGING"]): + m.d.comb += triggered.eq(top_level != prev) + + with m.Elif(trigger_op == self.operations["GT"]): + m.d.comb += triggered.eq(top_level > trigger_arg) + + with m.Elif(trigger_op == self.operations["LT"]): + m.d.comb += triggered.eq(top_level < trigger_arg) + + with m.Elif(trigger_op == self.operations["GEQ"]): + m.d.comb += triggered.eq(top_level >= trigger_arg) + + with m.Elif(trigger_op == self.operations["LEQ"]): + m.d.comb += triggered.eq(top_level <= trigger_arg) + + with m.Elif(trigger_op == self.operations["EQ"]): + m.d.comb += triggered.eq(top_level == trigger_arg) + + with m.Elif(trigger_op == self.operations["NEQ"]): + m.d.comb += triggered.eq(top_level != trigger_arg) + + with m.Else(): + m.d.comb += triggered.eq(0) + + # Combine all the triggers + m.d.comb += self.trig.eq( + Cat(attrs["triggered"] for attrs in self.probe_signals.values()).any() + ) + + def run_state_machine(self, m): + self.prev_request_start = Signal(1) + self.prev_request_stop = Signal(1) + + # Rising edge detection for start/stop requests + m.d.sync += self.prev_request_start.eq(self.registers.request_start) + m.d.sync += self.prev_request_stop.eq(self.registers.request_stop) + + m.d.comb += self.sample_mem.user_addr.eq(self.registers.write_pointer) + + with m.If(self.registers.state == self.states["IDLE"]): + m.d.sync += self.registers.write_pointer.eq(0) + m.d.sync += self.registers.read_pointer.eq(0) + m.d.sync += self.sample_mem.user_we.eq(0) # or something like this + + with m.If((self.registers.request_start) & (~self.prev_request_start)): + m.d.sync += self.registers.state.eq(self.states["MOVE_TO_POSITION"]) + + with m.Elif(self.registers.state == self.states["MOVE_TO_POSITION"]): + m.d.sync += self.registers.write_pointer.eq( + self.registers.write_pointer + 1 + ) + m.d.sync += self.sample_mem.user_we.eq(1) + + with m.If(self.registers.write_pointer == self.registers.trigger_loc): + with m.If(self.trig): + m.d.sync += self.registers.state.eq(self.states["CAPTURING"]) + + with m.Else(): + m.d.sync += self.registers.state.eq(self.states["IN_POSITION"]) + + with m.Elif(self.registers.state == self.states["IN_POSITION"]): + m.d.sync += self.registers.write_pointer.eq( + (self.registers.write_pointer + 1) % self.config["sample_depth"] + ) + m.d.sync += self.registers.read_pointer.eq( + (self.registers.read_pointer + 1) % self.config["sample_depth"] + ) + m.d.sync += self.sample_mem.user_we.eq(1) + + with m.If(self.trig): + m.d.sync += self.registers.state.eq(self.states["CAPTURING"]) + + with m.Elif(self.registers.state == self.states["CAPTURING"]): + with m.If(self.registers.write_pointer == self.registers.read_pointer): + m.d.sync += self.sample_mem.user_we.eq(0) + m.d.sync += self.registers.state.eq(self.states["CAPTURED"]) + + with m.Else(): + m.d.sync += self.registers.write_pointer.eq( + (self.registers.write_pointer + 1) % self.config["sample_depth"] + ) + + with m.If((self.registers.request_stop) & (~self.prev_request_stop)): + m.d.sync += self.registers.state.eq(self.states["IDLE"]) + + def elaborate(self, platform): + m = Module() + + # Add registers and sample memory as submodules + m.submodules["registers"] = self.registers + m.submodules["sample_mem"] = self.sample_mem + + # Concat all the probes together, and feed to input of sample memory + # (it is necessary to reverse the order such that first probe occupies + # the lowest location in memory) + m.d.comb += self.sample_mem.user_data.eq( + Cat([p["top_level"] for p in self.probe_signals.values()][::-1]) + ) + + self.run_state_machine(m) + self.run_triggers(m) + + # Wire internal modules + m.d.comb += [ + self.registers.addr_i.eq(self.addr_i), + self.registers.data_i.eq(self.data_i), + self.registers.rw_i.eq(self.rw_i), + self.registers.valid_i.eq(self.valid_i), + self.sample_mem.addr_i.eq(self.registers.addr_o), + self.sample_mem.data_i.eq(self.registers.data_o), + self.sample_mem.rw_i.eq(self.registers.rw_o), + self.sample_mem.valid_i.eq(self.registers.valid_o), + self.addr_o.eq(self.sample_mem.addr_o), + self.data_o.eq(self.sample_mem.data_o), + self.rw_o.eq(self.sample_mem.rw_o), + self.valid_o.eq(self.sample_mem.valid_o), + ] + + return m + + def get_top_level_ports(self): + return [p["top_level"] for p in self.probe_signals.values()] + + def get_max_addr(self): + return self.sample_mem.get_max_addr() + + def set_triggers(self): + # reset all triggers to zero + for name in self.probe_signals.keys(): + self.registers.set_probe(name + "_op", 0) + self.registers.set_probe(name + "_arg", 0) + + # set triggers + for trigger in self.config["triggers"]: + components = trigger.strip().split(" ") + + # Handle triggers that don't need an argument + if len(components) == 2: + name, op = components + self.registers.set_probe(name + "_op", self.operations[op]) + + # Handle triggers that do need an argument + elif len(components) == 3: + name, op, arg = components + self.registers.set_probe(name + "_op", self.operations[op]) + self.registers.set_probe(name + "_arg", int(arg)) + + def capture(self, verbose=False): + print_if_verbose = lambda x: print(x) if verbose else None + + # If core is not in IDLE state, request that it return to IDLE + print_if_verbose(" -> Resetting core...") + state = self.registers.get_probe("state") + if state != self.states["IDLE"]: + self.registers.set_probe("request_stop", 0) + self.registers.set_probe("request_stop", 1) + self.registers.set_probe("request_stop", 0) + + if self.registers.get_probe("state") != self.states["IDLE"]: + raise ValueError("Logic analyzer did not reset to IDLE state.") + + # Set triggers + print_if_verbose(" -> Setting triggers...") + self.set_triggers() + + # Set trigger mode, default to single-shot if user didn't specify a mode + print_if_verbose(" -> Setting trigger mode...") + if "trigger_mode" in self.config: + self.registers.set_probe("trigger_mode", self.config["trigger_mode"]) + + else: + self.registers.set_probe("trigger_mode", self.trigger_modes["SINGLE_SHOT"]) + + # Set trigger location + print_if_verbose(" -> Setting trigger location...") + self.registers.set_probe("trigger_loc", self.config["trigger_loc"]) + + # Send a start request to the state machine + print_if_verbose(" -> Starting capture...") + self.registers.set_probe("request_start", 1) + self.registers.set_probe("request_start", 0) + + # Poll the state machine's state, and wait for the capture to complete + print_if_verbose(" -> Waiting for capture to complete...") + while self.registers.get_probe("state") != self.states["CAPTURED"]: + pass + + # Read out the entirety of the sample memory + print_if_verbose(" -> Reading sample memory contents...") + addrs = list(range(self.config["sample_depth"])) + raw_capture = self.sample_mem.read_from_user_addr(addrs) + + # Revolve the memory around the read_pointer, such that all the beginning + # of the caputure is at the first element + print_if_verbose(" -> Checking read pointer and revolving memory...") + read_pointer = self.registers.get_probe("read_pointer") + + data = raw_capture[read_pointer:] + raw_capture[:read_pointer] + return LogicAnalyzerCapture(data, self.config) + + +class LogicAnalyzerCapture: + def __init__(self, data, config): + self.data = data + self.config = config + + def get_trigger_loc(self): + return self.config["trigger_loc"] + + def get_trace(self, probe_name): + # sum up the widths of all the probes below this one + lower = 0 + for name, width in self.config["probes"].items(): + if name == probe_name: + break + + lower += width + + # add the width of the probe we'd like + upper = lower + self.config["probes"][probe_name] + + total_probe_width = sum(self.config["probes"].values()) + binary = [f"{d:0{total_probe_width}b}" for d in self.data] + return [int(b[lower:upper], 2) for b in binary] + + def export_vcd(self, path): + from vcd import VCDWriter + from datetime import datetime + + # Use the same datetime format that iVerilog uses + timestamp = datetime.now().strftime("%a %b %w %H:%M:%S %Y") + vcd_file = open(path, "w") + + with VCDWriter(vcd_file, "10 ns", timestamp, "manta") as writer: + # each probe has a name, width, and writer associated with it + signals = [] + for name, width in self.config["probes"].items(): + signal = { + "name": name, + "width": width, + "data": self.get_trace(name), + "var": writer.register_var("manta", name, "wire", size=width), + } + signals.append(signal) + + clock = writer.register_var("manta", "clk", "wire", size=1) + trigger = writer.register_var("manta", "trigger", "wire", size=1) + + # add the data to each probe in the vcd file + for timestamp in range(0, 2 * len(self.data)): + # run the clock + writer.change(clock, timestamp, timestamp % 2 == 0) + + # set the trigger + triggered = (timestamp // 2) >= self.get_trigger_loc() + writer.change(trigger, timestamp, triggered) + + # add other signals + for signal in signals: + var = signal["var"] + sample = signal["data"][timestamp // 2] + + writer.change(var, timestamp, sample) + + vcd_file.close() + + def export_playback_module(self, path): + return LogicAnalyzerPlayback(self.data, self.config) + + def export_playback_verilog(self, path): + la = LogicAnalyzerPlayback(self.data, self.config) + from amaranth.back import verilog + + with open(path, "w") as f: + f.write( + verilog.convert( + la, + name="logic_analyzer_playback", + ports=la.get_top_level_ports(), + strip_internal_attrs=True, + ) + ) + + +class LogicAnalyzerPlayback(Elaboratable): + def __init__(self, data, config): + self.data = data + self.config = config + + # State Machine + self.enable = Signal(1) + self.done = Signal(1) + + # Top-Level Probe signals + self.top_level_probes = {} + for name, width in self.config["probes"].items(): + self.top_level_probes[name] = Signal(width, name=name) + + # Instantiate memory + self.mem = Memory( + depth=self.config["sample_depth"], + width=sum(self.config["probes"].values()), + init=self.data, + ) + + self.read_port = self.mem.read_port() + + def elaborate(self, platform): + m = Module() + m.submodules["mem"] = self.mem + m.d.comb += self.read_port.en.eq(1) + + # Assign the probe values by part-selecting from the data port + lower = 0 + for name, width in reversed(self.config["probes"].items()): + signal = self.top_level_probes[name] + + # Set output probe to zero if we're not + with m.If(~self.done): + m.d.comb += signal.eq(self.read_port.data[lower : lower + width]) + + with m.Else(): + m.d.comb += signal.eq(0) + + lower += width + + # Iterate through the samples if saved + with m.If((self.enable) & (~self.done)): + with m.If(self.read_port.addr < (self.config["sample_depth"] - 1)): + m.d.sync += self.read_port.addr.eq(self.read_port.addr + 1) + + with m.Else(): + m.d.sync += self.done.eq(1) + + return m + + def get_top_level_ports(self): + return [self.enable, self.done] + list(self.top_level_probes.values()) diff --git a/src/manta/manta.py b/src/manta/manta.py new file mode 100644 index 0000000..073f55a --- /dev/null +++ b/src/manta/manta.py @@ -0,0 +1,170 @@ +from amaranth import * +from warnings import warn +from .uart import UARTInterface + +# from .ethernet import EthernetInterface +from .io_core import IOCore +from .memory_core import ReadOnlyMemoryCore +from .logic_analyzer_core import LogicAnalyzerCore + + +class Manta(Elaboratable): + def __init__(self, config): + # load config from either a configuration file or a dictionary. Users primarily use the + # config file, but the dictionary is included for internal tests. + + if isinstance(config, str): + self.config = self.read_config_file(config) + + if isinstance(config, dict): + self.config = config + + self.check_config() + + self.interface = self.get_interface() + self.cores = self.get_cores() + self.add_friendly_core_names() + + def read_config_file(self, path): + """ + Take path to configuration file, and retun the configuration as a python list/dict object. + """ + + extension = path.split(".")[-1] + + if "json" in extension: + with open(path, "r") as f: + import json + + return json.load(f) + + elif "yaml" in extension or "yml" in extension: + with open(path, "r") as f: + import yaml + + return yaml.safe_load(f) + + else: + raise ValueError("Unable to recognize configuration file extension.") + + def check_config(self): + if "cores" not in self.config: + raise ValueError("No cores specified in configuration file.") + + if not len(self.config["cores"]) > 0: + raise ValueError("Must specify at least one core.") + + for name, attrs in self.config["cores"].items(): + # make sure core type is specified + if "type" not in attrs: + raise ValueError(f"No type specified for core {name}.") + + if attrs["type"] not in ["logic_analyzer", "io", "memory_read_only"]: + raise ValueError(f"Unrecognized core type specified for {name}.") + + def get_interface(self): + if "uart" in self.config: + return UARTInterface(self.config["uart"]) + + elif "ethernet" in self.config: + return EthernetInterface(self.config["ethernet"]) + + else: + raise ValueError("Unrecognized interface specified.") + + def get_cores(self): + """ """ + + cores = {} + base_addr = 0 + for name, attrs in self.config["cores"].items(): + if attrs["type"] == "io": + core = IOCore(attrs, base_addr, self.interface) + + elif attrs["type"] == "logic_analyzer": + core = LogicAnalyzerCore(attrs, base_addr, self.interface) + + elif attrs["type"] == "memory_read_only": + core = ReadOnlyMemoryCore(attrs, base_addr, self.interface) + + # make sure we're not out of address space + if core.get_max_addr() > (2**16) - 1: + raise ValueError( + f"Ran out of address space to allocate to core {name}." + ) + + # Make the next core's base address start one address after the previous one's + base_addr = core.get_max_addr() + 1 + cores[name] = core + + return cores + + def add_friendly_core_names(self): + """ + Add cores to the instance under a friendly name - ie, a core named `my_core` belonging + to a Manta instance `m` could be obtained with `m.cores["my_core"]`, but this allows + it to be obtained with `m.my_core`. Which is way nicer. + """ + + for name, instance in self.cores.items(): + if not hasattr(self, name): + setattr(self, name, instance) + + else: + raise ValueError( + "Cannot add object to Manta instance - name is already taken!" + ) + + def elaborate(self, platform): + # make a module object + # add all the submodules + # connect them together, which consists of: + # connect interface to first core + # connect cores to each other + # connect interface to last core + + m = Module() + + # Add interface as submodule + m.submodules["interface"] = self.interface + + # Add all cores as submodules + for name, instance in self.cores.items(): + m.submodules[name] = instance + + # Connect first/last cores to interface output/input respectively + core_instances = list(self.cores.values()) + first_core = core_instances[0] + last_core = core_instances[-1] + m.d.comb += [ + first_core.addr_i.eq(self.interface.addr_o), + first_core.data_i.eq(self.interface.data_o), + first_core.rw_i.eq(self.interface.rw_o), + first_core.valid_i.eq(self.interface.valid_o), + self.interface.addr_i.eq(last_core.addr_o), + self.interface.data_i.eq(last_core.data_o), + self.interface.rw_i.eq(last_core.rw_o), + self.interface.valid_i.eq(last_core.valid_o), + ] + + # Connect output of ith core to input of (i+1)th core + for i in range(len(core_instances) - 1): + ith_core = core_instances[i] + i_plus_oneth_core = core_instances[i + 1] + + m.d.comb += [ + i_plus_oneth_core.addr_i.eq(ith_core.addr_o), + i_plus_oneth_core.data_i.eq(ith_core.data_o), + i_plus_oneth_core.rw_i.eq(ith_core.rw_o), + i_plus_oneth_core.valid_i.eq(ith_core.valid_o), + ] + + return m + + def get_top_level_ports(self): + ports = self.interface.get_top_level_ports() + + for name, instance in self.cores.items(): + ports += instance.get_top_level_ports() + + return ports diff --git a/src/manta/manta_def_tmpl.v b/src/manta/manta_def_tmpl.v deleted file mode 100644 index 252a858..0000000 --- a/src/manta/manta_def_tmpl.v +++ /dev/null @@ -1,34 +0,0 @@ -/* -This module was generated with Manta /* VERSION */ on /* TIMESTAMP */ by /* USER */ - -If this breaks or if you've got spicy formal verification memes, contact fischerm [at] mit.edu - -Provided under a GNU GPLv3 license. Go wild. - -Here's an example instantiation of the Manta module you configured, feel free to copy-paste -this into your source! - -manta manta_inst ( - .clk(clk), - - /* EX_INST_PORTS */); - -*/ - -module manta ( - input wire clk, - - /* TOP_LEVEL_PORTS */); - - - /* INTERFACE_RX */ - - /* CORE_CHAIN */ - - /* INTERFACE_TX */ - -endmodule - -/* ---- Module Definitions ---- */ - -/* MODULE_DEFS */ \ No newline at end of file diff --git a/src/manta/memory_core.py b/src/manta/memory_core.py new file mode 100644 index 0000000..cf4d9ae --- /dev/null +++ b/src/manta/memory_core.py @@ -0,0 +1,205 @@ +from amaranth import * +from warnings import warn +from .utils import * +from math import ceil + + +class ReadOnlyMemoryCore(Elaboratable): + def __init__(self, config, base_addr, interface): + self.config = config + self.base_addr = base_addr + self.interface = interface + + self.check_config(config) + + self.depth = self.config["depth"] + self.width = self.config["width"] + self.max_addr = self.base_addr + (self.depth * ceil(self.width / 16)) + + self.define_signals() + self.define_mems() + + def check_config(self, config): + # Check for unrecognized options + valid_options = ["type", "depth", "width"] + for option in config: + if option not in valid_options: + warn(f"Ignoring unrecognized option '{option}' in memory core.") + + # Check depth is provided and positive + if "depth" not in config: + raise ValueError("Depth of memory core must be specified.") + + if not isinstance(config["depth"], int): + raise ValueError("Depth of memory core must be an integer.") + + if config["depth"] <= 0: + raise ValueError("Depth of memory core must be positive. ") + + # Check width is provided and positive + if "width" not in config: + raise ValueError("Width of memory core must be specified.") + + if not isinstance(config["width"], int): + raise ValueError("Width of memory core must be an integer.") + + if config["width"] <= 0: + raise ValueError("Width of memory core must be positive. ") + + def define_signals(self): + # Bus Input + self.addr_i = Signal(16) + self.data_i = Signal(16) + self.rw_i = Signal(1) + self.valid_i = Signal(1) + + # Bus Pipelining + self.addr_pipe = [Signal(16) for _ in range(3)] + self.data_pipe = [Signal(16) for _ in range(3)] + self.rw_pipe = [Signal(1) for _ in range(3)] + self.valid_pipe = [Signal(1) for _ in range(3)] + + # Bus Output + self.addr_o = Signal(16, reset=0) + self.data_o = Signal(16, reset=0) + self.rw_o = Signal(1, reset=0) + self.valid_o = Signal(1, reset=0) + + # User Port + self.user_addr = Signal(range(self.depth)) + self.user_data = Signal(self.width) + self.user_we = Signal(1) + + def pipeline_bus(self, m): + # Pipelining + m.d.sync += self.addr_pipe[0].eq(self.addr_i) + m.d.sync += self.data_pipe[0].eq(self.data_i) + m.d.sync += self.rw_pipe[0].eq(self.rw_i) + m.d.sync += self.valid_pipe[0].eq(self.valid_i) + + for i in range(1, 3): + m.d.sync += self.addr_pipe[i].eq(self.addr_pipe[i - 1]) + m.d.sync += self.data_pipe[i].eq(self.data_pipe[i - 1]) + m.d.sync += self.rw_pipe[i].eq(self.rw_pipe[i - 1]) + m.d.sync += self.valid_pipe[i].eq(self.valid_pipe[i - 1]) + + m.d.sync += self.addr_o.eq(self.addr_pipe[2]) + m.d.sync += self.data_o.eq(self.data_pipe[2]) + m.d.sync += self.rw_o.eq(self.rw_pipe[2]) + m.d.sync += self.valid_o.eq(self.valid_pipe[2]) + + def define_mems(self): + # ok there's three cases: + # 1. integer number of 16 bit mems + # 2. integer number of 16 bit mems + partial mem + # 3. just the partial mem (width < 16) + + # Only one, partial-width memory is needed + if self.width < 16: + self.mems = [Memory(depth=self.depth, width=self.width)] + + # Only full-width memories are needed + elif self.width % 16 == 0: + self.mems = [ + Memory(depth=self.depth, width=16) for _ in range(self.width // 16) + ] + + # Both full-width and partial memories are needed + else: + self.mems = [ + Memory(depth=self.depth, width=16) for i in range(self.width // 16) + ] + self.mems += [Memory(depth=self.depth, width=self.width % 16)] + + def handle_read_ports(self, m): + # These are tied to the bus + for i, mem in enumerate(self.mems): + read_port = mem.read_port() + m.d.comb += read_port.en.eq(1) + + start_addr = self.base_addr + (i * self.depth) + stop_addr = start_addr + self.depth - 1 + + # Throw BRAM operations into the front of the pipeline + with m.If( + (self.valid_i) + & (~self.rw_i) + & (self.addr_i >= start_addr) + & (self.addr_i <= stop_addr) + ): + m.d.sync += read_port.addr.eq(self.addr_i - start_addr) + + # Pull BRAM reads from the back of the pipeline + with m.If( + (self.valid_pipe[2]) + & (~self.rw_pipe[2]) + & (self.addr_pipe[2] >= start_addr) + & (self.addr_pipe[2] <= stop_addr) + ): + m.d.sync += self.data_o.eq(read_port.data) + + def handle_write_ports(self, m): + # These are given to the user + for i, mem in enumerate(self.mems): + write_port = mem.write_port() + + m.d.comb += write_port.addr.eq(self.user_addr) + m.d.comb += write_port.data.eq(self.user_data[16 * i : 16 * (i + 1)]) + m.d.comb += write_port.en.eq(self.user_we) + + def elaborate(self, platform): + m = Module() + + # Add memories as submodules + for i, mem in enumerate(self.mems): + m.submodules[f"mem_{i}"] = mem + + self.pipeline_bus(m) + self.handle_read_ports(m) + self.handle_write_ports(m) + return m + + def get_top_level_ports(self): + return [self.user_addr, self.user_data, self.user_we] + + def get_max_addr(self): + return self.max_addr + + def read_from_user_addr(self, addrs): + """ + Read the memory stored at the provided address, as seen from the user side. + """ + + # Convert user address space to bus address space + # (for instance, for a core with base address 10 and width 33, + # reading from address 4 is actually a read from address 14 and address 14 + depth, and address 14 + 2*depth) + + if isinstance(addrs, int): + return self.read_from_user_addr([addrs])[0] + + bus_addrs = [] + for addr in addrs: + bus_addrs += [ + addr + self.base_addr + i * self.depth for i in range(len(self.mems)) + ] + + datas = self.interface.read(bus_addrs) + data_chunks = split_into_chunks(datas, len(self.mems)) + return [words_to_value(chunk) for chunk in data_chunks] + + # def write_to_user_addr(self, addrs, datas): + # """ + # Read from the address + # """ + + # bus_addrs = [] + # for addr in addrs: + # bus_addrs += [ + # addr + self.base_addr + i * self.depth for i in range(len(self.mems)) + # ] + + # bus_datas = [] + # for data in datas: + # bus_datas += value_to_words(data) + + # self.interface.write(bus_addrs, bus_datas) diff --git a/src/manta/uart.py b/src/manta/uart.py new file mode 100644 index 0000000..cba6337 --- /dev/null +++ b/src/manta/uart.py @@ -0,0 +1,583 @@ +from amaranth import * +from amaranth.lib.data import ArrayLayout +from warnings import warn +from .utils import * +from serial import Serial + + +class UARTInterface(Elaboratable): + def __init__(self, config): + self.config = config + self.check_config(self.config) + + self.port = config["port"] + self.clock_freq = config["clock_freq"] + self.baudrate = config["baudrate"] + self.clocks_per_baud = int(self.clock_freq // self.baudrate) + + self.define_signals() + + # Set chunk_size, which is the max amount of bytes that the core will + # dump to the OS driver at a time. Since the FPGA will return bytes + # almost instantaneously, this prevents the OS's input buffer from + # overflowing, and dropping bytes. + self.chunk_size = 256 # in bytes + if "chunk_size" in config: + self.chunk_size = config["chunk_size"] + + def check_config(self, config): + # Warn if unrecognized options have been given + recognized_options = ["port", "clock_freq", "baudrate", "chunk_size"] + for option in config: + if option not in recognized_options: + warn( + f"Ignoring unrecognized option '{option}' in UART interface config." + ) + + # Ensure a serial port has been given + if "port" not in config: + raise ValueError("No serial port provided to UART interface.") + + # Ensure clock frequency is provided and positive + if "clock_freq" not in config: + raise ValueError("No clock frequency provided to UART interface.") + + if config["clock_freq"] <= 0: + raise ValueError("Non-positive clock frequency provided to UART interface.") + + # Check that baudrate is provided and positive + if "baudrate" not in config: + raise ValueError("No baudrate provided to UART interface.") + + if config["baudrate"] <= 0: + raise ValueError("Non-positive baudrate provided to UART interface.") + + # Confirm the actual baudrate is within 5% of the target baudrate + clock_freq = config["clock_freq"] + baudrate = config["baudrate"] + clocks_per_baud = clock_freq // baudrate + actual_baudrate = clock_freq / clocks_per_baud + error = 100 * abs(actual_baudrate - baudrate) / baudrate + + if error > 5: + raise ValueError( + "UART interface is unable to match targeted baudrate with specified clock frequency." + ) + + def get_serial_device(self): + """ + Return an open PySerial serial device if one exists, otherwise, open one. + """ + if hasattr(self, "serial_device"): + return self.serial_device + + else: + if self.port != "auto": + self.serial_device = Serial(self.port, self.baudrate, timeout=1) + return self.serial_device + + else: + # Try to autodetect which port to use based on the PID/VID of the device attached. + # This looks for the PID/VID of the FT2232, the primary chip used on the icestick + # and Digilent dev boards. However, folks will likely want to connect other things + # in the future, so in the future we'll probably want to look for other chips as + # well. + + # The FT2232 exposes two serial ports - and for whatever reason it usually has the + # 0th device used for JTAG programming, and the 1st used for UART. So we'll grab + # the 1st. + + import serial.tools.list_ports + + ports = [] + for port in serial.tools.list_ports.comports(): + if (port.vid == 0x403) and (port.pid == 0x6010): + ports.append(port) + + if len(ports) != 2: + raise ValueError( + f"Expected to see two serial ports for FT2232 device, but instead see {len(ports)}." + ) + + if ports[0].serial_number != ports[1].serial_number: + raise ValueError( + f"Serial numbers should be the same on both FT2232 ports - probably somehow grabbed ports on two different devices." + ) + + if ports[0].location > ports[1].location: + chosen_port = ports[0].device + + else: + chosen_port = ports[1].device + + self.serial_device = Serial(chosen_port, self.baudrate, timeout=1) + return self.serial_device + + def get_top_level_ports(self): + return [self.rx, self.tx] + + def read(self, addrs): + """ + Read the data stored in a set of address on Manta's internal memory. Addresses + must be specified as either integers or a list of integers. + """ + + # Handle a single integer address + if isinstance(addrs, int): + return self.read([addrs])[0] + + # Make sure all list elements are integers + if not all(isinstance(a, int) for a in addrs): + raise ValueError("Read address must be an integer or list of integers.") + + # Send read requests, and get responses + ser = self.get_serial_device() + addr_chunks = split_into_chunks(addrs, self.chunk_size) + datas = [] + + for addr_chunk in addr_chunks: + # Encode addrs into read requests + bytes_out = b"".join([f"R{a:04X}\r\n".encode("ascii") for a in addr_chunk]) + ser.write(bytes_out) + + # Read responses have the same length as read requests + bytes_in = ser.read(len(bytes_out)) + + if len(bytes_in) != len(bytes_out): + raise ValueError( + f"Only got {len(bytes_in)} out of {len(bytes_out)} bytes." + ) + + # Split received bytes into individual responses and decode + responses = split_into_chunks(bytes_in, 7) + data_chunk = [self.decode_read_response(r) for r in responses] + datas += data_chunk + + return datas + + def write(self, addrs, datas): + """ + Write the provided data into the provided addresses in Manta's internal memory. + Addresses and data must be specified as either integers or a list of integers. + """ + + # Handle a single integer address and data + if isinstance(addrs, int) and isinstance(datas, int): + return self.write([addrs], [datas]) + + # Make sure address and datas are all integers + if not isinstance(addrs, list) or not isinstance(datas, list): + raise ValueError( + "Write addresses and data must be an integer or list of integers." + ) + + if not all(isinstance(a, int) for a in addrs): + raise ValueError("Write addresses must be all be integers.") + + if not all(isinstance(d, int) for d in datas): + raise ValueError("Write data must all be integers.") + + # I'm not sure if it's necessary to split outputs into chunks + # I think the output buffer doesn't really drop stuff, just the input buffer + + # Encode addrs and datas into write requests + bytes_out = "".join([f"W{a:04X}{d:04X}\r\n" for a, d in zip(addrs, datas)]) + bytes_out = bytes_out.encode("ascii") + ser = self.get_serial_device() + ser.write(bytes_out) + + def decode_read_response(self, response_bytes): + """ + Check that read response is formatted properly, and extract the encoded data if so. + """ + + # Make sure response is not empty + if response_bytes is None: + raise ValueError("Unable to decode read response - no bytes received.") + + # Make sure response is properly encoded + response_ascii = response_bytes.decode("ascii") + + if len(response_ascii) != 7: + raise ValueError( + "Unable to decode read response - wrong number of bytes received." + ) + + if response_ascii[0] != "D": + raise ValueError("Unable to decode read response - incorrect preamble.") + + for i in range(1, 5): + if response_ascii[i] not in "0123456789ABCDEF": + raise ValueError("Unable to decode read response - invalid data byte.") + + if response_ascii[5] != "\r": + raise ValueError("Unable to decode read response - incorrect EOL.") + + if response_ascii[6] != "\n": + raise ValueError("Unable to decode read response - incorrect EOL.") + + return int(response_ascii[1:5], 16) + + def define_signals(self): + self.rx = Signal() + self.tx = Signal() + + self.addr_o = Signal(16) + self.data_o = Signal(16) + self.rw_o = Signal() + self.valid_o = Signal() + + self.addr_i = Signal(16) + self.data_i = Signal(16) + self.rw_i = Signal() + self.valid_i = Signal() + + def elaborate(self, platform): + # fancy submoduling and such goes in here + m = Module() + + m.submodules["uart_rx"] = uart_rx = UARTReceiver(self.clocks_per_baud) + m.submodules["bridge_rx"] = bridge_rx = RecieveBridge() + m.submodules["bridge_tx"] = bridge_tx = TransmitBridge() + m.submodules["uart_tx"] = uart_tx = UARTTransmitter(self.clocks_per_baud) + + m.d.comb += [ + # UART RX -> Internal Bus + uart_rx.rx.eq(self.rx), + bridge_rx.data_i.eq(uart_rx.data_o), + bridge_rx.valid_i.eq(uart_rx.valid_o), + self.data_o.eq(bridge_rx.data_o), + self.addr_o.eq(bridge_rx.addr_o), + self.rw_o.eq(bridge_rx.rw_o), + self.valid_o.eq(bridge_rx.valid_o), + # Internal Bus -> UART TX + bridge_tx.data_i.eq(self.data_i), + bridge_tx.rw_i.eq(self.rw_i), + bridge_tx.valid_i.eq(self.valid_i), + uart_tx.data_i.eq(bridge_tx.data_o), + uart_tx.start_i.eq(bridge_tx.start_o), + bridge_tx.done_i.eq(uart_tx.done_o), + self.tx.eq(uart_tx.tx), + ] + return m + + +class UARTReceiver(Elaboratable): + def __init__(self, clocks_per_baud): + self.clocks_per_baud = clocks_per_baud + + # Top-Level Ports + self.rx = Signal() + self.data_o = Signal(8, reset=0) + self.valid_o = Signal(1, reset=0) + + # Internal Signals + self.busy = Signal() + self.bit_index = Signal(range(10)) + self.baud_counter = Signal(range(2 * clocks_per_baud)) + + self.rx_d = Signal() + self.rx_q = Signal() + self.rx_q_prev = Signal() + + def elaborate(self, platform): + m = Module() + + # Two Flip-Flop Synchronizer + m.d.sync += [ + self.rx_d.eq(self.rx), + self.rx_q.eq(self.rx_d), + self.rx_q_prev.eq(self.rx_q), + ] + + m.d.sync += self.valid_o.eq(0) + + with m.If(~self.busy): + with m.If((~self.rx_q) & (self.rx_q_prev)): + m.d.sync += self.busy.eq(1) + m.d.sync += self.bit_index.eq(8) + m.d.sync += self.baud_counter.eq( + self.clocks_per_baud + (self.clocks_per_baud // 2) - 2 + ) + + with m.Else(): + with m.If(self.baud_counter == 0): + with m.If(self.bit_index == 0): + m.d.sync += self.valid_o.eq(1) + m.d.sync += self.busy.eq(0) + m.d.sync += self.bit_index.eq(0) + m.d.sync += self.baud_counter.eq(0) + + with m.Else(): + # m.d.sync += self.data_o.eq(Cat(self.rx_q, self.data_o[0:7])) + m.d.sync += self.data_o.eq(Cat(self.data_o[1:8], self.rx_q)) + m.d.sync += self.bit_index.eq(self.bit_index - 1) + m.d.sync += self.baud_counter.eq(self.clocks_per_baud - 1) + + with m.Else(): + m.d.sync += self.baud_counter.eq(self.baud_counter - 1) + + return m + + +class RecieveBridge(Elaboratable): + def __init__(self): + # Top-Level Ports + self.data_i = Signal(8) + self.valid_i = Signal() + + self.addr_o = Signal(16, reset=0) + self.data_o = Signal(16, reset=0) + self.rw_o = Signal(1, reset=0) + self.valid_o = Signal(1, reset=0) + + # State Machine + self.IDLE_STATE = 0 + self.READ_STATE = 1 + self.WRITE_STATE = 2 + + # Internal Signals + self.buffer = Signal(ArrayLayout(4, 8), reset_less=True) + self.state = Signal(2, reset=self.IDLE_STATE) + self.byte_num = Signal(4, reset=0) + self.is_eol = Signal() + self.is_ascii_hex = Signal() + self.from_ascii_hex = Signal(8) + + def drive_ascii_signals(self, m): + # Decode 0-9 + with m.If((self.data_i >= 0x30) & (self.data_i <= 0x39)): + m.d.comb += self.is_ascii_hex.eq(1) + m.d.comb += self.from_ascii_hex.eq(self.data_i - 0x30) + + # Decode A-F + with m.Elif((self.data_i >= 0x41) & (self.data_i <= 0x46)): + m.d.comb += self.is_ascii_hex.eq(1) + m.d.comb += self.from_ascii_hex.eq(self.data_i - 0x41 + 10) + + with m.Else(): + m.d.comb += self.is_ascii_hex.eq(0) + m.d.comb += self.from_ascii_hex.eq(0) + + with m.If((self.data_i == ord("\r")) | (self.data_i == ord("\n"))): + m.d.comb += self.is_eol.eq(1) + + with m.Else(): + m.d.comb += self.is_eol.eq(0) + + def drive_output_bus(self, m): + with m.If( + (self.state == self.READ_STATE) & (self.byte_num == 4) & (self.is_eol) + ): + m.d.comb += self.addr_o.eq( + Cat(self.buffer[3], self.buffer[2], self.buffer[1], self.buffer[0]) + ) + m.d.comb += self.data_o.eq(0) + m.d.comb += self.valid_o.eq(1) + m.d.comb += self.rw_o.eq(0) + + with m.Elif( + (self.state == self.WRITE_STATE) & (self.byte_num == 8) & (self.is_eol) + ): + m.d.comb += self.addr_o.eq( + Cat(self.buffer[3], self.buffer[2], self.buffer[1], self.buffer[0]) + ) + m.d.comb += self.data_o.eq( + Cat(self.buffer[7], self.buffer[6], self.buffer[5], self.buffer[4]) + ) + m.d.comb += self.valid_o.eq(1) + m.d.comb += self.rw_o.eq(1) + + with m.Else(): + m.d.comb += self.addr_o.eq(0) + m.d.comb += self.data_o.eq(0) + m.d.comb += self.rw_o.eq(0) + m.d.comb += self.valid_o.eq(0) + + def drive_fsm(self, m): + with m.If(self.valid_i): + with m.If(self.state == self.IDLE_STATE): + m.d.sync += self.byte_num.eq(0) + + with m.If(self.data_i == ord("R")): + m.d.sync += self.state.eq(self.READ_STATE) + + with m.Elif(self.data_i == ord("W")): + m.d.sync += self.state.eq(self.WRITE_STATE) + + with m.If(self.state == self.READ_STATE): + # buffer bytes if we don't have enough + with m.If(self.byte_num < 4): + # if bytes aren't valid ASCII then return to IDLE state + with m.If(self.is_ascii_hex == 0): + m.d.sync += self.state.eq(self.IDLE_STATE) + + # otherwise buffer them + with m.Else(): + m.d.sync += self.buffer[self.byte_num].eq(self.from_ascii_hex) + m.d.sync += self.byte_num.eq(self.byte_num + 1) + + with m.Else(): + m.d.sync += self.state.eq(self.IDLE_STATE) + + with m.If(self.state == self.WRITE_STATE): + # buffer bytes if we don't have enough + with m.If(self.byte_num < 8): + # if bytes aren't valid ASCII then return to IDLE state + with m.If(self.is_ascii_hex == 0): + m.d.sync += self.state.eq(self.IDLE_STATE) + + # otherwise buffer them + with m.Else(): + m.d.sync += self.buffer[self.byte_num].eq(self.from_ascii_hex) + m.d.sync += self.byte_num.eq(self.byte_num + 1) + + with m.Else(): + m.d.sync += self.state.eq(self.IDLE_STATE) + pass + + def elaborate(self, platform): + m = Module() + + self.drive_ascii_signals(m) + self.drive_output_bus(m) + self.drive_fsm(m) + + return m + + +class UARTTransmitter(Elaboratable): + def __init__(self, clocks_per_baud): + self.clocks_per_baud = clocks_per_baud + + # Top-Level Ports + self.data_i = Signal(8) + self.start_i = Signal() + self.done_o = Signal(reset=1) + + self.tx = Signal(reset=1) + + # Internal Signals + self.baud_counter = Signal(range(clocks_per_baud)) + self.buffer = Signal(9) + self.bit_index = Signal(4) + + def elaborate(self, platform): + m = Module() + + with m.If((self.start_i) & (self.done_o)): + m.d.sync += self.baud_counter.eq(self.clocks_per_baud - 1) + m.d.sync += self.buffer.eq(Cat(self.data_i, 1)) + m.d.sync += self.bit_index.eq(0) + m.d.sync += self.done_o.eq(0) + m.d.sync += self.tx.eq(0) + + with m.Elif(~self.done_o): + m.d.sync += self.baud_counter.eq(self.baud_counter - 1) + m.d.sync += self.done_o.eq((self.baud_counter == 1) & (self.bit_index == 9)) + + # A baud period has elapsed + with m.If(self.baud_counter == 0): + m.d.sync += self.baud_counter.eq(self.clocks_per_baud - 1) + + # Clock out another bit if there are any left + with m.If(self.bit_index < 9): + m.d.sync += self.tx.eq(self.buffer.bit_select(self.bit_index, 1)) + m.d.sync += self.bit_index.eq(self.bit_index + 1) + + # Byte has been sent, send out next one or go to idle + with m.Else(): + with m.If(self.start_i): + m.d.sync += self.buffer.eq(Cat(self.data_i, 1)) + m.d.sync += self.bit_index.eq(0) + m.d.sync += self.tx.eq(0) + + with m.Else(): + m.d.sync += self.done_o.eq(1) + return m + + +class TransmitBridge(Elaboratable): + def __init__(self): + # Top-Level Ports + self.data_i = Signal(16) + self.rw_i = Signal() + self.valid_i = Signal() + + self.data_o = Signal(8, reset=0) + self.start_o = Signal(1) + self.done_i = Signal() + + # Internal Signals + self.buffer = Signal(16, reset=0) + self.count = Signal(4, reset=0) + self.busy = Signal(1, reset=0) + self.to_ascii_hex = Signal(8) + self.n = Signal(4) + + def elaborate(self, platform): + m = Module() + + m.d.comb += self.start_o.eq(self.busy) + + with m.If(~self.busy): + with m.If((self.valid_i) & (~self.rw_i)): + m.d.sync += self.busy.eq(1) + m.d.sync += self.buffer.eq(self.data_i) + + with m.Else(): + # uart_tx is transmitting a byte: + with m.If(self.done_i): + m.d.sync += self.count.eq(self.count + 1) + + # Message has been transmitted + with m.If(self.count > 5): + m.d.sync += self.count.eq(0) + + # Go back to idle, or transmit next message + with m.If((self.valid_i) & (~self.rw_i)): + m.d.sync += self.buffer.eq(self.data_i) + + with m.Else(): + m.d.sync += self.busy.eq(0) + + # define to_ascii_hex + with m.If(self.n < 10): + m.d.comb += self.to_ascii_hex.eq(self.n + 0x30) + with m.Else(): + m.d.comb += self.to_ascii_hex.eq(self.n + 0x41 - 10) + + # run the sequence + with m.If(self.count == 0): + m.d.comb += self.n.eq(0) + m.d.comb += self.data_o.eq(ord("D")) + + with m.Elif(self.count == 1): + m.d.comb += self.n.eq(self.buffer[12:16]) + m.d.comb += self.data_o.eq(self.to_ascii_hex) + + with m.Elif(self.count == 2): + m.d.comb += self.n.eq(self.buffer[8:12]) + m.d.comb += self.data_o.eq(self.to_ascii_hex) + + with m.Elif(self.count == 3): + m.d.comb += self.n.eq(self.buffer[4:8]) + m.d.comb += self.data_o.eq(self.to_ascii_hex) + + with m.Elif(self.count == 4): + m.d.comb += self.n.eq(self.buffer[0:4]) + m.d.comb += self.data_o.eq(self.to_ascii_hex) + + with m.Elif(self.count == 5): + m.d.comb += self.n.eq(0) + m.d.comb += self.data_o.eq(ord("\r")) + + with m.Elif(self.count == 6): + m.d.comb += self.n.eq(0) + m.d.comb += self.data_o.eq(ord("\n")) + + with m.Else(): + m.d.comb += self.n.eq(0) + m.d.comb += self.data_o.eq(0) + + return m diff --git a/src/manta/uart_iface/__init__.py b/src/manta/uart_iface/__init__.py deleted file mode 100644 index 98f2ffc..0000000 --- a/src/manta/uart_iface/__init__.py +++ /dev/null @@ -1,186 +0,0 @@ -from ..utils import * - -class UARTInterface: - def __init__(self, config): - # Warn if unrecognized options have been given - for option in config: - if option not in ["port", "clock_freq", "baudrate", "chunk_size", "verbose"]: - print(f"Warning: Ignoring unrecognized option '{option}' in UART interface.") - - # Obtain port. Try to automatically detect port if "auto" is specified - assert "port" in config, "No serial port provided to UART core." - self.port = config["port"] - - # Check that clock frequency is provided and positive - assert "clock_freq" in config, "Clock frequency not provided to UART core." - assert config["clock_freq"] > 0, "Clock frequency must be positive." - self.clock_freq = config["clock_freq"] - - # Check that baudrate is provided and positive - assert "baudrate" in config, "Baudrate not provided to UART core." - assert config["baudrate"] > 0, "Baudrate must be positive." - self.baudrate = config["baudrate"] - - # Confirm core clock is sufficiently fast - clocks_per_baud = self.clock_freq // self.baudrate - assert clocks_per_baud >= 2 - self.clocks_per_baud = clocks_per_baud - - # Confirm we can match baudrate suffeciently well - actual_baudrate = self.clock_freq / clocks_per_baud - baudrate_error = 100 * abs(actual_baudrate - self.baudrate) / self.baudrate - assert baudrate_error <= 5, \ - "Unable to match target baudrate - they differ by {baudrate_error}%" - - # Set chunk_size, which is the max amount of bytes that get dumped - # to the OS driver at a time - self.chunk_size = 256 - if "chunk_size" in config: - self.chunk_size = config["chunk_size"] - - # Set verbosity - self.verbose = False - if "verbose" in config: - self.verbose = config["verbose"] - - def open_port_if_not_alredy_open(self): - if self.port == "auto": - self.port = self.autodetect_port() - - if not hasattr(self, "ser"): - import serial - self.ser = serial.Serial(self.port, self.baudrate) - - def autodetect_port(self): - # as far as I know the FT2232 is the only chip used on the icestick/digilent boards, so just look for that - import serial.tools.list_ports - - recognized_devices = [] - for port in serial.tools.list_ports.comports(): - if (port.vid == 0x403) and (port.pid == 0x6010): - recognized_devices.append(port) - - # board manufacturers seem to always make the 0th serial - # interface on the FT2232 be for programming over JTAG, - # and then the 1st to be for UART. as a result, we always - # grab the device with the larger location - - rd = recognized_devices - assert len(recognized_devices) == 2, f"Expected to see two serial ports for FT2232 device, but instead see {len(recognized_devices)}." - assert rd[0].serial_number == rd[1].serial_number, "Serial numbers should be the same on both FT2232 ports - probably somehow grabbed ports on two different devices." - return rd[0].device if rd[0].location > rd[1].location else rd[1].device - - def decode_response(self, response): - """Make sure reponse from FPGA has the correct format, and return data contained within if so.""" - assert response is not None, "No reponse received." - - response_str = response.decode('ascii') - assert response_str[0] == 'D', "Bad message recieved, incorrect preamble." - assert response_str[-2] == '\r', "Bad message received, incorrect EOL." - assert response_str[-1] == '\n', "Bad message received, incorrect EOL." - assert len(response_str) == 7, f"Wrong number of bytes received, expecting 7 but got {len(response)}." - - return int(response_str[1:5], 16) - - - def read(self, addr): - # Perform type checks, output list of addresses - if isinstance(addr, int): - addrs = [addr] - - elif isinstance(addr, list): - assert all(isinstance(a, int) for a in addr), \ - "Read addresses must be integer or list of integers." - addrs = addr - - else: - raise ValueError("Read addresses must be integer or list of integers.") - - # send data in chunks because the reponses will fill up the OS's - # input buffer in no time flat - self.open_port_if_not_alredy_open() - - inbound_bytes = b"" - for i in range(0, len(addrs), self.chunk_size): - addr_chunk = addrs[i:i+self.chunk_size] - - outbound_bytes = [f"R{addr:04X}\r\n".encode('ascii') for addr in addr_chunk] - outbound_bytes = b"".join(outbound_bytes) - - self.ser.write(outbound_bytes) - - inbound_bytes += self.ser.read(len(outbound_bytes)) - - data = [] - for i in range(0, len(inbound_bytes), 7): - response = inbound_bytes[i:i+7] - data.append(self.decode_response(response)) - - if isinstance(addr, int): - return data[0] - - else: - return data - - def write(self, addr, data): - # Perform type checks, output list of addresses - if isinstance(addr, int): - assert isinstance(data, int), \ - "Data must also be integer if address is integer." - addrs = [addr] - datas = [data] - - elif isinstance(addr, list): - assert all(isinstance(a, int) for a in addr), \ - "Write addresses must be integer or list of integers." - - assert all(isinstance(d, int) for d in data), \ - "Write data must be integer or list of integers." - - assert len(addr) == len(data), \ - "There must be equal number of write addresses and data." - - addrs = addr - datas = data - - else: - raise ValueError("Write addresses and data must be integer or list of integers.") - - # send data in chunks because the reponses will fill up the OS's - # input buffer in no time flat - self.open_port_if_not_alredy_open() - - for i in range(0, len(addrs), self.chunk_size): - addr_chunk = addrs[i:i+self.chunk_size] - data_chunk = datas[i:i+self.chunk_size] - - - outbound_bytes = [f"W{a:04X}{d:04X}\r\n" for a, d in zip(addr_chunk, data_chunk)] - outbound_bytes = [ob.encode('ascii') for ob in outbound_bytes] - outbound_bytes = b"".join(outbound_bytes) - - self.ser.write(outbound_bytes) - - def hdl_top_level_ports(self): - # this should return the probes that we want to connect to top-level, but like as a string of verilog - return ["input wire rx", "output reg tx"] - - def rx_hdl_def(self): - uart_rx_def = VerilogManipulator("uart_iface/uart_rx.v").get_hdl() - bridge_rx_def = VerilogManipulator("uart_iface/bridge_rx.v").get_hdl() - return uart_rx_def + '\n' + bridge_rx_def - - def tx_hdl_def(self): - uart_tx_def = VerilogManipulator("uart_iface/uart_tx.v").get_hdl() - bridge_tx_def = VerilogManipulator("uart_iface/bridge_tx.v").get_hdl() - return bridge_tx_def + '\n' + uart_tx_def - - def rx_hdl_inst(self): - rx = VerilogManipulator("uart_iface/uart_rx_bridge_rx_inst_tmpl.v") - rx.sub(self.clocks_per_baud, "/* CLOCKS_PER_BAUD */") - return rx.get_hdl() - - def tx_hdl_inst(self): - tx = VerilogManipulator("uart_iface/uart_tx_bridge_tx_inst_tmpl.v") - tx.sub(self.clocks_per_baud, "/* CLOCKS_PER_BAUD */") - return tx.get_hdl() \ No newline at end of file diff --git a/src/manta/uart_iface/bridge_rx.v b/src/manta/uart_iface/bridge_rx.v deleted file mode 100644 index 995b1ab..0000000 --- a/src/manta/uart_iface/bridge_rx.v +++ /dev/null @@ -1,150 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -module bridge_rx ( - input wire clk, - - input wire [7:0] data_i, - input wire valid_i, - - output reg [15:0] addr_o, - output reg [15:0] data_o, - output reg rw_o, - output reg valid_o); - - initial addr_o = 0; - initial data_o = 0; - initial rw_o = 0; - initial valid_o = 0; - - function [3:0] from_ascii_hex; - // convert an ascii char encoding a hex value to - // the corresponding hex value - input [7:0] c; - - if ((c >= 8'h30) && (c <= 8'h39)) from_ascii_hex = c - 8'h30; - else if ((c >= 8'h41) && (c <= 8'h46)) from_ascii_hex = c - 8'h41 + 'd10; - else from_ascii_hex = 0; - endfunction - - function is_ascii_hex; - // checks if a byte is an ascii char encoding a hex digit - input [7:0] c; - - if ((c >= 8'h30) && (c <= 8'h39)) is_ascii_hex = 1; // 0-9 - else if ((c >= 8'h41) && (c <= 8'h46)) is_ascii_hex = 1; // A-F - else is_ascii_hex = 0; - endfunction - - reg [7:0] buffer [7:0]; // = 0; // todo: see if sby will tolerate packed arrays? - - localparam IDLE = 0; - localparam READ = 1; - localparam WRITE = 2; - reg [1:0] state = 0; - reg [3:0] byte_num = 0; - - always @(posedge clk) begin - addr_o <= 0; - data_o <= 0; - rw_o <= 0; - valid_o <= 0; - - if (state == IDLE) begin - byte_num <= 0; - if (valid_i) begin - if (data_i == "R") state <= READ; - if (data_i == "W") state <= WRITE; - end - end - - else begin - if (valid_i) begin - // buffer bytes regardless of if they're good - byte_num <= byte_num + 1; - buffer[byte_num] <= data_i; - - // current transaction specifies a read operation - if(state == READ) begin - - // go to idle if anything doesn't make sense - if(byte_num < 4) begin - if(!is_ascii_hex(data_i)) state <= IDLE; - end - - else if(byte_num == 4) begin - state <= IDLE; - - // put data on the bus if the last byte looks good - if((data_i == 8'h0D) || (data_i == 8'h0A)) begin - addr_o <= (from_ascii_hex(buffer[0]) << 12) | - (from_ascii_hex(buffer[1]) << 8) | - (from_ascii_hex(buffer[2]) << 4) | - (from_ascii_hex(buffer[3])); - data_o <= 0; - rw_o <= 0; - valid_o <= 1; - end - end - end - - // current transaction specifies a write transaction - if(state == WRITE) begin - - // go to idle if anything doesn't make sense - if(byte_num < 8) begin - if(!is_ascii_hex(data_i)) state <= IDLE; - end - - else if(byte_num == 8) begin - state <= IDLE; - - // put data on the bus if the last byte looks good - if((data_i == 8'h0A) || (data_i == 8'h0D)) begin - addr_o <= (from_ascii_hex(buffer[0]) << 12) | - (from_ascii_hex(buffer[1]) << 8) | - (from_ascii_hex(buffer[2]) << 4) | - (from_ascii_hex(buffer[3])); - data_o <= (from_ascii_hex(buffer[4]) << 12) | - (from_ascii_hex(buffer[5]) << 8) | - (from_ascii_hex(buffer[6]) << 4) | - (from_ascii_hex(buffer[7])); - rw_o <= 1; - valid_o <= 1; - end - end - end - end - end - end - -`ifdef FORMAL - always @(posedge clk) begin - // covers - find_any_write_transaction: cover(rw_o == 1); - find_any_read_transaction: cover(rw_o == 0); - - find_specific_write_transaction: - cover(data_o == 16'h1234 && addr_o == 16'h5678 && rw_o == 1 && valid_o == 1); - - find_specific_read_transaction: - cover(addr_o == 16'h1234 && rw_o == 0 && valid_o == 1); - - find_spacey_write_transaction: - cover((rw_o == 1) && ($past(valid_i, 3) == 0)); - - // asserts - no_back_to_back_transactions: - assert( ~(valid_o && $past(valid_o)) ); - - no_invalid_states: - assert(state == IDLE || state == READ || state == WRITE); - - byte_counter_only_increases: - assert(byte_num == $past(byte_num) || byte_num == $past(byte_num) + 1 || byte_num == 0); - end -`endif // FORMAL -endmodule - - -`default_nettype wire \ No newline at end of file diff --git a/src/manta/uart_iface/bridge_tx.v b/src/manta/uart_iface/bridge_tx.v deleted file mode 100644 index 70bbf0d..0000000 --- a/src/manta/uart_iface/bridge_tx.v +++ /dev/null @@ -1,70 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -module bridge_tx ( - input wire clk, - - input wire [15:0] data_i, - input wire rw_i, - input wire valid_i, - - output reg [7:0] data_o, - output reg start_o, - input wire done_i); - - function [7:0] to_ascii_hex; - // convert a number from 0-15 into the corresponding ascii char - input [3:0] n; - to_ascii_hex = (n < 10) ? (n + 8'h30) : (n + 8'h41 - 'd10); - endfunction - - localparam PREAMBLE = "D"; - localparam CR = 8'h0D; - localparam LF = 8'h0A; - - reg busy = 0; - reg [15:0] buffer = 0; - reg [3:0] count = 0; - - assign start_o = busy; - - always @(posedge clk) begin - // idle until valid read transaction arrives on bus - if (!busy) begin - if (valid_i && !rw_i) begin - busy <= 1; - buffer <= data_i; - end - end - - if (busy) begin - // uart module is done transmitting a byte - if(done_i) begin - count <= count + 1; - - // message has been transmitted - if (count > 5) begin - count <= 0; - - // go back to idle or transmit next message - if (valid_i && !rw_i) buffer <= data_i; - else busy <= 0; - end - end - end - end - - always @(*) begin - case (count) - 0: data_o = PREAMBLE; - 1: data_o = to_ascii_hex(buffer[15:12]); - 2: data_o = to_ascii_hex(buffer[11:8]); - 3: data_o = to_ascii_hex(buffer[7:4]); - 4: data_o = to_ascii_hex(buffer[3:0]); - 5: data_o = CR; - 6: data_o = LF; - default: data_o = 0; - endcase - end -endmodule -`default_nettype wire \ No newline at end of file diff --git a/src/manta/uart_iface/uart_rx.v b/src/manta/uart_iface/uart_rx.v deleted file mode 100644 index a4e8abb..0000000 --- a/src/manta/uart_iface/uart_rx.v +++ /dev/null @@ -1,62 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -// Modified from Dan Gisselquist's rx_uart module, -// available at https://zipcpu.com/tutorial/ex-09-uartrx.zip - -module uart_rx ( - input wire clk, - - input wire rx, - - output reg [7:0] data_o, - output reg valid_o); - - parameter CLOCKS_PER_BAUD = 0; - localparam IDLE = 0; - localparam BIT_ZERO = 1; - localparam STOP_BIT = 9; - - reg [3:0] state = IDLE; - reg [15:0] baud_counter = 0; - reg zero_baud_counter; - assign zero_baud_counter = (baud_counter == 0); - - // 2FF Synchronizer - reg ck_uart = 1; - reg q_uart = 1; - always @(posedge clk) - { ck_uart, q_uart } <= { q_uart, rx }; - - always @(posedge clk) - if (state == IDLE) begin - state <= IDLE; - baud_counter <= 0; - if (!ck_uart) begin - state <= BIT_ZERO; - baud_counter <= CLOCKS_PER_BAUD+CLOCKS_PER_BAUD/2-1'b1; - end - end - - else if (zero_baud_counter) begin - state <= state + 1; - baud_counter <= CLOCKS_PER_BAUD-1'b1; - if (state == STOP_BIT) begin - state <= IDLE; - baud_counter <= 0; - end - end - - else baud_counter <= baud_counter - 1'b1; - - always @(posedge clk) - if ( (zero_baud_counter) && (state != STOP_BIT) ) - data_o <= {ck_uart, data_o[7:1]}; - - initial valid_o = 1'b0; - always @(posedge clk) - valid_o <= ( (zero_baud_counter) && (state == STOP_BIT) ); - -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/src/manta/uart_iface/uart_rx_bridge_rx_inst_tmpl.v b/src/manta/uart_iface/uart_rx_bridge_rx_inst_tmpl.v deleted file mode 100644 index 8ff8dec..0000000 --- a/src/manta/uart_iface/uart_rx_bridge_rx_inst_tmpl.v +++ /dev/null @@ -1,20 +0,0 @@ -uart_rx #(.CLOCKS_PER_BAUD(/* CLOCKS_PER_BAUD */)) urx ( - .clk(clk), - .rx(rx), - - .data_o(urx_brx_data), - .valid_o(urx_brx_valid)); - -reg [7:0] urx_brx_data; -reg urx_brx_valid; - -bridge_rx brx ( - .clk(clk), - - .data_i(urx_brx_data), - .valid_i(urx_brx_valid), - - .addr_o(), - .data_o(), - .rw_o(), - .valid_o()); \ No newline at end of file diff --git a/src/manta/uart_iface/uart_tx.v b/src/manta/uart_iface/uart_tx.v deleted file mode 100644 index ea249a7..0000000 --- a/src/manta/uart_iface/uart_tx.v +++ /dev/null @@ -1,61 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -module uart_tx ( - input wire clk, - - input wire [7:0] data_i, - input wire start_i, - output reg done_o, - - output reg tx); - - // this module supports only 8N1 serial at a configurable baudrate - parameter CLOCKS_PER_BAUD = 0; - reg [$clog2(CLOCKS_PER_BAUD)-1:0] baud_counter = 0; - - reg [8:0] buffer = 0; - reg [3:0] bit_index = 0; - - initial done_o = 1; - initial tx = 1; - - always @(posedge clk) begin - if (start_i && done_o) begin - baud_counter <= CLOCKS_PER_BAUD - 1; - buffer <= {1'b1, data_i}; - bit_index <= 0; - done_o <= 0; - tx <= 0; - end - - else if (!done_o) begin - baud_counter <= baud_counter - 1; - done_o <= (baud_counter == 1) && (bit_index == 9); - - // a baud period has elapsed - if (baud_counter == 0) begin - baud_counter <= CLOCKS_PER_BAUD - 1; - - // clock out another bit if there are any left - if (bit_index < 9) begin - tx <= buffer[bit_index]; - bit_index <= bit_index + 1; - end - - // byte has been sent, send out next one or go to idle - else begin - if(start_i) begin - buffer <= {1'b1, data_i}; - bit_index <= 0; - tx <= 0; - end - - else done_o <= 1; - end - end - end - end -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/src/manta/uart_iface/uart_tx_bridge_tx_inst_tmpl.v b/src/manta/uart_iface/uart_tx_bridge_tx_inst_tmpl.v deleted file mode 100644 index bfe68b6..0000000 --- a/src/manta/uart_iface/uart_tx_bridge_tx_inst_tmpl.v +++ /dev/null @@ -1,23 +0,0 @@ -bridge_tx btx ( - .clk(clk), - - .data_i(), - .rw_i(), - .valid_i(), - - .data_o(btx_utx_data), - .start_o(btx_utx_start), - .done_i(utx_btx_done)); - -reg [7:0] btx_utx_data; -reg btx_utx_start; -reg utx_btx_done; - -uart_tx #(.CLOCKS_PER_BAUD(/* CLOCKS_PER_BAUD */)) utx ( - .clk(clk), - - .data_i(btx_utx_data), - .start_i(btx_utx_start), - .done_o(utx_btx_done), - - .tx(tx)); \ No newline at end of file diff --git a/src/manta/utils.py b/src/manta/utils.py index 67decc5..a40fa0a 100644 --- a/src/manta/utils.py +++ b/src/manta/utils.py @@ -1,124 +1,129 @@ -import pkgutil +from amaranth.sim import Simulator from math import ceil +import os -def pack_16bit_words(data): - """Takes a list of integers, interprets them as 16-bit integers, and - concatenates them together in little-endian order.""" + +def words_to_value(data): + """ + Takes a list of integers, interprets them as 16-bit integers, and + concatenates them together in little-endian order. + """ for d in data: - if d > 0: assert d < 2**16, "Unsigned integer too large." - if d < 0: assert d < 2**15, "Signed integer too large." + if d > 0 and d > 2**16 - 1: + raise ValueError("Unsigned integer too large.") - return int(''.join([f'{i:016b}' for i in data[::-1]]), 2) + if d < 0 and d < -(2**15 - 1): + raise ValueError("Signed integer too large.") -def unpack_16bit_words(data, n_words): - """Takes a integer, interprets it as a set of 16-bit integers - concatenated together, and splits it into a list of 16-bit numbers""" + return int("".join([f"{i:016b}" for i in data[::-1]]), 2) - assert isinstance(data, int), "Behavior is only defined for nonnegative integers." - assert data >= 0, "Behavior is only defined for nonnegative integers." + +def value_to_words(data, n_words): + """ + Takes a integer, interprets it as a set of 16-bit integers + concatenated together, and splits it into a list of 16-bit numbers. + """ + + if not isinstance(data, int) or data < 0: + raise ValueError("Behavior is only defined for nonnegative integers.") # convert to binary, split into 16-bit chunks, and then convert back to list of int - binary = f'{data:0b}'.zfill(n_words * 16) - return [int(binary[i:i+16], 2) for i in range(0, 16 * n_words, 16)][::-1] - -class VerilogManipulator: - def __init__(self, filepath=None): - if filepath is not None: - self.hdl = pkgutil.get_data(__name__, filepath).decode() - - # scrub any default_nettype or timescale directives from the source - self.hdl = self.hdl.replace("`default_nettype none", "") - self.hdl = self.hdl.replace("`default_nettype wire", "") - self.hdl = self.hdl.replace("`timescale 1ns/1ps", "") - self.hdl = self.hdl.strip() - - # python tries to be cute and automatically convert - # line endings on Windows, but Manta's source comes - # with (and injects) UNIX line endings, so Python - # ends up adding way too many line breaks, so we just - # undo anything it's done when we load the file - self.hdl = self.hdl.replace("\r\n", "\n") - - else: - self.hdl = None - - def sub(self, replace, find): - # sometimes we have integer inputs, want to accomodate - if isinstance(replace, str): - replace_str = replace - - elif isinstance(replace, int): - replace_str = str(replace) - - else: - raise ValueError("Only string and integer arguments supported.") + binary = f"{data:0b}".zfill(n_words * 16) + return [int(binary[i : i + 16], 2) for i in range(0, 16 * n_words, 16)][::-1] - # if the string being subbed in isn't multiline, just - # find-and-replace like normal: - if "\n" not in replace_str: - self.hdl = self.hdl.replace(find, replace_str) +def split_into_chunks(data, chunk_size): + """ + Split a list into a list of lists, where each sublist has length `chunk_size`. + If the list can't be evenly divided into chunks, then the last entry in the + returned list will have length less than `chunk_size`. + """ - # if the string being substituted in is multiline, - # make sure the replace text gets put at the same - # indentation level by adding whitespace to left - # of the line. - else: - for line in self.hdl.split("\n"): - if find in line: - # get whitespace that's on the left side of the line - whitespace = line.rstrip().replace(line.lstrip(), "") - - # add it to every line, except the first - replace_as_lines = replace_str.split("\n") - replace_with_whitespace = f"\n{whitespace}".join(replace_as_lines) - - # replace the first occurance in the HDL with it - self.hdl = self.hdl.replace(find, replace_with_whitespace, 1) - - def get_hdl(self): - return self.hdl - - def net_dec(self, nets, net_type, trailing_comma = False): - """Takes a dictonary of nets in the format {probe: width}, and generates - the net declarations that would go in a Verilog module definition. - - For example, calling net_dec({foo : 1, bar : 4}, "input wire") would produce: - - input wire foo, - input [3:0] wire bar - - Which you'd then slap into your module declaration, along with all the other - inputs and outputs the module needs.""" - - dec = [] - for name, width in nets.items(): - if width == 1: - dec.append(f"{net_type} {name}") - - else: - dec.append(f"{net_type} [{width-1}:0] {name}") - - dec = ",\n".join(dec) - dec = dec + "," if trailing_comma else dec - return dec - - def net_conn(self, nets, trailing_comma = False): - """Takes a dictionary of nets in the format {probe: width}, and generates - the net connections that would go in the Verilog module instantiation. - - For example, calling net_conn({foo: 1, bar: 4}) would produce: - - .foo(foo), - .bar(bar) - - Which you'd then slap into your module instantiation, along with all the other - module inputs and outputs that get connected elsewhere.""" + return [data[i : i + chunk_size] for i in range(0, len(data), chunk_size)] - conn = [f".{name}({name})" for name in nets] - conn = ",\n".join(conn) - conn = conn + "," if trailing_comma else conn +def simulate(top, testbench, vcd_path=None): + """ + Run a behavior simulation using Amaranth's built-in simulator `pysim`. Takes + the top-level module to simulate, the testbench process to run, and an optional + path to export a VCD file to. + """ + sim = Simulator(top) + sim.add_clock(1e-6) # 1 MHz + sim.add_sync_process(testbench) - return conn + if vcd_path is None: + sim.run() + + else: + with sim.write_vcd(vcd_path): + sim.run() + + +def verify_register(module, addr, expected_data): + """ + Read the contents of a register out over a module's bus connection, and verify + that it contains the expected data. + + Unfortunately because Amaranth uses generator functions to define processes, + this must be a generator function and thus cannot return a value - it must + yield the next timestep. This means that the comparision with the expected + value must occur inside this function and not somewhere else, it's not + possible to return a value from here, and compare it in the calling function. + """ + + # place read transaction on the bus + yield module.addr_i.eq(addr) + yield module.data_i.eq(0) + yield module.rw_i.eq(0) + yield module.valid_i.eq(1) + yield + yield module.addr_i.eq(0) + yield module.valid_i.eq(0) + + # wait for output to be valid + while not (yield module.valid_o): + yield + + # compare returned value with expected + data = yield (module.data_o) + if data != expected_data: + raise ValueError(f"Read from {addr} yielded {data} instead of {expected_data}") + + +def write_register(module, addr, data): + """ + Write to a register over a module's bus connection, placing the contents of `data` + at `addr`. + """ + + yield module.addr_i.eq(addr) + yield module.data_i.eq(data) + yield module.rw_i.eq(1) + yield module.valid_i.eq(1) + yield + yield module.valid_i.eq(0) + yield + + +def xilinx_tools_installed(): + """ + Return whether Vivado is installed, by checking if the VIVADO environment variable is set. + + This variable should point to the binary itself, not just the folder it's located in + (ie, /tools/Xilinx/Vivado/2023.1/bin/vivado, not /tools/Xilinx/Vivado/2023.1/bin) + """ + return "VIVADO" in os.environ + + +def ice40_tools_installed(): + """ + Return whether the ice40 tools are installed, by checking if the YOSYS, NEXTPNR_ICE40, + ICEPACK, and ICEPROG environment variables are defined. + + # These variables should point to the binaries themselves, not just the folder it's located in + # (ie, /tools/oss-cad-suite/bin/yosys, not /tools/oss-cad-suite/bin/) + """ + tools = ["YOSYS", "NEXTPNR_ICE40", "ICEPACK", "ICEPROG"] + return all(tool in os.environ for tool in tools) diff --git a/test/auto_gen/invalid_configs/0_mangled_yaml.yaml b/test/auto_gen/invalid_configs/0_mangled_yaml.yaml deleted file mode 100644 index 866e678..0000000 --- a/test/auto_gen/invalid_configs/0_mangled_yaml.yaml +++ /dev/null @@ -1,26 +0,0 @@ ---- -cores: - my_io_core: - type: io - - inputs: - btnu: 1 - btnd: 1 - btnl: Q - btnr: 1 - btnc: 1 - sw: 16 - - outputs: - led: 16 - led16_b: 1 - led16_g: 1 - led16_r: 1 - led17_b: 1 - led17_g: 1 - led17_r: 1 - -uart: - port: "auto" - baudrate: 115200 - clock_freq: 100000000 \ No newline at end of file diff --git a/test/auto_gen/invalid_configs/1_mangled_yaml.yaml b/test/auto_gen/invalid_configs/1_mangled_yaml.yaml deleted file mode 100644 index c786cdb..0000000 --- a/test/auto_gen/invalid_configs/1_mangled_yaml.yaml +++ /dev/null @@ -1,26 +0,0 @@ ---- -cores: - my_io_core: - type: io - - inputs: - btnu: 1 - btnd: 1 - btnl: 1 - btnr: 1 - btnc: - sw: 16 - - outputs: - led: 16 - led16_b: 1 - led16_g: 1 - led16_r: 1 - led17_b: 1 - led17_g: 1 - led17_r: 1 - -uart: - port: "auto" - baudrate: 115200 - clock_freq: 100000000 \ No newline at end of file diff --git a/test/auto_gen/invalid_configs/2_mangled_yaml.yaml b/test/auto_gen/invalid_configs/2_mangled_yaml.yaml deleted file mode 100644 index 9386d37..0000000 --- a/test/auto_gen/invalid_configs/2_mangled_yaml.yaml +++ /dev/null @@ -1,26 +0,0 @@ ---- -cores: - my_io_core: - type: io - - inputs: - btnu: 1 - btnd: 1 - btnl: 1 - btnr: 1 - btnc: randomstringthatsnotaninteger - sw: 16 - - outputs: - led: 16 - led16_b: 1 - led16_g: 1 - led16_r: 1 - led17_b: 1 - led17_g: 1 - led17_r: 1 - -uart: - port: "auto" - baudrate: 115200 - clock_freq: 100000000 \ No newline at end of file diff --git a/test/auto_gen/run_tests.py b/test/auto_gen/run_tests.py deleted file mode 100644 index 3e5ec4c..0000000 --- a/test/auto_gen/run_tests.py +++ /dev/null @@ -1,56 +0,0 @@ -# try to build manta instances from valid and invalid configuration files - -from os import listdir -from os.path import isfile -from manta import Manta - - -# Valid Configurations - -# test that they make a python API without errors -# TODO: test that their verilog passes lint - -print(" ==== Testing valid configurations ====") -valid_configs_path = "test/auto_gen/valid_configs/" -for config_file in sorted(listdir(valid_configs_path)): - caught_exception = None - try: - m = Manta(valid_configs_path + config_file) - - except Exception as e: - caught_exception = e - - if caught_exception is None: - print(f" -> no exceptions correctly raised by config file {config_file}") - - else: - raise RuntimeError( - f"Configuration {config_file} shouldn't have raised an exception, but raised {caught_exception}" - ) - - -print("\n") - -# Invalid Configurations - -# test that they throw errors when generating a python API - -print(" ==== Testing invalid configurations ====") -invalid_configs_path = "test/auto_gen/invalid_configs/" -for config_file in sorted(listdir(invalid_configs_path)): - caught_exception = None - try: - m = Manta(invalid_configs_path + config_file) - - except Exception as e: - caught_exception = e - - if caught_exception is not None: - print( - f" -> exception correctly raised by config file {config_file}: {caught_exception}" - ) - - else: - raise RuntimeError( - f"Configuration {config_file} should have raised an exception, but did not!" - ) diff --git a/test/auto_gen/valid_configs/0_io_core.yaml b/test/auto_gen/valid_configs/0_io_core.yaml deleted file mode 100644 index 867efbe..0000000 --- a/test/auto_gen/valid_configs/0_io_core.yaml +++ /dev/null @@ -1,26 +0,0 @@ ---- -cores: - my_io_core: - type: io - - inputs: - btnu: 1 - btnd: 1 - btnl: 1 - btnr: 1 - btnc: 1 - sw: 16 - - outputs: - led: 16 - led16_b: 1 - led16_g: 1 - led16_r: 1 - led17_b: 1 - led17_g: 1 - led17_r: 1 - -uart: - port: "auto" - baudrate: 115200 - clock_freq: 100000000 \ No newline at end of file diff --git a/test/auto_gen/valid_configs/1_logic_analyzer.yaml b/test/auto_gen/valid_configs/1_logic_analyzer.yaml deleted file mode 100644 index 107efa8..0000000 --- a/test/auto_gen/valid_configs/1_logic_analyzer.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -cores: - my_logic_analyzer: - type: logic_analyzer - sample_depth: 4096 - - probes: - larry: 1 - curly: 1 - moe: 1 - shemp: 4 - - triggers: - - larry && curly && ~moe - -uart: - port: "auto" - baudrate: 115200 - clock_freq: 100000000 \ No newline at end of file diff --git a/test/formal_verification/bridge_rx.sby b/test/formal_verification/bridge_rx.sby deleted file mode 100644 index 93a9ed9..0000000 --- a/test/formal_verification/bridge_rx.sby +++ /dev/null @@ -1,29 +0,0 @@ -[tasks] -basic bmc -nofullskip prove -cover -noverific cover -basic cover : default - -[options] -cover: -mode cover --- -prove: -mode prove --- -bmc: -mode bmc --- - -[engines] -smtbmc boolector - -[script] -nofullskip: read -define NO_FULL_SKIP=1 -noverific: read -noverific -read -formal bridge_rx.v -prep -top bridge_rx - -[files] -src/manta/uart_iface/bridge_rx.v \ No newline at end of file diff --git a/test/functional_sim/block_memory_tb.sv b/test/functional_sim/block_memory_tb.sv deleted file mode 100644 index 818ca3b..0000000 --- a/test/functional_sim/block_memory_tb.sv +++ /dev/null @@ -1,182 +0,0 @@ -`default_nettype none - -`define CP 10 -`define HCP 5 - -`define BRAM_DEPTH 256 -`define BRAM_WIDTH 33 -`define ADDR_WIDTH $clog2(`BRAM_DEPTH) - -task read_reg_bus_side ( - input [15:0] addr, - output [15:0] data - ); - - block_memory_tb.tb_bc_addr = addr; - block_memory_tb.tb_bc_rw = 0; - block_memory_tb.tb_bc_valid = 1; - #`CP - block_memory_tb.tb_bc_rw = 0; - block_memory_tb.tb_bc_valid = 0; - while (!block_memory_tb.bc_tb_valid) #`CP; - data = block_memory_tb.bc_tb_data; - - $display(" -> bus read 0x%h from addr 0x%h", data, addr); -endtask - -task write_reg_bus_side( - input [15:0] addr, - input [15:0] data - ); - - block_memory_tb.tb_bc_addr = addr; - block_memory_tb.tb_bc_data = data; - block_memory_tb.tb_bc_rw = 1; - block_memory_tb.tb_bc_valid = 1; - #`CP - block_memory_tb.tb_bc_rw = 0; - block_memory_tb.tb_bc_valid = 0; - while (!block_memory_tb.bc_tb_valid) #`CP; - - $display(" -> bus wrote 0x%h to addr 0x%h", data, addr); -endtask - -task write_and_verify_bus_side( - input [15:0] addr, - input [15:0] write_data - ); - - reg [15:0] read_data; - - write_reg_bus_side(addr, write_data); - read_reg_bus_side(addr, read_data); - assert(read_data == write_data) else $fatal(0, "data read does not match data written!"); -endtask - -task read_user_side( - input [`ADDR_WIDTH-1:0] addr - ); - - block_memory_tb.bram_user_we = 0; - block_memory_tb.bram_user_addr = addr; - #(2*`CP); - $display("user read 0x%h from addr 0x%h", block_memory_tb.bram_user_dout, addr); -endtask - -task write_user_side( - input [`ADDR_WIDTH-1:0] addr, - input [`BRAM_WIDTH-1:0] data - ); - - block_memory_tb.bram_user_we = 1; - block_memory_tb.bram_user_addr = addr; - block_memory_tb.bram_user_din = data; - #(2*`CP); - $display("user wrote 0x%h to addr 0x%h", data, addr); -endtask - - -module block_memory_tb; - - // boilerplate - logic clk; - integer test_num; - reg [15:0] read_value; - - // tb -> bram_core bus - logic [15:0] tb_bc_addr; - logic [15:0] tb_bc_data; - logic tb_bc_rw; - logic tb_bc_valid; - - // bram_core -> tb bus - logic [15:0] bc_tb_addr; - logic [15:0] bc_tb_data; - logic bc_tb_rw; - logic bc_tb_valid; - - // bram itself - localparam BRAM_DEPTH = `BRAM_DEPTH; - localparam BRAM_WIDTH = `BRAM_WIDTH; - localparam ADDR_WIDTH = $clog2(BRAM_DEPTH); - logic [ADDR_WIDTH-1:0] bram_user_addr = 0; - logic [BRAM_WIDTH-1:0] bram_user_din = 0; - logic [BRAM_WIDTH-1:0] bram_user_dout; - logic bram_user_we = 0; - - block_memory #(.DEPTH(BRAM_DEPTH), .WIDTH(BRAM_WIDTH)) block_mem ( - .clk(clk), - - .addr_i(tb_bc_addr), - .data_i(tb_bc_data), - .rw_i(tb_bc_rw), - .valid_i(tb_bc_valid), - - .addr_o(bc_tb_addr), - .data_o(bc_tb_data), - .rw_o(bc_tb_rw), - .valid_o(bc_tb_valid), - - .user_clk(clk), - .user_addr(bram_user_addr), - .user_din(bram_user_din), - .user_dout(bram_user_dout), - .user_we(bram_user_we)); - - always begin - #`HCP - clk = !clk; - end - - initial begin - $dumpfile("block_memory_tb.vcd"); - $dumpvars(0, block_memory_tb); - - // setup and reset - clk = 0; - test_num = 0; - - tb_bc_addr = 0; - tb_bc_data = 0; - tb_bc_rw = 0; - tb_bc_valid = 0; - - bram_user_addr = 0; - bram_user_din = 0; - bram_user_we = 0; - - #`HCP - - - - #(10*`CP); - - /* ==== Test 1 Begin ==== */ - $display("\n=== test 1: read/write from BRAM, verify ==="); - test_num = 1; - write_and_verify_bus_side(0, 'h6789); - write_and_verify_bus_side(1, 'h2345); - write_and_verify_bus_side(2, 'h0001); - - // now query what's on the the user side at address 0 - read_user_side(0); - - write_and_verify_bus_side(3, 'h1111); - write_and_verify_bus_side(4, 'h1111); - write_and_verify_bus_side(5, 'h0001); - - // now query what's on the the user side at address 0 - read_user_side(1); - - write_user_side(1, 0); - read_user_side(1); - - #(10*`CP); - - /* ==== Test 1 End ==== */ - - $finish(); - end -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/test/functional_sim/bridge_rx_tb.sv b/test/functional_sim/bridge_rx_tb.sv deleted file mode 100644 index 78b4049..0000000 --- a/test/functional_sim/bridge_rx_tb.sv +++ /dev/null @@ -1,185 +0,0 @@ -`default_nettype none -// `timescale 1ns/1ps - -`define CP 10 -`define HCP 5 - -task test_good_read_msg ( - input string message, - input [15:0] addr - ); - - bridge_rx_tb.tb_brx_valid = 1; - for(int i=0; i < $size(message); i++) begin - bridge_rx_tb.tb_brx_data = message [i]; - if(bridge_rx_tb.brx_tb_valid) begin - assert(bridge_rx_tb.brx_tb_addr == addr) else $fatal(0, "wrong addr!"); - assert(bridge_rx_tb.brx_tb_rw == 0) else $fatal(0, "wrong rw!"); - assert(bridge_rx_tb.brx_tb_data == 0) else $fatal(0, "wrong data!"); - end - #`CP; - end - bridge_rx_tb.tb_brx_valid = 0; -endtask - -task test_good_write_msg ( - input string message, - input [15:0] addr, - input [15:0] data - ); - - bridge_rx_tb.tb_brx_valid = 1; - for(int i=0; i < $size(message); i++) begin - bridge_rx_tb.tb_brx_data = message[i]; - if(bridge_rx_tb.brx_tb_valid) begin - assert(bridge_rx_tb.brx_tb_addr == addr) else $fatal(0, "wrong addr!"); - assert(bridge_rx_tb.brx_tb_rw == 1) else $fatal(0, "wrong rw!"); - assert(bridge_rx_tb.brx_tb_data == data) else $fatal(0, "wrong data!"); - end - #`CP; - end - bridge_rx_tb.tb_brx_valid = 0; -endtask - -task test_bad_msg ( - input string message - ); - - bridge_rx_tb.tb_brx_valid = 1; - for(int i=0; i < $size(message); i++) begin - bridge_rx_tb.tb_brx_data = message[i]; - assert(bridge_rx_tb.brx_tb_valid == 0) else $fatal(0, "wrong valid!"); - #`CP; - end - bridge_rx_tb.tb_brx_valid = 0; -endtask - - -module bridge_rx_tb; -// https://www.youtube.com/watch?v=WCOAr-96bGc - -//boilerplate -logic clk; -integer test_num; - -// uart inputs and outputs -logic [7:0] tb_brx_data; -logic tb_brx_valid; - -logic [15:0] brx_tb_addr; -logic [15:0] brx_tb_data; -logic brx_tb_rw; -logic brx_tb_valid; - -bridge_rx bridge_rx_uut( - .clk(clk), - - .data_i(tb_brx_data), - .valid_i(tb_brx_valid), - - .addr_o(brx_tb_addr), - .data_o(brx_tb_data), - .rw_o(brx_tb_rw), - .valid_o(brx_tb_valid)); - -always begin - #`HCP - clk = !clk; -end - -initial begin - $dumpfile("bridge_rx.vcd"); - $dumpvars(0, bridge_rx_tb); - - // setup and reset - clk = 0; - tb_brx_data = 0; - tb_brx_valid = 0; - test_num = 0; - #`CP - #`HCP - - test_num = test_num + 1; - $display("\n=== test %2d: transmit W12345678(CR)(LF) for baseline functionality ===", test_num); - test_good_write_msg("W12345678\r\n", 16'h1234, 16'h5678); - #(10*`CP); - - test_num = test_num + 1; - $display("\n=== test %2d: transmit WDEADBEEF(CR)(LF) for proper state reset ===", test_num); - test_good_write_msg("WDEADBEEF\r\n", 16'hDEAD, 16'hBEEF); - #(10*`CP); - - test_num = test_num + 1; - $display("\n=== test %2d: transmit RBABE(CR)(LF) for baseline functionality ===", test_num); - test_good_read_msg("RBABE\r\n", 16'hBABE); - #(10*`CP); - - test_num = test_num + 1; - $display("\n=== test %2d: transmit R0000(CR) for EOL insensitivity ===", test_num); - test_good_read_msg("R0000\r", 16'hBABE); - #(10*`CP); - - test_num = test_num + 1; - $display("\n=== test %2d: transmit R1234(LF) for EOL insensitivity ===", test_num); - test_good_read_msg("R1234\n", 16'h1234); - #(10*`CP); - - test_num = test_num + 1; - $display("\n=== test %2d: transmit WF00DBEEF(CR) for EOL insensitivity ===", test_num); - test_good_write_msg("WF00DBEEF\r", 16'hF00D, 16'hBEEF); - #(10*`CP); - - test_num = test_num + 1; - $display("\n=== test %2d: transmit WB0BACAFE(LF) for EOL insensitivity ===", test_num); - test_good_write_msg("WB0BACAFE\r", 16'hB0BA, 16'hCAFE); - #(10*`CP); - - test_num = test_num + 1; - $display("\n=== test %2d: transmit R1234(LF)R5678 for back-to-back messages ===", test_num); - test_good_read_msg("R1234\r\n", 16'h1234); - test_good_read_msg("R5678\r\n", 16'h5678); - #(10*`CP); - - $display("\n\nIntentionally bad messages:"); - - test_num = test_num + 1; - $display("\n=== test %2d: transmit RABC(CR)(LF) for message length ===", test_num); - test_bad_msg("RABC\r\n"); - #(10*`CP); - - test_num = test_num + 1; - $display("\n=== test %2d: transmit R12345(CR)(LF) for message length ===", test_num); - test_bad_msg("R12345\r\n"); - #(10*`CP); - - test_num = test_num + 1; - $display("\n=== test %2d: transmit M(CR)(LF) for message length ===", test_num); - test_bad_msg("WABC\r\n"); - #(10*`CP); - - test_num = test_num + 1; - $display("\n=== test %2d: transmit W123456789101112131415161718191201222(CR)(LF) for message length ===", test_num); - test_bad_msg("W123456789101112131415161718191201222\r\n"); - #(10*`CP); - - test_num = test_num + 1; - $display("\n=== test %2d: transmit RABCG(CR)(LF) for invalid characters ===", test_num); - test_bad_msg("RABCG\r\n"); - #(10*`CP); - - test_num = test_num + 1; - $display("\n=== test %2d: transmit WABC[]()##*@(CR)(LF) for invalid characters and message length ===", test_num); - test_bad_msg("WABC[]()##*@\r\n"); - #(10*`CP); - - test_num = test_num + 1; - $display("\n=== test %2d: transmit R(CR)(LF) for message length ===", test_num); - test_bad_msg("R\r\n"); - #(10*`CP); - - $finish(); -end - - -endmodule -`default_nettype wire \ No newline at end of file diff --git a/test/functional_sim/bridge_tx_tb.sv b/test/functional_sim/bridge_tx_tb.sv deleted file mode 100644 index b55e6d2..0000000 --- a/test/functional_sim/bridge_tx_tb.sv +++ /dev/null @@ -1,116 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -`define CP 10 -`define HCP 5 - -module bridge_tx_tb; -// https://www.youtube.com/watch?v=WCOAr-96bGc - -// boilerplate -logic clk; -integer test_num; - -// tb -> bridge_tx signals -logic [15:0] tb_btx_data; -logic tb_btx_valid; - -// uart_tx -> tb signals -logic utx_tb_tx; - -bridge_tx btx ( - .clk(clk), - - .data_i(tb_btx_data), - .rw_i(1'b0), - .valid_i(tb_btx_valid), - - .data_o(btx_utx_data), - .start_o(btx_utx_start), - .done_i(utx_btx_done)); - -reg [7:0] btx_utx_data; -reg btx_utx_start; -reg utx_btx_done; - -uart_tx #(.CLOCKS_PER_BAUD(10)) utx ( - .clk(clk), - - .data_i(btx_utx_data), - .start_i(btx_utx_start), - .done_o(utx_btx_done), - - .tx(utx_tb_tx)); - -always begin - #`HCP - clk = !clk; -end - -initial begin - $dumpfile("bridge_tx.vcd"); - $dumpvars(0, bridge_tx_tb); - - // setup and reset - clk = 0; - test_num = 0; - - tb_btx_valid = 0; - tb_btx_data = 0; - #(10*`CP); - - /* ==== Test 1 Begin ==== */ - $display("\n=== test 1: receive 0x0123 for baseline functionality ==="); - test_num = 1; - tb_btx_data = 16'h0123; - tb_btx_valid = 1; - - #`CP; - tb_btx_valid = 0; - - #(100000*`CP); - /* ==== Test 1 End ==== */ - - /* ==== Test 2 Begin ==== */ - $display("\n=== test 2: receive 0x4567 for baseline functionality ==="); - test_num = 2; - tb_btx_data = 16'h4567; - tb_btx_valid = 1; - - #`CP; - tb_btx_valid = 0; - - #(100000*`CP); - /* ==== Test 2 End ==== */ - - /* ==== Test 3 Begin ==== */ - $display("\n=== test 3: receive 0x89AB for baseline functionality ==="); - test_num = 3; - tb_btx_data = 16'h89AB; - tb_btx_valid = 1; - - #`CP; - tb_btx_valid = 0; - - #(100000*`CP); - /* ==== Test 3 End ==== */ - - /* ==== Test 4 Begin ==== */ - $display("\n=== test 4: receive 0xCDEF for baseline functionality ==="); - test_num = 4; - tb_btx_data = 16'hCDEF; - tb_btx_valid = 1; - - #`CP; - tb_btx_valid = 0; - - #(100000*`CP); - /* ==== Test 4 End ==== */ - - $finish(); -end - - -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/test/functional_sim/ethernet_rx_tb.sv b/test/functional_sim/ethernet_rx_tb.sv deleted file mode 100644 index 89ee8d4..0000000 --- a/test/functional_sim/ethernet_rx_tb.sv +++ /dev/null @@ -1,98 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -`define FPGA_MAC 48'h69_69_5A_06_54_91 -`define HOST_MAC 48'h00_E0_4C_68_1E_0C -`define ETHERTYPE 16'h88_B5 - -module ethernet_rx_tb(); - - // https://www.youtube.com/watch?v=K35qOTQLNpA - logic clk; - - always begin - #5; - clk = !clk; - end - - logic crsdv; - logic [1:0] rxd; - - logic txen; - logic [1:0] txd; - - logic [39:0] mtx_payload; - logic mtx_start; - - mac_tx #( - .SRC_MAC(`HOST_MAC), - .DST_MAC(`FPGA_MAC), - .ETHERTYPE(`ETHERTYPE), - .PAYLOAD_LENGTH_BYTES(5) - ) mtx ( - .clk(clk), - - .payload(mtx_payload), - .start(mtx_start), - - .txen(txen), - .txd(txd)); - - assign rxd = txd; - assign crsdv = txen; - - logic [15:0] erx_addr; - logic [15:0] erx_data; - logic erx_rw; - logic erx_valid; - - ethernet_rx #( - .FPGA_MAC(`FPGA_MAC), - .ETHERTYPE(`ETHERTYPE) - ) erx ( - .clk(clk), - - .crsdv(crsdv), - .rxd(rxd), - - .addr_o(erx_addr), - .data_o(erx_data), - .rw_o(erx_rw), - .valid_o(erx_valid)); - - initial begin - $dumpfile("ethernet_rx_tb.vcd"); - $dumpvars(0, ethernet_rx_tb); - clk = 0; - mtx_payload = 0; - mtx_start = 0; - #50; - - // try to send a read request to the bus: - mtx_payload = 40'h01_0002_0001; - mtx_start = 1; - #10; - mtx_start = 0; - #10000; - - - - - // for (int i=0; i<32; i=i+1) begin - // mtx_payload = i; - // mtx_start = 0; - // #10; - // mtx_start = 1; - // #10; - // mtx_start = 0; - // while(!mrx_valid) #10; - - // #1000; - - // assert(mrx_payload == i) else $fatal(0, "data mismatch!"); - // end - $finish(); - end - -endmodule -`default_nettype wire \ No newline at end of file diff --git a/test/functional_sim/ethernet_tx_tb.sv b/test/functional_sim/ethernet_tx_tb.sv deleted file mode 100644 index 0146753..0000000 --- a/test/functional_sim/ethernet_tx_tb.sv +++ /dev/null @@ -1,121 +0,0 @@ -`default_nettype none -//`timescale 1ns/1ps - -`define FPGA_MAC 48'h69_69_5A_06_54_91 -`define HOST_MAC 48'h00_E0_4C_68_1E_0C -`define ETHERTYPE 16'h88_B5 - -task send_on_etx_receive_on_mrx ( - input [15:0] data - ); - - ethernet_tx_tb.etx_data = data; - ethernet_tx_tb.etx_rw = 0; - ethernet_tx_tb.etx_valid = 0; - #10; - ethernet_tx_tb.etx_valid = 1; - #10; - ethernet_tx_tb.etx_valid = 0; - - while(!ethernet_tx_tb.mrx_valid) #10; - - $display(ethernet_tx_tb.mrx_payload); -endtask - -module ethernet_tx_tb(); - - // https://www.youtube.com/watch?v=K35qOTQLNpA - logic clk; - - always begin - #5; - clk = !clk; - end - - logic txen; - logic [1:0] txd; - - // ethernet tx - reg [15:0] etx_data; - reg etx_rw; - reg etx_valid; - - ethernet_tx #( - .FPGA_MAC(`FPGA_MAC), - .HOST_MAC(`HOST_MAC), - .ETHERTYPE(`ETHERTYPE) - ) etx ( - .clk(clk), - - .data_i(etx_data), - .rw_i(etx_rw), - .valid_i(etx_valid), - - .txen(txen), - .txd(txd)); - - // mac_rx, for decoding - logic crsdv; - logic [1:0] rxd; - - reg [55:0] mrx_payload; - reg mrx_valid; - - mac_rx #( - // this is the host mac since we're using mac_rx to impersonate - // the host computer, to which packets are currently addressed. - - .FPGA_MAC(`HOST_MAC), - .ETHERTYPE(`ETHERTYPE) - ) mrx ( - .clk(clk), - - .crsdv(crsdv), - .rxd(rxd), - - .payload(mrx_payload), - .valid(mrx_valid)); - - logic [15:0] where_ethertype_should_be; - logic [7:0] where_rw_should_be; - logic [15:0] where_addr_should_be; - logic [15:0] where_data_should_be; - assign {where_ethertype_should_be, where_rw_should_be, where_addr_should_be, where_data_should_be} = mrx_payload; - - assign rxd = txd; - assign crsdv = txen; - - initial begin - $dumpfile("ethernet_tx_tb.vcd"); - $dumpvars(0, ethernet_tx_tb); - clk = 0; - etx_data = 16'h6970; - etx_rw = 0; - etx_valid = 0; - #50; - - send_on_etx_receive_on_mrx(16'h6970); - - #10000; - - - - - // for (int i=0; i<32; i=i+1) begin - // mtx_payload = i; - // mtx_start = 0; - // #10; - // mtx_start = 1; - // #10; - // mtx_start = 0; - // while(!mrx_valid) #10; - - // #1000; - - // assert(mrx_payload == i) else $fatal(0, "data mismatch!"); - // end - $finish(); - end - -endmodule -`default_nettype wire \ No newline at end of file diff --git a/test/functional_sim/io_core_tb/io_core.v b/test/functional_sim/io_core_tb/io_core.v deleted file mode 100644 index 8f8daa7..0000000 --- a/test/functional_sim/io_core_tb/io_core.v +++ /dev/null @@ -1,118 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -module io_core( - input wire bus_clk, - input wire user_clk, - - // inputs - input wire probe0, - input wire [1:0] probe1, - input wire [7:0] probe2, - input wire [19:0] probe3, - - // outputs - output reg probe4, - output reg [1:0] probe5, - output reg [7:0] probe6, - output reg [19:0] probe7, - - // input port - input wire [15:0] addr_i, - input wire [15:0] data_i, - input wire rw_i, - input wire valid_i, - - // output port - output reg [15:0] addr_o, - output reg [15:0] data_o, - output reg rw_o, - output reg valid_o - ); - - parameter BASE_ADDR = 0; - - reg strobe = 0; - - // configure buffers - // inputs - reg probe0_buf = 0; - reg [1:0] probe1_buf = 0; - reg [7:0] probe2_buf = 0; - reg [19:0] probe3_buf = 0; - - // outputs - reg probe4_buf = 1; // PROBE4_INITIAL_VALUE; - reg [1:0] probe5_buf = 3; // PROBE5_INITIAL_VALUE; - reg [7:0] probe6_buf = 6; // PROBE6_INITIAL_VALUE; - reg [19:0] probe7_buf = 7; // PROBE7_INITIAL_VALUE; - - initial begin - probe4 = 1; // PROBE4_INITIAL_VALUE; - probe5 = 3; // PROBE5_INITIAL_VALUE; - probe6 = 6; // PROBE6_INITIAL_VALUE; - probe7 = 7; // PROBE7_INITIAL_VALUE; - end - - // synchronize buffers and probes on strobe - always @(posedge user_clk) begin - if(strobe) begin - // update input buffers from input probes - probe0_buf <= probe0; - probe1_buf <= probe1; - probe2_buf <= probe2; - probe3_buf <= probe3; - - // update output buffers from output probes - probe4 <= probe4_buf; - probe5 <= probe5_buf; - probe6 <= probe6_buf; - probe7 <= probe7_buf; - end - end - - - // handle bus operations - always @(posedge bus_clk) begin - addr_o <= addr_i; - data_o <= data_i; - rw_o <= rw_i; - valid_o <= valid_i; - - // check if address is valid - if( (valid_i) && (addr_i >= BASE_ADDR) && (addr_i <= BASE_ADDR + 10)) begin - - if(!rw_i) begin // reads - case (addr_i) - BASE_ADDR + 0: data_o <= strobe; - - BASE_ADDR + 1: data_o <= probe0_buf; // width 1 - BASE_ADDR + 2: data_o <= probe1_buf; // width 2 - BASE_ADDR + 3: data_o <= probe2_buf; // width 8 - BASE_ADDR + 4: data_o <= probe3_buf[15:0]; // width 20 - BASE_ADDR + 5: data_o <= probe3_buf[19:16]; - - BASE_ADDR + 6: data_o <= probe4_buf; // width 1 - BASE_ADDR + 7: data_o <= probe5_buf; // width 2 - BASE_ADDR + 8: data_o <= probe6_buf; // width 8 - BASE_ADDR + 9: data_o <= probe7_buf[15:0]; // width 20 - BASE_ADDR + 10: data_o <= probe7_buf[19:16]; - endcase - end - - else begin // writes - case (addr_i) - BASE_ADDR + 0: strobe <= data_i[0]; - - BASE_ADDR + 6: probe4_buf <= data_i[0]; - BASE_ADDR + 7: probe5_buf <= data_i[1:0]; - BASE_ADDR + 8: probe6_buf <= data_i[7:0]; - BASE_ADDR + 9: probe7_buf[15:0] <= data_i; - BASE_ADDR + 10: probe7_buf[19:16] <= data_i[3:0]; - endcase - end - end - end -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/test/functional_sim/io_core_tb/io_core_tb.sv b/test/functional_sim/io_core_tb/io_core_tb.sv deleted file mode 100644 index 3a1caef..0000000 --- a/test/functional_sim/io_core_tb/io_core_tb.sv +++ /dev/null @@ -1,277 +0,0 @@ -`default_nettype none - -`define CP 10 -`define HCP 5 - -task read_reg ( - input [15:0] addr, - output [15:0] data, - input string desc - ); - - io_core_tb.tb_io_addr = addr; - io_core_tb.tb_io_rw = 0; - io_core_tb.tb_io_valid = 1; - #`CP - io_core_tb.tb_io_valid = 0; - while (!io_core_tb.io_tb_valid) #`CP; - data = io_core_tb.io_tb_data; - - $display(" -> read 0x%h from addr 0x%h (%s)", data, addr, desc); -endtask - -task write_reg( - input [15:0] addr, - input [15:0] data, - input string desc - ); - - io_core_tb.tb_io_addr = addr; - io_core_tb.tb_io_data = data; - io_core_tb.tb_io_rw = 1; - io_core_tb.tb_io_valid = 1; - #`CP - io_core_tb.tb_io_valid = 0; - while (!io_core_tb.io_tb_valid) #`CP; - - $display(" -> wrote 0x%h to addr 0x%h (%s)", data, addr, desc); -endtask - -task write_and_verify( - input [15:0] addr, - input [15:0] write_data, - input string desc - ); - - reg [15:0] read_data; - - write_reg(addr, write_data, desc); - read_reg(addr, read_data, desc); - assert(read_data == write_data) else $fatal(0, "data read does not match data written!"); -endtask - -// task read_all_reg(); -// string desc; -// for(int i = 0; i < (io_core_tb.la.block_mem.MAX_ADDR); i++) begin - -// if(i == io_core_tb.la.fsm_registers.BASE_ADDR) desc = "FSM"; -// if(i == io_core_tb.la.trig_blk.BASE_ADDR) desc = "TRIG BLK"; -// if(i == io_core_tb.la.block_mem.BASE_ADDR) desc = "SAMPLE MEM"; - -// read_reg(i, io_core_tb.read_value, desc); -// end -// endtask - -module io_core_tb; - - // boilerplate - logic clk; - integer test_num; - - // inputs - logic probe0; - logic [1:0] probe1; - logic [7:0] probe2; - logic [19:0] probe3; - - // outputs - logic probe4; - logic [1:0] probe5; - logic [7:0] probe6; - logic [19:0] probe7; - - // tb -> io bus - logic [15:0] tb_io_addr; - logic [15:0] tb_io_data; - logic tb_io_rw; - logic tb_io_valid; - - // la -> io bus - logic [15:0] io_tb_addr; - logic [15:0] io_tb_data; - logic io_tb_rw; - logic io_tb_valid; - - - io_core #(.BASE_ADDR(0)) io( - .bus_clk(clk), - .user_clk(clk), - - // inputs - .probe0(probe0), - .probe1(probe1), - .probe2(probe2), - .probe3(probe3), - - // outputs - .probe4(probe4), - .probe5(probe5), - .probe6(probe6), - .probe7(probe7), - - // input port - .addr_i(tb_io_addr), - .data_i(tb_io_data), - .rw_i(tb_io_rw), - .valid_i(tb_io_valid), - - // output port - .addr_o(io_tb_addr), - .data_o(io_tb_data), - .rw_o(io_tb_rw), - .valid_o(io_tb_valid)); - - always begin - #`HCP - clk = !clk; - end - - logic [15:0] read_data; - - initial begin - $dumpfile("io_core_tb.vcd"); - $dumpvars(0, io_core_tb); - - // setup and reset - clk = 0; - test_num = 0; - - tb_io_addr = 0; - tb_io_data = 0; - tb_io_rw = 0; - tb_io_valid = 0; - - probe0 = 0; - probe1 = 1; - probe2 = 2; - probe3 = 3; - - // #`HCP - #(10*`CP); - - /* ==== Test 1 Begin ==== */ - $display("\n=== test 1: read initial register states ==="); - test_num = 1; - read_reg(0, read_data, "strobe"); - read_reg(1, read_data, "probe0"); - read_reg(2, read_data, "probe1"); - read_reg(3, read_data, "probe2"); - read_reg(4, read_data, "probe3[15:0]"); - read_reg(5, read_data, "probe3[19:16]"); - - read_reg(6, read_data, "probe4"); - read_reg(7, read_data, "probe5"); - read_reg(8, read_data, "probe6"); - read_reg(9, read_data, "probe7[15:0]"); - read_reg(10, read_data, "probe7[19:16]"); - #(10*`CP); - /* ==== Test 1 End ==== */ - - /* ==== Test 2 Begin ==== */ - $display("\n=== test 2: assert input buffers initialized correctly ==="); - test_num = 2; - read_reg(0, read_data, "strobe"); - assert(read_data == 0) else $fatal(0, "strobe does not initialize to zero!"); - assert(io.strobe == 0) else $fatal(0, "strobe does not initialize to zero!"); - - read_reg(1, read_data, "probe0"); - assert(read_data == 0) else $fatal(0, "probe0_buf does not initialize to zero!"); - assert(io.probe0_buf == 0) else $fatal(0, "probe0_buf does not initialize to zero!"); - - read_reg(2, read_data, "probe1"); - assert(read_data == 0) else $fatal(0, "probe1_buf does not initialize to zero!"); - assert(io.probe1_buf == 0) else $fatal(0, "probe1_buf does not initialize to zero!"); - - read_reg(3, read_data, "probe2"); - assert(read_data == 0) else $fatal(0, "probe2_buf does not initialize to zero!"); - assert(io.probe2_buf == 0) else $fatal(0, "probe2_buf does not initialize to zero!"); - - read_reg(4, read_data, "probe3[15:0]"); - assert(read_data == 0) else $fatal(0, "probe3_buf does not initialize to zero!"); - read_reg(5, read_data, "probe3[19:16]"); - assert(read_data == 0) else $fatal(0, "probe3_buf does not initialize to zero!"); - assert(io.probe3_buf == 0) else $fatal(0, "probe3_buf does not initialize to zero!"); - - #(10*`CP); - /* ==== Test 2 End ==== */ - - - /* ==== Test 3 Begin ==== */ - $display("\n=== test 3: assert outputs and output buffers initialized correctly ==="); - test_num = 3; - read_reg(6, read_data, "probe4"); - assert(read_data == 1) else $fatal(0, "probe4 does not initialize correctly!"); - assert(io.probe4_buf == 1) else $fatal(0, "probe4_buf does not initialize correctly!"); - assert(io.probe4 == 1) else $fatal(0, "probe4 does not initialize correctly!"); - - read_reg(7, read_data, "probe5"); - assert(read_data == 3) else $fatal(0, "probe5 does not initialize correctly!"); - assert(io.probe5_buf == 3) else $fatal(0, "probe5_buf does not initialize correctly!"); - assert(io.probe5 == 3) else $fatal(0, "probe5 does not initialize correctly!"); - - read_reg(8, read_data, "probe6"); - assert(read_data == 6) else $fatal(0, "probe6 does not initialize correctly!"); - assert(io.probe6_buf == 6) else $fatal(0, "probe6_buf does not initialize correctly!"); - assert(io.probe6 == 6) else $fatal(0, "probe6 does not initialize correctly!"); - - read_reg(9, read_data, "probe7[15:0]"); - assert(read_data == 7) else $fatal(0, "probe7 does not initialize correctly!"); - read_reg(10, read_data, "probe7[19:16]"); - assert(read_data == 0) else $fatal(0, "probe7 does not initialize correctly!"); - assert(io.probe7_buf == 7) else $fatal(0, "probe7_buf does not initialize correctly!"); - assert(io.probe7 == 7) else $fatal(0, "probe7 does not initialize correctly!"); - - - #(10*`CP); - /* ==== Test 3 End ==== */ - - /* ==== Test 4 Begin ==== */ - $display("\n=== test 4: write new output value to each output probe==="); - test_num = 4; - write_reg(6, 0, "probe4"); - assert(io.probe4_buf == 0) else $fatal(0, "probe4_buf does not update correctly!"); - assert(io.probe4 != 0) else $fatal(0, "probe4 updated without strobing!"); - - write_reg(7, 0, "probe5"); - assert(io.probe5_buf == 0) else $fatal(0, "probe5_buf does not update correctly!"); - assert(io.probe5 != 0) else $fatal(0, "probe5 updated without strobing!"); - - write_reg(8, 0, "probe6"); - assert(io.probe6_buf == 0) else $fatal(0, "probe6_buf does not update correctly!"); - assert(io.probe6 != 0) else $fatal(0, "probe6 updated without strobing!"); - - write_reg(9, 0, "probe7[15:0]"); - write_reg(10, 0, "probe7[19:16]"); - assert(io.probe7_buf == 0) else $fatal(0, "probe7_buf does not update correctly!"); - assert(io.probe7 != 0) else $fatal(0, "probe7 updated without strobing!"); - #(10*`CP); - /* ==== Test 4 End ==== */ - - /* ==== Test 5 Begin ==== */ - $display("\n=== test 5: strobe core, check that inputs and outputs updated ==="); - test_num = 5; - - write_reg(0, 1, "strobe"); - write_reg(0, 0, "strobe"); - - assert(io.probe4 == 0) else $fatal(0, "probe4 did not update correctly!"); - assert(io.probe5 == 0) else $fatal(0, "probe5 did not update correctly!"); - assert(io.probe6 == 0) else $fatal(0, "probe6 did not update correctly!"); - assert(io.probe7 == 0) else $fatal(0, "probe7 did not update correctly!"); - - assert(io.probe0_buf == 0) else $fatal(0, "probe0_buf did not update correctly!"); - assert(io.probe1_buf == 1) else $fatal(0, "probe1_buf did not update correctly!"); - assert(io.probe2_buf == 2) else $fatal(0, "probe2_buf did not update correctly!"); - assert(io.probe3_buf == 3) else $fatal(0, "probe3_buf did not update correctly!"); - assert(io.probe4_buf == 0) else $fatal(0, "probe4_buf did not update correctly!"); - assert(io.probe5_buf == 0) else $fatal(0, "probe5_buf did not update correctly!"); - assert(io.probe6_buf == 0) else $fatal(0, "probe6_buf did not update correctly!"); - assert(io.probe7_buf == 0) else $fatal(0, "probe7_buf did not update correctly!"); - /* ==== Test 5 End ==== */ - - - $finish(); - end -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/test/functional_sim/logic_analyzer_tb/logic_analyzer_tb.sv b/test/functional_sim/logic_analyzer_tb/logic_analyzer_tb.sv deleted file mode 100644 index 36288de..0000000 --- a/test/functional_sim/logic_analyzer_tb/logic_analyzer_tb.sv +++ /dev/null @@ -1,257 +0,0 @@ -`default_nettype none - -`define CP 10 -`define HCP 5 - -task read_reg ( - input [15:0] addr, - output [15:0] data, - input string desc - ); - - logic_analyzer_tb.tb_la_addr = addr; - logic_analyzer_tb.tb_la_rw = 0; - logic_analyzer_tb.tb_la_valid = 1; - #`CP - logic_analyzer_tb.tb_la_valid = 0; - while (!logic_analyzer_tb.la_tb_valid) #`CP; - data = logic_analyzer_tb.la_tb_data; - - $display(" -> read 0x%h from addr 0x%h (%s)", data, addr, desc); -endtask - -task write_reg( - input [15:0] addr, - input [15:0] data, - input string desc - ); - - logic_analyzer_tb.tb_la_addr = addr; - logic_analyzer_tb.tb_la_data = data; - logic_analyzer_tb.tb_la_rw = 1; - logic_analyzer_tb.tb_la_valid = 1; - #`CP - logic_analyzer_tb.tb_la_valid = 0; - while (!logic_analyzer_tb.la_tb_valid) #`CP; - - $display(" -> wrote 0x%h to addr 0x%h (%s)", data, addr, desc); -endtask - -task write_and_verify( - input [15:0] addr, - input [15:0] write_data, - input string desc - ); - - reg [15:0] read_data; - - write_reg(addr, write_data, desc); - read_reg(addr, read_data, desc); - assert(read_data == write_data) else $fatal(0, "data read does not match data written!"); -endtask - -task read_all_reg(); - string desc; - for(int i = 0; i < (logic_analyzer_tb.la.block_mem.MAX_ADDR); i++) begin - - if(i == logic_analyzer_tb.la.fsm_registers.BASE_ADDR) desc = "FSM"; - if(i == logic_analyzer_tb.la.trig_blk.BASE_ADDR) desc = "TRIG BLK"; - if(i == logic_analyzer_tb.la.block_mem.BASE_ADDR) desc = "SAMPLE MEM"; - - read_reg(i, logic_analyzer_tb.read_value, desc); - end -endtask - -module logic_analyzer_tb; - - // boilerplate - logic clk; - integer test_num; - - // signal generator - logic larry; - logic curly; - logic moe; - logic [3:0] shemp; - - // tb -> la bus - logic [15:0] tb_la_addr; - logic [15:0] tb_la_data; - logic tb_la_rw; - logic tb_la_valid; - - // la -> tb bus - logic [15:0] la_tb_addr; - logic [15:0] la_tb_data; - logic la_tb_rw; - logic la_tb_valid; - - - logic_analyzer la( - .clk(clk), - - // probes - .larry(larry), - .curly(curly), - .moe(moe), - .shemp(shemp), - - // input port - .addr_i(tb_la_addr), - .data_i(tb_la_data), - .rw_i(tb_la_rw), - .valid_i(tb_la_valid), - - // output port - .addr_o(la_tb_addr), - .data_o(la_tb_data), - .rw_o(la_tb_rw), - .valid_o(la_tb_valid)); - - always begin - #`HCP - clk = !clk; - end - - reg [15:0] read_value; - - initial begin - $dumpfile("logic_analyzer_tb.vcd"); - $dumpvars(0, logic_analyzer_tb); - - // setup and reset - clk = 0; - test_num = 0; - - tb_la_addr = 0; - tb_la_data = 0; - tb_la_rw = 0; - tb_la_valid = 0; - - larry = 0; - curly = 0; - moe = 0; - shemp = 0; - #`HCP - #(10*`CP); - - - // /* ==== Test 2 Begin ==== */ - // $display("\n=== test 2: read/write to trigger block registers, verify ==="); - // test_num = 2; - - // // larry - // write_and_verify(3, 0, "larry_op"); - // write_and_verify(3, 2, "larry_op"); - // write_and_verify(3, 0, "larry_op"); - - // write_and_verify(4, 0, "larry_arg"); - // write_and_verify(4, 1, "larry_arg"); - // write_and_verify(4, 0, "larry_arg"); - - // // curly - // write_and_verify(5, 0, "curly_op"); - // write_and_verify(5, 3, "curly_op"); - // write_and_verify(5, 0, "curly_op"); - - // write_and_verify(6, 0, "curly_arg"); - // write_and_verify(6, 1, "curly_arg"); - // write_and_verify(6, 0, "curly_arg"); - - // // moe - // write_and_verify(7, 0, "moe_op"); - // write_and_verify(7, 5, "moe_op"); - // write_and_verify(7, 0, "moe_op"); - - // write_and_verify(8, 0, "moe_arg"); - // write_and_verify(8, 1, "moe_arg"); - // write_and_verify(8, 0, "moe_arg"); - - // // shemp - // write_and_verify(9, 0, "shemp_op"); - // write_and_verify(9, 7, "shemp_op"); - // write_and_verify(9, 0, "shemp_op"); - - // write_and_verify(10, 0, "shemp_arg"); - // write_and_verify(10, 7, "shemp_arg"); - // write_and_verify(10, 0, "shemp_arg"); - - // #(10*`CP); - - // /* ==== Test 2 End ==== */ - - - /* ==== Test 4 Begin ==== */ - $display("\n=== test 4: verify FSM does move out of IDLE when running ==="); - test_num = 4; - - $display(" -> setting up trigger (larry == 1)"); - write_reg(la.trig_blk.BASE_ADDR + 0, 8, "larry_op"); - write_reg(la.trig_blk.BASE_ADDR + 1, 1, "larry_arg"); - - $display(" -> requesting start"); - write_reg(3, 1, "request_start"); - write_reg(3, 0, "request_start"); - #`CP - - $display(" -> set larry = 1"); - larry = 1; - - // read - $display(" -> la core is in state 0x%h", la.fsm_registers.state); - $display(" -> wait a clock cycle"); - #`CP - $display(" -> la core is in state 0x%h", la.fsm_registers.state); - - // run until the FILLED state is reached - $display(" -> wait until FILLED state is reached"); - while (la.fsm_registers.state != la.la_controller.CAPTURED) begin - {larry, curly, moe, shemp} = {larry, curly, moe, shemp} + 1; - #`CP; - end - - $display(" -> read from sample memory:"); - read_all_reg(); - - #(200*`CP); - /* ==== Test 4 End ==== */ - - // /* ==== Test 5 Begin ==== */ - // $display("\n=== test 5: change trigger to fire on shemp > 3, and verify ==="); - // test_num = 5; - - // write_and_verify(9, 6, "shemp_op"); // set operation to GT - // write_and_verify(10, 3, "shemp_arg"); // set argument to 3 - - // assert( (la.fsm_registers.state == la.la_controller.IDLE) || (la.fsm_registers.state == la.la_controller.CAPTURED) ) - // else $fatal(0, "core is running when it shouldn't be!"); - - // larry = 0; - // curly = 0; - // moe = 0; - // shemp = 0; - - // // start the core - // // TODO: start the core - - // shemp = 4; - // $display(" -> set shemp = 4"); - - // // run until the FILLED state is reached - // $display(" -> wait until FILLED state is reached"); - // while (la.fsm_registers.state != la.la_controller.CAPTURED) begin - // {larry, curly, moe, shemp} = {larry, curly, moe, shemp} + 2; - // #`CP; - // end - - // $display(" -> read from sample memory:"); - // read_all_reg(); - - // #(10*`CP); - // /* ==== Test 5 End ==== */ - - $finish(); - end -endmodule - -`default_nettype wire \ No newline at end of file diff --git a/test/functional_sim/logic_analyzer_tb/manta.yaml b/test/functional_sim/logic_analyzer_tb/manta.yaml deleted file mode 100644 index cbd04c1..0000000 --- a/test/functional_sim/logic_analyzer_tb/manta.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -cores: - logic_analyzer: - type: logic_analyzer - sample_depth: 128 - - probes: - larry: 1 - curly: 1 - moe: 1 - shemp: 4 - - triggers: - - larry && curly && ~moe - -uart: - port: "auto" - baudrate: 115200 - clock_freq: 100000000 \ No newline at end of file diff --git a/test/functional_sim/mac_tb.sv b/test/functional_sim/mac_tb.sv deleted file mode 100644 index c812fc2..0000000 --- a/test/functional_sim/mac_tb.sv +++ /dev/null @@ -1,86 +0,0 @@ -`default_nettype none -`timescale 1ns/1ps - -`define FPGA_MAC 48'h69_69_5A_06_54_91 -`define HOST_MAC 48'h00_E0_4C_68_1E_0C -`define ETHERTYPE 16'h88_B5 - - -module mac_tb(); - logic clk; - - always begin - #5; - clk = !clk; - end - - logic crsdv; - logic [1:0] rxd; - - logic txen; - logic [1:0] txd; - - // this testbench makes sure that our rx pipeline is good, - // so we'll have mtx simulate the host machine and blast - // 5 bytes (plus padding) onto our fake RMII - logic [39:0] mtx_payload; - logic mtx_start; - - logic [39:0] mrx_payload; - logic mrx_valid; - - mac_tx #( - .SRC_MAC(`HOST_MAC), - .DST_MAC(`FPGA_MAC), - .ETHERTYPE(`ETHERTYPE), - .PAYLOAD_LENGTH_BYTES(5) - ) mtx ( - .clk(clk), - - .payload(mtx_payload), - .start(mtx_start), - - .txen(txen), - .txd(txd)); - - assign rxd = txd; - assign crsdv = txen; - - mac_rx #( - .FPGA_MAC(`FPGA_MAC), - .ETHERTYPE(`ETHERTYPE) - ) mrx ( - .clk(clk), - - .crsdv(crsdv), - .rxd(rxd), - - .payload(mrx_payload), - .valid(mrx_valid)); - - initial begin - $dumpfile("mac_tb.vcd"); - $dumpvars(0, mac_tb); - clk = 0; - mtx_payload = 0; - mtx_start = 0; - #10; - - for (int i=0; i<32; i=i+1) begin - mtx_payload = i; - mtx_start = 0; - #10; - mtx_start = 1; - #10; - mtx_start = 0; - while(!mrx_valid) #10; - - #1000; - - assert(mrx_payload == i) else $fatal(0, "data mismatch!"); - end - $finish(); - end - -endmodule -`default_nettype wire \ No newline at end of file diff --git a/test/functional_sim/uart_rx_tb.sv b/test/functional_sim/uart_rx_tb.sv deleted file mode 100644 index 9993eb3..0000000 --- a/test/functional_sim/uart_rx_tb.sv +++ /dev/null @@ -1,94 +0,0 @@ -`default_nettype none - -`define CP 10 -`define HCP 5 - -task automatic test_receive ( - input [7:0] data, - input integer CLOCKS_PER_BAUD - ); - - // send a byte to uart_rx, and check that it receives properly - - integer data_bit = 0; - logic valid_has_been_asserted = 0; - - for(int i=0; i < (10*CLOCKS_PER_BAUD); i++) begin - - // clock out data bits on each baud period - data_bit = i / CLOCKS_PER_BAUD; - if (data_bit == 0) uart_rx_tb.tb_urx_rx = 0; - else if ((data_bit > 0) && (data_bit < 9)) uart_rx_tb.tb_urx_rx = data[data_bit-1]; - else uart_rx_tb.tb_urx_rx = 1; - - - // every cycle, run checks on uart_rx: - - // make sure valid isn't asserted before end of byte - if (data_bit < 9) begin - assert(uart_rx_tb.urx_tb_valid == 0) else $fatal(0, "valid asserted before end of byte!"); - end - - // make sure valid is only asserted once - if (valid_has_been_asserted) begin - assert(uart_rx_tb.urx_tb_valid == 0) else $fatal(0, "valid asserted more than once!"); - end - - // make sure byte is presented once last bit has been clocked out - if (uart_rx_tb.urx_tb_valid) begin - assert(data_bit == 9) else $fatal(0, "byte presented before it is complete"); - assert(uart_rx_tb.urx_tb_data == data) else $fatal(0, "wrong data!"); - valid_has_been_asserted = 1; - end - - #`CP; - end - - // make sure valid was asserted at some point - assert (valid_has_been_asserted) else $fatal(0, "valid not asserted!"); -endtask - -module uart_rx_tb(); - logic clk; - integer test_num; - - logic tb_urx_rx; - logic [7:0] urx_tb_data; - logic urx_tb_valid; - uart_rx #(.CLOCKS_PER_BAUD(10)) urx ( - .clk(clk), - .rx(tb_urx_rx), - .data_o(urx_tb_data), - .valid_o(urx_tb_valid)); - - always begin - #`HCP - clk = !clk; - end - - initial begin - $dumpfile("uart_rx_tb.vcd"); - $dumpvars(0, uart_rx_tb); - clk = 0; - test_num = 0; - tb_urx_rx = 1; - #`HCP; - - // test all possible bytes - test_num = test_num + 1; - for(int i=0; i < 256; i++) begin - test_receive(i, 10); - #(100*`CP); - end - - // test all possible bytes (no delay between them) - test_num = test_num + 1; - for(int i=0; i < 256; i++) begin - test_receive(i, 10); - end - - $finish(); - end -endmodule - -`default_nettype wire diff --git a/test/functional_sim/uart_tx_tb.sv b/test/functional_sim/uart_tx_tb.sv deleted file mode 100644 index 308069e..0000000 --- a/test/functional_sim/uart_tx_tb.sv +++ /dev/null @@ -1,99 +0,0 @@ -`default_nettype none - -`define CP 10 -`define HCP 5 - -task automatic transmit_byte ( - input [7:0] data, - input integer CLOCKS_PER_BAUD - ); - - // send a byte from uart_tx, and check that it transmits properly - - integer data_bit = 0; - for(int i=0; i < (10*CLOCKS_PER_BAUD)-1; i++) begin - - // check that data bit is correct on every baud period - data_bit = i / CLOCKS_PER_BAUD; - if (data_bit == 0) begin - assert(uart_tx_tb.utx_tb_tx == 0) else $fatal(0, "wrong start bit!"); - end - - else if ((data_bit > 0) && (data_bit < 9)) begin - assert(uart_tx_tb.utx_tb_tx == data[data_bit-1]) else $fatal(0, "wrong data bit!"); - end - - else begin - assert(uart_tx_tb.utx_tb_tx == 1) else $fatal(0, "wrong stop bit!"); - end - - - // check that done is not asserted during transmisison - assert(!uart_tx_tb.utx_tb_done) else $fatal(0, "wrong done!"); - #`CP; - end - - // assert that done is asserted at end of transmission - assert(uart_tx_tb.utx_tb_done) else $fatal(0, "wrong done!"); -endtask - -module uart_tx_tb(); - logic clk; - integer test_num; - - logic [7:0] tb_utx_data; - logic tb_utx_start; - logic utx_tb_done; - logic utx_tb_tx; - - uart_tx #(.CLOCKS_PER_BAUD(10)) utx ( - .clk(clk), - - .data_i(tb_utx_data), - .start_i(tb_utx_start), - .done_o(utx_tb_done), - - .tx(utx_tb_tx)); - - always begin - #`HCP - clk = !clk; - end - - initial begin - $dumpfile("uart_tx_tb.vcd"); - $dumpvars(0, uart_tx_tb); - clk = 0; - test_num = 0; - - tb_utx_data = 0; - tb_utx_start = 0; - #`HCP; - - // test all possible bytes - test_num = test_num + 1; - for(int i=0; i < 256; i++) begin - tb_utx_start = 1; - tb_utx_data = i; - #`CP; - tb_utx_start = 0; - tb_utx_data = 0; - transmit_byte(i, 10); - #(100*`CP); - end - - // test all possible bytes (no delay between them) - test_num = test_num + 1; - for(int i=0; i < 256; i++) begin - tb_utx_start = 1; - tb_utx_data = i; - #`CP; - tb_utx_data = 0; - transmit_byte(i, 10); - end - - $finish(); - end -endmodule - -`default_nettype wire diff --git a/test/test_bridge_rx_sim.py b/test/test_bridge_rx_sim.py new file mode 100644 index 0000000..89c3d4d --- /dev/null +++ b/test/test_bridge_rx_sim.py @@ -0,0 +1,120 @@ +from amaranth.sim import Simulator +from manta.uart import RecieveBridge +from manta.utils import * + + +bridge_rx = RecieveBridge() + + +def verify_read_decoding(bytes, addr): + """ + Send a series of bytes to the receive bridge, and verify that the bridge places + a read request with the appropriate address on the internal bus. + """ + valid_asserted = False + yield bridge_rx.valid_i.eq(1) + + for i, byte in enumerate(bytes): + yield bridge_rx.data_i.eq(byte) + + if (yield bridge_rx.valid_o) and (i > 0): + valid_asserted = True + if (yield bridge_rx.addr_o) != addr: + raise ValueError("wrong addr!") + + if (yield bridge_rx.rw_o) != 0: + raise ValueError("wrong rw!") + + if (yield bridge_rx.data_o) != 0: + raise ValueError("wrong data!") + + yield + + yield bridge_rx.valid_i.eq(0) + yield bridge_rx.data_i.eq(0) + + if not valid_asserted and not (yield bridge_rx.valid_o): + raise ValueError("Bridge failed to output valid message.") + + +def verify_write_decoding(bytes, addr, data): + """ + Send a series of bytes to the receive bridge, and verify that the bridge places + a write request with the appropriate address and data on the internal bus. + """ + valid_asserted = False + yield bridge_rx.valid_i.eq(1) + + for i, byte in enumerate(bytes): + yield bridge_rx.data_i.eq(byte) + + if (yield bridge_rx.valid_o) and (i > 0): + valid_asserted = True + if (yield bridge_rx.addr_o) != addr: + raise ValueError("wrong addr!") + + if (yield bridge_rx.rw_o) != 1: + raise ValueError("wrong rw!") + + if (yield bridge_rx.data_o) != data: + raise ValueError("wrong data!") + + yield + + yield bridge_rx.valid_i.eq(0) + yield bridge_rx.data_i.eq(0) + + if not valid_asserted and not (yield bridge_rx.valid_o): + raise ValueError("Bridge failed to output valid message.") + + +def verify_bad_bytes(bytes): + """ + Send a series of bytes to the receive bridge, and verify that the bridge does not + place any transaction on the internal bus. + """ + yield bridge_rx.valid_i.eq(1) + + for byte in bytes: + yield bridge_rx.data_i.eq(byte) + + if (yield bridge_rx.valid_o): + raise ValueError("Bridge decoded invalid message.") + + yield + + yield bridge_rx.valid_i.eq(0) + + +def test_read_decode(): + def testbench(): + yield from verify_read_decoding(b"R0000\r\n", 0x0000) + yield from verify_read_decoding(b"R1234\r\n", 0x1234) + yield from verify_read_decoding(b"RBABE\r\n", 0xBABE) + yield from verify_read_decoding(b"R5678\n", 0x5678) + yield from verify_read_decoding(b"R9ABC\r", 0x9ABC) + + simulate(bridge_rx, testbench) + + +def test_write_decode(): + def testbench(): + yield from verify_write_decoding(b"W12345678\r\n", 0x1234, 0x5678) + yield from verify_write_decoding(b"WDEADBEEF\r\n", 0xDEAD, 0xBEEF) + yield from verify_write_decoding(b"WDEADBEEF\r", 0xDEAD, 0xBEEF) + yield from verify_write_decoding(b"WB0BACAFE\n", 0xB0BA, 0xCAFE) + + simulate(bridge_rx, testbench) + + +def test_no_decode(): + def testbench(): + yield from verify_bad_bytes(b"RABC\r\n") + yield from verify_bad_bytes(b"R12345\r\n") + yield from verify_bad_bytes(b"M\r\n") + yield from verify_bad_bytes(b"W123456789101112131415161718191201222\r\n") + yield from verify_bad_bytes(b"RABCG\r\n") + yield from verify_bad_bytes(b"WABC[]()##*@\r\n") + yield from verify_bad_bytes(b"R\r\n") + + simulate(bridge_rx, testbench) diff --git a/test/test_bridge_tx_sim.py b/test/test_bridge_tx_sim.py new file mode 100644 index 0000000..9a1568d --- /dev/null +++ b/test/test_bridge_tx_sim.py @@ -0,0 +1,67 @@ +from amaranth.sim import Simulator +from manta.uart import TransmitBridge +from manta.utils import * +from random import randint, sample + + +bridge_tx = TransmitBridge() + + +def verify_encoding(data, bytes): + """ + Place a read response on the internal bus, and verify that the sequence of bytes + sent from TransmitBridge matches the provided bytestring `bytes`. + + This function also models an ideal UARTTransmitter module, which begins transmitting + bytes when `start` is asserted, and reports when it is done by asserting `done`. + """ + + # Place a read response on the internal bus + yield bridge_tx.data_i.eq(data) + yield bridge_tx.valid_i.eq(1) + yield bridge_tx.rw_i.eq(0) + yield bridge_tx.done_i.eq(1) + + yield + + yield bridge_tx.data_i.eq(0) + yield bridge_tx.valid_i.eq(0) + yield bridge_tx.rw_i.eq(0) + + yield + + # Model the UARTTransmitter + sent_bytes = b"" + iters = 0 + + while len(sent_bytes) < len(bytes): + # If start_o is asserted, set done_i to zero, then delay, then set it back to one + if (yield bridge_tx.start_o): + yield bridge_tx.done_i.eq(0) + sent_bytes += (yield bridge_tx.data_o).to_bytes(1, "big") + + yield bridge_tx.done_i.eq(0) + for _ in range(10): + yield + + yield bridge_tx.done_i.eq(1) + yield + + # Time out if not enough bytes after trying to get bytes 15 times + iters += 1 + if iters > 15: + raise ValueError("Timed out waiting for bytes.") + + # Verify bytes sent from ReceiveBridge match expected_bytes + if sent_bytes != bytes: + raise ValueError(f"Received {sent_bytes} instead of {bytes}.") + + +def test_some_random_values(): + def testbench(): + for i in sample(range(0xFFFF), k=5000): + expected = f"D{i:04X}\r\n".encode("ascii") + print(i) + yield from verify_encoding(i, expected) + + simulate(bridge_tx, testbench) diff --git a/test/test_io_core_hw.py b/test/test_io_core_hw.py new file mode 100644 index 0000000..25f0b2c --- /dev/null +++ b/test/test_io_core_hw.py @@ -0,0 +1,129 @@ +from amaranth import * +from amaranth_boards.nexys4ddr import Nexys4DDRPlatform +from amaranth_boards.icestick import ICEStickPlatform +from manta import Manta +from manta.utils import * +import pytest +from random import randint + + +class IOCoreLoopbackTest(Elaboratable): + def __init__(self, platform, port): + self.platform = platform + self.port = port + + self.config = self.platform_specific_config() + self.m = Manta(self.config) + + def platform_specific_config(self): + return { + "cores": { + "io_core": { + "type": "io", + "inputs": {"probe0": 1, "probe1": 2, "probe2": 8, "probe3": 20}, + "outputs": { + "probe4": {"width": 1, "initial_value": 1}, + "probe5": { + "width": 2, + "initial_value": 2, + }, + "probe6": 8, + "probe7": {"width": 20, "initial_value": 65538}, + }, + } + }, + "uart": { + "port": self.port, + "baudrate": 3e6, + "clock_freq": self.platform.default_clk_frequency, + }, + } + + def elaborate(self, platform): + m = Module() + m.submodules["manta"] = self.m + + uart_pins = platform.request("uart") + + m.d.comb += [ + self.m.io_core.probe0.eq(self.m.io_core.probe4), + self.m.io_core.probe1.eq(self.m.io_core.probe5), + self.m.io_core.probe2.eq(self.m.io_core.probe6), + self.m.io_core.probe3.eq(self.m.io_core.probe7), + self.m.interface.rx.eq(uart_pins.rx.i), + uart_pins.tx.o.eq(self.m.interface.tx), + ] + + return m + + def build_and_program(self): + self.platform.build(self, do_program=True) + + def verify_output_probe_initial_values(self): + """ + Test that all output probes take their expected initial values. + We can't really test for the same of input probes, since the + strobe register pulses every time the get_probe() method is called. + """ + + # Test that all output probes take their initial values + inputs = self.config["cores"]["io_core"]["inputs"] + outputs = self.config["cores"]["io_core"]["outputs"] + + for name, attrs in outputs.items(): + actual = self.m.io_core.get_probe(name) + + if isinstance(attrs, dict): + if "initial_value" in attrs: + expected = attrs["initial_value"] + + else: + expected = 0 + + if actual != expected: + raise ValueError( + f"Output probe {name} took initial value of {actual} instead of {expected}." + ) + + def verify_probes_update(self): + """ + This design ties all the output probes to input probes, so this + test sets the outputs to random values, and verifies the inputs match + """ + inputs = self.config["cores"]["io_core"]["inputs"] + outputs = self.config["cores"]["io_core"]["outputs"] + + # The config is specified in such a way that the first output is + # connected to the first output, the second output is connected + # to the second input, and so on... + for input, output in zip(inputs, outputs): + width = self.config["cores"]["io_core"]["inputs"][input] + value = randint(0, 2**width - 1) + + self.m.io_core.set_probe(output, value) + readback = self.m.io_core.get_probe(input) + + if readback != value: + raise ValueError( + f"Reading {output} through {input} yielded {readback} instead of {value}!" + ) + + else: + print( + f"Reading {output} through {input} yielded {readback} as expected." + ) + + def verify(self): + self.build_and_program() + self.verify_output_probe_initial_values() + self.verify_probes_update() + + +@pytest.mark.skipif(not xilinx_tools_installed(), reason="no toolchain installed") +def test_output_probe_initial_values_xilinx(): + IOCoreLoopbackTest(Nexys4DDRPlatform(), "/dev/ttyUSB2").verify() + + +@pytest.mark.skipif(not ice40_tools_installed(), reason="no toolchain installed") +def test_output_probe_initial_values_ice40(): + IOCoreLoopbackTest(ICEStickPlatform(), "/dev/ttyUSB1").verify() diff --git a/test/test_io_core_sim.py b/test/test_io_core_sim.py new file mode 100644 index 0000000..5ef1405 --- /dev/null +++ b/test/test_io_core_sim.py @@ -0,0 +1,155 @@ +from amaranth.sim import Simulator +from manta.io_core import IOCore +from manta.utils import * +from random import randint + +config = { + "type": "io", + "inputs": {"probe0": 1, "probe1": 2, "probe2": 8, "probe3": 20}, + "outputs": { + "probe4": {"width": 1, "initial_value": 1}, + "probe5": {"width": 2, "initial_value": 2}, + "probe6": 8, + "probe7": {"width": 20, "initial_value": 65538}, + }, +} + +io_core = IOCore(config, base_addr=0, interface=None) + + +def pulse_strobe_register(): + strobe_addr = io_core.mmap["strobe"]["addrs"][0] + yield from write_register(io_core, strobe_addr, 0) + yield from write_register(io_core, strobe_addr, 1) + yield from write_register(io_core, strobe_addr, 0) + + +def test_output_probe_initial_values(): + def testbench(): + # Verify all output probes initialize to the values in the config + for name, attrs in config["outputs"].items(): + initial_value = 0 + if isinstance(attrs, dict): + if "initial_value" in attrs: + initial_value = attrs["initial_value"] + + output_probe = getattr(io_core, name) + value = yield output_probe + + if value != initial_value: + raise ValueError( + f"Output probe {name} initialized to {value} instead of {initial_value}" + ) + + else: + print(f"Output probe {name} initialized to {value} as expected.") + + simulate(io_core, testbench) + + +def test_input_probe_buffer_initial_value(): + def testbench(): + # Verify all input probe buffers initialize to zero + for name, width in config["inputs"].items(): + addrs = io_core.mmap[name + "_buf"]["addrs"] + + for addr in addrs: + yield from verify_register(io_core, addr, 0) + + simulate(io_core, testbench) + + +def test_output_probe_buffer_initial_value(): + def testbench(): + # Verify all output probe buffers initialize to the values in the config + for name, attrs in config["outputs"].items(): + addrs = io_core.mmap[name + "_buf"]["addrs"] + + datas = [0] * len(addrs) + if isinstance(attrs, dict): + if "initial_value" in attrs: + datas = value_to_words(attrs["initial_value"], len(addrs)) + + for addr, data in zip(addrs, datas): + yield from verify_register(io_core, addr, data) + + simulate(io_core, testbench) + + +def test_output_probes_are_writeable(): + def testbench(): + for name, attrs in config["outputs"].items(): + if isinstance(attrs, dict): + width = attrs["width"] + else: + width = attrs + + addrs = io_core.mmap[name + "_buf"]["addrs"] + test_value = randint(0, (2**width) - 1) + datas = value_to_words(test_value, len(addrs)) + + # write value to registers + for addr, data in zip(addrs, datas): + yield from write_register(io_core, addr, data) + + # read value back from registers + for addr, data in zip(addrs, datas): + yield from verify_register(io_core, addr, data) + + simulate(io_core, testbench) + + +def test_output_probes_update(): + def testbench(): + for name, attrs in config["outputs"].items(): + if isinstance(attrs, dict): + width = attrs["width"] + else: + width = attrs + + addrs = io_core.mmap[name + "_buf"]["addrs"] + test_value = randint(0, (2**width) - 1) + datas = value_to_words(test_value, len(addrs)) + + # write value to registers + for addr, data in zip(addrs, datas): + yield from write_register(io_core, addr, data) + + # pulse strobe register + yield from pulse_strobe_register() + + # check that outputs took updated value + output_probe = getattr(io_core, name) + value = yield (output_probe) + + if value != test_value: + raise ValueError( + f"Output probe {name} took value {value} instead of {test_value} after pulsing strobe." + ) + + else: + print(f"Output probe {name} took value {value} after pulsing strobe.") + + simulate(io_core, testbench) + + +def test_input_probes_update(): + def testbench(): + for name, width in config["inputs"].items(): + test_value = randint(0, (2**width) - 1) + + # set input probe value + input_probe = getattr(io_core, name) + yield input_probe.eq(test_value) + + # pulse strobe register + yield from pulse_strobe_register() + + # check that values are as expected once read back + addrs = io_core.mmap[name + "_buf"]["addrs"] + datas = value_to_words(test_value, len(addrs)) + + for addr, data in zip(addrs, datas): + yield from verify_register(io_core, addr, data) + + simulate(io_core, testbench) diff --git a/test/test_logic_analyzer_hw.py b/test/test_logic_analyzer_hw.py new file mode 100644 index 0000000..1b6b063 --- /dev/null +++ b/test/test_logic_analyzer_hw.py @@ -0,0 +1,84 @@ +from amaranth import * +from amaranth_boards.nexys4ddr import Nexys4DDRPlatform +from amaranth_boards.icestick import ICEStickPlatform +from manta import Manta +from manta.utils import * +import pytest + + +class LogicAnalyzerCounterTest(Elaboratable): + def __init__(self, platform, port): + self.platform = platform + self.port = port + + self.config = self.platform_specific_config() + self.m = Manta(self.config) + + def platform_specific_config(self): + return { + "cores": { + "la": { + "type": "logic_analyzer", + "sample_depth": 1024, + "trigger_loc": 500, + "probes": {"larry": 1, "curly": 3, "moe": 9}, + "triggers": ["moe RISING"], + }, + }, + "uart": { + "port": self.port, + "baudrate": 3e6, + "clock_freq": self.platform.default_clk_frequency, + }, + } + + def elaborate(self, platform): + m = Module() + m.submodules["manta"] = self.m + uart_pins = platform.request("uart") + + larry = self.m.la.probe_signals["larry"]["top_level"] + curly = self.m.la.probe_signals["curly"]["top_level"] + moe = self.m.la.probe_signals["moe"]["top_level"] + + m.d.sync += larry.eq(larry + 1) + m.d.sync += curly.eq(curly + 1) + m.d.sync += moe.eq(moe + 1) + + m.d.comb += [ + self.m.interface.rx.eq(uart_pins.rx.i), + uart_pins.tx.o.eq(self.m.interface.tx), + ] + + return m + + def build_and_program(self): + self.platform.build(self, do_program=True) + + def verify(self): + self.build_and_program() + cap = self.m.la.capture() + + # check that VCD export works + cap.export_vcd("out.vcd") + + # check that Verilog export works + cap.export_playback_verilog("out.v") + + # verify that each signal is just a counter modulo the width of the signal + for name, width in self.m.la.config["probes"].items(): + trace = cap.get_trace(name) + + for i in range(len(trace) - 1): + if trace[i + 1] != (trace[i] + 1) % (2**width): + raise ValueError("Bad counter!") + + +@pytest.mark.skipif(not xilinx_tools_installed(), reason="no toolchain installed") +def test_mem_core_xilinx(): + LogicAnalyzerCounterTest(Nexys4DDRPlatform(), "/dev/ttyUSB2").verify() + + +@pytest.mark.skipif(not ice40_tools_installed(), reason="no toolchain installed") +def test_mem_core_ice40(): + LogicAnalyzerCounterTest(ICEStickPlatform(), "/dev/ttyUSB1").verify() diff --git a/test/test_logic_analyzer_sim.py b/test/test_logic_analyzer_sim.py new file mode 100644 index 0000000..b35e682 --- /dev/null +++ b/test/test_logic_analyzer_sim.py @@ -0,0 +1,140 @@ +from amaranth.sim import Simulator +from manta.logic_analyzer_core import LogicAnalyzerCore +from manta.utils import * +from random import sample + +config = { + "type": "logic_analyzer", + "sample_depth": 1024, + "trigger_loc": 500, + "probes": {"larry": 1, "curly": 3, "moe": 9}, + "triggers": ["moe RISING"], +} + +# class SimulatedBusInterface(): +# def __init__(self, core): +# self.core = core + +# def write(self, addrs, datas): +# # Handle a single integer address and data +# if isinstance(addrs, int) and isinstance(datas, int): +# return self.write([addrs], [datas]) + +# # Make sure address and datas are all integers +# if not isinstance(addrs, list) or not isinstance(datas, list): +# raise ValueError( +# "Write addresses and data must be an integer or list of integers." +# ) + +# if not all(isinstance(a, int) for a in addrs): +# raise ValueError("Write addresses must be all be integers.") + +# if not all(isinstance(d, int) for d in datas): +# raise ValueError("Write data must all be integers.") + +# # I'm not sure if it's necessary to split outputs into chunks +# # I think the output buffer doesn't really drop stuff, just the input buffer + +# for addr, data in zip(addrs, datas): +# yield from write_register(self.core, addr, data) + +# def read(self, addrs): +# # Handle a single integer address +# if isinstance(addrs, int): +# return self.read([addrs])[0] + +# # Make sure all list elements are integers +# if not all(isinstance(a, int) for a in addrs): +# raise ValueError("Read address must be an integer or list of integers.") + +# datas = [] +# for addr in addrs: +# yield la.addr_i.eq(addr) +# yield la.data_i.eq(0) +# yield la.rw_i.eq(0) +# yield la.valid_i.eq(1) +# yield +# yield la.addr_i.eq(0) +# yield la.valid_i.eq(0) + +# # wait for output to be valid +# while not (yield la.valid_o): +# yield + +# datas.append( (yield la.data_o) ) + +# return datas + +la = LogicAnalyzerCore(config, base_addr=0, interface=None) +# interface = SimulatedBusInterface(la) +# la.registers.interface = interface # unironically the least cursed part of this +# la.sample_mem.interface = interface # unironically the least cursed part of this + + +def print_data_at_addr(addr): + # place read transaction on the bus + yield la.addr_i.eq(addr) + yield la.data_i.eq(0) + yield la.rw_i.eq(0) + yield la.valid_i.eq(1) + yield + yield la.addr_i.eq(0) + yield la.valid_i.eq(0) + + # wait for output to be valid + while not (yield la.valid_o): + yield + + print(f"addr: {hex(addr)} data: {hex((yield la.data_o))}") + + +def set_logic_analyzer_register(name, data): + addr = la.registers.mmap[f"{name}_buf"]["addrs"][0] + + yield from write_register(la, 0, 0) + yield from write_register(la, addr, data) + yield from write_register(la, 0, 1) + yield from write_register(la, 0, 0) + + +def test_do_you_fucking_work(): + def testbench(): + # # ok nice what happens if we try to run the core, which includes: + yield from set_logic_analyzer_register("request_stop", 1) + yield from set_logic_analyzer_register("request_stop", 0) + + # setting triggers + yield from set_logic_analyzer_register("curly_op", la.operations["EQ"]) + yield from set_logic_analyzer_register("curly_arg", 4) + + # setting trigger mode + yield from set_logic_analyzer_register( + "trigger_mode", 0 + ) # right now this is not actually respected...oops + + # setting trigger location + yield from set_logic_analyzer_register("trigger_loc", 500) + + # starting capture + yield from set_logic_analyzer_register("request_start", 1) + yield from set_logic_analyzer_register("request_start", 0) + + # wait a few hundred clock cycles, see what happens + for _ in range(700): + yield + + # provide the trigger condition + yield la.probe_signals["curly"]["top_level"].eq(4) + + for _ in range(700): + yield + + # dump sample memory contents + yield from write_register(la, 0, 0) + yield from write_register(la, 0, 1) + yield from write_register(la, 0, 0) + + for addr in range(la.get_max_addr()): + yield from print_data_at_addr(addr) + + simulate(la, testbench, "la_core.vcd") diff --git a/test/test_mem_core_hw.py b/test/test_mem_core_hw.py new file mode 100644 index 0000000..cb3c1de --- /dev/null +++ b/test/test_mem_core_hw.py @@ -0,0 +1,114 @@ +from amaranth import * +from amaranth_boards.nexys4ddr import Nexys4DDRPlatform +from amaranth_boards.icestick import ICEStickPlatform +from manta import Manta +from manta.utils import * +import pytest +from random import randint, sample +from math import ceil, log2 + +""" +Fundamentally we want a function to generate a configuration (as a dictionary) +for a memory core given the width, depth, and platform. This could be a random +configuration, or a standard one. +""" + + +class MemoryCoreLoopbackTest(Elaboratable): + def __init__(self, platform, width, depth, port): + self.platform = platform + self.width = width + self.depth = depth + self.port = port + + self.config = self.platform_specific_config() + self.m = Manta(self.config) + + def platform_specific_config(self): + return { + "cores": { + "mem_core": { + "type": "memory_read_only", + "width": self.width, + "depth": self.depth, + }, + "io_core": { + "type": "io", + "outputs": { + "addr": ceil(log2(self.depth)), + "data": self.width, + "we": 1, + }, + }, + }, + "uart": { + "port": self.port, + "baudrate": 3e6, + "clock_freq": self.platform.default_clk_frequency, + }, + } + + def elaborate(self, platform): + m = Module() + m.submodules["manta"] = self.m + + uart_pins = platform.request("uart") + + m.d.comb += [ + self.m.mem_core.user_addr.eq(self.m.io_core.addr), + self.m.mem_core.user_data.eq(self.m.io_core.data), + self.m.mem_core.user_we.eq(self.m.io_core.we), + self.m.interface.rx.eq(uart_pins.rx.i), + uart_pins.tx.o.eq(self.m.interface.tx), + ] + + return m + + def build_and_program(self): + self.platform.build(self, do_program=True) + + def write_user_side(self, addr, data): + self.m.io_core.set_probe("we", 0) + self.m.io_core.set_probe("addr", addr) + self.m.io_core.set_probe("data", data) + self.m.io_core.set_probe("we", 1) + self.m.io_core.set_probe("we", 0) + + def verify_register(self, addr, expected_data): + data = self.m.mem_core.read_from_user_addr(addr) + + if data != expected_data: + raise ValueError( + f"Memory read from {hex(addr)} returned {hex(data)} instead of {hex(expected_data)}." + ) + + def verify(self): + self.build_and_program() + + # Read and write randomly from the bus side + for addr in sample(range(self.depth), k=self.depth): + data = randint(0, 2**self.width - 1) + self.write_user_side(addr, data) + self.verify_register(addr, data) + + +@pytest.mark.skipif(not xilinx_tools_installed(), reason="no toolchain installed") +def test_mem_core_xilinx(): + MemoryCoreLoopbackTest(Nexys4DDRPlatform(), 33, 1024, "/dev/ttyUSB2").verify() + + +@pytest.mark.skipif(not ice40_tools_installed(), reason="no toolchain installed") +def test_mem_core_ice40(): + port = "/dev/ttyUSB1" + MemoryCoreLoopbackTest(ICEStickPlatform(), 1, 2, port).verify() + MemoryCoreLoopbackTest(ICEStickPlatform(), 1, 512, port).verify() + MemoryCoreLoopbackTest(ICEStickPlatform(), 1, 1024, port).verify() + MemoryCoreLoopbackTest(ICEStickPlatform(), 8, 2, port).verify() + MemoryCoreLoopbackTest(ICEStickPlatform(), 8, 512, port).verify() + MemoryCoreLoopbackTest(ICEStickPlatform(), 8, 1024, port).verify() + MemoryCoreLoopbackTest(ICEStickPlatform(), 14, 512, port).verify() + MemoryCoreLoopbackTest(ICEStickPlatform(), 14, 1024, port).verify() + MemoryCoreLoopbackTest(ICEStickPlatform(), 16, 512, port).verify() + MemoryCoreLoopbackTest(ICEStickPlatform(), 16, 1024, port).verify() + MemoryCoreLoopbackTest(ICEStickPlatform(), 33, 512, port).verify() + MemoryCoreLoopbackTest(ICEStickPlatform(), 33, 1024, port).verify() diff --git a/test/test_mem_core_sim.py b/test/test_mem_core_sim.py new file mode 100644 index 0000000..675991f --- /dev/null +++ b/test/test_mem_core_sim.py @@ -0,0 +1,45 @@ +from manta.memory_core import ReadOnlyMemoryCore +from manta.utils import * +from random import randint, sample + + +def fill_mem_from_user_port(mem_core, depth): + for i in range(depth): + yield mem_core.user_addr.eq(i) + yield mem_core.user_data.eq(i) + yield mem_core.user_we.eq(1) + yield + + yield mem_core.user_we.eq(0) + yield + + +def verify_mem_core(width, depth, base_addr): + config = {"type": "memory", "width": width, "depth": depth} + mem_core = ReadOnlyMemoryCore(config, base_addr, interface=None) + + def testbench(): + yield from fill_mem_from_user_port(mem_core, depth) + + # Read from address sequentially + for i in range(depth): + yield from verify_register(mem_core, i + base_addr, i % (2**width)) + + # Read from addresses randomly + for i in sample(range(depth), k=depth): + yield from verify_register(mem_core, i + base_addr, i % (2**width)) + + simulate(mem_core, testbench) + + +def test_sweep_core_widths(): + for i in range(1, 64): + verify_mem_core(i, 128, 0) + + +def test_random_cores(): + for _ in range(5): + width = randint(0, 512) + depth = randint(0, 1024) + base_addr = randint(0, 2**16 - 1 - depth) + verify_mem_core(width, depth, base_addr) diff --git a/test/test_toolchains.py b/test/test_toolchains.py new file mode 100644 index 0000000..c21c26a --- /dev/null +++ b/test/test_toolchains.py @@ -0,0 +1,15 @@ +from amaranth_boards.test.blinky import * +from amaranth_boards.nexys4ddr import Nexys4DDRPlatform +from amaranth_boards.icestick import ICEStickPlatform +from manta.utils import * +import pytest + + +@pytest.mark.skipif(not xilinx_tools_installed(), reason="no toolchain installed") +def test_arty_a7_tools(): + Nexys4DDRPlatform().build(Blinky(), do_program=False) + + +@pytest.mark.skipif(not ice40_tools_installed(), reason="no toolchain installed") +def test_ice40_tools(): + ICEStickPlatform().build(Blinky(), do_program=False) diff --git a/test/test_uart_rx_sim.py b/test/test_uart_rx_sim.py new file mode 100644 index 0000000..3604591 --- /dev/null +++ b/test/test_uart_rx_sim.py @@ -0,0 +1,65 @@ +from amaranth.sim import Simulator +from manta.uart import UARTReceiver +from manta.utils import * +from random import sample + + +uart_rx = UARTReceiver(clocks_per_baud=10) + + +def verify_receive(data): + # 8N1 serial, LSB sent first + data_bits = "0" + f"{data:08b}"[::-1] + "1" + data_bits = [int(bit) for bit in data_bits] + + valid_asserted_before = False + + for i in range(10 * uart_rx.clocks_per_baud): + bit_index = i // uart_rx.clocks_per_baud + + # Every cycle, run checks on uart_rx: + if (yield uart_rx.valid_o): + if (yield uart_rx.data_o) != data: + a = yield uart_rx.data_o + print(data_bits) + raise ValueError( + f"Incorrect byte presented - gave {hex(a)} instead of {hex(data)}!" + ) + + if bit_index != 9: + print(bit_index) + raise ValueError("Byte presented before it is complete!") + + if not valid_asserted_before: + valid_asserted_before = True + + else: + raise ValueError("Valid asserted more than once!") + + yield uart_rx.rx.eq(data_bits[bit_index]) + yield + + if not valid_asserted_before: + raise ValueError("Failed to assert valid!") + + +def test_all_possible_bytes(): + def testbench(): + yield uart_rx.rx.eq(1) + yield + + for i in range(0xFF): + yield from verify_receive(i) + + simulate(uart_rx, testbench) + + +def test_bytes_random_sample(): + def testbench(): + yield uart_rx.rx.eq(1) + yield + + for i in sample(range(0xFF), k=0xFF): + yield from verify_receive(i) + + simulate(uart_rx, testbench) diff --git a/test/test_uart_tx_sim.py b/test/test_uart_tx_sim.py new file mode 100644 index 0000000..c78d076 --- /dev/null +++ b/test/test_uart_tx_sim.py @@ -0,0 +1,57 @@ +from amaranth.sim import Simulator +from manta.uart import UARTTransmitter +from manta.utils import * +from random import sample + + +uart_tx = UARTTransmitter(clocks_per_baud=10) + + +def verify_bit_sequence(byte): + """ + Request a byte to be transmitted, and verify that the sequence of bits is correct. + """ + + # Request byte to be transmitted + yield uart_tx.data_i.eq(byte) + yield uart_tx.start_i.eq(1) + yield + yield uart_tx.data_i.eq(0) + yield uart_tx.start_i.eq(0) + yield + + # Check that data bit is correct on every clock baud period + + # 8N1 serial, LSB sent first + data_bits = "0" + f"{byte:08b}"[::-1] + "1" + data_bits = [int(bit) for bit in data_bits] + + for i in range(10 * uart_tx.clocks_per_baud): + bit_index = i // uart_tx.clocks_per_baud + + if (yield uart_tx.tx) != data_bits[bit_index]: + raise ValueError("Wrong bit in sequence!") + + if (yield uart_tx.done_o) and (bit_index != 9): + raise ValueError("Done asserted too early!") + + yield + + if not (yield uart_tx.done_o): + raise ValueError("Done not asserted at end of transmission!") + + +def test_all_possible_bytes(): + def testbench(): + for i in range(0xFF): + yield from verify_bit_sequence(i) + + simulate(uart_tx, testbench) + + +def test_bytes_random_sample(): + def testbench(): + for i in sample(range(0xFF), k=0xFF): + yield from verify_bit_sequence(i) + + simulate(uart_tx, testbench) diff --git a/test/test_verilog_gen.py b/test/test_verilog_gen.py new file mode 100644 index 0000000..65bed93 --- /dev/null +++ b/test/test_verilog_gen.py @@ -0,0 +1,14 @@ +from manta.cli import gen +from manta import Manta +import tempfile +import os + + +def test_verilog_gen(): + with tempfile.TemporaryDirectory() as tmp_dir: + print("Created temporary directory at", tmp_dir) + + gen("test/test_verilog_gen.yaml", tmp_dir + "/manta.v") + + if not os.path.isfile(tmp_dir + "/manta.v"): + raise ValueError("No Verilog file generated!") diff --git a/test/functional_sim/io_core_tb/manta.yaml b/test/test_verilog_gen.yaml similarity index 53% rename from test/functional_sim/io_core_tb/manta.yaml rename to test/test_verilog_gen.yaml index 975a96b..09feddc 100644 --- a/test/functional_sim/io_core_tb/manta.yaml +++ b/test/test_verilog_gen.yaml @@ -2,7 +2,6 @@ cores: io_core: type: io - user_clock: True inputs: probe0: 1 @@ -14,11 +13,15 @@ cores: probe4: width: 1 initial_value: 1 - probe5: 2 + probe5: + width: 2 + initial_value: 2 probe6: 8 - probe7: 20 + probe7: + width: 20 + initial_value: 65538 uart: - port: "auto" - baudrate: 3000000 - clock_freq: 100000000 + port: "/dev/ttyUSB1" + baudrate: 115200 + clock_freq: 12000000

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".format(sys.argv[0])) - - else: - input_fname = sys.argv[1] - image_in = Image.open(input_fname) - image_in = image_in.convert('RGB') - - # Resize the image - image_in = image_in.resize((128, 128)) - image_out = image_in.copy() - w, h = image_in.size - - # Take input image and divide each color channel's value by 16 - for y in range(h): - for x in range(w): - r, g, b = image_in.getpixel((x, y)) - image_out.putpixel((x,y), (r//16, g//16, b//16)) - - - # Save the image itself - pixels = [] - for y in range(h): - for x in range(w): - (r, g, b) = image_out.getpixel((x,y)) - color = (r*16*16) + (g*16) + (b) - pixels.append(color) - - from manta import Manta - m = Manta('manta.yaml') - - addrs = list(range(len(pixels))) - m.image_mem.write(addrs, pixels) \ No newline at end of file diff --git a/examples/nexys_a7/video_sprite_ether/src/clk_gen.v b/examples/nexys_a7/video_sprite_ether/src/clk_gen.v deleted file mode 100644 index 91d4265..0000000 --- a/examples/nexys_a7/video_sprite_ether/src/clk_gen.v +++ /dev/null @@ -1,207 +0,0 @@ - -// file: clk_gen.v -// -// (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved. -// -// This file contains confidential and proprietary information -// of Xilinx, Inc. and is protected under U.S. and -// international copyright and other intellectual property -// laws. -// -// DISCLAIMER -// This disclaimer is not a license and does not grant any -// rights to the materials distributed herewith. Except as -// otherwise provided in a valid license issued to you by -// Xilinx, and to the maximum extent permitted by applicable -// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND -// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES -// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING -// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- -// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and -// (2) Xilinx shall not be liable (whether in contract or tort, -// including negligence, or under any other theory of -// liability) for any loss or damage of any kind or nature -// related to, arising under or in connection with these -// materials, including for any direct, or any indirect, -// special, incidental, or consequential loss or damage -// (including loss of data, profits, goodwill, or any type of -// loss or damage suffered as a result of any action brought -// by a third party) even if such damage or loss was -// reasonably foreseeable or Xilinx had been advised of the -// possibility of the same. -// -// CRITICAL APPLICATIONS -// Xilinx products are not designed or intended to be fail- -// safe, or for use in any application requiring fail-safe -// performance, such as life-support or safety devices or -// systems, Class III medical devices, nuclear facilities, -// applications related to the deployment of airbags, or any -// other applications that could lead to death, personal -// injury, or severe property or environmental damage -// (individually and collectively, "Critical -// Applications"). Customer assumes the sole risk and -// liability of any use of Xilinx products in Critical -// Applications, subject only to applicable laws and -// regulations governing limitations on product liability. -// -// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS -// PART OF THIS FILE AT ALL TIMES. -// -//---------------------------------------------------------------------------- -// User entered comments -//---------------------------------------------------------------------------- -// None -// -//---------------------------------------------------------------------------- -// Output Output Phase Duty Cycle Pk-to-Pk Phase -// Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps) -//---------------------------------------------------------------------------- -// clk_50mhz__50.00000______0.000______50.0______150.541_____99.281 -// clk_65mhz__65.00000______0.000______50.0______142.278_____99.281 -// -//---------------------------------------------------------------------------- -// Input Clock Freq (MHz) Input Jitter (UI) -//---------------------------------------------------------------------------- -// __primary_________100.000____________0.010 - -`timescale 1ps/1ps - -module clk_gen - - (// Clock in ports - // Clock out ports - output clk_50mhz, - output clk_65mhz, - input clk_100mhz - ); - // Input buffering - //------------------------------------ -wire clk_100mhz_clk_gen; -wire clk_in2_clk_gen; - IBUF clkin1_ibufg - (.O (clk_100mhz_clk_gen), - .I (clk_100mhz)); - - - - - // Clocking PRIMITIVE - //------------------------------------ - - // Instantiation of the MMCM PRIMITIVE - // * Unused inputs are tied off - // * Unused outputs are labeled unused - - wire clk_50mhz_clk_gen; - wire clk_65mhz_clk_gen; - wire clk_out3_clk_gen; - wire clk_out4_clk_gen; - wire clk_out5_clk_gen; - wire clk_out6_clk_gen; - wire clk_out7_clk_gen; - - wire [15:0] do_unused; - wire drdy_unused; - wire psdone_unused; - wire locked_int; - wire clkfbout_clk_gen; - wire clkfbout_buf_clk_gen; - wire clkfboutb_unused; - wire clkout0b_unused; - wire clkout1b_unused; - wire clkout2_unused; - wire clkout2b_unused; - wire clkout3_unused; - wire clkout3b_unused; - wire clkout4_unused; - wire clkout5_unused; - wire clkout6_unused; - wire clkfbstopped_unused; - wire clkinstopped_unused; - - MMCME2_ADV - #(.BANDWIDTH ("OPTIMIZED"), - .CLKOUT4_CASCADE ("FALSE"), - .COMPENSATION ("ZHOLD"), - .STARTUP_WAIT ("FALSE"), - .DIVCLK_DIVIDE (1), - .CLKFBOUT_MULT_F (9.750), - .CLKFBOUT_PHASE (0.000), - .CLKFBOUT_USE_FINE_PS ("FALSE"), - .CLKOUT0_DIVIDE_F (19.500), - .CLKOUT0_PHASE (0.000), - .CLKOUT0_DUTY_CYCLE (0.500), - .CLKOUT0_USE_FINE_PS ("FALSE"), - .CLKOUT1_DIVIDE (15), - .CLKOUT1_PHASE (0.000), - .CLKOUT1_DUTY_CYCLE (0.500), - .CLKOUT1_USE_FINE_PS ("FALSE"), - .CLKIN1_PERIOD (10.000)) - mmcm_adv_inst - // Output clocks - ( - .CLKFBOUT (clkfbout_clk_gen), - .CLKFBOUTB (clkfboutb_unused), - .CLKOUT0 (clk_50mhz_clk_gen), - .CLKOUT0B (clkout0b_unused), - .CLKOUT1 (clk_65mhz_clk_gen), - .CLKOUT1B (clkout1b_unused), - .CLKOUT2 (clkout2_unused), - .CLKOUT2B (clkout2b_unused), - .CLKOUT3 (clkout3_unused), - .CLKOUT3B (clkout3b_unused), - .CLKOUT4 (clkout4_unused), - .CLKOUT5 (clkout5_unused), - .CLKOUT6 (clkout6_unused), - // Input clock control - .CLKFBIN (clkfbout_buf_clk_gen), - .CLKIN1 (clk_100mhz_clk_gen), - .CLKIN2 (1'b0), - // Tied to always select the primary input clock - .CLKINSEL (1'b1), - // Ports for dynamic reconfiguration - .DADDR (7'h0), - .DCLK (1'b0), - .DEN (1'b0), - .DI (16'h0), - .DO (do_unused), - .DRDY (drdy_unused), - .DWE (1'b0), - // Ports for dynamic phase shift - .PSCLK (1'b0), - .PSEN (1'b0), - .PSINCDEC (1'b0), - .PSDONE (psdone_unused), - // Other control and status signals - .LOCKED (locked_int), - .CLKINSTOPPED (clkinstopped_unused), - .CLKFBSTOPPED (clkfbstopped_unused), - .PWRDWN (1'b0), - .RST (1'b0)); - -// Clock Monitor clock assigning -//-------------------------------------- - // Output buffering - //----------------------------------- - - BUFG clkf_buf - (.O (clkfbout_buf_clk_gen), - .I (clkfbout_clk_gen)); - - - - - - - BUFG clkout1_buf - (.O (clk_50mhz), - .I (clk_50mhz_clk_gen)); - - - BUFG clkout2_buf - (.O (clk_65mhz), - .I (clk_65mhz_clk_gen)); - - - -endmodule diff --git a/examples/nexys_a7/video_sprite_ether/src/top_level.sv b/examples/nexys_a7/video_sprite_ether/src/top_level.sv deleted file mode 100644 index c1023db..0000000 --- a/examples/nexys_a7/video_sprite_ether/src/top_level.sv +++ /dev/null @@ -1,108 +0,0 @@ -`timescale 1ns / 1ps -`default_nettype none - -module top_level ( - input wire clk_100mhz, - - output reg eth_refclk, - output reg eth_rstn, - - input wire eth_crsdv, - input wire [1:0] eth_rxd, - - output reg eth_txen, - output reg [1:0] eth_txd, - - output logic [3:0] vga_r, vga_g, vga_b, - output logic vga_hs, vga_vs); - - assign eth_rstn = 1; - - // Clock generation - logic clk_50mhz; - logic clk_65mhz; - assign eth_refclk = clk_50mhz; - - clk_gen gen( - .clk_100mhz(clk_100mhz), - .clk_50mhz(clk_50mhz), - .clk_65mhz(clk_65mhz)); - - // VGA signals - logic [10:0] hcount; - logic [9:0] vcount; - logic hsync, vsync, blank; - - vga vga_gen( - .pixel_clk_in(clk_65mhz), - .hcount_out(hcount), - .vcount_out(vcount), - .hsync_out(hsync), - .vsync_out(vsync), - .blank_out(blank)); - - // VGA Pipelining - reg[1:0][10:0] hcount_pipe; - reg[1:0][10:0] vcount_pipe; - reg[1:0] hsync_pipe; - reg[1:0] vsync_pipe; - reg[1:0] blank_pipe; - - always_ff @(posedge clk_65mhz)begin - hcount_pipe[0] <= hcount; - vcount_pipe[0] <= vcount; - hsync_pipe[0] <= hsync; - vsync_pipe[0] <= vsync; - blank_pipe[0] <= blank; - for (int i=1; i<2; i = i+1)begin - hcount_pipe[i] <= hcount_pipe[i-1]; - vcount_pipe[i] <= vcount_pipe[i-1]; - hsync_pipe[i] <= hsync_pipe[i-1]; - vsync_pipe[i] <= vsync_pipe[i-1]; - blank_pipe[i] <= blank_pipe[i-1]; - end - end - - localparam WIDTH = 128; - localparam HEIGHT = 128; - - localparam X = 0; - localparam Y = 0; - - // calculate rom address - logic [$clog2(WIDTH*HEIGHT)-1:0] image_addr; - assign image_addr = (hcount - X) + ((vcount - Y) * WIDTH); - - logic in_sprite; - assign in_sprite = ((hcount_pipe[1] >= X && hcount_pipe[1] < (X + WIDTH)) && - (vcount_pipe[1] >= Y && vcount_pipe[1] < (Y + HEIGHT))); - - manta manta_inst ( - .clk(clk_50mhz), - - .crsdv(eth_crsdv), - .rxd(eth_rxd), - .txen(eth_txen), - .txd(eth_txd), - - .image_mem_clk(clk_65mhz), - .image_mem_addr(image_addr), - .image_mem_din(), - .image_mem_dout(sprite_color), - .image_mem_we(1'b0)); - - logic [11:0] sprite_color; - logic [11:0] color; - assign color = in_sprite ? sprite_color : 12'h0; - - // the following lines are required for the Nexys4 VGA circuit - do not change - assign vga_r = ~blank_pipe[1] ? color[11:8]: 0; - assign vga_g = ~blank_pipe[1] ? color[7:4] : 0; - assign vga_b = ~blank_pipe[1] ? color[3:0] : 0; - - assign vga_hs = ~hsync_pipe[1]; - assign vga_vs = ~vsync_pipe[1]; - - -endmodule -`default_nettype wire diff --git a/examples/nexys_a7/video_sprite_ether/src/vga.sv b/examples/nexys_a7/video_sprite_ether/src/vga.sv deleted file mode 100644 index 3fa787f..0000000 --- a/examples/nexys_a7/video_sprite_ether/src/vga.sv +++ /dev/null @@ -1,68 +0,0 @@ - -/* vga: Generate VGA display signals (1024 x 768 @ 60Hz) - * - * ---- HORIZONTAL ----- ------VERTICAL ----- - * Active Active - * Freq Video FP Sync BP Video FP Sync BP - * 640x480, 60Hz 25.175 640 16 96 48 480 11 2 31 - * 800x600, 60Hz 40.000 800 40 128 88 600 1 4 23 - * 1024x768, 60Hz 65.000 1024 24 136 160 768 3 6 29 - * 1280x1024, 60Hz 108.00 1280 48 112 248 768 1 3 38 - * 1280x720p 60Hz 75.25 1280 72 80 216 720 3 5 30 - * 1920x1080 60Hz 148.5 1920 88 44 148 1080 4 5 36 - * - * change the clock frequency, front porches, sync's, and back porches to create - * other screen resolutions - */ - -module vga( - input wire pixel_clk_in, - output logic [10:0] hcount_out, // pixel number on current line - output logic [9:0] vcount_out, // line number - output logic vsync_out, hsync_out, - output logic blank_out); - - parameter DISPLAY_WIDTH = 1024; // display width - parameter DISPLAY_HEIGHT = 768; // number of lines - - parameter H_FP = 24; // horizontal front porch - parameter H_SYNC_PULSE = 136; // horizontal sync - parameter H_BP = 160; // horizontal back porch - - parameter V_FP = 3; // vertical front porch - parameter V_SYNC_PULSE = 6; // vertical sync - parameter V_BP = 29; // vertical back porch - - // horizontal: 1344 pixels total - // display 1024 pixels per line - logic hblank,vblank; - logic hsyncon,hsyncoff,hreset,hblankon; - assign hblankon = (hcount_out == (DISPLAY_WIDTH -1)); - assign hsyncon = (hcount_out == (DISPLAY_WIDTH + H_FP - 1)); //1047 - assign hsyncoff = (hcount_out == (DISPLAY_WIDTH + H_FP + H_SYNC_PULSE - 1)); // 1183 - assign hreset = (hcount_out == (DISPLAY_WIDTH + H_FP + H_SYNC_PULSE + H_BP - 1)); //1343 - - // vertical: 806 lines total - // display 768 lines - logic vsyncon,vsyncoff,vreset,vblankon; - assign vblankon = hreset & (vcount_out == (DISPLAY_HEIGHT - 1)); // 767 - assign vsyncon = hreset & (vcount_out == (DISPLAY_HEIGHT + V_FP - 1)); // 771 - assign vsyncoff = hreset & (vcount_out == (DISPLAY_HEIGHT + V_FP + V_SYNC_PULSE - 1)); // 777 - assign vreset = hreset & (vcount_out == (DISPLAY_HEIGHT + V_FP + V_SYNC_PULSE + V_BP - 1)); // 805 - - // sync and blanking - logic next_hblank,next_vblank; - assign next_hblank = hreset ? 0 : hblankon ? 1 : hblank; - assign next_vblank = vreset ? 0 : vblankon ? 1 : vblank; - always_ff @(posedge pixel_clk_in) begin - hcount_out <= hreset ? 0 : hcount_out + 1; - hblank <= next_hblank; - hsync_out <= hsyncon ? 0 : hsyncoff ? 1 : hsync_out; // active low - - vcount_out <= hreset ? (vreset ? 0 : vcount_out + 1) : vcount_out; - vblank <= next_vblank; - vsync_out <= vsyncon ? 0 : vsyncoff ? 1 : vsync_out; // active low - - blank_out <= next_vblank | (next_hblank & ~hreset); - end -endmodule \ No newline at end of file diff --git a/examples/nexys_a7/video_sprite_ether/xdc/top_level.xdc b/examples/nexys_a7/video_sprite_ether/xdc/top_level.xdc deleted file mode 100644 index 8a3551b..0000000 --- a/examples/nexys_a7/video_sprite_ether/xdc/top_level.xdc +++ /dev/null @@ -1,253 +0,0 @@ -## This file is a general .xdc for the Nexys4 DDR Rev. C -## To use it in a project: -## - uncomment the lines corresponding to used pins -## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project - -## This file has been modified from the default .xdc provided by Digilent for the Nexys A7 - -## Clock signal -set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { clk_100mhz }]; #IO_L12P_T1_MRCC_35 Sch=clk_100mhz -create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {clk_100mhz}]; - - -##Switches - -#set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { sw[0] }]; #IO_L24N_T3_RS0_15 Sch=sw[0] -#set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 } [get_ports { sw[1] }]; #IO_L3N_T0_DQS_EMCCLK_14 Sch=sw[1] -#set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { sw[2] }]; #IO_L6N_T0_D08_VREF_14 Sch=sw[2] -#set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { sw[3] }]; #IO_L13N_T2_MRCC_14 Sch=sw[3] -#set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { sw[4] }]; #IO_L12N_T1_MRCC_14 Sch=sw[4] -#set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { sw[5] }]; #IO_L7N_T1_D10_14 Sch=sw[5] -#set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { sw[6] }]; #IO_L17N_T2_A13_D29_14 Sch=sw[6] -#set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { sw[7] }]; #IO_L5N_T0_D07_14 Sch=sw[7] -#set_property -dict { PACKAGE_PIN T8 IOSTANDARD LVCMOS18 } [get_ports { sw[8] }]; #IO_L24N_T3_34 Sch=sw[8] -#set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS18 } [get_ports { sw[9] }]; #IO_25_34 Sch=sw[9] -#set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { sw[10] }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=sw[10] -#set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { sw[11] }]; #IO_L23P_T3_A03_D19_14 Sch=sw[11] -#set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { sw[12] }]; #IO_L24P_T3_35 Sch=sw[12] -#set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { sw[13] }]; #IO_L20P_T3_A08_D24_14 Sch=sw[13] -#set_property -dict { PACKAGE_PIN U11 IOSTANDARD LVCMOS33 } [get_ports { sw[14] }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=sw[14] -#set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { sw[15] }]; #IO_L21P_T3_DQS_14 Sch=sw[15] - - -## LEDs - -#set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { led[0] }]; #IO_L18P_T2_A24_15 Sch=led[0] -#set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { led[1] }]; #IO_L24P_T3_RS1_15 Sch=led[1] -#set_property -dict { PACKAGE_PIN J13 IOSTANDARD LVCMOS33 } [get_ports { led[2] }]; #IO_L17N_T2_A25_15 Sch=led[2] -#set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { led[3] }]; #IO_L8P_T1_D11_14 Sch=led[3] -#set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { led[4] }]; #IO_L7P_T1_D09_14 Sch=led[4] -#set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { led[5] }]; #IO_L18N_T2_A11_D27_14 Sch=led[5] -#set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { led[6] }]; #IO_L17P_T2_A14_D30_14 Sch=led[6] -#set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { led[7] }]; #IO_L18P_T2_A12_D28_14 Sch=led[7] -#set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { led[8] }]; #IO_L16N_T2_A15_D31_14 Sch=led[8] -#set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { led[9] }]; #IO_L14N_T2_SRCC_14 Sch=led[9] -#set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { led[10] }]; #IO_L22P_T3_A05_D21_14 Sch=led[10] -#set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { led[11] }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=led[11] -#set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { led[12] }]; #IO_L16P_T2_CSI_B_14 Sch=led[12] -#set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { led[13] }]; #IO_L22N_T3_A04_D20_14 Sch=led[13] -#set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { led[14] }]; #IO_L20N_T3_A07_D23_14 Sch=led[14] -#set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { led[15] }]; #IO_L21N_T3_DQS_A06_D22_14 Sch=led[15] - -#set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { led16_b }]; #IO_L5P_T0_D06_14 Sch=led16_b -#set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { led16_g }]; #IO_L10P_T1_D14_14 Sch=led16_g -#set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { led16_r }]; #IO_L11P_T1_SRCC_14 Sch=led16_r -#set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { led17_b }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=led17_b -#set_property -dict { PACKAGE_PIN R11 IOSTANDARD LVCMOS33 } [get_ports { led17_g }]; #IO_0_14 Sch=led17_g -#set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { led17_r }]; #IO_L11N_T1_SRCC_14 Sch=led17_r - - -##7 segment display - -#set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { ca }]; #IO_L24N_T3_A00_D16_14 Sch=ca -#set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { cb }]; #IO_25_14 Sch=cb -#set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { cc }]; #IO_25_15 Sch=cc -#set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { cd }]; #IO_L17P_T2_A26_15 Sch=cd -#set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ce }]; #IO_L13P_T2_MRCC_14 Sch=ce -#set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { cf }]; #IO_L19P_T3_A10_D26_14 Sch=cf -#set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { cg }]; #IO_L4P_T0_D04_14 Sch=cg - -#set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { dp }]; #IO_L19N_T3_A21_VREF_15 Sch=dp - -#set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { an[0] }]; #IO_L23P_T3_FOE_B_15 Sch=an[0] -#set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { an[1] }]; #IO_L23N_T3_FWE_B_15 Sch=an[1] -#set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { an[2] }]; #IO_L24P_T3_A01_D17_14 Sch=an[2] -#set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { an[3] }]; #IO_L19P_T3_A22_15 Sch=an[3] -#set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { an[4] }]; #IO_L8N_T1_D12_14 Sch=an[4] -#set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { an[5] }]; #IO_L14P_T2_SRCC_14 Sch=an[5] -#set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { an[6] }]; #IO_L23P_T3_35 Sch=an[6] -#set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { an[7] }]; #IO_L23N_T3_A02_D18_14 Sch=an[7] - - -##Buttons - -#set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { cpu_resetn }]; #IO_L3P_T0_DQS_AD1P_15 Sch=cpu_resetn - -#set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { btnc }]; #IO_L9P_T1_DQS_14 Sch=btnc -#set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { btnu }]; #IO_L4N_T0_D05_14 Sch=btnu -#set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { btnl }]; #IO_L12P_T1_MRCC_14 Sch=btnl -#set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { btnr }]; #IO_L10N_T1_D15_14 Sch=btnr -#set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { btnd }]; #IO_L9N_T1_DQS_D13_14 Sch=btnd - - -##Pmod Headers - - -##Pmod Header JA - -#set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { ja[0] }]; #IO_L20N_T3_A19_15 Sch=ja[1] -#set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { ja[1] }]; #IO_L21N_T3_DQS_A18_15 Sch=ja[2] -#set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { ja[2] }]; #IO_L21P_T3_DQS_15 Sch=ja[3] -#set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { ja[3] }]; #IO_L18N_T2_A23_15 Sch=ja[4] -#set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L16N_T2_A27_15 Sch=ja[7] -#set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L16P_T2_A28_15 Sch=ja[8] -#set_property -dict { PACKAGE_PIN F18 IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L22N_T3_A16_15 Sch=ja[9] -#set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_L22P_T3_A17_15 Sch=ja[10] - - -##Pmod Header JB - -#set_property -dict { PACKAGE_PIN D14 IOSTANDARD LVCMOS33 } [get_ports { jb[0] }]; #IO_L1P_T0_AD0P_15 Sch=jb[1] -#set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { jb[1] }]; #IO_L14N_T2_SRCC_15 Sch=jb[2] -#set_property -dict { PACKAGE_PIN G16 IOSTANDARD LVCMOS33 } [get_ports { jb[2] }]; #IO_L13N_T2_MRCC_15 Sch=jb[3] -#set_property -dict { PACKAGE_PIN H14 IOSTANDARD LVCMOS33 } [get_ports { jb[3] }]; #IO_L15P_T2_DQS_15 Sch=jb[4] -#set_property -dict { PACKAGE_PIN E16 IOSTANDARD LVCMOS33 } [get_ports { jb[4] }]; #IO_L11N_T1_SRCC_15 Sch=jb[7] -#set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { jb[5] }]; #IO_L5P_T0_AD9P_15 Sch=jb[8] -#set_property -dict { PACKAGE_PIN G13 IOSTANDARD LVCMOS33 } [get_ports { jb[6] }]; #IO_0_15 Sch=jb[9] -#set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { jb[7] }]; #IO_L13P_T2_MRCC_15 Sch=jb[10] - - -##Pmod Header JC - -#set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { jc[0] }]; #IO_L23N_T3_35 Sch=jc[1] -#set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { jc[1] }]; #IO_L19N_T3_VREF_35 Sch=jc[2] -#set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { jc[2] }]; #IO_L22N_T3_35 Sch=jc[3] -#set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { jc[3] }]; #IO_L19P_T3_35 Sch=jc[4] -#set_property -dict { PACKAGE_PIN E7 IOSTANDARD LVCMOS33 } [get_ports { jc[4] }]; #IO_L6P_T0_35 Sch=jc[7] -#set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { jc[5] }]; #IO_L22P_T3_35 Sch=jc[8] -#set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { jc[6] }]; #IO_L21P_T3_DQS_35 Sch=jc[9] -#set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { jc[7] }]; #IO_L5P_T0_AD13P_35 Sch=jc[10] - - -##Pmod Header JD - -#set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { jd[0] }]; #IO_L21N_T3_DQS_35 Sch=jd[1] -#set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports { jd[1] }]; #IO_L17P_T2_35 Sch=jd[2] -#set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { jd[2] }]; #IO_L17N_T2_35 Sch=jd[3] -#set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { jd[3] }]; #IO_L20N_T3_35 Sch=jd[4] -#set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { jd[4] }]; #IO_L15P_T2_DQS_35 Sch=jd[7] -#set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { jd[5] }]; #IO_L20P_T3_35 Sch=jd[8] -#set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { jd[6] }]; #IO_L15N_T2_DQS_35 Sch=jd[9] -#set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { jd[7] }]; #IO_L13N_T2_MRCC_35 Sch=jd[10] - - -##Pmod Header JXADC - -#set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVDS } [get_ports { xa_n[0] }]; #IO_L9N_T1_DQS_AD3N_15 Sch=xa_n[1] -#set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVDS } [get_ports { xa_p[0] }]; #IO_L9P_T1_DQS_AD3P_15 Sch=xa_p[1] -#set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVDS } [get_ports { xa_n[1] }]; #IO_L8N_T1_AD10N_15 Sch=xa_n[2] -#set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVDS } [get_ports { xa_p[1] }]; #IO_L8P_T1_AD10P_15 Sch=xa_p[2] -#set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVDS } [get_ports { xa_n[2] }]; #IO_L7N_T1_AD2N_15 Sch=xa_n[3] -#set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVDS } [get_ports { xa_p[2] }]; #IO_L7P_T1_AD2P_15 Sch=xa_p[3] -#set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVDS } [get_ports { xa_n[3] }]; #IO_L10N_T1_AD11N_15 Sch=xa_n[4] -#set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVDS } [get_ports { xa_p[3] }]; #IO_L10P_T1_AD11P_15 Sch=xa_p[4] - - -##VGA Connector - -set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { vga_r[0] }]; #IO_L8N_T1_AD14N_35 Sch=vga_r[0] -set_property -dict { PACKAGE_PIN B4 IOSTANDARD LVCMOS33 } [get_ports { vga_r[1] }]; #IO_L7N_T1_AD6N_35 Sch=vga_r[1] -set_property -dict { PACKAGE_PIN C5 IOSTANDARD LVCMOS33 } [get_ports { vga_r[2] }]; #IO_L1N_T0_AD4N_35 Sch=vga_r[2] -set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { vga_r[3] }]; #IO_L8P_T1_AD14P_35 Sch=vga_r[3] - -set_property -dict { PACKAGE_PIN C6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[0] }]; #IO_L1P_T0_AD4P_35 Sch=vga_g[0] -set_property -dict { PACKAGE_PIN A5 IOSTANDARD LVCMOS33 } [get_ports { vga_g[1] }]; #IO_L3N_T0_DQS_AD5N_35 Sch=vga_g[1] -set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[2] }]; #IO_L2N_T0_AD12N_35 Sch=vga_g[2] -set_property -dict { PACKAGE_PIN A6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[3] }]; #IO_L3P_T0_DQS_AD5P_35 Sch=vga_g[3] - -set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[0] }]; #IO_L2P_T0_AD12P_35 Sch=vga_b[0] -set_property -dict { PACKAGE_PIN C7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[1] }]; #IO_L4N_T0_35 Sch=vga_b[1] -set_property -dict { PACKAGE_PIN D7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[2] }]; #IO_L6N_T0_VREF_35 Sch=vga_b[2] -set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { vga_b[3] }]; #IO_L4P_T0_35 Sch=vga_b[3] - -set_property -dict { PACKAGE_PIN B11 IOSTANDARD LVCMOS33 } [get_ports { vga_hs }]; #IO_L4P_T0_15 Sch=vga_hs -set_property -dict { PACKAGE_PIN B12 IOSTANDARD LVCMOS33 } [get_ports { vga_vs }]; #IO_L3N_T0_DQS_AD1N_15 Sch=vga_vs - -##Micro SD Connector - -#set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { sd_reset }]; #IO_L14P_T2_SRCC_35 Sch=sd_reset -#set_property -dict { PACKAGE_PIN A1 IOSTANDARD LVCMOS33 } [get_ports { sd_cd }]; #IO_L9N_T1_DQS_AD7N_35 Sch=sd_cd -#set_property -dict { PACKAGE_PIN B1 IOSTANDARD LVCMOS33 } [get_ports { sd_sck }]; #IO_L9P_T1_DQS_AD7P_35 Sch=sd_sck -#set_property -dict { PACKAGE_PIN C1 IOSTANDARD LVCMOS33 } [get_ports { sd_cmd }]; #IO_L16N_T2_35 Sch=sd_cmd -#set_property -dict { PACKAGE_PIN C2 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[0] }]; #IO_L16P_T2_35 Sch=sd_dat[0] -#set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[1] }]; #IO_L18N_T2_35 Sch=sd_dat[1] -#set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[2] }]; #IO_L18P_T2_35 Sch=sd_dat[2] -#set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { sd_dat[3] }]; #IO_L14N_T2_SRCC_35 Sch=sd_dat[3] - - -##Accelerometer - -#set_property -dict { PACKAGE_PIN E15 IOSTANDARD LVCMOS33 } [get_ports { acl_miso }]; #IO_L11P_T1_SRCC_15 Sch=acl_miso -#set_property -dict { PACKAGE_PIN F14 IOSTANDARD LVCMOS33 } [get_ports { acl_mosi }]; #IO_L5N_T0_AD9N_15 Sch=acl_mosi -#set_property -dict { PACKAGE_PIN F15 IOSTANDARD LVCMOS33 } [get_ports { acl_sclk }]; #IO_L14P_T2_SRCC_15 Sch=acl_sclk -#set_property -dict { PACKAGE_PIN D15 IOSTANDARD LVCMOS33 } [get_ports { acl_csn }]; #IO_L12P_T1_MRCC_15 Sch=acl_csn -#set_property -dict { PACKAGE_PIN B13 IOSTANDARD LVCMOS33 } [get_ports { acl_int[1] }]; #IO_L2P_T0_AD8P_15 Sch=acl_int[1] -#set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 } [get_ports { acl_int[2] }]; #IO_L20P_T3_A20_15 Sch=acl_int[2] - - -##Temperature Sensor - -#set_property -dict { PACKAGE_PIN C14 IOSTANDARD LVCMOS33 } [get_ports { tmp_scl }]; #IO_L1N_T0_AD0N_15 Sch=tmp_scl -#set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS33 } [get_ports { tmp_sda }]; #IO_L12N_T1_MRCC_15 Sch=tmp_sda -#set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 } [get_ports { tmp_int }]; #IO_L6N_T0_VREF_15 Sch=tmp_int -#set_property -dict { PACKAGE_PIN B14 IOSTANDARD LVCMOS33 } [get_ports { tmp_ct }]; #IO_L2N_T0_AD8N_15 Sch=tmp_ct - -##Omnidirectional Microphone - -#set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { m_clk }]; #IO_25_35 Sch=m_clk -#set_property -dict { PACKAGE_PIN H5 IOSTANDARD LVCMOS33 } [get_ports { m_data }]; #IO_L24N_T3_35 Sch=m_data -#set_property -dict { PACKAGE_PIN F5 IOSTANDARD LVCMOS33 } [get_ports { m_lrsel }]; #IO_0_35 Sch=m_lrsel - - -##PWM Audio Amplifier - -#set_property -dict { PACKAGE_PIN A11 IOSTANDARD LVCMOS33 } [get_ports { aud_pwm }]; #IO_L4N_T0_15 Sch=aud_pwm -#set_property -dict { PACKAGE_PIN D12 IOSTANDARD LVCMOS33 } [get_ports { aud_sd }]; #IO_L6P_T0_15 Sch=aud_sd - - -##USB-RS232 Interface - -#set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { uart_txd_in }]; #IO_L7P_T1_AD6P_35 Sch=uart_txd_in -#set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { uart_rxd_out }]; #IO_L11N_T1_SRCC_35 Sch=uart_rxd_out -#set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { uart_cts }]; #IO_L12N_T1_MRCC_35 Sch=uart_cts -#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { uart_rts }]; #IO_L5N_T0_AD13N_35 Sch=uart_rts - -##USB HID (PS/2) - -#set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { ps2_clk }]; #IO_L13P_T2_MRCC_35 Sch=ps2_clk -#set_property -dict { PACKAGE_PIN B2 IOSTANDARD LVCMOS33 } [get_ports { ps2_data }]; #IO_L10N_T1_AD15N_35 Sch=ps2_data - - -##SMSC Ethernet PHY - -#set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { eth_mdc }]; #IO_L11P_T1_SRCC_16 Sch=eth_mdc -#set_property -dict { PACKAGE_PIN A9 IOSTANDARD LVCMOS33 } [get_ports { eth_mdio }]; #IO_L14N_T2_SRCC_16 Sch=eth_mdio -set_property -dict { PACKAGE_PIN B3 IOSTANDARD LVCMOS33 } [get_ports { eth_rstn }]; #IO_L10P_T1_AD15P_35 Sch=eth_rstn -set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { eth_crsdv }]; #IO_L6N_T0_VREF_16 Sch=eth_crsdv -#set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { eth_rxerr }]; #IO_L13N_T2_MRCC_16 Sch=eth_rxerr -set_property -dict { PACKAGE_PIN C11 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[0] }]; #IO_L13P_T2_MRCC_16 Sch=eth_rxd[0] -set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[1] }]; #IO_L19N_T3_VREF_16 Sch=eth_rxd[1] -set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { eth_txen }]; #IO_L11N_T1_SRCC_16 Sch=eth_txen -set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[0] }]; #IO_L14P_T2_SRCC_16 Sch=eth_txd[0] -set_property -dict { PACKAGE_PIN A8 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[1] }]; #IO_L12N_T1_MRCC_16 Sch=eth_txd[1] -set_property -dict { PACKAGE_PIN D5 IOSTANDARD LVCMOS33 } [get_ports { eth_refclk }]; #IO_L11P_T1_SRCC_35 Sch=eth_refclk -#set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { eth_intn }]; #IO_L12P_T1_MRCC_16 Sch=eth_intn - - -##Quad SPI Flash - -#set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[0] }]; #IO_L1P_T0_D00_MOSI_14 Sch=qspi_dq[0] -#set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[1] }]; #IO_L1N_T0_D01_DIN_14 Sch=qspi_dq[1] -#set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[2] }]; #IO_L2P_T0_D02_14 Sch=qspi_dq[2] -#set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[3] }]; #IO_L2N_T0_D03_14 Sch=qspi_dq[3] -#set_property -dict { PACKAGE_PIN L13 IOSTANDARD LVCMOS33 } [get_ports { qspi_csn }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_csn \ No newline at end of file diff --git a/examples/nexys_a7/video_sprite_uart/img/buff_doge.png b/examples/nexys_a7/video_sprite_uart/img/buff_doge.png deleted file mode 100644 index d504d022b1fbe9896a43e008ec41ffbad202d00d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69692 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�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