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 (!%%LINK%func;implemented?;implemented?%%(ExtensionName::S) && !%%LINK%func;implemented?;implemented?%%(ExtensionName::U) && !%%LINK%func;implemented?;implemented?%%(ExtensionName::H)) {
  return PrivilegeMode::M;
} else {
  return current_mode;
}
return current_mode;

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

assert (builtin)

Assert that a condition is true. Failure represents an error in the IDL model.

Return Type

 void

Arguments

 Boolean test, String message

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 (%%LINK%func;mode;mode%%() == PrivilegeMode::M) {
  return PrivilegeMode::M;
} else if (%%LINK%func;implemented?;implemented?%%(ExtensionName::S) && %%LINK%func;mode;mode%%() == PrivilegeMode::HS) || (%%LINK%func;mode;mode%%() == PrivilegeMode::U) {
  if (($bits(CSR[medeleg]) & (1 << $bits(exception_code))) != 0) {
    return PrivilegeMode::HS;
  } else {
    return PrivilegeMode::M;
  }
} else {
  %%LINK%func;assert;assert%%(%%LINK%func;implemented?;implemented?%%(ExtensionName::H) && %%LINK%func;mode;mode%%() == PrivilegeMode::VS) || (%%LINK%func;mode;mode%%() == PrivilegeMode::VU, "Unexpected mode");
  if (($bits(CSR[medeleg]) & (1 << $bits(exception_code))) != 0) {
    if (($bits(CSR[hedeleg]) & (1 << $bits(exception_code))) != 0) {
      return PrivilegeMode::VS;
    } else {
      return PrivilegeMode::HS;
    }
  } else {
    return PrivilegeMode::M;
  }
}
if (%%LINK%func;mode;mode%%() == PrivilegeMode::M) {
  return PrivilegeMode::M;
} else if (%%LINK%func;mode;mode%%() == PrivilegeMode::HS) || (%%LINK%func;mode;mode%%() == PrivilegeMode::U) {
  if (($bits(CSR[medeleg]) & (1 << $bits(exception_code))) != 0) {
    return PrivilegeMode::HS;
  } else {
    return PrivilegeMode::M;
  }
} else {
  %%LINK%func;assert;assert%%(%%LINK%func;mode;mode%%() == PrivilegeMode::VS) || (%%LINK%func;mode;mode%%() == PrivilegeMode::VU, "Unexpected mode");
  if (($bits(CSR[medeleg]) & (1 << $bits(exception_code))) != 0) {
    if (($bits(CSR[hedeleg]) & (1 << $bits(exception_code))) != 0) {
      return PrivilegeMode::VS;
    } else {
      return PrivilegeMode::HS;
    }
  } else {
    return PrivilegeMode::M;
  }
}

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 !(true);

mtval_for

Given an exception code and a legal non-zero value for mtval, returns the value to be written in mtval considering implementation options

Return Type

 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 (%%LINK%func;implemented?;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 !(true);

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 (%%LINK%func;implemented?;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 !(true);

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[mip].sw_read() & $bits(CSR[mie]);
if (pending_ints == 0) {
  pending_and_enabled_interrupts = 0;
  return ;
}
Boolean HAS_MIDELEG = %%LINK%func;implemented_version?;implemented_version?%%(ExtensionName::S, "<= 1.9.1") || (%%LINK%func;implemented_version?;implemented_version?%%(ExtensionName::S, "> 1.9.1") && %%LINK%func;implemented_version?;implemented_version?%%(ExtensionName::Sm, "> 1.9.1"));
Bits<MXLEN> mmode_enabled_ints = %%LINK%func;mode;mode%%() == PrivilegeMode::M) && (%%LINK%csr_field;mstatus.MIE;CSR[mstatus].MIE%% == 1'b0 ? 0 : ($bits(CSR[mie]) & (HAS_MIDELEG ? ~$bits(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 (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1'b1) {
  Bits<MXLEN> smode_enabled_ints = %%LINK%func;mode;mode%%() == PrivilegeMode::M) || (%%LINK%csr_field;mstatus.SIE;CSR[mstatus].SIE%% == 1'b0 ? 0 : $bits(CSR[mie]) & ($bits(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[mip].sw_read() & $bits(CSR[mie]);
if (pending_ints == 0) {
  pending_and_enabled_interrupts = 0;
  return ;
}
Boolean HAS_MIDELEG = true;
Bits<MXLEN> mmode_enabled_ints = %%LINK%func;mode;mode%%() == PrivilegeMode::M) && (%%LINK%csr_field;mstatus.MIE;CSR[mstatus].MIE%% == 1'b0 ? 0 : ($bits(CSR[mie]) & (~$bits(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 ;
}
if (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1'b1) {
  Bits<MXLEN> smode_enabled_ints = %%LINK%func;mode;mode%%() == PrivilegeMode::M) || (%%LINK%csr_field;mstatus.SIE;CSR[mstatus].SIE%% == 1'b0 ? 0 : $bits(CSR[mie]) & ($bits(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) {
  %%LINK%func;notify_mode_change;notify_mode_change%%(new_mode, current_mode);
  current_mode = new_mode;
  %%LINK%func;refresh_pending_interrupts;refresh_pending_interrupts%%();
}
if (new_mode != current_mode) {
  %%LINK%func;notify_mode_change;notify_mode_change%%(new_mode, current_mode);
  current_mode = new_mode;
  %%LINK%func;refresh_pending_interrupts;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 = %%LINK%func;exception_handling_mode;exception_handling_mode%%(exception_code);
if (handling_mode == PrivilegeMode::M) {
  %%LINK%csr_field;mepc.PC;CSR[mepc].PC%% = $pc;
  if (!%%LINK%func;mtval_readonly?;mtval_readonly?%%()) {
    %%LINK%csr_field;mtval.VALUE;CSR[mtval].VALUE%% = %%LINK%func;mtval_for;mtval_for%%(exception_code, tval);
  }
  $pc = {%%LINK%csr_field;mtvec.BASE;CSR[mtvec].BASE%%, 2'b00};
  %%LINK%csr_field;mcause.INT;CSR[mcause].INT%% = 1'b0;
  %%LINK%csr_field;mcause.CODE;CSR[mcause].CODE%% = $bits(exception_code);
  if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1) {
    %%LINK%csr_field;mtval2.VALUE;CSR[mtval2].VALUE%% = 0;
    %%LINK%csr_field;mtinst.VALUE;CSR[mtinst].VALUE%% = 0;
    if (from_mode == PrivilegeMode::VU || from_mode == PrivilegeMode::VS) {
      if (MXLEN == 32) {
        %%LINK%csr_field;mstatush.MPV;CSR[mstatush].MPV%% = 1;
      } else {
        %%LINK%csr_field;mstatus.MPV;CSR[mstatus].MPV%% = 1;
      }
    } else {
      if (MXLEN == 32) {
        %%LINK%csr_field;mstatush.MPV;CSR[mstatush].MPV%% = 0;
      } else {
        %%LINK%csr_field;mstatus.MPV;CSR[mstatus].MPV%% = 0;
      }
    }
  }
  %%LINK%csr_field;mstatus.MPP;CSR[mstatus].MPP%% = $bits(from_mode);
} else if (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1 && (handling_mode == PrivilegeMode::S)) {
  %%LINK%csr_field;sepc.PC;CSR[sepc].PC%% = $pc;
  if (!%%LINK%func;stval_readonly?;stval_readonly?%%()) {
    %%LINK%csr_field;stval.VALUE;CSR[stval].VALUE%% = %%LINK%func;stval_for;stval_for%%(exception_code, tval);
  }
  $pc = {%%LINK%csr_field;stvec.BASE;CSR[stvec].BASE%%, 2'b00};
  %%LINK%csr_field;scause.INT;CSR[scause].INT%% = 1'b0;
  %%LINK%csr_field;scause.CODE;CSR[scause].CODE%% = $bits(exception_code);
  %%LINK%csr_field;mstatus.SPP;CSR[mstatus].SPP%% = $bits(from_mode)[0];
  if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1) {
    %%LINK%csr_field;htval.VALUE;CSR[htval].VALUE%% = 0;
    %%LINK%csr_field;htinst.VALUE;CSR[htinst].VALUE%% = 0;
    %%LINK%csr_field;hstatus.SPV;CSR[hstatus].SPV%% = $bits(from_mode)[2];
    if (from_mode == PrivilegeMode::VU || from_mode == PrivilegeMode::VS) {
      %%LINK%csr_field;hstatus.SPV;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) {
        %%LINK%csr_field;hstatus.GVA;CSR[hstatus].GVA%% = 1;
      } else {
        %%LINK%csr_field;hstatus.GVA;CSR[hstatus].GVA%% = 0;
      }
      %%LINK%csr_field;hstatus.SPVP;CSR[hstatus].SPVP%% = $bits(from_mode)[0];
    } else {
      %%LINK%csr_field;hstatus.SPV;CSR[hstatus].SPV%% = 0;
      %%LINK%csr_field;hstatus.GVA;CSR[hstatus].GVA%% = 0;
    }
  }
} else if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1 && (handling_mode == PrivilegeMode::VS)) {
  %%LINK%csr_field;vsepc.PC;CSR[vsepc].PC%% = $pc;
  if (!%%LINK%func;vstval_readonly?;vstval_readonly?%%()) {
    %%LINK%csr_field;vstval.VALUE;CSR[vstval].VALUE%% = %%LINK%func;vstval_for;vstval_for%%(exception_code, tval);
  }
  $pc = {%%LINK%csr_field;vstvec.BASE;CSR[vstvec].BASE%%, 2'b00};
  %%LINK%csr_field;vscause.INT;CSR[vscause].INT%% = 1'b0;
  %%LINK%csr_field;vscause.CODE;CSR[vscause].CODE%% = $bits(exception_code);
  %%LINK%csr_field;vsstatus.SPP;CSR[vsstatus].SPP%% = $bits(from_mode)[0];
}
%%LINK%func;set_mode;set_mode%%(handling_mode);
%%LINK%func;abort_current_instruction;abort_current_instruction%%();
PrivilegeMode handling_mode = %%LINK%func;exception_handling_mode;exception_handling_mode%%(exception_code);
if (handling_mode == PrivilegeMode::M) {
  %%LINK%csr_field;mepc.PC;CSR[mepc].PC%% = $pc;
  %%LINK%csr_field;mtval.VALUE;CSR[mtval].VALUE%% = %%LINK%func;mtval_for;mtval_for%%(exception_code, tval);
  $pc = {%%LINK%csr_field;mtvec.BASE;CSR[mtvec].BASE%%, 2'b00};
  %%LINK%csr_field;mcause.INT;CSR[mcause].INT%% = 1'b0;
  %%LINK%csr_field;mcause.CODE;CSR[mcause].CODE%% = $bits(exception_code);
  if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1) {
    %%LINK%csr_field;mtval2.VALUE;CSR[mtval2].VALUE%% = 0;
    %%LINK%csr_field;mtinst.VALUE;CSR[mtinst].VALUE%% = 0;
    if (from_mode == PrivilegeMode::VU || from_mode == PrivilegeMode::VS) {
      %%LINK%csr_field;mstatus.MPV;CSR[mstatus].MPV%% = 1;
    } else {
      %%LINK%csr_field;mstatus.MPV;CSR[mstatus].MPV%% = 0;
    }
  }
  %%LINK%csr_field;mstatus.MPP;CSR[mstatus].MPP%% = $bits(from_mode);
} else if (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1 && (handling_mode == PrivilegeMode::S)) {
  %%LINK%csr_field;sepc.PC;CSR[sepc].PC%% = $pc;
  %%LINK%csr_field;stval.VALUE;CSR[stval].VALUE%% = %%LINK%func;stval_for;stval_for%%(exception_code, tval);
  $pc = {%%LINK%csr_field;stvec.BASE;CSR[stvec].BASE%%, 2'b00};
  %%LINK%csr_field;scause.INT;CSR[scause].INT%% = 1'b0;
  %%LINK%csr_field;scause.CODE;CSR[scause].CODE%% = $bits(exception_code);
  %%LINK%csr_field;mstatus.SPP;CSR[mstatus].SPP%% = $bits(from_mode)[0];
  if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1) {
    %%LINK%csr_field;htval.VALUE;CSR[htval].VALUE%% = 0;
    %%LINK%csr_field;htinst.VALUE;CSR[htinst].VALUE%% = 0;
    %%LINK%csr_field;hstatus.SPV;CSR[hstatus].SPV%% = $bits(from_mode)[2];
    if (from_mode == PrivilegeMode::VU || from_mode == PrivilegeMode::VS) {
      %%LINK%csr_field;hstatus.SPV;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) {
        %%LINK%csr_field;hstatus.GVA;CSR[hstatus].GVA%% = 1;
      } else {
        %%LINK%csr_field;hstatus.GVA;CSR[hstatus].GVA%% = 0;
      }
      %%LINK%csr_field;hstatus.SPVP;CSR[hstatus].SPVP%% = $bits(from_mode)[0];
    } else {
      %%LINK%csr_field;hstatus.SPV;CSR[hstatus].SPV%% = 0;
      %%LINK%csr_field;hstatus.GVA;CSR[hstatus].GVA%% = 0;
    }
  }
} else if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1 && (handling_mode == PrivilegeMode::VS)) {
  %%LINK%csr_field;vsepc.PC;CSR[vsepc].PC%% = $pc;
  %%LINK%csr_field;vstval.VALUE;CSR[vstval].VALUE%% = %%LINK%func;vstval_for;vstval_for%%(exception_code, tval);
  $pc = {%%LINK%csr_field;vstvec.BASE;CSR[vstvec].BASE%%, 2'b00};
  %%LINK%csr_field;vscause.INT;CSR[vscause].INT%% = 1'b0;
  %%LINK%csr_field;vscause.CODE;CSR[vscause].CODE%% = $bits(exception_code);
  %%LINK%csr_field;vsstatus.SPP;CSR[vsstatus].SPP%% = $bits(from_mode)[0];
}
%%LINK%func;set_mode;set_mode%%(handling_mode);
%%LINK%func;abort_current_instruction;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) {
  %%LINK%func;unpredictable;unpredictable%%("Imprecise synchronous exception");
} else {
  %%LINK%func;raise_precise;raise_precise%%(exception_code, from_mode, tval);
}
if (!PRECISE_SYNCHRONOUS_EXCEPTIONS) {
  %%LINK%func;unpredictable;unpredictable%%("Imprecise synchronous exception");
} else {
  %%LINK%func;raise_precise;raise_precise%%(exception_code, from_mode, tval);
}

is_naturally_aligned

Checks if value is naturally aligned to N bits.

Return Type

 Boolean

Arguments

 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 (%%LINK%func;implemented?;implemented?%%(ExtensionName::H)) {
  return (MXLEN == 32) ? %%LINK%csr_field;mstatush.MPV;CSR[mstatush].MPV%% : %%LINK%csr_field;mstatus.MPV;CSR[mstatus].MPV%%;
} else {
  %%LINK%func;assert;assert%%(false, "TODO");
}
return %%LINK%csr_field;mstatus.MPV;CSR[mstatus].MPV%%;

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 (%%LINK%func;mode;mode%%() == PrivilegeMode::M) {
  if (%%LINK%csr_field;misa.U;CSR[misa].U%% == 1 && %%LINK%csr_field;mstatus.MPRV;CSR[mstatus].MPRV%% == 1) {
    if (%%LINK%csr_field;mstatus.MPP;CSR[mstatus].MPP%% == 0b00) {
      if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1 && %%LINK%func;mpv;mpv%%() == 0b1) {
        return PrivilegeMode::VU;
      } else {
        return PrivilegeMode::U;
      }
    } else if (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1 && %%LINK%csr_field;mstatus.MPP;CSR[mstatus].MPP%% == 0b01) {
      if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1 && %%LINK%func;mpv;mpv%%() == 0b1) {
        return PrivilegeMode::VS;
      } else {
        return PrivilegeMode::S;
      }
    }
  }
}
return %%LINK%func;mode;mode%%();
if (%%LINK%func;mode;mode%%() == PrivilegeMode::M) {
  if (%%LINK%csr_field;misa.U;CSR[misa].U%% == 1 && %%LINK%csr_field;mstatus.MPRV;CSR[mstatus].MPRV%% == 1) {
    if (%%LINK%csr_field;mstatus.MPP;CSR[mstatus].MPP%% == 0b00) {
      if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1 && %%LINK%func;mpv;mpv%%() == 0b1) {
        return PrivilegeMode::VU;
      } else {
        return PrivilegeMode::U;
      }
    } else if (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1 && %%LINK%csr_field;mstatus.MPP;CSR[mstatus].MPP%% == 0b01) {
      if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1 && %%LINK%func;mpv;mpv%%() == 0b1) {
        return PrivilegeMode::VS;
      } else {
        return PrivilegeMode::S;
      }
    }
  }
}
return %%LINK%func;mode;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).

Returns SatpMode::Reserved if the setting found in satp or vsatp is invalid.

Return Type

 SatpMode

Arguments

 PrivilegeMode mode
  • Original

  • Pruned

