profile
viewpoint
Scott Johnson scottj97 San Francisco, CA

riscv-software-src/riscv-isa-sim 1209

Spike, a RISC-V ISA Simulator

scottj97/environment-modules-in-git 1

Enable Git control of Modulefiles

scottj97/aruba 0

Scott's hack of aruba to allow slashes in file matchers; see branch 0.14.2-match-slash

scottj97/Cache 0

Python Program to Fill Up the Cache during Initialization

scottj97/custom_uvm_report_server 0

Customized UVM Report Server

scottj97/git 0

Git Source Code Mirror plus scottj97's fix so git-p4 works with old perforce versions

scottj97/pyelftools 0

Parsing ELF and DWARF in Python

scottj97/pyhocon 0

HOCON parser for Python, forked to add hex literals (see branch hexliterals)

scottj97/pyparsing 0

scottj97's fork to fix copy.deepcopy of ParseResults (see branch deepcopy-fix)

PullRequestReviewEvent
PullRequestReviewEvent

issue commentriscv-software-src/riscv-isa-sim

mstatus.FS is not set to dirty when mstatus.FS is changed

You're right, BOOM is unnecessarily setting Dirty here. Any unnecessary setting of Dirty like this may reduce performance, but in this instance I'd guess the impact is negligible.

Strangely, from looking at the code, I don't see the Spike behavior you observe. I'd expect any csrwi to fcsr to set FS=Dirty.

It also seems unreasonable in any hardware implementation to compare the old and the new value and decide to Dirty based on that. In a straightforward implementation, any write to fcsr will set Dirty.

sammy17

comment created time in 10 days

PullRequestReviewEvent

pull request commentriscv-software-src/riscv-isa-sim

add support for CMO v1.0

Isn't it funny that the CBO ops take store {page fault, guest page fault, access fault}, though they do not actually require store permissions at all? (Except cbo.zero)

liweiwei90

comment created time in 15 days

Pull request review commentriscv-software-src/riscv-isa-sim

add support for CMO v1.0

 reg_t mmu_t::pmp_homogeneous(reg_t addr, reg_t len)   return true; } -reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_type, bool virt, bool hlvx)+reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, int& type, int trap_type, bool virt, bool hlvx)

Nevermind, I see why. This smells bad but I can't think of a better way. :(

liweiwei90

comment created time in 15 days

PullRequestReviewEvent

Pull request review commentriscv-software-src/riscv-isa-sim

