Functions
implemented? (builtin)
Return true if the implementation supports extension
.
Return Type |
|
---|---|
Arguments |
|
unpredictable (builtin)
Indicate that the hart has reached a state that is unpredictable because the RISC-V spec allows multiple behaviors. Generally, this will be a fatal condition to any emulation, since it is unclear what to do next.
The single argument why is a string describing why the hart entered an unpredictable state.
Return Type |
|
---|---|
Arguments |
|
read_hpm_counter (builtin)
Returns the value of hpmcounterN.
N must be between 3..31.
hpmcounterN must be implemented.
Return Type |
|
---|---|
Arguments |
|
hartid (builtin)
Returns the value for mhartid as seen by this hart.
Must obey the rules of the priv spec:
The mhartid CSR is an MXLEN-bit read-only register containing the integer ID of the hardware thread running the code. This register must be readable in any implementation. Hart IDs might not necessarily be numbered contiguously in a multiprocessor system, but at least one hart must have a hart ID of zero. Hart IDs must be unique within the execution environment.
Return Type |
|
---|---|
Arguments |
None |
read_mcycle (builtin)
Return the current value of the cycle counter.
Return Type |
|
---|---|
Arguments |
None |
read_mtime (builtin)
Return the current value of the real time device.
Return Type |
|
---|---|
Arguments |
None |
sw_write_mcycle (builtin)
Given a value that software is trying to write into mcycle, perform the write and return the value that will actually be written.
Return Type |
|
---|---|
Arguments |
|
cache_block_zero (builtin)
Zero the cache block at the given physical address.
The cache block may be zeroed using 1 or more writes.
A cache-block-sized region is zeroed regardless of whether or not the memory is in a cacheable PMA region.
Return Type |
|
---|---|
Arguments |
|
eei_ecall_from_m (builtin)
When TRAP_ON_ECALL_FROM_M is false, this function will be called to emulate the EEI handling of ECALL-from-M.
If TRAP_ON_ECALL_FROM_M is true, this function will never be called, and does not need to be provided (if pruning is applied to IDL).
Return Type |
|
---|---|
Arguments |
None |
eei_ecall_from_s (builtin)
When TRAP_ON_ECALL_FROM_S is false, this function will be called to emulate the EEI handling of ECALL-from-S.
If TRAP_ON_ECALL_FROM_S is true, this function will never be called, and does not need to be provided (if pruning is applied to IDL).
Return Type |
|
---|---|
Arguments |
None |
eei_ecall_from_u (builtin)
When TRAP_ON_ECALL_FROM_U is false, this function will be called to emulate the EEI handling of ECALL-from-U.
If TRAP_ON_ECALL_FROM_U is true, this function will never be called, and does not need to be provided (if pruning is applied to IDL).
Return Type |
|
---|---|
Arguments |
None |
eei_ecall_from_vs (builtin)
When TRAP_ON_ECALL_FROM_VS is false, this function will be called to emulate the EEI handling of ECALL-from-VS.
If TRAP_ON_ECALL_FROM_VS is true, this function will never be called, and does not need to be provided (if pruning is applied to IDL).
Return Type |
|
---|---|
Arguments |
None |
eei_ebreak (builtin)
When TRAP_ON_EBREAK is false, this function will be called to emulate the EEI handling of EBREAK
If TRAP_ON_EBREAK is true, this function will never be called, and does not need to be provided (if pruning is applied to IDL).
Return Type |
|
---|---|
Arguments |
None |
memory_model_acquire (builtin)
Perform an acquire; that is, ensure that no subsequent operation in program order appears to an external observer to occur after the operation calling this function.
Return Type |
|
---|---|
Arguments |
None |
memory_model_release (builtin)
Perform a release; that is, ensure that no prior store in program order can be observed external to this hart after this function returns.
Return Type |
|
---|---|
Arguments |
None |
assert (builtin)
Assert that a condition is true. Failure represents an error in the IDL model.
Return Type |
|
---|---|
Arguments |
|
notify_mode_change (builtin)
Called whenever the privilege mode changes. Downstream tools can use this to hook events.
Return Type |
|
---|---|
Arguments |
|
abort_current_instruction (builtin)
Abort the current instruction, and start refetching from $pc.
Return Type |
|
---|---|
Arguments |
None |
zext (builtin)
Zero extend value
starting at first_extended_bit
.
Bits [XLEN-1
:`first_extended_bit`] of the return value
should get the value 0
;
Return Type |
|
---|---|
Arguments |
|
ebreak (builtin)
Raise an Environment Break
exception, returning control to the debug environment.
Return Type |
|
---|---|
Arguments |
None |
saturate (builtin)
If unsigned value
is less than max_value
, return value
.
Otherwise, return max_value
.
Return Type |
|
---|---|
Arguments |
|
prefetch_instruction (builtin)
Hint to prefetch a block containing virtual_address for an upcoming fetch.
Return Type |
|
---|---|
Arguments |
|
prefetch_read (builtin)
Hint to prefetch a block containing virtual_address for an upcoming load.
Return Type |
|
---|---|
Arguments |
|
prefetch_write (builtin)
Hint to prefetch a block containing virtual_address for an upcoming store.
Return Type |
|
---|---|
Arguments |
|
fence (builtin)
Execute a memory ordering fence.(according to the FENCE instruction).
Return Type |
|
---|---|
Arguments |
|
fence_tso (builtin)
Execute a TSO memory ordering fence.(according to the FENCE instruction).
Return Type |
|
---|---|
Arguments |
None |
ifence (builtin)
Execute a memory ordering instruction fence (according to FENCE.I).
Return Type |
|
---|---|
Arguments |
None |
pause (builtin)
Pause hart retirement for a implementation-defined period of time, which may be zero.
See Zihintpause for more.
Return Type |
|
---|---|
Arguments |
None |
pow (builtin)
Return value
to the power exponent
.
Return Type |
|
---|---|
Arguments |
|
maybe_cache_translation (builtin)
Given a translation result, potentially cache the result for later use. This function models a TLB fill operation. A valid implementation does nothing.
Return Type |
|
---|---|
Arguments |
|
cached_translation (builtin)
Possibly returns a cached translation result matching vaddr.
If the result is value, the first return value will be true. paddr is the full translation of vaddr, including the page offset pbmt is the result of any paged-based attributes for the translation
Return Type |
|
---|---|
Arguments |
|
order_pgtbl_writes_before_vmafence (builtin)
Orders all writes prior to this call in global memory order that affect a page table in the set identified by order_type before any subsequent sfence.vma/hfence.vma/sinval.vma/hinval.gvma/hinval.vvma in program order.
Performs the ordering function of SFENCE.VMA/HFENCE.[GV]VMA/SFENCE.W.INVAL.
A valid implementation does nothing if address caching is not used.
Return Type |
|
---|---|
Arguments |
|
order_pgtbl_reads_after_vmafence (builtin)
Orders all reads after to this call in global memory order to a page table in the set identified by order_type after any prior sfence.vma/hfence.vma/sinval.vma/hinval.gvma/hinval.vvma in program order.
Performs the ordering function of SFENCE.VMA/HFENCE.[GV]VMA/SFENCE.INVAL.IR.
A valid implementation does nothing if address caching is not used.
Return Type |
|
---|---|
Arguments |
|
invalidate_translations (builtin)
Locally invalidate the cached S-mode/VS-mode/G-stage address translations contained in the set identified by inval_type.
A valid implementation does nothing if address caching is not used.
Return Type |
|
---|---|
Arguments |
|
read_physical_memory (builtin)
Read from physical memory.
Return Type |
|
---|---|
Arguments |
|
write_physical_memory (builtin)
Write to physical memory.
Return Type |
|
---|---|
Arguments |
|
wfi (builtin)
Wait-for-interrupt: hint that the processor should enter a low power state until the next interrupt.
A valid implementation is a no-op.
The model will advance the PC; this function does not need to.
Return Type |
|
---|---|
Arguments |
None |
pma_applies? (builtin)
Checks if attr is applied to the entire physical address region between [paddr, paddr + len) based on static PMA attributes.
Return Type |
|
---|---|
Arguments |
|
atomic_check_then_write_32 (builtin)
Atomically:
-
Reads 32-bits from paddr
-
Compares the read value to compare_value
-
Writes write_value to paddr if the comparison was bitwise-equal
returns true if the write occurs, and false otherwise
Preconditions:
-
paddr will be aligned to 32-bits
Return Type |
|
---|---|
Arguments |
|
atomic_check_then_write_64 (builtin)
Atomically:
-
Reads 64-bits from paddr
-
Compares the read value to compare_value
-
Writes write_value to paddr if the comparison was bitwise-equal
returns true if the write occurs, and false otherwise
Preconditions:
-
paddr will be aligned to 64-bits
Return Type |
|
---|---|
Arguments |
|
atomically_set_pte_a (builtin)
Atomically:
-
Reads the pte_len value at pte_addr
-
If the read value does not exactly equal pte_value, returns false
-
-
Sets the 'A' bit and writes the result to pte_addr
-
return true
Preconditions:
-
pte_addr will be aligned to 64-bits
Return Type |
|
---|---|
Arguments |
|
atomically_set_pte_a_d (builtin)
Atomically:
-
Reads the pte_len value at pte_addr
-
If the read value does not exactly equal pte_value, returns false
-
-
Sets the 'A' and 'D' bits and writes the result to pte_addr
-
return true
Preconditions:
-
pte_addr will be aligned to 64-bits
Return Type |
|
---|---|
Arguments |
|
atomic_read_modify_write_32 (builtin)
Atomically read-modify-write 32-bits starting at phys_address using value and op.
Return the original (unmodified) read value.
All access checks/alignment checks/etc. should be done before calling this function; it’s assumed the RMW is OK to proceed.
Return Type |
|
---|---|
Arguments |
|
atomic_read_modify_write_64 (builtin)
Atomically read-modify-write 64-bits starting at phys_address using value and op.
Return the original (unmodified) read value.
All access checks/alignment checks/etc. should be done before calling this function; it’s assumed the RMW is OK to proceed.
Return Type |
|
---|---|
Arguments |
|
power_of_2?
Returns true if value is a power of two, false otherwise
Return Type |
|
---|---|
Arguments |
|
return (value != 0) && value & (value - 1 == 0);
ary_includes?
Returns true if value is an element of ary, and false otherwise
Return Type |
|
---|---|
Arguments |
|
for (U32 i = 0; i < ARY_SIZE; i++) {
if (ary[i] == value) {
return true;
}
}
return false;
has_virt_mem?
Returns true if some virtual memory translation (Sv*) is supported in the config.
Return Type |
|
---|---|
Arguments |
None |
return implemented?(ExtensionName::Sv32) || implemented?(ExtensionName::Sv39) || implemented?(ExtensionName::Sv48) || implemented?(ExtensionName::Sv57);
highest_set_bit
Returns the position of the highest (nearest MSB) bit that is '1', or -1 if value is zero.
Return Type |
|
---|---|
Arguments |
|
for (U32 i = xlen() - 1; i >= 0; i--) {
if (value[i] == 1) {
return i;
}
}
return -'sd1;
count_leading_zeros
Returns the number of leading 0 bits before the most-significant 1 bit of value, or N if value is zero.
Return Type |
|
---|---|
Arguments |
|
for (U32 i = 0; i < N; i++) {
if (value[N - 1 - i] == 1) {
return i;
}
}
return N;
sext
Sign extend value
starting at first_extended_bit
.
Bits [XLEN-1
:`first_extended_bit`] of the return value
should get the value of bit (first_extended bit - 1
).
Return Type |
|
---|---|
Arguments |
|
if (first_extended_bit == XLEN) {
return value;
} else {
Bits<1> sign = value[first_extended_bit - 1];
for (U32 i = XLEN - 1; i >= first_extended_bit; i--) {
value[i] = sign;
}
return value;
}
bit_length
Returns the minimum number of bits needed to represent value.
Only works on unsigned values.
The value 0 returns 1.
Return Type |
|
---|---|
Arguments |
|
for (XReg i = 63; i > 0; i--) {
if (value[i] == 1) {
return i;
}
}
return 1;
is_naturally_aligned
Checks if value is naturally aligned to N bits.
Return Type |
|
---|---|
Arguments |
|
return true if (N == 8);
XReg Mask = (N / 8) - 1;
return (value & ~Mask) == value;
in_naturally_aligned_region?
Checks if a length-bit access starting at address lies entirely within an N-bit naturally-aligned region.
Return Type |
|
---|---|
Arguments |
|
XReg Mask = (N / 8) - 1;
return (address & ~Mask) == ((address + length - 1) & ~Mask);
contains?
Given a region defined by region_start, region_size, determine if a target defined by target_start, target_size is completely contained with the region.
Return Type |
|
---|---|
Arguments |
|
return target_start >= region_start && (target_start + target_size) <= (region_start + region_size);
set_fp_flag
Add flag to the sticky flags bits in CSR[fcsr]
Return Type |
|
---|---|
Arguments |
|
if (flag == FpFlag::NX) {
CSR[fcsr].NX = 1;
} else if (flag == FpFlag::UF) {
CSR[fcsr].UF = 1;
} else if (flag == FpFlag::OF) {
CSR[fcsr].OF = 1;
} else if (flag == FpFlag::DZ) {
CSR[fcsr].DZ = 1;
} else if (flag == FpFlag::NV) {
CSR[fcsr].NV = 1;
}
rm_to_mode
Convert rm to a RoundingMode.
encoding is the full encoding of the instruction rm comes from.
Will raise an IllegalInstruction exception if rm is a reserved encoding.
Return Type |
|
---|---|
Arguments |
|
if (rm == $bits(RoundingMode::RNE)) {
return RoundingMode::RNE;
} else if (rm == $bits(RoundingMode::RTZ)) {
return RoundingMode::RTZ;
} else if (rm == $bits(RoundingMode::RDN)) {
return RoundingMode::RDN;
} else if (rm == $bits(RoundingMode::RUP)) {
return RoundingMode::RUP;
} else if (rm == $bits(RoundingMode::RMM)) {
return RoundingMode::RMM;
} else if (rm == $bits(RoundingMode::DYN)) {
return CSR[fcsr].FRM;
} else {
raise(ExceptionCode::IllegalInstruction, mode(), encoding);
}
mark_f_state_dirty
Potentially updates mstatus.FS to the Dirty (3) state, depending on configuration settings.
Return Type |
|
---|---|
Arguments |
None |
if (HW_MSTATUS_FS_DIRTY_UPDATE == "precise") {
CSR[mstatus].FS = 3;
} else if (HW_MSTATUS_FS_DIRTY_UPDATE == "imprecise") {
unpredictable("The hart may or may not update mstatus.FS now");
}
nan_box
Produces a properly NaN-boxed floating-point value from a floating-point value of smaller size by adding all 1’s to the upper bits.
Return Type |
|
---|---|
Arguments |
|
assert(FROM_SIZE < TO_SIZE, "Bad template arugments; FROM_SIZE must be less than TO_SIZE");
return {{TO_SIZE - FROM_SIZE{1'b1}}, from_value};
check_f_ok
Checks if instructions from the F extension can be executed, and, if not, raise an exception.
Return Type |
|
---|---|
Arguments |
|
is_sp_neg_inf?
Return true if sp_value is negative infinity.
Return Type |
|
---|---|
Arguments |
|
return sp_value == SP_NEG_INF;
is_sp_pos_inf?
Return true if sp_value is positive infinity.
Return Type |
|
---|---|
Arguments |
|
return sp_value == SP_POS_INF;
is_sp_neg_norm?
Returns true if sp_value is a negative normal number.
Return Type |
|
---|---|
Arguments |
|
return (sp_value[31] == 1) && (sp_value[30:23] != 0b11111111) && !((sp_value[30:23] == 0b00000000) && sp_value[22:0] != 0);
is_sp_pos_norm?
Returns true if sp_value is a positive normal number.
Return Type |
|
---|---|
Arguments |
|
return (sp_value[31] == 0) && (sp_value[30:23] != 0b11111111) && !((sp_value[30:23] == 0b00000000) && sp_value[22:0] != 0);
is_sp_neg_subnorm?
Returns true if sp_value is a negative subnormal number.
Return Type |
|
---|---|
Arguments |
|
return (sp_value[31] == 1) && (sp_value[30:23] == 0) && (sp_value[22:0] != 0);
is_sp_pos_subnorm?
Returns true if sp_value is a positive subnormal number.
Return Type |
|
---|---|
Arguments |
|
return (sp_value[31] == 0) && (sp_value[30:23] == 0) && (sp_value[22:0] != 0);
is_sp_neg_zero?
Returns true if sp_value is negative zero.
Return Type |
|
---|---|
Arguments |
|
return sp_value == SP_NEG_ZERO;
is_sp_pos_zero?
Returns true if sp_value is positive zero.
Return Type |
|
---|---|
Arguments |
|
return sp_value == SP_POS_ZERO;
is_sp_nan?
Returns true if sp_value is a NaN (quiet or signaling)
Return Type |
|
---|---|
Arguments |
|
return (sp_value[30:23] == 0b11111111) && (sp_value[22:0] != 0);
is_sp_signaling_nan?
Returns true if sp_value is a signaling NaN
Return Type |
|
---|---|
Arguments |
|
return (sp_value[30:23] == 0b11111111) && (sp_value[22] == 0) && (sp_value[21:0] != 0);
is_sp_quiet_nan?
Returns true if sp_value is a quiet NaN
Return Type |
|
---|---|
Arguments |
|
return (sp_value[30:23] == 0b11111111) && (sp_value[22] == 1);
softfloat_shiftRightJam32
Shifts a right by the number of bits given in dist, which must not be zero. If any nonzero bits are shifted off, they are "jammed" into the least-significant bit of the shifted value by setting the least-significant bit to 1. This shifted-and-jammed value is returned. The value of dist can be arbitrarily large. In particular, if dist is greater than 32, the result will be either 0 or 1, depending on whether a is zero or nonzero.
Return Type |
|
---|---|
Arguments |
|
return (dist < 31) ? a >> dist | (a << (-dist & 31 != 0) ? 1 : 0) : ((a != 0) ? 1 : 0);
softfloat_shiftRightJam64
Shifts a right by the number of bits given in dist, which must not be zero. If any nonzero bits are shifted off, they are "jammed" into the least-significant bit of the shifted value by setting the least-significant bit to 1. This shifted-and-jammed value is returned.
The value of 'dist' can be arbitrarily large. In particular, if dist is greater than 64, the result will be either 0 or 1, depending on whether a is zero or nonzero.
Return Type |
|
---|---|
Arguments |
|
return (dist < 63) ? a >> dist | (a << (-dist & 63 != 0) ? 1 : 0) : ((a != 0) ? 1 : 0);
softfloat_roundToI32
Round to unsigned 32-bit integer, using rounding_mode
Return Type |
|
---|---|
Arguments |
|
Bits<16> roundIncrement = 0x800;
if ((roundingMode != RoundingMode::RMM) && (roundingMode != RoundingMode::RNE)) {
roundIncrement = 0;
if (sign == 1 ? (roundingMode == RoundingMode::RDN) : (roundingMode == RoundingMode::RUP)) {
roundIncrement = 0xFFF;
}
}
Bits<16> roundBits = sig & 0xFFF;
sig = sig + roundIncrement;
if ((sig & 0xFFFFF00000000000) != 0) {
set_fp_flag(FpFlag::NV);
return sign == 1 ? WORD_NEG_OVERFLOW : WORD_POS_OVERFLOW;
}
Bits<32> sig32 = sig >> 12;
if ((roundBits == 0x800 && (roundingMode == RoundingMode::RNE))) {
sig32 = sig32 & ~32'b1;
}
Bits<32> z = (sign == 1) ? -sig32 : sig32;
if ((z != 0) && $signed(z) < 0) != (sign == 1) {
set_fp_flag(FpFlag::NV);
return sign == 1 ? WORD_NEG_OVERFLOW : WORD_POS_OVERFLOW;
}
if (roundBits != 0) {
set_fp_flag(FpFlag::NX);
}
return z;
packToF32UI
Pack components into a 32-bit value
Return Type |
|
---|---|
Arguments |
|
return {sign, exp, sig};
packToF16UI
Pack components into a 16-bit value
Return Type |
|
---|---|
Arguments |
|
return {sign, exp, sig};
softfloat_normSubnormalF16Sig
normalize subnormal half-precision value
Return Type |
|
---|---|
Arguments |
|
Bits<8> shift_dist = count_leading_zeros<16>(hp_value);
return {1 - shift_dist, hp_value << shift_dist};
softfloat_normRoundPackToF32
Normalize, round, and pack into a 32-bit floating point value
Return Type |
|
---|---|
Arguments |
|
Bits<8> shiftDist = count_leading_zeros<32>(sig) - 1;
exp = exp - shiftDist;
if ((7 <= shiftDist) && (exp < 0xFD)) {
return packToF32UI(sign, (sig != 0) ? exp : 0, sig << (shiftDist - 7));
} else {
return softfloat_roundPackToF32(sign, exp, sig << shiftDist, mode);
}
softfloat_roundPackToF32
Round FP value according to mdode and then pack it in IEEE format.
Return Type |
|
---|---|
Arguments |
|
Bits<8> roundIncrement = 0x40;
if ((mode != RoundingMode::RNE) && (mode != RoundingMode::RMM)) {
roundIncrement = (mode == sign != 0) ? RoundingMode::RDN : RoundingMode::RUP ? 0x7F : 0;
}
Bits<8> roundBits = sig & 0x7f;
if (0xFD <= exp) {
if ($signed(exp) < 0) {
Boolean isTiny = ($signed(exp) < -8's1) || (sig + roundIncrement < 0x80000000);
sig = softfloat_shiftRightJam32(sig, -exp);
exp = 0;
roundBits = sig & 0x7F;
if (isTiny && (roundBits != 0)) {
set_fp_flag(FpFlag::UF);
}
} else if (0xFD < $signed(exp) || (0x80000000 <= sig + roundIncrement)) {
set_fp_flag(FpFlag::OF);
set_fp_flag(FpFlag::NX);
return packToF32UI(sign, 0xFF, 0) - roundIncrement == 0) ? 1 : 0); } } sig = (sig + roundIncrement);
if (sig == 0) {
exp = 0;
}
return packToF32UI(sign, exp, sig);
mode
Returns the current active privilege mode.
Return Type |
|
---|---|
Arguments |
None |
if (!implemented?(ExtensionName::S) && !implemented?(ExtensionName::U) && !implemented?(ExtensionName::H)) {
return PrivilegeMode::M;
} else {
return current_mode;
}
set_mode
Set the current privilege mode to new_mode
Return Type |
|
---|---|
Arguments |
|
if (new_mode != current_mode) {
notify_mode_change(new_mode, current_mode);
current_mode = new_mode;
}
exception_handling_mode
Returns the target privilege mode that will handle synchronous exception exception_code
Return Type |
|
---|---|
Arguments |
|
if (mode() == PrivilegeMode::M) {
return PrivilegeMode::M;
} else if (implemented?(ExtensionName::S) && mode() == PrivilegeMode::HS) || (mode() == PrivilegeMode::U) {
if (($bits(CSR[medeleg]) & (1 << $bits(exception_code))) != 0) {
return PrivilegeMode::HS;
} else {
return PrivilegeMode::M;
}
} else {
assert(implemented?(ExtensionName::H) && mode() == PrivilegeMode::VS) || (mode() == PrivilegeMode::VU, "Unexpected mode");
if (($bits(CSR[medeleg]) & (1 << $bits(exception_code))) != 0) {
if (($bits(CSR[hedeleg]) & (1 << $bits(exception_code))) != 0) {
return PrivilegeMode::VS;
} else {
return PrivilegeMode::HS;
}
} else {
return PrivilegeMode::M;
}
}
unimplemented_csr
Either raises an IllegalInstruction exception or enters unpredictable state, depending on the setting of the TRAP_ON_UNIMPLEMENTED_CSR parameter.
Return Type |
|
---|---|
Arguments |
|
if (TRAP_ON_UNIMPLEMENTED_CSR) {
raise(ExceptionCode::IllegalInstruction, mode(), encoding);
} else {
unpredictable("Accessing an unimplmented CSR");
}
mtval_readonly?
Returns whether or not CSR[mtval] is read-only based on implementation options
Return Type |
|
---|---|
Arguments |
None |
return !(REPORT_VA_IN_MTVAL_ON_BREAKPOINT || REPORT_VA_IN_MTVAL_ON_LOAD_MISALIGNED || REPORT_VA_IN_MTVAL_ON_STORE_AMO_MISALIGNED || REPORT_VA_IN_MTVAL_ON_INSTRUCTION_MISALIGNED || REPORT_VA_IN_MTVAL_ON_LOAD_ACCESS_FAULT || REPORT_VA_IN_MTVAL_ON_STORE_AMO_ACCESS_FAULT || REPORT_VA_IN_MTVAL_ON_INSTRUCTION_ACCESS_FAULT || REPORT_VA_IN_MTVAL_ON_LOAD_PAGE_FAULT || REPORT_VA_IN_MTVAL_ON_STORE_AMO_PAGE_FAULT || REPORT_VA_IN_MTVAL_ON_INSTRUCTION_PAGE_FAULT || REPORT_ENCODING_IN_MTVAL_ON_ILLEGAL_INSTRUCTION || REPORT_CAUSE_IN_MTVAL_ON_SHADOW_STACK_SOFTWARE_CHECK || REPORT_CAUSE_IN_MTVAL_ON_LANDING_PAD_SOFTWARE_CHECK);
stval_readonly?
Returns whether or not CSR[stval] is read-only based on implementation options
Return Type |
|
---|---|
Arguments |
None |
if (implemented?(ExtensionName::S)) {
return !(REPORT_VA_IN_STVAL_ON_BREAKPOINT || REPORT_VA_IN_STVAL_ON_LOAD_MISALIGNED || REPORT_VA_IN_STVAL_ON_STORE_AMO_MISALIGNED || REPORT_VA_IN_STVAL_ON_INSTRUCTION_MISALIGNED || REPORT_VA_IN_STVAL_ON_LOAD_ACCESS_FAULT || REPORT_VA_IN_STVAL_ON_STORE_AMO_ACCESS_FAULT || REPORT_VA_IN_STVAL_ON_INSTRUCTION_ACCESS_FAULT || REPORT_VA_IN_STVAL_ON_LOAD_PAGE_FAULT || REPORT_VA_IN_STVAL_ON_STORE_AMO_PAGE_FAULT || REPORT_VA_IN_STVAL_ON_INSTRUCTION_PAGE_FAULT || REPORT_ENCODING_IN_STVAL_ON_ILLEGAL_INSTRUCTION || REPORT_CAUSE_IN_STVAL_ON_SHADOW_STACK_SOFTWARE_CHECK || REPORT_CAUSE_IN_STVAL_ON_LANDING_PAD_SOFTWARE_CHECK);
} else {
return true;
}
vstval_readonly?
Returns whether or not CSR[vstval] is read-only based on implementation options
Return Type |
|
---|---|
Arguments |
None |
if (implemented?(ExtensionName::H)) {
return !(REPORT_VA_IN_VSTVAL_ON_BREAKPOINT || REPORT_VA_IN_VSTVAL_ON_LOAD_MISALIGNED || REPORT_VA_IN_VSTVAL_ON_STORE_AMO_MISALIGNED || REPORT_VA_IN_VSTVAL_ON_INSTRUCTION_MISALIGNED || REPORT_VA_IN_VSTVAL_ON_LOAD_ACCESS_FAULT || REPORT_VA_IN_VSTVAL_ON_STORE_AMO_ACCESS_FAULT || REPORT_VA_IN_VSTVAL_ON_INSTRUCTION_ACCESS_FAULT || REPORT_VA_IN_VSTVAL_ON_LOAD_PAGE_FAULT || REPORT_VA_IN_VSTVAL_ON_STORE_AMO_PAGE_FAULT || REPORT_VA_IN_VSTVAL_ON_INSTRUCTION_PAGE_FAULT || REPORT_ENCODING_IN_VSTVAL_ON_ILLEGAL_INSTRUCTION || REPORT_CAUSE_IN_VSTVAL_ON_SHADOW_STACK_SOFTWARE_CHECK || REPORT_CAUSE_IN_VSTVAL_ON_LANDING_PAD_SOFTWARE_CHECK);
} else {
return true;
}
mtval_for
Given an exception code and a legal non-zero value for mtval, returns the value to be written in mtval considering implementation options
Return Type |
|
---|---|
Arguments |
|
if (exception_code == ExceptionCode::Breakpoint) {
return REPORT_VA_IN_MTVAL_ON_BREAKPOINT ? tval : 0;
} else if (exception_code == ExceptionCode::LoadAddressMisaligned) {
return REPORT_VA_IN_MTVAL_ON_LOAD_MISALIGNED ? tval : 0;
} else if (exception_code == ExceptionCode::StoreAmoAddressMisaligned) {
return REPORT_VA_IN_MTVAL_ON_STORE_AMO_MISALIGNED ? tval : 0;
} else if (exception_code == ExceptionCode::InstructionAddressMisaligned) {
return REPORT_VA_IN_MTVAL_ON_INSTRUCTION_MISALIGNED ? tval : 0;
} else if (exception_code == ExceptionCode::LoadAccessFault) {
return REPORT_VA_IN_MTVAL_ON_LOAD_ACCESS_FAULT ? tval : 0;
} else if (exception_code == ExceptionCode::StoreAmoAccessFault) {
return REPORT_VA_IN_MTVAL_ON_STORE_AMO_ACCESS_FAULT ? tval : 0;
} else if (exception_code == ExceptionCode::InstructionAccessFault) {
return REPORT_VA_IN_MTVAL_ON_INSTRUCTION_ACCESS_FAULT ? tval : 0;
} else if (exception_code == ExceptionCode::LoadPageFault) {
return REPORT_VA_IN_MTVAL_ON_LOAD_PAGE_FAULT ? tval : 0;
} else if (exception_code == ExceptionCode::StoreAmoPageFault) {
return REPORT_VA_IN_MTVAL_ON_STORE_AMO_PAGE_FAULT ? tval : 0;
} else if (exception_code == ExceptionCode::InstructionPageFault) {
return REPORT_VA_IN_MTVAL_ON_INSTRUCTION_PAGE_FAULT ? tval : 0;
} else if (exception_code == ExceptionCode::IllegalInstruction) {
return REPORT_ENCODING_IN_MTVAL_ON_ILLEGAL_INSTRUCTION ? tval : 0;
} else if (exception_code == ExceptionCode::SoftwareCheck) {
return tval;
} else {
return 0;
}
stval_for
Given an exception code and a legal non-zero value for stval, returns the value to be written in stval considering implementation options
Return Type |
|
---|---|
Arguments |
|
if (exception_code == ExceptionCode::Breakpoint) {
return REPORT_VA_IN_STVAL_ON_BREAKPOINT ? tval : 0;
} else if (exception_code == ExceptionCode::LoadAddressMisaligned) {
return REPORT_VA_IN_STVAL_ON_LOAD_MISALIGNED ? tval : 0;
} else if (exception_code == ExceptionCode::StoreAmoAddressMisaligned) {
return REPORT_VA_IN_STVAL_ON_STORE_AMO_MISALIGNED ? tval : 0;
} else if (exception_code == ExceptionCode::InstructionAddressMisaligned) {
return REPORT_VA_IN_STVAL_ON_INSTRUCTION_MISALIGNED ? tval : 0;
} else if (exception_code == ExceptionCode::LoadAccessFault) {
return REPORT_VA_IN_STVAL_ON_LOAD_ACCESS_FAULT ? tval : 0;
} else if (exception_code == ExceptionCode::StoreAmoAccessFault) {
return REPORT_VA_IN_STVAL_ON_STORE_AMO_ACCESS_FAULT ? tval : 0;
} else if (exception_code == ExceptionCode::InstructionAccessFault) {
return REPORT_VA_IN_STVAL_ON_INSTRUCTION_ACCESS_FAULT ? tval : 0;
} else if (exception_code == ExceptionCode::LoadPageFault) {
return REPORT_VA_IN_STVAL_ON_LOAD_PAGE_FAULT ? tval : 0;
} else if (exception_code == ExceptionCode::StoreAmoPageFault) {
return REPORT_VA_IN_STVAL_ON_STORE_AMO_PAGE_FAULT ? tval : 0;
} else if (exception_code == ExceptionCode::InstructionPageFault) {
return REPORT_VA_IN_STVAL_ON_INSTRUCTION_PAGE_FAULT ? tval : 0;
} else if (exception_code == ExceptionCode::IllegalInstruction) {
return REPORT_ENCODING_IN_STVAL_ON_ILLEGAL_INSTRUCTION ? tval : 0;
} else if (exception_code == ExceptionCode::SoftwareCheck) {
return tval;
} else {
return 0;
}
vstval_for
Given an exception code and a legal non-zero value for vstval, returns the value to be written in vstval considering implementation options
Return Type |
|
---|---|
Arguments |
|
if (exception_code == ExceptionCode::Breakpoint) {
return REPORT_VA_IN_VSTVAL_ON_BREAKPOINT ? tval : 0;
} else if (exception_code == ExceptionCode::LoadAddressMisaligned) {
return REPORT_VA_IN_VSTVAL_ON_LOAD_MISALIGNED ? tval : 0;
} else if (exception_code == ExceptionCode::StoreAmoAddressMisaligned) {
return REPORT_VA_IN_VSTVAL_ON_STORE_AMO_MISALIGNED ? tval : 0;
} else if (exception_code == ExceptionCode::InstructionAddressMisaligned) {
return REPORT_VA_IN_VSTVAL_ON_INSTRUCTION_MISALIGNED ? tval : 0;
} else if (exception_code == ExceptionCode::LoadAccessFault) {
return REPORT_VA_IN_VSTVAL_ON_LOAD_ACCESS_FAULT ? tval : 0;
} else if (exception_code == ExceptionCode::StoreAmoAccessFault) {
return REPORT_VA_IN_VSTVAL_ON_STORE_AMO_ACCESS_FAULT ? tval : 0;
} else if (exception_code == ExceptionCode::InstructionAccessFault) {
return REPORT_VA_IN_VSTVAL_ON_INSTRUCTION_ACCESS_FAULT ? tval : 0;
} else if (exception_code == ExceptionCode::LoadPageFault) {
return REPORT_VA_IN_VSTVAL_ON_LOAD_PAGE_FAULT ? tval : 0;
} else if (exception_code == ExceptionCode::StoreAmoPageFault) {
return REPORT_VA_IN_VSTVAL_ON_STORE_AMO_PAGE_FAULT ? tval : 0;
} else if (exception_code == ExceptionCode::InstructionPageFault) {
return REPORT_VA_IN_VSTVAL_ON_INSTRUCTION_PAGE_FAULT ? tval : 0;
} else if (exception_code == ExceptionCode::IllegalInstruction) {
return REPORT_ENCODING_IN_VSTVAL_ON_ILLEGAL_INSTRUCTION ? tval : 0;
} else if (exception_code == ExceptionCode::SoftwareCheck) {
return tval;
} else {
return 0;
}
raise_guest_page_fault
Raise a guest page fault exception.
Return Type |
|
---|---|
Arguments |
|
ExceptionCode code;
Boolean write_gpa_in_tval;
if (op == MemoryOperation::Read) {
code = ExceptionCode::LoadGuestPageFault;
write_gpa_in_tval = REPORT_GPA_IN_TVAL_ON_LOAD_GUEST_PAGE_FAULT;
} else if (op == MemoryOperation::Write || op == MemoryOperation::ReadModifyWrite) {
code = ExceptionCode::StoreAmoGuestPageFault;
write_gpa_in_tval = REPORT_GPA_IN_TVAL_ON_STORE_AMO_GUEST_PAGE_FAULT;
} else {
assert(op == MemoryOperation::Fetch, "unexpected memory operation");
code = ExceptionCode::InstructionGuestPageFault;
write_gpa_in_tval = REPORT_GPA_IN_TVAL_ON_INSTRUCTION_GUEST_PAGE_FAULT;
}
PrivilegeMode handling_mode = exception_handling_mode(code);
if (handling_mode == PrivilegeMode::S) {
CSR[htval].VALUE = write_gpa_in_tval ? (gpa >> 2) : 0;
CSR[htinst].VALUE = tinst_value;
CSR[sepc].PC = $pc;
if (!stval_readonly?()) {
CSR[stval].VALUE = stval_for(code, gva);
}
$pc = {CSR[stvec].BASE, 2'b00};
CSR[scause].INT = 1'b0;
CSR[scause].CODE = $bits(code);
CSR[hstatus].GVA = 1;
CSR[hstatus].SPV = 1;
CSR[hstatus].SPVP = $bits(from_mode)[0];
CSR[mstatus].SPP = $bits(from_mode)[0];
} else {
assert(handling_mode == PrivilegeMode::M, "unexpected privilege mode");
CSR[mtval2].VALUE = write_gpa_in_tval ? (gpa >> 2) : 0;
CSR[mtinst].VALUE = tinst_value;
CSR[mstatus].MPP = $bits(from_mode)[1:0];
if (XLEN == 64) {
CSR[mstatus].MPV = 1;
} else {
CSR[mstatush].MPV = 1;
}
}
set_mode(handling_mode);
abort_current_instruction();
raise
Raise synchronous exception number exception_code
.
The exception may be imprecise, and will cause exectuion to enter an unpredictable state, if PRECISE_SYNCHRONOUS_EXCEPTIONS is false.
Otherwise, the exception will be precise.
Return Type |
|
---|---|
Arguments |
|
if (!PRECISE_SYNCHRONOUS_EXCEPTIONS) {
unpredictable("Imprecise synchronous exception");
} else {
raise_precise(exception_code, from_mode, tval);
}
raise_precise
Raise synchronous exception number exception_code
.
Return Type |
|
---|---|
Arguments |
|
PrivilegeMode handling_mode = exception_handling_mode(exception_code);
if (handling_mode == PrivilegeMode::M) {
CSR[mepc].PC = $pc;
if (!mtval_readonly?()) {
CSR[mtval].VALUE = mtval_for(exception_code, tval);
}
$pc = {CSR[mtvec].BASE, 2'b00};
CSR[mcause].INT = 1'b0;
CSR[mcause].CODE = $bits(exception_code);
if (CSR[misa].H == 1) {
CSR[mtval2].VALUE = 0;
CSR[mtinst].VALUE = 0;
if (from_mode == PrivilegeMode::VU || from_mode == PrivilegeMode::VS) {
if (XLEN == 32) {
CSR[mstatush].MPV = 1;
} else {
CSR[mstatus].MPV = 1;
}
} else {
if (XLEN == 32) {
CSR[mstatush].MPV = 0;
} else {
CSR[mstatus].MPV = 0;
}
}
}
CSR[mstatus].MPP = $bits(from_mode);
} else if (CSR[misa].S == 1 && (handling_mode == PrivilegeMode::S)) {
CSR[sepc].PC = $pc;
if (!stval_readonly?()) {
CSR[stval].VALUE = stval_for(exception_code, tval);
}
$pc = {CSR[stvec].BASE, 2'b00};
CSR[scause].INT = 1'b0;
CSR[scause].CODE = $bits(exception_code);
CSR[mstatus].SPP = $bits(from_mode)[0];
if (CSR[misa].H == 1) {
CSR[htval].VALUE = 0;
CSR[htinst].VALUE = 0;
CSR[hstatus].SPV = $bits(from_mode)[2];
if (from_mode == PrivilegeMode::VU || from_mode == PrivilegeMode::VS) {
CSR[hstatus].SPV = 1;
if (exception_code == ExceptionCode::Breakpoint) && (REPORT_VA_IN_STVAL_ON_BREAKPOINT || exception_code == ExceptionCode::LoadAddressMisaligned) && (REPORT_VA_IN_STVAL_ON_LOAD_MISALIGNED || exception_code == ExceptionCode::StoreAmoAddressMisaligned) && (REPORT_VA_IN_STVAL_ON_STORE_AMO_MISALIGNED || exception_code == ExceptionCode::InstructionAddressMisaligned) && (REPORT_VA_IN_STVAL_ON_INSTRUCTION_MISALIGNED || exception_code == ExceptionCode::LoadAccessFault) && (REPORT_VA_IN_STVAL_ON_LOAD_ACCESS_FAULT || exception_code == ExceptionCode::StoreAmoAccessFault) && (REPORT_VA_IN_STVAL_ON_STORE_AMO_ACCESS_FAULT || exception_code == ExceptionCode::InstructionAccessFault) && (REPORT_VA_IN_STVAL_ON_INSTRUCTION_ACCESS_FAULT || exception_code == ExceptionCode::LoadPageFault) && (REPORT_VA_IN_STVAL_ON_LOAD_PAGE_FAULT || exception_code == ExceptionCode::StoreAmoPageFault) && (REPORT_VA_IN_STVAL_ON_STORE_AMO_PAGE_FAULT || exception_code == ExceptionCode::InstructionPageFault) && (REPORT_VA_IN_STVAL_ON_INSTRUCTION_PAGE_FAULT) {
CSR[hstatus].GVA = 1;
} else {
CSR[hstatus].GVA = 0;
}
CSR[hstatus].SPVP = $bits(from_mode)[0];
} else {
CSR[hstatus].SPV = 0;
CSR[hstatus].GVA = 0;
}
}
} else if (CSR[misa].H == 1 && (handling_mode == PrivilegeMode::VS)) {
CSR[vsepc].PC = $pc;
if (!vstval_readonly?()) {
CSR[vstval].VALUE = vstval_for(exception_code, tval);
}
$pc = {CSR[vstvec].BASE, 2'b00};
CSR[vscause].INT = 1'b0;
CSR[vscause].CODE = $bits(exception_code);
CSR[vsstatus].SPP = $bits(from_mode)[0];
}
set_mode(handling_mode);
abort_current_instruction();
ialign
Returns IALIGN, the smallest instruction encoding size, in bits.
Return Type |
|
---|---|
Arguments |
None |
if (implemented?(ExtensionName::C) && (CSR[misa].C == 0x1)) {
return 16;
} else {
return 32;
}
jump
Jump to virtual address target_addr
.
If target address is misaligned, raise a MisalignedAddress
exception.
Return Type |
|
---|---|
Arguments |
|
jump_halfword
Jump to virtual halfword address target_hw_addr
.
If target address is misaligned, raise a MisalignedAddress
exception.
Return Type |
|
---|---|
Arguments |
|
valid_interrupt_code?
Returns true if code is a legal interrupt number.
Return Type |
|
---|---|
Arguments |
|
if (code > 1 << $enum_element_size(InterruptCode - 1)) {
return false;
}
if (ary_includes?<$enum_size(InterruptCode), $enum_element_size(InterruptCode)>($enum_to_a(InterruptCode), code)) {
return true;
} else {
return false;
}
valid_exception_code?
Returns true if code is a legal exception number.
Return Type |
|
---|---|
Arguments |
|
if (code > 1 << $enum_element_size(ExceptionCode - 1)) {
return false;
}
if (ary_includes?<$enum_size(InterruptCode), $enum_element_size(InterruptCode)>($enum_to_a(InterruptCode), code)) {
return true;
} else {
return false;
}
xlen
Returns the effective XLEN for the current privilege mode.
Return Type |
|
---|---|
Arguments |
None |
if (XLEN == 32) {
return 32;
} else {
if (mode() == PrivilegeMode::M) {
if (CSR[misa].MXL == $bits(XRegWidth::XLEN32)) {
return 32;
} else if (CSR[misa].MXL == $bits(XRegWidth::XLEN64)) {
return 64;
}
} else if (implemented?(ExtensionName::S) && mode() == PrivilegeMode::S) {
if (CSR[mstatus].SXL == $bits(XRegWidth::XLEN32)) {
return 32;
} else if (CSR[mstatus].SXL == $bits(XRegWidth::XLEN64)) {
return 64;
}
} else if (implemented?(ExtensionName::U) && mode() == PrivilegeMode::U) {
if (CSR[mstatus].UXL == $bits(XRegWidth::XLEN32)) {
return 32;
} else if (CSR[mstatus].UXL == $bits(XRegWidth::XLEN64)) {
return 64;
}
} else if (implemented?(ExtensionName::H) && mode() == PrivilegeMode::VS) {
if (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN32)) {
return 32;
} else if (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN64)) {
return 64;
}
} else if (implemented?(ExtensionName::H) && mode() == PrivilegeMode::VU) {
if (CSR[vsstatus].UXL == $bits(XRegWidth::XLEN32)) {
return 32;
} else if (CSR[vsstatus].UXL == $bits(XRegWidth::XLEN64)) {
return 64;
}
}
}
mask_eaddr
Mask upper N bits of an effective address if pointer masking is enabled
Return Type |
|
---|---|
Arguments |
|
return eaddr;
pmp_match_64
Given a physical address, see if any PMP entry matches.
If there is a complete match, return the PmpCfg that guards the region. If there is no match or a partial match, report that result.
Return Type |
|
---|---|
Arguments |
|
Bits<12> pmpcfg0_addr = 0x3a0;
Bits<12> pmpaddr0_addr = 0x3b0;
for (U32 i = 0; i < NUM_PMP_ENTRIES; i++) {
Bits<12> pmpcfg_idx = pmpcfg0_addr + (i / 8) * 2;
Bits<6> shamt = (i % 8) * 8;
PmpCfg cfg = ($bits(CSR[pmpcfg0_addr]) >> shamt)[7:0];
Bits<12> pmpaddr_idx = pmpaddr0_addr + i;
Bits<PHYS_ADDR_WIDTH> range_hi = 0;
Bits<PHYS_ADDR_WIDTH> range_lo = 0;
if (cfg.A == $bits(PmpCfg_A::TOR)) {
if (i == 0) {
range_lo = 0;
} else {
range_lo = (CSR[pmpaddr_idx - 1] << 2)[PHYS_ADDR_WIDTH - 1:0];
}
range_hi = (CSR[pmpaddr_idx] << 2)[PHYS_ADDR_WIDTH - 1:0];
} else if (cfg.A == $bits(PmpCfg_A::NAPOT)) {
Bits<PHYS_ADDR_WIDTH - 2> pmpaddr_value = CSR[pmpaddr_idx].sw_read()[PHYS_ADDR_WIDTH - 3:0];
Bits<PHYS_ADDR_WIDTH - 2> mask = pmpaddr_value ^ (pmpaddr_value + 1);
range_lo = (pmpaddr_value & ~mask) << 2;
Bits<PHYS_ADDR_WIDTH - 2> len = mask + 1;
range_hi = pmpaddr_value & ~mask) + len) << 2; } else if (cfg.A == $bits(PmpCfg_A::NA4 {
range_lo = (CSR[pmpaddr_idx] << 2)[PHYS_ADDR_WIDTH - 1:0];
range_hi = range_lo + 4;
}
if ((paddr >= range_lo) && paddr + (access_size / 8 < range_hi)) {
return PmpMatchResult::FullMatch, cfg;
} else if (! {
return PmpMatchResult::PartialMatch, -;
}
}
return PmpMatchResult::NoMatch, -;
pmp_match_32
Given a physical address, see if any PMP entry matches.
If there is a complete match, return the PmpCfg that guards the region. If there is no match or a partial match, report that result.
Return Type |
|
---|---|
Arguments |
|
Bits<12> pmpcfg0_addr = 0x3a0;
Bits<12> pmpaddr0_addr = 0x3b0;
for (U32 i = 0; i < NUM_PMP_ENTRIES; i++) {
Bits<12> pmpcfg_idx = pmpcfg0_addr + (i / 4);
Bits<6> shamt = (i % 4) * 8;
PmpCfg cfg = ($bits(CSR[pmpcfg0_addr]) >> shamt)[7:0];
Bits<12> pmpaddr_idx = pmpaddr0_addr + i;
Bits<PHYS_ADDR_WIDTH> range_hi = 0;
Bits<PHYS_ADDR_WIDTH> range_lo = 0;
if (cfg.A == $bits(PmpCfg_A::TOR)) {
if (i == 0) {
range_lo = 0;
} else {
range_lo = (CSR[pmpaddr_idx - 1] << 2)[PHYS_ADDR_WIDTH - 1:0];
}
range_hi = (CSR[pmpaddr_idx] << 2)[PHYS_ADDR_WIDTH - 1:0];
} else if (cfg.A == $bits(PmpCfg_A::NAPOT)) {
Bits<PHYS_ADDR_WIDTH - 2> pmpaddr_value = CSR[pmpaddr_idx].sw_read()[PHYS_ADDR_WIDTH - 3:0];
Bits<PHYS_ADDR_WIDTH - 2> mask = pmpaddr_value ^ (pmpaddr_value + 1);
range_lo = (pmpaddr_value & ~mask) << 2;
Bits<PHYS_ADDR_WIDTH - 2> len = mask + 1;
range_hi = pmpaddr_value & ~mask) + len) << 2; } else if (cfg.A == $bits(PmpCfg_A::NA4 {
range_lo = ($bits(CSR[pmpaddr_idx]) << 2)[PHYS_ADDR_WIDTH - 1:0];
range_hi = range_lo + 4;
}
if ((paddr >= range_lo) && paddr + (access_size / 8 < range_hi)) {
return PmpMatchResult::FullMatch, cfg;
} else if (! {
return PmpMatchResult::PartialMatch, -;
}
}
return PmpMatchResult::NoMatch, -;
pmp_match
Given a physical address, see if any PMP entry matches.
If there is a complete match, return the PmpCfg that guards the region. If there is no match or a partial match, report that result.
Return Type |
|
---|---|
Arguments |
|
if (XLEN == 64) {
return pmp_match_64<access_size>(paddr);
} else {
return pmp_match_32<access_size>(paddr);
}
mpv
Returns the current value of CSR[mstatus].MPV (when MXLEN == 64) of CSR[mstatush].MPV (when MXLEN == 32)
Return Type |
|
---|---|
Arguments |
None |
if (implemented?(ExtensionName::H)) {
return (XLEN == 32) ? CSR[mstatush].MPV : CSR[mstatus].MPV;
} else {
assert(false, "TODO");
}
effective_ldst_mode
Returns the effective privilege mode for normal explicit loads and stores, taking into account the current actual privilege mode and modifications from mstatus.MPRV.
Return Type |
|
---|---|
Arguments |
None |
if (mode() == PrivilegeMode::M) {
if (CSR[misa].U == 1 && CSR[mstatus].MPRV == 1) {
if (CSR[mstatus].MPP == 0b00) {
if (CSR[misa].H == 1 && mpv() == 0b1) {
return PrivilegeMode::VU;
} else {
return PrivilegeMode::U;
}
} else if (CSR[misa].S == 1 && CSR[mstatus].MPP == 0b01) {
if (CSR[misa].H == 1 && mpv() == 0b1) {
return PrivilegeMode::VS;
} else {
return PrivilegeMode::S;
}
}
}
}
return mode();
pmp_check
Given a physical address and operation type, return whether or not the access is allowed by PMP.
Return Type |
|
---|---|
Arguments |
|
PrivilegeMode mode = effective_ldst_mode();
PmpMatchResult match_result;
PmpCfg cfg;
(match_result, cfg = pmp_match<access_size>(paddr));
if (match_result == PmpMatchResult::FullMatch) {
if (mode == PrivilegeMode::M && (cfg.L == 0)) {
return true;
}
if (type == MemoryOperation::Write && (cfg.W == 0)) {
return false;
} else if (type == MemoryOperation::Read && (cfg.R == 0)) {
return false;
} else if (type == MemoryOperation::Fetch && (cfg.X == 0)) {
return false;
}
} else if (match_result == PmpMatchResult::NoMatch) {
if (mode == PrivilegeMode::M) {
return true;
} else {
return false;
}
} else {
assert(match_result == PmpMatchResult::PartialMatch, "PMP matching logic error");
return false;
}
return true;
access_check
Checks if the physical address paddr is able to access memory, and raises the appropriate exception if not.
Return Type |
|
---|---|
Arguments |
|
base32?
return True iff current effective XLEN == 32
Return Type |
|
---|---|
Arguments |
None |
if (XLEN == 32) {
return true;
} else {
XRegWidth xlen32 = XRegWidth::XLEN32;
if (mode() == PrivilegeMode::M) {
return CSR[misa].MXL == $bits(xlen32);
} else if (implemented?(ExtensionName::S) && mode() == PrivilegeMode::S) {
return CSR[mstatus].SXL == $bits(xlen32);
} else if (implemented?(ExtensionName::U) && mode() == PrivilegeMode::U) {
return CSR[mstatus].UXL == $bits(xlen32);
} else if (implemented?(ExtensionName::H) && mode() == PrivilegeMode::VS) {
return CSR[hstatus].VSXL == $bits(xlen32);
} else {
assert(implemented?(ExtensionName::H) && mode() == PrivilegeMode::VU, "Unexpected mode");
return CSR[vsstatus].UXL == $bits(xlen32);
}
}
base64?
return True iff current effective XLEN == 64
Return Type |
|
---|---|
Arguments |
None |
return xlen() == 64;
current_translation_mode
Returns the current first-stage translation mode for an explicit load or store from mode given the machine state (e.g., value of satp or vsatp csr).
Return Type |
|
---|---|
Arguments |
|
PrivilegeMode effective_mode = effective_ldst_mode();
if (effective_mode == PrivilegeMode::M) {
return SatpMode::Bare;
}
if (CSR[misa].H == 1'b1) {
if (effective_mode == PrivilegeMode::VS || effective_mode == PrivilegeMode::VU) {
Bits<4> mode_val = CSR[vsatp].MODE;
if (mode_val == $bits(SatpMode::Sv32)) {
if (XLEN == 64) {
if ((effective_mode == PrivilegeMode::VS) && (CSR[hstatus].VSXL != $bits(XRegWidth::XLEN32))) {
return SatpMode::Reserved;
}
if ((effective_mode == PrivilegeMode::VU) && (CSR[vsstatus].UXL != $bits(XRegWidth::XLEN32))) {
return SatpMode::Reserved;
}
}
if (!SV32_VSMODE_TRANSLATION) {
return SatpMode::Reserved;
}
return SatpMode::Sv32;
} else if ((XLEN == 64) && (mode_val == $bits(SatpMode::Sv39))) {
if (effective_mode == PrivilegeMode::VS && CSR[hstatus].VSXL != $bits(XRegWidth::XLEN64)) {
return SatpMode::Reserved;
}
if (effective_mode == PrivilegeMode::VU && CSR[vsstatus].UXL != $bits(XRegWidth::XLEN64)) {
return SatpMode::Reserved;
}
if (!SV39_VSMODE_TRANSLATION) {
return SatpMode::Reserved;
}
return SatpMode::Sv39;
} else if ((XLEN == 64) && (mode_val == $bits(SatpMode::Sv48))) {
if (effective_mode == PrivilegeMode::VS && CSR[hstatus].VSXL != $bits(XRegWidth::XLEN64)) {
return SatpMode::Reserved;
}
if (effective_mode == PrivilegeMode::VU && CSR[vsstatus].UXL != $bits(XRegWidth::XLEN64)) {
return SatpMode::Reserved;
}
if (!SV48_VSMODE_TRANSLATION) {
return SatpMode::Reserved;
}
return SatpMode::Sv48;
} else if ((XLEN == 64) && (mode_val == $bits(SatpMode::Sv57))) {
if (effective_mode == PrivilegeMode::VS && CSR[hstatus].VSXL != $bits(XRegWidth::XLEN64)) {
return SatpMode::Reserved;
}
if (effective_mode == PrivilegeMode::VU && CSR[vsstatus].UXL != $bits(XRegWidth::XLEN64)) {
return SatpMode::Reserved;
}
if (!SV57_VSMODE_TRANSLATION) {
return SatpMode::Reserved;
}
return SatpMode::Sv57;
} else {
return SatpMode::Reserved;
}
}
}
assert(effective_mode == PrivilegeMode::S || effective_mode == PrivilegeMode::U, "unexpected priv mode");
Bits<4> mode_val = CSR[vsatp].MODE;
if (mode_val == $bits(SatpMode::Sv32)) {
if (XLEN == 64) {
if (effective_mode == PrivilegeMode::S && CSR[mstatus].SXL != $bits(XRegWidth::XLEN32)) {
return SatpMode::Reserved;
}
if (effective_mode == PrivilegeMode::U && CSR[sstatus].UXL != $bits(XRegWidth::XLEN32)) {
return SatpMode::Reserved;
}
}
if (!implemented?(ExtensionName::Sv32)) {
return SatpMode::Reserved;
}
} else if ((XLEN == 64) && (mode_val == $bits(SatpMode::Sv39))) {
if (effective_mode == PrivilegeMode::S && CSR[mstatus].SXL != $bits(XRegWidth::XLEN64)) {
return SatpMode::Reserved;
}
if (effective_mode == PrivilegeMode::U && CSR[sstatus].UXL != $bits(XRegWidth::XLEN64)) {
return SatpMode::Reserved;
}
if (!implemented?(ExtensionName::Sv39)) {
return SatpMode::Reserved;
}
return SatpMode::Sv39;
} else if ((XLEN == 64) && (mode_val == $bits(SatpMode::Sv48))) {
if (effective_mode == PrivilegeMode::S && CSR[mstatus].SXL != $bits(XRegWidth::XLEN64)) {
return SatpMode::Reserved;
}
if (effective_mode == PrivilegeMode::U && CSR[sstatus].UXL != $bits(XRegWidth::XLEN64)) {
return SatpMode::Reserved;
}
if (!implemented?(ExtensionName::Sv48)) {
return SatpMode::Reserved;
}
return SatpMode::Sv48;
} else if ((XLEN == 64) && (mode_val == $bits(SatpMode::Sv57))) {
if (effective_mode == PrivilegeMode::S && CSR[mstatus].SXL != $bits(XRegWidth::XLEN64)) {
return SatpMode::Reserved;
}
if (effective_mode == PrivilegeMode::U && CSR[sstatus].UXL != $bits(XRegWidth::XLEN64)) {
return SatpMode::Reserved;
}
if (!implemented?(ExtensionName::Sv57)) {
return SatpMode::Reserved;
}
return SatpMode::Sv57;
} else {
return SatpMode::Reserved;
}
current_gstage_translation_mode
Returns the current second-stage translation mode for a load or store from VS-mode or VU-mode.
Return Type |
|
---|---|
Arguments |
None |
return CSR[hgatp].MODE;
translate_gstage
Translates a guest physical address to a physical address.
Return Type |
|
---|---|
Arguments |
|
TranslationResult result;
if (effective_mode == PrivilegeMode::S || effective_mode == PrivilegeMode::U) {
result.paddr = gpaddr;
return result;
}
Boolean mxr = CSR[mstatus].MXR == 1;
if (GSTAGE_MODE_BARE && CSR[hgatp].MODE == $bits(HgatpMode::Bare)) {
result.paddr = gpaddr;
return result;
} else if (SV32X4_TRANSLATION && CSR[hgatp].MODE == $bits(HgatpMode::Sv32x4)) {
return gstage_page_walk<32, 34, 32, 2>(gpaddr, vaddr, op, effective_mode, false, encoding);
} else if (SV39X4_TRANSLATION && CSR[hgatp].MODE == $bits(HgatpMode::Sv39x4)) {
return gstage_page_walk<39, 56, 64, 3>(gpaddr, vaddr, op, effective_mode, false, encoding);
} else if (SV48X4_TRANSLATION && CSR[hgatp].MODE == $bits(HgatpMode::Sv48x4)) {
return gstage_page_walk<48, 56, 64, 4>(gpaddr, vaddr, op, effective_mode, false, encoding);
} else if (SV57X4_TRANSLATION && CSR[hgatp].MODE == $bits(HgatpMode::Sv57x4)) {
return gstage_page_walk<57, 56, 64, 5>(gpaddr, vaddr, op, effective_mode, false, encoding);
} else {
if (op == MemoryOperation::Read) {
raise_guest_page_fault(op, gpaddr, vaddr, tinst_value_for_guest_page_fault(op, encoding, true), effective_mode);
} else if (op == MemoryOperation::Write || op == MemoryOperation::ReadModifyWrite) {
raise_guest_page_fault(op, gpaddr, vaddr, tinst_value_for_guest_page_fault(op, encoding, true), effective_mode);
} else {
assert(op == MemoryOperation::Fetch, "unexpected memory op");
raise_guest_page_fault(op, gpaddr, vaddr, tinst_value_for_guest_page_fault(op, encoding, true), effective_mode);
}
}
tinst_value_for_guest_page_fault
Returns the value of htinst/mtinst for a Guest Page Fault
Return Type |
|
---|---|
Arguments |
|
if (for_final_vs_pte) {
if (op == MemoryOperation::Fetch) {
if (TINST_VALUE_ON_FINAL_INSTRUCTION_GUEST_PAGE_FAULT == "always zero") {
return 0;
} else {
assert(TINST_VALUE_ON_FINAL_INSTRUCTION_GUEST_PAGE_FAULT == "always pseudoinstruction", "Instruction guest page faults can only report zero/pseudo instruction in tval");
return 0x00002000;
}
} else if (op == MemoryOperation::Read) {
if (TINST_VALUE_ON_FINAL_LOAD_GUEST_PAGE_FAULT == "always zero") {
return 0;
} else if (TINST_VALUE_ON_FINAL_LOAD_GUEST_PAGE_FAULT == "always pseudoinstruction") {
if ((VSXLEN == 32) || XLEN == 64) && (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN32)) {
return 0x00002000;
} else {
return 0x00003000;
}
} else if (TINST_VALUE_ON_FINAL_LOAD_GUEST_PAGE_FAULT == "always transformed standard instruction") {
return tinst_transform(encoding, 0);
} else {
unpredictable("Custom value written into htinst/mtinst");
}
} else if (op == MemoryOperation::Write || op == MemoryOperation::ReadModifyWrite) {
if (TINST_VALUE_ON_FINAL_STORE_AMO_GUEST_PAGE_FAULT == "always zero") {
return 0;
} else if (TINST_VALUE_ON_FINAL_STORE_AMO_GUEST_PAGE_FAULT == "always pseudoinstruction") {
if ((VSXLEN == 32) || XLEN == 64) && (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN32)) {
return 0x00002020;
} else {
return 0x00003020;
}
} else if (TINST_VALUE_ON_FINAL_STORE_AMO_GUEST_PAGE_FAULT == "always transformed standard instruction") {
return tinst_transform(encoding, 0);
} else {
unpredictable("Custom value written into htinst/mtinst");
}
}
} else {
if (REPORT_GPA_IN_TVAL_ON_INTERMEDIATE_GUEST_PAGE_FAULT) {
if ((VSXLEN == 32) || XLEN == 64) && (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN32)) {
return 0x00002000;
} else if ((VSXLEN == 64) || XLEN == 64) && (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN64)) {
return 0x00003000;
}
}
}
tinst_transform
Returns the standard transformation of an encoding for htinst/mtinst
Return Type |
|
---|---|
Arguments |
|
if (encoding[1:0] == 0b11) {
if (encoding[6:2] == 5'b00001) {
return {{12{1'b0}}, addr_offset, encoding[14:0]};
} else if (encoding[6:2] == 5'b01000) {
return {{7{1'b0}}, encoding[24:20], addr_offset, encoding[14:12], {5{1'b0}}, encoding[6:0]};
} else if (encoding[6:2] == 5'b01011) {
return {encoding[31:20], addr_offset, encoding[14:0]};
} else if (encoding[6:2] == 5'b00011) {
return {encoding[31:20], addr_offset, encoding[14:0]};
} else {
assert(false, "Bad transform");
}
} else {
assert(false, "TODO: compressed instruction");
}
transformed_standard_instruction_for_tinst
Transforms an instruction encoding for htinst.
Return Type |
|
---|---|
Arguments |
|
assert(false, "TODO");
return 0;
tinst_value
Returns the value of htinst/mtinst for the given exception code.
Return Type |
|
---|---|
Arguments |
|
if (code == ExceptionCode::InstructionAddressMisaligned) {
if (TINST_VALUE_ON_INSTRUCTION_ADDRESS_MISALIGNED == "always zero") {
return 0;
} else {
unpredictable("An unpredictable value is written into tinst in response to an InstructionAddressMisaligned exception");
}
} else if (code == ExceptionCode::InstructionAccessFault) {
return 0;
} else if (code == ExceptionCode::IllegalInstruction) {
return 0;
} else if (code == ExceptionCode::Breakpoint) {
if (TINST_VALUE_ON_BREAKPOINT == "always zero") {
return 0;
} else {
unpredictable("An unpredictable value is written into tinst in response to a Breakpoint exception");
}
} else if (code == ExceptionCode::VirtualInstruction) {
if (TINST_VALUE_ON_VIRTUAL_INSTRUCTION == "always zero") {
return 0;
} else {
unpredictable("An unpredictable value is written into tinst in response to a VirtualInstruction exception");
}
} else if (code == ExceptionCode::LoadAddressMisaligned) {
if (TINST_VALUE_ON_LOAD_ADDRESS_MISALIGNED == "always zero") {
return 0;
} else if (TINST_VALUE_ON_LOAD_ADDRESS_MISALIGNED == "always transformed standard instruction") {
return transformed_standard_instruction_for_tinst(encoding);
} else {
unpredictable("An unpredictable value is written into tinst in response to a LoadAddressMisaligned exception");
}
} else if (code == ExceptionCode::LoadAccessFault) {
if (TINST_VALUE_ON_LOAD_ACCESS_FAULT == "always zero") {
return 0;
} else if (TINST_VALUE_ON_LOAD_ACCESS_FAULT == "always transformed standard instruction") {
return transformed_standard_instruction_for_tinst(encoding);
} else {
unpredictable("An unpredictable value is written into tinst in response to a LoadAccessFault exception");
}
} else if (code == ExceptionCode::StoreAmoAddressMisaligned) {
if (TINST_VALUE_ON_STORE_AMO_ADDRESS_MISALIGNED == "always zero") {
return 0;
} else if (TINST_VALUE_ON_STORE_AMO_ADDRESS_MISALIGNED == "always transformed standard instruction") {
return transformed_standard_instruction_for_tinst(encoding);
} else {
unpredictable("An unpredictable value is written into tinst in response to a StoreAmoAddressMisaligned exception");
}
} else if (code == ExceptionCode::StoreAmoAccessFault) {
if (TINST_VALUE_ON_STORE_AMO_ACCESS_FAULT == "always zero") {
return 0;
} else if (TINST_VALUE_ON_STORE_AMO_ACCESS_FAULT == "always transformed standard instruction") {
return transformed_standard_instruction_for_tinst(encoding);
} else {
unpredictable("An unpredictable value is written into tinst in response to a StoreAmoAccessFault exception");
}
} else if (code == ExceptionCode::Ucall) {
if (TINST_VALUE_ON_UCALL == "always zero") {
return 0;
} else {
unpredictable("An unpredictable value is written into tinst in response to a UCall exception");
}
} else if (code == ExceptionCode::Scall) {
if (TINST_VALUE_ON_SCALL == "always zero") {
return 0;
} else {
unpredictable("An unpredictable value is written into tinst in response to a SCall exception");
}
} else if (code == ExceptionCode::Mcall) {
if (TINST_VALUE_ON_MCALL == "always zero") {
return 0;
} else {
unpredictable("An unpredictable value is written into tinst in response to a MCall exception");
}
} else if (code == ExceptionCode::VScall) {
if (TINST_VALUE_ON_VSCALL == "always zero") {
return 0;
} else {
unpredictable("An unpredictable value is written into tinst in response to a VSCall exception");
}
} else if (code == ExceptionCode::InstructionPageFault) {
return 0;
} else if (code == ExceptionCode::LoadPageFault) {
if (TINST_VALUE_ON_LOAD_PAGE_FAULT == "always zero") {
return 0;
} else if (TINST_VALUE_ON_LOAD_PAGE_FAULT == "always transformed standard instruction") {
return transformed_standard_instruction_for_tinst(encoding);
} else {
unpredictable("An unpredictable value is written into tinst in response to a LoadPageFault exception");
}
} else if (code == ExceptionCode::StoreAmoPageFault) {
if (TINST_VALUE_ON_STORE_AMO_PAGE_FAULT == "always zero") {
return 0;
} else if (TINST_VALUE_ON_STORE_AMO_PAGE_FAULT == "always transformed standard instruction") {
return transformed_standard_instruction_for_tinst(encoding);
} else {
unpredictable("An unpredictable value is written into tinst in response to a StoreAmoPageFault exception");
}
} else {
assert(false, "Unhandled exception type");
}
gstage_page_walk
Translate guest physical address to physical address through a page walk.
May raise a Guest Page Fault if an error involving the page table structure occurs along the walk.
Implicit reads of the page table are accessed check, and may raise Access Faults. Implicit writes (updates of A/D) are also accessed checked, and may raise Access Faults
The translated address is not accessed checked.
Returns the translated physical address.
Return Type |
|
---|---|
Arguments |
|
Bits<PA_SIZE> ppn;
TranslationResult result;
U32 VPN_SIZE = (LEVELS == 2) ? 10 : 9;
ExceptionCode access_fault_code = op == MemoryOperation::Read ? ExceptionCode::LoadAccessFault : (op == MemoryOperation::Fetch ? ExceptionCode::InstructionAccessFault : ExceptionCode::StoreAmoAccessFault);
ExceptionCode page_fault_code = op == MemoryOperation::Read ? ExceptionCode::LoadGuestPageFault : (op == MemoryOperation::Fetch ? ExceptionCode::InstructionGuestPageFault : ExceptionCode::StoreAmoGuestPageFault);
Boolean mxr = for_final_vs_pte && (CSR[mstatus].MXR == 1);
Boolean pbmte = CSR[menvcfg].PBMTE == 1;
Boolean adue = CSR[menvcfg].ADUE == 1;
Bits<32> tinst = tinst_value_for_guest_page_fault(op, encoding, for_final_vs_pte);
U32 max_gpa_width = LEVELS * VPN_SIZE + 2 + 12;
if (gpaddr >> max_gpa_width != 0) {
raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode);
}
ppn = CSR[hgatp].PPN;
for (U32 i = (LEVELS - 1); i >= 0; i--) {
U32 this_vpn_size = (i == (LEVELS - 1)) ? VPN_SIZE + 2 : VPN_SIZE;
U32 vpn = (gpaddr >> (12 + VPN_SIZE * i)) & 1 << this_vpn_size) - 1); Bits<PA_SIZE> pte_paddr = (ppn << 12) + (vpn * (PTESIZE / 8;
if (!pma_applies?(PmaAttribute::HardwarePageTableRead, pte_paddr, PTESIZE)) {
raise(access_fault_code, PrivilegeMode::U, vaddr);
}
access_check(pte_paddr, PTESIZE, vaddr, MemoryOperation::Read, access_fault_code, effective_mode);
Bits<PTESIZE> pte = read_physical_memory<PTESIZE>(pte_paddr);
PteFlags pte_flags = pte[9:0];
if ((VA_SIZE != 32) && (pte[60:54] != 0)) {
raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode);
}
if (!implemented?(ExtensionName::Svnapot)) {
if ((PTESIZE >= 64) && pte[63] != 0) {
raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode);
}
}
if ((PTESIZE >= 64) && !pbmte && (pte[62:61] != 0)) {
raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode);
}
if ((PTESIZE >= 64) && pbmte && (pte[62:61] == 3)) {
raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode);
}
if (pte_flags.V == 0) {
raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode);
}
if (pte_flags.R == 0 && pte_flags.W == 1) {
raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode);
}
if (pte_flags.R == 1 || pte_flags.X == 1) {
if (pte_flags.U == 0) {
raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode);
}
if (op == MemoryOperation::Write) || (op == MemoryOperation::ReadModifyWrite && (pte_flags.W == 0)) {
raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode);
} else if ((op == MemoryOperation::Fetch) && (pte_flags.X == 0)) {
raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode);
} else if ((op == MemoryOperation::Read) || (op == MemoryOperation::ReadModifyWrite)) {
if (!mxr) && (pte_flags.R == 0 || mxr) && (pte_flags.X == 0 && pte_flags.R == 0) {
raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode);
}
}
if ((i > 0) && (pte[(i - 1) * VPN_SIZE:10] != 0)) {
raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode);
}
if ((pte_flags.A == 0) || pte_flags.D == 0) && ((op == MemoryOperation::Write) || (op == MemoryOperation::ReadModifyWrite)) {
if (adue) {
if (!pma_applies?(PmaAttribute::RsrvEventual, pte_paddr, PTESIZE)) {
raise(access_fault_code, PrivilegeMode::U, vaddr);
}
if (!pma_applies?(PmaAttribute::HardwarePageTableWrite, pte_paddr, PTESIZE)) {
raise(access_fault_code, PrivilegeMode::U, vaddr);
}
access_check(pte_paddr, PTESIZE, vaddr, MemoryOperation::Write, access_fault_code, effective_mode);
Boolean success;
Bits<PTESIZE> updated_pte;
if (pte_flags.D == 0 && (op == MemoryOperation::Write || op == MemoryOperation::ReadModifyWrite)) {
updated_pte = pte | 0b11000000;
} else {
updated_pte = pte | 0b01000000;
}
if (PTESIZE == 32) {
success = atomic_check_then_write_32(pte_paddr, pte, updated_pte);
} else if (PTESIZE == 64) {
success = atomic_check_then_write_64(pte_paddr, pte, updated_pte);
} else {
assert(false, "Unexpected PTESIZE");
}
if (!success) {
i = i + 1;
} else {
result.paddr = pte_paddr;
if (PTESIZE >= 64) {
result.pbmt = pte[62:61];
}
result.pte_flags = pte_flags;
return result;
}
} else {
raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode);
}
}
} else {
if (i == 0) {
raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode);
}
if (pte_flags.D == 1 || pte_flags.A == 1 || pte_flags.U == 1) {
raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode);
}
if ((VA_SIZE != 32) && (pte[62:61] != 0)) {
raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode);
}
if ((VA_SIZE != 32) && pte[63] != 0) {
raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode);
}
ppn = pte[PA_SIZE - 3:10] << 12;
}
}
stage1_page_walk
Translate virtual address to physical address through a page walk.
May raise a Page Fault if an error involving the page table structure occurs along the walk.
Implicit reads of the page table are accessed check, and may raise Access Faults. Implicit writes (updates of A/D) are also accessed checked, and may raise Access Faults
The translated address is not accessed checked.
Returns the translated guest physical address.
Return Type |
|
---|---|
Arguments |
|
Bits<PA_SIZE> ppn;
TranslationResult result;
U32 VPN_SIZE = (LEVELS == 2) ? 10 : 9;
ExceptionCode access_fault_code = op == MemoryOperation::Read ? ExceptionCode::LoadAccessFault : (op == MemoryOperation::Fetch ? ExceptionCode::InstructionAccessFault : ExceptionCode::StoreAmoAccessFault);
ExceptionCode page_fault_code = op == MemoryOperation::Read ? ExceptionCode::LoadPageFault : (op == MemoryOperation::Fetch ? ExceptionCode::InstructionPageFault : ExceptionCode::StoreAmoPageFault);
Boolean sse = false;
Boolean adue;
if (CSR[misa].H == 1 && (effective_mode == PrivilegeMode::VS || effective_mode == PrivilegeMode::VU)) {
adue = CSR[henvcfg].ADUE == 1;
} else {
adue = CSR[menvcfg].ADUE == 1;
}
Boolean pbmte;
if (VA_SIZE == 32) {
pbmte = false;
} else {
if (CSR[misa].H == 1 && (effective_mode == PrivilegeMode::VS || effective_mode == PrivilegeMode::VU)) {
pbmte = CSR[henvcfg].PBMTE == 1;
} else {
pbmte = CSR[menvcfg].PBMTE == 1;
}
}
Boolean mxr;
if (CSR[misa].H == 1 && (effective_mode == PrivilegeMode::VS || effective_mode == PrivilegeMode::VU)) {
mxr = (CSR[mstatus].MXR == 1) || (CSR[vsstatus].MXR == 1);
} else {
mxr = CSR[mstatus].MXR == 1;
}
Boolean sum;
if (CSR[misa].H == 1 && (effective_mode == PrivilegeMode::VS)) {
sum = CSR[vsstatus].SUM == 1;
} else {
sum = CSR[mstatus].SUM == 1;
}
ppn = CSR[vsatp].PPN;
if ((VA_SIZE < xlen()) && (vaddr[xlen() - 1:VA_SIZE] != {xlen() - VA_SIZE{vaddr[VA_SIZE - 1]}})) {
raise(page_fault_code, effective_mode, vaddr);
}
for (U32 i = (LEVELS - 1); i >= 0; i--) {
U32 vpn = (vaddr >> (12 + VPN_SIZE * i)) & 1 << VPN_SIZE) - 1); Bits<PA_SIZE> pte_gpaddr = (ppn << 12) + (vpn * (PTESIZE / 8;
TranslationResult pte_phys = translate_gstage(pte_gpaddr, vaddr, MemoryOperation::Read, effective_mode, encoding);
if (!pma_applies?(PmaAttribute::HardwarePageTableRead, pte_phys.paddr, PTESIZE)) {
raise(access_fault_code, effective_mode, vaddr);
}
access_check(pte_phys.paddr, PTESIZE, vaddr, MemoryOperation::Read, access_fault_code, effective_mode);
Bits<PTESIZE> pte = read_physical_memory<PTESIZE>(pte_phys.paddr);
PteFlags pte_flags = pte[9:0];
Boolean ss_page = (pte_flags.R == 0) && (pte_flags.W == 1) && (pte_flags.X == 0);
if ((VA_SIZE != 32) && (pte[60:54] != 0)) {
raise(page_fault_code, effective_mode, vaddr);
}
if (pte_flags.V == 0) {
raise(page_fault_code, effective_mode, vaddr);
}
if (!sse) {
if ((pte_flags.R == 0) && (pte_flags.W == 1)) {
raise(page_fault_code, effective_mode, vaddr);
}
}
if (pbmte) {
if (pte[62:61] == 3) {
raise(page_fault_code, effective_mode, vaddr);
}
} else {
if ((PTESIZE >= 64) && (pte[62:61] != 0)) {
raise(page_fault_code, effective_mode, vaddr);
}
}
if (!implemented?(ExtensionName::Svnapot)) {
if ((PTESIZE >= 64) && (pte[63] != 0)) {
raise(page_fault_code, effective_mode, vaddr);
}
}
if (pte_flags.R == 1 || pte_flags.X == 1) {
if (op == MemoryOperation::Read || op == MemoryOperation::ReadModifyWrite) {
if (!mxr) && (pte_flags.R == 0 || mxr) && (pte_flags.X == 0 && pte_flags.R == 0) {
raise(page_fault_code, effective_mode, vaddr);
}
if (effective_mode == PrivilegeMode::U && pte_flags.U == 0) {
raise(page_fault_code, effective_mode, vaddr);
} else if (CSR[misa].H == 1 && effective_mode == PrivilegeMode::VU && pte_flags.U == 0) {
raise(page_fault_code, effective_mode, vaddr);
} else if (effective_mode == PrivilegeMode::S && pte_flags.U == 1 && !sum) {
raise(page_fault_code, effective_mode, vaddr);
} else if (effective_mode == PrivilegeMode::VS && pte_flags.U == 1 && !sum) {
raise(page_fault_code, effective_mode, vaddr);
}
}
if (op == MemoryOperation::Write) || (op == MemoryOperation::ReadModifyWrite && (pte_flags.W == 0)) {
raise(page_fault_code, effective_mode, vaddr);
} else if ((op == MemoryOperation::Fetch) && (pte_flags.X == 0)) {
raise(page_fault_code, effective_mode, vaddr);
} else if ((op == MemoryOperation::Fetch) && ss_page) {
raise(page_fault_code, effective_mode, vaddr);
}
raise(page_fault_code, effective_mode, vaddr) if ;
if ((pte_flags.A == 0) || pte_flags.D == 0) && ((op == MemoryOperation::Write) || (op == MemoryOperation::ReadModifyWrite)) {
if (adue) {
TranslationResult pte_phys = translate_gstage(pte_gpaddr, vaddr, MemoryOperation::Write, effective_mode, encoding);
if (!pma_applies?(PmaAttribute::RsrvEventual, pte_phys.paddr, PTESIZE)) {
raise(access_fault_code, effective_mode, vaddr);
}
if (!pma_applies?(PmaAttribute::HardwarePageTableWrite, pte_phys.paddr, PTESIZE)) {
raise(access_fault_code, effective_mode, vaddr);
}
access_check(pte_phys.paddr, PTESIZE, vaddr, MemoryOperation::Write, access_fault_code, effective_mode);
Boolean success;
Bits<PTESIZE> updated_pte;
if (pte_flags.D == 0 && (op == MemoryOperation::Write || op == MemoryOperation::ReadModifyWrite)) {
updated_pte = pte | 0b11000000;
} else {
updated_pte = pte | 0b01000000;
}
if (PTESIZE == 32) {
success = atomic_check_then_write_32(pte_phys.paddr, pte, updated_pte);
} else if (PTESIZE == 64) {
success = atomic_check_then_write_64(pte_phys.paddr, pte, updated_pte);
} else {
assert(false, "Unexpected PTESIZE");
}
if (!success) {
i = i + 1;
} else {
TranslationResult pte_phys = translate_gstage({(pte[PA_SIZE - 3:(i * VPN_SIZE) + 10] << 2), vaddr[11:0]}, vaddr, op, effective_mode, encoding);
result.paddr = pte_phys.paddr;
result.pbmt = pte_phys.pbmt == 0 ? pte[62:61] : pte_phys.pbmt;
result.pte_flags = pte_flags;
return result;
}
} else {
raise(page_fault_code, effective_mode, vaddr);
}
}
TranslationResult pte_phys = translate_gstage({(pte[PA_SIZE - 3:(i * VPN_SIZE) + 10] << 2), vaddr[11:0]}, vaddr, op, effective_mode, encoding);
result.paddr = pte_phys.paddr;
if (PTESIZE >= 64) {
result.pbmt = pte_phys.pbmt == Pbmt::PMA ? $enum(Pbmt, pte[62:61]) : pte_phys.pbmt;
}
result.pte_flags = pte_flags;
return result;
} else {
if (i == 0) {
raise(page_fault_code, effective_mode, vaddr);
}
if (pte_flags.D == 1 || pte_flags.A == 1 || pte_flags.U == 1) {
raise(page_fault_code, effective_mode, vaddr);
}
if ((VA_SIZE != 32) && (pte[62:61] != 0)) {
raise(page_fault_code, effective_mode, vaddr);
}
if ((VA_SIZE != 32) && pte[63] != 0) {
raise(page_fault_code, effective_mode, vaddr);
}
ppn = pte[PA_SIZE - 3:10] << 12;
}
}
translate
Translate a virtual address for operation type op that appears to execute at effective_mode.
The translation will depend on the effective privilege mode.
May raise a Page Fault or Access Fault.
The final physical address is not access checked (for PMP, PMA, etc., violations). (though intermediate page table reads will be)
Return Type |
|
---|---|
Arguments |
|
Boolean cached_translation_valid;
TranslationResult cached_translation_result;
(cached_translation_valid, cached_translation_result = cached_translation(vaddr, op));
if (cached_translation_valid) {
return cached_translation_result;
}
TranslationResult result;
if (effective_mode == PrivilegeMode::M) {
return vaddr;
}
SatpMode translation_mode = current_translation_mode(effective_mode);
if (translation_mode == SatpMode::Reserved) {
if (op == MemoryOperation::Read) {
raise(ExceptionCode::LoadPageFault, effective_mode, vaddr);
} else if (op == MemoryOperation::Write || op == MemoryOperation::ReadModifyWrite) {
raise(ExceptionCode::StoreAmoPageFault, effective_mode, vaddr);
} else {
assert(op == MemoryOperation::Fetch, "Unexpected memory operation");
raise(ExceptionCode::InstructionPageFault, effective_mode, vaddr);
}
}
if (translation_mode == SatpMode::Sv32) {
result = stage1_page_walk<32, 34, 32, 2>(vaddr, op, effective_mode, encoding);
} else if (translation_mode == SatpMode::Sv39) {
result = stage1_page_walk<39, 56, 64, 3>(vaddr, op, effective_mode, encoding);
} else if (translation_mode == SatpMode::Sv48) {
result = stage1_page_walk<48, 56, 64, 4>(vaddr, op, effective_mode, encoding);
} else if (translation_mode == SatpMode::Sv57) {
result = stage1_page_walk<57, 56, 64, 5>(vaddr, op, effective_mode, encoding);
} else {
assert(false, "Unexpected SatpMode");
}
maybe_cache_translation(vaddr, op, result);
return result;
canonical_vaddr?
Returns whether or not vaddr is a valid (i.e., canonical) virtual address.
If pointer masking (S**pm) is enabled, then vaddr will be masked before checking the canonical address.
Return Type |
|
---|---|
Arguments |
|
if (CSR[misa].S == 1'b0) {
return true;
}
SatpMode satp_mode;
if (virtual_mode?()) {
satp_mode = CSR[vsatp].MODE;
} else {
satp_mode = CSR[satp].MODE;
}
XReg eaddr = mask_eaddr(vaddr);
if (satp_mode == SatpMode::Bare) {
return true;
} else if (satp_mode == SatpMode::Sv32) {
return true;
} else if (satp_mode == SatpMode::Sv39) {
return eaddr[63:39] == {25{eaddr[38]}};
} else if (satp_mode == SatpMode::Sv48) {
return eaddr[63:48] == {16{eaddr[47]}};
} else if (satp_mode == SatpMode::Sv57) {
return eaddr[63:57] == {6{eaddr[56]}};
}
canonical_gpaddr?
Returns whether or not gpaddr is a valid (i.e., canonical) guest physical address.
Return Type |
|
---|---|
Arguments |
|
SatpMode satp_mode = CSR[satp].MODE;
if (satp_mode == SatpMode::Bare) {
return true;
} else if (satp_mode == SatpMode::Sv32) {
return true;
} else if ((XLEN > 32) && (satp_mode == SatpMode::Sv39)) {
return gpaddr[63:39] == {25{gpaddr[38]}};
} else if ((XLEN > 32) && (satp_mode == SatpMode::Sv48)) {
return gpaddr[63:48] == {16{gpaddr[47]}};
} else if ((XLEN > 32) && (satp_mode == SatpMode::Sv57)) {
return gpaddr[63:57] == {6{gpaddr[56]}};
}
misaligned_is_atomic?
Returns true if an access starting at physical_address that is N bits long is atomic.
This function takes into account any Atomicity Granule PMAs, so it should not be used for load-reserved/store-conditional, since those PMAs do not apply to those accesses.
Return Type |
|
---|---|
Arguments |
|
return false if (MISALIGNED_MAX_ATOMICITY_GRANULE_SIZE == 0);
if (pma_applies?(PmaAttribute::MAG16, physical_address, N) && in_naturally_aligned_region?<128>(physical_address, N)) {
return true;
} else if (pma_applies?(PmaAttribute::MAG8, physical_address, N) && in_naturally_aligned_region?<4>(physical_address, N)) {
return true;
} else if (pma_applies?(PmaAttribute::MAG4, physical_address, N) && in_naturally_aligned_region?<32>(physical_address, N)) {
return true;
} else if (pma_applies?(PmaAttribute::MAG2, physical_address, N) && in_naturally_aligned_region?<16>(physical_address, N)) {
return true;
} else {
return false;
}
read_memory_aligned
Read from virtual memory using a known aligned address.
Return Type |
|
---|---|
Arguments |
|
TranslationResult result;
if (CSR[misa].S == 1) {
result = translate(virtual_address, MemoryOperation::Read, effective_ldst_mode(), encoding);
} else {
result.paddr = virtual_address;
}
access_check(result.paddr, LEN, virtual_address, MemoryOperation::Read, ExceptionCode::LoadAccessFault, effective_ldst_mode());
return read_physical_memory<LEN>(result.paddr);
read_memory
Read from virtual memory.
Return Type |
|
---|---|
Arguments |
|
Boolean aligned = is_naturally_aligned<LEN>(virtual_address);
XReg physical_address;
if (aligned) {
return read_memory_aligned<LEN>(virtual_address, encoding);
}
if (MISALIGNED_MAX_ATOMICITY_GRANULE_SIZE > 0) {
assert(MISALIGNED_LDST_EXCEPTION_PRIORITY == "low", "Invalid config: can't mix low-priority misaligned exceptions with large atomicity granule");
physical_address = (CSR[misa].S == 1) ? translate(virtual_address, MemoryOperation::Read, effective_ldst_mode(), encoding).paddr : virtual_address;
if (misaligned_is_atomic?<LEN>(physical_address)) {
access_check(physical_address, LEN, virtual_address, MemoryOperation::Read, ExceptionCode::LoadAccessFault, effective_ldst_mode());
return read_physical_memory<LEN>(physical_address);
}
}
if (!MISALIGNED_LDST) {
if (MISALIGNED_LDST_EXCEPTION_PRIORITY == "low") {
physical_address = (CSR[misa].S == 1) ? translate(virtual_address, MemoryOperation::Read, effective_ldst_mode(), encoding).paddr : virtual_address;
access_check(physical_address, LEN, virtual_address, MemoryOperation::Read, ExceptionCode::LoadAccessFault, effective_ldst_mode());
}
raise(ExceptionCode::LoadAddressMisaligned, effective_ldst_mode(), virtual_address);
} else {
if (MISALIGNED_SPLIT_STRATEGY == "by_byte") {
Bits<LEN> result = 0;
for (U32 i = 0; i <= LEN; i++) {
result = result | (read_memory_aligned<8>(virtual_address + i, encoding) << (8 * i));
}
return result;
} else if (MISALIGNED_SPLIT_STRATEGY == "custom") {
unpredictable("An implementation is free to break a misaligned access any way, leading to unpredictable behavior when any part of the misaligned access causes an exception");
}
}
invalidate_reservation_set
Invalidates any currently held reservation set.
This function may be called by the platform, independent of any actions occurring in the local hart, for any or no reason. The platorm must call this function if an external hart or device accesses part of this reservation set while reservation_set_valid could be true. |
Return Type |
|
---|---|
Arguments |
None |
reservation_set_valid = false;
register_reservation_set
Register a reservation for a physical address range that subsumes [physical_address, physical_address + N).
Return Type |
|
---|---|
Arguments |
|
reservation_set_valid = true;
reservation_set_address = physical_address;
if (LRSC_RESERVATION_STRATEGY == "reserve naturally-aligned 64-byte region") {
reservation_set_address = physical_address & ~XLEN'h3f;
reservation_set_size = 64;
} else if (LRSC_RESERVATION_STRATEGY == "reserve naturally-aligned 128-byte region") {
reservation_set_address = physical_address & ~XLEN'h7f;
reservation_set_size = 128;
} else if (LRSC_RESERVATION_STRATEGY == "reserve exactly enough to cover the access") {
reservation_set_address = physical_address;
reservation_set_size = length;
} else if (LRSC_RESERVATION_STRATEGY == "custom") {
unpredictable("Implementations may set reservation sets of any size, as long as they cover the reserved accessed");
} else {
assert(false, "Unexpected LRSC_RESERVATION_STRATEGY");
}
load_reserved
Register a reservation for virtual_address at least N bits long and read the value from memory.
If aq is set, then also perform a memory model acquire.
If rl is set, then also perform a memory model release (software is discouraged from doing so).
This function assumes alignment checks have already occurred.
Return Type |
|
---|---|
Arguments |
|
Bits<PHYS_ADDR_WIDTH> physical_address = (CSR[misa].S == 1) ? translate(virtual_address, MemoryOperation::Read, effective_ldst_mode(), encoding).paddr : virtual_address;
if (pma_applies?(PmaAttribute::RsrvNone, physical_address, N)) {
raise(ExceptionCode::LoadAccessFault, effective_ldst_mode(), virtual_address);
}
if (aq == 1) {
memory_model_acquire();
}
if (rl == 1) {
memory_model_release();
}
register_reservation_set(physical_address, N);
if (CSR[misa].S == 1 && LRSC_FAIL_ON_VA_SYNONYM) {
reservation_virtual_address = virtual_address;
}
return read_memory_aligned<N>(physical_address, encoding);
store_conditional
Atomically check the reservation set to ensure:
-
it is valid
-
it covers the region addressed by this store
-
the address setting the reservation set matches virtual address
If the preceeding are met, perform the store and return 0. Otherwise, return 1.
Return Type |
|
---|---|
Arguments |
|
Bits<PHYS_ADDR_WIDTH> physical_address = (CSR[misa].S == 1) ? translate(virtual_address, MemoryOperation::Write, effective_ldst_mode(), encoding).paddr : virtual_address;
if (pma_applies?(PmaAttribute::RsrvNone, physical_address, N)) {
raise(ExceptionCode::StoreAmoAccessFault, effective_ldst_mode(), virtual_address);
}
access_check(physical_address, N, virtual_address, MemoryOperation::Write, ExceptionCode::StoreAmoAccessFault, effective_ldst_mode());
if (aq == 1) {
memory_model_acquire();
}
if (rl == 1) {
memory_model_release();
}
if (reservation_set_valid == false) {
return false;
}
if (!contains?(reservation_set_address, reservation_set_size, physical_address, N)) {
invalidate_reservation_set();
return false;
}
if (LRSC_FAIL_ON_NON_EXACT_LRSC) {
if (reservation_physical_address != physical_address || reservation_size != N) {
invalidate_reservation_set();
return false;
}
}
if (LRSC_FAIL_ON_VA_SYNONYM) {
if (reservation_virtual_address != virtual_address || reservation_size != N) {
invalidate_reservation_set();
return false;
}
}
write_physical_memory<N>(physical_address, value);
return true;
amo
Atomically read-modify-write the location at virtual_address.
The value written to virtual_address will depend on op.
If aq is 1, then the amo also acts as a memory model acquire. If rl is 1, then the amo also acts as a memory model release.
Return Type |
|
---|---|
Arguments |
|
Boolean aligned = is_naturally_aligned<N>(virtual_address);
if (!aligned && MISALIGNED_LDST_EXCEPTION_PRIORITY == "high") {
raise(ExceptionCode::StoreAmoAddressMisaligned, effective_ldst_mode(), virtual_address);
}
Bits<PHYS_ADDR_WIDTH> physical_address = (CSR[misa].S == 1) ? translate(virtual_address, MemoryOperation::ReadModifyWrite, effective_ldst_mode(), encoding).paddr : virtual_address;
if (pma_applies?(PmaAttribute::AmoNone, physical_address, N)) {
raise(ExceptionCode::StoreAmoAccessFault, effective_ldst_mode(), virtual_address);
} else if (op == AmoOperation::Add || op == AmoOperation::Max || op == AmoOperation::Maxu || op == AmoOperation::Min || op == AmoOperation::Minu && !pma_applies?(PmaAttribute::AmoArithmetic, physical_address, N)) {
raise(ExceptionCode::StoreAmoAccessFault, effective_ldst_mode(), virtual_address);
} else if (op == AmoOperation::And || op == AmoOperation::Or || op == AmoOperation::Xor && !pma_applies?(PmaAttribute::AmoLogical, physical_address, N)) {
raise(ExceptionCode::StoreAmoAccessFault, effective_ldst_mode(), virtual_address);
} else {
assert(pma_applies?(PmaAttribute::AmoSwap, physical_address, N) && op == AmoOperation::Swap, "Bad AMO operation");
}
if (!aligned && !misaligned_is_atomic?<N>(physical_address)) {
raise(ExceptionCode::StoreAmoAddressMisaligned, effective_ldst_mode(), virtual_address);
}
if (N == 32) {
return atomic_read_modify_write_32(physical_address, value, op);
} else {
return atomic_read_modify_write_64(physical_address, value, op);
}
write_memory_aligned
Write to virtual memory using a known aligned address.
Return Type |
|
---|---|
Arguments |
|
XReg physical_address;
physical_address = (CSR[misa].S == 1) ? translate(virtual_address, MemoryOperation::Write, effective_ldst_mode(), encoding).paddr : virtual_address;
access_check(physical_address, LEN, virtual_address, MemoryOperation::Write, ExceptionCode::StoreAmoAccessFault, effective_ldst_mode());
write_physical_memory<LEN>(physical_address, value);
write_memory
Write to virtual memory
Return Type |
|
---|---|
Arguments |
|
Boolean aligned = is_naturally_aligned<LEN>(virtual_address);
XReg physical_address;
if (aligned) {
write_memory_aligned<LEN>(virtual_address, value, encoding);
}
if (MISALIGNED_MAX_ATOMICITY_GRANULE_SIZE > 0) {
assert(MISALIGNED_LDST_EXCEPTION_PRIORITY == "low", "Invalid config: can't mix low-priority misaligned exceptions with large atomicity granule");
physical_address = (CSR[misa].S == 1) ? translate(virtual_address, MemoryOperation::Write, effective_ldst_mode(), encoding).paddr : virtual_address;
if (misaligned_is_atomic?<LEN>(physical_address)) {
access_check(physical_address, LEN, virtual_address, MemoryOperation::Write, ExceptionCode::StoreAmoAccessFault, effective_ldst_mode());
write_physical_memory<LEN>(physical_address, value);
}
}
if (!MISALIGNED_LDST) {
if (MISALIGNED_LDST_EXCEPTION_PRIORITY == "low") {
physical_address = (CSR[misa].S == 1) ? translate(virtual_address, MemoryOperation::Write, effective_ldst_mode(), encoding).paddr : virtual_address;
access_check(physical_address, LEN, virtual_address, MemoryOperation::Write, ExceptionCode::StoreAmoAccessFault, effective_ldst_mode());
}
raise(ExceptionCode::StoreAmoAddressMisaligned, effective_ldst_mode(), virtual_address);
} else {
if (MISALIGNED_SPLIT_STRATEGY == "by_byte") {
for (U32 i = 0; i <= LEN; i++) {
write_memory_aligned<8>(virtual_address + i, (value >> (8 * i))[7:0], encoding);
}
} else if (MISALIGNED_SPLIT_STRATEGY == "custom") {
unpredictable("An implementation is free to break a misaligned access any way, leading to unpredictable behavior when any part of the misaligned access causes an exception");
}
}
mstatus_sd_has_known_reset
Returns true if the mstatus.SD bit has a defined reset value, as determined by various parameters.
Return Type |
|
---|---|
Arguments |
None |
Boolean fs_has_single_value = !implemented?(ExtensionName::F || ($array_size(MSTATUS_FS_LEGAL_VALUES) == 1));
Boolean vs_has_single_value = !implemented?(ExtensionName::V || ($array_size(MSTATUS_VS_LEGAL_VALUES) == 1));
return fs_has_single_value && vs_has_single_value;
mstatus_sd_reset_value
Returns the reset value of mstatus.SD when known
Return Type |
|
---|---|
Arguments |
None |
assert(mstatus_sd_has_known_reset(), "mstatus_sd_reset_value is only defined when mstatus_sd_has_known_reset() == true");
Bits<2> fs_value, vs_value;
if ((!implemented?(ExtensionName::F)) || ($array_size(MSTATUS_FS_LEGAL_VALUES) == 1)) {
fs_value = (!implemented?(ExtensionName::F)) ? 0 : MSTATUS_FS_LEGAL_VALUES[0];
}
if ((!implemented?(ExtensionName::V)) || ($array_size(MSTATUS_VS_LEGAL_VALUES) == 1)) {
fs_value = (!implemented?(ExtensionName::V)) ? 0 : MSTATUS_VS_LEGAL_VALUES[0];
}
return fs_value == 3) || (vs_value == 3 ? 1 : 0;