Hi All,
I have a question about whether the value of the upper bits are defined in the FD register file, for any of the double to single size narrowing or move operations: i.e.
- FCVT.S.D, FCVT.S.W, FCVT.S.WU (on RV{32,64}FD)
- FCVT.S.L and
FCVT.S.LU, FMV.S.X (on RV64FD)
What should the state of the upper bits be after any of these operations?
a) sign extend into the upper bits of a 64-bit register file?
b) zero extend into the upper bits of a 64-bit register file?
c) upper bits hold their previous bit values?
d) upper bits values are undefined?
The C pseudo code instructions I am working on use C cast notation for sign and zero extending. i.e. assigning s32() to a 64-bit signed type has the well-defined behaviour of sign extending. The integer register are all maximal width signed integers.
The sign extension versus zero extension recently caught me out on the 32-bit logical shift instructions on RV64 which counter intuitively (to me) sign extend for unsigned types. It seems all narrower integer operations will sign extend even if they are unsigned (logical). I used Alex’s port of the riscv-tests for the Linux ABI to test them <
https://github.com/arsv/riscv-qemu-tests> as I haven’t implemented the privileged spec yet.
These all pass the tests (and the rest of the integer ISA):
slliw "Shift Left Logical Immediate Word" "rd = s32(u32(rs1) << imm)"
srliw "Shift Right Logical Immediate Word" "rd = s32(u32(rs1) >> imm)"
sraiw "Shift Right Arithmetic Immediate Word" "rd = s32(rs1) >> imm"
sllw "Shift Left Logical Word" "rd = s32(u32(rs1) << (rs2 & 0b111111))"
srlw "Shift Right Logical Word" "rd = s32(u32(rs1) >> (rs2 & 0b111111))"
sraw "Shift Right Arithmetic Word" "rd = s32(rs1) >> (rs2 & 0b111111)”
The integer pseudo code now sign extends to wider type in the integer register file. The notation is able to get away with simple assignment to rd because it is the largest signed type, so sign extension happens naturally. I could potentially make type sugar aliases for sign_extend<32>(val) and to make it more human readable however the cast behaviour of C is “well defined".
However narrowing conversions in the float register are another story and may leave garbage bits in the upper 32-bits for narrowing conversion which could be read back out with fmv.x.d on RV64FD and result in undefined values on RV32FD if performing and fcvt.s.d (convert double to single) followed by fmv.x.d (shift double to int register).
fcvt.s.w "FP Convert Word to Float (SP)" "f32(frd) = f32(s32(rs1))"
fcvt.s.wu "FP Convert Word Unsigned to Float (SP)" "f32(frd) = f32(u32(rs1))"
fmv.s.x "FP Move from Integer Register (SP)" "u32(frd) = u32(rs1)"
fcvt.s.l "FP Convert Double Word to Float (SP)" "f32(frd) = f32(s64(rs1))"
fcvt.s.lu "FP Convert Double Word Unsigned to Float (SP)" "f32(frd) = f32(u64(rs1))"
fcvt.s.d "FP Convert DP to SP" "f32(frd) = f32(f64(frs1))"
fmv.x.d "FP Move to Integer Register (DP)" "rd = s64(frs1)”
Example, fcvt.s.d currently assigns to a float in a union of a float, double, integer words with padding in the correct endian order for the platform (so I can implement fmv). I don’t know an easy way to zero extend a float once it is a float so the upper bits are currently defined as "c) the upper bits hold their previous bit values". At least any other behaviour is not easily expressible in simple C. Some hardware may in fact have a different policy for the upper bits in the register file upon narrowing conversions.
fcvt.s.d "FP Convert DP to SP" "f32(frd) = f32(f64(frs1))”
and fmv.s.x could be made to sign extend very easily as it access an integer alias in the float/double register file union
fmv.s.x "FP Move from Integer Register (SP)” "sx(frd) = u32(rs1)”
and fmv.x.d (ont RV32) will currently integer overflow the binary representation of the double truncating it to 32 bits of the mantissa.
fmv.x.d "FP Move to Integer Register (DP)" "rd = s64(frs1)”
I think Krste just answered FMV.X.D. It should narrow to float on RV32IFD?
In any case, I have so far been able to express a large portion of the ISA as simple C pseudo code however there are a few edge cases with FP and I still need to implement fcsr and frm and I have to suppress OS Divide By Zero exceptions and what not...
Michael