You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
208 lines
4.8 KiB
208 lines
4.8 KiB
// See LICENSE for license details.
|
|
#ifndef _RISCV_VECTOR_UNIT_H
|
|
#define _RISCV_VECTOR_UNIT_H
|
|
|
|
#include <array>
|
|
#include <cstdint>
|
|
|
|
#include "decode.h"
|
|
#include "csrs.h"
|
|
|
|
class processor_t;
|
|
|
|
enum VRM{
|
|
RNU = 0,
|
|
RNE,
|
|
RDN,
|
|
ROD,
|
|
INVALID_RM
|
|
};
|
|
|
|
template<uint64_t N>
|
|
struct type_usew_t;
|
|
|
|
template<>
|
|
struct type_usew_t<8>
|
|
{
|
|
using type=uint8_t;
|
|
};
|
|
|
|
template<>
|
|
struct type_usew_t<16>
|
|
{
|
|
using type=uint16_t;
|
|
};
|
|
|
|
template<>
|
|
struct type_usew_t<32>
|
|
{
|
|
using type=uint32_t;
|
|
};
|
|
|
|
template<>
|
|
struct type_usew_t<64>
|
|
{
|
|
using type=uint64_t;
|
|
};
|
|
|
|
template<uint64_t N>
|
|
struct type_sew_t;
|
|
|
|
template<>
|
|
struct type_sew_t<8>
|
|
{
|
|
using type=int8_t;
|
|
};
|
|
|
|
template<>
|
|
struct type_sew_t<16>
|
|
{
|
|
using type=int16_t;
|
|
};
|
|
|
|
template<>
|
|
struct type_sew_t<32>
|
|
{
|
|
using type=int32_t;
|
|
};
|
|
|
|
template<>
|
|
struct type_sew_t<64>
|
|
{
|
|
using type=int64_t;
|
|
};
|
|
|
|
// Element Group of 4 32 bits elements (128b total).
|
|
using EGU32x4_t = std::array<uint32_t, 4>;
|
|
|
|
// Element Group of 8 32 bits elements (256b total).
|
|
using EGU32x8_t = std::array<uint32_t, 8>;
|
|
|
|
// Element Group of 4 64 bits elements (256b total).
|
|
using EGU64x4_t = std::array<uint64_t, 4>;
|
|
|
|
// Element Group of 16 8 bits elements (128b total).
|
|
using EGU8x16_t = std::array<uint8_t, 16>;
|
|
|
|
class vectorUnit_t
|
|
{
|
|
public:
|
|
processor_t* p = nullptr;
|
|
void *reg_file = nullptr;
|
|
int setvl_count = 0;
|
|
reg_t vlmax = 0;
|
|
reg_t vlenb = 0;
|
|
csr_t_p vxsat = 0;
|
|
vector_csr_t_p vxrm = 0, vstart = 0, vl = 0, vtype = 0;
|
|
reg_t vma = 0, vta = 0;
|
|
reg_t vsew = 0;
|
|
float vflmul = 0;
|
|
reg_t altfmt = 0;
|
|
reg_t ELEN = 0, VLEN = 0;
|
|
bool vill = false;
|
|
bool vstart_alu = false;
|
|
|
|
// vector element for various SEW
|
|
template<typename T> 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<T, 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<T, N> - 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<typename EG> EG&
|
|
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<EG>::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)
|
|
{
|
|
return (elt<uint8_t>(vReg, n / 8) >> (n % 8)) & 1;
|
|
}
|
|
|
|
void set_mask_elt(reg_t vReg, reg_t n, bool value)
|
|
{
|
|
auto& e = elt<uint8_t>(vReg, n / 8, true);
|
|
e = (e & ~(1U << (n % 8))) | (value << (n % 8));
|
|
}
|
|
|
|
private:
|
|
|
|
void log_elt_write_if_needed(reg_t vReg) const;
|
|
|
|
public:
|
|
|
|
void reset();
|
|
|
|
vectorUnit_t() {}
|
|
|
|
~vectorUnit_t() {
|
|
free(reg_file);
|
|
reg_file = 0;
|
|
}
|
|
|
|
reg_t set_vl(int rd, int rs1, reg_t reqVL, reg_t newType);
|
|
|
|
reg_t get_vlen() { return VLEN; }
|
|
reg_t get_elen() { return ELEN; }
|
|
reg_t get_slen() { return VLEN; }
|
|
|
|
VRM get_vround_mode() {
|
|
return (VRM)(vxrm->read());
|
|
}
|
|
};
|
|
#endif
|
|
|