PrivilegeMode effective_mode = %%LINK%func;effective_ldst_mode;effective_ldst_mode%%();
if (effective_mode == PrivilegeMode::M) {
  return SatpMode::Bare;
}
if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1'b1) {
  if (effective_mode == PrivilegeMode::VS || effective_mode == PrivilegeMode::VU) {
    Bits<4> mode_val = %%LINK%csr_field;vsatp.MODE;CSR[vsatp].MODE%%;
    if (mode_val == $bits(SatpMode::Sv32)) {
      if (MXLEN == 64) {
        if ((effective_mode == PrivilegeMode::VS) && (%%LINK%csr_field;hstatus.VSXL;CSR[hstatus].VSXL%% != $bits(XRegWidth::XLEN32))) {
          return SatpMode::Reserved;
        }
        if ((effective_mode == PrivilegeMode::VU) && (%%LINK%csr_field;vsstatus.UXL;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 && %%LINK%csr_field;hstatus.VSXL;CSR[hstatus].VSXL%% != $bits(XRegWidth::XLEN64)) {
        return SatpMode::Reserved;
      }
      if (effective_mode == PrivilegeMode::VU && %%LINK%csr_field;vsstatus.UXL;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 && %%LINK%csr_field;hstatus.VSXL;CSR[hstatus].VSXL%% != $bits(XRegWidth::XLEN64)) {
        return SatpMode::Reserved;
      }
      if (effective_mode == PrivilegeMode::VU && %%LINK%csr_field;vsstatus.UXL;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 && %%LINK%csr_field;hstatus.VSXL;CSR[hstatus].VSXL%% != $bits(XRegWidth::XLEN64)) {
        return SatpMode::Reserved;
      }
      if (effective_mode == PrivilegeMode::VU && %%LINK%csr_field;vsstatus.UXL;CSR[vsstatus].UXL%% != $bits(XRegWidth::XLEN64)) {
        return SatpMode::Reserved;
      }
      if (!SV57_VSMODE_TRANSLATION) {
        return SatpMode::Reserved;
      }
      return SatpMode::Sv57;
    } else {
      return SatpMode::Reserved;
    }
  }
} else if (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1'b1) {
  %%LINK%func;assert;assert%%(effective_mode == PrivilegeMode::S || effective_mode == PrivilegeMode::U, "unexpected priv mode");
  Bits<4> mode_val = %%LINK%csr_field;satp.MODE;CSR[satp].MODE%%;
  if (mode_val == $bits(SatpMode::Sv32)) {
    if (MXLEN == 64) {
      if (effective_mode == PrivilegeMode::S && %%LINK%csr_field;mstatus.SXL;CSR[mstatus].SXL%% != $bits(XRegWidth::XLEN32)) {
        return SatpMode::Reserved;
      }
      if (effective_mode == PrivilegeMode::U && %%LINK%csr_field;sstatus.UXL;CSR[sstatus].UXL%% != $bits(XRegWidth::XLEN32)) {
        return SatpMode::Reserved;
      }
    }
    if (!%%LINK%func;implemented?;implemented?%%(ExtensionName::Sv32)) {
      return SatpMode::Reserved;
    }
  } else if ((MXLEN == 64) && (mode_val == $bits(SatpMode::Sv39))) {
    if (effective_mode == PrivilegeMode::S && %%LINK%csr_field;mstatus.SXL;CSR[mstatus].SXL%% != $bits(XRegWidth::XLEN64)) {
      return SatpMode::Reserved;
    }
    if (effective_mode == PrivilegeMode::U && %%LINK%csr_field;sstatus.UXL;CSR[sstatus].UXL%% != $bits(XRegWidth::XLEN64)) {
      return SatpMode::Reserved;
    }
    if (!%%LINK%func;implemented?;implemented?%%(ExtensionName::Sv39)) {
      return SatpMode::Reserved;
    }
    return SatpMode::Sv39;
  } else if ((MXLEN == 64) && (mode_val == $bits(SatpMode::Sv48))) {
    if (effective_mode == PrivilegeMode::S && %%LINK%csr_field;mstatus.SXL;CSR[mstatus].SXL%% != $bits(XRegWidth::XLEN64)) {
      return SatpMode::Reserved;
    }
    if (effective_mode == PrivilegeMode::U && %%LINK%csr_field;sstatus.UXL;CSR[sstatus].UXL%% != $bits(XRegWidth::XLEN64)) {
      return SatpMode::Reserved;
    }
    if (!%%LINK%func;implemented?;implemented?%%(ExtensionName::Sv48)) {
      return SatpMode::Reserved;
    }
    return SatpMode::Sv48;
  } else if ((MXLEN == 64) && (mode_val == $bits(SatpMode::Sv57))) {
    if (effective_mode == PrivilegeMode::S && %%LINK%csr_field;mstatus.SXL;CSR[mstatus].SXL%% != $bits(XRegWidth::XLEN64)) {
      return SatpMode::Reserved;
    }
    if (effective_mode == PrivilegeMode::U && %%LINK%csr_field;sstatus.UXL;CSR[sstatus].UXL%% != $bits(XRegWidth::XLEN64)) {
      return SatpMode::Reserved;
    }
    if (!%%LINK%func;implemented?;implemented?%%(ExtensionName::Sv57)) {
      return SatpMode::Reserved;
    }
    return SatpMode::Sv57;
  } else {
    return SatpMode::Reserved;
  }
}
PrivilegeMode effective_mode = %%LINK%func;effective_ldst_mode;effective_ldst_mode%%();
if (effective_mode == PrivilegeMode::M) {
  return SatpMode::Bare;
}
if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1'b1) {
  if (effective_mode == PrivilegeMode::VS || effective_mode == PrivilegeMode::VU) {
    Bits<4> mode_val = %%LINK%csr_field;vsatp.MODE;CSR[vsatp].MODE%%;
    if (mode_val == $bits(SatpMode::Sv32)) {
      if ((effective_mode == PrivilegeMode::VS) && (%%LINK%csr_field;hstatus.VSXL;CSR[hstatus].VSXL%% != $bits(XRegWidth::XLEN32))) {
        return SatpMode::Reserved;
      }
      if ((effective_mode == PrivilegeMode::VU) && (%%LINK%csr_field;vsstatus.UXL;CSR[vsstatus].UXL%% != $bits(XRegWidth::XLEN32))) {
        return SatpMode::Reserved;
      }
      return SatpMode::Reserved;
      return SatpMode::Sv32;
    } else if ((mode_val == $bits(SatpMode::Sv39))) {
      if (effective_mode == PrivilegeMode::VS && %%LINK%csr_field;hstatus.VSXL;CSR[hstatus].VSXL%% != $bits(XRegWidth::XLEN64)) {
        return SatpMode::Reserved;
      }
      if (effective_mode == PrivilegeMode::VU && %%LINK%csr_field;vsstatus.UXL;CSR[vsstatus].UXL%% != $bits(XRegWidth::XLEN64)) {
        return SatpMode::Reserved;
      }

      return SatpMode::Sv39;
    } else if ((mode_val == $bits(SatpMode::Sv48))) {
      if (effective_mode == PrivilegeMode::VS && %%LINK%csr_field;hstatus.VSXL;CSR[hstatus].VSXL%% != $bits(XRegWidth::XLEN64)) {
        return SatpMode::Reserved;
      }
      if (effective_mode == PrivilegeMode::VU && %%LINK%csr_field;vsstatus.UXL;CSR[vsstatus].UXL%% != $bits(XRegWidth::XLEN64)) {
        return SatpMode::Reserved;
      }

      return SatpMode::Sv48;
    } else if ((mode_val == $bits(SatpMode::Sv57))) {
      if (effective_mode == PrivilegeMode::VS && %%LINK%csr_field;hstatus.VSXL;CSR[hstatus].VSXL%% != $bits(XRegWidth::XLEN64)) {
        return SatpMode::Reserved;
      }
      if (effective_mode == PrivilegeMode::VU && %%LINK%csr_field;vsstatus.UXL;CSR[vsstatus].UXL%% != $bits(XRegWidth::XLEN64)) {
        return SatpMode::Reserved;
      }

      return SatpMode::Sv57;
    } else {
      return SatpMode::Reserved;
    }
  }
} else if (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1'b1) {
  %%LINK%func;assert;assert%%(effective_mode == PrivilegeMode::S || effective_mode == PrivilegeMode::U, "unexpected priv mode");
  Bits<4> mode_val = %%LINK%csr_field;satp.MODE;CSR[satp].MODE%%;
  if (mode_val == $bits(SatpMode::Sv32)) {
    if (effective_mode == PrivilegeMode::S && %%LINK%csr_field;mstatus.SXL;CSR[mstatus].SXL%% != $bits(XRegWidth::XLEN32)) {
      return SatpMode::Reserved;
    }
    if (effective_mode == PrivilegeMode::U && %%LINK%csr_field;sstatus.UXL;CSR[sstatus].UXL%% != $bits(XRegWidth::XLEN32)) {
      return SatpMode::Reserved;
    }
    return SatpMode::Reserved;
  } else if ((mode_val == $bits(SatpMode::Sv39))) {
    if (effective_mode == PrivilegeMode::S && %%LINK%csr_field;mstatus.SXL;CSR[mstatus].SXL%% != $bits(XRegWidth::XLEN64)) {
      return SatpMode::Reserved;
    }
    if (effective_mode == PrivilegeMode::U && %%LINK%csr_field;sstatus.UXL;CSR[sstatus].UXL%% != $bits(XRegWidth::XLEN64)) {
      return SatpMode::Reserved;
    }

    return SatpMode::Sv39;
  } else if ((mode_val == $bits(SatpMode::Sv48))) {
    if (effective_mode == PrivilegeMode::S && %%LINK%csr_field;mstatus.SXL;CSR[mstatus].SXL%% != $bits(XRegWidth::XLEN64)) {
      return SatpMode::Reserved;
    }
    if (effective_mode == PrivilegeMode::U && %%LINK%csr_field;sstatus.UXL;CSR[sstatus].UXL%% != $bits(XRegWidth::XLEN64)) {
      return SatpMode::Reserved;
    }

    return SatpMode::Sv48;
  } else if ((mode_val == $bits(SatpMode::Sv57))) {
    if (effective_mode == PrivilegeMode::S && %%LINK%csr_field;mstatus.SXL;CSR[mstatus].SXL%% != $bits(XRegWidth::XLEN64)) {
      return SatpMode::Reserved;
    }
    if (effective_mode == PrivilegeMode::U && %%LINK%csr_field;sstatus.UXL;CSR[sstatus].UXL%% != $bits(XRegWidth::XLEN64)) {
      return SatpMode::Reserved;
    }
    return SatpMode::Reserved;
    return SatpMode::Sv57;
  } else {
    return SatpMode::Reserved;
  }
}

xlen

Returns the effective XLEN for the current privilege mode.

Return Type

 Bits<8>

Arguments

  • Original

  • Pruned

