Compare commits
	
		
			43 Commits
		
	
	
		
			047c3b8893
			...
			dev
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| d73215c889 | |||
| 87643983ec | |||
| 94fef0a245 | |||
| 1a0a659ace | |||
| f2ce91ec39 | |||
| 043bb339fe | |||
| 693676d61a | |||
| 94d5d6b854 | |||
| 71f128f6c9 | |||
| ea8277ee5b | |||
| c5e4f8039a | |||
| 8c91ccdd54 | |||
| 9966656e8b | |||
| 3ccb79c6c2 | |||
| 2bb7e3b5a9 | |||
| 371caf094c | |||
| 841f53e76c | |||
| ff0b91e683 | |||
| e1e561bb6c | |||
| 9a1fda087c | |||
| c5a0cf7ecc | |||
| 9a6973fb89 | |||
| d8094384ad | |||
| 86ca91920f | |||
| 64d6635d5f | |||
| 6a6ae96a96 | |||
| a856b7f634 | |||
| 011802ffbe | |||
| 4fae4fe19a | |||
| d6248865b3 | |||
| 2317fec71d | |||
| ff9ad9e94a | |||
| 4dc69a92c5 | |||
| ba7630c03c | |||
| f9916e5856 | |||
| 7731159dd0 | |||
| 699b3c0189 | |||
| 08f931bbde | |||
| 7da2bb2b64 | |||
| e4194d0925 | |||
| 86d9122740 | |||
| 5bd3dd8111 | |||
| 66ac91af7b | 
							
								
								
									
										63
									
								
								README.md
									
									
									
									
									
								
							
							
						
						| @@ -1,3 +1,64 @@ | |||||||
