diff options
-rw-r--r-- | fesvr/htif.cc | 4 | ||||
-rw-r--r-- | fesvr/htif.h | 12 | ||||
-rw-r--r-- | fesvr/memif.cc | 48 | ||||
-rw-r--r-- | fesvr/memif.h | 33 | ||||
-rw-r--r-- | fesvr/syscall.cc | 8 | ||||
-rw-r--r-- | riscv/byteorder.h | 64 | ||||
-rw-r--r-- | riscv/mmu.cc | 8 | ||||
-rw-r--r-- | riscv/mmu.h | 26 | ||||
-rw-r--r-- | riscv/sim.cc | 2 |
9 files changed, 135 insertions, 70 deletions
diff --git a/fesvr/htif.cc b/fesvr/htif.cc index 996e321..4f34cec 100644 --- a/fesvr/htif.cc +++ b/fesvr/htif.cc @@ -217,7 +217,7 @@ int htif_t::run() while (!signal_exit && exitcode == 0) { if (auto tohost = from_target(mem.read_uint64(tohost_addr))) { - mem.write_uint64(tohost_addr, 0); + mem.write_uint64(tohost_addr, target_endian<uint64_t>::zero); command_t cmd(mem, tohost, fromhost_callback); device_list.handle_command(cmd); } else { @@ -226,7 +226,7 @@ int htif_t::run() device_list.tick(); - if (!fromhost_queue.empty() && mem.read_uint64(fromhost_addr) == 0) { + if (!fromhost_queue.empty() && !mem.read_uint64(fromhost_addr)) { mem.write_uint64(fromhost_addr, to_target(fromhost_queue.front())); fromhost_queue.pop(); } diff --git a/fesvr/htif.h b/fesvr/htif.h index 66a626d..3cee25f 100644 --- a/fesvr/htif.h +++ b/fesvr/htif.h @@ -29,27 +29,27 @@ class htif_t : public chunked_memif_t virtual memif_t& memif() { return mem; } - template<typename T> inline T from_target(T n) const + template<typename T> inline T from_target(target_endian<T> n) const { #ifdef RISCV_ENABLE_DUAL_ENDIAN memif_endianness_t endianness = get_target_endianness(); assert(endianness == memif_endianness_little || endianness == memif_endianness_big); - return endianness == memif_endianness_big? from_be(n) : from_le(n); + return endianness == memif_endianness_big? n.from_be() : n.from_le(); #else - return from_le(n); + return n.from_le(); #endif } - template<typename T> inline T to_target(T n) const + template<typename T> inline target_endian<T> to_target(T n) const { #ifdef RISCV_ENABLE_DUAL_ENDIAN memif_endianness_t endianness = get_target_endianness(); assert(endianness == memif_endianness_little || endianness == memif_endianness_big); - return endianness == memif_endianness_big? to_be(n) : to_le(n); + return endianness == memif_endianness_big? target_endian<T>::to_be(n) : target_endian<T>::to_le(n); #else - return to_le(n); + return target_endian<T>::to_le(n); #endif } diff --git a/fesvr/memif.cc b/fesvr/memif.cc index fd96291..e56bd94 100644 --- a/fesvr/memif.cc +++ b/fesvr/memif.cc @@ -94,90 +94,90 @@ void memif_t::write(addr_t addr, size_t len, const void* bytes) throw std::runtime_error("misaligned address"); \ this->write(addr, sizeof(val), &val) -uint8_t memif_t::read_uint8(addr_t addr) +target_endian<uint8_t> memif_t::read_uint8(addr_t addr) { - uint8_t val; + target_endian<uint8_t> val; MEMIF_READ_FUNC; } -int8_t memif_t::read_int8(addr_t addr) +target_endian<int8_t> memif_t::read_int8(addr_t addr) { - int8_t val; + target_endian<int8_t> val; MEMIF_READ_FUNC; } -void memif_t::write_uint8(addr_t addr, uint8_t val) +void memif_t::write_uint8(addr_t addr, target_endian<uint8_t> val) { MEMIF_WRITE_FUNC; } -void memif_t::write_int8(addr_t addr, int8_t val) +void memif_t::write_int8(addr_t addr, target_endian<int8_t> val) { MEMIF_WRITE_FUNC; } -uint16_t memif_t::read_uint16(addr_t addr) +target_endian<uint16_t> memif_t::read_uint16(addr_t addr) { - uint16_t val; + target_endian<uint16_t> val; MEMIF_READ_FUNC; } -int16_t memif_t::read_int16(addr_t addr) +target_endian<int16_t> memif_t::read_int16(addr_t addr) { - int16_t val; + target_endian<int16_t> val; MEMIF_READ_FUNC; } -void memif_t::write_uint16(addr_t addr, uint16_t val) +void memif_t::write_uint16(addr_t addr, target_endian<uint16_t> val) { MEMIF_WRITE_FUNC; } -void memif_t::write_int16(addr_t addr, int16_t val) +void memif_t::write_int16(addr_t addr, target_endian<int16_t> val) { MEMIF_WRITE_FUNC; } -uint32_t memif_t::read_uint32(addr_t addr) +target_endian<uint32_t> memif_t::read_uint32(addr_t addr) { - uint32_t val; + target_endian<uint32_t> val; MEMIF_READ_FUNC; } -int32_t memif_t::read_int32(addr_t addr) +target_endian<int32_t> memif_t::read_int32(addr_t addr) { - int32_t val; + target_endian<int32_t> val; MEMIF_READ_FUNC; } -void memif_t::write_uint32(addr_t addr, uint32_t val) +void memif_t::write_uint32(addr_t addr, target_endian<uint32_t> val) { MEMIF_WRITE_FUNC; } -void memif_t::write_int32(addr_t addr, int32_t val) +void memif_t::write_int32(addr_t addr, target_endian<int32_t> val) { MEMIF_WRITE_FUNC; } -uint64_t memif_t::read_uint64(addr_t addr) +target_endian<uint64_t> memif_t::read_uint64(addr_t addr) { - uint64_t val; + target_endian<uint64_t> val; MEMIF_READ_FUNC; } -int64_t memif_t::read_int64(addr_t addr) +target_endian<int64_t> memif_t::read_int64(addr_t addr) { - int64_t val; + target_endian<int64_t> val; MEMIF_READ_FUNC; } -void memif_t::write_uint64(addr_t addr, uint64_t val) +void memif_t::write_uint64(addr_t addr, target_endian<uint64_t> val) { MEMIF_WRITE_FUNC; } -void memif_t::write_int64(addr_t addr, int64_t val) +void memif_t::write_int64(addr_t addr, target_endian<int64_t> val) { MEMIF_WRITE_FUNC; } diff --git a/fesvr/memif.h b/fesvr/memif.h index aaa9f05..001c425 100644 --- a/fesvr/memif.h +++ b/fesvr/memif.h @@ -5,6 +5,7 @@ #include <stdint.h> #include <stddef.h> +#include "byteorder.h" typedef uint64_t reg_t; typedef int64_t sreg_t; @@ -43,28 +44,28 @@ public: virtual void write(addr_t addr, size_t len, const void* bytes); // read and write 8-bit words - virtual uint8_t read_uint8(addr_t addr); - virtual int8_t read_int8(addr_t addr); - virtual void write_uint8(addr_t addr, uint8_t val); - virtual void write_int8(addr_t addr, int8_t val); + virtual target_endian<uint8_t> read_uint8(addr_t addr); + virtual target_endian<int8_t> read_int8(addr_t addr); + virtual void write_uint8(addr_t addr, target_endian<uint8_t> val); + virtual void write_int8(addr_t addr, target_endian<int8_t> val); // read and write 16-bit words - virtual uint16_t read_uint16(addr_t addr); - virtual int16_t read_int16(addr_t addr); - virtual void write_uint16(addr_t addr, uint16_t val); - virtual void write_int16(addr_t addr, int16_t val); + virtual target_endian<uint16_t> read_uint16(addr_t addr); + virtual target_endian<int16_t> read_int16(addr_t addr); + virtual void write_uint16(addr_t addr, target_endian<uint16_t> val); + virtual void write_int16(addr_t addr, target_endian<int16_t> val); // read and write 32-bit words - virtual uint32_t read_uint32(addr_t addr); - virtual int32_t read_int32(addr_t addr); - virtual void write_uint32(addr_t addr, uint32_t val); - virtual void write_int32(addr_t addr, int32_t val); + virtual target_endian<uint32_t> read_uint32(addr_t addr); + virtual target_endian<int32_t> read_int32(addr_t addr); + virtual void write_uint32(addr_t addr, target_endian<uint32_t> val); + virtual void write_int32(addr_t addr, target_endian<int32_t> val); // read and write 64-bit words - virtual uint64_t read_uint64(addr_t addr); - virtual int64_t read_int64(addr_t addr); - virtual void write_uint64(addr_t addr, uint64_t val); - virtual void write_int64(addr_t addr, int64_t val); + virtual target_endian<uint64_t> read_uint64(addr_t addr); + virtual target_endian<int64_t> read_int64(addr_t addr); + virtual void write_uint64(addr_t addr, target_endian<uint64_t> val); + virtual void write_int64(addr_t addr, target_endian<int64_t> val); // endianness virtual void set_target_endianness(memif_endianness_t endianness) { diff --git a/fesvr/syscall.cc b/fesvr/syscall.cc index 6feb13b..18bdc13 100644 --- a/fesvr/syscall.cc +++ b/fesvr/syscall.cc @@ -299,10 +299,10 @@ reg_t syscall_t::sys_getcwd(reg_t pbuf, reg_t size, reg_t a2, reg_t a3, reg_t a4 reg_t syscall_t::sys_getmainvars(reg_t pbuf, reg_t limit, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6) { std::vector<std::string> args = htif->target_args(); - std::vector<uint64_t> words(args.size() + 3); + std::vector<target_endian<uint64_t>> words(args.size() + 3); words[0] = htif->to_target<uint64_t>(args.size()); - words[args.size()+1] = 0; // argv[argc] = NULL - words[args.size()+2] = 0; // envp[0] = NULL + words[args.size()+1] = target_endian<uint64_t>::zero; // argv[argc] = NULL + words[args.size()+2] = target_endian<uint64_t>::zero; // envp[0] = NULL size_t sz = (args.size() + 3) * sizeof(words[0]); for (size_t i = 0; i < args.size(); i++) @@ -340,7 +340,7 @@ reg_t syscall_t::sys_chdir(reg_t path, reg_t a1, reg_t a2, reg_t a3, reg_t a4, r void syscall_t::dispatch(reg_t mm) { - reg_t magicmem[8]; + target_endian<reg_t> magicmem[8]; memif->read(mm, sizeof(magicmem), magicmem); reg_t n = htif->from_target(magicmem[0]); diff --git a/riscv/byteorder.h b/riscv/byteorder.h index 393a70b..2760e6a 100644 --- a/riscv/byteorder.h +++ b/riscv/byteorder.h @@ -27,4 +27,68 @@ template<typename T> static inline T from_be(T n) { return swap(n); } template<typename T> static inline T to_be(T n) { return swap(n); } #endif +// Wrapper to mark a value as target endian, to guide conversion code + +template<typename T> class base_endian { + + protected: + T value; + + base_endian(T n) : value(n) {} + + public: + // Setting to and testing against zero never needs swapping + base_endian() : value(0) {} + bool operator!() { return !value; } + + // Bitwise logic operations can be performed without swapping + base_endian& operator|=(const base_endian& rhs) { value |= rhs.value; return *this; } + base_endian& operator&=(const base_endian& rhs) { value &= rhs.value; return *this; } + base_endian& operator^=(const base_endian& rhs) { value ^= rhs.value; return *this; } + + inline T from_be() { return ::from_be(value); } + inline T from_le() { return ::from_le(value); } +}; + +template<typename T> class target_endian : public base_endian<T> { + protected: + target_endian(T n) : base_endian<T>(n) {} + + public: + target_endian() {} + + static inline target_endian to_be(T n) { return target_endian(::to_be(n)); } + static inline target_endian to_le(T n) { return target_endian(::to_le(n)); } + + // Useful values over which swapping is identity + static const target_endian zero; + static const target_endian all_ones; +}; + +template<typename T> const target_endian<T> target_endian<T>::zero = target_endian(T(0)); +template<typename T> const target_endian<T> target_endian<T>::all_ones = target_endian(~T(0)); + + +// Specializations with implicit conversions (no swap information needed) + +template<> class target_endian<uint8_t> : public base_endian<uint8_t> { + public: + target_endian() {} + target_endian(uint8_t n) : base_endian<uint8_t>(n) {} + operator uint8_t() { return value; } + + static inline target_endian to_be(uint8_t n) { return target_endian(n); } + static inline target_endian to_le(uint8_t n) { return target_endian(n); } +}; + +template<> class target_endian<int8_t> : public base_endian<int8_t> { + public: + target_endian() {} + target_endian(int8_t n) : base_endian<int8_t>(n) {} + operator int8_t() { return value; } + + static inline target_endian to_be(int8_t n) { return target_endian(n); } + static inline target_endian to_le(int8_t n) { return target_endian(n); } +}; + #endif diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 02295f0..fa2cfd1 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -322,7 +322,7 @@ reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_ty throw_access_exception(gva, trap_type); } - reg_t pte = vm.ptesize == 4 ? from_target(*(uint32_t*)ppte) : from_target(*(uint64_t*)ppte); + reg_t pte = vm.ptesize == 4 ? from_target(*(target_endian<uint32_t>*)ppte) : from_target(*(target_endian<uint64_t>*)ppte); reg_t ppn = pte >> PTE_PPN_SHIFT; if (PTE_TABLE(pte)) { // next level of page table @@ -344,7 +344,7 @@ reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_ty if ((pte & ad) != ad) { if (!pmp_ok(pte_paddr, vm.ptesize, STORE, PRV_S)) throw_access_exception(gva, trap_type); - *(uint32_t*)ppte |= to_target((uint32_t)ad); + *(target_endian<uint32_t>*)ppte |= to_target((uint32_t)ad); } #else // take exception if access or possibly dirty bit is not set. @@ -395,7 +395,7 @@ reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode, bool virt, bool mxr) if (!ppte || !pmp_ok(pte_paddr, vm.ptesize, LOAD, PRV_S)) throw_access_exception(addr, type); - reg_t pte = vm.ptesize == 4 ? from_target(*(uint32_t*)ppte) : from_target(*(uint64_t*)ppte); + reg_t pte = vm.ptesize == 4 ? from_target(*(target_endian<uint32_t>*)ppte) : from_target(*(target_endian<uint64_t>*)ppte); reg_t ppn = pte >> PTE_PPN_SHIFT; if (PTE_TABLE(pte)) { // next level of page table @@ -417,7 +417,7 @@ reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode, bool virt, bool mxr) if ((pte & ad) != ad) { if (!pmp_ok(pte_paddr, vm.ptesize, STORE, PRV_S)) throw_access_exception(addr, type); - *(uint32_t*)ppte |= to_target((uint32_t)ad); + *(target_endian<uint32_t>*)ppte |= to_target((uint32_t)ad); } #else // take exception if access or possibly dirty bit is not set. diff --git a/riscv/mmu.h b/riscv/mmu.h index dc65891..2acbfb6 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -101,10 +101,10 @@ public: size_t size = sizeof(type##_t); \ if (likely(tlb_load_tag[vpn % TLB_ENTRIES] == vpn)) { \ if (proc) READ_MEM(addr, size); \ - return from_target(*(type##_t*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr)); \ + return from_target(*(target_endian<type##_t>*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr)); \ } \ if (unlikely(tlb_load_tag[vpn % TLB_ENTRIES] == (vpn | TLB_CHECK_TRIGGERS))) { \ - type##_t data = from_target(*(type##_t*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr)); \ + type##_t data = from_target(*(target_endian<type##_t>*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr)); \ if (!matched_trigger) { \ matched_trigger = trigger_exception(OPERATION_LOAD, addr, data); \ if (matched_trigger) \ @@ -113,7 +113,7 @@ public: if (proc) READ_MEM(addr, size); \ return data; \ } \ - type##_t res; \ + target_endian<type##_t> res; \ load_slow_path(addr, sizeof(type##_t), (uint8_t*)&res, (xlate_flags)); \ if (proc) READ_MEM(addr, size); \ if (xlate_flags) \ @@ -165,7 +165,7 @@ public: size_t size = sizeof(type##_t); \ if (likely(tlb_store_tag[vpn % TLB_ENTRIES] == vpn)) { \ if (proc) WRITE_MEM(addr, val, size); \ - *(type##_t*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr) = to_target(val); \ + *(target_endian<type##_t>*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr) = to_target(val); \ } \ else if (unlikely(tlb_store_tag[vpn % TLB_ENTRIES] == (vpn | TLB_CHECK_TRIGGERS))) { \ if (!matched_trigger) { \ @@ -174,10 +174,10 @@ public: throw *matched_trigger; \ } \ if (proc) WRITE_MEM(addr, val, size); \ - *(type##_t*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr) = to_target(val); \ + *(target_endian<type##_t>*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr) = to_target(val); \ } \ else { \ - type##_t target_val = to_target(val); \ + target_endian<type##_t> target_val = to_target(val); \ store_slow_path(addr, sizeof(type##_t), (const uint8_t*)&target_val, (xlate_flags)); \ if (proc) WRITE_MEM(addr, val, size); \ } \ @@ -360,21 +360,21 @@ public: #endif } - template<typename T> inline T from_target(T n) const + template<typename T> inline T from_target(target_endian<T> n) const { #ifdef RISCV_ENABLE_DUAL_ENDIAN - return target_big_endian? from_be(n) : from_le(n); + return target_big_endian? n.from_be() : n.from_le(); #else - return from_le(n); + return n.from_le(); #endif } - template<typename T> inline T to_target(T n) const + template<typename T> inline target_endian<T> to_target(T n) const { #ifdef RISCV_ENABLE_DUAL_ENDIAN - return target_big_endian? to_be(n) : to_le(n); + return target_big_endian? target_endian<T>::to_be(n) : target_endian<T>::to_le(n); #else - return to_le(n); + return target_endian<T>::to_le(n); #endif } @@ -429,7 +429,7 @@ private: result = tlb_data[vpn % TLB_ENTRIES]; } if (unlikely(tlb_insn_tag[vpn % TLB_ENTRIES] == (vpn | TLB_CHECK_TRIGGERS))) { - uint16_t* ptr = (uint16_t*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr); + target_endian<uint16_t>* ptr = (target_endian<uint16_t>*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr); int match = proc->trigger_match(OPERATION_EXECUTE, addr, from_target(*ptr)); if (match >= 0) { throw trigger_matched_t(match, OPERATION_EXECUTE, addr, from_target(*ptr)); diff --git a/riscv/sim.cc b/riscv/sim.cc index ef405c3..6faa1ac 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -336,7 +336,7 @@ void sim_t::read_chunk(addr_t taddr, size_t len, void* dst) void sim_t::write_chunk(addr_t taddr, size_t len, const void* src) { assert(len == 8); - uint64_t data; + target_endian<uint64_t> data; memcpy(&data, src, sizeof data); debug_mmu->store_uint64(taddr, debug_mmu->from_target(data)); } |