From 887875959aa84af92291db334898aaa20956e632 Mon Sep 17 00:00:00 2001 From: allexanderbergmans Date: Fri, 3 Jul 2026 12:17:10 +0200 Subject: init --- .DS_Store | Bin 0 -> 8196 bytes .gitignore | 30 + README.md | 43 ++ configure.ac | 2 + doc/.DS_Store | Bin 0 -> 6148 bytes doc/README.md | 12 + doc/spec/isa_reference.html | 106 ++++ doc/spec/isa_reference.md | 899 ++++++++++++++++++++++++++++ doc/spec/isa_reference.pdf | Bin 0 -> 90197 bytes editors/vscode/README.md | 34 ++ editors/vscode/isa-syntax-1.0.0.vsix | Bin 0 -> 3414 bytes editors/vscode/language-configuration.json | 8 + editors/vscode/package.json | 27 + editors/vscode/syntaxes/isa.tmLanguage.json | 70 +++ examples/README.md | 7 + gen/README.md | 14 + gen/decoder/main.c | 3 + gen/disassembler/main.c | 3 + gen/docs/convert.sh | 55 ++ gen/docs/generator.c | 481 +++++++++++++++ gen/docs/generator.h | 9 + gen/docs/isa-docgen | Bin 0 -> 51736 bytes gen/docs/isa_defs/arch.isa | 68 +++ gen/docs/isa_defs/csrs.isa | 191 ++++++ gen/docs/isa_defs/instructions.isa | 512 ++++++++++++++++ gen/docs/isa_defs/registers.isa | 289 +++++++++ gen/docs/main.c | 83 +++ gen/docs/parser.c | 256 ++++++++ gen/docs/parser.h | 9 + gen/docs/style.css | 139 +++++ gen/docs/types.h | 78 +++ gen/encoder/main.c | 3 + gen/opcodes/main.c | 3 + gen/tablegen/main.c | 3 + isa/README.md | 12 + isa/encoding/base.yaml | 3 + isa/opcodes/base.yaml | 8 + runtime/README.md | 6 + sim/README.md | 8 + tests/README.md | 8 + tools/README.md | 17 + 41 files changed, 3499 insertions(+) create mode 100644 .DS_Store create mode 100644 .gitignore create mode 100644 README.md create mode 100644 configure.ac create mode 100644 doc/.DS_Store create mode 100644 doc/README.md create mode 100644 doc/spec/isa_reference.html create mode 100644 doc/spec/isa_reference.md create mode 100644 doc/spec/isa_reference.pdf create mode 100644 editors/vscode/README.md create mode 100644 editors/vscode/isa-syntax-1.0.0.vsix create mode 100644 editors/vscode/language-configuration.json create mode 100644 editors/vscode/package.json create mode 100644 editors/vscode/syntaxes/isa.tmLanguage.json create mode 100644 examples/README.md create mode 100644 gen/README.md create mode 100644 gen/decoder/main.c create mode 100644 gen/disassembler/main.c create mode 100644 gen/docs/convert.sh create mode 100644 gen/docs/generator.c create mode 100644 gen/docs/generator.h create mode 100755 gen/docs/isa-docgen create mode 100644 gen/docs/isa_defs/arch.isa create mode 100644 gen/docs/isa_defs/csrs.isa create mode 100644 gen/docs/isa_defs/instructions.isa create mode 100644 gen/docs/isa_defs/registers.isa create mode 100644 gen/docs/main.c create mode 100644 gen/docs/parser.c create mode 100644 gen/docs/parser.h create mode 100644 gen/docs/style.css create mode 100644 gen/docs/types.h create mode 100644 gen/encoder/main.c create mode 100644 gen/opcodes/main.c create mode 100644 gen/tablegen/main.c create mode 100644 isa/README.md create mode 100644 isa/encoding/base.yaml create mode 100644 isa/opcodes/base.yaml create mode 100644 runtime/README.md create mode 100644 sim/README.md create mode 100644 tests/README.md create mode 100644 tools/README.md diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..ed9e52b Binary files /dev/null and b/.DS_Store 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 Binary files /dev/null and b/doc/.DS_Store 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 @@ + + + + +Fyntv ISA Reference Manual + + + +
+
+

Fyntv Instruction Set Architecture

+

Reference Manual

+

Version: 0.0.0.1  |  Date: June 2026

+
+
+

Registers

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RegisterABI NameDescriptionSaved
x0zeroAlways-zero register — reads return 0, writes are discardedNo
x1raReturn address link registerNo
x2spStack pointerYes
x3gpGlobal pointerYes
x4tpThread pointerYes
x5t0Temporary register 0No
x6t1Temporary register 1No
x7t2Temporary register 2No
x8s0Saved register 0 / frame pointerYes
x9s1Saved register 1Yes
x10a0Function argument 0 / return value 0No
x11a1Function argument 1 / return value 1No
x12a2Function argument 2No
x13a3Function argument 3No
x14a4Function argument 4No
x15a5Function argument 5No
x16a6Function argument 6No
x17a7Function argument 7No
x18s2Saved register 2Yes
x19s3Saved register 3Yes
x20s4Saved register 4Yes
x21s5Saved register 5Yes
x22s6Saved register 6Yes
x23s7Saved register 7Yes
x24s8Saved register 8Yes
x25s9Saved register 9Yes
x26s10Saved register 10Yes
x27s11Saved register 11Yes
x28t3Temporary register 3No
x29t4Temporary register 4No
x30t5Temporary register 5No
x31t6Temporary register 6No
+
+
+

