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.
Files changed (403) hide show
  1. ipweave/__init__.py +28 -0
  2. ipweave/_legacy_cli.py +80 -0
  3. ipweave/_loc.py +46 -0
  4. ipweave/_toolchain/__init__.py +37 -0
  5. ipweave/_toolchain/yosys.py +255 -0
  6. ipweave/_tree.py +59 -0
  7. ipweave/_unused.py +47 -0
  8. ipweave/_utils.py +104 -0
  9. ipweave/agents.py +241 -0
  10. ipweave/asserts.py +15 -0
  11. ipweave/board/LICENSE.amaranth-boards.txt +21 -0
  12. ipweave/board/LICENSE.litex-boards.txt +26 -0
  13. ipweave/board/__init__.py +38 -0
  14. ipweave/board/_catalogue.json +45923 -0
  15. ipweave/board/_programmer.py +110 -0
  16. ipweave/board/_provenance.json +1701 -0
  17. ipweave/board/_registry.py +248 -0
  18. ipweave/board/adi_adrv2crr_fmc.py +594 -0
  19. ipweave/board/adi_plutosdr.py +57 -0
  20. ipweave/board/alchitry_au.py +252 -0
  21. ipweave/board/alchitry_cu.py +191 -0
  22. ipweave/board/alchitry_mojo.py +85 -0
  23. ipweave/board/alchitry_ptv2.py +740 -0
  24. ipweave/board/alibaba_vu13p.py +319 -0
  25. ipweave/board/alibaba_xcku3p.py +183 -0
  26. ipweave/board/aliexpress_xc7k420t.py +114 -0
  27. ipweave/board/aliexpress_xc7k70t.py +243 -0
  28. ipweave/board/alinx_ax7010.py +237 -0
  29. ipweave/board/alinx_ax7020.py +190 -0
  30. ipweave/board/alinx_ax7203.py +242 -0
  31. ipweave/board/alinx_ax7325b.py +323 -0
  32. ipweave/board/alinx_axau15.py +262 -0
  33. ipweave/board/alinx_axu2cga.py +179 -0
  34. ipweave/board/arrow_deca.py +218 -0
  35. ipweave/board/arty_a7.py +949 -0
  36. ipweave/board/arty_s7.py +780 -0
  37. ipweave/board/arty_z7.py +220 -0
  38. ipweave/board/atlys.py +387 -0
  39. ipweave/board/avnet_aesku40.py +100 -0
  40. ipweave/board/berkeleylab_marble.py +341 -0
  41. ipweave/board/berkeleylab_obsidian.py +229 -0
  42. ipweave/board/blackice.py +185 -0
  43. ipweave/board/blackice_ii.py +188 -0
  44. ipweave/board/bochenjingxin_kintex7_basec.py +84 -0
  45. ipweave/board/butterstick.py +336 -0
  46. ipweave/board/camlink_4k.py +65 -0
  47. ipweave/board/chameleon96.py +134 -0
  48. ipweave/board/cmod_a7.py +441 -0
  49. ipweave/board/cmod_s7.py +155 -0
  50. ipweave/board/colorlight_5a75b_r7_0.py +250 -0
  51. ipweave/board/colorlight_i9plus.py +300 -0
  52. ipweave/board/cora_z7.py +452 -0
  53. ipweave/board/de0.py +347 -0
  54. ipweave/board/de0_cv.py +344 -0
  55. ipweave/board/de0nano.py +226 -0
  56. ipweave/board/de10_lite.py +303 -0
  57. ipweave/board/de10_nano.py +249 -0
  58. ipweave/board/de1_soc.py +293 -0
  59. ipweave/board/decklink_intensity_pro_4k.py +72 -0
  60. ipweave/board/decklink_mini_4k.py +139 -0
  61. ipweave/board/decklink_quad_hdmi_recorder.py +159 -0
  62. ipweave/board/designs.py +239 -0
  63. ipweave/board/digilent_arty_z7.py +170 -0
  64. ipweave/board/digilent_netfpga_sume.py +280 -0
  65. ipweave/board/digilent_nexys4.py +421 -0
  66. ipweave/board/digilent_nexys_video.py +405 -0
  67. ipweave/board/digilent_pynq_z1.py +262 -0
  68. ipweave/board/digilent_zedboard.py +337 -0
  69. ipweave/board/digilent_zybo_z7.py +132 -0
  70. ipweave/board/ebaz4205.py +59 -0
  71. ipweave/board/ecp5_5g_evn.py +442 -0
  72. ipweave/board/ecpix5.py +698 -0
  73. ipweave/board/efinix_t120f324_kit.py +59 -0
  74. ipweave/board/efinix_t120f576_kit.py +67 -0
  75. ipweave/board/efinix_t20f256_kit.py +67 -0
  76. ipweave/board/efinix_t8f81_kit.py +63 -0
  77. ipweave/board/efinix_ti180j484_kit.py +67 -0
  78. ipweave/board/efinix_ti375c529_kit.py +63 -0
  79. ipweave/board/efinix_ti375n1156_kit.py +67 -0
  80. ipweave/board/efinix_ti60f225_kit.py +67 -0
  81. ipweave/board/efinix_tz170j484_kit.py +67 -0
  82. ipweave/board/ego1.py +290 -0
  83. ipweave/board/embedfire_rise_pro.py +335 -0
  84. ipweave/board/enclustra_mercury_kx2.py +348 -0
  85. ipweave/board/enclustra_mercury_xu5.py +96 -0
  86. ipweave/board/extensions/__init__.py +0 -0
  87. ipweave/board/extensions/pmod.py +94 -0
  88. ipweave/board/fairwaves_xtrx.py +168 -0
  89. ipweave/board/fomu_hacker.py +109 -0
  90. ipweave/board/fomu_pvt.py +88 -0
  91. ipweave/board/fpc_iii.py +159 -0
  92. ipweave/board/fpgawars_alhambra2.py +147 -0
  93. ipweave/board/gadgetfactory_papilio_pro.py +128 -0
  94. ipweave/board/genesys2.py +566 -0
  95. ipweave/board/hseda_xc7a35t.py +202 -0
  96. ipweave/board/hyvision_pcie_opt01_revf.py +313 -0
  97. ipweave/board/ice40_hx1k_blink_evn.py +132 -0
  98. ipweave/board/ice40_hx8k_b_evn.py +233 -0
  99. ipweave/board/ice40_up5k_b_evn.py +161 -0
  100. ipweave/board/icebreaker.py +150 -0
  101. ipweave/board/icebreaker_bitsy.py +175 -0
  102. ipweave/board/icepi_zero.py +207 -0
  103. ipweave/board/icestick.py +124 -0
  104. ipweave/board/icesugar.py +154 -0
  105. ipweave/board/icesugar_nano.py +89 -0
  106. ipweave/board/icesugar_pro.py +251 -0
  107. ipweave/board/isx_im1283.py +112 -0
  108. ipweave/board/kc705.py +83 -0
  109. ipweave/board/kcu105.py +78 -0
  110. ipweave/board/kosagi_fomu_evt.py +111 -0
  111. ipweave/board/kosagi_netv2.py +203 -0
  112. ipweave/board/krtkl_snickerdoodle.py +210 -0
  113. ipweave/board/lambdaconcept_pcie_screamer.py +100 -0
  114. ipweave/board/lambdaconcept_pcie_screamer_m2.py +85 -0
  115. ipweave/board/lattice_ecp5_vip.py +170 -0
  116. ipweave/board/limesdr_xtrx.py +173 -0
  117. ipweave/board/linsn_rv901t.py +186 -0
  118. ipweave/board/logicbone.py +427 -0
  119. ipweave/board/machdyne_krote.py +94 -0
  120. ipweave/board/machxo2_breakout.py +335 -0
  121. ipweave/board/machxo3_sk.py +708 -0
  122. ipweave/board/mercury.py +264 -0
  123. ipweave/board/micronova_mercury2.py +186 -0
  124. ipweave/board/microphase_a7_lite.py +220 -0
  125. ipweave/board/microzed_z010.py +153 -0
  126. ipweave/board/microzed_z020.py +168 -0
  127. ipweave/board/mist.py +86 -0
  128. ipweave/board/mister.py +308 -0
  129. ipweave/board/mlk_cu07_ku15p.py +122 -0
  130. ipweave/board/mnt_rkx7.py +191 -0
  131. ipweave/board/myir_myc_j7a100t.py +249 -0
  132. ipweave/board/nandland_go.py +118 -0
  133. ipweave/board/newae_cw305.py +109 -0
  134. ipweave/board/nexys4ddr.py +420 -0
  135. ipweave/board/nitefury.py +340 -0
  136. ipweave/board/numato_aller.py +145 -0
  137. ipweave/board/numato_mimas.py +171 -0
  138. ipweave/board/numato_mimas_a7.py +364 -0
  139. ipweave/board/numato_nereid.py +332 -0
  140. ipweave/board/numato_tagus.py +291 -0
  141. ipweave/board/ocp_tap_timecard.py +183 -0
  142. ipweave/board/opalkelly_xem8320.py +492 -0
  143. ipweave/board/opensourcesdrlab_kintex7.py +286 -0
  144. ipweave/board/orangecrab_r0_1.py +176 -0
  145. ipweave/board/orangecrab_r0_2.py +565 -0
  146. ipweave/board/pano_logic_g2.py +136 -0
  147. ipweave/board/qmtech_kintex7_devboard.py +191 -0
  148. ipweave/board/qmtech_xc7a35t.py +175 -0
  149. ipweave/board/qmtech_xc7k325t.py +183 -0
  150. ipweave/board/qwertyembedded_beaglewire.py +116 -0
  151. ipweave/board/redpitaya.py +118 -0
  152. ipweave/board/redpitaya_125_14.py +111 -0
  153. ipweave/board/resources/__init__.py +4 -0
  154. ipweave/board/resources/display.py +36 -0
  155. ipweave/board/resources/interface.py +144 -0
  156. ipweave/board/resources/memory.py +240 -0
  157. ipweave/board/resources/user.py +43 -0
  158. ipweave/board/rfsoc4x2.py +264 -0
  159. ipweave/board/rz_easyfpga_a2_2.py +246 -0
  160. ipweave/board/saanlima_pipistrello.py +206 -0
  161. ipweave/board/seeedstudio_spartan_edge_accelerator.py +123 -0
  162. ipweave/board/siglent_sds1104xe.py +100 -0
  163. ipweave/board/signaloid_c0_microsd.py +87 -0
  164. ipweave/board/sk_xc6slx9.py +160 -0
  165. ipweave/board/sqrl_fk33.py +119 -0
  166. ipweave/board/stepmxo2.py +207 -0
  167. ipweave/board/supercon19badge.py +329 -0
  168. ipweave/board/tang_mega_138k_pro_dock.py +123 -0
  169. ipweave/board/tang_nano.py +63 -0
  170. ipweave/board/tang_nano_9k.py +147 -0
  171. ipweave/board/tang_primer_20k.py +921 -0
  172. ipweave/board/te0714_03_50_2I.py +238 -0
  173. ipweave/board/test/__init__.py +0 -0
  174. ipweave/board/test/blinky.py +51 -0
  175. ipweave/board/tinyfpga_ax1.py +50 -0
  176. ipweave/board/tinyfpga_ax2.py +50 -0
  177. ipweave/board/tinyfpga_bx.py +109 -0
  178. ipweave/board/trenz_mega65.py +75 -0
  179. ipweave/board/trenz_s7mini.py +79 -0
  180. ipweave/board/trenz_te0710.py +59 -0
  181. ipweave/board/trenz_te0711.py +63 -0
  182. ipweave/board/trenz_te0725.py +160 -0
  183. ipweave/board/trenz_te0741.py +67 -0
  184. ipweave/board/trenz_te0890.py +132 -0
  185. ipweave/board/tul_pynq_z2.py +101 -0
  186. ipweave/board/ulx3s.py +1478 -0
  187. ipweave/board/upduino_v1.py +112 -0
  188. ipweave/board/upduino_v2.py +116 -0
  189. ipweave/board/upduino_v3.py +122 -0
  190. ipweave/board/versa_ecp5.py +329 -0
  191. ipweave/board/versa_ecp5_5g.py +279 -0
  192. ipweave/board/xilinx_ac701.py +426 -0
  193. ipweave/board/xilinx_alveo_u280.py +179 -0
  194. ipweave/board/xilinx_kc705.py +580 -0
  195. ipweave/board/xilinx_kcu105.py +600 -0
  196. ipweave/board/xilinx_kcu116.py +426 -0
  197. ipweave/board/xilinx_kv260.py +50 -0
  198. ipweave/board/xilinx_sp605.py +323 -0
  199. ipweave/board/xilinx_vc707.py +707 -0
  200. ipweave/board/xilinx_vcu128.py +441 -0
  201. ipweave/board/xilinx_zc706.py +430 -0
  202. ipweave/board/xilinx_zcu102.py +534 -0
  203. ipweave/board/xilinx_zcu216.py +257 -0
  204. ipweave/board/ypcb_00338_1p1.py +145 -0
  205. ipweave/board/ztex213.py +53 -0
  206. ipweave/board/zturn_lite_z007s.py +116 -0
  207. ipweave/board/zturn_lite_z010.py +116 -0
  208. ipweave/build/__init__.py +3 -0
  209. ipweave/build/dsl.py +283 -0
  210. ipweave/build/plat.py +442 -0
  211. ipweave/build/res.py +317 -0
  212. ipweave/build/run.py +315 -0
  213. ipweave/bus/__init__.py +108 -0
  214. ipweave/bus/_expr.py +121 -0
  215. ipweave/bus/binding/__init__.py +100 -0
  216. ipweave/bus/binding/ahb.py +153 -0
  217. ipweave/bus/binding/apb4.py +106 -0
  218. ipweave/bus/binding/axi4.py +211 -0
  219. ipweave/bus/binding/axi4_lite.py +161 -0
  220. ipweave/bus/binding/base.py +327 -0
  221. ipweave/bus/binding/obi.py +56 -0
  222. ipweave/bus/binding/stream.py +171 -0
  223. ipweave/bus/binding/tilelink_uh.py +197 -0
  224. ipweave/bus/binding/tilelink_ul.py +156 -0
  225. ipweave/bus/binding/wishbone.py +99 -0
  226. ipweave/bus/checker.py +203 -0
  227. ipweave/bus/core.py +162 -0
  228. ipweave/bus/model.py +417 -0
  229. ipweave/bus/spec.py +580 -0
  230. ipweave/bus/specs/ahb.toml +218 -0
  231. ipweave/bus/specs/apb4.toml +76 -0
  232. ipweave/bus/specs/axi4.toml +218 -0
  233. ipweave/bus/specs/axi4_lite.toml +229 -0
  234. ipweave/bus/specs/axi_stream.toml +131 -0
  235. ipweave/bus/specs/decoupled.toml +36 -0
  236. ipweave/bus/specs/obi.toml +88 -0
  237. ipweave/bus/specs/tilelink_uh.toml +277 -0
  238. ipweave/bus/specs/tilelink_ul.toml +216 -0
  239. ipweave/bus/specs/wishbone.toml +176 -0
  240. ipweave/check/__init__.py +127 -0
  241. ipweave/check/clocking.py +185 -0
  242. ipweave/check/connectivity.py +104 -0
  243. ipweave/check/depth.py +241 -0
  244. ipweave/check/domains.py +242 -0
  245. ipweave/check/fsm.py +196 -0
  246. ipweave/check/mbist.py +103 -0
  247. ipweave/check/netlist.py +91 -0
  248. ipweave/check/pipeline.py +138 -0
  249. ipweave/check/scan.py +117 -0
  250. ipweave/check/views.py +279 -0
  251. ipweave/check/xprop.py +68 -0
  252. ipweave/cleanroom/__init__.py +13 -0
  253. ipweave/cleanroom/_model.py +304 -0
  254. ipweave/cli.py +1215 -0
  255. ipweave/dft/__init__.py +13 -0
  256. ipweave/dft/_model.py +195 -0
  257. ipweave/dft/ijtag.py +273 -0
  258. ipweave/dft/mbist.py +163 -0
  259. ipweave/dft/tap.py +178 -0
  260. ipweave/emit/__init__.py +0 -0
  261. ipweave/emit/cxxrtl.py +40 -0
  262. ipweave/emit/ipxact.py +443 -0
  263. ipweave/emit/ipxact_schemas/PROVENANCE.json +37 -0
  264. ipweave/emit/ipxact_schemas/abstractionDefinition.xsd +302 -0
  265. ipweave/emit/ipxact_schemas/abstractor.xsd +165 -0
  266. ipweave/emit/ipxact_schemas/autoConfigure.xsd +109 -0
  267. ipweave/emit/ipxact_schemas/busDefinition.xsd +114 -0
  268. ipweave/emit/ipxact_schemas/busInterface.xsd +591 -0
  269. ipweave/emit/ipxact_schemas/catalog.xsd +79 -0
  270. ipweave/emit/ipxact_schemas/commonStructures.xsd +1134 -0
  271. ipweave/emit/ipxact_schemas/component.xsd +450 -0
  272. ipweave/emit/ipxact_schemas/constraints.xsd +261 -0
  273. ipweave/emit/ipxact_schemas/design.xsd +73 -0
  274. ipweave/emit/ipxact_schemas/designConfig.xsd +187 -0
  275. ipweave/emit/ipxact_schemas/file.xsd +467 -0
  276. ipweave/emit/ipxact_schemas/fileType.xsd +88 -0
  277. ipweave/emit/ipxact_schemas/generator.xsd +286 -0
  278. ipweave/emit/ipxact_schemas/identifier.xsd +102 -0
  279. ipweave/emit/ipxact_schemas/memoryMap.xsd +1862 -0
  280. ipweave/emit/ipxact_schemas/model.xsd +372 -0
  281. ipweave/emit/ipxact_schemas/port.xsd +1161 -0
  282. ipweave/emit/ipxact_schemas/signalDrivers.xsd +221 -0
  283. ipweave/emit/ipxact_schemas/simpleTypes.xsd +286 -0
  284. ipweave/emit/ipxact_schemas/subInstances.xsd +376 -0
  285. ipweave/emit/ipxact_schemas/typeDefinitions.xsd +198 -0
  286. ipweave/emit/ipxact_schemas/xml.xsd +24 -0
  287. ipweave/emit/rtlil.py +1306 -0
  288. ipweave/emit/sdc.py +189 -0
  289. ipweave/emit/sv/__init__.py +26 -0
  290. ipweave/emit/sv/_emit.py +1237 -0
  291. ipweave/emit/sv/_expr.py +554 -0
  292. ipweave/emit/sv/_ports.py +208 -0
  293. ipweave/emit/sv/_raise.py +125 -0
  294. ipweave/emit/sv/_writer.py +227 -0
  295. ipweave/emit/upf.py +139 -0
  296. ipweave/emit/verilog.py +62 -0
  297. ipweave/flow/__init__.py +8 -0
  298. ipweave/flow/graph.py +280 -0
  299. ipweave/hdl/__init__.py +40 -0
  300. ipweave/hdl/_ast.py +3272 -0
  301. ipweave/hdl/_cd.py +93 -0
  302. ipweave/hdl/_dsl.py +702 -0
  303. ipweave/hdl/_ir.py +1804 -0
  304. ipweave/hdl/_mem.py +273 -0
  305. ipweave/hdl/_nir.py +1498 -0
  306. ipweave/hdl/_time.py +252 -0
  307. ipweave/hdl/_xfrm.py +701 -0
  308. ipweave/ip/__init__.py +15 -0
  309. ipweave/ip/cdc/__init__.py +43 -0
  310. ipweave/ip/cdc/handshake.py +215 -0
  311. ipweave/ip/cdc/stream.py +123 -0
  312. ipweave/ip/datapath/__init__.py +34 -0
  313. ipweave/ip/datapath/divide.py +191 -0
  314. ipweave/ip/datapath/multiply.py +201 -0
  315. ipweave/ip/datapath/prefix.py +210 -0
  316. ipweave/ip/datapath/reduce.py +135 -0
  317. ipweave/ip/datapath/shift.py +231 -0
  318. ipweave/ip/datapath/storage.py +233 -0
  319. ipweave/ip/flow/__init__.py +34 -0
  320. ipweave/ip/flow/arbiter.py +195 -0
  321. ipweave/ip/flow/buffer.py +190 -0
  322. ipweave/ip/flow/crossbar.py +159 -0
  323. ipweave/lib/__init__.py +0 -0
  324. ipweave/lib/cdc.py +282 -0
  325. ipweave/lib/crc/__init__.py +362 -0
  326. ipweave/lib/crc/catalog.py +911 -0
  327. ipweave/lib/data.py +1437 -0
  328. ipweave/lib/enum.py +416 -0
  329. ipweave/lib/fifo.py +593 -0
  330. ipweave/lib/io.py +1155 -0
  331. ipweave/lib/memory.py +462 -0
  332. ipweave/lib/meta.py +155 -0
  333. ipweave/lib/stream.py +125 -0
  334. ipweave/lib/wiring.py +1996 -0
  335. ipweave/licence.py +168 -0
  336. ipweave/params.py +228 -0
  337. ipweave/phys.py +332 -0
  338. ipweave/pipeline.py +344 -0
  339. ipweave/platform/__init__.py +68 -0
  340. ipweave/platform/_altera.py +83 -0
  341. ipweave/platform/_common.py +80 -0
  342. ipweave/platform/_efinix.py +296 -0
  343. ipweave/platform/_microchip.py +198 -0
  344. ipweave/platform/_registry.py +304 -0
  345. ipweave/platform/_run.py +63 -0
  346. ipweave/platform/asic.py +306 -0
  347. ipweave/plugin.py +319 -0
  348. ipweave/power.py +386 -0
  349. ipweave/regs/__init__.py +49 -0
  350. ipweave/regs/block.py +296 -0
  351. ipweave/regs/cheader.py +138 -0
  352. ipweave/regs/manual.py +171 -0
  353. ipweave/regs/model.py +429 -0
  354. ipweave/regs/ral.py +176 -0
  355. ipweave/regs/rdl.py +442 -0
  356. ipweave/rpc.py +114 -0
  357. ipweave/rules/__init__.py +900 -0
  358. ipweave/serve/__init__.py +13 -0
  359. ipweave/serve/_protocol.py +140 -0
  360. ipweave/serve/_tools.py +242 -0
  361. ipweave/sim/__init__.py +13 -0
  362. ipweave/sim/_async.py +782 -0
  363. ipweave/sim/_base.py +101 -0
  364. ipweave/sim/_pyclock.py +37 -0
  365. ipweave/sim/_pycoro.py +129 -0
  366. ipweave/sim/_pyeval.py +231 -0
  367. ipweave/sim/_pyrtl.py +628 -0
  368. ipweave/sim/core.py +486 -0
  369. ipweave/sim/pysim.py +731 -0
  370. ipweave/spec/__init__.py +21 -0
  371. ipweave/spec/_model.py +259 -0
  372. ipweave/spec/documents.py +244 -0
  373. ipweave/strict.py +138 -0
  374. ipweave/tech/__init__.py +27 -0
  375. ipweave/tech/_model.py +454 -0
  376. ipweave/timing.py +432 -0
  377. ipweave/trace.py +291 -0
  378. ipweave/tracer.py +77 -0
  379. ipweave/utils.py +40 -0
  380. ipweave/vendor/__init__.py +46 -0
  381. ipweave/vendor/_altera.py +531 -0
  382. ipweave/vendor/_gowin.py +584 -0
  383. ipweave/vendor/_lattice.py +1062 -0
  384. ipweave/vendor/_quicklogic.py +191 -0
  385. ipweave/vendor/_siliconblue.py +595 -0
  386. ipweave/vendor/_xilinx.py +1310 -0
  387. ipweave/verif/__init__.py +10 -0
  388. ipweave/verif/cosim.py +417 -0
  389. ipweave/verif/cover.py +307 -0
  390. ipweave/verif/equiv.py +194 -0
  391. ipweave/verif/formal.py +286 -0
  392. ipweave/verif/golden.py +202 -0
  393. ipweave/verif/lint.py +258 -0
  394. ipweave/verif/regression.py +195 -0
  395. ipweave/verif/tools.py +198 -0
  396. ipweave-0.1.0.dist-info/METADATA +265 -0
  397. ipweave-0.1.0.dist-info/RECORD +403 -0
  398. ipweave-0.1.0.dist-info/WHEEL +5 -0
  399. ipweave-0.1.0.dist-info/entry_points.txt +5 -0
  400. ipweave-0.1.0.dist-info/licenses/LICENSE +202 -0
  401. ipweave-0.1.0.dist-info/licenses/LICENSE.amaranth.txt +21 -0
  402. ipweave-0.1.0.dist-info/licenses/NOTICE +113 -0
  403. 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