From 631f09462050c8173dacb22a83e6ef3dacc3c8a1 Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 6 Jul 2021 12:26:46 +0200 Subject: update README/ex example --- ISA_notes.md | 127 ++++++++++++++++++++++++++++++++++++++++++++ README.md | 158 ------------------------------------------------------- README.rst | 142 +++++++++++++++++++++++++++++++++++++++++++++++++ ex.elf | Bin 8228 -> 8224 bytes ex.format | 13 ++--- ex.pack | 11 +--- ex.subv | 11 +--- ex.survey | 25 ++++----- ex.valid | 16 ++++++ hello_world.subv | 43 +++++++++++++++ notes.md | 128 -------------------------------------------- subv.sh | 39 ++++++++++++++ test.subv | 43 --------------- 13 files changed, 383 insertions(+), 373 deletions(-) create mode 100644 ISA_notes.md delete mode 100644 README.md create mode 100644 README.rst create mode 100644 ex.valid create mode 100644 hello_world.subv delete mode 100644 notes.md create mode 100755 subv.sh delete mode 100644 test.subv diff --git a/ISA_notes.md b/ISA_notes.md new file mode 100644 index 0000000..8f56686 --- /dev/null +++ b/ISA_notes.md @@ -0,0 +1,127 @@ +# RISC-V full size Instructions Formats (32bit): + +## R-format: op(rs1, rs2) -> rd +`opcode[7] rd[5] funct3[3] rs1[5] rs2[5] funct7[7]` + +register arithmetic/logical +opcode: 0b0110011 / 0x33 + +| funct7 | funct3 | operation | +|========|========|===========| +| 0x0 | 0x0 | ADD | +| 0x20 | 0x0 | SUB | +| 0x0 | 0x1 | SLL | +| 0x0 | 0x2 | SLT | +| 0x0 | 0x3 | SLTU | +| 0x0 | 0x4 | XOR | +| 0x0 | 0x5 | SRL | +| 0x20 | 0x5 | SRA | +| 0x0 | 0x6 | OR | +| 0x0 | 0x7 | AND | + +## I-Format: op(rs1, imm12) -> rd +`opcode[7] rd[5] funct3[3] rs1[5] imm[12]` + +load +opcode: 0b0000011 / 0x03 + +- rs1: base address +- imm12: offset (scaled/signed by funct3) + +| funct3 | operation | | +|========|===========|=====| +| 0x0 | LB | i8 | +| 0x1 | LH | i16 | +| 0x2 | LW | i32 | +| 0x4 | LBU | u8 | +| 0x5 | LHU | u16 | + + +immediate arhitmetic/logical +opcode: 0b0010011 / 0x13 + +- rs1: base address +- imm12: offset (scaled/signed by funct3) + +| funct3 | operation | | +|========|===========|==============================| +| 0x0 | ADDI | | +| 0x2 | SLTI | | +| 0x3 | SLTIU | | +| 0x4 | XORI | | +| 0x6 | ORI | | +| 0x7 | ANDI | | +| 0x1 | SLLI | imm12 = 0b0000000 , shamt[5] | +| 0x5 | SRLI | imm12 = 0b0000000 , shamt[5] | +| 0x5 | SRAI | imm12 = 0b0100000 , shamt[5] | + + +jalr +opcode = 0b1100111 / 0x67 + +- rs1: base address +- imm12: offset (bytes) +- save PC+4 in rd +- jump to offset + +## S-format: op(rs1, rs2, imm12) +`opcode[7] imm4:0[5] funct3[3] rs1[5] rs2[5] imm11:5[7]` + +store +opcode: 0b0100011 / 0x23 + +- rs1: base address +- rs2: data +- imm12: offset (scaled/signed by funct3) + +| funct3 | operation | | +|========|===========|==========================| +| 0x0 | SB | i8, imm12 in bytes | +| 0x1 | SH | i16, imm12 in half-words | +| 0x2 | SW | i32, imm13 in words | + +## B-format: op(rs1, rs2, imm12/13) +`opcode[7] imm11[1] imm4:1[4] funct3[3] rs1[5] rs2[5] imm10:5[6] imm12[1]` + +branch +opcode = 0b1100011 / 0x63 + +- rs1, rs2: registers to compare +- imm12/13: PC offset in half-words + +| funct3 | operation | +|========|===========| +| 0x0 | BEQ | +| 0x1 | BNE | +| 0x4 | BLT | +| 0x5 | BGE | +| 0x6 | BLTU | +| 0x7 | BGEU | + +## U-Format: op(imm20/32) -> rd +`opcode[7] rd[5] imm31:12[20]` +upper-bit immediates (lui, auipc) + +lui +opcode: 0b0110111 / 0x37 + +- imm20: top 20 bits of rd +- clears bottom 12 bits +- combine lui + addi to load 32bit immediate + NOTE: sign extension requires some trickery. + +auipc: +opcode: 0b0010111 / 0x17 + +- imm20: top 20 bits of offset added to PC +- result stored in rd + +## J-Format: op(imm20/21) -> rd +`opcode[7] rd[5] imm31:12[20]` +immediates on a 32bit scale (jal) + +jal +opcode = 0b1101111 / 0x6f + +- save PC+4 in rd +- imm20/21: PC offset in half-words diff --git a/README.md b/README.md deleted file mode 100644 index cd47df9..0000000 --- a/README.md +++ /dev/null @@ -1,158 +0,0 @@ -# SubV - -This is a wip clone of [SubX][mu] for the RISC-V RV31I base ISA. - - $ out.elf - $ ./qemu.sh out.elf - -## Status - -Features: - -- ELF output: ✔️ -- Free arg order: ❌ -- SubX cross-asm: ❌ - -Instruction Groups: - -- OP-IMM: ✔️✔️ -- OP: ✔️❌ -- LUI: ✔️✔️ -- AIUPC: ✔️❌ -- JAL: ✔️✔️ -- JALR: ✔️❌ -- BRANCH: ❌❌ -- LOAD: ✔️❌ -- STORE: ✔️✔️ - -(✔️❌: implemented but untested) - -## Pipeline - -back to front: - -- `elf.py`: takes hex bytes and segment headers, outputs an ELF file -- `pack.py`: packs bitfields (`3/3 1/1 f/4`) into hex bytes (`fb`) -- `format.py`: bit-packs ops into ISA format -- `survey.py`: replaces label references by their addresses -- `validate.py`: checks op-arguments and puts them into canonical order - -and now front to back with a little example: - - $ ./validate.py ex.valid - $ ./survey.py ex.survey - $ ./format.py ex.format - $ ./pack.py ex.pack - $ ./elf.py ex.elf - $ ./qemu.sh ex.elf - -`ex.subv`: hand-writable. - - == code 0x80000000 - # repeatedly print "Hi\\n" - main: - # load 0x10010000 (UART0) into t0 - 37/lui 5/rd/t0 0x10010/imm20 - # store 0x48 (H) in UART0+0 - 13/opi 0/subop/add 6/rd/t1 0/rs/x0 48/imm12 - 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12 - # store 0x69 (i) in UART0+0 - 13/opi 0/subop/add 6/rd/t1 0/rs/x0 69/imm12 - 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12 - # store 0x0a (\n) in UART0+0 - 13/opi 0/subop/add 6/rd/t1 0/rs/x0 0a/imm12 - 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12 - # jump back up to the top - 6f/jal 0/rd/x0 main/off21 - -`ex.format`: mnemonics validated and discarded - - == code 0x80000000 - # repeatedly print "Hi\n" - main: - # load 0x10010000 (UART0) into t0 - 37/u 05/rd 10010/imm20 - # store 0x48 (H) in UART0+0 - 13/i 0/subop 6/rd 0/rs 48/imm12 - 23/s 2/subop 5/rs2 6/rs1 0/off12 - # store 0x69 (i) in UART0+0 - 13/i 0/subop 6/rd 0/rs 69/imm12 - 23/s 2/subop 5/rs2 6/rs1 0/off12 - # store 0x0a (\n) in UART0+0 - 13/i 0/subop 6/rd 0/rs 0a/imm12 - 23/s 2/subop 5/rs2 6/rs1 0/off12 - # jump back up to the top - 6f/j 0/4d main/off21 - -`ex.survey`: references resolved and labels removed - - == code 0x80000000 - # repeatedly print "Hi\n" - # main: - # load 0x10010000 (UART0) into t0 - 37/u 05/rd 10010/imm20 - # store 0x48 (H) in UART0+0 - 13/i 0/subop 6/rd 0/rs 48/imm12 - 23/s 2/subop 5/rs2 6/rs1 0/off12 - # store 0x69 (i) in UART0+0 - 13/i 0/subop 6/rd 0/rs 69/imm12 - 23/s 2/subop 5/rs2 6/rs1 0/off12 - # store 0x0a (\n) in UART0+0 - 13/i 0/subop 6/rd 0/rs 0a/imm12 - 23/s 2/subop 5/rs2 6/rs1 0/off12 - # jump back up to the top - 6f/j 0/4d fffe4/off21 - -`ex.format`: arguments sliced and diced and put into the ISA order. - - == code 0x80000000 - # repeatedly print "Hi\n" - # main: - # load 0x10010000 (UART0) into t0 - 37/7 05/5 10010/20 - # store 0x48 (H) in UART0+0 - 13/7 06/5 00/3 00/5 48/12 - 23/7 00/5 02/3 05/5 06/5 00/7 - # store 0x69 (i) in UART0+0 - 13/7 06/5 00/3 00/5 69/12 - 23/7 00/5 02/3 05/5 06/5 00/7 - # store 0x0a (\n) in UART0+0 - 13/7 06/5 00/3 00/5 0a/12 - 23/7 00/5 02/3 05/5 06/5 00/7 - # jump back up to the top - 6f/7 00/5 ff/8 01/1 3f2/10 01/1 - -`ex.pack`: fully packed, ready to run bare-metal - - == code 0x80000000 - # repeatedly print "Hi\n" - # main: - # load 0x10010000 (UART0) into t0 - b7 02 01 10 - # store 0x48 (H) in UART0+0 - 13 03 80 04 - 23 a0 62 00 - # store 0x69 (i) in UART0+0 - 13 03 90 06 - 23 a0 62 00 - # store 0x0a (\n) in UART0+0 - 13 03 a0 00 - 23 a0 62 00 - # jump back up to the top - 6f f0 5f fe - -`ex.elf`: binary file for use with `qemu` (see next section). - -## Debugging - -You can hook gdb into `qemu` using the `-s` flag, and make it halt on start -using the `-S` flag. `gdb` can be attached using `target remote localhost:1234`: - - $ ./qemu.sh out.elf -S -s - # in another terminal - $ riscv32-elf-gdb -iex "target remote localhost:1234" - layout asm # show assembly trace - nexti # step forward one instruction - c # free-run forward - -[mu]: https://github.com/akkartik/mu diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..ed8ddd2 --- /dev/null +++ b/README.rst @@ -0,0 +1,142 @@ +SubV +==== + +This is a wip clone of SubX_ for the RISC-V RV32I base ISA. + +:: + + $ hello_world.elf + $ ./qemu.sh hello_world.elf + +Pipeline +-------- + +back to front: + +- ``elf.py``: takes hex bytes and segment headers, outputs an ELF file +- ``pack.py``: packs bitfields (``3/3 1/1 f/4``) into hex bytes (``fb``) +- ``format.py``: bit-packs ops into ISA format +- ``survey.py``: replaces label references by their addresses +- ``validate.py``: checks op-arguments and puts them into canonical order + +and now front to back with a little example:: + + $ ./validate.py ex.valid + $ ./survey.py ex.survey + $ ./format.py ex.format + $ ./pack.py ex.pack + $ ./elf.py ex.elf + $ ./qemu.sh ex.elf + +``ex.subv``: hand-writable:: + + == code 0x80000000 + # repeatedly print "Hi\n" + main: + # load 0x10010000 (UART0) into t0 + 37/lui 5/rd/t0 0x10010/imm20 + # store 0x48 (H) in UART0+0 + 13/opi 0/subop/add 6/rd/t1 0/rs/x0 48/imm12 + 23/store 2/width/word 5/rs/t0 6/rs/t1 0/off12 + # store 0x69 (i) in UART0+0 + 13/opi 0/subop/add 6/rd/t1 0/rs/x0 69/imm12 + 23/store 2/width/word 5/rs/t0 6/rs/t1 0/off12 + # store 0x0a (\n) in UART0+0 + 13/opi 0/subop/add 6/rd/t1 0/rs/x0 0a/imm12 + 23/store 2/width/word 5/rs/t0 6/rs/t1 0/off12 + # jump back up to the top + 6f/jal 0/rd/x0 main/off21 + +``ex.valid``: mnemonics validated and discarded:: + + == code 0x80000000 + # repeatedly print "Hi\n" + main: + # load 0x10010000 (UART0) into t0 + 37/u 5/rd 10010/imm20 + # store 0x48 (H) in UART0+0 + 13/i 6/rd 0/funct3 0/rs 48/imm12 + 23/s 5/rs1 0/imm12 2/funct3 6/rs2 + # store 0x69 (i) in UART0+0 + 13/i 6/rd 0/funct3 0/rs 69/imm12 + 23/s 5/rs1 0/imm12 2/funct3 6/rs2 + # store 0x0a (\n) in UART0+0 + 13/i 6/rd 0/funct3 0/rs a/imm12 + 23/s 5/rs1 0/imm12 2/funct3 6/rs2 + # jump back up to the top + 6f/j 0/rd main/off21 + +``ex.survey``: references resolved and labels removed:: + + == code 0x80000000 + # repeatedly print "Hi\n" + # main: + # load 0x10010000 (UART0) into t0 + 37/u 5/rd 10010/imm20 + # store 0x48 (H) in UART0+0 + 13/i 6/rd 0/funct3 0/rs 48/imm12 + 23/s 5/rs1 0/imm12 2/funct3 6/rs2 + # store 0x69 (i) in UART0+0 + 13/i 6/rd 0/funct3 0/rs 69/imm12 + 23/s 5/rs1 0/imm12 2/funct3 6/rs2 + # store 0x0a (\n) in UART0+0 + 13/i 6/rd 0/funct3 0/rs a/imm12 + 23/s 5/rs1 0/imm12 2/funct3 6/rs2 + # jump back up to the top + 6f/j 0/rd -1c/imm21 + +``ex.format``: arguments sliced and diced and put into the ISA order:: + + == code 0x80000000 + # repeatedly print "Hi\n" + # main: + # load 0x10010000 (UART0) into t0 + 37/7 05/5 10010/20 + # store 0x48 (H) in UART0+0 + 13/7 06/5 0/3 00/5 048/12 + 23/7 00/5 2/3 05/5 06/5 00/7 + # store 0x69 (i) in UART0+0 + 13/7 06/5 0/3 00/5 069/12 + 23/7 00/5 2/3 05/5 06/5 00/7 + # store 0x0a (\n) in UART0+0 + 13/7 06/5 0/3 00/5 00a/12 + 23/7 00/5 2/3 05/5 06/5 00/7 + # jump back up to the top + 6f/7 00/5 ff/8 1/1 3f2/10 1/1 + +``ex.elf``: ELF binary for loading in qemu:: + + $ riscv32-elf-readelf -l ex.elf + + Elf file type is EXEC (Executable file) + Entry point 0x80000000 + There is 1 program header, starting at offset 52 + + Program Headers: + Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align + LOAD 0x002000 0x80000000 0x80000000 0x00020 0x00020 R E 0x1000 + +Repo Contents +------------- + +- ``{validate,survey,format,pack,elf}.py``: pipeline stages +- ``{subv,bits}.py``: helpers for pipeline stages +- ``subv.sh``: Helper for running SubV code through all pipeline stages. + It will keep intermediate results in a temporary directory if errors occur, + and can be made to keep these results next to the input file with `--keep`. + + +Debugging +--------- + +You can hook `gdb` into `qemu` using the `-s` flag, and make it halt on start +using the `-S` flag. `gdb` can be attached using `target remote localhost:1234`: + + $ ./qemu.sh hello_world.elf -S -s + # in another terminal + $ riscv32-elf-gdb -iex "target remote localhost:1234" + layout asm # show assembly trace + nexti # step forward one instruction + c # free-run forward + +.. _SubX: https://github.com/akkartik/mu/blob/main/subx.md diff --git a/ex.elf b/ex.elf index 66dfc13..a509aaf 100644 Binary files a/ex.elf and b/ex.elf differ diff --git a/ex.format b/ex.format index 5fb48d8..6727dd1 100644 --- a/ex.format +++ b/ex.format @@ -1,6 +1,6 @@ == code 0x80000000 # repeatedly print "Hi\n" -main: +# main: # load 0x10010000 (UART0) into t0 37/7 05/5 10010/20 # store 0x48 (H) in UART0+0 @@ -12,12 +12,5 @@ main: # store 0x0a (\n) in UART0+0 13/7 06/5 0/3 00/5 00a/12 23/7 00/5 2/3 05/5 06/5 00/7 -# jump back up to the top (three versions): -# a) jal 21bit relative (with 0th bit forced to 0) -# 6f/jal 0/rd/x0 main/off21 -# b) auipc+jalr 32bit relative (note label offset) -17/7 07/5 main/off32/[31:12] -67/7 00/5 0/3 07/5 main+4/off32/[11:0] -# c) lui+jalr 32bit absolute -# 37/lui 7/rd/t2 main/imm32 -# 67/jalr 0/subop 0/rd/x0 7/rs/t2 main/imm32 +# jump back up to the top +6f/7 00/5 ff/8 1/1 3f2/10 1/1 diff --git a/ex.pack b/ex.pack index 5a6cdf4..e0cb8b9 100644 --- a/ex.pack +++ b/ex.pack @@ -12,12 +12,5 @@ b7 02 01 10 # store 0x0a (\n) in UART0+0 13 03 a0 00 23 a0 62 00 -# jump back up to the top (three versions): -# a) jal 21bit relative (with 0th bit forced to 0) -# 6f/jal 0/rd/x0 main/off21 -# b) auipc+jalr 32bit relative (note label offset) -97 f3 ff ff -67 80 43 fe -# c) lui+jalr 32bit absolute -# 37/lui 7/rd/t2 main/imm32 -# 67/jalr 0/subop 0/rd/x0 7/rs/t2 main/imm32 +# jump back up to the top +6f f0 5f fe diff --git a/ex.subv b/ex.subv index 16e9baf..408dabb 100644 --- a/ex.subv +++ b/ex.subv @@ -12,12 +12,5 @@ main: # store 0x0a (\n) in UART0+0 13/opi 0/subop/add 6/rd/t1 0/rs/x0 0a/imm12 23/store 2/width/word 5/rs/t0 6/rs/t1 0/off12 - # jump back up to the top (three versions): - # a) jal 21bit relative (with 0th bit forced to 0) - # 6f/jal 0/rd/x0 main/off21 - # b) auipc+jalr 32bit relative (note label offset) - 17/auipc 7/rd/t2 main/off20hi - 67/jalr 0/subop 0/rd/x0 7/rs/t2 main+4/off12lo - # c) lui+jalr 32bit absolute - # 37/lui 7/rd/t2 main/imm32 - # 67/jalr 0/subop 0/rd/x0 7/rs/t2 main/imm32 + # jump back up to the top + 6f/jal 0/rd/x0 main/off21 diff --git a/ex.survey b/ex.survey index 09e8475..e30860c 100644 --- a/ex.survey +++ b/ex.survey @@ -2,22 +2,15 @@ # repeatedly print "Hi\n" # main: # load 0x10010000 (UART0) into t0 -37/7 05/5 10010/20 +37/u 5/rd 10010/imm20 # store 0x48 (H) in UART0+0 -13/7 06/5 00/3 00/5 48/12 -23/7 00/5 02/3 05/5 06/5 00/7 +13/i 6/rd 0/funct3 0/rs 48/imm12 +23/s 5/rs1 0/imm12 2/funct3 6/rs2 # store 0x69 (i) in UART0+0 -13/7 06/5 00/3 00/5 69/12 -23/7 00/5 02/3 05/5 06/5 00/7 +13/i 6/rd 0/funct3 0/rs 69/imm12 +23/s 5/rs1 0/imm12 2/funct3 6/rs2 # store 0x0a (\n) in UART0+0 -13/7 06/5 00/3 00/5 0a/12 -23/7 00/5 02/3 05/5 06/5 00/7 -# jump back up to the top (three versions): -# a) jal 21bit relative (with 0th bit forced to 0) -# 6f/jal 0/rd/x0 main/off21 -# b) auipc+jalr 32bit relative (note label offset) -17/7 07/5 fffff/20 -67/7 00/5 00/3 07/5 fe4/12 -# c) lui+jalr 32bit absolute -# 37/lui 7/rd/t2 main/imm32 -# 67/jalr 0/subop 0/rd/x0 7/rs/t2 main/imm32 +13/i 6/rd 0/funct3 0/rs a/imm12 +23/s 5/rs1 0/imm12 2/funct3 6/rs2 +# jump back up to the top +6f/j 0/rd -1c/imm21 diff --git a/ex.valid b/ex.valid new file mode 100644 index 0000000..1652954 --- /dev/null +++ b/ex.valid @@ -0,0 +1,16 @@ +== code 0x80000000 +# repeatedly print "Hi\n" +main: +# load 0x10010000 (UART0) into t0 +37/u 5/rd 10010/imm20 +# store 0x48 (H) in UART0+0 +13/i 6/rd 0/funct3 0/rs 48/imm12 +23/s 5/rs1 0/imm12 2/funct3 6/rs2 +# store 0x69 (i) in UART0+0 +13/i 6/rd 0/funct3 0/rs 69/imm12 +23/s 5/rs1 0/imm12 2/funct3 6/rs2 +# store 0x0a (\n) in UART0+0 +13/i 6/rd 0/funct3 0/rs a/imm12 +23/s 5/rs1 0/imm12 2/funct3 6/rs2 +# jump back up to the top +6f/j 0/rd main/off21 diff --git a/hello_world.subv b/hello_world.subv new file mode 100644 index 0000000..60d9065 --- /dev/null +++ b/hello_world.subv @@ -0,0 +1,43 @@ +== code 0x80000000 + # load mhartid CSR into t0, trap all but first Hart + 73/system 5/rd/t0 2/funct3/csrrs 0/rs/x0 f14/imm12/mhartid + 63/branch 1/subop/!= 5/rs/t0 0/rs/x0 0/off13 + +main: + # x4 = &message + # . load high bits + 37/lui a/rd/a0 Message/imm20hi + # . add low bits + 13/opi 0/subop/add 4/rd/x4 a/rs/a0 Message/imm12lo + # call print + 6f/jal 1/rd/ra print/off21 +loop: + # infinite loop + 6f/jal 0/rd/x0 loop/off21 + +print: + # load 0x10010000 (UART0) into t0 + 37/lui 5/rd/t0 0x10010/imm20 +print:loop: + # load unsigned byte at x4 + 03/load 4/subop/byte 6/rd/t1 a/rs/a0 0/imm12 + # break loop if zero + 63/branch 0/subop/== 6/rs/t1 0/rs/x0 print:break/off13 +print:spin: + # spin if FIFO is full + 03/load 2/subop/word 7/rd/t2 5/rs/t0 0/imm12 + 63/branch 4/subop/< 7/rs/t2 0/rs/x0 print:spin/off13 + # print char + 23/store 2/width/word 5/rs/t0 6/rs/t1 0/off12 + # increment x4 + 13/opi 0/subop/add a/rd/a0 a/rs/a0 1/imm12 + # jump back up + 6f/jal 0/rd/x0 print:loop/off21 +print:break: + # return + 67/jalr 0/subop 0/rd/x0 1/rs/ra 0/off12 + +== data 0x80500000 +Message: + # "Hello World!\n\0" + 48/8 65/8 6c/8 6c/8 6f/8 20/8 77/8 6f/8 72/8 6c/8 64/8 21/8 0a/8 00/8 diff --git a/notes.md b/notes.md deleted file mode 100644 index cc051da..0000000 --- a/notes.md +++ /dev/null @@ -1,128 +0,0 @@ - -# RISC-V full size Instructions Formats (32bit): - -## R-format: op(rs1, rs2) -> rd -`opcode[7] rd[5] funct3[3] rs1[5] rs2[5] funct7[7]` - -register arithmetic/logical -opcode: 0b0110011 / 0x33 - -| funct7 | funct3 | operation | -|========|========|===========| -| 0x0 | 0x0 | ADD | -| 0x20 | 0x0 | SUB | -| 0x0 | 0x1 | SLL | -| 0x0 | 0x2 | SLT | -| 0x0 | 0x3 | SLTU | -| 0x0 | 0x4 | XOR | -| 0x0 | 0x5 | SRL | -| 0x20 | 0x5 | SRA | -| 0x0 | 0x6 | OR | -| 0x0 | 0x7 | AND | - -## I-Format: op(rs1, imm12) -> rd -`opcode[7] rd[5] funct3[3] rs1[5] imm[12]` - -load -opcode: 0b0000011 / 0x03 - -- rs1: base address -- imm12: offset (scaled/signed by funct3) - -| funct3 | operation | | -|========|===========|=====| -| 0x0 | LB | i8 | -| 0x1 | LH | i16 | -| 0x2 | LW | i32 | -| 0x4 | LBU | u8 | -| 0x5 | LHU | u16 | - - -immediate arhitmetic/logical -opcode: 0b0010011 / 0x13 - -- rs1: base address -- imm12: offset (scaled/signed by funct3) - -| funct3 | operation | | -|========|===========|==============================| -| 0x0 | ADDI | | -| 0x2 | SLTI | | -| 0x3 | SLTIU | | -| 0x4 | XORI | | -| 0x6 | ORI | | -| 0x7 | ANDI | | -| 0x1 | SLLI | imm12 = 0b0000000 , shamt[5] | -| 0x5 | SRLI | imm12 = 0b0000000 , shamt[5] | -| 0x5 | SRAI | imm12 = 0b0100000 , shamt[5] | - - -jalr -opcode = 0b1100111 / 0x67 - -- rs1: base address -- imm12: offset (bytes) -- save PC+4 in rd -- jump to offset - -## S-format: op(rs1, rs2, imm12) -`opcode[7] imm4:0[5] funct3[3] rs1[5] rs2[5] imm11:5[7]` - -store -opcode: 0b0100011 / 0x23 - -- rs1: base address -- rs2: data -- imm12: offset (scaled/signed by funct3) - -| funct3 | operation | | -|========|===========|==========================| -| 0x0 | SB | i8, imm12 in bytes | -| 0x1 | SH | i16, imm12 in half-words | -| 0x2 | SW | i32, imm13 in words | - -## SB-format: op(rs1, rs2, imm12/13) -`opcode[7] imm11[1] imm4:1[4] funct3[3] rs1[5] rs2[5] imm10:5[6] imm12[1]` - -branch -opcode = 0b1100011 / 0x63 - -- rs1, rs2: registers to compare -- imm12/13: PC offset in half-words - -| funct3 | operation | -|========|===========| -| 0x0 | BEQ | -| 0x1 | BNE | -| 0x4 | BLT | -| 0x5 | BGE | -| 0x6 | BLTU | -| 0x7 | BGEU | - -## U-Format: op(imm20/32) -> rd -`opcode[7] rd[5] imm31:12[20]` -upper-bit immediates (lui, auipc) - -lui -opcode: 0b0110111 / 0x37 - -- imm20: top 20 bits of rd -- clears bottom 12 bits -- combine lui + addi to load 32bit immediate - NOTE: sign extension requires some trickery. - -auipc: -opcode: 0b0010111 / 0x17 - -- imm20: top 20 bits of offset added to PC -- result stored in rd - -## J-Format: op(imm20/21) -> rd -`opcode[7] rd[5] imm31:12[20]` -immediates on a 32bit scale (jal) - -jal -opcode = 0b1101111 / 0x6f - -- save PC+4 in rd -- imm20/21: PC offset in half-words diff --git a/subv.sh b/subv.sh new file mode 100755 index 0000000..feb7f6c --- /dev/null +++ b/subv.sh @@ -0,0 +1,39 @@ +#!/bin/sh +set -e + +if [ "$#" -eq 2 -a \( \( "$1" = "--keep" \) -o \( "$1" = "-k" \) \) ]; then + INPUT="$2" + BASE=$(dirname "$INPUT")/$(basename "$INPUT" .subv) +elif [ "$#" -eq 1 ]; then + INPUT="$1" + DIR=$(mktemp -dt subv.XXXXXX) + BASE="$DIR"/$(basename "$INPUT" .subv) +else + echo "Error: invalid arguments" 1>&2 + echo "Usage: $0 [-k|--keep] input.subv" 1>&2 + exit 1 +fi + +msg() { + echo -e "\e[1;32m$1\e[00m" 1>&2 +} + +msg "OUTPUTTING TO $BASE.*" + +msg VALIDATING... +./validate.py <"$INPUT" >"$BASE.valid" +msg SURVEYING... +./survey.py <"$BASE.valid" >"$BASE.survey" +msg FORMATTING... +./format.py <"$BASE.survey" >"$BASE.format" +msg PACKING... +./pack.py <"$BASE.format" >"$BASE.pack" +msg ELFING... +./elf.py <"$BASE.pack" >"$BASE.elf" +msg DONE! + +if [ -n "$DIR" ]; then + cat "$BASE.elf" + rm "$BASE".* + rmdir "$DIR" +fi diff --git a/test.subv b/test.subv deleted file mode 100644 index 60d9065..0000000 --- a/test.subv +++ /dev/null @@ -1,43 +0,0 @@ -== code 0x80000000 - # load mhartid CSR into t0, trap all but first Hart - 73/system 5/rd/t0 2/funct3/csrrs 0/rs/x0 f14/imm12/mhartid - 63/branch 1/subop/!= 5/rs/t0 0/rs/x0 0/off13 - -main: - # x4 = &message - # . load high bits - 37/lui a/rd/a0 Message/imm20hi - # . add low bits - 13/opi 0/subop/add 4/rd/x4 a/rs/a0 Message/imm12lo - # call print - 6f/jal 1/rd/ra print/off21 -loop: - # infinite loop - 6f/jal 0/rd/x0 loop/off21 - -print: - # load 0x10010000 (UART0) into t0 - 37/lui 5/rd/t0 0x10010/imm20 -print:loop: - # load unsigned byte at x4 - 03/load 4/subop/byte 6/rd/t1 a/rs/a0 0/imm12 - # break loop if zero - 63/branch 0/subop/== 6/rs/t1 0/rs/x0 print:break/off13 -print:spin: - # spin if FIFO is full - 03/load 2/subop/word 7/rd/t2 5/rs/t0 0/imm12 - 63/branch 4/subop/< 7/rs/t2 0/rs/x0 print:spin/off13 - # print char - 23/store 2/width/word 5/rs/t0 6/rs/t1 0/off12 - # increment x4 - 13/opi 0/subop/add a/rd/a0 a/rs/a0 1/imm12 - # jump back up - 6f/jal 0/rd/x0 print:loop/off21 -print:break: - # return - 67/jalr 0/subop 0/rd/x0 1/rs/ra 0/off12 - -== data 0x80500000 -Message: - # "Hello World!\n\0" - 48/8 65/8 6c/8 6c/8 6f/8 20/8 77/8 6f/8 72/8 6c/8 64/8 21/8 0a/8 00/8 -- cgit v1.2.3