From 4930b53c84359ca4a494763d347d3ca9f53bbc36 Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Sat, 19 Apr 2025 15:10:09 +0200 Subject: [PATCH] reworked ports layout + adapted multiplexer --- gallery/target_api.pdf | Bin 7099 -> 7586 bytes gallery/target_api.typ | 7 +- src/elements/block.typ | 1 + src/elements/element.typ | 82 +++++++++++++--------- src/elements/multiplexer.typ | 82 +++++++++------------- src/elements/ports.typ | 127 ++++++++++++++++++++++++++--------- src/util.typ | 13 +--- src/wire.typ | 3 +- 8 files changed, 185 insertions(+), 130 deletions(-) diff --git a/gallery/target_api.pdf b/gallery/target_api.pdf index 840b7562c8c05e13e9a38b06c039a836eb3e0055..d1a960055e43e7ceac6a7fbbbfce8792de7e7f3a 100644 GIT binary patch delta 4025 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 diff --git a/gallery/target_api.typ b/gallery/target_api.typ index 6b810ef..b856434 100644 --- a/gallery/target_api.typ +++ b/gallery/target_api.typ @@ -17,7 +17,7 @@ wire.stub("PCBuf.CLK", name: "CLK") wire.stub("PCBuf.EN", name: "PCWrite") - /* + element.multiplexer( pos: ( 3, (align: "in0", with: "PCBuf.PC") @@ -25,9 +25,10 @@ size: (1, 2), id: "AdrSrc-MP", fill: util.colors.orange, - entries: 2 + entries: 2, + debug: (ports: true) ) - wire.wire( + /*wire.wire( "PCBuf.PC", "AdrSrc-MP.in0", id: "wPCBuf-InstDataMgr", diff --git a/src/elements/block.typ b/src/elements/block.typ index 58a1b6f..8df321d 100644 --- a/src/elements/block.typ +++ b/src/elements/block.typ @@ -19,6 +19,7 @@ #let block( ..args ) = element.elmt( + cls: "block", draw-shape: draw-shape, ..args ) \ No newline at end of file diff --git a/src/elements/element.typ b/src/elements/element.typ index d83c4b5..d38a824 100644 --- a/src/elements/element.typ +++ b/src/elements/element.typ @@ -1,5 +1,5 @@ #import "@preview/cetz:0.3.2": draw, coordinate, matrix, vector -#import "ports.typ": add-ports, add-port +#import "ports.typ": add-ports, add-port, get-port-pos, get-port-idx #import "../util.typ" #let find-port(ports, id) = { @@ -10,7 +10,7 @@ } } } - panic("Could not find port with id " + str(id)) + panic("Could not find port with id '" + str(id) + "'") } #let local-to-global(origin, u, v, points) = { @@ -42,7 +42,7 @@ return pos.at(axis) } -#let resolve-align(ctx, elmt, align, with, axis) = { +#let resolve-align(ctx, elmt, bounds, align, with, axis) = { let (align-side, i) = find-port(elmt.ports, align) let margins = (0%, 0%) if align-side in elmt.ports-margins { @@ -67,12 +67,12 @@ let used-len = len * used-pct / 100% start-margin = len * margins.at(0) / 100% - dl = used-len * (i + 1) / (elmt.ports.at(align-side).len() + 1) - - if not elmt.auto-ports { + //dl = used-len * (i + 1) / (elmt.ports.at(align-side).len() + 1) + dl = get-port-pos(elmt, bounds, align-side, align, get-port-idx(elmt, align, side: align-side)) + /*if not elmt.auto-ports { start-margin = 0 - dl = elmt.ports-pos.at(with)(len) - } + dl = elmt.ports-pos.at(align)(len) + }*/ } else if align-side == ortho-sides.first() { dl = 0 start-margin = 0 @@ -89,7 +89,7 @@ return with-pos.at(axis) - dl + start-margin } -#let resolve-coordinate(ctx, elmt, coord, axis) = { +#let resolve-coordinate(ctx, elmt, bounds, coord, axis) = { if type(coord) == dictionary { let offset = coord.at("offset", default: none) let from = coord.at("from", default: none) @@ -105,7 +105,7 @@ return resolve-offset(ctx, offset, from, axis) } else if none not in (align, with) { - return resolve-align(ctx, elmt, align, with, axis) + return resolve-align(ctx, elmt, bounds, align, with, axis) } else { panic("Dictionnary must either provide both 'offset' and 'from', or 'align' and 'with'") } @@ -116,11 +116,11 @@ return coord } -#let make-bounds(x, y, w, h) = { +#let make-bounds(elmt, x, y, w, h) = { let w2 = w / 2 let h2 = h / 2 - return ( + let bounds = ( bl: (x, y), tl: (x, y + h), tr: (x + w, y + h), @@ -131,6 +131,33 @@ l: (x, y + h2), r: (x + w, y + h2), ) + bounds += ( + sides: ( + north: (bounds.tl, bounds.tr), + south: (bounds.bl, bounds.br), + west: (bounds.tl, bounds.bl), + east: (bounds.tr, bounds.br), + ), + lengths: ( + north: (bounds.tr.at(0) - bounds.tl.at(0)), + south: (bounds.br.at(0) - bounds.bl.at(0)), + west: (bounds.tl.at(1) - bounds.bl.at(1)), + east: (bounds.tr.at(1) - bounds.br.at(1)), + ), + ports: (:) + ) + for (side, props) in bounds.sides.pairs() { + let props2 = props + if side in elmt.ports-margins { + let (pt0, pt1) = props + let margins = ports-margins.at(side) + a = (pt0, margins.at(0), pt1) + b = (pt0, 100% - margins.at(1), pt1) + props2 = (a, b) + } + bounds.ports.insert(side, props2) + } + return bounds } #let render(draw-shape, elmt) = draw.group(name: elmt.id, ctx => { @@ -140,10 +167,10 @@ let x = elmt.pos.first() let y = elmt.pos.last() - x = resolve-coordinate(ctx, elmt, x, 0) - y = resolve-coordinate(ctx, elmt, y, 1) - - let bounds = make-bounds(x, y, width, height) + let bounds = make-bounds(elmt, 0, 0, width, height) + x = resolve-coordinate(ctx, elmt, bounds, x, 0) + y = resolve-coordinate(ctx, elmt, bounds, y, 1) + bounds = make-bounds(elmt, x, y, width, height) // Workaround because CeTZ needs to have all draw functions in the body let func = {} @@ -171,15 +198,7 @@ ) } - if elmt.auto-ports { - add-ports( - elmt.id, - bounds, - elmt.ports, - elmt.ports-margins, - debug: elmt.debug.ports - ) - } + add-ports(elmt, bounds) }) /// Draws an element @@ -210,6 +229,7 @@ /// Supported fields include: /// - `ports`: if true, shows dots on all ports of the element #let elmt( + cls: "element", draw-shape: default-draw-shape, pre-process: default-pre-process, pos: (0, 0), @@ -221,11 +241,11 @@ fill: none, stroke: black + 1pt, id: auto, - auto-ports: true, - ports-y: (:), + ports-pos: auto, debug: ( ports: false - ) + ), + extra: (:) ) = { for (key, side-ports) in ports.pairs() { if type(side-ports) == str { @@ -249,6 +269,7 @@ return (( + cls: cls, id: id, draw: render.with(draw-shape), pre-process: pre-process, @@ -260,8 +281,7 @@ ports-margins: ports-margins, fill: fill, stroke: stroke, - auto-ports: auto-ports, - ports-y: ports-y, + ports-pos: ports-pos, debug: debug - ),) + ) + extra,) } diff --git a/src/elements/multiplexer.typ b/src/elements/multiplexer.typ index d7c29eb..8e55173 100644 --- a/src/elements/multiplexer.typ +++ b/src/elements/multiplexer.typ @@ -3,29 +3,29 @@ #import "element.typ" #import "ports.typ": add-port -#let draw-shape(id, tl, tr, br, bl, fill, stroke, h-ratio: 60%) = { - let margin = (100% - h-ratio) / 2 - let tr2 = (tr, margin, br) - let br2 = (br, margin, tr) - let f = draw.group(name: id, { +#let draw-shape(elmt, bounds) = { + let margin = (100% - elmt.l-ratio) / 2 + let tr2 = (bounds.tr, margin, bounds.br) + let br2 = (bounds.br, margin, bounds.tr) + let f = draw.group(name: elmt.id, { draw.merge-path( inset: 0.5em, - fill: fill, - stroke: stroke, + fill: elmt.fill, + stroke: elmt.stroke, close: true, - draw.line(tl, tr2, br2, bl) + draw.line(bounds.tl, tr2, br2, bounds.bl) ) - draw.anchor("north", (tl, 50%, tr2)) - draw.anchor("south", (bl, 50%, br2)) - draw.anchor("west", (tl, 50%, bl)) + draw.anchor("north", (bounds.tl, 50%, tr2)) + draw.anchor("south", (bounds.bl, 50%, br2)) + draw.anchor("west", (bounds.tl, 50%, bounds.bl)) draw.anchor("east", (tr2, 50%, br2)) - draw.anchor("north-west", tl) + draw.anchor("north-west", bounds.tl) draw.anchor("north-east", tr2) draw.anchor("south-east", br2) - draw.anchor("south-west", bl) + draw.anchor("south-west", bounds.bl) }) - return (f, tl, tr, br, bl) + return (f, bounds) } /// Draws a multiplexer @@ -35,64 +35,44 @@ /// - entries (int, array): If it is an integer, it defines the number of input ports (automatically named with their binary index). If it is an array of strings, it defines the name of each input. /// - h-ratio (ratio): The height ratio of the right side relative to the full height #let multiplexer( - x: none, - y: none, - w: none, - h: none, - name: none, - name-anchor: "center", entries: 2, - h-ratio: 60%, - fill: none, - stroke: black + 1pt, - id: "", - debug: ( - ports: false - ) + l-ratio: 60%, + ..args ) = { - let ports = () - let ports-y = ( - out: (h) => {h * 0.5} + let in-ports = () + let ports-pos = ( + "east": auto, ) if (type(entries) == int) { let nbits = calc.ceil(calc.log(entries, base: 2)) for i in range(entries) { let bits = util.lpad(str(i, base: 2), nbits) - ports.push((id: "in" + str(i), name: bits)) + in-ports.push((id: "in" + str(i), name: bits)) } } else { for (i, port) in entries.enumerate() { - ports.push((id: "in" + str(i), name: port)) + in-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}) - } + let n = in-ports.len() + ports-pos.insert("west", (l, i) => {l * (i + 0.5) / n}) element.elmt( - draw-shape: draw-shape.with(h-ratio: h-ratio), - x: x, - y: y, - w: w, - h: h, - name: name, - name-anchor: name-anchor, - ports: (west: ports, east: ((id: "out"),)), - fill: fill, - stroke: stroke, - id: id, - ports-y: ports-y, - auto-ports: false, - debug: debug + cls: "multiplexer", + draw-shape: draw-shape, + ports: (west: in-ports, east: ((id: "out"),)), + ports-pos: ports-pos, + extra: (l-ratio: l-ratio), + ..args ) + /* 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")) + */ } \ No newline at end of file diff --git a/src/elements/ports.typ b/src/elements/ports.typ index 66d1f0c..eecd300 100644 --- a/src/elements/ports.typ +++ b/src/elements/ports.typ @@ -1,6 +1,74 @@ #import "@preview/cetz:0.3.2": draw #import "../util.typ": rotate-anchor +#let get-port-side(elmt, port) = { + for (side, ports) in elmt.ports { + for p in ports { + if p.id == port { + return side + } + } + } + panic("Unknown port " + port + " on element " + element.id) +} + +#let get-port-idx(elmt, port, side: auto) = { + if side == auto { + side = get-port-side(elmt, port) + } + assert( + side in elmt.ports, + message: "No ports on side '" + side + "' of element '" + elmt.id + "'" + ) + let i = elmt.ports.at(side).position(p => p.id == port) + assert( + i != none, + message: "Could not find port '" + port + "' on side '" + side + "' of element '" + elmt.id + "'" + ) + return i +} + +#let get-port-pos(elmt, bounds, side, port, port-i) = { + let (pt0, pt1) = bounds.ports.at(side) + let side-len = if side in ("north", "south") { + pt1.at(0) - pt0.at(0) + } else { + pt0.at(1) - pt1.at(1) + } + + let offset = if ( + elmt.ports-pos == auto or + elmt.ports-pos.at(side, default: auto) == auto + ) { + let space = 100% / (elmt.ports.at(side, default: ()).len() + 1) + (port-i + 1) * space + } else { + assert( + side in elmt.ports-pos, + message: "Could not reliably compute port position (missing side)" + ) + let side-pos = elmt.ports-pos.at(side) + if type(side-pos) == function { + (side-pos)(side-len, port-i) + } else if type(side-pos) == array { + (side-pos.at(i))(side-len) + } else if type(side-pos) == dictionary { + assert( + port in side-pos, + message: "Could not reliably compute port position (missing port)" + ) + (side-pos.at(port))(side-len) + } else { + panic("Could not reliably compute port position (invalid type)") + } + } + + if type(offset) == ratio { + offset = offset * side-len / 100% + } + return offset +} + #let add-port( elmt-id, side, port, pos, prev: none, @@ -54,46 +122,41 @@ } #let add-ports( - elmt-id, - bounds, - ports, - ports-margins, - debug: false + elmt, + bounds ) = { - let sides = ( - "north": (bounds.tl, bounds.tr), - "east": (bounds.tr, bounds.br), - "south": (bounds.bl, bounds.br), - "west": (bounds.tl, bounds.bl) - ) + let debug = elmt.debug.ports - if type(ports) != dictionary { + if type(elmt.ports) != dictionary { return } - for (side, props) in sides { - let side-ports = ports.at(side, default: ()) + for (side, props) in bounds.ports { + let side-ports = elmt.ports.at(side, default: ()) let space = 100% / (side-ports.len() + 1) - + + let (pt0, pt1) = props + let side-len = if side in ("north", "south") { + pt1.at(0) - pt0.at(0) + } else { + pt0.at(1) - pt1.at(1) + } for (i, port) in side-ports.enumerate() { - let pct = (i + 1) * space - let pt0 = props.at(0) - let pt1 = props.at(1) + let offset = get-port-pos(elmt, bounds, side, port, i) - if side in ports-margins { - let (a, b) = (pt0, pt1) - let margins = ports-margins.at(side) - a = (pt0, margins.at(0), pt1) - b = (pt0, 100% - margins.at(1), pt1) - pt0 = a - pt1 = b + let pos = (pt0, offset, pt1) + let offset-prev = if type(offset) == ratio { + offset - space / 2 + } else { + offset - space * side-len / 200% } - - let pos = (pt0, pct, pt1) - let pct-prev = (i + 0.5) * space - let pct-next = (i + 1.5) * space - let pos-prev = (pt0, pct-prev, pt1) - let pos-next = (pt0, pct-next, pt1) + let offset-next = if type(offset) == ratio { + offset + space / 2 + } else { + offset + space * side-len / 200% + } + let pos-prev = (pt0, offset-prev, pt1) + let pos-next = (pt0, offset-next, pt1) if port.at("small", default: false) { pos-prev = (pos, 4pt, pt0) @@ -101,7 +164,7 @@ } add-port( - elmt-id, + elmt.id, side, port, pos, diff --git a/src/util.typ b/src/util.typ index 037ae67..a444434 100644 --- a/src/util.typ +++ b/src/util.typ @@ -73,15 +73,4 @@ #let valid-anchors = ( "center", "north", "east", "west", "south", "north-east", "north-west", "south-east", "south-west" -) - -#let get-port-side(element, port) = { - for (side, ports) in element.ports { - for p in ports { - if p.id == port { - return side - } - } - } - panic("Unknown port " + port + " on element " + element.id) -} \ No newline at end of file +) \ No newline at end of file diff --git a/src/wire.typ b/src/wire.typ index 661faed..899e4c1 100644 --- a/src/wire.typ +++ b/src/wire.typ @@ -1,5 +1,6 @@ #import "@preview/cetz:0.3.2": draw, coordinate -#import "util.typ": opposite-anchor, get-port-side +#import "util.typ": opposite-anchor +#import "elements/ports.typ": get-port-side #import "elements/element.typ" /// List of valid wire styles