diff --git a/hwpe/neureka/pulp_inject_fault.tcl b/hwpe/neureka/pulp_inject_fault.tcl index fa7efb25..2792de23 100644 --- a/hwpe/neureka/pulp_inject_fault.tcl +++ b/hwpe/neureka/pulp_inject_fault.tcl @@ -17,8 +17,8 @@ set log_injections 1 set seed 12345 set print_statistics 1 -set inject_start_time 80000000000ps -set inject_stop_time 150000000000ps +set inject_start_time 20000000ps +set inject_stop_time 37500000ps set injection_clock "pulp_cluster_tb/cluster_i/clk_i" set injection_clock_trigger 0 set fault_period 100 diff --git a/hwpe/redmule/Makefile b/hwpe/redmule/Makefile index a92a1dbc..79c0c0d9 100644 --- a/hwpe/redmule/Makefile +++ b/hwpe/redmule/Makefile @@ -2,6 +2,8 @@ PULP_APP = test PULP_APP_SRCS = redmule.c PULP_CFLAGS = -O3 +export LEGACY_DMA=1 + ifeq ($(use_dma),1) PULP_CFLAGS += -DUSE_DMA endif diff --git a/hwpe/redmule/pulp_inject_fault.tcl b/hwpe/redmule/pulp_inject_fault.tcl index 61ccadfc..a0a7c544 100644 --- a/hwpe/redmule/pulp_inject_fault.tcl +++ b/hwpe/redmule/pulp_inject_fault.tcl @@ -17,8 +17,8 @@ set log_injections 1 set seed 12345 set print_statistics 1 -set inject_start_time 550000000000ps -set inject_stop_time 750000000000ps +set inject_start_time 137500000ps +set inject_stop_time 187500000ps set injection_clock "pulp_cluster_tb/cluster_i/clk_i" set injection_clock_trigger 0 set fault_period 150 diff --git a/hwpe/redmule_256iter/Makefile b/hwpe/redmule_256iter/Makefile index 88346b61..b037422c 100644 --- a/hwpe/redmule_256iter/Makefile +++ b/hwpe/redmule_256iter/Makefile @@ -2,6 +2,8 @@ PULP_APP = test PULP_APP_SRCS = redmule.c PULP_CFLAGS = -O3 +export LEGACY_DMA=1 + ifeq ($(use_dma),1) PULP_CFLAGS += -DUSE_DMA endif diff --git a/hwpe/redmule_softclear/Makefile b/hwpe/redmule_softclear/Makefile index 88346b61..b037422c 100644 --- a/hwpe/redmule_softclear/Makefile +++ b/hwpe/redmule_softclear/Makefile @@ -2,6 +2,8 @@ PULP_APP = test PULP_APP_SRCS = redmule.c PULP_CFLAGS = -O3 +export LEGACY_DMA=1 + ifeq ($(use_dma),1) PULP_CFLAGS += -DUSE_DMA endif diff --git a/hwpe/softex/Makefile b/hwpe/softex/Makefile index a15e3981..b8f3a2ff 100644 --- a/hwpe/softex/Makefile +++ b/hwpe/softex/Makefile @@ -2,6 +2,8 @@ PULP_APP = test PULP_APP_SRCS = softex.c PULP_CFLAGS = -O3 +export LEGACY_DMA=1 + ifeq ($(use_dma),1) PULP_CFLAGS += -DUSE_DMA endif diff --git a/idma_tests/README.md b/idma_tests/README.md new file mode 100644 index 00000000..0e11d8a8 --- /dev/null +++ b/idma_tests/README.md @@ -0,0 +1,21 @@ +## IDMA Tests + +This folder contains basic tests for the iDMA IP. +Currently, the following are supported: +- **1D transfers** +- **2D transfers** +- **3D transfers** + +To launch each test: +1. Move into the related folder. +2. Launch the following: + 1. `make stimuli` : this will generate the randomized stimuli for the test. The randomized stimuli consist of transfer sizes, number of transfers to be executed, n-dimensional strides, etc ... + 2. `make clean all` : this will compile the C code. Few choices are available: + - **Single Core mode**: no flags are needed. All transfers specified in the stimuli will be executed by Core 0 only. + - **Sequential Multi-Core Mode**: specify **MULTI_CORE_S=1** in the command line when compiling the code. In this mode, all cores will execute the transfers specified in the stimuli in a sequential manner. + - **Parallel Multi-Core Mode**: specify **MULTI_CORE_P=1** in the command line when compiling the code. In this mode, all cores will execute the transfers specified in the stimulin in a parallel manner. + - **Quick Mode**: specify **QUICK_MODE=1** in the command line when compiling the code. In this mode the non-random inputs (declared in the idma_presets.h files) are used instead of the random ones. + 3. `make run` : this will launch the simulation in bash mode (use gui=1 for Modelsim gui). +4. All transfers will be executed in the three different directions that are currently supported: **L1->L2, L2->L1, L1->L1**. + +Updated drivers for the iDMA can be found at **pulp_cluster/pulp-runtime/include/hal/dma/idma_v2.h** and **pulp_cluster/pulp-runtime/include/archi/dma/idma_v2.h**. diff --git a/idma_tests/gen_stimuli.py b/idma_tests/gen_stimuli.py new file mode 100644 index 00000000..29c439a2 --- /dev/null +++ b/idma_tests/gen_stimuli.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python + +import sys +import random +import argparse +import math +import re + +# Extracting testcase +if len(sys.argv) > 1: + testcase = sys.argv[1] +else: + testcase = None + + +# Define max values for size, strides and length +TRANSFER_SIZE = 128 +MAX_STRIDE = 10 +MAX_LENGTH = 10 +MAX_REPS = 5 +# Randomize the number of transfers to execute +NB_TRANSFERS = random.randint(1, 10) +# Create array for sizes of each transfer +transfers = [None] * NB_TRANSFERS + +######################################### +# 1D STIMULI GENERATION +######################################### + +# The following function writes the needed defines and the structure containing the parameter fields for a 1-dimensional transfer +def write_transfer_params_1d(f, struct_name, params_array_name, arr): + f.write ('%s %s[] = {\n' % (struct_name, params_array_name)) + for v in arr: + size = random.randint(1, TRANSFER_SIZE) + f.write('{%d},\n' % size) + f.write('};\n\n') + return + +# The following function writes an array of structures containing the parameters for the 1-dimensional transfers to be executed +def write_defs_array_1d(f, name, val, name_size, name_struct): + f.write('#define %s %d\n\n' % (name,val)) + f.write ('typedef struct { \n') + f.write (' unsigned int %s;\n' % name_size) + f.write ('} %s;\n\n' %name_struct) + return + +######################################### +# 2D STIMULI GENERATION +######################################### + +# The following function writes the needed defines and the structure containing the parameter fields for a 2-dimensional transfer +def write_defs_array_2d(f, name, val, name_size, length, name_src_stride, name_dst_stride, name_struct): + f.write('#define %s %d\n\n' % (name,val)) + f.write ('typedef struct { \n') + f.write (' unsigned int %s;\n' % name_size) + f.write (' unsigned int %s;\n' % length) + f.write (' unsigned int %s;\n' % name_src_stride) + f.write (' unsigned int %s;\n' % name_dst_stride) + f.write ('} %s;\n\n' %name_struct) + return + +# The following function writes an array of structures containing the parameters for the 2-dimensional transfers to be executed +def write_transfer_params_2d(f, struct_name, params_array_name, arr): + f.write ('%s %s[] = {\n' % (struct_name, params_array_name)) + for v in arr: + length = random.randint(1, MAX_LENGTH) + size = random.randint(1, TRANSFER_SIZE) + length + src_stride = random.randint(1, MAX_STRIDE) + length + dst_stride = random.randint(1, MAX_STRIDE) + length + f.write('{%d, %d, %d, %d},\n' % (size, length, src_stride, dst_stride)) + f.write('};\n\n') + return + +######################################### +# 3D STIMULI GENERATION +######################################### + +# The following function writes the needed defines and the structure containing the parameter fields for a 2-dimensional transfer +def write_defs_array_3d(f, name, val, name_size, length, name_src_stride_2d, name_dst_stride_2d, name_src_stride_3d, name_dst_stride_3d, num_reps_3d, name_struct): + f.write('#define %s %d\n\n' % (name,val)) + f.write ('typedef struct { \n') + f.write (' unsigned int %s;\n' % name_size) + f.write (' unsigned int %s;\n' % length) + f.write (' unsigned int %s;\n' % name_src_stride_2d) + f.write (' unsigned int %s;\n' % name_dst_stride_2d) + f.write (' unsigned int %s;\n' % name_src_stride_3d) + f.write (' unsigned int %s;\n' % name_dst_stride_3d) + f.write (' unsigned int %s;\n' % num_reps_3d) + f.write ('} %s;\n\n' %name_struct) + return + +# The following function writes an array of structures containing the parameters for the 2-dimensional transfers to be executed +def write_transfer_params_3d(f, struct_name, params_array_name, arr): + f.write ('%s %s[] = {\n' % (struct_name, params_array_name)) + for v in arr: + length = random.randint(1, MAX_LENGTH) + size = random.randint(1, TRANSFER_SIZE) + length + src_stride_2d = random.randint(1, MAX_STRIDE) + length + dst_stride_2d = random.randint(1, MAX_STRIDE) + length + src_stride_3d = random.randint(1, MAX_STRIDE) + length + dst_stride_3d = random.randint(1, MAX_STRIDE) + length + num_reps_3d = random.randint(1, MAX_REPS) + f.write('{%d, %d, %d, %d, %d, %d, %d},\n' % (size, length, src_stride_2d, dst_stride_2d, src_stride_3d, dst_stride_3d, num_reps_3d)) + f.write('};\n\n') + return + + +def gen_stim_1d(f_param, f_def, testcase): + print ("Generate stimuli for 1d testcase") + struct_name = 'transfer_1d' + size_field_name = 'size_1d' + params_array_name = 'params_1d' + write_defs_array_1d(f_def, 'NB_TRANSFERS', NB_TRANSFERS, size_field_name, struct_name) + write_transfer_params_1d(f_param, struct_name, params_array_name, transfers) + +def gen_stim_2d(f_param, f_def, testcase): + print ("Generate stimuli for 2d testcase") + struct_name = 'transfer_2d' + size_field_name = 'size_2d' + length_field_name = 'length' + src_stride_field_name = 'src_stride_2d' + dst_stride_field_name = 'dst_stride_2d' + params_array_name = 'params_2d' + write_defs_array_2d(f_def, 'NB_TRANSFERS', NB_TRANSFERS, size_field_name, length_field_name, src_stride_field_name, dst_stride_field_name, struct_name) + write_transfer_params_2d(f_param, struct_name, params_array_name, transfers) + +def gen_stim_3d(f_param, f_def, testcase): + print ("Generate stimuli for 3d testcase") + struct_name = 'transfer_3d' + size_field_name = 'size_3d' + length_field_name = 'length' + src_stride_2d_field_name = 'src_stride_2d' + src_stride_3d_field_name = 'src_stride_3d' + dst_stride_2d_field_name = 'dst_stride_2d' + dst_stride_3d_field_name = 'dst_stride_3d' + num_reps_3d_field_name = 'num_reps_3d' + params_array_name = 'params_3d' + write_defs_array_3d(f_def, 'NB_TRANSFERS', NB_TRANSFERS, size_field_name, length_field_name, src_stride_2d_field_name, dst_stride_2d_field_name, src_stride_3d_field_name, dst_stride_3d_field_name, num_reps_3d_field_name, struct_name) + write_transfer_params_3d(f_param, struct_name, params_array_name, transfers) + + +# Selecting the testcase depending on what was specified through command line (defaulting to 1D) + +if (testcase == '1D'): + print ("Generating stimuli for 1D case") + f_param_1d = open('idma_param_1d.h', 'w') + f_def_1d = open('idma_def_1d.h', 'w') + gen_stim_1d(f_param_1d, f_def_1d, testcase) +elif (testcase == '2D'): + print ("Generating stimuli for 2D case") + f_param_2d = open('idma_param_2d.h', 'w') + f_def_2d = open('idma_def_2d.h', 'w') + gen_stim_2d(f_param_2d, f_def_2d, testcase) +elif (testcase == '3D'): + print ("Generating stimuli for 3D case") + f_param_3d = open('idma_param_3d.h', 'w') + f_def_3d = open('idma_def_3d.h', 'w') + gen_stim_3d(f_param_3d, f_def_3d, testcase) +else: + print ("No testcase specified --> generating stimuli for 1d case") + f_param_1d = open('idma_param_1d.h', 'w') + f_def_1d = open('idma_def_1d.h', 'w') + gen_stim_1d(f_param_1d, f_def_1d, testcase) diff --git a/idma_tests/idma_multi_core/Makefile b/idma_tests/idma_multi_core/Makefile new file mode 100644 index 00000000..330603e9 --- /dev/null +++ b/idma_tests/idma_multi_core/Makefile @@ -0,0 +1,36 @@ +PULP_APP = test +TEST_SRCS ?= idma_multi_core.c +PULP_APP_SRCS = $(TEST_SRCS) + +ifdef VERBOSE +PULP_CFLAGS += -DVERBOSE +endif + +ifdef CYCLE_COUNT +PULP_CFLAGS += -DCYCLE_COUNT +PULP_CFLAGS += -DVERBOSE +endif + +ifdef MULTI_CORE_P +PULP_CFLAGS += -DMULTI_CORE_P +endif + +ifdef MULTI_CORE_S +PULP_CFLAGS += -DMULTI_CORE_S +endif + +ifdef SINGLE_CORE +PULP_CFLAGS += -DSINGLE_CORE +endif + +ifdef QUICK_MODE +PULP_CFLAGS += -DQUICK_MODE +endif + +PULP_CFLAGS += -O3 +stackSize = 4096 + +include $(PULP_SDK_HOME)/install/rules/pulp.mk + +stimuli: + python ../gen_stimuli.py 1D diff --git a/idma_tests/idma_multi_core/idma_def_1d.h b/idma_tests/idma_multi_core/idma_def_1d.h new file mode 100644 index 00000000..5c3e7932 --- /dev/null +++ b/idma_tests/idma_multi_core/idma_def_1d.h @@ -0,0 +1,6 @@ +#define NB_TRANSFERS 5 + +typedef struct { + unsigned int size_1d; +} transfer_1d; + diff --git a/idma_tests/idma_multi_core/idma_multi_core.c b/idma_tests/idma_multi_core/idma_multi_core.c new file mode 100644 index 00000000..398ae5dc --- /dev/null +++ b/idma_tests/idma_multi_core/idma_multi_core.c @@ -0,0 +1,227 @@ +#include "idma_multi_core.h" + +#define TOT_SIZE 8 * CORE_SPACE + +int errors[8] = {0}; +int test_status = 8; + +uint32_t l1_addr[8] = {0}; +uint32_t l1_dst_addr[8] = {0}; +uint32_t l2_addr[8] = {0}; + +int test_idma_1D (int core_id, uint32_t size, int ext2loc, int loc2loc) { + volatile uint8_t *src_ptr, *dst_ptr; + + int error = 0; + + if (loc2loc == 1) { + // L1 to L1 transfer + src_ptr = (uint8_t*) l1_addr[core_id]; + dst_ptr = (uint8_t*) l1_dst_addr[core_id]; + } else if (ext2loc == 1) { + // L2 to L1 transfer + src_ptr = (uint8_t*) l2_addr[core_id]; + dst_ptr = (uint8_t*) l1_addr[core_id]; + } else { + // L1 to L2 transfer + src_ptr = (uint8_t*) l1_addr[core_id]; + dst_ptr = (uint8_t*) l2_addr[core_id]; + } + + // Fill source region with test data + for (int i = 0; i < size; i++) { + src_ptr[i] = (uint8_t)(i & 0xFF); + dst_ptr[i] = (uint8_t)((i-1)&0xFF); + } + + if (loc2loc == 1) { + reset_cycle_count(); + start_cycle_count(); + plp_cl_dma_wait_toL1(pulp_cl_idma_L1ToL1((unsigned int) src_ptr, (unsigned int) dst_ptr, size)); + stop_cycle_count(); + } else if (ext2loc == 1) { + reset_cycle_count(); + start_cycle_count(); + plp_cl_dma_wait_toL1(pulp_cl_idma_L2ToL1((unsigned int) src_ptr, (unsigned int) dst_ptr, size)); + stop_cycle_count(); + } else { + reset_cycle_count(); + start_cycle_count(); + plp_cl_dma_wait_toL2(pulp_cl_idma_L1ToL2((unsigned int) src_ptr, (unsigned int) dst_ptr, size)); + stop_cycle_count(); + } + + print_perf(); + + // Check the results + + for (int i=0; i < size; i++) { + uint8_t expected = src_ptr[i]; + uint8_t actual = dst_ptr[i]; + + if (expected != actual) { + error++; + PRINTF ("Core[%d]: Error: expected @%8x = %8x vs actual @%8x = %8x \n", rt_core_id(), expected, &src_ptr[i], actual, &dst_ptr[i]); + } + } + + return error; +} + +void allocate_mem_to_cores () { + int core_id = rt_core_id(); + + // Pre-allocate TOT_SIZE = 8 * CORE_SPACE: then we split this window to assign + // each core its available space for iDMA transfers + // pi_l1_malloc starts allocating from 0x10004008 in L1 + // pi_l2_malloc starts allocating from 0x1c000a60 in L2 + + if (core_id == 0) { + l1_addr[0] = (uint32_t) pi_l1_malloc(0, TOT_SIZE); + l1_dst_addr[0] = (uint32_t) pi_l1_malloc(0, TOT_SIZE); + l2_addr[0] = (uint32_t) pi_l2_malloc(TOT_SIZE); + } + + // The following synch_barrier is needed so that + // no core can assign its address range until the mallocs are executed + synch_barrier(); + + l1_addr[core_id] = l1_addr[0] + core_id * CORE_SPACE; + l1_dst_addr[core_id] = l1_dst_addr[0] + core_id * CORE_SPACE; + l2_addr[core_id] = l2_addr[0] + core_id * CORE_SPACE; + + if (core_id == 0) { + for (int i = 0; i < 8; i++) { + PRINTF ("Core %d: l1_addr[%d] = %8x \n", core_id, i, l1_addr[i]); + PRINTF ("Core %d: l1_dst_addr[%d] = %8x \n", core_id, i, l1_dst_addr[i]); + PRINTF ("Core %d: l2_addr[%d] = %8x \n", core_id, i, l2_addr[i]); + } + } + + // The following synch_barrier is needed so that + // no core can start executing until all address ranges have been assigned + synch_barrier(); + +} + +void free_allocated_memory () { + + synch_barrier(); + // Only Core 0 takes care of freeing the allocated memory, since it's the one + // allocated it at the beginning of the test + if (rt_core_id() == 0) { + pi_l1_free(0, l1_addr, TOT_SIZE); + pi_l1_free(0, l1_dst_addr, TOT_SIZE); + pi_l2_free(l2_addr, TOT_SIZE); + } +} + +int cluster_task () { + int core_id = rt_core_id(); + unsigned int size = 0; + + allocate_mem_to_cores(); + + #ifdef MULTI_CORE_P + // MULTI CORE PARALLEL MODE: each core uses the iDMA in a parallel manner + if (core_id == 0) { + PRINTF ("MULTI CORE PARALLEL MODE \n"); + } + + synch_barrier(); + for (int k = 0; k < NB_TRANSFERS; k++) { + #ifdef QUICK_MODE + size = idma_presets[k].size_1d; + #else + size = params_1d[k].size_1d; + #endif + // L1 -> L2 + PRINTF ("L1 -> L2 => Size: %d | Core: %d \n", size, rt_core_id()); + errors[core_id] += test_idma_1D(core_id, size, 0, 0); + // L2 -> L1 + PRINTF ("L2 -> L1 => Size: %d | Core: %d \n", size, rt_core_id()); + errors[core_id] += test_idma_1D(core_id, size, 1, 0); + // L1 -> L1 + PRINTF ("L1 -> L1 => Size: %d | Core: %d \n", size, rt_core_id()); + errors[core_id] += test_idma_1D(core_id, size, 0, 1); + } + synch_barrier(); + + #elif MULTI_CORE_S + // MULTI CORE SERIAL MODE: each core uses the iDMA in a serial manner + if (core_id == 0) { + PRINTF ("MULTI CORE SERIAL MODE \n"); + } + for (int i = 0; i < 8; i++) { + if (core_id == i) { + for (int k = 0; k < NB_TRANSFERS; k++) { + #ifdef QUICK_MODE + size = idma_presets[k].size_1d; + #else + size = params_1d[k].size_1d; + #endif + // L1 -> L2 + PRINTF ("Core[%d]: L1 -> L2 => Size: %d \n", rt_core_id(), size); + errors[core_id] += test_idma_1D(core_id, size, 0, 0); + // L2 -> L1 + if (core_id == 0){ + PRINTF ("Core[%d]: L2 -> L1=> Size: %d \n", rt_core_id(), size); + } + errors[core_id] += test_idma_1D(core_id, size, 1, 0); + // L1 -> L1 + if (core_id == 0){ + PRINTF ("Core[%d]: L1 -> L1 => Size: %d \n", rt_core_id(), size); + } + errors[core_id] += test_idma_1D(core_id, size, 0, 1); + } + } + synch_barrier(); + } + #else + if (core_id == 0) { + // SINGLE CORE MODE: just core 0 uses the iDMA + PRINTF ("SINGLE CORE MODE: CORE 0 \n"); + for (int k = 0; k < NB_TRANSFERS; k++) { + #ifdef QUICK_MODE + size = idma_presets[k].size_1d; + #else + size = params_1d[k].size_1d; + #endif + // L1 -> L2 + PRINTF ("L1 -> L2 => Size: %d \n", size); + errors[core_id] += test_idma_1D(core_id, size, 0, 0); + // L2 -> L1 + PRINTF ("L2 -> L1=> Size: %d \n", size); + errors[core_id] += test_idma_1D(core_id, size, 1, 0); + // L1 -> L1 + PRINTF ("L1 -> L1 => Size: %d \n", size); + errors[core_id] += test_idma_1D(core_id, size, 0, 1); + } + } + #endif + + if (core_id == 0) { + for (int i = 0; i<8; i++) { + if (errors[i] == 0) { + PRINTF ("Core %d returned %d errors \n", i, errors[i]); + test_status--; + } + } + } + + free_allocated_memory(); + + return test_status; +} + +int main () { + int retval = 1; + #ifdef ARCHI_HAS_FC + PRINTF ("Fabric Controller calling cluster task \n"); + if (rt_cluster_id() != 0) + return bench_cluster_forward(0); + #endif + retval = cluster_task(); + + return retval; +} diff --git a/idma_tests/idma_multi_core/idma_multi_core.h b/idma_tests/idma_multi_core/idma_multi_core.h new file mode 100644 index 00000000..c81e99b4 --- /dev/null +++ b/idma_tests/idma_multi_core/idma_multi_core.h @@ -0,0 +1,61 @@ +// Copyright 2022 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 +// +//Author: Andreas Kuster +// +//Description: Generated register defines for dma_frontend + +#include "pulp.h" +#include +#include +#include +#include +#include + +#include "idma_def_1d.h" +#include "idma_presets.h" +#include "idma_param_1d.h" + +#ifndef _DMA_FRONTEND_REG_DEFS_ +#define _DMA_FRONTEND_REG_DEFS_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define DMA_CONF_DECOUPLE 0 +#define DMA_CONF_DEBURST 0 +#define DMA_CONF_SERIALIZE 0 + +#define CORE_SPACE 2048 + +#if VERBOSE + #define PRINTF(...) printf(__VA_ARGS__) +#else + #define PRINTF(...) +#endif + +#ifdef CYCLE_COUNT + static inline void start_cycle_count () { perf_start(); } + static inline void stop_cycle_count () { perf_stop(); } + static inline void reset_cycle_count () { perf_reset(); } + static inline void print_perf() { PRINTF ("Performances: \n"); perf_print_all(); } +#else + static inline void start_cycle_count () { } + static inline void stop_cycle_count () { } + static inline void reset_cycle_count () { } + static inline void print_perf() { } +#endif + + +#ifdef QUICK_MODE + #define TRANSFERS 12 +#else + #define TRANSFERS NB_TRANSFERS +#endif + +#ifdef __cplusplus +} // extern "C" +#endif +#endif // _DMA_FRONTEND_REG_DEFS_ diff --git a/idma_tests/idma_multi_core/idma_param_1d.h b/idma_tests/idma_multi_core/idma_param_1d.h new file mode 100644 index 00000000..64605f49 --- /dev/null +++ b/idma_tests/idma_multi_core/idma_param_1d.h @@ -0,0 +1,8 @@ +transfer_1d params_1d[] = { +{41}, +{50}, +{112}, +{33}, +{122}, +}; + diff --git a/idma_tests/idma_multi_core/idma_presets.h b/idma_tests/idma_multi_core/idma_presets.h new file mode 100644 index 00000000..6cd7ec55 --- /dev/null +++ b/idma_tests/idma_multi_core/idma_presets.h @@ -0,0 +1,3 @@ +transfer_1d idma_presets [] = { + 1, 2, 3, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048 +}; \ No newline at end of file diff --git a/idma_tests/idma_multi_core_2d/Makefile b/idma_tests/idma_multi_core_2d/Makefile new file mode 100644 index 00000000..6f645c4c --- /dev/null +++ b/idma_tests/idma_multi_core_2d/Makefile @@ -0,0 +1,32 @@ +PULP_APP = test +TEST_SRCS ?= idma_multi_core_2d.c +PULP_APP_SRCS = $(TEST_SRCS) + +ifdef VERBOSE +PULP_CFLAGS += -DVERBOSE +endif + +ifdef CYCLE_COUNT +PULP_CFLAGS += -DCYCLE_COUNT +PULP_CFLAGS += -DVERBOSE +endif + +ifdef MULTI_CORE_P +PULP_CFLAGS += -DMULTI_CORE_P +endif + +ifdef MULTI_CORE_S +PULP_CFLAGS += -DMULTI_CORE_S +endif + +ifdef QUICK_MODE +PULP_CFLAGS += -DQUICK_MODE +endif + +PULP_CFLAGS += -O3 +stackSize = 4096 + +include $(PULP_SDK_HOME)/install/rules/pulp.mk + +stimuli: + python ../gen_stimuli.py 2D \ No newline at end of file diff --git a/idma_tests/idma_multi_core_2d/idma_def_2d.h b/idma_tests/idma_multi_core_2d/idma_def_2d.h new file mode 100644 index 00000000..0851d0e1 --- /dev/null +++ b/idma_tests/idma_multi_core_2d/idma_def_2d.h @@ -0,0 +1,9 @@ +#define NB_TRANSFERS 5 + +typedef struct { + unsigned int size_2d; + unsigned int length; + unsigned int src_stride_2d; + unsigned int dst_stride_2d; +} transfer_2d; + diff --git a/idma_tests/idma_multi_core_2d/idma_multi_core_2d.c b/idma_tests/idma_multi_core_2d/idma_multi_core_2d.c new file mode 100644 index 00000000..293dfebe --- /dev/null +++ b/idma_tests/idma_multi_core_2d/idma_multi_core_2d.c @@ -0,0 +1,243 @@ +#include "idma_multi_core_2d.h" + +#define TOT_SIZE 8 * CORE_SPACE + +int errors[8] = {0}; +int test_status = 8; + +uint32_t l1_addr[8] = {0}; +uint32_t l1_dst_addr[8] = {0}; +uint32_t l2_addr[8] = {0}; + +int test_idma_2D (int core_id, transfer_2d transfer, int ext2loc, int loc2loc) { + volatile uint8_t *src_ptr, *dst_ptr; + + int error = 0; + int src_offset_2d, dst_offset_2d; + + uint32_t src_stride = transfer.src_stride_2d; + uint32_t dst_stride = transfer.dst_stride_2d; + uint32_t size = transfer.size_2d; + uint32_t length = transfer.length; + uint32_t num_reps = size/length; + + if (loc2loc == 1) { + // L1 to L1 transfer + src_ptr = (uint8_t*) l1_addr[core_id]; + dst_ptr = (uint8_t*) l1_dst_addr[core_id]; + } else if (ext2loc == 1) { + // L2 to L1 transfer + src_ptr = (uint8_t*) l2_addr[core_id]; + dst_ptr = (uint8_t*) l1_addr[core_id]; + } else { + // L1 to L2 transfer + src_ptr = (uint8_t*) l1_addr[core_id]; + dst_ptr = (uint8_t*) l2_addr[core_id]; + } + + // Fill source region with test data + for (int q = 0; q < num_reps; q++) { + src_offset_2d = q * src_stride; + dst_offset_2d = q * dst_stride; + for (int i = 0; i < length; i++) { + src_ptr[i+src_offset_2d] = (uint8_t)(i & 0xFF); + dst_ptr[i+dst_offset_2d] = (uint8_t)((i-1) & 0xFF); + } + } + + if (loc2loc == 1) { + reset_cycle_count(); + start_cycle_count(); + plp_cl_dma_wait_toL1(pulp_cl_idma_L1ToL1_2d((unsigned int)src_ptr, (unsigned int)dst_ptr, length, src_stride, dst_stride, num_reps)); + stop_cycle_count(); + } else if (ext2loc == 1) { + reset_cycle_count(); + start_cycle_count(); + plp_cl_dma_wait_toL1(pulp_cl_idma_L2ToL1_2d((unsigned int)src_ptr, (unsigned int)dst_ptr, length, src_stride, dst_stride, num_reps)); + stop_cycle_count(); + } else { + reset_cycle_count(); + start_cycle_count(); + plp_cl_dma_wait_toL2(pulp_cl_idma_L1ToL2_2d((unsigned int)src_ptr, (unsigned int)dst_ptr, length, src_stride, dst_stride, num_reps)); + stop_cycle_count(); + } + + print_perf(); + + + // Check the results + + for (unsigned int rep = 0; rep < num_reps; rep++) { + unsigned int src_offset = rep * src_stride; + unsigned int dst_offset = rep * dst_stride; + for (unsigned int i = 0; i < length; i++) { + uint8_t expected = src_ptr[src_offset + i]; + uint8_t actual = dst_ptr[dst_offset + i]; + + if (expected != actual) { + error++; + PRINTF ("Core[%d]: ERROR: expected[%d] @%8x = %8x vs actual[%d] @%8x = %8x \n", rt_core_id(), src_offset + i, &src_ptr[src_offset + i], + expected, dst_offset+i, &dst_ptr[dst_offset + i], actual); + } + + } + } + + return error; +} + +void allocate_mem_to_cores () { + int core_id = rt_core_id(); + + // Pre-allocate TOT_SIZE = 8 * CORE_SPACE: then we split this window to assign + // each core its available space for iDMA transfers + // pi_l1_malloc starts allocating from 0x10004008 in L1 + // pi_l2_malloc starts allocating from 0x1c000a60 in L2 + + if (core_id == 0) { + l1_addr[0] = (uint32_t) pi_l1_malloc(0, TOT_SIZE); + l1_dst_addr[0] = (uint32_t) pi_l1_malloc(0, TOT_SIZE); + l2_addr[0] = (uint32_t) pi_l2_malloc(TOT_SIZE); + } + + // The following synch_barrier is needed so that + // no core can assign its address range until the mallocs are executed + synch_barrier(); + + l1_addr[core_id] = l1_addr[0] + core_id * CORE_SPACE; + l1_dst_addr[core_id] = l1_dst_addr[0] + core_id * CORE_SPACE; + l2_addr[core_id] = l2_addr[0] + core_id * CORE_SPACE; + + if (core_id == 0) { + for (int i = 0; i < 8; i++) { + PRINTF ("Core %d: l1_addr[%d] = %8x \n", core_id, i, l1_addr[i]); + PRINTF ("Core %d: l1_dst_addr[%d] = %8x \n", core_id, i, l1_dst_addr[i]); + PRINTF ("Core %d: l2_addr[%d] = %8x \n", core_id, i, l2_addr[i]); + } + } + + // The following synch_barrier is needed so that + // no core can start executing until all address ranges have been assigned + synch_barrier(); + +} + +void free_allocated_memory () { + + synch_barrier(); + // Only Core 0 takes care of freeing the allocated memory, since it's the one + // allocated it at the beginning of the test + if (rt_core_id() == 0) { + pi_l1_free(0, l1_addr, TOT_SIZE); + pi_l1_free(0, l1_dst_addr, TOT_SIZE); + pi_l2_free(l2_addr, TOT_SIZE); + } +} + +int cluster_task () { + + int core_id = rt_core_id(); + + allocate_mem_to_cores(); + + transfer_2d transfer; + + #ifdef MULTI_CORE_P + // MULTI CORE PARALLEL MODE: each core uses the iDMA in a parallel manner + if (core_id == 0) { + PRINTF ("MULTI CORE PARALLEL MODE \n"); + } + + synch_barrier(); + for (int k = 0; k < TRANSFERS; k++) { + #ifdef QUICK_MODE + transfer = idma_presets[k]; + #else + transfer = params_2d[k]; + #endif + // L1 -> L2 + PRINTF ("Core[%d]: L1 -> L2 Transfer Parameters: Size: %d | Length: %d | Src_stride_2d: %d | Dst_stride_2d: %d \n", rt_core_id(), transfer.size_2d, transfer.length, transfer.src_stride_2d, transfer.dst_stride_2d); + errors[core_id] += test_idma_2D(core_id, transfer, 0, 0); + // L2 -> L1 + PRINTF ("Core[%d]: L2 -> L1 Transfer Parameters: Size: %d | Length: %d | Src_stride_2d: %d | Dst_stride_2d: %d \n", rt_core_id(), transfer.size_2d, transfer.length, transfer.src_stride_2d, transfer.dst_stride_2d); + errors[core_id] += test_idma_2D(core_id, transfer, 1, 0); + // L1 -> L1 + PRINTF ("Core[%d]: L1 -> L1 Transfer Parameters: Size: %d | Length: %d | Src_stride_2d: %d | Dst_stride_2d: %d \n", rt_core_id(), transfer.size_2d, transfer.length, transfer.src_stride_2d, transfer.dst_stride_2d); + errors[core_id] += test_idma_2D(core_id, transfer, 0, 1); + } + synch_barrier(); + + #elif MULTI_CORE_S + // MULTI CORE SERIAL MODE: each core uses the iDMA in a serial manner + if (core_id == 0) { + PRINTF ("MULTI CORE SERIAL MODE \n"); + } + for (int i = 0; i < 8; i++) { + if (core_id == i) { + for (int k = 0; k < TRANSFERS; k++) { + #ifdef QUICK_MODE + transfer = idma_presets[k]; + #else + transfer = params_2d[k]; + #endif + // L1 -> L2 + PRINTF ("Core[%d]: L1 -> L2 Transfer Parameters: Size: %d | Length: %d | Src_stride_2d: %d | Dst_stride_2d: %d \n", rt_core_id(), transfer.size_2d, transfer.length, transfer.src_stride_2d, transfer.dst_stride_2d); + errors[core_id] += test_idma_2D(core_id, transfer, 0, 0); + // L2 -> L1 + PRINTF ("Core[%d]: L2 -> L1 Transfer Parameters: Size: %d | Length: %d | Src_stride_2d: %d | Dst_stride_2d: %d \n", rt_core_id(), transfer.size_2d, transfer.length, transfer.src_stride_2d, transfer.dst_stride_2d); + errors[core_id] += test_idma_2D(core_id, transfer, 1, 0); + // L1 -> L1 + PRINTF ("Core[%d]: L1 -> L1 Transfer Parameters: Size: %d | Length: %d | Src_stride_2d: %d | Dst_stride_2d: %d \n", rt_core_id(), transfer.size_2d, transfer.length, transfer.src_stride_2d, transfer.dst_stride_2d); + errors[core_id] += test_idma_2D(core_id, transfer, 0, 1); + } + } + synch_barrier(); + } + #else + // SINGLE CORE MODE: just core 0 uses the iDMA + if (core_id == 0) { + PRINTF ("SINGLE CORE MODE \n"); + for (int k = 0; k < TRANSFERS; k++) { + #ifdef QUICK_MODE + transfer = idma_presets[k]; + #else + transfer = params_2d[k]; + #endif + // L1 -> L2 + PRINTF ("Core[%d]: L1 -> L2 Transfer Parameters: Size: %d | Length: %d | Src_stride_2d: %d | Dst_stride_2d: %d \n", rt_core_id(), transfer.size_2d, transfer.length, transfer.src_stride_2d, transfer.dst_stride_2d); + errors[core_id] += test_idma_2D(core_id, transfer, 0, 0); + // L2 -> L1 + PRINTF ("Core[%d]: L2 -> L1 Transfer Parameters: Size: %d | Length: %d | Src_stride_2d: %d | Dst_stride_2d: %d \n", rt_core_id(), transfer.size_2d, transfer.length, transfer.src_stride_2d, transfer.dst_stride_2d); + errors[core_id] += test_idma_2D(core_id, transfer, 1, 0); + // L1 -> L1 + PRINTF ("Core[%d]: L1 -> L1 Transfer Parameters: Size: %d | Length: %d | Src_stride_2d: %d | Dst_stride_2d: %d \n", rt_core_id(), transfer.size_2d, transfer.length, transfer.src_stride_2d, transfer.dst_stride_2d); + errors[core_id] += test_idma_2D(core_id, transfer, 0, 1); + } + } + #endif + + if (core_id == 0) { + for (int i = 0; i<8; i++) { + if (errors[i] == 0) { + PRINTF ("Core %d returned %d errors \n", i, errors[i]); + test_status --; + } + } + } + + free_allocated_memory(); + + return test_status; +} + +int main () { + int retval = 1; + #ifdef ARCHI_HAS_FC + PRINTF ("Fabric Controller calling cluster task \n"); + if (rt_cluster_id() != 0) + return bench_cluster_forward(0); + #endif + retval = cluster_task(); + + return retval; +} diff --git a/idma_tests/idma_multi_core_2d/idma_multi_core_2d.h b/idma_tests/idma_multi_core_2d/idma_multi_core_2d.h new file mode 100644 index 00000000..dd6d227a --- /dev/null +++ b/idma_tests/idma_multi_core_2d/idma_multi_core_2d.h @@ -0,0 +1,61 @@ +// Copyright 2022 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 +// +//Author: Andreas Kuster +// +//Description: Generated register defines for dma_frontend + +#include "pulp.h" +#include +#include +#include +#include +#include + +#include "idma_def_2d.h" +#include "idma_param_2d.h" +#include "idma_presets.h" + +#ifndef _DMA_FRONTEND_REG_DEFS_ +#define _DMA_FRONTEND_REG_DEFS_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define DMA_CONF_DECOUPLE 0 +#define DMA_CONF_DEBURST 0 +#define DMA_CONF_SERIALIZE 0 + +#define CORE_SPACE 2048 + +#ifdef QUICK_MODE +#define TRANSFERS 7 +#else +#define TRANSFERS NB_TRANSFERS +#endif + +#ifdef VERBOSE + #define PRINTF(...) printf(__VA_ARGS__) +#else + #define PRINTF(...) +#endif + +#ifdef CYCLE_COUNT + static inline void start_cycle_count () { perf_start(); } + static inline void stop_cycle_count () { perf_stop(); } + static inline void reset_cycle_count () { perf_reset(); } + static inline void print_perf() { PRINTF ("Performances: \n"); perf_print_all(); } +#else + static inline void start_cycle_count () { } + static inline void stop_cycle_count () { } + static inline void reset_cycle_count () { } + static inline void print_perf() { } +#endif + + +#ifdef __cplusplus +} // extern "C" +#endif +#endif // _DMA_FRONTEND_REG_DEFS_ diff --git a/idma_tests/idma_multi_core_2d/idma_param_2d.h b/idma_tests/idma_multi_core_2d/idma_param_2d.h new file mode 100644 index 00000000..cc9386cd --- /dev/null +++ b/idma_tests/idma_multi_core_2d/idma_param_2d.h @@ -0,0 +1,7 @@ +transfer_2d params_2d[] = { +{67, 2, 11, 4}, +{98, 2, 4, 8}, +{86, 4, 6, 5}, +{48, 3, 10, 9}, +{126, 4, 6, 14}, +}; diff --git a/idma_tests/idma_multi_core_2d/idma_presets.h b/idma_tests/idma_multi_core_2d/idma_presets.h new file mode 100644 index 00000000..ab7adeab --- /dev/null +++ b/idma_tests/idma_multi_core_2d/idma_presets.h @@ -0,0 +1,10 @@ + +transfer_2d idma_presets[] = { +{1, 1, 1, 1}, +{2, 2, 512, 512}, +{4, 2, 256, 256}, +{16, 8, 64, 64}, +{64, 8, 16, 16}, +{128, 8, 8, 8}, +{512, 2, 4, 4}, +}; diff --git a/idma_tests/idma_multi_core_3d/Makefile b/idma_tests/idma_multi_core_3d/Makefile new file mode 100644 index 00000000..ef03857d --- /dev/null +++ b/idma_tests/idma_multi_core_3d/Makefile @@ -0,0 +1,32 @@ +PULP_APP = test +TEST_SRCS ?= idma_multi_core_3d.c +PULP_APP_SRCS = $(TEST_SRCS) + +ifdef VERBOSE +PULP_CFLAGS += -DVERBOSE +endif + +ifdef CYCLE_COUNT +PULP_CFLAGS += -DCYCLE_COUNT +PULP_CFLAGS += -DVERBOSE +endif + +ifdef MULTI_CORE_P +PULP_CFLAGS += -DMULTI_CORE_P +endif + +ifdef MULTI_CORE_S +PULP_CFLAGS += -DMULTI_CORE_S +endif + +ifdef QUICK_MODE +PULP_CFLAGS += -DQUICK_MODE +endif + +PULP_CFLAGS += -O3 +stackSize = 4096 + +include $(PULP_SDK_HOME)/install/rules/pulp.mk + +stimuli: + python ../gen_stimuli.py 3D \ No newline at end of file diff --git a/idma_tests/idma_multi_core_3d/idma_def_3d.h b/idma_tests/idma_multi_core_3d/idma_def_3d.h new file mode 100644 index 00000000..cd7b0305 --- /dev/null +++ b/idma_tests/idma_multi_core_3d/idma_def_3d.h @@ -0,0 +1,12 @@ +#define NB_TRANSFERS 7 + +typedef struct { + unsigned int size_3d; + unsigned int length; + unsigned int src_stride_2d; + unsigned int dst_stride_2d; + unsigned int src_stride_3d; + unsigned int dst_stride_3d; + unsigned int num_reps_3d; +} transfer_3d; + diff --git a/idma_tests/idma_multi_core_3d/idma_multi_core_3d.c b/idma_tests/idma_multi_core_3d/idma_multi_core_3d.c new file mode 100644 index 00000000..a100baf9 --- /dev/null +++ b/idma_tests/idma_multi_core_3d/idma_multi_core_3d.c @@ -0,0 +1,274 @@ +#include "idma_multi_core_3d.h" + +#define TOT_SIZE 8 * CORE_SPACE + +int errors[8] = {0}; +int test_status = 8; + +uint32_t l1_addr[8] = {0}; +uint32_t l1_dst_addr[8] = {0}; +uint32_t l2_addr[8] = {0}; + +int test_idma_3D (int core_id, transfer_3d transfer, int ext2loc, int loc2loc) { + volatile uint8_t *src_ptr, *dst_ptr; + unsigned int offset_3d = 0; + int src_offset_2d = 0; + int dst_offset_2d = 0; + int src_offset_3d = 0; + int dst_offset_3d = 0; + + int error = 0; + + uint32_t src_stride_2d = transfer.src_stride_2d; + uint32_t dst_stride_2d = transfer.dst_stride_2d; + uint32_t src_stride_3d = transfer.src_stride_3d; + uint32_t dst_stride_3d = transfer.dst_stride_3d; + uint32_t size = transfer.size_3d; + uint32_t length = transfer.length; + uint32_t num_reps = size/length; + uint32_t num_reps_3d = transfer.num_reps_3d; + + if (loc2loc == 1) { + // L1 to L1 transfer + src_ptr = (uint8_t*) l1_addr[core_id]; + dst_ptr = (uint8_t*) l1_dst_addr[core_id]; + } else if (ext2loc == 1) { + // L2 to L1 transfer + src_ptr = (uint8_t*) l2_addr[core_id]; + dst_ptr = (uint8_t*) l1_addr[core_id]; + } else { + // L1 to L2 transfer + src_ptr = (uint8_t*) l1_addr[core_id]; + dst_ptr = (uint8_t*) l2_addr[core_id]; + } + + // Fill source region with test data + for (int j = 0; j < num_reps_3d; j++) { + for (int q = 0; q < num_reps; q++) { + for (int i = 0; i < length; i++) { + src_ptr[i+src_offset_2d+src_offset_3d] = (uint8_t)(i & 0xFF); + dst_ptr[i+dst_offset_2d+dst_offset_3d] = (uint8_t)((i-1) & 0xFF); + } + src_offset_2d += src_stride_2d; + dst_offset_2d += dst_stride_2d; + } + src_offset_2d = 0; + dst_offset_2d = 0; + src_offset_3d += (num_reps-1) * src_stride_2d + src_stride_3d; + dst_offset_3d += (num_reps-1) * dst_stride_2d + dst_stride_3d; + } + + if (loc2loc == 1) { + reset_cycle_count(); + start_cycle_count(); + plp_cl_dma_wait_toL1(pulp_cl_idma_L1ToL1_3d((unsigned int)src_ptr, (unsigned int)dst_ptr, length, src_stride_2d, dst_stride_2d, num_reps, + src_stride_3d, dst_stride_3d, num_reps_3d)); + stop_cycle_count(); + } else if (ext2loc == 1) { + reset_cycle_count(); + start_cycle_count(); + plp_cl_dma_wait_toL1(pulp_cl_idma_L2ToL1_3d((unsigned int)src_ptr, (unsigned int)dst_ptr, length, src_stride_2d, dst_stride_2d, num_reps, + src_stride_3d, dst_stride_3d, num_reps_3d)); + stop_cycle_count(); + } else { + reset_cycle_count(); + start_cycle_count(); + plp_cl_dma_wait_toL2(pulp_cl_idma_L1ToL2_3d((unsigned int)src_ptr, (unsigned int)dst_ptr, length, src_stride_2d, dst_stride_2d, num_reps, + src_stride_3d, dst_stride_3d, num_reps_3d)); + stop_cycle_count(); + } + + print_perf(); + + // Check the results + src_offset_2d = 0; + dst_offset_2d = 0; + src_offset_3d = 0; + dst_offset_3d = 0; + + for (int rep_3d = 0; rep_3d < num_reps_3d; rep_3d ++) { + for (unsigned int rep = 0; rep < num_reps; rep++) { + for (unsigned int i = 0; i < length; i++) { + uint8_t expected = src_ptr[src_offset_2d + src_offset_3d + i]; + uint8_t actual = dst_ptr[dst_offset_2d + dst_offset_3d + i]; + + if (expected != actual) { + PRINTF ("Core[%d]: ERROR: expected @%8x[%d] = %8x vs actual @%8x[%d] = %8x \n", rt_core_id(), &src_ptr[src_offset_2d + src_offset_3d + i], src_offset_2d + src_offset_3d + i, + expected, &dst_ptr[dst_offset_2d + dst_offset_3d + i], dst_offset_2d + dst_offset_3d + i, actual); + error++; + } + } + src_offset_2d += src_stride_2d; + dst_offset_2d += dst_stride_2d; + } + src_offset_2d = 0; + dst_offset_2d = 0; + src_offset_3d += (num_reps-1) * src_stride_2d + src_stride_3d; + dst_offset_3d += (num_reps-1) * dst_stride_2d + dst_stride_3d; + } + + return error; +} + +void allocate_mem_to_cores () { + int core_id = rt_core_id(); + + // Pre-allocate TOT_SIZE = 8 * CORE_SPACE: then we split this window to assign + // each core its available space for iDMA transfers + // pi_l1_malloc starts allocating from 0x10004008 in L1 + // pi_l2_malloc starts allocating from 0x1c000a60 in L2 + + if (core_id == 0) { + l1_addr[0] = (uint32_t) pi_l1_malloc(0, TOT_SIZE); + l1_dst_addr[0] = (uint32_t) pi_l1_malloc(0, TOT_SIZE); + l2_addr[0] = (uint32_t) pi_l2_malloc(TOT_SIZE); + } + + // The following synch_barrier is needed so that + // no core can assign its address range until the mallocs are executed + synch_barrier(); + + l1_addr[core_id] = l1_addr[0] + core_id * CORE_SPACE; + l1_dst_addr[core_id] = l1_dst_addr[0] + core_id * CORE_SPACE; + l2_addr[core_id] = l2_addr[0] + core_id * CORE_SPACE; + + if (core_id == 0) { + for (int i = 0; i < 8; i++) { + PRINTF ("Core %d: l1_addr[%d] = %8x \n", core_id, i, l1_addr[i]); + PRINTF ("Core %d: l1_dst_addr[%d] = %8x \n", core_id, i, l1_dst_addr[i]); + PRINTF ("Core %d: l2_addr[%d] = %8x \n", core_id, i, l2_addr[i]); + } + } + + // The following synch_barrier is needed so that + // no core can start executing until all address ranges have been assigned + synch_barrier(); + +} + +void free_allocated_memory () { + + synch_barrier(); + // Only Core 0 takes care of freeing the allocated memory, since it's the one + // allocated it at the beginning of the test + if (rt_core_id() == 0) { + pi_l1_free(0, l1_addr, TOT_SIZE); + pi_l1_free(0, l1_dst_addr, TOT_SIZE); + pi_l2_free(l2_addr, TOT_SIZE); + } +} + +int cluster_task () { + + int core_id = rt_core_id(); + + allocate_mem_to_cores(); + + transfer_3d transfer; + + #ifdef MULTI_CORE_P + // MULTI CORE PARALLEL MODE: each core uses the iDMA in a parallel manner + if (core_id == 0) { + PRINTF ("MULTI CORE PARALLEL MODE \n"); + } + + synch_barrier(); + for (int k = 0; k < TRANSFERS; k++) { + #ifdef QUICK_MODE + transfer = idma_presets[k]; + #else + transfer = params_3d[k]; + #endif + // L1 -> L2 + PRINTF ("Core[%d]: L1 -> L2 Transfer Parameters: Size: %d | Length: %d | Src_stride_2d: %d | Dst_stride_2d: %d | Src_stride_3d: %d | Dst_stride_3d: %d | Num_reps_3d: %d\n", + rt_core_id(), transfer.size_3d, transfer.length, transfer.src_stride_2d, transfer.dst_stride_2d, transfer.src_stride_3d, transfer.dst_stride_3d,transfer.num_reps_3d); + errors[core_id] += test_idma_3D(core_id, transfer, 0, 0); + // L2 -> L1 + PRINTF ("Core[%d]: L2 -> L1 Transfer Parameters: Size: %d | Length: %d | Src_stride_2d: %d | Dst_stride_2d: %d | Src_stride_3d: %d | Dst_stride_3d: %d | Num_reps_3d: %d\n", + rt_core_id(), transfer.size_3d, transfer.length, transfer.src_stride_2d, transfer.dst_stride_2d, transfer.src_stride_3d, transfer.dst_stride_3d,transfer.num_reps_3d); + errors[core_id] += test_idma_3D(core_id, transfer, 1, 0); + // L1 -> L1 transfer + PRINTF ("Core[%d]: L1 -> L1 Transfer Parameters: Size: %d | Length: %d | Src_stride_2d: %d | Dst_stride_2d: %d | Src_stride_3d: %d | Dst_stride_3d: %d | Num_reps_3d: %d\n", + rt_core_id(), transfer.size_3d, transfer.length, transfer.src_stride_2d, transfer.dst_stride_2d, transfer.src_stride_3d, transfer.dst_stride_3d,transfer.num_reps_3d); + errors[core_id] += test_idma_3D(core_id, transfer, 0, 1); + } + synch_barrier(); + + #elif MULTI_CORE_S + // MULTI CORE SERIAL MODE: each core uses the iDMA in a serial manner + if (core_id == 0) { + PRINTF ("MULTI CORE SERIAL MODE \n"); + } + for (int i = 0; i < 8; i++) { + if (core_id == i) { + for (int k = 0; k < TRANSFERS; k++) { + #ifdef QUICK_MODE + transfer = idma_presets[k]; + #else + transfer = params_3d[k]; + #endif + // L1 -> L2 + PRINTF ("Core[%d]: L1 -> L2 Transfer Parameters: Size: %d | Length: %d | Src_stride_2d: %d | Dst_stride_2d: %d | Src_stride_3d: %d | Dst_stride_3d: %d | Num_reps_3d: %d\n", + rt_core_id(), transfer.size_3d, transfer.length, transfer.src_stride_2d, transfer.dst_stride_2d, transfer.src_stride_3d, transfer.dst_stride_3d,transfer.num_reps_3d); + errors[core_id] += test_idma_3D(core_id, transfer, 0, 0); + // L2 -> L1 + PRINTF ("Core[%d]: L2 -> L1 Transfer Parameters: Size: %d | Length: %d | Src_stride_2d: %d | Dst_stride_2d: %d | Src_stride_3d: %d | Dst_stride_3d: %d | Num_reps_3d: %d\n", + rt_core_id(), transfer.size_3d, transfer.length, transfer.src_stride_2d, transfer.dst_stride_2d, transfer.src_stride_3d, transfer.dst_stride_3d,transfer.num_reps_3d); + errors[core_id] += test_idma_3D(core_id, transfer, 1, 0); + // L1 -> L1 transfer + PRINTF ("Core[%d]: L1 -> L1 Transfer Parameters: Size: %d | Length: %d | Src_stride_2d: %d | Dst_stride_2d: %d | Src_stride_3d: %d | Dst_stride_3d: %d | Num_reps_3d: %d\n", + rt_core_id(), transfer.size_3d, transfer.length, transfer.src_stride_2d, transfer.dst_stride_2d, transfer.src_stride_3d, transfer.dst_stride_3d,transfer.num_reps_3d); + errors[core_id] += test_idma_3D(core_id, transfer, 0, 1); + } + } + synch_barrier(); + } + #else + if (core_id == 0) { + for (int k = 0; k < TRANSFERS; k++) { + #ifdef QUICK_MODE + transfer = idma_presets[k]; + #else + transfer = params_3d[k]; + #endif + // L1 -> L2 + PRINTF ("Core[%d]: L1 -> L2 Transfer Parameters: Size: %d | Length: %d | Src_stride_2d: %d | Dst_stride_2d: %d | Src_stride_3d: %d | Dst_stride_3d: %d | Num_reps_3d: %d\n", + rt_core_id(), transfer.size_3d, transfer.length, transfer.src_stride_2d, transfer.dst_stride_2d, transfer.src_stride_3d, transfer.dst_stride_3d,transfer.num_reps_3d); + errors[core_id] += test_idma_3D(core_id, transfer, 0, 0); + // L2 -> L1 + PRINTF ("Core[%d]: L2 -> L1 Transfer Parameters: Size: %d | Length: %d | Src_stride_2d: %d | Dst_stride_2d: %d | Src_stride_3d: %d | Dst_stride_3d: %d | Num_reps_3d: %d\n", + rt_core_id(), transfer.size_3d, transfer.length, transfer.src_stride_2d, transfer.dst_stride_2d, transfer.src_stride_3d, transfer.dst_stride_3d,transfer.num_reps_3d); + errors[core_id] += test_idma_3D(core_id, transfer, 1, 0); + // L1 -> L1 + PRINTF ("Core[%d]: L1 -> L1 Transfer Parameters: Size: %d | Length: %d | Src_stride_2d: %d | Dst_stride_2d: %d | Src_stride_3d: %d | Dst_stride_3d: %d | Num_reps_3d: %d\n", + rt_core_id(), transfer.size_3d, transfer.length, transfer.src_stride_2d, transfer.dst_stride_2d, transfer.src_stride_3d, transfer.dst_stride_3d,transfer.num_reps_3d); + errors[core_id] += test_idma_3D(core_id, transfer, 0, 1); + } + } + #endif + + if (core_id == 0) { + for (int i = 0; i<8; i++) { + if (errors[i] == 0) { + PRINTF ("Core %d returned %d errors \n", i, errors[i]); + test_status--; + } + } + } + + free_allocated_memory(); + + return test_status; +} + +int main () { + int retval = 1; + #ifdef ARCHI_HAS_FC + PRINTF ("Fabric Controller calling cluster task \n"); + if (rt_cluster_id() != 0) + return bench_cluster_forward(0); + #endif + retval = cluster_task(); + + return retval; +} diff --git a/idma_tests/idma_multi_core_3d/idma_multi_core_3d.h b/idma_tests/idma_multi_core_3d/idma_multi_core_3d.h new file mode 100644 index 00000000..461ef9d4 --- /dev/null +++ b/idma_tests/idma_multi_core_3d/idma_multi_core_3d.h @@ -0,0 +1,61 @@ +// Copyright 2022 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 +// +//Author: Andreas Kuster +// +//Description: Generated register defines for dma_frontend + +#include "pulp.h" +#include +#include +#include +#include +#include + +#include "idma_def_3d.h" +#include "idma_param_3d.h" +#include "idma_presets.h" + +#ifndef _DMA_FRONTEND_REG_DEFS_ +#define _DMA_FRONTEND_REG_DEFS_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define DMA_CONF_DECOUPLE 0 +#define DMA_CONF_DEBURST 0 +#define DMA_CONF_SERIALIZE 0 + +#define CORE_SPACE 2048 + +#ifdef QUICK_MODE +#define TRANSFERS 9 +#else +#define TRANSFERS NB_TRANSFERS +#endif + +#ifdef VERBOSE + #define PRINTF(...) printf(__VA_ARGS__) +#else + #define PRINTF(...) +#endif + +#ifdef CYCLE_COUNT + static inline void start_cycle_count () { perf_start(); } + static inline void stop_cycle_count () { perf_stop(); } + static inline void reset_cycle_count () { perf_reset(); } + static inline void print_perf() { PRINTF ("Performances: \n"); perf_print_all(); } +#else + static inline void start_cycle_count () { } + static inline void stop_cycle_count () { } + static inline void reset_cycle_count () { } + static inline void print_perf() { } +#endif + + +#ifdef __cplusplus +} // extern "C" +#endif +#endif // _DMA_FRONTEND_REG_DEFS_ diff --git a/idma_tests/idma_multi_core_3d/idma_param_3d.h b/idma_tests/idma_multi_core_3d/idma_param_3d.h new file mode 100644 index 00000000..d1e14a58 --- /dev/null +++ b/idma_tests/idma_multi_core_3d/idma_param_3d.h @@ -0,0 +1,10 @@ +transfer_3d params_3d[] = { +{47, 2, 11, 4, 7, 11, 4}, +{134, 9, 12, 18, 16, 13, 4}, +{54, 10, 13, 11, 17, 18, 3}, +{103, 10, 11, 15, 20, 11, 4}, +{45, 10, 16, 20, 15, 17, 1}, +{40, 10, 12, 15, 16, 12, 1}, +{79, 8, 11, 17, 17, 9, 4}, +}; + diff --git a/idma_tests/idma_multi_core_3d/idma_presets.h b/idma_tests/idma_multi_core_3d/idma_presets.h new file mode 100644 index 00000000..8c88b24a --- /dev/null +++ b/idma_tests/idma_multi_core_3d/idma_presets.h @@ -0,0 +1,15 @@ +// Parameters are declared in this order: +// size, length, src_stride_2d, dst_stride_2d, src_stride_3d, dst_stride_3d, num_reps_3d + +transfer_3d idma_presets[] = { +{1, 1, 1, 1, 1, 1, 1}, +{2, 8, 8, 8, 8, 8, 2}, +{3, 8, 8, 8, 8, 8, 4}, +{4, 8, 16, 16, 16, 16, 8}, +{8, 8, 32, 32, 32, 32, 8}, +{16, 8, 16, 16, 16, 16, 8}, +{32, 2, 2, 2, 2, 2, 2}, +{64, 4, 4, 4, 4, 4, 2}, +{128, 4, 4, 4, 4, 4, 4}, +}; + diff --git a/reliability_tests/dmr_matmul/pulp_inject_fault.tcl b/reliability_tests/dmr_matmul/pulp_inject_fault.tcl index 857d373b..998b429a 100644 --- a/reliability_tests/dmr_matmul/pulp_inject_fault.tcl +++ b/reliability_tests/dmr_matmul/pulp_inject_fault.tcl @@ -17,8 +17,8 @@ set log_injections 1 set seed 12345 set print_statistics 1 -set inject_start_time 250856000000ps -set inject_stop_time 413000000000ps +set inject_start_time 54000ns +set inject_stop_time 68000ns set injection_clock "pulp_cluster_tb/cluster_i/clk_i" set injection_clock_trigger 0 set fault_period 250 diff --git a/reliability_tests/ecc_test/Makefile b/reliability_tests/ecc_test/Makefile index d19f2869..50b0a4b3 100755 --- a/reliability_tests/ecc_test/Makefile +++ b/reliability_tests/ecc_test/Makefile @@ -10,6 +10,8 @@ endif ifeq ($(multi_bit_upset),1) export MULTI_BIT_UPSET=1 +else + export MULTI_BIT_UPSET=0 endif include $(PULP_SDK_HOME)/install/rules/pulp.mk diff --git a/reliability_tests/ecc_test/pulp_inject_fault.tcl b/reliability_tests/ecc_test/pulp_inject_fault.tcl index 45cef477..f6050c1e 100644 --- a/reliability_tests/ecc_test/pulp_inject_fault.tcl +++ b/reliability_tests/ecc_test/pulp_inject_fault.tcl @@ -17,8 +17,8 @@ set log_injections 1 set seed 12345 set print_statistics 1 -set inject_start_time 110584000000ps -set inject_stop_time 203880000000ps +set inject_start_time 27646000ps +set inject_stop_time 50970000ps set injection_clock "pulp_cluster_tb/cluster_i/clk_i" set injection_clock_trigger 0 set fault_period 100