if (MXLEN == 32) {
  return 32;
} else {
  if (%%LINK%func;mode;mode%%() == PrivilegeMode::M) {
    if (%%LINK%csr_field;misa.MXL;CSR[misa].MXL%% == $bits(XRegWidth::XLEN32)) {
      return 32;
    } else if (%%LINK%csr_field;misa.MXL;CSR[misa].MXL%% == $bits(XRegWidth::XLEN64)) {
      return 64;
    }
  } else if (%%LINK%func;implemented?;implemented?%%(ExtensionName::S) && %%LINK%func;mode;mode%%() == PrivilegeMode::S) {
    if (%%LINK%csr_field;mstatus.SXL;CSR[mstatus].SXL%% == $bits(XRegWidth::XLEN32)) {
      return 32;
    } else if (%%LINK%csr_field;mstatus.SXL;CSR[mstatus].SXL%% == $bits(XRegWidth::XLEN64)) {
      return 64;
    }
  } else if (%%LINK%func;implemented?;implemented?%%(ExtensionName::U) && %%LINK%func;mode;mode%%() == PrivilegeMode::U) {
    if (%%LINK%csr_field;mstatus.UXL;CSR[mstatus].UXL%% == $bits(XRegWidth::XLEN32)) {
      return 32;
    } else if (%%LINK%csr_field;mstatus.UXL;CSR[mstatus].UXL%% == $bits(XRegWidth::XLEN64)) {
      return 64;
    }
  } else if (%%LINK%func;implemented?;implemented?%%(ExtensionName::H) && %%LINK%func;mode;mode%%() == PrivilegeMode::VS) {
    if (%%LINK%csr_field;hstatus.VSXL;CSR[hstatus].VSXL%% == $bits(XRegWidth::XLEN32)) {
      return 32;
    } else if (%%LINK%csr_field;hstatus.VSXL;CSR[hstatus].VSXL%% == $bits(XRegWidth::XLEN64)) {
      return 64;
    }
  } else if (%%LINK%func;implemented?;implemented?%%(ExtensionName::H) && %%LINK%func;mode;mode%%() == PrivilegeMode::VU) {
    if (%%LINK%csr_field;vsstatus.UXL;CSR[vsstatus].UXL%% == $bits(XRegWidth::XLEN32)) {
      return 32;
    } else if (%%LINK%csr_field;vsstatus.UXL;CSR[vsstatus].UXL%% == $bits(XRegWidth::XLEN64)) {
      return 64;
    }
  }
}
if (%%LINK%func;mode;mode%%() == PrivilegeMode::M) {
  if (%%LINK%csr_field;misa.MXL;CSR[misa].MXL%% == $bits(XRegWidth::XLEN32)) {
    return 32;
  } else if (%%LINK%csr_field;misa.MXL;CSR[misa].MXL%% == $bits(XRegWidth::XLEN64)) {
    return 64;
  }
} else if (%%LINK%func;mode;mode%%() == PrivilegeMode::S) {
  if (%%LINK%csr_field;mstatus.SXL;CSR[mstatus].SXL%% == $bits(XRegWidth::XLEN32)) {
    return 32;
  } else if (%%LINK%csr_field;mstatus.SXL;CSR[mstatus].SXL%% == $bits(XRegWidth::XLEN64)) {
    return 64;
  }
} else if (%%LINK%func;mode;mode%%() == PrivilegeMode::U) {
  if (%%LINK%csr_field;mstatus.UXL;CSR[mstatus].UXL%% == $bits(XRegWidth::XLEN32)) {
    return 32;
  } else if (%%LINK%csr_field;mstatus.UXL;CSR[mstatus].UXL%% == $bits(XRegWidth::XLEN64)) {
    return 64;
  }
} else if (%%LINK%func;mode;mode%%() == PrivilegeMode::VS) {
  if (%%LINK%csr_field;hstatus.VSXL;CSR[hstatus].VSXL%% == $bits(XRegWidth::XLEN32)) {
    return 32;
  } else if (%%LINK%csr_field;hstatus.VSXL;CSR[hstatus].VSXL%% == $bits(XRegWidth::XLEN64)) {
    return 64;
  }
} else if (%%LINK%func;mode;mode%%() == PrivilegeMode::VU) {
  if (%%LINK%csr_field;vsstatus.UXL;CSR[vsstatus].UXL%% == $bits(XRegWidth::XLEN32)) {
    return 32;
  } else if (%%LINK%csr_field;vsstatus.UXL;CSR[vsstatus].UXL%% == $bits(XRegWidth::XLEN64)) {
    return 64;
  }
}

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 {
      %%LINK%func;assert;assert%%(TINST_VALUE_ON_FINAL_INSTRUCTION_GUEST_PAGE_FAULT == "always pseudoinstruction", "Instruction guest page faults can only report zero/pseudo instruction in tval");
      return 0x00002000;
    }
  } else if (op == MemoryOperation::Read) {
    if (TINST_VALUE_ON_FINAL_LOAD_GUEST_PAGE_FAULT == "always zero") {
      return 0;
    } else if (TINST_VALUE_ON_FINAL_LOAD_GUEST_PAGE_FAULT == "always pseudoinstruction") {
      if ((VSXLEN == 32) || MXLEN == 64) && (%%LINK%csr_field;hstatus.VSXL;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 %%LINK%func;tinst_transform;tinst_transform%%(encoding, 0);
    } else {
      %%LINK%func;unpredictable;unpredictable%%("Custom value written into htinst/mtinst");
    }
  } else if (op == MemoryOperation::Write || op == MemoryOperation::ReadModifyWrite) {
    if (TINST_VALUE_ON_FINAL_STORE_AMO_GUEST_PAGE_FAULT == "always zero") {
      return 0;
    } else if (TINST_VALUE_ON_FINAL_STORE_AMO_GUEST_PAGE_FAULT == "always pseudoinstruction") {
      if ((VSXLEN == 32) || MXLEN == 64) && (%%LINK%csr_field;hstatus.VSXL;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 %%LINK%func;tinst_transform;tinst_transform%%(encoding, 0);
    } else {
      %%LINK%func;unpredictable;unpredictable%%("Custom value written into htinst/mtinst");
    }
  }
} else {
  if (REPORT_GPA_IN_TVAL_ON_INTERMEDIATE_GUEST_PAGE_FAULT) {
    if ((VSXLEN == 32) || MXLEN == 64) && (%%LINK%csr_field;hstatus.VSXL;CSR[hstatus].VSXL%% == $bits(XRegWidth::XLEN32)) {
      return 0x00002000;
    } else if ((VSXLEN == 64) || MXLEN == 64) && (%%LINK%csr_field;hstatus.VSXL;CSR[hstatus].VSXL%% == $bits(XRegWidth::XLEN64)) {
      return 0x00003000;
    }
  }
}
if (for_final_vs_pte) {
  if (op == MemoryOperation::Fetch) {
    return 0;
  } else if (op == MemoryOperation::Read) {
    return %%LINK%func;tinst_transform;tinst_transform%%(encoding, 0);
  } else if (op == MemoryOperation::Write || op == MemoryOperation::ReadModifyWrite) {
    return %%LINK%func;tinst_transform;tinst_transform%%(encoding, 0);
  }
} else {
  if (%%LINK%csr_field;hstatus.VSXL;CSR[hstatus].VSXL%% == $bits(XRegWidth::XLEN32)) {
    return 0x00002000;
  } else {
    return 0x00003000;
  }
}

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 {
  %%LINK%func;assert;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 = %%LINK%func;exception_handling_mode;exception_handling_mode%%(code);
if (handling_mode == PrivilegeMode::S) {
  %%LINK%csr_field;htval.VALUE;CSR[htval].VALUE%% = write_gpa_in_tval ? (gpa >> 2) : 0;
  %%LINK%csr_field;htinst.VALUE;CSR[htinst].VALUE%% = tinst_value;
  %%LINK%csr_field;sepc.PC;CSR[sepc].PC%% = $pc;
  if (!%%LINK%func;stval_readonly?;stval_readonly?%%()) {
    %%LINK%csr_field;stval.VALUE;CSR[stval].VALUE%% = %%LINK%func;stval_for;stval_for%%(code, gva);
  }
  $pc = {%%LINK%csr_field;stvec.BASE;CSR[stvec].BASE%%, 2'b00};
  %%LINK%csr_field;scause.INT;CSR[scause].INT%% = 1'b0;
  %%LINK%csr_field;scause.CODE;CSR[scause].CODE%% = $bits(code);
  %%LINK%csr_field;hstatus.GVA;CSR[hstatus].GVA%% = 1;
  %%LINK%csr_field;hstatus.SPV;CSR[hstatus].SPV%% = 1;
  %%LINK%csr_field;hstatus.SPVP;CSR[hstatus].SPVP%% = $bits(from_mode)[0];
  %%LINK%csr_field;mstatus.SPP;CSR[mstatus].SPP%% = $bits(from_mode)[0];
} else {
  %%LINK%func;assert;assert%%(handling_mode == PrivilegeMode::M, "unexpected privilege mode");
  %%LINK%csr_field;mtval2.VALUE;CSR[mtval2].VALUE%% = write_gpa_in_tval ? (gpa >> 2) : 0;
  %%LINK%csr_field;mtinst.VALUE;CSR[mtinst].VALUE%% = tinst_value;
  %%LINK%csr_field;mstatus.MPP;CSR[mstatus].MPP%% = $bits(from_mode)[1:0];
  if (MXLEN == 64) {
    %%LINK%csr_field;mstatus.MPV;CSR[mstatus].MPV%% = 1;
  } else {
    %%LINK%csr_field;mstatush.MPV;CSR[mstatush].MPV%% = 1;
  }
}
%%LINK%func;set_mode;set_mode%%(handling_mode);
%%LINK%func;abort_current_instruction;abort_current_instruction%%();
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 {
  %%LINK%func;assert;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 = %%LINK%func;exception_handling_mode;exception_handling_mode%%(code);
if (handling_mode == PrivilegeMode::S) {
  %%LINK%csr_field;htval.VALUE;CSR[htval].VALUE%% = (gpa >> 2);
  %%LINK%csr_field;htinst.VALUE;CSR[htinst].VALUE%% = tinst_value;
  %%LINK%csr_field;sepc.PC;CSR[sepc].PC%% = $pc;
  %%LINK%csr_field;stval.VALUE;CSR[stval].VALUE%% = 0;
  $pc = {%%LINK%csr_field;stvec.BASE;CSR[stvec].BASE%%, 2'b00};
  %%LINK%csr_field;scause.INT;CSR[scause].INT%% = 1'b0;
  %%LINK%csr_field;scause.CODE;CSR[scause].CODE%% = $bits(code);
  %%LINK%csr_field;hstatus.GVA;CSR[hstatus].GVA%% = 1;
  %%LINK%csr_field;hstatus.SPV;CSR[hstatus].SPV%% = 1;
  %%LINK%csr_field;hstatus.SPVP;CSR[hstatus].SPVP%% = $bits(from_mode)[0];
  %%LINK%csr_field;mstatus.SPP;CSR[mstatus].SPP%% = $bits(from_mode)[0];
} else {
  %%LINK%func;assert;assert%%(handling_mode == PrivilegeMode::M, "unexpected privilege mode");
  %%LINK%csr_field;mtval2.VALUE;CSR[mtval2].VALUE%% = (gpa >> 2);
  %%LINK%csr_field;mtinst.VALUE;CSR[mtinst].VALUE%% = tinst_value;
  %%LINK%csr_field;mstatus.MPP;CSR[mstatus].MPP%% = $bits(from_mode)[1:0];
  %%LINK%csr_field;mstatus.MPV;CSR[mstatus].MPV%% = 1;
}
%%LINK%func;set_mode;set_mode%%(handling_mode);
%%LINK%func;abort_current_instruction;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

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;
  PmpCfg cfg = ($bits(CSR[pmpcfg0_addr]) >> shamt)[7:0];
  Bits<12> pmpaddr_idx = pmpaddr0_addr + i;
  Bits<PHYS_ADDR_WIDTH> range_hi = 0;
  Bits<PHYS_ADDR_WIDTH> range_lo = 0;
  if (cfg.A == $bits(PmpCfg_A::TOR)) {
    if (i == 0) {
      range_lo = 0;
    } else {
      range_lo = ($bits(CSR[pmpaddr_idx - 1]) << 2)[PHYS_ADDR_WIDTH - 1:0];
    }
    range_hi = ($bits(CSR[pmpaddr_idx]) << 2)[PHYS_ADDR_WIDTH - 1:0];
  } else if (cfg.A == $bits(PmpCfg_A::NAPOT)) {
    Bits<PHYS_ADDR_WIDTH - 2> pmpaddr_value = CSR[pmpaddr_idx].sw_read()[PHYS_ADDR_WIDTH - 3:0];
    Bits<PHYS_ADDR_WIDTH - 2> mask = pmpaddr_value ^ (pmpaddr_value + 1);
    range_lo = (pmpaddr_value & ~mask) << 2;
    Bits<PHYS_ADDR_WIDTH - 2> len = mask + 1;
    range_hi = pmpaddr_value & ~mask) + len) << 2;   } else if (cfg.A == $bits(PmpCfg_A::NA4 {
    range_lo = ($bits(CSR[pmpaddr_idx]) << 2)[PHYS_ADDR_WIDTH - 1:0];
    range_hi = range_lo + 4;
  }
  if ((paddr >= range_lo) && paddr + (access_size / 8 < range_hi)) {
    return PmpMatchResult::FullMatch, cfg;
  } else if (! {
    return PmpMatchResult::PartialMatch, -;
  }
}
return PmpMatchResult::NoMatch, -;
Bits<12> pmpcfg0_addr = 0x3a0;
Bits<12> pmpaddr0_addr = 0x3b0;
for (U32 i = 0; true; i++) {
  Bits<12> pmpcfg_idx = 0x3a0;
  Bits<6> shamt = 8;
  PmpCfg cfg = ($bits(CSR[pmpcfg0_addr]) >> shamt)[7:0];
  Bits<12> pmpaddr_idx = 0x3b1;
  Bits<PHYS_ADDR_WIDTH> range_hi = 0;
  Bits<PHYS_ADDR_WIDTH> range_lo = 0;
  if (cfg.A == $bits(PmpCfg_A::TOR)) {
    range_lo = ($bits(CSR[pmpaddr_idx - 1]) << 2)[55:0];
    range_hi = ($bits(CSR[pmpaddr_idx]) << 2)[55:0];
  } else if (cfg.A == $bits(PmpCfg_A::NAPOT)) {
    Bits<PHYS_ADDR_WIDTH - 2> pmpaddr_value = CSR[pmpaddr_idx].sw_read()[53:0];
    Bits<PHYS_ADDR_WIDTH - 2> mask = pmpaddr_value ^ (pmpaddr_value + 1);
    range_lo = (pmpaddr_value & ~mask) << 2;
    Bits<PHYS_ADDR_WIDTH - 2> len = mask + 1;
    range_hi = pmpaddr_value & ~mask) + len) << 2;   } else if (cfg.A == $bits(PmpCfg_A::NA4 {
    range_lo = ($bits(CSR[pmpaddr_idx]) << 2)[55:0];
    range_hi = range_lo + 4;
  }
  if ((paddr >= range_lo) && paddr + (access_size / 8 < range_hi)) {
    return PmpMatchResult::FullMatch, cfg;
  } else if (! {
    return PmpMatchResult::PartialMatch, -;
  }
}
return PmpMatchResult::NoMatch, -;

pmp_match

Given a physical address, see if any PMP entry matches.

If there is a complete match, return the PmpCfg that guards the region. If there is no match or a partial match, report that result.

Return Type

 PmpMatchResult, PmpCfg

Arguments

 Bits<PHYS_ADDR_WIDTH> paddr, U32 access_size
  • Original

  • Pruned

if (MXLEN == 64) {
  return %%LINK%func;pmp_match_64;pmp_match_64%%(paddr, access_size);
} else {
  return %%LINK%func;pmp_match_32;pmp_match_32%%(paddr, access_size);
}
return %%LINK%func;pmp_match_64;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 = %%LINK%func;effective_ldst_mode;effective_ldst_mode%%();
PmpMatchResult match_result;
PmpCfg cfg;
(match_result, cfg = %%LINK%func;pmp_match;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 {
  %%LINK%func;assert;assert%%(match_result == PmpMatchResult::PartialMatch, "PMP matching logic error");
  return false;
}
return true;
PrivilegeMode mode = %%LINK%func;effective_ldst_mode;effective_ldst_mode%%();
PmpMatchResult match_result;
PmpCfg cfg;
(match_result, cfg = %%LINK%func;pmp_match;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 {
  %%LINK%func;assert;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

if (paddr > 1 << PHYS_ADDR_WIDTH) - access_size {
  %%LINK%func;raise;raise%%(fault_type, from_mode, vaddr);
}
if (%%LINK%func;implemented?;implemented?%%(ExtensionName::Smpmp)) {
  if (!%%LINK%func;pmp_check;pmp_check%%(paddr[PHYS_ADDR_WIDTH - 1:0], access_size, type)) {
    %%LINK%func;raise;raise%%(fault_type, from_mode, vaddr);
  }
}
if (paddr > 0x100000000000000) - access_size {
  %%LINK%func;raise;raise%%(fault_type, from_mode, vaddr);
}
if (!%%LINK%func;pmp_check;pmp_check%%(paddr[55:0], access_size, type)) {
  %%LINK%func;raise;raise%%(fault_type, from_mode, vaddr);
}

read_physical_memory_64 (builtin)

Read eight bytes from physical memory.

Return Type

 Bits<64>

Arguments

 XReg paddr

read_physical_memory

Read from physical memory.

Return Type

 Bits<len>

Arguments

 XReg paddr
  • Original

  • Pruned

if (len == 8) {
  return %%LINK%func;read_physical_memory_8;read_physical_memory_8%%(paddr);
} else if (len == 16) {
  return %%LINK%func;read_physical_memory_16;read_physical_memory_16%%(paddr);
} else if (len == 32) {
  return %%LINK%func;read_physical_memory_32;read_physical_memory_32%%(paddr);
} else if (len == 64) {
  return %%LINK%func;read_physical_memory_64;read_physical_memory_64%%(paddr);
} else {
  %%LINK%func;assert;assert%%(false, "Invalid len");
}
if (len == 8) {
  return %%LINK%func;read_physical_memory_8;read_physical_memory_8%%(paddr);
} else if (len == 16) {
  return %%LINK%func;read_physical_memory_16;read_physical_memory_16%%(paddr);
} else if (len == 32) {
  return %%LINK%func;read_physical_memory_32;read_physical_memory_32%%(paddr);
} else if (len == 64) {
  return %%LINK%func;read_physical_memory_64;read_physical_memory_64%%(paddr);
} else {
  %%LINK%func;assert;assert%%(false, "Invalid len");
}

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

 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 && (%%LINK%csr_field;mstatus.MXR;CSR[mstatus].MXR%% == 1);
Boolean pbmte = %%LINK%csr_field;menvcfg.PBMTE;CSR[menvcfg].PBMTE%% == 1;
Boolean adue = %%LINK%csr_field;menvcfg.ADUE;CSR[menvcfg].ADUE%% == 1;
Bits<32> tinst = %%LINK%func;tinst_value_for_guest_page_fault;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) {
  %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
}
ppn = %%LINK%csr_field;hgatp.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 (!%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::HardwarePageTableRead, pte_paddr, PTESIZE)) {
    %%LINK%func;raise;raise%%(access_fault_code, PrivilegeMode::U, vaddr);
  }
  %%LINK%func;access_check;access_check%%(pte_paddr, PTESIZE, vaddr, MemoryOperation::Read, access_fault_code, effective_mode);
  Bits<PTESIZE> pte = %%LINK%func;read_physical_memory;read_physical_memory%%<PTESIZE>(pte_paddr);
  PteFlags pte_flags = pte[9:0];
  if ((VA_SIZE != 32) && (pte[60:54] != 0)) {
    %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
  }
  if (!%%LINK%func;implemented?;implemented?%%(ExtensionName::Svnapot)) {
    if ((PTESIZE >= 64) && pte[63] != 0) {
      %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
    }
  }
  if ((PTESIZE >= 64) && !pbmte && (pte[62:61] != 0)) {
    %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
  }
  if ((PTESIZE >= 64) && pbmte && (pte[62:61] == 3)) {
    %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
  }
  if (pte_flags.V == 0) {
    %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
  }
  if (pte_flags.R == 0 && pte_flags.W == 1) {
    %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
  }
  if (pte_flags.R == 1 || pte_flags.X == 1) {
    if (pte_flags.U == 0) {
      %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
    }
    if (op == MemoryOperation::Write) || (op == MemoryOperation::ReadModifyWrite && (pte_flags.W == 0)) {
      %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
    } else if ((op == MemoryOperation::Fetch) && (pte_flags.X == 0)) {
      %%LINK%func;raise_guest_page_fault;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) {
        %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
      }
    }
    if ((i > 0) && (pte[(i - 1) * VPN_SIZE:10] != 0)) {
      %%LINK%func;raise_guest_page_fault;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 (!%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::RsrvEventual, pte_paddr, PTESIZE)) {
          %%LINK%func;raise;raise%%(access_fault_code, PrivilegeMode::U, vaddr);
        }
        if (!%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::HardwarePageTableWrite, pte_paddr, PTESIZE)) {
          %%LINK%func;raise;raise%%(access_fault_code, PrivilegeMode::U, vaddr);
        }
        %%LINK%func;access_check;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 = %%LINK%func;atomic_check_then_write_32;atomic_check_then_write_32%%(pte_paddr, pte, updated_pte);
        } else if (PTESIZE == 64) {
          success = %%LINK%func;atomic_check_then_write_64;atomic_check_then_write_64%%(pte_paddr, pte, updated_pte);
        } else {
          %%LINK%func;assert;assert%%(false, "Unexpected PTESIZE");
        }
        if (!success) {
          i = i + 1;
        } else {
          result.paddr = pte_paddr;
          if (PTESIZE >= 64) {
            result.pbmt = $enum(Pbmt, pte[62:61]);
          }
          result.pte_flags = pte_flags;
          return result;
        }
      } else {
        %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
      }
    }
  } else {
    if (i == 0) {
      %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
    }
    if (pte_flags.D == 1 || pte_flags.A == 1 || pte_flags.U == 1) {
      %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
    }
    if ((VA_SIZE != 32) && (pte[62:61] != 0)) {
      %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
    }
    if ((VA_SIZE != 32) && pte[63] != 0) {
      %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
    }
    ppn = pte[PA_SIZE - 3:10] << 12;
  }
}
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 && (%%LINK%csr_field;mstatus.MXR;CSR[mstatus].MXR%% == 1);
Boolean pbmte = false;
Boolean adue = false;
Bits<32> tinst = %%LINK%func;tinst_value_for_guest_page_fault;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) {
  %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
}
ppn = %%LINK%csr_field;hgatp.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 (!%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::HardwarePageTableRead, pte_paddr, PTESIZE)) {
    %%LINK%func;raise;raise%%(access_fault_code, PrivilegeMode::U, vaddr);
  }
  %%LINK%func;access_check;access_check%%(pte_paddr, PTESIZE, vaddr, MemoryOperation::Read, access_fault_code, effective_mode);
  Bits<PTESIZE> pte = %%LINK%func;read_physical_memory;read_physical_memory%%<PTESIZE>(pte_paddr);
  PteFlags pte_flags = pte[9:0];
  if ((VA_SIZE != 32) && (pte[60:54] != 0)) {
    %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
  }
  if ((PTESIZE >= 64) && pte[63] != 0) {
    %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
  }
  if ((PTESIZE >= 64)) {
    %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
  }
  if (false && (pte[62:61] == 3)) {
    %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
  }
  if (pte_flags.V == 0) {
    %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
  }
  if (pte_flags.R == 0 && pte_flags.W == 1) {
    %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
  }
  if (pte_flags.R == 1 || pte_flags.X == 1) {
    if (pte_flags.U == 0) {
      %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
    }
    if (op == MemoryOperation::Write) || (op == MemoryOperation::ReadModifyWrite && (pte_flags.W == 0)) {
      %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
    } else if ((op == MemoryOperation::Fetch) && (pte_flags.X == 0)) {
      %%LINK%func;raise_guest_page_fault;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) {
        %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
      }
    }
    if ((i > 0) && (pte[(i - 1) * VPN_SIZE:10] != 0)) {
      %%LINK%func;raise_guest_page_fault;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)) {
      %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
    }
  } else {
    if (i == 0) {
      %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
    }
    if (pte_flags.D == 1 || pte_flags.A == 1 || pte_flags.U == 1) {
      %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
    }
    if ((VA_SIZE != 32) && (pte[62:61] != 0)) {
      %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
    }
    if ((VA_SIZE != 32) && pte[63] != 0) {
      %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, tinst, effective_mode);
    }
    ppn = pte[PA_SIZE - 3:10] << 12;
  }
}

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 {
    %%LINK%func;assert;assert%%(false, "Bad transform");
  }
} else {
  %%LINK%func;assert;assert%%(false, "TODO: compressed instruction");
}
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 {
    %%LINK%func;assert;assert%%(false, "Bad transform");
  }
} else {
  %%LINK%func;assert;assert%%(false, "TODO: compressed instruction");
}

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 (effective_mode == PrivilegeMode::S || effective_mode == PrivilegeMode::U) {
  result.paddr = gpaddr;
  return result;
}
Boolean mxr = %%LINK%csr_field;mstatus.MXR;CSR[mstatus].MXR%% == 1;
if (GSTAGE_MODE_BARE && %%LINK%csr_field;hgatp.MODE;CSR[hgatp].MODE%% == $bits(HgatpMode::Bare)) {
  result.paddr = gpaddr;
  return result;
} else if (SV32X4_TRANSLATION && %%LINK%csr_field;hgatp.MODE;CSR[hgatp].MODE%% == $bits(HgatpMode::Sv32x4)) {
  return %%LINK%func;gstage_page_walk;gstage_page_walk%%<32, 34, 32, 2>(gpaddr, vaddr, op, effective_mode, false, encoding);
} else if (SV39X4_TRANSLATION && %%LINK%csr_field;hgatp.MODE;CSR[hgatp].MODE%% == $bits(HgatpMode::Sv39x4)) {
  return %%LINK%func;gstage_page_walk;gstage_page_walk%%<39, 56, 64, 3>(gpaddr, vaddr, op, effective_mode, false, encoding);
} else if (SV48X4_TRANSLATION && %%LINK%csr_field;hgatp.MODE;CSR[hgatp].MODE%% == $bits(HgatpMode::Sv48x4)) {
  return %%LINK%func;gstage_page_walk;gstage_page_walk%%<48, 56, 64, 4>(gpaddr, vaddr, op, effective_mode, false, encoding);
} else if (SV57X4_TRANSLATION && %%LINK%csr_field;hgatp.MODE;CSR[hgatp].MODE%% == $bits(HgatpMode::Sv57x4)) {
  return %%LINK%func;gstage_page_walk;gstage_page_walk%%<57, 56, 64, 5>(gpaddr, vaddr, op, effective_mode, false, encoding);
} else {
  if (op == MemoryOperation::Read) {
    %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, %%LINK%func;tinst_value_for_guest_page_fault;tinst_value_for_guest_page_fault%%(op, encoding, true), effective_mode);
  } else if (op == MemoryOperation::Write || op == MemoryOperation::ReadModifyWrite) {
    %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, %%LINK%func;tinst_value_for_guest_page_fault;tinst_value_for_guest_page_fault%%(op, encoding, true), effective_mode);
  } else {
    %%LINK%func;assert;assert%%(op == MemoryOperation::Fetch, "unexpected memory op");
    %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, %%LINK%func;tinst_value_for_guest_page_fault;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 = %%LINK%csr_field;mstatus.MXR;CSR[mstatus].MXR%% == 1;
if (%%LINK%csr_field;hgatp.MODE;CSR[hgatp].MODE%% == $bits(HgatpMode::Bare)) {
  result.paddr = gpaddr;
  return result;
} else if (%%LINK%csr_field;hgatp.MODE;CSR[hgatp].MODE%% == $bits(HgatpMode::Sv39x4)) {
  return %%LINK%func;gstage_page_walk;gstage_page_walk%%<39, 56, 64, 3>(gpaddr, vaddr, op, effective_mode, false, encoding);
} else if (%%LINK%csr_field;hgatp.MODE;CSR[hgatp].MODE%% == $bits(HgatpMode::Sv48x4)) {
  return %%LINK%func;gstage_page_walk;gstage_page_walk%%<48, 56, 64, 4>(gpaddr, vaddr, op, effective_mode, false, encoding);
} else {
  if (op == MemoryOperation::Read) {
    %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, %%LINK%func;tinst_value_for_guest_page_fault;tinst_value_for_guest_page_fault%%(op, encoding, true), effective_mode);
  } else if (op == MemoryOperation::Write || op == MemoryOperation::ReadModifyWrite) {
    %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, %%LINK%func;tinst_value_for_guest_page_fault;tinst_value_for_guest_page_fault%%(op, encoding, true), effective_mode);
  } else {
    %%LINK%func;assert;assert%%(op == MemoryOperation::Fetch, "unexpected memory op");
    %%LINK%func;raise_guest_page_fault;raise_guest_page_fault%%(op, gpaddr, vaddr, %%LINK%func;tinst_value_for_guest_page_fault;tinst_value_for_guest_page_fault%%(op, encoding, true), effective_mode);
  }
}

