Browse Source

[WIP] started to add TinyCC backend

develop
Eyck Jentzsch 1 month ago
parent
commit
116ed9bb5c

+ 11
- 12
CMakeLists.txt View File

@@ -44,15 +44,17 @@ add_subdirectory(softfloat)
FILE(GLOB RiscVSCHeaders ${CMAKE_CURRENT_SOURCE_DIR}/incl/sysc/*.h ${CMAKE_CURRENT_SOURCE_DIR}/incl/sysc/*/*.h)
set(LIB_HEADERS ${RiscVSCHeaders} )
set(LIB_SOURCES
src/iss/rv32gc.cpp
#src/iss/rv32gc.cpp
src/iss/rv32imac.cpp
src/iss/rv64i.cpp
src/iss/rv64gc.cpp
src/internal/fp_functions.cpp
src/internal/vm_rv32gc.cpp
src/internal/vm_rv32imac.cpp
src/internal/vm_rv64i.cpp
src/internal/vm_rv64gc.cpp
#src/iss/rv64i.cpp
#src/iss/rv64gc.cpp
src/iss/mnrv32.cpp
src/vm/llvm/fp_functions.cpp
#src/vm/llvm/vm_rv32gc.cpp
src/vm/llvm/vm_rv32imac.cpp
#src/vm/llvm/vm_rv64i.cpp
#src/vm/llvm/vm_rv64gc.cpp
src/vm/tcc/vm_mnrv32.cpp
src/plugin/instruction_count.cpp
src/plugin/cycle_estimate.cpp)

@@ -62,15 +64,12 @@ set(LIBRARY_NAME riscv)
# Define the library
add_library(${LIBRARY_NAME} ${LIB_SOURCES})
SET(${LIBRARY_NAME} -Wl,-whole-archive -l${LIBRARY_NAME} -Wl,-no-whole-archive)
target_link_libraries(${LIBRARY_NAME} softfloat)
target_link_libraries(${LIBRARY_NAME} dbt-core)
target_link_libraries(${LIBRARY_NAME} scc-util)
target_link_libraries(${LIBRARY_NAME} softfloat dbt-core tinycc scc-util)
set_target_properties(${LIBRARY_NAME} PROPERTIES
VERSION ${VERSION} # ${VERSION} was defined in the main CMakeLists.
FRAMEWORK FALSE
PUBLIC_HEADER "${LIB_HEADERS}" # specify the public headers
)
#set_property(TARGET ${LIBRARY_NAME} PROPERTY POSITION_INDEPENDENT_CODE ON)

if(SystemC_FOUND)
set(SC_LIBRARY_NAME riscv_sc)

+ 12
- 0
gen_input/minres_rv.core_desc View File

@@ -6,6 +6,18 @@ import "RVC.core_desc"
import "RVF.core_desc"
import "RVD.core_desc"

Core MNRV32 provides RV32I/*, RV32IC */ {
constants {
XLEN:=32;
PCLEN:=32;
// definitions for the architecture wrapper
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
MISA_VAL:=0b01000000000101000001000100000101;
PGSIZE := 0x1000; //1 << 12;
PGMASK := 0xfff; //PGSIZE-1
}
}

