Compare commits

...

2 Commits

Author SHA1 Message Date
86d9122740
added groups 2024-05-18 13:06:57 +02:00
5bd3dd8111
added more customization options for wires 2024-05-18 12:39:47 +02:00
10 changed files with 374 additions and 16 deletions

View File

@ -114,3 +114,30 @@ gates.gate-xor(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all")
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 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")
```)

Binary file not shown.

BIN
gallery/test4.pdf Normal file

Binary file not shown.

217
gallery/test4.typ Normal file
View File

@ -0,0 +1,217 @@
#import "@preview/cetz:0.2.2": draw
#import "../src/lib.typ": *
#set page(flipped: true)
#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),
(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),
(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)
})
wire.wire(
"w-dp-clk",
("dp-port-clk", (-1, 4.2)),
style: "zigzag",
zigzag-dir: "horizontal",
zigzag-ratio: 100%
)
draw.content("w-dp-clk.end", "clk", anchor: "east", padding: 3pt)
wire.wire(
"w-dp-rst",
("dp-port-rst", (horizontal: (-1, 0), vertical: ()))
)
draw.content("w-dp-rst.end", "rst", anchor: "east", padding: 3pt)
})

Binary file not shown.

View File

@ -158,7 +158,8 @@ Simply import #link("src/lib.typ") and call the `circuit` function:
read("src/elements/alu.typ") + "\n" +
read("src/elements/block.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",
scope: (
element: element,

View File

@ -11,3 +11,5 @@
#import "elements/logic/or.typ": gate-or, gate-nor
#import "elements/logic/xor.typ": gate-xor, gate-xnor
#import "elements/logic/buf.typ": gate-buf, gate-not
#import "elements/group.typ": group

View File

@ -33,7 +33,7 @@
/// - `name` (`str`): Optional name displayed *in* the block
/// - `clock` (`bool`): Whether it is a clock port (triangle symbol)
/// - `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
/// - stroke (stroke): Border stroke
/// - id (str): The block id (for future reference)

80
src/elements/group.typ Normal file
View File

@ -0,0 +1,80 @@
#import "@preview/cetz:0.2.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
}

View File

@ -7,8 +7,8 @@
#let signal-width = 1pt
#let bus-width = 1.5pt
#let intersection(pt) = {
draw.circle(pt, radius: .2, stroke: none, fill: black)
#let intersection(pt, radius: .2, fill: black) = {
draw.circle(pt, radius: radius, stroke: none, fill: fill)
}
#let get-direct-wire(pts) = {
@ -19,17 +19,26 @@
return (pts, anchors)
}
#let get-zigzag-wire(pts, ratio) = {
#let get-zigzag-wire(pts, ratio, dir) = {
let start = pts.first()
let end = pts.last()
let mid = (start, ratio, end)
let points = (
let points = if dir == "vertical" {
(
start,
(horizontal: mid, vertical: ()),
(horizontal: (), vertical: end),
end
)
} else {
(
start,
(horizontal: (), vertical: mid),
(horizontal: end, vertical: ()),
end
)
}
let anchors = (
"start": start,
"zig": points.at(1),
@ -102,7 +111,10 @@
/// - 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)
/// - 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-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-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")
@ -116,7 +128,10 @@
dashed: false,
style: "direct",
reverse: false,
directed: false,
rotate-name: true,
zigzag-ratio: 50%,
zigzag-dir: "vertical",
dodge-y: 0,
dodge-sides: ("east", "west"),
dodge-margins: (5%, 5%)
@ -144,7 +159,7 @@
(points, anchors) = get-direct-wire(pts)
} 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" {
(points, anchors) = get-dodge-wire(
@ -156,8 +171,12 @@
)
}
let mark = (fill: color)
if directed {
mark = (end: ">", fill: color)
}
draw.group(name: id, {
draw.line(..points, stroke: stroke)
draw.line(..points, stroke: stroke, mark: mark)
for (anchor-name, anchor-pos) in anchors {
draw.anchor(anchor-name, anchor-pos)
}
@ -165,8 +184,20 @@
let first-pt = id + ".start"
let last-pt = id + ".end"
let first-pos = points.first()
let second-pos = points.at(1)
if reverse {
(first-pt, last-pt) = (last-pt, first-pt)
(first-pos, second-pos) = (second-pos, first-pos)
}
let angle = 0deg
if rotate-name {
(ctx, first-pos) = coordinate.resolve(ctx, first-pos)
(ctx, second-pos) = coordinate.resolve(ctx, second-pos)
let (x1, y1, _) = first-pos
let (x2, y2, _) = second-pos
angle = calc.atan2(x2 - x1, y2 - y1)
}
if name != none {
@ -199,7 +230,7 @@
anchor = "south-east"
}
draw.content(point, anchor: anchor, padding: 3pt, name)
draw.content(point, anchor: anchor, padding: 3pt, angle: angle, name)
}
}