Compare commits
	
		
			1 Commits
		
	
	
		
			7af7e040da
			...
			feature/is
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| a6c7b1427e | 
@@ -1,75 +1,80 @@
 | 
				
			|||||||
cmake_minimum_required(VERSION 3.12)
 | 
					cmake_minimum_required(VERSION 3.12)
 | 
				
			||||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
 | 
					 | 
				
			||||||
###############################################################################
 | 
					###############################################################################
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
###############################################################################
 | 
					###############################################################################
 | 
				
			||||||
project(dbt-rise-tgc VERSION 1.0.0)
 | 
					project(dbt-rise-tgc VERSION 1.0.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include(GNUInstallDirs)
 | 
					include(GNUInstallDirs)
 | 
				
			||||||
include(flink)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
find_package(elfio QUIET)
 | 
					find_package(elfio QUIET)
 | 
				
			||||||
find_package(Boost COMPONENTS coroutine)
 | 
					find_package(Boost COMPONENTS coroutine)
 | 
				
			||||||
find_package(jsoncpp)
 | 
					find_package(jsoncpp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if(TARGET tcc::tcc)
 | 
					 | 
				
			||||||
  set(WITH_TCC ON)
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if(WITH_LLVM)
 | 
					if(WITH_LLVM)
 | 
				
			||||||
    if(DEFINED ENV{LLVM_HOME})
 | 
					    if(DEFINED ENV{LLVM_HOME})
 | 
				
			||||||
        find_path (LLVM_DIR LLVM-Config.cmake $ENV{LLVM_HOME}/lib/cmake/llvm)
 | 
					        find_path (LLVM_DIR LLVM-Config.cmake $ENV{LLVM_HOME}/lib/cmake/llvm)
 | 
				
			||||||
    endif()
 | 
					    endif(DEFINED ENV{LLVM_HOME})
 | 
				
			||||||
    find_package(LLVM QUIET CONFIG)
 | 
					    find_package(LLVM REQUIRED CONFIG)
 | 
				
			||||||
    if(LLVM_FOUND)
 | 
					    message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
 | 
				
			||||||
    	message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
 | 
					    message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
 | 
				
			||||||
    	message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
 | 
					    llvm_map_components_to_libnames(llvm_libs support core mcjit x86codegen x86asmparser)
 | 
				
			||||||
    	llvm_map_components_to_libnames(llvm_libs support core mcjit x86codegen x86asmparser)
 | 
					 | 
				
			||||||
	else()
 | 
					 | 
				
			||||||
		find_package(LLVM REQUIRED LLVMSupport LLVMCore LLVMMCJIT LLVMX86CodeGen LLVMX86AsmParser)
 | 
					 | 
				
			||||||
	endif()
 | 
					 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Mac needed variables (adapt for your needs - http://www.cmake.org/Wiki/CMake_RPATH_handling#Mac_OS_X_and_the_RPATH)
 | 
				
			||||||
 | 
					#set(CMAKE_MACOSX_RPATH ON)
 | 
				
			||||||
 | 
					#set(CMAKE_SKIP_BUILD_RPATH FALSE)
 | 
				
			||||||
 | 
					#set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
 | 
				
			||||||
 | 
					#set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
 | 
				
			||||||
 | 
					#set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_subdirectory(softfloat)
 | 
					add_subdirectory(softfloat)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(LIB_SOURCES 
 | 
					set(LIB_SOURCES 
 | 
				
			||||||
    src/iss/plugin/instruction_count.cpp
 | 
					    src/iss/plugin/instruction_count.cpp
 | 
				
			||||||
	src/iss/arch/tgc_c.cpp
 | 
						src/iss/arch/tgc_c.cpp
 | 
				
			||||||
	src/vm/tcc/vm_tgc_c.cpp
 | 
					 | 
				
			||||||
	src/vm/interp/vm_tgc_c.cpp
 | 
						src/vm/interp/vm_tgc_c.cpp
 | 
				
			||||||
	src/vm/fp_functions.cpp
 | 
						src/vm/fp_functions.cpp
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
if(WITH_TCC)
 | 
					 | 
				
			||||||
	list(APPEND LIB_SOURCES src/vm/tcc/vm_tgc_c.cpp)
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# library files
 | 
					# library files
 | 
				
			||||||
FILE(GLOB GEN_ISS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp)
 | 
					if(TARGET ${CORE_NAME}_cpp)
 | 
				
			||||||
FILE(GLOB GEN_VM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/interp/vm_*.cpp)
 | 
					    list(APPEND LIB_SOURCES ${${CORE_NAME}_OUTPUT_FILES})
 | 
				
			||||||
list(APPEND LIB_SOURCES ${GEN_ISS_SOURCES} ${GEN_VM_SOURCES})
 | 
					else()
 | 
				
			||||||
foreach(FILEPATH ${GEN_ISS_SOURCES})
 | 
					    FILE(GLOB GEN_ISS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp)
 | 
				
			||||||
    get_filename_component(CORE ${FILEPATH} NAME_WE)
 | 
					    FILE(GLOB GEN_VM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/interp/vm_*.cpp)
 | 
				
			||||||
    string(TOUPPER ${CORE} CORE)
 | 
					    list(APPEND LIB_SOURCES ${GEN_ISS_SOURCES} ${GEN_VM_SOURCES})
 | 
				
			||||||
    list(APPEND LIB_DEFINES CORE_${CORE})
 | 
					    foreach(FILEPATH ${GEN_ISS_SOURCES})
 | 
				
			||||||
endforeach()
 | 
					        get_filename_component(CORE ${FILEPATH} NAME_WE)
 | 
				
			||||||
message("Core defines are ${LIB_DEFINES}")
 | 
					        string(TOUPPER ${CORE} CORE)
 | 
				
			||||||
 | 
					        list(APPEND LIB_DEFINES CORE_${CORE})
 | 
				
			||||||
if(WITH_LLVM)
 | 
					    endforeach()
 | 
				
			||||||
	FILE(GLOB LLVM_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/llvm/vm_*.cpp)
 | 
					    message("Defines are ${LIB_DEFINES}")
 | 
				
			||||||
	list(APPEND LIB_SOURCES ${LLVM_GEN_SOURCES})
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if(WITH_TCC)
 | 
					 | 
				
			||||||
	FILE(GLOB TCC_GEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/tcc/vm_*.cpp)
 | 
					 | 
				
			||||||
	list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES})
 | 
					 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if(TARGET RapidJSON OR TARGET RapidJSON::RapidJSON)
 | 
					if(TARGET RapidJSON OR TARGET RapidJSON::RapidJSON)
 | 
				
			||||||
    list(APPEND LIB_SOURCES src/iss/plugin/cycle_estimate.cpp src/iss/plugin/pctrace.cpp)
 | 
					    list(APPEND LIB_SOURCES src/iss/plugin/cycle_estimate.cpp src/iss/plugin/pctrace.cpp)
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if(WITH_LLVM)
 | 
				
			||||||
 | 
						FILE(GLOB LLVM_GEN_SOURCES
 | 
				
			||||||
 | 
						    ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/llvm/vm_*.cpp
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						list(APPEND LIB_SOURCES ${LLVM_GEN_SOURCES})
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if(WITH_TCC)
 | 
				
			||||||
 | 
						FILE(GLOB TCC_GEN_SOURCES
 | 
				
			||||||
 | 
						    ${CMAKE_CURRENT_SOURCE_DIR}/src/vm/tcc/vm_*.cpp
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES})
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Define the library
 | 
					# Define the library
 | 
				
			||||||
add_library(${PROJECT_NAME} ${LIB_SOURCES})
 | 
					add_library(${PROJECT_NAME} ${LIB_SOURCES})
 | 
				
			||||||
 | 
					# list code gen dependencies
 | 
				
			||||||
 | 
					if(TARGET ${CORE_NAME}_cpp)
 | 
				
			||||||
 | 
					    add_dependencies(${PROJECT_NAME} ${CORE_NAME}_cpp)
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
 | 
					if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
 | 
				
			||||||
     target_compile_options(${PROJECT_NAME} PRIVATE -Wno-shift-count-overflow)
 | 
					     target_compile_options(${PROJECT_NAME} PRIVATE -Wno-shift-count-overflow)
 | 
				
			||||||
@@ -84,8 +89,8 @@ if(TARGET jsoncpp::jsoncpp)
 | 
				
			|||||||
else()
 | 
					else()
 | 
				
			||||||
	target_link_libraries(${PROJECT_NAME} PUBLIC jsoncpp)
 | 
						target_link_libraries(${PROJECT_NAME} PUBLIC jsoncpp)
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
if(BUILD_SHARED_LIBS)
 | 
					if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND BUILD_SHARED_LIBS)
 | 
				
			||||||
    target_force_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-core)
 | 
					    target_link_libraries(${PROJECT_NAME} PUBLIC -Wl,--whole-archive dbt-rise-core -Wl,--no-whole-archive)
 | 
				
			||||||
else()
 | 
					else()
 | 
				
			||||||
    target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-core)
 | 
					    target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-core)
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
@@ -156,7 +161,7 @@ if(WITH_TCC)
 | 
				
			|||||||
    target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_TCC)
 | 
					    target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_TCC)
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
# Links the target exe against the libraries
 | 
					# Links the target exe against the libraries
 | 
				
			||||||
target_force_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc)
 | 
					target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc)
 | 
				
			||||||
if(TARGET Boost::program_options)
 | 
					if(TARGET Boost::program_options)
 | 
				
			||||||
    target_link_libraries(${PROJECT_NAME} PUBLIC Boost::program_options)
 | 
					    target_link_libraries(${PROJECT_NAME} PUBLIC Boost::program_options)
 | 
				
			||||||
else()
 | 
					else()
 | 
				
			||||||
@@ -181,13 +186,10 @@ install(TARGETS tgc-sim
 | 
				
			|||||||
###############################################################################
 | 
					###############################################################################
 | 
				
			||||||
if(TARGET scc-sysc)
 | 
					if(TARGET scc-sysc)
 | 
				
			||||||
	project(dbt-rise-tgc_sc VERSION 1.0.0)
 | 
						project(dbt-rise-tgc_sc VERSION 1.0.0)
 | 
				
			||||||
	set(LIB_SOURCES 
 | 
					    add_library(${PROJECT_NAME} 
 | 
				
			||||||
    	src/sysc/core_complex.cpp
 | 
					    	src/sysc/core_complex.cpp
 | 
				
			||||||
    	src/sysc/register_tgc_c.cpp
 | 
					    	src/sysc/register_tgc_c.cpp
 | 
				
			||||||
	)
 | 
					    )
 | 
				
			||||||
	FILE(GLOB GEN_SC_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/sysc/register_*.cpp)
 | 
					 | 
				
			||||||
	list(APPEND LIB_SOURCES ${GEN_SC_SOURCES})
 | 
					 | 
				
			||||||
    add_library(${PROJECT_NAME} ${LIB_SOURCES})
 | 
					 | 
				
			||||||
    target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC)
 | 
					    target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC)
 | 
				
			||||||
    target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
 | 
					    target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
 | 
				
			||||||
    foreach(F IN LISTS TGC_SOURCES)
 | 
					    foreach(F IN LISTS TGC_SOURCES)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,35 +0,0 @@
 | 
				
			|||||||
# according to https://github.com/horance-liu/flink.cmake/tree/master
 | 
					 | 
				
			||||||
# SPDX-License-Identifier: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
include(CMakeParseArguments)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function(target_do_force_link_libraries target visibility lib)
 | 
					 | 
				
			||||||
  if(MSVC)
 | 
					 | 
				
			||||||
    target_link_libraries(${target} ${visibility} "/WHOLEARCHIVE:${lib}")
 | 
					 | 
				
			||||||
  elseif(APPLE)
 | 
					 | 
				
			||||||
    target_link_libraries(${target} ${visibility} -Wl,-force_load ${lib})
 | 
					 | 
				
			||||||
  else()
 | 
					 | 
				
			||||||
    target_link_libraries(${target} ${visibility} -Wl,--whole-archive ${lib} -Wl,--no-whole-archive)
 | 
					 | 
				
			||||||
  endif()
 | 
					 | 
				
			||||||