Core RV32IMAC provides RV32I, RV32M, RV32A, RV32IC {
constants {
XLEN:=32;

+ 9
- 0
gen_input/templates/tcc/CORENAME_cyles.txt.gtl View File

@@ -0,0 +1,9 @@
{
"${coreDef.name}" : [<%instructions.eachWithIndex{instr,index -> %>${index==0?"":","}
{
"name" : "${instr.name}",
"size" : ${instr.length},
"delay" : ${generator.hasAttribute(instr.instruction, com.minres.coredsl.coreDsl.InstrAttribute.COND)?[1,1]:1}
}<%}%>
]
}

+ 221
- 0
gen_input/templates/tcc/incl-CORENAME.h.gtl View File

@@ -0,0 +1,221 @@
/*******************************************************************************
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/

<%
import com.minres.coredsl.coreDsl.Register
import com.minres.coredsl.coreDsl.RegisterFile
import com.minres.coredsl.coreDsl.RegisterAlias
def getTypeSize(size){
if(size > 32) 64 else if(size > 16) 32 else if(size > 8) 16 else 8
}
def getOriginalName(reg){
if( reg.original instanceof RegisterFile) {
if( reg.index != null ) {
return reg.original.name+generator.generateHostCode(reg.index)
} else {
return reg.original.name
}
} else if(reg.original instanceof Register){
return reg.original.name
}
}
def getRegisterNames(){
def regNames = []
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{
regNames+=reg.name.toLowerCase()+it
}
} else if(reg instanceof Register){
regNames+=reg.name.toLowerCase()
}
}
return regNames
}
def getRegisterAliasNames(){
def regMap = allRegs.findAll{it instanceof RegisterAlias }.collectEntries {[getOriginalName(it), it.name]}
return allRegs.findAll{it instanceof Register || it instanceof RegisterFile}.collect{reg ->
if( reg instanceof RegisterFile) {
return (reg.range.right..reg.range.left).collect{ (regMap[reg.name]?:regMap[reg.name+it]?:reg.name.toLowerCase()+it).toLowerCase() }
} else if(reg instanceof Register){
regMap[reg.name]?:reg.name.toLowerCase()
}
}.flatten()
}
%>
#ifndef _${coreDef.name.toUpperCase()}_H_
#define _${coreDef.name.toUpperCase()}_H_

#include <array>
#include <iss/arch/traits.h>
#include <iss/arch_if.h>
#include <iss/vm_if.h>

namespace iss {
namespace arch {

struct ${coreDef.name.toLowerCase()};

template <> struct traits<${coreDef.name.toLowerCase()}> {

constexpr static char const* const core_type = "${coreDef.name}";
static constexpr std::array<const char*, ${getRegisterNames().size}> reg_names{
{"${getRegisterNames().join("\", \"")}"}};
static constexpr std::array<const char*, ${getRegisterAliasNames().size}> reg_aliases{
{"${getRegisterAliasNames().join("\", \"")}"}};

enum constants {${coreDef.constants.collect{c -> c.name+"="+c.value}.join(', ')}};

constexpr static unsigned FP_REGS_SIZE = ${coreDef.constants.find {it.name=='FLEN'}?.value?:0};

enum reg_e {<%
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{%>
${reg.name}${it},<%
}
} else if(reg instanceof Register){ %>
${reg.name},<%
}
}%>
NUM_REGS,
NEXT_${pc.name}=NUM_REGS,
TRAP_STATE,
PENDING_TRAP,
MACHINE_STATE,
LAST_BRANCH,
ICOUNT<%
allRegs.each { reg ->
if(reg instanceof RegisterAlias){ def aliasname=getOriginalName(reg)%>,
${reg.name} = ${aliasname}<%
}
}%>
};

using reg_t = uint${regDataWidth}_t;

using addr_t = uint${addrDataWidth}_t;

using code_word_t = uint${addrDataWidth}_t; //TODO: check removal

using virt_addr_t = iss::typed_addr_t<iss::address_type::VIRTUAL>;

using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;

static constexpr std::array<const uint32_t, ${regSizes.size}> reg_bit_widths{
{${regSizes.join(",")}}};

static constexpr std::array<const uint32_t, ${regOffsets.size}> reg_byte_offsets{
{${regOffsets.join(",")}}};

static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);

enum sreg_flag_e { FLAGS };

enum mem_type_e { ${allSpaces.collect{s -> s.name}.join(', ')} };
};

struct ${coreDef.name.toLowerCase()}: public arch_if {

using virt_addr_t = typename traits<${coreDef.name.toLowerCase()}>::virt_addr_t;
using phys_addr_t = typename traits<${coreDef.name.toLowerCase()}>::phys_addr_t;
using reg_t = typename traits<${coreDef.name.toLowerCase()}>::reg_t;
using addr_t = typename traits<${coreDef.name.toLowerCase()}>::addr_t;

${coreDef.name.toLowerCase()}();
~${coreDef.name.toLowerCase()}();

void reset(uint64_t address=0) override;

uint8_t* get_regs_base_ptr() override;
/// deprecated
void get_reg(short idx, std::vector<uint8_t>& value) override {}
void set_reg(short idx, const std::vector<uint8_t>& value) override {}
/// deprecated
bool get_flag(int flag) override {return false;}
void set_flag(int, bool value) override {};
/// deprecated
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};

inline uint64_t get_icount() { return reg.icount; }

inline bool should_stop() { return interrupt_sim; }

inline phys_addr_t v2p(const iss::addr_t& addr){
if (addr.space != traits<${coreDef.name.toLowerCase()}>::MEM || addr.type == iss::address_type::PHYSICAL ||
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) {
return phys_addr_t(addr.access, addr.space, addr.val&traits<${coreDef.name.toLowerCase()}>::addr_mask);
} else
return virt2phys(addr);
}

virtual phys_addr_t virt2phys(const iss::addr_t& addr);

virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }

inline uint32_t get_last_branch() { return reg.last_branch; }

protected:
struct ${coreDef.name}_regs {<%
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{%>
uint${generator.getSize(reg)}_t ${reg.name}${it} = 0;<%
}
} else if(reg instanceof Register){ %>
uint${generator.getSize(reg)}_t ${reg.name} = 0;<%
}
}%>
uint${generator.getSize(pc)}_t NEXT_${pc.name} = 0;
uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0;
uint64_t icount = 0;
} reg;

std::array<address_type, 4> addr_mode;
bool interrupt_sim=false;
<%
def fcsr = allRegs.find {it.name=='FCSR'}
if(fcsr != null) {%>
uint${generator.getSize(fcsr)}_t get_fcsr(){return reg.FCSR;}
void set_fcsr(uint${generator.getSize(fcsr)}_t val){reg.FCSR = val;}
<%} else { %>
uint32_t get_fcsr(){return 0;}
void set_fcsr(uint32_t val){}
<%}%>
};

}
}
#endif /* _${coreDef.name.toUpperCase()}_H_ */

+ 117
- 0
gen_input/templates/tcc/src-CORENAME.cpp.gtl View File

@@ -0,0 +1,117 @@
/*******************************************************************************
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
<%
import com.minres.coredsl.coreDsl.Register
import com.minres.coredsl.coreDsl.RegisterFile
import com.minres.coredsl.coreDsl.RegisterAlias
def getOriginalName(reg){
if( reg.original instanceof RegisterFile) {
if( reg.index != null ) {
return reg.original.name+generator.generateHostCode(reg.index)
} else {
return reg.original.name
}
} else if(reg.original instanceof Register){
return reg.original.name
}
}
def getRegisterNames(){
def regNames = []
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{
regNames+=reg.name.toLowerCase()+it
}
} else if(reg instanceof Register){
regNames+=reg.name.toLowerCase()
}
}
return regNames
}
def getRegisterAliasNames(){
def regMap = allRegs.findAll{it instanceof RegisterAlias }.collectEntries {[getOriginalName(it), it.name]}
return allRegs.findAll{it instanceof Register || it instanceof RegisterFile}.collect{reg ->
if( reg instanceof RegisterFile) {
return (reg.range.right..reg.range.left).collect{ (regMap[reg.name]?:regMap[reg.name+it]?:reg.name.toLowerCase()+it).toLowerCase() }
} else if(reg instanceof Register){
regMap[reg.name]?:reg.name.toLowerCase()
}
}.flatten()
}
%>
#include "util/ities.h"
#include <util/logging.h>

#include <elfio/elfio.hpp>
#include <iss/arch/${coreDef.name.toLowerCase()}.h>

#ifdef __cplusplus
extern "C" {
#endif
#include <ihex.h>
#ifdef __cplusplus
}
#endif
#include <cstdio>
#include <cstring>
#include <fstream>

using namespace iss::arch;

constexpr std::array<const char*, ${getRegisterNames().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_names;
constexpr std::array<const char*, ${getRegisterAliasNames().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_aliases;
constexpr std::array<const uint32_t, ${regSizes.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_bit_widths;
constexpr std::array<const uint32_t, ${regOffsets.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_byte_offsets;

${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() {
reg.icount = 0;
}

${coreDef.name.toLowerCase()}::~${coreDef.name.toLowerCase()}() = default;

void ${coreDef.name.toLowerCase()}::reset(uint64_t address) {
for(size_t i=0; i<traits<${coreDef.name.toLowerCase()}>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<${coreDef.name.toLowerCase()}>::reg_t),0));
reg.PC=address;
reg.NEXT_PC=reg.PC;
reg.trap_state=0;
reg.machine_state=0x3;
reg.icount=0;
}

uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() {
return reinterpret_cast<uint8_t*>(&reg);
}

${coreDef.name.toLowerCase()}::phys_addr_t ${coreDef.name.toLowerCase()}::virt2phys(const iss::addr_t &pc) {
return phys_addr_t(pc); // change logical address to physical address
}


+ 327
- 0
gen_input/templates/tcc/vm-vm_CORENAME.cpp.gtl View File

@@ -0,0 +1,327 @@
/*******************************************************************************
* Copyright (C) 2020 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/

#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <iss/arch/riscv_hart_msu_vp.h>
#include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h>
#include <iss/iss.h>
#include <iss/llvm/vm_base.h>
#include <util/logging.h>
#include <strstream>

#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#include <fmt/format.h>

#include <array>
#include <iss/debugger/riscv_target_adapter.h>

namespace iss {
namespace vm {
namespace fp_impl {
void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned);
}
}

namespace tcc {
namespace ${coreDef.name.toLowerCase()} {
using namespace iss::arch;
using namespace iss::debugger;
using namespace iss::vm::llvm;

template <typename ARCH> class vm_impl : public vm_base<ARCH> {
public:
using super = typename iss::vm::llvm::vm_base<ARCH>;
using virt_addr_t = typename super::virt_addr_t;
using phys_addr_t = typename super::phys_addr_t;
using code_word_t = typename super::code_word_t;
using addr_t = typename super::addr_t;

vm_impl();

vm_impl(ARCH &core, unsigned core_id = 0, unsigned cluster_id = 0);

void enableDebug(bool enable) { super::sync_exec = super::ALL_SYNC; }

target_adapter_if *accquire_target_adapter(server_if *srv) override {
debugger_if::dbg_enabled = true;
if (vm_base<ARCH>::tgt_adapter == nullptr)
vm_base<ARCH>::tgt_adapter = new riscv_target_adapter<ARCH>(srv, this->get_arch());
return vm_base<ARCH>::tgt_adapter;
}

protected:
using vm_base<ARCH>::get_reg_ptr;

using this_class = vm_impl<ARCH>;
using compile_ret_t = std::tuple<continuation_e>;
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, std::ostringstream&);

inline const char *name(size_t index){return traits<ARCH>::reg_aliases.at(index);}

template <typename T> inline ConstantInt *size(T type) {
return ConstantInt::get(getContext(), APInt(32, type->getType()->getScalarSizeInBits()));
}

void setup_module(Module* m) override {
super::setup_module(m);
iss::vm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN);
}

inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) {
return super::gen_cond_assign(cond, this->gen_ext(trueVal, size), this->gen_ext(falseVal, size));
}

compile_ret_t gen_single_inst_behavior(virt_addr_t &, unsigned int &, std::ostringstream&) override;

void gen_leave_behavior(BasicBlock *leave_blk) override;

void gen_raise_trap(uint16_t trap_id, uint16_t cause);

void gen_leave_trap(unsigned lvl);

void gen_wait(unsigned type);

void gen_trap_behavior(BasicBlock *) override;

void gen_trap_check(BasicBlock *bb);

inline Value *gen_reg_load(unsigned i, unsigned level = 0) {
return this->builder.CreateLoad(get_reg_ptr(i), false);
}

inline void gen_set_pc(virt_addr_t pc, unsigned reg_num) {
Value *next_pc_v = this->builder.CreateSExtOrTrunc(this->gen_const(traits<ARCH>::XLEN, pc.val),
this->get_type(traits<ARCH>::XLEN));
this->builder.CreateStore(next_pc_v, get_reg_ptr(reg_num), true);
}

// some compile time constants
// enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 };
enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 };
enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 };
enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) };

std::array<compile_func, LUT_SIZE> lut;

std::array<compile_func, LUT_SIZE_C> lut_00, lut_01, lut_10;
std::array<compile_func, LUT_SIZE> lut_11;

std::array<compile_func *, 4> qlut;

std::array<const uint32_t, 4> lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}};

void expand_bit_mask(int pos, uint32_t mask, uint32_t value, uint32_t valid, uint32_t idx, compile_func lut[],
compile_func f) {
if (pos < 0) {
lut[idx] = f;
} else {
auto bitmask = 1UL << pos;
if ((mask & bitmask) == 0) {
expand_bit_mask(pos - 1, mask, value, valid, idx, lut, f);
} else {
if ((valid & bitmask) == 0) {
expand_bit_mask(pos - 1, mask, value, valid, (idx << 1), lut, f);
expand_bit_mask(pos - 1, mask, value, valid, (idx << 1) + 1, lut, f);
} else {
auto new_val = idx << 1;
if ((value & bitmask) != 0) new_val++;
expand_bit_mask(pos - 1, mask, value, valid, new_val, lut, f);
}
}
}
}

inline uint32_t extract_fields(uint32_t val) { return extract_fields(29, val >> 2, lutmasks[val & 0x3], 0); }

uint32_t extract_fields(int pos, uint32_t val, uint32_t mask, uint32_t lut_val) {
if (pos >= 0) {
auto bitmask = 1UL << pos;
if ((mask & bitmask) == 0) {
lut_val = extract_fields(pos - 1, val, mask, lut_val);
} else {
auto new_val = lut_val << 1;
if ((val & bitmask) != 0) new_val++;
lut_val = extract_fields(pos - 1, val, mask, new_val);
}
}
return lut_val;
}

private:
/****************************************************************************
* start opcode definitions
****************************************************************************/
struct InstructionDesriptor {
size_t length;
uint32_t value;
uint32_t mask;
compile_func op;
};

const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
/* instruction ${instr.instruction.name} */
{${instr.length}, ${instr.value}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
}};
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
/* instruction ${idx}: ${instr.name} */
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){<%instr.code.eachLine{%>
${it}<%}%>
}
<%}%>
/****************************************************************************
* end opcode definitions
****************************************************************************/
compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr, std::stringstream& os) {
this->gen_sync(iss::PRE_SYNC, instr_descr.size());
this->builder.CreateStore(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), true),
get_reg_ptr(traits<ARCH>::PC), true);
this->builder.CreateStore(
this->builder.CreateAdd(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::ICOUNT), true),
this->gen_const(64U, 1)),
get_reg_ptr(traits<ARCH>::ICOUNT), true);
pc = pc + ((instr & 3) == 3 ? 4 : 2);
this->gen_raise_trap(0, 2); // illegal instruction trap
this->gen_sync(iss::POST_SYNC, instr_descr.size());
this->gen_trap_check(this->leave_blk);
return BRANCH;
}
};

