Skip to content

Commit 34afbba

Browse files
spec: update TOC (#478)
* spec: add chapters * spec: clean up toc * spec: separate ecalls * Fixes for shiroa * Reformat ebook.typ a bit --------- Co-authored-by: Robin Jadoul <robin.jadoul@3milabs.tech>
1 parent 6eecb98 commit 34afbba

5 files changed

Lines changed: 169 additions & 102 deletions

File tree

spec/about_ecalls.typ

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#import "/book.typ": book-page, aside
2+
#import "/src.typ": load_config, load_chip
3+
#import "/chip.typ": (
4+
render_chip_column_table,
5+
total_nr_variables,
6+
total_nr_instantiated_columns,
7+
render_constraint_table,
8+
render_chip_assumptions,
9+
render_chip_padding_table,
10+
)
11+
12+
#let config = load_config()
13+
14+
#show: book-page("about_ecalls.typ")
15+
16+
ECALLs provide system-level functionalities to the guest program.
17+
18+
When `ECALL` is executed, it is assumed that:
19+
- register `A7` contains the system call number
20+
#footnote([The RISC-V system call ABI; libriscv.no, #link("https://web.archive.org/web/20260128152107/https://libriscv.no/docs/concepts/syscalls/#the-risc-v-system-call-abi")[[src]]]),
21+
- the arguments are located in registers `A0`-`A6`, and
22+
- the return value is written to `A0`,
23+
where `A0`-`A7` are symbolic names for the registers `x10`-`x17`
24+
#footnote([RISC-V - Register sets; en.wikipedia.org, #link("https://web.archive.org/web/20260209053447/https://en.wikipedia.org/wiki/RISC-V#Register_sets")[[src]]]).

spec/book.typ

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,53 @@
88
authors: ("3MI Labs", "Aligned"),
99
version: "0.2",
1010
summary: (
11-
("logup.typ", [LogUp argument], <logup>),
12-
("memory.typ", [Memory argument], <memory>),
13-
("variables.typ", [Variables], <vars>),
14-
("signatures.typ", [Signatures], <signatures>),
15-
("is_bit.typ", [IS_BIT template], <isbit>),
16-
("sign.typ", [SIGN template], <sign>),
17-
("add.typ", [ADD/SUB template], <add>),
18-
("neg.typ", [NEG template], <neg>),
19-
("decode.typ", [DECODE table], <decode>),
20-
("cpu.typ", [CPU chip], <cpu>),
21-
("shift.typ", [SHIFT chip], <shift>),
22-
("branch.typ", [BRANCH chip], <branch>),
23-
("memw.typ", [MEMW chip], <memw>),
24-
("lt.typ", [LT chip], <lt>),
25-
("mul.typ", [MUL chip], <mul>),
26-
("dvrm.typ", [DVRM chip], <dvrm>),
27-
("load.typ", [LOAD chip], <load>),
28-
("ecall.typ", [ECALL chips], <ecall>),
29-
("bitwise.typ", [BITWISE chips], <bitwise>),
11+
("PROOF SYSTEM", (
12+
("logup.typ", [LogUp argument], <logup>),
13+
("memory.typ", [Memory argument], <memory>),
14+
)),
15+
("OVERVIEW", (
16+
("variables.typ", [Variables], <vars>),
17+
("signatures.typ", [Signatures], <signatures>),
18+
)),
19+
("TEMPLATES", (
20+
("is_bit.typ", [IS_BIT template], <isbit>),
21+
("sign.typ", [SIGN template], <sign>),
22+
("add.typ", [ADD/SUB template], <add>),
23+
("neg.typ", [NEG template], <neg>),
24+
)),
25+
("MEMORY", (
26+
("memw.typ", [MEMW chip], <memw>),
27+
)),
28+
("CPU", (
29+
("decode.typ", [DECODE table], <decode>),
30+
("cpu.typ", [CPU chip], <cpu>),
31+
)),
32+
("ALU", (
33+
("shift.typ", [SHIFT chip], <shift>),
34+
("branch.typ", [BRANCH chip], <branch>),
35+
("lt.typ", [LT chip], <lt>),
36+
("mul.typ", [MUL chip], <mul>),
37+
("dvrm.typ", [DVRM chip], <dvrm>),
38+
("load.typ", [LOAD chip], <load>),
39+
("bitwise.typ", [BITWISE chips], <bitwise>),
40+
)),
41+
("ECALLS", (
42+
("about_ecalls.typ", [About ECALL], <ecall>),
43+
("halt.typ", [HALT chip], <halt>),
44+
("commit.typ", [COMMIT chip], <commit>),
45+
))
3046
)
3147
)
48+
#let meta_sections = meta.summary.map(m => m.at(1)).sum()
3249
#book-meta(
3350
title: meta.title,
3451
authors: meta.authors,
35-
summary: prefix-chapter("front.typ", meta.title) + meta.summary.map(((ch, title, _ref)) => chapter(ch, title)).join()
52+
summary: prefix-chapter("front.typ", meta.title)
53+
+ meta.summary.map(
54+
((title, sections)) => {
55+
heading(depth: 1, title) + sections.map(((ch, title, _ref)) => chapter(ch, title)).join()
56+
}
57+
).join()
3658
)
3759

