diff --git a/riscv/vector_unit.cc b/riscv/vector_unit.cc index 9b8cd2e3..07a776f3 100644 --- a/riscv/vector_unit.cc +++ b/riscv/vector_unit.cc @@ -89,87 +89,7 @@ reg_t vectorUnit_t::vectorUnit_t::set_vl(int rd, int rs1, reg_t reqVL, reg_t new return vl->read(); } -template T& vectorUnit_t::elt(reg_t vReg, reg_t n, bool UNUSED is_write) { - assert(vsew != 0); - assert((VLEN >> 3)/sizeof(T) > 0); - reg_t elts_per_reg = (VLEN >> 3) / (sizeof(T)); - vReg += n / elts_per_reg; - n = n % elts_per_reg; -#ifdef WORDS_BIGENDIAN - // "V" spec 0.7.1 requires lower indices to map to lower significant - // bits when changing SEW, thus we need to index from the end on BE. - n ^= elts_per_reg - 1; -#endif - - if (unlikely(p->get_log_commits_enabled() && is_write)) +void vectorUnit_t::log_elt_write_if_needed(reg_t vReg) const { + if (unlikely(p->get_log_commits_enabled())) p->get_state()->log_reg_write[((vReg) << 4) | 2] = {0, 0}; - - T *regStart = (T*)((char*)reg_file + vReg * (VLEN >> 3)); - return regStart[n]; -} - -// The logic differences between 'elt()' and 'elt_group()' come from -// the fact that, while 'elt()' requires that the element is fully -// contained in a single vector register, the element group may span -// multiple registers in a single register group (LMUL>1). -// -// Notes: -// - We do NOT check that a single element - i.e., the T in the element -// group type std::array - fits within a single register, or that -// T is smaller or equal to VSEW. Implementations of the instructions -// sometimes use a different T than what the specification suggests. -// Instructon implementations should 'require()' what the specification -// dictates. -// - We do NOT check that 'vReg' is a valid register group, or that -// 'n+1' element groups fit in the register group 'vReg'. It is -// the responsibility of the caller to validate those preconditions. -template EG& -vectorUnit_t::elt_group(reg_t vReg, reg_t n, bool UNUSED is_write) { -#ifdef WORDS_BIGENDIAN - fputs("vectorUnit_t::elt_group is not compatible with WORDS_BIGENDIAN setup.\n", - stderr); - abort(); -#endif - using T = typename EG::value_type; - constexpr std::size_t N = std::tuple_size::value; - assert(N > 0); - - assert(vsew != 0); - constexpr reg_t elt_group_size = N * sizeof(T); - const reg_t reg_group_size = (VLEN >> 3) * vflmul; - assert(((n + 1) * elt_group_size) <= reg_group_size); - - const reg_t start_byte = n * elt_group_size; - const reg_t bytes_per_reg = VLEN >> 3; - - // Inclusive first/last register indices. - const reg_t reg_first = vReg + start_byte / bytes_per_reg; - const reg_t reg_last = vReg + (start_byte + elt_group_size - 1) / bytes_per_reg; - - // Element groups per register groups - for (reg_t vidx = reg_first; vidx <= reg_last; ++vidx) { - if (unlikely(p->get_log_commits_enabled() && is_write)) { - p->get_state()->log_reg_write[(vidx << 4) | 2] = {0, 0}; - } - } - - return *(EG*)((char*)reg_file + vReg * (VLEN >> 3) + start_byte); } - -template signed char& vectorUnit_t::elt(reg_t, reg_t, bool); -template short& vectorUnit_t::elt(reg_t, reg_t, bool); -template int& vectorUnit_t::elt(reg_t, reg_t, bool); -template long& vectorUnit_t::elt(reg_t, reg_t, bool); -template long long& vectorUnit_t::elt(reg_t, reg_t, bool); -template uint8_t& vectorUnit_t::elt(reg_t, reg_t, bool); -template uint16_t& vectorUnit_t::elt(reg_t, reg_t, bool); -template uint32_t& vectorUnit_t::elt(reg_t, reg_t, bool); -template uint64_t& vectorUnit_t::elt(reg_t, reg_t, bool); -template float16_t& vectorUnit_t::elt(reg_t, reg_t, bool); -template float32_t& vectorUnit_t::elt(reg_t, reg_t, bool); -template float64_t& vectorUnit_t::elt(reg_t, reg_t, bool); - -template EGU32x4_t& vectorUnit_t::elt_group(reg_t, reg_t, bool); -template EGU32x8_t& vectorUnit_t::elt_group(reg_t, reg_t, bool); -template EGU64x4_t& vectorUnit_t::elt_group(reg_t, reg_t, bool); -template EGU8x16_t& vectorUnit_t::elt_group(reg_t, reg_t, bool); diff --git a/riscv/vector_unit.h b/riscv/vector_unit.h index bfd256eb..88d4399d 100644 --- a/riscv/vector_unit.h +++ b/riscv/vector_unit.h @@ -103,10 +103,71 @@ public: bool vstart_alu = false; // vector element for various SEW - template T& elt(reg_t vReg, reg_t n, bool is_write = false); + template T& elt(reg_t vReg, reg_t n, bool is_write = false) { + assert(vsew != 0); + assert((VLEN >> 3)/sizeof(T) > 0); + reg_t elts_per_reg = (VLEN >> 3) / (sizeof(T)); + vReg += n / elts_per_reg; + n = n % elts_per_reg; +#ifdef WORDS_BIGENDIAN + // "V" spec 0.7.1 requires lower indices to map to lower significant + // bits when changing SEW, thus we need to index from the end on BE. + n ^= elts_per_reg - 1; +#endif + if (is_write) + log_elt_write_if_needed(vReg); + + T *regStart = (T*)((char*)reg_file + vReg * (VLEN >> 3)); + return regStart[n]; + } + // vector element group access, where EG is a std::array. + // The logic differences between 'elt()' and 'elt_group()' come from + // the fact that, while 'elt()' requires that the element is fully + // contained in a single vector register, the element group may span + // multiple registers in a single register group (LMUL>1). + // + // Notes: + // - We do NOT check that a single element - i.e., the T in the element + // group type std::array - fits within a single register, or that + // T is smaller or equal to VSEW. Implementations of the instructions + // sometimes use a different T than what the specification suggests. + // Instructon implementations should 'require()' what the specification + // dictates. + // - We do NOT check that 'vReg' is a valid register group, or that + // 'n+1' element groups fit in the register group 'vReg'. It is + // the responsibility of the caller to validate those preconditions. + template EG& - elt_group(reg_t vReg, reg_t n, bool is_write = false); + elt_group(reg_t vReg, reg_t n, bool is_write = false) { +#ifdef WORDS_BIGENDIAN + fputs("vectorUnit_t::elt_group is not compatible with WORDS_BIGENDIAN setup.\n", + stderr); + abort(); +#endif + using T = typename EG::value_type; + constexpr std::size_t N = std::tuple_size::value; + assert(N > 0); + + assert(vsew != 0); + constexpr reg_t elt_group_size = N * sizeof(T); + const reg_t reg_group_size = (VLEN >> 3) * vflmul; + assert(((n + 1) * elt_group_size) <= reg_group_size); + + const reg_t start_byte = n * elt_group_size; + const reg_t bytes_per_reg = VLEN >> 3; + + // Inclusive first/last register indices. + const reg_t reg_first = vReg + start_byte / bytes_per_reg; + const reg_t reg_last = vReg + (start_byte + elt_group_size - 1) / bytes_per_reg; + + // Element groups per register groups + for (reg_t vidx = reg_first; vidx <= reg_last; ++vidx) + if (is_write) + log_elt_write_if_needed(vidx); + + return *(EG*)((char*)reg_file + vReg * (VLEN >> 3) + start_byte); + } bool mask_elt(reg_t vReg, reg_t n) { @@ -119,6 +180,10 @@ public: e = (e & ~(1U << (n % 8))) | (value << (n % 8)); } +private: + + void log_elt_write_if_needed(reg_t vReg) const; + public: void reset();