176 lines
10 KiB
C++
176 lines
10 KiB
C++
#include "tgc_c.h"
|
|
#include <vector>
|
|
#include <array>
|
|
#include <cstdlib>
|
|
#include <algorithm>
|
|
|
|
namespace iss {
|
|
namespace arch {
|
|
namespace {
|
|
// according to
|
|
// https://stackoverflow.com/questions/8871204/count-number-of-1s-in-binary-representation
|
|
#ifdef __GCC__
|
|
constexpr size_t bit_count(uint32_t u) { return __builtin_popcount(u); }
|
|
#elif __cplusplus < 201402L
|
|
constexpr size_t uCount(uint32_t u) { return u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111); }
|
|
constexpr size_t bit_count(uint32_t u) { return ((uCount(u) + (uCount(u) >> 3)) & 030707070707) % 63; }
|
|
#else
|
|
constexpr size_t bit_count(uint32_t u) {
|
|
size_t uCount = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
|
|
return ((uCount + (uCount >> 3)) & 030707070707) % 63;
|
|
}
|
|
#endif
|
|
|
|
using opcode_e = traits<tgc_c>::opcode_e;
|
|
|
|
/****************************************************************************
|
|
* start opcode definitions
|
|
****************************************************************************/
|
|
struct instruction_desriptor {
|
|
size_t length;
|
|
uint32_t value;
|
|
uint32_t mask;
|
|
opcode_e op;
|
|
};
|
|
|
|
const std::array<instruction_desriptor, 90> instr_descr = {{
|
|
/* entries are: size, valid value, valid mask, function ptr */
|
|
{32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, opcode_e::LUI},
|
|
{32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, opcode_e::AUIPC},
|
|
{32, 0b00000000000000000000000001101111, 0b00000000000000000000000001111111, opcode_e::JAL},
|
|
{32, 0b00000000000000000000000001100111, 0b00000000000000000111000001111111, opcode_e::JALR},
|
|
{32, 0b00000000000000000000000001100011, 0b00000000000000000111000001111111, opcode_e::BEQ},
|
|
{32, 0b00000000000000000001000001100011, 0b00000000000000000111000001111111, opcode_e::BNE},
|
|
{32, 0b00000000000000000100000001100011, 0b00000000000000000111000001111111, opcode_e::BLT},
|
|
{32, 0b00000000000000000101000001100011, 0b00000000000000000111000001111111, opcode_e::BGE},
|
|
{32, 0b00000000000000000110000001100011, 0b00000000000000000111000001111111, opcode_e::BLTU},
|
|
{32, 0b00000000000000000111000001100011, 0b00000000000000000111000001111111, opcode_e::BGEU},
|
|
{32, 0b00000000000000000000000000000011, 0b00000000000000000111000001111111, opcode_e::LB},
|
|
{32, 0b00000000000000000001000000000011, 0b00000000000000000111000001111111, opcode_e::LH},
|
|
{32, 0b00000000000000000010000000000011, 0b00000000000000000111000001111111, opcode_e::LW},
|
|
{32, 0b00000000000000000100000000000011, 0b00000000000000000111000001111111, opcode_e::LBU},
|
|
{32, 0b00000000000000000101000000000011, 0b00000000000000000111000001111111, opcode_e::LHU},
|
|
{32, 0b00000000000000000000000000100011, 0b00000000000000000111000001111111, opcode_e::SB},
|
|
{32, 0b00000000000000000001000000100011, 0b00000000000000000111000001111111, opcode_e::SH},
|
|
{32, 0b00000000000000000010000000100011, 0b00000000000000000111000001111111, opcode_e::SW},
|
|
{32, 0b00000000000000000000000000010011, 0b00000000000000000111000001111111, opcode_e::ADDI},
|
|
{32, 0b00000000000000000010000000010011, 0b00000000000000000111000001111111, opcode_e::SLTI},
|
|
{32, 0b00000000000000000011000000010011, 0b00000000000000000111000001111111, opcode_e::SLTIU},
|
|
{32, 0b00000000000000000100000000010011, 0b00000000000000000111000001111111, opcode_e::XORI},
|
|
{32, 0b00000000000000000110000000010011, 0b00000000000000000111000001111111, opcode_e::ORI},
|
|
{32, 0b00000000000000000111000000010011, 0b00000000000000000111000001111111, opcode_e::ANDI},
|
|
{32, 0b00000000000000000001000000010011, 0b11111110000000000111000001111111, opcode_e::SLLI},
|
|
{32, 0b00000000000000000101000000010011, 0b11111110000000000111000001111111, opcode_e::SRLI},
|
|
{32, 0b01000000000000000101000000010011, 0b11111110000000000111000001111111, opcode_e::SRAI},
|
|
{32, 0b00000000000000000000000000110011, 0b11111110000000000111000001111111, opcode_e::ADD},
|
|
{32, 0b01000000000000000000000000110011, 0b11111110000000000111000001111111, opcode_e::SUB},
|
|
{32, 0b00000000000000000001000000110011, 0b11111110000000000111000001111111, opcode_e::SLL},
|
|
{32, 0b00000000000000000010000000110011, 0b11111110000000000111000001111111, opcode_e::SLT},
|
|
{32, 0b00000000000000000011000000110011, 0b11111110000000000111000001111111, opcode_e::SLTU},
|
|
{32, 0b00000000000000000100000000110011, 0b11111110000000000111000001111111, opcode_e::XOR},
|
|
{32, 0b00000000000000000101000000110011, 0b11111110000000000111000001111111, opcode_e::SRL},
|
|
{32, 0b01000000000000000101000000110011, 0b11111110000000000111000001111111, opcode_e::SRA},
|
|
{32, 0b00000000000000000110000000110011, 0b11111110000000000111000001111111, opcode_e::OR},
|
|
{32, 0b00000000000000000111000000110011, 0b11111110000000000111000001111111, opcode_e::AND},
|
|
{32, 0b00000000000000000000000000001111, 0b00000000000000000111000001111111, opcode_e::FENCE},
|
|
{32, 0b00000000000000000000000001110011, 0b11111111111111111111111111111111, opcode_e::ECALL},
|
|
{32, 0b00000000000100000000000001110011, 0b11111111111111111111111111111111, opcode_e::EBREAK},
|
|
{32, 0b00000000001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::URET},
|
|
{32, 0b00010000001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::SRET},
|
|
{32, 0b00110000001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::MRET},
|
|
{32, 0b00010000010100000000000001110011, 0b11111111111111111111111111111111, opcode_e::WFI},
|
|
{32, 0b01111011001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::DRET},
|
|
{32, 0b00000000000000000001000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRW},
|
|
{32, 0b00000000000000000010000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRS},
|
|
{32, 0b00000000000000000011000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRC},
|
|
{32, 0b00000000000000000101000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRWI},
|
|
{32, 0b00000000000000000110000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRSI},
|
|
{32, 0b00000000000000000111000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRCI},
|
|
{32, 0b00000000000000000001000000001111, 0b00000000000000000111000001111111, opcode_e::FENCE_I},
|
|
{32, 0b00000010000000000000000000110011, 0b11111110000000000111000001111111, opcode_e::MUL},
|
|
{32, 0b00000010000000000001000000110011, 0b11111110000000000111000001111111, opcode_e::MULH},
|
|
{32, 0b00000010000000000010000000110011, 0b11111110000000000111000001111111, opcode_e::MULHSU},
|
|
{32, 0b00000010000000000011000000110011, 0b11111110000000000111000001111111, opcode_e::MULHU},
|
|
{32, 0b00000010000000000100000000110011, 0b11111110000000000111000001111111, opcode_e::DIV},
|
|
{32, 0b00000010000000000101000000110011, 0b11111110000000000111000001111111, opcode_e::DIVU},
|
|
{32, 0b00000010000000000110000000110011, 0b11111110000000000111000001111111, opcode_e::REM},
|
|
{32, 0b00000010000000000111000000110011, 0b11111110000000000111000001111111, opcode_e::REMU},
|
|
{16, 0b0000000000000000, 0b1110000000000011, opcode_e::CADDI4SPN},
|
|
{16, 0b0100000000000000, 0b1110000000000011, opcode_e::CLW},
|
|
{16, 0b1100000000000000, 0b1110000000000011, opcode_e::CSW},
|
|
{16, 0b0000000000000001, 0b1110000000000011, opcode_e::CADDI},
|
|
{16, 0b0000000000000001, 0b1110111110000011, opcode_e::CNOP},
|
|
{16, 0b0010000000000001, 0b1110000000000011, opcode_e::CJAL},
|
|
{16, 0b0100000000000001, 0b1110000000000011, opcode_e::CLI},
|
|
{16, 0b0110000000000001, 0b1110000000000011, opcode_e::CLUI},
|
|
{16, 0b0110000100000001, 0b1110111110000011, opcode_e::CADDI16SP},
|
|
{16, 0b0110000000000001, 0b1111000001111111, opcode_e::__reserved_clui},
|
|
{16, 0b1000000000000001, 0b1111110000000011, opcode_e::CSRLI},
|
|
{16, 0b1000010000000001, 0b1111110000000011, opcode_e::CSRAI},
|
|
{16, 0b1000100000000001, 0b1110110000000011, opcode_e::CANDI},
|
|
{16, 0b1000110000000001, 0b1111110001100011, opcode_e::CSUB},
|
|
{16, 0b1000110000100001, 0b1111110001100011, opcode_e::CXOR},
|
|
{16, 0b1000110001000001, 0b1111110001100011, opcode_e::COR},
|
|
{16, 0b1000110001100001, 0b1111110001100011, opcode_e::CAND},
|
|
{16, 0b1010000000000001, 0b1110000000000011, opcode_e::CJ},
|
|
{16, 0b1100000000000001, 0b1110000000000011, opcode_e::CBEQZ},
|
|
{16, 0b1110000000000001, 0b1110000000000011, opcode_e::CBNEZ},
|
|
{16, 0b0000000000000010, 0b1111000000000011, opcode_e::CSLLI},
|
|
{16, 0b0100000000000010, 0b1110000000000011, opcode_e::CLWSP},
|
|
{16, 0b1000000000000010, 0b1111000000000011, opcode_e::CMV},
|
|
{16, 0b1000000000000010, 0b1111000001111111, opcode_e::CJR},
|
|
{16, 0b1000000000000010, 0b1111111111111111, opcode_e::__reserved_cmv},
|
|
{16, 0b1001000000000010, 0b1111000000000011, opcode_e::CADD},
|
|
{16, 0b1001000000000010, 0b1111000001111111, opcode_e::CJALR},
|
|
{16, 0b1001000000000010, 0b1111111111111111, opcode_e::CEBREAK},
|
|
{16, 0b1100000000000010, 0b1110000000000011, opcode_e::CSWSP},
|
|
{16, 0b0000000000000000, 0b1111111111111111, opcode_e::DII},
|
|
}};
|
|
|
|
}
|
|
|
|
template<>
|
|
struct instruction_decoder<tgc_c> {
|
|
using opcode_e = traits<tgc_c>::opcode_e;
|
|
using code_word_t=traits<tgc_c>::code_word_t;
|
|
|
|
struct instruction_pattern {
|
|
uint32_t value;
|
|
uint32_t mask;
|
|
opcode_e id;
|
|
};
|
|
|
|
std::array<std::vector<instruction_pattern>, 4> qlut;
|
|
|
|
template<typename T>
|
|
unsigned decode_instruction(T);
|
|
|
|
instruction_decoder() {
|
|
for (auto instr : instr_descr) {
|
|
auto quadrant = instr.value & 0x3;
|
|
qlut[quadrant].push_back(instruction_pattern{instr.value, instr.mask, instr.op});
|
|
}
|
|
for(auto& lut: qlut){
|
|
std::sort(std::begin(lut), std::end(lut), [](instruction_pattern const& a, instruction_pattern const& b){
|
|
return bit_count(a.mask) > bit_count(b.mask);
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
template<>
|
|
unsigned instruction_decoder<tgc_c>::decode_instruction<traits<tgc_c>::code_word_t>(traits<tgc_c>::code_word_t instr){
|
|
auto res = std::find_if(std::begin(qlut[instr&0x3]), std::end(qlut[instr&0x3]), [instr](instruction_pattern const& e){
|
|
return !((instr&e.mask) ^ e.value );
|
|
});
|
|
return static_cast<unsigned>(res!=std::end(qlut[instr&0x3])? res->id : opcode_e::MAX_OPCODE);
|
|
}
|
|
|
|
|
|
std::unique_ptr<instruction_decoder<tgc_c>> traits<tgc_c>::get_decoder(){
|
|
return std::make_unique<instruction_decoder<tgc_c>>();
|
|
}
|
|
|
|
}
|
|
}
|