read_physical_memory_32 (builtin)

Read four bytes from physical memory.

Return Type

 Bits<32>

Arguments

 XReg paddr

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

 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 (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1 && (effective_mode == PrivilegeMode::VS || effective_mode == PrivilegeMode::VU)) {
  adue = %%LINK%csr_field;henvcfg.ADUE;CSR[henvcfg].ADUE%% == 1;
} else {
  adue = %%LINK%csr_field;menvcfg.ADUE;CSR[menvcfg].ADUE%% == 1;
}
Boolean pbmte;
if (VA_SIZE == 32) {
  pbmte = false;
} else {
  if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1 && (effective_mode == PrivilegeMode::VS || effective_mode == PrivilegeMode::VU)) {
    pbmte = %%LINK%csr_field;henvcfg.PBMTE;CSR[henvcfg].PBMTE%% == 1;
  } else {
    pbmte = %%LINK%csr_field;menvcfg.PBMTE;CSR[menvcfg].PBMTE%% == 1;
  }
}
Boolean mxr;
if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1 && (effective_mode == PrivilegeMode::VS || effective_mode == PrivilegeMode::VU)) {
  mxr = (%%LINK%csr_field;mstatus.MXR;CSR[mstatus].MXR%% == 1) || (%%LINK%csr_field;vsstatus.MXR;CSR[vsstatus].MXR%% == 1);
} else {
  mxr = %%LINK%csr_field;mstatus.MXR;CSR[mstatus].MXR%% == 1;
}
Boolean sum;
if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1 && (effective_mode == PrivilegeMode::VS)) {
  sum = %%LINK%csr_field;vsstatus.SUM;CSR[vsstatus].SUM%% == 1;
} else {
  sum = %%LINK%csr_field;mstatus.SUM;CSR[mstatus].SUM%% == 1;
}
ppn = %%LINK%csr_field;vsatp.PPN;CSR[vsatp].PPN%%;
if ((VA_SIZE < %%LINK%func;xlen;xlen%%()) && (vaddr[%%LINK%func;xlen;xlen%%() - 1:VA_SIZE] != {%%LINK%func;xlen;xlen%%() - VA_SIZE{vaddr[VA_SIZE - 1]}})) {
  %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
}
for (U32 i = (LEVELS - 1); i >= 0; i--) {
  U32 vpn = (vaddr >> (12 + VPN_SIZE * i)) & 1 << VPN_SIZE) - 1);   Bits<PA_SIZE> pte_gpaddr = (ppn << 12) + (vpn * (PTESIZE / 8;
  TranslationResult pte_phys = %%LINK%func;translate_gstage;translate_gstage%%(pte_gpaddr, vaddr, MemoryOperation::Read, effective_mode, encoding);
  if (!%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::HardwarePageTableRead, pte_phys.paddr, PTESIZE)) {
    %%LINK%func;raise;raise%%(access_fault_code, effective_mode, vaddr);
  }
  %%LINK%func;access_check;access_check%%(pte_phys.paddr, PTESIZE, vaddr, MemoryOperation::Read, access_fault_code, effective_mode);
  Bits<PTESIZE> pte = %%LINK%func;read_physical_memory;read_physical_memory%%<PTESIZE>(pte_phys.paddr);
  PteFlags pte_flags = pte[9:0];
  Boolean ss_page = (pte_flags.R == 0) && (pte_flags.W == 1) && (pte_flags.X == 0);
  if ((VA_SIZE != 32) && (pte[60:54] != 0)) {
    %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
  }
  if (pte_flags.V == 0) {
    %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
  }
  if (!sse) {
    if ((pte_flags.R == 0) && (pte_flags.W == 1)) {
      %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
    }
  }
  if (pbmte) {
    if (pte[62:61] == 3) {
      %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
    }
  } else {
    if ((PTESIZE >= 64) && (pte[62:61] != 0)) {
      %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
    }
  }
  if (!%%LINK%func;implemented?;implemented?%%(ExtensionName::Svnapot)) {
    if ((PTESIZE >= 64) && (pte[63] != 0)) {
      %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
    }
  }
  if (pte_flags.R == 1 || pte_flags.X == 1) {
    if (op == MemoryOperation::Read || op == MemoryOperation::ReadModifyWrite) {
      if (!mxr) && (pte_flags.R == 0 || mxr) && (pte_flags.X == 0 && pte_flags.R == 0) {
        %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
      }
      if (effective_mode == PrivilegeMode::U && pte_flags.U == 0) {
        %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
      } else if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1 && effective_mode == PrivilegeMode::VU && pte_flags.U == 0) {
        %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
      } else if (effective_mode == PrivilegeMode::S && pte_flags.U == 1 && !sum) {
        %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
      } else if (effective_mode == PrivilegeMode::VS && pte_flags.U == 1 && !sum) {
        %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
      }
    }
    if (op == MemoryOperation::Write) || (op == MemoryOperation::ReadModifyWrite && (pte_flags.W == 0)) {
      %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
    } else if ((op == MemoryOperation::Fetch) && (pte_flags.X == 0)) {
      %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
    } else if ((op == MemoryOperation::Fetch) && ss_page) {
      %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
    }
    %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr) if ;
    if ((pte_flags.A == 0) || pte_flags.D == 0) && ((op == MemoryOperation::Write) || (op == MemoryOperation::ReadModifyWrite)) {
      if (adue) {
        TranslationResult pte_phys = %%LINK%func;translate_gstage;translate_gstage%%(pte_gpaddr, vaddr, MemoryOperation::Write, effective_mode, encoding);
        if (!%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::RsrvEventual, pte_phys.paddr, PTESIZE)) {
          %%LINK%func;raise;raise%%(access_fault_code, effective_mode, vaddr);
        }
        if (!%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::HardwarePageTableWrite, pte_phys.paddr, PTESIZE)) {
          %%LINK%func;raise;raise%%(access_fault_code, effective_mode, vaddr);
        }
        %%LINK%func;access_check;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 = %%LINK%func;atomic_check_then_write_32;atomic_check_then_write_32%%(pte_phys.paddr, pte, updated_pte);
        } else if (PTESIZE == 64) {
          success = %%LINK%func;atomic_check_then_write_64;atomic_check_then_write_64%%(pte_phys.paddr, pte, updated_pte);
        } else {
          %%LINK%func;assert;assert%%(false, "Unexpected PTESIZE");
        }
        if (!success) {
          i = i + 1;
        } else {
          TranslationResult pte_phys = %%LINK%func;translate_gstage;translate_gstage%%({(pte[PA_SIZE - 3:(i * VPN_SIZE) + 10] << 2), vaddr[11:0]}, vaddr, op, effective_mode, encoding);
          result.paddr = pte_phys.paddr;
          result.pbmt = pte_phys.pbmt == Pbmt::PMA ? $enum(Pbmt, pte[62:61]) : pte_phys.pbmt;
          result.pte_flags = pte_flags;
          return result;
        }
      } else {
        %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
      }
    }
    TranslationResult pte_phys = %%LINK%func;translate_gstage;translate_gstage%%({(pte[PA_SIZE - 3:(i * VPN_SIZE) + 10] << 2), vaddr[11:0]}, vaddr, op, effective_mode, encoding);
    result.paddr = pte_phys.paddr;
    if (PTESIZE >= 64) {
      result.pbmt = pte_phys.pbmt == Pbmt::PMA ? $enum(Pbmt, pte[62:61]) : pte_phys.pbmt;
    }
    result.pte_flags = pte_flags;
    return result;
  } else {
    if (i == 0) {
      %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
    }
    if (pte_flags.D == 1 || pte_flags.A == 1 || pte_flags.U == 1) {
      %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
    }
    if ((VA_SIZE != 32) && (pte[62:61] != 0)) {
      %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
    }
    if ((VA_SIZE != 32) && pte[63] != 0) {
      %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
    }
    ppn = pte[PA_SIZE - 3:10] << 12;
  }
}
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 (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1 && (effective_mode == PrivilegeMode::VS || effective_mode == PrivilegeMode::VU)) {
  adue = false;
} else {
  adue = false;
}
Boolean pbmte;
if (VA_SIZE == 32) {
  pbmte = false;
} else {
  if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1 && (effective_mode == PrivilegeMode::VS || effective_mode == PrivilegeMode::VU)) {
    pbmte = false;
  } else {
    pbmte = false;
  }
}
Boolean mxr;
if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1 && (effective_mode == PrivilegeMode::VS || effective_mode == PrivilegeMode::VU)) {
  mxr = (%%LINK%csr_field;mstatus.MXR;CSR[mstatus].MXR%% == 1) || (%%LINK%csr_field;vsstatus.MXR;CSR[vsstatus].MXR%% == 1);
} else {
  mxr = %%LINK%csr_field;mstatus.MXR;CSR[mstatus].MXR%% == 1;
}
Boolean sum;
if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1 && (effective_mode == PrivilegeMode::VS)) {
  sum = %%LINK%csr_field;vsstatus.SUM;CSR[vsstatus].SUM%% == 1;
} else {
  sum = %%LINK%csr_field;mstatus.SUM;CSR[mstatus].SUM%% == 1;
}
ppn = %%LINK%csr_field;vsatp.PPN;CSR[vsatp].PPN%%;
if ((VA_SIZE < %%LINK%func;xlen;xlen%%()) && (vaddr[%%LINK%func;xlen;xlen%%() - 1:VA_SIZE] != {%%LINK%func;xlen;xlen%%() - VA_SIZE{vaddr[VA_SIZE - 1]}})) {
  %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
}
for (U32 i = (LEVELS - 1); i >= 0; i--) {
  U32 vpn = (vaddr >> (12 + VPN_SIZE * i)) & 1 << VPN_SIZE) - 1);   Bits<PA_SIZE> pte_gpaddr = (ppn << 12) + (vpn * (PTESIZE / 8;
  TranslationResult pte_phys = %%LINK%func;translate_gstage;translate_gstage%%(pte_gpaddr, vaddr, MemoryOperation::Read, effective_mode, encoding);
  if (!%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::HardwarePageTableRead, pte_phys.paddr, PTESIZE)) {
    %%LINK%func;raise;raise%%(access_fault_code, effective_mode, vaddr);
  }
  %%LINK%func;access_check;access_check%%(pte_phys.paddr, PTESIZE, vaddr, MemoryOperation::Read, access_fault_code, effective_mode);
  Bits<PTESIZE> pte = %%LINK%func;read_physical_memory;read_physical_memory%%<PTESIZE>(pte_phys.paddr);
  PteFlags pte_flags = pte[9:0];
  Boolean ss_page = (pte_flags.R == 0) && (pte_flags.W == 1) && (pte_flags.X == 0);
  if ((VA_SIZE != 32) && (pte[60:54] != 0)) {
    %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
  }
  if (pte_flags.V == 0) {
    %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
  }
  if ((pte_flags.R == 0) && (pte_flags.W == 1)) {
    %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
  }
  if ((PTESIZE >= 64) && (pte[62:61] != 0)) {
    %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
  }
  if ((PTESIZE >= 64) && (pte[63] != 0)) {
    %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
  }
  if (pte_flags.R == 1 || pte_flags.X == 1) {
    if (op == MemoryOperation::Read || op == MemoryOperation::ReadModifyWrite) {
      if (!mxr) && (pte_flags.R == 0 || mxr) && (pte_flags.X == 0 && pte_flags.R == 0) {
        %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
      }
      if (effective_mode == PrivilegeMode::U && pte_flags.U == 0) {
        %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
      } else if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1 && effective_mode == PrivilegeMode::VU && pte_flags.U == 0) {
        %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
      } else if (effective_mode == PrivilegeMode::S && pte_flags.U == 1 && !sum) {
        %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
      } else if (effective_mode == PrivilegeMode::VS && pte_flags.U == 1 && !sum) {
        %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
      }
    }
    if (op == MemoryOperation::Write) || (op == MemoryOperation::ReadModifyWrite && (pte_flags.W == 0)) {
      %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
    } else if ((op == MemoryOperation::Fetch) && (pte_flags.X == 0)) {
      %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
    } else if ((op == MemoryOperation::Fetch) && ss_page) {
      %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
    }
    %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr) if ;
    if ((pte_flags.A == 0) || pte_flags.D == 0) && ((op == MemoryOperation::Write) || (op == MemoryOperation::ReadModifyWrite)) {
      %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
    }
    TranslationResult pte_phys = %%LINK%func;translate_gstage;translate_gstage%%({(pte[PA_SIZE - 3:(i * VPN_SIZE) + 10] << 2), vaddr[11:0]}, vaddr, op, effective_mode, encoding);
    result.paddr = pte_phys.paddr;
    if (PTESIZE >= 64) {
      result.pbmt = pte_phys.pbmt == Pbmt::PMA ? $enum(Pbmt, pte[62:61]) : pte_phys.pbmt;
    }
    result.pte_flags = pte_flags;
    return result;
  } else {
    if (i == 0) {
      %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
    }
    if (pte_flags.D == 1 || pte_flags.A == 1 || pte_flags.U == 1) {
      %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
    }
    if ((VA_SIZE != 32) && (pte[62:61] != 0)) {
      %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
    }
    if ((VA_SIZE != 32) && pte[63] != 0) {
      %%LINK%func;raise;raise%%(page_fault_code, effective_mode, vaddr);
    }
    ppn = pte[PA_SIZE - 3:10] << 12;
  }
}

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 = %%LINK%func;cached_translation;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 = %%LINK%func;current_translation_mode;current_translation_mode%%(effective_mode);
if (translation_mode == SatpMode::Reserved) {
  if (op == MemoryOperation::Read) {
    %%LINK%func;raise;raise%%(ExceptionCode::LoadPageFault, effective_mode, vaddr);
  } else if (op == MemoryOperation::Write || op == MemoryOperation::ReadModifyWrite) {
    %%LINK%func;raise;raise%%(ExceptionCode::StoreAmoPageFault, effective_mode, vaddr);
  } else {
    %%LINK%func;assert;assert%%(op == MemoryOperation::Fetch, "Unexpected memory operation");
    %%LINK%func;raise;raise%%(ExceptionCode::InstructionPageFault, effective_mode, vaddr);
  }
}
if (translation_mode == SatpMode::Sv32) {
  result = %%LINK%func;stage1_page_walk;stage1_page_walk%%<32, 34, 32, 2>(vaddr, op, effective_mode, encoding);
} else if (translation_mode == SatpMode::Sv39) {
  result = %%LINK%func;stage1_page_walk;stage1_page_walk%%<39, 56, 64, 3>(vaddr, op, effective_mode, encoding);
} else if (translation_mode == SatpMode::Sv48) {
  result = %%LINK%func;stage1_page_walk;stage1_page_walk%%<48, 56, 64, 4>(vaddr, op, effective_mode, encoding);
} else if (translation_mode == SatpMode::Sv57) {
  result = %%LINK%func;stage1_page_walk;stage1_page_walk%%<57, 56, 64, 5>(vaddr, op, effective_mode, encoding);
} else {
  %%LINK%func;assert;assert%%(false, "Unexpected SatpMode");
}
%%LINK%func;maybe_cache_translation;maybe_cache_translation%%(vaddr, op, result);
return result;
Boolean cached_translation_valid;
CachedTranslationResult cached_translation_result;
cached_translation_result = %%LINK%func;cached_translation;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 = %%LINK%func;current_translation_mode;current_translation_mode%%(effective_mode);
if (translation_mode == SatpMode::Reserved) {
  if (op == MemoryOperation::Read) {
    %%LINK%func;raise;raise%%(ExceptionCode::LoadPageFault, effective_mode, vaddr);
  } else if (op == MemoryOperation::Write || op == MemoryOperation::ReadModifyWrite) {
    %%LINK%func;raise;raise%%(ExceptionCode::StoreAmoPageFault, effective_mode, vaddr);
  } else {
    %%LINK%func;assert;assert%%(op == MemoryOperation::Fetch, "Unexpected memory operation");
    %%LINK%func;raise;raise%%(ExceptionCode::InstructionPageFault, effective_mode, vaddr);
  }
}
if (translation_mode == SatpMode::Sv32) {
  result = %%LINK%func;stage1_page_walk;stage1_page_walk%%<32, 34, 32, 2>(vaddr, op, effective_mode, encoding);
} else if (translation_mode == SatpMode::Sv39) {
  result = %%LINK%func;stage1_page_walk;stage1_page_walk%%<39, 56, 64, 3>(vaddr, op, effective_mode, encoding);
} else if (translation_mode == SatpMode::Sv48) {
  result = %%LINK%func;stage1_page_walk;stage1_page_walk%%<48, 56, 64, 4>(vaddr, op, effective_mode, encoding);
} else if (translation_mode == SatpMode::Sv57) {
  result = %%LINK%func;stage1_page_walk;stage1_page_walk%%<57, 56, 64, 5>(vaddr, op, effective_mode, encoding);
} else {
  %%LINK%func;assert;assert%%(false, "Unexpected SatpMode");
}
%%LINK%func;maybe_cache_translation;maybe_cache_translation%%(vaddr, op, result);
return result;

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

 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

 Bits<PHYS_ADDR_WIDTH> physical_address
  • Original

  • Pruned

return false if (MISALIGNED_MAX_ATOMICITY_GRANULE_SIZE == 0);
if (%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::MAG16, physical_address, N) && %%LINK%func;in_naturally_aligned_region?;in_naturally_aligned_region?%%<128>(physical_address, N)) {
  return true;
} else if (%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::MAG8, physical_address, N) && %%LINK%func;in_naturally_aligned_region?;in_naturally_aligned_region?%%<4>(physical_address, N)) {
  return true;
} else if (%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::MAG4, physical_address, N) && %%LINK%func;in_naturally_aligned_region?;in_naturally_aligned_region?%%<32>(physical_address, N)) {
  return true;
} else if (%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::MAG2, physical_address, N) && %%LINK%func;in_naturally_aligned_region?;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

 Bits<N>

