diff options
author | Scott Johnson <scott.johnson@arilinc.com> | 2023-03-03 05:22:52 -0800 |
---|---|---|
committer | Andrew Waterman <andrew@sifive.com> | 2023-03-04 17:30:31 -0800 |
commit | 1951f80361e7cb82a8baa975183d036e8a944bd2 (patch) | |
tree | 6f2e6ca06d58f833204989cb01cc8d59c9fffab8 /riscv/mmu.cc | |
parent | 360e55535da0d3a0f8123bbe9ca4b2947950e8ea (diff) | |
download | riscv-isa-sim-1951f80361e7cb82a8baa975183d036e8a944bd2.zip riscv-isa-sim-1951f80361e7cb82a8baa975183d036e8a944bd2.tar.gz riscv-isa-sim-1951f80361e7cb82a8baa975183d036e8a944bd2.tar.bz2 |
Don't issue misaligned or non-power-of-2 MMIO accesses
@aswaterman explains:
Rather than requiring each MMIO device to support arbitrary sizes and
alignments, decompose MMIO misaligned loads and stores in such a way
as to guarantee their constituent parts are always aligned.
(Specifically, they now always decompose to a sequence of one-byte
accesses.)
This is not a semantic change for main-memory accesses, but it is a
semantic change for I/O devices. It makes them more realistic, in that
most bus standards don't support non-power-of-2-sized accesses.
Diffstat (limited to 'riscv/mmu.cc')
-rw-r--r-- | riscv/mmu.cc | 31 |
1 files changed, 24 insertions, 7 deletions
diff --git a/riscv/mmu.cc b/riscv/mmu.cc index fc80dfa..8ce7a3a 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -147,18 +147,35 @@ bool mmu_t::mmio_fetch(reg_t paddr, size_t len, uint8_t* bytes) bool mmu_t::mmio_load(reg_t paddr, size_t len, uint8_t* bytes) { - if (!mmio_ok(paddr, LOAD)) - return false; - - return sim->mmio_load(paddr, len, bytes); + return mmio(paddr, len, bytes, LOAD); } bool mmu_t::mmio_store(reg_t paddr, size_t len, const uint8_t* bytes) { - if (!mmio_ok(paddr, STORE)) - return false; + return mmio(paddr, len, const_cast<uint8_t*>(bytes), STORE); +} + +bool mmu_t::mmio(reg_t paddr, size_t len, uint8_t* bytes, access_type type) +{ + bool power_of_2 = (len & (len - 1)) == 0; + bool naturally_aligned = (paddr & (len - 1)) == 0; + + if (power_of_2 && naturally_aligned) { + if (!mmio_ok(paddr, type)) + return false; + + if (type == STORE) + return sim->mmio_store(paddr, len, bytes); + else + return sim->mmio_load(paddr, len, bytes); + } - return sim->mmio_store(paddr, len, bytes); + for (size_t i = 0; i < len; i++) { + if (!mmio(paddr + i, 1, bytes + i, type)) + return false; + } + + return true; } void mmu_t::check_triggers(triggers::operation_t operation, reg_t address, std::optional<reg_t> data) |