initial commit

This commit is contained in:
Louis Heredero 2024-12-13 23:04:02 +01:00
commit 85d05c9595
Signed by: HEL
GPG Key ID: 8D83DE470F8544E7
33 changed files with 1932 additions and 0 deletions

161
README.md Normal file
View File

@ -0,0 +1,161 @@
# Typstuff, stuff I made with Typst <!-- omit from toc -->
This repository lists some of the stuff I have made using Typst
Smaller scripts will be included directly in this repository
---
### Table of contents <!-- omit from toc -->
- [RIVET](#rivet)
- [Chronos](#chronos)
- [Circuiteria](#circuiteria)
- [Functastic](#functastic)
- [Math tools](#math-tools)
- [Sankeynoa](#sankeynoa)
- [RISCV Utilities](#riscv-utilities)
- [Simple UML class diagrams](#simple-uml-class-diagrams)
- [Tasty TacOS](#tasty-tacos)
- [Leetcode trees](#leetcode-trees)
- [Cafeteria menus](#cafeteria-menus)
- [Avent of Code](#avent-of-code)
## RIVET
*Links*:
[Repo](https://git.kb28.ch/HEL/rivet-typst) /
[Universe](https://typst.app/universe/package/rivet)
*Description*:
Register / Instruction Visualizer & Explainer Tool with Typst, using CeTZ
<p align="center">
<img src="images/rivet.png" width="400">
</p>
## Chronos
*Links*:
[Repo](https://git.kb28.ch/HEL/chronos) /
[Universe](https://typst.app/universe/package/chronos)
*Description*:
A Typst package to draw sequence diagrams with CeTZ
<p align="center">
<img src="images/chronos.png" width="150">
</p>
## Circuiteria
*Links*:
[Repo](https://git.kb28.ch/HEL/circuiteria) /
[Universe](https://typst.app/universe/package/circuiteria)
*Description*:
Drawing block circuits with Typst made easy, using CeTZ
<p align="center">
<img src="images/circuiteria.png" width="300">
</p>
## Functastic
*Links*:
[Repo](https://git.kb28.ch/HEL/functastic)
*Description*:
A Typst package to create sign tables of mathematical functions
<p align="center">
<img src="images/functastic.png" width="400">
</p>
## Math tools
*Links*:
[Repo](https://git.kb28.ch/HEL/math-tools)
*Description*:
Useful mathematical functions
<p align="center">
<img src="images/math_tools.png" width="400">
</p>
## Sankeynoa
*Links*:
[Repo](https://git.kb28.ch/HEL/sankeynoa)
*Description*:
Beautiful Sankey diagrams using CeTZ
<p align="center">
<img src="images/sankeynoa.png" width="400">
</p>
## RISCV Utilities
*Links*:
[Directory](./misc/riscv/)
*Description*:
Some RISCV utilities to show instructions
<p align="center">
<img src="images/riscv.png" width="500">
</p>
## Simple UML class diagrams
*Links*:
[Directory](./misc/uml/)
*Description*:
Functions do make simple class diagrams and directly parse UML
<p align="center">
<img src="images/uml.png" width="400">
</p>
## Tasty TacOS
*Links*:
[Repo](https://git.kb28.ch/HEL/tasty-tacos)
*Description*:
Various algorithms from the OS course
<p align="center">
<img src="images/tasty_tacos.png" width="500">
</p>
## Leetcode trees
*Links*:
[Directory](./misc/leetcode_trees/)
*Description*:
Function to easily display leetcode tree exercises in a CeTZ canvas
<p align="center">
<img src="images/leetcode_trees.png" width="300">
</p>
## Cafeteria menus
*Links*:
[Directory](./misc/menus/)
*Description*:
Cafeteria menus for the week, used by a Discord and a Telegram bot
<p align="center">
<img src="images/menus.png" width="500">
</p>
## Avent of Code
*Links*:
[Repo](https://git.kb28.ch/HEL/AdventOfCode2024)
*Description*:
My attempt at Advent of Code (2024)
<p align="center">
<img src="images/aoc.png" width="300">
</p>

BIN
images/aoc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

BIN
images/chronos.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
images/circuiteria.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

BIN
images/functastic.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

BIN
images/leetcode_trees.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
images/math_tools.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

BIN
images/menus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

BIN
images/riscv.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
images/rivet.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 KiB

BIN
images/sankeynoa.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
images/tasty_tacos.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

BIN
images/uml.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

67
misc/blobs/blobs.typ Normal file
View File

@ -0,0 +1,67 @@
#import "@preview/cetz:0.3.1": draw
#let rand-consts = (
a: 1103515245,
c: 12345,
m: (1).bit-lshift(31)
)
#let random(seed) = {
let seed = calc.rem(rand-consts.a * seed + rand-consts.c, rand-consts.m)
let value = seed / rand-consts.m
return (seed, value)
}
#let draw-blob(
seed,
center,
radius,
n-pts: 8,
curviness: 0.4,
debug: false,
..args
) = {
let pts = ()
let angle-step = 360deg / n-pts
let seed = seed
let v
if debug {
draw.circle(center, radius: radius, stroke: (dash: "dashed"))
}
for i in range(n-pts) {
(seed, v) = random(seed)
let angle = angle-step * (i + v - 0.5)
(seed, v) = random(seed)
let f = calc.rem(i, 2) * 2 - 1
let r = radius * (1 + f * v * curviness)
let dx = r * calc.cos(angle)
let dy = r * calc.sin(angle)
let pt = (center.first() + dx, center.last() + dy)
pts.push(pt)
if debug {
draw.circle(
pt,
radius: .1,
stroke: none,
fill: black
)
draw.line(
center,
(rel: center, to: (angle-step * i, radius)),
stroke: (dash: "dashed")
)
}
}
let name = args.named().at("name", default: none)
draw.group(name: name, {
draw.hobby(..pts, close: true, ..args)
if name != none {
draw.copy-anchors(name)
draw.anchor("center", center)
}
})
}

BIN
misc/blobs/main.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

79
misc/blobs/main.typ Normal file
View File

@ -0,0 +1,79 @@
#import "@preview/cetz:0.3.1": canvas, draw
#import "blobs.typ": draw-blob
#set page(width: auto, height: auto, margin: 1cm)
#canvas({
draw-blob(
2, (0, 0), 1.5,
stroke: green,
name: "blob1"
)
draw-blob(
8, (5, 0), 1.5,
n-pts: 10,
stroke: orange,
name: "blob2"
)
draw.circle(
"blob1.center",
radius: .05,
fill: black,
stroke: none,
name: "x"
)
draw.circle(
"blob2.center",
radius: .05,
fill: black,
stroke: none,
name: "y"
)
draw.content(
"x",
[$arrow(x)$],
anchor: "east",
padding: 3pt
)
draw.content(
"y",
[$arrow(y)$],
anchor: "west",
padding: 3pt
)
draw.content(
(-1.2, .8),
text(fill: green)[$RR^n$]
)
draw.content(
(4.6, 1.4),
text(fill: orange)[$RR^m$]
)
let mid = (2.5, .5)
draw.bezier-through(
"x.north-east", mid, "y.north-west",
stroke: blue + .5pt,
mark: (end: ">", fill: blue),
name: "arrow"
)
draw.content(
mid,
[$f$],
anchor: "south",
padding: 3pt
)
draw.content(
(2.5, -1),
text(fill: blue)[$f: RR^n -> RR^m$]
)
})

Binary file not shown.

View File

@ -0,0 +1,97 @@
#import "@preview/cetz:0.3.1": canvas, draw
#let leetcode-tree(nodes, highlighted: ()) = {
let height = calc.ceil(
calc.log(
nodes.len() + 1,
base: 2
)
)
let dy = 1
let dx = 0.8
let r = 0.3
let width = dx * (calc.pow(2, height - 1) + 1)
for lvl in range(height) {
let n = calc.pow(2, lvl)
let y = -lvl * dy
for i in range(n) {
let j = i + n - 1
if j >= nodes.len() {
break
}
let node = nodes.at(j)
if node != none {
let x = width * (i + .5) / n
let name = "l" + str(lvl) + "-n" + str(i)
let is-highlighted = (j in highlighted) or (lvl, i) in highlighted
draw.circle(
(x, y),
radius: r,
name: name,
fill: if is-highlighted {
blue.lighten(75%)
} else {
none
}
)
draw.content(
name + ".center",
str(node)
)
if lvl != 0 {
let pi = i.bit-rshift(1)
draw.line(
"l" + str(lvl - 1) + "-n" + str(pi),
name
)
}
}
}
}
}
#set page(width: auto, height: auto, margin: 1cm)
#canvas({
leetcode-tree(
(2,1,3,none,none,none,4),
highlighted: (2,)
)
})
#pagebreak()
#canvas({
leetcode-tree(
(1,2,3,4,5,6,none,none,none,7,8)
)
})
#pagebreak()
#canvas({
leetcode-tree(
(99,3,2,none,6,4,5,none,none,none,none,8,7)
)
})
#pagebreak()
#canvas({
leetcode-tree(
(0,3,1,none,none,none,2)
)
})
#pagebreak()
#canvas({
leetcode-tree(
(0,3,1,2)
)
})

65
misc/menus/menu.json Normal file
View File

@ -0,0 +1,65 @@
[
{
"date": "2024-09-09",
"menus": [
{
"name": "Risotto à la courge",
"extra": [
"Chips de courge",
"Fromage râpé"
],
"prices": {
"E": 8.1,
"C": 11.0,
"D": 9.9,
"V": 12.6
}
},
{
"name": "Ragoût de cerf",
"extra": [
"Spätzli au beurre",
"Choux de Bruxelles et chou rouge"
],
"prices": {
"E": 11.5,
"C": 14.4,
"D": 13.3,
"V": 16.0
}
}
]
},
{
"date": "2024-09-10",
"menus": [
{
"name": "Rösti aux champignons",
"extra": [
"Sauce crême",
"Salade du chef"
],
"prices": {
"E": 7.0,
"C": 9.0,
"D": 8.0,
"V": 10.0
}
},
{
"name": "Boulette de poulet",
"extra": [
"Sauce alfredo",
"Pâtes spaghetti",
"Jardinière de légumes"
],
"prices": {
"E": 10.5,
"C": 13.4,
"D": 12.3,
"V": 15.0
}
}
]
}
]

BIN
misc/menus/menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

202
misc/menus/menu.typ Normal file
View File

@ -0,0 +1,202 @@
#let path = sys.inputs.at("path", default: "menu.json")
#let all-combos = sys.inputs.at("all-combos", default: "false") == "true"
#let categories = sys.inputs.at("categories", default: "E,D,C,V").split(",")
#let dark = sys.inputs.at("dark", default: "false") == "true"
#let days = json(path)
#let nbsp = sym.space.nobreak
#let colors = if dark {(
bg: rgb("#1f1f24"),
text: white,
categories: rgb("#70c947"),
menu-sep: rgb("#ababab"),
title-underline: rgb("#eb2324"),
day-sep: rgb("#a3cf40")
)} else {(
bg: white,
text: black,
categories: rgb("#577F25"),
menu-sep: rgb("#ababab"),
title-underline: rgb("#e34243"),
day-sep: rgb("#82BC00")
)}
#let width = if days.len() > 1 {20cm} else {10cm}
#set page(
margin: 0cm,
height: auto,
width: width,
fill: colors.bg
)
#set text(
fill: colors.text
)
#let parse-date(date-txt) = {
let (year, month, day) = date-txt.split("-")
return datetime(year: int(year), month: int(month), day: int(day))
}
#let fmt-number(
number,
decimals: 2,
decimal-sep: ".",
thousands-sep: "'"
) = {
let integer = calc.trunc(number)
let decimal = calc.fract(number)
let res = str(integer).clusters()
.rev()
.chunks(3)
.map(c => c.join(""))
.join(thousands-sep)
.rev()
if decimals != 0 {
res += decimal-sep
decimal = decimal * calc.pow(10, decimals)
decimal = calc.round(decimal)
decimal = str(decimal) + ("0" * decimals)
res += decimal.slice(0, decimals)
}
return res
}
#let day-names = (
"Lundi",
"Mardi",
"Mercredi",
"Jeudi",
"Vendredi",
"Samedi",
"Dimanche"
)
#let display-menus(
days,
categories,
day-sep-stroke: colors.day-sep + 1pt,
title-underline-stroke: colors.title-underline + 2pt,
menu-sep-stroke: colors.menu-sep + 1pt,
price-categ-color: colors.categories
) = {
set text(font: "Liberation Sans", hyphenate: true)
let cols = calc.min(2, days.len())
let cells = ()
for day in days {
let date = parse-date(day.date)
let weekday = date.weekday() - 1
let day-name = day-names.at(weekday)
let menus = ()
for menu in day.menus {
let price-cell = grid.cell(rowspan: 2)[]
let prices = menu.at(
"prices",
default: (:)
)
if menu.keys().contains("price") {
prices = ("": menu.price)
}
let pairs = prices.pairs()
.filter(p => p.first() in categories)
.sorted(key: p => p.last())
let prices = pairs.map(p => {
let categ = emph(
text(
fill: price-categ-color,
p.first()
)
)
let price = fmt-number(p.last())
categ + ":" + nbsp + "CHF" + nbsp + price
})
price-cell = grid.cell(
rowspan: menu.extra.len() + 1,
stack(dir: ttb, spacing: .4em, ..prices)
)
//let price = "CHF" + sym.space.nobreak + str(menu.price)
menus.push(
grid(
columns: (1fr, auto),
column-gutter: .4em,
row-gutter: .4em,
[*#menu.name*],
price-cell,
..menu.extra.map(l => text(10pt, l))
)
)
}
let title = align(
center,
stack(
dir: ttb,
spacing: .5em,
text(size: 14pt, weight: "bold", day-name),
text(size: 10pt, date.display("[day].[month]"))
)
)
let title-box = box(
width: 50%,
inset: .6em,
stroke: (bottom: title-underline-stroke),
title
)
let title-cell = grid.cell(align: center, title-box)
cells.push(box(width: 100%, grid(
columns: (100%),
inset: (x, y) => (
top: if y == 0 {0pt} else {.8em},
bottom: if y == 0 {0pt} else {2em}
),
stroke: (_, y) => (top: if y < 2 {none} else {menu-sep-stroke}),
title-cell,
..menus
)))
}
if calc.rem(cells.len(), 2) == 1 {
cells.last() = grid.cell(colspan: calc.min(2, cols), cells.last())
}
grid(
columns: (100% / cols,) * cols,
inset: (x: 1.5em, y: .8em),
stroke: (x, y) => {
let borders = (:)
if x != 0 {
borders.insert("left", day-sep-stroke)
}
if y != 0 {
borders.insert("top", day-sep-stroke)
}
return borders
},
..cells
)
}
#{
if all-combos {
let n-combos = calc.pow(2, categories.len())
for i in range(n-combos) {
let filtered-categories = categories.enumerate().filter(p => {
let (j, categ) = p
return i.bit-rshift(j).bit-and(1) != 0
}).map(p => p.last())
display-menus(days, filtered-categories)
pagebreak(weak: true)
}
} else {
display-menus(days, categories)
}
}

