RISC-V Control And Status Registers

Links

Control and Status Registers (CSRs)

In RISC-V assembly, frm stands for Floating-Point Rounding Mode. It is a 3-bit subfield within the fcsr (Floating-Point Control and Status Register).

When you write floating-point instructions in simulators like RARS (RISC-V Assembler and Runtime Simulator), you can handle rounding either statically (per instruction) or dynamically (using the frm register).

  1. RISC-V supports five distinct rounding modes mapped to specific 3-bit binary encodings:

    Binary Code Mnemonic Meaning
    000 RNE Round to Nearest, ties to Even (Default RISC-V mode)
    001 RTZ Round Towards Zero (Truncation)
    010 RDN Round Down (Towards -infinity)
    011 RUP Round Up (Towards +inifinity)
    100 RMM Round to Nearest, ties to Max Magnitude
    101–110   Reserved for future use
    111 DYN Dynamic (Uses the mode currently active in the frm register)

  2. Static vs. Dynamic Rounding in RARS

    Static Rounding (Per-Instruction)

    You can append a specific rounding mode mnemonic directly to your floating-point instruction. This overrides whatever is inside the frm register for that specific execution.

    fadd.s f1, f2, f3, rtz # Adds f2 and f3, rounds toward zero, stores in f1 fcvt.w.s t0, f1, rdn # Converts float to integer, rounding down

    Dynamic Rounding (Default Behavior)

    If you do not specify a rounding mode suffix, RARS defaults to using dyn, which tells the processor to look at the global frm field in the fcsr.

    add.s f1, f2, f3 # Equivalent to fadd.s f1, f2, f3, dyn

  3. Reading and Writing frm in RARS

    RISC-V provides dedicated pseudo-instructions to manipulate the frm register without needing to mask out other parts of the full fcsr register:

    • frrm rd (Read Rounding Mode): Copies the current 3-bit frm value into the integer register rd.

    • fsrm rd, rs1 (Swap Rounding Mode): Copies the old frm value into rd, and writes a new 3-bit rounding mode from rs1 into frm.

    Example: Dynamically Changing Rounding

    .text .globl main main: # 1. Read current rounding mode (should be 000 / RNE by default) frrm t0 # t0 now holds the current frm value # 2. Change rounding mode to RTZ (Round Towards Zero = 1) li t1, 1 # 1 corresponds to RTZ fsrm t2, t1 # t2 saves old mode; frm is updated to 1 (RTZ) # 3. Perform a floating point operation using the new dynamic mode # (Since no static suffix is given, it looks at frm, which is now RTZ) fadd.s f1, f2, f3