forked from HEL/circuiteria
Introduces a new "s-shape" wire style connecting two ports on opposite cardinal sides (east<->west or north<->south) via 5 segments joined at 4 corners (u1-start, u1-end, u2-start, u2-end). The axis is auto-detected from port anchors; when both endpoints share the same perpendicular coordinate (single-block loopback) `s-ratio-mid` is reinterpreted as an absolute signed offset so the crossbar can still be placed above or below the endpoints. Supports anchor-based placement via the `s-at-*` family of parameters (s-at-1, s-at-mid, s-at-2) analogous to `zigzag-at` and `u-at`.
399 lines
12 KiB
Typst
399 lines
12 KiB
Typst
#import "example.typ": example
|
|
|
|
#let alu = example(```
|
|
element.alu(x: 0, y: 0, w: 1, h: 2, id: "alu")
|
|
wire.stub("alu-port-in1", "west")
|
|
wire.stub("alu-port-in2", "west")
|
|
wire.stub("alu-port-out", "east")
|
|
```)
|
|
|
|
#let block = example(```
|
|
element.block(
|
|
x: 0, y: 0, w: 2, h: 2, id: "block",
|
|
ports: (
|
|
north: ((id: "clk", clock: true),),
|
|
west: ((id: "in1", name: "A"),
|
|
(id: "in2", name: "B")),
|
|
east: ((id: "out", name: "C"),)
|
|
)
|
|
)
|
|
wire.stub("block-port-clk", "north")
|
|
wire.stub("block-port-in1", "west")
|
|
wire.stub("block-port-in2", "west")
|
|
wire.stub("block-port-out", "east")
|
|
```)
|
|
|
|
#let extender = example(```
|
|
element.extender(
|
|
x: 0, y: 0, w: 3, h: 1,
|
|
id: "extender"
|
|
)
|
|
wire.stub("extender-port-in", "west")
|
|
wire.stub("extender-port-out", "east")
|
|
```)
|
|
|
|
#let multiplexer = example(```
|
|
element.multiplexer(
|
|
x: 0, y: 0, w: 1, h: 3,
|
|
id: "multiplexer",
|
|
entries: 3
|
|
)
|
|
wire.stub("multiplexer.north", "north")
|
|
wire.stub("multiplexer-port-out", "east")
|
|
|
|
element.multiplexer(
|
|
x: 0, y: -4, w: 1, h: 3,
|
|
id: "multiplexer2",
|
|
entries: ("A", "B", "C")
|
|
)
|
|
wire.stub("multiplexer2.south", "south")
|
|
wire.stub("multiplexer2-port-out", "east")
|
|
|
|
for i in range(3) {
|
|
wire.stub("multiplexer-port-in" + str(i), "west")
|
|
wire.stub("multiplexer2-port-in" + str(i), "west")
|
|
}
|
|
```)
|
|
|
|
#let wires = example(```
|
|
for i in range(5) {
|
|
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.content((i * 3 + 1, -1), raw(wire.wire-styles.at(i)))
|
|
}
|
|
wire.wire("w1", ("p0", "p1"), style: "direct")
|
|
wire.wire("w2", ("p2", "p3"), style: "zigzag")
|
|
wire.wire("w3", ("p4", "p5"), style: "dodge",
|
|
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"))
|
|
wire.wire("w5", ("p8", "p9"), style: "u-shape",
|
|
u-side: "east", u-depth: 0.5)
|
|
```, vertical: true)
|
|
|
|
#let zigzag-at = example(
|
|
```
|
|
// `zigzag-at` places the middle bend of a zigzag wire
|
|
// on the axis of a referenced anchor, overriding
|
|
// `zigzag-ratio`.
|
|
element.block(x: 0, y: 0, w: 1.5, h: 1.5, id: "src",
|
|
ports: (east: ((id: "o", name: "O"),),))
|
|
element.block(x: 3, y: -1.2, w: 1, h: 1, id: "ref",
|
|
fill: util.colors.pink,
|
|
ports: (west: ((id: "p", name: "R"),),))
|
|
element.block(x: 5.5, y: -2, w: 1.5, h: 1.5, id: "dst",
|
|
ports: (west: ((id: "i", name: "I"),),))
|
|
// String form: anchor name of a port.
|
|
wire.wire("w1", ("src-port-o", "dst-port-i"),
|
|
style: "zigzag",
|
|
zigzag-at: "ref-port-p")
|
|
// Ergonomic offset: shift 8pt right of ref.east.
|
|
wire.wire("w2", ("src-port-o", "dst-port-i"),
|
|
style: "zigzag",
|
|
zigzag-at: (rel: 8pt, to: "ref.east"))
|
|
```,
|
|
vertical: true,
|
|
)
|
|
|
|
#let u-shape-wire = example(
|
|
```
|
|
// east <-> east (u-side auto-detected)
|
|
element.block(x: 0, y: 0, w: 1.5, h: 1.5, id: "eA",
|
|
fill: util.colors.orange,
|
|
ports: (east: ((id: "out"),)))
|
|
element.block(x: 0.5, y: -2.5, w: 1.5, h: 1.5, id: "eB",
|
|
fill: util.colors.orange,
|
|
ports: (east: ((id: "out"),)))
|
|
wire.wire("uEE", ("eA-port-out", "eB-port-out"),
|
|
style: "u-shape", u-depth: 0.5)
|
|
|
|
// west <-> west (auto-detected)
|
|
element.block(x: 6, y: 0, w: 1.5, h: 1.5, id: "wA",
|
|
fill: util.colors.yellow,
|
|
ports: (west: ((id: "in"),)))
|
|
element.block(x: 6.5, y: -2.5, w: 1.5, h: 1.5, id: "wB",
|
|
fill: util.colors.yellow,
|
|
ports: (west: ((id: "in"),)))
|
|
wire.wire("uWW", ("wA-port-in", "wB-port-in"),
|
|
style: "u-shape", u-depth: 0.5)
|
|
|
|
// north <-> north (auto-detected)
|
|
element.block(x: 10, y: -3, w: 1.5, h: 1.5, id: "nA",
|
|
fill: util.colors.green,
|
|
ports: (north: ((id: "out"),)))
|
|
element.block(x: 12.5, y: -2.5, w: 1.5, h: 1.5, id: "nB",
|
|
fill: util.colors.green,
|
|
ports: (north: ((id: "out"),)))
|
|
wire.wire("uNN", ("nA-port-out", "nB-port-out"),
|
|
style: "u-shape", u-depth: 0.5)
|
|
|
|
// south <-> south with explicit u-side override
|
|
element.block(x: 16, y: -3, w: 1.5, h: 1.5, id: "sA",
|
|
fill: util.colors.pink,
|
|
ports: (south: ((id: "out"),)))
|
|
element.block(x: 18.5, y: -3.5, w: 1.5, h: 1.5, id: "sB",
|
|
fill: util.colors.pink,
|
|
ports: (south: ((id: "out"),)))
|
|
wire.wire("uSS", ("sA-port-out", "sB-port-out"),
|
|
style: "u-shape", u-side: "south", u-depth: 0.5)
|
|
```,
|
|
vertical: true,
|
|
)
|
|
|
|
#let u-at = example(
|
|
```
|
|
// `u-at` places the U-bend crossbar on the axis
|
|
// of a referenced anchor, overriding `u-depth`.
|
|
element.block(x: 0, y: 0, w: 1.5, h: 1.5, id: "eA",
|
|
fill: util.colors.orange,
|
|
ports: (east: ((id: "o1"), (id: "o2"))))
|
|
element.block(x: 0, y: -3.5, w: 1.5, h: 1.5, id: "eB",
|
|
fill: util.colors.orange,
|
|
ports: (east: ((id: "i1"), (id: "i2"))))
|
|
element.block(x: 4, y: -2.25, w: 0.6, h: 0.6, id: "ref",
|
|
fill: util.colors.pink)
|
|
// Align one U crossbar with ref.east.
|
|
wire.wire("u1", ("eA-port-o1", "eB-port-i1"),
|
|
style: "u-shape",
|
|
u-at: "ref.east")
|
|
// Ergonomic scalar offset: 1 right of ref.east.
|
|
wire.wire("u2", ("eA-port-o2", "eB-port-i2"),
|
|
style: "u-shape", color: util.colors.blue,
|
|
u-at: (rel: 1, to: "ref.east"))
|
|
```,
|
|
vertical: true,
|
|
)
|
|
|
|
#let s-shape-wire = example(
|
|
```
|
|
// `s-shape` connects endpoints on opposite sides
|
|
// via 5 segments joined at 4 corners (u1-start,
|
|
// u1-end, u2-start, u2-end). Auto-detects axis
|
|
// from port anchors.
|
|
element.block(x: 0, y: 0, w: 1, h: 1, id: "A",
|
|
fill: util.colors.orange,
|
|
ports: (west: ((id: "out"),)))
|
|
element.block(x: 2.5, y: -1.75, w: 1, h: 1, id: "B",
|
|
fill: util.colors.orange,
|
|
ports: (east: ((id: "in"),)))
|
|
wire.wire("s1", ("A-port-out", "B-port-in"),
|
|
style: "s-shape")
|
|
|
|
// Anchor-based override of the crossbar position.
|
|
element.block(x: 5.5, y: 0, w: 1, h: 1, id: "C",
|
|
fill: util.colors.yellow,
|
|
ports: (west: ((id: "out"),)))
|
|
element.block(x: 8.5, y: -1.75, w: 1, h: 1, id: "D",
|
|
fill: util.colors.yellow,
|
|
ports: (east: ((id: "in"),)))
|
|
element.block(x: 7, y: -0.7, w: 0.5, h: 0.5, id: "ref",
|
|
fill: util.colors.pink)
|
|
wire.wire("s2", ("C-port-out", "D-port-in"),
|
|
style: "s-shape",
|
|
s-at-mid: "ref.south")
|
|
|
|
// C-shape degeneration: crossbar outside the
|
|
// endpoint span (s-ratio-mid > 100%).
|
|
element.block(x: 11, y: 0, w: 1, h: 1, id: "E",
|
|
fill: util.colors.green,
|
|
ports: (west: ((id: "out"),)))
|
|
element.block(x: 14, y: -0.75, w: 1, h: 1, id: "F",
|
|
fill: util.colors.green,
|
|
ports: (east: ((id: "in"),)))
|
|
wire.wire("s3", ("E-port-out", "F-port-in"),
|
|
style: "s-shape",
|
|
s-ratio-mid: 200%)
|
|
```,
|
|
vertical: true,
|
|
)
|
|
|
|
#let s-shape-wire-vertical = example(
|
|
```
|
|
// `s-shape` on the vertical axis (north <-> south):
|
|
// seg1 and seg5 are vertical, the crossbar is
|
|
// vertical, and the two horizontals connect them.
|
|
element.block(x: 0, y: 0, w: 1, h: 1, id: "A",
|
|
fill: util.colors.orange,
|
|
ports: (north: ((id: "out"),)))
|
|
element.block(x: 2, y: -3, w: 1, h: 1, id: "B",
|
|
fill: util.colors.orange,
|
|
ports: (south: ((id: "in"),)))
|
|
wire.wire("s1", ("A-port-out", "B-port-in"),
|
|
style: "s-shape")
|
|
|
|
// Anchor-based override of the vertical crossbar.
|
|
element.block(x: 5, y: 0, w: 1, h: 1, id: "C",
|
|
fill: util.colors.yellow,
|
|
ports: (north: ((id: "out"),)))
|
|
element.block(x: 7, y: -3, w: 1, h: 1, id: "D",
|
|
fill: util.colors.yellow,
|
|
ports: (south: ((id: "in"),)))
|
|
element.block(x: 6.25, y: -1.5, w: 0.5, h: 0.5, id: "vref",
|
|
fill: util.colors.pink)
|
|
wire.wire("s2", ("C-port-out", "D-port-in"),
|
|
style: "s-shape",
|
|
s-at-mid: "vref.east")
|
|
```,
|
|
vertical: true,
|
|
)
|
|
|
|
#let s-shape-wire-loopback = example(
|
|
```
|
|
// `s-shape` looping back on a single block that
|
|
// has a west output and an east input. The wire
|
|
// exits west, wraps around below the block via a
|
|
// C-shape, and enters from the east.
|
|
//
|
|
// Since both endpoints share the same y, the
|
|
// crossbar's position is set by `s-ratio-mid`
|
|
// as an absolute distance below the endpoint y.
|
|
element.block(x: 2, y: 0, w: 1.5, h: 1.5, id: "A",
|
|
fill: util.colors.orange,
|
|
ports: (
|
|
west: ((id: "out"),),
|
|
east: ((id: "in"),),
|
|
))
|
|
wire.wire("s1", ("A-port-out", "A-port-in"),
|
|
style: "s-shape",
|
|
s-depth-1: 1.5, s-depth-2: 1.5,
|
|
s-ratio-mid: 150%)
|
|
|
|
// Negative `s-ratio-mid` routes the crossbar the
|
|
// other way (above the block).
|
|
element.block(x: 7, y: 0, w: 1.5, h: 1.5, id: "B",
|
|
fill: util.colors.yellow,
|
|
ports: (
|
|
west: ((id: "out"),),
|
|
east: ((id: "in"),),
|
|
))
|
|
wire.wire("s2", ("B-port-out", "B-port-in"),
|
|
style: "s-shape",
|
|
s-depth-1: 1.5, s-depth-2: 1.5,
|
|
s-ratio-mid: -150%)
|
|
```,
|
|
vertical: true,
|
|
)
|
|
|
|
#let stub = example(```
|
|
draw.circle((0, 0), radius: .1, name: "p")
|
|
wire.stub("p", "north", name: "north", length: 1)
|
|
wire.stub("p", "east", name: "east", vertical: true)
|
|
wire.stub("p", "south", name: "south", length: 15pt)
|
|
wire.stub("p", "west", name: "west", length: 3em)
|
|
```)
|
|
|
|
#let gate-and = example(```
|
|
gates.gate-and(x: 0, y: 0, w: 1.5, h: 1.5)
|
|
gates.gate-and(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all")
|
|
```, vertical: true)
|
|
|
|
#let gate-nand = example(```
|
|
gates.gate-nand(x: 0, y: 0, w: 1.5, h: 1.5)
|
|
gates.gate-nand(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all")
|
|
```, vertical: true)
|
|
|
|
#let gate-buf = example(```
|
|
gates.gate-buf(x: 0, y: 0, w: 1.5, h: 1.5)
|
|
gates.gate-buf(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all")
|
|
```, vertical: true)
|
|
|
|
#let gate-not = example(```
|
|
gates.gate-not(x: 0, y: 0, w: 1.5, h: 1.5)
|
|
gates.gate-not(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all")
|
|
```, vertical: true)
|
|
|
|
#let gate-or = example(```
|
|
gates.gate-or(x: 0, y: 0, w: 1.5, h: 1.5)
|
|
gates.gate-or(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all")
|
|
```, vertical: true)
|
|
|
|
#let gate-nor = example(```
|
|
gates.gate-nor(x: 0, y: 0, w: 1.5, h: 1.5)
|
|
gates.gate-nor(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all")
|
|
```, vertical: true)
|
|
|
|
#let gate-xor = example(```
|
|
gates.gate-xor(x: 0, y: 0, w: 1.5, h: 1.5)
|
|
gates.gate-xor(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all")
|
|
```, vertical: true)
|
|
|
|
#let gate-xnor = example(```
|
|
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")
|
|
```, 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")
|
|
```)
|