fence
Memory ordering fence
This instruction is defined by:
-
I, version >= 0
This instruction is included in the following profiles:
-
RVA20S64 (Mandatory)
-
RVA20U64 (Mandatory)
-
RVA22S64 (Mandatory)
-
RVA22U64 (Mandatory)
Synopsis
Orders memory operations.
The fence instruction is used to order device I/O and memory accesses as viewed by other RISC-V harts and external devices or coprocessors. Any combination of device input (I), device output (O), memory reads (R), and memory writes (W) may be ordered with respect to any combination of the same. Informally, no other RISC-V hart or external device can observe any operation in the successor set following a fence before any operation in the predecessor set preceding the fence.
The predecessor and successor fields have the same format to specify operation types:
pred |
succ |
||||||
---|---|---|---|---|---|---|---|
27 |
26 |
25 |
24 |
23 |
22 |
21 |
20 |
PI |
PO |
PR |
PW |
SI |
SO |
SR |
SW |
fm field | Mnemonic | Meaning |
---|---|---|
0000 |
none |
Normal Fence |
1000 |
TSO |
With |
other |
Reserved for future use. |
When the mode field fm is 0001
and both the predecessor and successor sets are 'RW',
then the instruction acts as a special-case fence.tso
. fence.tso
orders all load operations
in its predecessor set before all memory operations in its successor set, and all store operations
in its predecessor set before all store operations in its successor set. This leaves non-AMO store
operations in the 'fence.tso’s predecessor set unordered with non-AMO loads in its successor set.
When mode field fm is not 0001
, or when mode field fm is 0001
but the pred and
succ fields are not both 'RW' (0x3), then the fence acts as a baseline fence (e.g., fm is
effectively 0000
). This is unaffected by the FIOM bits, described below (implicit promotion does
not change how fence.tso
is decoded).
The rs1
and rd
fields are unused and ignored.
In modes other than M-mode, fence is further affected by menvcfg.FIOM, senvcfg.FIOM<% if ext?(:H) %>, and/or henvcfg.FIOM<% end %> as follows:
menvcfg.FIOM | pred.PI pred.PO succ.SI succ.SO |
→ → → → |
effective PR effective PW effective SR effective SW |
---|---|---|---|
0 |
- |
from encoding |
|
1 |
0 |
from encoding |
|
1 |
1 |
1 |
menvcfg.FIOM | senvcfg.FIOM | pred.PI pred.PO succ.SI succ.SO |
→ → → → |
effective PR effective PW effective SR effective SW |
---|---|---|---|---|
0 |
0 |
- |
from encoding |
|
0 |
1 |
0 |
from encoding |
|
0 |
1 |
1 |
1 |
|
1 |
- |
0 |
from encoding |
|
1 |
- |
1 |
1 |
<%- if ext?(:H) -%> .Effective PR/PW/SR/SW in VS-mode and VU-mode
menvcfg.FIOM | henvcfg.FIOM | pred.PI pred.PO succ.SI succ.SO |
→ → → → |
effective PR effective PW effective SR effective SW |
---|---|---|---|---|
0 |
0 |
- |
from encoding |
|
0 |
1 |
0 |
from encoding |
|
0 |
1 |
1 |
1 |
|
1 |
- |
0 |
from encoding |
|
1 |
- |
1 |
1 |
<%- end -%>
Decode Variables
Bits<4> fm = $encoding[31:28];
Bits<4> pred = $encoding[27:24];
Bits<4> succ = $encoding[23:20];
Bits<5> rs1 = $encoding[19:15];
Bits<5> rd = $encoding[11:7];
Execution
-
IDL
-
Sail
Boolean is_fence_tso;
Boolean is_pause;
if (fm == 1) {
if (pred == 0x3 && succ == 0x3) {
is_fence_tso = true;
}
}
if (implemented?(ExtensionName::Zihintpause)) {
if ((pred == 1) && (succ == 0) && (fm == 0) && (rd == 0) && (rs1 == 0)) {
is_pause = true;
}
}
Boolean pred_i = pred[3] == 1;
Boolean pred_o = pred[2] == 1;
Boolean pred_r = pred[1] == 1;
Boolean pred_w = pred[0] == 1;
Boolean succ_i = succ[3] == 1;
Boolean succ_o = succ[2] == 1;
Boolean succ_r = succ[1] == 1;
Boolean succ_w = succ[0] == 1;
if (is_fence_tso) {
fence_tso();
} else if (is_pause) {
pause();
} else {
if (mode() == PrivilegeMode::S) {
if (CSR[menvcfg].FIOM == 1) {
if (pred_i) {
pred_r = true;
}
if (pred_o) {
pred_w = true;
}
if (succ_i) {
succ_r = true;
}
if (succ_o) {
succ_w = true;
}
}
} else if (mode() == PrivilegeMode::U) {
if ((CSR[menvcfg].FIOM | CSR[senvcfg].FIOM) == 1) {
if (pred_i) {
pred_r = true;
}
if (pred_o) {
pred_w = true;
}
if (succ_i) {
succ_r = true;
}
if (succ_o) {
succ_w = true;
}
}
} else if (mode() == PrivilegeMode::VS || mode() == PrivilegeMode::VU) {
if ((CSR[menvcfg].FIOM | CSR[henvcfg].FIOM) == 1) {
if (pred_i) {
pred_r = true;
}
if (pred_o) {
pred_w = true;
}
if (succ_i) {
succ_r = true;
}
if (succ_o) {
succ_w = true;
}
}
}
fence(pred_i, pred_o, pred_r, pred_w, succ_i, succ_o, succ_r, succ_w);
}
{
// If the FIOM bit in menvcfg/senvcfg is set then the I/O bits can imply R/W.
let fiom = is_fiom_active();
let pred = effective_fence_set(pred, fiom);
let succ = effective_fence_set(succ, fiom);
match (pred, succ) {
(_ : bits(2) @ 0b11, _ : bits(2) @ 0b11) => __barrier(Barrier_RISCV_rw_rw()),
(_ : bits(2) @ 0b10, _ : bits(2) @ 0b11) => __barrier(Barrier_RISCV_r_rw()),
(_ : bits(2) @ 0b10, _ : bits(2) @ 0b10) => __barrier(Barrier_RISCV_r_r()),
(_ : bits(2) @ 0b11, _ : bits(2) @ 0b01) => __barrier(Barrier_RISCV_rw_w()),
(_ : bits(2) @ 0b01, _ : bits(2) @ 0b01) => __barrier(Barrier_RISCV_w_w()),
(_ : bits(2) @ 0b01, _ : bits(2) @ 0b11) => __barrier(Barrier_RISCV_w_rw()),
(_ : bits(2) @ 0b11, _ : bits(2) @ 0b10) => __barrier(Barrier_RISCV_rw_r()),
(_ : bits(2) @ 0b10, _ : bits(2) @ 0b01) => __barrier(Barrier_RISCV_r_w()),
(_ : bits(2) @ 0b01, _ : bits(2) @ 0b10) => __barrier(Barrier_RISCV_w_r()),
(_ : bits(4) , _ : bits(2) @ 0b00) => (),
(_ : bits(2) @ 0b00, _ : bits(4) ) => (),
_ => { print("FIXME: unsupported fence");
() }
};
RETIRE_SUCCESS
}