fence

Memory ordering fence

This instruction is defined by:

  • I, version >= 0

This instruction is included in the following profiles:

  • MockProfile 64-bit Unpriv (Mandatory)

  • MockProfile 64-bit S-mode (Mandatory)

  • RVA20U64 (Mandatory)

  • RVA22U64 (Mandatory)

  • RVI20U32 (Mandatory)

  • RVI20U64 (Mandatory)

Encoding

svg

Assembly format

fence TODO

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

Table 1. Fence mode encoding
fm field Mnemonic Meaning

0000

none

Normal Fence

1000

TSO

With FENCE RW,RW: exclude write-to-read ordering; otherwise: Reserved for future use.

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:

Table 2. Effective PR/PW/SR/SW in (H)S-mode
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

Table 3. Effective PR/PW/SR/SW in U-mode
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 -%>

Access

M HS U VS VU

Always

Always

Always

Always

Always

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
}