Instruction Set

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MnemonicFormatOpcodeOperandsDescription
ADDR0x33rd, rs1, rs2Add registers
SUBR0x33rd, rs1, rs2Subtract registers
ADDII0x13rd, rs1, imm12Add sign-extended 12-bit immediate to register rs1
SLTR0x33rd, rs1, rs2Set if rs1 is less than rs2 (signed)
SLTUR0x33rd, rs1, rs2Set if rs1 is less than rs2 (unsigned)
SLTII0x13rd, rs1, imm12Set if rs1 is less than immediate (signed)
SLTIUI0x13rd, rs1, imm12Set if rs1 is less than immediate (unsigned)
LUIU0x37rd, imm20Load upper immediate — places 20-bit immediate in upper 20 bits of rd
AUIPCU0x17rd, imm20Add upper immediate to PC — forms PC-relative address
ANDR0x33rd, rs1, rs2Bitwise AND
ORR0x33rd, rs1, rs2Bitwise OR
XORR0x33rd, rs1, rs2Bitwise XOR
ANDII0x13rd, rs1, imm12Bitwise AND with immediate
ORII0x13rd, rs1, imm12Bitwise OR with immediate
XORII0x13rd, rs1, imm12Bitwise XOR with immediate
SLLR0x33rd, rs1, rs2Logical left shift by lower 5 bits of rs2
SRLR0x33rd, rs1, rs2Logical right shift by lower 5 bits of rs2
SRAR0x33rd, rs1, rs2Arithmetic right shift by lower 5 bits of rs2
SLLII0x13rd, rs1, shamt5Logical left shift by immediate shift amount
SRLII0x13rd, rs1, shamt5Logical right shift by immediate shift amount
SRAII0x13rd, rs1, shamt5Arithmetic right shift by immediate shift amount
LBI0x03rd, offset(rs1)Load byte (sign-extended)
LHI0x03rd, offset(rs1)Load halfword (sign-extended)
LWI0x03rd, offset(rs1)Load word
LBUI0x03rd, offset(rs1)Load byte (zero-extended)
LHUI0x03rd, offset(rs1)Load halfword (zero-extended)
SBS0x23rs2, offset(rs1)Store byte
SHS0x23rs2, offset(rs1)Store halfword
SWS0x23rs2, offset(rs1)Store word
BEQB0x63rs1, rs2, labelBranch equal
BNEB0x63rs1, rs2, labelBranch not equal
BLTB0x63rs1, rs2, labelBranch less than (signed)
BGEB0x63rs1, rs2, labelBranch greater than or equal (signed)
BLTUB0x63rs1, rs2, labelBranch less than (unsigned)
BGEUB0x63rs1, rs2, labelBranch greater than or equal (unsigned)
JALJ0x6Frd, labelJump and link — jump to PC+offset, save return address to rd
JALRI0x67rd, rs1, offsetJump and link register — jump to rs1+offset, save return address
FENCEI0x0Fpred, succMemory ordering fence
FENCEII0x0FInstruction fence — synchronizes instruction and data streams
ECALLI0x73Environment call — raises a system call exception
EBREAKI0x73Breakpoint — raises a breakpoint exception
CSRRWI0x73rd, csr, rs1Atomic read/write CSR — writes rs1 to CSR, returns old value in rd
CSRRSI0x73rd, csr, rs1Atomic read and set bits in CSR
CSRRCI0x73rd, csr, rs1Atomic read and clear bits in CSR
CSRRWII0x73rd, csr, uimm5Atomic read/write CSR with immediate
CSRRSII0x73rd, csr, uimm5Atomic read and set bits in CSR with immediate
CSRRCII0x73rd, csr, uimm5Atomic read and clear bits in CSR with immediate
+
+
+ + 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 Binary files /dev/null and b/doc/spec/isa_reference.pdf 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 Binary files /dev/null and b/editors/vscode/isa-syntax-1.0.0.vsix 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 +#include +#include + +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, "\n\n\n"); + fprintf(out, "\n"); + fprintf(out, "%s ISA Reference Manual\n", + db->arch_name[0] ? db->arch_name : "Fyntv"); + fprintf(out, "\n"); + fprintf(out, "\n\n
\n"); + + fprintf(out, "
\n"); + fprintf(out, "

%s Instruction Set Architecture

\n", + db->arch_name[0] ? db->arch_name : "Fyntv"); + fprintf(out, "

Reference Manual

\n"); + fprintf(out, "

Version: %s  |  Date: %s

\n", + db->arch_version[0] ? db->arch_version : "1.0.0", + db->arch_date[0] ? db->arch_date : "June 2026"); + fprintf(out, "
\n"); + + fprintf(out, "
\n"); + fprintf(out, "

Registers

\n"); + fprintf(out, "\n"); + for (int i = 0; i < db->num_registers; i++) { + fprintf(out, "\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, "
RegisterABI NameDescriptionSaved
%s%s%s%s
\n
\n"); + + fprintf(out, "
\n"); + fprintf(out, "

Instruction Set

\n"); + fprintf(out, "\n"); + for (int i = 0; i < db->num_instructions; i++) { + fprintf(out, "\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, "
MnemonicFormatOpcodeOperandsDescription
%s%s0x%02X%s%s
\n
\n"); + + fprintf(out, "
\n\n\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 Binary files /dev/null and b/gen/docs/isa-docgen 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 +#include +#include + +static void print_usage(const char *prog) { + fprintf(stderr, "Usage: %s [options] \n\n", prog); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -o 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 +#include +#include +#include +#include + +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 +#include + +#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 | -- cgit v1.3