From ec34844dc87e163f6dc8aa11d946b26bcb8ca910 Mon Sep 17 00:00:00 2001 From: <> Date: Mon, 7 Aug 2023 17:17:17 +0000 Subject: [PATCH] Update documentation --- .nojekyll | 0 404.html | 903 +++ assets/images/favicon.png | Bin 0 -> 1870 bytes assets/images/livehd.svg | 821 ++ assets/javascripts/bundle.220ee61c.min.js | 29 + assets/javascripts/bundle.220ee61c.min.js.map | 8 + assets/javascripts/lunr/min/lunr.ar.min.js | 1 + assets/javascripts/lunr/min/lunr.da.min.js | 18 + assets/javascripts/lunr/min/lunr.de.min.js | 18 + assets/javascripts/lunr/min/lunr.du.min.js | 18 + assets/javascripts/lunr/min/lunr.es.min.js | 18 + assets/javascripts/lunr/min/lunr.fi.min.js | 18 + assets/javascripts/lunr/min/lunr.fr.min.js | 18 + assets/javascripts/lunr/min/lunr.hi.min.js | 1 + assets/javascripts/lunr/min/lunr.hu.min.js | 18 + assets/javascripts/lunr/min/lunr.hy.min.js | 1 + assets/javascripts/lunr/min/lunr.it.min.js | 18 + assets/javascripts/lunr/min/lunr.ja.min.js | 1 + assets/javascripts/lunr/min/lunr.jp.min.js | 1 + assets/javascripts/lunr/min/lunr.kn.min.js | 1 + assets/javascripts/lunr/min/lunr.ko.min.js | 1 + assets/javascripts/lunr/min/lunr.multi.min.js | 1 + assets/javascripts/lunr/min/lunr.nl.min.js | 18 + assets/javascripts/lunr/min/lunr.no.min.js | 18 + assets/javascripts/lunr/min/lunr.pt.min.js | 18 + assets/javascripts/lunr/min/lunr.ro.min.js | 18 + assets/javascripts/lunr/min/lunr.ru.min.js | 18 + assets/javascripts/lunr/min/lunr.sa.min.js | 1 + .../lunr/min/lunr.stemmer.support.min.js | 1 + assets/javascripts/lunr/min/lunr.sv.min.js | 18 + assets/javascripts/lunr/min/lunr.ta.min.js | 1 + assets/javascripts/lunr/min/lunr.te.min.js | 1 + assets/javascripts/lunr/min/lunr.th.min.js | 1 + assets/javascripts/lunr/min/lunr.tr.min.js | 18 + assets/javascripts/lunr/min/lunr.vi.min.js | 1 + assets/javascripts/lunr/min/lunr.zh.min.js | 1 + assets/javascripts/lunr/tinyseg.js | 206 + assets/javascripts/lunr/wordcut.js | 6708 +++++++++++++++++ .../workers/search.74e28a9f.min.js | 42 + .../workers/search.74e28a9f.min.js.map | 8 + assets/pyrope5.png | Bin 0 -> 16663 bytes assets/stylesheets/main.eebd395e.min.css | 1 + assets/stylesheets/main.eebd395e.min.css.map | 1 + assets/stylesheets/palette.ecc896b0.min.css | 1 + .../stylesheets/palette.ecc896b0.min.css.map | 1 + index.html | 938 +++ javascripts/config.js | 17 + livehd/00-intro/index.html | 1045 +++ livehd/01-install/index.html | 1090 +++ livehd/02-usage/index.html | 1281 ++++ livehd/03-memory/index.html | 1109 +++ livehd/04-api/index.html | 986 +++ livehd/05-lgraph/index.html | 2614 +++++++ livehd/06-lnast/index.html | 2025 +++++ livehd/10-bazel/index.html | 1249 +++ livehd/10b-3rdparty/index.html | 1092 +++ livehd/11-pass/index.html | 1190 +++ livehd/12-github/index.html | 1299 ++++ livehd/13-style/index.html | 1614 ++++ livehd/graphviz/and.dot | 33 + livehd/graphviz/and.png | Bin 0 -> 27104 bytes livehd/graphviz/assign_simple_expression.dot | 42 + livehd/graphviz/assign_simple_expression.png | Bin 0 -> 47443 bytes livehd/graphviz/assign_trivial_constant.dot | 19 + livehd/graphviz/assign_trivial_constant.png | Bin 0 -> 11178 bytes livehd/graphviz/attribute.dot | 70 + livehd/graphviz/attribute.png | Bin 0 -> 83948 bytes livehd/graphviz/for.dot | 56 + livehd/graphviz/for.png | Bin 0 -> 66864 bytes livehd/graphviz/full_case_if.dot | 75 + livehd/graphviz/full_case_if.png | Bin 0 -> 89223 bytes livehd/graphviz/function_call_exp.dot | 109 + livehd/graphviz/function_call_exp.png | Bin 0 -> 159081 bytes livehd/graphviz/function_call_imp.dot | 109 + livehd/graphviz/function_call_imp.png | Bin 0 -> 159109 bytes livehd/graphviz/function_def.dot | 48 + livehd/graphviz/function_def.png | Bin 0 -> 56659 bytes livehd/graphviz/function_def_conditional.dot | 59 + livehd/graphviz/function_def_conditional.png | Bin 0 -> 77953 bytes livehd/graphviz/inv.dot | 17 + livehd/graphviz/inv.png | Bin 0 -> 7015 bytes livehd/graphviz/logical_inv.dot | 16 + livehd/graphviz/logical_inv.png | Bin 0 -> 7007 bytes livehd/graphviz/new_for.dot | 96 + livehd/graphviz/new_for.png | Bin 0 -> 120445 bytes livehd/graphviz/simple_if.dot | 52 + livehd/graphviz/simple_if.png | Bin 0 -> 50180 bytes livehd/graphviz/tuple.dot | 49 + livehd/graphviz/tuple.png | Bin 0 -> 44600 bytes livehd/graphviz/tuple_concat.dot | 74 + livehd/graphviz/tuple_concat.png | Bin 0 -> 95519 bytes livehd/graphviz/while.dot | 40 + livehd/graphviz/while.png | Bin 0 -> 38251 bytes pyrope/00-hwdesign/index.html | 1724 +++++ pyrope/01-introduction/index.html | 1304 ++++ pyrope/02-basics/index.html | 1597 ++++ pyrope/03-bundle/index.html | 1545 ++++ pyrope/04-variables/index.html | 2601 +++++++ pyrope/05-assert/index.html | 1345 ++++ pyrope/05b-statements/index.html | 1612 ++++ pyrope/06-functions/index.html | 1611 ++++ pyrope/06b-instantiation/index.html | 1682 +++++ pyrope/06c-pipelining/index.html | 1558 ++++ pyrope/07-typesystem/index.html | 2352 ++++++ pyrope/07b-structtype/index.html | 1701 +++++ pyrope/08-memories/index.html | 1349 ++++ pyrope/09-stdlib/index.html | 940 +++ pyrope/10-internals/index.html | 2135 ++++++ pyrope/10b-vslang/index.html | 1342 ++++ pyrope/11-deprecated/index.html | 1274 ++++ pyrope/12-lnast/index.html | 3109 ++++++++ pyrope/13-stdlib/index.html | 1143 +++ search/search_index.json | 1 + sitemap.xml | 3 + sitemap.xml.gz | Bin 0 -> 127 bytes 115 files changed, 59455 insertions(+) create mode 100644 .nojekyll create mode 100644 404.html create mode 100644 assets/images/favicon.png create mode 100644 assets/images/livehd.svg create mode 100644 assets/javascripts/bundle.220ee61c.min.js create mode 100644 assets/javascripts/bundle.220ee61c.min.js.map create mode 100644 assets/javascripts/lunr/min/lunr.ar.min.js create mode 100644 assets/javascripts/lunr/min/lunr.da.min.js create mode 100644 assets/javascripts/lunr/min/lunr.de.min.js create mode 100644 assets/javascripts/lunr/min/lunr.du.min.js create mode 100644 assets/javascripts/lunr/min/lunr.es.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hu.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hy.min.js create mode 100644 assets/javascripts/lunr/min/lunr.it.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ja.min.js create mode 100644 assets/javascripts/lunr/min/lunr.jp.min.js create mode 100644 assets/javascripts/lunr/min/lunr.kn.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ko.min.js create mode 100644 assets/javascripts/lunr/min/lunr.multi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.nl.min.js create mode 100644 assets/javascripts/lunr/min/lunr.no.min.js create mode 100644 assets/javascripts/lunr/min/lunr.pt.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ro.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ru.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sa.min.js create mode 100644 assets/javascripts/lunr/min/lunr.stemmer.support.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sv.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ta.min.js create mode 100644 assets/javascripts/lunr/min/lunr.te.min.js create mode 100644 assets/javascripts/lunr/min/lunr.th.min.js create mode 100644 assets/javascripts/lunr/min/lunr.tr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.vi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.zh.min.js create mode 100644 assets/javascripts/lunr/tinyseg.js create mode 100644 assets/javascripts/lunr/wordcut.js create mode 100644 assets/javascripts/workers/search.74e28a9f.min.js create mode 100644 assets/javascripts/workers/search.74e28a9f.min.js.map create mode 100644 assets/pyrope5.png create mode 100644 assets/stylesheets/main.eebd395e.min.css create mode 100644 assets/stylesheets/main.eebd395e.min.css.map create mode 100644 assets/stylesheets/palette.ecc896b0.min.css create mode 100644 assets/stylesheets/palette.ecc896b0.min.css.map create mode 100644 index.html create mode 100644 javascripts/config.js create mode 100644 livehd/00-intro/index.html create mode 100644 livehd/01-install/index.html create mode 100644 livehd/02-usage/index.html create mode 100644 livehd/03-memory/index.html create mode 100644 livehd/04-api/index.html create mode 100644 livehd/05-lgraph/index.html create mode 100644 livehd/06-lnast/index.html create mode 100644 livehd/10-bazel/index.html create mode 100644 livehd/10b-3rdparty/index.html create mode 100644 livehd/11-pass/index.html create mode 100644 livehd/12-github/index.html create mode 100644 livehd/13-style/index.html create mode 100644 livehd/graphviz/and.dot create mode 100644 livehd/graphviz/and.png create mode 100644 livehd/graphviz/assign_simple_expression.dot create mode 100644 livehd/graphviz/assign_simple_expression.png create mode 100644 livehd/graphviz/assign_trivial_constant.dot create mode 100644 livehd/graphviz/assign_trivial_constant.png create mode 100644 livehd/graphviz/attribute.dot create mode 100644 livehd/graphviz/attribute.png create mode 100644 livehd/graphviz/for.dot create mode 100644 livehd/graphviz/for.png create mode 100644 livehd/graphviz/full_case_if.dot create mode 100644 livehd/graphviz/full_case_if.png create mode 100644 livehd/graphviz/function_call_exp.dot create mode 100644 livehd/graphviz/function_call_exp.png create mode 100644 livehd/graphviz/function_call_imp.dot create mode 100644 livehd/graphviz/function_call_imp.png create mode 100644 livehd/graphviz/function_def.dot create mode 100644 livehd/graphviz/function_def.png create mode 100644 livehd/graphviz/function_def_conditional.dot create mode 100644 livehd/graphviz/function_def_conditional.png create mode 100644 livehd/graphviz/inv.dot create mode 100644 livehd/graphviz/inv.png create mode 100644 livehd/graphviz/logical_inv.dot create mode 100644 livehd/graphviz/logical_inv.png create mode 100644 livehd/graphviz/new_for.dot create mode 100644 livehd/graphviz/new_for.png create mode 100644 livehd/graphviz/simple_if.dot create mode 100644 livehd/graphviz/simple_if.png create mode 100644 livehd/graphviz/tuple.dot create mode 100644 livehd/graphviz/tuple.png create mode 100644 livehd/graphviz/tuple_concat.dot create mode 100644 livehd/graphviz/tuple_concat.png create mode 100644 livehd/graphviz/while.dot create mode 100644 livehd/graphviz/while.png create mode 100644 pyrope/00-hwdesign/index.html create mode 100644 pyrope/01-introduction/index.html create mode 100644 pyrope/02-basics/index.html create mode 100644 pyrope/03-bundle/index.html create mode 100644 pyrope/04-variables/index.html create mode 100644 pyrope/05-assert/index.html create mode 100644 pyrope/05b-statements/index.html create mode 100644 pyrope/06-functions/index.html create mode 100644 pyrope/06b-instantiation/index.html create mode 100644 pyrope/06c-pipelining/index.html create mode 100644 pyrope/07-typesystem/index.html create mode 100644 pyrope/07b-structtype/index.html create mode 100644 pyrope/08-memories/index.html create mode 100644 pyrope/09-stdlib/index.html create mode 100644 pyrope/10-internals/index.html create mode 100644 pyrope/10b-vslang/index.html create mode 100644 pyrope/11-deprecated/index.html create mode 100644 pyrope/12-lnast/index.html create mode 100644 pyrope/13-stdlib/index.html create mode 100644 search/search_index.json create mode 100644 sitemap.xml create mode 100644 sitemap.xml.gz diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..3b16f32 --- /dev/null +++ b/404.html @@ -0,0 +1,903 @@ + + + + + + + + + + + + + + + + + + LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..1cf13b9f9d978896599290a74f77d5dbe7d1655c GIT binary patch literal 1870 zcmV-U2eJ5xP)Gc)JR9QMau)O=X#!i9;T z37kk-upj^(fsR36MHs_+1RCI)NNu9}lD0S{B^g8PN?Ww(5|~L#Ng*g{WsqleV}|#l zz8@ri&cTzw_h33bHI+12+kK6WN$h#n5cD8OQt`5kw6p~9H3()bUQ8OS4Q4HTQ=1Ol z_JAocz`fLbT2^{`8n~UAo=#AUOf=SOq4pYkt;XbC&f#7lb$*7=$na!mWCQ`dBQsO0 zLFBSPj*N?#u5&pf2t4XjEGH|=pPQ8xh7tpx;US5Cx_Ju;!O`ya-yF`)b%TEt5>eP1ZX~}sjjA%FJF?h7cX8=b!DZl<6%Cv z*G0uvvU+vmnpLZ2paivG-(cd*y3$hCIcsZcYOGh{$&)A6*XX&kXZd3G8m)G$Zz-LV z^GF3VAW^Mdv!)4OM8EgqRiz~*Cji;uzl2uC9^=8I84vNp;ltJ|q-*uQwGp2ma6cY7 z;`%`!9UXO@fr&Ebapfs34OmS9^u6$)bJxrucutf>`dKPKT%%*d3XlFVKunp9 zasduxjrjs>f8V=D|J=XNZp;_Zy^WgQ$9WDjgY=z@stwiEBm9u5*|34&1Na8BMjjgf3+SHcr`5~>oz1Y?SW^=K z^bTyO6>Gar#P_W2gEMwq)ot3; zREHn~U&Dp0l6YT0&k-wLwYjb?5zGK`W6S2v+K>AM(95m2C20L|3m~rN8dprPr@t)5lsk9Hu*W z?pS990s;Ez=+Rj{x7p``4>+c0G5^pYnB1^!TL=(?HLHZ+HicG{~4F1d^5Awl_2!1jICM-!9eoLhbbT^;yHcefyTAaqRcY zmuctDopPT!%k+}x%lZRKnzykr2}}XfG_ne?nRQO~?%hkzo;@RN{P6o`&mMUWBYMTe z6i8ChtjX&gXl`nvrU>jah)2iNM%JdjqoaeaU%yVn!^70x-flljp6Q5tK}5}&X8&&G zX3fpb3E(!rH=zVI_9Gjl45w@{(ITqngWFe7@9{mX;tO25Z_8 zQHEpI+FkTU#4xu>RkN>b3Tnc3UpWzPXWm#o55GKF09j^Mh~)K7{QqbO_~(@CVq! zS<8954|P8mXN2MRs86xZ&Q4EfM@JB94b=(YGuk)s&^jiSF=t3*oNK3`rD{H`yQ?d; ztE=laAUoZx5?RC8*WKOj`%LXEkgDd>&^Q4M^z`%u0rg-It=hLCVsq!Z%^6eB-OvOT zFZ28TN&cRmgU}Elrnk43)!>Z1FCPL2K$7}gwzIc48NX}#!A1BpJP?#v5wkNprhV** z?Cpalt1oH&{r!o3eSKc&ap)iz2BTn_VV`4>9M^b3;(YY}4>#ML6{~(4mH+?%07*qo IM6N<$f(jP3KmY&$ literal 0 HcmV?d00001 diff --git a/assets/images/livehd.svg b/assets/images/livehd.svg new file mode 100644 index 0000000..c37efaa --- /dev/null +++ b/assets/images/livehd.svg @@ -0,0 +1,821 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + Graphviz + + + LNAST + Yosys + LNAST + + Yosys + + + + + + + + + + + + + + + pass + mockturtle + + LGraph + + Verilog + FIRRTL + C++ + FIRRTL + Verilog + + + + + json + + + + json + + + Pyrope + + Pyrope + + diff --git a/assets/javascripts/bundle.220ee61c.min.js b/assets/javascripts/bundle.220ee61c.min.js new file mode 100644 index 0000000..116072a --- /dev/null +++ b/assets/javascripts/bundle.220ee61c.min.js @@ -0,0 +1,29 @@ +"use strict";(()=>{var Ci=Object.create;var gr=Object.defineProperty;var Ri=Object.getOwnPropertyDescriptor;var ki=Object.getOwnPropertyNames,Ht=Object.getOwnPropertySymbols,Hi=Object.getPrototypeOf,yr=Object.prototype.hasOwnProperty,nn=Object.prototype.propertyIsEnumerable;var rn=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))yr.call(t,r)&&rn(e,r,t[r]);if(Ht)for(var r of Ht(t))nn.call(t,r)&&rn(e,r,t[r]);return e};var on=(e,t)=>{var r={};for(var n in e)yr.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&Ht)for(var n of Ht(e))t.indexOf(n)<0&&nn.call(e,n)&&(r[n]=e[n]);return r};var Pt=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Pi=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ki(t))!yr.call(e,o)&&o!==r&&gr(e,o,{get:()=>t[o],enumerable:!(n=Ri(t,o))||n.enumerable});return e};var yt=(e,t,r)=>(r=e!=null?Ci(Hi(e)):{},Pi(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var sn=Pt((xr,an)=>{(function(e,t){typeof xr=="object"&&typeof an!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(xr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(O){return!!(O&&O!==document&&O.nodeName!=="HTML"&&O.nodeName!=="BODY"&&"classList"in O&&"contains"in O.classList)}function f(O){var Qe=O.type,De=O.tagName;return!!(De==="INPUT"&&s[Qe]&&!O.readOnly||De==="TEXTAREA"&&!O.readOnly||O.isContentEditable)}function c(O){O.classList.contains("focus-visible")||(O.classList.add("focus-visible"),O.setAttribute("data-focus-visible-added",""))}function u(O){O.hasAttribute("data-focus-visible-added")&&(O.classList.remove("focus-visible"),O.removeAttribute("data-focus-visible-added"))}function p(O){O.metaKey||O.altKey||O.ctrlKey||(a(r.activeElement)&&c(r.activeElement),n=!0)}function m(O){n=!1}function d(O){a(O.target)&&(n||f(O.target))&&c(O.target)}function h(O){a(O.target)&&(O.target.classList.contains("focus-visible")||O.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(O.target))}function v(O){document.visibilityState==="hidden"&&(o&&(n=!0),Y())}function Y(){document.addEventListener("mousemove",N),document.addEventListener("mousedown",N),document.addEventListener("mouseup",N),document.addEventListener("pointermove",N),document.addEventListener("pointerdown",N),document.addEventListener("pointerup",N),document.addEventListener("touchmove",N),document.addEventListener("touchstart",N),document.addEventListener("touchend",N)}function B(){document.removeEventListener("mousemove",N),document.removeEventListener("mousedown",N),document.removeEventListener("mouseup",N),document.removeEventListener("pointermove",N),document.removeEventListener("pointerdown",N),document.removeEventListener("pointerup",N),document.removeEventListener("touchmove",N),document.removeEventListener("touchstart",N),document.removeEventListener("touchend",N)}function N(O){O.target.nodeName&&O.target.nodeName.toLowerCase()==="html"||(n=!1,B())}document.addEventListener("keydown",p,!0),document.addEventListener("mousedown",m,!0),document.addEventListener("pointerdown",m,!0),document.addEventListener("touchstart",m,!0),document.addEventListener("visibilitychange",v,!0),Y(),r.addEventListener("focus",d,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var cn=Pt(Er=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(c){return!1}},r=t(),n=function(c){var u={next:function(){var p=c.shift();return{done:p===void 0,value:p}}};return r&&(u[Symbol.iterator]=function(){return u}),u},o=function(c){return encodeURIComponent(c).replace(/%20/g,"+")},i=function(c){return decodeURIComponent(String(c).replace(/\+/g," "))},s=function(){var c=function(p){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var m=typeof p;if(m!=="undefined")if(m==="string")p!==""&&this._fromString(p);else if(p instanceof c){var d=this;p.forEach(function(B,N){d.append(N,B)})}else if(p!==null&&m==="object")if(Object.prototype.toString.call(p)==="[object Array]")for(var h=0;hd[0]?1:0}),c._entries&&(c._entries={});for(var p=0;p1?i(d[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(f,c){typeof f!="string"&&(f=String(f)),c&&typeof c!="string"&&(c=String(c));var u=document,p;if(c&&(e.location===void 0||c!==e.location.href)){c=c.toLowerCase(),u=document.implementation.createHTMLDocument(""),p=u.createElement("base"),p.href=c,u.head.appendChild(p);try{if(p.href.indexOf(c)!==0)throw new Error(p.href)}catch(O){throw new Error("URL unable to set base "+c+" due to "+O)}}var m=u.createElement("a");m.href=f,p&&(u.body.appendChild(m),m.href=m.href);var d=u.createElement("input");if(d.type="url",d.value=f,m.protocol===":"||!/:/.test(m.href)||!d.checkValidity()&&!c)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:m});var h=new e.URLSearchParams(this.search),v=!0,Y=!0,B=this;["append","delete","set"].forEach(function(O){var Qe=h[O];h[O]=function(){Qe.apply(h,arguments),v&&(Y=!1,B.search=h.toString(),Y=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var N=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==N&&(N=this.search,Y&&(v=!1,this.searchParams._fromString(this.search),v=!0))}})},s=i.prototype,a=function(f){Object.defineProperty(s,f,{get:function(){return this._anchorElement[f]},set:function(c){this._anchorElement[f]=c},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(f){a(f)}),Object.defineProperty(s,"search",{get:function(){return this._anchorElement.search},set:function(f){this._anchorElement.search=f,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(s,{toString:{get:function(){var f=this;return function(){return f.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(f){this._anchorElement.href=f,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(f){this._anchorElement.pathname=f},enumerable:!0},origin:{get:function(){var f={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],c=this._anchorElement.port!=f&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(c?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(f){},enumerable:!0},username:{get:function(){return""},set:function(f){},enumerable:!0}}),i.createObjectURL=function(f){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(f){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er)});var qr=Pt((Mt,Nr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Mt=="object"&&typeof Nr=="object"?Nr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Mt=="object"?Mt.ClipboardJS=r():t.ClipboardJS=r()})(Mt,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return Ai}});var s=i(279),a=i.n(s),f=i(370),c=i.n(f),u=i(817),p=i.n(u);function m(j){try{return document.execCommand(j)}catch(T){return!1}}var d=function(T){var E=p()(T);return m("cut"),E},h=d;function v(j){var T=document.documentElement.getAttribute("dir")==="rtl",E=document.createElement("textarea");E.style.fontSize="12pt",E.style.border="0",E.style.padding="0",E.style.margin="0",E.style.position="absolute",E.style[T?"right":"left"]="-9999px";var H=window.pageYOffset||document.documentElement.scrollTop;return E.style.top="".concat(H,"px"),E.setAttribute("readonly",""),E.value=j,E}var Y=function(T,E){var H=v(T);E.container.appendChild(H);var I=p()(H);return m("copy"),H.remove(),I},B=function(T){var E=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},H="";return typeof T=="string"?H=Y(T,E):T instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(T==null?void 0:T.type)?H=Y(T.value,E):(H=p()(T),m("copy")),H},N=B;function O(j){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?O=function(E){return typeof E}:O=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},O(j)}var Qe=function(){var T=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},E=T.action,H=E===void 0?"copy":E,I=T.container,q=T.target,Me=T.text;if(H!=="copy"&&H!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(q!==void 0)if(q&&O(q)==="object"&&q.nodeType===1){if(H==="copy"&&q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(H==="cut"&&(q.hasAttribute("readonly")||q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Me)return N(Me,{container:I});if(q)return H==="cut"?h(q):N(q,{container:I})},De=Qe;function $e(j){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?$e=function(E){return typeof E}:$e=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},$e(j)}function Ei(j,T){if(!(j instanceof T))throw new TypeError("Cannot call a class as a function")}function tn(j,T){for(var E=0;E0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof I.action=="function"?I.action:this.defaultAction,this.target=typeof I.target=="function"?I.target:this.defaultTarget,this.text=typeof I.text=="function"?I.text:this.defaultText,this.container=$e(I.container)==="object"?I.container:document.body}},{key:"listenClick",value:function(I){var q=this;this.listener=c()(I,"click",function(Me){return q.onClick(Me)})}},{key:"onClick",value:function(I){var q=I.delegateTarget||I.currentTarget,Me=this.action(q)||"copy",kt=De({action:Me,container:this.container,target:this.target(q),text:this.text(q)});this.emit(kt?"success":"error",{action:Me,text:kt,trigger:q,clearSelection:function(){q&&q.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(I){return vr("action",I)}},{key:"defaultTarget",value:function(I){var q=vr("target",I);if(q)return document.querySelector(q)}},{key:"defaultText",value:function(I){return vr("text",I)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(I){var q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return N(I,q)}},{key:"cut",value:function(I){return h(I)}},{key:"isSupported",value:function(){var I=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],q=typeof I=="string"?[I]:I,Me=!!document.queryCommandSupported;return q.forEach(function(kt){Me=Me&&!!document.queryCommandSupported(kt)}),Me}}]),E}(a()),Ai=Li},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,f){for(;a&&a.nodeType!==o;){if(typeof a.matches=="function"&&a.matches(f))return a;a=a.parentNode}}n.exports=s},438:function(n,o,i){var s=i(828);function a(u,p,m,d,h){var v=c.apply(this,arguments);return u.addEventListener(m,v,h),{destroy:function(){u.removeEventListener(m,v,h)}}}function f(u,p,m,d,h){return typeof u.addEventListener=="function"?a.apply(null,arguments):typeof m=="function"?a.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(v){return a(v,p,m,d,h)}))}function c(u,p,m,d){return function(h){h.delegateTarget=s(h.target,p),h.delegateTarget&&d.call(u,h)}}n.exports=f},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(n,o,i){var s=i(879),a=i(438);function f(m,d,h){if(!m&&!d&&!h)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(h))throw new TypeError("Third argument must be a Function");if(s.node(m))return c(m,d,h);if(s.nodeList(m))return u(m,d,h);if(s.string(m))return p(m,d,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(m,d,h){return m.addEventListener(d,h),{destroy:function(){m.removeEventListener(d,h)}}}function u(m,d,h){return Array.prototype.forEach.call(m,function(v){v.addEventListener(d,h)}),{destroy:function(){Array.prototype.forEach.call(m,function(v){v.removeEventListener(d,h)})}}}function p(m,d,h){return a(document.body,m,d,h)}n.exports=f},817:function(n){function o(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var f=window.getSelection(),c=document.createRange();c.selectNodeContents(i),f.removeAllRanges(),f.addRange(c),s=f.toString()}return s}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,s,a){var f=this.e||(this.e={});return(f[i]||(f[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var f=this;function c(){f.off(i,c),s.apply(a,arguments)}return c._=s,this.on(i,c,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),f=0,c=a.length;for(f;f{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var rs=/["'&<>]/;Yo.exports=ns;function ns(e){var t=""+e,r=rs.exec(t);if(!r)return t;var n,o="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function W(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var n=r.call(e),o,i=[],s;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)i.push(o.value)}catch(a){s={error:a}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(s)throw s.error}}return i}function D(e,t,r){if(r||arguments.length===2)for(var n=0,o=t.length,i;n1||a(m,d)})})}function a(m,d){try{f(n[m](d))}catch(h){p(i[0][3],h)}}function f(m){m.value instanceof et?Promise.resolve(m.value.v).then(c,u):p(i[0][2],m)}function c(m){a("next",m)}function u(m){a("throw",m)}function p(m,d){m(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function pn(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof Ee=="function"?Ee(e):e[Symbol.iterator](),r={},n("next"),n("throw"),n("return"),r[Symbol.asyncIterator]=function(){return this},r);function n(i){r[i]=e[i]&&function(s){return new Promise(function(a,f){s=e[i](s),o(a,f,s.done,s.value)})}}function o(i,s,a,f){Promise.resolve(f).then(function(c){i({value:c,done:a})},s)}}function C(e){return typeof e=="function"}function at(e){var t=function(n){Error.call(n),n.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var It=at(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(n,o){return o+1+") "+n.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function Ve(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Ie=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,n,o,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=Ee(s),f=a.next();!f.done;f=a.next()){var c=f.value;c.remove(this)}}catch(v){t={error:v}}finally{try{f&&!f.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var u=this.initialTeardown;if(C(u))try{u()}catch(v){i=v instanceof It?v.errors:[v]}var p=this._finalizers;if(p){this._finalizers=null;try{for(var m=Ee(p),d=m.next();!d.done;d=m.next()){var h=d.value;try{ln(h)}catch(v){i=i!=null?i:[],v instanceof It?i=D(D([],W(i)),W(v.errors)):i.push(v)}}}catch(v){n={error:v}}finally{try{d&&!d.done&&(o=m.return)&&o.call(m)}finally{if(n)throw n.error}}}if(i)throw new It(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)ln(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Ve(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Ve(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Sr=Ie.EMPTY;function jt(e){return e instanceof Ie||e&&"closed"in e&&C(e.remove)&&C(e.add)&&C(e.unsubscribe)}function ln(e){C(e)?e():e.unsubscribe()}var Le={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var st={setTimeout:function(e,t){for(var r=[],n=2;n0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,s=o.isStopped,a=o.observers;return i||s?Sr:(this.currentObservers=null,a.push(r),new Ie(function(){n.currentObservers=null,Ve(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,s=n.isStopped;o?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new F;return r.source=this,r},t.create=function(r,n){return new xn(r,n)},t}(F);var xn=function(e){ie(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Sr},t}(x);var Et={now:function(){return(Et.delegate||Date).now()},delegate:void 0};var wt=function(e){ie(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=Et);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,s=n._infiniteTimeWindow,a=n._timestampProvider,f=n._windowTime;o||(i.push(r),!s&&i.push(a.now()+f)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,s=o._buffer,a=s.slice(),f=0;f0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var s=r.actions;n!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==n&&(ut.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Wt);var Sn=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(Dt);var Oe=new Sn(wn);var M=new F(function(e){return e.complete()});function Vt(e){return e&&C(e.schedule)}function Cr(e){return e[e.length-1]}function Ye(e){return C(Cr(e))?e.pop():void 0}function Te(e){return Vt(Cr(e))?e.pop():void 0}function zt(e,t){return typeof Cr(e)=="number"?e.pop():t}var pt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Nt(e){return C(e==null?void 0:e.then)}function qt(e){return C(e[ft])}function Kt(e){return Symbol.asyncIterator&&C(e==null?void 0:e[Symbol.asyncIterator])}function Qt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function zi(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Yt=zi();function Gt(e){return C(e==null?void 0:e[Yt])}function Bt(e){return un(this,arguments,function(){var r,n,o,i;return $t(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,et(r.read())];case 3:return n=s.sent(),o=n.value,i=n.done,i?[4,et(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,et(o)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Jt(e){return C(e==null?void 0:e.getReader)}function U(e){if(e instanceof F)return e;if(e!=null){if(qt(e))return Ni(e);if(pt(e))return qi(e);if(Nt(e))return Ki(e);if(Kt(e))return On(e);if(Gt(e))return Qi(e);if(Jt(e))return Yi(e)}throw Qt(e)}function Ni(e){return new F(function(t){var r=e[ft]();if(C(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function qi(e){return new F(function(t){for(var r=0;r=2;return function(n){return n.pipe(e?A(function(o,i){return e(o,i,n)}):de,ge(1),r?He(t):Dn(function(){return new Zt}))}}function Vn(){for(var e=[],t=0;t=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new x}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,f=a===void 0?!0:a;return function(c){var u,p,m,d=0,h=!1,v=!1,Y=function(){p==null||p.unsubscribe(),p=void 0},B=function(){Y(),u=m=void 0,h=v=!1},N=function(){var O=u;B(),O==null||O.unsubscribe()};return y(function(O,Qe){d++,!v&&!h&&Y();var De=m=m!=null?m:r();Qe.add(function(){d--,d===0&&!v&&!h&&(p=$r(N,f))}),De.subscribe(Qe),!u&&d>0&&(u=new rt({next:function($e){return De.next($e)},error:function($e){v=!0,Y(),p=$r(B,o,$e),De.error($e)},complete:function(){h=!0,Y(),p=$r(B,s),De.complete()}}),U(O).subscribe(u))})(c)}}function $r(e,t){for(var r=[],n=2;ne.next(document)),e}function K(e,t=document){return Array.from(t.querySelectorAll(e))}function z(e,t=document){let r=ce(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ce(e,t=document){return t.querySelector(e)||void 0}function _e(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function tr(e){return L(b(document.body,"focusin"),b(document.body,"focusout")).pipe(ke(1),l(()=>{let t=_e();return typeof t!="undefined"?e.contains(t):!1}),V(e===_e()),J())}function Xe(e){return{x:e.offsetLeft,y:e.offsetTop}}function Kn(e){return L(b(window,"load"),b(window,"resize")).pipe(Ce(0,Oe),l(()=>Xe(e)),V(Xe(e)))}function rr(e){return{x:e.scrollLeft,y:e.scrollTop}}function dt(e){return L(b(e,"scroll"),b(window,"resize")).pipe(Ce(0,Oe),l(()=>rr(e)),V(rr(e)))}var Yn=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!Wr||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),va?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!Wr||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=ba.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),Gn=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),Jn=typeof WeakMap!="undefined"?new WeakMap:new Yn,Xn=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=ga.getInstance(),n=new La(t,r,this);Jn.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){Xn.prototype[e]=function(){var t;return(t=Jn.get(this))[e].apply(t,arguments)}});var Aa=function(){return typeof nr.ResizeObserver!="undefined"?nr.ResizeObserver:Xn}(),Zn=Aa;var eo=new x,Ca=$(()=>k(new Zn(e=>{for(let t of e)eo.next(t)}))).pipe(g(e=>L(ze,k(e)).pipe(R(()=>e.disconnect()))),X(1));function he(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ye(e){return Ca.pipe(S(t=>t.observe(e)),g(t=>eo.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),l(()=>he(e)))),V(he(e)))}function bt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function ar(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var to=new x,Ra=$(()=>k(new IntersectionObserver(e=>{for(let t of e)to.next(t)},{threshold:0}))).pipe(g(e=>L(ze,k(e)).pipe(R(()=>e.disconnect()))),X(1));function sr(e){return Ra.pipe(S(t=>t.observe(e)),g(t=>to.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),l(({isIntersecting:r})=>r))))}function ro(e,t=16){return dt(e).pipe(l(({y:r})=>{let n=he(e),o=bt(e);return r>=o.height-n.height-t}),J())}var cr={drawer:z("[data-md-toggle=drawer]"),search:z("[data-md-toggle=search]")};function no(e){return cr[e].checked}function Ke(e,t){cr[e].checked!==t&&cr[e].click()}function Ue(e){let t=cr[e];return b(t,"change").pipe(l(()=>t.checked),V(t.checked))}function ka(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Ha(){return L(b(window,"compositionstart").pipe(l(()=>!0)),b(window,"compositionend").pipe(l(()=>!1))).pipe(V(!1))}function oo(){let e=b(window,"keydown").pipe(A(t=>!(t.metaKey||t.ctrlKey)),l(t=>({mode:no("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),A(({mode:t,type:r})=>{if(t==="global"){let n=_e();if(typeof n!="undefined")return!ka(n,r)}return!0}),pe());return Ha().pipe(g(t=>t?M:e))}function le(){return new URL(location.href)}function ot(e){location.href=e.href}function io(){return new x}function ao(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)ao(e,r)}function _(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)ao(n,o);return n}function fr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function so(){return location.hash.substring(1)}function Dr(e){let t=_("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Pa(e){return L(b(window,"hashchange"),e).pipe(l(so),V(so()),A(t=>t.length>0),X(1))}function co(e){return Pa(e).pipe(l(t=>ce(`[id="${t}"]`)),A(t=>typeof t!="undefined"))}function Vr(e){let t=matchMedia(e);return er(r=>t.addListener(()=>r(t.matches))).pipe(V(t.matches))}function fo(){let e=matchMedia("print");return L(b(window,"beforeprint").pipe(l(()=>!0)),b(window,"afterprint").pipe(l(()=>!1))).pipe(V(e.matches))}function zr(e,t){return e.pipe(g(r=>r?t():M))}function ur(e,t={credentials:"same-origin"}){return ue(fetch(`${e}`,t)).pipe(fe(()=>M),g(r=>r.status!==200?Ot(()=>new Error(r.statusText)):k(r)))}function We(e,t){return ur(e,t).pipe(g(r=>r.json()),X(1))}function uo(e,t){let r=new DOMParser;return ur(e,t).pipe(g(n=>n.text()),l(n=>r.parseFromString(n,"text/xml")),X(1))}function pr(e){let t=_("script",{src:e});return $(()=>(document.head.appendChild(t),L(b(t,"load"),b(t,"error").pipe(g(()=>Ot(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(l(()=>{}),R(()=>document.head.removeChild(t)),ge(1))))}function po(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function lo(){return L(b(window,"scroll",{passive:!0}),b(window,"resize",{passive:!0})).pipe(l(po),V(po()))}function mo(){return{width:innerWidth,height:innerHeight}}function ho(){return b(window,"resize",{passive:!0}).pipe(l(mo),V(mo()))}function bo(){return G([lo(),ho()]).pipe(l(([e,t])=>({offset:e,size:t})),X(1))}function lr(e,{viewport$:t,header$:r}){let n=t.pipe(ee("size")),o=G([n,r]).pipe(l(()=>Xe(e)));return G([r,t,o]).pipe(l(([{height:i},{offset:s,size:a},{x:f,y:c}])=>({offset:{x:s.x-f,y:s.y-c+i},size:a})))}(()=>{function e(n,o){parent.postMessage(n,o||"*")}function t(...n){return n.reduce((o,i)=>o.then(()=>new Promise(s=>{let a=document.createElement("script");a.src=i,a.onload=s,document.body.appendChild(a)})),Promise.resolve())}var r=class extends EventTarget{constructor(n){super(),this.url=n,this.m=i=>{i.source===this.w&&(this.dispatchEvent(new MessageEvent("message",{data:i.data})),this.onmessage&&this.onmessage(i))},this.e=(i,s,a,f,c)=>{if(s===`${this.url}`){let u=new ErrorEvent("error",{message:i,filename:s,lineno:a,colno:f,error:c});this.dispatchEvent(u),this.onerror&&this.onerror(u)}};let o=document.createElement("iframe");o.hidden=!0,document.body.appendChild(this.iframe=o),this.w.document.open(),this.w.document.write(` + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

LiveHD and Pyrope

+

LiveHD is the compiler infrastructure that allows to work +with Hardware Description Languages (HDLs) like Verilog, CHISEL, and Pyrope.

+

Pyrope is the new HDL built on top of LiveHD.

+

Hardware Design provides an introduction to hardware design +for software designers.

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/javascripts/config.js b/javascripts/config.js new file mode 100644 index 0000000..60eda3e --- /dev/null +++ b/javascripts/config.js @@ -0,0 +1,17 @@ +window.MathJax = { + tex: { + inlineMath: [["\\(", "\\)"]], + displayMath: [["\\[", "\\]"]], + processEscapes: true, + processEnvironments: true + }, + options: { + ignoreHtmlClass: ".*|", + processHtmlClass: "arithmatex" + } +}; + +document$.subscribe(() => { + MathJax.typesetPromise() +}) + diff --git a/livehd/00-intro/index.html b/livehd/00-intro/index.html new file mode 100644 index 0000000..aeec43b --- /dev/null +++ b/livehd/00-intro/index.html @@ -0,0 +1,1045 @@ + + + + + + + + + + + + + + + + + + + + + + Introduction - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Introduction

+

LiveHD is an infrastructure designed for Live Hardware Development. By live, we +mean that small changes in the design should have the synthesis and simulation +results in a few seconds.

+

As the goal of "seconds," we do not need to perform too fine grain incremental +work. Notice that this is a different goal from having an typical incremental +synthesis, where many edges are added and removed in the order of thousands of +nodes/edges.

+

Goal

+

LiveHD: a fast and friendly hardware development flow that you can trust

+
    +
  • To be "Fast", LiveHD aims to be parallel, scalable, and incremental/live flow.
  • +
  • To be "friendly", LiveHD aims to build new models to have good error reporting.
  • +
  • To "trust", LiveHD has CI and many random tests with logic equivalence tests (LEC).
  • +
+

LiveHD Framework

+

LiveHD is optimized for synthesis and simulation. The main components of LiveHD +includes LGraph, LNAST, integrated 3rd-party tools, code generation, and "live" +techniques.

+

A compilation goes through the following steps:

+
    +
  • +

    Source code goes through a lexer/parser to create a parse tree or language specific AST.

    +
  • +
  • +

    The parse tree or language specific AST is translated to LNAST. LNAST is a +AST-like representation that it is independent of the specific language. +Pyrope, CHISEL, and Verilog translate to LNAST.

    +
  • +
  • +

    The are several passes on LNAST to infer the correct type and bitsizes. The goal is to +expand tuples, macros at LNAST level, but this code is still not finished.

    +
  • +
  • +

    The LNAST is a tree-like representation which is translated to Lgraph. In a +way, LNAST is a HIR (High-level IR) and Lgraph is a LIR (Low-level IR). For +each Lgraph node, there is an equivalent LNAST, but not the opposite.

    +
  • +
  • +

    LGraph has a hierarchical graph representation designed for fast synthesis +and simulation. It interfaces other tools like Yosys, ABC, OpenTimer, and +Mockturtle.

    +
  • +
  • +

    For code generation, it is possible to translate back to LNAST or to directly +output from Lgraph.

    +
  • +
+

LiveHD overall flow

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/livehd/01-install/index.html b/livehd/01-install/index.html new file mode 100644 index 0000000..932120e --- /dev/null +++ b/livehd/01-install/index.html @@ -0,0 +1,1090 @@ + + + + + + + + + + + + + + + + + + + + + + Installation - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Installation

+

This is a high level description of how to build LiveHD.

+

Requirements

+

Although LiveHD should run on most common Linux distributions, it is heavily tested on both Arch and Kali (Debian based).

+

The following programs are assumed to be present when building LiveHD:

+
    +
  • GCC 12+ or Clang 12+ (C++20 support is required)
  • +
  • Bazel
  • +
  • python3
  • +
+

It is also assumed that bash is used to compile LiveHD.

+

gcc and clang offers better warnings and execution speed dependent of the benchmark.

+

If you're unsure if your copy of gcc or clang is new enough, you can check the version by typing

+
g++ --version
+
+

or

+
clang++ --version
+
+

Steps

+

Download LiveHD source

+
git clone https://github.com/masc-ucsc/livehd
+
+

Install Bazelisk

+

Bazelisk is a wrapper around bazel that allows you to use a specific version.

+

If you do not have system permissions, you can install a local bazelisk

+
npm install  @bazel/bazelisk
+alias bazel=$(pwd)/node_modules/\@bazel/bazelisk/bazelisk.js
+
+

You can also install it directly if you have administrative permissions:

+

macos: +

brew install bazelisk.
+

+

Linux: +

npm install -g @bazel/bazelisk
+

+
go install github.com/bazelbuild/bazelisk@latest
+export PATH=$PATH:$(go env GOPATH)/bin
+
+

Arch linux: +

pacaur -S bazelisk  # or yay or paru installers
+

+

Build LiveHD

+

LiveHD has several build options, detailed below. All three should result in a working executable, but may differ in speed or output.

+

A binary will be created in livehd/bazel-bin/main/lgshell.

+
bazel build       //main:all # fast build, no debug symbols, slow execution (default)
+bazel build -copt //main:all # fastest execution speed, no debug symbols, no assertions
+bazel build -cdbg //main:all # moderate execution speed, debug symbols
+
+

Potential issues

+

If you have multiple gcc versions, you may need to specify the latest. E.g:

+
CXX=g++-8 CC=gcc-8 bazel build //main:all -c opt # fast execution for benchmarking
+CXX=g++-8 CC=gcc-8 bazel build //main:all -c dbg # debugging/development
+
+

If you want to run clang specific version:

+
CXX=clang++-10 CC=clang-10 bazel build //main:all -c dbg # debugging/development
+
+

Make sure that the openJDK installed is compatible with bazel and has the certificates to use tools. E.g in debian:

+
dpkg-reconfigure openjdk-11-jdk
+/var/lib/dpkg/ca-certificates-java.postinst configure
+
+

If you fail to build for the first time, you may need to clear the cache under your home directory before rebuilding:

+
rm -rf ~/.cache/bazel
+
+

Make sure to have enough memory (4+GB at least)

+

Next Steps

+

To start using LiveHD, check out Usage. If you're interested in working on LiveHD, refer to Creating a pass.

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/livehd/02-usage/index.html b/livehd/02-usage/index.html new file mode 100644 index 0000000..0fddf90 --- /dev/null +++ b/livehd/02-usage/index.html @@ -0,0 +1,1281 @@ + + + + + + + + + + + + + + + + + + + + + + Usage - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Usage

+

This is a high level description of how to use LiveHD.

+

Sample usage

+

Below are some sample usages of the LiveHD shell (lgshell). A bash prompt is +indicated by $, an lgshell prompt is indicated by livehd>, and a Yosys +prompt is indicated by a yosys>. Lgshell supports color output and +autocompletion using the tab key.

+

General concepts

+

Currently, LiveHD can interface Verilog, FIRRTL, and Pyrope HDLs through +different front-end commands. After the parsing step, the HDL source can +be be transformed into LiveHD's internal intermediate representations, LNAST and +LGraph, and perform mid-end optimizations based on the two IRs, and generates +the optimized (or synthesized) Verilog code at the back-end.

+

Starting and exiting the shell

+
$ ./bazel-bin/main/lgshell
+livehd> help
+  ...
+livehd> help pass.sample
+livehd> exit
+
+

Verilog Compilation

+

The following uses Verilog as the example to demonstrate the compilations +commands. It imports a Verilog file with a specified the database path, +translates to the LNAST IR, lowers the LNAST IR to LGraph IR, executes some +compiler optimizations, and generates the optimized Verilog code to the tmp +directory. By default, a database called lgdb will be set in the livehd +directory to store the internal representations, but users can optionally +specify a prefered path.

+
livehd> inou.liveparse path:/your/path/lgdb_foo files:/your/path/bar.v |> inou.verilog |> pass.lnast_tolg |> pass.cprop |> pass.bitwidth |> inou.cgen.verilog odir:tmp
+
+

A command lgraph.match can also be used to specify a (sub)hierarchy to operate +over, which can then be moved from pass to pass using the pipe (|>) operator.

+

When Verilog file(s) are compiled through a series of commands in lgshell, if a +problem occurs while compiling Verilog files (due to a syntax error, use of +un-synthesizable Verilog, or something else), the corresponding error will be +printed. Once a hierarchy has been created, other lgshell commands can read, +modify, or export this hierarchy freely.

+

Pyrope Compilation

+

The Pyrope compilation flow is similar to the Verilog commands except the +front-end Pyrope parser pass inou.pyrope

+
livehd> inou.pyrope path:/your/path/lgdb_foo files:/your/path/bar.prp |> pass.lnast_tolg |> pass.cprop |> pass.bitwidth |> inou.cgen.verilog odir:tmp
+
+

Additionally, users can compile a Pyrope code with a mid-end command of +pass.compiler which integrates standard compilation passes in LiveHD such as (1) +pass.lnast_tolg for IR lowering, (2) pass.cprop for legacy compiler +optimizations such as copy and constant propagation, peep-hole optimization, deadcode elimination, and high-level data-structure resolving (3) pass.bitwidth for circuit bitwidth optimization.

+
livehd> inou.pyrope path:/your/path/lgdb_foo files:/your/path/bar.prp |> pass.compiler |> inou.cgen.verilog odir:tmp
+
+

FIRRTL Compilation

+

LiveHD compiles FIRRTL code with the protocal buffer format. Users can reference +this doc +to generate the protocol buffers file from Chisel/FIRRTL compiler.

+

The LiveHD FIRRTL compiler uses a integrated mid-end commands as explained in +the previous Pyrope example to compiles the FIRRTL HDL. Set gviz option to +true to automatically generate the visiual Graphviz for individual steps. Set +hier option to true for hierarchical Chisel design in most cases. Specify the +top module name with the top option.

+
livehd> inou.firrtl.tolnast path:/your/path/lgdb_foo files:/your/path/bar.pb |> pass.compiler gviz:false top:top_module_name hier:true |> inou.cgen.verilog odir:tmp
+
+

Textual LNAST IR Dump

+

To display the content of the LNAST IR after parse (Pyrope as the example)

+

inou.pyrope files:foo.prp |> lnast.dump

+

Textual LGraph IR Dump

+

To display the content of the LGraph IR (Pyrope as the example)

+

inou.pyrope files:foo.prp |> pass.lnast_tolg |> lgraph.dump

+

LGraph serialization

+

To serialize the content of the LGraph IR (Pyrope as the example), default path is lgdb +inou.pyrope files:foo.prp |> pass.lnast_tolg |> lgraph.save

+

LGraph deserialization

+

To deserialize a stored LGraph, and pass it to some lgraph passes +lgraph.open name:foo |> pass.cprop |> pass.bitwidth |> inou.cgen.verilog odir:tmp

+

Graphviz LGraph IR Dump

+

To display the content of the LGraph IR (Pyrope after the cprop pass as the example) +inou.pyrope files:foo.prp |> pass.lnast_tolg |> pass.cprop |> inou.graphviz.from

+
    +
  • Print information about an existing LGraph: +
    $ ./bazel-bin/main/lgshell
    +livehd> inou.liveparse files:./inou/yosys/tests/trivial.v |> inou.verilog
    +livehd> lgraph.match |> lgraph.stats
    +livehd> lgraph.match |> lgraph.dump
    +
    + lgraph.match picks up any LGraphs matching the regex passed (or everything if no regex is provided) and treats every single one as the top of the hierarchy, whereas lgraph.open name:<root module> will just open the root module as the top of the hierarchy.
  • +
+

Running a custom pass

+
$ ./bazel-bin/main/lgshell
+livehd> inou.pyrope files:./inou/pyrope/tests/if1.prp
+livehd> lgraph.match |> <pass name>
+
+

Low level directed build

+
    +
  • To compile an individual pass: +
    $ bazel build -c dbg //pass/sample:pass_sample
    +$ bazel build -c dbg //inou/yosys:all
    +
  • +
  • To build a direct Yosys executable that has LiveHD embedded: +
    $ bazel build -c dbg //inou/yosys:all
    +$./bazel-bin/inou/yosys/yosys2
    +
  • +
+

Parallel Compilation

+

LiveHD support parallel compilation, it will set the thread number to the +highest available resources in your system. To manually set the compilation thread
+number, for example, 1, set the following environment variable +

export LIVEHD_THREADS=1
+

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/livehd/03-memory/index.html b/livehd/03-memory/index.html new file mode 100644 index 0000000..93a6e77 --- /dev/null +++ b/livehd/03-memory/index.html @@ -0,0 +1,1109 @@ + + + + + + + + + + + + + + + + + + + + + + Memory and concurrency - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Memory and concurrency

+

This section explains the memory management or garbage collect principles used +and the relationship with concurrency models.

+

Memory management models

+

Memory management in a multi-threaded environment main challenge arises from +deletes and additions that can trigger memory allocation/de-allocation. In +LiveHD, we address this problem the following way:

+
    +
  • +

    Only one thread can allocate/deallocate memory in an object at a given time. + To allow updates, a RW access is required. Otherwise, a RD access is enough. + Both return a std::unique_ptr. The API guarantees that only one thread can do + RW-access for a given object. Notice that the calling thread can have + multiple RD access and WR access to the same object simulnateusly. The check + is only against "other threads". There are 2 APIs:

    +
  • +
  • +

    ref_rd_snapshot(): gets a RD access, and an assertion checks that + there is no other thread has wr_snapshot during the lifetime of the + returned std::unique_ptr

    +
  • +
  • +

    ref_wr_snapshot(): gets a RW access, and an assertion checks that + there is no other thread has rd_snapshot during the lifetime of the + returned std::unique_ptr.

    +
  • +
+
+

Note

+

Updating an atomic counter inside an object does not require a RW-access, +but a rd_snapshot because it does not trigger memory +allocation/deallocation. Adding/deleting elements requires a wr_snapshot.

+
+
    +
  • +

    Creating an object requires a ref_wr_snapshot.

    +
  • +
  • +

    The only way to pass references across threads is with std::unique_ptr or + calling to the library which will create a std::unique_ptr.

    +
  • +
+
+

Note

+

If a std::unique_ptr created from a snapshot is passed to another thread, +the creator thread is still the owner of the thread pointer. If this is not +the intention, it may be safer for the new thread to call the library to +access ownership.

+
+

This approach is somewhat similar to a hazzard pointer. The snapshot API +indicates intention to modify (which can delete), but instead of failing with a +nullptr return, we trigger a compile failure because it should never be the +case. Each lgraph/lnast can be updated in parallel, but only if they are +independent. The assertion is to check that there is no bug.

+

LiveHD uses 3 main techniques to perform memory management.

+

RAII or std::unique_ptr

+

When an object is created and there is a single user, the code should use RAII +or std::unique_ptr. RAII means that when the object is out of scope, the memory +is recycled. std::unique_ptr will automatically call the destructor when the +reference use is zero.

+
    +
  • In LiveHD, RAII references should not be passed between threads.
  • +
  • std::unique_ptr can be passed between threads.
  • +
+

snapshot

+

For objects that can be shared across threads, the snapshot API must be used.

+

std::shared_ptr

+

std::shared_ptr is one of the "heavy" cost options for garbage collection. In +LiveHD, we do not use the atomic std::shared_ptr. The std::shared_ptr are NOT +allowed to be passed between threads. It is a memory management for data only +within a thread or compiler pass.

+

To avoid reference counting overheads, when passed to methods, a const +std::shared<XX> & should be used nearly in all the cases.

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/livehd/04-api/index.html b/livehd/04-api/index.html new file mode 100644 index 0000000..ac1ca2e --- /dev/null +++ b/livehd/04-api/index.html @@ -0,0 +1,986 @@ + + + + + + + + + + + + + + + + + + + + + + C++ API - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

C++ API

+

LiveHD is built on C++17, LGraph and LNAST are the two key data structures +inside LiveHD to support new hardware design.
+* LGraph stands for Live Graph. It is graph or netlist data + structure at the core of LiveHD. +* LNAST stands for Language Neutral AST. It is an Abstract + Syntax Tree (AST) designed to be simple but to allow the translation from + multiple languages like CHIRRTL, Verilog, and Pyrope.

+

While LNAST could be seen as a high level API with control flow information, +LGraph is a lower level graph API where many LNAST high level constructs are +simplified.

+

There is a division of functionality between LNAST and LGraph:

+
    +
  • +

    LNAST: Language Neutral AST, the high level tree based representation/API

    +
      +
    • Bundles:
        +
      • Flatten fields (only flat attributes passed to LGraph)
      • +
      • Find IOs (inputs and outputs). Populate the sub_node accordingly.
      • +
      • Detect as array if legal bundle index.
      • +
      +
    • +
    • Constant propagation (comptime decision)
    • +
    • Linear time compiler passes (dead code elimination, constant folding) but not complex (GVN, SAT...)
    • +
    • Lgraph creation
        +
      • Inline small LNASTs
      • +
      • Partition too large LGraphs
      • +
      +
    • +
    • Type checking
    • +
    • Unroll for and while loops
    • +
    +
  • +
  • +

    LGraph: Live Graph, the low level graph/netlist level based representation/API

    +
      +
    • Attributes
        +
      • Bitwidth
      • +
      • Debug flag
      • +
      +
    • +
    • Complex optimizations
        +
      • cprop (Peephole, constant folding, ...)
      • +
      • lecopt, Logic Equivalence based optimizations
      • +
      • synthesis
      • +
      +
    • +
    +
  • +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/livehd/05-lgraph/index.html b/livehd/05-lgraph/index.html new file mode 100644 index 0000000..a5a9f24 --- /dev/null +++ b/livehd/05-lgraph/index.html @@ -0,0 +1,2614 @@ + + + + + + + + + + + + + + + + + + + + + + LGraph - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

LGraph

+
+

Warning

+

LiveHD is beta under active development and we keep improving the +API. Semantic versioning is a 0.+, significant API changes are expect.

+
+

The LGraph is built directly through LNAST to LGraph translations. The LNAST +builds a gated-SSA which is translated to LGraph. Understanding the LGraph is +needed if you want to build a LiveHD pass.

+

LGraph is a graph or netlist where each vertex is called a node, and it has a +cell type and a set of input/output pins.

+

API

+

A single LGraph represents a single netlist module. LGraph is composed of +nodes, node pins, edges, cell types, and tables of attributes. An LGraph node +is affiliated with a cell node type and each type defines different amounts of input +and output node pins. For example, a node can have 3 input ports and 2 output +pins. Each of the input/output pins can have many edges to other graph nodes. +Every node pin has an affiliated node pid. In the code, every node_pin has a +Port_ID.

+

A pair of driver pin and sink pin constitutes an edge. The bitwidth of the +driver pin determines the edge bitwidth.

+

Node, Node_pin, and Edge Construction

+
    +
  • create a node without associated type (edges can not be created until a type is associated)
  • +
+
new_node = lg->create_node()
+//note: type and/or bits still need to be assigned later
+
+
    +
  • create node with node type assigned
  • +
+
new_node = lg->create_node(Node_type_Op)
+//note: recommended way if you know the target node type
+
+
    +
  • create a constant node
  • +
+
new_node = lg->create_node_const(value)
+//note: recommended way to create a const node
+
+
    +
  • setup default driver pin for pin_0 of a node
  • +
+
driver_pin = new_node.setup_driver_pin();
+//note: every cell in LGraph has only one driver pin, pin0
+
+
    +
  • setup default sink pin for pin_0 of a node
  • +
+
sink_pin = new_node.setup_sink_pin()
+//note: when you know the node type only has one input pin
+
+
    +
  • +

    setup sink pin for pin_x of a node, for more information, please refer to the + Cell type section. For quick reference of the sink pin names of each cell + type, please see + cell.cpp +

    sink_pin = new_node.setup_sink_pin("some_name")
    +

    +
  • +
  • +

    add an edge between driver_pin and sink_pin

    +
  • +
+
driver_pin.connect(sink_pin);
+
+
    +
  • get the driver node of an edge
  • +
+
driver_node = edge.driver.get_node()
+
+
    +
  • use node as the index/key for a container
  • +
+
absl::flat_hash_map<Node::Compact, int> my_map;
+my_map[node1.get_compact()] = 77;
+my_map[node2.get_compact()] = 42;
+...
+
+
    +
  • use node_pin as the index/key for a container
  • +
+
absl::flat_hash_map<Node_pin::Compact, int> my_map;
+my_map[node_pin1.get_compact()] = 14;
+my_map[node_pin2.get_compact()] = 58;
+...
+
+
    +
  • get the node_pin back from a Node_pin::Compact
  • +
+
Node_pin dpin(lg, some_dpin.get_compact())
+
+
    +
  • get the node back from a Node::Compact
  • +
+
Node node(lg, some_node.get_compact())
+
+
    +
  • create a LGraph input(output) with the name
  • +
+
new_node_pin = lg->add_graph_input(std::string_view)
+
+
    +
  • debug information of a node
  • +
+
node.debug_name()
+
+
    +
  • debug information of a node_pin
  • +
+
node_pin.debug_name()
+
+
    +
  • iterate output edges and get node/pin information from it
  • +
+
for (auto &out : node.out_edges()) {
+  auto  dpin       = out.driver;
+  auto  dpin_pid   = dpin.get_pid();
+  auto  dnode_name = dpin.get_node().debug_name();
+  auto  snode_name = out.sink.get_node().debug_name();
+  auto  spin_pid   = out.sink.get_pid();
+  auto  dpin_name  = dpin.has_name() ? dpin.get_name() : "";
+  auto  dbits      = dpin.get_bits();
+
+  fmt::print(" {}->{}[label=\"{}b :{} :{} :{}\"];\n"
+      , dnode_name, snode_name, dbits, dpin_pid, spin_pid, dpin_name);
+}
+
+

Non-Hierarchical Traversal Iterators

+

LGraph allows forward and backward traversals in the nodes (bidirectional +graph). The reason is that some algorithms need a forward and some a backward +traversal, being bidirectional would help. Whenever possible, the fast iterator +should be used.

+
for (const auto &node:lg->fast())     {...} // unordered but very fast traversal
+
+for (const auto &node:lg->forward())  {...} // propagates forward from each input/constant
+
+for (const auto &node:lg->backward()) {...} // propagates backward from each output
+
+

The LGraph iterator such as for(auto node: g->forward()) do not visit graph +input and outputs.

+
// simple way using lambda
+lg->each_graph_input([&](const Node_pin &pin){
+
+  //your operation with graph_input node_pin;
+
+});
+
+

Hierarchical Traversal Iterators

+

LGraph supports hierarchical traversal. Each sub-module of a hierarchical +design will be transformed into a new LGraph and represented as a sub-graph node +in the parent module. If the hierarchical traversal is used, every time the +iterator encounters a sub-graph node, it will load the sub-graph persistent +tables to the memory and traverse the subgraph recursively, ignoring the +sub-graph input/outputs. This cross-module traversal treats the hierarchical +netlist just like a flattened design. In this way, all integrated third-party +tools could automatically achieve global design optimization or analysis by +leveraging the LGraph hierarchical traversal feature.

+
for (const auto &node:lg->forward(true)) {...}
+
+

Edge Iterators

+

To iterate over the input edges of node, simply call:

+
for (const auto &inp_edge : node.inp_edges()) {...}
+
+

And for output edges:

+
for (const auto &out_edge : node.out_edges()) {...}
+
+

Attribute Design

+

Design attribute stands for the characteristic given to a LGraph node or node +pin. For instance, the characteristic of a node name and node physical +placement. Despite a single LGraph stands for a particular module, it could be +instantiated multiple times. In this case, same module could have different +attribute at different hierarchy of the netlist. A good design of attribute +structure should be able to represent both non-hierarchical and hierarchical +characteristic.

+

Non-Hierarchical Attribute

+

Non-hierarchical LGraph attributes include pin name, node name and line of +source code. Such properties should be the same across different LGraph +instantia- tions. Two instantiations of the same LGraph module will have the +exact same user-defined node name on every node. For example, instantiations of +a subgraph-2 in both top and subgraph-1 would maintain the same non-hierarchical +attribute table.

+
node.set_name(std::string_view name);
+
+

Hierarchical attribute

+

LGraph also support hierarchical attribute. It is achieved by using a tree data +structure to record the design hierarchy. In LGraph, every graph has a unique +id (lg_id), every instantiation of a graph would form some nodes in the tree and +every tree node is indexed by a unique hierarchical id (hid). We are able to +identify a unique instantiation of a graph and generate its own hierarchical +attribute table. An example of hierarchical attribute is wire-delay.

+
node_pin.set_delay(float delay);
+
+

Cell type

+

For each LGraph node, there is a specific cell type. This section explains the +operation to perform for each node. It includes a precise way to compute the +maximum and minimum value for the output.

+

In LGraph, the cell types operate like having unlimited precision with signed +numbers. Most HDL IRs have a type for signed inputs and another for unsigned. +LiveHD handles the superset (sign and unlimited precision) with a single node. +In LGraph, an unsigned value is signed value that is always positive. This +simplifies the mixing and conversions which simplifies the passes. The drawback +is that the export may have to convert back to signed/unsigned for some +languages like Verilog.

+

Maybe even more important is that all the LGraph cell types generate the same +result if the input is sign-extended. This has implications, for example a +typical HDL IR type like "concat" does not exist because the result is +dependent on the inputs size. This has the advantage of simplifying the +decisions of when to drop bits in a value. It also makes it easier to guarantee +no loss of precision. Any drop of precision requires explicit handling with +operations like and-gate with masks or Shifts.

+

The document also explains corner cases in relationship to Verilog and how to +convert to/from Verilog semantics. These are corner cases to deal with sign and +precision. Each HDL may have different semantics, the Verilog is to showcase +the specifics because it is a popular HDL.

+

All the cell types are in core/cell.hpp and core/cell.cpp. The type +enumerate is called Ntype. In general the nodes have a single output with the +exception of complex nodes like subgraphs or memories. The inputs is a string in +lower case or upper case. Upper case ('A') means that many edges (or output +drivers) can connect to the same node input or sink pin, lower case ('a') means +that only a driver can connect to the input or sink pin.

+

Each cell type can be called directly with Pyrope using a low level RTL syntax. +This is useful for debugging not for general use as it can result in less +efficient LNAST code.

+

An example of a multi-driver sink pin is the Sum cell which can do Y=3+20+a0+a3 +where A_{0} = 3, A_{1} = 20, A_{2} = a0, and A_{3} = a3. Another way to +represent in valid Pyrope RTL syntax is:

+
Y = __sum(A=(3,20,a0,a3))
+
+

An example if single driver sink pin is the SRA cell which can do Y=20>>3. +It is lower case because only one driver pin can connect to 'a' and 'b'. Another way +to represent a valid Pyrope RTL syntax is:

+
Y = __sra(a=20,b=3)
+
+

The section includes description on how to compute the maximum (max) and +minimum (min) allowed result range. This is used by the bitwidth inference +pass. To ease the explanation, a sign value means that the result may be +negative (a.sign == a.min<0). known is true if the result sign is known +(a.known == a.max<0 or a.min>=0), either positive or negative (neg == +a.max<0). The cells explanation also requires the to compute the bit mask +(a.mask == (1<<a.bits)-1).

+

For any value (a), the number of bits required (bits) is a.bits = log2(absmax(a.max,a.min))+1.

+

Sum

+

Addition and substraction node is a single cell Ntype that performs +2-complement additions and substractions with unlimited precision.

+
graph LR + cell --Y--> c(fa:fa-spinner) + a(fa:fa-spinner) --A--> cell[Sum]:::cell + b(fa:fa-spinner) --B--> cell + classDef cell stroke-width:3px +
+

If the inputs do not have the same size, they are sign extended to all have the +same length.

+

Forward Propagation

+
    +
  • Value: +
    %Y = A.reduce('+') - B.reduce('+')
    +
  • +
  • Max/min: +
    %max = 0
    +%min = 0
    +for a in A {
    +  %max += A.max
    +  %min += A.min
    +}
    +for b in B {
    +  %max -= b.min
    +  %min -= b.max
    +}
    +
  • +
+

Backward Propagation

+

Backward propagation is possible when all the inputs but ONE are known. The +algorithm can check and look for the inputs that have more precision than +needed and reduce the max/min backwards.

+

For example, if and all the inputs but one A are known (max/min has the max/min +computed for all the inputs but the unknown one)

+
A_{unknown}.max = Y.max - max 
+A_{unknown}.min = Y.min - min 
+
+

If the unknow is in port B:

+
B_{unknown}.max = min - T.min
+B_{unknown}.min = max - Y.max
+
+

Verilog Considerations

+

In Verilog, the addition is unsigned if any of the inputs is unsigned. If any +input is unsigned. all the inputs will be "unsigned extended" to match the +largest value. This is different from Sum_Op semantics were each input is +signed or unsigned extended independent of the other inputs. To match the +semantics, when mixing signed and unsigned, all the potentially negative inputs +must be converted to unsign with the Ntype_op::Tposs.

+
logic signed [3:0] a = -1
+logic signed [4:0] c;
+
+assign c = a + 1'b1;
+
+

The previous Verilog example extends everything to 5 bits (c) UNSIGNED extended +because one of the inputs is unsigned (1b1 is unsigned in verilog, and 2sb1 is +signed +1). LGraph semantics are different, everything is signed.

+
c = 5b01111 + 5b0001 // this is the Verilog semantics by matching size
+c == -16 (!!)
+
+

The Verilog addition/substraction output can have more bits than the inputs. +This is the same as in LGraph Sum. Nevertheless, Verilog requires to specify +the bits for all the input/outputs. This means that whenever Verilog drops +precision an AND gate must be added (or a SEXT for signed output). In the +following examples only the 'g' and 'h' variables needed.

+
  wire [7:0] a;
+  wire [7:0] b;
+  wire [6:0] c;
+  wire [8:0] f = a + b; // f = __sum(a,b)  // a same size as b
+  wire [8:0] f = a + c; // f = __sum(a,__get_mask(c,-1))
+  wire [7:0] g = a + b; // g = __and(__sum(a,b),0x7F)
+  wire [6:0] h = a + b; // h = __and(__sum(a,b),0x3F)
+
+

Peephole Optimizations

+
    +
  • Y = x-0+0+... becomes Y = x+...
  • +
  • Y = x-x+... becomes Y = ...
  • +
  • Y = x+x+... becomes Y = (x<<1)+...
  • +
  • Y = (x<<n)+(y<<m) where m>n becomes Y = (x+y<<(m-n)<<n
  • +
  • Y = (~x)+1+... becomes Y = ...-x
  • +
  • Y = a + (b<<n) becomes Y = {(a>>n)+b, a&n.mask}
  • +
  • Y = a - (b<<n) becomes Y = {(a>>n)-b, a&n.mask}
  • +
  • If every x,y... lower bit is zero Y=x+y+... becomes Y=((x>>1)+(y>>1)+..)<<1
  • +
+

Mult

+

Multiply operator. There is no cell type that combines multiplication and +division because unlike in Sum. The reason is that with integers the order of multiplication/division changes +the result even with unlimited precision integers (a*(b/c) != (a*b)/c).

+
graph LR + cell --Y--> c(fa:fa-spinner) + a(fa:fa-spinner) --A--> cell[Mult]:::cell + classDef cell stroke-width:3px +
+

Forward Propagation

+
    +
  • Value: +
    Y = A.reduce('*')
    +
  • +
  • Max/min: +
    var tmax = 1
    +vat tmin = 1
    +var sign  = 0
    +for i in A {
    +  tmax *= maxabs(A.max, A.min)
    +  tmin *= minabs(A.max, A.min)
    +  known = false                when min<0 and max>0
    +  sign += 1                    when max<0
    +}
    +if know { // sign is know
    +  if sign & 1 { // negative
    +    %max = -tmin
    +    %min = -tmax
    +  }else{
    +    %max = tmax
    +    %min = tmin
    +  }
    +}else{
    +  %max =  tmax
    +  %min = -tmax
    +}
    +
  • +
+

Backward Propagation

+

If only one input is missing, it is possible to infer the max/min from the +output and the other inputs. Like in the sum case, if all the inputs but one +and the output is known, it is possible to backward propagate to further +constraint the unknown input.

+
A_{unknown}.max = Y.max / A.min
+A_{unknown}.min = Y.min / A.max
+
+

Verilog Considerations

+

Unlike the Sum, the Verilog 2 LiveHD translation does not need to extend the +inputs to have matching sizes. Multiplying/dividing signed and unsigned numbers +has the same result. The bit representation is the same if the result was +signed or unsigned.

+

LiveHD mult node result (Y) number of bits can be more efficient than in +Verilog. E.g: if the max value of A0 is 3 (2 bits) and A1 is 5 (3bits). If the +result is unsigned, the maximum result is 15 (4 bits). In Verilog, the result +will always be 5 bits. If the Verilog result was to an unsigned variable. +Either all the inputs were unsigned, or there should pass to an get_mask to +force the MSB as positive. This extra bit will be simplified but it will notify +LGraph that the output is to be treated as unsigned.

+

Peephole Optimizations

+
    +
  • Y = a*1*... becomes Y=a*...
  • +
  • Y = a*0*... becomes Y=0
  • +
  • Y = power2a*... becomes Y=(...)<<log2(power2a)
  • +
  • Y = (power2a+power2b)*... becomes tmp=... ; Y = (tmp+tmp<<power2b)<<(power2a-power2b) when power2a>power2b
  • +
  • Y = (power2a-power2b)*... becomes tmp=... ; Y = (tmp-tmp<<power2b)<<(power2a-power2b) when power2a>power2b
  • +
+

Div

+

Division operator. The division operation is quite similar to the inverse of +the multiplication, but a key difference is that only one driver is allowed for +each input ('a' vs 'A').

+
graph LR + cell --Y--> c(fa:fa-spinner) + a(fa:fa-spinner) --a--> cell[Div]:::cell + b(fa:fa-spinner) --b--> cell + classDef cell stroke-width:3px +
+

Forward Propagation

+
    +
  • Value: +
    Y = a/b
    +
  • +
  • Max/min: +
    %max = a.max/b.min
    +%min = a.min/b.max
    +
    +for i in a.max,a.min {
    +  for j in b.max,b.min {
    +     next        when j == 0
    +     tmp = i / j
    +     %max = tmp   when tmp > max
    +     %min = tmp   when tmp < min
    +  }
    +}
    +
  • +
+

Backward Propagation

+

The backward propagation from the division can extracted from the forward +propagation. It is a simpler case of multiplication backward propagation.

+

Verilog Considerations

+

The same considerations as in the multiplication should be applied.

+

Peephole Optimizations

+
    +
  • Y = a/1 becomes Y=a
  • +
  • Y = 0/b becomes Y=0
  • +
  • Y = a/power2b becomes Y=a>>log2(power2b) if Y.known and !Y.neg
  • +
  • Y = a/power2b becomes Y=1+~(a>>log2(power2b)) if Y.known and Y.neg
  • +
  • Y = (x*c)/a if c.bits>a.bits becomes Y = x * (c/a) which should be a smaller division.
  • +
  • If b is a constant and Y.known and !Y.neg. From the hackers delight, we
  • +
  • know that the division can be changed for a multiplication
  • +
  • Y=(a*(((1<<(a.bits+2)))/b+1))>>(a.bits+2) If a sign is not known. Then `Y
  • +
  • = Y.neg? (~Y_unsigned+1):Y_unsigned`
  • +
+

Modulo (how to model)

+

There is no mod cell (Ntype_op::Mod) in LGraph. The reason is that a modulo +different from a power of 2 is very rare in hardware. If the language supports +modulo operations, they must be translated to division/multiplication.

+
y = a mod b
+
+

It is the same as:

+
y = a-b*(a/b)
+
+

If b is a power of 2, the division optimization will transform the modulo operation to:

+
y = a - (a>>n)<<n
+
+

The add optimization should reduce it to:

+
y = a & n.mask
+
+

Not

+

Bitwise Not operator

+
graph LR + cell --Y--> c(fa:fa-spinner) + a(fa:fa-spinner) --a--> cell[Div]:::cell + classDef cell stroke-width:3px +
+

Forward Propagation

+
    +
  • Value: +
    Y = ~a
    +
  • +
  • Max/min: +
    %max = max(~a.max,~a.min)
    +%min = min(~a.max,~a.min)
    +
  • +
+

Backward Propagation

+
a.max = max(~Y.max,~Y.min)
+a.min = min(~Y.max,~Y.min)
+
+

Verilog Considerations*

+

Same semantics as verilog

+

Peephole Optimizations

+

No optimizations by itself, it has a single input. Other operations like Sum_Op can optimize when combined with Not_Op.

+

And

+

And is a typical AND gate with multiple inputs. All the inputs connect to pin +'A' because input order does not matter. The result is always a signed number.

+
digraph And {
+    rankdir=LR;
+    size="1,0.5"
+
+    node [shape = circle]; And;
+    node [shape = point ]; q0
+    node [shape = point ]; q
+
+    q0 -> And [ label ="A" ];
+    And  -> q [ label = "Y" ];
+}
+
+

Forward Propagation

+
    +
  • \(Y = \forall_{i=0}^{\infty} Y \& A_{i}\)
  • +
  • \(m = \forall_{i=0}^{\infty} min(m,A_{i}.bits)\)
  • +
  • \(Y.max = (1\ll m)-1\)
  • +
  • \(Y.min = -Y.max-1\)
  • +
+

Backward Propagation

+

The And cell has a significant backpropagation impact. Even if some inputs had +more bits, after the And cell the upper bits are dropped. This allows the back +propagation to indicate that those bits are useless.

+
    +
  • $a.max = Y.max $
  • +
  • $a.min = -Y.max-1 $
  • +
+

Other Considerations

+

Peephole Optimizations

+

Comparators

+

LT, GT, EQ

+

There are only 3 comparators. Other typically found like LE, GE, and NE can be +created by simply negating one of the LGraph comparators. GT = ~LE, LT = ~GE, and NE = ~EQ.

+

Forward Propagation

+
    +
  • +

    Y = A LT B

    +
  • +
  • +

    Y = A0 LT B and A1 LT B

    +
  • +
  • +

    Y = A0 LT B0 and A1 LT B0 and A0 LT B1 and A1 LT B1

    +
  • +
+

Backward Propagation

+

Peephole Optimizations

+

Other Considerations

+

Verilog treats all the inputs as unsigned if any of them is unsigned. LGraph treats all the inputs as signed all the time.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
sizeABOperation
a==bSSEQ(a,b)
a==bSUEQ(a,b)
a==bUSEQ(a,b)
a==bUUEQ(a,b)
a< bSSLT(a,b)
a< bSULT(a,Tposs(b))
a< bUSLT(Tposs(a),b)
a< bUULT(Tposs(a),Tposs(b))
+

SHL_op

+

Shift Left performs the typical shift left when there is a single amount +(a<<amt). The allow supports multiple left shift amounts. In this case the +shift left is used to build one hot encoding mask. (1<<(1,2) == (1<<1)|(1<<2))

+

The result for when there are not amounts (a<<()) is -1. Notice that this +is not ZERO but -1. The -1 means that all the bits are set. The reason is that +when there are no offsets in the onehot encoding, the default functionality is +to select all the bit masks, and hence -1.

+

SRA_op

+

Logical or sign extension shift right.

+

Verilog Considerations

+

Verilog has 2 types of shift >> and >>>. The first is unsigned right shift, +the 2nd is arithmetic right shift. LGraph only has arithmetic right shift +(ShiftRigt_op). The verilog translation should make the value unsigned +(ShiftRigt(Join(0,a),b)) before calling the shift operation. Conversely, for +a >>> if the input is Verilog unsigned (ShiftRigt(a,b))

+

Mux_op

+

Forward Propagation

+
    +
  • \(Y = P_{(1+P_{0}}\)
  • +
  • \(Y.max = (1\ll m)-1\)
  • +
  • \(Y.max = \forall_{i=0}^{\infty} P_{i}.max\)
  • +
  • \(Y.max = \forall_{i=0}^{\infty} P_{i}.min\)
  • +
+

Backward Propagation

+

Peephole Optimizations

+

Other Considerations

+

LUT_op

+

And_op

+

reduce AND a =u= -1 // unsigned equal

+

Or_op

+

reduce OR a != 0

+

Xor_op

+

reduce xor is a chain of XORs.

+

Const_op

+

SFlop_op

+

AFlop_op

+

FFlop_op

+

Latch_op

+

Get_mask_op

+

Inputs - a, mask +Get_mask (a, mask) +Functionality - Output contains only those bits a[i], for which mask[i] = 1, other bits a[i] for which mask[i] = 0, are dropped. +a & mask are interpreted as signed numbers and sign extended to the size of the other, if required. +eg - Get_mask (0sb11000011, 0sb10101010) = 0sb1001 + Get_mask (0sb11110000, 0sb00001111) = 0sb0000 + Get_mask (0sb0011, 0sb10) = 0sb001 + Get_mask (0sb10, 0sb1010) = 0sb11

+

Set_mask_op

+

Inputs - a, value, mask +Set_mask(a, mask, value) +Functionality - Replaces all bits a[i] for which mask[i] = 1, with value[i] +Retains all bits a[i] for which mask[i] = 0. +// Check - if a, value are signed, actually none of them should be extended and their signs should not matter, but a might need to retain it's sign +eg - Set_mask (0b101 01 010, 0sb000 11 000, 0b001 10 011) = 0sb 101 10 010

+

Sext_op (Sign extend)

+

Inputs - a, b +Sext (a, b) +Selects only bits a[b:0] dropping all remaining MSBs. +The selected a[b:0] is interpretded as a signed value, a's sign does not matter,b conyains the MSB index and hence is always unsigned/ positive +eg Sext (0b10101010, 4) = 0sb01010 = 0xA = +10 +Sext (0b10101010, 5) = 0sb101010 = 0x2A = -22

+

Memory_op

+

Memory is the basic block to represent SRAM-like structures. Any large storage will benefit from using memory arrays instead of flops, which are slower to simulate. These memories are highly configurable.

+
digraph Memory {
+    rankdir=LR;
+    size="2,1"
+
+    node [shape = circle]; Memory;
+    node [shape = point ]; q0
+    node [shape = point ]; q1
+    node [shape = point ]; q2
+    node [shape = point ]; q3
+    node [shape = point ]; q4
+    node [shape = point ]; q5
+    node [shape = point ]; q6
+    node [shape = point ]; q7
+    node [shape = point ]; q8
+    node [shape = point ]; q9
+    node [shape = point ]; q10
+    node [shape = point ]; q
+
+    q0 -> Memory [ label ="a (addr)" ];
+    q1 -> Memory [ label ="b (bits)" ];
+    q2 -> Memory [ label ="c (clock)" ];
+    q3 -> Memory [ label ="d (data in)" ];
+    q4 -> Memory [ label ="e (enable)" ];
+    q5 -> Memory [ label ="f (fwd)" ];
+    q6 -> Memory [ label ="l (latency)" ];
+    q7 -> Memory [ label ="m (wmask)" ];
+    q8 -> Memory [ label ="p (posedge)" ];
+    q9 -> Memory [ label ="s (size)" ];
+    q10 -> Memory [ label ="w (wmode)" ];
+    Memory  -> q [ label ="Q (data out)" ];
+}
+
+
    +
  • s (size) is for the array size in number of entries
  • +
  • b (bits) is the number of bits per entry
  • +
  • f (fwd) points to a 0/1 constant driver pin to indicate if writes forward value (0b0 for write-only ports). Effectively, it means zero cycles read latency when enabled. fwd is more than just setting latency=0. Even with latency zero, the write delay affects until the result is visible. With fwd enabled, the write latency does not matter to observe the results. This requires a costly forwarding logic.
  • +
  • c,d,e,q... are the memory configuration, data, address ports
  • +
+

Ports (a,c...p,w) are arrays/vectors to support multiported memories. If a single instance +exists in a port, the same is used across all the ports. E.g: if clock (c) is populated:

+
mem1.c = clk1 // clk for all the memory ports
+
+mem2.c[0] = clk1 // clock for memory port 0
+mem2.c[1] = clk2 // clock for memory port 1
+mem2.c[2] = clk2 // clock for memory port 2
+
+

Each memory port (rd, wr, or rd/wr) has the following ports:

+
    +
  • a (addr) points to the driver pin for the address. The address bits should match the array size (ceil(log2(s)))
  • +
  • c (clock) points to the clock driver pin
  • +
  • d (data_in) points to the write data driver pin (read result is in q port).
  • +
  • e (enable) points to the driver pin for read/write enable.
  • +
  • l (latency) points to an integer constant driver pin (2 bits always). For writes latency from 1 to 3, for reads latency from 0 to 3
  • +
  • w (wmask) Points to the write mask (1 == write, 0==no write). The mask bust be a big as the number of bits per entry (b). The wmask pin can be disconnected which means no write mask (a write will write all the bits).
  • +
  • p (posedge) points to a 1/0 constant driver pin
  • +
  • m (mode) points to the driver pin or switching between read (0) and write mode (1) (single bit)
  • +
  • Q (data_out) is a driver pin with the data read from the memory
  • +
+

All the entries but the wmask must be populated. If the wmask is not set, a +full write size is expected. Read-only ports do not have data and wmask +fields if the write use the low ports (0,1...). By placing the read-only ports +to the high numbers, we can avoid populating the wmask (m) and data out (q) +ports. If the read ports use low port numbers those fields must be populated to +allow the correct matching between write port (a[n]) and write result +(q[n]).

+

All the ports must be populated with the correct size. This is important +because some modules access the field by bit position. +If it is not used, it will point to a zero constant with the correct number of bits. +The exception to this is wmask which, if b indicates 8 bits per entry, +will be equivalent to 0xFF. Setting wmask to 0b1 will mean a 1 bit zero, +and the memory will be incorrectly operated.

+

The memory usually has power of two sizes. If the size is not a power of 2, the +address is rounded up. Writes to the invalid addresses will generated random +memory updates. Reads should read random data.

+

Forward Propagation

+

Backward Propagation

+

Other Considerations

+

Peephole Optimizations

+

SubGraph_op

+

And_Op: bitwise AND with 2 outputs single bit reduction (RED) or bitwise +Y = VAL&..&VAL ; RED= &Y

+

Forward Propagation

+
    +
  • \(Y = \left\{\begin{matrix} VAL>>OFF & SZ==0 \\ (VAL>>OFF) \& (1<<SZ)-1) & otherwise \end{matrix}\right.\)
  • +
  • \(Y.max = \left\{\begin{matrix} VAL.max>>OFF & SZ==0 \\ (VAL.max>>OFF) \& (1<<SZ)-1) & otherwise \end{matrix}\right.\)
  • +
  • \(Y.min = 0\)
  • +
  • \(Y.sign = 0\)
  • +
+

Backward Propagation

+

The sign can not be backward propagated because Pick_Op removes the sign no matter the input sign.

+

To be continued ...

+

Optimization

+

Not all the nodes have the same complexity overhead. When performing peephole +optimization is possible to trade one set of nodes for others. In general, +we have this set of overheads:

+
    +
  • +

    0 overhead: not, get_mask, set_mask, sext, and SHL/SRA with constant shift + amounts. The rational is that those are just "wiring" cells to connect or + extract wires across. The NOT gate is not really zero, but it could be easily + mixed with sorrounding cells.

    +
  • +
  • +

    1 overhead: And, Or, Xor, LUT, Mux

    +
  • +
  • +

    3 overhead: LT, GT, EQ, Ror

    +
  • +
  • +

    4 overhead: Less than 4 bit output Sum, and SHL/SRA with non-compile time + shift amount. This can be costly an require hardware like barrel shifters.

    +
  • +
  • +

    5 overhead: large Sum, SHL/SRA.

    +
  • +
  • +

    6 Overhead: Mult/Div

    +
  • +
+

If a overhead level can be elininated having a small number of different cells +with a smaller overhead level,the translation makes sense. Notice the "small +number of cells", after all everything can be translated to nand gates. A 3x +factor is somewhat reasonable. This means that a 5-level overhead is fine to be +replaced for 3 4-level (or 3 3-level) but not for 4 4-level overhead. Zero +overhead cells are not included in the list of cells in the replacement.

+

This is a heuristic. Once works, it is a nice target to use AI to decide +when/if a transformation is worth.

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/livehd/06-lnast/index.html b/livehd/06-lnast/index.html new file mode 100644 index 0000000..1ad93f0 --- /dev/null +++ b/livehd/06-lnast/index.html @@ -0,0 +1,2025 @@ + + + + + + + + + + + + + + + + + + + + + + LNAST - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

LNAST

+

LNAST stands for Language-Neutral Abstract Syntax Tree, which is constituted of +Lnast_nodes and indexed by a tree structure.

+

LiveHD has two main data structures: LNAST and LGraph. The LNAST is the higher +level representation with a tree structure. The LGraph is the lower level +representation with a graph structure. Each node in LGraph has a LNAST +equivalent node, but LNAST is more high level and several nodes in LNAST may +not have a one-to-one mapping to LGraph.

+

Each Lnast_node should has a specific node type and contain the following information from source code tokens

+

(a) line number
+(b) pos_start, pos_end
+(c) string_view (optional)

+

Function Overloadings of Node Data Construction

+

Every node construction method has four function overloadings.
+For example, to construct a Lnast_node with a type of reference,
+we could use one of the following functions:

+
// C++
+auto node_ref = Lnast_node::create_ref("foo");     
+auto node_ref = Lnast_node::create_ref("foo", line_num);     
+auto node_ref = Lnast_node::create_ref("foo", line_num, pos1, pos2);     
+auto node_ref = Lnast_node::create_ref(token);   
+
+

In case (1), you only knows the variable name is "foo".
+In case (2), you know the variable name and the corresponding line number.
+In case (3), you know the variable name, the line number, and the charactrer position.
+In case (4), you are building LNAST from your HDL AST and you already have the Token.
+The toke should have line number, positions, and string_view information.

+

Another Example

+

If you don't care the string_view to be stored in the lnast node, just leave it empty for set "foo" for it. +This is true for many of the operator node, for example, to build a node with type of assign.

+
// C++
+auto node_assign = Lnast_node::create_assign();   
+auto node_assign = Lnast_node::create_assign(line_num);     
+auto node_assign = Lnast_node::create_assign(line_num, pos1, pos2);   
+auto node_assign = Lnast_node::create_assign(token); // The token is not necessary to have a string_view  
+
+

LNAST Node Types

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
topstmtsifuiffor
func_callfunc_defassigndp_assignmut
bit_andbit_orbit_notbit_xorreduce_or
logical_andlogical_orlogical_notplusminus
multdivmodshlsra
sextset_maskget_maskmask_andmask_popcount
mask_xorisneeqlt
legtgerefconst
rangetuple_concattuple_addtuple_gettuple_set
attr_setattr_geterr_flagphihot_phi
invalid
+

Scope

+

top

+

Every LNAST has a top node as the root. A top node has one or more child +nodes, which can only be stmts.

+
<top> --| <stmts>
+        | <stmts>
+        | <stmts>
+        |  ...
+
+

stmts

+

A stmts node represents a sequence of statements.

+
<stmts> --| <const>     : scope name
+          | <assign>
+          | <plus>
+          | <func_def>
+          | ...
+
+

Statements

+

if

+

An if node represents a conditional branch, which can be a statement or an +expression.

+
<if> --| <ref/const> : if condition variable
+       | <stmts>     : if branch
+       | <ref/const> : elif condition variable  \  N times
+       | <stmts>     : elif branch              /
+       | <stmts>     : else branch
+
+

uif

+

Unique if. Similar to if, but add additional assertions to check if at most one condition +is true.

+
<uif> --| <ref/const> : if condition variable
+        | <stmts>     : if branch
+        | <ref/const> : elif condition variable  \  N times
+        | <stmts>     : elif branch              /
+        | <stmts>     : else branch
+
+

for

+

A for node represents a for-loop over a range or tuple. Note that the loop +must be unrolled during compilation.

+
<for> --| <ref>   : iterator variable
+        | <ref>   : iterated variable (tuple or range)
+        | <stmts> : for-loop body
+
+

func_def

+

A func_def node represents a functional block with input/output arguments.

+
<func_def> --| <ref/const> : input arguments
+             | <ref/const> : output arguments
+             | <stmts>     : function body
+
+

func_call

+

A func_call node represents an instantiation of a functional block.

+
<func_call> --| <ref/const> : Lvalue
+              | <ref>       : function reference
+              | <ref/const> : input arguments
+
+

assign

+

An assign node represents a variable assignment. Note that the Rvalue can only +be a const or ref.

+
<assign> --| <ref>       : Lvalue
+           | <ref/const> : Rvalue
+
+

dp_assign

+

the "lhs := rhs" assignment (dp_assign) is like the "=" assignment but there is no check +for overflow. If the rhs has more bits than the lhs, the upper bits will be +dropped.

+
<dp_assign> --| <ref>       : Lvalue
+              | <ref/const> : Rvalue
+
+

Primitives

+

const

+

Constant value.

+
<const> "0x1234"
+
+

ref

+

Variable.

+
<ref> "variable_name"
+
+

range

+

Range.

+
<range> --| <ref> or <const> : from-value
+          | <ref> or <const> : to-value
+
+

Unary Expressions

+
<op> --| <ref>       : Lvalue
+       | <ref/const> : Rvalue
+
+

bit_not

+

Bitwise not. Flip all Rvalue bits.

+

reduce_or

+

Or all Lvalue bits.

+

logical_not

+

Logical Not. Flip Rvalue where Rvalue must be a boolean.

+

Binary Expressions

+
<op> --| <ref>       : Lvalue
+       | <ref/const> : R-1
+       | <ref/const> : R-2
+
+

mod

+

Modulo of R-1 over R-2.

+

shl

+

Left-shift R-1 by R-2.

+

sra

+

Right-shift R-1 by R-2.

+

ne

+

Not equal to.

+

eq

+

Equal to.

+

lt

+

Less than.

+

le

+

Less than or equal to.

+

gt

+

Greater than.

+

ge

+

Greater than or equal to.

+

N-ary Expressions

+
<op> --| <ref>       : Lvalue
+       | <ref/const> : R-1     \
+       | <ref/const> : R-2      \
+       | <ref/const> : R-3       2 or more values
+       | ...                    /
+       | <ref/const> : R-N     /
+
+

bit_and

+

Bitwise and.

+

bit_or

+

Bitwise or.

+

bit_xor

+

Bitwise xor.

+

plus

+

Summation of R-1 to R-N.

+

minus

+

R-1 minus summation of R-2 to R-N.

+

mult

+

Product of R-1 to R-N.

+

div

+

R-1 divided by product of R-2 to R-N

+

Tuples

+

tuple_concat

+
<tuple_concat> --| <ref> : Lvalue
+                 | <ref> : R-1 (tuple)
+                 | <ref> : R-2 (tuple)
+                 | ...
+                 | <ref> : R-N (tuple)
+
+

tuple_add

+
<tuple_add> --| <ref> : Lvalue
+              | <ref/const>
+              | <assign> --| <ref>       \ Field 0
+                           | <ref/const> /
+              | <assign> --| <ref>       \ Field 1
+                           | <ref/const> /
+              |  ...
+              | <assign> --| <ref>       \ Field N
+                           | <ref/const> /
+
+

tuple_set

+
<tuple_set> --| <ref>        : Lvalue
+              | <ref/<const> : 1st-level selection   \
+              | ...                                   1..N selections
+              | <ref/<const> : Nth-level selection   /
+              | <ref/<const> : Rvalue
+
+

tuple_get

+
<tuple_get> --| <ref>       : Lvalue
+              | <ref>       : Rvalue (selected from this value)
+              | <ref/const> : 1st-level selection   \
+              | ...                                  1..N selections
+              | <ref/const> : Nth-level selection   /
+
+

Module Input, Output, and Register Declaration

+

In LNAST, all input/output/register are defined in the node type reference +with differenct prefix of string_view, "$" stands for input, "%" stands for +output, and "#" stands for register.

+

Input

+
// Pyrope
+foo = $a
+
+
// Verilog
+input a;
+
+
// C++
+auto node_input = Lnast_node::create_ref("$a", line_num, pos1, pos2);
+
+

Output

+
// Pyrope
+%out
+
+
// Verilog
+output out;
+
+
// C++
+auto node_output = Lnast_node::create_ref("%out", line_num, pos1, pos2);
+
+

Register

+
// Pyrope
+reg_foo
+
+
// Verilog
+reg reg_foo;
+
+
// C++
+auto node_reg = Lnast_node::create_ref("reg_foo", line_num, pos1, pos2);
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/livehd/10-bazel/index.html b/livehd/10-bazel/index.html new file mode 100644 index 0000000..3a28188 --- /dev/null +++ b/livehd/10-bazel/index.html @@ -0,0 +1,1249 @@ + + + + + + + + + + + + + + + + + + + + + + Bazel build - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Bazel build

+

Bazel is a relatively new build system open sourced by google. The main difference +with traditional Makefiles is that it checks to make sure that dependences are not +lost and the builds are reproducible and hermetic. This document explains how +to use Bazel in the LGraph project.

+

Build targets are referred to using the syntax //<relative path to BUILD file>:<executable>, where +// is the path of the root livehd directory.

+

To build the LiveHD shell and supporting libraries, the target would be //main:all. +To build every target in LiveHD (helpful for checking if changes cause compilation failures), the target would be //:.... For more details on target syntax, see this page.

+

Release vs fastbuild (default) vs debug

+

For debugging/development use -c dbg, for benchmarking and testing -c opt.

+
    +
  • +

    Fast build: no optimization, minimal debugging information (no local variable information), assertions turned on (default) +

    $ bazel build <target>
    +

    +
  • +
  • +

    Debug build: some optimization, full debugging information, assertions turned on +

    $ bazel build -c dbg <target>
    +

    +
  • +
+

or use address sanitizer to detect memory leaks +

$ bazel build -c dbg --config asan //...
+

+

or use thread sanitizer to detect data races +

$ bazel build -c dbg --config tsan //...
+

+
    +
  • +

    Release build: most optimization, no debug symbols, assertions turned off +

    $ bazel build -c opt <target>
    +

    +
  • +
  • +

    Benchmarking build: aggressive optimization for the current architecture (binary may not be portable!) +

    $ bazel build --config=bench <target>
    +

    +
  • +
+

See the commands executed

+

The bazel '-s' option prints the command executed. The sandbox may still be deleted.

+
$ bazel build -s //main:all
+
+

Keep all the files in bazel run for debugging

+

Bazel runs process in a sandbox what it is deleted after each run. To preserve it for debugging a failing test.

+
bazel test --sandbox_debug -c dbg //YOUR_TEST_HERE
+
+

Check the failing log, it will show you the sandbox location. You can change directory to it, and debug as usual.

+

To run FIXME tests

+

Many times, we have new tests that make the regression fail. We use "fixme" if +the test is a new one and LGraph is still not patched. We want the test in the system, +but we do not want to make fail the regressions.

+

Those tests are marked with tags "fixme" in the BUILD. E.g:

+
sh_test(
+    name = "my_test.sh",
+    tags = ["fixme"],  # This is a fixme test. It fails, but we should fix it
+    srcs = ["tests/pyrope_test.sh"],
+
+

To run all the fixme tests +

$ bazel test --test_tag_filters "fixme" <target>
+
+To list all the fixme tests (the goal is to have zero) +
$ bazel query 'attr(tags, fixme, tests(<target>))'
+

+

List bazel targets starting from top directory

+
$ bazel query <target>
+
+

List bazel targets starting from any directory

+
$ bazel query <target>
+
+

List files needed for a given target

+
$ bazel query "deps(<target>)"
+
+

List all the passes that use core (those should be listed at main/BUILD deps)

+
$ bazel query "rdeps(//pass/..., //core:all)" | grep pass_
+
+

Clear out cache (not needed in most cases)

+

This command is useful for benchmarking build time, and when system parameters change (the compiler gets upgraded, for example) +

$ bazel clean --expunge
+

+

To run LONG tests

+

In addition to the short tests, there are sets of long tests that are run frequently +but not before every push to main line. The reason is that those are multi-hour +tests. +

$ bazel test --test_tag_filters "long1" <target>
+
+There are up to 8 long tests categories (long1, long2, long3...). Each of those +tests groups should last less than 4 hours when running in a dual core machine +(travis or azure).

+

To list the tests under each tag. E.g., to list all the tests with long1 tag. +

$ bazel query 'attr(tags, long1, tests(<target>))'
+

+

Debugging with bazel

+

First run the tests to see the failing one. Then run with debug options +the failing test. E.g: +

$ bazel run -c dbg //eprp:all
+
+Increase logging level if wanted +
$ LGRAPH_LOG=info bazel run -c dbg //eprp:all
+
+To run with gdb +
$ bazel build -c dbg //eprp:eprp_test
+$ gdb bazel-bin/eprp/eprp_test
+(gdb) b Eprp::run
+(gdb) r
+
+(lldb is also supported.)

+

To create a fully static binary

+

In the cc_binary of the relevant BUILD file, add linkopts = ['-static']

+

Notice that the lgshell still needs the directory inside +bazel-bin/main/lgshell.runfiles when using inou.yosys.\*

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/livehd/10b-3rdparty/index.html b/livehd/10b-3rdparty/index.html new file mode 100644 index 0000000..0dbe097 --- /dev/null +++ b/livehd/10b-3rdparty/index.html @@ -0,0 +1,1092 @@ + + + + + + + + + + + + + + + + + + + + + + 3rd Party - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

3rd Party

+

This section is for more advanced users that want to build LiveHD with some external 3rd party tool.

+

When integrating LiveHD with a 3rd party tool (nextpnr in this example), you can either bring the 3rd +party tool to LiveHD and hence build it with bazel, or you can export the LiveHD code/libraries +and integrate with the 3rd party project. This document covers the later case.

+

Requirements

+

Bazel pulls a specific set of library dependences, if you export, you must ensure that the 3rd party tool +uses the same library version. The 3 main source of likely conflict is "boost", "abseil", and "fmt". +The "fmt" library is unlikely to be a conflict because LiveHD uses it as "header" only to avoid conflicts +with other tools like slang.

+

To check the boost and abseil version, the easiest way: +

bazel build -c dbg //main:all
+# boost version 1.71 in this case
+grep -i "define BOOST_VERSION " bazel-*/external/boost//boost/version.hpp
+#define BOOST_VERSION 107100
+
+# abseil version 20210324
+grep "define ABSL_OPTION_INLINE_NAMESPACE_NAME" bazel-*/external/com_google_absl/absl/base/options.h
+#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_20210324
+

+

nextpnr example

+

nextpnr uses boost, in the previous example, you need to compile it with boost 1.71, with the usual requirements:

+
# nextpnr ice40 needs icestorm, so install it first
+git clone https://github.com/cliffordwolf/icestorm.git
+cd icestorm
+make
+sudo make install
+
+# compile nextpnr itself
+git clone https://github.com/YosysHQ/nextpnr.git
+cd nextpnr
+mkdir build
+cd build
+cmake -DARCH=ice40 ../
+make -j $(ncpus)
+
+

The previous steps should compile before you attempt to integrate LiveHD to nextpnr.

+

Then, you need to clone and compile LiveHD. If you clone and compile parallel to nextpnr

+
git clone https://github.com/masc-ucsc/livehd.git
+cd livehd
+bazel build -c dbg //main:all  # You could use -c opt for faster/optimized compilation
+cd ../nextpnr/build/
+ln -s ../../livehd/
+ln -s livehd/bazel-out
+ln -s livehd/bazel-livehd
+
+

Then, we need to copy the bazel gcc build instructions and combine with the nextpnr build

+

Copy this to a file called pp: +

--- livehd.params   2021-09-25 17:47:36.656724997 -0700
++++ livehd.params   2021-09-25 17:40:24.365650808 -0700
+@@ -1,16 +1,17 @@
+--o
+-bazel-out/k8-dbg/bin/main/lgshell
++-std=c++17
++-Wno-unknown-pragmas
++-I livehd/eprp -I livehd/elab -I bazel-livehd/external/com_google_absl -I bazel-livehd/external/fmt/include/ -I bazel-livehd/external/iassert/src -I livehd/mmap_lib/include -I livehd/core -I livehd/task -I livehd/lemu -I ./bazel-livehd/external/rapidjson -I livehd/pass/common -I ./bazel-livehd/external/replxx/include
++./extra.cpp
+ -pie
+ -fuse-ld=gold
+ -Wl,-no-as-needed
+ -Wl,-z,relro,-z,now
+ -B/usr/bin
+ -pass-exit-codes
+ -lstdc++
+ -lm
+-bazel-out/k8-dbg/bin/main/_objs/lgshell/main.pic.o
+ -Wl,--start-lib
+ bazel-out/k8-dbg/bin/main/_objs/main/inou_lef_api.pic.o
+ bazel-out/k8-dbg/bin/main/_objs/main/main_api.pic.o
+ bazel-out/k8-dbg/bin/main/_objs/main/meta_api.pic.o
+ bazel-out/k8-dbg/bin/main/_objs/main/top_api.pic.o
+

+

The patch adds a new c++ file to compile (extra.cpp). It will be nicer if the file is in the nextpnr directory structure, but this is as an example of how to integrate. extra.cpp has a call to LiveHD to open a database as example.

+
cp livehd/bazel-bin/main/lgshell-2.params livehd.params
+patch <pp
+
+

This example uses extra.cpp as a sample LiveHD call inside nextpnr. The extra.cpp contents:

+
#include "lgraph.hpp"
+
+void some_func() {
+  Lgraph *lg = Lgraph::open("lgdb","top");
+
+  lg->dump();
+}
+
+

Then you need to add the @livehd.params to the end of the nextpnr-ice40 link step. A way to get the command line +is to use the VERBOSE=1 option.

+
rm -f nextpnr-ice40
+make VERBOSE=1 nextpnr-ice40
+
+

Cut and paste the command, it will end with something like thon3.9.so @livehd.params to be something like: +

/usr/bin/c++ -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wno-array-bounds -fPIC -O3 -g -pipe -flto -fno-fat-lto-objects CMakeFiles/nextpnr-ice40.dir/common/archcheck.cc.o CMakeFiles/nextpnr-ice40.dir/common/basectx.cc.o CMakeFiles/nextpnr-ice40.dir/common/bits.cc.o CMakeFiles/nextpnr-ice40.dir/common/command.cc.o CMakeFiles/nextpnr-ice40.dir/common/context.cc.o CMakeFiles/nextpnr-ice40.dir/common/design_utils.cc.o CMakeFiles/nextpnr-ice40.dir/common/embed.cc.o CMakeFiles/nextpnr-ice40.dir/common/handle_error.cc.o CMakeFiles/nextpnr-ice40.dir/common/idstring.cc.o CMakeFiles/nextpnr-ice40.dir/common/idstringlist.cc.o CMakeFiles/nextpnr-ice40.dir/common/log.cc.o CMakeFiles/nextpnr-ice40.dir/common/nextpnr.cc.o CMakeFiles/nextpnr-ice40.dir/common/nextpnr_assertions.cc.o CMakeFiles/nextpnr-ice40.dir/common/nextpnr_namespaces.cc.o CMakeFiles/nextpnr-ice40.dir/common/nextpnr_types.cc.o CMakeFiles/nextpnr-ice40.dir/common/place_common.cc.o CMakeFiles/nextpnr-ice40.dir/common/placer1.cc.o CMakeFiles/nextpnr-ice40.dir/common/placer_heap.cc.o CMakeFiles/nextpnr-ice40.dir/common/property.cc.o CMakeFiles/nextpnr-ice40.dir/common/pybindings.cc.o CMakeFiles/nextpnr-ice40.dir/common/report.cc.o CMakeFiles/nextpnr-ice40.dir/common/router1.cc.o CMakeFiles/nextpnr-ice40.dir/common/router2.cc.o CMakeFiles/nextpnr-ice40.dir/common/sdf.cc.o CMakeFiles/nextpnr-ice40.dir/common/str_ring_buffer.cc.o CMakeFiles/nextpnr-ice40.dir/common/svg.cc.o CMakeFiles/nextpnr-ice40.dir/common/timing.cc.o CMakeFiles/nextpnr-ice40.dir/common/timing_opt.cc.o CMakeFiles/nextpnr-ice40.dir/3rdparty/json11/json11.cpp.o CMakeFiles/nextpnr-ice40.dir/json/jsonwrite.cc.o CMakeFiles/nextpnr-ice40.dir/frontend/json_frontend.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/arch.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/arch_place.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/arch_pybindings.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/bitstream.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/cells.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/chains.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/delay.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/gfx.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/main.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/pack.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/pcf.cc.o CMakeFiles/chipdb-ice40.dir/ice40/chipdb/chipdb-384.cc.o CMakeFiles/chipdb-ice40.dir/ice40/chipdb/chipdb-1k.cc.o CMakeFiles/chipdb-ice40.dir/ice40/chipdb/chipdb-5k.cc.o CMakeFiles/chipdb-ice40.dir/ice40/chipdb/chipdb-u4k.cc.o CMakeFiles/chipdb-ice40.dir/ice40/chipdb/chipdb-8k.cc.o -o nextpnr-ice40  -ltbb /usr/lib/x86_64-linux-gnu/libboost_filesystem.so /usr/lib/x86_64-linux-gnu/libboost_program_options.so /usr/lib/x86_64-linux-gnu/libboost_iostreams.so /usr/lib/x86_64-linux-gnu/libboost_system.so /usr/lib/x86_64-linux-gnu/libboost_thread.so -lpthread /usr/lib/x86_64-linux-gnu/libboost_regex.so /usr/lib/x86_64-linux-gnu/libboost_chrono.so /usr/lib/x86_64-linux-gnu/libboost_date_time.so /usr/lib/x86_64-linux-gnu/libboost_atomic.so -lpthread /usr/lib/x86_64-linux-gnu/libpython3.9.so @livehd.params
+

+

You can check that the new binary includes liveHD with something like: +

nm nextpnr-ice40 | grep -i Lgraph
+

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/livehd/11-pass/index.html b/livehd/11-pass/index.html new file mode 100644 index 0000000..90d43d8 --- /dev/null +++ b/livehd/11-pass/index.html @@ -0,0 +1,1190 @@ + + + + + + + + + + + + + + + + + + + + + + Creating a Pass - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Creating a Pass

+

This document provides some minimal suggestion on how to build a new LiveHD pass.

+

Most LiveHD passes reside inside inou or pass. The only difference is that +inou focuses on translation from some external tool to/from LiveHD while +pass works on transformations from LiveHD to LiveHD.

+

Create a pass

+

Check the pass/sample directory for how to create a trivial pass.

+
    +
  • Create pass/XXX directory
  • +
+

The typical is to have these files:

+
    +
  • pass/XXX/pass_XXX.[cpp|hpp]: C++ and Header file to interface with lgshell
  • +
  • pass/XXX/XXX.[cpp|hpp]: C++ file to perform the pass over a Lgraph or LNAST API
  • +
  • pass/XXX/BUILD: the Bazel build configuration file
  • +
  • pass/XXX/tests/XXX_test.cpp: A google test checking the pass
  • +
+

Finally, add the new pass to main/BUILD

+

Pass Parameters and Common variables

+

One of the main goals is to have a uniform set of passes in lgshell. lgshell should use this common +variable names when possible

+
    name:foo        lgraph name
+    path:lgdb       lgraph database path (lgdb)
+    files:foo,var   comma separated list of files used for INPUT
+    odir:.          output directory to generate files like verilog/pyrope...
+
+

Some hints/comments useful for developers

+

Using clang when building

+

The regression system builds for both gcc and clang. To force a clang build, set the following environment variables before building:

+
CXX=clang++ CC=clang bazel build -c dbg //...
+
+

Perf in lgbench

+

Use lgbench to gather statistics in your code block. It also allows to run perf record +for the code section (from lgbench construction to destruction). To enable perf record +set LGBENCH_PERF environment variable

+
export LGBENCH_PERF=1
+
+

GDB/LLDB usage

+

For most tests, you can debug with

+
gdb ./bazel-bin/main/lgshell
+
+

or

+
lldb ./bazel-bin/main/lgshell
+
+

Note that breakpoint locations may not resolve until lgshell is started and the relevant LGraph libraries are loaded.

+

Address Sanitizer

+

LiveHD has the option to run it with address sanitizer to detect memory leaks.

+
bazel build -c dbg --config asan //...
+
+

Thread Sanitizer

+

To debug with concurrent data race.

+
bazel build -c dbg --config tsan //...
+
+

Debugging a broken Docker image

+

The travis/azure regressions run several docker images. To debug the issue, run the same as the failing +docker image. c++ OPT with archlinux-masc image

+
    +
  1. Create some directory to share data in/out the docker run (to avoid + mistakes/issues, I would not share home directory unless you have done it + several times before)
  2. +
+
mkdir $HOME/docker
+
+
    +
  1. Run the docker image (in some masc docker images you can change the user to not being root)
  2. +
+
docker run --rm --cap-add SYS_ADMIN -it  -e LOCAL_USER_ID=$(id -u $USER) -v ${HOME}/docker:/home/user mascucsc/archlinux-masc
+
+# Once inside docker image. Create local "user" at /home/user with your userid
+/usr/local/bin/entrypoint.sh
+
+
    +
  1. If the docker image did not have the livehd repo, clone it
  2. +
+
git clone https://github.com/masc-ucsc/livehd.git
+
+
    +
  1. Build with the failing options and debug
  2. +
+
CXX=g++ CC=gcc bazel build -c opt //...
+
+

A docker distro that specially fails (address randomizing and muslc vs libc) is alpine. The command line to debug it:

+
docker run --rm --cap-add SYS_ADMIN -it -e LOCAL_USER_ID=$(id -u $USER) -v $HOME:/home/user -v/local/scrap:/local/scrap mascucsc/alpine-masc
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/livehd/12-github/index.html b/livehd/12-github/index.html new file mode 100644 index 0000000..592d4f3 --- /dev/null +++ b/livehd/12-github/index.html @@ -0,0 +1,1299 @@ + + + + + + + + + + + + + + + + + + + + + + GitHub Guide - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

GitHub Guide

+

LiveHD is the synthesis/emulation flow primarily maintained and developed by +the MASC lab at UC Santa Cruz. Since LiveHD is used for computer +architecture and VLSI research, the MASC lab has an internal private +repo for some still in progress works. This is done using a private repo so +that we can wait until the research is published before pushing changes to the +public repo hosted on GitHub.

+

This guide explains how we use git at the MASC group, and how you could setup a +similar flow to contribute to the LiveHD project. Other groups may choose to +adapt this technique for their own use.

+

LiveHD uses bazel as a build system, as a result, we no longer use submodules. +Instead we use the built-in bazel support to pull specific repositories.

+

Github Configuration and Commands

+

This section is for git first time users and to show the git configuration used +by the MASC group.

+

Configuration

+

Suggested options for git first time users

+
# Rebase no merge by default
+git config --global pull.rebase true
+# Set your name and email
+git config --global user.email "perico@lospalotes.com"
+git config --global user.name "Perico LosPalotes"
+git config --global pull.rebase true
+git config --global rebase.autoStash true
+
+

Rebase vs No-Rebase

+

Rebase creates cleaner logs, but sometimes it gets difficult to fix conflicts +with rebase. For cases that you are struggling to merge a conflict, you could +do this:

+
# undo the failed rebase merge
+git rebase --abort
+
+# make sure that your code changes were committed
+git commit -a -m "Your commit message"
+git pull --no-rebase
+
+# Fix the conflict without rebase (easier)
+git commit -a -m "your merge message"
+git pull --no-rebase
+git push
+
+

Typical git commands

+

Clean the directory from any file not in git (it will remove all the files not committed)

+
git clean -fdx
+
+

Save and restore un-committed changes to allow a new git pull. stash is like a +"push" and "pop" replays the changes in the current directory. This will happen +automatically if you have the autoStash configuration option.

+
git stash
+git pull
+git stash pop
+
+

See the differences against the server (still not pushed). Everything may be +committed, so git diff may be empty

+
git diff @{u}
+
+

Git Hercules statistics

+
hercules --languages C++ --burndown --burndown-people --pb https://github.com/masc-ucsc/livehd >hercules1.data
+labours -f pb -m overwrites-matrix -o hercules1a.pdf <hercules1.data
+labours -f pb -m ownership -o hercules1b.pdf <hercules1.data
+
+hercules --languages C++ --burndown --first-parent --pb https://github.com/masc-ucsc/livehd >hercules2.data
+labours -f pb -m burndown-project -o hercules2.pdf <hercules2.data
+
+hercules --languages C++ --devs --pb https://github.com/masc-ucsc/livehd >hercules3.data
+labours -f pb -m old-vs-new -o hercules3a.pdf <hercules3.data
+labours -f pb -m devs -o hercules3b.pdf <hercules3.data
+labours -f pb -m devs-efforts -o hercules3c.pdf <hercules3.data
+
+

Test/Developer LiveHD case (no commits)

+

If you do not plan to do many changes, and just wants to try LiveHD or be a +LiveHD user, the easiest way is to just clone the repo:

+
git clone https://github.com/masc-ucsc/livehd
+cd livehd
+
+

From time to time, you should get the latest version to have the latest bug fixes/patches. +Just a typical git pull should suffice:

+
git pull
+
+

Infrequent Contributor Flow (ADVANCED USERS)

+

These are instructions for advanced users, more likely other university/company +institutions with a team working on this project. The larger team may want to +have some private repository with internal development and some pushes/pulls to +the main LiveHD repo. For single external users, I would suggest to just fork +the repository and do pull requests.

+

If you work outside UCSC and/or you are an infrequent contributor, you have two +main options: fork or private clone. The fork approach requires you to have +your repository public, if you have publications or work-in-progress that you +do not want to share the best option is to have a private repo (livehd-private).

+

The simplest way to contribute to LiveHD is to create a public repo or a public +fork, and a pull request. Most git guides use the origin/master (in fork or +private repo) to synchronize with upstream/master (upstream main LiveHD repo). +This means that your local changes should NOT go to your origin/master. +Instead, you should create a branch for your local work. This works like a +charm if you do pull requests, and it is reasonable if you have a long +development branch without intention to push upstream.

+

Although it is possible to create a different setup, we recommend that you keep +the origin/master clean to synchronize with upstream/origin. You should create +a new branch for each feature that you may want to upstream (origin/feature-x), +and a local development branch (dev) for all your team members.

+
    +
  1. +

    Clone the repo:

    +
    git clone https://github.com/masc-ucsc/livehd.git livehd
    +cd livehd
    +
    +
  2. +
  3. +

    Create development branch (dev)

    +
    git checkout -b dev
    +
    +
  4. +
  5. +

    Create a branch from origin/master to create a pull request to upstream/master

    +
    git checkout -b pull_request_xxx
    +
    +
  6. +
  7. +

    Create a branch from dev for internal development if needed

    +
    git checkout -b feature_xx_4dev dev
    +
    +
  8. +
  9. +

    Synchronize origin/master from main upstream/master

    +

    Add remote upstream (if not added before)

    +
    git remote -v
    +
    +

    If remote -v did not list upstream. Add them

    +
    git remote add upstream https://github.com/masc-ucsc/livehd.git
    +git fetch upstream
    +
    +

    Make sure that you are in origin/master

    +
    git checkout master
    +
    +

    Bring the changes from the remote upstream/master to local master/origin

    +
    git merge upstream/master
    +
    +

    Push to repo origin/master if everything was fine

    +
    git push origin master
    +
    +

    To see the difference with upstream (it should be empty)

    +
    git diff @{upstream}
    +
    +
  10. +
  11. +

    Synchronize the dev branch with the latest master sync

    +
    git checkout dev
    +git merge origin/master
    +git push # same as "push origin dev" because dev is checkout
    +
    +
  12. +
  13. +

    In case that you did not, push to the corresponding branch to the server

    +
    git push origin dev
    +git push origin pull_request_xxx
    +git push origin feature_xx_4dev
    +
    +
  14. +
  15. +

    Create new pull request to upstream

    +

    Make sure that origin/master is in sync (step 5)

    +
    git diff @{upstream} # should be empty
    +
    +

    Rebase/merge the feature request with latest origin master

    +
    git checkout pull_request_xxx
    +git rebase master
    +git push upstream pull_request_xxx
    +
    +
  16. +
+

Now create a pull request through github, and the UCSC/MASC team will review it.

+

Occasional Pull Request steps

+

If you just want to do some small contributions to LiveHD doing a public fork is the +easiest way to contribute. Just fork, commit to forked master, and click on the web link +after you push.

+

Frequent Contributor

+

If you are working on LiveHD at UC Santa Cruz, contact Jose +Renau to be added to the MASC organization +on GitHub so that you have write access to the repo. The setup is similar to +the infrequent contributor flow but you have +access to directly commit to the public repository. Even the upstream/master.

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/livehd/13-style/index.html b/livehd/13-style/index.html new file mode 100644 index 0000000..31e8b86 --- /dev/null +++ b/livehd/13-style/index.html @@ -0,0 +1,1614 @@ + + + + + + + + + + + + + + + + + + + + + + Coding Style - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Coding Style

+

These are the coding style rules for LiveHD C++. Each rule can be broken, but it +should be VERY rare, and a small comment should be placed explaining why.

+

Overall

+
    +
  • When possible keep the system simple. Complexity is the enemy of maintenance.
  • +
  • Deprecate no longer used features.
  • +
  • Try to reduce friction. This means to avoid hidden/complex steps.
  • +
  • Every main API should have a unit test for testing but also to demonstrate usage.
  • +
+

comments

+

Code should be the comments, try to keep comments concise. They should explain +the WHY not the HOW. The code is the HOW.

+

Labels used in comments:

+
// FIXME: Known bug/issue but no time to fix it at the moment
+
+// TODO: Code improvement that will improve perf/quality/??? but no time at the moment
+
+// WARNING: message for some "strange" "weird" code that if changes has effects
+// (bug). Usually, this is a "not nice" code that must be kept for some reason.
+
+// NOTE: Any comment that you want to remember something about (not critical)
+
+// STYLE: why you broke a style rule (pointers, iterator...)
+
+

strings

+

We use std::string and std::string_view. These are the rules:

+
    +
  • +

    Arguments for functions are always std::string_view (no const std::string &)

    +
  • +
  • +

    If the return argument is not allocated in the function, we return a std::string_view

    +
  • +
  • +

    If the return argument can be a new string, the function returns std::string

    +
  • +
  • +

    Use the absl::StrCat, absl::StrAppend, absl::StrSplit when possible

    +
  • +
  • +

    To convert to/from integers use str_tools::to_i to_hex ...

    +
  • +
  • +

    Use str_tools for sub-string operations like str_tools::ends_with

    +
  • +
+

Variable naming rules

+
    +
  • No camelCase. Use underscores to separate words: +
    foo_bar = Foo_bar(3);
    +
  • +
  • Use plural for containers with multiple entries like vector, singular otherwise +
    elem = entries[index];
    +
  • +
  • Classes/types/enums start with uppercase. Lowercase otherwise +
    val = My_enum::Big;
    +class Sweet_potato {
    +
  • +
+

Error handling and exceptions

+

Use the Pass::error or Pass:warn for error and likely error (warn). Internally, error generates +and exception capture by the main lgshell to move to the next task.

+
Pass::error("inou_yaml: can only have a yaml_input or a graph_name, not both");
+Pass::warn("inou_yaml.to_lg: output:{} input:{} graph:{}", output, input, graph_name);
+
+

No tabs, indentation is 2 spaces

+

Make sure to configure your editor to use 2 spaces

+

You can configure your text editor to do this automatically

+

Include order

+

First do C includes (try to avoid when possible), then an empty line with C++ +includes, then an empty line followed with lgraph related includes. E.g:

+
#include <sys/types.h>
+#include <dirent.h>
+
+#include <iostream>
+#include <set>
+
+#include "graph_library.hpp"
+#include "lgedgeiter.hpp"
+
+

Keep column widths short

+
    +
  • Less than 120 characters if at all possible (meaning not compromising + readability)
  • +
+

You can configure your text editor to do this automatically

+

Avoid trailing spaces

+

You can configure your text editor to highlight them. + https://github.com/ntpeters/vim-better-whitespace

+

Use C++14 iterators not ::iterator

+
for(auto idx:g->unordered()) {
+}
+
+

Use structured returns when iterator is returned for cleaner code:

+
for(const auto &[name, id]:name2id) {
+  // ...
+
+

Use "auto", or "const auto", when possible.

+
for(auto idx:g->unordered()) {
+  for(const auto &c:g->out_edges(idx)) {
+
+

const and local variables

+

It may be too verbose to write const all the time. The coding style request to use +const (when possible) in iterators and pointers. The others are up to the programmer.

+

Do not use std::unordered_set, std::map, use flat_hash_map or flat_hash_set from abseil

+
#include "absl/container/flat_hash_map.h"
+#include "absl/container/flat_hash_set.h"
+
+absl::flat_hash_map<Index_ID, RTLIL::Wire *>   my_example;
+
+

Some common idioms to handle map/sets

+

Traverse the map/set, and as it traverses decide to erase some of the entries: +

for (auto it = m.begin(), end = m.end(); it != end;) {
+  if (condition_to_erase_it) {
+    m.erase(it++);
+  } else {
+    ++it;
+  }
+}
+

+

To check if a key is present: +

if (set.contains(key_value)) {
+}
+

+

Use absl::Span instead of std::vector as return argument

+

absl::Span is the equivalent of string_view for a string but for vectors. Like +string_view, it does not have ownership, and the size in the span can decrease +(not increase) without changing the original vector with "subspan". Faster and +more functional, no reason to return "const std::vector &", instead return +"absl::Span".

+
#include "absl/types/span.h"
+
+absl::Span<Sub_node>    get_sub_nodes() const {
+  I(sub_nodes.size()>=1);
+  return absl::MakeSpan(sub_nodes).subspan(1); // Skip first element from vector
+};
+
+

Pass by reference and use "const" when possible

+
void print(const Sub_node& g); //or
+
+void edit(Sub_node& g);
+
+

Note that older code still uses pointers, this is no longer allowed.

+

Avoid dynamic allocation as much as possible

+

The idea is to RARELY directly allocate pointer allocation

+

Use:

+
foo = Sweet_potato(3, 7)
+
+

instead of

+
foo = new Sweet_potato(3, 7)
+
+

Do not use "new"/"delete" keywords. Use smart pointers if needed (VERY VERY rare)

+

Use: +

foo = std::make_unique<Sweet_potato>(3,7);
+

+

instead of

+
foo = new Sweet_potato(3, 7)
+
+

Use fmt::print to print messages for debugging

+
fmt::print("This is a debug message, name = {}, id = {}\n",g->get_name(), idx);
+
+

Use accessors consistently

+
    +
  • get_XX(): gets "const XX &" from object without side effects (assert if it does not exist)
      +
    • operator(Y) is an alias for get_XX(Y)
    • +
    +
  • +
  • ref_XX(): gets "XX * " (nullptr if it does not exist)
  • +
  • find_XX(): similar to get_XX but, if it does not exist return invalid object (is_invalid())
  • +
  • setup_XX(): gets XX from object, if it does not exists, it creates it
  • +
  • create_XX(): clears previous XX from object, and creates a new and returns it
  • +
  • set_XX(): sets XX to object, it creates if it does not exist. Similar to + create, but does not return reference.
  • +
+

If a variable is const, it can be exposed directly without get/set accessors

+

foo = x.const_var; // No need to have x.get_const_var()

+

Use bitarray class to have a compact bitvector marker

+
bitarray visited(g->max_size());
+
+

Use iassert extensively / be meaningful whenever possible in assertions

+

This usually means use meaningful variable names and conditions that are easy to understand. +If the meaning is not clear from the assertion, use a comment in the same line. +This way, when the assertion is triggered it is easy to identify the problem.

+
I(n_edges > 0); //at least one edge needed to perform this function
+
+

We use the https://github.com/masc-ucsc/iassert package. Go to the iassert for more details on the advantages +and how to allow it to use GDB with assertions.

+

Develop in debug mode and benchmark in release mode

+

Extra checks should be only in debug. Debug and release must execute the same, +only checks (not behavior change) allowed in debug mode.

+

Benchmark in release. It is 2x-10x faster.

+

Use compact if/else brackets

+

Use clang-format as configured to catch style errors. LGraph clang-format is +based on google format, but it adds several alignment directives and wider +terminal.

+
   cd XXXX
+   clang-format -i *pp
+
+
std::vector<LGraph *> Inou_yaml::generate() {
+
+  if (opack.graph_name != "") {
+     // ...
+  } else {
+     // ..
+  }
+
+

Decide how to use attributes

+

Attributes are parameters or information that an be per Node, Node_pin or Edge. In LGraph, attributes are +persistent. This means that they are kept across execution runs in the LGraph database (E.g: in lgdb).

+

For persistent attributes, the structures to use are defined in core/annotate.hpp. Any new attribute +must be added to "annotate.hpp" to preserve persistence and to make sure that they are cleared when needed.

+

Many times it is important to have information per node, but that it is not persistent across runs. For example, +when building a LGraph from Yosys, there is a need to remember pointers from yosys to LGraph. This by definition can not be persistent because pointers change across runs. For this case, there are several options.

+

The Non-Persistent Annotations

+

If the data structure needs to keep most of the node/pins in the Lgraph, use the compact_class notation: +

absl::flat_hash_map<SomeData, Node_pin::Compact_class> s2pin;
+absl::flat_hash_map<SomeData, Node::Compact_class>     s2node;
+
+SomeData d1;
+Lgraph *lg; // LGraph owning the node
+s2pin[d1]  = node.get_driver_pin().get_compact_class(); // Example of use getting a pint
+s2node[d1] = node.get_compact_class();
+auto name = s2pin[d1].get_node(lg).get_name();   // Pick previously set driver name
+

+

Another example:

+
absl::flat_hash_map<Node_pin::Compact, RTLIL::Wire *>  input_map;
+
+input_map[pin.get_compact()] = wire;
+
+auto *wire = input_map[pin.get_compact()];
+
+for(const auto &[key, value]:input_map) {
+  Node_pin pin(lg, key); // Key is a ::Compact, not a Node_pin
+  auto name  = pin.get_name();
+  // ... Some use here
+}
+
+

If the data structure just holds a small subset of the graph, you can keep the +metadata, and use Node/Node_pin directly. E.g:

+
absl::flat_hash_map<SomeData, Node_pin> s2pin;
+absl::flat_hash_map<SomeData, Node>     s2node;
+
+SomeData d1;
+s2pin[d1]  = node.get_driver_pin(); // Example of use getting a pint
+s2node[d1] = node;
+auto name = s2pin[d1].get_name();   // Pick previously set driver name
+
+

In this case, it is fine to use the full Node, Node_pin, or Edge. This has some +pointers inside, but it is OK because it is not persistent.

+

Avoid code duplication

+

The rule is that if the same code appears in 3 places, it should be refactored

+

Tool to detect duplication +

    find . -name '*.?pp' | grep -v test >list.txt
+    duplo -ml 12 -pt 90 list.txt report.txt
+

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/livehd/graphviz/and.dot b/livehd/graphviz/and.dot new file mode 100644 index 0000000..f0ad8c0 --- /dev/null +++ b/livehd/graphviz/and.dot @@ -0,0 +1,33 @@ +digraph assign { + rankdir=LR + bgcolor="transparent" + + node [fontname = "helvetica", shape=record, style="rounded", penwidth = 2]; + edge [fontname = "helvetica", color="#142b30", arrowhead="normal", penwidth = 2]; + graph [fontname = "helvetica"]; + + + node_1 [label = " and | lhs | op1 | op2 | op3 "]; + node_2 [label = " ref | ___a"]; + node_3 [label = " ref | a"]; + node_4 [label = " ref | b"]; + node_5 [label = " ref | c"]; + + node_6 [label = " assign | lhs | rhs"]; + node_7 [label = " ref | out"]; + node_8 [label = " ref | ___a"]; + + node_9 [label = " stmts | stmt1 | stmt2"]; + + node_9:s1 -> node_1:a; + node_9:s2 -> node_6:a; + + node_1:l -> node_2:a; + node_1:r1 -> node_3:a; + node_1:r2 -> node_4:a; + node_1:r3 -> node_5:a; + + node_6:l -> node_7:a; + node_6:r -> node_8:a; + +} diff --git a/livehd/graphviz/and.png b/livehd/graphviz/and.png new file mode 100644 index 0000000000000000000000000000000000000000..65d7ca5b301885c5e6a15ad97518df3359b1d75c GIT binary patch literal 27104 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 HI^zET-o*|h literal 0 HcmV?d00001 diff --git a/livehd/graphviz/assign_simple_expression.dot b/livehd/graphviz/assign_simple_expression.dot new file mode 100644 index 0000000..206d60f --- /dev/null +++ b/livehd/graphviz/assign_simple_expression.dot @@ -0,0 +1,42 @@ +digraph assign { + rankdir=LR + bgcolor="transparent" + + node [fontname = "helvetica", shape=record, style="rounded", penwidth = 2]; + edge [fontname = "helvetica", color="#142b30", arrowhead="normal", penwidth = 2]; + graph [fontname = "helvetica"]; + + + nodea0 [label = " minus | lhs | op1 | op2 "]; + nodea1 [label = " ref | ___a"]; + nodea2 [label = " ref | x"]; + nodea3 [label = " const | 0d1"]; + + nodeb0 [label = " plus | lhs | op1 | op2 | op3 "]; + nodeb1 [label = " ref | ___b"]; + nodeb2 [label = " ref | ___a"]; + nodeb3 [label = " const | 0d3"]; + nodeb4 [label = " const | 0d2"]; + + node5 [label = " dp_assign | lhs | rhs"]; + node6 [label = " ref | total"]; + node7 [label = " ref | ___b"]; + + node8 [label = " stmts | stmt1 | stmt2 | stmt3"]; + + node8:s1 -> nodea0:a; + node8:s2 -> nodeb0:a; + node8:s3 -> node5:a; + + nodea0:l -> nodea1:a; + nodea0:r1 -> nodea2:a; + nodea0:r2 -> nodea3:a; + + nodeb0:l -> nodeb1:a; + nodeb0:r1 -> nodeb2:a; + nodeb0:r2 -> nodeb3:a; + nodeb0:r3 -> nodeb4:a; + + node5:l -> node6:a; + node5:r -> node7:a; +} diff --git a/livehd/graphviz/assign_simple_expression.png b/livehd/graphviz/assign_simple_expression.png new file mode 100644 index 0000000000000000000000000000000000000000..0aeacc8588bff4568d124f01148787448603f333 GIT binary patch literal 47443 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 node1:a; + node1:l -> node2:a; + node1:r -> node3:a; +} diff --git a/livehd/graphviz/assign_trivial_constant.png b/livehd/graphviz/assign_trivial_constant.png new file mode 100644 index 0000000000000000000000000000000000000000..ffa1f82978204086b67fa2e78745ea75ed07351c GIT binary patch literal 11178 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 literal 0 HcmV?d00001 diff --git a/livehd/graphviz/attribute.dot b/livehd/graphviz/attribute.dot new file mode 100644 index 0000000..31996c2 --- /dev/null +++ b/livehd/graphviz/attribute.dot @@ -0,0 +1,70 @@ +digraph assign { + rankdir=LR + bgcolor="transparent" + + node [fontname = "helvetica", shape=record, style="rounded", penwidth = 2]; + edge [fontname = "helvetica", color="#142b30", arrowhead="normal", penwidth = 2]; + graph [fontname = "helvetica"]; + + + + node_0 [label = " stmts | stmt1 | stmt2 | stmt3 | stmt4 | stmt5 | stmt6"]; + + node_2 [label = " dot | lhs | op1 | op2 "]; + node_3 [label = " ref | ___a"]; + node_4 [label = " ref | foo"]; + node_5 [label = " ref | __bits"]; + + node_6 [label = " assign | lhs | rhs"]; + node_7 [label = " ref | ___a"]; + node_8 [label = " const | 0d3"]; + + node_9 [label = " assign | lhs | rhs"]; + node_a [label = " ref | foo"]; + node_b [label = " const | 0d7"]; + + node_c [label = " tuple | tuple_name | key-value"] + node_d [label = " ref | ___b"]; + + node_e [label = " assign | lhs | rhs"]; + node_f [label = " ref | __bits"]; + node_g [label = " const | 0d10"]; + + node_h [label = " as | lhs | rhs"]; + node_i [label = " ref | bar"]; + node_j [label = " ref | ___b"]; + + + node_k [label = " assign | lhs | rhs"]; + node_l [label = " ref | bar"]; + node_m [label = " const | 0d123"]; + + node_0:s1 -> node_2:a + node_0:s2 -> node_6:a; + node_0:s3 -> node_9:a; + node_0:s4 -> node_c:a; + node_0:s5 -> node_h:a; + node_0:s6 -> node_k:a; + + node_2:l -> node_3:a; + node_2:r1 -> node_4:a; + node_2:r2 -> node_5:a; + + node_6:l -> node_7:a; + node_6:r -> node_8:a; + + node_9:l -> node_a:a; + node_9:r -> node_b:a; + + node_c:n -> node_d:a; + node_c:kv1 -> node_e:a; + + node_e:l -> node_f:a; + node_e:r -> node_g:a; + + node_h:l -> node_i:a; + node_h:r -> node_j:a; + + node_k:l -> node_l:a; + node_k:r -> node_m:a; + } diff --git a/livehd/graphviz/attribute.png b/livehd/graphviz/attribute.png new file mode 100644 index 0000000000000000000000000000000000000000..abb7421cd9fc7f7d6dc9e47693902cfca142708a GIT binary patch literal 83948 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�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 literal 0 HcmV?d00001 diff --git a/livehd/graphviz/for.dot b/livehd/graphviz/for.dot new file mode 100644 index 0000000..c4ac7c6 --- /dev/null +++ b/livehd/graphviz/for.dot @@ -0,0 +1,56 @@ +digraph assign { + rankdir=LR + bgcolor="transparent" + + node [fontname = "helvetica", shape=record, style="rounded", penwidth = 2]; + edge [fontname = "helvetica", color="#142b30", arrowhead="normal", penwidth = 2]; + graph [fontname = "helvetica"]; + + node0 [label = " stmts | stmt1 | stmt2"]; + + nodea [label = " for | stmts | it_name | tup"]; + nodeb [label = " stmts | stmt1 | stmt2 | stmt3 | stmt4"]; + + nodee [label = " select | lhs | op1 | op2"]; + nodef [label = " ref | ___d"]; + nodeg [label = " ref | tup_foo"]; + nodeh [label = " ref | i"]; + + c1_itr [label = " ref | i"]; + + c1_itrr [label = " ref | ___a"]; + + c1 [label = " stmts | stmt1"]; + + c1_tup [label = " tuple | tuple_name | key-value | key-value"] + c1_tup_n [label = " ref | ___a"]; + + c1_begin [label = " assign | lhs | rhs"]; + c1_begin:l -> c1_begin_l:a; + c1_begin:r -> c1_begin_r:a; + c1_begin_l [label = " ref | __range_begin"]; + c1_begin_r [label = " const | 0d0"]; + + c2_begin [label = " assign | lhs | rhs"]; + c2_begin:l -> c2_begin_l:a; + c2_begin:r -> c2_begin_r:a; + c2_begin_l [label = " ref | __range_end"]; + c2_begin_r [label = " const | 0d3"]; + + nodea:itr -> c1_itr:a; + nodea:itrr -> c1_itrr:a; + node0:s1 -> c1:a; + node0:s2 -> nodea:a; + c1:s1 -> c1_tup:a; + c1_tup:n -> c1_tup_n:a; + c1_tup:kv1 -> c1_begin:a; + c1_tup:kv2 -> c2_begin:a; + + nodea:stmts0 -> nodeb:a; + + nodeb:s1 -> nodee:a; + + nodee:l -> nodef:a; + nodee:r1 -> nodeg:a; + nodee:r2 -> nodeh:a; +} diff --git a/livehd/graphviz/for.png b/livehd/graphviz/for.png new file mode 100644 index 0000000000000000000000000000000000000000..a6e623087fe3d5f19b42d195b32e98cf5e176a32 GIT binary patch literal 66864 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 node1:a; + node1:c1 -> node2:a; + node1:s1 -> node7:a; + node1:c2 -> nodet:a; + node1:s2 -> nodeg:a; + node1:s3 -> nodek:a; + node1:cd1 -> nodex:a; + node1:cd2 -> nodey:a; + + node2:s1 -> node3:a; + node3:l -> node4:a; + node3:r1 -> node5:a; + node3:r2 -> node6:a; + + node7:s1 -> node8:a; + node8:l -> nodea:a; + node8:r -> nodeb:a; + + nodet:s1 -> nodec:a; + nodec:l -> noded:a; + nodec:r1 -> nodee:a; + nodec:r2 -> nodef:a; + + nodeg:s1 -> nodeh:a; + nodeh:l -> nodei:a; + nodeh:r -> nodej:a; + + nodek:s1 -> nodel:a; + nodel:l -> nodem:a; + nodel:l -> noden:a; + +} diff --git a/livehd/graphviz/full_case_if.png b/livehd/graphviz/full_case_if.png new file mode 100644 index 0000000000000000000000000000000000000000..955d40f9bdfe401a1cb53d94e0c33b6e9ef0bbf0 GIT binary patch literal 89223 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 literal 0 HcmV?d00001 diff --git a/livehd/graphviz/function_call_exp.dot b/livehd/graphviz/function_call_exp.dot new file mode 100644 index 0000000..8210d36 --- /dev/null +++ b/livehd/graphviz/function_call_exp.dot @@ -0,0 +1,109 @@ +digraph assign { + rankdir=LR + bgcolor="transparent" + + node [fontname = "helvetica", shape=record, style="rounded", penwidth = 2]; + edge [fontname = "helvetica", color="#142b30", arrowhead="normal", penwidth = 2]; + graph [fontname = "helvetica"]; + + node0 [label = " stmts | stmt1 | stmt2 | stmt3 | stmt4 | stmt5 | stmt6" ]; + node1 [label = " func_def | func_name | cstmts | condition | stmts | input | input | output "] + node2 [label = " ref | func_xor"]; + node3 [label = " const | true"]; + node4 [label = " stmts | stmt1 | stmt2"]; + node5 [label = " ref | $a"]; + node6 [label = " ref | $b"]; + node7 [label = " ref | %out"]; + + node2b [label = " stmts"]; + node1:cstmts -> node2b:a; + + node8 [label = " xor | lhs | op1 | op2 "]; + node9 [label = " ref | ___b"]; + nodea [label = " ref | $a"]; + nodeb [label = " ref | $b"]; + + nodec [label = " assign | lhs | rhs"]; + noded [label = " ref | %out"]; + nodee [label = " ref | ___b"]; + + nodef [label = " assign | lhs | rhs"]; + nodeg [label = " ref | func_xor"]; + nodeh [label = " ref | \___a"]; + + nodei [label = " tuple | tuple_name | key-value | key-value"] + nodej [label = " ref | ___d"]; + + nodek [label = " assign | lhs | rhs"]; + nodel [label = " ref | a"]; + nodem [label = " ref | $foo"]; + + noden [label = " assign | lhs | rhs"]; + nodeo [label = " ref | b"]; + nodep [label = " ref | $bar"]; + + nodeq [label = " func_call | lhs | func_name | arguments"]; + noder [label = " ref | my_xor"]; + nodes [label = " ref | func_xor"]; + nodet [label = " ref | ___d"]; + + + nodeu [label = " dot | lhs | op1 | op2 "]; + nodev [label = " ref | ___f"]; + nodew [label = " ref | my_xor"]; + nodex [label = " ref | out"]; + + nodey [label = " assign | lhs | rhs"]; + nodez [label = " ref | %out"]; + nodeaa [label = " ref | ___f"]; + + + + node0:s1 -> node1:a; + node0:s2 -> nodef:a; + node0:s3 -> nodei:a; + node0:s4 -> nodeq:a; + node0:s5 -> nodeu:a; + node0:s6 -> nodey:a; + + node1:n -> node2:a; + node1:cond -> node3:a; + node1:stmts -> node4:a; + node1:io1 -> node5:a; + node1:io2 -> node6:a; + node1:io3 -> node7:a; + + node4:s1 -> node8:a; + node4:s2 -> nodec:a; + + node8:l -> node9:a; + node8:r1 -> nodea:a; + node8:r2 -> nodeb:a; + + nodec:l -> noded:a; + nodec:r -> nodee:a; + + nodef:l -> nodeg:a; + nodef:r -> nodeh:a; + + nodei:n -> nodej:a; + nodei:kv1 -> nodek:a; + nodei:kv2 -> noden:a; + + nodek:l -> nodel:a; + nodek:r -> nodem:a; + + noden:l -> nodeo:a; + noden:r -> nodep:a; + + nodeq:l -> noder:a; + nodeq:n -> nodes:a; + nodeq:tp-> nodet:a; + + nodeu:l -> nodev:a; + nodeu:r1 -> nodew:a; + nodeu:r2 -> nodex:a; + + nodey:l -> nodez:a; + nodey:r -> nodeaa:a; +} diff --git a/livehd/graphviz/function_call_exp.png b/livehd/graphviz/function_call_exp.png new file mode 100644 index 0000000000000000000000000000000000000000..dae783120a67023b91e6b72441d47975605e88f8 GIT binary patch literal 159081 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 node2b:a; + + node8 [label = " xor | lhs | op1 | op2 "]; + node9 [label = " ref | ___b"]; + nodea [label = " ref | $a"]; + nodeb [label = " ref | $b"]; + + nodec [label = " assign | lhs | rhs"]; + noded [label = " ref | %out"]; + nodee [label = " ref | ___b"]; + + nodef [label = " assign | lhs | rhs"]; + nodeg [label = " ref | func_xor"]; + nodeh [label = " ref | \___a"]; + + nodei [label = " tuple | tuple_name | key-value | key-value"] + nodej [label = " ref | ___d"]; + + nodek [label = " assign | lhs | rhs"]; + nodel [label = " ref | null"]; + nodem [label = " ref | $foo"]; + + noden [label = " assign | lhs | rhs"]; + nodeo [label = " ref | null"]; + nodep [label = " ref | $bar"]; + + nodeq [label = " func_call | lhs | func_name | arguments"]; + noder [label = " ref | my_xor"]; + nodes [label = " ref | func_xor"]; + nodet [label = " ref | ___d"]; + + + nodeu [label = " dot | lhs | op1 | op2 "]; + nodev [label = " ref | ___f"]; + nodew [label = " ref | my_xor"]; + nodex [label = " ref | out"]; + + nodey [label = " assign | lhs | rhs"]; + nodez [label = " ref | %out"]; + nodeaa [label = " ref | ___f"]; + + + + node0:s1 -> node1:a; + node0:s2 -> nodef:a; + node0:s3 -> nodei:a; + node0:s4 -> nodeq:a; + node0:s5 -> nodeu:a; + node0:s6 -> nodey:a; + + node1:n -> node2:a; + node1:cond -> node3:a; + node1:stmts -> node4:a; + node1:io1 -> node5:a; + node1:io2 -> node6:a; + node1:io3 -> node7:a; + + node4:s1 -> node8:a; + node4:s2 -> nodec:a; + + node8:l -> node9:a; + node8:r1 -> nodea:a; + node8:r2 -> nodeb:a; + + nodec:l -> noded:a; + nodec:r -> nodee:a; + + nodef:l -> nodeg:a; + nodef:r -> nodeh:a; + + nodei:n -> nodej:a; + nodei:kv1 -> nodek:a; + nodei:kv2 -> noden:a; + + nodek:l -> nodel:a; + nodek:r -> nodem:a; + + noden:l -> nodeo:a; + noden:r -> nodep:a; + + nodeq:l -> noder:a; + nodeq:n -> nodes:a; + nodeq:tp-> nodet:a; + + nodeu:l -> nodev:a; + nodeu:r1 -> nodew:a; + nodeu:r2 -> nodex:a; + + nodey:l -> nodez:a; + nodey:r -> nodeaa:a; +} diff --git a/livehd/graphviz/function_call_imp.png b/livehd/graphviz/function_call_imp.png new file mode 100644 index 0000000000000000000000000000000000000000..858a501e775f82771d471e7e223ada58f59b4643 GIT binary patch literal 159109 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

`*l=6 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 literal 0 HcmV?d00001 diff --git a/livehd/graphviz/function_def.dot b/livehd/graphviz/function_def.dot new file mode 100644 index 0000000..e1fa1b4 --- /dev/null +++ b/livehd/graphviz/function_def.dot @@ -0,0 +1,48 @@ +digraph assign { + rankdir=LR + bgcolor="transparent" + + node [fontname = "helvetica", shape=record, style="rounded", penwidth = 2]; + edge [fontname = "helvetica", color="#142b30", arrowhead="normal", penwidth = 2]; + graph [fontname = "helvetica"]; + + node0 [label = " stmts | stmt1"]; + node1 [label = " func_def | func_name | cstmts | condition | stmts | input | input | output "] + node2 [label = " ref | func_xor"]; + node3 [label = " ref | $a"]; + node4 [label = " ref | $b"]; + node5 [label = " ref | %out"]; + node6 [label = " stmts | stmt1 | stmt2"]; + + node2b [label = " stmts"]; + node1:c1 -> node2b:a; + + node7 [label = " xor | lhs | op1 | op2 "]; + node8 [label = " ref | ___b"]; + node9 [label = " ref | $a"]; + nodea [label = " ref | $b"]; + + nodeb [label = " assign | lhs | rhs"]; + nodec [label = " ref | %out"]; + noded [label = " ref | ___b"]; + + nodee [label = " const | true"]; + + node0:s1 -> node1:a; + node1:n -> node2:a; + node1:stmts -> node6:a; + node1:cond -> nodee:a; + node1:io1 -> node3:a; + node1:io2 -> node4:a; + node1:io3 -> node5:a; + + node6:s1 -> node7:a; + node6:s2 -> nodeb:a; + + node7:l -> node8:a; + node7:r1 -> node9:a; + node7:r2 -> nodea:a; + + nodeb:l -> nodec:a; + nodeb:r -> noded:a; +} diff --git a/livehd/graphviz/function_def.png b/livehd/graphviz/function_def.png new file mode 100644 index 0000000000000000000000000000000000000000..665cc8d162bfd953569e1005b7e019f568fd129b GIT binary patch literal 56659 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 node2b:a; + + node2b [label = " stmts | stmt1"]; + node3b [label = " greaterthan | lhs | op1 | op2 "]; + node4b [label = " ref | ___a"]; + node5b [label = " ref | a"]; + node6b [label = " const | 0d3"]; + + node2b:s1 -> node3b:a; + node3b:l -> node4b:a; + node3b:r1 -> node5b:a; + node3b:r2 -> node6b:a; + + node2 [label = " ref | func_xor"]; + node3 [label = " ref | $a"]; + node4 [label = " ref | $b"]; + node5 [label = " ref | %out"]; + node6 [label = " stmts | stmt1 | stmt2"]; + + node7 [label = " xor | lhs | op1 | op2 "]; + node8 [label = " ref | ___b"]; + node9 [label = " ref | $a"]; + nodea [label = " ref | $b"]; + + nodeb [label = " assign | lhs | rhs"]; + nodec [label = " ref | %out"]; + noded [label = " ref | ___b"]; + + nodee [label = " ref | $valid"]; + + node0:s1 -> node1:a; + node1:n -> node2:a; + node1:stmts -> node6:a; + node1:cond -> nodee:a; + node1:io1 -> node3:a; + node1:io2 -> node4:a; + node1:io3 -> node5:a; + + node6:s1 -> node7:a; + node6:s2 -> nodeb:a; + + node7:l -> node8:a; + node7:r1 -> node9:a; + node7:r2 -> nodea:a; + + nodeb:l -> nodec:a; + nodeb:r -> noded:a; +} diff --git a/livehd/graphviz/function_def_conditional.png b/livehd/graphviz/function_def_conditional.png new file mode 100644 index 0000000000000000000000000000000000000000..a2e9c420419ada95734cf9757781396fae1c081d GIT binary patch literal 77953 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

8Cp*;>zR{jKL(lS?{8#`f``kK+<^%=A{ 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 node_7:a; + node_6:r -> node_8:a; + +} diff --git a/livehd/graphviz/inv.png b/livehd/graphviz/inv.png new file mode 100644 index 0000000000000000000000000000000000000000..bf54aaa577f1a045d901a04f6a1ba5c40be8f55b GIT binary patch literal 7015 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 node_7:a; + node_6:r -> node_8:a; + +} diff --git a/livehd/graphviz/logical_inv.png b/livehd/graphviz/logical_inv.png new file mode 100644 index 0000000000000000000000000000000000000000..aa02e967b3c0f8fe17975927eecd34fe358d659d GIT binary patch literal 7007 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 literal 0 HcmV?d00001 diff --git a/livehd/graphviz/new_for.dot b/livehd/graphviz/new_for.dot new file mode 100644 index 0000000..1983c67 --- /dev/null +++ b/livehd/graphviz/new_for.dot @@ -0,0 +1,96 @@ +digraph assign { + rankdir=LR + bgcolor="transparent" + + node [fontname = "helvetica", shape=record, style="rounded", penwidth = 2]; + edge [fontname = "helvetica", color="#142b30", arrowhead="normal", penwidth = 2]; + graph [fontname = "helvetica"]; + + // Top Statements + node0 [label = " stmts | stmt1 | stmt2"]; + + // For Node + nodea [label = " for | stmts | it_name | tup"]; + nodeb [label = " stmts | stmt1 | stmt2 | stmt3 | stmt4"]; + + // select + nodee [label = " select | lhs | op1 | op2"]; + nodef [label = " ref | ___d"]; + nodeg [label = " ref | tup_foo"]; + nodeh [label = " ref | i"]; + + // minus + nodei [label = " minus | lhs | op1 | op2"]; + nodej [label = " ref | ___g"]; + nodek [label = " const | 0d3"]; + nodel [label = " ref | i"]; + + // select + nodem [label = " select | lhs | op1 | op2"]; + noden [label = " ref | ___f"]; + nodeo [label = " ref | tup_bar"]; + nodep [label = " ref | ___g"]; + + // assign + nodeq [label = " assign | lhs | rhs"]; + noder [label = " ref | ___d"]; + nodes [label = " ref | ___f"]; + + // it_name + c1_itr [label = " ref | i"]; + + // tup + c1_itrr [label = " ref | ___a"]; + + + // Statements Node for Tuple Node + c1 [label = " stmts | stmt1"]; + + // Tuple Node + c1_tup [label = " tuple | tuple_name | key-value | key-value"] + c1_tup_n [label = " ref | ___a"]; + + c1_begin [label = " assign | lhs | rhs"]; + c1_begin:l -> c1_begin_l:a; + c1_begin:r -> c1_begin_r:a; + c1_begin_l [label = " ref | __range_begin"]; + c1_begin_r [label = " const | 0d0"]; + + c2_begin [label = " assign | lhs | rhs"]; + c2_begin:l -> c2_begin_l:a; + c2_begin:r -> c2_begin_r:a; + c2_begin_l [label = " ref | __range_end"]; + c2_begin_r [label = " const | 0d3"]; + + // Connect Nodes together + nodea:itr -> c1_itr:a; + nodea:itrr -> c1_itrr:a; + node0:s1 -> c1:a; + node0:s2 -> nodea:a; + c1:s1 -> c1_tup:a; + c1_tup:n -> c1_tup_n:a; + c1_tup:kv1 -> c1_begin:a; + c1_tup:kv2 -> c2_begin:a; + + nodea:stmts0 -> nodeb:a; + + nodeb:s1 -> nodee:a; + nodeb:s2 -> nodei:a; + nodeb:s3 -> nodem:a; + nodeb:s4 -> nodeq:a; + + nodee:l -> nodef:a; + nodee:r1 -> nodeg:a; + nodee:r2 -> nodeh:a; + + nodei:l -> nodej:a; + nodei:r1 -> nodek:a; + nodei:r2 -> nodel:a; + + nodem:l -> noden:a; + nodem:r1 -> nodeo:a; + nodem:r2 -> nodep:a; + + nodeq:l -> noder:a; + nodeq:r -> nodes:a; +} diff --git a/livehd/graphviz/new_for.png b/livehd/graphviz/new_for.png new file mode 100644 index 0000000000000000000000000000000000000000..07c0c5eb2f1daf2ff0aa9881e5c3186dea69a293 GIT binary patch literal 120445 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 d$M^Q-9rusq!fIibDG=}ll~ node1:a; + node1:c1 -> node2:a; + node1:s1 -> node7:a; + node1:cond1 -> nodef:a; + + node2:s1 -> node3:a; + node3:l -> node4:a; + node3:r1 -> node5:a; + node3:r2 -> node6:a; + + node7:s1 -> node8:a; + node7:s2 -> nodec:a; + + node8:l -> node9:a; + node8:r1 -> nodea:a; + node8:r2 -> nodeb:a; + + nodec:l -> noded:a; + nodec:r -> nodee:a; + +} diff --git a/livehd/graphviz/simple_if.png b/livehd/graphviz/simple_if.png new file mode 100644 index 0000000000000000000000000000000000000000..602a6dcf57110f832abe43c0a782ad7949164029 GIT binary patch literal 50180 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

4=`Sj3*M4R^p35I}OM-@Hm`Z>?0sT2o5xdr4 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 node_5:a + node_0:s2 -> node_1:a; + + + node_5:l -> node_6:a; + node_5:r1 -> node_7:a; + node_5:r2 -> node_8:a; + + + node_1:n -> node_1_1:a; + node_1:kv1 -> node_2:a; + node_1:kv2 -> node_9:a; + + node_2:l -> node_3:a; + node_2:r -> node_4:a; + + + node_9:l -> node_a:a; + node_9:r -> node_b:a; + + +} diff --git a/livehd/graphviz/tuple.png b/livehd/graphviz/tuple.png new file mode 100644 index 0000000000000000000000000000000000000000..5316a49e3aaeab1207bcd9c6321659c06d9306fb GIT binary patch literal 44600 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 >s%1i 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 E1u(FPQ~&?~ literal 0 HcmV?d00001 diff --git a/livehd/graphviz/tuple_concat.dot b/livehd/graphviz/tuple_concat.dot new file mode 100644 index 0000000..069f0e4 --- /dev/null +++ b/livehd/graphviz/tuple_concat.dot @@ -0,0 +1,74 @@ +digraph assign { + rankdir=LR + bgcolor="transparent" + + node [fontname = "helvetica", shape=record, style="rounded", penwidth = 2]; + edge [fontname = "helvetica", color="#142b30", arrowhead="normal", penwidth = 2]; + graph [fontname = "helvetica"]; + + node_0 [label = " stmts | stmt1 | stmt2 | stmt3 | stmt4 | stmt5"]; + + node_5 [label = " plus | lhs | op1 | op2 "]; + node_6 [label = " ref | ___d"]; + node_7 [label = " ref | cat"]; + node_8 [label = " const | 0d2"]; + + node_1 [label = " tup | tup_name | key-value | key-value"] + node_1_1 [label = " ref | tup"]; + + node_2 [label = " assign | lhs | rhs"]; + node_3 [label = " ref | foo"]; + node_4 [label = " const | 0d1"]; + + node_9 [label = " assign | lhs | rhs"]; + node_a [label = " ref | bar"]; + node_b [label = " ref | ___d"]; + + + node_j [label = " tuple | tuple_name | key-value | key-value"] + node_j_1 [label = " ref | ___f"]; + + node_k [label = " const | 0d4"]; + node_n [label = " ref | dog"]; + + node_q [label = " tuple_concat | lhs | op1 | op2 "]; + node_r [label = " ref | ___e"]; + node_s [label = " ref | tup"]; + node_t [label = " ref | ___f"]; + + node_u [label = " assign | lhs | rhs"]; + node_v [label = " ref | tup"]; + node_w [label = " ref | ___e"]; + + node_0:s1 -> node_5:a + node_0:s2 -> node_1:a; + node_0:s4 -> node_j:a; + node_0:s5 -> node_q:a; + node_0:s6 -> node_u:a; + + node_5:l -> node_6:a; + node_5:r1 -> node_7:a; + node_5:r2 -> node_8:a; + + + node_1:n -> node_1_1:a; + node_1:kv1 -> node_2:a; + node_1:kv2 -> node_9:a; + + node_2:l -> node_3:a; + node_2:r -> node_4:a; + + node_9:l -> node_a:a; + node_9:r -> node_b:a; + + node_j:n -> node_j_1:a; + node_j:kv1 -> node_k:a; + node_j:kv2 -> node_n:a; + + node_q:l -> node_r:a; + node_q:r1 -> node_s:a; + node_q:r2 -> node_t:a; + + node_u:l -> node_v:a; + node_u:r -> node_w:a; +} diff --git a/livehd/graphviz/tuple_concat.png b/livehd/graphviz/tuple_concat.png new file mode 100644 index 0000000000000000000000000000000000000000..fd248daa11e0b253afa464f4e0cce611a830ce57 GIT binary patch literal 95519 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 literal 0 HcmV?d00001 diff --git a/livehd/graphviz/while.dot b/livehd/graphviz/while.dot new file mode 100644 index 0000000..4003abf --- /dev/null +++ b/livehd/graphviz/while.dot @@ -0,0 +1,40 @@ +digraph assign { + rankdir=LR + bgcolor="transparent" + + node [fontname = "helvetica", shape=record, style="rounded", penwidth = 2]; + edge [fontname = "helvetica", color="#142b30", arrowhead="normal", penwidth = 2]; + graph [fontname = "helvetica"]; + + node0 [label = " stmts | stmt1 | stmt2 "]; + node1 [label = " while | condition | stmt"]; + + node2 [label = " greaterthan | lhs | op1 | op2 "]; + node3 [label = " ref | ___a"]; + node4 [label = " ref | i"]; + node5 [label = " const | 0d0"]; + + node6 [label = " ref | ___a"]; + + node7 [label = " stmts | stmt1 | stmt2 | ..."]; + node8 [label = " select| lhs | op1 | op2 "]; + node9 [label = " ref | ___b"]; + nodea [label = " ref | tup_foo"]; + nodeb [label = " ref | i"]; + + node0:s1 -> node2:a; + node0:s2 -> node1:a; + node1:cond1 -> node6:a; + node1:s1 -> node7:a; + + node2:l -> node3:a; + node2:r1 -> node4:a; + node2:r2 -> node5:a; + + node7:s1 -> node8:a; + + node8:l -> node9:a; + node8:r1 -> nodea:a; + node8:r2 -> nodeb:a; + +} diff --git a/livehd/graphviz/while.png b/livehd/graphviz/while.png new file mode 100644 index 0000000000000000000000000000000000000000..82a59420b8aa0300376cb6742526bd4142485a9f GIT binary patch literal 38251 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 c&*kQN2(E-UBk + + + + + + + + + + + + + + + + + + + + Hardware Design - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Hardware Design

+

Most language manuals/guides do not include a chapter on "what is +programming?", but Pyrope is a hardware description language or HDL. This +document is a guideline for hardware design for software designers. The idea is +to be high level to explain the differences without going to syntactic details +in different languages.

+

No Von Neumann

+

Most software programming languages are built to program Von Neumann CPUs. When +dealing with single-threaded code, the programmer has a sequence of "commands" +or "statements" specified in a programming language. The machine executes one +of those statements after another. There are "control flow" instructions to +select what is the following statement to execute.

+

Potentially more restricting, software languages have a central or distributed +"memory" concept where program data resides. For single-threaded code, there +tends to be a main unified memory.

+

Current CPUs follow a Von Neumann approach1. Languages designed to program +CPUs have the same model to map existing hardware efficiently. Since the +languages are Von Neumann, it is logical that CPUs also evolve to keep the same +model and further improve the performance. Since CPUs and languages follow the +same Von Neumann model, software designers' mindset assumes this same concept. +This feedback loop has resulted in most languages, hardware, and developers +evolving around this model.

+

Neither FPGAs nor ASICs is Von Neumann machines. There is no program counter to +execute one statement after another, and there is no central memory. Those +concepts could be built on top, and this is in fact what CPUs are about. CPUs +are all about making efficient Von Neumann machines on top of FPGAs and/or +ASICs given some power/area/performance constraints.

+

To design a CPU or any hardware without a Von Neumann model, the standard +concepts that all languages use of main memory or single-threaded execution do +not make much sense. The reason is that the cells available in hardware are +always there. The result can be used or not, but it is always there.

+

At a high level, hardware designers decide the basic hardware constructs to +include in the design (adders, logic gates...) and how to connect them. Those +hardware blocks will be there all the time, and the connection is fixed too. In +contrast, a software designer needs to build efficient programs for one or more +Von Neumann CPUs.

+

Optimization knobs

+

Programming hardware and software are all about solving a problem to meet some +performance/power/cost constraints using the available resources. The +difference is that the resources in hardware and software are not the same. In +software, there are instructions; in hardware, there are cells2. This +results in different optimization knobs.

+

Designing an efficient software program is all about deciding the sequence of +instructions to be small and fast. The computer architecture Iron's law +summarizes it well. The performance is "Instruction Count" x "Instructions Per +Cycle" x "Frequency". Since software programmers do not tend to consider the +frequency, it is all about executing fewer instructions and doing each +instruction as fast as possible. The software designer has to create a sequence +of instructions to solve a problem. Those instructions could use resources like +memory.

+

Instead of instructions, most hardware designers have hardware blocks or cells +like adders, multiplexors, flops, SRAMs... There are no central resources like +memory, and they have to consider frequency.

+

Like a software designer, the hardware designer needs to solve a problem. +Still, instead of selecting a sequence of instructions, the designer selects +the cells or hardware blocks and their interconnection. The designer divides +problems into smaller pipeline stages to have a high frequency. A design with +small cells that can achieve the desired frequency is an exemplary hardware +design3. So it is all about instantiating blocks and connecting them.

+

In hardware, there are two big categories of blocks: Combinational and +Sequential. Combinational do not have a clock and perform operations like +adding, and, xor... Sequential has a clock. The clock is used to remember a +value. Hence the output of a sequential block retains or memoizes the value of +previous cycles while combinational blocks have no memory or clock concept.

+

The hardware blocks are physical devices that need time to generate a valid +output given a change in their inputs. When combinational blocks are connected, +their maximum speed or frequency can be decided by finding the slowest path in +the combinational blocks connected. This means that sequential blocks should +separate combinational blocks to achieve higher frequency. This is called +pipelining. There are overheads of adding more sequential blocks, and the +hardware designer needs to find the correct balance given a set of constraints +like area/frequency/power.

+

A significant effort in hardware design goes to pipelining. Not only to find +the correct spot separating combinational blocks but because the sequential +block adds a concept of "state" or memory. Starting from a working combination +lock and randomly adding some "sequential" blocks is highly likely to generate +an incorrect result. Pipelining adds the conceptual problem that adding +sequential blocks changes the semantics and that ALL the combinational blocks +should have more or less the same frequency. Otherwise, the pipeline design is +unbalanced4, and the slowest pipeline decides the overall frequency.

+

The pipelining optimization concept is very different from software +optimization. In software, designers care about the average. If a function is +slow and its execution requires half of the execution time, reducing by half +should have a 25% performance improvement. The designer does not need to +improve very infrequently used functions. In hardware, designers care about the +worst case. If a pipeline stage is slow, improving it will result in a +frequency improvement if it was the slowest. The benefit will be just the +difference with the next slower pipeline stage, not optimizing the pipeline +itself.

+

The result is that hardware and software designers need to worry about +different constraints like pipelining. Combined with the fact that hardware +optimizations need to care about the worst case, not average, it is common for +hardware designers to say that designing hardware is hard.

+

HLS vs. HDL

+

Hardware designers also use programming languages to specify their FPGA/ASIC +design. In the past, designers "drew" the transistor/cells/gates and had a more +visual layout to see/place where each combination and the sequential block was +located. Although it is possible to do a design in such a way, it is not as +productive as using some hardware design language.

+

There are many popular software languages like C++, Java, Rust, swift... There +are also several hardware design languages, but they tend to fall into two +categories: HLS (High-Level Synthesis) or HDLs (Hardware Description +Languages). HLS can be languages like a subset of C or Rust. The HDLs are +languages like Verilog, CHISEL, or Pyrope.

+

In a nutshell, HLS tries to leverage the larger Von Neumann community +(languages and humans that know to program Von Neumann) and use compilers to +transform to efficient hardware mappings that are not Von Neumann.

+

HLS has to deal with constructs like loops and central memory. The typical +solution for loops is to use heuristics and/or directives to split the loops +into different pipeline stages. The standard solution for global memory is not +to use it or put compiler directives to guide them. Other constructs like +memory allocation and recursion are also avoided in HLS. When a C program is +translated to hardware, if it has pointers and uses memory, it needs directives +to indicate where the memory resides and mark potential overlap or pointer +aliasing between pointers. Otherwise, the generated translation is likely to be +inefficient.

+

HDLs (Hardware Description Languages) do not have a Von Neumann model. The +currently most popular HDL (Verilog) is a data flow language that does not have +a global program counter like Von Neumann languages. Instead, the programmer +specifies a hierarchy of modules5. In Verilog, the execution of each module +has a complicated set of options, but from a high-level point of view, a group +of statements is executed in each module. The module executes forever because +it is a set of gates instantiated in the hardware design.

+

Hardware artifacts

+

This section goes over several of the leading hardware artifacts that tend to +be exist in most HDLs independent of the syntax.

+

Instantiation vs execution

+

Hardware designers decide the gates are instantiated6 in the design, while +software designers focus on executing the instructions. If a set of gates is +rarely used, the hardware still has to instantiate them, and their performance +area impact is independent of the usage frequency. In software, a set of seldom +executed instructions have no performance impact. This is not the case in +hardware. As such, languages build around "instantiation" more than traditional +instruction execution.

+

Instantiation means that the designer explicitly indicates the gates or +circuits mapped to hardware. In the vast majority of HDLs (Verilog, CHISEl, +pyRTL, VHDL...), the designer specifies a top-level module. Each module can +have a set of gates and more instantiated sub-modules.

+

In "software," languages have a "main" or starting execution point. The "main" +executes or calls several functions depending on the data. Functions can +iterate in loops, and the program finishes execution when the main finishes.

+

In contrast, most HDLs differ from software languages in that they specify an +instantiation tree hierarchy of modules, and then provide some syntax on how +each module executes independently of the other modules.

+

In HDLs, the execution never ends, and the modules run independently. It +resembles a bit of an actor model. An actor is a module with individual +execution, but there are many differences like the tree structure of +instantiations and the incapacity to spawn new actors. Although it is possible +to build an HLS around the actor model without spawning capability, popular +HDLs do not.

+

In most HDLs, the instantiated tree hierarchy is fixed. This makes sense from a +hardware point of view7, but this means that a module can not be called +inside a control flow statement. A common mistake from designers learning HDLs +is to call a module conditionally. E.g., this code sequence is not what a +software programmer may expect:

+
+
+
+
var result = 0
+if some_opcode {
+  result = do_division(a,b)
+}else{
+  result = do_multiplication(a,b)
+}
+
+
+
+
var result = 0
+var result1 = do_division(a,b)
+var result2 = do_multiplication(a,b)
+if some_opcode {
+  result = result1
+}else{
+  result = result2
+}
+
+
+
+
+

A software programmer thinks about executing instructions. The previous syntax +looks like execute or call do_division when some_opcode is true, but it is +impossible to do in most HDLs because they are centered around instantiation, +not execution. For synthesizable code, none of the most popular HDLs like +Verilog, VHDL, CHISEL, pyRTL allow the instantiation of a module in a +conditional. Some like Verilog have functions but those are inlined. When +called, they can be seen as a macro preprocessor that inserts the function +statements.

+

HDLs force the designer to spicy the instantiation unconditionally, and then +the if selects between the instantiations. Even though HDLs look like they +execute instructions, they do not; it is all about cell instantiation and how +to connect those instances. The if is not a branch instruction, it is a +multiplexor instantiation. The do_division is not a function call; it +instantiates a circuit or module.

+
+

Artifact

+

Function calls inside control flow statements are either not allowed or +forced to be inlined.

+
+
+

Artifact

+

HDLs look like instruction execution, but they are about circuit +instantiation.

+
+

Pipelining

+

Pipelining is adding registers in combinational circuits to create smaller +critical paths and hence higher frequency designs. It is essential to hardware +design, and there is not much related to it in software design flows.

+

To illustrate the problem, imagine a pipelined multiplier function (mult) that +takes one cycle to produce the results, and the programmer has an assertion +checking that it was a multiply. The result c is not the current cycle a*b +but the last cycle a multiplied by the last cycle b. This is not what would +be expected in a software API.

+
+
+
+
var c = mul(a,b)
+assert c == a * b // assert fails!!
+
+
+
+
var c = mul(a,b)
+assert c == a#[-1] * b#[-1] // read last cycle #[-1] a and b
+
+
+
+
+

If actors execution resembles concurrent module instantiation execution, +async/await resembles pipelining. In async/await, the results of a function are +not available at the function return. In HDLs, there is no await, and the +results from previous cycles are output by the module instance.

+

Pipelining is not restricted to just function or module instantiations. A the +module itself can have a set of registers, and different variables/wires have +the results from different cycles. It is up to the designer to manage it, and +it is one of the primary complexity sources of hardware design and +verification.

+
+

Artifact

+

Different variables or wires can have results from other cycles due to +pipelining.

+
+

Simulation vs synthesis

+

Hardware designs tend to have extensive verification infrastructures. The +reason is that once the chip is fabricated, it can not be easily be patched +like software. It may need to trash millions of dollars and take months to get +the next chip, even for just a line of code patch. This is not different from +software; it is just that the cost of a bug could be potentially much higher.

+

The difference from software is that the "simulation" results used for +verification may be different from the hardware results generated during +"synthesis".

+

A mismatch between synthesis and simulation could happen due to script +directives in the synthesis scripts, or due to use language features that only +affect simulation.

+
+
+
+
initial begin // initial code may not be used in synthesis
+   c = 3;
+end
+
+#3 d = 4; // delay simulation update, not synthesis update
+case (x)  // synthesis: full_case, parallel_case
+...
+
+
+
+
// Do allow simulation code to have side-effects on synthesis code
+// directives affect simulation AND synthesis (not one or the other)
+
+unique case(x) // do not use synthesis only directives
+...
+
+
+
+
+
+

Artifact

+

Simulation and synthesis results can have different functionality

+
+

Reset

+

Programmers are used to initializing their variables. Since the modules are +called every cycle, the typical software syntax for initialization does not +work. To make it worse, some languages like Verilog (and others) have two +initializations: reset and simulation setup.

+

Some differences between reset and software initialization:

+
    +
  • Reset can take many cycles
  • +
  • Reset can be called many times
  • +
  • Reset vs. variable initialization in some languages (Verilog)
  • +
+
+
+
+
initial begin
+   d = 1;
+end
+always @(posedge clk) begin
+   if (reset) begin
+     d = 2;
+...
+
+
+
+
// Just use the reset flop values to initialize contents
+
+always @(posedge clk) begin
+   if (reset) begin
+     d = 2;
+...
+
+
+
+
+
+

Artifact

+

Reset is different from variable initialization

+
+

Non-blocking assignments

+

Many HDLs have what hardware designers call "non-blocking assignments". The idea +is that in hardware, when assigning a variable, the designer could think about +the "result at the end of this cycle" rather than "update this mutable variable".

+

Technically, a nonblocking assignment is an assignment to a variable, but the +variable will be updated only at the end of the cycle. To illustrate the +concept, imagine a counter. The counter can be updated with a non-blocking +assignment and following statements could still read the value before the +scheduled update.

+
+
+
+
counter <- counter + 1  // non-blocking assignment
+tmp     <- counter + 2  // non-blocking assignment
+assert tmp == (counter+1) // this may FAIL!
+
+
+
+
// Do not use non-blocking
+counter = counter + 1  // blocking assignment
+tmp     = counter + 2  // blocking assignment
+assert tmp == (counter+1) // this never fails
+
+
+
+
+
+

Artifact

+

Some HDLs support non-blocking assignments which are not found in software.

+
+

Invalid code

+

HDLs can generate invalid code that can not be fabricated, or it is strongly +recommended not to be fabricated. Examples are:

+
    +
  • +

    Combinational loops. Creating a loop with combinational logic is generally + considered a bug (only a few circuits could accept this). If the + combinational loop is inside a mux, it can be difficult to catch during + verification unless a good toggle coverage results.

    +
  • +
  • +

    Implicit latches. Some HDLs like Verilog can generate code with implicit + latches. Since the module is executed each time, variables with a missing + initialization can remember results from the last cycles generating implicit + latches. Most ASIC tools do not accept this, and it is considered a bug.

    +
  • +
  • +

    Bogus flow. Any compile (software or hardware) can have bugs, but because + hardware compilers tend to have a smaller user base; they have more bugs than + typical software compilers. Since this cost of fixing a bug is also higher, + the solution is to have an additional verification or logical equivalence + test.

    +
  • +
+

If the compile generates an executable in software flows, it is considered a +valid executable unless invalid assembly directives are used. In most HDLs, +this is not the case due to constructs like combinational loops.

+
+

Artifact

+

HDLs can generate invalid synthesis and/or simulation code.

+
+

Multi value logic

+

Software designers are used to binary numbers with 0s and 1s. In many HDLs, +there are more than two possible states for each bit. In languages like +Verilog, there are four states: 0, 1, ? or z. Where ? is a "quantum" +like state indicating that it is both zero and one simultaneously, and the z +indicates that it is in high impedance, which means that nobody is writing the +value. Some languages like VHDL have even more states.

+

The challenge is that when running code, the result may be unexpected. There +are many discussions on addressing what the community calls "x-propagation." +There is no agreement on the best solution. The reason for not removing ? is +that some large structures will not be initialized because of overheads. +Although widely considered dangerous, some engineers like the ? to allow more +freedom to the synthesis tools8

+

There are three leading solutions categories:

+
    +
  • Allow ? and run many simulations with different x-propagation rules.
  • +
  • Allow ? and randomly pick 0/1 for each ? bit at simulation time.
  • +
  • Do not allow ?.
  • +
+
+
+
+
x = 0b?   // a ? state
+if x {
+   puts "x is never true"
+}
+reg signed [3:0] a = -1;
+$display("%b\n", a[5:1]); // displays xx111
+
+
+
+
// there is no agreement on the community, but possible solutions:
+x = 0b? // (1): compile error
+if x {  // (2): randomly pick 1 or 0
+}
+reg signed [3:0] a = -1;
+$display("%b\n", a[5:1]); // displays 11111 (sign extend)
+
+
+
+
+
+

Artifact

+

HDLs can operate over non-binary logic

+
+

Simpler HDL constructs

+

Not everything is more challenging in HDLs when compared with software programming +languages. These are some differences that can make the HDLs simpler:

+

Unlimited precision

+

High-performance software must adjust to the hardware, and as such, there are +several integer types (int, short, long). The result is that the programmer +tends to be careful with overflows and type conversion. This is not a problem +in hardware. If a 113 bits adder is needed, it can be synthesized. If only a 7 +bits adder is required; the synthesis can create the smaller adder too.

+

Some HLS may have different integer sizes, but it is either a "strange" design +the decision or just as a type check so that no unnecessary hardware is generated.

+

Overflow is a source of many subtle bugs. For example, experience programmers +write a + (b-a))/2 not the expected (a+b)/2 because of integer overflow +semantics. HDLs can handle this like unlimited precision scripting languages +without the overhead.

+

No pointers

+

Memory and pointer management is big issue in most languages. Either garbage +collection, manual, or alternative approaches. Since there is no global +memory, there is no memory to manage. Maybe even more important, there is no +need for pointers. This avoids another set of problems like null dereferencing.

+

No destructors

+

Since there is no global memory, there is no need to have garbage collection or +the associated object destruction. If a "hardware resource" is utilized, it can +not be recycled. As a result, the destructor may not make sense in hardware.

+

Pass by value

+

Most software languages support passing function arguments either by value or +reference. This is done to avoid copying the object that may reside in memory. +Again, HLS has no memory. Therefore it is not as problematic.

+

Most HDLs only support passing by value. This is not a drawback but avoid +another source of bugs without the cost overhead that it will represent in a +Vonn Neumann machine.

+

No recursion

+

Most HDLs support recursion at compile-time but not at runtime. The reason is +that there is no "stack memory". If the depth is bound, it can support run-time +recursion, but the potentially sizeable combinational path would be "strange". +Only manageable with retiming. As a result, most HDLs do not support runtime +recursion.

+
+
+
    +
  1. +

    Multi-threaded CPUs are just an array of Von Neumann machines. 

    +
  2. +
  3. +

    In this document, we call any logic gate, flop, or memory array. 

    +
  4. +
  5. +

    There are other constraints like power, but the same idea/problem could + be said for software design. 

    +
  6. +
  7. +

    Unbalance pipelines have higher overheads in power/area. 

    +
  8. +
  9. +

    Verilog modules could be seen as functions in a software language that + can be instantiated in one or more places. The instantiation point sets a + hierarchy of modules. 

    +
  10. +
  11. +

    Instantiation is the process of deciding which gates are fabricated or + mapped in a given hardware design. In an ASIC, it is the process of selecting + a set of gates that will be manufactured. 

    +
  12. +
  13. +

    Transistors can not be added at runtime. 

    +
  14. +
  15. +

    This is very controversial, and many companies coding styles do not allow + the use of ? to improve synthesis results. 

    +
  16. +
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyrope/01-introduction/index.html b/pyrope/01-introduction/index.html new file mode 100644 index 0000000..d5bd873 --- /dev/null +++ b/pyrope/01-introduction/index.html @@ -0,0 +1,1304 @@ + + + + + + + + + + + + + + + + + + + + + + Introduction - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Introduction

+
+

Warning

+

This document explains the future Pyrope, some features are still not implemented. They are documented to guide the designers.

+
+

Pyrope is a modern hardware description language, with these focus points:

+
    +
  • Fast parallel and incremental elaboration
  • +
  • Modern and concise language
  • +
  • Avoiding hardware specific artifacts +
  • +
  • Zero cost abstraction
  • +
  • Help hardware verification:
      +
    • Powerful type system
    • +
    • Hot-Reload support, powerful assertions
    • +
    • Allows Pyrope 2 Verilog, edit Verilog, Verilog 2 Pyrope, edit Pyrope...
    • +
    • Static checks as long as they not produce false positives
    • +
    +
  • +
+

Hello world

+

Create a directory for the project: +

$ mkdir hello
+$ cd hello
+$ mkdir src
+

+

Populate the Pyrope code

+

src/hello.prp +

test "my first test" {
+  puts "hello world"
+}
+

+

Run +

$prp test
+

+

All the pyrope files reside in the src directory. The prp builder calls LiveHD to +elaborate the pyrope files and run all the tests.

+

Trivial GCD

+

Populate the Pyrope code

+
+
+
+

src/gcd.prp: +

 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
var gcd = proc (a:uint,b:uint)->(reg x:uint) {
+  x = a
+  reg y = b
+
+  while y!=0 #> {
+    if x > y { 
+      x -= y 
+    }else{ 
+      y -= x 
+    }
+  }
+}
+
+for a in 1..=100 {
+  for b in 1..=100 {
+    test "check.gcd({},{})",a,b {
+      let z =#[..] gcd(a,b)
+
+      waitfor z?
+
+      assert z == __my_cpp_gcd(v1=a, v2=b)
+    }
+  }
+}
+

+

src/my_cpp_gcd.cpp +

25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
void my_gcd_cpp(const Lbundle &inp, Lbundle &out) {
+  assert(inp.has_const("v1") && inp.has_const("v2"));
+
+  auto x = inp.get_const("v1");
+  auto y = inp.get_const("v2");
+
+  while (y > 0) {
+    if (x > y) {
+      x -= y
+    }else{
+      y -= x
+    }
+  }
+
+  out.add_const(x);
+}
+

+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
import Chisel._
+import firrtl_interpreter.InterpretiveTester
+import org.scalatest.{Matchers, FlatSpec}
+
+object GCDCalculator {
+  def computeGcd(a: Int, b: Int): (Int, Int) = {
+    var x = a
+    var y = b
+    while(y > 0 ) {
+      if (x > y) {
+        x -= y
+      }
+      else {
+        y -= x
+      }
+    }
+    x
+  }
+}
+
+class GCD extends Module {
+  val io = new Bundle {
+    val a  = UInt(INPUT,  16)
+    val b  = UInt(INPUT,  16)
+    val e  = Bool(INPUT)
+    val z  = UInt(OUTPUT, 16)
+    val v  = Bool(OUTPUT)
+  }
+  val x  = Reg(UInt())
+  val y  = Reg(UInt())
+  when   (x > y) { x := x - y }
+  unless (x > y) { y := y - x }
+  when (io.e) { x := io.a; y := io.b }
+  io.z := x
+  io.v := y === UInt(0)
+}
+
+class InterpreterUsageSpec extends FlatSpec with Matchers {
+
+  "GCD" should "return correct values for a range of inputs" in {
+    val s = Driver.emit(() => new GCD)
+
+    val tester = new InterpretiveTester(s)
+
+    for {
+      i <- 1 to 100
+      j <- 1 to 100
+    } {
+      tester.poke("io_a", i)
+      tester.poke("io_b", j)
+      tester.poke("io_e", 1)
+      tester.step()
+      tester.poke("io_e", 0)
+
+      while (tester.peek("io_v") != BigInt(1)) {
+        tester.step()
+      }
+      tester.expect("io_z", BigInt(GCDCalculator.computeGcd(i, j)._1))
+    }
+    tester.report()
+  }
+}
+
+
+
+
+

Run +

$prp test check.gcd
+

+

The gcd.prp includes the top-level module (gcd) and the unit test.

+
    +
  • +

    Some Pyrope features not common in other HDLs (CHISEL):

    +
      +
    • +

      Pyrope is not a DSL. Most modern HDLs like CHISEL, pyMTL, pyRTL, CλaSH + are DSL cases. In these cases, there is a host language (SCALA, or Python, + or Haskell) that must be executed. The result of the execution is the hardware + description which can be Verilog or some internal IR like FIRRTL in CHISEL. + The advantage of the DSL is that it can leverage the existing language to + have a nice hardware generator. The disadvantage is that there are 2 languages + at once, the DSL and the host language, and that it is difficult to do + incremental because the generated executable from the host language must be + executed to generate the design.

      +
    • +
    • +

      Global type inference. In the gcd example, the input/outputs are + inferred.

      +
    • +
    • +

      Synthesizable object system with runtime polymorphism

      +
    • +
    • +

      Immutable objects

      +
    • +
    • +

      Language support for several hardware constructs

      +
    • +
    +
  • +
  • +

    Some Pyrope features not common in other languages

    +
      +
    • +

      No object references, only pass by value

      +
    • +
    • +

      Pipelining support

      +
    • +
    +
  • +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyrope/02-basics/index.html b/pyrope/02-basics/index.html new file mode 100644 index 0000000..8407abb --- /dev/null +++ b/pyrope/02-basics/index.html @@ -0,0 +1,1597 @@ + + + + + + + + + + + + + + + + + + + + + + Basic syntax - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Basic syntax

+

Comments

+

Comments begin with //, there are no multi-line comments

+
// comment
+a = 3 // another comment
+
+

Constants

+

Integers

+

Pyrope has unlimited precision signed integers. Any literal starting with a +digit is a likely integer constant.

+
0xF_a_0 // 4000 in hexa. Underscores have no meaning
+0b1100  // 12 in binary
+0sb1110 // -2 in binary (sb signed binary)
+33      // 33 in decimal
+0o111   // 73 in octal
+0111    // 111 in decimal (some languages use octal here)
+
+

Since powers of two are very common, Pyrope decimal integers can use the K, M, G, and T modifiers.

+
assert 1K == 1024
+assert 1M == 1024*1024
+assert 1G == 1024*1024*1024
+assert 1T == 1024*1024*1024*1024
+
+

Several hardware languages support unknown bits (?) or high-impedance (z). Pyrope +aims at being compatible with synthesizable Verilog, as such ? is also supported in +the binary encoding.

+
0b?             // 0 or 1 in decimal
+0sb?            // 0 or -1 in decimal
+0b?0            // 0 or 2 in decimal
+0sb0?0          // 0 or 2 in decimal
+
+

The Verilog high impedance z is not supported. A bus construct must be used instead.

+

Like in many HDLs, Pyrope has unknowns ?. The x-propagation is a source of +complexity in most hardware models. Pyrope has x or ? to be compatible with +Verilog existing designs. This means that inside the Pyrope compiler, the +constant operations with unknowns are compatible with Verilog semantics. When +the simulation is performed, the expectation is to randomly generate a 0 or 1 +for each unknown (?) bit.

+

The advice is not to use ? besides match statement pattern matching. It is +less error prone to use the default value (zero or empty string), but sometimes it +is easier to use nil when converting Verilog code to Pyrope code. The nil +means that the numeric value is invalid. If any operation is performed with +nil, the result is an assertion failure. The only thing allowed to do with +nil is to copy it. While the nil behaves like an invalid value, the 0sb? +behaves like an unknown value that still can be used in arithmetic operations. +E.g: 0sb? | 1 is 1 but nil | 1 is an assertion error.

+

Notice that nil is a state in the integer basic type, it is not a new type by +itself, it does not represent an invalid pointer, but rather an invalid integer. Also +important is that the compiler will guarantee that all the nil are eliminated +at compile time or a compile error is generated.

+

Strings

+

Pyrope accepts single line strings with a single quote (') or double quote +("). Single quote does not have escape character, double quote supports escape +sequences.

+
a = "hello \n newline"
+b = 'simpler here'
+
+
    +
  • \n: newline
  • +
  • \\: backslash
  • +
  • \": double quote
  • +
  • `: backtick quote
  • +
  • \xNN: hexadecimal 8 bit character (2 digits)
  • +
  • \uNNNN: hexadecimal 16-bit Unicode character UTF-8 encoded (4 digits)
  • +
+

Pyrope allows string interpolation only when double quote is used. +Nevertheless, when string interpolation is used, the formatting guidelines are +not allowed. The style is like C++ fmt::format which allows an identifier. When +the identifier is provided the string is processed accordingly.

+
let num       = 2
+let color     = "blue"
+let extension = "s"
+
+let txt1 = "I have {num} {color} potato{extension}"
+let txt2 = format('I have {:d} {} potato{} ', num, color, extension)
+cassert txt1 == txt2 == "I have 2 blue potatos"
+
+let txt3 = 'I have {num}'         // single quote does not do interpolation
+cassert txt3 == "I have \{num\}"  // \{ escapes the interpolation
+
+

Integers and strings can be converted back and forth:

+
var a:string = "127"
+var b:int    = a     // same as var b = int(a)
+var c:string = b     // same as var c = string(b)
+assert a == c
+assert b == 0x7F
+assert a == b        // compile error, 'a' and 'b' have different types
+
+

Newlines and spaces

+

Spaces do not have meaning but new lines do. Several programming languages like +Python use indentation level (spaces) to know the parsing meaning of +expressions. In Pyrope, spaces do not have meaning, and newlines combined with +the first token after newline is enough to decide the end of statement.

+

By looking at the first character after a new line, it is possible to know if +the rest of the line belongs to the previous statement or it is a new +statement.

+

If the line starts with an alphanumeric ([a-z0-9] that excludes operators +like or, and) value or an open parenthesis ((), the rest of the line +belongs to a new statement.

+
var (a,b,c,d) = _
+a = 1
+  + 3           // 1st stmt
+(b,c) = (1,3)   // 2nd stmt
+cassert a == 4 and b == 1 and c == 3
+
+d = 1 +         // OK, but not formatted to style
+    3
+
+

This functionality allows parallelizing the parsing and elaboration in Pyrope. +More important, it makes the code more readable, by looking at the beginning of +the line, it is possible to know if it is a new statement or a continuation of +the last one. It also helps to standardize the code format by allowing only one +style.

+

Identifiers

+

An identifier is any non-reserved keyword that starts with an underscore or an +alphabetic character. Since Pyrope is designer to support any synthesizable +Verilog automatic translation, any sequence of characters between backticks +(`) can form a valid identifier. The identifier uses the same escape sequence +as strings.

+
`foo is . strange!\nidentifier` = 4
+`for` = 3
+cassert `for`+1 == `foo is . strange!\nidentifier`
+
+

Using the backtick, Pyrope can use any string as an identifier, even reserved +keywords. Identifiers are case sensitive like Verilog, but the compiler issues +errors for non ` escaped identifiers that do not follow these conditions in +order:

+
    +
  • Identifiers with a single character followed by a number can be upper or lower case.
  • +
  • An all upper case variable must be a compile time constant comptime.
  • +
  • Types should either: (1) start the first character uppercase and everything + else lower case; (2) be all lower case and finish with _t.
  • +
  • All the other identifiers that start with an alpha character [a-z] are + always lower case.
  • +
+

Semicolons

+

Semicolons are not needed to separate statements. In Pyrope, a semicolon (;) +has the same meaning as a newline. Sometimes it is possible to add +semicolons to separate statements. Since newlines affect the meaning of the +program, a semicolon can do too.

+
a = 1 ; b = 2
+
+

Printing and debugging

+

Printing messages is useful for debugging. puts prints a message and the string +is formatted using the c++20 fmt format. There is an implicit newline printed. +The same without a newline can be achieved with print.

+
a = 1
+puts "Hello a is {}", a
+
+

Pyrope does string interpolation, and it has attributes to access line of code +and file name. Since tracing or debugging variables is quite common, the dbg +statement behaves like puts and also prints the line of code and file name for +easier tracing.

+
a = 1                                            // file foo line 3
+puts "{}:{} a:{} tracing a", a.[file], a.[loc], a
+puts "{a.[file]}:{a.loc} a:{a} tracing a"        // Same as previous
+dbg a, "tracing a"
+
+

The previous statements print "foo:3 a:1 tracing a" in the 3 cases. The line of +code corresponds to the latest update of variable, not the dbg statement.

+

Since many modules can print at the same cycle, it is possible to put a +relative priority between puts (priority). If no relative priority is +provided, a default 0 priority is provided. Messages are kept to the end of the +cycle, and then printed in alphabetical order for a given priority. This is +done to be deterministic. Higher priority (higher value) are printed after +lower priority. Messages generated by assertions also get serialized like puts +statements but have the highest priority.

+

To avoid breaking down different puts inside the same method. All the puts +in a given cycle are shown together.

+

This example will print "hello world" even though there are 2 puts/prints in +different files.

+
// src/file1.prp
+puts(priority=2, " world")
+
+// src/file2.prp
+print(priority=1, "hello")
+
+

The available puts/print arguments: +* priority: relative order to print in a given cycle. +* file: file to send the message. E.g: stdout, stderr, my_large.log,...

+

A related command to the puts is the format it behaves like print but +returns a string.

+

puts/print are a bit special. In most languages, IO operations like puts are +considered to have side-effects. In Pyrope, the puts can not modify the +behavior of the synthesized code and it is considered a non-side-effect lambda +call. This allows to have puts calls in functions.

+

Functions and procedures

+

Pyrope only supports anonymous lambdas. A lambda can be assigned to a variable, +and it can be called as most programmers expect. Lambda +section has more details on the allowed syntax.

+
var f = fun(a,b) { a + b }
+
+

Pyrope naming for consistency:

+
    +
  • +

    lambda is any sequence of statements grouped in a code block that can be + assigned to a variable and called to execute later.

    +
  • +
  • +

    function is a lambda with only combination statements without non-Pyrope + calls.

    +
  • +
  • +

    procedure is a lambda that can have combination like function but also + non-combinational (register/memories). Procedures are a superset of functions.

    +
  • +
  • +

    method is a lambda (function or procedure) that updates another + variable. The first argument is an explicit self.

    +
  • +
  • +

    module is a lambda that has a physical instance. Lambdas are either inlined + or modules.

    +
  • +
+

lambda are not only restricted to Pyrope code. It is possible to interface with +non-Pyrope (C++) code, but the calls should respect the same +procedure/function definition. A C++ function can not update the C++ +internal state or generate output because the simulation/compiler is allowed to +call it multiple times. This is not the case for C++ procedure.

+

Evaluation order

+

Statements are evaluated one after another in program order. The main source of +conflicts come from expressions.

+

The expression evaluation order is important if the elements in the expression +can have side effects. Pyrope constrains the expressions so that no matter the +evaluation order, the synthesis result is the same.

+

As a reference, languages like C++11 do not have a defined order of evaluation for +all types of expressions. Calling call1() + call2() is not defined. Either +call1() first or call2() first.

+

In many languages, the evaluation order is defined for logical expressions. +This is typically called the short-circuit evaluation. Some languages like +Pascal, Rust, Kotlin have different and/or to express conditional evaluation. +In Pascal, there is an and/or and and_then/or_else (conditional). In Rust +&/| and &&/|| (conditional). In Kotlin &&/|| and and/or (conditional). +Pyrope uses has the and/or without short-circuit, and the and_then/or_else +with explicit short-circuit.

+

The programmer can explicitly set an evaluation order by using short-circuit +expressions like and_then, or_else, or control expressions (if/else, +match, for). An expression can have many function calls because those +have no side-effects, and hence the evaluation order is not important.

+

A procedure is an lambda that can update state internally. It can be through +a C++ API call, or some synthesizable state. As such, only one procedure call +can exist per expression.

+
var a = fcall() + 1               // OK
+var x = pcall() + a               // OK, proc combined with variable read
+var b = fcall(a) + 10 + pcall(a)  // OK
+var d = t.pcall() + pcall2(b)     // compile error, multiple procedure calls
+var y = t.pcall() + t.pcall()     // compile error, multiple procedure calls
+
+

Expressions also can have a code blocks ({ }) as long as there are no +side-effects. In a way, expression code blocks can be seen as a type of +functions that are called immedialy after definition.

+
var a = {var d=3 ; last d+1} + 100 // OK
+assert a == (3+1+100)
+assert a == {3+1+100}  // same, expression evaluated as 104 and returned
+
+

For most expressions, Pyrope is more restrictive than other languages because +it wants to be a fully defined deterministic independent of implementation. To +handle logging/messaging in function calls, Pyrope treats puts as a special +instruction. Pyrope runtime delays the puts output until the end of the cycle. +Section (Printing)[02-basics.md#printing] has more details.

+

To illustrate the evaluation order, it is useful to see a Verilog example. The +following Verilog sequence evaluates differently in VCS and Icarus Verilog. +Pyrope treats puts and assertion messages in a special way. The reason why +some methods may be called is dependent on the optimization (in this case, +testing(1) got optimized away by vcs).

+
module test();
+
+function testing(input [0:3] a);
+  begin
+    $display("test called with %d",a);
+    testing=1;
+  end
+endfunction
+
+initial begin
+  if (0 && testing(1)) begin
+    $display("test1");
+  end
+
+  if (1 && testing(2)) begin
+    $display("test2");
+  end
+
+  if (0 || testing(3)) begin
+    $display("test3");
+  end
+
+  if (1 || testing(4)) begin
+    $display("test4");
+  end
+end
+
+
+
+
+
test called with  1
+test called with  2
+test2
+test called with  3
+test3
+test called with  4
+test4
+
+
+
+
test called with  2
+test2
+test called with  3
+test3
+test called with  4
+test4
+
+
+
+
test called with 2
+test2
+test called with 3
+test3
+test4
+
+
+
+
+

If an order is needed and a function call can have debug side-effects or +synthesis side-effects, the statement must be broken down into several +statements, or the and_then and or_else operations must be used.

+
+
+
+
var r1 = pcall1() or  pcall2()  // compile error, non-deterministic
+
+
+var r2 = pcall1() and pcall2()  // compile error, non-deterministic
+
+
+var r3 = pcall1() +   pcall2()  // compile error
+// compile error only if pcall1/pcall2 can have side effects
+
+
+
+
var r1 = fcall1()
+r1  = fcall2() unless r1
+
+var r2 = fcall1()
+r2  = fcall2() when r2
+
+var r3 = fcall1()
+r3 += fcall2()
+
+
+
+
var r1 = fcall1() or_else fcall2()
+
+
+var r2 = fcall1() and_then fcall2()
+
+
+var r3 = fcall1()
+r3 += fcall2()
+
+
+
+
+

Basic gates

+

Pyrope allows a low level or structural direct basic gate instantiation. There +are some basic gates to which to which the compiler translates Pyrope code to. These +basic gates are also directly accesible:

+
    +
  • __sum for addition and substraction gate.
  • +
  • __mult for multiplication gate.
  • +
  • __div for divisions gate.
  • +
  • __and for bitwise and gate
  • +
  • __or for bitwise or gate
  • +
  • __xor for bitwise xor gate
  • +
  • __ror for bitwise reduce-or gate
  • +
  • __not for bitwise not gate
  • +
  • __get_mask for extrating bits using a mask gate
  • +
  • __set_mask for replacing bits using a mask gate
  • +
  • __sext for sign-extension gate
  • +
  • __lt for less-than comparison gate
  • +
  • __ge for greater-equal comparison gate
  • +
  • __eq for equal comparison gate
  • +
  • __shl for shift left logical gate
  • +
  • __sra for shift right arithmetic gate
  • +
  • __lut for Look-Up-Table gate
  • +
  • __mux for a priority multiplexer
  • +
  • __hotmux for a one-hot excoded multiplexer
  • +
  • __memory for a memory gate
  • +
  • __flop for a flop gate
  • +
  • __latch for a latch gate
  • +
+

Each of the basic gates operate always over signed integers like Pyrope, but +their semantics vary. A more detailed explanation is available at LiveHD cell +type section.

+

Initialization

+

Each variable declaration (var or let) must have an assigned value. The +type default value is _ (0 integer, "" string, false boolean, nil +otherwise)

+
a  = 3        // compile error, no previous let or var
+
+var b = 3
+b  = 5        // OK
+b += 1        // OK
+
+let cu3 = if runtime { 3 }else{ 5 }
+
+let d = "hello"  // OK
+d = "bar"        // compile error, 'd' is immutable
+var d = "bar"    // compile error, 'd' already declared
+
+var e = _        // OK, no type or default value, just scope declaration
+e:u32 = 33       // OK
+
+var Foo = 33     // compiler error, 'let Foo = 33'
+Foo  = 33        // compiler error, `Foo` already declared as immutable
+
+

When the variable is a tuple or a range style, the default initialization is +nil. 0sb? can not be applied to ranges or tuples value because it is +restricted for integers. nil should be used in those cases.

+
var tup = nil
+
+if cond::[comptime] {
+  tup = (a=1,b=2)
+}else{
+  tup = (a=1,b:u4=3,c=3)
+}
+
+cassert tup.a == 1
+cassert cond implies tup.b==2
+cassert !cond implies tup.b==3
+
+

Variables with first character upper case are comptime. This means that the contents +must be known/fix at compilation time.

+
var A_xxx = something             // comptime
+var A_yyy::[comptime] = something // also comptime, redundant but legal
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyrope/03-bundle/index.html b/pyrope/03-bundle/index.html new file mode 100644 index 0000000..b3ad432 --- /dev/null +++ b/pyrope/03-bundle/index.html @@ -0,0 +1,1545 @@ + + + + + + + + + + + + + + + + + + + + + + Tuples - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Tuples

+

Tuples are a basic construct in Pyrope. Tuples are defined as an "ordered" +sequence fields that can be named. Arrays/memories are a subcategory of tuples +by requiring all the entries to have the same type. Internally, there is +not a difference between tuples and arrays, but it is possible to check +that all the fields are the same (hence array) by using brackets instead of parenthesis.

+
var b = (f1=3,f2=4) // b is named and ordered
+var c = (1,d=4)     // c is ordered and unnamed (some entries are not named)
+
+var d = (1,2,3,4)     // array or tuple
+assert d == [1,2,3,4] // the [] also check that all the fields have same type
+
+assert (true,1) != [true,1]  // compile error, true is not the same type as 1
+
+

To access fields in a tuple we use the dot . or [] +

var a = (
+  ,r1 = (b=1,c=2)
+  ,r2 = (3,4)
+)
+// tuple position is from left to right
+cassert a.r1 == (1,2) and a.r2 == (3,4)
+cassert a.0  == (1,2) and a[1] == (3,4)
+
+// different ways to access the same field
+cassert a.r1.c    == 2
+cassert a['r1'].c == 2
+cassert a.r1.1    == 2
+cassert a.r1[1]   == 2
+cassert a[0][1]   == 2
+cassert a[0]['c'] == 2
+cassert a['r1.c'] == 2
+cassert a['r1.1'] == 2
+cassert a['0.c']  == 2
+cassert a['0.1']  == 2
+cassert a.0.c     == 2
+cassert a.0.1     == 2
+

+

The only main difference between a.0 (dot) and a[0] (select) access is that +dot access guarantees to be compile time index, while the select can have +compile time or run-time index.

+

There is introspection to check for an existing field with the has and !has operators.

+
var a = (foo = 3)
+cassert a has 'foo'
+cassert !(a has 'bar')
+cassert a !has 'bar' // "has no" is the opposite of "has"
+cassert a has 0
+cassert a !has 1
+cassert a !has 1
+
+

Tuple named fields can have a default type and or contents:

+
var val = 4
+var x = (
+  ,field1=1           // field1 with implicit type and 1 value
+  ,field2:string = _  // field2 with explicit type and "" default value
+  ,field3:int = 3     // field3 with explicit type and 3 value
+  ,val                // unnamed field with value `val` (4)
+)
+
+

Tuple and scope

+

Since tuples can be named or unnamed, an entry like xx=(foo) creates a tuple xx +and copies the current scope variable foo contents as the first entry. In many cases +it is required to pass a sequence of strings or identifiers. A solution is to +name all the fields or quote as strings:

+
var x=100
+
+var tup1 = ('x',y=4)
+var tup2 = (x,y=4)
+
+cassert tup1[0] == 'x'
+cassert tup2[0] == 100
+
+

Some constructs like enumerates and attributes typically pass identifiers +without assigning a value. The problem is that the syntax becomes not so +"nice". To address these cases, Pyrope does not use a variable reference but a +"string" in the enumerate (enum(a,b=3)) and attribute (foo::[attr], +foo.[attr]). In these constructs, a reference can be enforced with ...var

+
let aa = 3
+let a = enum(aa,b=3)
+cassert a==b
+
+cassert x.[size] == x.['size']
+
+let zz= "size"
+cassert x.[...zz] == x.[size]
+
+

Everything is a tuple

+

In Pyrope everything is a Tuple, and it has some implications that this +section tries to clarify.

+

A tuple starts with ( and finishes with ). In most languages, the +parentheses have two meanings, operation precedence and/or tuple/record. +In Pyrope, since a single element is a tuple too, the parenthesis always means +a tuple.

+

A code like (1+(2),4) can be read as "Create a tuple of two entries. The +first entry is the result of the addition of 1 (which is a tuple of 1) and a +tuple that has 2 as a unique entry. The second entry in the tuple is 4".

+

The tuple entries are separated by comma (,). Extra commas do not add meaning.

+
var a = (1,2)   // tuple of 2 entries, 1 and 2
+var b = (1)     // tuple of 1 entry, 1
+var c = 1       // tuple of 1 entry, 1
+var d = (,,1,,) // tuple of 1 entry, 1
+cassert a.0 == b.0 == c.0 == d.0
+cassert a!=b
+cassert b == c == d
+
+

A tuple with a single entry element is called a scalar.

+

Tuples are used in many places:

+
    +
  • The arguments for a call function are a tuple. E.g: fcall(1,2)
  • +
  • The return of a function call is always a tuple. E.g: foo = fcall()
  • +
  • The index for a selector [...] is a tuple. As syntax sugar, the tuple parenthesis can be omitted. E.g: foo@[0,2,3]
  • +
  • The complex type declaration are a tuple. E.g: let Xtype = (f=1,b:string)
  • +
+

Tuple mutability

+

The tuple entries can be mutable/immutable and named/unnamed. Tuple entries +follow the variable mutability rules with the exception that = can be +used to declare a mutable field. (a=3) is equivalent to (var a=3).

+
var c=(x=1,let b = 2, var d=3)
+c.x   = 3  // OK
+x.foo = 2  // compile error, tuple 'x' does not have field 'foo'
+c.b   = 10 // compile error, 'c.b' is immutable
+c.d   = 30 // OK, d was already mutable type
+
+let d=(x=1, let y=2, var z=3)
+d.x   = 2  // OK
+d.foo = 3  // compile error, tuple 'd' does not have field foo'
+d.z   = 4  // compile error, 'd' is immutable
+
+var e:d = _
+assert e.x==1 and e.y==2 and e.z==3
+e.x = 30   // OK
+e.y = 30   // compile error, 'e.y' is immutable
+e.z = 30   // OK
+
+

Tuples are always ordered, but they can have unnamed entries. If needed a _ +can be used for name or default value during the tuple declaration.

+
var b = 100
+var a = (b:u8, b, b:u8 = _, let c=4) // a.0 and a.1 are unnamed, a.2==a.b 
+a.b = 200
+assert a == (100, 100, 200, 4)
+
+var f = (b=3, let e=5)
+f.b = 4                 // OK
+f.e = 10                // compile error, `f.e` is immutable
+
+let x = (1,2)
+x[0] = 3                // compile error, 'x' is immutable
+var y = (1, let _ = 3)  // 2nd field is unnamed (only let allows that)
+y[0] = 100              // OK
+y[1] = 101              // compile error, `y[1]` is immutable
+
+

While the tuple entries can be either mutable or immutable, the field +name/types are immutable. It is possible to construct new tuples with the ++ +(concatenate) and ... (in-place operator):

+
var a=(a=1,b=2)
+let b=(c=3)
+
+let ccat1 = a ++ b
+assert ccat1 == (a=1,b=2,c=3)
+assert ccat1 == (1,2,3)
+
+var ccat2 = a                // mutable tuple
+a = a ++ (b=20)
+assert ccat2 == (a=1,b=(2,20),c=3)
+assert ccat2 == (1,(2,20),3)
+
+var join1 = (...a,...b)
+assert join1 == (a=1,b=2,c=3)
+assert join1 == (1,2,3)
+
+var join2 = (...a,...(b=20)) // compile error, 'b' already exists
+
+

The a ++ b concatenates two tuples. If the same field exists in both tuples, +the resulting field will have a tuple with the entries of a and b. The +concat tries to match by field name, if the field names do not match or have no +name a new entry is created. The algorithm starts with tuple a and starts +from tuple field 0 upwards.

+
assert(((1,a=2,c=3) ++ (a=20,33,c=30,4)) == (1,a=(2,20),c=(3,30),33,4))
+
+

The ... also concatenates, but it is an "inline concatenate". The difference +is where the fields are concatenated and that it triggers a compile error if +the same entry already exists.

+

Field access

+

Since everything is a tuple, any variable can do variable.0.0.0.0 because it +literaly means, return the tuple first entry for four times.

+

Another useful shortcut is when a tuple has a single field or entry, the tuple +contents can be accessed without requiring the individual position or field +entry name. This is quite useful for function return tuples with a single +entry.

+
let x = (first=(second=3))
+
+assert x.first.second == 3
+assert x.first        == 3
+assert x              == 3
+assert x.0.second     == 3
+assert x.first.0      == 3
+assert x.0            == 3
+
+

Tuples vs arrays

+

Tuples are ordered, as such, it is possible to use them as arrays. Tuples and +arrays share most behavior/operations, the key difference is that arrays are +unnamed with the same type for all the entries.

+
var bund1 = (0,1,2,3,4) // ordered and can be used as an array
+
+var bund2 = (bund1,bund1,((10,20),30))
+assert bund2[0][1] == 1
+assert bund2[1][1] == 1
+assert bund2[2][0] == (10,20)
+assert bund2[2][0][1] == 20
+assert bund2[2][1] == 30
+
+

Pyrope tries to be compatible with synthesizable Verilog. In Verilog, when an +out of bounds, access is performed in a packed array (unpacked arrays are not +synthesizable), or an index has unknown bits (?), a runtime warning can be +generated and the result is an unknown (0sb?). Notice that this is a +pessimistic assumption because maybe all the entries have the same value when +the index has unknowns.

+

The Pyrope compile will trigger compile errors for out-of-bound access. It is not +possible to create an array index that may perform an out of bounds access.

+
var array = (0,1,2)       // size 3, not 4
+let tmp = array[3]        // compile error, out of bounds access
+var index = 2
+if runtime {
+  index = 4
+}
+// Index can be 2 or 4
+
+var res1 = array[index]   // compile error, out of bounds access 
+
+var res2 = 0sb?           // Possible code to be compatible with Verilog
+if index<3 {
+  res = array[index]      // OK
+}
+
+

Pyrope compiler will allow an index of an array/tuple with unknowns. If the +index has unknown bits (0sb? or 0b1?0) but the compiler can not know, the +result will have unknowns (see internals for more details). +Notice that the only way to have unknowns is that somewhere else a variable or +a memory was explicitly initialized with unknowns. The default initialization +in Pyrope is 0, not unknown like Verilog.

+

Concatenate fields

+

Each tuple field must be unique. Nevertheless, it is practical to have +fields that add more subfields. This is the case for overloading. To +append or concatenate in a given field the ++= operator can be assigned.

+
var x = (
+  ,ff = 1
+  ,ff = 2 // compile error
+)
+
+var y = (
+  ,ff = 1
+  ,ff ++= 2
+  ,zz ++= 3
+)
+assert y == (ff=(1,2),zz=3)
+
+

Optional tuple parenthesis

+

Parenthesis marks the beginning and the end of a tuple. Those parentheses can +be avoided for an unnamed tuple in some cases:

+
    +
  • When doing a simple function call at the beginning of a line.
  • +
  • When used inside a selector [...].
  • +
  • When used after an in operator followed by a { like in a for and match statements.
  • +
  • For the inputs in a match statement.
  • +
  • A single element lambda return value.
  • +
+
fcall 1,2         // same as: fcall(1,2)
+b = xx[1,2]       // same as: xx[(1,2)]
+
+for a in 1,2,3 {  // same as: for a in (1,2,3) {
+  x = a
+}
+y = match z {    
+  in 1,2 { 4 }    // same as: in (1,2) { 4 }
+  else { 5 }
+}
+y2 = match var one=1 ; one ++ z {  // same as: y2 = match (1,z) {
+  == (1,2) { 4 }
+}
+
+let addb = fun(a,b:u32)-> a:u32 { // same as: letaddb = fun(a,b:u32)->(a:u32)  
+  a = a + b
+}
+
+

A named tuple parenthesis can be omitted on the left-hand side of an +assignment. This is to mutate or declare multiple variables at once. It is not +allowed to avoid the parenthesis at the right-hand-side of the statement. The +reason is that it is a bit confusing.

+
var a,b = (2,3)    // compile error, left-hand-side must be a tuple (a,b)
+var (a,b) = 2,3    // compile error, right-hand-side must be a tuple (2,3)
+var (a,b) = (2,3)
+assert a==2 and b==3
+
+var (c,d) = 1..=2  // compile error, range is a single entry assignment
+var c = 1..=2      // OK
+var (c,d) = 1      // compile error, 2 entry tuple in lhs, same in rhs
+var (c,d) = (1,2)  // OK
+assert c == 1 and d == 2
+
+

One thing to remember is that the = separates the statement in two parts +(left and right), this is not the case with type or attributes that always +apply to the immediatly declared variable or item.

+
let c = 4
+let (x,b) = (true, c:u3) // assign x=true, b=4 AND check that c is type u3
+
+cassert x == true
+cassert b == 4 
+
+

Enumerate (enum)

+

Enumerates, or enums for short, use the familiar tuple structure, but there is +a significant difference in initialization. Enums require named tuples, but in +most cases the named tupled should not have a set value. Enums automatically +assigns values, tuples need explicit value initialization.

+
let b = "foo"
+let c = 1
+let test1     = enum(a=c,b)    // OK
+let something = (b)            // OK
+cassert something == "foo"
+cassert test1.a != test1.b
+cassert test1.a==1 and test1.b==2
+
+

The enum keyword does not reference scope variables unless the reference is +on the right-hand-side.

+

If an external variable wants to be used as a field, there has to be an explicit +expression with a string type or a named tuple.

+
let a = "field"
+let c = (foo=4)
+let my_other_enum = enum(...a,b=3,...c)
+cassert my_other_enum.field != my_other_enum.b
+cassert my_other_enum.b   == 3
+cassert my_other_enum.foo == 4
+cassert my_other_enum.foo != my_other_enum.b
+
+

The enum default values are NOT like typical non-hardware languages. The enum +auto-created values use a one-hot encoding. The first entry has the first bit +set, the 2nd the 2nd bit set. If an entry has a value, the next entry uses +the next free bit. If any field is set, then the enumerate behaves like a +traditional enumerate sequence.

+
let V3 = enum(
+   ,a
+   ,b
+   ,c
+)
+cassert V3.a == 1
+cassert V3.b == 2
+cassert V3.c == 4
+
+let V4 = enum(
+   ,a
+   ,b=5
+   ,c
+)
+cassert V4.a == 0
+cassert V4.b == 5
+cassert V4.c == 6
+
+

Hierarchical enumerates

+

Enum can accept hierarchical tuples. Each enum level follows the same algorithm. +Each entry tries to find a new bit. In the case of the hierarchy, the lower +hierarchy level bits are kept.

+
let Animal = enum(
+  ,bird  =(eagle, parrot)
+  ,mammal=(rat  , human )
+)
+
+cassert Animal.bird.eagle != Animal.mammal
+cassert Animal.bird != Animal.mammal.human
+cassert Animal.bird == Animal.bird.parrot
+
+cassert int(Animal.bird        ) == 0b000001
+cassert int(Animal.bird.eagle  ) == 0b000011
+cassert int(Animal.bird.parrot ) == 0b000101
+cassert int(Animal.mammal      ) == 0b001000
+cassert int(Animal.mammal.rat  ) == 0b011000
+cassert int(Animal.mammal.human) == 0b101000
+
+

In general, for each leaf enum, the number of bits is equivalent to the number +of entries in the leaf tuple.

+

It is possible to use a sequence that is more consistent with traditional +programming languages, but this only works with non-hierarchical enumerates +when an integer type (:int, :u32, :i4 ...) is used.

+
let V5=enum(
+   ,a
+   ,b=5
+   ,c
+)
+cassert int(V5.a) == 0
+cassert int(V5.b) == 5
+cassert int(V5.c) == 6
+
+

The same syntax is used for enums to different objects. The hierarchy is not +allowed when an ordered numbering is requested.

+

Enumerates of the same type can perform bitwise binary operations +(and/or/xor/nand/xnor/xnor) and set operators (in/!in).

+
let human_rat = Animal.mammal.rat | Animal.mammal.human  // union op
+
+assert Animal.mammal      in human_rat
+assert Animal.mammal.rat  in human_rat
+assert Animal.bird       !in human_rat
+
+

Enumerate typecast

+

To convert a string back and forth to an enumerate, explicit typecast is needed +but possible.

+
let E3=enum(
+  ,l1=(
+    ,l1a
+    ,l1b
+    )
+  ,l2
+  )
+cassert string(E3.l1.l1a) == "E3.l1.l1a"
+cassert string(E3.l1) == "E3.l1"
+cassert E3("l1.l2") == E3.l1.l2
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyrope/04-variables/index.html b/pyrope/04-variables/index.html new file mode 100644 index 0000000..0e189e6 --- /dev/null +++ b/pyrope/04-variables/index.html @@ -0,0 +1,2601 @@ + + + + + + + + + + + + + + + + + + + + + + Variables and types - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Variables and types

+

A variable is an instance of a given type. The type may be inferred from use. +The basic types are Boolean, lambda, Integer, Range, and String. All those +types can be combined with tuples.

+

Variable scope

+

Scope constrains variables visibility. There are three types of scope +delimitation in Pyrope: code block scope, lambda scope, and tuple scope. Each +has a different set of rules constraining the variable visibility. Overall, the +variable/field is visible from declaration until the end of scope.

+

Pyrope uses var or let to declare a variable, but all the declarations must +have a value. _ is used to specify the default value (false for boolean, +0 for integer, "" for string, undefined lambda for lambda, and 0..=0 for +range).

+

In all the cases, variable declaration is either: +* let variable [:type] = expression +* var variable [:type] = expression

+

In a tuple scope, variable [:type] = expression is equivalent to var +variable [:type] = expression. This is to avoid the most common case +where tuple fields are frequently declared var not let. This is +different from lambda captures that declare a new variable but they are +always immutable (let).

+
+
+
+
assert a == 3        // compile error, undefined variable 'a'
+var a = 3
+{
+  assert a == 3
+  a = 33             // OK. assign 33
+  a:int = 33         // OK, assign 33 and check that 'a' has type int
+  let b = 4
+  let a = 3333       // compile error, variable shadowing
+  var a = 33         // compile error, variable shadowing
+}
+assert b == 3        // compile error, undefined variable 'b'
+
+
+
+
assert a == 3        // compile error, undefined variable 'a'
+var a = 3
+var x = 10
+let f1 = fun[a,x=a+1]() {
+  assert a == 3
+  a = 33             // compile error, capture/inputs are immutable
+  x = 300            // compile error, capture/inputs are immutable
+  let b = 4
+  let a = 3333       // compile error, variable shadowing
+  var a = 33         // compile error, variable shadowing
+  return b+3
+}
+assert f1() == 7
+assert x == 10
+assert b == 3        // compile error, undefined variable 'b'
+
+let f2 = fun() {     // restrict scope
+  assert a == 3      // compile error, undefined variable 'a'
+}
+let f3 = fun[ff=a]() { // restrict scope
+  assert ff == 3     // OK
+  ff = 3             // compile error, immutable variable
+}
+
+
+
+
var a = 3
+let r1 = (
+  ,a = a+1           // same as var a = a+1
+  ,c = {assert a == 3 and self.a==4; 50}
+)
+r1.a = 33            // compile error, 'r1' is immutable variable
+
+var r2 = (a=100, let c=(a=a+1, e=self.a+30))
+assert r2 == (a=100,c=(a=101, e=131))  // checks values not mutability
+r2.a = 33            // OK
+r2.c.a = 33          // compile error, 'r2.c' is immutable variable
+
+
+
+
+
    +
  • +

    Shadowing is not allowed in lambdas or code blocks. Tuples can redefine + (shadow) the same variable but to use inside the tuple, the self keyword + must be used always to access tuple scoped variables.

    +
  • +
  • +

    Lambdas and tuples upper scope variables are always immutable.

    +
  • +
  • +

    Lambdas can restrict upper scope visibility with [].

    +
  • +
  • +

    A variable is visible from definition until the end of scope in program order.

    +
  • +
+

Since the captures and lambda inputs are always immutable, it is not allowed to +declare them as var and redundant to declare them as let.

+
let f3 = fun(var x) { x + 1 }    // compile error, inputs are immutable
+let f2 = fun[var x](z) { x + z } // compile error, captures are immutable
+
+

Tuple scope is also useful for declaring function default values:

+
fun example(a:int, b:int=self.a+5) -> (_:int) {
+  return a+b
+}
+assert example(a=3) == (a+a+5)
+assert example(6,7) == (6+7)
+assert example(6) == (6+6+5)
+assert example(b=3) !=0         // compile error: undefined `a` argument
+
+

Basic types

+

Pyrope has 8 basic types:

+
    +
  • boolean: either true or false
  • +
  • enum: enumerated
  • +
  • fun: A function or pure combinational lambda
  • +
  • int: which is signed integer of unlimited precision
  • +
  • proc: A procedure or lambda with state/clock or side-effects
  • +
  • range: A one hot encoding of values 1..=3 == 0b1110
  • +
  • string: which is a sequence of characters
  • +
  • variant: An union without typecast
  • +
+

All the types except the function can be converted back and forth to an +integer.

+

Integer or int

+

Integers have unlimited precision and they are always signed. Unlike most other +languages, there is only one type for integer (unlimited), but the type system +allows to add constrains to be checked when assigning the variable contents. +Notice that the type is the same (u32 is the same type as i3, they just have +different constraints):

+
    +
  • int: an unlimited precision integer number.
  • +
  • unsigned: An integer basic type constrained to be a natural number.
  • +
  • u<num>: An integer basic type constrained to be a natural number with a maximum value of \(2^{\texttt{num}}\). E.g: u10 can go from zero to 1024.
  • +
  • i<num>: an integer 2s complement number with a maximum value of \(2^{\texttt{num}-1}-1\) and a minimum of \(-2^{\texttt{num}}\).
  • +
  • int(a..<b): integer basic type constrained to be between a and b.
  • +
+
var a:int         = _ // any value, no constrain
+var b:unsigned    = _ // only positive values
+var c:u13         = _ // only from 0 to 1<<13
+var d:int(20..=30)= _ // only values from 20 to 30 (both included)
+var d:int(-5..<6) = _ // only values from -5 to 6 (6 not included)
+var e:int(-1,0)   = _ // 1 bit integer: -1 or 0
+
+

Integers can have 3 value (0,1,?) expression or a nil. Section +Integers has more details, but those values can not be +part of the type requirement.

+

Integer typecast accepts strings as input. The string must be a valid formatted +Pryope number or an assertion is raised.

+

Boolean

+

A boolean is either true or false. Booleans can not mix with integers in +expressions unless there is an explicit typecast (int(false)==0 and +int(true)==-1) or the integer is a 1 bit signed integer (0 and -1). Unlike +integers, booleans do not support undefined value. A typecast from integer to +boolean will raise an assertion when the integer has undefined bits (?) or +nil.

+
let b = true
+let c = 3
+
+if c    { call(x) }  // compile error, 'c' is not a boolean expression
+if c!=0 { call(x) }  // OK
+
+var d = b or false   // OK
+var e = c or false   // compile error, 'c' is not a boolean
+
+let e = 0xfeed
+if e@[3] {           // OK, bit extraction for single bit returns a boolean
+  call(x)
+}
+
+assert 0 == (int(true)  + 1)  // explicity typecast
+assert 1 == (int(false) + 1)  // explicity typecast
+assert boolean(33) or false   // explicity typecast
+
+

String input typecase is valid, but anything different than ("0", "1", "-1", +"true", "TRUE", "t", "false", "FALSE", "f") raises an assertion failure.

+

Logical and arithmetic operations can not be mixed.

+
let x = a and b
+let y = x + 1    // compile error: 'x' is a boolean, '1' is integer
+
+

Lambda (fun/proc)

+

Lambdas have several options (see Functions), but from a +high level they provide a sequence of statements and they have a tuple for +input and a tuple for output. Lambdas also can capture values from declaration. +Like strings, lambdas are always immutable objects but they can be assigned +to mutable variables.

+

Range

+

Ranges are very useful in hardware description languages to select bits. They +are 3 ways to specify a closed range:

+
    +
  • first..=last: Range from first to the last element, both included
  • +
  • first..<last: Range from first to last, but the last element is not included
  • +
  • first..+size: Range from first to first+size. Since there is size + elements, it is equivalent to write first..<(first+last).
  • +
+

When used inside selectors ([range]) the ranges can be open (no first/last specified) +or use negative numbers. Ranges only work with positive numbers, a negative +number is to specify the distance from last.

+
    +
  • [first..<-val] is the same as [first..<(last-val+1)]. The advantage is that the last or +size in the tuple can be unknown.
  • +
  • [first..] is the same as [first..=-1].
  • +
+
let a = (1,2,3)
+assert a[0..] == (1,2,3)
+assert a[1..] == (2,3)
+assert a[..=1] == (1,2)
+assert a[..<2] == (1,2)
+assert a[1..<10] == (2,3)
+
+let b = 0b0110_1001
+assert b@[1..]        == 0b0110_100
+assert b@[1..=-1]     == 0b0110_100
+assert b@[1..=-2]     == 0b0110_100  // unsigned result from bit selector
+assert b@sext[1..=-2] == 0sb110_100
+assert b@[1..=-3]     == 0sb10_100
+assert b@[1..<-3]     == 0b0_100
+assert b@[0]          == false
+
+

A range is a separate tuple. As such it can not directly compare with +tupes. It requires an explicit conversion. If the range does not contain +negative values, it can be converted to an integer back and forth which +corresponds to a one-hot encoding.

+

Range type cast from integers use the same one-hot encoding. It is not possible +to type cast from tuple to range, but it is possible from range to tuple.

+
let c = 1..=3
+assert int(c) == 0b1110
+assert range(0b01_1100) == 2..=4
+
+assert range(1,2,3)            // compile error, typecast not allowed
+assert (1,2,3) == tuple(1..=3)
+
+

In most cases, the range can be used in contructs like for for positive and +negative numbers. The tuple typecast is not needed, but if placed the +semantic is the same. The same tuple typecast is also optional when doing a +comparison. Both ranges a step to change the step.

+
assert   int(0..=10 step  2) == 0b101_0101_0101
+assert tuple(0..=10 step  2) == ( 0,2,4,6,8,10)
+assert tuple(10..=0 step -2) == (10,8,6,4,2, 0)
+assert      (10..=0 step -2) == (10,8,6,4,2, 0)
+
+assert -1..=2 == (-1,0,1,2)
+let x = -1..=2
+
+assert (i for i in 0..=10 step 2) == (0,2,4,6,8,10)
+
+

Since the range is an integer, a decreasing range should have the same meaning +that an increasing range (1..=3 == 3..=1) but to avoid mistakes/confusions, +Pyrope generates a compile error in decreasing ranges.

+
assert 5..=0                           // compile error, 5 + 1 never reaches 0
+assert 5..=0 step -1 == (5,4,3,2,1,0)
+
+

A closed range can be converted to a single integer or a tuple. A range +encoded as an integer is a set of one-hot encodings. As such, there is no +order, but in Pyrope, ranges always have the order from smallest to largest. +The step expr can be added to indicate a step or step function. This is only +possible when both begin and end of the range are fully specified.

+
assert((0..<30 step 10) == (0,10,20)) // ranges and tuples can combined
+assert((1..=3) ++ 4 == (1,2,3,4))   // tuple and range ops become a tuple
+assert 1..=3 == (1,2,3)
+assert((1..=3)@[..] == 0b1110)      // convert range to integer with @[..]
+
+

String

+

Strings are a basic type, but they can be typecasted to integers using the +ASCII sequence. The string encoding assigns the lower bits to the first +characters in the string, each character has 8 bits associated.

+
a = 'cad'              // c is 0x63, a is 0x61, and d is 0x64
+b = 0x64_61_63
+assert a == string(b)  // typecast number to string
+assert int(a) == b     // typecast string to number
+assert a@[..] == b     // typecast string to number
+
+

Like ranges, strings can also be seen as a tuple, and when tuple operations are +performed they are converted to a tuple.

+
assert "hello" == ('h','e','l','l','o')
+assert "h" ++ "ell" == ('h','e','l','l') == "hell"
+
+

Type declarations

+

Each variable has a type, either implicit or explicit, and as such, it can be +used to declare a new type.

+

Pyrope does not have a type keyword. Instead it leverages the tuples for type +creation. The difference is that a type should be an immutable variable, and +therefore it is recommended to start with Uppercase.

+
var bund1 = (color:string, value:s33)
+x:bund1        = _      // OK, declare x of type bund1 with default values
+bund1.color    = "red"  // OK
+bund1.is_green = fun(self) { self.color == "green" }
+x.color        = "blue" // OK
+
+let typ = (color:string, value:s33, is_green:fun(self) = _)
+y:typ        = _        // OK
+typ.color    = "red"    // compile error
+typ.is_green = fun(self) { self.color == "green" }
+y.color      = "red"    // OK
+
+let bund3 = (color:string, value:s33)
+z:bund3        = _                 // OK
+bund3.color    = "red"             // compile error
+bund3.is_green = fun(self) { ... } // compile error
+z.color        = "blue"            // OK
+
+assert x equals typ  // same type structure
+assert z equals typ  // same type structure
+assert x equals z    // same type structure
+
+assert y is typ
+assert typ is typ
+assert z !is bund3 
+assert z !is typ
+assert z !is bund1
+
+

Adding a method to a tuple with tup.fn = fun... is the same as tup = tup ++ +(fn=fun...).

+

Type checks

+

When a type is used in the left-hand-side of a declaration statement, the +type is set for the whole existence of the variable. It is possible to also +use type checks outside the variable declaration. Those are to check that +the variable does comply with the type specified.

+
var a = true  // infer a is a boolean
+
+foo = a:bool or false // checks that 'a' is a boolean
+
+

Attributes

+

Attributes is the mechanism that the programmer specifies some special +checks/functionality that the compiler should perform. Attributes are +associates to variables either setting an attribute or checking the value. Some +example of check is to mark statements compile time constant, or read the +number of bits in an assertion, or placement hints, or even interact with the +synthesis flow to read timing delays.

+

Pyrope does not specify the attributes, the compiler flow specifies them. +Reading attributes should not affect a logical equivalence check. Writing +attributes can have a side-effect because it can change bits use for +wrap/saturate or change pins like reset/clock in registers. Additionally, +attributes can affect assertions, so they can stop/abort the compilation.

+

The are three operations that can be done with attributes: set, check, read.

+
    +
  • +

    Set: when associated to a variable type in the left-hand-side of an + assignment or directly accessed. If a variable definition, this binds the + attribute with all the use cases of the variable. If the variable just + changes attribute value, a direct assignment is possible E.g: foo::[max=300] + = 4 or baz.[attr] = 10

    +
  • +
  • +

    Check: when associated to a type property in the right-hand-side of an + assignment. The attribute is a comma separated list of boolean expression + that must evaluate true only at this statement. E.g: var tmp = + yy::[comptime, attr2>0] + xx

    +
  • +
  • +

    Read: a direct read of an attribute value is possible with variable.field.[attribute]

    +
  • +
+

The attribute set, writes a value to the attribute. If no value is given a +boolean true is set. The attribute checks are expressions that must evaluate +true.

+

Since conditional code can depend on an attribute, which results in executing a +different code sequence that can lead to the change of the attribute. This can +create a iterative process. It is up to the compiler to handle this, but the +most logical is to trigger a compile error if there is no fast convergence.

+
// attribute set
+var foo:u32:[comptime=true] = xx   // enforce that foo is comptime true always
+var bar::[comptime] = xx           // same as previous statement
+yyy = xx                           // yyy does not check comptime
+yyy::[comptime=true] = xx          // now, checks that 'yyy` is comptime
+
+// attribute check
+if bar == 3 {
+  tmp = bar::[comptime == true]    // check that this use of bar is comptime
+  tmp = bar::[comptime]            // same as previous statement
+  tmp = bar ; assert bar.[comptime] // same as previous statements
+}
+                                   // bar/foo may not be comptime
+
+// attribute read
+assert tmp.[bits] < 30 and !tmp.[comptime]
+
+

The attribute check is like a type check, both can be converted to assertions, +but the syntax is cleaner.

+
+
+
+
let x = y::[cond,bar==3] + 1
+
+read_state = fun(x) {
+  let f:u32:[comptime] = x // f is compile time or a error is generated
+  return f                 // f should be compile time constant
+}
+
+var foo = read_state(zz) // foo will be compile time constant
+
+
+
+
let x = y + 1
+cassert y.[cond]
+cassert y.[bar]==3
+
+read_state = fun(x) {
+  let f = x
+  cassert f does u32
+  cassert f.[comptime]
+  f
+}
+
+var foo = read_state(zz) // foo will be compile time constant
+
+
+
+
+

Pyrope allows to assign the attribute to a variable or a function call. Not to +statements because it is confusing if applied to the condition or all the +sub-statements.

+
if cond::[comptime] {    // cond is checked to be compile time constant
+  x::[comptime] = a +1   // x is set to be compile time constant
+}else{
+  x::[comptime] = b      // x is set to be compile time constant
+}
+
+
+if cond.[comptime] {  // checks if cond is compute at comptime
+  let v = cond
+  if cond {
+    puts "cond is compile time and true"
+  }
+}
+
+

The programmer could create custom attributes but then a LiveHD compiler pass +to deal with the new attribute is needed to handle based on their specific +semantic. To understand the potential Pyrope syntax, this is a hypothetical +::[poison] attribute that marks tuple.

+
let bad = (a=3,b::[poison]=4)
+
+let b = bad.b
+
+assert b.[poison] and b==4
+
+

Attributes control fields like the default reset and clock signal. This allows +to change the control inside procedures. Notice that this means that attributes +are passed by reference. This is not a value copy, but a pass by reference. +This is needed because when connecting things like a reset, we want to connect +to the reset wire, not the current reset value.

+
let counter = proc(en, width) {
+  reg value:uint:[bits=width] = 0
+  value = value + 1
+  value
+}
+
+let counter2::[clock_pin=clk1]=counter
+let counter3::[reset_pin=rst2]=counter
+
+var ctr2 =#[..] counter2(my_enable)
+var ctr3 =#[..] counter3(my_enable)
+
+

In the long term, the goal is to have any synthesis directive that can affect +the correctness of the result to be part of the design specification so that it +can be checked during simulation/verification.

+

There are 3 main classes of a attributes that all the Pyrope compilers should +always implement: Bitwidth, comptime, debug.

+

Variable attribute list

+

In the future, the compiler may implement some of the following attributes, as +such, these attribute names are reserved and not allowed for custom attribute +passes:

+
    +
  • clock: indicate a signal/input is a clock wire
  • +
  • critical: synthesis time criticality
  • +
  • debug (sticky): variable use for debug only, not synthesis allowed
  • +
  • delay: synthesis time delay
  • +
  • defer: for reads, it means last value written. For assigns, it means defer write
  • +
  • deprecated: to generate special warnigns about usage
  • +
  • donttouch: do not touch/optimize away
  • +
  • file: to print the file where the variable was declared
  • +
  • inline, noinline: to indicate if a module is inlined
  • +
  • inp_delay, out_delay: synthesis optimizations hints
  • +
  • keep: same as donttouch but shorter
  • +
  • key: variable/entry key name
  • +
  • left_of, right_of, top_of, bottom_of, align_with: placement hints
  • +
  • let and var: is the variable declared as let and/or var
  • +
  • loc: line of code information
  • +
  • max_delay, min_delay: synthesis optimizations checked at simulation
  • +
  • max_load, max_fanout, max_cap: synthesis optimization hints
  • +
  • multicycle: number of cycles for optimizations checked at simulation
  • +
  • pipeline: pipeline related information
  • +
  • private: variable/field not visible to import/regref
  • +
  • rand and crand: simulation and compile time random number generation
  • +
  • reset: indicate a signal/input is a reset wire
  • +
  • size: Number of entries in tuple or array
  • +
  • typename: type name at variable declaration
  • +
  • valid, retry: for elastic pipelines
  • +
  • warn: is a boolean what when set to false disables compile warnings for associated variable
  • +
+

Registers and pipestage attribute list

+

Registers have the following attributes:

+
    +
  • async: false by default, selects an asynchronous reset
  • +
  • initial: reset value when reset is high
  • +
  • clock: connected to clock by default
  • +
  • reset: connected to reset by default
  • +
  • negreset: active low reset signal
  • +
  • posclk: true by default, selects a posedge or negnedge flop
  • +
  • retime: allow to retime across the register
  • +
+

Pipestage accept the same register attributes but also two more:

+
    +
  • lat: latency for the pipestage
  • +
  • num: Number of unitsi used when the pipestage is not fully pipelined.
  • +
+

Memories attribute list

+

Memories are arrays with persistence like registers. As such, some of the attributes +are similar to registers, but unlike registers they can have multiple clocks.

+
    +
  • addr: Tuple of address ports for the memory.
  • +
  • bits: The number of bits for each memory entry
  • +
  • size: The number of entries. Total size in bits is \(size x bits\).
  • +
  • clock: Optional clock pin, clock by default. A tuple is possible to specify the clock for each address port.
  • +
  • din: Tuple for memory data in port. The read ports must be hardwired to 0.
  • +
  • enable: Tuple for each memory port. Write or read enable (read ports can have enable too).
  • +
  • fwd: Forwarding guaranteed (true/false). If fwd is false, there is no guarantee, it can have fwd or not.
  • +
  • latency: Number of cycles (0 or 1) when the read is performed
  • +
  • wensize: Write enable size allows to have a write mask. The default value + is 1, a wensize of 2 means that there are 2 bits in the enable for each + port. a wensize 2 with 2 ports has a total of 2+2+2 enable bits. Bit 0 of the + enable controls the lower bits of the memory entry selected.
  • +
  • rdport: Indicates which of the ports are read and which are written ports.
  • +
  • posclk: Positive edge clock memory for all the memory clocks. The default is true but it can be set to false.
  • +
+

Lambda attribute list

+

Lambda attributes allow Introspection which requires some attributes.

+
    +
  • inputs: returns the input tuple from the lambda
  • +
  • outputs: returns the input tuple from the lambda
  • +
  • where: returns the lambda used in the where clause
  • +
+

Bitwidth attribute list

+

To set constrains on integer, boolean, and range basic types, the compiler has a set +of bitwidth related attributes:

+
    +
  • max: the maximum value allowed
  • +
  • min: the minimum value allowed
  • +
  • ubits: Maximum number of bits to represent the unsigned value. The number must be positive or zero
  • +
  • sbits: Maximum number of bits, and the number can be negative
  • +
  • wrap: allows to drop bits that do not fit on the left-hand side. It performs sign + extension if needed.
  • +
  • saturate keeps the maximum or minimum (negative integer) that fits on the + left-hand side.
  • +
+

The integer type constructor allows to use a range to set max/min, but it is +syntax sugar for direct attribute set.

+
opt1:uint(300) = 0
+opt2:int:[min=0,max=300] = 0  // same
+opt3::[min=0,max=300] = 0     // same
+opt4:int(0..=300) = 0         // same
+
+assert opt1.[ubits] == 0    // opt1 initialized to 0, so 0 bits
+opt1 = 200
+assert opt1.[ubits] == 8    // last assignment needs 9 sbits or 8 ubits
+tmp  = opt1::[ubits==8] + 1   // expression AND assert opt1.[ubits]==8 check
+
+

The wrap/saturate are attributes that only make sense for attribute set. There +is not much to check/read besides checking that it was set before.

+
a:u32 = 100
+b:u10 = 0
+c:u5  = 0
+d:u5  = 0
+w:u5:[wrap] = 0     // attribute set for all the 'w' uses
+
+b = a               // OK, o precision lost
+c::[wrap] = a       // OK, same as c = a@[0..<5] (Since 100 is 0b1100100, c==4)
+c = a               // compile error, 100 overflows the maximum value of 'c'
+w = a               // OK, 'w' has a wrap set at declaration
+
+c::[saturate] = a   // OK, c == 31
+c = 31
+d = c + 1           // compile error, '32' overflows the maximum value of 'd'
+
+d::[wrap] = c + 1   // OK d == 0
+d::[saturate] = c+1 // OK, d==31
+d::[saturate] = c+1 // OK, d==31
+
+x::[saturate] boolean = c // compile error, saturate only allowed in integers
+
+

comptime attribute

+

Pyrope borrows the comptime functionality from Zig. Any variable can +set/check/read the compile time status. This means that the value must be +constant at compile time or a compile error is generated.

+
let a::[comptime] = 1     // obviously comptime
+b::[comptime] = a + 2     // OK too
+let c::[comptime] = rand  // compile error, 'c' is not compile time constant
+
+

To avoid too frequent comptime directives, Pyrope treats all the variables that +start with uppercase as compile time constants.

+
var Xconst1 = 1      // obvious comptime
+var Xvar2   = rand   // compile error, 'Xvar2' is not compile time constant
+
+

debug attribute

+

In software and more commonly in hardware, it is common to have extra +statements and state to debug the code. These debug functionality can be more +than plain assertions, they can also include code.

+

The debug attribute marks a mutable or immutable variable. At synthesis, all +the statements that use a debug can be removed. debug variables can read +from non debug variables, but non-debug variables can not read from debug. +This guarantees that debug variables, or statements, do not have any +side-effects beyond debug statements.

+
var a = (b::[debug]=2, c = 3) // a.b is a debug variable
+let c::[debug] = 3
+
+

Assignments to debug variables also bypass protection access. This means that +private variables in tuples can be accessed (read-only). Since assert marks +all the results as debug, it allows to read any public/private variable/field.

+
x:(_priv=3, zz=4) = _
+
+let tmp = x._priv         // compile error
+let tmp::[debug] = x.priv // OK
+
+assert x._priv == 3    // OK, assert is a debug statement
+
+

Register

+

Both mutable and immutable variables are created every cycle. To have +persistence across cycles the reg type must be used.

+
reg counter:u32   = 10
+var not_a_reg:u32 = 20
+
+

In reg, the right-hand side of the initialization (10 in the +counterexample) is called only during reset. In non-register variables, the +right-hand side is called every cycle. Most of the cases reg is mutable but +it can be declared as immutable.

+

Public vs private

+

All variables are public by default. To declare a variable private within the +tuple or file the private attribute must be set.

+

The private has different meaning depending on when it is applied:

+
    +
  • +

    When applied to a tuple entry ((field::[private] = 3)), it means that the + entry can not be accessed outside the tuple.

    +
  • +
  • +

    When applied to a pipestage variable (var foo::[private] = 3), it means that the + variable is not pipelined to the next type stage. Section + pipestage has more details.

    +
  • +
  • +

    When is applied to a pyrope file upper scope variable (reg top_reg:[private] + = 0), it means that an import command or register reference can not access + it across files. Section typesystem has more details.

    +
  • +
+

Operators

+

There are the typical basic operators found in most common languages except +exponent operations. The reason is that those are very hardware intensive and a +library code should be used instead.

+

All the operators work over signed integers.

+

Unary operators

+
    +
  • !a or not a logical negation
  • +
  • ~a bitwise negation
  • +
  • -a arithmetic negation
  • +
+

Binary integer operators

+
    +
  • a + b addition
  • +
  • a - b substraction
  • +
  • a * b multiplication
  • +
  • a / b division
  • +
  • a & b bitwise and
  • +
  • a | b bitwise or
  • +
  • a ^ b bitwise xor
  • +
  • a ~& b bitwise nand
  • +
  • a ~| b bitwise nor
  • +
  • a ~^ b bitwise xnor
  • +
  • a >> b arithmetic right shift
  • +
  • a@[..] >> b logical right shift
  • +
  • a << b left shift
  • +
+

In the previous operations, a and b need to be integers. The exception is +a << b where b can be a tuple. The << allows having multiple values +provided by a tuple on the right-hand side or amount. This is useful to create +one-hot encodings.

+
cassert 1<<(1,4,3) == 0b01_1010
+
+

Binary boolean operators

+
    +
  • a and b logical and
  • +
  • a or b logical or
  • +
  • a implies b logical implication
  • +
  • a !and b logical nand
  • +
  • a !or b logical nor
  • +
  • a !implies b logical not implication
  • +
+

Tuple/Set operators

+
    +
  • a in b is element a in tuple b
  • +
  • a !in b true when element a is not in tuple b
  • +
  • tuple(a) converts a to tuple, a can be a boolean, range, integer, + string, or already a tuple
  • +
+

Most operations behave as expected when applied to signed unlimited precision +integers.

+

The a in b checks if values of a are in b. Notice that both can be +tuples. If a is a named tuple, the entries in b match by name, and then +contents. If a is unnamed, it matches only contents by position.

+
cassert (1,2) in (0,1,3,2,4)
+cassert (1,2) in (a=0,b=1,c=3,2,e=4)
+cassert (a=2) !in (1,2,3)
+cassert (a=2) in (1,a=2,c=3)
+cassert (a=1,2) in (3,2,4,a=1)
+cassert (a=1,2) !in (1,2,4,a=4)
+cassert (a=1) !in (a=(1,2))
+
+

The a in b has to deal with undefined values (nil, 0sb?). The LHS with an undefined +will be true if the RHS has the same named entry either defined or undefined.

+
cassert (x=nil,c=3) in (x=3,c=3)
+cassert (x=nil,c=3) in (x=nil,c=3,d=4)
+cassert (c=3)      !in (c=nil,d=4)
+
+
    +
  • a ++ b concatenate two tuples. If field appears in both, concatenate field. The a field is +defined in one tupe and undefined in the other, the undefined value is not concatenated.
  • +
+
cassert ((a=1,c=3) ++ (a=1,b=2,c=nil)) == (a=(1,1), c=3, b=2)
+cassert ((1,2) ++ (a=2,nil,5)) == (1,2,a=2,5)
+cassert ((x=1) ++ (a=2,nil,5)) == (x=1,a=2,nil,5)
+
+cassert ((x=1,b=2) ++ (x=0sb?,3)) == (x=1,b=2,3)
+
+
    +
  • (,...b) in-place insert b. Behaves like a ++ b but it triggers a + compile error if both have the same defined named field.
  • +
+
cassert (1,b=2,...(3,c=3),6) == (1,b=2,3,c=3,6)
+cassert (1,b=2,...(nil,c=3),0sb?,6) == (1,b=2,nil,c=3,0sb?,6)
+
+

Type operators

+
    +
  • a has b checks if a tuple has the b field where b is a string or + integer (position).
  • +
+
cassert((a=1,b=2) has "a")
+
+
    +
  • a does b is the tuple structure of a a subset of b
  • +
  • a equals b same as (a does b) and (b does a)
  • +
  • a case b same as cassert a does b and for each b field with a defined value, + the value matches a (nil, 0sb? are undefined values)
  • +
  • a is b is a nominal type check. Equivalent to a::[typename] == b::[typename]
  • +
+

Each type operator also has the negated (a !does b) == !(a does b), (a +!equals b) == !(a equals b), a !case b == !(a case b)

+

The does performs just name matching when the LHS is a named tuple. It +reverts to name and position matching when some of the LHS entries are unnamed.

+
cassert (a=1,b=3) does (b=100,a=333,e=40,5)
+cassert (a=1,3) does (a=100,300,b=333,e=40,5)
+cassert (a=1,3) !does (b=100,300,a=333,e=40,5)
+
+

A a case b is equivalent to cassert b does a and for each defined value in +b there has to be the same value in a. This can be used in any expression +but it is quite useful for match ... case patterns.

+
match (a=1,b=3) {
+  case (a=1) { cassert true }
+  else { cassert false }
+}
+
+match let t=(a=1,b=3); t {
+  case (a=1  ,c=4) { cassert false }
+  case (b=nil,a=1) { cassert t.b==3 and t.a==1 }
+  else { cassert false }
+}
+
+

An x = a case b can be translated to:

+
cassert b does a
+x = b in a
+
+

Reduce and bit selection operators

+

The reduce operators and bit selection share a common syntax +variable@op[sel] where:

+
    +
  • +

    variable is a tuple where all the tuple fields and subfields must have a + explicit type size unless the tuple has 1 entry.

    +
  • +
  • +

    op is the operation to perform

    +
      +
    • |: or-reduce.
    • +
    • &: and-reduce.
    • +
    • ^: xor-reduce or parity check.
    • +
    • +: pop-count.
    • +
    • sext: Sign extends selected bits.
    • +
    • zext: Zero sign extends selected bits (default option)
    • +
    +
  • +
  • +

    sel can be a close-range like 1..<=4 or (1,4,6) or an open range like + 3... Internally, the open range is converted to a close-range based on the + variable size.

    +
  • +
+

The or/and/xor reduce have a single bit signed result (not boolean). This means +that the result can be 0 (0sb0) or -1 (0sb1). pop-count and zext have +always positive results. sext is a sign-extended, so it can be positive or +negative.

+

If no operator is provided, a zext is used by default. The bit selection without +operator can also be used on the left-hand side to update a set of bits.

+

The or-reduce and and-reduce are always size insensitive. This means that to +perform the reduction it is not needed to know the number of bits. It could +pick more or fewer bits and the result is the same. E.g: 0sb111 or 0sb111111 +have the same and/or reduce. This is the reason why both can work with open and +close ranges.

+

This is not the case for the xor-reduce and pop-count. These two operations are +size insensitive for positive numbers but sensitive for negative numbers. E.g: +pop-count of 0sb111 is different than 0sb111111. When the variable is negative +a close range must be used. Alternatively, a zext must be used to select +bits accordingly. E.g: variable@[0..=3]@+[..] does a zext and the positive result +is passed to the pop-count. The compiler could infer the size and compute, but +it is considered non-intuitive for programmers.

+
x = 0b1_0110   // positive
+y = 0s1_0110   // negative
+assert x@[0,2] == 0b10
+assert y@[100,200]       == 0b11   and x@[100,200]       == 0
+assert y@sext[0,100,200] == 0sb110 and x@sext[1,100,200] == 0b001
+assert x@|[..] == -1
+assert x@&[0,1] == 0
+assert x@+[0..=5] == x@+[0..<100] == 3
+assert y@+[0..=5]  // compile error, 'y' can be negative
+assert y@[..]@+[..] == 3
+assert y@[0..=5]@+[..] == 3
+assert y@[0..=6]@+[..] == 4
+
+var z     = 0b0110
+z@[0] = 1
+assert z == 0b0111
+z@[0] = 0b11 // compile error, '0b11` overflows the maximum allowed value of `z@[0]`
+
+
+

Note

+

It is important to remember that in Pyrope all the operations use signed +numbers. This means that an and-reduce over any positive number is always going +to be zero because the most significant bit is zero, E.g: 0xFF@&[..] == 0. In +some cases, a close-range will be needed if the intention is to ignore the sign. +E.g: 0xFF@&[0..<8] == -1.

+
+

The bit selection operator only works with ranges, boolean, and integers. It +does not work with tuples or strings. For converting in these object a union: +must be used.

+

Another important characteristic of the bit selection is that the order of the +bits on the selection does not affect the result. Internally, it is a bitmask +that has no order. For the zext and sext, the same order as the input +variable is respected. This means that var@[1,2] == var@[2,1]. As a result, +the bit selection can not be used to transpose bits. A tuple must be used for +such an operation.

+
var v = 0b10
+assert v@[0,1] == v@[1,2] == v@[..] == v@[0..=1] == v@[..=1] == 0b10
+
+var trans = 0
+
+trans@[0] = v@[1]
+trans@[1] = v@[0]
+assert trans == 0b01
+
+

Precedence

+

Pyrope has very shallow precedence, unlike most other languages the +programmer should explicitly indicate the precedence. The exception is for +widely expected precedence.

+
    +
  • Unary operators (not,!,~,?) bind stronger than binary operators (+,++,-,*...)
  • +
  • Comparators can be chained (a<=c<=d) same as (a<=c and c<=d)
  • +
  • mult/div precedence is only against +,- operators.
  • +
  • Parenthesis can be avoided when a expression left-to-right has the same + result as right-to-left.
  • +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PriorityCategoryMain operators in category
1unarynot ! ~ ?
2mult/div*, /
3other binary..,^, &, -,+, ++, <<, >>, in, does, has, case, equals, to
4comparators<, <=, ==, !=, >=, >
5logicaland, or, implies
+
assert((x or !y) == (x or (!y)) == (x or not y))
+assert((3*5+5) == ((3*5) + 5) == 3*5 + 5)
+
+a = x1 or x2==x3 // same as b = x1 or (x2==x3)
+b = 3 & 4 * 4    // compile error: use parenthesis for explicit precedence
+c = 3
+  & 4 * 4
+  & 5 + 3        // compile error: use parenthesis for explicit precedence
+c2 = 3
+  & (4 * 4)
+  & (5 + 3)      // OK
+
+d = 3 + 3 - 5    // OK, same result right-left
+
+e = 1
+  | 5
+  & 6           // compile error: use parenthesis for explicit precedence
+
+f = (1 & 4)
+  | (1 + 5)
+  | 1
+
+g = 1 + 3
+  * 1 + 2
+  + 5           // OK, but not nice
+
+g1= 1 + (3 * 1)
+  + 2
+  + 5           // OK
+
+g2= (1 + 3)
+  * (1 + 2)
+  + 5           // OK
+
+h = x or y and z// compile error: use parenthesis for explicit precedence
+
+i = a == 3 <= b == d
+assert i == (a==3 and 3<=b and b == d)
+
+

Comparators can be chained, but only when they follow the same type.

+
assert a <= b <= c  // same as a<=b and b<=c
+assert a == b <= c  // compile error, chained only allowed with same comparator
+
+

Optional

+

The ? is used by several languages to handle optional or null pointer +references. In non-hardware languages, ? is used to check if there is valid +data or a null pointer. This is the same as checking the ::[valid] attribute +with a more friendly syntax.

+

Pyrope does not have null pointers or memory associated management. Pyrope uses +? to handle ::[valid] data. Instead, the data is left to behave without the +optional, but there is a new "valid" field associated with each tuple entry. +Notice that it is not for each tuple level but each tuple entry.

+

There are 4 explicitly interact with valids:

+
    +
  • +

    tup.f1? reads the valid for field f1 from tuple tup

    +
  • +
  • +

    tup?.f1.f2 returns 0bs0 if tuple fields f1 or f2 are invalid

    +
  • +
  • +

    tup.f1? = cond explicitly sets the field f1 valid to cond

    +
  • +
  • +

    a = b op c variable a will be valid if b AND c are valid

    +
  • +
+

The optional or valid attached to each variable and tuple field is implicitly +computed as follows:

+
    +
  • +

    Non-register variables are initialized with valid unless _ is used in the + initialization which explicitly clears the valid attribute.

    +
  • +
  • +

    Registers set the valid after reset, but if the reset clears the valid, there + is not guaranteed on attribute [valid] during reset. If the register does + not have a reset signal, the register is always valid unless explicitly + cleared.

    +
  • +
  • +

    Left-hand side variables valids are set to the and-gate of all the variable + valids used in the expression

    +
  • +
  • +

    memory/arrays do not tend to have reset signals. As such they are always + valid unless the memory has explicit reset code. In which case the valid + behaves like in flops.

    +
  • +
  • +

    Writing to a register updates the register valid based on the din valid, or + when the attribute [valid] is explicitly managed.

    +
  • +
  • +

    conditionals (if) update valids independently for each path

    +
  • +
  • +

    A tuple field has the valid set to false if any of the tuple fields is + invalid

    +
  • +
  • +

    The valid computation can be overwritten with the [valid] attribute. This + is possible even during reset.

    +
  • +
+
+

Observation

+

The variable valid calculation is similar to the Elastic 'output_written' +from Liam but it is not an +elastic update because it does not consider the abort or retry.

+
+

The previous rules will clear a valid only if an expression has no valid, but +the only way to have a non-valid is if the inputs to the lambda are invalid or +if the valid is explicitly clear. The rules are designed to have no overhead +when valid are not used. The compiler should detect that the valid is true all +the time, and the associated logic is removed.

+

Most statements evaluate independent of the valid expression. Expressions will +evaluate the same if any of the inputs is valid or invalid. The valid attribute +is computed in parallel to avoid being in the critical path. The exception are +the verification statements like asserts and printing statatements like puts. +These statements are gated or not performed if any of the inputs is invalid. To +ignore the valid check, the always command can be appended before and as a +result the statments will evaluate every cycle independent of the reset/valid +status.

+
var v1:u32 = _                 // v1 is zero every cycle AND not valid
+assert v1.[valid] == false
+var v2:u32 = 0                 // v2 is zero every cycle AND     valid
+assert v2.[valid] == true
+
+cassert v1?
+cassert not v2?
+
+assert v1 == 0 and v2 == 3     // data still same as usual
+
+v1 = 0sb?                      // OK, poison data
+v2 = 0sb?                      // OK, poison data, and update valid
+assert v2?                     // valid even though data is not
+
+assert v1 != 0                 // usual verilog x logic
+assert v2 != 0                 // usual verilog x logic
+
+let res1 = v1 + 0              // valid with just unknown 0sb? data
+let res2 = v2 + 0              // valid with just unknown 0sb? data
+
+assert res1?
+assert res2?
+
+reg counter:u32 = 0
+
+always assert counter.reset implies !counter?
+
+

valid can be overwritten by the setter method:

+
let custom = (
+  ,data:i16 = _
+  ,setter = proc(ref self, v) {
+    self.data = v
+    self.[valid] = v != 33
+  }
+)
+
+var x:custom = _
+
+cassert x?
+x.data = 33
+cassert not x?
+x.data = 100
+cassert x?
+
+

The contents of the tuple field do not affect the field valid bit. It is +data-independent. Tuples also can have an optional type, which behaves like +adding optional to each of the tuple fields.

+
let complex = (
+  ,reg v1:string = "foo"
+  ,v2:string = _
+
+  ,setter = proc(ref self,v) {
+     self.v1 = v
+     self.v2 = v
+  }
+)
+
+var x1:complex = _
+var x2:complex:[valid=false] = 0  // toggle valid, and set zero
+var x3:complex = 0
+x3.[valid] = false                // set invalid
+
+assert x1.v1 == "" and x1.v2 == ""
+assert not x2? and not x2.v1? and not v2.v2?
+assert x2.v1 == "" and x2.v2 == ""
+
+assert x2?.v1 == "" and x2?.v1 != ""  // any comparison is false
+
+// When x2? is false, any x2?.foo returns 0sb? with the associated x rules
+
+x2.v2 = "hello" // direct access still OK
+
+assert not x2? and x2.v1 == "" and x2.v2 == "hello"
+
+x2 = "world"
+
+assert x2? and x2?.v1 == "world" and x2.v1 == "world"
+
+

Variable initialization

+

Variable initialization indicates the default value set every cycle and the +optional (::[valid] attribute).

+

The let and var statements require an initialization value for each cycle. +Pyrope only has undefined values unless explicitly indicated. A variable has an +undefined value if and only if the value is set to nil or all the bits are +unknown (0sb?). Undefined variables always have invalid optional +(.[valid]==false), and defined can have valid or invalid optional.

+

On any assignment (v = _) where the rhs is a single underscore _, the +variable optional is set to false, and it is assigned the default value:

+
    +
  • 0 for integer
  • +
  • false for boolean
  • +
  • "" for string
  • +
  • nil otherwise
  • +
+
var a:int = _
+cassert a==0 and a.[valid] == false and not a?
+
+var b:int = 0
+cassert b==0 and b.[valid] and b?
+b = nil
+cassert b==nil and b.[valid] == false and not b?
+
+var c:fun(a1) = _
+cassert c == nil and c.[valid]==false
+c = fun(a1) { cassert true }
+cassert c!= nil and c.[valid]
+
+var d:[] = _               // empty tuple
+cassert d != nil and d.[valid]
+cassert d[0] == nil and !d[0].[valid]
+
+var e:int = nil
+cassert e==nil and !e.[valid] and not e?
+e = 0
+cassert e==0 and e.[valid] and e?
+
+

The same rules apply when a tuple or a type is declared.

+
let a = "foo"
+
+var at1 = (
+  ,a:string 
+)
+cassert at1[0] == "foo"
+cassert at1 !has "a"    // at1.a undefined
+
+var at2 = (
+  ,a:string = _
+)
+cassert at2.a == ""  and at2.a.[valid]==false
+at2.a = "torrellas"
+cassert at2.a == "torrellas" and at2[0] == "torrellas"
+
+var at3:at2 = _
+cassert at3.a == ""  and at3.a.[valid]==false
+
+var at4:at2 = (a="josep")
+cassert at4.a == "josep"  and at4.a.[valid] and at4.[valid]
+
+

Conditional path affect variable initialization and values. If all the +conditional passes assign a value, the valid will be true. If only one path +assigns a value, the valid will be set only on that path, but the data may +always have the path.

+
var x=_
+var y=2
+var z=_
+if rand {
+  x = 3
+  y = 4
+  z = 5
+}else{
+  z = 6
+}
+assert x==3  // Simplified due to the _ initialization
+assert rand      implies x.[valid]
+assert x.[valid] implies rand
+
+assert y.[valid]
+assert  rand implies y == 4
+assert !rand implies y == 2
+
+assert z.[valid]
+assert  rand implies z == 5
+assert !rand implies z == 6
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyrope/05-assert/index.html b/pyrope/05-assert/index.html new file mode 100644 index 0000000..f8f4591 --- /dev/null +++ b/pyrope/05-assert/index.html @@ -0,0 +1,1345 @@ + + + + + + + + + + + + + + + + + + + + + + Verification - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Verification

+

Verification covers the language constructs and special support to ease design verification.

+

Assertions

+

Assertions are considered debug statements. This means that they can not +have side effects on non-debug statements.

+

Pyrope supports a syntax close to Verilog for assertions. The language is +designed to have 3 levels of assertion checking: compilation time, +simulation runtime, and formal verification time.

+

There are 5 main verification statements:

+
    +
  • +

    assert and cassert are used to specify conditions that should hold true. + cassert is required to hold true at compile time and assert can be + checked either at compile or runtime if too slow to check. If the condition + doesn't hold, an error is raised.

    +
  • +
  • +

    optimize is exactly like assert, but it also allows the tool to simplify + code based on the given conditions. This can lead to more efficient code + generation. While unproven assert can be enabled/disabled during + simulation, optimize can not be disabled because it can lead to incorrect + simulation state.

    +
  • +
  • +

    requires is statement that can be placed in lambdas. The clause specifies + pre conditions to be true when the lambda is called. requires allows for code + optimizations like optimize statement.

    +
  • +
  • +

    ensures is a statement similar to requires but the clause specifies a + post condition. ensures allows code optimizations like optimize statement.

    +
  • +
+

Hardware setups always have an extensive CI/verification setup. This means that +run-time assertion failures are OK, better compile time to reduce design time, +but OK at simulation time. This means that in things like type check, if it may +be OK but not possible to prove, the compiler can decide to insert an assert +instead of forcing a code structure change. To enforce that an assertion is +checked only at compile time a cassert must be used. assert, requires, +ensures can be checked at runtime if not possible to check at compile time.

+
a = 3
+assert a == 3          // checked at runtime (or compile time)
+cassert a == 3         // checked at compile time
+
+optimize b > 3         // may optimize and perform a runtime check
+
+let max_not_zero = fun(a,b) -> (res)
+  requires a>0
+  requires b>0
+  ensures res==a or res==b {
+
+  res = if a>b {a} else {b}
+}
+
+

A whole statement is conditionally executed using the when/unless gate expression. +This is useful to gate verification statements (assert, optimize) +that can have spurious error messages under some conditions.

+
a = 0
+if cond {
+  a = 3
+}
+assert cond implies a == 3, "the branch was taken, so it must be 3??"
+assert a == 3, "the same error" when   cond
+assert a == 0, "the same error" unless cond
+
+

The recommendation is to write as many assert and optimize as possible. If +something can not happen, writing the optimize has the advantage of allowing +the synthesis tool to generate more efficient code.

+

The optimize will allow code optimizations, the cassert should also result +in code optimizations. The reason why assert does not trigger optimizations +is because they can be enabled/disabled at simulation time.

+

In a way, most type checks have equivalent cassert checks.

+

LEC

+

The lec command is a formal verification step that checks that all the +arguments are logically equivalent. lec only works for combinational logic, +so does not need to worry about state or reset signals. The first argument is +the gold model, the rest are implementation. This matters because the gold +model unknown output bit checks against any value for the equivalent +implementation bit.

+
+

Note

+

The recommendation is to use optimize and assert frequently, but +clearly to check preconditions and postconditions of methods. The 1949 +Turing quote of how to write assertions and programs is still valid "the +programmer should make a number of definite assertions which can be checked +individually, and from which the correctness of the whole program easily +follows."

+
+
let fun1 = fun(a,b) { a | b}
+let fun2 = fun(a,b) { ~(~a | ~b) }
+lec fun1, fun2
+
+

In addition, there is the lec_valid command. It is similar to lec but it +checks the optional or valid (::[valid]) from the output. It can take several +cycles to show the same result.

+
let mul2 = proc(a,b) -> (reg out) {
+  reg pipe1 = _
+
+  out = pipe1
+
+  pipe1 = a*b
+}
+
+let mul0 = fun(a,b)->(out) { out = a*b }
+
+lec_valid mul0, mult2
+
+

Coverage

+

A bit connected with the assertion is coverage. The goal of an assertion is to be +true all the time. The goal of a coverage point is to be true at least once +during testing.

+

There are two directives cover and covercase. The names are similar to the +System Verilog coverpoint and covergroup but the meaning is not the same.

+
    +
  • +

    cover cond [, message] the boolean expression cond must evaluate true + sometime during the verification or the tool can prove that it is true at + compile time.

    +
  • +
  • +

    covercase grp, cond [,message] is very similar to cover but it has a grp + group. There can be one or more covers for a given group. The extra check is + that one of the cond in the cover case must be true each time.

    +
  • +
+
// coverage case NUM group states that random should be odd or even
+covecase NUM,   random&1 , "odd number"
+covecase NUM, !(random&1), "even number"
+
+covercase COND1, reset, "in reset"
+covercase COND1, val>3, "bigger than 3"
+
+assert((!reset and val>3) or reset)  // less checks than COND1
+
+cover a==3, "at least a is 3 once in a while"
+
+

The covercase is similar to writing the assertions, but it checks that all +the conditions happen through time or a low coverage is reported. In the +COND1 case, the assertion does not check that sometimes reset is set, and +others the value is bigger than 3. The assertion will succeed if reset is always +set, but the covercase will fail because the "bigger than 3" case will not be +tested.

+

The cover allows to not be true a given cycle. To allow the same in a +covercase, the designer can add coverase GRP, true. This is a true always +cover point for the indicated cover group.

+

Reset, optional, and verification

+

In hardware is common to have an undefined state during the reset period. To +avoid unnecessary assertion failures, if any of the inputs depends on a +register directly or indirectly, the assertion is not checked when the reset is +high for the given registers. In Pyrope, the registers and memory contents +outputs are "invalid" (::[valid] attribute). assert and optimize will not +check when any of the signals are invalid. This is useful to avoid unnecessary +assert checks during reset or when the lambda is called with invalid data.

+

Adding the always modifier before the assert/coverage keywords guarantees +that the check is performed every cycle independent of the valid attribute.

+

To provide assert/optimize during reset, Pyrope provides a always assert, +always cassert, always optimize, always covercase, and +always cover.

+
reg memory:[]u33 = (1,2,3) // may take cycles to load this contents
+
+assert memory[0] == 1 // not checked during reset
+
+always assert memory[1] == 2 // may fail during reset
+always assert memory[1] == 2 unless memory.reset  // should not fail
+
+

Random

+

Random number generation are quite useful for verification. Pyrope provides +easy interfaces to generate "compile time" (::[crand]) and "simulation time" +random number (::[rand]) generation.

+
let x:u8 = _
+
+for i in 1..<100 {
+  cassert 0 <= x.[crand]  <= 255
+}
+
+let get_rand_0_2556 = fun(a:u8) {
+  a.[rand]
+}
+
+

Both rand and crand look at the set type max/min value and create a randon value +between them. rand picks randomly in boolean and enumerate types, but it triggers +a compile error for string, range, and lambda types.

+

When applied to a tuple, it randomly picks an entry from the tuple.

+
let a = (1,2,3,b=4)
+let x = a.[rand]
+
+cassert x==1 or x==2 or x==3 or x==4
+cassert x.b==4 when x==4
+
+

The simulation random number is considered a ::[debug] statement, this means +that it can not have an impact on synthesis or a compile error is generated.

+

Test

+

Pyrope has the test [message [,args]+] ( [stmts+] }.

+
+
+
+
let add = fun(a,b) { a+b }
+
+for a in 0..=20 {
+  for b in 0..=20 {
+    test "checking add({},{})", a,b {
+       cassert a+b == add(a,b)
+    }
+  }
+}
+
+
+
+
let add = fun(a,b) { a+b }
+
+test "checking add" {
+  for a in 0..=20 {
+    for b in 0..=20 {
+       cassert a+b == add(a,b)
+    }
+  }
+}
+
+
+
+
+

The test code block also accepts the keyword step that advances one clock +cycle, and the test continues from that given point. This is useful for when a +lambda is instantiated and we want to check/update the inputs/outputs.

+
let counter = proc(update)->(value) {
+  reg count:u8:[wrap] = 0
+
+  value = count
+
+  count += 1 when update
+}
+
+test "counter through several cycles" {
+
+  var inp = true
+  let x = counter(inp.[defer])  // inp contents at the end of each cycle
+
+  assert x == 0 // x.value == 0
+  assert inp == true
+
+  step
+
+  assert x == 1
+  inp = false
+
+  step
+
+  assert x == 1
+  assert inp == false
+  inp = true
+
+  assert inp == true
+  assert x == 1
+
+  step
+
+  assert inp == true
+  assert x == 2
+}
+
+

During test simulation, all the assertions are checked but the test does not +stop with a failure until the end. Sometimes it is useful to write tests to +check that assertions fail. Assertion failures will be printed but the test +will continue and fail only if the assert.[failed] is true. The test code +block also accepts to read and/or clear failed attribute.

+
test "assert should fail" {
+
+ let n = assert.[failed]
+ assert n == false
+
+ assert false // FAILS
+
+ assert assert.[false]
+
+ assert.[failed] = false // disable test failures done when it finishes
+}
+
+

Monitor

+

TODO

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyrope/05b-statements/index.html b/pyrope/05b-statements/index.html new file mode 100644 index 0000000..0f6c72f --- /dev/null +++ b/pyrope/05b-statements/index.html @@ -0,0 +1,1612 @@ + + + + + + + + + + + + + + + + + + + + + + Statements - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Statements

+

Conditional (if/elif/else)

+

Pyrope uses a typical if, elif, else sequence found in most languages. +Before the if starts, there is an optional keyword unique that enforces that +a single condition is true in the if/elif chain. This is useful for synthesis +which allows a parallel mux. The unique is a cleaner way to write an +optimize statement.

+

The if sequence can be used in expressions too.

+
a = unique if x1 == 1 {
+    300
+  }elif x2 == 2 {
+    400
+  }else{
+    500
+  }
+
+var x = _
+if a { x = 3 } else { x = 4 }
+
+

The equivalent code with an explicit optimize, but unlike the optimize, the +unique will guarantee to generate the hotmux statement.

+
optimize !(x1==1 and x2==2)
+a = if x1 == 1 {
+    300
+  }elif x2 == 2 {
+    400
+  }else{
+    500
+  }
+
+

Like several modern programming languages, there can be a list of expressions +in the evaluation condition. If variables are declared, they are restricted to +the remaining if/else statement blocks.

+
var tmp = x+1
+
+if var x1=x+1; x1 == tmp {
+   puts "x1:{} is the same as tmp:{}", x1, tmp
+}elif var x2=x+2; x2 == tmp {
+   puts "x1:{} != x2:{} == tmp:{}", x1, x2, tmp
+}
+
+

Unique parallel conditional (match)

+

The match statement is similar to a chain of unique if/elif, like the unique +if/elif sequence, one of the options in the match must be true. The difference +is that one of the entries must be truth or an error is generated. This makes +the match statement a replacement for the common "unique parallel case" +Verilog directive. The match statement behaves like also having an optimize +statement which allows for more efficient code generation than a sequence of +if/else.

+

In addition to functionality, the syntax is different to avoid redundancy. +match joins the match expression with the beginning of the matching entry must +form a valid expression.

+
x = 1
+match x {
+  == 1            { puts "always true" }
+  in 2,3          { puts "never"       }
+}
+// It is equivalent to:
+unique if x == 1  { puts "always true" }
+elif x in (2,3)   { puts "never"       }
+else              { assert false       }
+
+

Like the if, it can also be used as an expression.

+
var hot = match x {
+    == 0sb001 { a }
+    == 0sb010 { b }
+    == 0sb100 { c }
+  }
+
+// Equivalent
+optimize (x==0sb001 or x==0sb010 or x==0sb100)
+var hot2 = __hotmux(x, a, b, c)
+
+assert hot==hot2
+
+

Like the if statement, a sequence of statements and declarations are possible in the match statement.

+
match let one=1 ; one ++ (2) {
+  == (1,2) { puts "one:{}", one }      // should always hit
+}
+
+

Since the == is the most common condition in the match statement, it can be +omitted.

+
for x in 1..=5 {
+  let v1 = match x {
+    3 { "three" }
+    4 { "four" }
+    else { "neither"}
+  }
+
+  let v2 = match x {
+    == 3 { "three" }
+    == 4 { "four" }
+    else { "neither"}
+  }
+  cassert v1 == v2
+}
+
+

Gate statements (when/unless)

+

A simple statement like assignments, variable declarations, and function calls +and returns can be gated or not executed with a when or unless statement. +This is similar to an if statement, but the difference is that the statement +is in the current scope, not creating a new scope. This allows cleaner more +compact syntax.

+
var a = 3
+a += 1 when false             // never executes 
+assert a == 3
+assert a == 1000 when a > 10  // assert never executed either
+
+reg my = 3 when some_condition  // no register declared otherwise
+
+return "fail" unless success_condition
+
+

Complex assignments like a |> b(1) |> c can not be gated because it is not +clear if the gated applies to the last call or the whole pipeline sequence. +Similarly, gating ifs/match statements do not make much sense. As a result, +when/unless can only be applied to assignments, function calls, and code +block control statements (return, break, continue).

+

Code block

+

A code block is a sequence of statements delimited by { and }. The +functionality is the same as in other languages. Variables declared within +a code block are not visible outside the code block. In other words, code block +variables have scope from definition until the end of the code block.

+

Code blocks are different from lambdas. A lambda consists of a code block but +it has several differences. In lambdas, (1) variables defined in upper scopes +are accessed inside as immutable copies only when captured by scope; (2) inputs +and outputs could be constrained, and (3) the return statement finishes a +lambda not a code block.

+

The main features of code blocks:

+
    +
  • +

    Code blocks define a new scope. New variable declarations inside are not visible outside it.

    +
  • +
  • +

    Code blocks do not allow variable declaration shadowing.

    +
  • +
  • +

    Expressions can have multiple code blocks but they are not allowed to have + side-effects for variables outside the code block. The evaluation + order provides more details on expressions + evaluation order.

    +
  • +
  • +

    When used in an expression or lambda, the last statement in the lambda code + block can be an expression. It is not needed to add the return keyword in + this case.

    +
  • +
+
{
+  var x=1
+  var z=_
+  {
+    z = 10
+    var x=_           // compiler error, 'x' is a shawdow variable
+  }
+  assert z == 10 
+}
+let zz = x            // compile error, `x` is out of scope
+
+var yy = {let x=3 ; 33/3} + 1
+assert yy == 12
+let xx = {yy=1 ; 33}  // compile error, 'yy' has side effects
+
+if {let a=1+yy; 13<a} {
+  // a is not visible in this scope
+  some_code()
+}
+
+let doit = fun(f,a) {
+  let x = f(a)
+  assert x == 7
+  return 3
+}
+
+let z3 = doit(fun(a) { 
+  assert a!=0
+  return 7             // exist the current lambda
+  100                  // never reached statement
+}, 33)
+cassert z3 == 3
+
+

Loop (for)

+

The for iterates over the first-level elements in a tuple or the values in a +range. In all the cases, the number of loop iterations must be known at +compile time. The loop exit condition can not be run-time data-dependent.

+

The loop can have an early exit when calling break and skip of the current +iteration with the continue keyword.

+
for i in 0..<100 {
+ some_code(i)
+}
+
+var bund = (1,2,3,4)
+for (index,i) in bund.enumerate() {
+  assert bund[j] == i
+}
+
+
let b = (a=1,b=3,c=5,7,11)
+assert b.keys() == ('a', 'b', 'c', '', '')
+assert b.enumerate() == ((0,1), (1,3), (2,5), (3,7), (4,11))
+let xx= zip(b.keys(), b.enumerate()) 
+cassert xx == (('a',0,a=1), ('b',1,b=3), ('c',2,c=5), ('',3,7), ('',4,11))
+
+for (key,index,i) in zip(keys(b),b.enumerate()) {
+  assert i==1  implies (index==0 and key == 'a')
+  assert i==3  implies (index==1 and key == 'b')
+  assert i==5  implies (index==2 and key == 'c')
+  assert i==7  implies (index==3 and key == '' )
+  assert i==11 implies (index==4 and key == '' )
+}
+
+let c = ((1,a=3), b=4, c=(x=1,y=6))
+assert c.enumerate() == ((0,(1,a=3)), (1,b=4), (2,c=(x=1,y=6)))
+
+

The for can also be used in an expression that allows building comprehensions +to initialize arrays. Pyrope uses a comprehension similar to Julia or Python.

+
var c = for i in 1..<5 { var xx = i }  // compile error, no expression
+var d = i for i in 0..<5 
+var e = i for i in 0..<5 if i
+assert (0,1,2,3,4) == d
+assert e == (1,2,3,4)
+
+

The iterating element is copied by value, if the intention is to iterate over a +vector or array to modify the contents, a ref must be used. Only the element +is mutable. When a ref is used, it must be a variable reference, not a +function call return (value). The mutable for can not be used in +comprehensions.

+
b = (1,2,3,4,5)
+
+for x in ref b {
+  x += 1
+}
+assert b == (2,3,4,5,6)
+
+

Code block control

+

Code block control statements allow changing the control flow for lambdas and +loop statements (for, loop, and while). return can have a value.

+
    +
  • +

    return exits or terminates the current lambda. The current output variables + are provided as the lambda output. If a tuple is provided, the tuple is the + returned value, the output variables are not used.

    +
  • +
  • +

    break terminates the closest inner loop (for/while/loop). If none is + found, a compile error is generated.

    +
  • +
  • +

    continue looks for the closest inner loop (for/while/loop) code + block. The continue will perform the next loop iteration. If no inner loop + is found, a compile error is generated.

    +
  • +
+
var total:[] = _
+for a in 1..=10 {
+  continue when a == 2
+  total ++= a
+  break when a == 3    // exit for scope
+}
+assert total == (1,3)
+
+if true {
+  code(x)
+  continue             // compile error, no upper loop scope
+}
+
+a = 3
+var total2:[] = _
+while a>0 {
+  total2 ++= a
+  break when a == 2    // exit if scope
+  a = a - 1
+  continue
+  assert false         // never executed
+}
+assert total2 == (3,2)
+
+total = i+10 for i in 1..=9 if i<3
+assert total == (11, 12)
+
+

while/loop

+

while cond { [stmts]+ } is a typical while loop found in most programming +languages. The only difference is that like with loops, the while must be fully +unrolled at compilation time. The loop { [stmts]+ } is equivalent to a while +true { [stmts]+ }.

+

Like if/match, the while condition can have a sequence of statements with +variable declarations visible only inside the while statements.

+
// a do while contruct does not exist, but a loop is quite clean/close
+
+var a = 0
+loop {
+  puts "a:{}",a
+
+  a += 1
+
+  break unless a < 10 
+} // do{ ... }while(a<10)
+
+

defer

+

A defer attribute can be applied to variables. When used to read a variable, +it returns the last values written to the variable the end of the current +cycle. This is needed if we need to have any loop in connecting blocks. The +defer applied to a write, delays the write update to the end of the cycle. +The delayed writes happen before the delayed reads. This is also for delaying +assertion checks to the end of the cycle like post condition checks.

+
var c = 10
+assert b.[defer] == 33    // behaves like a postcondition
+b = c.[defer]
+assert b == 33
+c += 20
+c += 3
+
+

To connect the ring function calls in a loop. +

f1 = ring(a, f4.[defer])
+f2 = ring(b, f1)
+f3 = ring(c, f2)
+f4 = ring(d, f3)
+

+

If the intention is to read the result after being a flop, there is no need to +use the defer, a normal register access could do it. If the read +variables are registers, the flop#[0] is not the same as defer. The flop#[0] +reads the value before any update, the defer read, gets values after updates.

+
reg counter:u32 = _
+
+let counter_m1 = counter#[1]  // compile error, #[1] only allowed for debug
+let counter_0  = counter#[0]  // current cycle 
+let counter_1  = counter#[-1] // last cycle
+let counter_2  = counter#[-2] // last last cycle cycle 
+
+var deferred = counter.[defer]
+
+if counter < 100 {
+  counter += 1
+}else{
+  counter = 0
+}
+
+if counter == 10 {
+  assert deferred   == 10
+  assert counter_0  ==  9
+  assert counter_1  ==  8
+  assert counter_2  ==  7
+}
+
+

The defer can also be applied to write/updates to the end of the cycle but +uses/reads the current value. In a way, the assignment is delayed to the end of +the current cycle. If there are many defers to the same variable, they are +ordered in program order.

+
var a = 1
+assert a == 1 and a.[defer] == 200
+
+a::[defer] = 100
+assert a == 1 and a.[defer] == 200
+
+a::[defer] = 200
+assert a == 1 and a.[defer] == 200
+
+

If there are defer reads and defer assignments, the defered writes are +performed before the defered reads.

+
var a = 1
+var x = 100
+x::[defer] = a
+a = 200
+
+cassert x == 100
+assert x.[defer] == 1
+
+

Testing (test)

+

The test statement requires a text identifier to notify when the test fails. +The test is similar to a puts statement followed by a scope (test <str> +[,args] { stmts+ }). The statements inside the code block can not have any +effect outside.

+
test "my test {}", 1 {
+  assert true
+}
+
+

Each test can run in parallel, to increase the throughput, putting the +randomization outside the test statement increases the number of tests:

+
+
+
+
let add = fun(a,b) { a+b }
+
+for i in 0..<10 { // 10 tests
+  let a = (-30..<100).rand
+  let b = (-30..<100).rand
+
+  test "test {}+{}",a,b {
+    assert add(a,b) == (a+b)
+  }
+}
+
+
+
+
let add = fun(a,b) { a+b }
+
+test "test 10 additions" {
+  for i in 0..<10 { // 10 tests
+    let a = (-30..<100).rand
+    let b = (-30..<100).rand
+
+    assert add(a,b) == (a+b)
+  }
+}
+
+
+
+
+

Test only statements

+

test code blocks are allowed to use special statements not available outside +testing blocks:

+
    +
  • +

    step [ncycles] advances the simulation for several cycles. The local variables +will preserve the value, the inputs may change value.

    +
  • +
  • +

    waitfor condition is a syntax sugar to wait for a condition to be true.

    +
  • +
+
+
+
+
test "wait 1 cycle" {
+  let a = 1 + input
+  puts "printed every cycle input={}", a
+  step 1
+  puts "also every cycle a={}",a  // printed on cycle later
+}
+
+
+
+
test "wait 1 cycle" {
+  {
+    let a = 1 + input
+    puts "printed every cycle input={}", a
+  } #> {
+    puts "also every cycle a={}",a  // printed on cycle later
+  }
+}
+
+
+
+
+

The waitfor command is equivalent to a while with a step.

+
+
+
+
total = 3
+
+waitfor a_cond  // wait until a_cond is true
+
+assert total == 3 and a_cond
+
+
+
+
total = 3
+
+while !a_cond {
+  step
+}
+
+assert total == 3 and a_cond
+
+
+
+
+

The main reason for using the step is that the "equivalent" #>[1] is a more +structured construct. The step behaves more like a "yield" in that the next +call or cycle it will continue from there. The #>[1] directive adds a +pipeline structure which means that it can be started each cycle. Calling a +lambda that has called a step and still has not finished should result in a +simulation assertion failure.

+
    +
  • +

    peek allows to read any flop, and lambda input or output

    +
  • +
  • +

    poke is similar to peek but allows to set a value on any flop and lambda + input/output.

    +
  • +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyrope/06-functions/index.html b/pyrope/06-functions/index.html new file mode 100644 index 0000000..f4d9204 --- /dev/null +++ b/pyrope/06-functions/index.html @@ -0,0 +1,1611 @@ + + + + + + + + + + + + + + + + + + + + + + Lambdas - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Lambdas

+

A lambda consists of a sequence of statements that can be bound to a variable. +The variable can be copied and called as needed. Unlike most languages, Pyrope +only supports anonymous lambdas. The reason is that without it lambdas would be +assigned to a namespace. Supporting namespaces would avoid aliases across +libraries, but Pyrope allows different versions of the same library at +different parts of the project. This will effectively create a namespace alias. +The solution is to not have namespaces but relies upon variable scope to decide +which lambda to call.

+
+

Observation

+

Allowing multiple version of the same library/code is supported by Pyrope. +It looks like a strange feature from a software point of view, but it is +common in hardware to have different blocks designed/verified at different +times. The team may not want to open and modernize a block. In hardware, it +is also common to have different blocks to be compiled with different +compiler versions. These are features that Pyrope enables.

+
+

Pyrope divides the lambdas into two categories: functions and procedures. +Functions operate only over combinational logic. They can not have any +synthesis side-effect. This means the function outputs are only a function of +the function inputs. Any external call can only affect debug statements not +the synthesizable code. functions resemble pure functions in normal +programming languages. In pure functions, the function results depend only on +the input parameters. In Pyrope, they are allowed to have side effects on debug +code (non-synthesizable).

+

Non-function lambdas are called procedures or methods. The only difference +between procedures and methods is that a method has self as the first +argument in the output which allows to mutable the called tuple.

+

Lambdas also can be divided into modules and non-modules. A module is a +lambda visible at synthesis call hierarchy. A non-module is an inlined or +flattened lambda.

+

functions are combinational logic, but procedures can have inputs and/or +outputs registerd or just be a generic pure combinational function.

+
+
+
+
let add=fun(a,b)->(res) {
+  res = a+b
+}
+
+fun add(a,b)->(res) {  // Same as let add=fun(a,b)->(res)
+  res = a+b
+}
+
+
+
+
let add=proc(a,b)->(res) {  // nicer to use fun, but proc works
+  res = a+b
+}
+
+proc add(a,b)->(res) {  // same
+  res = a+b
+}
+
+
+
+
let add=proc(reg a, reg b)->(res) {
+  res = a+b
+}
+
+proc add(reg a, reg b)->(res) { // same
+  res = a+b
+}
+
+
+
+
let add=proc(a, b)->(reg res) {
+  res = a+b
+}
+
+proc add(a, b)->(reg res) { // same
+  res = a+b
+}
+
+
+
+
+

Declaration

+

Only anonymous lambdas are supported, this means that there is no global scope +for functions, procedures, or modules. The only way for a file to access a +lambda is to have access to a local variable with a definition or to "import" a +variable from another file. The more familiar fun name or proc name +declaration is also valid, but it is syntax sugar and equivalent to let name = +fun.

+
let a_3   = {   3 }      // just scope, not a lambda. Scope is evaluate now
+let a_fun = fun() { 4 }  // when a_fun is called 4 is returned
+
+let fun3 = fun(){ 5 }    // public lambda that can be imported by other files
+
+let x = a_3()            // compile error, explicit call not posible in scope
+let x = a_fun()          // OK, explicit call needed when no arguments
+
+assert a_3() equals 3
+assert a_fun equals _:fun()
+assert a_fun() equals 4
+assert a_fun() == 4      // calls to eval the function
+
+

The lambda definition has the following fields:

+
[GENERIC] [CAPTURE] [INPUT] [-> OUTPUT] [where COND] |
+
+
    +
  • +

    GENERIC is an optional comma separated list of names between < and > to + use as generic types in the lambda.

    +
  • +
  • +

    CAPTURE has the list of capture variables for the lambda. If no capture is + provided, no local variable can be captured by value which is equivalent to + an empty list ([]), The captures are by value only, no capture by reference + is allowed. Unlike most languages, capture must be comptime. Section + Closures has more details.

    +
  • +
  • +

    INPUT has a list of inputs allowed with optional types. () indicates no + inputs. (...args) allow to accept a variable number of arguments.

    +
  • +
  • +

    OUTPUT has a list of outputs allowed with optional types. () indicates no + outputs.

    +
  • +
  • +

    COND is the condition under which this statement is valid. The COND can + use the inputs, outputs, and self to evaluate. If the outputs are used in + the COND, the lambda must be immutable (fun). This means that the method + is called when the condition could evaluate true depending on its execution, + but being immutable there are no side effects. Section + overload has more details.

    +
  • +
+
var add:fun(...x) = _
+add = fun (...x) { x.0+x.1+x.2 }      // no IO specified
+add = fun (a,b,c){ a+b+c }            // constrain inputs to a,b,c
+add = fun (a,b,c){ a+b+c }            // same
+add = fun (a:u32,b:s3,c){ a+b+c }     // constrain some input types
+add = fun (a,b,c) -> (x:u32){ a+b+c } // constrain result to u32
+add = fun (a,b,c) -> (res){ a+b+c }   // constrain result to be named res
+add = fun (a,b:a,c:a){ a+b+c }        // constrain inputs to have same type
+add = fun <T>(a:T,b:T,c:T){ a+b+c }   // same
+
+x = 2
+var add2:fun2(a) = _
+add2 = fun       (a){   x + a }    // compile error, undefined 'x'
+add2 = fun[     ](a){   x + a }    // compile error, undefined 'x'
+add2 = fun[x    ](a){   x + a }    // explicit capture x
+add2 = fun[foo=x](a){ foo + a }    // capture x but rename to something else
+
+var y = (
+  ,val:u32 = 1
+  ,inc1 = fun (ref self) { self.val = u32(self.val + 1) }
+)
+
+let my_log::[debug] = fun (...inp) {
+  print "loging:"
+  for i in inp {
+    print " {}", i
+  }
+  puts
+}
+
+let f = fun<X>(a:X,b:X){ a+b }   // enforces a and b with same type
+assert f(33:u22,100:u22)
+
+my_log a, false, x+1
+
+

Argument naming

+

Input arguments must be named. E.g: fcall(a=2,b=3) There are the following +exceptions that avoid naming arguments:

+
    +
  • +

    If the type system can distinguish between unnamed arguments (no ambiguity)

    +
  • +
  • +

    If there is an argument/call match. The calling variable name has the same as an argument

    +
  • +
  • +

    If the argument is a single letter, and there is no name match, only position is used

    +
  • +
  • +

    self does not need to be named (first argument position)

    +
  • +
+

There are several rules on how to handle arguments.

+
    +
  • +

    Calls use the Uniform Function Call Syntax (UFCS) but only when self is defined as + first argument. (a,b).f(x,y) == f((a,b),x,y)

    +
  • +
  • +

    Pipe |> concatenated inputs: (a,b) |> f(x,y) == f(x,y,a,b)

    +
  • +
  • +

    Function calls with arguments do not need parenthesis after newline or a + variable assignment: a = f(x,y) is the same as a = f x,y

    +
  • +
  • +

    Functions explicitly declared without arguments, do not need parenthesis in + function call.

    +
  • +
+

Pyrope uses a Uniform Function Call Syntax (UFCS) when the first argument is +self. It resembles Nim or D UFCS but it can be different from the order in +other languages. Notice the different order in UFCS vs pipe, and also that in +the pipe the argument tuple is concatenated.

+
let div  = fun (self,b) { self / b }  // named input tuple
+let div2 = fun (...x){ x.0 / x.1 }    // unnamed input tuple
+
+let noarg = fun () { 33 }         // explicit no args
+
+assert 33 == noarg()
+
+assert noarg == 33 // compile error, `noarg()` needed for calls without arguments
+
+a=div(3  , 4  , 3)       // compile error, div has 2 inputs
+b=div(self=8, b=4)       // OK, 2
+c=div self=8, b=4        // compile error, parenthesis needed for complex call
+d=(self=8).div(b=2)      // OK, 4
+d=(8).div(b=2)           // OK, 4 . self does not need to be named
+d=8.div(2)               // OK, single character inputs no need to be named
+e=(self=8).div b=2       // compile error, parenthesis needed for complex call
+
+h=div2(8, 4, 3)          // OK, 2 (3rd arg is not used)
+i=8.div2(4,3)            // compile error, no self in div2
+
+j=(8,4)  |> div2         // OK, 2, same as div2(8,4)
+j=(8,4)  |> div2()       // OK, 2, same as div2(8,4)
+k=(4)    |> div2(8)      // OK, 2, same as div2(8,4)
+l=(4,33) |> div2(8)      // OK, 2, same as div2(8,4,33)
+m=4      |> div2 8       // compile error, parenthesis needed for complex call
+
+n=div((8,4), 3)          // compile error: (8,4)/3 is undefined
+o=(8,4).div2(1)          // compile error: (8,4)/1 is undefined
+
+

The UFCS allows to have lambdas to call any tuple, but if the called tuple +has a lambda defined with the same name a compile error is generated. Like with +variables, Pyrope does not allow lambda call shadowing. Polymorphism is allowed +but only explicit one as explained later.

+
var tup = (
+  ,let f1 = fun(self) { 1 }
+)
+
+let f1 = fun (self){ 2 }   // compile error, f1 shadows tup.f1
+let f2 = fun (self){ 3 }
+
+assert f1()         != 0  // compile error, missing argument
+assert f1(tup)      != 0  // compile error, f1 shadowing (tup.f1 and f1)
+assert 4.f1()       != 0  // compile error, f1 can be called for tup, so shadow
+assert tup.f1()     != 0  // compile error, f1 is shadowing
+
+let xx = fun[tup] { tup.f1() } // OK, function restricted scope for f1
+assert xx()
+
+assert (4:tup).f1() == 1
+assert 4.f2()       == 3  // UFCS call
+assert tup.f1()     == 1
+
+

The keyword self is used to indicate that the function is accessing a tuple. +self is required to be the first argument. If the procedure modifies the tuple +contents, a ref self must be passed as input.

+
var tup2 = (
+  ,val:u8 = _
+  ,upd = proc(ref self) { self.val::[saturate] += 1 }
+  ,calc = fun(self) { self.val}
+)
+
+

A lambda call uses parenthesis (foo() or foo(1,2)). The parenthesis can be +avoid in tree conditions: (1) arguments are passed in a simple function call +statement; (2) after a pipeline directive; (3) the variable has a getter method +(get).

+
no_arg_fun()     // must use explicit parenthesis/called
+arg_fun 1,2      // parenthesis are optional
+arg_fun(1,2)     // OK too
+(1,2) |> arg_fun // OK too, it is after |>
+
+var intercepted:(
+ ,field:u32
+ ,getter=fun(self) { self.field + 1 }
+ ,setter=fun(ref self,v ) { self.field = v }
+) = 0
+
+cassert intercepted == 1  // will call get method without explicit call
+cassert intercepted.field == 0
+
+

Pass by reference

+

Pyrope is an HDL, and as such, there are not memory allocation issues. This +means that all the arguments are pass by value and the language has value +semantics. In other words, there is not need to worry about ownership or +move/forward semantics like in C++/Rust. All the arguments are always by value. +Nevertheless, sometimes is useful to pass a reference to an array/register so +that it can be updated/accessed on different lambdas.

+

Pyrope arguments are by value, unless the ref keyword is used. Pass by +reference is needed to avoid the copy by value of the function call. Unlike +non-hardware languages, there is no performance overhead in passing by value. +The reason for passing as reference is to allow the lambda to operate over the +passed argument. If modified, it behaves like if it were an implicit output. +This is quite useful for large objects like memories to avoid the copy.

+

The pass by reference behaves like if the calling lambda were inlined in the +caller lambda while still respecting the lambda scope. The ref keyword must +be explicit in the lambda input definition but also in the lambda call. The +lambda outputs can not have a ref modifier.

+

No logical or arithmetic operation can be done with a ref. As a result, it is +only useful for lambda input arguments.

+
let inc1 = fun(ref a) { a += 1 }
+
+let x = 3
+inc1(ref x)       // compile error, `x` is immutable but modified inside inc1
+
+var y = 3
+inc1(ref y)
+assert y == 4
+
+let banner = fun() { puts "hello"  }
+let execute_method = fun(fn) {
+  fn() // prints hello when banner passed as argument
+}
+
+execute_method(banner)     // OK
+
+

Output tuple

+

Pyrope everything is a tuple, even the output or return from a lambda. When a +single element is returned, it can be an unnamed tuple by omiting parenthesis.

+
let ret1 = fun()->(a:int) { // named
+  a = 1
+}
+
+let ret2 = fun()->a:int {   // unnamed
+  a = 2
+}
+
+let ret3 = fun()->(a,b) {   // named
+  a = 3
+  b = 4
+}
+
+let a1 = ret1()
+assert a1.a == 1 // NOT a1 == 1
+
+let a2 = ret2()
+assert a2 == 1   // NOT a2.a == 1
+
+let a3 = ret3()
+assert a3.a == 3 and a2.b == 4
+
+let (x1,x2) = ret3()
+assert x1   == 3 and x2   == 4
+
+

Attributes

+

Variables can have attributes, but procedures can also have them. Procedure +attributes have only one direction from inside the method to outside/caller. +They can be used to signal out of band information about the procedude. Attributes +can only be integer, bool, or string. Depending on the type, they are +initialized to 0, false, or "".

+

The procedure attribute is stored in the variable that keeps the lambda. This +means that it can be checked before or after the lambda call, and that +different variables can point to the same procedure but keep different +attributes.

+
let p1 = proc(a)->(res) {
+  self.[my_zero_found] or= (a == 0)
+
+  res = a + 1
+}
+
+let p2 = p1      // copy
+let p3 = ref p1  // reference
+
+test "testing p1" {
+  assert p1.[my_zero_found] == false
+  assert p2.[my_zero_found] == false
+
+  cassert p1(3) == 4
+  assert p1.[my_zero_found] == false
+
+  cassert p1(0) == 1
+  assert p1.my_zero_found == true
+
+  cassert p1(50) == 51
+  assert p1.[my_zero_found] == true
+  assert p2.[my_zero_found] == false
+  assert p3.[my_zero_found] == true
+}
+
+

Methods

+

Pyrope arguments are by value, unless the ref keyword is used. ref is +needed when a method intends to update the tuple contents. In this case, ref +self argument behaves like a pass by reference in non-hardware languages. This +means that the tuple fields are updated as the method executes, it does not +wait until the method finishes execution. A method without the ref keyword is +a pass by value call. Since all the inputs are immutable by default (let), +any self updates should generate a compile error.

+
let Nested_call = (
+  ,var x = 1
+  ,let outter= proc(ref self) {  self.x = 100 ; self.inner(); self.x = 5 }
+  ,let inner = fun(self) { assert self.x == 100 }
+  ,let faulty = proc(self) { self.x = 55 } // compile error, immutable self
+  ,proc okcall(ref self) { self.x = 55 }   // equivalent to let okcall=proc
+)
+
+

self can also be returned but this behaves like a normal copy by value +variable return.

+
var a_1 = (
+  ,x:u10
+  ,let f1 = fun(ref self,x)->(self) { // BOTH ref self and return self is OK
+    self.x = x
+    self
+  }
+)
+
+a_1.f1(3)
+var a_2 = a_1.f1(4)  // a_2 is updated, not a_1
+assert a_1.x == 3 and a_2.x == 4
+
+// Same behavior as in a function with UFCS
+fun2 = fun (ref self, x) { self.x = x }
+
+a_1.fun2(10)
+var a_3 = a_1.fun2(20)
+assert a_1 == 10 and a_3 == 20
+
+

Since UFCS does not allow shadowing, a wrapper must be built or a compile error is generated.

+
var counter = (
+  ,var val:i32 = 0
+  ,let inc = fun (ref self, v){ self.var += v }
+)
+
+assert counter.val == 0
+counter.inc(3)
+assert counter.val == 3
+
+let inc = fun (ref self, v) { self.var *= v } // NOT INC but multiply
+counter.inc(2)             // compile error, multiple inc options
+assert 44.inc(2) == 8
+
+counter.val = 5
+let mul = inc
+counter.mul(2)             // call the new mul method with UFCS
+assert counter.val == 10
+
+mul(counter, 2)            // also legal
+assert counter.val == 20
+
+

It is possible to add new methods after the type declaration. In some +languages, this is called extension functions.

+
let t1 = (a:u32)
+
+var x:t1 = (a=3)
+
+t1.double = proc(ref self) { self.a *= 2 }  // extension function
+// previous is exactly the same as:
+// t1 = t1 ++ (double = proc(ref self) { self.a *= 2 })
+
+var y:t1 = (a=3)
+x.double             // compile error, double method does not exit
+y.double             // OK
+assert y.a == 6
+
+

Constraining arguments

+

Arguments can constrain the inputs and input types. Unconstrained input types +allow for more freedom and a potentially variable number of arguments generics, but +it can be error-prone.

+
+
+
+
foo = fun (self) { puts "fun.foo" }
+a = (
+  ,foo = fun () {
+     bar = fun() { puts "bar" }
+     puts "mem.foo"
+     return (bar=bar)
+  }
+)
+b = 3
+c = "string"
+
+b.foo         // prints "fun.foo"
+b.foo()       // prints "fun.foo"
+x = a.foo     // prints "mem.foo"
+y = a.foo()   // prints "mem.foo"
+x()           // prints "bar"
+
+a.foo.bar()   // prints "mem.foo" and then "bar"
+a.foo().bar() // prints "mem.foo" and then "bar"
+a.foo().bar   // prints "mem.foo" and then "bar"
+
+c.foo         // prints "fun.foo"
+
+
+
+
foo = fun (self:int) { puts "fun.foo" }
+a = (
+  ,foo = fun () {
+     bar = fun() { puts "bar" }
+     puts "mem.foo"
+     return (bar=bar)
+  }
+)
+b = 3
+c = "string"
+
+b.foo         // prints "fun.foo"
+b.foo()       // prints "fun.foo"
+x = a.foo     // prints "mem.foo"
+y = a.foo()   // prints "mem.foo"
+x()           // prints "bar"
+
+a.foo.bar()   // prints "mem.foo" and then "bar"
+a.foo().bar() // prints "mem.foo" and then "bar"
+a.foo().bar   // prints "mem.foo" and then "bar"
+
+c.foo         // compile error, undefined 'foo' field/call
+
+
+
+
+

The where statement also allows to constrain arguments. This is a sample of +fibonnaci implementation with and without where clauses. Section +overload has more details on the method +overloading.

+
let fib1 = fun(n) where n==0 {0}
+        ++ fun(n) where n==1 {1}
+        ++ fun(n)            { fib1(n-1) + fib1(n-2) }
+
+assert fib1(10) == 55
+
+let fib2 = fun(n) {
+  return match n {
+    == 0 {0}
+    == 1 {1}
+    else {fib2(n-1) + fib2(n-2)}
+  }
+}
+
+assert fib2(10) == 55
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyrope/06b-instantiation/index.html b/pyrope/06b-instantiation/index.html new file mode 100644 index 0000000..3cd79a5 --- /dev/null +++ b/pyrope/06b-instantiation/index.html @@ -0,0 +1,1682 @@ + + + + + + + + + + + + + + + + + + + + + + Instantiation - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Instantiation

+

Instantiation is the process of translating from Pyrope to an equivalent set +of gates. The gates could be simplified or further optimized by later compiler +passes or optimization steps. This section provides an overview of how the +major Pyrope syntax constructs translate to gates.

+

Conditionals

+

Conditional statements like if/else and match translate to multiplexers +(muxes).

+

A trivial if/else with all the options covered is a simple mux.

+
var res:s4 = _
+if cond {
+  res = a
+}else{
+  res = b
+}
+
+// RTL equivalent (bus of 4 bits in a,b,res2)
+var res2:s4 = __mux(cond,b,a)
+
+lec res, res2
+
+

An expression if/else is also a mux.

+
var res = if cond { a }else{ b }
+
+// RTL equivalent
+var res2 = __mux(cond,b,a)
+
+lec res, res2
+
+

The when/unless is also a mux.

+
var res = a
+res = b unless cond
+
+// RTL equivalent
+var res2 = __mux(cond,b,a)
+
+lec res, res2
+
+

Chaining if/elif creates a chain of muxes. If not all the inputs are +covered, the value from before the if is used. If the variable did not exist, +a compile error is generated.

+
var res = a
+if cond1 {
+  res = b
+}elif cond2 {
+  res = c
+}else{
+  assert true // no res
+}
+
+// RTL equivalent
+var tmp = __mux(cond2, a, c)
+var res2= __mux(cond1, tmp, b)
+
+lec res, res2
+
+

unique if/elif is similar but avoids mux nesting using a one-hot encoded +mux.

+
var res = a
+unique if cond1 {
+  res = b
+}elif cond2 {
+  res = c
+} // no res in else
+
+// RTL equivalent
+var sel = (!cond1 and !cond2, cond1, cond2)@[..]  // one hot encode
+var res2= __hotmux(sel, a, b, c)
+optimize !(cond1 and cond2)                       // one hot check
+
+lec res, res2
+
+

The match is similar to the unique if but also checks that one of the +options is enabled, which allows further optimizations. From a Verilog designer +point of view, the match is a "full parallel" and the unique if is a +"parallel". Both are checked at verification and optimized at synthesis.

+
var res = a
+match x {
+  == c1 { res = b }
+  == c2 { res = c }
+  == c3 { res = d }
+}
+
+// RTL equivalent
+let cond1 = x == c1
+let cond2 = x == c2
+let cond3 = x == c3
+var sel = (cond1, cond2, !cond1 and !cond2)@[..]  // one hot encode (no cond3)
+var res2= __hotmux(sel, b, c, d)
+optimize ( cond1 and !cond2 and !cond3)
+      or (!cond1 and  cond2 and !cond3)
+      or (!cond1 and !cond2 and  cond3)    // one hot check (no else allowed)
+
+lec res, res2
+
+

Optional expression

+

Valid or optionals are computed for each assignment and passed to every lambda +call. Each variable has an associated valid bit, but it is removed if never +read, and it is always true unless the variables are assigned in conditionals +or non-short-circuit (and_then/or_else) expressions.

+
+
+
+
var lhs = v1 or_else v2
+
+// RTL equivalent
+let lhs2  = __or(v1, v2)
+let lhs2_v = __or(__and(v1?, v1), __and(v2?, v2))
+
+lec lhs , lhs2
+lec lhs?, lhs2_v
+
+
+
+
var lhs = v1 + v2
+
+// RTL equivalent
+let lhs2   = __sum(A=(v1, v2))
+let lhs2_v = __and(v1?, v2?)
+
+lec lhs , lhs2
+lec lhs?, lhs2_v
+
+
+
+
lhs = v0
+if cond1 {
+  lhs = v1
+}elif cond2 {
+  lhs = v2
+} // no else
+
+// RTL equivalent
+let tmp = __mux(cond2, v0, v2)
+let lhs2= __mux(cond1, tmp, v1)
+
+let tmp_v = __mux(cond2, v0?, v2?)
+let lhs2_v= __mux(cond1, tmp_v, v1?)
+
+lec lhs , lhs2
+lec lhs?, lhs2_v
+
+
+
+
let f = fun(a,b) { if a == 0 { 3 }else{ b } }
+
+var lhs = c
+if cond {
+   lhs = f(a,b)
+}
+
+// RTL equivalent
+let a_cond = __not(__ror(a))             // a == 0
+let tmp    = __mux(a_cond, b, 3)         // if a_cond { 3 }else{ b }
+var lhs2   = c
+lhs2       = __mux(cond, x, tmp)
+
+let tmp_v  = __mux(a_cond, a?, __and(a?,b?)) // a? or (a==0 and b?)
+
+let lhs2_v = __mux(cond, c?, tmp_v)
+
+lec lhs , lhs2
+lec lhs?, lhs2_v
+
+
+
+
+

Lambda calls

+

Lambda calls are either inlined or become a specific instance (module). When +the instance is located in a conditional path, the instance is moved to the +main scope toggling the inputs valid attribute ::[valid=false]. The instance +has the assigned variable name. If the instance is a var, the variable name +can be the SSA name.

+
+
+
+
let sub = proc(a,b)->(x) {
+  let tmp = sum(a,b)       // instance tmp,sum
+
+  x = sum(tmp,3)           // instance x,sum
+}
+
+let top = proc(a,b,c)->(x) {
+
+ x = sub(a,b).x
+ if c {
+   let tmp=3
+   x += sub(b,tmp).x
+ }
+}
+
+
+
+
let sub = proc(a,b)->(x) {
+  let tmp = sum(a,b)       // instance tmp
+
+  x = sum(tmp,3)           // instance x
+}
+
+let top = proc(a,b,c)->(x) {
+
+ x = sub(a,b).x           // instance x
+
+ let x_0 = _
+ let sub_arg_0 = _
+ let sub_arg_1 = _
+ if c {
+   let tmp=3
+   sub_arg_0 = b
+   sub_arg_1 = tmp
+   x += x_0.[defer]       // use defer (instance after conditional code)
+ }
+ x_0 = sub(sub_arg_0,sub_arg_1).x   // instance x_0 (SSA)
+}
+
+
+
+
+

Optional lambdas

+

HDLs use typical software constructs that look like function calls to represent +instances in design. As previously +explained, hardware languages are +about instantiation, and software languages are about instruction execution. A +lambda called unconditionally is likely to result in module unless the +compiler decides to be small and it is inlined.

+

In Pyrope, the semantics are that when a lambda is conditionally called, it +should behave like if the lambda were inlined in the conditional place. Since +functions have no side effects, it is also equivalent to call the lambda before +the conditional path, and assign the return value inside the conditional path +only. Special care must be handled for the puts which is allowed in +functions. The puts is not called if the function is conditionally called and +the condition is false.

+
+
+
+
let case_1_counter = proc(runtime)->(res) {
+
+  let r = (
+    ,reg total:u16 = _          // r is reg, everything is reg
+    ,increase = fun(a) {
+      puts "hello"
+
+      let res = self.total
+      self.total::[wrap] = res+a
+
+      res
+    }
+  )
+
+  if runtime == 2 {
+    res = r.increase(3)
+  }elif runtime == 4 {
+    res = r.increase(9)
+  }
+}
+
+
+
+
let case_1_counter = proc(runtime)->(res) {
+
+  let r = (
+    ,reg total:u16 = _
+    ,increase = fun(a) {
+      puts "hello"
+
+      let res = self.total
+      self.total::[wrap] = res+a
+
+      res
+    }
+  )
+
+  if runtime == 2 {
+    puts "hello"
+
+    let res = r.total
+    r.total::[wrap] = res+3
+    res = res
+  }elif runtime == 4 {
+    puts "hello"
+
+    let res = r.total
+    r.total::[wrap]= res+9
+    res = res
+  }
+}
+
+
+
+
+

The result of conditionally calling procedures is that most of the code may be +inlined. This can change the expected equivalent Verilog generated modules.

+

Calling a procedure with the inputs set invalid has a different behavior. For +once C++ calls will still happen, and updates to registers with not valid data +is allowed to reset the valid bit.

+

Expressions

+

Pyrope expressions are guaranteed to have the same result independent of the +order of evaluation. Only and_then, or_else or complex constructs like +if/else, match, for have evaluation order.

+

Setup vs reset vs execution

+

In a normal programming language, the Von Neumann PC specifies clear semantics +on when the code is executed. The language could also have a macro or template +system executed at compile-time, the rest of the code is called explicitly when +the function is called. As mentioned, a key difference is that HDLs focus on +instantiation of gates/logic/registers, not instruction execution. HDLs tend to +have 3 code sections:

+
    +
  • +

    Setup: This is code executed to set up the hierarchies, parameters, read + configuration setups... It is usually executed at compile time. In Verilog, + these are the preprocessor directives and the generate statements. In + CHISEL, the scala is the setup code.

    +
  • +
  • +

    Reset: Hardware starts in an undefined/inconsistent state. Usually, a reset + signal is enabled several cycles and the associated reset logic configures + the system to a given state.

    +
  • +
  • +

    Execution: This is the code executed every cycle after reset. The reset + logic activation can happen at any time, and parts of the machine may be in + reset mode while others are not.

    +
  • +
+

In addition, some languages like Verilog have "initialization" code that is +executed before reset. This is usually done for debugging, and it is not +synthesizable. Although not always synthesizable, we consider this setup code.

+

Pyrope aims to have the setup, reset, and execution specified.

+

Setup code

+

Compiling a Pyrope program requires specifying a "top file" file and a +"top variable" in the top file. The top file is executed only once. The top +file may "import" other files. Each of the imports is executed only once too. +The imported files are executed before the current file is executed. This is +applied recursively but no loops are supported in import dependence chains.

+

The "setup" code is the statements executed once for each imported file. Those +statements can not be "imported" by other files. Only the resulting public +variables can be imported.

+

During setup, each file can have a list of public variables. Those are +variables that can be used by importing modules. The "top variable" is +selected for simulation/synthesis.

+

It is important to point that comptime may be used during setup but also in +non-setup code. comptime just means that the associated variables are known +at compile time. This is quite useful during reset and execution too or just to +guaranteed that a computation is solved at compile time.

+

Reset code

+

The reset logic is associated with registers and memories. The assignment to +register declaration is the reset code. It will be called for as many cycles +are the reset is held active. The reg assignment can be a constant or a call +to conf that can provide a runtime file with the values to start the +simulation/synthesis.

+
reg r:u16 = 3 // reset sets r to 3
+r = 2             // non-reset assignment
+
+reg array:[]u16 = (1,2,3,4)  // reset values
+
+reg r2:u128 = conf.get("my_data.for.r2")
+
+reg array:[] = conf.get("some.conf.hex.dump")
+
+

The assignment during declaration to a register is always the reset value. If +the assignment is a method, the method is called every cycle during reset.

+
reg array:[1024]tag:[clock_pin=my_clock] = proc(ref self) {
+  reg reset_iter:u10:[reset_pin=false] = 0sb? // no reset flop
+
+  self[reset_iter].state = I
+
+  reset_iter::[wrap] = reset_iter + 1
+}
+
+

Since the reset can be high many cycles, it may be practical/necessary to have +a reset inside the reset procedure. To guarantee determinism, any register +inside the reset procedure can be either asynchrnous reset or a register +without reset signal.

+
reg my_flop:[8]u32 = proc(ref self) {
+  reg reset_counter:u3:[async=true] = _ // async is only posedge reset
+
+  self[reset_counter] = reset_counter
+  reset_counter::[wrap] += 1
+}
+
+

A related functionality and constrains happen when a tuple have some register +fields and some non-register fields. The same reset procedure is called every +cycle Similarly a tuple can have a reset when assigned to a register.

+
+
+
+
let Mix_tup = (
+  ,reg flag:bool = false
+  ,state: u2
+)
+
+var x:Mux_tup = (false,1)  // 0 used at reset, 1 used every cycle
+
+assert x.flag implies x.state == 2
+
+x.state = 0
+if x.flag {
+  x.state = 2
+}
+x.flag = true
+
+
+
+
let Mix_tup = (
+  ,reg flag:bool = false
+  ,state:u2
+)
+
+var x:Mux_tup = proc(ref self) {
+  self.flag  = proc(ref self) { self = false }  // reset code
+  self.state = 2                                // every cycle code
+}
+
+assert x.flag implies x.state == 2
+
+x.state = 0
+if x.flag {
+  x.state = 2
+}
+
+
+
+
+

A sample of asynchronous reset with different reset and clock signal

+
reg my_asyn_other_reg:u8:[
+  ,async = true
+  ,clock = ref clk2    // ref to connect, not read clk2 value
+  ,reset = ref reset33 // ref to connect, not read current reset33 value
+] = 33 // initialized to 33 at reset
+
+
+if my_async_other_reg == 33 {
+  my_async_other_reg = 4
+}
+
+assert my_async_other_reg in (4,33)
+
+

retime

+

Values stored in registers (flop or latches) and memories (synchronous or +asynchronous) can not be used in compiler optimization passes. The reason is that +a scan chain is allowed to replace the values.

+

The retime attribute indicates that the register/memory can be replicated and +used for optimization. Copy values can propagate through retime +register/memories.

+

A register or memory without explicit :[retime] attribute can only be optimized away +if there is no read AND no write to the register. Even just having writes the +register is preserved because it can be used to read values with the +scan-chain.

+

Execution code

+

HDLs specify a tree-like structure of modules. The top module could instantiate +several sub-modules. Pyrope Setup phase is to create such hierarchical +structures. The call order follows a program order from the top point every +cycle, even when reset is set.

+

The following Verilog hierarchy can be encoded with the equivalent Pyrope:

+
+
+
+
module inner(input z, input y, output a, output h);
+  assign a =   y & z;
+  assign h = !(y & z);
+
+endmodule
+
+module top2(input a, input b, output c, output d);
+
+inner foo(.y(a),.z(b),.a(c),.h(d));
+
+endmodule
+
+
+
+
let inner = fun(z,y)->(a,h) {
+  a =   y & z
+  h = !(y & z)
+}
+
+let top2 = fun(a,b)->(c,d) {
+  let x= inner(y=a,z=b)
+  c = x.a
+  d = x.h
+}
+
+
+
+
let Inner_t = (
+  ,setter = proc(ref self, z,y) {
+    self.a =   y & z
+    self.h = !(y & z)
+  }
+)
+
+let Top2_t = (
+  ,setter = proc(ref self,a,b) {
+    let foo:Inner_t = (y=a,z=b)
+
+    self.c = foo.a
+    self.d = foo.h
+  }
+)
+
+let top:Top2_t = (a,b)
+
+
+
+
let Inner_t = (
+  ,setter = proc(ref self, z,y) {
+    self.a =   y & z
+    self.h = !(y & z)
+  }
+)
+
+let Top2_t = (
+  ,foo:Inner_t = _
+  ,setter = proc(ref self,a,b) {
+    (self.c, self.d) = self.foo(y=a,z=b)
+  }
+)
+
+let top:Top2_t = (a,b)
+
+
+
+
+

The top-level module top2 must be a module, but as the alternative Pyrope +syntax shows, the inner modules may be in tuples or direct module calls. The +are advantages to each approach but the code quality should be the same.

+

Registers

+
reg a:u4 = 3
+a::[saturate] = a+1
+
+reg b = 4
+if cond {
+  reg c = _           // weird as reg, but legal syntax
+  c = b + 1
+  b = 5
+}
+
+// RTL equivalent
+a_qpin = __flop(reset=ref reset, clk=ref clk, initial=3, din=a.[defer])
+tmp    = __sum(A=(a_qpin, 1))
+a      = __mux(tmp[4], tmp@[0..=3], 0xF)    // saturate, not wrap
+
+b_qpin = __flop(reset=ref reset, clk=ref clk, initial=4, din=b.[defer])
+b      = __mux(cond, b_qpin, 5)
+
+c_cond_qpin = __flop(reset=ref reset, clk=ref clk, initial=0, din=c_cond.[defer])
+c_cond      = __sum(A=(b, 1))
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyrope/06c-pipelining/index.html b/pyrope/06c-pipelining/index.html new file mode 100644 index 0000000..a1a6ecd --- /dev/null +++ b/pyrope/06c-pipelining/index.html @@ -0,0 +1,1558 @@ + + + + + + + + + + + + + + + + + + + + + + Pipelining - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Pipelining

+

Registers

+

Together with memories, flip-flops or latches are the basic constructs used by +hardware to store information and to build pipeline stages. Pyrope's goal is to +be a zero-cost overhead, and as such it allows to handle flops directly.

+

To create an individual flop, a direct RTL instantiation of a __flop can be +used. Flops and latches have several pins din, q, clock, enable and +configuration options posclk, initial, and async.

+

A more programmer-friendly is to use to declare a register. The compiler does +not provide guarantees that the register will not be split into multiple +registers.

+

The explicit connection likely requires constructs like .[defer] to connect +the flop q pin.

+
+
+
+
var counter_next:u8:[wrap] = _
+
+let counter_q = __flop(din=counter_next.[defer] // defer to get last update
+                   ,reset_pin=my_rst, clock_pin=my_clk
+                   ,enable=my_enable            // enable control
+                   ,posclk=true
+                   ,initial=3                   // reset value
+                   ,async=false)
+
+counter_next = counter_q + 1
+
+
+
+
reg counter:u8:[reset_pin=my_rst, clock_pin=my_clk, posclk=true]= 3
+assert counter == counter#[0]  // counter still has the q value
+
+if my_enable {
+  counter::[wrap] = counter + 1
+}
+
+
+
+
+

Flops have din and a q pin. At the beginning of the cycle both din and +q have the same value, but as the din is updated with "next cycle" q +value their contents may be different. Different HDLs have different syntax to +distinguish between din and q pin. In Verilog, it is common to have a +coding style guideline that gives a different name to the din variables than to +the q variables (E.g: counter_q vs counter_next). The structural flop style +is a legal Pyrope code using these type of names.

+

In a more friendly Pyrope style, a register like counter starts with the q +pin each cycle. The last value written to counter connects to the din. It +is always possible to access the q pin/value directly with pipeline +directives something#[0].

+

If the register is accessed with the -1 cycle (#something#[-1]), the flop will +insert an additional pipeline to access 1 cycle before flop contents.

+

It is also possible to use positive values (variable#[3]) which means the +value in the future 3 cycles, but this is only allowed in debug statements like +assert or puts.

+

Latches are possible but with the direct RTL instantiation. Latches have +a din and enable pin like a flop, but just one option posclk.

+
var my_latch_q = __latch(din=my_din, enable=my_enable, posclk=true)
+
+

Pipestage

+

Pyrope has a pipestage statement (#>identifier[fsm_configuration]) that +helps to create simple pipeline stages. The identifier[fsm_configuration] is +optional and the default meaning is a fully pipelined 1 pipeline stage depth. +It is the same as saying _[lat=1]. The identifier can be accessed as an +attribute to count the pipestage utilization.

+

The fsm configuration can have lat (number of pipeline stages or latency) or +num (number of units). The number of units is only needed when the code is +not fully pipelined in combination with loop constructs like while, for, +and loop.

+

The num sets the number of units. The hardware will not back pressure, but an +assertion will fail during simulation if the number of units is overflowed. +num only makes sense when the latency (lat) is more than 1.

+
// variables/register before
+
+{
+  // stage 0 scope
+} #> {               // no identifier, 1 stage by default
+  // stage 1 scope
+} #>foo[2] {            // no identifier, 2 stages
+  // stage 2-3 scope
+} #>bar[1] {     // 'free_stage' identifier, 1 stages
+  // stage 4 scope
+} #> {
+  // stage 5 scope
+}
+
+// variables/register after pipestage
+
+

The semantics of pipestage are as follows:

+
    +
  • +

    Explicitly declared registers (reg foo) are not affected by pipestage

    +
  • +
  • +

    Variables declared before are "pipelined" inside each of the pipestage scopes.

    +
  • +
  • +

    Variables declared in a stage are pipelined to all the following stages + unless the variable is private (var priv_example::[private]=3)

    +
  • +
  • +

    The pipelined variables are not visible in the scope after the pipestage + sequence.

    +
  • +
  • +

    The original non-pipelined variable can be accessed with v#[0].

    +
  • +
+

To illustrate the semantics, imagine a module where the input i is a +monotonically increasing sequence (0,1,2,3,4,5,6,7....).

+
assert i==0 or (i#[-1] + 1 == i)
+
+let i_let = i
+
+var i_var0 = i
+var i_var1 = i
+
+reg i_reg0 = i        // initialization only
+reg i_reg1:i_reg0 = _
+
+i_reg1 = i                // every cycle
+
+{
+  assert i == i#[0]       // i#[0] is unflop input (or first defined) value
+  assert i == i_let
+  assert i == i_var0
+  assert i == i_var1
+
+  assert 0 == i_reg0
+  assert i == i_reg1
+
+  let _local_var = 3
+
+  let pub_var = 100 + i
+
+} #> {
+  assert _local_var!=0      // compile error, _local_var is not in scope
+  assert pub_var == 100 + i // pipelined pub_var
+
+  // both inputs and variables flop, so asserts hold
+  assert i == i_let
+  assert i == i_var0
+  assert i == i_var1
+
+  assert 0 == i_reg0        // i_reg0 never changes, so 0 is fine
+  assert i#[-1] == i_reg1   // last i-reg, not current
+
+  assert i == 0 or (i == i#[0]+1)  // i#[0] is the unflop original
+}
+
+assert pub_var != 0 // compile error, pub_var is not in scope
+
+

The pipestage accept the clock and posclk attributes from register to allow +the selection of different clock signal. Notice that it does not allow reset +or latch or async because it does not require reset logic.

+

Pipelining is one of the challenges of designing hardware. Even a simple pipestage +code can result in incorrect hardware. The reason is that if two pipestage blocks +generate an output simultaneously, there is no way to generate both outputs. The +result is a compile or simulation error.

+
let bad_code = proc(my_clk, inp)->(o1,o2) {
+
+  {
+    o1 = 1
+    o2 = inp + 1  // o2? iff bad_code called this cycle and inp? is valid
+  } #>my_pipe[lat=1,clock=my_clk] {
+    o1 = 2        // compile error, o1 driven simultaneous from multiple stages
+    o2 = inp + 2  // may be OK if inp is not valid every cycle
+  }
+
+}
+
+

Pipestage with loops

+

The pipestage directive (#>identifier[cycles]{ }) automatically creates a fully +pipeline design with cycles pipeline depth. cycles must be bigger or equal +than 1 and known at compile time. When cycles is not specified a 1 value is +assumed.

+

Pipestage can be applied to while and loop statements, not to for +statements because for must be fully unrolled at compile time.

+

When applied to loops, the loop becames a state machine with cycles the +maximum number of simultaneous loop iterations. It effectively means that +number of units or state machines that can perform the loop simultaneously. +The identifier becomes a procedure attribute.

+
+
+
+
let mul3=proc(a,b)->res {
+  let tmp = a*b
+  #>full_case[lat=3,num=3] { // Same as full_case[lat=3]
+    res = tmp
+  }
+}
+
+
+
+
let mul_slow=proc(a,b)->res {
+
+  let result  = 0
+  let rest    = a
+
+  while rest >= b #>_[lat=1,num=4] {  // lat=1 is latency per iteration
+    rest = rest - b
+    result += 1
+  }
+
+  res = result
+}
+
+
+
+
let mul1=proc(a,b)->(reg res) {
+  res = a*b
+}
+
+
+
+
let mul1=proc(a,b)->(res) {
+  #>full_case_again[lat=1] { 
+    res = a*b
+  }
+}
+
+
+
+
let mul0=proc(a,b)->(res) {
+  res = a*b
+}
+
+
+
+
+

To understand the fully pipelined behavior, the following shows the pipestage +against the more direct implementation with registers.

+
if cond {
+  var p1 = inp1
+  var out = _
+
+  {
+    var _l1 = inp1 + 1
+
+    var p2 = inp1 + 2
+  } #> {
+    out = p1 + p2
+  }
+
+  res = out
+}
+
+// Non pipestage equivalent
+if cond {
+  var p1 = inp1
+  var out = _
+
+  {
+    reg p1r = _
+    reg p2r = _
+
+    var l1::[private] = inp1 + 1  // private
+    var p2 = inp1 + 2             // public
+
+    out = p1r + p2r               // registered values
+
+    p1r = p1
+    p2r = p2
+  }
+
+  res = out
+}
+
+

Retiming

+

The registers manually inserted with the reg directive are preserved +and annotated so that synthesis retiming can not change them. This means +that by default register can not be duplicated or logic can move around.

+

A register can be marked with the retime flag, in which case the synthesis +tools are allowed to perform the following optimizations:

+
    +
  • +

    Retime or move logic across which effectively changes the meaning of the register.

    +
  • +
  • +

    Duplication is allowed when frequency improvements grant it.

    +
  • +
  • +

    Elimination. If there are no reads or no writes, the register can be remove + and replaced with a constant (no writes) or just removed (no reads).

    +
  • +
  • +

    Copy propagation is allowed across registers. This is not possible without + retime because the scan chain could reconfigure the flop.

    +
  • +
+

The registers automatically inserted with the pipestage command are marked +with retime true. Additionally, retime can be set in any register:

+
reg my_reg::[retime=true,clock=my_clk] = 0
+
+

Multiply-Add example

+

To illustrate the confusion/complication the following example illustrates a +multiplier that takes 3 cycles and an adder that takes 1 cycle to complete, and +the conceptual problems of integrating them:

+
+
+
+
let block = proc(in1,in2)->(out) {
+  {
+    let tmp = in1 * in2
+  } #>some_id[lat=3] {
+    out = tmp + in1#[0]
+  }
+}
+
+
+
+
add1 = proc(a,b) {     // 1 cycle add
+  reg r  = _
+  let rr = r           // get flop value
+  r = a+b
+  return rr
+}
+let mul3 = proc(a,b) { // 3 cycle multiply
+  reg reg1 = _
+  reg reg2 = _
+  reg reg3 = _
+  reg3 = reg2
+  reg2 = reg1
+  reg1 = a * b
+  return reg3
+}
+
+let block = proc(in1,in2)->(out) {
+  let x =#[..] mul3(in1, in2)
+  out   =#[..] add1(x,in3)
+}
+
+
+
+
+

In general, # is used when dealing with registers. The previous example use +procedures (proc ... {...}) instead of functions (fun ... {...}) because functions +only have combinational logic. When the procedures are called, the assigned +variable needs the =#[..]. This is to explicitly indicate to Pyrope that the +function called (mul3, add1) can have pipeline outputs. This helps the tool +but more importantly the programmer because it helps to check assumptions about +the function connections. The typical assignment = only connects +combinational logic.

+

The previous code connects two inputs (in1/in2) to a multiplier, and then +connects the result of the multiplier to an adder. The inputs are also +passed to the adder. This results in the following functionality:

+
graph LR + in1[in1] --a--> m0(mul3 cycle 0) + in2[in2] --b--> m0 + + m0 --> m1(mul3 cycle 1) + m1 --> m2(mul3 cycle 2) + + in1--a--> a0[add1 cycle 1] + m2 --b--> a0 + a0 --> out[out] +
+

The issue in most HDLs is that the connection is unaware of the pipelining, and +it is left up to the programmer to understand and check the potential pipeline +stages inside add1 and mul3. This lack of pipelining awareness in the +language syntax is common in most HDLs.

+

In Pyrope, the =#[..] must be used when there is any path that starts from the +inputs of the function passes through a pipeline stage to generate the +assignment. If all the paths have exactly 1 flop in between, it is a 1 stage +pipeline, if some paths have 2 flops and others 3, it is a 2 or 3 pipeline +stages. Sometimes, there are loops, and the tool has 1 to infinite pipeline +stages.

+

The default pipeline assignment =#[..] just checks that it is possible to have +pipeline stages between the module/function inputs and the assignment value. To +restrict the check, it accepts a range. E.g: =#[3] means that there are +exactly 3 flops or cycles between inputs and the assignment. =#[0..<4] means +that there are between 0 and 3 cycles, and open range could be used when there +are loops (E.g: =#[2..]).

+
let x = mul3(in1, in2)      // compile error: 'mul3' is pipelined
+let x =#[..] mul3(in1, in2) // OK
+out  =#[..] add1(x,in3)     // OK (in3 has 0 cycles, x has 3 cycles)
+out  =#[1] add1(x,in3)      // compile error: 'x' is pipelined with '3' cycles
+out  =#[3] add1(x,in3)      // compile error: 'in3' is pipelined with '1' cycle
+out  =#[1..<4] add1(x,in3)  // OK
+
+

The designer likely wanted to implement a multiply-add. As such, +the input to the adder should be from the same cycle as the multiplied started +to operate. Otherwise, values across cycles are mixed.

+
graph LR + in1[in1] --a--> m0(mul3 cycle 0) + in2[in2] --b--> m0 + + m0 --> m1(mul3 cycle 1) + m1 --> m2(mul3 cycle 2) + + in1 --> in1_0(flop cycle 0) + in1_0--> in1_1(flop cycle 1) + in1_1--> in1_2(flop cycle 2) + in1_2--a--> a0[add1 cycle 0] + m2 --b--> a0 + a0 --> out[out] +
+

It is possible to balance the pipeline stages explicitly, the issue is that it +is error-prone because it requires knowing exactly the number of cycles for +mul3.

+
+
+
+
{
+  let tmp = in1 * in2
+} #>fully_pipe[lat=3] {
+  out = tmp + in1
+}
+
+
+
+
x =#[..] mul3(in1, in2)
+y = in1#[-3]
+out =#[..] add1(a=x,b=y)    // connect in1 from -3 cycles
+
+
+
+
+
+

Observation

+

The explicit v#[-cycles] inserts registers and access the result cycles +before. This same syntax can be used with assertions similar to the Verilog +$past(v, cycles).

+
+

ALU example

+

Pipestages allow to build fully pipelined structures but also non-pipelined +state machines when applied to loops. This creates potential contention that the +designer must decide how to manage. This contention can be propagated outside +the procedure with attributes.

+

The ALU example illustrates the contention by creating an ALU with 3 different +pipelines (add,mul,div) that have different latencies and contention.

+
let quick_log2 = fun(a) {
+
+  cassert a>=1
+
+  var i = 1
+  var v = 0
+  while i < a.[bits] {
+    v |= i
+    i *= 2
+  }
+
+  return v
+}
+
+let div=proc(a,b,id)->(res,id) {
+  loop #>free_div_units[4] {
+    return (a >> quick_log2(b), id) when b@+[..] == 1
+    #>my_fsm[lat=5,num=1] {
+      res = (a/b, id)
+    }
+  }
+}
+
+let mul=proc(a,b,id)->(res, id) {
+  #>pending_counter[lat=3,num=2] {
+    res = a*b
+    id  = id
+  }
+}
+
+let add=proc(a,b,id)->(res,id) {
+  #>add_counter[lat=1] {         // Fully pipeline, num not specified
+    res = a+b
+    id  = id
+  }
+}
+
+let alu = proc(a,b,op, id)->(res,id) {
+
+  self.[total_free_units] = 1 
+     + mul.[pending_counter] 
+     + div.[free_div_units]
+     + add.[add_counter]
+
+  self.[div_units] = div.[free_div_units]
+
+  match op {
+    == OP.div {
+      assert div.[free_div_units]>0
+      (res,id) = div(a,b,id)
+    }
+    == OP.mul { (res,id) = mul(a,b,id) }
+    == OP.add { (res,id) = add(a,b,id) }
+  }
+}
+
+test "alu too many div" {
+
+ cassert alu.[total_free_units] == (1+3+4)
+
+ let r1 = alu(13,3, OP.div, 1)
+ assert alu.div_units==3
+ let r2 = alu(13,3, OP.div, 2)
+ assert alu.div_units==2
+ let r3 = alu(13,3, OP.div, 3)
+ assert alu.div_units==1
+ let r4 = alu(13,3, OP.div, 4)
+ assert alu.div_units==0
+
+ assert !r1? and !r2? and !r3? and !r4? // still invalid
+
+ let r5 = alu(13,4, OP.mul,5)
+ cassert mul.[pending_counter] == 2
+}
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyrope/07-typesystem/index.html b/pyrope/07-typesystem/index.html new file mode 100644 index 0000000..1d42901 --- /dev/null +++ b/pyrope/07-typesystem/index.html @@ -0,0 +1,2352 @@ + + + + + + + + + + + + + + + + + + + + + + Type system - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Type system

+

Type system assign types for each variable (type synthesis) and check that each +variable use/expression respects the allowed types (type check). Additionally, a +language can also use the type synthesis results to implement polymorphism.

+

Most HDLs do not have modern type systems, but they could benefit like in other +software domains. Unlike software, in the hardware, we do not need to have many integer +sizes because hardware can implement any size. This simplifies the type system +allowing unlimited precision integers but it needs a bitwidth inference mechanism.

+

Additionally, in hardware, it makes sense to have different implementations that +adjust for performance/constraints like size, area, FPGA/ASIC. Type systems +could help in these areas.

+

Types vs cassert

+

To understand the type check, it is useful to see an equivalent casser +translation. The type system has two components: type synthesis and type check. +The type check can be understood as a cassert.

+

After type synthesis, each variable has an associated type. Pyrope checks that +for each each assignment, the left-hand side (LHS) has a compatible type with +the right-hand side (RHS) of the expression. Additional type checks happen when +variables have a type check explicitly set (variable:type) in the rhs expression.

+

Although the type system is not implemented with asserts, it is an equivalent +way to understand the type system "check" behavior. Although it is possible to +declare just the cassert for type checks, the recommendation is to +use the explicit Pyrope type syntax because it is more readable and easier to +optimize.

+
+
+
+
var b = "hello"
+
+var a:u32 = 0
+
+a += 1
+
+a = b                       // incorrect
+
+
+var dest:u32 = 0
+
+dest = foo:u16 + v:u8
+
+
+
+
var b = "hello"
+
+var a:u32 = 0
+
+a += 1
+cassert a does u32
+a = b                       // incorrect
+cassert b does u32  // fails
+
+var dest:u32 = 0
+cassert (dest does u32) and (foo does u16) and (v does u8)
+dest = foo:u16 + v:u8
+
+
+
+
+

Building types

+

Each variable can be a basic type. In addition, each variable can have a set of +constraints from the type system. Pyrope type system constructs to handle types:

+
    +
  • +

    var and let allows declaring types.

    +
  • +
  • +

    a does b: Checks 'a' is a superset or equal to 'b'. In the future, the + Unicode character "\u02287" could be used as an alternative to does (a +⊇ b).

    +
  • +
  • +

    a:b is equivalent to a does b for type check, but it is also used by type + synthesis when used in the left-hand-side of assignments.

    +
  • +
  • +

    a equals b: Checks that a does b and b does a. Effectively checking + that they have the same type. Notice that this is not like checking for + logical equivalence, just type equivalence.

    +
  • +
+
let t1 = (a:int=1  , b:string)
+let t2 = (a:int=100, b:string)
+var v1 = (a=33     , b="hello")
+
+let f1 = fun() {
+  return (a=33     , b="hello")
+}
+
+assert t1    equals t2
+assert t1    equals v1
+assert f1()  equals t1
+assert _:f1 !equals t1
+assert _:t1  equals t2
+
+

equals and does check for types. Sometimes, the type can have a function +call and you do not want to call it. The solution in this case is to use the +:type to avoid the function call.

+

Since the puts command understands types, it can be used on any variable, and +it is able to print/dump the results.

+
let At:int(33..) = _      // number bigger than 32
+let Bt=(
+  ,c:string = _
+  ,d=100
+  ,setter = fun(ref self, ...args) { self.c = args }
+)
+
+var a:At=40
+var a2 = At(40)
+cassert a == a2
+
+var b:Bt="hello"
+var b2 = Bt("hello")
+cassert b == b2
+
+puts "a:{} or {}", a, at // a:40 or 33
+puts "b:{}", b           // b:(c="hello",d=100)
+
+

Type equivalence

+

The does operator is the base to compare types. It follows structural typing rules. +These are the detailed rules for the a does b operator depending on the a and b fields:

+
    +
  • +

    false when a and b are different basic types (boolean, fun, + integer, proc, range, string, enums).

    +
  • +
  • +

    true when a and b have the same basic type of either boolean or string.

    +
  • +
  • +

    true when a and b are enum and a has all the possible enumerates + fields in b with the same value.

    +
  • +
  • +

    a.max>=b.max and a.min<=b.min when a and b are integers. The max/min + are previously constrained values in left-hand-side statements, or inferred + from right-hand-side if no lhs type is specified.

    +
  • +
  • +

    (a@[..] & b@[..]) == b@[..] when a and b are range. This means that the a + range has at least all the values in b range.

    +
  • +
  • +

    There are two cases for tuples. If all the tuple entries are named, a does + b is true if for all the root fields in b the a.field does b.field. When + either a or b have unnamed fields, for each field in b the name but + also position should match. The conclusion is that if any field has no name, + all the fields should match by position and/or name if available.

    +
  • +
  • +

    a does b is false if the explicit array size of a is smaller than the + explicit array size of b. If the size check is true, the array entry type + is checked. _:[]x does _:[]y is false when _:x does _:y is false.

    +
  • +
  • +

    The lambdas have a more complicated set of rules explained later.

    +
  • +
+
assert (a:int:(max=33,min=0) does (a:int(20,5)))
+assert (a:int(0..=33)       !does (a:int(50,5)))
+
+assert  (a:string,b:int) does (a:"hello", b:33)
+assert ((b:int,a:string) !does (a:"hello", b:33)) // order maters in tuples
+
+assert  _:fun(x,xxx2)->(y,z) does _:fun(x     )->(y,z)
+assert (_:fun(x     )->(y,z) !does _:fun(x,xxx2)->(y,z))
+
+

For named tuples, this code shows some of the corner cases:

+
let t1 = (a:string, b:int)
+let t2 = (b:int, a:string)
+
+var a:t1  = ("hello", 3)     // OK
+var a1:t1 = (3, "hello")     // compile error, positions do not match
+var b:t1  = (a="hello", 3)   // OK
+var b1:t1 = (3, a="hello")   // compile error, positions do not match
+var c:t1  = (a="hello", b=3) // OK
+var c1:t1 = (b=3, a="hello") // OK
+
+var d:t2 = c                 // OK, both fully named
+assert d.0 == c.1 and c.0 == d.1
+assert d.a == c.a and d.b == c.b
+
+

Ignoring the value is what makes equals different from ==. As a result +different functionality functions could be equals.

+
let a = fun() { 1 }
+let b = fun() { 2 }
+assert a equals _:fun()    // 1 !equals :fun()
+
+assert a() != b()              // 1 != 2
+assert a() equals b()          // 1 equals 2
+
+assert _:a equals _:fun()
+
+

Type check with values

+

Many programming languages have a match with structural checking. Pyrope +does allows to do so, but it is also quite common to filter/match for a given +value in the tuple. This is not possible with does because it ignores all the +field values. Pyrope has a case that extends the does comparison and also +checks that for the matching fields, the value is the same.

+

The previous explanation of a does b and a case b ignored types. When types +are present, both need to match type.

+
cassert (a:u32=0, b:bool) does (a:u32, c:string="hello", b=false)
+cassert (a:u32=0, c:string="hello", b=false) case (a = 0, b:bool) // b is nil
+
+cassert (a:u32=0, c:string="hello", b=false) !case (a:u32 = 1 , b:bool=nil )
+cassert (a:u32=0, c:string="hello", b=false) !case (a:bool=nil, b:bool=nil )
+cassert (a:u32=0, c:string="hello", b=false) !case (a = 0     , b     =true)
+
+

Nominal type check

+

Pyrope has structural type checking, but there is a keyword is that allows to +check that the type name matches a is b returns true if the type of a has +the same name as the type of b. The a is b is a boolean expression like a +does b, not a a:b type check. This means that it can be used in where +statements or any conditional code.

+

a is b is equivalent to check the a variable declaration type name against +the b variable declaration type name. If their declaration had no type, the +inferred type name is used.

+
let a = 3
+let b = 200
+cassert a is b
+
+let c:u32 = 10
+cassert a !is c
+cassert a::[typename] == "int" and c::[typename] == "u32"
+
+let d:u32 = nil
+cassert c is d
+
+let e = (a:u32=1)
+let f:(a:u32) = 33
+cassert e is f
+
+

Since it checks equivalence, when a is b == b is a.

+
let X1 = (b:u32)
+let X2 = (b:u32)
+
+let t1:X1 = (b=3)
+let t2:X2 = (b=3)
+assert (b=3) !is X2  // same as (b=3) !is X2
+assert t1 equals t2
+assert t1 !is t2
+
+let t4:X1 = (b=5)
+
+assert t4  equals t1
+assert t4  is     t1
+assert t4 !is     t2
+
+let f2 = fun(x) where x is X1 {
+  x.b + 1
+}
+
+

Enums with types

+

Enumerates (enums) create a number for each entry in a set of identifiers. +Pyrope also allows associating a tuple or type for each entry. Another +difference from a tuple is that the enumerate values must be known at compile +time.

+
let Rgb = (
+  ,c:u24
+  ,setter = proc(ref self, c) { self.c = c }
+)
+
+let Color = enum(
+  ,Yellow:Rgb = 0xffff00
+  ,Red:Rgb    = 0xff0000
+  ,Green      = Rgb(0x00ff00) // alternative
+  ,Blue       = Rgb(0x0000ff)
+)
+
+var y:Color = Color.Red
+if y == Color.Red {
+  puts "c1:{} c2:{}\n", y, y.c  // prints: c1:Color.Red c2:0xff0000
+}
+
+

It is also possible to support an algebraic data type with enums. This requires +each enumerate entry to have an associated type. In can also be seen as a union +type, where the enumerate has to be either of the enum entries where each is +associated to a type.

+
let ADT=enum(
+  ,Person:(eats:string) = _
+  ,Robot:(charges_with:string) = _
+)
+
+let nourish = fun(x:ADT) {
+  match x {
+    == ADT.Person { puts "eating:{}"  , x.eats         }
+    == ADT.Robot  { puts "charging:{}", x.charges_with }
+  }
+}
+
+test "my main" {
+  (_:Person="pizza", _:Robot="electricity").each(nourish)
+}
+
+

Bitwidth

+

Integers can be constrained based on the maximum and minimum value (not by +the number of bits).

+

Pyrope automatically infers the maximum and minimum values for each numeric +variable. If a variable width can not be inferred, the compiler generates a +compilation error. A compilation error is generated if the destination +variable has an assigned size smaller than the operand results.

+

The programmer can specify the maximum number of bits, or the maximum value range. +The programmer can not specify the exact number of bits because the compiler has +the option to optimize the design.

+

In fact, internally Pyrope only tracks the max and min value. When the +sbits/ubits is used, it is converted to a max/min range. Pyrope code can +set or access the bitwidth attributes for each integer variable.

+
    +
  • $max: the maximum number
  • +
  • $min: the minimum number
  • +
  • $sbits: the number of bits to represent the value
  • +
  • $ubits: the number of bits. The variable must be always positive or a compile error.
  • +
+

Internally, Pyrope has 2 sets of max/min. The constrained and the current. +The constrained is set during type declaration. The current is computed based +on the possible max/min value given the current path/values. The current should +never exceed the constrained or a compile error is generated. Similarly, the +current should be bound to a given size or a compile error is generated.

+

The constrained does not need to be specifed. In this case, the hardware will +use whatever current value is found. This allows to write code that adjust to +the needed number of integer bits.

+

When the attributes are read, it reads the current. it does not read the constrained.

+
var val:u8 = 0   // designer constraints a to be between 0 and 255
+assert val.[sbits] == 0
+
+val = 3          // val has 3 bits (0sb011 all the numbers are signed)
+
+val = 300        // compile error, '300' overflows the maximum allowed value of 'val'
+
+val = 1          // max=1,min=1 sbits=2, ubits=1
+assert val.[ubits] == 1 and val.[min]==1 and val.[max]==1 and val.[sbits]==2
+
+val::[wrap] = 0x1F0 // Drop bits from 0x1F0 to fit in constrained type
+assert val == 240 == 0xF0
+
+val = u8(0x1F0)    // same
+assert val == 0xF0
+
+

Pyrope leverages LiveHD bitwidth pass to compute the maximum and minimum value +of each variable. For each operation, the maximum and minimum are computed. For +control-flow divergences, the worst possible path is considered.

+
var a = 3                  // a: current(max=3,min=3) constrain()
+var c:int(0..=10) = _      // c: current(max=0,min=0) constrain(max=10,min=0)
+if b {
+  c = a+1                  // c: current(max=4,min=4) constrain(max=10,min=0)
+}else{
+  c = a                    // c: current(max=3,min=3) constrain(max=10,min=0)
+}
+                           // c: current(max=4,min=3) constrain(max=10,min=0)
+
+var e::[sbits = 4] = _     // e: current(max=0,min=0) constrain(max=7,min=-8)
+e = 2                      // e: current(max=2,min=2) constrain(max=7,min=-8)
+var d = c                  // d: current(max=4,min=3) constrain()
+if d==4 {
+  d = e + 1                // d: current(max=3,min=3) constrain()
+}
+var g:u3 = d               // g: current(max=4,min=3) constrain(max=7,min=0)
+var h = c@[0,1]            // h: current(max=3,min=0) constrain()
+
+

Bitwidth uses narrowing to converge (see +internals). The GCD example does not specify +the input/output size, but narrowing allows it to work without typecasts. To +understand, the comments show the max/min bitwidth computations.

+
if cmd? {
+  (x,y) = cmd   // x.max=cmd.a.max; x.min = 0 (uint) ; ....
+}elif x > y {
+                // narrowing: x.min = y.min + 1 = 1
+                // narrowing: y.max = x.min - 1
+  x = x - y     // x.max = x.max - x.min = x.max - 1
+                // x.min = x.min - y.max = 1
+}else{          // x <= y
+                // narrowing: x.max = y.min
+                // narrowing: y.min = x.min
+  y = y - x     // y.max = y.max - x.min = y.max
+                // y.min = y.min - x.max = 0
+}
+                // merging: x.max = x.max ; x.min = 0
+                // merging: y.max = y.max ; y.min = 0
+                // converged because x and y is same or smaller at beginning
+
+

The bitwidth pass may not converge to find a valid size even with narrowing. +In this case, the programmer must insert a typecast or operation to constrain +the bitwidth by typecasting. For example, this could work:

+
reg x = 0
+reg y = 0
+if cmd? {
+  (x,y) = cmd
+}elif x > y {
+  x = x - y
+}else{
+  y = y - x
+}
+x:cmd.a:[wrap] = x  // use cmd.a type for x, and drop bits as needed
+y = cmd.b(y)        // typecast y to cmd.b type (this can add a mux)
+
+

Pyrope uses signed integers for all the operations and transformations, but +when the code is optimized it does not need to waste bits when the most +significant bit is known to be always zero (positive numbers like u4). The +verilog code generation or the synthesis netlist uses the bitwidth pass to +remove the extra unnecessary bit when it is guaranteed to be zero. This +effectively "packs" the encoding.

+

Variants

+

A Pyrope variant is the equivalent of an union type. A variant type spifices a +set of types allowed for a given variable. In Pyrope, a variant looks like a +tuple where each entry has a different type. Unlike tuples all the "space" or +bits used are shared because the tuple can have only one entry with data at a +given time.

+

Pyrope supports variants but not unions. The difference between typical (like +C++) union and variant is that union can be used for a typecast to convert +between values, the variant is the same but it does not allow bit convertion. +It tracks the type from the assignment, and an error is generated if the +incorrect type is accesed. Pyrope requires explicit type conversion with +bitwise operations.

+

Variant shares syntax with enums declaration, but the usage and functionality +is quite different. Enums do not allow to update values and variants are tuples +with multiple labels sharing a single storage location.

+

The main advantage of variant is to save space. This means that the most +typical use is in combination with registers or memories, when alternative +types can be stored across cycles.

+
let e_type=enum(str:String = "hello",num=22)
+let v_type=variant(str:String, num:int) // No default value in variant
+
+var vv:v_type = (num=0x65)
+cassert vv.num == 0x64
+let xx = vv.str                         // compile or simulation error
+
+

The variant variable allows to explicitly or implicitly access the subtype. +Variants may not be solved at compile time, and the error will be a simulation +error. A comptime directive can force a compile time-only variant.

+
let Vtype=variant(str:String,num:int,b:bool)
+
+let x1a:Vtype = "hello"                 // implicit variant type
+let x1b:Vtype = (str="hello")           // explicit variant type
+
+var x2:Vtype:[comptime] = "hello"       // comptime
+
+cassert x1a.str == "hello" and x1a == "hello"
+cassert x1b.str == "hello" and x1b == "hello"
+
+let err1 = x1a.num                      // compile or simulation error
+let err2 = x1b.b                        // compile or simulation error
+let err3 = x2.num                       // compile error
+
+

As a reference, enums allow to compare for field but not update enum entries.

+
var ee = e_type
+ee.str = "new_string"       // compile error, enum is immutable
+
+match ee {
+ == e_type.str { }
+ == e_type.num { }
+}
+
+

Typecasting

+

To convert between tuples, an explicit setter is needed unless the tuple fields +names, order, and types match.

+
let at=(c:string,d:u32)
+let bt=(c:string,d:u100)
+
+let ct=(
+  ,d:u32    = _
+  ,c:string = _
+)
+// different order
+let dt=(
+  ,d:u32    = _
+  ,c:string = _
+  ,setter = proc (ref self, x:at) { self.d = x.d ; self.c = x.c }
+)
+
+var b:bt=(c="hello", d=10000)
+var a:at=_
+
+a = b          // OK c is string, and 10000 fits in u32
+
+var c:ct= a    // OK even different order because all names match
+
+var d:dt = a   // OK, call intitial to type cast
+
+
    +
  • To string: The format allows to convert any type/tuple to a string.
  • +
  • To integer: variable@[..] for string, range, and bool, union otherwise.
  • +
  • union allows to convert across types by specifying the size explicitly.
  • +
+

Introspection

+

Introspection is possible for tuples.

+
a = (b=1,c:u32=2)
+var b = a
+b.c=100
+
+assert a equals b
+assert a.size == 2
+assert a['b'] == 1
+assert a['c'] equals u32
+
+assert   a has 'c'
+assert !(a has 'foo')
+
+assert a.[id] == 'a'
+assert a.0.[id] == ':0:b' and a.b.[id] == ':0:b'
+assert a.1.[id] == ':1:c' and a.c.[id] == ':1:c'
+
+

Function definitions allocate a tuple, which allows to introspect the +function but not to change the functionality. Functions have 3 fields inputs, +outputs, where. The where is a function that always returns true if unset +at declaration.

+
let fu = fun(a,b=2) -> (c) where a>10 { c = a + b }
+assert fu.[inp] equals ('a','b')
+assert fu.[out] equals ('c')
+assert fu.[where](a=200) and !fu.[where](a=1)
+
+

This means that when ignoring named vs unnamed calls, overloading behaves like +this:

+
let x:u32 = fn(a1,a2)
+
+let model_poly_call = fun(fn, ...args)->(out) {
+  for f in fn {
+     continue unless f.[inp] does args
+     continue unless f.[out] does out
+     return f(args) when i.[where](args)
+  }
+}
+let x:u32 = model_poly_call(fn, a1, a2)
+
+

There are several uses for introspection, but for example, it is possible to build a +function that returns a randomly mutated tuple.

+
let randomize::[debug] = fun(ref self) {
+  let rnd = import("prp/rnd")
+  for i in ref self {
+    if i equals _:int {
+      i = rnd.between(i.[max],i.[min])
+    }elif i equals _:bool {
+      i = rnd.boolean()
+    }
+  }
+  self
+}
+
+let x = (a=1,b=true,c="hello")
+let y = x.randomize
+
+assert x.a==1 and x.b==true and x.c=="hello"
+cover  y.a!=1
+cover  y.b!=true
+assert y.c=="hello"  // string is not supposed to mutate in randomize()
+
+

Global scope

+

There are no global variables or functions in Pyrope. Variable scope is +restricted by code block { ... } and/or the file. Each Pyrope file is a +function, but they are only visible to the same directory/project Pyrope files.

+

There are only two ways to access variables outside Pyrope file. The import +statement allows referencing public lambdas from other files. The register +declarations allow to assign an ID, and other files can access the register by +"reference".

+

import

+

import keyword allows to access functions not defined in the current file. +Any call to a function or tuple outside requires a prior import statement.

+
// file: src/my_fun.prp
+let fun1    = fun(a,b) { a+b }
+let fun2    = fun(a) {
+  let inside = fun() { 3 }
+  a
+}
+let another = fun(a) { a }
+
+let mytup = (
+  ,call3 = fun() { puts "call called" }
+)
+
+
// file: src/user.prp
+a = import("my_fun/*fun*")
+a.fun1(a=1,b=2)         // OK
+a.another(a=1,2)        // compile error, 'another' is not an imported function
+a.fun2.inside()         // compile error, `inside` is not in top scope variable
+
+let fun1 = import("my_fun/fun1")
+lec fun1, a.fun1
+
+x = import("my_fun/mytup")
+
+x.call3()                // prints call called
+
+

The import points to a file setup code +list of public variables or types. The setup code corresponds to the "top" scope +in the imported file. The import statement can only be executed during the +setup phase. The import allows for cyclic dependencies between files as long as +there is no true cyclic dependency between variables. This means that "false" +cyclic dependencies are allowed but not true ones.

+

The import behaves like cut and pasting the imported code. It is not a +reference to the file, but rather a cut and paste of functionality. This means +that when importing a variable, it creates a copy. If two files import the same +variable, they are not referencing the same variable, but each has a separate +copy.

+

The import is delayed until the imported variable is used in the local file. +There is no order guarantee between imported files, just that the code needed +to compute the used imported variables is executed before.

+

The import statement is a filename or path without the file extension. +Directories named code, src, and lib are skipped. No need to add them in +the path. import stops the search on the first hit. If no match happens, a +compile error is generated.

+

import allows specialized libraries per subproject. For example, xx/yy/zz can +use a different library version than xx/bb/cc if the library is provided by yy, +or use a default one from the xx directory.

+
let a = import("prj1/file1")
+let b = import("file1")       // import xxx_fun from file1 in the local project
+let c = import("file2")       // import the functions from local file2
+let d = import("prj2/file3")  // import the functions from project prj2 and file3
+
+

Many languages have a "using" or "import" or "include" command that includes +all the imported functions/variables to the current scope. Pyrope does not +allow that, but it is possible to use a mixin to add the imported functionality +to a tuple.

+
let b = import("prp/Number")
+var a = import("fancy/Number_mixin")
+
+let Number = b ++ a // patch the default Number class
+
+var x:Number = 3
+
+

Register reference

+

While import "copies" the contents, regref or Register reference allows to +reference (not copy) an existing register in the call hierarchy.

+

The syntax of regref is similar to import but the semantics are very different. +While import looks through Pyrope files, regref looks through the instantiation +hierarchy for matching register names. regdef only can get a reference to a +register, it can not be used to import functions or variables.

+
let do_increase = proc() {
+  reg counter = 0
+
+  counter:u32:[wrap] = counter + 1
+}
+
+let do_debug = proc() {
+  let cntr = regref("do_increase/counter")
+
+  puts "The counter value is {}", cntr
+}
+
+

Verilog has a more flexible semantics with the Hierarchical Reference. It also +allows to go through the module hierarchy and read/write the contents of any +variable. Pyrope only allows you to reference registers by unique name. Verilog +hierarchical reference is not popular for 2 main reasons: (1) It is considered +"not nice" to bypass the module interface and touch an internal variable; (2) +some tools do not support it as synthesizable; (3) the evaluation order is not +clear because the execution order of the modules is not defined.

+

Allowing only a single lambda to update registers avoids the evaluation order +problem. From a low level point of view, the updates go to the register din +pin, and the references read the register q pin. The register references +follow the model of single writer multiple reader. This means that only a +single lambda can update the register, but many lambdas can read the register. +This allows to be independent on the lambda evaluation order.

+

The register reference uses instantiated registers. This means that if a lambda +having a register is called in multiple places, only one can write, and the +others are reading the update. It is useful to have configuration registers. In +this case, multiple instances of the same register can have different values. +As an illustrative example, a UART can have a register and the controller can +set a different value for each uart base register.

+
// file remote.prp
+
+let xxx = proc(some,code) {
+  reg uart_addr:u32 = _
+  assert 0x400 > uart_addr >= 0x300
+}
+
+// file local.prp
+let setup_xx = proc() {
+  var xx = regref("uart_addr") // match xxx.uart_addr if xxx is in hierarchy
+  var index = 0
+  for val in ref xx {          // ref does not allow enumerate
+    val = 0x300+index*0x10     // sets uart_addr to 0x300, 0x310, 0x320...
+    index += 1
+  }
+}
+
+

Maybe the best way to understand the regdef is to see the differences with +the import:

+
    +
  • Instantiation vs File hierarchy
  • +
  • regref finds matches across instantiated registers.
  • +
  • import traverses the file/directory hierarchy to find one matche.
  • +
  • Success vs Failure
  • +
  • regref keeps going to find all the matches, and it is possible to have a zero matches
  • +
  • import stops at the first match, and a compile error is generated if there is no match.
  • +
+

Mocking library

+

One possible use of the register reference is to create a "mocking" library. A +mocking library instantiates a large design but forces some subblocks to +produce some results for testing. The challenge is that it needs undriven +registers. During testing, the peek/poke is more flexible and it can +overwrite an existing value. The peek/poke use the same reference as import +or register reference.

+
let bpred = ( // complex predictor
+  ,let taken = fun(){ self.some_table[som_var] >=0 }
+)
+
+test "mocking taken branches" {
+  poke "bpred_file/taken", true
+
+  var l = core.fetch.predict(0xFFF)
+}
+
+

Operator overloading

+

There is no operator overload in Pyrope. + always adds Numbers, ++ always +concatenates a tuple or a String, and is always for boolean types,...

+

Getter/Setter method

+

Pyrope tuples can use the same syntax as a lambda call or a direct assignment. +Both the assignment and the lambda call follow the same rules for ambiguity as +the default lambda calls. This means that fields must be named unless single +character names, or variable name matches argument name, or there is no type +ambiguity.

+
let Typ1 = (
+  ,a:string = "none"
+  ,b:u32    = 0
+)
+
+let w      = Typ1(a="foo", b=33)  // OK
+let x:Typ1 = (a="foo", b=33)      // OK, same as before
+
+let v:Typ1 = Typ1(a="foo", b=33)  // OK, but redundant Typ1
+let y:Typ1 = ("foo", 33)          // OK, because no conflict by type
+
+var z:Typ1 = _                    // OK, default field values
+cassert z.a == "none" and z.b == 0
+z = ("foo",33)
+
+cassert v==w==x==y==z
+
+

Pyrope allows a setter method to intercept assignments or construction. The same +setter method is called in all the previous cases.

+

The setter method can use single character arguments for array index, but they must +respect the declaration order.

+
let Typ2 = (
+  ,a:string = "none"
+  ,b:u32    = 0
+  ,setter = proc(ref self, a, b) { self.a = a ; self.b = b }
+)
+
+var x:Typ2 = (a="x", b=0)
+var y:Typ2 = (a="x", b=0)
+
+x["hello"] = 44
+y = ("hello",44)
+cassert x==y
+
+

Tuples can be multi-dimensional, and the index can handle multiple indexes at once.

+
let Matrix8x8 = (
+  ,data:[8][8]u16 = _
+  ,setter = fun(ref self, x:int(0,7), y:int(0,7), v:u16) {
+    self.data[x][y] = v
+  } ++ fun(ref self, x:int(0,7), v:u16) {
+    for ent in ref data[x] {
+      ent = v
+    }
+  } ++ fun(ref self) { // default initialization
+    for ent in ref data {
+      ent = 0
+    }
+  }
+)
+
+let m:Matrix8x8 = _
+cassert m.data[0][3] == 0
+
+m[1,2] = 100
+cassert m.data[1][2] == 100
+m[1] = 3
+cassert m.data[1][2] == 3
+m[4][5] = 33
+cassert m.data[4][5] == 33
+
+m[1] = 40
+cassert m[1] == (3,40,3,3,3,3,3,3)
+
+

The default getter/setter allows for indexing each of the dimentions and returns +a slice of the object. Since they can be overwritten, the explicit overload selects +which to pick.

+
let Matrix2x2 = (
+  ,data:[2][2]u16 = _
+  ,getter = fun(ref self, x:int(0,2), y:int(0,2)) {
+    self.data[x][y] + 1
+  }
+
+)
+
+let n:Matrix2x2 = _
+n.data[0][1] = 2      // default setter
+
+cassert n[0][1] == 3  // getter does + 1
+cassert n[0] == (0,3) // compile error, no getter for fun(ref self, x)
+
+

The symmetric getter method is called whenever the tuple is read. Since each +variable or tuple field is also a tuple, the getter/setter allow to intercept +any variable/field. The same array rule applies to the getter.

+
let My_2_elem = (
+  ,data:[2]string = _
+  ,setter = proc(ref self, x:uint(0..<2), v:string) {
+    self.data[x] = v
+  } ++ proc(ref self, v:My_2_elem) {
+    self.data = v.data
+    } ++ proc(ref self) { // default _ assignment
+      self.data = _
+    }
+  ,getter = fun(self)         { self.data    }
+         ++ fun(self, i:uint) { self.data[i] }
+)
+
+var v:My_2_elem = _
+var x:My_2_elem = _
+
+v = (x=0, "hello")
+v[1] = "world"
+
+cassert v[0] == "hello"
+cassert v == ("hello", "world")  // not
+
+let z = v
+cassert z !equals v   // v has v.data, z does not
+
+

The getter/setter can also be used to intercept and/or modify the value +set/returned.

+
let some_obj = (
+  ,a1:string
+  ,a2 = (
+    ,_val:u32 = _                               // hidden field
+
+    ,getter=fun(self) { self._val + 100 }
+    ,setter=proc(ref self, x) { self._val = x+1 }
+  )
+  ,setter = proc(ref self, a,b){                  // setter
+    self.a1      = a
+    self.a2._val = b
+  }
+)
+
+var x:some_obj = ("hello", 3)
+
+assert x.a1 == "hello"
+assert x.a2 == 103
+x.a2 = 5
+
+

The getter method can be overloaded. This allows +to customize by return type:

+
let showcase = (
+  ,v:int = _
+  ,getter = fun(self)->(_:string) where self.i>10 {
+    format("this is a big {} number", self.v)
+  } ++ fun(self)->(_:int) {
+    self.v
+  }
+)
+
+var s:showcase = _
+s.v = 3
+let r1:string = s // compile error, no matching getter
+let r2:int    = s // OK
+
+s.v = 100
+let r3:string = s // OK
+cassert r3 == "this is a bit 100 number"
+
+

Like all the lambdas, the getter method can also be overloaded on the return type. +In this case, it allows building typecast per type.

+
let my_obj = (
+  ,val:u32 = _
+  ,getter = fun(self)->(_:string ){ string(self.val) }
+       ++ fun(self)->(_:bool){ self.val != 0    }
+       ++ fun(self)->(_:int    ){ self.val         }
+)
+
+

Attribute setter/getter value

+

The setter/getter can also access attributes:

+
var obj1::[attr1] = (
+  ,data:int = _
+  ,setter = fun(ref self, v) {
+    if v.[attr2] {
+      self.data.[attr3] = 33
+    }
+    cassert self.[attr1]
+  }
+)
+
+

Default setter value

+

All the variable declarations need a explicit assigned value. The _ allows to +pick the default value based on the type. If the type is an integer, the _ is equivalent +to a zero. If the type is a boolean, the default or _ is false. For more complicated +tuple types, the setter will be called without any value.

+
let fint:int = _
+cassert fint == 0
+
+var fbool:bool = _
+cassert fbool == 0
+
+let Tup = (
+  ,v:string = _  // default to empty
+  ,setter = fun(ref self) { // no args, default setter for _
+     cassert self.v == ""
+     self.v = "empty33"
+  } ++ fun(ref self, v) {
+     self.v = v
+  }
+)
+
+var x:Tup = _
+cassert x.v == "empty33"
+
+x = "Padua"
+cassert x.v == "Padua"
+
+var y = Tup()
+cassert y.v == "empty33"
+
+y = "ucsc"
+cassert y.v == "ucsc"
+
+

Array/Tuple getter/setter

+

Array index also use the setter or getter methods.

+
var my_arr = (
+  ,vector:[16]u8 = 0
+  ,getter = fun(self, idx:u4) {
+     self.vector[idx]
+  }
+  ,setter = proc(ref self, idx:u4, val:u8) {
+     self.vector[idx] = val
+  } ++ proc(ref self) {
+     // default constructor declaration
+  }
+)
+
+my_arr[3] = 300           // calls setter
+my_arr.3  = 300           // calls setter
+cassert my_add[3] == 300  // calls getter
+cassert my_add.3  == 300  // calls getter
+
+

Unlike languages like C++, the setter is only called if there is a new value +assigned. This means that the index must always be in the left-hand-side of an +assignment.

+

If the getter/setter uses a string argument, this also allows to access tuple fields.

+
let Point = (
+  ,priv_x:int:[private] = 0
+  ,priv_y:int:[private] = 0
+
+  ,setter = proc(ref self, x:int, y:int) {
+    self.priv_x = x
+    self.priv_y = y
+  }
+
+  ,getter = proc(self, idx:string) {
+    match idx {
+     == 'x' { self.priv_x }
+     == 'y' { self.priv_y }
+    }
+  }
+)
+
+let p:Point = (1,2)
+
+cassert p['x'] == 1 and p['y'] == 2
+cassert p.x == 1 and p.y == 2          // compile error
+
+

Compare method

+

The comparator operations (==, !=, <=,...) need to be overloaded for most +objects. Pyrope has the lt and eq methods to build all the other +comparators. When non-provided the lt (Less Than) is a compile error, and the +eq (Equal) compares that all the tuple fields are equal.

+
let t=(
+  ,v:string = _
+  ,setter = proc(ref self) { self.v = a }
+  ,lt = fun(self,other)->(_:bool){ self.v  < other.v }
+  ,eq = fun(self,other)            { self.v == other.v } // infer return
+)
+
+var m1:t = 10
+var m2:t = 4
+assert m1 < m2 and !(m1==m2)
+assert m1 <= m2 and m1 != m2 and m2 > m1 and m2 >= m1
+
+

The default tuple comparator (a == b) compares values, not types like a does +b, but a compile error is created unless a equals b returns true. This means +that a comparison by tuple position suffices even for named tuples.

+
let t1=(
+  ,long_name:string = "foo"
+  ,b=33
+)
+let t2=(
+  ,b=33
+  ,long_name:string = "foo"
+)
+let t3=(
+  ,33
+  ,long_name:string = "foo"
+)
+
+cassert t1==t2
+cassert t1 !equals t3
+let x = t1==t3           // compile error, t1 !equals t3
+
+

The comparator a == b when a or b are tuples is equivalent to: +

cassert (a==b) == ((a in b) and (b in a))
+cassert a equals b
+

+

With the eq overload, it is possible to compare named and unnamed tuples.

+
let t1=(
+  ,long_name:string = "foo"
+  ,b=33
+)
+let t2=(
+  ,xx_a=33
+  ,yy_b = "foo"
+  ,eq = fun(self, o:t1) {
+    return self.xx_a == o.b and self.xx_y == o.long_name
+  } ++ fun(self, o:t2) {
+    return self.xx_a == o.xx_a and self.xx_y == o.xx_y
+  }
+)
+
+cassert t1==t2 and t2==t1
+
+

Since a == b can compare two different objects, it is not clear if a.eq or b.eq method +is called. Pyrope has the following rule:

+
    +
  • If only one of the two has a defined method, that method is called.
  • +
  • If both have defined methods, they should have the same set of eq methods or a compile error is created.
  • +
+

It is also possible to provide a custom ge (Greater Than). The ge is redundant +with the lt and eq ((a >= b) == (a==b or b<a)) but it allows to have more +efficient implemetations:

+

For integer operations, the Pyrope should result to the following equivalent Lgraph:

+
    +
  • a == b is __eq(a,b)
  • +
  • a != b is __not(__eq(a,b))
  • +
  • a < b is __lt(a,b)
  • +
  • a < b is __lt(b,a)
  • +
  • a <= b is __lt(a,b) | __eq(a,b) (without ge) or __ge(b,a)
  • +
  • a >= b is __lt(b,a) | __eq(a,b) (without ge) or __ge(a,b)
  • +
+

Non-Pyrope (C++) calls

+

Calling C++ or external code is still fully synthesizable if the code is +available at compile time. An example could be calling a C++ API to read a json +file during the setup phase to decide configuration parameters.

+
let cfg = __read_json()
+
+let ext = if cfg.foo.bar == 3 {
+   foo
+}else{
+   bar
+}
+
+

Non-Pyrope calls have the same procedure/function distinction and use the same +Pyrope lambda definition but they do not have the where clause.

+

If no type is provided, a C++ call assumes a proc(...inp)->(...out) type is +can pass many inputs/outputs and has permission to mutate values. Any call to a +method with two underscores __ is either a basic gate or a C++ function.

+
let __my_typed_cpp:fun(a,b)->(e) = _
+
+

Type defining non-Pyrope code is good to catch errors and also because declaring +function allows to handle several cases of circular dependencies not possible with procedure import section

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyrope/07b-structtype/index.html b/pyrope/07b-structtype/index.html new file mode 100644 index 0000000..a17220c --- /dev/null +++ b/pyrope/07b-structtype/index.html @@ -0,0 +1,1701 @@ + + + + + + + + + + + + + + + + + + + + + + Structural Typing - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Structural Typing

+

Pyrope uses structural typing somewhat simular to other languages like +Typescript, but there are some difference simplifications like not references, +everything is passed by value, no union types.

+

Type check

+

The x does y checks that x does the same as y and maybe more. It type +system syntax means that x is a subtype of y, or that y is a supertype +x.

+

Using the typical Animal, Dog, Greyhound set of tuples, Dog does Animal +and Greyhound does Dog, but not (Animal does Dog).

+

Dealing with tuple assignments y = x, a compile error is generated unless the +type system satisfies y does x or an explicit type conversion is provided. +The basic behavior of does is explained in (Type +equivalance)[07-typesystem.md#Type_equivalence].

+
let Animal = (
+  ,legs:int = _
+  ,name= "unnamed"
+  ,say_name = fun() { puts name }
+)
+
+let Dog = Animal ++ (
+  ,setter = proc(ref self) { self.legs = 4 }
+  ,bark = fun() { puts "bark bark" }
+)
+
+let Bird = Animal ++ (
+  ,seeds_eaten:int = _
+
+  ,setter = proc(ref self)  { self.legs = 2 }
+      ++ proc(ref self, a:Animal)    { self.legs = 2 ; name = "bird animal" }
+  ,eat_seeds = proc(ref self, n) { self.seeds_eaten += n }
+)
+
+let Greyhound = Dog ++ ( // also extends Dog
+  ,race = fun() { puts "running fast" }
+)
+
+
var a:Animal = _
+var b:Bird = _
+var d:Dog = _
+
+d = a // compile error, 'a does d' is false
+b = a // OK, explicit setter in Bird for Animal
+
+a = d // OK, 'd does a' is true
+a = b // OK, 'Bird does Animal' is true
+
+

When the x in x = y is an integer basic type, there is an additional +check to guarantee that no precision is lost. Otherwise, an explicit wrap or +drop directive must be used.

+

Arrays

+

The same rules of assignments exists for arrays. In Pyrope, arrays can be +mutable, but they can never be passed by reference. This means that the typical +issue of mutable containers can not exists.

+
var a_vec:[]Animal = _
+var b_vec:[]Bird = _
+var d_vec:[]Dog = _
+
+a_vec[0] = d:Dog    // OK
+a_vec[1] = b:Bird   // OK
+
+d_vec[0] = d:Dog        // OK  'd does d'
+d_vec[0] = g:Greyhound  // OK  'g does d'
+d_vec[0] = b:Bird       // Compile error
+d_vec[0] = a:Animal     // Compile error
+
+b_vec[0] = d:Dog        // OK, explicit conversion
+b_vec[0] = g:Greyhound  // OK, explicit conversion
+b_vec[0] = b:Bird       // OK, 'b does b'
+b_vec[0] = a:Animal     // OK, explicit conversion
+
+let do_animal_vec = fun(a_vec:[]Animal)->(r:[]Animal) {
+  r = a_vec
+  r[0] = d:Dog  // OK `d does r[0]`
+}
+
+var x = do_animal_vec(b_vec:[]Bird) // OK
+assert x does _:[]Animal  // not :[]Bird
+
+

Basic types

+

One of the complains about structural type system is that two types with +exactly the same tuple fields have the same type. In Pyrope, the field name +should match. Since every element is a type of one, read/writing a named tuple +of one does not need the field, and hence it allows to create different types:

+
let Age = (
+  ,age:int = _
+)
+let Weight = (
+  ,weight:int = _
+)
+
+assert Age !does Weight
+
+var a:Age = 3
+assert a == a.age == a.0 == 3
+
+var w:Weight = 100
+
+let err = a == w // compile error, not (a equals w) or overload
+
+

Lambda

+

A way to classify a language is to look at the generics and lambda calls. +Languages can have type constraints or type classes. Type classes (Hakell, +Rust, Swift) specify the "consent" of argumetns or return types allowed for +lambda or generic. Type constrains (C++, typescript, Pyrope) constraints the +arguments or return types allowed. Pyrope follows a type constraint approach.

+

The following f method has no constraints on the input arguments. It can pass +anything, but constraints the return value to be an integer.

+
let f = fun(a,b) -> (r:int) { r = xx(a) + xx(b) }
+
+

The type can be inferred for arguments and return values. If the lambda +definition has no type constraints. A "different" implementation lambda exist +for each combination of inferred types. It behaves like if the the lambda were +inlined in the caller.

+

The constraints can be different per type, or use a more familiar generic syntax. +The f1 example constraints a and b arguments to have a type that +satisfies (a does Some_type_class) and (b does Some_type_class).

+
let f1 = fun<T:Some_type_class>(a:T,b:T) -> (r:int) { r = xx(a) + xx(b) }
+
+

While performing assignments checks that the left-hand-side tuple fields are +fully populated (x=y) by checking that y does x. The same check happens for +the lambda calls, but the check is performed when a lambda is passed as +an argument.

+

For each lambda call (ret_val = f(a1,a2)), the type system check against the +defined lambda (f = fun(ad1:ad1_t, ad2)->(rd1:rd1_t, rd2)). In this case, the +check for the calling arguments ((a1,a2) does (:ad1_t, :())) should be +satisfied. Notice that some of the inputs (ad2) have no defined type, so those +unspecified arguments always satisfies by the type check.

+

The return tuple is also used in the type system (ret_val does (:rd1_t, +:())), the check is the same as in an assignment (lhs does rhs). In +overloading cases explained later, the return type could also be part of the +overloading check.

+
let fa_t:fun(a:Animal)->() = _
+let fd_t:fun(d:Dog)->() = _
+
+let call_animal = fun(a:Animal)->() {
+   puts a.name // OK
+}
+let call_dog:fd_t = fun(d:Dog)->() {    // OK to add type in lhs
+   d.bark()    // OK
+}
+
+let f_a = fun(fa:fa_t) { 
+  var a:Animal = _
+  var d:Dog = _
+  fa(a)  // OK
+  fa(d)  // OK, `d does Animal` is true
+}
+f_a(call_animal) // OK
+f_a(call_dog)    // compile error, `fa_t does call_dog` is false
+
+let f_d = fun(fd:fd_t) { 
+  var a:Animal = _
+  var d:Dog = _
+  fd(a)  // compile error, `a does Dog` is false
+  fd(d)  // OK
+}
+f_d(call_animal) // OK, `fd_t does call_animal` is true
+f_d(call_dog)    // OK
+
+

In tuple comparisons, does and ==, the tuple field position is not used +when both tuples are fully named. If tuple field is unnamed, both existing +names and positions should match in the comparison. For fully named tuples, +when all the fields have names, (a=1,b=2) does (b=2,a=1) is true.

+

The same rule also applies to lambda calls. If all the arguments are named, the +relative call argument position is independent. If an argument is an expression +or unnamed, the position is important.

+

A special case is the in-place operator (...) during lambda definition. Even +for fully named tuples, the position is used. One one in-place operator is +allowed per lambda definition (a,b,...x,c), the does operator uses name and +position like in unnamed tuples even if all the fields are named. First, it +matches the position and names provided, and then checks the rest to the +in-place with the relative order left.

+
let m = fun(a:int,...x:(_:string,c:int,d), y:int)->() { 
+  assert a == 1
+  assert x.0 == "here"
+  assert x.1 == 2 == x.c
+  assert y == 3
+  if d does int { // inferred type
+    assert d == 33
+  }else{
+    assert d == "x"
+  }
+}
+
+m(1,"here",2,"x",3)         // OK
+m(a=1,"here",2,"x",3)       // OK
+m(a=1,"here",c=2,"x",3)     // OK
+m(a=1,"here",c=2,33,y=3)    // OK
+
+m("1","here",2,33,3)       // compile error, a:int
+m("1","here",2,3)          // compile error, x has 3 fields
+
+

For all the checks that are not function reference or in-place, the x does y +check could be summarized as x is a superset of y. x has all the +functionality of y and maybe more. In a more formal compiler nomenclature x does +y applied to tuples is called a covariant relationship. It is covariant +because adding the same extra fields to both x and y keeps the semantics +(((foo=3,...x) does (foo=3,...y)) == x does y). This allows to extend the +tuple semantics and the relationship is preserved.

+

When x and y are in a lambda passed as reference to another lambda (lambda +reference), the relationship is not covariant but contravariant. Dog does +Animal is true, but :fun(x:Dog)->() does _:fun(x:Animal)->() is false. The +reason is shown in the previous example. The fun(fd:fd_t) can be called +with call_animal because the fields accessed by call_animal are only a +subset of Dog and hence if called inside f_d it can handle the Dog type. +The opposite is not the case.

+

:fun(x1)->(x2) does _:fun(y1)->y2 check is equivalent to (y1 does x1) and (x2 +does y2).

+

Given a lambda passed as argument (:fun(x:fun(c:c_t)->(d:d_t))->(y)), the +check when passing the lambda as argument to x a function like +fun(w:w_t)->(z:z_t). In this case, the :fun(:w_t)->(_:z_t) does +fun(:c_t)->(_:d_t) is a contravariant test for inputs and covariant for +outputs. This makes it equivalent to (_:c_t does _:w_t) and (_:z_t does _:d_t).

+

If the same type is used as input and output is an equivalence check (((a does +b) and (b does a)) == (a equals b)). In programming languages this is called +an invariance or bivariance.

+

Pyrope uses the typical check in modern languages where the function arguments +are contravariant and the return type is covariant. In Pyrope, the return type +is checked in the covariant and contravariant checks.

+

Lambda overloading

+

Pyrope does not have global scope for defined lambdas. Instead, all the lambda +must reside in a local variable or must be "imported". Nevertheless, a local +variable can have multiple lambdas. It is similar to Odin's "explicit procedure +overloading". This section explains how is the overloading selection in this +case.

+

By overloading, this section refers to typical ad-hoc polymorphism where the same +function/procedure name can have different functionality for different types.

+

For Pyrope overloading, lambdas are typically added at the end ++= of the tuple. +This means that it is NOT overwriting an existing functionality, but providing +a new call capability.

+

There is a priority of overloading in the tuple order. If the intention is to +intercept, the lambda must be added at the head of the tuple entry.

+
let base = (
+  ,fun1 = fun() { 1 }         // catch all
+  ,fun2 = fun() { 2 }         // catch all
+  ,fun3 = fun() { 3 }         // catch all
+)
+let ext = base ++ (
+  ,fun1 =   fun (a,b){ 4 }  // overwrite allowed with extends
+  ,fun2 ++= fun (a,b){ 5 }  // append
+  ,fun2 ++= fun ()   { 6 }  // append
+  ,fun3 =   fun(a,b) { 7 } ++ base.fun3 // prepend
+  ,fun3 =   fun()    { 8 } ++ base.fun3 // prepend
+)
+
+var t:ext = _
+
+// t.fun1 only has ext.fun1
+assert t.fun1(a=1,b=2) == 4
+t.fun1()                 // compile error, no option without arguments
+
+// t.fun2 has base.fun2 and then ext.fun2
+assert t.fun2(1,2) == 5  // EXACT match of arguments has higher priority
+assert t.fun2() == 2     // base.fun2 catches all ahead of ext.fun2
+
+// t.fun3 has ext.fun3 and then base.fun3
+assert t.fun3(1,2) == 7  // EXACT match of arguments has higher priority
+assert t.fun3() == 8     // ext.fun3 catches all ahead of ext.fun3
+
+

A more traditional "overload" calling the is possible by calling the lambda directly:

+
let x = base ++ (
+  ,fun1 = fun() { return base.fun1() + 100 }
+)
+
+

To allow overloading the base lambda as var. By concatenating lambdas to a +variable, we effectively create an unnamed tuple with multiple entries. Since +all the variables are tuples of size one too, the following rules apply to any +lambda call:

+
    +
  • +

    Given a lambda call f(a:a_t)->(_:r_t) with defined call and return types. + Iterate and pick all the lambda definitions f(x)->(y) that satisfy x does + a_t and y does r_t using the previously explained lambda checks.

    +
  • +
  • +

    If the r_t is unknown at call time, use only the call arguments x does + a_t. Check that all the matching lambdas have the same defined return type. + Otherwise a compile error is generated indicating that the type can not be + infered.

    +
  • +
  • +

    If the list is empty, generate a compile error (no possible lambda to call).

    +
  • +
  • +

    Once a list of ordered modules is found, evaluate the where COND. COND + can include inputs, self, and outputs. If a COND is comptime true (no + COND is the same as true), stop selecting additional modules. If COND + is comptime false remove from the list and continue. All the selected + modules will be executed, but the output will be selected based on priority + order based on the COND result at runtime.

    +
  • +
  • +

    If the list has more than one entry, and any of them is a proc, generate a + compile error. Dynamic dispatch only works with functions fun.

    +
  • +
+

If the where COND is not compile time there must be a where true condition +to catch the default behavior.

+

The previous rules imply that Pyrope has some type of dynamic dispatch. The +types for the inputs and outputs must be known at compile time (static +dispatch) but the where condition may be known at run-time as long as the +lambda is immutable (fun).

+

The where condition is not considered part of the type system, but a syntax +sugar to allow several function implementations depending on some condition. +The alternative and equivalent syntax is to add all the if/else chain at +every call but this result in not so maintanable code.

+
var fun_list = fun(a,b){ a+b}
+fun_list ++= fun(a,b,c){ a+b+c }
+fun_list ++= fun(a,b,c,d){ a+b+c+d }
+
+assert fun_list.[size] == 3    // 3 lambda entries in fun_list
+
+assert fun_list(1,2) == 3
+assert fun_list(1,2,4) == 7
+assert fun_list(1,2,4,5) == 12
+assert fun_list(1,2,4,5,6) == 18 // compile error, no function with 5 args
+
+
+fun_list ++= fun(a,b){ 100}
+assert fun_list(1,2) == 3
+
+fun_list = fun(a,b){ 200} ++ fun_list
+assert fun_list(1,2) == 200
+
+

For untyped named argument calls:

+
var f1 = fun(a,b){ a+b+100 }
+  f1 ++= fun(x,y){ x+y+200 }
+
+assert f1(a=1,b=2) == 103
+assert f1(x=1,y=2) == 203
+assert f1(  1,  2) == 103  // first in list
+
+

For typed calls:

+
var fo = fun(a:int,b:string)->(_:bool)  { true    }
+  fo ++= fun(a:int,b:int   )->(_:bool)  { false   }
+  fo ++= fun(a:int,b:int   )->(_:string){ "hello" }
+
+let a = fo(3,hello)
+assert a == true
+
+let b = fo(3,300)        // first in list return bool
+assert b == false
+
+let c:int = fo(3,300)    // compile error, no lambda fulfills constrains
+let c:string = fo(3,300)
+assert c == "hello"
+
+

For conditional argument calls:

+
var f1 = fun(a,b)      where a >  40 { b+100    }
+      ++ fun(a,b)->(x) where x > 300 { b+200    } // output x
+      ++ fun(a,b)->(a) where a >  20 { b+300    } // input a
+      ++ fun(a,b)->(x) where x >  10 { b+400    } // output x
+      ++ fun(a,b)                    { a+b+1000 } // default
+
+var fun_manual = fun(a,b){  // equivalent but not as maintenable
+  if a>40 {
+    return b+100
+  }
+  let x = b + 200
+  if x>300 {
+    return (x=x)
+  }
+  if a>20 {
+    return b+300
+  }
+  let tmp = a + b
+  if tmp >10 {
+    return (a=tmp)
+  }
+  return a+b+1000
+}
+
+test "check equiv" {
+  for a in -100..=100 {
+    for b in -100..=100 {
+      assert f1(a,b) == fun_manual(a,b)
+    }
+  }
+}
+
+

Parametric polymorphism

+

Add-hoc polymorphism overloads a function, and parametric polymorphism allows to +parametrize types based on arguments.

+
let Param_type = fun(a) { return (xx:a = _) }
+
+let x:Param_type(string) = (xx="hello")
+let x:Param_type(int)    = (xx=130)
+
+

Summary polymorphism

+

Subtype polymorphism: A subtype provides functionality/api for another super type. +

let Animal = (
+  ,speak:fun(self) = _
+)
+let Cat: Animal = (
+  ,speak = fun(self) { puts "meaow" }
+)
+let Bird: Animal = (
+  ,speak = fun(self) { puts "pio pio" }
+)
+

+

Parametric polymorphism: Same function works for many types +

let smallest = fun(...a) {
+  let x = a[0]
+  for i in a[1..] {
+    x = i when i < x
+  }
+  return x
+}
+

+

Ad-hoc polymorphism: capacity to overload the same lambda name with different types. +

let speak = fun(a:Bird) { puts "pio pio"  } 
+         ++ fun(a:Cat) { puts "meaow" }
+

+

Coercion polymorphism: Capacity to cast a type to another +

let Type1 = (
+  ,setter = fun(ref self, a:int) {  }
+)
+let a:Type1 = 33
+

+

Traits and mixin

+

There is no object inheritance in Pyrope, but tuples allow to build mixin and +composition.

+

A mixin is when an object or class can add methods and the parent object can +access them. In several languages, there are different constructs to build them +(E.g: an include inside a class in Ruby). Since Pyrope tuples are not +immutable, new methods can be added like in mixin.

+
let Say_mixin = (
+  ,say = fun(s) { puts s }
+)
+
+let Say_hi_mixin = (
+  ,say_hi  = fun() {self.say("hi {}", self.name) }
+  ,say_bye = fun() {self.say("bye {}", self.name) }
+)
+
+let User = (
+  ,name:string = _
+  ,setter = proc(ref self, n:string) { self.name = n }
+)
+
+let Mixing_all = Say_mixin ++ Say_hi_mixin ++ User
+
+var a:Mixing_all="Julius Caesar"
+a.say_hi()
+
+

Mixin is very expressive by allowing redefining methods. If two tuples have the +same field a tuple, the concatenated operator (++) will create an entry with +two or more sub-entries. This is likely an error with basic types but useful to +handle explicit method overload.

+

In a way, the concatenate just adds methods from two tuples to create a new +tuple. In programming languages with object-oriented programming (OOP), there +are many keywords (virtual, final, override, static...) to constrain +how methods can be updated/changed. In Pyrope, the let and var keywords can +be added to any tuple field. The let makes the entry immutable when applied +to a method, it behaves like a final keyword in most languages.

+

There are also two ways to concatenate tuples in Pyrope. t1 ++ t2 and +(...t1, ...t2):

+
    +
  • +

    t1 ++ t2 concatenates each field in both tuples. A compile error is + generated if t1 field is a let with a defined value, and t2 has also + the same defined field.

    +
  • +
  • +

    (...t1, ...t2) inserts in-place, triggers a compile error if the same + public field appears in both tuples and it is defined in both. private + fields are privatized and hence do not trigger overload failure.

    +
  • +
+
let Int1 = (
+  ,var counter:int:[private] = 0
+  ,add = proc(ref self, v) { self.counter += v }
+  ,get = fun(self) -> (_:int) { self.counter }
+  ,api_pending: proc(ref self, x:int) -> (o:string) = _
+)
+
+let Int2 = (
+  ,var counter:int:[private] = 0
+  ,accumulate = proc(ref self, v) { self.counter += v ; return self.counter }
+  ,api_pending:proc(ref self, x:string) -> (o:string) = _
+)
+
+let Combined = (...Int1, ...Int2
+  ,api_pending = proc(ref self, x:int) -> (o:string) {
+    self.add(x)
+    string(self.accumulate(self.get()))
+  }
+)
+
+

It is also important to notice that when one of the tuples as an entry, it can +have an undefined value (nil or 0sb?). If the entry value is undefined, +neither concatenate (++) or in-place insert (...) trigger a compile error. +This is quite useful for defining interfaces because the default value for a +function is nil.

+
let Interface = (
+  ,let add:fun(ref self, x) = _ // nil or undefined method
+  ,let sub = fun(ref self,x ) { self.add(-x) }
+)
+
+Interface.add(3)                // compile error, undefined method
+
+let My_obj = (
+  ,val1:u8 = 0
+  ,let add = fun(ref self, x) { self.val += x }
+) ++ Interface                  // OK, but not recommended
+
+let My_obj2 = (
+  ,...Interface                 // recommended
+  ,val1:u8 = 0
+  ,let add = fun(ref self, x) { self.val += x }
+)
+cassert My_obj equals My_obj2   // same behavioir no defined overlap fiels
+
+let xx:My_obj = _               // default initialization
+
+cassert xx.val1 == 0
+xx.add(3)
+cassert xx.val1 == 3
+xx.sub(2)
+cassert xx.val1 == 1
+
+

Pyrope does not directly check that all the undefined methods are implemented, +but this will trigger a compile error whenever the undefined method is used. +This is different from most static type languages, but a bit closer to +dynamically typed languages. The difference is that the check is at compile +time, but an error happens ONLY if the method is used anywhere in the +instantiated project.

+

To build tuples that implement the functionality of other tuples, the recommended +technique is to use the in-place operator. It checks that there is no defined overlap +between both tuples.

+

An issue with in-place operator is when more than one tuple has the setter +method. If the tuples are concatenated with ... and error is triggered, if +the tuples are concatenated with ++ it does not check if methods overlap. +Neither is the expected solution for a mixin.

+

The solution is to remove fields from the in-place concatenation and to +explicitly create the new methods with some support method.

+
let exclude = fun(o,...a) {
+  let new_tup = ()
+  for (key,idx,e) in zip(o.keys(),o.enumerate()) {
+    // create single tupe and append to preserve key and position order
+    let sing_tup = ()
+    sing_tup[key] = e
+    new_tup ++= sing_tup unless key in o
+  }
+  new_tup
+}
+
+let Shape = (
+  ,name:string = _
+  ,area:fun (self )->(_:i32)  = _            // undefined 
+  ,increase_size:proc(ref self, x:i12) = _  // undefined 
+
+  ,setter=proc(ref self, name ) { self.name = name } // implemented, use =
+  ,say_name=fun(self) { puts "name:{}", name }
+)
+
+let Circle = (
+  ,...exclude(Shape,'setter')
+
+  ,setter        = proc(ref self) { Circle.setter(this, "circle") }
+  ,increase_size = proc(ref self, x:i12) { self.rad *= x }
+  ,rad:i32       = _
+  ,area = fun(self) -> (_:i32) {
+     let pi = import("math").pi
+     return pi * self.rad * self.rad
+  }
+):Shape  // extra check that the exclude did not remove too many fields
+
+

Row type

+

Pyrope has structural typing, but also allows to infer the types. The where +statement can be used to implement some functionality that resembles the row +type inference. The where clause is followed by a list of comma separated +conditions that must evaluate true for the function to be valid.

+
let rotate = fun(a) where a has 'x', a has 'y' and_then a.y!=30 {
+  var r = a
+  r.x = a.y
+  r.y = a.x
+  return r
+}
+
+

The previous rotate function is difficult to implement with a traditional +structural typing.

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyrope/08-memories/index.html b/pyrope/08-memories/index.html new file mode 100644 index 0000000..5d96d57 --- /dev/null +++ b/pyrope/08-memories/index.html @@ -0,0 +1,1349 @@ + + + + + + + + + + + + + + + + + + + + + + Memories - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Memories

+

A significant effort of hardware design revolves around memories. Unlike Von +Neumann models, memories must be explicitly managed. Some list of concerns +when designing memories in ASIC/FPGAs:

+
    +
  • Reads and Writes may have different number of cycles to take effect
  • +
  • Reset does not initialize memory contents
  • +
  • There may not be data forwarding if a read and a write happen in the same cycle
  • +
  • ASIC memories come from memory compilers that require custom setup pins and connections
  • +
  • FPGA memories tend to have their own set of constraints too
  • +
  • Logic around memories like BIST has to be added before fabrication
  • +
+

This constrains the language, it is difficult to have a typical vector/memory +provided by the language that handles all these cases. Instead, the complex +memories are managed by the Pyrope standard library.

+

The flow directly supports arrays/memories in two ways:

+
    +
  • Async memories or arrays
  • +
  • RTL instantiation
  • +
+

Async memories or arrays

+

Asynchronous memories, async memories for short, have the same Pyrope tuple +interface. The difference between tuples/arrays and async memories is that the +async memories preserve the array contents across cycles. In contrast, the array +contents are cleared at the end of each cycle.

+

In Pyrope, an async memory has one cycle to write a value and 0 cycles to read. +The memory has forwarding by default, which behaves like a 0 cycle +read/write. From a non-hardware programmer, the default memory looks like an array with +persistence across cycles.

+

Pyrope async memories behave like what a "traditional software programmer" will +expect in an array. This means that values are initialized and there is +forwarding enabled. This is not what a "traditional hardware programmer" will expect. +In languages like CHISEL there is no forwarding or initialization. In Pyrope is +possible to have different options of async memories, but those should use the +RTL interface.

+

The async memories behave like tuples/arrays but there is a small difference, +the persistence of state between clock cycles. To be persistent across clock +cycles, this is achieved with a reg declaration. When a variable is declared +with var the contents are lost at the end of the cycle, when declared with +reg the contents are preserved across cycles.

+

In most cases, the arrays and async memories can be inferred automatically. The +maximum/minimum value on the index effectively sets the size and the default +initialization is zero.

+
reg mem:[] = 0
+mem[3]   = something // async memory
+var array:[] = _
+array[3] = something // array no cross cycles persistence
+
+
var index:u7 = _
+var index2:u6 = _
+
+array[index] = something
+some_result  = array[index2+3]
+
+

In the previous example, the compiler infers that the bundle at most has 127 entries.

+

There are several constructs to declare arrays or async memories:

+
reg mem1:[16]i8 = 3   // mem 16bit memory initialized to 3 with type i8
+reg mem2:[16]i8 = _   // mem 16bit memory initialized to 0 with type i8
+var mem3:[] = 0sb?        // array infer size and type, 0sb? initialized
+var mem4:[13] = 0         // array 13 entries size, initialized to zero
+
+

Pyrope allows slicing of bundles and hence arrays.

+
x1 = array[first..<last]  // from first to last, last not included
+x2 = array[first..=last]  // from first to last, last included
+x3 = array[first..+size]  // from first to first+size, first+size. not included
+
+

Since bundles are multi-dimensional, arrays or async memories are multi-dimensional too.

+
a[3][4] = 1
+
+var b:[4][8]u8 = 13
+
+assert b[2][7] == 13
+assert b[2][10]      // compile error, '10' is out of bound access for 'b[2]'
+
+

It is possible to initialize the async memory with an array. The initialization +of async memories happens whenever reset is set on the system. A key difference +between arrays (no clock) and memories is that arrays initialization value must +be comptime while memories and reg can have a sequence of statements to +generate a reset value.

+
+
+
+
var mem1:[4][8]u5 = 0
+var reset_value:[3][8]u5:[comptime] = _ // only used during reset
+for i in 0..<3 {
+  for j in 0..<8 {
+    reset_value[i][j] = j
+  }
+}
+reg mem2 = reset_value   // infer async mem u5[3][8]
+
+
+
+
var mem = ( 
+  ,(u5(0), u5(0), u5(0), u5(0), u5(0), u5(0), u5(0), u5(0))
+  ,(u5(0), u5(0), u5(0), u5(0), u5(0), u5(0), u5(0), u5(0))
+  ,(u5(0), u5(0), u5(0), u5(0), u5(0), u5(0), u5(0), u5(0))
+  ,(u5(0), u5(0), u5(0), u5(0), u5(0), u5(0), u5(0), u5(0))
+)
+reg mem2 = ( 
+  ,(u5(0), u5(1), u5(2), u5(3), u5(4), u5(5), u5(6), u5(7))
+  ,(u5(0), u5(1), u5(2), u5(3), u5(4), u5(5), u5(6), u5(7))
+  ,(u5(0), u5(1), u5(2), u5(3), u5(4), u5(5), u5(6), u5(7))
+)
+
+
+
+
+

Sync memories

+

Pyrope asynchronous memories provide the result of the read address and update +their contents on the same cycle. This means that traditional SRAM arrays can +not be directly used. Most SRAM arrays either flop the inputs or flop the +outputs (sense amplifiers). This document calls synchronous memories the +memories that either has a flop input or an output.

+

There are two ways in Pyrope to instantiate more traditional synchronous +memories. Either use async memories with flopped inputs/outputs or do a +direct RTL instantiation.

+

Flop the inputs or outputs

+

When either the inputs or the output of the asynchronous memory access is +directly connected to a flop, the flow can recognize the memory as asynchronous memory. A further constrain is that only single dimension memories. +Multi-dimensional memories or memories with partial updates need to use the +RTL instantiation.

+

To illustrate the point of simple single dimensional synchronous memories, this +is a typical decode stage from an in-order CPU:

+
+
+
+
reg rf:[32]i64 = 0sb?   // random initialized
+
+reg a:(addr1:u5, addr2:u5) = (0,0)
+
+data_rs1 = rf[a.addr1]
+data_rs2 = rf[a.addr2]
+
+a = (insn[8..=11], insn[0..=4])
+
+
+
+
var rf:[32]i64 = 0sb?
+
+reg a:(data1:i64, data2:i64) = _
+
+data_rs1 = a.data1
+data_rs2 = a.data2
+
+a = (rf[insn[8..=11]], rf[insn[0..=4]])
+
+
+
+
+

RTL instantiation

+

There are several constraints and additional options to synchronous memories +that the async memory interface can not provide: multi-dimension, partial updates, +negative edge clock...

+

Pyrope allows for a direct call to LiveHD cells with the RTL instantiation, as +such that memories can be created directly.

+
// A 2rd+1wr memory (RF type)
+
+mem.addr    = (raddr0, raddr1, wraddr)
+mem.bits    = 4
+mem.size    = 16
+mem.clock   = my_clock
+mem.din     = (0, 0, din0)
+mem.enable  = (1, 1, we0)
+
+mem.fwd     = false
+mem.latency = (1, 1, 1)
+mem.wensize = 1 // we bit (no write mask)
+mem.rdport  = (-1,1,0) // 0 WR, !=0 -> RD
+
+res =#[..] __memory(mem)
+
+q0 = res.0
+q1 = res.1
+
+

The previous code directly instantiates a memory and passes the configuration.

+

Multi cycle memories are pipelined elements, and using them requires the =#[..] assignment +and the same rules as pipeline flops apply (See pipelining).

+

Multidimensional arrays

+

Pyrope supports multi-dimensional arrays, it is possible to slice the array by +dimension. The entries are in a row-major order.

+
var d2:[2][2] = ((1,2),(3,4))
+assert d2[0][0] == 1 and d2[0][1] == 2 and d2[1][0] == 3 and d2[1][1] == 4
+
+assert d2[0] == (1,2) and d2[1] == (2,3)
+
+

The for iterator goes over each entry of the bundle/array. If a matrix, it +does in row-major order. This allows building a simple function to flatten +multi-dimensional arrays.

+
let flatten = fun(...arr) {
+  var res = 0
+  for i in arr {
+    res ++= i
+  }
+  return res
+}
+
+assert flatten(d2) == (1,2,3,4)
+assert flatten((((1),2),3),4) == (1,2,3,4)
+
+

Array index

+

Array index by default are unsigned integers, but the index can be constrained +with tuples or by requiring an enumerate.

+
var x1:[2]u3 = (0,1)
+assert x1[0] == 0 and x1[1] == 1
+
+var X=enum(
+  ,t1 = 0 // sequential enum, not one hot enum (explicit assign)
+  ,t2
+  ,t3
+)
+
+var x2:[X]u3 = _
+x2[X.t1] = 0
+x2[X.t2] = 1
+x2[0]              // compile error, only enum index
+
+var x3:[-8..<7]u3 = _  // accept signed values
+
+var x4:[100..<132]u3 = _
+
+assert x4[100] == 0
+assert x4[3]       // compile error, out of bounds index
+
+

Reset and initialization

+

Like the let and var statements, reg statements require an initialization +value. While let/var initialize every cycle, the reg initialization is the +value to set during reset.

+

Like in let/var cases, the reset/initialization value can use the traditional +Verilog uninitialized (0sb?) contents. The Pyrope semantics for any bit with +? value is to respect arithmetic Verilog semantics at compile time, but to +randomly generate a zero/ones for each simulation. As a result assertions can +fail with unknowns.

+
reg r_ver = 0sb?
+
+reg r = _
+var v = _
+
+assert v == 0 and r == 0
+
+assert !(r_ver != 0)    // it will randomly fail
+assert !(r_ver == 0)    // it will randomly fail
+assert !(r_ver != 0sb?) // it will randomly fail
+assert !(r_ver == 0sb?) // it will randomly fail
+
+

The reset for arrays may take several cycles to take effect, this can lead to +unexpected results during the reset period. Memories and registers are randomly +initialized before reset during simulation. There is no guarantee of zero +initialization before reset.

+
var arr:[] = (0,1,2,3,4,5,6,7)
+
+always assert arr[0] == 0 and arr[7] == 7  // may FAIL during reset
+
+reg mem:[] = (0,1,2,3,4,5,6,7)
+
+always assert mem[7] == 7                  // may FAIL during reset
+always assert mem[7] == 7 unless mem.reset // OK
+assert mem[7] == 7                         // OK, not checked during reset
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyrope/09-stdlib/index.html b/pyrope/09-stdlib/index.html new file mode 100644 index 0000000..fccb5d5 --- /dev/null +++ b/pyrope/09-stdlib/index.html @@ -0,0 +1,940 @@ + + + + + + + + + + + + + + + + + + + + + + Pyrope std lib - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Pyrope std lib

+

Like most languages, a standard library provides some common functionality around.

+

The standard library provides methods for the basic types (Number, String, Boolean) and utility code like fifos. +The utils must be imported but the basic types are imported by default.

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyrope/10-internals/index.html b/pyrope/10-internals/index.html new file mode 100644 index 0000000..b5dbe84 --- /dev/null +++ b/pyrope/10-internals/index.html @@ -0,0 +1,2135 @@ + + + + + + + + + + + + + + + + + + + + + + Internals - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+ +
+ + + +
+
+ + + + + + + +

Internals

+

This section of the document provides a series of disconnected topics about the +compiler internals that affects semantics.

+

Tuple operations

+

There are 3 basic operations/checks with tuples that affect many other +operations: a in b, a does b, and lambda call rules.

+
    +
  • +

    a in b allows to work when b is a name/unnamed tuple even when a is named.

    +
  • +
  • +

    a does b requires b to be named consistent with names in a.

    +
  • +
  • +

    lambda call matches the arguments with the definition in a third different set of rules.

    +
  • +
+
cassert (a=1) in (1,a=1,3)
+cassert (a=1) !does (1,a=1,3)
+
+let f = fun(a) { puts "{}",a }
+let g = fun(long, short) { puts "{}",long }
+
+f(a=1)             // OK
+f(1)               // OK
+
+g(long=1, short=1) // OK
+g(1,1)             // compile error
+let long=1
+g(long, short=1)   // OK
+let short=1
+g(long, short)     // OK
+
+

Operators like a == b, a case b, a equals b, ... built on top of the previous functionality.

+

Determinism

+

Pyrope is designed to be deterministic. This means that the result is always +the same for synthesis. Simulation is also deterministic unless the random seed +is changed or non-Pyrope (C++) calls to procedures add non-determinism.

+

Expressions are deterministic because procedures have an explicit order in +Pyrope. Only functions have a non-explicit order, but functions are pure +without side-effects. puts can be called non-deterministically but the result +is buffered and ordered at the end of the cycle to be deterministic.

+

The only source of non-determinism is non-Pyrope (C++) calls from procedures +executed at different pipeline stages. The pipeline stages could be executed in +any order, it is just that the same order must be repeated deterministically +during simulation. The non-Pyrope calls must be ::[comptime] to affect +synthesis. So the synthesis is deterministic, but the testing like cosimulation +may not.

+

The same non-Pyrope calls also represent a problem for the compiler +optimizations. During the setup phase, several non-Pyrope can exist like +reading the configuration file. If the non-Pyrope calls are not deterministic, +the result could be a non-deterministic setup phase.

+

The idea is that the non-Pyrope API is also divided in 2 categories: +functions and procedures. A function can be called many times without +non-Pyrope side-effects. Pyrope guarantees that the procedures are called in +the same order given a source code, but does not guarantee the call order. This +guarantee order slowdowns simulation and elaboration. Whenever possible, use +functions instead of procedures for compilation speed reasons.

+

Import

+

import statement allows for circular dependencies of files, but not of +variables. This means that if there is no dependency (a imports b), just +running a before b is enough. If there is a dependency (a imports b and b +imports a) a multiple compiler pass is proposed, but other solutions are +allowed as long as it can handle not true circular dependences.

+

The solution to this problem is to pick an order, and import at least three +times the files involved in the cyclic dependency. The files involved in the +cylic dependency are alphabetically sorted and called three times: (1) a +import b, then b import a; (2) a import b and b import a; (3) a import +b and b import a. Only the last import chain can perform procedure proc +calls (Pyrope and non-Pyrope) and puts/debug statements.

+

If the result of the last two imports has the same variables, the import has +"converged", otherwise a compile error is generated. This multi-pass solution +does not address all the false paths, but the common case of having two sets of +independent variables. This should address most of the Pyrope cases because +there is no concept of "reference/pointer" which is a common source of +dependences.

+

Register reference

+

Register reference (regfef) can create a dependence update between files, but this is +not a source of non-determinism because only one file can perform updates for +the register din pin, and all the updated register can only read the register +q pin.

+

Dealing with unknowns

+

Pyrope tries to be compatible with synthesizable Verilog but not equivalent. As +such it must handle/understand unknowns. Compatible does not mean that it will +generate the same ? bits as Verilog, but that it will not generate an unknown +when Verilog has known. It is allowed to generate a 0 or a 1 when the +Verilog logical equivalence check generates an ?.

+

An example of different behavior is that Verilog semantics state 0 * 0sb? is +0sb? while most programmers would expect a zero.

+

The previous definition of compatibility could allow the Pyrope compiler to +randomly replace all the unknowns by 0 or 1 when doing internal compiler +passes. This is not done at compile time to keep determinism, but simulation +time should randomly pick 0/1 for unknown bits.

+

The issue is that the most likely source of having unknowns in operations is +either during reset or due to a bug on how to handle non initialized structures +like memories.

+

The compiler internal transformations use a 3-state logic that includes 0, +1, and ? for each bit. Any register or memory initialized with unknowns +will generate a Verilog with the same initialization.

+

The compiler internals only needs to deal with unknowns during the copy +propagation or peephole optimizations. The compile goes through 2 phases: LNAST +and Lgraph.

+

In the compiler passes, we have the following semantics:

+
    +
  • +

    In Pyrope, there are 3 array-like structures: non-persistent arrays, register + arrays, and custom RTL memories. Verilog and CHISEL memories get translated + to custom RTL memories. Non-persistent Verilog/CHISEL get translated to arrays. + In Verilog, the semantics is that an out of bounds access generates unknowns. In + CHISEL, the Vec is that an out of bound access uses the first index + of the array. A CHISEL out of bound memory is an unknown like in Verilog. These + are the semantics applied by the compiler optimization/transformations:

    +
      +
    • +

      Custom RTL memories do not allow value propagation across the array, only + across non-persistent arrays, or register arrays explicitly marked with + retime=true.

      +
    • +
    • +

      An out of bound RTL address drops the unused index bits. For non-power of + two arrays, out of bounds access triggers a compile error. The code must + be fixed to avoid access. An if addr < mem_size { ... mem[addr] ... } + tends to be enough. This is to guarantee that passes like Verilog and + CHISEL have the same semantics, and trigger likely bugs in Pyrope code.

      +
    • +
    • +

      An index with unknowns does not perform value propagation.

      +
    • +
    +
  • +
  • +

    Shifts, additions and substractions propagate unknowns at computation. E.g: + 0b11?0 + 0b1 is 0b11?1, 0b1?0 >> 1 is 0b1?.

    +
  • +
  • +

    Other arithmetic are more conservative. When an input is unknown, the result + is unknown only respecting the sign when possible. E.g: 0b1?0? * -1 is + 0sb1?.

    +
  • +
  • +

    Logic operations behave like Verilog. 0b000111??? | 0b01?01?01? is + 0b01?111?1?.

    +
  • +
  • +

    Equality comparisons (== and !=) use unknowns, this means that at compile + time 0b1? != 0b10. Comparisons is consistent with the equivalent logic + operations a == b is the same as (a ^ b) == -1.

    +
  • +
  • +

    Other comparisons (<=, <, >, >=) return true if the comparison is + true for each possible unknown bit.

    +
  • +
  • +

    match statement and unique if will trigger a compile error if the unknown + semantics during compiler passes can trigger 2 options simultaneously. The + solution is to change to a sequence of ifs or change the code to guarantee + no unknowns.

    +
  • +
  • +

    if statement without unique logical expressions that have an unknown + (single bit) are a source of confusion. In Verilog, it depends on the + compiler options. A classic compiler will generate ? in all the updated + variables. A Tmerge option will propagate ? only if both sides can + generate a different value. The LNAST optimization pass will behave like the + Tmerge when the if/mux control has unknowns:

    +
      +
    • +

      If all the paths have the same constant value, the if is useless and + the correct value will be used.

      +
    • +
    • +

      If any path has a different constant value, the generated result bits will + have unknowns if the source bits are different or unknown.

      +
    • +
    • +

      If any paths are not constant, there is no LNAST optimization. Further + Lgraph optimizations could optimize if all the mux generated values are + proved to be the same.

      +
    • +
    +
  • +
  • +

    The for loops are expanded, if the expression in the for is unknown, a + compile error is generated.

    +
  • +
  • +

    The while loops are also expanded, if the condition on the while loop has + unknowns a compile error is generated.

    +
  • +
+

At the end of the LNAST generation, a Lgraph is created. Only the registers and +memory initialization are allowed to have unknowns in Lgraph. Any invalid +(nil) assigned to an output or register triggers a compile error. Any unknown constant +bit is translated preserved (0b10?).

+

The semantics on the generated simulator are similar to CHISEL, any unknowns +are randomly translated to 0 or 1 at initialization.

+

Optimize directive

+

The optimize directive is like an assert but it also allows compiler +optimizations. In a way, it is a safer version of Verilog ?. Unlike other +languages like C++23, Pyrope optimize verifies at simulation time that the +optimize is correct. This means that the optimize is checked like an +assert but it allows the compiler to optimize based on the condition. +asserts do not trigger optimizations because their check can be disabled at +simulation time, and hence create mismatches between simulation and synthesis +if the compiler optimized over assertions.

+
+
+
+
always_comb begin // one hot mux
+  case (sel)
+    3b001 : f=i0;
+    3b010 : f=i1;
+    3b100 : f=i2;
+    default: f=2b??;
+  endcase
+end
+
+
+
+
optimize sel==1 or sel==2 or sel==4 // not needed. match sets it
+match sel {
+  == 0b001 { f = i0 }
+  == 0b010 { f = i2 }
+  == 0b100 { f = i3 }
+}
+
+
+
+
f = (sel[0] & i0)
+  | (sel[1] & i1)
+  | (sel[2] & i2)
+
+
+
+
+

Optimize allows more freedom, without dangerous Verilog x-optimizations:

+
+
+
+
if (a == 0) begin
+   assert(false);
+   out = '?;
+end else if (1 + a) == 1 begin // always false
+   out = 1;
+end else begin
+   out = 3;
+end
+
+array[3] = '?; // entry 3 will not be used
+// array = (1,2,3,'?,5,6,7,8)
+res = array[b]
+
+
+
+
optimize a != 0
+
+
+if (1 + a) != 1 { // always false
+  out = 1
+}else{
+  out = 3
+}
+
+optimize b != 3
+// array = (1,2,3,4,5,6,7,8)
+res = array[b]
+
+
+
+
+

Unknown no optimization

+

In Verilog, unknowns can trigger synthesis optimizations. This is not the case +in Pyrope. Each unknown bit (?) can result in random 0/1 at simulation time, but it will +not trigger optimizations. The optimize statement should be use for such behavior.

+
assert cond==3     // Not cassert or optimize, so no optimized
+var x1 = 0sb?
+
+if cond == 3 {
+  x1 = 1
+}
+assert x1==1 // still not optimized (cassert fails)
+cassert !x1.[comptime]
+
+var x2 = 0sb?
+optimize cond==3
+if cond == 3 {
+  x2 = 1
+}
+cassert x2==1
+cassert x2.[comptime]
+
+

LNAST optimization

+

The compiler has three IR levels: The high level is the parse AST, the +mid-level is the LNAST, and the low level is the Lgraph. This section explains +the main steps in the LNAST optimizations/transformations before performing +type synthesis and generating the lower level Lgraph. This is a minimum of +optimizations without them several type conflicts would be affected.

+

Unlike the parse AST, the LNAST nodes are guaranteed to be in topological +order. This means that a single pass that visits the children first (deep +first) is sufficient.

+

The work can be performed as a single "global" topographical pass starting from +the root/top, where each LNAST node performs these operations during traversal +depending on the LNAST node:

+
    +
  • +

    If the node allows, perform these node input optimization first:

    +
      +
    • +

      constant folding for existing node, also be performed as instruction + combining proceeds

      +
    • +
    • +

      instruction combining from sources only for same type but not beyond 128 + n-ary nodes. This step subsumes constant propagation and copy + propagation. E.g: a+(x-3)+1 becomes a+x-3+1

      +
    • +
    • +

      create a canonical order by sorting the inputs by name/constant. E.g: + + 2 a b. This simplifies the following steps but it is not needed for + semantics. Most commutative gates (add/sub/and/or/...) will have a + single constant as a result.

      +
    • +
    • +

      trivial simplification with constants for existing node, also performed + as instruction combining proceeds. E.g.: a+0 == a, a or true + == true ...

      +
    • +
    • +

      trivial identity simplification for existing node, also performed as + instruction combining proceeds. E.g: a^a == a, a-a=0 ...

      +
    • +
    +
  • +
  • +

    If the node is a ::[comptime] trigger a compile error unless all the inputs are + constant

    +
      +
    • cassert should satisfy the condition or a compile error is generated
    • +
    +
  • +
  • +

    If the node is a loop (for/while) that has at least one iteration expand + the loop. This is an iterative process because the loop exit condition may + depend on the loop body or functions called inside. After the loop + expansions, no for, while, break, last, continue statement + exists.

    +
  • +
  • +

    If the node is a function call, iterate over the possible polymorphic calls. + Call the first call that is valid (input types). Call the function and pass + all the input constants needed. This requires specializing the function + by input constants and types. If no call matches a valid type trigger a + compile error

    +
  • +
  • +

    Delete unreachable statements (if false { delete his }, delete this when false, ...)

    +
  • +
  • +

    Compute these steps that may be needed in future steps:

    +
      +
    • +

      Perform the "Mark" phase typical in dead-code-elimination (DCE) so that + dead nodes are not generated when creating the Lgraph.

      +
    • +
    • +

      Update the tuple field in the Symbol Table

      +
    • +
    • +

      Track the array accesses for memory/array Lgraph generation

      +
    • +
    +
  • +
+

Type synthesis

+

The type synthesis and check are performed during the LNAST pass. Pyrope uses a +structural type system with global type inference.

+

The type inference should be performed as the same time as the LNAST +optimization traverses the tree. It can not be a separate pass because there +can be interactions between the LNAST optimization and the Type synthesis. +These are the additional checks performed for type synthesis:

+
    +
  • +

    If the node does type checks (equals, does) compute the outcome and + perform copy propagation. The result of this step is that the compiler is + effectively doing flow-type inference. All the types must be resolved before. + If the equals/does was in a if condition, the control is decided at + compile time.

    +
  • +
  • +

    If the node reads bitwidth, replace the node with the computer Bitwidth value + (max, min, ubits, and/or sbits)

    +
      +
    • Compute the max/min for the output[s] using the bitwidth algorithm. + Update the symbol table with the range. This is only needed because some + code like polymorphism functions can read the bits.
    • +
    +
  • +
  • +

    If the node is a conditional (if/match), the pass performs narrowing1.

    +
      +
    • +

      When the expression has these possible syntax v >= y, v > + y or the reciprocals, restrict the Bitwidth. E.g: in the v < y + restricts the v.max = y.min-1 ; y.min = v.min + 1

      +
    • +
    • +

      When the expression is an equality format eq [and eq]* or eq [or + eq]* like v1 == z1 and v2 != z2, create a v1=z1 and v2=z2 in the + corresponding path. This will help bitwidth and copy propagation. + Complicated mixes of and/or have no path optimization

      +
    • +
    • +

      When the expression is a single variable a or !a, set the variable + true and false in both paths

      +
    • +
    +
  • +
+

No previous transformation could break the type checks. This means that the +copy propagation, and final lgraph translation the type checks are respected.

+
    +
  • +

    All the entries on the comparator have the same type (LHS equals RHS)

    +
  • +
  • +

    Left side assignments respect the assigned type (LHS does RHS)

    +
  • +
  • +

    Any explicit type on any expression should respect the type (var does type)

    +
  • +
+

The previous algorithm describes the semantics, the implementation may be +different. For example, to parallelize the algorithm, each LNAST tree can be +processed locally, and then a global top pass is performed.

+

Programming warts

+

In programming languages, warts are small code fragments that have unexpected +or not great behavior. Every language has its warts. This section tries to list +the Pyrope main ones to address and learn more about the language.

+

Shadowing

+

Pyrope does not allow shadowing, but you can still have it with tuples. To +access the tuple field, the self.field is always required. This avoid the +problem of true shadowing.

+
let f1 = fun() { 1 }
+
+let tup = (
+  ,f1 = fun() { 2 }
+
+  ,code = fun() {
+     assert self.f1() == 2
+     assert f1() == 1
+  }
+)
+
+

Closures

+

Closures capture extra state or inputs at definition. The capture variables are +always immutable let no matter the outter scope definition. Therefore, +capture variables behave like passed by value, not reference.

+

One important thing is 'when' does the capture happens. Pyrope follows the +model of most languages like C++ that captures at lambda definition, not lambda +execution.

+
+
+
+
var x_s = 10
+
+let call_captured = fun[x_s]() {
+  return fun[x_s]() {
+    assert x_s == 10
+    return x_s
+  }
+}
+
+test "capture test" {
+  let tst = fun() {
+    var x_s = 20   // not variable shadowing because fun scope
+
+    let x1 = call_captured()
+    assert x1 == 10
+
+    x_s = 30;
+
+    let x2 = call_captured()
+    assert x2 == 10
+  }
+  tst // call the test
+}
+
+
+
+
#include <iostream>
+
+int main() {
+
+  int x_s{ 10 };
+
+  auto call_captured{
+    [x_s]() {
+      assert(x_s == 10);
+      return x_s;
+    }
+  };
+  }
+
+  x_s = 20;
+
+  auto x1 = call_captured();
+  assert(x1==10);
+
+  x_s = 30;
+
+  auto x2 = call_captured();
+  assert(x2==10);
+}
+
+
+
+
+

Some languages like ZIG do not allow closures, but they allow structs with a lambda to +implement an equivalent functionality. It is possible in Pyrope to also create a tuple +and populate the getter. This effectively behaves as the closures. Internally, Pyrope +may do this implementation.

+
+
+
+
let j = 1
+let b = fun[j](x:i32)-> :i32 {
+  return x+j
+}
+
+assert b(1) == 2
+
+test "closure with tuple" {
+  var a: i32 = 1
+  a += 1
+
+  var addX = (
+    ,a: i32 = a                        // copy value, runtime or comptime
+    ,getter = fun(self, x: i32) {
+      return x + self.a
+    }
+  )
+
+  a += 100;
+
+  assert addX(2) == 4
+}
+
+test "plain closure" {
+  var a:i32 = 1
+  a += 1
+
+  let addX = fun[a](x: i32) { // Same behaviour as closure with tuple
+    return x + a
+  }
+
+  a += 100;
+
+  assert addX(2) == 4
+}
+
+
+
+
pub fn main() void {
+    const j = 1;
+    var b = struct{
+        fn function(x: i32) i32 {
+            return x+j;
+        }
+    }.function;
+
+    @import("std").debug.assert(b(1) == 2);
+}
+
+test "closure with runtime" {
+  var a: i32 = 1;
+  a += 1;
+
+  const addX = (struct {
+    a: i32,
+    fn call(self: @This(), x: i32) i32 {
+      return x + self.a;
+    }
+  } { .a = a }).call;
+
+  a += 100;
+
+  @import("std").debug.assert(addX(2) == 4);
+}
+
+
+
+
+

Capture values must be explicit, or no capture happens. This means that +...fun[](...)... is the same as ...fun(...)....

+
var x = 3
+
+let f1 = fun[x]()->(_:int){
+   assert x == 3
+   var x = _    // compile error. Shadow captured x
+   return 200
+}
+let f2 = fun()->(_:int){
+   var x = _    // OK, no captures 'x' variable
+   x = 100
+   return x
+}
+
+

Capture variables pass the value at capture time:

+
var x = 3
+var y = 10
+
+let fun2 = fun[y]()->(_:int){
+  y = 100              // compile error, y is immutable when captured
+  var x  = 200
+  return y + x
+}
+x = 1000
+assert fun2() == 203
+
+

Lambda arguments

+

Lambda calls happen whenever an identifer is followed by a list of expressions. +If the first expression in the list has parenthesis, it can lead to unexpected +behavior:

+
assert 0 == (0)  // OK, same as assert( 0 == (0) )
+assert (0) == 0  // compile error: (assert(0)) == 0 is an expression
+assert(0 == 0)   // OK
+
+

It is also easy to forget that parenthesis can be ommited in simple expressions, +not when ranges or tuples are involed.

+
asssert 2 in (1,2)  // compile error, not allowed to drop parenthesis
+asssert(2 in (1,2)) // OK
+
+

Multiple tuples

+

The evaluation order is always the same program order starting from the top +module. Remember that the setter method is the constructor called even when +there is no initial value set.

+
let X_t = (
+  ,i1 = (
+    ,i1_field:u32 = 1
+    ,i2_field:u32 = 2
+    ,setter = proc(ref self, a) {
+       self.i1_field = a
+    }
+  )
+  ,i2 = (
+    ,i1_field:i32 = 11
+    ,setter = proc(ref self, a) {
+       self.i1_field = a
+    }
+  )
+)
+
+var top = (
+  ,setter = proc(ref self) {
+    var x:X_t = _
+    assert x.i1.i1_field == 1
+    assert x.i1.i2_field == 2
+    assert x.i2.i1_field == 11
+
+    x.i1 = 400
+
+    assert x.i1.i1_field == 400
+    assert x.i1.i2_field == 2
+    assert x.i2.i1_field == 11
+
+    x.i2 = 1000
+
+    assert x.i1.i1_field == 400
+    assert x.i1.i2_field == 2
+    assert x.i2.i1_field == 1000
+  }
+)
+
+

If a lambda in the hierarchy does not have a setter/constructor, the program order +follows the tuple scope which is in tuple ordered asignment.

+

Unknowns

+

Pyrope respects the same semantics as Verilog with unknowns. As such, there can +be many unexpected behaviors in these cases. The difference is that in Pyrope +everything is initialized and unknowns (0sb?) can happen only when explicitly +enabled.

+

The compare respects Verilog semantics. This means that it is true if and only +if all the possible values are true, which is quite counter-intuitive behavior +for programmers not used to 4 value logic.

+
assert !(0sb? == 0)
+assert !(0sb? != 0)
+assert !(0sb? == 0sb?)
+assert !(0sb? != 0sb?)
+
+

There is no way to know at run-time if a value is unknown, but a compile trick +can work. The reason is that integers can be converted to strings in a C++ API

+
var x = 0sb10?
+let str = __to_string(x) // only works for compile time constants
+assert x == "0sb10?"
+
+

for loop

+

The for expects a tuple, and iterates over the tuple. This can lead to some +unexpected behaviour. The most strange is that ranges are always from smallest +to largest. It is not legal to do a 5..<0 range, the solution is to use a +to which creates a tuple not a range.

+
let s:string="hell"
+for (idx,i) in s.enumerate() {
+  let v = match idx {
+   == 0 { "h" }
+   == 1 { "e" }
+   == 2 { "l" }
+   == 3 { "l" }
+  }
+  assert v == i
+}
+
+let t = (1,2,3)
+for (idx,i) in t.enumerate() {
+  let v = match idx {
+   == 0 { 1 }
+   == 1 { 2 }
+   == 2 { 3 }
+  }
+  assert v == i
+}
+
+let r=2..<5
+for (idx,i) in r.enumerate() {
+  let v = match idx {
+   == 0 { 2 }
+   == 1 { 3 }
+   == 2 { 4 }
+  }
+  assert v == i
+}
+
+let r2=4..=2 step -1
+assert r2 == (4,3,2)
+for (idx,i) in r2.enumerate() {
+  let v = match idx {
+   == 0 { 4 }
+   == 1 { 3 }
+   == 2 { 2 }
+  }
+  assert v == r2[i]
+}
+
+for i in 2..<5 {
+  let ri = 2+(4-i) // reverse index
+  // 2 == (2..<5).trailing_one
+  // 4 == (2..<5).leading_one
+  let v = match idx {
+   == 0 { 4 }
+   == 1 { 3 }
+   == 2 { 2 }
+  }
+  assert v == ri
+}
+
+for (idx,i) in enumerate(123) {
+  assert i == 123 and idx==0
+}
+
+

Multiple bit selection

+

Ranges are sets, this creates potentially unexpected results in reverse for +iterators, but also in bit section:

+
let v = 0xF0
+
+assert v@[0] == 0
+assert v@[4] == 1       // unsigned output
+assert v@sext[4] == -1  // signed output
+
+assert v@[3..=4] == 0b010 == v@[3,4]
+assert v@[4..=3 step -1] == 0b010
+assert v@[4,3] == v@[3,4] == 0b010
+
+let tmp1 = (v@[4], v@[3])@[..]  // typecast from
+let tmp2 = (v@[3], v@[4])@[..]
+let tmp3 = v@[3,4]
+assert tmp1 == 0b01
+assert tmp2 == 0b100
+assert tmp3 == 0b10
+
+let tmp1s = (v@sext[4], v@sext[3])@[..]  // typecast from
+let tmp2s = (v@sext[3], v@sext[4])@[..]
+let tmp3s = v@[4,3]
+assert tmp1s == 0b01
+assert tmp2s == 0b10
+assert tmp3s == 0b10
+
+let tmp1ss = (v@sext[4], v@sext[3])@sext[..]  // typecast from
+let tmp2ss = (v@sext[3], v@sext[4])@sext[..]
+let tmp3ss = v@sext[3,4]
+assert tmp1ss == 0b01  ==  1
+assert tmp2ss == 0sb10 == -2
+assert tmp3ss == 0sb10 == -2 == v@sext[4,3]
+
+

The reason is that for multiple bit selection assumes a smaller to larger bits. +If the opposite order is needed, support functions/code must explicitly do it.

+

In Pyrope, there is no order in bit selection (xx@[0,1,2,3] == xx@[3,2,1,0]). +This is done to avoid mistakes. If a bit swap is wanted, it must be explicit.

+
let reverse = fun(x:uint)->(total:uint) {
+  for i in 0..<x.__bits {
+    total <<= 1
+    total  |= x@[i]
+  }
+}
+assert reverse(0b10110) == 0b01101
+
+

Unexpected calls

+

Passing a lambda argument with a ref does not have any side effect because +lambdas without arguments need to be explicitly called or just passed as +reference.

+
let args = fun(x) { puts "args:{}", b ; 1}
+let here = fun()  { puts "here" ; 3}
+
+let call_now   = fun(f:fun){ return f() }
+let call_defer = fun(f:fun){ return f   }
+
+let x0 = call_now(here)          // prints "here"
+let e1 = call_now(args)          // compile error, args needs arguments
+let x1 = call_defer(here)        // nothing printed
+let e2 = call_defer(args)        // compile error, args needs arguments
+assert x0  == 3                  // nothing printed
+assert x1  == 3                  // nothing printed
+
+let x2 = call_now(ref here)      // prints "here"
+let e3 = call_now(ref args)      // compile error, args needs arguments
+let x3 = call_defer(ref here)    // nothing printed
+let x4 = call_defer(ref args)    // nothing printed
+assert x2  == 3                  // nothing printed
+assert x3()  == 3                // prints "here"
+assert x3  == 3                  // compile error, explicit call needed
+assert x4  == 1                  // compile error, args needs arguments
+assert x4("xx") == 1             // prints "args:xx"
+
+

if is an expression

+

Since if, for, match are expressions, you can build some strange code:

+
if if x == 3 { true }else{ false } {
+  puts "x is 3"
+}
+
+ +

There is no -- operator in Pyrope, but there is a - which can +be followed by a negative number -3.

+
let v = (3)--3
+assert v == 6
+
+
+
+
    +
  1. +

    Narrowing is based on "ABCD: eliminating array bounds checks on-demand" + by Ras Bodik et al. 

    +
  2. +
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyrope/10b-vslang/index.html b/pyrope/10b-vslang/index.html new file mode 100644 index 0000000..c5819fa --- /dev/null +++ b/pyrope/10b-vslang/index.html @@ -0,0 +1,1342 @@ + + + + + + + + + + + + + + + + + + + + + + vs Other Languages - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

vs Other Languages

+

This section provides some snippet examples to understand the differences +between Pyrope and a different set of languages.

+

Generic non-HDL

+

Pyrope is an HDL that tries to look like a non-HDL with modern/concise syntax. +Some of the Pyrope semantics are simpler than most non-HDL because of several +features like unlimited precision, lack of pointers and issues to manage memory +do not exist in ASICs/FPGAs. These are explained in simpler HDL +constructs section.

+

There are some features in Pyrope that are non-existing in non-HDLs. +ASICs/FPGAs design leverage some features like reset, pipelining, connecting +modules that require syntax/semantics not needed in languages like Rust, C, +Java. This section lists the main hardware specific syntax.

+

reset vs cycle

+

Nearly all the programming languages have a "main" that starts execution. From +the entry point, a precise control flow is followed until an "exit" is found. +If there is no exit, the control flow eventually returns to the end of main and +an implicit exit exist when "main" finishes. There is no concept of cycle or +reset.

+

Pyrope tries to imitate non-HDLs and it has the same entry point "top" and also follows +a precise control flow from that entry point. This is what a non-hardware designer +will expect, but there is no exit/abort. The control flow will continue until +it returns to the end of the "top" or entry point.

+

The key difference is that the "top" or entry point is called every cycle. From +a hardware point of view, the whole program executes in a single clock cycle. +All the program state is lost unless preserved in register variables.

+

Those registers variables have an "initialization" step that in hardware +corresponds to a reset phase. Each register declaration assignment has reset +code only executed during reset.

+

Defer

+

Some programming languages like Zig or Odin have a defer statement. In +non-HDLs, a defer means that the statements inside the defer are executed when +the "scope" finishes. Usually, the defer statements are executed before the +function return.

+

Pyrope defers the statements not to the end of the scope but to the end of the +clock cycle. The defer delays the "write" until the end of the clock cycle, the +defer does not defer the reads, just the write or update. To read the value +from the end of the cycle an attribute variable.[defer] must be used.

+

These are constructs not existing in software but needed in hardware because it +is necessary to connect blocks. Following the control flow from the top only +allows to connect forward. Some contructs like connecting a ring require a +"backward edge". The attribute [defer] allow such type of constructs.

+
var a = 1
+var b = 2
+
+cassert a==1 and b==2
+b::[defer] = a
+cassert a==1 and b==2
+
+cassert b.[defer] == 1
+
+

Pipelining

+

Pyrope should be easier to program than non-HDLs with the exception of dealing +with cycles. While memory management tends to be the main complexity in +non-HDLs, pipelining or dealing with interaction across cycles is the main +complexity in HDLs.

+

Pyrope has several constructs to help that do not apply to non-HDL, +pipelining has most of the pipelining specific syntax.

+

C++

+

Pyrope and C++ are quite different in syntax, but some nice C++23 syntax has +similarities for Pyrope.

+
auto max_gap_count(std::vector<int> nums) {
+    std::ranges::sort(nums, std::greater{});
+    auto const diffs = nums
+        | std::views::adjacent_transform<2>(std::minus{});
+    return std::ranges::count(diffs, std::ranges::max(diffs));
+}
+
+
let max_gap_count = fun(nums) {
+  let max  = import("std").max
+  let sort = import("std").sort
+  let adjacent_transform = fun(a,num,f) {
+    var res:[] = _
+    for i in 0..<a.length step num {
+      res ++= f(a[i..+num])
+    }
+    return res
+  }
+  let count = fun(a,b) {
+    var r = 0
+    for i in a {
+      r += 1 when i == b
+    }
+    return r
+  }
+
+  return numbers
+     |> sort(fun(a,b) { a<b })
+     |> adjacent_transform(num=2, fun(a,b) { a-b } )
+     |> fun(a) { count(a, a.max) }
+}
+
+

Swift

+

There are many diffirences with Swift, but this section just highlights a couple because it helps +to understand the Pyrope semantics.

+

Protocol vs Pyrope constrains

+

Swift protocols resemble type classes. As such require consent for implementing +a functionality. Pyrope resembles C++ concepts that constraint functionality.

+
func add<T>(a:T, b:T) -> T { a + b }  // compile error
+func add<T:Numeric>(a:T, b:T) -> T { a + b }
+
+
let add = fun(a,b) { a + b }            // OK, no constrains
+let add = fun<T:int>(a:T,b:T) { a + b } // constrain both to have same type
+
+

When a protocol defines an interface, in Swift:

+
protocol Shape {
+  func name()      -> String
+  func area()      -> Float
+  func perimeter() -> Float
+}
+
+class Rectangle : Shape {  }
+class Circle    : Shape {  }
+
+func print_share_info<T:Shape>(_ s:T) {
+
+}
+
+

In Pyrope: +

let Shape = (
+  ,name:fun(self)->(_:string)    = _
+  ,area:fun(self)->(_:Float)     = _  // NOTE: Pyrope does not have float type
+  ,perimeter:fun(self)->(_:Float)= _
+)
+
+let Rectangle:(...Shape,...OtherAPI) = (...some_code_here)
+let Circle:Shape = (...some_code_here)
+
+let print_share_info = fun(s:Shape) { }
+

+

Rust

+

Rust is not an HDL, as such it has to deal with many other issues like memory. This section is just +a syntax comparison.

+

Lambda

+

In Rust, the self keyword when applied to lambda arguments can be &self, +self, &mut self. In Pyrope, there is only a self and ref self. The +equivalent of the &mut self is ref self. Pyrope does not have the +equivalent of mut self that allows to modify a copy of self.

+
pub struct AnObject {
+  v:i32
+}
+
+imp AnObject {
+  pub fn f1(&mut self) -> i32 {
+    let res = self.v;
+    self.v += 1;
+    res
+  }
+  pub fn f2(self) -> i32 {
+    self.v
+  }
+}
+
+

A Rust style Pyrope equivalent:

+
let AnObject = (
+  ,v:i32 = _
+)
+
+let f1 = proc(ref self:AnObject) -> :i32 { // unnamed output tuple
+  let res = self.v
+  self.v += 1
+  return res
+}
+let f2 = fun(self:AnObject) -> :i32 {
+  return self.v
+}
+
+

A more Pyrope style equivalent:

+
let AnObject = (
+  ,v:i32 = _
+  ,f1 = proc(ref self) -> (res:i32) {
+    res = self.v
+    self.v += 1
+  }
+  ,f2 = fun(self) -> :i32 { self.v }
+)
+
+

Typescript

+

Pyrope has a type system quite similar to Typescript, but there are significant +differences. The main is that Pyrope does not allow union types.

+

There are also difference in some semantics. For example, Typescript "foo" in +bar is equivalent to the bar has "foo" in Pyrope. Both check if entry foo +exists in the tuple bar (bar.foo). There is no Typescript equivalent to the +Pyrope "foo" in bar which checks if bar is a tuple with an entry equal to +string "foo".

+

Matlab

+

Matlab has a convenient multi-dimensional array or array initialization. It +does not require comma. E.g: a = [a b 100 c] is valid Matlab.

+

Pyrope requires commas to distinguish from multi-line statements, hence a = [a,b,100,c] +To initialize a multi-dimensional array, it follows other languages syntax, but +in Pyrope both () and [] are allowed and have the same meaning.

+
let x = [[1,2],[3,4]]
+assert x == ((1,2),[3,4])
+assert x[0,1] == 2 == x[0][1]
+assert x[1,0] == 3 == x[1][0]
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyrope/11-deprecated/index.html b/pyrope/11-deprecated/index.html new file mode 100644 index 0000000..ae425b0 --- /dev/null +++ b/pyrope/11-deprecated/index.html @@ -0,0 +1,1274 @@ + + + + + + + + + + + + + + + + + + + + + + Deprecated or Future - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Deprecated or Future

+

Pyrope has been in internal development for many years, those are some features +tried and deprecated or removed until a better solution is found.

+

step options

+

The step command breaks the execution of the function in the statements before and after the step. In the next +cycle, the statements after the step are executed. The issue was that the step could be placed inside complicated +nests of 'if' and 'for' loops. This results in a difficult code to get right.

+

The plan is to add something like this feature in the future, once a cleaner implementation is designed.

+

Fluid pipelines

+

The plan is to re-add the fluid pipelines syntax, but all the other features must be added first.

+

Bundle index with bundles

+

Bundles do not allow an index with another bundle unless it is a trivial bundle +(one element). To illustrate the current constraints:

+
+
+
+
type Person = (name:string, age:u32)
+var a = (one:Person, two:Person)
+
+x = ('one', 'two')
+a[x].age = 10
+
+
+
+
let Person = (name:string=_, age:u32=_)
+var a = (one:Person, two:Person)
+
+x = 'one'
+y = 'two'
+a[x].age = 10
+a[y].age = 10
+
+
+
+
+

In the future, it may be allowed but some options may not be allowed. For +example, if the index bundle is not unordered, the result of the assignment may +not be easy to predict by the programmer.

+

async/await and coroutines

+

In non-hardware languages, there are several constructs to handle +asynchronicity. Asynchronicity is not to leverage parallelism for speedup but +software constructs to handle long latency operations. The most popular +models/techniques are async/await, coroutines, and actors.

+

In a way, pipelining could be expressed with similar constructs. This has the +advantage of having a larger community (software) to understand/program +hardware more easily.

+

To illustrate the point, suppose a telescoping subtract-like unit that +provides a response of the operation in 1 or 2 cycles depending on the value of +the input. If the b input is 0, the result is a+1. Otherwise, the result is +a-b+1. The first finishes in 1 cycle, the second in 2 cycles. This seemly +easy idea is not so easy to implement because it needs to handle 2 flops and +there could be a structural hazard on the flop if the previous cycle was scheduled +for 2 cycles and the current for 1 cycle.

+

This example explicitly manages the valid output signals.

+
let telescope_unit = fun(a:u32,b:u32,start:bool) -> (res:u32) {
+
+  reg result_done = 0
+  reg result_flop = 0
+
+  if result_done {
+    res = result_flop
+  }
+
+  reg int_done = _
+  reg int_flop = _
+  reg int_b = _
+
+  if int_done {  // pending work (2 cycle op, can not telescope)
+    result_flop = int_flop-int_b
+    result_done = int_done
+    int_flop = a+1
+    int_b    = b
+    int_done = start
+  }else{          // no pending work from before (telescoping is allowed)
+    if b == 0 {
+      result_flop = a+1
+      result_done = start
+    }else{
+      result_flop = int_flop-int_b
+      int_flop = a+1
+      int_b    = b
+      int_done = start
+    }
+  }
+}
+
+

In a simple telescoping use case, the puts command will be called 1 or 2 cycles +after the telescope_unit starts. For the designer, this is quite difficult to +handle. How many flops to add to remember the starting point for a and b.

+
 let res1 =#[1,2] telescope_unit(a,b,start)
+
+ if res1? {
+   puts "{}-{}+1 is {}", a, b, res1.res  // incorrect reference to a
+ }
+
+

To address the issue that the telescope_unit can have multiple cycles to +complete, a yield directive can behave like co-routines. Effectively, +remembering the live-ins and continue executing when the condition is +satisfied.

+
 let res1 =#[1,2] telescope_unit(a,b,start)
+
+ yield res1? // wait for condition to happen
+ assert res1?
+
+ // code executed 1 or 2 cycles after telescope_unit is called
+ puts "{}-{}+1 is {}", a, b, res1.res
+
+

An alternative implementation is using the #>identifier[lat=cycles] keyword. The disadvantage is +that two operations could finish on the same cycle, and the circuits are not as +efficient.

+
// implicit start/end (starts when called)
+let telescope_unit3 = fun(a:u32,b:u32) -> (_:u32) {
+
+  {
+    let tmp = a+1
+  } #>one_pipe[lat=1] {
+    if b == 0 {
+      return tmp
+    }
+    let tmp2 = tmp-b
+  } #> {
+    return tmp2
+  }
+}
+
+

The code sample for explicitly managed step function usage:

+
 let res2 =#[1,2] telescope_unit3(a,b,start)
+
+ if res2? { // code executed 1 or 2 cycles after telescope_unit is called
+   puts "{}-{}+1 is {}", a, b, res2
+ }
+
+

The code sample for implicitly managed step function usage:

+
 async res3 =#[1,2] telescope_unit3(a,b) when start
+
+ await res3 {
+   // a and b could have the correct results due to the async/await
+   puts "{}-{}+1 is {}", a, b, res3.res
+ }
+
+

Extensible enums

+

Once an enum is created, it can not be modified. There is no reason not to support +compile time addition/removal from an enum. Languages with union types could behave +like extending an enum, but not reducing it. Some potential API for Pyrope

+

Using the set operations:

+
enum Order = (One, Two, Three)
+enum Order2 = (...Order, Four)
+enum Order2 = Order ++ Four       // error on overlap?
+enum Order3 = Order except Three  // new "remove" tuple op
+
+

Overloading the logical operations is another option, but breaks the rule of +lack of overloading in ops:

+
enum Order2 = Order or (Four)
+enum Order3 = Order and not (Three)
+
+

Using the trait syntax creates some confusion on the meaning, but an option is to have +custom keywords for enum:

+
enum Order2 = Order with (Four)
+enum Order3 = Order except Three
+
+

Once we support adding/removing to enums, operations like this would make sense:

+
match x:Order {
+  in Order2      { puts "1 or 2" }
+  == Order.Three { puts "3"      }
+}
+
+

repipe

+
+

Note

+

The repipe statement was deprecated because the pipestage could + achieve similar results more cleanly in most of the cases that it was + tried. Also, repipe would have required a custom lgraph pass to balance + pipeline stages.

+
+

The repipe statement tries to balance the number of pipeline stages by +inserting registers. If it can not guarantee the same pipeline depth, a compile +error is generated. If there is any feedback loop, likely, the +pipeline can not be rebalanced with repipe.

+

The syntax for repipe is repipe res = (list of variables). The result is a +tuple with as many fields as the list of input variables but with enough flops +so that the pipeline is balanced from the list of variables and the function +inputs.

+

Liam constructs

+

In most HDLs loops have to be compile time unrolled, in an earlier version of +Pyrope1 allowed for extra keywords to create an actor model and create +state machines where each loop iteration will be executed in a cycle.

+
while some_condition {
+
+  step   // next cycle starts here
+}
+
+

Fluid constructs:

+
    +
  • variable? check if variable valid bit is set
  • +
  • variable! check if variable has a fluid backpressure
  • +
  • keep do not consume variable on use
  • +
  • step stop the cycle here, continue next cycle after the yield statement
  • +
+
+
+
    +
  1. +

    Liam: An Actor Based Programming Model for HDLs, Haven Skinner, Rafael +T. Possignolo, and Jose Renau. 15th ACM-IEEE International Conference on Formal +Methods and Models for System Design (MEMOCODE), October 2017. 

    +
  2. +
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyrope/12-lnast/index.html b/pyrope/12-lnast/index.html new file mode 100644 index 0000000..dac7097 --- /dev/null +++ b/pyrope/12-lnast/index.html @@ -0,0 +1,3109 @@ + + + + + + + + + + + + + + + + + + + + + + LNAST - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

LNAST

+

This document is to showcase some of the Pyrope to LNAST translation. This is +useful to have a more "formal" description of the language semantics.

+

Variable names

+

LNAST does not rename variables to be SSA, it relies in a symbol table to track +past entries. Nevertheless, to reduce amount of tracking information when a +variable starts with underscores (___foo or _._foo), the variable can not +be updated, BUT it is still legal to update tuple fields inside ___foo like +___foo.bar = 3. Program variables names that do not need SSA (let) can use +_._foo to reduce tracking. Special variable names like the ones needing an +underscore use double tick in the name _foo here. Those are special variables +names that do not allow to use compact tuple representation like foo here.field.

+
+
+
+
let x = 3 + 1
+var z = 4
+`foo x` = x + z + 2
+
+
+
+
plus
+  ref ___1
+  const 3
+  const 1
+let
+  ref  x
+  ref  ___1
+var
+  ref z
+  const 4
+plus
+  ref ___2
+  ref x
+  ref z
+  const 2
+assign
+  ref `foo x`
+  ref ___2
+
+
+
+
plus
+  ref ___1
+  const 3
+  const 1
+let
+  ref  x
+  ref  ___1
+var
+  ref z
+  const 4
+plus
+  ref `foo x`
+  ref x
+  ref z
+  const 2
+
+
+
+
+

The three LNAST nodes to set values in variables are let/var/assign. Each can have +types and/or attributes.

+
+
+
+
let a:u2:[foo] = b:u1:[bar]
+
+x:u2:[foo] = y:u1:[bar]
+
+
+
+
set
+  ref a
+    prim_type_uint
+      const 2
+    attr_ref_set
+      const foo
+      const true
+  ref b
+    prim_type_uint
+      const 2
+    attr_check
+      const bar
+      const true
+
+assign
+  ref x
+    prim_type_uint
+      const 2
+    attr_ref_set
+      const foo
+      const true
+  ref y
+    prim_type_uint
+      const 2
+    attr_check
+      const bar
+      const true
+
+
+
+
+

Tuples

+

Tuples are "ordered" sequences that can be named. There are LNAST tuple +specific nodes (tup_add, tup_set, tup_get, tup_concat) but in many +cases the direct LNAST operations can handle tuples directly.

+
    +
  • tup_add creates a new tuple with entries
  • +
  • tup_set adds/updates a field to an existing tuple.
  • +
  • tup_get gets the contents of a tuple entry
  • +
  • tup_concat concatenates two or more tuples
  • +
+

To indicate the tuple position, identifiers can have :pos:name. For example +x.:3:foo = 2 is legal. It is the same as x[3] = 2 or x.foo=2 and check +that entry 3 has label foo. This allows to create more compact LNAST. +Direct access in operations like plus behave like a tup_set or tup_get.

+
+
+
+
x = 3
+a = (b=2, x=x+1, y=self.b+1)
+
+
+
+
assign
+  ref      x
+  const    3
+assign
+  ref      ___t1
+  const    2
+plus
+  ref      ___t2
+  ref      x
+  const    1
+plus
+  ref      ___t3
+  ref      ___t1
+  const    1
+tup_add
+  ref      a
+  var
+    ref      b
+    ref      __t1
+  var
+    ref      x
+    ref      ___t2
+  var
+    ref      y
+    ref      ___t4
+
+
+
+
assign
+  ref      x
+  const    3
+plus
+  ref      ___t2
+  ref      x
+  const    1
+plus
+  ref      ___t3
+  ref      ___t1
+  const    1
+tup_add
+  ref      a
+  var
+    ref      b
+    const   2
+  var
+    ref      x
+    ref      ___t2
+  var
+    ref      y
+    ref      ___t4
+
+
+
+
assign
+  ref      x
+  const    3
+var
+  ref      a.0b
+  ref      2
+plus
+  ref      ___t1
+  ref      x
+  const    1
+var
+  ref      a.1x
+  ref      ___t1
+plus
+  ref      ___t2
+  const    a.0b
+  const    1
+var
+  ref     a.2y
+  ref     ___t2
+
+
+
+
+

tup_set and tup_get can access through several levels in one command. +tup_add does not allow recursive entrances, it requires intermediate tuple +construction. attr_get and attr_set follow the same syntax as +tup_get/tup_set.

+
+
+
+
x = tup[1].foo[xx]
+tup[4].foo[yy] = y
+
+z = (foo=(bar=1))
+
+
+
+
tup_get
+  ref x
+  ref tup
+  const 1
+  const foo
+  ref xx
+
+tup_set
+  ref tup
+  const 4
+  const foo
+  ref yy
+  ref y
+
+tup_add
+  ref ___1
+  var
+    ref bar
+    const 1
+
+tup_add
+  ref z
+  var
+    ref foo
+    ref ___1
+
+
+
+
+

Tuples can have a let in declaration to indicate that the field is immutable.

+
+
+
+
var a = (b=2, let x=1+1)
+
+
+
+
assign
+  ref    ___t1
+  const  2
+plus
+  ref    ___t2
+  const  1
+  const  1
+tup_add:
+  ref     a
+  var
+    ref     b
+    ref     __t1
+  let
+    ref     x
+    ref     ___t2
+
+
+
+
var
+  ref    a.:0:b
+  const  2
+plus
+  ref    ___2
+  const  1
+  const  1
+let
+  ref    a.:1:x
+  ref    ___2
+
+
+
+
+

Tuple concatenation does not use plus but the tup_concat operator.

+
+
+
+
var a = (2, 1+1)
+let x = a ++ (c=3) ++ 1
+
+
+
+
assign
+  ref    ___1
+  const  2
+plus
+  ref    ___2
+  const  1
+  const  1
+tup_add:
+  ref    ___33
+  ref    ___1
+  ref    ___2
+var
+  ref    a
+  ref    ___33
+tup_add
+  ref    ___3
+  const  c
+  const  3
+tup_concat
+  ref    ___4
+  ref    a
+  ref    ___3
+  const  1
+let
+  ref    x
+  ref    ___4
+
+
+
+
var
+  ref    a.:0:
+  const  2
+plus
+  ref    ___2
+  const  1
+  const  1
+var
+  ref    a.:1:
+  ref    ___2
+tup_add
+  ref    ___3
+  const  c
+  const  3
+tup_concat
+  ref    ___4
+  ref    a
+  ref    ___3
+  const  1
+let
+  ref    x
+  ref    ___4
+
+
+
+
+

Attributes

+

There are 3 main operations with attributes: set, get, check, but 4 types of +LNAST nodes (attr_get/attr_set and attr_ref_set/attr_ref_check). +attr_get/attr_set operate at the root level and have the same syntax as +tup_set/tup_get but the last entry is an attribute name. +attr_ref_set/attr_ref_check are sub-nodes of ref, as such they operate +over the associated ref node destination.

+

attr_ref_check only works comparing equal to a const or ref. More complex +attribute comparisons needs attr_get and casserts to operate.

+

Attribute set are in left-hand-side of assignments which can also be in tuple entries.

+
+
+
+
a::[f=3,b] = 1
+x = (y::[z=7]=2, 4)
+
+
+
+
assign
+  ref a
+    attr_ref_set
+      const f
+      const 3
+    attr_ref_set
+      const b
+      const true
+  const 1
+
+tup_add
+  ref ___1
+  var
+    ref y
+      attr_ref_set
+        const z
+        const 7
+    const 2
+  const 4
+
+assign
+  ref x
+  ref ___1
+
+
+
+
+

Attribute checks are always right-hand-side. The constraint in all the cases is +that an attribute name can be check against an expression but only 3 basic +comparisons are valid ([attr==(expr) or [attr] or [!attr]). The +expression can not use other attribute fields. If complex relationships must be +checked between attributes a cassert must be used.

+
+
+
+
var x = (let z=x::[!y], 4::[foo])
+let y = a::[f==3,b] + 1
+
+
+
+
assign
+  ref ___tmp
+  const 4
+
+tup_add
+  ref ___4
+  let
+    ref z
+    ref x
+      attr_ref_check
+        const y
+        const false
+  ref ___tmp
+    attr_ref_check
+      const foo
+      const true
+var
+  ref x
+  ref ___4
+
+plus
+  ref ___1
+  ref a
+    attr_ref_check
+      const f
+      const 3
+    attr_ref_check
+      const b
+      const true
+  const 1
+let
+  ref y
+  ref ___1
+
+
+
+
tup_add
+  ref ___4
+  let
+    ref z
+    ref x
+      attr_ref_check
+        const y
+        const false
+  const 4
+
+attr_get
+  ref ___no_attr_const_check
+  const 4
+  const foo
+
+fcall
+  ref ___0
+  ref cassert
+  ref ___no_attr_const_check
+
+var
+  ref x
+  ref ___4
+
+plus
+  ref ___1
+  ref a
+    attr_ref_check
+      const f
+      const 3
+    attr_ref_check
+      const b
+      const true
+  const 1
+let
+  ref y
+  ref ___1
+
+
+
+
+

Sticky attributes

+

Attributes can be sticky or not. A sticky attribute "polutes" or keeps +the attribute to the left-hand-side expression. Non-sticky attributes +do not affect or propagate.

+

Attributes are not sticky by default, but some like .[debug] is a sticky +attribute. This means that if any of the elements in any operation has a debug +attribute, the result also has a .[debug] attribute. There is no way to +remove these attributes.

+
+
+
+
let d::[debug] = 3
+
+var a = d + 100
+
+cassert a.[debug]  // debug is sticky
+
+
+
+
let
+  ref d
+    attr_ref_set
+      const debug
+      const true
+  const 3
+
+plus
+  ___tmp
+  ref d
+  const 100
+
+var
+  ref a
+  ref ___tmp
+
+attr_get
+  ref ___get
+  ref a
+  const debug
+
+fcall
+  ___unused
+  ref cassert
+  ref ___get
+
+
+
+
+

Once a variable gets assigned an attribute, the attribute stays with the +variable and any variables that got a direct copy. The only way to remove it is +with arithmetic operations and/or bit selection.

+
let foo::[attr1=2] = 3
+
+var foo2 = foo
+cassert foo2.[attr1] == 2
+
+let foo3 = foo@[..]
+cassert foo3 !has _::[attr1]
+
+var xx = 4
+xx::[attr2=5] = 1
+
+let xx2 = xx
+cassert xx2.[attr2] == 5
+cassert xx2 has _::[attr2]
+
+let xx3 = xx + 0
+cassert xx3 !has _::[attr2]
+
+

Bit selection

+

Pyrope has several bit selection operations. The default maps get_mask and +set_mask LNAST nodes. One important thing is that both get_mask and +set_mask operate over a MASK. This means that it is a one-hot encoding if a +single bit is operated. The one-hot encoding can be created with a range or +with a shl operator.

+
+
+
+
foo@[1,2] = xx
+yy = foo@[5] + xx@[1..<4]
+
+
+
+
shl
+  ref ___c1
+  const 1
+  const 1
+
+shl
+  ref ___c2
+  const 1
+  const 2
+
+tup_add
+  ref ___t
+  ref ___c1
+  ref ___c2
+
+set_mask
+  ref foo
+  ref foo
+  ref ___t
+  ref xx
+
+range
+  ref ___c5
+  const 5
+  const 5
+  const 1
+
+get_mask
+  ref ___3
+  ref foo
+  ref ___c5
+
+range
+  ref ___4
+  const 1
+  const 3
+  const 1
+
+get_mask
+  ref ___5
+  ref xx
+  ref ___4
+
+add
+  ref yy
+  ref ___4
+  ref ___5
+
+
+
+
shl
+  ref ___t
+  const 1
+  const 1
+  const 2
+
+set_mask
+  ref foo
+  ref foo
+  ref ___t
+  ref xx
+
+get_mask
+  ref ___3
+  ref foo
+  const 5
+
+range
+  ref ___4
+  const 1
+  const 3
+  const 1
+
+get_mask
+  ref ___5
+  ref xx
+  ref ___4
+
+add
+  ref yy
+  ref ___4
+  ref ___5
+
+
+
+
+

It is possible to use a foo@sext[range] to perform a bit selection with sign +extension. The sext LNAST node is equivalent to the Lgraph sext that has 2 +inputs. The variable and from what bit to perform sign-extension. This means +that the LNAST translation needs a get_mask and a sext node. The sext, ++, |, ^ bit selection modifiers can only be applied to right-hand-side +operations.

+
+
+
+
let t1 = foo@sext[..=4]
+let t2 = foo@|[..=4]
+let t3 = foo@&[..=4]
+let t4 = foo@^[..=4]
+let t5 = foo@+[..=4]
+
+
+
+
range
+  ref ___r
+  const 0
+  const 4
+  const 1
+
+get_mask
+  ref ___t
+  ref foo
+  ref ___r
+
+sext
+  ref ___t1
+  ref ___t
+  const 4
+let
+  ref t1
+  ref ___t1
+
+reduce_or
+  ref ___t2
+  ref ___t
+let
+  ref t2
+  ref ___t2
+
+reduce_and       // reduce_and(x) == (sext(x) == -1)
+  ref ___t3
+  ref ___t
+let
+  ref t3
+  ref ___t3
+
+reduce_xor
+  ref ___t4
+  ref ___t
+let
+  ref t4
+  ref ___t4
+
+popcount
+  ref ___t5
+  ref ___t
+let
+  ref t5
+  ref ___t5
+
+
+
+
+

Direct LNAST/Lgraph call

+

A direct Lgraph call can be done with __cell where cell is the Lgraph cell +like plus, LUT, memory. In LNAST this is translated like a lambda call.

+
+
+
+
let foo = 3
+let bar = 300
+let b = __plus(1,2,foo,bar)
+
+
+
+
let
+  ref foo
+  const 3
+let
+  ref bar
+  const 300
+tup_add
+  ref ___0
+  const 1
+  const 2
+  ref foo
+  ref bar
+fcall
+  ref b
+  ref __plus
+  ref ___0
+
+
+
+
+

A direct LNAST call can be done calling an LNAST method, where the first entry +is the root LNAST node, and rest follow a tree syntax with strings.

+
+
+
+
LNAST("let", ("ref", "x"), ("const", "5"))
+
+
+
+
let
+  ref x
+  const 5
+
+
+
+
+

Basic operators

+

Basic operators are binary or unary operators in Pyrope that have a one-to-one +translation to LNAST nodes.

+

Unary

+
    +
  • !a or not a translates to lnot
  • +
  • ~a translates to not
  • +
  • -a translates to minus(0,a)
  • +
+

Binary integer

+
    +
  • a + b translates to plus
  • +
  • a - b translates to minus
  • +
  • a * b translates to mult
  • +
  • a / b translates to div
  • +
  • a & b translates to and
  • +
  • a | b translates to or
  • +
  • a ^ b translates to xor
  • +
  • a >> b translates to sra
  • +
  • a << b translates to shl
  • +
+

There is a mod LNAST operator that performs module operations. It does not +have a direct Pyrope syntax, but it can be called directly __mod(a,b).

+

Binary boolean

+
    +
  • a and b translated to land
  • +
  • a or b translates to lor
  • +
+

Complex operators

+

Complex operators are binary operators in Pyrope that require more than one +LNAST statement.

+

Binary integer

+

Binary nand (x=a ~& b): +

and
+  ref ___0
+  ref a
+  ref b
+not
+  ref x
+  ref ___0
+

+

Binary nor (x=a ~| b): +

or
+  ref ___0
+  ref a
+  ref b
+not
+  ref x
+  ref ___0
+

+

Binary xor (x=a ~^ b): +

xor
+  ref ___0
+  ref a
+  ref b
+not
+  ref x
+  ref ___0
+

+

Logical shift right (x = a@[..] >> b): +

get_mask
+  ref ___0
+  ref a
+sra
+  ref x
+  ref ___0
+  ref b
+

+

Binary logical

+

Logical implication (x = a implies b): +

not
+  ref ___0
+  ref a
+lor
+  ref x
+  ref ___0
+  ref b
+

+

Logical nand (x = a !and b): +

land
+  ref ___0
+  ref a
+  ref b
+not
+  ref x
+  ref ___0
+

+

Logical nor (x = a !or b): +

lor
+  ref ___0
+  ref a
+  ref b
+not
+  ref x
+  ref ___0
+

+

Logical not implication (x = a !implies b): +

not
+  ref ___0
+  ref b
+land
+  ref x
+  ref a
+  ref ___0
+

+

Short-circuit boolean (and_then/or_else)

+

The short-circuit boolean prevent expressions from being evaluated. This only +matters if there is a procedure call, but at LNAST it is not possible to know +due to getter overload. As a result, the sequence of statments is translated to +a sequence of nested if statements.

+
+
+
+
a = b and_then c and_then (d or e)
+
+
+
+
+
+
land
+  ref ___0
+  ref b
+  ref c
+assign
+  ref a
+  ref ___0
+if
+  ref ___0
+  stmts
+    lor ___1
+      ref d
+      ref e
+    assign
+      ref a
+      ref ___1
+
+
+
+
+
a = b or_else c or_else (d and e)
+
+
+
+
+
+
lor
+  ref ___0
+  ref b
+  ref c
+assign
+  ref a
+  ref ___0
+if
+  ref ___0
+  stmts
+  stmts  // else only
+    land
+      ref ___1
+      ref d
+      ref e
+    assign
+      ref a
+      ref ___1
+
+

Tuple/Set operators

+

The in operator does not have a Lgraph equivalent becuase it is type +dependent: tuple, range, or enumerate. The range and enumerate can get +translated to an AND gate over the bitcode translation, but the tuple check +requires a tuple check.

+
let tup=(1,2,3)
+let ran=1..<5
+let enu = enum(a,b=(x,y),c)
+
+cassert 2 in tup
+cassert 3 in ran
+cassert enu.b.x in enu.b
+
+

The resul is a common in LNAST operation that gets different functionality +dependent on the input type.

+
+
+
+
c = a in b
+d = a !in b
+
+
+
+
in
+  ref c
+  ref a
+  ref b
+not
+  ref d
+  ref c
+
+
+
+
+

There are two tuple concatenate operator a ++ b and (a,...b). x=a++b translates to:

+
tup_concat
+  ref x
+  ref a
+  ref b
+
+

The inplace concatenate is equivalent but it has a check (cassert) to detect overlap. After the concatenation, +the fields in a and b should be found in the result x or there was an overlap.

+

x=(a,..b) translates to: +

tup_concat
+  ref x
+  ref a
+  ref b
+in
+  ref ___1
+  ref a
+  ref x
+in
+  ref ___2
+  ref b
+  ref x
+land
+  ref ___3
+  ref ___1
+  ref ___2
+fcall
+  ref ___0
+  ref cassert
+  ref ___3
+

+

Tuple to operator

+

The to is an iterator but instead of a range, it creates a tuple.

+

tmp = a to b by c translates to: +

to
+  ref tmp
+  ref a
+  ref b
+  ref c
+

+

tmp = 3 to b translates to: +

to
+  ref tmp
+  const 3
+  ref b
+  const 1
+

+

Range operator

+

Ranges can be open or closed. The closed ranges have the start/end/step +defined.

+

x = a..<=b by 2 translates to: +

range
+  ref x
+  ref a
+  ref b
+  const 2
+

+

x = a..<=b by 2 translates to: +

range
+  ref x
+  ref a
+  ref b
+  const 2
+

+

x = a..<b translates to: +

sub
+  ref tmp
+  ref b
+  ref 1
+
+range
+  ref x
+  ref a
+  ref tmp
+  const 1
+

+

Type operators

+

To check if a field name or position exists in a tuple, x = a has b translates: +

has
+  ref x
+  ref a
+  ref b
+

+

To check the tuple structure, Pyrope has a does b. It returns true if the +tuple of a a subset of b. x = a does b translates to: +

does
+  ref x
+  ref a
+  ref b
+

+

To check equality of tuples x = a equals b same as x = (a does b) and (b does a). Translates to: +

does
+  ref ___0
+  ref a
+  ref b
+does
+  ref ___1
+  ref b
+  ref a
+land
+  ref x
+  ref ___0
+  ref ___1
+

+

The a case b does match operation. a case b same as cassert b does a and +for each b field with a defined value, the value matches a (nil, 0sb? +are undefined values). x = a case b translates to: +

does
+  ref ___0
+  ref b
+  ref a
+fcall
+  ref ___1
+  ref cassert
+  ref ___0
+in
+  ref x
+  ref b
+  ref a
+

+

To perform a nominal type check, the attributes can be accessed directly. x = a is b translates to: +

attr_get
+  ref ___0
+  ref a
+  const typename
+attr_get
+  ref ___1
+  ref b
+  const typename
+eq
+  ref x
+  ref ___0
+  ref ___1
+

+

if/unique if

+

Like many modern languages, if accepts not only a boolean expression but a +sequence of statements. Like C++17, before a condition, there can be a sequence +of statements that can include variable declarations. Pyrope variables initial +statement declarations are visiable in the if and else statements like +C++17 does.

+

A special constraint from Pyrope is that the initial statements and condition +check can not have side-effects. Hence, they can not have procedure calls, +only function calls.

+
+
+
+
var total=3
+if var x=3; x<3 {
+  total+=x
+}elif var z=3; z<4 {
+  total+=x+z
+}
+
+
+
+
var total=3
+{
+  var x=3
+  if x<3 {
+    total+=x
+  }else{
+    var z=3
+    if z<4 {
+      total+=x+z
+    }
+  }
+}
+
+
+
+
int total=3;
+if (int x=3; x<3) {
+  total+=x;
+}else if (int z=3; z<4) {
+  total+=x+z;
+}
+
+
+
+
+

Pyrope has if and unique if. The difference is that unique if guarantees +that only one of the branch conditions is taken. It is possible to have all the +conditions not taken. This allows synthesis optimizations because it implies +that the condition is a one-hot encoding.

+
+
+
+
if var x=a ; x<3 {
+  t = 100+x               // z not in scope
+}elif var z = x+c ; z>5 {
+  t = 200+z+x             // z and x in scope
+}
+
+
+
+
stmts
+  var
+    ref x
+    ref a
+  lt
+    ref ___1
+    ref x
+    const 3
+  if
+    ref ___1
+    stmts
+      add
+        ref t
+        const 100
+        ref x
+    stmts
+      add
+        ref ___2
+        ref x
+        ref c
+      var
+        ref z
+        ref ___2
+      gt
+        ref ___3
+        ref z
+        const 5
+      if
+        ref ___3
+        stmts
+          add
+            ref t
+            const 200
+            ref z
+            ref x
+
+
+
+
+

The unique if is similar, but all the conditions include and optimize +directive to be checked. This means that the conditions must be checked even if +the else is not reached. This is fine because neither the statements nor the +condition checks are allowed to have side-effects.

+

An important limitation of unique if is that only the first condition can +have initial statement. It is not allowed to have initialization statements in +the elif conditions.

+
+
+
+
unique if a<3 {
+  y = 10
+}elif a>40 {  // not allowed to do 'elif var z=40; a>z'
+  y = 20+x
+}
+
+
+
+
let tmp1 = a<3
+let tmp2 = a>40
+let tmp3 = 1<<(tmp1,tmp2)
+optimize tmp3@+[..]<=1        // at most one bit set
+
+if tmp1 {
+  y = 10
+}elif tmp2 {
+  y = 20+x
+}
+
+
+
+
lt
+  ref ___1
+  ref z
+  const 3
+gt
+  ref ___2
+  ref a
+  const 40
+shl           // create one-hot encoding
+  ref ___3
+  const 1
+  ref ___1
+  ref ___2
+popcount
+  ref ___4
+  ref ___3
+le
+  ref ___5
+  ref ___4
+  const 1
+fcall
+  ref nil
+  ref optimize
+  ref ___5
+if
+  ref ___1
+  stmts
+    assign
+      ref y
+      const 10
+  ref ___2
+  stmts
+    add
+      ref y
+      const 20
+      ref x
+
+
+
+
+

match

+

The match statement behaves like a unique if but it also checks that at least +one of the paths is taken. This means that if the else exists in the match, +it behaves like a unique if. If the else does not exist, an else { assert +false } is created.

+
+
+
+
var z = 0
+match x {
+ == 3 { z = 1 }
+ in 4..<6 { z = 2 }
+}
+
+match x {
+ <  5 { z = 1 }
+ else { z = 3 }
+}
+
+
+
+
var
+  ref z
+  const 0
+
+eq
+  ref ___0
+  ref x
+  const 3
+range
+  ref ___2
+  const 4
+  const 5
+in
+  ref ___1
+  ref x
+  ref ___2
+
+shl
+  ref ___3
+  const 1
+  ref ___1
+  ref ___2
+popcount
+  ref ___4
+  ref ___3
+le
+  ref ___5
+  ref ___4
+  const 1
+fcall
+  ref nil
+  ref optimize
+  ref ___5
+
+if
+  ref ___1
+  stmts
+    assign
+      ref z
+      const 1
+  ref ___2
+  stmts
+    assign
+      ref z
+      const 2
+  stmts
+    fcall
+      ref ___6
+      ref assert
+      const false
+
+// 2nd match
+lt
+  ref ___6
+  ref x
+  const 5
+shl
+  ref ___7
+  const 1
+  ref ___6
+popcount
+  ref ___8
+  ref ___7
+le
+  ref ___9
+  ref ___8
+  const 1
+fcall
+  ref nil
+  ref optimize
+  ref ___9
+if
+  ref ___6
+  stmts
+    assign
+      ref z
+      const 1
+  stmts
+    assign
+      ref z
+      const 3
+
+
+
+
+

Scope

+

Like most languages Pyrope has variable scope, but it does not allow variable +shadowing. This section showcases some cases on how the scope is generated.

+

New variables can have a statement scope for if, while, and match +statements.

+
+
+
+
if var x=3; x<4 {
+  cassert x==3
+}
+while var z=1; x {
+  x -= z
+}
+var z=0
+match var x=2 ; z+x {
+  == 2 { cassert true  }
+  != 7 { cassert true  }
+  else { cassert false }
+}
+
+
+
+
stmts
+  var
+    ref x
+    const 3
+  lt
+    ref ___1
+    ref x
+    const 4
+  if
+    ref ___1
+    stmts
+      eq
+        ref ___2
+        ref x
+        const 3
+      fcall
+        ref ___0
+        ref cassert
+        ref ___2
+
+stmts
+  var
+    ref z
+    const 1
+  loop
+    if
+      ref x
+      stmts
+        break
+    sub
+      ref x
+      ref x
+      ref z
+
+var
+  ref z
+  const 0
+stmts
+  var
+    ref x
+    const 2
+  add
+    ref ___3
+    ref z
+    ref x
+  eq
+    ref ___t1
+    ref ___3
+    const 2
+  ne
+    ref ___t2
+    ref ___3
+    const 7
+  shl           // create one-hot encoding
+    ref ___x
+    const 1
+    ref ___t1
+    ref ___t2
+  popcount
+    ref ___y
+    ref ___x
+  le
+    ref ___z
+    ref ___y
+    const 1
+  fcall
+    ref nil
+    ref optimize
+    ref ___z
+  if
+    ref ___t1
+    stmts
+      fcall
+        ref ___4
+        ref cassert
+        const true
+    ref ___t2
+    stmts
+      fcall
+        ref ___5
+        ref cassert
+        const true
+    stmts
+      fcall
+        ref ___6
+        ref cassert
+        const false
+
+
+
+
+

while/loop/for

+

Pyrope has loop, while, and for constructs to handle different types of loops. +In all the cases, the loops must be expanded at LNAST compile time. In LNAST, there +is only loop construct.

+
+
+
+
loop {
+  i += 1
+  break when i==3
+}
+
+
+
+
loop
+  add
+    ref i
+    ref i
+    const 1
+  eq
+    ref ___1
+    ref i
+    const 3
+  if
+    ref ___1
+    stmts
+      break
+
+
+
+
+

The while translates to a loop with a break statement.

+
+
+
+
while var i=0 ; i!=3 {
+  i += 1
+}
+
+
+
+
stmts
+  var
+    ref i
+    const 0
+  loop
+    neq
+      ref ___1
+      ref i
+      const 3
+    not
+      ref ___2
+      ref ___1
+    if
+      ref ___2
+      stmts
+        break
+
+
+
+
+

The for construct is also a loop, but it can have element, index, and key in the iterator. Also, it can allow a ref to mutate the contents.

+
+
+
+
for (index,key,value) in enumerate(key(tup)) {
+  mycall(value,index,key)
+}
+
+
+
+
for value in ref tup {
+  mycall(value)
+  value = 0
+}
+
+
+
+
attr_get
+  ref ___tup_size
+  ref tup
+  const size
+gt
+  ref ___2
+  ref ___tup_size
+  const 0
+if
+  ref ___2
+  stmts
+    var
+      ref value
+      ref _
+    var
+      ref index
+      const 0
+    var
+      ref key
+      const ""
+    loop
+      attr_get
+        ref key
+        ref tup
+        ref index
+        const "key"
+      tup_get
+        ref value
+        ref tup
+        ref index
+      tup_add
+        ref ___6
+        ref index
+        ref key
+        ref value
+      fcall
+        ref ___empty
+        ref mycall
+        ref ___6
+      add
+        ref index
+        ref index
+        const 1
+      eq
+        ref ___3
+        ref ___tup_size
+        ref index
+      if
+        ref ___3
+        stmts
+          break
+
+
+
+
attr_get
+  ref ___tup_size
+  ref tup
+  const size
+gt
+  ref ___2
+  ref ___tup_size
+  const 0
+if
+  ref ___2
+  stmts
+    var
+      ref value
+      ref _
+    var
+      ref index
+      const 0
+    var
+      ref key
+      const ""
+    loop
+      attr_get
+        ref key
+        ref tup
+        ref index
+        const "key"
+      tup_get
+        ref tup
+        ref index
+        ref value
+      tup_add
+        ref ___6
+        ref index
+        ref key
+        ref value
+      fcall
+        ref ___empty
+        ref mycall
+        ref ___6
+      tup_set
+        ref tup
+        ref index
+        ref value
+      add
+        ref index
+        ref index
+        const 1
+      eq
+        ref ___3
+        ref ___tup_size
+        ref index
+      if
+        ref ___3
+        stmts
+          break
+
+
+
+
+

The for comprehensions behave similarly, but the cont/brk statements have +the value that must be concatenated (tup_concat) to the result. If the last +statement is an expression, the value is contatenated.

+

puts/print/format

+

All the string variables must be known at compile time, but it is still OK to +pass strings as arguments to simulation functions that have no side-effects in +the running simulation like puts and print.

+

format uses C++ fmt::format syntax and returns a string, so it must be solved +at compile time. This means that the LNAST passes should have a format +implementation to allow copy propagation to proceed. When format is used, a +single quote should be used to avoid string interpolation.

+

The LNAST translation for all these instructions is just a normal function +call. The format must be executed at compile time and propagate/copy as +needed. The puts/print should generate simulation calls but not synthesis +code.

+
+
+
+
let num = 1
+let color = "blue"
+let extension = "s"
+
+let txt1 = "I have {num} {color} potato{extension}"  // interpolation
+let txt2 = format('I have {:d} {} potato{}', num, color, extension)
+
+
+
+
let
+  ref num
+  const 1
+let
+  ref color
+  const blue
+let
+  ref extension
+  const s
+
+tup_add
+  ref ___tmp
+  const "I have {} {} potato{}"
+  ref num
+  ref color
+  ref extension
+
+fcall
+  ref txt1
+  ref format
+  ref ___tmp
+
+tup_add
+  ref ___tmp2
+  const 'I have {:d} {} potato{}'
+  ref num
+  ref color
+  ref extension
+
+fcall
+  ref txt2
+  ref format
+  ref ___tmp2
+
+
+
+
+

Lambda call

+

A lambda call arguments requires do not always require to be named like when a +variable used matches a calling argument. To support the matching while +processing the LNAST, the arguments tuple must be named for all the arguments +unless an argument is an expression.

+
+
+
+
x = fcall(a,b=3,foo,1+2)
+
+
+
+
add
+  ref ___t
+  const 1
+  const 2
+
+tup_add
+  ref ___args
+  let
+    ref a
+    ref a
+  let
+    ref b
+    const 3
+  let
+    ref foo
+    ref foo
+  ref ___t
+
+fcall
+  ref x
+  ref fcall
+  ref ___args
+
+
+
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyrope/13-stdlib/index.html b/pyrope/13-stdlib/index.html new file mode 100644 index 0000000..47e87cc --- /dev/null +++ b/pyrope/13-stdlib/index.html @@ -0,0 +1,1143 @@ + + + + + + + + + + + + + + + + + + + + Pyrope Standard Library - LiveHD and Pyrope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Pyrope Standard Library

+

This is a list of functionality that import prp should produce.

+

Basic operations

+

All the LNAST node have an associated function matching name to simplify the +creation of operations: plus, minus, mult, div, mod, ror...

+
let prp = import("prp")
+cassert prp.plus(1,2,3) == 6
+
+

Library code: +

let plus = fun(...a:int)->(_:int) {
+  var r = 0
+  for e in a {
+    r += e
+  }
+  r
+}
+

+

Array/Tuple operators

+

Size of length

+

Sample use: +

let x = (1,2,23)
+
+cassert p.len(x) == 3
+

+

Library code: +

let len = fun(x) { x.[size] }
+

+

map

+

Sample use:

+
let x = (1,2,3)
+
+cassert x.map(fun(i){ i+1 }) == (2,3,4)
+
+

Library code: +

let map = fun<T>(f:fun(a:T),...x:[]T) {
+  return f(e) for e in x
+}
+

+

filter

+

Sample use:

+
cassert (1,2,3).filter(fun(i){ i!=2 }) == (1,3)
+
+

Library code:

+
let filter = fun<T>(f:fun(a:T)->(_:Bool),...x:[]T) {
+  return e for e in x if not f(e)
+}
+
+

reduce

+

Sample use:

+
cassrt (1,2,3).reduce(prp.plus) == 6
+
+

Library code:

+
let reduce = fun(op:fun<T>(a:T,b:T)->(_:T), ...x) {
+  return x when x.[size] <= 1
+
+  var res = x[0]
+  for i in x[1..] {
+    res = op(res, i)
+  }
+  return res
+}
+
+

TODO

+

It would be nice to have the same methods (and names) as the c++20 std::views + adaptors so that it is easier for developers to get familiar. E.g: filter, + transform, drop, join, split, reverse, common, counted...

+

https://en.cppreference.com/w/cpp/ranges

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 0000000..d3df1c7 --- /dev/null +++ b/search/search_index.json @@ -0,0 +1 @@ +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"LiveHD and Pyrope","text":"

LiveHD is the compiler infrastructure that allows to work with Hardware Description Languages (HDLs) like Verilog, CHISEL, and Pyrope.

Pyrope is the new HDL built on top of LiveHD.

Hardware Design provides an introduction to hardware design for software designers.

"},{"location":"livehd/00-intro/","title":"Introduction","text":"

LiveHD is an infrastructure designed for Live Hardware Development. By live, we mean that small changes in the design should have the synthesis and simulation results in a few seconds.

As the goal of \"seconds,\" we do not need to perform too fine grain incremental work. Notice that this is a different goal from having an typical incremental synthesis, where many edges are added and removed in the order of thousands of nodes/edges.

"},{"location":"livehd/00-intro/#goal","title":"Goal","text":"

LiveHD: a fast and friendly hardware development flow that you can trust

  • To be \"Fast\", LiveHD aims to be parallel, scalable, and incremental/live flow.
  • To be \"friendly\", LiveHD aims to build new models to have good error reporting.
  • To \"trust\", LiveHD has CI and many random tests with logic equivalence tests (LEC).
"},{"location":"livehd/00-intro/#livehd-framework","title":"LiveHD Framework","text":"

LiveHD is optimized for synthesis and simulation. The main components of LiveHD includes LGraph, LNAST, integrated 3rd-party tools, code generation, and \"live\" techniques.

A compilation goes through the following steps:

  • Source code goes through a lexer/parser to create a parse tree or language specific AST.

  • The parse tree or language specific AST is translated to LNAST. LNAST is a AST-like representation that it is independent of the specific language. Pyrope, CHISEL, and Verilog translate to LNAST.

  • The are several passes on LNAST to infer the correct type and bitsizes. The goal is to expand tuples, macros at LNAST level, but this code is still not finished.

  • The LNAST is a tree-like representation which is translated to Lgraph. In a way, LNAST is a HIR (High-level IR) and Lgraph is a LIR (Low-level IR). For each Lgraph node, there is an equivalent LNAST, but not the opposite.

  • LGraph has a hierarchical graph representation designed for fast synthesis and simulation. It interfaces other tools like Yosys, ABC, OpenTimer, and Mockturtle.

  • For code generation, it is possible to translate back to LNAST or to directly output from Lgraph.

"},{"location":"livehd/01-install/","title":"Installation","text":"

This is a high level description of how to build LiveHD.

"},{"location":"livehd/01-install/#requirements","title":"Requirements","text":"

Although LiveHD should run on most common Linux distributions, it is heavily tested on both Arch and Kali (Debian based).

The following programs are assumed to be present when building LiveHD:

  • GCC 12+ or Clang 12+ (C++20 support is required)
  • Bazel
  • python3

It is also assumed that bash is used to compile LiveHD.

gcc and clang offers better warnings and execution speed dependent of the benchmark.

If you're unsure if your copy of gcc or clang is new enough, you can check the version by typing

g++ --version\n

or

clang++ --version\n
"},{"location":"livehd/01-install/#steps","title":"Steps","text":"

Download LiveHD source

git clone https://github.com/masc-ucsc/livehd\n

Install Bazelisk

Bazelisk is a wrapper around bazel that allows you to use a specific version.

If you do not have system permissions, you can install a local bazelisk

npm install  @bazel/bazelisk\nalias bazel=$(pwd)/node_modules/\\@bazel/bazelisk/bazelisk.js\n

You can also install it directly if you have administrative permissions:

macos:

brew install bazelisk.\n

Linux:

npm install -g @bazel/bazelisk\n

go install github.com/bazelbuild/bazelisk@latest\nexport PATH=$PATH:$(go env GOPATH)/bin\n

Arch linux:

pacaur -S bazelisk  # or yay or paru installers\n

Build LiveHD

LiveHD has several build options, detailed below. All three should result in a working executable, but may differ in speed or output.

A binary will be created in livehd/bazel-bin/main/lgshell.

bazel build       //main:all # fast build, no debug symbols, slow execution (default)\nbazel build -copt //main:all # fastest execution speed, no debug symbols, no assertions\nbazel build -cdbg //main:all # moderate execution speed, debug symbols\n
"},{"location":"livehd/01-install/#potential-issues","title":"Potential issues","text":"

If you have multiple gcc versions, you may need to specify the latest. E.g:

CXX=g++-8 CC=gcc-8 bazel build //main:all -c opt # fast execution for benchmarking\nCXX=g++-8 CC=gcc-8 bazel build //main:all -c dbg # debugging/development\n

If you want to run clang specific version:

CXX=clang++-10 CC=clang-10 bazel build //main:all -c dbg # debugging/development\n

Make sure that the openJDK installed is compatible with bazel and has the certificates to use tools. E.g in debian:

dpkg-reconfigure openjdk-11-jdk\n/var/lib/dpkg/ca-certificates-java.postinst configure\n

If you fail to build for the first time, you may need to clear the cache under your home directory before rebuilding:

rm -rf ~/.cache/bazel\n

Make sure to have enough memory (4+GB at least)

"},{"location":"livehd/01-install/#next-steps","title":"Next Steps","text":"

To start using LiveHD, check out Usage. If you're interested in working on LiveHD, refer to Creating a pass.

"},{"location":"livehd/02-usage/","title":"Usage","text":"

This is a high level description of how to use LiveHD.

"},{"location":"livehd/02-usage/#sample-usage","title":"Sample usage","text":"

Below are some sample usages of the LiveHD shell (lgshell). A bash prompt is indicated by $, an lgshell prompt is indicated by livehd>, and a Yosys prompt is indicated by a yosys>. Lgshell supports color output and autocompletion using the tab key.

"},{"location":"livehd/02-usage/#general-concepts","title":"General concepts","text":"

Currently, LiveHD can interface Verilog, FIRRTL, and Pyrope HDLs through different front-end commands. After the parsing step, the HDL source can be be transformed into LiveHD's internal intermediate representations, LNAST and LGraph, and perform mid-end optimizations based on the two IRs, and generates the optimized (or synthesized) Verilog code at the back-end.

"},{"location":"livehd/02-usage/#starting-and-exiting-the-shell","title":"Starting and exiting the shell","text":"
$ ./bazel-bin/main/lgshell\nlivehd> help\n  ...\nlivehd> help pass.sample\nlivehd> exit\n
"},{"location":"livehd/02-usage/#verilog-compilation","title":"Verilog Compilation","text":"

The following uses Verilog as the example to demonstrate the compilations commands. It imports a Verilog file with a specified the database path, translates to the LNAST IR, lowers the LNAST IR to LGraph IR, executes some compiler optimizations, and generates the optimized Verilog code to the tmp directory. By default, a database called lgdb will be set in the livehd directory to store the internal representations, but users can optionally specify a prefered path.

livehd> inou.liveparse path:/your/path/lgdb_foo files:/your/path/bar.v |> inou.verilog |> pass.lnast_tolg |> pass.cprop |> pass.bitwidth |> inou.cgen.verilog odir:tmp\n

A command lgraph.match can also be used to specify a (sub)hierarchy to operate over, which can then be moved from pass to pass using the pipe (|>) operator.

When Verilog file(s) are compiled through a series of commands in lgshell, if a problem occurs while compiling Verilog files (due to a syntax error, use of un-synthesizable Verilog, or something else), the corresponding error will be printed. Once a hierarchy has been created, other lgshell commands can read, modify, or export this hierarchy freely.

"},{"location":"livehd/02-usage/#pyrope-compilation","title":"Pyrope Compilation","text":"

The Pyrope compilation flow is similar to the Verilog commands except the front-end Pyrope parser pass inou.pyrope

livehd> inou.pyrope path:/your/path/lgdb_foo files:/your/path/bar.prp |> pass.lnast_tolg |> pass.cprop |> pass.bitwidth |> inou.cgen.verilog odir:tmp\n

Additionally, users can compile a Pyrope code with a mid-end command of pass.compiler which integrates standard compilation passes in LiveHD such as (1) pass.lnast_tolg for IR lowering, (2) pass.cprop for legacy compiler optimizations such as copy and constant propagation, peep-hole optimization, deadcode elimination, and high-level data-structure resolving (3) pass.bitwidth for circuit bitwidth optimization.

livehd> inou.pyrope path:/your/path/lgdb_foo files:/your/path/bar.prp |> pass.compiler |> inou.cgen.verilog odir:tmp\n
"},{"location":"livehd/02-usage/#firrtl-compilation","title":"FIRRTL Compilation","text":"

LiveHD compiles FIRRTL code with the protocal buffer format. Users can reference this doc to generate the protocol buffers file from Chisel/FIRRTL compiler.

The LiveHD FIRRTL compiler uses a integrated mid-end commands as explained in the previous Pyrope example to compiles the FIRRTL HDL. Set gviz option to true to automatically generate the visiual Graphviz for individual steps. Set hier option to true for hierarchical Chisel design in most cases. Specify the top module name with the top option.

livehd> inou.firrtl.tolnast path:/your/path/lgdb_foo files:/your/path/bar.pb |> pass.compiler gviz:false top:top_module_name hier:true |> inou.cgen.verilog odir:tmp\n
"},{"location":"livehd/02-usage/#textual-lnast-ir-dump","title":"Textual LNAST IR Dump","text":"

To display the content of the LNAST IR after parse (Pyrope as the example)

inou.pyrope files:foo.prp |> lnast.dump

"},{"location":"livehd/02-usage/#textual-lgraph-ir-dump","title":"Textual LGraph IR Dump","text":"

To display the content of the LGraph IR (Pyrope as the example)

inou.pyrope files:foo.prp |> pass.lnast_tolg |> lgraph.dump

"},{"location":"livehd/02-usage/#lgraph-serialization","title":"LGraph serialization","text":"

To serialize the content of the LGraph IR (Pyrope as the example), default path is lgdb inou.pyrope files:foo.prp |> pass.lnast_tolg |> lgraph.save

"},{"location":"livehd/02-usage/#lgraph-deserialization","title":"LGraph deserialization","text":"

To deserialize a stored LGraph, and pass it to some lgraph passes lgraph.open name:foo |> pass.cprop |> pass.bitwidth |> inou.cgen.verilog odir:tmp

"},{"location":"livehd/02-usage/#graphviz-lgraph-ir-dump","title":"Graphviz LGraph IR Dump","text":"

To display the content of the LGraph IR (Pyrope after the cprop pass as the example) inou.pyrope files:foo.prp |> pass.lnast_tolg |> pass.cprop |> inou.graphviz.from

  • Print information about an existing LGraph:
    $ ./bazel-bin/main/lgshell\nlivehd> inou.liveparse files:./inou/yosys/tests/trivial.v |> inou.verilog\nlivehd> lgraph.match |> lgraph.stats\nlivehd> lgraph.match |> lgraph.dump\n
    lgraph.match picks up any LGraphs matching the regex passed (or everything if no regex is provided) and treats every single one as the top of the hierarchy, whereas lgraph.open name:<root module> will just open the root module as the top of the hierarchy.
"},{"location":"livehd/02-usage/#running-a-custom-pass","title":"Running a custom pass","text":"
$ ./bazel-bin/main/lgshell\nlivehd> inou.pyrope files:./inou/pyrope/tests/if1.prp\nlivehd> lgraph.match |> <pass name>\n
"},{"location":"livehd/02-usage/#low-level-directed-build","title":"Low level directed build","text":"
  • To compile an individual pass:
    $ bazel build -c dbg //pass/sample:pass_sample\n$ bazel build -c dbg //inou/yosys:all\n
  • To build a direct Yosys executable that has LiveHD embedded:
    $ bazel build -c dbg //inou/yosys:all\n$./bazel-bin/inou/yosys/yosys2\n
"},{"location":"livehd/02-usage/#parallel-compilation","title":"Parallel Compilation","text":"

LiveHD support parallel compilation, it will set the thread number to the highest available resources in your system. To manually set the compilation thread number, for example, 1, set the following environment variable

export LIVEHD_THREADS=1\n

"},{"location":"livehd/03-memory/","title":"Memory and concurrency","text":"

This section explains the memory management or garbage collect principles used and the relationship with concurrency models.

"},{"location":"livehd/03-memory/#memory-management-models","title":"Memory management models","text":"

Memory management in a multi-threaded environment main challenge arises from deletes and additions that can trigger memory allocation/de-allocation. In LiveHD, we address this problem the following way:

  • Only one thread can allocate/deallocate memory in an object at a given time. To allow updates, a RW access is required. Otherwise, a RD access is enough. Both return a std::unique_ptr. The API guarantees that only one thread can do RW-access for a given object. Notice that the calling thread can have multiple RD access and WR access to the same object simulnateusly. The check is only against \"other threads\". There are 2 APIs:

  • ref_rd_snapshot(): gets a RD access, and an assertion checks that there is no other thread has wr_snapshot during the lifetime of the returned std::unique_ptr

  • ref_wr_snapshot(): gets a RW access, and an assertion checks that there is no other thread has rd_snapshot during the lifetime of the returned std::unique_ptr.

Note

Updating an atomic counter inside an object does not require a RW-access, but a rd_snapshot because it does not trigger memory allocation/deallocation. Adding/deleting elements requires a wr_snapshot.

  • Creating an object requires a ref_wr_snapshot.

  • The only way to pass references across threads is with std::unique_ptr or calling to the library which will create a std::unique_ptr.

Note

If a std::unique_ptr created from a snapshot is passed to another thread, the creator thread is still the owner of the thread pointer. If this is not the intention, it may be safer for the new thread to call the library to access ownership.

This approach is somewhat similar to a hazzard pointer. The snapshot API indicates intention to modify (which can delete), but instead of failing with a nullptr return, we trigger a compile failure because it should never be the case. Each lgraph/lnast can be updated in parallel, but only if they are independent. The assertion is to check that there is no bug.

LiveHD uses 3 main techniques to perform memory management.

"},{"location":"livehd/03-memory/#raii-or-stdunique_ptr","title":"RAII or std::unique_ptr","text":"

When an object is created and there is a single user, the code should use RAII or std::unique_ptr. RAII means that when the object is out of scope, the memory is recycled. std::unique_ptr will automatically call the destructor when the reference use is zero.

  • In LiveHD, RAII references should not be passed between threads.
  • std::unique_ptr can be passed between threads.
"},{"location":"livehd/03-memory/#snapshot","title":"snapshot","text":"

For objects that can be shared across threads, the snapshot API must be used.

"},{"location":"livehd/03-memory/#stdshared_ptr","title":"std::shared_ptr","text":"

std::shared_ptr is one of the \"heavy\" cost options for garbage collection. In LiveHD, we do not use the atomic std::shared_ptr. The std::shared_ptr are NOT allowed to be passed between threads. It is a memory management for data only within a thread or compiler pass.

To avoid reference counting overheads, when passed to methods, a const std::shared<XX> & should be used nearly in all the cases.

"},{"location":"livehd/04-api/","title":"C++ API","text":"

LiveHD is built on C++17, LGraph and LNAST are the two key data structures inside LiveHD to support new hardware design. * LGraph stands for Live Graph. It is graph or netlist data structure at the core of LiveHD. * LNAST stands for Language Neutral AST. It is an Abstract Syntax Tree (AST) designed to be simple but to allow the translation from multiple languages like CHIRRTL, Verilog, and Pyrope.

While LNAST could be seen as a high level API with control flow information, LGraph is a lower level graph API where many LNAST high level constructs are simplified.

There is a division of functionality between LNAST and LGraph:

  • LNAST: Language Neutral AST, the high level tree based representation/API

    • Bundles:
      • Flatten fields (only flat attributes passed to LGraph)
      • Find IOs (inputs and outputs). Populate the sub_node accordingly.
      • Detect as array if legal bundle index.
    • Constant propagation (comptime decision)
    • Linear time compiler passes (dead code elimination, constant folding) but not complex (GVN, SAT...)
    • Lgraph creation
      • Inline small LNASTs
      • Partition too large LGraphs
    • Type checking
    • Unroll for and while loops
  • LGraph: Live Graph, the low level graph/netlist level based representation/API

    • Attributes
      • Bitwidth
      • Debug flag
    • Complex optimizations
      • cprop (Peephole, constant folding, ...)
      • lecopt, Logic Equivalence based optimizations
      • synthesis
"},{"location":"livehd/05-lgraph/","title":"LGraph","text":"

Warning

LiveHD is beta under active development and we keep improving the API. Semantic versioning is a 0.+, significant API changes are expect.

The LGraph is built directly through LNAST to LGraph translations. The LNAST builds a gated-SSA which is translated to LGraph. Understanding the LGraph is needed if you want to build a LiveHD pass.

LGraph is a graph or netlist where each vertex is called a node, and it has a cell type and a set of input/output pins.

"},{"location":"livehd/05-lgraph/#api","title":"API","text":"

A single LGraph represents a single netlist module. LGraph is composed of nodes, node pins, edges, cell types, and tables of attributes. An LGraph node is affiliated with a cell node type and each type defines different amounts of input and output node pins. For example, a node can have 3 input ports and 2 output pins. Each of the input/output pins can have many edges to other graph nodes. Every node pin has an affiliated node pid. In the code, every node_pin has a Port_ID.

A pair of driver pin and sink pin constitutes an edge. The bitwidth of the driver pin determines the edge bitwidth.

"},{"location":"livehd/05-lgraph/#node-node_pin-and-edge-construction","title":"Node, Node_pin, and Edge Construction","text":"
  • create a node without associated type (edges can not be created until a type is associated)
new_node = lg->create_node()\n//note: type and/or bits still need to be assigned later\n
  • create node with node type assigned
new_node = lg->create_node(Node_type_Op)\n//note: recommended way if you know the target node type\n
  • create a constant node
new_node = lg->create_node_const(value)\n//note: recommended way to create a const node\n
  • setup default driver pin for pin_0 of a node
driver_pin = new_node.setup_driver_pin();\n//note: every cell in LGraph has only one driver pin, pin0\n
  • setup default sink pin for pin_0 of a node
sink_pin = new_node.setup_sink_pin()\n//note: when you know the node type only has one input pin\n
  • setup sink pin for pin_x of a node, for more information, please refer to the Cell type section. For quick reference of the sink pin names of each cell type, please see cell.cpp

    sink_pin = new_node.setup_sink_pin(\"some_name\")\n

  • add an edge between driver_pin and sink_pin

driver_pin.connect(sink_pin);\n
  • get the driver node of an edge
driver_node = edge.driver.get_node()\n
  • use node as the index/key for a container
absl::flat_hash_map<Node::Compact, int> my_map;\nmy_map[node1.get_compact()] = 77;\nmy_map[node2.get_compact()] = 42;\n...\n
  • use node_pin as the index/key for a container
absl::flat_hash_map<Node_pin::Compact, int> my_map;\nmy_map[node_pin1.get_compact()] = 14;\nmy_map[node_pin2.get_compact()] = 58;\n...\n
  • get the node_pin back from a Node_pin::Compact
Node_pin dpin(lg, some_dpin.get_compact())\n
  • get the node back from a Node::Compact
Node node(lg, some_node.get_compact())\n
  • create a LGraph input(output) with the name
new_node_pin = lg->add_graph_input(std::string_view)\n
  • debug information of a node
node.debug_name()\n
  • debug information of a node_pin
node_pin.debug_name()\n
  • iterate output edges and get node/pin information from it
for (auto &out : node.out_edges()) {\nauto  dpin       = out.driver;\nauto  dpin_pid   = dpin.get_pid();\nauto  dnode_name = dpin.get_node().debug_name();\nauto  snode_name = out.sink.get_node().debug_name();\nauto  spin_pid   = out.sink.get_pid();\nauto  dpin_name  = dpin.has_name() ? dpin.get_name() : \"\";\nauto  dbits      = dpin.get_bits();\n\nfmt::print(\" {}->{}[label=\\\"{}b :{} :{} :{}\\\"];\\n\"\n, dnode_name, snode_name, dbits, dpin_pid, spin_pid, dpin_name);\n}\n
"},{"location":"livehd/05-lgraph/#non-hierarchical-traversal-iterators","title":"Non-Hierarchical Traversal Iterators","text":"

LGraph allows forward and backward traversals in the nodes (bidirectional graph). The reason is that some algorithms need a forward and some a backward traversal, being bidirectional would help. Whenever possible, the fast iterator should be used.

for (const auto &node:lg->fast())     {...} // unordered but very fast traversal\n\nfor (const auto &node:lg->forward())  {...} // propagates forward from each input/constant\n\nfor (const auto &node:lg->backward()) {...} // propagates backward from each output\n

The LGraph iterator such as for(auto node: g->forward()) do not visit graph input and outputs.

// simple way using lambda\nlg->each_graph_input([&](const Node_pin &pin){\n\n\u00a0\u00a0//your operation with graph_input node_pin;\n\n});\n
"},{"location":"livehd/05-lgraph/#hierarchical-traversal-iterators","title":"Hierarchical Traversal Iterators","text":"

LGraph supports hierarchical traversal. Each sub-module of a hierarchical design will be transformed into a new LGraph and represented as a sub-graph node in the parent module. If the hierarchical traversal is used, every time the iterator encounters a sub-graph node, it will load the sub-graph persistent tables to the memory and traverse the subgraph recursively, ignoring the sub-graph input/outputs. This cross-module traversal treats the hierarchical netlist just like a flattened design. In this way, all integrated third-party tools could automatically achieve global design optimization or analysis by leveraging the LGraph hierarchical traversal feature.

for (const auto &node:lg->forward(true)) {...}\n
"},{"location":"livehd/05-lgraph/#edge-iterators","title":"Edge Iterators","text":"

To iterate over the input edges of node, simply call:

for (const auto &inp_edge : node.inp_edges()) {...}\n

And for output edges:

for (const auto &out_edge : node.out_edges()) {...}\n
"},{"location":"livehd/05-lgraph/#attribute-design","title":"Attribute Design","text":"

Design attribute stands for the characteristic given to a LGraph node or node pin. For instance, the characteristic of a node name and node physical placement. Despite a single LGraph stands for a particular module, it could be instantiated multiple times. In this case, same module could have different attribute at different hierarchy of the netlist. A good design of attribute structure should be able to represent both non-hierarchical and hierarchical characteristic.

"},{"location":"livehd/05-lgraph/#non-hierarchical-attribute","title":"Non-Hierarchical Attribute","text":"

Non-hierarchical LGraph attributes include pin name, node name and line of source code. Such properties should be the same across different LGraph instantia- tions. Two instantiations of the same LGraph module will have the exact same user-defined node name on every node. For example, instantiations of a subgraph-2 in both top and subgraph-1 would maintain the same non-hierarchical attribute table.

node.set_name(std::string_view name);\n
"},{"location":"livehd/05-lgraph/#hierarchical-attribute","title":"Hierarchical attribute","text":"

LGraph also support hierarchical attribute. It is achieved by using a tree data structure to record the design hierarchy. In LGraph, every graph has a unique id (lg_id), every instantiation of a graph would form some nodes in the tree and every tree node is indexed by a unique hierarchical id (hid). We are able to identify a unique instantiation of a graph and generate its own hierarchical attribute table. An example of hierarchical attribute is wire-delay.

node_pin.set_delay(float delay);\n
"},{"location":"livehd/05-lgraph/#cell-type","title":"Cell type","text":"

For each LGraph node, there is a specific cell type. This section explains the operation to perform for each node. It includes a precise way to compute the maximum and minimum value for the output.

In LGraph, the cell types operate like having unlimited precision with signed numbers. Most HDL IRs have a type for signed inputs and another for unsigned. LiveHD handles the superset (sign and unlimited precision) with a single node. In LGraph, an unsigned value is signed value that is always positive. This simplifies the mixing and conversions which simplifies the passes. The drawback is that the export may have to convert back to signed/unsigned for some languages like Verilog.

Maybe even more important is that all the LGraph cell types generate the same result if the input is sign-extended. This has implications, for example a typical HDL IR type like \"concat\" does not exist because the result is dependent on the inputs size. This has the advantage of simplifying the decisions of when to drop bits in a value. It also makes it easier to guarantee no loss of precision. Any drop of precision requires explicit handling with operations like and-gate with masks or Shifts.

The document also explains corner cases in relationship to Verilog and how to convert to/from Verilog semantics. These are corner cases to deal with sign and precision. Each HDL may have different semantics, the Verilog is to showcase the specifics because it is a popular HDL.

All the cell types are in core/cell.hpp and core/cell.cpp. The type enumerate is called Ntype. In general the nodes have a single output with the exception of complex nodes like subgraphs or memories. The inputs is a string in lower case or upper case. Upper case ('A') means that many edges (or output drivers) can connect to the same node input or sink pin, lower case ('a') means that only a driver can connect to the input or sink pin.

Each cell type can be called directly with Pyrope using a low level RTL syntax. This is useful for debugging not for general use as it can result in less efficient LNAST code.

An example of a multi-driver sink pin is the Sum cell which can do Y=3+20+a0+a3 where A_{0} = 3, A_{1} = 20, A_{2} = a0, and A_{3} = a3. Another way to represent in valid Pyrope RTL syntax is:

Y = __sum(A=(3,20,a0,a3))\n

An example if single driver sink pin is the SRA cell which can do Y=20>>3. It is lower case because only one driver pin can connect to 'a' and 'b'. Another way to represent a valid Pyrope RTL syntax is:

Y = __sra(a=20,b=3)\n

The section includes description on how to compute the maximum (max) and minimum (min) allowed result range. This is used by the bitwidth inference pass. To ease the explanation, a sign value means that the result may be negative (a.sign == a.min<0). known is true if the result sign is known (a.known == a.max<0 or a.min>=0), either positive or negative (neg == a.max<0). The cells explanation also requires the to compute the bit mask (a.mask == (1<<a.bits)-1).

For any value (a), the number of bits required (bits) is a.bits = log2(absmax(a.max,a.min))+1.

"},{"location":"livehd/05-lgraph/#sum","title":"Sum","text":"

Addition and substraction node is a single cell Ntype that performs 2-complement additions and substractions with unlimited precision.

graph LR cell --Y--> c(fa:fa-spinner) a(fa:fa-spinner) --A--> cell[Sum]:::cell b(fa:fa-spinner) --B--> cell classDef cell stroke-width:3px

If the inputs do not have the same size, they are sign extended to all have the same length.

Forward Propagation

  • Value:
    %Y = A.reduce('+') - B.reduce('+')\n
  • Max/min:
    %max = 0\n%min = 0\nfor a in A {\n  %max += A.max\n  %min += A.min\n}\nfor b in B {\n  %max -= b.min\n  %min -= b.max\n}\n

Backward Propagation

Backward propagation is possible when all the inputs but ONE are known. The algorithm can check and look for the inputs that have more precision than needed and reduce the max/min backwards.

For example, if and all the inputs but one A are known (max/min has the max/min computed for all the inputs but the unknown one)

A_{unknown}.max = Y.max - max \nA_{unknown}.min = Y.min - min \n

If the unknow is in port B:

B_{unknown}.max = min - T.min\nB_{unknown}.min = max - Y.max\n

Verilog Considerations

In Verilog, the addition is unsigned if any of the inputs is unsigned. If any input is unsigned. all the inputs will be \"unsigned extended\" to match the largest value. This is different from Sum_Op semantics were each input is signed or unsigned extended independent of the other inputs. To match the semantics, when mixing signed and unsigned, all the potentially negative inputs must be converted to unsign with the Ntype_op::Tposs.

logic signed [3:0] a = -1\nlogic signed [4:0] c;\n\nassign c = a + 1'b1;\n

The previous Verilog example extends everything to 5 bits (c) UNSIGNED extended because one of the inputs is unsigned (1b1 is unsigned in verilog, and 2sb1 is signed +1). LGraph semantics are different, everything is signed.

c = 5b01111 + 5b0001 // this is the Verilog semantics by matching size\nc == -16 (!!)\n

The Verilog addition/substraction output can have more bits than the inputs. This is the same as in LGraph Sum. Nevertheless, Verilog requires to specify the bits for all the input/outputs. This means that whenever Verilog drops precision an AND gate must be added (or a SEXT for signed output). In the following examples only the 'g' and 'h' variables needed.

  wire [7:0] a;\nwire [7:0] b;\nwire [6:0] c;\nwire [8:0] f = a + b; // f = __sum(a,b)  // a same size as b\nwire [8:0] f = a + c; // f = __sum(a,__get_mask(c,-1))\nwire [7:0] g = a + b; // g = __and(__sum(a,b),0x7F)\nwire [6:0] h = a + b; // h = __and(__sum(a,b),0x3F)\n

Peephole Optimizations

  • Y = x-0+0+... becomes Y = x+...
  • Y = x-x+... becomes Y = ...
  • Y = x+x+... becomes Y = (x<<1)+...
  • Y = (x<<n)+(y<<m) where m>n becomes Y = (x+y<<(m-n)<<n
  • Y = (~x)+1+... becomes Y = ...-x
  • Y = a + (b<<n) becomes Y = {(a>>n)+b, a&n.mask}
  • Y = a - (b<<n) becomes Y = {(a>>n)-b, a&n.mask}
  • If every x,y... lower bit is zero Y=x+y+... becomes Y=((x>>1)+(y>>1)+..)<<1
"},{"location":"livehd/05-lgraph/#mult","title":"Mult","text":"

Multiply operator. There is no cell type that combines multiplication and division because unlike in Sum. The reason is that with integers the order of multiplication/division changes the result even with unlimited precision integers (a*(b/c) != (a*b)/c).

graph LR cell --Y--> c(fa:fa-spinner) a(fa:fa-spinner) --A--> cell[Mult]:::cell classDef cell stroke-width:3px

Forward Propagation

  • Value:
    Y = A.reduce('*')\n
  • Max/min:
    var tmax = 1\nvat tmin = 1\nvar sign  = 0\nfor i in A {\n  tmax *= maxabs(A.max, A.min)\n  tmin *= minabs(A.max, A.min)\n  known = false                when min<0 and max>0\n  sign += 1                    when max<0\n}\nif know { // sign is know\n  if sign & 1 { // negative\n    %max = -tmin\n    %min = -tmax\n  }else{\n    %max = tmax\n    %min = tmin\n  }\n}else{\n  %max =  tmax\n  %min = -tmax\n}\n

Backward Propagation

If only one input is missing, it is possible to infer the max/min from the output and the other inputs. Like in the sum case, if all the inputs but one and the output is known, it is possible to backward propagate to further constraint the unknown input.

A_{unknown}.max = Y.max / A.min\nA_{unknown}.min = Y.min / A.max\n

Verilog Considerations

Unlike the Sum, the Verilog 2 LiveHD translation does not need to extend the inputs to have matching sizes. Multiplying/dividing signed and unsigned numbers has the same result. The bit representation is the same if the result was signed or unsigned.

LiveHD mult node result (Y) number of bits can be more efficient than in Verilog. E.g: if the max value of A0 is 3 (2 bits) and A1 is 5 (3bits). If the result is unsigned, the maximum result is 15 (4 bits). In Verilog, the result will always be 5 bits. If the Verilog result was to an unsigned variable. Either all the inputs were unsigned, or there should pass to an get_mask to force the MSB as positive. This extra bit will be simplified but it will notify LGraph that the output is to be treated as unsigned.

Peephole Optimizations

  • Y = a*1*... becomes Y=a*...
  • Y = a*0*... becomes Y=0
  • Y = power2a*... becomes Y=(...)<<log2(power2a)
  • Y = (power2a+power2b)*... becomes tmp=... ; Y = (tmp+tmp<<power2b)<<(power2a-power2b) when power2a>power2b
  • Y = (power2a-power2b)*... becomes tmp=... ; Y = (tmp-tmp<<power2b)<<(power2a-power2b) when power2a>power2b
"},{"location":"livehd/05-lgraph/#div","title":"Div","text":"

Division operator. The division operation is quite similar to the inverse of the multiplication, but a key difference is that only one driver is allowed for each input ('a' vs 'A').

graph LR cell --Y--> c(fa:fa-spinner) a(fa:fa-spinner) --a--> cell[Div]:::cell b(fa:fa-spinner) --b--> cell classDef cell stroke-width:3px

Forward Propagation

  • Value:
    Y = a/b\n
  • Max/min:
    %max = a.max/b.min\n%min = a.min/b.max\n\nfor i in a.max,a.min {\n  for j in b.max,b.min {\n     next        when j == 0\n     tmp = i / j\n     %max = tmp   when tmp > max\n     %min = tmp   when tmp < min\n  }\n}\n

Backward Propagation

The backward propagation from the division can extracted from the forward propagation. It is a simpler case of multiplication backward propagation.

Verilog Considerations

The same considerations as in the multiplication should be applied.

Peephole Optimizations

  • Y = a/1 becomes Y=a
  • Y = 0/b becomes Y=0
  • Y = a/power2b becomes Y=a>>log2(power2b) if Y.known and !Y.neg
  • Y = a/power2b becomes Y=1+~(a>>log2(power2b)) if Y.known and Y.neg
  • Y = (x*c)/a if c.bits>a.bits becomes Y = x * (c/a) which should be a smaller division.
  • If b is a constant and Y.known and !Y.neg. From the hackers delight, we
  • know that the division can be changed for a multiplication
  • Y=(a*(((1<<(a.bits+2)))/b+1))>>(a.bits+2) If a sign is not known. Then `Y
  • = Y.neg? (~Y_unsigned+1):Y_unsigned`
"},{"location":"livehd/05-lgraph/#modulo-how-to-model","title":"Modulo (how to model)","text":"

There is no mod cell (Ntype_op::Mod) in LGraph. The reason is that a modulo different from a power of 2 is very rare in hardware. If the language supports modulo operations, they must be translated to division/multiplication.

y = a mod b\n

It is the same as:

y = a-b*(a/b)\n

If b is a power of 2, the division optimization will transform the modulo operation to:

y = a - (a>>n)<<n\n

The add optimization should reduce it to:

y = a & n.mask\n
"},{"location":"livehd/05-lgraph/#not","title":"Not","text":"

Bitwise Not operator

graph LR cell --Y--> c(fa:fa-spinner) a(fa:fa-spinner) --a--> cell[Div]:::cell classDef cell stroke-width:3px

Forward Propagation

  • Value:
    Y = ~a\n
  • Max/min:
    %max = max(~a.max,~a.min)\n%min = min(~a.max,~a.min)\n

Backward Propagation

a.max = max(~Y.max,~Y.min)\na.min = min(~Y.max,~Y.min)\n

Verilog Considerations*

Same semantics as verilog

Peephole Optimizations

No optimizations by itself, it has a single input. Other operations like Sum_Op can optimize when combined with Not_Op.

"},{"location":"livehd/05-lgraph/#and","title":"And","text":"

And is a typical AND gate with multiple inputs. All the inputs connect to pin 'A' because input order does not matter. The result is always a signed number.

digraph And {\n    rankdir=LR;\n    size=\"1,0.5\"\n\n    node [shape = circle]; And;\n    node [shape = point ]; q0\n    node [shape = point ]; q\n\n    q0 -> And [ label =\"A\" ];\n    And  -> q [ label = \"Y\" ];\n}\n
"},{"location":"livehd/05-lgraph/#forward-propagation","title":"Forward Propagation","text":"
  • \\(Y = \\forall_{i=0}^{\\infty} Y \\& A_{i}\\)
  • \\(m = \\forall_{i=0}^{\\infty} min(m,A_{i}.bits)\\)
  • \\(Y.max = (1\\ll m)-1\\)
  • \\(Y.min = -Y.max-1\\)
"},{"location":"livehd/05-lgraph/#backward-propagation","title":"Backward Propagation","text":"

The And cell has a significant backpropagation impact. Even if some inputs had more bits, after the And cell the upper bits are dropped. This allows the back propagation to indicate that those bits are useless.

  • $a.max = Y.max $
  • $a.min = -Y.max-1 $
"},{"location":"livehd/05-lgraph/#other-considerations","title":"Other Considerations","text":""},{"location":"livehd/05-lgraph/#peephole-optimizations","title":"Peephole Optimizations","text":""},{"location":"livehd/05-lgraph/#comparators","title":"Comparators","text":"

LT, GT, EQ

There are only 3 comparators. Other typically found like LE, GE, and NE can be created by simply negating one of the LGraph comparators. GT = ~LE, LT = ~GE, and NE = ~EQ.

"},{"location":"livehd/05-lgraph/#forward-propagation_1","title":"Forward Propagation","text":"
  • Y = A LT B

  • Y = A0 LT B and A1 LT B

  • Y = A0 LT B0 and A1 LT B0 and A0 LT B1 and A1 LT B1

"},{"location":"livehd/05-lgraph/#backward-propagation_1","title":"Backward Propagation","text":""},{"location":"livehd/05-lgraph/#peephole-optimizations_1","title":"Peephole Optimizations","text":""},{"location":"livehd/05-lgraph/#other-considerations_1","title":"Other Considerations","text":"

Verilog treats all the inputs as unsigned if any of them is unsigned. LGraph treats all the inputs as signed all the time.

size A B Operation a==b S S EQ(a,b) a==b S U EQ(a,b) a==b U S EQ(a,b) a==b U U EQ(a,b) a< b S S LT(a,b) a< b S U LT(a,Tposs(b)) a< b U S LT(Tposs(a),b) a< b U U LT(Tposs(a),Tposs(b))"},{"location":"livehd/05-lgraph/#shl_op","title":"SHL_op","text":"

Shift Left performs the typical shift left when there is a single amount (a<<amt). The allow supports multiple left shift amounts. In this case the shift left is used to build one hot encoding mask. (1<<(1,2) == (1<<1)|(1<<2))

The result for when there are not amounts (a<<()) is -1. Notice that this is not ZERO but -1. The -1 means that all the bits are set. The reason is that when there are no offsets in the onehot encoding, the default functionality is to select all the bit masks, and hence -1.

"},{"location":"livehd/05-lgraph/#sra_op","title":"SRA_op","text":"

Logical or sign extension shift right.

"},{"location":"livehd/05-lgraph/#verilog-considerations","title":"Verilog Considerations","text":"

Verilog has 2 types of shift >> and >>>. The first is unsigned right shift, the 2nd is arithmetic right shift. LGraph only has arithmetic right shift (ShiftRigt_op). The verilog translation should make the value unsigned (ShiftRigt(Join(0,a),b)) before calling the shift operation. Conversely, for a >>> if the input is Verilog unsigned (ShiftRigt(a,b))

"},{"location":"livehd/05-lgraph/#mux_op","title":"Mux_op","text":""},{"location":"livehd/05-lgraph/#forward-propagation_2","title":"Forward Propagation","text":"
  • \\(Y = P_{(1+P_{0}}\\)
  • \\(Y.max = (1\\ll m)-1\\)
  • \\(Y.max = \\forall_{i=0}^{\\infty} P_{i}.max\\)
  • \\(Y.max = \\forall_{i=0}^{\\infty} P_{i}.min\\)
"},{"location":"livehd/05-lgraph/#backward-propagation_2","title":"Backward Propagation","text":""},{"location":"livehd/05-lgraph/#peephole-optimizations_2","title":"Peephole Optimizations","text":""},{"location":"livehd/05-lgraph/#other-considerations_2","title":"Other Considerations","text":""},{"location":"livehd/05-lgraph/#lut_op","title":"LUT_op","text":""},{"location":"livehd/05-lgraph/#and_op","title":"And_op","text":"

reduce AND a =u= -1 // unsigned equal

"},{"location":"livehd/05-lgraph/#or_op","title":"Or_op","text":"

reduce OR a != 0

"},{"location":"livehd/05-lgraph/#xor_op","title":"Xor_op","text":"

reduce xor is a chain of XORs.

"},{"location":"livehd/05-lgraph/#const_op","title":"Const_op","text":""},{"location":"livehd/05-lgraph/#sflop_op","title":"SFlop_op","text":""},{"location":"livehd/05-lgraph/#aflop_op","title":"AFlop_op","text":""},{"location":"livehd/05-lgraph/#fflop_op","title":"FFlop_op","text":""},{"location":"livehd/05-lgraph/#latch_op","title":"Latch_op","text":""},{"location":"livehd/05-lgraph/#get_mask_op","title":"Get_mask_op","text":"

Inputs - a, mask Get_mask (a, mask) Functionality - Output contains only those bits a[i], for which mask[i] = 1, other bits a[i] for which mask[i] = 0, are dropped. a & mask are interpreted as signed numbers and sign extended to the size of the other, if required. eg - Get_mask (0sb11000011, 0sb10101010) = 0sb1001 Get_mask (0sb11110000, 0sb00001111) = 0sb0000 Get_mask (0sb0011, 0sb10) = 0sb001 Get_mask (0sb10, 0sb1010) = 0sb11

"},{"location":"livehd/05-lgraph/#set_mask_op","title":"Set_mask_op","text":"

Inputs - a, value, mask Set_mask(a, mask, value) Functionality - Replaces all bits a[i] for which mask[i] = 1, with value[i] Retains all bits a[i] for which mask[i] = 0. // Check - if a, value are signed, actually none of them should be extended and their signs should not matter, but a might need to retain it's sign eg - Set_mask (0b101 01 010, 0sb000 11 000, 0b001 10 011) = 0sb 101 10 010

"},{"location":"livehd/05-lgraph/#sext_op-sign-extend","title":"Sext_op (Sign extend)","text":"

Inputs - a, b Sext (a, b) Selects only bits a[b:0] dropping all remaining MSBs. The selected a[b:0] is interpretded as a signed value, a's sign does not matter,b conyains the MSB index and hence is always unsigned/ positive eg Sext (0b10101010, 4) = 0sb01010 = 0xA = +10 Sext (0b10101010, 5) = 0sb101010 = 0x2A = -22

"},{"location":"livehd/05-lgraph/#memory_op","title":"Memory_op","text":"

Memory is the basic block to represent SRAM-like structures. Any large storage will benefit from using memory arrays instead of flops, which are slower to simulate. These memories are highly configurable.

digraph Memory {\n    rankdir=LR;\n    size=\"2,1\"\n\n    node [shape = circle]; Memory;\n    node [shape = point ]; q0\n    node [shape = point ]; q1\n    node [shape = point ]; q2\n    node [shape = point ]; q3\n    node [shape = point ]; q4\n    node [shape = point ]; q5\n    node [shape = point ]; q6\n    node [shape = point ]; q7\n    node [shape = point ]; q8\n    node [shape = point ]; q9\n    node [shape = point ]; q10\n    node [shape = point ]; q\n\n    q0 -> Memory [ label =\"a (addr)\" ];\n    q1 -> Memory [ label =\"b (bits)\" ];\n    q2 -> Memory [ label =\"c (clock)\" ];\n    q3 -> Memory [ label =\"d (data in)\" ];\n    q4 -> Memory [ label =\"e (enable)\" ];\n    q5 -> Memory [ label =\"f (fwd)\" ];\n    q6 -> Memory [ label =\"l (latency)\" ];\n    q7 -> Memory [ label =\"m (wmask)\" ];\n    q8 -> Memory [ label =\"p (posedge)\" ];\n    q9 -> Memory [ label =\"s (size)\" ];\n    q10 -> Memory [ label =\"w (wmode)\" ];\n    Memory  -> q [ label =\"Q (data out)\" ];\n}\n
  • s (size) is for the array size in number of entries
  • b (bits) is the number of bits per entry
  • f (fwd) points to a 0/1 constant driver pin to indicate if writes forward value (0b0 for write-only ports). Effectively, it means zero cycles read latency when enabled. fwd is more than just setting latency=0. Even with latency zero, the write delay affects until the result is visible. With fwd enabled, the write latency does not matter to observe the results. This requires a costly forwarding logic.
  • c,d,e,q... are the memory configuration, data, address ports

Ports (a,c...p,w) are arrays/vectors to support multiported memories. If a single instance exists in a port, the same is used across all the ports. E.g: if clock (c) is populated:

mem1.c = clk1 // clk for all the memory ports\n\nmem2.c[0] = clk1 // clock for memory port 0\nmem2.c[1] = clk2 // clock for memory port 1\nmem2.c[2] = clk2 // clock for memory port 2\n

Each memory port (rd, wr, or rd/wr) has the following ports:

  • a (addr) points to the driver pin for the address. The address bits should match the array size (ceil(log2(s)))
  • c (clock) points to the clock driver pin
  • d (data_in) points to the write data driver pin (read result is in q port).
  • e (enable) points to the driver pin for read/write enable.
  • l (latency) points to an integer constant driver pin (2 bits always). For writes latency from 1 to 3, for reads latency from 0 to 3
  • w (wmask) Points to the write mask (1 == write, 0==no write). The mask bust be a big as the number of bits per entry (b). The wmask pin can be disconnected which means no write mask (a write will write all the bits).
  • p (posedge) points to a 1/0 constant driver pin
  • m (mode) points to the driver pin or switching between read (0) and write mode (1) (single bit)
  • Q (data_out) is a driver pin with the data read from the memory

All the entries but the wmask must be populated. If the wmask is not set, a full write size is expected. Read-only ports do not have data and wmask fields if the write use the low ports (0,1...). By placing the read-only ports to the high numbers, we can avoid populating the wmask (m) and data out (q) ports. If the read ports use low port numbers those fields must be populated to allow the correct matching between write port (a[n]) and write result (q[n]).

All the ports must be populated with the correct size. This is important because some modules access the field by bit position. If it is not used, it will point to a zero constant with the correct number of bits. The exception to this is wmask which, if b indicates 8 bits per entry, will be equivalent to 0xFF. Setting wmask to 0b1 will mean a 1 bit zero, and the memory will be incorrectly operated.

The memory usually has power of two sizes. If the size is not a power of 2, the address is rounded up. Writes to the invalid addresses will generated random memory updates. Reads should read random data.

"},{"location":"livehd/05-lgraph/#forward-propagation_3","title":"Forward Propagation","text":""},{"location":"livehd/05-lgraph/#backward-propagation_3","title":"Backward Propagation","text":""},{"location":"livehd/05-lgraph/#other-considerations_3","title":"Other Considerations","text":""},{"location":"livehd/05-lgraph/#peephole-optimizations_3","title":"Peephole Optimizations","text":""},{"location":"livehd/05-lgraph/#subgraph_op","title":"SubGraph_op","text":"

And_Op: bitwise AND with 2 outputs single bit reduction (RED) or bitwise Y = VAL&..&VAL ; RED= &Y

"},{"location":"livehd/05-lgraph/#forward-propagation_4","title":"Forward Propagation","text":"
  • \\(Y = \\left\\{\\begin{matrix} VAL>>OFF & SZ==0 \\\\ (VAL>>OFF) \\& (1<<SZ)-1) & otherwise \\end{matrix}\\right.\\)
  • \\(Y.max = \\left\\{\\begin{matrix} VAL.max>>OFF & SZ==0 \\\\ (VAL.max>>OFF) \\& (1<<SZ)-1) & otherwise \\end{matrix}\\right.\\)
  • \\(Y.min = 0\\)
  • \\(Y.sign = 0\\)
"},{"location":"livehd/05-lgraph/#backward-propagation_4","title":"Backward Propagation","text":"

The sign can not be backward propagated because Pick_Op removes the sign no matter the input sign.

"},{"location":"livehd/05-lgraph/#to-be-continued","title":"To be continued ...","text":""},{"location":"livehd/05-lgraph/#optimization","title":"Optimization","text":"

Not all the nodes have the same complexity overhead. When performing peephole optimization is possible to trade one set of nodes for others. In general, we have this set of overheads:

  • 0 overhead: not, get_mask, set_mask, sext, and SHL/SRA with constant shift amounts. The rational is that those are just \"wiring\" cells to connect or extract wires across. The NOT gate is not really zero, but it could be easily mixed with sorrounding cells.

  • 1 overhead: And, Or, Xor, LUT, Mux

  • 3 overhead: LT, GT, EQ, Ror

  • 4 overhead: Less than 4 bit output Sum, and SHL/SRA with non-compile time shift amount. This can be costly an require hardware like barrel shifters.

  • 5 overhead: large Sum, SHL/SRA.

  • 6 Overhead: Mult/Div

If a overhead level can be elininated having a small number of different cells with a smaller overhead level,the translation makes sense. Notice the \"small number of cells\", after all everything can be translated to nand gates. A 3x factor is somewhat reasonable. This means that a 5-level overhead is fine to be replaced for 3 4-level (or 3 3-level) but not for 4 4-level overhead. Zero overhead cells are not included in the list of cells in the replacement.

This is a heuristic. Once works, it is a nice target to use AI to decide when/if a transformation is worth.

"},{"location":"livehd/06-lnast/","title":"LNAST","text":"

LNAST stands for Language-Neutral Abstract Syntax Tree, which is constituted of Lnast_nodes and indexed by a tree structure.

LiveHD has two main data structures: LNAST and LGraph. The LNAST is the higher level representation with a tree structure. The LGraph is the lower level representation with a graph structure. Each node in LGraph has a LNAST equivalent node, but LNAST is more high level and several nodes in LNAST may not have a one-to-one mapping to LGraph.

Each Lnast_node should has a specific node type and contain the following information from source code tokens

(a) line number (b) pos_start, pos_end (c) string_view (optional)

"},{"location":"livehd/06-lnast/#function-overloadings-of-node-data-construction","title":"Function Overloadings of Node Data Construction","text":"

Every node construction method has four function overloadings. For example, to construct a Lnast_node with a type of reference, we could use one of the following functions:

// C++\nauto node_ref = Lnast_node::create_ref(\"foo\");     auto node_ref = Lnast_node::create_ref(\"foo\", line_num);     auto node_ref = Lnast_node::create_ref(\"foo\", line_num, pos1, pos2);     auto node_ref = Lnast_node::create_ref(token);   

In case (1), you only knows the variable name is \"foo\". In case (2), you know the variable name and the corresponding line number. In case (3), you know the variable name, the line number, and the charactrer position. In case (4), you are building LNAST from your HDL AST and you already have the Token. The toke should have line number, positions, and string_view information.

"},{"location":"livehd/06-lnast/#another-example","title":"Another Example","text":"

If you don't care the string_view to be stored in the lnast node, just leave it empty for set \"foo\" for it. This is true for many of the operator node, for example, to build a node with type of assign.

// C++\nauto node_assign = Lnast_node::create_assign();   auto node_assign = Lnast_node::create_assign(line_num);     auto node_assign = Lnast_node::create_assign(line_num, pos1, pos2);   auto node_assign = Lnast_node::create_assign(token); // The token is not necessary to have a string_view  \n
"},{"location":"livehd/06-lnast/#lnast-node-types","title":"LNAST Node Types","text":"top stmts if uif for func_call func_def assign dp_assign mut bit_and bit_or bit_not bit_xor reduce_or logical_and logical_or logical_not plus minus mult div mod shl sra sext set_mask get_mask mask_and mask_popcount mask_xor is ne eq lt le gt ge ref const range tuple_concat tuple_add tuple_get tuple_set attr_set attr_get err_flag phi hot_phi invalid"},{"location":"livehd/06-lnast/#scope","title":"Scope","text":""},{"location":"livehd/06-lnast/#top","title":"top","text":"

Every LNAST has a top node as the root. A top node has one or more child nodes, which can only be stmts.

<top> --| <stmts>\n        | <stmts>\n        | <stmts>\n        |  ...\n
"},{"location":"livehd/06-lnast/#stmts","title":"stmts","text":"

A stmts node represents a sequence of statements.

<stmts> --| <const>     : scope name\n          | <assign>\n          | <plus>\n          | <func_def>\n          | ...\n
"},{"location":"livehd/06-lnast/#statements","title":"Statements","text":""},{"location":"livehd/06-lnast/#if","title":"if","text":"

An if node represents a conditional branch, which can be a statement or an expression.

<if> --| <ref/const> : if condition variable\n       | <stmts>     : if branch\n       | <ref/const> : elif condition variable  \\  N times\n       | <stmts>     : elif branch              /\n       | <stmts>     : else branch\n
"},{"location":"livehd/06-lnast/#uif","title":"uif","text":"

Unique if. Similar to if, but add additional assertions to check if at most one condition is true.

<uif> --| <ref/const> : if condition variable\n        | <stmts>     : if branch\n        | <ref/const> : elif condition variable  \\  N times\n        | <stmts>     : elif branch              /\n        | <stmts>     : else branch\n
"},{"location":"livehd/06-lnast/#for","title":"for","text":"

A for node represents a for-loop over a range or tuple. Note that the loop must be unrolled during compilation.

<for> --| <ref>   : iterator variable\n        | <ref>   : iterated variable (tuple or range)\n        | <stmts> : for-loop body\n
"},{"location":"livehd/06-lnast/#func_def","title":"func_def","text":"

A func_def node represents a functional block with input/output arguments.

<func_def> --| <ref/const> : input arguments\n             | <ref/const> : output arguments\n             | <stmts>     : function body\n
"},{"location":"livehd/06-lnast/#func_call","title":"func_call","text":"

A func_call node represents an instantiation of a functional block.

<func_call> --| <ref/const> : Lvalue\n              | <ref>       : function reference\n              | <ref/const> : input arguments\n
"},{"location":"livehd/06-lnast/#assign","title":"assign","text":"

An assign node represents a variable assignment. Note that the Rvalue can only be a const or ref.

<assign> --| <ref>       : Lvalue\n           | <ref/const> : Rvalue\n
"},{"location":"livehd/06-lnast/#dp_assign","title":"dp_assign","text":"

the \"lhs := rhs\" assignment (dp_assign) is like the \"=\" assignment but there is no check for overflow. If the rhs has more bits than the lhs, the upper bits will be dropped.

<dp_assign> --| <ref>       : Lvalue\n              | <ref/const> : Rvalue\n
"},{"location":"livehd/06-lnast/#primitives","title":"Primitives","text":""},{"location":"livehd/06-lnast/#const","title":"const","text":"

Constant value.

<const> \"0x1234\"\n
"},{"location":"livehd/06-lnast/#ref","title":"ref","text":"

Variable.

<ref> \"variable_name\"\n
"},{"location":"livehd/06-lnast/#range","title":"range","text":"

Range.

<range> --| <ref> or <const> : from-value\n          | <ref> or <const> : to-value\n
"},{"location":"livehd/06-lnast/#unary-expressions","title":"Unary Expressions","text":"
<op> --| <ref>       : Lvalue\n       | <ref/const> : Rvalue\n
"},{"location":"livehd/06-lnast/#bit_not","title":"bit_not","text":"

Bitwise not. Flip all Rvalue bits.

"},{"location":"livehd/06-lnast/#reduce_or","title":"reduce_or","text":"

Or all Lvalue bits.

"},{"location":"livehd/06-lnast/#logical_not","title":"logical_not","text":"

Logical Not. Flip Rvalue where Rvalue must be a boolean.

"},{"location":"livehd/06-lnast/#binary-expressions","title":"Binary Expressions","text":"
<op> --| <ref>       : Lvalue\n       | <ref/const> : R-1\n       | <ref/const> : R-2\n
"},{"location":"livehd/06-lnast/#mod","title":"mod","text":"

Modulo of R-1 over R-2.

"},{"location":"livehd/06-lnast/#shl","title":"shl","text":"

Left-shift R-1 by R-2.

"},{"location":"livehd/06-lnast/#sra","title":"sra","text":"

Right-shift R-1 by R-2.

"},{"location":"livehd/06-lnast/#ne","title":"ne","text":"

Not equal to.

"},{"location":"livehd/06-lnast/#eq","title":"eq","text":"

Equal to.

"},{"location":"livehd/06-lnast/#lt","title":"lt","text":"

Less than.

"},{"location":"livehd/06-lnast/#le","title":"le","text":"

Less than or equal to.

"},{"location":"livehd/06-lnast/#gt","title":"gt","text":"

Greater than.

"},{"location":"livehd/06-lnast/#ge","title":"ge","text":"

Greater than or equal to.

"},{"location":"livehd/06-lnast/#n-ary-expressions","title":"N-ary Expressions","text":"
<op> --| <ref>       : Lvalue\n       | <ref/const> : R-1     \\\n       | <ref/const> : R-2      \\\n       | <ref/const> : R-3       2 or more values\n       | ...                    /\n       | <ref/const> : R-N     /\n
"},{"location":"livehd/06-lnast/#bit_and","title":"bit_and","text":"

Bitwise and.

"},{"location":"livehd/06-lnast/#bit_or","title":"bit_or","text":"

Bitwise or.

"},{"location":"livehd/06-lnast/#bit_xor","title":"bit_xor","text":"

Bitwise xor.

"},{"location":"livehd/06-lnast/#plus","title":"plus","text":"

Summation of R-1 to R-N.

"},{"location":"livehd/06-lnast/#minus","title":"minus","text":"

R-1 minus summation of R-2 to R-N.

"},{"location":"livehd/06-lnast/#mult","title":"mult","text":"

Product of R-1 to R-N.

"},{"location":"livehd/06-lnast/#div","title":"div","text":"

R-1 divided by product of R-2 to R-N

"},{"location":"livehd/06-lnast/#tuples","title":"Tuples","text":""},{"location":"livehd/06-lnast/#tuple_concat","title":"tuple_concat","text":"
<tuple_concat> --| <ref> : Lvalue\n                 | <ref> : R-1 (tuple)\n                 | <ref> : R-2 (tuple)\n                 | ...\n                 | <ref> : R-N (tuple)\n
"},{"location":"livehd/06-lnast/#tuple_add","title":"tuple_add","text":"
<tuple_add> --| <ref> : Lvalue\n              | <ref/const>\n              | <assign> --| <ref>       \\ Field 0\n                           | <ref/const> /\n              | <assign> --| <ref>       \\ Field 1\n                           | <ref/const> /\n              |  ...\n              | <assign> --| <ref>       \\ Field N\n                           | <ref/const> /\n
"},{"location":"livehd/06-lnast/#tuple_set","title":"tuple_set","text":"
<tuple_set> --| <ref>        : Lvalue\n              | <ref/<const> : 1st-level selection   \\\n              | ...                                   1..N selections\n              | <ref/<const> : Nth-level selection   /\n              | <ref/<const> : Rvalue\n
"},{"location":"livehd/06-lnast/#tuple_get","title":"tuple_get","text":"
<tuple_get> --| <ref>       : Lvalue\n              | <ref>       : Rvalue (selected from this value)\n              | <ref/const> : 1st-level selection   \\\n              | ...                                  1..N selections\n              | <ref/const> : Nth-level selection   /\n
"},{"location":"livehd/06-lnast/#module-input-output-and-register-declaration","title":"Module Input, Output, and Register Declaration","text":"

In LNAST, all input/output/register are defined in the node type reference with differenct prefix of string_view, \"$\" stands for input, \"%\" stands for output, and \"#\" stands for register.

"},{"location":"livehd/06-lnast/#input","title":"Input","text":"
// Pyrope\nfoo = $a\n
// Verilog\ninput a;\n
// C++\nauto node_input = Lnast_node::create_ref(\"$a\", line_num, pos1, pos2);\n
"},{"location":"livehd/06-lnast/#output","title":"Output","text":"
// Pyrope\n%out\n
// Verilog\noutput out;\n
// C++\nauto node_output = Lnast_node::create_ref(\"%out\", line_num, pos1, pos2);\n
"},{"location":"livehd/06-lnast/#register","title":"Register","text":"
// Pyrope\nreg_foo\n
// Verilog\nreg reg_foo;\n
// C++\nauto node_reg = Lnast_node::create_ref(\"reg_foo\", line_num, pos1, pos2);\n
"},{"location":"livehd/10-bazel/","title":"Bazel build","text":"

Bazel is a relatively new build system open sourced by google. The main difference with traditional Makefiles is that it checks to make sure that dependences are not lost and the builds are reproducible and hermetic. This document explains how to use Bazel in the LGraph project.

Build targets are referred to using the syntax //<relative path to BUILD file>:<executable>, where // is the path of the root livehd directory.

To build the LiveHD shell and supporting libraries, the target would be //main:all. To build every target in LiveHD (helpful for checking if changes cause compilation failures), the target would be //:.... For more details on target syntax, see this page.

"},{"location":"livehd/10-bazel/#release-vs-fastbuild-default-vs-debug","title":"Release vs fastbuild (default) vs debug","text":"

For debugging/development use -c dbg, for benchmarking and testing -c opt.

  • Fast build: no optimization, minimal debugging information (no local variable information), assertions turned on (default)

    $ bazel build <target>\n

  • Debug build: some optimization, full debugging information, assertions turned on

    $ bazel build -c dbg <target>\n

or use address sanitizer to detect memory leaks

$ bazel build -c dbg --config asan //...\n

or use thread sanitizer to detect data races

$ bazel build -c dbg --config tsan //...\n

  • Release build: most optimization, no debug symbols, assertions turned off

    $ bazel build -c opt <target>\n

  • Benchmarking build: aggressive optimization for the current architecture (binary may not be portable!)

    $ bazel build --config=bench <target>\n

"},{"location":"livehd/10-bazel/#see-the-commands-executed","title":"See the commands executed","text":"

The bazel '-s' option prints the command executed. The sandbox may still be deleted.

$ bazel build -s //main:all\n
"},{"location":"livehd/10-bazel/#keep-all-the-files-in-bazel-run-for-debugging","title":"Keep all the files in bazel run for debugging","text":"

Bazel runs process in a sandbox what it is deleted after each run. To preserve it for debugging a failing test.

bazel test --sandbox_debug -c dbg //YOUR_TEST_HERE\n

Check the failing log, it will show you the sandbox location. You can change directory to it, and debug as usual.

"},{"location":"livehd/10-bazel/#to-run-fixme-tests","title":"To run FIXME tests","text":"

Many times, we have new tests that make the regression fail. We use \"fixme\" if the test is a new one and LGraph is still not patched. We want the test in the system, but we do not want to make fail the regressions.

Those tests are marked with tags \"fixme\" in the BUILD. E.g:

sh_test(\n    name = \"my_test.sh\",\n    tags = [\"fixme\"],  # This is a fixme test. It fails, but we should fix it\n    srcs = [\"tests/pyrope_test.sh\"],\n

To run all the fixme tests

$ bazel test --test_tag_filters \"fixme\" <target>\n
To list all the fixme tests (the goal is to have zero)
$ bazel query 'attr(tags, fixme, tests(<target>))'\n

"},{"location":"livehd/10-bazel/#list-bazel-targets-starting-from-top-directory","title":"List bazel targets starting from top directory","text":"
$ bazel query <target>\n
"},{"location":"livehd/10-bazel/#list-bazel-targets-starting-from-any-directory","title":"List bazel targets starting from any directory","text":"
$ bazel query <target>\n
"},{"location":"livehd/10-bazel/#list-files-needed-for-a-given-target","title":"List files needed for a given target","text":"
$ bazel query \"deps(<target>)\"\n
"},{"location":"livehd/10-bazel/#list-all-the-passes-that-use-core-those-should-be-listed-at-mainbuild-deps","title":"List all the passes that use core (those should be listed at main/BUILD deps)","text":"
$ bazel query \"rdeps(//pass/..., //core:all)\" | grep pass_\n
"},{"location":"livehd/10-bazel/#clear-out-cache-not-needed-in-most-cases","title":"Clear out cache (not needed in most cases)","text":"

This command is useful for benchmarking build time, and when system parameters change (the compiler gets upgraded, for example)

$ bazel clean --expunge\n

"},{"location":"livehd/10-bazel/#to-run-long-tests","title":"To run LONG tests","text":"

In addition to the short tests, there are sets of long tests that are run frequently but not before every push to main line. The reason is that those are multi-hour tests.

$ bazel test --test_tag_filters \"long1\" <target>\n
There are up to 8 long tests categories (long1, long2, long3...). Each of those tests groups should last less than 4 hours when running in a dual core machine (travis or azure).

To list the tests under each tag. E.g., to list all the tests with long1 tag.

$ bazel query 'attr(tags, long1, tests(<target>))'\n

"},{"location":"livehd/10-bazel/#debugging-with-bazel","title":"Debugging with bazel","text":"

First run the tests to see the failing one. Then run with debug options the failing test. E.g:

$ bazel run -c dbg //eprp:all\n
Increase logging level if wanted
$ LGRAPH_LOG=info bazel run -c dbg //eprp:all\n
To run with gdb
$ bazel build -c dbg //eprp:eprp_test\n$ gdb bazel-bin/eprp/eprp_test\n(gdb) b Eprp::run\n(gdb) r\n
(lldb is also supported.)

"},{"location":"livehd/10-bazel/#to-create-a-fully-static-binary","title":"To create a fully static binary","text":"

In the cc_binary of the relevant BUILD file, add linkopts = ['-static']

Notice that the lgshell still needs the directory inside bazel-bin/main/lgshell.runfiles when using inou.yosys.\\*

"},{"location":"livehd/10b-3rdparty/","title":"3rd Party","text":"

This section is for more advanced users that want to build LiveHD with some external 3rd party tool.

When integrating LiveHD with a 3rd party tool (nextpnr in this example), you can either bring the 3rd party tool to LiveHD and hence build it with bazel, or you can export the LiveHD code/libraries and integrate with the 3rd party project. This document covers the later case.

"},{"location":"livehd/10b-3rdparty/#requirements","title":"Requirements","text":"

Bazel pulls a specific set of library dependences, if you export, you must ensure that the 3rd party tool uses the same library version. The 3 main source of likely conflict is \"boost\", \"abseil\", and \"fmt\". The \"fmt\" library is unlikely to be a conflict because LiveHD uses it as \"header\" only to avoid conflicts with other tools like slang.

To check the boost and abseil version, the easiest way:

bazel build -c dbg //main:all\n# boost version 1.71 in this case\ngrep -i \"define BOOST_VERSION \" bazel-*/external/boost//boost/version.hpp\n#define BOOST_VERSION 107100\n\n# abseil version 20210324\ngrep \"define ABSL_OPTION_INLINE_NAMESPACE_NAME\" bazel-*/external/com_google_absl/absl/base/options.h\n#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_20210324\n

"},{"location":"livehd/10b-3rdparty/#nextpnr-example","title":"nextpnr example","text":"

nextpnr uses boost, in the previous example, you need to compile it with boost 1.71, with the usual requirements:

# nextpnr ice40 needs icestorm, so install it first\ngit clone https://github.com/cliffordwolf/icestorm.git\ncd icestorm\nmake\nsudo make install\n\n# compile nextpnr itself\ngit clone https://github.com/YosysHQ/nextpnr.git\ncd nextpnr\nmkdir build\ncd build\ncmake -DARCH=ice40 ../\nmake -j $(ncpus)\n

The previous steps should compile before you attempt to integrate LiveHD to nextpnr.

Then, you need to clone and compile LiveHD. If you clone and compile parallel to nextpnr

git clone https://github.com/masc-ucsc/livehd.git\ncd livehd\nbazel build -c dbg //main:all  # You could use -c opt for faster/optimized compilation\ncd ../nextpnr/build/\nln -s ../../livehd/\nln -s livehd/bazel-out\nln -s livehd/bazel-livehd\n

Then, we need to copy the bazel gcc build instructions and combine with the nextpnr build

Copy this to a file called pp:

--- livehd.params   2021-09-25 17:47:36.656724997 -0700\n+++ livehd.params   2021-09-25 17:40:24.365650808 -0700\n@@ -1,16 +1,17 @@\n--o\n-bazel-out/k8-dbg/bin/main/lgshell\n+-std=c++17\n+-Wno-unknown-pragmas\n+-I livehd/eprp -I livehd/elab -I bazel-livehd/external/com_google_absl -I bazel-livehd/external/fmt/include/ -I bazel-livehd/external/iassert/src -I livehd/mmap_lib/include -I livehd/core -I livehd/task -I livehd/lemu -I ./bazel-livehd/external/rapidjson -I livehd/pass/common -I ./bazel-livehd/external/replxx/include\n+./extra.cpp\n -pie\n -fuse-ld=gold\n -Wl,-no-as-needed\n -Wl,-z,relro,-z,now\n -B/usr/bin\n -pass-exit-codes\n -lstdc++\n -lm\n-bazel-out/k8-dbg/bin/main/_objs/lgshell/main.pic.o\n -Wl,--start-lib\n bazel-out/k8-dbg/bin/main/_objs/main/inou_lef_api.pic.o\n bazel-out/k8-dbg/bin/main/_objs/main/main_api.pic.o\n bazel-out/k8-dbg/bin/main/_objs/main/meta_api.pic.o\n bazel-out/k8-dbg/bin/main/_objs/main/top_api.pic.o\n

The patch adds a new c++ file to compile (extra.cpp). It will be nicer if the file is in the nextpnr directory structure, but this is as an example of how to integrate. extra.cpp has a call to LiveHD to open a database as example.

cp livehd/bazel-bin/main/lgshell-2.params livehd.params\npatch <pp\n

This example uses extra.cpp as a sample LiveHD call inside nextpnr. The extra.cpp contents:

#include \"lgraph.hpp\"\n\nvoid some_func() {\nLgraph *lg = Lgraph::open(\"lgdb\",\"top\");\n\nlg->dump();\n}\n

Then you need to add the @livehd.params to the end of the nextpnr-ice40 link step. A way to get the command line is to use the VERBOSE=1 option.

rm -f nextpnr-ice40\nmake VERBOSE=1 nextpnr-ice40\n

Cut and paste the command, it will end with something like thon3.9.so @livehd.params to be something like:

/usr/bin/c++ -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wno-array-bounds -fPIC -O3 -g -pipe -flto -fno-fat-lto-objects CMakeFiles/nextpnr-ice40.dir/common/archcheck.cc.o CMakeFiles/nextpnr-ice40.dir/common/basectx.cc.o CMakeFiles/nextpnr-ice40.dir/common/bits.cc.o CMakeFiles/nextpnr-ice40.dir/common/command.cc.o CMakeFiles/nextpnr-ice40.dir/common/context.cc.o CMakeFiles/nextpnr-ice40.dir/common/design_utils.cc.o CMakeFiles/nextpnr-ice40.dir/common/embed.cc.o CMakeFiles/nextpnr-ice40.dir/common/handle_error.cc.o CMakeFiles/nextpnr-ice40.dir/common/idstring.cc.o CMakeFiles/nextpnr-ice40.dir/common/idstringlist.cc.o CMakeFiles/nextpnr-ice40.dir/common/log.cc.o CMakeFiles/nextpnr-ice40.dir/common/nextpnr.cc.o CMakeFiles/nextpnr-ice40.dir/common/nextpnr_assertions.cc.o CMakeFiles/nextpnr-ice40.dir/common/nextpnr_namespaces.cc.o CMakeFiles/nextpnr-ice40.dir/common/nextpnr_types.cc.o CMakeFiles/nextpnr-ice40.dir/common/place_common.cc.o CMakeFiles/nextpnr-ice40.dir/common/placer1.cc.o CMakeFiles/nextpnr-ice40.dir/common/placer_heap.cc.o CMakeFiles/nextpnr-ice40.dir/common/property.cc.o CMakeFiles/nextpnr-ice40.dir/common/pybindings.cc.o CMakeFiles/nextpnr-ice40.dir/common/report.cc.o CMakeFiles/nextpnr-ice40.dir/common/router1.cc.o CMakeFiles/nextpnr-ice40.dir/common/router2.cc.o CMakeFiles/nextpnr-ice40.dir/common/sdf.cc.o CMakeFiles/nextpnr-ice40.dir/common/str_ring_buffer.cc.o CMakeFiles/nextpnr-ice40.dir/common/svg.cc.o CMakeFiles/nextpnr-ice40.dir/common/timing.cc.o CMakeFiles/nextpnr-ice40.dir/common/timing_opt.cc.o CMakeFiles/nextpnr-ice40.dir/3rdparty/json11/json11.cpp.o CMakeFiles/nextpnr-ice40.dir/json/jsonwrite.cc.o CMakeFiles/nextpnr-ice40.dir/frontend/json_frontend.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/arch.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/arch_place.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/arch_pybindings.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/bitstream.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/cells.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/chains.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/delay.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/gfx.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/main.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/pack.cc.o CMakeFiles/nextpnr-ice40.dir/ice40/pcf.cc.o CMakeFiles/chipdb-ice40.dir/ice40/chipdb/chipdb-384.cc.o CMakeFiles/chipdb-ice40.dir/ice40/chipdb/chipdb-1k.cc.o CMakeFiles/chipdb-ice40.dir/ice40/chipdb/chipdb-5k.cc.o CMakeFiles/chipdb-ice40.dir/ice40/chipdb/chipdb-u4k.cc.o CMakeFiles/chipdb-ice40.dir/ice40/chipdb/chipdb-8k.cc.o -o nextpnr-ice40  -ltbb /usr/lib/x86_64-linux-gnu/libboost_filesystem.so /usr/lib/x86_64-linux-gnu/libboost_program_options.so /usr/lib/x86_64-linux-gnu/libboost_iostreams.so /usr/lib/x86_64-linux-gnu/libboost_system.so /usr/lib/x86_64-linux-gnu/libboost_thread.so -lpthread /usr/lib/x86_64-linux-gnu/libboost_regex.so /usr/lib/x86_64-linux-gnu/libboost_chrono.so /usr/lib/x86_64-linux-gnu/libboost_date_time.so /usr/lib/x86_64-linux-gnu/libboost_atomic.so -lpthread /usr/lib/x86_64-linux-gnu/libpython3.9.so @livehd.params\n

You can check that the new binary includes liveHD with something like:

nm nextpnr-ice40 | grep -i Lgraph\n

"},{"location":"livehd/11-pass/","title":"Creating a Pass","text":"

This document provides some minimal suggestion on how to build a new LiveHD pass.

Most LiveHD passes reside inside inou or pass. The only difference is that inou focuses on translation from some external tool to/from LiveHD while pass works on transformations from LiveHD to LiveHD.

"},{"location":"livehd/11-pass/#create-a-pass","title":"Create a pass","text":"

Check the pass/sample directory for how to create a trivial pass.

  • Create pass/XXX directory

The typical is to have these files:

  • pass/XXX/pass_XXX.[cpp|hpp]: C++ and Header file to interface with lgshell
  • pass/XXX/XXX.[cpp|hpp]: C++ file to perform the pass over a Lgraph or LNAST API
  • pass/XXX/BUILD: the Bazel build configuration file
  • pass/XXX/tests/XXX_test.cpp: A google test checking the pass

Finally, add the new pass to main/BUILD

"},{"location":"livehd/11-pass/#pass-parameters-and-common-variables","title":"Pass Parameters and Common variables","text":"

One of the main goals is to have a uniform set of passes in lgshell. lgshell should use this common variable names when possible

    name:foo        lgraph name\n    path:lgdb       lgraph database path (lgdb)\nfiles:foo,var   comma separated list of files used for INPUT\n    odir:.          output directory to generate files like verilog/pyrope...\n
"},{"location":"livehd/11-pass/#some-hintscomments-useful-for-developers","title":"Some hints/comments useful for developers","text":""},{"location":"livehd/11-pass/#using-clang-when-building","title":"Using clang when building","text":"

The regression system builds for both gcc and clang. To force a clang build, set the following environment variables before building:

CXX=clang++ CC=clang bazel build -c dbg //...\n
"},{"location":"livehd/11-pass/#perf-in-lgbench","title":"Perf in lgbench","text":"

Use lgbench to gather statistics in your code block. It also allows to run perf record for the code section (from lgbench construction to destruction). To enable perf record set LGBENCH_PERF environment variable

export LGBENCH_PERF=1\n
"},{"location":"livehd/11-pass/#gdblldb-usage","title":"GDB/LLDB usage","text":"

For most tests, you can debug with

gdb ./bazel-bin/main/lgshell\n

or

lldb ./bazel-bin/main/lgshell\n

Note that breakpoint locations may not resolve until lgshell is started and the relevant LGraph libraries are loaded.

"},{"location":"livehd/11-pass/#address-sanitizer","title":"Address Sanitizer","text":"

LiveHD has the option to run it with address sanitizer to detect memory leaks.

bazel build -c dbg --config asan //...\n
"},{"location":"livehd/11-pass/#thread-sanitizer","title":"Thread Sanitizer","text":"

To debug with concurrent data race.

bazel build -c dbg --config tsan //...\n
"},{"location":"livehd/11-pass/#debugging-a-broken-docker-image","title":"Debugging a broken Docker image","text":"

The travis/azure regressions run several docker images. To debug the issue, run the same as the failing docker image. c++ OPT with archlinux-masc image

  1. Create some directory to share data in/out the docker run (to avoid mistakes/issues, I would not share home directory unless you have done it several times before)
mkdir $HOME/docker\n
  1. Run the docker image (in some masc docker images you can change the user to not being root)
docker run --rm --cap-add SYS_ADMIN -it  -e LOCAL_USER_ID=$(id -u $USER) -v ${HOME}/docker:/home/user mascucsc/archlinux-masc\n\n# Once inside docker image. Create local \"user\" at /home/user with your userid\n/usr/local/bin/entrypoint.sh\n
  1. If the docker image did not have the livehd repo, clone it
git clone https://github.com/masc-ucsc/livehd.git\n
  1. Build with the failing options and debug
CXX=g++ CC=gcc bazel build -c opt //...\n

A docker distro that specially fails (address randomizing and muslc vs libc) is alpine. The command line to debug it:

docker run --rm --cap-add SYS_ADMIN -it -e LOCAL_USER_ID=$(id -u $USER) -v $HOME:/home/user -v/local/scrap:/local/scrap mascucsc/alpine-masc\n
"},{"location":"livehd/12-github/","title":"GitHub Guide","text":"

LiveHD is the synthesis/emulation flow primarily maintained and developed by the MASC lab at UC Santa Cruz. Since LiveHD is used for computer architecture and VLSI research, the MASC lab has an internal private repo for some still in progress works. This is done using a private repo so that we can wait until the research is published before pushing changes to the public repo hosted on GitHub.

This guide explains how we use git at the MASC group, and how you could setup a similar flow to contribute to the LiveHD project. Other groups may choose to adapt this technique for their own use.

LiveHD uses bazel as a build system, as a result, we no longer use submodules. Instead we use the built-in bazel support to pull specific repositories.

"},{"location":"livehd/12-github/#github-configuration-and-commands","title":"Github Configuration and Commands","text":"

This section is for git first time users and to show the git configuration used by the MASC group.

"},{"location":"livehd/12-github/#configuration","title":"Configuration","text":"

Suggested options for git first time users

# Rebase no merge by default\ngit config --global pull.rebase true\n# Set your name and email\ngit config --global user.email \"perico@lospalotes.com\"\ngit config --global user.name \"Perico LosPalotes\"\ngit config --global pull.rebase true\ngit config --global rebase.autoStash true\n
"},{"location":"livehd/12-github/#rebase-vs-no-rebase","title":"Rebase vs No-Rebase","text":"

Rebase creates cleaner logs, but sometimes it gets difficult to fix conflicts with rebase. For cases that you are struggling to merge a conflict, you could do this:

# undo the failed rebase merge\ngit rebase --abort\n\n# make sure that your code changes were committed\ngit commit -a -m \"Your commit message\"\ngit pull --no-rebase\n\n# Fix the conflict without rebase (easier)\ngit commit -a -m \"your merge message\"\ngit pull --no-rebase\ngit push\n
"},{"location":"livehd/12-github/#typical-git-commands","title":"Typical git commands","text":"

Clean the directory from any file not in git (it will remove all the files not committed)

git clean -fdx\n

Save and restore un-committed changes to allow a new git pull. stash is like a \"push\" and \"pop\" replays the changes in the current directory. This will happen automatically if you have the autoStash configuration option.

git stash\ngit pull\ngit stash pop\n

See the differences against the server (still not pushed). Everything may be committed, so git diff may be empty

git diff @{u}\n
"},{"location":"livehd/12-github/#git-hercules-statistics","title":"Git Hercules statistics","text":"
hercules --languages C++ --burndown --burndown-people --pb https://github.com/masc-ucsc/livehd >hercules1.data\nlabours -f pb -m overwrites-matrix -o hercules1a.pdf <hercules1.data\nlabours -f pb -m ownership -o hercules1b.pdf <hercules1.data\n\nhercules --languages C++ --burndown --first-parent --pb https://github.com/masc-ucsc/livehd >hercules2.data\nlabours -f pb -m burndown-project -o hercules2.pdf <hercules2.data\n\nhercules --languages C++ --devs --pb https://github.com/masc-ucsc/livehd >hercules3.data\nlabours -f pb -m old-vs-new -o hercules3a.pdf <hercules3.data\nlabours -f pb -m devs -o hercules3b.pdf <hercules3.data\nlabours -f pb -m devs-efforts -o hercules3c.pdf <hercules3.data\n
"},{"location":"livehd/12-github/#testdeveloper-livehd-case-no-commits","title":"Test/Developer LiveHD case (no commits)","text":"

If you do not plan to do many changes, and just wants to try LiveHD or be a LiveHD user, the easiest way is to just clone the repo:

git clone https://github.com/masc-ucsc/livehd\ncd livehd\n

From time to time, you should get the latest version to have the latest bug fixes/patches. Just a typical git pull should suffice:

git pull\n
"},{"location":"livehd/12-github/#infrequent-contributor-flow-advanced-users","title":"Infrequent Contributor Flow (ADVANCED USERS)","text":"

These are instructions for advanced users, more likely other university/company institutions with a team working on this project. The larger team may want to have some private repository with internal development and some pushes/pulls to the main LiveHD repo. For single external users, I would suggest to just fork the repository and do pull requests.

If you work outside UCSC and/or you are an infrequent contributor, you have two main options: fork or private clone. The fork approach requires you to have your repository public, if you have publications or work-in-progress that you do not want to share the best option is to have a private repo (livehd-private).

The simplest way to contribute to LiveHD is to create a public repo or a public fork, and a pull request. Most git guides use the origin/master (in fork or private repo) to synchronize with upstream/master (upstream main LiveHD repo). This means that your local changes should NOT go to your origin/master. Instead, you should create a branch for your local work. This works like a charm if you do pull requests, and it is reasonable if you have a long development branch without intention to push upstream.

Although it is possible to create a different setup, we recommend that you keep the origin/master clean to synchronize with upstream/origin. You should create a new branch for each feature that you may want to upstream (origin/feature-x), and a local development branch (dev) for all your team members.

  1. Clone the repo:

    git clone https://github.com/masc-ucsc/livehd.git livehd\ncd livehd\n
  2. Create development branch (dev)

    git checkout -b dev\n
  3. Create a branch from origin/master to create a pull request to upstream/master

    git checkout -b pull_request_xxx\n
  4. Create a branch from dev for internal development if needed

    git checkout -b feature_xx_4dev dev\n
  5. Synchronize origin/master from main upstream/master

    Add remote upstream (if not added before)

    git remote -v\n

    If remote -v did not list upstream. Add them

    git remote add upstream https://github.com/masc-ucsc/livehd.git\ngit fetch upstream\n

    Make sure that you are in origin/master

    git checkout master\n

    Bring the changes from the remote upstream/master to local master/origin

    git merge upstream/master\n

    Push to repo origin/master if everything was fine

    git push origin master\n

    To see the difference with upstream (it should be empty)

    git diff @{upstream}\n
  6. Synchronize the dev branch with the latest master sync

    git checkout dev\ngit merge origin/master\ngit push # same as \"push origin dev\" because dev is checkout\n
  7. In case that you did not, push to the corresponding branch to the server

    git push origin dev\ngit push origin pull_request_xxx\ngit push origin feature_xx_4dev\n
  8. Create new pull request to upstream

    Make sure that origin/master is in sync (step 5)

    git diff @{upstream} # should be empty\n

    Rebase/merge the feature request with latest origin master

    git checkout pull_request_xxx\ngit rebase master\ngit push upstream pull_request_xxx\n

Now create a pull request through github, and the UCSC/MASC team will review it.

"},{"location":"livehd/12-github/#occasional-pull-request-steps","title":"Occasional Pull Request steps","text":"

If you just want to do some small contributions to LiveHD doing a public fork is the easiest way to contribute. Just fork, commit to forked master, and click on the web link after you push.

"},{"location":"livehd/12-github/#frequent-contributor","title":"Frequent Contributor","text":"

If you are working on LiveHD at UC Santa Cruz, contact Jose Renau to be added to the MASC organization on GitHub so that you have write access to the repo. The setup is similar to the infrequent contributor flow but you have access to directly commit to the public repository. Even the upstream/master.

"},{"location":"livehd/13-style/","title":"Coding Style","text":"

These are the coding style rules for LiveHD C++. Each rule can be broken, but it should be VERY rare, and a small comment should be placed explaining why.

"},{"location":"livehd/13-style/#overall","title":"Overall","text":"
  • When possible keep the system simple. Complexity is the enemy of maintenance.
  • Deprecate no longer used features.
  • Try to reduce friction. This means to avoid hidden/complex steps.
  • Every main API should have a unit test for testing but also to demonstrate usage.
"},{"location":"livehd/13-style/#comments","title":"comments","text":"

Code should be the comments, try to keep comments concise. They should explain the WHY not the HOW. The code is the HOW.

Labels used in comments:

// FIXME: Known bug/issue but no time to fix it at the moment\n\n// TODO: Code improvement that will improve perf/quality/??? but no time at the moment\n\n// WARNING: message for some \"strange\" \"weird\" code that if changes has effects\n// (bug). Usually, this is a \"not nice\" code that must be kept for some reason.\n\n// NOTE: Any comment that you want to remember something about (not critical)\n\n// STYLE: why you broke a style rule (pointers, iterator...)\n
"},{"location":"livehd/13-style/#strings","title":"strings","text":"

We use std::string and std::string_view. These are the rules:

  • Arguments for functions are always std::string_view (no const std::string &)

  • If the return argument is not allocated in the function, we return a std::string_view

  • If the return argument can be a new string, the function returns std::string

  • Use the absl::StrCat, absl::StrAppend, absl::StrSplit when possible

  • To convert to/from integers use str_tools::to_i to_hex ...

  • Use str_tools for sub-string operations like str_tools::ends_with

"},{"location":"livehd/13-style/#variable-naming-rules","title":"Variable naming rules","text":"
  • No camelCase. Use underscores to separate words:
    foo_bar = Foo_bar(3);\n
  • Use plural for containers with multiple entries like vector, singular otherwise
    elem = entries[index];\n
  • Classes/types/enums start with uppercase. Lowercase otherwise
    val = My_enum::Big;\nclass Sweet_potato {\n
"},{"location":"livehd/13-style/#error-handling-and-exceptions","title":"Error handling and exceptions","text":"

Use the Pass::error or Pass:warn for error and likely error (warn). Internally, error generates and exception capture by the main lgshell to move to the next task.

Pass::error(\"inou_yaml: can only have a yaml_input or a graph_name, not both\");\nPass::warn(\"inou_yaml.to_lg: output:{} input:{} graph:{}\", output, input, graph_name);\n
"},{"location":"livehd/13-style/#no-tabs-indentation-is-2-spaces","title":"No tabs, indentation is 2 spaces","text":"

Make sure to configure your editor to use 2 spaces

You can configure your text editor to do this automatically

"},{"location":"livehd/13-style/#include-order","title":"Include order","text":"

First do C includes (try to avoid when possible), then an empty line with C++ includes, then an empty line followed with lgraph related includes. E.g:

#include <sys/types.h>\n#include <dirent.h>\n\n#include <iostream>\n#include <set>\n\n#include \"graph_library.hpp\"\n#include \"lgedgeiter.hpp\"\n
"},{"location":"livehd/13-style/#keep-column-widths-short","title":"Keep column widths short","text":"
  • Less than 120 characters if at all possible (meaning not compromising readability)

You can configure your text editor to do this automatically

"},{"location":"livehd/13-style/#avoid-trailing-spaces","title":"Avoid trailing spaces","text":"

You can configure your text editor to highlight them. https://github.com/ntpeters/vim-better-whitespace

"},{"location":"livehd/13-style/#use-c14-iterators-not-iterator","title":"Use C++14 iterators not ::iterator","text":"
for(auto idx:g->unordered()) {\n}\n

Use structured returns when iterator is returned for cleaner code:

for(const auto &[name, id]:name2id) {\n// ...\n
"},{"location":"livehd/13-style/#use-auto-or-const-auto-when-possible","title":"Use \"auto\", or \"const auto\", when possible.","text":"
for(auto idx:g->unordered()) {\nfor(const auto &c:g->out_edges(idx)) {\n
"},{"location":"livehd/13-style/#const-and-local-variables","title":"const and local variables","text":"

It may be too verbose to write const all the time. The coding style request to use const (when possible) in iterators and pointers. The others are up to the programmer.

"},{"location":"livehd/13-style/#do-not-use-stdunordered_set-stdmap-use-flat_hash_map-or-flat_hash_set-from-abseil","title":"Do not use std::unordered_set, std::map, use flat_hash_map or flat_hash_set from abseil","text":"
#include \"absl/container/flat_hash_map.h\"\n#include \"absl/container/flat_hash_set.h\"\n\nabsl::flat_hash_map<Index_ID, RTLIL::Wire *>   my_example;\n
"},{"location":"livehd/13-style/#some-common-idioms-to-handle-mapsets","title":"Some common idioms to handle map/sets","text":"

Traverse the map/set, and as it traverses decide to erase some of the entries:

for (auto it = m.begin(), end = m.end(); it != end;) {\nif (condition_to_erase_it) {\nm.erase(it++);\n} else {\n++it;\n}\n}\n

To check if a key is present:

if (set.contains(key_value)) {\n}\n

"},{"location":"livehd/13-style/#use-abslspan-instead-of-stdvector-as-return-argument","title":"Use absl::Span instead of std::vector as return argument","text":"

absl::Span is the equivalent of string_view for a string but for vectors. Like string_view, it does not have ownership, and the size in the span can decrease (not increase) without changing the original vector with \"subspan\". Faster and more functional, no reason to return \"const std::vector &\", instead return \"absl::Span\".

#include \"absl/types/span.h\"\n\nabsl::Span<Sub_node>    get_sub_nodes() const {\nI(sub_nodes.size()>=1);\nreturn absl::MakeSpan(sub_nodes).subspan(1); // Skip first element from vector\n};\n
"},{"location":"livehd/13-style/#pass-by-reference-and-use-const-when-possible","title":"Pass by reference and use \"const\" when possible","text":"
void print(const Sub_node& g); //or\n\nvoid edit(Sub_node& g);\n

Note that older code still uses pointers, this is no longer allowed.

"},{"location":"livehd/13-style/#avoid-dynamic-allocation-as-much-as-possible","title":"Avoid dynamic allocation as much as possible","text":"

The idea is to RARELY directly allocate pointer allocation

Use:

foo = Sweet_potato(3, 7)\n

instead of

foo = new Sweet_potato(3, 7)\n
"},{"location":"livehd/13-style/#do-not-use-newdelete-keywords-use-smart-pointers-if-needed-very-very-rare","title":"Do not use \"new\"/\"delete\" keywords. Use smart pointers if needed (VERY VERY rare)","text":"

Use:

foo = std::make_unique<Sweet_potato>(3,7);\n

instead of

foo = new Sweet_potato(3, 7)\n
"},{"location":"livehd/13-style/#use-fmtprint-to-print-messages-for-debugging","title":"Use fmt::print to print messages for debugging","text":"
fmt::print(\"This is a debug message, name = {}, id = {}\\n\",g->get_name(), idx);\n
"},{"location":"livehd/13-style/#use-accessors-consistently","title":"Use accessors consistently","text":"
  • get_XX(): gets \"const XX &\" from object without side effects (assert if it does not exist)
    • operator(Y) is an alias for get_XX(Y)
  • ref_XX(): gets \"XX * \" (nullptr if it does not exist)
  • find_XX(): similar to get_XX but, if it does not exist return invalid object (is_invalid())
  • setup_XX(): gets XX from object, if it does not exists, it creates it
  • create_XX(): clears previous XX from object, and creates a new and returns it
  • set_XX(): sets XX to object, it creates if it does not exist. Similar to create, but does not return reference.

If a variable is const, it can be exposed directly without get/set accessors

foo = x.const_var; // No need to have x.get_const_var()

"},{"location":"livehd/13-style/#use-bitarray-class-to-have-a-compact-bitvector-marker","title":"Use bitarray class to have a compact bitvector marker","text":"
bitarray visited(g->max_size());\n
"},{"location":"livehd/13-style/#use-iassert-extensively-be-meaningful-whenever-possible-in-assertions","title":"Use iassert extensively / be meaningful whenever possible in assertions","text":"

This usually means use meaningful variable names and conditions that are easy to understand. If the meaning is not clear from the assertion, use a comment in the same line. This way, when the assertion is triggered it is easy to identify the problem.

I(n_edges > 0); //at least one edge needed to perform this function\n

We use the https://github.com/masc-ucsc/iassert package. Go to the iassert for more details on the advantages and how to allow it to use GDB with assertions.

"},{"location":"livehd/13-style/#develop-in-debug-mode-and-benchmark-in-release-mode","title":"Develop in debug mode and benchmark in release mode","text":"

Extra checks should be only in debug. Debug and release must execute the same, only checks (not behavior change) allowed in debug mode.

Benchmark in release. It is 2x-10x faster.

"},{"location":"livehd/13-style/#use-compact-ifelse-brackets","title":"Use compact if/else brackets","text":"

Use clang-format as configured to catch style errors. LGraph clang-format is based on google format, but it adds several alignment directives and wider terminal.

   cd XXXX\n   clang-format -i *pp\n
std::vector<LGraph *> Inou_yaml::generate() {\n\nif (opack.graph_name != \"\") {\n// ...\n} else {\n// ..\n}\n
"},{"location":"livehd/13-style/#decide-how-to-use-attributes","title":"Decide how to use attributes","text":"

Attributes are parameters or information that an be per Node, Node_pin or Edge. In LGraph, attributes are persistent. This means that they are kept across execution runs in the LGraph database (E.g: in lgdb).

For persistent attributes, the structures to use are defined in core/annotate.hpp. Any new attribute must be added to \"annotate.hpp\" to preserve persistence and to make sure that they are cleared when needed.

Many times it is important to have information per node, but that it is not persistent across runs. For example, when building a LGraph from Yosys, there is a need to remember pointers from yosys to LGraph. This by definition can not be persistent because pointers change across runs. For this case, there are several options.

"},{"location":"livehd/13-style/#the-non-persistent-annotations","title":"The Non-Persistent Annotations","text":"

If the data structure needs to keep most of the node/pins in the Lgraph, use the compact_class notation:

absl::flat_hash_map<SomeData, Node_pin::Compact_class> s2pin;\nabsl::flat_hash_map<SomeData, Node::Compact_class>     s2node;\n\nSomeData d1;\nLgraph *lg; // LGraph owning the node\ns2pin[d1]  = node.get_driver_pin().get_compact_class(); // Example of use getting a pint\ns2node[d1] = node.get_compact_class();\nauto name = s2pin[d1].get_node(lg).get_name();   // Pick previously set driver name\n

Another example:

absl::flat_hash_map<Node_pin::Compact, RTLIL::Wire *>  input_map;\n\ninput_map[pin.get_compact()] = wire;\n\nauto *wire = input_map[pin.get_compact()];\n\nfor(const auto &[key, value]:input_map) {\nNode_pin pin(lg, key); // Key is a ::Compact, not a Node_pin\nauto name  = pin.get_name();\n// ... Some use here\n}\n

If the data structure just holds a small subset of the graph, you can keep the metadata, and use Node/Node_pin directly. E.g:

absl::flat_hash_map<SomeData, Node_pin> s2pin;\nabsl::flat_hash_map<SomeData, Node>     s2node;\n\nSomeData d1;\ns2pin[d1]  = node.get_driver_pin(); // Example of use getting a pint\ns2node[d1] = node;\nauto name = s2pin[d1].get_name();   // Pick previously set driver name\n

In this case, it is fine to use the full Node, Node_pin, or Edge. This has some pointers inside, but it is OK because it is not persistent.

"},{"location":"livehd/13-style/#avoid-code-duplication","title":"Avoid code duplication","text":"

The rule is that if the same code appears in 3 places, it should be refactored

Tool to detect duplication

    find . -name '*.?pp' | grep -v test >list.txt\n    duplo -ml 12 -pt 90 list.txt report.txt\n

"},{"location":"pyrope/00-hwdesign/","title":"Hardware Design","text":"

Most language manuals/guides do not include a chapter on \"what is programming?\", but Pyrope is a hardware description language or HDL. This document is a guideline for hardware design for software designers. The idea is to be high level to explain the differences without going to syntactic details in different languages.

"},{"location":"pyrope/00-hwdesign/#no-von-neumann","title":"No Von Neumann","text":"

Most software programming languages are built to program Von Neumann CPUs. When dealing with single-threaded code, the programmer has a sequence of \"commands\" or \"statements\" specified in a programming language. The machine executes one of those statements after another. There are \"control flow\" instructions to select what is the following statement to execute.

Potentially more restricting, software languages have a central or distributed \"memory\" concept where program data resides. For single-threaded code, there tends to be a main unified memory.

Current CPUs follow a Von Neumann approach1. Languages designed to program CPUs have the same model to map existing hardware efficiently. Since the languages are Von Neumann, it is logical that CPUs also evolve to keep the same model and further improve the performance. Since CPUs and languages follow the same Von Neumann model, software designers' mindset assumes this same concept. This feedback loop has resulted in most languages, hardware, and developers evolving around this model.

Neither FPGAs nor ASICs is Von Neumann machines. There is no program counter to execute one statement after another, and there is no central memory. Those concepts could be built on top, and this is in fact what CPUs are about. CPUs are all about making efficient Von Neumann machines on top of FPGAs and/or ASICs given some power/area/performance constraints.

To design a CPU or any hardware without a Von Neumann model, the standard concepts that all languages use of main memory or single-threaded execution do not make much sense. The reason is that the cells available in hardware are always there. The result can be used or not, but it is always there.

At a high level, hardware designers decide the basic hardware constructs to include in the design (adders, logic gates...) and how to connect them. Those hardware blocks will be there all the time, and the connection is fixed too. In contrast, a software designer needs to build efficient programs for one or more Von Neumann CPUs.

"},{"location":"pyrope/00-hwdesign/#optimization-knobs","title":"Optimization knobs","text":"

Programming hardware and software are all about solving a problem to meet some performance/power/cost constraints using the available resources. The difference is that the resources in hardware and software are not the same. In software, there are instructions; in hardware, there are cells2. This results in different optimization knobs.

Designing an efficient software program is all about deciding the sequence of instructions to be small and fast. The computer architecture Iron's law summarizes it well. The performance is \"Instruction Count\" x \"Instructions Per Cycle\" x \"Frequency\". Since software programmers do not tend to consider the frequency, it is all about executing fewer instructions and doing each instruction as fast as possible. The software designer has to create a sequence of instructions to solve a problem. Those instructions could use resources like memory.

Instead of instructions, most hardware designers have hardware blocks or cells like adders, multiplexors, flops, SRAMs... There are no central resources like memory, and they have to consider frequency.

Like a software designer, the hardware designer needs to solve a problem. Still, instead of selecting a sequence of instructions, the designer selects the cells or hardware blocks and their interconnection. The designer divides problems into smaller pipeline stages to have a high frequency. A design with small cells that can achieve the desired frequency is an exemplary hardware design3. So it is all about instantiating blocks and connecting them.

In hardware, there are two big categories of blocks: Combinational and Sequential. Combinational do not have a clock and perform operations like adding, and, xor... Sequential has a clock. The clock is used to remember a value. Hence the output of a sequential block retains or memoizes the value of previous cycles while combinational blocks have no memory or clock concept.

The hardware blocks are physical devices that need time to generate a valid output given a change in their inputs. When combinational blocks are connected, their maximum speed or frequency can be decided by finding the slowest path in the combinational blocks connected. This means that sequential blocks should separate combinational blocks to achieve higher frequency. This is called pipelining. There are overheads of adding more sequential blocks, and the hardware designer needs to find the correct balance given a set of constraints like area/frequency/power.

A significant effort in hardware design goes to pipelining. Not only to find the correct spot separating combinational blocks but because the sequential block adds a concept of \"state\" or memory. Starting from a working combination lock and randomly adding some \"sequential\" blocks is highly likely to generate an incorrect result. Pipelining adds the conceptual problem that adding sequential blocks changes the semantics and that ALL the combinational blocks should have more or less the same frequency. Otherwise, the pipeline design is unbalanced4, and the slowest pipeline decides the overall frequency.

The pipelining optimization concept is very different from software optimization. In software, designers care about the average. If a function is slow and its execution requires half of the execution time, reducing by half should have a 25% performance improvement. The designer does not need to improve very infrequently used functions. In hardware, designers care about the worst case. If a pipeline stage is slow, improving it will result in a frequency improvement if it was the slowest. The benefit will be just the difference with the next slower pipeline stage, not optimizing the pipeline itself.

The result is that hardware and software designers need to worry about different constraints like pipelining. Combined with the fact that hardware optimizations need to care about the worst case, not average, it is common for hardware designers to say that designing hardware is hard.

"},{"location":"pyrope/00-hwdesign/#hls-vs-hdl","title":"HLS vs. HDL","text":"

Hardware designers also use programming languages to specify their FPGA/ASIC design. In the past, designers \"drew\" the transistor/cells/gates and had a more visual layout to see/place where each combination and the sequential block was located. Although it is possible to do a design in such a way, it is not as productive as using some hardware design language.

There are many popular software languages like C++, Java, Rust, swift... There are also several hardware design languages, but they tend to fall into two categories: HLS (High-Level Synthesis) or HDLs (Hardware Description Languages). HLS can be languages like a subset of C or Rust. The HDLs are languages like Verilog, CHISEL, or Pyrope.

In a nutshell, HLS tries to leverage the larger Von Neumann community (languages and humans that know to program Von Neumann) and use compilers to transform to efficient hardware mappings that are not Von Neumann.

HLS has to deal with constructs like loops and central memory. The typical solution for loops is to use heuristics and/or directives to split the loops into different pipeline stages. The standard solution for global memory is not to use it or put compiler directives to guide them. Other constructs like memory allocation and recursion are also avoided in HLS. When a C program is translated to hardware, if it has pointers and uses memory, it needs directives to indicate where the memory resides and mark potential overlap or pointer aliasing between pointers. Otherwise, the generated translation is likely to be inefficient.

HDLs (Hardware Description Languages) do not have a Von Neumann model. The currently most popular HDL (Verilog) is a data flow language that does not have a global program counter like Von Neumann languages. Instead, the programmer specifies a hierarchy of modules5. In Verilog, the execution of each module has a complicated set of options, but from a high-level point of view, a group of statements is executed in each module. The module executes forever because it is a set of gates instantiated in the hardware design.

"},{"location":"pyrope/00-hwdesign/#hardware-artifacts","title":"Hardware artifacts","text":"

This section goes over several of the leading hardware artifacts that tend to be exist in most HDLs independent of the syntax.

"},{"location":"pyrope/00-hwdesign/#instantiation-vs-execution","title":"Instantiation vs execution","text":"

Hardware designers decide the gates are instantiated6 in the design, while software designers focus on executing the instructions. If a set of gates is rarely used, the hardware still has to instantiate them, and their performance area impact is independent of the usage frequency. In software, a set of seldom executed instructions have no performance impact. This is not the case in hardware. As such, languages build around \"instantiation\" more than traditional instruction execution.

Instantiation means that the designer explicitly indicates the gates or circuits mapped to hardware. In the vast majority of HDLs (Verilog, CHISEl, pyRTL, VHDL...), the designer specifies a top-level module. Each module can have a set of gates and more instantiated sub-modules.

In \"software,\" languages have a \"main\" or starting execution point. The \"main\" executes or calls several functions depending on the data. Functions can iterate in loops, and the program finishes execution when the main finishes.

In contrast, most HDLs differ from software languages in that they specify an instantiation tree hierarchy of modules, and then provide some syntax on how each module executes independently of the other modules.

In HDLs, the execution never ends, and the modules run independently. It resembles a bit of an actor model. An actor is a module with individual execution, but there are many differences like the tree structure of instantiations and the incapacity to spawn new actors. Although it is possible to build an HLS around the actor model without spawning capability, popular HDLs do not.

In most HDLs, the instantiated tree hierarchy is fixed. This makes sense from a hardware point of view7, but this means that a module can not be called inside a control flow statement. A common mistake from designers learning HDLs is to call a module conditionally. E.g., this code sequence is not what a software programmer may expect:

Problematic codePossible solution
var result = 0\nif some_opcode {\n  result = do_division(a,b)\n}else{\n  result = do_multiplication(a,b)\n}\n
var result = 0\nvar result1 = do_division(a,b)\nvar result2 = do_multiplication(a,b)\nif some_opcode {\n  result = result1\n}else{\n  result = result2\n}\n

A software programmer thinks about executing instructions. The previous syntax looks like execute or call do_division when some_opcode is true, but it is impossible to do in most HDLs because they are centered around instantiation, not execution. For synthesizable code, none of the most popular HDLs like Verilog, VHDL, CHISEL, pyRTL allow the instantiation of a module in a conditional. Some like Verilog have functions but those are inlined. When called, they can be seen as a macro preprocessor that inserts the function statements.

HDLs force the designer to spicy the instantiation unconditionally, and then the if selects between the instantiations. Even though HDLs look like they execute instructions, they do not; it is all about cell instantiation and how to connect those instances. The if is not a branch instruction, it is a multiplexor instantiation. The do_division is not a function call; it instantiates a circuit or module.

Artifact

Function calls inside control flow statements are either not allowed or forced to be inlined.

Artifact

HDLs look like instruction execution, but they are about circuit instantiation.

"},{"location":"pyrope/00-hwdesign/#pipelining","title":"Pipelining","text":"

Pipelining is adding registers in combinational circuits to create smaller critical paths and hence higher frequency designs. It is essential to hardware design, and there is not much related to it in software design flows.

To illustrate the problem, imagine a pipelined multiplier function (mult) that takes one cycle to produce the results, and the programmer has an assertion checking that it was a multiply. The result c is not the current cycle a*b but the last cycle a multiplied by the last cycle b. This is not what would be expected in a software API.

Problematic codeHLS possible solution
var c = mul(a,b)\nassert c == a * b // assert fails!!\n
var c = mul(a,b)\nassert c == a#[-1] * b#[-1] // read last cycle #[-1] a and b\n

If actors execution resembles concurrent module instantiation execution, async/await resembles pipelining. In async/await, the results of a function are not available at the function return. In HDLs, there is no await, and the results from previous cycles are output by the module instance.

Pipelining is not restricted to just function or module instantiations. A the module itself can have a set of registers, and different variables/wires have the results from different cycles. It is up to the designer to manage it, and it is one of the primary complexity sources of hardware design and verification.

Artifact

Different variables or wires can have results from other cycles due to pipelining.

"},{"location":"pyrope/00-hwdesign/#simulation-vs-synthesis","title":"Simulation vs synthesis","text":"

Hardware designs tend to have extensive verification infrastructures. The reason is that once the chip is fabricated, it can not be easily be patched like software. It may need to trash millions of dollars and take months to get the next chip, even for just a line of code patch. This is not different from software; it is just that the cost of a bug could be potentially much higher.

The difference from software is that the \"simulation\" results used for verification may be different from the hardware results generated during \"synthesis\".

A mismatch between synthesis and simulation could happen due to script directives in the synthesis scripts, or due to use language features that only affect simulation.

Problematic codeHLS possible solution
initial begin // initial code may not be used in synthesis\nc = 3;\nend\n\n#3 d = 4; // delay simulation update, not synthesis update\ncase (x)  // synthesis: full_case, parallel_case\n...\n
// Do allow simulation code to have side-effects on synthesis code\n// directives affect simulation AND synthesis (not one or the other)\n\nunique case(x) // do not use synthesis only directives\n...\n

Artifact

Simulation and synthesis results can have different functionality

"},{"location":"pyrope/00-hwdesign/#reset","title":"Reset","text":"

Programmers are used to initializing their variables. Since the modules are called every cycle, the typical software syntax for initialization does not work. To make it worse, some languages like Verilog (and others) have two initializations: reset and simulation setup.

Some differences between reset and software initialization:

  • Reset can take many cycles
  • Reset can be called many times
  • Reset vs. variable initialization in some languages (Verilog)
Problematic codeHLS possible solution
initial begin\nd = 1;\nend\nalways @(posedge clk) begin\nif (reset) begin\nd = 2;\n...\n
// Just use the reset flop values to initialize contents\n\nalways @(posedge clk) begin\nif (reset) begin\nd = 2;\n...\n

Artifact

Reset is different from variable initialization

"},{"location":"pyrope/00-hwdesign/#non-blocking-assignments","title":"Non-blocking assignments","text":"

Many HDLs have what hardware designers call \"non-blocking assignments\". The idea is that in hardware, when assigning a variable, the designer could think about the \"result at the end of this cycle\" rather than \"update this mutable variable\".

Technically, a nonblocking assignment is an assignment to a variable, but the variable will be updated only at the end of the cycle. To illustrate the concept, imagine a counter. The counter can be updated with a non-blocking assignment and following statements could still read the value before the scheduled update.

Problematic codeHLS possible solution
counter <- counter + 1  // non-blocking assignment\ntmp     <- counter + 2  // non-blocking assignment\nassert tmp == (counter+1) // this may FAIL!\n
// Do not use non-blocking\ncounter = counter + 1  // blocking assignment\ntmp     = counter + 2  // blocking assignment\nassert tmp == (counter+1) // this never fails\n

Artifact

Some HDLs support non-blocking assignments which are not found in software.

"},{"location":"pyrope/00-hwdesign/#invalid-code","title":"Invalid code","text":"

HDLs can generate invalid code that can not be fabricated, or it is strongly recommended not to be fabricated. Examples are:

  • Combinational loops. Creating a loop with combinational logic is generally considered a bug (only a few circuits could accept this). If the combinational loop is inside a mux, it can be difficult to catch during verification unless a good toggle coverage results.

  • Implicit latches. Some HDLs like Verilog can generate code with implicit latches. Since the module is executed each time, variables with a missing initialization can remember results from the last cycles generating implicit latches. Most ASIC tools do not accept this, and it is considered a bug.

  • Bogus flow. Any compile (software or hardware) can have bugs, but because hardware compilers tend to have a smaller user base; they have more bugs than typical software compilers. Since this cost of fixing a bug is also higher, the solution is to have an additional verification or logical equivalence test.

If the compile generates an executable in software flows, it is considered a valid executable unless invalid assembly directives are used. In most HDLs, this is not the case due to constructs like combinational loops.

Artifact

HDLs can generate invalid synthesis and/or simulation code.

"},{"location":"pyrope/00-hwdesign/#multi-value-logic","title":"Multi value logic","text":"

Software designers are used to binary numbers with 0s and 1s. In many HDLs, there are more than two possible states for each bit. In languages like Verilog, there are four states: 0, 1, ? or z. Where ? is a \"quantum\" like state indicating that it is both zero and one simultaneously, and the z indicates that it is in high impedance, which means that nobody is writing the value. Some languages like VHDL have even more states.

The challenge is that when running code, the result may be unexpected. There are many discussions on addressing what the community calls \"x-propagation.\" There is no agreement on the best solution. The reason for not removing ? is that some large structures will not be initialized because of overheads. Although widely considered dangerous, some engineers like the ? to allow more freedom to the synthesis tools8

There are three leading solutions categories:

  • Allow ? and run many simulations with different x-propagation rules.
  • Allow ? and randomly pick 0/1 for each ? bit at simulation time.
  • Do not allow ?.
Problematic codeHLS possible solution
x = 0b?   // a ? state\nif x {\nputs \"x is never true\"\n}\nreg signed [3:0] a = -1;\n$display(\"%b\\n\", a[5:1]); // displays xx111\n
// there is no agreement on the community, but possible solutions:\nx = 0b? // (1): compile error\nif x {  // (2): randomly pick 1 or 0\n}\nreg signed [3:0] a = -1;\n$display(\"%b\\n\", a[5:1]); // displays 11111 (sign extend)\n

Artifact

HDLs can operate over non-binary logic

"},{"location":"pyrope/00-hwdesign/#simpler-hdl-constructs","title":"Simpler HDL constructs","text":"

Not everything is more challenging in HDLs when compared with software programming languages. These are some differences that can make the HDLs simpler:

"},{"location":"pyrope/00-hwdesign/#unlimited-precision","title":"Unlimited precision","text":"

High-performance software must adjust to the hardware, and as such, there are several integer types (int, short, long). The result is that the programmer tends to be careful with overflows and type conversion. This is not a problem in hardware. If a 113 bits adder is needed, it can be synthesized. If only a 7 bits adder is required; the synthesis can create the smaller adder too.

Some HLS may have different integer sizes, but it is either a \"strange\" design the decision or just as a type check so that no unnecessary hardware is generated.

Overflow is a source of many subtle bugs. For example, experience programmers write a + (b-a))/2 not the expected (a+b)/2 because of integer overflow semantics. HDLs can handle this like unlimited precision scripting languages without the overhead.

"},{"location":"pyrope/00-hwdesign/#no-pointers","title":"No pointers","text":"

Memory and pointer management is big issue in most languages. Either garbage collection, manual, or alternative approaches. Since there is no global memory, there is no memory to manage. Maybe even more important, there is no need for pointers. This avoids another set of problems like null dereferencing.

"},{"location":"pyrope/00-hwdesign/#no-destructors","title":"No destructors","text":"

Since there is no global memory, there is no need to have garbage collection or the associated object destruction. If a \"hardware resource\" is utilized, it can not be recycled. As a result, the destructor may not make sense in hardware.

"},{"location":"pyrope/00-hwdesign/#pass-by-value","title":"Pass by value","text":"

Most software languages support passing function arguments either by value or reference. This is done to avoid copying the object that may reside in memory. Again, HLS has no memory. Therefore it is not as problematic.

Most HDLs only support passing by value. This is not a drawback but avoid another source of bugs without the cost overhead that it will represent in a Vonn Neumann machine.

"},{"location":"pyrope/00-hwdesign/#no-recursion","title":"No recursion","text":"

Most HDLs support recursion at compile-time but not at runtime. The reason is that there is no \"stack memory\". If the depth is bound, it can support run-time recursion, but the potentially sizeable combinational path would be \"strange\". Only manageable with retiming. As a result, most HDLs do not support runtime recursion.

  1. Multi-threaded CPUs are just an array of Von Neumann machines.\u00a0\u21a9

  2. In this document, we call any logic gate, flop, or memory array.\u00a0\u21a9

  3. There are other constraints like power, but the same idea/problem could be said for software design.\u00a0\u21a9

  4. Unbalance pipelines have higher overheads in power/area.\u00a0\u21a9

  5. Verilog modules could be seen as functions in a software language that can be instantiated in one or more places. The instantiation point sets a hierarchy of modules.\u00a0\u21a9

  6. Instantiation is the process of deciding which gates are fabricated or mapped in a given hardware design. In an ASIC, it is the process of selecting a set of gates that will be manufactured.\u00a0\u21a9

  7. Transistors can not be added at runtime.\u00a0\u21a9

  8. This is very controversial, and many companies coding styles do not allow the use of ? to improve synthesis results.\u00a0\u21a9

"},{"location":"pyrope/01-introduction/","title":"Introduction","text":"

Warning

This document explains the future Pyrope, some features are still not implemented. They are documented to guide the designers.

Pyrope is a modern hardware description language, with these focus points:

  • Fast parallel and incremental elaboration
  • Modern and concise language
  • Avoiding hardware specific artifacts
    • Allows optional hierarchical calls
    • Supports instantiation optimization with typical software syntax
    • Supports pipelining constructs
    • No mismatch simulation vs synthesis
    • Single reset mechanism
    • Avoid non-blocking assignments
    • Checks on invalid code
    • Random on multi value logic when doing control flow
  • Zero cost abstraction
  • Help hardware verification:
    • Powerful type system
    • Hot-Reload support, powerful assertions
    • Allows Pyrope 2 Verilog, edit Verilog, Verilog 2 Pyrope, edit Pyrope...
    • Static checks as long as they not produce false positives
"},{"location":"pyrope/01-introduction/#hello-world","title":"Hello world","text":"

Create a directory for the project:

$ mkdir hello\n$ cd hello\n$ mkdir src\n

Populate the Pyrope code

src/hello.prp

test \"my first test\" {\n  puts \"hello world\"\n}\n

Run

$prp test\n

All the pyrope files reside in the src directory. The prp builder calls LiveHD to elaborate the pyrope files and run all the tests.

"},{"location":"pyrope/01-introduction/#trivial-gcd","title":"Trivial GCD","text":"

Populate the Pyrope code

PyropeCHISEL

src/gcd.prp:

var gcd = proc (a:uint,b:uint)->(reg x:uint) {\n  x = a\n  reg y = b\n\n  while y!=0 #> {\n    if x > y { \n      x -= y \n    }else{ \n      y -= x \n    }\n  }\n}\n\nfor a in 1..=100 {\n  for b in 1..=100 {\n    test \"check.gcd({},{})\",a,b {\n      let z =#[..] gcd(a,b)\n\n      waitfor z?\n\n      assert z == __my_cpp_gcd(v1=a, v2=b)\n    }\n  }\n}\n

src/my_cpp_gcd.cpp

void my_gcd_cpp(const Lbundle &inp, Lbundle &out) {\nassert(inp.has_const(\"v1\") && inp.has_const(\"v2\"));\n\nauto x = inp.get_const(\"v1\");\nauto y = inp.get_const(\"v2\");\n\nwhile (y > 0) {\nif (x > y) {\nx -= y\n}else{\ny -= x\n}\n}\n\nout.add_const(x);\n}\n

import Chisel._\nimport firrtl_interpreter.InterpretiveTester\nimport org.scalatest.{Matchers, FlatSpec}\n\nobject GCDCalculator {\ndef computeGcd(a: Int, b: Int): (Int, Int) = {\nvar x = a\nvar y = b\nwhile(y > 0 ) {\nif (x > y) {\nx -= y\n}\nelse {\ny -= x\n}\n}\nx\n}\n}\n\nclass GCD extends Module {\nval io = new Bundle {\nval a  = UInt(INPUT,  16)\nval b  = UInt(INPUT,  16)\nval e  = Bool(INPUT)\nval z  = UInt(OUTPUT, 16)\nval v  = Bool(OUTPUT)\n}\nval x  = Reg(UInt())\nval y  = Reg(UInt())\nwhen   (x > y) { x := x - y }\nunless (x > y) { y := y - x }\nwhen (io.e) { x := io.a; y := io.b }\nio.z := x\nio.v := y === UInt(0)\n}\n\nclass InterpreterUsageSpec extends FlatSpec with Matchers {\n\n\"GCD\" should \"return correct values for a range of inputs\" in {\nval s = Driver.emit(() => new GCD)\n\nval tester = new InterpretiveTester(s)\n\nfor {\ni <- 1 to 100\nj <- 1 to 100\n} {\ntester.poke(\"io_a\", i)\ntester.poke(\"io_b\", j)\ntester.poke(\"io_e\", 1)\ntester.step()\ntester.poke(\"io_e\", 0)\n\nwhile (tester.peek(\"io_v\") != BigInt(1)) {\ntester.step()\n}\ntester.expect(\"io_z\", BigInt(GCDCalculator.computeGcd(i, j)._1))\n}\ntester.report()\n}\n}\n

Run

$prp test check.gcd\n

The gcd.prp includes the top-level module (gcd) and the unit test.

  • Some Pyrope features not common in other HDLs (CHISEL):

    • Pyrope is not a DSL. Most modern HDLs like CHISEL, pyMTL, pyRTL, C\u03bbaSH are DSL cases. In these cases, there is a host language (SCALA, or Python, or Haskell) that must be executed. The result of the execution is the hardware description which can be Verilog or some internal IR like FIRRTL in CHISEL. The advantage of the DSL is that it can leverage the existing language to have a nice hardware generator. The disadvantage is that there are 2 languages at once, the DSL and the host language, and that it is difficult to do incremental because the generated executable from the host language must be executed to generate the design.

    • Global type inference. In the gcd example, the input/outputs are inferred.

    • Synthesizable object system with runtime polymorphism

    • Immutable objects

    • Language support for several hardware constructs

  • Some Pyrope features not common in other languages

    • No object references, only pass by value

    • Pipelining support

"},{"location":"pyrope/02-basics/","title":"Basic syntax","text":""},{"location":"pyrope/02-basics/#comments","title":"Comments","text":"

Comments begin with //, there are no multi-line comments

// comment\na = 3 // another comment\n
"},{"location":"pyrope/02-basics/#constants","title":"Constants","text":""},{"location":"pyrope/02-basics/#integers","title":"Integers","text":"

Pyrope has unlimited precision signed integers. Any literal starting with a digit is a likely integer constant.

0xF_a_0 // 4000 in hexa. Underscores have no meaning\n0b1100  // 12 in binary\n0sb1110 // -2 in binary (sb signed binary)\n33      // 33 in decimal\n0o111   // 73 in octal\n0111    // 111 in decimal (some languages use octal here)\n

Since powers of two are very common, Pyrope decimal integers can use the K, M, G, and T modifiers.

assert 1K == 1024\nassert 1M == 1024*1024\nassert 1G == 1024*1024*1024\nassert 1T == 1024*1024*1024*1024\n

Several hardware languages support unknown bits (?) or high-impedance (z). Pyrope aims at being compatible with synthesizable Verilog, as such ? is also supported in the binary encoding.

0b?             // 0 or 1 in decimal\n0sb?            // 0 or -1 in decimal\n0b?0            // 0 or 2 in decimal\n0sb0?0          // 0 or 2 in decimal\n

The Verilog high impedance z is not supported. A bus construct must be used instead.

Like in many HDLs, Pyrope has unknowns ?. The x-propagation is a source of complexity in most hardware models. Pyrope has x or ? to be compatible with Verilog existing designs. This means that inside the Pyrope compiler, the constant operations with unknowns are compatible with Verilog semantics. When the simulation is performed, the expectation is to randomly generate a 0 or 1 for each unknown (?) bit.

The advice is not to use ? besides match statement pattern matching. It is less error prone to use the default value (zero or empty string), but sometimes it is easier to use nil when converting Verilog code to Pyrope code. The nil means that the numeric value is invalid. If any operation is performed with nil, the result is an assertion failure. The only thing allowed to do with nil is to copy it. While the nil behaves like an invalid value, the 0sb? behaves like an unknown value that still can be used in arithmetic operations. E.g: 0sb? | 1 is 1 but nil | 1 is an assertion error.

Notice that nil is a state in the integer basic type, it is not a new type by itself, it does not represent an invalid pointer, but rather an invalid integer. Also important is that the compiler will guarantee that all the nil are eliminated at compile time or a compile error is generated.

"},{"location":"pyrope/02-basics/#strings","title":"Strings","text":"

Pyrope accepts single line strings with a single quote (') or double quote (\"). Single quote does not have escape character, double quote supports escape sequences.

a = \"hello \\n newline\"\nb = 'simpler here'\n
  • \\n: newline
  • \\\\: backslash
  • \\\": double quote
  • `: backtick quote
  • \\xNN: hexadecimal 8 bit character (2 digits)
  • \\uNNNN: hexadecimal 16-bit Unicode character UTF-8 encoded (4 digits)

Pyrope allows string interpolation only when double quote is used. Nevertheless, when string interpolation is used, the formatting guidelines are not allowed. The style is like C++ fmt::format which allows an identifier. When the identifier is provided the string is processed accordingly.

let num       = 2\nlet color     = \"blue\"\nlet extension = \"s\"\n\nlet txt1 = \"I have {num} {color} potato{extension}\"\nlet txt2 = format('I have {:d} {} potato{} ', num, color, extension)\ncassert txt1 == txt2 == \"I have 2 blue potatos\"\n\nlet txt3 = 'I have {num}'         // single quote does not do interpolation\ncassert txt3 == \"I have \\{num\\}\"  // \\{ escapes the interpolation\n

Integers and strings can be converted back and forth:

var a:string = \"127\"\nvar b:int    = a     // same as var b = int(a)\nvar c:string = b     // same as var c = string(b)\nassert a == c\nassert b == 0x7F\nassert a == b        // compile error, 'a' and 'b' have different types\n
"},{"location":"pyrope/02-basics/#newlines-and-spaces","title":"Newlines and spaces","text":"

Spaces do not have meaning but new lines do. Several programming languages like Python use indentation level (spaces) to know the parsing meaning of expressions. In Pyrope, spaces do not have meaning, and newlines combined with the first token after newline is enough to decide the end of statement.

By looking at the first character after a new line, it is possible to know if the rest of the line belongs to the previous statement or it is a new statement.

If the line starts with an alphanumeric ([a-z0-9] that excludes operators like or, and) value or an open parenthesis ((), the rest of the line belongs to a new statement.

var (a,b,c,d) = _\na = 1\n  + 3           // 1st stmt\n(b,c) = (1,3)   // 2nd stmt\ncassert a == 4 and b == 1 and c == 3\n\nd = 1 +         // OK, but not formatted to style\n    3\n

This functionality allows parallelizing the parsing and elaboration in Pyrope. More important, it makes the code more readable, by looking at the beginning of the line, it is possible to know if it is a new statement or a continuation of the last one. It also helps to standardize the code format by allowing only one style.

"},{"location":"pyrope/02-basics/#identifiers","title":"Identifiers","text":"

An identifier is any non-reserved keyword that starts with an underscore or an alphabetic character. Since Pyrope is designer to support any synthesizable Verilog automatic translation, any sequence of characters between backticks (`) can form a valid identifier. The identifier uses the same escape sequence as strings.

`foo is . strange!\\nidentifier` = 4\n`for` = 3\ncassert `for`+1 == `foo is . strange!\\nidentifier`\n

Using the backtick, Pyrope can use any string as an identifier, even reserved keywords. Identifiers are case sensitive like Verilog, but the compiler issues errors for non ` escaped identifiers that do not follow these conditions in order:

  • Identifiers with a single character followed by a number can be upper or lower case.
  • An all upper case variable must be a compile time constant comptime.
  • Types should either: (1) start the first character uppercase and everything else lower case; (2) be all lower case and finish with _t.
  • All the other identifiers that start with an alpha character [a-z] are always lower case.
"},{"location":"pyrope/02-basics/#semicolons","title":"Semicolons","text":"

Semicolons are not needed to separate statements. In Pyrope, a semicolon (;) has the same meaning as a newline. Sometimes it is possible to add semicolons to separate statements. Since newlines affect the meaning of the program, a semicolon can do too.

a = 1 ; b = 2\n
"},{"location":"pyrope/02-basics/#printing-and-debugging","title":"Printing and debugging","text":"

Printing messages is useful for debugging. puts prints a message and the string is formatted using the c++20 fmt format. There is an implicit newline printed. The same without a newline can be achieved with print.

a = 1\nputs \"Hello a is {}\", a\n

Pyrope does string interpolation, and it has attributes to access line of code and file name. Since tracing or debugging variables is quite common, the dbg statement behaves like puts and also prints the line of code and file name for easier tracing.

a = 1                                            // file foo line 3\nputs \"{}:{} a:{} tracing a\", a.[file], a.[loc], a\nputs \"{a.[file]}:{a.loc} a:{a} tracing a\"        // Same as previous\ndbg a, \"tracing a\"\n

The previous statements print \"foo:3 a:1 tracing a\" in the 3 cases. The line of code corresponds to the latest update of variable, not the dbg statement.

Since many modules can print at the same cycle, it is possible to put a relative priority between puts (priority). If no relative priority is provided, a default 0 priority is provided. Messages are kept to the end of the cycle, and then printed in alphabetical order for a given priority. This is done to be deterministic. Higher priority (higher value) are printed after lower priority. Messages generated by assertions also get serialized like puts statements but have the highest priority.

To avoid breaking down different puts inside the same method. All the puts in a given cycle are shown together.

This example will print \"hello world\" even though there are 2 puts/prints in different files.

// src/file1.prp\nputs(priority=2, \" world\")\n\n// src/file2.prp\nprint(priority=1, \"hello\")\n

The available puts/print arguments: * priority: relative order to print in a given cycle. * file: file to send the message. E.g: stdout, stderr, my_large.log,...

A related command to the puts is the format it behaves like print but returns a string.

puts/print are a bit special. In most languages, IO operations like puts are considered to have side-effects. In Pyrope, the puts can not modify the behavior of the synthesized code and it is considered a non-side-effect lambda call. This allows to have puts calls in functions.

"},{"location":"pyrope/02-basics/#functions-and-procedures","title":"Functions and procedures","text":"

Pyrope only supports anonymous lambdas. A lambda can be assigned to a variable, and it can be called as most programmers expect. Lambda section has more details on the allowed syntax.

var f = fun(a,b) { a + b }\n

Pyrope naming for consistency:

  • lambda is any sequence of statements grouped in a code block that can be assigned to a variable and called to execute later.

  • function is a lambda with only combination statements without non-Pyrope calls.

  • procedure is a lambda that can have combination like function but also non-combinational (register/memories). Procedures are a superset of functions.

  • method is a lambda (function or procedure) that updates another variable. The first argument is an explicit self.

  • module is a lambda that has a physical instance. Lambdas are either inlined or modules.

lambda are not only restricted to Pyrope code. It is possible to interface with non-Pyrope (C++) code, but the calls should respect the same procedure/function definition. A C++ function can not update the C++ internal state or generate output because the simulation/compiler is allowed to call it multiple times. This is not the case for C++ procedure.

"},{"location":"pyrope/02-basics/#evaluation-order","title":"Evaluation order","text":"

Statements are evaluated one after another in program order. The main source of conflicts come from expressions.

The expression evaluation order is important if the elements in the expression can have side effects. Pyrope constrains the expressions so that no matter the evaluation order, the synthesis result is the same.

As a reference, languages like C++11 do not have a defined order of evaluation for all types of expressions. Calling call1() + call2() is not defined. Either call1() first or call2() first.

In many languages, the evaluation order is defined for logical expressions. This is typically called the short-circuit evaluation. Some languages like Pascal, Rust, Kotlin have different and/or to express conditional evaluation. In Pascal, there is an and/or and and_then/or_else (conditional). In Rust &/| and &&/|| (conditional). In Kotlin &&/|| and and/or (conditional). Pyrope uses has the and/or without short-circuit, and the and_then/or_else with explicit short-circuit.

The programmer can explicitly set an evaluation order by using short-circuit expressions like and_then, or_else, or control expressions (if/else, match, for). An expression can have many function calls because those have no side-effects, and hence the evaluation order is not important.

A procedure is an lambda that can update state internally. It can be through a C++ API call, or some synthesizable state. As such, only one procedure call can exist per expression.

var a = fcall() + 1               // OK\nvar x = pcall() + a               // OK, proc combined with variable read\nvar b = fcall(a) + 10 + pcall(a)  // OK\nvar d = t.pcall() + pcall2(b)     // compile error, multiple procedure calls\nvar y = t.pcall() + t.pcall()     // compile error, multiple procedure calls\n

Expressions also can have a code blocks ({ }) as long as there are no side-effects. In a way, expression code blocks can be seen as a type of functions that are called immedialy after definition.

var a = {var d=3 ; last d+1} + 100 // OK\nassert a == (3+1+100)\nassert a == {3+1+100}  // same, expression evaluated as 104 and returned\n

For most expressions, Pyrope is more restrictive than other languages because it wants to be a fully defined deterministic independent of implementation. To handle logging/messaging in function calls, Pyrope treats puts as a special instruction. Pyrope runtime delays the puts output until the end of the cycle. Section (Printing)[02-basics.md#printing] has more details.

To illustrate the evaluation order, it is useful to see a Verilog example. The following Verilog sequence evaluates differently in VCS and Icarus Verilog. Pyrope treats puts and assertion messages in a special way. The reason why some methods may be called is dependent on the optimization (in this case, testing(1) got optimized away by vcs).

module test();\n\nfunction testing(input [0:3] a);\nbegin\n$display(\"test called with %d\",a);\ntesting=1;\nend\nendfunction\n\ninitial begin\nif (0 && testing(1)) begin\n$display(\"test1\");\nend\n\nif (1 && testing(2)) begin\n$display(\"test2\");\nend\n\nif (0 || testing(3)) begin\n$display(\"test3\");\nend\n\nif (1 || testing(4)) begin\n$display(\"test4\");\nend\nend\n
Icarus outputVCS outputC++/short-circuit output
test called with  1\ntest called with  2\ntest2\ntest called with  3\ntest3\ntest called with  4\ntest4\n
test called with  2\ntest2\ntest called with  3\ntest3\ntest called with  4\ntest4\n
test called with 2\ntest2\ntest called with 3\ntest3\ntest4\n

If an order is needed and a function call can have debug side-effects or synthesis side-effects, the statement must be broken down into several statements, or the and_then and or_else operations must be used.

Incorrect code with side-effectsAlternative 1Alternative 2
var r1 = pcall1() or  pcall2()  // compile error, non-deterministic\n\n\nvar r2 = pcall1() and pcall2()  // compile error, non-deterministic\n\n\nvar r3 = pcall1() +   pcall2()  // compile error\n// compile error only if pcall1/pcall2 can have side effects\n
var r1 = fcall1()\nr1  = fcall2() unless r1\n\nvar r2 = fcall1()\nr2  = fcall2() when r2\n\nvar r3 = fcall1()\nr3 += fcall2()\n
var r1 = fcall1() or_else fcall2()\n\n\nvar r2 = fcall1() and_then fcall2()\n\n\nvar r3 = fcall1()\nr3 += fcall2()\n
"},{"location":"pyrope/02-basics/#basic-gates","title":"Basic gates","text":"

Pyrope allows a low level or structural direct basic gate instantiation. There are some basic gates to which to which the compiler translates Pyrope code to. These basic gates are also directly accesible:

  • __sum for addition and substraction gate.
  • __mult for multiplication gate.
  • __div for divisions gate.
  • __and for bitwise and gate
  • __or for bitwise or gate
  • __xor for bitwise xor gate
  • __ror for bitwise reduce-or gate
  • __not for bitwise not gate
  • __get_mask for extrating bits using a mask gate
  • __set_mask for replacing bits using a mask gate
  • __sext for sign-extension gate
  • __lt for less-than comparison gate
  • __ge for greater-equal comparison gate
  • __eq for equal comparison gate
  • __shl for shift left logical gate
  • __sra for shift right arithmetic gate
  • __lut for Look-Up-Table gate
  • __mux for a priority multiplexer
  • __hotmux for a one-hot excoded multiplexer
  • __memory for a memory gate
  • __flop for a flop gate
  • __latch for a latch gate

Each of the basic gates operate always over signed integers like Pyrope, but their semantics vary. A more detailed explanation is available at LiveHD cell type section.

"},{"location":"pyrope/02-basics/#initialization","title":"Initialization","text":"

Each variable declaration (var or let) must have an assigned value. The type default value is _ (0 integer, \"\" string, false boolean, nil otherwise)

a  = 3        // compile error, no previous let or var\n\nvar b = 3\nb  = 5        // OK\nb += 1        // OK\n\nlet cu3 = if runtime { 3 }else{ 5 }\n\nlet d = \"hello\"  // OK\nd = \"bar\"        // compile error, 'd' is immutable\nvar d = \"bar\"    // compile error, 'd' already declared\n\nvar e = _        // OK, no type or default value, just scope declaration\ne:u32 = 33       // OK\n\nvar Foo = 33     // compiler error, 'let Foo = 33'\nFoo  = 33        // compiler error, `Foo` already declared as immutable\n

When the variable is a tuple or a range style, the default initialization is nil. 0sb? can not be applied to ranges or tuples value because it is restricted for integers. nil should be used in those cases.

var tup = nil\n\nif cond::[comptime] {\n  tup = (a=1,b=2)\n}else{\n  tup = (a=1,b:u4=3,c=3)\n}\n\ncassert tup.a == 1\ncassert cond implies tup.b==2\ncassert !cond implies tup.b==3\n

Variables with first character upper case are comptime. This means that the contents must be known/fix at compilation time.

var A_xxx = something             // comptime\nvar A_yyy::[comptime] = something // also comptime, redundant but legal\n
"},{"location":"pyrope/03-bundle/","title":"Tuples","text":"

Tuples are a basic construct in Pyrope. Tuples are defined as an \"ordered\" sequence fields that can be named. Arrays/memories are a subcategory of tuples by requiring all the entries to have the same type. Internally, there is not a difference between tuples and arrays, but it is possible to check that all the fields are the same (hence array) by using brackets instead of parenthesis.

var b = (f1=3,f2=4) // b is named and ordered\nvar c = (1,d=4)     // c is ordered and unnamed (some entries are not named)\n\nvar d = (1,2,3,4)     // array or tuple\nassert d == [1,2,3,4] // the [] also check that all the fields have same type\n\nassert (true,1) != [true,1]  // compile error, true is not the same type as 1\n

To access fields in a tuple we use the dot . or []

var a = (\n  ,r1 = (b=1,c=2)\n  ,r2 = (3,4)\n)\n// tuple position is from left to right\ncassert a.r1 == (1,2) and a.r2 == (3,4)\ncassert a.0  == (1,2) and a[1] == (3,4)\n\n// different ways to access the same field\ncassert a.r1.c    == 2\ncassert a['r1'].c == 2\ncassert a.r1.1    == 2\ncassert a.r1[1]   == 2\ncassert a[0][1]   == 2\ncassert a[0]['c'] == 2\ncassert a['r1.c'] == 2\ncassert a['r1.1'] == 2\ncassert a['0.c']  == 2\ncassert a['0.1']  == 2\ncassert a.0.c     == 2\ncassert a.0.1     == 2\n

The only main difference between a.0 (dot) and a[0] (select) access is that dot access guarantees to be compile time index, while the select can have compile time or run-time index.

There is introspection to check for an existing field with the has and !has operators.

var a = (foo = 3)\ncassert a has 'foo'\ncassert !(a has 'bar')\ncassert a !has 'bar' // \"has no\" is the opposite of \"has\"\ncassert a has 0\ncassert a !has 1\ncassert a !has 1\n

Tuple named fields can have a default type and or contents:

var val = 4\nvar x = (\n  ,field1=1           // field1 with implicit type and 1 value\n  ,field2:string = _  // field2 with explicit type and \"\" default value\n  ,field3:int = 3     // field3 with explicit type and 3 value\n  ,val                // unnamed field with value `val` (4)\n)\n
"},{"location":"pyrope/03-bundle/#tuple-and-scope","title":"Tuple and scope","text":"

Since tuples can be named or unnamed, an entry like xx=(foo) creates a tuple xx and copies the current scope variable foo contents as the first entry. In many cases it is required to pass a sequence of strings or identifiers. A solution is to name all the fields or quote as strings:

var x=100\n\nvar tup1 = ('x',y=4)\nvar tup2 = (x,y=4)\n\ncassert tup1[0] == 'x'\ncassert tup2[0] == 100\n

Some constructs like enumerates and attributes typically pass identifiers without assigning a value. The problem is that the syntax becomes not so \"nice\". To address these cases, Pyrope does not use a variable reference but a \"string\" in the enumerate (enum(a,b=3)) and attribute (foo::[attr], foo.[attr]). In these constructs, a reference can be enforced with ...var

let aa = 3\nlet a = enum(aa,b=3)\ncassert a==b\n\ncassert x.[size] == x.['size']\n\nlet zz= \"size\"\ncassert x.[...zz] == x.[size]\n
"},{"location":"pyrope/03-bundle/#everything-is-a-tuple","title":"Everything is a tuple","text":"

In Pyrope everything is a Tuple, and it has some implications that this section tries to clarify.

A tuple starts with ( and finishes with ). In most languages, the parentheses have two meanings, operation precedence and/or tuple/record. In Pyrope, since a single element is a tuple too, the parenthesis always means a tuple.

A code like (1+(2),4) can be read as \"Create a tuple of two entries. The first entry is the result of the addition of 1 (which is a tuple of 1) and a tuple that has 2 as a unique entry. The second entry in the tuple is 4\".

The tuple entries are separated by comma (,). Extra commas do not add meaning.

var a = (1,2)   // tuple of 2 entries, 1 and 2\nvar b = (1)     // tuple of 1 entry, 1\nvar c = 1       // tuple of 1 entry, 1\nvar d = (,,1,,) // tuple of 1 entry, 1\ncassert a.0 == b.0 == c.0 == d.0\ncassert a!=b\ncassert b == c == d\n

A tuple with a single entry element is called a scalar.

Tuples are used in many places:

  • The arguments for a call function are a tuple. E.g: fcall(1,2)
  • The return of a function call is always a tuple. E.g: foo = fcall()
  • The index for a selector [...] is a tuple. As syntax sugar, the tuple parenthesis can be omitted. E.g: foo@[0,2,3]
  • The complex type declaration are a tuple. E.g: let Xtype = (f=1,b:string)
"},{"location":"pyrope/03-bundle/#tuple-mutability","title":"Tuple mutability","text":"

The tuple entries can be mutable/immutable and named/unnamed. Tuple entries follow the variable mutability rules with the exception that = can be used to declare a mutable field. (a=3) is equivalent to (var a=3).

var c=(x=1,let b = 2, var d=3)\nc.x   = 3  // OK\nx.foo = 2  // compile error, tuple 'x' does not have field 'foo'\nc.b   = 10 // compile error, 'c.b' is immutable\nc.d   = 30 // OK, d was already mutable type\n\nlet d=(x=1, let y=2, var z=3)\nd.x   = 2  // OK\nd.foo = 3  // compile error, tuple 'd' does not have field foo'\nd.z   = 4  // compile error, 'd' is immutable\n\nvar e:d = _\nassert e.x==1 and e.y==2 and e.z==3\ne.x = 30   // OK\ne.y = 30   // compile error, 'e.y' is immutable\ne.z = 30   // OK\n

Tuples are always ordered, but they can have unnamed entries. If needed a _ can be used for name or default value during the tuple declaration.

var b = 100\nvar a = (b:u8, b, b:u8 = _, let c=4) // a.0 and a.1 are unnamed, a.2==a.b \na.b = 200\nassert a == (100, 100, 200, 4)\n\nvar f = (b=3, let e=5)\nf.b = 4                 // OK\nf.e = 10                // compile error, `f.e` is immutable\n\nlet x = (1,2)\nx[0] = 3                // compile error, 'x' is immutable\nvar y = (1, let _ = 3)  // 2nd field is unnamed (only let allows that)\ny[0] = 100              // OK\ny[1] = 101              // compile error, `y[1]` is immutable\n

While the tuple entries can be either mutable or immutable, the field name/types are immutable. It is possible to construct new tuples with the ++ (concatenate) and ... (in-place operator):

var a=(a=1,b=2)\nlet b=(c=3)\n\nlet ccat1 = a ++ b\nassert ccat1 == (a=1,b=2,c=3)\nassert ccat1 == (1,2,3)\n\nvar ccat2 = a                // mutable tuple\na = a ++ (b=20)\nassert ccat2 == (a=1,b=(2,20),c=3)\nassert ccat2 == (1,(2,20),3)\n\nvar join1 = (...a,...b)\nassert join1 == (a=1,b=2,c=3)\nassert join1 == (1,2,3)\n\nvar join2 = (...a,...(b=20)) // compile error, 'b' already exists\n

The a ++ b concatenates two tuples. If the same field exists in both tuples, the resulting field will have a tuple with the entries of a and b. The concat tries to match by field name, if the field names do not match or have no name a new entry is created. The algorithm starts with tuple a and starts from tuple field 0 upwards.

assert(((1,a=2,c=3) ++ (a=20,33,c=30,4)) == (1,a=(2,20),c=(3,30),33,4))\n

The ... also concatenates, but it is an \"inline concatenate\". The difference is where the fields are concatenated and that it triggers a compile error if the same entry already exists.

"},{"location":"pyrope/03-bundle/#field-access","title":"Field access","text":"

Since everything is a tuple, any variable can do variable.0.0.0.0 because it literaly means, return the tuple first entry for four times.

Another useful shortcut is when a tuple has a single field or entry, the tuple contents can be accessed without requiring the individual position or field entry name. This is quite useful for function return tuples with a single entry.

let x = (first=(second=3))\n\nassert x.first.second == 3\nassert x.first        == 3\nassert x              == 3\nassert x.0.second     == 3\nassert x.first.0      == 3\nassert x.0            == 3\n
"},{"location":"pyrope/03-bundle/#tuples-vs-arrays","title":"Tuples vs arrays","text":"

Tuples are ordered, as such, it is possible to use them as arrays. Tuples and arrays share most behavior/operations, the key difference is that arrays are unnamed with the same type for all the entries.

var bund1 = (0,1,2,3,4) // ordered and can be used as an array\n\nvar bund2 = (bund1,bund1,((10,20),30))\nassert bund2[0][1] == 1\nassert bund2[1][1] == 1\nassert bund2[2][0] == (10,20)\nassert bund2[2][0][1] == 20\nassert bund2[2][1] == 30\n

Pyrope tries to be compatible with synthesizable Verilog. In Verilog, when an out of bounds, access is performed in a packed array (unpacked arrays are not synthesizable), or an index has unknown bits (?), a runtime warning can be generated and the result is an unknown (0sb?). Notice that this is a pessimistic assumption because maybe all the entries have the same value when the index has unknowns.

The Pyrope compile will trigger compile errors for out-of-bound access. It is not possible to create an array index that may perform an out of bounds access.

var array = (0,1,2)       // size 3, not 4\nlet tmp = array[3]        // compile error, out of bounds access\nvar index = 2\nif runtime {\n  index = 4\n}\n// Index can be 2 or 4\n\nvar res1 = array[index]   // compile error, out of bounds access \n\nvar res2 = 0sb?           // Possible code to be compatible with Verilog\nif index<3 {\n  res = array[index]      // OK\n}\n

Pyrope compiler will allow an index of an array/tuple with unknowns. If the index has unknown bits (0sb? or 0b1?0) but the compiler can not know, the result will have unknowns (see internals for more details). Notice that the only way to have unknowns is that somewhere else a variable or a memory was explicitly initialized with unknowns. The default initialization in Pyrope is 0, not unknown like Verilog.

"},{"location":"pyrope/03-bundle/#concatenate-fields","title":"Concatenate fields","text":"

Each tuple field must be unique. Nevertheless, it is practical to have fields that add more subfields. This is the case for overloading. To append or concatenate in a given field the ++= operator can be assigned.

var x = (\n  ,ff = 1\n  ,ff = 2 // compile error\n)\n\nvar y = (\n  ,ff = 1\n  ,ff ++= 2\n  ,zz ++= 3\n)\nassert y == (ff=(1,2),zz=3)\n
"},{"location":"pyrope/03-bundle/#optional-tuple-parenthesis","title":"Optional tuple parenthesis","text":"

Parenthesis marks the beginning and the end of a tuple. Those parentheses can be avoided for an unnamed tuple in some cases:

  • When doing a simple function call at the beginning of a line.
  • When used inside a selector [...].
  • When used after an in operator followed by a { like in a for and match statements.
  • For the inputs in a match statement.
  • A single element lambda return value.
fcall 1,2         // same as: fcall(1,2)\nb = xx[1,2]       // same as: xx[(1,2)]\n\nfor a in 1,2,3 {  // same as: for a in (1,2,3) {\n  x = a\n}\ny = match z {    \n  in 1,2 { 4 }    // same as: in (1,2) { 4 }\n  else { 5 }\n}\ny2 = match var one=1 ; one ++ z {  // same as: y2 = match (1,z) {\n  == (1,2) { 4 }\n}\n\nlet addb = fun(a,b:u32)-> a:u32 { // same as: letaddb = fun(a,b:u32)->(a:u32)  \n  a = a + b\n}\n

A named tuple parenthesis can be omitted on the left-hand side of an assignment. This is to mutate or declare multiple variables at once. It is not allowed to avoid the parenthesis at the right-hand-side of the statement. The reason is that it is a bit confusing.

var a,b = (2,3)    // compile error, left-hand-side must be a tuple (a,b)\nvar (a,b) = 2,3    // compile error, right-hand-side must be a tuple (2,3)\nvar (a,b) = (2,3)\nassert a==2 and b==3\n\nvar (c,d) = 1..=2  // compile error, range is a single entry assignment\nvar c = 1..=2      // OK\nvar (c,d) = 1      // compile error, 2 entry tuple in lhs, same in rhs\nvar (c,d) = (1,2)  // OK\nassert c == 1 and d == 2\n

One thing to remember is that the = separates the statement in two parts (left and right), this is not the case with type or attributes that always apply to the immediatly declared variable or item.

let c = 4\nlet (x,b) = (true, c:u3) // assign x=true, b=4 AND check that c is type u3\n\ncassert x == true\ncassert b == 4 \n
"},{"location":"pyrope/03-bundle/#enumerate-enum","title":"Enumerate (enum)","text":"

Enumerates, or enums for short, use the familiar tuple structure, but there is a significant difference in initialization. Enums require named tuples, but in most cases the named tupled should not have a set value. Enums automatically assigns values, tuples need explicit value initialization.

let b = \"foo\"\nlet c = 1\nlet test1     = enum(a=c,b)    // OK\nlet something = (b)            // OK\ncassert something == \"foo\"\ncassert test1.a != test1.b\ncassert test1.a==1 and test1.b==2\n

The enum keyword does not reference scope variables unless the reference is on the right-hand-side.

If an external variable wants to be used as a field, there has to be an explicit expression with a string type or a named tuple.

let a = \"field\"\nlet c = (foo=4)\nlet my_other_enum = enum(...a,b=3,...c)\ncassert my_other_enum.field != my_other_enum.b\ncassert my_other_enum.b   == 3\ncassert my_other_enum.foo == 4\ncassert my_other_enum.foo != my_other_enum.b\n

The enum default values are NOT like typical non-hardware languages. The enum auto-created values use a one-hot encoding. The first entry has the first bit set, the 2nd the 2nd bit set. If an entry has a value, the next entry uses the next free bit. If any field is set, then the enumerate behaves like a traditional enumerate sequence.

let V3 = enum(\n   ,a\n   ,b\n   ,c\n)\ncassert V3.a == 1\ncassert V3.b == 2\ncassert V3.c == 4\n\nlet V4 = enum(\n   ,a\n   ,b=5\n   ,c\n)\ncassert V4.a == 0\ncassert V4.b == 5\ncassert V4.c == 6\n
"},{"location":"pyrope/03-bundle/#hierarchical-enumerates","title":"Hierarchical enumerates","text":"

Enum can accept hierarchical tuples. Each enum level follows the same algorithm. Each entry tries to find a new bit. In the case of the hierarchy, the lower hierarchy level bits are kept.

let Animal = enum(\n  ,bird  =(eagle, parrot)\n  ,mammal=(rat  , human )\n)\n\ncassert Animal.bird.eagle != Animal.mammal\ncassert Animal.bird != Animal.mammal.human\ncassert Animal.bird == Animal.bird.parrot\n\ncassert int(Animal.bird        ) == 0b000001\ncassert int(Animal.bird.eagle  ) == 0b000011\ncassert int(Animal.bird.parrot ) == 0b000101\ncassert int(Animal.mammal      ) == 0b001000\ncassert int(Animal.mammal.rat  ) == 0b011000\ncassert int(Animal.mammal.human) == 0b101000\n

In general, for each leaf enum, the number of bits is equivalent to the number of entries in the leaf tuple.

It is possible to use a sequence that is more consistent with traditional programming languages, but this only works with non-hierarchical enumerates when an integer type (:int, :u32, :i4 ...) is used.

let V5=enum(\n   ,a\n   ,b=5\n   ,c\n)\ncassert int(V5.a) == 0\ncassert int(V5.b) == 5\ncassert int(V5.c) == 6\n

The same syntax is used for enums to different objects. The hierarchy is not allowed when an ordered numbering is requested.

Enumerates of the same type can perform bitwise binary operations (and/or/xor/nand/xnor/xnor) and set operators (in/!in).

let human_rat = Animal.mammal.rat | Animal.mammal.human  // union op\n\nassert Animal.mammal      in human_rat\nassert Animal.mammal.rat  in human_rat\nassert Animal.bird       !in human_rat\n
"},{"location":"pyrope/03-bundle/#enumerate-typecast","title":"Enumerate typecast","text":"

To convert a string back and forth to an enumerate, explicit typecast is needed but possible.

let E3=enum(\n  ,l1=(\n    ,l1a\n    ,l1b\n    )\n  ,l2\n  )\ncassert string(E3.l1.l1a) == \"E3.l1.l1a\"\ncassert string(E3.l1) == \"E3.l1\"\ncassert E3(\"l1.l2\") == E3.l1.l2\n
"},{"location":"pyrope/04-variables/","title":"Variables and types","text":"

A variable is an instance of a given type. The type may be inferred from use. The basic types are Boolean, lambda, Integer, Range, and String. All those types can be combined with tuples.

"},{"location":"pyrope/04-variables/#variable-scope","title":"Variable scope","text":"

Scope constrains variables visibility. There are three types of scope delimitation in Pyrope: code block scope, lambda scope, and tuple scope. Each has a different set of rules constraining the variable visibility. Overall, the variable/field is visible from declaration until the end of scope.

Pyrope uses var or let to declare a variable, but all the declarations must have a value. _ is used to specify the default value (false for boolean, 0 for integer, \"\" for string, undefined lambda for lambda, and 0..=0 for range).

In all the cases, variable declaration is either: * let variable [:type] = expression * var variable [:type] = expression

In a tuple scope, variable [:type] = expression is equivalent to var variable [:type] = expression. This is to avoid the most common case where tuple fields are frequently declared var not let. This is different from lambda captures that declare a new variable but they are always immutable (let).

Code Block scopeLambda scopeTuple scope
assert a == 3        // compile error, undefined variable 'a'\nvar a = 3\n{\n  assert a == 3\n  a = 33             // OK. assign 33\n  a:int = 33         // OK, assign 33 and check that 'a' has type int\n  let b = 4\n  let a = 3333       // compile error, variable shadowing\n  var a = 33         // compile error, variable shadowing\n}\nassert b == 3        // compile error, undefined variable 'b'\n
assert a == 3        // compile error, undefined variable 'a'\nvar a = 3\nvar x = 10\nlet f1 = fun[a,x=a+1]() {\n  assert a == 3\n  a = 33             // compile error, capture/inputs are immutable\n  x = 300            // compile error, capture/inputs are immutable\n  let b = 4\n  let a = 3333       // compile error, variable shadowing\n  var a = 33         // compile error, variable shadowing\n  return b+3\n}\nassert f1() == 7\nassert x == 10\nassert b == 3        // compile error, undefined variable 'b'\n\nlet f2 = fun() {     // restrict scope\n  assert a == 3      // compile error, undefined variable 'a'\n}\nlet f3 = fun[ff=a]() { // restrict scope\n  assert ff == 3     // OK\n  ff = 3             // compile error, immutable variable\n}\n
var a = 3\nlet r1 = (\n  ,a = a+1           // same as var a = a+1\n  ,c = {assert a == 3 and self.a==4; 50}\n)\nr1.a = 33            // compile error, 'r1' is immutable variable\n\nvar r2 = (a=100, let c=(a=a+1, e=self.a+30))\nassert r2 == (a=100,c=(a=101, e=131))  // checks values not mutability\nr2.a = 33            // OK\nr2.c.a = 33          // compile error, 'r2.c' is immutable variable\n
  • Shadowing is not allowed in lambdas or code blocks. Tuples can redefine (shadow) the same variable but to use inside the tuple, the self keyword must be used always to access tuple scoped variables.

  • Lambdas and tuples upper scope variables are always immutable.

  • Lambdas can restrict upper scope visibility with [].

  • A variable is visible from definition until the end of scope in program order.

Since the captures and lambda inputs are always immutable, it is not allowed to declare them as var and redundant to declare them as let.

let f3 = fun(var x) { x + 1 }    // compile error, inputs are immutable\nlet f2 = fun[var x](z) { x + z } // compile error, captures are immutable\n

Tuple scope is also useful for declaring function default values:

fun example(a:int, b:int=self.a+5) -> (_:int) {\n  return a+b\n}\nassert example(a=3) == (a+a+5)\nassert example(6,7) == (6+7)\nassert example(6) == (6+6+5)\nassert example(b=3) !=0         // compile error: undefined `a` argument\n
"},{"location":"pyrope/04-variables/#basic-types","title":"Basic types","text":"

Pyrope has 8 basic types:

  • boolean: either true or false
  • enum: enumerated
  • fun: A function or pure combinational lambda
  • int: which is signed integer of unlimited precision
  • proc: A procedure or lambda with state/clock or side-effects
  • range: A one hot encoding of values 1..=3 == 0b1110
  • string: which is a sequence of characters
  • variant: An union without typecast

All the types except the function can be converted back and forth to an integer.

"},{"location":"pyrope/04-variables/#integer-or-int","title":"Integer or int","text":"

Integers have unlimited precision and they are always signed. Unlike most other languages, there is only one type for integer (unlimited), but the type system allows to add constrains to be checked when assigning the variable contents. Notice that the type is the same (u32 is the same type as i3, they just have different constraints):

  • int: an unlimited precision integer number.
  • unsigned: An integer basic type constrained to be a natural number.
  • u<num>: An integer basic type constrained to be a natural number with a maximum value of \\(2^{\\texttt{num}}\\). E.g: u10 can go from zero to 1024.
  • i<num>: an integer 2s complement number with a maximum value of \\(2^{\\texttt{num}-1}-1\\) and a minimum of \\(-2^{\\texttt{num}}\\).
  • int(a..<b): integer basic type constrained to be between a and b.
var a:int         = _ // any value, no constrain\nvar b:unsigned    = _ // only positive values\nvar c:u13         = _ // only from 0 to 1<<13\nvar d:int(20..=30)= _ // only values from 20 to 30 (both included)\nvar d:int(-5..<6) = _ // only values from -5 to 6 (6 not included)\nvar e:int(-1,0)   = _ // 1 bit integer: -1 or 0\n

Integers can have 3 value (0,1,?) expression or a nil. Section Integers has more details, but those values can not be part of the type requirement.

Integer typecast accepts strings as input. The string must be a valid formatted Pryope number or an assertion is raised.

"},{"location":"pyrope/04-variables/#boolean","title":"Boolean","text":"

A boolean is either true or false. Booleans can not mix with integers in expressions unless there is an explicit typecast (int(false)==0 and int(true)==-1) or the integer is a 1 bit signed integer (0 and -1). Unlike integers, booleans do not support undefined value. A typecast from integer to boolean will raise an assertion when the integer has undefined bits (?) or nil.

let b = true\nlet c = 3\n\nif c    { call(x) }  // compile error, 'c' is not a boolean expression\nif c!=0 { call(x) }  // OK\n\nvar d = b or false   // OK\nvar e = c or false   // compile error, 'c' is not a boolean\n\nlet e = 0xfeed\nif e@[3] {           // OK, bit extraction for single bit returns a boolean\n  call(x)\n}\n\nassert 0 == (int(true)  + 1)  // explicity typecast\nassert 1 == (int(false) + 1)  // explicity typecast\nassert boolean(33) or false   // explicity typecast\n

String input typecase is valid, but anything different than (\"0\", \"1\", \"-1\", \"true\", \"TRUE\", \"t\", \"false\", \"FALSE\", \"f\") raises an assertion failure.

Logical and arithmetic operations can not be mixed.

let x = a and b\nlet y = x + 1    // compile error: 'x' is a boolean, '1' is integer\n
"},{"location":"pyrope/04-variables/#lambda-funproc","title":"Lambda (fun/proc)","text":"

Lambdas have several options (see Functions), but from a high level they provide a sequence of statements and they have a tuple for input and a tuple for output. Lambdas also can capture values from declaration. Like strings, lambdas are always immutable objects but they can be assigned to mutable variables.

"},{"location":"pyrope/04-variables/#range","title":"Range","text":"

Ranges are very useful in hardware description languages to select bits. They are 3 ways to specify a closed range:

  • first..=last: Range from first to the last element, both included
  • first..<last: Range from first to last, but the last element is not included
  • first..+size: Range from first to first+size. Since there is size elements, it is equivalent to write first..<(first+last).

When used inside selectors ([range]) the ranges can be open (no first/last specified) or use negative numbers. Ranges only work with positive numbers, a negative number is to specify the distance from last.

  • [first..<-val] is the same as [first..<(last-val+1)]. The advantage is that the last or size in the tuple can be unknown.
  • [first..] is the same as [first..=-1].
let a = (1,2,3)\nassert a[0..] == (1,2,3)\nassert a[1..] == (2,3)\nassert a[..=1] == (1,2)\nassert a[..<2] == (1,2)\nassert a[1..<10] == (2,3)\n\nlet b = 0b0110_1001\nassert b@[1..]        == 0b0110_100\nassert b@[1..=-1]     == 0b0110_100\nassert b@[1..=-2]     == 0b0110_100  // unsigned result from bit selector\nassert b@sext[1..=-2] == 0sb110_100\nassert b@[1..=-3]     == 0sb10_100\nassert b@[1..<-3]     == 0b0_100\nassert b@[0]          == false\n

A range is a separate tuple. As such it can not directly compare with tupes. It requires an explicit conversion. If the range does not contain negative values, it can be converted to an integer back and forth which corresponds to a one-hot encoding.

Range type cast from integers use the same one-hot encoding. It is not possible to type cast from tuple to range, but it is possible from range to tuple.

let c = 1..=3\nassert int(c) == 0b1110\nassert range(0b01_1100) == 2..=4\n\nassert range(1,2,3)            // compile error, typecast not allowed\nassert (1,2,3) == tuple(1..=3)\n

In most cases, the range can be used in contructs like for for positive and negative numbers. The tuple typecast is not needed, but if placed the semantic is the same. The same tuple typecast is also optional when doing a comparison. Both ranges a step to change the step.

assert   int(0..=10 step  2) == 0b101_0101_0101\nassert tuple(0..=10 step  2) == ( 0,2,4,6,8,10)\nassert tuple(10..=0 step -2) == (10,8,6,4,2, 0)\nassert      (10..=0 step -2) == (10,8,6,4,2, 0)\n\nassert -1..=2 == (-1,0,1,2)\nlet x = -1..=2\n\nassert (i for i in 0..=10 step 2) == (0,2,4,6,8,10)\n

Since the range is an integer, a decreasing range should have the same meaning that an increasing range (1..=3 == 3..=1) but to avoid mistakes/confusions, Pyrope generates a compile error in decreasing ranges.

assert 5..=0                           // compile error, 5 + 1 never reaches 0\nassert 5..=0 step -1 == (5,4,3,2,1,0)\n

A closed range can be converted to a single integer or a tuple. A range encoded as an integer is a set of one-hot encodings. As such, there is no order, but in Pyrope, ranges always have the order from smallest to largest. The step expr can be added to indicate a step or step function. This is only possible when both begin and end of the range are fully specified.

assert((0..<30 step 10) == (0,10,20)) // ranges and tuples can combined\nassert((1..=3) ++ 4 == (1,2,3,4))   // tuple and range ops become a tuple\nassert 1..=3 == (1,2,3)\nassert((1..=3)@[..] == 0b1110)      // convert range to integer with @[..]\n
"},{"location":"pyrope/04-variables/#string","title":"String","text":"

Strings are a basic type, but they can be typecasted to integers using the ASCII sequence. The string encoding assigns the lower bits to the first characters in the string, each character has 8 bits associated.

a = 'cad'              // c is 0x63, a is 0x61, and d is 0x64\nb = 0x64_61_63\nassert a == string(b)  // typecast number to string\nassert int(a) == b     // typecast string to number\nassert a@[..] == b     // typecast string to number\n

Like ranges, strings can also be seen as a tuple, and when tuple operations are performed they are converted to a tuple.

assert \"hello\" == ('h','e','l','l','o')\nassert \"h\" ++ \"ell\" == ('h','e','l','l') == \"hell\"\n
"},{"location":"pyrope/04-variables/#type-declarations","title":"Type declarations","text":"

Each variable has a type, either implicit or explicit, and as such, it can be used to declare a new type.

Pyrope does not have a type keyword. Instead it leverages the tuples for type creation. The difference is that a type should be an immutable variable, and therefore it is recommended to start with Uppercase.

var bund1 = (color:string, value:s33)\nx:bund1        = _      // OK, declare x of type bund1 with default values\nbund1.color    = \"red\"  // OK\nbund1.is_green = fun(self) { self.color == \"green\" }\nx.color        = \"blue\" // OK\n\nlet typ = (color:string, value:s33, is_green:fun(self) = _)\ny:typ        = _        // OK\ntyp.color    = \"red\"    // compile error\ntyp.is_green = fun(self) { self.color == \"green\" }\ny.color      = \"red\"    // OK\n\nlet bund3 = (color:string, value:s33)\nz:bund3        = _                 // OK\nbund3.color    = \"red\"             // compile error\nbund3.is_green = fun(self) { ... } // compile error\nz.color        = \"blue\"            // OK\n\nassert x equals typ  // same type structure\nassert z equals typ  // same type structure\nassert x equals z    // same type structure\n\nassert y is typ\nassert typ is typ\nassert z !is bund3 \nassert z !is typ\nassert z !is bund1\n

Adding a method to a tuple with tup.fn = fun... is the same as tup = tup ++ (fn=fun...).

"},{"location":"pyrope/04-variables/#type-checks","title":"Type checks","text":"

When a type is used in the left-hand-side of a declaration statement, the type is set for the whole existence of the variable. It is possible to also use type checks outside the variable declaration. Those are to check that the variable does comply with the type specified.

var a = true  // infer a is a boolean\n\nfoo = a:bool or false // checks that 'a' is a boolean\n
"},{"location":"pyrope/04-variables/#attributes","title":"Attributes","text":"

Attributes is the mechanism that the programmer specifies some special checks/functionality that the compiler should perform. Attributes are associates to variables either setting an attribute or checking the value. Some example of check is to mark statements compile time constant, or read the number of bits in an assertion, or placement hints, or even interact with the synthesis flow to read timing delays.

Pyrope does not specify the attributes, the compiler flow specifies them. Reading attributes should not affect a logical equivalence check. Writing attributes can have a side-effect because it can change bits use for wrap/saturate or change pins like reset/clock in registers. Additionally, attributes can affect assertions, so they can stop/abort the compilation.

The are three operations that can be done with attributes: set, check, read.

  • Set: when associated to a variable type in the left-hand-side of an assignment or directly accessed. If a variable definition, this binds the attribute with all the use cases of the variable. If the variable just changes attribute value, a direct assignment is possible E.g: foo::[max=300] = 4 or baz.[attr] = 10

  • Check: when associated to a type property in the right-hand-side of an assignment. The attribute is a comma separated list of boolean expression that must evaluate true only at this statement. E.g: var tmp = yy::[comptime, attr2>0] + xx

  • Read: a direct read of an attribute value is possible with variable.field.[attribute]

The attribute set, writes a value to the attribute. If no value is given a boolean true is set. The attribute checks are expressions that must evaluate true.

Since conditional code can depend on an attribute, which results in executing a different code sequence that can lead to the change of the attribute. This can create a iterative process. It is up to the compiler to handle this, but the most logical is to trigger a compile error if there is no fast convergence.

// attribute set\nvar foo:u32:[comptime=true] = xx   // enforce that foo is comptime true always\nvar bar::[comptime] = xx           // same as previous statement\nyyy = xx                           // yyy does not check comptime\nyyy::[comptime=true] = xx          // now, checks that 'yyy` is comptime\n\n// attribute check\nif bar == 3 {\n  tmp = bar::[comptime == true]    // check that this use of bar is comptime\n  tmp = bar::[comptime]            // same as previous statement\n  tmp = bar ; assert bar.[comptime] // same as previous statements\n}\n                                   // bar/foo may not be comptime\n\n// attribute read\nassert tmp.[bits] < 30 and !tmp.[comptime]\n

The attribute check is like a type check, both can be converted to assertions, but the syntax is cleaner.

Attribute CheckAssertion Equivalent Check
let x = y::[cond,bar==3] + 1\n\nread_state = fun(x) {\n  let f:u32:[comptime] = x // f is compile time or a error is generated\n  return f                 // f should be compile time constant\n}\n\nvar foo = read_state(zz) // foo will be compile time constant\n
let x = y + 1\ncassert y.[cond]\ncassert y.[bar]==3\n\nread_state = fun(x) {\n  let f = x\n  cassert f does u32\n  cassert f.[comptime]\n  f\n}\n\nvar foo = read_state(zz) // foo will be compile time constant\n

Pyrope allows to assign the attribute to a variable or a function call. Not to statements because it is confusing if applied to the condition or all the sub-statements.

if cond::[comptime] {    // cond is checked to be compile time constant\n  x::[comptime] = a +1   // x is set to be compile time constant\n}else{\n  x::[comptime] = b      // x is set to be compile time constant\n}\n\n\nif cond.[comptime] {  // checks if cond is compute at comptime\n  let v = cond\n  if cond {\n    puts \"cond is compile time and true\"\n  }\n}\n

The programmer could create custom attributes but then a LiveHD compiler pass to deal with the new attribute is needed to handle based on their specific semantic. To understand the potential Pyrope syntax, this is a hypothetical ::[poison] attribute that marks tuple.

let bad = (a=3,b::[poison]=4)\n\nlet b = bad.b\n\nassert b.[poison] and b==4\n

Attributes control fields like the default reset and clock signal. This allows to change the control inside procedures. Notice that this means that attributes are passed by reference. This is not a value copy, but a pass by reference. This is needed because when connecting things like a reset, we want to connect to the reset wire, not the current reset value.

let counter = proc(en, width) {\n  reg value:uint:[bits=width] = 0\n  value = value + 1\n  value\n}\n\nlet counter2::[clock_pin=clk1]=counter\nlet counter3::[reset_pin=rst2]=counter\n\nvar ctr2 =#[..] counter2(my_enable)\nvar ctr3 =#[..] counter3(my_enable)\n

In the long term, the goal is to have any synthesis directive that can affect the correctness of the result to be part of the design specification so that it can be checked during simulation/verification.

There are 3 main classes of a attributes that all the Pyrope compilers should always implement: Bitwidth, comptime, debug.

"},{"location":"pyrope/04-variables/#variable-attribute-list","title":"Variable attribute list","text":"

In the future, the compiler may implement some of the following attributes, as such, these attribute names are reserved and not allowed for custom attribute passes:

  • clock: indicate a signal/input is a clock wire
  • critical: synthesis time criticality
  • debug (sticky): variable use for debug only, not synthesis allowed
  • delay: synthesis time delay
  • defer: for reads, it means last value written. For assigns, it means defer write
  • deprecated: to generate special warnigns about usage
  • donttouch: do not touch/optimize away
  • file: to print the file where the variable was declared
  • inline, noinline: to indicate if a module is inlined
  • inp_delay, out_delay: synthesis optimizations hints
  • keep: same as donttouch but shorter
  • key: variable/entry key name
  • left_of, right_of, top_of, bottom_of, align_with: placement hints
  • let and var: is the variable declared as let and/or var
  • loc: line of code information
  • max_delay, min_delay: synthesis optimizations checked at simulation
  • max_load, max_fanout, max_cap: synthesis optimization hints
  • multicycle: number of cycles for optimizations checked at simulation
  • pipeline: pipeline related information
  • private: variable/field not visible to import/regref
  • rand and crand: simulation and compile time random number generation
  • reset: indicate a signal/input is a reset wire
  • size: Number of entries in tuple or array
  • typename: type name at variable declaration
  • valid, retry: for elastic pipelines
  • warn: is a boolean what when set to false disables compile warnings for associated variable
"},{"location":"pyrope/04-variables/#registers-and-pipestage-attribute-list","title":"Registers and pipestage attribute list","text":"

Registers have the following attributes:

  • async: false by default, selects an asynchronous reset
  • initial: reset value when reset is high
  • clock: connected to clock by default
  • reset: connected to reset by default
  • negreset: active low reset signal
  • posclk: true by default, selects a posedge or negnedge flop
  • retime: allow to retime across the register

Pipestage accept the same register attributes but also two more:

  • lat: latency for the pipestage
  • num: Number of unitsi used when the pipestage is not fully pipelined.
"},{"location":"pyrope/04-variables/#memories-attribute-list","title":"Memories attribute list","text":"

Memories are arrays with persistence like registers. As such, some of the attributes are similar to registers, but unlike registers they can have multiple clocks.

  • addr: Tuple of address ports for the memory.
  • bits: The number of bits for each memory entry
  • size: The number of entries. Total size in bits is \\(size x bits\\).
  • clock: Optional clock pin, clock by default. A tuple is possible to specify the clock for each address port.
  • din: Tuple for memory data in port. The read ports must be hardwired to 0.
  • enable: Tuple for each memory port. Write or read enable (read ports can have enable too).
  • fwd: Forwarding guaranteed (true/false). If fwd is false, there is no guarantee, it can have fwd or not.
  • latency: Number of cycles (0 or 1) when the read is performed
  • wensize: Write enable size allows to have a write mask. The default value is 1, a wensize of 2 means that there are 2 bits in the enable for each port. a wensize 2 with 2 ports has a total of 2+2+2 enable bits. Bit 0 of the enable controls the lower bits of the memory entry selected.
  • rdport: Indicates which of the ports are read and which are written ports.
  • posclk: Positive edge clock memory for all the memory clocks. The default is true but it can be set to false.
"},{"location":"pyrope/04-variables/#lambda-attribute-list","title":"Lambda attribute list","text":"

Lambda attributes allow Introspection which requires some attributes.

  • inputs: returns the input tuple from the lambda
  • outputs: returns the input tuple from the lambda
  • where: returns the lambda used in the where clause
"},{"location":"pyrope/04-variables/#bitwidth-attribute-list","title":"Bitwidth attribute list","text":"

To set constrains on integer, boolean, and range basic types, the compiler has a set of bitwidth related attributes:

  • max: the maximum value allowed
  • min: the minimum value allowed
  • ubits: Maximum number of bits to represent the unsigned value. The number must be positive or zero
  • sbits: Maximum number of bits, and the number can be negative
  • wrap: allows to drop bits that do not fit on the left-hand side. It performs sign extension if needed.
  • saturate keeps the maximum or minimum (negative integer) that fits on the left-hand side.

The integer type constructor allows to use a range to set max/min, but it is syntax sugar for direct attribute set.

opt1:uint(300) = 0\nopt2:int:[min=0,max=300] = 0  // same\nopt3::[min=0,max=300] = 0     // same\nopt4:int(0..=300) = 0         // same\n\nassert opt1.[ubits] == 0    // opt1 initialized to 0, so 0 bits\nopt1 = 200\nassert opt1.[ubits] == 8    // last assignment needs 9 sbits or 8 ubits\ntmp  = opt1::[ubits==8] + 1   // expression AND assert opt1.[ubits]==8 check\n

The wrap/saturate are attributes that only make sense for attribute set. There is not much to check/read besides checking that it was set before.

a:u32 = 100\nb:u10 = 0\nc:u5  = 0\nd:u5  = 0\nw:u5:[wrap] = 0     // attribute set for all the 'w' uses\n\nb = a               // OK, o precision lost\nc::[wrap] = a       // OK, same as c = a@[0..<5] (Since 100 is 0b1100100, c==4)\nc = a               // compile error, 100 overflows the maximum value of 'c'\nw = a               // OK, 'w' has a wrap set at declaration\n\nc::[saturate] = a   // OK, c == 31\nc = 31\nd = c + 1           // compile error, '32' overflows the maximum value of 'd'\n\nd::[wrap] = c + 1   // OK d == 0\nd::[saturate] = c+1 // OK, d==31\nd::[saturate] = c+1 // OK, d==31\n\nx::[saturate] boolean = c // compile error, saturate only allowed in integers\n
"},{"location":"pyrope/04-variables/#comptime-attribute","title":"comptime attribute","text":"

Pyrope borrows the comptime functionality from Zig. Any variable can set/check/read the compile time status. This means that the value must be constant at compile time or a compile error is generated.

let a::[comptime] = 1     // obviously comptime\nb::[comptime] = a + 2     // OK too\nlet c::[comptime] = rand  // compile error, 'c' is not compile time constant\n

To avoid too frequent comptime directives, Pyrope treats all the variables that start with uppercase as compile time constants.

var Xconst1 = 1      // obvious comptime\nvar Xvar2   = rand   // compile error, 'Xvar2' is not compile time constant\n
"},{"location":"pyrope/04-variables/#debug-attribute","title":"debug attribute","text":"

In software and more commonly in hardware, it is common to have extra statements and state to debug the code. These debug functionality can be more than plain assertions, they can also include code.

The debug attribute marks a mutable or immutable variable. At synthesis, all the statements that use a debug can be removed. debug variables can read from non debug variables, but non-debug variables can not read from debug. This guarantees that debug variables, or statements, do not have any side-effects beyond debug statements.

var a = (b::[debug]=2, c = 3) // a.b is a debug variable\nlet c::[debug] = 3\n

Assignments to debug variables also bypass protection access. This means that private variables in tuples can be accessed (read-only). Since assert marks all the results as debug, it allows to read any public/private variable/field.

x:(_priv=3, zz=4) = _\n\nlet tmp = x._priv         // compile error\nlet tmp::[debug] = x.priv // OK\n\nassert x._priv == 3    // OK, assert is a debug statement\n
"},{"location":"pyrope/04-variables/#register","title":"Register","text":"

Both mutable and immutable variables are created every cycle. To have persistence across cycles the reg type must be used.

reg counter:u32   = 10\nvar not_a_reg:u32 = 20\n

In reg, the right-hand side of the initialization (10 in the counterexample) is called only during reset. In non-register variables, the right-hand side is called every cycle. Most of the cases reg is mutable but it can be declared as immutable.

"},{"location":"pyrope/04-variables/#public-vs-private","title":"Public vs private","text":"

All variables are public by default. To declare a variable private within the tuple or file the private attribute must be set.

The private has different meaning depending on when it is applied:

  • When applied to a tuple entry ((field::[private] = 3)), it means that the entry can not be accessed outside the tuple.

  • When applied to a pipestage variable (var foo::[private] = 3), it means that the variable is not pipelined to the next type stage. Section pipestage has more details.

  • When is applied to a pyrope file upper scope variable (reg top_reg:[private] = 0), it means that an import command or register reference can not access it across files. Section typesystem has more details.

"},{"location":"pyrope/04-variables/#operators","title":"Operators","text":"

There are the typical basic operators found in most common languages except exponent operations. The reason is that those are very hardware intensive and a library code should be used instead.

All the operators work over signed integers.

"},{"location":"pyrope/04-variables/#unary-operators","title":"Unary operators","text":"
  • !a or not a logical negation
  • ~a bitwise negation
  • -a arithmetic negation
"},{"location":"pyrope/04-variables/#binary-integer-operators","title":"Binary integer operators","text":"
  • a + b addition
  • a - b substraction
  • a * b multiplication
  • a / b division
  • a & b bitwise and
  • a | b bitwise or
  • a ^ b bitwise xor
  • a ~& b bitwise nand
  • a ~| b bitwise nor
  • a ~^ b bitwise xnor
  • a >> b arithmetic right shift
  • a@[..] >> b logical right shift
  • a << b left shift

In the previous operations, a and b need to be integers. The exception is a << b where b can be a tuple. The << allows having multiple values provided by a tuple on the right-hand side or amount. This is useful to create one-hot encodings.

cassert 1<<(1,4,3) == 0b01_1010\n
"},{"location":"pyrope/04-variables/#binary-boolean-operators","title":"Binary boolean operators","text":"
  • a and b logical and
  • a or b logical or
  • a implies b logical implication
  • a !and b logical nand
  • a !or b logical nor
  • a !implies b logical not implication
"},{"location":"pyrope/04-variables/#tupleset-operators","title":"Tuple/Set operators","text":"
  • a in b is element a in tuple b
  • a !in b true when element a is not in tuple b
  • tuple(a) converts a to tuple, a can be a boolean, range, integer, string, or already a tuple

Most operations behave as expected when applied to signed unlimited precision integers.

The a in b checks if values of a are in b. Notice that both can be tuples. If a is a named tuple, the entries in b match by name, and then contents. If a is unnamed, it matches only contents by position.

cassert (1,2) in (0,1,3,2,4)\ncassert (1,2) in (a=0,b=1,c=3,2,e=4)\ncassert (a=2) !in (1,2,3)\ncassert (a=2) in (1,a=2,c=3)\ncassert (a=1,2) in (3,2,4,a=1)\ncassert (a=1,2) !in (1,2,4,a=4)\ncassert (a=1) !in (a=(1,2))\n

The a in b has to deal with undefined values (nil, 0sb?). The LHS with an undefined will be true if the RHS has the same named entry either defined or undefined.

cassert (x=nil,c=3) in (x=3,c=3)\ncassert (x=nil,c=3) in (x=nil,c=3,d=4)\ncassert (c=3)      !in (c=nil,d=4)\n
  • a ++ b concatenate two tuples. If field appears in both, concatenate field. The a field is defined in one tupe and undefined in the other, the undefined value is not concatenated.
cassert ((a=1,c=3) ++ (a=1,b=2,c=nil)) == (a=(1,1), c=3, b=2)\ncassert ((1,2) ++ (a=2,nil,5)) == (1,2,a=2,5)\ncassert ((x=1) ++ (a=2,nil,5)) == (x=1,a=2,nil,5)\n\ncassert ((x=1,b=2) ++ (x=0sb?,3)) == (x=1,b=2,3)\n
  • (,...b) in-place insert b. Behaves like a ++ b but it triggers a compile error if both have the same defined named field.
cassert (1,b=2,...(3,c=3),6) == (1,b=2,3,c=3,6)\ncassert (1,b=2,...(nil,c=3),0sb?,6) == (1,b=2,nil,c=3,0sb?,6)\n
"},{"location":"pyrope/04-variables/#type-operators","title":"Type operators","text":"
  • a has b checks if a tuple has the b field where b is a string or integer (position).
cassert((a=1,b=2) has \"a\")\n
  • a does b is the tuple structure of a a subset of b
  • a equals b same as (a does b) and (b does a)
  • a case b same as cassert a does b and for each b field with a defined value, the value matches a (nil, 0sb? are undefined values)
  • a is b is a nominal type check. Equivalent to a::[typename] == b::[typename]

Each type operator also has the negated (a !does b) == !(a does b), (a !equals b) == !(a equals b), a !case b == !(a case b)

The does performs just name matching when the LHS is a named tuple. It reverts to name and position matching when some of the LHS entries are unnamed.

cassert (a=1,b=3) does (b=100,a=333,e=40,5)\ncassert (a=1,3) does (a=100,300,b=333,e=40,5)\ncassert (a=1,3) !does (b=100,300,a=333,e=40,5)\n

A a case b is equivalent to cassert b does a and for each defined value in b there has to be the same value in a. This can be used in any expression but it is quite useful for match ... case patterns.

match (a=1,b=3) {\n  case (a=1) { cassert true }\n  else { cassert false }\n}\n\nmatch let t=(a=1,b=3); t {\n  case (a=1  ,c=4) { cassert false }\n  case (b=nil,a=1) { cassert t.b==3 and t.a==1 }\n  else { cassert false }\n}\n

An x = a case b can be translated to:

cassert b does a\nx = b in a\n
"},{"location":"pyrope/04-variables/#reduce-and-bit-selection-operators","title":"Reduce and bit selection operators","text":"

The reduce operators and bit selection share a common syntax variable@op[sel] where:

  • variable is a tuple where all the tuple fields and subfields must have a explicit type size unless the tuple has 1 entry.

  • op is the operation to perform

    • |: or-reduce.
    • &: and-reduce.
    • ^: xor-reduce or parity check.
    • +: pop-count.
    • sext: Sign extends selected bits.
    • zext: Zero sign extends selected bits (default option)
  • sel can be a close-range like 1..<=4 or (1,4,6) or an open range like 3... Internally, the open range is converted to a close-range based on the variable size.

The or/and/xor reduce have a single bit signed result (not boolean). This means that the result can be 0 (0sb0) or -1 (0sb1). pop-count and zext have always positive results. sext is a sign-extended, so it can be positive or negative.

If no operator is provided, a zext is used by default. The bit selection without operator can also be used on the left-hand side to update a set of bits.

The or-reduce and and-reduce are always size insensitive. This means that to perform the reduction it is not needed to know the number of bits. It could pick more or fewer bits and the result is the same. E.g: 0sb111 or 0sb111111 have the same and/or reduce. This is the reason why both can work with open and close ranges.

This is not the case for the xor-reduce and pop-count. These two operations are size insensitive for positive numbers but sensitive for negative numbers. E.g: pop-count of 0sb111 is different than 0sb111111. When the variable is negative a close range must be used. Alternatively, a zext must be used to select bits accordingly. E.g: variable@[0..=3]@+[..] does a zext and the positive result is passed to the pop-count. The compiler could infer the size and compute, but it is considered non-intuitive for programmers.

x = 0b1_0110   // positive\ny = 0s1_0110   // negative\nassert x@[0,2] == 0b10\nassert y@[100,200]       == 0b11   and x@[100,200]       == 0\nassert y@sext[0,100,200] == 0sb110 and x@sext[1,100,200] == 0b001\nassert x@|[..] == -1\nassert x@&[0,1] == 0\nassert x@+[0..=5] == x@+[0..<100] == 3\nassert y@+[0..=5]  // compile error, 'y' can be negative\nassert y@[..]@+[..] == 3\nassert y@[0..=5]@+[..] == 3\nassert y@[0..=6]@+[..] == 4\n\nvar z     = 0b0110\nz@[0] = 1\nassert z == 0b0111\nz@[0] = 0b11 // compile error, '0b11` overflows the maximum allowed value of `z@[0]`\n

Note

It is important to remember that in Pyrope all the operations use signed numbers. This means that an and-reduce over any positive number is always going to be zero because the most significant bit is zero, E.g: 0xFF@&[..] == 0. In some cases, a close-range will be needed if the intention is to ignore the sign. E.g: 0xFF@&[0..<8] == -1.

The bit selection operator only works with ranges, boolean, and integers. It does not work with tuples or strings. For converting in these object a union: must be used.

Another important characteristic of the bit selection is that the order of the bits on the selection does not affect the result. Internally, it is a bitmask that has no order. For the zext and sext, the same order as the input variable is respected. This means that var@[1,2] == var@[2,1]. As a result, the bit selection can not be used to transpose bits. A tuple must be used for such an operation.

var v = 0b10\nassert v@[0,1] == v@[1,2] == v@[..] == v@[0..=1] == v@[..=1] == 0b10\n\nvar trans = 0\n\ntrans@[0] = v@[1]\ntrans@[1] = v@[0]\nassert trans == 0b01\n
"},{"location":"pyrope/04-variables/#precedence","title":"Precedence","text":"

Pyrope has very shallow precedence, unlike most other languages the programmer should explicitly indicate the precedence. The exception is for widely expected precedence.

  • Unary operators (not,!,~,?) bind stronger than binary operators (+,++,-,*...)
  • Comparators can be chained (a<=c<=d) same as (a<=c and c<=d)
  • mult/div precedence is only against +,- operators.
  • Parenthesis can be avoided when a expression left-to-right has the same result as right-to-left.
Priority Category Main operators in category 1 unary not ! ~ ? 2 mult/div *, / 3 other binary ..,^, &, -,+, ++, <<, >>, in, does, has, case, equals, to 4 comparators <, <=, ==, !=, >=, > 5 logical and, or, implies
assert((x or !y) == (x or (!y)) == (x or not y))\nassert((3*5+5) == ((3*5) + 5) == 3*5 + 5)\n\na = x1 or x2==x3 // same as b = x1 or (x2==x3)\nb = 3 & 4 * 4    // compile error: use parenthesis for explicit precedence\nc = 3\n  & 4 * 4\n  & 5 + 3        // compile error: use parenthesis for explicit precedence\nc2 = 3\n  & (4 * 4)\n  & (5 + 3)      // OK\n\nd = 3 + 3 - 5    // OK, same result right-left\n\ne = 1\n  | 5\n  & 6           // compile error: use parenthesis for explicit precedence\n\nf = (1 & 4)\n  | (1 + 5)\n  | 1\n\ng = 1 + 3\n  * 1 + 2\n  + 5           // OK, but not nice\n\ng1= 1 + (3 * 1)\n  + 2\n  + 5           // OK\n\ng2= (1 + 3)\n  * (1 + 2)\n  + 5           // OK\n\nh = x or y and z// compile error: use parenthesis for explicit precedence\n\ni = a == 3 <= b == d\nassert i == (a==3 and 3<=b and b == d)\n

Comparators can be chained, but only when they follow the same type.

assert a <= b <= c  // same as a<=b and b<=c\nassert a == b <= c  // compile error, chained only allowed with same comparator\n
"},{"location":"pyrope/04-variables/#optional","title":"Optional","text":"

The ? is used by several languages to handle optional or null pointer references. In non-hardware languages, ? is used to check if there is valid data or a null pointer. This is the same as checking the ::[valid] attribute with a more friendly syntax.

Pyrope does not have null pointers or memory associated management. Pyrope uses ? to handle ::[valid] data. Instead, the data is left to behave without the optional, but there is a new \"valid\" field associated with each tuple entry. Notice that it is not for each tuple level but each tuple entry.

There are 4 explicitly interact with valids:

  • tup.f1? reads the valid for field f1 from tuple tup

  • tup?.f1.f2 returns 0bs0 if tuple fields f1 or f2 are invalid

  • tup.f1? = cond explicitly sets the field f1 valid to cond

  • a = b op c variable a will be valid if b AND c are valid

The optional or valid attached to each variable and tuple field is implicitly computed as follows:

  • Non-register variables are initialized with valid unless _ is used in the initialization which explicitly clears the valid attribute.

  • Registers set the valid after reset, but if the reset clears the valid, there is not guaranteed on attribute [valid] during reset. If the register does not have a reset signal, the register is always valid unless explicitly cleared.

  • Left-hand side variables valids are set to the and-gate of all the variable valids used in the expression

  • memory/arrays do not tend to have reset signals. As such they are always valid unless the memory has explicit reset code. In which case the valid behaves like in flops.

  • Writing to a register updates the register valid based on the din valid, or when the attribute [valid] is explicitly managed.

  • conditionals (if) update valids independently for each path

  • A tuple field has the valid set to false if any of the tuple fields is invalid

  • The valid computation can be overwritten with the [valid] attribute. This is possible even during reset.

Observation

The variable valid calculation is similar to the Elastic 'output_written' from Liam but it is not an elastic update because it does not consider the abort or retry.

The previous rules will clear a valid only if an expression has no valid, but the only way to have a non-valid is if the inputs to the lambda are invalid or if the valid is explicitly clear. The rules are designed to have no overhead when valid are not used. The compiler should detect that the valid is true all the time, and the associated logic is removed.

Most statements evaluate independent of the valid expression. Expressions will evaluate the same if any of the inputs is valid or invalid. The valid attribute is computed in parallel to avoid being in the critical path. The exception are the verification statements like asserts and printing statatements like puts. These statements are gated or not performed if any of the inputs is invalid. To ignore the valid check, the always command can be appended before and as a result the statments will evaluate every cycle independent of the reset/valid status.

var v1:u32 = _                 // v1 is zero every cycle AND not valid\nassert v1.[valid] == false\nvar v2:u32 = 0                 // v2 is zero every cycle AND     valid\nassert v2.[valid] == true\n\ncassert v1?\ncassert not v2?\n\nassert v1 == 0 and v2 == 3     // data still same as usual\n\nv1 = 0sb?                      // OK, poison data\nv2 = 0sb?                      // OK, poison data, and update valid\nassert v2?                     // valid even though data is not\n\nassert v1 != 0                 // usual verilog x logic\nassert v2 != 0                 // usual verilog x logic\n\nlet res1 = v1 + 0              // valid with just unknown 0sb? data\nlet res2 = v2 + 0              // valid with just unknown 0sb? data\n\nassert res1?\nassert res2?\n\nreg counter:u32 = 0\n\nalways assert counter.reset implies !counter?\n

valid can be overwritten by the setter method:

let custom = (\n  ,data:i16 = _\n  ,setter = proc(ref self, v) {\n    self.data = v\n    self.[valid] = v != 33\n  }\n)\n\nvar x:custom = _\n\ncassert x?\nx.data = 33\ncassert not x?\nx.data = 100\ncassert x?\n

The contents of the tuple field do not affect the field valid bit. It is data-independent. Tuples also can have an optional type, which behaves like adding optional to each of the tuple fields.

let complex = (\n  ,reg v1:string = \"foo\"\n  ,v2:string = _\n\n  ,setter = proc(ref self,v) {\n     self.v1 = v\n     self.v2 = v\n  }\n)\n\nvar x1:complex = _\nvar x2:complex:[valid=false] = 0  // toggle valid, and set zero\nvar x3:complex = 0\nx3.[valid] = false                // set invalid\n\nassert x1.v1 == \"\" and x1.v2 == \"\"\nassert not x2? and not x2.v1? and not v2.v2?\nassert x2.v1 == \"\" and x2.v2 == \"\"\n\nassert x2?.v1 == \"\" and x2?.v1 != \"\"  // any comparison is false\n\n// When x2? is false, any x2?.foo returns 0sb? with the associated x rules\n\nx2.v2 = \"hello\" // direct access still OK\n\nassert not x2? and x2.v1 == \"\" and x2.v2 == \"hello\"\n\nx2 = \"world\"\n\nassert x2? and x2?.v1 == \"world\" and x2.v1 == \"world\"\n
"},{"location":"pyrope/04-variables/#variable-initialization","title":"Variable initialization","text":"

Variable initialization indicates the default value set every cycle and the optional (::[valid] attribute).

The let and var statements require an initialization value for each cycle. Pyrope only has undefined values unless explicitly indicated. A variable has an undefined value if and only if the value is set to nil or all the bits are unknown (0sb?). Undefined variables always have invalid optional (.[valid]==false), and defined can have valid or invalid optional.

On any assignment (v = _) where the rhs is a single underscore _, the variable optional is set to false, and it is assigned the default value:

  • 0 for integer
  • false for boolean
  • \"\" for string
  • nil otherwise
var a:int = _\ncassert a==0 and a.[valid] == false and not a?\n\nvar b:int = 0\ncassert b==0 and b.[valid] and b?\nb = nil\ncassert b==nil and b.[valid] == false and not b?\n\nvar c:fun(a1) = _\ncassert c == nil and c.[valid]==false\nc = fun(a1) { cassert true }\ncassert c!= nil and c.[valid]\n\nvar d:[] = _               // empty tuple\ncassert d != nil and d.[valid]\ncassert d[0] == nil and !d[0].[valid]\n\nvar e:int = nil\ncassert e==nil and !e.[valid] and not e?\ne = 0\ncassert e==0 and e.[valid] and e?\n

The same rules apply when a tuple or a type is declared.

let a = \"foo\"\n\nvar at1 = (\n  ,a:string \n)\ncassert at1[0] == \"foo\"\ncassert at1 !has \"a\"    // at1.a undefined\n\nvar at2 = (\n  ,a:string = _\n)\ncassert at2.a == \"\"  and at2.a.[valid]==false\nat2.a = \"torrellas\"\ncassert at2.a == \"torrellas\" and at2[0] == \"torrellas\"\n\nvar at3:at2 = _\ncassert at3.a == \"\"  and at3.a.[valid]==false\n\nvar at4:at2 = (a=\"josep\")\ncassert at4.a == \"josep\"  and at4.a.[valid] and at4.[valid]\n

Conditional path affect variable initialization and values. If all the conditional passes assign a value, the valid will be true. If only one path assigns a value, the valid will be set only on that path, but the data may always have the path.

var x=_\nvar y=2\nvar z=_\nif rand {\n  x = 3\n  y = 4\n  z = 5\n}else{\n  z = 6\n}\nassert x==3  // Simplified due to the _ initialization\nassert rand      implies x.[valid]\nassert x.[valid] implies rand\n\nassert y.[valid]\nassert  rand implies y == 4\nassert !rand implies y == 2\n\nassert z.[valid]\nassert  rand implies z == 5\nassert !rand implies z == 6\n
"},{"location":"pyrope/05-assert/","title":"Verification","text":"

Verification covers the language constructs and special support to ease design verification.

"},{"location":"pyrope/05-assert/#assertions","title":"Assertions","text":"

Assertions are considered debug statements. This means that they can not have side effects on non-debug statements.

Pyrope supports a syntax close to Verilog for assertions. The language is designed to have 3 levels of assertion checking: compilation time, simulation runtime, and formal verification time.

There are 5 main verification statements:

  • assert and cassert are used to specify conditions that should hold true. cassert is required to hold true at compile time and assert can be checked either at compile or runtime if too slow to check. If the condition doesn't hold, an error is raised.

  • optimize is exactly like assert, but it also allows the tool to simplify code based on the given conditions. This can lead to more efficient code generation. While unproven assert can be enabled/disabled during simulation, optimize can not be disabled because it can lead to incorrect simulation state.

  • requires is statement that can be placed in lambdas. The clause specifies pre conditions to be true when the lambda is called. requires allows for code optimizations like optimize statement.

  • ensures is a statement similar to requires but the clause specifies a post condition. ensures allows code optimizations like optimize statement.

Hardware setups always have an extensive CI/verification setup. This means that run-time assertion failures are OK, better compile time to reduce design time, but OK at simulation time. This means that in things like type check, if it may be OK but not possible to prove, the compiler can decide to insert an assert instead of forcing a code structure change. To enforce that an assertion is checked only at compile time a cassert must be used. assert, requires, ensures can be checked at runtime if not possible to check at compile time.

a = 3\nassert a == 3          // checked at runtime (or compile time)\ncassert a == 3         // checked at compile time\n\noptimize b > 3         // may optimize and perform a runtime check\n\nlet max_not_zero = fun(a,b) -> (res)\n  requires a>0\n  requires b>0\n  ensures res==a or res==b {\n\n  res = if a>b {a} else {b}\n}\n

A whole statement is conditionally executed using the when/unless gate expression. This is useful to gate verification statements (assert, optimize) that can have spurious error messages under some conditions.

a = 0\nif cond {\n  a = 3\n}\nassert cond implies a == 3, \"the branch was taken, so it must be 3??\"\nassert a == 3, \"the same error\" when   cond\nassert a == 0, \"the same error\" unless cond\n

The recommendation is to write as many assert and optimize as possible. If something can not happen, writing the optimize has the advantage of allowing the synthesis tool to generate more efficient code.

The optimize will allow code optimizations, the cassert should also result in code optimizations. The reason why assert does not trigger optimizations is because they can be enabled/disabled at simulation time.

In a way, most type checks have equivalent cassert checks.

"},{"location":"pyrope/05-assert/#lec","title":"LEC","text":"

The lec command is a formal verification step that checks that all the arguments are logically equivalent. lec only works for combinational logic, so does not need to worry about state or reset signals. The first argument is the gold model, the rest are implementation. This matters because the gold model unknown output bit checks against any value for the equivalent implementation bit.

Note

The recommendation is to use optimize and assert frequently, but clearly to check preconditions and postconditions of methods. The 1949 Turing quote of how to write assertions and programs is still valid \"the programmer should make a number of definite assertions which can be checked individually, and from which the correctness of the whole program easily follows.\"

let fun1 = fun(a,b) { a | b}\nlet fun2 = fun(a,b) { ~(~a | ~b) }\nlec fun1, fun2\n

In addition, there is the lec_valid command. It is similar to lec but it checks the optional or valid (::[valid]) from the output. It can take several cycles to show the same result.

let mul2 = proc(a,b) -> (reg out) {\n  reg pipe1 = _\n\n  out = pipe1\n\n  pipe1 = a*b\n}\n\nlet mul0 = fun(a,b)->(out) { out = a*b }\n\nlec_valid mul0, mult2\n
"},{"location":"pyrope/05-assert/#coverage","title":"Coverage","text":"

A bit connected with the assertion is coverage. The goal of an assertion is to be true all the time. The goal of a coverage point is to be true at least once during testing.

There are two directives cover and covercase. The names are similar to the System Verilog coverpoint and covergroup but the meaning is not the same.

  • cover cond [, message] the boolean expression cond must evaluate true sometime during the verification or the tool can prove that it is true at compile time.

  • covercase grp, cond [,message] is very similar to cover but it has a grp group. There can be one or more covers for a given group. The extra check is that one of the cond in the cover case must be true each time.

// coverage case NUM group states that random should be odd or even\ncovecase NUM,   random&1 , \"odd number\"\ncovecase NUM, !(random&1), \"even number\"\n\ncovercase COND1, reset, \"in reset\"\ncovercase COND1, val>3, \"bigger than 3\"\n\nassert((!reset and val>3) or reset)  // less checks than COND1\n\ncover a==3, \"at least a is 3 once in a while\"\n

The covercase is similar to writing the assertions, but it checks that all the conditions happen through time or a low coverage is reported. In the COND1 case, the assertion does not check that sometimes reset is set, and others the value is bigger than 3. The assertion will succeed if reset is always set, but the covercase will fail because the \"bigger than 3\" case will not be tested.

The cover allows to not be true a given cycle. To allow the same in a covercase, the designer can add coverase GRP, true. This is a true always cover point for the indicated cover group.

"},{"location":"pyrope/05-assert/#reset-optional-and-verification","title":"Reset, optional, and verification","text":"

In hardware is common to have an undefined state during the reset period. To avoid unnecessary assertion failures, if any of the inputs depends on a register directly or indirectly, the assertion is not checked when the reset is high for the given registers. In Pyrope, the registers and memory contents outputs are \"invalid\" (::[valid] attribute). assert and optimize will not check when any of the signals are invalid. This is useful to avoid unnecessary assert checks during reset or when the lambda is called with invalid data.

Adding the always modifier before the assert/coverage keywords guarantees that the check is performed every cycle independent of the valid attribute.

To provide assert/optimize during reset, Pyrope provides a always assert, always cassert, always optimize, always covercase, and always cover.

reg memory:[]u33 = (1,2,3) // may take cycles to load this contents\n\nassert memory[0] == 1 // not checked during reset\n\nalways assert memory[1] == 2 // may fail during reset\nalways assert memory[1] == 2 unless memory.reset  // should not fail\n
"},{"location":"pyrope/05-assert/#random","title":"Random","text":"

Random number generation are quite useful for verification. Pyrope provides easy interfaces to generate \"compile time\" (::[crand]) and \"simulation time\" random number (::[rand]) generation.

let x:u8 = _\n\nfor i in 1..<100 {\n  cassert 0 <= x.[crand]  <= 255\n}\n\nlet get_rand_0_2556 = fun(a:u8) {\n  a.[rand]\n}\n

Both rand and crand look at the set type max/min value and create a randon value between them. rand picks randomly in boolean and enumerate types, but it triggers a compile error for string, range, and lambda types.

When applied to a tuple, it randomly picks an entry from the tuple.

let a = (1,2,3,b=4)\nlet x = a.[rand]\n\ncassert x==1 or x==2 or x==3 or x==4\ncassert x.b==4 when x==4\n

The simulation random number is considered a ::[debug] statement, this means that it can not have an impact on synthesis or a compile error is generated.

"},{"location":"pyrope/05-assert/#test","title":"Test","text":"

Pyrope has the test [message [,args]+] ( [stmts+] }.

Many parallel testsSingle large test
let add = fun(a,b) { a+b }\n\nfor a in 0..=20 {\n  for b in 0..=20 {\n    test \"checking add({},{})\", a,b {\n       cassert a+b == add(a,b)\n    }\n  }\n}\n
let add = fun(a,b) { a+b }\n\ntest \"checking add\" {\n  for a in 0..=20 {\n    for b in 0..=20 {\n       cassert a+b == add(a,b)\n    }\n  }\n}\n

The test code block also accepts the keyword step that advances one clock cycle, and the test continues from that given point. This is useful for when a lambda is instantiated and we want to check/update the inputs/outputs.

let counter = proc(update)->(value) {\n  reg count:u8:[wrap] = 0\n\n  value = count\n\n  count += 1 when update\n}\n\ntest \"counter through several cycles\" {\n\n  var inp = true\n  let x = counter(inp.[defer])  // inp contents at the end of each cycle\n\n  assert x == 0 // x.value == 0\n  assert inp == true\n\n  step\n\n  assert x == 1\n  inp = false\n\n  step\n\n  assert x == 1\n  assert inp == false\n  inp = true\n\n  assert inp == true\n  assert x == 1\n\n  step\n\n  assert inp == true\n  assert x == 2\n}\n

During test simulation, all the assertions are checked but the test does not stop with a failure until the end. Sometimes it is useful to write tests to check that assertions fail. Assertion failures will be printed but the test will continue and fail only if the assert.[failed] is true. The test code block also accepts to read and/or clear failed attribute.

test \"assert should fail\" {\n\n let n = assert.[failed]\n assert n == false\n\n assert false // FAILS\n\n assert assert.[false]\n\n assert.[failed] = false // disable test failures done when it finishes\n}\n
"},{"location":"pyrope/05-assert/#monitor","title":"Monitor","text":"

TODO

"},{"location":"pyrope/05b-statements/","title":"Statements","text":""},{"location":"pyrope/05b-statements/#conditional-ifelifelse","title":"Conditional (if/elif/else)","text":"

Pyrope uses a typical if, elif, else sequence found in most languages. Before the if starts, there is an optional keyword unique that enforces that a single condition is true in the if/elif chain. This is useful for synthesis which allows a parallel mux. The unique is a cleaner way to write an optimize statement.

The if sequence can be used in expressions too.

a = unique if x1 == 1 {\n    300\n  }elif x2 == 2 {\n    400\n  }else{\n    500\n  }\n\nvar x = _\nif a { x = 3 } else { x = 4 }\n

The equivalent code with an explicit optimize, but unlike the optimize, the unique will guarantee to generate the hotmux statement.

optimize !(x1==1 and x2==2)\na = if x1 == 1 {\n    300\n  }elif x2 == 2 {\n    400\n  }else{\n    500\n  }\n

Like several modern programming languages, there can be a list of expressions in the evaluation condition. If variables are declared, they are restricted to the remaining if/else statement blocks.

var tmp = x+1\n\nif var x1=x+1; x1 == tmp {\n   puts \"x1:{} is the same as tmp:{}\", x1, tmp\n}elif var x2=x+2; x2 == tmp {\n   puts \"x1:{} != x2:{} == tmp:{}\", x1, x2, tmp\n}\n
"},{"location":"pyrope/05b-statements/#unique-parallel-conditional-match","title":"Unique parallel conditional (match)","text":"

The match statement is similar to a chain of unique if/elif, like the unique if/elif sequence, one of the options in the match must be true. The difference is that one of the entries must be truth or an error is generated. This makes the match statement a replacement for the common \"unique parallel case\" Verilog directive. The match statement behaves like also having an optimize statement which allows for more efficient code generation than a sequence of if/else.

In addition to functionality, the syntax is different to avoid redundancy. match joins the match expression with the beginning of the matching entry must form a valid expression.

x = 1\nmatch x {\n  == 1            { puts \"always true\" }\n  in 2,3          { puts \"never\"       }\n}\n// It is equivalent to:\nunique if x == 1  { puts \"always true\" }\nelif x in (2,3)   { puts \"never\"       }\nelse              { assert false       }\n

Like the if, it can also be used as an expression.

var hot = match x {\n    == 0sb001 { a }\n    == 0sb010 { b }\n    == 0sb100 { c }\n  }\n\n// Equivalent\noptimize (x==0sb001 or x==0sb010 or x==0sb100)\nvar hot2 = __hotmux(x, a, b, c)\n\nassert hot==hot2\n

Like the if statement, a sequence of statements and declarations are possible in the match statement.

match let one=1 ; one ++ (2) {\n  == (1,2) { puts \"one:{}\", one }      // should always hit\n}\n

Since the == is the most common condition in the match statement, it can be omitted.

for x in 1..=5 {\n  let v1 = match x {\n    3 { \"three\" }\n    4 { \"four\" }\n    else { \"neither\"}\n  }\n\n  let v2 = match x {\n    == 3 { \"three\" }\n    == 4 { \"four\" }\n    else { \"neither\"}\n  }\n  cassert v1 == v2\n}\n
"},{"location":"pyrope/05b-statements/#gate-statements-whenunless","title":"Gate statements (when/unless)","text":"

A simple statement like assignments, variable declarations, and function calls and returns can be gated or not executed with a when or unless statement. This is similar to an if statement, but the difference is that the statement is in the current scope, not creating a new scope. This allows cleaner more compact syntax.

var a = 3\na += 1 when false             // never executes \nassert a == 3\nassert a == 1000 when a > 10  // assert never executed either\n\nreg my = 3 when some_condition  // no register declared otherwise\n\nreturn \"fail\" unless success_condition\n

Complex assignments like a |> b(1) |> c can not be gated because it is not clear if the gated applies to the last call or the whole pipeline sequence. Similarly, gating ifs/match statements do not make much sense. As a result, when/unless can only be applied to assignments, function calls, and code block control statements (return, break, continue).

"},{"location":"pyrope/05b-statements/#code-block","title":"Code block","text":"

A code block is a sequence of statements delimited by { and }. The functionality is the same as in other languages. Variables declared within a code block are not visible outside the code block. In other words, code block variables have scope from definition until the end of the code block.

Code blocks are different from lambdas. A lambda consists of a code block but it has several differences. In lambdas, (1) variables defined in upper scopes are accessed inside as immutable copies only when captured by scope; (2) inputs and outputs could be constrained, and (3) the return statement finishes a lambda not a code block.

The main features of code blocks:

  • Code blocks define a new scope. New variable declarations inside are not visible outside it.

  • Code blocks do not allow variable declaration shadowing.

  • Expressions can have multiple code blocks but they are not allowed to have side-effects for variables outside the code block. The evaluation order provides more details on expressions evaluation order.

  • When used in an expression or lambda, the last statement in the lambda code block can be an expression. It is not needed to add the return keyword in this case.

{\n  var x=1\n  var z=_\n  {\n    z = 10\n    var x=_           // compiler error, 'x' is a shawdow variable\n  }\n  assert z == 10 \n}\nlet zz = x            // compile error, `x` is out of scope\n\nvar yy = {let x=3 ; 33/3} + 1\nassert yy == 12\nlet xx = {yy=1 ; 33}  // compile error, 'yy' has side effects\n\nif {let a=1+yy; 13<a} {\n  // a is not visible in this scope\n  some_code()\n}\n\nlet doit = fun(f,a) {\n  let x = f(a)\n  assert x == 7\n  return 3\n}\n\nlet z3 = doit(fun(a) { \n  assert a!=0\n  return 7             // exist the current lambda\n  100                  // never reached statement\n}, 33)\ncassert z3 == 3\n
"},{"location":"pyrope/05b-statements/#loop-for","title":"Loop (for)","text":"

The for iterates over the first-level elements in a tuple or the values in a range. In all the cases, the number of loop iterations must be known at compile time. The loop exit condition can not be run-time data-dependent.

The loop can have an early exit when calling break and skip of the current iteration with the continue keyword.

for i in 0..<100 {\n some_code(i)\n}\n\nvar bund = (1,2,3,4)\nfor (index,i) in bund.enumerate() {\n  assert bund[j] == i\n}\n
let b = (a=1,b=3,c=5,7,11)\nassert b.keys() == ('a', 'b', 'c', '', '')\nassert b.enumerate() == ((0,1), (1,3), (2,5), (3,7), (4,11))\nlet xx= zip(b.keys(), b.enumerate()) \ncassert xx == (('a',0,a=1), ('b',1,b=3), ('c',2,c=5), ('',3,7), ('',4,11))\n\nfor (key,index,i) in zip(keys(b),b.enumerate()) {\n  assert i==1  implies (index==0 and key == 'a')\n  assert i==3  implies (index==1 and key == 'b')\n  assert i==5  implies (index==2 and key == 'c')\n  assert i==7  implies (index==3 and key == '' )\n  assert i==11 implies (index==4 and key == '' )\n}\n\nlet c = ((1,a=3), b=4, c=(x=1,y=6))\nassert c.enumerate() == ((0,(1,a=3)), (1,b=4), (2,c=(x=1,y=6)))\n

The for can also be used in an expression that allows building comprehensions to initialize arrays. Pyrope uses a comprehension similar to Julia or Python.

var c = for i in 1..<5 { var xx = i }  // compile error, no expression\nvar d = i for i in 0..<5 \nvar e = i for i in 0..<5 if i\nassert (0,1,2,3,4) == d\nassert e == (1,2,3,4)\n

The iterating element is copied by value, if the intention is to iterate over a vector or array to modify the contents, a ref must be used. Only the element is mutable. When a ref is used, it must be a variable reference, not a function call return (value). The mutable for can not be used in comprehensions.

b = (1,2,3,4,5)\n\nfor x in ref b {\n  x += 1\n}\nassert b == (2,3,4,5,6)\n
"},{"location":"pyrope/05b-statements/#code-block-control","title":"Code block control","text":"

Code block control statements allow changing the control flow for lambdas and loop statements (for, loop, and while). return can have a value.

  • return exits or terminates the current lambda. The current output variables are provided as the lambda output. If a tuple is provided, the tuple is the returned value, the output variables are not used.

  • break terminates the closest inner loop (for/while/loop). If none is found, a compile error is generated.

  • continue looks for the closest inner loop (for/while/loop) code block. The continue will perform the next loop iteration. If no inner loop is found, a compile error is generated.

var total:[] = _\nfor a in 1..=10 {\n  continue when a == 2\n  total ++= a\n  break when a == 3    // exit for scope\n}\nassert total == (1,3)\n\nif true {\n  code(x)\n  continue             // compile error, no upper loop scope\n}\n\na = 3\nvar total2:[] = _\nwhile a>0 {\n  total2 ++= a\n  break when a == 2    // exit if scope\n  a = a - 1\n  continue\n  assert false         // never executed\n}\nassert total2 == (3,2)\n\ntotal = i+10 for i in 1..=9 if i<3\nassert total == (11, 12)\n
"},{"location":"pyrope/05b-statements/#whileloop","title":"while/loop","text":"

while cond { [stmts]+ } is a typical while loop found in most programming languages. The only difference is that like with loops, the while must be fully unrolled at compilation time. The loop { [stmts]+ } is equivalent to a while true { [stmts]+ }.

Like if/match, the while condition can have a sequence of statements with variable declarations visible only inside the while statements.

// a do while contruct does not exist, but a loop is quite clean/close\n\nvar a = 0\nloop {\n  puts \"a:{}\",a\n\n  a += 1\n\n  break unless a < 10 \n} // do{ ... }while(a<10)\n
"},{"location":"pyrope/05b-statements/#defer","title":"defer","text":"

A defer attribute can be applied to variables. When used to read a variable, it returns the last values written to the variable the end of the current cycle. This is needed if we need to have any loop in connecting blocks. The defer applied to a write, delays the write update to the end of the cycle. The delayed writes happen before the delayed reads. This is also for delaying assertion checks to the end of the cycle like post condition checks.

var c = 10\nassert b.[defer] == 33    // behaves like a postcondition\nb = c.[defer]\nassert b == 33\nc += 20\nc += 3\n

To connect the ring function calls in a loop.

f1 = ring(a, f4.[defer])\nf2 = ring(b, f1)\nf3 = ring(c, f2)\nf4 = ring(d, f3)\n

If the intention is to read the result after being a flop, there is no need to use the defer, a normal register access could do it. If the read variables are registers, the flop#[0] is not the same as defer. The flop#[0] reads the value before any update, the defer read, gets values after updates.

reg counter:u32 = _\n\nlet counter_m1 = counter#[1]  // compile error, #[1] only allowed for debug\nlet counter_0  = counter#[0]  // current cycle \nlet counter_1  = counter#[-1] // last cycle\nlet counter_2  = counter#[-2] // last last cycle cycle \n\nvar deferred = counter.[defer]\n\nif counter < 100 {\n  counter += 1\n}else{\n  counter = 0\n}\n\nif counter == 10 {\n  assert deferred   == 10\n  assert counter_0  ==  9\n  assert counter_1  ==  8\n  assert counter_2  ==  7\n}\n

The defer can also be applied to write/updates to the end of the cycle but uses/reads the current value. In a way, the assignment is delayed to the end of the current cycle. If there are many defers to the same variable, they are ordered in program order.

var a = 1\nassert a == 1 and a.[defer] == 200\n\na::[defer] = 100\nassert a == 1 and a.[defer] == 200\n\na::[defer] = 200\nassert a == 1 and a.[defer] == 200\n

If there are defer reads and defer assignments, the defered writes are performed before the defered reads.

var a = 1\nvar x = 100\nx::[defer] = a\na = 200\n\ncassert x == 100\nassert x.[defer] == 1\n
"},{"location":"pyrope/05b-statements/#testing-test","title":"Testing (test)","text":"

The test statement requires a text identifier to notify when the test fails. The test is similar to a puts statement followed by a scope (test <str> [,args] { stmts+ }). The statements inside the code block can not have any effect outside.

test \"my test {}\", 1 {\n  assert true\n}\n

Each test can run in parallel, to increase the throughput, putting the randomization outside the test statement increases the number of tests:

Parallel testsSingle test
let add = fun(a,b) { a+b }\n\nfor i in 0..<10 { // 10 tests\n  let a = (-30..<100).rand\n  let b = (-30..<100).rand\n\n  test \"test {}+{}\",a,b {\n    assert add(a,b) == (a+b)\n  }\n}\n
let add = fun(a,b) { a+b }\n\ntest \"test 10 additions\" {\n  for i in 0..<10 { // 10 tests\n    let a = (-30..<100).rand\n    let b = (-30..<100).rand\n\n    assert add(a,b) == (a+b)\n  }\n}\n
"},{"location":"pyrope/05b-statements/#test-only-statements","title":"Test only statements","text":"

test code blocks are allowed to use special statements not available outside testing blocks:

  • step [ncycles] advances the simulation for several cycles. The local variables will preserve the value, the inputs may change value.

  • waitfor condition is a syntax sugar to wait for a condition to be true.

stepsynthesizable equivalent
test \"wait 1 cycle\" {\n  let a = 1 + input\n  puts \"printed every cycle input={}\", a\n  step 1\n  puts \"also every cycle a={}\",a  // printed on cycle later\n}\n
test \"wait 1 cycle\" {\n  {\n    let a = 1 + input\n    puts \"printed every cycle input={}\", a\n  } #> {\n    puts \"also every cycle a={}\",a  // printed on cycle later\n  }\n}\n

The waitfor command is equivalent to a while with a step.

waitforequivalent Pyrope
total = 3\n\nwaitfor a_cond  // wait until a_cond is true\n\nassert total == 3 and a_cond\n
total = 3\n\nwhile !a_cond {\n  step\n}\n\nassert total == 3 and a_cond\n

The main reason for using the step is that the \"equivalent\" #>[1] is a more structured construct. The step behaves more like a \"yield\" in that the next call or cycle it will continue from there. The #>[1] directive adds a pipeline structure which means that it can be started each cycle. Calling a lambda that has called a step and still has not finished should result in a simulation assertion failure.

  • peek allows to read any flop, and lambda input or output

  • poke is similar to peek but allows to set a value on any flop and lambda input/output.

"},{"location":"pyrope/06-functions/","title":"Lambdas","text":"

A lambda consists of a sequence of statements that can be bound to a variable. The variable can be copied and called as needed. Unlike most languages, Pyrope only supports anonymous lambdas. The reason is that without it lambdas would be assigned to a namespace. Supporting namespaces would avoid aliases across libraries, but Pyrope allows different versions of the same library at different parts of the project. This will effectively create a namespace alias. The solution is to not have namespaces but relies upon variable scope to decide which lambda to call.

Observation

Allowing multiple version of the same library/code is supported by Pyrope. It looks like a strange feature from a software point of view, but it is common in hardware to have different blocks designed/verified at different times. The team may not want to open and modernize a block. In hardware, it is also common to have different blocks to be compiled with different compiler versions. These are features that Pyrope enables.

Pyrope divides the lambdas into two categories: functions and procedures. Functions operate only over combinational logic. They can not have any synthesis side-effect. This means the function outputs are only a function of the function inputs. Any external call can only affect debug statements not the synthesizable code. functions resemble pure functions in normal programming languages. In pure functions, the function results depend only on the input parameters. In Pyrope, they are allowed to have side effects on debug code (non-synthesizable).

Non-function lambdas are called procedures or methods. The only difference between procedures and methods is that a method has self as the first argument in the output which allows to mutable the called tuple.

Lambdas also can be divided into modules and non-modules. A module is a lambda visible at synthesis call hierarchy. A non-module is an inlined or flattened lambda.

functions are combinational logic, but procedures can have inputs and/or outputs registerd or just be a generic pure combinational function.

Combinational (fun)Combinational (proc)Inputs Registerd (proc)Outputs Registerd (proc)
let add=fun(a,b)->(res) {\n  res = a+b\n}\n\nfun add(a,b)->(res) {  // Same as let add=fun(a,b)->(res)\n  res = a+b\n}\n
let add=proc(a,b)->(res) {  // nicer to use fun, but proc works\n  res = a+b\n}\n\nproc add(a,b)->(res) {  // same\n  res = a+b\n}\n
let add=proc(reg a, reg b)->(res) {\n  res = a+b\n}\n\nproc add(reg a, reg b)->(res) { // same\n  res = a+b\n}\n
let add=proc(a, b)->(reg res) {\n  res = a+b\n}\n\nproc add(a, b)->(reg res) { // same\n  res = a+b\n}\n
"},{"location":"pyrope/06-functions/#declaration","title":"Declaration","text":"

Only anonymous lambdas are supported, this means that there is no global scope for functions, procedures, or modules. The only way for a file to access a lambda is to have access to a local variable with a definition or to \"import\" a variable from another file. The more familiar fun name or proc name declaration is also valid, but it is syntax sugar and equivalent to let name = fun.

let a_3   = {   3 }      // just scope, not a lambda. Scope is evaluate now\nlet a_fun = fun() { 4 }  // when a_fun is called 4 is returned\n\nlet fun3 = fun(){ 5 }    // public lambda that can be imported by other files\n\nlet x = a_3()            // compile error, explicit call not posible in scope\nlet x = a_fun()          // OK, explicit call needed when no arguments\n\nassert a_3() equals 3\nassert a_fun equals _:fun()\nassert a_fun() equals 4\nassert a_fun() == 4      // calls to eval the function\n

The lambda definition has the following fields:

[GENERIC] [CAPTURE] [INPUT] [-> OUTPUT] [where COND] |\n
  • GENERIC is an optional comma separated list of names between < and > to use as generic types in the lambda.

  • CAPTURE has the list of capture variables for the lambda. If no capture is provided, no local variable can be captured by value which is equivalent to an empty list ([]), The captures are by value only, no capture by reference is allowed. Unlike most languages, capture must be comptime. Section Closures has more details.

  • INPUT has a list of inputs allowed with optional types. () indicates no inputs. (...args) allow to accept a variable number of arguments.

  • OUTPUT has a list of outputs allowed with optional types. () indicates no outputs.

  • COND is the condition under which this statement is valid. The COND can use the inputs, outputs, and self to evaluate. If the outputs are used in the COND, the lambda must be immutable (fun). This means that the method is called when the condition could evaluate true depending on its execution, but being immutable there are no side effects. Section overload has more details.

var add:fun(...x) = _\nadd = fun (...x) { x.0+x.1+x.2 }      // no IO specified\nadd = fun (a,b,c){ a+b+c }            // constrain inputs to a,b,c\nadd = fun (a,b,c){ a+b+c }            // same\nadd = fun (a:u32,b:s3,c){ a+b+c }     // constrain some input types\nadd = fun (a,b,c) -> (x:u32){ a+b+c } // constrain result to u32\nadd = fun (a,b,c) -> (res){ a+b+c }   // constrain result to be named res\nadd = fun (a,b:a,c:a){ a+b+c }        // constrain inputs to have same type\nadd = fun <T>(a:T,b:T,c:T){ a+b+c }   // same\n\nx = 2\nvar add2:fun2(a) = _\nadd2 = fun       (a){   x + a }    // compile error, undefined 'x'\nadd2 = fun[     ](a){   x + a }    // compile error, undefined 'x'\nadd2 = fun[x    ](a){   x + a }    // explicit capture x\nadd2 = fun[foo=x](a){ foo + a }    // capture x but rename to something else\n\nvar y = (\n  ,val:u32 = 1\n  ,inc1 = fun (ref self) { self.val = u32(self.val + 1) }\n)\n\nlet my_log::[debug] = fun (...inp) {\n  print \"loging:\"\n  for i in inp {\n    print \" {}\", i\n  }\n  puts\n}\n\nlet f = fun<X>(a:X,b:X){ a+b }   // enforces a and b with same type\nassert f(33:u22,100:u22)\n\nmy_log a, false, x+1\n
"},{"location":"pyrope/06-functions/#argument-naming","title":"Argument naming","text":"

Input arguments must be named. E.g: fcall(a=2,b=3) There are the following exceptions that avoid naming arguments:

  • If the type system can distinguish between unnamed arguments (no ambiguity)

  • If there is an argument/call match. The calling variable name has the same as an argument

  • If the argument is a single letter, and there is no name match, only position is used

  • self does not need to be named (first argument position)

There are several rules on how to handle arguments.

  • Calls use the Uniform Function Call Syntax (UFCS) but only when self is defined as first argument. (a,b).f(x,y) == f((a,b),x,y)

  • Pipe |> concatenated inputs: (a,b) |> f(x,y) == f(x,y,a,b)

  • Function calls with arguments do not need parenthesis after newline or a variable assignment: a = f(x,y) is the same as a = f x,y

  • Functions explicitly declared without arguments, do not need parenthesis in function call.

Pyrope uses a Uniform Function Call Syntax (UFCS) when the first argument is self. It resembles Nim or D UFCS but it can be different from the order in other languages. Notice the different order in UFCS vs pipe, and also that in the pipe the argument tuple is concatenated.

let div  = fun (self,b) { self / b }  // named input tuple\nlet div2 = fun (...x){ x.0 / x.1 }    // unnamed input tuple\n\nlet noarg = fun () { 33 }         // explicit no args\n\nassert 33 == noarg()\n\nassert noarg == 33 // compile error, `noarg()` needed for calls without arguments\n\na=div(3  , 4  , 3)       // compile error, div has 2 inputs\nb=div(self=8, b=4)       // OK, 2\nc=div self=8, b=4        // compile error, parenthesis needed for complex call\nd=(self=8).div(b=2)      // OK, 4\nd=(8).div(b=2)           // OK, 4 . self does not need to be named\nd=8.div(2)               // OK, single character inputs no need to be named\ne=(self=8).div b=2       // compile error, parenthesis needed for complex call\n\nh=div2(8, 4, 3)          // OK, 2 (3rd arg is not used)\ni=8.div2(4,3)            // compile error, no self in div2\n\nj=(8,4)  |> div2         // OK, 2, same as div2(8,4)\nj=(8,4)  |> div2()       // OK, 2, same as div2(8,4)\nk=(4)    |> div2(8)      // OK, 2, same as div2(8,4)\nl=(4,33) |> div2(8)      // OK, 2, same as div2(8,4,33)\nm=4      |> div2 8       // compile error, parenthesis needed for complex call\n\nn=div((8,4), 3)          // compile error: (8,4)/3 is undefined\no=(8,4).div2(1)          // compile error: (8,4)/1 is undefined\n

The UFCS allows to have lambdas to call any tuple, but if the called tuple has a lambda defined with the same name a compile error is generated. Like with variables, Pyrope does not allow lambda call shadowing. Polymorphism is allowed but only explicit one as explained later.

var tup = (\n  ,let f1 = fun(self) { 1 }\n)\n\nlet f1 = fun (self){ 2 }   // compile error, f1 shadows tup.f1\nlet f2 = fun (self){ 3 }\n\nassert f1()         != 0  // compile error, missing argument\nassert f1(tup)      != 0  // compile error, f1 shadowing (tup.f1 and f1)\nassert 4.f1()       != 0  // compile error, f1 can be called for tup, so shadow\nassert tup.f1()     != 0  // compile error, f1 is shadowing\n\nlet xx = fun[tup] { tup.f1() } // OK, function restricted scope for f1\nassert xx()\n\nassert (4:tup).f1() == 1\nassert 4.f2()       == 3  // UFCS call\nassert tup.f1()     == 1\n

The keyword self is used to indicate that the function is accessing a tuple. self is required to be the first argument. If the procedure modifies the tuple contents, a ref self must be passed as input.

var tup2 = (\n  ,val:u8 = _\n  ,upd = proc(ref self) { self.val::[saturate] += 1 }\n  ,calc = fun(self) { self.val}\n)\n

A lambda call uses parenthesis (foo() or foo(1,2)). The parenthesis can be avoid in tree conditions: (1) arguments are passed in a simple function call statement; (2) after a pipeline directive; (3) the variable has a getter method (get).

no_arg_fun()     // must use explicit parenthesis/called\narg_fun 1,2      // parenthesis are optional\narg_fun(1,2)     // OK too\n(1,2) |> arg_fun // OK too, it is after |>\n\nvar intercepted:(\n ,field:u32\n ,getter=fun(self) { self.field + 1 }\n ,setter=fun(ref self,v ) { self.field = v }\n) = 0\n\ncassert intercepted == 1  // will call get method without explicit call\ncassert intercepted.field == 0\n
"},{"location":"pyrope/06-functions/#pass-by-reference","title":"Pass by reference","text":"

Pyrope is an HDL, and as such, there are not memory allocation issues. This means that all the arguments are pass by value and the language has value semantics. In other words, there is not need to worry about ownership or move/forward semantics like in C++/Rust. All the arguments are always by value. Nevertheless, sometimes is useful to pass a reference to an array/register so that it can be updated/accessed on different lambdas.

Pyrope arguments are by value, unless the ref keyword is used. Pass by reference is needed to avoid the copy by value of the function call. Unlike non-hardware languages, there is no performance overhead in passing by value. The reason for passing as reference is to allow the lambda to operate over the passed argument. If modified, it behaves like if it were an implicit output. This is quite useful for large objects like memories to avoid the copy.

The pass by reference behaves like if the calling lambda were inlined in the caller lambda while still respecting the lambda scope. The ref keyword must be explicit in the lambda input definition but also in the lambda call. The lambda outputs can not have a ref modifier.

No logical or arithmetic operation can be done with a ref. As a result, it is only useful for lambda input arguments.

let inc1 = fun(ref a) { a += 1 }\n\nlet x = 3\ninc1(ref x)       // compile error, `x` is immutable but modified inside inc1\n\nvar y = 3\ninc1(ref y)\nassert y == 4\n\nlet banner = fun() { puts \"hello\"  }\nlet execute_method = fun(fn) {\n  fn() // prints hello when banner passed as argument\n}\n\nexecute_method(banner)     // OK\n
"},{"location":"pyrope/06-functions/#output-tuple","title":"Output tuple","text":"

Pyrope everything is a tuple, even the output or return from a lambda. When a single element is returned, it can be an unnamed tuple by omiting parenthesis.

let ret1 = fun()->(a:int) { // named\n  a = 1\n}\n\nlet ret2 = fun()->a:int {   // unnamed\n  a = 2\n}\n\nlet ret3 = fun()->(a,b) {   // named\n  a = 3\n  b = 4\n}\n\nlet a1 = ret1()\nassert a1.a == 1 // NOT a1 == 1\n\nlet a2 = ret2()\nassert a2 == 1   // NOT a2.a == 1\n\nlet a3 = ret3()\nassert a3.a == 3 and a2.b == 4\n\nlet (x1,x2) = ret3()\nassert x1   == 3 and x2   == 4\n
"},{"location":"pyrope/06-functions/#attributes","title":"Attributes","text":"

Variables can have attributes, but procedures can also have them. Procedure attributes have only one direction from inside the method to outside/caller. They can be used to signal out of band information about the procedude. Attributes can only be integer, bool, or string. Depending on the type, they are initialized to 0, false, or \"\".

The procedure attribute is stored in the variable that keeps the lambda. This means that it can be checked before or after the lambda call, and that different variables can point to the same procedure but keep different attributes.

let p1 = proc(a)->(res) {\n  self.[my_zero_found] or= (a == 0)\n\n  res = a + 1\n}\n\nlet p2 = p1      // copy\nlet p3 = ref p1  // reference\n\ntest \"testing p1\" {\n  assert p1.[my_zero_found] == false\n  assert p2.[my_zero_found] == false\n\n  cassert p1(3) == 4\n  assert p1.[my_zero_found] == false\n\n  cassert p1(0) == 1\n  assert p1.my_zero_found == true\n\n  cassert p1(50) == 51\n  assert p1.[my_zero_found] == true\n  assert p2.[my_zero_found] == false\n  assert p3.[my_zero_found] == true\n}\n
"},{"location":"pyrope/06-functions/#methods","title":"Methods","text":"

Pyrope arguments are by value, unless the ref keyword is used. ref is needed when a method intends to update the tuple contents. In this case, ref self argument behaves like a pass by reference in non-hardware languages. This means that the tuple fields are updated as the method executes, it does not wait until the method finishes execution. A method without the ref keyword is a pass by value call. Since all the inputs are immutable by default (let), any self updates should generate a compile error.

let Nested_call = (\n  ,var x = 1\n  ,let outter= proc(ref self) {  self.x = 100 ; self.inner(); self.x = 5 }\n  ,let inner = fun(self) { assert self.x == 100 }\n  ,let faulty = proc(self) { self.x = 55 } // compile error, immutable self\n  ,proc okcall(ref self) { self.x = 55 }   // equivalent to let okcall=proc\n)\n

self can also be returned but this behaves like a normal copy by value variable return.

var a_1 = (\n  ,x:u10\n  ,let f1 = fun(ref self,x)->(self) { // BOTH ref self and return self is OK\n    self.x = x\n    self\n  }\n)\n\na_1.f1(3)\nvar a_2 = a_1.f1(4)  // a_2 is updated, not a_1\nassert a_1.x == 3 and a_2.x == 4\n\n// Same behavior as in a function with UFCS\nfun2 = fun (ref self, x) { self.x = x }\n\na_1.fun2(10)\nvar a_3 = a_1.fun2(20)\nassert a_1 == 10 and a_3 == 20\n

Since UFCS does not allow shadowing, a wrapper must be built or a compile error is generated.

var counter = (\n  ,var val:i32 = 0\n  ,let inc = fun (ref self, v){ self.var += v }\n)\n\nassert counter.val == 0\ncounter.inc(3)\nassert counter.val == 3\n\nlet inc = fun (ref self, v) { self.var *= v } // NOT INC but multiply\ncounter.inc(2)             // compile error, multiple inc options\nassert 44.inc(2) == 8\n\ncounter.val = 5\nlet mul = inc\ncounter.mul(2)             // call the new mul method with UFCS\nassert counter.val == 10\n\nmul(counter, 2)            // also legal\nassert counter.val == 20\n

It is possible to add new methods after the type declaration. In some languages, this is called extension functions.

let t1 = (a:u32)\n\nvar x:t1 = (a=3)\n\nt1.double = proc(ref self) { self.a *= 2 }  // extension function\n// previous is exactly the same as:\n// t1 = t1 ++ (double = proc(ref self) { self.a *= 2 })\n\nvar y:t1 = (a=3)\nx.double             // compile error, double method does not exit\ny.double             // OK\nassert y.a == 6\n
"},{"location":"pyrope/06-functions/#constraining-arguments","title":"Constraining arguments","text":"

Arguments can constrain the inputs and input types. Unconstrained input types allow for more freedom and a potentially variable number of arguments generics, but it can be error-prone.

unconstrained declarationconstrained declaration
foo = fun (self) { puts \"fun.foo\" }\na = (\n  ,foo = fun () {\n     bar = fun() { puts \"bar\" }\n     puts \"mem.foo\"\n     return (bar=bar)\n  }\n)\nb = 3\nc = \"string\"\n\nb.foo         // prints \"fun.foo\"\nb.foo()       // prints \"fun.foo\"\nx = a.foo     // prints \"mem.foo\"\ny = a.foo()   // prints \"mem.foo\"\nx()           // prints \"bar\"\n\na.foo.bar()   // prints \"mem.foo\" and then \"bar\"\na.foo().bar() // prints \"mem.foo\" and then \"bar\"\na.foo().bar   // prints \"mem.foo\" and then \"bar\"\n\nc.foo         // prints \"fun.foo\"\n
foo = fun (self:int) { puts \"fun.foo\" }\na = (\n  ,foo = fun () {\n     bar = fun() { puts \"bar\" }\n     puts \"mem.foo\"\n     return (bar=bar)\n  }\n)\nb = 3\nc = \"string\"\n\nb.foo         // prints \"fun.foo\"\nb.foo()       // prints \"fun.foo\"\nx = a.foo     // prints \"mem.foo\"\ny = a.foo()   // prints \"mem.foo\"\nx()           // prints \"bar\"\n\na.foo.bar()   // prints \"mem.foo\" and then \"bar\"\na.foo().bar() // prints \"mem.foo\" and then \"bar\"\na.foo().bar   // prints \"mem.foo\" and then \"bar\"\n\nc.foo         // compile error, undefined 'foo' field/call\n

The where statement also allows to constrain arguments. This is a sample of fibonnaci implementation with and without where clauses. Section overload has more details on the method overloading.

let fib1 = fun(n) where n==0 {0}\n        ++ fun(n) where n==1 {1}\n        ++ fun(n)            { fib1(n-1) + fib1(n-2) }\n\nassert fib1(10) == 55\n\nlet fib2 = fun(n) {\n  return match n {\n    == 0 {0}\n    == 1 {1}\n    else {fib2(n-1) + fib2(n-2)}\n  }\n}\n\nassert fib2(10) == 55\n
"},{"location":"pyrope/06b-instantiation/","title":"Instantiation","text":"

Instantiation is the process of translating from Pyrope to an equivalent set of gates. The gates could be simplified or further optimized by later compiler passes or optimization steps. This section provides an overview of how the major Pyrope syntax constructs translate to gates.

"},{"location":"pyrope/06b-instantiation/#conditionals","title":"Conditionals","text":"

Conditional statements like if/else and match translate to multiplexers (muxes).

A trivial if/else with all the options covered is a simple mux.

var res:s4 = _\nif cond {\n  res = a\n}else{\n  res = b\n}\n\n// RTL equivalent (bus of 4 bits in a,b,res2)\nvar res2:s4 = __mux(cond,b,a)\n\nlec res, res2\n

An expression if/else is also a mux.

var res = if cond { a }else{ b }\n\n// RTL equivalent\nvar res2 = __mux(cond,b,a)\n\nlec res, res2\n

The when/unless is also a mux.

var res = a\nres = b unless cond\n\n// RTL equivalent\nvar res2 = __mux(cond,b,a)\n\nlec res, res2\n

Chaining if/elif creates a chain of muxes. If not all the inputs are covered, the value from before the if is used. If the variable did not exist, a compile error is generated.

var res = a\nif cond1 {\n  res = b\n}elif cond2 {\n  res = c\n}else{\n  assert true // no res\n}\n\n// RTL equivalent\nvar tmp = __mux(cond2, a, c)\nvar res2= __mux(cond1, tmp, b)\n\nlec res, res2\n

unique if/elif is similar but avoids mux nesting using a one-hot encoded mux.

var res = a\nunique if cond1 {\n  res = b\n}elif cond2 {\n  res = c\n} // no res in else\n\n// RTL equivalent\nvar sel = (!cond1 and !cond2, cond1, cond2)@[..]  // one hot encode\nvar res2= __hotmux(sel, a, b, c)\noptimize !(cond1 and cond2)                       // one hot check\n\nlec res, res2\n

The match is similar to the unique if but also checks that one of the options is enabled, which allows further optimizations. From a Verilog designer point of view, the match is a \"full parallel\" and the unique if is a \"parallel\". Both are checked at verification and optimized at synthesis.

var res = a\nmatch x {\n  == c1 { res = b }\n  == c2 { res = c }\n  == c3 { res = d }\n}\n\n// RTL equivalent\nlet cond1 = x == c1\nlet cond2 = x == c2\nlet cond3 = x == c3\nvar sel = (cond1, cond2, !cond1 and !cond2)@[..]  // one hot encode (no cond3)\nvar res2= __hotmux(sel, b, c, d)\noptimize ( cond1 and !cond2 and !cond3)\n      or (!cond1 and  cond2 and !cond3)\n      or (!cond1 and !cond2 and  cond3)    // one hot check (no else allowed)\n\nlec res, res2\n
"},{"location":"pyrope/06b-instantiation/#optional-expression","title":"Optional expression","text":"

Valid or optionals are computed for each assignment and passed to every lambda call. Each variable has an associated valid bit, but it is removed if never read, and it is always true unless the variables are assigned in conditionals or non-short-circuit (and_then/or_else) expressions.

Short-circuit expressionUsual expressionConditionalsLambda call (inlined)
var lhs = v1 or_else v2\n\n// RTL equivalent\nlet lhs2  = __or(v1, v2)\nlet lhs2_v = __or(__and(v1?, v1), __and(v2?, v2))\n\nlec lhs , lhs2\nlec lhs?, lhs2_v\n
var lhs = v1 + v2\n\n// RTL equivalent\nlet lhs2   = __sum(A=(v1, v2))\nlet lhs2_v = __and(v1?, v2?)\n\nlec lhs , lhs2\nlec lhs?, lhs2_v\n
lhs = v0\nif cond1 {\n  lhs = v1\n}elif cond2 {\n  lhs = v2\n} // no else\n\n// RTL equivalent\nlet tmp = __mux(cond2, v0, v2)\nlet lhs2= __mux(cond1, tmp, v1)\n\nlet tmp_v = __mux(cond2, v0?, v2?)\nlet lhs2_v= __mux(cond1, tmp_v, v1?)\n\nlec lhs , lhs2\nlec lhs?, lhs2_v\n
let f = fun(a,b) { if a == 0 { 3 }else{ b } }\n\nvar lhs = c\nif cond {\n   lhs = f(a,b)\n}\n\n// RTL equivalent\nlet a_cond = __not(__ror(a))             // a == 0\nlet tmp    = __mux(a_cond, b, 3)         // if a_cond { 3 }else{ b }\nvar lhs2   = c\nlhs2       = __mux(cond, x, tmp)\n\nlet tmp_v  = __mux(a_cond, a?, __and(a?,b?)) // a? or (a==0 and b?)\n\nlet lhs2_v = __mux(cond, c?, tmp_v)\n\nlec lhs , lhs2\nlec lhs?, lhs2_v\n
"},{"location":"pyrope/06b-instantiation/#lambda-calls","title":"Lambda calls","text":"

Lambda calls are either inlined or become a specific instance (module). When the instance is located in a conditional path, the instance is moved to the main scope toggling the inputs valid attribute ::[valid=false]. The instance has the assigned variable name. If the instance is a var, the variable name can be the SSA name.

Lambda callInstance
let sub = proc(a,b)->(x) {\n  let tmp = sum(a,b)       // instance tmp,sum\n\n  x = sum(tmp,3)           // instance x,sum\n}\n\nlet top = proc(a,b,c)->(x) {\n\n x = sub(a,b).x\n if c {\n   let tmp=3\n   x += sub(b,tmp).x\n }\n}\n
let sub = proc(a,b)->(x) {\n  let tmp = sum(a,b)       // instance tmp\n\n  x = sum(tmp,3)           // instance x\n}\n\nlet top = proc(a,b,c)->(x) {\n\n x = sub(a,b).x           // instance x\n\n let x_0 = _\n let sub_arg_0 = _\n let sub_arg_1 = _\n if c {\n   let tmp=3\n   sub_arg_0 = b\n   sub_arg_1 = tmp\n   x += x_0.[defer]       // use defer (instance after conditional code)\n }\n x_0 = sub(sub_arg_0,sub_arg_1).x   // instance x_0 (SSA)\n}\n
"},{"location":"pyrope/06b-instantiation/#optional-lambdas","title":"Optional lambdas","text":"

HDLs use typical software constructs that look like function calls to represent instances in design. As previously explained, hardware languages are about instantiation, and software languages are about instruction execution. A lambda called unconditionally is likely to result in module unless the compiler decides to be small and it is inlined.

In Pyrope, the semantics are that when a lambda is conditionally called, it should behave like if the lambda were inlined in the conditional place. Since functions have no side effects, it is also equivalent to call the lambda before the conditional path, and assign the return value inside the conditional path only. Special care must be handled for the puts which is allowed in functions. The puts is not called if the function is conditionally called and the condition is false.

Conditional proc callPyrope inline equivalent
let case_1_counter = proc(runtime)->(res) {\n\n  let r = (\n    ,reg total:u16 = _          // r is reg, everything is reg\n    ,increase = fun(a) {\n      puts \"hello\"\n\n      let res = self.total\n      self.total::[wrap] = res+a\n\n      res\n    }\n  )\n\n  if runtime == 2 {\n    res = r.increase(3)\n  }elif runtime == 4 {\n    res = r.increase(9)\n  }\n}\n
let case_1_counter = proc(runtime)->(res) {\n\n  let r = (\n    ,reg total:u16 = _\n    ,increase = fun(a) {\n      puts \"hello\"\n\n      let res = self.total\n      self.total::[wrap] = res+a\n\n      res\n    }\n  )\n\n  if runtime == 2 {\n    puts \"hello\"\n\n    let res = r.total\n    r.total::[wrap] = res+3\n    res = res\n  }elif runtime == 4 {\n    puts \"hello\"\n\n    let res = r.total\n    r.total::[wrap]= res+9\n    res = res\n  }\n}\n

The result of conditionally calling procedures is that most of the code may be inlined. This can change the expected equivalent Verilog generated modules.

Calling a procedure with the inputs set invalid has a different behavior. For once C++ calls will still happen, and updates to registers with not valid data is allowed to reset the valid bit.

"},{"location":"pyrope/06b-instantiation/#expressions","title":"Expressions","text":"

Pyrope expressions are guaranteed to have the same result independent of the order of evaluation. Only and_then, or_else or complex constructs like if/else, match, for have evaluation order.

"},{"location":"pyrope/06b-instantiation/#setup-vs-reset-vs-execution","title":"Setup vs reset vs execution","text":"

In a normal programming language, the Von Neumann PC specifies clear semantics on when the code is executed. The language could also have a macro or template system executed at compile-time, the rest of the code is called explicitly when the function is called. As mentioned, a key difference is that HDLs focus on instantiation of gates/logic/registers, not instruction execution. HDLs tend to have 3 code sections:

  • Setup: This is code executed to set up the hierarchies, parameters, read configuration setups... It is usually executed at compile time. In Verilog, these are the preprocessor directives and the generate statements. In CHISEL, the scala is the setup code.

  • Reset: Hardware starts in an undefined/inconsistent state. Usually, a reset signal is enabled several cycles and the associated reset logic configures the system to a given state.

  • Execution: This is the code executed every cycle after reset. The reset logic activation can happen at any time, and parts of the machine may be in reset mode while others are not.

In addition, some languages like Verilog have \"initialization\" code that is executed before reset. This is usually done for debugging, and it is not synthesizable. Although not always synthesizable, we consider this setup code.

Pyrope aims to have the setup, reset, and execution specified.

"},{"location":"pyrope/06b-instantiation/#setup-code","title":"Setup code","text":"

Compiling a Pyrope program requires specifying a \"top file\" file and a \"top variable\" in the top file. The top file is executed only once. The top file may \"import\" other files. Each of the imports is executed only once too. The imported files are executed before the current file is executed. This is applied recursively but no loops are supported in import dependence chains.

The \"setup\" code is the statements executed once for each imported file. Those statements can not be \"imported\" by other files. Only the resulting public variables can be imported.

During setup, each file can have a list of public variables. Those are variables that can be used by importing modules. The \"top variable\" is selected for simulation/synthesis.

It is important to point that comptime may be used during setup but also in non-setup code. comptime just means that the associated variables are known at compile time. This is quite useful during reset and execution too or just to guaranteed that a computation is solved at compile time.

"},{"location":"pyrope/06b-instantiation/#reset-code","title":"Reset code","text":"

The reset logic is associated with registers and memories. The assignment to register declaration is the reset code. It will be called for as many cycles are the reset is held active. The reg assignment can be a constant or a call to conf that can provide a runtime file with the values to start the simulation/synthesis.

reg r:u16 = 3 // reset sets r to 3\nr = 2             // non-reset assignment\n\nreg array:[]u16 = (1,2,3,4)  // reset values\n\nreg r2:u128 = conf.get(\"my_data.for.r2\")\n\nreg array:[] = conf.get(\"some.conf.hex.dump\")\n

The assignment during declaration to a register is always the reset value. If the assignment is a method, the method is called every cycle during reset.

reg array:[1024]tag:[clock_pin=my_clock] = proc(ref self) {\n  reg reset_iter:u10:[reset_pin=false] = 0sb? // no reset flop\n\n  self[reset_iter].state = I\n\n  reset_iter::[wrap] = reset_iter + 1\n}\n

Since the reset can be high many cycles, it may be practical/necessary to have a reset inside the reset procedure. To guarantee determinism, any register inside the reset procedure can be either asynchrnous reset or a register without reset signal.

reg my_flop:[8]u32 = proc(ref self) {\n  reg reset_counter:u3:[async=true] = _ // async is only posedge reset\n\n  self[reset_counter] = reset_counter\n  reset_counter::[wrap] += 1\n}\n

A related functionality and constrains happen when a tuple have some register fields and some non-register fields. The same reset procedure is called every cycle Similarly a tuple can have a reset when assigned to a register.

Mixed tuple reset with constantsMixed tuple reset with method
let Mix_tup = (\n  ,reg flag:bool = false\n  ,state: u2\n)\n\nvar x:Mux_tup = (false,1)  // 0 used at reset, 1 used every cycle\n\nassert x.flag implies x.state == 2\n\nx.state = 0\nif x.flag {\n  x.state = 2\n}\nx.flag = true\n
let Mix_tup = (\n  ,reg flag:bool = false\n  ,state:u2\n)\n\nvar x:Mux_tup = proc(ref self) {\n  self.flag  = proc(ref self) { self = false }  // reset code\n  self.state = 2                                // every cycle code\n}\n\nassert x.flag implies x.state == 2\n\nx.state = 0\nif x.flag {\n  x.state = 2\n}\n

A sample of asynchronous reset with different reset and clock signal

reg my_asyn_other_reg:u8:[\n  ,async = true\n  ,clock = ref clk2    // ref to connect, not read clk2 value\n  ,reset = ref reset33 // ref to connect, not read current reset33 value\n] = 33 // initialized to 33 at reset\n\n\nif my_async_other_reg == 33 {\n  my_async_other_reg = 4\n}\n\nassert my_async_other_reg in (4,33)\n
"},{"location":"pyrope/06b-instantiation/#retime","title":"retime","text":"

Values stored in registers (flop or latches) and memories (synchronous or asynchronous) can not be used in compiler optimization passes. The reason is that a scan chain is allowed to replace the values.

The retime attribute indicates that the register/memory can be replicated and used for optimization. Copy values can propagate through retime register/memories.

A register or memory without explicit :[retime] attribute can only be optimized away if there is no read AND no write to the register. Even just having writes the register is preserved because it can be used to read values with the scan-chain.

"},{"location":"pyrope/06b-instantiation/#execution-code","title":"Execution code","text":"

HDLs specify a tree-like structure of modules. The top module could instantiate several sub-modules. Pyrope Setup phase is to create such hierarchical structures. The call order follows a program order from the top point every cycle, even when reset is set.

The following Verilog hierarchy can be encoded with the equivalent Pyrope:

VerilogPyrope equivalentPyrope alternative IPyrope alternative II
module inner(input z, input y, output a, output h);\nassign a =   y & z;\nassign h = !(y & z);\n\nendmodule\n\nmodule top2(input a, input b, output c, output d);\n\ninner foo(.y(a),.z(b),.a(c),.h(d));\n\nendmodule\n
let inner = fun(z,y)->(a,h) {\n  a =   y & z\n  h = !(y & z)\n}\n\nlet top2 = fun(a,b)->(c,d) {\n  let x= inner(y=a,z=b)\n  c = x.a\n  d = x.h\n}\n
let Inner_t = (\n  ,setter = proc(ref self, z,y) {\n    self.a =   y & z\n    self.h = !(y & z)\n  }\n)\n\nlet Top2_t = (\n  ,setter = proc(ref self,a,b) {\n    let foo:Inner_t = (y=a,z=b)\n\n    self.c = foo.a\n    self.d = foo.h\n  }\n)\n\nlet top:Top2_t = (a,b)\n
let Inner_t = (\n  ,setter = proc(ref self, z,y) {\n    self.a =   y & z\n    self.h = !(y & z)\n  }\n)\n\nlet Top2_t = (\n  ,foo:Inner_t = _\n  ,setter = proc(ref self,a,b) {\n    (self.c, self.d) = self.foo(y=a,z=b)\n  }\n)\n\nlet top:Top2_t = (a,b)\n

The top-level module top2 must be a module, but as the alternative Pyrope syntax shows, the inner modules may be in tuples or direct module calls. The are advantages to each approach but the code quality should be the same.

"},{"location":"pyrope/06b-instantiation/#registers","title":"Registers","text":"
reg a:u4 = 3\na::[saturate] = a+1\n\nreg b = 4\nif cond {\n  reg c = _           // weird as reg, but legal syntax\n  c = b + 1\n  b = 5\n}\n\n// RTL equivalent\na_qpin = __flop(reset=ref reset, clk=ref clk, initial=3, din=a.[defer])\ntmp    = __sum(A=(a_qpin, 1))\na      = __mux(tmp[4], tmp@[0..=3], 0xF)    // saturate, not wrap\n\nb_qpin = __flop(reset=ref reset, clk=ref clk, initial=4, din=b.[defer])\nb      = __mux(cond, b_qpin, 5)\n\nc_cond_qpin = __flop(reset=ref reset, clk=ref clk, initial=0, din=c_cond.[defer])\nc_cond      = __sum(A=(b, 1))\n
"},{"location":"pyrope/06c-pipelining/","title":"Pipelining","text":""},{"location":"pyrope/06c-pipelining/#registers","title":"Registers","text":"

Together with memories, flip-flops or latches are the basic constructs used by hardware to store information and to build pipeline stages. Pyrope's goal is to be a zero-cost overhead, and as such it allows to handle flops directly.

To create an individual flop, a direct RTL instantiation of a __flop can be used. Flops and latches have several pins din, q, clock, enable and configuration options posclk, initial, and async.

A more programmer-friendly is to use to declare a register. The compiler does not provide guarantees that the register will not be split into multiple registers.

The explicit connection likely requires constructs like .[defer] to connect the flop q pin.

Structural flop stylePyrope style
var counter_next:u8:[wrap] = _\n\nlet counter_q = __flop(din=counter_next.[defer] // defer to get last update\n                   ,reset_pin=my_rst, clock_pin=my_clk\n                   ,enable=my_enable            // enable control\n                   ,posclk=true\n                   ,initial=3                   // reset value\n                   ,async=false)\n\ncounter_next = counter_q + 1\n
reg counter:u8:[reset_pin=my_rst, clock_pin=my_clk, posclk=true]= 3\nassert counter == counter#[0]  // counter still has the q value\n\nif my_enable {\n  counter::[wrap] = counter + 1\n}\n

Flops have din and a q pin. At the beginning of the cycle both din and q have the same value, but as the din is updated with \"next cycle\" q value their contents may be different. Different HDLs have different syntax to distinguish between din and q pin. In Verilog, it is common to have a coding style guideline that gives a different name to the din variables than to the q variables (E.g: counter_q vs counter_next). The structural flop style is a legal Pyrope code using these type of names.

In a more friendly Pyrope style, a register like counter starts with the q pin each cycle. The last value written to counter connects to the din. It is always possible to access the q pin/value directly with pipeline directives something#[0].

If the register is accessed with the -1 cycle (#something#[-1]), the flop will insert an additional pipeline to access 1 cycle before flop contents.

It is also possible to use positive values (variable#[3]) which means the value in the future 3 cycles, but this is only allowed in debug statements like assert or puts.

Latches are possible but with the direct RTL instantiation. Latches have a din and enable pin like a flop, but just one option posclk.

var my_latch_q = __latch(din=my_din, enable=my_enable, posclk=true)\n
"},{"location":"pyrope/06c-pipelining/#pipestage","title":"Pipestage","text":"

Pyrope has a pipestage statement (#>identifier[fsm_configuration]) that helps to create simple pipeline stages. The identifier[fsm_configuration] is optional and the default meaning is a fully pipelined 1 pipeline stage depth. It is the same as saying _[lat=1]. The identifier can be accessed as an attribute to count the pipestage utilization.

The fsm configuration can have lat (number of pipeline stages or latency) or num (number of units). The number of units is only needed when the code is not fully pipelined in combination with loop constructs like while, for, and loop.

The num sets the number of units. The hardware will not back pressure, but an assertion will fail during simulation if the number of units is overflowed. num only makes sense when the latency (lat) is more than 1.

// variables/register before\n\n{\n  // stage 0 scope\n} #> {               // no identifier, 1 stage by default\n  // stage 1 scope\n} #>foo[2] {            // no identifier, 2 stages\n  // stage 2-3 scope\n} #>bar[1] {     // 'free_stage' identifier, 1 stages\n  // stage 4 scope\n} #> {\n  // stage 5 scope\n}\n\n// variables/register after pipestage\n

The semantics of pipestage are as follows:

  • Explicitly declared registers (reg foo) are not affected by pipestage

  • Variables declared before are \"pipelined\" inside each of the pipestage scopes.

  • Variables declared in a stage are pipelined to all the following stages unless the variable is private (var priv_example::[private]=3)

  • The pipelined variables are not visible in the scope after the pipestage sequence.

  • The original non-pipelined variable can be accessed with v#[0].

To illustrate the semantics, imagine a module where the input i is a monotonically increasing sequence (0,1,2,3,4,5,6,7....).

assert i==0 or (i#[-1] + 1 == i)\n\nlet i_let = i\n\nvar i_var0 = i\nvar i_var1 = i\n\nreg i_reg0 = i        // initialization only\nreg i_reg1:i_reg0 = _\n\ni_reg1 = i                // every cycle\n\n{\n  assert i == i#[0]       // i#[0] is unflop input (or first defined) value\n  assert i == i_let\n  assert i == i_var0\n  assert i == i_var1\n\n  assert 0 == i_reg0\n  assert i == i_reg1\n\n  let _local_var = 3\n\n  let pub_var = 100 + i\n\n} #> {\n  assert _local_var!=0      // compile error, _local_var is not in scope\n  assert pub_var == 100 + i // pipelined pub_var\n\n  // both inputs and variables flop, so asserts hold\n  assert i == i_let\n  assert i == i_var0\n  assert i == i_var1\n\n  assert 0 == i_reg0        // i_reg0 never changes, so 0 is fine\n  assert i#[-1] == i_reg1   // last i-reg, not current\n\n  assert i == 0 or (i == i#[0]+1)  // i#[0] is the unflop original\n}\n\nassert pub_var != 0 // compile error, pub_var is not in scope\n

The pipestage accept the clock and posclk attributes from register to allow the selection of different clock signal. Notice that it does not allow reset or latch or async because it does not require reset logic.

Pipelining is one of the challenges of designing hardware. Even a simple pipestage code can result in incorrect hardware. The reason is that if two pipestage blocks generate an output simultaneously, there is no way to generate both outputs. The result is a compile or simulation error.

let bad_code = proc(my_clk, inp)->(o1,o2) {\n\n  {\n    o1 = 1\n    o2 = inp + 1  // o2? iff bad_code called this cycle and inp? is valid\n  } #>my_pipe[lat=1,clock=my_clk] {\n    o1 = 2        // compile error, o1 driven simultaneous from multiple stages\n    o2 = inp + 2  // may be OK if inp is not valid every cycle\n  }\n\n}\n
"},{"location":"pyrope/06c-pipelining/#pipestage-with-loops","title":"Pipestage with loops","text":"

The pipestage directive (#>identifier[cycles]{ }) automatically creates a fully pipeline design with cycles pipeline depth. cycles must be bigger or equal than 1 and known at compile time. When cycles is not specified a 1 value is assumed.

Pipestage can be applied to while and loop statements, not to for statements because for must be fully unrolled at compile time.

When applied to loops, the loop becames a state machine with cycles the maximum number of simultaneous loop iterations. It effectively means that number of units or state machines that can perform the loop simultaneously. The identifier becomes a procedure attribute.

Fully PipelinedState-machineSlow 1 StageSlow 1 Stage (alt syntax)Pure Combinatinal
let mul3=proc(a,b)->res {\n  let tmp = a*b\n  #>full_case[lat=3,num=3] { // Same as full_case[lat=3]\n    res = tmp\n  }\n}\n
let mul_slow=proc(a,b)->res {\n\n  let result  = 0\n  let rest    = a\n\n  while rest >= b #>_[lat=1,num=4] {  // lat=1 is latency per iteration\n    rest = rest - b\n    result += 1\n  }\n\n  res = result\n}\n
let mul1=proc(a,b)->(reg res) {\n  res = a*b\n}\n
let mul1=proc(a,b)->(res) {\n  #>full_case_again[lat=1] { \n    res = a*b\n  }\n}\n
let mul0=proc(a,b)->(res) {\n  res = a*b\n}\n

To understand the fully pipelined behavior, the following shows the pipestage against the more direct implementation with registers.

if cond {\n  var p1 = inp1\n  var out = _\n\n  {\n    var _l1 = inp1 + 1\n\n    var p2 = inp1 + 2\n  } #> {\n    out = p1 + p2\n  }\n\n  res = out\n}\n\n// Non pipestage equivalent\nif cond {\n  var p1 = inp1\n  var out = _\n\n  {\n    reg p1r = _\n    reg p2r = _\n\n    var l1::[private] = inp1 + 1  // private\n    var p2 = inp1 + 2             // public\n\n    out = p1r + p2r               // registered values\n\n    p1r = p1\n    p2r = p2\n  }\n\n  res = out\n}\n
"},{"location":"pyrope/06c-pipelining/#retiming","title":"Retiming","text":"

The registers manually inserted with the reg directive are preserved and annotated so that synthesis retiming can not change them. This means that by default register can not be duplicated or logic can move around.

A register can be marked with the retime flag, in which case the synthesis tools are allowed to perform the following optimizations:

  • Retime or move logic across which effectively changes the meaning of the register.

  • Duplication is allowed when frequency improvements grant it.

  • Elimination. If there are no reads or no writes, the register can be remove and replaced with a constant (no writes) or just removed (no reads).

  • Copy propagation is allowed across registers. This is not possible without retime because the scan chain could reconfigure the flop.

The registers automatically inserted with the pipestage command are marked with retime true. Additionally, retime can be set in any register:

reg my_reg::[retime=true,clock=my_clk] = 0\n
"},{"location":"pyrope/06c-pipelining/#multiply-add-example","title":"Multiply-Add example","text":"

To illustrate the confusion/complication the following example illustrates a multiplier that takes 3 cycles and an adder that takes 1 cycle to complete, and the conceptual problems of integrating them:

PipestageExplicit Stages
let block = proc(in1,in2)->(out) {\n  {\n    let tmp = in1 * in2\n  } #>some_id[lat=3] {\n    out = tmp + in1#[0]\n  }\n}\n
add1 = proc(a,b) {     // 1 cycle add\n  reg r  = _\n  let rr = r           // get flop value\n  r = a+b\n  return rr\n}\nlet mul3 = proc(a,b) { // 3 cycle multiply\n  reg reg1 = _\n  reg reg2 = _\n  reg reg3 = _\n  reg3 = reg2\n  reg2 = reg1\n  reg1 = a * b\n  return reg3\n}\n\nlet block = proc(in1,in2)->(out) {\n  let x =#[..] mul3(in1, in2)\n  out   =#[..] add1(x,in3)\n}\n

In general, # is used when dealing with registers. The previous example use procedures (proc ... {...}) instead of functions (fun ... {...}) because functions only have combinational logic. When the procedures are called, the assigned variable needs the =#[..]. This is to explicitly indicate to Pyrope that the function called (mul3, add1) can have pipeline outputs. This helps the tool but more importantly the programmer because it helps to check assumptions about the function connections. The typical assignment = only connects combinational logic.

The previous code connects two inputs (in1/in2) to a multiplier, and then connects the result of the multiplier to an adder. The inputs are also passed to the adder. This results in the following functionality:

graph LR in1[in1] --a--> m0(mul3 cycle 0) in2[in2] --b--> m0 m0 --> m1(mul3 cycle 1) m1 --> m2(mul3 cycle 2) in1--a--> a0[add1 cycle 1] m2 --b--> a0 a0 --> out[out]

The issue in most HDLs is that the connection is unaware of the pipelining, and it is left up to the programmer to understand and check the potential pipeline stages inside add1 and mul3. This lack of pipelining awareness in the language syntax is common in most HDLs.

In Pyrope, the =#[..] must be used when there is any path that starts from the inputs of the function passes through a pipeline stage to generate the assignment. If all the paths have exactly 1 flop in between, it is a 1 stage pipeline, if some paths have 2 flops and others 3, it is a 2 or 3 pipeline stages. Sometimes, there are loops, and the tool has 1 to infinite pipeline stages.

The default pipeline assignment =#[..] just checks that it is possible to have pipeline stages between the module/function inputs and the assignment value. To restrict the check, it accepts a range. E.g: =#[3] means that there are exactly 3 flops or cycles between inputs and the assignment. =#[0..<4] means that there are between 0 and 3 cycles, and open range could be used when there are loops (E.g: =#[2..]).

let x = mul3(in1, in2)      // compile error: 'mul3' is pipelined\nlet x =#[..] mul3(in1, in2) // OK\nout  =#[..] add1(x,in3)     // OK (in3 has 0 cycles, x has 3 cycles)\nout  =#[1] add1(x,in3)      // compile error: 'x' is pipelined with '3' cycles\nout  =#[3] add1(x,in3)      // compile error: 'in3' is pipelined with '1' cycle\nout  =#[1..<4] add1(x,in3)  // OK\n

The designer likely wanted to implement a multiply-add. As such, the input to the adder should be from the same cycle as the multiplied started to operate. Otherwise, values across cycles are mixed.

graph LR in1[in1] --a--> m0(mul3 cycle 0) in2[in2] --b--> m0 m0 --> m1(mul3 cycle 1) m1 --> m2(mul3 cycle 2) in1 --> in1_0(flop cycle 0) in1_0--> in1_1(flop cycle 1) in1_1--> in1_2(flop cycle 2) in1_2--a--> a0[add1 cycle 0] m2 --b--> a0 a0 --> out[out]

It is possible to balance the pipeline stages explicitly, the issue is that it is error-prone because it requires knowing exactly the number of cycles for mul3.

PipestageExplicitly added pipeline stages
{\n  let tmp = in1 * in2\n} #>fully_pipe[lat=3] {\n  out = tmp + in1\n}\n
x =#[..] mul3(in1, in2)\ny = in1#[-3]\nout =#[..] add1(a=x,b=y)    // connect in1 from -3 cycles\n

Observation

The explicit v#[-cycles] inserts registers and access the result cycles before. This same syntax can be used with assertions similar to the Verilog $past(v, cycles).

"},{"location":"pyrope/06c-pipelining/#alu-example","title":"ALU example","text":"

Pipestages allow to build fully pipelined structures but also non-pipelined state machines when applied to loops. This creates potential contention that the designer must decide how to manage. This contention can be propagated outside the procedure with attributes.

The ALU example illustrates the contention by creating an ALU with 3 different pipelines (add,mul,div) that have different latencies and contention.

let quick_log2 = fun(a) {\n\n  cassert a>=1\n\n  var i = 1\n  var v = 0\n  while i < a.[bits] {\n    v |= i\n    i *= 2\n  }\n\n  return v\n}\n\nlet div=proc(a,b,id)->(res,id) {\n  loop #>free_div_units[4] {\n    return (a >> quick_log2(b), id) when b@+[..] == 1\n    #>my_fsm[lat=5,num=1] {\n      res = (a/b, id)\n    }\n  }\n}\n\nlet mul=proc(a,b,id)->(res, id) {\n  #>pending_counter[lat=3,num=2] {\n    res = a*b\n    id  = id\n  }\n}\n\nlet add=proc(a,b,id)->(res,id) {\n  #>add_counter[lat=1] {         // Fully pipeline, num not specified\n    res = a+b\n    id  = id\n  }\n}\n\nlet alu = proc(a,b,op, id)->(res,id) {\n\n  self.[total_free_units] = 1 \n     + mul.[pending_counter] \n     + div.[free_div_units]\n     + add.[add_counter]\n\n  self.[div_units] = div.[free_div_units]\n\n  match op {\n    == OP.div {\n      assert div.[free_div_units]>0\n      (res,id) = div(a,b,id)\n    }\n    == OP.mul { (res,id) = mul(a,b,id) }\n    == OP.add { (res,id) = add(a,b,id) }\n  }\n}\n\ntest \"alu too many div\" {\n\n cassert alu.[total_free_units] == (1+3+4)\n\n let r1 = alu(13,3, OP.div, 1)\n assert alu.div_units==3\n let r2 = alu(13,3, OP.div, 2)\n assert alu.div_units==2\n let r3 = alu(13,3, OP.div, 3)\n assert alu.div_units==1\n let r4 = alu(13,3, OP.div, 4)\n assert alu.div_units==0\n\n assert !r1? and !r2? and !r3? and !r4? // still invalid\n\n let r5 = alu(13,4, OP.mul,5)\n cassert mul.[pending_counter] == 2\n}\n
"},{"location":"pyrope/07-typesystem/","title":"Type system","text":"

Type system assign types for each variable (type synthesis) and check that each variable use/expression respects the allowed types (type check). Additionally, a language can also use the type synthesis results to implement polymorphism.

Most HDLs do not have modern type systems, but they could benefit like in other software domains. Unlike software, in the hardware, we do not need to have many integer sizes because hardware can implement any size. This simplifies the type system allowing unlimited precision integers but it needs a bitwidth inference mechanism.

Additionally, in hardware, it makes sense to have different implementations that adjust for performance/constraints like size, area, FPGA/ASIC. Type systems could help in these areas.

"},{"location":"pyrope/07-typesystem/#types-vs-cassert","title":"Types vs cassert","text":"

To understand the type check, it is useful to see an equivalent casser translation. The type system has two components: type synthesis and type check. The type check can be understood as a cassert.

After type synthesis, each variable has an associated type. Pyrope checks that for each each assignment, the left-hand side (LHS) has a compatible type with the right-hand side (RHS) of the expression. Additional type checks happen when variables have a type check explicitly set (variable:type) in the rhs expression.

Although the type system is not implemented with asserts, it is an equivalent way to understand the type system \"check\" behavior. Although it is possible to declare just the cassert for type checks, the recommendation is to use the explicit Pyrope type syntax because it is more readable and easier to optimize.

Snippet with typesSnippet with comptime assert
var b = \"hello\"\n\nvar a:u32 = 0\n\na += 1\n\na = b                       // incorrect\n\n\nvar dest:u32 = 0\n\ndest = foo:u16 + v:u8\n
var b = \"hello\"\n\nvar a:u32 = 0\n\na += 1\ncassert a does u32\na = b                       // incorrect\ncassert b does u32  // fails\n\nvar dest:u32 = 0\ncassert (dest does u32) and (foo does u16) and (v does u8)\ndest = foo:u16 + v:u8\n
"},{"location":"pyrope/07-typesystem/#building-types","title":"Building types","text":"

Each variable can be a basic type. In addition, each variable can have a set of constraints from the type system. Pyrope type system constructs to handle types:

  • var and let allows declaring types.

  • a does b: Checks 'a' is a superset or equal to 'b'. In the future, the Unicode character \"\\u02287\" could be used as an alternative to does (a \u2287 b).

  • a:b is equivalent to a does b for type check, but it is also used by type synthesis when used in the left-hand-side of assignments.

  • a equals b: Checks that a does b and b does a. Effectively checking that they have the same type. Notice that this is not like checking for logical equivalence, just type equivalence.

let t1 = (a:int=1  , b:string)\nlet t2 = (a:int=100, b:string)\nvar v1 = (a=33     , b=\"hello\")\n\nlet f1 = fun() {\n  return (a=33     , b=\"hello\")\n}\n\nassert t1    equals t2\nassert t1    equals v1\nassert f1()  equals t1\nassert _:f1 !equals t1\nassert _:t1  equals t2\n

equals and does check for types. Sometimes, the type can have a function call and you do not want to call it. The solution in this case is to use the :type to avoid the function call.

Since the puts command understands types, it can be used on any variable, and it is able to print/dump the results.

let At:int(33..) = _      // number bigger than 32\nlet Bt=(\n  ,c:string = _\n  ,d=100\n  ,setter = fun(ref self, ...args) { self.c = args }\n)\n\nvar a:At=40\nvar a2 = At(40)\ncassert a == a2\n\nvar b:Bt=\"hello\"\nvar b2 = Bt(\"hello\")\ncassert b == b2\n\nputs \"a:{} or {}\", a, at // a:40 or 33\nputs \"b:{}\", b           // b:(c=\"hello\",d=100)\n
"},{"location":"pyrope/07-typesystem/#type-equivalence","title":"Type equivalence","text":"

The does operator is the base to compare types. It follows structural typing rules. These are the detailed rules for the a does b operator depending on the a and b fields:

  • false when a and b are different basic types (boolean, fun, integer, proc, range, string, enums).

  • true when a and b have the same basic type of either boolean or string.

  • true when a and b are enum and a has all the possible enumerates fields in b with the same value.

  • a.max>=b.max and a.min<=b.min when a and b are integers. The max/min are previously constrained values in left-hand-side statements, or inferred from right-hand-side if no lhs type is specified.

  • (a@[..] & b@[..]) == b@[..] when a and b are range. This means that the a range has at least all the values in b range.

  • There are two cases for tuples. If all the tuple entries are named, a does b is true if for all the root fields in b the a.field does b.field. When either a or b have unnamed fields, for each field in b the name but also position should match. The conclusion is that if any field has no name, all the fields should match by position and/or name if available.

  • a does b is false if the explicit array size of a is smaller than the explicit array size of b. If the size check is true, the array entry type is checked. _:[]x does _:[]y is false when _:x does _:y is false.

  • The lambdas have a more complicated set of rules explained later.

assert (a:int:(max=33,min=0) does (a:int(20,5)))\nassert (a:int(0..=33)       !does (a:int(50,5)))\n\nassert  (a:string,b:int) does (a:\"hello\", b:33)\nassert ((b:int,a:string) !does (a:\"hello\", b:33)) // order maters in tuples\n\nassert  _:fun(x,xxx2)->(y,z) does _:fun(x     )->(y,z)\nassert (_:fun(x     )->(y,z) !does _:fun(x,xxx2)->(y,z))\n

For named tuples, this code shows some of the corner cases:

let t1 = (a:string, b:int)\nlet t2 = (b:int, a:string)\n\nvar a:t1  = (\"hello\", 3)     // OK\nvar a1:t1 = (3, \"hello\")     // compile error, positions do not match\nvar b:t1  = (a=\"hello\", 3)   // OK\nvar b1:t1 = (3, a=\"hello\")   // compile error, positions do not match\nvar c:t1  = (a=\"hello\", b=3) // OK\nvar c1:t1 = (b=3, a=\"hello\") // OK\n\nvar d:t2 = c                 // OK, both fully named\nassert d.0 == c.1 and c.0 == d.1\nassert d.a == c.a and d.b == c.b\n

Ignoring the value is what makes equals different from ==. As a result different functionality functions could be equals.

let a = fun() { 1 }\nlet b = fun() { 2 }\nassert a equals _:fun()    // 1 !equals :fun()\n\nassert a() != b()              // 1 != 2\nassert a() equals b()          // 1 equals 2\n\nassert _:a equals _:fun()\n
"},{"location":"pyrope/07-typesystem/#type-check-with-values","title":"Type check with values","text":"

Many programming languages have a match with structural checking. Pyrope does allows to do so, but it is also quite common to filter/match for a given value in the tuple. This is not possible with does because it ignores all the field values. Pyrope has a case that extends the does comparison and also checks that for the matching fields, the value is the same.

The previous explanation of a does b and a case b ignored types. When types are present, both need to match type.

cassert (a:u32=0, b:bool) does (a:u32, c:string=\"hello\", b=false)\ncassert (a:u32=0, c:string=\"hello\", b=false) case (a = 0, b:bool) // b is nil\n\ncassert (a:u32=0, c:string=\"hello\", b=false) !case (a:u32 = 1 , b:bool=nil )\ncassert (a:u32=0, c:string=\"hello\", b=false) !case (a:bool=nil, b:bool=nil )\ncassert (a:u32=0, c:string=\"hello\", b=false) !case (a = 0     , b     =true)\n
"},{"location":"pyrope/07-typesystem/#nominal-type-check","title":"Nominal type check","text":"

Pyrope has structural type checking, but there is a keyword is that allows to check that the type name matches a is b returns true if the type of a has the same name as the type of b. The a is b is a boolean expression like a does b, not a a:b type check. This means that it can be used in where statements or any conditional code.

a is b is equivalent to check the a variable declaration type name against the b variable declaration type name. If their declaration had no type, the inferred type name is used.

let a = 3\nlet b = 200\ncassert a is b\n\nlet c:u32 = 10\ncassert a !is c\ncassert a::[typename] == \"int\" and c::[typename] == \"u32\"\n\nlet d:u32 = nil\ncassert c is d\n\nlet e = (a:u32=1)\nlet f:(a:u32) = 33\ncassert e is f\n

Since it checks equivalence, when a is b == b is a.

let X1 = (b:u32)\nlet X2 = (b:u32)\n\nlet t1:X1 = (b=3)\nlet t2:X2 = (b=3)\nassert (b=3) !is X2  // same as (b=3) !is X2\nassert t1 equals t2\nassert t1 !is t2\n\nlet t4:X1 = (b=5)\n\nassert t4  equals t1\nassert t4  is     t1\nassert t4 !is     t2\n\nlet f2 = fun(x) where x is X1 {\n  x.b + 1\n}\n
"},{"location":"pyrope/07-typesystem/#enums-with-types","title":"Enums with types","text":"

Enumerates (enums) create a number for each entry in a set of identifiers. Pyrope also allows associating a tuple or type for each entry. Another difference from a tuple is that the enumerate values must be known at compile time.

let Rgb = (\n  ,c:u24\n  ,setter = proc(ref self, c) { self.c = c }\n)\n\nlet Color = enum(\n  ,Yellow:Rgb = 0xffff00\n  ,Red:Rgb    = 0xff0000\n  ,Green      = Rgb(0x00ff00) // alternative\n  ,Blue       = Rgb(0x0000ff)\n)\n\nvar y:Color = Color.Red\nif y == Color.Red {\n  puts \"c1:{} c2:{}\\n\", y, y.c  // prints: c1:Color.Red c2:0xff0000\n}\n

It is also possible to support an algebraic data type with enums. This requires each enumerate entry to have an associated type. In can also be seen as a union type, where the enumerate has to be either of the enum entries where each is associated to a type.

let ADT=enum(\n  ,Person:(eats:string) = _\n  ,Robot:(charges_with:string) = _\n)\n\nlet nourish = fun(x:ADT) {\n  match x {\n    == ADT.Person { puts \"eating:{}\"  , x.eats         }\n    == ADT.Robot  { puts \"charging:{}\", x.charges_with }\n  }\n}\n\ntest \"my main\" {\n  (_:Person=\"pizza\", _:Robot=\"electricity\").each(nourish)\n}\n
"},{"location":"pyrope/07-typesystem/#bitwidth","title":"Bitwidth","text":"

Integers can be constrained based on the maximum and minimum value (not by the number of bits).

Pyrope automatically infers the maximum and minimum values for each numeric variable. If a variable width can not be inferred, the compiler generates a compilation error. A compilation error is generated if the destination variable has an assigned size smaller than the operand results.

The programmer can specify the maximum number of bits, or the maximum value range. The programmer can not specify the exact number of bits because the compiler has the option to optimize the design.

In fact, internally Pyrope only tracks the max and min value. When the sbits/ubits is used, it is converted to a max/min range. Pyrope code can set or access the bitwidth attributes for each integer variable.

  • $max: the maximum number
  • $min: the minimum number
  • $sbits: the number of bits to represent the value
  • $ubits: the number of bits. The variable must be always positive or a compile error.

Internally, Pyrope has 2 sets of max/min. The constrained and the current. The constrained is set during type declaration. The current is computed based on the possible max/min value given the current path/values. The current should never exceed the constrained or a compile error is generated. Similarly, the current should be bound to a given size or a compile error is generated.

The constrained does not need to be specifed. In this case, the hardware will use whatever current value is found. This allows to write code that adjust to the needed number of integer bits.

When the attributes are read, it reads the current. it does not read the constrained.

var val:u8 = 0   // designer constraints a to be between 0 and 255\nassert val.[sbits] == 0\n\nval = 3          // val has 3 bits (0sb011 all the numbers are signed)\n\nval = 300        // compile error, '300' overflows the maximum allowed value of 'val'\n\nval = 1          // max=1,min=1 sbits=2, ubits=1\nassert val.[ubits] == 1 and val.[min]==1 and val.[max]==1 and val.[sbits]==2\n\nval::[wrap] = 0x1F0 // Drop bits from 0x1F0 to fit in constrained type\nassert val == 240 == 0xF0\n\nval = u8(0x1F0)    // same\nassert val == 0xF0\n

Pyrope leverages LiveHD bitwidth pass to compute the maximum and minimum value of each variable. For each operation, the maximum and minimum are computed. For control-flow divergences, the worst possible path is considered.

var a = 3                  // a: current(max=3,min=3) constrain()\nvar c:int(0..=10) = _      // c: current(max=0,min=0) constrain(max=10,min=0)\nif b {\n  c = a+1                  // c: current(max=4,min=4) constrain(max=10,min=0)\n}else{\n  c = a                    // c: current(max=3,min=3) constrain(max=10,min=0)\n}\n                           // c: current(max=4,min=3) constrain(max=10,min=0)\n\nvar e::[sbits = 4] = _     // e: current(max=0,min=0) constrain(max=7,min=-8)\ne = 2                      // e: current(max=2,min=2) constrain(max=7,min=-8)\nvar d = c                  // d: current(max=4,min=3) constrain()\nif d==4 {\n  d = e + 1                // d: current(max=3,min=3) constrain()\n}\nvar g:u3 = d               // g: current(max=4,min=3) constrain(max=7,min=0)\nvar h = c@[0,1]            // h: current(max=3,min=0) constrain()\n

Bitwidth uses narrowing to converge (see internals). The GCD example does not specify the input/output size, but narrowing allows it to work without typecasts. To understand, the comments show the max/min bitwidth computations.

if cmd? {\n  (x,y) = cmd   // x.max=cmd.a.max; x.min = 0 (uint) ; ....\n}elif x > y {\n                // narrowing: x.min = y.min + 1 = 1\n                // narrowing: y.max = x.min - 1\n  x = x - y     // x.max = x.max - x.min = x.max - 1\n                // x.min = x.min - y.max = 1\n}else{          // x <= y\n                // narrowing: x.max = y.min\n                // narrowing: y.min = x.min\n  y = y - x     // y.max = y.max - x.min = y.max\n                // y.min = y.min - x.max = 0\n}\n                // merging: x.max = x.max ; x.min = 0\n                // merging: y.max = y.max ; y.min = 0\n                // converged because x and y is same or smaller at beginning\n

The bitwidth pass may not converge to find a valid size even with narrowing. In this case, the programmer must insert a typecast or operation to constrain the bitwidth by typecasting. For example, this could work:

reg x = 0\nreg y = 0\nif cmd? {\n  (x,y) = cmd\n}elif x > y {\n  x = x - y\n}else{\n  y = y - x\n}\nx:cmd.a:[wrap] = x  // use cmd.a type for x, and drop bits as needed\ny = cmd.b(y)        // typecast y to cmd.b type (this can add a mux)\n

Pyrope uses signed integers for all the operations and transformations, but when the code is optimized it does not need to waste bits when the most significant bit is known to be always zero (positive numbers like u4). The verilog code generation or the synthesis netlist uses the bitwidth pass to remove the extra unnecessary bit when it is guaranteed to be zero. This effectively \"packs\" the encoding.

"},{"location":"pyrope/07-typesystem/#variants","title":"Variants","text":"

A Pyrope variant is the equivalent of an union type. A variant type spifices a set of types allowed for a given variable. In Pyrope, a variant looks like a tuple where each entry has a different type. Unlike tuples all the \"space\" or bits used are shared because the tuple can have only one entry with data at a given time.

Pyrope supports variants but not unions. The difference between typical (like C++) union and variant is that union can be used for a typecast to convert between values, the variant is the same but it does not allow bit convertion. It tracks the type from the assignment, and an error is generated if the incorrect type is accesed. Pyrope requires explicit type conversion with bitwise operations.

Variant shares syntax with enums declaration, but the usage and functionality is quite different. Enums do not allow to update values and variants are tuples with multiple labels sharing a single storage location.

The main advantage of variant is to save space. This means that the most typical use is in combination with registers or memories, when alternative types can be stored across cycles.

let e_type=enum(str:String = \"hello\",num=22)\nlet v_type=variant(str:String, num:int) // No default value in variant\n\nvar vv:v_type = (num=0x65)\ncassert vv.num == 0x64\nlet xx = vv.str                         // compile or simulation error\n

The variant variable allows to explicitly or implicitly access the subtype. Variants may not be solved at compile time, and the error will be a simulation error. A comptime directive can force a compile time-only variant.

let Vtype=variant(str:String,num:int,b:bool)\n\nlet x1a:Vtype = \"hello\"                 // implicit variant type\nlet x1b:Vtype = (str=\"hello\")           // explicit variant type\n\nvar x2:Vtype:[comptime] = \"hello\"       // comptime\n\ncassert x1a.str == \"hello\" and x1a == \"hello\"\ncassert x1b.str == \"hello\" and x1b == \"hello\"\n\nlet err1 = x1a.num                      // compile or simulation error\nlet err2 = x1b.b                        // compile or simulation error\nlet err3 = x2.num                       // compile error\n

As a reference, enums allow to compare for field but not update enum entries.

var ee = e_type\nee.str = \"new_string\"       // compile error, enum is immutable\n\nmatch ee {\n == e_type.str { }\n == e_type.num { }\n}\n
"},{"location":"pyrope/07-typesystem/#typecasting","title":"Typecasting","text":"

To convert between tuples, an explicit setter is needed unless the tuple fields names, order, and types match.

let at=(c:string,d:u32)\nlet bt=(c:string,d:u100)\n\nlet ct=(\n  ,d:u32    = _\n  ,c:string = _\n)\n// different order\nlet dt=(\n  ,d:u32    = _\n  ,c:string = _\n  ,setter = proc (ref self, x:at) { self.d = x.d ; self.c = x.c }\n)\n\nvar b:bt=(c=\"hello\", d=10000)\nvar a:at=_\n\na = b          // OK c is string, and 10000 fits in u32\n\nvar c:ct= a    // OK even different order because all names match\n\nvar d:dt = a   // OK, call intitial to type cast\n
  • To string: The format allows to convert any type/tuple to a string.
  • To integer: variable@[..] for string, range, and bool, union otherwise.
  • union allows to convert across types by specifying the size explicitly.
"},{"location":"pyrope/07-typesystem/#introspection","title":"Introspection","text":"

Introspection is possible for tuples.

a = (b=1,c:u32=2)\nvar b = a\nb.c=100\n\nassert a equals b\nassert a.size == 2\nassert a['b'] == 1\nassert a['c'] equals u32\n\nassert   a has 'c'\nassert !(a has 'foo')\n\nassert a.[id] == 'a'\nassert a.0.[id] == ':0:b' and a.b.[id] == ':0:b'\nassert a.1.[id] == ':1:c' and a.c.[id] == ':1:c'\n

Function definitions allocate a tuple, which allows to introspect the function but not to change the functionality. Functions have 3 fields inputs, outputs, where. The where is a function that always returns true if unset at declaration.

let fu = fun(a,b=2) -> (c) where a>10 { c = a + b }\nassert fu.[inp] equals ('a','b')\nassert fu.[out] equals ('c')\nassert fu.[where](a=200) and !fu.[where](a=1)\n

This means that when ignoring named vs unnamed calls, overloading behaves like this:

let x:u32 = fn(a1,a2)\n\nlet model_poly_call = fun(fn, ...args)->(out) {\n  for f in fn {\n     continue unless f.[inp] does args\n     continue unless f.[out] does out\n     return f(args) when i.[where](args)\n  }\n}\nlet x:u32 = model_poly_call(fn, a1, a2)\n

There are several uses for introspection, but for example, it is possible to build a function that returns a randomly mutated tuple.

let randomize::[debug] = fun(ref self) {\n  let rnd = import(\"prp/rnd\")\n  for i in ref self {\n    if i equals _:int {\n      i = rnd.between(i.[max],i.[min])\n    }elif i equals _:bool {\n      i = rnd.boolean()\n    }\n  }\n  self\n}\n\nlet x = (a=1,b=true,c=\"hello\")\nlet y = x.randomize\n\nassert x.a==1 and x.b==true and x.c==\"hello\"\ncover  y.a!=1\ncover  y.b!=true\nassert y.c==\"hello\"  // string is not supposed to mutate in randomize()\n
"},{"location":"pyrope/07-typesystem/#global-scope","title":"Global scope","text":"

There are no global variables or functions in Pyrope. Variable scope is restricted by code block { ... } and/or the file. Each Pyrope file is a function, but they are only visible to the same directory/project Pyrope files.

There are only two ways to access variables outside Pyrope file. The import statement allows referencing public lambdas from other files. The register declarations allow to assign an ID, and other files can access the register by \"reference\".

"},{"location":"pyrope/07-typesystem/#import","title":"import","text":"

import keyword allows to access functions not defined in the current file. Any call to a function or tuple outside requires a prior import statement.

// file: src/my_fun.prp\nlet fun1    = fun(a,b) { a+b }\nlet fun2    = fun(a) {\n  let inside = fun() { 3 }\n  a\n}\nlet another = fun(a) { a }\n\nlet mytup = (\n  ,call3 = fun() { puts \"call called\" }\n)\n
// file: src/user.prp\na = import(\"my_fun/*fun*\")\na.fun1(a=1,b=2)         // OK\na.another(a=1,2)        // compile error, 'another' is not an imported function\na.fun2.inside()         // compile error, `inside` is not in top scope variable\n\nlet fun1 = import(\"my_fun/fun1\")\nlec fun1, a.fun1\n\nx = import(\"my_fun/mytup\")\n\nx.call3()                // prints call called\n

The import points to a file setup code list of public variables or types. The setup code corresponds to the \"top\" scope in the imported file. The import statement can only be executed during the setup phase. The import allows for cyclic dependencies between files as long as there is no true cyclic dependency between variables. This means that \"false\" cyclic dependencies are allowed but not true ones.

The import behaves like cut and pasting the imported code. It is not a reference to the file, but rather a cut and paste of functionality. This means that when importing a variable, it creates a copy. If two files import the same variable, they are not referencing the same variable, but each has a separate copy.

The import is delayed until the imported variable is used in the local file. There is no order guarantee between imported files, just that the code needed to compute the used imported variables is executed before.

The import statement is a filename or path without the file extension. Directories named code, src, and lib are skipped. No need to add them in the path. import stops the search on the first hit. If no match happens, a compile error is generated.

import allows specialized libraries per subproject. For example, xx/yy/zz can use a different library version than xx/bb/cc if the library is provided by yy, or use a default one from the xx directory.

let a = import(\"prj1/file1\")\nlet b = import(\"file1\")       // import xxx_fun from file1 in the local project\nlet c = import(\"file2\")       // import the functions from local file2\nlet d = import(\"prj2/file3\")  // import the functions from project prj2 and file3\n

Many languages have a \"using\" or \"import\" or \"include\" command that includes all the imported functions/variables to the current scope. Pyrope does not allow that, but it is possible to use a mixin to add the imported functionality to a tuple.

let b = import(\"prp/Number\")\nvar a = import(\"fancy/Number_mixin\")\n\nlet Number = b ++ a // patch the default Number class\n\nvar x:Number = 3\n
"},{"location":"pyrope/07-typesystem/#register-reference","title":"Register reference","text":"

While import \"copies\" the contents, regref or Register reference allows to reference (not copy) an existing register in the call hierarchy.

The syntax of regref is similar to import but the semantics are very different. While import looks through Pyrope files, regref looks through the instantiation hierarchy for matching register names. regdef only can get a reference to a register, it can not be used to import functions or variables.

let do_increase = proc() {\n  reg counter = 0\n\n  counter:u32:[wrap] = counter + 1\n}\n\nlet do_debug = proc() {\n  let cntr = regref(\"do_increase/counter\")\n\n  puts \"The counter value is {}\", cntr\n}\n

Verilog has a more flexible semantics with the Hierarchical Reference. It also allows to go through the module hierarchy and read/write the contents of any variable. Pyrope only allows you to reference registers by unique name. Verilog hierarchical reference is not popular for 2 main reasons: (1) It is considered \"not nice\" to bypass the module interface and touch an internal variable; (2) some tools do not support it as synthesizable; (3) the evaluation order is not clear because the execution order of the modules is not defined.

Allowing only a single lambda to update registers avoids the evaluation order problem. From a low level point of view, the updates go to the register din pin, and the references read the register q pin. The register references follow the model of single writer multiple reader. This means that only a single lambda can update the register, but many lambdas can read the register. This allows to be independent on the lambda evaluation order.

The register reference uses instantiated registers. This means that if a lambda having a register is called in multiple places, only one can write, and the others are reading the update. It is useful to have configuration registers. In this case, multiple instances of the same register can have different values. As an illustrative example, a UART can have a register and the controller can set a different value for each uart base register.

// file remote.prp\n\nlet xxx = proc(some,code) {\n  reg uart_addr:u32 = _\n  assert 0x400 > uart_addr >= 0x300\n}\n\n// file local.prp\nlet setup_xx = proc() {\n  var xx = regref(\"uart_addr\") // match xxx.uart_addr if xxx is in hierarchy\n  var index = 0\n  for val in ref xx {          // ref does not allow enumerate\n    val = 0x300+index*0x10     // sets uart_addr to 0x300, 0x310, 0x320...\n    index += 1\n  }\n}\n

Maybe the best way to understand the regdef is to see the differences with the import:

  • Instantiation vs File hierarchy
  • regref finds matches across instantiated registers.
  • import traverses the file/directory hierarchy to find one matche.
  • Success vs Failure
  • regref keeps going to find all the matches, and it is possible to have a zero matches
  • import stops at the first match, and a compile error is generated if there is no match.
"},{"location":"pyrope/07-typesystem/#mocking-library","title":"Mocking library","text":"

One possible use of the register reference is to create a \"mocking\" library. A mocking library instantiates a large design but forces some subblocks to produce some results for testing. The challenge is that it needs undriven registers. During testing, the peek/poke is more flexible and it can overwrite an existing value. The peek/poke use the same reference as import or register reference.

let bpred = ( // complex predictor\n  ,let taken = fun(){ self.some_table[som_var] >=0 }\n)\n\ntest \"mocking taken branches\" {\n  poke \"bpred_file/taken\", true\n\n  var l = core.fetch.predict(0xFFF)\n}\n
"},{"location":"pyrope/07-typesystem/#operator-overloading","title":"Operator overloading","text":"

There is no operator overload in Pyrope. + always adds Numbers, ++ always concatenates a tuple or a String, and is always for boolean types,...

"},{"location":"pyrope/07-typesystem/#gettersetter-method","title":"Getter/Setter method","text":"

Pyrope tuples can use the same syntax as a lambda call or a direct assignment. Both the assignment and the lambda call follow the same rules for ambiguity as the default lambda calls. This means that fields must be named unless single character names, or variable name matches argument name, or there is no type ambiguity.

let Typ1 = (\n  ,a:string = \"none\"\n  ,b:u32    = 0\n)\n\nlet w      = Typ1(a=\"foo\", b=33)  // OK\nlet x:Typ1 = (a=\"foo\", b=33)      // OK, same as before\n\nlet v:Typ1 = Typ1(a=\"foo\", b=33)  // OK, but redundant Typ1\nlet y:Typ1 = (\"foo\", 33)          // OK, because no conflict by type\n\nvar z:Typ1 = _                    // OK, default field values\ncassert z.a == \"none\" and z.b == 0\nz = (\"foo\",33)\n\ncassert v==w==x==y==z\n

Pyrope allows a setter method to intercept assignments or construction. The same setter method is called in all the previous cases.

The setter method can use single character arguments for array index, but they must respect the declaration order.

let Typ2 = (\n  ,a:string = \"none\"\n  ,b:u32    = 0\n  ,setter = proc(ref self, a, b) { self.a = a ; self.b = b }\n)\n\nvar x:Typ2 = (a=\"x\", b=0)\nvar y:Typ2 = (a=\"x\", b=0)\n\nx[\"hello\"] = 44\ny = (\"hello\",44)\ncassert x==y\n

Tuples can be multi-dimensional, and the index can handle multiple indexes at once.

let Matrix8x8 = (\n  ,data:[8][8]u16 = _\n  ,setter = fun(ref self, x:int(0,7), y:int(0,7), v:u16) {\n    self.data[x][y] = v\n  } ++ fun(ref self, x:int(0,7), v:u16) {\n    for ent in ref data[x] {\n      ent = v\n    }\n  } ++ fun(ref self) { // default initialization\n    for ent in ref data {\n      ent = 0\n    }\n  }\n)\n\nlet m:Matrix8x8 = _\ncassert m.data[0][3] == 0\n\nm[1,2] = 100\ncassert m.data[1][2] == 100\nm[1] = 3\ncassert m.data[1][2] == 3\nm[4][5] = 33\ncassert m.data[4][5] == 33\n\nm[1] = 40\ncassert m[1] == (3,40,3,3,3,3,3,3)\n

The default getter/setter allows for indexing each of the dimentions and returns a slice of the object. Since they can be overwritten, the explicit overload selects which to pick.

let Matrix2x2 = (\n  ,data:[2][2]u16 = _\n  ,getter = fun(ref self, x:int(0,2), y:int(0,2)) {\n    self.data[x][y] + 1\n  }\n\n)\n\nlet n:Matrix2x2 = _\nn.data[0][1] = 2      // default setter\n\ncassert n[0][1] == 3  // getter does + 1\ncassert n[0] == (0,3) // compile error, no getter for fun(ref self, x)\n

The symmetric getter method is called whenever the tuple is read. Since each variable or tuple field is also a tuple, the getter/setter allow to intercept any variable/field. The same array rule applies to the getter.

let My_2_elem = (\n  ,data:[2]string = _\n  ,setter = proc(ref self, x:uint(0..<2), v:string) {\n    self.data[x] = v\n  } ++ proc(ref self, v:My_2_elem) {\n    self.data = v.data\n    } ++ proc(ref self) { // default _ assignment\n      self.data = _\n    }\n  ,getter = fun(self)         { self.data    }\n         ++ fun(self, i:uint) { self.data[i] }\n)\n\nvar v:My_2_elem = _\nvar x:My_2_elem = _\n\nv = (x=0, \"hello\")\nv[1] = \"world\"\n\ncassert v[0] == \"hello\"\ncassert v == (\"hello\", \"world\")  // not\n\nlet z = v\ncassert z !equals v   // v has v.data, z does not\n

The getter/setter can also be used to intercept and/or modify the value set/returned.

let some_obj = (\n  ,a1:string\n  ,a2 = (\n    ,_val:u32 = _                               // hidden field\n\n    ,getter=fun(self) { self._val + 100 }\n    ,setter=proc(ref self, x) { self._val = x+1 }\n  )\n  ,setter = proc(ref self, a,b){                  // setter\n    self.a1      = a\n    self.a2._val = b\n  }\n)\n\nvar x:some_obj = (\"hello\", 3)\n\nassert x.a1 == \"hello\"\nassert x.a2 == 103\nx.a2 = 5\n

The getter method can be overloaded. This allows to customize by return type:

let showcase = (\n  ,v:int = _\n  ,getter = fun(self)->(_:string) where self.i>10 {\n    format(\"this is a big {} number\", self.v)\n  } ++ fun(self)->(_:int) {\n    self.v\n  }\n)\n\nvar s:showcase = _\ns.v = 3\nlet r1:string = s // compile error, no matching getter\nlet r2:int    = s // OK\n\ns.v = 100\nlet r3:string = s // OK\ncassert r3 == \"this is a bit 100 number\"\n

Like all the lambdas, the getter method can also be overloaded on the return type. In this case, it allows building typecast per type.

let my_obj = (\n  ,val:u32 = _\n  ,getter = fun(self)->(_:string ){ string(self.val) }\n       ++ fun(self)->(_:bool){ self.val != 0    }\n       ++ fun(self)->(_:int    ){ self.val         }\n)\n
"},{"location":"pyrope/07-typesystem/#attribute-settergetter-value","title":"Attribute setter/getter value","text":"

The setter/getter can also access attributes:

var obj1::[attr1] = (\n  ,data:int = _\n  ,setter = fun(ref self, v) {\n    if v.[attr2] {\n      self.data.[attr3] = 33\n    }\n    cassert self.[attr1]\n  }\n)\n
"},{"location":"pyrope/07-typesystem/#default-setter-value","title":"Default setter value","text":"

All the variable declarations need a explicit assigned value. The _ allows to pick the default value based on the type. If the type is an integer, the _ is equivalent to a zero. If the type is a boolean, the default or _ is false. For more complicated tuple types, the setter will be called without any value.

let fint:int = _\ncassert fint == 0\n\nvar fbool:bool = _\ncassert fbool == 0\n\nlet Tup = (\n  ,v:string = _  // default to empty\n  ,setter = fun(ref self) { // no args, default setter for _\n     cassert self.v == \"\"\n     self.v = \"empty33\"\n  } ++ fun(ref self, v) {\n     self.v = v\n  }\n)\n\nvar x:Tup = _\ncassert x.v == \"empty33\"\n\nx = \"Padua\"\ncassert x.v == \"Padua\"\n\nvar y = Tup()\ncassert y.v == \"empty33\"\n\ny = \"ucsc\"\ncassert y.v == \"ucsc\"\n
"},{"location":"pyrope/07-typesystem/#arraytuple-gettersetter","title":"Array/Tuple getter/setter","text":"

Array index also use the setter or getter methods.

var my_arr = (\n  ,vector:[16]u8 = 0\n  ,getter = fun(self, idx:u4) {\n     self.vector[idx]\n  }\n  ,setter = proc(ref self, idx:u4, val:u8) {\n     self.vector[idx] = val\n  } ++ proc(ref self) {\n     // default constructor declaration\n  }\n)\n\nmy_arr[3] = 300           // calls setter\nmy_arr.3  = 300           // calls setter\ncassert my_add[3] == 300  // calls getter\ncassert my_add.3  == 300  // calls getter\n

Unlike languages like C++, the setter is only called if there is a new value assigned. This means that the index must always be in the left-hand-side of an assignment.

If the getter/setter uses a string argument, this also allows to access tuple fields.

let Point = (\n  ,priv_x:int:[private] = 0\n  ,priv_y:int:[private] = 0\n\n  ,setter = proc(ref self, x:int, y:int) {\n    self.priv_x = x\n    self.priv_y = y\n  }\n\n  ,getter = proc(self, idx:string) {\n    match idx {\n     == 'x' { self.priv_x }\n     == 'y' { self.priv_y }\n    }\n  }\n)\n\nlet p:Point = (1,2)\n\ncassert p['x'] == 1 and p['y'] == 2\ncassert p.x == 1 and p.y == 2          // compile error\n
"},{"location":"pyrope/07-typesystem/#compare-method","title":"Compare method","text":"

The comparator operations (==, !=, <=,...) need to be overloaded for most objects. Pyrope has the lt and eq methods to build all the other comparators. When non-provided the lt (Less Than) is a compile error, and the eq (Equal) compares that all the tuple fields are equal.

let t=(\n  ,v:string = _\n  ,setter = proc(ref self) { self.v = a }\n  ,lt = fun(self,other)->(_:bool){ self.v  < other.v }\n  ,eq = fun(self,other)            { self.v == other.v } // infer return\n)\n\nvar m1:t = 10\nvar m2:t = 4\nassert m1 < m2 and !(m1==m2)\nassert m1 <= m2 and m1 != m2 and m2 > m1 and m2 >= m1\n

The default tuple comparator (a == b) compares values, not types like a does b, but a compile error is created unless a equals b returns true. This means that a comparison by tuple position suffices even for named tuples.

let t1=(\n  ,long_name:string = \"foo\"\n  ,b=33\n)\nlet t2=(\n  ,b=33\n  ,long_name:string = \"foo\"\n)\nlet t3=(\n  ,33\n  ,long_name:string = \"foo\"\n)\n\ncassert t1==t2\ncassert t1 !equals t3\nlet x = t1==t3           // compile error, t1 !equals t3\n

The comparator a == b when a or b are tuples is equivalent to:

cassert (a==b) == ((a in b) and (b in a))\ncassert a equals b\n

With the eq overload, it is possible to compare named and unnamed tuples.

let t1=(\n  ,long_name:string = \"foo\"\n  ,b=33\n)\nlet t2=(\n  ,xx_a=33\n  ,yy_b = \"foo\"\n  ,eq = fun(self, o:t1) {\n    return self.xx_a == o.b and self.xx_y == o.long_name\n  } ++ fun(self, o:t2) {\n    return self.xx_a == o.xx_a and self.xx_y == o.xx_y\n  }\n)\n\ncassert t1==t2 and t2==t1\n

Since a == b can compare two different objects, it is not clear if a.eq or b.eq method is called. Pyrope has the following rule:

  • If only one of the two has a defined method, that method is called.
  • If both have defined methods, they should have the same set of eq methods or a compile error is created.

It is also possible to provide a custom ge (Greater Than). The ge is redundant with the lt and eq ((a >= b) == (a==b or b<a)) but it allows to have more efficient implemetations:

For integer operations, the Pyrope should result to the following equivalent Lgraph:

  • a == b is __eq(a,b)
  • a != b is __not(__eq(a,b))
  • a < b is __lt(a,b)
  • a < b is __lt(b,a)
  • a <= b is __lt(a,b) | __eq(a,b) (without ge) or __ge(b,a)
  • a >= b is __lt(b,a) | __eq(a,b) (without ge) or __ge(a,b)
"},{"location":"pyrope/07-typesystem/#non-pyrope-c-calls","title":"Non-Pyrope (C++) calls","text":"

Calling C++ or external code is still fully synthesizable if the code is available at compile time. An example could be calling a C++ API to read a json file during the setup phase to decide configuration parameters.

let cfg = __read_json()\n\nlet ext = if cfg.foo.bar == 3 {\n   foo\n}else{\n   bar\n}\n

Non-Pyrope calls have the same procedure/function distinction and use the same Pyrope lambda definition but they do not have the where clause.

If no type is provided, a C++ call assumes a proc(...inp)->(...out) type is can pass many inputs/outputs and has permission to mutate values. Any call to a method with two underscores __ is either a basic gate or a C++ function.

let __my_typed_cpp:fun(a,b)->(e) = _\n

Type defining non-Pyrope code is good to catch errors and also because declaring function allows to handle several cases of circular dependencies not possible with procedure import section

"},{"location":"pyrope/07b-structtype/","title":"Structural Typing","text":"

Pyrope uses structural typing somewhat simular to other languages like Typescript, but there are some difference simplifications like not references, everything is passed by value, no union types.

"},{"location":"pyrope/07b-structtype/#type-check","title":"Type check","text":"

The x does y checks that x does the same as y and maybe more. It type system syntax means that x is a subtype of y, or that y is a supertype x.

Using the typical Animal, Dog, Greyhound set of tuples, Dog does Animal and Greyhound does Dog, but not (Animal does Dog).

Dealing with tuple assignments y = x, a compile error is generated unless the type system satisfies y does x or an explicit type conversion is provided. The basic behavior of does is explained in (Type equivalance)[07-typesystem.md#Type_equivalence].

let Animal = (\n  ,legs:int = _\n  ,name= \"unnamed\"\n  ,say_name = fun() { puts name }\n)\n\nlet Dog = Animal ++ (\n  ,setter = proc(ref self) { self.legs = 4 }\n  ,bark = fun() { puts \"bark bark\" }\n)\n\nlet Bird = Animal ++ (\n  ,seeds_eaten:int = _\n\n  ,setter = proc(ref self)  { self.legs = 2 }\n      ++ proc(ref self, a:Animal)    { self.legs = 2 ; name = \"bird animal\" }\n  ,eat_seeds = proc(ref self, n) { self.seeds_eaten += n }\n)\n\nlet Greyhound = Dog ++ ( // also extends Dog\n  ,race = fun() { puts \"running fast\" }\n)\n
var a:Animal = _\nvar b:Bird = _\nvar d:Dog = _\n\nd = a // compile error, 'a does d' is false\nb = a // OK, explicit setter in Bird for Animal\n\na = d // OK, 'd does a' is true\na = b // OK, 'Bird does Animal' is true\n

When the x in x = y is an integer basic type, there is an additional check to guarantee that no precision is lost. Otherwise, an explicit wrap or drop directive must be used.

"},{"location":"pyrope/07b-structtype/#arrays","title":"Arrays","text":"

The same rules of assignments exists for arrays. In Pyrope, arrays can be mutable, but they can never be passed by reference. This means that the typical issue of mutable containers can not exists.

var a_vec:[]Animal = _\nvar b_vec:[]Bird = _\nvar d_vec:[]Dog = _\n\na_vec[0] = d:Dog    // OK\na_vec[1] = b:Bird   // OK\n\nd_vec[0] = d:Dog        // OK  'd does d'\nd_vec[0] = g:Greyhound  // OK  'g does d'\nd_vec[0] = b:Bird       // Compile error\nd_vec[0] = a:Animal     // Compile error\n\nb_vec[0] = d:Dog        // OK, explicit conversion\nb_vec[0] = g:Greyhound  // OK, explicit conversion\nb_vec[0] = b:Bird       // OK, 'b does b'\nb_vec[0] = a:Animal     // OK, explicit conversion\n\nlet do_animal_vec = fun(a_vec:[]Animal)->(r:[]Animal) {\n  r = a_vec\n  r[0] = d:Dog  // OK `d does r[0]`\n}\n\nvar x = do_animal_vec(b_vec:[]Bird) // OK\nassert x does _:[]Animal  // not :[]Bird\n
"},{"location":"pyrope/07b-structtype/#basic-types","title":"Basic types","text":"

One of the complains about structural type system is that two types with exactly the same tuple fields have the same type. In Pyrope, the field name should match. Since every element is a type of one, read/writing a named tuple of one does not need the field, and hence it allows to create different types:

let Age = (\n  ,age:int = _\n)\nlet Weight = (\n  ,weight:int = _\n)\n\nassert Age !does Weight\n\nvar a:Age = 3\nassert a == a.age == a.0 == 3\n\nvar w:Weight = 100\n\nlet err = a == w // compile error, not (a equals w) or overload\n
"},{"location":"pyrope/07b-structtype/#lambda","title":"Lambda","text":"

A way to classify a language is to look at the generics and lambda calls. Languages can have type constraints or type classes. Type classes (Hakell, Rust, Swift) specify the \"consent\" of argumetns or return types allowed for lambda or generic. Type constrains (C++, typescript, Pyrope) constraints the arguments or return types allowed. Pyrope follows a type constraint approach.

The following f method has no constraints on the input arguments. It can pass anything, but constraints the return value to be an integer.

let f = fun(a,b) -> (r:int) { r = xx(a) + xx(b) }\n

The type can be inferred for arguments and return values. If the lambda definition has no type constraints. A \"different\" implementation lambda exist for each combination of inferred types. It behaves like if the the lambda were inlined in the caller.

The constraints can be different per type, or use a more familiar generic syntax. The f1 example constraints a and b arguments to have a type that satisfies (a does Some_type_class) and (b does Some_type_class).

let f1 = fun<T:Some_type_class>(a:T,b:T) -> (r:int) { r = xx(a) + xx(b) }\n

While performing assignments checks that the left-hand-side tuple fields are fully populated (x=y) by checking that y does x. The same check happens for the lambda calls, but the check is performed when a lambda is passed as an argument.

For each lambda call (ret_val = f(a1,a2)), the type system check against the defined lambda (f = fun(ad1:ad1_t, ad2)->(rd1:rd1_t, rd2)). In this case, the check for the calling arguments ((a1,a2) does (:ad1_t, :())) should be satisfied. Notice that some of the inputs (ad2) have no defined type, so those unspecified arguments always satisfies by the type check.

The return tuple is also used in the type system (ret_val does (:rd1_t, :())), the check is the same as in an assignment (lhs does rhs). In overloading cases explained later, the return type could also be part of the overloading check.

let fa_t:fun(a:Animal)->() = _\nlet fd_t:fun(d:Dog)->() = _\n\nlet call_animal = fun(a:Animal)->() {\n   puts a.name // OK\n}\nlet call_dog:fd_t = fun(d:Dog)->() {    // OK to add type in lhs\n   d.bark()    // OK\n}\n\nlet f_a = fun(fa:fa_t) { \n  var a:Animal = _\n  var d:Dog = _\n  fa(a)  // OK\n  fa(d)  // OK, `d does Animal` is true\n}\nf_a(call_animal) // OK\nf_a(call_dog)    // compile error, `fa_t does call_dog` is false\n\nlet f_d = fun(fd:fd_t) { \n  var a:Animal = _\n  var d:Dog = _\n  fd(a)  // compile error, `a does Dog` is false\n  fd(d)  // OK\n}\nf_d(call_animal) // OK, `fd_t does call_animal` is true\nf_d(call_dog)    // OK\n

In tuple comparisons, does and ==, the tuple field position is not used when both tuples are fully named. If tuple field is unnamed, both existing names and positions should match in the comparison. For fully named tuples, when all the fields have names, (a=1,b=2) does (b=2,a=1) is true.

The same rule also applies to lambda calls. If all the arguments are named, the relative call argument position is independent. If an argument is an expression or unnamed, the position is important.

A special case is the in-place operator (...) during lambda definition. Even for fully named tuples, the position is used. One one in-place operator is allowed per lambda definition (a,b,...x,c), the does operator uses name and position like in unnamed tuples even if all the fields are named. First, it matches the position and names provided, and then checks the rest to the in-place with the relative order left.

let m = fun(a:int,...x:(_:string,c:int,d), y:int)->() { \n  assert a == 1\n  assert x.0 == \"here\"\n  assert x.1 == 2 == x.c\n  assert y == 3\n  if d does int { // inferred type\n    assert d == 33\n  }else{\n    assert d == \"x\"\n  }\n}\n\nm(1,\"here\",2,\"x\",3)         // OK\nm(a=1,\"here\",2,\"x\",3)       // OK\nm(a=1,\"here\",c=2,\"x\",3)     // OK\nm(a=1,\"here\",c=2,33,y=3)    // OK\n\nm(\"1\",\"here\",2,33,3)       // compile error, a:int\nm(\"1\",\"here\",2,3)          // compile error, x has 3 fields\n

For all the checks that are not function reference or in-place, the x does y check could be summarized as x is a superset of y. x has all the functionality of y and maybe more. In a more formal compiler nomenclature x does y applied to tuples is called a covariant relationship. It is covariant because adding the same extra fields to both x and y keeps the semantics (((foo=3,...x) does (foo=3,...y)) == x does y). This allows to extend the tuple semantics and the relationship is preserved.

When x and y are in a lambda passed as reference to another lambda (lambda reference), the relationship is not covariant but contravariant. Dog does Animal is true, but :fun(x:Dog)->() does _:fun(x:Animal)->() is false. The reason is shown in the previous example. The fun(fd:fd_t) can be called with call_animal because the fields accessed by call_animal are only a subset of Dog and hence if called inside f_d it can handle the Dog type. The opposite is not the case.

:fun(x1)->(x2) does _:fun(y1)->y2 check is equivalent to (y1 does x1) and (x2 does y2).

Given a lambda passed as argument (:fun(x:fun(c:c_t)->(d:d_t))->(y)), the check when passing the lambda as argument to x a function like fun(w:w_t)->(z:z_t). In this case, the :fun(:w_t)->(_:z_t) does fun(:c_t)->(_:d_t) is a contravariant test for inputs and covariant for outputs. This makes it equivalent to (_:c_t does _:w_t) and (_:z_t does _:d_t).

If the same type is used as input and output is an equivalence check (((a does b) and (b does a)) == (a equals b)). In programming languages this is called an invariance or bivariance.

Pyrope uses the typical check in modern languages where the function arguments are contravariant and the return type is covariant. In Pyrope, the return type is checked in the covariant and contravariant checks.

"},{"location":"pyrope/07b-structtype/#lambda-overloading","title":"Lambda overloading","text":"

Pyrope does not have global scope for defined lambdas. Instead, all the lambda must reside in a local variable or must be \"imported\". Nevertheless, a local variable can have multiple lambdas. It is similar to Odin's \"explicit procedure overloading\". This section explains how is the overloading selection in this case.

By overloading, this section refers to typical ad-hoc polymorphism where the same function/procedure name can have different functionality for different types.

For Pyrope overloading, lambdas are typically added at the end ++= of the tuple. This means that it is NOT overwriting an existing functionality, but providing a new call capability.

There is a priority of overloading in the tuple order. If the intention is to intercept, the lambda must be added at the head of the tuple entry.

let base = (\n  ,fun1 = fun() { 1 }         // catch all\n  ,fun2 = fun() { 2 }         // catch all\n  ,fun3 = fun() { 3 }         // catch all\n)\nlet ext = base ++ (\n  ,fun1 =   fun (a,b){ 4 }  // overwrite allowed with extends\n  ,fun2 ++= fun (a,b){ 5 }  // append\n  ,fun2 ++= fun ()   { 6 }  // append\n  ,fun3 =   fun(a,b) { 7 } ++ base.fun3 // prepend\n  ,fun3 =   fun()    { 8 } ++ base.fun3 // prepend\n)\n\nvar t:ext = _\n\n// t.fun1 only has ext.fun1\nassert t.fun1(a=1,b=2) == 4\nt.fun1()                 // compile error, no option without arguments\n\n// t.fun2 has base.fun2 and then ext.fun2\nassert t.fun2(1,2) == 5  // EXACT match of arguments has higher priority\nassert t.fun2() == 2     // base.fun2 catches all ahead of ext.fun2\n\n// t.fun3 has ext.fun3 and then base.fun3\nassert t.fun3(1,2) == 7  // EXACT match of arguments has higher priority\nassert t.fun3() == 8     // ext.fun3 catches all ahead of ext.fun3\n

A more traditional \"overload\" calling the is possible by calling the lambda directly:

let x = base ++ (\n  ,fun1 = fun() { return base.fun1() + 100 }\n)\n

To allow overloading the base lambda as var. By concatenating lambdas to a variable, we effectively create an unnamed tuple with multiple entries. Since all the variables are tuples of size one too, the following rules apply to any lambda call:

  • Given a lambda call f(a:a_t)->(_:r_t) with defined call and return types. Iterate and pick all the lambda definitions f(x)->(y) that satisfy x does a_t and y does r_t using the previously explained lambda checks.

  • If the r_t is unknown at call time, use only the call arguments x does a_t. Check that all the matching lambdas have the same defined return type. Otherwise a compile error is generated indicating that the type can not be infered.

  • If the list is empty, generate a compile error (no possible lambda to call).

  • Once a list of ordered modules is found, evaluate the where COND. COND can include inputs, self, and outputs. If a COND is comptime true (no COND is the same as true), stop selecting additional modules. If COND is comptime false remove from the list and continue. All the selected modules will be executed, but the output will be selected based on priority order based on the COND result at runtime.

  • If the list has more than one entry, and any of them is a proc, generate a compile error. Dynamic dispatch only works with functions fun.

If the where COND is not compile time there must be a where true condition to catch the default behavior.

The previous rules imply that Pyrope has some type of dynamic dispatch. The types for the inputs and outputs must be known at compile time (static dispatch) but the where condition may be known at run-time as long as the lambda is immutable (fun).

The where condition is not considered part of the type system, but a syntax sugar to allow several function implementations depending on some condition. The alternative and equivalent syntax is to add all the if/else chain at every call but this result in not so maintanable code.

var fun_list = fun(a,b){ a+b}\nfun_list ++= fun(a,b,c){ a+b+c }\nfun_list ++= fun(a,b,c,d){ a+b+c+d }\n\nassert fun_list.[size] == 3    // 3 lambda entries in fun_list\n\nassert fun_list(1,2) == 3\nassert fun_list(1,2,4) == 7\nassert fun_list(1,2,4,5) == 12\nassert fun_list(1,2,4,5,6) == 18 // compile error, no function with 5 args\n\n\nfun_list ++= fun(a,b){ 100}\nassert fun_list(1,2) == 3\n\nfun_list = fun(a,b){ 200} ++ fun_list\nassert fun_list(1,2) == 200\n

For untyped named argument calls:

var f1 = fun(a,b){ a+b+100 }\n  f1 ++= fun(x,y){ x+y+200 }\n\nassert f1(a=1,b=2) == 103\nassert f1(x=1,y=2) == 203\nassert f1(  1,  2) == 103  // first in list\n

For typed calls:

var fo = fun(a:int,b:string)->(_:bool)  { true    }\n  fo ++= fun(a:int,b:int   )->(_:bool)  { false   }\n  fo ++= fun(a:int,b:int   )->(_:string){ \"hello\" }\n\nlet a = fo(3,hello)\nassert a == true\n\nlet b = fo(3,300)        // first in list return bool\nassert b == false\n\nlet c:int = fo(3,300)    // compile error, no lambda fulfills constrains\nlet c:string = fo(3,300)\nassert c == \"hello\"\n

For conditional argument calls:

var f1 = fun(a,b)      where a >  40 { b+100    }\n      ++ fun(a,b)->(x) where x > 300 { b+200    } // output x\n      ++ fun(a,b)->(a) where a >  20 { b+300    } // input a\n      ++ fun(a,b)->(x) where x >  10 { b+400    } // output x\n      ++ fun(a,b)                    { a+b+1000 } // default\n\nvar fun_manual = fun(a,b){  // equivalent but not as maintenable\n  if a>40 {\n    return b+100\n  }\n  let x = b + 200\n  if x>300 {\n    return (x=x)\n  }\n  if a>20 {\n    return b+300\n  }\n  let tmp = a + b\n  if tmp >10 {\n    return (a=tmp)\n  }\n  return a+b+1000\n}\n\ntest \"check equiv\" {\n  for a in -100..=100 {\n    for b in -100..=100 {\n      assert f1(a,b) == fun_manual(a,b)\n    }\n  }\n}\n
"},{"location":"pyrope/07b-structtype/#parametric-polymorphism","title":"Parametric polymorphism","text":"

Add-hoc polymorphism overloads a function, and parametric polymorphism allows to parametrize types based on arguments.

let Param_type = fun(a) { return (xx:a = _) }\n\nlet x:Param_type(string) = (xx=\"hello\")\nlet x:Param_type(int)    = (xx=130)\n
"},{"location":"pyrope/07b-structtype/#summary-polymorphism","title":"Summary polymorphism","text":"

Subtype polymorphism: A subtype provides functionality/api for another super type.

let Animal = (\n  ,speak:fun(self) = _\n)\nlet Cat: Animal = (\n  ,speak = fun(self) { puts \"meaow\" }\n)\nlet Bird: Animal = (\n  ,speak = fun(self) { puts \"pio pio\" }\n)\n

Parametric polymorphism: Same function works for many types

let smallest = fun(...a) {\n  let x = a[0]\n  for i in a[1..] {\n    x = i when i < x\n  }\n  return x\n}\n

Ad-hoc polymorphism: capacity to overload the same lambda name with different types.

let speak = fun(a:Bird) { puts \"pio pio\"  } \n         ++ fun(a:Cat) { puts \"meaow\" }\n

Coercion polymorphism: Capacity to cast a type to another

let Type1 = (\n  ,setter = fun(ref self, a:int) {  }\n)\nlet a:Type1 = 33\n

"},{"location":"pyrope/07b-structtype/#traits-and-mixin","title":"Traits and mixin","text":"

There is no object inheritance in Pyrope, but tuples allow to build mixin and composition.

A mixin is when an object or class can add methods and the parent object can access them. In several languages, there are different constructs to build them (E.g: an include inside a class in Ruby). Since Pyrope tuples are not immutable, new methods can be added like in mixin.

let Say_mixin = (\n  ,say = fun(s) { puts s }\n)\n\nlet Say_hi_mixin = (\n  ,say_hi  = fun() {self.say(\"hi {}\", self.name) }\n  ,say_bye = fun() {self.say(\"bye {}\", self.name) }\n)\n\nlet User = (\n  ,name:string = _\n  ,setter = proc(ref self, n:string) { self.name = n }\n)\n\nlet Mixing_all = Say_mixin ++ Say_hi_mixin ++ User\n\nvar a:Mixing_all=\"Julius Caesar\"\na.say_hi()\n

Mixin is very expressive by allowing redefining methods. If two tuples have the same field a tuple, the concatenated operator (++) will create an entry with two or more sub-entries. This is likely an error with basic types but useful to handle explicit method overload.

In a way, the concatenate just adds methods from two tuples to create a new tuple. In programming languages with object-oriented programming (OOP), there are many keywords (virtual, final, override, static...) to constrain how methods can be updated/changed. In Pyrope, the let and var keywords can be added to any tuple field. The let makes the entry immutable when applied to a method, it behaves like a final keyword in most languages.

There are also two ways to concatenate tuples in Pyrope. t1 ++ t2 and (...t1, ...t2):

  • t1 ++ t2 concatenates each field in both tuples. A compile error is generated if t1 field is a let with a defined value, and t2 has also the same defined field.

  • (...t1, ...t2) inserts in-place, triggers a compile error if the same public field appears in both tuples and it is defined in both. private fields are privatized and hence do not trigger overload failure.

let Int1 = (\n  ,var counter:int:[private] = 0\n  ,add = proc(ref self, v) { self.counter += v }\n  ,get = fun(self) -> (_:int) { self.counter }\n  ,api_pending: proc(ref self, x:int) -> (o:string) = _\n)\n\nlet Int2 = (\n  ,var counter:int:[private] = 0\n  ,accumulate = proc(ref self, v) { self.counter += v ; return self.counter }\n  ,api_pending:proc(ref self, x:string) -> (o:string) = _\n)\n\nlet Combined = (...Int1, ...Int2\n  ,api_pending = proc(ref self, x:int) -> (o:string) {\n    self.add(x)\n    string(self.accumulate(self.get()))\n  }\n)\n

It is also important to notice that when one of the tuples as an entry, it can have an undefined value (nil or 0sb?). If the entry value is undefined, neither concatenate (++) or in-place insert (...) trigger a compile error. This is quite useful for defining interfaces because the default value for a function is nil.

let Interface = (\n  ,let add:fun(ref self, x) = _ // nil or undefined method\n  ,let sub = fun(ref self,x ) { self.add(-x) }\n)\n\nInterface.add(3)                // compile error, undefined method\n\nlet My_obj = (\n  ,val1:u8 = 0\n  ,let add = fun(ref self, x) { self.val += x }\n) ++ Interface                  // OK, but not recommended\n\nlet My_obj2 = (\n  ,...Interface                 // recommended\n  ,val1:u8 = 0\n  ,let add = fun(ref self, x) { self.val += x }\n)\ncassert My_obj equals My_obj2   // same behavioir no defined overlap fiels\n\nlet xx:My_obj = _               // default initialization\n\ncassert xx.val1 == 0\nxx.add(3)\ncassert xx.val1 == 3\nxx.sub(2)\ncassert xx.val1 == 1\n

Pyrope does not directly check that all the undefined methods are implemented, but this will trigger a compile error whenever the undefined method is used. This is different from most static type languages, but a bit closer to dynamically typed languages. The difference is that the check is at compile time, but an error happens ONLY if the method is used anywhere in the instantiated project.

To build tuples that implement the functionality of other tuples, the recommended technique is to use the in-place operator. It checks that there is no defined overlap between both tuples.

An issue with in-place operator is when more than one tuple has the setter method. If the tuples are concatenated with ... and error is triggered, if the tuples are concatenated with ++ it does not check if methods overlap. Neither is the expected solution for a mixin.

The solution is to remove fields from the in-place concatenation and to explicitly create the new methods with some support method.

let exclude = fun(o,...a) {\n  let new_tup = ()\n  for (key,idx,e) in zip(o.keys(),o.enumerate()) {\n    // create single tupe and append to preserve key and position order\n    let sing_tup = ()\n    sing_tup[key] = e\n    new_tup ++= sing_tup unless key in o\n  }\n  new_tup\n}\n\nlet Shape = (\n  ,name:string = _\n  ,area:fun (self )->(_:i32)  = _            // undefined \n  ,increase_size:proc(ref self, x:i12) = _  // undefined \n\n  ,setter=proc(ref self, name ) { self.name = name } // implemented, use =\n  ,say_name=fun(self) { puts \"name:{}\", name }\n)\n\nlet Circle = (\n  ,...exclude(Shape,'setter')\n\n  ,setter        = proc(ref self) { Circle.setter(this, \"circle\") }\n  ,increase_size = proc(ref self, x:i12) { self.rad *= x }\n  ,rad:i32       = _\n  ,area = fun(self) -> (_:i32) {\n     let pi = import(\"math\").pi\n     return pi * self.rad * self.rad\n  }\n):Shape  // extra check that the exclude did not remove too many fields\n
"},{"location":"pyrope/07b-structtype/#row-type","title":"Row type","text":"

Pyrope has structural typing, but also allows to infer the types. The where statement can be used to implement some functionality that resembles the row type inference. The where clause is followed by a list of comma separated conditions that must evaluate true for the function to be valid.

let rotate = fun(a) where a has 'x', a has 'y' and_then a.y!=30 {\n  var r = a\n  r.x = a.y\n  r.y = a.x\n  return r\n}\n

The previous rotate function is difficult to implement with a traditional structural typing.

"},{"location":"pyrope/08-memories/","title":"Memories","text":"

A significant effort of hardware design revolves around memories. Unlike Von Neumann models, memories must be explicitly managed. Some list of concerns when designing memories in ASIC/FPGAs:

  • Reads and Writes may have different number of cycles to take effect
  • Reset does not initialize memory contents
  • There may not be data forwarding if a read and a write happen in the same cycle
  • ASIC memories come from memory compilers that require custom setup pins and connections
  • FPGA memories tend to have their own set of constraints too
  • Logic around memories like BIST has to be added before fabrication

This constrains the language, it is difficult to have a typical vector/memory provided by the language that handles all these cases. Instead, the complex memories are managed by the Pyrope standard library.

The flow directly supports arrays/memories in two ways:

  • Async memories or arrays
  • RTL instantiation
"},{"location":"pyrope/08-memories/#async-memories-or-arrays","title":"Async memories or arrays","text":"

Asynchronous memories, async memories for short, have the same Pyrope tuple interface. The difference between tuples/arrays and async memories is that the async memories preserve the array contents across cycles. In contrast, the array contents are cleared at the end of each cycle.

In Pyrope, an async memory has one cycle to write a value and 0 cycles to read. The memory has forwarding by default, which behaves like a 0 cycle read/write. From a non-hardware programmer, the default memory looks like an array with persistence across cycles.

Pyrope async memories behave like what a \"traditional software programmer\" will expect in an array. This means that values are initialized and there is forwarding enabled. This is not what a \"traditional hardware programmer\" will expect. In languages like CHISEL there is no forwarding or initialization. In Pyrope is possible to have different options of async memories, but those should use the RTL interface.

The async memories behave like tuples/arrays but there is a small difference, the persistence of state between clock cycles. To be persistent across clock cycles, this is achieved with a reg declaration. When a variable is declared with var the contents are lost at the end of the cycle, when declared with reg the contents are preserved across cycles.

In most cases, the arrays and async memories can be inferred automatically. The maximum/minimum value on the index effectively sets the size and the default initialization is zero.

reg mem:[] = 0\nmem[3]   = something // async memory\nvar array:[] = _\narray[3] = something // array no cross cycles persistence\n
var index:u7 = _\nvar index2:u6 = _\n\narray[index] = something\nsome_result  = array[index2+3]\n

In the previous example, the compiler infers that the bundle at most has 127 entries.

There are several constructs to declare arrays or async memories:

reg mem1:[16]i8 = 3   // mem 16bit memory initialized to 3 with type i8\nreg mem2:[16]i8 = _   // mem 16bit memory initialized to 0 with type i8\nvar mem3:[] = 0sb?        // array infer size and type, 0sb? initialized\nvar mem4:[13] = 0         // array 13 entries size, initialized to zero\n

Pyrope allows slicing of bundles and hence arrays.

x1 = array[first..<last]  // from first to last, last not included\nx2 = array[first..=last]  // from first to last, last included\nx3 = array[first..+size]  // from first to first+size, first+size. not included\n

Since bundles are multi-dimensional, arrays or async memories are multi-dimensional too.

a[3][4] = 1\n\nvar b:[4][8]u8 = 13\n\nassert b[2][7] == 13\nassert b[2][10]      // compile error, '10' is out of bound access for 'b[2]'\n

It is possible to initialize the async memory with an array. The initialization of async memories happens whenever reset is set on the system. A key difference between arrays (no clock) and memories is that arrays initialization value must be comptime while memories and reg can have a sequence of statements to generate a reset value.

Pyrope array syntaxExplicit initialization
var mem1:[4][8]u5 = 0\nvar reset_value:[3][8]u5:[comptime] = _ // only used during reset\nfor i in 0..<3 {\n  for j in 0..<8 {\n    reset_value[i][j] = j\n  }\n}\nreg mem2 = reset_value   // infer async mem u5[3][8]\n
var mem = ( \n  ,(u5(0), u5(0), u5(0), u5(0), u5(0), u5(0), u5(0), u5(0))\n  ,(u5(0), u5(0), u5(0), u5(0), u5(0), u5(0), u5(0), u5(0))\n  ,(u5(0), u5(0), u5(0), u5(0), u5(0), u5(0), u5(0), u5(0))\n  ,(u5(0), u5(0), u5(0), u5(0), u5(0), u5(0), u5(0), u5(0))\n)\nreg mem2 = ( \n  ,(u5(0), u5(1), u5(2), u5(3), u5(4), u5(5), u5(6), u5(7))\n  ,(u5(0), u5(1), u5(2), u5(3), u5(4), u5(5), u5(6), u5(7))\n  ,(u5(0), u5(1), u5(2), u5(3), u5(4), u5(5), u5(6), u5(7))\n)\n
"},{"location":"pyrope/08-memories/#sync-memories","title":"Sync memories","text":"

Pyrope asynchronous memories provide the result of the read address and update their contents on the same cycle. This means that traditional SRAM arrays can not be directly used. Most SRAM arrays either flop the inputs or flop the outputs (sense amplifiers). This document calls synchronous memories the memories that either has a flop input or an output.

There are two ways in Pyrope to instantiate more traditional synchronous memories. Either use async memories with flopped inputs/outputs or do a direct RTL instantiation.

"},{"location":"pyrope/08-memories/#flop-the-inputs-or-outputs","title":"Flop the inputs or outputs","text":"

When either the inputs or the output of the asynchronous memory access is directly connected to a flop, the flow can recognize the memory as asynchronous memory. A further constrain is that only single dimension memories. Multi-dimensional memories or memories with partial updates need to use the RTL instantiation.

To illustrate the point of simple single dimensional synchronous memories, this is a typical decode stage from an in-order CPU:

Flop the inputsFlop the outputs
reg rf:[32]i64 = 0sb?   // random initialized\n\nreg a:(addr1:u5, addr2:u5) = (0,0)\n\ndata_rs1 = rf[a.addr1]\ndata_rs2 = rf[a.addr2]\n\na = (insn[8..=11], insn[0..=4])\n
var rf:[32]i64 = 0sb?\n\nreg a:(data1:i64, data2:i64) = _\n\ndata_rs1 = a.data1\ndata_rs2 = a.data2\n\na = (rf[insn[8..=11]], rf[insn[0..=4]])\n
"},{"location":"pyrope/08-memories/#rtl-instantiation","title":"RTL instantiation","text":"

There are several constraints and additional options to synchronous memories that the async memory interface can not provide: multi-dimension, partial updates, negative edge clock...

Pyrope allows for a direct call to LiveHD cells with the RTL instantiation, as such that memories can be created directly.

// A 2rd+1wr memory (RF type)\n\nmem.addr    = (raddr0, raddr1, wraddr)\nmem.bits    = 4\nmem.size    = 16\nmem.clock   = my_clock\nmem.din     = (0, 0, din0)\nmem.enable  = (1, 1, we0)\n\nmem.fwd     = false\nmem.latency = (1, 1, 1)\nmem.wensize = 1 // we bit (no write mask)\nmem.rdport  = (-1,1,0) // 0 WR, !=0 -> RD\n\nres =#[..] __memory(mem)\n\nq0 = res.0\nq1 = res.1\n

The previous code directly instantiates a memory and passes the configuration.

Multi cycle memories are pipelined elements, and using them requires the =#[..] assignment and the same rules as pipeline flops apply (See pipelining).

"},{"location":"pyrope/08-memories/#multidimensional-arrays","title":"Multidimensional arrays","text":"

Pyrope supports multi-dimensional arrays, it is possible to slice the array by dimension. The entries are in a row-major order.

var d2:[2][2] = ((1,2),(3,4))\nassert d2[0][0] == 1 and d2[0][1] == 2 and d2[1][0] == 3 and d2[1][1] == 4\n\nassert d2[0] == (1,2) and d2[1] == (2,3)\n

The for iterator goes over each entry of the bundle/array. If a matrix, it does in row-major order. This allows building a simple function to flatten multi-dimensional arrays.

let flatten = fun(...arr) {\n  var res = 0\n  for i in arr {\n    res ++= i\n  }\n  return res\n}\n\nassert flatten(d2) == (1,2,3,4)\nassert flatten((((1),2),3),4) == (1,2,3,4)\n
"},{"location":"pyrope/08-memories/#array-index","title":"Array index","text":"

Array index by default are unsigned integers, but the index can be constrained with tuples or by requiring an enumerate.

var x1:[2]u3 = (0,1)\nassert x1[0] == 0 and x1[1] == 1\n\nvar X=enum(\n  ,t1 = 0 // sequential enum, not one hot enum (explicit assign)\n  ,t2\n  ,t3\n)\n\nvar x2:[X]u3 = _\nx2[X.t1] = 0\nx2[X.t2] = 1\nx2[0]              // compile error, only enum index\n\nvar x3:[-8..<7]u3 = _  // accept signed values\n\nvar x4:[100..<132]u3 = _\n\nassert x4[100] == 0\nassert x4[3]       // compile error, out of bounds index\n
"},{"location":"pyrope/08-memories/#reset-and-initialization","title":"Reset and initialization","text":"

Like the let and var statements, reg statements require an initialization value. While let/var initialize every cycle, the reg initialization is the value to set during reset.

Like in let/var cases, the reset/initialization value can use the traditional Verilog uninitialized (0sb?) contents. The Pyrope semantics for any bit with ? value is to respect arithmetic Verilog semantics at compile time, but to randomly generate a zero/ones for each simulation. As a result assertions can fail with unknowns.

reg r_ver = 0sb?\n\nreg r = _\nvar v = _\n\nassert v == 0 and r == 0\n\nassert !(r_ver != 0)    // it will randomly fail\nassert !(r_ver == 0)    // it will randomly fail\nassert !(r_ver != 0sb?) // it will randomly fail\nassert !(r_ver == 0sb?) // it will randomly fail\n

The reset for arrays may take several cycles to take effect, this can lead to unexpected results during the reset period. Memories and registers are randomly initialized before reset during simulation. There is no guarantee of zero initialization before reset.

var arr:[] = (0,1,2,3,4,5,6,7)\n\nalways assert arr[0] == 0 and arr[7] == 7  // may FAIL during reset\n\nreg mem:[] = (0,1,2,3,4,5,6,7)\n\nalways assert mem[7] == 7                  // may FAIL during reset\nalways assert mem[7] == 7 unless mem.reset // OK\nassert mem[7] == 7                         // OK, not checked during reset\n
"},{"location":"pyrope/09-stdlib/","title":"Pyrope std lib","text":"

Like most languages, a standard library provides some common functionality around.

The standard library provides methods for the basic types (Number, String, Boolean) and utility code like fifos. The utils must be imported but the basic types are imported by default.

"},{"location":"pyrope/10-internals/","title":"Internals","text":"

This section of the document provides a series of disconnected topics about the compiler internals that affects semantics.

"},{"location":"pyrope/10-internals/#tuple-operations","title":"Tuple operations","text":"

There are 3 basic operations/checks with tuples that affect many other operations: a in b, a does b, and lambda call rules.

  • a in b allows to work when b is a name/unnamed tuple even when a is named.

  • a does b requires b to be named consistent with names in a.

  • lambda call matches the arguments with the definition in a third different set of rules.

cassert (a=1) in (1,a=1,3)\ncassert (a=1) !does (1,a=1,3)\n\nlet f = fun(a) { puts \"{}\",a }\nlet g = fun(long, short) { puts \"{}\",long }\n\nf(a=1)             // OK\nf(1)               // OK\n\ng(long=1, short=1) // OK\ng(1,1)             // compile error\nlet long=1\ng(long, short=1)   // OK\nlet short=1\ng(long, short)     // OK\n

Operators like a == b, a case b, a equals b, ... built on top of the previous functionality.

"},{"location":"pyrope/10-internals/#determinism","title":"Determinism","text":"

Pyrope is designed to be deterministic. This means that the result is always the same for synthesis. Simulation is also deterministic unless the random seed is changed or non-Pyrope (C++) calls to procedures add non-determinism.

Expressions are deterministic because procedures have an explicit order in Pyrope. Only functions have a non-explicit order, but functions are pure without side-effects. puts can be called non-deterministically but the result is buffered and ordered at the end of the cycle to be deterministic.

The only source of non-determinism is non-Pyrope (C++) calls from procedures executed at different pipeline stages. The pipeline stages could be executed in any order, it is just that the same order must be repeated deterministically during simulation. The non-Pyrope calls must be ::[comptime] to affect synthesis. So the synthesis is deterministic, but the testing like cosimulation may not.

The same non-Pyrope calls also represent a problem for the compiler optimizations. During the setup phase, several non-Pyrope can exist like reading the configuration file. If the non-Pyrope calls are not deterministic, the result could be a non-deterministic setup phase.

The idea is that the non-Pyrope API is also divided in 2 categories: functions and procedures. A function can be called many times without non-Pyrope side-effects. Pyrope guarantees that the procedures are called in the same order given a source code, but does not guarantee the call order. This guarantee order slowdowns simulation and elaboration. Whenever possible, use functions instead of procedures for compilation speed reasons.

"},{"location":"pyrope/10-internals/#import","title":"Import","text":"

import statement allows for circular dependencies of files, but not of variables. This means that if there is no dependency (a imports b), just running a before b is enough. If there is a dependency (a imports b and b imports a) a multiple compiler pass is proposed, but other solutions are allowed as long as it can handle not true circular dependences.

The solution to this problem is to pick an order, and import at least three times the files involved in the cyclic dependency. The files involved in the cylic dependency are alphabetically sorted and called three times: (1) a import b, then b import a; (2) a import b and b import a; (3) a import b and b import a. Only the last import chain can perform procedure proc calls (Pyrope and non-Pyrope) and puts/debug statements.

If the result of the last two imports has the same variables, the import has \"converged\", otherwise a compile error is generated. This multi-pass solution does not address all the false paths, but the common case of having two sets of independent variables. This should address most of the Pyrope cases because there is no concept of \"reference/pointer\" which is a common source of dependences.

"},{"location":"pyrope/10-internals/#register-reference","title":"Register reference","text":"

Register reference (regfef) can create a dependence update between files, but this is not a source of non-determinism because only one file can perform updates for the register din pin, and all the updated register can only read the register q pin.

"},{"location":"pyrope/10-internals/#dealing-with-unknowns","title":"Dealing with unknowns","text":"

Pyrope tries to be compatible with synthesizable Verilog but not equivalent. As such it must handle/understand unknowns. Compatible does not mean that it will generate the same ? bits as Verilog, but that it will not generate an unknown when Verilog has known. It is allowed to generate a 0 or a 1 when the Verilog logical equivalence check generates an ?.

An example of different behavior is that Verilog semantics state 0 * 0sb? is 0sb? while most programmers would expect a zero.

The previous definition of compatibility could allow the Pyrope compiler to randomly replace all the unknowns by 0 or 1 when doing internal compiler passes. This is not done at compile time to keep determinism, but simulation time should randomly pick 0/1 for unknown bits.

The issue is that the most likely source of having unknowns in operations is either during reset or due to a bug on how to handle non initialized structures like memories.

The compiler internal transformations use a 3-state logic that includes 0, 1, and ? for each bit. Any register or memory initialized with unknowns will generate a Verilog with the same initialization.

The compiler internals only needs to deal with unknowns during the copy propagation or peephole optimizations. The compile goes through 2 phases: LNAST and Lgraph.

In the compiler passes, we have the following semantics:

  • In Pyrope, there are 3 array-like structures: non-persistent arrays, register arrays, and custom RTL memories. Verilog and CHISEL memories get translated to custom RTL memories. Non-persistent Verilog/CHISEL get translated to arrays. In Verilog, the semantics is that an out of bounds access generates unknowns. In CHISEL, the Vec is that an out of bound access uses the first index of the array. A CHISEL out of bound memory is an unknown like in Verilog. These are the semantics applied by the compiler optimization/transformations:

    • Custom RTL memories do not allow value propagation across the array, only across non-persistent arrays, or register arrays explicitly marked with retime=true.

    • An out of bound RTL address drops the unused index bits. For non-power of two arrays, out of bounds access triggers a compile error. The code must be fixed to avoid access. An if addr < mem_size { ... mem[addr] ... } tends to be enough. This is to guarantee that passes like Verilog and CHISEL have the same semantics, and trigger likely bugs in Pyrope code.

    • An index with unknowns does not perform value propagation.

  • Shifts, additions and substractions propagate unknowns at computation. E.g: 0b11?0 + 0b1 is 0b11?1, 0b1?0 >> 1 is 0b1?.

  • Other arithmetic are more conservative. When an input is unknown, the result is unknown only respecting the sign when possible. E.g: 0b1?0? * -1 is 0sb1?.

  • Logic operations behave like Verilog. 0b000111??? | 0b01?01?01? is 0b01?111?1?.

  • Equality comparisons (== and !=) use unknowns, this means that at compile time 0b1? != 0b10. Comparisons is consistent with the equivalent logic operations a == b is the same as (a ^ b) == -1.

  • Other comparisons (<=, <, >, >=) return true if the comparison is true for each possible unknown bit.

  • match statement and unique if will trigger a compile error if the unknown semantics during compiler passes can trigger 2 options simultaneously. The solution is to change to a sequence of ifs or change the code to guarantee no unknowns.

  • if statement without unique logical expressions that have an unknown (single bit) are a source of confusion. In Verilog, it depends on the compiler options. A classic compiler will generate ? in all the updated variables. A Tmerge option will propagate ? only if both sides can generate a different value. The LNAST optimization pass will behave like the Tmerge when the if/mux control has unknowns:

    • If all the paths have the same constant value, the if is useless and the correct value will be used.

    • If any path has a different constant value, the generated result bits will have unknowns if the source bits are different or unknown.

    • If any paths are not constant, there is no LNAST optimization. Further Lgraph optimizations could optimize if all the mux generated values are proved to be the same.

  • The for loops are expanded, if the expression in the for is unknown, a compile error is generated.

  • The while loops are also expanded, if the condition on the while loop has unknowns a compile error is generated.

At the end of the LNAST generation, a Lgraph is created. Only the registers and memory initialization are allowed to have unknowns in Lgraph. Any invalid (nil) assigned to an output or register triggers a compile error. Any unknown constant bit is translated preserved (0b10?).

The semantics on the generated simulator are similar to CHISEL, any unknowns are randomly translated to 0 or 1 at initialization.

"},{"location":"pyrope/10-internals/#optimize-directive","title":"Optimize directive","text":"

The optimize directive is like an assert but it also allows compiler optimizations. In a way, it is a safer version of Verilog ?. Unlike other languages like C++23, Pyrope optimize verifies at simulation time that the optimize is correct. This means that the optimize is checked like an assert but it allows the compiler to optimize based on the condition. asserts do not trigger optimizations because their check can be disabled at simulation time, and hence create mismatches between simulation and synthesis if the compiler optimized over assertions.

Verilog x-optimizationPyrope matchGenerated Logic 1 bit f
always_comb begin // one hot mux\ncase (sel)\n3\u2019b001 : f=i0;\n3\u2019b010 : f=i1;\n3\u2019b100 : f=i2;\ndefault: f=2\u2019b??;\nendcase\nend\n
optimize sel==1 or sel==2 or sel==4 // not needed. match sets it\nmatch sel {\n  == 0b001 { f = i0 }\n  == 0b010 { f = i2 }\n  == 0b100 { f = i3 }\n}\n
f = (sel[0] & i0)\n  | (sel[1] & i1)\n  | (sel[2] & i2)\n

Optimize allows more freedom, without dangerous Verilog x-optimizations:

Bad Verilog x-optimizationPyrope optimize
if (a == 0) begin\nassert(false);\nout = '?;\nend else if (1 + a) == 1 begin // always false\nout = 1;\nend else begin\nout = 3;\nend\n\narray[3] = '?; // entry 3 will not be used\n// array = (1,2,3,'?,5,6,7,8)\nres = array[b]\n
optimize a != 0\n\n\nif (1 + a) != 1 { // always false\n  out = 1\n}else{\n  out = 3\n}\n\noptimize b != 3\n// array = (1,2,3,4,5,6,7,8)\nres = array[b]\n
"},{"location":"pyrope/10-internals/#unknown-no-optimization","title":"Unknown no optimization","text":"

In Verilog, unknowns can trigger synthesis optimizations. This is not the case in Pyrope. Each unknown bit (?) can result in random 0/1 at simulation time, but it will not trigger optimizations. The optimize statement should be use for such behavior.

assert cond==3     // Not cassert or optimize, so no optimized\nvar x1 = 0sb?\n\nif cond == 3 {\n  x1 = 1\n}\nassert x1==1 // still not optimized (cassert fails)\ncassert !x1.[comptime]\n\nvar x2 = 0sb?\noptimize cond==3\nif cond == 3 {\n  x2 = 1\n}\ncassert x2==1\ncassert x2.[comptime]\n
"},{"location":"pyrope/10-internals/#lnast-optimization","title":"LNAST optimization","text":"

The compiler has three IR levels: The high level is the parse AST, the mid-level is the LNAST, and the low level is the Lgraph. This section explains the main steps in the LNAST optimizations/transformations before performing type synthesis and generating the lower level Lgraph. This is a minimum of optimizations without them several type conflicts would be affected.

Unlike the parse AST, the LNAST nodes are guaranteed to be in topological order. This means that a single pass that visits the children first (deep first) is sufficient.

The work can be performed as a single \"global\" topographical pass starting from the root/top, where each LNAST node performs these operations during traversal depending on the LNAST node:

  • If the node allows, perform these node input optimization first:

    • constant folding for existing node, also be performed as instruction combining proceeds

    • instruction combining from sources only for same type but not beyond 128 n-ary nodes. This step subsumes constant propagation and copy propagation. E.g: a+(x-3)+1 becomes a+x-3+1

    • create a canonical order by sorting the inputs by name/constant. E.g: + 2 a b. This simplifies the following steps but it is not needed for semantics. Most commutative gates (add/sub/and/or/...) will have a single constant as a result.

    • trivial simplification with constants for existing node, also performed as instruction combining proceeds. E.g.: a+0 == a, a or true == true ...

    • trivial identity simplification for existing node, also performed as instruction combining proceeds. E.g: a^a == a, a-a=0 ...

  • If the node is a ::[comptime] trigger a compile error unless all the inputs are constant

    • cassert should satisfy the condition or a compile error is generated
  • If the node is a loop (for/while) that has at least one iteration expand the loop. This is an iterative process because the loop exit condition may depend on the loop body or functions called inside. After the loop expansions, no for, while, break, last, continue statement exists.

  • If the node is a function call, iterate over the possible polymorphic calls. Call the first call that is valid (input types). Call the function and pass all the input constants needed. This requires specializing the function by input constants and types. If no call matches a valid type trigger a compile error

  • Delete unreachable statements (if false { delete his }, delete this when false, ...)

  • Compute these steps that may be needed in future steps:

    • Perform the \"Mark\" phase typical in dead-code-elimination (DCE) so that dead nodes are not generated when creating the Lgraph.

    • Update the tuple field in the Symbol Table

    • Track the array accesses for memory/array Lgraph generation

"},{"location":"pyrope/10-internals/#type-synthesis","title":"Type synthesis","text":"

The type synthesis and check are performed during the LNAST pass. Pyrope uses a structural type system with global type inference.

The type inference should be performed as the same time as the LNAST optimization traverses the tree. It can not be a separate pass because there can be interactions between the LNAST optimization and the Type synthesis. These are the additional checks performed for type synthesis:

  • If the node does type checks (equals, does) compute the outcome and perform copy propagation. The result of this step is that the compiler is effectively doing flow-type inference. All the types must be resolved before. If the equals/does was in a if condition, the control is decided at compile time.

  • If the node reads bitwidth, replace the node with the computer Bitwidth value (max, min, ubits, and/or sbits)

    • Compute the max/min for the output[s] using the bitwidth algorithm. Update the symbol table with the range. This is only needed because some code like polymorphism functions can read the bits.
  • If the node is a conditional (if/match), the pass performs narrowing1.

    • When the expression has these possible syntax v >= y, v > y or the reciprocals, restrict the Bitwidth. E.g: in the v < y restricts the v.max = y.min-1 ; y.min = v.min + 1

    • When the expression is an equality format eq [and eq]* or eq [or eq]* like v1 == z1 and v2 != z2, create a v1=z1 and v2=z2 in the corresponding path. This will help bitwidth and copy propagation. Complicated mixes of and/or have no path optimization

    • When the expression is a single variable a or !a, set the variable true and false in both paths

No previous transformation could break the type checks. This means that the copy propagation, and final lgraph translation the type checks are respected.

  • All the entries on the comparator have the same type (LHS equals RHS)

  • Left side assignments respect the assigned type (LHS does RHS)

  • Any explicit type on any expression should respect the type (var does type)

The previous algorithm describes the semantics, the implementation may be different. For example, to parallelize the algorithm, each LNAST tree can be processed locally, and then a global top pass is performed.

"},{"location":"pyrope/10-internals/#programming-warts","title":"Programming warts","text":"

In programming languages, warts are small code fragments that have unexpected or not great behavior. Every language has its warts. This section tries to list the Pyrope main ones to address and learn more about the language.

"},{"location":"pyrope/10-internals/#shadowing","title":"Shadowing","text":"

Pyrope does not allow shadowing, but you can still have it with tuples. To access the tuple field, the self.field is always required. This avoid the problem of true shadowing.

let f1 = fun() { 1 }\n\nlet tup = (\n  ,f1 = fun() { 2 }\n\n  ,code = fun() {\n     assert self.f1() == 2\n     assert f1() == 1\n  }\n)\n
"},{"location":"pyrope/10-internals/#closures","title":"Closures","text":"

Closures capture extra state or inputs at definition. The capture variables are always immutable let no matter the outter scope definition. Therefore, capture variables behave like passed by value, not reference.

One important thing is 'when' does the capture happens. Pyrope follows the model of most languages like C++ that captures at lambda definition, not lambda execution.

Pyrope capture timeC++17 capture time
var x_s = 10\n\nlet call_captured = fun[x_s]() {\n  return fun[x_s]() {\n    assert x_s == 10\n    return x_s\n  }\n}\n\ntest \"capture test\" {\n  let tst = fun() {\n    var x_s = 20   // not variable shadowing because fun scope\n\n    let x1 = call_captured()\n    assert x1 == 10\n\n    x_s = 30;\n\n    let x2 = call_captured()\n    assert x2 == 10\n  }\n  tst // call the test\n}\n
#include <iostream>\n\nint main() {\n\nint x_s{ 10 };\n\nauto call_captured{\n[x_s]() {\nassert(x_s == 10);\nreturn x_s;\n}\n};\n}\n\nx_s = 20;\n\nauto x1 = call_captured();\nassert(x1==10);\n\nx_s = 30;\n\nauto x2 = call_captured();\nassert(x2==10);\n}\n

Some languages like ZIG do not allow closures, but they allow structs with a lambda to implement an equivalent functionality. It is possible in Pyrope to also create a tuple and populate the getter. This effectively behaves as the closures. Internally, Pyrope may do this implementation.

Pyrope tuple closure styleZIG closure style with struct
let j = 1\nlet b = fun[j](x:i32)-> :i32 {\n  return x+j\n}\n\nassert b(1) == 2\n\ntest \"closure with tuple\" {\n  var a: i32 = 1\n  a += 1\n\n  var addX = (\n    ,a: i32 = a                        // copy value, runtime or comptime\n    ,getter = fun(self, x: i32) {\n      return x + self.a\n    }\n  )\n\n  a += 100;\n\n  assert addX(2) == 4\n}\n\ntest \"plain closure\" {\n  var a:i32 = 1\n  a += 1\n\n  let addX = fun[a](x: i32) { // Same behaviour as closure with tuple\n    return x + a\n  }\n\n  a += 100;\n\n  assert addX(2) == 4\n}\n
pub fn main() void {\nconst j = 1;\nvar b = struct{\nfn function(x: i32) i32 {\nreturn x+j;\n}\n}.function;\n\n@import(\"std\").debug.assert(b(1) == 2);\n}\n\ntest \"closure with runtime\" {\nvar a: i32 = 1;\na += 1;\n\nconst addX = (struct {\na: i32,\nfn call(self: @This(), x: i32) i32 {\nreturn x + self.a;\n}\n} { .a = a }).call;\n\na += 100;\n\n@import(\"std\").debug.assert(addX(2) == 4);\n}\n

Capture values must be explicit, or no capture happens. This means that ...fun[](...)... is the same as ...fun(...)....

var x = 3\n\nlet f1 = fun[x]()->(_:int){\n   assert x == 3\n   var x = _    // compile error. Shadow captured x\n   return 200\n}\nlet f2 = fun()->(_:int){\n   var x = _    // OK, no captures 'x' variable\n   x = 100\n   return x\n}\n

Capture variables pass the value at capture time:

var x = 3\nvar y = 10\n\nlet fun2 = fun[y]()->(_:int){\n  y = 100              // compile error, y is immutable when captured\n  var x  = 200\n  return y + x\n}\nx = 1000\nassert fun2() == 203\n
"},{"location":"pyrope/10-internals/#lambda-arguments","title":"Lambda arguments","text":"

Lambda calls happen whenever an identifer is followed by a list of expressions. If the first expression in the list has parenthesis, it can lead to unexpected behavior:

assert 0 == (0)  // OK, same as assert( 0 == (0) )\nassert (0) == 0  // compile error: (assert(0)) == 0 is an expression\nassert(0 == 0)   // OK\n

It is also easy to forget that parenthesis can be ommited in simple expressions, not when ranges or tuples are involed.

asssert 2 in (1,2)  // compile error, not allowed to drop parenthesis\nasssert(2 in (1,2)) // OK\n
"},{"location":"pyrope/10-internals/#multiple-tuples","title":"Multiple tuples","text":"

The evaluation order is always the same program order starting from the top module. Remember that the setter method is the constructor called even when there is no initial value set.

let X_t = (\n  ,i1 = (\n    ,i1_field:u32 = 1\n    ,i2_field:u32 = 2\n    ,setter = proc(ref self, a) {\n       self.i1_field = a\n    }\n  )\n  ,i2 = (\n    ,i1_field:i32 = 11\n    ,setter = proc(ref self, a) {\n       self.i1_field = a\n    }\n  )\n)\n\nvar top = (\n  ,setter = proc(ref self) {\n    var x:X_t = _\n    assert x.i1.i1_field == 1\n    assert x.i1.i2_field == 2\n    assert x.i2.i1_field == 11\n\n    x.i1 = 400\n\n    assert x.i1.i1_field == 400\n    assert x.i1.i2_field == 2\n    assert x.i2.i1_field == 11\n\n    x.i2 = 1000\n\n    assert x.i1.i1_field == 400\n    assert x.i1.i2_field == 2\n    assert x.i2.i1_field == 1000\n  }\n)\n

If a lambda in the hierarchy does not have a setter/constructor, the program order follows the tuple scope which is in tuple ordered asignment.

"},{"location":"pyrope/10-internals/#unknowns","title":"Unknowns","text":"

Pyrope respects the same semantics as Verilog with unknowns. As such, there can be many unexpected behaviors in these cases. The difference is that in Pyrope everything is initialized and unknowns (0sb?) can happen only when explicitly enabled.

The compare respects Verilog semantics. This means that it is true if and only if all the possible values are true, which is quite counter-intuitive behavior for programmers not used to 4 value logic.

assert !(0sb? == 0)\nassert !(0sb? != 0)\nassert !(0sb? == 0sb?)\nassert !(0sb? != 0sb?)\n

There is no way to know at run-time if a value is unknown, but a compile trick can work. The reason is that integers can be converted to strings in a C++ API

var x = 0sb10?\nlet str = __to_string(x) // only works for compile time constants\nassert x == \"0sb10?\"\n
"},{"location":"pyrope/10-internals/#for-loop","title":"for loop","text":"

The for expects a tuple, and iterates over the tuple. This can lead to some unexpected behaviour. The most strange is that ranges are always from smallest to largest. It is not legal to do a 5..<0 range, the solution is to use a to which creates a tuple not a range.

let s:string=\"hell\"\nfor (idx,i) in s.enumerate() {\n  let v = match idx {\n   == 0 { \"h\" }\n   == 1 { \"e\" }\n   == 2 { \"l\" }\n   == 3 { \"l\" }\n  }\n  assert v == i\n}\n\nlet t = (1,2,3)\nfor (idx,i) in t.enumerate() {\n  let v = match idx {\n   == 0 { 1 }\n   == 1 { 2 }\n   == 2 { 3 }\n  }\n  assert v == i\n}\n\nlet r=2..<5\nfor (idx,i) in r.enumerate() {\n  let v = match idx {\n   == 0 { 2 }\n   == 1 { 3 }\n   == 2 { 4 }\n  }\n  assert v == i\n}\n\nlet r2=4..=2 step -1\nassert r2 == (4,3,2)\nfor (idx,i) in r2.enumerate() {\n  let v = match idx {\n   == 0 { 4 }\n   == 1 { 3 }\n   == 2 { 2 }\n  }\n  assert v == r2[i]\n}\n\nfor i in 2..<5 {\n  let ri = 2+(4-i) // reverse index\n  // 2 == (2..<5).trailing_one\n  // 4 == (2..<5).leading_one\n  let v = match idx {\n   == 0 { 4 }\n   == 1 { 3 }\n   == 2 { 2 }\n  }\n  assert v == ri\n}\n\nfor (idx,i) in enumerate(123) {\n  assert i == 123 and idx==0\n}\n
"},{"location":"pyrope/10-internals/#multiple-bit-selection","title":"Multiple bit selection","text":"

Ranges are sets, this creates potentially unexpected results in reverse for iterators, but also in bit section:

let v = 0xF0\n\nassert v@[0] == 0\nassert v@[4] == 1       // unsigned output\nassert v@sext[4] == -1  // signed output\n\nassert v@[3..=4] == 0b010 == v@[3,4]\nassert v@[4..=3 step -1] == 0b010\nassert v@[4,3] == v@[3,4] == 0b010\n\nlet tmp1 = (v@[4], v@[3])@[..]  // typecast from\nlet tmp2 = (v@[3], v@[4])@[..]\nlet tmp3 = v@[3,4]\nassert tmp1 == 0b01\nassert tmp2 == 0b100\nassert tmp3 == 0b10\n\nlet tmp1s = (v@sext[4], v@sext[3])@[..]  // typecast from\nlet tmp2s = (v@sext[3], v@sext[4])@[..]\nlet tmp3s = v@[4,3]\nassert tmp1s == 0b01\nassert tmp2s == 0b10\nassert tmp3s == 0b10\n\nlet tmp1ss = (v@sext[4], v@sext[3])@sext[..]  // typecast from\nlet tmp2ss = (v@sext[3], v@sext[4])@sext[..]\nlet tmp3ss = v@sext[3,4]\nassert tmp1ss == 0b01  ==  1\nassert tmp2ss == 0sb10 == -2\nassert tmp3ss == 0sb10 == -2 == v@sext[4,3]\n

The reason is that for multiple bit selection assumes a smaller to larger bits. If the opposite order is needed, support functions/code must explicitly do it.

In Pyrope, there is no order in bit selection (xx@[0,1,2,3] == xx@[3,2,1,0]). This is done to avoid mistakes. If a bit swap is wanted, it must be explicit.

let reverse = fun(x:uint)->(total:uint) {\n  for i in 0..<x.__bits {\n    total <<= 1\n    total  |= x@[i]\n  }\n}\nassert reverse(0b10110) == 0b01101\n
"},{"location":"pyrope/10-internals/#unexpected-calls","title":"Unexpected calls","text":"

Passing a lambda argument with a ref does not have any side effect because lambdas without arguments need to be explicitly called or just passed as reference.

let args = fun(x) { puts \"args:{}\", b ; 1}\nlet here = fun()  { puts \"here\" ; 3}\n\nlet call_now   = fun(f:fun){ return f() }\nlet call_defer = fun(f:fun){ return f   }\n\nlet x0 = call_now(here)          // prints \"here\"\nlet e1 = call_now(args)          // compile error, args needs arguments\nlet x1 = call_defer(here)        // nothing printed\nlet e2 = call_defer(args)        // compile error, args needs arguments\nassert x0  == 3                  // nothing printed\nassert x1  == 3                  // nothing printed\n\nlet x2 = call_now(ref here)      // prints \"here\"\nlet e3 = call_now(ref args)      // compile error, args needs arguments\nlet x3 = call_defer(ref here)    // nothing printed\nlet x4 = call_defer(ref args)    // nothing printed\nassert x2  == 3                  // nothing printed\nassert x3()  == 3                // prints \"here\"\nassert x3  == 3                  // compile error, explicit call needed\nassert x4  == 1                  // compile error, args needs arguments\nassert x4(\"xx\") == 1             // prints \"args:xx\"\n
"},{"location":"pyrope/10-internals/#if-is-an-expression","title":"if is an expression","text":"

Since if, for, match are expressions, you can build some strange code:

if if x == 3 { true }else{ false } {\n  puts \"x is 3\"\n}\n
"},{"location":"pyrope/10-internals/#legal-but-weird","title":"Legal but weird","text":"

There is no -- operator in Pyrope, but there is a - which can be followed by a negative number -3.

let v = (3)--3\nassert v == 6\n
  1. Narrowing is based on \"ABCD: eliminating array bounds checks on-demand\" by Ras Bodik et al.\u00a0\u21a9

"},{"location":"pyrope/10b-vslang/","title":"vs Other Languages","text":"

This section provides some snippet examples to understand the differences between Pyrope and a different set of languages.

"},{"location":"pyrope/10b-vslang/#generic-non-hdl","title":"Generic non-HDL","text":"

Pyrope is an HDL that tries to look like a non-HDL with modern/concise syntax. Some of the Pyrope semantics are simpler than most non-HDL because of several features like unlimited precision, lack of pointers and issues to manage memory do not exist in ASICs/FPGAs. These are explained in simpler HDL constructs section.

There are some features in Pyrope that are non-existing in non-HDLs. ASICs/FPGAs design leverage some features like reset, pipelining, connecting modules that require syntax/semantics not needed in languages like Rust, C, Java. This section lists the main hardware specific syntax.

"},{"location":"pyrope/10b-vslang/#reset-vs-cycle","title":"reset vs cycle","text":"

Nearly all the programming languages have a \"main\" that starts execution. From the entry point, a precise control flow is followed until an \"exit\" is found. If there is no exit, the control flow eventually returns to the end of main and an implicit exit exist when \"main\" finishes. There is no concept of cycle or reset.

Pyrope tries to imitate non-HDLs and it has the same entry point \"top\" and also follows a precise control flow from that entry point. This is what a non-hardware designer will expect, but there is no exit/abort. The control flow will continue until it returns to the end of the \"top\" or entry point.

The key difference is that the \"top\" or entry point is called every cycle. From a hardware point of view, the whole program executes in a single clock cycle. All the program state is lost unless preserved in register variables.

Those registers variables have an \"initialization\" step that in hardware corresponds to a reset phase. Each register declaration assignment has reset code only executed during reset.

"},{"location":"pyrope/10b-vslang/#defer","title":"Defer","text":"

Some programming languages like Zig or Odin have a defer statement. In non-HDLs, a defer means that the statements inside the defer are executed when the \"scope\" finishes. Usually, the defer statements are executed before the function return.

Pyrope defers the statements not to the end of the scope but to the end of the clock cycle. The defer delays the \"write\" until the end of the clock cycle, the defer does not defer the reads, just the write or update. To read the value from the end of the cycle an attribute variable.[defer] must be used.

These are constructs not existing in software but needed in hardware because it is necessary to connect blocks. Following the control flow from the top only allows to connect forward. Some contructs like connecting a ring require a \"backward edge\". The attribute [defer] allow such type of constructs.

var a = 1\nvar b = 2\n\ncassert a==1 and b==2\nb::[defer] = a\ncassert a==1 and b==2\n\ncassert b.[defer] == 1\n
"},{"location":"pyrope/10b-vslang/#pipelining","title":"Pipelining","text":"

Pyrope should be easier to program than non-HDLs with the exception of dealing with cycles. While memory management tends to be the main complexity in non-HDLs, pipelining or dealing with interaction across cycles is the main complexity in HDLs.

Pyrope has several constructs to help that do not apply to non-HDL, pipelining has most of the pipelining specific syntax.

"},{"location":"pyrope/10b-vslang/#c","title":"C++","text":"

Pyrope and C++ are quite different in syntax, but some nice C++23 syntax has similarities for Pyrope.

auto max_gap_count(std::vector<int> nums) {\nstd::ranges::sort(nums, std::greater{});\nauto const diffs = nums\n| std::views::adjacent_transform<2>(std::minus{});\nreturn std::ranges::count(diffs, std::ranges::max(diffs));\n}\n
let max_gap_count = fun(nums) {\n  let max  = import(\"std\").max\n  let sort = import(\"std\").sort\n  let adjacent_transform = fun(a,num,f) {\n    var res:[] = _\n    for i in 0..<a.length step num {\n      res ++= f(a[i..+num])\n    }\n    return res\n  }\n  let count = fun(a,b) {\n    var r = 0\n    for i in a {\n      r += 1 when i == b\n    }\n    return r\n  }\n\n  return numbers\n     |> sort(fun(a,b) { a<b })\n     |> adjacent_transform(num=2, fun(a,b) { a-b } )\n     |> fun(a) { count(a, a.max) }\n}\n
"},{"location":"pyrope/10b-vslang/#swift","title":"Swift","text":"

There are many diffirences with Swift, but this section just highlights a couple because it helps to understand the Pyrope semantics.

"},{"location":"pyrope/10b-vslang/#protocol-vs-pyrope-constrains","title":"Protocol vs Pyrope constrains","text":"

Swift protocols resemble type classes. As such require consent for implementing a functionality. Pyrope resembles C++ concepts that constraint functionality.

func add<T>(a:T, b:T) -> T { a + b }  // compile error\nfunc add<T:Numeric>(a:T, b:T) -> T { a + b }\n
let add = fun(a,b) { a + b }            // OK, no constrains\nlet add = fun<T:int>(a:T,b:T) { a + b } // constrain both to have same type\n

When a protocol defines an interface, in Swift:

protocol Shape {\n  func name()      -> String\n  func area()      -> Float\n  func perimeter() -> Float\n}\n\nclass Rectangle : Shape {  }\nclass Circle    : Shape {  }\n\nfunc print_share_info<T:Shape>(_ s:T) {\n\n}\n

In Pyrope:

let Shape = (\n  ,name:fun(self)->(_:string)    = _\n  ,area:fun(self)->(_:Float)     = _  // NOTE: Pyrope does not have float type\n  ,perimeter:fun(self)->(_:Float)= _\n)\n\nlet Rectangle:(...Shape,...OtherAPI) = (...some_code_here)\nlet Circle:Shape = (...some_code_here)\n\nlet print_share_info = fun(s:Shape) { }\n

"},{"location":"pyrope/10b-vslang/#rust","title":"Rust","text":"

Rust is not an HDL, as such it has to deal with many other issues like memory. This section is just a syntax comparison.

"},{"location":"pyrope/10b-vslang/#lambda","title":"Lambda","text":"

In Rust, the self keyword when applied to lambda arguments can be &self, self, &mut self. In Pyrope, there is only a self and ref self. The equivalent of the &mut self is ref self. Pyrope does not have the equivalent of mut self that allows to modify a copy of self.

pub struct AnObject {\nv:i32\n}\n\nimp AnObject {\npub fn f1(&mut self) -> i32 {\nlet res = self.v;\nself.v += 1;\nres\n}\npub fn f2(self) -> i32 {\nself.v\n}\n}\n

A Rust style Pyrope equivalent:

let AnObject = (\n  ,v:i32 = _\n)\n\nlet f1 = proc(ref self:AnObject) -> :i32 { // unnamed output tuple\n  let res = self.v\n  self.v += 1\n  return res\n}\nlet f2 = fun(self:AnObject) -> :i32 {\n  return self.v\n}\n

A more Pyrope style equivalent:

let AnObject = (\n  ,v:i32 = _\n  ,f1 = proc(ref self) -> (res:i32) {\n    res = self.v\n    self.v += 1\n  }\n  ,f2 = fun(self) -> :i32 { self.v }\n)\n
"},{"location":"pyrope/10b-vslang/#typescript","title":"Typescript","text":"

Pyrope has a type system quite similar to Typescript, but there are significant differences. The main is that Pyrope does not allow union types.

There are also difference in some semantics. For example, Typescript \"foo\" in bar is equivalent to the bar has \"foo\" in Pyrope. Both check if entry foo exists in the tuple bar (bar.foo). There is no Typescript equivalent to the Pyrope \"foo\" in bar which checks if bar is a tuple with an entry equal to string \"foo\".

"},{"location":"pyrope/10b-vslang/#matlab","title":"Matlab","text":"

Matlab has a convenient multi-dimensional array or array initialization. It does not require comma. E.g: a = [a b 100 c] is valid Matlab.

Pyrope requires commas to distinguish from multi-line statements, hence a = [a,b,100,c] To initialize a multi-dimensional array, it follows other languages syntax, but in Pyrope both () and [] are allowed and have the same meaning.

let x = [[1,2],[3,4]]\nassert x == ((1,2),[3,4])\nassert x[0,1] == 2 == x[0][1]\nassert x[1,0] == 3 == x[1][0]\n
"},{"location":"pyrope/11-deprecated/","title":"Deprecated or Future","text":"

Pyrope has been in internal development for many years, those are some features tried and deprecated or removed until a better solution is found.

"},{"location":"pyrope/11-deprecated/#step-options","title":"step options","text":"

The step command breaks the execution of the function in the statements before and after the step. In the next cycle, the statements after the step are executed. The issue was that the step could be placed inside complicated nests of 'if' and 'for' loops. This results in a difficult code to get right.

The plan is to add something like this feature in the future, once a cleaner implementation is designed.

"},{"location":"pyrope/11-deprecated/#fluid-pipelines","title":"Fluid pipelines","text":"

The plan is to re-add the fluid pipelines syntax, but all the other features must be added first.

"},{"location":"pyrope/11-deprecated/#bundle-index-with-bundles","title":"Bundle index with bundles","text":"

Bundles do not allow an index with another bundle unless it is a trivial bundle (one element). To illustrate the current constraints:

Bundle index (not allowed)Current legal Pyrope
type Person = (name:string, age:u32)\nvar a = (one:Person, two:Person)\n\nx = ('one', 'two')\na[x].age = 10\n
let Person = (name:string=_, age:u32=_)\nvar a = (one:Person, two:Person)\n\nx = 'one'\ny = 'two'\na[x].age = 10\na[y].age = 10\n

In the future, it may be allowed but some options may not be allowed. For example, if the index bundle is not unordered, the result of the assignment may not be easy to predict by the programmer.

"},{"location":"pyrope/11-deprecated/#asyncawait-and-coroutines","title":"async/await and coroutines","text":"

In non-hardware languages, there are several constructs to handle asynchronicity. Asynchronicity is not to leverage parallelism for speedup but software constructs to handle long latency operations. The most popular models/techniques are async/await, coroutines, and actors.

In a way, pipelining could be expressed with similar constructs. This has the advantage of having a larger community (software) to understand/program hardware more easily.

To illustrate the point, suppose a telescoping subtract-like unit that provides a response of the operation in 1 or 2 cycles depending on the value of the input. If the b input is 0, the result is a+1. Otherwise, the result is a-b+1. The first finishes in 1 cycle, the second in 2 cycles. This seemly easy idea is not so easy to implement because it needs to handle 2 flops and there could be a structural hazard on the flop if the previous cycle was scheduled for 2 cycles and the current for 1 cycle.

This example explicitly manages the valid output signals.

let telescope_unit = fun(a:u32,b:u32,start:bool) -> (res:u32) {\n\n  reg result_done = 0\n  reg result_flop = 0\n\n  if result_done {\n    res = result_flop\n  }\n\n  reg int_done = _\n  reg int_flop = _\n  reg int_b = _\n\n  if int_done {  // pending work (2 cycle op, can not telescope)\n    result_flop = int_flop-int_b\n    result_done = int_done\n    int_flop = a+1\n    int_b    = b\n    int_done = start\n  }else{          // no pending work from before (telescoping is allowed)\n    if b == 0 {\n      result_flop = a+1\n      result_done = start\n    }else{\n      result_flop = int_flop-int_b\n      int_flop = a+1\n      int_b    = b\n      int_done = start\n    }\n  }\n}\n

In a simple telescoping use case, the puts command will be called 1 or 2 cycles after the telescope_unit starts. For the designer, this is quite difficult to handle. How many flops to add to remember the starting point for a and b.

 let res1 =#[1,2] telescope_unit(a,b,start)\n\n if res1? {\n   puts \"{}-{}+1 is {}\", a, b, res1.res  // incorrect reference to a\n }\n

To address the issue that the telescope_unit can have multiple cycles to complete, a yield directive can behave like co-routines. Effectively, remembering the live-ins and continue executing when the condition is satisfied.

 let res1 =#[1,2] telescope_unit(a,b,start)\n\n yield res1? // wait for condition to happen\n assert res1?\n\n // code executed 1 or 2 cycles after telescope_unit is called\n puts \"{}-{}+1 is {}\", a, b, res1.res\n

An alternative implementation is using the #>identifier[lat=cycles] keyword. The disadvantage is that two operations could finish on the same cycle, and the circuits are not as efficient.

// implicit start/end (starts when called)\nlet telescope_unit3 = fun(a:u32,b:u32) -> (_:u32) {\n\n  {\n    let tmp = a+1\n  } #>one_pipe[lat=1] {\n    if b == 0 {\n      return tmp\n    }\n    let tmp2 = tmp-b\n  } #> {\n    return tmp2\n  }\n}\n

The code sample for explicitly managed step function usage:

 let res2 =#[1,2] telescope_unit3(a,b,start)\n\n if res2? { // code executed 1 or 2 cycles after telescope_unit is called\n   puts \"{}-{}+1 is {}\", a, b, res2\n }\n

The code sample for implicitly managed step function usage:

 async res3 =#[1,2] telescope_unit3(a,b) when start\n\n await res3 {\n   // a and b could have the correct results due to the async/await\n   puts \"{}-{}+1 is {}\", a, b, res3.res\n }\n
"},{"location":"pyrope/11-deprecated/#extensible-enums","title":"Extensible enums","text":"

Once an enum is created, it can not be modified. There is no reason not to support compile time addition/removal from an enum. Languages with union types could behave like extending an enum, but not reducing it. Some potential API for Pyrope

Using the set operations:

enum Order = (One, Two, Three)\nenum Order2 = (...Order, Four)\nenum Order2 = Order ++ Four       // error on overlap?\nenum Order3 = Order except Three  // new \"remove\" tuple op\n

Overloading the logical operations is another option, but breaks the rule of lack of overloading in ops:

enum Order2 = Order or (Four)\nenum Order3 = Order and not (Three)\n

Using the trait syntax creates some confusion on the meaning, but an option is to have custom keywords for enum:

enum Order2 = Order with (Four)\nenum Order3 = Order except Three\n

Once we support adding/removing to enums, operations like this would make sense:

match x:Order {\n  in Order2      { puts \"1 or 2\" }\n  == Order.Three { puts \"3\"      }\n}\n
"},{"location":"pyrope/11-deprecated/#repipe","title":"repipe","text":"

Note

The repipe statement was deprecated because the pipestage could achieve similar results more cleanly in most of the cases that it was tried. Also, repipe would have required a custom lgraph pass to balance pipeline stages.

The repipe statement tries to balance the number of pipeline stages by inserting registers. If it can not guarantee the same pipeline depth, a compile error is generated. If there is any feedback loop, likely, the pipeline can not be rebalanced with repipe.

The syntax for repipe is repipe res = (list of variables). The result is a tuple with as many fields as the list of input variables but with enough flops so that the pipeline is balanced from the list of variables and the function inputs.

"},{"location":"pyrope/11-deprecated/#liam-constructs","title":"Liam constructs","text":"

In most HDLs loops have to be compile time unrolled, in an earlier version of Pyrope1 allowed for extra keywords to create an actor model and create state machines where each loop iteration will be executed in a cycle.

while some_condition {\n\n  step   // next cycle starts here\n}\n

Fluid constructs:

  • variable? check if variable valid bit is set
  • variable! check if variable has a fluid backpressure
  • keep do not consume variable on use
  • step stop the cycle here, continue next cycle after the yield statement
  1. Liam: An Actor Based Programming Model for HDLs, Haven Skinner, Rafael T. Possignolo, and Jose Renau. 15th ACM-IEEE International Conference on Formal Methods and Models for System Design (MEMOCODE), October 2017.\u00a0\u21a9

"},{"location":"pyrope/12-lnast/","title":"LNAST","text":"

This document is to showcase some of the Pyrope to LNAST translation. This is useful to have a more \"formal\" description of the language semantics.

"},{"location":"pyrope/12-lnast/#variable-names","title":"Variable names","text":"

LNAST does not rename variables to be SSA, it relies in a symbol table to track past entries. Nevertheless, to reduce amount of tracking information when a variable starts with underscores (___foo or _._foo), the variable can not be updated, BUT it is still legal to update tuple fields inside ___foo like ___foo.bar = 3. Program variables names that do not need SSA (let) can use _._foo to reduce tracking. Special variable names like the ones needing an underscore use double tick in the name _foo here. Those are special variables names that do not allow to use compact tuple representation like foo here.field.

PyropeLNAST directLNAST optimized
let x = 3 + 1\nvar z = 4\n`foo x` = x + z + 2\n
plus\n  ref ___1\n  const 3\n  const 1\nlet\n  ref  x\n  ref  ___1\nvar\n  ref z\n  const 4\nplus\n  ref ___2\n  ref x\n  ref z\n  const 2\nassign\n  ref `foo x`\n  ref ___2\n
plus\n  ref ___1\n  const 3\n  const 1\nlet\n  ref  x\n  ref  ___1\nvar\n  ref z\n  const 4\nplus\n  ref `foo x`\n  ref x\n  ref z\n  const 2\n

The three LNAST nodes to set values in variables are let/var/assign. Each can have types and/or attributes.

PyropeLNAST
let a:u2:[foo] = b:u1:[bar]\n\nx:u2:[foo] = y:u1:[bar]\n
set\n  ref a\n    prim_type_uint\n      const 2\n    attr_ref_set\n      const foo\n      const true\n  ref b\n    prim_type_uint\n      const 2\n    attr_check\n      const bar\n      const true\n\nassign\n  ref x\n    prim_type_uint\n      const 2\n    attr_ref_set\n      const foo\n      const true\n  ref y\n    prim_type_uint\n      const 2\n    attr_check\n      const bar\n      const true\n
"},{"location":"pyrope/12-lnast/#tuples","title":"Tuples","text":"

Tuples are \"ordered\" sequences that can be named. There are LNAST tuple specific nodes (tup_add, tup_set, tup_get, tup_concat) but in many cases the direct LNAST operations can handle tuples directly.

  • tup_add creates a new tuple with entries
  • tup_set adds/updates a field to an existing tuple.
  • tup_get gets the contents of a tuple entry
  • tup_concat concatenates two or more tuples

To indicate the tuple position, identifiers can have :pos:name. For example x.:3:foo = 2 is legal. It is the same as x[3] = 2 or x.foo=2 and check that entry 3 has label foo. This allows to create more compact LNAST. Direct access in operations like plus behave like a tup_set or tup_get.

Tuple in PyropeLNAST directLNAST optimizedLNAST Alternative
x = 3\na = (b=2, x=x+1, y=self.b+1)\n
assign\n  ref      x\n  const    3\nassign\n  ref      ___t1\n  const    2\nplus\n  ref      ___t2\n  ref      x\n  const    1\nplus\n  ref      ___t3\n  ref      ___t1\n  const    1\ntup_add\n  ref      a\n  var\n    ref      b\n    ref      __t1\n  var\n    ref      x\n    ref      ___t2\n  var\n    ref      y\n    ref      ___t4\n
assign\n  ref      x\n  const    3\nplus\n  ref      ___t2\n  ref      x\n  const    1\nplus\n  ref      ___t3\n  ref      ___t1\n  const    1\ntup_add\n  ref      a\n  var\n    ref      b\n    const   2\n  var\n    ref      x\n    ref      ___t2\n  var\n    ref      y\n    ref      ___t4\n
assign\n  ref      x\n  const    3\nvar\n  ref      a.0b\n  ref      2\nplus\n  ref      ___t1\n  ref      x\n  const    1\nvar\n  ref      a.1x\n  ref      ___t1\nplus\n  ref      ___t2\n  const    a.0b\n  const    1\nvar\n  ref     a.2y\n  ref     ___t2\n

tup_set and tup_get can access through several levels in one command. tup_add does not allow recursive entrances, it requires intermediate tuple construction. attr_get and attr_set follow the same syntax as tup_get/tup_set.

PyropeLNAST
x = tup[1].foo[xx]\ntup[4].foo[yy] = y\n\nz = (foo=(bar=1))\n
tup_get\n  ref x\n  ref tup\n  const 1\n  const foo\n  ref xx\n\ntup_set\n  ref tup\n  const 4\n  const foo\n  ref yy\n  ref y\n\ntup_add\n  ref ___1\n  var\n    ref bar\n    const 1\n\ntup_add\n  ref z\n  var\n    ref foo\n    ref ___1\n

Tuples can have a let in declaration to indicate that the field is immutable.

Tuple in PyropeLNAST directLNAST Optimized
var a = (b=2, let x=1+1)\n
assign\n  ref    ___t1\n  const  2\nplus\n  ref    ___t2\n  const  1\n  const  1\ntup_add:\n  ref     a\n  var\n    ref     b\n    ref     __t1\n  let\n    ref     x\n    ref     ___t2\n
var\n  ref    a.:0:b\n  const  2\nplus\n  ref    ___2\n  const  1\n  const  1\nlet\n  ref    a.:1:x\n  ref    ___2\n

Tuple concatenation does not use plus but the tup_concat operator.

Tuple in PyropeLNAST directLNAST optimized
var a = (2, 1+1)\nlet x = a ++ (c=3) ++ 1\n
assign\n  ref    ___1\n  const  2\nplus\n  ref    ___2\n  const  1\n  const  1\ntup_add:\n  ref    ___33\n  ref    ___1\n  ref    ___2\nvar\n  ref    a\n  ref    ___33\ntup_add\n  ref    ___3\n  const  c\n  const  3\ntup_concat\n  ref    ___4\n  ref    a\n  ref    ___3\n  const  1\nlet\n  ref    x\n  ref    ___4\n
var\n  ref    a.:0:\n  const  2\nplus\n  ref    ___2\n  const  1\n  const  1\nvar\n  ref    a.:1:\n  ref    ___2\ntup_add\n  ref    ___3\n  const  c\n  const  3\ntup_concat\n  ref    ___4\n  ref    a\n  ref    ___3\n  const  1\nlet\n  ref    x\n  ref    ___4\n
"},{"location":"pyrope/12-lnast/#attributes","title":"Attributes","text":"

There are 3 main operations with attributes: set, get, check, but 4 types of LNAST nodes (attr_get/attr_set and attr_ref_set/attr_ref_check). attr_get/attr_set operate at the root level and have the same syntax as tup_set/tup_get but the last entry is an attribute name. attr_ref_set/attr_ref_check are sub-nodes of ref, as such they operate over the associated ref node destination.

attr_ref_check only works comparing equal to a const or ref. More complex attribute comparisons needs attr_get and casserts to operate.

Attribute set are in left-hand-side of assignments which can also be in tuple entries.

PyropeLNAST direct
a::[f=3,b] = 1\nx = (y::[z=7]=2, 4)\n
assign\n  ref a\n    attr_ref_set\n      const f\n      const 3\n    attr_ref_set\n      const b\n      const true\n  const 1\n\ntup_add\n  ref ___1\n  var\n    ref y\n      attr_ref_set\n        const z\n        const 7\n    const 2\n  const 4\n\nassign\n  ref x\n  ref ___1\n

Attribute checks are always right-hand-side. The constraint in all the cases is that an attribute name can be check against an expression but only 3 basic comparisons are valid ([attr==(expr) or [attr] or [!attr]). The expression can not use other attribute fields. If complex relationships must be checked between attributes a cassert must be used.

PyropeLNAST option 1LNAST option 2
var x = (let z=x::[!y], 4::[foo])\nlet y = a::[f==3,b] + 1\n
assign\n  ref ___tmp\n  const 4\n\ntup_add\n  ref ___4\n  let\n    ref z\n    ref x\n      attr_ref_check\n        const y\n        const false\n  ref ___tmp\n    attr_ref_check\n      const foo\n      const true\nvar\n  ref x\n  ref ___4\n\nplus\n  ref ___1\n  ref a\n    attr_ref_check\n      const f\n      const 3\n    attr_ref_check\n      const b\n      const true\n  const 1\nlet\n  ref y\n  ref ___1\n
tup_add\n  ref ___4\n  let\n    ref z\n    ref x\n      attr_ref_check\n        const y\n        const false\n  const 4\n\nattr_get\n  ref ___no_attr_const_check\n  const 4\n  const foo\n\nfcall\n  ref ___0\n  ref cassert\n  ref ___no_attr_const_check\n\nvar\n  ref x\n  ref ___4\n\nplus\n  ref ___1\n  ref a\n    attr_ref_check\n      const f\n      const 3\n    attr_ref_check\n      const b\n      const true\n  const 1\nlet\n  ref y\n  ref ___1\n
"},{"location":"pyrope/12-lnast/#sticky-attributes","title":"Sticky attributes","text":"

Attributes can be sticky or not. A sticky attribute \"polutes\" or keeps the attribute to the left-hand-side expression. Non-sticky attributes do not affect or propagate.

Attributes are not sticky by default, but some like .[debug] is a sticky attribute. This means that if any of the elements in any operation has a debug attribute, the result also has a .[debug] attribute. There is no way to remove these attributes.

PyropeLNAST
let d::[debug] = 3\n\nvar a = d + 100\n\ncassert a.[debug]  // debug is sticky\n
let\n  ref d\n    attr_ref_set\n      const debug\n      const true\n  const 3\n\nplus\n  ___tmp\n  ref d\n  const 100\n\nvar\n  ref a\n  ref ___tmp\n\nattr_get\n  ref ___get\n  ref a\n  const debug\n\nfcall\n  ___unused\n  ref cassert\n  ref ___get\n

Once a variable gets assigned an attribute, the attribute stays with the variable and any variables that got a direct copy. The only way to remove it is with arithmetic operations and/or bit selection.

let foo::[attr1=2] = 3\n\nvar foo2 = foo\ncassert foo2.[attr1] == 2\n\nlet foo3 = foo@[..]\ncassert foo3 !has _::[attr1]\n\nvar xx = 4\nxx::[attr2=5] = 1\n\nlet xx2 = xx\ncassert xx2.[attr2] == 5\ncassert xx2 has _::[attr2]\n\nlet xx3 = xx + 0\ncassert xx3 !has _::[attr2]\n
"},{"location":"pyrope/12-lnast/#bit-selection","title":"Bit selection","text":"

Pyrope has several bit selection operations. The default maps get_mask and set_mask LNAST nodes. One important thing is that both get_mask and set_mask operate over a MASK. This means that it is a one-hot encoding if a single bit is operated. The one-hot encoding can be created with a range or with a shl operator.

PyropeLNAST directLNAST optimized
foo@[1,2] = xx\nyy = foo@[5] + xx@[1..<4]\n
shl\n  ref ___c1\n  const 1\n  const 1\n\nshl\n  ref ___c2\n  const 1\n  const 2\n\ntup_add\n  ref ___t\n  ref ___c1\n  ref ___c2\n\nset_mask\n  ref foo\n  ref foo\n  ref ___t\n  ref xx\n\nrange\n  ref ___c5\n  const 5\n  const 5\n  const 1\n\nget_mask\n  ref ___3\n  ref foo\n  ref ___c5\n\nrange\n  ref ___4\n  const 1\n  const 3\n  const 1\n\nget_mask\n  ref ___5\n  ref xx\n  ref ___4\n\nadd\n  ref yy\n  ref ___4\n  ref ___5\n
shl\n  ref ___t\n  const 1\n  const 1\n  const 2\n\nset_mask\n  ref foo\n  ref foo\n  ref ___t\n  ref xx\n\nget_mask\n  ref ___3\n  ref foo\n  const 5\n\nrange\n  ref ___4\n  const 1\n  const 3\n  const 1\n\nget_mask\n  ref ___5\n  ref xx\n  ref ___4\n\nadd\n  ref yy\n  ref ___4\n  ref ___5\n

It is possible to use a foo@sext[range] to perform a bit selection with sign extension. The sext LNAST node is equivalent to the Lgraph sext that has 2 inputs. The variable and from what bit to perform sign-extension. This means that the LNAST translation needs a get_mask and a sext node. The sext, +, |, ^ bit selection modifiers can only be applied to right-hand-side operations.

PyropeLNAST
let t1 = foo@sext[..=4]\nlet t2 = foo@|[..=4]\nlet t3 = foo@&[..=4]\nlet t4 = foo@^[..=4]\nlet t5 = foo@+[..=4]\n
range\n  ref ___r\n  const 0\n  const 4\n  const 1\n\nget_mask\n  ref ___t\n  ref foo\n  ref ___r\n\nsext\n  ref ___t1\n  ref ___t\n  const 4\nlet\n  ref t1\n  ref ___t1\n\nreduce_or\n  ref ___t2\n  ref ___t\nlet\n  ref t2\n  ref ___t2\n\nreduce_and       // reduce_and(x) == (sext(x) == -1)\n  ref ___t3\n  ref ___t\nlet\n  ref t3\n  ref ___t3\n\nreduce_xor\n  ref ___t4\n  ref ___t\nlet\n  ref t4\n  ref ___t4\n\npopcount\n  ref ___t5\n  ref ___t\nlet\n  ref t5\n  ref ___t5\n
"},{"location":"pyrope/12-lnast/#direct-lnastlgraph-call","title":"Direct LNAST/Lgraph call","text":"

A direct Lgraph call can be done with __cell where cell is the Lgraph cell like plus, LUT, memory. In LNAST this is translated like a lambda call.

PyropeLNAST
let foo = 3\nlet bar = 300\nlet b = __plus(1,2,foo,bar)\n
let\n  ref foo\n  const 3\nlet\n  ref bar\n  const 300\ntup_add\n  ref ___0\n  const 1\n  const 2\n  ref foo\n  ref bar\nfcall\n  ref b\n  ref __plus\n  ref ___0\n

A direct LNAST call can be done calling an LNAST method, where the first entry is the root LNAST node, and rest follow a tree syntax with strings.

PyropeLNAST
LNAST(\"let\", (\"ref\", \"x\"), (\"const\", \"5\"))\n
let\n  ref x\n  const 5\n
"},{"location":"pyrope/12-lnast/#basic-operators","title":"Basic operators","text":"

Basic operators are binary or unary operators in Pyrope that have a one-to-one translation to LNAST nodes.

"},{"location":"pyrope/12-lnast/#unary","title":"Unary","text":"
  • !a or not a translates to lnot
  • ~a translates to not
  • -a translates to minus(0,a)
"},{"location":"pyrope/12-lnast/#binary-integer","title":"Binary integer","text":"
  • a + b translates to plus
  • a - b translates to minus
  • a * b translates to mult
  • a / b translates to div
  • a & b translates to and
  • a | b translates to or
  • a ^ b translates to xor
  • a >> b translates to sra
  • a << b translates to shl

There is a mod LNAST operator that performs module operations. It does not have a direct Pyrope syntax, but it can be called directly __mod(a,b).

"},{"location":"pyrope/12-lnast/#binary-boolean","title":"Binary boolean","text":"
  • a and b translated to land
  • a or b translates to lor
"},{"location":"pyrope/12-lnast/#complex-operators","title":"Complex operators","text":"

Complex operators are binary operators in Pyrope that require more than one LNAST statement.

"},{"location":"pyrope/12-lnast/#binary-integer_1","title":"Binary integer","text":"

Binary nand (x=a ~& b):

and\n  ref ___0\n  ref a\n  ref b\nnot\n  ref x\n  ref ___0\n

Binary nor (x=a ~| b):

or\n  ref ___0\n  ref a\n  ref b\nnot\n  ref x\n  ref ___0\n

Binary xor (x=a ~^ b):

xor\n  ref ___0\n  ref a\n  ref b\nnot\n  ref x\n  ref ___0\n

Logical shift right (x = a@[..] >> b):

get_mask\n  ref ___0\n  ref a\nsra\n  ref x\n  ref ___0\n  ref b\n

"},{"location":"pyrope/12-lnast/#binary-logical","title":"Binary logical","text":"

Logical implication (x = a implies b):

not\n  ref ___0\n  ref a\nlor\n  ref x\n  ref ___0\n  ref b\n

Logical nand (x = a !and b):

land\n  ref ___0\n  ref a\n  ref b\nnot\n  ref x\n  ref ___0\n

Logical nor (x = a !or b):

lor\n  ref ___0\n  ref a\n  ref b\nnot\n  ref x\n  ref ___0\n

Logical not implication (x = a !implies b):

not\n  ref ___0\n  ref b\nland\n  ref x\n  ref a\n  ref ___0\n

Short-circuit boolean (and_then/or_else)

The short-circuit boolean prevent expressions from being evaluated. This only matters if there is a procedure call, but at LNAST it is not possible to know due to getter overload. As a result, the sequence of statments is translated to a sequence of nested if statements.

PyropeLNAST
a = b and_then c and_then (d or e)\n
land\n  ref ___0\n  ref b\n  ref c\nassign\n  ref a\n  ref ___0\nif\n  ref ___0\n  stmts\n    lor ___1\n      ref d\n      ref e\n    assign\n      ref a\n      ref ___1\n
PyropeLNAST
a = b or_else c or_else (d and e)\n
lor\n  ref ___0\n  ref b\n  ref c\nassign\n  ref a\n  ref ___0\nif\n  ref ___0\n  stmts\n  stmts  // else only\n    land\n      ref ___1\n      ref d\n      ref e\n    assign\n      ref a\n      ref ___1\n
"},{"location":"pyrope/12-lnast/#tupleset-operators","title":"Tuple/Set operators","text":"

The in operator does not have a Lgraph equivalent becuase it is type dependent: tuple, range, or enumerate. The range and enumerate can get translated to an AND gate over the bitcode translation, but the tuple check requires a tuple check.

let tup=(1,2,3)\nlet ran=1..<5\nlet enu = enum(a,b=(x,y),c)\n\ncassert 2 in tup\ncassert 3 in ran\ncassert enu.b.x in enu.b\n

The resul is a common in LNAST operation that gets different functionality dependent on the input type.

PyropeLNAST
c = a in b\nd = a !in b\n
in\n  ref c\n  ref a\n  ref b\nnot\n  ref d\n  ref c\n

There are two tuple concatenate operator a ++ b and (a,...b). x=a++b translates to:

tup_concat\n  ref x\n  ref a\n  ref b\n

The inplace concatenate is equivalent but it has a check (cassert) to detect overlap. After the concatenation, the fields in a and b should be found in the result x or there was an overlap.

x=(a,..b) translates to:

tup_concat\n  ref x\n  ref a\n  ref b\nin\n  ref ___1\n  ref a\n  ref x\nin\n  ref ___2\n  ref b\n  ref x\nland\n  ref ___3\n  ref ___1\n  ref ___2\nfcall\n  ref ___0\n  ref cassert\n  ref ___3\n

"},{"location":"pyrope/12-lnast/#tuple-to-operator","title":"Tuple to operator","text":"

The to is an iterator but instead of a range, it creates a tuple.

tmp = a to b by c translates to:

to\n  ref tmp\n  ref a\n  ref b\n  ref c\n

tmp = 3 to b translates to:

to\n  ref tmp\n  const 3\n  ref b\n  const 1\n

"},{"location":"pyrope/12-lnast/#range-operator","title":"Range operator","text":"

Ranges can be open or closed. The closed ranges have the start/end/step defined.

x = a..<=b by 2 translates to:

range\n  ref x\n  ref a\n  ref b\n  const 2\n

x = a..<=b by 2 translates to:

range\n  ref x\n  ref a\n  ref b\n  const 2\n

x = a..<b translates to:

sub\n  ref tmp\n  ref b\n  ref 1\n\nrange\n  ref x\n  ref a\n  ref tmp\n  const 1\n

"},{"location":"pyrope/12-lnast/#type-operators","title":"Type operators","text":"

To check if a field name or position exists in a tuple, x = a has b translates:

has\n  ref x\n  ref a\n  ref b\n

To check the tuple structure, Pyrope has a does b. It returns true if the tuple of a a subset of b. x = a does b translates to:

does\n  ref x\n  ref a\n  ref b\n

To check equality of tuples x = a equals b same as x = (a does b) and (b does a). Translates to:

does\n  ref ___0\n  ref a\n  ref b\ndoes\n  ref ___1\n  ref b\n  ref a\nland\n  ref x\n  ref ___0\n  ref ___1\n

The a case b does match operation. a case b same as cassert b does a and for each b field with a defined value, the value matches a (nil, 0sb? are undefined values). x = a case b translates to:

does\n  ref ___0\n  ref b\n  ref a\nfcall\n  ref ___1\n  ref cassert\n  ref ___0\nin\n  ref x\n  ref b\n  ref a\n

To perform a nominal type check, the attributes can be accessed directly. x = a is b translates to:

attr_get\n  ref ___0\n  ref a\n  const typename\nattr_get\n  ref ___1\n  ref b\n  const typename\neq\n  ref x\n  ref ___0\n  ref ___1\n

"},{"location":"pyrope/12-lnast/#ifunique-if","title":"if/unique if","text":"

Like many modern languages, if accepts not only a boolean expression but a sequence of statements. Like C++17, before a condition, there can be a sequence of statements that can include variable declarations. Pyrope variables initial statement declarations are visiable in the if and else statements like C++17 does.

A special constraint from Pyrope is that the initial statements and condition check can not have side-effects. Hence, they can not have procedure calls, only function calls.

PyropePyrope EquivalentC++17 equivalent
var total=3\nif var x=3; x<3 {\n  total+=x\n}elif var z=3; z<4 {\n  total+=x+z\n}\n
var total=3\n{\n  var x=3\n  if x<3 {\n    total+=x\n  }else{\n    var z=3\n    if z<4 {\n      total+=x+z\n    }\n  }\n}\n
int total=3;\nif (int x=3; x<3) {\ntotal+=x;\n}else if (int z=3; z<4) {\ntotal+=x+z;\n}\n

Pyrope has if and unique if. The difference is that unique if guarantees that only one of the branch conditions is taken. It is possible to have all the conditions not taken. This allows synthesis optimizations because it implies that the condition is a one-hot encoding.

PyropeLNAST
if var x=a ; x<3 {\n  t = 100+x               // z not in scope\n}elif var z = x+c ; z>5 {\n  t = 200+z+x             // z and x in scope\n}\n
stmts\n  var\n    ref x\n    ref a\n  lt\n    ref ___1\n    ref x\n    const 3\n  if\n    ref ___1\n    stmts\n      add\n        ref t\n        const 100\n        ref x\n    stmts\n      add\n        ref ___2\n        ref x\n        ref c\n      var\n        ref z\n        ref ___2\n      gt\n        ref ___3\n        ref z\n        const 5\n      if\n        ref ___3\n        stmts\n          add\n            ref t\n            const 200\n            ref z\n            ref x\n

The unique if is similar, but all the conditions include and optimize directive to be checked. This means that the conditions must be checked even if the else is not reached. This is fine because neither the statements nor the condition checks are allowed to have side-effects.

An important limitation of unique if is that only the first condition can have initial statement. It is not allowed to have initialization statements in the elif conditions.

PyropePyrope EquivalentLNAST
unique if a<3 {\n  y = 10\n}elif a>40 {  // not allowed to do 'elif var z=40; a>z'\n  y = 20+x\n}\n
let tmp1 = a<3\nlet tmp2 = a>40\nlet tmp3 = 1<<(tmp1,tmp2)\noptimize tmp3@+[..]<=1        // at most one bit set\n\nif tmp1 {\n  y = 10\n}elif tmp2 {\n  y = 20+x\n}\n
lt\n  ref ___1\n  ref z\n  const 3\ngt\n  ref ___2\n  ref a\n  const 40\nshl           // create one-hot encoding\n  ref ___3\n  const 1\n  ref ___1\n  ref ___2\npopcount\n  ref ___4\n  ref ___3\nle\n  ref ___5\n  ref ___4\n  const 1\nfcall\n  ref nil\n  ref optimize\n  ref ___5\nif\n  ref ___1\n  stmts\n    assign\n      ref y\n      const 10\n  ref ___2\n  stmts\n    add\n      ref y\n      const 20\n      ref x\n
"},{"location":"pyrope/12-lnast/#match","title":"match","text":"

The match statement behaves like a unique if but it also checks that at least one of the paths is taken. This means that if the else exists in the match, it behaves like a unique if. If the else does not exist, an else { assert false } is created.

PyropeLNAST
var z = 0\nmatch x {\n == 3 { z = 1 }\n in 4..<6 { z = 2 }\n}\n\nmatch x {\n <  5 { z = 1 }\n else { z = 3 }\n}\n
var\n  ref z\n  const 0\n\neq\n  ref ___0\n  ref x\n  const 3\nrange\n  ref ___2\n  const 4\n  const 5\nin\n  ref ___1\n  ref x\n  ref ___2\n\nshl\n  ref ___3\n  const 1\n  ref ___1\n  ref ___2\npopcount\n  ref ___4\n  ref ___3\nle\n  ref ___5\n  ref ___4\n  const 1\nfcall\n  ref nil\n  ref optimize\n  ref ___5\n\nif\n  ref ___1\n  stmts\n    assign\n      ref z\n      const 1\n  ref ___2\n  stmts\n    assign\n      ref z\n      const 2\n  stmts\n    fcall\n      ref ___6\n      ref assert\n      const false\n\n// 2nd match\nlt\n  ref ___6\n  ref x\n  const 5\nshl\n  ref ___7\n  const 1\n  ref ___6\npopcount\n  ref ___8\n  ref ___7\nle\n  ref ___9\n  ref ___8\n  const 1\nfcall\n  ref nil\n  ref optimize\n  ref ___9\nif\n  ref ___6\n  stmts\n    assign\n      ref z\n      const 1\n  stmts\n    assign\n      ref z\n      const 3\n
"},{"location":"pyrope/12-lnast/#scope","title":"Scope","text":"

Like most languages Pyrope has variable scope, but it does not allow variable shadowing. This section showcases some cases on how the scope is generated.

New variables can have a statement scope for if, while, and match statements.

PyropeLNAST
if var x=3; x<4 {\n  cassert x==3\n}\nwhile var z=1; x {\n  x -= z\n}\nvar z=0\nmatch var x=2 ; z+x {\n  == 2 { cassert true  }\n  != 7 { cassert true  }\n  else { cassert false }\n}\n
stmts\n  var\n    ref x\n    const 3\n  lt\n    ref ___1\n    ref x\n    const 4\n  if\n    ref ___1\n    stmts\n      eq\n        ref ___2\n        ref x\n        const 3\n      fcall\n        ref ___0\n        ref cassert\n        ref ___2\n\nstmts\n  var\n    ref z\n    const 1\n  loop\n    if\n      ref x\n      stmts\n        break\n    sub\n      ref x\n      ref x\n      ref z\n\nvar\n  ref z\n  const 0\nstmts\n  var\n    ref x\n    const 2\n  add\n    ref ___3\n    ref z\n    ref x\n  eq\n    ref ___t1\n    ref ___3\n    const 2\n  ne\n    ref ___t2\n    ref ___3\n    const 7\n  shl           // create one-hot encoding\n    ref ___x\n    const 1\n    ref ___t1\n    ref ___t2\n  popcount\n    ref ___y\n    ref ___x\n  le\n    ref ___z\n    ref ___y\n    const 1\n  fcall\n    ref nil\n    ref optimize\n    ref ___z\n  if\n    ref ___t1\n    stmts\n      fcall\n        ref ___4\n        ref cassert\n        const true\n    ref ___t2\n    stmts\n      fcall\n        ref ___5\n        ref cassert\n        const true\n    stmts\n      fcall\n        ref ___6\n        ref cassert\n        const false\n
"},{"location":"pyrope/12-lnast/#whileloopfor","title":"while/loop/for","text":"

Pyrope has loop, while, and for constructs to handle different types of loops. In all the cases, the loops must be expanded at LNAST compile time. In LNAST, there is only loop construct.

Pyrope loopLNAST
loop {\n  i += 1\n  break when i==3\n}\n
loop\n  add\n    ref i\n    ref i\n    const 1\n  eq\n    ref ___1\n    ref i\n    const 3\n  if\n    ref ___1\n    stmts\n      break\n

The while translates to a loop with a break statement.

Pyrope whileLNAST
while var i=0 ; i!=3 {\n  i += 1\n}\n
stmts\n  var\n    ref i\n    const 0\n  loop\n    neq\n      ref ___1\n      ref i\n      const 3\n    not\n      ref ___2\n      ref ___1\n    if\n      ref ___2\n      stmts\n        break\n

The for construct is also a loop, but it can have element, index, and key in the iterator. Also, it can allow a ref to mutate the contents.

Pyrope forPyrope ref forLNAST forLNAST ref for
for (index,key,value) in enumerate(key(tup)) {\n  mycall(value,index,key)\n}\n
for value in ref tup {\n  mycall(value)\n  value = 0\n}\n
attr_get\n  ref ___tup_size\n  ref tup\n  const size\ngt\n  ref ___2\n  ref ___tup_size\n  const 0\nif\n  ref ___2\n  stmts\n    var\n      ref value\n      ref _\n    var\n      ref index\n      const 0\n    var\n      ref key\n      const \"\"\n    loop\n      attr_get\n        ref key\n        ref tup\n        ref index\n        const \"key\"\n      tup_get\n        ref value\n        ref tup\n        ref index\n      tup_add\n        ref ___6\n        ref index\n        ref key\n        ref value\n      fcall\n        ref ___empty\n        ref mycall\n        ref ___6\n      add\n        ref index\n        ref index\n        const 1\n      eq\n        ref ___3\n        ref ___tup_size\n        ref index\n      if\n        ref ___3\n        stmts\n          break\n
attr_get\n  ref ___tup_size\n  ref tup\n  const size\ngt\n  ref ___2\n  ref ___tup_size\n  const 0\nif\n  ref ___2\n  stmts\n    var\n      ref value\n      ref _\n    var\n      ref index\n      const 0\n    var\n      ref key\n      const \"\"\n    loop\n      attr_get\n        ref key\n        ref tup\n        ref index\n        const \"key\"\n      tup_get\n        ref tup\n        ref index\n        ref value\n      tup_add\n        ref ___6\n        ref index\n        ref key\n        ref value\n      fcall\n        ref ___empty\n        ref mycall\n        ref ___6\n      tup_set\n        ref tup\n        ref index\n        ref value\n      add\n        ref index\n        ref index\n        const 1\n      eq\n        ref ___3\n        ref ___tup_size\n        ref index\n      if\n        ref ___3\n        stmts\n          break\n

The for comprehensions behave similarly, but the cont/brk statements have the value that must be concatenated (tup_concat) to the result. If the last statement is an expression, the value is contatenated.

"},{"location":"pyrope/12-lnast/#putsprintformat","title":"puts/print/format","text":"

All the string variables must be known at compile time, but it is still OK to pass strings as arguments to simulation functions that have no side-effects in the running simulation like puts and print.

format uses C++ fmt::format syntax and returns a string, so it must be solved at compile time. This means that the LNAST passes should have a format implementation to allow copy propagation to proceed. When format is used, a single quote should be used to avoid string interpolation.

The LNAST translation for all these instructions is just a normal function call. The format must be executed at compile time and propagate/copy as needed. The puts/print should generate simulation calls but not synthesis code.

PyropeLNAST
let num = 1\nlet color = \"blue\"\nlet extension = \"s\"\n\nlet txt1 = \"I have {num} {color} potato{extension}\"  // interpolation\nlet txt2 = format('I have {:d} {} potato{}', num, color, extension)\n
let\n  ref num\n  const 1\nlet\n  ref color\n  const blue\nlet\n  ref extension\n  const s\n\ntup_add\n  ref ___tmp\n  const \"I have {} {} potato{}\"\n  ref num\n  ref color\n  ref extension\n\nfcall\n  ref txt1\n  ref format\n  ref ___tmp\n\ntup_add\n  ref ___tmp2\n  const 'I have {:d} {} potato{}'\n  ref num\n  ref color\n  ref extension\n\nfcall\n  ref txt2\n  ref format\n  ref ___tmp2\n
"},{"location":"pyrope/12-lnast/#lambda-call","title":"Lambda call","text":"

A lambda call arguments requires do not always require to be named like when a variable used matches a calling argument. To support the matching while processing the LNAST, the arguments tuple must be named for all the arguments unless an argument is an expression.

PyropeLNAST
x = fcall(a,b=3,foo,1+2)\n
add\n  ref ___t\n  const 1\n  const 2\n\ntup_add\n  ref ___args\n  let\n    ref a\n    ref a\n  let\n    ref b\n    const 3\n  let\n    ref foo\n    ref foo\n  ref ___t\n\nfcall\n  ref x\n  ref fcall\n  ref ___args\n
"},{"location":"pyrope/13-stdlib/","title":"Pyrope Standard Library","text":"

This is a list of functionality that import prp should produce.

"},{"location":"pyrope/13-stdlib/#basic-operations","title":"Basic operations","text":"

All the LNAST node have an associated function matching name to simplify the creation of operations: plus, minus, mult, div, mod, ror...

let prp = import(\"prp\")\ncassert prp.plus(1,2,3) == 6\n

Library code:

let plus = fun(...a:int)->(_:int) {\n  var r = 0\n  for e in a {\n    r += e\n  }\n  r\n}\n

"},{"location":"pyrope/13-stdlib/#arraytuple-operators","title":"Array/Tuple operators","text":""},{"location":"pyrope/13-stdlib/#size-of-length","title":"Size of length","text":"

Sample use:

let x = (1,2,23)\n\ncassert p.len(x) == 3\n

Library code:

let len = fun(x) { x.[size] }\n

"},{"location":"pyrope/13-stdlib/#map","title":"map","text":"

Sample use:

let x = (1,2,3)\n\ncassert x.map(fun(i){ i+1 }) == (2,3,4)\n

Library code:

let map = fun<T>(f:fun(a:T),...x:[]T) {\n  return f(e) for e in x\n}\n

"},{"location":"pyrope/13-stdlib/#filter","title":"filter","text":"

Sample use:

cassert (1,2,3).filter(fun(i){ i!=2 }) == (1,3)\n

Library code:

let filter = fun<T>(f:fun(a:T)->(_:Bool),...x:[]T) {\n  return e for e in x if not f(e)\n}\n
"},{"location":"pyrope/13-stdlib/#reduce","title":"reduce","text":"

Sample use:

cassrt (1,2,3).reduce(prp.plus) == 6\n

Library code:

let reduce = fun(op:fun<T>(a:T,b:T)->(_:T), ...x) {\n  return x when x.[size] <= 1\n\n  var res = x[0]\n  for i in x[1..] {\n    res = op(res, i)\n  }\n  return res\n}\n
"},{"location":"pyrope/13-stdlib/#todo","title":"TODO","text":"

It would be nice to have the same methods (and names) as the c++20 std::views adaptors so that it is easier for developers to get familiar. E.g: filter, transform, drop, join, split, reverse, common, counted...

https://en.cppreference.com/w/cpp/ranges

"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..0f8724e --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..3846604428a62ad7d6ba627931b1fdce10c73b17 GIT binary patch literal 127 zcmV-_0D%7=iwFoEC(&dA|8r?{Wo=<_E_iKh04<9_3V)_WXo8&M?ytk3HC}0~zlG)Vu

5=5tbcC^T*e#s38 zwLd}JwCqAce#Ur0D37@MEsuC(CQKKx6#p$DKd^*EHPULvS@sR-ezz@(8*ukxW-TT+ z-VLKBi791a%jEcIL-^Eh4d8-4-{l-_1HN2r(TyVg@GHBif|r^fA4^k?B_f6Lh3AC- z%(tNvVzi6<_6)p&JALfoc@bpo99S0PYB>LJw@>N5vV*XtV+XKRxQMD56#gvswGt^I z?Bm7lE`g6jV^ahp{2_Kr1-A9)eo)@Z5~=&^6nok=kOJa0BR{SH{Q^cm=y{j@oLzWw zu_kslO}7%kY)so$Uh~1u7%((Ohp$F2aliYaxcvDV6s%a&M#Nt=I{sZw~qP5tkEsRGA|Hx9xkGt#LX3rzDo3&lH26cSst)YuSTrz-}qL zKaf9!G^y3UjZGnp(89Sw8B>fUJ^a{~+=;WihxPhBnE%vHN<8Jv;2qE5CPj~>8><%j zdn`+PU+n6@caP5-+?Yz*x@T4*->8VPxZLpFh*QE2YsfQVh};86nY|j#UsR_Y#a^T> z5c-i*pgrI;A+XR~=a?a}fEa={AvOK}wF5mzrRJNXMkcaJ zR9kU#|7@sEzAmioSGJ$apWC7My!@_$A?e>4(FT|+=gs)lG&*<8+T8Or)zL2@H2coT zYhFb+A6G{_WXJVwFCK_cb#XAd8{h%p@ogEpuZI)0+a6MEgH}(N5ees7sC3)2shXOw zGaKd;x~lN=N2TJ|!&0tMA2wd1_i2^?9xmZWYcl{nOzzE z^S=+2B=EOV9=s9hYNL+nds|)+W2!~H5+H+P-1K6;m;4!|)mf0!OtQxUazp1@P&9-Q z$ftsA3VtWB2qEvCHHTi{etd*l3T8ujmVD@S`Px4wBk|OR@<%7#>8|f1OVUb2^BD{$ zq+Qu0zdLA#@LiQuYhR5{zkAt--L}aI^?Ml-C}yL8=8^Pn!xMpPJ>Pvn{Dl z%z8SHdjm{K{z@XeBTYEQ3BfGV2cCs zB`2!$KcdGY7kva&A0JBTgr66h2(eD|Tl6oMhsjqJc&Jf9Z-m^Nu%wk6gOP4nwF)Ox z%1nHMy|(5_ga~hN7ORv_p-RH@q1Ho5MaT(z(df5dAm5A}oNuR+DX+(q-%>nBRAf2+i zm7I$kFNTuC=R(jEskV|VmRpIU)PlZSUu#%CT9+@3UpTNFTN7o}!gGl2_iw&B-&2b&>NQUMYOx0`2tM7l zo!<)g$gH2Sn$i{=xtWe~^*&oUv9 ziWt^H46{5JA-Eut4;u)Z*Y5zGzLMMwq>ZGSqlQa7f@OC>7Nh%W`6zmqQy+p}@$g>> z76X0nf1uoR&69s$Gr7T=m8tP`6JS@M>5F1~ddf2hv!*!!wdL>}8;tYZri^;+qT=s( zaIS5T)4o&t0+T381C`7-36A0qB=Eg!Loh*5l~=w046UnUz2lTzMo<*mbk$afmBw*G z4dBcm%mVI!Wxnf!ol-ws(OBtAPH&ByYG!GQdL+_9>mC1#AW{#IgT{aGQ!i$n|myz zLrBP)c;r=-9zQ=ZYrvNJmUJM7X*jy+GSRUy^a&Xa`sC9Lt0=uU0UjJcIOs2g_3lb_ zt|Cr3Ut>75jj1U@R^f(ySZd2~-PG>EsjcJOyoysR`~&?4r;7qn&N;N8`e~gq@3iw` zNY=qMm#3 z74+ST8vGuir%}rv>e&X5&!Ald z=SGKyJxTI@-c=mT3VfZmzjs?0m|UycF!Zw>LgfCJC!OBwO#4fJs6pC2f}ck&ir7JB z>5%j@7ZLhj_wfZnDKphRQ0g$gV3<777HV)WI^W&%NPHeGljB*l!KzeNXwJv2O&r<3 zAD^-81OBG4(7<(Z*e9#DtROC@g9FA-MqtaEI4SNsvVESvB{#$do>xvv$0?Wz{_S^=t>+v&@E{#(U2s<)r_VyT}L({rqgd zvvNG5l7RbyQMsGV@W?8lc7!uezwC^Yb4FyS2-Sjhh!v? zCBGfR^*3;zfpXFifbcKPVtu=1DTqFpmUpFDS2qd-g+0c`X5SIsR<=#`zsVNhaOr+!HQH?MgTTsu#qd?g_Mq;rR&P9CJB|2wvI^sd z$5Q%644@AS5@_>4{V2-@pY2+FF10a+amEUml}U({g_%oU(lbp(TlYTPo`>G5=6_I| z=@K00%W$M(ve?z=lF%kD@2n}YAM<+T&__R~cgy9~VQ|i4gj9bEm7ye%YmKg$`vOdr z(x*2U4%7q(bI48#tH}AXVZ&OZxA*j;z5@PND5i0AB^#yev&ET>2<;-q_C5?jhHXY zHVLcaK+vkFq#}H+capGEDtt|VL9NEq@w?`4);!aPq2hnp(d%ziH*)6>!fyz9`a_*T zRcZOU$C|-aYwj%nvI|x;iAk~Gv8g_9J;xta^Z{mGp2z4N7=Xi35lkHT>`C?j&LCW&%2IXI{^pB*u8El)c?%tvYMe0A4AVmGX@ zRvB=U$ep2C@rzsVe+6=hhXm{2s4% z&Nzzw&ZvqZYBAQ0Har53yc+;I!P6oZpmYcc3RQ&ut&P?4oOai+#G)2H&<77o2iwa8 z1=Z)D0g@t=#_|5YeCNydpT(wLqgq0u78&v8;MQQ-y;{Sg^T1tgQw-(Kp|k9-M}Ath9Z?$K1rDOJDhaF2EqfFv zl@zI!e#Mbj6Fn!U2~0Dpq$R%x%7ld*T30Tl@uGNfAn0JBuXNONd_d7~t|Cpcf7fI& zda$sM(M~JR0uq7Vn-q#nv^;lL+wUYO8KU;|o**jq!iTLcDyVV}4)*=&^4c>De~Z70 zSZyG1n=aP~W6u{4sQvjgbSuKz#`MGltP*U!X7!fJwBV5Ay~LDPbh(;gDPGQQAW3%# zS08T$C#^E6jxe*P2rJr3{C!k?pw-6HJ?^DGgFHI;SUA6x^j*NXP`+JprjP9q4_$26 zl@#CTSvv~&D9l=-Eu@E?h~ik-ukpo_K2kg@8dL11!cF_RSKv})!}vY0osnU}W4qoE zI&(8W0!<+t)DMZ%{A4I5h&dmp#c#gY-J(GaKB9$mLoF3V5j#tL(!2b|T6{>PjywaG zc~=dJgP1`t4v%vw4w2LgrSDxWq&#VJr9|8)b3l7ld8b z!N>zi3GrGhhM9RUtv&syo!A5wk(T~v+!7JwNawBh)fxsC=cEKIL@O~ZJmJEmb{&a! z`)}V63Z|azm$%q`{o+l*6u+Cvas24M&`zRVpd#y`f}Y+&c2D$WdEhZtW?vm7mE>#$nRk`CO_nVs86>Uj`#w}`}F3HJx(hOwjaLZHz_E1Yg(H6 zVBXv2=V~QFoFx9Ow6D(UbJ14c40tWRQhoz@C{r7M7!4BD|LTEIo<(;^SNH`{+C-9@ zhyX?Rbs&kNW>_E3`j@dAvSJa7QcDF;W(;Ik5!w_}dCMF}z;(v`DJq$#5J(Oo={5SH zl^~b>-)w&ta&R{)YvCo)Nk=GhOTn}!S7c3OO8fR8lBs$b3)g#u_iSS6-PM;0oycy$ zDg=vEpcwPlcQi8ZTJoUWnm(hm%byKA9=R6Ey1$b}TF8^Z*rkf?Kt{kqSq1y$eb}lL z>fj2i_?g^!qEE&2ZtJ|NH80Oqk5qWr`a9KfoF}b{=?;(F{hM4GMTc~|T3o#C0`fu0 zRSb5YE5rQmQ~$x;z-`r;>BS(^Z90PT;L>Y;jImeAXzEDMv>_r}0&NM*p5d*J-?n>o zwt9QTIkzun#gJG!4`}YS|6CSW)8*Qa20>R9ueLv}Nu5QHD=_#jB_q+;G1$mH|6%u` zBbW(b+PFV==Nnx7Ehr*e%llXf>3RP`lYmAB7IsW8KJ$zmC=nMF!i=^z>Ajeow--FV z6C%Fl(Q#HJLJ_bm@>6!!-4f_Y3AARGj2eVUT*t6Xi9**N#bXK8%D4LQ%&D|IU-6?H zsck);9a=c-w~ljO(XykrtKD z@(Er~RqXiMy_5HNpJl3hAR7(@TcCC6;`BS@t(|5;u5Lp+{^nhxr9#~q@2&oqodA5` zQl4exqwQ7q)G{!A2S}j$#-dffOMcSrI92%8c-J)YaZY4YW#Dyirfh2E6qW=`?Bb{ywjk-K^d3Y{Y(nTDO! zKb*378$~GY{l%-b}NQ6A#0^^oAI#mU+&-czxY5i%&Oqw+2S zc8pJ>;ZP)6HFzCWV;jJhwyf=nl>;`6FCU`3U-;deu~RQ|A( zNg^BeL2@TuL*ksuU1Iq;2*olpkhWSUFMPQ*%$yz*G!s2@;a+_9n+;4HjstYX(fn#z zV68;|IYSgGc)t%#DG{X){vj$h49*$1OhX*AqeZ>73YGKU?TNfzE3`R%=xmJIu-fBV zicPS7(HEGcnE}k8r)}>6QAPBX?_)D(azkO!6a#O{qcT^Jc`Nb z!CUJ?|3H@@4LNDKr10FPTT`Aj>HtO0%DH38t}goPN(SXTpbar%S)$;OV9did$Cmug z6!4{S#wFcXj)rwV6=zOwX$y7>z>RoA2VE@9b#8?}C^zEU9U2gr> zQz>-nmV!Dip&vIQq@r_Z)NFk`gktZKNa?nHw6Doz!JFmH2Yk{WfKuT;vi zbQm-d2du$TFW~PA91S9w8fIoI9W&~<yIir0OliDd{8p;(UmLBeuq>4t&Gws2?x$ADK}3dQC2GZ) zK1_m_;5}h8#&ro??I}iE>mbB{sFZ%^PRoa*2OqOv6ynos2f6yB0Sik`+AhF}iFJ{A zJ)|4Wc^v2IV|oyk(b*=BQ{a{su6j=vgKQ(dInYF`34T&VpB9cjc-!dc#doz2sjJ}c zO*vU^$`W^M<)AGWU$yd^*JxLK{F(gD$<{|jZY2uH!3*0Do@n!|nyV`NwdC$TODeuO z*gm*trM)u6@>ZDC;MkD)cBM}xuc;g%V~8`98J1r;K!d$R5F3o?2We%2Qj-M8t4x_R zt`i~5@K+xjvt3fLJMqurbY*x}gQ-b8Y*eOl@>47$q(+jGL^mtxhIGsN$S(Byi!!jl z!=c05(fJhM-REJ6As{h`DX`I1f$qrHN;k(wz^Y} zDn?m5RL<*|;MSoa2QFexwRv%Y!CM#OEDFy0`Qbemd`SNnRNkid2Q&dKr`W9sXrh}* zn)4lm5jz+?4hU}8rr}j|C?A~Ud32`d2Nq}iX*2O`B1Gm2?KhEwF#fbHXR+`c=ok_bUB*2?__43vl#x9neJ#_00I`e>myck z$!F~9G)l!Fr`=&yX5^Ie)BLxyr`e9l%KLAloA$P|ebkN)1P-{#IshRqOl=OT}&$c)8bQl%32)9*@^U6Xe>NoV9_bO~h|2tPCId7M!9Cyhwwq${&lq%Ujw zp6e_I$~j{HWK`2iDT{JV=Nml*hT{X^$0KBzwR3Fj2=?tyRSh&+hvt~pJJDz$H%STXKK_O}xj_+HH zvZQU*cDoKwv46+Pp-Ht_xjEh!lshAY6UJQWs;N=tl%#l3WKrB73Z2nuAIGPT?W)`F zP^VdBD>CF_w$FwS!Yd$;kE-kn4s)(iI%Sxwt5%$sSeWvff$-y&b!qB56MAmioNv+8 z>ij+Y$t!<7MzybXpTq{HMXhRhk7bJ)S2WBCPCQcjGhe6vLJCGGrQ^TCl?y}XNa5K_ zsgT(a9;?$2*@UV_{e(1jzoF+pI`_W4V4PCQ!wh24AS$8!AZZ;ga&zUDFx^ve22<&H z)jt!IE~(fBX+D@fKR%Pn@;ij*|1lKK2<^cvu4s&|czNYH6e_JH#cN8bc)cBRkFE(>UF=*=2}-xg-m@bs&8!M8@}wN|8R{EvD@| zf!&(PwK(Rjk7R=aNtLw4zDGGrB*AbxNbDPG(a~=nUYiD;?o~nhx;{e|EyHWqY#_sH ztp&V~I)Hmf74o6lq^t5qpsu_l?zsUj#o(%|3BlRDT&bi;l$u%5R$u$?hv>q)!TVQe>Ao8xK71A%yOm*fA2VXY=?g!3U}tEEy- zYpD;Z8_Md(`$+iRjqE0uSA>~LaQB8K4j34L*pQkq87L4mm@0{SgIR_84kZsE@#IZi z7f@uK=tQJMAo!?$X$YL!L`>$^02K|>V*NXWWnnOy)(71U_l%^Kocp}Bm{gMm1>=4f6M~4 zrx$KnKh?i~TkuFqL#gEWYr}t7qPco-+=u``BRD{T@&i&Jn~hO8uM>*PpoQ^0{mik+ zLZtB08j>nP$DyIO;QHHjHM(pUY3#9GEBG!RY4;f1eLWvO1MzByTP5UL{1C>bv)+8g zIP=U?EqNEBL4+rNOSiRMj1i;4YO?|NUw7W>{Yzdv^reUh7Rb8O9tz78M<sY4sk*jqn7s0Hs>* zfg~EqOp*OXsO`cJ!}6J5^ByFLd{yHak&&8?w&P>dS_T33Fv0t&%V2$VD%|DxHYgS{ zYv{O8w>F#!9%#m-g`_C54QF_|HTkx08Y$M3j_@oE3p0dFWt;ekjMn+&j{ieiLvce+ z4PBOkge2a~`QJUGNF+^*3#A>Tf{ul23@fHw4Y~oNRb6EK zYM%Ut(bCy-A?)GJ6Lwqda)7`^t93KJ%rb2&!x3~G;a=!mBD6<;1{kng5mY7i>-2eg~Guy>TPX{L9{mVrq)VVU6;wQJGnW7mT5 ze0~&ND7QrY#n|Q5Cp1Povkj(pqo^Vz7})dz0b#UEGw)=wJuPqUxIvcR<=Ad4-?@KR zK%(Au)!WXh8vC(8usSHkl^|B@C?~Y;SEA5bK9U1|qs`!B()pHdkAoZQNg?l{h8+Fk z!mCUeLbAHB!Fu44@|9)_Cju#5$8#Y>W8+tJnPZJzGf?@G9&59N+S7W3=tCPLC_|}} zrHZ>DsQk7(?O!I>$;~D@bf;nsA7SsPgoKaTmM7l4O}0B|K=p@^F@rq9WXFKx_ngC;=9#@O1NQ*QNpV476{ zcW!8YIT!JuzkAZT<5TQZWxUkifu{Z^BCdJ;7+A{7-0gLX6x=C~+U2nhNMTU~ghGvX z<5?uBLR$U(I?=jtY%egsKfY3CWZ7N&BkC>Fupps zH;|dA-&xr;FH$VY~4JNlJN*oVt62p^>KzS&8)?WB)%%jjK!>s|%gANXW22v@{y8kNz znTCv-D4pHdLX8FVf<5?G%CmxWaZFw^$gi=VSrTzfc&8#NywQ9*lI@|x{pr5{bAqy! zkts)-9X0q&GcDd}YVi(L{SX~9;D$Z1XltaPd>KHOvl#fRzxM%XdGj@Y3pajQ3=+X7 zPei5+|AXJi;6s1bjhFlb*}?P%k<;P`=!>s)_hUAA#l;TRW&&>JhEK(0_WLr@2%}%`i+!~>99-2zv^-YK%UIxGB2}L+v}hjY=31xN(I{37XG@$6nLz(+TjIvf^_M>?Ni_H(*?VRTSovGyMhq;c)e45ZkF4-eu{wZ$i8{QNLek8ww zF+~%hwZSSHcqZiNF0i=ECbc#}7D{K<|OwQCUW^3Sym=`hPxer*1ywyi_U3scITREadPOm6RWZ z4-aI|5cG^Zv0GZad(}?dHB1W4e$s@r%sSXnj?>}#;z_zxh$V`BO{a79A7|9un$Q(C zKnx_+Br%g&W?;jM@E6+q{;@?|Zq>`$DvrlMXHZ?4BdPS`zYqE}+4fCp=27cN1D zFaP^Z^1H*+k1~pWX}5}!1KiXx(u>%qd&f#wvCAa`?Y7kJ)XmD*DDo*Y^<+9JIyb~9 z0~K1o8wLy`4>9*x9(wJ$|badEabB!!xSNJF5Gly`&bG&SUjvf^X_>5zrF!Q^oX2!Llal zeU_HraoL3mJ085&UTXYd+?{smsPE;pI!!zD5C>kdd;M1aNOs&)KiN@+sM+w5EpLDPU=+xAXPF23PL0X9EwkzV}`de<=t4bKx z!j+I42%bj2($0$Su}}-)O%lZ~_Xxt>M~fMR1E?FGS?w@TS2Oz)r4htnk#3b^7pX=h zBRnwOX<2gKtexeTX`-dbpt-$Dxo_R$aH7X~#;#D&e+cnjJ$Uny(dFZJtRb1S8z|JL2| z@4}TI3oyOnCs86d-&#c2^Ii`Itcha=jE8=WO(3=@aT(>5ZaDj8-JLAQ>kzbtUbv<( zC1EqAQSPtik2IjnTRS{s9Ap2|&3i5XP|8Waa}u|gRRSH7h|YiPkKU`NDQhtdg_Vu< zP(!NLKMgG1s|Sy)}%~nL3wulK08d<~=haQ~pu33jWmH ztI%V5Y5u;2SsJVy8PROK>!1AK$Cgm*ODH|9{Ne@)SD)64?RB*tG{DNO{j?Gse*eYXFc!T`D`ysJx)UZwdy~rO3r+=ph z!sESlC|2ysg$(Z<;?Kzx5Q7kG$6e4`Q4l_9Tb1SgDG%-?4V9!Li4Xu!{C&}aw&>?a z;|K3ht&!}fhA11j&irOC(g`GKMy!-}@L-p(7#uR1A`a3xJ zUrx_oR8Rdy^FIR22>@PjiJPkFUl3#dDnpbZ8-$$NMum_=?lX)09$}~^4j!-N0NLkI z-rHXo=FHK?^wB*~vXE6@=t$@%WyvXk#1r*lxPWpBqw;^ePoq3sw`8W3fPZeDZv4#rLO=J~bJOLxh&K=j%{?FVK z@YEX$mFGb7)B2Y7&zHKS=S7Y?0)+>Z^d&-h2{8bcq|iwXh3ak>;QB6e_a50*0&haj zLAX6;qWfhI0(!D2qBr zS`(GwiwHnwF~p;5l-Z@MWJSCEohRtU20W3O96e_nK^Nz&OUi(OKa5=4VkRyZ6ssHt z2=H%O^*0z(9wPv|F}4T+Q48mXZljD@)$AdutFG{Wj@krd+Xz-V!hZ<8DR22GA5;Hp z)Z-QQnaThd_*Zu*F1;HJByh3mlB5urm43A;@o3Gtu!^kgmK+$=6NRQNXW@h%+!v{)~Y3 zp3Osz{pXL$#vWX4=dbC)7k6=8!A^@c5zQBfR!XXg>$%Ail|t0sbDY zD)*ilypV@kA|^zoNgxPf3tb9v08+o9FgPe5a;&ZRDt&Qi9-Quv1A1n-2(4Z%_z z!A~O}aYPXo#ky7K`{JxGP~xlr`G%Ol#7}Ri;fu)dGrGZ2991wv-{fOLP{2C#`WoEb zF6$q1ph%&OjoQbk7s~ml56e!uEFQT)vBnP3h4AZP)SH`fcqNgWzsG@>&q!^(b~H1DaTr zjVpE40SC=%H;aq!dl!>Zh^O$`CSOPMxN#Nn9pMD_D>lP;=(y}dXEXFRbr5Nv@AgyK zwj#@{LzOg~so&J|HwfE!qq$QPof|a~0G&6GZ{B9zYHk%ibeyk1FUni&ap)nkQfVH}*7;)%z8Uk4vo6z=Wb(i3Gs}EVOAeDwr%h@#TGy{Xi0=UsZV5+Htza z@QU_j@mnNvf}@zxE9%$T~4T>P$Nl8M`zgimet`rA4{oifiuc%7O6BlEw6meJP}8u9h^;8CNzd8A$5iTP3q+ zA>gg`Kx{Z}e=-U%QD#v=`b-tF*XFx~>IxvIXz^_vATH)*HDTZJ+vWCXhPJS_?f&HT z4v_W^r^3kPXC;Xj+GwtI&lu~j5Zj-~>um7sX!6w(;ZXsGyxSziVZ3d+k2mhp8~AOi z-d8@vCnOV*%T+!KBkk?glefz(qix-js>A;VyMiFV9+2*9yicq*GTTUhN^dMSJcHPo zRM$(Y2t?Db!>A$vdcN?gK8rG8<p2eQZLZHx zVAKnvPG0Z&gx9-03fo?lbtxi6{G9XK0Q``61^BF&Vnn%#2Kn zHecg1ddKhD{`3i8((Y$xQ*=%*Py1?Y4-{I(^Y@3frxzD-kspL7zgx-go14Yq3=@m! zsy}Kv%A$J@UeVTn1!`r8buc^a8@9GW(S}Wa7BTXX2f!$RG?Dmyp?22QFH8YWS3e zh)9qQRnG&uCv#QS%xJqtpiTZ*OSIN2o)sRrHo1sU8t|)1{2|WMP-+_mh)Nv66mhN3 z{XllMIKQ|UgOXOJ@c`TM8!mk<&$9mH%3k!KE*)luE61b9?xu!#cEfS2Ux|So7Fwc?U?#i%Vz?s>u6Lu^NPomD<98D>9X-svDPpw3+(^qn zp$bLT1|%QNe=td*fwF2oI3kAa=0ER8)e_7E=4C?~a|bUAegEtc=;F0iluiYHVvsyi ztg&827GOY(sgK^@`x3P5jgo?m=&sf|+keOsE2$%IMe5yAHr<1BX`DxgAJez$KDLrW zL(-hEMJeYHYtC}6vX#(?_tS8Ds2@5)8)xlM%!ZYkcIfRKEmu@+CrCC2GTt zESV+}2SFg^#|zcU-osB|?RWb0p>+|=VV(km&ky4mRpK@w_+-P<14h?}B!qSu`8CLR z=smpl9B6dOH$cP4dQa?SHu)|Hbx0+h>srJ~XBwNJ)b8_Ml(j3i#XsFs_wSxx8S0n= zF5!#KQIjo|J;_~$bQND{Z<$pZ#3BvcUF0y_4&xpaT=0vh3pPy1LyL*S4N5*N0pAk@ z)w(0R4qM2esyCu$S1DD^THiS7~KYxenboWCWmpiibhcl-j zwi0|P%?F-FdL!A5EWZS{d{Zu&5@V)&IyC8SF?u<`AhmJ%$9;V|!~weZXevQ4c@|9| z1jx{s{6dAXO&F+`=0qmoBq~CCQMgS`(vE1)j(i4hYWNy@5z+oT0U(~NXtPGTI5l8=!KHwXAgIMJJupvj?)hT?g!7};Cac`S0!@st zhWi&BzZcCBp&c>PyaU-gy&h}u4A((HZF_>#{kxiW2B6#6Tf0Dl6WlOEvNFzTdYjJf zXa;xs!ROW@PkOE)Y0_ath175-Zs2u&fMfw-a8NSUIs%>z9e9Al7WDkL-+|S;IWRoY zHkOWfM=^Jn9pZz2-TKRT)xEBtPhHE2Bice@iF@Q~*GF|O-nG=}C7Yb-U`D>DSIaR; zKfv8%a@J*W1y0`#jVMK7jbZ7AdAYB=?IQ-Y>~Xp@iWGRwq4s9(rKu^I27|fya4!gp zVdOz}+zAju(6FAnevm+5El*F+N}F>>)VuDg~E<7_zvy4^gt7D}DeK|IrSh z_nG}iiZrM7=r|H>C_VZVvHSt?2Ctf;$-X^+ZthAKOH8o)3Q|}e0HIkrgit4#e2ZbV zftbU>En>X#Lgc*ItP>7B+2--7DJ4fNMtAYFi}&Lyq>vES6k}_1!eM6AnJzZHf~?6Y z6aDlqg+8IJ5QQ(nABj4fBQ3@0WPY=WD3&)@G2j289EQr6JbQQG%8neICx_{lnBa&| zzNFVH62wE9p!->xj<~CB9-%>=0ZSRI)CWigB*kM7vcUNuzi%%I1#anadK)W!0YUzq zrNABEVxOP=7%wv>*XkHqzUikN^ceDe`&>=Ret-)`?OnM2+?#Mr6p-(Sr{HgEB0o1D zuGfS0%vxl!tsPV=iT-~yy=6dD-S;*;Fmwz^gLHRycXx+`q;z)<-8qDaAQDPROT*AZ zi6Y&tbSWYAocs5_{}1!+%!$4C*=Jp`)SV z@{A_ruG{(0mpX}NE_lynh9twOeXjJP`&Crm9&XHJ+#O@uMYz_k(O|SDh~bUZ@d#}v z`tMN>p+BPz$qN%XfAM#lu0e~=O}zgdaH(lvG@k##3`modcs=O~tSZ48X7m!*EG(Ms}GI^2W_u<&gr&m`XEVbiS*-IRUCcZ z8$x+9_4(j1UBvPoX>|pG9;-MarNReO{Y7(>SaJNNECH3Ueg61*-+6h zU*gsq#*kG_%f_KIXR!^DXAjv8av4u1uqHa)aVRQq5WT&T*zflMJaK3Ma#SLm_GT@u zVzmP|^&nR;q%@H5jQ6!#u{Vrut=&O7=@R)NcRZ(5hY5N4c%%2%A~jVi4&>6 zmGVtDbo*tJ*EU~~yykqYp_ncVgwMK1`+7<}a1|~pj zFO0~5ZWBzp{Ma}bE) zGX{<^B>+H>f@&^!*kq)|Gl=A%8Y|E4Ay-)swvJKg18P8qo0svSlQ$G-@6o0k?a5x` zGHK+w(JfiLuE+fQcTPGPm=YcoZLtP2kyBYNbaLMBRg|&f!hL6-IFpfW8o#*G%{JyT zgb@QLOa%_(Wn4{-+uCt;O}J;*WFsWlgUf1M9o2iDTTm*I6McR58O5at{J>hFxd{W; zsyT9+rb+yM!9x4Ph4-UAeQklrnfs;|2wR14=sx2k472~$HuL@Stm*e0KoBb0lNHYeD;E5dTivzbDF`_rkFN$VoOfmz*(Vi zHuO@tphAqeuV=wymrT%4Abn&2&{hnll6yDcfyoMpmdXNj`jqsEDkPu=5aXd88W1L^ zwv%{ftIj)o?h)y3uBRR@nr#4Dl&U`W|?WN3i~*K`%q_x zKig}a!@#e}dDnr2PI0%Hx`x)^AIHSxq{gr(me-Au{O94=Mn`BFw}QN7G&eHjx9nbM zy4vJA^+;{tNMzwVz!bZU@~v)jbA-z6(}{K0jyFel!cnvyjDX&4AdtRCzhNYzqa;9r zvK`A5BP`}pA4j&9u@7k-^bIYwZyT6GS}t_7JTb>BxvXG~5s^WkNG5hJoOwM+i&3+F zVeKp4`#M#v<37`LknioH^WXdWVi_mn7lFb2Uf7nz(R+!*+iF8V{joP3A8{V1gcFIq zfhMBx3pjo`+PEeB4lV|_kRCH}iN&v(VH_GJg6020X@CT+kYioSld0~}BAs=xdww3! zmd}mR9s&9bGrEzZ+O%$E>yMk>+wrP^VhOI*Hy7!The0MFlbkRED@YjWEyoziIXDX! zj_h>Hpo{wo@+x&!P7FWj#VyWxkqrI6Z}^JdlH{VuWC!)4;f_)tkJs@Ys1Oo)EUblk zr1E)fYZsycO(jh*iWv44mW~}|AmcCA*`x5DsKDuc{U{KmhLQ%662nWN&k95_qUQ!S zB131=nZz-EweqWMt#E^HEf|-)VuL)TVe~j*(SjK%z_~Oo5jsK$2_C?~jJ^ z=r+uOeeG|s+Y@s(UQZhQEj%VXU;LaCO&aq7;}&vx9Y$(f7%`;M@h=4oeFrUYDpW!i zE>W=MH^a{9-jSf3s+ z0YXDPM&@U!4%#G>XI=t$Dd$uOkT$;se#)pz3ZHpB?d|i7D6y$3^Vi zhA;pP+p%Jo5A%vRyZ48+vWsgV7{jbm;%5M6f_!te>!I|!J!U)<53iAxC_-pQ zTy|U3aolQq{iR;KHIhughzea^ZYf~m6GWq%kG9ShY?eV*%o0t78me7W?G^+mt-6qi z?OP+aZT(q0NRwqphiD)*R8s;h5thQ+Ypn@>t{T<~c(qcRr}-`P%3t*2`-aNwg2~H^ z_noN?^Q*vPNA#B_IQk^SXC*}4gG5O&I}Jkiu^6LpZLrR@XdKwk&@d6*h`V*PqIi4H z?wt(P#{qQJ@xuegX0LDHQ^pj*`Ar~1)q~jFtK~qbRE?(o#SXWR_jm3uSZ{3B@Fr(7 zacQNAkTG6^3dH?5bWAVGDt*k#gHIxB%0h1p%QiI_!^dvu$T2I%YY`{OaJO+t9jQ_|0~)fCER3;Z*j-6DI&hH+@)h!JEm-d$Mp(jafrMS;Gn^ijaw4V-_i3mI_W&|=lVD;BQ8eN^@1UNf3g3~&DYAcgu%3ql568&D z;9N^9SEZuYnOCm988XCvI--=y`u(f5VtRPl)uYSq>K|2`TyV+>=jv;MldfAfjU>Jo za9iLTi9EbKGSW(g>5H>i(N2ynB>#)4$g|lc?HC`XRXI zuKW)pP$P)uKzH#2!Sb4lo_f4{z{V%6U;B2dzz&U)-kP%C?b_&J8NE(s&$|E^+(Q2& z3s~;Hx4=D{SNBjhop)ci3-FSSJ<33Wzf&KZU9+fyHj3eIc1M;$50pvn2>%X0L*!?0 zZ#1iT?zc`nx@1|M;}b+Eh7TTD%I&-79}`dAL(mP0ok6Ibk7*lG2f^Yz`7?P%$w&xt zwzfF29t3Ah~Bm z;$tr9VTFrV7 z*BBlC)>IEpVDRjdpsOemaBwY3M=3msW<^J*SMq`|w+Vjh3mu6m!jd9yA0oGgygDl5 zT;hLmw??YBN`bwQUCSPZS&nyzSL@SYyWX9vtmzb`H-VJND_lisDt!(x^hFZzJcMi@;8b zp9V&-D4La%g@GhCO;z!60iUUog<7Q+R|DT<=qmA<;=f8I*gnSsDLEbE;<&$1R&BuT}Xjje)sTq8 zI*+q5)+%&G@#|-s6_}yyM`KJ?&=0Z|+d5~y?{0itB*t+#H3XO|l){3e3R`(VNj$5k zkz>c{!_e&GUa^>`gHk}%2hViva4|;ga4M?3&45)!V0L^3)C<_v3zP2^-x^3d_OFl7 zgIBVAuY`7Aov6($BcZ$!rhWrT#^vH5+yb*;OAK|O$|Hnk`51*uJv>=2hu!*&0Md+CKHWh zaC2VeqD$r%POhi`nS}B&taWH*g=4$!o!XED1|E5*`*1^PK5p{6$gr07i}&=&5A^yr zh?>Q4Bt3$3`nx=ck5*B-X@WK=d8t~G@V{CC2q6(bcyY6Bbj5AVZp=)n_lCc=iLT+O zD-?Go)~dhd$o#mgs$sBGf8X%W0c0^>|Gsr=@W#o$<69^q=9YfQ2b4WxbY^QrSJH2rZ3B#bzoi>`COw#q7e{teV6#B`BoaxcW*nHW=X7H*z+=L$!*4aU;A4+_t{klcISChYW` z(8OuI0cW@;(h*W>faM@_F4&)qRXsp5Q8M)xUBvzWG|}v-53jD3utquk^4yhy(zk<+ z=DY2$#Lctx+uD#hvI=jTp*lH!0_C0JXpE&^qs@NLxFN&KiuXWygXX8Tia$BF-w9K) zG;@D2)}d7mvPpfh4D0^&)dD+O)&c@@{Vo7N2emkkl9Cz77cJjhRdQMo~=zfcn@wXvueLq(+={D1y^WAf=+H|M&( z1WE-ch%XD1)>O)US&f@*UBqS^?I8%Zh(vcL4JR=Bs&gIl!2&`{RG30+Cs%MS&Itc} zjM3Jns06GMk{Za=O0S*C$%+VRYR_)WW@1RNN4D`ImE}UJLaWIZ652JNybTGPu5?46<_W^ zlL+&($}n8-qQK0iED#hlR9q&AL_5k$(#GePp?}Ro=RSqH5|3-y=(1I0t-tCs_!cqZ z?^`19XXJNpih(F_0mFjZZqZT{eDy>h-8?cvYNs_f8&~6hfJKb;?uz+x#7tVTET(2< z`^FsLs~yT(i* zM2MY)B`b$!v;tswKF}8qnfe&4WqLK0H?BJfWI6x3rFAqTxGeyKQiH|bHp18KJ>11< z8|Mwl8GhNgD#iV0uV!-wV&!kGd7k3d3qY6ZE|(wOB0o7@-jRO03yvJG!~wJ)x9$27 zOn*=er-O?a#!{oUr0r5y6cRuD4>3(Qpoax4l|-A_D(?Vpo=n!pDZ3P}Z@CY%~!L};;l zAlfWmo|ks6QO{0iy*n%H^=RqO)MMY6Cz=GtRq3EZ3yphZ7~et8OO})0^YqmZkg**6 zWYKvlDp1YeVEe%>SUsT-j20p+2V#9=({z>EOc;nQc5~5(*?W6&=IY7&3;j}7TX~Il zZ%Kx9Z}yk+GFJ=n8}eUog*%#jrg78KTzk^lnr-bMwE=9O<=cqZ1k2+0@ymPV$F(;4 zm>UELf(vftW%}H(=bo9V>MP<|JhQ<&JH(v7Kn0)03Zn158kkPasm00kh&!!mImoI@ zI}!vL(FGhiDO+2Ees16%|62bu?R8h{Nl<-uNZJfTw`aAca;20wYJ6 z{0<>nQ*T!PtxKE9yke_pl20=5hYnlqTdi#i^b!gS3iafa=8J?JT+P%xs6jv}!SidJ z>q{@h7Ju6CJ9Bgq(7B80syn32TvqdtO{SgBVJJ?!Ih)V_cGh)~y<``IFFFOfTlmH% zWZBPNZwL8AH7@&nFx;n1)TDZn8*m@(YO_36l3n^ZRMiQm@O^nHMc6tLMn~zwi7@i@ z)w5zkFS{mtB>0XL)tC_aQfvP<408-R=Yd)Q`=psf*u8Ayq1;&X@IZC_8cLp`U+tw;AQ7k!uX^f&o^^=$n@=v) zY5BK>QWQ|M0RIJrEjq1EH8QP8{0gSfj3+Bu%B8#w1MV3%-aSU#Z$-zcuYrSR4 z)YsPH^QpEDc%rsHfQ{)WZyYN)pEBxsqmip*IuMqhWv@O|@T1YaW(`Z-Ax9yK2_d^B zyom?jrM|y~VrLmor@@&wjW+dZkDM&E-cuF5@Tz{^ZkF`0i4VPU)pPyT_T}^ar~Jmf z�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