Skip to content

Commit

Permalink
FPGA support (#77)
Browse files Browse the repository at this point in the history
Co-authored-by: Benoit Denkinger <[email protected]>
  • Loading branch information
benoitdenkinger and Benoit Denkinger authored Sep 30, 2024
1 parent 5eb93f4 commit feffecc
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 29 deletions.
25 changes: 17 additions & 8 deletions cmake/firmware/add_tests.cmake
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Iterates through the DIRECTORY sub-directories and create targets
# to start simulating each test.
function(add_tests EXECUTABLE DIRECTORY)
cmake_parse_arguments(ARG "USE_PLUSARGS" "WIDTH" "ARGS;DEPS" ${ARGN})
if(ARG_UNPARSED_ARGUMENTS)
Expand All @@ -6,6 +8,7 @@ function(add_tests EXECUTABLE DIRECTORY)

include("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../utils/subdirectory_search.cmake")
include("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../utils/colours.cmake")
include("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../utils/format_string_spacing.cmake")
include("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/fw_utils.cmake")
SUBDIRLIST(TEST_SUBDIRS ${DIRECTORY})

Expand All @@ -19,21 +22,23 @@ function(add_tests EXECUTABLE DIRECTORY)
set(PREFIX --)
endif()

unset(msg)
unset(_msg)
list(APPEND _msg "-------------------------------------------------------------------------\n")
string(REPLACE "__" "::" ALIAS_NAME ${SOC_NAME})
list(APPEND _msg "------------ Adding tests for SoC: \"${ALIAS_NAME}\", tb executable: \"${EXECUTABLE}\"\n")
list(APPEND _msg "Adding tests for SoC:\n")
list(APPEND _msg " ${ALIAS_NAME}, tb executable: ${EXECUTABLE}\n")
list(APPEND _msg "Added tests:\n")

enable_testing()
unset(_test_msg)
foreach(test ${TEST_SUBDIRS})
add_subdirectory("${DIRECTORY}/${test}" "${test}_test")
if(SOCMAKE_DONT_ADD_TEST)
unset(SOCMAKE_DONT_ADD_TEST)
continue()
endif()
foreach(fw_prj ${FW_PROJECT_NAME})
list(APPEND _msg " ${fw_prj}: ${${fw_prj}_DESCRIPTION}\n")
list(APPEND _test_msg " ${fw_prj}: ${${fw_prj}_DESCRIPTION}")
list(APPEND test_list ${fw_prj})
get_target_property(HEX_FILE ${fw_prj} HEX_${ARG_WIDTH}bit_FILE)
get_target_property(HEX_TEXT_FILE ${fw_prj} HEX_TEXT_${ARG_WIDTH}bit_FILE)
Expand All @@ -45,7 +50,7 @@ function(add_tests EXECUTABLE DIRECTORY)
${PREFIX}firmware_text=${HEX_TEXT_FILE}
${PREFIX}firmware_data=${HEX_DATA_FILE}
${ARG_ARGS}
)
)

add_custom_target(run_${fw_prj}
COMMAND ./${EXECUTABLE}
Expand All @@ -54,7 +59,7 @@ function(add_tests EXECUTABLE DIRECTORY)
${PREFIX}firmware_data=${HEX_DATA_FILE}
${ARG_ARGS}
DEPENDS ${EXECUTABLE} ${fw_prj} ${ARG_DEPS}
)
)
endforeach()
endforeach()

Expand All @@ -63,12 +68,16 @@ function(add_tests EXECUTABLE DIRECTORY)
add_custom_target(check
COMMAND ${CMAKE_CTEST_COMMAND} -j${NPROC}
DEPENDS ${test_list} ${EXECUTABLE}
)
)

format_string_spacing(formatted_test_msg "${_test_msg}" " ; ")

list(APPEND _msg "${formatted_test_msg}")

