[[memorymodel]] == RVWMO Memory Consistency Model, Version 2.0 This chapter defines the RISC-V memory consistency model. A memory consistency model is a set of rules specifying the values that can be returned by loads of memory. RISC-V uses a memory model called "RVWMO" (RISC-V Weak Memory Ordering) which is designed to provide flexibility for architects to build high-performance scalable designs while simultaneously supporting a tractable programming model. (((design, high performance))) (((design, scalable))) Under RVWMO, code running on a single hart appears to execute in order from the perspective of other memory instructions in the same hart, but memory instructions from another hart may observe the memory instructions from the first hart being executed in a different order. Therefore, multithreaded code may require explicit synchronization to guarantee ordering between memory instructions from different harts. The base RISC-V ISA provides a FENCE instruction for this purpose, described in <>, while the atomics extension "A" additionally defines load-reserved/store-conditional and atomic read-modify-write instructions. (((atomics, misaligned))) The standard ISA extension for total store ordering "Ztso" (<>) augments RVWMO with additional rules specific to those extensions. The appendices to this specification provide both axiomatic and operational formalizations of the memory consistency model as well as additional explanatory material. (((FENCE))) (((SFENCE))) [NOTE] ==== This chapter defines the memory model for regular main memory operations. The interaction of the memory model with I/O memory, instruction fetches, FENCE.I, page table walks, and SFENCE.VMA is not (yet) formalized. Some or all of the above may be formalized in a future revision of this specification. The RV128 base ISA and future ISA extensions such as the V vector and J JIT extensions will need to be incorporated into a future revision as well. Memory consistency models supporting overlapping memory accesses of different widths simultaneously remain an active area of academic research and are not yet fully understood. The specifics of how memory accesses of different sizes interact under RVWMO are specified to the best of our current abilities, but they are subject to revision should new issues be uncovered. ==== [[rvwmo]] === Definition of the RVWMO Memory Model The RVWMO memory model is defined in terms of the _global memory order_, a total ordering of the memory operations produced by all harts. In general, a multithreaded program has many different possible executions, with each execution having its own corresponding global memory order. (((RVWMO))) The global memory order is defined over the primitive load and store operations generated by memory instructions. It is then subject to the constraints defined in the rest of this chapter. Any execution satisfying all of the memory model constraints is a legal execution (as far as the memory model is concerned). [[rvwmo-primitives]] ==== Memory Model Primitives The _program order_ over memory operations reflects the order in which the instructions that generate each load and store are logically laid out in that hart's dynamic instruction stream; i.e., the order in which a simple in-order processor would execute the instructions of that hart. Memory-accessing instructions give rise to _memory operations_. A memory operation can be either a _load operation_, a _store operation_, or both simultaneously. All memory operations are single-copy atomic: they can never be observed in a partially complete state. (((operations, memory))) Among instructions in RV32GC and RV64GC, each aligned memory instruction gives rise to exactly one memory operation, with two exceptions. First, an unsuccessful SC instruction does not give rise to any memory operations. Second, FLD and FSD instructions may each give rise to multiple memory operations if XLEN<64, as stated in <> and clarified below. An aligned AMO gives rise to a single memory operation that is both a load operation and a store operation simultaneously. [NOTE] ==== Instructions in the RV128 base instruction set and in future ISA extensions such as *V* (vector) and *P* (SIMD) may give rise to multiple memory operations. However, the memory model for these extensions has not yet been formalized. ==== A misaligned load or store instruction may be decomposed into a set of component memory operations of any granularity. An FLD or FSD instruction for which XLEN<64 may also be decomposed into a set of component memory operations of any granularity. The memory operations generated by such instructions are not ordered with respect to each other in program order, but they are ordered normally with respect to the memory operations generated by preceding and subsequent instructions in program order. The atomics extension "A" does not require execution environments to support misaligned atomic instructions at all. However, if misaligned atomics are supported via the misaligned atomicity granule PMA, then AMOs within an atomicity granule are not decomposed, nor are loads and stores defined in the base ISAs, nor are loads and stores of no more than XLEN bits defined in the F, D, and Q extensions. (((decomposition))) [NOTE] ==== The decomposition of misaligned memory operations down to byte granularity facilitates emulation on implementations that do not natively support misaligned accesses. Such implementations might, for example, simply iterate over the bytes of a misaligned access one by one. ==== An LR instruction and an SC instruction are said to be _paired_ if the LR precedes the SC in program order and if there are no other LR or SC instructions in between; the corresponding memory operations are said to be paired as well (except in case of a failed SC, where no store operation is generated). The complete list of conditions determining whether an SC must succeed, may succeed, or must fail is defined in <>. Load and store operations may also carry one or more ordering annotations from the following set: "acquire-RCpc", "acquire-RCsc", "release-RCpc", and "release-RCsc". An AMO or LR instruction with _aq_ set has an "acquire-RCsc" annotation. An AMO or SC instruction with _rl_ set has a "release-RCsc" annotation. An AMO, LR, or SC instruction with both _aq_ and _rl_ set has both "acquire-RCsc" and "release-RCsc" annotations. For convenience, we use the term "acquire annotation" to refer to an acquire-RCpc annotation or an acquire-RCsc annotation. Likewise, a "release annotation" refers to a release-RCpc annotation or a release-RCsc annotation. An "RCpc annotation" refers to an acquire-RCpc annotation or a release-RCpc annotation. An _RCsc annotation_ refers to an acquire-RCsc annotation or a release-RCsc annotation. [NOTE] ==== In the memory model literature, the term "RCpc" stands for release consistency with processor-consistent synchronization operations, and the term "RCsc" stands for release consistency with sequentially consistent synchronization operations. While there are many different definitions for acquire and release annotations in the literature, in the context of RVWMO these terms are concisely and completely defined by <> rules 5-7. "RCpc" annotations are currently only used when implicitly assigned to every memory access per the standard extension "Ztso" (<>). Furthermore, although the ISA does not currently contain native load-acquire or store-release instructions, nor RCpc variants thereof, the RVWMO model itself is designed to be forwards-compatible with the potential addition of any or all of the above into the ISA in a future extension. ==== [[mem-dependencies]] ==== Syntactic Dependencies The definition of the RVWMO memory model depends in part on the notion of a syntactic dependency, defined as follows. In the context of defining dependencies, a _register_ refers either to an entire general-purpose register, some portion of a CSR, or an entire CSR. The granularity at which dependencies are tracked through CSRs is specific to each CSR and is defined in <>. Syntactic dependencies are defined in terms of instructions' _source registers_, instructions' _destination registers_, and the way instructions _carry a dependency_ from their source registers to their destination registers. This section provides a general definition of all of these terms; however, <> provides a complete listing of the specifics for each instruction. In general, a register _r_ other than `x0` is a _source register_ for an instruction _i_ if any of the following hold: * In the opcode of _i_, _rs1_, _rs2_, or _rs3_ is set to _r_ * _i_ is a CSR instruction, and in the opcode of _i_, _csr_ is set to _r_, unless _i_ is CSRRW or CSRRWI and _rd_ is set to `x0` * _r_ is a CSR and an implicit source register for _i_, as defined in <> * _r_ is a CSR that aliases with another source register for _i_ Memory instructions also further specify which source registers are _address source registers_ and which are _data source registers_. In general, a register _r_ other than `x0` is a _destination register_ for an instruction _i_ if any of the following hold: * In the opcode of _i_, _rd_ is set to _r_ * _i_ is a CSR instruction, and in the opcode of _i_, _csr_ is set to _r_, unless _i_ is CSRRS or CSRRC and _rs1_ is set to `x0` or _i_ is CSRRSI or CSRRCI and uimm[4:0] is set to zero. * _r_ is a CSR and an implicit destination register for _i_, as defined in <> * _r_ is a CSR that aliases with another destination register for _i_ Most non-memory instructions _carry a dependency_ from each of their source registers to each of their destination registers. However, there are exceptions to this rule; see <>. Instruction _j_ has a _syntactic dependency_ on instruction _i_ via destination register _s_ of _i_ and source register _r_ of _j_ if either of the following hold: * _s_ is the same as _r_, and no instruction program-ordered between _i_ and _j_ has _r_ as a destination register * There is an instruction _m_ program-ordered between _i_ and _j_ such that all of the following hold: . _j_ has a syntactic dependency on _m_ via destination register _q_ and source register _r_ . _m_ has a syntactic dependency on _i_ via destination register _s_ and source register _p_ . _m_ carries a dependency from _p_ to _q_ Finally, in the definitions that follow, let _a_ and _b_ be two memory operations, and let _i_ and _j_ be the instructions that generate _a_ and _b_, respectively. _b_ has a _syntactic address dependency_ on _a_ if _r_ is an address source register for _j_ and _j_ has a syntactic dependency on _i_ via source register _r_ _b_ has a _syntactic data dependency_ on _a_ if _b_ is a store operation, _r_ is a data source register for _j_, and _j_ has a syntactic dependency on _i_ via source register _r_ _b_ has a _syntactic control dependency_ on _a_ if there is an instruction _m_ program-ordered between _i_ and _j_ such that _m_ is a branch or indirect jump and _m_ has a syntactic dependency on _i_. [NOTE] ==== Generally speaking, non-AMO load instructions do not have data source registers, and unconditional non-AMO store instructions do not have destination registers. However, a successful SC instruction is considered to have the register specified in _rd_ as a destination register, and hence it is possible for an instruction to have a syntactic dependency on a successful SC instruction that precedes it in program order. ==== ==== Preserved Program Order [[ppo]] The global memory order for any given execution of a program respects some but not all of each hart’s program order. The subset of program order that must be respected by the global memory order is known as _preserved program order_. The complete definition of preserved program order is as follows (and note that AMOs are simultaneously both loads and stores): memory operation _a_ precedes memory operation _b_ in preserved program order (and hence also in the global memory order) if _a_ precedes _b_ in program order, _a_ and _b_ both access regular main memory (rather than I/O regions), and any of the following hold: [[overlapping-ordering]] * Overlapping-Address Orderings: . _b_ is a store, and _a_ and _b_ access overlapping memory addresses . _a_ and _b_ are loads, _x_ is a byte read by both _a_ and _b_, there is no store to _x_ between _a_ and _b_ in program order, and _a_ and _b_ return values for _x_ written by different memory operations . _a_ is generated by an AMO or SC instruction, _b_ is a load, and _b_ returns a value written by _a_ * Explicit Synchronization [start=4] . There is a FENCE instruction that orders _a_ before _b_ . _a_ has an acquire annotation . _b_ has a release annotation . _a_ and _b_ both have RCsc annotations . _a_ is paired with _b_ * Syntactic Dependencies [start=9] . _b_ has a syntactic address dependency on _a_ . _b_ has a syntactic data dependency on _a_ . _b_ is a store, and _b_ has a syntactic control dependency on _a_ * Pipeline Dependencies [start=12] . _b_ is a load, and there exists some store _m_ between _a_ and _b_ in program order such that _m_ has an address or data dependency on _a_, and _b_ returns a value written by _m_ . _b_ is a store, and there exists some instruction _m_ between _a_ and _b_ in program order such that _m_ has an address dependency on _a_ ==== Memory Model Axioms An execution of a RISC-V program obeys the RVWMO memory consistency model only if there exists a global memory order conforming to preserved program order and satisfying the _load value axiom_, the _atomicity axiom_, and the _progress axiom_. [[ax-load]] ===== Load Value Axiom Each byte of each load _i_ returns the value written to that byte by the store that is the latest in global memory order among the following stores: . Stores that write that byte and that precede _i_ in the global memory order . Stores that write that byte and that precede _i_ in program order [[ax-atom]] ===== Atomicity Axiom If _r_ and _w_ are paired load and store operations generated by aligned LR and SC instructions in a hart _h_, _s_ is a store to byte _x_, and _r_ returns a value written by _s_, then _s_ must precede _w_ in the global memory order, and there can be no store from a hart other than _h_ to byte _x_ following _s_ and preceding _w_ in the global memory order. [NOTE] ==== The <> theoretically supports LR/SC pairs of different widths and to mismatched addresses, since implementations are permitted to allow SC operations to succeed in such cases. However, in practice, we expect such patterns to be rare, and their use is discouraged. ==== [[ax-prog]] ===== Progress Axiom No memory operation may be preceded in the global memory order by an infinite sequence of other memory operations. [[csr-granularity]] === CSR Dependency Tracking Granularity .Granularities at which syntactic dependencies are tracked through CSRs [%autowdith,float="center",align="center",cols="<,<,<",options="header",] |=== |Name |Portions Tracked as Independent Units |Aliases |_fflags_ |Bits 4, 3, 2, 1, 0 |_fcsr_ |_frm_ |entire CSR |_fcsr_ |_fcsr_ |Bits 7-5, 4, 3, 2, 1, 0 |_fflags_, _frm_ |=== Note: read-only CSRs are not listed, as they do not participate in the definition of syntactic dependencies. [[source-dest-regs]] === Source and Destination Register Listings This section provides a concrete listing of the source and destination registers for each instruction. These listings are used in the definition of syntactic dependencies in <>. The term "accumulating CSR" is used to describe a CSR that is both a source and a destination register, but which carries a dependency only from itself to itself. Instructions carry a dependency from each source register in the "Source Registers" column to each destination register in the "Destination Registers" column, from each source register in the "Source Registers" column to each CSR in the "Accumulating CSRs" column, and from each CSR in the "Accumulating CSRs" column to itself, except where annotated otherwise. Key: - ^A^Address source register - ^D^Data source register - † The instruction does not carry a dependency from any source register to any destination register - ‡ The instruction carries dependencies from source register(s) to destination register(s) as specified .RV32I Base Integer Instruction Set [%autowidth,float="center",align="center",cols="<,<,<,<,<",options="header"] |=== ||Source Registers |Destination Registers|Accumulating CSRs| |LUI | |_rd_ | | |AUIPC | |_rd_ || |JAL | |_rd_ || |JALR† |_rs1_ |_rd_ || |BEQ |_rs1_, _rs2_ | || |BNE |_rs1_, _rs2_ | || |BLT |_rs1_, _rs2_ | || |BGE |_rs1_, _rs2_ | || |BLTU |_rs1_, _rs2_ | || |BGEU |_rs1_, _rs2_ | || |LB † | _rs1_ ^A^ | _rd_ || |LH † | _rs1_ ^A^ | _rd_ || |LW † | _rs1_ ^A^ | _rd_ || |LBU † | _rs1_ ^A^ | _rd_ || |LHU † | _rs1_ ^A^ | _rd_ || |SB |_rs1_ ^A^, _rs2_ ^D^ | || |SH |_rs1_ ^A^, _rs2_ ^D^ | || |SW |_rs1_ ^A^, _rs2_ ^D^ | || |ADDI |_rs1_ |_rd_ || |SLTI |_rs1_ |_rd_ || |SLTIU |_rs1_ |_rd_ || |XORI |_rs1_ |_rd_ || |ORI |_rs1_ |_rd_ || |ANDI |_rs1_ |_rd_ || |SLLI |_rs1_ |_rd_ || |SRLI |_rs1_ |_rd_ || |SRAI |_rs1_ |_rd_ || |ADD |_rs1_, _rs2_ |_rd_ || |SUB |_rs1_, _rs2_ |_rd_ || |SLL |_rs1_, _rs2_ |_rd_ || |SLT |_rs1_, _rs2_ |_rd_ || |SLTU |_rs1_, _rs2_ |_rd_ || |XOR |_rs1_, _rs2_ |_rd_ || |SRL |_rs1_, _rs2_ |_rd_ || |SRA |_rs1_, _rs2_ |_rd_ || |OR |_rs1_, _rs2_ |_rd_ || |AND |_rs1_, _rs2_ |_rd_ || |FENCE | | || |FENCE.I | | || |ECALL | | || |EBREAK | | || |CSRRW‡ |_rs1_, _csr_^*^ | _rd_, _csr_ | |^*^unless _rd_=`x0` |CSRRS‡ |_rs1_, _csr_ |_rd_ ^*^, _csr_ | |^*^unless _rs1_=`x0` |CSRRC‡ |_rs1_, _csr_ |_rd_ ^*^, _csr_ | |^*^unless _rs1_=`x0` 5+| ‡ carries a dependency from _rs1_ to _csr_ and from _csr_ to _rd_ |CSRRWI ‡ |_csr_ ^*^ |_rd_, _csr_ | |^*^unless _rd_=_x0_ |CSRRSI ‡ |_csr_ |_rd_, _csr_^*^ | |^*^unless uimm[4:0]=0 |CSRRCI ‡ |_csr_ |_rd_, _csr_^*^ | |^*^unless uimm[4:0]=0 5+| ‡ carries a dependency from _csr_ to _rd_ |=== .RV64I Base Integer Instruction Set [%autowidth.stretch,float="center",align="center",cols="<,<,<,<,<",options="header"] |=== | |Source Registers |Destination Registers |Accumulating CSRs| |_LWU_ † |_rs1_ ^A^ |_rd_ | | |_LD_ † |_rs1_ ^A^ |_rd_ | | |SD |_rs1_ ^A^, _rs2_ ^D^ | | | |SLLI | _rs1_ | _rd_ | | |SRLI | _rs1_ | _rd_ | | |SRAI | _rs1_ | _rd_ | | |ADDIW | _rs1_ | _rd_ | | |SLLIW | _rs1_ | _rd_ | | |SRLIW | _rs1_ | _rd_ | | |SRAIW | _rs1_ | _rd_ | | |ADDW | _rs1_, _rs2_ |_rd_ || |SUBW | _rs1_, _rs2_ |_rd_ || |SLLW | _rs1_, _rs2_ |_rd_ || |SRLW | _rs1_, _rs2_ |_rd_ || |SRAW | _rs1_, _rs2_ |_rd_ || |=== .RV32M Standard Extension [%autowidth.stretch,float="center",align="center",cols="<,<,<,<,<",options="header"] |=== | |Source Registers |Destination Registers |Accumulating CSRs| |MUL | _rs1_, _rs2_ |_rd_ || |MULH | _rs1_, _rs2_ |_rd_ || |MULHSU |_rs1_, _rs2_ |_rd_ || |MULHU |_rs1_, _rs2_ |_rd_ || |DIV |_rs1_, _rs2_ |_rd_ || |DIVU |_rs1_, _rs2_ |_rd_ || |REM |_rs1_, _rs2_ |_rd_ || |REMU |_rs1_, _rs2_ |_rd_ || |=== .RV64M Standard Extension [%autowidth.stretch,float="center",align="center",cols="<,<,<,<,<",options="header"] |=== ||Source Registers |Destination Registers |Accumulating CSRs| |MULW |_rs1_, _rs2_ |_rd_ || |DIVW |_rs1_, _rs2_ |_rd_ || |DIVUW |_rs1_, _rs2_ |_rd_ || |REMW |_rs1_, _rs2_ |_rd_ || |REMUW |_rs1_, _rs2_ |_rd_ || |=== .RV32A Standard Extension [%autowidth.stretch,float="center",align="center",cols="<,<,<,<,<",options="header"] |=== ||Source Registers |Destination Registers |Accumulating CSRs| |LR.W† | _rs1_ ^A^ | _rd_ | | |SC.W† | _rs1_ ^A^, _rs2_ ^D^ | _rd_ ^*^ | | ^*^ if successful |AMOSWAP.W† |_rs1_ ^A^, _rs2_ ^D^ |_rd_ | | |AMOADD.W† |_rs1_ ^A^, _rs2_ ^D^ |_rd_ | | |AMOXOR.W† |_rs1_ ^A^, _rs2_ ^D^ |_rd_ | | |AMOAND.W† |_rs1_ ^A^, _rs2_ ^D^ |_rd_ | | |AMOOR.W† |_rs1_ ^A^, _rs2_^D^ |_rd_ | | |AMOMIN.W† |_rs1_ ^A^, _rs2_ ^D^ |_rd_ | | |AMOMAX.W† |_rs1_ ^A^, _rs2_ ^D^ |_rd_ | | |AMOMINU.W† |_rs1_ ^A^, _rs2_ ^D^ |_rd_ | | |AMOMAXU.W† |_rs1_ ^A^, _rs2_ ^D^ |_rd_ | | |=== .RV64A Standard Extension [%autowidth.stretch,float="center",align="center",cols="<,<,<,<,<",options="header"] |=== | |Source Registers |Destination Registers |Accumulating CSRs| |LR.D† |_rs1_ ^A^ |_rd_ | | |SC.D† |_rs1_ ^A^, _rs2_ ^D^ |_rd_ ^*^ | |^*^if successful |AMOSWAP.D† |_rs1_ ^A^, _rs2_ ^D^ |_rd_ | | |AMOADD.D† |_rs1_ ^A^, _rs2_ ^D^ |_rd_ | | |AMOXOR.D† |_rs1_ ^A^, _rs2_ ^D^ |_rd_ | | |AMOAND.D† |_rs1_ ^A^, _rs2_^D^ |_rd_ | | |AMOOR.D† |_rs1_ ^A^, _rs2_^D^ |_rd_ | | |AMOMIN.D† |_rs1_ ^A^, _rs2_^D^ |_rd_ | | |AMOMAX.D† |_rs1_ ^A^, _rs2_^D^ |_rd_ | | |AMOMINU.D† |_rs1_ ^A^, _rs2_^D^ |_rd_ | | |AMOMAXU.D† |_rs1_ ^A^, _rs2_^D^ |_rd_ | | |=== .RV32F Standard Extension [%autowidth.stretch,float="center",align="center",cols="<,<,<,<,<",options="header"] |=== | |Source Registers |Destination Registers |Accumulating CSRs | |FLW† |_rs1_ ^A^ |_rd_ | | |FSW |_rs1_ ^A^, _rs2_^D^ | | | |FMADD.S |_rs1_, _rs2_, _rs3_, frm^*^ |_rd_ |NV, OF, UF, NX |^*^if rm=111 |FMSUB.S |_rs1_, _rs2_, _rs3_, frm^*^ |_rd_ |NV, OF, UF, NX |^*^if rm=111 |FNMSUB.S |_rs1_, _rs2_, _rs3_, frm^*^ |_rd_ |NV, OF, UF, NX |^*^if rm=111 |FNMADD.S |_rs1_, _rs2_, _rs3_, frm^*^ |_rd_ |NV, OF, UF, NX |^*^if rm=111 |FADD.S |_rs1_, _rs2_, frm^*^ |_rd_ |NV, OF, NX |^*^if rm=111 |FSUB.S |_rs1_, _rs2_, frm^*^ |_rd_ |NV, OF, NX |^*^if rm=111 |FMUL.S |_rs1_, _rs2_, frm^*^ |_rd_ |NV, OF, UF, NX |^*^if rm=111 |FDIV.S |_rs1_, _rs2_, frm^*^ |_rd_ |NV, DZ, OF, UF, NX |^*^if rm=111 |FSQRT.S |_rs1_, frm^*^ |_rd_ |NV, NX |^*^if rm=111 |FSGNJ.S |_rs1_, _rs2_ |_rd_ | | |FSGNJN.S |_rs1_, _rs2_ |_rd_ | | |FSGNJX.S |_rs1_, _rs2_ |_rd_ | | |FMIN.S |_rs1_, _rs2_ |_rd_ |NV | |FMAX.S |_rs1_, _rs2_ |_rd_ |NV | |FCVT.W.S |_rs1_, frm^*^ |_rd_ |NV, NX |^*^if rm=111 |FCVT.WU.S |_rs1_, frm^*^ |_rd_ |NV, NX |^*^if rm=111 |FMV.X.W |_rs1_ |_rd_ | | |FEQ.S |_rs1_, _rs2_ |_rd_ |NV | |FLT.S |_rs1_, _rs2_ |_rd_ |NV | |FLE.S |_rs1_, _rs2_ |_rd_ |NV | |FCLASS.S |_rs1_ |_rd_ | | |FCVT.S.W |_rs1_, frm^*^ |_rd_ |NX |^*^if rm=111 |FCVT.S.WU |_rs1_, frm^*^ |_rd_ |NX |^*^if rm=111 |FMV.W.X |_rs1_ |_rd_ | | |=== .RV64F Standard Extension [%autowidth.stretch,float="center",align="center",cols="<,<,<,<,<",options="header"] |=== | |Source Registers |Destination Registers |Accumulating CSRs| |FCVT.L.S |_rs1_, frm^*^ |_rd_ |NV, NX |^*^if rm=111 |FCVT.LU.S |_rs1_, frm^*^ |_rd_ |NV, NX |^*^if rm=111 |FCVT.S.L |_rs1_, frm^*^ |_rd_ |NX |^*^if rm=111 |FCVT.S.LU |_rs1_, frm^*^ |_rd_ |NX |^*^if rm=111 |=== .RV32D Standard Extension [%autowidth.stretch,float="center",align="center",cols="<,<,<,<,<",options="header"] |=== | |Source Registers|Destination Registers |Accumulating CSRs | |FLD† |_rs1_ ^A^ |_rd_ | | |FSD |_rs1_ ^A^, _rs2_^D^ | | | |FMADD.D |_rs1_, _rs2_, _rs3_, frm^*^ |_rd_ |NV, OF, UF, NX |^*^if rm=111 |FMSUB.D |_rs1_, _rs2_, _rs3_, frm^*^ |_rd_ |NV, OF, UF, NX |^*^if rm=111 |FNMSUB.D |_rs1_, _rs2_, _rs3_, frm^*^ |_rd_ |NV, OF, UF, NX |^*^if rm=111 |FNMADD.D |_rs1_, _rs2_, _rs3_, frm^*^ |_rd_ |NV, OF, UF, NX |^*^if rm=111 |FADD.D |_rs1_, _rs2_, frm^*^ |_rd_ |NV, OF, NX |^*^if rm=111 |FSUB.D |_rs1_, _rs2_, frm^*^ |_rd_ |NV, OF, NX |^*^if rm=111 |FMUL.D |_rs1_, _rs2_, frm^*^ |_rd_ |NV, OF, UF, NX |^*^if rm=111 |FDIV.D |_rs1_, _rs2_, frm^*^ |_rd_ |NV, DZ, OF, UF, NX |^*^if rm=111 |FSQRT.D |_rs1_, frm^*^ |_rd_ |NV, NX |^*^if rm=111 |FSGNJ.D |_rs1_, _rs2_ |_rd_ | | |FSGNJN.D |_rs1_, _rs2_ |_rd_ | | |FSGNJX.D |_rs1_, _rs2_ |_rd_ | | |FMIN.D |_rs1_, _rs2_ |_rd_ |NV | |FMAX.D |_rs1_, _rs2_ |_rd_ |NV | |FCVT.S.D |_rs1_, frm^*^ |_rd_ |NV, OF, UF, NX |^*^if rm=111 |FCVT.D.S |_rs1_ |_rd_ |NV | |FEQ.D |_rs1_, _rs2_ |_rd_ |NV | |FLT.D |_rs1_, _rs2_ |_rd_ |NV | |FLE.D |_rs1_, _rs2_ |_rd_ |NV | |FCLASS.D |_rs1_ |_rd_ | | |FCVT.W.D |_rs1_,^*^ |_rd_ |NV, NX |^*^if rm=111 |FCVT.WU.D |_rs1_, frm^*^ |_rd_ |NV, NX |^*^if rm=111 |FCVT.D.W |_rs1_ |_rd_ | | |FCVT.D.WU |_rs1_ |_rd_ | | |=== .RV64D Standard Extension [%autowidth.stretch,float="center",align="center",cols="<,<,<,<,<",options="header"] |=== | |Source Registers |Destination Registers |Accumulating CSRs | |FCVT.L.D |_rs1_, frm^*^ |_rd_ |NV, NX |^*^if rm=111 |FCVT.LU.D |_rs1_, frm^*^ |_rd_ |NV, NX |^*^if rm=111 |FMV.X.D |_rs1_ |_rd_ | | |FCVT.D.L |_rs1_, frm^*^ |_rd_ |NX |^*^if rm=111 |FCVT.D.LU |_rs1_, frm^*^ |_rd_ |NX |^*^if rm=111 |FMV.D.X |_rs1_ |_rd_ | | |===