From SizeCoding
Revision as of 16:10, 18 April 2024 by Popolon (talk | contribs) (Introduction: add link to RISC-V Code Size Reduction Group and explain what means ISA here)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search


RISC-V is an open and free standard or RISC ISA (Instruction Set Architecture). It exists in 32,64 and still in draft stage, 128 bits wide versions. There are lot of free or non free implementations. You can find software, FPGA, or ASIC implementations on most codeforges like Github, Gitlab, Gitea, etc... Several research institute around the world also opened their own versions.

The RISC-V Code Size Reduction Group worked on code reduction in RISC-V ISA

The RISC-V processor ISA

The RISC-V Processor is a RISC based architecture, with less instructions than most other RISC processors, as one the goal is to hardly shrink number of transistors. For example, there is no GT (>) or LE (<=) hardware instructions, only LT (<) or GE (>=) instructions, but GT and LE can be synthesized by switching it to LT/GE, and the registers in test to keep the test as needed. The only immediate value possible is coded on 12 bits. If the value is signed, the sign will be extended to the higher bit, of the size of the register. Several instructions are supported in RISC-V assembly language that doesn't actually exists as code machine instructions.

Warning: Generally less instruction in ISA (Instruction Set Architecture) as for RISC-V, means more instruction in machine code to have the same computation process, so RISC-V is not really competitive with other architectures for size-coding. It's advantage is more on transistors size-coding in its implementations, allowing more cores or more extensions than other architecture for the same die size, and a more efficient computation/power ratio. So there is also some LUT sizecoding tips, as used in the PicoRV32 implementation (ISC licensen similar to BSD one).

One of the main goals of the specifications is to have modularity with high granularity. So bitwise operators, multiplications/divisions, vector instructions for example are on different optional extensions, that can be implemented or not by RISC-V processor makers, reducing the total number of transistors depending on processor usage. Each extension have its own letter added in the name of the processor.

The specifications are all available on the risc-v.org site: https://riscv.org/technical/specifications/

Nomenclature and extensions

  • RV|32/64/128|E/I/G: RiscV, 32, 64 or 128 bits, base Embedded/ Integer/General purpose instruction set

So you will see generally RV32I for 32bits version + other letters corresponding to extensions as defined below. RV32E means (still) reduced, embedded systems version of integer instruction set. RV32I or (RV64G) means RV32 or RV64 + General purpose (including IMAFD + Zicsr+ Zifenci extension) as described below:

Basic 'standardized extension are:

  • Zifencei: Instruction-Fetch Fence
  • M: Multiplication/division
  • A: Atomic instructions
  • Zicsr: Control and Status Register
  • F: Single-precision Floating-Point
  • D: Double-precision Floating-Point
  • G: General pupose (all of the above together)
  • Q: Quad-precision Floating-Point
  • L: Decimal Floating-Point (IEEE 754-2008)
  • C: Compressed instructions
  • B: Bit manipulation
  • J: JIT for dynamically translated languages
  • T: Transactional memory
  • P: Packed SIMD instructions
  • V: Vector instructions (as a vector processor, not as a packed SIMD)
  • Zam: Misaligned Atomics
  • Ztso: Total Store Ordering
  • S: Supervisor-level Instruction-Set Extensions
  • H: Hypervisor-level Instruction-Set Extensions
  • X<name>: Non standard extension
  • Crypto extension is frozen, and should be available in October.

General options and 16bits Compressed mnemonics extension

OS like Debian use RV64GC as default compiler extensions options. This mean General (IMAF) + Compressed instructions. Compressed mnemonics (assembly instructions) are a limited subset of mnemonics, that all fits on 16 bits. They are prefixed by c., and described in "Chapter 16 . “C” Standard Extension for Compressed Instructions, Version 2.0", page 97, of of the current specifications : "The RISC-V Instruction Set Manual - Volume I: Unprivileged ISA - Document Version 20191213".

RISC-V Assembly language use pseudo mnemonics (li=load immediate, is one of them) and assemblers like those of GCC or CLANG, convert them with their best efforts to more optimised ones, using compressed version, if the C flag is passed to --march argument:

if f(loat) option is passed (as in imafc or gc), the final executable is a bit bigger than without it. So it can be interesting to limit extensions to really used one. However it can be useful to have access to floats numbers in demos.

An example of building script with stripping if floats aren't used. You can decide to pass (tinydemo.s) or not the .s (tinydemo) to the script:

riscv64-elf-as -march=rv64imac -o $file.o $file.s
riscv64-elf-ld -o $file $file.o
riscv64-elf-strip --strip-all $file

A similar script with clang. -s shorter version of -strip-all can be used. It make slightly bigger elf executables.

clang --target=riscv64 -march=rv64imac -mno-relax ${file}.s -c -o ${file}.o
ld.lld -strip-all ${file}.o -o ${file}

To disassemble the executable file, you can use gnu objdump with -d option:

riscv64-elf-objdump -d tinydemo

However. This show pseudocode version of the software. To display mnemonics really used, add the option -M no-aliases as is:

riscv64-elf-objdump -d -M no-aliases tinydemo

The option -x of objdump allow to see all the most segments of the ELF binary, but due to its usage to libBDF decoding, it only contains some part. The readelf tool (also part of GNU binutils) display all real segments with -S option. There is probably still some byte to gain there :).

riscv64-elf-readelf -S tinydemo


Registers in assembly language can be called x0-x31 or by their specific functions. x0 is always 0 and can't be changed.

In compressed mnemonics, only 8 registers are available, due to 3bits limit of the register field in this case. Theses registers are for integer, x8-x15 or s0,s1,a0-a5 (in ABI), and for floats f8-f15 or in ABI fs0,fs1,fa0-fa5. An assembler error will occur if you try to use other registers with c. mnemonics, or a pseudo-instruction will be translated in non c. mnemonic.


Assembler, compiler, linker

  • GNU tools contains both RISC-V 32 and 64bits compiler (in GCC), assembler (as), linker (ld), striper (strip), dumper/disassembler (objdump) contained in (gnu-binutils) and debugger (GDB, GNU Debugger), they are available for native or cross-compiling on most GNU/Linux distribution.
  • CLANG/LLVM contains compiler/assembler (clang), linker that can strip (ld.lld)
  • Bronzebeard is a standalone assembler for developing bare metal RISC-V programs. It has been used mainly on Longan Nano a RV32 board generally sold with an LCD screen. There are few demo on this board. The initialisation of the screen on this platform has an important footprint that can't allow to go in 128B or 256B competitions.
  • Arduino has several RISC-V implementations.
  • It exists various assembler, simulators, emulators (Qemu, TinyEMU, RVVM,… including WASM versions), various FPGA softcore implementations of RISC-V, and finally lot of cheap ASIC/boards hardware ones see below for various methods for running RISC-V code.

Most other languages are also available in RISC-V instruction set. Some Linux distribution have been ported and ISO are available (Debian, Ubuntu for example). Haiku OS also work on RISC-V platform, and there are plenty of embedded OS working on it (Arduino, FreeRTOS, HarmonyOS, LiteOS, RT-Thread, RustOS, Zephyr...).

Testing it

If you don't have one of those cheap boards, you can still test RISC-V assembly on an emulator.

Qemu allow to execute RISC-V application or systems on any kind of architectures. You can use the same tricks than used on x86 to reduce the binary size of the ELF binary format made with GNU tools. "user static binfmt" allow to runs risc-v binaries transparently in non-risc-v systems.

The main author of Qemu also made TinyEmu, a RISC-V only tiny emulator, it already has WASM ports, so you can play with it on the web.