endfunction()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function(target_force_link_libraries target)
 | 
					 | 
				
			||||||
  cmake_parse_arguments(FLINK
 | 
					 | 
				
			||||||
    ""
 | 
					 | 
				
			||||||
    ""
 | 
					 | 
				
			||||||
    "PUBLIC;INTERFACE;PRIVATE"
 | 
					 | 
				
			||||||
    ${ARGN}
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
  foreach(lib IN LISTS FLINK_PUBLIC)
 | 
					 | 
				
			||||||
    target_do_force_link_libraries(${target} PUBLIC ${lib})
 | 
					 | 
				
			||||||
  endforeach()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  foreach(lib IN LISTS FLINK_INTERFACE)
 | 
					 | 
				
			||||||
    target_do_force_link_libraries(${target} INTERFACE ${lib})
 | 
					 | 
				
			||||||
  endforeach()
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
  foreach(lib IN LISTS FLINK_PRIVATE)
 | 
					 | 
				
			||||||
    target_do_force_link_libraries(${target} PRIVATE ${lib})
 | 
					 | 
				
			||||||
  endforeach()
 | 
					 | 
				
			||||||
endfunction()
 | 
					 | 
				
			||||||
@@ -55,7 +55,7 @@ def byteSize(int size){
 | 
				
			|||||||
    return 128;
 | 
					    return 128;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
def getCString(def val){
 | 
					def getCString(def val){
 | 
				
			||||||
    return val.toString()+'ULL'
 | 
					    return val.toString()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
%>
 | 
					%>
 | 
				
			||||||
#ifndef _${coreDef.name.toUpperCase()}_H_
 | 
					#ifndef _${coreDef.name.toUpperCase()}_H_
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,72 +0,0 @@
 | 
				
			|||||||
/*******************************************************************************
 | 
					 | 
				
			||||||
 * Copyright (C) 2023 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_factory.h"
 | 
					 | 
				
			||||||
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
 | 
					 | 
				
			||||||
#include <iss/arch/riscv_hart_m_p.h>
 | 
					 | 
				
			||||||
#include <iss/arch/riscv_hart_mu_p.h>
 | 
					 | 
				
			||||||
#include "sc_core_adapter.h"
 | 
					 | 
				
			||||||
#include "core_complex.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace iss {
 | 
					 | 
				
			||||||
namespace interp {
 | 
					 | 
				
			||||||
using namespace sysc;
 | 
					 | 
				
			||||||
volatile std::array<bool, 2> ${coreDef.name.toLowerCase()}_init = {
 | 
					 | 
				
			||||||
        iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
 | 
					 | 
				
			||||||
            auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
 | 
					 | 
				
			||||||
            auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::${coreDef.name.toLowerCase()}>>(cc);
 | 
					 | 
				
			||||||
            return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
 | 
					 | 
				
			||||||
        }),
 | 
					 | 
				
			||||||
        iss_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
 | 
					 | 
				
			||||||
            auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
 | 
					 | 
				
			||||||
            auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}>>(cc);
 | 
					 | 
				
			||||||
            return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#if defined(WITH_TCC)
 | 
					 | 
				
			||||||
namespace tcc {
 | 
					 | 
				
			||||||
volatile std::array<bool, 2> ${coreDef.name.toLowerCase()}_init = {
 | 
					 | 
				
			||||||
        core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned gdb_port, void* data) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
					 | 
				
			||||||
            auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
 | 
					 | 
				
			||||||
            auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::${coreDef.name.toLowerCase()}>>(cc);
 | 
					 | 
				
			||||||
            return {cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
 | 
					 | 
				
			||||||
        }),
 | 
					 | 
				
			||||||
        core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned gdb_port, void* data) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
					 | 
				
			||||||
            auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
 | 
					 | 
				
			||||||
            auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::${coreDef.name.toLowerCase()}>>(cc);
 | 
					 | 
				
			||||||
            return {cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::${coreDef.name.toLowerCase()}*>(cpu), gdb_port)}};
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -158,81 +158,30 @@ private:
 | 
				
			|||||||
    /****************************************************************************
 | 
					    /****************************************************************************
 | 
				
			||||||
     * start opcode definitions
 | 
					     * start opcode definitions
 | 
				
			||||||
     ****************************************************************************/
 | 
					     ****************************************************************************/
 | 
				
			||||||
    struct instruction_descriptor {
 | 
					    struct InstructionDesriptor {
 | 
				
			||||||
        size_t length;
 | 
					        size_t length;
 | 
				
			||||||
        uint32_t value;
 | 
					        uint32_t value;
 | 
				
			||||||
        uint32_t mask;
 | 
					        uint32_t mask;
 | 
				
			||||||
        typename arch::traits<ARCH>::opcode_e op;
 | 
					        typename arch::traits<ARCH>::opcode_e op;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    struct decoding_tree_node{
 | 
					 | 
				
			||||||
        std::vector<instruction_descriptor> instrs;
 | 
					 | 
				
			||||||
        std::vector<decoding_tree_node*> children;
 | 
					 | 
				
			||||||
        uint32_t submask = std::numeric_limits<uint32_t>::max();
 | 
					 | 
				
			||||||
        uint32_t value;
 | 
					 | 
				
			||||||
        decoding_tree_node(uint32_t value) : value(value){}
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    decoding_tree_node* root {nullptr};
 | 
					    const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
 | 
				
			||||||
    const std::array<instruction_descriptor, ${instructions.size}> instr_descr = {{
 | 
					 | 
				
			||||||
         /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
 | 
					         /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
 | 
				
			||||||
        {${instr.length}, ${instr.encoding}, ${instr.mask}, arch::traits<ARCH>::opcode_e::${instr.instruction.name}},<%}%>
 | 
					        {${instr.length}, ${instr.encoding}, ${instr.mask}, arch::traits<ARCH>::opcode_e::${instr.instruction.name}},<%}%>
 | 
				
			||||||
    }};
 | 
					    }};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //static constexpr typename traits::addr_t upper_bits = ~traits::PGMASK;
 | 
				
			||||||
    iss::status fetch_ins(virt_addr_t pc, uint8_t * data){
 | 
					    iss::status fetch_ins(virt_addr_t pc, uint8_t * data){
 | 
				
			||||||
        auto phys_pc = this->core.v2p(pc);
 | 
					        auto phys_pc = this->core.v2p(pc);
 | 
				
			||||||
 | 
					        //if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
 | 
				
			||||||
 | 
					        //    if (this->core.read(phys_pc, 2, data) != iss::Ok) return iss::Err;
 | 
				
			||||||
 | 
					        //    if ((data[0] & 0x3) == 0x3) // this is a 32bit instruction
 | 
				
			||||||
 | 
					        //        if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) return iss::Err;
 | 
				
			||||||
 | 
					        //} else {
 | 
				
			||||||
            if (this->core.read(phys_pc, 4, data) != iss::Ok)  return iss::Err;
 | 
					            if (this->core.read(phys_pc, 4, data) != iss::Ok)  return iss::Err;
 | 
				
			||||||
 | 
					        //}
 | 
				
			||||||
        return iss::Ok;
 | 
					        return iss::Ok;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    void populate_decoding_tree(decoding_tree_node* root){
 | 
					 | 
				
			||||||
        //create submask
 | 
					 | 
				
			||||||
        for(auto instr: root->instrs){
 | 
					 | 
				
			||||||
            root->submask &= instr.mask;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        //put each instr according to submask&encoding into children
 | 
					 | 
				
			||||||
        for(auto instr: root->instrs){
 | 
					 | 
				
			||||||
            bool foundMatch = false;
 | 
					 | 
				
			||||||
            for(auto child: root->children){
 | 
					 | 
				
			||||||
                //use value as identifying trait
 | 
					 | 
				
			||||||
                if(child->value == (instr.value&root->submask)){
 | 
					 | 
				
			||||||
                    child->instrs.push_back(instr);
 | 
					 | 
				
			||||||
                    foundMatch = true;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if(!foundMatch){
 | 
					 | 
				
			||||||
                decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask);
 | 
					 | 
				
			||||||
                child->instrs.push_back(instr);
 | 
					 | 
				
			||||||
                root->children.push_back(child);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        root->instrs.clear();
 | 
					 | 
				
			||||||
        //call populate_decoding_tree for all children
 | 
					 | 
				
			||||||
        if(root->children.size() >1)
 | 
					 | 
				
			||||||
            for(auto child: root->children){
 | 
					 | 
				
			||||||
                populate_decoding_tree(child);      
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        else{
 | 
					 | 
				
			||||||
            //sort instrs by value of the mask, this works bc we want to have the least restrictive one last
 | 
					 | 
				
			||||||
            std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) {
 | 
					 | 
				
			||||||
            return instr1.mask > instr2.mask;
 | 
					 | 
				
			||||||
            }); 
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    typename arch::traits<ARCH>::opcode_e  decode_instr(decoding_tree_node* node, code_word_t word){
 | 
					 | 
				
			||||||
        if(!node->children.size()){
 | 
					 | 
				
			||||||
            if(node->instrs.size() == 1) return node->instrs[0].op;
 | 
					 | 
				
			||||||
            for(auto instr : node->instrs){
 | 
					 | 
				
			||||||
                if((instr.mask&word) == instr.value) return instr.op;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else{
 | 
					 | 
				
			||||||
            for(auto child : node->children){
 | 
					 | 
				
			||||||
                if (child->value == (node->submask&word)){
 | 
					 | 
				
			||||||
                    return decode_instr(child, word);
 | 
					 | 
				
			||||||
                }  
 | 
					 | 
				
			||||||
            }  
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return arch::traits<ARCH>::opcode_e::MAX_OPCODE;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
 | 
					template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
 | 
				
			||||||
@@ -259,11 +208,16 @@ constexpr size_t bit_count(uint32_t u) {
 | 
				
			|||||||
template <typename ARCH>
 | 
					template <typename ARCH>
 | 
				
			||||||
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
 | 
					vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
 | 
				
			||||||
: vm_base<ARCH>(core, core_id, cluster_id) {
 | 
					: vm_base<ARCH>(core, core_id, cluster_id) {
 | 
				
			||||||
    root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
 | 
					    unsigned id=0;
 | 
				
			||||||
    for(auto instr:instr_descr){
 | 
					    for (auto instr : instr_descr) {
 | 
				
			||||||
        root->instrs.push_back(instr);
 | 
					        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);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    populate_decoding_tree(root);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline bool is_count_limit_enabled(finish_cond_e cond){
 | 
					inline bool is_count_limit_enabled(finish_cond_e cond){
 | 
				
			||||||
@@ -274,6 +228,14 @@ inline bool is_jump_to_self_enabled(finish_cond_e cond){
 | 
				
			|||||||
    return (cond & finish_cond_e::JUMP_TO_SELF) == finish_cond_e::JUMP_TO_SELF;
 | 
					    return (cond & finish_cond_e::JUMP_TO_SELF) == finish_cond_e::JUMP_TO_SELF;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename ARCH>
 | 
				
			||||||
 | 
					typename arch::traits<ARCH>::opcode_e vm_impl<ARCH>::decode_inst_id(code_word_t instr){
 | 
				
			||||||
 | 
					    for(auto& e: qlut[instr&0x3]){
 | 
				
			||||||
 | 
					        if(!((instr&e.mask) ^ e.value )) return e.id;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return arch::traits<ARCH>::opcode_e::MAX_OPCODE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename ARCH>
 | 
					template <typename ARCH>
 | 
				
			||||||
typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){
 | 
					typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){
 | 
				
			||||||
    auto pc=start;
 | 
					    auto pc=start;
 | 
				
			||||||
@@ -295,7 +257,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
 | 
				
			|||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            if (is_jump_to_self_enabled(cond) &&
 | 
					            if (is_jump_to_self_enabled(cond) &&
 | 
				
			||||||
                    (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
 | 
					                    (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
 | 
				
			||||||
            auto inst_id = decode_instr(root, instr);
 | 
					            auto inst_id = decode_inst_id(instr);
 | 
				
			||||||
            // pre execution stuff
 | 
					            // pre execution stuff
 | 
				
			||||||
             this->core.reg.last_branch = 0;
 | 
					             this->core.reg.last_branch = 0;
 | 
				
			||||||
            if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id));
 | 
					            if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id));
 | 
				
			||||||
@@ -342,7 +304,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
 | 
				
			|||||||
    return pc;
 | 
					    return pc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace ${coreDef.name.toLowerCase()}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <>
 | 
					template <>
 | 
				
			||||||
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
 | 
					std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
 | 
				
			||||||
@@ -358,14 +320,14 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
 | 
				
			|||||||
#include <iss/arch/riscv_hart_mu_p.h>
 | 
					#include <iss/arch/riscv_hart_mu_p.h>
 | 
				
			||||||
namespace iss {
 | 
					namespace iss {
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
volatile std::array<bool, 2> dummy = {
 | 
					std::array<bool, 2> dummy = {
 | 
				
			||||||
        core_factory::instance().register_creator<core_factory::CPP>("${coreDef.name.toLowerCase()}|m_p|interp", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
					        core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|interp", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
				
			||||||
            auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
 | 
					            auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
 | 
				
			||||||
		    auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
 | 
							    auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
 | 
				
			||||||
		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
 | 
							    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
 | 
				
			||||||
            return {cpu_ptr{cpu}, vm_ptr{vm}};
 | 
					            return {cpu_ptr{cpu}, vm_ptr{vm}};
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
        core_factory::instance().register_creator<core_factory::CPP>("${coreDef.name.toLowerCase()}|mu_p|interp", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
					        core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|interp", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
				
			||||||
            auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>();
 | 
					            auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>();
 | 
				
			||||||
		    auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
 | 
							    auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
 | 
				
			||||||
		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
 | 
							    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
 | 
				
			||||||
@@ -374,3 +336,8 @@ volatile std::array<bool, 2> dummy = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
						bool* get_${coreDef.name.toLowerCase()}_interp_creators() {
 | 
				
			||||||
 | 
							return iss::dummy.data();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -120,7 +120,57 @@ protected:
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					    // 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(static_cast<uint32_t>(EXTR_MASK32)), LUT_SIZE_C = 1 << util::bit_count(static_cast<uint32_t>(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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
 | 
					    template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
 | 
				
			||||||
    inline S sext(U from) {
 | 
					    inline S sext(U from) {
 | 
				
			||||||
        auto mask = (1ULL<<W) - 1;
 | 
					        auto mask = (1ULL<<W) - 1;
 | 
				
			||||||
@@ -132,23 +182,14 @@ private:
 | 
				
			|||||||
    /****************************************************************************
 | 
					    /****************************************************************************
 | 
				
			||||||
     * start opcode definitions
 | 
					     * start opcode definitions
 | 
				
			||||||
     ****************************************************************************/
 | 
					     ****************************************************************************/
 | 
				
			||||||
    struct instruction_descriptor {
 | 
					    struct InstructionDesriptor {
 | 
				
			||||||
        size_t length;
 | 
					        size_t length;
 | 
				
			||||||
        uint32_t value;
 | 
					        uint32_t value;
 | 
				
			||||||
        uint32_t mask;
 | 
					        uint32_t mask;
 | 
				
			||||||
        compile_func op;
 | 
					        compile_func op;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    struct decoding_tree_node{
 | 
					 | 
				
			||||||
        std::vector<instruction_descriptor> instrs;
 | 
					 | 
				
			||||||
        std::vector<decoding_tree_node*> children;
 | 
					 | 
				
			||||||
        uint32_t submask = std::numeric_limits<uint32_t>::max();
 | 
					 | 
				
			||||||
        uint32_t value;
 | 
					 | 
				
			||||||
        decoding_tree_node(uint32_t value) : value(value){}
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    decoding_tree_node* root {nullptr};
 | 
					    const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
 | 
				
			||||||
 | 
					 | 
				
			||||||
    const std::array<instruction_descriptor, ${instructions.size}> instr_descr = {{
 | 
					 | 
				
			||||||
         /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
 | 
					         /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
 | 
				
			||||||
        /* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
 | 
					        /* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
 | 
				
			||||||
        {${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
 | 
					        {${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
 | 
				
			||||||
@@ -186,64 +227,11 @@ private:
 | 
				
			|||||||
        vm_impl::gen_trap_check(tu);
 | 
					        vm_impl::gen_trap_check(tu);
 | 
				
			||||||
        return BRANCH;
 | 
					        return BRANCH;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    //decoding functionality
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void populate_decoding_tree(decoding_tree_node* root){
 | 
					 | 
				
			||||||
        //create submask
 | 
					 | 
				
			||||||
        for(auto instr: root->instrs){
 | 
					 | 
				
			||||||
            root->submask &= instr.mask;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        //put each instr according to submask&encoding into children
 | 
					 | 
				
			||||||
        for(auto instr: root->instrs){
 | 
					 | 
				
			||||||
            bool foundMatch = false;
 | 
					 | 
				
			||||||
            for(auto child: root->children){
 | 
					 | 
				
			||||||
                //use value as identifying trait
 | 
					 | 
				
			||||||
                if(child->value == (instr.value&root->submask)){
 | 
					 | 
				
			||||||
                    child->instrs.push_back(instr);
 | 
					 | 
				
			||||||
                    foundMatch = true;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if(!foundMatch){
 | 
					 | 
				
			||||||
                decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask);
 | 
					 | 
				
			||||||
                child->instrs.push_back(instr);
 | 
					 | 
				
			||||||
                root->children.push_back(child);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        root->instrs.clear();
 | 
					 | 
				
			||||||
        //call populate_decoding_tree for all children
 | 
					 | 
				
			||||||
        if(root->children.size() >1)
 | 
					 | 
				
			||||||
            for(auto child: root->children){
 | 
					 | 
				
			||||||
                populate_decoding_tree(child);      
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        else{
 | 
					 | 
				
			||||||
            //sort instrs by value of the mask, this works bc we want to have the least restrictive one last
 | 
					 | 
				
			||||||
            std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) {
 | 
					 | 
				
			||||||
            return instr1.mask > instr2.mask;
 | 
					 | 
				
			||||||
            }); 
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    compile_func decode_instr(decoding_tree_node* node, code_word_t word){
 | 
					 | 
				
			||||||
        if(!node->children.size()){
 | 
					 | 
				
			||||||
            if(node->instrs.size() == 1) return node->instrs[0].op;
 | 
					 | 
				
			||||||
            for(auto instr : node->instrs){
 | 
					 | 
				
			||||||
                if((instr.mask&word) == instr.value) return instr.op;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else{
 | 
					 | 
				
			||||||
            for(auto child : node->children){
 | 
					 | 
				
			||||||
                if (child->value == (node->submask&word)){
 | 
					 | 
				
			||||||
                    return decode_instr(child, word);
 | 
					 | 
				
			||||||
                }  
 | 
					 | 
				
			||||||
            }  
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return nullptr;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename CODE_WORD> void debug_fn(CODE_WORD instr) {
 | 
					template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
 | 
				
			||||||
    volatile CODE_WORD x = instr;
 | 
					    volatile CODE_WORD x = insn;
 | 
				
			||||||
    instr = 2 * x;
 | 
					    insn = 2 * x;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
 | 
					template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
 | 
				
			||||||
@@ -251,11 +239,14 @@ template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
 | 
				
			|||||||
template <typename ARCH>
 | 
					template <typename ARCH>
 | 
				
			||||||
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
 | 
					vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
 | 
				
			||||||
: vm_base<ARCH>(core, core_id, cluster_id) {
 | 
					: vm_base<ARCH>(core, core_id, cluster_id) {
 | 
				
			||||||
    root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
 | 
					    qlut[0] = lut_00.data();
 | 
				
			||||||
    for(auto instr:instr_descr){
 | 
					    qlut[1] = lut_01.data();
 | 
				
			||||||
        root->instrs.push_back(instr);
 | 
					    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);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    populate_decoding_tree(root);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename ARCH>
 | 
					template <typename ARCH>
 | 
				
			||||||
@@ -263,19 +254,30 @@ std::tuple<continuation_e>
 | 
				
			|||||||
vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, tu_builder& tu) {
 | 
					vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, tu_builder& tu) {
 | 
				
			||||||
    // we fetch at max 4 byte, alignment is 2
 | 
					    // we fetch at max 4 byte, alignment is 2
 | 
				
			||||||
    enum {TRAP_ID=1<<16};
 | 
					    enum {TRAP_ID=1<<16};
 | 
				
			||||||
    code_word_t instr = 0;
 | 
					    code_word_t insn = 0;
 | 
				
			||||||
 | 
					    // const typename traits::addr_t upper_bits = ~traits::PGMASK;
 | 
				
			||||||
    phys_addr_t paddr(pc);
 | 
					    phys_addr_t paddr(pc);
 | 
				
			||||||
 | 
					    auto *const data = (uint8_t *)&insn;
 | 
				
			||||||
    paddr = this->core.v2p(pc);
 | 
					    paddr = this->core.v2p(pc);
 | 
				
			||||||
    auto res = this->core.read(paddr, 4, reinterpret_cast<uint8_t*>(&instr));
 | 
					//    if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
 | 
				
			||||||
    if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
 | 
					//        auto res = this->core.read(paddr, 2, data);
 | 
				
			||||||
    if (instr == 0x0000006f || (instr&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
 | 
					//        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
 | 
					    // curr pc on stack
 | 
				
			||||||
    ++inst_cnt;
 | 
					    ++inst_cnt;
 | 
				
			||||||
    auto f = decode_instr(root, instr);
 | 
					    auto lut_val = extract_fields(insn);
 | 
				
			||||||
 | 
					    auto f = qlut[insn & 0x3][lut_val];
 | 
				
			||||||
    if (f == nullptr) {
 | 
					    if (f == nullptr) {
 | 
				
			||||||
        f = &this_class::illegal_intruction;
 | 
					        f = &this_class::illegal_intruction;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return (this->*f)(pc, instr, tu);
 | 
					    return (this->*f)(pc, insn, tu);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) {
 | 
					template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) {
 | 
				
			||||||
@@ -299,7 +301,7 @@ template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(tu_builder& tu) {
 | 
				
			|||||||
    tu("return *next_pc;");
 | 
					    tu("return *next_pc;");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace ${coreDef.name.toLowerCase()}
 | 
					} // namespace mnrv32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <>
 | 
					template <>
 | 
				
			||||||
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
 | 
					std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
 | 
				
			||||||
@@ -315,14 +317,14 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
 | 
				
			|||||||
#include <iss/arch/riscv_hart_mu_p.h>
 | 
					#include <iss/arch/riscv_hart_mu_p.h>
 | 
				
			||||||
namespace iss {
 | 
					namespace iss {
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
volatile std::array<bool, 2> dummy = {
 | 
					std::array<bool, 2> dummy = {
 | 
				
			||||||
        core_factory::instance().register_creator<core_factory::CPP>("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
					        core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
				
			||||||
            auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
 | 
					            auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
 | 
				
			||||||
		    auto vm = new tcc::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
 | 
							    auto vm = new tcc::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
 | 
				
			||||||
		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
 | 
							    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
 | 
				
			||||||
            return {cpu_ptr{cpu}, vm_ptr{vm}};
 | 
					            return {cpu_ptr{cpu}, vm_ptr{vm}};
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
        core_factory::instance().register_creator<core_factory::CPP>("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
					        core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
				
			||||||
            auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>();
 | 
					            auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>();
 | 
				
			||||||
		    auto vm = new tcc::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
 | 
							    auto vm = new tcc::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
 | 
				
			||||||
		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
 | 
							    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
 | 
				
			||||||
@@ -331,3 +333,8 @@ volatile std::array<bool, 2> dummy = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
						bool* get_${coreDef.name.toLowerCase()}_tcc_creators() {
 | 
				
			||||||
 | 
							return iss::dummy.data();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										3
									
								
								src-gen/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								src-gen/.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,2 @@
 | 
				
			|||||||
/iss
 | 
					/iss
 | 
				
			||||||
/vm
 | 
					/vm
 | 
				
			||||||
/sysc
 | 
					 | 
				
			||||||
@@ -53,7 +53,7 @@ template <> struct traits<tgc_c> {
 | 
				
			|||||||
    static constexpr std::array<const char*, 36> reg_aliases{
 | 
					    static constexpr std::array<const char*, 36> 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", "NEXT_PC", "PRIV", "DPC"}};
 | 
					        {"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", "NEXT_PC", "PRIV", "DPC"}};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    enum constants {MISA_VAL=1073746180ULL, MARCHID_VAL=2147483651ULL, XLEN=32ULL, INSTR_ALIGNMENT=2ULL, RFS=32ULL, fence=0ULL, fencei=1ULL, fencevmal=2ULL, fencevmau=3ULL, CSR_SIZE=4096ULL, MUL_LEN=64ULL};
 | 
					    enum constants {MISA_VAL=1073746180, MARCHID_VAL=2147483651, XLEN=32, INSTR_ALIGNMENT=2, RFS=32, fence=0, fencei=1, fencevmal=2, fencevmau=3, CSR_SIZE=4096, MUL_LEN=64};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constexpr static unsigned FP_REGS_SIZE = 0;
 | 
					    constexpr static unsigned FP_REGS_SIZE = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -80,17 +80,9 @@ class core_factory {
 | 
				
			|||||||
public:
 | 
					public:
 | 
				
			||||||
    static core_factory & instance() { static core_factory bf; return bf; }
 | 
					    static core_factory & instance() { static core_factory bf; return bf; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool register_creator(const std::string & className, create_fn const& fn) {
 | 
					    bool register_creator(const std::string &, create_fn const&);
 | 
				
			||||||
        registry[className] = fn;
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    base_t create(std::string const& className, unsigned gdb_port=0, void* init_data=nullptr) const {
 | 
					    base_t create(const std::string &, unsigned gdb_port=0, void* init_data=nullptr) const;
 | 
				
			||||||
        registry_t::const_iterator regEntry = registry.find(className);
 | 
					 | 
				
			||||||
        if (regEntry != registry.end())
 | 
					 | 
				
			||||||
            return regEntry->second(gdb_port, init_data);
 | 
					 | 
				
			||||||
        return {nullptr, nullptr};
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::vector<std::string> get_names() {
 | 
					    std::vector<std::string> get_names() {
 | 
				
			||||||
        std::vector<std::string> keys{registry.size()};
 | 
					        std::vector<std::string> keys{registry.size()};
 | 
				
			||||||
@@ -101,6 +93,18 @@ public:
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline bool core_factory::register_creator(const std::string & className, create_fn const& fn) {
 | 
				
			||||||
 | 
					    registry[className] = fn;
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline core_factory::base_t core_factory::create(const std::string &className, unsigned gdb_port, void* data) const {
 | 
				
			||||||
 | 
					    registry_t::const_iterator regEntry = registry.find(className);
 | 
				
			||||||
 | 
					    if (regEntry != registry.end())
 | 
				
			||||||
 | 
					        return regEntry->second(gdb_port, data);
 | 
				
			||||||
 | 
					    return {nullptr, nullptr};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _ISS_FACTORY_H_ */
 | 
					#endif /* _ISS_FACTORY_H_ */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,7 +39,7 @@
 | 
				
			|||||||
#include <boost/program_options.hpp>
 | 
					#include <boost/program_options.hpp>
 | 
				
			||||||
#include "iss/arch/tgc_mapper.h"
 | 
					#include "iss/arch/tgc_mapper.h"
 | 
				
			||||||
#ifdef WITH_LLVM
 | 
					#ifdef WITH_LLVM
 | 
				
			||||||
#include <iss/llvm/jit_init.h>
 | 
					#include <iss/llvm/jit_helper.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#include <iss/log_categories.h>
 | 
					#include <iss/log_categories.h>
 | 
				
			||||||
#include "iss/plugin/cycle_estimate.h"
 | 
					#include "iss/plugin/cycle_estimate.h"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,11 +37,10 @@
 | 
				
			|||||||
#include <iss/debugger/target_adapter_if.h>
 | 
					#include <iss/debugger/target_adapter_if.h>
 | 
				
			||||||
#include <iss/iss.h>
 | 
					#include <iss/iss.h>
 | 
				
			||||||
#include <iss/vm_types.h>
 | 
					#include <iss/vm_types.h>
 | 
				
			||||||
#include "iss_factory.h"
 | 
					 | 
				
			||||||
#ifndef WIN32
 | 
					#ifndef WIN32
 | 
				
			||||||
#include <iss/plugin/loader.h>
 | 
					#include <iss/plugin/loader.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#include "sc_core_adapter_if.h"
 | 
					#include "core_complex.h"
 | 
				
			||||||
#include <iss/arch/tgc_mapper.h>
 | 
					#include <iss/arch/tgc_mapper.h>
 | 
				
			||||||
#include <scc/report.h>
 | 
					#include <scc/report.h>
 | 
				
			||||||
#include <util/ities.h>
 | 
					#include <util/ities.h>
 | 
				
			||||||
@@ -86,9 +85,136 @@ using namespace sc_core;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
iss::debugger::encoder_decoder encdec;
 | 
					iss::debugger::encoder_decoder encdec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
 | 
					std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename PLAT>
 | 
				
			||||||
 | 
					class core_wrapper_t : public PLAT {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    using reg_t       = typename arch::traits<typename PLAT::core>::reg_t;
 | 
				
			||||||
 | 
					    using phys_addr_t = typename arch::traits<typename PLAT::core>::phys_addr_t;
 | 
				
			||||||
 | 
					    using heart_state_t = typename PLAT::hart_state_type;
 | 
				
			||||||
 | 
					    core_wrapper_t(core_complex *owner)
 | 
				
			||||||
 | 
					    : owner(owner) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t get_mode() { return this->reg.PRIV; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline void set_interrupt_execution(bool v) { this->interrupt_sim = v?1:0; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline bool get_interrupt_execution() { return this->interrupt_sim; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    heart_state_t &get_state() { return this->state; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void notify_phase(iss::arch_if::exec_phase p) override {
 | 
				
			||||||
 | 
					        if (p == iss::arch_if::ISTART)
 | 
				
			||||||
 | 
					            owner->sync(this->instr_if.get_total_cycles());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sync_type needed_sync() const override { return PRE_SYNC; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void disass_output(uint64_t pc, const std::string instr) override {
 | 
				
			||||||
 | 
					        if (!owner->disass_output(pc, instr)) {
 | 
				
			||||||
 | 
					            std::stringstream s;
 | 
				
			||||||
 | 
					            s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0')
 | 
				
			||||||
 | 
					              << std::setw(sizeof(reg_t) * 2) << (reg_t)this->state.mstatus << std::dec << ";c:"
 | 
				
			||||||
 | 
					              << this->reg.icount + this->cycle_offset << "]";
 | 
				
			||||||
 | 
					            SCCDEBUG(owner->name())<<"disass: "
 | 
				
			||||||
 | 
					                << "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40)
 | 
				
			||||||
 | 
					                << std::setfill(' ') << std::left << instr << s.str();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data) override {
 | 
				
			||||||
 | 
					        if (addr.access && access_type::DEBUG)
 | 
				
			||||||
 | 
					            return owner->read_mem_dbg(addr.val, length, data) ? Ok : Err;
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            return owner->read_mem(addr.val, length, data, is_fetch(addr.access)) ? Ok : Err;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    status write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data) override {
 | 
				
			||||||
 | 
					        if (addr.access && access_type::DEBUG)
 | 
				
			||||||
 | 
					            return owner->write_mem_dbg(addr.val, length, data) ? Ok : Err;
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            auto res = owner->write_mem(addr.val, length, data) ? Ok : Err;
 | 
				
			||||||
 | 
					            // clear MTIP on mtimecmp write
 | 
				
			||||||
 | 
					            if (addr.val == 0x2004000) {
 | 
				
			||||||
 | 
					                reg_t val;
 | 
				
			||||||
 | 
					                this->read_csr(arch::mip, val);
 | 
				
			||||||
 | 
					                if (val & (1ULL << 7)) this->write_csr(arch::mip, val & ~(1ULL << 7));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return res;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    status read_csr(unsigned addr, reg_t &val) override {
 | 
				
			||||||
 | 
					#ifndef CWR_SYSTEMC
 | 
				
			||||||
 | 
					        if((addr==arch::time || addr==arch::timeh) && owner->mtime_o.get_interface(0)){
 | 
				
			||||||
 | 
					            uint64_t time_val;
 | 
				
			||||||
 | 
					            bool ret = owner->mtime_o->nb_peek(time_val);
 | 
				
			||||||
 | 
					            if (addr == iss::arch::time) {
 | 
				
			||||||
 | 
					                val = static_cast<reg_t>(time_val);
 | 
				
			||||||
 | 
					            } else if (addr == iss::arch::timeh) {
 | 
				
			||||||
 | 
					                if (sizeof(reg_t) != 4) return iss::Err;
 | 
				
			||||||
 | 
					                val = static_cast<reg_t>(time_val >> 32);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return ret?Ok:Err;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							if((addr==arch::time || addr==arch::timeh)){
 | 
				
			||||||
 | 
								uint64_t time_val = owner->mtime_i.read();
 | 
				
			||||||
 | 
								if (addr == iss::arch::time) {
 | 
				
			||||||
 | 
									val = static_cast<reg_t>(time_val);
 | 
				
			||||||
 | 
								} else if (addr == iss::arch::timeh) {
 | 
				
			||||||
 | 
									if (sizeof(reg_t) != 4) return iss::Err;
 | 
				
			||||||
 | 
									val = static_cast<reg_t>(time_val >> 32);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return Ok;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return PLAT::read_csr(addr, val);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void wait_until(uint64_t flags) override {
 | 
				
			||||||
 | 
					        SCCDEBUG(owner->name()) << "Sleeping until interrupt";
 | 
				
			||||||
 | 
					        while(this->reg.pending_trap == 0 && (this->csr[arch::mip] & this->csr[arch::mie]) == 0) {
 | 
				
			||||||
 | 
					            sc_core::wait(wfi_evt);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        PLAT::wait_until(flags);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void local_irq(short id, bool value) {
 | 
				
			||||||
 | 
					        reg_t mask = 0;
 | 
				
			||||||
 | 
					        switch (id) {
 | 
				
			||||||
 | 
					        case 3: // SW
 | 
				
			||||||
 | 
					            mask = 1 << 3;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case 7: // timer
 | 
				
			||||||
 | 
					            mask = 1 << 7;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case 11: // external
 | 
				
			||||||
 | 
					            mask = 1 << 11;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            if(id>15) mask = 1 << id;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (value) {
 | 
				
			||||||
 | 
					            this->csr[arch::mip] |= mask;
 | 
				
			||||||
 | 
					            wfi_evt.notify();
 | 
				
			||||||
 | 
					        } else
 | 
				
			||||||
 | 
					            this->csr[arch::mip] &= ~mask;
 | 
				
			||||||
 | 
					        this->check_interrupt();
 | 
				
			||||||
 | 
					        if(value)
 | 
				
			||||||
 | 
					            SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    core_complex *const owner;
 | 
				
			||||||
 | 
					    sc_event wfi_evt;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int cmd_sysc(int argc, char *argv[], debugger::out_func of, debugger::data_func df,
 | 
					int cmd_sysc(int argc, char *argv[], debugger::out_func of, debugger::data_func df,
 | 
				
			||||||
             debugger::target_adapter_if *tgt_adapter) {
 | 
					             debugger::target_adapter_if *tgt_adapter) {
 | 
				
			||||||
    if (argc > 1) {
 | 
					    if (argc > 1) {
 | 
				
			||||||
@@ -128,9 +254,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void reset(uint64_t addr){vm->reset(addr);}
 | 
					    void reset(uint64_t addr){vm->reset(addr);}
 | 
				
			||||||
    inline void start(){vm->start();}
 | 
					    inline void start(){vm->start();}
 | 
				
			||||||
    inline std::pair<uint64_t, bool> load_file(std::string const& name){
 | 
					    inline std::pair<uint64_t, bool> load_file(std::string const& name){ return cpu->load_file(name);};
 | 
				
			||||||
        iss::arch_if* cc = cpu->get_arch_if();
 | 
					 | 
				
			||||||
        return cc->load_file(name);};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::function<unsigned(void)> get_mode;
 | 
					    std::function<unsigned(void)> get_mode;
 | 
				
			||||||
    std::function<uint64_t(void)> get_state;
 | 
					    std::function<uint64_t(void)> get_state;
 | 
				
			||||||
@@ -138,35 +262,45 @@ public:
 | 
				
			|||||||
    std::function<void(bool)> set_interrupt_execution;
 | 
					    std::function<void(bool)> set_interrupt_execution;
 | 
				
			||||||
    std::function<void(short, bool)> local_irq;
 | 
					    std::function<void(short, bool)> local_irq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void create_cpu(std::string const& type, std::string const& backend, unsigned gdb_port, uint32_t hart_id){
 | 
					    template<typename PLAT>
 | 
				
			||||||
        auto & f = sysc::iss_factory::instance();
 | 
					    std::tuple<cpu_ptr, vm_ptr> create_core(std::string const& backend, unsigned gdb_port, uint32_t hart_id){
 | 
				
			||||||
        if(type.size()==0 || type == "?") {
 | 
					        auto* lcpu = new core_wrapper_t<PLAT>(owner);
 | 
				
			||||||
            std::cout<<"Available cores: "<<util::join(f.get_names(), ", ")<<std::endl;
 | 
					        lcpu->set_mhartid(hart_id);
 | 
				
			||||||
            sc_core::sc_stop();
 | 
					        get_mode = [lcpu]() { return lcpu->get_mode(); };
 | 
				
			||||||
        } else if (type.find('|') != std::string::npos) {
 | 
					        get_state = [lcpu]() { return lcpu->get_state().mstatus.backing.val; };
 | 
				
			||||||
            std::tie(cpu, vm) = f.create(type+"|"+backend);
 | 
					        get_interrupt_execution = [lcpu]() { return lcpu->get_interrupt_execution(); };
 | 
				
			||||||
        } else {
 | 
					        set_interrupt_execution = [lcpu](bool b) { return lcpu->set_interrupt_execution(b); };
 | 
				
			||||||
            auto base_isa = type.substr(0, 5);
 | 
					        local_irq = [lcpu](short s, bool b) { return lcpu->local_irq(s, b); };
 | 
				
			||||||
            if(base_isa=="tgc_d" || base_isa=="tgc_e") {
 | 
					        if(backend == "interp")
 | 
				
			||||||
                std::tie(cpu, vm) = f.create(type + "|mu_p_clic_pmp|" + backend, gdb_port, owner);
 | 
					            return {cpu_ptr{lcpu}, vm_ptr{iss::interp::create(static_cast<typename PLAT::core*>(lcpu), gdb_port)}};
 | 
				
			||||||
            } else {
 | 
					#ifdef WITH_LLVM
 | 
				
			||||||
                std::tie(cpu, vm) = f.create(type + "|m_p|" + backend, gdb_port, owner);
 | 
					        if(backend == "llvm")
 | 
				
			||||||
           }
 | 
					            return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}};
 | 
				
			||||||
        }
 | 
					#endif
 | 
				
			||||||
        if(!cpu ){
 | 
					#ifdef WITH_TCC
 | 
				
			||||||
            SCCFATAL() << "Could not create cpu for isa " << type << " and backend " <<backend;
 | 
					        if(backend == "tcc")
 | 
				
			||||||
        }
 | 
					    s        return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}};
 | 
				
			||||||
        if(!vm ){
 | 
					#endif
 | 
				
			||||||
            SCCFATAL() << "Could not create vm for isa " << type << " and backend " <<backend;
 | 
					        return {nullptr, nullptr};
 | 
				
			||||||
        }
 | 
					    }
 | 
				
			||||||
        auto* sc_cpu_if = reinterpret_cast<sc_core_adapter_if*>(cpu.get());
 | 
					 | 
				
			||||||
        sc_cpu_if->set_mhartid(hart_id);
 | 
					 | 
				
			||||||
        get_mode = [sc_cpu_if]() { return sc_cpu_if->get_mode(); };
 | 
					 | 
				
			||||||
        get_state = [sc_cpu_if]() { return sc_cpu_if->get_state(); };
 | 
					 | 
				
			||||||
        get_interrupt_execution = [sc_cpu_if]() { return sc_cpu_if->get_interrupt_execution(); };
 | 
					 | 
				
			||||||
        set_interrupt_execution = [sc_cpu_if](bool b) { return sc_cpu_if->set_interrupt_execution(b); };
 | 
					 | 
				
			||||||
        local_irq = [sc_cpu_if](short s, bool b) { return sc_cpu_if->local_irq(s, b); };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void create_cpu(std::string const& type, std::string const& backend, unsigned gdb_port, uint32_t hart_id){
 | 
				
			||||||
 | 
					        CREATE_CORE(tgc_c)
 | 
				
			||||||
 | 
					#ifdef CORE_TGC_B
 | 
				
			||||||
 | 
					        CREATE_CORE(tgc_b)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef CORE_TGC_D
 | 
				
			||||||
 | 
					        CREATE_CORE(tgc_d)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef CORE_TGC_D_XRB_MAC
 | 
				
			||||||
 | 
					        CREATE_CORE(tgc_d_xrb_mac)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef CORE_TGC_D_XRB_NN
 | 
				
			||||||
 | 
					        CREATE_CORE(tgc_d_xrb_nn)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            LOG(ERR) << "Illegal argument value for core type: " << type << std::endl;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        auto *srv = debugger::server<debugger::gdb_session>::get();
 | 
					        auto *srv = debugger::server<debugger::gdb_session>::get();
 | 
				
			||||||
        if (srv) tgt_adapter = srv->get_target();
 | 
					        if (srv) tgt_adapter = srv->get_target();
 | 
				
			||||||
        if (tgt_adapter)
 | 
					        if (tgt_adapter)
 | 
				
			||||||
@@ -179,7 +313,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    core_complex * const owner;
 | 
					    core_complex * const owner;
 | 
				
			||||||
    vm_ptr vm{nullptr};
 | 
					    vm_ptr vm{nullptr};
 | 
				
			||||||
    sc_cpu_ptr cpu{nullptr};
 | 
					    cpu_ptr cpu{nullptr};
 | 
				
			||||||
    iss::debugger::target_adapter_if *tgt_adapter{nullptr};
 | 
					    iss::debugger::target_adapter_if *tgt_adapter{nullptr};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -500,5 +634,5 @@ bool core_complex::write_mem_dbg(uint64_t addr, unsigned length, const uint8_t *
 | 
				
			|||||||
    gp.set_streaming_width(length);
 | 
					    gp.set_streaming_width(length);
 | 
				
			||||||
    return dbus->transport_dbg(gp) == length;
 | 
					    return dbus->transport_dbg(gp) == length;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
} /* namespace tgfs */
 | 
					} /* namespace SiFive */
 | 
				
			||||||
} /* namespace sysc */
 | 
					} /* namespace sysc */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,88 +0,0 @@
 | 
				
			|||||||
/*******************************************************************************
 | 
					 | 
				
			||||||
 * Copyright (C) 2021 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 _ISS_FACTORY_H_
 | 
					 | 
				
			||||||
#define _ISS_FACTORY_H_
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <iss/iss.h>
 | 
					 | 
				
			||||||
#include "sc_core_adapter_if.h"
 | 
					 | 
				
			||||||
#include <memory>
 | 
					 | 
				
			||||||
#include <unordered_map>
 | 
					 | 
				
			||||||
#include <functional>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <algorithm>
 | 
					 | 
				
			||||||
#include <vector>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace sysc {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using sc_cpu_ptr = std::unique_ptr<sc_core_adapter_if>;
 | 
					 | 
				
			||||||
using vm_ptr= std::unique_ptr<iss::vm_if>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class iss_factory {
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
    using base_t = std::tuple<sc_cpu_ptr, vm_ptr>;
 | 
					 | 
				
			||||||
    using create_fn = std::function<base_t(unsigned, void*) >;
 | 
					 | 
				
			||||||
    using registry_t = std::unordered_map<std::string, create_fn> ;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    iss_factory() = default;
 | 
					 | 
				
			||||||
    iss_factory(const iss_factory &) = delete;
 | 
					 | 
				
			||||||
    iss_factory & operator=(const iss_factory &) = delete;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static iss_factory & instance() { static iss_factory bf; return bf; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool register_creator(const std::string & className, create_fn const& fn) {
 | 
					 | 
				
			||||||
        registry[className] = fn;
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    base_t create(std::string const& className, unsigned gdb_port=0, void* init_data=nullptr) const {
 | 
					 | 
				
			||||||
        registry_t::const_iterator regEntry = registry.find(className);
 | 
					 | 
				
			||||||
        if (regEntry != registry.end())
 | 
					 | 
				
			||||||
            return regEntry->second(gdb_port, init_data);
 | 
					 | 
				
			||||||
        return {nullptr, nullptr};
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::vector<std::string> get_names() {
 | 
					 | 
				
			||||||
        std::vector<std::string> keys{registry.size()};
 | 
					 | 
				
			||||||
        std::transform(std::begin(registry), std::end(registry), std::begin(keys), [](std::pair<std::string, create_fn> const& p){
 | 
					 | 
				
			||||||
            return p.first;
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        return keys;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
    registry_t registry;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif /* _ISS_FACTORY_H_ */
 | 
					 | 
				
			||||||
@@ -1,36 +1,14 @@
 | 
				
			|||||||
/*******************************************************************************
 | 
					/*
 | 
				
			||||||
 * Copyright (C) 2023 MINRES Technologies GmbH
 | 
					 * register_tgc_c.cpp
 | 
				
			||||||
 * All rights reserved.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Redistribution and use in source and binary forms, with or without
 | 
					 *  Created on: Jul 5, 2023
 | 
				
			||||||
 * modification, are permitted provided that the following conditions are met:
 | 
					 *      Author: eyck
 | 
				
			||||||
 *
 | 
					 */
 | 
				
			||||||
 * 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_factory.h"
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <iss/factory.h>
 | 
				
			||||||
#include <iss/arch/tgc_c.h>
 | 
					#include <iss/arch/tgc_c.h>
 | 
				
			||||||
#include <iss/arch/riscv_hart_m_p.h>
 | 
					#include <iss/arch/riscv_hart_m_p.h>
 | 
				
			||||||
#include <iss/arch/riscv_hart_mu_p.h>
 | 
					#include <iss/arch/riscv_hart_mu_p.h>
 | 
				
			||||||
@@ -38,35 +16,18 @@
 | 
				
			|||||||
#include "core_complex.h"
 | 
					#include "core_complex.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace iss {
 | 
					namespace iss {
 | 
				
			||||||
namespace interp {
 | 
					namespace {
 | 
				
			||||||
using namespace sysc;
 | 
					volatile std::array<bool, 2> dummy = {
 | 
				
			||||||
volatile std::array<bool, 2> tgc_init = {
 | 
					        core_factory::instance().register_creator("tgc_c|m_p|interp", [](unsigned gdb_port, void* data) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
				
			||||||
        iss_factory::instance().register_creator("tgc_c|m_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
 | 
					            auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
 | 
				
			||||||
            auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
 | 
					            arch::tgc_c* lcpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc_c>>(cc);
 | 
				
			||||||
            auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc_c>>(cc);
 | 
					            return {cpu_ptr{lcpu}, vm_ptr{interp::create(lcpu, gdb_port)}};
 | 
				
			||||||
            return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc_c*>(cpu), gdb_port)}};
 | 
					 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
        iss_factory::instance().register_creator("tgc_c|mu_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t {
 | 
					        core_factory::instance().register_creator("tgc_c|mu_p|interp", [](unsigned gdb_port, void* data) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
				
			||||||
            auto* cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
 | 
					            auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
 | 
				
			||||||
            auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc_c>>(cc);
 | 
					            arch::tgc_c* lcpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc_c>>(cc);
 | 
				
			||||||
            return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc_c*>(cpu), gdb_port)}};
 | 
					            return {cpu_ptr{lcpu}, vm_ptr{interp::create(lcpu, gdb_port)}};
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#if defined(WITH_TCC)
 | 
					 | 
				
			||||||
namespace tcc {
 | 
					 | 
				
			||||||
volatile std::array<bool, 2> tgc_init = {
 | 
					 | 
				
			||||||
        core_factory::instance().register_creator("tgc_c|m_p|tcc", [](unsigned gdb_port, void* data) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
					 | 
				
			||||||
            auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
 | 
					 | 
				
			||||||
            auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc_c>>(cc);
 | 
					 | 
				
			||||||
            return {cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc_c*>(cpu), gdb_port)}};
 | 
					 | 
				
			||||||
        }),
 | 
					 | 
				
			||||||
        core_factory::instance().register_creator("tgc_c|mu_p|tcc", [](unsigned gdb_port, void* data) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
					 | 
				
			||||||
            auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
 | 
					 | 
				
			||||||
            auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc_c>>(cc);
 | 
					 | 
				
			||||||
            return {cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc_c*>(cpu), gdb_port)}};
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,14 +11,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <scc/report.h>
 | 
					#include <scc/report.h>
 | 
				
			||||||
#include <util/ities.h>
 | 
					#include <util/ities.h>
 | 
				
			||||||
#include "sc_core_adapter_if.h"
 | 
					#include "core_complex.h"
 | 
				
			||||||
#include <iss/iss.h>
 | 
					#include <iss/iss.h>
 | 
				
			||||||
#include <iss/vm_types.h>
 | 
					#include <iss/vm_types.h>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace sysc {
 | 
					
 | 
				
			||||||
template<typename PLAT>
 | 
					template<typename PLAT>
 | 
				
			||||||
class sc_core_adapter : public PLAT, public sc_core_adapter_if {
 | 
					class sc_core_adapter : public PLAT {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    using reg_t       = typename iss::arch::traits<typename PLAT::core>::reg_t;
 | 
					    using reg_t       = typename iss::arch::traits<typename PLAT::core>::reg_t;
 | 
				
			||||||
    using phys_addr_t = typename iss::arch::traits<typename PLAT::core>::phys_addr_t;
 | 
					    using phys_addr_t = typename iss::arch::traits<typename PLAT::core>::phys_addr_t;
 | 
				
			||||||
@@ -26,17 +26,13 @@ public:
 | 
				
			|||||||
    sc_core_adapter(sysc::tgfs::core_complex *owner)
 | 
					    sc_core_adapter(sysc::tgfs::core_complex *owner)
 | 
				
			||||||
    : owner(owner) { }
 | 
					    : owner(owner) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    iss::arch_if* get_arch_if() override { return this;}
 | 
					    uint32_t get_mode() { return this->reg.PRIV; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void set_mhartid(unsigned id) override { PLAT::set_mhartid(id); }
 | 
					    inline void set_interrupt_execution(bool v) { this->interrupt_sim = v?1:0; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint32_t get_mode() override { return this->reg.PRIV; }
 | 
					    inline bool get_interrupt_execution() { return this->interrupt_sim; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void set_interrupt_execution(bool v) override { this->interrupt_sim = v?1:0; }
 | 
					    heart_state_t &get_state() { return this->state; }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool get_interrupt_execution() override { return this->interrupt_sim; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint64_t get_state() override { return this->state.mstatus.backing.val; }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void notify_phase(iss::arch_if::exec_phase p) override {
 | 
					    void notify_phase(iss::arch_if::exec_phase p) override {
 | 
				
			||||||
        if (p == iss::arch_if::ISTART)
 | 
					        if (p == iss::arch_if::ISTART)
 | 
				
			||||||
@@ -117,7 +113,7 @@ public:
 | 
				
			|||||||
        PLAT::wait_until(flags);
 | 
					        PLAT::wait_until(flags);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void local_irq(short id, bool value) override {
 | 
					    void local_irq(short id, bool value) {
 | 
				
			||||||
        reg_t mask = 0;
 | 
					        reg_t mask = 0;
 | 
				
			||||||
        switch (id) {
 | 
					        switch (id) {
 | 
				
			||||||
        case 3: // SW
 | 
					        case 3: // SW
 | 
				
			||||||
@@ -147,5 +143,6 @@ private:
 | 
				
			|||||||
    sysc::tgfs::core_complex *const owner;
 | 
					    sysc::tgfs::core_complex *const owner;
 | 
				
			||||||
    sc_core::sc_event wfi_evt;
 | 
					    sc_core::sc_event wfi_evt;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _SYSC_SC_CORE_ADAPTER_H_ */
 | 
					#endif /* _SYSC_SC_CORE_ADAPTER_H_ */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,31 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * sc_core_adapter.h
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  Created on: Jul 5, 2023
 | 
					 | 
				
			||||||
 *      Author: eyck
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef _SYSC_SC_CORE_ADAPTER_IF_H_
 | 
					 | 
				
			||||||
#define _SYSC_SC_CORE_ADAPTER_IF_H_
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <scc/report.h>
 | 
					 | 
				
			||||||
#include <util/ities.h>
 | 
					 | 
				
			||||||
#include "core_complex.h"
 | 
					 | 
				
			||||||
#include <iss/iss.h>
 | 
					 | 
				
			||||||
#include <iss/vm_types.h>
 | 
					 | 
				
			||||||
#include <iostream>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace sysc {
 | 
					 | 
				
			||||||
struct sc_core_adapter_if {
 | 
					 | 
				
			||||||
    virtual iss::arch_if* get_arch_if() = 0;
 | 
					 | 
				
			||||||
    virtual void set_mhartid(unsigned) = 0;
 | 
					 | 
				
			||||||
    virtual uint32_t get_mode() = 0;
 | 
					 | 
				
			||||||
    virtual uint64_t get_state() = 0;
 | 
					 | 
				
			||||||
    virtual bool get_interrupt_execution() = 0;
 | 
					 | 
				
			||||||
    virtual void set_interrupt_execution(bool v) = 0;
 | 
					 | 
				
			||||||
    virtual void local_irq(short id, bool value) = 0;
 | 
					 | 
				
			||||||
    virtual ~sc_core_adapter_if() = default;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif /* _SYSC_SC_CORE_ADAPTER_IF_H_ */
 | 
					 | 
				
			||||||
@@ -152,22 +152,14 @@ private:
 | 
				
			|||||||
    /****************************************************************************
 | 
					    /****************************************************************************
 | 
				
			||||||
     * start opcode definitions
 | 
					     * start opcode definitions
 | 
				
			||||||
     ****************************************************************************/
 | 
					     ****************************************************************************/
 | 
				
			||||||
    struct instruction_descriptor {
 | 
					    struct InstructionDesriptor {
 | 
				
			||||||
        size_t length;
 | 
					        size_t length;
 | 
				
			||||||
        uint32_t value;
 | 
					        uint32_t value;
 | 
				
			||||||
        uint32_t mask;
 | 
					        uint32_t mask;
 | 
				
			||||||
        typename arch::traits<ARCH>::opcode_e op;
 | 
					        typename arch::traits<ARCH>::opcode_e op;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    struct decoding_tree_node{
 | 
					 | 
				
			||||||
        std::vector<instruction_descriptor> instrs;
 | 
					 | 
				
			||||||
        std::vector<decoding_tree_node*> children;
 | 
					 | 
				
			||||||
        uint32_t submask = std::numeric_limits<uint32_t>::max();
 | 
					 | 
				
			||||||
        uint32_t value;
 | 
					 | 
				
			||||||
        decoding_tree_node(uint32_t value) : value(value){}
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    decoding_tree_node* root {nullptr};
 | 
					    const std::array<InstructionDesriptor, 87> instr_descr = {{
 | 
				
			||||||
    const std::array<instruction_descriptor, 87> instr_descr = {{
 | 
					 | 
				
			||||||
         /* entries are: size, valid value, valid mask, function ptr */
 | 
					         /* entries are: size, valid value, valid mask, function ptr */
 | 
				
			||||||
        {32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, arch::traits<ARCH>::opcode_e::LUI},
 | 
					        {32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, arch::traits<ARCH>::opcode_e::LUI},
 | 
				
			||||||
        {32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, arch::traits<ARCH>::opcode_e::AUIPC},
 | 
					        {32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, arch::traits<ARCH>::opcode_e::AUIPC},
 | 
				
			||||||
@@ -258,61 +250,18 @@ private:
 | 
				
			|||||||
        {16, 0b0000000000000000, 0b1111111111111111, arch::traits<ARCH>::opcode_e::DII},
 | 
					        {16, 0b0000000000000000, 0b1111111111111111, arch::traits<ARCH>::opcode_e::DII},
 | 
				
			||||||
    }};
 | 
					    }};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //static constexpr typename traits::addr_t upper_bits = ~traits::PGMASK;
 | 
				
			||||||
    iss::status fetch_ins(virt_addr_t pc, uint8_t * data){
 | 
					    iss::status fetch_ins(virt_addr_t pc, uint8_t * data){
 | 
				
			||||||
        auto phys_pc = this->core.v2p(pc);
 | 
					        auto phys_pc = this->core.v2p(pc);
 | 
				
			||||||
 | 
					        //if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
 | 
				
			||||||
 | 
					        //    if (this->core.read(phys_pc, 2, data) != iss::Ok) return iss::Err;
 | 
				
			||||||
 | 
					        //    if ((data[0] & 0x3) == 0x3) // this is a 32bit instruction
 | 
				
			||||||
 | 
					        //        if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) return iss::Err;
 | 
				
			||||||
 | 
					        //} else {
 | 
				
			||||||
            if (this->core.read(phys_pc, 4, data) != iss::Ok)  return iss::Err;
 | 
					            if (this->core.read(phys_pc, 4, data) != iss::Ok)  return iss::Err;
 | 
				
			||||||
 | 
					        //}
 | 
				
			||||||
        return iss::Ok;
 | 
					        return iss::Ok;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    void populate_decoding_tree(decoding_tree_node* root){
 | 
					 | 
				
			||||||
        //create submask
 | 
					 | 
				
			||||||
        for(auto instr: root->instrs){
 | 
					 | 
				
			||||||
            root->submask &= instr.mask;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        //put each instr according to submask&encoding into children
 | 
					 | 
				
			||||||
        for(auto instr: root->instrs){
 | 
					 | 
				
			||||||
            bool foundMatch = false;
 | 
					 | 
				
			||||||
            for(auto child: root->children){
 | 
					 | 
				
			||||||
                //use value as identifying trait
 | 
					 | 
				
			||||||
                if(child->value == (instr.value&root->submask)){
 | 
					 | 
				
			||||||
                    child->instrs.push_back(instr);
 | 
					 | 
				
			||||||
                    foundMatch = true;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if(!foundMatch){
 | 
					 | 
				
			||||||
                decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask);
 | 
					 | 
				
			||||||
                child->instrs.push_back(instr);
 | 
					 | 
				
			||||||
                root->children.push_back(child);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        root->instrs.clear();
 | 
					 | 
				
			||||||
        //call populate_decoding_tree for all children
 | 
					 | 
				
			||||||
        if(root->children.size() >1)
 | 
					 | 
				
			||||||
            for(auto child: root->children){
 | 
					 | 
				
			||||||
                populate_decoding_tree(child);      
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        else{
 | 
					 | 
				
			||||||
            //sort instrs by value of the mask, this works bc we want to have the least restrictive one last
 | 
					 | 
				
			||||||
            std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) {
 | 
					 | 
				
			||||||
            return instr1.mask > instr2.mask;
 | 
					 | 
				
			||||||
            }); 
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    typename arch::traits<ARCH>::opcode_e  decode_instr(decoding_tree_node* node, code_word_t word){
 | 
					 | 
				
			||||||
        if(!node->children.size()){
 | 
					 | 
				
			||||||
            if(node->instrs.size() == 1) return node->instrs[0].op;
 | 
					 | 
				
			||||||
            for(auto instr : node->instrs){
 | 
					 | 
				
			||||||
                if((instr.mask&word) == instr.value) return instr.op;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else{
 | 
					 | 
				
			||||||
            for(auto child : node->children){
 | 
					 | 
				
			||||||
                if (child->value == (node->submask&word)){
 | 
					 | 
				
			||||||
                    return decode_instr(child, word);
 | 
					 | 
				
			||||||
                }  
 | 
					 | 
				
			||||||
            }  
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return arch::traits<ARCH>::opcode_e::MAX_OPCODE;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
 | 
					template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
 | 
				
			||||||
@@ -339,11 +288,16 @@ constexpr size_t bit_count(uint32_t u) {
 | 
				
			|||||||
template <typename ARCH>
 | 
					template <typename ARCH>
 | 
				
			||||||
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
 | 
					vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
 | 
				
			||||||
: vm_base<ARCH>(core, core_id, cluster_id) {
 | 
					: vm_base<ARCH>(core, core_id, cluster_id) {
 | 
				
			||||||
    root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
 | 
					    unsigned id=0;
 | 
				
			||||||
    for(auto instr:instr_descr){
 | 
					    for (auto instr : instr_descr) {
 | 
				
			||||||
        root->instrs.push_back(instr);
 | 
					        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);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    populate_decoding_tree(root);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline bool is_count_limit_enabled(finish_cond_e cond){
 | 
					inline bool is_count_limit_enabled(finish_cond_e cond){
 | 
				
			||||||
@@ -354,6 +308,14 @@ inline bool is_jump_to_self_enabled(finish_cond_e cond){
 | 
				
			|||||||
    return (cond & finish_cond_e::JUMP_TO_SELF) == finish_cond_e::JUMP_TO_SELF;
 | 
					    return (cond & finish_cond_e::JUMP_TO_SELF) == finish_cond_e::JUMP_TO_SELF;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename ARCH>
 | 
				
			||||||
 | 
					typename arch::traits<ARCH>::opcode_e vm_impl<ARCH>::decode_inst_id(code_word_t instr){
 | 
				
			||||||
 | 
					    for(auto& e: qlut[instr&0x3]){
 | 
				
			||||||
 | 
					        if(!((instr&e.mask) ^ e.value )) return e.id;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return arch::traits<ARCH>::opcode_e::MAX_OPCODE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename ARCH>
 | 
					template <typename ARCH>
 | 
				
			||||||
typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){
 | 
					typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){
 | 
				
			||||||
    auto pc=start;
 | 
					    auto pc=start;
 | 
				
			||||||
@@ -375,7 +337,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
 | 
				
			|||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            if (is_jump_to_self_enabled(cond) &&
 | 
					            if (is_jump_to_self_enabled(cond) &&
 | 
				
			||||||
                    (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
 | 
					                    (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
 | 
				
			||||||
            auto inst_id = decode_instr(root, instr);
 | 
					            auto inst_id = decode_inst_id(instr);
 | 
				
			||||||
            // pre execution stuff
 | 
					            // pre execution stuff
 | 
				
			||||||
             this->core.reg.last_branch = 0;
 | 
					             this->core.reg.last_branch = 0;
 | 
				
			||||||
            if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id));
 | 
					            if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id));
 | 
				
			||||||
@@ -2673,7 +2635,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
 | 
				
			|||||||
    return pc;
 | 
					    return pc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace tgc_c
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <>
 | 
					template <>
 | 
				
			||||||
std::unique_ptr<vm_if> create<arch::tgc_c>(arch::tgc_c *core, unsigned short port, bool dump) {
 | 
					std::unique_ptr<vm_if> create<arch::tgc_c>(arch::tgc_c *core, unsigned short port, bool dump) {
 | 
				
			||||||
@@ -2689,7 +2651,7 @@ std::unique_ptr<vm_if> create<arch::tgc_c>(arch::tgc_c *core, unsigned short por
 | 
				
			|||||||
#include <iss/arch/riscv_hart_mu_p.h>
 | 
					#include <iss/arch/riscv_hart_mu_p.h>
 | 
				
			||||||
namespace iss {
 | 
					namespace iss {
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
volatile std::array<bool, 2> dummy = {
 | 
					std::array<bool, 2> dummy = {
 | 
				
			||||||
        core_factory::instance().register_creator("tgc_c|m_p|interp", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
					        core_factory::instance().register_creator("tgc_c|m_p|interp", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
				
			||||||
            auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::tgc_c>();
 | 
					            auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::tgc_c>();
 | 
				
			||||||
		    auto vm = new interp::tgc_c::vm_impl<arch::tgc_c>(*cpu, false);
 | 
							    auto vm = new interp::tgc_c::vm_impl<arch::tgc_c>(*cpu, false);
 | 
				
			||||||
@@ -2705,3 +2667,8 @@ volatile std::array<bool, 2> dummy = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
						bool* get_tgc_c_interp_creators() {
 | 
				
			||||||
 | 
							return iss::dummy.data();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -120,7 +120,57 @@ protected:
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					    // 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(static_cast<uint32_t>(EXTR_MASK32)), LUT_SIZE_C = 1 << util::bit_count(static_cast<uint32_t>(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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
 | 
					    template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
 | 
				
			||||||
    inline S sext(U from) {
 | 
					    inline S sext(U from) {
 | 
				
			||||||
        auto mask = (1ULL<<W) - 1;
 | 
					        auto mask = (1ULL<<W) - 1;
 | 
				
			||||||
@@ -132,23 +182,14 @@ private:
 | 
				
			|||||||
    /****************************************************************************
 | 
					    /****************************************************************************
 | 
				
			||||||
     * start opcode definitions
 | 
					     * start opcode definitions
 | 
				
			||||||
     ****************************************************************************/
 | 
					     ****************************************************************************/
 | 
				
			||||||
    struct instruction_descriptor {
 | 
					    struct InstructionDesriptor {
 | 
				
			||||||
        size_t length;
 | 
					        size_t length;
 | 
				
			||||||
        uint32_t value;
 | 
					        uint32_t value;
 | 
				
			||||||
        uint32_t mask;
 | 
					        uint32_t mask;
 | 
				
			||||||
        compile_func op;
 | 
					        compile_func op;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    struct decoding_tree_node{
 | 
					 | 
				
			||||||
        std::vector<instruction_descriptor> instrs;
 | 
					 | 
				
			||||||
        std::vector<decoding_tree_node*> children;
 | 
					 | 
				
			||||||
        uint32_t submask = std::numeric_limits<uint32_t>::max();
 | 
					 | 
				
			||||||
        uint32_t value;
 | 
					 | 
				
			||||||
        decoding_tree_node(uint32_t value) : value(value){}
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    decoding_tree_node* root {nullptr};
 | 
					    const std::array<InstructionDesriptor, 87> instr_descr = {{
 | 
				
			||||||
 | 
					 | 
				
			||||||
    const std::array<instruction_descriptor, 87> instr_descr = {{
 | 
					 | 
				
			||||||
         /* entries are: size, valid value, valid mask, function ptr */
 | 
					         /* entries are: size, valid value, valid mask, function ptr */
 | 
				
			||||||
        /* instruction LUI, encoding '0b00000000000000000000000000110111' */
 | 
					        /* instruction LUI, encoding '0b00000000000000000000000000110111' */
 | 
				
			||||||
        {32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, &this_class::__lui},
 | 
					        {32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, &this_class::__lui},
 | 
				
			||||||
@@ -452,14 +493,14 @@ private:
 | 
				
			|||||||
            this->gen_raise_trap(tu, 0,  2);
 | 
					            this->gen_raise_trap(tu, 0,  2);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else{
 | 
					        else{
 | 
				
			||||||
        	auto new_pc = tu.assignment(tu.ext((tu.bitwise_and((tu.add(tu.load(rs1+ traits::X0, 0),tu.constant((int16_t)sext<12>(imm),16))),tu.constant(~0x1,8))),32,true),32);
 | 
					        	auto new_pc = tu.assignment(tu.ext((tu.bitwise_and((tu.add(tu.load(rs1+ traits::X0, 0),tu.constant((int16_t)sext<12>(imm),16))),tu.constant(~ 0x1,8))),32,true),32);
 | 
				
			||||||
        	tu.open_if(tu.srem(new_pc,tu.constant(static_cast<uint32_t>(traits:: INSTR_ALIGNMENT),32)));
 | 
					        	tu.open_if(tu.srem(new_pc,tu.constant(static_cast<uint32_t>(traits:: INSTR_ALIGNMENT),32)));
 | 
				
			||||||
        	this->gen_raise_trap(tu, 0,  0);
 | 
					        	this->gen_raise_trap(tu, 0,  0);
 | 
				
			||||||
        	tu.open_else();
 | 
					        	tu.open_else();
 | 
				
			||||||
        	if(rd!= 0) {
 | 
					        	if(rd!= 0) {
 | 
				
			||||||
        	    tu.store(rd + traits::X0,tu.ext((tu.add(tu.ext(cur_pc_val,32,false),tu.constant( 4,8))),32,true));
 | 
					        	    tu.store(rd + traits::X0,tu.ext((tu.add(tu.ext(cur_pc_val,32,false),tu.constant( 4,8))),32,true));
 | 
				
			||||||
        	}
 | 
					        	}
 | 
				
			||||||
        	auto PC_val_v = tu.assignment("PC_val", tu.bitwise_and(new_pc,tu.constant(~0x1,8)),32);
 | 
					        	auto PC_val_v = tu.assignment("PC_val", tu.bitwise_and(new_pc,tu.constant(~ 0x1,8)),32);
 | 
				
			||||||
        	tu.store(traits::NEXT_PC, PC_val_v);
 | 
					        	tu.store(traits::NEXT_PC, PC_val_v);
 | 
				
			||||||
        	tu.store(traits::LAST_BRANCH, tu.constant(2U, 2));
 | 
					        	tu.store(traits::LAST_BRANCH, tu.constant(2U, 2));
 | 
				
			||||||
        	tu.close_scope();
 | 
					        	tu.close_scope();
 | 
				
			||||||
@@ -1921,7 +1962,7 @@ private:
 | 
				
			|||||||
        else{
 | 
					        else{
 | 
				
			||||||
        	auto xrd = tu.assignment(tu.read_mem(traits::CSR, csr, 32),32);
 | 
					        	auto xrd = tu.assignment(tu.read_mem(traits::CSR, csr, 32),32);
 | 
				
			||||||
        	if(zimm!= 0) {
 | 
					        	if(zimm!= 0) {
 | 
				
			||||||
        	    tu.write_mem(traits::CSR, csr, tu.bitwise_and(xrd,tu.constant(~((uint32_t)zimm),32)));
 | 
					        	    tu.write_mem(traits::CSR, csr, tu.bitwise_and(xrd,tu.constant(~ ((uint32_t)zimm),32)));
 | 
				
			||||||
        	}
 | 
					        	}
 | 
				
			||||||
        	if(rd!= 0) {
 | 
					        	if(rd!= 0) {
 | 
				
			||||||
        	    tu.store(rd + traits::X0,xrd);
 | 
					        	    tu.store(rd + traits::X0,xrd);
 | 
				
			||||||
@@ -2122,13 +2163,13 @@ private:
 | 
				
			|||||||
        	auto divisor = tu.assignment(tu.ext(tu.load(rs2+ traits::X0, 0),32,false),32);
 | 
					        	auto divisor = tu.assignment(tu.ext(tu.load(rs2+ traits::X0, 0),32,false),32);
 | 
				
			||||||
        	if(rd!= 0){ tu.open_if(tu.icmp(ICmpInst::ICMP_NE,divisor,tu.constant( 0,8)));
 | 
					        	if(rd!= 0){ tu.open_if(tu.icmp(ICmpInst::ICMP_NE,divisor,tu.constant( 0,8)));
 | 
				
			||||||
        	auto MMIN = tu.assignment(tu.constant(((uint32_t)1)<<(static_cast<uint32_t>(traits:: XLEN)-1),32),32);
 | 
					        	auto MMIN = tu.assignment(tu.constant(((uint32_t)1)<<(static_cast<uint32_t>(traits:: XLEN)-1),32),32);
 | 
				
			||||||
        	tu.open_if(tu.logical_and(tu.icmp(ICmpInst::ICMP_EQ,tu.load(rs1+ traits::X0, 0),MMIN),tu.icmp(ICmpInst::ICMP_EQ,divisor,tu.constant(-1,8))));
 | 
					        	tu.open_if(tu.logical_and(tu.icmp(ICmpInst::ICMP_EQ,tu.load(rs1+ traits::X0, 0),MMIN),tu.icmp(ICmpInst::ICMP_EQ,divisor,tu.constant(- 1,8))));
 | 
				
			||||||
        	tu.store(rd + traits::X0,MMIN);
 | 
					        	tu.store(rd + traits::X0,MMIN);
 | 
				
			||||||
        	tu.open_else();
 | 
					        	tu.open_else();
 | 
				
			||||||
        	tu.store(rd + traits::X0,tu.ext((tu.sdiv(dividend,divisor)),32,true));
 | 
					        	tu.store(rd + traits::X0,tu.ext((tu.sdiv(dividend,divisor)),32,true));
 | 
				
			||||||
        	tu.close_scope();
 | 
					        	tu.close_scope();
 | 
				
			||||||
        	tu.open_else();
 | 
					        	tu.open_else();
 | 
				
			||||||
        	tu.store(rd + traits::X0,tu.constant((uint32_t)-1,32));
 | 
					        	tu.store(rd + traits::X0,tu.constant((uint32_t)- 1,32));
 | 
				
			||||||
        	tu.close_scope();
 | 
					        	tu.close_scope();
 | 
				
			||||||
        	}
 | 
					        	}
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -2167,7 +2208,7 @@ private:
 | 
				
			|||||||
        	}
 | 
					        	}
 | 
				
			||||||
        	tu.open_else();
 | 
					        	tu.open_else();
 | 
				
			||||||
        	if(rd!=0) {
 | 
					        	if(rd!=0) {
 | 
				
			||||||
        	    tu.store(rd + traits::X0,tu.constant((uint32_t)-1,32));
 | 
					        	    tu.store(rd + traits::X0,tu.constant((uint32_t)- 1,32));
 | 
				
			||||||
        	}
 | 
					        	}
 | 
				
			||||||
        	tu.close_scope();
 | 
					        	tu.close_scope();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -2202,7 +2243,7 @@ private:
 | 
				
			|||||||
        else{
 | 
					        else{
 | 
				
			||||||
        	tu.open_if(tu.icmp(ICmpInst::ICMP_NE,tu.load(rs2+ traits::X0, 0),tu.constant( 0,8)));
 | 
					        	tu.open_if(tu.icmp(ICmpInst::ICMP_NE,tu.load(rs2+ traits::X0, 0),tu.constant( 0,8)));
 | 
				
			||||||
        	auto MMIN = tu.assignment(tu.constant( 1<<(static_cast<uint32_t>(traits:: XLEN)-1),8),32);
 | 
					        	auto MMIN = tu.assignment(tu.constant( 1<<(static_cast<uint32_t>(traits:: XLEN)-1),8),32);
 | 
				
			||||||
        	tu.open_if(tu.logical_and(tu.icmp(ICmpInst::ICMP_EQ,tu.load(rs1+ traits::X0, 0),MMIN),tu.icmp(ICmpInst::ICMP_EQ,tu.ext(tu.load(rs2+ traits::X0, 0),32,false),tu.constant(-1,8))));
 | 
					        	tu.open_if(tu.logical_and(tu.icmp(ICmpInst::ICMP_EQ,tu.load(rs1+ traits::X0, 0),MMIN),tu.icmp(ICmpInst::ICMP_EQ,tu.ext(tu.load(rs2+ traits::X0, 0),32,false),tu.constant(- 1,8))));
 | 
				
			||||||
        	if(rd!=0) {
 | 
					        	if(rd!=0) {
 | 
				
			||||||
        	    tu.store(rd + traits::X0,tu.constant( 0,8));
 | 
					        	    tu.store(rd + traits::X0,tu.constant( 0,8));
 | 
				
			||||||
        	}
 | 
					        	}
 | 
				
			||||||
@@ -2914,7 +2955,7 @@ private:
 | 
				
			|||||||
        gen_set_pc(tu, pc, traits::NEXT_PC);
 | 
					        gen_set_pc(tu, pc, traits::NEXT_PC);
 | 
				
			||||||
        tu.open_scope();
 | 
					        tu.open_scope();
 | 
				
			||||||
        if(rs1&&rs1<static_cast<uint32_t>(traits:: RFS)) {
 | 
					        if(rs1&&rs1<static_cast<uint32_t>(traits:: RFS)) {
 | 
				
			||||||
            auto PC_val_v = tu.assignment("PC_val", tu.bitwise_and(tu.load(rs1%static_cast<uint32_t>(traits:: RFS)+ traits::X0, 0),tu.constant(~0x1,8)),32);
 | 
					            auto PC_val_v = tu.assignment("PC_val", tu.bitwise_and(tu.load(rs1%static_cast<uint32_t>(traits:: RFS)+ traits::X0, 0),tu.constant(~ 0x1,8)),32);
 | 
				
			||||||
            tu.store(traits::NEXT_PC, PC_val_v);
 | 
					            tu.store(traits::NEXT_PC, PC_val_v);
 | 
				
			||||||
            tu.store(traits::LAST_BRANCH, tu.constant(2U, 2));
 | 
					            tu.store(traits::LAST_BRANCH, tu.constant(2U, 2));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -3002,7 +3043,7 @@ private:
 | 
				
			|||||||
        else{
 | 
					        else{
 | 
				
			||||||
        	auto new_pc = tu.assignment(tu.load(rs1+ traits::X0, 0),32);
 | 
					        	auto new_pc = tu.assignment(tu.load(rs1+ traits::X0, 0),32);
 | 
				
			||||||
        	tu.store(1 + traits::X0,tu.ext((tu.add(tu.ext(cur_pc_val,32,false),tu.constant( 2,8))),32,true));
 | 
					        	tu.store(1 + traits::X0,tu.ext((tu.add(tu.ext(cur_pc_val,32,false),tu.constant( 2,8))),32,true));
 | 
				
			||||||
        	auto PC_val_v = tu.assignment("PC_val", tu.bitwise_and(new_pc,tu.constant(~0x1,8)),32);
 | 
					        	auto PC_val_v = tu.assignment("PC_val", tu.bitwise_and(new_pc,tu.constant(~ 0x1,8)),32);
 | 
				
			||||||
        	tu.store(traits::NEXT_PC, PC_val_v);
 | 
					        	tu.store(traits::NEXT_PC, PC_val_v);
 | 
				
			||||||
        	tu.store(traits::LAST_BRANCH, tu.constant(2U, 2));
 | 
					        	tu.store(traits::LAST_BRANCH, tu.constant(2U, 2));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -3095,64 +3136,11 @@ private:
 | 
				
			|||||||
        vm_impl::gen_trap_check(tu);
 | 
					        vm_impl::gen_trap_check(tu);
 | 
				
			||||||
        return BRANCH;
 | 
					        return BRANCH;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    //decoding functionality
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void populate_decoding_tree(decoding_tree_node* root){
 | 
					 | 
				
			||||||
        //create submask
 | 
					 | 
				
			||||||
        for(auto instr: root->instrs){
 | 
					 | 
				
			||||||
            root->submask &= instr.mask;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        //put each instr according to submask&encoding into children
 | 
					 | 
				
			||||||
        for(auto instr: root->instrs){
 | 
					 | 
				
			||||||
            bool foundMatch = false;
 | 
					 | 
				
			||||||
            for(auto child: root->children){
 | 
					 | 
				
			||||||
                //use value as identifying trait
 | 
					 | 
				
			||||||
                if(child->value == (instr.value&root->submask)){
 | 
					 | 
				
			||||||
                    child->instrs.push_back(instr);
 | 
					 | 
				
			||||||
                    foundMatch = true;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if(!foundMatch){
 | 
					 | 
				
			||||||
                decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask);
 | 
					 | 
				
			||||||
                child->instrs.push_back(instr);
 | 
					 | 
				
			||||||
                root->children.push_back(child);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        root->instrs.clear();
 | 
					 | 
				
			||||||
        //call populate_decoding_tree for all children
 | 
					 | 
				
			||||||
        if(root->children.size() >1)
 | 
					 | 
				
			||||||
            for(auto child: root->children){
 | 
					 | 
				
			||||||
                populate_decoding_tree(child);      
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        else{
 | 
					 | 
				
			||||||
            //sort instrs by value of the mask, this works bc we want to have the least restrictive one last
 | 
					 | 
				
			||||||
            std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) {
 | 
					 | 
				
			||||||
            return instr1.mask > instr2.mask;
 | 
					 | 
				
			||||||
            }); 
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    compile_func decode_instr(decoding_tree_node* node, code_word_t word){
 | 
					 | 
				
			||||||
        if(!node->children.size()){
 | 
					 | 
				
			||||||
            if(node->instrs.size() == 1) return node->instrs[0].op;
 | 
					 | 
				
			||||||
            for(auto instr : node->instrs){
 | 
					 | 
				
			||||||
                if((instr.mask&word) == instr.value) return instr.op;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else{
 | 
					 | 
				
			||||||
            for(auto child : node->children){
 | 
					 | 
				
			||||||
                if (child->value == (node->submask&word)){
 | 
					 | 
				
			||||||
                    return decode_instr(child, word);
 | 
					 | 
				
			||||||
                }  
 | 
					 | 
				
			||||||
            }  
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return nullptr;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename CODE_WORD> void debug_fn(CODE_WORD instr) {
 | 
					template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
 | 
				
			||||||
    volatile CODE_WORD x = instr;
 | 
					    volatile CODE_WORD x = insn;
 | 
				
			||||||
    instr = 2 * x;
 | 
					    insn = 2 * x;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
 | 
					template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
 | 
				
			||||||
@@ -3160,11 +3148,14 @@ template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
 | 
				
			|||||||
template <typename ARCH>
 | 
					template <typename ARCH>
 | 
				
			||||||
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
 | 
					vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
 | 
				
			||||||
: vm_base<ARCH>(core, core_id, cluster_id) {
 | 
					: vm_base<ARCH>(core, core_id, cluster_id) {
 | 
				
			||||||
    root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
 | 
					    qlut[0] = lut_00.data();
 | 
				
			||||||
    for(auto instr:instr_descr){
 | 
					    qlut[1] = lut_01.data();
 | 
				
			||||||
        root->instrs.push_back(instr);
 | 
					    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);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    populate_decoding_tree(root);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename ARCH>
 | 
					template <typename ARCH>
 | 
				
			||||||
@@ -3172,19 +3163,30 @@ std::tuple<continuation_e>
 | 
				
			|||||||
vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, tu_builder& tu) {
 | 
					vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, tu_builder& tu) {
 | 
				
			||||||
    // we fetch at max 4 byte, alignment is 2
 | 
					    // we fetch at max 4 byte, alignment is 2
 | 
				
			||||||
    enum {TRAP_ID=1<<16};
 | 
					    enum {TRAP_ID=1<<16};
 | 
				
			||||||
    code_word_t instr = 0;
 | 
					    code_word_t insn = 0;
 | 
				
			||||||
 | 
					    // const typename traits::addr_t upper_bits = ~traits::PGMASK;
 | 
				
			||||||
    phys_addr_t paddr(pc);
 | 
					    phys_addr_t paddr(pc);
 | 
				
			||||||
 | 
					    auto *const data = (uint8_t *)&insn;
 | 
				
			||||||
    paddr = this->core.v2p(pc);
 | 
					    paddr = this->core.v2p(pc);
 | 
				
			||||||
    auto res = this->core.read(paddr, 4, reinterpret_cast<uint8_t*>(&instr));
 | 
					//    if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
 | 
				
			||||||
    if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
 | 
					//        auto res = this->core.read(paddr, 2, data);
 | 
				
			||||||
    if (instr == 0x0000006f || (instr&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
 | 
					//        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
 | 
					    // curr pc on stack
 | 
				
			||||||
    ++inst_cnt;
 | 
					    ++inst_cnt;
 | 
				
			||||||
    auto f = decode_instr(root, instr);
 | 
					    auto lut_val = extract_fields(insn);
 | 
				
			||||||
 | 
					    auto f = qlut[insn & 0x3][lut_val];
 | 
				
			||||||
    if (f == nullptr) {
 | 
					    if (f == nullptr) {
 | 
				
			||||||
        f = &this_class::illegal_intruction;
 | 
					        f = &this_class::illegal_intruction;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return (this->*f)(pc, instr, tu);
 | 
					    return (this->*f)(pc, insn, tu);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) {
 | 
					template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) {
 | 
				
			||||||
@@ -3208,7 +3210,7 @@ template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(tu_builder& tu) {
 | 
				
			|||||||
    tu("return *next_pc;");
 | 
					    tu("return *next_pc;");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace tgc_c
 | 
					} // namespace mnrv32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <>
 | 
					template <>
 | 
				
			||||||
std::unique_ptr<vm_if> create<arch::tgc_c>(arch::tgc_c *core, unsigned short port, bool dump) {
 | 
					std::unique_ptr<vm_if> create<arch::tgc_c>(arch::tgc_c *core, unsigned short port, bool dump) {
 | 
				
			||||||
@@ -3216,7 +3218,7 @@ std::unique_ptr<vm_if> create<arch::tgc_c>(arch::tgc_c *core, unsigned short por
 | 
				
			|||||||
    if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
 | 
					    if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
 | 
				
			||||||
    return std::unique_ptr<vm_if>(ret);
 | 
					    return std::unique_ptr<vm_if>(ret);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
} // namespace tcc
 | 
					} // namesapce tcc
 | 
				
			||||||
} // namespace iss
 | 
					} // namespace iss
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <iss/factory.h>
 | 
					#include <iss/factory.h>
 | 
				
			||||||
@@ -3224,19 +3226,24 @@ std::unique_ptr<vm_if> create<arch::tgc_c>(arch::tgc_c *core, unsigned short por
 | 
				
			|||||||
#include <iss/arch/riscv_hart_mu_p.h>
 | 
					#include <iss/arch/riscv_hart_mu_p.h>
 | 
				
			||||||
namespace iss {
 | 
					namespace iss {
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
volatile std::array<bool, 2> dummy = {
 | 
					std::array<bool, 2> dummy = {
 | 
				
			||||||
        core_factory::instance().register_creator("tgc_c|m_p|tcc", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
					        core_factory::instance().register_creator("tgc_c|m_p|tcc", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
				
			||||||
            auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::tgc_c>();
 | 
					            auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::tgc_c>();
 | 
				
			||||||
            auto* vm = new tcc::tgc_c::vm_impl<arch::tgc_c>(*cpu, false);
 | 
							    auto vm = new tcc::tgc_c::vm_impl<arch::tgc_c>(*cpu, false);
 | 
				
			||||||
		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
 | 
							    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
 | 
				
			||||||
            return {cpu_ptr{cpu}, vm_ptr{vm}};
 | 
					            return {cpu_ptr{cpu}, vm_ptr{vm}};
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
        core_factory::instance().register_creator("tgc_c|mu_p|tcc", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
					        core_factory::instance().register_creator("tgc_c|mu_p|tcc", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
 | 
				
			||||||
            auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::tgc_c>();
 | 
					            auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::tgc_c>();
 | 
				
			||||||
            auto* vm = new tcc::tgc_c::vm_impl<arch::tgc_c>(*cpu, false);
 | 
							    auto vm = new tcc::tgc_c::vm_impl<arch::tgc_c>(*cpu, false);
 | 
				
			||||||
		    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
 | 
							    if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
 | 
				
			||||||
            return {cpu_ptr{cpu}, vm_ptr{vm}};
 | 
					            return {cpu_ptr{cpu}, vm_ptr{vm}};
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
						bool* get_tgc_c_tcc_creators() {
 | 
				
			||||||
 | 
							return iss::dummy.data();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user