list(APPEND _msg "\nTo run ctest on all of the tests run:\n")
list(APPEND _msg " make check\n")
list(APPEND _msg " make check\n")
list(APPEND _msg "To run any of the added tests execute:\n")
list(APPEND _msg " make run_<test_name>\n")
list(APPEND _msg " make run_<test_name>\n")
list(APPEND _msg "-------------------------------------------------------------------------")
string(REPLACE ";" "" _msg "${_msg}")
msg("${_msg}" Blue)
Expand Down
4 changes: 3 additions & 1 deletion cmake/firmware/toolchains/riscv_toolchain.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ find_program(RISCV_STRIP ${TOOLCHAIN_PREFIX}-strip HINTS ${RISCV_GNU_PA

set(CMAKE_C_COMPILER ${RISCV_C_COMPILER})
set(CMAKE_CXX_COMPILER ${RISCV_CXX_COMPILER})
set(CMAKE_ASM_COMPILER ${RISCV_C_COMPILER})
set(CMAKE_ASM ${RISCV_ASM})
set(CMAKE_AR ${RISCV_AR})
set(CMAKE_LINKER ${RISCV_LINKER})
Expand Down Expand Up @@ -85,8 +86,9 @@ string(APPEND CMAKE_C_FLAGS " -mabi=ilp32")
# Optimize for size by default
string(APPEND CMAKE_C_FLAGS " -Os")

# Pass common flags for c++ compilation flow
# Pass common flags for c++ anD assembly compilation flow
set(CMAKE_CXX_FLAGS ${CMAKE_C_FLAGS})
set(CMAKE_ASM_FLAGS ${CMAKE_C_FLAGS})

#######################
# Options for Linking #
Expand Down
33 changes: 31 additions & 2 deletions cmake/fpga/uart_programmer/uart_programmer.cmake
Original file line number Diff line number Diff line change
@@ -1,19 +1,37 @@
# Iterates through the DIRECTORY sub-directories and create targets
# to start uart transactions for each test.
function(uart_programmer DIRECTORY BAUDRATE DEV)
cmake_parse_arguments(ARG "" "" "" ${ARGN})
if(ARG_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} passed unrecognized argument " "${ARG_UNPARSED_ARGUMENTS}")
endif()

include("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../utils/find_python.cmake")
include("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../utils/subdirectory_search.cmake")
include("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../utils/format_string_spacing.cmake")
include("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../utils/colours.cmake")
SUBDIRLIST(TEST_SUBDIRS ${DIRECTORY})

find_python3()
set(UART_PROGRAMMER ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/uart_programmer.py)

unset(_msg)
list(APPEND _msg "-------------------------------------------------------------------------\n")
string(REPLACE "__" "::" ALIAS_NAME ${SOC_NAME})
list(APPEND _msg "Adding tests for SoC:\n")
list(APPEND _msg " ${ALIAS_NAME}\n")
list(APPEND _msg "Added tests:\n")

unset(_test_msg)
foreach(test ${TEST_SUBDIRS})
add_subdirectory("${DIRECTORY}/${test}" "${test}_test")
if(SOCMAKE_DONT_ADD_TEST)
unset(SOCMAKE_DONT_ADD_TEST)
continue()
endif()
foreach(fw_prj ${FW_PROJECT_NAME})
list(APPEND _test_msg " ${fw_prj}: ${${fw_prj}_DESCRIPTION}")
list(APPEND test_list ${fw_prj})
get_target_property(HEX_FILE ${fw_prj} HEX_32bit_FILE)
get_target_property(HEX_TEXT_FILE ${fw_prj} HEX_TEXT_32bit_FILE)
get_target_property(HEX_DATA_FILE ${fw_prj} HEX_DATA_32bit_FILE)
Expand All @@ -28,6 +46,17 @@ function(uart_programmer DIRECTORY BAUDRATE DEV)
)
endforeach()
endforeach()

format_string_spacing(formatted_test_msg "${_test_msg}" " ; ")

list(APPEND _msg "${formatted_test_msg}")

list(APPEND _msg "To run any of the added tests on the FPGA:\n")
list(APPEND _msg " make program_<test_name>\n")
list(APPEND _msg "-------------------------------------------------------------------------")
string(REPLACE ";" "" _msg "${_msg}")
msg("${_msg}" Blue)

endfunction()


24 changes: 12 additions & 12 deletions cmake/fpga/uart_programmer/uart_programmer.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ def program(
text_bytes = b''
for line in text_lines:
line = line.strip()

if line.startswith('@') or line == '':
continue

words = line.split()
for word in words:
byte_data = bytes.fromhex(word)
Expand All @@ -34,10 +34,10 @@ def program(
data_bytes = b''
for line in data_lines:
line = line.strip()

if line.startswith('@') or line == '':
continue

words = line.split()
for word in words:
byte_data = bytes.fromhex(word)
Expand All @@ -48,7 +48,7 @@ def program(
num_text_bytes = len(text_bytes).to_bytes(4, byteorder='little')
num_data_bytes = (len(data_bytes)).to_bytes(4, byteorder='little')


print("-----------------------------------------------------")
print(f"----- Programming {dev} at baudrate {baudrate} ---")

Expand All @@ -65,31 +65,31 @@ def program(
def getport(dev):
ports = serial.tools.list_ports.comports()
port_names = [port.device for port in ports]

default_port = port_names[0]
if dev in port_names:
default_port = dev
elif "/dev/ttyUSB0" in port_names:
default_port = "/dev/ttyUSB0"

print(f"Available ports:")
for index,port in enumerate(port_names):
print(f"{index+1}: {port}", end="")
if port == default_port:
print(" (default)", end="")

print()

input_port = input(f"Enter port number (default {default_port}): ")
try:
port = port_names[int(input_port)-1]
except:
port = default_port

print(f"Selected port: {port}")
return port



def main():
parser = argparse.ArgumentParser(
Expand Down
9 changes: 3 additions & 6 deletions cmake/fpga/vivado/vivado.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,13 @@ function(vivado IP_LIB)
--outdir ${OUTDIR}
--verilog-defs ${ARG_VERILOG_DEFINES} ${CMP_DEFS_ARG}

COMMAND touch ${STAMP_FILE}
COMMAND /bin/sh -c date > ${STAMP_FILE}
DEPENDS ${SOURCES} ${XDC_FILES} ${IP_LIB}
COMMENT "Running ${CMAKE_CURRENT_FUNCTION} on ${IP_LIB}"
)
)

add_custom_target(
${IP_LIB}_vivado
DEPENDS ${BITSTREAM} ${STAMP_FILE}
)
)
endfunction()



87 changes: 87 additions & 0 deletions cmake/utils/format_string_spacing.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
include_guard(GLOBAL)

# Take an input list of strings with single space words and replace each
# space with the corresponding formatting character (e.g., tab(s), space(s)).
# If a space is not given a replacement character, a single space is kept
#
# Example usage:
# set(input_list " test1: Test1 does that." " test2: Test2 does this and that.")
# set(replacements " ;\t")
#
# format_string(FORMATTED_STRING "${input_list}" "${replacements}")
# Output:
# test1: Test1 does that.
# test2: Test2 does this and that.

function(format_string_spacing OUTPUT_VAR input_list replacements)
# Split the replacement characters into a list.
string(REPLACE ";" ";" replacement_list "${replacements}")

set(formatted_string "") # To store the final formatted result
set(max_lengths "") # To store the maximum length of each part before spaces


# Step 1: Calculate maximum lengths for the sections before each space
foreach(line IN LISTS input_list)
string(REPLACE " " ";" split_line "${line}")
set(index 0)
foreach(section IN LISTS split_line)
string(LENGTH "${section}" section_length)

# Expand max_lengths if it is the first pass
list(LENGTH max_lengths list_size)
if(list_size LESS_EQUAL index)
list(APPEND max_lengths 0)
endif()

# Update max length for each column section
list(GET max_lengths ${index} current_max_length)
if(section_length GREATER current_max_length)
list(REMOVE_AT max_lengths ${index})
list(INSERT max_lengths ${index} ${section_length})
endif()

math(EXPR index "${index} + 1")
endforeach()
endforeach()

# Step 2: Format each line based on the calculated max lengths
foreach(line IN LISTS input_list)
string(REPLACE " " ";" split_line "${line}")

set(formatted_line "")
set(index 0)
foreach(section IN LISTS split_line)
# Get the length of the section
string(LENGTH "${section}" section_length)

# Get the max length for this section
list(GET max_lengths ${index} max_length)

# Pad the section with spaces to match the maximum length
math(EXPR padding_length "${max_length} - ${section_length}")
string(REPEAT " " ${padding_length} padding)

# Append the section to the formatted line
set(formatted_line "${formatted_line}${section}")

# Add the replacement string if available, otherwise keep original space
list(LENGTH replacement_list replacement_count)
if(${index} LESS replacement_count)
list(GET replacement_list ${index} replacement_char)
set(formatted_line "${formatted_line}${padding}${replacement_char}")
else()
# Add original space back if no replacement is available
set(formatted_line "${formatted_line} ")
endif()

math(EXPR index "${index} + 1")
endforeach()

# Add the formatted line to the final formatted string
string(APPEND formatted_string "${formatted_line}\n")
endforeach()

# Step 3: Return the formatted string
set(${OUTPUT_VAR} "${formatted_string}" PARENT_SCOPE)
endfunction()

0 comments on commit feffecc

Please sign in to comment.