Compare commits
	
		
			21 Commits
		
	
	
		
			86d9122740
			...
			v0.1.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 9a1fda087c | |||
| c5a0cf7ecc | |||
| 9a6973fb89 | |||
| d8094384ad | |||
| 86ca91920f | |||
| 64d6635d5f | |||
| 6a6ae96a96 | |||
| a856b7f634 | |||
| 011802ffbe | |||
| 4fae4fe19a | |||
| d6248865b3 | |||
| 2317fec71d | |||
| ff9ad9e94a | |||
| 4dc69a92c5 | |||
| ba7630c03c | |||
| f9916e5856 | |||
| 7731159dd0 | |||
| 699b3c0189 | |||
| 08f931bbde | |||
| 7da2bb2b64 | |||
| e4194d0925 | 
							
								
								
									
										63
									
								
								README.md
									
									
									
									
									
								
							
							
						
						| @@ -1,3 +1,64 @@ | ||||
| # circuiteria | ||||
|  | ||||
| Drawing block circuits with Typst made easy, using CeTZ | ||||
| Circuiteria is a [Typst](https://typst.app) package for drawing block circuit diagrams using the [CeTZ](https://typst.app/universe/package/cetz) package. | ||||
|  | ||||
| <p align="center"> | ||||
|   <img src="./gallery/platypus.png" alt="Perry the platypus"> | ||||
| </p> | ||||
|  | ||||
| ## Examples | ||||
| <table> | ||||
|   <tr> | ||||
|     <td colspan="2"> | ||||
|       <a href="./gallery/test.typ"> | ||||
|         <img src="./gallery/test.png" width="500px"> | ||||
|       </a> | ||||
|     </td> | ||||
|   </tr> | ||||
|   <tr> | ||||
|     <td colspan="2">A bit of eveything</td> | ||||
|   </tr> | ||||
|   <tr> | ||||
|     <td colspan="2"> | ||||
|       <a href="./gallery/test5.typ"> | ||||
|         <img src="./gallery/test5.png" width="500px"> | ||||
|       </a> | ||||
|     </td> | ||||
|   </tr> | ||||
|   <tr> | ||||
|     <td colspan="2">Wires everywhere</td> | ||||
|   </tr> | ||||
|   <tr> | ||||
|     <td> | ||||
|       <a href="./gallery/test4.typ"> | ||||
|         <img src="./gallery/test4.png" width="250px"> | ||||
|       </a> | ||||
|     </td> | ||||
|     <td> | ||||
|       <a href="./gallery/test6.typ"> | ||||
|         <img src="./gallery/test6.png" width="250px"> | ||||
|       </a> | ||||
|     </td> | ||||
|   </tr> | ||||
|   <tr> | ||||
|     <td>Groups</td> | ||||
|     <td>Rotated</td> | ||||
|   </tr> | ||||
| </table> | ||||
|  | ||||
| > **Note**\ | ||||
| > These circuit layouts were copied from a digital design course given by prof. S. Zahno and recreated using this package | ||||
|  | ||||
| *Click on the example image to jump to the code.* | ||||
|  | ||||
| ## Usage | ||||
| For more information, see the [manual](manual.pdf) | ||||
|  | ||||
| To use this package, simply import [circuiteria](https://typst.app/universe/package/circuiteria) and call the `circuit` function: | ||||
| ```typ | ||||
| #import "@preview/circuiteria:0.1.0" | ||||
| #circuiteria.circuit({ | ||||
|   import circuiteria: * | ||||
|   ... | ||||
| }) | ||||
| ``` | ||||
| @@ -140,4 +140,11 @@ element.block(id: "b3", w: 2, h: 3, | ||||
| wire.wire("w1", ("b1-port-out", "b3-port-in1")) | ||||
| wire.wire("w2", ("b2-port-out", "b3-port-in2"), | ||||
|           style: "zigzag") | ||||
| ```) | ||||
|  | ||||
| #let intersection = example(``` | ||||
| wire.wire("w1", ((0, 0), (1, 1)), style: "zigzag") | ||||
| wire.wire("w2", ((0, 0), (1, -.5)), | ||||
|           style: "zigzag", zigzag-ratio: 80%) | ||||
| wire.intersection("w1.zig") | ||||
| ```) | ||||
							
								
								
									
										40
									
								
								gallery.bash
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,40 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| PDFS=false | ||||
|  | ||||
| while getopts "p" flag | ||||
| do | ||||
|     case "${flag}" in | ||||
|         p) PDFS=true;; | ||||
|     esac | ||||
| done | ||||
|  | ||||
| echo "Generating gallery images" | ||||
|  | ||||
| set -- ./gallery/*.typ | ||||
| cnt="$#" | ||||
| i=1 | ||||
| for f | ||||
| do | ||||
|     f2="${f/typ/png}" | ||||
|     echo "($i/$cnt) $f -> $f2" | ||||
|     typst c --root ./ "$f" "$f2" | ||||
|     i=$((i+1)) | ||||
| done | ||||
|  | ||||
| if [ "$PDFS" = true ] | ||||
| then | ||||
|     echo | ||||
|     echo "Generating gallery PDFs" | ||||
|  | ||||
|     set -- ./gallery/*.typ | ||||
|     cnt="$#" | ||||
|     i=1 | ||||
|     for f | ||||
|     do | ||||
|         f2="${f/typ/pdf}" | ||||
|         echo "($i/$cnt) $f -> $f2" | ||||
|         typst c --root ./ "$f" "$f2" | ||||
|         i=$((i+1)) | ||||
|     done | ||||
| fi | ||||
							
								
								
									
										
											BIN
										
									
								
								gallery/platypus.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								gallery/platypus.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 45 KiB | 
							
								
								
									
										77
									
								
								gallery/platypus.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,77 @@ | ||||
| #import "../src/lib.typ": * | ||||
|  | ||||
| #set page(width: auto, height: auto, margin: .5cm) | ||||
|  | ||||
| #let teal = rgb(37, 155, 166) | ||||
| #let orange = rgb(254, 160, 93) | ||||
| #let brown = rgb(97, 54, 60) | ||||
|  | ||||
| #circuit({ | ||||
|   element.group(id: "platypus", name: "A platypus", { | ||||
|     element.block( | ||||
|       x: 0, y: 0, w: 2, h: 3, id: "body", | ||||
|       fill: teal, | ||||
|       ports: ( | ||||
|         east: ( | ||||
|           (id: "out"), | ||||
|         ) | ||||
|       ), | ||||
|       ports-margins: ( | ||||
|         east: (50%, 10%) | ||||
|       ) | ||||
|     ) | ||||
|  | ||||
|     element.block( | ||||
|       x: 2.5, y: 1.5, w: 1.5, h: 1, id: "beak", | ||||
|       fill: orange, | ||||
|       ports: ( | ||||
|         south: ( | ||||
|           (id: "in"), | ||||
|         ) | ||||
|       ) | ||||
|     ) | ||||
|  | ||||
|     wire.wire("w1", ("body-port-out", "beak-port-in"), style: "zigzag", zigzag-ratio: 100%) | ||||
|   }) | ||||
|  | ||||
|   let O = (rel: (2, 0), to: "platypus.south-east") | ||||
|    | ||||
|   element.group(id: "perry", name: "Perry the platypus", { | ||||
|     element.block( | ||||
|       x: (rel: 0, to: O), y: 0, w: 2, h: 3, id: "body", | ||||
|       fill: teal, | ||||
|       ports: ( | ||||
|         east: ( | ||||
|           (id: "out"), | ||||
|         ) | ||||
|       ), | ||||
|       ports-margins: ( | ||||
|         east: (50%, 10%) | ||||
|       ) | ||||
|     ) | ||||
|  | ||||
|     element.block( | ||||
|       x: (rel: 2.5, to: O), y: 1.5, w: 1.5, h: 1, id: "beak", | ||||
|       fill: orange, | ||||
|       ports: ( | ||||
|         south: ( | ||||
|           (id: "in"), | ||||
|         ) | ||||
|       ) | ||||
|     ) | ||||
|  | ||||
|     element.block( | ||||
|       x: (rel: 0.25, to: O), y: 3.2, w: 1.5, h: 0.5, id: "hat", | ||||
|       fill: brown | ||||
|     ) | ||||
|  | ||||
|     wire.wire("w2", ("body-port-out", "beak-port-in"), style: "zigzag", zigzag-ratio: 100%) | ||||
|   }) | ||||
|  | ||||
|   wire.wire( | ||||
|     "w3", | ||||
|     ("platypus.east", (horizontal: "perry.west", vertical: ())), | ||||
|     directed: true, | ||||
|     bus: true | ||||
|   ) | ||||
| }) | ||||
							
								
								
									
										
											BIN
										
									
								
								gallery/test.pdf
									
									
									
									
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								gallery/test.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 142 KiB | 
| @@ -1,6 +1,6 @@ | ||||
| #import "../src/lib.typ": circuit, element, util, wire | ||||
|  | ||||
| #set page(flipped: true) | ||||
| #set page(width: auto, height: auto, margin: .5cm) | ||||
|  | ||||
| #circuit({ | ||||
|   element.block( | ||||
| @@ -294,6 +294,6 @@ | ||||
|     bus: true | ||||
|   ) | ||||
|  | ||||
|   wire.intersection("wResMP-RegFile.dodge-end") | ||||
|   wire.intersection("wResMP-AdrSrc.dodge-end") | ||||
|   wire.intersection("wResMP-RegFile.dodge-end", radius: .2) | ||||
|   wire.intersection("wResMP-AdrSrc.dodge-end", radius: .2) | ||||
| }) | ||||
							
								
								
									
										
											BIN
										
									
								
								gallery/test2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 142 KiB | 
| @@ -1,6 +1,6 @@ | ||||
| #import "../src/lib.typ": circuit, element, util, wire | ||||
|  | ||||
| #set page(flipped: true) | ||||
| #set page(width: auto, height: auto, margin: .5cm) | ||||
|  | ||||
| #circuit({ | ||||
|   element.block( | ||||
| @@ -307,6 +307,6 @@ | ||||
|     bus: true | ||||
|   ) | ||||
|    | ||||
|   wire.intersection("wResMP-RegFile.dodge-end") | ||||
|   wire.intersection("wResMP-AdrSrc.dodge-end") | ||||
|   wire.intersection("wResMP-RegFile.dodge-end", radius: .2) | ||||
|   wire.intersection("wResMP-AdrSrc.dodge-end", radius: .2) | ||||
| }) | ||||
							
								
								
									
										
											BIN
										
									
								
								gallery/test3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 66 KiB | 
| @@ -1,8 +1,7 @@ | ||||
| #import "@preview/cetz:0.2.2": draw | ||||
| #import "../src/lib.typ": circuit, element, util, wire | ||||
|  | ||||
| #set page(flipped: true) | ||||
| #let debug = false | ||||
| #set page(width: auto, height: auto, margin: .5cm) | ||||
|  | ||||
| #circuit({ | ||||
|   element.block( | ||||
| @@ -14,18 +13,14 @@ | ||||
|         (id: "out1"), | ||||
|         (id: "out2"), | ||||
|       ) | ||||
|     ), | ||||
|     debug: ( | ||||
|       ports: debug  | ||||
|  | ||||
|     ) | ||||
|   ) | ||||
|   element.gate-and( | ||||
|     x: 4, y: 0, w: 2, h: 2, id: "and1", debug: (ports: debug), | ||||
|     x: 4, y: 0, w: 2, h: 2, id: "and1", | ||||
|     inverted: ("in1") | ||||
|   ) | ||||
|   element.gate-or( | ||||
|     x: 7, y: 0, w: 2, h: 2, id: "or1", debug: (ports: debug), | ||||
|     x: 7, y: 0, w: 2, h: 2, id: "or1", | ||||
|     inverted: ("in0", "out") | ||||
|   ) | ||||
|  | ||||
| @@ -47,7 +42,7 @@ | ||||
|   ) | ||||
|  | ||||
|   element.gate-and( | ||||
|     x: 11, y: 0, w: 2, h: 2, id: "and2", inputs: 3, debug: (ports: debug), | ||||
|     x: 11, y: 0, w: 2, h: 2, id: "and2", inputs: 3, | ||||
|     inverted: ("in0", "in2") | ||||
|   ) | ||||
|   for i in range(3) { | ||||
| @@ -55,35 +50,35 @@ | ||||
|   } | ||||
|  | ||||
|   element.gate-xor( | ||||
|     x: 14, y: 0, w: 2, h: 2, id: "xor", debug: (ports: debug), | ||||
|     x: 14, y: 0, w: 2, h: 2, id: "xor", | ||||
|     inverted: ("in1") | ||||
|   ) | ||||
|    | ||||
|   element.gate-buf( | ||||
|     x: 0, y: -3, w: 2, h: 2, id: "buf", debug: (ports: debug) | ||||
|     x: 0, y: -3, w: 2, h: 2, id: "buf" | ||||
|   ) | ||||
|   element.gate-not( | ||||
|     x: 0, y: -6, w: 2, h: 2, id: "not", debug: (ports: debug) | ||||
|     x: 0, y: -6, w: 2, h: 2, id: "not" | ||||
|   ) | ||||
|    | ||||
|   element.gate-and( | ||||
|     x: 3, y: -3, w: 2, h: 2, id: "and", debug: (ports: debug) | ||||
|     x: 3, y: -3, w: 2, h: 2, id: "and" | ||||
|   ) | ||||
|   element.gate-nand( | ||||
|     x: 3, y: -6, w: 2, h: 2, id: "nand", debug: (ports: debug) | ||||
|     x: 3, y: -6, w: 2, h: 2, id: "nand" | ||||
|   ) | ||||
|    | ||||
|   element.gate-or( | ||||
|     x: 6, y: -3, w: 2, h: 2, id: "or", debug: (ports: debug) | ||||
|     x: 6, y: -3, w: 2, h: 2, id: "or" | ||||
|   ) | ||||
|   element.gate-nor( | ||||
|     x: 6, y: -6, w: 2, h: 2, id: "nor", debug: (ports: debug) | ||||
|     x: 6, y: -6, w: 2, h: 2, id: "nor" | ||||
|   ) | ||||
|    | ||||
|   element.gate-xor( | ||||
|     x: 9, y: -3, w: 2, h: 2, id: "xor", debug: (ports: debug) | ||||
|     x: 9, y: -3, w: 2, h: 2, id: "xor" | ||||
|   ) | ||||
|   element.gate-xnor( | ||||
|     x: 9, y: -6, w: 2, h: 2, id: "xnor", debug: (ports: debug) | ||||
|     x: 9, y: -6, w: 2, h: 2, id: "xnor" | ||||
|   ) | ||||
| }) | ||||
							
								
								
									
										
											BIN
										
									
								
								gallery/test4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 159 KiB | 
| @@ -1,7 +1,7 @@ | ||||
| #import "@preview/cetz:0.2.2": draw | ||||
| #import "../src/lib.typ": * | ||||
|  | ||||
| #set page(flipped: true) | ||||
| #set page(width: auto, height: auto, margin: .5cm) | ||||
|  | ||||
| #circuit({ | ||||
|   element.group(id: "toplvl", name: "Toplevel", { | ||||
| @@ -18,7 +18,7 @@ | ||||
|         name: "Datapath", | ||||
|         ports: ( | ||||
|           north: ( | ||||
|             (id: "clk", clock: true), | ||||
|             (id: "clk", clock: true, small: true), | ||||
|             (id: "Zero"), | ||||
|             (id: "Regsrc"), | ||||
|             (id: "PCSrc"), | ||||
| @@ -104,7 +104,7 @@ | ||||
|       name: "Data\n Memory", | ||||
|       ports: ( | ||||
|         north: ( | ||||
|           (id: "clk", clock: true), | ||||
|           (id: "clk", clock: true, small: true), | ||||
|           (id: "WE", name: "WE") | ||||
|         ), | ||||
|         west: ( | ||||
| @@ -200,18 +200,22 @@ | ||||
|     draw.content("dmem.south-west", [*External Memories*], anchor: "north", padding: 10pt) | ||||
|   }) | ||||
|  | ||||
|   wire.wire( | ||||
|     "w-dp-clk", | ||||
|     ("dp-port-clk", (-1, 4.2)), | ||||
|     style: "zigzag", | ||||
|     zigzag-dir: "horizontal", | ||||
|     zigzag-ratio: 100% | ||||
|   draw.line(name: "w-dp-clk", | ||||
|     "dp-port-clk", | ||||
|     (rel: (0, .5), to: ()), | ||||
|     ( | ||||
|       rel: (-.5, 0), | ||||
|       to: (horizontal: "toplvl.west", vertical: ()) | ||||
|     ) | ||||
|   ) | ||||
|   draw.content("w-dp-clk.end", "clk", anchor: "east", padding: 3pt) | ||||
|    | ||||
|   wire.wire( | ||||
|     "w-dp-rst", | ||||
|     ("dp-port-rst", (horizontal: (-1, 0), vertical: ())) | ||||
|   draw.line(name: "w-dp-rst", | ||||
|     "dp-port-rst", | ||||
|     ( | ||||
|       rel: (-.5, 0), | ||||
|       to: (horizontal: "toplvl.west", vertical: ()) | ||||
|     ) | ||||
|   ) | ||||
|   draw.content("w-dp-rst.end", "rst", anchor: "east", padding: 3pt) | ||||
| }) | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								gallery/test5.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								gallery/test5.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 276 KiB | 
							
								
								
									
										435
									
								
								gallery/test5.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,435 @@ | ||||
| #import "@preview/cetz:0.2.2": draw | ||||
| #import "../src/lib.typ": * | ||||
|  | ||||
| #set page(width: auto, height: auto, margin: .5cm) | ||||
|  | ||||
| #circuit({ | ||||
|   element.multiplexer( | ||||
|     x: 0, y: 0, w: .5, h: 1.5, id: "PCMux", | ||||
|     entries: 2, | ||||
|     fill: util.colors.blue, | ||||
|     h-ratio: 80% | ||||
|   ) | ||||
|   element.block( | ||||
|     x: (rel: 2, to: "PCMux.east"), | ||||
|     y: (from: "PCMux-port-out", to: "in"), | ||||
|     w: 1, h: 1.5, id: "PCBuf", | ||||
|     ports: ( | ||||
|       north: ((id: "clk", clock: true),), | ||||
|       west: ((id: "in"),), | ||||
|       east: ((id: "out"),) | ||||
|     ), | ||||
|     fill: util.colors.green | ||||
|   ) | ||||
|  | ||||
|   element.block( | ||||
|     x: (rel: 2, to: "PCBuf.east"), | ||||
|     y: (from: "PCBuf-port-out", to: "A"), | ||||
|     w: 3, h: 4, id: "IMem", | ||||
|     ports: ( | ||||
|       west: ( | ||||
|         (id: "A", name: "A"), | ||||
|       ), | ||||
|       east: ( | ||||
|         (id: "RD", name: "RD"), | ||||
|       ) | ||||
|     ), | ||||
|     ports-margins: ( | ||||
|       west: (0%, 50%), | ||||
|       east: (0%, 50%) | ||||
|     ), | ||||
|     fill: util.colors.green, | ||||
|     name: "Instruction\nMemory" | ||||
|   ) | ||||
|   element.block( | ||||
|     x: (rel: 3, to: "IMem.east"), | ||||
|     y: (from: "IMem-port-RD", to: "A1"), | ||||
|     w: 4.5, h: 4, id: "RegFile", | ||||
|     ports: ( | ||||
|       north: ( | ||||
|         (id: "clk", clock: true, small: true), | ||||
|         (id: "WE3", name: "WE3"), | ||||
|         (id: "dummy1") | ||||
|       ), | ||||
|       west: ( | ||||
|         (id: "dummy2"), | ||||
|         (id: "A1", name: "A1"), | ||||
|         (id: "dummy3"), | ||||
|         (id: "A2", name: "A2"), | ||||
|         (id: "A3", name: "A3"), | ||||
|         (id: "dummy4"), | ||||
|         (id: "WD3", name: "WD3"), | ||||
|       ), | ||||
|       east: ( | ||||
|         (id: "RD1", name: "RD1"), | ||||
|         (id: "RD2", name: "RD2"), | ||||
|       ) | ||||
|     ), | ||||
|     ports-margins: ( | ||||
|       north: (-20%, -20%), | ||||
|       east: (0%, 10%) | ||||
|     ), | ||||
|     fill: util.colors.green, | ||||
|     name: "Register\nFile" | ||||
|   ) | ||||
|  | ||||
|   element.alu( | ||||
|     x: (rel: -.7, to: "IMem.center"), | ||||
|     y: -7, | ||||
|     w: 1.4, h: 2.8, id: "PCAdd", | ||||
|     name: text("+", size: 1.5em), | ||||
|     name-anchor: "name", | ||||
|     fill: util.colors.pink | ||||
|   ) | ||||
|   element.extender( | ||||
|     x: (rel: 0, to: "RegFile.west"), | ||||
|     y: (from: "PCAdd-port-out", to: "in"), | ||||
|     w: 4, h: 1.5, id: "Ext", | ||||
|     h-ratio: 50%, | ||||
|     name: "Extend", | ||||
|     name-anchor: "south", | ||||
|     align-out: false, | ||||
|     fill: util.colors.green | ||||
|   ) | ||||
|  | ||||
|   element.multiplexer( | ||||
|     x: (rel: 3, to: "RegFile.east"), | ||||
|     y: (from: "RegFile-port-RD2", to: "in0"), | ||||
|     w: .5, h: 1.5, id: "SrcBMux", | ||||
|     fill: util.colors.blue, | ||||
|     h-ratio: 80% | ||||
|   ) | ||||
|  | ||||
|   element.alu( | ||||
|     x: (rel: 2, to: "SrcBMux.east"), | ||||
|     y: (from: "SrcBMux-port-out", to: "in2"), | ||||
|     w: 1.4, h: 2.8, id: "ALU", | ||||
|     name: rotate("ALU", -90deg), | ||||
|     name-anchor: "name", | ||||
|     fill: util.colors.pink | ||||
|   ) | ||||
|   element.alu( | ||||
|     x: (rel: 2, to: "SrcBMux.east"), | ||||
|     y: (from: "Ext-port-out", to: "in2"), | ||||
|     w: 1.4, h: 2.8, id: "JumpAdd", | ||||
|     name: text("+", size: 1.5em), | ||||
|     name-anchor: "name", | ||||
|     fill: util.colors.pink | ||||
|   ) | ||||
|  | ||||
|   element.block( | ||||
|     x: (rel: 4, to: "ALU.east"), | ||||
|     y: (from: "ALU-port-out", to: "A"), | ||||
|     w: 3, h: 4, id: "DMem", | ||||
|     name: "Data\nMemory", | ||||
|     ports: ( | ||||
|       north: ( | ||||
|         (id: "clk", clock: true, small: true), | ||||
|         (id: "dummy1"), | ||||
|         (id: "WE", name: "WE") | ||||
|       ), | ||||
|       west: ( | ||||
|         (id: "A", name: "A"), | ||||
|         (id: "WD", name: "WD") | ||||
|       ), | ||||
|       east: ( | ||||
|         (id: "RD", name: "RD"), | ||||
|         (id: "dummy2") | ||||
|       ) | ||||
|     ), | ||||
|     ports-margins: ( | ||||
|       north: (-10%, -10%), | ||||
|       west: (-20%, -30%), | ||||
|       east: (-10%, -20%) | ||||
|     ), | ||||
|     fill: util.colors.green | ||||
|   ) | ||||
|  | ||||
|   element.multiplexer( | ||||
|     x: (rel: 3, to: "DMem.east"), | ||||
|     y: (from: "DMem-port-RD", to: "in1"), | ||||
|     w: .5, h: 1.5, id: "ResMux", | ||||
|     entries: 2, | ||||
|     fill: util.colors.blue, | ||||
|     h-ratio: 80% | ||||
|   ) | ||||
|  | ||||
|   element.block( | ||||
|     x: (rel: 0, to: "RegFile.west"), | ||||
|     y: 3.5, w: 2.5, h: 5, id: "Ctrl", | ||||
|     name: "Control\nUnit", | ||||
|     name-anchor: "north", | ||||
|     ports: ( | ||||
|       west: ( | ||||
|         (id: "op", name: "op"), | ||||
|         (id: "funct3", name: "funct3"), | ||||
|         (id: "funct7", name: [funct7#sub("[5]")]), | ||||
|         (id: "zero", name: "Zero"), | ||||
|       ), | ||||
|       east: ( | ||||
|         (id: "PCSrc"), | ||||
|         (id: "ResSrc"), | ||||
|         (id: "MemWrite"), | ||||
|         (id: "ALUCtrl"), | ||||
|         (id: "ALUSrc"), | ||||
|         (id: "ImmSrc"), | ||||
|         (id: "RegWrite"), | ||||
|       ) | ||||
|     ), | ||||
|     ports-margins: ( | ||||
|       west: (40%, 0%) | ||||
|     ), | ||||
|     fill: util.colors.orange | ||||
|   ) | ||||
|  | ||||
|   // Wires | ||||
|   wire.wire( | ||||
|     "wPCNext", ("PCMux-port-out", "PCBuf-port-in"), | ||||
|     name: "PCNext" | ||||
|   ) | ||||
|   wire.stub("PCBuf-port-clk", "north", name: "clk", length: 0.25) | ||||
|   wire.wire( | ||||
|     "wPC1", ("PCBuf-port-out", "IMem-port-A"), | ||||
|     name: "PC" | ||||
|   ) | ||||
|   wire.wire( | ||||
|     "wPC2", ("PCBuf-port-out", "JumpAdd-port-in1"), | ||||
|     style: "zigzag", | ||||
|     zigzag-ratio: 1 | ||||
|   ) | ||||
|   wire.wire( | ||||
|     "wPC3", ("PCBuf-port-out", "PCAdd-port-in1"), | ||||
|     style: "zigzag", | ||||
|     zigzag-ratio: 1 | ||||
|   ) | ||||
|   wire.intersection("wPC2.zig") | ||||
|   wire.intersection("wPC2.zag") | ||||
|   wire.stub("PCAdd-port-in2", "west", name: "4", length: 1.5) | ||||
|   wire.wire( | ||||
|     "wPC+4", ("PCAdd-port-out", "PCMux-port-in0"), | ||||
|     style: "dodge", | ||||
|     dodge-sides: ("east", "west"), | ||||
|     dodge-y: -7.5, | ||||
|     dodge-margins: (1.2, .5), | ||||
|     name: "PC+4", | ||||
|     name-pos: "start" | ||||
|   ) | ||||
|    | ||||
|   let mid = ("IMem-port-RD", 50%, "RegFile-port-A1") | ||||
|   wire.wire( | ||||
|     "wInstr", ("IMem-port-RD", mid), | ||||
|     bus: true, | ||||
|     name: "Instr", | ||||
|     name-pos: "start" | ||||
|   ) | ||||
|   draw.hide({ | ||||
|     draw.line(name: "bus-top", | ||||
|       mid, | ||||
|       (horizontal: (), vertical: "Ctrl-port-op") | ||||
|     ) | ||||
|     draw.line(name: "bus-bot", | ||||
|       mid, | ||||
|       (horizontal: (), vertical: "Ext-port-in") | ||||
|     ) | ||||
|   }) | ||||
|   wire.wire( | ||||
|     "wInstrBus", ("bus-top.end", "bus-bot.end"), | ||||
|     bus: true | ||||
|   ) | ||||
|   wire.wire( | ||||
|     "wOp", ("Ctrl-port-op", (horizontal: mid, vertical: ())), | ||||
|     bus: true, | ||||
|     reverse: true, | ||||
|     slice: (6, 0) | ||||
|   ) | ||||
|   wire.wire( | ||||
|     "wF3", ("Ctrl-port-funct3", (horizontal: mid, vertical: ())), | ||||
|     bus: true, | ||||
|     reverse: true, | ||||
|     slice: (14, 12) | ||||
|   ) | ||||
|   wire.wire( | ||||
|     "wF7", ("Ctrl-port-funct7", (horizontal: mid, vertical: ())), | ||||
|     bus: true, | ||||
|     reverse: true, | ||||
|     slice: (30,) | ||||
|   ) | ||||
|   wire.wire( | ||||
|     "wA1", ("RegFile-port-A1", (horizontal: mid, vertical: ())), | ||||
|     bus: true, | ||||
|     reverse: true, | ||||
|     slice: (19, 15) | ||||
|   ) | ||||
|   wire.wire( | ||||
|     "wA2", ("RegFile-port-A2", (horizontal: mid, vertical: ())), | ||||
|     bus: true, | ||||
|     reverse: true, | ||||
|     slice: (24, 20) | ||||
|   ) | ||||
|   wire.wire( | ||||
|     "wA3", ("RegFile-port-A3", (horizontal: mid, vertical: ())), | ||||
|     bus: true, | ||||
|     reverse: true, | ||||
|     slice: (11, 7) | ||||
|   ) | ||||
|   wire.wire( | ||||
|     "wExt", ("Ext-port-in", (horizontal: mid, vertical: ())), | ||||
|     bus: true, | ||||
|     reverse: true, | ||||
|     slice: (31, 7) | ||||
|   ) | ||||
|   wire.intersection("wF3.end") | ||||
|   wire.intersection("wF7.end") | ||||
|   wire.intersection("wA1.end") | ||||
|   wire.intersection("wA2.end") | ||||
|   wire.intersection("wA3.end") | ||||
|  | ||||
|   wire.stub("RegFile-port-clk", "north", name: "clk", length: 0.25) | ||||
|   wire.wire("wRD2", ("RegFile-port-RD2", "SrcBMux-port-in0")) | ||||
|   wire.wire( | ||||
|     "wWD", ("RegFile-port-RD2", "DMem-port-WD"), | ||||
|     style: "zigzag", | ||||
|     zigzag-ratio: 1.5, | ||||
|     name: "WriteData", | ||||
|     name-pos: "end" | ||||
|   ) | ||||
|   wire.intersection("wWD.zig") | ||||
|  | ||||
|   wire.wire( | ||||
|     "wImmALU", ("Ext-port-out", "SrcBMux-port-in1"), | ||||
|     style: "zigzag", | ||||
|     zigzag-ratio: 2.5, | ||||
|     name: "ImmExt", | ||||
|     name-pos: "start" | ||||
|   ) | ||||
|   wire.wire( | ||||
|     "wImmJump", ("Ext-port-out", "JumpAdd-port-in2") | ||||
|   ) | ||||
|   wire.intersection("wImmALU.zig") | ||||
|   wire.wire( | ||||
|     "wJumpPC", ("JumpAdd-port-out", "PCMux-port-in1"), | ||||
|     style: "dodge", | ||||
|     dodge-sides: ("east", "west"), | ||||
|     dodge-y: -8, | ||||
|     dodge-margins: (1, 1), | ||||
|     name: "PCTarget", | ||||
|     name-pos: "start" | ||||
|   ) | ||||
|  | ||||
|   wire.wire( | ||||
|     "wSrcA", ("RegFile-port-RD1", "ALU-port-in1"), | ||||
|     name: "SrcA", | ||||
|     name-pos: "end" | ||||
|   ) | ||||
|   wire.wire( | ||||
|     "wSrcB", ("SrcBMux-port-out", "ALU-port-in2"), | ||||
|     name: "SrcB", | ||||
|     name-pos: "end" | ||||
|   ) | ||||
|  | ||||
|   wire.wire( | ||||
|     "wZero", ( | ||||
|       ("ALU.north-east", 50%, "ALU-port-out"), | ||||
|       "Ctrl-port-zero" | ||||
|     ), | ||||
|     style: "dodge", | ||||
|     dodge-sides: ("east", "west"), | ||||
|     dodge-y: 3, | ||||
|     dodge-margins: (1.5, 1), | ||||
|     name: "Zero", | ||||
|     name-pos: "start" | ||||
|   ) | ||||
|   wire.wire( | ||||
|     "wALURes1", ("ALU-port-out", "DMem-port-A"), | ||||
|     name: "ALUResult", | ||||
|     name-pos: "start" | ||||
|   ) | ||||
|   wire.wire( | ||||
|     "wALURes2", ("ALU-port-out", "ResMux-port-in0"), | ||||
|     style: "dodge", | ||||
|     dodge-sides: ("east", "west"), | ||||
|     dodge-y: 2, | ||||
|     dodge-margins: (3, 2) | ||||
|   ) | ||||
|   wire.intersection("wALURes2.start2") | ||||
|  | ||||
|   wire.stub("DMem-port-clk", "north", name: "clk", length: 0.25) | ||||
|   wire.wire( | ||||
|     "wRD", ("DMem-port-RD", "ResMux-port-in1"), | ||||
|     name: "ReadData", | ||||
|     name-pos: "start" | ||||
|   ) | ||||
|  | ||||
|   wire.wire( | ||||
|     "wRes", ("ResMux-port-out", "RegFile-port-WD3"), | ||||
|     style: "dodge", | ||||
|     dodge-sides: ("east", "west"), | ||||
|     dodge-y: -7.5, | ||||
|     dodge-margins: (1, 2) | ||||
|   ) | ||||
|   draw.content( | ||||
|     "wRes.dodge-start", | ||||
|     "Result", | ||||
|     anchor: "south-east", | ||||
|     padding: 5pt | ||||
|   ) | ||||
|  | ||||
|   // Other wires | ||||
|   draw.group({ | ||||
|     draw.stroke(util.colors.blue) | ||||
|     draw.line(name: "wPCSrc",  | ||||
|       "Ctrl-port-PCSrc", | ||||
|       (horizontal: "RegFile.east", vertical: ()), | ||||
|       (horizontal: (), vertical: (rel: (0, 0.5), to: "Ctrl.north")), | ||||
|       (horizontal: "PCMux.north", vertical: ()), | ||||
|       "PCMux.north" | ||||
|     ) | ||||
|     draw.line(name: "wResSrc", | ||||
|       "Ctrl-port-ResSrc", | ||||
|       (horizontal: "ResMux.north", vertical: ()), | ||||
|       "ResMux.north" | ||||
|     ) | ||||
|     draw.line(name: "wMemWrite", | ||||
|       "Ctrl-port-MemWrite", | ||||
|       (horizontal: "DMem-port-WE", vertical: ()), | ||||
|       "DMem-port-WE" | ||||
|     ) | ||||
|     draw.line(name: "wALUCtrl", | ||||
|       "Ctrl-port-ALUCtrl", | ||||
|       (horizontal: "ALU.north", vertical: ()), | ||||
|       "ALU.north" | ||||
|     ) | ||||
|     draw.line(name: "wALUSrc", | ||||
|       "Ctrl-port-ALUSrc", | ||||
|       (horizontal: "SrcBMux.north", vertical: ()), | ||||
|       "SrcBMux.north" | ||||
|     ) | ||||
|     draw.line(name: "wImmSrc", | ||||
|       "Ctrl-port-ImmSrc", | ||||
|       (rel: (1, 0), to: (horizontal: "RegFile.east", vertical: ())), | ||||
|       (horizontal: (), vertical: (rel: (0, -.5), to: "RegFile.south")), | ||||
|       (horizontal: "Ext.north", vertical: ()), | ||||
|       "Ext.north" | ||||
|     ) | ||||
|     draw.line(name: "wRegWrite", | ||||
|       "Ctrl-port-RegWrite", | ||||
|       (rel: (.5, 0), to: (horizontal: "RegFile.east", vertical: ())), | ||||
|       (horizontal: (), vertical: ("Ctrl.south", 50%, "RegFile.north")), | ||||
|       (horizontal: "RegFile-port-WE3", vertical: ()), | ||||
|       "RegFile-port-WE3" | ||||
|     ) | ||||
|  | ||||
|     let names = ( | ||||
|       "PCSrc": "PCSrc", | ||||
|       "ResSrc": "ResultSrc", | ||||
|       "MemWrite": "MemWrite", | ||||
|       "ALUCtrl": [ALUControl#sub("[2:0]")], | ||||
|       "ALUSrc": "ALUSrc", | ||||
|       "ImmSrc": [ImmSrc#sub("[1:0]")], | ||||
|       "RegWrite": "RegWrite" | ||||
|     ) | ||||
|     for (port, name) in names { | ||||
|       draw.content("Ctrl-port-"+port, name, anchor: "south-west", padding: 3pt) | ||||
|     } | ||||
|   }) | ||||
| }) | ||||
							
								
								
									
										
											BIN
										
									
								
								gallery/test6.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								gallery/test6.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 76 KiB | 
							
								
								
									
										194
									
								
								gallery/test6.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,194 @@ | ||||
| #import "@preview/cetz:0.2.2": draw, vector | ||||
| #import "../src/lib.typ": * | ||||
|  | ||||
| #set page(width: auto, height: auto, margin: .5cm) | ||||
|  | ||||
| #circuit({ | ||||
|   element.multiplexer( | ||||
|     x: 10, y: 0, w: 1, h: 6, id: "ResMux", | ||||
|     entries: ("000", "001", "010", "011", "101"), | ||||
|     h-ratio: 90%, | ||||
|     fill: util.colors.blue | ||||
|   ) | ||||
|   element.extender( | ||||
|     x: (rel: -3, to: "ResMux.west"), | ||||
|     y: (from: "ResMux-port-in4", to: "out"), | ||||
|     w: 2, h: 1, id: "Ext", | ||||
|     name: "Zero Ext", | ||||
|     name-anchor: "south", | ||||
|     fill: util.colors.green | ||||
|   ) | ||||
|   gates.gate-or( | ||||
|     x: (rel: -2, to: "ResMux.west"), | ||||
|     y: (from: "ResMux-port-in3", to: "out"), | ||||
|     w: 1, h: 1, id: "Or" | ||||
|   ) | ||||
|   gates.gate-and( | ||||
|     x: (rel: -2, to: "ResMux.west"), | ||||
|     y: (from: "ResMux-port-in2", to: "out"), | ||||
|     w: 1, h: 1, id: "And" | ||||
|   ) | ||||
|   element.alu( | ||||
|     x: (rel: -2.5, to: "Ext.west"), | ||||
|     y: (from: "ResMux-port-in0", to: "out"), | ||||
|     w: 1.5, h: 3, id: "Add", | ||||
|     name: text("+", size: 1.5em), | ||||
|     name-anchor: "name", | ||||
|     fill: util.colors.pink | ||||
|   ) | ||||
|   element.multiplexer( | ||||
|     x: (rel: -1.5, to: "Add.west"), | ||||
|     y: (from: "Add-port-in1", to: "out"), | ||||
|     w: 0.5, h: 1.5, id: "NotMux", | ||||
|     h-ratio: 80%, | ||||
|     fill: util.colors.blue | ||||
|   ) | ||||
|   gates.gate-not( | ||||
|     x: (rel: -2, to: "NotMux.west"), | ||||
|     y: (from: "NotMux-port-in1", to: "out"), | ||||
|     w: 1, h: 1, id: "Not" | ||||
|   ) | ||||
|    | ||||
|   draw.hide( | ||||
|     draw.line(name: "l1", | ||||
|       "Not-port-in0", | ||||
|       (rel: (-2, 0), to: ()), | ||||
|       (horizontal: (), vertical: "NotMux-port-in0") | ||||
|     ) | ||||
|   ) | ||||
|   let b = "l1.end" | ||||
|   draw.hide( | ||||
|     draw.line(name: "l2", | ||||
|       b, | ||||
|       (horizontal: (), vertical: "Add-port-in2") | ||||
|     ) | ||||
|   ) | ||||
|   let a = "l2.end" | ||||
|  | ||||
|   wire.wire("wB0", (b, "NotMux-port-in0"), bus: true) | ||||
|   wire.wire( | ||||
|     "wB1", (b, "Not-port-in0"), | ||||
|     style: "zigzag", | ||||
|     zigzag-ratio: 1.5, | ||||
|     bus: true | ||||
|   ) | ||||
|   wire.wire( | ||||
|     "wB2", (b, "And-port-in0"), | ||||
|     style: "zigzag", | ||||
|     zigzag-ratio: 1, | ||||
|     bus: true | ||||
|   ) | ||||
|   wire.wire( | ||||
|     "wB3", (b, "Or-port-in0"), | ||||
|     style: "zigzag", | ||||
|     zigzag-ratio: 1, | ||||
|     bus: true | ||||
|   ) | ||||
|   wire.intersection("wB1.zig") | ||||
|   wire.intersection("wB2.zig") | ||||
|   wire.intersection("wB2.zag") | ||||
|  | ||||
|   wire.wire("wNot", ("Not-port-out", "NotMux-port-in1"), bus: true) | ||||
|   wire.wire("wAddA", ("NotMux-port-out", "Add-port-in1"), bus: true) | ||||
|  | ||||
|   wire.wire("wA0", (a, "Add-port-in2"), bus: true) | ||||
|   wire.wire( | ||||
|     "wA1", (a, "And-port-in1"), | ||||
|     style: "zigzag", | ||||
|     zigzag-ratio: 0.5, | ||||
|     bus: true | ||||
|   ) | ||||
|   wire.wire( | ||||
|     "wA2", (a, "Or-port-in1"), | ||||
|     style: "zigzag", | ||||
|     zigzag-ratio: 0.5, | ||||
|     bus: true | ||||
|   ) | ||||
|   wire.intersection("wA1.zig") | ||||
|   wire.intersection("wA1.zag") | ||||
|  | ||||
|   wire.wire("wMux0", ("Add-port-out", "ResMux-port-in0"), bus: true) | ||||
|   wire.wire( | ||||
|     "wMux1", ("Add-port-out", "ResMux-port-in1"), | ||||
|     style: "zigzag", | ||||
|     zigzag-ratio: 2, | ||||
|     bus: true | ||||
|   ) | ||||
|   wire.wire("wMux2", ("And-port-out", "ResMux-port-in2"), bus: true) | ||||
|   wire.wire("wMux3", ("Or-port-out", "ResMux-port-in3"), bus: true) | ||||
|   wire.wire("wMux4", ("Ext-port-out", "ResMux-port-in4"), bus: true) | ||||
|  | ||||
|   wire.wire( | ||||
|     "wAdd", ("Add-port-out", "Ext-port-in"), | ||||
|     style: "zigzag", | ||||
|     zigzag-ratio: 0.5, | ||||
|     bus: true | ||||
|   ) | ||||
|  | ||||
|   wire.intersection("wMux1.zig") | ||||
|   wire.intersection("wAdd.zig") | ||||
|  | ||||
|   let c = (rel: (0, 2), to: "ResMux.north") | ||||
|   wire.wire("wResCtrl", (c, "ResMux.north"), bus: true) | ||||
|   wire.wire( | ||||
|     "wAddCtrl", (c, "Add.north"), | ||||
|     style: "zigzag", | ||||
|     zigzag-dir: "horizontal" | ||||
|   ) | ||||
|  | ||||
|   let d = (rel: (1, 0), to: "ResMux-port-out") | ||||
|   wire.wire("wRes", ("ResMux-port-out", d), bus: true) | ||||
|  | ||||
|   draw.content( | ||||
|     "wAddCtrl.zag", | ||||
|     [ALUControl#sub("[1]")], | ||||
|     anchor: "south-west", | ||||
|     padding: 3pt | ||||
|   ) | ||||
|    | ||||
|   wire.wire( | ||||
|     "wCout", ("Add.south", (horizontal: (), vertical: "Ext.north-east")) | ||||
|   ) | ||||
|   draw.content( | ||||
|     "wCout.end", | ||||
|     [C#sub("out")], | ||||
|     angle: 90deg, | ||||
|     anchor: "east", | ||||
|     padding: 3pt | ||||
|   ) | ||||
|   draw.content( | ||||
|     a, | ||||
|     [A], | ||||
|     angle: 90deg, | ||||
|     anchor: "south", | ||||
|     padding: 3pt | ||||
|   ) | ||||
|   draw.content( | ||||
|     b, | ||||
|     [B], | ||||
|     angle: 90deg, | ||||
|     anchor: "south", | ||||
|     padding: 3pt | ||||
|   ) | ||||
|   draw.content( | ||||
|     c, | ||||
|     [ALUControl#sub("[2:0]")], | ||||
|     angle: 90deg, | ||||
|     anchor: "west", | ||||
|     padding: 3pt | ||||
|   ) | ||||
|   draw.content( | ||||
|     d, | ||||
|     [Result], | ||||
|     angle: 90deg, | ||||
|     anchor: "north", | ||||
|     padding: 3pt | ||||
|   ) | ||||
|   draw.content( | ||||
|     ("wAdd.zig", 0.2, "wAdd.zag"), | ||||
|     text("[N-1]", size: 0.8em), | ||||
|     angle: 90deg, | ||||
|     anchor: "north-east", | ||||
|     padding: 3pt | ||||
|   ) | ||||
| }) | ||||
							
								
								
									
										
											BIN
										
									
								
								manual.pdf
									
									
									
									
									
								
							
							
						
						| @@ -24,6 +24,11 @@ | ||||
|     draw.anchor("south", (p2, 50%, p3)) | ||||
|     draw.anchor("west", (p0, 50%, p3)) | ||||
|     draw.anchor("east", (p1, 50%, p2)) | ||||
|     draw.anchor("north-west", p0) | ||||
|     draw.anchor("north-east", p1) | ||||
|     draw.anchor("south-east", p2) | ||||
|     draw.anchor("south-west", p3) | ||||
|     draw.anchor("name", (p5, 50%, (p1, 50%, p2))) | ||||
|   }) | ||||
|  | ||||
|   let f2 = add-port(id, "west", (id: "in1"), (p0, 50%, p6)) | ||||
| @@ -81,6 +86,7 @@ | ||||
|     ports-y: ( | ||||
|       in1: (h) => {h * 0.225}, | ||||
|       in2: (h) => {h * 0.775}, | ||||
|       out: (h) => {h * 0.5} | ||||
|     ), | ||||
|     debug: debug | ||||
|   ) | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| #import "@preview/cetz:0.2.2": draw, coordinate | ||||
| #import "ports.typ": add-ports, add-port | ||||
| #import "../util.typ" | ||||
|  | ||||
| #let find-port(ports, id) = { | ||||
|   for (side, side-ports) in ports { | ||||
| @@ -51,13 +52,13 @@ | ||||
|   h: none, | ||||
|   name: none, | ||||
|   name-anchor: "center", | ||||
|   ports: (), | ||||
|   ports-margins: (), | ||||
|   ports: (:), | ||||
|   ports-margins: (:), | ||||
|   fill: none, | ||||
|   stroke: black + 1pt, | ||||
|   id: "", | ||||
|   auto-ports: true, | ||||
|   ports-y: (), | ||||
|   ports-y: (:), | ||||
|   debug: ( | ||||
|     ports: false | ||||
|   ) | ||||
| @@ -115,7 +116,7 @@ | ||||
|   if (name != none) { | ||||
|     draw.content( | ||||
|       (name: id, anchor: name-anchor), | ||||
|       anchor: name-anchor, | ||||
|       anchor: if name-anchor in util.valid-anchors {name-anchor} else {"center"}, | ||||
|       padding: 0.5em, | ||||
|       align(center)[*#name*] | ||||
|     ) | ||||
|   | ||||
| @@ -1,14 +1,23 @@ | ||||
| #import "@preview/cetz:0.2.2": draw | ||||
| #import "element.typ" | ||||
| #import "ports.typ": add-port | ||||
|  | ||||
| #let draw-shape(id, tl, tr, br, bl, fill, stroke) = { | ||||
| #let draw-shape(id, tl, tr, br, bl, fill, stroke, h-ratio: 75%, align-out: true) = { | ||||
|   let (x, y) = bl | ||||
|   let (width, height) = (tr.at(0) - x, tr.at(1) - y) | ||||
|  | ||||
|   tl = (x, y + height * 0.75) | ||||
|   let tr2 = (x + width, y + height * 0.75) | ||||
|   let ratio = h-ratio / 100% | ||||
|  | ||||
|   tl = (x, y + height * ratio) | ||||
|   let tr2 = (x + width, y + height * ratio) | ||||
|   let br = (x + width, y) | ||||
|   (tr, tr2) = (tr2, tr) | ||||
|    | ||||
|   if align-out { | ||||
|     (tr, tr2) = (tr2, tr) | ||||
|   } else { | ||||
|     (tr, tr2) = (tr, tr) | ||||
|   } | ||||
|  | ||||
|   let f = draw.group(name: id, { | ||||
|     draw.merge-path( | ||||
|       inset: 0.5em, | ||||
| @@ -21,6 +30,10 @@ | ||||
|     draw.anchor("south", (bl, 50%, br)) | ||||
|     draw.anchor("west", (tl, 50%, bl)) | ||||
|     draw.anchor("east", (tr2, 50%, br)) | ||||
|     draw.anchor("north-west", tl) | ||||
|     draw.anchor("north-east", tr2) | ||||
|     draw.anchor("south-east", br) | ||||
|     draw.anchor("south-west", bl) | ||||
|   }) | ||||
|   return (f, tl, tr, br, bl) | ||||
| } | ||||
| @@ -28,7 +41,9 @@ | ||||
| /// Draws a bit extender | ||||
| /// | ||||
| /// #examples.extender | ||||
| /// For parameters description, see #doc-ref("element.elmt") | ||||
| /// For other parameters description, see #doc-ref("element.elmt") | ||||
| /// - h-ratio (ratio): The height ratio of the left side relative to the full height | ||||
| /// - align-out (bool): If true, the output and input ports are aligned, otherwise, the output port is centered on the right side | ||||
| #let extender( | ||||
|   x: none, | ||||
|   y: none, | ||||
| @@ -39,6 +54,8 @@ | ||||
|   fill: none, | ||||
|   stroke: black + 1pt, | ||||
|   id: "", | ||||
|   h-ratio: 75%, | ||||
|   align-out: true, | ||||
|   debug: ( | ||||
|     ports: false | ||||
|   ) | ||||
| @@ -51,9 +68,14 @@ | ||||
|       (id: "out"), | ||||
|     ) | ||||
|   ) | ||||
|   let out-pct = if align-out {h-ratio / 2} else {50%} | ||||
|   let ports-y = ( | ||||
|     "in": (h) => {h - h * (h-ratio / 200%)}, | ||||
|     "out": (h) => {h - h * (out-pct / 100%)} | ||||
|   ) | ||||
|    | ||||
|   element.elmt( | ||||
|     draw-shape: draw-shape, | ||||
|     draw-shape: draw-shape.with(h-ratio: h-ratio, align-out: align-out), | ||||
|     x: x, | ||||
|     y: y, | ||||
|     w: w, | ||||
| @@ -61,9 +83,16 @@ | ||||
|     name: name, | ||||
|     name-anchor: name-anchor, | ||||
|     ports: ports, | ||||
|     auto-ports: false, | ||||
|     ports-y: ports-y, | ||||
|     fill: fill, | ||||
|     stroke: stroke, | ||||
|     id: id, | ||||
|     debug: debug | ||||
|   ) | ||||
|  | ||||
|   let in-pos = (rel: (0, h * (h-ratio / 200%)), to: id+".south-west") | ||||
|   let out-pos = (id+".south-east", out-pct, id+".north-east") | ||||
|   add-port(id, "west", ports.west.first(), in-pos) | ||||
|   add-port(id, "east", ports.east.first(), out-pos) | ||||
| } | ||||
| @@ -5,8 +5,8 @@ | ||||
|   let (x, y) = bl | ||||
|   let (width, height) = (tr.at(0) - x, tr.at(1) - y) | ||||
|  | ||||
|   let t = (x + width / 4, y + height) | ||||
|   let b = (x + width / 4, y) | ||||
|   let t = (x + width / 2, y + height) | ||||
|   let b = (x + width / 2, y) | ||||
|  | ||||
|   let f = draw.group(name: id, { | ||||
|     draw.merge-path( | ||||
| @@ -16,7 +16,7 @@ | ||||
|       name: id + "-path", | ||||
|       close: true, { | ||||
|         draw.line(bl, tl, t) | ||||
|         draw.bezier((), b, tr, br) | ||||
|         draw.arc-through((), (tr , 50%, br), b) | ||||
|         draw.line((), b) | ||||
|       } | ||||
|     ) | ||||
|   | ||||
| @@ -33,7 +33,7 @@ | ||||
|   y: none, | ||||
|   w: none, | ||||
|   h: none, | ||||
|   inputs: 2, | ||||
|   inputs: 1, | ||||
|   fill: none, | ||||
|   stroke: black + 1pt, | ||||
|   id: "", | ||||
| @@ -65,7 +65,7 @@ | ||||
|   y: none, | ||||
|   w: none, | ||||
|   h: none, | ||||
|   inputs: 2, | ||||
|   inputs: 1, | ||||
|   fill: none, | ||||
|   stroke: black + 1pt, | ||||
|   id: "", | ||||
|   | ||||
| @@ -33,7 +33,7 @@ | ||||
|   stroke: black + 1pt, | ||||
|   id: "", | ||||
|   inverted: (), | ||||
|   inverted-radius: 0.2, | ||||
|   inverted-radius: 0.1, | ||||
|   debug: ( | ||||
|     ports: false | ||||
|   ) | ||||
| @@ -58,19 +58,16 @@ | ||||
|   if (type(y) == dictionary) { | ||||
|     let from = y.from | ||||
|     let to = y.to | ||||
|     let (to-side, i) = find-port(ports, to) | ||||
|     let margins = (0%, 0%) | ||||
|     if to-side in ports-margins { | ||||
|       margins = ports-margins.at(to-side) | ||||
|     } | ||||
|     let used-pct = 100% - margins.at(0) - margins.at(1) | ||||
|     let used-height = height * used-pct / 100% | ||||
|     let top-margin = height * margins.at(0) / 100% | ||||
|      | ||||
|     let dy = used-height * (i + 1) / (ports.at(to-side).len() + 1) | ||||
|     let dy | ||||
|     if to == "out" { | ||||
|       dy = height / 2 | ||||
|     } else { | ||||
|       dy = height * (i + 0.5) / inputs | ||||
|     } | ||||
|      | ||||
|     let (ctx, from-pos) = coordinate.resolve(ctx, from) | ||||
|     y = from-pos.at(1) + dy - height + top-margin | ||||
|     y = from-pos.at(1) + dy - height | ||||
|   } | ||||
|  | ||||
|   let tl = (x, y + height) | ||||
|   | ||||
| @@ -1,10 +1,12 @@ | ||||
| #import "@preview/cetz:0.2.2": draw | ||||
| #import "../util.typ" | ||||
| #import "element.typ" | ||||
| #import "ports.typ": add-port | ||||
|  | ||||
| #let draw-shape(id, tl, tr, br, bl, fill, stroke) = { | ||||
|   let tr2 = (tr, 20%, br) | ||||
|   let br2 = (tr, 80%, br) | ||||
| #let draw-shape(id, tl, tr, br, bl, fill, stroke, h-ratio: 60%) = { | ||||
|   let margin = (100% - h-ratio) / 2 | ||||
|   let tr2 = (tr, margin, br) | ||||
|   let br2 = (br, margin, tr) | ||||
|   let f = draw.group(name: id, { | ||||
|     draw.merge-path( | ||||
|       inset: 0.5em, | ||||
| @@ -17,7 +19,12 @@ | ||||
|     draw.anchor("south", (bl, 50%, br2)) | ||||
|     draw.anchor("west", (tl, 50%, bl)) | ||||
|     draw.anchor("east", (tr2, 50%, br2)) | ||||
|     draw.anchor("north-west", tl) | ||||
|     draw.anchor("north-east", tr2) | ||||
|     draw.anchor("south-east", br2) | ||||
|     draw.anchor("south-west", bl) | ||||
|   }) | ||||
|  | ||||
|   return (f, tl, tr, br, bl) | ||||
| } | ||||
|  | ||||
| @@ -26,6 +33,7 @@ | ||||
| /// #examples.multiplexer | ||||
| /// For other parameters description, see #doc-ref("element.elmt") | ||||
| /// - entries (int, array): If it is an integer, it defines the number of input ports (automatically named with their binary index). If it is an array of strings, it defines the name of each input. | ||||
| /// - h-ratio (ratio): The height ratio of the right side relative to the full height | ||||
| #let multiplexer( | ||||
|   x: none, | ||||
|   y: none, | ||||
| @@ -34,6 +42,7 @@ | ||||
|   name: none, | ||||
|   name-anchor: "center", | ||||
|   entries: 2, | ||||
|   h-ratio: 60%, | ||||
|   fill: none, | ||||
|   stroke: black + 1pt, | ||||
|   id: "", | ||||
| @@ -42,6 +51,9 @@ | ||||
|   ) | ||||
| ) = { | ||||
|   let ports = () | ||||
|   let ports-y = ( | ||||
|     out: (h) => {h * 0.5} | ||||
|   ) | ||||
|  | ||||
|   if (type(entries) == int) { | ||||
|     let nbits = calc.ceil(calc.log(entries, base: 2)) | ||||
| @@ -54,9 +66,15 @@ | ||||
|       ports.push((id: "in" + str(i), name: port)) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   let space = 100% / ports.len() | ||||
|   let l = ports.len() | ||||
|   for (i, port) in ports.enumerate() { | ||||
|     ports-y.insert(port.id, (h) => {h * (i + 0.5) / l}) | ||||
|   } | ||||
|    | ||||
|   element.elmt( | ||||
|     draw-shape: draw-shape, | ||||
|     draw-shape: draw-shape.with(h-ratio: h-ratio), | ||||
|     x: x, | ||||
|     y: y, | ||||
|     w: w, | ||||
| @@ -67,6 +85,14 @@ | ||||
|     fill: fill, | ||||
|     stroke: stroke, | ||||
|     id: id, | ||||
|     ports-y: ports-y, | ||||
|     auto-ports: false, | ||||
|     debug: debug | ||||
|   ) | ||||
|  | ||||
|   for (i, port) in ports.enumerate() { | ||||
|     let pct = (i + 0.5) * space | ||||
|     add-port(id, "west", port, (id+".north-west", pct, id+".south-west")) | ||||
|   } | ||||
|   add-port(id, "east", (id: "out"), (id+".north-east", 50%, id+".south-east")) | ||||
| } | ||||
| @@ -15,11 +15,12 @@ | ||||
|       panic("Clock port must have previous and next positions") | ||||
|     } | ||||
|      | ||||
|     let size = if port.at("small", default: false) {8pt} else {1em} | ||||
|     let offset | ||||
|     if      (side == "north") { offset = (   0, -1em) } | ||||
|     else if (side == "east")  { offset = (-1em,    0) } | ||||
|     else if (side == "south") { offset = (   0,  1em) } | ||||
|     else if (side == "west")  { offset = ( 1em,    0) } | ||||
|     if      (side == "north") { offset = (    0, -size) } | ||||
|     else if (side == "east")  { offset = (-size,     0) } | ||||
|     else if (side == "south") { offset = (    0,  size) } | ||||
|     else if (side == "west")  { offset = ( size,     0) } | ||||
|  | ||||
|     let pos1 = (rel: offset, to: pos) | ||||
|  | ||||
| @@ -96,6 +97,11 @@ | ||||
|       let pos-prev = (pt0, pct-prev, pt1) | ||||
|       let pos-next = (pt0, pct-next, pt1) | ||||
|  | ||||
|       if port.at("small", default: false) { | ||||
|         pos-prev = (pos, 4pt, pt0) | ||||
|         pos-next = (pos, 4pt, pt1) | ||||
|       } | ||||
|  | ||||
|       add-port( | ||||
|         elmt-id, | ||||
|         side, | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| #let version = version((0,0,2)) | ||||
| #let version = version(0, 1, 0) | ||||
|  | ||||
| #import "circuit.typ": circuit | ||||
| #import "element.typ" | ||||
|   | ||||
| @@ -68,4 +68,9 @@ | ||||
|     south-east: "south-west", | ||||
|     south-west: "north-west" | ||||
|   ).at(anchor) | ||||
| } | ||||
| } | ||||
|  | ||||
| #let valid-anchors = ( | ||||
|   "center", "north", "east", "west", "south", | ||||
|   "north-east", "north-west", "south-east", "south-west" | ||||
| ) | ||||
							
								
								
									
										25
									
								
								src/wire.typ
									
									
									
									
									
								
							
							
						
						| @@ -7,7 +7,12 @@ | ||||
| #let signal-width = 1pt | ||||
| #let bus-width = 1.5pt | ||||
|  | ||||
| #let intersection(pt, radius: .2, fill: black) = { | ||||
| /// Draws a wire intersection at the given anchor | ||||
| /// #examples.intersection | ||||
| /// - pt (point): A CeTZ compatible point / anchor | ||||
| /// - radius (number): The radius of the intersection | ||||
| /// - fill (color): The fill color | ||||
| #let intersection(pt, radius: .1, fill: black) = { | ||||
|   draw.circle(pt, radius: radius, stroke: none, fill: fill) | ||||
| } | ||||
|  | ||||
| @@ -22,7 +27,11 @@ | ||||
| #let get-zigzag-wire(pts, ratio, dir) = { | ||||
|   let start = pts.first() | ||||
|   let end = pts.last() | ||||
|   let mid = (start, ratio, end) | ||||
|   let mid = if dir == "vertical" { | ||||
|     (start, ratio, (horizontal: end, vertical: ())) | ||||
|   } else { | ||||
|     (start, ratio, (horizontal: (), vertical: end)) | ||||
|   } | ||||
|  | ||||
|   let points = if dir == "vertical" { | ||||
|     ( | ||||
| @@ -188,15 +197,18 @@ | ||||
|   let second-pos = points.at(1) | ||||
|   if reverse { | ||||
|     (first-pt, last-pt) = (last-pt, first-pt) | ||||
|     (first-pos, second-pos) = (second-pos, first-pos) | ||||
|   } | ||||
|    | ||||
|   let angle = 0deg | ||||
|   if rotate-name { | ||||
|     (ctx, first-pos) = coordinate.resolve(ctx, first-pos) | ||||
|     (ctx, second-pos) = coordinate.resolve(ctx, second-pos) | ||||
|     let (x1, y1, _) = first-pos | ||||
|     let (x2, y2, _) = second-pos | ||||
|      | ||||
|     if reverse { | ||||
|       (first-pos, second-pos) = (second-pos, first-pos) | ||||
|     } | ||||
|     let (x1, y1, ..) = first-pos | ||||
|     let (x2, y2, ..) = second-pos | ||||
|     angle = calc.atan2(x2 - x1, y2 - y1) | ||||
|   } | ||||
|    | ||||
| @@ -235,8 +247,7 @@ | ||||
|   } | ||||
|  | ||||
|   if slice != none { | ||||
|     let (start, end) = slice | ||||
|     let slice-txt = "[" + str(start) + ":" + str(end) + "]" | ||||
|     let slice-txt = "[" + slice.map(b => str(b)).join(":") + "]" | ||||
|      | ||||
|     draw.content( | ||||
|       first-pt, | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| [package] | ||||
| name = "circuiteria" | ||||
| version = "0.0.2" | ||||
| version = "0.1.0" | ||||
| compiler = "0.11.0" | ||||
| repository = "https://git.kb28.ch/HEL/circuiteria" | ||||
| entrypoint = "src/lib.typ" | ||||
| @@ -11,4 +11,4 @@ categories = [ "visualization" ] | ||||
| license = "Apache-2.0" | ||||
| description = "Drawing block circuits with Typst made easy, using CeTZ" | ||||
| keywords = [ "circuit", "block", "draw" ] | ||||
| exclude = [ "/gallery/*" ] | ||||
| exclude = [ "gallery", "gallery.bash", "doc" ] | ||||