Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/workflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,17 @@ jobs:
name: riscv-sim-${{ matrix.compiler_name }}-${{ matrix.build_type }}
path: build

- name: make sim executable
run: |
chmod +x build/riscv-sim.x

- name: clone risc-v tests
if: matrix.compiler.name == 'clang'
if: matrix.compiler_name == 'clang'
run: |
git clone --depth 1 https://gitlab.com/iDang3r/riscv-interpreter-task.git

- name: run risc-v tests
if: matrix.compiler.name == 'clang'
if: matrix.compiler_name == 'clang'
working-directory: riscv-interpreter-task
run: |
make test INTERPRETER="${{ github.workspace }}/build/riscv-sim.x"
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ build
*.log
compile_commands.json
.cache
perf.data
perf.data.old
__pycache__

# tests:
*.o
Expand Down
2 changes: 1 addition & 1 deletion flags/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,5 @@ target_link_options(sim-flags

target_compile_definitions(sim-flags INTERFACE
$<$<CONFIG:Release>:SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_INFO>
$<$<CONFIG:Debug>:SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_TRACE>
$<$<CONFIG:Debug>:SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_DEBUG>
)
2 changes: 1 addition & 1 deletion src/helpers/include/helpers/trace_calls.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace hlp {
inline void trace_call([[maybe_unused]] std::source_location loc = std::source_location::current()) {
#if !defined(NDEBUG)
// spdlog::debug("Function call: {}, {}:{}", loc.function_name(), loc.file_name(), loc.line());
spdlog::debug("Function call: {}", loc.function_name());
spdlog::trace("Function call: {}", loc.function_name());
#endif // NDEBUG
}

Expand Down
1 change: 0 additions & 1 deletion src/isa/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,5 @@ target_link_libraries(isa
sim-flags
sim
helpers

softfloat
)
2 changes: 1 addition & 1 deletion src/isa/include/isa/ext_f.inc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// name mask match
// name mask match
MNEMONIC(FLW, 0x0000707f, 0x00002007)
MNEMONIC(FSW, 0x0000707f, 0x00002027)

Expand Down
4 changes: 2 additions & 2 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ int main(int argc, const char* argv[]) {
#if defined (NDEBUG)
spdlog::set_level(spdlog::level::info);
#else // NDEBUG
spdlog::flush_on(spdlog::level::trace);
spdlog::set_level(spdlog::level::trace);
// spdlog::flush_on(spdlog::level::trace);
spdlog::set_level(spdlog::level::debug);
#endif // NDEBUG

// log argv
Expand Down
4 changes: 3 additions & 1 deletion src/sim/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
add_library(sim STATIC)

add_subdirectory(decode)

target_sources(sim
PRIVATE
source/elf_loader.cpp
source/decode.cpp
source/memory.cpp
source/rv_sim.cpp
source/dispatch.cpp
Expand All @@ -19,6 +20,7 @@ target_link_libraries(sim
sim-flags
helpers
isa
decode

spdlog
elfio::elfio
Expand Down
25 changes: 25 additions & 0 deletions src/sim/decode/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
add_library(decode STATIC)

add_subdirectory(pygen)

set_source_files_properties("${DECODE_CPP_OUT}" PROPERTIES GENERATED TRUE)

target_sources(decode PRIVATE "${DECODE_CPP_OUT}")

add_dependencies(decode ${DECODE_CODEGEN_TARGET})

target_include_directories(decode
PUBLIC
include
)

target_link_libraries(decode
PRIVATE
sim-flags
helpers
isa

spdlog
softfloat
)

Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
#include "isa/mnemonics.hpp"
#include "isa/isa_defs.hpp"

namespace sim {
namespace sim::decode {

isa::InsnMnemonic Decode(isa::UndecodedInsn insn);

}
} // namespace sim::decode

#endif // DECODE_HPP_
74 changes: 74 additions & 0 deletions src/sim/decode/pygen/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
find_package(Python3 REQUIRED COMPONENTS Interpreter)

set(DECODE_PYGEN_DIR "${CMAKE_CURRENT_LIST_DIR}")
set(DECODE_DIR "${DECODE_PYGEN_DIR}/..") # decode/
get_filename_component(DECODE_DIR "${DECODE_DIR}" ABSOLUTE) # normilize path

set(GEN_SCRIPT "${DECODE_PYGEN_DIR}/gen_decoder.py")
set(GEN_DEPS
"${DECODE_PYGEN_DIR}/gen_decoder.py"
"${DECODE_PYGEN_DIR}/insn_mnem.py"
"${DECODE_PYGEN_DIR}/opcode_dtree.py"
"${DECODE_PYGEN_DIR}/mnem_parse.py"
"${DECODE_PYGEN_DIR}/emit_cpp.py"
)

set(LIN_CPP "${DECODE_DIR}/source/lin_decode.cpp")

set(ISA_EXT_INC "${CMAKE_SOURCE_DIR}/src/isa/include/isa/isa_ext.inc")

set(GEN_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
set(DECODE_CPP_OUT "${GEN_DIR}/decode.cpp")
set(DOT_OUT "${GEN_DIR}/dtree.dot")
set(COMPILE_DOT_SH "compile_dot.sh")

# options
set(DECODE_BACKEND "generated" CACHE STRING "Decode backend: linear|generated")
set_property(CACHE DECODE_BACKEND PROPERTY STRINGS linear generated)

option(DECODE_EMIT_DOT "Emit decode decision tree .dot during generation" OFF)
set(DECODE_GEN_EXTRA_ARGS "" CACHE STRING "Extra args for gen_decoder.py (CMake list separated by ';')")

# Build command depending on backend
if (DECODE_BACKEND STREQUAL "generated")
if (DECODE_EMIT_DOT)
set(DOT_ARGS --dot "${DOT_OUT}")
else()
set(DOT_ARGS)
endif()

add_custom_command(
OUTPUT "${DECODE_CPP_OUT}"
COMMAND "${CMAKE_COMMAND}" -E make_directory "${GEN_DIR}"
COMMAND "${Python3_EXECUTABLE}" "${GEN_SCRIPT}"
--isa "${ISA_EXT_INC}"
--output "${DECODE_CPP_OUT}"
${DOT_ARGS}
${DECODE_GEN_EXTRA_ARGS}
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${DECODE_PYGEN_DIR}/${COMPILE_DOT_SH}" "${GEN_DIR}/${COMPILE_DOT_SH}"
DEPENDS
"${ISA_EXT_INC}"
"${DECODE_PYGEN_DIR}/${COMPILE_DOT_SH}"
${GEN_DEPS}
WORKING_DIRECTORY "${DECODE_PYGEN_DIR}"
COMMENT "Generating decoder.cpp (backend=generated)"
VERBATIM
)
elseif (DECODE_BACKEND STREQUAL "linear")
add_custom_command(
OUTPUT "${DECODE_CPP_OUT}"
COMMAND "${CMAKE_COMMAND}" -E make_directory "${GEN_DIR}"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${LIN_CPP}" "${DECODE_CPP_OUT}"
DEPENDS "${LIN_CPP}"
COMMENT "Preparing decoder.cpp (backend=linear)"
VERBATIM
)
else()
message(FATAL_ERROR "Unknown DECODE_BACKEND='${DECODE_BACKEND}'. Use linear|generated.")
endif()

add_custom_target(decode_codegen DEPENDS "${DECODE_CPP_OUT}")

# Export outputs to decode
set(DECODE_CPP_OUT "${DECODE_CPP_OUT}" PARENT_SCOPE)
set(DECODE_CODEGEN_TARGET decode_codegen PARENT_SCOPE)
3 changes: 3 additions & 0 deletions src/sim/decode/pygen/compile_dot.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#/bin/bash

dot -Tsvg $1 -o $1.svg
42 changes: 42 additions & 0 deletions src/sim/decode/pygen/emit_cpp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from opcode_dtree import DTree, DTreeLeaf, DTreeNode, DTreeTestBit
from pathlib import Path

def _node_gen(node: DTreeNode, depth: int = 0) -> str:
indent = " " * depth

if isinstance(node, DTreeLeaf):
return f"{indent}return isa::InsnMnemonic::{node.insn_name};\n"

cond_if = f"{indent}if (isa::IsBitSet(insn, {node.bit_idx})) {{\n"
cond_else = f"{indent}}} else {{\n"
cond_end = f"{indent}}}\n"

return cond_if + _node_gen(node.one, depth=depth + 1) + cond_else + _node_gen(node.zero, depth=depth + 1) + cond_end

def gen(op_dtree: DTree, namespace: str = "sim::decode") -> str:
prologue = f"""
// THIS CODE IS GENERATED
// by decode/gen_decoder.py
#include "decode/decode.hpp"

#include "isa/isa_hlp.hpp"
#include "isa/mnemonics.hpp"

namespace {namespace} {{

isa::InsnMnemonic Decode(isa::UndecodedInsn insn) {{
"""

epilogue = f"""
}}

}} // namespace {namespace}
"""

decode_body = _node_gen(op_dtree.get_root(), depth=1)

return prologue + decode_body + epilogue

def write_gen(gen_path: Path, opcode_dtree: DTree, namespace: str = "sim::decode"):
gen_code = gen(opcode_dtree, namespace=namespace)
gen_path.write_text(gen_code)
24 changes: 24 additions & 0 deletions src/sim/decode/pygen/gen_decoder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import argparse
from pathlib import Path

import mnem_parse
import opcode_dtree
import emit_cpp

if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--isa", required=True, help="isa_ext.inc file path")
parser.add_argument("--output", required=True, help="output file path")
parser.add_argument("--dot", help="file path to .dot representation of decode tree")
args = parser.parse_args()

isa_path = Path(args.isa).resolve()

mnems = mnem_parse.parse(isa_path)
dtree = opcode_dtree.build_dtree(mnems)
if args.dot:
dot_path = Path(args.dot)
dtree.write_dot(dot_path)

cpp_path = Path(args.output)
emit_cpp.write_gen(cpp_path, dtree)
9 changes: 9 additions & 0 deletions src/sim/decode/pygen/insn_mnem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from dataclasses import dataclass

@dataclass()
class Insn:
name: str
mask: int
match: int


55 changes: 55 additions & 0 deletions src/sim/decode/pygen/mnem_parse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from typing import List
from pathlib import Path
import re

from insn_mnem import Insn

# example of match #include "isa/ext_i.inc"
MNEM_PATH_RGX = re.compile(r'^(?!//)[ \t]*#include\s+"isa/(?P<file_name>[^\"]+)"', re.MULTILINE)

def _mnem_files(isa_path: Path) -> List[Path]:
isa_src = isa_path.read_text()
isa_dir = isa_path.parent

files = []
for file_match in MNEM_PATH_RGX.finditer(isa_src):
files.append(isa_dir / Path(file_match.group("file_name")))

return files

# example of mathc
# MNEMONIC(LUI, 0x0000007f, 0x00000037)
MNEM_RGX = re.compile(r"""
MNEMONIC\(
\s*(?P<name>\w+)\s*,
\s*(?P<mask>0x[0-9a-fA-F]+)\s*,
\s*(?P<match>0x[0-9a-fA-F]+)\s*
\)
""",
re.VERBOSE
)

def _parse_mnem_file(mnem_file: Path) -> List[Insn]:
mnem_src = mnem_file.read_text()
mnems = []

for mnem_match in MNEM_RGX.finditer(mnem_src):
name = mnem_match.group("name")
mask = int(mnem_match.group("mask"), 16)
match = int(mnem_match.group("match"), 16)

insn = Insn(name, mask, match)
mnems.append(insn)

return mnems

def parse(isa_path: Path) -> List[Insn]:
files = _mnem_files(isa_path)

isa_mnems = []

for mnem_file in files:
mnems = _parse_mnem_file(mnem_file)
isa_mnems += mnems

return isa_mnems
Loading