template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
volatile CODE_WORD x = insn;
insn = 2 * x;
}

template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }

template <typename ARCH>
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
: vm_base<ARCH>(core, core_id, cluster_id) {
qlut[0] = lut_00.data();
qlut[1] = lut_01.data();
qlut[2] = lut_10.data();
qlut[3] = lut_11.data();
for (auto instr : instr_descr) {
auto quantrant = instr.value & 0x3;
expand_bit_mask(29, lutmasks[quantrant], instr.value >> 2, instr.mask >> 2, 0, qlut[quantrant], instr.op);
}
}

template <typename ARCH>
std::tuple<continuation_e>
vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, std::ostringstream& os) {
// we fetch at max 4 byte, alignment is 2
enum {TRAP_ID=1<<16};
code_word_t insn = 0;
const typename traits<ARCH>::addr_t upper_bits = ~traits<ARCH>::PGMASK;
phys_addr_t paddr(pc);
auto *const data = (uint8_t *)&insn;
paddr = this->core.v2p(pc);
if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
auto res = this->core.read(paddr, 2, data);
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
if ((insn & 0x3) == 0x3) { // this is a 32bit instruction
res = this->core.read(this->core.v2p(pc + 2), 2, data + 2);
}
} else {
auto res = this->core.read(paddr, 4, data);
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
}
if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
// curr pc on stack
++inst_cnt;
auto lut_val = extract_fields(insn);
auto f = qlut[insn & 0x3][lut_val];
if (f == nullptr) {
f = &this_class::illegal_intruction;
}
return (this->*f)(pc, insn, this_block);
}

template <typename ARCH> void vm_impl<ARCH>::gen_leave_behavior(BasicBlock *leave_blk) {
this->builder.SetInsertPoint(leave_blk);
this->builder.CreateRet(this->builder.CreateLoad(get_reg_ptr(arch::traits<ARCH>::NEXT_PC), false));
}

template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) {
auto *TRAP_val = this->gen_const(32, 0x80 << 24 | (cause << 16) | trap_id);
this->builder.CreateStore(TRAP_val, get_reg_ptr(traits<ARCH>::TRAP_STATE), true);
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits<ARCH>::LAST_BRANCH), false);
}

template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) {
std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, lvl)) };
this->builder.CreateCall(this->mod->getFunction("leave_trap"), args);
auto *PC_val = this->gen_read_mem(traits<ARCH>::CSR, (lvl << 8) + 0x41, traits<ARCH>::XLEN / 8);
this->builder.CreateStore(PC_val, get_reg_ptr(traits<ARCH>::NEXT_PC), false);
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits<ARCH>::LAST_BRANCH), false);
}

template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) {
std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, type)) };
this->builder.CreateCall(this->mod->getFunction("wait"), args);
}

template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(BasicBlock *trap_blk) {
this->builder.SetInsertPoint(trap_blk);
auto *trap_state_val = this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::TRAP_STATE), true);
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()),
get_reg_ptr(traits<ARCH>::LAST_BRANCH), false);
std::vector<Value *> args{this->core_ptr, this->adj_to64(trap_state_val),
this->adj_to64(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::PC), false))};
this->builder.CreateCall(this->mod->getFunction("enter_trap"), args);
auto *trap_addr_val = this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), false);
this->builder.CreateRet(trap_addr_val);
}

template <typename ARCH> inline void vm_impl<ARCH>::gen_trap_check(BasicBlock *bb) {
auto *v = this->builder.CreateLoad(get_reg_ptr(arch::traits<ARCH>::TRAP_STATE), true);
this->gen_cond_branch(this->builder.CreateICmp(
ICmpInst::ICMP_EQ, v,
ConstantInt::get(getContext(), APInt(v->getType()->getIntegerBitWidth(), 0))),
bb, this->trap_blk, 1);
}
} // namespace ${coreDef.name.toLowerCase()}

template <>
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
auto ret = new ${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*core, dump);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
return std::unique_ptr<vm_if>(ret);
}
}
} // namespace iss

+ 250
- 0
incl/iss/arch/mnrv32.h View File

