Browse Source

Tag target endian values to help guide conversion code

pull/575/head
Marcus Comstedt 6 years ago
parent
commit
8e3bcb2eef
  1. 4
      fesvr/htif.cc
  2. 12
      fesvr/htif.h
  3. 48
      fesvr/memif.cc
  4. 33
      fesvr/memif.h
  5. 8
      fesvr/syscall.cc
  6. 64
      riscv/byteorder.h
  7. 8
      riscv/mmu.cc
  8. 26
      riscv/mmu.h
  9. 2
      riscv/sim.cc

4
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();
}

12
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
}

48
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;
}

33
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) {

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

64
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

8
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.

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

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

Loading…
Cancel
Save