Arguments

 XReg virtual_address, Bits<N> value, AmoOperation op, Bits<1>    aq, Bits<1>    rl, Bits<INSTR_ENC_SIZE> encoding
  • Original

  • Pruned

Boolean aligned = %%LINK%func;is_naturally_aligned;is_naturally_aligned%%<N>(virtual_address);
if (!aligned && MISALIGNED_LDST_EXCEPTION_PRIORITY == "high") {
  %%LINK%func;raise;raise%%(ExceptionCode::StoreAmoAddressMisaligned, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), virtual_address);
}
Bits<PHYS_ADDR_WIDTH> physical_address = (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1) ? %%LINK%func;translate;translate%%(virtual_address, MemoryOperation::ReadModifyWrite, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), encoding).paddr : virtual_address;
if (%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::AmoNone, physical_address, N)) {
  %%LINK%func;raise;raise%%(ExceptionCode::StoreAmoAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), virtual_address);
} else if (op == AmoOperation::Add || op == AmoOperation::Max || op == AmoOperation::Maxu || op == AmoOperation::Min || op == AmoOperation::Minu && !%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::AmoArithmetic, physical_address, N)) {
  %%LINK%func;raise;raise%%(ExceptionCode::StoreAmoAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), virtual_address);
} else if (op == AmoOperation::And || op == AmoOperation::Or || op == AmoOperation::Xor && !%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::AmoLogical, physical_address, N)) {
  %%LINK%func;raise;raise%%(ExceptionCode::StoreAmoAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), virtual_address);
} else {
  %%LINK%func;assert;assert%%(%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::AmoSwap, physical_address, N) && op == AmoOperation::Swap, "Bad AMO operation");
}
if (!aligned && !%%LINK%func;misaligned_is_atomic?;misaligned_is_atomic?%%<N>(physical_address)) {
  %%LINK%func;raise;raise%%(ExceptionCode::StoreAmoAddressMisaligned, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), virtual_address);
}
if (N == 32) {
  return %%LINK%func;atomic_read_modify_write_32;atomic_read_modify_write_32%%(physical_address, value, op);
} else {
  return %%LINK%func;atomic_read_modify_write_64;atomic_read_modify_write_64%%(physical_address, value, op);
}
Boolean aligned = %%LINK%func;is_naturally_aligned;is_naturally_aligned%%<N>(virtual_address);
if (!aligned) {
  %%LINK%func;raise;raise%%(ExceptionCode::StoreAmoAddressMisaligned, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), virtual_address);
}
Bits<PHYS_ADDR_WIDTH> physical_address = (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1) ? %%LINK%func;translate;translate%%(virtual_address, MemoryOperation::ReadModifyWrite, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), encoding).paddr : virtual_address;
if (%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::AmoNone, physical_address, N)) {
  %%LINK%func;raise;raise%%(ExceptionCode::StoreAmoAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), virtual_address);
} else if (op == AmoOperation::Add || op == AmoOperation::Max || op == AmoOperation::Maxu || op == AmoOperation::Min || op == AmoOperation::Minu && !%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::AmoArithmetic, physical_address, N)) {
  %%LINK%func;raise;raise%%(ExceptionCode::StoreAmoAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), virtual_address);
} else if (op == AmoOperation::And || op == AmoOperation::Or || op == AmoOperation::Xor && !%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::AmoLogical, physical_address, N)) {
  %%LINK%func;raise;raise%%(ExceptionCode::StoreAmoAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), virtual_address);
} else {
  %%LINK%func;assert;assert%%(%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::AmoSwap, physical_address, N) && op == AmoOperation::Swap, "Bad AMO operation");
}
if (!aligned && !%%LINK%func;misaligned_is_atomic?;misaligned_is_atomic?%%<N>(physical_address)) {
  %%LINK%func;raise;raise%%(ExceptionCode::StoreAmoAddressMisaligned, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), virtual_address);
}
if (N == 32) {
  return %%LINK%func;atomic_read_modify_write_32;atomic_read_modify_write_32%%(physical_address, value, op);
} else {
  return %%LINK%func;atomic_read_modify_write_64;atomic_read_modify_write_64%%(physical_address, value, op);
}

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

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

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

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") {
  %%LINK%func;unpredictable;unpredictable%%("Implementations may set reservation sets of any size, as long as they cover the reserved accessed");
} else {
  %%LINK%func;assert;assert%%(false, "Unexpected LRSC_RESERVATION_STRATEGY");
}
reservation_set_valid = true;
reservation_set_address = physical_address;
reservation_set_address = physical_address & ~MXLEN'h3f;
reservation_set_size = 64;

read_memory_aligned

Read from virtual memory using a known aligned address.

Return Type

 Bits<LEN>

Arguments

 XReg virtual_address, Bits<INSTR_ENC_SIZE> encoding
  • Original

  • Pruned

TranslationResult result;
if (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1) {
  result = %%LINK%func;translate;translate%%(virtual_address, MemoryOperation::Read, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), encoding);
} else {
  result.paddr = virtual_address;
}
%%LINK%func;access_check;access_check%%(result.paddr, LEN, virtual_address, MemoryOperation::Read, ExceptionCode::LoadAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%());
return %%LINK%func;read_physical_memory;read_physical_memory%%<LEN>(result.paddr);
TranslationResult result;
if (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1) {
  result = %%LINK%func;translate;translate%%(virtual_address, MemoryOperation::Read, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), encoding);
} else {
  result.paddr = virtual_address;
}
%%LINK%func;access_check;access_check%%(result.paddr, LEN, virtual_address, MemoryOperation::Read, ExceptionCode::LoadAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%());
return %%LINK%func;read_physical_memory;read_physical_memory%%<LEN>(result.paddr);

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

 Bits<N>

Arguments

 Bits<MXLEN> virtual_address, Bits<1>    aq, Bits<1>    rl, Bits<INSTR_ENC_SIZE> encoding
  • Original

  • Pruned

Bits<PHYS_ADDR_WIDTH> physical_address = (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1) ? %%LINK%func;translate;translate%%(virtual_address, MemoryOperation::Read, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), encoding).paddr : virtual_address;
if (%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::RsrvNone, physical_address, N)) {
  %%LINK%func;raise;raise%%(ExceptionCode::LoadAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), virtual_address);
}
if (aq == 1) {
  %%LINK%func;memory_model_acquire;memory_model_acquire%%();
}
if (rl == 1) {
  %%LINK%func;memory_model_release;memory_model_release%%();
}
%%LINK%func;register_reservation_set;register_reservation_set%%(physical_address, N);
if (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1 && LRSC_FAIL_ON_VA_SYNONYM) {
  reservation_virtual_address = virtual_address;
}
return %%LINK%func;read_memory_aligned;read_memory_aligned%%<N>(physical_address, encoding);
Bits<PHYS_ADDR_WIDTH> physical_address = (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1) ? %%LINK%func;translate;translate%%(virtual_address, MemoryOperation::Read, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), encoding).paddr : virtual_address;
if (%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::RsrvNone, physical_address, N)) {
  %%LINK%func;raise;raise%%(ExceptionCode::LoadAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), virtual_address);
}
if (aq == 1) {
  %%LINK%func;memory_model_acquire;memory_model_acquire%%();
}
if (rl == 1) {
  %%LINK%func;memory_model_release;memory_model_release%%();
}
%%LINK%func;register_reservation_set;register_reservation_set%%(physical_address, N);
if (false) {
  reservation_virtual_address = virtual_address;
}
return %%LINK%func;read_memory_aligned;read_memory_aligned%%<N>(physical_address, encoding);

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;

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

 XReg paddr, Bits<len> value
  • Original

  • Pruned

if (len == 8) {
  %%LINK%func;write_physical_memory_8;write_physical_memory_8%%(paddr, value);
} else if (len == 16) {
  %%LINK%func;write_physical_memory_16;write_physical_memory_16%%(paddr, value);
} else if (len == 32) {
  %%LINK%func;write_physical_memory_32;write_physical_memory_32%%(paddr, value);
} else if (len == 64) {
  %%LINK%func;write_physical_memory_64;write_physical_memory_64%%(paddr, value);
} else {
  %%LINK%func;assert;assert%%(false, "Invalid len");
}
if (len == 8) {
  %%LINK%func;write_physical_memory_8;write_physical_memory_8%%(paddr, value);
} else if (len == 16) {
  %%LINK%func;write_physical_memory_16;write_physical_memory_16%%(paddr, value);
} else if (len == 32) {
  %%LINK%func;write_physical_memory_32;write_physical_memory_32%%(paddr, value);
} else if (len == 64) {
  %%LINK%func;write_physical_memory_64;write_physical_memory_64%%(paddr, value);
} else {
  %%LINK%func;assert;assert%%(false, "Invalid len");
}

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

 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 = (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1) ? %%LINK%func;translate;translate%%(virtual_address, MemoryOperation::Write, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), encoding).paddr : virtual_address;
if (%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::RsrvNone, physical_address, N)) {
  %%LINK%func;raise;raise%%(ExceptionCode::StoreAmoAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), virtual_address);
}
%%LINK%func;access_check;access_check%%(physical_address, N, virtual_address, MemoryOperation::Write, ExceptionCode::StoreAmoAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%());
if (aq == 1) {
  %%LINK%func;memory_model_acquire;memory_model_acquire%%();
}
if (rl == 1) {
  %%LINK%func;memory_model_release;memory_model_release%%();
}
if (reservation_set_valid == false) {
  return false;
}
if (!%%LINK%func;contains?;contains?%%(reservation_set_address, reservation_set_size, physical_address, N)) {
  %%LINK%func;invalidate_reservation_set;invalidate_reservation_set%%();
  return false;
}
if (LRSC_FAIL_ON_NON_EXACT_LRSC) {
  if (reservation_physical_address != physical_address || reservation_size != N) {
    %%LINK%func;invalidate_reservation_set;invalidate_reservation_set%%();
    return false;
  }
}
if (LRSC_FAIL_ON_VA_SYNONYM) {
  if (reservation_virtual_address != virtual_address || reservation_size != N) {
    %%LINK%func;invalidate_reservation_set;invalidate_reservation_set%%();
    return false;
  }
}
%%LINK%func;write_physical_memory;write_physical_memory%%<N>(physical_address, value);
return true;
Bits<PHYS_ADDR_WIDTH> physical_address = (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1) ? %%LINK%func;translate;translate%%(virtual_address, MemoryOperation::Write, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), encoding).paddr : virtual_address;
if (%%LINK%func;pma_applies?;pma_applies?%%(PmaAttribute::RsrvNone, physical_address, N)) {
  %%LINK%func;raise;raise%%(ExceptionCode::StoreAmoAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), virtual_address);
}
%%LINK%func;access_check;access_check%%(physical_address, N, virtual_address, MemoryOperation::Write, ExceptionCode::StoreAmoAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%());
if (aq == 1) {
  %%LINK%func;memory_model_acquire;memory_model_acquire%%();
}
if (rl == 1) {
  %%LINK%func;memory_model_release;memory_model_release%%();
}
if (reservation_set_valid == false) {
  return false;
}
if (!%%LINK%func;contains?;contains?%%(reservation_set_address, reservation_set_size, physical_address, N)) {
  %%LINK%func;invalidate_reservation_set;invalidate_reservation_set%%();
  return false;
}


%%LINK%func;write_physical_memory;write_physical_memory%%<N>(physical_address, value);
return true;

write_physical_memory_32 (builtin)

Write four bytes to physical memory.

Return Type

 void

Arguments

 XReg paddr, Bits<32> value

highest_set_bit

Returns the position of the highest (nearest MSB) bit that is '1', or -1 if value is zero.

Return Type

 XReg

Arguments

 XReg value
  • Original

  • Pruned

for (U32 i = %%LINK%func;xlen;xlen%%() - 1; i >= 0; i--) {
  if (value[i] == 1) {
    return i;
  }
}
return -'sd1;
for (U32 i = %%LINK%func;xlen;xlen%%() - 1; i >= 0; i--) {
  if (value[i] == 1) {
    return i;
  }
}
return -'sd1;

lowest_set_bit

Returns the position of the lowest (nearest LSB) bit that is '1', or XLEN if value is zero.

Return Type

 XReg

Arguments

 XReg value
  • Original

  • Pruned

for (U32 i = 0; i < %%LINK%func;xlen;xlen%%(); i++) {
  if (value[i] == 1) {
    return i;
  }
}
return %%LINK%func;xlen;xlen%%();
for (U32 i = 0; i < %%LINK%func;xlen;xlen%%(); i++) {
  if (value[i] == 1) {
    return i;
  }
}
return %%LINK%func;xlen;xlen%%();

creg2reg

Maps a C register index (e.g., rs1' in the specification) to an X register index. From the specification:

Table 1. Registers specified by the three-bit rs1′, rs2′, and rd′ fields of the CIW, CL, CS, CA, and CB formats.

RVC Register Number

Integer Register Number

Integer Register ABI Name

Floating-Point Register Number

Floating-Point Register ABI Name

000

001

010

011

100

101

110

111

x8

x9

x10

x11

x12

x13

x14

x15

s0

s1

a0

a1

a2

a3

a4

a5

f8

f9

f10

f11

f12

f13

f14

f15

fs0

fs1

fa0

fa1

fa2

fa3

fa4

fa5

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 == MXLEN) {
  return value;
} else {
  Bits<1> sign = value[first_extended_bit - 1];
  for (U32 i = 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 (%%LINK%func;implemented?;implemented?%%(ExtensionName::C) && (%%LINK%csr_field;misa.C;CSR[misa].C%% == 0x1)) {
  return 16;
} else {
  return 32;
}
if ((%%LINK%csr_field;misa.C;CSR[misa].C%% == 0x1)) {
  return 16;
} else {
  return 32;
}

jump

Jump to virtual address target_addr.

If target address is misaligned, raise a MisalignedAddress exception.

Return Type

 void

Arguments

 XReg target_addr
  • Original

  • Pruned

if ((%%LINK%func;ialign;ialign%%() == 16) && target_addr & 0x1) != 0 {
  %%LINK%func;raise;raise%%(ExceptionCode::InstructionAddressMisaligned, %%LINK%func;mode;mode%%(), target_addr);
} else if ((%%LINK%func;ialign;ialign%%() == 32) && (target_addr & 0x3) != 0) {
  %%LINK%func;raise;raise%%(ExceptionCode::InstructionAddressMisaligned, %%LINK%func;mode;mode%%(), target_addr);
}
$pc = target_addr;
if ((%%LINK%func;ialign;ialign%%() == 16) && target_addr & 0x1) != 0 {
  %%LINK%func;raise;raise%%(ExceptionCode::InstructionAddressMisaligned, %%LINK%func;mode;mode%%(), target_addr);
} else if ((%%LINK%func;ialign;ialign%%() == 32) && (target_addr & 0x3) != 0) {
  %%LINK%func;raise;raise%%(ExceptionCode::InstructionAddressMisaligned, %%LINK%func;mode;mode%%(), target_addr);
}
$pc = target_addr;

eei_ebreak (builtin)

When TRAP_ON_EBREAK is false, this function will be called to emulate the EEI handling of EBREAK

If TRAP_ON_EBREAK is true, this function will never be called, and does not need to be provided (if pruning is applied to IDL).

Return Type

 void

Arguments

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

%%LINK%func;assert;assert%%((target_hw_addr & 0x1) == 0x0, "Expected halfword-aligned address in jump_halfword");
if (%%LINK%func;ialign;ialign%%() != 16) {
  if ((target_hw_addr & 0x3) != 0) {
    %%LINK%func;raise;raise%%(ExceptionCode::InstructionAddressMisaligned, %%LINK%func;mode;mode%%(), target_hw_addr);
  }
}
$pc = target_hw_addr;
%%LINK%func;assert;assert%%((target_hw_addr & 0x1) == 0x0, "Expected halfword-aligned address in jump_halfword");
if (%%LINK%func;ialign;ialign%%() != 16) {
  if ((target_hw_addr & 0x3) != 0) {
    %%LINK%func;raise;raise%%(ExceptionCode::InstructionAddressMisaligned, %%LINK%func;mode;mode%%(), target_hw_addr);
  }
}
$pc = target_hw_addr;

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

 Bits<LEN>

Arguments

 XReg virtual_address, Bits<INSTR_ENC_SIZE> encoding
  • Original

  • Pruned

Boolean aligned = %%LINK%func;is_naturally_aligned;is_naturally_aligned%%<LEN>(virtual_address);
XReg physical_address;
if (aligned) {
  return %%LINK%func;read_memory_aligned;read_memory_aligned%%<LEN>(virtual_address, encoding);
}
if (MISALIGNED_MAX_ATOMICITY_GRANULE_SIZE > 0) {
  %%LINK%func;assert;assert%%(MISALIGNED_LDST_EXCEPTION_PRIORITY == "low", "Invalid config: can't mix low-priority misaligned exceptions with large atomicity granule");
  physical_address = (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1) ? %%LINK%func;translate;translate%%(virtual_address, MemoryOperation::Read, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), encoding).paddr : virtual_address;
  if (%%LINK%func;misaligned_is_atomic?;misaligned_is_atomic?%%<LEN>(physical_address)) {
    %%LINK%func;access_check;access_check%%(physical_address, LEN, virtual_address, MemoryOperation::Read, ExceptionCode::LoadAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%());
    return %%LINK%func;read_physical_memory;read_physical_memory%%<LEN>(physical_address);
  }
}
if (!MISALIGNED_LDST) {
  if (MISALIGNED_LDST_EXCEPTION_PRIORITY == "low") {
    physical_address = (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1) ? %%LINK%func;translate;translate%%(virtual_address, MemoryOperation::Read, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), encoding).paddr : virtual_address;
    %%LINK%func;access_check;access_check%%(physical_address, LEN, virtual_address, MemoryOperation::Read, ExceptionCode::LoadAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%());
  }
  %%LINK%func;raise;raise%%(ExceptionCode::LoadAddressMisaligned, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), virtual_address);
} else {
  if (MISALIGNED_SPLIT_STRATEGY == "by_byte") {
    Bits<LEN> result = 0;
    for (U32 i = 0; i <= (LEN / 8); i++) {
      result = result | (%%LINK%func;read_memory_aligned;read_memory_aligned%%<8>(virtual_address + i, encoding) << (8 * i));
    }
    return result;
  } else if (MISALIGNED_SPLIT_STRATEGY == "custom") {
    %%LINK%func;unpredictable;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 = %%LINK%func;is_naturally_aligned;is_naturally_aligned%%<LEN>(virtual_address);
XReg physical_address;
if (aligned) {
  return %%LINK%func;read_memory_aligned;read_memory_aligned%%<LEN>(virtual_address, encoding);
}

Bits<LEN> result = 0;
for (U32 i = 0; i <= (LEN / 8); i++) {
  result = result | (%%LINK%func;read_memory_aligned;read_memory_aligned%%<8>(virtual_address + i, encoding) << (8));
}
return result;

write_memory_aligned

Write to virtual memory using a known aligned address.

Return Type

 void

Arguments

 XReg virtual_address, Bits<LEN> value, Bits<INSTR_ENC_SIZE> encoding
  • Original

  • Pruned

XReg physical_address;
physical_address = (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1) ? %%LINK%func;translate;translate%%(virtual_address, MemoryOperation::Write, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), encoding).paddr : virtual_address;
%%LINK%func;access_check;access_check%%(physical_address, LEN, virtual_address, MemoryOperation::Write, ExceptionCode::StoreAmoAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%());
%%LINK%func;write_physical_memory;write_physical_memory%%<LEN>(physical_address, value);
XReg physical_address;
physical_address = (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1) ? %%LINK%func;translate;translate%%(virtual_address, MemoryOperation::Write, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), encoding).paddr : virtual_address;
%%LINK%func;access_check;access_check%%(physical_address, LEN, virtual_address, MemoryOperation::Write, ExceptionCode::StoreAmoAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%());
%%LINK%func;write_physical_memory;write_physical_memory%%<LEN>(physical_address, value);

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

 XReg virtual_address, Bits<LEN> value, Bits<INSTR_ENC_SIZE> encoding
  • Original

  • Pruned