@@ -0,0 +1,250 @@
/*******************************************************************************
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/


#ifndef _MNRV32_H_
#define _MNRV32_H_

#include <array>
#include <iss/arch/traits.h>
#include <iss/arch_if.h>
#include <iss/vm_if.h>

namespace iss {
namespace arch {

struct mnrv32;

template <> struct traits<mnrv32> {

constexpr static char const* const core_type = "MNRV32";
static constexpr std::array<const char*, 33> reg_names{
{"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31", "pc"}};
static constexpr std::array<const char*, 33> reg_aliases{
{"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", "pc"}};

enum constants {XLEN=32, PCLEN=32, MISA_VAL=0b1000000000101000001000100000101, PGSIZE=0x1000, PGMASK=0xfff};

constexpr static unsigned FP_REGS_SIZE = 0;

enum reg_e {
X0,
X1,
X2,
X3,
X4,
X5,
X6,
X7,
X8,
X9,
X10,
X11,
X12,
X13,
X14,
X15,
X16,
X17,
X18,
X19,
X20,
X21,
X22,
X23,
X24,
X25,
X26,
X27,
X28,
X29,
X30,
X31,
PC,
NUM_REGS,
NEXT_PC=NUM_REGS,
TRAP_STATE,
PENDING_TRAP,
MACHINE_STATE,
LAST_BRANCH,
ICOUNT,
ZERO = X0,
RA = X1,
SP = X2,
GP = X3,
TP = X4,
T0 = X5,
T1 = X6,
T2 = X7,
S0 = X8,
S1 = X9,
A0 = X10,
A1 = X11,
A2 = X12,
A3 = X13,
A4 = X14,
A5 = X15,
A6 = X16,
A7 = X17,
S2 = X18,
S3 = X19,
S4 = X20,
S5 = X21,
S6 = X22,
S7 = X23,
S8 = X24,
S9 = X25,
S10 = X26,
S11 = X27,
T3 = X28,
T4 = X29,
T5 = X30,
T6 = X31
};

using reg_t = uint32_t;

using addr_t = uint32_t;

using code_word_t = uint32_t; //TODO: check removal

using virt_addr_t = iss::typed_addr_t<iss::address_type::VIRTUAL>;

using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;

static constexpr std::array<const uint32_t, 39> reg_bit_widths{
{32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,64}};

static constexpr std::array<const uint32_t, 40> reg_byte_offsets{
{0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,160}};

static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);

enum sreg_flag_e { FLAGS };

enum mem_type_e { MEM, CSR, FENCE, RES };
};

struct mnrv32: public arch_if {

using virt_addr_t = typename traits<mnrv32>::virt_addr_t;
using phys_addr_t = typename traits<mnrv32>::phys_addr_t;
using reg_t = typename traits<mnrv32>::reg_t;
using addr_t = typename traits<mnrv32>::addr_t;

mnrv32();
~mnrv32();

void reset(uint64_t address=0) override;

uint8_t* get_regs_base_ptr() override;
/// deprecated
void get_reg(short idx, std::vector<uint8_t>& value) override {}
void set_reg(short idx, const std::vector<uint8_t>& value) override {}
/// deprecated
bool get_flag(int flag) override {return false;}
void set_flag(int, bool value) override {};
/// deprecated
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};

inline uint64_t get_icount() { return reg.icount; }

inline bool should_stop() { return interrupt_sim; }

inline phys_addr_t v2p(const iss::addr_t& addr){
if (addr.space != traits<mnrv32>::MEM || addr.type == iss::address_type::PHYSICAL ||
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) {
return phys_addr_t(addr.access, addr.space, addr.val&traits<mnrv32>::addr_mask);
} else
return virt2phys(addr);
}

virtual phys_addr_t virt2phys(const iss::addr_t& addr);

virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }

inline uint32_t get_last_branch() { return reg.last_branch; }

protected:
struct MNRV32_regs {
uint32_t X0 = 0;
uint32_t X1 = 0;
uint32_t X2 = 0;
uint32_t X3 = 0;
uint32_t X4 = 0;
uint32_t X5 = 0;
uint32_t X6 = 0;
uint32_t X7 = 0;
uint32_t X8 = 0;
uint32_t X9 = 0;
uint32_t X10 = 0;
uint32_t X11 = 0;
uint32_t X12 = 0;
uint32_t X13 = 0;
uint32_t X14 = 0;
uint32_t X15 = 0;
uint32_t X16 = 0;
uint32_t X17 = 0;
uint32_t X18 = 0;
uint32_t X19 = 0;
uint32_t X20 = 0;
uint32_t X21 = 0;
uint32_t X22 = 0;
uint32_t X23 = 0;
uint32_t X24 = 0;
uint32_t X25 = 0;
uint32_t X26 = 0;
uint32_t X27 = 0;
uint32_t X28 = 0;
uint32_t X29 = 0;
uint32_t X30 = 0;
uint32_t X31 = 0;
uint32_t PC = 0;
uint32_t NEXT_PC = 0;
uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0;
uint64_t icount = 0;
} reg;

std::array<address_type, 4> addr_mode;
bool interrupt_sim=false;

uint32_t get_fcsr(){return 0;}
void set_fcsr(uint32_t val){}

};

}
}
#endif /* _MNRV32_H_ */

+ 79
- 0
src/iss/mnrv32.cpp View File

