17 Commits

11 changed files with 277 additions and 214 deletions

3
.gitignore vendored
View File

@ -151,3 +151,6 @@ compile_commands.json
CTestTestfile.cmake
*.dump
.vscode/c_cpp_properties.json
semihosting_test/build/semihosting_test
semihosting_test/build/Makefile

View File

@ -1,19 +1,172 @@
cmake_minimum_required(VERSION 3.12)
# Set default RISC-V toolchain if not specified
if(NOT DEFINED RISCV_TOOLCHAIN_PATH)
set(RISCV_TOOLCHAIN_PATH "/opt/shared/cross-toolchains/gcc13/CentOS/riscv64-unknown-elf/bin" CACHE STRING "Path to RISC-V toolchain")
endif()
# Allow override of compiler executables
if(NOT DEFINED RISCV_GCC)
set(RISCV_GCC "/opt/shared/cross-toolchains/gcc13/CentOS/riscv64-unknown-elf/bin/riscv64-unknown-elf-gcc" CACHE STRING "RISC-V GCC compiler")
endif()
if(NOT DEFINED RISCV_GXX)
set(RISCV_GXX "${RISCV_TOOLCHAIN_PATH}/riscv64-unknown-elf-g++" CACHE STRING "RISC-V G++ compiler")
endif()
if(NOT DEFINED RISCV_OBJCOPY)
set(RISCV_OBJCOPY "${RISCV_TOOLCHAIN_PATH}/riscv64-unknown-elf-objcopy" CACHE STRING "RISC-V objcopy")
endif()
if(NOT DEFINED RISCV_OBJDUMP)
set(RISCV_OBJDUMP "${RISCV_TOOLCHAIN_PATH}/riscv64-unknown-elf-objdump" CACHE STRING "RISC-V objdump")
endif()
# Set the compilers
set(CMAKE_C_COMPILER ${RISCV_GCC})
set(CMAKE_CXX_COMPILER ${RISCV_GXX})
project(Firmware)
# Define supported configurations
set(SUPPORTED_BOARDS iss)
set(SUPPORTED_ISAS "rv32i;rv32im;rv32imc;rv64i;rv64im;rv64imc;imc")
set(SUPPORTED_ABIS "ilp32;ilp32f;lp64;lp64f")
# Build target options
option(BUILD_HELLO_WORLD "Build hello-world example" ON)
option(BUILD_DHRYSTONE "Build dhrystone benchmark" OFF)
option(BUILD_COREMARK "Build coremark benchmark" OFF)
option(BUILD_ALL "Build all targets" OFF)
# If BUILD_ALL is ON, enable all targets
if(BUILD_ALL)
set(BUILD_HELLO_WORLD ON)
set(BUILD_DHRYSTONE ON)
set(BUILD_COREMARK ON)
endif()
# Set default values and validate configurations
if(NOT DEFINED BOARD)
set(BOARD iss)
set(BOARD iss CACHE STRING "Target board")
endif()
if(NOT DEFINED ISA)
set(ISA imc)
set(ISA rv32imc CACHE STRING "Target ISA")
endif()
message(STATUS "Building firmware using ${BOARD} board configuration")
add_custom_target(fw-hello-world ALL
COMMAND make -C ${riscvfw_SOURCE_DIR}/hello-world BOARD=${BOARD} ISA=${ISA}
USES_TERMINAL
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
add_custom_target(fw-dhrystone ALL
COMMAND make -C ${riscvfw_SOURCE_DIR}/benchmarks/dhrystone BOARD=${BOARD} ISA=${ISA}
USES_TERMINAL
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
add_custom_target(fw-coremark ALL
COMMAND make -C ${riscvfw_SOURCE_DIR}/benchmarks/coremark BOARD=${BOARD} ISA=${ISA}
USES_TERMINAL
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
if(NOT DEFINED RISCV_ABI)
if(ISA MATCHES "^rv64")
set(RISCV_ABI "lp64" CACHE STRING "RISC-V ABI")
else()
set(RISCV_ABI "ilp32" CACHE STRING "RISC-V ABI")
endif()
endif()
# Validate configurations
if(NOT BOARD IN_LIST SUPPORTED_BOARDS)
message(FATAL_ERROR "Invalid BOARD specified. Supported boards: ${SUPPORTED_BOARDS}")
endif()
if(NOT ISA IN_LIST SUPPORTED_ISAS)
message(FATAL_ERROR "Invalid ISA specified(${ISA}). Supported ISAs: ${SUPPORTED_ISAS}")
endif()
if(NOT RISCV_ABI IN_LIST SUPPORTED_ABIS)
message(FATAL_ERROR "Invalid ABI specified. Supported ABIs: ${SUPPORTED_ABIS}")
endif()
# Set RISC-V architecture based on ISA
if(ISA MATCHES "^rv")
set(RISCV_ARCH ${ISA})
else()
# Default to rv32 for backward compatibility
set(RISCV_ARCH "rv32${ISA}")
endif()
# Set BSP base directory
set(BSP_BASE "${CMAKE_CURRENT_SOURCE_DIR}/bare-metal-bsp")
# Global compile definitions
add_compile_definitions(BOARD_${BOARD})
# RISC-V specific compiler flags
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 -g -march=${RISCV_ARCH}_zicsr_zifencei -mabi=${RISCV_ABI} -mcmodel=medany")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -g -march=${RISCV_ARCH}_zicsr_zifencei -mabi=${RISCV_ABI} -mcmodel=medany")
#set(CMAKE_ASM_COMPILER riscv64-unknown-elf-as)
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -O2 -g -march=${RISCV_ARCH}_zicsr_zifencei -mabi=${RISCV_ABI} -mcmodel=medany")
# Optional: Enable semihosting support
option(SEMIHOSTING "Enable semihosting support" OFF)
if(SEMIHOSTING)
add_compile_definitions(SEMIHOSTING)
endif()
#create interface library for propagating compile options
#add_library(global_compile_options INTERFACE)
# Compile options
#target_compile_options(global_compile_options INTERFACE
# -march=${RISCV_ARCH}_zicsr_zifencei
# -mabi=${RISCV_ABI}
# -mcmodel=medany
# -O2
# -g
# -ffunction-sections
# -fdata-sections
#)
message(STATUS "Building firmware with configuration:")
message(STATUS " Board: ${BOARD}")
message(STATUS " ISA: ${ISA} (Architecture: ${RISCV_ARCH})")
message(STATUS " ABI: ${RISCV_ABI}")
message(STATUS " Semihosting: ${SEMIHOSTING}")
message(STATUS " Toolchain:")
message(STATUS " Path: ${RISCV_TOOLCHAIN_PATH}")
message(STATUS " C Compiler: ${CMAKE_C_COMPILER}")
message(STATUS " C++ Compiler: ${CMAKE_CXX_COMPILER}")
message(STATUS "Targets to build:")
message(STATUS " hello-world: ${BUILD_HELLO_WORLD}")
message(STATUS " dhrystone: ${BUILD_DHRYSTONE}")
message(STATUS " coremark: ${BUILD_COREMARK}")
add_subdirectory(bare-metal-bsp)
# Add subdirectories based on build options
if(BUILD_HELLO_WORLD)
add_subdirectory(hello-world)
endif()
if(BUILD_DHRYSTONE)
add_subdirectory(benchmarks/dhrystone)
endif()
if(BUILD_COREMARK)
add_subdirectory(benchmarks/coremark)
endif()
# Create an all-inclusive target only if BUILD_ALL is ON
if(BUILD_ALL)
add_custom_target(fw-common ALL
DEPENDS
hello-world
dhrystone
coremark
)
endif()
# Print build instructions
message(STATUS "")
message(STATUS "Build instructions:")
message(STATUS " Build all targets: cmake -DBUILD_ALL=ON ..")
message(STATUS " Build specific target: cmake -DBUILD_HELLO_WORLD=ON -DBUILD_DHRYSTONE=OFF -DBUILD_COREMARK=OFF ..")
message(STATUS " Configure board: cmake -DBOARD=iss ..")
message(STATUS " Configure ISA: cmake -DISA=rv32imc ..")
message(STATUS " Configure ABI: cmake -DRISCV_ABI=ilp32 ..")
message(STATUS " Enable semihosting: cmake -DSEMIHOSTING=ON ..")
message(STATUS " Set toolchain path: cmake -DRISCV_TOOLCHAIN_PATH=/path/to/toolchain ..")
message(STATUS " Set specific compiler: cmake -DRISCV_GCC=/path/to/riscv-gcc -DRISCV_GXX=/path/to/riscv-g++ ..")

View File

@ -0,0 +1,66 @@
cmake_minimum_required(VERSION 3.12)
project(coremark C)
# Include BSP libwrap
include(${BSP_BASE}/libwrap/CMakeLists.txt)
# Source files
set(SOURCES
core_portme.c
cvt.c
ee_printf.c
cm/core_list_join.c
cm/core_main.c
cm/core_matrix.c
cm/core_state.c
cm/core_util.c
)
# Create executable
add_executable(coremark ${SOURCES})
# Include directories
target_include_directories(coremark PRIVATE
${BSP_BASE}/include
${BSP_BASE}/drivers
${BSP_BASE}/env
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/cm
)
# Link with libwrap
target_link_libraries(coremark PRIVATE
LIBWRAP_TGC
)
# Add compile definitions
target_compile_definitions(coremark PRIVATE
BOARD_${BOARD}
PERFORMANCE_RUN=1
ITERATIONS=1000
COMPILER_FLAGS="${CMAKE_C_FLAGS}"
COMPILER_VERSION="${CMAKE_C_COMPILER_VERSION}"
)
# Set compile options
target_compile_options(coremark PRIVATE
-march=${RISCV_ARCH}_zicsr_zifencei
-mabi=${RISCV_ABI}
-mcmodel=medany
-ffunction-sections
-fdata-sections
-O2 # Optimization level for benchmarking
)
# Set linker options
target_link_options(coremark PRIVATE
-T${BSP_BASE}/env/${BOARD}/link.ld
-nostartfiles
-Wl,--gc-sections
${LIBWRAP_TGC_LDFLAGS}
)
# Install target
install(TARGETS coremark
RUNTIME DESTINATION bin
)

View File

@ -1,2 +1,3 @@
dhrystone
/dhrystone.dis
build/

View File

@ -0,0 +1,21 @@
cmake_minimum_required(VERSION 3.21)
project(dhrystone C)
set(TARGET dhrystone)
set(CMAKE_BUILD_TYPE Release)
set(ITERATIONS 50000) # 20000 for TGC
add_executable(${TARGET} dhry_1.c dhry_2.c dhry_stubs.c)
target_include_directories(${TARGET} PRIVATE ${CMAKE_CURRENT_LIST_DIR})
target_compile_options(${TARGET} PRIVATE -fno-inline -fno-builtin-printf -fno-common -Wno-implicit -funroll-loops -fpeel-loops -fgcse-sm -fgcse-las)
target_compile_definitions(${TARGET} PRIVATE ITERATIONS=${ITERATIONS} HZ=32768 TIME NO_INIT)
set(BOARD "iss" CACHE STRING "Target board")
add_subdirectory(../../bare-metal-bsp bsp)
target_link_libraries(${TARGET} PRIVATE bsp)
target_link_options(${TARGET} PRIVATE LINKER:--wrap=scanf)
include(CMakePrintHelpers)
cmake_print_properties(TARGETS ${TARGET} PROPERTIES COMPILE_DEFINITIONS COMPILE_OPTIONS LINK_OPTIONS INTERFACE_LINK_OPTIONS)
add_custom_command(TARGET ${TARGET} POST_BUILD
COMMAND ${CMAKE_OBJDUMP} -S ${TARGET}.elf > ${TARGET}.dis
COMMENT "Creating disassembly for ${TARGET}")

View File

@ -15,9 +15,9 @@ else
RISCV_ABI:=ilp32
endif
# '-lgcc -lm' are needed to add softfloat routines
CFLAGS := -g -march=$(RISCV_ARCH)_zicsr_zifencei -mabi=$(RISCV_ABI) -mcmodel=medlow -O3 -DITERATIONS=$(ITERATIONS) -DHZ=32768 -DTIME -DNO_INIT -fno-inline -fno-builtin-printf -fno-common -Wno-implicit \
CFLAGS := -g -O3 -DITERATIONS=$(ITERATIONS) -DHZ=32768 -DTIME -DNO_INIT -fno-inline -fno-builtin-printf -fno-common -Wno-implicit \
-funroll-loops -fpeel-loops -fgcse-sm -fgcse-las
LDFLAGS := -g -march=$(RISCV_ARCH)_zicsr_zifencei -mabi=$(RISCV_ABI) -mcmodel=medlow -Wl,--wrap=scanf -Wl,--wrap=printf -Wl,--wrap=exit -lgcc -lm
LDFLAGS := -Wl,--wrap=scanf
TOOL_DIR=$(dir $(compiler))

View File

@ -1,108 +0,0 @@
import argparse
import os
import shutil
import subprocess
import time
from pathlib import Path
def run_command(command, cwd=None):
"""Run a shell command in the specified directory and return its output."""
result = subprocess.run(
command,
shell=True,
cwd=cwd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=False,
)
return result.stdout.decode("utf-8"), result.stderr.decode("utf-8")
def build_test_cases(makefile_dir, iterations):
"""Run the Makefile with the specified iterations."""
make_command = f"make clean && make ITERATIONS={iterations}"
stdout, stderr = run_command(make_command, cwd=makefile_dir)
if stderr:
raise RuntimeError(f"Error during make: {stderr}")
def main(simulator_path, makefile_dir):
# Directory for generated test cases
generated_dir = makefile_dir.parent / "workspace"
os.makedirs(generated_dir, exist_ok=True)
# Define the iterations
iterations_list = [10, 20, 30]
# 15 value up to 6.000.000 evenly apart on a log scale
iterations_list = [
1,
2,
4,
8,
17,
34,
69,
141,
287,
582,
1182,
2401,
4878,
9910,
20133,
40914,
83103,
168830,
343042,
696712,
1414641,
2874878,
5837995,
]
for iteration in iterations_list:
try:
# Update the Makefile with the current ITERATIONS value
build_test_cases(makefile_dir, iteration)
except RuntimeError as e:
print(f"Error during compilation with ITERATIONS={iteration}: {e}")
continue
# Run the simulator with the generated test case
exe = makefile_dir / "dhrystone.elf"
if not exe.is_file():
exit(f"{exe} does not exist")
verbose_exe = generated_dir / "bin" / f"dhrystone_{iteration}.elf"
os.makedirs(verbose_exe.parent, exist_ok=True)
shutil.copy(exe, verbose_exe)
backends = ["interp", "llvm", "tcc", "asmjit"]
for backend in backends:
log_file = os.path.join(generated_dir, f"{backend}_{iteration}.log")
sim_command = f"{simulator_path} -f {exe} --backend {backend}"
start_time = time.time()
sim_stdout, sim_stderr = run_command(sim_command)
end_time = time.time()
elapsed_time = end_time - start_time
# Save the output to the logfile
with open(log_file, "w", encoding="utf8") as f:
f.write(sim_stdout)
if sim_stderr:
f.write(f"\nErrors:\n{sim_stderr}")
print(
f"Ran {backend} in {elapsed_time:.2f} s, Output saved to {backend}_{iteration}.log"
)
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Run simulations with generated test cases."
)
parser.add_argument("simulator_path", help="Path to the simulator executable.")
args = parser.parse_args()
dhrystone_path = Path(__file__).parent / "dhrystone"
main(args.simulator_path, dhrystone_path)

View File

@ -1,86 +0,0 @@
import argparse
import os
import re
from pathlib import Path
import plotly.express as px
import yaml
def parse_logs(log_dir):
results = []
for filename in os.listdir(log_dir):
if filename.endswith(".log"):
filepath = os.path.join(log_dir, filename)
with open(filepath, "r", encoding="utf8") as file:
for line in file:
if (
"Executed" in line
and "instructions" in line
and "during" in line
and "resulting in" in line
):
parts = line.split()
instructions = int(parts[3])
time_idx = parts.index("during") + 1
time = int(parts[time_idx].rstrip("ms"))
mips_idx = parts.index("resulting") + 2
mips = float(parts[mips_idx].rstrip("MIPS"))
backend, iterations, _ = re.split(r"[_.]", filename)
results.append(
{
"backend": backend,
"run_count": int(iterations),
"instructions": instructions,
"time": time,
"mips": mips,
}
)
return results
def write_yaml(results, output_file):
with open(output_file, "w", encoding="utf8") as file:
yaml.dump(results, file)
def visualize_mips_over_instructions(yaml_file):
# Read data from YAML file
with open(yaml_file, "r", encoding="utf8") as file:
data = yaml.safe_load(file)
# Extract instructions and MIPS values
run_count = [entry["run_count"] for entry in data]
mips = [entry["mips"] for entry in data]
backends = [entry["backend"] for entry in data]
# Create scatter plot using Plotly Express
fig = px.line(
x=run_count,
y=mips,
color=backends,
labels={"x": "Dhrystone Iterations", "y": "MIPS", "color": "Backend"},
title="MIPS over Amount of Dhrystone Iterations",
log_x=True,
)
fig.show()
def main():
parser = argparse.ArgumentParser(
description="""
Parse log files and extract relevant information. Create a 'results.yaml' file and visualize it.
Intended to be run after 'dhrystone_run_multiple.py'"""
)
parser.add_argument("log_dir", help="Path to the directory containing log files.")
args = parser.parse_args()
result_file = Path(__file__).parent / "results.yaml"
if not result_file.is_file():
results = parse_logs(args.log_dir)
write_yaml(results, result_file)
visualize_mips_over_instructions(result_file)
if __name__ == "__main__":
main()

View File

@ -1,2 +1,3 @@
/hello
/hello.dis
build/

View File

@ -0,0 +1,12 @@
cmake_minimum_required(VERSION 3.21)
project(hello-world C)
set(TARGET hello)
add_executable(${TARGET} hello.c)
set(BOARD "iss" CACHE STRING "Target board")
add_subdirectory(../bare-metal-bsp bsp)
target_link_libraries(${TARGET} PRIVATE bsp)
add_custom_command(TARGET ${TARGET} POST_BUILD
COMMAND ${CMAKE_OBJDUMP} -S ${TARGET}.elf > ${TARGET}.dis
COMMENT "Creating disassembly for ${TARGET}")