Boolean aligned = %%LINK%func;is_naturally_aligned;is_naturally_aligned%%<LEN>(virtual_address);
XReg physical_address;
if (aligned) {
  %%LINK%func;write_memory_aligned;write_memory_aligned%%<LEN>(virtual_address, value, encoding);
  return ;
}
if (MISALIGNED_MAX_ATOMICITY_GRANULE_SIZE > 0) {
  %%LINK%func;assert;assert%%(MISALIGNED_LDST_EXCEPTION_PRIORITY == "low", "Invalid config: can't mix low-priority misaligned exceptions with large atomicity granule");
  physical_address = (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1) ? %%LINK%func;translate;translate%%(virtual_address, MemoryOperation::Write, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), encoding).paddr : virtual_address;
  if (%%LINK%func;misaligned_is_atomic?;misaligned_is_atomic?%%<LEN>(physical_address)) {
    %%LINK%func;access_check;access_check%%(physical_address, LEN, virtual_address, MemoryOperation::Write, ExceptionCode::StoreAmoAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%());
    %%LINK%func;write_physical_memory;write_physical_memory%%<LEN>(physical_address, value);
    return ;
  }
}
if (!MISALIGNED_LDST) {
  if (MISALIGNED_LDST_EXCEPTION_PRIORITY == "low") {
    physical_address = (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1) ? %%LINK%func;translate;translate%%(virtual_address, MemoryOperation::Write, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), encoding).paddr : virtual_address;
    %%LINK%func;access_check;access_check%%(physical_address, LEN, virtual_address, MemoryOperation::Write, ExceptionCode::StoreAmoAccessFault, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%());
  }
  %%LINK%func;raise;raise%%(ExceptionCode::StoreAmoAddressMisaligned, %%LINK%func;effective_ldst_mode;effective_ldst_mode%%(), virtual_address);
} else {
  if (MISALIGNED_SPLIT_STRATEGY == "by_byte") {
    for (U32 i = 0; i <= (LEN / 8); i++) {
      %%LINK%func;write_memory_aligned;write_memory_aligned%%<8>(virtual_address + i, (value >> (8 * i))[7:0], encoding);
    }
  } else if (MISALIGNED_SPLIT_STRATEGY == "custom") {
    %%LINK%func;unpredictable;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 = %%LINK%func;is_naturally_aligned;is_naturally_aligned%%<LEN>(virtual_address);
XReg physical_address;
if (aligned) {
  %%LINK%func;write_memory_aligned;write_memory_aligned%%<LEN>(virtual_address, value, encoding);
  return ;
}

for (U32 i = 0; i <= (LEN / 8); i++) {
  %%LINK%func;write_memory_aligned;write_memory_aligned%%<8>(virtual_address + i, (value >> (8))[7:0], encoding);
}

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
  • Original

  • Pruned

if (MUTABLE_MISA_F && %%LINK%csr_field;misa.F;CSR[misa].F%% == 0) {
  %%LINK%func;raise;raise%%(ExceptionCode::IllegalInstruction, %%LINK%func;mode;mode%%(), encoding);
}
if (%%LINK%csr_field;mstatus.FS;CSR[mstatus].FS%% == 0) {
  %%LINK%func;raise;raise%%(ExceptionCode::IllegalInstruction, %%LINK%func;mode;mode%%(), encoding);
}
if (%%LINK%csr_field;mstatus.FS;CSR[mstatus].FS%% == 0) {
  %%LINK%func;raise;raise%%(ExceptionCode::IllegalInstruction, %%LINK%func;mode;mode%%(), 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, %%LINK%csr_field;fcsr.FRM;CSR[fcsr].FRM%%);
} else {
  %%LINK%func;raise;raise%%(ExceptionCode::IllegalInstruction, %%LINK%func;mode;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, %%LINK%csr_field;fcsr.FRM;CSR[fcsr].FRM%%);
} else {
  %%LINK%func;raise;raise%%(ExceptionCode::IllegalInstruction, %%LINK%func;mode;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];

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];

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);

set_fp_flag

Add flag to the sticky flags bits in CSR[fcsr]

Return Type

 void

Arguments

 FpFlag flag
  • Original

  • Pruned

if (flag == FpFlag::NX) {
  %%LINK%csr_field;fcsr.NX;CSR[fcsr].NX%% = 1;
} else if (flag == FpFlag::UF) {
  %%LINK%csr_field;fcsr.UF;CSR[fcsr].UF%% = 1;
} else if (flag == FpFlag::OF) {
  %%LINK%csr_field;fcsr.OF;CSR[fcsr].OF%% = 1;
} else if (flag == FpFlag::DZ) {
  %%LINK%csr_field;fcsr.DZ;CSR[fcsr].DZ%% = 1;
} else if (flag == FpFlag::NV) {
  %%LINK%csr_field;fcsr.NV;CSR[fcsr].NV%% = 1;
}
if (flag == FpFlag::NX) {
  %%LINK%csr_field;fcsr.NX;CSR[fcsr].NX%% = 1;
} else if (flag == FpFlag::UF) {
  %%LINK%csr_field;fcsr.UF;CSR[fcsr].UF%% = 1;
} else if (flag == FpFlag::OF) {
  %%LINK%csr_field;fcsr.OF;CSR[fcsr].OF%% = 1;
} else if (flag == FpFlag::DZ) {
  %%LINK%csr_field;fcsr.DZ;CSR[fcsr].DZ%% = 1;
} else if (flag == FpFlag::NV) {
  %%LINK%csr_field;fcsr.NV;CSR[fcsr].NV%% = 1;
}

softfloat_propagateNaNF32UI

Interpreting 'a' and 'b' as the bit patterns of two 32-bit floating- | point values, at least one of which is a NaN, returns the bit pattern of | the combined NaN result. If either 'a' or 'b' has the pattern of a | signaling NaN, the invalid exception is raised.

Return Type

 U32

Arguments

 U32 a, U32 b
  • Original

  • Pruned

Boolean isSigNaN_a = %%LINK%func;is_sp_signaling_nan?;is_sp_signaling_nan?%%(a);
Boolean isSigNaN_b = %%LINK%func;is_sp_signaling_nan?;is_sp_signaling_nan?%%(b);
if (isSigNaN_a || isSigNaN_b) {
  %%LINK%func;set_fp_flag;set_fp_flag%%(FpFlag::NV);
}
return SP_CANONICAL_NAN;
Boolean isSigNaN_a = %%LINK%func;is_sp_signaling_nan?;is_sp_signaling_nan?%%(a);
Boolean isSigNaN_b = %%LINK%func;is_sp_signaling_nan?;is_sp_signaling_nan?%%(b);
if (isSigNaN_a || isSigNaN_b) {
  %%LINK%func;set_fp_flag;set_fp_flag%%(FpFlag::NV);
}
return SP_CANONICAL_NAN;

packToF32UI

Pack components into a 32-bit value

Return Type

 Bits<32>

Arguments

 Bits<1> sign, Bits<8> exp, Bits<23> sig
  • Original

  • Pruned

return {sign, exp, sig};
return {sign, exp, sig};

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

 Bits<bit_length(N)>

Arguments

 Bits<N> 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;

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 & 31 != 0) ? 1 : 0) : ((a != 0) ? 1 : 0);
return (dist < 31) ? a >> dist | (a << (-dist & 31 != 0) ? 1 : 0) : ((a != 0) ? 1 : 0);

softfloat_roundPackToF32

Round FP value according to mdode and then pack it in IEEE format.

Return Type

 Bits<32>

Arguments

 Bits<1> sign, Bits<8> exp, Bits<23> 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) < 0) {
    Boolean isTiny = ($signed(exp) < -8's1) || (sig + roundIncrement < 0x80000000);
    sig = %%LINK%func;softfloat_shiftRightJam32;softfloat_shiftRightJam32%%(sig, -exp);
    exp = 0;
    roundBits = sig & 0x7F;
    if (isTiny && (roundBits != 0)) {
      %%LINK%func;set_fp_flag;set_fp_flag%%(FpFlag::UF);
    }
  } else if (0xFD < $signed(exp) || (0x80000000 <= sig + roundIncrement)) {
    %%LINK%func;set_fp_flag;set_fp_flag%%(FpFlag::OF);
    %%LINK%func;set_fp_flag;set_fp_flag%%(FpFlag::NX);
    return %%LINK%func;packToF32UI;packToF32UI%%(sign, 0xFF, 0) - roundIncrement == 0) ? 1 : 0);   } } sig = (sig + roundIncrement);
if (sig == 0) {
  exp = 0;
}
return %%LINK%func;packToF32UI;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) < 0) {
    Boolean isTiny = ($signed(exp) < -8's1) || (sig + roundIncrement < 0x80000000);
    sig = %%LINK%func;softfloat_shiftRightJam32;softfloat_shiftRightJam32%%(sig, -exp);
    exp = 0;
    roundBits = sig & 0x7F;
    if (isTiny && (roundBits != 0)) {
      %%LINK%func;set_fp_flag;set_fp_flag%%(FpFlag::UF);
    }
  } else if ((0x80000000 <= sig + roundIncrement)) {
    %%LINK%func;set_fp_flag;set_fp_flag%%(FpFlag::OF);
    %%LINK%func;set_fp_flag;set_fp_flag%%(FpFlag::NX);
    return %%LINK%func;packToF32UI;packToF32UI%%(sign, 0xFF, 0) - roundIncrement == 0) ? 1 : 0);   } } sig = (sig + roundIncrement);
if (sig == 0) {
  exp = 0;
}
return %%LINK%func;packToF32UI;packToF32UI%%(sign, exp, sig);

softfloat_normRoundPackToF32

Normalize, round, and pack into a 32-bit floating point value

Return Type

 Bits<32>

Arguments

 Bits<1> sign, Bits<8> exp, Bits<23> sig, RoundingMode mode
  • Original

  • Pruned