@@ -0,0 +1,79 @@
/*******************************************************************************
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
#include "util/ities.h"
#include <util/logging.h>

#include <elfio/elfio.hpp>
#include <iss/arch/mnrv32.h>

#ifdef __cplusplus
extern "C" {
#endif
#include <ihex.h>
#ifdef __cplusplus
}
#endif
#include <cstdio>
#include <cstring>
#include <fstream>

using namespace iss::arch;

constexpr std::array<const char*, 33> iss::arch::traits<iss::arch::mnrv32>::reg_names;
constexpr std::array<const char*, 33> iss::arch::traits<iss::arch::mnrv32>::reg_aliases;
constexpr std::array<const uint32_t, 39> iss::arch::traits<iss::arch::mnrv32>::reg_bit_widths;
constexpr std::array<const uint32_t, 40> iss::arch::traits<iss::arch::mnrv32>::reg_byte_offsets;

mnrv32::mnrv32() {
reg.icount = 0;
}

mnrv32::~mnrv32() = default;

void mnrv32::reset(uint64_t address) {
for(size_t i=0; i<traits<mnrv32>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<mnrv32>::reg_t),0));
reg.PC=address;
reg.NEXT_PC=reg.PC;
reg.trap_state=0;
reg.machine_state=0x3;
reg.icount=0;
}

uint8_t *mnrv32::get_regs_base_ptr() {
return reinterpret_cast<uint8_t*>(&reg);
}

mnrv32::phys_addr_t mnrv32::virt2phys(const iss::addr_t &pc) {
return phys_addr_t(pc); // change logical address to physical address
}


+ 18
- 18
src/main.cpp View File

@@ -107,26 +107,26 @@ int main(int argc, char *argv[]) {
std::unique_ptr<iss::vm_if> vm{nullptr};
std::unique_ptr<iss::arch_if> cpu{nullptr};
std::string isa_opt(clim["isa"].as<std::string>());
if (isa_opt=="rv64ia") {
iss::arch::rv64i* lcpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv64i>();
vm = iss::create(lcpu, clim["gdb-port"].as<unsigned>());
cpu.reset(lcpu);
} else if (isa_opt=="rv64gc") {
iss::arch::rv64gc* lcpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv64gc>();
vm = iss::create(lcpu, clim["gdb-port"].as<unsigned>());
cpu.reset(lcpu);
} else if (isa_opt=="rv32imac") {
// if (isa_opt=="rv64ia") {
// iss::arch::rv64i* lcpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv64i>();
// vm = iss::llvm::create(lcpu, clim["gdb-port"].as<unsigned>());
// cpu.reset(lcpu);
// } else if (isa_opt=="rv64gc") {
// iss::arch::rv64gc* lcpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv64gc>();
// vm = iss::llvm::create(lcpu, clim["gdb-port"].as<unsigned>());
// cpu.reset(lcpu);
// } else if (isa_opt=="rv32imac") {
iss::arch::rv32imac* lcpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv32imac>();
vm = iss::create(lcpu, clim["gdb-port"].as<unsigned>());
vm = iss::llvm::create(lcpu, clim["gdb-port"].as<unsigned>());
cpu.reset(lcpu);
} else if (isa_opt=="rv32gc") {
iss::arch::rv32gc* lcpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv32gc>();
vm = iss::create(lcpu, clim["gdb-port"].as<unsigned>());
cpu.reset(lcpu);
} else {
LOG(ERROR) << "Illegal argument value for '--isa': " << clim["isa"].as<std::string>() << std::endl;
return 127;
}
// } else if (isa_opt=="rv32gc") {
// iss::arch::rv32gc* lcpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv32gc>();
// vm = iss::llvm::create(lcpu, clim["gdb-port"].as<unsigned>());
// cpu.reset(lcpu);
// } else {
// LOG(ERROR) << "Illegal argument value for '--isa': " << clim["isa"].as<std::string>() << std::endl;
// return 127;
// }
if (clim.count("plugin")) {
for (std::string opt_val : clim["plugin"].as<std::vector<std::string>>()) {
std::string plugin_name{opt_val};

+ 1
- 1
src/sysc/core_complex.cpp View File

@@ -282,7 +282,7 @@ void core_complex::trace(sc_trace_file *trf) const {}

void core_complex::before_end_of_elaboration() {
cpu = scc::make_unique<core_wrapper>(this);
vm = create<arch::rv32imac>(cpu.get(), gdb_server_port.get_value(), dump_ir.get_value());
vm = llvm::create<arch::rv32imac>(cpu.get(), gdb_server_port.get_value(), dump_ir.get_value());
#ifdef WITH_SCV
vm->setDisassEnabled(enable_disass.get_value() || m_db != nullptr);
#else

src/internal/fp_functions.cpp → src/vm/llvm/fp_functions.cpp View File

@@ -44,7 +44,7 @@ extern "C" {
#include <limits>

namespace iss {
namespace llvm {
namespace vm {
namespace fp_impl {

using namespace std;

src/internal/vm_rv32gc.cpp → src/vm/llvm/vm_rv32gc.cpp View File

@@ -47,7 +47,7 @@
#include <iss/debugger/riscv_target_adapter.h>

namespace iss {
namespace llvm {
namespace vm {
namespace fp_impl {
void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned);
}
@@ -57,11 +57,11 @@ namespace rv32gc {
using namespace iss::arch;
using namespace llvm;
using namespace iss::debugger;
using namespace iss::llvm;
using namespace iss::vm::llvm;

template <typename ARCH> class vm_impl : public vm_base<ARCH> {
public:
using super = typename iss::llvm::vm_base<ARCH>;
using super = typename iss::vm::llvm::vm_base<ARCH>;
using virt_addr_t = typename super::virt_addr_t;
using phys_addr_t = typename super::phys_addr_t;
using code_word_t = typename super::code_word_t;
@@ -91,7 +91,7 @@ protected:

void setup_module(Module* m) override {
super::setup_module(m);
iss::llvm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN);
iss::vm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN);
}

inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) {

src/internal/vm_rv32imac.cpp → src/vm/llvm/vm_rv32imac.cpp View File

@@ -47,12 +47,12 @@
#include <iss/debugger/riscv_target_adapter.h>

namespace iss {
namespace llvm {
namespace vm {
namespace fp_impl {
void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned);
}
}
namespace llvm {
namespace rv32imac {
using namespace iss::arch;
using namespace llvm;
@@ -91,7 +91,7 @@ protected:

void setup_module(Module* m) override {
super::setup_module(m);
iss::llvm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN);
iss::vm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN);
}

inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) {
@@ -4815,5 +4815,5 @@ std::unique_ptr<vm_if> create<arch::rv32imac>(arch::rv32imac *core, unsigned sho
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
return std::unique_ptr<vm_if>(ret);
}
}
} // namespace iss

src/internal/vm_rv64gc.cpp → src/vm/llvm/vm_rv64gc.cpp View File

@@ -47,7 +47,7 @@
#include <iss/debugger/riscv_target_adapter.h>

namespace iss {
namespace llvm {
namespace vm {
namespace fp_impl {
void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned);
}
@@ -57,11 +57,11 @@ namespace rv64gc {
using namespace iss::arch;
using namespace llvm;
using namespace iss::debugger;
using namespace iss::llvm;
using namespace iss::vm::llvm;

template <typename ARCH> class vm_impl : public vm_base<ARCH> {
public:
using super = typename iss::llvm::vm_base<ARCH>;
using super = typename iss::vm::llvm::vm_base<ARCH>;
using virt_addr_t = typename super::virt_addr_t;
using phys_addr_t = typename super::phys_addr_t;
using code_word_t = typename super::code_word_t;
@@ -91,7 +91,7 @@ protected:

void setup_module(Module* m) override {
super::setup_module(m);
iss::llvm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN);
iss::vm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN);
}

inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) {

src/internal/vm_rv64i.cpp → src/vm/llvm/vm_rv64i.cpp View File

@@ -47,7 +47,7 @@
#include <iss/debugger/riscv_target_adapter.h>

namespace iss {
namespace llvm {
namespace vm {
namespace fp_impl {
void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned);
}
@@ -57,11 +57,11 @@ namespace rv64i {
using namespace iss::arch;
using namespace llvm;
using namespace iss::debugger;
using namespace iss::llvm;
using namespace iss::vm::llvm;

template <typename ARCH> class vm_impl : public vm_base<ARCH> {
public:
using super = typename iss::llvm::vm_base<ARCH>;
using super = typename iss::vm::llvm::vm_base<ARCH>;
using virt_addr_t = typename super::virt_addr_t;
using phys_addr_t = typename super::phys_addr_t;
using code_word_t = typename super::code_word_t;
@@ -91,7 +91,7 @@ protected:

void setup_module(Module* m) override {
super::setup_module(m);
iss::llvm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN);
iss::vm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN);
}

inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) {

+ 610
- 0
src/vm/tcc/vm_mnrv32.cpp View File

@@ -0,0 +1,610 @@
/*******************************************************************************
* Copyright (C) 2020 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/

#include <iss/arch/mnrv32.h>
#include <iss/arch/riscv_hart_msu_vp.h>
#include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h>
#include <iss/iss.h>
#include <iss/tcc/vm_base.h>
#include <util/logging.h>
#include <sstream>

#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#include <fmt/format.h>

#include <array>
#include <iss/debugger/riscv_target_adapter.h>

namespace iss {
namespace tcc {
namespace mnrv32 {
using namespace iss::arch;
using namespace iss::debugger;
using namespace iss::vm::tcc;

template <typename ARCH> class vm_impl : public vm_base<ARCH> {
public:
using super = typename iss::vm::tcc::vm_base<ARCH>;
using virt_addr_t = typename super::virt_addr_t;
using phys_addr_t = typename super::phys_addr_t;
using code_word_t = typename super::code_word_t;
using addr_t = typename super::addr_t;

using Value = void;
using ConstantInt = void;
using Type = void;

vm_impl();

vm_impl(ARCH &core, unsigned core_id = 0, unsigned cluster_id = 0);

void enableDebug(bool enable) { super::sync_exec = super::ALL_SYNC; }

target_adapter_if *accquire_target_adapter(server_if *srv) override {
debugger_if::dbg_enabled = true;
if (vm_base<ARCH>::tgt_adapter == nullptr)
vm_base<ARCH>::tgt_adapter = new riscv_target_adapter<ARCH>(srv, this->get_arch());
return vm_base<ARCH>::tgt_adapter;
}

protected:
using vm_base<ARCH>::get_reg_ptr;

using this_class = vm_impl<ARCH>;
using compile_ret_t = std::tuple<continuation_e>;
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, std::ostringstream&);

inline const char *name(size_t index){return traits<ARCH>::reg_aliases.at(index);}

template <typename T> inline ConstantInt *size(T type) {
return nullptr;
}

void setup_module(Module* m) override {
super::setup_module(m);
}

inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) {
return super::gen_cond_assign(cond, this->gen_ext(trueVal, size), this->gen_ext(falseVal, size));
}

compile_ret_t gen_single_inst_behavior(virt_addr_t &, unsigned int &, std::ostringstream&) override;

void gen_leave_behavior(std::ostringstream& os) override;

void gen_raise_trap(uint16_t trap_id, uint16_t cause);

void gen_leave_trap(unsigned lvl);

void gen_wait(unsigned type);

void gen_trap_behavior(std::ostringstream& os) override;

void gen_trap_check(std::ostringstream& os){}

inline Value *gen_reg_load(unsigned i, unsigned level = 0) {
return this->builder.CreateLoad(get_reg_ptr(i), false);
}

inline void gen_set_pc(virt_addr_t pc, unsigned reg_num) {
Value *next_pc_v = this->builder.CreateSExtOrTrunc(this->gen_const(traits<ARCH>::XLEN, pc.val),
this->get_type(traits<ARCH>::XLEN));
this->builder.CreateStore(next_pc_v, get_reg_ptr(reg_num), true);
}

// some compile time constants
// enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 };
enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 };
enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 };
enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) };

std::array<compile_func, LUT_SIZE> lut;

std::array<compile_func, LUT_SIZE_C> lut_00, lut_01, lut_10;
std::array<compile_func, LUT_SIZE> lut_11;

std::array<compile_func *, 4> qlut;

std::array<const uint32_t, 4> lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}};

void expand_bit_mask(int pos, uint32_t mask, uint32_t value, uint32_t valid, uint32_t idx, compile_func lut[],
compile_func f) {
if (pos < 0) {
lut[idx] = f;
} else {
auto bitmask = 1UL << pos;
if ((mask & bitmask) == 0) {
expand_bit_mask(pos - 1, mask, value, valid, idx, lut, f);
} else {
if ((valid & bitmask) == 0) {
expand_bit_mask(pos - 1, mask, value, valid, (idx << 1), lut, f);
expand_bit_mask(pos - 1, mask, value, valid, (idx << 1) + 1, lut, f);
} else {
auto new_val = idx << 1;
if ((value & bitmask) != 0) new_val++;
expand_bit_mask(pos - 1, mask, value, valid, new_val, lut, f);
}
}
}
}

inline uint32_t extract_fields(uint32_t val) { return extract_fields(29, val >> 2, lutmasks[val & 0x3], 0); }

uint32_t extract_fields(int pos, uint32_t val, uint32_t mask, uint32_t lut_val) {
if (pos >= 0) {
auto bitmask = 1UL << pos;
if ((mask & bitmask) == 0) {
lut_val = extract_fields(pos - 1, val, mask, lut_val);
} else {
auto new_val = lut_val << 1;
if ((val & bitmask) != 0) new_val++;
lut_val = extract_fields(pos - 1, val, mask, new_val);
}
}
return lut_val;
}

private:
/****************************************************************************
* start opcode definitions
****************************************************************************/
struct InstructionDesriptor {
size_t length;
uint32_t value;
uint32_t mask;
compile_func op;
};

