Functions
implemented? (generated)
Return true if the implementation supports extension.
Return Type |
Boolean |
|---|---|
Arguments |
ExtensionName extension |
mode
Returns the current active privilege mode.
Return Type |
PrivilegeMode |
|---|---|
Arguments |
-
Original
-
Pruned
if ((!implemented?(ExtensionName::S)) && (!implemented?(ExtensionName::U)) && (!implemented?(ExtensionName::H))) { return PrivilegeMode::M; } else { return current_mode; }
return current_mode;
unreachable (builtin)
Indicate that the IDL line should be unreachable.
If this function is called, it represents a bug in the IDL code.
Return Type |
void |
|---|---|
Arguments |
xlen
Returns the effective XLEN for the current privilege mode.
Return Type |
Bits<8> |
|---|---|
Arguments |
-
Original
-
Pruned
if (MXLEN == 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 {
unreachable();
}
} 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 {
unreachable();
}
} 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 {
unreachable();
}
} 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 {
unreachable();
}
} 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;
} else {
unreachable();
}
} else {
unreachable();
}
}
if (mode() == PrivilegeMode::M) { return 64; } else if (mode() == PrivilegeMode::S) { if (CSR[mstatus].SXL == $bits(XRegWidth::XLEN32)) { return 32; } else if (CSR[mstatus].SXL == $bits(XRegWidth::XLEN64)) { return 64; } else { unreachable(); } } else if (mode() == PrivilegeMode::U) { if (CSR[mstatus].UXL == $bits(XRegWidth::XLEN32)) { return 32; } else if (CSR[mstatus].UXL == $bits(XRegWidth::XLEN64)) { return 64; } else { unreachable(); } } else if (mode() == PrivilegeMode::VS) { if (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN32)) { return 32; } else if (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN64)) { return 64; } else { unreachable(); } } else if (mode() == PrivilegeMode::VU) { if (CSR[vsstatus].UXL == $bits(XRegWidth::XLEN32)) { return 32; } else if (CSR[vsstatus].UXL == $bits(XRegWidth::XLEN64)) { return 64; } else { unreachable(); } } else { unreachable(); }
creg2reg
Maps a C register index (e.g., rs1' in the specification) to an X register index. From the
specification:
|
|
Return Type |
Bits<5> |
|---|---|
Arguments |
Bits<3> creg_idx |
-
Original
-
Pruned
return {2'b01, creg_idx};
return {2'b01, creg_idx};
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 |
XReg |
|---|---|
Arguments |
XReg value, XReg first_extended_bit |
-
Original
-
Pruned
if (first_extended_bit == MXLEN) {
return value;
} else {
Bits<1> sign = value[first_extended_bit - 1];
for (U32 i = MXLEN - 1; i >= first_extended_bit; i--) {
value[i] = sign;
}
return value;
}
if (first_extended_bit == 7'64) {
return value;
} else {
Bits<1> sign = value[first_extended_bit - 1];
for (U32 i = 7'63; i >= first_extended_bit; i--) {
value[i] = sign;
}
return value;
}
ialign
Returns IALIGN, the smallest instruction encoding size, in bits.
Return Type |
Bits<6> |
|---|---|
Arguments |
-
Original
-
Pruned
if (implemented?(ExtensionName::C) && (CSR[misa].C == 0x1)) { return 16; } else { return 32; }
return 16;
exception_handling_mode
Returns the target privilege mode that will handle synchronous exception exception_code
Return Type |
PrivilegeMode |
|---|---|
Arguments |
ExceptionCode exception_code |
-
Original
-
Pruned
if (mode() == PrivilegeMode::M) { return PrivilegeMode::M; } else if (implemented?(ExtensionName::S) && mode() == PrivilegeMode::HS) || (mode() == PrivilegeMode::U) { if (($bits(CSR[CSR[medeleg]]) & (MXLEN'1 << $bits(exception_code))) != 0) { return PrivilegeMode::HS; } else { return PrivilegeMode::M; } } else if (implemented?(ExtensionName::H) && mode() == PrivilegeMode::VS) || (mode() == PrivilegeMode::VU) { if (($bits(CSR[CSR[medeleg]]) & (MXLEN'1 << $bits(exception_code))) != 0) { if (($bits(CSR[CSR[hedeleg]]) & (MXLEN'1 << $bits(exception_code))) != 0) { return PrivilegeMode::VS; } else { return PrivilegeMode::HS; } } else { return PrivilegeMode::M; } } else { unreachable(); }
if (mode() == PrivilegeMode::M) { return PrivilegeMode::M; } else if (mode() == PrivilegeMode::S) || (mode() == PrivilegeMode::U) { if (($bits(CSR[CSR[medeleg]]) & (MXLEN'1 << $bits(exception_code))) != 0) { return PrivilegeMode::S; } else { return PrivilegeMode::M; } } else if (mode() == PrivilegeMode::VS) || (mode() == PrivilegeMode::VU) { if (($bits(CSR[CSR[medeleg]]) & (MXLEN'1 << $bits(exception_code))) != 0) { if (($bits(CSR[CSR[hedeleg]]) & (MXLEN'1 << $bits(exception_code))) != 0) { return PrivilegeMode::VS; } else { return PrivilegeMode::S; } } else { return PrivilegeMode::M; } } else { unreachable(); }
mtval_readonly?
Returns whether or not CSR[mtval] is read-only based on implementation options
Return Type |
Boolean |
|---|---|
Arguments |
-
Original
-
Pruned
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);
return false;
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 |
XReg |
|---|---|
Arguments |
ExceptionCode exception_code, XReg tval |
-
Original
-
Pruned
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;
}
if (exception_code == ExceptionCode::Breakpoint) {
return tval;
} else if (exception_code == ExceptionCode::LoadAddressMisaligned) {
return tval;
} else if (exception_code == ExceptionCode::StoreAmoAddressMisaligned) {
return tval;
} else if (exception_code == ExceptionCode::InstructionAddressMisaligned) {
return tval;
} else if (exception_code == ExceptionCode::LoadAccessFault) {
return tval;
} else if (exception_code == ExceptionCode::StoreAmoAccessFault) {
return tval;
} else if (exception_code == ExceptionCode::InstructionAccessFault) {
return tval;
} else if (exception_code == ExceptionCode::LoadPageFault) {
return tval;
} else if (exception_code == ExceptionCode::StoreAmoPageFault) {
return tval;
} else if (exception_code == ExceptionCode::InstructionPageFault) {
return tval;
} else if (exception_code == ExceptionCode::IllegalInstruction) {
return tval;
} else if (exception_code == ExceptionCode::SoftwareCheck) {
return tval;
} else {
return 0;
}
stval_readonly?
Returns whether or not CSR[stval] is read-only based on implementation options
Return Type |
Boolean |
|---|---|
Arguments |
-
Original
-
Pruned
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; }
return false;
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 |
XReg |
|---|---|
Arguments |
ExceptionCode exception_code, XReg tval |
-
Original
-
Pruned
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;
}
if (exception_code == ExceptionCode::Breakpoint) {
return tval;
} else if (exception_code == ExceptionCode::LoadAddressMisaligned) {
return tval;
} else if (exception_code == ExceptionCode::StoreAmoAddressMisaligned) {
return tval;
} else if (exception_code == ExceptionCode::InstructionAddressMisaligned) {
return tval;
} else if (exception_code == ExceptionCode::LoadAccessFault) {
return tval;
} else if (exception_code == ExceptionCode::StoreAmoAccessFault) {
return tval;
} else if (exception_code == ExceptionCode::InstructionAccessFault) {
return tval;
} else if (exception_code == ExceptionCode::LoadPageFault) {
return tval;
} else if (exception_code == ExceptionCode::StoreAmoPageFault) {
return tval;
} else if (exception_code == ExceptionCode::InstructionPageFault) {
return tval;
} else if (exception_code == ExceptionCode::IllegalInstruction) {
return tval;
} else if (exception_code == ExceptionCode::SoftwareCheck) {
return tval;
} else {
return 0;
}
vstval_readonly?
Returns whether or not CSR[vstval] is read-only based on implementation options
Return Type |
Boolean |
|---|---|
Arguments |
-
Original
-
Pruned
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; }
return false;
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 |
XReg |
|---|---|
Arguments |
ExceptionCode exception_code, XReg tval |
-
Original
-
Pruned
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;
}
if (exception_code == ExceptionCode::Breakpoint) {
return tval;
} else if (exception_code == ExceptionCode::LoadAddressMisaligned) {
return tval;
} else if (exception_code == ExceptionCode::StoreAmoAddressMisaligned) {
return tval;
} else if (exception_code == ExceptionCode::InstructionAddressMisaligned) {
return tval;
} else if (exception_code == ExceptionCode::LoadAccessFault) {
return tval;
} else if (exception_code == ExceptionCode::StoreAmoAccessFault) {
return tval;
} else if (exception_code == ExceptionCode::InstructionAccessFault) {
return tval;
} else if (exception_code == ExceptionCode::LoadPageFault) {
return tval;
} else if (exception_code == ExceptionCode::StoreAmoPageFault) {
return tval;
} else if (exception_code == ExceptionCode::InstructionPageFault) {
return tval;
} else if (exception_code == ExceptionCode::IllegalInstruction) {
return tval;
} else if (exception_code == ExceptionCode::SoftwareCheck) {
return tval;
} else {
return 0;
}
notify_mode_change (builtin)
Called whenever the privilege mode changes. Downstream tools can use this to hook events.
Return Type |
void |
|---|---|
Arguments |
PrivilegeMode new_mode, PrivilegeMode old_mode |
implemented_version? (generated)
Return true if the implementation supports extension meeting 'version_requirement'.
Return Type |
Boolean |
|---|---|
Arguments |
ExtensionName extension, String version_requirement |
refresh_pending_interrupts
refreshes the calculation of a pending interrupt
needs to be called after any state update that could change a pending interrupt. This includes: - CSR[mip] - CSR[mie] - CSR[mstatus].MIE - CSR[mstatus].SIE - CSR[vsstatus].SIE - CSR[mideleg] - CSR[sideleg] - CSR[hideleg] - CSR[hvip] - CSR[hgeip] - CSR[hgeie] - mode changes
Return Type |
void |
|---|---|
Arguments |
-
Original
-
Pruned
Bits<MXLEN> pending_ints = CSR[CSR[mip]].sw_read() & $bits(CSR[CSR[mie]]); if (pending_ints == 0) { pending_and_enabled_interrupts = 0; return ; } Boolean HAS_MIDELEG = implemented_version?(ExtensionName::S, "<= 1.9.1") || (implemented_version?(ExtensionName::S, "> 1.9.1") && implemented_version?(ExtensionName::Sm, "> 1.9.1")); Bits<MXLEN> mmode_enabled_ints = mode() == PrivilegeMode::M) && (CSR[mstatus].MIE == 1'b0 ? 0 : ($bits(CSR[CSR[mie]]) & (HAS_MIDELEG ? ~$bits(CSR[CSR[mideleg]]) : ~MXLEN'0)); Bits<MXLEN> mmode_pending_and_enabled = pending_ints & mmode_enabled_ints; if (mmode_pending_and_enabled != 0) { pending_and_enabled_interrupts = mmode_pending_and_enabled; return ; } if (CSR[misa].S == 1'b1) { Bits<MXLEN> smode_enabled_ints = mode() == PrivilegeMode::M) || (CSR[mstatus].SIE == 1'b0 ? 0 : $bits(CSR[CSR[mie]]) & ($bits(CSR[CSR[mideleg]])); Bits<MXLEN> smode_pending_and_enabled = pending_ints & smode_enabled_ints; if (smode_pending_and_enabled != 0) { pending_and_enabled_interrupts = smode_pending_and_enabled; return ; } } pending_and_enabled_interrupts = 0;
Bits<MXLEN> pending_ints = CSR[CSR[mip]].sw_read() & $bits(CSR[CSR[mie]]); if (pending_ints == 0) { pending_and_enabled_interrupts = 0; return ; } Boolean HAS_MIDELEG = true; Bits<MXLEN> mmode_enabled_ints = mode() == PrivilegeMode::M) && (CSR[mstatus].MIE == 1'b0 ? 0 : ($bits(CSR[CSR[mie]]) & (~$bits(CSR[CSR[mideleg]]))); Bits<MXLEN> mmode_pending_and_enabled = pending_ints & mmode_enabled_ints; if (mmode_pending_and_enabled != 0) { pending_and_enabled_interrupts = mmode_pending_and_enabled; return ; } Bits<MXLEN> smode_enabled_ints = mode() == PrivilegeMode::M) || (CSR[mstatus].SIE == 1'b0 ? 0 : $bits(CSR[CSR[mie]]) & ($bits(CSR[CSR[mideleg]])); Bits<MXLEN> smode_pending_and_enabled = pending_ints & smode_enabled_ints; if (smode_pending_and_enabled != 0) { pending_and_enabled_interrupts = smode_pending_and_enabled; return ; } pending_and_enabled_interrupts = 0;
set_mode
Set the current privilege mode to new_mode
Return Type |
void |
|---|---|
Arguments |
PrivilegeMode new_mode |
-
Original
-
Pruned
if (new_mode != current_mode) {
notify_mode_change(new_mode, current_mode);
current_mode = new_mode;
refresh_pending_interrupts();
}
if (new_mode != current_mode) {
notify_mode_change(new_mode, current_mode);
current_mode = new_mode;
refresh_pending_interrupts();
}
abort_current_instruction (builtin)
Abort the current instruction, and start refetching from $pc.
Return Type |
void |
|---|---|
Arguments |
raise_precise
Raise synchronous exception number exception_code.
Return Type |
void |
|---|---|
Arguments |
ExceptionCode exception_code, PrivilegeMode from_mode, XReg tval |
-
Original
-
Pruned
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 (implemented?(ExtensionName::H) && CSR[misa].H == 1) { CSR[mtval2].VALUE = 0; CSR[mtinst].VALUE = 0; if (from_mode == PrivilegeMode::VU || from_mode == PrivilegeMode::VS) { if (MXLEN == 32) { CSR[mstatush].MPV = 1; } else { CSR[mstatus].MPV = 1; } } else { if (MXLEN == 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();
PrivilegeMode handling_mode = exception_handling_mode(exception_code); if (handling_mode == PrivilegeMode::M) { CSR[mepc].PC = $pc; 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); CSR[mtval2].VALUE = 0; CSR[mtinst].VALUE = 0; if (from_mode == PrivilegeMode::VU || from_mode == PrivilegeMode::VS) { CSR[mstatus].MPV = 1; } else { CSR[mstatus].MPV = 0; } CSR[mstatus].MPP = $bits(from_mode); } else if ((handling_mode == PrivilegeMode::S)) { CSR[sepc].PC = $pc; 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]; 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) || (exception_code == ExceptionCode::LoadAddressMisaligned) || (exception_code == ExceptionCode::StoreAmoAddressMisaligned) || (exception_code == ExceptionCode::InstructionAddressMisaligned) || (exception_code == ExceptionCode::LoadAccessFault) || (exception_code == ExceptionCode::StoreAmoAccessFault) || (exception_code == ExceptionCode::InstructionAccessFault) || (exception_code == ExceptionCode::LoadPageFault) || (exception_code == ExceptionCode::StoreAmoPageFault) || (exception_code == ExceptionCode::InstructionPageFault)) { 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 ((handling_mode == PrivilegeMode::VS)) { CSR[vsepc].PC = $pc; 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();
raise
Raise synchronous exception number exception_code.
The exception may be imprecise, and will cause execution to enter an unpredictable state, if PRECISE_SYNCHRONOUS_EXCEPTIONS is false.
Otherwise, the exception will be precise.
Return Type |
void |
|---|---|
Arguments |
ExceptionCode exception_code, PrivilegeMode from_mode, XReg tval |
-
Original
-
Pruned
if (!PRECISE_SYNCHRONOUS_EXCEPTIONS) {
unpredictable("Imprecise synchronous exception");
} else {
raise_precise(exception_code, from_mode, tval);
}
raise_precise(exception_code, from_mode, tval);
jump
Jump to virtual address target_addr.
If target address is misaligned, raise a MisalignedAddress exception.
Return Type |
void |
|---|---|
Arguments |
XReg target_addr |
-
Original
-
Pruned
is_naturally_aligned
Checks if value is naturally aligned to N bits.
Return Type |
Boolean |
|---|---|
Arguments |
U32 N, XReg value |
-
Original
-
Pruned
return true if (N == 8); XReg Mask = (N / 8) - 1; return (value & ~Mask) == value;
return true if (N == 8); XReg Mask = (N / 8) - 1; return (value & ~Mask) == value;
mpv
Returns the current value of CSR[mstatus].MPV (when MXLEN == 64) of CSR[mstatush].MPV (when MXLEN == 32)
Return Type |
Bits<1> |
|---|---|
Arguments |
-
Original
-
Pruned
if (implemented?(ExtensionName::H)) { return (MXLEN == 32) ? CSR[mstatush].MPV : CSR[mstatus].MPV; } else { assert(false, "TODO"); unreachable(); }
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 |
PrivilegeMode |
|---|---|
Arguments |
-
Original
-
Pruned
if (mode() == PrivilegeMode::M) { if (CSR[misa].U == 1 && CSR[mstatus].MPRV == 1) { if (CSR[mstatus].MPP == 0b00) { if (implemented?(ExtensionName::H) && CSR[misa].H == 1 && mpv() == 0b1) { return PrivilegeMode::VU; } else { return PrivilegeMode::U; } } else if (CSR[misa].S == 1 && CSR[mstatus].MPP == 0b01) { if (implemented?(ExtensionName::H) && CSR[misa].H == 1 && mpv() == 0b1) { return PrivilegeMode::VS; } else { return PrivilegeMode::S; } } } } return mode();
if (mode() == PrivilegeMode::M) { if (CSR[mstatus].MPRV == 1) { if (CSR[mstatus].MPP == 0b00) { if (mpv() == 0b1) { return PrivilegeMode::VU; } else { return PrivilegeMode::U; } } else if (CSR[mstatus].MPP == 0b01) { if (mpv() == 0b1) { return PrivilegeMode::VS; } else { return PrivilegeMode::S; } } } } return mode();
cached_translation (generated)
Possibly returns a cached translation result matching vaddr.
CachedTranslationResult contains a Boolean 'valid' field. If valid, 'result' is a usable translation. Otherwise, the cache lookup failed.
Return Type |
CachedTranslationResult |
|---|---|
Arguments |
XReg vaddr, MemoryOperation op |
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 |
SatpMode |
|---|---|
Arguments |
PrivilegeMode mode |
-
Original
-
Pruned
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::Bare)) { return SatpMode::Bare; } else if (mode_val == $bits(SatpMode::Sv32)) { if (MXLEN == 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 ((MXLEN == 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 ((MXLEN == 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 ((MXLEN == 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; } } else { return SatpMode::Reserved; } } else if (CSR[misa].S == 1'b1) { assert(effective_mode == PrivilegeMode::S || effective_mode == PrivilegeMode::U, "unexpected priv mode"); Bits<4> mode_val = CSR[satp].MODE; if (mode_val == $bits(SatpMode::Bare)) { return SatpMode::Bare; } else if (mode_val == $bits(SatpMode::Sv32)) { if (MXLEN == 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; } return SatpMode::Sv32; } else if ((MXLEN == 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 ((MXLEN == 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 ((MXLEN == 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; } } else { return SatpMode::Reserved; }
PrivilegeMode effective_mode = effective_ldst_mode(); if (effective_mode == PrivilegeMode::M) { return SatpMode::Bare; } if (effective_mode == PrivilegeMode::VS || effective_mode == PrivilegeMode::VU) { Bits<4> mode_val = CSR[vsatp].MODE; if (mode_val == $bits(SatpMode::Bare)) { return SatpMode::Bare; } else if (mode_val == $bits(SatpMode::Sv32)) { 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 ((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; } return SatpMode::Sv39; } else if ((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; } return SatpMode::Sv48; } else if ((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; } return SatpMode::Sv57; } else { return SatpMode::Reserved; } } else { return SatpMode::Reserved; }
tinst_value_for_guest_page_fault
Returns the value of htinst/mtinst for a Guest Page Fault
Return Type |
XReg |
|---|---|
Arguments |
MemoryOperation op, Bits<INSTR_ENC_SIZE> encoding, Boolean for_final_vs_pte |
-
Original
-
Pruned
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 (($array_size(VSXLEN) == 1 && VSXLEN[0] == 32) || MXLEN == 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");
return 0;
}
} 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 (($array_size(VSXLEN) == 1 && VSXLEN[0] == 32) || MXLEN == 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");
return 0;
}
}
} else {
if (REPORT_GPA_IN_TVAL_ON_INTERMEDIATE_GUEST_PAGE_FAULT) {
if (($array_size(VSXLEN) == 1 && VSXLEN[0] == 32) || MXLEN == 64) && (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN32)) {
return 0x00002000;
} else if (($array_size(VSXLEN) == 1 && VSXLEN[0] == 64) || MXLEN == 64) && (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN64)) {
return 0x00003000;
}
}
}
return 0;
if (for_final_vs_pte) {
if (op == MemoryOperation::Fetch) {
return 0;
} else if (op == MemoryOperation::Read) {
return tinst_transform(encoding, 0);
} else if (op == MemoryOperation::Write || op == MemoryOperation::ReadModifyWrite) {
return tinst_transform(encoding, 0);
}
} else {
if (false || (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN32))) {
return 0x00002000;
} else if (($array_size([7'64]) == 1) || (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN64))) {
return 0x00003000;
}
}
return 0;
assert (builtin)
Assert that a condition is true. Failure represents an error in the IDL model.
Return Type |
void |
|---|---|
Arguments |
Boolean test, String message |
raise_guest_page_fault
Raise a guest page fault exception.
Return Type |
void |
|---|---|
Arguments |
MemoryOperation op, XReg gpa, XReg gva, XReg tinst_value, PrivilegeMode from_mode |
-
Original
-
Pruned
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 (MXLEN == 64) {
CSR[mstatus].MPV = 1;
} else {
CSR[mstatush].MPV = 1;
}
}
set_mode(handling_mode);
abort_current_instruction();
ExceptionCode code;
Boolean write_gpa_in_tval;
if (op == MemoryOperation::Read) {
code = ExceptionCode::LoadGuestPageFault;
write_gpa_in_tval = true;
} else if (op == MemoryOperation::Write || op == MemoryOperation::ReadModifyWrite) {
code = ExceptionCode::StoreAmoGuestPageFault;
write_gpa_in_tval = true;
} else {
assert(op == MemoryOperation::Fetch, "unexpected memory operation");
code = ExceptionCode::InstructionGuestPageFault;
write_gpa_in_tval = true;
}
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;
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];
CSR[mstatus].MPV = 1;
}
set_mode(handling_mode);
abort_current_instruction();
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 |
Boolean |
|---|---|
Arguments |
PmaAttribute attr, Bits<PHYS_ADDR_WIDTH> paddr, U32 len |
direct_csr_lookup (generated)
Return CSR info for a CSR with direct address csr_addr.
If no CSR exists, <return_value>.valid == false
Return Type |
Csr |
|---|---|
Arguments |
Bits<12> csr_addr |
csr_sw_read (generated)
Returns the result of CSR[csr].sw_read(); i.e., the software view of the register
Return Type |
Bits<64> |
|---|---|
Arguments |
Csr csr |
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 |
PmpMatchResult, PmpCfg |
|---|---|
Arguments |
Bits<PHYS_ADDR_WIDTH> paddr, U32 access_size |
-
Original
-
Pruned
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;
Csr pmpcfg_csr = direct_csr_lookup(pmpcfg_idx);
PmpCfg cfg = (csr_hw_read(pmpcfg_csr) >> shamt)[7:0];
Bits<12> pmpaddr_idx = pmpaddr0_addr + i;
Csr pmpaddr_csr = direct_csr_lookup(pmpaddr_idx);
Bits<64> pmpaddr_csr_value = csr_sw_read(pmpaddr_csr);
Bits<PHYS_ADDR_WIDTH> range_base = 0;
Bits<PHYS_ADDR_WIDTH> range_limit = 0;
if (cfg.A == $bits(PmpCfg_A::TOR)) {
if (i == 0) {
range_base = 0;
} else {
Csr tor_pmpaddr_csr = direct_csr_lookup(pmpaddr_idx - 1);
range_base = (csr_sw_read(tor_pmpaddr_csr))[PHYS_ADDR_WIDTH - 1:0];
}
range_limit = (pmpaddr_csr_value)[PHYS_ADDR_WIDTH - 1:0] - 1;
} else if (cfg.A == $bits(PmpCfg_A::NAPOT)) {
Bits<PHYS_ADDR_WIDTH - 1> pmpaddr_value = pmpaddr_csr_value[PHYS_ADDR_WIDTH - 1:0];
Bits<PHYS_ADDR_WIDTH - 1> mask = pmpaddr_value ^ (pmpaddr_value + 1);
range_base = (pmpaddr_value & ~mask);
range_limit = range_base + mask;
} else if (cfg.A == $bits(PmpCfg_A::NA4)) {
range_base = pmpaddr_csr_value[PHYS_ADDR_WIDTH - 1:0];
range_limit = range_base + 3;
}
if (paddr {
return PmpMatchResult::FullMatch, cfg;
} else if (! {
return PmpMatchResult::PartialMatch, -;
}
}
return PmpMatchResult::NoMatch, -;
Bits<12> pmpcfg0_addr = 0x3a0;
Bits<12> pmpaddr0_addr = 0x3b0;
for (U32 i = 0; i < 7'16; i++) {
Bits<12> pmpcfg_idx = 12'h3a0 + (i / 8) * 2;
Bits<6> shamt = (i % 8) * 8;
Csr pmpcfg_csr = direct_csr_lookup(pmpcfg_idx);
PmpCfg cfg = (csr_hw_read(pmpcfg_csr) >> shamt)[7:0];
Bits<12> pmpaddr_idx = 12'h3b0 + i;
Csr pmpaddr_csr = direct_csr_lookup(pmpaddr_idx);
Bits<64> pmpaddr_csr_value = csr_sw_read(pmpaddr_csr);
Bits<PHYS_ADDR_WIDTH> range_base = 0;
Bits<PHYS_ADDR_WIDTH> range_limit = 0;
if (cfg.A == $bits(PmpCfg_A::TOR)) {
if (i == 0) {
range_base = 0;
} else {
Csr tor_pmpaddr_csr = direct_csr_lookup(pmpaddr_idx - 1);
range_base = (csr_sw_read(tor_pmpaddr_csr))[7'55:0];
}
range_limit = pmpaddr_csr_value[7'55:0] - 1;
} else if (cfg.A == $bits(PmpCfg_A::NAPOT)) {
Bits<PHYS_ADDR_WIDTH - 1> pmpaddr_value = pmpaddr_csr_value[7'55:0];
Bits<PHYS_ADDR_WIDTH - 1> mask = pmpaddr_value ^ (pmpaddr_value + 1);
range_base = (pmpaddr_value & ~mask);
range_limit = range_base + mask;
} else if (cfg.A == $bits(PmpCfg_A::NA4)) {
range_base = pmpaddr_csr_value[7'55:0];
range_limit = range_base + 3;
}
if (paddr {
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 |
PmpMatchResult, PmpCfg |
|---|---|
Arguments |
Bits<PHYS_ADDR_WIDTH> paddr, U32 access_size |
-
Original
-
Pruned
if (MXLEN == 64) {
return pmp_match_64(paddr, access_size);
} else {
return pmp_match_32(paddr, access_size);
}
return pmp_match_64(paddr, access_size);
pmp_check
Given a physical address and operation type, return whether or not the access is allowed by PMP.
Return Type |
Boolean |
|---|---|
Arguments |
Bits<PHYS_ADDR_WIDTH> paddr, U32 access_size, MemoryOperation type |
-
Original
-
Pruned
PrivilegeMode mode = effective_ldst_mode(); PmpMatchResult match_result; PmpCfg cfg; (match_result, cfg = pmp_match(paddr, access_size)); 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;
PrivilegeMode mode = effective_ldst_mode(); PmpMatchResult match_result; PmpCfg cfg; (match_result, cfg = pmp_match(paddr, access_size)); 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 |
void |
|---|---|
Arguments |
Bits<PHYS_ADDR_WIDTH> paddr, U32 access_size, XReg vaddr, MemoryOperation type, ExceptionCode fault_type, PrivilegeMode from_mode |
-
Original
-
Pruned
read_physical_memory_32 (builtin)
Read four bytes from physical memory.
Return Type |
Bits<32> |
|---|---|
Arguments |
XReg paddr |
read_physical_memory
Read from physical memory.
Return Type |
XReg |
|---|---|
Arguments |
U32 len, XReg paddr |
-
Original
-
Pruned
if (len == 8) {
return read_physical_memory_8(paddr);
} else if (len == 16) {
return read_physical_memory_16(paddr);
} else if (len == 32) {
return read_physical_memory_32(paddr);
} else if (len == 64) {
return read_physical_memory_64(paddr);
} else {
assert(false, "Invalid len");
return 0;
}
if (len == 8) {
return read_physical_memory_8(paddr);
} else if (len == 16) {
return read_physical_memory_16(paddr);
} else if (len == 32) {
return read_physical_memory_32(paddr);
} else if (len == 64) {
return read_physical_memory_64(paddr);
} else {
assert(false, "Invalid len");
return 0;
}
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 |
TranslationResult |
|---|---|
Arguments |
U32 VA_SIZE, U32 PA_SIZE, U32 PTESIZE, U32 LEVELS, XReg gpaddr, XReg vaddr, MemoryOperation op, PrivilegeMode effective_mode, Boolean for_final_vs_pte, Bits<INSTR_ENC_SIZE> encoding |
-
Original
-
Pruned
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 = implemented?(ExtensionName::Svpbmt) && CSR[menvcfg].PBMTE == 1; Boolean adue = implemented?(ExtensionName::Svadu) && 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); XReg pte = read_physical_memory(PTESIZE, pte_paddr); PteFlags pte_flags = pte[9:0]; if (xlen() == 64) { if ((VA_SIZE != 32) && (pte[58:54] != 0)) { raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } if (!implemented?(ExtensionName::Svrsw60t59b)) { if ((PTESIZE >= 64) && pte[60:59] != 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:0] != 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"); unreachable(); } if (!success) { i = i + 1; } else { result.paddr = pte_paddr; if ((xlen() == 64) && (PTESIZE >= 64)) { result.pbmt = $enum(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 (xlen() == 64) { 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; } } unreachable();
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 = false; Boolean adue = false; 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); XReg pte = read_physical_memory(PTESIZE, pte_paddr); PteFlags pte_flags = pte[9:0]; if (xlen() == 64) { if ((VA_SIZE != 32) && (pte[58:54] != 0)) { raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } if ((PTESIZE >= 64) && pte[60:59] != 0) { raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } if ((PTESIZE >= 64) && pte[63] != 0) { raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } if ((PTESIZE >= 64) && (pte[62:61] != 0)) { raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } if (false && (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:0] != 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)) { 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 (xlen() == 64) { 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; } } unreachable();
read_physical_memory_64 (builtin)
Read eight bytes from physical memory.
Return Type |
Bits<64> |
|---|---|
Arguments |
XReg paddr |
tinst_transform
Returns the standard transformation of an encoding for htinst/mtinst
Return Type |
Bits<INSTR_ENC_SIZE> |
|---|---|
Arguments |
Bits<INSTR_ENC_SIZE> encoding, Bits<5> addr_offset |
-
Original
-
Pruned
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");
unreachable();
}
} else {
assert(false, "TODO: compressed instruction");
unreachable();
}
if (encoding[1:0] == 0b11) {
if (encoding[6:2] == 5'b00001) {
return {12'0, addr_offset, encoding[14:0]};
} else if (encoding[6:2] == 5'b01000) {
return {7'0, encoding[24:20], addr_offset, encoding[14:12], 5'0, 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");
unreachable();
}
} else {
assert(false, "TODO: compressed instruction");
unreachable();
}
translate_gstage
Translates a guest physical address to a physical address.
Return Type |
TranslationResult |
|---|---|
Arguments |
XReg gpaddr, XReg vaddr, MemoryOperation op, PrivilegeMode effective_mode, Bits<INSTR_ENC_SIZE> encoding |
-
Original
-
Pruned
TranslationResult result; if (!implemented?(ExtensionName::H) || 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); } }
TranslationResult result;
if (effective_mode == PrivilegeMode::S || effective_mode == PrivilegeMode::U) {
result.paddr = gpaddr;
return result;
}
Boolean mxr = CSR[mstatus].MXR == 1;
if (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 (CSR[hgatp].MODE == $bits(HgatpMode::Sv39x4)) {
return gstage_page_walk(39, 56, 64, 3, gpaddr, vaddr, op, effective_mode, false, encoding);
} else if (CSR[hgatp].MODE == $bits(HgatpMode::Sv48x4)) {
return gstage_page_walk(48, 56, 64, 4, 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);
}
}
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 |
TranslationResult |
|---|---|
Arguments |
U32 VA_SIZE, U32 PA_SIZE, U32 PTESIZE, U32 LEVELS, Bits<MXLEN> vaddr, MemoryOperation op, PrivilegeMode effective_mode, Bits<INSTR_ENC_SIZE> encoding |
-
Original
-
Pruned
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 = implemented?(ExtensionName::Svadu) && CSR[henvcfg].ADUE == 1; } else { adue = implemented?(ExtensionName::Svadu) && CSR[menvcfg].ADUE == 1; } Boolean pbmte; if ((xlen() == 32) || VA_SIZE == 32) { pbmte = false; } else { if (CSR[misa].H == 1 && (effective_mode == PrivilegeMode::VS || effective_mode == PrivilegeMode::VU)) { pbmte = implemented?(ExtensionName::Svpbmt) && CSR[henvcfg].PBMTE == 1; } else { pbmte = implemented?(ExtensionName::Svpbmt) && 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); ppn = CSR[vsatp].PPN; } else { mxr = CSR[mstatus].MXR == 1; ppn = CSR[satp].PPN; } Boolean sum; if (CSR[misa].H == 1 && (effective_mode == PrivilegeMode::VS)) { sum = CSR[vsstatus].SUM == 1; } else { sum = CSR[mstatus].SUM == 1; } if ((VA_SIZE < xlen()) && (vaddr[xlen() - 1:VA_SIZE] != {xlen() - VA_SIZE{vaddr[VA_SIZE - 1]}})) { raise(page_fault_code, 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, mode(), vaddr); } access_check(pte_phys.paddr, PTESIZE, vaddr, MemoryOperation::Read, access_fault_code, effective_mode); XReg 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 ((xlen() == 64) && (VA_SIZE != 32) && (pte[58:54] != 0)) { raise(page_fault_code, mode(), vaddr); } if (pte_flags.V == 0) { raise(page_fault_code, mode(), vaddr); } if (!sse) { if ((pte_flags.R == 0) && (pte_flags.W == 1)) { raise(page_fault_code, mode(), vaddr); } } if (xlen() == 64) { if (pbmte) { if (pte[62:61] == 3) { raise(page_fault_code, mode(), vaddr); } } else { if ((PTESIZE >= 64) && (pte[62:61] != 0)) { raise(page_fault_code, mode(), vaddr); } } if (!implemented?(ExtensionName::Svrsw60t59b)) { if ((PTESIZE >= 64) && pte[60:59] != 0) { raise(page_fault_code, mode(), vaddr); } } if (!implemented?(ExtensionName::Svnapot)) { if ((PTESIZE >= 64) && (pte[63] != 0)) { raise(page_fault_code, mode(), vaddr); } } } if (pte_flags.R == 1 || pte_flags.X == 1) { Bits<PA_SIZE> paddr_base = pte[PA_SIZE - 3:I * VPN_SIZE + 10] `<< (I * VPN_SIZE + 12); Bits<PA_SIZE> offset = vaddr[I * VPN_SIZE + 11:0]; 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, mode(), vaddr); } if (effective_mode == PrivilegeMode::U && pte_flags.U == 0) { raise(page_fault_code, mode(), vaddr); } else if (CSR[misa].H == 1 && effective_mode == PrivilegeMode::VU && pte_flags.U == 0) { raise(page_fault_code, mode(), vaddr); } else if (effective_mode == PrivilegeMode::S && pte_flags.U == 1 && !sum) { raise(page_fault_code, mode(), vaddr); } else if (effective_mode == PrivilegeMode::VS && pte_flags.U == 1 && !sum) { raise(page_fault_code, mode(), vaddr); } } if (op == MemoryOperation::Write) || (op == MemoryOperation::ReadModifyWrite && (pte_flags.W == 0)) { raise(page_fault_code, mode(), vaddr); } else if ((op == MemoryOperation::Fetch) && (pte_flags.X == 0)) { raise(page_fault_code, mode(), vaddr); } else if ((op == MemoryOperation::Fetch) && ss_page) { raise(page_fault_code, mode(), vaddr); } raise(page_fault_code, 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"); unreachable(); } if (!success) { I = I + 1; } else { TranslationResult pte_phys = translate_gstage(paddr_base + offset, vaddr, op, effective_mode, encoding); result.paddr = pte_phys.paddr; if (xlen() == 64) { result.pbmt = pte_phys.pbmt == Pbmt::PMA ? $enum(Pbmt, pte[62:61]) : pte_phys.pbmt; } result.pte_flags = pte_flags; return result; } } else { raise(page_fault_code, mode(), vaddr); } } TranslationResult pte_phys = translate_gstage(paddr_base + offset, vaddr, op, effective_mode, encoding); result.paddr = pte_phys.paddr; if (xlen() == 64 && 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, mode(), vaddr); } if (pte_flags.D == 1 || pte_flags.A == 1 || pte_flags.U == 1) { raise(page_fault_code, mode(), vaddr); } if ((xlen() == 64) && (VA_SIZE != 32) && (pte[62:61] != 0)) { raise(page_fault_code, mode(), vaddr); } if ((xlen() == 64) && (VA_SIZE != 32) && pte[63] != 0) { raise(page_fault_code, mode(), vaddr); } ppn = pte[PA_SIZE - 3:10]; } } unreachable();
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 ((effective_mode == PrivilegeMode::VS || effective_mode == PrivilegeMode::VU)) {
adue = false;
} else {
adue = false;
}
Boolean pbmte;
if ((xlen() == 32) || VA_SIZE == 32) {
pbmte = false;
} else {
if ((effective_mode == PrivilegeMode::VS || effective_mode == PrivilegeMode::VU)) {
pbmte = false;
} else {
pbmte = false;
}
}
Boolean mxr;
if ((effective_mode == PrivilegeMode::VS || effective_mode == PrivilegeMode::VU)) {
mxr = (CSR[mstatus].MXR == 1) || (CSR[vsstatus].MXR == 1);
ppn = CSR[vsatp].PPN;
} else {
mxr = CSR[mstatus].MXR == 1;
ppn = CSR[satp].PPN;
}
Boolean sum;
if ((effective_mode == PrivilegeMode::VS)) {
sum = CSR[vsstatus].SUM == 1;
} else {
sum = CSR[mstatus].SUM == 1;
}
if ((VA_SIZE < xlen()) && (vaddr[xlen() - 1:VA_SIZE] != {xlen() - VA_SIZE{vaddr[VA_SIZE - 1]}})) {
raise(page_fault_code, 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, mode(), vaddr);
}
access_check(pte_phys.paddr, PTESIZE, vaddr, MemoryOperation::Read, access_fault_code, effective_mode);
XReg 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 ((xlen() == 64) && (VA_SIZE != 32) && (pte[58:54] != 0)) {
raise(page_fault_code, mode(), vaddr);
}
if (pte_flags.V == 0) {
raise(page_fault_code, mode(), vaddr);
}
if ((pte_flags.R == 0) && (pte_flags.W == 1)) {
raise(page_fault_code, mode(), vaddr);
}
if (xlen() == 64) {
if (pbmte) {
if (pte[62:61] == 3) {
raise(page_fault_code, mode(), vaddr);
}
} else {
if ((PTESIZE >= 64) && (pte[62:61] != 0)) {
raise(page_fault_code, mode(), vaddr);
}
}
if ((PTESIZE >= 64) && pte[60:59] != 0) {
raise(page_fault_code, mode(), vaddr);
}
if ((PTESIZE >= 64) && (pte[63] != 0)) {
raise(page_fault_code, mode(), vaddr);
}
}
if (pte_flags.R == 1 || pte_flags.X == 1) {
Bits<PA_SIZE> paddr_base = pte[PA_SIZE - 3:I * VPN_SIZE + 10] `<< (I * VPN_SIZE + 12);
Bits<PA_SIZE> offset = vaddr[I * VPN_SIZE + 11:0];
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, mode(), vaddr);
}
if (effective_mode == PrivilegeMode::U && pte_flags.U == 0) {
raise(page_fault_code, mode(), vaddr);
} else if (effective_mode == PrivilegeMode::VU && pte_flags.U == 0) {
raise(page_fault_code, mode(), vaddr);
} else if (effective_mode == PrivilegeMode::S && pte_flags.U == 1 && !sum) {
raise(page_fault_code, mode(), vaddr);
} else if (effective_mode == PrivilegeMode::VS && pte_flags.U == 1 && !sum) {
raise(page_fault_code, mode(), vaddr);
}
}
if (op == MemoryOperation::Write) || (op == MemoryOperation::ReadModifyWrite && (pte_flags.W == 0)) {
raise(page_fault_code, mode(), vaddr);
} else if ((op == MemoryOperation::Fetch) && (pte_flags.X == 0)) {
raise(page_fault_code, mode(), vaddr);
} else if ((op == MemoryOperation::Fetch) && ss_page) {
raise(page_fault_code, mode(), vaddr);
}
raise(page_fault_code, 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");
unreachable();
}
if (!success) {
I = I + 1;
} else {
TranslationResult pte_phys = translate_gstage(paddr_base + offset, vaddr, op, effective_mode, encoding);
result.paddr = pte_phys.paddr;
if (xlen() == 64) {
result.pbmt = pte_phys.pbmt == Pbmt::PMA ? $enum(Pbmt, pte[62:61]) : pte_phys.pbmt;
}
result.pte_flags = pte_flags;
return result;
}
} else {
raise(page_fault_code, mode(), vaddr);
}
}
TranslationResult pte_phys = translate_gstage(paddr_base + offset, vaddr, op, effective_mode, encoding);
result.paddr = pte_phys.paddr;
if (xlen() == 64 && 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, mode(), vaddr);
}
if (pte_flags.D == 1 || pte_flags.A == 1 || pte_flags.U == 1) {
raise(page_fault_code, mode(), vaddr);
}
if ((xlen() == 64) && (VA_SIZE != 32) && (pte[62:61] != 0)) {
raise(page_fault_code, mode(), vaddr);
}
if ((xlen() == 64) && (VA_SIZE != 32) && pte[63] != 0) {
raise(page_fault_code, mode(), vaddr);
}
ppn = pte[PA_SIZE - 3:10];
}
}
unreachable();
maybe_cache_translation (generated)
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 |
void |
|---|---|
Arguments |
XReg vaddr, MemoryOperation op, TranslationResult result |
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 |
TranslationResult |
|---|---|
Arguments |
XReg vaddr, MemoryOperation op, PrivilegeMode effective_mode, Bits<INSTR_ENC_SIZE> encoding |
-
Original
-
Pruned
Boolean cached_translation_valid; CachedTranslationResult cached_translation_result; cached_translation_result = cached_translation(vaddr, op); if (cached_translation_result.valid) { return cached_translation_result.result; } TranslationResult result; if (effective_mode == PrivilegeMode::M) { result.paddr = vaddr; return result; } SatpMode translation_mode = current_translation_mode(effective_mode); if (translation_mode == SatpMode::Reserved) { if (op == MemoryOperation::Read) { raise(ExceptionCode::LoadPageFault, mode(), vaddr); } else if (op == MemoryOperation::Write || op == MemoryOperation::ReadModifyWrite) { raise(ExceptionCode::StoreAmoPageFault, mode(), vaddr); } else { assert(op == MemoryOperation::Fetch, "Unexpected memory operation"); raise(ExceptionCode::InstructionPageFault, mode(), vaddr); } } if (translation_mode == SatpMode::Bare) { result.paddr = vaddr; } else if (xlen() == 32 && translation_mode == SatpMode::Sv32) { result = stage1_page_walk(32, 34, 32, 2, vaddr, op, effective_mode, encoding); } else if (xlen() == 64 && translation_mode == SatpMode::Sv39) { result = stage1_page_walk(39, 56, 64, 3, vaddr, op, effective_mode, encoding); } else if (xlen() == 64 && translation_mode == SatpMode::Sv48) { result = stage1_page_walk(48, 56, 64, 4, vaddr, op, effective_mode, encoding); } else if (xlen() == 64 && translation_mode == SatpMode::Sv57) { result = stage1_page_walk(57, 56, 64, 5, vaddr, op, effective_mode, encoding); } else { assert(false, "Unexpected SatpMode"); unreachable(); } maybe_cache_translation(vaddr, op, result); return result;
Boolean cached_translation_valid; CachedTranslationResult cached_translation_result; cached_translation_result = cached_translation(vaddr, op); if (cached_translation_result.valid) { return cached_translation_result.result; } TranslationResult result; if (effective_mode == PrivilegeMode::M) { result.paddr = vaddr; return result; } SatpMode translation_mode = current_translation_mode(effective_mode); if (translation_mode == SatpMode::Reserved) { if (op == MemoryOperation::Read) { raise(ExceptionCode::LoadPageFault, mode(), vaddr); } else if (op == MemoryOperation::Write || op == MemoryOperation::ReadModifyWrite) { raise(ExceptionCode::StoreAmoPageFault, mode(), vaddr); } else { assert(op == MemoryOperation::Fetch, "Unexpected memory operation"); raise(ExceptionCode::InstructionPageFault, mode(), vaddr); } } if (translation_mode == SatpMode::Bare) { result.paddr = vaddr; } else if (xlen() == 32 && translation_mode == SatpMode::Sv32) { result = stage1_page_walk(32, 34, 32, 2, vaddr, op, effective_mode, encoding); } else if (xlen() == 64 && translation_mode == SatpMode::Sv39) { result = stage1_page_walk(39, 56, 64, 3, vaddr, op, effective_mode, encoding); } else if (xlen() == 64 && translation_mode == SatpMode::Sv48) { result = stage1_page_walk(48, 56, 64, 4, vaddr, op, effective_mode, encoding); } else if (xlen() == 64 && translation_mode == SatpMode::Sv57) { result = stage1_page_walk(57, 56, 64, 5, vaddr, op, effective_mode, encoding); } else { assert(false, "Unexpected SatpMode"); unreachable(); } maybe_cache_translation(vaddr, op, result); return result;
read_memory_aligned
Read from virtual memory using a known aligned address.
If rl is 1, then the load also acts as a memory model release (applied after all checks pass but before the physical read). If aq is 1, then the load also acts as a memory model acquire (applied after the read).
Return Type |
XReg |
|---|---|
Arguments |
U32 LEN, XReg virtual_address, Bits<INSTR_ENC_SIZE> encoding, Bits<1> aq, Bits<1> rl |
-
Original
-
Pruned
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()); if (rl == 1'b1) { memory_model_release(); } XReg value = read_physical_memory(LEN, result.paddr); if (aq == 1'b1) { memory_model_acquire(); } return value;
TranslationResult result; result = translate(virtual_address, MemoryOperation::Read, effective_ldst_mode(), encoding); access_check(result.paddr, LEN, virtual_address, MemoryOperation::Read, ExceptionCode::LoadAccessFault, effective_ldst_mode()); if (rl == 1'b1) { memory_model_release(); } XReg value = read_physical_memory(LEN, result.paddr); if (aq == 1'b1) { memory_model_acquire(); } return value;
read_physical_memory_8 (builtin)
Read a byte from physical memory.
Return Type |
Bits<8> |
|---|---|
Arguments |
XReg paddr |
read_memory
Read from virtual memory.
Return Type |
XReg |
|---|---|
Arguments |
U32 LEN, XReg virtual_address, Bits<INSTR_ENC_SIZE> encoding |
-
Original
-
Pruned
Boolean aligned = is_naturally_aligned(LEN, virtual_address); XReg physical_address; if (aligned) { return read_memory_aligned(LEN, virtual_address, encoding, 1'b0, 1'b0); } 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, mode(), virtual_address); } else { if (MISALIGNED_SPLIT_STRATEGY == "sequential_bytes") { XReg result = 0; for (U32 I = 0; I < (LEN / 8); I++) { result = result | (read_memory_aligned(8, virtual_address + I, encoding, 1'b0, 1'b0) `<< (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"); return 0; } } return 0;
Boolean aligned = is_naturally_aligned(LEN, virtual_address); XReg physical_address; if (aligned) { return read_memory_aligned(LEN, virtual_address, encoding, 1'b0, 1'b0); } XReg result = 0; for (U32 I = 0; I < (LEN / 8); I++) { result = result | (read_memory_aligned(8, virtual_address + I, encoding, 1'b0, 1'b0) `<< (8 * I)); } return result;
write_physical_memory_64 (builtin)
Write eight bytes to physical memory.
Return Type |
void |
|---|---|
Arguments |
XReg paddr, Bits<64> value |
write_physical_memory
Write to physical memory.
Return Type |
void |
|---|---|
Arguments |
U32 len, XReg paddr, XReg value |
-
Original
-
Pruned
if (len == 8) {
write_physical_memory_8(paddr, value);
} else if (len == 16) {
write_physical_memory_16(paddr, value);
} else if (len == 32) {
write_physical_memory_32(paddr, value);
} else if (len == 64) {
write_physical_memory_64(paddr, value);
} else {
assert(false, "Invalid len");
}
if (len == 8) {
write_physical_memory_8(paddr, value);
} else if (len == 16) {
write_physical_memory_16(paddr, value);
} else if (len == 32) {
write_physical_memory_32(paddr, value);
} else if (len == 64) {
write_physical_memory_64(paddr, value);
} else {
assert(false, "Invalid len");
}
write_memory_aligned
Write to virtual memory using a known aligned address.
If rl is 1, then the store also acts as a memory model release (applied after all checks pass but before the physical write). If aq is 1, then the store also acts as a memory model acquire.
Return Type |
void |
|---|---|
Arguments |
U32 LEN, XReg virtual_address, XReg value, Bits<INSTR_ENC_SIZE> encoding, Bits<1> aq, Bits<1> rl |
-
Original
-
Pruned
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()); if (rl == 1'b1) { memory_model_release(); } write_physical_memory(LEN, physical_address, value); if (aq == 1'b1) { memory_model_acquire(); }
XReg physical_address; physical_address = translate(virtual_address, MemoryOperation::Write, effective_ldst_mode(), encoding).paddr; access_check(physical_address, LEN, virtual_address, MemoryOperation::Write, ExceptionCode::StoreAmoAccessFault, effective_ldst_mode()); if (rl == 1'b1) { memory_model_release(); } write_physical_memory(LEN, physical_address, value); if (aq == 1'b1) { memory_model_acquire(); }
write_physical_memory_8 (builtin)
Write a byte to physical memory.
Return Type |
void |
|---|---|
Arguments |
XReg paddr, Bits<8> value |
write_memory
Write to virtual memory
Return Type |
void |
|---|---|
Arguments |
U32 LEN, XReg virtual_address, XReg value, Bits<INSTR_ENC_SIZE> encoding |
-
Original
-
Pruned
Boolean aligned = is_naturally_aligned(LEN, virtual_address); XReg physical_address; if (aligned) { write_memory_aligned(LEN, virtual_address, value, encoding, 1'b0, 1'b0); return ; } 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); return ; } } 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, mode(), virtual_address); } else { if (MISALIGNED_SPLIT_STRATEGY == "sequential_bytes") { for (U32 I = 0; I < (LEN / 8); I++) { write_memory_aligned(8, virtual_address + I, (value >> (8 * I))[7:0], encoding, 1'b0, 1'b0); } } 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"); } }
Boolean aligned = is_naturally_aligned(LEN, virtual_address); XReg physical_address; if (aligned) { write_memory_aligned(LEN, virtual_address, value, encoding, 1'b0, 1'b0); return ; } for (U32 I = 0; I < (LEN / 8); I++) { write_memory_aligned(8, virtual_address + I, (value >> (8 * I))[7:0], encoding, 1'b0, 1'b0); }
write_physical_memory_32 (builtin)
Write four bytes to physical memory.
Return Type |
void |
|---|---|
Arguments |
XReg paddr, Bits<32> value |
check_f_ok
Checks if instructions from the F extension can be executed, and, if not, raise an exception.
Return Type |
void |
|---|---|
Arguments |
Bits<INSTR_ENC_SIZE> encoding |
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 |
RoundingMode |
|---|---|
Arguments |
Bits<3> rm, Bits<32> encoding |
-
Original
-
Pruned
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 $enum(RoundingMode, CSR[fcsr].FRM);
} else {
raise(ExceptionCode::IllegalInstruction, mode(), encoding);
}
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 $enum(RoundingMode, CSR[fcsr].FRM);
} else {
raise(ExceptionCode::IllegalInstruction, mode(), encoding);
}
signF32UI
Extract sign-bit of a 32-bit floating point number
Return Type |
Bits<1> |
|---|---|
Arguments |
Bits<32> a |
-
Original
-
Pruned
return a[31];
return a[31];
is_sp_signaling_nan?
Returns true if sp_value is a signaling NaN
Return Type |
Boolean |
|---|---|
Arguments |
Bits<32> sp_value |
-
Original
-
Pruned
return (sp_value[30:23] == 0b11111111) && (sp_value[22] == 0) && (sp_value[21:0] != 0);
return (sp_value[30:23] == 0b11111111) && (sp_value[22] == 0) && (sp_value[21:0] != 0);
expF32UI
Extract exponent of a 32-bit floating point number
Return Type |
Bits<8> |
|---|---|
Arguments |
Bits<32> a |
-
Original
-
Pruned
return a[30:23];
return a[30:23];
fracF32UI
Extract significand of a 32-bit floating point number
Return Type |
Bits<23> |
|---|---|
Arguments |
Bits<32> a |
-
Original
-
Pruned
return a[22:0];
return a[22:0];
packToF32UI
Pack components into a 32-bit value
Return Type |
Bits<32> |
|---|---|
Arguments |
Bits<1> sign, Bits<8> exp, Bits<32> sig |
-
Original
-
Pruned
return (sign `<< 31) + (exp `<< 23) + sig;
return (sign `<< 31) + (exp `<< 23) + sig;
softfloat_roundPackToF32
Round FP value according to mdode and then pack it in IEEE format.
Return Type |
Bits<32> |
|---|---|
Arguments |
Bits<1> sign, Bits<16> exp, Bits<32> sig, RoundingMode mode |
-
Original
-
Pruned
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) < 's0) {
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 ('shFD < $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) {
sig = sig & ~32'b1;
}
if (sig == 0) {
exp = 0;
}
return packToF32UI(sign, exp, sig);
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) < 's0) {
Boolean isTiny = ($signed(exp) < 8'-1) || (sig + roundIncrement < 0x80000000);
sig = softfloat_shiftRightJam32(sig, -exp);
exp = 0;
roundBits = sig & 0x7F;
if (isTiny && (roundBits != 0)) {
set_fp_flag(FpFlag::UF);
}
} else if ('shFD < $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) {
sig = sig & 32'hfffffffe;
}
if (sig == 0) {
exp = 0;
}
return packToF32UI(sign, exp, sig);
softfloat_addMagsF32
Returns sum of the magnitudes of 2 floating point numbers
Return Type |
U32 |
|---|---|
Arguments |
U32 a, U32 b, RoundingMode mode |
-
Original
-
Pruned
if (is_sp_signaling_nan?(a) || is_sp_signaling_nan?(b)) { set_fp_flag(FpFlag::NV); } Bits<16> expA = expF32UI(a); Bits<32> sigA = fracF32UI(a); Bits<16> expB = expF32UI(b); Bits<32> sigB = fracF32UI(b); U32 sigZ; U32 z; Bits<1> signZ; Bits<8> expZ; Bits<16> expDiff = expA - expB; if (expDiff == 16'd0) { if (expA == 8'd0) { z = a + b; return z; } if (expA == 8'hFF) { if ((sigA != 8'd0) || (sigB != 8'd0)) { return SP_CANONICAL_NAN; } return a; } signZ = signF32UI(a); expZ = expA; sigZ = 32'h01000000 + sigA + sigB; if (sigZ & 0x1) == 0) && (expZ < 8'hFE { sigZ = sigZ >> 1; return (32'h0 + (signZ << 31) + (expZ << 23) + sigZ); } sigZ = sigZ << 6; } else { signZ = signF32UI(a); sigA = sigA << 6; sigB = sigB << 6; if ($signed(expDiff) < 0s) { if (expB == 8'hFF) { if (sigB != 0) { return SP_CANONICAL_NAN; } return packToF32UI(signZ, 8'hFF, 23'h0); } expZ = expB; sigA = (expA == 0) ? 2 * sigA : (sigA + 0x20000000); sigA = softfloat_shiftRightJam32(sigA, -expDiff); } else { if (expA == 8'hFF) { if (sigA != 0) { return SP_CANONICAL_NAN; } return a; } expZ = expA; sigB = (expB == 0) ? 2 * sigB : (sigB + 0x20000000); sigB = softfloat_shiftRightJam32(sigB, expDiff); } sigZ = 0x20000000 + sigA + sigB; if (sigZ < 0x40000000) { expZ = expZ - 1; sigZ = sigZ << 1; } } return softfloat_roundPackToF32(signZ, expZ, sigZ, mode);
if (is_sp_signaling_nan?(a) || is_sp_signaling_nan?(b)) { set_fp_flag(FpFlag::NV); } Bits<16> expA = expF32UI(a); Bits<32> sigA = fracF32UI(a); Bits<16> expB = expF32UI(b); Bits<32> sigB = fracF32UI(b); U32 sigZ; U32 z; Bits<1> signZ; Bits<8> expZ; Bits<16> expDiff = expA - expB; if (expDiff == 16'd0) { if (expA == 8'd0) { z = a + b; return z; } if (expA == 8'hFF) { if ((sigA != 8'd0) || (sigB != 8'd0)) { return 32'h7fc00000; } return a; } signZ = signF32UI(a); expZ = expA; sigZ = 32'h01000000 + sigA + sigB; if (sigZ & 0x1) == 0) && (expZ < 8'hFE { sigZ = sigZ >> 1; return (32'h0 + (signZ << 31) + (expZ << 23) + sigZ); } sigZ = sigZ << 6; } else { signZ = signF32UI(a); sigA = sigA << 6; sigB = sigB << 6; if ($signed(expDiff) < 0s) { if (expB == 8'hFF) { if (sigB != 0) { return 32'h7fc00000; } return packToF32UI(signZ, 8'hFF, 23'h0); } expZ = expB; sigA = (expA == 0) ? 2 * sigA : (sigA + 0x20000000); sigA = softfloat_shiftRightJam32(sigA, -expDiff); } else { if (expA == 8'hFF) { if (sigA != 0) { return 32'h7fc00000; } return a; } expZ = expA; sigB = (expB == 0) ? 2 * sigB : (sigB + 0x20000000); sigB = softfloat_shiftRightJam32(sigB, expDiff); } sigZ = 0x20000000 + sigA + sigB; if (sigZ < 0x40000000) { expZ = expZ - 1; sigZ = sigZ << 1; } } return softfloat_roundPackToF32(signZ, expZ, sigZ, mode);
f32_add
Returns sum of 2 floating point numbers
Return Type |
U32 |
|---|---|
Arguments |
U32 a, U32 b, RoundingMode mode |
-
Original
-
Pruned
U32 a_xor_b = a ^ b; if (signF32UI(a_xor_b) == 1) { return softfloat_subMagsF32(a, b, mode); } else { return softfloat_addMagsF32(a, b, mode); }
U32 a_xor_b = a ^ b; if (signF32UI(a_xor_b) == 1) { return softfloat_subMagsF32(a, b, mode); } else { return softfloat_addMagsF32(a, b, mode); }
mark_f_state_dirty
Potentially updates mstatus.FS to the Dirty (3) state, depending on configuration settings.
Return Type |
void |
|---|---|
Arguments |
-
Original
-
Pruned
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");
}
is_sp_neg_inf?
Return true if sp_value is negative infinity.
Return Type |
Boolean |
|---|---|
Arguments |
Bits<32> sp_value |
-
Original
-
Pruned
return sp_value == SP_NEG_INF;
return sp_value == 32'hff800000;
is_sp_neg_norm?
Returns true if sp_value is a negative normal number.
Return Type |
Boolean |
|---|---|
Arguments |
Bits<32> sp_value |
-
Original
-
Pruned
return (sp_value[31] == 1) && (sp_value[30:23] != 0b11111111) && (sp_value[30:23] != 0b00000000);
return (sp_value[31] == 1) && (sp_value[30:23] != 0b11111111) && (sp_value[30:23] != 0b00000000);
is_sp_neg_subnorm?
Returns true if sp_value is a negative subnormal number.
Return Type |
Boolean |
|---|---|
Arguments |
Bits<32> sp_value |
-
Original
-
Pruned
return (sp_value[31] == 1) && (sp_value[30:23] == 0) && (sp_value[22:0] != 0);
return (sp_value[31] == 1) && (sp_value[30:23] == 0) && (sp_value[22:0] != 0);
is_sp_neg_zero?
Returns true if sp_value is negative zero.
Return Type |
Boolean |
|---|---|
Arguments |
Bits<32> sp_value |
-
Original
-
Pruned
return sp_value == SP_NEG_ZERO;
return sp_value == 32'h80000000;
is_sp_pos_zero?
Returns true if sp_value is positive zero.
Return Type |
Boolean |
|---|---|
Arguments |
Bits<32> sp_value |
-
Original
-
Pruned
return sp_value == SP_POS_ZERO;
return sp_value == 32'0;
is_sp_pos_subnorm?
Returns true if sp_value is a positive subnormal number.
Return Type |
Boolean |
|---|---|
Arguments |
Bits<32> sp_value |
-
Original
-
Pruned
return (sp_value[31] == 0) && (sp_value[30:23] == 0) && (sp_value[22:0] != 0);
return (sp_value[31] == 0) && (sp_value[30:23] == 0) && (sp_value[22:0] != 0);
is_sp_pos_norm?
Returns true if sp_value is a positive normal number.
Return Type |
Boolean |
|---|---|
Arguments |
Bits<32> sp_value |
-
Original
-
Pruned
return (sp_value[31] == 0) && (sp_value[30:23] != 0b11111111) && (sp_value[30:23] != 0b00000000);
return (sp_value[31] == 0) && (sp_value[30:23] != 0b11111111) && (sp_value[30:23] != 0b00000000);
is_sp_pos_inf?
Return true if sp_value is positive infinity.
Return Type |
Boolean |
|---|---|
Arguments |
Bits<32> sp_value |
-
Original
-
Pruned
return sp_value == SP_POS_INF;
return sp_value == 32'h7f800000;
is_sp_quiet_nan?
Returns true if sp_value is a quiet NaN
Return Type |
Boolean |
|---|---|
Arguments |
Bits<32> sp_value |
-
Original
-
Pruned
return (sp_value[30:23] == 0b11111111) && (sp_value[22] == 1);
return (sp_value[30:23] == 0b11111111) && (sp_value[22] == 1);
set_fp_flag
Add flag to the sticky flags bits in CSR[fcsr]
Return Type |
void |
|---|---|
Arguments |
FpFlag flag |
-
Original
-
Pruned
softfloat_shiftRightJam64Extra
Shifts the 128 bits formed by concatenating 'a' and 'extra' right by 64 plus the number of bits given in 'dist', which must not be zero. This shifted value is at most 64 nonzero bits and is returned in the 'v' field of the 'struct uint64_extra' result. The 64-bit 'extra' field of the result contains a value formed as follows from the bits that were shifted off: The last bit shifted off is the most-significant bit of the 'extra' field, and the other 63 bits of the 'extra' field are all zero if and only if all_but the_last bits shifted off were all zero. (This function makes more sense if 'a' and 'extra' are considered to form an unsigned fixed-point number with binary point between 'a' and 'extra'. This fixed-point value is shifted right by the number of bits given in 'dist', and the integer part of this shifted value is returned in the 'v' field of the result. The fractional part of the shifted value is modified as described above and returned in the 'extra' field of the result.)
Return Type |
TwoU64s |
|---|---|
Arguments |
Bits<64> a, Bits<64> extra, Bits<32> dist |
-
Original
-
Pruned
TwoU64s z;
if (dist < 64) {
z.u1 = a >> dist;
z.u2 = a << (-dist & 63);
} else {
z.u1 = 0;
z.u2 = (dist == 64) ? a : ((a != 0) ? 1 : 0);
}
z.u2 = z.u2 | ((extra != 0) ? 1 : 0);
return z;
TwoU64s z;
if (dist < 64) {
z.u1 = a >> dist;
z.u2 = a << (-dist & 63);
} else {
z.u1 = 0;
z.u2 = (dist == 64) ? a : ((a != 0) ? 1 : 0);
}
z.u2 = z.u2 | ((extra != 0) ? 1 : 0);
return z;
softfloat_roundToI64
Round to signed 64-bit integer, using roundingMode. Translated from Berkeley Softfloat softfloat_roundToI64.
Return Type |
Bits<64> |
|---|---|
Arguments |
Bits<1> sign, Bits<64> sig, Bits<64> sigExtra, RoundingMode roundingMode |
-
Original
-
Pruned
Bits<64> z;
Boolean needs_increment = false;
if ((roundingMode == RoundingMode::RMM) || (roundingMode == RoundingMode::RNE)) {
if (64'h8000000000000000 <= sigExtra) {
needs_increment = true;
}
} else {
if ((sigExtra != 0) && sign != 0) ? (roundingMode == RoundingMode::RDN) : (roundingMode == RoundingMode::RUP) {
needs_increment = true;
}
}
if (needs_increment) {
sig = sig + 1;
if (sig == 0) {
set_fp_flag(FpFlag::NV);
return (sign == 1) ? I64_NEG_OVERFLOW : I64_POS_OVERFLOW;
}
if ((sigExtra == 64'h8000000000000000) && (roundingMode == RoundingMode::RNE)) {
sig = sig & ~64'h1;
}
}
z = (sign == 1) ? -sig : sig;
if ((z != 0) && (($signed(z) < 0s) ? 1 : 0) ^ sign) == 1 {
set_fp_flag(FpFlag::NV);
return (sign == 1) ? I64_NEG_OVERFLOW : I64_POS_OVERFLOW;
}
if (sigExtra != 0) {
set_fp_flag(FpFlag::NX);
}
return z;
Bits<64> z;
Boolean needs_increment = false;
if ((roundingMode == RoundingMode::RMM) || (roundingMode == RoundingMode::RNE)) {
if (64'h8000000000000000 <= sigExtra) {
needs_increment = true;
}
} else {
if ((sigExtra != 0) && sign != 0) ? (roundingMode == RoundingMode::RDN) : (roundingMode == RoundingMode::RUP) {
needs_increment = true;
}
}
if (needs_increment) {
sig = sig + 1;
if (sig == 0) {
set_fp_flag(FpFlag::NV);
return (sign == 1) ? 64'h8000000000000000 : 64'h7fffffffffffffff;
}
if ((sigExtra == 64'h8000000000000000) && (roundingMode == RoundingMode::RNE)) {
sig = sig & 64'hfffffffffffffffe;
}
}
z = (sign == 1) ? -sig : sig;
if ((z != 0) && (($signed(z) < 0s) ? 1 : 0) ^ sign) == 1 {
set_fp_flag(FpFlag::NV);
return (sign == 1) ? 64'h8000000000000000 : 64'h7fffffffffffffff;
}
if (sigExtra != 0) {
set_fp_flag(FpFlag::NX);
}
return z;
f32_to_i64
Converts 32-bit floating point number to a signed 64-bit integer. Translated from Berkeley Softfloat f32_to_i64.
Return Type |
Bits<64> |
|---|---|
Arguments |
U32 a, RoundingMode mode |
-
Original
-
Pruned
Bits<1> sign = signF32UI(a); Bits<16> exp = expF32UI(a); Bits<32> sig = fracF32UI(a); Bits<16> shiftDist = 16'hBE - exp; Bits<64> sig64; Bits<64> extra; if ($signed(shiftDist) < 0s) { set_fp_flag(FpFlag::NV); if ((exp == 16'hFF) && (sig != 0)) { return I64_NAN; } else { return (sign == 1) ? I64_NEG_OVERFLOW : I64_POS_OVERFLOW; } } if (exp != 0) { sig = sig | 32'h00800000; } sig64 = sig `<< 40; extra = 0; if (shiftDist != 0) { TwoU64s sig64Extra = softfloat_shiftRightJam64Extra(sig64, 0, $signed(shiftDist)); sig64 = sig64Extra.u1; extra = sig64Extra.u2; } return softfloat_roundToI64(sign, sig64, extra, mode);
Bits<1> sign = signF32UI(a); Bits<16> exp = expF32UI(a); Bits<32> sig = fracF32UI(a); Bits<16> shiftDist = 16'hBE - exp; Bits<64> sig64; Bits<64> extra; if ($signed(shiftDist) < 0s) { set_fp_flag(FpFlag::NV); if ((exp == 16'hFF) && (sig != 0)) { return 64'h7fffffffffffffff; } else { return (sign == 1) ? 64'h8000000000000000 : 64'h7fffffffffffffff; } } if (exp != 0) { sig = sig | 32'h00800000; } sig64 = sig `<< 40; extra = 0; if (shiftDist != 0) { TwoU64s sig64Extra = softfloat_shiftRightJam64Extra(sig64, 0, $signed(shiftDist)); sig64 = sig64Extra.u1; extra = sig64Extra.u2; } return softfloat_roundToI64(sign, sig64, extra, mode);
softfloat_roundToUI64
Round to unsigned 64-bit integer, using roundingMode. Translated from Berkeley Softfloat softfloat_roundToUI64.
Return Type |
Bits<64> |
|---|---|
Arguments |
Bits<1> sign, Bits<64> sig, Bits<64> sigExtra, RoundingMode roundingMode |
-
Original
-
Pruned
Boolean needs_increment = false;
if ((roundingMode == RoundingMode::RMM) || (roundingMode == RoundingMode::RNE)) {
if (64'h8000000000000000 <= sigExtra) {
needs_increment = true;
}
} else {
if (sign != 0) {
if ((sig | sigExtra) == 0) {
return 0;
}
if (roundingMode == RoundingMode::RDN) {
set_fp_flag(FpFlag::NV);
if (sign == 1) {
return UI64_NEG_OVERFLOW;
} else {
return UI64_POS_OVERFLOW;
}
}
} else {
if ((roundingMode == RoundingMode::RUP) && (sigExtra != 0)) {
needs_increment = true;
}
}
}
if (needs_increment) {
sig = sig + 1;
if (sig == 0) {
set_fp_flag(FpFlag::NV);
if (sign == 1) {
return UI64_NEG_OVERFLOW;
} else {
return UI64_POS_OVERFLOW;
}
}
if ((sigExtra == 64'h8000000000000000) && (roundingMode == RoundingMode::RNE)) {
sig = sig & ~64'h1;
}
}
if ((sign != 0) && (sig != 0)) {
set_fp_flag(FpFlag::NV);
if (sign == 1) {
return UI64_NEG_OVERFLOW;
} else {
return UI64_POS_OVERFLOW;
}
}
if (sigExtra != 0) {
set_fp_flag(FpFlag::NX);
}
return sig;
Boolean needs_increment = false;
if ((roundingMode == RoundingMode::RMM) || (roundingMode == RoundingMode::RNE)) {
if (64'h8000000000000000 <= sigExtra) {
needs_increment = true;
}
} else {
if (sign != 0) {
if ((sig | sigExtra) == 0) {
return 0;
}
if (roundingMode == RoundingMode::RDN) {
set_fp_flag(FpFlag::NV);
if (sign == 1) {
return 64'0;
} else {
return 64'hffffffffffffffff;
}
}
} else {
if ((roundingMode == RoundingMode::RUP) && (sigExtra != 0)) {
needs_increment = true;
}
}
}
if (needs_increment) {
sig = sig + 1;
if (sig == 0) {
set_fp_flag(FpFlag::NV);
if (sign == 1) {
return 64'0;
} else {
return 64'hffffffffffffffff;
}
}
if ((sigExtra == 64'h8000000000000000) && (roundingMode == RoundingMode::RNE)) {
sig = sig & 64'hfffffffffffffffe;
}
}
if ((sign != 0) && (sig != 0)) {
set_fp_flag(FpFlag::NV);
if (sign == 1) {
return 64'0;
} else {
return 64'hffffffffffffffff;
}
}
if (sigExtra != 0) {
set_fp_flag(FpFlag::NX);
}
return sig;
f32_to_ui64
Converts 32-bit floating point number to an unsigned 64-bit integer. Translated from Berkeley Softfloat f32_to_ui64.
Return Type |
Bits<64> |
|---|---|
Arguments |
U32 a, RoundingMode mode |
-
Original
-
Pruned
Bits<1> sign = signF32UI(a); Bits<16> exp = expF32UI(a); Bits<32> sig = fracF32UI(a); Bits<16> shiftDist; Bits<64> sig64, extra; shiftDist = 16'hBE - exp; if ($signed(shiftDist) < 0s) { set_fp_flag(FpFlag::NV); if ((exp == 0xFF) && (sig != 0)) { return UI64_NAN; } else if (sign != 0) { return UI64_NEG_OVERFLOW; } else { return UI64_POS_OVERFLOW; } } if (exp != 0) { sig = sig | 32'h00800000; } sig64 = sig `<< 40; extra = 0; if (shiftDist != 0) { TwoU64s sig64Extra = softfloat_shiftRightJam64Extra(sig64, 0, $signed(shiftDist)); sig64 = sig64Extra.u1; extra = sig64Extra.u2; } return softfloat_roundToUI64(sign, sig64, extra, mode);
Bits<1> sign = signF32UI(a); Bits<16> exp = expF32UI(a); Bits<32> sig = fracF32UI(a); Bits<16> shiftDist; Bits<64> sig64, extra; shiftDist = 16'hBE - exp; if ($signed(shiftDist) < 0s) { set_fp_flag(FpFlag::NV); if ((exp == 0xFF) && (sig != 0)) { return 64'hffffffffffffffff; } else if (sign != 0) { return 64'0; } else { return 64'hffffffffffffffff; } } if (exp != 0) { sig = sig | 32'h00800000; } sig64 = sig `<< 40; extra = 0; if (shiftDist != 0) { TwoU64s sig64Extra = softfloat_shiftRightJam64Extra(sig64, 0, $signed(shiftDist)); sig64 = sig64Extra.u1; extra = sig64Extra.u2; } return softfloat_roundToUI64(sign, sig64, extra, mode);
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 |
XReg |
|---|---|
Arguments |
U32 N, XReg value |
-
Original
-
Pruned
for (U32 i = 0; i < N; i++) {
if (value[N - 1 - i] == 1) {
return i;
}
}
return N;
for (U32 i = 0; i < N; i++) {
if (value[N - 1 - i] == 1) {
return i;
}
}
return N;
i64_to_f32
Converts 64-bit signed integer to 32-bit floating point number. Translated from Berkeley Softfloat i64_to_f32.
Return Type |
U32 |
|---|---|
Arguments |
Bits<64> a, RoundingMode mode |
-
Original
-
Pruned
Bits<1> sign = a[63];
Bits<64> absA;
if (sign == 1) {
absA = -a;
} else {
absA = a;
}
Bits<8> shiftDist = count_leading_zeros(64, absA) - 40;
Bits<32> sig;
if ($signed(shiftDist) >= 0s) {
if (a != 0) {
return packToF32UI(sign, 16'h95 - shiftDist, absA << shiftDist);
} else {
return 0;
}
} else {
shiftDist = shiftDist + 7;
if ($signed(shiftDist) < 0s) {
sig = softfloat_shortShiftRightJam64(absA, -shiftDist);
} else {
sig = absA << shiftDist;
}
return softfloat_roundPackToF32(sign, 8'h9C - shiftDist, sig, mode);
}
Bits<1> sign = a[63];
Bits<64> absA;
if (sign == 1) {
absA = -a;
} else {
absA = a;
}
Bits<8> shiftDist = count_leading_zeros(64, absA) - 40;
Bits<32> sig;
if ($signed(shiftDist) >= 0s) {
if (a != 0) {
return packToF32UI(sign, 16'h95 - shiftDist, absA << shiftDist);
} else {
return 0;
}
} else {
shiftDist = shiftDist + 7;
if ($signed(shiftDist) < 0s) {
sig = softfloat_shortShiftRightJam64(absA, -shiftDist);
} else {
sig = absA << shiftDist;
}
return softfloat_roundPackToF32(sign, 8'h9C - shiftDist, sig, mode);
}
softfloat_shortShiftRightJam64
Shifts a right by dist bits (dist must be in 1..31), jamming any shifted-off bits into the least-significant bit of the result.
Return Type |
Bits<64> |
|---|---|
Arguments |
Bits<64> a, Bits<8> dist |
-
Original
-
Pruned
return a >> dist | (a & ((64'h1 << dist) - 1 != 0) ? 1 : 0);
return a >> dist | (a & ((64'h1 << dist) - 1 != 0) ? 1 : 0);
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 |
Bits<32> |
|---|---|
Arguments |
Bits<32> a, Bits<32> dist |
-
Original
-
Pruned
return (dist < 31) ? a >> dist | ((a[dist - 1:0] != 0) ? 1 : 0) : ((a != 0) ? 1 : 0);
return (dist < 31) ? a >> dist | ((a[dist - 1:0] != 0) ? 1 : 0) : ((a != 0) ? 1 : 0);
ui64_to_f32
Converts 64-bit unsigned integer to 32-bit floating point number. Translated from Berkeley Softfloat ui64_to_f32.
Return Type |
U32 |
|---|---|
Arguments |
Bits<64> a, RoundingMode mode |
-
Original
-
Pruned
Bits<8> shiftDist = count_leading_zeros(64, a) - 40; Bits<32> sig; if (0s <= $signed(shiftDist)) { if (a != 0) { return packToF32UI(0, 8'h95 - shiftDist, a << shiftDist); } else { return 0; } } else { shiftDist = shiftDist + 7; if ($signed(shiftDist) < 0s) { sig = softfloat_shortShiftRightJam64(a, -shiftDist); } else { sig = a << shiftDist; } return softfloat_roundPackToF32(0, 8'h9C - shiftDist, sig, mode); }
Bits<8> shiftDist = count_leading_zeros(64, a) - 40; Bits<32> sig; if (0s <= $signed(shiftDist)) { if (a != 0) { return packToF32UI(0, 8'h95 - shiftDist, a << shiftDist); } else { return 0; } } else { shiftDist = shiftDist + 7; if ($signed(shiftDist) < 0s) { sig = softfloat_shortShiftRightJam64(a, -shiftDist); } else { sig = a << shiftDist; } return softfloat_roundPackToF32(0, 8'h9C - shiftDist, sig, mode); }
softfloat_normRoundPackToF32
Normalize, round, and pack into a 32-bit floating point value
Return Type |
Bits<32> |
|---|---|
Arguments |
Bits<1> sign, Bits<16> exp, Bits<32> sig, RoundingMode mode |
-
Original
-
Pruned
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); }
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); }
i32_to_f32
Converts 32-bit signed integer to 32-bit floating point number
Return Type |
U32 |
|---|---|
Arguments |
U32 a, RoundingMode mode |
-
Original
-
Pruned
Bits<1> sign = a[31];
if ((a & 0x7FFFFFFF) == 0) {
return (sign == 1) ? packToF32UI(1, 0x9E, 0) : packToF32UI(0, 0, 0);
}
U32 absA = (sign == 1) ? -a : a;
return softfloat_normRoundPackToF32(sign, 0x9C, absA, mode);
Bits<1> sign = a[31];
if ((a & 0x7FFFFFFF) == 0) {
return (sign == 1) ? 32'hcf000000 : 32'0;
}
U32 absA = (sign == 1) ? -a : a;
return softfloat_normRoundPackToF32(sign, 0x9C, absA, mode);
ui32_to_f32
Converts 32-bit unsigned integer to 32-bit floating point number
Return Type |
U32 |
|---|---|
Arguments |
U32 a, RoundingMode mode |
-
Original
-
Pruned
if (a == 0) {
return a;
}
if (a[31] == 1) {
return softfloat_roundPackToF32(0, 0x9D, a >> 1 | (a & 1), mode);
} else {
return softfloat_normRoundPackToF32(0, 0x9C, a, mode);
}
if (a == 0) {
return a;
}
if (a[31] == 1) {
return softfloat_roundPackToF32(0, 0x9D, a >> 1 | (a & 1), mode);
} else {
return softfloat_normRoundPackToF32(0, 0x9C, a, mode);
}
softfloat_roundToI32
Round to signed 32-bit integer, using rounding_mode
Return Type |
Bits<32> |
|---|---|
Arguments |
Bits<1> sign, Bits<64> sig, RoundingMode roundingMode |
-
Original
-
Pruned
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) < 's0) != (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;
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 ? 32'h80000000 : 32'h7fffffff;
}
Bits<32> sig32 = sig >> 12;
if ((roundBits == 0x800 && (roundingMode == RoundingMode::RNE))) {
sig32 = sig32 & 32'hfffffffe;
}
Bits<32> z = (sign == 1) ? -sig32 : sig32;
if ((z != 0) && $signed(z) < 's0) != (sign == 1) {
set_fp_flag(FpFlag::NV);
return sign == 1 ? 32'h80000000 : 32'h7fffffff;
}
if (roundBits != 0) {
set_fp_flag(FpFlag::NX);
}
return z;
f32_to_i32
Converts 32-bit floating point number to a signed 32-bit integer
Return Type |
U32 |
|---|---|
Arguments |
U32 a, RoundingMode mode |
-
Original
-
Pruned
Bits<1> sign = signF32UI(a); Bits<16> exp = expF32UI(a); Bits<32> sig = fracF32UI(a); Bits<16> shiftDist; U64 sig64; if ((exp == 8'hFF) && (sig != 0)) { sign = 0; set_fp_flag(FpFlag::NV); return I32_NAN; } if (exp != 0) { sig = sig | 32'h00800000; } sig64 = sig `<< 32; shiftDist = 8'hAA - exp; if ($signed(shiftDist) > 0s) { sig64 = softfloat_shiftRightJam64(sig64, shiftDist); } return softfloat_roundToI32(sign, sig64, mode);
Bits<1> sign = signF32UI(a); Bits<16> exp = expF32UI(a); Bits<32> sig = fracF32UI(a); Bits<16> shiftDist; U64 sig64; if ((exp == 8'hFF) && (sig != 0)) { sign = 0; set_fp_flag(FpFlag::NV); return 32'h7fffffff; } if (exp != 0) { sig = sig | 32'h00800000; } sig64 = sig `<< 32; shiftDist = 8'hAA - exp; if ($signed(shiftDist) > 0s) { sig64 = softfloat_shiftRightJam64(sig64, shiftDist); } return softfloat_roundToI32(sign, sig64, mode);
softfloat_roundToUI32
Round to unsigned 32-bit integer, using rounding_mode
Return Type |
Bits<32> |
|---|---|
Arguments |
Bits<1> sign, Bits<64> sig, RoundingMode roundingMode |
-
Original
-
Pruned
Bits<16> roundIncrement = 0x800;
if ((roundingMode != RoundingMode::RMM) && (roundingMode != RoundingMode::RNE)) {
roundIncrement = 0;
if (sign == 1) {
if (sig == 0) {
return 0;
}
if (roundingMode == RoundingMode::RDN) {
set_fp_flag(FpFlag::NV);
}
} else {
if (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 ? UI32_NEG_OVERFLOW : UI32_POS_OVERFLOW;
}
Bits<32> z = sig >> 12;
if ((roundBits == 0x800 && (roundingMode == RoundingMode::RNE))) {
z = z & ~32'b1;
}
if ((z != 0) && (sign == 1)) {
set_fp_flag(FpFlag::NV);
return sign == 1 ? UI32_NEG_OVERFLOW : UI32_POS_OVERFLOW;
}
if (roundBits != 0) {
set_fp_flag(FpFlag::NX);
}
return z;
Bits<16> roundIncrement = 0x800;
if ((roundingMode != RoundingMode::RMM) && (roundingMode != RoundingMode::RNE)) {
roundIncrement = 0;
if (sign == 1) {
if (sig == 0) {
return 0;
}
if (roundingMode == RoundingMode::RDN) {
set_fp_flag(FpFlag::NV);
}
} else {
if (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 ? 32'0 : 32'hffffffff;
}
Bits<32> z = sig >> 12;
if ((roundBits == 0x800 && (roundingMode == RoundingMode::RNE))) {
z = z & 32'hfffffffe;
}
if ((z != 0) && (sign == 1)) {
set_fp_flag(FpFlag::NV);
return sign == 1 ? 32'0 : 32'hffffffff;
}
if (roundBits != 0) {
set_fp_flag(FpFlag::NX);
}
return z;
f32_to_ui32
Converts 32-bit floating point number to an unsigned 32-bit integer
Return Type |
U32 |
|---|---|
Arguments |
U32 a, RoundingMode mode |
-
Original
-
Pruned
Bits<1> sign = signF32UI(a); Bits<16> exp = expF32UI(a); Bits<32> sig = fracF32UI(a); Bits<16> shiftDist; U64 sig64; if ((exp == 8'hFF) && (sig != 0)) { sign = 0; set_fp_flag(FpFlag::NV); return UI32_NAN; } if (exp != 0) { sig = sig | 32'h00800000; } sig64 = sig `<< 32; shiftDist = 8'hAA - exp; if ($signed(shiftDist) > 0s) { sig64 = softfloat_shiftRightJam64(sig64, shiftDist); } return softfloat_roundToUI32(sign, sig64, mode);
Bits<1> sign = signF32UI(a); Bits<16> exp = expF32UI(a); Bits<32> sig = fracF32UI(a); Bits<16> shiftDist; U64 sig64; if ((exp == 8'hFF) && (sig != 0)) { sign = 0; set_fp_flag(FpFlag::NV); return 32'hffffffff; } if (exp != 0) { sig = sig | 32'h00800000; } sig64 = sig `<< 32; shiftDist = 8'hAA - exp; if ($signed(shiftDist) > 0s) { sig64 = softfloat_shiftRightJam64(sig64, shiftDist); } return softfloat_roundToUI32(sign, sig64, mode);
softfloat_normSubnormalF32Sig
Normalize a subnormal F32 significand. Returns (exp, sig32) where exp is the adjusted exponent (two’s complement in Bits<16>) and sig32 is the normalized significand with implicit leading 1 at bit 23. The exponent is widened to Bits<16> (rather than the natural Bits<8>) so that callers can add two adjusted exponents together (e.g. expA + expB - bias) without overflow.
Return Type |
ExpAndSig |
|---|---|
Arguments |
Bits<32> sig |
-
Original
-
Pruned
Bits<16> shiftDist = count_leading_zeros(32, sig) - 8; ExpAndSig ret; ret.exp = 1 - shiftDist; ret.sig = sig << shiftDist; return ret;
Bits<16> shiftDist = count_leading_zeros(32, sig) - 8; ExpAndSig ret; ret.exp = 1 - shiftDist; ret.sig = sig << shiftDist; return ret;
softfloat_approxRecip32_1
Returns floor(0x7FFFFFFFFFFFFFFF / a), matching the platform-specific Berkeley SoftFloat macro on 64-bit hosts. Computed via binary long division.
Return Type |
U32 |
|---|---|
Arguments |
Bits<32> a |
-
Original
-
Pruned
Bits<64> a64 = {32'h0, a};
Bits<64> a_top = a64 << 31;
Bits<64> rem = 64'h7FFFFFFFFFFFFFFF;
Bits<32> q = 0;
for (U32 i = 0; i < 32; i++) {
Bits<64> d = a_top >> i;
if (rem >= d) {
q = q | (32'h1 << (31 - i));
rem = rem - d;
}
}
return q;
Bits<64> a64 = {32'h0, a};
Bits<64> a_top = a64 << 31;
Bits<64> rem = 64'h7FFFFFFFFFFFFFFF;
Bits<32> q = 0;
for (U32 i = 0; i < 32; i++) {
Bits<64> d = a_top >> i;
if (rem >= d) {
q = q | (32'h1 << (31 - i));
rem = rem - d;
}
}
return q;
f32_div
Divides two 32-bit floating point numbers. Translated from Berkeley Softfloat f32_div.
Return Type |
U32 |
|---|---|
Arguments |
U32 a, U32 b, RoundingMode mode |
-
Original
-
Pruned
if (is_sp_signaling_nan?(a) || is_sp_signaling_nan?(b)) { set_fp_flag(FpFlag::NV); } Bits<1> signA = signF32UI(a); Bits<16> expA = expF32UI(a); Bits<32> sigA = fracF32UI(a); Bits<1> signB = signF32UI(b); Bits<16> expB = expF32UI(b); Bits<32> sigB = fracF32UI(b); Bits<1> signZ = signA ^ signB; Bits<16> expZ; if (expA == 8'hFF) { if (sigA != 0) { return SP_CANONICAL_NAN; } if (expB == 8'hFF) { if (sigB != 0) { return SP_CANONICAL_NAN; } set_fp_flag(FpFlag::NV); return SP_CANONICAL_NAN; } return packToF32UI(signZ, 8'hFF, 0); } if (expB == 8'hFF) { if (sigB != 0) { return SP_CANONICAL_NAN; } return packToF32UI(signZ, 0, 0); } if (expB == 0) { if (sigB == 0) { if ((expA == 0) && (sigA == 0)) { set_fp_flag(FpFlag::NV); return SP_CANONICAL_NAN; } set_fp_flag(FpFlag::DZ); return packToF32UI(signZ, 8'hFF, 0); } ExpAndSig norm = softfloat_normSubnormalF32Sig(sigB); expB = norm.exp; sigB = norm.sig; } if (expA == 0) { if (sigA == 0) { return packToF32UI(signZ, 0, 0); } ExpAndSig norm = softfloat_normSubnormalF32Sig(sigA); expA = norm.exp; sigA = norm.sig; } expZ = expA - expB + 16'h007E; sigA = sigA | 32'h00800000; sigB = sigB | 32'h00800000; if (sigA < sigB) { expZ = expZ - 1; sigA = sigA << 8; } else { sigA = sigA << 7; } sigB = sigB << 8; Bits<32> recip32 = softfloat_approxRecip32_1(sigB); Bits<32> sigZ = (sigA `* recip32) >> 32; sigZ = sigZ + 2; if ((sigZ & 7) <= 2) { sigZ = sigZ & ~32'h3; Bits<64> rem = (sigA `<< 31) - (sigZ `* sigB); if ((rem & 64'h8000000000000000) != 0) { sigZ = sigZ - 4; } else { if (rem != 0) { sigZ = sigZ | 1; } } } return softfloat_roundPackToF32(signZ, expZ, sigZ, mode);
if (is_sp_signaling_nan?(a) || is_sp_signaling_nan?(b)) { set_fp_flag(FpFlag::NV); } Bits<1> signA = signF32UI(a); Bits<16> expA = expF32UI(a); Bits<32> sigA = fracF32UI(a); Bits<1> signB = signF32UI(b); Bits<16> expB = expF32UI(b); Bits<32> sigB = fracF32UI(b); Bits<1> signZ = signA ^ signB; Bits<16> expZ; if (expA == 8'hFF) { if (sigA != 0) { return 32'h7fc00000; } if (expB == 8'hFF) { if (sigB != 0) { return 32'h7fc00000; } set_fp_flag(FpFlag::NV); return 32'h7fc00000; } return packToF32UI(signZ, 8'hFF, 0); } if (expB == 8'hFF) { if (sigB != 0) { return 32'h7fc00000; } return packToF32UI(signZ, 0, 0); } if (expB == 0) { if (sigB == 0) { if ((expA == 0) && (sigA == 0)) { set_fp_flag(FpFlag::NV); return 32'h7fc00000; } set_fp_flag(FpFlag::DZ); return packToF32UI(signZ, 8'hFF, 0); } ExpAndSig norm = softfloat_normSubnormalF32Sig(sigB); expB = norm.exp; sigB = norm.sig; } if (expA == 0) { if (sigA == 0) { return packToF32UI(signZ, 0, 0); } ExpAndSig norm = softfloat_normSubnormalF32Sig(sigA); expA = norm.exp; sigA = norm.sig; } expZ = expA - expB + 16'h007E; sigA = sigA | 32'h00800000; sigB = sigB | 32'h00800000; if (sigA < sigB) { expZ = expZ - 1; sigA = sigA << 8; } else { sigA = sigA << 7; } sigB = sigB << 8; Bits<32> recip32 = softfloat_approxRecip32_1(sigB); Bits<32> sigZ = (sigA `* recip32) >> 32; sigZ = sigZ + 2; if ((sigZ & 7) <= 2) { sigZ = sigZ & 32'hfffffffc; Bits<64> rem = (sigA `<< 31) - (sigZ `* sigB); if ((rem & 64'h8000000000000000) != 0) { sigZ = sigZ - 4; } else { if (rem != 0) { sigZ = sigZ | 1; } } } return softfloat_roundPackToF32(signZ, expZ, sigZ, mode);
is_sp_nan?
Returns true if sp_value is a NaN (quiet or signaling)
Return Type |
Boolean |
|---|---|
Arguments |
Bits<32> sp_value |
-
Original
-
Pruned
return (sp_value[30:23] == 0b11111111) && (sp_value[22:0] != 0);
return (sp_value[30:23] == 0b11111111) && (sp_value[22:0] != 0);
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 |
XReg |
|---|---|
Arguments |
U32 FROM_SIZE, U32 TO_SIZE, XReg from_value |
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 |
Bits<64> |
|---|---|
Arguments |
Bits<64> a, Bits<32> dist |
-
Original
-
Pruned
return (dist < 63) ? a >> dist | ((a[dist - 1:0] != 0) ? 1 : 0) : ((a != 0) ? 1 : 0);
return (dist < 63) ? a >> dist | ((a[dist - 1:0] != 0) ? 1 : 0) : ((a != 0) ? 1 : 0);
count_leading_zeros_64
Returns the number of leading 0 bits before the most-significant 1 bit of value, or N if value is zero.
Return Type |
XReg |
|---|---|
Arguments |
U32 N, Bits<64> value |
-
Original
-
Pruned
for (U32 i = 0; i < N; i++) {
if (value[N - 1 - i] == 1) {
return i;
}
}
return N;
for (U32 i = 0; i < N; i++) {
if (value[N - 1 - i] == 1) {
return i;
}
}
return N;
f32_muladd
Fused multiply-add for single-precision floats. Computes (a * b) + c, with sign modifications based on op: Softfloat_mulAdd_addC: (a * b) + c Softfloat_mulAdd_subC: (a * b) - c (negate c) Softfloat_mulAdd_subProd: -(a * b) + c (negate product) Translated from Berkeley Softfloat softfloat_mulAddF32.
Return Type |
U32 |
|---|---|
Arguments |
U32 a, U32 b, U32 c, F32MulAddOp op, RoundingMode mode |
-
Original
-
Pruned
if (is_sp_signaling_nan?(a) || is_sp_signaling_nan?(b) || is_sp_signaling_nan?(c)) { set_fp_flag(FpFlag::NV); } Bits<1> signA = signF32UI(a); Bits<16> expA = expF32UI(a); Bits<32> sigA = fracF32UI(a); Bits<1> signB = signF32UI(b); Bits<16> expB = expF32UI(b); Bits<32> sigB = fracF32UI(b); Bits<1> signC = signF32UI(c) ^ op == F32MulAddOp::Softfloat_mulAdd_subC) ? 1 : 0); Bits<16> expC = expF32UI(c); Bits<32> sigC = fracF32UI(c); Bits<1> signProd = (signA ^ signB) ^ ((op == F32MulAddOp::Softfloat_mulAdd_subProd) ? 1 : 0); Bits<32> magBits; Bits<64> sig64Z; if (expA == 0xFF) { if ((sigA != 0) || ((expB == 0xFF) && (sigB != 0) { return SP_CANONICAL_NAN; } magBits = expB | sigB; if (magBits != 0) { U32 zA = packToF32UI(signProd, 0xFF, 0); if (expC != 0xFF) { return zA; } if (sigC != 0) { return SP_CANONICAL_NAN; } if (signProd == signC) { return zA; } } set_fp_flag(FpFlag::NV); return SP_CANONICAL_NAN; } if (expB == 0xFF) { if (sigB != 0) { return SP_CANONICAL_NAN; } magBits = expA | sigA; if (magBits != 0) { U32 zB = packToF32UI(signProd, 0xFF, 0); if (expC != 0xFF) { return zB; } if (sigC != 0) { return SP_CANONICAL_NAN; } if (signProd == signC) { return zB; } } set_fp_flag(FpFlag::NV); return SP_CANONICAL_NAN; } if (expC == 0xFF) { if (sigC != 0) { return SP_CANONICAL_NAN; } return c; } if (expA == 0) { if (sigA == 0) { if (expC | sigC) == 0) && (signProd != signC { return packToF32UI((mode == RoundingMode::RDN) ? 1 : 0, 0, 0); } return c; } ExpAndSig norm = softfloat_normSubnormalF32Sig(sigA); expA = norm.exp; sigA = norm.sig; } if (expB == 0) { if (sigB == 0) { if (expC | sigC) == 0) && (signProd != signC { return packToF32UI((mode == RoundingMode::RDN) ? 1 : 0, 0, 0); } return c; } ExpAndSig norm = softfloat_normSubnormalF32Sig(sigB); expB = norm.exp; sigB = norm.sig; } Bits<16> expProd = expA + expB - 16'h007E; sigA = (sigA | 32'h00800000) << 7; sigB = (sigB | 32'h00800000) << 7; U64 sigProd = sigA `* sigB; if (sigProd < 64'h2000000000000000) { expProd = expProd - 1; sigProd = sigProd << 1; } Bits<1> signZ = signProd; Bits<16> expZ; Bits<32> sigZ; if (expC == 0) { if (sigC == 0) { expZ = expProd - 1; sigZ = softfloat_shiftRightJam64(sigProd, 31); return softfloat_roundPackToF32(signZ, expZ, sigZ, mode); } ExpAndSig norm = softfloat_normSubnormalF32Sig(sigC); expC = norm.exp; sigC = norm.sig; } sigC = (sigC | 0x00800000) << 6; Bits<16> expDiff = expProd - expC; if (signProd == signC) { if ($signed(expDiff) <= 0s) { expZ = expC; sigZ = sigC + softfloat_shiftRightJam64(sigProd, 32 - expDiff); } else { expZ = expProd; sig64Z = sigProd + softfloat_shiftRightJam64(sigC `<< 32, expDiff); sigZ = softfloat_shiftRightJam64(sig64Z, 32); } if (sigZ < 0x40000000) { expZ = expZ - 1; sigZ = sigZ << 1; } return softfloat_roundPackToF32(signZ, expZ, sigZ, mode); } else { U64 sig64C = sigC `<< 32; if ($signed(expDiff) < 0s) { signZ = signC; expZ = expC; sig64Z = sig64C - softfloat_shiftRightJam64(sigProd, -expDiff); } else if (expDiff == 0) { expZ = expProd; sig64Z = sigProd - sig64C; if (sig64Z == 0) { return packToF32UI((mode == RoundingMode::RDN) ? 1 : 0, 0, 0); } if ((sig64Z & 64'h8000000000000000) != 0) { signZ = signZ ^ 1; sig64Z = -sig64Z; } } else { expZ = expProd; sig64Z = sigProd - softfloat_shiftRightJam64(sig64C, expDiff); } Bits<8> shiftDist = count_leading_zeros_64(64, sig64Z) - 1; expZ = expZ - shiftDist; shiftDist = shiftDist - 8'h20; if ($signed(shiftDist) < 0s) { sigZ = softfloat_shiftRightJam64(sig64Z, -shiftDist); } else { sigZ = sig64Z << shiftDist; } return softfloat_roundPackToF32(signZ, expZ, sigZ, mode); }
if (is_sp_signaling_nan?(a) || is_sp_signaling_nan?(b) || is_sp_signaling_nan?(c)) { set_fp_flag(FpFlag::NV); } Bits<1> signA = signF32UI(a); Bits<16> expA = expF32UI(a); Bits<32> sigA = fracF32UI(a); Bits<1> signB = signF32UI(b); Bits<16> expB = expF32UI(b); Bits<32> sigB = fracF32UI(b); Bits<1> signC = signF32UI(c) ^ op == F32MulAddOp::Softfloat_mulAdd_subC) ? 1 : 0); Bits<16> expC = expF32UI(c); Bits<32> sigC = fracF32UI(c); Bits<1> signProd = (signA ^ signB) ^ ((op == F32MulAddOp::Softfloat_mulAdd_subProd) ? 1 : 0); Bits<32> magBits; Bits<64> sig64Z; if (expA == 0xFF) { if ((sigA != 0) || ((expB == 0xFF) && (sigB != 0) { return 32'h7fc00000; } magBits = expB | sigB; if (magBits != 0) { U32 zA = packToF32UI(signProd, 0xFF, 0); if (expC != 0xFF) { return zA; } if (sigC != 0) { return 32'h7fc00000; } if (signProd == signC) { return zA; } } set_fp_flag(FpFlag::NV); return 32'h7fc00000; } if (expB == 0xFF) { if (sigB != 0) { return 32'h7fc00000; } magBits = expA | sigA; if (magBits != 0) { U32 zB = packToF32UI(signProd, 0xFF, 0); if (expC != 0xFF) { return zB; } if (sigC != 0) { return 32'h7fc00000; } if (signProd == signC) { return zB; } } set_fp_flag(FpFlag::NV); return 32'h7fc00000; } if (expC == 0xFF) { if (sigC != 0) { return 32'h7fc00000; } return c; } if (expA == 0) { if (sigA == 0) { if (expC | sigC) == 0) && (signProd != signC { return packToF32UI((mode == RoundingMode::RDN) ? 1 : 0, 0, 0); } return c; } ExpAndSig norm = softfloat_normSubnormalF32Sig(sigA); expA = norm.exp; sigA = norm.sig; } if (expB == 0) { if (sigB == 0) { if (expC | sigC) == 0) && (signProd != signC { return packToF32UI((mode == RoundingMode::RDN) ? 1 : 0, 0, 0); } return c; } ExpAndSig norm = softfloat_normSubnormalF32Sig(sigB); expB = norm.exp; sigB = norm.sig; } Bits<16> expProd = expA + expB - 16'h007E; sigA = (sigA | 32'h00800000) << 7; sigB = (sigB | 32'h00800000) << 7; U64 sigProd = sigA `* sigB; if (sigProd < 64'h2000000000000000) { expProd = expProd - 1; sigProd = sigProd << 1; } Bits<1> signZ = signProd; Bits<16> expZ; Bits<32> sigZ; if (expC == 0) { if (sigC == 0) { expZ = expProd - 1; sigZ = softfloat_shiftRightJam64(sigProd, 31); return softfloat_roundPackToF32(signZ, expZ, sigZ, mode); } ExpAndSig norm = softfloat_normSubnormalF32Sig(sigC); expC = norm.exp; sigC = norm.sig; } sigC = (sigC | 0x00800000) << 6; Bits<16> expDiff = expProd - expC; if (signProd == signC) { if ($signed(expDiff) <= 0s) { expZ = expC; sigZ = sigC + softfloat_shiftRightJam64(sigProd, 32 - expDiff); } else { expZ = expProd; sig64Z = sigProd + softfloat_shiftRightJam64(sigC `<< 32, expDiff); sigZ = softfloat_shiftRightJam64(sig64Z, 32); } if (sigZ < 0x40000000) { expZ = expZ - 1; sigZ = sigZ << 1; } return softfloat_roundPackToF32(signZ, expZ, sigZ, mode); } else { U64 sig64C = sigC `<< 32; if ($signed(expDiff) < 0s) { signZ = signC; expZ = expC; sig64Z = sig64C - softfloat_shiftRightJam64(sigProd, -expDiff); } else if (expDiff == 0) { expZ = expProd; sig64Z = sigProd - sig64C; if (sig64Z == 0) { return packToF32UI((mode == RoundingMode::RDN) ? 1 : 0, 0, 0); } if ((sig64Z & 64'h8000000000000000) != 0) { signZ = signZ ^ 1; sig64Z = -sig64Z; } } else { expZ = expProd; sig64Z = sigProd - softfloat_shiftRightJam64(sig64C, expDiff); } Bits<8> shiftDist = count_leading_zeros_64(64, sig64Z) - 1; expZ = expZ - shiftDist; shiftDist = shiftDist - 8'h20; if ($signed(shiftDist) < 0s) { sigZ = softfloat_shiftRightJam64(sig64Z, -shiftDist); } else { sigZ = sig64Z << shiftDist; } return softfloat_roundPackToF32(signZ, expZ, sigZ, mode); }
f32_mul
Multiplies two 32-bit floating point numbers. Translated from Berkeley Softfloat f32_mul.
Return Type |
U32 |
|---|---|
Arguments |
U32 a, U32 b, RoundingMode mode |
-
Original
-
Pruned
if (is_sp_signaling_nan?(a) || is_sp_signaling_nan?(b)) { set_fp_flag(FpFlag::NV); } Bits<1> signA = signF32UI(a); Bits<16> expA = expF32UI(a); Bits<23> fracA = fracF32UI(a); Bits<1> signB = signF32UI(b); Bits<16> expB = expF32UI(b); Bits<23> fracB = fracF32UI(b); Bits<1> signZ = signA ^ signB; Bits<32> sigA = fracA; Bits<32> sigB = fracB; Bits<16> expZ; Bits<32> sigZ; if (expA == 8'hFF) { if ((fracA != 0) || expB == 8'hFF) && (fracB != 0) { return SP_CANONICAL_NAN; } if ((expB == 0) && (fracB == 0)) { set_fp_flag(FpFlag::NV); return SP_CANONICAL_NAN; } return packToF32UI(signZ, 8'hFF, 0); } if (expB == 8'hFF) { if (fracB != 0) { return SP_CANONICAL_NAN; } if ((expA == 0) && (fracA == 0)) { set_fp_flag(FpFlag::NV); return SP_CANONICAL_NAN; } return packToF32UI(signZ, 8'hFF, 0); } if (expA == 0) { if (fracA == 0) { return packToF32UI(signZ, 0, 0); } ExpAndSig norm = softfloat_normSubnormalF32Sig(fracA); expA = norm.exp; sigA = norm.sig; } if (expB == 0) { if (fracB == 0) { return packToF32UI(signZ, 0, 0); } ExpAndSig norm = softfloat_normSubnormalF32Sig(fracB); expB = norm.exp; sigB = norm.sig; } expZ = expA + expB - 16'h007F; sigA = (sigA | 32'h00800000) << 7; sigB = (sigB | 32'h00800000) << 8; sigZ = softfloat_shiftRightJam64(sigA `* sigB, 32); if (sigZ < 0x40000000) { expZ = expZ - 1; sigZ = sigZ << 1; } return softfloat_roundPackToF32(signZ, expZ, sigZ, mode);
if (is_sp_signaling_nan?(a) || is_sp_signaling_nan?(b)) { set_fp_flag(FpFlag::NV); } Bits<1> signA = signF32UI(a); Bits<16> expA = expF32UI(a); Bits<23> fracA = fracF32UI(a); Bits<1> signB = signF32UI(b); Bits<16> expB = expF32UI(b); Bits<23> fracB = fracF32UI(b); Bits<1> signZ = signA ^ signB; Bits<32> sigA = fracA; Bits<32> sigB = fracB; Bits<16> expZ; Bits<32> sigZ; if (expA == 8'hFF) { if ((fracA != 0) || expB == 8'hFF) && (fracB != 0) { return 32'h7fc00000; } if ((expB == 0) && (fracB == 0)) { set_fp_flag(FpFlag::NV); return 32'h7fc00000; } return packToF32UI(signZ, 8'hFF, 0); } if (expB == 8'hFF) { if (fracB != 0) { return 32'h7fc00000; } if ((expA == 0) && (fracA == 0)) { set_fp_flag(FpFlag::NV); return 32'h7fc00000; } return packToF32UI(signZ, 8'hFF, 0); } if (expA == 0) { if (fracA == 0) { return packToF32UI(signZ, 0, 0); } ExpAndSig norm = softfloat_normSubnormalF32Sig(fracA); expA = norm.exp; sigA = norm.sig; } if (expB == 0) { if (fracB == 0) { return packToF32UI(signZ, 0, 0); } ExpAndSig norm = softfloat_normSubnormalF32Sig(fracB); expB = norm.exp; sigB = norm.sig; } expZ = expA + expB - 16'h007F; sigA = (sigA | 32'h00800000) << 7; sigB = (sigB | 32'h00800000) << 8; sigZ = softfloat_shiftRightJam64(sigA `* sigB, 32); if (sigZ < 0x40000000) { expZ = expZ - 1; sigZ = sigZ << 1; } return softfloat_roundPackToF32(signZ, expZ, sigZ, mode);
softfloat_approxRecipSqrt32_1
Returns a 32-bit approximation of 1/sqrt(a). Translated from Berkeley Softfloat softfloat_approxRecipSqrt32_1.
Return Type |
U32 |
|---|---|
Arguments |
Bits<1> oddExpA, Bits<32> a |
-
Original
-
Pruned
Bits<8> index = a;
r = r + ((adj `* sqrSigma0) >> 48);
if ((r & 32'h80000000) == 0) {
r = 32'h80000000;
}
return r;
Bits<8> index = a;
r = r + ((adj `* sqrSigma0) >> 48);
if ((r & 32'h80000000) == 0) {
r = 32'h80000000;
}
return r;
f32_sqrt
Computes the square root of a 32-bit floating point number. Translated from Berkeley Softfloat f32_sqrt.
Return Type |
U32 |
|---|---|
Arguments |
U32 a, RoundingMode mode |
-
Original
-
Pruned
if (is_sp_signaling_nan?(a)) { set_fp_flag(FpFlag::NV); } Bits<1> signA = signF32UI(a); Bits<16> expA = expF32UI(a); Bits<32> fracA = fracF32UI(a); if (expA == 8'hFF) { if (fracA != 0) { return SP_CANONICAL_NAN; } if (signA == 0) { return a; } set_fp_flag(FpFlag::NV); return SP_CANONICAL_NAN; } if (signA == 1) { if ((expA == 0) && (fracA == 0)) { return a; } set_fp_flag(FpFlag::NV); return SP_CANONICAL_NAN; } if (expA == 0) { if (fracA == 0) { return a; } ExpAndSig norm = softfloat_normSubnormalF32Sig(fracA); expA = norm.exp; fracA = norm.sig; } Bits<16> adjExp = expA - 16'h007F; Bits<16> expZ = adjExp + 16'h007E; Bits<1> oddExpA = expA[0]; Bits<32> sigA32 = (fracA | 32'h00800000) << 8; Bits<32> sigZ = (sigA32 `* softfloat_approxRecipSqrt32_1(oddExpA, sigA32)) >> 32; if (oddExpA == 1) { sigZ = sigZ >> 1; } sigZ = sigZ + 2; if ((sigZ & 0x3F) < 2) { Bits<32> shiftedSigZ = sigZ >> 2; Bits<32> negRem = shiftedSigZ * shiftedSigZ; sigZ = sigZ & ~32'h3; if ((negRem & 0x80000000) != 0) { sigZ = sigZ | 1; } else { if (negRem != 0) { sigZ = sigZ - 1; } } } return softfloat_roundPackToF32(0, expZ, sigZ, mode);
if (is_sp_signaling_nan?(a)) { set_fp_flag(FpFlag::NV); } Bits<1> signA = signF32UI(a); Bits<16> expA = expF32UI(a); Bits<32> fracA = fracF32UI(a); if (expA == 8'hFF) { if (fracA != 0) { return 32'h7fc00000; } if (signA == 0) { return a; } set_fp_flag(FpFlag::NV); return 32'h7fc00000; } if (signA == 1) { if ((expA == 0) && (fracA == 0)) { return a; } set_fp_flag(FpFlag::NV); return 32'h7fc00000; } if (expA == 0) { if (fracA == 0) { return a; } ExpAndSig norm = softfloat_normSubnormalF32Sig(fracA); expA = norm.exp; fracA = norm.sig; } Bits<16> adjExp = expA - 16'h007F; Bits<16> expZ = adjExp + 16'h007E; Bits<1> oddExpA = expA[0]; Bits<32> sigA32 = (fracA | 32'h00800000) << 8; Bits<32> sigZ = (sigA32 `* softfloat_approxRecipSqrt32_1(oddExpA, sigA32)) >> 32; if (oddExpA == 1) { sigZ = sigZ >> 1; } sigZ = sigZ + 2; if ((sigZ & 0x3F) < 2) { Bits<32> shiftedSigZ = sigZ >> 2; Bits<32> negRem = shiftedSigZ * shiftedSigZ; sigZ = sigZ & 32'hfffffffc; if ((negRem & 0x80000000) != 0) { sigZ = sigZ | 1; } else { if (negRem != 0) { sigZ = sigZ - 1; } } } return softfloat_roundPackToF32(0, expZ, sigZ, mode);
softfloat_subMagsF32
Returns difference of the magnitudes of 2 floating point numbers
Return Type |
U32 |
|---|---|
Arguments |
U32 a, U32 b, RoundingMode mode |
-
Original
-
Pruned
if (is_sp_signaling_nan?(a) || is_sp_signaling_nan?(b)) { set_fp_flag(FpFlag::NV); } Bits<16> expA = expF32UI(a); Bits<32> sigA = fracF32UI(a); Bits<16> expB = expF32UI(b); Bits<32> sigB = fracF32UI(b); U32 sigZ; U32 z; Bits<1> signZ; Bits<8> expZ; U32 sigDiff; U32 sigX; U32 sigY; Bits<8> shiftDist; Bits<16> expDiff = expA - expB; if (expDiff == 16'd0) { if (expA == 8'hFF) { set_fp_flag(FpFlag::NV); return SP_CANONICAL_NAN; } sigDiff = sigA - sigB; if (sigDiff == 0) { return packToF32UI(((mode == RoundingMode::RDN) ? 1 : 0), 0, 0); } if (expA != 0) { expA = expA - 1; } signZ = signF32UI(a); if (sigDiff < 0) { signZ = ~signZ; sigDiff = -32'sh1 * sigDiff; } shiftDist = count_leading_zeros(32, sigDiff) - 8; expZ = expA - shiftDist; if (expZ < 0) { shiftDist = expA; expZ = 0; } return packToF32UI(signZ, expZ, sigDiff << shiftDist); } else { signZ = signF32UI(a); sigA = sigA << 7; sigB = sigB << 7; if ($signed(expDiff) < 0s) { signZ = ~signZ; if (expB == 0xFF) { if (sigB != 0) { return SP_CANONICAL_NAN; } return packToF32UI(signZ, expB, 0); } expZ = expB - 1; sigX = sigB | 0x40000000; sigY = sigA + ((expA != 0) ? 0x40000000 : sigA); expDiff = -expDiff; } else { if (expA == 0xFF) { if (sigA != 0) { return SP_CANONICAL_NAN; } return a; } expZ = expA - 1; sigX = sigA | 0x40000000; sigY = sigB + ((expB != 0) ? 0x40000000 : sigB); } return softfloat_normRoundPackToF32(signZ, expZ, sigX - softfloat_shiftRightJam32(sigY, expDiff), mode); }
if (is_sp_signaling_nan?(a) || is_sp_signaling_nan?(b)) { set_fp_flag(FpFlag::NV); } Bits<16> expA = expF32UI(a); Bits<32> sigA = fracF32UI(a); Bits<16> expB = expF32UI(b); Bits<32> sigB = fracF32UI(b); U32 sigZ; U32 z; Bits<1> signZ; Bits<8> expZ; U32 sigDiff; U32 sigX; U32 sigY; Bits<8> shiftDist; Bits<16> expDiff = expA - expB; if (expDiff == 16'd0) { if (expA == 8'hFF) { set_fp_flag(FpFlag::NV); return 32'h7fc00000; } sigDiff = sigA - sigB; if (sigDiff == 0) { return packToF32UI(((mode == RoundingMode::RDN) ? 1 : 0), 0, 0); } if (expA != 0) { expA = expA - 1; } signZ = signF32UI(a); if (sigDiff < 0) { signZ = ~signZ; sigDiff = 32'-1 * sigDiff; } shiftDist = count_leading_zeros(32, sigDiff) - 8; expZ = expA - shiftDist; if (expZ < 0) { shiftDist = expA; expZ = 0; } return packToF32UI(signZ, expZ, sigDiff << shiftDist); } else { signZ = signF32UI(a); sigA = sigA << 7; sigB = sigB << 7; if ($signed(expDiff) < 0s) { signZ = ~signZ; if (expB == 0xFF) { if (sigB != 0) { return 32'h7fc00000; } return packToF32UI(signZ, expB, 0); } expZ = expB - 1; sigX = sigB | 0x40000000; sigY = sigA + ((expA != 0) ? 0x40000000 : sigA); expDiff = -expDiff; } else { if (expA == 0xFF) { if (sigA != 0) { return 32'h7fc00000; } return a; } expZ = expA - 1; sigX = sigA | 0x40000000; sigY = sigB + ((expB != 0) ? 0x40000000 : sigB); } return softfloat_normRoundPackToF32(signZ, expZ, sigX - softfloat_shiftRightJam32(sigY, expDiff), mode); }
f32_sub
Returns difference of 2 floating point numbers
Return Type |
U32 |
|---|---|
Arguments |
U32 a, U32 b, RoundingMode mode |
-
Original
-
Pruned
U32 a_xor_b = a ^ b; if (signF32UI(a_xor_b) == 1) { return softfloat_addMagsF32(a, b, mode); } else { return softfloat_subMagsF32(a, b, mode); }
U32 a_xor_b = a ^ b; if (signF32UI(a_xor_b) == 1) { return softfloat_addMagsF32(a, b, mode); } else { return softfloat_subMagsF32(a, b, mode); }
jump_halfword
Jump to virtual halfword address target_hw_addr.
If target address is misaligned, raise a MisalignedAddress exception.
Return Type |
void |
|---|---|
Arguments |
XReg target_hw_addr |
-
Original
-
Pruned
assert((target_hw_addr & 0x1) == 0x0, "Expected halfword-aligned address in jump_halfword"); $pc = target_hw_addr;
fence_tso (builtin)
Execute a TSO memory ordering fence.(according to the FENCE instruction).
Return Type |
void |
|---|---|
Arguments |
fence (builtin)
Execute a memory ordering fence.(according to the FENCE instruction).
Return Type |
void |
|---|---|
Arguments |
Boolean pi, Boolean pr, Boolean po, Boolean pw, Boolean si, Boolean sr, Boolean so, Boolean sw |
read_physical_memory_16 (builtin)
Read two bytes from physical memory.
Return Type |
Bits<16> |
|---|---|
Arguments |
XReg paddr |
write_physical_memory_16 (builtin)
Write two bytes to physical memory.
Return Type |
void |
|---|---|
Arguments |
XReg paddr, Bits<16> value |
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 |
void |
|---|---|
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 |
void |
|---|---|
Arguments |
VmaOrderType order_type |
invalidate_translations (generated)
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 |
void |
|---|---|
Arguments |
VmaOrderType inval_type |
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 |
void |
|---|---|
Arguments |
VmaOrderType order_type |
mask_eaddr
Mask upper N bits of an effective address if pointer masking is enabled
Return Type |
XReg |
|---|---|
Arguments |
XReg eaddr |
-
Original
-
Pruned
return eaddr;
return eaddr;
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 |
Boolean |
|---|---|
Arguments |
XReg vaddr |
-
Original
-
Pruned
if (CSR[misa].S == 1'b0) { return true; } SatpMode satp_mode; if (virtual_mode?()) { satp_mode = $enum(SatpMode, CSR[vsatp].MODE); } else { satp_mode = $enum(SatpMode, CSR[satp].MODE); } XReg eaddr = mask_eaddr(vaddr); if (SATP_MODE_BARE && (satp_mode == SatpMode::Bare)) { return true; } else if ((MXLEN == 32) && satp_mode == SatpMode::Sv32) { return true; } else if ((MXLEN == 64) && satp_mode == SatpMode::Sv39) { return eaddr[63:39] == {25{eaddr[38]}}; } else if ((MXLEN == 64) && satp_mode == SatpMode::Sv48) { return eaddr[63:48] == {16{eaddr[47]}}; } else if ((MXLEN == 64) && satp_mode == SatpMode::Sv57) { return eaddr[63:57] == {6{eaddr[56]}}; } return false;
SatpMode satp_mode; if (virtual_mode?()) { satp_mode = $enum(SatpMode, CSR[vsatp].MODE); } else { satp_mode = $enum(SatpMode, CSR[satp].MODE); } XReg eaddr = mask_eaddr(vaddr); if ((satp_mode == SatpMode::Bare)) { 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]}}; } return false;
canonical_gpaddr?
Returns whether or not gpaddr is a valid (i.e., canonical) guest physical address.
Return Type |
Boolean |
|---|---|
Arguments |
XReg gpaddr |
-
Original
-
Pruned
SatpMode satp_mode = $enum(SatpMode, CSR[satp].MODE); if (satp_mode == SatpMode::Bare) { return true; } else if (satp_mode == SatpMode::Sv32) { return true; } else if ((MXLEN > 32) && (satp_mode == SatpMode::Sv39)) { return gpaddr[63:39] == {25{gpaddr[38]}}; } else if ((MXLEN > 32) && (satp_mode == SatpMode::Sv48)) { return gpaddr[63:48] == {16{gpaddr[47]}}; } else if ((MXLEN > 32) && (satp_mode == SatpMode::Sv57)) { return gpaddr[63:57] == {6{gpaddr[56]}}; } return false;
SatpMode satp_mode = $enum(SatpMode, CSR[satp].MODE); if (satp_mode == SatpMode::Bare) { return true; } else if (satp_mode == SatpMode::Sv32) { return true; } else if ((satp_mode == SatpMode::Sv39)) { return gpaddr[63:39] == {25{gpaddr[38]}}; } else if ((satp_mode == SatpMode::Sv48)) { return gpaddr[63:48] == {16{gpaddr[47]}}; } else if ((satp_mode == SatpMode::Sv57)) { return gpaddr[63:57] == {6{gpaddr[56]}}; } return false;
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 |
void |
|---|---|
Arguments |
String why |
vector_state
Get the current vector state from CSRs
Return Type |
VectorState |
|---|---|
Arguments |
-
Original
-
Pruned
VectorState state; state.log2_sew = 3 + CSR[vtype].VSEW; state.sew = 7'b1 << state.log2_sew; Bits<3> vlmul = CSR[vtype].VLMUL; state.lmul_type = CSR[vtype].VLMUL[2] == 1'b1 ? VectorLmulType::Divide : VectorLmulType::Multiply; state.log2_lmul = CSR[vtype].VLMUL[1:0]; if (vlmul == 3'b101) { state.log2_lmul = 3; } else if (vlmul == 3'b110) { state.log2_lmul = 2; } else if (vlmul == 3'b111) { state.log2_lmul = 1; } else if (vlmul == 3'b100) { unpredictable("VLMUL value 0b100 is reserved"); } return state;
VectorState state; state.log2_sew = 3 + CSR[vtype].VSEW; state.sew = 7'b1 << state.log2_sew; Bits<3> vlmul = CSR[vtype].VLMUL; state.lmul_type = CSR[vtype].VLMUL[2] == 1'b1 ? VectorLmulType::Divide : VectorLmulType::Multiply; state.log2_lmul = CSR[vtype].VLMUL[1:0]; if (vlmul == 3'b101) { state.log2_lmul = 3; } else if (vlmul == 3'b110) { state.log2_lmul = 2; } else if (vlmul == 3'b111) { state.log2_lmul = 1; } else if (vlmul == 3'b100) { unpredictable("VLMUL value 0b100 is reserved"); } return state;
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 |
void |
|---|---|
Arguments |
in_naturally_aligned_region?
Checks if a length-bit access starting at address lies entirely within an N-bit naturally-aligned region.
Return Type |
Boolean |
|---|---|
Arguments |
U32 N, XReg address, U32 length |
-
Original
-
Pruned
XReg Mask = (N / 8) - 1; return (address & ~Mask) == ((address + length - 1) & ~Mask);
XReg Mask = (N / 8) - 1; return (address & ~Mask) == ((address + length - 1) & ~Mask);
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 |
Boolean |
|---|---|
Arguments |
U32 N, Bits<PHYS_ADDR_WIDTH> physical_address |
-
Original
-
Pruned
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?(64, 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; }
return false
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 |
Bits<64> |
|---|---|
Arguments |
Bits<PHYS_ADDR_WIDTH> phys_addr, Bits<64> value, AmoOperation op |
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 |
XReg |
|---|---|
Arguments |
U32 N, XReg virtual_address, XReg value, AmoOperation op, Bits<1> aq, Bits<1> rl, Bits<INSTR_ENC_SIZE> encoding |
-
Original
-
Pruned
Boolean aligned = is_naturally_aligned(N, virtual_address); if (!aligned && MISALIGNED_LDST_EXCEPTION_PRIORITY == "high") { raise(ExceptionCode::StoreAmoAddressMisaligned, 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, mode(), virtual_address); } else if (op == AmoOperation::Add || op == AmoOperation::Max || op == AmoOperation::Maxu || op == AmoOperation::Min || op == AmoOperation::Minu) { if (!pma_applies?(PmaAttribute::AmoArithmetic, physical_address, N)) { raise(ExceptionCode::StoreAmoAccessFault, mode(), virtual_address); } } else if (op == AmoOperation::And || op == AmoOperation::Or || op == AmoOperation::Xor) { if (!pma_applies?(PmaAttribute::AmoLogical, physical_address, N)) { raise(ExceptionCode::StoreAmoAccessFault, 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, 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); }
Boolean aligned = is_naturally_aligned(N, virtual_address); if (!aligned) { raise(ExceptionCode::StoreAmoAddressMisaligned, mode(), virtual_address); } Bits<PHYS_ADDR_WIDTH> physical_address = translate(virtual_address, MemoryOperation::ReadModifyWrite, effective_ldst_mode(), encoding).paddr; if (pma_applies?(PmaAttribute::AmoNone, physical_address, N)) { raise(ExceptionCode::StoreAmoAccessFault, mode(), virtual_address); } else if ((op == AmoOperation::Add || op == AmoOperation::Max || op == AmoOperation::Maxu || op == AmoOperation::Min || op == AmoOperation::Minu)) { if (!pma_applies?(PmaAttribute::AmoArithmetic, physical_address, N)) { raise(ExceptionCode::StoreAmoAccessFault, mode(), virtual_address); } } else if ((op == AmoOperation::And || op == AmoOperation::Or || op == AmoOperation::Xor)) { if (!pma_applies?(PmaAttribute::AmoLogical, physical_address, N)) { raise(ExceptionCode::StoreAmoAccessFault, mode(), virtual_address); } } else { assert(pma_applies?(PmaAttribute::AmoSwap, physical_address, N) && op == AmoOperation::Swap, "Bad AMO operation"); } if (!aligned) { raise(ExceptionCode::StoreAmoAddressMisaligned, 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); }
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 |
void |
|---|---|
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 |
Bits<32> |
|---|---|
Arguments |
Bits<PHYS_ADDR_WIDTH> phys_addr, Bits<32> value, AmoOperation op |
register_reservation_set
Register a reservation for a physical address range that subsumes [physical_address, physical_address + N).
Return Type |
void |
|---|---|
Arguments |
Bits<MXLEN> physical_address, Bits<MXLEN> length |
-
Original
-
Pruned
reservation_set_valid = true;
reservation_set_address = physical_address;
if (LRSC_RESERVATION_STRATEGY == "reserve naturally-aligned 64-byte region") {
reservation_set_address = physical_address & ~MXLEN'h3f;
reservation_set_size = 64;
} else if (LRSC_RESERVATION_STRATEGY == "reserve naturally-aligned 128-byte region") {
reservation_set_address = physical_address & ~MXLEN'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");
unreachable();
}
reservation_set_valid = true; reservation_set_address = physical_address; reservation_set_address = physical_address & 64'hffffffffffffffc0; reservation_set_size = 64;
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 |
XReg |
|---|---|
Arguments |
U32 N, Bits<MXLEN> virtual_address, Bits<1> aq, Bits<1> rl, Bits<INSTR_ENC_SIZE> encoding |
-
Original
-
Pruned
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, 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, 1'b0, 1'b0);
Bits<PHYS_ADDR_WIDTH> physical_address = translate(virtual_address, MemoryOperation::Read, effective_ldst_mode(), encoding).paddr; if (pma_applies?(PmaAttribute::RsrvNone, physical_address, N)) { raise(ExceptionCode::LoadAccessFault, mode(), virtual_address); } if (aq == 1) { memory_model_acquire(); } if (rl == 1) { memory_model_release(); } register_reservation_set(physical_address, N); return read_memory_aligned(N, physical_address, encoding, 1'b0, 1'b0);
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 |
Boolean |
|---|---|
Arguments |
XReg region_start, U32 region_size, XReg target_start, U32 target_size |
-
Original
-
Pruned
return target_start >= region_start && (target_start + target_size) <= (region_start + region_size);
return target_start >= region_start && (target_start + target_size) <= (region_start + region_size);
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 platform 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 |
void |
|---|---|
Arguments |
-
Original
-
Pruned
reservation_set_valid = false;
reservation_set_valid = false;
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 preceding are met, perform the store and return 0. Otherwise, return 1.
Return Type |
Boolean |
|---|---|
Arguments |
U32 N, Bits<MXLEN> virtual_address, Bits<MXLEN> value, Bits<1> aq, Bits<1> rl, Bits<INSTR_ENC_SIZE> encoding |
-
Original
-
Pruned
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, 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;
Bits<PHYS_ADDR_WIDTH> physical_address = translate(virtual_address, MemoryOperation::Write, effective_ldst_mode(), encoding).paddr; if (pma_applies?(PmaAttribute::RsrvNone, physical_address, N)) { raise(ExceptionCode::StoreAmoAccessFault, 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, 64'64, physical_address, N)) { invalidate_reservation_set(); return false; } write_physical_memory(N, physical_address, value); return true;
wrs_nto (builtin)
Wait-on-reservation-set with no timeout: hint that the processor should enter a low power state until the reservation set is invalidated or an interrupt is pending.
A valid implementation is a no-op.
The model will advance the PC; this function does not need to.
Return Type |
void |
|---|---|
Arguments |
wrs_sto (builtin)
Wait-on-reservation-set with short timeout: hint that the processor should enter a low power state until the reservation set is invalidated, an interrupt is pending, or an implementation-defined short timeout elapses.
A valid implementation is a no-op.
The model will advance the PC; this function does not need to.
Return Type |
void |
|---|---|
Arguments |
highest_set_bit
Returns the position of the highest (nearest MSB) bit that is '1', or -1 if value is zero.
Return Type |
Bits<8> |
|---|---|
Arguments |
XReg value |
lowest_set_bit
Returns the position of the lowest (nearest LSB) bit that is '1', or XLEN if value is zero.
Return Type |
Bits<8> |
|---|---|
Arguments |
XReg value |
softfloat_roundToI32_no_flag
Round to signed 32-bit integer, using rounding_mode No flag to be set
Return Type |
Bits<32> |
|---|---|
Arguments |
Bits<1> sign, Bits<64> sig, RoundingMode roundingMode |
-
Original
-
Pruned
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) {
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) < 's0) != (sign == 1) {
return sign == 1 ? WORD_NEG_OVERFLOW : WORD_POS_OVERFLOW;
}
return z;
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) {
return sign == 1 ? 32'h80000000 : 32'h7fffffff;
}
Bits<32> sig32 = sig >> 12;
if ((roundBits == 0x800 && (roundingMode == RoundingMode::RNE))) {
sig32 = sig32 & 32'hfffffffe;
}
Bits<32> z = (sign == 1) ? -sig32 : sig32;
if ((z != 0) && $signed(z) < 's0) != (sign == 1) {
return sign == 1 ? 32'h80000000 : 32'h7fffffff;
}
return z;
f32_to_i32_no_flag
Converts 32-bit floating point number to a signed 32-bit integer No flags to be set
Return Type |
U32 |
|---|---|
Arguments |
U32 a, RoundingMode mode |
-
Original
-
Pruned
Bits<1> sign = signF32UI(a); Bits<8> exp = expF32UI(a); Bits<23> sig = fracF32UI(a); Bits<8> shiftDist; U64 sig64; if ((exp == 8'hFF) && (sig != 0)) { sign = 0; return I32_NAN; } if (exp != 0) { sig = sig | 32'h00800000; } sig64 = sig `<< 32; shiftDist = 8'hAA - exp; if (shiftDist > 0) { sig64 = softfloat_shiftRightJam64(sig64, shiftDist); } return softfloat_roundToI32_no_flag(sign, sig64, mode);
Bits<1> sign = signF32UI(a); Bits<8> exp = expF32UI(a); Bits<23> sig = fracF32UI(a); Bits<8> shiftDist; U64 sig64; if ((exp == 8'hFF) && (sig != 0)) { sign = 0; return 32'h7fffffff; } if (exp != 0) { sig = sig | 32'h00800000; } sig64 = sig `<< 32; shiftDist = 8'hAA - exp; if (shiftDist > 0) { sig64 = softfloat_shiftRightJam64(sig64, shiftDist); } return softfloat_roundToI32_no_flag(sign, sig64, mode);
returnMag
Returns magnitude of the given number Does not modify the input
Return Type |
U32 |
|---|---|
Arguments |
U32 a |
-
Original
-
Pruned
U32 a_copy = a; a_copy[31] = 1'b0; return a_copy;
U32 a_copy = a; a_copy[31] = 1'b0; return a_copy;
softfloat_normRoundPackToF32_no_flag
Normalize, round, and pack into a 32-bit floating point value No flags to be set
Return Type |
Bits<32> |
|---|---|
Arguments |
Bits<1> sign, Bits<16> exp, Bits<32> sig, RoundingMode mode |
-
Original
-
Pruned
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_no_flag(sign, exp, sig << shiftDist, mode); }
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_no_flag(sign, exp, sig << shiftDist, mode); }
i32_to_f32_no_flag
Converts 32-bit signed integer to 32-bit floating point number No flags to be set
Return Type |
U32 |
|---|---|
Arguments |
U32 a, RoundingMode mode |
-
Original
-
Pruned
Bits<1> sign = a[31];
if ((a & 0x7FFFFFFF) == 0) {
return (sign == 1) ? packToF32UI(1, 0x9E, 0) : packToF32UI(0, 0, 0);
}
U32 magnitude_of_A = returnMag(a);
return softfloat_normRoundPackToF32_no_flag(sign, 0x9C, magnitude_of_A, mode);
Bits<1> sign = a[31];
if ((a & 0x7FFFFFFF) == 0) {
return (sign == 1) ? 32'hcf000000 : 32'0;
}
U32 magnitude_of_A = returnMag(a);
return softfloat_normRoundPackToF32_no_flag(sign, 0x9C, magnitude_of_A, mode);
round_f32_to_integral
Rounds 32-bit floating point number to a signed 32-bit integer. This 32-bit integer is represented as a floating point number and returned.
Return Type |
U32 |
|---|---|
Arguments |
U32 a, RoundingMode mode |
-
Original
-
Pruned
if ((is_sp_neg_inf?(a)) || (is_sp_pos_inf?(a)) || (is_sp_pos_zero?(a)) || (is_sp_neg_zero?(a))) { return a; } else if (is_sp_signaling_nan?(a)) { set_fp_flag(FpFlag::NV); return a; } U32 intermediate; intermediate = f32_to_i32_no_flag(a, mode); return i32_to_f32_no_flag(intermediate, mode);
if ((is_sp_neg_inf?(a)) || (is_sp_pos_inf?(a)) || (is_sp_pos_zero?(a)) || (is_sp_neg_zero?(a))) { return a; } else if (is_sp_signaling_nan?(a)) { set_fp_flag(FpFlag::NV); return a; } U32 intermediate; intermediate = f32_to_i32_no_flag(a, mode); return i32_to_f32_no_flag(intermediate, mode);
softfloat_normSubnormalF16Sig
normalize subnormal half-precision value
Return Type |
Bits<5>, Bits<10> |
|---|---|
Arguments |
Bits<16> hp_value |
-
Original
-
Pruned
Bits<8> shift_dist = count_leading_zeros(16, hp_value); return 1 - shift_dist, hp_value << shift_dist;
Bits<8> shift_dist = count_leading_zeros(16, hp_value); return 1 - shift_dist, hp_value << shift_dist;
packToF16UI
Pack components into a 16-bit value
Return Type |
Bits<32> |
|---|---|
Arguments |
Bits<1> sign, Bits<5> exp, Bits<10> sig |
-
Original
-
Pruned
return {sign, exp, sig};
return {sign, exp, sig};
prefetch_instruction (builtin)
Hint to prefetch a block containing virtual_address for an upcoming fetch.
Return Type |
void |
|---|---|
Arguments |
XReg virtual_address |
prefetch_read (builtin)
Hint to prefetch a block containing virtual_address for an upcoming load.
Return Type |
void |
|---|---|
Arguments |
XReg virtual_address |
prefetch_write (builtin)
Hint to prefetch a block containing virtual_address for an upcoming store.
Return Type |
void |
|---|---|
Arguments |
XReg virtual_address |
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 |
void |
|---|---|
Arguments |
XReg cache_block_physical_address |
unimplemented_csr
Either raises an IllegalInstruction exception or enters unpredictable state, depending on the setting of the TRAP_ON_UNIMPLEMENTED_CSR parameter.
Return Type |
void |
|---|---|
Arguments |
Bits<INSTR_ENC_SIZE> encoding |
-
Original
-
Pruned
if (TRAP_ON_UNIMPLEMENTED_CSR) {
raise(ExceptionCode::IllegalInstruction, mode(), encoding);
} else {
unpredictable("Accessing an unimplmented CSR");
}
compatible_mode?
Returns true if target_mode is more privileged than actual_mode.
Return Type |
Boolean |
|---|---|
Arguments |
PrivilegeMode target_mode, PrivilegeMode actual_mode |
-
Original
-
Pruned
if (target_mode == PrivilegeMode::M) {
return actual_mode == PrivilegeMode::M;
} else if (target_mode == PrivilegeMode::S) {
return (actual_mode == PrivilegeMode::M) || (actual_mode == PrivilegeMode::S);
} else if (target_mode == PrivilegeMode::U) {
return (actual_mode == PrivilegeMode::M) || (actual_mode == PrivilegeMode::S) || (actual_mode == PrivilegeMode::U);
} else if (target_mode == PrivilegeMode::VS) {
return (actual_mode == PrivilegeMode::M) || (actual_mode == PrivilegeMode::S) || (actual_mode == PrivilegeMode::VS);
} else if (target_mode == PrivilegeMode::VU) {
return (actual_mode == PrivilegeMode::M) || (actual_mode == PrivilegeMode::S) || (actual_mode == PrivilegeMode::VS) || (actual_mode == PrivilegeMode::VU);
}
return false;
if (target_mode == PrivilegeMode::M) {
return actual_mode == PrivilegeMode::M;
} else if (target_mode == PrivilegeMode::S) {
return (actual_mode == PrivilegeMode::M) || (actual_mode == PrivilegeMode::S);
} else if (target_mode == PrivilegeMode::U) {
return (actual_mode == PrivilegeMode::M) || (actual_mode == PrivilegeMode::S) || (actual_mode == PrivilegeMode::U);
} else if (target_mode == PrivilegeMode::VS) {
return (actual_mode == PrivilegeMode::M) || (actual_mode == PrivilegeMode::S) || (actual_mode == PrivilegeMode::VS);
} else if (target_mode == PrivilegeMode::VU) {
return (actual_mode == PrivilegeMode::M) || (actual_mode == PrivilegeMode::S) || (actual_mode == PrivilegeMode::VS) || (actual_mode == PrivilegeMode::VU);
}
return false;
csr_sw_write (generated)
Writes value to csr, applying an WARL transformations first.
Uses the sw_write(…) functions of CSR field definitions.
Return Type |
void |
|---|---|
Arguments |
Csr csr, Bits<MXLEN> value |
ifence (builtin)
Execute a memory ordering instruction fence (according to FENCE.I).
Return Type |
void |
|---|---|
Arguments |
pause (builtin)
Pause hart retirement for a implementation-defined period of time, which may be zero.
See Zihintpause for more.
Return Type |
void |
|---|---|
Arguments |
read_hpm_counter (builtin)
Returns the value of hpmcounterN.
N must be between 3..31.
hpmcounterN must be implemented.
Return Type |
Bits<64> |
|---|---|
Arguments |
Bits<5> n |
valid_interrupt_code?
Returns true if code is a legal interrupt number.
Return Type |
Boolean |
|---|---|
Arguments |
XReg code |
-
Original
-
Pruned
if (code > 1 `<< $enum_element_size(InterruptCode - 1)) {
return false;
}
if ($array_includes?($enum_to_a(InterruptCode), code)) {
return true;
} else {
return false;
}
if (code > 5'15) {
return false;
}
if ($array_includes?($enum_to_a(InterruptCode), code)) {
return true;
} else {
return false;
}
valid_exception_code?
Returns true if code is a legal exception number.
Return Type |
Boolean |
|---|---|
Arguments |
XReg code |
-
Original
-
Pruned
if (code > 1 `<< $enum_element_size(ExceptionCode - 1)) {
return false;
}
if ($array_includes?($enum_to_a(ExceptionCode), code)) {
return true;
} else {
return false;
}
if (code > 6'31) {
return false;
}
if ($array_includes?($enum_to_a(ExceptionCode), code)) {
return true;
} else {
return false;
}
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 |
Bits<64> |
|---|---|
Arguments |
Bits<64> value |
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 |
XReg |
|---|---|
Arguments |
mstatus_sd_has_known_reset
Returns true if the mstatus.SD bit has a defined reset value, as determined by various parameters.
Return Type |
Boolean |
|---|---|
Arguments |
-
Original
-
Pruned
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;
Boolean fs_has_single_value = ($array_size([2'0, 2'1, 2'2, 2'3]) == 1); Boolean vs_has_single_value = ($array_size([2'0, 2'1, 2'2, 2'3]) == 1); return false;
mstatus_sd_reset_value
Returns the reset value of mstatus.SD when known
Return Type |
Bits<1> |
|---|---|
Arguments |
-
Original
-
Pruned
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)) { vs_value = (!implemented?(ExtensionName::V)) ? 0 : MSTATUS_VS_LEGAL_VALUES[0]; } return fs_value == 3) || (vs_value == 3 ? 1 : 0;
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 (($array_size([2'0, 2'1, 2'2, 2'3]) == 1)) { fs_value = 2'0; } if (($array_size([2'0, 2'1, 2'2, 2'3]) == 1)) { vs_value = 2'0; } return fs_value == 3) || (vs_value == 3 ? 1 : 0;
read_mtime (builtin)
Return the current value of the real time device.
Return Type |
Bits<64> |
|---|---|
Arguments |
highest_priority_interrupt
Given a bitmask of interrupts in the format of MIE/MIP, return the highest priority interrupt code that is set
Interrupt priority is: MEI, MSI, MTI, SEI, SSI, STI, SGEI, VSEI, VSSI, VSTI, LCOFI
Return Type |
InterruptCode |
|---|---|
Arguments |
Bits<MXLEN> int_mask |
-
Original
-
Pruned
if (int_mask[$bits(InterruptCode::MachineExternal)] == 1'b1) {
return InterruptCode::MachineExternal;
} else if (int_mask[$bits(InterruptCode::MachineSoftware)] == 1'b1) {
return InterruptCode::MachineSoftware;
} else if (int_mask[$bits(InterruptCode::MachineTimer)] == 1'b1) {
return InterruptCode::MachineTimer;
} else if (CSR[misa].S == 1'b1) {
if (int_mask[$bits(InterruptCode::SupervisorExternal)] == 1'b1) {
return InterruptCode::SupervisorExternal;
} else if (int_mask[$bits(InterruptCode::SupervisorSoftware)] == 1'b1) {
return InterruptCode::SupervisorSoftware;
} else if (int_mask[$bits(InterruptCode::SupervisorTimer)] == 1'b1) {
return InterruptCode::SupervisorTimer;
}
} else if (implemented?(ExtensionName::Sscofpmf)) {
if (int_mask[$bits(InterruptCode::LocalCounterOverflow)] == 1'b1) {
return InterruptCode::LocalCounterOverflow;
}
}
assert(false, "There is no valid interrupt");
unreachable();
if (int_mask[$bits(InterruptCode::MachineExternal)] == 1'b1) {
return InterruptCode::MachineExternal;
} else if (int_mask[$bits(InterruptCode::MachineSoftware)] == 1'b1) {
return InterruptCode::MachineSoftware;
} else if (int_mask[$bits(InterruptCode::MachineTimer)] == 1'b1) {
return InterruptCode::MachineTimer;
} else {
if (int_mask[$bits(InterruptCode::SupervisorExternal)] == 1'b1) {
return InterruptCode::SupervisorExternal;
} else if (int_mask[$bits(InterruptCode::SupervisorSoftware)] == 1'b1) {
return InterruptCode::SupervisorSoftware;
} else if (int_mask[$bits(InterruptCode::SupervisorTimer)] == 1'b1) {
return InterruptCode::SupervisorTimer;
}
}
assert(false, "There is no valid interrupt");
unreachable();
choose_interrupt
Return the highest priority interrupt that is both pending and enabled and the mode it will be taken in
Return Type |
InterruptCode, PrivilegeMode |
|---|---|
Arguments |
-
Original
-
Pruned
InterruptCode chosen; Boolean HAS_MIDELEG = implemented_version?(ExtensionName::S, "<= 1.9.1") || (implemented_version?(ExtensionName::S, "> 1.9.1") && implemented_version?(ExtensionName::Sm, "> 1.9.1")); Bits<MXLEN> mmode_pending_and_enabled = pending_and_enabled_interrupts & ~(HAS_MIDELEG ? $bits(CSR[CSR[mideleg]]) : MXLEN'0); if (mmode_pending_and_enabled != 0) { assert((mode() != PrivilegeMode::M) || (CSR[mstatus].MIE == 1'b1), "M-mode interrupts are not enabled"); chosen = highest_priority_interrupt(mmode_pending_and_enabled); } else if (CSR[misa].S == 1'b1) { Bits<MXLEN> smode_pending_and_enabled = (pending_and_enabled_interrupts & $bits(CSR[CSR[mideleg]])); if (smode_pending_and_enabled != 0) { assert((mode() == PrivilegeMode::U) || (mode() == PrivilegeMode::VU) || (mode() == PrivilegeMode::VS) || (mode() == PrivilegeMode::S) && (CSR[mstatus].SIE == 1'b1), "S-mode interrupt can't be triggered"); chosen = highest_priority_interrupt(smode_pending_and_enabled); } } assert($bits(chosen) != 0, "Didn't pick interrupt?"); PrivilegeMode to_mode; Bits<MXLEN> chosen_mask = (MXLEN'1 << $bits(chosen)); if (((HAS_MIDELEG ? $bits(CSR[CSR[mideleg]]) : MXLEN'0) & chosen_mask) == 0) { to_mode = PrivilegeMode::M; } else { if (CSR[misa].S == 1'b1) { to_mode = PrivilegeMode::S; } else { to_mode = PrivilegeMode::U; } } return chosen, to_mode;
InterruptCode chosen; Boolean HAS_MIDELEG = true; Bits<MXLEN> mmode_pending_and_enabled = pending_and_enabled_interrupts & ~($bits(CSR[CSR[mideleg]])); if (mmode_pending_and_enabled != 0) { assert((mode() != PrivilegeMode::M) || (CSR[mstatus].MIE == 1'b1), "M-mode interrupts are not enabled"); chosen = highest_priority_interrupt(mmode_pending_and_enabled); } else { Bits<MXLEN> smode_pending_and_enabled = (pending_and_enabled_interrupts & $bits(CSR[CSR[mideleg]])); if (smode_pending_and_enabled != 0) { assert((mode() == PrivilegeMode::U) || (mode() == PrivilegeMode::VU) || (mode() == PrivilegeMode::VS) || (mode() == PrivilegeMode::S) && (CSR[mstatus].SIE == 1'b1), "S-mode interrupt can't be triggered"); chosen = highest_priority_interrupt(smode_pending_and_enabled); } } assert($bits(chosen) != 0, "Didn't pick interrupt?"); PrivilegeMode to_mode; Bits<MXLEN> chosen_mask = (MXLEN'1 << $bits(chosen)); if ($bits(CSR[CSR[mideleg]] & chosen_mask) == 0) { to_mode = PrivilegeMode::M; } else { to_mode = PrivilegeMode::S; } return chosen, to_mode;
set_mode_no_refresh
Set the current privilege mode to new_mode, but don’t refresh interrupts
Return Type |
void |
|---|---|
Arguments |
PrivilegeMode new_mode |
-
Original
-
Pruned
if (new_mode != current_mode) {
notify_mode_change(new_mode, current_mode);
current_mode = new_mode;
}
if (new_mode != current_mode) {
notify_mode_change(new_mode, current_mode);
current_mode = new_mode;
}
take_interrupt
Take (adjust CSRs and set PC to handler) the highest priority interrupt that is both pending and enabled
Return Type |
void |
|---|---|
Arguments |
-
Original
-
Pruned
PrivilegeMode to_mode; InterruptCode code; (code, to_mode = choose_interrupt()); if (to_mode == PrivilegeMode::M) { CSR[mepc].PC = $pc; CSR[mstatus].MPP = $bits(mode())[1:0]; if (CSR[misa].H == 1'b1) { if (MXLEN == 64) { CSR[mstatus].MPV = $bits(mode())[2]; } else { CSR[mstatush].MPV = $bits(mode())[2]; } CSR[mtval2].VALUE = 0; CSR[mtinst].VALUE = 0; } CSR[mcause].CODE = $bits(code); CSR[mcause].INT = 1'b1; CSR[mtval].VALUE = 0; if (CSR[mtvec].MODE == 0) { $pc = {CSR[mtvec].BASE, 2'b00}; } else if (CSR[mtvec].MODE == 1'b1) { $pc = {CSR[mtvec].BASE, 2'b00} + ($bits(code) * 4); } } else if ((CSR[misa].S == 1'b1) && (to_mode == PrivilegeMode::S)) { CSR[sepc].PC = $pc; CSR[mstatus].SPP = $bits(mode())[0]; if (CSR[misa].H == 1'b1) { CSR[hstatus].SPV = $bits(mode())[2]; } CSR[scause].CODE = $bits(code); CSR[scause].INT = 1'b1; CSR[stval].VALUE = 0; if (CSR[stvec].MODE == 0) { $pc = {CSR[stvec].BASE, 2'b00}; } else if (CSR[stvec].MODE == 1'b1) { $pc = {CSR[stvec].BASE, 2'b00} + ($bits(code) * 4); } } else if ((CSR[misa].H == 1'b1) && (to_mode == PrivilegeMode::VS)) { CSR[vsepc].PC = $pc; CSR[vsstatus].SPP = $bits(mode())[0]; CSR[vscause].CODE = $bits(code); CSR[vscause].INT = 1'b1; CSR[vstval].VALUE = 0; if (CSR[vstvec].MODE == 0) { $pc = {CSR[vstvec].BASE, 2'b00}; } else if (CSR[vstvec].MODE == 1'b1) { $pc = {CSR[vstvec].BASE, 2'b00} + ($bits(code) * 4); } } set_mode_no_refresh(to_mode);
PrivilegeMode to_mode; InterruptCode code; (code, to_mode = choose_interrupt()); if (to_mode == PrivilegeMode::M) { CSR[mepc].PC = $pc; CSR[mstatus].MPP = $bits(mode())[1:0]; CSR[mstatus].MPV = $bits(mode())[2]; CSR[mtval2].VALUE = 0; CSR[mtinst].VALUE = 0; CSR[mcause].CODE = $bits(code); CSR[mcause].INT = 1'b1; CSR[mtval].VALUE = 0; if (CSR[mtvec].MODE == 0) { $pc = {CSR[mtvec].BASE, 2'b00}; } else if (CSR[mtvec].MODE == 1'b1) { $pc = {CSR[mtvec].BASE, 2'b00} + ($bits(code) * 4); } } else if ((to_mode == PrivilegeMode::S)) { CSR[sepc].PC = $pc; CSR[mstatus].SPP = $bits(mode())[0]; CSR[hstatus].SPV = $bits(mode())[2]; CSR[scause].CODE = $bits(code); CSR[scause].INT = 1'b1; CSR[stval].VALUE = 0; if (CSR[stvec].MODE == 0) { $pc = {CSR[stvec].BASE, 2'b00}; } else if (CSR[stvec].MODE == 1'b1) { $pc = {CSR[stvec].BASE, 2'b00} + ($bits(code) * 4); } } else if ((to_mode == PrivilegeMode::VS)) { CSR[vsepc].PC = $pc; CSR[vsstatus].SPP = $bits(mode())[0]; CSR[vscause].CODE = $bits(code); CSR[vscause].INT = 1'b1; CSR[vstval].VALUE = 0; if (CSR[vstvec].MODE == 0) { $pc = {CSR[vstvec].BASE, 2'b00}; } else if (CSR[vstvec].MODE == 1'b1) { $pc = {CSR[vstvec].BASE, 2'b00} + ($bits(code) * 4); } } set_mode_no_refresh(to_mode);
fetch_memory_aligned_16
Fetch 16 bits from virtual memory using a known aligned address.
Return Type |
Bits<16> |
|---|---|
Arguments |
XReg virtual_address |
-
Original
-
Pruned
TranslationResult result; if (CSR[misa].S == 1) { result = translate(virtual_address, MemoryOperation::Fetch, mode(), virtual_address); } else { result.paddr = virtual_address; } access_check(result.paddr, 16, virtual_address, MemoryOperation::Fetch, ExceptionCode::InstructionAccessFault, mode()); return read_physical_memory(16, result.paddr);
TranslationResult result; result = translate(virtual_address, MemoryOperation::Fetch, mode(), virtual_address); access_check(result.paddr, 16, virtual_address, MemoryOperation::Fetch, ExceptionCode::InstructionAccessFault, mode()); return read_physical_memory(16, result.paddr);
set_external_interrupt
Set an external interrupt targeting target_mode
Return Type |
void |
|---|---|
Arguments |
PrivilegeMode target_mode |
-
Original
-
Pruned
if (target_mode == PrivilegeMode::M) {
CSR[mip].MEIP = 1'b1;
} else if ((CSR[misa].S == 1'b1) && (target_mode == PrivilegeMode::S)) {
pending_smode_external_interrupt = true;
} else if ((CSR[misa].H == 1'b1) && (target_mode == PrivilegeMode::VS)) {
CSR[mip].VSEIP = 1'b1;
} else {
assert(false, "Invalid target_mode");
}
refresh_pending_interrupts();
if (target_mode == PrivilegeMode::M) {
CSR[mip].MEIP = 1'b1;
} else if ((target_mode == PrivilegeMode::S)) {
pending_smode_external_interrupt = true;
} else if ((target_mode == PrivilegeMode::VS)) {
CSR[mip].VSEIP = 1'b1;
} else {
assert(false, "Invalid target_mode");
}
refresh_pending_interrupts();
clear_external_interrupt
Clear an external interrupt targeting target_mode
Return Type |
void |
|---|---|
Arguments |
PrivilegeMode target_mode |
-
Original
-
Pruned
if (target_mode == PrivilegeMode::M) {
CSR[mip].MEIP = 1'b0;
} else if ((CSR[misa].S == 1'b1) && (target_mode == PrivilegeMode::S)) {
pending_smode_external_interrupt = false;
} else if ((CSR[misa].H == 1'b1) && (target_mode == PrivilegeMode::VS)) {
CSR[mip].VSEIP = 1'b0;
} else {
assert(false, "Invalid target_mode");
}
refresh_pending_interrupts();
if (target_mode == PrivilegeMode::M) {
CSR[mip].MEIP = 1'b0;
} else if ((target_mode == PrivilegeMode::S)) {
pending_smode_external_interrupt = false;
} else if ((target_mode == PrivilegeMode::VS)) {
CSR[mip].VSEIP = 1'b0;
} else {
assert(false, "Invalid target_mode");
}
refresh_pending_interrupts();
set_software_interrupt
Set a software interrupt targeting target_mode
Return Type |
void |
|---|---|
Arguments |
PrivilegeMode target_mode |
-
Original
-
Pruned
clear_software_interrupt
Clear a software interrupt targeting target_mode
Return Type |
void |
|---|---|
Arguments |
PrivilegeMode target_mode |
-
Original
-
Pruned
set_timer_interrupt
Set a timer interrupt from the platform targeting target_mode
Return Type |
void |
|---|---|
Arguments |
PrivilegeMode target_mode |
-
Original
-
Pruned
if (target_mode == PrivilegeMode::M) {
CSR[mip].MTIP = 1'b1;
} else if ((CSR[misa].S == 1'b1) && (target_mode == PrivilegeMode::S)) {
CSR[mip].STIP = 1'b1;
} else if ((CSR[misa].H == 1'b1) && (target_mode == PrivilegeMode::VS)) {
pending_vsmode_timer_interrupt = true;
} else {
assert(false, "Invalid target_mode");
}
refresh_pending_interrupts();
clear_timer_interrupt
Set a timer interrupt from the platform targeting target_mode
Return Type |
void |
|---|---|
Arguments |
PrivilegeMode target_mode |
-
Original
-
Pruned
if (target_mode == PrivilegeMode::M) {
CSR[mip].MTIP = 1'b0;
} else if ((CSR[misa].S == 1'b1) && (target_mode == PrivilegeMode::S)) {
CSR[mip].STIP = 1'b0;
} else if ((CSR[misa].H == 1'b1) && (target_mode == PrivilegeMode::VS)) {
pending_vsmode_timer_interrupt = false;
} else {
assert(false, "Invalid target_mode");
}
refresh_pending_interrupts();