BIN
misc/menus/menu_dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

BIN
misc/menus/menu_student.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

BIN
misc/riscv/main.pdf Normal file

Binary file not shown.

39
misc/riscv/main.typ Normal file
View File

@ -0,0 +1,39 @@
#import "riscv.typ"
#set page(width: auto, height: auto, margin: 1cm)
#riscv.explain-instruction-encoding("lui x0, 0x12")
#riscv.explain-instruction-encoding("add sp, a0, a1")
#pagebreak()
#riscv.riscv-to-bin(```
0x00000300 main: jal ra, simple # call
0x00000304 add s0, s1, s1
0x0000051c simple: jalr x0, ra, 0 # return
```)
#pagebreak()
#riscv.riscv-to-bin(```
f1:
addi sp, sp, -20 # make space on stack for 5 words
sw a0, 16(sp)
sw a1, 12(sp)
sw ra, 8(sp) # save ra on stack
sw s4, 4(sp)
sw s5, 0(sp)
jal ra, f2
lw ra, 8(sp) # restore ra (and other regs) from stack
addi sp, sp, 20 # deallocate stack space
jalr zero, ra, 0
# f2 (leaf-function) only uses s4 and calls no functions
f2:
addi sp, sp, -4 # make space on stack for 1 word
sw s4, 0(sp)
lw s4, 0(sp)
addi sp, sp, 4 # deallocate stack space
jalr zero, ra, 0
```)

455
misc/riscv/riscv.typ Normal file
View File

@ -0,0 +1,455 @@
#let colors = (
address: rgb(228, 103, 103),
label: rgb(119, 97, 204),
op: rgb(235, 105, 40)
)
#let opcodes = (
"lui": 0b0110111,
"auipc": 0b0010111,
"jal": 0b1101111,
"jalr": 0b1100111,
"beq": 0b1100011,
"bne": 0b1100011,
"blt": 0b1100011,
"bge": 0b1100011,
"bltu": 0b1100011,
"bgeu": 0b1100011,
"lb": 0b0000011,
"lh": 0b0000011,
"lw": 0b0000011,
"lbu": 0b0000011,
"lhu": 0b0000011,
"sb": 0b0100011,
"sh": 0b0100011,
"sw": 0b0100011,
"addi": 0b0010011,
"slti": 0b0010011,
"sltiu": 0b0010011,
"xori": 0b0010011,
"ori": 0b0010011,
"andi": 0b0010011,
"slli": 0b0010011,
"srli": 0b0010011,
"srai": 0b0010011,
"add": 0b0110011,
"sub": 0b0110011,
"sll": 0b0110011,
"slt": 0b0110011,
"sltu": 0b0110011,
"xor": 0b0110011,
"srl": 0b0110011,
"sra": 0b0110011,
"or": 0b0110011,
"and": 0b0110011,
)
#let types = (
"lui": "U",
"auipc": "U",
"jal": "J",
"jalr": "I",
"beq": "B",
"bne": "B",
"blt": "B",
"bge": "B",
"bltu": "B",
"bgeu": "B",
"lb": "L",
"lh": "L",
"lw": "L",
"lbu": "L",
"lhu": "L",
"sb": "S",
"sh": "S",
"sw": "S",
"addi": "I",
"slti": "I",
"sltiu": "I",
"xori": "I",
"ori": "I",
"andi": "I",
"slli": "I",
"srli": "I",
"srai": "I",
"add": "R",
"sub": "R",
"sll": "R",
"slt": "R",
"sltu": "R",
"xor": "R",
"srl": "R",
"sra": "R",
"or": "R",
"and": "R",
)
#let funct3 = (
"jalr": 0b000,
"beq": 0b000,
"bne": 0b001,
"blt": 0b100,
"bge": 0b101,
"bltu": 0b110,
"bgeu": 0b111,
"lb": 0b000,
"lh": 0b001,
"lw": 0b010,
"lbu": 0b100,
"lhu": 0b101,
"sb": 0b000,
"sh": 0b001,
"sw": 0b010,
"addi": 0b000,
"slti": 0b010,
"sltiu": 0b011,
"xori": 0b100,
"ori": 0b110,
"andi": 0b111,
"slli": 0b001,
"srli": 0b101,
"srai": 0b101,
"add": 0b000,
"sub": 0b000,
"sll": 0b001,
"slt": 0b010,
"sltu": 0b011,
"xor": 0b100,
"srl": 0b101,
"sra": 0b101,
"or": 0b110,
"and": 0b111,
)
#let funct7 = (
"slli": 0b0000000,
"srli": 0b0000000,
"srai": 0b0100000,
"add": 0b0000000,
"sub": 0b0100000,
"sll": 0b0000000,
"slt": 0b0000000,
"sltu": 0b0000000,
"xor": 0b0000000,
"srl": 0b0000000,
"sra": 0b0100000,
"or": 0b0000000,
"and": 0b0000000,
)
#let regs = (
"zero": 0, "ra": 1, "sp": 2, "gp": 3,
"tp": 4, "t0": 5, "t1": 6, "t2": 7,
"s0": 8, "fp": 8, "s1": 9, "a0": 10, "a1": 11,
"a2": 12, "a3": 13, "a4": 14, "a5": 15,
"a6": 16, "a7": 17, "s2": 18, "s3": 19,
"s4": 20, "s5": 21, "s6": 22, "s7": 23,
"s8": 24, "s9": 25, "s10": 26, "s11": 27,
"t3": 28, "t4": 29, "t5": 30, "t6": 31
)
#let zfill(string, length, c: "0") = {
let res = c * length + string
return res.slice(-length)
}
#let int-to-bin(value, bits) = {
if value < 0 {
let m = (1).bit-lshift(bits) - 1
let v = str((-value).bit-xor(m) + 1, base: 2)
return zfill(v, bits, c: "1")
}
let v = str(value, base: 2)
return zfill(v, bits)
}
#let parse-reg(value) = {
let number = value.last()
if not value.starts-with("x") {
number = regs.at(value)
}
return int(number)
}
#let parse-imm(value) = {
let imm = eval(value)
assert(type(imm) == int)
return imm
}
#let parse-addr(value) = {
let matches = value.match(regex("(.*)\((.*)\)"))
let imm = matches.captures.first()
let reg = matches.captures.last()
imm = parse-imm(imm)
reg = parse-reg(reg)
return (reg, imm)
}
#let parse-args(instr, instr-type, args) = {
let parsed = (:)
let r1 = parse-reg(args.first())
if instr-type in ("R", "I", "L", "U", "J") {
parsed.insert("rd", r1)
} else if instr-type == "B" {
parsed.insert("rs1", r1)
} else if instr-type == "S" {
parsed.insert("rs2", r1)
}
let r2 = none
let r3 = none
let imm = none
if instr-type == "R" {
r2 = parse-reg(args.at(1))
r3 = parse-reg(args.at(2))
} else if instr-type in ("I", "B") {
r2 = parse-reg(args.at(1))
imm = parse-imm(args.at(2))
} else if instr-type in ("U", "J") {
imm = parse-imm(args.at(1))
} else if instr-type in ("L", "S") {
(r2, imm) = parse-addr(args.at(1))
}
if instr-type == "R" {
parsed.insert("rs1", r2)
parsed.insert("rs2", r3)
} else if instr-type in ("I", "L", "S") {
parsed.insert("rs1", r2)
parsed.insert("imm", imm)
} else if instr-type == "B" {
parsed.insert("rs2", r2)
parsed.insert("imm", imm)
} else if instr-type in ("U", "J") {
parsed.insert("imm", imm)
}
return parsed
}
#let format-imm(imm, sections) = {
let value = 0
for section in sections {
if type(section) == int {
let bit = imm.bit-rshift(section).bit-and(1)
value = value.bit-lshift(1).bit-or(bit)
} else {
let (start, end) = section
if start > end {
(start, end) = (end, start)
}
let span = end - start + 1
let mask = (1).bit-lshift(span) - 1
let bits = imm.bit-rshift(start).bit-and(mask)
value = value.bit-lshift(span).bit-or(bits)
}
}
return value
}
#let instr-to-bin(instruction) = {
let (instr, ..args) = instruction.split(" ")
args = args.join("").split(",").map(a => a.trim())
instr = lower(instr)
let parts = ()
let parts-names = ()
let opcode = opcodes.at(instr)
let instr-type = types.at(instr)
let code = 0
let parsed-args = parse-args(instr, instr-type, args)
let imm = parsed-args.at("imm", default: none)
let add-part(code, parts, part, bits) = {
code = code.bit-lshift(bits).bit-or(part)
parts.push(int-to-bin(part, bits))
return (code, parts)
}
if instr in ("slli", "srli", "srai") {
let f7 = funct7.at(instr)
(code, parts) = add-part(code, parts, f7, 7)
parts-names.push("funct7")
let v = format-imm(imm, ((4,0),))
(code, parts) = add-part(code, parts, v, 5)
parts-names.push("shamt")
} else if instr-type == "R" {
let v = funct7.at(instr)
parts-names.push("funct7")
(code, parts) = add-part(code, parts, v, 7)
} else if instr-type in ("I", "L") {
let v = format-imm(imm, ((11,0),))
(code, parts) = add-part(code, parts, v, 12)
parts-names.push("imm[11:0]")
} else if instr-type == "S" {
let v = format-imm(imm, ((11, 5),))
(code, parts) = add-part(code, parts, v, 7)
parts-names.push("imm[11:5]")
} else if instr-type == "B" {
let v = format-imm(imm, (12, (10, 5)))
(code, parts) = add-part(code, parts, v, 7)
parts-names.push("imm[12|10:5]")
} else if instr-type == "U" {
let v = format-imm(imm, ((19, 0),))
(code, parts) = add-part(code, parts, v, 20)
parts-names.push("imm[31:12]")
} else if instr-type == "J" {
let v = format-imm(imm, (20, (10, 1), 11, (19, 12)))
(code, parts) = add-part(code, parts, v, 20)
parts-names.push("imm[20|10:1|11|19:12]")
}
if instr-type in ("R", "S", "B") {
(code, parts) = add-part(code, parts, parsed-args.rs2, 5)
parts-names.push("rs2")
}
if instr-type in ("R", "I", "L", "S", "B") {
(code, parts) = add-part(code, parts, parsed-args.rs1, 5)
parts-names.push("rs1")
(code, parts) = add-part(code, parts, funct3.at(instr), 3)
parts-names.push("funct3")
}
if instr-type in ("R", "I", "L", "U", "J") {
(code, parts) = add-part(code, parts, parsed-args.rd, 5)
parts-names.push("rd")
} else if instr-type == "S" {
let v = format-imm(imm, ((4, 0),))
(code, parts) = add-part(code, parts, v, 5)
parts-names.push("imm[4:0]")
} else if instr-type == "B" {
let v = format-imm(imm, ((4, 1), 11))
(code, parts) = add-part(code, parts, v, 5)
parts-names.push("imm[4:1|11]")
}
(code, parts) = add-part(code, parts, opcode, 7)
parts-names.push("opcode")
return (
instruction: instruction,
parts: parts,
names: parts-names,
code: code
)
}
#let color-instruction(line) = {
let res = ""
if line.starts-with("0x") {
let (addr, ..rest) = line.split(" ")
line = rest.join(" ").trim()
res += text(raw(addr), fill: colors.address) + " "
}
if ":" in line {
let label
(label, line) = line.split(":")
line = line.trim()
res += text(raw(label), fill: colors.label) + ": "
if line.len() == 0 {
return res
}
}
let (op, ..args) = line.split(" ")
args = args.join("").split(",").map(a => a.trim())
args = args.map(a => raw(a))
res += text(raw(op), fill: colors.op) + " "
res += args.join(", ")
return res
}
#let explain-instruction-encoding(instruction) = {
let encoded = instr-to-bin(instruction)
let parts = encoded.parts
let names = encoded.names
let code = encoded.code
parts.zip(names).map(((v, n)) => $underbrace(#raw(v), #n)$).join(" ")
[ \= #raw(instruction) \= 0x#raw(zfill(str(code, base: 16), 8))]
}
#let replace-label-refs(instr, labels, addr) = {
let (op, ..args) = instr.split(" ")
args = args.join("").split(",").map(a => a.trim())
if op in ("beq", "bne", "blt", "bge", "bltu", "bgeu", "jal") {
let label = args.last()
let target = labels.at(label)
let offset = target - addr
args.last() = str(offset)
}
return op + " " + args.join(", ")
}
#let riscv-to-bin(riscv, start-address: 0) = {
let src = riscv
if type(riscv) == raw or type(riscv) == content {
src = riscv.text
}
let lines = src.split("\n")
.map(l => l.split("#").first().trim())
.filter(l => l.len() != 0)
let labels = (:)
let addr = start-address
let lines2 = ()
let addresses = ()
for line in lines {
let set-addr = none
if line.starts-with("0x") {
let rest
(set-addr, ..rest) = line.split(" ")
line = rest.join(" ")
addr = eval(set-addr)
}
if ":" in line {
let label
(label, line) = line.split(":")
labels.insert(label, addr)
line = line.trim()
if line.len() == 0 {
continue
}
}
lines2.push(line.trim())
addresses.push(addr)
if set-addr == none {
addr += 4
}
}
let cells = ()
for (line, addr) in lines2.zip(addresses) {
let instr = replace-label-refs(line, labels, addr)
let encoded = instr-to-bin(instr)
let addr-txt = "0x" + zfill(str(addr, base: 16), 8)
let code-txt = "0x" + zfill(str(encoded.code, base: 16), 8)
addr-txt = raw(addr-txt)
addr-txt = text(addr-txt, fill: colors.address)
let label = ""
if addr in labels.values() {
label = labels.pairs().filter(p => p.last() == addr).first().first()
label += ":"
}
label = text(raw(label), fill: colors.label)
cells.push(addr-txt)
cells.push(label)
cells.push(raw(code-txt))
cells.push(color-instruction(line))
}
table(
align: left + horizon,
stroke: none,
columns: 4,
inset: 5pt,
..cells
)
}

BIN
misc/riscv/riscv_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
misc/riscv/riscv_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
misc/riscv/riscv_3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

BIN
misc/uml/main.pdf Normal file

Binary file not shown.

104
misc/uml/main.typ Normal file
View File

@ -0,0 +1,104 @@
#import "uml.typ"
#set page(width: auto, height: auto, margin: 1cm)
#uml.diagram({
import uml: *
class("Person", abstract, {
attr("name", "str")
attr("phoneNumber", "str")
attr("emailAddress", "str")
method("purchaseParkingPass")
})
class("Address", {
attr("street", "str")
attr("city", "str")
attr("state", "str")
attr("postalCode", "int")
attr("country", "str")
method("validate", "bool", private)
method("outputAsLabel", "str")
})
class("Student", {
attr("studentNumber", "int")
attr("averageMark", "int")
method("isEligibleToEnroll", "bool", ("str",))
method("getSeminarsTaken", "int")
})
class("Professor", {
attr("salary", "int", package)
attr("staffNumber", "int", protected)
attr("yearsOfService", "int", private)
attr("numberOfClasses", "int")
})
})
#pagebreak()
#uml.diagram({
import uml: *
class("Pageable", interface, {
attr("UNKNOWN_N_OF_PAGES", "int", default: -1)
})
class("SQLStatement", {
method("executeQuery", "ResultSet", (sql: "String"))
method("isPoolable", "Boolean")
method("getQueryTimeout", "int")
method("clearWarnings")
})
class("SearchService", {
attr("config", "Configuration", private)
attr("engine", "SearchEngine", private)
method("search", "SearchResult", (query: "SearchRequest"))
method("createEngine", "SearchEngine", private, static)
})
class("SearchService", grouped: true, {
attr("config", "Configuration", private)
attr("engine", "SearchEngine", private)
method("search", "SearchResult", (query: "SearchRequest"))
method("createEngine", "SearchEngine", private, static)
})
})
#pagebreak()
#import "parser.typ": parse
#parse(```
@class-grouped=true
class Button {
-theController : Controller*
+press() : void
+setTheController(p : Controller*) : void
}
abstract class Controller {
-theLight : Light*
-lampState : boolean
+evButtonPressed() : void
+setTheLight(p : Light*) : void
-toggle() : void
}
class Light {
+on() : void
+off() : void
}
```)
#pagebreak()
#parse(```
class City {
+resources: HashMap[ResourceType, Int]
+globalHappiness: Double
}
abstract class Building {
+getResourcesOnBuilt(): HashMap[ResourceType, Int]
}
```)

94
misc/uml/parser.typ Normal file
View File

@ -0,0 +1,94 @@
#import "uml.typ"
#let parse-args(data) = {
let args = data.split(",").map(a => a.trim()).filter(a => a.len() != 0)
let res
if ":" in data {
res = (:)
} else {
res = ()
}
for arg in args {
let parts = arg.split(":")
let arg-name = none
let arg-type
if parts.len() == 1 {
if type(res) == dictionary {
panic("Cannot mix named and unnamed arguments")
}
arg-type = parts.first().trim()
res.push(arg-type)
} else {
arg-name = parts.first().trim()
arg-type = parts.slice(1).join(":").trim()
res.insert(arg-name, arg-type)
}
}
return res
}
#let parse(data) = {
let elements = ()
if type(data) == raw or type(data) == content {
data = data.text
}
let classes = data.matches(regex("(?ms)(abstract class|class|interface) (.*?)\s*\{(.*?)\}"))
for class in classes {
let family-name = class.captures.first()
let family = (
class: none,
"abstract class": uml.abstract,
"interface": uml.interface,
"enum": uml.enum,
).at(family-name)
let name = class.captures.at(1)
let class-data = class.captures.last().trim()
let members = class-data.matches(regex("(?m)^\s*(.*?)\s*(:\s*([^:]*?))?$")).filter(m => m.text.len() != 0)
let attributes = ()
let methods = ()
for member in members {
let member-name = member.captures.first()
let val-type = member.captures.last()
let visibility = none
if member-name.starts-with(regex("\+|-|~|#")) {
let vis = member-name.first()
member-name = member-name.slice(1)
visibility = (
"+": uml.public,
"-": uml.private,
"~": uml.package,
"#": uml.protected
).at(vis)
}
if member-name.ends-with(")") {
let func = member-name.match(regex("^(.*?)\((.*)\)$"))
member-name = func.captures.first()
let args = parse-args(func.captures.last())
methods += uml.method(member-name, visibility, val-type, args)
} else {
attributes += uml.attr(member-name, visibility, val-type)
}
}
elements += uml.class(name, family, attributes + methods)
}
let defaults = (:)
let params = data.matches(regex("(?m)^\s*@\s*(.*?)\s*=\s*(.*)\s*$"))
for param in params {
let key = param.captures.first()
let value = eval(param.captures.last(), scope: (uml: uml))
defaults.insert(key, value)
}
return uml.diagram(elements, defaults)
}

569
misc/uml/uml.typ Normal file
View File

@ -0,0 +1,569 @@
#import "@preview/cetz:0.2.2": canvas, draw
#let class-counter = counter("uml-class")
#let class-colors = (
rgb("#C02B22"),
rgb("#D4721C"),
rgb("D3BC2F"),
rgb("60CB12"),
rgb("#2ECC40"),
rgb("#39CCA5"),
rgb("#38B4DA"),
rgb("#0074d9"),
rgb("#450DC9"),
rgb("#890DC9"),
)
#let visibility(vis, symbol) = (type: "visibility", visibility: vis, symbol: symbol)
#let public = visibility("public", "+")
#let private = visibility("private", "-")
#let protected = visibility("protected", "#")
#let package = visibility("package", "~")
#let class-family(family, prefix: none) = (
type: "class-family",
family: family,
prefix: prefix
)
#let abstract = class-family("abstract")
#let interface = class-family("interface", prefix: "interface")
#let trait = class-family("trait")
#let enum = class-family("enum")
#let utility = class-family("utility", prefix: "utility")
#let staticity(static) = (type: "staticity", static: static)
#let static = staticity(true)
#let non-static = staticity(false)
#let class(name, ..args, grouped: none) = {
let attributes = ()
let methods = ()
let visibility = none
let family = none
let args = args.pos()
if args.len() != 0 {
for arg in args {
if type(arg) == dictionary {
if arg.type == "visibility" {
visibility = arg
} else if arg.type == "class-family" {
family = arg
}
} else if type(arg) == array {
for elmt in arg {
if type(elmt) == dictionary {
if elmt.type == "visibility" {
visibility = elmt
} else if elmt.type == "attribute" {
attributes.push(elmt)
} else if elmt.type == "method" {
methods.push(elmt)
}
}
}
}
}
}
return ((
type: "class",
name: name,
visibility: visibility,
family: family,
attributes: attributes,
methods: methods,
color: rgb(184, 84, 80),
grouped: grouped
),)
}
#let attr(name, default: none, ..args) = {
let visibility = none
let staticity = none
let val-type = none
for arg in args.pos() {
if type(arg) == dictionary {
if arg.type == "visibility" {
visibility = arg
} else if arg.type == "type" {
val-type = arg
} else if arg.type == "staticity" {
staticity = staticity
}
} else if type(arg) == str {
val-type = arg
}
}
return ((
type: "attribute",
name: name,
visibility: visibility,
staticity: staticity,
val-type: val-type,
default: default
),)
}
#let method(name, ..args) = {
let visibility = none
let staticity = none
let parameters = none
let return-type = none
for arg in args.pos() {
if type(arg) == dictionary {
if "type" in arg {
if arg.type == "visibility" {
visibility = arg
} else if arg.type == "staticity" {
staticity = arg
}
} else {
parameters = arg
}
} else if type(arg) == str {
return-type = arg
} else if type(arg) == array {
parameters = arg
}
}
return ((
type: "method",
name: name,
visibility: visibility,
staticity: staticity,
parameters: parameters,
return-type: return-type
),)
}
#let render-attr(attr, defaults, show-visibility: true) = {
let visibility = if attr.visibility == none {
defaults.attr-visibility
} else {
attr.visibility
}
let staticity = if attr.staticity == none {
defaults.attr-staticity
} else {
attr.staticity
}
let name = attr.name
if staticity.static {
name = underline(name)
}
let txt = name
if show-visibility {
txt = visibility.symbol + txt
}
if attr.val-type != none {
txt += ": " + attr.val-type
}
if attr.default != none {
txt += " = " + str(attr.default)
}
return txt
}
#let render-method(method, defaults, show-visibility: true) = {
let visibility = if method.visibility == none {
defaults.method-visibility
} else {
method.visibility
}
let staticity = if method.staticity == none {
defaults.method-staticity
} else {
method.staticity
}
let params = ()
if type(method.parameters) == array {
params = method.parameters
} else if type(method.parameters) == dictionary {
params = method.parameters
.pairs()
.map(((n, t)) => n + ": " + t)
}
let name = method.name
if staticity.static {
name = underline(name)
}
let txt = name
if show-visibility {
txt = visibility.symbol + txt
}
txt += "(" + params.join(", ") + ")"
if method.return-type != none {
txt += ": " + method.return-type
}
return txt
}
#let get-attributes-by-visibility(class, defaults) = {
let by-vis = (:)
for attr in class.attributes {
let visibility = if attr.visibility == none {
defaults.attr-visibility
} else {
attr.visibility
}
if not visibility.visibility in by-vis {
by-vis.insert(visibility.visibility, ())
}
by-vis.at(visibility.visibility).push(attr)
}
return by-vis
}
#let get-methods-by-visibility(class, defaults) = {
let by-vis = (:)
for method in class.methods {
let visibility = if method.visibility == none {
defaults.method-visibility
} else {
method.visibility
}
if not visibility.visibility in by-vis {
by-vis.insert(visibility.visibility, ())
}
by-vis.at(visibility.visibility).push(method)
}
return by-vis
}
#let render-class-attributes(class, defaults) = {
let grouped = if class.grouped == none {
defaults.class-grouped
} else {
class.grouped
}
let cells = ()
if not grouped {
for attr in class.attributes {
cells.push(render-attr(attr, defaults, show-visibility: true))
}
} else {
let by-vis = get-attributes-by-visibility(class, defaults)
for (vis, attrs) in by-vis {
cells.push(table.cell(vis + ":"))
cells += attrs.map(attr => {
let txt = render-attr(attr, defaults, show-visibility: false)
pad(left: 1em, txt)
})
}
}
return cells
}
#let render-class-methods(class, defaults) = {
let grouped = if class.grouped == none {
defaults.class-grouped
} else {
class.grouped
}
let cells = ()
if not grouped {
for method in class.methods {
cells.push(render-method(method, defaults, show-visibility: true))
}
} else {
let by-vis = get-methods-by-visibility(class, defaults)
for (vis, attrs) in by-vis {
cells.push(table.cell(vis + ":"))
cells += attrs.map(method => {
let txt = render-method(method, defaults, show-visibility: false)
pad(left: 1em, txt)
})
}
}
return cells
}
#let render-class(class, defaults) = context {
let family = if class.family == none {
defaults.class-family
} else {
class.family
}
let cells = ()
cells += render-class-attributes(class, defaults)
cells.push(table.hline())
cells += render-class-methods(class, defaults)
let name = [*#class.name*]
let family = class.family
if family == abstract {
name = emph(name)
}
if family != none and family.prefix != none {
name = [*«#family.prefix»*\ #name]
}
let class-i = class-counter.get().first()
let col = class-colors.at(calc.rem(class-i, class-colors.len()))
set table.hline(stroke: col)
table(
inset: (top: 0.5em, bottom: 0.5em, left: 0.5em, right: 0.5em),
stroke: (x, y) => {
let s = (left: col, right: col)
if y == 0 {
s.insert("top", col)
s.insert("bottom", col)
}
return s
},
align: (x, y) => {
if y == 0 {
return center + horizon
}
return left + horizon
},
fill: (x, y) => if y == 0 {
col.lighten(75%)
} else {
none
},
table.header(name),
..cells,
table.hline()
)
class-counter.step()
}
#let diagram(..args) = {
class-counter.update(0)
let args = args.pos()
let defaults = (
class-family: none,
class-grouped: false,
attr-visibility: public,
attr-staticity: non-static,
method-visibility: public,
method-staticity: non-static,
)
let elements = ()
if args.len() != 0 {
for arg in args {
if type(arg) == dictionary {
defaults += arg
} else if type(arg) == array {
elements = arg
}
}
}
let cells = ()
for element in elements {
if element.type == "class" {
cells.push(render-class(element, defaults))
}
}
box(
stroke: black,
inset: 1em,
grid(
columns: 2,
column-gutter: 1em,
align: center + horizon,
row-gutter: 1em,
..cells
)
)
}
#let render-attr2(pos, id, attr, defaults, show-visibility: true) = {
let visibility = if attr.visibility == none {
defaults.attr-visibility
} else {
attr.visibility
}
let staticity = if attr.staticity == none {
defaults.attr-staticity
} else {
attr.staticity
}
let name = attr.name
if staticity.static {
name = underline(name)
}
let txt = name
if show-visibility {
txt = visibility.symbol + txt
}
if attr.val-type != none {
txt += ": " + attr.val-type
}
if attr.default != none {
txt += " = " + str(attr.default)
}
draw.content(pos, txt, name: id)
}
#let render-method2(method, defaults, show-visibility: true) = {
let visibility = if method.visibility == none {
defaults.method-visibility
} else {
method.visibility
}
let staticity = if method.staticity == none {
defaults.method-staticity
} else {
method.staticity
}
let params = ()
if type(method.parameters) == array {
params = method.parameters
} else if type(method.parameters) == dictionary {
params = method.parameters
.pairs()
.map(((n, t)) => n + ": " + t)
}
let name = method.name
if staticity.static {
name = underline(name)
}
let txt = name
if show-visibility {
txt = visibility.symbol + txt
}
txt += "(" + params.join(", ") + ")"
if method.return-type != none {
txt += ": " + method.return-type
}
draw.content((), txt)
}
#let render-class-attributes2(class, defaults) = {
let grouped = if class.grouped == none {
defaults.class-grouped
} else {
class.grouped
}
let cells = ()
let prev = ()
if not grouped {
for (i, attr) in class.attributes.enumerate() {
let id = "class-"+class.name+"-attr-"+str(i)
let txt = render-attr(attr, defaults, show-visibility: true)
draw.content((rel: (0, -0.4em), to: prev), name: id, anchor: "north-west", txt)
prev = id + ".south-west"
}
} else {
let by-vis = get-attributes-by-visibility(class, defaults)
for (vis, attrs) in by-vis {
cells.push(table.cell(vis + ":"))
let vis-id = "class-"+class.name+"-attrs-"+vis
draw.content((rel: (0, -0.4em), to: prev), name: vis-id, anchor: "north-west", vis + ":")
prev = vis-id + ".south-west"
for (i, attr) in attrs.enumerate() {
let txt = render-attr(attr, defaults, show-visibility: false)
txt = pad(left: 1em, txt)
let id = vis-id + "-" + str(i)
draw.content((rel: (0, -0.4em), to: prev), name: id, anchor: "north-west", txt)
prev = id + ".south-west"
}
}
}
}
#let render-class-methods2(class, defaults) = {
}
#let render-class2(class, defaults) = {
let attr-group = render-class-attributes2(class, defaults)
let method-group = render-class-methods2(class, defaults)
let family = if class.family == none {
defaults.class-family
} else {
class.family
}
let name = [*#class.name*]
let family = class.family
if family == abstract {
name = emph(name)
}
if family != none and family.prefix != none {
name = [*«#family.prefix»*\ #name]
}
let class-i = class-counter.get().first()
let col = class-colors.at(calc.rem(class-i, class-colors.len()))
draw.group(name: "class-"+class.name, {
draw.group(name: "class-"+class.name+"-name", padding: 5pt, {
draw.content((), name)
})
draw.on-layer(-1, {
draw.rect("class-"+class.name+"-name.north-west", "class-"+class.name+"-name.south-east", fill: col.lighten(75%), stroke: col, layer: -1)
})
draw.group(name: "class-"+class.name+"-attrs", padding: 0.2em, {
attr-group
})
method-group
})
draw.rect("class-"+class.name+".north-west", "class-"+class.name+".south-east", stroke: col)
}
#let render-class3(class, defaults) = {
let id = "class-" + class.name
return draw.content((rel: (3, 0), to: ()), render-class(class, defaults), name: id)
}
#let diagram2(..args) = context {
class-counter.update(0)
let args = args.pos()
let defaults = (
class-family: none,
class-grouped: false,
attr-visibility: public,
attr-staticity: non-static,
method-visibility: public,
method-staticity: non-static,
)
let elements = ()
if args.len() != 0 {
for arg in args {
if type(arg) == dictionary {
defaults += arg
} else if type(arg) == array {
elements = arg
}
}
}
let cells = ()
canvas({
for element in elements {
if element.type == "class" {
render-class3(element, defaults)
}
}
draw.line("class-Test", "class-Essai", mark: (end: "diamond", scale: 2))
})
}