const std::array<InstructionDesriptor, 52> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */
/* instruction LUI */
{32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, &this_class::__lui},
/* instruction AUIPC */
{32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, &this_class::__auipc},
/* instruction JAL */
{32, 0b00000000000000000000000001101111, 0b00000000000000000000000001111111, &this_class::__jal},
/* instruction JALR */
{32, 0b00000000000000000000000001100111, 0b00000000000000000111000001111111, &this_class::__jalr},
/* instruction BEQ */
{32, 0b00000000000000000000000001100011, 0b00000000000000000111000001111111, &this_class::__beq},
/* instruction BNE */
{32, 0b00000000000000000001000001100011, 0b00000000000000000111000001111111, &this_class::__bne},
/* instruction BLT */
{32, 0b00000000000000000100000001100011, 0b00000000000000000111000001111111, &this_class::__blt},
/* instruction BGE */
{32, 0b00000000000000000101000001100011, 0b00000000000000000111000001111111, &this_class::__bge},
/* instruction BLTU */
{32, 0b00000000000000000110000001100011, 0b00000000000000000111000001111111, &this_class::__bltu},
/* instruction BGEU */
{32, 0b00000000000000000111000001100011, 0b00000000000000000111000001111111, &this_class::__bgeu},
/* instruction LB */
{32, 0b00000000000000000000000000000011, 0b00000000000000000111000001111111, &this_class::__lb},
/* instruction LH */
{32, 0b00000000000000000001000000000011, 0b00000000000000000111000001111111, &this_class::__lh},
/* instruction LW */
{32, 0b00000000000000000010000000000011, 0b00000000000000000111000001111111, &this_class::__lw},
/* instruction LBU */
{32, 0b00000000000000000100000000000011, 0b00000000000000000111000001111111, &this_class::__lbu},
/* instruction LHU */
{32, 0b00000000000000000101000000000011, 0b00000000000000000111000001111111, &this_class::__lhu},
/* instruction SB */
{32, 0b00000000000000000000000000100011, 0b00000000000000000111000001111111, &this_class::__sb},
/* instruction SH */
{32, 0b00000000000000000001000000100011, 0b00000000000000000111000001111111, &this_class::__sh},
/* instruction SW */
{32, 0b00000000000000000010000000100011, 0b00000000000000000111000001111111, &this_class::__sw},
/* instruction ADDI */
{32, 0b00000000000000000000000000010011, 0b00000000000000000111000001111111, &this_class::__addi},
/* instruction SLTI */
{32, 0b00000000000000000010000000010011, 0b00000000000000000111000001111111, &this_class::__slti},
/* instruction SLTIU */
{32, 0b00000000000000000011000000010011, 0b00000000000000000111000001111111, &this_class::__sltiu},
/* instruction XORI */
{32, 0b00000000000000000100000000010011, 0b00000000000000000111000001111111, &this_class::__xori},
/* instruction ORI */
{32, 0b00000000000000000110000000010011, 0b00000000000000000111000001111111, &this_class::__ori},
/* instruction ANDI */
{32, 0b00000000000000000111000000010011, 0b00000000000000000111000001111111, &this_class::__andi},
/* instruction SLLI */
{32, 0b00000000000000000001000000010011, 0b11111110000000000111000001111111, &this_class::__slli},
/* instruction SRLI */
{32, 0b00000000000000000101000000010011, 0b11111110000000000111000001111111, &this_class::__srli},
/* instruction SRAI */
{32, 0b01000000000000000101000000010011, 0b11111110000000000111000001111111, &this_class::__srai},
/* instruction ADD */
{32, 0b00000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__add},
/* instruction SUB */
{32, 0b01000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__sub},
/* instruction SLL */
{32, 0b00000000000000000001000000110011, 0b11111110000000000111000001111111, &this_class::__sll},
/* instruction SLT */
{32, 0b00000000000000000010000000110011, 0b11111110000000000111000001111111, &this_class::__slt},
/* instruction SLTU */
{32, 0b00000000000000000011000000110011, 0b11111110000000000111000001111111, &this_class::__sltu},
/* instruction XOR */
{32, 0b00000000000000000100000000110011, 0b11111110000000000111000001111111, &this_class::__xor},
/* instruction SRL */
{32, 0b00000000000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__srl},
/* instruction SRA */
{32, 0b01000000000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__sra},
/* instruction OR */
{32, 0b00000000000000000110000000110011, 0b11111110000000000111000001111111, &this_class::__or},
/* instruction AND */
{32, 0b00000000000000000111000000110011, 0b11111110000000000111000001111111, &this_class::__and},
/* instruction FENCE */
{32, 0b00000000000000000000000000001111, 0b11110000000000000111000001111111, &this_class::__fence},
/* instruction FENCE_I */
{32, 0b00000000000000000001000000001111, 0b00000000000000000111000001111111, &this_class::__fence_i},
/* instruction ECALL */
{32, 0b00000000000000000000000001110011, 0b11111111111111111111111111111111, &this_class::__ecall},
/* instruction EBREAK */
{32, 0b00000000000100000000000001110011, 0b11111111111111111111111111111111, &this_class::__ebreak},
/* instruction URET */
{32, 0b00000000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__uret},
/* instruction SRET */
{32, 0b00010000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__sret},
/* instruction MRET */
{32, 0b00110000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__mret},
/* instruction WFI */
{32, 0b00010000010100000000000001110011, 0b11111111111111111111111111111111, &this_class::__wfi},
/* instruction SFENCE.VMA */
{32, 0b00010010000000000000000001110011, 0b11111110000000000111111111111111, &this_class::__sfence_vma},
/* instruction CSRRW */
{32, 0b00000000000000000001000001110011, 0b00000000000000000111000001111111, &this_class::__csrrw},
/* instruction CSRRS */
{32, 0b00000000000000000010000001110011, 0b00000000000000000111000001111111, &this_class::__csrrs},
/* instruction CSRRC */
{32, 0b00000000000000000011000001110011, 0b00000000000000000111000001111111, &this_class::__csrrc},
/* instruction CSRRWI */
{32, 0b00000000000000000101000001110011, 0b00000000000000000111000001111111, &this_class::__csrrwi},
/* instruction CSRRSI */
{32, 0b00000000000000000110000001110011, 0b00000000000000000111000001111111, &this_class::__csrrsi},
/* instruction CSRRCI */
{32, 0b00000000000000000111000001110011, 0b00000000000000000111000001111111, &this_class::__csrrci},
}};
/* instruction definitions */
/* instruction 0: LUI */
compile_ret_t __lui(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 1: AUIPC */
compile_ret_t __auipc(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 2: JAL */
compile_ret_t __jal(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
this->gen_sync(PRE_SYNC, 0);

uint8_t rd = ((bit_sub<7,5>(instr)));
uint8_t rs1 = ((bit_sub<15,5>(instr)));
int16_t imm = signextend<int16_t,12>((bit_sub<20,12>(instr)));
if(this->disass_enabled){
/* generate console output when executing the command */
auto mnemonic = fmt::format(
"{mnemonic:10} {rd}, {rs1}, {imm:#0x}", fmt::arg("mnemonic", "jalr"),
fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm));
os<<"print_disass(0x"<<std::hex<<this->core_ptr<<", 0x"<<pc.val<<", \""<<mnemonic<<"\");\n";
}

auto cur_pc_val = pc.val;
pc=pc+4;
}
/* instruction 3: JALR */
compile_ret_t __jalr(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 4: BEQ */
compile_ret_t __beq(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 5: BNE */
compile_ret_t __bne(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 6: BLT */
compile_ret_t __blt(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 7: BGE */
compile_ret_t __bge(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 8: BLTU */
compile_ret_t __bltu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 9: BGEU */
compile_ret_t __bgeu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 10: LB */
compile_ret_t __lb(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 11: LH */
compile_ret_t __lh(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 12: LW */
compile_ret_t __lw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 13: LBU */
compile_ret_t __lbu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 14: LHU */
compile_ret_t __lhu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 15: SB */
compile_ret_t __sb(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 16: SH */
compile_ret_t __sh(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 17: SW */
compile_ret_t __sw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 18: ADDI */
compile_ret_t __addi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 19: SLTI */
compile_ret_t __slti(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 20: SLTIU */
compile_ret_t __sltiu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 21: XORI */
compile_ret_t __xori(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 22: ORI */
compile_ret_t __ori(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 23: ANDI */
compile_ret_t __andi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 24: SLLI */
compile_ret_t __slli(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 25: SRLI */
compile_ret_t __srli(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 26: SRAI */
compile_ret_t __srai(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 27: ADD */
compile_ret_t __add(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 28: SUB */
compile_ret_t __sub(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 29: SLL */
compile_ret_t __sll(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 30: SLT */
compile_ret_t __slt(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 31: SLTU */
compile_ret_t __sltu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 32: XOR */
compile_ret_t __xor(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 33: SRL */
compile_ret_t __srl(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 34: SRA */
compile_ret_t __sra(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 35: OR */
compile_ret_t __or(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 36: AND */
compile_ret_t __and(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 37: FENCE */
compile_ret_t __fence(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 38: FENCE_I */
compile_ret_t __fence_i(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 39: ECALL */
compile_ret_t __ecall(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 40: EBREAK */
compile_ret_t __ebreak(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 41: URET */
compile_ret_t __uret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 42: SRET */
compile_ret_t __sret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 43: MRET */
compile_ret_t __mret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 44: WFI */
compile_ret_t __wfi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 45: SFENCE.VMA */
compile_ret_t __sfence_vma(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 46: CSRRW */
compile_ret_t __csrrw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 47: CSRRS */
compile_ret_t __csrrs(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 48: CSRRC */
compile_ret_t __csrrc(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 49: CSRRWI */
compile_ret_t __csrrwi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 50: CSRRSI */
compile_ret_t __csrrsi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/* instruction 51: CSRRCI */
compile_ret_t __csrrci(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){
}
/****************************************************************************
* end opcode definitions
****************************************************************************/
compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr, std::ostringstream& oss) {
vm_impl::gen_sync(iss::PRE_SYNC, instr_descr.size());
pc = pc + ((instr & 3) == 3 ? 4 : 2);
gen_raise_trap(0, 2); // illegal instruction trap
vm_impl::gen_sync(iss::POST_SYNC, instr_descr.size());
vm_impl::gen_trap_check(oss);
return BRANCH;
}
};

template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
volatile CODE_WORD x = insn;
insn = 2 * x;
}

template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }

template <typename ARCH>
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
: vm_base<ARCH>(core, core_id, cluster_id) {
qlut[0] = lut_00.data();
qlut[1] = lut_01.data();
qlut[2] = lut_10.data();
qlut[3] = lut_11.data();
for (auto instr : instr_descr) {
auto quantrant = instr.value & 0x3;
expand_bit_mask(29, lutmasks[quantrant], instr.value >> 2, instr.mask >> 2, 0, qlut[quantrant], instr.op);
}
}

template <typename ARCH>
std::tuple<continuation_e>
vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, std::ostringstream& os) {
// we fetch at max 4 byte, alignment is 2
enum {TRAP_ID=1<<16};
code_word_t insn = 0;
const typename traits<ARCH>::addr_t upper_bits = ~traits<ARCH>::PGMASK;
phys_addr_t paddr(pc);
auto *const data = (uint8_t *)&insn;
paddr = this->core.v2p(pc);
if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
auto res = this->core.read(paddr, 2, data);
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
if ((insn & 0x3) == 0x3) { // this is a 32bit instruction
res = this->core.read(this->core.v2p(pc + 2), 2, data + 2);
}
} else {
auto res = this->core.read(paddr, 4, data);
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
}
if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
// curr pc on stack
++inst_cnt;
auto lut_val = extract_fields(insn);
auto f = qlut[insn & 0x3][lut_val];
if (f == nullptr) {
f = &this_class::illegal_intruction;
}
return (this->*f)(pc, insn, os);
}

template <typename ARCH> void vm_impl<ARCH>::gen_leave_behavior(std::ostringstream& os) {
}

template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) {
}

template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) {
}

template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) {
}

template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(std::ostringstream& os) {
}

} // namespace mnrv32

template <>
std::unique_ptr<vm_if> create<arch::mnrv32>(arch::mnrv32 *core, unsigned short port, bool dump) {
auto ret = new mnrv32::vm_impl<arch::mnrv32>(*core, dump);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
return std::unique_ptr<vm_if>(ret);
}
}
} // namespace iss

+ 1273
- 0
src/vm/tcc/vm_rv32gc.cpp
File diff suppressed because it is too large
View File


+ 913
- 0
src/vm/tcc/vm_rv32imac.cpp View File

@@ -0,0 +1,913 @@
/*******************************************************************************
* Copyright (C) 2020 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/

#include <iss/arch/rv32imac.h>
#include <iss/arch/riscv_hart_msu_vp.h>
#include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h>
#include <iss/iss.h>
#include <iss/llvm/vm_base.h>
#include <util/logging.h>

#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#include <fmt/format.h>

#include <array>
#include <iss/debugger/riscv_target_adapter.h>

namespace iss {
namespace vm {
namespace fp_impl {
void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned);
}
}

namespace tcc {
namespace rv32imac {
using namespace iss::arch;
using namespace iss::debugger;
using namespace iss::vm::llvm;

template <typename ARCH> class vm_impl : public vm_base<ARCH> {
public:
using super = typename iss::vm::llvm::vm_base<ARCH>;
using virt_addr_t = typename super::virt_addr_t;
using phys_addr_t = typename super::phys_addr_t;
using code_word_t = typename super::code_word_t;
using addr_t = typename super::addr_t;

vm_impl();

vm_impl(ARCH &core, unsigned core_id = 0, unsigned cluster_id = 0);

void enableDebug(bool enable) { super::sync_exec = super::ALL_SYNC; }

target_adapter_if *accquire_target_adapter(server_if *srv) override {
debugger_if::dbg_enabled = true;
if (vm_base<ARCH>::tgt_adapter == nullptr)
vm_base<ARCH>::tgt_adapter = new riscv_target_adapter<ARCH>(srv, this->get_arch());
return vm_base<ARCH>::tgt_adapter;
}

protected:
using vm_base<ARCH>::get_reg_ptr;

using this_class = vm_impl<ARCH>;
using compile_ret_t = std::tuple<continuation_e>;
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, std::ostringstream&);

inline const char *name(size_t index){return traits<ARCH>::reg_aliases.at(index);}

template <typename T> inline ConstantInt *size(T type) {
return ConstantInt::get(getContext(), APInt(32, type->getType()->getScalarSizeInBits()));
}

void setup_module(Module* m) override {
super::setup_module(m);
iss::vm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN);
}

inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) {
return super::gen_cond_assign(cond, this->gen_ext(trueVal, size), this->gen_ext(falseVal, size));
}

compile_ret_t gen_single_inst_behavior(virt_addr_t &, unsigned int &, std::ostringstream&) override;

void gen_leave_behavior(BasicBlock *leave_blk) override;

void gen_raise_trap(uint16_t trap_id, uint16_t cause);

void gen_leave_trap(unsigned lvl);

void gen_wait(unsigned type);

void gen_trap_behavior(BasicBlock *) override;

void gen_trap_check(BasicBlock *bb);

inline Value *gen_reg_load(unsigned i, unsigned level = 0) {
return this->builder.CreateLoad(get_reg_ptr(i), false);
}

inline void gen_set_pc(virt_addr_t pc, unsigned reg_num) {
Value *next_pc_v = this->builder.CreateSExtOrTrunc(this->gen_const(traits<ARCH>::XLEN, pc.val),
this->get_type(traits<ARCH>::XLEN));
this->builder.CreateStore(next_pc_v, get_reg_ptr(reg_num), true);
}

// some compile time constants
// enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 };
enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 };
enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 };
enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) };

std::array<compile_func, LUT_SIZE> lut;

std::array<compile_func, LUT_SIZE_C> lut_00, lut_01, lut_10;
std::array<compile_func, LUT_SIZE> lut_11;

std::array<compile_func *, 4> qlut;

std::array<const uint32_t, 4> lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}};

void expand_bit_mask(int pos, uint32_t mask, uint32_t value, uint32_t valid, uint32_t idx, compile_func lut[],
compile_func f) {
if (pos < 0) {
lut[idx] = f;
} else {
auto bitmask = 1UL << pos;
if ((mask & bitmask) == 0) {
expand_bit_mask(pos - 1, mask, value, valid, idx, lut, f);
} else {
if ((valid & bitmask) == 0) {
expand_bit_mask(pos - 1, mask, value, valid, (idx << 1), lut, f);
expand_bit_mask(pos - 1, mask, value, valid, (idx << 1) + 1, lut, f);
} else {
auto new_val = idx << 1;
if ((value & bitmask) != 0) new_val++;
expand_bit_mask(pos - 1, mask, value, valid, new_val, lut, f);
}
}
}
}

inline uint32_t extract_fields(uint32_t val) { return extract_fields(29, val >> 2, lutmasks[val & 0x3], 0); }

uint32_t extract_fields(int pos, uint32_t val, uint32_t mask, uint32_t lut_val) {
if (pos >= 0) {
auto bitmask = 1UL << pos;
if ((mask & bitmask) == 0) {
lut_val = extract_fields(pos - 1, val, mask, lut_val);
} else {
auto new_val = lut_val << 1;
if ((val & bitmask) != 0) new_val++;
lut_val = extract_fields(pos - 1, val, mask, new_val);
}
}
return lut_val;
}

private:
/****************************************************************************
* start opcode definitions
****************************************************************************/
struct InstructionDesriptor {
size_t length;
uint32_t value;
uint32_t mask;
compile_func op;
};

const std::array<InstructionDesriptor, 99> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */
/* instruction JALR */
{32, 0b00000000000000000000000001100111, 0b00000000000000000111000001111111, &this_class::__jalr},
/* instruction C.ADDI4SPN */
{16, 0b0000000000000000, 0b1110000000000011, &this_class::__c_addi4spn},
/* instruction C.LW */
{16, 0b0100000000000000, 0b1110000000000011, &this_class::__c_lw},
/* instruction C.SW */
{16, 0b1100000000000000, 0b1110000000000011, &this_class::__c_sw},
/* instruction C.ADDI */
{16, 0b0000000000000001, 0b1110000000000011, &this_class::__c_addi},
/* instruction C.NOP */
{16, 0b0000000000000001, 0b1111111111111111, &this_class::__c_nop},
/* instruction C.JAL */
{16, 0b0010000000000001, 0b1110000000000011, &this_class::__c_jal},
/* instruction C.LI */
{16, 0b0100000000000001, 0b1110000000000011, &this_class::__c_li},
/* instruction C.LUI */
{16, 0b0110000000000001, 0b1110000000000011, &this_class::__c_lui},
/* instruction C.ADDI16SP */
{16, 0b0110000100000001, 0b1110111110000011, &this_class::__c_addi16sp},
/* instruction C.SRLI */
{16, 0b1000000000000001, 0b1111110000000011, &this_class::__c_srli},
/* instruction C.SRAI */
{16, 0b1000010000000001, 0b1111110000000011, &this_class::__c_srai},
/* instruction C.ANDI */
{16, 0b1000100000000001, 0b1110110000000011, &this_class::__c_andi},
/* instruction C.SUB */
{16, 0b1000110000000001, 0b1111110001100011, &this_class::__c_sub},
/* instruction C.XOR */
{16, 0b1000110000100001, 0b1111110001100011, &this_class::__c_xor},
/* instruction C.OR */
{16, 0b1000110001000001, 0b1111110001100011, &this_class::__c_or},
/* instruction C.AND */
{16, 0b1000110001100001, 0b1111110001100011, &this_class::__c_and},