summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.DS_Storebin0 -> 8196 bytes
-rw-r--r--.gitignore30
-rw-r--r--README.md43
-rw-r--r--configure.ac2
-rw-r--r--doc/.DS_Storebin0 -> 6148 bytes
-rw-r--r--doc/README.md12
-rw-r--r--doc/spec/isa_reference.html106
-rw-r--r--doc/spec/isa_reference.md899
-rw-r--r--doc/spec/isa_reference.pdfbin0 -> 90197 bytes
-rw-r--r--editors/vscode/README.md34
-rw-r--r--editors/vscode/isa-syntax-1.0.0.vsixbin0 -> 3414 bytes
-rw-r--r--editors/vscode/language-configuration.json8
-rw-r--r--editors/vscode/package.json27
-rw-r--r--editors/vscode/syntaxes/isa.tmLanguage.json70
-rw-r--r--examples/README.md7
-rw-r--r--gen/README.md14
-rw-r--r--gen/decoder/main.c3
-rw-r--r--gen/disassembler/main.c3
-rw-r--r--gen/docs/convert.sh55
-rw-r--r--gen/docs/generator.c481
-rw-r--r--gen/docs/generator.h9
-rwxr-xr-xgen/docs/isa-docgenbin0 -> 51736 bytes
-rw-r--r--gen/docs/isa_defs/arch.isa68
-rw-r--r--gen/docs/isa_defs/csrs.isa191
-rw-r--r--gen/docs/isa_defs/instructions.isa512
-rw-r--r--gen/docs/isa_defs/registers.isa289
-rw-r--r--gen/docs/main.c83
-rw-r--r--gen/docs/parser.c256
-rw-r--r--gen/docs/parser.h9
-rw-r--r--gen/docs/style.css139
-rw-r--r--gen/docs/types.h78
-rw-r--r--gen/encoder/main.c3
-rw-r--r--gen/opcodes/main.c3
-rw-r--r--gen/tablegen/main.c3
-rw-r--r--isa/README.md12
-rw-r--r--isa/encoding/base.yaml3
-rw-r--r--isa/opcodes/base.yaml8
-rw-r--r--runtime/README.md6
-rw-r--r--sim/README.md8
-rw-r--r--tests/README.md8
-rw-r--r--tools/README.md17
41 files changed, 3499 insertions, 0 deletions
diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..ed9e52b
--- /dev/null
+++ b/.DS_Store
Binary files differ
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..bc3feba
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,30 @@
+# Build outputs
+*.o
+*.a
+*.so
+*.elf
+*.hex
+
+# Generated sources
+/gen/*/output/
+/gen/*/build/
+
+# Toolchain builds
+/tools/*/build/
+
+# Simulator
+/sim/build/
+
+# Autotools
+Makefile
+Makefile.in
+configure
+config.status
+config.log
+autom4te.cache/
+
+# IDE
+.cate/
+.vscode/
+.idea/
+*.swp
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e064336
--- /dev/null
+++ b/README.md
@@ -0,0 +1,43 @@
+# Fyntv — Flexible Yet Novel Transform Vector
+
+```
+fyntv/
+├── doc/ — ISA specification, programmer's manual, ABI docs
+├── isa/ — Formal ISA definition: encoding, opcodes, extensions
+├── gen/ — Code generators (C programs that generate source code)
+│ ├── tablegen/ — Instruction table generation (like LLVM TableGen)
+│ ├── decoder/ — Generate decoder sources from ISA definitions
+│ ├── encoder/ — Generate encoder/assembler sources
+│ ├── disassembler/ — Generate disassembler sources
+│ ├── opcodes/ — Generate opcode header files
+│ ├── abi/ — Generate ABI-related sources
+│ └── docs/ — Generate documentation from machine-readable ISA defs
+├── asm/ — Assembler
+├── disasm/ — Disassembler
+├── tools/ — Full binutils-style toolchain
+│ ├── gas/ — Assembler (GNU style)
+│ ├── ld/ — Linker
+│ ├── objdump/ — Object file dumper
+│ ├── objcopy/ — Object file copy/strip
+│ ├── readelf/ — ELF reader
+│ ├── nm/ — Symbol listing
+│ ├── ar/ — Archive utility
+│ ├── size/ — Section size reporter
+│ ├── strings/ — String extractor
+│ ├── addr2line/ — Address-to-line converter
+│ └── cxxfilt/ — C++ name demangler
+├── sim/ — Instruction-set simulator / emulator
+├── linker/ — Linker scripts & runtime
+├── runtime/ — C runtime (crt0, startup code)
+├── tests/ — Test suites
+│ ├── asm/ — Assembly-level tests
+│ ├── sim/ — Simulator tests
+│ ├── regression/— Regression test suite
+│ └── benchmarks/— Benchmark programs
+├── examples/ — Example programs
+│ ├── asm/ — Assembly examples
+│ ├── c/ — C language examples
+│ └── benchmarks/— Dhrystone, Coremark, etc.
+├── scripts/ — Build scripts, CI, release tooling
+└── docker/ — Docker build environments
+```
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..a09bcb7
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,2 @@
+# Autoconf input — generates configure script
+# Checks for: C compiler, Python, make, flex, bison
diff --git a/doc/.DS_Store b/doc/.DS_Store
new file mode 100644
index 0000000..f670f3f
--- /dev/null
+++ b/doc/.DS_Store
Binary files differ
diff --git a/doc/README.md b/doc/README.md
new file mode 100644
index 0000000..ba08550
--- /dev/null
+++ b/doc/README.md
@@ -0,0 +1,12 @@
+# Documentation
+
+| Directory | Contents |
+|----------------|-----------------------------------------------|
+| `spec/` | Formal ISA specification reference manual |
+| `manual/` | Programmer's guide — assembly, toolchain use |
+| `abi/` | Application Binary Interface specification |
+| `internals/` | Microarchitecture, pipeline, implementor notes|
+| `examples/` | Annotated code examples in asm/C |
+
+The `gen/docs/` generator produces source files for these docs from the
+machine-readable ISA definitions.
diff --git a/doc/spec/isa_reference.html b/doc/spec/isa_reference.html
new file mode 100644
index 0000000..b2a8353
--- /dev/null
+++ b/doc/spec/isa_reference.html
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<title>Fyntv ISA Reference Manual</title>
+<link rel="stylesheet" href="style.css">
+</head>
+<body>
+<article>
+<header>
+<h1>Fyntv Instruction Set Architecture</h1>
+<p class="subtitle">Reference Manual</p>
+<p><strong>Version:</strong> 0.0.0.1 &nbsp;|&nbsp; <strong>Date:</strong> June 2026</p>
+</header>
+<section id="registers">
+<h2>Registers</h2>
+<table><thead><tr><th>Register</th><th>ABI Name</th><th>Description</th><th>Saved</th></tr></thead><tbody>
+<tr><td>x0</td><td>zero</td><td>Always-zero register — reads return 0, writes are discarded</td><td>No</td></tr>
+<tr><td>x1</td><td>ra</td><td>Return address link register</td><td>No</td></tr>
+<tr><td>x2</td><td>sp</td><td>Stack pointer</td><td>Yes</td></tr>
+<tr><td>x3</td><td>gp</td><td>Global pointer</td><td>Yes</td></tr>
+<tr><td>x4</td><td>tp</td><td>Thread pointer</td><td>Yes</td></tr>
+<tr><td>x5</td><td>t0</td><td>Temporary register 0</td><td>No</td></tr>
+<tr><td>x6</td><td>t1</td><td>Temporary register 1</td><td>No</td></tr>
+<tr><td>x7</td><td>t2</td><td>Temporary register 2</td><td>No</td></tr>
+<tr><td>x8</td><td>s0</td><td>Saved register 0 / frame pointer</td><td>Yes</td></tr>
+<tr><td>x9</td><td>s1</td><td>Saved register 1</td><td>Yes</td></tr>
+<tr><td>x10</td><td>a0</td><td>Function argument 0 / return value 0</td><td>No</td></tr>
+<tr><td>x11</td><td>a1</td><td>Function argument 1 / return value 1</td><td>No</td></tr>
+<tr><td>x12</td><td>a2</td><td>Function argument 2</td><td>No</td></tr>
+<tr><td>x13</td><td>a3</td><td>Function argument 3</td><td>No</td></tr>
+<tr><td>x14</td><td>a4</td><td>Function argument 4</td><td>No</td></tr>
+<tr><td>x15</td><td>a5</td><td>Function argument 5</td><td>No</td></tr>
+<tr><td>x16</td><td>a6</td><td>Function argument 6</td><td>No</td></tr>
+<tr><td>x17</td><td>a7</td><td>Function argument 7</td><td>No</td></tr>
+<tr><td>x18</td><td>s2</td><td>Saved register 2</td><td>Yes</td></tr>
+<tr><td>x19</td><td>s3</td><td>Saved register 3</td><td>Yes</td></tr>
+<tr><td>x20</td><td>s4</td><td>Saved register 4</td><td>Yes</td></tr>
+<tr><td>x21</td><td>s5</td><td>Saved register 5</td><td>Yes</td></tr>
+<tr><td>x22</td><td>s6</td><td>Saved register 6</td><td>Yes</td></tr>
+<tr><td>x23</td><td>s7</td><td>Saved register 7</td><td>Yes</td></tr>
+<tr><td>x24</td><td>s8</td><td>Saved register 8</td><td>Yes</td></tr>
+<tr><td>x25</td><td>s9</td><td>Saved register 9</td><td>Yes</td></tr>
+<tr><td>x26</td><td>s10</td><td>Saved register 10</td><td>Yes</td></tr>
+<tr><td>x27</td><td>s11</td><td>Saved register 11</td><td>Yes</td></tr>
+<tr><td>x28</td><td>t3</td><td>Temporary register 3</td><td>No</td></tr>
+<tr><td>x29</td><td>t4</td><td>Temporary register 4</td><td>No</td></tr>
+<tr><td>x30</td><td>t5</td><td>Temporary register 5</td><td>No</td></tr>
+<tr><td>x31</td><td>t6</td><td>Temporary register 6</td><td>No</td></tr>
+</tbody></table>
+</section>
+<section id="instructions">
+<h2>Instruction Set</h2>
+<table><thead><tr><th>Mnemonic</th><th>Format</th><th>Opcode</th><th>Operands</th><th>Description</th></tr></thead><tbody>
+<tr><td><code>ADD</code></td><td>R</td><td><code>0x33</code></td><td><code>rd, rs1, rs2</code></td><td>Add registers</td></tr>
+<tr><td><code>SUB</code></td><td>R</td><td><code>0x33</code></td><td><code>rd, rs1, rs2</code></td><td>Subtract registers</td></tr>
+<tr><td><code>ADDI</code></td><td>I</td><td><code>0x13</code></td><td><code>rd, rs1, imm12</code></td><td>Add sign-extended 12-bit immediate to register rs1</td></tr>
+<tr><td><code>SLT</code></td><td>R</td><td><code>0x33</code></td><td><code>rd, rs1, rs2</code></td><td>Set if rs1 is less than rs2 (signed)</td></tr>
+<tr><td><code>SLTU</code></td><td>R</td><td><code>0x33</code></td><td><code>rd, rs1, rs2</code></td><td>Set if rs1 is less than rs2 (unsigned)</td></tr>
+<tr><td><code>SLTI</code></td><td>I</td><td><code>0x13</code></td><td><code>rd, rs1, imm12</code></td><td>Set if rs1 is less than immediate (signed)</td></tr>
+<tr><td><code>SLTIU</code></td><td>I</td><td><code>0x13</code></td><td><code>rd, rs1, imm12</code></td><td>Set if rs1 is less than immediate (unsigned)</td></tr>
+<tr><td><code>LUI</code></td><td>U</td><td><code>0x37</code></td><td><code>rd, imm20</code></td><td>Load upper immediate — places 20-bit immediate in upper 20 bits of rd</td></tr>
+<tr><td><code>AUIPC</code></td><td>U</td><td><code>0x17</code></td><td><code>rd, imm20</code></td><td>Add upper immediate to PC — forms PC-relative address</td></tr>
+<tr><td><code>AND</code></td><td>R</td><td><code>0x33</code></td><td><code>rd, rs1, rs2</code></td><td>Bitwise AND</td></tr>
+<tr><td><code>OR</code></td><td>R</td><td><code>0x33</code></td><td><code>rd, rs1, rs2</code></td><td>Bitwise OR</td></tr>
+<tr><td><code>XOR</code></td><td>R</td><td><code>0x33</code></td><td><code>rd, rs1, rs2</code></td><td>Bitwise XOR</td></tr>
+<tr><td><code>ANDI</code></td><td>I</td><td><code>0x13</code></td><td><code>rd, rs1, imm12</code></td><td>Bitwise AND with immediate</td></tr>
+<tr><td><code>ORI</code></td><td>I</td><td><code>0x13</code></td><td><code>rd, rs1, imm12</code></td><td>Bitwise OR with immediate</td></tr>
+<tr><td><code>XORI</code></td><td>I</td><td><code>0x13</code></td><td><code>rd, rs1, imm12</code></td><td>Bitwise XOR with immediate</td></tr>
+<tr><td><code>SLL</code></td><td>R</td><td><code>0x33</code></td><td><code>rd, rs1, rs2</code></td><td>Logical left shift by lower 5 bits of rs2</td></tr>
+<tr><td><code>SRL</code></td><td>R</td><td><code>0x33</code></td><td><code>rd, rs1, rs2</code></td><td>Logical right shift by lower 5 bits of rs2</td></tr>
+<tr><td><code>SRA</code></td><td>R</td><td><code>0x33</code></td><td><code>rd, rs1, rs2</code></td><td>Arithmetic right shift by lower 5 bits of rs2</td></tr>
+<tr><td><code>SLLI</code></td><td>I</td><td><code>0x13</code></td><td><code>rd, rs1, shamt5</code></td><td>Logical left shift by immediate shift amount</td></tr>
+<tr><td><code>SRLI</code></td><td>I</td><td><code>0x13</code></td><td><code>rd, rs1, shamt5</code></td><td>Logical right shift by immediate shift amount</td></tr>
+<tr><td><code>SRAI</code></td><td>I</td><td><code>0x13</code></td><td><code>rd, rs1, shamt5</code></td><td>Arithmetic right shift by immediate shift amount</td></tr>
+<tr><td><code>LB</code></td><td>I</td><td><code>0x03</code></td><td><code>rd, offset(rs1)</code></td><td>Load byte (sign-extended)</td></tr>
+<tr><td><code>LH</code></td><td>I</td><td><code>0x03</code></td><td><code>rd, offset(rs1)</code></td><td>Load halfword (sign-extended)</td></tr>
+<tr><td><code>LW</code></td><td>I</td><td><code>0x03</code></td><td><code>rd, offset(rs1)</code></td><td>Load word</td></tr>
+<tr><td><code>LBU</code></td><td>I</td><td><code>0x03</code></td><td><code>rd, offset(rs1)</code></td><td>Load byte (zero-extended)</td></tr>
+<tr><td><code>LHU</code></td><td>I</td><td><code>0x03</code></td><td><code>rd, offset(rs1)</code></td><td>Load halfword (zero-extended)</td></tr>
+<tr><td><code>SB</code></td><td>S</td><td><code>0x23</code></td><td><code>rs2, offset(rs1)</code></td><td>Store byte</td></tr>
+<tr><td><code>SH</code></td><td>S</td><td><code>0x23</code></td><td><code>rs2, offset(rs1)</code></td><td>Store halfword</td></tr>
+<tr><td><code>SW</code></td><td>S</td><td><code>0x23</code></td><td><code>rs2, offset(rs1)</code></td><td>Store word</td></tr>
+<tr><td><code>BEQ</code></td><td>B</td><td><code>0x63</code></td><td><code>rs1, rs2, label</code></td><td>Branch equal</td></tr>
+<tr><td><code>BNE</code></td><td>B</td><td><code>0x63</code></td><td><code>rs1, rs2, label</code></td><td>Branch not equal</td></tr>
+<tr><td><code>BLT</code></td><td>B</td><td><code>0x63</code></td><td><code>rs1, rs2, label</code></td><td>Branch less than (signed)</td></tr>
+<tr><td><code>BGE</code></td><td>B</td><td><code>0x63</code></td><td><code>rs1, rs2, label</code></td><td>Branch greater than or equal (signed)</td></tr>
+<tr><td><code>BLTU</code></td><td>B</td><td><code>0x63</code></td><td><code>rs1, rs2, label</code></td><td>Branch less than (unsigned)</td></tr>
+<tr><td><code>BGEU</code></td><td>B</td><td><code>0x63</code></td><td><code>rs1, rs2, label</code></td><td>Branch greater than or equal (unsigned)</td></tr>
+<tr><td><code>JAL</code></td><td>J</td><td><code>0x6F</code></td><td><code>rd, label</code></td><td>Jump and link — jump to PC+offset, save return address to rd</td></tr>
+<tr><td><code>JALR</code></td><td>I</td><td><code>0x67</code></td><td><code>rd, rs1, offset</code></td><td>Jump and link register — jump to rs1+offset, save return address</td></tr>
+<tr><td><code>FENCE</code></td><td>I</td><td><code>0x0F</code></td><td><code>pred, succ</code></td><td>Memory ordering fence</td></tr>
+<tr><td><code>FENCEI</code></td><td>I</td><td><code>0x0F</code></td><td><code>—</code></td><td>Instruction fence — synchronizes instruction and data streams</td></tr>
+<tr><td><code>ECALL</code></td><td>I</td><td><code>0x73</code></td><td><code>—</code></td><td>Environment call — raises a system call exception</td></tr>
+<tr><td><code>EBREAK</code></td><td>I</td><td><code>0x73</code></td><td><code>—</code></td><td>Breakpoint — raises a breakpoint exception</td></tr>
+<tr><td><code>CSRRW</code></td><td>I</td><td><code>0x73</code></td><td><code>rd, csr, rs1</code></td><td>Atomic read/write CSR — writes rs1 to CSR, returns old value in rd</td></tr>
+<tr><td><code>CSRRS</code></td><td>I</td><td><code>0x73</code></td><td><code>rd, csr, rs1</code></td><td>Atomic read and set bits in CSR</td></tr>
+<tr><td><code>CSRRC</code></td><td>I</td><td><code>0x73</code></td><td><code>rd, csr, rs1</code></td><td>Atomic read and clear bits in CSR</td></tr>
+<tr><td><code>CSRRWI</code></td><td>I</td><td><code>0x73</code></td><td><code>rd, csr, uimm5</code></td><td>Atomic read/write CSR with immediate</td></tr>
+<tr><td><code>CSRRSI</code></td><td>I</td><td><code>0x73</code></td><td><code>rd, csr, uimm5</code></td><td>Atomic read and set bits in CSR with immediate</td></tr>
+<tr><td><code>CSRRCI</code></td><td>I</td><td><code>0x73</code></td><td><code>rd, csr, uimm5</code></td><td>Atomic read and clear bits in CSR with immediate</td></tr>
+</tbody></table>
+</section>
+</article>
+</body>
+</html>
diff --git a/doc/spec/isa_reference.md b/doc/spec/isa_reference.md
new file mode 100644
index 0000000..ab7b1da
--- /dev/null
+++ b/doc/spec/isa_reference.md
@@ -0,0 +1,899 @@
+---
+title: "Fyntv Instruction Set Architecture"
+subtitle: "Reference Manual"
+version: "0.0.0.1"
+date: "June 2026"
+status: "Draft"
+geometry: margin=1in
+toc: true
+numbersections: true
+---
+
+\newpage
+
+# Revision History
+
+| Version | Date | Description |
+|---------|------|-------------|
+| 0.0.0.1 | June 2026 | Initial Fyntv release |
+
+\newpage
+
+\tableofcontents
+
+\newpage
+
+# Introduction
+
+This document defines the **Fyntv Instruction Set Architecture (ISA)** version 0.0.0.1.
+
+## Scope
+
+This specification covers:
+
+- Instruction formats and encoding
+- Register file and calling convention
+- All base and extension instructions
+- Control and status registers (CSRs)
+- Exception and trap handling
+
+## ISA Overview
+
+The Fyntv ISA is a load-store architecture with:
+
+- 32 general-purpose registers (x0–x31)
+- Fixed-width 32-bit instructions
+- Three operand formats: register (R-type), immediate (I-type), and store (S-type)
+- Branch (B-type) and upper-immediate (U-type) variants
+- A separate jump-and-link (J-type) format
+
+\newpage
+
+# Registers
+
+## General-Purpose Registers
+
+The architecture provides 32 general-purpose registers (x0–x31), each 32 bits wide. Register x0 is hardwired to the constant zero.
+
+| Register | ABI Name | Description | Callee-Saved |
+|----------|----------|-------------|--------------|
+| x0 | zero | Always-zero register — reads return 0, writes are discarded | — |
+| x1 | ra | Return address link register | No |
+| x2 | sp | Stack pointer | Yes |
+| x3 | gp | Global pointer | Yes |
+| x4 | tp | Thread pointer | Yes |
+| x5 | t0 | Temporary register 0 | No |
+| x6 | t1 | Temporary register 1 | No |
+| x7 | t2 | Temporary register 2 | No |
+| x8 | s0 | Saved register 0 / frame pointer | Yes |
+| x9 | s1 | Saved register 1 | Yes |
+| x10 | a0 | Function argument 0 / return value 0 | No |
+| x11 | a1 | Function argument 1 / return value 1 | No |
+| x12 | a2 | Function argument 2 | No |
+| x13 | a3 | Function argument 3 | No |
+| x14 | a4 | Function argument 4 | No |
+| x15 | a5 | Function argument 5 | No |
+| x16 | a6 | Function argument 6 | No |
+| x17 | a7 | Function argument 7 | No |
+| x18 | s2 | Saved register 2 | Yes |
+| x19 | s3 | Saved register 3 | Yes |
+| x20 | s4 | Saved register 4 | Yes |
+| x21 | s5 | Saved register 5 | Yes |
+| x22 | s6 | Saved register 6 | Yes |
+| x23 | s7 | Saved register 7 | Yes |
+| x24 | s8 | Saved register 8 | Yes |
+| x25 | s9 | Saved register 9 | Yes |
+| x26 | s10 | Saved register 10 | Yes |
+| x27 | s11 | Saved register 11 | Yes |
+| x28 | t3 | Temporary register 3 | No |
+| x29 | t4 | Temporary register 4 | No |
+| x30 | t5 | Temporary register 5 | No |
+| x31 | t6 | Temporary register 6 | No |
+
+### ABI Calling Convention
+
+| Register | ABI Name | Caller-Saved | Argument |
+|----------|----------|-------------|----------|
+| x0 | zero | No | No |
+| x1 | ra | No | No |
+| x2 | sp | No | No |
+| x3 | gp | No | No |
+| x4 | tp | No | No |
+| x5 | t0 | Yes | No |
+| x6 | t1 | Yes | No |
+| x7 | t2 | Yes | No |
+| x8 | s0 | No | No |
+| x9 | s1 | No | No |
+| x10 | a0 | Yes | Yes |
+| x11 | a1 | Yes | Yes |
+| x12 | a2 | Yes | Yes |
+| x13 | a3 | Yes | Yes |
+| x14 | a4 | Yes | Yes |
+| x15 | a5 | Yes | Yes |
+| x16 | a6 | Yes | Yes |
+| x17 | a7 | Yes | Yes |
+| x18 | s2 | No | No |
+| x19 | s3 | No | No |
+| x20 | s4 | No | No |
+| x21 | s5 | No | No |
+| x22 | s6 | No | No |
+| x23 | s7 | No | No |
+| x24 | s8 | No | No |
+| x25 | s9 | No | No |
+| x26 | s10 | No | No |
+| x27 | s11 | No | No |
+| x28 | t3 | Yes | No |
+| x29 | t4 | Yes | No |
+| x30 | t5 | Yes | No |
+| x31 | t6 | Yes | No |
+
+\newpage
+
+# Instruction Formats
+
+Instructions are encoded in one of several fixed formats. All formats share the same opcode placement (bits 6:0) to allow efficient decoding.
+
+### R-Type Format
+
+Bit width: **32 bits**
+
+```
+ 31:25 |24:20|19:15|14:12|11:7| 6:0
+funct7 | rs2 | rs1 |funct3| rd |opcode
+ 7 | 5 | 5 | 3 | 5 | 7
+```
+
+### I-Type Format
+
+Bit width: **32 bits**
+
+```
+ 31:20 |19:15|14:12|11:7| 6:0
+ imm | rs1 |funct3| rd |opcode
+ 12 | 5 | 3 | 5 | 7
+```
+
+### S-Type Format
+
+Bit width: **32 bits**
+
+```
+ 31:25 |24:20|19:15|14:12|11:7| 6:0
+imm_hi | rs2 | rs1 |funct3|imm_lo|opcode
+ 7 | 5 | 5 | 3 | 5 | 7
+```
+
+### B-Type Format
+
+Bit width: **32 bits**
+
+```
+31:31|30:25 |24:20|19:15|14:12|11:7| 6:0
+imm_12|imm_10_5| rs2 | rs1 |funct3|imm_4_1|opcode
+1| 6 | 5 | 5 | 3 | 5 | 7
+```
+
+### U-Type Format
+
+Bit width: **32 bits**
+
+```
+ 31:12 |11:7| 6:0
+ imm | rd |opcode
+ 20 | 5 | 7
+```
+
+### J-Type Format
+
+Bit width: **32 bits**
+
+```
+31:31| 30:21 |20:20| 19:12 |11:7| 6:0
+imm_20| imm_10_1 |imm_11|imm_19_12| rd |opcode
+1| 10 |1| 8 | 5 | 7
+```
+
+\newpage
+
+# Instruction Set
+
+## Branch Operations
+
+| Mnemonic | Format | Opcode | Funct3 | Funct7 | Operands | Description |
+|----------|--------|--------|--------|--------|----------|-------------|
+| `BNE` | B | `0x63` | 0x1 | — | rs1, rs2, label | Branch not equal |
+| `BEQ` | B | `0x63` | 0x0 | — | rs1, rs2, label | Branch equal |
+| `BLT` | B | `0x63` | 0x4 | — | rs1, rs2, label | Branch less than (signed) |
+| `BGE` | B | `0x63` | 0x5 | — | rs1, rs2, label | Branch greater than or equal (signed) |
+| `BLTU` | B | `0x63` | 0x6 | — | rs1, rs2, label | Branch less than (unsigned) |
+| `BGEU` | B | `0x63` | 0x7 | — | rs1, rs2, label | Branch greater than or equal (unsigned) |
+## Integer Operations
+
+| Mnemonic | Format | Opcode | Funct3 | Funct7 | Operands | Description |
+|----------|--------|--------|--------|--------|----------|-------------|
+| `AUIPC` | U | `0x17` | — | — | rd, imm20 | Add upper immediate to PC — forms PC-relative address |
+| `SLT` | R | `0x33` | 0x2 | 0x00 | rd, rs1, rs2 | Set if rs1 is less than rs2 (signed) |
+| `SLTU` | R | `0x33` | 0x3 | 0x00 | rd, rs1, rs2 | Set if rs1 is less than rs2 (unsigned) |
+| `SLTI` | I | `0x13` | 0x2 | — | rd, rs1, imm12 | Set if rs1 is less than immediate (signed) |
+| `SLTIU` | I | `0x13` | 0x3 | — | rd, rs1, imm12 | Set if rs1 is less than immediate (unsigned) |
+| `LUI` | U | `0x37` | — | — | rd, imm20 | Load upper immediate — places 20-bit immediate in upper 20 bits of rd |
+| `ADD` | R | `0x33` | 0x0 | 0x00 | rd, rs1, rs2 | Add registers |
+| `SUB` | R | `0x33` | 0x0 | 0x20 | rd, rs1, rs2 | Subtract registers |
+| `ADDI` | I | `0x13` | 0x0 | — | rd, rs1, imm12 | Add sign-extended 12-bit immediate to register rs1 |
+## Jump Operations
+
+| Mnemonic | Format | Opcode | Funct3 | Funct7 | Operands | Description |
+|----------|--------|--------|--------|--------|----------|-------------|
+| `JAL` | J | `0x6F` | — | — | rd, label | Jump and link — jump to PC+offset, save return address to rd |
+| `JALR` | I | `0x67` | 0x0 | — | rd, rs1, offset | Jump and link register — jump to rs1+offset, save return address |
+## Logical Operations
+
+| Mnemonic | Format | Opcode | Funct3 | Funct7 | Operands | Description |
+|----------|--------|--------|--------|--------|----------|-------------|
+| `XOR` | R | `0x33` | 0x4 | 0x00 | rd, rs1, rs2 | Bitwise XOR |
+| `OR` | R | `0x33` | 0x6 | 0x00 | rd, rs1, rs2 | Bitwise OR |
+| `AND` | R | `0x33` | 0x7 | 0x00 | rd, rs1, rs2 | Bitwise AND |
+| `ORI` | I | `0x13` | 0x6 | — | rd, rs1, imm12 | Bitwise OR with immediate |
+| `XORI` | I | `0x13` | 0x4 | — | rd, rs1, imm12 | Bitwise XOR with immediate |
+| `ANDI` | I | `0x13` | 0x7 | — | rd, rs1, imm12 | Bitwise AND with immediate |
+## Memory Operations
+
+| Mnemonic | Format | Opcode | Funct3 | Funct7 | Operands | Description |
+|----------|--------|--------|--------|--------|----------|-------------|
+| `SW` | S | `0x23` | 0x2 | — | rs2, offset(rs1) | Store word |
+| `LB` | I | `0x03` | 0x0 | — | rd, offset(rs1) | Load byte (sign-extended) |
+| `LH` | I | `0x03` | 0x1 | — | rd, offset(rs1) | Load halfword (sign-extended) |
+| `LW` | I | `0x03` | 0x2 | — | rd, offset(rs1) | Load word |
+| `LBU` | I | `0x03` | 0x4 | — | rd, offset(rs1) | Load byte (zero-extended) |
+| `LHU` | I | `0x03` | 0x5 | — | rd, offset(rs1) | Load halfword (zero-extended) |
+| `SB` | S | `0x23` | 0x0 | — | rs2, offset(rs1) | Store byte |
+| `SH` | S | `0x23` | 0x1 | — | rs2, offset(rs1) | Store halfword |
+## Shift Operations
+
+| Mnemonic | Format | Opcode | Funct3 | Funct7 | Operands | Description |
+|----------|--------|--------|--------|--------|----------|-------------|
+| `SRAI` | I | `0x13` | 0x5 | — | rd, rs1, shamt5 | Arithmetic right shift by immediate shift amount |
+| `SLLI` | I | `0x13` | 0x1 | — | rd, rs1, shamt5 | Logical left shift by immediate shift amount |
+| `SRA` | R | `0x33` | 0x5 | 0x20 | rd, rs1, rs2 | Arithmetic right shift by lower 5 bits of rs2 |
+| `SRL` | R | `0x33` | 0x5 | 0x00 | rd, rs1, rs2 | Logical right shift by lower 5 bits of rs2 |
+| `SLL` | R | `0x33` | 0x1 | 0x00 | rd, rs1, rs2 | Logical left shift by lower 5 bits of rs2 |
+| `SRLI` | I | `0x13` | 0x5 | — | rd, rs1, shamt5 | Logical right shift by immediate shift amount |
+## Synchronization Operations
+
+| Mnemonic | Format | Opcode | Funct3 | Funct7 | Operands | Description |
+|----------|--------|--------|--------|--------|----------|-------------|
+| `FENCEI` | I | `0x0F` | 0x1 | — | — | Instruction fence — synchronizes instruction and data streams |
+| `FENCE` | I | `0x0F` | 0x0 | — | pred, succ | Memory ordering fence |
+## System Operations
+
+| Mnemonic | Format | Opcode | Funct3 | Funct7 | Operands | Description |
+|----------|--------|--------|--------|--------|----------|-------------|
+| `CSRRCI` | I | `0x73` | 0x7 | — | rd, csr, uimm5 | Atomic read and clear bits in CSR with immediate |
+| `ECALL` | I | `0x73` | 0x0 | — | — | Environment call — raises a system call exception |
+| `EBREAK` | I | `0x73` | 0x0 | — | — | Breakpoint — raises a breakpoint exception |
+| `CSRRW` | I | `0x73` | 0x1 | — | rd, csr, rs1 | Atomic read/write CSR — writes rs1 to CSR, returns old value in rd |
+| `CSRRS` | I | `0x73` | 0x2 | — | rd, csr, rs1 | Atomic read and set bits in CSR |
+| `CSRRC` | I | `0x73` | 0x3 | — | rd, csr, rs1 | Atomic read and clear bits in CSR |
+| `CSRRWI` | I | `0x73` | 0x5 | — | rd, csr, uimm5 | Atomic read/write CSR with immediate |
+| `CSRRSI` | I | `0x73` | 0x6 | — | rd, csr, uimm5 | Atomic read and set bits in CSR with immediate |
+
+\newpage
+
+## Instruction Details
+
+### BNE
+
+- **Format:** B
+- **Opcode:** `0x63`
+- **Funct3:** `0x1`
+- **Operands:** `rs1, rs2, label`
+- **Description:** Branch not equal
+- **Operation:** `if (rs1 != rs2) PC += sext(offset)`
+
+### BEQ
+
+- **Format:** B
+- **Opcode:** `0x63`
+- **Funct3:** `0x0`
+- **Operands:** `rs1, rs2, label`
+- **Description:** Branch equal
+- **Operation:** `if (rs1 == rs2) PC += sext(offset)`
+
+### BLT
+
+- **Format:** B
+- **Opcode:** `0x63`
+- **Funct3:** `0x4`
+- **Operands:** `rs1, rs2, label`
+- **Description:** Branch less than (signed)
+- **Operation:** `if (rs1 < rs2) PC += sext(offset)`
+
+### BGE
+
+- **Format:** B
+- **Opcode:** `0x63`
+- **Funct3:** `0x5`
+- **Operands:** `rs1, rs2, label`
+- **Description:** Branch greater than or equal (signed)
+- **Operation:** `if (rs1 >= rs2) PC += sext(offset)`
+
+### BLTU
+
+- **Format:** B
+- **Opcode:** `0x63`
+- **Funct3:** `0x6`
+- **Operands:** `rs1, rs2, label`
+- **Description:** Branch less than (unsigned)
+- **Operation:** `if (rs1 < rs2) PC += sext(offset)`
+
+### BGEU
+
+- **Format:** B
+- **Opcode:** `0x63`
+- **Funct3:** `0x7`
+- **Operands:** `rs1, rs2, label`
+- **Description:** Branch greater than or equal (unsigned)
+- **Operation:** `if (rs1 >= rs2) PC += sext(offset)`
+
+### AUIPC
+
+- **Format:** U
+- **Opcode:** `0x17`
+- **Operands:** `rd, imm20`
+- **Description:** Add upper immediate to PC — forms PC-relative address
+- **Operation:** `rd = PC + (imm20 << 12)`
+
+### SLT
+
+- **Format:** R
+- **Opcode:** `0x33`
+- **Funct3:** `0x2`
+- **Funct7:** `0x00`
+- **Operands:** `rd, rs1, rs2`
+- **Description:** Set if rs1 is less than rs2 (signed)
+- **Operation:** `rd = (rs1 < rs2) ? 1 : 0`
+
+### SLTU
+
+- **Format:** R
+- **Opcode:** `0x33`
+- **Funct3:** `0x3`
+- **Funct7:** `0x00`
+- **Operands:** `rd, rs1, rs2`
+- **Description:** Set if rs1 is less than rs2 (unsigned)
+- **Operation:** `rd = (rs1 < rs2) ? 1 : 0`
+
+### SLTI
+
+- **Format:** I
+- **Opcode:** `0x13`
+- **Funct3:** `0x2`
+- **Operands:** `rd, rs1, imm12`
+- **Description:** Set if rs1 is less than immediate (signed)
+- **Operation:** `rd = (rs1 < sext(imm12)) ? 1 : 0`
+
+### SLTIU
+
+- **Format:** I
+- **Opcode:** `0x13`
+- **Funct3:** `0x3`
+- **Operands:** `rd, rs1, imm12`
+- **Description:** Set if rs1 is less than immediate (unsigned)
+- **Operation:** `rd = (rs1 < sext(imm12)) ? 1 : 0`
+
+### LUI
+
+- **Format:** U
+- **Opcode:** `0x37`
+- **Operands:** `rd, imm20`
+- **Description:** Load upper immediate — places 20-bit immediate in upper 20 bits of rd
+- **Operation:** `rd = imm20 << 12`
+
+### ADD
+
+- **Format:** R
+- **Opcode:** `0x33`
+- **Funct3:** `0x0`
+- **Funct7:** `0x00`
+- **Operands:** `rd, rs1, rs2`
+- **Description:** Add registers
+- **Operation:** `rd = rs1 + rs2`
+
+### SUB
+
+- **Format:** R
+- **Opcode:** `0x33`
+- **Funct3:** `0x0`
+- **Funct7:** `0x20`
+- **Operands:** `rd, rs1, rs2`
+- **Description:** Subtract registers
+- **Operation:** `rd = rs1 - rs2`
+
+### ADDI
+
+- **Format:** I
+- **Opcode:** `0x13`
+- **Funct3:** `0x0`
+- **Operands:** `rd, rs1, imm12`
+- **Description:** Add sign-extended 12-bit immediate to register rs1
+- **Operation:** `rd = rs1 + sext(imm12)`
+
+### JAL
+
+- **Format:** J
+- **Opcode:** `0x6F`
+- **Operands:** `rd, label`
+- **Description:** Jump and link — jump to PC+offset, save return address to rd
+- **Operation:** `rd = PC + 4; PC += sext(offset)`
+
+### JALR
+
+- **Format:** I
+- **Opcode:** `0x67`
+- **Funct3:** `0x0`
+- **Operands:** `rd, rs1, offset`
+- **Description:** Jump and link register — jump to rs1+offset, save return address
+- **Operation:** `rd = PC + 4; PC = (rs1 + sext(offset)) & ~1`
+
+### XOR
+
+- **Format:** R
+- **Opcode:** `0x33`
+- **Funct3:** `0x4`
+- **Funct7:** `0x00`
+- **Operands:** `rd, rs1, rs2`
+- **Description:** Bitwise XOR
+- **Operation:** `rd = rs1 ^ rs2`
+
+### OR
+
+- **Format:** R
+- **Opcode:** `0x33`
+- **Funct3:** `0x6`
+- **Funct7:** `0x00`
+- **Operands:** `rd, rs1, rs2`
+- **Description:** Bitwise OR
+- **Operation:** `rd = rs1 | rs2`
+
+### AND
+
+- **Format:** R
+- **Opcode:** `0x33`
+- **Funct3:** `0x7`
+- **Funct7:** `0x00`
+- **Operands:** `rd, rs1, rs2`
+- **Description:** Bitwise AND
+- **Operation:** `rd = rs1 & rs2`
+
+### ORI
+
+- **Format:** I
+- **Opcode:** `0x13`
+- **Funct3:** `0x6`
+- **Operands:** `rd, rs1, imm12`
+- **Description:** Bitwise OR with immediate
+- **Operation:** `rd = rs1 | sext(imm12)`
+
+### XORI
+
+- **Format:** I
+- **Opcode:** `0x13`
+- **Funct3:** `0x4`
+- **Operands:** `rd, rs1, imm12`
+- **Description:** Bitwise XOR with immediate
+- **Operation:** `rd = rs1 ^ sext(imm12)`
+
+### ANDI
+
+- **Format:** I
+- **Opcode:** `0x13`
+- **Funct3:** `0x7`
+- **Operands:** `rd, rs1, imm12`
+- **Description:** Bitwise AND with immediate
+- **Operation:** `rd = rs1 & sext(imm12)`
+
+### SW
+
+- **Format:** S
+- **Opcode:** `0x23`
+- **Funct3:** `0x2`
+- **Operands:** `rs2, offset(rs1)`
+- **Description:** Store word
+- **Operation:** `MEM[rs1 + offset][31:0] = rs2[31:0]`
+
+### LB
+
+- **Format:** I
+- **Opcode:** `0x03`
+- **Funct3:** `0x0`
+- **Operands:** `rd, offset(rs1)`
+- **Description:** Load byte (sign-extended)
+- **Operation:** `rd = sext(MEM[rs1 + offset][7:0])`
+
+### LH
+
+- **Format:** I
+- **Opcode:** `0x03`
+- **Funct3:** `0x1`
+- **Operands:** `rd, offset(rs1)`
+- **Description:** Load halfword (sign-extended)
+- **Operation:** `rd = sext(MEM[rs1 + offset][15:0])`
+
+### LW
+
+- **Format:** I
+- **Opcode:** `0x03`
+- **Funct3:** `0x2`
+- **Operands:** `rd, offset(rs1)`
+- **Description:** Load word
+- **Operation:** `rd = MEM[rs1 + offset][31:0]`
+
+### LBU
+
+- **Format:** I
+- **Opcode:** `0x03`
+- **Funct3:** `0x4`
+- **Operands:** `rd, offset(rs1)`
+- **Description:** Load byte (zero-extended)
+- **Operation:** `rd = MEM[rs1 + offset][7:0]`
+
+### LHU
+
+- **Format:** I
+- **Opcode:** `0x03`
+- **Funct3:** `0x5`
+- **Operands:** `rd, offset(rs1)`
+- **Description:** Load halfword (zero-extended)
+- **Operation:** `rd = MEM[rs1 + offset][15:0]`
+
+### SB
+
+- **Format:** S
+- **Opcode:** `0x23`
+- **Funct3:** `0x0`
+- **Operands:** `rs2, offset(rs1)`
+- **Description:** Store byte
+- **Operation:** `MEM[rs1 + offset][7:0] = rs2[7:0]`
+
+### SH
+
+- **Format:** S
+- **Opcode:** `0x23`
+- **Funct3:** `0x1`
+- **Operands:** `rs2, offset(rs1)`
+- **Description:** Store halfword
+- **Operation:** `MEM[rs1 + offset][15:0] = rs2[15:0]`
+
+### SRAI
+
+- **Format:** I
+- **Opcode:** `0x13`
+- **Funct3:** `0x5`
+- **Operands:** `rd, rs1, shamt5`
+- **Description:** Arithmetic right shift by immediate shift amount
+- **Operation:** `rd = rs1 >>> shamt`
+
+### SLLI
+
+- **Format:** I
+- **Opcode:** `0x13`
+- **Funct3:** `0x1`
+- **Operands:** `rd, rs1, shamt5`
+- **Description:** Logical left shift by immediate shift amount
+- **Operation:** `rd = rs1 << shamt`
+
+### SRA
+
+- **Format:** R
+- **Opcode:** `0x33`
+- **Funct3:** `0x5`
+- **Funct7:** `0x20`
+- **Operands:** `rd, rs1, rs2`
+- **Description:** Arithmetic right shift by lower 5 bits of rs2
+- **Operation:** `rd = rs1 >>> rs2[4:0]`
+
+### SRL
+
+- **Format:** R
+- **Opcode:** `0x33`
+- **Funct3:** `0x5`
+- **Funct7:** `0x00`
+- **Operands:** `rd, rs1, rs2`
+- **Description:** Logical right shift by lower 5 bits of rs2
+- **Operation:** `rd = rs1 >> rs2[4:0]`
+
+### SLL
+
+- **Format:** R
+- **Opcode:** `0x33`
+- **Funct3:** `0x1`
+- **Funct7:** `0x00`
+- **Operands:** `rd, rs1, rs2`
+- **Description:** Logical left shift by lower 5 bits of rs2
+- **Operation:** `rd = rs1 << rs2[4:0]`
+
+### SRLI
+
+- **Format:** I
+- **Opcode:** `0x13`
+- **Funct3:** `0x5`
+- **Operands:** `rd, rs1, shamt5`
+- **Description:** Logical right shift by immediate shift amount
+- **Operation:** `rd = rs1 >> shamt`
+
+### FENCEI
+
+- **Format:** I
+- **Opcode:** `0x0F`
+- **Funct3:** `0x1`
+- **Operands:** `—`
+- **Description:** Instruction fence — synchronizes instruction and data streams
+- **Operation:** `Flushes instruction cache after data writes`
+
+### FENCE
+
+- **Format:** I
+- **Opcode:** `0x0F`
+- **Funct3:** `0x0`
+- **Operands:** `pred, succ`
+- **Description:** Memory ordering fence
+- **Operation:** `Orders memory accesses as specified by pred and succ fields`
+
+### CSRRCI
+
+- **Format:** I
+- **Opcode:** `0x73`
+- **Funct3:** `0x7`
+- **Operands:** `rd, csr, uimm5`
+- **Description:** Atomic read and clear bits in CSR with immediate
+- **Operation:** `rd = CSR[csr]; CSR[csr] &= ~zimm`
+
+### ECALL
+
+- **Format:** I
+- **Opcode:** `0x73`
+- **Funct3:** `0x0`
+- **Operands:** `—`
+- **Description:** Environment call — raises a system call exception
+- **Operation:** `Traps to the configured exception handler`
+
+### EBREAK
+
+- **Format:** I
+- **Opcode:** `0x73`
+- **Funct3:** `0x0`
+- **Operands:** `—`
+- **Description:** Breakpoint — raises a breakpoint exception
+- **Operation:** `Used by debuggers to halt program execution`
+
+### CSRRW
+
+- **Format:** I
+- **Opcode:** `0x73`
+- **Funct3:** `0x1`
+- **Operands:** `rd, csr, rs1`
+- **Description:** Atomic read/write CSR — writes rs1 to CSR, returns old value in rd
+- **Operation:** `rd = CSR[csr]; CSR[csr] = rs1`
+
+### CSRRS
+
+- **Format:** I
+- **Opcode:** `0x73`
+- **Funct3:** `0x2`
+- **Operands:** `rd, csr, rs1`
+- **Description:** Atomic read and set bits in CSR
+- **Operation:** `rd = CSR[csr]; CSR[csr] |= rs1`
+
+### CSRRC
+
+- **Format:** I
+- **Opcode:** `0x73`
+- **Funct3:** `0x3`
+- **Operands:** `rd, csr, rs1`
+- **Description:** Atomic read and clear bits in CSR
+- **Operation:** `rd = CSR[csr]; CSR[csr] &= ~rs1`
+
+### CSRRWI
+
+- **Format:** I
+- **Opcode:** `0x73`
+- **Funct3:** `0x5`
+- **Operands:** `rd, csr, uimm5`
+- **Description:** Atomic read/write CSR with immediate
+- **Operation:** `rd = CSR[csr]; CSR[csr] = zimm`
+
+### CSRRSI
+
+- **Format:** I
+- **Opcode:** `0x73`
+- **Funct3:** `0x6`
+- **Operands:** `rd, csr, uimm5`
+- **Description:** Atomic read and set bits in CSR with immediate
+- **Operation:** `rd = CSR[csr]; CSR[csr] |= zimm`
+
+\newpage
+
+# Opcode Map
+
+The following table shows the top-level opcode mapping. The opcode occupies bits 6:0 of every instruction.
+
+| opcode[6:0] | Type | Instructions |
+|-------------|------|-------------|
+| `0x33` (51) | R | ADD, SUB, SLT, SLTU, AND, OR, XOR, SLL, SRL, SRA (10 inst)s |
+| `0x13` (19) | I | ADDI, SLTI, SLTIU, ANDI, ORI, XORI, SLLI, SRLI, SRAI (9 inst)s |
+| `0x37` (55) | U | LUI (1 inst) |
+| `0x17` (23) | U | AUIPC (1 inst) |
+| `0x03` (3) | I | LB, LH, LW, LBU, LHU (5 inst)s |
+| `0x23` (35) | S | SB, SH, SW (3 inst)s |
+| `0x63` (99) | B | BEQ, BNE, BLT, BGE, BLTU, BGEU (6 inst)s |
+| `0x6F` (111) | J | JAL (1 inst) |
+| `0x67` (103) | I | JALR (1 inst) |
+| `0x0F` (15) | I | FENCE, FENCEI (2 inst)s |
+| `0x73` (115) | I | ECALL, EBREAK, CSRRW, CSRRS, CSRRC, CSRRWI, CSRRSI, CSRRCI (8 inst)s |
+
+### Encoding Matrix
+
+| opcode \ funct3 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+|---|---|---|---|---|---|---|---|---|
+| `0x33` | ADD | SLL | SLT | SLTU | XOR | SRL | OR | AND |
+| `0x13` | ADDI | SLLI | SLTI | SLTIU | XORI | SRLI | ORI | ANDI |
+| `0x37` | — | — | — | — | — | — | — | — |
+| `0x17` | — | — | — | — | — | — | — | — |
+| `0x03` | LB | LH | LW | — | LBU | LHU | — | — |
+| `0x23` | SB | SH | SW | — | — | — | — | — |
+| `0x63` | BEQ | BNE | — | — | BLT | BGE | BLTU | BGEU |
+| `0x6F` | — | — | — | — | — | — | — | — |
+| `0x67` | JALR | — | — | — | — | — | — | — |
+| `0x0F` | FENCE | FENCEI | — | — | — | — | — | — |
+| `0x73` | ECALL | CSRRW | CSRRS | CSRRC | — | CSRRWI | CSRRSI | CSRRCI |
+
+\newpage
+
+# Exception and Trap Handling
+
+## Exception Types
+
+| Exception Code | Name | Description |
+|----------------|------|-------------|
+| 0 | Instruction address misaligned | PC not aligned to 4 bytes |
+| 1 | Instruction access fault | Failed to fetch instruction |
+| 2 | Illegal instruction | Unrecognized opcode |
+| 3 | Breakpoint | EBREAK instruction executed |
+| 4 | Load address misaligned | Load address not properly aligned |
+| 5 | Load access fault | Failed to load from memory |
+| 6 | Store address misaligned | Store address not properly aligned |
+| 7 | Store access fault | Failed to store to memory |
+| 8 | Environment call from U-mode | ECALL in user mode |
+| 9 | Environment call from S-mode | ECALL in supervisor mode |
+| 11 | Environment call from M-mode | ECALL in machine mode |
+
+## Trap Vector
+
+On taking a trap, the implementation:
+
+1. Sets `mepc` to the PC of the trapping instruction (or next PC for ECALL/EBREAK)
+2. Sets `mcause` to the exception code
+3. Sets `mtval` to exception-specific information
+4. Sets `mstatus.MPP` to the current privilege mode
+5. Sets `mstatus.MPIE` to `mstatus.MIE`
+6. Clears `mstatus.MIE`
+7. Sets PC to `mtvec`
+
+\newpage
+
+# Pseudo-Instructions
+
+| Pseudo-instruction | Expansion | Description |
+|-------------------|-----------|-------------|
+| `NOP` | `ADDI x0, x0, 0` | No operation |
+| `MV rd, rs` | `ADDI rd, rs, 0` | Copy register |
+| `NOT rd, rs` | `XORI rd, rs, -1` | Bitwise NOT |
+| `NEG rd, rs` | `SUB rd, x0, rs` | Negate register |
+| `LI rd, imm` | (multiple) | Load immediate |
+| `LA rd, label` | (multiple) | Load address |
+| `RET` | `JALR x0, x1, 0` | Return from subroutine |
+| `CALL label` | (multiple) | Call subroutine |
+| `J label` | `JAL x0, label` | Unconditional jump |
+| `JR rs` | `JALR x0, rs, 0` | Jump register |
+
+\newpage
+
+# Control and Status Registers
+
+The following CSRs are accessible via the `CSRRW`, `CSRRS`, `CSRRC`, and their immediate variants.
+
+| Address | Name | Description |
+|---------|------|-------------|
+| `0x300` | mstatus | Machine status register — holds global interrupt enable and privilege state |
+| `0x301` | misa | Machine ISA register — encodes supported ISA extensions |
+| `0x302` | medeleg | Machine exception delegation register |
+| `0x303` | mideleg | Machine interrupt delegation register |
+| `0x304` | mie | Machine interrupt-enable register |
+| `0x305` | mtvec | Machine trap-handler base address |
+| `0x306` | mcounteren | Machine counter enable register |
+| `0x340` | mscratch | Scratch register for machine-mode trap handlers |
+| `0x341` | mepc | Machine exception program counter — holds PC of trapping instruction |
+| `0x342` | mcause | Machine trap cause — encodes exception or interrupt cause |
+| `0x343` | mtval | Machine trap value — exception-specific information |
+| `0x344` | mip | Machine interrupt pending register |
+| `0x3A0` | pmpcfg0 | Physical memory protection configuration 0 |
+| `0x3B0` | pmpaddr0 | Physical memory protection address 0 |
+| `0x3B1` | pmpaddr1 | Physical memory protection address 1 |
+| `0x3B2` | pmpaddr2 | Physical memory protection address 2 |
+| `0x3B3` | pmpaddr3 | Physical memory protection address 3 |
+| `0xB00` | mcycle | Machine cycle counter — counts number of clock cycles |
+| `0xB02` | minstret | Machine instructions-retired counter |
+| `0xB03` | mhpmcounter3 | Machine hardware performance counter 3 |
+| `0xB04` | mhpmcounter4 | Machine hardware performance counter 4 |
+| `0xB05` | mhpmcounter5 | Machine hardware performance counter 5 |
+| `0x323` | mhpmevent3 | Machine hardware performance event selector 3 |
+| `0x324` | mhpmevent4 | Machine hardware performance event selector 4 |
+| `0x325` | mhpmevent5 | Machine hardware performance event selector 5 |
+| `0xC00` | ucycle | User-mode cycle counter read |
+| `0xC02` | uinstret | User-mode instructions-retired read |
+| `0xC80` | ucycleh | Upper 32 bits of user-mode cycle counter |
+| `0xC82` | uinstreth | Upper 32 bits of user-mode instructions-retired counter |
+| `0x100` | sstatus | Supervisor status register |
+| `0x104` | sie | Supervisor interrupt-enable register |
+| `0x105` | stvec | Supervisor trap-handler base address |
+| `0x140` | sscratch | Scratch register for supervisor-mode trap handlers |
+| `0x141` | sepc | Supervisor exception program counter |
+| `0x142` | scause | Supervisor trap cause register |
+| `0x143` | stval | Supervisor trap value register |
+| `0x144` | sip | Supervisor interrupt pending register |
+| `0x180` | satp | Supervisor address translation and protection — controls page tables |
+
+\newpage
+
+# Quick Reference
+
+## Instruction Encoding Quick Reference
+
+### R-Type
+
+```
+ 31:27 | 26:25 | 24:20 | 19:15 | 14:12 | 11:7 | 6:0
+ funct7 | — | rs2 | rs1 | funct3 | rd | opcode
+ 7 | 2 | 5 | 5 | 3 | 5 | 7
+```
+
+### I-Type
+
+```
+ 31:20 | 19:15 | 14:12 | 11:7 | 6:0
+ imm[11:0]| rs1 | funct3 | rd | opcode
+ 12 | 5 | 3 | 5 | 7
+```
+
+### S-Type
+
+```
+ 31:27 | 26:25 | 24:20 | 19:15 | 14:12 | 11:7 | 6:0
+ imm[11:5]| — | rs2 | rs1 | funct3 | imm[4:0]| opcode
+ 7 | 2 | 5 | 5 | 3 | 5 | 7
+```
+
+### B-Type
+
+```
+ 31 | 30:27 | 26:25 | 24:20 | 19:15 | 14:12 | 11:8 | 7 | 6:0
+ imm[12]| imm[10:5]| — | rs2 | rs1 | funct3 | imm[4:1]| imm[11]| opcode
+ 1 | 6 | 2 | 5 | 5 | 3 | 4 | 1 | 7
+```
+
+### U-Type
+
+```
+ 31:12 | 11:7 | 6:0
+ imm[31:12] | rd | opcode
+ 20 | 5 | 7
+```
+
+### J-Type
+
+```
+ 31 | 30:21 | 20 | 19:12 | 11:7 | 6:0
+ imm[20]| imm[10:1]| imm[11]| imm[19:12]| rd | opcode
+ 1 | 10 | 1 | 8 | 5 | 7
+```
+
diff --git a/doc/spec/isa_reference.pdf b/doc/spec/isa_reference.pdf
new file mode 100644
index 0000000..73f0733
--- /dev/null
+++ b/doc/spec/isa_reference.pdf
Binary files differ
diff --git a/editors/vscode/README.md b/editors/vscode/README.md
new file mode 100644
index 0000000..e7db36d
--- /dev/null
+++ b/editors/vscode/README.md
@@ -0,0 +1,34 @@
+# ISA Syntax Highlighting for VS Code
+
+Highlights `.isa` definition files — block types, keys, hex values, comments, bit ranges, and booleans.
+
+## Install
+
+```bash
+# Symlink into your VS Code extensions folder
+mkdir -p ~/.vscode/extensions
+ln -sf "$PWD" ~/.vscode/extensions/myisa-isa-syntax
+```
+
+Or copy the folder:
+
+```bash
+cp -r "$PWD" ~/.vscode/extensions/myisa-isa-syntax
+```
+
+Then **reload VS Code** (`Cmd+Shift+P` → "Developer: Reload Window").
+
+Open any `.isa` file — syntax highlighting activates automatically.
+
+## Colors by token
+
+| Token | Color |
+|-------|-------|
+| `ARCH`, `FORMAT`, `REGISTER`, `INSTRUCTION`, `CSR` | Keyword purple |
+| Block name (e.g. `ADD`, `x0`, `R`) | Entity/type blue-green |
+| `END` | Keyword purple |
+| Keys (`NAME`, `OPCODE`, `DESC`, etc.) | Property orange/yellow |
+| `0x...` hex values | Numeric green |
+| `31:25` bit ranges | Numeric green |
+| `true`/`false` booleans | Language constant |
+| `#` comments | Comment gray |
diff --git a/editors/vscode/isa-syntax-1.0.0.vsix b/editors/vscode/isa-syntax-1.0.0.vsix
new file mode 100644
index 0000000..9efef29
--- /dev/null
+++ b/editors/vscode/isa-syntax-1.0.0.vsix
Binary files differ
diff --git a/editors/vscode/language-configuration.json b/editors/vscode/language-configuration.json
new file mode 100644
index 0000000..e7a0d58
--- /dev/null
+++ b/editors/vscode/language-configuration.json
@@ -0,0 +1,8 @@
+{
+ "comments": {
+ "lineComment": "#"
+ },
+ "brackets": [],
+ "autoClosingPairs": [],
+ "surroundingPairs": []
+}
diff --git a/editors/vscode/package.json b/editors/vscode/package.json
new file mode 100644
index 0000000..d591994
--- /dev/null
+++ b/editors/vscode/package.json
@@ -0,0 +1,27 @@
+{
+ "name": "isa-syntax",
+ "displayName": "ISA Definition Syntax Highlighting",
+ "description": "Syntax highlighting for .isa ISA definition files (used by the MyISA doc generator)",
+ "version": "1.0.0",
+ "publisher": "myisa",
+ "license": "MIT",
+ "engines": { "vscode": "^1.80.0" },
+ "categories": ["Programming Languages"],
+ "contributes": {
+ "languages": [{
+ "id": "isa",
+ "aliases": ["ISA Definition", "isa"],
+ "extensions": [".isa"],
+ "configuration": "./language-configuration.json",
+ "icon": {
+ "light": "./icon.png",
+ "dark": "./icon.png"
+ }
+ }],
+ "grammars": [{
+ "language": "isa",
+ "scopeName": "source.isa",
+ "path": "./syntaxes/isa.tmLanguage.json"
+ }]
+ }
+}
diff --git a/editors/vscode/syntaxes/isa.tmLanguage.json b/editors/vscode/syntaxes/isa.tmLanguage.json
new file mode 100644
index 0000000..c4de36a
--- /dev/null
+++ b/editors/vscode/syntaxes/isa.tmLanguage.json
@@ -0,0 +1,70 @@
+{
+ "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
+ "name": "ISA Definition",
+ "scopeName": "source.isa",
+ "fileTypes": ["isa"],
+ "patterns": [
+ { "include": "#comments" },
+ { "include": "#block-header" },
+ { "include": "#end-keyword" },
+ { "include": "#keys" },
+ { "include": "#hex-numbers" },
+ { "include": "#bit-ranges" },
+ { "include": "#booleans" },
+ { "include": "#numbers" },
+ { "include": "#names" }
+ ],
+ "repository": {
+ "comments": {
+ "patterns": [{
+ "match": "#.*$",
+ "name": "comment.line.hash.isa"
+ }]
+ },
+ "block-header": {
+ "patterns": [
+ {
+ "match": "\\b(ARCH|FORMAT|REGISTER|INSTRUCTION|CSR)\\b",
+ "name": "keyword.control.block-type.isa"
+ },
+ {
+ "match": "(?<=(ARCH|FORMAT|REGISTER|INSTRUCTION|CSR)\\s+)([A-Za-z_][A-Za-z0-9_]*)",
+ "name": "entity.name.type.isa"
+ }
+ ]
+ },
+ "end-keyword": {
+ "match": "\\bEND\\b",
+ "name": "keyword.control.end.isa"
+ },
+ "keys": {
+ "patterns": [
+ { "match": "\\b(NAME|VERSION|DATE|STATUS)\\b", "name": "support.type.property-name.meta.isa" },
+ { "match": "\\b(WIDTH|FIELD|FIELDS)\\b", "name": "support.type.property-name.format.isa" },
+ { "match": "\\b(ABBR|DESC|PRESERVE|CALLER|ARG|INDEX)\\b", "name": "support.type.property-name.register.isa" },
+ { "match": "\\b(FORMAT|OPCODE|FUNCT3|FUNCT7|OPERANDS|NOTE|CATEGORY|IMM)\\b", "name": "support.type.property-name.instruction.isa" },
+ { "match": "\\b(NUMBER)\\b", "name": "support.type.property-name.csr.isa" }
+ ]
+ },
+ "hex-numbers": {
+ "match": "\\b0[xX][0-9a-fA-F]+\\b",
+ "name": "constant.numeric.hex.isa"
+ },
+ "bit-ranges": {
+ "match": "\\b([0-9]+:[0-9]+)\\b",
+ "name": "constant.numeric.bit-range.isa"
+ },
+ "booleans": {
+ "match": "\\b(true|false|yes|no)\\b",
+ "name": "constant.language.boolean.isa"
+ },
+ "numbers": {
+ "match": "\\b[0-9]+\\b",
+ "name": "constant.numeric.decimal.isa"
+ },
+ "names": {
+ "match": "\\b([A-Za-z_][A-Za-z0-9_]*)\\b",
+ "name": "variable.other.isa"
+ }
+ }
+}
diff --git a/examples/README.md b/examples/README.md
new file mode 100644
index 0000000..b7b399c
--- /dev/null
+++ b/examples/README.md
@@ -0,0 +1,7 @@
+# Example Programs
+
+| Directory | Contents |
+|--------------|--------------------------------------|
+| `asm/` | Hand-written assembly examples |
+| `c/` | C programs compiled to Fyntv |
+| `benchmarks/`| Standard benchmark ports |
diff --git a/gen/README.md b/gen/README.md
new file mode 100644
index 0000000..958814c
--- /dev/null
+++ b/gen/README.md
@@ -0,0 +1,14 @@
+# Code Generators (C Programs)
+
+Each generator reads the ISA definitions (`../isa/`) and produces C source
+code for the assembler, disassembler, simulator, and documentation.
+
+| Generator | Input | Output |
+|------------------|-------------------|----------------------------------|
+| `tablegen/` | ISA encoding | Instruction decode tables |
+| `decoder/` | Encoding tables | Decode switch/case source |
+| `encoder/` | Opcode tables | Assembler encode logic |
+| `disassembler/` | Opcode tables | Disassembler string formatting |
+| `opcodes/` | Opcode YAML | `opcodes.h`, `opcodes.c` |
+| `abi/` | ABI spec | Calling convention stubs |
+| `docs/` | ISA YAML | RST/Markdown/HTML ISA manual |
diff --git a/gen/decoder/main.c b/gen/decoder/main.c
new file mode 100644
index 0000000..d9676f6
--- /dev/null
+++ b/gen/decoder/main.c
@@ -0,0 +1,3 @@
+// decoder — Generate C decoder source from tablegen output
+// Reads: tablegen output tables
+// Writes: decode.c / decode.h for the simulator and tools
diff --git a/gen/disassembler/main.c b/gen/disassembler/main.c
new file mode 100644
index 0000000..b3548c7
--- /dev/null
+++ b/gen/disassembler/main.c
@@ -0,0 +1,3 @@
+// disassembler — Generate disassembler source
+// Reads: opcode definitions from ../isa/opcodes/
+// Writes: disasm.c / disasm.h for objdump and the simulator
diff --git a/gen/docs/convert.sh b/gen/docs/convert.sh
new file mode 100644
index 0000000..047eb63
--- /dev/null
+++ b/gen/docs/convert.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+# convert.sh — Convert generated Markdown ISA doc to PDF
+# Usage: ./convert.sh [input.md] [output.pdf]
+#
+# Requires: pandoc + xelatex (or wkhtmltopdf)
+# Install: brew install pandoc mactex (macOS)
+# apt install pandoc texlive (Linux)
+
+set -e
+
+INPUT="${1:-../../doc/spec/isa_reference.md}"
+OUTPUT="${2:-../../doc/spec/isa_reference.pdf}"
+DIR="$(cd "$(dirname "$OUTPUT")" && pwd)"
+BASE="$(basename "$OUTPUT")"
+
+echo "Converting: $INPUT → $OUTPUT"
+
+if command -v pandoc >/dev/null 2>&1; then
+ if command -v xelatex >/dev/null 2>&1; then
+ pandoc "$INPUT" \
+ -o "$OUTPUT" \
+ --pdf-engine=xelatex \
+ -V geometry:margin=1in \
+ -V colorlinks=true \
+ -V linkcolor=blue \
+ -V toccolor=blue \
+ -V mainfont="Times New Roman" \
+ -V monofont="Courier New" \
+ --toc --toc-depth=3 \
+ --highlight-style=tango
+ echo "PDF generated: $OUTPUT"
+ elif command -v wkhtmltopdf >/dev/null 2>&1; then
+ DIR="$(dirname "$INPUT")"
+ pandoc "$INPUT" \
+ -o "${DIR}/isa_reference.html" \
+ --self-contained \
+ --toc --toc-depth=3
+ wkhtmltopdf \
+ --margin-top 20mm \
+ --margin-bottom 20mm \
+ --margin-left 15mm \
+ --margin-right 15mm \
+ --toc \
+ "${DIR}/isa_reference.html" "$OUTPUT"
+ echo "PDF generated: $OUTPUT"
+ else
+ echo "Error: No PDF engine found."
+ echo "Install: brew install pandoc mactex (macOS)"
+ echo " or: apt install pandoc texlive-latex-base (Linux)"
+ exit 1
+ fi
+else
+ echo "Error: pandoc not found. Install it first."
+ exit 1
+fi
diff --git a/gen/docs/generator.c b/gen/docs/generator.c
new file mode 100644
index 0000000..f67e42f
--- /dev/null
+++ b/gen/docs/generator.c
@@ -0,0 +1,481 @@
+#include "generator.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+static void write_title_page(FILE *out, const IsaDb *db) {
+ fprintf(out, "---\n");
+ fprintf(out, "title: \"%s Instruction Set Architecture\"\n", db->arch_name[0] ? db->arch_name : "Fyntv");
+ fprintf(out, "subtitle: \"Reference Manual\"\n");
+ fprintf(out, "version: \"%s\"\n", db->arch_version[0] ? db->arch_version : "1.0.0");
+ fprintf(out, "date: \"%s\"\n", db->arch_date[0] ? db->arch_date : "June 2026");
+ fprintf(out, "status: \"%s\"\n", db->arch_status[0] ? db->arch_status : "Draft");
+ fprintf(out, "geometry: margin=1in\n");
+ fprintf(out, "toc: true\n");
+ fprintf(out, "numbersections: true\n");
+ fprintf(out, "---\n\n");
+}
+
+static void write_revision_history(FILE *out, const IsaDb *db) {
+ fprintf(out, "\\newpage\n\n");
+ fprintf(out, "# Revision History\n\n");
+ fprintf(out, "| Version | Date | Description |\n");
+ fprintf(out, "|---------|------|-------------|\n");
+ fprintf(out, "| %s | %s | Initial %s release |\n",
+ db->arch_version[0] ? db->arch_version : "1.0.0",
+ db->arch_date[0] ? db->arch_date : "2026-06",
+ db->arch_name[0] ? db->arch_name : "ISA");
+ fprintf(out, "\n\\newpage\n\n");
+}
+
+static void write_toc_placeholder(FILE *out) {
+ fprintf(out, "\\tableofcontents\n\n");
+ fprintf(out, "\\newpage\n\n");
+}
+
+static void write_intro(FILE *out, const IsaDb *db) {
+ fprintf(out, "# Introduction\n\n");
+ fprintf(out, "This document defines the **%s Instruction Set Architecture (ISA)** version %s.\n\n",
+ db->arch_name[0] ? db->arch_name : "Fyntv",
+ db->arch_version[0] ? db->arch_version : "1.0.0");
+
+ fprintf(out, "## Scope\n\n");
+ fprintf(out, "This specification covers:\n\n");
+ fprintf(out, "- Instruction formats and encoding\n");
+ fprintf(out, "- Register file and calling convention\n");
+ fprintf(out, "- All base and extension instructions\n");
+ fprintf(out, "- Control and status registers (CSRs)\n");
+ fprintf(out, "- Exception and trap handling\n\n");
+
+ fprintf(out, "## ISA Overview\n\n");
+ fprintf(out, "The %s ISA is a load-store architecture with:\n\n",
+ db->arch_name[0] ? db->arch_name : "Fyntv");
+ fprintf(out, "- 32 general-purpose registers (x0–x31)\n");
+ fprintf(out, "- Fixed-width 32-bit instructions\n");
+ fprintf(out, "- Three operand formats: register (R-type), immediate (I-type), and store (S-type)\n");
+ fprintf(out, "- Branch (B-type) and upper-immediate (U-type) variants\n");
+ fprintf(out, "- A separate jump-and-link (J-type) format\n\n");
+ fprintf(out, "\\newpage\n\n");
+}
+
+static void write_registers(FILE *out, const IsaDb *db) {
+ fprintf(out, "# Registers\n\n");
+ fprintf(out, "## General-Purpose Registers\n\n");
+ fprintf(out, "The architecture provides 32 general-purpose registers (x0–x31), "
+ "each 32 bits wide. Register x0 is hardwired to the constant zero.\n\n");
+
+ fprintf(out, "| Register | ABI Name | Description | Callee-Saved |\n");
+ fprintf(out, "|----------|----------|-------------|--------------|\n");
+ for (int i = 0; i < db->num_registers; i++) {
+ const IsaRegister *r = &db->registers[i];
+ fprintf(out, "| %s | %s | %s | %s |\n",
+ r->name, r->abbr[0] ? r->abbr : "—",
+ r->desc[0] ? r->desc : "—",
+ r->preserve ? "Yes" : (r->preserve == 0 && r->index != 0 ? "No" : "—"));
+ }
+
+ fprintf(out, "\n### ABI Calling Convention\n\n");
+ fprintf(out, "| Register | ABI Name | Caller-Saved | Argument |\n");
+ fprintf(out, "|----------|----------|-------------|----------|\n");
+ for (int i = 0; i < db->num_registers; i++) {
+ const IsaRegister *r = &db->registers[i];
+ fprintf(out, "| %s | %s | %s | %s |\n",
+ r->name, r->abbr[0] ? r->abbr : "—",
+ r->caller_saved ? "Yes" : "No",
+ r->arg_reg ? "Yes" : "No");
+ }
+ fprintf(out, "\n\\newpage\n\n");
+}
+
+static void write_format_diagram(FILE *out, const IsaFormat *fmt) {
+ fprintf(out, "### %s-Type Format\n\n", fmt->name);
+ fprintf(out, "Bit width: **%d bits**\n\n", fmt->width);
+ fprintf(out, "```\n");
+
+ for (int row = 0; row < 3; row++) {
+ for (int j = fmt->num_fields - 1; j >= 0; j--) {
+ int fw = fmt->fields[j].high - fmt->fields[j].low + 1;
+ if (j < fmt->num_fields - 1) fputc('|', out);
+
+ if (row == 0) {
+ int rpad = (fw - 5) / 2;
+ int lpad = fw - 5 - rpad;
+ if (rpad < 0) rpad = 0;
+ if (lpad < 0) lpad = 0;
+ for (int k = 0; k < rpad; k++) fputc(' ', out);
+ fprintf(out, "%d:%d", fmt->fields[j].high, fmt->fields[j].low);
+ for (int k = 0; k < lpad; k++) fputc(' ', out);
+ } else if (row == 1) {
+ int slen = (int)strlen(fmt->fields[j].name);
+ int rpad = (fw - slen) / 2;
+ int lpad = fw - slen - rpad;
+ if (rpad < 0) rpad = 0;
+ if (lpad < 0) lpad = 0;
+ for (int k = 0; k < rpad; k++) fputc(' ', out);
+ fprintf(out, "%s", fmt->fields[j].name);
+ for (int k = 0; k < lpad; k++) fputc(' ', out);
+ } else {
+ char buf[16];
+ snprintf(buf, sizeof(buf), "%d", fw);
+ int slen = (int)strlen(buf);
+ int rpad = (fw - slen) / 2;
+ int lpad = fw - slen - rpad;
+ if (rpad < 0) rpad = 0;
+ if (lpad < 0) lpad = 0;
+ for (int k = 0; k < rpad; k++) fputc(' ', out);
+ fprintf(out, "%s", buf);
+ for (int k = 0; k < lpad; k++) fputc(' ', out);
+ }
+ }
+ fprintf(out, "\n");
+ }
+
+ fprintf(out, "```\n\n");
+}
+
+static void write_formats(FILE *out, const IsaDb *db) {
+ fprintf(out, "# Instruction Formats\n\n");
+ fprintf(out, "Instructions are encoded in one of several fixed formats. "
+ "All formats share the same opcode placement (bits 6:0) to "
+ "allow efficient decoding.\n\n");
+
+ for (int i = 0; i < db->num_formats; i++) {
+ write_format_diagram(out, &db->formats[i]);
+ }
+
+ fprintf(out, "\\newpage\n\n");
+}
+
+static int cat_cmp(const void *a, const void *b) {
+ return strcasecmp(((const IsaInstruction *)a)->category,
+ ((const IsaInstruction *)b)->category);
+}
+
+static void write_instructions(FILE *out, const IsaDb *db) {
+ fprintf(out, "# Instruction Set\n\n");
+
+ if (db->num_instructions == 0) {
+ fprintf(out, "No instructions defined.\n\n");
+ return;
+ }
+
+ IsaInstruction *sorted = malloc(db->num_instructions * sizeof(IsaInstruction));
+ if (!sorted) return;
+ memcpy(sorted, db->instructions, db->num_instructions * sizeof(IsaInstruction));
+ qsort(sorted, db->num_instructions, sizeof(IsaInstruction), cat_cmp);
+
+ char current_cat[MAX_LABEL] = "";
+ for (int i = 0; i < db->num_instructions; i++) {
+ const IsaInstruction *inst = &sorted[i];
+ const char *cat = inst->category[0] ? inst->category : "Uncategorized";
+
+ if (strcasecmp(current_cat, cat) != 0) {
+ strncpy(current_cat, cat, MAX_LABEL - 1);
+ fprintf(out, "## %s Operations\n\n", cat);
+
+ fprintf(out, "| Mnemonic | Format | Opcode | Funct3 | Funct7 | Operands | Description |\n");
+ fprintf(out, "|----------|--------|--------|--------|--------|----------|-------------|\n");
+ }
+
+ char f3buf[16], f7buf[16];
+ if (inst->funct3_valid) snprintf(f3buf, sizeof(f3buf), "0x%X", inst->funct3);
+ else strcpy(f3buf, "—");
+ if (inst->funct7_valid) snprintf(f7buf, sizeof(f7buf), "0x%02X", inst->funct7);
+ else strcpy(f7buf, "—");
+
+ fprintf(out, "| `%s` | %s | `0x%02X` | %s | %s | %s | %s |\n",
+ inst->name,
+ inst->fmt_name,
+ inst->opcode,
+ f3buf, f7buf,
+ inst->operands[0] ? inst->operands : "—",
+ inst->desc);
+ }
+
+ fprintf(out, "\n\\newpage\n\n");
+
+ fprintf(out, "## Instruction Details\n\n");
+ strcpy(current_cat, "");
+ for (int i = 0; i < db->num_instructions; i++) {
+ const IsaInstruction *inst = &sorted[i];
+ const char *cat = inst->category[0] ? inst->category : "Uncategorized";
+
+ if (strcasecmp(current_cat, cat) != 0) {
+ strncpy(current_cat, cat, MAX_LABEL - 1);
+ }
+
+ fprintf(out, "### %s\n\n", inst->name);
+ fprintf(out, "- **Format:** %s\n", inst->fmt_name);
+ fprintf(out, "- **Opcode:** `0x%02X`\n", inst->opcode);
+ if (inst->funct3_valid)
+ fprintf(out, "- **Funct3:** `0x%X`\n", inst->funct3);
+ if (inst->funct7_valid)
+ fprintf(out, "- **Funct7:** `0x%02X`\n", inst->funct7);
+ fprintf(out, "- **Operands:** `%s`\n", inst->operands[0] ? inst->operands : "(none)");
+ fprintf(out, "- **Description:** %s\n", inst->desc);
+ if (inst->note[0])
+ fprintf(out, "- **Operation:** `%s`\n", inst->note);
+ fprintf(out, "\n");
+ }
+
+ free(sorted);
+ fprintf(out, "\\newpage\n\n");
+}
+
+static void write_opcode_map(FILE *out, const IsaDb *db) {
+ fprintf(out, "# Opcode Map\n\n");
+ fprintf(out, "The following table shows the top-level opcode mapping. "
+ "The opcode occupies bits 6:0 of every instruction.\n\n");
+
+ fprintf(out, "| opcode[6:0] | Type | Instructions |\n");
+ fprintf(out, "|-------------|------|-------------|\n");
+
+ int seen_ops[128] = {0};
+ for (int i = 0; i < db->num_instructions; i++) {
+ const IsaInstruction *inst = &db->instructions[i];
+ int op = inst->opcode & 0x7F;
+ if (seen_ops[op]) continue;
+ seen_ops[op] = 1;
+
+ fprintf(out, "| `0x%02X` (%d) | %s | %s", op, op, inst->fmt_name, inst->name);
+ int count = 1;
+ for (int j = i + 1; j < db->num_instructions; j++) {
+ if ((db->instructions[j].opcode & 0x7F) == (unsigned)op) {
+ fprintf(out, ", %s", db->instructions[j].name);
+ count++;
+ }
+ }
+ fprintf(out, " (%d inst)%s |\n", count, count > 1 ? "s" : "");
+ }
+
+ fprintf(out, "\n### Encoding Matrix\n\n");
+ fprintf(out, "| opcode \\ funct3 |");
+ for (int f3 = 0; f3 < 8; f3++) fprintf(out, " %X |", f3);
+ fprintf(out, "\n");
+ fprintf(out, "|");
+ for (int f3 = 0; f3 < 9; f3++) fprintf(out, "---|");
+ fprintf(out, "\n");
+
+ int seen_ops2[128] = {0};
+ for (int i = 0; i < db->num_instructions; i++) {
+ const IsaInstruction *inst = &db->instructions[i];
+ int op = inst->opcode & 0x7F;
+ if (seen_ops2[op]) continue;
+ seen_ops2[op] = 1;
+
+ fprintf(out, "| `0x%02X` |", op);
+ for (int f3 = 0; f3 < 8; f3++) {
+ int found = 0;
+ for (int j = 0; j < db->num_instructions; j++) {
+ if ((db->instructions[j].opcode & 0x7F) == (unsigned)op &&
+ db->instructions[j].funct3 == (unsigned)f3 &&
+ db->instructions[j].funct3_valid) {
+ fprintf(out, " %s |", db->instructions[j].name);
+ found = 1;
+ break;
+ }
+ }
+ if (!found) fprintf(out, " — |");
+ }
+ fprintf(out, "\n");
+ }
+
+ fprintf(out, "\n\\newpage\n\n");
+}
+
+static void write_csrs(FILE *out, const IsaDb *db) {
+ if (db->num_csrs == 0) return;
+
+ fprintf(out, "# Control and Status Registers\n\n");
+ fprintf(out, "The following CSRs are accessible via the `CSRRW`, `CSRRS`, "
+ "`CSRRC`, and their immediate variants.\n\n");
+
+ fprintf(out, "| Address | Name | Description |\n");
+ fprintf(out, "|---------|------|-------------|\n");
+ for (int i = 0; i < db->num_csrs; i++) {
+ fprintf(out, "| `0x%03X` | %s | %s |\n",
+ db->csrs[i].number, db->csrs[i].name, db->csrs[i].desc);
+ }
+ fprintf(out, "\n\\newpage\n\n");
+}
+
+static void write_exceptions(FILE *out) {
+ fprintf(out, "# Exception and Trap Handling\n\n");
+ fprintf(out, "## Exception Types\n\n");
+ fprintf(out, "| Exception Code | Name | Description |\n");
+ fprintf(out, "|----------------|------|-------------|\n");
+ fprintf(out, "| 0 | Instruction address misaligned | PC not aligned to 4 bytes |\n");
+ fprintf(out, "| 1 | Instruction access fault | Failed to fetch instruction |\n");
+ fprintf(out, "| 2 | Illegal instruction | Unrecognized opcode |\n");
+ fprintf(out, "| 3 | Breakpoint | EBREAK instruction executed |\n");
+ fprintf(out, "| 4 | Load address misaligned | Load address not properly aligned |\n");
+ fprintf(out, "| 5 | Load access fault | Failed to load from memory |\n");
+ fprintf(out, "| 6 | Store address misaligned | Store address not properly aligned |\n");
+ fprintf(out, "| 7 | Store access fault | Failed to store to memory |\n");
+ fprintf(out, "| 8 | Environment call from U-mode | ECALL in user mode |\n");
+ fprintf(out, "| 9 | Environment call from S-mode | ECALL in supervisor mode |\n");
+ fprintf(out, "| 11 | Environment call from M-mode | ECALL in machine mode |\n\n");
+
+ fprintf(out, "## Trap Vector\n\n");
+ fprintf(out, "On taking a trap, the implementation:\n\n");
+ fprintf(out, "1. Sets `mepc` to the PC of the trapping instruction (or next PC for ECALL/EBREAK)\n");
+ fprintf(out, "2. Sets `mcause` to the exception code\n");
+ fprintf(out, "3. Sets `mtval` to exception-specific information\n");
+ fprintf(out, "4. Sets `mstatus.MPP` to the current privilege mode\n");
+ fprintf(out, "5. Sets `mstatus.MPIE` to `mstatus.MIE`\n");
+ fprintf(out, "6. Clears `mstatus.MIE`\n");
+ fprintf(out, "7. Sets PC to `mtvec`\n\n");
+
+ fprintf(out, "\\newpage\n\n");
+}
+
+static void write_pseudo_instructions(FILE *out) {
+ fprintf(out, "# Pseudo-Instructions\n\n");
+ fprintf(out, "| Pseudo-instruction | Expansion | Description |\n");
+ fprintf(out, "|-------------------|-----------|-------------|\n");
+ fprintf(out, "| `NOP` | `ADDI x0, x0, 0` | No operation |\n");
+ fprintf(out, "| `MV rd, rs` | `ADDI rd, rs, 0` | Copy register |\n");
+ fprintf(out, "| `NOT rd, rs` | `XORI rd, rs, -1` | Bitwise NOT |\n");
+ fprintf(out, "| `NEG rd, rs` | `SUB rd, x0, rs` | Negate register |\n");
+ fprintf(out, "| `LI rd, imm` | (multiple) | Load immediate |\n");
+ fprintf(out, "| `LA rd, label` | (multiple) | Load address |\n");
+ fprintf(out, "| `RET` | `JALR x0, x1, 0` | Return from subroutine |\n");
+ fprintf(out, "| `CALL label` | (multiple) | Call subroutine |\n");
+ fprintf(out, "| `J label` | `JAL x0, label` | Unconditional jump |\n");
+ fprintf(out, "| `JR rs` | `JALR x0, rs, 0` | Jump register |\n");
+ fprintf(out, "\n\\newpage\n\n");
+}
+
+static void write_quick_reference(FILE *out) {
+ fprintf(out, "# Quick Reference\n\n");
+ fprintf(out, "## Instruction Encoding Quick Reference\n\n");
+
+ fprintf(out, "### R-Type\n\n");
+ fprintf(out, "```\n");
+ fprintf(out, " 31:27 | 26:25 | 24:20 | 19:15 | 14:12 | 11:7 | 6:0\n");
+ fprintf(out, " funct7 | — | rs2 | rs1 | funct3 | rd | opcode\n");
+ fprintf(out, " 7 | 2 | 5 | 5 | 3 | 5 | 7\n");
+ fprintf(out, "```\n\n");
+
+ fprintf(out, "### I-Type\n\n");
+ fprintf(out, "```\n");
+ fprintf(out, " 31:20 | 19:15 | 14:12 | 11:7 | 6:0\n");
+ fprintf(out, " imm[11:0]| rs1 | funct3 | rd | opcode\n");
+ fprintf(out, " 12 | 5 | 3 | 5 | 7\n");
+ fprintf(out, "```\n\n");
+
+ fprintf(out, "### S-Type\n\n");
+ fprintf(out, "```\n");
+ fprintf(out, " 31:27 | 26:25 | 24:20 | 19:15 | 14:12 | 11:7 | 6:0\n");
+ fprintf(out, " imm[11:5]| — | rs2 | rs1 | funct3 | imm[4:0]| opcode\n");
+ fprintf(out, " 7 | 2 | 5 | 5 | 3 | 5 | 7\n");
+ fprintf(out, "```\n\n");
+
+ fprintf(out, "### B-Type\n\n");
+ fprintf(out, "```\n");
+ fprintf(out, " 31 | 30:27 | 26:25 | 24:20 | 19:15 | 14:12 | 11:8 | 7 | 6:0\n");
+ fprintf(out, " imm[12]| imm[10:5]| — | rs2 | rs1 | funct3 | imm[4:1]| imm[11]| opcode\n");
+ fprintf(out, " 1 | 6 | 2 | 5 | 5 | 3 | 4 | 1 | 7\n");
+ fprintf(out, "```\n\n");
+
+ fprintf(out, "### U-Type\n\n");
+ fprintf(out, "```\n");
+ fprintf(out, " 31:12 | 11:7 | 6:0\n");
+ fprintf(out, " imm[31:12] | rd | opcode\n");
+ fprintf(out, " 20 | 5 | 7\n");
+ fprintf(out, "```\n\n");
+
+ fprintf(out, "### J-Type\n\n");
+ fprintf(out, "```\n");
+ fprintf(out, " 31 | 30:21 | 20 | 19:12 | 11:7 | 6:0\n");
+ fprintf(out, " imm[20]| imm[10:1]| imm[11]| imm[19:12]| rd | opcode\n");
+ fprintf(out, " 1 | 10 | 1 | 8 | 5 | 7\n");
+ fprintf(out, "```\n\n");
+}
+
+int gen_markdown(const IsaDb *db, const char *output_path) {
+ FILE *out = fopen(output_path, "w");
+ if (!out) {
+ fprintf(stderr, "Error: cannot write to %s\n", output_path);
+ return -1;
+ }
+
+ printf("Generating: %s\n", output_path);
+ printf(" Formats: %d\n", db->num_formats);
+ printf(" Registers: %d\n", db->num_registers);
+ printf(" Instructions: %d\n", db->num_instructions);
+ printf(" CSRs: %d\n", db->num_csrs);
+
+ write_title_page(out, db);
+ write_revision_history(out, db);
+ write_toc_placeholder(out);
+ write_intro(out, db);
+ write_registers(out, db);
+ write_formats(out, db);
+ write_instructions(out, db);
+ write_opcode_map(out, db);
+ write_exceptions(out);
+ write_pseudo_instructions(out);
+
+ if (db->num_csrs > 0)
+ write_csrs(out, db);
+
+ write_quick_reference(out);
+
+ fclose(out);
+ printf(" Done: %s\n", output_path);
+ return 0;
+}
+
+int gen_html(const IsaDb *db, const char *output_path) {
+ FILE *out = fopen(output_path, "w");
+ if (!out) {
+ fprintf(stderr, "Error: cannot write to %s\n", output_path);
+ return -1;
+ }
+
+ fprintf(out, "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n");
+ fprintf(out, "<meta charset=\"UTF-8\">\n");
+ fprintf(out, "<title>%s ISA Reference Manual</title>\n",
+ db->arch_name[0] ? db->arch_name : "Fyntv");
+ fprintf(out, "<link rel=\"stylesheet\" href=\"style.css\">\n");
+ fprintf(out, "</head>\n<body>\n<article>\n");
+
+ fprintf(out, "<header>\n");
+ fprintf(out, "<h1>%s Instruction Set Architecture</h1>\n",
+ db->arch_name[0] ? db->arch_name : "Fyntv");
+ fprintf(out, "<p class=\"subtitle\">Reference Manual</p>\n");
+ fprintf(out, "<p><strong>Version:</strong> %s &nbsp;|&nbsp; <strong>Date:</strong> %s</p>\n",
+ db->arch_version[0] ? db->arch_version : "1.0.0",
+ db->arch_date[0] ? db->arch_date : "June 2026");
+ fprintf(out, "</header>\n");
+
+ fprintf(out, "<section id=\"registers\">\n");
+ fprintf(out, "<h2>Registers</h2>\n");
+ fprintf(out, "<table><thead><tr><th>Register</th><th>ABI Name</th><th>Description</th><th>Saved</th></tr></thead><tbody>\n");
+ for (int i = 0; i < db->num_registers; i++) {
+ fprintf(out, "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n",
+ db->registers[i].name,
+ db->registers[i].abbr[0] ? db->registers[i].abbr : "—",
+ db->registers[i].desc[0] ? db->registers[i].desc : "—",
+ db->registers[i].preserve ? "Yes" : "No");
+ }
+ fprintf(out, "</tbody></table>\n</section>\n");
+
+ fprintf(out, "<section id=\"instructions\">\n");
+ fprintf(out, "<h2>Instruction Set</h2>\n");
+ fprintf(out, "<table><thead><tr><th>Mnemonic</th><th>Format</th><th>Opcode</th><th>Operands</th><th>Description</th></tr></thead><tbody>\n");
+ for (int i = 0; i < db->num_instructions; i++) {
+ fprintf(out, "<tr><td><code>%s</code></td><td>%s</td><td><code>0x%02X</code></td><td><code>%s</code></td><td>%s</td></tr>\n",
+ db->instructions[i].name,
+ db->instructions[i].fmt_name,
+ db->instructions[i].opcode,
+ db->instructions[i].operands[0] ? db->instructions[i].operands : "—",
+ db->instructions[i].desc);
+ }
+ fprintf(out, "</tbody></table>\n</section>\n");
+
+ fprintf(out, "</article>\n</body>\n</html>\n");
+ fclose(out);
+ return 0;
+}
diff --git a/gen/docs/generator.h b/gen/docs/generator.h
new file mode 100644
index 0000000..407b47a
--- /dev/null
+++ b/gen/docs/generator.h
@@ -0,0 +1,9 @@
+#ifndef GENERATOR_H
+#define GENERATOR_H
+
+#include "types.h"
+
+int gen_markdown(const IsaDb *db, const char *output_path);
+int gen_html(const IsaDb *db, const char *output_path);
+
+#endif
diff --git a/gen/docs/isa-docgen b/gen/docs/isa-docgen
new file mode 100755
index 0000000..c330db7
--- /dev/null
+++ b/gen/docs/isa-docgen
Binary files differ
diff --git a/gen/docs/isa_defs/arch.isa b/gen/docs/isa_defs/arch.isa
new file mode 100644
index 0000000..f1added
--- /dev/null
+++ b/gen/docs/isa_defs/arch.isa
@@ -0,0 +1,68 @@
+# Fyntv Architecture Definition
+ARCH Fyntv
+ NAME Fyntv
+ VERSION 0.0.0.1
+ DATE June 2026
+ STATUS Draft
+END
+
+# =============================================================================
+# Instruction Formats
+# =============================================================================
+
+FORMAT R
+ WIDTH 32
+ FIELD opcode 6:0
+ FIELD rd 11:7
+ FIELD funct3 14:12
+ FIELD rs1 19:15
+ FIELD rs2 24:20
+ FIELD funct7 31:25
+END
+
+FORMAT I
+ WIDTH 32
+ FIELD opcode 6:0
+ FIELD rd 11:7
+ FIELD funct3 14:12
+ FIELD rs1 19:15
+ FIELD imm 31:20
+END
+
+FORMAT S
+ WIDTH 32
+ FIELD opcode 6:0
+ FIELD imm_lo 11:7
+ FIELD funct3 14:12
+ FIELD rs1 19:15
+ FIELD rs2 24:20
+ FIELD imm_hi 31:25
+END
+
+FORMAT B
+ WIDTH 32
+ FIELD opcode 6:0
+ FIELD imm_4_1 11:7
+ FIELD funct3 14:12
+ FIELD rs1 19:15
+ FIELD rs2 24:20
+ FIELD imm_10_5 30:25
+ FIELD imm_12 31:31
+END
+
+FORMAT U
+ WIDTH 32
+ FIELD opcode 6:0
+ FIELD rd 11:7
+ FIELD imm 31:12
+END
+
+FORMAT J
+ WIDTH 32
+ FIELD opcode 6:0
+ FIELD rd 11:7
+ FIELD imm_19_12 19:12
+ FIELD imm_11 20:20
+ FIELD imm_10_1 30:21
+ FIELD imm_20 31:31
+END
diff --git a/gen/docs/isa_defs/csrs.isa b/gen/docs/isa_defs/csrs.isa
new file mode 100644
index 0000000..e2098ef
--- /dev/null
+++ b/gen/docs/isa_defs/csrs.isa
@@ -0,0 +1,191 @@
+# Fyntv Control and Status Register Definitions
+
+CSR mstatus
+ NUMBER 0x300
+ DESC Machine status register — holds global interrupt enable and privilege state
+END
+
+CSR misa
+ NUMBER 0x301
+ DESC Machine ISA register — encodes supported ISA extensions
+END
+
+CSR medeleg
+ NUMBER 0x302
+ DESC Machine exception delegation register
+END
+
+CSR mideleg
+ NUMBER 0x303
+ DESC Machine interrupt delegation register
+END
+
+CSR mie
+ NUMBER 0x304
+ DESC Machine interrupt-enable register
+END
+
+CSR mtvec
+ NUMBER 0x305
+ DESC Machine trap-handler base address
+END
+
+CSR mcounteren
+ NUMBER 0x306
+ DESC Machine counter enable register
+END
+
+CSR mscratch
+ NUMBER 0x340
+ DESC Scratch register for machine-mode trap handlers
+END
+
+CSR mepc
+ NUMBER 0x341
+ DESC Machine exception program counter — holds PC of trapping instruction
+END
+
+CSR mcause
+ NUMBER 0x342
+ DESC Machine trap cause — encodes exception or interrupt cause
+END
+
+CSR mtval
+ NUMBER 0x343
+ DESC Machine trap value — exception-specific information
+END
+
+CSR mip
+ NUMBER 0x344
+ DESC Machine interrupt pending register
+END
+
+CSR pmpcfg0
+ NUMBER 0x3A0
+ DESC Physical memory protection configuration 0
+END
+
+CSR pmpaddr0
+ NUMBER 0x3B0
+ DESC Physical memory protection address 0
+END
+
+CSR pmpaddr1
+ NUMBER 0x3B1
+ DESC Physical memory protection address 1
+END
+
+CSR pmpaddr2
+ NUMBER 0x3B2
+ DESC Physical memory protection address 2
+END
+
+CSR pmpaddr3
+ NUMBER 0x3B3
+ DESC Physical memory protection address 3
+END
+
+CSR mcycle
+ NUMBER 0xB00
+ DESC Machine cycle counter — counts number of clock cycles
+END
+
+CSR minstret
+ NUMBER 0xB02
+ DESC Machine instructions-retired counter
+END
+
+CSR mhpmcounter3
+ NUMBER 0xB03
+ DESC Machine hardware performance counter 3
+END
+
+CSR mhpmcounter4
+ NUMBER 0xB04
+ DESC Machine hardware performance counter 4
+END
+
+CSR mhpmcounter5
+ NUMBER 0xB05
+ DESC Machine hardware performance counter 5
+END
+
+CSR mhpmevent3
+ NUMBER 0x323
+ DESC Machine hardware performance event selector 3
+END
+
+CSR mhpmevent4
+ NUMBER 0x324
+ DESC Machine hardware performance event selector 4
+END
+
+CSR mhpmevent5
+ NUMBER 0x325
+ DESC Machine hardware performance event selector 5
+END
+
+CSR ucycle
+ NUMBER 0xC00
+ DESC User-mode cycle counter read
+END
+
+CSR uinstret
+ NUMBER 0xC02
+ DESC User-mode instructions-retired read
+END
+
+CSR ucycleh
+ NUMBER 0xC80
+ DESC Upper 32 bits of user-mode cycle counter
+END
+
+CSR uinstreth
+ NUMBER 0xC82
+ DESC Upper 32 bits of user-mode instructions-retired counter
+END
+
+CSR sstatus
+ NUMBER 0x100
+ DESC Supervisor status register
+END
+
+CSR sie
+ NUMBER 0x104
+ DESC Supervisor interrupt-enable register
+END
+
+CSR stvec
+ NUMBER 0x105
+ DESC Supervisor trap-handler base address
+END
+
+CSR sscratch
+ NUMBER 0x140
+ DESC Scratch register for supervisor-mode trap handlers
+END
+
+CSR sepc
+ NUMBER 0x141
+ DESC Supervisor exception program counter
+END
+
+CSR scause
+ NUMBER 0x142
+ DESC Supervisor trap cause register
+END
+
+CSR stval
+ NUMBER 0x143
+ DESC Supervisor trap value register
+END
+
+CSR sip
+ NUMBER 0x144
+ DESC Supervisor interrupt pending register
+END
+
+CSR satp
+ NUMBER 0x180
+ DESC Supervisor address translation and protection — controls page tables
+END
diff --git a/gen/docs/isa_defs/instructions.isa b/gen/docs/isa_defs/instructions.isa
new file mode 100644
index 0000000..c7255d3
--- /dev/null
+++ b/gen/docs/isa_defs/instructions.isa
@@ -0,0 +1,512 @@
+# Fyntv Core Integer Instructions
+
+INSTRUCTION ADD
+ FORMAT R
+ OPCODE 0x33
+ FUNCT3 0x0
+ FUNCT7 0x00
+ OPERANDS rd, rs1, rs2
+ DESC Add registers
+ NOTE rd = rs1 + rs2
+ CATEGORY Integer
+END
+
+INSTRUCTION SUB
+ FORMAT R
+ OPCODE 0x33
+ FUNCT3 0x0
+ FUNCT7 0x20
+ OPERANDS rd, rs1, rs2
+ DESC Subtract registers
+ NOTE rd = rs1 - rs2
+ CATEGORY Integer
+END
+
+INSTRUCTION ADDI
+ FORMAT I
+ OPCODE 0x13
+ FUNCT3 0x0
+ OPERANDS rd, rs1, imm12
+ DESC Add sign-extended 12-bit immediate to register rs1
+ NOTE rd = rs1 + sext(imm12)
+ CATEGORY Integer
+ IMM true
+END
+
+INSTRUCTION SLT
+ FORMAT R
+ OPCODE 0x33
+ FUNCT3 0x2
+ FUNCT7 0x00
+ OPERANDS rd, rs1, rs2
+ DESC Set if rs1 is less than rs2 (signed)
+ NOTE rd = (rs1 < rs2) ? 1 : 0
+ CATEGORY Integer
+END
+
+INSTRUCTION SLTU
+ FORMAT R
+ OPCODE 0x33
+ FUNCT3 0x3
+ FUNCT7 0x00
+ OPERANDS rd, rs1, rs2
+ DESC Set if rs1 is less than rs2 (unsigned)
+ NOTE rd = (rs1 < rs2) ? 1 : 0
+ CATEGORY Integer
+END
+
+INSTRUCTION SLTI
+ FORMAT I
+ OPCODE 0x13
+ FUNCT3 0x2
+ OPERANDS rd, rs1, imm12
+ DESC Set if rs1 is less than immediate (signed)
+ NOTE rd = (rs1 < sext(imm12)) ? 1 : 0
+ CATEGORY Integer
+ IMM true
+END
+
+INSTRUCTION SLTIU
+ FORMAT I
+ OPCODE 0x13
+ FUNCT3 0x3
+ OPERANDS rd, rs1, imm12
+ DESC Set if rs1 is less than immediate (unsigned)
+ NOTE rd = (rs1 < sext(imm12)) ? 1 : 0
+ CATEGORY Integer
+ IMM true
+END
+
+INSTRUCTION LUI
+ FORMAT U
+ OPCODE 0x37
+ OPERANDS rd, imm20
+ DESC Load upper immediate — places 20-bit immediate in upper 20 bits of rd
+ NOTE rd = imm20 << 12
+ CATEGORY Integer
+END
+
+INSTRUCTION AUIPC
+ FORMAT U
+ OPCODE 0x17
+ OPERANDS rd, imm20
+ DESC Add upper immediate to PC — forms PC-relative address
+ NOTE rd = PC + (imm20 << 12)
+ CATEGORY Integer
+END
+
+# =============================================================================
+# Logical Instructions
+# =============================================================================
+
+INSTRUCTION AND
+ FORMAT R
+ OPCODE 0x33
+ FUNCT3 0x7
+ FUNCT7 0x00
+ OPERANDS rd, rs1, rs2
+ DESC Bitwise AND
+ NOTE rd = rs1 & rs2
+ CATEGORY Logical
+END
+
+INSTRUCTION OR
+ FORMAT R
+ OPCODE 0x33
+ FUNCT3 0x6
+ FUNCT7 0x00
+ OPERANDS rd, rs1, rs2
+ DESC Bitwise OR
+ NOTE rd = rs1 | rs2
+ CATEGORY Logical
+END
+
+INSTRUCTION XOR
+ FORMAT R
+ OPCODE 0x33
+ FUNCT3 0x4
+ FUNCT7 0x00
+ OPERANDS rd, rs1, rs2
+ DESC Bitwise XOR
+ NOTE rd = rs1 ^ rs2
+ CATEGORY Logical
+END
+
+INSTRUCTION ANDI
+ FORMAT I
+ OPCODE 0x13
+ FUNCT3 0x7
+ OPERANDS rd, rs1, imm12
+ DESC Bitwise AND with immediate
+ NOTE rd = rs1 & sext(imm12)
+ CATEGORY Logical
+ IMM true
+END
+
+INSTRUCTION ORI
+ FORMAT I
+ OPCODE 0x13
+ FUNCT3 0x6
+ OPERANDS rd, rs1, imm12
+ DESC Bitwise OR with immediate
+ NOTE rd = rs1 | sext(imm12)
+ CATEGORY Logical
+ IMM true
+END
+
+INSTRUCTION XORI
+ FORMAT I
+ OPCODE 0x13
+ FUNCT3 0x4
+ OPERANDS rd, rs1, imm12
+ DESC Bitwise XOR with immediate
+ NOTE rd = rs1 ^ sext(imm12)
+ CATEGORY Logical
+ IMM true
+END
+
+# =============================================================================
+# Shift Instructions
+# =============================================================================
+
+INSTRUCTION SLL
+ FORMAT R
+ OPCODE 0x33
+ FUNCT3 0x1
+ FUNCT7 0x00
+ OPERANDS rd, rs1, rs2
+ DESC Logical left shift by lower 5 bits of rs2
+ NOTE rd = rs1 << rs2[4:0]
+ CATEGORY Shift
+END
+
+INSTRUCTION SRL
+ FORMAT R
+ OPCODE 0x33
+ FUNCT3 0x5
+ FUNCT7 0x00
+ OPERANDS rd, rs1, rs2
+ DESC Logical right shift by lower 5 bits of rs2
+ NOTE rd = rs1 >> rs2[4:0]
+ CATEGORY Shift
+END
+
+INSTRUCTION SRA
+ FORMAT R
+ OPCODE 0x33
+ FUNCT3 0x5
+ FUNCT7 0x20
+ OPERANDS rd, rs1, rs2
+ DESC Arithmetic right shift by lower 5 bits of rs2
+ NOTE rd = rs1 >>> rs2[4:0]
+ CATEGORY Shift
+END
+
+INSTRUCTION SLLI
+ FORMAT I
+ OPCODE 0x13
+ FUNCT3 0x1
+ OPERANDS rd, rs1, shamt5
+ DESC Logical left shift by immediate shift amount
+ NOTE rd = rs1 << shamt
+ CATEGORY Shift
+END
+
+INSTRUCTION SRLI
+ FORMAT I
+ OPCODE 0x13
+ FUNCT3 0x5
+ OPERANDS rd, rs1, shamt5
+ DESC Logical right shift by immediate shift amount
+ NOTE rd = rs1 >> shamt
+ CATEGORY Shift
+END
+
+INSTRUCTION SRAI
+ FORMAT I
+ OPCODE 0x13
+ FUNCT3 0x5
+ OPERANDS rd, rs1, shamt5
+ DESC Arithmetic right shift by immediate shift amount
+ NOTE rd = rs1 >>> shamt
+ CATEGORY Shift
+END
+
+# =============================================================================
+# Memory Instructions
+# =============================================================================
+
+INSTRUCTION LB
+ FORMAT I
+ OPCODE 0x03
+ FUNCT3 0x0
+ OPERANDS rd, offset(rs1)
+ DESC Load byte (sign-extended)
+ NOTE rd = sext(MEM[rs1 + offset][7:0])
+ CATEGORY Memory
+END
+
+INSTRUCTION LH
+ FORMAT I
+ OPCODE 0x03
+ FUNCT3 0x1
+ OPERANDS rd, offset(rs1)
+ DESC Load halfword (sign-extended)
+ NOTE rd = sext(MEM[rs1 + offset][15:0])
+ CATEGORY Memory
+END
+
+INSTRUCTION LW
+ FORMAT I
+ OPCODE 0x03
+ FUNCT3 0x2
+ OPERANDS rd, offset(rs1)
+ DESC Load word
+ NOTE rd = MEM[rs1 + offset][31:0]
+ CATEGORY Memory
+END
+
+INSTRUCTION LBU
+ FORMAT I
+ OPCODE 0x03
+ FUNCT3 0x4
+ OPERANDS rd, offset(rs1)
+ DESC Load byte (zero-extended)
+ NOTE rd = MEM[rs1 + offset][7:0]
+ CATEGORY Memory
+END
+
+INSTRUCTION LHU
+ FORMAT I
+ OPCODE 0x03
+ FUNCT3 0x5
+ OPERANDS rd, offset(rs1)
+ DESC Load halfword (zero-extended)
+ NOTE rd = MEM[rs1 + offset][15:0]
+ CATEGORY Memory
+END
+
+INSTRUCTION SB
+ FORMAT S
+ OPCODE 0x23
+ FUNCT3 0x0
+ OPERANDS rs2, offset(rs1)
+ DESC Store byte
+ NOTE MEM[rs1 + offset][7:0] = rs2[7:0]
+ CATEGORY Memory
+END
+
+INSTRUCTION SH
+ FORMAT S
+ OPCODE 0x23
+ FUNCT3 0x1
+ OPERANDS rs2, offset(rs1)
+ DESC Store halfword
+ NOTE MEM[rs1 + offset][15:0] = rs2[15:0]
+ CATEGORY Memory
+END
+
+INSTRUCTION SW
+ FORMAT S
+ OPCODE 0x23
+ FUNCT3 0x2
+ OPERANDS rs2, offset(rs1)
+ DESC Store word
+ NOTE MEM[rs1 + offset][31:0] = rs2[31:0]
+ CATEGORY Memory
+END
+
+# =============================================================================
+# Branch Instructions
+# =============================================================================
+
+INSTRUCTION BEQ
+ FORMAT B
+ OPCODE 0x63
+ FUNCT3 0x0
+ OPERANDS rs1, rs2, label
+ DESC Branch equal
+ NOTE if (rs1 == rs2) PC += sext(offset)
+ CATEGORY Branch
+END
+
+INSTRUCTION BNE
+ FORMAT B
+ OPCODE 0x63
+ FUNCT3 0x1
+ OPERANDS rs1, rs2, label
+ DESC Branch not equal
+ NOTE if (rs1 != rs2) PC += sext(offset)
+ CATEGORY Branch
+END
+
+INSTRUCTION BLT
+ FORMAT B
+ OPCODE 0x63
+ FUNCT3 0x4
+ OPERANDS rs1, rs2, label
+ DESC Branch less than (signed)
+ NOTE if (rs1 < rs2) PC += sext(offset)
+ CATEGORY Branch
+END
+
+INSTRUCTION BGE
+ FORMAT B
+ OPCODE 0x63
+ FUNCT3 0x5
+ OPERANDS rs1, rs2, label
+ DESC Branch greater than or equal (signed)
+ NOTE if (rs1 >= rs2) PC += sext(offset)
+ CATEGORY Branch
+END
+
+INSTRUCTION BLTU
+ FORMAT B
+ OPCODE 0x63
+ FUNCT3 0x6
+ OPERANDS rs1, rs2, label
+ DESC Branch less than (unsigned)
+ NOTE if (rs1 < rs2) PC += sext(offset)
+ CATEGORY Branch
+END
+
+INSTRUCTION BGEU
+ FORMAT B
+ OPCODE 0x63
+ FUNCT3 0x7
+ OPERANDS rs1, rs2, label
+ DESC Branch greater than or equal (unsigned)
+ NOTE if (rs1 >= rs2) PC += sext(offset)
+ CATEGORY Branch
+END
+
+# =============================================================================
+# Jump Instructions
+# =============================================================================
+
+INSTRUCTION JAL
+ FORMAT J
+ OPCODE 0x6F
+ OPERANDS rd, label
+ DESC Jump and link — jump to PC+offset, save return address to rd
+ NOTE rd = PC + 4; PC += sext(offset)
+ CATEGORY Jump
+END
+
+INSTRUCTION JALR
+ FORMAT I
+ OPCODE 0x67
+ FUNCT3 0x0
+ OPERANDS rd, rs1, offset
+ DESC Jump and link register — jump to rs1+offset, save return address
+ NOTE rd = PC + 4; PC = (rs1 + sext(offset)) & ~1
+ CATEGORY Jump
+END
+
+# =============================================================================
+# Synchronization Instructions
+# =============================================================================
+
+INSTRUCTION FENCE
+ FORMAT I
+ OPCODE 0x0F
+ FUNCT3 0x0
+ OPERANDS pred, succ
+ DESC Memory ordering fence
+ NOTE Orders memory accesses as specified by pred and succ fields
+ CATEGORY Synchronization
+END
+
+INSTRUCTION FENCEI
+ FORMAT I
+ OPCODE 0x0F
+ FUNCT3 0x1
+ OPERANDS —
+ DESC Instruction fence — synchronizes instruction and data streams
+ NOTE Flushes instruction cache after data writes
+ CATEGORY Synchronization
+END
+
+# =============================================================================
+# System Instructions
+# =============================================================================
+
+INSTRUCTION ECALL
+ FORMAT I
+ OPCODE 0x73
+ FUNCT3 0x0
+ OPERANDS —
+ DESC Environment call — raises a system call exception
+ NOTE Traps to the configured exception handler
+ CATEGORY System
+END
+
+INSTRUCTION EBREAK
+ FORMAT I
+ OPCODE 0x73
+ FUNCT3 0x0
+ OPERANDS —
+ DESC Breakpoint — raises a breakpoint exception
+ NOTE Used by debuggers to halt program execution
+ CATEGORY System
+END
+
+INSTRUCTION CSRRW
+ FORMAT I
+ OPCODE 0x73
+ FUNCT3 0x1
+ OPERANDS rd, csr, rs1
+ DESC Atomic read/write CSR — writes rs1 to CSR, returns old value in rd
+ NOTE rd = CSR[csr]; CSR[csr] = rs1
+ CATEGORY System
+END
+
+INSTRUCTION CSRRS
+ FORMAT I
+ OPCODE 0x73
+ FUNCT3 0x2
+ OPERANDS rd, csr, rs1
+ DESC Atomic read and set bits in CSR
+ NOTE rd = CSR[csr]; CSR[csr] |= rs1
+ CATEGORY System
+END
+
+INSTRUCTION CSRRC
+ FORMAT I
+ OPCODE 0x73
+ FUNCT3 0x3
+ OPERANDS rd, csr, rs1
+ DESC Atomic read and clear bits in CSR
+ NOTE rd = CSR[csr]; CSR[csr] &= ~rs1
+ CATEGORY System
+END
+
+INSTRUCTION CSRRWI
+ FORMAT I
+ OPCODE 0x73
+ FUNCT3 0x5
+ OPERANDS rd, csr, uimm5
+ DESC Atomic read/write CSR with immediate
+ NOTE rd = CSR[csr]; CSR[csr] = zimm
+ CATEGORY System
+END
+
+INSTRUCTION CSRRSI
+ FORMAT I
+ OPCODE 0x73
+ FUNCT3 0x6
+ OPERANDS rd, csr, uimm5
+ DESC Atomic read and set bits in CSR with immediate
+ NOTE rd = CSR[csr]; CSR[csr] |= zimm
+ CATEGORY System
+END
+
+INSTRUCTION CSRRCI
+ FORMAT I
+ OPCODE 0x73
+ FUNCT3 0x7
+ OPERANDS rd, csr, uimm5
+ DESC Atomic read and clear bits in CSR with immediate
+ NOTE rd = CSR[csr]; CSR[csr] &= ~zimm
+ CATEGORY System
+END
diff --git a/gen/docs/isa_defs/registers.isa b/gen/docs/isa_defs/registers.isa
new file mode 100644
index 0000000..baa8124
--- /dev/null
+++ b/gen/docs/isa_defs/registers.isa
@@ -0,0 +1,289 @@
+# Fyntv Register Definitions
+
+REGISTER x0
+ ABBR zero
+ DESC Always-zero register — reads return 0, writes are discarded
+ PRESERVE false
+ CALLER false
+ ARG false
+ INDEX 0
+END
+
+REGISTER x1
+ ABBR ra
+ DESC Return address link register
+ PRESERVE false
+ CALLER false
+ ARG false
+ INDEX 1
+END
+
+REGISTER x2
+ ABBR sp
+ DESC Stack pointer
+ PRESERVE true
+ CALLER false
+ ARG false
+ INDEX 2
+END
+
+REGISTER x3
+ ABBR gp
+ DESC Global pointer
+ PRESERVE true
+ CALLER false
+ ARG false
+ INDEX 3
+END
+
+REGISTER x4
+ ABBR tp
+ DESC Thread pointer
+ PRESERVE true
+ CALLER false
+ ARG false
+ INDEX 4
+END
+
+REGISTER x5
+ ABBR t0
+ DESC Temporary register 0
+ PRESERVE false
+ CALLER true
+ ARG false
+ INDEX 5
+END
+
+REGISTER x6
+ ABBR t1
+ DESC Temporary register 1
+ PRESERVE false
+ CALLER true
+ ARG false
+ INDEX 6
+END
+
+REGISTER x7
+ ABBR t2
+ DESC Temporary register 2
+ PRESERVE false
+ CALLER true
+ ARG false
+ INDEX 7
+END
+
+REGISTER x8
+ ABBR s0
+ DESC Saved register 0 / frame pointer
+ PRESERVE true
+ CALLER false
+ ARG false
+ INDEX 8
+END
+
+REGISTER x9
+ ABBR s1
+ DESC Saved register 1
+ PRESERVE true
+ CALLER false
+ ARG false
+ INDEX 9
+END
+
+REGISTER x10
+ ABBR a0
+ DESC Function argument 0 / return value 0
+ PRESERVE false
+ CALLER true
+ ARG true
+ INDEX 10
+END
+
+REGISTER x11
+ ABBR a1
+ DESC Function argument 1 / return value 1
+ PRESERVE false
+ CALLER true
+ ARG true
+ INDEX 11
+END
+
+REGISTER x12
+ ABBR a2
+ DESC Function argument 2
+ PRESERVE false
+ CALLER true
+ ARG true
+ INDEX 12
+END
+
+REGISTER x13
+ ABBR a3
+ DESC Function argument 3
+ PRESERVE false
+ CALLER true
+ ARG true
+ INDEX 13
+END
+
+REGISTER x14
+ ABBR a4
+ DESC Function argument 4
+ PRESERVE false
+ CALLER true
+ ARG true
+ INDEX 14
+END
+
+REGISTER x15
+ ABBR a5
+ DESC Function argument 5
+ PRESERVE false
+ CALLER true
+ ARG true
+ INDEX 15
+END
+
+REGISTER x16
+ ABBR a6
+ DESC Function argument 6
+ PRESERVE false
+ CALLER true
+ ARG true
+ INDEX 16
+END
+
+REGISTER x17
+ ABBR a7
+ DESC Function argument 7
+ PRESERVE false
+ CALLER true
+ ARG true
+ INDEX 17
+END
+
+REGISTER x18
+ ABBR s2
+ DESC Saved register 2
+ PRESERVE true
+ CALLER false
+ ARG false
+ INDEX 18
+END
+
+REGISTER x19
+ ABBR s3
+ DESC Saved register 3
+ PRESERVE true
+ CALLER false
+ ARG false
+ INDEX 19
+END
+
+REGISTER x20
+ ABBR s4
+ DESC Saved register 4
+ PRESERVE true
+ CALLER false
+ ARG false
+ INDEX 20
+END
+
+REGISTER x21
+ ABBR s5
+ DESC Saved register 5
+ PRESERVE true
+ CALLER false
+ ARG false
+ INDEX 21
+END
+
+REGISTER x22
+ ABBR s6
+ DESC Saved register 6
+ PRESERVE true
+ CALLER false
+ ARG false
+ INDEX 22
+END
+
+REGISTER x23
+ ABBR s7
+ DESC Saved register 7
+ PRESERVE true
+ CALLER false
+ ARG false
+ INDEX 23
+END
+
+REGISTER x24
+ ABBR s8
+ DESC Saved register 8
+ PRESERVE true
+ CALLER false
+ ARG false
+ INDEX 24
+END
+
+REGISTER x25
+ ABBR s9
+ DESC Saved register 9
+ PRESERVE true
+ CALLER false
+ ARG false
+ INDEX 25
+END
+
+REGISTER x26
+ ABBR s10
+ DESC Saved register 10
+ PRESERVE true
+ CALLER false
+ ARG false
+ INDEX 26
+END
+
+REGISTER x27
+ ABBR s11
+ DESC Saved register 11
+ PRESERVE true
+ CALLER false
+ ARG false
+ INDEX 27
+END
+
+REGISTER x28
+ ABBR t3
+ DESC Temporary register 3
+ PRESERVE false
+ CALLER true
+ ARG false
+ INDEX 28
+END
+
+REGISTER x29
+ ABBR t4
+ DESC Temporary register 4
+ PRESERVE false
+ CALLER true
+ ARG false
+ INDEX 29
+END
+
+REGISTER x30
+ ABBR t5
+ DESC Temporary register 5
+ PRESERVE false
+ CALLER true
+ ARG false
+ INDEX 30
+END
+
+REGISTER x31
+ ABBR t6
+ DESC Temporary register 6
+ PRESERVE false
+ CALLER true
+ ARG false
+ INDEX 31
+END
diff --git a/gen/docs/main.c b/gen/docs/main.c
new file mode 100644
index 0000000..760253e
--- /dev/null
+++ b/gen/docs/main.c
@@ -0,0 +1,83 @@
+#include "parser.h"
+#include "generator.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+static void print_usage(const char *prog) {
+ fprintf(stderr, "Usage: %s [options] <isa_defs_dir>\n\n", prog);
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -o <file> Output Markdown file (default: doc/spec/isa_reference.md)\n");
+ fprintf(stderr, " --html Also generate HTML output\n");
+ fprintf(stderr, " --help Show this help\n\n");
+ fprintf(stderr, "Generates professional ISA reference documentation from .isa definition files.\n");
+}
+
+int main(int argc, char **argv) {
+ const char *defs_dir = NULL;
+ const char *output = "doc/spec/isa_reference.md";
+ int gen_html_flag = 0;
+
+ for (int i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "--help") == 0) {
+ print_usage(argv[0]);
+ return 0;
+ } else if (strcmp(argv[i], "-o") == 0 && i + 1 < argc) {
+ output = argv[++i];
+ } else if (strcmp(argv[i], "--html") == 0) {
+ gen_html_flag = 1;
+ } else if (argv[i][0] != '-') {
+ defs_dir = argv[i];
+ } else {
+ fprintf(stderr, "Unknown option: %s\n", argv[i]);
+ print_usage(argv[0]);
+ return 1;
+ }
+ }
+
+ if (!defs_dir) {
+ fprintf(stderr, "Error: no ISA definitions directory specified.\n\n");
+ print_usage(argv[0]);
+ return 1;
+ }
+
+ IsaDb db;
+ memset(&db, 0, sizeof(db));
+
+ printf("ISA Documentation Generator\n");
+ printf("Reading definitions from: %s\n", defs_dir);
+
+ if (isa_parse_dir(defs_dir, &db) != 0) {
+ fprintf(stderr, "Error: failed to parse ISA definitions.\n");
+ return 1;
+ }
+
+ printf("\nParsed:\n");
+ printf(" %d format(s)\n", db.num_formats);
+ printf(" %d register(s)\n", db.num_registers);
+ printf(" %d instruction(s)\n", db.num_instructions);
+ printf(" %d CSR(s)\n", db.num_csrs);
+
+ if (db.num_instructions == 0) {
+ fprintf(stderr, "Warning: no instructions loaded. Output will be sparse.\n");
+ }
+
+ if (gen_markdown(&db, output) != 0) {
+ fprintf(stderr, "Error: failed to generate Markdown.\n");
+ return 1;
+ }
+
+ if (gen_html_flag) {
+ char html_path[1024];
+ snprintf(html_path, sizeof(html_path), "%s.html", output);
+ const char *ext = strrchr(output, '.');
+ if (ext) {
+ size_t len = ext - output;
+ snprintf(html_path, sizeof(html_path), "%.*s.html", (int)len, output);
+ }
+ gen_html(&db, html_path);
+ }
+
+ printf("\nDone. Output: %s\n", output);
+ return 0;
+}
diff --git a/gen/docs/parser.c b/gen/docs/parser.c
new file mode 100644
index 0000000..2852070
--- /dev/null
+++ b/gen/docs/parser.c
@@ -0,0 +1,256 @@
+#include "parser.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <dirent.h>
+
+static void str_trim(char *s) {
+ char *e;
+ while (isspace((unsigned char)*s)) s++;
+ if (*s == 0) return;
+ e = s + strlen(s) - 1;
+ while (e > s && isspace((unsigned char)*e)) e--;
+ *(e + 1) = '\0';
+}
+
+static int str_split(const char *line, char **key, char **val) {
+ static char buf[MAX_LINE];
+ strncpy(buf, line, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
+ char *eq = strchr(buf, ' ');
+ if (!eq) { *key = buf; *val = ""; return 0; }
+ *eq = '\0';
+ *key = buf;
+ *val = eq + 1;
+ str_trim(*key);
+ str_trim(*val);
+ return 1;
+}
+
+static int str_to_int(const char *s) {
+ if (strncmp(s, "0x", 2) == 0 || strncmp(s, "0X", 2) == 0)
+ return (int)strtol(s, NULL, 16);
+ return atoi(s);
+}
+
+static int str_to_bool(const char *s) {
+ return strcmp(s, "true") == 0 || strcmp(s, "yes") == 0 || strcmp(s, "1") == 0;
+}
+
+static int parse_block(FILE *f, const char *block_type, const char *block_name, IsaDb *db) {
+ char line[MAX_LINE];
+
+ if (strcasecmp(block_type, "FORMAT") == 0) {
+ if (db->num_formats >= MAX_FMTS) {
+ fprintf(stderr, "Too many formats (max %d)\n", MAX_FMTS);
+ return -1;
+ }
+ IsaFormat *fmt = &db->formats[db->num_formats];
+ strncpy(fmt->name, block_name, MAX_NAME - 1);
+ fmt->width = 32;
+ fmt->num_fields = 0;
+
+ while (fgets(line, sizeof(line), f)) {
+ char *trimmed = line;
+ while (isspace((unsigned char)*trimmed)) trimmed++;
+ if (*trimmed == '#' || *trimmed == '\n') continue;
+ if (strncmp(trimmed, "END", 3) == 0) break;
+
+ char *key, *val;
+ str_split(trimmed, &key, &val);
+
+ if (strcasecmp(key, "WIDTH") == 0) {
+ fmt->width = str_to_int(val);
+ } else if (strcasecmp(key, "FIELD") == 0) {
+ if (fmt->num_fields >= MAX_FIELDS) {
+ fprintf(stderr, "Too many fields in format %s\n", fmt->name);
+ continue;
+ }
+ char fname[64];
+ int high, low;
+ if (sscanf(val, "%63s %d:%d", fname, &high, &low) >= 3) {
+ strncpy(fmt->fields[fmt->num_fields].name, fname, MAX_LABEL - 1);
+ fmt->fields[fmt->num_fields].high = high;
+ fmt->fields[fmt->num_fields].low = low;
+ fmt->num_fields++;
+ }
+ }
+ }
+ db->num_formats++;
+ } else if (strcasecmp(block_type, "REGISTER") == 0) {
+ if (db->num_registers >= MAX_REGS) {
+ fprintf(stderr, "Too many registers (max %d)\n", MAX_REGS);
+ return -1;
+ }
+ IsaRegister *reg = &db->registers[db->num_registers];
+ memset(reg, 0, sizeof(*reg));
+ strncpy(reg->name, block_name, MAX_NAME - 1);
+ reg->preserve = -1;
+
+ while (fgets(line, sizeof(line), f)) {
+ char *trimmed = line;
+ while (isspace((unsigned char)*trimmed)) trimmed++;
+ if (*trimmed == '#' || *trimmed == '\n') continue;
+ if (strncmp(trimmed, "END", 3) == 0) break;
+
+ char *key, *val;
+ str_split(trimmed, &key, &val);
+
+ if (strcasecmp(key, "ABBR") == 0)
+ strncpy(reg->abbr, val, MAX_LABEL - 1);
+ else if (strcasecmp(key, "DESC") == 0)
+ strncpy(reg->desc, val, MAX_DESC - 1);
+ else if (strcasecmp(key, "PRESERVE") == 0)
+ reg->preserve = str_to_bool(val);
+ else if (strcasecmp(key, "CALLER") == 0)
+ reg->caller_saved = str_to_bool(val);
+ else if (strcasecmp(key, "ARG") == 0)
+ reg->arg_reg = str_to_bool(val);
+ else if (strcasecmp(key, "INDEX") == 0)
+ reg->index = str_to_int(val);
+ }
+ if (reg->preserve == -1) reg->preserve = 0;
+ db->num_registers++;
+ } else if (strcasecmp(block_type, "INSTRUCTION") == 0) {
+ if (db->num_instructions >= MAX_INSTS) {
+ fprintf(stderr, "Too many instructions (max %d)\n", MAX_INSTS);
+ return -1;
+ }
+ IsaInstruction *inst = &db->instructions[db->num_instructions];
+ memset(inst, 0, sizeof(*inst));
+ strncpy(inst->name, block_name, MAX_NAME - 1);
+ inst->funct3_valid = 0;
+ inst->funct7_valid = 0;
+
+ while (fgets(line, sizeof(line), f)) {
+ char *trimmed = line;
+ while (isspace((unsigned char)*trimmed)) trimmed++;
+ if (*trimmed == '#' || *trimmed == '\n') continue;
+ if (strncmp(trimmed, "END", 3) == 0) break;
+
+ char *key, *val;
+ str_split(trimmed, &key, &val);
+
+ if (strcasecmp(key, "FORMAT") == 0)
+ strncpy(inst->fmt_name, val, MAX_NAME - 1);
+ else if (strcasecmp(key, "OPCODE") == 0)
+ inst->opcode = (uint32_t)str_to_int(val);
+ else if (strcasecmp(key, "FUNCT3") == 0) {
+ inst->funct3 = (uint32_t)str_to_int(val);
+ inst->funct3_valid = 1;
+ } else if (strcasecmp(key, "FUNCT7") == 0) {
+ inst->funct7 = (uint32_t)str_to_int(val);
+ inst->funct7_valid = 1;
+ } else if (strcasecmp(key, "OPERANDS") == 0)
+ strncpy(inst->operands, val, MAX_OPERANDS - 1);
+ else if (strcasecmp(key, "DESC") == 0)
+ strncpy(inst->desc, val, MAX_DESC - 1);
+ else if (strcasecmp(key, "NOTE") == 0)
+ strncpy(inst->note, val, MAX_NOTE - 1);
+ else if (strcasecmp(key, "CATEGORY") == 0)
+ strncpy(inst->category, val, MAX_LABEL - 1);
+ else if (strcasecmp(key, "IMM") == 0)
+ inst->has_imm = str_to_bool(val);
+ }
+ db->num_instructions++;
+ } else if (strcasecmp(block_type, "CSR") == 0) {
+ if (db->num_csrs >= MAX_CSRS) {
+ fprintf(stderr, "Too many CSRs (max %d)\n", MAX_CSRS);
+ return -1;
+ }
+ IsaCsr *csr = &db->csrs[db->num_csrs];
+ memset(csr, 0, sizeof(*csr));
+ strncpy(csr->name, block_name, MAX_NAME - 1);
+
+ while (fgets(line, sizeof(line), f)) {
+ char *trimmed = line;
+ while (isspace((unsigned char)*trimmed)) trimmed++;
+ if (*trimmed == '#' || *trimmed == '\n') continue;
+ if (strncmp(trimmed, "END", 3) == 0) break;
+
+ char *key, *val;
+ str_split(trimmed, &key, &val);
+
+ if (strcasecmp(key, "NUMBER") == 0)
+ csr->number = str_to_int(val);
+ else if (strcasecmp(key, "DESC") == 0)
+ strncpy(csr->desc, val, MAX_DESC - 1);
+ }
+ db->num_csrs++;
+ } else if (strcasecmp(block_type, "ARCH") == 0) {
+ while (fgets(line, sizeof(line), f)) {
+ char *trimmed = line;
+ while (isspace((unsigned char)*trimmed)) trimmed++;
+ if (*trimmed == '#' || *trimmed == '\n') continue;
+ if (strncmp(trimmed, "END", 3) == 0) break;
+
+ char *key, *val;
+ str_split(trimmed, &key, &val);
+
+ if (strcasecmp(key, "NAME") == 0)
+ strncpy(db->arch_name, val, MAX_NAME - 1);
+ else if (strcasecmp(key, "VERSION") == 0)
+ strncpy(db->arch_version, val, MAX_LABEL - 1);
+ else if (strcasecmp(key, "DATE") == 0)
+ strncpy(db->arch_date, val, MAX_LABEL - 1);
+ else if (strcasecmp(key, "STATUS") == 0)
+ strncpy(db->arch_status, val, MAX_LABEL - 1);
+ }
+ }
+
+ return 0;
+}
+
+int isa_parse_file(const char *path, IsaDb *db) {
+ FILE *f = fopen(path, "r");
+ if (!f) {
+ fprintf(stderr, "Error: cannot open %s\n", path);
+ return -1;
+ }
+
+ char line[MAX_LINE];
+ int line_num = 0;
+
+ while (fgets(line, sizeof(line), f)) {
+ line_num++;
+ char *trimmed = line;
+ while (isspace((unsigned char)*trimmed)) trimmed++;
+ if (*trimmed == '#' || *trimmed == '\n' || *trimmed == '\r') continue;
+
+ char type[MAX_LABEL], name[MAX_NAME];
+ if (sscanf(trimmed, "%31s %63s", type, name) >= 2) {
+ if (parse_block(f, type, name, db) != 0) {
+ fprintf(stderr, "Error parsing %s in %s line %d\n", type, path, line_num);
+ fclose(f);
+ return -1;
+ }
+ }
+ }
+
+ fclose(f);
+ return 0;
+}
+
+int isa_parse_dir(const char *dir, IsaDb *db) {
+ DIR *d = opendir(dir);
+ if (!d) {
+ fprintf(stderr, "Error: cannot open directory %s\n", dir);
+ return -1;
+ }
+
+ struct dirent *entry;
+ while ((entry = readdir(d)) != NULL) {
+ if (entry->d_type != DT_REG) continue;
+ const char *ext = strrchr(entry->d_name, '.');
+ if (!ext || strcasecmp(ext, ".isa") != 0) continue;
+
+ char path[MAX_PATH];
+ snprintf(path, sizeof(path), "%s/%s", dir, entry->d_name);
+ printf(" Parsing: %s\n", path);
+ isa_parse_file(path, db);
+ }
+
+ closedir(d);
+ return 0;
+}
diff --git a/gen/docs/parser.h b/gen/docs/parser.h
new file mode 100644
index 0000000..53a27fc
--- /dev/null
+++ b/gen/docs/parser.h
@@ -0,0 +1,9 @@
+#ifndef PARSER_H
+#define PARSER_H
+
+#include "types.h"
+
+int isa_parse_file(const char *path, IsaDb *db);
+int isa_parse_dir(const char *dir, IsaDb *db);
+
+#endif
diff --git a/gen/docs/style.css b/gen/docs/style.css
new file mode 100644
index 0000000..305b00b
--- /dev/null
+++ b/gen/docs/style.css
@@ -0,0 +1,139 @@
+/* style.css — Professional styling for ISA reference HTML (used by wkhtmltopdf) */
+
+body {
+ font-family: "Times New Roman", Times, serif;
+ font-size: 11pt;
+ line-height: 1.5;
+ color: #1a1a1a;
+ max-width: 7in;
+ margin: 0 auto;
+ padding: 1in 0.5in;
+}
+
+h1 {
+ font-size: 24pt;
+ text-align: center;
+ margin-top: 2in;
+ margin-bottom: 0.3in;
+ page-break-before: always;
+}
+
+h1:first-of-type {
+ margin-top: 3in;
+ page-break-before: avoid;
+}
+
+.subtitle {
+ text-align: center;
+ font-size: 16pt;
+ color: #555;
+ margin-bottom: 0.5in;
+}
+
+h2 {
+ font-size: 16pt;
+ border-bottom: 2px solid #333;
+ padding-bottom: 4pt;
+ margin-top: 0.5in;
+}
+
+h3 {
+ font-size: 13pt;
+ margin-top: 0.3in;
+}
+
+h4 {
+ font-size: 11pt;
+ font-style: italic;
+ margin-top: 0.2in;
+}
+
+table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 0.2in 0;
+ font-size: 9.5pt;
+}
+
+th, td {
+ border: 1px solid #999;
+ padding: 4pt 6pt;
+ text-align: left;
+ vertical-align: top;
+}
+
+th {
+ background-color: #e8e8e8;
+ font-weight: bold;
+}
+
+tr:nth-child(even) {
+ background-color: #f6f6f6;
+}
+
+code {
+ font-family: "Courier New", Courier, monospace;
+ font-size: 9.5pt;
+ background-color: #f0f0f0;
+ padding: 1pt 3pt;
+ border-radius: 2pt;
+}
+
+pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: 9pt;
+ background-color: #f8f8f8;
+ border: 1px solid #ddd;
+ padding: 8pt;
+ overflow-x: auto;
+ line-height: 1.3;
+}
+
+pre code {
+ background: none;
+ padding: 0;
+}
+
+/* Page breaks */
+section, .chapter {
+ page-break-before: always;
+}
+
+/* Tables of contents */
+#TOC {
+ page-break-after: always;
+}
+
+#TOC ul {
+ list-style: none;
+ padding-left: 0;
+}
+
+#TOC li {
+ margin: 4pt 0;
+}
+
+/* Header and footer */
+@page {
+ @top-center {
+ content: element(header);
+ font-size: 9pt;
+ color: #888;
+ }
+ @bottom-center {
+ content: counter(page);
+ font-size: 9pt;
+ }
+}
+
+@media print {
+ body {
+ padding: 0;
+ }
+ table {
+ page-break-inside: avoid;
+ }
+ h2, h3 {
+ page-break-after: avoid;
+ }
+}
diff --git a/gen/docs/types.h b/gen/docs/types.h
new file mode 100644
index 0000000..14fb4e0
--- /dev/null
+++ b/gen/docs/types.h
@@ -0,0 +1,78 @@
+#ifndef TYPES_H
+#define TYPES_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#define MAX_NAME 64
+#define MAX_LABEL 32
+#define MAX_DESC 512
+#define MAX_NOTE 512
+#define MAX_OPERANDS 128
+#define MAX_FIELDS 8
+#define MAX_INSTS 256
+#define MAX_REGS 64
+#define MAX_FMTS 16
+#define MAX_CSRS 128
+#define MAX_LINE 1024
+#define MAX_TOKENS 16
+#define MAX_PATH 256
+
+typedef struct {
+ char name[MAX_NAME];
+ int width;
+ int num_fields;
+ struct {
+ char name[MAX_LABEL];
+ int high;
+ int low;
+ } fields[MAX_FIELDS];
+} IsaFormat;
+
+typedef struct {
+ char name[MAX_NAME];
+ char abbr[MAX_LABEL];
+ char desc[MAX_DESC];
+ int preserve;
+ int caller_saved;
+ int arg_reg;
+ int index;
+} IsaRegister;
+
+typedef struct {
+ char name[MAX_NAME];
+ char fmt_name[MAX_NAME];
+ uint32_t opcode;
+ uint32_t funct3;
+ uint32_t funct7;
+ uint32_t funct3_valid;
+ uint32_t funct7_valid;
+ char operands[MAX_OPERANDS];
+ char desc[MAX_DESC];
+ char note[MAX_NOTE];
+ char category[MAX_LABEL];
+ int has_imm;
+} IsaInstruction;
+
+typedef struct {
+ char name[MAX_NAME];
+ int number;
+ char desc[MAX_DESC];
+} IsaCsr;
+
+typedef struct {
+ IsaFormat formats[MAX_FMTS];
+ int num_formats;
+ IsaRegister registers[MAX_REGS];
+ int num_registers;
+ IsaInstruction instructions[MAX_INSTS];
+ int num_instructions;
+ IsaCsr csrs[MAX_CSRS];
+ int num_csrs;
+ char arch_name[MAX_NAME];
+ char arch_version[MAX_LABEL];
+ char arch_date[MAX_LABEL];
+ char arch_status[MAX_LABEL];
+} IsaDb;
+
+#endif
diff --git a/gen/encoder/main.c b/gen/encoder/main.c
new file mode 100644
index 0000000..ac3fed5
--- /dev/null
+++ b/gen/encoder/main.c
@@ -0,0 +1,3 @@
+// encoder — Generate assembler encoder source
+// Reads: opcode definitions from ../isa/opcodes/
+// Writes: encode.c / encode.h mapping mnemonics→instruction words
diff --git a/gen/opcodes/main.c b/gen/opcodes/main.c
new file mode 100644
index 0000000..f9819fd
--- /dev/null
+++ b/gen/opcodes/main.c
@@ -0,0 +1,3 @@
+// opcodes — Generate opcode header files
+// Reads: ../isa/opcodes/*.yaml
+// Writes: opcodes.h (enum, bitfield structs, encode/decode macros)
diff --git a/gen/tablegen/main.c b/gen/tablegen/main.c
new file mode 100644
index 0000000..ef91ae2
--- /dev/null
+++ b/gen/tablegen/main.c
@@ -0,0 +1,3 @@
+// tablegen — Generate instruction decode tables from ISA encoding definitions
+// Reads: ../isa/encoding/*.yaml
+// Writes: decoder tables (switch/case, bit-mask dispatch)
diff --git a/isa/README.md b/isa/README.md
new file mode 100644
index 0000000..bf855eb
--- /dev/null
+++ b/isa/README.md
@@ -0,0 +1,12 @@
+# ISA Definition
+
+Formal, machine-readable specification of the instruction set.
+
+## Structure
+
+- `encoding/` — Instruction encoding bitfield definitions (JSON/YAML tables)
+- `opcodes/` — Opcode mnemonics, values, operand types
+- `extensions/` — Optional ISA extensions (e.g. float, vector, crypto)
+- `privileged/` — Privileged architecture: CSRs, traps, memory management
+
+This directory is the **source of truth** consumed by the generators in `gen/`.
diff --git a/isa/encoding/base.yaml b/isa/encoding/base.yaml
new file mode 100644
index 0000000..0b4654a
--- /dev/null
+++ b/isa/encoding/base.yaml
@@ -0,0 +1,3 @@
+# Base instruction encoding format
+# Instruction width: 32-bit fixed / 16+32 variable
+# Format fields: opcode, rd, funct3, rs1, rs2, funct7, imm
diff --git a/isa/opcodes/base.yaml b/isa/opcodes/base.yaml
new file mode 100644
index 0000000..289bc46
--- /dev/null
+++ b/isa/opcodes/base.yaml
@@ -0,0 +1,8 @@
+# Base instruction opcode definitions
+# Format: mnemonic, encoding, operands, type, description
+# e.g.:
+# - mnemonic: ADD
+# encoding: 0b0000000_?????_?????_000_?????_0110011
+# operands: [rd, rs1, rs2]
+# type: R
+# description: Add registers
diff --git a/runtime/README.md b/runtime/README.md
new file mode 100644
index 0000000..8dad172
--- /dev/null
+++ b/runtime/README.md
@@ -0,0 +1,6 @@
+# Runtime Support
+
+- `crt0.S` — C runtime startup (reset handler, .bss clear, call main)
+- `crti.S` — C runtime init (constructor init)
+- `crtn.S` — C runtime fini (constructor fini)
+- `linker.ld` — Default linker script
diff --git a/sim/README.md b/sim/README.md
new file mode 100644
index 0000000..45fc547
--- /dev/null
+++ b/sim/README.md
@@ -0,0 +1,8 @@
+# Instruction-Set Simulator
+
+Functional (and optionally cycle-approximate) simulator for Fyntv.
+
+- Reads ELF binaries
+- Executes instructions via decode-dispatch loop
+- Provides GDB remote debugging stub
+- Tracks instruction counts, cycle estimates
diff --git a/tests/README.md b/tests/README.md
new file mode 100644
index 0000000..5046211
--- /dev/null
+++ b/tests/README.md
@@ -0,0 +1,8 @@
+# Test Suites
+
+| Directory | Contents |
+|------------------|-------------------------------------------|
+| `asm/` | Instruction-level assembly tests |
+| `sim/` | Simulator compliance tests |
+| `regression/` | Regression test suite (one test per bug) |
+| `benchmarks/` | Performance benchmarks (Dhrystone, etc.) |
diff --git a/tools/README.md b/tools/README.md
new file mode 100644
index 0000000..a3aae90
--- /dev/null
+++ b/tools/README.md
@@ -0,0 +1,17 @@
+# Toolchain (binutils-style)
+
+Standard GNU binutils ports for Fyntv:
+
+| Tool | Purpose |
+|-------------|--------------------------------------|
+| `gas/` | Assembler |
+| `ld/` | Linker |
+| `objdump/` | Disassembler + object dump |
+| `objcopy/` | Section copying / stripping |
+| `readelf/` | ELF file reader |
+| `nm/` | Symbol listing |
+| `ar/` | Static library archiver |
+| `size/` | Section/symbol size listing |
+| `strings/` | Printable string extraction |
+| `addr2line/`| Virtual address → source line |
+| `cxxfilt/` | C++ ABI name demangling |