diff --git a/CHANGELOG.md b/CHANGELOG.md index fa4eb7c..cc083ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [v0.3.1] - 2026-06-14 +- Support for non-consecutive ranges ([#13](https://git.kb28.ch/HEL/rivet-typst/pulls/13)) +- Prevent drawing separators on starting lines of fields ([#17](https://git.kb28.ch/HEL/rivet-typst/pulls/17)) +- Fix end line on non-consecutive ranges ending at the highest bit not being draw ([#18](https://git.kb28.ch/HEL/rivet-typst/pulls/18)) +- Add documentation for `start` property of structures ([61f13df815f](https://git.kb28.ch/HEL/rivet-typst/commit/6f13df815f99fd6be8b6b3a02b4d53bcc8fe0aff)) + ## [v0.3.0] - 2025-05-03 - updated CeTZ to 0.3.4 - updated to Typst 0.13.1 diff --git a/README.md b/README.md index a928135..5eb5249 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ It is based on the [homonymous Python script](https://git.kb28.ch/HEL/rivet/) - + A black on white diagram showing the bit structure of a machine instruction, detailing operands, flags and selectors. @@ -19,7 +19,7 @@ It is based on the [homonymous Python script](https://git.kb28.ch/HEL/rivet/) - + A white on blue diagram showing the bit structure of RISC-V memory instructions, detailing operands, flags and selectors. @@ -35,7 +35,7 @@ For more information, see the [manual](manual.pdf) To use this package, simply import `schema` from [rivet](https://typst.app/universe/package/rivet) and call `schema.load` to parse a schema description. Then use `schema.render` to render it, et voilĂ  ! ```typ -#import "@preview/rivet:0.3.0": schema -#let doc = schema.load("path/to/schema.yaml") +#import "@preview/rivet:0.3.1": schema +#let doc = schema.load(yaml("path/to/schema.yaml")) #schema.render(doc) ``` \ No newline at end of file diff --git a/gallery/example1.pdf b/gallery/example1.pdf index 96dbf60..22d52c8 100644 Binary files a/gallery/example1.pdf and b/gallery/example1.pdf differ diff --git a/gallery/example1.typ b/gallery/example1.typ index bfb9ca0..17e095b 100644 --- a/gallery/example1.typ +++ b/gallery/example1.typ @@ -1,6 +1,6 @@ -#import "../src/lib.typ": schema, config +#import "@preview/rivet:0.3.1": schema, config -#let example = schema.load("/gallery/example1.yaml") +#let example = schema.load(yaml("./example1.yaml")) #schema.render(example, config: config.config( full-page: true )) \ No newline at end of file diff --git a/gallery/example2.pdf b/gallery/example2.pdf index ee09bba..0692021 100644 Binary files a/gallery/example2.pdf and b/gallery/example2.pdf differ diff --git a/gallery/example2.typ b/gallery/example2.typ index 012dd9b..0fddad6 100644 --- a/gallery/example2.typ +++ b/gallery/example2.typ @@ -1,6 +1,6 @@ -#import "../src/lib.typ": schema, config +#import "@preview/rivet:0.3.1": schema, config -#let example = schema.load("/gallery/example2.yaml") +#let example = schema.load(yaml("./example2.yaml")) #schema.render(example, config: config.blueprint( full-page: true, left-labels: true diff --git a/gallery/example3.pdf b/gallery/example3.pdf index 0cb441b..de8082b 100644 Binary files a/gallery/example3.pdf and b/gallery/example3.pdf differ diff --git a/gallery/example3.typ b/gallery/example3.typ index cf04b43..c2f28a6 100644 --- a/gallery/example3.typ +++ b/gallery/example3.typ @@ -1,6 +1,6 @@ -#import "../src/lib.typ": schema, config +#import "@preview/rivet:0.3.1": schema, config -#let example = schema.load("/gallery/example1.yaml") +#let example = schema.load(yaml("/gallery/example1.yaml")) //#schema.render(example) = Chapter 1 diff --git a/gallery/riscv/riscv.typ b/gallery/riscv/riscv.typ index 0802ad9..7b9f3c5 100644 --- a/gallery/riscv/riscv.typ +++ b/gallery/riscv/riscv.typ @@ -1,14 +1,14 @@ -#import "../../src/lib.typ": * +#import "@preview/rivet:0.3.1": * #let conf = config.config( full-page: true, left-labels: true ) -#let alu = schema.load("/gallery/riscv/alu_instr.yaml") +#let alu = schema.load(yaml("./alu_instr.yaml")) #schema.render(alu, config: conf) -#let branch = schema.load("/gallery/riscv/branch_instr.yaml") +#let branch = schema.load(yaml("./branch_instr.yaml")) #schema.render(branch, config: conf) -#let mem = schema.load("/gallery/riscv/mem_instr.yaml") +#let mem = schema.load(yaml("./mem_instr.yaml")) #schema.render(mem, config: conf) diff --git a/gallery/test.pdf b/gallery/test.pdf index c8d4a11..929dd14 100644 Binary files a/gallery/test.pdf and b/gallery/test.pdf differ diff --git a/gallery/test.typ b/gallery/test.typ index 515a846..d5348f8 100644 --- a/gallery/test.typ +++ b/gallery/test.typ @@ -1,16 +1,17 @@ -#import "../src/lib.typ": * +#import "@preview/rivet:0.3.1": * -#let test-yaml = schema.load("/gallery/test.yaml") +#let test-yaml = schema.load(yaml("./test.yaml")) #schema.render(test-yaml, config: config.config( full-page: true )) -#let test-json = schema.load("/gallery/test.json") +#let test-json = schema.load(json("./test.json")) #schema.render(test-json, config: config.blueprint( full-page: true )) -#let test-xml = schema.load("/gallery/test.xml") +#let test-xml-raw = schema.xml-loader.parse(xml("./test.xml").first()) +#let test-xml = schema.load(test-xml-raw) #schema.render(test-xml, config: config.dark( full-page: true )) diff --git a/manual.pdf b/manual.pdf index 35debf3..6fcd811 100644 Binary files a/manual.pdf and b/manual.pdf differ diff --git a/manual.typ b/manual.typ index 6445fa4..65d75d0 100644 --- a/manual.typ +++ b/manual.typ @@ -105,7 +105,7 @@ Since the XML format is quite different from the other, you might find it helpfu A schema contains a dictionary of structures. There must be at least one defined structure named "main". -It can also optionnaly contain a "colors" dictionary. More details about this in #link()[Colors] +It can also optionally contain a "colors" dictionary. More details about this in #link()[Colors] ```json { @@ -152,6 +152,34 @@ The range name (or key) defines the left- and rightmost bits (e.g. `7-4` goes fr } ``` +=== Start + +By default, structures start at bit 0, but you may want to number bits from 1, or another arbitrary value. To do this, you can set the `start` property of a structure to the desired start value. For example, + +```json +"main": { + "bits": 8, + "start": 4, + "ranges": { + "11-7": { ... }, + "6-4": { ... } + } +} +``` + +#let start-schema = (structures: (main: (bits: 8, start: 4, ranges: ("11-7": (name: ""), "6-4": (name: ""))))) + +would render as + +#align( + center, + schema.render( + schema.load(start-schema), + width: 50% + ) +) + + == Range A range represents a group of consecutive bits. It can have a name (displayed in the bit cells), a description (displayed under the structure) and / or values. @@ -335,7 +363,7 @@ structures: #let x = schema.xml-loader.load("schema.xml") #let s = schema.load(x) // From file -#let x = schema.xml-loader.parse(yaml("schema.yaml").first()) +#let x = schema.xml-loader.parse(xml("schema.xml").first()) #let s = schema.load(x) // Raw block #let s = schema.load(```xml diff --git a/src/lib.typ b/src/lib.typ index ed44ea6..defd663 100644 --- a/src/lib.typ +++ b/src/lib.typ @@ -1,4 +1,4 @@ -#let version = version(0,3,0) +#let version = version(0,3,1) #import "config.typ" #import "schema.typ" \ No newline at end of file diff --git a/src/renderer.typ b/src/renderer.typ index 39ecb2e..ec0c3d3 100644 --- a/src/renderer.typ +++ b/src/renderer.typ @@ -387,8 +387,10 @@ } let range-boundaries = () for r in struct.ranges.values() { - let i = to-real-i(if config.ltr-bits {r.start} else {r.end}) - range-boundaries.push(i) + let start-i = to-real-i(if config.ltr-bits {r.start} else {r.end}) + let end-i = to-real-i(if config.ltr-bits {r.end} else {r.start}) + 1 + range-boundaries.push(start-i) + range-boundaries.push(end-i) } // Draw colors @@ -407,6 +409,11 @@ indices.push(r.start) indices.push(r.end) } + // ensure first and last bits are included + if not indices.contains(0) { indices.insert(0, struct.start) } + if not indices.contains(struct.bits + struct.start - 1) { + indices.push(struct.bits + struct.start - 1) + } } for i in range(struct.bits) { @@ -453,8 +460,9 @@ let desc-y = bits-y + bit-h * 2 // Names + simple descriptions - for range_ in ranges { + for (i, range_) in ranges.enumerate() { let start-i = to-real-i(if config.ltr-bits {range_.start} else {range_.end}) + let end-i = to-real-i(if config.ltr-bits {range_.end} else {range_.start}) let start-x = bits-x + start-i * bit-w let width = rng.bits(range_) * bit-w @@ -464,6 +472,28 @@ let line-x = if config.ltr-bits {start-x + width} else {start-x} shapes += draw-line(border-col, (line-x, bits-y), (line-x, bits-y + bit-h)) shapes += draw-text(range_.name, txt-col, name-x, name-y, fill: bg-col) + + // paint end line only if needed + let is-not-limit = if config.ltr-bits { start-i != 0 } else { end-i != struct.bits - 1 } + if ( + is-not-limit + and ranges + .at( + i + + { + if config.ltr-bits and i < ranges.len() - 1 { 1 } else { -1 } + }, + ) + .end + != range_.start - 1 + ) { + line-x += if config.ltr-bits { -width } else { width } + shapes += draw-line( + border-col, + (line-x, bits-y), + (line-x, bits-y + bit-h), + ) + } if range_.description != "" { let shapes_ @@ -568,4 +598,4 @@ config: config, render: render.with(config) ) -} \ No newline at end of file +} diff --git a/src/xml-loader.typ b/src/xml-loader.typ index 9513766..ac3962f 100644 --- a/src/xml-loader.typ +++ b/src/xml-loader.typ @@ -76,8 +76,9 @@ } return ( - bits: elmt.attrs.bits, - ranges: ranges + bits: int(elmt.attrs.bits), + ranges: ranges, + start: elmt.attrs.at("start", default: 0) ) } diff --git a/typst.toml b/typst.toml index 878fc30..f8c6645 100644 --- a/typst.toml +++ b/typst.toml @@ -1,6 +1,6 @@ [package] name = "rivet" -version = "0.3.0" +version = "0.3.1" compiler = "0.13.1" repository = "https://git.kb28.ch/HEL/rivet-typst" entrypoint = "src/lib.typ" @@ -9,6 +9,6 @@ authors = [ ] categories = [ "visualization" ] license = "Apache-2.0" -description = "Register / Instruction Visualizer & Explainer Tool with Typst, using CeTZ" +description = "Register / Instruction Visualizer & Explainer Tool, using CeTZ" keywords = [ "assembly", "instruction", "binary" ] exclude = [ "gallery", "justfile", "docs" ] \ No newline at end of file