3860
#let common-formatting(body) = {
@@ -93,11 +115,11 @@
93115
#let xref(rf) = {
94116
assert(is-shiroa, message: "xref should only be used when compiling for shiroa")
95117
let lbl = rf.target
96-
let found = meta.summary.find(((_, _, tag)) => str(lbl).starts-with(str(tag)))
118+
let found = meta_sections.find(((_, _, tag)) => str(lbl).starts-with(str(tag)))
97119
context if found != none and found.at(0) != _toplevel.final() {
98120
let (ch, title, ref) = found
99121
if ref == lbl {
100-
cross-link("/" + ch, [Chapter #(meta.summary.position(x => x == found) + 1)])
122+
cross-link("/" + ch, [Chapter #(meta_sections.position(x => x == found) + 1)])
101123
} else {
102124
// Because shiroa does weird url escaping
103125
let shiroa-label = label(str(lbl).replace(":", "%3A"))
@@ -130,12 +152,12 @@
130152
}
131153

132154
#let book-page(file, ..args) = {
133-
let file = if file.ends-with(".typ") {
134-
file
135-
} else {
136-
lower(file) + ".typ"
155+
if not file.ends-with(".typ") {
156+
file = lower(file) + ".typ"
137157
}
138-
assert(meta.summary.find(((f, __)) => f == file) != none, message: "Couldn't resolve typst source file " + file)
158+
159+
assert(meta_sections.find(s => s.at(0) == file) != none, message: "Couldn't resolve typst source file " + file)
160+
139161
if is-shiroa {
140162
(body) => {
141163
show: common-formatting
@@ -147,7 +169,7 @@
147169
}
148170
})
149171
let cond() = _toplevel.final() == file
150-
project.with(..args, title: context meta.summary.find(x => x.at(0) == _toplevel.final()).at(1), cond: cond)([
172+
project.with(..args, title: context meta_sections.find(x => x.at(0) == _toplevel.final()).at(1), cond: cond)([
151173
#show ref: it => context if _toplevel.final() == file {
152174
xref(it)
153175
}

spec/ecall.typ renamed to spec/commit.typ

Lines changed: 7 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -10,80 +10,21 @@
1010
render_chip_padding_table,
1111
)
1212

13-
#let config = load_config()
14-
15-
#show: book-page("ecall.typ")
16-
17-
ECALLs provide system-level functionalities to the guest program.
18-
19-
When `ECALL` is executed, it is assumed that:
20-
- register `A7` contains the system call number
21-
#footnote([The RISC-V system call ABI; libriscv.no, #link("https://web.archive.org/web/20260128152107/https://libriscv.no/docs/concepts/syscalls/#the-risc-v-system-call-abi")[[src]]]),
22-
- the arguments are located in registers `A0`-`A6`, and
23-
- the return value is written to `A0`,
24-
where `A0`-`A7` are symbolic names for the registers `x10`-`x17`
25-
#footnote([RISC-V - Register sets; en.wikipedia.org, #link("https://web.archive.org/web/20260209053447/https://en.wikipedia.org/wiki/RISC-V#Register_sets")[[src]]]).
26-
27-
28-
#let config = load_config()
29-
#let chip = load_chip("src/halt.toml", config)
30-
#let halt = raw(chip.name)
31-
= #halt chip
32-
33-
== Columns
34-
#let nr_variables = total_nr_variables(chip)
35-
#let nr_columns = total_nr_instantiated_columns(chip, config)
36-
#let nr_halt_interactions = compute_nr_interactions(chip)
37-
38-
The #halt chip leverages #nr_variables variable, spanning #nr_columns columns and leverages #nr_halt_interactions interaction(s):
39-
#render_chip_column_table(chip, config)
40-
41-
== Assumptions
42-
It is assumed the input is range checked:
43-
#render_chip_assumptions(chip, config)
44-
45-
== Constraints
46-
The #halt chip:
47-
+ makes sure register `x10` (containing the exit code) equals $0$ (@halt:c:read_zero_exit_code),
48-
+ writes $0$ to all other registers (@halt:c:zeroize_registers_lo/@halt:c:zeroize_registers_hi), and
49-
+ sets `pc` equal to $1$ (@halt:c:pc).
50-
Note that the writes performed by all these interactions are accompanied by the timestamp $2^64-1$; the maximum timestamp.
51-
This prevents any other operation involving memory from being executed hereafter.
52-
#render_constraint_table(chip, config, groups: "all")
53-
54-
#aside("Note on register clean up",
55-
[
56-
Observe that --- in its current state --- this solution puts the burden of verifying the register cleanup on the verifier inside of the lookup argument.
57-
Alternatively, one could add 31 lookups to the "memory" table to remove the _known_ final tokens for the registers there.
58-
])
59-
60-
=== Lookup
61-
In this VM, halting is considered equivalent to executing a `sys_exit`.
62-
Hence, this chip responds to `ECALL`s with system call number 93.
63-
#footnote([RISC-V GNU-toolchain, `unistd.h`; version 2026-01-23, #link("https://github.com/riscv-collab/riscv-gnu-toolchain/blob/2026.01.23/linux-headers/include/asm-generic/unistd.h#L258")[[src]]])
64-
The HALT chip therefore contributes the following interaction to the lookup-argument:
65-
#render_constraint_table(chip, config, groups: "lookup")
66-
67-
== Padding
68-
This chip should only contain a single row.
69-
Given that $2^0 = 1$, this chip does not need to be padded.
70-
As such, no padding is defined.
71-
13+
#show: book-page("commit.typ")
7214

7315
#let config = load_config()
7416
#let chip = load_chip("src/commit.toml", config)
7517
#let commit = raw(chip.name)
76-
= #commit chip
7718

78-
== Columns
19+
= Columns
7920
#let nr_variables = total_nr_variables(chip)
8021
#let nr_columns = total_nr_instantiated_columns(chip, config)
81-
#let nr_commit_interactions = compute_nr_interactions(chip)
22+
#let nr_interactions = compute_nr_interactions(chip)
8223

83-
The #commit chip leverages #nr_variables variables, spanning #nr_columns columns and leverages #nr_commit_interactions interactions:
24+
The #commit chip leverages #nr_variables variables, spanning #nr_columns columns and leverages #nr_interactions interactions:
8425
#render_chip_column_table(chip, config)
8526

86-
== Constraints
27+
= Constraints
8728
In this VM, committing is considered equivalent to writing a value to `stdout`.
8829
Hence, this chip responds to `ECALL`s with system call number 64.
8930
#footnote([RISC-V GNU-toolchain, `unistd.h`; version 2026-01-23, #link("https://github.com/riscv-collab/riscv-gnu-toolchain/blob/2026.01.23/linux-headers/include/asm-generic/unistd.h#L174")[[src]]])
@@ -152,11 +93,11 @@ Lastly, we must make sure `first`, `end` and `μ` are bits (@commit:c:range_firs
15293
These are required to ensure the multiplicities $-(#`μ` - #`first`)$ and $#`μ` - #`end`$ are binary.
15394
#render_constraint_table(chip, config, groups: "bits")
15495

155-
== Padding
96+
= Padding
15697
To pad this chip, use the below data.
15798
#render_chip_padding_table(chip, config)
15899

159-
== Notes/optimizations
100+
= Notes/optimizations
160101
- The current version only supports writing to `stdout`.
161102
This chip could potentially be extended to support writing to arbitrary `fd`s
162103
- One might be able to replace @commit:c:end by `end => count = 0`.

spec/ebook.typ

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,39 @@
66
#align(center, text(style: "italic", fill: luma(40%))[Version #meta.version])
77
#align(center, meta.authors.join(", "))
88
#pagebreak(weak: true)
9-
#outline()
9+
10+
// outline
11+
#show outline.entry.where(level: 1): set outline.entry(fill: line(length: 100%, stroke: stroke(dash: "solid")))
12+
#show outline.entry.where(level: 1): it => {
13+
v(15pt, weak: true)
14+
strong(it)
15+
v(5pt, weak: true)
16+
}
17+
#show outline.entry.where(level: 2): it => {
18+
v(10pt, weak: true)
19+
it
20+
}
21+
#outline(depth: 3)
22+
23+
// chapter pages
24+
#show heading.where(level: 1): it => align(center + horizon)[#underline(it, offset: 10pt, extent: 5pt)]
1025

1126
#show: common-formatting
12-
#show heading: set heading(numbering: "1.1")
27+
#show heading: set heading(numbering: (..args) => {
28+
let args = args.pos()
29+
let skip_first = args.slice(calc.min(args.len(), 1))
30+
numbering("1.1", ..skip_first)
31+
})
1332
#show raw.where(block: true): set block(fill: luma(230))
1433

15-
#meta.summary.map(((ch, title, ref)) => [
16-
#pagebreak(weak: true)
17-
#heading(supplement: [Chapter], level: 1, title)#ref
18-
#set heading(offset: 1)
19-
#include ch
20-
]).join()
34+
#for (ch_title, sections) in meta.summary {
35+
pagebreak(weak: true)
36+
heading(supplement: [Chapter], level: 1, ch_title, numbering: none)
37+
38+
for (sec, sec_title, ref) in sections {
39+
pagebreak(weak: true)
40+
[#heading(level: 2, supplement: [Section], sec_title)#ref]
41+
set heading(offset: 2)
42+
include sec
43+
}
44+
}

spec/halt.typ

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#import "/book.typ": book-page, aside
2+
#import "/src.typ": load_config, load_chip
3+
#import "/chip.typ": (
4+
render_chip_column_table,
5+
total_nr_variables,
6+
total_nr_instantiated_columns,
7+
compute_nr_interactions,
8+
render_constraint_table,
9+
render_chip_assumptions,
10+
render_chip_padding_table,
11+
)
12+
13+
#show: book-page("halt.typ")
14+
15+
#let config = load_config()
16+
#let chip = load_chip("src/halt.toml", config)
17+
#let halt = raw(chip.name)
18+
19+
= Columns
20+
#let nr_variables = total_nr_variables(chip)
21+
#let nr_columns = total_nr_instantiated_columns(chip, config)
22+
#let nr_interactions = compute_nr_interactions(chip)
23+
24+
The #halt chip leverages #nr_variables variable, spanning #nr_columns columns and leverages #nr_interactions interactions::
25+
#render_chip_column_table(chip, config)
26+
27+
= Assumptions
28+
It is assumed the input is range checked:
29+
#render_chip_assumptions(chip, config)
30+
31+
= Constraints
32+
The #halt chip:
33+
+ makes sure register `x10` (containing the exit code) equals $0$ (@halt:c:read_zero_exit_code),
34+
+ writes $0$ to all other registers (@halt:c:zeroize_registers_lo/@halt:c:zeroize_registers_hi), and
35+
+ sets `pc` equal to $1$ (@halt:c:pc).
36+
Note that the writes performed by all these interactions are accompanied by the timestamp $2^64-1$; the maximum timestamp.
37+
This prevents any other operation involving memory from being executed hereafter.
38+
#render_constraint_table(chip, config, groups: "all")
39+
40+
#aside("Note on register clean up",
41+
[
42+
Observe that --- in its current state --- this solution puts the burden of verifying the register cleanup on the verifier inside of the lookup argument.
43+
Alternatively, one could add 31 lookups to the "memory" table to remove the _known_ final tokens for the registers there.
44+
])
45+
46+
== Lookup
47+
In this VM, halting is considered equivalent to executing a `sys_exit`.
48+
Hence, this chip responds to `ECALL`s with system call number 93.
49+
#footnote([RISC-V GNU-toolchain, `unistd.h`; version 2026-01-23, #link("https://github.com/riscv-collab/riscv-gnu-toolchain/blob/2026.01.23/linux-headers/include/asm-generic/unistd.h#L258")[[src]]])
50+
The HALT chip therefore contributes the following interaction to the lookup-argument:
51+
#render_constraint_table(chip, config, groups: "lookup")
52+
53+
= Padding
54+
This chip should only contain a single row.
55+
Given that $2^0 = 1$, this chip does not need to be padded.
56+
As such, no padding is defined.

0 commit comments

Comments
 (0)