| # circuiteria | # 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.2.0" | ||||||
|  | #circuiteria.circuit({ | ||||||
|  |   import circuiteria: * | ||||||
|  |   ... | ||||||
|  | }) | ||||||
|  | ``` | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| #import "@preview/cetz:0.2.2": draw | #import "@preview/cetz:0.3.2": draw | ||||||
| #import "../src/circuit.typ": circuit | #import "../src/circuit.typ": circuit | ||||||
| #import "../src/util.typ" | #import "../src/util.typ" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -56,7 +56,7 @@ for i in range(3) { | |||||||
| ```) | ```) | ||||||
|  |  | ||||||
| #let wires = example(``` | #let wires = example(``` | ||||||
| for i in range(3) { | for i in range(4) { | ||||||
|   draw.circle((i * 3, 0), radius: .1, name: "p" + str(i * 2)) |   draw.circle((i * 3, 0), radius: .1, name: "p" + str(i * 2)) | ||||||
|   draw.circle((i * 3 + 2, 1), radius: .1, name: "p" + str(i * 2 + 1)) |   draw.circle((i * 3 + 2, 1), radius: .1, name: "p" + str(i * 2 + 1)) | ||||||
|   draw.content((i * 3 + 1, -1), raw(wire.wire-styles.at(i))) |   draw.content((i * 3 + 1, -1), raw(wire.wire-styles.at(i))) | ||||||
| @@ -65,6 +65,10 @@ wire.wire("w1", ("p0", "p1"), style: "direct") | |||||||
| wire.wire("w2", ("p2", "p3"), style: "zigzag") | wire.wire("w2", ("p2", "p3"), style: "zigzag") | ||||||
| wire.wire("w3", ("p4", "p5"), style: "dodge", | wire.wire("w3", ("p4", "p5"), style: "dodge", | ||||||
|           dodge-y: -0.5, dodge-margins: (0.5, 0.5)) |           dodge-y: -0.5, dodge-margins: (0.5, 0.5)) | ||||||
|  | wire.wire("w4", ("p6","p7"), style: "guided", | ||||||
|  |           guided-center:(20%, 40%), guided-margins: (90%,87%), | ||||||
|  |           guided-sides: ("north","south")) | ||||||
|  |  | ||||||
| ```, vertical: true) | ```, vertical: true) | ||||||
|  |  | ||||||
| #let stub = example(``` | #let stub = example(``` | ||||||
| @@ -113,4 +117,78 @@ gates.gate-xor(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all") | |||||||
| #let gate-xnor = example(``` | #let gate-xnor = example(``` | ||||||
| gates.gate-xnor(x: 0, y: 0, w: 1.5, h: 1.5) | gates.gate-xnor(x: 0, y: 0, w: 1.5, h: 1.5) | ||||||
| gates.gate-xnor(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all") | gates.gate-xnor(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all") | ||||||
| ```, vertical: true) | ```, vertical: true) | ||||||
|  |  | ||||||
|  | #let iec-gate-and = example(``` | ||||||
|  | gates.iec-gate-and(x: 0, y: 0, w: 1.5, h: 1.5) | ||||||
|  | gates.iec-gate-and(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all") | ||||||
|  | ```, vertical: true) | ||||||
|  |  | ||||||
|  | #let iec-gate-nand = example(``` | ||||||
|  | gates.iec-gate-nand(x: 0, y: 0, w: 1.5, h: 1.5) | ||||||
|  | gates.iec-gate-nand(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all") | ||||||
|  | ```, vertical: true) | ||||||
|  |  | ||||||
|  | #let iec-gate-or = example(``` | ||||||
|  | gates.iec-gate-or(x: 0, y: 0, w: 1.5, h: 1.5) | ||||||
|  | gates.iec-gate-or(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all") | ||||||
|  | ```, vertical: true) | ||||||
|  |  | ||||||
|  | #let iec-gate-nor = example(``` | ||||||
|  | gates.iec-gate-nor(x: 0, y: 0, w: 1.5, h: 1.5) | ||||||
|  | gates.iec-gate-nor(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all") | ||||||
|  | ```, vertical: true) | ||||||
|  |  | ||||||
|  | #let iec-gate-xor = example(``` | ||||||
|  | gates.iec-gate-xor(x: 0, y: 0, w: 1.5, h: 1.5) | ||||||
|  | gates.iec-gate-xor(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all") | ||||||
|  | ```, vertical: true) | ||||||
|  |  | ||||||
|  | #let iec-gate-xnor = example(``` | ||||||
|  | gates.iec-gate-xnor(x: 0, y: 0, w: 1.5, h: 1.5) | ||||||
|  | gates.iec-gate-xnor(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all") | ||||||
|  | ```, vertical: true) | ||||||
|  |  | ||||||
|  | #let iec-gate-buf = example(``` | ||||||
|  | gates.iec-gate-buf(x: 0, y: 0, w: 1.5, h: 1.5) | ||||||
|  | gates.iec-gate-buf(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all") | ||||||
|  | ```, vertical: true) | ||||||
|  |  | ||||||
|  | #let iec-gate-not = example(``` | ||||||
|  | gates.iec-gate-not(x: 0, y: 0, w: 1.5, h: 1.5) | ||||||
|  | gates.iec-gate-not(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all") | ||||||
|  | ```, vertical: true) | ||||||
|  |  | ||||||
|  | #let group = example(``` | ||||||
|  | element.group( | ||||||
|  |   id: "g1", name: "Group 1", stroke: (dash: "dashed"), | ||||||
|  |   { | ||||||
|  |     element.block(id: "b1", w: 2, h: 2, | ||||||
|  |       x: 0, y: 1.5, | ||||||
|  |       ports: (east: ((id: "out"),)), | ||||||
|  |       fill: util.colors.green | ||||||
|  |     ) | ||||||
|  |     element.block(id: "b2", w: 2, h: 1, | ||||||
|  |       x: 0, y: 0, | ||||||
|  |       ports: (east: ((id: "out"),)), | ||||||
|  |       fill: util.colors.orange | ||||||
|  |     ) | ||||||
|  |   } | ||||||
|  | ) | ||||||
|  | element.block(id: "b3", w: 2, h: 3, | ||||||
|  |   x: (rel: 1, to: "g1.east"), | ||||||
|  |   y: (from: "b1-port-out", to: "in1"), | ||||||
|  |   ports: (west: ((id: "in1"), (id: "in2"))), | ||||||
|  |   fill: util.colors.blue | ||||||
|  | ) | ||||||
|  | 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") | ||||||
|  | ```) | ||||||
|   | |||||||
							
								
								
									
										
											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 | #import "../src/lib.typ": circuit, element, util, wire | ||||||
|  |  | ||||||
| #set page(flipped: true) | #set page(width: auto, height: auto, margin: .5cm) | ||||||
|  |  | ||||||
| #circuit({ | #circuit({ | ||||||
|   element.block( |   element.block( | ||||||
| @@ -105,7 +105,7 @@ | |||||||
|     ) |     ) | ||||||
|   ) |   ) | ||||||
|   wire.stub("RegFile-port-CLK", "north", name: "CLK") |   wire.stub("RegFile-port-CLK", "north", name: "CLK") | ||||||
|   wire.stub("RegFile-port-WE3", "north", name: "Regwrite", vertical: true) |   wire.stub("RegFile-port-WE3", "north", name: "Regwrite", name-offset: 0.6) | ||||||
|   wire.stub("RegFile-port-A2", "west") |   wire.stub("RegFile-port-A2", "west") | ||||||
|   wire.stub("RegFile-port-RD2", "east") |   wire.stub("RegFile-port-RD2", "east") | ||||||
|  |  | ||||||
| @@ -294,6 +294,6 @@ | |||||||
|     bus: true |     bus: true | ||||||
|   ) |   ) | ||||||
|  |  | ||||||
|   wire.intersection("wResMP-RegFile.dodge-end") |   wire.intersection("wResMP-RegFile.dodge-end", radius: .2) | ||||||
|   wire.intersection("wResMP-AdrSrc.dodge-end") |   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 | #import "../src/lib.typ": circuit, element, util, wire | ||||||
|  |  | ||||||
| #set page(flipped: true) | #set page(width: auto, height: auto, margin: .5cm) | ||||||
|  |  | ||||||
| #circuit({ | #circuit({ | ||||||
|   element.block( |   element.block( | ||||||
| @@ -110,7 +110,7 @@ | |||||||
|     ) |     ) | ||||||
|   ) |   ) | ||||||
|   wire.stub("RegFile-port-CLK", "north", name: "CLK") |   wire.stub("RegFile-port-CLK", "north", name: "CLK") | ||||||
|   wire.stub("RegFile-port-WE3", "north", name: "Regwrite", vertical: true) |   wire.stub("RegFile-port-WE3", "north", name: "Regwrite", name-offset: 0.6) | ||||||
|   wire.stub("RegFile-port-A2", "west") |   wire.stub("RegFile-port-A2", "west") | ||||||
|   wire.stub("RegFile-port-RD2", "east") |   wire.stub("RegFile-port-RD2", "east") | ||||||
|  |  | ||||||
| @@ -307,6 +307,6 @@ | |||||||
|     bus: true |     bus: true | ||||||
|   ) |   ) | ||||||
|    |    | ||||||
|   wire.intersection("wResMP-RegFile.dodge-end") |   wire.intersection("wResMP-RegFile.dodge-end", radius: .2) | ||||||
|   wire.intersection("wResMP-AdrSrc.dodge-end") |   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 "@preview/cetz:0.3.2": draw | ||||||
| #import "../src/lib.typ": circuit, element, util, wire | #import "../src/lib.typ": circuit, element, util, wire | ||||||
|  |  | ||||||
| #set page(flipped: true) | #set page(width: auto, height: auto, margin: .5cm) | ||||||
| #let debug = false |  | ||||||
|  |  | ||||||
| #circuit({ | #circuit({ | ||||||
|   element.block( |   element.block( | ||||||
| @@ -14,18 +13,14 @@ | |||||||
|         (id: "out1"), |         (id: "out1"), | ||||||
|         (id: "out2"), |         (id: "out2"), | ||||||
|       ) |       ) | ||||||
|     ), |  | ||||||
|     debug: ( |  | ||||||
|       ports: debug  |  | ||||||
|  |  | ||||||
|     ) |     ) | ||||||
|   ) |   ) | ||||||
|   element.gate-and( |   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") |     inverted: ("in1") | ||||||
|   ) |   ) | ||||||
|   element.gate-or( |   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") |     inverted: ("in0", "out") | ||||||
|   ) |   ) | ||||||
|  |  | ||||||
| @@ -47,7 +42,7 @@ | |||||||
|   ) |   ) | ||||||
|  |  | ||||||
|   element.gate-and( |   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") |     inverted: ("in0", "in2") | ||||||
|   ) |   ) | ||||||
|   for i in range(3) { |   for i in range(3) { | ||||||
| @@ -55,35 +50,35 @@ | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   element.gate-xor( |   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") |     inverted: ("in1") | ||||||
|   ) |   ) | ||||||
|    |    | ||||||
|   element.gate-buf( |   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( |   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( |   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( |   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( |   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( |   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( |   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( |   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.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								gallery/test4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 159 KiB | 
							
								
								
									
										221
									
								
								gallery/test4.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,221 @@ | |||||||
|  | #import "@preview/cetz:0.3.2": draw | ||||||
|  | #import "../src/lib.typ": * | ||||||
|  |  | ||||||
|  | #set page(width: auto, height: auto, margin: .5cm) | ||||||
|  |  | ||||||
|  | #circuit({ | ||||||
|  |   element.group(id: "toplvl", name: "Toplevel", { | ||||||
|  |     element.group( | ||||||
|  |       id: "proc", | ||||||
|  |       name: "Processor", | ||||||
|  |       padding: 1.5em, | ||||||
|  |       stroke: (dash: "dashed"), | ||||||
|  |       { | ||||||
|  |       element.block( | ||||||
|  |         x: 0, y: 0, w: 8, h: 4, | ||||||
|  |         id: "dp", | ||||||
|  |         fill: util.colors.pink, | ||||||
|  |         name: "Datapath", | ||||||
|  |         ports: ( | ||||||
|  |           north: ( | ||||||
|  |             (id: "clk", clock: true, small: true), | ||||||
|  |             (id: "Zero"), | ||||||
|  |             (id: "Regsrc"), | ||||||
|  |             (id: "PCSrc"), | ||||||
|  |             (id: "ResultSrc"), | ||||||
|  |             (id: "ALUControl"), | ||||||
|  |             (id: "ImmSrc"), | ||||||
|  |             (id: "RegWrite"), | ||||||
|  |             (id: "dummy") | ||||||
|  |           ), | ||||||
|  |           east: ( | ||||||
|  |             (id: "PC", name: "PC"), | ||||||
|  |             (id: "Instr", name: "Instr"), | ||||||
|  |             (id: "ALUResult", name: "ALUResult"), | ||||||
|  |             (id: "dummy"), | ||||||
|  |             (id: "WriteData", name: "WriteData"), | ||||||
|  |             (id: "ReadData", name: "ReadData"), | ||||||
|  |           ), | ||||||
|  |           west: ( | ||||||
|  |             (id: "rst"), | ||||||
|  |           ) | ||||||
|  |         ), | ||||||
|  |         ports-margins: ( | ||||||
|  |           north: (0%, 0%), | ||||||
|  |           west: (0%, 70%) | ||||||
|  |         ) | ||||||
|  |       ) | ||||||
|  |        | ||||||
|  |       element.block( | ||||||
|  |         x: 0, y: 7, w: 8, h: 3, | ||||||
|  |         id: "ctrl", | ||||||
|  |         fill: util.colors.orange, | ||||||
|  |         name: "Controller", | ||||||
|  |         ports: ( | ||||||
|  |           east: ( | ||||||
|  |             (id: "Instr", name: "Instr"), | ||||||
|  |           ), | ||||||
|  |           south: ( | ||||||
|  |             (id: "dummy"), | ||||||
|  |             (id: "Zero"), | ||||||
|  |             (id: "Regsrc"), | ||||||
|  |             (id: "PCSrc"), | ||||||
|  |             (id: "ResultSrc"), | ||||||
|  |             (id: "ALUControl"), | ||||||
|  |             (id: "ImmSrc"), | ||||||
|  |             (id: "RegWrite"), | ||||||
|  |             (id: "MemWrite") | ||||||
|  |           ) | ||||||
|  |         ), | ||||||
|  |         ports-margins: ( | ||||||
|  |           south: (0%, 0%) | ||||||
|  |         ) | ||||||
|  |       ) | ||||||
|  |       wire.wire( | ||||||
|  |         "w-Zero", | ||||||
|  |         ("dp-port-Zero", "ctrl-port-Zero"), | ||||||
|  |         name: "Zero", | ||||||
|  |         name-pos: "start", | ||||||
|  |         directed: true | ||||||
|  |       ) | ||||||
|  |       for p in ("Regsrc", "PCSrc", "ResultSrc", "ALUControl", "ImmSrc", "RegWrite") { | ||||||
|  |         wire.wire( | ||||||
|  |           "w-" + p, | ||||||
|  |           ("ctrl-port-"+p, "dp-port-"+p), | ||||||
|  |           name: p, | ||||||
|  |           name-pos: "start", | ||||||
|  |           directed: true | ||||||
|  |         ) | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       draw.content( | ||||||
|  |         (rel: (0, 1em), to: "ctrl.north"), | ||||||
|  |         [*RISCV single*], | ||||||
|  |         anchor: "south" | ||||||
|  |       ) | ||||||
|  |     }) | ||||||
|  |      | ||||||
|  |     element.block( | ||||||
|  |       x: (rel: 3.5, to: "dp.east"), | ||||||
|  |       y: (from: "dp-port-ReadData", to: "RD"), | ||||||
|  |       w: 3, h: 4, | ||||||
|  |       id: "dmem", | ||||||
|  |       fill: util.colors.green, | ||||||
|  |       name: "Data\n Memory", | ||||||
|  |       ports: ( | ||||||
|  |         north: ( | ||||||
|  |           (id: "clk", clock: true, small: true), | ||||||
|  |           (id: "WE", name: "WE") | ||||||
|  |         ), | ||||||
|  |         west: ( | ||||||
|  |           (id: "dummy"), | ||||||
|  |           (id: "dummy"), | ||||||
|  |           (id: "A", name: "A"), | ||||||
|  |           (id: "dummy"), | ||||||
|  |           (id: "WD", name: "WD"), | ||||||
|  |           (id: "RD", name: "RD"), | ||||||
|  |         ) | ||||||
|  |       ), | ||||||
|  |       ports-margins: ( | ||||||
|  |         north: (0%, 10%) | ||||||
|  |       ) | ||||||
|  |     ) | ||||||
|  |     wire.wire( | ||||||
|  |       "w-DataAddr", | ||||||
|  |       ("dp-port-ALUResult", "dmem-port-A"), | ||||||
|  |       name: "DataAddr", | ||||||
|  |       name-pos: "end", | ||||||
|  |       directed: true | ||||||
|  |     ) | ||||||
|  |     wire.wire( | ||||||
|  |       "w-WriteData", | ||||||
|  |       ("dp-port-WriteData", "dmem-port-WD"), | ||||||
|  |       name: "WriteData", | ||||||
|  |       name-pos: "end", | ||||||
|  |       directed: true | ||||||
|  |     ) | ||||||
|  |     wire.wire( | ||||||
|  |       "w-ReadData", | ||||||
|  |       ("dmem-port-RD", "dp-port-ReadData"), | ||||||
|  |       name: "ReadData", | ||||||
|  |       name-pos: "end", | ||||||
|  |       reverse: true, | ||||||
|  |       directed: true | ||||||
|  |     ) | ||||||
|  |     wire.wire( | ||||||
|  |       "w-MemWrite", | ||||||
|  |       ("ctrl-port-MemWrite", "dmem-port-WE"), | ||||||
|  |       style: "zigzag", | ||||||
|  |       name: "MemWrite", | ||||||
|  |       name-pos: "start", | ||||||
|  |       zigzag-dir: "horizontal", | ||||||
|  |       zigzag-ratio: 80%, | ||||||
|  |       directed: true | ||||||
|  |     ) | ||||||
|  |     wire.stub( | ||||||
|  |       "dmem-port-clk", "north", | ||||||
|  |       name: "clk", length: 3pt | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     element.block( | ||||||
|  |       x: (rel: 3.5, to: "dp.east"), | ||||||
|  |       y: (from: "ctrl-port-Instr", to: "dummy"), | ||||||
|  |       w: 3, h: 4, | ||||||
|  |       id: "imem", | ||||||
|  |       fill: util.colors.green, | ||||||
|  |       name: "Instruction\n Memory", | ||||||
|  |       ports: ( | ||||||
|  |         west: ( | ||||||
|  |           (id: "A", name: "A"), | ||||||
|  |           (id: "dummy"), | ||||||
|  |           (id: "dummy2"), | ||||||
|  |           (id: "RD", name: "RD"), | ||||||
|  |         ) | ||||||
|  |       ) | ||||||
|  |     ) | ||||||
|  |     wire.wire( | ||||||
|  |       "w-PC", | ||||||
|  |       ("dp-port-PC", "imem-port-A"), | ||||||
|  |       style: "zigzag", | ||||||
|  |       directed: true | ||||||
|  |     ) | ||||||
|  |     wire.wire( | ||||||
|  |       "w-Instr1", | ||||||
|  |       ("imem-port-RD", "dp-port-Instr"), | ||||||
|  |       style: "zigzag", | ||||||
|  |       zigzag-ratio: 30%, | ||||||
|  |       directed: true | ||||||
|  |     ) | ||||||
|  |     wire.wire( | ||||||
|  |       "w-Instr2", | ||||||
|  |       ("imem-port-RD", "ctrl-port-Instr"), | ||||||
|  |       style: "zigzag", | ||||||
|  |       zigzag-ratio: 30%, | ||||||
|  |       directed: true | ||||||
|  |     ) | ||||||
|  |     wire.intersection("w-Instr1.zig", radius: 2pt) | ||||||
|  |     draw.content("w-Instr1.zig", "Instr", anchor: "south", padding: 4pt) | ||||||
|  |     draw.content("w-PC.zig", "PC", anchor: "south-east", padding: 2pt) | ||||||
|  |  | ||||||
|  |     draw.content("dmem.south-west", [*External Memories*], anchor: "north", padding: 10pt) | ||||||
|  |   }) | ||||||
|  |  | ||||||
|  |   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) | ||||||
|  |    | ||||||
|  |   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: 275 KiB | 
							
								
								
									
										435
									
								
								gallery/test5.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,435 @@ | |||||||
|  | #import "@preview/cetz:0.3.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.3.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
										
									
								
								gallery/test7.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								gallery/test7.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 34 KiB | 
							
								
								
									
										98
									
								
								gallery/test7.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,98 @@ | |||||||
|  | #import "@preview/cetz:0.3.2": draw | ||||||
|  | #import "../src/lib.typ": circuit, element, util, wire | ||||||
|  |  | ||||||
|  | #set page(width: auto, height: auto, margin: .5cm) | ||||||
|  |  | ||||||
|  | #circuit({ | ||||||
|  |   element.iec-gate-buf( | ||||||
|  |     x: 0, | ||||||
|  |     y: 0, | ||||||
|  |     w: 2, | ||||||
|  |     h: 2, | ||||||
|  |     id: "iec-buf", | ||||||
|  |     inputs: 1, | ||||||
|  |   ) | ||||||
|  |   wire.stub("iec-buf-port-in0", "west") | ||||||
|  |  | ||||||
|  |   element.iec-gate-not( | ||||||
|  |     x: 3, | ||||||
|  |     y: 0, | ||||||
|  |     w: 2, | ||||||
|  |     h: 2, | ||||||
|  |     id: "iec-not", | ||||||
|  |     inputs: 1, | ||||||
|  |   ) | ||||||
|  |   wire.stub("iec-not-port-in0", "west") | ||||||
|  |  | ||||||
|  |   element.iec-gate-and( | ||||||
|  |     id: "iec-and", | ||||||
|  |     x: 0, | ||||||
|  |     y: -3, | ||||||
|  |     w: 2, | ||||||
|  |     h: 2, | ||||||
|  |     inputs: 2, | ||||||
|  |   ) | ||||||
|  |   for i in range(2) { | ||||||
|  |     wire.stub("iec-and-port-in" + str(i), "west") | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   element.iec-gate-nand( | ||||||
|  |     id: "iec-nand", | ||||||
|  |     x: 3, | ||||||
|  |     y: -3, | ||||||
|  |     w: 2, | ||||||
|  |     h: 2, | ||||||
|  |     inputs: 2, | ||||||
|  |   ) | ||||||
|  |   for i in range(2) { | ||||||
|  |     wire.stub("iec-nand-port-in" + str(i), "west") | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   element.iec-gate-or( | ||||||
|  |     id: "iec-or", | ||||||
|  |     x: 0, | ||||||
|  |     y: -6, | ||||||
|  |     w: 2, | ||||||
|  |     h: 2, | ||||||
|  |     inputs: 2, | ||||||
|  |   ) | ||||||
|  |   for i in range(2) { | ||||||
|  |     wire.stub("iec-or-port-in" + str(i), "west") | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   element.iec-gate-nor( | ||||||
|  |     id: "iec-nor", | ||||||
|  |     x: 3, | ||||||
|  |     y: -6, | ||||||
|  |     w: 2, | ||||||
|  |     h: 2, | ||||||
|  |     inputs: 2, | ||||||
|  |   ) | ||||||
|  |   for i in range(2) { | ||||||
|  |     wire.stub("iec-nor-port-in" + str(i), "west") | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   element.iec-gate-xor( | ||||||
|  |     id: "iec-xor", | ||||||
|  |     x: 0, | ||||||
|  |     y: -9, | ||||||
|  |     w: 2, | ||||||
|  |     h: 2, | ||||||
|  |     inputs: 2, | ||||||
|  |   ) | ||||||
|  |   for i in range(2) { | ||||||
|  |     wire.stub("iec-xor-port-in" + str(i), "west") | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   element.iec-gate-xnor( | ||||||
|  |     id: "iec-nxor", | ||||||
|  |     x: 3, | ||||||
|  |     y: -9, | ||||||
|  |     w: 2, | ||||||
|  |     h: 2, | ||||||
|  |     inputs: 2, | ||||||
|  |   ) | ||||||
|  |   for i in range(2) { | ||||||
|  |     wire.stub("iec-nxor-port-in" + str(i), "west") | ||||||
|  |   } | ||||||
|  | }) | ||||||
							
								
								
									
										11
									
								
								justfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,11 @@ | |||||||
|  | # Local Variables: | ||||||
|  | # mode: makefile | ||||||
|  | # End: | ||||||
|  | gallery_dir := "./gallery" | ||||||
|  | set shell := ["bash", "-uc"] | ||||||
|  |  | ||||||
|  | manual: | ||||||
|  |   typst c manual.typ manual.pdf | ||||||
|  |  | ||||||
|  | gallery: | ||||||
|  |   for f in "{{gallery_dir}}"/*.typ; do typst c --root . "$f" "${f%typ}png"; done | ||||||
							
								
								
									
										
											BIN
										
									
								
								manual.pdf
									
									
									
									
									
								
							
							
						
						
							
								
								
									
										51
									
								
								manual.typ
									
									
									
									
									
								
							
							
						
						| @@ -1,5 +1,5 @@ | |||||||
| #import "@preview/tidy:0.3.0" | #import "@preview/tidy:0.4.1" | ||||||
| #import "@preview/cetz:0.2.2": draw, canvas | #import "@preview/cetz:0.3.2": draw, canvas | ||||||
| #import "src/lib.typ" | #import "src/lib.typ" | ||||||
| #import "doc/examples.typ" | #import "doc/examples.typ" | ||||||
| #import "src/circuit.typ": circuit | #import "src/circuit.typ": circuit | ||||||
| @@ -12,7 +12,7 @@ | |||||||
|   numbering("1.1", ..num) |   numbering("1.1", ..num) | ||||||
| }) | }) | ||||||
| #{ | #{ | ||||||
|   outline(indent: true, depth: 3) |   outline(indent: auto, depth: 3) | ||||||
| } | } | ||||||
|  |  | ||||||
| #show link: set text(blue) | #show link: set text(blue) | ||||||
| @@ -47,7 +47,7 @@ | |||||||
|  |  | ||||||
| #set page(numbering: "1/1", header: align(right)[circuiteria #sym.dash.em v#lib.version]) | #set page(numbering: "1/1", header: align(right)[circuiteria #sym.dash.em v#lib.version]) | ||||||
| #set page( | #set page( | ||||||
|   header: locate(loc => { |   header: context { | ||||||
|     let txt = [circuiteria #sym.dash.em v#lib.version] |     let txt = [circuiteria #sym.dash.em v#lib.version] | ||||||
|     let cnt = counter(heading) |     let cnt = counter(heading) | ||||||
|     let cnt-val = cnt.get() |     let cnt-val = cnt.get() | ||||||
| @@ -65,8 +65,8 @@ | |||||||
|         #rect(width: 100%, height: .5em, radius: .25em, stroke: none, fill: util.colors.values().at(i)) |         #rect(width: 100%, height: .5em, radius: .25em, stroke: none, fill: util.colors.values().at(i)) | ||||||
|       ] |       ] | ||||||
|     ) |     ) | ||||||
|   }), |   }, | ||||||
|   footer: locate(loc => { |   footer: context { | ||||||
|     let cnt = counter(heading) |     let cnt = counter(heading) | ||||||
|     let cnt-val = cnt.get() |     let cnt-val = cnt.get() | ||||||
|     if cnt-val.len() < 2 { return } |     if cnt-val.len() < 2 { return } | ||||||
| @@ -80,12 +80,12 @@ | |||||||
|       ], |       ], | ||||||
|       counter(page).display("1/1", both: true) |       counter(page).display("1/1", both: true) | ||||||
|     ) |     ) | ||||||
|   }) |   } | ||||||
| ) | ) | ||||||
|  |  | ||||||
| #let doc-ref(target, full: false, var: false) = { | #let doc-ref(target, full: false, var: false) = { | ||||||
|   let (module, func) = target.split(".") |   let (module, func) = target.split(".") | ||||||
|   let label-name = module + func |   let label-name = module + "-" + func | ||||||
|   let display-name = func |   let display-name = func | ||||||
|   if full { |   if full { | ||||||
|     display-name = target |     display-name = target | ||||||
| @@ -94,7 +94,7 @@ | |||||||
|     label-name += "()" |     label-name += "()" | ||||||
|     display-name += "()" |     display-name += "()" | ||||||
|   } |   } | ||||||
|   link(label(label-name))[#display-name] |   link(label(label-name), raw(display-name)) | ||||||
| } | } | ||||||
|  |  | ||||||
| = Introduction | = Introduction | ||||||
| @@ -103,11 +103,21 @@ This package provides a way to make beautiful block circuit diagrams using the C | |||||||
|  |  | ||||||
| = Usage | = Usage | ||||||
|  |  | ||||||
| Simply import #link("src/lib.typ") and call the `circuit` function: | Simply import Circuiteria and call the `circuit` function: | ||||||
| #pad(left: 1em)[```typ | #pad(left: 1em)[```typ | ||||||
| #import "src/lib.typ" | #import "@preview/circuiteria:0.2.0" | ||||||
| #lib.circuit({ | #circuiteria.circuit({ | ||||||
|   import lib: * |   import circuiteria: * | ||||||
|  |   ... | ||||||
|  | }) | ||||||
|  | ```] | ||||||
|  |  | ||||||
|  | == Project installation | ||||||
|  | If you have installed Circuiteria directly in your project, import #link("src/lib.typ") and call the `circuit` function: | ||||||
|  | #pad(left: 1em)[```typ | ||||||
|  | #import "src/lib.typ" as circuiteria | ||||||
|  | #circuiteria.circuit({ | ||||||
|  |   import circuiteria: * | ||||||
|   ... |   ... | ||||||
| }) | }) | ||||||
| ```] | ```] | ||||||
| @@ -117,6 +127,7 @@ Simply import #link("src/lib.typ") and call the `circuit` function: | |||||||
| #let circuit-docs = tidy.parse-module( | #let circuit-docs = tidy.parse-module( | ||||||
|   read("src/circuit.typ"), |   read("src/circuit.typ"), | ||||||
|   name: "circuit", |   name: "circuit", | ||||||
|  |   old-syntax: true, | ||||||
|   require-all-parameters: true |   require-all-parameters: true | ||||||
| ) | ) | ||||||
| #tidy.show-module(circuit-docs) | #tidy.show-module(circuit-docs) | ||||||
| @@ -126,6 +137,7 @@ Simply import #link("src/lib.typ") and call the `circuit` function: | |||||||
| #let util-docs = tidy.parse-module( | #let util-docs = tidy.parse-module( | ||||||
|   read("src/util.typ"), |   read("src/util.typ"), | ||||||
|   name: "util", |   name: "util", | ||||||
|  |   old-syntax: true, | ||||||
|   require-all-parameters: true, |   require-all-parameters: true, | ||||||
|   scope: ( |   scope: ( | ||||||
|     util: util, |     util: util, | ||||||
| @@ -140,6 +152,7 @@ Simply import #link("src/lib.typ") and call the `circuit` function: | |||||||
| #let wire-docs = tidy.parse-module( | #let wire-docs = tidy.parse-module( | ||||||
|   read("src/wire.typ"), |   read("src/wire.typ"), | ||||||
|   name: "wire", |   name: "wire", | ||||||
|  |   old-syntax: true, | ||||||
|   require-all-parameters: true, |   require-all-parameters: true, | ||||||
|   scope: ( |   scope: ( | ||||||
|     wire: wire, |     wire: wire, | ||||||
| @@ -158,8 +171,10 @@ Simply import #link("src/lib.typ") and call the `circuit` function: | |||||||
|   read("src/elements/alu.typ") + "\n" + |   read("src/elements/alu.typ") + "\n" + | ||||||
|   read("src/elements/block.typ") + "\n" + |   read("src/elements/block.typ") + "\n" + | ||||||
|   read("src/elements/extender.typ") + "\n" + |   read("src/elements/extender.typ") + "\n" + | ||||||
|   read("src/elements/multiplexer.typ"), |   read("src/elements/multiplexer.typ") + "\n" + | ||||||
|  |   read("src/elements/group.typ"), | ||||||
|   name: "element", |   name: "element", | ||||||
|  |   old-syntax: true, | ||||||
|   scope: ( |   scope: ( | ||||||
|     element: element, |     element: element, | ||||||
|     circuit: circuit, |     circuit: circuit, | ||||||
| @@ -180,8 +195,14 @@ Simply import #link("src/lib.typ") and call the `circuit` function: | |||||||
|   read("src/elements/logic/and.typ") + "\n" + |   read("src/elements/logic/and.typ") + "\n" + | ||||||
|   read("src/elements/logic/buf.typ") + "\n" + |   read("src/elements/logic/buf.typ") + "\n" + | ||||||
|   read("src/elements/logic/or.typ") + "\n" + |   read("src/elements/logic/or.typ") + "\n" + | ||||||
|   read("src/elements/logic/xor.typ"), |   read("src/elements/logic/xor.typ") + "\n" + | ||||||
|  |   read("src/elements/logic/iec_gate.typ") + "\n" + | ||||||
|  |   read("src/elements/logic/iec_and.typ") + "\n" + | ||||||
|  |   read("src/elements/logic/iec_buf.typ") + "\n" + | ||||||
|  |   read("src/elements/logic/iec_or.typ") + "\n" + | ||||||
|  |   read("src/elements/logic/iec_xor.typ"), | ||||||
|   name: "gates", |   name: "gates", | ||||||
|  |   old-syntax: true, | ||||||
|   scope: ( |   scope: ( | ||||||
|     element: element, |     element: element, | ||||||
|     circuit: circuit, |     circuit: circuit, | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| #import "@preview/cetz:0.2.2": canvas | #import "@preview/cetz:0.3.2": canvas | ||||||
| #import "@preview/tidy:0.3.0" | #import "@preview/tidy:0.3.0" | ||||||
|  |  | ||||||
| /// Draws a block circuit diagram | /// Draws a block circuit diagram | ||||||
| @@ -9,6 +9,5 @@ | |||||||
| /// - length (length, ratio): Optional base unit | /// - length (length, ratio): Optional base unit | ||||||
| /// -> none | /// -> none | ||||||
| #let circuit(body, length: 2em) = { | #let circuit(body, length: 2em) = { | ||||||
|   set text(font: "Source Sans 3") |  | ||||||
|   canvas(length: length, body) |   canvas(length: length, body) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -10,4 +10,11 @@ | |||||||
| #import "elements/logic/and.typ": gate-and, gate-nand | #import "elements/logic/and.typ": gate-and, gate-nand | ||||||
| #import "elements/logic/or.typ": gate-or, gate-nor | #import "elements/logic/or.typ": gate-or, gate-nor | ||||||
| #import "elements/logic/xor.typ": gate-xor, gate-xnor | #import "elements/logic/xor.typ": gate-xor, gate-xnor | ||||||
| #import "elements/logic/buf.typ": gate-buf, gate-not | #import "elements/logic/buf.typ": gate-buf, gate-not | ||||||
|  | #import "elements/logic/iec_gate.typ": iec-gate | ||||||
|  | #import "elements/logic/iec_and.typ": iec-gate-and, iec-gate-nand | ||||||
|  | #import "elements/logic/iec_buf.typ": iec-gate-buf, iec-gate-not | ||||||
|  | #import "elements/logic/iec_or.typ": iec-gate-or, iec-gate-nor | ||||||
|  | #import "elements/logic/iec_xor.typ": iec-gate-xor, iec-gate-xnor | ||||||
|  |  | ||||||
|  | #import "elements/group.typ": group | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| #import "@preview/cetz:0.2.2": draw | #import "@preview/cetz:0.3.2": draw | ||||||
| #import "element.typ" | #import "element.typ" | ||||||
| #import "ports.typ": add-port | #import "ports.typ": add-port | ||||||
|  |  | ||||||
| @@ -24,6 +24,11 @@ | |||||||
|     draw.anchor("south", (p2, 50%, p3)) |     draw.anchor("south", (p2, 50%, p3)) | ||||||
|     draw.anchor("west", (p0, 50%, p3)) |     draw.anchor("west", (p0, 50%, p3)) | ||||||
|     draw.anchor("east", (p1, 50%, p2)) |     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)) |   let f2 = add-port(id, "west", (id: "in1"), (p0, 50%, p6)) | ||||||
| @@ -81,6 +86,7 @@ | |||||||
|     ports-y: ( |     ports-y: ( | ||||||
|       in1: (h) => {h * 0.225}, |       in1: (h) => {h * 0.225}, | ||||||
|       in2: (h) => {h * 0.775}, |       in2: (h) => {h * 0.775}, | ||||||
|  |       out: (h) => {h * 0.5} | ||||||
|     ), |     ), | ||||||
|     debug: debug |     debug: debug | ||||||
|   ) |   ) | ||||||
|   | |||||||
| @@ -1,9 +1,9 @@ | |||||||
| #import "@preview/cetz:0.2.2": draw | #import "@preview/cetz:0.3.2": draw | ||||||
| #import "element.typ" | #import "element.typ" | ||||||
|  |  | ||||||
| #let draw-shape(id, tl, tr, br, bl, fill, stroke) = { | #let draw-shape(id, tl, tr, br, bl, fill, stroke, radius: 0.5em) = { | ||||||
|   let f = draw.rect( |   let f = draw.rect( | ||||||
|     radius: 0.5em, |     radius: radius, | ||||||
|     inset: 0.5em, |     inset: 0.5em, | ||||||
|     fill: fill, |     fill: fill, | ||||||
|     stroke: stroke, |     stroke: stroke, | ||||||
| @@ -27,13 +27,14 @@ | |||||||
|   ports: (), |   ports: (), | ||||||
|   ports-margins: (), |   ports-margins: (), | ||||||
|   fill: none, |   fill: none, | ||||||
|  |   radius: 0.5em, | ||||||
|   stroke: black + 1pt, |   stroke: black + 1pt, | ||||||
|   id: "", |   id: "", | ||||||
|   debug: ( |   debug: ( | ||||||
|     ports: false |     ports: false | ||||||
|   ) |   ) | ||||||
| ) = element.elmt( | ) = element.elmt( | ||||||
|   draw-shape: draw-shape, |   draw-shape: draw-shape.with(radius: radius), | ||||||
|   x: x, |   x: x, | ||||||
|   y: y, |   y: y, | ||||||
|   w: w, |   w: w, | ||||||
| @@ -46,4 +47,4 @@ | |||||||
|   stroke: stroke, |   stroke: stroke, | ||||||
|   id: id, |   id: id, | ||||||
|   debug: debug |   debug: debug | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| #import "@preview/cetz:0.2.2": draw, coordinate | #import "@preview/cetz:0.3.2": draw, coordinate | ||||||
| #import "ports.typ": add-ports, add-port | #import "ports.typ": add-ports, add-port | ||||||
|  | #import "../util.typ" | ||||||
|  |  | ||||||
| #let find-port(ports, id) = { | #let find-port(ports, id) = { | ||||||
|   for (side, side-ports) in ports { |   for (side, side-ports) in ports { | ||||||
| @@ -33,7 +34,7 @@ | |||||||
| ///   - `name` (`str`): Optional name displayed *in* the block | ///   - `name` (`str`): Optional name displayed *in* the block | ||||||
| ///   - `clock` (`bool`): Whether it is a clock port (triangle symbol) | ///   - `clock` (`bool`): Whether it is a clock port (triangle symbol) | ||||||
| ///   - `vertical` (`bool`): Whether the name should be drawn vertically | ///   - `vertical` (`bool`): Whether the name should be drawn vertically | ||||||
| /// - ports-margins (dictionary): Dictionary of ports margins (used with automatic port placement). They keys are cardinal directions ("north", "east", "south", "west"). The values are tuples of (<start>, <end>) margins (numbers) | /// - ports-margins (dictionary): Dictionary of ports margins (used with automatic port placement). They keys are cardinal directions ("north", "east", "south", "west"). The values are tuples of (`<start>`, `<end>`) margins (numbers) | ||||||
| /// - fill (none, color): Fill color | /// - fill (none, color): Fill color | ||||||
| /// - stroke (stroke): Border stroke | /// - stroke (stroke): Border stroke | ||||||
| /// - id (str): The block id (for future reference) | /// - id (str): The block id (for future reference) | ||||||
| @@ -51,13 +52,13 @@ | |||||||
|   h: none, |   h: none, | ||||||
|   name: none, |   name: none, | ||||||
|   name-anchor: "center", |   name-anchor: "center", | ||||||
|   ports: (), |   ports: (:), | ||||||
|   ports-margins: (), |   ports-margins: (:), | ||||||
|   fill: none, |   fill: none, | ||||||
|   stroke: black + 1pt, |   stroke: black + 1pt, | ||||||
|   id: "", |   id: "", | ||||||
|   auto-ports: true, |   auto-ports: true, | ||||||
|   ports-y: (), |   ports-y: (:), | ||||||
|   debug: ( |   debug: ( | ||||||
|     ports: false |     ports: false | ||||||
|   ) |   ) | ||||||
| @@ -87,15 +88,26 @@ | |||||||
|     if to-side in ports-margins { |     if to-side in ports-margins { | ||||||
|       margins = ports-margins.at(to-side) |       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) |  | ||||||
|  |  | ||||||
|     if not auto-ports { |     let dy | ||||||
|  |     let top-margin | ||||||
|  |     if to-side in ("east", "west") { | ||||||
|  |       let used-pct = 100% - margins.at(0) - margins.at(1) | ||||||
|  |       let used-height = height * used-pct / 100% | ||||||
|  |       top-margin = height * margins.at(0) / 100% | ||||||
|  |        | ||||||
|  |       dy = used-height * (i + 1) / (ports.at(to-side).len() + 1) | ||||||
|  |  | ||||||
|  |       if not auto-ports { | ||||||
|  |         top-margin = 0 | ||||||
|  |         dy = ports-y.at(to)(height) | ||||||
|  |       } | ||||||
|  |     } else if to-side == "north" { | ||||||
|  |       dy = 0 | ||||||
|  |       top-margin = 0 | ||||||
|  |     } else if to-side == "south" { | ||||||
|  |       dy = height | ||||||
|       top-margin = 0 |       top-margin = 0 | ||||||
|       dy = ports-y.at(to)(height) |  | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     let (ctx, from-pos) = coordinate.resolve(ctx, from) |     let (ctx, from-pos) = coordinate.resolve(ctx, from) | ||||||
| @@ -115,7 +127,7 @@ | |||||||
|   if (name != none) { |   if (name != none) { | ||||||
|     draw.content( |     draw.content( | ||||||
|       (name: id, anchor: name-anchor), |       (name: id, anchor: name-anchor), | ||||||
|       anchor: name-anchor, |       anchor: if name-anchor in util.valid-anchors {name-anchor} else {"center"}, | ||||||
|       padding: 0.5em, |       padding: 0.5em, | ||||||
|       align(center)[*#name*] |       align(center)[*#name*] | ||||||
|     ) |     ) | ||||||
|   | |||||||
| @@ -1,14 +1,23 @@ | |||||||
| #import "@preview/cetz:0.2.2": draw | #import "@preview/cetz:0.3.2": draw | ||||||
| #import "element.typ" | #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 (x, y) = bl | ||||||
|   let (width, height) = (tr.at(0) - x, tr.at(1) - y) |   let (width, height) = (tr.at(0) - x, tr.at(1) - y) | ||||||
|  |  | ||||||
|   tl = (x, y + height * 0.75) |   let ratio = h-ratio / 100% | ||||||
|   let tr2 = (x + width, y + height * 0.75) |  | ||||||
|  |   tl = (x, y + height * ratio) | ||||||
|  |   let tr2 = (x + width, y + height * ratio) | ||||||
|   let br = (x + width, y) |   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, { |   let f = draw.group(name: id, { | ||||||
|     draw.merge-path( |     draw.merge-path( | ||||||
|       inset: 0.5em, |       inset: 0.5em, | ||||||
| @@ -21,6 +30,10 @@ | |||||||
|     draw.anchor("south", (bl, 50%, br)) |     draw.anchor("south", (bl, 50%, br)) | ||||||
|     draw.anchor("west", (tl, 50%, bl)) |     draw.anchor("west", (tl, 50%, bl)) | ||||||
|     draw.anchor("east", (tr2, 50%, br)) |     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) |   return (f, tl, tr, br, bl) | ||||||
| } | } | ||||||
| @@ -28,7 +41,9 @@ | |||||||
| /// Draws a bit extender | /// Draws a bit extender | ||||||
| /// | /// | ||||||
| /// #examples.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( | #let extender( | ||||||
|   x: none, |   x: none, | ||||||
|   y: none, |   y: none, | ||||||
| @@ -39,6 +54,8 @@ | |||||||
|   fill: none, |   fill: none, | ||||||
|   stroke: black + 1pt, |   stroke: black + 1pt, | ||||||
|   id: "", |   id: "", | ||||||
|  |   h-ratio: 75%, | ||||||
|  |   align-out: true, | ||||||
|   debug: ( |   debug: ( | ||||||
|     ports: false |     ports: false | ||||||
|   ) |   ) | ||||||
| @@ -51,9 +68,14 @@ | |||||||
|       (id: "out"), |       (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( |   element.elmt( | ||||||
|     draw-shape: draw-shape, |     draw-shape: draw-shape.with(h-ratio: h-ratio, align-out: align-out), | ||||||
|     x: x, |     x: x, | ||||||
|     y: y, |     y: y, | ||||||
|     w: w, |     w: w, | ||||||
| @@ -61,9 +83,16 @@ | |||||||
|     name: name, |     name: name, | ||||||
|     name-anchor: name-anchor, |     name-anchor: name-anchor, | ||||||
|     ports: ports, |     ports: ports, | ||||||
|  |     auto-ports: false, | ||||||
|  |     ports-y: ports-y, | ||||||
|     fill: fill, |     fill: fill, | ||||||
|     stroke: stroke, |     stroke: stroke, | ||||||
|     id: id, |     id: id, | ||||||
|     debug: debug |     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) | ||||||
| } | } | ||||||
							
								
								
									
										80
									
								
								src/elements/group.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,80 @@ | |||||||
|  | #import "@preview/cetz:0.3.2": draw, coordinate | ||||||
|  | #import "../util.typ" | ||||||
|  |  | ||||||
|  | /// Draws a group of elements | ||||||
|  | /// | ||||||
|  | /// #examples.group | ||||||
|  | /// - body (elements, function): Elements to group | ||||||
|  | /// - id (str): see #doc-ref("element.elmt") | ||||||
|  | /// - name (str): The group's name | ||||||
|  | /// - name-anchor (str): The anchor for the name. \ | ||||||
|  | ///     Note: the name will be placed on the *outside* of the group | ||||||
|  | /// - fill (color): see #doc-ref("element.elmt") | ||||||
|  | /// - stroke (stroke): see #doc-ref("element.elmt") | ||||||
|  | /// - padding (float,length,array,dictionary): The inside padding: | ||||||
|  | ///    - float / length: same for all sides | ||||||
|  | ///    - array: either (`<all>`,), (`<vertical>`, `<horizontal>`) or (`<top>`, `<right>`, `<bottom>`, `<left>`) | ||||||
|  | ///    - dictionary: valid keys are "top", "right", "bottom" and "left" | ||||||
|  | /// - radius (number): The corner radius | ||||||
|  | #let group( | ||||||
|  |   body, | ||||||
|  |   id: "", | ||||||
|  |   name: none, | ||||||
|  |   name-anchor: "south", | ||||||
|  |   fill: none, | ||||||
|  |   stroke: black + 1pt, | ||||||
|  |   padding: 0.5em, | ||||||
|  |   radius: 0.5em | ||||||
|  | ) = { | ||||||
|  |   let min-x = none | ||||||
|  |   let max-x = none | ||||||
|  |   let min-y = none | ||||||
|  |   let max-y = none | ||||||
|  |  | ||||||
|  |   let pad-top = padding | ||||||
|  |   let pad-bottom = padding | ||||||
|  |   let pad-left = padding | ||||||
|  |   let pad-right = padding | ||||||
|  |  | ||||||
|  |   if type(padding) == array { | ||||||
|  |     if padding.len() == 0 { | ||||||
|  |       panic("Padding array must contain at least one value") | ||||||
|  |     } else if padding.len() == 1 { | ||||||
|  |       pad-top = padding.first() | ||||||
|  |       pad-bottom = padding.first() | ||||||
|  |       pad-left = padding.first() | ||||||
|  |       pad-right = padding.first() | ||||||
|  |     } else if padding.len() == 2 { | ||||||
|  |       pad-top = padding.first() | ||||||
|  |       pad-bottom = padding.first() | ||||||
|  |       pad-left = padding.last() | ||||||
|  |       pad-right = padding.last() | ||||||
|  |     } else if padding.len() == 4 { | ||||||
|  |       (pad-top, pad-right, pad-bottom, pad-left) = padding | ||||||
|  |     } | ||||||
|  |   } else if type(padding) == dictionary { | ||||||
|  |     pad-top = padding.at("top", default: 0.5em) | ||||||
|  |     pad-right = padding.at("right", default: 0.5em) | ||||||
|  |     pad-bottom = padding.at("bottom", default: 0.5em) | ||||||
|  |     pad-left = padding.at("left", default: 0.5em) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   draw.hide(draw.group(name: id+"-inner", body)) | ||||||
|  |   draw.rect( | ||||||
|  |     (rel: (-pad-left, -pad-bottom), to: id+"-inner.south-west"), | ||||||
|  |     (rel: (pad-right, pad-top), to: id+"-inner.north-east"), | ||||||
|  |     name: id, | ||||||
|  |     radius: radius, | ||||||
|  |     stroke: stroke, | ||||||
|  |     fill: fill | ||||||
|  |   ) | ||||||
|  |   if name != none { | ||||||
|  |     draw.content( | ||||||
|  |       id + "." + name-anchor, | ||||||
|  |       anchor: util.opposite-anchor(name-anchor), | ||||||
|  |       padding: 5pt, | ||||||
|  |       [*#name*] | ||||||
|  |     ) | ||||||
|  |   } | ||||||
|  |   body | ||||||
|  | } | ||||||
| @@ -1,12 +1,12 @@ | |||||||
| #import "@preview/cetz:0.2.2": draw | #import "@preview/cetz:0.3.2": draw | ||||||
| #import "gate.typ" | #import "gate.typ" | ||||||
|  |  | ||||||
| #let draw-shape(id, tl, tr, br, bl, fill, stroke) = { | #let draw-shape(id, tl, tr, br, bl, fill, stroke) = { | ||||||
|   let (x, y) = bl |   let (x, y) = bl | ||||||
|   let (width, height) = (tr.at(0) - x, tr.at(1) - y) |   let (width, height) = (tr.at(0) - x, tr.at(1) - y) | ||||||
|  |  | ||||||
|   let t = (x + width / 4, y + height) |   let t = (x + width / 2, y + height) | ||||||
|   let b = (x + width / 4, y) |   let b = (x + width / 2, y) | ||||||
|  |  | ||||||
|   let f = draw.group(name: id, { |   let f = draw.group(name: id, { | ||||||
|     draw.merge-path( |     draw.merge-path( | ||||||
| @@ -16,7 +16,7 @@ | |||||||
|       name: id + "-path", |       name: id + "-path", | ||||||
|       close: true, { |       close: true, { | ||||||
|         draw.line(bl, tl, t) |         draw.line(bl, tl, t) | ||||||
|         draw.bezier((), b, tr, br) |         draw.arc-through((), (tr , 50%, br), b) | ||||||
|         draw.line((), b) |         draw.line((), b) | ||||||
|       } |       } | ||||||
|     ) |     ) | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| #import "@preview/cetz:0.2.2": draw | #import "@preview/cetz:0.3.2": draw | ||||||
| #import "gate.typ" | #import "gate.typ" | ||||||
|  |  | ||||||
| #let draw-shape(id, tl, tr, br, bl, fill, stroke) = { | #let draw-shape(id, tl, tr, br, bl, fill, stroke) = { | ||||||
| @@ -33,7 +33,7 @@ | |||||||
|   y: none, |   y: none, | ||||||
|   w: none, |   w: none, | ||||||
|   h: none, |   h: none, | ||||||
|   inputs: 2, |   inputs: 1, | ||||||
|   fill: none, |   fill: none, | ||||||
|   stroke: black + 1pt, |   stroke: black + 1pt, | ||||||
|   id: "", |   id: "", | ||||||
| @@ -65,7 +65,7 @@ | |||||||
|   y: none, |   y: none, | ||||||
|   w: none, |   w: none, | ||||||
|   h: none, |   h: none, | ||||||
|   inputs: 2, |   inputs: 1, | ||||||
|   fill: none, |   fill: none, | ||||||
|   stroke: black + 1pt, |   stroke: black + 1pt, | ||||||
|   id: "", |   id: "", | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| #import "@preview/cetz:0.2.2": draw, coordinate | #import "@preview/cetz:0.3.2": draw, coordinate | ||||||
| #import "../ports.typ": add-ports, add-port | #import "../ports.typ": add-ports, add-port | ||||||
| #import "../element.typ" | #import "../element.typ" | ||||||
|  |  | ||||||
| @@ -33,7 +33,7 @@ | |||||||
|   stroke: black + 1pt, |   stroke: black + 1pt, | ||||||
|   id: "", |   id: "", | ||||||
|   inverted: (), |   inverted: (), | ||||||
|   inverted-radius: 0.2, |   inverted-radius: 0.1, | ||||||
|   debug: ( |   debug: ( | ||||||
|     ports: false |     ports: false | ||||||
|   ) |   ) | ||||||
| @@ -58,19 +58,16 @@ | |||||||
|   if (type(y) == dictionary) { |   if (type(y) == dictionary) { | ||||||
|     let from = y.from |     let from = y.from | ||||||
|     let to = y.to |     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) |     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) |   let tl = (x, y + height) | ||||||
|   | |||||||
							
								
								
									
										70
									
								
								src/elements/logic/iec_and.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,70 @@ | |||||||
|  | #import "@preview/cetz:0.3.2": draw | ||||||
|  | // #import "iec_gate.typ" as iec-gate | ||||||
|  | #import "iec_gate.typ" as iec-gate | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// Draws an IEC-AND gate. This function is also available as `element.iec-gate-and()` | ||||||
|  | ///  | ||||||
|  | /// For parameters, see #doc-ref("gates.iec-gate") | ||||||
|  | /// #examples.iec-gate-and | ||||||
|  | #let iec-gate-and( | ||||||
|  |   x: none, | ||||||
|  |   y: none, | ||||||
|  |   w: none, | ||||||
|  |   h: none, | ||||||
|  |   inputs: 2, | ||||||
|  |   fill: none, | ||||||
|  |   stroke: black + 1pt, | ||||||
|  |   id: "", | ||||||
|  |   inverted: (), | ||||||
|  |   debug: ( | ||||||
|  |     ports: false | ||||||
|  |   ), | ||||||
|  | ) = { | ||||||
|  |   iec-gate.iec-gate( | ||||||
|  |     x: x, | ||||||
|  |     y: y, | ||||||
|  |     w: w, | ||||||
|  |     h: h, | ||||||
|  |     inputs: inputs, | ||||||
|  |     fill: fill, | ||||||
|  |     stroke: stroke, | ||||||
|  |     id: id, | ||||||
|  |     inverted: inverted, | ||||||
|  |     debug: debug, | ||||||
|  |     symbol: $amp$, | ||||||
|  |   ) | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// Draws an IEC-NAND gate. This function is also available as `element.iec-gate-nand()` | ||||||
|  | ///  | ||||||
|  | /// For parameters, see #doc-ref("gates.iec-gate") | ||||||
|  | /// #examples.iec-gate-nand | ||||||
|  | #let iec-gate-nand( | ||||||
|  |   x: none, | ||||||
|  |   y: none, | ||||||
|  |   w: none, | ||||||
|  |   h: none, | ||||||
|  |   inputs: 2, | ||||||
|  |   fill: none, | ||||||
|  |   stroke: black + 1pt, | ||||||
|  |   id: "", | ||||||
|  |   inverted: (), | ||||||
|  |   debug: ( | ||||||
|  |     ports: false | ||||||
|  |   ), | ||||||
|  | ) = { | ||||||
|  |   iec-gate-and( | ||||||
|  |     x: x, | ||||||
|  |     y: y, | ||||||
|  |     w: w, | ||||||
|  |     h: h, | ||||||
|  |     inputs: inputs, | ||||||
|  |     fill: fill, | ||||||
|  |     stroke: stroke, | ||||||
|  |     id: id, | ||||||
|  |     inverted: if inverted != "all" {inverted + ("out",)} else {inverted}, | ||||||
|  |     debug: debug, | ||||||
|  |   ) | ||||||
|  | } | ||||||
							
								
								
									
										68
									
								
								src/elements/logic/iec_buf.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,68 @@ | |||||||
|  | #import "@preview/cetz:0.3.2": draw | ||||||
|  | #import "iec_gate.typ" as iec-gate | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// Draws an IEC buffer gate. This function is also available as `element.iec-gate-buf()` | ||||||
|  | /// | ||||||
|  | /// For parameters, see #doc-ref("gates.iec-gate") | ||||||
|  | /// #examples.iec-gate-buf | ||||||
|  | #let iec-gate-buf( | ||||||
|  |   x: none, | ||||||
|  |   y: none, | ||||||
|  |   w: none, | ||||||
|  |   h: none, | ||||||
|  |   inputs: 2, | ||||||
|  |   fill: none, | ||||||
|  |   stroke: black + 1pt, | ||||||
|  |   id: "", | ||||||
|  |   inverted: (), | ||||||
|  |   debug: ( | ||||||
|  |     ports: false, | ||||||
|  |   ), | ||||||
|  | ) = { | ||||||
|  |   iec-gate.iec-gate( | ||||||
|  |     x: x, | ||||||
|  |     y: y, | ||||||
|  |     w: w, | ||||||
|  |     h: h, | ||||||
|  |     inputs: inputs, | ||||||
|  |     fill: fill, | ||||||
|  |     stroke: stroke, | ||||||
|  |     id: id, | ||||||
|  |     inverted: inverted, | ||||||
|  |     debug: debug, | ||||||
|  |     symbol: "1", | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// Draws an IEC NOT gate. This function is also available as `element.iec-gate-not()` | ||||||
|  | ///  | ||||||
|  | /// For parameters, see #doc-ref("gates.iec-gate") | ||||||
|  | /// #examples.iec-gate-not | ||||||
|  | #let iec-gate-not( | ||||||
|  |   x: none, | ||||||
|  |   y: none, | ||||||
|  |   w: none, | ||||||
|  |   h: none, | ||||||
|  |   inputs: 2, | ||||||
|  |   fill: none, | ||||||
|  |   stroke: black + 1pt, | ||||||
|  |   id: "", | ||||||
|  |   inverted: (), | ||||||
|  |   debug: ( | ||||||
|  |     ports: false, | ||||||
|  |   ), | ||||||
|  | ) = { | ||||||
|  |   iec-gate-buf( | ||||||
|  |     x: x, | ||||||
|  |     y: y, | ||||||
|  |     w: w, | ||||||
|  |     h: h, | ||||||
|  |     inputs: inputs, | ||||||
|  |     fill: fill, | ||||||
|  |     stroke: stroke, | ||||||
|  |     id: id, | ||||||
|  |     inverted: if inverted != "all" { inverted + ("out",) } else { inverted }, | ||||||
|  |     debug: debug, | ||||||
|  |   ) | ||||||
|  | } | ||||||
							
								
								
									
										125
									
								
								src/elements/logic/iec_gate.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,125 @@ | |||||||
|  | #import "@preview/cetz:0.3.2": draw, coordinate | ||||||
|  | #import "../ports.typ": add-ports, add-port | ||||||
|  | #import "../element.typ" | ||||||
|  |  | ||||||
|  | #let default-draw-shape(id, tl, tr, br, bl, fill, stroke, symbol) = { | ||||||
|  |   let shapes = draw.rect( | ||||||
|  |     inset: 0.5em, | ||||||
|  |     fill: fill, | ||||||
|  |     stroke: stroke, | ||||||
|  |     name: id, | ||||||
|  |     bl, tr | ||||||
|  |   ) | ||||||
|  |   shapes += draw.content( | ||||||
|  |     id + ".center", | ||||||
|  |     [*$ symbol $*] | ||||||
|  |   ) | ||||||
|  |   return (shapes, tl, tr, br, bl) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// Draws a logic gate. This function is also available as `element.iec-gate()` | ||||||
|  | /// | ||||||
|  | /// - draw-shape (function): see #doc-ref("element.elmt") | ||||||
|  | /// - x (number, dictionary): see #doc-ref("element.elmt") | ||||||
|  | /// - y (number, dictionary): see #doc-ref("element.elmt") | ||||||
|  | /// - w (number): see #doc-ref("element.elmt") | ||||||
|  | /// - h (number): see #doc-ref("element.elmt") | ||||||
|  | /// - inputs (int): The number of inputs | ||||||
|  | /// - fill (none, color): see #doc-ref("element.elmt") | ||||||
|  | /// - stroke (stroke): see #doc-ref("element.elmt") | ||||||
|  | /// - id (str): see #doc-ref("element.elmt") | ||||||
|  | /// - inverted (str, array): Either "all" or an array of port ids to display as inverted | ||||||
|  | /// - inverted-radius (number): The radius of inverted ports dot | ||||||
|  | /// - debug (dictionary): see #doc-ref("element.elmt") | ||||||
|  | /// - symbol (str): The symbol to display at the center of the gate | ||||||
|  | #let iec-gate( | ||||||
|  |   draw-shape: default-draw-shape, | ||||||
|  |   x: none, | ||||||
|  |   y: none, | ||||||
|  |   w: none, | ||||||
|  |   h: none, | ||||||
|  |   inputs: 2, | ||||||
|  |   fill: none, | ||||||
|  |   stroke: black + 1pt, | ||||||
|  |   id: "", | ||||||
|  |   inverted: (), | ||||||
|  |   inverted-radius: 0.1, | ||||||
|  |   debug: ( | ||||||
|  |     ports: false | ||||||
|  |   ), | ||||||
|  |   symbol: "", | ||||||
|  | ) = draw.get-ctx(ctx => { | ||||||
|  |   let width = w | ||||||
|  |   let height = h | ||||||
|  |  | ||||||
|  |   let x = x | ||||||
|  |   let y = y | ||||||
|  |   if x == none { panic("Parameter x must be set") } | ||||||
|  |   if y == none { panic("Parameter y must be set") } | ||||||
|  |   if w == none { panic("Parameter w must be set") } | ||||||
|  |   if h == none { panic("Parameter h must be set") } | ||||||
|  |  | ||||||
|  |   if (type(x) == dictionary) { | ||||||
|  |     let offset = x.rel | ||||||
|  |     let to = x.to | ||||||
|  |     let (ctx, to-pos) = coordinate.resolve(ctx, (rel: (offset, 0), to: to)) | ||||||
|  |     x = to-pos.at(0) | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   if (type(y) == dictionary) { | ||||||
|  |     let from = y.from | ||||||
|  |     let to = y.to | ||||||
|  |      | ||||||
|  |     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 | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   let tl = (x, y + height) | ||||||
|  |   let tr = (x + width, y + height) | ||||||
|  |   let br = (x + width, y) | ||||||
|  |   let bl = (x, y) | ||||||
|  |  | ||||||
|  |   // Workaround because CeTZ needs to have all draw functions in the body | ||||||
|  |   let func = {} | ||||||
|  |   (func, tl, tr, br, bl) = draw-shape(id, tl, tr, br, bl, fill, stroke, symbol) | ||||||
|  |   func | ||||||
|  |  | ||||||
|  |   let space = 100% / inputs | ||||||
|  |   for i in range(inputs) { | ||||||
|  |     let pct = (i + 0.5) * space | ||||||
|  |     let port-pos = (tl, pct, bl) | ||||||
|  |     let port-name = "in" + str(i) | ||||||
|  |     if inverted == "all" or port-name in inverted { | ||||||
|  |       draw.circle( | ||||||
|  |         port-pos, | ||||||
|  |         radius: inverted-radius, | ||||||
|  |         anchor: "east", | ||||||
|  |         stroke: stroke | ||||||
|  |       ) | ||||||
|  |       port-pos = (rel: (-2 * inverted-radius, 0), to: port-pos) | ||||||
|  |     } | ||||||
|  |     add-port( | ||||||
|  |       id, "west", | ||||||
|  |       (id: port-name), port-pos, | ||||||
|  |       debug: debug.ports | ||||||
|  |     ) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   let out-pos = id + ".east" | ||||||
|  |   if inverted == "all" or "out" in inverted { | ||||||
|  |     draw.circle(out-pos, radius: inverted-radius, anchor: "west", stroke: stroke) | ||||||
|  |     out-pos = (rel: (2 * inverted-radius, 0), to: out-pos) | ||||||
|  |   } | ||||||
|  |   add-port( | ||||||
|  |     id, "east", | ||||||
|  |     (id: "out"), out-pos, | ||||||
|  |     debug: debug.ports | ||||||
|  |   ) | ||||||
|  | }) | ||||||
							
								
								
									
										67
									
								
								src/elements/logic/iec_or.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,67 @@ | |||||||
|  | #import "@preview/cetz:0.3.2": draw | ||||||
|  | #import "iec_gate.typ" as iec-gate | ||||||
|  |  | ||||||
|  | /// Draws an IEC-OR gate. This function is also available as `element.iec-gate-or()` | ||||||
|  | ///  | ||||||
|  | /// For parameters, see #doc-ref("gates.iec-gate") | ||||||
|  | /// #examples.iec-gate-or | ||||||
|  | #let iec-gate-or( | ||||||
|  |   x: none, | ||||||
|  |   y: none, | ||||||
|  |   w: none, | ||||||
|  |   h: none, | ||||||
|  |   inputs: 2, | ||||||
|  |   fill: none, | ||||||
|  |   stroke: black + 1pt, | ||||||
|  |   id: "", | ||||||
|  |   inverted: (), | ||||||
|  |   debug: ( | ||||||
|  |     ports: false | ||||||
|  |   ) | ||||||
|  | ) = { | ||||||
|  |   iec-gate.iec-gate( | ||||||
|  |     x: x, | ||||||
|  |     y: y, | ||||||
|  |     w: w, | ||||||
|  |     h: h, | ||||||
|  |     inputs: inputs, | ||||||
|  |     fill: fill, | ||||||
|  |     stroke: stroke, | ||||||
|  |     id: id, | ||||||
|  |     inverted: inverted, | ||||||
|  |     debug: debug, | ||||||
|  |     symbol: $>= 1$, | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// Draws an IEC-NOR gate. This function is also available as `element.iec-gate-nor()` | ||||||
|  | ///  | ||||||
|  | /// For parameters, see #doc-ref("gates.iec-gate") | ||||||
|  | /// #examples.iec-gate-nor | ||||||
|  | #let iec-gate-nor( | ||||||
|  |   x: none, | ||||||
|  |   y: none, | ||||||
|  |   w: none, | ||||||
|  |   h: none, | ||||||
|  |   inputs: 2, | ||||||
|  |   fill: none, | ||||||
|  |   stroke: black + 1pt, | ||||||
|  |   id: "", | ||||||
|  |   inverted: (), | ||||||
|  |   debug: ( | ||||||
|  |     ports: false | ||||||
|  |   ) | ||||||
|  | ) = { | ||||||
|  |   iec-gate-or( | ||||||
|  |     x: x, | ||||||
|  |     y: y, | ||||||
|  |     w: w, | ||||||
|  |     h: h, | ||||||
|  |     inputs: inputs, | ||||||
|  |     fill: fill, | ||||||
|  |     stroke: stroke, | ||||||
|  |     id: id, | ||||||
|  |     inverted: if inverted != "all" {inverted + ("out",)} else {inverted}, | ||||||
|  |     debug: debug | ||||||
|  |   ) | ||||||
|  | } | ||||||
							
								
								
									
										67
									
								
								src/elements/logic/iec_xor.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,67 @@ | |||||||
|  | #import "@preview/cetz:0.3.2": draw | ||||||
|  | #import "iec_gate.typ" as iec-gate | ||||||
|  |  | ||||||
|  | /// Draws an IEC-XOR gate. This function is also available as `element.iec-gate-xor()` | ||||||
|  | ///  | ||||||
|  | /// For parameters, see #doc-ref("gates.iec-gate") | ||||||
|  | /// #examples.iec-gate-xor | ||||||
|  | #let iec-gate-xor( | ||||||
|  |   x: none, | ||||||
|  |   y: none, | ||||||
|  |   w: none, | ||||||
|  |   h: none, | ||||||
|  |   inputs: 2, | ||||||
|  |   fill: none, | ||||||
|  |   stroke: black + 1pt, | ||||||
|  |   id: "", | ||||||
|  |   inverted: (), | ||||||
|  |   debug: ( | ||||||
|  |     ports: false | ||||||
|  |   ) | ||||||
|  | ) = { | ||||||
|  |   iec-gate.iec-gate( | ||||||
|  |     x: x, | ||||||
|  |     y: y, | ||||||
|  |     w: w, | ||||||
|  |     h: h, | ||||||
|  |     inputs: inputs, | ||||||
|  |     fill: fill, | ||||||
|  |     stroke: stroke, | ||||||
|  |     id: id, | ||||||
|  |     inverted: inverted, | ||||||
|  |     debug: debug, | ||||||
|  |     symbol: $= 1$, | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// Draws an IEC-XNOR gate. This function is also available as `element.iec-gate-xnor()` | ||||||
|  | ///  | ||||||
|  | /// For parameters, see #doc-ref("gates.iec-gate") | ||||||
|  | /// #examples.iec-gate-xnor | ||||||
|  | #let iec-gate-xnor( | ||||||
|  |   x: none, | ||||||
|  |   y: none, | ||||||
|  |   w: none, | ||||||
|  |   h: none, | ||||||
|  |   inputs: 2, | ||||||
|  |   fill: none, | ||||||
|  |   stroke: black + 1pt, | ||||||
|  |   id: "", | ||||||
|  |   inverted: (), | ||||||
|  |   debug: ( | ||||||
|  |     ports: false | ||||||
|  |   ) | ||||||
|  | ) = { | ||||||
|  |   iec-gate-xor( | ||||||
|  |     x: x, | ||||||
|  |     y: y, | ||||||
|  |     w: w, | ||||||
|  |     h: h, | ||||||
|  |     inputs: inputs, | ||||||
|  |     fill: fill, | ||||||
|  |     stroke: stroke, | ||||||
|  |     id: id, | ||||||
|  |     inverted: if inverted != "all" {inverted + ("out",)} else {inverted}, | ||||||
|  |     debug: debug | ||||||
|  |   ) | ||||||
|  | } | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| #import "@preview/cetz:0.2.2": draw | #import "@preview/cetz:0.3.2": draw | ||||||
| #import "gate.typ" | #import "gate.typ" | ||||||
|  |  | ||||||
| #let draw-shape(id, tl, tr, br, bl, fill, stroke) = { | #let draw-shape(id, tl, tr, br, bl, fill, stroke) = { | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| #import "@preview/cetz:0.2.2": draw | #import "@preview/cetz:0.3.2": draw | ||||||
| #import "gate.typ" | #import "gate.typ" | ||||||
|  |  | ||||||
| #let space = 10% | #let space = 10% | ||||||
|   | |||||||
| @@ -1,10 +1,12 @@ | |||||||
| #import "@preview/cetz:0.2.2": draw | #import "@preview/cetz:0.3.2": draw | ||||||
| #import "../util.typ" | #import "../util.typ" | ||||||
| #import "element.typ" | #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: 60%) = { | ||||||
|   let tr2 = (tr, 20%, br) |   let margin = (100% - h-ratio) / 2 | ||||||
|   let br2 = (tr, 80%, br) |   let tr2 = (tr, margin, br) | ||||||
|  |   let br2 = (br, margin, tr) | ||||||
|   let f = draw.group(name: id, { |   let f = draw.group(name: id, { | ||||||
|     draw.merge-path( |     draw.merge-path( | ||||||
|       inset: 0.5em, |       inset: 0.5em, | ||||||
| @@ -17,7 +19,12 @@ | |||||||
|     draw.anchor("south", (bl, 50%, br2)) |     draw.anchor("south", (bl, 50%, br2)) | ||||||
|     draw.anchor("west", (tl, 50%, bl)) |     draw.anchor("west", (tl, 50%, bl)) | ||||||
|     draw.anchor("east", (tr2, 50%, br2)) |     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) |   return (f, tl, tr, br, bl) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -26,6 +33,7 @@ | |||||||
| /// #examples.multiplexer | /// #examples.multiplexer | ||||||
| /// For other parameters description, see #doc-ref("element.elmt") | /// 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. | /// - 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( | #let multiplexer( | ||||||
|   x: none, |   x: none, | ||||||
|   y: none, |   y: none, | ||||||
| @@ -34,6 +42,7 @@ | |||||||
|   name: none, |   name: none, | ||||||
|   name-anchor: "center", |   name-anchor: "center", | ||||||
|   entries: 2, |   entries: 2, | ||||||
|  |   h-ratio: 60%, | ||||||
|   fill: none, |   fill: none, | ||||||
|   stroke: black + 1pt, |   stroke: black + 1pt, | ||||||
|   id: "", |   id: "", | ||||||
| @@ -42,6 +51,9 @@ | |||||||
|   ) |   ) | ||||||
| ) = { | ) = { | ||||||
|   let ports = () |   let ports = () | ||||||
|  |   let ports-y = ( | ||||||
|  |     out: (h) => {h * 0.5} | ||||||
|  |   ) | ||||||
|  |  | ||||||
|   if (type(entries) == int) { |   if (type(entries) == int) { | ||||||
|     let nbits = calc.ceil(calc.log(entries, base: 2)) |     let nbits = calc.ceil(calc.log(entries, base: 2)) | ||||||
| @@ -54,9 +66,15 @@ | |||||||
|       ports.push((id: "in" + str(i), name: port)) |       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( |   element.elmt( | ||||||
|     draw-shape: draw-shape, |     draw-shape: draw-shape.with(h-ratio: h-ratio), | ||||||
|     x: x, |     x: x, | ||||||
|     y: y, |     y: y, | ||||||
|     w: w, |     w: w, | ||||||
| @@ -67,6 +85,14 @@ | |||||||
|     fill: fill, |     fill: fill, | ||||||
|     stroke: stroke, |     stroke: stroke, | ||||||
|     id: id, |     id: id, | ||||||
|  |     ports-y: ports-y, | ||||||
|  |     auto-ports: false, | ||||||
|     debug: debug |     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")) | ||||||
| } | } | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| #import "@preview/cetz:0.2.2": draw | #import "@preview/cetz:0.3.2": draw | ||||||
| #import "../util.typ": rotate-anchor | #import "../util.typ": rotate-anchor | ||||||
|  |  | ||||||
| #let add-port( | #let add-port( | ||||||
| @@ -15,11 +15,12 @@ | |||||||
|       panic("Clock port must have previous and next positions") |       panic("Clock port must have previous and next positions") | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     let size = if port.at("small", default: false) {8pt} else {1em} | ||||||
|     let offset |     let offset | ||||||
|     if      (side == "north") { offset = (   0, -1em) } |     if      (side == "north") { offset = (    0, -size) } | ||||||
|     else if (side == "east")  { offset = (-1em,    0) } |     else if (side == "east")  { offset = (-size,     0) } | ||||||
|     else if (side == "south") { offset = (   0,  1em) } |     else if (side == "south") { offset = (    0,  size) } | ||||||
|     else if (side == "west")  { offset = ( 1em,    0) } |     else if (side == "west")  { offset = ( size,     0) } | ||||||
|  |  | ||||||
|     let pos1 = (rel: offset, to: pos) |     let pos1 = (rel: offset, to: pos) | ||||||
|  |  | ||||||
| @@ -96,6 +97,11 @@ | |||||||
|       let pos-prev = (pt0, pct-prev, pt1) |       let pos-prev = (pt0, pct-prev, pt1) | ||||||
|       let pos-next = (pt0, pct-next, 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( |       add-port( | ||||||
|         elmt-id, |         elmt-id, | ||||||
|         side, |         side, | ||||||
|   | |||||||
| @@ -2,4 +2,9 @@ | |||||||
| #import "elements/logic/and.typ": gate-and, gate-nand | #import "elements/logic/and.typ": gate-and, gate-nand | ||||||
| #import "elements/logic/or.typ": gate-or, gate-nor | #import "elements/logic/or.typ": gate-or, gate-nor | ||||||
| #import "elements/logic/xor.typ": gate-xor, gate-xnor | #import "elements/logic/xor.typ": gate-xor, gate-xnor | ||||||
| #import "elements/logic/buf.typ": gate-buf, gate-not | #import "elements/logic/buf.typ": gate-buf, gate-not | ||||||
|  | #import "elements/logic/iec_gate.typ": iec-gate | ||||||
|  | #import "elements/logic/iec_and.typ": iec-gate-and, iec-gate-nand | ||||||
|  | #import "elements/logic/iec_or.typ": iec-gate-or, iec-gate-nor | ||||||
|  | #import "elements/logic/iec_buf.typ": iec-gate-buf, iec-gate-not | ||||||
|  | #import "elements/logic/iec_xor.typ": iec-gate-xor, iec-gate-xnor | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| #let version = version((0,0,2)) | #let version = version(0, 2, 0) | ||||||
|  |  | ||||||
| #import "circuit.typ": circuit | #import "circuit.typ": circuit | ||||||
| #import "element.typ" | #import "element.typ" | ||||||
|   | |||||||
| @@ -68,4 +68,9 @@ | |||||||
|     south-east: "south-west", |     south-east: "south-west", | ||||||
|     south-west: "north-west" |     south-west: "north-west" | ||||||
|   ).at(anchor) |   ).at(anchor) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #let valid-anchors = ( | ||||||
|  |   "center", "north", "east", "west", "south", | ||||||
|  |   "north-east", "north-west", "south-east", "south-west" | ||||||
|  | ) | ||||||
							
								
								
									
										191
									
								
								src/wire.typ
									
									
									
									
									
								
							
							
						
						| @@ -1,14 +1,19 @@ | |||||||
| #import "@preview/cetz:0.2.2": draw, coordinate | #import "@preview/cetz:0.3.2": draw, coordinate | ||||||
| #import "util.typ": opposite-anchor | #import "util.typ": opposite-anchor | ||||||
|  |  | ||||||
| /// List of valid wire styles | /// List of valid wire styles | ||||||
| /// #examples.wires | /// #examples.wires | ||||||
| #let wire-styles = ("direct", "zigzag", "dodge") | #let wire-styles = ("direct", "zigzag", "dodge", "guided") | ||||||
| #let signal-width = 1pt | #let signal-width = 1pt | ||||||
| #let bus-width = 1.5pt | #let bus-width = 1.5pt | ||||||
|  |  | ||||||
| #let intersection(pt) = { | /// Draws a wire intersection at the given anchor | ||||||
|   draw.circle(pt, radius: .2, stroke: none, fill: black) | /// #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) | ||||||
| } | } | ||||||
|  |  | ||||||
| #let get-direct-wire(pts) = { | #let get-direct-wire(pts) = { | ||||||
| @@ -19,17 +24,30 @@ | |||||||
|   return (pts, anchors) |   return (pts, anchors) | ||||||
| } | } | ||||||
|  |  | ||||||
| #let get-zigzag-wire(pts, ratio) = { | #let get-zigzag-wire(pts, ratio, dir) = { | ||||||
|   let start = pts.first() |   let start = pts.first() | ||||||
|   let end = pts.last() |   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 = ( |   let points = if dir == "vertical" { | ||||||
|     start, |     ( | ||||||
|     (horizontal: mid, vertical: ()), |       start, | ||||||
|     (horizontal: (), vertical: end), |       (horizontal: mid, vertical: ()), | ||||||
|     end |       (horizontal: (), vertical: end), | ||||||
|   ) |       end | ||||||
|  |     ) | ||||||
|  |   } else { | ||||||
|  |     ( | ||||||
|  |       start, | ||||||
|  |       (horizontal: (), vertical: mid), | ||||||
|  |       (horizontal: end, vertical: ()), | ||||||
|  |       end | ||||||
|  |     ) | ||||||
|  |   } | ||||||
|   let anchors = ( |   let anchors = ( | ||||||
|     "start": start, |     "start": start, | ||||||
|     "zig": points.at(1), |     "zig": points.at(1), | ||||||
| @@ -91,6 +109,88 @@ | |||||||
|   return (points, anchors) |   return (points, anchors) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #let get-guided-wire(pts, margins, sides, center-guides, ctx) = { | ||||||
|  |   let start = pts.first() | ||||||
|  |   let end = pts.last() | ||||||
|  |   let (margin-start, margin-end) = margins | ||||||
|  |   let (side-start, side-end) = sides | ||||||
|  |   let (center_horizontal, center_vertical) = center-guides | ||||||
|  |  | ||||||
|  |   let (ctx, p0) = coordinate.resolve(ctx, start) | ||||||
|  |   let (ctx, p6) = coordinate.resolve(ctx, end) | ||||||
|  |   p0 = (x: p0.first(), y: p0.at(1)) | ||||||
|  |   p6 = (x: p6.first(), y: p6.at(1)) | ||||||
|  |  | ||||||
|  |   let box_width = calc.abs(p6.x - p0.x) | ||||||
|  |   let box_height = calc.abs(p6.y - p0.y) | ||||||
|  |  | ||||||
|  |   // finding correct dx and dy | ||||||
|  |   let dx1 = box_width * margin-start / 100% | ||||||
|  |   if side-start == "west" { | ||||||
|  |     dx1 *= -1 | ||||||
|  |   } else if side-start == "north" or side-start == "south" { dx1 = 0} | ||||||
|  |  | ||||||
|  |   let dx2 = box_width * margin-end / 100% | ||||||
|  |   if side-end == "west" { | ||||||
|  |     dx2 *= -1 | ||||||
|  |   } else if side-end == "north" or side-end == "south" { dx2 = 0} | ||||||
|  |  | ||||||
|  |   let dy1 = box_height * margin-start / 100% | ||||||
|  |   if side-start == "south" { | ||||||
|  |     dy1 *= -1 | ||||||
|  |   } else if side-start == "west" or side-start == "east" { dy1 = 0} | ||||||
|  |  | ||||||
|  |   let dy2 = box_height * margin-end / 100% | ||||||
|  |   if side-end == "south" { | ||||||
|  |     dy2 *= -1 | ||||||
|  |   } else if side-end == "west" or side-end == "east" { dy2 = 0} | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   // points that are closest to the edge points | ||||||
|  |   let p1 = (p0.x + dx1, p0.y + dy1) | ||||||
|  |   let p5 = (p6.x + dx2, p6.y + dy2) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   // middle point | ||||||
|  |   let center_x = p0.x + box_width * center_horizontal / 100% | ||||||
|  |   let center_y = p0.y + box_height * center_vertical / 100% | ||||||
|  |   let p3 = (center_x, center_y) | ||||||
|  |  | ||||||
|  |   // setting up the points for that touch the guides | ||||||
|  |   let p2 = (0,0) | ||||||
|  |   let p4 = (0,0) | ||||||
|  |   if side-start in ("north", "south") { | ||||||
|  |     p2 = (horizontal: p3, vertical: p1) | ||||||
|  |   } else { | ||||||
|  |     p2 = (horizontal: p1, vertical: p3) | ||||||
|  |   } | ||||||
|  |   if side-end in ("north", "south") { | ||||||
|  |     p4 = (horizontal: p3, vertical: p5) | ||||||
|  |   } else if side-end in ("east", "west") { | ||||||
|  |     p4 = (horizontal: p5, vertical: p3) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // returning | ||||||
|  |   let points = ( | ||||||
|  |     start, | ||||||
|  |     p1, | ||||||
|  |     p2, | ||||||
|  |     p3, | ||||||
|  |     p4, | ||||||
|  |     p5, | ||||||
|  |     end | ||||||
|  |   ) | ||||||
|  |   let anchors = ( | ||||||
|  |     "start": start, | ||||||
|  |     "start2": points.at(1), | ||||||
|  |     "guide-start": points.at(2), | ||||||
|  |     "center": points.at(3), | ||||||
|  |     "guide-end": points.at(4), | ||||||
|  |     "end2": points.at(5), | ||||||
|  |     "end": end | ||||||
|  |   ) | ||||||
|  |   return (points, anchors) | ||||||
|  | } | ||||||
| /// Draws a wire between two points | /// Draws a wire between two points | ||||||
| /// - id (str): The wire's id, for future reference (anchors) | /// - id (str): The wire's id, for future reference (anchors) | ||||||
| /// - pts (array): The two points (as CeTZ compatible coordinates, i.e. XY, relative positions, ids, etc.) | /// - pts (array): The two points (as CeTZ compatible coordinates, i.e. XY, relative positions, ids, etc.) | ||||||
| @@ -102,10 +202,16 @@ | |||||||
| /// - dashed (bool): Whether the stroke is dashed or not | /// - dashed (bool): Whether the stroke is dashed or not | ||||||
| /// - style (str): The wire's style (see #doc-ref("wire.wire-styles", var: true) for possible values) | /// - style (str): The wire's style (see #doc-ref("wire.wire-styles", var: true) for possible values) | ||||||
| /// - reverse (bool): If true, the start and end points will be swapped (useful in cases where the start point depends on the end point, for example with perpendiculars) | /// - reverse (bool): If true, the start and end points will be swapped (useful in cases where the start point depends on the end point, for example with perpendiculars) | ||||||
|  | /// - directed (bool): If true, the wire will be directed, meaning an arrow will be drawn at the endpoint | ||||||
|  | /// - rotate-name (bool): If true, the name will be rotated according to the wire's slope | ||||||
| /// - zigzag-ratio (ratio): Position of the zigzag vertical relative to the horizontal span (only with style "zigzag") | /// - zigzag-ratio (ratio): Position of the zigzag vertical relative to the horizontal span (only with style "zigzag") | ||||||
|  | /// - zigzag-dir (str): The zigzag's direction. As either "vertical" or "horizontal" (only with dstyle "zigzag") | ||||||
| /// - dodge-y (number): Y position to dodge the wire to (only with style "dodge") | /// - dodge-y (number): Y position to dodge the wire to (only with style "dodge") | ||||||
| /// - dodge-sides (array): The start and end sides (going out of the connected element) of the wire (only with style "dodge") | /// - dodge-sides (array): The start and end sides (going out of the connected element) of the wire (only with style "dodge") | ||||||
| /// - dodge-margins (array): The start and end margins (i.e. space before dodging) of the wire (only with style "dodge") | /// - dodge-margins (array): The start and end margins (i.e. space before dodging) of the wire (only with style "dodge") | ||||||
|  | /// - guided-center (array): the horizontal and vertical guides of the center guides (only with style "guided") | ||||||
|  | /// - guided-margins (array): the start and end of guided margins of the wire (only with style "guided") | ||||||
|  | /// - guided-sides (array): the side of start and end array (must be either "north", "south", "west", "east") (only work with style "guided") | ||||||
| #let wire( | #let wire( | ||||||
|   id, pts, |   id, pts, | ||||||
|   bus: false, |   bus: false, | ||||||
| @@ -116,7 +222,13 @@ | |||||||
|   dashed: false, |   dashed: false, | ||||||
|   style: "direct", |   style: "direct", | ||||||
|   reverse: false, |   reverse: false, | ||||||
|  |   guided-center: (50%, 50%), | ||||||
|  |   guided-margins: (5%, 5%), | ||||||
|  |   guided-sides: ("east", "west"), | ||||||
|  |   directed: false, | ||||||
|  |   rotate-name: true, | ||||||
|   zigzag-ratio: 50%, |   zigzag-ratio: 50%, | ||||||
|  |   zigzag-dir: "vertical", | ||||||
|   dodge-y: 0, |   dodge-y: 0, | ||||||
|   dodge-sides: ("east", "west"), |   dodge-sides: ("east", "west"), | ||||||
|   dodge-margins: (5%, 5%) |   dodge-margins: (5%, 5%) | ||||||
| @@ -144,7 +256,7 @@ | |||||||
|     (points, anchors) = get-direct-wire(pts) |     (points, anchors) = get-direct-wire(pts) | ||||||
|      |      | ||||||
|   } else if style == "zigzag" { |   } else if style == "zigzag" { | ||||||
|     (points, anchors) = get-zigzag-wire(pts, zigzag-ratio) |     (points, anchors) = get-zigzag-wire(pts, zigzag-ratio, zigzag-dir) | ||||||
|      |      | ||||||
|   } else if style == "dodge" { |   } else if style == "dodge" { | ||||||
|     (points, anchors) = get-dodge-wire( |     (points, anchors) = get-dodge-wire( | ||||||
| @@ -154,10 +266,22 @@ | |||||||
|       dodge-sides, |       dodge-sides, | ||||||
|       ctx |       ctx | ||||||
|     ) |     ) | ||||||
|  |   } else if style == "guided" { | ||||||
|  |     (points, anchors) = get-guided-wire( | ||||||
|  |       pts, | ||||||
|  |       guided-margins, | ||||||
|  |       guided-sides, | ||||||
|  |       guided-center, | ||||||
|  |       ctx | ||||||
|  |     ) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   let mark = (fill: color) | ||||||
|  |   if directed { | ||||||
|  |     mark = (end: ">", fill: color) | ||||||
|  |   } | ||||||
|   draw.group(name: id, { |   draw.group(name: id, { | ||||||
|     draw.line(..points, stroke: stroke) |     draw.line(..points, stroke: stroke, mark: mark) | ||||||
|     for (anchor-name, anchor-pos) in anchors { |     for (anchor-name, anchor-pos) in anchors { | ||||||
|       draw.anchor(anchor-name, anchor-pos) |       draw.anchor(anchor-name, anchor-pos) | ||||||
|     } |     } | ||||||
| @@ -165,10 +289,25 @@ | |||||||
|  |  | ||||||
|   let first-pt = id + ".start" |   let first-pt = id + ".start" | ||||||
|   let last-pt = id + ".end" |   let last-pt = id + ".end" | ||||||
|  |   let first-pos = points.first() | ||||||
|  |   let second-pos = points.at(1) | ||||||
|   if reverse { |   if reverse { | ||||||
|     (first-pt, last-pt) = (last-pt, first-pt) |     (first-pt, last-pt) = (last-pt, first-pt) | ||||||
|   } |   } | ||||||
|    |    | ||||||
|  |   let angle = 0deg | ||||||
|  |   if rotate-name { | ||||||
|  |     (ctx, first-pos) = coordinate.resolve(ctx, first-pos) | ||||||
|  |     (ctx, second-pos) = coordinate.resolve(ctx, 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) | ||||||
|  |   } | ||||||
|  |    | ||||||
|   if name != none { |   if name != none { | ||||||
|     let names = () |     let names = () | ||||||
|      |      | ||||||
| @@ -199,13 +338,12 @@ | |||||||
|         anchor = "south-east" |         anchor = "south-east" | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       draw.content(point, anchor: anchor, padding: 3pt, name) |       draw.content(point, anchor: anchor, padding: 3pt, angle: angle, name) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if slice != none { |   if slice != none { | ||||||
|     let (start, end) = slice |     let slice-txt = "[" + slice.map(b => str(b)).join(":") + "]" | ||||||
|     let slice-txt = "[" + str(start) + ":" + str(end) + "]" |  | ||||||
|      |      | ||||||
|     draw.content( |     draw.content( | ||||||
|       first-pt, |       first-pt, | ||||||
| @@ -224,16 +362,25 @@ | |||||||
| /// - name (none, str): Optional name displayed at the end of the stub | /// - name (none, str): Optional name displayed at the end of the stub | ||||||
| /// - vertical (bool): Whether the name should be displayed vertically | /// - vertical (bool): Whether the name should be displayed vertically | ||||||
| /// - length (number): The length of the stub | /// - length (number): The length of the stub | ||||||
| #let stub(port-id, side, name: none, vertical: false, length: 1em) = { | /// - name-offset (number): The name offset, perpendicular to the stub | ||||||
|   let offset = ( | #let stub(port-id, side, name: none, vertical: false, length: 1em, name-offset: 0) = { | ||||||
|  |   let end-offset = ( | ||||||
|     north: (0, length), |     north: (0, length), | ||||||
|     east: (length, 0), |     east: (length, 0), | ||||||
|     south: (0, -length), |     south: (0, -length), | ||||||
|     west: (-length, 0) |     west: (-length, 0) | ||||||
|   ).at(side) |   ).at(side) | ||||||
|  |    | ||||||
|  |   let name-offset = ( | ||||||
|  |     north: (name-offset, length), | ||||||
|  |     east: (length, name-offset), | ||||||
|  |     south: (name-offset, -length), | ||||||
|  |     west: (-length, name-offset) | ||||||
|  |   ).at(side) | ||||||
|  |  | ||||||
|   draw.line( |   draw.line( | ||||||
|     port-id, |     port-id, | ||||||
|     (rel: offset, to: port-id) |     (rel: end-offset, to: port-id) | ||||||
|   ) |   ) | ||||||
|   if name != none { |   if name != none { | ||||||
|     let text-anchor = if vertical { |     let text-anchor = if vertical { | ||||||
| @@ -248,8 +395,8 @@ | |||||||
|       anchor: text-anchor, |       anchor: text-anchor, | ||||||
|       padding: 0.2em, |       padding: 0.2em, | ||||||
|       angle: if vertical {90deg} else {0deg}, |       angle: if vertical {90deg} else {0deg}, | ||||||
|       (rel: offset, to: port-id), |       (rel: name-offset, to: port-id), | ||||||
|       name |       name | ||||||
|     ) |     ) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| [package] | [package] | ||||||
| name = "circuiteria" | name = "circuiteria" | ||||||
| version = "0.0.2" | version = "0.2.0" | ||||||
| compiler = "0.11.0" | compiler = "0.13.0" | ||||||
| repository = "https://git.kb28.ch/HEL/circuiteria" | repository = "https://git.kb28.ch/HEL/circuiteria" | ||||||
| entrypoint = "src/lib.typ" | entrypoint = "src/lib.typ" | ||||||
| authors = [ | authors = [ | ||||||
| @@ -11,4 +11,4 @@ categories = [ "visualization" ] | |||||||
| license = "Apache-2.0" | license = "Apache-2.0" | ||||||
| description = "Drawing block circuits with Typst made easy, using CeTZ" | description = "Drawing block circuits with Typst made easy, using CeTZ" | ||||||
| keywords = [ "circuit", "block", "draw" ] | keywords = [ "circuit", "block", "draw" ] | ||||||
| exclude = [ "/gallery/*" ] | exclude = [ "gallery", "justfile", "doc" ] | ||||||