git.s-ol.nu subv / master
master

Tree @master (Download .tar.gz)

SubV

This is a wip clone of SubX for the RISC-V RV32I base ISA.

$ <examples/hello_world.subv ./validate.py | ./survey.py | ./format.py | ./pack.py | ./elf.py >examples/hello_world.elf
$ ./qemu.sh examples/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 <examples/ex.subv   >examples/ex.valid
$ ./survey.py   <examples/ex.valid  >examples/ex.survey
$ ./format.py   <examples/ex.survey >examples/ex.format
$ ./pack.py     <examples/ex.format >examples/ex.pack
$ ./elf.py      <examples/ex.pack   >examples/ex.elf
$ ./qemu.sh ex.elf

ex.subv: hand-writable:

== code 0x80400000
# repeatedly print "Hi\n"
main:
  # load 0x10000000 (UART0) into t0
  37/lui 5/rd/t0 10000/imm20
  # store 0x48 (H) in UART0+0
  13/opi 0/subop/add 6/rd/t1 0/rs/x0 48/imm12
  23/store 0/width/byte 5/rs/t0 0/off12 6/rs/t1
  # store 0x69 (i) in UART0+0
  13/opi 0/subop/add 6/rd/t1 0/rs/x0 69/imm12
  23/store 0/width/byte 5/rs/t0 0/off12 6/rs/t1
  # store 0x0a (\n) in UART0+0
  13/opi 0/subop/add 6/rd/t1 0/rs/x0 0a/imm12
  23/store 0/width/byte 5/rs/t0 0/off12 6/rs/t1
  # jump back up to the top
  6f/jal 0/rd/x0 main/off21

ex.valid: mnemonics validated and discarded:

== code 0x80400000
# repeatedly print "Hi\n"
main:
# load 0x10000000 (UART0) into t0
37/u 5/rd 10000/imm20
# store 0x48 (H) in UART0+0
13/i 6/rd 0/funct3 0/rs 48/imm12
23/s 0/funct3 5/rs1 0/imm12 6/rs2
# store 0x69 (i) in UART0+0
13/i 6/rd 0/funct3 0/rs 69/imm12
23/s 0/funct3 5/rs1 0/imm12 6/rs2
# store 0x0a (\n) in UART0+0
13/i 6/rd 0/funct3 0/rs a/imm12
23/s 0/funct3 5/rs1 0/imm12 6/rs2
# jump back up to the top
6f/j 0/rd main/off21

ex.survey: references resolved and labels removed:

== code 0x80400000
# repeatedly print "Hi\n"
# main:
# load 0x10000000 (UART0) into t0
37/u 5/rd 10000/imm20
# store 0x48 (H) in UART0+0
13/i 6/rd 0/funct3 0/rs 48/imm12
23/s 0/funct3 5/rs1 0/imm12 6/rs2
# store 0x69 (i) in UART0+0
13/i 6/rd 0/funct3 0/rs 69/imm12
23/s 0/funct3 5/rs1 0/imm12 6/rs2
# store 0x0a (\n) in UART0+0
13/i 6/rd 0/funct3 0/rs a/imm12
23/s 0/funct3 5/rs1 0/imm12 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