diff --git a/main.typ b/main.typ deleted file mode 100644 index 82993b0..0000000 --- a/main.typ +++ /dev/null @@ -1,1039 +0,0 @@ -#import "@preview/cetz:0.2.2": canvas, draw, coordinate, vector - -#set text(font: "Source Sans Pro") -#set page(flipped: true) - -#let diag-colors = ( - orange: rgb(245, 180, 147), - yellow: rgb(250, 225, 127), - green: rgb(127, 200, 172), - pink: rgb(236, 127, 178), - purple: rgb(189, 151, 255) -) - -#let lpad(s, len) = { - let res = "0" * len + s - return res.slice(-len) -} - -#let opposite-anchor(anchor) = { - return ( - north: "south", - east: "west", - south: "north", - west: "east", - - north-west: "south-east", - north-east: "south-west", - south-east: "north-west", - south-west: "north-east" - ).at(anchor) -} - -#let diag-port-stub(port-id, side, name: none, vertical: false, length: 1em) = { - - let offset = ( - north: (0, length), - east: (length, 0), - south: (0, -length), - west: (-length, 0) - ).at(side) - draw.line( - port-id, - (rel: offset, to: port-id) - ) - if name != none { - let text-anchor = if vertical { - ( - "north": "west", - "south": "east", - "west": "south", - "east": "north" - ).at(side) - } else { opposite-anchor(side) } - draw.content( - anchor: text-anchor, - padding: 0.2em, - angle: if vertical {90deg} else {0deg}, - (rel: offset, to: port-id), - name - ) - } -} - -#let diag-port( - elmt-id, - side, - port, - pos, - prev: none, - next: none, - debug: false -) = { - let name = port.at("name", default: "") - let name-rotate = port.at("vertical", default: false) - - if (port.at("clock", default: false)) { - if prev == none or next == none { - panic("Clock port must have previous and next positions") - } - - let offset - if (side == "north") { - offset = (0, -1em) - } else if (side == "east") { - offset = (-1em, 0) - } else if (side == "south") { - offset = (0, 1em) - } else if (side == "west") { - offset = (1em, 0) - } - let pos1 = (rel: offset, to: pos) - - // TODO: use context or vectors to have the height relative to the width - draw.line( - prev, pos1, next - ) - } - draw.content( - pos, - anchor: if name-rotate { - ( - "north": "east", - "south": "west", - "west": "north", - "east": "south" - ).at(side) - } else {side}, - padding: 2pt, - angle: if name-rotate {90deg} else {0deg}, - name - ) - if debug { - draw.circle( - pos, - name: elmt-id + "-port-" + port.at("id"), - radius: .1, - stroke: none, - fill: red - ) - - } else { - draw.hide(draw.circle( - pos, - radius: 0, - stroke: none, - name: elmt-id + "-port-" + port.at("id") - )) - } -} - -#let diag-ports( - elmt-id, - tl, tr, br, bl, - ports, - ports-margins, - debug: false -) = { - let sides = ( - "north": (tl, tr), - "east": (tr, br), - "south": (bl, br), - "west": (tl, bl) - ) - for (side, props) in sides { - let side-ports = ports.at(side, default: ()) - for (i, port) in side-ports.enumerate() { - let pct = (i + 1) * 100% / (side-ports.len() + 1) - let pt0 = props.at(0) - let pt1 = props.at(1) - - 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, pct, pt1) - - let pct-prev = (i + 0.5) * 100% / (side-ports.len() + 1) - let pct-next = (i + 1.5) * 100% / (side-ports.len() + 1) - let pos-prev = (pt0, pct-prev, pt1) - let pos-next = (pt0, pct-next, pt1) - diag-port( - elmt-id, - side, - port, - pos, - prev: pos-prev, - next: pos-next, - debug: debug - ) - /* - - let name = port.at("name", default: "") - let name-rotate = port.at("vertical", default: false) - - if (port.at("clock", default: false)) { - let pct-prev = (i + 0.5) * 100% / (side-ports.len() + 1) - let pct-next = (i + 1.5) * 100% / (side-ports.len() + 1) - let pos0 = (pt0, pct-prev, pt1) - let offset - if (side == "north") { - offset = (0, -1em) - } else if (side == "east") { - offset = (-1em, 0) - } else if (side == "south") { - offset = (0, 1em) - } else if (side == "west") { - offset = (1em, 0) - } - let pos1 = (rel: offset, to: pos) - let pos2 = (pt0, pct-next, pt1) - - // TODO: use context or vectors to have the height relative to the width - draw.line( - pos0, pos1, pos2 - ) - } - draw.content( - pos, - anchor: if name-rotate { - ( - "north": "east", - "south": "west", - "west": "north", - "east": "south" - ).at(side) - } else {side}, - padding: 2pt, - angle: if name-rotate {90deg} else {0deg}, - name - ) - if debug { - draw.circle( - pos, - name: elmt-id + "-port-" + port.at("id"), - radius: .1, - stroke: none, - fill: red - ) - - } else { - draw.hide(draw.circle( - pos, - radius: 0, - stroke: none, - name: elmt-id + "-port-" + port.at("id") - )) - }*/ - } - } -} - -#let diag-find-port(ports, id) = { - for (side, side-ports) in ports { - for (i, port) in side-ports.enumerate() { - if port.id == id { - return (side, i) - } - } - } - panic("Could not find port with id " + str(id)) -} - -#let diag-elmt( - appearance: "rect", - x: none, - y: none, - w: none, - h: none, - name: none, - name-pos: "center", - ports: (), - ports-margins: (), - fill: none, - stroke: black + 1pt, - id: "", - debug: ( - grid: false, - ports: false - ) -) = draw.get-ctx(ctx => { - let width = w - let height = h - - 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(y) == dictionary) { - let from = y.from - let to = y.to - let (to-side, i) = diag-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) - - if appearance == "alu" { - top-margin = 0 - if to == "in1" { - dy = height * 0.225 - } else if to == "in2" { - dy = height * 0.775 - } - } - - let (ctx, from-pos) = coordinate.resolve(ctx, from) - y = from-pos.at(1) + dy - height + top-margin - } - - let tl = (x, y + height) - let tr = (x + width, y + height) - let br = (x + width, y) - let bl = (x, y) - - if appearance == "rect" { - draw.rect( - radius: 0.5em, - inset: 0.5em, - fill: fill, - stroke: stroke, - name: id, - bl, tr - ) - } else if appearance == "multiplexer" { - let tr2 = (tr, 20%, br) - let br2 = (tr, 80%, br) - draw.group(name: id, { - draw.merge-path( - inset: 0.5em, - fill: fill, - stroke: stroke, - close: true, - draw.line(tl, tr2, br2, bl) - ) - draw.anchor("north", (tl, 50%, tr2)) - draw.anchor("south", (bl, 50%, br2)) - draw.anchor("west", (tl, 50%, bl)) - draw.anchor("east", (tr2, 50%, br2)) - }) - - } else if appearance == "extender" { - tl = (x, y + height * 0.75) - let tr2 = (x + width, y + height * 0.75) - let br = (x + width, y) - (tr, tr2) = (tr2, tr) - draw.group(name: id, { - draw.merge-path( - inset: 0.5em, - fill: fill, - stroke: stroke, - close: true, - draw.line(tl, tr2, br, bl) - ) - draw.anchor("north", (tl, 50%, tr2)) - draw.anchor("south", (bl, 50%, br)) - draw.anchor("west", (tl, 50%, bl)) - draw.anchor("east", (tr2, 50%, br)) - }) - } else if appearance == "alu" { - let p0 = tl - let p1 = (tr, 10%, br) - let p2 = (tr, 90%, br) - let p3 = bl - let p4 = (tl, 55%, bl) - let p5 = (tl, 50%, br) - let p6 = (tl, 45%, bl) - - draw.group(name: id, { - - draw.merge-path( - inset: 0.5em, - fill: fill, - stroke: stroke, - close: true, - draw.line(p0, p1, p2, p3, p4, p5, p6) - ) - draw.anchor("north", (p0, 50%, p1)) - draw.anchor("south", (p2, 50%, p3)) - draw.anchor("west", (p0, 50%, p3)) - draw.anchor("east", (p1, 50%, p2)) - }) - - diag-port(id, "west", (id: "in1"), (p0, 50%, p6)) - diag-port(id, "west", (id: "in2"), (p3, 50%, p4)) - diag-port(id, "east", (id: "out"), (p1, 50%, p2)) - } - /*draw.for-each-anchor(id, (name) => { - draw.circle(id + "." + name, radius: .1, fill: red) - })*/ - - if (name != none) { - let block-anchor = "center" - let name-anchor = "center" - if (name-pos == "top") { - block-anchor = "north" - name-anchor = "north" - } else if (name-pos == "bottom") { - block-anchor = "south" - name-anchor = "south" - } else if (name-pos == "left") { - block-anchor = "west" - name-anchor = "west" - } else if (name-pos == "right") { - block-anchor = "east" - name-anchor = "east" - } - draw.content( - (name: id, anchor: block-anchor), - anchor: name-anchor, - padding: 0.5em, - align(center)[*#name*] - ) - - } - if appearance != "alu" { - diag-ports( - id, - tl, tr, br, bl, - ports, - ports-margins, - debug: debug.ports - ) - } -}) - -#let diag-block( - x: none, - y: none, - w: none, - h: none, - name: none, - name-pos: "center", - ports: (), - ports-margins: (), - fill: none, - stroke: black + 1pt, - id: "", - debug: ( - grid: false, - ports: false - ) -) = diag-elmt( - appearance: "rect", - x: x, - y: y, - w: w, - h: h, - name: name, - name-pos: name-pos, - ports: ports, - ports-margins: ports-margins, - fill: fill, - stroke: stroke, - id: id, - debug: debug -) - -#let diag-multiplexer( - x: none, - y: none, - w: none, - h: none, - name: none, - name-pos: "center", - entries: 2, - fill: none, - stroke: black + 1pt, - id: "", - debug: ( - grid: false, - ports: false - ) -) = { - let ports = () - - if (type(entries) == int) { - let nbits = calc.ceil(calc.log(entries, base: 2)) - for i in range(entries) { - let bits = lpad(str(i, base: 2), nbits) - ports.push((id: "in" + str(i), name: bits)) - } - } - - diag-elmt( - appearance: "multiplexer", - x: x, - y: y, - w: w, - h: h, - name: name, - name-pos: name-pos, - ports: (west: ports, east: ((id: "out"),)), - fill: fill, - stroke: stroke, - id: id, - debug: debug - ) -} - -#let diag-extender( - x: none, - y: none, - w: none, - h: none, - name: none, - name-pos: "center", - fill: none, - stroke: black + 1pt, - id: "", - debug: ( - grid: false, - ports: false - ) -) = { - let ports = ( - west: ( - (id: "in"), - ), - east: ( - (id: "out"), - ) - ) - - diag-elmt( - appearance: "extender", - x: x, - y: y, - w: w, - h: h, - name: name, - name-pos: name-pos, - ports: ports, - fill: fill, - stroke: stroke, - id: id, - debug: debug - ) -} - -#let diag-alu( - x: none, - y: none, - w: none, - h: none, - name: none, - name-pos: "center", - fill: none, - stroke: black + 1pt, - id: "", - debug: ( - grid: false, - ports: false - ) -) = { - let ports = ( - west: ( - (id: "in1"), - (id: "in2"), - ), - east: ( - (id: "out"), - ) - ) - - diag-elmt( - appearance: "alu", - x: x, - y: y, - w: w, - h: h, - name: name, - name-pos: name-pos, - ports: ports, - fill: fill, - stroke: stroke, - id: id, - debug: debug - ) -} - -#let diag-wire( - id, - pts, - bus: false, - name: none, - name-pos: "middle", - slice: none, - color: black, - dashed: false, - style: "direct", - reverse: false, - zigzag-ratio: 50%, - dodge-y: 0, - dodge-sides: ("east", "west"), - dodge-margins: (5%, 5%) -) = draw.get-ctx(ctx => { - let styles = ( - "direct", - "zigzag", - "dodge" - ) - if not style in styles { - panic("Invalid wire style '" + style + "'") - } - if pts.len() != 2 { - panic("Wrong number of points for style '" + style + "' (got " + str(pts.len()) + " instead of 2)") - } - - let stroke = (paint: color, thickness: if bus {1.5pt} else {1pt}) - if dashed { - stroke.insert("dash", "dashed") - } - - let points = () - let anchors = () - - if style == "direct" { - points = pts - anchors = ( - "start": points.first(), - "end": points.last() - ) - - } else if style == "zigzag" { - let start = pts.at(0) - let end = pts.at(1) - let mid = (start, zigzag-ratio, end) - - points = ( - start, - (horizontal: mid, vertical: ()), - (horizontal: (), vertical: end), - end - ) - anchors = ( - "start": points.first(), - "zig": points.at(1), - "zag": points.at(1), - "end": points.last() - ) - - } else if style == "dodge" { - let start = pts.at(0) - let end = pts.at(1) - let p1 = (start, dodge-margins.at(0), end) - let p2 = (end, dodge-margins.at(1), start) - - let (ctx, p0) = coordinate.resolve(ctx, start) - let (ctx, p3) = coordinate.resolve(ctx, end) - p0 = (x: p0.at(0), y: p0.at(1)) - p3 = (x: p3.at(0), y: p3.at(1)) - let (margin-start, margin-end) = dodge-margins - let (side-start, side-end) = dodge-sides - - let dx1 = margin-start - let dx2 = margin-end - - if type(margin-start) == ratio { - dx1 = calc.abs(p3.x - p0.x) * margin-start / 100% - } - if type(margin-end) == ratio { - dx2 = calc.abs(p3.x - p0.x) * margin-end / 100% - } - if side-start == "west" { - dx1 *= -1 - } - if side-end == "east" { - dx2 *= -1 - } - p1 = (p0.x + dx1, p0.y) - p2 = (p3.x - dx2, p0.y) - - points = ( - start, - (horizontal: p1, vertical: ()), - (horizontal: (), vertical: (0, dodge-y)), - (horizontal: p2, vertical: ()), - (horizontal: (), vertical: end), - end - ) - anchors = ( - "start": start, - "start2": points.at(1), - "dodge-start": points.at(2), - "dodge-end": points.at(3), - "end2": points.at(4), - "end": end - ) - } - - draw.group(name: id, { - draw.line(..points, stroke: stroke) - for (anchor-name, anchor-pos) in anchors { - draw.anchor(anchor-name, anchor-pos) - } - }) - - let first-pt = id + ".start" - let last-pt = id + ".end" - if reverse { - (first-pt, last-pt) = (last-pt, first-pt) - } - - if name != none { - let names = () - - if type(name) == str { - names = ((name, name-pos),) - - } else if type(name) == array { - names = ( - (name.at(0), "start"), - (name.at(1), "end") - ) - } - - for (name, pos) in names { - let point - let anchor - - if pos == "middle" { - point = (first-pt, 50%, last-pt) - anchor = "south" - } else if pos == "start" { - point = first-pt - anchor = "south-west" - } else if pos == "end" { - point = last-pt - anchor = "south-east" - } - draw.content(point, anchor: anchor, padding: 3pt, name) - } - } - if slice != none { - let slice-txt = "[" + str(slice.first()) + ":" + str(slice.last()) + "]" - - draw.content( - first-pt, - anchor: "south-west", - padding: 3pt, - text(slice-txt, size: 0.75em) - ) - } -}) - -#let diag-intersection(pt) = { - draw.circle(pt, radius: .2, stroke: none, fill: black) -} - -#context { - canvas(length: 2em, { - diag-block( - x: 0, y: 0, w: 1.5, h: 2.2, - id: "PC-buf", - fill: diag-colors.orange, - ports: ( - west: ( - (id: "PCNext"), - ), - north: ( - (id: "CLK", clock: true), - ), - east: ( - (id: "PC"), - ), - south: ( - (id: "EN", name: "EN"), - ) - ) - ) - diag-port-stub("PC-buf-port-CLK", "north", name: "CLK") - diag-port-stub("PC-buf-port-EN", "south", name: "PCWrite") - - diag-multiplexer( - x: 3, y: (from: "PC-buf-port-PC", to: "in0"), w: 1, h: 2, - id: "AdrSrc-MP", - fill: diag-colors.orange, - entries: 2 - ) - diag-wire( - "wPCBuf-InstDataMgr", ( - "PC-buf-port-PC", - "AdrSrc-MP-port-in0" - ), - name: "PC", - bus: true - ) - diag-port-stub("AdrSrc-MP.north", "north", name: "AdrSrc") - - diag-block( - x: 6, y: (from: "AdrSrc-MP-port-out", to: "A"), w: 3, h: 4, - id: "InstDataMgr", - fill: diag-colors.yellow, - ports: ( - west: ( - (id: "A", name: "A"), - (id: "WD", name: "WD") - ), - north: ( - (id: "CLK", clock: true), - (id: "WE", name: "WE", vertical: true), - (id: "IRWrite", name: "IRWrite", vertical: true) - ), - east: ( - (id: "Instr", name: "Instr."), - (id: "RD", name: "RD") - ) - ), - ports-margins: ( - west: (30%, 0%), - east: (40%, 0%) - ) - ) - diag-wire( - "wAdrSrcMP-InstDataMgr", ( - "AdrSrc-MP-port-out", - "InstDataMgr-port-A" - ), - name: "Addr", - name-pos: "end", - bus: true - ) - - diag-port-stub("InstDataMgr-port-CLK", "north", name: "CLK") - diag-port-stub("InstDataMgr-port-WE", "north") - diag-port-stub("InstDataMgr-port-IRWrite", "north") - diag-port-stub("InstDataMgr-port-WD", "west") - - diag-block( - x: 15, y: (from: "InstDataMgr-port-RD", to: "WD3"), w: 3, h: 4, - id: "RegFile", - fill: diag-colors.pink, - ports: ( - west: ( - (id: "A1", name: "A1"), - (id: "A2", name: "A2"), - (id: "A3", name: "A3"), - (id: "WD3", name: "WD3"), - ), - north: ( - (id: "CLK", clock: true), - (id: "WE3", name: "WE3", vertical: true) - ), - east: ( - (id: "RD1", name: "RD1"), - (id: "RD2", name: "RD2"), - ) - ), - ports-margins: ( - east: (20%, 20%) - ) - ) - diag-port-stub("RegFile-port-CLK", "north", name: "CLK") - diag-port-stub("RegFile-port-WE3", "north", name: "Regwrite", vertical: true) - diag-port-stub("RegFile-port-A2", "west") - diag-port-stub("RegFile-port-RD2", "east") - - diag-extender( - x: 15, y: -3.5, w: 3, h: 1, - id: "Extender", - fill: diag-colors.green - ) - diag-wire( - "wExtender-ImmSrc", ( - "Extender.north", - (18, -2) - ), - style: "zigzag", - zigzag-ratio: 0%, - name: "ImmSrc", - name-pos: "end", - bus: true - ) - - let mid = ("InstDataMgr.east", 50%, "RegFile.west") - diag-wire( - "wInstDataMgr-Bus", ( - "InstDataMgr-port-Instr", - (vertical: (), horizontal: mid) - ), - name: "Instr", - name-pos: "start", - bus: true - ) - diag-wire( - "wBus", ( - (v => (v.at(0), -3.5), mid), - (horizontal: (), vertical: (0, 3.5)), - ), - bus: true - ) - diag-wire( - "wBus-RegFile-A1", ( - "RegFile-port-A1", - (horizontal: mid, vertical: ()), - ), - name: "RS1", - name-pos: "end", - slice: (19, 15), - reverse: true, - bus: true - ) - diag-wire( - "wBus-RegFile-A3", ( - "RegFile-port-A3", - (horizontal: mid, vertical: ()), - ), - name: "RD", - name-pos: "end", - slice: (11, 7), - reverse: true, - bus: true - ) - diag-wire( - "wBus-Extender", ( - "Extender-port-in", - (horizontal: mid, vertical: ()), - ), - slice: (31, 7), - reverse: true, - bus: true - ) - - diag-alu( - x: 22, y: (from: "RegFile-port-RD1", to: "in1"), w: 1, h: 2, - id: "ALU", - fill: diag-colors.purple - ) - diag-wire( - "wRegFile-ALU", ( - "RegFile-port-RD1", - "ALU-port-in1" - ), - name: ("A", "SrcA"), - bus: true - ) - - diag-block( - x: 26, y: (from: "ALU-port-out", to: "in"), w: 1.5, h: 2, - id: "OutBuf", - fill: diag-colors.orange, - ports: ( - west: ( - (id: "in"), - ), - north: ( - (id: "CLK", clock: true), - ), - east: ( - (id: "out"), - ) - ) - ) - diag-port-stub("OutBuf-port-CLK", "north", name: "CLK") - diag-wire( - "wALU-OutBuf", ( - "ALU-port-out", - "OutBuf-port-in" - ), - name: "ALUResult", - bus: true - ) - - diag-multiplexer( - x: 30, y: (from: "OutBuf-port-out", to: "in0"), w: 1, h: 2.5, - id: "Res-MP", - fill: diag-colors.orange, - entries: 3 - ) - diag-port-stub("Res-MP.north", "north", name: "ResultSrc") - diag-port-stub("Res-MP-port-in2", "west") - diag-wire( - "wOutBuf-ResMP", ( - "OutBuf-port-out", - "Res-MP-port-in0" - ), - name: "ALUOut", - bus: true - ) - - diag-wire( - "wExt-ALU", ( - "Extender-port-out", - "ALU-port-in2", - ), - name: ("ImmExt", "SrcB"), - bus: true, - style: "zigzag", - zigzag-ratio: 60% - ) - - diag-wire( - "wInstDataMgr-ResMP", ( - "InstDataMgr-port-RD", - "Res-MP-port-in1" - ), - style: "dodge", - dodge-y: -4, - dodge-sides: ("east", "west"), - name: "Data", - name-pos: "start", - bus: true - ) - - diag-wire( - "wResMP-AdrSrc", ( - "Res-MP-port-out", - "AdrSrc-MP-port-in1" - ), - style: "dodge", - dodge-y: -5, - dodge-sides: ("east", "west"), - dodge-margins: (0.5, 1), - bus: true - ) - - diag-wire( - "wResMP-RegFile", ( - "Res-MP-port-out", - "RegFile-port-WD3" - ), - style: "dodge", - dodge-y: -5, - dodge-sides: ("east", "west"), - dodge-margins: (0.5, 1), - bus: true - ) - - diag-wire( - "wResMP-PCBuf", ( - "Res-MP-port-out", - "PC-buf-port-PCNext" - ), - style: "dodge", - dodge-y: -5, - dodge-sides: ("east", "west"), - dodge-margins: (0.5, 1.5), - name: "PCNext", - name-pos: "end", - bus: true - ) - - - diag-intersection("wResMP-RegFile.dodge-end") - diag-intersection("wResMP-AdrSrc.dodge-end") - }) -} \ No newline at end of file