add support for CMO v1.0

 reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode, bool virt, bool hlvx       break;     } else if (type == FETCH || hlvx ? !(pte & PTE_X) :                type == LOAD          ? !(pte & PTE_R) && !(mxr && (pte & PTE_X)) :-                                       !((pte & PTE_R) && (pte & PTE_W))) {+                                       (type == STORE) && !((pte & PTE_R) && (pte & PTE_W))) {       break;     } else if ((ppn & ((reg_t(1) << ptshift) - 1)) != 0) {       break;     } else {+      if (type & CBO) {

On second thought, my exception would break the exception cause because none of the type flags would be set anymore.

liweiwei90

comment created time in 15 days

PullRequestReviewEvent
PullRequestReviewEvent

Pull request review commentriscv-software-src/riscv-isa-sim

add support for CMO v1.0

 reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode, bool virt, bool hlvx       break;     } else if (type == FETCH || hlvx ? !(pte & PTE_X) :                type == LOAD          ? !(pte & PTE_R) && !(mxr && (pte & PTE_X)) :-                                       !((pte & PTE_R) && (pte & PTE_W))) {+                                       (type == STORE) && !((pte & PTE_R) && (pte & PTE_W))) {       break;     } else if ((ppn & ((reg_t(1) << ptshift) - 1)) != 0) {       break;     } else {+      if (type & CBO) {+        if ((type & FETCH) && !(pte & PTE_X))+          type &= ~FETCH;+        if ((type & LOAD) && !(pte & PTE_R) && !(mxr && (pte & PTE_X)))+          type &= ~LOAD;+        if ((type == STORE) && !((pte & PTE_R) && (pte & PTE_W)))

Shouldn't this be (type & STORE)?

liweiwei90

comment created time in 15 days

Pull request review commentriscv-software-src/riscv-isa-sim

add support for CMO v1.0

 reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode, bool virt, bool hlvx       break;     } else if (type == FETCH || hlvx ? !(pte & PTE_X) :                type == LOAD          ? !(pte & PTE_R) && !(mxr && (pte & PTE_X)) :-                                       !((pte & PTE_R) && (pte & PTE_W))) {+                                       (type == STORE) && !((pte & PTE_R) && (pte & PTE_W))) {       break;     } else if ((ppn & ((reg_t(1) << ptshift) - 1)) != 0) {       break;     } else {+      if (type & CBO) {

This is unfortunate duplication of the XWR checking. Can't this be combined with the earlier block at line 427? Remove the if (type & CBO) then at the end if (type == 0 || type == CBO) break;.

liweiwei90

comment created time in 15 days

PullRequestReviewEvent

Pull request review commentriscv-software-src/riscv-isa-sim

add support for CMO v1.0

 reg_t mmu_t::pmp_homogeneous(reg_t addr, reg_t len)   return true; } -reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_type, bool virt, bool hlvx)+reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, int& type, int trap_type, bool virt, bool hlvx)

Why use a reference for type?

liweiwei90

comment created time in 15 days

PullRequestReviewEvent

issue commentriscv-software-src/riscv-isa-sim

RV32EMC support

If Spike's going to show E in misa then it should actually implement E fully, including the exceptions on accessing x16-x31.

subhajit26

comment created time in 15 days

issue openedriscv/riscv-isa-manual

PMP and MPRV description misleading

The PMP description in 3.7 says:

PMP checks are applied to all accesses whose effective privilege mode is S or U, including instruction fetches in S and U mode, data accesses in S and U mode when the MPRV bit in the mstatus register is clear, and data accesses in any mode when the MPRV bit in mstatus is set and the MPP field in mstatus contains S or U.

Since this change MPRV cannot be 1 outside of M-mode, so this is misleading when it qualifies accesses in S and U mode with MPRV being clear.

Suggestion:

PMP checks are applied to all accesses whose effective privilege mode is S or U, including instruction fetches and data accesses in S and U mode, data accesses in M mode when the MPRV bit in mstatus is set and the MPP field in mstatus contains S or U, and HLV/HLVX/HSV instructions from any mode.

(See #528 for a similar change.)

created time in 15 days

Pull request review commentriscv-software-src/riscv-isa-sim

add support for CMO v1.0

 void mmu_t::load_slow_path(reg_t addr, reg_t len, uint8_t* bytes, uint32_t xlate   } } +void mmu_t::clean_inval(reg_t addr, bool clean, bool inval)+{+  reg_t paddr = addr;+  bool page = false, guest = false, access = false;+  bool has_gva;+  reg_t gpa;++  bool fault = true;+  try {+    paddr = translate(addr, 1, LOAD, 0);+    fault = false;+  } catch (trap_load_access_fault& t) {+    access = true;+    has_gva = t.has_gva();+  } catch (trap_load_page_fault& t) {+    page = true;+    has_gva = t.has_gva();+  } catch (trap_load_guest_page_fault& t) {+    guest = true;+    gpa = t.get_tval2();+  }++  if (fault) {+    try {+      paddr = translate(addr, 1, FETCH, 0);+    } catch (trap_instruction_access_fault& t) {+      access = true;+      has_gva = t.has_gva();+    } catch (trap_instruction_page_fault& t) {+      page = true;+      has_gva = t.has_gva();+    } catch (trap_instruction_guest_page_fault& t) {+      guest = true;+      gpa = t.get_tval2();+    }+  }++  if (access) {

Two problems I see in this logic:

  1. If LOAD detects an access fault, it tries again with FETCH. But access will still be true, so this will take a store access fault, when it should successfully perform the CBO.
  2. This does not seem to check for STORE permissions at all? If the page is read-only, the operation should not be allowed (right?).
liweiwei90

comment created time in 16 days

PullRequestReviewEvent
PullRequestReviewEvent

Pull request review commentriscv-software-src/riscv-isa-sim

add support for CMO v1.0

 void mmu_t::load_slow_path(reg_t addr, reg_t len, uint8_t* bytes, uint32_t xlate   } } +void mmu_t::clean_inval(reg_t addr, bool clean, bool inval)+{+  reg_t paddr = addr;+  bool page = false, guest = false, access = false;+  bool has_gva;+  reg_t gpa;+  access_type type = LOAD;+  bool fault = true;+  try {+    paddr = translate(addr, 1, LOAD, 0);+    type = LOAD;+    fault = false;+  } catch (trap_load_access_fault& t) {+    access = true;+    has_gva = t.has_gva();+  } catch (trap_load_page_fault& t) {+    page = true;+    has_gva = t.has_gva();+  } catch (trap_load_guest_page_fault& t) {+    guest = true;+    gpa = t.get_tval2();+  }++  if (fault) {+    try {+      paddr = translate(addr, 1, STORE, 0);+      type = STORE;+      fault = false;+    } catch (trap_store_access_fault& t) {+      access = true;+      has_gva = t.has_gva();+    } catch (trap_store_page_fault& t) {+      page = true;+      has_gva = t.has_gva();+    } catch (trap_store_guest_page_fault& t) {+      guest = true;+      gpa = t.get_tval2();+    }+  }++  if (fault) {+    try {+      paddr = translate(addr, 1, FETCH, 0);+      type = FETCH;+    } catch (trap_instruction_access_fault& t) {+      access = true;+      has_gva = t.has_gva();+    } catch (trap_instruction_page_fault& t) {+      page = true;+      has_gva = t.has_gva();+    } catch (trap_instruction_guest_page_fault& t) {+      guest = true;+      gpa = t.get_tval2();+    }+  }++  if (access) {+    trap_store_access_fault(has_gva, addr, 0, 0);+  } else if (guest) {+    trap_store_guest_page_fault(addr, gpa, 0);+  } else if (page) {+    trap_store_page_fault(has_gva, addr, 0, 0);+  } else {+    if (auto host_addr = sim->addr_to_mem(paddr)) {+      if (tracer.interested_in_range(paddr, paddr + PGSIZE, type))+        tracer.clean_invalidate(paddr, blocksz, clean, inval);+      else+        refill_tlb(addr, paddr, host_addr, type);+    } else {+      throw trap_store_access_fault((proc) ? proc->state.v : false, addr, 0, 0);+    }++    if (!matched_trigger) {+      matched_trigger = trigger_exception(type == LOAD? OPERATION_LOAD :+                                          type == STORE? OPERATION_STORE : OPERATION_EXECUTE,+                                          addr, 0);+      if (matched_trigger)+        throw *matched_trigger;+    }+  }+}

In the spec, " A cache-block management instruction is permitted to access the specified cache block whenever a load instruction, store instruction, or instruction fetch is permitted to access the corresponding physical addresses." That means it may do LOAD STORE or FETCH check. However, current translate progress can only pass one type at a time. So in above implementation it divide into three steps to check each access type:

  • No matter which access type pass the translation progress, cbo instruction will execute successfully.
  • If all of them trigger exceptions. it will combine the final exception result according which exception is triggered at last (birefly access fault> guest page fault > page fault)

How does this work with MPRV=1 (which does not affect fetch)? Perhaps the spec is too vague here. As of 83fdb70955be23215ad7800bcc3d8226b0685820, clean_inval() tries a load access type, and if that detects a fault, it tries a fetch access type. Those could be two completely different paddrs if MPRV=1. That doesn't seem desirable. The spec refers only to "the corresponding physical address", i.e. only a single possible physical address.

liweiwei90

comment created time in 16 days

PullRequestReviewEvent
PullRequestReviewEvent

Pull request review commentriscv-software-src/riscv-isa-sim

add support for CMO v1.0

 void mmu_t::load_slow_path(reg_t addr, reg_t len, uint8_t* bytes, uint32_t xlate   } } +void mmu_t::clean_inval(reg_t addr, bool clean, bool inval)+{+  reg_t paddr = addr;+  bool page = false, guest = false, access = false;+  bool has_gva;+  reg_t gpa;+  access_type type = LOAD;+  bool fault = true;+  try {+    paddr = translate(addr, 1, LOAD, 0);+    type = LOAD;+    fault = false;+  } catch (trap_load_access_fault& t) {+    access = true;+    has_gva = t.has_gva();+  } catch (trap_load_page_fault& t) {+    page = true;+    has_gva = t.has_gva();+  } catch (trap_load_guest_page_fault& t) {+    guest = true;+    gpa = t.get_tval2();+  }++  if (fault) {+    try {+      paddr = translate(addr, 1, STORE, 0);+      type = STORE;+      fault = false;+    } catch (trap_store_access_fault& t) {+      access = true;+      has_gva = t.has_gva();+    } catch (trap_store_page_fault& t) {+      page = true;+      has_gva = t.has_gva();+    } catch (trap_store_guest_page_fault& t) {+      guest = true;+      gpa = t.get_tval2();+    }+  }++  if (fault) {+    try {+      paddr = translate(addr, 1, FETCH, 0);+      type = FETCH;+    } catch (trap_instruction_access_fault& t) {+      access = true;+      has_gva = t.has_gva();+    } catch (trap_instruction_page_fault& t) {+      page = true;+      has_gva = t.has_gva();+    } catch (trap_instruction_guest_page_fault& t) {+      guest = true;+      gpa = t.get_tval2();+    }+  }++  if (access) {+    trap_store_access_fault(has_gva, addr, 0, 0);+  } else if (guest) {+    trap_store_guest_page_fault(addr, gpa, 0);+  } else if (page) {+    trap_store_page_fault(has_gva, addr, 0, 0);+  } else {+    if (auto host_addr = sim->addr_to_mem(paddr)) {+      if (tracer.interested_in_range(paddr, paddr + PGSIZE, type))+        tracer.clean_invalidate(paddr, blocksz, clean, inval);+      else+        refill_tlb(addr, paddr, host_addr, type);+    } else {+      throw trap_store_access_fault((proc) ? proc->state.v : false, addr, 0, 0);+    }++    if (!matched_trigger) {+      matched_trigger = trigger_exception(type == LOAD? OPERATION_LOAD :+                                          type == STORE? OPERATION_STORE : OPERATION_EXECUTE,+                                          addr, 0);+      if (matched_trigger)+        throw *matched_trigger;+    }+  }+}

OK, I concede. I agree it would get messy elsewhere.

Won't hardware need to do all that mess, though?

liweiwei90

comment created time in 17 days

PullRequestReviewEvent

Pull request review commentriscv-software-src/riscv-isa-sim

add support for CMO v1.0

 void mmu_t::load_slow_path(reg_t addr, reg_t len, uint8_t* bytes, uint32_t xlate   } } +void mmu_t::clean_inval(reg_t addr, bool clean, bool inval)+{+  reg_t paddr = addr;+  bool page = false, guest = false, access = false;+  bool has_gva;+  reg_t gpa;+  access_type type = LOAD;+  bool fault = true;+  try {+    paddr = translate(addr, 1, LOAD, 0);+    type = LOAD;+    fault = false;+  } catch (trap_load_access_fault& t) {+    access = true;+    has_gva = t.has_gva();+  } catch (trap_load_page_fault& t) {+    page = true;+    has_gva = t.has_gva();+  } catch (trap_load_guest_page_fault& t) {+    guest = true;+    gpa = t.get_tval2();+  }++  if (fault) {+    try {+      paddr = translate(addr, 1, STORE, 0);+      type = STORE;+      fault = false;+    } catch (trap_store_access_fault& t) {+      access = true;+      has_gva = t.has_gva();+    } catch (trap_store_page_fault& t) {+      page = true;+      has_gva = t.has_gva();+    } catch (trap_store_guest_page_fault& t) {+      guest = true;+      gpa = t.get_tval2();+    }+  }++  if (fault) {+    try {+      paddr = translate(addr, 1, FETCH, 0);+      type = FETCH;+    } catch (trap_instruction_access_fault& t) {+      access = true;+      has_gva = t.has_gva();+    } catch (trap_instruction_page_fault& t) {+      page = true;+      has_gva = t.has_gva();+    } catch (trap_instruction_guest_page_fault& t) {+      guest = true;+      gpa = t.get_tval2();+    }+  }++  if (access) {+    trap_store_access_fault(has_gva, addr, 0, 0);+  } else if (guest) {+    trap_store_guest_page_fault(addr, gpa, 0);+  } else if (page) {+    trap_store_page_fault(has_gva, addr, 0, 0);+  } else {+    if (auto host_addr = sim->addr_to_mem(paddr)) {+      if (tracer.interested_in_range(paddr, paddr + PGSIZE, type))+        tracer.clean_invalidate(paddr, blocksz, clean, inval);+      else+        refill_tlb(addr, paddr, host_addr, type);+    } else {+      throw trap_store_access_fault((proc) ? proc->state.v : false, addr, 0, 0);+    }++    if (!matched_trigger) {+      matched_trigger = trigger_exception(type == LOAD? OPERATION_LOAD :+                                          type == STORE? OPERATION_STORE : OPERATION_EXECUTE,+                                          addr, 0);+      if (matched_trigger)+        throw *matched_trigger;+    }+  }+}

