diff options
author | Lucas Fryzek <lucas.fryzek@gmail.com> | 2022-11-02 18:35:40 -0400 |
---|---|---|
committer | Lucas Fryzek <lucas.fryzek@gmail.com> | 2022-11-02 18:35:40 -0400 |
commit | 1920b397fad8b1d6cd0233a5aa9a12365b16a287 (patch) | |
tree | 2b10edd83a77f59dcfdce2f3a38bea4126e06fd1 |
Initial commit
33 files changed, 1803 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d5a1572 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.swp +build diff --git a/assets/2022-04-03-rasterizing-triangles/Screenshot-from-2022-04-03-13-43-13.png b/assets/2022-04-03-rasterizing-triangles/Screenshot-from-2022-04-03-13-43-13.png Binary files differnew file mode 100644 index 0000000..064b4ad --- /dev/null +++ b/assets/2022-04-03-rasterizing-triangles/Screenshot-from-2022-04-03-13-43-13.png diff --git a/assets/2022-06-09-baremetal-risc-v/PXL_20220609_121350403.jpg b/assets/2022-06-09-baremetal-risc-v/PXL_20220609_121350403.jpg Binary files differnew file mode 100644 index 0000000..5fae2e4 --- /dev/null +++ b/assets/2022-06-09-baremetal-risc-v/PXL_20220609_121350403.jpg diff --git a/assets/2022-06-09-baremetal-risc-v/riscv-terminal.png b/assets/2022-06-09-baremetal-risc-v/riscv-terminal.png Binary files differnew file mode 100644 index 0000000..3e3eb35 --- /dev/null +++ b/assets/2022-06-09-baremetal-risc-v/riscv-terminal.png diff --git a/assets/budding.svg b/assets/budding.svg new file mode 100644 index 0000000..7ed9a87 --- /dev/null +++ b/assets/budding.svg @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg width="60.975mm" height="85.691mm" version="1.1" viewBox="0 0 60.975 85.691" xmlns="http://www.w3.org/2000/svg"> + <g transform="translate(-84.962 -110.58)"> + <g fill="#358856"> + <path d="m106.96 161.58c20.946-12.093-21.999-30.358-21.999-30.358s1.0535 42.451 21.999 30.358z"/> + <path d="m122.31 162.4c17.102 17.102 23.63-29.107 23.63-29.107s-40.732 12.005-23.63 29.107z"/> + <path d="m108.12 153.32c23.362-6.2599-13.393-35.018-13.393-35.018s-9.9696 41.278 13.393 35.018z" display="none"/> + <path d="m117.82 160.32c24.186-1e-5 -1.2921-49.748-1.2921-49.748s-22.894 49.748 1.2921 49.748z" display="none"/> + <path d="m122.37 154.14c20.946 12.093 15.291-34.231 15.291-34.231s-36.237 22.138-15.291 34.231z" display="none"/> + </g> + <path d="m90.892 157.59 9.8659 38.676h28.021l10.363-38.676z" fill="#b35642"/> + </g> +</svg> diff --git a/assets/evergreen.svg b/assets/evergreen.svg new file mode 100644 index 0000000..544159a --- /dev/null +++ b/assets/evergreen.svg @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg width="60.975mm" height="85.691mm" version="1.1" viewBox="0 0 60.975 85.691" xmlns="http://www.w3.org/2000/svg"> + <g transform="translate(-84.962 -110.58)"> + <g fill="#358856"> + <path d="m106.96 161.58c20.946-12.093-21.999-30.358-21.999-30.358s1.0535 42.451 21.999 30.358z"/> + <path d="m122.31 162.4c17.102 17.102 23.63-29.107 23.63-29.107s-40.732 12.005-23.63 29.107z"/> + <path d="m108.12 153.32c23.362-6.2599-13.393-35.018-13.393-35.018s-9.9696 41.278 13.393 35.018z"/> + <path d="m117.82 160.32c24.186-1e-5 -1.2921-49.748-1.2921-49.748s-22.894 49.748 1.2921 49.748z"/> + <path d="m122.37 154.14c20.946 12.093 15.291-34.231 15.291-34.231s-36.237 22.138-15.291 34.231z"/> + </g> + <path d="m90.892 157.59 9.8659 38.676h28.021l10.363-38.676z" fill="#b35642"/> + </g> +</svg> diff --git a/assets/favicon.svg b/assets/favicon.svg new file mode 100755 index 0000000..3562c96 --- /dev/null +++ b/assets/favicon.svg @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="12mm" height="12mm" version="1.1" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> + <metadata> + <rdf:RDF> + <cc:Work rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> + </cc:Work> + </rdf:RDF> + </metadata> + <g transform="matrix(1.8047 0 0 1.8047 -4.0184 -2.2793)"> + <rect x="2.2266" y="1.263" width="6.6493" height="6.6493" ry="1.19" fill="#1a81ef"/> + <g transform="matrix(.75 0 0 .75 -60.944 -146.98)" fill="#fcfdff" stroke-width=".26458" aria-label="y"> + <path d="m88.108 205.8h0.89958l0.84666-2.2966 1.9897-5.1012h-0.84666l-1.5346 4.2756-1.5028-4.2756h-0.94191l2.0108 5.1012z"/> + <path d="m86.443 198.4h-0.94191l2.0108 5.1012-0.92075 2.2966h0.89958l0.84666-2.2966"/> + <path d="m89.384 200.82 0.94325-2.4183h-0.84666l-0.48816 1.5928"/> + </g> + </g> +</svg> diff --git a/assets/favicon_original.svg b/assets/favicon_original.svg new file mode 100644 index 0000000..0f1cff0 --- /dev/null +++ b/assets/favicon_original.svg @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + width="12mm" + height="12mm" + viewBox="0 0 12 12" + version="1.1" + id="svg861" + inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)" + sodipodi:docname="favicon_original.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + <defs + id="defs855" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="3.7819956" + inkscape:cx="-17.451104" + inkscape:cy="66.763695" + inkscape:document-units="mm" + inkscape:current-layer="layer1" + inkscape:document-rotation="0" + showgrid="false" + inkscape:window-width="1530" + inkscape:window-height="1016" + inkscape:window-x="26" + inkscape:window-y="23" + inkscape:window-maximized="0" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:showpageshadow="2" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" /> + <metadata + id="metadata858"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="matrix(1.8047145,0,0,1.8047145,-4.0183802,-2.2792785)"> + <rect + style="fill:#1a81ef;fill-opacity:1;stroke:none;stroke-width:0.1005;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" + id="rect1442" + width="6.649251" + height="6.649251" + x="2.2266016" + y="1.2629579" + ry="1.1899979" /> + <g + aria-label="y" + id="text964" + style="font-size:10.5833px;line-height:1.25;font-family:Cantarell;-inkscape-font-specification:Cantarell;letter-spacing:0px;fill:#fcfdff;fill-opacity:1;stroke-width:0.264583" + transform="matrix(0.74999999,0,0,0.74999999,-60.943862,-146.98325)"> + <path + d="m 88.108292,205.79658 h 0.89958 l 0.846664,-2.29658 1.989661,-5.10115 h -0.846664 l -1.534579,4.27565 -1.502828,-4.27565 H 87.018212 L 89.029039,203.5 Z" + style="fill:#fcfdff;fill-opacity:1;stroke-width:0.264583" + id="path966" /> + <path + d="m 86.442598,198.39865 h -0.941914 l 2.010827,5.10115 -0.920747,2.29658 h 0.89958 l 0.846664,-2.29658" + style="font-size:10.5833px;line-height:1.25;font-family:Cantarell;-inkscape-font-specification:Cantarell;letter-spacing:0px;fill:#fcfdff;fill-opacity:1;stroke-width:0.264583" + id="path966-7" + sodipodi:nodetypes="cccccc" /> + <path + d="m 89.383738,200.81717 0.943247,-2.41832 h -0.846664 l -0.488165,1.59282" + style="font-size:10.5833px;line-height:1.25;font-family:Cantarell;-inkscape-font-specification:Cantarell;letter-spacing:0px;display:inline;fill:#fcfdff;fill-opacity:1;stroke-width:0.264583" + id="path966-7-6" + sodipodi:nodetypes="cccc" /> + </g> + </g> +</svg> diff --git a/assets/full_plant.svg b/assets/full_plant.svg new file mode 100644 index 0000000..ce301e9 --- /dev/null +++ b/assets/full_plant.svg @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="60.974876mm" + height="85.69059mm" + viewBox="0 0 60.974876 85.69059" + version="1.1" + id="svg5" + inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)" + sodipodi:docname="full_plant.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <sodipodi:namedview + id="namedview7" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + inkscape:document-units="mm" + showgrid="false" + inkscape:zoom="0.98520767" + inkscape:cx="-23.852839" + inkscape:cy="245.63349" + inkscape:window-width="1920" + inkscape:window-height="1043" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="layer1" /> + <defs + id="defs2" /> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-84.961725,-110.57618)"> + <path + style="display:inline;fill:#358856;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 106.96114,161.57546 c 20.94591,-12.09313 -21.999415,-30.35829 -21.999415,-30.35829 0,0 1.053503,42.45142 21.999415,30.35829 z" + id="path3245" + sodipodi:nodetypes="zaz" /> + <path + style="display:inline;fill:#358856;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 122.30661,162.40412 c 17.10227,17.10226 23.62999,-29.10711 23.62999,-29.10711 0,0 -40.73226,12.00484 -23.62999,29.10711 z" + id="path3245-3" + sodipodi:nodetypes="zaz" /> + <path + style="display:inline;fill:#358856;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 108.12393,153.3185 c 23.36212,-6.25987 -13.39251,-35.01773 -13.39251,-35.01773 0,0 -9.969636,41.2776 13.39251,35.01773 z" + id="path3245-3-6" + sodipodi:nodetypes="zaz" /> + <path + style="display:inline;fill:#358856;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 117.82191,160.32437 c 24.18625,-10e-6 -1.29214,-49.74819 -1.29214,-49.74819 0,0 -22.894127,49.74819 1.29214,49.74819 z" + id="path3245-3-6-5" + sodipodi:nodetypes="zaz" /> + <path + style="display:inline;fill:#358856;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 122.3659,154.13868 c 20.94591,12.09313 15.29135,-34.2312 15.29135,-34.2312 0,0 -36.23727,22.13808 -15.29135,34.2312 z" + id="path3245-3-6-7" + sodipodi:nodetypes="zaz" /> + <path + style="display:inline;fill:#b35642;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 90.892009,157.59108 9.865921,38.67569 h 28.0209 l 10.36312,-38.67569 z" + id="path509" + sodipodi:nodetypes="ccccc" /> + </g> +</svg> diff --git a/assets/me.jpg b/assets/me.jpg Binary files differnew file mode 100644 index 0000000..134de31 --- /dev/null +++ b/assets/me.jpg diff --git a/assets/minima-social-icons.svg b/assets/minima-social-icons.svg new file mode 100644 index 0000000..fa7399f --- /dev/null +++ b/assets/minima-social-icons.svg @@ -0,0 +1,33 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + +<symbol id="dribbble" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path d="M8 16c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm6.747-6.905c-.234-.074-2.115-.635-4.257-.292.894 2.456 1.258 4.456 1.328 4.872 1.533-1.037 2.624-2.68 2.93-4.58zM10.67 14.3c-.102-.6-.5-2.688-1.46-5.18l-.044.014C5.312 10.477 3.93 13.15 3.806 13.4c1.158.905 2.614 1.444 4.194 1.444.947 0 1.85-.194 2.67-.543zm-7.747-1.72c.155-.266 2.03-3.37 5.555-4.51.09-.03.18-.056.27-.08-.173-.39-.36-.778-.555-1.16-3.413 1.02-6.723.977-7.023.97l-.003.208c0 1.755.665 3.358 1.756 4.57zM1.31 6.61c.307.005 3.122.017 6.318-.832-1.132-2.012-2.353-3.705-2.533-3.952-1.912.902-3.34 2.664-3.784 4.785zM6.4 1.368c.188.253 1.43 1.943 2.548 4 2.43-.91 3.46-2.293 3.582-2.468C11.323 1.827 9.736 1.176 8 1.176c-.55 0-1.087.066-1.6.19zm6.89 2.322c-.145.194-1.29 1.662-3.816 2.694.16.325.31.656.453.99.05.117.1.235.147.352 2.274-.286 4.533.172 4.758.22-.015-1.613-.59-3.094-1.543-4.257z"/></symbol> + +<symbol id="facebook" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path d="M15.117 0H.883C.395 0 0 .395 0 .883v14.234c0 .488.395.883.883.883h7.663V9.804H6.46V7.39h2.086V5.607c0-2.066 1.262-3.19 3.106-3.19.883 0 1.642.064 1.863.094v2.16h-1.28c-1 0-1.195.48-1.195 1.18v1.54h2.39l-.31 2.42h-2.08V16h4.077c.488 0 .883-.395.883-.883V.883C16 .395 15.605 0 15.117 0" fill-rule="nonzero"/></symbol> + +<symbol id="flickr" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path d="M0 8c0 2.05 1.662 3.71 3.71 3.71 2.05 0 3.713-1.66 3.713-3.71S5.76 4.29 3.71 4.29C1.663 4.29 0 5.95 0 8zm8.577 0c0 2.05 1.662 3.71 3.712 3.71C14.33 11.71 16 10.05 16 8s-1.662-3.71-3.71-3.71c-2.05 0-3.713 1.66-3.713 3.71z"/></symbol> + +<symbol id="github" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path d="M8 0C3.58 0 0 3.582 0 8c0 3.535 2.292 6.533 5.47 7.59.4.075.547-.172.547-.385 0-.19-.007-.693-.01-1.36-2.226.483-2.695-1.073-2.695-1.073-.364-.924-.89-1.17-.89-1.17-.725-.496.056-.486.056-.486.803.056 1.225.824 1.225.824.714 1.223 1.873.87 2.33.665.072-.517.278-.87.507-1.07-1.777-.2-3.644-.888-3.644-3.953 0-.873.31-1.587.823-2.147-.09-.202-.36-1.015.07-2.117 0 0 .67-.215 2.2.82.64-.178 1.32-.266 2-.27.68.004 1.36.092 2 .27 1.52-1.035 2.19-.82 2.19-.82.43 1.102.16 1.915.08 2.117.51.56.82 1.274.82 2.147 0 3.073-1.87 3.75-3.65 3.947.28.24.54.73.54 1.48 0 1.07-.01 1.93-.01 2.19 0 .21.14.46.55.38C13.71 14.53 16 11.53 16 8c0-4.418-3.582-8-8-8"/></symbol> + +<symbol id="googleplus" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path d="M5.09 7.273v1.745h2.89c-.116.75-.873 2.197-2.887 2.197-1.737 0-3.155-1.44-3.155-3.215S3.353 4.785 5.09 4.785c.99 0 1.652.422 2.03.786l1.382-1.33c-.887-.83-2.037-1.33-3.41-1.33C2.275 2.91 0 5.19 0 8s2.276 5.09 5.09 5.09c2.94 0 4.888-2.065 4.888-4.974 0-.334-.036-.59-.08-.843H5.09zm10.91 0h-1.455V5.818H13.09v1.455h-1.454v1.454h1.455v1.455h1.46V8.727H16"/></symbol> + +<symbol id="instagram" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path d="M8 0C5.827 0 5.555.01 4.702.048 3.85.088 3.27.222 2.76.42c-.526.204-.973.478-1.417.923-.445.444-.72.89-.923 1.417-.198.51-.333 1.09-.372 1.942C.008 5.555 0 5.827 0 8s.01 2.445.048 3.298c.04.852.174 1.433.372 1.942.204.526.478.973.923 1.417.444.445.89.72 1.417.923.51.198 1.09.333 1.942.372.853.04 1.125.048 3.298.048s2.445-.01 3.298-.048c.852-.04 1.433-.174 1.942-.372.526-.204.973-.478 1.417-.923.445-.444.72-.89.923-1.417.198-.51.333-1.09.372-1.942.04-.853.048-1.125.048-3.298s-.01-2.445-.048-3.298c-.04-.852-.174-1.433-.372-1.942-.204-.526-.478-.973-.923-1.417-.444-.445-.89-.72-1.417-.923-.51-.198-1.09-.333-1.942-.372C10.445.008 10.173 0 8 0zm0 1.44c2.136 0 2.39.01 3.233.048.78.036 1.203.166 1.485.276.374.145.64.318.92.598.28.28.453.546.598.92.11.282.24.705.276 1.485.038.844.047 1.097.047 3.233s-.01 2.39-.05 3.233c-.04.78-.17 1.203-.28 1.485-.15.374-.32.64-.6.92-.28.28-.55.453-.92.598-.28.11-.71.24-1.49.276-.85.038-1.1.047-3.24.047s-2.39-.01-3.24-.05c-.78-.04-1.21-.17-1.49-.28-.38-.15-.64-.32-.92-.6-.28-.28-.46-.55-.6-.92-.11-.28-.24-.71-.28-1.49-.03-.84-.04-1.1-.04-3.23s.01-2.39.04-3.24c.04-.78.17-1.21.28-1.49.14-.38.32-.64.6-.92.28-.28.54-.46.92-.6.28-.11.7-.24 1.48-.28.85-.03 1.1-.04 3.24-.04zm0 2.452c-2.27 0-4.108 1.84-4.108 4.108 0 2.27 1.84 4.108 4.108 4.108 2.27 0 4.108-1.84 4.108-4.108 0-2.27-1.84-4.108-4.108-4.108zm0 6.775c-1.473 0-2.667-1.194-2.667-2.667 0-1.473 1.194-2.667 2.667-2.667 1.473 0 2.667 1.194 2.667 2.667 0 1.473-1.194 2.667-2.667 2.667zm5.23-6.937c0 .53-.43.96-.96.96s-.96-.43-.96-.96.43-.96.96-.96.96.43.96.96z"/></symbol> + +<symbol id="linkedin" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path d="M13.632 13.635h-2.37V9.922c0-.886-.018-2.025-1.234-2.025-1.235 0-1.424.964-1.424 1.96v3.778h-2.37V6H8.51v1.04h.03c.318-.6 1.092-1.233 2.247-1.233 2.4 0 2.845 1.58 2.845 3.637v4.188zM3.558 4.955c-.762 0-1.376-.617-1.376-1.377 0-.758.614-1.375 1.376-1.375.76 0 1.376.617 1.376 1.375 0 .76-.617 1.377-1.376 1.377zm1.188 8.68H2.37V6h2.376v7.635zM14.816 0H1.18C.528 0 0 .516 0 1.153v13.694C0 15.484.528 16 1.18 16h13.635c.652 0 1.185-.516 1.185-1.153V1.153C16 .516 15.467 0 14.815 0z" fill-rule="nonzero"/></symbol> + +<symbol id="pinterest" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path d="M8 0C3.582 0 0 3.582 0 8c0 3.39 2.108 6.285 5.084 7.45-.07-.633-.133-1.604.028-2.295.146-.625.938-3.977.938-3.977s-.24-.48-.24-1.188c0-1.11.646-1.943 1.448-1.943.683 0 1.012.513 1.012 1.127 0 .687-.436 1.713-.662 2.664-.19.797.4 1.445 1.185 1.445 1.42 0 2.514-1.498 2.514-3.662 0-1.91-1.376-3.25-3.342-3.25-2.276 0-3.61 1.71-3.61 3.47 0 .69.263 1.43.593 1.83.066.08.075.15.057.23-.06.25-.196.8-.223.91-.035.15-.115.18-.268.11C3.516 10.46 2.89 9 2.89 7.82c0-2.52 1.834-4.84 5.287-4.84 2.774 0 4.932 1.98 4.932 4.62 0 2.76-1.74 4.98-4.16 4.98-.81 0-1.57-.42-1.84-.92l-.5 1.9c-.18.698-.67 1.57-1 2.1.75.23 1.54.357 2.37.357 4.41 0 8-3.58 8-8s-3.59-8-8-8z" fill-rule="nonzero"/></symbol> + +<symbol id="rss" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path d="M12.8 16C12.8 8.978 7.022 3.2 0 3.2V0c8.777 0 16 7.223 16 16h-3.2zM2.194 11.61c1.21 0 2.195.985 2.195 2.196 0 1.21-.99 2.194-2.2 2.194C.98 16 0 15.017 0 13.806c0-1.21.983-2.195 2.194-2.195zM10.606 16h-3.11c0-4.113-3.383-7.497-7.496-7.497v-3.11c5.818 0 10.606 4.79 10.606 10.607z"/></symbol> + +<symbol id="stackoverflow" class="svg-icon" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path d="M12.658 14.577v-4.27h1.423V16H1.23v-5.693h1.42v4.27h10.006zm-8.583-1.423h7.16V11.73h-7.16v1.424zm.173-3.235l6.987 1.46.3-1.38L4.55 8.54l-.302 1.38zm.906-3.37l6.47 3.02.602-1.3-6.47-3.02-.602 1.29zm1.81-3.19l5.478 4.57.906-1.08L7.87 2.28l-.9 1.078zM10.502 0L9.338.863l4.27 5.735 1.164-.862L10.5 0z"/></symbol> + +<symbol id="twitter" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path d="M16 3.038c-.59.26-1.22.437-1.885.517.677-.407 1.198-1.05 1.443-1.816-.634.37-1.337.64-2.085.79-.598-.64-1.45-1.04-2.396-1.04-1.812 0-3.282 1.47-3.282 3.28 0 .26.03.51.085.75-2.728-.13-5.147-1.44-6.766-3.42C.83 2.58.67 3.14.67 3.75c0 1.14.58 2.143 1.46 2.732-.538-.017-1.045-.165-1.487-.41v.04c0 1.59 1.13 2.918 2.633 3.22-.276.074-.566.114-.865.114-.21 0-.41-.02-.61-.058.42 1.304 1.63 2.253 3.07 2.28-1.12.88-2.54 1.404-4.07 1.404-.26 0-.52-.015-.78-.045 1.46.93 3.18 1.474 5.04 1.474 6.04 0 9.34-5 9.34-9.33 0-.14 0-.28-.01-.42.64-.46 1.2-1.04 1.64-1.7z" fill-rule="nonzero"/></symbol> + +<symbol id="youtube" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path d="M0 7.345c0-1.294.16-2.59.16-2.59s.156-1.1.636-1.587c.608-.637 1.408-.617 1.764-.684C3.84 2.36 8 2.324 8 2.324s3.362.004 5.6.166c.314.038.996.04 1.604.678.48.486.636 1.588.636 1.588S16 6.05 16 7.346v1.258c0 1.296-.16 2.59-.16 2.59s-.156 1.102-.636 1.588c-.608.638-1.29.64-1.604.678-2.238.162-5.6.166-5.6.166s-4.16-.037-5.44-.16c-.356-.067-1.156-.047-1.764-.684-.48-.487-.636-1.587-.636-1.587S0 9.9 0 8.605v-1.26zm6.348 2.73V5.58l4.323 2.255-4.32 2.24z"/></symbol> + +<symbol id="mastodon" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"> + <path transform="scale(0.07)" d="M211.80734 139.0875c-3.18125 16.36625-28.4925 34.2775-57.5625 37.74875-15.15875 1.80875-30.08375 3.47125-45.99875 2.74125-26.0275-1.1925-46.565-6.2125-46.565-6.2125 0 2.53375.15625 4.94625.46875 7.2025 3.38375 25.68625 25.47 27.225 46.39125 27.9425 21.11625.7225 39.91875-5.20625 39.91875-5.20625l.8675 19.09s-14.77 7.93125-41.08125 9.39c-14.50875.7975-32.52375-.365-53.50625-5.91875C9.23234 213.82 1.40609 165.31125.20859 116.09125c-.365-14.61375-.14-28.39375-.14-39.91875 0-50.33 32.97625-65.0825 32.97625-65.0825C49.67234 3.45375 78.20359.2425 107.86484 0h.72875c29.66125.2425 58.21125 3.45375 74.8375 11.09 0 0 32.975 14.7525 32.975 65.0825 0 0 .41375 37.13375-4.59875 62.915"/> + <path transform="scale(0.07)" fill="#FFF" d="M177.50984 80.077v60.94125h-24.14375v-59.15c0-12.46875-5.24625-18.7975-15.74-18.7975-11.6025 0-17.4175 7.5075-17.4175 22.3525v32.37625H96.20734V85.42325c0-14.845-5.81625-22.3525-17.41875-22.3525-10.49375 0-15.74 6.32875-15.74 18.7975v59.15H38.90484V80.077c0-12.455 3.17125-22.3525 9.54125-29.675 6.56875-7.3225 15.17125-11.07625 25.85-11.07625 12.355 0 21.71125 4.74875 27.8975 14.2475l6.01375 10.08125 6.015-10.08125c6.185-9.49875 15.54125-14.2475 27.8975-14.2475 10.6775 0 19.28 3.75375 25.85 11.07625 6.36875 7.3225 9.54 17.22 9.54 29.675"/> +</symbol> + + +</svg> diff --git a/assets/seadling.svg b/assets/seadling.svg new file mode 100644 index 0000000..d135359 --- /dev/null +++ b/assets/seadling.svg @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg width="60.975mm" height="85.691mm" version="1.1" viewBox="0 0 60.975 85.691" xmlns="http://www.w3.org/2000/svg"> + <g transform="translate(-84.962 -110.58)"> + <path d="m90.892 157.59 9.8659 38.676h28.021l10.363-38.676z" fill="#b35642"/> + </g> +</svg> diff --git a/assets/style.css b/assets/style.css new file mode 100644 index 0000000..d688429 --- /dev/null +++ b/assets/style.css @@ -0,0 +1,375 @@ +body +{ + background-color: #e9e9e7; + color: #353534; + font-family: Open Sans,Arial; +} + +figure +{ + display: block; + margin: auto; + width: fit-content; +} + +img +{ + display: block; + margin: auto; + max-width: 100%; + height: auto; +} + +img + figcaption +{ + text-align: center; + display: block; + margin: auto; +} + + +pre +{ + background-color: #FCFBF7; + border-radius: 5px; + padding: 10px; +} + +blockquote +{ + background-color: #FCFBF7; + border-radius: 5px; + padding: 5px; + border-left: 10px solid #cecece; +} + +.note-body +{ + max-width: 66%; + margin: auto; +} + +.contact-list, .social-media-list +{ + list-style: none; + margin-left: 0; +} + +.svg-icon +{ + width: 16px; + height: 16px; + display: inline-block; + fill: #828282; + padding-right: 5px; + vertical-align: text-top; +} + +.title-header +{ + margin: 0; + font-size: 72px; +} + +.page-title-header +{ + display:block; + margin: auto; + font-size: 72px; +} + +.title-header-container +{ + display:flex; + font-size: 72px; + font-weight: bold; + flex-wrap: wrap; + margin-top: 0; +} + +.page-info-container +{ + display: flex; +} + +.page-info-container p +{ + margin-bottom: 2px; +} + +.page-info-date-container +{ + display: flex; + margin-left: auto; +} + +.plant-status +{ + display: flex; + margin: 0; + text-transform: capitalize; +} + +.plant-status img +{ + width: 20px; + margin-right: 5px; +} + +.page-info-date +{ + margin-left: 10px; +} + +.note-divider +{ + background-color: #cecece; + width: 60%; + height: 1px; + display: block; + margin: auto; +} + +.page-title-header-container +{ + width: fit-content; + margin: auto; + display: block; +} + +.header-bar +{ + display: flex; + align-items: center; + margin-bottom: 0.5em; + margin-left: 1em; + margin-top: 1em; +} + +.header-links +{ + margin-left: auto; +} + +a.header-link +{ + padding-right: 1em; + color: #353534; +} + +main +{ + max-width: 1400px; + margin: 40px auto; +} + +.main-heading +{ + font-size: 66px; +} + +.animated-box +{ + height: 1.2em; + overflow: hidden; + position: relative; +} + +.notes-container +{ + display: flex; + flex-wrap: wrap; +} + +.note-box +{ + max-width: 400px; + max-height: 500px; + background-color: #FCFBF7; + margin-right: 20px; + height: 100%; + width: 400px; + margin-bottom: 20px; + border-radius: 5px; + border: 2px solid #E6E3E1; + box-shadow: 0 0 10px #E6E3E1; +} + +.note-link +{ + color: #353534; + text-decoration: none; +} + +.note-link:hover +{ + transform: scale(110%); +} + +.note-box h2, .note-box p +{ + margin-top: 10px; + margin-left: 10px; + margin-bottom: 10px; +} + +.note-box img +{ + max-width: 380px; + max-height: 480px; + margin-left: auto; + margin-right: auto; + display: block; + margin-top: 10px; + border-radius: 5px; +} + +.page-self-image +{ + float: right; + max-height: 300px; + border-radius: 5px; +} + +.animated-box::before +{ + top: 0; + left: 0; + z-index: 1; + width: 100%; + content: ''; + height: 10px; + position: absolute; + background: linear-gradient(180deg, #e9e9e7, #e9e9e700); +} + +.animated-box::after +{ + left: 0; + bottom: 0; + z-index: 1; + width: 100%; + content: ''; + height: 10px; + position: absolute; + background: linear-gradient(180deg, #e9e9e700, #e9e9e7); + +} + +.item-1 +{ + color: #1a81ef; +} + +.item-2 +{ + color: #155fb4; +} + +ul.animated-name +{ + margin: 0; + padding: 0; + animation: scrollUp 10s ease-in-out infinite normal; +} + +ul.animated-name li.animated-name +{ + opacity: 1; + height: 20px; + padding-top: 0; + padding-bottom: 1em; + padding-right: 0; + list-style: none; +} + +@keyframes scrollUp +{ + from + { + transform: translateY(0); + } + to + { + transform: translateY(-83.2%); + } +} + +p code +{ + background-color: #FCFBF7; + border-radius: 5px; + padding: 2px; +} + +/* Copied from pandoc template */ +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +span.underline{text-decoration: underline;} +div.column{display: inline-block; vertical-align: top; width: 50%;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +pre > code.sourceCode { white-space: pre; position: relative; } +pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span:empty { height: 1.2em; } +.sourceCode { overflow: visible; } +code.sourceCode > span { color: inherit; text-decoration: inherit; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +pre > code.sourceCode { white-space: pre-wrap; } +pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +} +pre.numberSource code + { counter-reset: source-line 0; } +pre.numberSource code > span + { position: relative; left: -4em; counter-increment: source-line; } +pre.numberSource code > span > a:first-child::before + { content: counter(source-line); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + color: #aaaaaa; + } +pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; } +div.sourceCode + { } +@media screen { +pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +} +code span.al { color: #ff0000; font-weight: bold; } /* Alert */ +code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */ +code span.at { color: #7d9029; } /* Attribute */ +code span.bn { color: #40a070; } /* BaseN */ +code span.bu { } /* BuiltIn */ +code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */ +code span.ch { color: #4070a0; } /* Char */ +code span.cn { color: #880000; } /* Constant */ +code span.co { color: #60a0b0; font-style: italic; } /* Comment */ +code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */ +code span.do { color: #ba2121; font-style: italic; } /* Documentation */ +code span.dt { color: #902000; } /* DataType */ +code span.dv { color: #40a070; } /* DecVal */ +code span.er { color: #ff0000; font-weight: bold; } /* Error */ +code span.ex { } /* Extension */ +code span.fl { color: #40a070; } /* Float */ +code span.fu { color: #06287e; } /* Function */ +code span.im { } /* Import */ +code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */ +code span.kw { color: #007020; font-weight: bold; } /* Keyword */ +code span.op { color: #666666; } /* Operator */ +code span.ot { color: #007020; } /* Other */ +code span.pp { color: #bc7a00; } /* Preprocessor */ +code span.sc { color: #4070a0; } /* SpecialChar */ +code span.ss { color: #bb6688; } /* SpecialString */ +code span.st { color: #4070a0; } /* String */ +code span.va { color: #19177c; } /* Variable */ +code span.vs { color: #4070a0; } /* VerbatimString */ +code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */ +.display.math{display: block; text-align: center; margin: 0.5rem auto;} diff --git a/html/about.html b/html/about.html new file mode 100644 index 0000000..e79068a --- /dev/null +++ b/html/about.html @@ -0,0 +1,48 @@ +<!doctype html> + +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + + <title>About</title> + + <link rel="stylesheet" href="/assets/style.css"> + <link rel="icon" type="image/x-icon" href="/assets/favicon.svg"> +</head> + +<body> + <div class="header-bar"> + <a href="/index.html"> + <img src="/assets/favicon.svg" alt="frycon logo"> + </a> + <div class="header-links"> + <a href="/now.html" class="header-link">Now</a> + <a href="/about.html" class="header-link">About</a> + </div> + </div> + <main> +<div class="page-title-header-container"> + <h1 class="page-title-header">About</h1> + </div> +<div class="note-divider"></div> +<div class="note-body"> +<p><img class="page-self-image" src="/assets/me.jpg"></p> +<p>Hello my name is Lucas Fryzek, and welcome to my website!</p> +<p>I’m a software developer with specific interests in computer graphics, embedded systems, and operating systems. For my day job I work on DO-178 certified graphics drivers for safety critical environments, and in my free time I enjoy working on personal projects (including this website). I plan to use this site to share information about projects I’m working on, or just generally cool stuff I’m interested in.</p> +<div class="social-links-container"> +<ul class="social-media-list"> +<li> +<a href="https://github.com/Hazematman"> <svg class="svg-icon"><use xlink:href="/assets/minima-social-icons.svg#github"></use></svg> <span>Hazematman</span> </a> +</li> +<li> +<a href="https://www.linkedin.com/in/lucas-fryzek"> <svg class="svg-icon"><use xlink:href="/assets/minima-social-icons.svg#linkedin"></use></svg> <span>lucas-fryzek</span> </a> +</li> +<li> +<a href="https://www.twitter.com/Hazematman"> <svg class="svg-icon"><use xlink:href="/assets/minima-social-icons.svg#twitter"></use></svg> <span>Hazematman</span> </a> +</li> +</ul> +</div> +</div> </main> +</body> +</html> diff --git a/html/assets b/html/assets new file mode 120000 index 0000000..ec2e4be --- /dev/null +++ b/html/assets @@ -0,0 +1 @@ +../assets
\ No newline at end of file diff --git a/html/index.html b/html/index.html new file mode 100644 index 0000000..6100efc --- /dev/null +++ b/html/index.html @@ -0,0 +1,63 @@ +<!doctype html> + +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + + <title>Fryzek Concepts</title> + + <link rel="stylesheet" href="/assets/style.css"> + <link rel="icon" type="image/x-icon" href="/assets/favicon.svg"> +</head> + +<body> + <div class="header-bar"> + <a href="/index.html"> + <img src="/assets/favicon.svg" alt="frycon logo"> + </a> + <div class="header-links"> + <a href="/now.html" class="header-link">Now</a> + <a href="/about.html" class="header-link">About</a> + </div> + </div> + <main> +<div class="title-header-container"> + <div class="animated-box"> + <ul class="animated-name"> + <li class="animated-name item-1">Lucas</li> + <li class="animated-name item-2">卢卡斯</li> + <li class="animated-name item-2">Λούκας</li> + <li class="animated-name item-2">Lukáš</li> + <li class="animated-name item-2">ルーカス</li> + <li class="animated-name item-1">Lucas</li> + </ul> + </div> + <h1 class=title-header> is a developer working on cool things. </h1> +</div> + +<h2 class="main-heading">Notes</h2> +<div class="notes-container"> + <a href="/notes/digital_garden.html" class="note-link"> + <div class="note-box"> + <h2>Digital Garden</h2> + <p>After reading Maggie Appleton page on digital gardens I was inspired to convert my own website into...</p> + </div> + </a> + <a href="/notes/rasterizing-triangles.html" class="note-link"> + <div class="note-box"> + <img src="/assets/2022-04-03-rasterizing-triangles/Screenshot-from-2022-04-03-13-43-13.png"> + <h2>Rasterizing Triangles</h2> + <p>Lately I’ve been trying to implement a software renderer following the algorithm described by ...</p> + </div> + </a> + <a href="/notes/baremetal-risc-v.html" class="note-link"> + <div class="note-box"> + <img src="/assets/2022-06-09-baremetal-risc-v/PXL_20220609_121350403.jpg"> + <h2>Baremetal RISC-V</h2> + <p>After re-watching suckerpinch’s Reverse Emulation video I got inspired to try and replicate what ...</p> + </div> + </a> + </div> </main> +</body> +</html> diff --git a/html/notes/baremetal-risc-v.html b/html/notes/baremetal-risc-v.html new file mode 100644 index 0000000..f9cc288 --- /dev/null +++ b/html/notes/baremetal-risc-v.html @@ -0,0 +1,152 @@ +<!doctype html> + +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + + <title>Baremetal RISC-V</title> + <meta name="dcterms.date" content="2022-06-09" /> + + <link rel="stylesheet" href="/assets/style.css"> + <link rel="icon" type="image/x-icon" href="/assets/favicon.svg"> +</head> + +<body> + <div class="header-bar"> + <a href="/index.html"> + <img src="/assets/favicon.svg" alt="frycon logo"> + </a> + <div class="header-links"> + <a href="/now.html" class="header-link">Now</a> + <a href="/about.html" class="header-link">About</a> + </div> + </div> + <main> +<div class="page-title-header-container"> + <h1 class="page-title-header">Baremetal RISC-V</h1> + <div class="page-info-container"> + <div class="plant-status"> + <img src="/assets/budding.svg"> + <p>budding</p> + </div> + <div class="page-info-date-container"> + <p class="page-info-date">Published: 2022-06-09</p> + <p class="page-info-date">Last Edited: 2022-06-09</p> + </div> + </div> + </div> +<div class="note-divider"></div> +<div class="note-body"> +<p>After re-watching suckerpinch’s <a href="https://www.youtube.com/watch?v=ar9WRwCiSr0">“Reverse Emulation”</a> video I got inspired to try and replicate what he did, but instead do it on an N64. Now my idea here is not to preform reverse emulation on the N64 itself but instead to use the SBC as a cheap way to make a dev focused flash cart. Seeing that sukerpinch was able to meet the timings of the NES bus made me think it might be possible to meet the N64 bus timings taking an approach similar to his.</p> +<h2 id="why-risc-v-baremetal">Why RISC-V Baremetal?</h2> +<p>The answer here is more utilitarian then idealistic, I originally wanted to use a Raspberry Pi since I thought that board may be more accessible if other people want to try and replicate this project. Instead what I found is that it is impossible to procure a Raspberry Pi. Not to be deterred I purchased a <a href="https://linux-sunxi.org/Allwinner_Nezha">“Allwinner Nezha”</a> a while back and its just been collecting dust in my storage. I figured this would be a good project to test the board out on since it has a large amount of RAM (1GB on my board), a fast processor (1 GHz), and accessible GPIO. As for why baremetal? Well one of the big problems suckerpinch ran into was being interrupted by the Linux kernel while his software was running. The board was fast enough to respond to the bus timings but Linux would throw off those timings with preemption. This is why I’m taking the approach to do everything baremetal. Giving 100% of the CPU time to my program emulating the CPU bus.</p> +<h2 id="risc-v-baremetal-development">RISC-V Baremetal Development</h2> +<p>Below I’ll document how I got a baremetal program running on the Nezha board, to provide guidance to anyone who wants to try doing something like this themselves.</p> +<h3 id="toolchain-setup">Toolchain Setup</h3> +<p>In order to do any RISC-V development we will need to setup a RISC-V toolchain that isn’t tied to a specific OS like linux. Thankfully the RISC-V org set up a simple to use git repo that has a script to build an entire RISC-V toolchain on your machine. Since you’re building the whole toolchain from source this will take some time on my machine (Ryzen 4500u, 16GB of RAM, 1TB PCIe NVMe storage), it took around ~30 minutes to build the whole tool chain. You can find the repo <a href="https://github.com/riscv-collab/riscv-gnu-toolchain">here</a>, and follow the instructions in the <code>Installation (Newlib)</code> section of the README. That will setup a bare bones OS independent toolchain that can use newlib for the cstdlib (not that I am currently using it in my software).</p> +<h3 id="setting-up-a-program">Setting up a Program</h3> +<p>This is probably one of the more complicated steps in baremetal programming as this will involve setting up a linker script, which can sometimes feel like an act of black magic to get right. I’ll try to walk through some linker script basics to show how I setup mine. The linker script <code>linker.ld</code> I’m using is below</p> +<pre class="ld"><code>SECTIONS +{ + . = 0x45000000; + .text : { + PROVIDE(__text_start = .); + *(.text.start) + *(.text*) + . = ALIGN(4096); + PROVIDE(__text_end = .); + } + .data : { + PROVIDE(__data_start = .); + . = ALIGN(16); + *(.rodata*); + *(.data .data.*) + PROVIDE(__data_end = .); + } + . += 1024; + PROVIDE(__stack_start = .); + . = ALIGN(16); + . += 4096; + PROVIDE(__stack_end = .); + + /DISCARD/ : + { + *(.riscv.attributes); + *(.comment); + } +}</code></pre> +<p>The purpose of a linkscript is to describe how our binary will be organized, the script I wrote will do the follow</p> +<ol type="1"> +<li>Start the starting address offset to <code>0x45000000</code>, This is the address we are going to load the binary into memory, so any pointers in the program will need to be offset from this address</li> +<li>start the binary off with the <code>.text</code> section which will contain the executable code, in the text section we want the code for <code>.text.start</code> to come first. this is the code that implements the “C runtime”. That is this is the code with the <code>_start</code> function that will setup the stack pointer and call into the C <code>main</code> function. After that we will place the text for all the other functions in our binary. We keep this section aligned to <code>4096</code> bytes, and the <code>PROVIDE</code> functions creates a symbol with a pointer to that location in memory. We won’t use the text start and end pointers in our program but it can be useful if you want to know stuff about your binary at runtime of your program</li> +<li>Next is the <code>.data</code> section that has all the data for our program. Here you can see I also added the <code>rodata</code> or read only section to the data section. The reason I did this is because I’m not going to bother with properly implementing read only data. We also keep the data aligned to 16 bytes to ensure that every memory access will be aligned for a 64bit RISCV memory access.</li> +<li>The last “section” is not a real section but some extra padding at the end to reserve the stack. Here I am reserving 4096 (4Kb) for the stack of my program.</li> +<li>Lastly I’m going to discard a few sections that GCC will compile into the binary that I don’t need at all.</li> +</ol> +<p>Now this probably isn’t the best way to write a linker script. For example the stack is just kind of a hack in it, and I don’t implement the <code>.bss</code> section for zero initialized data.</p> +<p>With this linker script we can now setup a basic program, we can use the code presented below as the <code>main.c</code> file</p> +<div class="sourceCode" id="cb2"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im"><stdint.h></span></span> +<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="pp">#define UART0_BASE 0x02500000</span></span> +<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="pp">#define UART0_DATA_REG (UART0_BASE + 0x0000)</span></span> +<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="pp">#define UART0_USR (UART0_BASE + 0x007c)</span></span> +<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="pp">#define write_reg(r, v) write_reg_handler((volatile uint32_t*)(r), (v))</span></span> +<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> write_reg_handler<span class="op">(</span><span class="dt">volatile</span> <span class="dt">uint32_t</span> <span class="op">*</span>reg<span class="op">,</span> <span class="dt">const</span> <span class="dt">uint32_t</span> value<span class="op">)</span></span> +<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span> +<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a> reg<span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">=</span> value<span class="op">;</span></span> +<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> +<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a><span class="pp">#define read_reg(r) read_reg_handler((volatile uint32_t*)(r))</span></span> +<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a><span class="dt">uint32_t</span> read_reg_handler<span class="op">(</span><span class="dt">volatile</span> <span class="dt">uint32_t</span> <span class="op">*</span>reg<span class="op">)</span></span> +<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span> +<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> reg<span class="op">[</span><span class="dv">0</span><span class="op">];</span></span> +<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> +<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> _putchar<span class="op">(</span><span class="dt">char</span> c<span class="op">)</span></span> +<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span> +<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a> <span class="cf">while</span><span class="op">((</span>read_reg<span class="op">(</span>UART0_USR<span class="op">)</span> <span class="op">&</span> <span class="bn">0b10</span><span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span> +<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a> <span class="op">{</span></span> +<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a> asm<span class="op">(</span><span class="st">"nop"</span><span class="op">);</span></span> +<span id="cb2-24"><a href="#cb2-24" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> +<span id="cb2-25"><a href="#cb2-25" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-26"><a href="#cb2-26" aria-hidden="true" tabindex="-1"></a> write_reg<span class="op">(</span>UART0_DATA_REG<span class="op">,</span> c<span class="op">);</span></span> +<span id="cb2-27"><a href="#cb2-27" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> +<span id="cb2-28"><a href="#cb2-28" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-29"><a href="#cb2-29" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>hello_world <span class="op">=</span> <span class="st">"Hello World!</span><span class="sc">\r\n</span><span class="st">"</span><span class="op">;</span></span> +<span id="cb2-30"><a href="#cb2-30" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-31"><a href="#cb2-31" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span></span> +<span id="cb2-32"><a href="#cb2-32" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span> +<span id="cb2-33"><a href="#cb2-33" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span><span class="op">(</span><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>c <span class="op">=</span> hello_world<span class="op">;</span> c<span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">!=</span> <span class="ch">'\0'</span><span class="op">;</span> c<span class="op">++)</span></span> +<span id="cb2-34"><a href="#cb2-34" aria-hidden="true" tabindex="-1"></a> <span class="op">{</span></span> +<span id="cb2-35"><a href="#cb2-35" aria-hidden="true" tabindex="-1"></a> _putchar<span class="op">(</span>c<span class="op">);</span></span> +<span id="cb2-36"><a href="#cb2-36" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span> +<span id="cb2-37"><a href="#cb2-37" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> +<p>This program will write the string “Hello World!” to the serial port. Now a common question for code like this is how did I know to set all the <code>UART0</code> registers? Well the way to find this information is to look at the datasheet, programmer’s manual, or user manual for the chip you are using. In this case we are using an Allwinner D1 and we can find the user manual with all the registers on the linux-sunxi page <a href="https://linux-sunxi.org/D1">here</a>. On pages 900 to 940 we can see a description on how the serial works for this SoC. I also looked at the schematic <a href="https://dl.linux-sunxi.org/D1/D1_Nezha_development_board_schematic_diagram_20210224.pdf">here</a>, to see that the serial port we have is wired to <code>UART0</code> on the SoC. From here we are relying on uboot to boot the board which will setup the serial port for us, which means we can just write to the UART data register to start printing content to the console.</p> +<p>We will also need need to setup a basic assembly program to setup the stack and call our main function. Below you can see my example called <code>start.S</code></p> +<div class="sourceCode" id="cb3"><pre class="sourceCode asm"><code class="sourceCode fasm"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>.<span class="bu">section</span> <span class="op">.</span>text<span class="op">.</span>start</span> +<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a> .global _start</span> +<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="fu">_start:</span></span> +<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> la <span class="kw">sp</span><span class="op">,</span> __stack_start</span> +<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a> j main</span></code></pre></div> +<p>This assembly file just creates a section called <code>.text.start</code> and a global symbol for a function called <code>_start</code> which will be the first function our program executes. All this assembly file does is setup the stack pointer register <code>sp</code> to with the address (using the load address <code>la</code> pseudo instruction) to the stack we setup in the linker script, and then call the main function by jumping directly to it.</p> +<h3 id="building-the-program">Building the Program</h3> +<p>Building the program is pretty straight forward, we need to tell gcc to build the two source files without including the c standard library, and then to link the binary using our linker script. we can do this with the following command</p> +<pre><code>riscv64-unknown-elf-gcc march=rv64g --std=gnu99 -msmall-data-limit=0 -c main.c +riscv64-unknown-elf-gcc march=rv64g --std=gnu99 -msmall-data-limit=0 -c start.S +riscv64-unknown-elf-gcc march=rv64g -march=rv64g -ffreestanding -nostdlib -msmall-data-limit=0 -T linker.ld start.o main.o -o app.elf +riscv64-unknown-elf-objcopy -O binary app.elf app.bin</code></pre> +<p>This will build our source files into <code>.o</code> files first, then combine those <code>.o</code> files into a <code>.elf</code> file, finally converting the <code>.elf</code> into a raw binary file where we use the <code>.bin</code> extension. We need a raw binary file as we want to just load our program into memory and begin executing. If we load the <code>.elf</code> file it will have the elf header and other extra data that is not executable in it. In order to run a <code>.elf</code> file we would need an elf loader, which goes beyond the scope of this example.</p> +<h3 id="running-the-program">Running the Program</h3> +<p>Now we have the raw binary its time to try and load it. I found that the uboot configuration that comes with the board has pretty limited support for loading binaries. So we are going to take advantage of the <code>loadx</code> command to load the binary over serial. In the uboot terminal we are going to run the command:</p> +<pre><code>loadx 45000000</code></pre> +<p>Now the next steps will depend on which serial terminal you are using. We want to use the <code>XMODEM</code> protocol to load the binary. In the serial terminal I am using <code>gnu screen</code> you can execute arbitrary programs and send their output to the serial terminal. You can do this by hitting the key combination “CTRL-A + :” and then typing in <code>exec !! sx app.bin</code>. This will send the binary to the serial terminal using the XMODEM protocol. If you are not using GNU screen look up instructions for how to send an XMODEM binary. Now that the binary is loaded we can type in</p> +<pre><code>go 45000000</code></pre> +<p>The should start to execute the program and you should see <code>Hello World!</code> printed to the console!</p> +<p><img src="/assets/2022-06-09-baremetal-risc-v/riscv-terminal.png" /></p> +<h2 id="whats-next">What’s Next?</h2> +<p>Well the sky is the limit! We have a method to load and run a program that can do anything on the Nezha board now. Looking through the datasheet we can see how to access the GPIO on the board to blink an LED. If you’re really ambitious you could try getting ethernet or USB working in a baremetal environment. I am going to continue on my goal of emulating the N64 cartridge bus which will require me to get GPIO working as well as interrupts on the GPIO lines. If you want to see the current progress of my work you can check it out on github <a href="https://github.com/Hazematman/N64-Cart-Emulator">here</a>.</p> +</div> </main> +</body> +</html> diff --git a/html/notes/digital_garden.html b/html/notes/digital_garden.html new file mode 100644 index 0000000..6410f73 --- /dev/null +++ b/html/notes/digital_garden.html @@ -0,0 +1,45 @@ +<!doctype html> + +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + + <title>Digital Garden</title> + <meta name="dcterms.date" content="2022-10-30" /> + + <link rel="stylesheet" href="/assets/style.css"> + <link rel="icon" type="image/x-icon" href="/assets/favicon.svg"> +</head> + +<body> + <div class="header-bar"> + <a href="/index.html"> + <img src="/assets/favicon.svg" alt="frycon logo"> + </a> + <div class="header-links"> + <a href="/now.html" class="header-link">Now</a> + <a href="/about.html" class="header-link">About</a> + </div> + </div> + <main> +<div class="page-title-header-container"> + <h1 class="page-title-header">Digital Garden</h1> + <div class="page-info-container"> + <div class="plant-status"> + <img src="/assets/seadling.svg"> + <p>seadling</p> + </div> + <div class="page-info-date-container"> + <p class="page-info-date">Published: 2022-10-30</p> + <p class="page-info-date">Last Edited: 2022-11-01</p> + </div> + </div> + </div> +<div class="note-divider"></div> +<div class="note-body"> +<p>After reading Maggie Appleton page on <a href="https://maggieappleton.com/garden-history">digital gardens</a> I was inspired to convert my own website into a digital garden.</p> +<p>I have many half baked ideas that a never finish. Some of them get to a published state like <a href="rasterizing-triangles"></a> and <a href="baremetal-risc-v"></a>, but many of them never make it to the published state. The idea of digital garden seems very appealing to me, as it encourages you to post on a topic even if you haven’t made it “publishable” yet.</p> +</div> </main> +</body> +</html> diff --git a/html/notes/rasterizing-triangles.html b/html/notes/rasterizing-triangles.html new file mode 100644 index 0000000..c6c5f15 --- /dev/null +++ b/html/notes/rasterizing-triangles.html @@ -0,0 +1,124 @@ +<!doctype html> + +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + + <title>Rasterizing Triangles</title> + <meta name="dcterms.date" content="2022-04-03" /> + + <link rel="stylesheet" href="/assets/style.css"> + <link rel="icon" type="image/x-icon" href="/assets/favicon.svg"> +</head> + +<body> + <div class="header-bar"> + <a href="/index.html"> + <img src="/assets/favicon.svg" alt="frycon logo"> + </a> + <div class="header-links"> + <a href="/now.html" class="header-link">Now</a> + <a href="/about.html" class="header-link">About</a> + </div> + </div> + <main> +<div class="page-title-header-container"> + <h1 class="page-title-header">Rasterizing Triangles</h1> + <div class="page-info-container"> + <div class="plant-status"> + <img src="/assets/budding.svg"> + <p>budding</p> + </div> + <div class="page-info-date-container"> + <p class="page-info-date">Published: 2022-04-03</p> + <p class="page-info-date">Last Edited: 2022-10-30</p> + </div> + </div> + </div> +<div class="note-divider"></div> +<div class="note-body"> +<p>Lately I’ve been trying to implement a software renderer <a href="https://www.cs.drexel.edu/~david/Classes/Papers/comp175-06-pineda.pdf">following the algorithm described by Juan Pineda in “A Parallel Algorithm for Polygon Rasterization”</a>. For those unfamiliar with the paper, it describes an algorithm to rasterize triangles that has an extremely nice quality, that you simply need to preform a few additions per pixel to see if the next pixel is inside the triangle. It achieves this quality by defining an edge function that has the following property:</p> +<pre><code>E(x+1,y) = E(x,y) + dY +E(x,y+1) = E(x,y) - dX</code></pre> +<p>This property is extremely nice for a rasterizer as additions are quite cheap to preform and with this method we limit the amount of work we have to do per pixel. One frustrating quality of this paper is that it suggest that you can calculate more properties than just if a pixel is inside the triangle with simple addition, but provides no explanation for how to do that. In this blog I would like to explore how you implement a Pineda style rasterizer that can calculate per pixel values using simple addition.</p> +<figure> +<img src="/assets/2022-04-03-rasterizing-triangles/Screenshot-from-2022-04-03-13-43-13.png" alt="Triangle rasterized using code in this post" /><figcaption aria-hidden="true">Triangle rasterized using code in this post</figcaption> +</figure> +<p>In order to figure out how build this rasterizer <a href="https://www.reddit.com/r/GraphicsProgramming/comments/tqxxmu/interpolating_values_in_a_pineda_style_rasterizer/">I reached out to the internet</a> to help build some more intuition on how the properties of this rasterizer. From this reddit post I gained more intuition on how we can use the edge function values to linear interpolate values on the triangle. Here is there relevant comment that gave me all the information I needed</p> +<blockquote> +<p>Think about the edge function’s key property:</p> +<p><em>recognize that the formula given for E(x,y) is the same as the formula for the magnitude of the cross product between the vector from (X,Y) to (X+dX, Y+dY), and the vector from (X,Y) to (x,y). By the well known property of cross products, the magnitude is zero if the vectors are colinear, and changes sign as the vectors cross from one side to the other.</em></p> +<p>The magnitude of the edge distance is the area of the parallelogram formed by <code>(X,Y)->(X+dX,Y+dY)</code> and <code>(X,Y)->(x,y)</code>. If you normalize by the parallelogram area at the <em>other</em> point in the triangle you get a barycentric coordinate that’s 0 along the <code>(X,Y)->(X+dX,Y+dY)</code> edge and 1 at the other point. You can precompute each interpolated triangle parameter normalized by this area at setup time, and in fact most hardware computes per-pixel step values (pre 1/w correction) so that all the parameters are computed as a simple addition as you walk along each raster.</p> +<p>Note that when you’re implementing all of this it’s critical to keep all the math in the integer domain (snapping coordinates to some integer sub-pixel precision, I’d recommend at least 4 bits) and using a tie-breaking function (typically top-left) for pixels exactly on the edge to avoid pixel double-hits or gaps in adjacent triangles.</p> +<p>https://www.reddit.com/r/GraphicsProgramming/comments/tqxxmu/interpolating_values_in_a_pineda_style_rasterizer/i2krwxj/</p> +</blockquote> +<p>From this comment you can see that it is trivial to calculate to calculate the barycentric coordinates of the triangle from the edge function. You simply need to divide the the calculated edge function value by the area of parallelogram. Now what is the area of triangle? Well this is where some <a href="https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/barycentric-coordinates">more research</a> online helped. If the edge function defines the area of a parallelogram (2 times the area of the triangle) of <code>(X,Y)->(X+dX,Y+dY)</code> and <code>(X,Y)->(x,y)</code>, and we calculate three edge function values (one for each edge), then we have 2 times the area of each of the sub triangles that are defined by our point.</p> +<figure> +<img src="https://www.scratchapixel.com/images/upload/ray-triangle/barycentric.png?" alt="Triangle barycentric coordinates from scratchpixel tutorial" /><figcaption aria-hidden="true">Triangle barycentric coordinates from scratchpixel tutorial</figcaption> +</figure> +<p>From this its trivial to see that we can calculate 2 times the area of the triangle just by adding up all the individual areas of the sub triangles (I used triangles here, but really we are adding the area of sub parallelograms to get the area of the whole parallelogram that has 2 times the area of the triangle we are drawing), that is adding the value of all the edge functions together. From this we can see to linear interpolate any value on the triangle we can use the following equation</p> +<pre><code>Value(x,y) = (e0*v0 + e1*v1 + e2*v2) / (e0 + e1 + e2) +Value(x,y) = (e0*v0 + e1*v1 + e2*v2) / area</code></pre> +<p>Where <code>e0, e1, e2</code> are the edge function values and <code>v0, v1, v2</code> are the per vertex values we want to interpolate.</p> +<p>This is great for the calculating the per vertex values, but we still haven’t achieved the property of calculating the interpolate value per pixel with simple addition. To do that we need to use the property of the edge function I described above</p> +<pre><code>Value(x+1, y) = (E0(x+1, y)*v0 + E1(x+1, y)*v1 + E2(x+1, y)*v2) / area +Value(x+1, y) = ((e0+dY0)*v0 + (e1+dY1)*v1 + (e2+dY2)*v2) / area +Value(x+1, y) = (e0*v0 + dY0*v0 + e1*v1+dY1*v1 + e2*v2 + dY2*v2) / area +Value(x+1, y) = (e0*v0 + e1*v1 + e2*v2)/area + (dY0*v0 + dY1*v1 + dY2*v2)/area +Value(x+1, y) = Value(x,y) + (dY0*v0 + dY1*v1 + dY2*v2)/area</code></pre> +<p>From here we can see that if we work through all the math, we can find this same property where the interpolated value is equal to the previous interpolated value plus some number. Therefore if we pre-compute this addition value, when we iterate over the pixels we only need to add this pre-computed number to the interpolated value of the previous pixel. We can repeat this process again to figure out the equation of the pre-computed value for <code>Value(x, y+1)</code> but I’ll save you the time and provide both equations below</p> +<pre><code>dYV = (dY0*v0 + dY1*v1 + dY2*v2)/area +dXV = (dX0*v0 + dX1*v1 + dX2*v2)/area +Value(x+1, y) = Value(x,y) + dYV +Value(x, y+1) = Value(x,y) - dXV</code></pre> +<p>Where <code>dY0, dY1, dY2</code> are the differences between y coordinates as described in Pineda’s paper, <code>dX0, dX1, dX2</code> are the differences in x coordinates as described in Pineda’s paper, and the area is the pre-calculated sum of the edge functions</p> +<p>Now you should be able to build a Pineda style rasterizer that can calculate per pixel interpolated values using simple addition, by following pseudo code like this:</p> +<pre><code>func edge(x, y, xi, yi, dXi, dYi) + return (x - xi)*dYi - (y-yi)*dXi + +func draw_triangle(x0, y0, x1, y1, x2, y2, v0, v1, v2): + dX0 = x0 - x2 + dX1 = x1 - x0 + dX2 = x2 - x2 + dY0 = y0 - y2 + dY1 = y1 - y0 + dY2 = y2 - y1 + start_x = 0 + start_y = 0 + e0 = edge(start_x, start_y, x0, y0, dX0, dY0) + e1 = edge(start_x, start_y, x1, y1, dX1, dY1) + e2 = edge(start_x, start_y, x2, y2, dX2, dY2) + area = e0 + e1 + e2 + dYV = (dY0*v0 + dY1*v1 + dY2*v2) / area + dXV = (dX0*v0 + dX1*v1 + dX2*v2) / area + + v = (e0*v0 + e1*v1 + e2*v2) / area + + starting_e0 = e0 + starting_e1 = e1 + starting_e2 = e2 + starting_v = v + + for y = 0 to screen_height: + for x = 0 to screen_width: + if(e0 >= 0 && e1 >= 0 && e2 >= 0) + draw_pixel(x, y, v) + e0 = e0 + dY0 + e1 = e1 + dY1 + e2 = e2 + dY2 + v = v + dYV + + e0 = starting_e0 - dX0 + e1 = starting_e1 - dX1 + e2 = starting_e2 - dX2 + v = starting_v - dXV + + starting_e0 = e0 + starting_e1 = e1 + starting_e2 = e2 + starting_v = v</code></pre> +<p>Now this pseudo code is not the most efficient as it will iterate over the entire screen to draw one triangle, but it provides a starting basis to show how to use these Pineda properties to calculate per vertex values. One thing to note if you do implement this is, if you use fixed point arithmetic, be careful to insure you have enough precision to calculate all of these values with overflow or underflow. This was an issue I ran into running out of precision when I did the divide by the area.</p> +</div> </main> +</body> +</html> diff --git a/html/now.html b/html/now.html new file mode 100644 index 0000000..c79a750 --- /dev/null +++ b/html/now.html @@ -0,0 +1,37 @@ +<!doctype html> + +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + + <title>Now</title> + + <link rel="stylesheet" href="/assets/style.css"> + <link rel="icon" type="image/x-icon" href="/assets/favicon.svg"> +</head> + +<body> + <div class="header-bar"> + <a href="/index.html"> + <img src="/assets/favicon.svg" alt="frycon logo"> + </a> + <div class="header-links"> + <a href="/now.html" class="header-link">Now</a> + <a href="/about.html" class="header-link">About</a> + </div> + </div> + <main> +<div class="page-title-header-container"> + <h1 class="page-title-header">Now</h1> + </div> +<div class="note-divider"></div> +<div class="note-body"> +<p>A monthly update about my life</p> +<blockquote> +<h2 id="october-2022">October 2022</h2> +<p>After reading about digital gardens, I’ve decided to convert my whole website into its very own digital garden. I wasn’t too happy with existing themes and tools I could find online so I decided to try and build a digital garden engine myself using pandoc and custom filters.</p> +</blockquote> +</div> </main> +</body> +</html> @@ -0,0 +1,3 @@ +--- +title: "Fryzek Concepts" +--- diff --git a/makefile b/makefile new file mode 100644 index 0000000..2bcebe6 --- /dev/null +++ b/makefile @@ -0,0 +1,46 @@ +SRC_DIR := notes +BUILD_DIR := build +HTML_DIR := html +PAGE_DIR := pages +SOURCE_DOCS := $(wildcard $(SRC_DIR)/*.md) +PAGE_DOCS := $(wildcard $(PAGE_DIR)/*.md) + +META_DOCS=$(patsubst $(SRC_DIR)/%,$(BUILD_DIR)/%,$(SOURCE_DOCS:.md=.meta)) +HTML_DOCS=$(patsubst $(SRC_DIR)/%,$(HTML_DIR)/notes/%,$(SOURCE_DOCS:.md=.html)) +SOURCE_FILES=$(patsubst $(SRC_DIR)/%,%,$(SOURCE_DOCS:.md=)) +PAGE_FILES=$(patsubst $(PAGE_DIR)/%,$(HTML_DIR)/%,$(PAGE_DOCS:.md=.html)) + +$(BUILD_DIR)/%.meta: $(SRC_DIR)/%.md + @mkdir -p $(BUILD_DIR) + pandoc --write=tools/link_gen.lua $< -o $@ + +.PRECIOUS: $(META_DOCS) +$(HTML_DIR)/notes/%.html: $(BUILD_DIR)/%.meta $(META_DOCS) + @mkdir -p $(HTML_DIR) + @mkdir -p $(HTML_DIR)/notes + pandoc -s --template=./templates/main.html \ + --lua-filter=./tools/note.lua \ + $(patsubst $(BUILD_DIR)/%,$(SRC_DIR)/%,$(<:.meta=.md)) \ + --highlight-style=pygments \ + -o $@ + +$(HTML_DIR)/%.html: $(PAGE_DIR)/%.md + @mkdir -p $(HTML_DIR) + pandoc -s --template=./templates/main.html \ + $< \ + --highlight-style=pygments \ + -o $@ + +$(HTML_DIR)/index.html: $(HTML_DOCS) $(PAGE_FILES) + ln -sf ../assets -t $(HTML_DIR) + pandoc -s --lua-filter=./tools/front_page.lua --template=./templates/main.html main.md \ + --metadata=note_list:"$(SOURCE_FILES)" \ + -o $@ + +.PHONY: all clean + +all: $(HTML_DIR)/index.html + +clean: + rm -r build + rm -r html diff --git a/notes/baremetal-risc-v.md b/notes/baremetal-risc-v.md new file mode 100644 index 0000000..c0651a5 --- /dev/null +++ b/notes/baremetal-risc-v.md @@ -0,0 +1,163 @@ +--- +layout: post +title: "Baremetal RISC-V" +date: "2022-06-09" +last_edit: "2022-06-09" +status: 2 +tags: + - "baremetal" + - "c-2" + - "riscv" +cover_image: "/assets/2022-06-09-baremetal-risc-v/PXL_20220609_121350403.jpg" +--- + +After re-watching suckerpinch's ["Reverse Emulation"](https://www.youtube.com/watch?v=ar9WRwCiSr0) video I got inspired to try and replicate what he did, but instead do it on an N64. Now my idea here is not to preform reverse emulation on the N64 itself but instead to use the SBC as a cheap way to make a dev focused flash cart. Seeing that sukerpinch was able to meet the timings of the NES bus made me think it might be possible to meet the N64 bus timings taking an approach similar to his. + +## Why RISC-V Baremetal? + +The answer here is more utilitarian then idealistic, I originally wanted to use a Raspberry Pi since I thought that board may be more accessible if other people want to try and replicate this project. Instead what I found is that it is impossible to procure a Raspberry Pi. Not to be deterred I purchased a ["Allwinner Nezha"](https://linux-sunxi.org/Allwinner_Nezha) a while back and its just been collecting dust in my storage. I figured this would be a good project to test the board out on since it has a large amount of RAM (1GB on my board), a fast processor (1 GHz), and accessible GPIO. As for why baremetal? Well one of the big problems suckerpinch ran into was being interrupted by the Linux kernel while his software was running. The board was fast enough to respond to the bus timings but Linux would throw off those timings with preemption. This is why I'm taking the approach to do everything baremetal. Giving 100% of the CPU time to my program emulating the CPU bus. + +## RISC-V Baremetal Development + +Below I'll document how I got a baremetal program running on the Nezha board, to provide guidance to anyone who wants to try doing something like this themselves. + +### Toolchain Setup + +In order to do any RISC-V development we will need to setup a RISC-V toolchain that isn't tied to a specific OS like linux. Thankfully the RISC-V org set up a simple to use git repo that has a script to build an entire RISC-V toolchain on your machine. Since you're building the whole toolchain from source this will take some time on my machine (Ryzen 4500u, 16GB of RAM, 1TB PCIe NVMe storage), it took around ~30 minutes to build the whole tool chain. You can find the repo [here](https://github.com/riscv-collab/riscv-gnu-toolchain), and follow the instructions in the `Installation (Newlib)` section of the README. That will setup a bare bones OS independent toolchain that can use newlib for the cstdlib (not that I am currently using it in my software). + +### Setting up a Program + +This is probably one of the more complicated steps in baremetal programming as this will involve setting up a linker script, which can sometimes feel like an act of black magic to get right. I'll try to walk through some linker script basics to show how I setup mine. The linker script `linker.ld` I'm using is below + +```ld +SECTIONS +{ + . = 0x45000000; + .text : { + PROVIDE(__text_start = .); + *(.text.start) + *(.text*) + . = ALIGN(4096); + PROVIDE(__text_end = .); + } + .data : { + PROVIDE(__data_start = .); + . = ALIGN(16); + *(.rodata*); + *(.data .data.*) + PROVIDE(__data_end = .); + } + . += 1024; + PROVIDE(__stack_start = .); + . = ALIGN(16); + . += 4096; + PROVIDE(__stack_end = .); + + /DISCARD/ : + { + *(.riscv.attributes); + *(.comment); + } +} +``` + +The purpose of a linkscript is to describe how our binary will be organized, the script I wrote will do the follow + +1. Start the starting address offset to `0x45000000`, This is the address we are going to load the binary into memory, so any pointers in the program will need to be offset from this address +2. start the binary off with the `.text` section which will contain the executable code, in the text section we want the code for `.text.start` to come first. this is the code that implements the "C runtime". That is this is the code with the `_start` function that will setup the stack pointer and call into the C `main` function. After that we will place the text for all the other functions in our binary. We keep this section aligned to `4096` bytes, and the `PROVIDE` functions creates a symbol with a pointer to that location in memory. We won't use the text start and end pointers in our program but it can be useful if you want to know stuff about your binary at runtime of your program +3. Next is the `.data` section that has all the data for our program. Here you can see I also added the `rodata` or read only section to the data section. The reason I did this is because I'm not going to bother with properly implementing read only data. We also keep the data aligned to 16 bytes to ensure that every memory access will be aligned for a 64bit RISCV memory access. +4. The last "section" is not a real section but some extra padding at the end to reserve the stack. Here I am reserving 4096 (4Kb) for the stack of my program. +5. Lastly I'm going to discard a few sections that GCC will compile into the binary that I don't need at all. + +Now this probably isn't the best way to write a linker script. For example the stack is just kind of a hack in it, and I don't implement the `.bss` section for zero initialized data. + +With this linker script we can now setup a basic program, we can use the code presented below as the `main.c` file + +```c +#include <stdint.h> + +#define UART0_BASE 0x02500000 +#define UART0_DATA_REG (UART0_BASE + 0x0000) +#define UART0_USR (UART0_BASE + 0x007c) + +#define write_reg(r, v) write_reg_handler((volatile uint32_t*)(r), (v)) +void write_reg_handler(volatile uint32_t *reg, const uint32_t value) +{ + reg[0] = value; +} + +#define read_reg(r) read_reg_handler((volatile uint32_t*)(r)) +uint32_t read_reg_handler(volatile uint32_t *reg) +{ + return reg[0]; +} + +void _putchar(char c) +{ + while((read_reg(UART0_USR) & 0b10) == 0) + { + asm("nop"); + } + + write_reg(UART0_DATA_REG, c); +} + +const char *hello_world = "Hello World!\r\n"; + +int main() +{ + for(const char *c = hello_world; c[0] != '\0'; c++) + { + _putchar(c); + } +} +``` + +This program will write the string "Hello World!" to the serial port. Now a common question for code like this is how did I know to set all the `UART0` registers? Well the way to find this information is to look at the datasheet, programmer's manual, or user manual for the chip you are using. In this case we are using an Allwinner D1 and we can find the user manual with all the registers on the linux-sunxi page [here](https://linux-sunxi.org/D1). On pages 900 to 940 we can see a description on how the serial works for this SoC. I also looked at the schematic [here](https://dl.linux-sunxi.org/D1/D1_Nezha_development_board_schematic_diagram_20210224.pdf), to see that the serial port we have is wired to `UART0` on the SoC. From here we are relying on uboot to boot the board which will setup the serial port for us, which means we can just write to the UART data register to start printing content to the console. + +We will also need need to setup a basic assembly program to setup the stack and call our main function. Below you can see my example called `start.S` + +```asm +.section .text.start + .global _start +_start: + la sp, __stack_start + j main +``` + +This assembly file just creates a section called `.text.start` and a global symbol for a function called `_start` which will be the first function our program executes. All this assembly file does is setup the stack pointer register `sp` to with the address (using the load address `la` pseudo instruction) to the stack we setup in the linker script, and then call the main function by jumping directly to it. + +### Building the Program + +Building the program is pretty straight forward, we need to tell gcc to build the two source files without including the c standard library, and then to link the binary using our linker script. we can do this with the following command + +``` +riscv64-unknown-elf-gcc march=rv64g --std=gnu99 -msmall-data-limit=0 -c main.c +riscv64-unknown-elf-gcc march=rv64g --std=gnu99 -msmall-data-limit=0 -c start.S +riscv64-unknown-elf-gcc march=rv64g -march=rv64g -ffreestanding -nostdlib -msmall-data-limit=0 -T linker.ld start.o main.o -o app.elf +riscv64-unknown-elf-objcopy -O binary app.elf app.bin +``` + +This will build our source files into `.o` files first, then combine those `.o` files into a `.elf` file, finally converting the `.elf` into a raw binary file where we use the `.bin` extension. We need a raw binary file as we want to just load our program into memory and begin executing. If we load the `.elf` file it will have the elf header and other extra data that is not executable in it. In order to run a `.elf` file we would need an elf loader, which goes beyond the scope of this example. + +### Running the Program + +Now we have the raw binary its time to try and load it. I found that the uboot configuration that comes with the board has pretty limited support for loading binaries. So we are going to take advantage of the `loadx` command to load the binary over serial. In the uboot terminal we are going to run the command: + +``` +loadx 45000000 +``` + +Now the next steps will depend on which serial terminal you are using. We want to use the `XMODEM` protocol to load the binary. In the serial terminal I am using `gnu screen` you can execute arbitrary programs and send their output to the serial terminal. You can do this by hitting the key combination "CTRL-A + :" and then typing in `exec !! sx app.bin`. This will send the binary to the serial terminal using the XMODEM protocol. If you are not using GNU screen look up instructions for how to send an XMODEM binary. Now that the binary is loaded we can type in + +``` +go 45000000 +``` + +The should start to execute the program and you should see `Hello World!` printed to the console! + + + +## What's Next? + +Well the sky is the limit! We have a method to load and run a program that can do anything on the Nezha board now. Looking through the datasheet we can see how to access the GPIO on the board to blink an LED. If you're really ambitious you could try getting ethernet or USB working in a baremetal environment. I am going to continue on my goal of emulating the N64 cartridge bus which will require me to get GPIO working as well as interrupts on the GPIO lines. If you want to see the current progress of my work you can check it out on github [here](https://github.com/Hazematman/N64-Cart-Emulator). diff --git a/notes/digital_garden.md b/notes/digital_garden.md new file mode 100644 index 0000000..70e8762 --- /dev/null +++ b/notes/digital_garden.md @@ -0,0 +1,14 @@ +--- +title: "Digital Garden" +date: "2022-10-30" +last_edit: "2022-11-01" +status: 1 +--- + +After reading Maggie Appleton page on [digital gardens](https://maggieappleton.com/garden-history) I was +inspired to convert my own website into a digital garden. + +I have many half baked ideas that a never finish. Some of them get to a published state like +[](rasterizing-triangles) and [](baremetal-risc-v), but many of them never make it to the published state. The +idea of digital garden seems very appealing to me, as it encourages you to post on a topic even if you haven't +made it "publishable" yet. diff --git a/notes/rasterizing-triangles.md b/notes/rasterizing-triangles.md new file mode 100644 index 0000000..f5d01e6 --- /dev/null +++ b/notes/rasterizing-triangles.md @@ -0,0 +1,115 @@ +--- +title: "Rasterizing Triangles" +date: "2022-04-03" +last_edit: "2022-10-30" +status: 2 +cover_image: "/assets/2022-04-03-rasterizing-triangles/Screenshot-from-2022-04-03-13-43-13.png" +--- + +Lately I've been trying to implement a software renderer [following the algorithm described by Juan Pineda in "A Parallel Algorithm for Polygon Rasterization"](https://www.cs.drexel.edu/~david/Classes/Papers/comp175-06-pineda.pdf). For those unfamiliar with the paper, it describes an algorithm to rasterize triangles that has an extremely nice quality, that you simply need to preform a few additions per pixel to see if the next pixel is inside the triangle. It achieves this quality by defining an edge function that has the following property: + +``` +E(x+1,y) = E(x,y) + dY +E(x,y+1) = E(x,y) - dX +``` + +This property is extremely nice for a rasterizer as additions are quite cheap to preform and with this method we limit the amount of work we have to do per pixel. One frustrating quality of this paper is that it suggest that you can calculate more properties than just if a pixel is inside the triangle with simple addition, but provides no explanation for how to do that. In this blog I would like to explore how you implement a Pineda style rasterizer that can calculate per pixel values using simple addition. + + + +In order to figure out how build this rasterizer [I reached out to the internet](https://www.reddit.com/r/GraphicsProgramming/comments/tqxxmu/interpolating_values_in_a_pineda_style_rasterizer/) to help build some more intuition on how the properties of this rasterizer. From this reddit post I gained more intuition on how we can use the edge function values to linear interpolate values on the triangle. Here is there relevant comment that gave me all the information I needed + +> Think about the edge function's key property: +> +> _recognize that the formula given for E(x,y) is the same as the formula for the magnitude of the cross product between the vector from (X,Y) to (X+dX, Y+dY), and the vector from (X,Y) to (x,y). By the well known property of cross products, the magnitude is zero if the vectors are colinear, and changes sign as the vectors cross from one side to the other._ +> +> The magnitude of the edge distance is the area of the parallelogram formed by `(X,Y)->(X+dX,Y+dY)` and `(X,Y)->(x,y)`. If you normalize by the parallelogram area at the _other_ point in the triangle you get a barycentric coordinate that's 0 along the `(X,Y)->(X+dX,Y+dY)` edge and 1 at the other point. You can precompute each interpolated triangle parameter normalized by this area at setup time, and in fact most hardware computes per-pixel step values (pre 1/w correction) so that all the parameters are computed as a simple addition as you walk along each raster. +> +> Note that when you're implementing all of this it's critical to keep all the math in the integer domain (snapping coordinates to some integer sub-pixel precision, I'd recommend at least 4 bits) and using a tie-breaking function (typically top-left) for pixels exactly on the edge to avoid pixel double-hits or gaps in adjacent triangles. +> +> https://www.reddit.com/r/GraphicsProgramming/comments/tqxxmu/interpolating\_values\_in\_a\_pineda\_style\_rasterizer/i2krwxj/ + +From this comment you can see that it is trivial to calculate to calculate the barycentric coordinates of the triangle from the edge function. You simply need to divide the the calculated edge function value by the area of parallelogram. Now what is the area of triangle? Well this is where some [more research](https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/barycentric-coordinates) online helped. If the edge function defines the area of a parallelogram (2 times the area of the triangle) of `(X,Y)->(X+dX,Y+dY)` and `(X,Y)->(x,y)`, and we calculate three edge function values (one for each edge), then we have 2 times the area of each of the sub triangles that are defined by our point. + + + +From this its trivial to see that we can calculate 2 times the area of the triangle just by adding up all the individual areas of the sub triangles (I used triangles here, but really we are adding the area of sub parallelograms to get the area of the whole parallelogram that has 2 times the area of the triangle we are drawing), that is adding the value of all the edge functions together. From this we can see to linear interpolate any value on the triangle we can use the following equation + +``` +Value(x,y) = (e0*v0 + e1*v1 + e2*v2) / (e0 + e1 + e2) +Value(x,y) = (e0*v0 + e1*v1 + e2*v2) / area +``` + +Where `e0, e1, e2` are the edge function values and `v0, v1, v2` are the per vertex values we want to interpolate. + +This is great for the calculating the per vertex values, but we still haven't achieved the property of calculating the interpolate value per pixel with simple addition. To do that we need to use the property of the edge function I described above + +``` +Value(x+1, y) = (E0(x+1, y)*v0 + E1(x+1, y)*v1 + E2(x+1, y)*v2) / area +Value(x+1, y) = ((e0+dY0)*v0 + (e1+dY1)*v1 + (e2+dY2)*v2) / area +Value(x+1, y) = (e0*v0 + dY0*v0 + e1*v1+dY1*v1 + e2*v2 + dY2*v2) / area +Value(x+1, y) = (e0*v0 + e1*v1 + e2*v2)/area + (dY0*v0 + dY1*v1 + dY2*v2)/area +Value(x+1, y) = Value(x,y) + (dY0*v0 + dY1*v1 + dY2*v2)/area +``` + +From here we can see that if we work through all the math, we can find this same property where the interpolated value is equal to the previous interpolated value plus some number. Therefore if we pre-compute this addition value, when we iterate over the pixels we only need to add this pre-computed number to the interpolated value of the previous pixel. We can repeat this process again to figure out the equation of the pre-computed value for `Value(x, y+1)` but I'll save you the time and provide both equations below + +``` +dYV = (dY0*v0 + dY1*v1 + dY2*v2)/area +dXV = (dX0*v0 + dX1*v1 + dX2*v2)/area +Value(x+1, y) = Value(x,y) + dYV +Value(x, y+1) = Value(x,y) - dXV +``` + +Where `dY0, dY1, dY2` are the differences between y coordinates as described in Pineda's paper, `dX0, dX1, dX2` are the differences in x coordinates as described in Pineda's paper, and the area is the pre-calculated sum of the edge functions + +Now you should be able to build a Pineda style rasterizer that can calculate per pixel interpolated values using simple addition, by following pseudo code like this: + +``` +func edge(x, y, xi, yi, dXi, dYi) + return (x - xi)*dYi - (y-yi)*dXi + +func draw_triangle(x0, y0, x1, y1, x2, y2, v0, v1, v2): + dX0 = x0 - x2 + dX1 = x1 - x0 + dX2 = x2 - x2 + dY0 = y0 - y2 + dY1 = y1 - y0 + dY2 = y2 - y1 + start_x = 0 + start_y = 0 + e0 = edge(start_x, start_y, x0, y0, dX0, dY0) + e1 = edge(start_x, start_y, x1, y1, dX1, dY1) + e2 = edge(start_x, start_y, x2, y2, dX2, dY2) + area = e0 + e1 + e2 + dYV = (dY0*v0 + dY1*v1 + dY2*v2) / area + dXV = (dX0*v0 + dX1*v1 + dX2*v2) / area + + v = (e0*v0 + e1*v1 + e2*v2) / area + + starting_e0 = e0 + starting_e1 = e1 + starting_e2 = e2 + starting_v = v + + for y = 0 to screen_height: + for x = 0 to screen_width: + if(e0 >= 0 && e1 >= 0 && e2 >= 0) + draw_pixel(x, y, v) + e0 = e0 + dY0 + e1 = e1 + dY1 + e2 = e2 + dY2 + v = v + dYV + + e0 = starting_e0 - dX0 + e1 = starting_e1 - dX1 + e2 = starting_e2 - dX2 + v = starting_v - dXV + + starting_e0 = e0 + starting_e1 = e1 + starting_e2 = e2 + starting_v = v +``` + +Now this pseudo code is not the most efficient as it will iterate over the entire screen to draw one triangle, but it provides a starting basis to show how to use these Pineda properties to calculate per vertex values. One thing to note if you do implement this is, if you use fixed point arithmetic, be careful to insure you have enough precision to calculate all of these values with overflow or underflow. This was an issue I ran into running out of precision when I did the divide by the area. diff --git a/pages/about.md b/pages/about.md new file mode 100644 index 0000000..d1c3f48 --- /dev/null +++ b/pages/about.md @@ -0,0 +1,36 @@ +--- +title: About +--- + +<img class="page-self-image" src="/assets/me.jpg"> + +Hello my name is Lucas Fryzek, and welcome to my website! + +I’m a software developer with specific interests in computer graphics, embedded systems, and +operating systems. For my day job I work on DO-178 certified graphics drivers for safety critical +environments, and in my free time I enjoy working on personal projects (including this website). I +plan to use this site to share information about projects I’m working on, or just generally cool stuff +I’m interested in. + +<div class="social-links-container"> +<ul class="social-media-list"> +<li> +<a href="https://github.com/Hazematman"> + <svg class="svg-icon"><use xlink:href="/assets/minima-social-icons.svg#github"></use></svg> + <span>Hazematman</span> +</a> +</li> +<li> +<a href="https://www.linkedin.com/in/lucas-fryzek"> + <svg class="svg-icon"><use xlink:href="/assets/minima-social-icons.svg#linkedin"></use></svg> + <span>lucas-fryzek</span> +</a> +</li> +<li> +<a href="https://www.twitter.com/Hazematman"> + <svg class="svg-icon"><use xlink:href="/assets/minima-social-icons.svg#twitter"></use></svg> + <span>Hazematman</span> +</a> +</li> +</ul> +</div> diff --git a/pages/now.md b/pages/now.md new file mode 100644 index 0000000..f3ebc55 --- /dev/null +++ b/pages/now.md @@ -0,0 +1,10 @@ +--- +title: Now +--- +A monthly update about my life + +> ## October 2022 +> After reading about digital gardens, I've decided to convert my whole website into +> its very own digital garden. I wasn't too happy with existing themes and tools I could find +> online so I decided to try and build a digital garden engine myself using pandoc and custom +> filters. diff --git a/templates/front_page.html b/templates/front_page.html new file mode 100644 index 0000000..ce987fb --- /dev/null +++ b/templates/front_page.html @@ -0,0 +1,24 @@ +<div class="title-header-container"> + <div class="animated-box"> + <ul class="animated-name"> + <li class="animated-name item-1">Lucas</li> + <li class="animated-name item-2">卢卡斯</li> + <li class="animated-name item-2">Λούκας</li> + <li class="animated-name item-2">Lukáš</li> + <li class="animated-name item-2">ルーカス</li> + <li class="animated-name item-1">Lucas</li> + </ul> + </div> + <h1 class=title-header> is a developer working on cool things. </h1> +</div> + +<h2 class="main-heading">Notes</h2> +<div class="notes-container"> + $for(notes)$ + <a href="$it.link$" class="note-link"> + <div class="note-box"> + $it.note$ + </div> + </a> + $endfor$ +</div> diff --git a/templates/main.html b/templates/main.html new file mode 100644 index 0000000..80c55ab --- /dev/null +++ b/templates/main.html @@ -0,0 +1,47 @@ +<!doctype html> + +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + + <title>$title$</title> +$for(author-meta)$ + <meta name="author" content="$author-meta$" /> +$endfor$ +$if(date-meta)$ + <meta name="dcterms.date" content="$date-meta$" /> +$endif$ +$if(keywords)$ + <meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" /> +$endif$ +$if(description-meta)$ + <meta name="description" content="$description-meta$" /> +$endif$ + + <link rel="stylesheet" href="/assets/style.css"> + <link rel="icon" type="image/x-icon" href="/assets/favicon.svg"> +</head> + +<body> + <div class="header-bar"> + <a href="/index.html"> + <img src="/assets/favicon.svg" alt="frycon logo"> + </a> + <div class="header-links"> + $if(show-notes-link)$ + <a href="/notes.html" class="header-link">Notes</a> + $endif$ + <a href="/now.html" class="header-link">Now</a> + <a href="/about.html" class="header-link">About</a> + </div> + </div> + <main> +$if(front_page)$ +${front_page()} +$else$ +${note()} +$endif$ + </main> +</body> +</html> diff --git a/templates/note.html b/templates/note.html new file mode 100644 index 0000000..917d461 --- /dev/null +++ b/templates/note.html @@ -0,0 +1,18 @@ +<div class="page-title-header-container"> + <h1 class="page-title-header">$title$</h1> + $if(date)$ + <div class="page-info-container"> + $if(note_status)$ + $note_status$ + $endif$ + <div class="page-info-date-container"> + <p class="page-info-date">Published: $date$</p> + <p class="page-info-date">Last Edited: $last_edit$</p> + </div> + </div> + $endif$ +</div> +<div class="note-divider"></div> +<div class="note-body"> +$body$ +</div> diff --git a/tools/front_page.lua b/tools/front_page.lua new file mode 100644 index 0000000..37ed783 --- /dev/null +++ b/tools/front_page.lua @@ -0,0 +1,63 @@ + +local function load_notes(note_list) + local notes = {} + for note in string.gmatch(note_list, "%S+") do + table.insert(notes, note) + end + return notes +end + +local function get_note(note_name) + local file = io.open(string.format("build/%s.meta", note_name), "r") + local note = {} + + for line in file:lines() do + local sep = string.find(line, ",") + local index = string.sub(line, 1, sep-1) + local content = string.sub(line, sep+1, -1) + + note[index] = content + end + + note["note_name"] = note_name + + file:close() + return note +end + +local function compare_note_dates(a, b) + return a.last_edit > b.last_edit +end + +function Pandoc(doc) + doc.meta["front_page"] = true + + local notes = {} + local note_names = load_notes(doc.meta["note_list"]) + for index, note in ipairs(note_names) do + table.insert(notes, get_note(note)) + end + + table.sort(notes, compare_note_dates) + + local output = pandoc.MetaList({}) + for index,note in ipairs(notes) do + local out_list = {} + + if note["cover_image"] ~= nil then + local image = pandoc.RawBlock("html", string.format("<img src=\"%s\">", note.cover_image)) + table.insert(out_list, image) + end + + local header = pandoc.Header(2, note.title) + table.insert(out_list, header) + + table.insert(out_list, pandoc.Para(string.format("%s...", note.preview))) + + local out = pandoc.MetaBlocks(out_list) + output:insert(pandoc.MetaMap({link=string.format("/notes/%s.html", note.note_name), note=out})) + end + + doc.meta["notes"] = output + return pandoc.Pandoc(doc.blocks, doc.meta) +end diff --git a/tools/link_gen.lua b/tools/link_gen.lua new file mode 100644 index 0000000..d23b923 --- /dev/null +++ b/tools/link_gen.lua @@ -0,0 +1,147 @@ +local pipe = pandoc.pipe +local stringify = (require 'pandoc.utils').stringify + +local meta = PANDOC_DOCUMENT.meta +local preview = "" +local internal_links = {} +local max_string_length = 100 + +local function append_str(buf, s) + if (#buf + #s) < max_string_length then + buf = buf .. s + end + + return buf +end + +local function file_exists(name) + local f = io.open(name, 'r') + if f ~= nil then + io.close(f) + return true + else + return false + end +end + +local function read_link_file(name) + local f = io.open(name, 'r') + if f ~= nil then + local output = {} + for line in f:lines() do + table.insert(output, line) + end + f:close() + return output + else + return {} + end +end + +local function write_link_file(name, links) + local f = io.open(name, 'w') + for i,v in ipairs(links) do + f:write(string.format("%s\n", v)) + end + f:close() +end + +local function item_in_table(table, item) + local inside = false + for i,v in ipairs(table) do + if v == item then + inside = true + break + end + end + + return inside +end + +local function get_filename(file) + return file:match("^.+/(.+)$") +end + +local function get_input_file() + local file = PANDOC_STATE.input_files[1] + file = get_filename(file) + file = string.gsub(file, ".md", "") + return file +end + +function Doc(body, metadata, variables) + local input_file = get_input_file() + + -- Write out link file for table + for i,v in ipairs(internal_links) do + local markdown_file = "./notes/" .. v .. ".md" + local link_file = "./build/" .. v .. ".links" + + -- check if markdown version of the file exists + if file_exists(markdown_file) then + links = read_link_file(link_file) + if not item_in_table(links, input_file) then + table.insert(links, input_file) + end + + write_link_file(link_file, links) + else + io.stderr:write(string.format("Linking to non-existant file '%s'\n", v)) + end + end + + local values = {} + local output = "" + for k,v in pairs(meta) do + values[k] = stringify(v) + end + + values["preview"] = preview + for k,v in pairs(values) do + output = output .. string.format("%s,%s\n", k, v) + end + + return output +end + +function Str(s) + preview = append_str(preview, s) + return "" +end + +function Space() + preview = append_str(preview, " ") + return "" +end + +function SoftBreak() + return Space() +end + +function LineBreak() + return Space() +end + +function Link(s, tgt, tit, attr) + if not string.find(tgt, "://") then + -- Check if link is already found elsewhere in document + local value_found = false + for index, value in ipairs(internal_links) do + if value == tgt then value_found = true end + end + + if not value_found then + table.insert(internal_links, tgt) + end + end + return "" +end + + +-- Ignore functions we haven't implemented as we don't need them +local meta = {} +meta.__index = + function(_, key) + return function() return '' end + end +setmetatable(_G, meta) diff --git a/tools/note.lua b/tools/note.lua new file mode 100644 index 0000000..3ec9a51 --- /dev/null +++ b/tools/note.lua @@ -0,0 +1,19 @@ +local stringify = (require 'pandoc.utils').stringify + +local status_map = {"seadling", "budding", "evergreen"} + +function Pandoc(doc) + doc.meta["front_page"] = false + + local status = stringify(doc.meta["status"]) + local status_name = status_map[tonumber(status)] + local text = pandoc.Para(status_name) + local image = pandoc.RawBlock("html", string.format("<img src=\"/assets/%s.svg\">", status_name)) + + local div = pandoc.Div({image, text}) + div.classes = {"plant-status"} + + local status_info = pandoc.MetaBlocks(div) + doc.meta["note_status"] = status_info + return pandoc.Pandoc(doc.blocks, doc.meta) +end |