forked from HEL/circuiteria
Introduces wire.breakout: a 45° diagonal line of configurable length (default 1em) that starts at a given (x, y) and exposes a port anchor <id>-port-<id> at its end point so wires can attach to it as if it were a block port. A synthesized <id>.center anchor is placed opposite the configured port-side so the side the port faces can be deduced from the anchor. - x/y accept number, (rel:, to:) and (from:) forms; (from:) sets the start point to the referenced anchor's coordinate. - direction: one of north-east/north-west/south-east/south-west. - Optional label positioned via name-pos (NE/NW/SE/SW); when name-pos is opposite to direction, the label falls back to the start point so it never covers the diagonal line. Label padding matches wire.wire (3pt). Also adds three examples (breakout, breakout-label, breakout-wire) in doc/examples.typ referenced from the docstring so tidy auto-renders them in the manual, and a gallery entry (gallery/test_breakout.typ) demonstrating orthogonal bus fan-out with breakouts in all four directions.
270 lines
8.0 KiB
Typst
270 lines
8.0 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(4) {
|
||
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"))
|
||
|
||
```, 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 breakout = example(```
|
||
// 16 breakouts: 4 directions × 4 label positions, laid out
|
||
// two per row so the labels have room to breathe.
|
||
let dirs = ("north-east", "north-west", "south-east", "south-west")
|
||
let poss = ("north-east", "north-west", "south-east", "south-west")
|
||
let short = (
|
||
"north-east": "NE", "north-west": "NW",
|
||
"south-east": "SE", "south-west": "SW",
|
||
)
|
||
let cols = 2
|
||
let dx = 5
|
||
let dy = 2
|
||
for (i, dir) in dirs.enumerate() {
|
||
for (j, pos) in poss.enumerate() {
|
||
let n = i * poss.len() + j
|
||
let r = calc.floor(n / cols)
|
||
let c = calc.rem(n, cols)
|
||
draw.circle((c * dx, -r * dy), radius: .05)
|
||
wire.breakout("b" + str(n),
|
||
x: c * dx, y: -r * dy,
|
||
direction: dir,
|
||
port-side: if dir.ends-with("east") { "west" } else { "east" },
|
||
name: short.at(dir) + "/" + short.at(pos),
|
||
name-pos: pos)
|
||
}
|
||
}
|
||
```)
|
||
|
||
#let breakout-label = example(```
|
||
// name-pos matches direction → label sits at the end point.
|
||
wire.breakout("b1", x: 0, y: 0, direction: "north-east",
|
||
port-side: "east",
|
||
name: "at end", name-pos: "north-east")
|
||
|
||
// name-pos opposite to direction → label would cover the line, so
|
||
// it falls back to the start point.
|
||
wire.breakout("b2", x: 4, y: 0, direction: "north-east",
|
||
port-side: "east",
|
||
name: "at start", name-pos: "south-west")
|
||
```, vertical: true)
|
||
|
||
#let breakout-wire = example(```
|
||
// Bus fan-out: a horizontal wire from the left block to the lower
|
||
// right block carries the full 10-bit bus. A breakout in the middle
|
||
// of that wire taps bits [9:5] and routes them to the upper right
|
||
// block via an L-shaped zigzag (up, then right).
|
||
element.block(x: 0, y: 0, w: 2, h: 2, id: "src",
|
||
fill: util.colors.blue,
|
||
ports: (east: ((id: "out"),)))
|
||
element.block(x: 6, y: 0, w: 2, h: 2, id: "dstL",
|
||
fill: util.colors.green,
|
||
ports: (west: ((id: "in"),)))
|
||
element.block(x: 6, y: 4, w: 2, h: 2, id: "dstU",
|
||
fill: util.colors.orange,
|
||
ports: (west: ((id: "in"),)))
|
||
|
||
// Full bus wire, labelled "[9:0]" on the left.
|
||
wire.wire("wbus", ("src-port-out", "dstL-port-in"),
|
||
name: "[9:0]", name-pos: "start")
|
||
|
||
// Breakout tapped from the midpoint of the bus.
|
||
wire.breakout("tap",
|
||
x: (rel: 2, to: "src-port-out"),
|
||
y: (from: "src-port-out"),
|
||
direction: "north-east",
|
||
port-side: "west",
|
||
name: "[9:5]", name-pos: "north-east")
|
||
|
||
// L-shaped wire from the breakout up and then right to the upper
|
||
// block's input.
|
||
wire.wire("wtap", ("tap-port-tap", "dstU-port-in"),
|
||
style: "zigzag", zigzag-dir: "horizontal",
|
||
zigzag-ratio: 100%)
|
||
```)
|
||
|
||
#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")
|
||
```)
|