diff --git a/backends/instructions_appendix/all_instructions.golden.adoc b/backends/instructions_appendix/all_instructions.golden.adoc index 46a78c77d..78f1c181f 100644 --- a/backends/instructions_appendix/all_instructions.golden.adoc +++ b/backends/instructions_appendix/all_instructions.golden.adoc @@ -1,6 +1,6 @@ = Instruction Appendix :doctype: book -:wavedrom: /workspace/riscv-unified-db/node_modules/.bin/wavedrom-cli +:wavedrom: /workspaces/riscv-unified-db/node_modules/.bin/wavedrom-cli // Now the document header is complete and the wavedrom attribute is active. @@ -16539,6 +16539,85 @@ Included in:: |=== +[#udb:doc:inst:pause] +== pause + +Synopsis:: +Pause hint + +Encoding:: +[wavedrom, ,svg,subs='attributes',width="100%"] +.... +{"reg":[{"bits":32,"name": 0x100000f,"type":2}]} +.... + +Description:: +The PAUSE instruction is a HINT that indicates the current hart's rate of +instruction retirement should be temporarily reduced or paused. The duration +of its effect must be bounded and may be zero. + +[NOTE] +==== +Software can use the PAUSE instruction to reduce energy consumption +while executing spin-wait code sequences. Multithreaded cores might +temporarily relinquish execution resources to other harts when PAUSE is +executed. It is recommended that a PAUSE instruction generally be +included in the code sequence for a spin-wait loop. + +A future extension might add primitives similar to the x86 MONITOR/MWAIT +instructions, which provide a more efficient mechanism to wait on writes +to a specific memory location. However, these instructions would not +supplant PAUSE. PAUSE is more appropriate when polling for non-memory +events, when polling for multiple events, or when software does not know +precisely what events it is polling for. + +The duration of a PAUSE instruction's effect may vary significantly +within and among implementations. In typical implementations this +duration should be much less than the time to perform a context switch, +probably more on the rough order of an on-chip cache miss latency or a +cacheless access to main memory. + +A series of PAUSE instructions can be used to create a cumulative delay +loosely proportional to the number of PAUSE instructions. In spin-wait +loops in portable code, however, only one PAUSE instruction should be +used before re-evaluating loop conditions, else the hart might stall +longer than optimal on some implementations, degrading system +performance. +==== + +PAUSE is encoded as a FENCE instruction with _pred_=`W`, _succ_=`0`, _fm_=`0`, +_xd_=`x0`, and _xs1_=`x0`. + +[NOTE] +==== +PAUSE is encoded as a hint within the FENCE opcode because some +implementations are expected to deliberately stall the PAUSE instruction +until outstanding memory transactions have completed. Because the +successor set is null, however, PAUSE does not _mandate_ any particular +memory ordering--hence, it truly is a HINT. + +Like other FENCE instructions, PAUSE cannot be used within LR/SC +sequences without voiding the forward-progress guarantee. + +The choice of a predecessor set of W is arbitrary, since the successor +set is null. Other HINTs similar to PAUSE might be encoded with other +predecessor sets. +==== + + +Decode Variables:: +pause has no decode variables. + +Included in:: +[options="autowrap,autowidth"] +|=== +| Extension | Version + +| *Zihintpause* | ~> 2.0.0 + +|=== + + [#udb:doc:inst:rem] == rem diff --git a/spec/std/isa/inst/I/fence.yaml b/spec/std/isa/inst/I/fence.yaml index ad67c29d0..56da57762 100644 --- a/spec/std/isa/inst/I/fence.yaml +++ b/spec/std/isa/inst/I/fence.yaml @@ -144,15 +144,6 @@ access: vs: always vu: always operation(): | - Boolean is_pause; - - if (implemented?(ExtensionName::Zihintpause)) { - if ((pred == 1) && (succ == 0) && (xd == 0) && (xs1 == 0)) { - # this is a PAUSE instruction - is_pause = true; - } - } - Boolean pred_i = pred[3] == 1; Boolean pred_o = pred[2] == 1; Boolean pred_r = pred[1] == 1; @@ -163,44 +154,38 @@ operation(): | Boolean succ_r = succ[1] == 1; Boolean succ_w = succ[0] == 1; - if (is_pause) { - pause(); - } else { - - # apply FIOM overrides - 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; } - } + # apply FIOM overrides + 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 - ); } + + fence( + pred_i, pred_o, pred_r, pred_w, + succ_i, succ_o, succ_r, succ_w + ); hints: - { $ref: inst/I/fence.tso.yaml# } + - { $ref: inst/Zihintpause/pause.yaml# } pseudoinstructions: - - when: (pred == 1) && (succ == 0) && (xd == 0) && (xs1 == 0) - to: pause - when: (pred == 4'b1111) && (succ == 4'b1111) to: fence # fence => fence iorw,iorw diff --git a/spec/std/isa/inst/Zihintpause/pause.yaml b/spec/std/isa/inst/Zihintpause/pause.yaml new file mode 100644 index 000000000..f09771f2d --- /dev/null +++ b/spec/std/isa/inst/Zihintpause/pause.yaml @@ -0,0 +1,74 @@ +# Copyright (c) Jordan Carlin +# SPDX-License-Identifier: BSD-3-Clause-Clear + +# yaml-language-server: $schema=../../../../schemas/inst_schema.json + +$schema: inst_schema.json# +kind: instruction +name: pause +long_name: Pause hint +description: | + The PAUSE instruction is a HINT that indicates the current hart's rate of + instruction retirement should be temporarily reduced or paused. The duration + of its effect must be bounded and may be zero. + + [NOTE] + ==== + Software can use the PAUSE instruction to reduce energy consumption + while executing spin-wait code sequences. Multithreaded cores might + temporarily relinquish execution resources to other harts when PAUSE is + executed. It is recommended that a PAUSE instruction generally be + included in the code sequence for a spin-wait loop. + + A future extension might add primitives similar to the x86 MONITOR/MWAIT + instructions, which provide a more efficient mechanism to wait on writes + to a specific memory location. However, these instructions would not + supplant PAUSE. PAUSE is more appropriate when polling for non-memory + events, when polling for multiple events, or when software does not know + precisely what events it is polling for. + + The duration of a PAUSE instruction's effect may vary significantly + within and among implementations. In typical implementations this + duration should be much less than the time to perform a context switch, + probably more on the rough order of an on-chip cache miss latency or a + cacheless access to main memory. + + A series of PAUSE instructions can be used to create a cumulative delay + loosely proportional to the number of PAUSE instructions. In spin-wait + loops in portable code, however, only one PAUSE instruction should be + used before re-evaluating loop conditions, else the hart might stall + longer than optimal on some implementations, degrading system + performance. + ==== + + PAUSE is encoded as a FENCE instruction with _pred_=`W`, _succ_=`0`, _fm_=`0`, + _xd_=`x0`, and _xs1_=`x0`. + + [NOTE] + ==== + PAUSE is encoded as a hint within the FENCE opcode because some + implementations are expected to deliberately stall the PAUSE instruction + until outstanding memory transactions have completed. Because the + successor set is null, however, PAUSE does not _mandate_ any particular + memory ordering--hence, it truly is a HINT. + + Like other FENCE instructions, PAUSE cannot be used within LR/SC + sequences without voiding the forward-progress guarantee. + + The choice of a predecessor set of W is arbitrary, since the successor + set is null. Other HINTs similar to PAUSE might be encoded with other + predecessor sets. + ==== + +definedBy: Zihintpause +assembly: "" +encoding: + match: "00000001000000000000000000001111" +access: + s: always + u: always + vs: always + vu: always +data_independent_timing: false +operation(): | + pause();