Inconsistency of load/store vs. computation opcode assignments

59 views
Skip to first unread message

Kelly Dean

unread,
Mar 2, 2018, 11:19:00 PM3/2/18
to RISC-V ISA Dev
One possible opcode assignment strategy (let's call this “fixed opcodes”) would be to have a standard pair of opcodes for LW and SW, independent of XLEN. Then for RV64, add a separate pair of opcodes for LD and SD, and for RV128, add LQ and SQ.

An alternative (let's call this “sliding opcodes”) would be to have a standard pair of opcodes for LOAD and STORE, which operate on XLEN bits. Then for RV64, add a separate pair of opcodes for LW and SW for 32-bit values, and for RV128, add LD and SD for 64-bit values.

Likewise, fixed opcodes for computation would be a standard set of opcodes for ADD[I]W, SUBW, and [SLL|SRL|SRA][I]W, independent of XLEN. Then for RV64, add a separate set of opcodes for *D, and for RV128, add *Q.

Sliding opcodes for computation would be a standard set of opcodes for ADD[I], SUB, and [SLL|SRL|SRA][I], which operate on XLEN bits. Then for RV64, add a separate set of opcodes for *W for 32-bit values, and for RV128, add *D for 64-bit values.

RISC-V's designers chose fixed opcodes for load/store, but sliding opcodes for computation. Was this inconsistency intentional, or a historical accident?

Rogier Brussee

unread,
Mar 4, 2018, 9:37:46 AM3/4/18
to RISC-V ISA Dev, ke...@prtime.org


Op zaterdag 3 maart 2018 05:19:00 UTC+1 schreef Kelly Dean:
Good question!

It seems RV could have its cake and eat it too, by using the opcodes for LQ/SQ for an LX/SX instruction (which could then clearly be used where LQ/SQ would have been used on RV128). It would match intptr_t/void* (aka long/void*) in the C programming language. 

To be effective I think it would then also be useful to be able to add  n*(XLEN/8) to do adres computations independent of XLEN. This could be done by extending the ADD instruction with 2 extra bits to indicate the unit of what is being added 

add_b   rd rs1 rs2         rd<- rs1 + rs2 << 0                                  # This is just an alias for the add instruction and should use its opcode)
add_x   rd rs1 rs2         rd<- rs1 + rs2 << log2(XLEN/8)              
add_w  rd rs1 rs2         rd<- rs1 + rs2 << 2
add_d   rd rs1rs2          rd<- rs1 + rs2 << 3 

( Perhaps for RV64/128 it is also useful to have something like 
addwu_b     rd rs1 rs2         rd<- rs1 + zext(rs2, 32) << 0
addwu_x     rd rs1 rs2         rd<- rs1 + zext(rs2, 32) << log2(XLEN/8)
addwu_w    rd rs1 rs2         rd<- rs1 + zext(rs2, 32) << 2
addwu_d     rd rs1 rs2         rd<- rs1 + zext(rs2, 32) << 3

with similar adddu_[bxwd] for RV128
)


One would have to think about the most optimal Compact (C)  encoding given such a scheme, but the two obvious ways would be to simply use the encoding for RV128 use the encodings for C.LQ[SP] C.SQ[SP] for LX[SP] SX[SP], but another would be to reuse the encodings for C.LD[SP] and C.SD[SP]  for a RV32/RV64 portable scheme backward compatible with RV64C that would also allow the use of C.FLD[SP]/C.FSD[SP]  



[1] i.e on RV32   N(0b00) = 0,  N(0b01) = 2, N(0b10) = 2  N(0b11) = 3,  
          on RV64   N(0b00) = 0,  N(0b01) = 3  N(0b10) = 2  N(0b11) = 3,  
          on RV128 N(0b00) = 0,  N(0b01) = 4  N(0b10) = 2  N(0b11) = 3,
Reply all
Reply to author
Forward
0 new messages