ipweave 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ipweave/__init__.py +28 -0
- ipweave/_legacy_cli.py +80 -0
- ipweave/_loc.py +46 -0
- ipweave/_toolchain/__init__.py +37 -0
- ipweave/_toolchain/yosys.py +255 -0
- ipweave/_tree.py +59 -0
- ipweave/_unused.py +47 -0
- ipweave/_utils.py +104 -0
- ipweave/agents.py +241 -0
- ipweave/asserts.py +15 -0
- ipweave/board/LICENSE.amaranth-boards.txt +21 -0
- ipweave/board/LICENSE.litex-boards.txt +26 -0
- ipweave/board/__init__.py +38 -0
- ipweave/board/_catalogue.json +45923 -0
- ipweave/board/_programmer.py +110 -0
- ipweave/board/_provenance.json +1701 -0
- ipweave/board/_registry.py +248 -0
- ipweave/board/adi_adrv2crr_fmc.py +594 -0
- ipweave/board/adi_plutosdr.py +57 -0
- ipweave/board/alchitry_au.py +252 -0
- ipweave/board/alchitry_cu.py +191 -0
- ipweave/board/alchitry_mojo.py +85 -0
- ipweave/board/alchitry_ptv2.py +740 -0
- ipweave/board/alibaba_vu13p.py +319 -0
- ipweave/board/alibaba_xcku3p.py +183 -0
- ipweave/board/aliexpress_xc7k420t.py +114 -0
- ipweave/board/aliexpress_xc7k70t.py +243 -0
- ipweave/board/alinx_ax7010.py +237 -0
- ipweave/board/alinx_ax7020.py +190 -0
- ipweave/board/alinx_ax7203.py +242 -0
- ipweave/board/alinx_ax7325b.py +323 -0
- ipweave/board/alinx_axau15.py +262 -0
- ipweave/board/alinx_axu2cga.py +179 -0
- ipweave/board/arrow_deca.py +218 -0
- ipweave/board/arty_a7.py +949 -0
- ipweave/board/arty_s7.py +780 -0
- ipweave/board/arty_z7.py +220 -0
- ipweave/board/atlys.py +387 -0
- ipweave/board/avnet_aesku40.py +100 -0
- ipweave/board/berkeleylab_marble.py +341 -0
- ipweave/board/berkeleylab_obsidian.py +229 -0
- ipweave/board/blackice.py +185 -0
- ipweave/board/blackice_ii.py +188 -0
- ipweave/board/bochenjingxin_kintex7_basec.py +84 -0
- ipweave/board/butterstick.py +336 -0
- ipweave/board/camlink_4k.py +65 -0
- ipweave/board/chameleon96.py +134 -0
- ipweave/board/cmod_a7.py +441 -0
- ipweave/board/cmod_s7.py +155 -0
- ipweave/board/colorlight_5a75b_r7_0.py +250 -0
- ipweave/board/colorlight_i9plus.py +300 -0
- ipweave/board/cora_z7.py +452 -0
- ipweave/board/de0.py +347 -0
- ipweave/board/de0_cv.py +344 -0
- ipweave/board/de0nano.py +226 -0
- ipweave/board/de10_lite.py +303 -0
- ipweave/board/de10_nano.py +249 -0
- ipweave/board/de1_soc.py +293 -0
- ipweave/board/decklink_intensity_pro_4k.py +72 -0
- ipweave/board/decklink_mini_4k.py +139 -0
- ipweave/board/decklink_quad_hdmi_recorder.py +159 -0
- ipweave/board/designs.py +239 -0
- ipweave/board/digilent_arty_z7.py +170 -0
- ipweave/board/digilent_netfpga_sume.py +280 -0
- ipweave/board/digilent_nexys4.py +421 -0
- ipweave/board/digilent_nexys_video.py +405 -0
- ipweave/board/digilent_pynq_z1.py +262 -0
- ipweave/board/digilent_zedboard.py +337 -0
- ipweave/board/digilent_zybo_z7.py +132 -0
- ipweave/board/ebaz4205.py +59 -0
- ipweave/board/ecp5_5g_evn.py +442 -0
- ipweave/board/ecpix5.py +698 -0
- ipweave/board/efinix_t120f324_kit.py +59 -0
- ipweave/board/efinix_t120f576_kit.py +67 -0
- ipweave/board/efinix_t20f256_kit.py +67 -0
- ipweave/board/efinix_t8f81_kit.py +63 -0
- ipweave/board/efinix_ti180j484_kit.py +67 -0
- ipweave/board/efinix_ti375c529_kit.py +63 -0
- ipweave/board/efinix_ti375n1156_kit.py +67 -0
- ipweave/board/efinix_ti60f225_kit.py +67 -0
- ipweave/board/efinix_tz170j484_kit.py +67 -0
- ipweave/board/ego1.py +290 -0
- ipweave/board/embedfire_rise_pro.py +335 -0
- ipweave/board/enclustra_mercury_kx2.py +348 -0
- ipweave/board/enclustra_mercury_xu5.py +96 -0
- ipweave/board/extensions/__init__.py +0 -0
- ipweave/board/extensions/pmod.py +94 -0
- ipweave/board/fairwaves_xtrx.py +168 -0
- ipweave/board/fomu_hacker.py +109 -0
- ipweave/board/fomu_pvt.py +88 -0
- ipweave/board/fpc_iii.py +159 -0
- ipweave/board/fpgawars_alhambra2.py +147 -0
- ipweave/board/gadgetfactory_papilio_pro.py +128 -0
- ipweave/board/genesys2.py +566 -0
- ipweave/board/hseda_xc7a35t.py +202 -0
- ipweave/board/hyvision_pcie_opt01_revf.py +313 -0
- ipweave/board/ice40_hx1k_blink_evn.py +132 -0
- ipweave/board/ice40_hx8k_b_evn.py +233 -0
- ipweave/board/ice40_up5k_b_evn.py +161 -0
- ipweave/board/icebreaker.py +150 -0
- ipweave/board/icebreaker_bitsy.py +175 -0
- ipweave/board/icepi_zero.py +207 -0
- ipweave/board/icestick.py +124 -0
- ipweave/board/icesugar.py +154 -0
- ipweave/board/icesugar_nano.py +89 -0
- ipweave/board/icesugar_pro.py +251 -0
- ipweave/board/isx_im1283.py +112 -0
- ipweave/board/kc705.py +83 -0
- ipweave/board/kcu105.py +78 -0
- ipweave/board/kosagi_fomu_evt.py +111 -0
- ipweave/board/kosagi_netv2.py +203 -0
- ipweave/board/krtkl_snickerdoodle.py +210 -0
- ipweave/board/lambdaconcept_pcie_screamer.py +100 -0
- ipweave/board/lambdaconcept_pcie_screamer_m2.py +85 -0
- ipweave/board/lattice_ecp5_vip.py +170 -0
- ipweave/board/limesdr_xtrx.py +173 -0
- ipweave/board/linsn_rv901t.py +186 -0
- ipweave/board/logicbone.py +427 -0
- ipweave/board/machdyne_krote.py +94 -0
- ipweave/board/machxo2_breakout.py +335 -0
- ipweave/board/machxo3_sk.py +708 -0
- ipweave/board/mercury.py +264 -0
- ipweave/board/micronova_mercury2.py +186 -0
- ipweave/board/microphase_a7_lite.py +220 -0
- ipweave/board/microzed_z010.py +153 -0
- ipweave/board/microzed_z020.py +168 -0
- ipweave/board/mist.py +86 -0
- ipweave/board/mister.py +308 -0
- ipweave/board/mlk_cu07_ku15p.py +122 -0
- ipweave/board/mnt_rkx7.py +191 -0
- ipweave/board/myir_myc_j7a100t.py +249 -0
- ipweave/board/nandland_go.py +118 -0
- ipweave/board/newae_cw305.py +109 -0
- ipweave/board/nexys4ddr.py +420 -0
- ipweave/board/nitefury.py +340 -0
- ipweave/board/numato_aller.py +145 -0
- ipweave/board/numato_mimas.py +171 -0
- ipweave/board/numato_mimas_a7.py +364 -0
- ipweave/board/numato_nereid.py +332 -0
- ipweave/board/numato_tagus.py +291 -0
- ipweave/board/ocp_tap_timecard.py +183 -0
- ipweave/board/opalkelly_xem8320.py +492 -0
- ipweave/board/opensourcesdrlab_kintex7.py +286 -0
- ipweave/board/orangecrab_r0_1.py +176 -0
- ipweave/board/orangecrab_r0_2.py +565 -0
- ipweave/board/pano_logic_g2.py +136 -0
- ipweave/board/qmtech_kintex7_devboard.py +191 -0
- ipweave/board/qmtech_xc7a35t.py +175 -0
- ipweave/board/qmtech_xc7k325t.py +183 -0
- ipweave/board/qwertyembedded_beaglewire.py +116 -0
- ipweave/board/redpitaya.py +118 -0
- ipweave/board/redpitaya_125_14.py +111 -0
- ipweave/board/resources/__init__.py +4 -0
- ipweave/board/resources/display.py +36 -0
- ipweave/board/resources/interface.py +144 -0
- ipweave/board/resources/memory.py +240 -0
- ipweave/board/resources/user.py +43 -0
- ipweave/board/rfsoc4x2.py +264 -0
- ipweave/board/rz_easyfpga_a2_2.py +246 -0
- ipweave/board/saanlima_pipistrello.py +206 -0
- ipweave/board/seeedstudio_spartan_edge_accelerator.py +123 -0
- ipweave/board/siglent_sds1104xe.py +100 -0
- ipweave/board/signaloid_c0_microsd.py +87 -0
- ipweave/board/sk_xc6slx9.py +160 -0
- ipweave/board/sqrl_fk33.py +119 -0
- ipweave/board/stepmxo2.py +207 -0
- ipweave/board/supercon19badge.py +329 -0
- ipweave/board/tang_mega_138k_pro_dock.py +123 -0
- ipweave/board/tang_nano.py +63 -0
- ipweave/board/tang_nano_9k.py +147 -0
- ipweave/board/tang_primer_20k.py +921 -0
- ipweave/board/te0714_03_50_2I.py +238 -0
- ipweave/board/test/__init__.py +0 -0
- ipweave/board/test/blinky.py +51 -0
- ipweave/board/tinyfpga_ax1.py +50 -0
- ipweave/board/tinyfpga_ax2.py +50 -0
- ipweave/board/tinyfpga_bx.py +109 -0
- ipweave/board/trenz_mega65.py +75 -0
- ipweave/board/trenz_s7mini.py +79 -0
- ipweave/board/trenz_te0710.py +59 -0
- ipweave/board/trenz_te0711.py +63 -0
- ipweave/board/trenz_te0725.py +160 -0
- ipweave/board/trenz_te0741.py +67 -0
- ipweave/board/trenz_te0890.py +132 -0
- ipweave/board/tul_pynq_z2.py +101 -0
- ipweave/board/ulx3s.py +1478 -0
- ipweave/board/upduino_v1.py +112 -0
- ipweave/board/upduino_v2.py +116 -0
- ipweave/board/upduino_v3.py +122 -0
- ipweave/board/versa_ecp5.py +329 -0
- ipweave/board/versa_ecp5_5g.py +279 -0
- ipweave/board/xilinx_ac701.py +426 -0
- ipweave/board/xilinx_alveo_u280.py +179 -0
- ipweave/board/xilinx_kc705.py +580 -0
- ipweave/board/xilinx_kcu105.py +600 -0
- ipweave/board/xilinx_kcu116.py +426 -0
- ipweave/board/xilinx_kv260.py +50 -0
- ipweave/board/xilinx_sp605.py +323 -0
- ipweave/board/xilinx_vc707.py +707 -0
- ipweave/board/xilinx_vcu128.py +441 -0
- ipweave/board/xilinx_zc706.py +430 -0
- ipweave/board/xilinx_zcu102.py +534 -0
- ipweave/board/xilinx_zcu216.py +257 -0
- ipweave/board/ypcb_00338_1p1.py +145 -0
- ipweave/board/ztex213.py +53 -0
- ipweave/board/zturn_lite_z007s.py +116 -0
- ipweave/board/zturn_lite_z010.py +116 -0
- ipweave/build/__init__.py +3 -0
- ipweave/build/dsl.py +283 -0
- ipweave/build/plat.py +442 -0
- ipweave/build/res.py +317 -0
- ipweave/build/run.py +315 -0
- ipweave/bus/__init__.py +108 -0
- ipweave/bus/_expr.py +121 -0
- ipweave/bus/binding/__init__.py +100 -0
- ipweave/bus/binding/ahb.py +153 -0
- ipweave/bus/binding/apb4.py +106 -0
- ipweave/bus/binding/axi4.py +211 -0
- ipweave/bus/binding/axi4_lite.py +161 -0
- ipweave/bus/binding/base.py +327 -0
- ipweave/bus/binding/obi.py +56 -0
- ipweave/bus/binding/stream.py +171 -0
- ipweave/bus/binding/tilelink_uh.py +197 -0
- ipweave/bus/binding/tilelink_ul.py +156 -0
- ipweave/bus/binding/wishbone.py +99 -0
- ipweave/bus/checker.py +203 -0
- ipweave/bus/core.py +162 -0
- ipweave/bus/model.py +417 -0
- ipweave/bus/spec.py +580 -0
- ipweave/bus/specs/ahb.toml +218 -0
- ipweave/bus/specs/apb4.toml +76 -0
- ipweave/bus/specs/axi4.toml +218 -0
- ipweave/bus/specs/axi4_lite.toml +229 -0
- ipweave/bus/specs/axi_stream.toml +131 -0
- ipweave/bus/specs/decoupled.toml +36 -0
- ipweave/bus/specs/obi.toml +88 -0
- ipweave/bus/specs/tilelink_uh.toml +277 -0
- ipweave/bus/specs/tilelink_ul.toml +216 -0
- ipweave/bus/specs/wishbone.toml +176 -0
- ipweave/check/__init__.py +127 -0
- ipweave/check/clocking.py +185 -0
- ipweave/check/connectivity.py +104 -0
- ipweave/check/depth.py +241 -0
- ipweave/check/domains.py +242 -0
- ipweave/check/fsm.py +196 -0
- ipweave/check/mbist.py +103 -0
- ipweave/check/netlist.py +91 -0
- ipweave/check/pipeline.py +138 -0
- ipweave/check/scan.py +117 -0
- ipweave/check/views.py +279 -0
- ipweave/check/xprop.py +68 -0
- ipweave/cleanroom/__init__.py +13 -0
- ipweave/cleanroom/_model.py +304 -0
- ipweave/cli.py +1215 -0
- ipweave/dft/__init__.py +13 -0
- ipweave/dft/_model.py +195 -0
- ipweave/dft/ijtag.py +273 -0
- ipweave/dft/mbist.py +163 -0
- ipweave/dft/tap.py +178 -0
- ipweave/emit/__init__.py +0 -0
- ipweave/emit/cxxrtl.py +40 -0
- ipweave/emit/ipxact.py +443 -0
- ipweave/emit/ipxact_schemas/PROVENANCE.json +37 -0
- ipweave/emit/ipxact_schemas/abstractionDefinition.xsd +302 -0
- ipweave/emit/ipxact_schemas/abstractor.xsd +165 -0
- ipweave/emit/ipxact_schemas/autoConfigure.xsd +109 -0
- ipweave/emit/ipxact_schemas/busDefinition.xsd +114 -0
- ipweave/emit/ipxact_schemas/busInterface.xsd +591 -0
- ipweave/emit/ipxact_schemas/catalog.xsd +79 -0
- ipweave/emit/ipxact_schemas/commonStructures.xsd +1134 -0
- ipweave/emit/ipxact_schemas/component.xsd +450 -0
- ipweave/emit/ipxact_schemas/constraints.xsd +261 -0
- ipweave/emit/ipxact_schemas/design.xsd +73 -0
- ipweave/emit/ipxact_schemas/designConfig.xsd +187 -0
- ipweave/emit/ipxact_schemas/file.xsd +467 -0
- ipweave/emit/ipxact_schemas/fileType.xsd +88 -0
- ipweave/emit/ipxact_schemas/generator.xsd +286 -0
- ipweave/emit/ipxact_schemas/identifier.xsd +102 -0
- ipweave/emit/ipxact_schemas/memoryMap.xsd +1862 -0
- ipweave/emit/ipxact_schemas/model.xsd +372 -0
- ipweave/emit/ipxact_schemas/port.xsd +1161 -0
- ipweave/emit/ipxact_schemas/signalDrivers.xsd +221 -0
- ipweave/emit/ipxact_schemas/simpleTypes.xsd +286 -0
- ipweave/emit/ipxact_schemas/subInstances.xsd +376 -0
- ipweave/emit/ipxact_schemas/typeDefinitions.xsd +198 -0
- ipweave/emit/ipxact_schemas/xml.xsd +24 -0
- ipweave/emit/rtlil.py +1306 -0
- ipweave/emit/sdc.py +189 -0
- ipweave/emit/sv/__init__.py +26 -0
- ipweave/emit/sv/_emit.py +1237 -0
- ipweave/emit/sv/_expr.py +554 -0
- ipweave/emit/sv/_ports.py +208 -0
- ipweave/emit/sv/_raise.py +125 -0
- ipweave/emit/sv/_writer.py +227 -0
- ipweave/emit/upf.py +139 -0
- ipweave/emit/verilog.py +62 -0
- ipweave/flow/__init__.py +8 -0
- ipweave/flow/graph.py +280 -0
- ipweave/hdl/__init__.py +40 -0
- ipweave/hdl/_ast.py +3272 -0
- ipweave/hdl/_cd.py +93 -0
- ipweave/hdl/_dsl.py +702 -0
- ipweave/hdl/_ir.py +1804 -0
- ipweave/hdl/_mem.py +273 -0
- ipweave/hdl/_nir.py +1498 -0
- ipweave/hdl/_time.py +252 -0
- ipweave/hdl/_xfrm.py +701 -0
- ipweave/ip/__init__.py +15 -0
- ipweave/ip/cdc/__init__.py +43 -0
- ipweave/ip/cdc/handshake.py +215 -0
- ipweave/ip/cdc/stream.py +123 -0
- ipweave/ip/datapath/__init__.py +34 -0
- ipweave/ip/datapath/divide.py +191 -0
- ipweave/ip/datapath/multiply.py +201 -0
- ipweave/ip/datapath/prefix.py +210 -0
- ipweave/ip/datapath/reduce.py +135 -0
- ipweave/ip/datapath/shift.py +231 -0
- ipweave/ip/datapath/storage.py +233 -0
- ipweave/ip/flow/__init__.py +34 -0
- ipweave/ip/flow/arbiter.py +195 -0
- ipweave/ip/flow/buffer.py +190 -0
- ipweave/ip/flow/crossbar.py +159 -0
- ipweave/lib/__init__.py +0 -0
- ipweave/lib/cdc.py +282 -0
- ipweave/lib/crc/__init__.py +362 -0
- ipweave/lib/crc/catalog.py +911 -0
- ipweave/lib/data.py +1437 -0
- ipweave/lib/enum.py +416 -0
- ipweave/lib/fifo.py +593 -0
- ipweave/lib/io.py +1155 -0
- ipweave/lib/memory.py +462 -0
- ipweave/lib/meta.py +155 -0
- ipweave/lib/stream.py +125 -0
- ipweave/lib/wiring.py +1996 -0
- ipweave/licence.py +168 -0
- ipweave/params.py +228 -0
- ipweave/phys.py +332 -0
- ipweave/pipeline.py +344 -0
- ipweave/platform/__init__.py +68 -0
- ipweave/platform/_altera.py +83 -0
- ipweave/platform/_common.py +80 -0
- ipweave/platform/_efinix.py +296 -0
- ipweave/platform/_microchip.py +198 -0
- ipweave/platform/_registry.py +304 -0
- ipweave/platform/_run.py +63 -0
- ipweave/platform/asic.py +306 -0
- ipweave/plugin.py +319 -0
- ipweave/power.py +386 -0
- ipweave/regs/__init__.py +49 -0
- ipweave/regs/block.py +296 -0
- ipweave/regs/cheader.py +138 -0
- ipweave/regs/manual.py +171 -0
- ipweave/regs/model.py +429 -0
- ipweave/regs/ral.py +176 -0
- ipweave/regs/rdl.py +442 -0
- ipweave/rpc.py +114 -0
- ipweave/rules/__init__.py +900 -0
- ipweave/serve/__init__.py +13 -0
- ipweave/serve/_protocol.py +140 -0
- ipweave/serve/_tools.py +242 -0
- ipweave/sim/__init__.py +13 -0
- ipweave/sim/_async.py +782 -0
- ipweave/sim/_base.py +101 -0
- ipweave/sim/_pyclock.py +37 -0
- ipweave/sim/_pycoro.py +129 -0
- ipweave/sim/_pyeval.py +231 -0
- ipweave/sim/_pyrtl.py +628 -0
- ipweave/sim/core.py +486 -0
- ipweave/sim/pysim.py +731 -0
- ipweave/spec/__init__.py +21 -0
- ipweave/spec/_model.py +259 -0
- ipweave/spec/documents.py +244 -0
- ipweave/strict.py +138 -0
- ipweave/tech/__init__.py +27 -0
- ipweave/tech/_model.py +454 -0
- ipweave/timing.py +432 -0
- ipweave/trace.py +291 -0
- ipweave/tracer.py +77 -0
- ipweave/utils.py +40 -0
- ipweave/vendor/__init__.py +46 -0
- ipweave/vendor/_altera.py +531 -0
- ipweave/vendor/_gowin.py +584 -0
- ipweave/vendor/_lattice.py +1062 -0
- ipweave/vendor/_quicklogic.py +191 -0
- ipweave/vendor/_siliconblue.py +595 -0
- ipweave/vendor/_xilinx.py +1310 -0
- ipweave/verif/__init__.py +10 -0
- ipweave/verif/cosim.py +417 -0
- ipweave/verif/cover.py +307 -0
- ipweave/verif/equiv.py +194 -0
- ipweave/verif/formal.py +286 -0
- ipweave/verif/golden.py +202 -0
- ipweave/verif/lint.py +258 -0
- ipweave/verif/regression.py +195 -0
- ipweave/verif/tools.py +198 -0
- ipweave-0.1.0.dist-info/METADATA +265 -0
- ipweave-0.1.0.dist-info/RECORD +403 -0
- ipweave-0.1.0.dist-info/WHEEL +5 -0
- ipweave-0.1.0.dist-info/entry_points.txt +5 -0
- ipweave-0.1.0.dist-info/licenses/LICENSE +202 -0
- ipweave-0.1.0.dist-info/licenses/LICENSE.amaranth.txt +21 -0
- ipweave-0.1.0.dist-info/licenses/NOTICE +113 -0
- ipweave-0.1.0.dist-info/top_level.txt +1 -0
ipweave/__init__.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Extract version for this package from the environment package metadata. This used to be a lot
|
|
2
|
+
# more difficult in earlier Python versions, and the `__version__` field is a legacy of that time.
|
|
3
|
+
import importlib.metadata
|
|
4
|
+
try:
|
|
5
|
+
__version__ = importlib.metadata.version(__package__)
|
|
6
|
+
except importlib.metadata.PackageNotFoundError:
|
|
7
|
+
# No importlib metadata for this package. This shouldn't normally happen, but some people
|
|
8
|
+
# prefer not installing packages via pip at all. Although not recommended we still support it.
|
|
9
|
+
# A source checkout that was never installed. The literal is the fallback rather
|
|
10
|
+
# than the source of truth, so an installed distribution cannot disagree with itself -
|
|
11
|
+
# and the banner in every generated file quotes this, so "unknown" would end up
|
|
12
|
+
# stamped into a customer's RTL.
|
|
13
|
+
__version__ = "0.1.0"
|
|
14
|
+
del importlib
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
from .hdl import *
|
|
18
|
+
|
|
19
|
+
# must be kept in sync with docs/reference.rst!
|
|
20
|
+
__all__ = [
|
|
21
|
+
"Shape", "unsigned", "signed",
|
|
22
|
+
"Value", "Const", "C", "Mux", "Cat", "Array", "Signal", "ClockSignal", "ResetSignal",
|
|
23
|
+
"Format", "Print", "Assert",
|
|
24
|
+
"Module",
|
|
25
|
+
"ClockDomain",
|
|
26
|
+
"Elaboratable", "Fragment", "Instance",
|
|
27
|
+
"DomainRenamer", "ResetInserter", "EnableInserter",
|
|
28
|
+
]
|
ipweave/_legacy_cli.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
|
|
3
|
+
from .hdl._ir import Fragment
|
|
4
|
+
from .emit import rtlil, cxxrtl, verilog
|
|
5
|
+
from .sim import Simulator
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
__all__ = ["main"]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def main_parser(parser=None):
|
|
12
|
+
if parser is None:
|
|
13
|
+
parser = argparse.ArgumentParser()
|
|
14
|
+
|
|
15
|
+
p_action = parser.add_subparsers(dest="action")
|
|
16
|
+
|
|
17
|
+
p_generate = p_action.add_parser("generate",
|
|
18
|
+
help="generate RTLIL, Verilog or CXXRTL from the design")
|
|
19
|
+
p_generate.add_argument("-t", "--type", dest="generate_type",
|
|
20
|
+
metavar="LANGUAGE", choices=["il", "cc", "v"],
|
|
21
|
+
help="generate LANGUAGE (il for RTLIL, v for Verilog, cc for CXXRTL; default: file extension of FILE, if given)")
|
|
22
|
+
p_generate.add_argument("--no-src", dest="emit_src", default=True, action="store_false",
|
|
23
|
+
help="suppress generation of source location attributes")
|
|
24
|
+
p_generate.add_argument("generate_file",
|
|
25
|
+
metavar="FILE", type=str, nargs="?",
|
|
26
|
+
help="write generated code to FILE")
|
|
27
|
+
|
|
28
|
+
p_simulate = p_action.add_parser(
|
|
29
|
+
"simulate", help="simulate the design")
|
|
30
|
+
p_simulate.add_argument("-v", "--vcd-file",
|
|
31
|
+
metavar="VCD-FILE", type=str,
|
|
32
|
+
help="write execution trace to VCD-FILE")
|
|
33
|
+
p_simulate.add_argument("-w", "--gtkw-file",
|
|
34
|
+
metavar="GTKW-FILE", type=str,
|
|
35
|
+
help="write GTKWave configuration to GTKW-FILE")
|
|
36
|
+
p_simulate.add_argument("-p", "--period", dest="sync_period",
|
|
37
|
+
metavar="TIME", type=float, default=1e-6,
|
|
38
|
+
help="set 'sync' clock domain period to TIME (default: %(default)s)")
|
|
39
|
+
p_simulate.add_argument("-c", "--clocks", dest="sync_clocks",
|
|
40
|
+
metavar="COUNT", type=int, required=True,
|
|
41
|
+
help="simulate for COUNT 'sync' clock periods")
|
|
42
|
+
|
|
43
|
+
return parser
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def main_runner(parser, args, design, platform=None, name="top", ports=None):
|
|
47
|
+
if args.action == "generate":
|
|
48
|
+
generate_type = args.generate_type
|
|
49
|
+
if generate_type is None and args.generate_file:
|
|
50
|
+
if args.generate_file.endswith(".il"):
|
|
51
|
+
generate_type = "il"
|
|
52
|
+
if args.generate_file.endswith(".cc"):
|
|
53
|
+
generate_type = "cc"
|
|
54
|
+
if args.generate_file.endswith(".v"):
|
|
55
|
+
generate_type = "v"
|
|
56
|
+
if generate_type is None:
|
|
57
|
+
parser.error("Unable to auto-detect language, specify explicitly with -t/--type")
|
|
58
|
+
if generate_type == "il":
|
|
59
|
+
output = rtlil.convert(design, platform=platform, name=name, ports=ports, emit_src=args.emit_src)
|
|
60
|
+
if generate_type == "cc":
|
|
61
|
+
output = cxxrtl.convert(design, platform=platform, name=name, ports=ports, emit_src=args.emit_src)
|
|
62
|
+
if generate_type == "v":
|
|
63
|
+
output = verilog.convert(design, platform=platform, name=name, ports=ports, emit_src=args.emit_src)
|
|
64
|
+
if args.generate_file:
|
|
65
|
+
with open(args.generate_file, "w") as f:
|
|
66
|
+
f.write(output)
|
|
67
|
+
else:
|
|
68
|
+
print(output)
|
|
69
|
+
|
|
70
|
+
if args.action == "simulate":
|
|
71
|
+
fragment = Fragment.get(design, platform)
|
|
72
|
+
sim = Simulator(fragment)
|
|
73
|
+
sim.add_clock(args.sync_period)
|
|
74
|
+
with sim.write_vcd(vcd_file=args.vcd_file, gtkw_file=args.gtkw_file, traces=ports):
|
|
75
|
+
sim.run_until(args.sync_period * args.sync_clocks, run_passive=True)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def main(*args, **kwargs):
|
|
79
|
+
parser = main_parser()
|
|
80
|
+
main_runner(parser, parser.parse_args(), *args, **kwargs)
|
ipweave/_loc.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Source locations, and why every diagnostic carries one.
|
|
2
|
+
|
|
3
|
+
The language records a ``(filename, lineno)`` tuple on every value and statement it
|
|
4
|
+
builds. That tuple is the difference between "assignment width mismatch" and "assignment
|
|
5
|
+
width mismatch at counter.py:31", and the second is the only one anybody can act on.
|
|
6
|
+
|
|
7
|
+
Copyright 2026 IPweave contributors. SPDX-License-Identifier: Apache-2.0
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
__all__ = ["Loc", "UNKNOWN", "loc_of"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass(frozen=True, slots=True)
|
|
19
|
+
class Loc:
|
|
20
|
+
file: str
|
|
21
|
+
line: int
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def short(self) -> str:
|
|
25
|
+
if not self.file:
|
|
26
|
+
return "<unknown>"
|
|
27
|
+
return f"{Path(self.file).name}:{self.line}"
|
|
28
|
+
|
|
29
|
+
def __str__(self) -> str:
|
|
30
|
+
return self.short
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
UNKNOWN = Loc("", 0)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def loc_of(obj) -> Loc:
|
|
37
|
+
"""The location recorded on a value, statement or fragment.
|
|
38
|
+
|
|
39
|
+
Returns :data:`UNKNOWN` rather than raising when there is none: a diagnostic with a
|
|
40
|
+
weak location is still worth printing, and a crash inside the error path replaces a
|
|
41
|
+
real problem with an unrelated one.
|
|
42
|
+
"""
|
|
43
|
+
src = getattr(obj, "src_loc", None)
|
|
44
|
+
if isinstance(src, tuple) and len(src) == 2 and isinstance(src[1], int):
|
|
45
|
+
return Loc(src[0] or "", src[1])
|
|
46
|
+
return UNKNOWN
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import shutil
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
__all__ = ["ToolNotFound", "tool_env_var", "has_tool", "require_tool"]
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ToolNotFound(Exception):
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def tool_env_var(name):
|
|
13
|
+
return name.upper().replace("-", "_").replace("+", "X")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _get_tool(name):
|
|
17
|
+
return os.environ.get(tool_env_var(name), name)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def has_tool(name):
|
|
21
|
+
return shutil.which(_get_tool(name)) is not None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def require_tool(name):
|
|
25
|
+
env_var = tool_env_var(name)
|
|
26
|
+
path = _get_tool(name)
|
|
27
|
+
if shutil.which(path) is None:
|
|
28
|
+
if env_var in os.environ:
|
|
29
|
+
raise ToolNotFound("Could not find required tool {} in {} as "
|
|
30
|
+
"specified via the {} environment variable".
|
|
31
|
+
format(name, path, env_var))
|
|
32
|
+
else:
|
|
33
|
+
raise ToolNotFound("Could not find required tool {} in PATH. Place "
|
|
34
|
+
"it directly in PATH or specify path explicitly "
|
|
35
|
+
"via the {} environment variable".
|
|
36
|
+
format(name, env_var))
|
|
37
|
+
return path
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import re
|
|
4
|
+
import subprocess
|
|
5
|
+
import warnings
|
|
6
|
+
import pathlib
|
|
7
|
+
import importlib.metadata
|
|
8
|
+
import importlib.resources
|
|
9
|
+
|
|
10
|
+
from . import has_tool, require_tool
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
__all__ = ["YosysError", "YosysBinary", "find_yosys"]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class YosysError(Exception):
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class YosysWarning(Warning):
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class YosysBinary:
|
|
25
|
+
@classmethod
|
|
26
|
+
def available(cls):
|
|
27
|
+
"""Check for Yosys availability.
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
-------
|
|
31
|
+
available : bool
|
|
32
|
+
``True`` if Yosys is installed, ``False`` otherwise. Installed binary may still not
|
|
33
|
+
be runnable, or might be too old to be useful.
|
|
34
|
+
"""
|
|
35
|
+
raise NotImplementedError
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def version(cls):
|
|
39
|
+
"""Get Yosys version.
|
|
40
|
+
|
|
41
|
+
Returns
|
|
42
|
+
-------
|
|
43
|
+
``None`` if version number could not be determined, or a 3-tuple ``(major, minor, distance)`` if it could.
|
|
44
|
+
|
|
45
|
+
major : int
|
|
46
|
+
Major version.
|
|
47
|
+
minor : int
|
|
48
|
+
Minor version.
|
|
49
|
+
distance : int
|
|
50
|
+
Distance to last tag per ``git describe``. May not be exact for system Yosys.
|
|
51
|
+
"""
|
|
52
|
+
raise NotImplementedError
|
|
53
|
+
|
|
54
|
+
@classmethod
|
|
55
|
+
def data_dir(cls):
|
|
56
|
+
"""Get Yosys data directory.
|
|
57
|
+
|
|
58
|
+
Returns
|
|
59
|
+
-------
|
|
60
|
+
data_dir : pathlib.Path
|
|
61
|
+
Yosys data directory (also known as "datdir").
|
|
62
|
+
"""
|
|
63
|
+
raise NotImplementedError
|
|
64
|
+
|
|
65
|
+
@classmethod
|
|
66
|
+
def run(cls, args, stdin=""):
|
|
67
|
+
"""Run Yosys process.
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
args : list of str
|
|
72
|
+
Arguments, not including the program name.
|
|
73
|
+
stdin : str
|
|
74
|
+
Standard input.
|
|
75
|
+
|
|
76
|
+
Returns
|
|
77
|
+
-------
|
|
78
|
+
stdout : str
|
|
79
|
+
Standard output.
|
|
80
|
+
|
|
81
|
+
Exceptions
|
|
82
|
+
----------
|
|
83
|
+
YosysError
|
|
84
|
+
Raised if Yosys returns a non-zero code. The exception message is the standard error
|
|
85
|
+
output.
|
|
86
|
+
"""
|
|
87
|
+
raise NotImplementedError
|
|
88
|
+
|
|
89
|
+
@classmethod
|
|
90
|
+
def _process_result(cls, returncode, stdout, stderr, ignore_warnings, src_loc_at):
|
|
91
|
+
if returncode:
|
|
92
|
+
raise YosysError(stderr.strip())
|
|
93
|
+
if not ignore_warnings:
|
|
94
|
+
for match in re.finditer(r"(?ms:^Warning: (.+)\n$)", stderr):
|
|
95
|
+
message = match.group(1).replace("\n", " ")
|
|
96
|
+
warnings.warn(message, YosysWarning, stacklevel=3 + src_loc_at)
|
|
97
|
+
return stdout
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class _BuiltinYosys(YosysBinary):
|
|
101
|
+
YOSYS_PACKAGE = "amaranth_yosys"
|
|
102
|
+
|
|
103
|
+
@classmethod
|
|
104
|
+
def available(cls):
|
|
105
|
+
try:
|
|
106
|
+
importlib.metadata.version(cls.YOSYS_PACKAGE)
|
|
107
|
+
return True
|
|
108
|
+
except importlib.metadata.PackageNotFoundError:
|
|
109
|
+
return False
|
|
110
|
+
|
|
111
|
+
@classmethod
|
|
112
|
+
def version(cls):
|
|
113
|
+
version = importlib.metadata.version(cls.YOSYS_PACKAGE)
|
|
114
|
+
match = re.match(r"^(\d+)\.(\d+)\.(?:\d+)(?:\.(\d+))?(?:\.post(\d+))?", version)
|
|
115
|
+
return (int(match[1]), int(match[2]), int(match[3] or 0), int(match[4] or 0))
|
|
116
|
+
|
|
117
|
+
@classmethod
|
|
118
|
+
def data_dir(cls):
|
|
119
|
+
return importlib.resources.files(cls.YOSYS_PACKAGE) / "share"
|
|
120
|
+
|
|
121
|
+
@classmethod
|
|
122
|
+
def run(cls, args, stdin="", *, ignore_warnings=False, src_loc_at=0):
|
|
123
|
+
popen = subprocess.Popen([sys.executable, "-m", cls.YOSYS_PACKAGE, *args],
|
|
124
|
+
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
125
|
+
encoding="utf-8")
|
|
126
|
+
stdout, stderr = popen.communicate(stdin)
|
|
127
|
+
return cls._process_result(popen.returncode, stdout, stderr, ignore_warnings, src_loc_at)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class _SystemYosys(YosysBinary):
|
|
131
|
+
YOSYS_BINARY = "yosys"
|
|
132
|
+
|
|
133
|
+
@classmethod
|
|
134
|
+
def available(cls):
|
|
135
|
+
return has_tool(cls.YOSYS_BINARY)
|
|
136
|
+
|
|
137
|
+
@classmethod
|
|
138
|
+
def version(cls):
|
|
139
|
+
version = cls.run(["-V"])
|
|
140
|
+
match = re.match(r"^Yosys (\d+)\.(\d+)(?:\+(\d+))?", version)
|
|
141
|
+
if match:
|
|
142
|
+
return (int(match[1]), int(match[2]), int(match[3] or 0))
|
|
143
|
+
else:
|
|
144
|
+
return None
|
|
145
|
+
|
|
146
|
+
@classmethod
|
|
147
|
+
def data_dir(cls):
|
|
148
|
+
popen = subprocess.Popen([require_tool(cls.YOSYS_BINARY) + "-config", "--datdir"],
|
|
149
|
+
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
150
|
+
encoding="utf-8")
|
|
151
|
+
stdout, stderr = popen.communicate()
|
|
152
|
+
if popen.returncode:
|
|
153
|
+
raise YosysError(stderr.strip())
|
|
154
|
+
return pathlib.Path(stdout.strip())
|
|
155
|
+
|
|
156
|
+
@classmethod
|
|
157
|
+
def run(cls, args, stdin="", *, ignore_warnings=False, src_loc_at=0):
|
|
158
|
+
popen = subprocess.Popen([require_tool(cls.YOSYS_BINARY), *args],
|
|
159
|
+
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
160
|
+
encoding="utf-8")
|
|
161
|
+
stdout, stderr = popen.communicate(stdin)
|
|
162
|
+
# If Yosys is built with an evaluation version of Verific, then Verific license
|
|
163
|
+
# information is printed first. It consists of empty lines and lines starting with `--`,
|
|
164
|
+
# which are not normally a part of Yosys output, and can be fairly safely removed.
|
|
165
|
+
#
|
|
166
|
+
# This is not ideal, but Verific license conditions rule out any other solution.
|
|
167
|
+
stdout = re.sub(r"\A(-- .+\n|\n)*", "", stdout)
|
|
168
|
+
return cls._process_result(popen.returncode, stdout, stderr, ignore_warnings, src_loc_at)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class _JavaScriptYosys(YosysBinary):
|
|
172
|
+
"""
|
|
173
|
+
This toolchain proxy is compatible with Pyodide_. The JavaScript environment must include
|
|
174
|
+
the following function:
|
|
175
|
+
|
|
176
|
+
.. code::
|
|
177
|
+
|
|
178
|
+
runAmaranthYosys(args: string[], stdin: string): (exit_code: int, stdout: string, stderr: string);
|
|
179
|
+
|
|
180
|
+
.. _Pyodide: https://pyodide.org/
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
@classmethod
|
|
184
|
+
def available(cls):
|
|
185
|
+
try:
|
|
186
|
+
return hasattr(__import__("js"), "runAmaranthYosys")
|
|
187
|
+
except ImportError:
|
|
188
|
+
return False
|
|
189
|
+
|
|
190
|
+
@classmethod
|
|
191
|
+
def version(cls):
|
|
192
|
+
version = cls.run(["-V"])
|
|
193
|
+
match = re.match(r"^Yosys (\d+)\.(\d+)(?:\+(\d+))?", version)
|
|
194
|
+
if match:
|
|
195
|
+
return (int(match[1]), int(match[2]), int(match[3] or 0))
|
|
196
|
+
else:
|
|
197
|
+
return None
|
|
198
|
+
|
|
199
|
+
@classmethod
|
|
200
|
+
def data_dir(cls):
|
|
201
|
+
# Not yet clear how this could work in a design with Wasm components. Most likely,
|
|
202
|
+
# the component would have to export its filesystem wholesale, and this method would
|
|
203
|
+
# return some kind of non-filesystem path-like object.
|
|
204
|
+
raise NotImplementedError
|
|
205
|
+
|
|
206
|
+
@classmethod
|
|
207
|
+
def run(cls, args, stdin="", *, ignore_warnings=False, src_loc_at=0):
|
|
208
|
+
exit_code, stdout, stderr = __import__("js").runAmaranthYosys(args, stdin)
|
|
209
|
+
return cls._process_result(exit_code, stdout, stderr, ignore_warnings, src_loc_at)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def find_yosys(requirement):
|
|
213
|
+
"""Find an available Yosys executable of required version.
|
|
214
|
+
|
|
215
|
+
Parameters
|
|
216
|
+
----------
|
|
217
|
+
requirement : function
|
|
218
|
+
Version check. Should return ``True`` if the version is acceptable, ``False`` otherwise.
|
|
219
|
+
|
|
220
|
+
Returns
|
|
221
|
+
-------
|
|
222
|
+
yosys_binary : subclass of YosysBinary
|
|
223
|
+
Proxy for running the requested version of Yosys.
|
|
224
|
+
|
|
225
|
+
Exceptions
|
|
226
|
+
----------
|
|
227
|
+
YosysError
|
|
228
|
+
Raised if required Yosys version is not found.
|
|
229
|
+
"""
|
|
230
|
+
proxies = []
|
|
231
|
+
_use_var = "IPWEAVE_USE_YOSYS" if "IPWEAVE_USE_YOSYS" in os.environ else "AMARANTH_USE_YOSYS"
|
|
232
|
+
clauses = os.environ.get(_use_var, "system,builtin").split(",")
|
|
233
|
+
for clause in clauses:
|
|
234
|
+
if clause == "builtin":
|
|
235
|
+
proxies.append(_BuiltinYosys)
|
|
236
|
+
elif clause == "system":
|
|
237
|
+
proxies.append(_SystemYosys)
|
|
238
|
+
elif clause == "javascript":
|
|
239
|
+
proxies.append(_JavaScriptYosys)
|
|
240
|
+
else:
|
|
241
|
+
raise YosysError(f"The {_use_var} environment variable contains "
|
|
242
|
+
"an unrecognized clause {!r}"
|
|
243
|
+
.format(clause))
|
|
244
|
+
for proxy in proxies:
|
|
245
|
+
if proxy.available():
|
|
246
|
+
version = proxy.version()
|
|
247
|
+
if version is not None and requirement(version):
|
|
248
|
+
return proxy
|
|
249
|
+
else:
|
|
250
|
+
if "AMARANTH_USE_YOSYS" in os.environ or "IPWEAVE_USE_YOSYS" in os.environ:
|
|
251
|
+
raise YosysError("Could not find an acceptable Yosys binary. Searched: {}"
|
|
252
|
+
.format(", ".join(clauses)))
|
|
253
|
+
else:
|
|
254
|
+
raise YosysError("Could not find an acceptable Yosys binary. The `amaranth-yosys` PyPI "
|
|
255
|
+
"package, if available for this platform, can be used as fallback")
|
ipweave/_tree.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Reductions written as balanced trees of named signals.
|
|
2
|
+
|
|
3
|
+
A flat ``a | b | c | d | e | f | g | h`` is correct, and it emits as one line that grows
|
|
4
|
+
with the operand count until ``IPW-E016`` reports it - which is the rule doing its job,
|
|
5
|
+
because the fix belongs in the generator rather than in the printer's line wrapping.
|
|
6
|
+
|
|
7
|
+
It is also worse RTL. A flat reduction leaves the association to synthesis, which will
|
|
8
|
+
usually build a tree and is under no obligation to; a tree built here is *stated*, its
|
|
9
|
+
depth is ``ceil(log2(n))`` by construction, and the intermediate names survive into the
|
|
10
|
+
output where somebody debugging a timing path can see them.
|
|
11
|
+
|
|
12
|
+
Copyright 2026 IPweave contributors. SPDX-License-Identifier: Apache-2.0
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from ipweave import Signal
|
|
18
|
+
|
|
19
|
+
__all__ = ["or_reduce", "and_reduce"]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _reduce(m, name: str, terms, combine, what: str):
|
|
23
|
+
level = list(terms)
|
|
24
|
+
if not level:
|
|
25
|
+
raise ValueError(f"{what} needs at least one term")
|
|
26
|
+
if len(level) == 1:
|
|
27
|
+
return level[0]
|
|
28
|
+
|
|
29
|
+
shape = level[0].shape()
|
|
30
|
+
stage = 0
|
|
31
|
+
while len(level) > 1:
|
|
32
|
+
nxt = []
|
|
33
|
+
for index in range(0, len(level), 2):
|
|
34
|
+
if index + 1 == len(level):
|
|
35
|
+
# An odd one out is carried to the next level rather than paired with an
|
|
36
|
+
# identity, which would add a level of logic to hide the asymmetry.
|
|
37
|
+
nxt.append(level[index])
|
|
38
|
+
continue
|
|
39
|
+
node = Signal(shape, name=f"{name}_l{stage}_{index // 2}")
|
|
40
|
+
m.d.comb += node.eq(combine(level[index], level[index + 1]))
|
|
41
|
+
nxt.append(node)
|
|
42
|
+
level = nxt
|
|
43
|
+
stage += 1
|
|
44
|
+
return level[0]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def or_reduce(m, name: str, terms):
|
|
48
|
+
"""Bitwise OR of ``terms``, as a balanced tree of named intermediates.
|
|
49
|
+
|
|
50
|
+
``terms`` may be any width, as long as they agree; the tree is built at the shape of
|
|
51
|
+
the first one. One term is returned unchanged rather than wrapped in a signal that
|
|
52
|
+
does nothing.
|
|
53
|
+
"""
|
|
54
|
+
return _reduce(m, name, terms, lambda a, b: a | b, "or_reduce")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def and_reduce(m, name: str, terms):
|
|
58
|
+
"""Bitwise AND of ``terms``, same shape and same reasoning as :func:`or_reduce`."""
|
|
59
|
+
return _reduce(m, name, terms, lambda a, b: a & b, "and_reduce")
|
ipweave/_unused.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import warnings
|
|
3
|
+
|
|
4
|
+
from ._utils import get_linter_option
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
__all__ = ["UnusedMustUse", "MustUse"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class UnusedMustUse(Warning):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class MustUse:
|
|
15
|
+
_MustUse__silence = False
|
|
16
|
+
_MustUse__warning = UnusedMustUse
|
|
17
|
+
|
|
18
|
+
def __new__(cls, *args, src_loc_at=0, **kwargs):
|
|
19
|
+
frame = sys._getframe(1 + src_loc_at)
|
|
20
|
+
self = super().__new__(cls)
|
|
21
|
+
self._MustUse__used = False
|
|
22
|
+
self._MustUse__context = dict(
|
|
23
|
+
filename=frame.f_code.co_filename,
|
|
24
|
+
lineno=frame.f_lineno,
|
|
25
|
+
source=self)
|
|
26
|
+
return self
|
|
27
|
+
|
|
28
|
+
def __del__(self):
|
|
29
|
+
if self._MustUse__silence:
|
|
30
|
+
return
|
|
31
|
+
if getattr(self._MustUse__warning, "_MustUse__silence", False):
|
|
32
|
+
return
|
|
33
|
+
if hasattr(self, "_MustUse__used") and not self._MustUse__used:
|
|
34
|
+
if get_linter_option(self._MustUse__context["filename"],
|
|
35
|
+
self._MustUse__warning.__qualname__, bool, True):
|
|
36
|
+
warnings.warn_explicit(
|
|
37
|
+
f"{self!r} created but never used", self._MustUse__warning,
|
|
38
|
+
**self._MustUse__context)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
_old_excepthook = sys.excepthook
|
|
42
|
+
def _silence_elaboratable(type, value, traceback):
|
|
43
|
+
# Don't show anything if the interpreter crashed; that'd just obscure the exception
|
|
44
|
+
# traceback instead of helping.
|
|
45
|
+
MustUse._MustUse__silence = True
|
|
46
|
+
_old_excepthook(type, value, traceback)
|
|
47
|
+
sys.excepthook = _silence_elaboratable
|
ipweave/_utils.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
import functools
|
|
3
|
+
import warnings
|
|
4
|
+
import linecache
|
|
5
|
+
import operator
|
|
6
|
+
import re
|
|
7
|
+
from collections.abc import Iterable
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
__all__ = ["to_binary", "flatten", "union", "final", "deprecated", "get_linter_options",
|
|
11
|
+
"get_linter_option"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def to_binary(n: int, width: int) -> str:
|
|
15
|
+
"""Formats ``n`` as exactly ``width`` binary digits, including when ``width`` is 0"""
|
|
16
|
+
n = operator.index(n)
|
|
17
|
+
width = operator.index(width)
|
|
18
|
+
if n not in range(1 << width):
|
|
19
|
+
raise ValueError(f"{n} does not fit in {width} bits")
|
|
20
|
+
if width == 0:
|
|
21
|
+
return ""
|
|
22
|
+
return f"{n:0{width}b}"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def flatten(i):
|
|
26
|
+
for e in i:
|
|
27
|
+
if isinstance(e, str) or not isinstance(e, Iterable):
|
|
28
|
+
yield e
|
|
29
|
+
else:
|
|
30
|
+
yield from flatten(e)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def union(i, start=None):
|
|
34
|
+
r = start
|
|
35
|
+
for e in i:
|
|
36
|
+
if r is None:
|
|
37
|
+
r = e
|
|
38
|
+
else:
|
|
39
|
+
r |= e
|
|
40
|
+
return r
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def final(cls):
|
|
44
|
+
def init_subclass():
|
|
45
|
+
raise TypeError("Subclassing {}.{} is not supported"
|
|
46
|
+
.format(cls.__module__, cls.__qualname__))
|
|
47
|
+
cls.__init_subclass__ = init_subclass
|
|
48
|
+
return cls
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def deprecated(message, stacklevel=2):
|
|
52
|
+
def decorator(f):
|
|
53
|
+
@functools.wraps(f)
|
|
54
|
+
def wrapper(*args, **kwargs):
|
|
55
|
+
warnings.warn(message, DeprecationWarning, stacklevel=stacklevel)
|
|
56
|
+
return f(*args, **kwargs)
|
|
57
|
+
return wrapper
|
|
58
|
+
return decorator
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _ignore_deprecated(f=None):
|
|
62
|
+
if f is None:
|
|
63
|
+
@contextlib.contextmanager
|
|
64
|
+
def context_like():
|
|
65
|
+
with warnings.catch_warnings():
|
|
66
|
+
warnings.filterwarnings(action="ignore", category=DeprecationWarning)
|
|
67
|
+
yield
|
|
68
|
+
return context_like()
|
|
69
|
+
else:
|
|
70
|
+
@functools.wraps(f)
|
|
71
|
+
def decorator_like(*args, **kwargs):
|
|
72
|
+
with warnings.catch_warnings():
|
|
73
|
+
warnings.filterwarnings(action="ignore", category=DeprecationWarning)
|
|
74
|
+
return f(*args, **kwargs)
|
|
75
|
+
return decorator_like
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def get_linter_options(filename):
|
|
79
|
+
first_line = linecache.getline(filename, 1)
|
|
80
|
+
if first_line:
|
|
81
|
+
match = re.match(r"^#\s*(?:ipweave|amaranth):\s*((?:\w+=\w+\s*)(?:,\s*\w+=\w+\s*)*)\n$", first_line)
|
|
82
|
+
if match:
|
|
83
|
+
return dict(map(lambda s: s.strip().split("=", 2), match.group(1).split(",")))
|
|
84
|
+
return dict()
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def get_linter_option(filename, name, type, default):
|
|
88
|
+
options = get_linter_options(filename)
|
|
89
|
+
if name not in options:
|
|
90
|
+
return default
|
|
91
|
+
|
|
92
|
+
option = options[name]
|
|
93
|
+
if type is bool:
|
|
94
|
+
if option in ("1", "yes", "enable"):
|
|
95
|
+
return True
|
|
96
|
+
if option in ("0", "no", "disable"):
|
|
97
|
+
return False
|
|
98
|
+
return default
|
|
99
|
+
if type is int:
|
|
100
|
+
try:
|
|
101
|
+
return int(option, 0)
|
|
102
|
+
except ValueError:
|
|
103
|
+
return default
|
|
104
|
+
assert False
|