Bits<8> shiftDist = %%LINK%func;count_leading_zeros;count_leading_zeros%%<32>(sig) - 1;
exp = exp - shiftDist;
if ((7 <= shiftDist) && (exp < 0xFD)) {
  return %%LINK%func;packToF32UI;packToF32UI%%(sign, (sig != 0) ? exp : 0, sig << (shiftDist - 7));
} else {
  return %%LINK%func;softfloat_roundPackToF32;softfloat_roundPackToF32%%(sign, exp, sig << shiftDist, mode);
}
Bits<8> shiftDist = %%LINK%func;count_leading_zeros;count_leading_zeros%%<32>(sig) - 1;
exp = exp - shiftDist;
if ((7 <= shiftDist) && (exp < 0xFD)) {
  return %%LINK%func;packToF32UI;packToF32UI%%(sign, (sig != 0) ? exp : 0, sig << (shiftDist - 7));
} else {
  return %%LINK%func;softfloat_roundPackToF32;softfloat_roundPackToF32%%(sign, exp, sig << shiftDist, 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

Bits<8> expA = %%LINK%func;expF32UI;expF32UI%%(a);
Bits<23> sigA = %%LINK%func;fracF32UI;fracF32UI%%(a);
Bits<8> expB = %%LINK%func;expF32UI;expF32UI%%(b);
Bits<23> sigB = %%LINK%func;fracF32UI;fracF32UI%%(b);
U32 sigZ;
U32 z;
Bits<1> signZ;
Bits<8> expZ;
U32 sigDiff;
U32 sigX;
U32 sigY;
U32 sigA_32;
U32 sigB_32;
Bits<8> shiftDist;
Bits<8> expDiff = expA - expB;
if (expDiff == 8'd0) {
  if (expA == 8'hFF) {
    if ((sigA != 8'd0) || (sigB != 8'd0)) {
      return %%LINK%func;softfloat_propagateNaNF32UI;softfloat_propagateNaNF32UI%%(a, b);
    }
    return a;
  }
  sigDiff = sigA - sigB;
  if (sigDiff == 0) {
    return %%LINK%func;packToF32UI;packToF32UI%%(((mode == RoundingMode::RDN) ? 1 : 0), 0, 0);
  }
  if (expA != 0) {
    expA = expA - 1;
  }
  signZ = %%LINK%func;signF32UI;signF32UI%%(a);
  if (sigDiff < 0) {
    signZ = ~signZ;
    sigDiff = -32'sh1 * sigDiff;
  }
  shiftDist = %%LINK%func;count_leading_zeros;count_leading_zeros%%<32>(sigDiff) - 8;
  expZ = expA - shiftDist;
  if (expZ < 0) {
    shiftDist = expA;
    expZ = 0;
  }
  return %%LINK%func;packToF32UI;packToF32UI%%(signZ, expZ, sigDiff << shiftDist);
} else {
  signZ = %%LINK%func;signF32UI;signF32UI%%(a);
  sigA_32 = 32'h0 + (sigA << 7);
  sigB_32 = 32'h0 + (sigB << 7);
  if (expDiff < 0) {
    signZ = ~signZ;
    if (expB == 0xFF) {
      if (sigB_32 != 0) {
        return %%LINK%func;softfloat_propagateNaNF32UI;softfloat_propagateNaNF32UI%%(a, b);
      }
      return %%LINK%func;packToF32UI;packToF32UI%%(signZ, expB, 0);
    }
    expZ = expB - 1;
    sigX = sigB_32 | 0x40000000;
    sigY = sigA_32 + ((expA != 0) ? 0x40000000 : sigA_32);
    expDiff = -expDiff;
  } else {
    if (expA == 0xFF) {
      if (sigA_32 != 0) {
        return %%LINK%func;softfloat_propagateNaNF32UI;softfloat_propagateNaNF32UI%%(a, b);
      }
      return a;
    }
    expZ = expA - 1;
    sigX = sigA_32 | 0x40000000;
    sigY = sigB_32 + ((expB != 0) ? 0x40000000 : sigB_32);
  }
  return %%LINK%func;softfloat_normRoundPackToF32;softfloat_normRoundPackToF32%%(signZ, expZ, sigX - %%LINK%func;softfloat_shiftRightJam32;softfloat_shiftRightJam32%%(sigY, expDiff), mode);
}
Bits<8> expA = %%LINK%func;expF32UI;expF32UI%%(a);
Bits<23> sigA = %%LINK%func;fracF32UI;fracF32UI%%(a);
Bits<8> expB = %%LINK%func;expF32UI;expF32UI%%(b);
Bits<23> sigB = %%LINK%func;fracF32UI;fracF32UI%%(b);
U32 sigZ;
U32 z;
Bits<1> signZ;
Bits<8> expZ;
U32 sigDiff;
U32 sigX;
U32 sigY;
U32 sigA_32;
U32 sigB_32;
Bits<8> shiftDist;
Bits<8> expDiff = expA - expB;
if (expDiff == 8'd0) {
  if (expA == 8'hFF) {
    if ((sigA != 8'd0) || (sigB != 8'd0)) {
      return %%LINK%func;softfloat_propagateNaNF32UI;softfloat_propagateNaNF32UI%%(a, b);
    }
    return a;
  }
  sigDiff = sigA - sigB;
  if (sigDiff == 0) {
    return %%LINK%func;packToF32UI;packToF32UI%%(((mode == RoundingMode::RDN) ? 1 : 0), 0, 0);
  }
  if (expA != 0) {
    expA = expA - 1;
  }
  signZ = %%LINK%func;signF32UI;signF32UI%%(a);
  if (sigDiff < 0) {
    signZ = ~signZ;
    sigDiff = -32'sh1 * sigDiff;
  }
  shiftDist = %%LINK%func;count_leading_zeros;count_leading_zeros%%<32>(sigDiff) - 8;
  expZ = expA - shiftDist;
  if (expZ < 0) {
    shiftDist = expA;
    expZ = 0;
  }
  return %%LINK%func;packToF32UI;packToF32UI%%(signZ, expZ, sigDiff << shiftDist);
} else {
  signZ = %%LINK%func;signF32UI;signF32UI%%(a);
  sigA_32 = 32'h0 + (sigA << 7);
  sigB_32 = 32'h0 + (sigB << 7);
  if (expDiff < 0) {
    signZ = ~signZ;
    if (expB == 0xFF) {
      if (sigB_32 != 0) {
        return %%LINK%func;softfloat_propagateNaNF32UI;softfloat_propagateNaNF32UI%%(a, b);
      }
      return %%LINK%func;packToF32UI;packToF32UI%%(signZ, expB, 0);
    }
    expZ = expB - 1;
    sigX = sigB_32 | 0x40000000;
    sigY = sigA_32 + ((expA != 0) ? 0x40000000 : sigA_32);
    expDiff = -expDiff;
  } else {
    if (expA == 0xFF) {
      if (sigA_32 != 0) {
        return %%LINK%func;softfloat_propagateNaNF32UI;softfloat_propagateNaNF32UI%%(a, b);
      }
      return a;
    }
    expZ = expA - 1;
    sigX = sigA_32 | 0x40000000;
    sigY = sigB_32 + ((expB != 0) ? 0x40000000 : sigB_32);
  }
  return %%LINK%func;softfloat_normRoundPackToF32;softfloat_normRoundPackToF32%%(signZ, expZ, sigX - %%LINK%func;softfloat_shiftRightJam32;softfloat_shiftRightJam32%%(sigY, expDiff), mode);
}

softfloat_addMagsF32

Returns sum of the magnitudes of 2 floating point numbers

Return Type

 U32

Arguments

 U32 a, U32 b, RoundingMode mode
  • Original

  • Pruned

Bits<8> expA = %%LINK%func;expF32UI;expF32UI%%(a);
Bits<23> sigA = %%LINK%func;fracF32UI;fracF32UI%%(a);
Bits<8> expB = %%LINK%func;expF32UI;expF32UI%%(b);
Bits<23> sigB = %%LINK%func;fracF32UI;fracF32UI%%(b);
U32 sigZ;
U32 z;
Bits<1> signZ;
Bits<8> expZ;
Bits<8> expDiff = expA - expB;
if (expDiff == 8'd0) {
  if (expA == 8'd0) {
    z = a + b;
    return z;
  }
  if (expA == 8'hFF) {
    if ((sigA != 8'd0) || (sigB != 8'd0)) {
      return %%LINK%func;softfloat_propagateNaNF32UI;softfloat_propagateNaNF32UI%%(a, b);
    }
    return a;
  }
  signZ = %%LINK%func;signF32UI;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 = %%LINK%func;signF32UI;signF32UI%%(a);
  U32 sigA_32 = 32'h0 + (sigA << 6);
  U32 sigB_32 = 32'h0 + (sigA << 6);
  if (expDiff < 0) {
    if (expB == 8'hFF) {
      if (sigB != 0) {
        return %%LINK%func;softfloat_propagateNaNF32UI;softfloat_propagateNaNF32UI%%(a, b);
      }
      return %%LINK%func;packToF32UI;packToF32UI%%(signZ, 8'hFF, 23'h0);
    }
    expZ = expB;
    sigA_32 = (expA == 0) ? 2 * sigA_32 : (sigA_32 + 0x20000000);
    sigA_32 = %%LINK%func;softfloat_shiftRightJam32;softfloat_shiftRightJam32%%(sigA_32, (32'h0 - expDiff));
  } else {
    if (expA == 8'hFF) {
      if (sigA != 0) {
        return %%LINK%func;softfloat_propagateNaNF32UI;softfloat_propagateNaNF32UI%%(a, b);
      }
      return a;
    }
    expZ = expA;
    sigB_32 = (expB == 0) ? 2 * sigB_32 : (sigB_32 + 0x20000000);
    sigB_32 = %%LINK%func;softfloat_shiftRightJam32;softfloat_shiftRightJam32%%(sigB_32, (32'h0 + expDiff));
  }
  U32 sigZ = 0x20000000 + sigA + sigB;
  if (sigZ < 0x40000000) {
    expZ = expZ - 1;
    sigZ = sigZ << 1;
  }
}
return %%LINK%func;softfloat_roundPackToF32;softfloat_roundPackToF32%%(signZ, expZ, sigZ[22:0], mode);
Bits<8> expA = %%LINK%func;expF32UI;expF32UI%%(a);
Bits<23> sigA = %%LINK%func;fracF32UI;fracF32UI%%(a);
Bits<8> expB = %%LINK%func;expF32UI;expF32UI%%(b);
Bits<23> sigB = %%LINK%func;fracF32UI;fracF32UI%%(b);
U32 sigZ;
U32 z;
Bits<1> signZ;
Bits<8> expZ;
Bits<8> expDiff = expA - expB;
if (expDiff == 8'd0) {
  if (expA == 8'd0) {
    z = a + b;
    return z;
  }
  if (expA == 8'hFF) {
    if ((sigA != 8'd0) || (sigB != 8'd0)) {
      return %%LINK%func;softfloat_propagateNaNF32UI;softfloat_propagateNaNF32UI%%(a, b);
    }
    return a;
  }
  signZ = %%LINK%func;signF32UI;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 = %%LINK%func;signF32UI;signF32UI%%(a);
  U32 sigA_32 = 32'h0 + (sigA << 6);
  U32 sigB_32 = 32'h0 + (sigA << 6);
  if (expDiff < 0) {
    if (expB == 8'hFF) {
      if (sigB != 0) {
        return %%LINK%func;softfloat_propagateNaNF32UI;softfloat_propagateNaNF32UI%%(a, b);
      }
      return %%LINK%func;packToF32UI;packToF32UI%%(signZ, 8'hFF, 23'h0);
    }
    expZ = expB;
    sigA_32 = (expA == 0) ? 2 * sigA_32 : (sigA_32 + 0x20000000);
    sigA_32 = %%LINK%func;softfloat_shiftRightJam32;softfloat_shiftRightJam32%%(sigA_32, (32'h0 - expDiff));
  } else {
    if (expA == 8'hFF) {
      if (sigA != 0) {
        return %%LINK%func;softfloat_propagateNaNF32UI;softfloat_propagateNaNF32UI%%(a, b);
      }
      return a;
    }
    expZ = expA;
    sigB_32 = (expB == 0) ? 2 * sigB_32 : (sigB_32 + 0x20000000);
    sigB_32 = %%LINK%func;softfloat_shiftRightJam32;softfloat_shiftRightJam32%%(sigB_32, (32'h0 + expDiff));
  }
  U32 sigZ = 0x20000000 + sigA + sigB;
  if (sigZ < 0x40000000) {
    expZ = expZ - 1;
    sigZ = sigZ << 1;
  }
}
return %%LINK%func;softfloat_roundPackToF32;softfloat_roundPackToF32%%(signZ, expZ, sigZ[22:0], 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 (%%LINK%func;signF32UI;signF32UI%%(a_xor_b) == 1) {
  return %%LINK%func;softfloat_subMagsF32;softfloat_subMagsF32%%(a, b, mode);
} else {
  return %%LINK%func;softfloat_addMagsF32;softfloat_addMagsF32%%(a, b, mode);
}
U32 a_xor_b = a ^ b;
if (%%LINK%func;signF32UI;signF32UI%%(a_xor_b) == 1) {
  return %%LINK%func;softfloat_subMagsF32;softfloat_subMagsF32%%(a, b, mode);
} else {
  return %%LINK%func;softfloat_addMagsF32;softfloat_addMagsF32%%(a, b, mode);
}

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 == SP_NEG_INF;

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) && sp_value[22:0] != 0);
return (sp_value[31] == 1) && (sp_value[30:23] != 0b11111111) && !((sp_value[30:23] == 0b00000000) && sp_value[22:0] != 0);

is_sp_neg_subnorm?

Returns true if sp_value is a negative subnormal number.

Return Type

 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 == SP_NEG_ZERO;

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 == SP_POS_ZERO;

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) && sp_value[22:0] != 0);
return (sp_value[31] == 0) && (sp_value[30:23] != 0b11111111) && !((sp_value[30:23] == 0b00000000) && sp_value[22:0] != 0);

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 == SP_POS_INF;

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);

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;

i32_to_f32

Converts 32-bit signed integer to 32-bit floating point

Return Type

 U32

Arguments

 U32 a, RoundingMode mode
  • Original

  • Pruned

Bits<1> sign = a[31];
if ((a & 0x7FFFFFFF) == 0) {
  return (sign == 1) ? %%LINK%func;packToF32UI;packToF32UI%%(1, 0x9E, 0) : %%LINK%func;packToF32UI;packToF32UI%%(0, 0, 0);
}
U32 magnitude_of_A = %%LINK%func;returnMag;returnMag%%(a);
return %%LINK%func;softfloat_normRoundPackToF32;softfloat_normRoundPackToF32%%(sign, 0x9C, magnitude_of_A, mode);
Bits<1> sign = a[31];
if ((a & 0x7FFFFFFF) == 0) {
  return (sign == 1) ? 0xcf000000 : 0;
}
U32 magnitude_of_A = %%LINK%func;returnMag;returnMag%%(a);
return %%LINK%func;softfloat_normRoundPackToF32;softfloat_normRoundPackToF32%%(sign, 0x9C, magnitude_of_A, 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") {
  %%LINK%csr_field;mstatus.FS;CSR[mstatus].FS%% = 3;
} else if (HW_MSTATUS_FS_DIRTY_UPDATE == "imprecise") {
  %%LINK%func;unpredictable;unpredictable%%("The hart may or may not update mstatus.FS now");
}
%%LINK%csr_field;mstatus.FS;CSR[mstatus].FS%% = 3;

ui32_to_f32

Converts 32-bit unsigned integer to 32-bit floating point

Return Type

 U32

Arguments

 U32 a, RoundingMode mode
  • Original

  • Pruned

if (a == 0) {
  return a;
}
if (a[31] == 1) {
  return %%LINK%func;softfloat_roundPackToF32;softfloat_roundPackToF32%%(0, 0x9D, a >> 1 | (a & 1), mode);
} else {
  return %%LINK%func;softfloat_normRoundPackToF32;softfloat_normRoundPackToF32%%(0, 0x9C, a, mode);
}
if (a == 0) {
  return a;
}
if (a[31] == 1) {
  return %%LINK%func;softfloat_roundPackToF32;softfloat_roundPackToF32%%(0, 0x9D, a >> 1 | (a & 1), mode);
} else {
  return %%LINK%func;softfloat_normRoundPackToF32;softfloat_normRoundPackToF32%%(0, 0x9C, a, mode);
}

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 & 63 != 0) ? 1 : 0) : ((a != 0) ? 1 : 0);
return (dist < 63) ? a >> dist | (a << (-dist & 63 != 0) ? 1 : 0) : ((a != 0) ? 1 : 0);

softfloat_roundToI32

Round to unsigned 32-bit integer, using rounding_mode

Return Type

 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) {
  %%LINK%func;set_fp_flag;set_fp_flag%%(FpFlag::NV);
  return sign == 1 ? WORD_NEG_OVERFLOW : WORD_POS_OVERFLOW;
}
Bits<32> sig32 = sig >> 12;
if ((roundBits == 0x800 && (roundingMode == RoundingMode::RNE))) {
  sig32 = sig32 & ~32'b1;
}
Bits<32> z = (sign == 1) ? -sig32 : sig32;
if ((z != 0) && $signed(z) < 0) != (sign == 1) {
  %%LINK%func;set_fp_flag;set_fp_flag%%(FpFlag::NV);
  return sign == 1 ? WORD_NEG_OVERFLOW : WORD_POS_OVERFLOW;
}
if (roundBits != 0) {
  %%LINK%func;set_fp_flag;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) {
  %%LINK%func;set_fp_flag;set_fp_flag%%(FpFlag::NV);
  return sign == 1 ? WORD_NEG_OVERFLOW : WORD_POS_OVERFLOW;
}
Bits<32> sig32 = sig >> 12;
if ((roundBits == 0x800 && (roundingMode == RoundingMode::RNE))) {
  sig32 = sig32 & ~32'b1;
}
Bits<32> z = (sign == 1) ? -sig32 : sig32;
if ((z != 0) && $signed(z) < 0) != (sign == 1) {
  %%LINK%func;set_fp_flag;set_fp_flag%%(FpFlag::NV);
  return sign == 1 ? WORD_NEG_OVERFLOW : WORD_POS_OVERFLOW;
}
if (roundBits != 0) {
  %%LINK%func;set_fp_flag;set_fp_flag%%(FpFlag::NX);
}
return z;

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

 Bits<TO_SIZE>

Arguments

 Bits<FROM_SIZE> from_value
  • Original

  • Pruned

%%LINK%func;assert;assert%%(FROM_SIZE < TO_SIZE, "Bad template arguments; FROM_SIZE must be less than TO_SIZE");
return {{TO_SIZE - FROM_SIZE{1'b1}}, from_value};
%%LINK%func;assert;assert%%(FROM_SIZE < TO_SIZE, "Bad template arguments; FROM_SIZE must be less than TO_SIZE");
return {{TO_SIZE - FROM_SIZE{1'b1}}, from_value};

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 (%%LINK%func;signF32UI;signF32UI%%(a_xor_b) == 1) {
  return %%LINK%func;softfloat_addMagsF32;softfloat_addMagsF32%%(a, b, mode);
} else {
  return %%LINK%func;softfloat_subMagsF32;softfloat_subMagsF32%%(a, b, mode);
}
U32 a_xor_b = a ^ b;
if (%%LINK%func;signF32UI;signF32UI%%(a_xor_b) == 1) {
  return %%LINK%func;softfloat_addMagsF32;softfloat_addMagsF32%%(a, b, mode);
} else {
  return %%LINK%func;softfloat_subMagsF32;softfloat_subMagsF32%%(a, b, mode);
}

eei_ecall_from_m (builtin)

When TRAP_ON_ECALL_FROM_M is false, this function will be called to emulate the EEI handling of ECALL-from-M.

If TRAP_ON_ECALL_FROM_M is true, this function will never be called, and does not need to be provided (if pruning is applied to IDL).

Return Type

 void

Arguments

eei_ecall_from_s (builtin)

When TRAP_ON_ECALL_FROM_S is false, this function will be called to emulate the EEI handling of ECALL-from-S.

If TRAP_ON_ECALL_FROM_S is true, this function will never be called, and does not need to be provided (if pruning is applied to IDL).

Return Type

 void

Arguments

eei_ecall_from_u (builtin)

When TRAP_ON_ECALL_FROM_U is false, this function will be called to emulate the EEI handling of ECALL-from-U.

If TRAP_ON_ECALL_FROM_U is true, this function will never be called, and does not need to be provided (if pruning is applied to IDL).

Return Type

 void

Arguments

eei_ecall_from_vs (builtin)

When TRAP_ON_ECALL_FROM_VS is false, this function will be called to emulate the EEI handling of ECALL-from-VS.

If TRAP_ON_ECALL_FROM_VS is true, this function will never be called, and does not need to be provided (if pruning is applied to IDL).

Return Type

 void

Arguments

fence_tso (builtin)

Execute a TSO memory ordering fence.(according to the FENCE instruction).

Return Type

 void

Arguments

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

virtual_mode?

Returns True if the current mode is virtual (VS or VU).

Return Type

 Boolean

Arguments

  • Original

  • Pruned

return (%%LINK%func;mode;mode%%() == PrivilegeMode::VS) || (%%LINK%func;mode;mode%%() == PrivilegeMode::VU);
return (%%LINK%func;mode;mode%%() == PrivilegeMode::VS) || (%%LINK%func;mode;mode%%() == PrivilegeMode::VU);

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 (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1'b0) {
  return true;
}
SatpMode satp_mode;
if (%%LINK%func;virtual_mode?;virtual_mode?%%()) {
  satp_mode = $enum(SatpMode, %%LINK%csr_field;vsatp.MODE;CSR[vsatp].MODE%%);
} else {
  satp_mode = $enum(SatpMode, %%LINK%csr_field;satp.MODE;CSR[satp].MODE%%);
}
XReg eaddr = %%LINK%func;mask_eaddr;mask_eaddr%%(vaddr);
if (satp_mode == SatpMode::Bare) {
  return true;
} else if (satp_mode == SatpMode::Sv32) {
  return true;
} else if (satp_mode == SatpMode::Sv39) {
  return eaddr[63:39] == {25{eaddr[38]}};
} else if (satp_mode == SatpMode::Sv48) {
  return eaddr[63:48] == {16{eaddr[47]}};
} else if (satp_mode == SatpMode::Sv57) {
  return eaddr[63:57] == {6{eaddr[56]}};
}
if (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1'b0) {
  return true;
}
SatpMode satp_mode;
if (%%LINK%func;virtual_mode?;virtual_mode?%%()) {
  satp_mode = $enum(SatpMode, %%LINK%csr_field;vsatp.MODE;CSR[vsatp].MODE%%);
} else {
  satp_mode = $enum(SatpMode, %%LINK%csr_field;satp.MODE;CSR[satp].MODE%%);
}
XReg eaddr = %%LINK%func;mask_eaddr;mask_eaddr%%(vaddr);
if (satp_mode == SatpMode::Bare) {
  return true;
} else if (satp_mode == SatpMode::Sv32) {
  return true;
} else if (satp_mode == SatpMode::Sv39) {
  return eaddr[63:39] == {25{eaddr[38]}};
} else if (satp_mode == SatpMode::Sv48) {
  return eaddr[63:48] == {16{eaddr[47]}};
} else if (satp_mode == SatpMode::Sv57) {
  return eaddr[63:57] == {6{eaddr[56]}};
}

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

implemented_csr? (generated)

Return true if csr_addr is an implemented CSR

Return Type

 Boolean

Arguments

 Bits<12> csr_addr

csr?

Returns true if csr_addr is an implemented csr, and the defining extension is not disabled

Return Type

 Boolean

Arguments

 Bits<12> csr_addr
  • Original

  • Pruned

if (!%%LINK%func;implemented_csr?;implemented_csr?%%(csr_addr)) {
  return false;
}
if (%%LINK%func;implemented?;implemented?%%(ExtensionName::S) && !CSR[csr_addr].implemented_without?(ExtensionName::S)) {
  return %%LINK%csr_field;misa.S;CSR[misa].S%% == 1'b1;
} else if (%%LINK%func;implemented?;implemented?%%(ExtensionName::U) && !CSR[csr_addr].implemented_without?(ExtensionName::U)) {
  return %%LINK%csr_field;misa.U;CSR[misa].U%% == 1'b1;
} else if (%%LINK%func;implemented?;implemented?%%(ExtensionName::H) && !CSR[csr_addr].implemented_without?(ExtensionName::H)) {
  return %%LINK%csr_field;misa.H;CSR[misa].H%% == 1'b1;
}
return true;
if (!%%LINK%func;implemented_csr?;implemented_csr?%%(csr_addr)) {
  return false;
}
if (!CSR[csr_addr].implemented_without?(ExtensionName::S)) {
  return %%LINK%csr_field;misa.S;CSR[misa].S%% == 1'b1;
} else if (!CSR[csr_addr].implemented_without?(ExtensionName::U)) {
  return %%LINK%csr_field;misa.U;CSR[misa].U%% == 1'b1;
} else if (!CSR[csr_addr].implemented_without?(ExtensionName::H)) {
  return %%LINK%csr_field;misa.H;CSR[misa].H%% == 1'b1;
}
return true;

check_csr

Checks if 'csr_addr' is a valid address, can be read in the current mode, and, if for_write is true, can be written in the current mode.

If the check fails, will either raise IllegalInsruction or cause unpredictable behavior, depending on TRAP_ON_UNIMPLEMENTED_CSR

Return Type

 void

Arguments

 Bits<12> csr_addr, Boolean for_write, Bits<INSTR_ENC_SIZE> encoding
  • Original

  • Pruned

if (!%%LINK%func;csr?;csr?%%(csr_addr)) {
  if (TRAP_ON_UNIMPLEMENTED_CSR) {
    %%LINK%func;raise;raise%%(ExceptionCode::IllegalInstruction, %%LINK%func;mode;mode%%(), encoding);
  } else {
    %%LINK%func;unpredictable;unpredictable%%("Attempt to read unimplemented CSR");
  }
}
PrivilegeMode priv_mode;
if (csr_addr[9:8] == 2'b00) {
  priv_mode = PrivilegeMode::M;
} else if (csr_addr[9:8] == 2'b01 || csr_addr[9:8] == 2'b10) {
  priv_mode = PrivilegeMode::S;
} else {
  priv_mode = PrivilegeMode::U;
}
if (priv_mode == PrivilegeMode::M) {
  if (%%LINK%func;mode;mode%%() != PrivilegeMode::M) {
    %%LINK%func;raise;raise%%(ExceptionCode::IllegalInstruction, %%LINK%func;mode;mode%%(), encoding);
  }
} else if (priv_mode == PrivilegeMode::S) {
  if (%%LINK%func;mode;mode%%() == PrivilegeMode::U || %%LINK%func;mode;mode%%() == PrivilegeMode::VU) {
    %%LINK%func;raise;raise%%(ExceptionCode::IllegalInstruction, %%LINK%func;mode;mode%%(), encoding);
  }
}
if (for_write && csr_addr[11:10] == 2'b11) {
  %%LINK%func;raise;raise%%(ExceptionCode::IllegalInstruction, %%LINK%func;mode;mode%%(), encoding);
}
if (!%%LINK%func;csr?;csr?%%(csr_addr)) {
  %%LINK%func;raise;raise%%(ExceptionCode::IllegalInstruction, %%LINK%func;mode;mode%%(), encoding);
}
PrivilegeMode priv_mode;
if (csr_addr[9:8] == 2'b00) {
  priv_mode = PrivilegeMode::M;
} else if (csr_addr[9:8] == 2'b01 || csr_addr[9:8] == 2'b10) {
  priv_mode = PrivilegeMode::S;
} else {
  priv_mode = PrivilegeMode::U;
}

if (for_write && csr_addr[11:10] == 2'b11) {
  %%LINK%func;raise;raise%%(ExceptionCode::IllegalInstruction, %%LINK%func;mode;mode%%(), encoding);
}

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

ary_includes?

Returns true if value is an element of ary, and false otherwise

Return Type

 Boolean

Arguments

 Bits<ELEMENT_SIZE> ary[ARY_SIZE], Bits<ELEMENT_SIZE> value
  • Original

  • Pruned

for (U32 i = 0; i < ARY_SIZE; i++) {
  if (ary[i] == value) {
    return true;
  }
}
return false;
for (U32 i = 0; i < ARY_SIZE; i++) {
  if (ary[i] == value) {
    return true;
  }
}
return false;

read_mcycle (builtin)

Return the current value of the cycle counter.

Return Type

 Bits<64>

Arguments

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 (%%LINK%func;ary_includes?;ary_includes?%%<$enum_size(InterruptCode), $enum_element_size(InterruptCode)>($enum_to_a(InterruptCode), code)) {
  return true;
} else {
  return false;
}
if (code > (15)) {
  return false;
}
if (%%LINK%func;ary_includes?;ary_includes?%%<$enum_size(InterruptCode), $enum_element_size(InterruptCode)>($enum_to_a(InterruptCode), code)) {
  return true;
} else {
  return false;
}

valid_exception_code?

Returns true if code is a legal exception number.

Return Type

 Boolean

Arguments

 XReg code
  • Original

  • Pruned

if (code > 1 << $enum_element_size(ExceptionCode - 1)) {
  return false;
}
if (%%LINK%func;ary_includes?;ary_includes?%%<$enum_size(InterruptCode), $enum_element_size(InterruptCode)>($enum_to_a(InterruptCode), code)) {
  return true;
} else {
  return false;
}
if (code > (31)) {
  return false;
}
if (%%LINK%func;ary_includes?;ary_includes?%%<$enum_size(InterruptCode), $enum_element_size(InterruptCode)>($enum_to_a(InterruptCode), 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

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;
}
if (%%LINK%csr_field;misa.S;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;
  }
}
if (%%LINK%func;implemented?;implemented?%%(ExtensionName::Sscofpmf)) {
  if (int_mask[$bits(InterruptCode::LocalCounterOverflow)] == 1'b1) {
    return InterruptCode::LocalCounterOverflow;
  }
}
%%LINK%func;assert;assert%%(false, "There is no valid interrupt");
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;
}
if (%%LINK%csr_field;misa.S;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;
  }
}
if (int_mask[$bits(InterruptCode::LocalCounterOverflow)] == 1'b1) {
  return InterruptCode::LocalCounterOverflow;
}
%%LINK%func;assert;assert%%(false, "There is no valid interrupt");

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 = %%LINK%func;implemented_version?;implemented_version?%%(ExtensionName::S, "<= 1.9.1") || (%%LINK%func;implemented_version?;implemented_version?%%(ExtensionName::S, "> 1.9.1") && %%LINK%func;implemented_version?;implemented_version?%%(ExtensionName::Sm, "> 1.9.1"));
Bits<MXLEN> mmode_pending_and_enabled = pending_and_enabled_interrupts & ~(HAS_MIDELEG ? $bits(CSR[mideleg]) : MXLEN'0);
if (mmode_pending_and_enabled != 0) {
  %%LINK%func;assert;assert%%((%%LINK%func;mode;mode%%() != PrivilegeMode::M) || (%%LINK%csr_field;mstatus.MIE;CSR[mstatus].MIE%% == 1'b1), "M-mode interrupts are not enabled");
  chosen = %%LINK%func;highest_priority_interrupt;highest_priority_interrupt%%(mmode_pending_and_enabled);
} else if (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1'b1) {
  Bits<MXLEN> smode_pending_and_enabled = (pending_and_enabled_interrupts & $bits(CSR[mideleg]));
  if (smode_pending_and_enabled != 0) {
    %%LINK%func;assert;assert%%((%%LINK%func;mode;mode%%() == PrivilegeMode::U) || (%%LINK%func;mode;mode%%() == PrivilegeMode::VU) || (%%LINK%func;mode;mode%%() == PrivilegeMode::VS) || (%%LINK%func;mode;mode%%() == PrivilegeMode::S) && (%%LINK%csr_field;mstatus.SIE;CSR[mstatus].SIE%% == 1'b1), "S-mode interrupt can't be triggered");
    chosen = %%LINK%func;highest_priority_interrupt;highest_priority_interrupt%%(smode_pending_and_enabled);
  }
}
%%LINK%func;assert;assert%%($bits(chosen) != 0, "Didn't pick interrupt?");
PrivilegeMode to_mode;
Bits<MXLEN> chosen_mask = (MXLEN'1 << $bits(chosen));
if (((HAS_MIDELEG ? $bits(CSR[mideleg]) : MXLEN'0) & chosen_mask) == 0) {
  to_mode = PrivilegeMode::M;
} else {
  if (%%LINK%csr_field;misa.S;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[mideleg]));
if (mmode_pending_and_enabled != 0) {
  %%LINK%func;assert;assert%%((%%LINK%func;mode;mode%%() != PrivilegeMode::M) || (%%LINK%csr_field;mstatus.MIE;CSR[mstatus].MIE%% == 1'b1), "M-mode interrupts are not enabled");
  chosen = %%LINK%func;highest_priority_interrupt;highest_priority_interrupt%%(mmode_pending_and_enabled);
} else if (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1'b1) {
  Bits<MXLEN> smode_pending_and_enabled = (pending_and_enabled_interrupts & $bits(CSR[mideleg]));
  if (smode_pending_and_enabled != 0) {
    %%LINK%func;assert;assert%%((%%LINK%func;mode;mode%%() == PrivilegeMode::U) || (%%LINK%func;mode;mode%%() == PrivilegeMode::VU) || (%%LINK%func;mode;mode%%() == PrivilegeMode::VS) || (%%LINK%func;mode;mode%%() == PrivilegeMode::S) && (%%LINK%csr_field;mstatus.SIE;CSR[mstatus].SIE%% == 1'b1), "S-mode interrupt can't be triggered");
    chosen = %%LINK%func;highest_priority_interrupt;highest_priority_interrupt%%(smode_pending_and_enabled);
  }
}
%%LINK%func;assert;assert%%($bits(chosen) != 0, "Didn't pick interrupt?");
PrivilegeMode to_mode;
Bits<MXLEN> chosen_mask = (MXLEN'1 << $bits(chosen));
if ($bits(CSR[mideleg] & chosen_mask) == 0) {
  to_mode = PrivilegeMode::M;
} else {
  if (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1'b1) {
    to_mode = PrivilegeMode::S;
  } else {
    to_mode = PrivilegeMode::U;
  }
}
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) {
  %%LINK%func;notify_mode_change;notify_mode_change%%(new_mode, current_mode);
  current_mode = new_mode;
}
if (new_mode != current_mode) {
  %%LINK%func;notify_mode_change;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 = %%LINK%func;choose_interrupt;choose_interrupt%%());
if (to_mode == PrivilegeMode::M) {
  %%LINK%csr_field;mepc.PC;CSR[mepc].PC%% = $pc;
  %%LINK%csr_field;mstatus.MPP;CSR[mstatus].MPP%% = $bits(%%LINK%func;mode;mode%%())[1:0];
  if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1'b1) {
    %%LINK%csr_field;mstatus.MPV;CSR[mstatus].MPV%% = $bits(%%LINK%func;mode;mode%%())[2];
    %%LINK%csr_field;mtval2.VALUE;CSR[mtval2].VALUE%% = 0;
    %%LINK%csr_field;mtinst.VALUE;CSR[mtinst].VALUE%% = 0;
  }
  %%LINK%csr_field;mcause.CODE;CSR[mcause].CODE%% = $bits(code);
  %%LINK%csr_field;mcause.INT;CSR[mcause].INT%% = 1'b1;
  %%LINK%csr_field;mtval.VALUE;CSR[mtval].VALUE%% = 0;
  if (%%LINK%csr_field;mtvec.MODE;CSR[mtvec].MODE%% == 0) {
    $pc = {%%LINK%csr_field;mtvec.BASE;CSR[mtvec].BASE%%, 2'b00};
  } else if (%%LINK%csr_field;mtvec.MODE;CSR[mtvec].MODE%% == 1'b1) {
    $pc = {%%LINK%csr_field;mtvec.BASE;CSR[mtvec].BASE%%, 2'b00} + ($bits(code) * 4);
  }
} else if ((%%LINK%csr_field;misa.S;CSR[misa].S%% == 1'b1) && (to_mode == PrivilegeMode::S)) {
  %%LINK%csr_field;sepc.PC;CSR[sepc].PC%% = $pc;
  %%LINK%csr_field;mstatus.SPP;CSR[mstatus].SPP%% = $bits(%%LINK%func;mode;mode%%())[0];
  if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1'b1) {
    %%LINK%csr_field;hstatus.SPV;CSR[hstatus].SPV%% = $bits(%%LINK%func;mode;mode%%())[2];
  }
  %%LINK%csr_field;scause.CODE;CSR[scause].CODE%% = $bits(code);
  %%LINK%csr_field;scause.INT;CSR[scause].INT%% = 1'b1;
  %%LINK%csr_field;stval.VALUE;CSR[stval].VALUE%% = 0;
  if (%%LINK%csr_field;stvec.MODE;CSR[stvec].MODE%% == 0) {
    $pc = {%%LINK%csr_field;stvec.BASE;CSR[stvec].BASE%%, 2'b00};
  } else if (%%LINK%csr_field;stvec.MODE;CSR[stvec].MODE%% == 1'b1) {
    $pc = {%%LINK%csr_field;stvec.BASE;CSR[stvec].BASE%%, 2'b00} + ($bits(code) * 4);
  }
} else if ((%%LINK%csr_field;misa.H;CSR[misa].H%% == 1'b1) && (to_mode == PrivilegeMode::VS)) {
  %%LINK%csr_field;vsepc.PC;CSR[vsepc].PC%% = $pc;
  %%LINK%csr_field;vsstatus.SPP;CSR[vsstatus].SPP%% = $bits(%%LINK%func;mode;mode%%())[0];
  %%LINK%csr_field;vscause.CODE;CSR[vscause].CODE%% = $bits(code);
  %%LINK%csr_field;vscause.INT;CSR[vscause].INT%% = 1'b1;
  %%LINK%csr_field;vstval.VALUE;CSR[vstval].VALUE%% = 0;
  if (%%LINK%csr_field;vstvec.MODE;CSR[vstvec].MODE%% == 0) {
    $pc = {%%LINK%csr_field;vstvec.BASE;CSR[vstvec].BASE%%, 2'b00};
  } else if (%%LINK%csr_field;vstvec.MODE;CSR[vstvec].MODE%% == 1'b1) {
    $pc = {%%LINK%csr_field;vstvec.BASE;CSR[vstvec].BASE%%, 2'b00} + ($bits(code) * 4);
  }
}
%%LINK%func;set_mode_no_refresh;set_mode_no_refresh%%(to_mode);
PrivilegeMode to_mode;
InterruptCode code;
(code, to_mode = %%LINK%func;choose_interrupt;choose_interrupt%%());
if (to_mode == PrivilegeMode::M) {
  %%LINK%csr_field;mepc.PC;CSR[mepc].PC%% = $pc;
  %%LINK%csr_field;mstatus.MPP;CSR[mstatus].MPP%% = $bits(%%LINK%func;mode;mode%%())[1:0];
  if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1'b1) {
    %%LINK%csr_field;mstatus.MPV;CSR[mstatus].MPV%% = $bits(%%LINK%func;mode;mode%%())[2];
    %%LINK%csr_field;mtval2.VALUE;CSR[mtval2].VALUE%% = 0;
    %%LINK%csr_field;mtinst.VALUE;CSR[mtinst].VALUE%% = 0;
  }
  %%LINK%csr_field;mcause.CODE;CSR[mcause].CODE%% = $bits(code);
  %%LINK%csr_field;mcause.INT;CSR[mcause].INT%% = 1'b1;
  %%LINK%csr_field;mtval.VALUE;CSR[mtval].VALUE%% = 0;
  if (%%LINK%csr_field;mtvec.MODE;CSR[mtvec].MODE%% == 0) {
    $pc = {%%LINK%csr_field;mtvec.BASE;CSR[mtvec].BASE%%, 2'b00};
  } else if (%%LINK%csr_field;mtvec.MODE;CSR[mtvec].MODE%% == 1'b1) {
    $pc = {%%LINK%csr_field;mtvec.BASE;CSR[mtvec].BASE%%, 2'b00} + ($bits(code) * 4);
  }
} else if ((%%LINK%csr_field;misa.S;CSR[misa].S%% == 1'b1) && (to_mode == PrivilegeMode::S)) {
  %%LINK%csr_field;sepc.PC;CSR[sepc].PC%% = $pc;
  %%LINK%csr_field;mstatus.SPP;CSR[mstatus].SPP%% = $bits(%%LINK%func;mode;mode%%())[0];
  if (%%LINK%csr_field;misa.H;CSR[misa].H%% == 1'b1) {
    %%LINK%csr_field;hstatus.SPV;CSR[hstatus].SPV%% = $bits(%%LINK%func;mode;mode%%())[2];
  }
  %%LINK%csr_field;scause.CODE;CSR[scause].CODE%% = $bits(code);
  %%LINK%csr_field;scause.INT;CSR[scause].INT%% = 1'b1;
  %%LINK%csr_field;stval.VALUE;CSR[stval].VALUE%% = 0;
  if (%%LINK%csr_field;stvec.MODE;CSR[stvec].MODE%% == 0) {
    $pc = {%%LINK%csr_field;stvec.BASE;CSR[stvec].BASE%%, 2'b00};
  } else if (%%LINK%csr_field;stvec.MODE;CSR[stvec].MODE%% == 1'b1) {
    $pc = {%%LINK%csr_field;stvec.BASE;CSR[stvec].BASE%%, 2'b00} + ($bits(code) * 4);
  }
} else if ((%%LINK%csr_field;misa.H;CSR[misa].H%% == 1'b1) && (to_mode == PrivilegeMode::VS)) {
  %%LINK%csr_field;vsepc.PC;CSR[vsepc].PC%% = $pc;
  %%LINK%csr_field;vsstatus.SPP;CSR[vsstatus].SPP%% = $bits(%%LINK%func;mode;mode%%())[0];
  %%LINK%csr_field;vscause.CODE;CSR[vscause].CODE%% = $bits(code);
  %%LINK%csr_field;vscause.INT;CSR[vscause].INT%% = 1'b1;
  %%LINK%csr_field;vstval.VALUE;CSR[vstval].VALUE%% = 0;
  if (%%LINK%csr_field;vstvec.MODE;CSR[vstvec].MODE%% == 0) {
    $pc = {%%LINK%csr_field;vstvec.BASE;CSR[vstvec].BASE%%, 2'b00};
  } else if (%%LINK%csr_field;vstvec.MODE;CSR[vstvec].MODE%% == 1'b1) {
    $pc = {%%LINK%csr_field;vstvec.BASE;CSR[vstvec].BASE%%, 2'b00} + ($bits(code) * 4);
  }
}
%%LINK%func;set_mode_no_refresh;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 (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1) {
  result = %%LINK%func;translate;translate%%(virtual_address, MemoryOperation::Fetch, %%LINK%func;mode;mode%%(), virtual_address);
} else {
  result.paddr = virtual_address;
}
%%LINK%func;access_check;access_check%%(result.paddr, 16, virtual_address, MemoryOperation::Fetch, ExceptionCode::InstructionAccessFault, %%LINK%func;mode;mode%%());
return %%LINK%func;read_physical_memory;read_physical_memory%%<16>(result.paddr);
TranslationResult result;
if (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1) {
  result = %%LINK%func;translate;translate%%(virtual_address, MemoryOperation::Fetch, %%LINK%func;mode;mode%%(), virtual_address);
} else {
  result.paddr = virtual_address;
}
%%LINK%func;access_check;access_check%%(result.paddr, 16, virtual_address, MemoryOperation::Fetch, ExceptionCode::InstructionAccessFault, %%LINK%func;mode;mode%%());
return %%LINK%func;read_physical_memory;read_physical_memory%%<16>(result.paddr);

fetch_memory_aligned_32

Fetch 32 bits from virtual memory using a known aligned address.

Return Type

 Bits<32>

Arguments

 XReg virtual_address
  • Original

  • Pruned

TranslationResult result;
if (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1) {
  result = %%LINK%func;translate;translate%%(virtual_address, MemoryOperation::Fetch, %%LINK%func;mode;mode%%(), virtual_address);
} else {
  result.paddr = virtual_address;
}
%%LINK%func;access_check;access_check%%(result.paddr, 32, virtual_address, MemoryOperation::Fetch, ExceptionCode::InstructionAccessFault, %%LINK%func;mode;mode%%());
return %%LINK%func;read_physical_memory;read_physical_memory%%<32>(result.paddr);
TranslationResult result;
if (%%LINK%csr_field;misa.S;CSR[misa].S%% == 1) {
  result = %%LINK%func;translate;translate%%(virtual_address, MemoryOperation::Fetch, %%LINK%func;mode;mode%%(), virtual_address);
} else {
  result.paddr = virtual_address;
}
%%LINK%func;access_check;access_check%%(result.paddr, 32, virtual_address, MemoryOperation::Fetch, ExceptionCode::InstructionAccessFault, %%LINK%func;mode;mode%%());
return %%LINK%func;read_physical_memory;read_physical_memory%%<32>(result.paddr);