Would it make any sense to modify translate() so that we can pass a list of access types? So we could do:

paddr = translate(addr, 1, LOAD | FETCH | STORE, 0);
liweiwei90

comment created time in 18 days

PullRequestReviewEvent
PullRequestReviewEvent

Pull request review commentriscv-software-src/riscv-isa-sim

add support for CMO v1.0

 void mmu_t::load_slow_path(reg_t addr, reg_t len, uint8_t* bytes, uint32_t xlate   } } +void mmu_t::clean_inval(reg_t addr, bool clean, bool inval)+{+  reg_t paddr = addr;+  bool page = false, guest = false, access = false;+  bool has_gva;+  reg_t gpa;+  access_type type = LOAD;+  bool fault = true;+  try {+    paddr = translate(addr, 1, LOAD, 0);+    type = LOAD;+    fault = false;+  } catch (trap_load_access_fault& t) {+    access = true;+    has_gva = t.has_gva();+  } catch (trap_load_page_fault& t) {+    page = true;+    has_gva = t.has_gva();+  } catch (trap_load_guest_page_fault& t) {+    guest = true;+    gpa = t.get_tval2();+  }++  if (fault) {+    try {+      paddr = translate(addr, 1, STORE, 0);+      type = STORE;+      fault = false;+    } catch (trap_store_access_fault& t) {+      access = true;+      has_gva = t.has_gva();+    } catch (trap_store_page_fault& t) {+      page = true;+      has_gva = t.has_gva();+    } catch (trap_store_guest_page_fault& t) {+      guest = true;+      gpa = t.get_tval2();+    }+  }++  if (fault) {+    try {+      paddr = translate(addr, 1, FETCH, 0);+      type = FETCH;+    } catch (trap_instruction_access_fault& t) {+      access = true;+      has_gva = t.has_gva();+    } catch (trap_instruction_page_fault& t) {+      page = true;+      has_gva = t.has_gva();+    } catch (trap_instruction_guest_page_fault& t) {+      guest = true;+      gpa = t.get_tval2();+    }+  }++  if (access) {+    trap_store_access_fault(has_gva, addr, 0, 0);+  } else if (guest) {+    trap_store_guest_page_fault(addr, gpa, 0);+  } else if (page) {+    trap_store_page_fault(has_gva, addr, 0, 0);+  } else {+    if (auto host_addr = sim->addr_to_mem(paddr)) {+      if (tracer.interested_in_range(paddr, paddr + PGSIZE, type))+        tracer.clean_invalidate(paddr, blocksz, clean, inval);+      else+        refill_tlb(addr, paddr, host_addr, type);+    } else {+      throw trap_store_access_fault((proc) ? proc->state.v : false, addr, 0, 0);+    }++    if (!matched_trigger) {+      matched_trigger = trigger_exception(type == LOAD? OPERATION_LOAD :+                                          type == STORE? OPERATION_STORE : OPERATION_EXECUTE,+                                          addr, 0);+      if (matched_trigger)+        throw *matched_trigger;+    }+  }+}

This seems excessive, especially all the special handling of exceptions.

liweiwei90

comment created time in 20 days

PullRequestReviewEvent
more