diff --git a/tasks/task5_1/Makefile b/tasks/task5_1/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..eb4010cdecf4b6483ac5f938578020b7df62c491 --- /dev/null +++ b/tasks/task5_1/Makefile @@ -0,0 +1,27 @@ +# name of your application +APPLICATION = blinky + +# If no BOARD is found in the environment, use this default: +BOARD ?= nucleo-f401re + +# This has to be the absolute path to the RIOT base directory: +RIOTBASE ?= $(CURDIR)/../../deps/RIOT + +# Comment this out to disable code in RIOT that does safety checking +# which is not needed in a production environment but helps in the +# development process: +DEVELHELP ?= 1 + +# Change this to 0 show compiler invocation lines by default: +QUIET ?= 1 + +# Use a peripheral timer for the delay, if available +FEATURES_REQUIRED += periph_timer +FEATURES_REQUIRED += periph_gpio_irq +USEMODULE += ztimer +USEMODULE += ztimer_usec +USEMODULE += periph_gpio + +CFLAGS += -DMAIN_HAS_NOARGC -w + +include $(RIOTBASE)/Makefile.include diff --git a/tasks/task5_1/core_list_join.c b/tasks/task5_1/core_list_join.c new file mode 100644 index 0000000000000000000000000000000000000000..5d76b4d858ac47a2017219a92a43105b31afecde --- /dev/null +++ b/tasks/task5_1/core_list_join.c @@ -0,0 +1,595 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ + +#include "coremark.h" +/* +Topic: Description + Benchmark using a linked list. + + Linked list is a common data structure used in many applications. + + For our purposes, this will excercise the memory units of the processor. + In particular, usage of the list pointers to find and alter data. + + We are not using Malloc since some platforms do not support this +library. + + Instead, the memory block being passed in is used to create a list, + and the benchmark takes care not to add more items then can be + accommodated by the memory block. The porting layer will make sure + that we have a valid memory block. + + All operations are done in place, without using any extra memory. + + The list itself contains list pointers and pointers to data items. + Data items contain the following: + + idx - An index that captures the initial order of the list. + data - Variable data initialized based on the input parameters. The 16b +are divided as follows: o Upper 8b are backup of original data. o Bit 7 +indicates if the lower 7 bits are to be used as is or calculated. o Bits 0-2 +indicate type of operation to perform to get a 7b value. o Bits 3-6 provide +input for the operation. + +*/ + +/* local functions */ + +list_head *core_list_find(list_head *list, list_data *info); +list_head *core_list_reverse(list_head *list); +list_head *core_list_remove(list_head *item); +list_head *core_list_undo_remove(list_head *item_removed, + list_head *item_modified); +list_head *core_list_insert_new(list_head * insert_point, + list_data * info, + list_head **memblock, + list_data **datablock, + list_head * memblock_end, + list_data * datablock_end); +typedef ee_s32 (*list_cmp)(list_data *a, list_data *b, core_results *res); +list_head *core_list_mergesort(list_head * list, + list_cmp cmp, + core_results *res); + +ee_s16 +calc_func(ee_s16 *pdata, core_results *res) +{ + ee_s16 data = *pdata; + ee_s16 retval; + ee_u8 optype + = (data >> 7) + & 1; /* bit 7 indicates if the function result has been cached */ + if (optype) /* if cached, use cache */ + return (data & 0x007f); + else + { /* otherwise calculate and cache the result */ + ee_s16 flag = data & 0x7; /* bits 0-2 is type of function to perform */ + ee_s16 dtype + = ((data >> 3) + & 0xf); /* bits 3-6 is specific data for the operation */ + dtype |= dtype << 4; /* replicate the lower 4 bits to get an 8b value */ + switch (flag) + { + case 0: + if (dtype < 0x22) /* set min period for bit corruption */ + dtype = 0x22; + retval = core_bench_state(res->size, + res->memblock[3], + res->seed1, + res->seed2, + dtype, + res->crc); + if (res->crcstate == 0) + res->crcstate = retval; + break; + case 1: + retval = core_bench_matrix(&(res->mat), dtype, res->crc); + if (res->crcmatrix == 0) + res->crcmatrix = retval; + break; + default: + retval = data; + break; + } + res->crc = crcu16(retval, res->crc); + retval &= 0x007f; + *pdata = (data & 0xff00) | 0x0080 | retval; /* cache the result */ + return retval; + } +} +/* Function: cmp_complex + Compare the data item in a list cell. + + Can be used by mergesort. +*/ +ee_s32 +cmp_complex(list_data *a, list_data *b, core_results *res) +{ + ee_s16 val1 = calc_func(&(a->data16), res); + ee_s16 val2 = calc_func(&(b->data16), res); + return val1 - val2; +} + +/* Function: cmp_idx + Compare the idx item in a list cell, and regen the data. + + Can be used by mergesort. +*/ +ee_s32 +cmp_idx(list_data *a, list_data *b, core_results *res) +{ + if (res == NULL) + { + a->data16 = (a->data16 & 0xff00) | (0x00ff & (a->data16 >> 8)); + b->data16 = (b->data16 & 0xff00) | (0x00ff & (b->data16 >> 8)); + } + return a->idx - b->idx; +} + +void +copy_info(list_data *to, list_data *from) +{ + to->data16 = from->data16; + to->idx = from->idx; +} + +/* Benchmark for linked list: + - Try to find multiple data items. + - List sort + - Operate on data from list (crc) + - Single remove/reinsert + * At the end of this function, the list is back to original state +*/ +ee_u16 +core_bench_list(core_results *res, ee_s16 finder_idx) +{ + ee_u16 retval = 0; + ee_u16 found = 0, missed = 0; + list_head *list = res->list; + ee_s16 find_num = res->seed3; + list_head *this_find; + list_head *finder, *remover; + list_data info = {0}; + ee_s16 i; + + info.idx = finder_idx; + /* find <find_num> values in the list, and change the list each time + * (reverse and cache if value found) */ + for (i = 0; i < find_num; i++) + { + info.data16 = (i & 0xff); + this_find = core_list_find(list, &info); + list = core_list_reverse(list); + if (this_find == NULL) + { + missed++; + retval += (list->next->info->data16 >> 8) & 1; + } + else + { + found++; + if (this_find->info->data16 & 0x1) /* use found value */ + retval += (this_find->info->data16 >> 9) & 1; + /* and cache next item at the head of the list (if any) */ + if (this_find->next != NULL) + { + finder = this_find->next; + this_find->next = finder->next; + finder->next = list->next; + list->next = finder; + } + } + if (info.idx >= 0) + info.idx++; +#if CORE_DEBUG + ee_printf("List find %d: [%d,%d,%d]\n", i, retval, missed, found); +#endif + } + retval += found * 4 - missed; + /* sort the list by data content and remove one item*/ + if (finder_idx > 0) + list = core_list_mergesort(list, cmp_complex, res); + remover = core_list_remove(list->next); + /* CRC data content of list from location of index N forward, and then undo + * remove */ + finder = core_list_find(list, &info); + if (!finder) + finder = list->next; + while (finder) + { + retval = crc16(list->info->data16, retval); + finder = finder->next; + } +#if CORE_DEBUG + ee_printf("List sort 1: %04x\n", retval); +#endif + remover = core_list_undo_remove(remover, list->next); + /* sort the list by index, in effect returning the list to original state */ + list = core_list_mergesort(list, cmp_idx, NULL); + /* CRC data content of list */ + finder = list->next; + while (finder) + { + retval = crc16(list->info->data16, retval); + finder = finder->next; + } +#if CORE_DEBUG + ee_printf("List sort 2: %04x\n", retval); +#endif + return retval; +} +/* Function: core_list_init + Initialize list with data. + + Parameters: + blksize - Size of memory to be initialized. + memblock - Pointer to memory block. + seed - Actual values chosen depend on the seed parameter. + The seed parameter MUST be supplied from a source that cannot be + determined at compile time + + Returns: + Pointer to the head of the list. + +*/ +list_head * +core_list_init(ee_u32 blksize, list_head *memblock, ee_s16 seed) +{ + /* calculated pointers for the list */ + ee_u32 per_item = 16 + sizeof(struct list_data_s); + ee_u32 size = (blksize / per_item) + - 2; /* to accommodate systems with 64b pointers, and make sure + same code is executed, set max list elements */ + list_head *memblock_end = memblock + size; + list_data *datablock = (list_data *)(memblock_end); + list_data *datablock_end = datablock + size; + /* some useful variables */ + ee_u32 i; + list_head *finder, *list = memblock; + list_data info; + + /* create a fake items for the list head and tail */ + list->next = NULL; + list->info = datablock; + list->info->idx = 0x0000; + list->info->data16 = (ee_s16)0x8080; + memblock++; + datablock++; + info.idx = 0x7fff; + info.data16 = (ee_s16)0xffff; + core_list_insert_new( + list, &info, &memblock, &datablock, memblock_end, datablock_end); + + /* then insert size items */ + for (i = 0; i < size; i++) + { + ee_u16 datpat = ((ee_u16)(seed ^ i) & 0xf); + ee_u16 dat + = (datpat << 3) | (i & 0x7); /* alternate between algorithms */ + info.data16 = (dat << 8) | dat; /* fill the data with actual data and + upper bits with rebuild value */ + core_list_insert_new( + list, &info, &memblock, &datablock, memblock_end, datablock_end); + } + /* and now index the list so we know initial seed order of the list */ + finder = list->next; + i = 1; + while (finder->next != NULL) + { + if (i < size / 5) /* first 20% of the list in order */ + finder->info->idx = i++; + else + { + ee_u16 pat = (ee_u16)(i++ ^ seed); /* get a pseudo random number */ + finder->info->idx = 0x3fff + & (((i & 0x07) << 8) + | pat); /* make sure the mixed items end up + after the ones in sequence */ + } + finder = finder->next; + } + list = core_list_mergesort(list, cmp_idx, NULL); +#if CORE_DEBUG + ee_printf("Initialized list:\n"); + finder = list; + while (finder) + { + ee_printf( + "[%04x,%04x]", finder->info->idx, (ee_u16)finder->info->data16); + finder = finder->next; + } + ee_printf("\n"); +#endif + return list; +} + +/* Function: core_list_insert + Insert an item to the list + + Parameters: + insert_point - where to insert the item. + info - data for the cell. + memblock - pointer for the list header + datablock - pointer for the list data + memblock_end - end of region for list headers + datablock_end - end of region for list data + + Returns: + Pointer to new item. +*/ +list_head * +core_list_insert_new(list_head * insert_point, + list_data * info, + list_head **memblock, + list_data **datablock, + list_head * memblock_end, + list_data * datablock_end) +{ + list_head *newitem; + + if ((*memblock + 1) >= memblock_end) + return NULL; + if ((*datablock + 1) >= datablock_end) + return NULL; + + newitem = *memblock; + (*memblock)++; + newitem->next = insert_point->next; + insert_point->next = newitem; + + newitem->info = *datablock; + (*datablock)++; + copy_info(newitem->info, info); + + return newitem; +} + +/* Function: core_list_remove + Remove an item from the list. + + Operation: + For a singly linked list, remove by copying the data from the next item + over to the current cell, and unlinking the next item. + + Note: + since there is always a fake item at the end of the list, no need to + check for NULL. + + Returns: + Removed item. +*/ +list_head * +core_list_remove(list_head *item) +{ + list_data *tmp; + list_head *ret = item->next; + /* swap data pointers */ + tmp = item->info; + item->info = ret->info; + ret->info = tmp; + /* and eliminate item */ + item->next = item->next->next; + ret->next = NULL; + return ret; +} + +/* Function: core_list_undo_remove + Undo a remove operation. + + Operation: + Since we want each iteration of the benchmark to be exactly the same, + we need to be able to undo a remove. + Link the removed item back into the list, and switch the info items. + + Parameters: + item_removed - Return value from the <core_list_remove> + item_modified - List item that was modified during <core_list_remove> + + Returns: + The item that was linked back to the list. + +*/ +list_head * +core_list_undo_remove(list_head *item_removed, list_head *item_modified) +{ + list_data *tmp; + /* swap data pointers */ + tmp = item_removed->info; + item_removed->info = item_modified->info; + item_modified->info = tmp; + /* and insert item */ + item_removed->next = item_modified->next; + item_modified->next = item_removed; + return item_removed; +} + +/* Function: core_list_find + Find an item in the list + + Operation: + Find an item by idx (if not 0) or specific data value + + Parameters: + list - list head + info - idx or data to find + + Returns: + Found item, or NULL if not found. +*/ +list_head * +core_list_find(list_head *list, list_data *info) +{ + if (info->idx >= 0) + { + while (list && (list->info->idx != info->idx)) + list = list->next; + return list; + } + else + { + while (list && ((list->info->data16 & 0xff) != info->data16)) + list = list->next; + return list; + } +} +/* Function: core_list_reverse + Reverse a list + + Operation: + Rearrange the pointers so the list is reversed. + + Parameters: + list - list head + info - idx or data to find + + Returns: + Found item, or NULL if not found. +*/ + +list_head * +core_list_reverse(list_head *list) +{ + list_head *next = NULL, *tmp; + while (list) + { + tmp = list->next; + list->next = next; + next = list; + list = tmp; + } + return next; +} +/* Function: core_list_mergesort + Sort the list in place without recursion. + + Description: + Use mergesort, as for linked list this is a realistic solution. + Also, since this is aimed at embedded, care was taken to use iterative + rather then recursive algorithm. The sort can either return the list to + original order (by idx) , or use the data item to invoke other other + algorithms and change the order of the list. + + Parameters: + list - list to be sorted. + cmp - cmp function to use + + Returns: + New head of the list. + + Note: + We have a special header for the list that will always be first, + but the algorithm could theoretically modify where the list starts. + + */ +list_head * +core_list_mergesort(list_head *list, list_cmp cmp, core_results *res) +{ + list_head *p, *q, *e, *tail; + ee_s32 insize, nmerges, psize, qsize, i; + + insize = 1; + + while (1) + { + p = list; + list = NULL; + tail = NULL; + + nmerges = 0; /* count number of merges we do in this pass */ + + while (p) + { + nmerges++; /* there exists a merge to be done */ + /* step `insize' places along from p */ + q = p; + psize = 0; + for (i = 0; i < insize; i++) + { + psize++; + q = q->next; + if (!q) + break; + } + + /* if q hasn't fallen off end, we have two lists to merge */ + qsize = insize; + + /* now we have two lists; merge them */ + while (psize > 0 || (qsize > 0 && q)) + { + + /* decide whether next element of merge comes from p or q */ + if (psize == 0) + { + /* p is empty; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + else if (qsize == 0 || !q) + { + /* q is empty; e must come from p. */ + e = p; + p = p->next; + psize--; + } + else if (cmp(p->info, q->info, res) <= 0) + { + /* First element of p is lower (or same); e must come from + * p. */ + e = p; + p = p->next; + psize--; + } + else + { + /* First element of q is lower; e must come from q. */ + e = q; + q = q->next; + qsize--; + } + + /* add the next element to the merged list */ + if (tail) + { + tail->next = e; + } + else + { + list = e; + } + tail = e; + } + + /* now p has stepped `insize' places along, and q has too */ + p = q; + } + + tail->next = NULL; + + /* If we have done only one merge, we're finished. */ + if (nmerges <= 1) /* allow for nmerges==0, the empty list case */ + return list; + + /* Otherwise repeat, merging lists twice the size */ + insize *= 2; + } +#if COMPILER_REQUIRES_SORT_RETURN + return list; +#endif +} diff --git a/tasks/task5_1/core_main.c b/tasks/task5_1/core_main.c new file mode 100644 index 0000000000000000000000000000000000000000..16635835d818c806afac41635a947406e4cdcad3 --- /dev/null +++ b/tasks/task5_1/core_main.c @@ -0,0 +1,394 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ + +/* File: core_main.c + This file contains the framework to acquire a block of memory, seed + initial parameters, tun t he benchmark and report the results. +*/ +#include "coremark.h" + +/* Function: iterate + Run the benchmark for a specified number of iterations. + + Operation: + For each type of benchmarked algorithm: + a - Initialize the data block for the algorithm. + b - Execute the algorithm N times. + + Returns: + NULL. +*/ +static ee_u16 list_known_crc[] = {(ee_u16)0xd4b0, (ee_u16)0x3340, + (ee_u16)0x6a79, (ee_u16)0xe714, + (ee_u16)0xe3c1}; +static ee_u16 matrix_known_crc[] = {(ee_u16)0xbe52, (ee_u16)0x1199, + (ee_u16)0x5608, (ee_u16)0x1fd7, + (ee_u16)0x0747}; +static ee_u16 state_known_crc[] = {(ee_u16)0x5e47, (ee_u16)0x39bf, + (ee_u16)0xe5a4, (ee_u16)0x8e3a, + (ee_u16)0x8d84}; +void *iterate(void *pres) { + ee_u32 i; + ee_u16 crc; + core_results *res = (core_results *)pres; + ee_u32 iterations = res->iterations; + res->crc = 0; + res->crclist = 0; + res->crcmatrix = 0; + res->crcstate = 0; + + for (i = 0; i < iterations; i++) { + crc = core_bench_list(res, 1); + res->crc = crcu16(crc, res->crc); + crc = core_bench_list(res, -1); + res->crc = crcu16(crc, res->crc); + if (i == 0) + res->crclist = res->crc; + } + return NULL; +} + +#if (SEED_METHOD == SEED_ARG) +ee_s32 get_seed_args(int i, int argc, char *argv[]); +#define get_seed(x) (ee_s16) get_seed_args(x, argc, argv) +#define get_seed_32(x) get_seed_args(x, argc, argv) +#else /* via function or volatile */ +ee_s32 get_seed_32(int i); +#define get_seed(x) (ee_s16) get_seed_32(x) +#endif + +#if (MEM_METHOD == MEM_STATIC) +ee_u8 static_memblk[TOTAL_DATA_SIZE]; +#endif +char *mem_name[3] = {"Static", "Heap", "Stack"}; +/* Function: main + Main entry routine for the benchmark. + This function is responsible for the following steps: + + 1 - Initialize input seeds from a source that cannot be determined at + compile time. 2 - Initialize memory block for use. 3 - Run and time the + benchmark. 4 - Report results, testing the validity of the output if the + seeds are known. + + Arguments: + 1 - first seed : Any value + 2 - second seed : Must be identical to first for iterations to be + identical 3 - third seed : Any value, should be at least an order of + magnitude less then the input size, but bigger then 32. 4 - Iterations : + Special, if set to 0, iterations will be automatically determined such that + the benchmark will run between 10 to 100 secs + +*/ + +#if MAIN_HAS_NOARGC +MAIN_RETURN_TYPE +main(void) { + int argc = 0; + char *argv[1]; +#else +MAIN_RETURN_TYPE +main(int argc, char *argv[]) { +#endif + ee_u16 i, j = 0, num_algorithms = 0; + ee_s16 known_id = -1, total_errors = 0; + ee_u16 seedcrc = 0; + CORE_TICKS total_time; + core_results results[MULTITHREAD]; +#if (MEM_METHOD == MEM_STACK) + ee_u8 stack_memblock[TOTAL_DATA_SIZE * MULTITHREAD]; +#endif + /* first call any initializations needed */ + portable_init(&(results[0].port), &argc, argv); + /* First some checks to make sure benchmark will run ok */ + if (sizeof(struct list_head_s) > 128) { + ee_printf("list_head structure too big for comparable data!\n"); + return MAIN_RETURN_VAL; + } + results[0].seed1 = get_seed(1); + results[0].seed2 = get_seed(2); + results[0].seed3 = get_seed(3); + results[0].iterations = get_seed_32(4); +#if CORE_DEBUG + results[0].iterations = 1; +#endif + results[0].execs = get_seed_32(5); + if (results[0].execs == 0) { /* if not supplied, execute all algorithms */ + results[0].execs = ALL_ALGORITHMS_MASK; + } + /* put in some default values based on one seed only for easy testing */ + if ((results[0].seed1 == 0) && (results[0].seed2 == 0) && + (results[0].seed3 == 0)) { /* performance run */ + results[0].seed1 = 0; + results[0].seed2 = 0; + results[0].seed3 = 0x66; + } + if ((results[0].seed1 == 1) && (results[0].seed2 == 0) && + (results[0].seed3 == 0)) { /* validation run */ + results[0].seed1 = 0x3415; + results[0].seed2 = 0x3415; + results[0].seed3 = 0x66; + } +#if (MEM_METHOD == MEM_STATIC) + results[0].memblock[0] = (void *)static_memblk; + results[0].size = TOTAL_DATA_SIZE; + results[0].err = 0; +#if (MULTITHREAD > 1) +#error "Cannot use a static data area with multiple contexts!" +#endif +#elif (MEM_METHOD == MEM_MALLOC) + for (i = 0; i < MULTITHREAD; i++) { + ee_s32 malloc_override = get_seed(7); + if (malloc_override != 0) + results[i].size = malloc_override; + else + results[i].size = TOTAL_DATA_SIZE; + results[i].memblock[0] = portable_malloc(results[i].size); + results[i].seed1 = results[0].seed1; + results[i].seed2 = results[0].seed2; + results[i].seed3 = results[0].seed3; + results[i].err = 0; + results[i].execs = results[0].execs; + } +#elif (MEM_METHOD == MEM_STACK) +for (i = 0; i < MULTITHREAD; i++) { + results[i].memblock[0] = stack_memblock + i * TOTAL_DATA_SIZE; + results[i].size = TOTAL_DATA_SIZE; + results[i].seed1 = results[0].seed1; + results[i].seed2 = results[0].seed2; + results[i].seed3 = results[0].seed3; + results[i].err = 0; + results[i].execs = results[0].execs; +} +#else +#error "Please define a way to initialize a memory block." +#endif + /* Data init */ + /* Find out how space much we have based on number of algorithms */ + for (i = 0; i < NUM_ALGORITHMS; i++) { + if ((1 << (ee_u32)i) & results[0].execs) + num_algorithms++; + } + for (i = 0; i < MULTITHREAD; i++) + results[i].size = results[i].size / num_algorithms; + /* Assign pointers */ + for (i = 0; i < NUM_ALGORITHMS; i++) { + ee_u32 ctx; + if ((1 << (ee_u32)i) & results[0].execs) { + for (ctx = 0; ctx < MULTITHREAD; ctx++) + results[ctx].memblock[i + 1] = + (char *)(results[ctx].memblock[0]) + results[0].size * j; + j++; + } + } + /* call inits */ + for (i = 0; i < MULTITHREAD; i++) { + if (results[i].execs & ID_LIST) { + results[i].list = core_list_init(results[0].size, results[i].memblock[1], + results[i].seed1); + } + if (results[i].execs & ID_MATRIX) { + core_init_matrix(results[0].size, results[i].memblock[2], + (ee_s32)results[i].seed1 | + (((ee_s32)results[i].seed2) << 16), + &(results[i].mat)); + } + if (results[i].execs & ID_STATE) { + core_init_state(results[0].size, results[i].seed1, + results[i].memblock[3]); + } + } + + /* automatically determine number of iterations if not set */ + if (results[0].iterations == 0) { + secs_ret secs_passed = 0; + ee_u32 divisor; + results[0].iterations = 1; + while (secs_passed < (secs_ret)1) { + results[0].iterations *= 10; + start_time(); + iterate(&results[0]); + stop_time(); + secs_passed = time_in_secs(get_time()); + } + /* now we know it executes for at least 1 sec, set actual run time at + * about 10 secs */ + divisor = (ee_u32)secs_passed; + if (divisor == 0) /* some machines cast float to int as 0 since this + conversion is not defined by ANSI, but we know at + least one second passed */ + divisor = 1; + results[0].iterations *= 1 + 10 / divisor; + } + /* perform actual benchmark */ + start_time(); +#if (MULTITHREAD > 1) + if (default_num_contexts > MULTITHREAD) { + default_num_contexts = MULTITHREAD; + } + for (i = 0; i < default_num_contexts; i++) { + results[i].iterations = results[0].iterations; + results[i].execs = results[0].execs; + core_start_parallel(&results[i]); + } + for (i = 0; i < default_num_contexts; i++) { + core_stop_parallel(&results[i]); + } +#else + iterate(&results[0]); +#endif + stop_time(); + total_time = get_time(); + /* get a function of the input to report */ + seedcrc = crc16(results[0].seed1, seedcrc); + seedcrc = crc16(results[0].seed2, seedcrc); + seedcrc = crc16(results[0].seed3, seedcrc); + seedcrc = crc16(results[0].size, seedcrc); + + switch (seedcrc) { /* test known output for common seeds */ + case 0x8a02: /* seed1=0, seed2=0, seed3=0x66, size 2000 per algorithm */ + known_id = 0; + ee_printf("6k performance run parameters for coremark.\n"); + break; + case 0x7b05: /* seed1=0x3415, seed2=0x3415, seed3=0x66, size 2000 per + algorithm */ + known_id = 1; + ee_printf("6k validation run parameters for coremark.\n"); + break; + case 0x4eaf: /* seed1=0x8, seed2=0x8, seed3=0x8, size 400 per algorithm + */ + known_id = 2; + ee_printf("Profile generation run parameters for coremark.\n"); + break; + case 0xe9f5: /* seed1=0, seed2=0, seed3=0x66, size 666 per algorithm */ + known_id = 3; + ee_printf("2K performance run parameters for coremark.\n"); + break; + case 0x18f2: /* seed1=0x3415, seed2=0x3415, seed3=0x66, size 666 per + algorithm */ + known_id = 4; + ee_printf("2K validation run parameters for coremark.\n"); + break; + default: + total_errors = -1; + break; + } + if (known_id >= 0) { + for (i = 0; i < default_num_contexts; i++) { + results[i].err = 0; + if ((results[i].execs & ID_LIST) && + (results[i].crclist != list_known_crc[known_id])) { + ee_printf("[%u]ERROR! list crc 0x%04x - should be 0x%04x\n", i, + results[i].crclist, list_known_crc[known_id]); + results[i].err++; + } + if ((results[i].execs & ID_MATRIX) && + (results[i].crcmatrix != matrix_known_crc[known_id])) { + ee_printf("[%u]ERROR! matrix crc 0x%04x - should be 0x%04x\n", i, + results[i].crcmatrix, matrix_known_crc[known_id]); + results[i].err++; + } + if ((results[i].execs & ID_STATE) && + (results[i].crcstate != state_known_crc[known_id])) { + ee_printf("[%u]ERROR! state crc 0x%04x - should be 0x%04x\n", i, + results[i].crcstate, state_known_crc[known_id]); + results[i].err++; + } + total_errors += results[i].err; + } + } + total_errors += check_data_types(); + /* and report results */ + ee_printf("CoreMark Size : %lu\n", (long unsigned)results[0].size); + ee_printf("Total ticks : %lu\n", (long unsigned)total_time); +#if HAS_FLOAT + ee_printf("Total time (secs): %f\n", time_in_secs(total_time)); + if (time_in_secs(total_time) > 0) + ee_printf("Iterations/Sec : %f\n", default_num_contexts * + results[0].iterations / + time_in_secs(total_time)); +#else + ee_printf("Total time (secs): %d\n", time_in_secs(total_time)); + if (time_in_secs(total_time) > 0) + ee_printf("Iterations/Sec : %d\n", default_num_contexts * + results[0].iterations / + time_in_secs(total_time)); +#endif + if (time_in_secs(total_time) < 10) { + ee_printf("ERROR! Must execute for at least 10 secs for a valid result!\n"); + total_errors++; + } + + ee_printf("Iterations : %lu\n", + (long unsigned)default_num_contexts * results[0].iterations); + ee_printf("Compiler version : %s\n", COMPILER_VERSION); + ee_printf("Compiler flags : %s\n", COMPILER_FLAGS); +#if (MULTITHREAD > 1) + ee_printf("Parallel %s : %d\n", PARALLEL_METHOD, default_num_contexts); +#endif + ee_printf("Memory location : %s\n", MEM_LOCATION); + /* output for verification */ + ee_printf("seedcrc : 0x%04x\n", seedcrc); + if (results[0].execs & ID_LIST) + for (i = 0; i < default_num_contexts; i++) + ee_printf("[%d]crclist : 0x%04x\n", i, results[i].crclist); + if (results[0].execs & ID_MATRIX) + for (i = 0; i < default_num_contexts; i++) + ee_printf("[%d]crcmatrix : 0x%04x\n", i, results[i].crcmatrix); + if (results[0].execs & ID_STATE) + for (i = 0; i < default_num_contexts; i++) + ee_printf("[%d]crcstate : 0x%04x\n", i, results[i].crcstate); + for (i = 0; i < default_num_contexts; i++) + ee_printf("[%d]crcfinal : 0x%04x\n", i, results[i].crc); + if (total_errors == 0) { + ee_printf( + "Correct operation validated. See README.md for run and reporting " + "rules.\n"); +#if HAS_FLOAT + if (known_id == 3) { + ee_printf("CoreMark 1.0 : %f / %s %s", + default_num_contexts * results[0].iterations / + time_in_secs(total_time), + COMPILER_VERSION, COMPILER_FLAGS); +#if defined(MEM_LOCATION) && !defined(MEM_LOCATION_UNSPEC) + ee_printf(" / %s", MEM_LOCATION); +#else + ee_printf(" / %s", mem_name[MEM_METHOD]); +#endif + +#if (MULTITHREAD > 1) + ee_printf(" / %d:%s", default_num_contexts, PARALLEL_METHOD); +#endif + ee_printf("\n"); + } +#endif + } + if (total_errors > 0) + ee_printf("Errors detected\n"); + if (total_errors < 0) + ee_printf("Cannot validate operation for these seed values, please compare " + "with results on a known platform.\n"); + +#if (MEM_METHOD == MEM_MALLOC) + for (i = 0; i < MULTITHREAD; i++) + portable_free(results[i].memblock[0]); +#endif + /* And last call any target specific code for finalizing */ + portable_fini(&(results[0].port)); + + return MAIN_RETURN_VAL; +} diff --git a/tasks/task5_1/core_matrix.c b/tasks/task5_1/core_matrix.c new file mode 100644 index 0000000000000000000000000000000000000000..29fd8ab455aa0d4ed11dbcc5fb812e7cef130a27 --- /dev/null +++ b/tasks/task5_1/core_matrix.c @@ -0,0 +1,359 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ + +#include "coremark.h" +/* +Topic: Description + Matrix manipulation benchmark + + This very simple algorithm forms the basis of many more complex +algorithms. + + The tight inner loop is the focus of many optimizations (compiler as +well as hardware based) and is thus relevant for embedded processing. + + The total available data space will be divided to 3 parts: + NxN Matrix A - initialized with small values (upper 3/4 of the bits all +zero). NxN Matrix B - initialized with medium values (upper half of the bits all +zero). NxN Matrix C - used for the result. + + The actual values for A and B must be derived based on input that is not +available at compile time. +*/ +ee_s16 matrix_test(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B, MATDAT val); +ee_s16 matrix_sum(ee_u32 N, MATRES *C, MATDAT clipval); +void matrix_mul_const(ee_u32 N, MATRES *C, MATDAT *A, MATDAT val); +void matrix_mul_vect(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B); +void matrix_mul_matrix(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B); +void matrix_mul_matrix_bitextract(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B); +void matrix_add_const(ee_u32 N, MATDAT *A, MATDAT val); + +#define matrix_test_next(x) (x + 1) +#define matrix_clip(x, y) ((y) ? (x)&0x0ff : (x)&0x0ffff) +#define matrix_big(x) (0xf000 | (x)) +#define bit_extract(x, from, to) (((x) >> (from)) & (~(0xffffffff << (to)))) + +#if CORE_DEBUG +void +printmat(MATDAT *A, ee_u32 N, char *name) +{ + ee_u32 i, j; + ee_printf("Matrix %s [%dx%d]:\n", name, N, N); + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + if (j != 0) + ee_printf(","); + ee_printf("%d", A[i * N + j]); + } + ee_printf("\n"); + } +} +void +printmatC(MATRES *C, ee_u32 N, char *name) +{ + ee_u32 i, j; + ee_printf("Matrix %s [%dx%d]:\n", name, N, N); + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + if (j != 0) + ee_printf(","); + ee_printf("%d", C[i * N + j]); + } + ee_printf("\n"); + } +} +#endif +/* Function: core_bench_matrix + Benchmark function + + Iterate <matrix_test> N times, + changing the matrix values slightly by a constant amount each time. +*/ +ee_u16 +core_bench_matrix(mat_params *p, ee_s16 seed, ee_u16 crc) +{ + ee_u32 N = p->N; + MATRES *C = p->C; + MATDAT *A = p->A; + MATDAT *B = p->B; + MATDAT val = (MATDAT)seed; + + crc = crc16(matrix_test(N, C, A, B, val), crc); + + return crc; +} + +/* Function: matrix_test + Perform matrix manipulation. + + Parameters: + N - Dimensions of the matrix. + C - memory for result matrix. + A - input matrix + B - operator matrix (not changed during operations) + + Returns: + A CRC value that captures all results calculated in the function. + In particular, crc of the value calculated on the result matrix + after each step by <matrix_sum>. + + Operation: + + 1 - Add a constant value to all elements of a matrix. + 2 - Multiply a matrix by a constant. + 3 - Multiply a matrix by a vector. + 4 - Multiply a matrix by a matrix. + 5 - Add a constant value to all elements of a matrix. + + After the last step, matrix A is back to original contents. +*/ +ee_s16 +matrix_test(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B, MATDAT val) +{ + ee_u16 crc = 0; + MATDAT clipval = matrix_big(val); + + matrix_add_const(N, A, val); /* make sure data changes */ +#if CORE_DEBUG + printmat(A, N, "matrix_add_const"); +#endif + matrix_mul_const(N, C, A, val); + crc = crc16(matrix_sum(N, C, clipval), crc); +#if CORE_DEBUG + printmatC(C, N, "matrix_mul_const"); +#endif + matrix_mul_vect(N, C, A, B); + crc = crc16(matrix_sum(N, C, clipval), crc); +#if CORE_DEBUG + printmatC(C, N, "matrix_mul_vect"); +#endif + matrix_mul_matrix(N, C, A, B); + crc = crc16(matrix_sum(N, C, clipval), crc); +#if CORE_DEBUG + printmatC(C, N, "matrix_mul_matrix"); +#endif + matrix_mul_matrix_bitextract(N, C, A, B); + crc = crc16(matrix_sum(N, C, clipval), crc); +#if CORE_DEBUG + printmatC(C, N, "matrix_mul_matrix_bitextract"); +#endif + + matrix_add_const(N, A, -val); /* return matrix to initial value */ + return crc; +} + +/* Function : matrix_init + Initialize the memory block for matrix benchmarking. + + Parameters: + blksize - Size of memory to be initialized. + memblk - Pointer to memory block. + seed - Actual values chosen depend on the seed parameter. + p - pointers to <mat_params> containing initialized matrixes. + + Returns: + Matrix dimensions. + + Note: + The seed parameter MUST be supplied from a source that cannot be + determined at compile time +*/ +ee_u32 +core_init_matrix(ee_u32 blksize, void *memblk, ee_s32 seed, mat_params *p) +{ + ee_u32 N = 0; + MATDAT *A; + MATDAT *B; + ee_s32 order = 1; + MATDAT val; + ee_u32 i = 0, j = 0; + if (seed == 0) + seed = 1; + while (j < blksize) + { + i++; + j = i * i * 2 * 4; + } + N = i - 1; + A = (MATDAT *)align_mem(memblk); + B = A + N * N; + + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + seed = ((order * seed) % 65536); + val = (seed + order); + val = matrix_clip(val, 0); + B[i * N + j] = val; + val = (val + order); + val = matrix_clip(val, 1); + A[i * N + j] = val; + order++; + } + } + + p->A = A; + p->B = B; + p->C = (MATRES *)align_mem(B + N * N); + p->N = N; +#if CORE_DEBUG + printmat(A, N, "A"); + printmat(B, N, "B"); +#endif + return N; +} + +/* Function: matrix_sum + Calculate a function that depends on the values of elements in the + matrix. + + For each element, accumulate into a temporary variable. + + As long as this value is under the parameter clipval, + add 1 to the result if the element is bigger then the previous. + + Otherwise, reset the accumulator and add 10 to the result. +*/ +ee_s16 +matrix_sum(ee_u32 N, MATRES *C, MATDAT clipval) +{ + MATRES tmp = 0, prev = 0, cur = 0; + ee_s16 ret = 0; + ee_u32 i, j; + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + cur = C[i * N + j]; + tmp += cur; + if (tmp > clipval) + { + ret += 10; + tmp = 0; + } + else + { + ret += (cur > prev) ? 1 : 0; + } + prev = cur; + } + } + return ret; +} + +/* Function: matrix_mul_const + Multiply a matrix by a constant. + This could be used as a scaler for instance. +*/ +void +matrix_mul_const(ee_u32 N, MATRES *C, MATDAT *A, MATDAT val) +{ + ee_u32 i, j; + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + C[i * N + j] = (MATRES)A[i * N + j] * (MATRES)val; + } + } +} + +/* Function: matrix_add_const + Add a constant value to all elements of a matrix. +*/ +void +matrix_add_const(ee_u32 N, MATDAT *A, MATDAT val) +{ + ee_u32 i, j; + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + A[i * N + j] += val; + } + } +} + +/* Function: matrix_mul_vect + Multiply a matrix by a vector. + This is common in many simple filters (e.g. fir where a vector of + coefficients is applied to the matrix.) +*/ +void +matrix_mul_vect(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B) +{ + ee_u32 i, j; + for (i = 0; i < N; i++) + { + C[i] = 0; + for (j = 0; j < N; j++) + { + C[i] += (MATRES)A[i * N + j] * (MATRES)B[j]; + } + } +} + +/* Function: matrix_mul_matrix + Multiply a matrix by a matrix. + Basic code is used in many algorithms, mostly with minor changes such as + scaling. +*/ +void +matrix_mul_matrix(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B) +{ + ee_u32 i, j, k; + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + C[i * N + j] = 0; + for (k = 0; k < N; k++) + { + C[i * N + j] += (MATRES)A[i * N + k] * (MATRES)B[k * N + j]; + } + } + } +} + +/* Function: matrix_mul_matrix_bitextract + Multiply a matrix by a matrix, and extract some bits from the result. + Basic code is used in many algorithms, mostly with minor changes such as + scaling. +*/ +void +matrix_mul_matrix_bitextract(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B) +{ + ee_u32 i, j, k; + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + C[i * N + j] = 0; + for (k = 0; k < N; k++) + { + MATRES tmp = (MATRES)A[i * N + k] * (MATRES)B[k * N + j]; + C[i * N + j] += bit_extract(tmp, 2, 4) * bit_extract(tmp, 5, 7); + } + } + } +} diff --git a/tasks/task5_1/core_portme.c b/tasks/task5_1/core_portme.c new file mode 100644 index 0000000000000000000000000000000000000000..0cb01ccdb4feaec5bdf5a387f259ac780c6e004c --- /dev/null +++ b/tasks/task5_1/core_portme.c @@ -0,0 +1,130 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ +#include "core_portme.h" +#include "coremark.h" +#include "ztimer.h" + +#if VALIDATION_RUN +volatile ee_s32 seed1_volatile = 0x3415; +volatile ee_s32 seed2_volatile = 0x3415; +volatile ee_s32 seed3_volatile = 0x66; +#endif +#if PERFORMANCE_RUN +volatile ee_s32 seed1_volatile = 0x0; +volatile ee_s32 seed2_volatile = 0x0; +volatile ee_s32 seed3_volatile = 0x66; +#endif +#if PROFILE_RUN +volatile ee_s32 seed1_volatile = 0x8; +volatile ee_s32 seed2_volatile = 0x8; +volatile ee_s32 seed3_volatile = 0x8; +#endif +volatile ee_s32 seed4_volatile = 5000; +volatile ee_s32 seed5_volatile = 0; +/* Porting : Timing functions + How to capture time and convert to seconds must be ported to whatever is + supported by the platform. e.g. Read value from on board RTC, read value from + cpu clock cycles performance counter etc. Sample implementation for standard + time.h and windows.h definitions included. +*/ +CORETIMETYPE +barebones_clock() { return ztimer_now(ZTIMER_USEC); } +/* Define : TIMER_RES_DIVIDER + Divider to trade off timer resolution and total time that can be + measured. + + Use lower values to increase resolution, but make sure that overflow + does not occur. If there are issues with the return value overflowing, + increase this value. + */ +#define GETMYTIME(_t) (*_t = barebones_clock()) +#define MYTIMEDIFF(fin, ini) ((fin) - (ini)) +#define TIMER_RES_DIVIDER 1 +#define SAMPLE_TIME_IMPLEMENTATION 1 +#define EE_TICKS_PER_SEC (1000000 / TIMER_RES_DIVIDER) + +/** Define Host specific (POSIX), or target specific global time variables. */ +static CORETIMETYPE start_time_val, stop_time_val; + +/* Function : start_time + This function will be called right before starting the timed portion of + the benchmark. + + Implementation may be capturing a system timer (as implemented in the + example code) or zeroing some system parameters - e.g. setting the cpu clocks + cycles to 0. +*/ +void start_time(void) { GETMYTIME(&start_time_val); } +/* Function : stop_time + This function will be called right after ending the timed portion of the + benchmark. + + Implementation may be capturing a system timer (as implemented in the + example code) or other system parameters - e.g. reading the current value of + cpu cycles counter. +*/ +void stop_time(void) { GETMYTIME(&stop_time_val); } +/* Function : get_time + Return an abstract "ticks" number that signifies time on the system. + + Actual value returned may be cpu cycles, milliseconds or any other + value, as long as it can be converted to seconds by <time_in_secs>. This + methodology is taken to accommodate any hardware or simulated platform. The + sample implementation returns millisecs by default, and the resolution is + controlled by <TIMER_RES_DIVIDER> +*/ +CORE_TICKS +get_time(void) { + CORE_TICKS elapsed = (CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val)); + return elapsed; +} +/* Function : time_in_secs + Convert the value returned by get_time to seconds. + + The <secs_ret> type is used to accommodate systems with no support for + floating point. Default implementation implemented by the EE_TICKS_PER_SEC + macro above. +*/ +secs_ret time_in_secs(CORE_TICKS ticks) { + secs_ret retval = ((secs_ret)ticks) / (secs_ret)EE_TICKS_PER_SEC; + return retval; +} + +ee_u32 default_num_contexts = 1; + +/* Function : portable_init + Target specific initialization code + Test for some common mistakes. +*/ +void portable_init(core_portable *p, int *argc, char *argv[]) { + (void)argc; // prevent unused warning + (void)argv; // prevent unused warning + + if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) { + ee_printf("ERROR! Please define ee_ptr_int to a type that holds a " + "pointer!\n"); + } + if (sizeof(ee_u32) != 4) { + ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\n"); + } + p->portable_id = 1; +} +/* Function : portable_fini + Target specific final code +*/ +void portable_fini(core_portable *p) { p->portable_id = 0; } diff --git a/tasks/task5_1/core_portme.h b/tasks/task5_1/core_portme.h new file mode 100644 index 0000000000000000000000000000000000000000..17fb33e8950f22e8e68f97ad430af93ce171447a --- /dev/null +++ b/tasks/task5_1/core_portme.h @@ -0,0 +1,209 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ +#include <stddef.h> +/* Topic : Description + This file contains configuration constants required to execute on + different platforms +*/ +#ifndef CORE_PORTME_H +#define CORE_PORTME_H +/************************/ +/* Data types and settings */ +/************************/ +/* Configuration : HAS_FLOAT + Define to 1 if the platform supports floating point. +*/ +#ifndef HAS_FLOAT +#define HAS_FLOAT 1 +#endif +/* Configuration : HAS_TIME_H + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef HAS_TIME_H +#define HAS_TIME_H 0 +#endif +/* Configuration : USE_CLOCK + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef USE_CLOCK +#define USE_CLOCK 0 +#endif +/* Configuration : HAS_STDIO + Define to 1 if the platform has stdio.h. +*/ +#ifndef HAS_STDIO +#define HAS_STDIO 1 +#endif +/* Configuration : HAS_PRINTF + Define to 1 if the platform has stdio.h and implements the printf + function. +*/ +#ifndef HAS_PRINTF +#define HAS_PRINTF 1 +#endif + +/* Definitions : COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION + Initialize these strings per platform +*/ +#ifndef COMPILER_VERSION +#ifdef __GNUC__ +#define COMPILER_VERSION "GCC"__VERSION__ +#else +#define COMPILER_VERSION "Please put compiler version here (e.g. gcc 4.1)" +#endif +#endif +#ifndef COMPILER_FLAGS +#define COMPILER_FLAGS "-O2" +#endif +#ifndef MEM_LOCATION +#define MEM_LOCATION "STACK" +#endif + +/* Data Types : + To avoid compiler issues, define the data types that need ot be used for + 8b, 16b and 32b in <core_portme.h>. + + *Imprtant* : + ee_ptr_int needs to be the data type used to hold pointers, otherwise + coremark may fail!!! +*/ +typedef signed short ee_s16; +typedef unsigned short ee_u16; +typedef signed int ee_s32; +typedef double ee_f32; +typedef unsigned char ee_u8; +typedef unsigned int ee_u32; +typedef ee_u32 ee_ptr_int; +typedef size_t ee_size_t; +#define NULL ((void *)0) +/* align_mem : + This macro is used to align an offset to point to a 32b value. It is + used in the Matrix algorithm to initialize the input memory blocks. +*/ +#define align_mem(x) (void *)(4 + (((ee_ptr_int)(x) - 1) & ~3)) + +/* Configuration : CORE_TICKS + Define type of return from the timing functions. + */ +#define CORETIMETYPE ee_u32 +typedef ee_u32 CORE_TICKS; + +/* Configuration : SEED_METHOD + Defines method to get seed values that cannot be computed at compile + time. + + Valid values : + SEED_ARG - from command line. + SEED_FUNC - from a system function. + SEED_VOLATILE - from volatile variables. +*/ +#ifndef SEED_METHOD +#define SEED_METHOD SEED_VOLATILE +#endif + +/* Configuration : MEM_METHOD + Defines method to get a block of memry. + + Valid values : + MEM_MALLOC - for platforms that implement malloc and have malloc.h. + MEM_STATIC - to use a static memory array. + MEM_STACK - to allocate the data block on the stack (NYI). +*/ +#ifndef MEM_METHOD +#define MEM_METHOD MEM_STACK +#endif + +/* Configuration : MULTITHREAD + Define for parallel execution + + Valid values : + 1 - only one context (default). + N>1 - will execute N copies in parallel. + + Note : + If this flag is defined to more then 1, an implementation for launching + parallel contexts must be defined. + + Two sample implementations are provided. Use <USE_PTHREAD> or <USE_FORK> + to enable them. + + It is valid to have a different implementation of <core_start_parallel> + and <core_end_parallel> in <core_portme.c>, to fit a particular architecture. +*/ +#ifndef MULTITHREAD +#define MULTITHREAD 0 +#define USE_PTHREAD 0 +#define USE_FORK 0 +#define USE_SOCKET 0 +#endif + +/* Configuration : MAIN_HAS_NOARGC + Needed if platform does not support getting arguments to main. + + Valid values : + 0 - argc/argv to main is supported + 1 - argc/argv to main is not supported + + Note : + This flag only matters if MULTITHREAD has been defined to a value + greater then 1. +*/ +#ifndef MAIN_HAS_NOARGC +#define MAIN_HAS_NOARGC 0 +#endif + +/* Configuration : MAIN_HAS_NORETURN + Needed if platform does not support returning a value from main. + + Valid values : + 0 - main returns an int, and return value will be 0. + 1 - platform does not support returning a value from main +*/ +#ifndef MAIN_HAS_NORETURN +#define MAIN_HAS_NORETURN 0 +#endif + +/* Variable : default_num_contexts + Not used for this simple port, must contain the value 1. +*/ +extern ee_u32 default_num_contexts; + +typedef struct CORE_PORTABLE_S { + ee_u8 portable_id; +} core_portable; + +/* target specific init/fini */ +void portable_init(core_portable *p, int *argc, char *argv[]); +void portable_fini(core_portable *p); + +#if !defined(PROFILE_RUN) && !defined(PERFORMANCE_RUN) && \ + !defined(VALIDATION_RUN) +#if (TOTAL_DATA_SIZE == 1200) +#define PROFILE_RUN 1 +#elif (TOTAL_DATA_SIZE == 2000) +#define PERFORMANCE_RUN 1 +#else +#define VALIDATION_RUN 1 +#endif +#endif + +int ee_printf(const char *fmt, ...); + +#endif /* CORE_PORTME_H */ diff --git a/tasks/task5_1/core_state.c b/tasks/task5_1/core_state.c new file mode 100644 index 0000000000000000000000000000000000000000..01800b30f876171180e074290bea62a15aac189c --- /dev/null +++ b/tasks/task5_1/core_state.c @@ -0,0 +1,330 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ + +#include "coremark.h" +/* local functions */ +enum CORE_STATE core_state_transition(ee_u8 **instr, ee_u32 *transition_count); + +/* +Topic: Description + Simple state machines like this one are used in many embedded products. + + For more complex state machines, sometimes a state transition table +implementation is used instead, trading speed of direct coding for ease of +maintenance. + + Since the main goal of using a state machine in CoreMark is to excercise +the switch/if behaviour, we are using a small moore machine. + + In particular, this machine tests type of string input, + trying to determine whether the input is a number or something else. + (see core_state.png). +*/ + +/* Function: core_bench_state + Benchmark function + + Go over the input twice, once direct, and once after introducing some + corruption. +*/ +ee_u16 +core_bench_state(ee_u32 blksize, + ee_u8 *memblock, + ee_s16 seed1, + ee_s16 seed2, + ee_s16 step, + ee_u16 crc) +{ + ee_u32 final_counts[NUM_CORE_STATES]; + ee_u32 track_counts[NUM_CORE_STATES]; + ee_u8 *p = memblock; + ee_u32 i; + +#if CORE_DEBUG + ee_printf("State Bench: %d,%d,%d,%04x\n", seed1, seed2, step, crc); +#endif + for (i = 0; i < NUM_CORE_STATES; i++) + { + final_counts[i] = track_counts[i] = 0; + } + /* run the state machine over the input */ + while (*p != 0) + { + enum CORE_STATE fstate = core_state_transition(&p, track_counts); + final_counts[fstate]++; +#if CORE_DEBUG + ee_printf("%d,", fstate); + } + ee_printf("\n"); +#else + } +#endif + p = memblock; + while (p < (memblock + blksize)) + { /* insert some corruption */ + if (*p != ',') + *p ^= (ee_u8)seed1; + p += step; + } + p = memblock; + /* run the state machine over the input again */ + while (*p != 0) + { + enum CORE_STATE fstate = core_state_transition(&p, track_counts); + final_counts[fstate]++; +#if CORE_DEBUG + ee_printf("%d,", fstate); + } + ee_printf("\n"); +#else + } +#endif + p = memblock; + while (p < (memblock + blksize)) + { /* undo corruption is seed1 and seed2 are equal */ + if (*p != ',') + *p ^= (ee_u8)seed2; + p += step; + } + /* end timing */ + for (i = 0; i < NUM_CORE_STATES; i++) + { + crc = crcu32(final_counts[i], crc); + crc = crcu32(track_counts[i], crc); + } + return crc; +} + +/* Default initialization patterns */ +static ee_u8 *intpat[4] + = { (ee_u8 *)"5012", (ee_u8 *)"1234", (ee_u8 *)"-874", (ee_u8 *)"+122" }; +static ee_u8 *floatpat[4] = { (ee_u8 *)"35.54400", + (ee_u8 *)".1234500", + (ee_u8 *)"-110.700", + (ee_u8 *)"+0.64400" }; +static ee_u8 *scipat[4] = { (ee_u8 *)"5.500e+3", + (ee_u8 *)"-.123e-2", + (ee_u8 *)"-87e+832", + (ee_u8 *)"+0.6e-12" }; +static ee_u8 *errpat[4] = { (ee_u8 *)"T0.3e-1F", + (ee_u8 *)"-T.T++Tq", + (ee_u8 *)"1T3.4e4z", + (ee_u8 *)"34.0e-T^" }; + +/* Function: core_init_state + Initialize the input data for the state machine. + + Populate the input with several predetermined strings, interspersed. + Actual patterns chosen depend on the seed parameter. + + Note: + The seed parameter MUST be supplied from a source that cannot be + determined at compile time +*/ +void +core_init_state(ee_u32 size, ee_s16 seed, ee_u8 *p) +{ + ee_u32 total = 0, next = 0, i; + ee_u8 *buf = 0; +#if CORE_DEBUG + ee_u8 *start = p; + ee_printf("State: %d,%d\n", size, seed); +#endif + size--; + next = 0; + while ((total + next + 1) < size) + { + if (next > 0) + { + for (i = 0; i < next; i++) + *(p + total + i) = buf[i]; + *(p + total + i) = ','; + total += next + 1; + } + seed++; + switch (seed & 0x7) + { + case 0: /* int */ + case 1: /* int */ + case 2: /* int */ + buf = intpat[(seed >> 3) & 0x3]; + next = 4; + break; + case 3: /* float */ + case 4: /* float */ + buf = floatpat[(seed >> 3) & 0x3]; + next = 8; + break; + case 5: /* scientific */ + case 6: /* scientific */ + buf = scipat[(seed >> 3) & 0x3]; + next = 8; + break; + case 7: /* invalid */ + buf = errpat[(seed >> 3) & 0x3]; + next = 8; + break; + default: /* Never happen, just to make some compilers happy */ + break; + } + } + size++; + while (total < size) + { /* fill the rest with 0 */ + *(p + total) = 0; + total++; + } +#if CORE_DEBUG + ee_printf("State Input: %s\n", start); +#endif +} + +static ee_u8 +ee_isdigit(ee_u8 c) +{ + ee_u8 retval; + retval = ((c >= '0') & (c <= '9')) ? 1 : 0; + return retval; +} + +/* Function: core_state_transition + Actual state machine. + + The state machine will continue scanning until either: + 1 - an invalid input is detected. + 2 - a valid number has been detected. + + The input pointer is updated to point to the end of the token, and the + end state is returned (either specific format determined or invalid). +*/ + +enum CORE_STATE +core_state_transition(ee_u8 **instr, ee_u32 *transition_count) +{ + ee_u8 * str = *instr; + ee_u8 NEXT_SYMBOL; + enum CORE_STATE state = CORE_START; + for (; *str && state != CORE_INVALID; str++) + { + NEXT_SYMBOL = *str; + if (NEXT_SYMBOL == ',') /* end of this input */ + { + str++; + break; + } + switch (state) + { + case CORE_START: + if (ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + } + else if (NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-') + { + state = CORE_S1; + } + else if (NEXT_SYMBOL == '.') + { + state = CORE_FLOAT; + } + else + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + transition_count[CORE_START]++; + break; + case CORE_S1: + if (ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INT; + transition_count[CORE_S1]++; + } + else if (NEXT_SYMBOL == '.') + { + state = CORE_FLOAT; + transition_count[CORE_S1]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S1]++; + } + break; + case CORE_INT: + if (NEXT_SYMBOL == '.') + { + state = CORE_FLOAT; + transition_count[CORE_INT]++; + } + else if (!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INT]++; + } + break; + case CORE_FLOAT: + if (NEXT_SYMBOL == 'E' || NEXT_SYMBOL == 'e') + { + state = CORE_S2; + transition_count[CORE_FLOAT]++; + } + else if (!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_FLOAT]++; + } + break; + case CORE_S2: + if (NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-') + { + state = CORE_EXPONENT; + transition_count[CORE_S2]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_S2]++; + } + break; + case CORE_EXPONENT: + if (ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_SCIENTIFIC; + transition_count[CORE_EXPONENT]++; + } + else + { + state = CORE_INVALID; + transition_count[CORE_EXPONENT]++; + } + break; + case CORE_SCIENTIFIC: + if (!ee_isdigit(NEXT_SYMBOL)) + { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + break; + default: + break; + } + } + *instr = str; + return state; +} diff --git a/tasks/task5_1/core_util.c b/tasks/task5_1/core_util.c new file mode 100644 index 0000000000000000000000000000000000000000..67c5d77575b42b874b98d0d84f2f223564e9f3ba --- /dev/null +++ b/tasks/task5_1/core_util.c @@ -0,0 +1,249 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ + +#include "coremark.h" +/* Function: get_seed + Get a values that cannot be determined at compile time. + + Since different embedded systems and compilers are used, 3 different + methods are provided: 1 - Using a volatile variable. This method is only + valid if the compiler is forced to generate code that reads the value of a + volatile variable from memory at run time. Please note, if using this method, + you would need to modify core_portme.c to generate training profile. 2 - + Command line arguments. This is the preferred method if command line + arguments are supported. 3 - System function. If none of the first 2 methods + is available on the platform, a system function which is not a stub can be + used. + + e.g. read the value on GPIO pins connected to switches, or invoke + special simulator functions. +*/ +#if (SEED_METHOD == SEED_VOLATILE) +extern volatile ee_s32 seed1_volatile; +extern volatile ee_s32 seed2_volatile; +extern volatile ee_s32 seed3_volatile; +extern volatile ee_s32 seed4_volatile; +extern volatile ee_s32 seed5_volatile; +ee_s32 +get_seed_32(int i) +{ + ee_s32 retval; + switch (i) + { + case 1: + retval = seed1_volatile; + break; + case 2: + retval = seed2_volatile; + break; + case 3: + retval = seed3_volatile; + break; + case 4: + retval = seed4_volatile; + break; + case 5: + retval = seed5_volatile; + break; + default: + retval = 0; + break; + } + return retval; +} +#elif (SEED_METHOD == SEED_ARG) +ee_s32 +parseval(char *valstring) +{ + ee_s32 retval = 0; + ee_s32 neg = 1; + int hexmode = 0; + if (*valstring == '-') + { + neg = -1; + valstring++; + } + if ((valstring[0] == '0') && (valstring[1] == 'x')) + { + hexmode = 1; + valstring += 2; + } + /* first look for digits */ + if (hexmode) + { + while (((*valstring >= '0') && (*valstring <= '9')) + || ((*valstring >= 'a') && (*valstring <= 'f'))) + { + ee_s32 digit = *valstring - '0'; + if (digit > 9) + digit = 10 + *valstring - 'a'; + retval *= 16; + retval += digit; + valstring++; + } + } + else + { + while ((*valstring >= '0') && (*valstring <= '9')) + { + ee_s32 digit = *valstring - '0'; + retval *= 10; + retval += digit; + valstring++; + } + } + /* now add qualifiers */ + if (*valstring == 'K') + retval *= 1024; + if (*valstring == 'M') + retval *= 1024 * 1024; + + retval *= neg; + return retval; +} + +ee_s32 +get_seed_args(int i, int argc, char *argv[]) +{ + if (argc > i) + return parseval(argv[i]); + return 0; +} + +#elif (SEED_METHOD == SEED_FUNC) +/* If using OS based function, you must define and implement the functions below + * in core_portme.h and core_portme.c ! */ +ee_s32 +get_seed_32(int i) +{ + ee_s32 retval; + switch (i) + { + case 1: + retval = portme_sys1(); + break; + case 2: + retval = portme_sys2(); + break; + case 3: + retval = portme_sys3(); + break; + case 4: + retval = portme_sys4(); + break; + case 5: + retval = portme_sys5(); + break; + default: + retval = 0; + break; + } + return retval; +} +#endif + +/* Function: crc* + Service functions to calculate 16b CRC code. + +*/ +ee_u16 +crcu8(ee_u8 data, ee_u16 crc) +{ + ee_u8 i = 0, x16 = 0, carry = 0; + + for (i = 0; i < 8; i++) + { + x16 = (ee_u8)((data & 1) ^ ((ee_u8)crc & 1)); + data >>= 1; + + if (x16 == 1) + { + crc ^= 0x4002; + carry = 1; + } + else + carry = 0; + crc >>= 1; + if (carry) + crc |= 0x8000; + else + crc &= 0x7fff; + } + return crc; +} +ee_u16 +crcu16(ee_u16 newval, ee_u16 crc) +{ + crc = crcu8((ee_u8)(newval), crc); + crc = crcu8((ee_u8)((newval) >> 8), crc); + return crc; +} +ee_u16 +crcu32(ee_u32 newval, ee_u16 crc) +{ + crc = crc16((ee_s16)newval, crc); + crc = crc16((ee_s16)(newval >> 16), crc); + return crc; +} +ee_u16 +crc16(ee_s16 newval, ee_u16 crc) +{ + return crcu16((ee_u16)newval, crc); +} + +ee_u8 +check_data_types() +{ + ee_u8 retval = 0; + if (sizeof(ee_u8) != 1) + { + ee_printf("ERROR: ee_u8 is not an 8b datatype!\n"); + retval++; + } + if (sizeof(ee_u16) != 2) + { + ee_printf("ERROR: ee_u16 is not a 16b datatype!\n"); + retval++; + } + if (sizeof(ee_s16) != 2) + { + ee_printf("ERROR: ee_s16 is not a 16b datatype!\n"); + retval++; + } + if (sizeof(ee_s32) != 4) + { + ee_printf("ERROR: ee_s32 is not a 32b datatype!\n"); + retval++; + } + if (sizeof(ee_u32) != 4) + { + ee_printf("ERROR: ee_u32 is not a 32b datatype!\n"); + retval++; + } + if (sizeof(ee_ptr_int) != sizeof(int *)) + { + ee_printf( + "ERROR: ee_ptr_int is not a datatype that holds an int pointer!\n"); + retval++; + } + if (retval > 0) + { + ee_printf("ERROR: Please modify the datatypes in core_portme.h!\n"); + } + return retval; +} diff --git a/tasks/task5_1/coremark.h b/tasks/task5_1/coremark.h new file mode 100644 index 0000000000000000000000000000000000000000..9c5e4060a6f676f4319b1fecf8989c813a29afd4 --- /dev/null +++ b/tasks/task5_1/coremark.h @@ -0,0 +1,183 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Original Author: Shay Gal-on +*/ + +/* Topic: Description + This file contains declarations of the various benchmark functions. +*/ + +/* Configuration: TOTAL_DATA_SIZE + Define total size for data algorithms will operate on +*/ +#ifndef TOTAL_DATA_SIZE +#define TOTAL_DATA_SIZE 2 * 1000 +#endif + +#define SEED_ARG 0 +#define SEED_FUNC 1 +#define SEED_VOLATILE 2 + +#define MEM_STATIC 0 +#define MEM_MALLOC 1 +#define MEM_STACK 2 + +#include "core_portme.h" + +#if HAS_STDIO +#include <stdio.h> +#endif +#if HAS_PRINTF +#define ee_printf printf +#endif + +/* Actual benchmark execution in iterate */ +void *iterate(void *pres); + +/* Typedef: secs_ret + For machines that have floating point support, get number of seconds as + a double. Otherwise an unsigned int. +*/ +#if HAS_FLOAT +typedef double secs_ret; +#else +typedef ee_u32 secs_ret; +#endif + +#if MAIN_HAS_NORETURN +#define MAIN_RETURN_VAL +#define MAIN_RETURN_TYPE void +#else +#define MAIN_RETURN_VAL 0 +#define MAIN_RETURN_TYPE int +#endif + +void start_time(void); +void stop_time(void); +CORE_TICKS get_time(void); +secs_ret time_in_secs(CORE_TICKS ticks); + +/* Misc useful functions */ +ee_u16 crcu8(ee_u8 data, ee_u16 crc); +ee_u16 crc16(ee_s16 newval, ee_u16 crc); +ee_u16 crcu16(ee_u16 newval, ee_u16 crc); +ee_u16 crcu32(ee_u32 newval, ee_u16 crc); +ee_u8 check_data_types(void); +void * portable_malloc(ee_size_t size); +void portable_free(void *p); +ee_s32 parseval(char *valstring); + +/* Algorithm IDS */ +#define ID_LIST (1 << 0) +#define ID_MATRIX (1 << 1) +#define ID_STATE (1 << 2) +#define ALL_ALGORITHMS_MASK (ID_LIST | ID_MATRIX | ID_STATE) +#define NUM_ALGORITHMS 3 + +/* list data structures */ +typedef struct list_data_s +{ + ee_s16 data16; + ee_s16 idx; +} list_data; + +typedef struct list_head_s +{ + struct list_head_s *next; + struct list_data_s *info; +} list_head; + +/*matrix benchmark related stuff */ +#define MATDAT_INT 1 +#if MATDAT_INT +typedef ee_s16 MATDAT; +typedef ee_s32 MATRES; +#else +typedef ee_f16 MATDAT; +typedef ee_f32 MATRES; +#endif + +typedef struct MAT_PARAMS_S +{ + int N; + MATDAT *A; + MATDAT *B; + MATRES *C; +} mat_params; + +/* state machine related stuff */ +/* List of all the possible states for the FSM */ +typedef enum CORE_STATE +{ + CORE_START = 0, + CORE_INVALID, + CORE_S1, + CORE_S2, + CORE_INT, + CORE_FLOAT, + CORE_EXPONENT, + CORE_SCIENTIFIC, + NUM_CORE_STATES +} core_state_e; + +/* Helper structure to hold results */ +typedef struct RESULTS_S +{ + /* inputs */ + ee_s16 seed1; /* Initializing seed */ + ee_s16 seed2; /* Initializing seed */ + ee_s16 seed3; /* Initializing seed */ + void * memblock[4]; /* Pointer to safe memory location */ + ee_u32 size; /* Size of the data */ + ee_u32 iterations; /* Number of iterations to execute */ + ee_u32 execs; /* Bitmask of operations to execute */ + struct list_head_s *list; + mat_params mat; + /* outputs */ + ee_u16 crc; + ee_u16 crclist; + ee_u16 crcmatrix; + ee_u16 crcstate; + ee_s16 err; + /* ultithread specific */ + core_portable port; +} core_results; + +/* Multicore execution handling */ +#if (MULTITHREAD > 1) +ee_u8 core_start_parallel(core_results *res); +ee_u8 core_stop_parallel(core_results *res); +#endif + +/* list benchmark functions */ +list_head *core_list_init(ee_u32 blksize, list_head *memblock, ee_s16 seed); +ee_u16 core_bench_list(core_results *res, ee_s16 finder_idx); + +/* state benchmark functions */ +void core_init_state(ee_u32 size, ee_s16 seed, ee_u8 *p); +ee_u16 core_bench_state(ee_u32 blksize, + ee_u8 *memblock, + ee_s16 seed1, + ee_s16 seed2, + ee_s16 step, + ee_u16 crc); + +/* matrix benchmark functions */ +ee_u32 core_init_matrix(ee_u32 blksize, + void * memblk, + ee_s32 seed, + mat_params *p); +ee_u16 core_bench_matrix(mat_params *p, ee_s16 seed, ee_u16 crc); diff --git a/tasks/task5_1/cvt.c b/tasks/task5_1/cvt.c new file mode 100644 index 0000000000000000000000000000000000000000..333e8ead2533bc82b14239aa3ad7a0667f8919a5 --- /dev/null +++ b/tasks/task5_1/cvt.c @@ -0,0 +1,127 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#include <math.h> +#define CVTBUFSIZE 80 +static char CVTBUF[CVTBUFSIZE]; + +static char * +cvt(double arg, int ndigits, int *decpt, int *sign, char *buf, int eflag) +{ + int r2; + double fi, fj; + char * p, *p1; + + if (ndigits < 0) + ndigits = 0; + if (ndigits >= CVTBUFSIZE - 1) + ndigits = CVTBUFSIZE - 2; + r2 = 0; + *sign = 0; + p = &buf[0]; + if (arg < 0) + { + *sign = 1; + arg = -arg; + } + arg = modf(arg, &fi); + p1 = &buf[CVTBUFSIZE]; + + if (fi != 0) + { + p1 = &buf[CVTBUFSIZE]; + while (fi != 0) + { + fj = modf(fi / 10, &fi); + *--p1 = (int)((fj + .03) * 10) + '0'; + r2++; + } + while (p1 < &buf[CVTBUFSIZE]) + *p++ = *p1++; + } + else if (arg > 0) + { + while ((fj = arg * 10) < 1) + { + arg = fj; + r2--; + } + } + p1 = &buf[ndigits]; + if (eflag == 0) + p1 += r2; + *decpt = r2; + if (p1 < &buf[0]) + { + buf[0] = '\0'; + return buf; + } + while (p <= p1 && p < &buf[CVTBUFSIZE]) + { + arg *= 10; + arg = modf(arg, &fj); + *p++ = (int)fj + '0'; + } + if (p1 >= &buf[CVTBUFSIZE]) + { + buf[CVTBUFSIZE - 1] = '\0'; + return buf; + } + p = p1; + *p1 += 5; + while (*p1 > '9') + { + *p1 = '0'; + if (p1 > buf) + ++*--p1; + else + { + *p1 = '1'; + (*decpt)++; + if (eflag == 0) + { + if (p > buf) + *p = '0'; + p++; + } + } + } + *p = '\0'; + return buf; +} + +char * +ecvt(double arg, int ndigits, int *decpt, int *sign) +{ + return cvt(arg, ndigits, decpt, sign, CVTBUF, 1); +} + +char * +ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 1); +} + +char * +fcvt(double arg, int ndigits, int *decpt, int *sign) +{ + return cvt(arg, ndigits, decpt, sign, CVTBUF, 0); +} + +char * +fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 0); +} diff --git a/tasks/task5_1/ee_printf.c b/tasks/task5_1/ee_printf.c new file mode 100644 index 0000000000000000000000000000000000000000..9f708492ee7ca8cc5572191e6b7fb32f69539d16 --- /dev/null +++ b/tasks/task5_1/ee_printf.c @@ -0,0 +1,605 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include <coremark.h> +#include <stdarg.h> +#include <stdio.h> + +#define ZEROPAD (1 << 0) /* Pad with zero */ +#define SIGN (1 << 1) /* Unsigned/signed long */ +#define PLUS (1 << 2) /* Show plus */ +#define SPACE (1 << 3) /* Spacer */ +#define LEFT (1 << 4) /* Left justified */ +#define HEX_PREP (1 << 5) /* 0x */ +#define UPPERCASE (1 << 6) /* 'ABCDEF' */ + +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; +static char *upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static ee_size_t strnlen(const char *s, ee_size_t count); + +static ee_size_t strnlen(const char *s, ee_size_t count) { + const char *sc; + for (sc = s; *sc != '\0' && count--; ++sc) + ; + return sc - s; +} + +static int skip_atoi(const char **s) { + int i = 0; + while (is_digit(**s)) + i = i * 10 + *((*s)++) - '0'; + return i; +} + +static char *number(char *str, long num, int base, int size, int precision, + int type) { + char c, sign, tmp[66]; + char *dig = digits; + int i; + + if (type & UPPERCASE) + dig = upper_digits; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + + if (type & HEX_PREP) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + + i = 0; + + if (num == 0) + tmp[i++] = '0'; + else { + while (num != 0) { + tmp[i++] = dig[((unsigned long)num) % (unsigned)base]; + num = ((unsigned long)num) / (unsigned)base; + } + } + + if (i > precision) + precision = i; + size -= precision; + if (!(type & (ZEROPAD | LEFT))) + while (size-- > 0) + *str++ = ' '; + if (sign) + *str++ = sign; + + if (type & HEX_PREP) { + if (base == 8) + *str++ = '0'; + else if (base == 16) { + *str++ = '0'; + *str++ = digits[33]; + } + } + + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + + return str; +} + +static char *eaddr(char *str, unsigned char *addr, int size, int precision, + int type) { + char tmp[24]; + char *dig = digits; + int i, len; + + if (type & UPPERCASE) + dig = upper_digits; + len = 0; + for (i = 0; i < 6; i++) { + if (i != 0) + tmp[len++] = ':'; + tmp[len++] = dig[addr[i] >> 4]; + tmp[len++] = dig[addr[i] & 0x0F]; + } + + if (!(type & LEFT)) + while (len < size--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = tmp[i]; + while (len < size--) + *str++ = ' '; + + return str; +} + +static char *iaddr(char *str, unsigned char *addr, int size, int precision, + int type) { + char tmp[24]; + int i, n, len; + + len = 0; + for (i = 0; i < 4; i++) { + if (i != 0) + tmp[len++] = '.'; + n = addr[i]; + + if (n == 0) + tmp[len++] = digits[0]; + else { + if (n >= 100) { + tmp[len++] = digits[n / 100]; + n = n % 100; + tmp[len++] = digits[n / 10]; + n = n % 10; + } else if (n >= 10) { + tmp[len++] = digits[n / 10]; + n = n % 10; + } + + tmp[len++] = digits[n]; + } + } + + if (!(type & LEFT)) + while (len < size--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = tmp[i]; + while (len < size--) + *str++ = ' '; + + return str; +} + +#if HAS_FLOAT + +char *ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); +char *fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); +static void ee_bufcpy(char *d, char *s, int count); + +void ee_bufcpy(char *pd, char *ps, int count) { + char *pe = ps + count; + while (ps != pe) + *pd++ = *ps++; +} + +static void parse_float(double value, char *buffer, char fmt, int precision) { + int decpt, sign, exp, pos; + char *digits = NULL; + char cvtbuf[80]; + int capexp = 0; + int magnitude; + + if (fmt == 'G' || fmt == 'E') { + capexp = 1; + fmt += 'a' - 'A'; + } + + if (fmt == 'g') { + digits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf); + magnitude = decpt - 1; + if (magnitude < -4 || magnitude > precision - 1) { + fmt = 'e'; + precision -= 1; + } else { + fmt = 'f'; + precision -= decpt; + } + } + + if (fmt == 'e') { + digits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf); + + if (sign) + *buffer++ = '-'; + *buffer++ = *digits; + if (precision > 0) + *buffer++ = '.'; + ee_bufcpy(buffer, digits + 1, precision); + buffer += precision; + *buffer++ = capexp ? 'E' : 'e'; + + if (decpt == 0) { + if (value == 0.0) + exp = 0; + else + exp = -1; + } else + exp = decpt - 1; + + if (exp < 0) { + *buffer++ = '-'; + exp = -exp; + } else + *buffer++ = '+'; + + buffer[2] = (exp % 10) + '0'; + exp = exp / 10; + buffer[1] = (exp % 10) + '0'; + exp = exp / 10; + buffer[0] = (exp % 10) + '0'; + buffer += 3; + } else if (fmt == 'f') { + digits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf); + if (sign) + *buffer++ = '-'; + if (*digits) { + if (decpt <= 0) { + *buffer++ = '0'; + *buffer++ = '.'; + for (pos = 0; pos < -decpt; pos++) + *buffer++ = '0'; + while (*digits) + *buffer++ = *digits++; + } else { + pos = 0; + while (*digits) { + if (pos++ == decpt) + *buffer++ = '.'; + *buffer++ = *digits++; + } + } + } else { + *buffer++ = '0'; + if (precision > 0) { + *buffer++ = '.'; + for (pos = 0; pos < precision; pos++) + *buffer++ = '0'; + } + } + } + + *buffer = '\0'; +} + +static void decimal_point(char *buffer) { + while (*buffer) { + if (*buffer == '.') + return; + if (*buffer == 'e' || *buffer == 'E') + break; + buffer++; + } + + if (*buffer) { + int n = strnlen(buffer, 256); + while (n > 0) { + buffer[n + 1] = buffer[n]; + n--; + } + + *buffer = '.'; + } else { + *buffer++ = '.'; + *buffer = '\0'; + } +} + +static void cropzeros(char *buffer) { + char *stop; + + while (*buffer && *buffer != '.') + buffer++; + if (*buffer++) { + while (*buffer && *buffer != 'e' && *buffer != 'E') + buffer++; + stop = buffer--; + while (*buffer == '0') + buffer--; + if (*buffer == '.') + buffer--; + while (buffer != stop) + *++buffer = 0; + } +} + +static char *flt(char *str, double num, int size, int precision, char fmt, + int flags) { + char tmp[80]; + char c, sign; + int n, i; + + // Left align means no zero padding + if (flags & LEFT) + flags &= ~ZEROPAD; + + // Determine padding and sign char + c = (flags & ZEROPAD) ? '0' : ' '; + sign = 0; + if (flags & SIGN) { + if (num < 0.0) { + sign = '-'; + num = -num; + size--; + } else if (flags & PLUS) { + sign = '+'; + size--; + } else if (flags & SPACE) { + sign = ' '; + size--; + } + } + + // Compute the precision value + if (precision < 0) + precision = 6; // Default precision: 6 + + // Convert floating point number to text + parse_float(num, tmp, fmt, precision); + + if ((flags & HEX_PREP) && precision == 0) + decimal_point(tmp); + if (fmt == 'g' && !(flags & HEX_PREP)) + cropzeros(tmp); + + n = strnlen(tmp, 256); + + // Output number with alignment and padding + size -= n; + if (!(flags & (ZEROPAD | LEFT))) + while (size-- > 0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (!(flags & LEFT)) + while (size-- > 0) + *str++ = c; + for (i = 0; i < n; i++) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + + return str; +} + +#endif + +static int ee_vsprintf(char *buf, const char *fmt, va_list args) { + int len; + unsigned long num; + int i, base; + char *str; + char *s; + + int flags; // Flags to number() + + int field_width; // Width of output field + int precision; // Min. # of digits for integers; max number of chars for + // from string + int qualifier; // 'h', 'l', or 'L' for integer fields + + for (str = buf; *fmt; fmt++) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + // Process flags + flags = 0; + repeat: + fmt++; // This also skips first '%' + switch (*fmt) { + case '-': + flags |= LEFT; + goto repeat; + case '+': + flags |= PLUS; + goto repeat; + case ' ': + flags |= SPACE; + goto repeat; + case '#': + flags |= HEX_PREP; + goto repeat; + case '0': + flags |= ZEROPAD; + goto repeat; + } + + // Get field width + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + fmt++; + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + // Get the precision + precision = -1; + if (*fmt == '.') { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + // Get the conversion qualifier + qualifier = -1; + if (*fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + fmt++; + } + + // Default base + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char)va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = "<NULL>"; + len = strnlen(s, precision); + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) { + field_width = 2 * sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, (unsigned long)va_arg(args, void *), 16, field_width, + precision, flags); + continue; + + case 'A': + flags |= UPPERCASE; + + case 'a': + if (qualifier == 'l') + str = eaddr(str, va_arg(args, unsigned char *), field_width, precision, + flags); + else + str = iaddr(str, va_arg(args, unsigned char *), field_width, precision, + flags); + continue; + + // Integer number formats - set up the flags and "break" + case 'o': + base = 8; + break; + + case 'X': + flags |= UPPERCASE; + + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + + case 'u': + break; + +#if HAS_FLOAT + + case 'f': + str = flt(str, va_arg(args, double), field_width, precision, *fmt, + flags | SIGN); + continue; + +#endif + + default: + if (*fmt != '%') + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + + str = number(str, num, base, field_width, precision, flags); + } + + *str = '\0'; + return str - buf; +} + +void uart_send_char(char c) { + printf("%c", c); + /* Output of a char to a UART usually follows the following model: + Wait until UART is ready + Write char to UART + Wait until UART is done + + Or in code: + while (*UART_CONTROL_ADDRESS != UART_READY); + *UART_DATA_ADDRESS = c; + while (*UART_CONTROL_ADDRESS != UART_READY); + + Check the UART sample code on your platform or the board + documentation. + */ +} + +int ee_printf(const char *fmt, ...) { + char buf[1024], *p; + va_list args; + int n = 0; + + va_start(args, fmt); + ee_vsprintf(buf, fmt, args); + va_end(args); + p = buf; + while (*p) { + uart_send_char(*p); + n++; + p++; + } + + return n; +} diff --git a/tasks/task5_2/Makefile b/tasks/task5_2/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3e4a5cbefa518ca4dce046c77a421ce773f9662c --- /dev/null +++ b/tasks/task5_2/Makefile @@ -0,0 +1,28 @@ +# name of your application +APPLICATION = blinky + +# If no BOARD is found in the environment, use this default: +BOARD ?= nucleo-f401re + +# This has to be the absolute path to the RIOT base directory: +RIOTBASE ?= $(CURDIR)/../../deps/RIOT + +# Comment this out to disable code in RIOT that does safety checking +# which is not needed in a production environment but helps in the +# development process: +DEVELHELP ?= 1 + +# Change this to 0 show compiler invocation lines by default: +QUIET ?= 1 + +# Use a peripheral timer for the delay, if available +FEATURES_REQUIRED += periph_timer +FEATURES_REQUIRED += periph_gpio_irq +USEMODULE += ztimer +USEMODULE += ztimer_usec +USEMODULE += ztimer_sec +USEMODULE += periph_gpio + +CFLAGS += -Wno-implicit-int -w + +include $(RIOTBASE)/Makefile.include diff --git a/tasks/task5_2/dhrystone.c b/tasks/task5_2/dhrystone.c new file mode 100644 index 0000000000000000000000000000000000000000..fb506bbd970ed6adeffe3fab0481b02c642f07a5 --- /dev/null +++ b/tasks/task5_2/dhrystone.c @@ -0,0 +1,402 @@ +/* Accuracy of timings and human fatigue controlled by next two lines */ +/*#define LOOPS 5000 /* Use this for slow or 16 bit machines */ +// #define LOOPS 50000 /* Use this for slow or 16 bit machines +// */ +#define LOOPS 500000 /* Use this for faster machines */ + +#include "ztimer.h" +#include <stdio.h> +#include <string.h> + +/* Compiler dependent options */ +#undef NOENUM /* Define if compiler has no enum's */ +#undef NOSTRUCTASSIGN /* Define if compiler can't assign structures */ + +/* define only one of the next two defines */ +/*#define TIMES /* Use times(2) time function */ +/*#define TIME /* Use time(2) time function */ +#define RIOT + +/* define the granularity of your times(2) function (when used) */ +#define HZ 100 /* times(2) returns 1/60 second (most) */ + +/* for compatibility with goofed up version */ +/*#define GOOF /* Define if you want the goofed up version */ + +#ifdef GOOF +char Version[] = "1.0"; +#else +char Version[] = "1.1"; +#endif + +#ifdef NOSTRUCTASSIGN +#define structassign(d, s) memcpy(&(d), &(s), sizeof(d)) +#else +#define structassign(d, s) d = s +#endif + +#ifdef NOENUM +#define Ident1 1 +#define Ident2 2 +#define Ident3 3 +#define Ident4 4 +#define Ident5 5 +typedef int Enumeration; +#else +typedef enum { Ident1, Ident2, Ident3, Ident4, Ident5 } Enumeration; +#endif + +typedef int OneToThirty; +typedef int OneToFifty; +typedef char CapitalLetter; +typedef char String30[31]; +typedef int Array1Dim[51]; +typedef int Array2Dim[51][51]; + +struct Record { + struct Record *PtrComp; + Enumeration Discr; + Enumeration EnumComp; + OneToFifty IntComp; + String30 StringComp; +}; + +typedef struct Record RecordType; +typedef RecordType *RecordPtr; +typedef int boolean; + +#define NULL 0 +#define TRUE 1 +#define FALSE 0 + +#ifndef REG +#define REG +#endif + +extern Enumeration Func1(); +extern boolean Func2(); + +#ifdef TIMES +#include <sys/times.h> +#include <sys/types.h> +#endif + +/* + * Package 1 + */ +int IntGlob; +boolean BoolGlob; +char Char1Glob; +char Char2Glob; +Array1Dim Array1Glob; +Array2Dim Array2Glob; +RecordPtr PtrGlb; +RecordPtr PtrGlbNext; + +Proc0() { + OneToFifty IntLoc1; + REG OneToFifty IntLoc2; + OneToFifty IntLoc3; + REG char CharLoc; + REG char CharIndex; + Enumeration EnumLoc; + String30 String1Loc; + String30 String2Loc; + extern char *malloc(); + + register unsigned int i; +#ifdef TIME + long time(); + long starttime; + long benchtime; + long nulltime; + + starttime = time((long *)0); + for (i = 0; i < LOOPS; ++i) + ; + nulltime = time((long *)0) - starttime; /* Computes o'head of loop */ +#endif +#ifdef TIMES + time_t starttime; + time_t benchtime; + time_t nulltime; + struct tms tms; + + times(&tms); + starttime = tms.tms_utime; + for (i = 0; i < LOOPS; ++i) + ; + times(&tms); + nulltime = tms.tms_utime - starttime; /* Computes overhead of looping */ +#endif +#ifdef RIOT + long starttime; + long benchtime; + long nulltime; + nulltime = ztimer_now(ZTIMER_SEC); +#endif + + PtrGlbNext = (RecordPtr)malloc(sizeof(RecordType)); + PtrGlb = (RecordPtr)malloc(sizeof(RecordType)); + PtrGlb->PtrComp = PtrGlbNext; + PtrGlb->Discr = Ident1; + PtrGlb->EnumComp = Ident3; + PtrGlb->IntComp = 40; + strcpy(PtrGlb->StringComp, "DHRYSTONE PROGRAM, SOME STRING"); +#ifndef GOOF + strcpy(String1Loc, "DHRYSTONE PROGRAM, 1'ST STRING"); /*GOOF*/ +#endif + Array2Glob[8][7] = 10; /* Was missing in published program */ + +/***************** +-- Start Timer -- +*****************/ +#ifdef TIME + starttime = time((long *)0); +#endif +#ifdef TIMES + times(&tms); + starttime = tms.tms_utime; +#endif +#ifdef RIOT + starttime = ztimer_now(ZTIMER_SEC); +#endif + for (i = 0; i < LOOPS; ++i) { + + Proc5(); + Proc4(); + IntLoc1 = 2; + IntLoc2 = 3; + strcpy(String2Loc, "DHRYSTONE PROGRAM, 2'ND STRING"); + EnumLoc = Ident2; + BoolGlob = !Func2(String1Loc, String2Loc); + while (IntLoc1 < IntLoc2) { + IntLoc3 = 5 * IntLoc1 - IntLoc2; + Proc7(IntLoc1, IntLoc2, &IntLoc3); + ++IntLoc1; + } + Proc8(Array1Glob, Array2Glob, IntLoc1, IntLoc3); + Proc1(PtrGlb); + for (CharIndex = 'A'; CharIndex <= Char2Glob; ++CharIndex) + if (EnumLoc == Func1(CharIndex, 'C')) + Proc6(Ident1, &EnumLoc); + IntLoc3 = IntLoc2 * IntLoc1; + IntLoc2 = IntLoc3 / IntLoc1; + IntLoc2 = 7 * (IntLoc3 - IntLoc2) - IntLoc1; + Proc2(&IntLoc1); + } + + /***************** + -- Stop Timer -- + *****************/ + +#ifdef TIME + benchtime = time((long *)0) - starttime - nulltime; + printf("Dhrystone(%s) time for %ld passes = %ld\n", Version, (long)LOOPS, + benchtime); + printf("This machine benchmarks at %ld dhrystones/second\n", + ((long)LOOPS) / benchtime); +#endif +#ifdef TIMES + times(&tms); + benchtime = tms.tms_utime - starttime - nulltime; + printf("Dhrystone(%s) time for %ld passes = %ld\n", Version, (long)LOOPS, + benchtime / HZ); + printf("This machine benchmarks at %ld dhrystones/second\n", + ((long)LOOPS) * HZ / benchtime); +#endif +#ifdef RIOT + benchtime = ztimer_now(ZTIMER_SEC) - starttime - nulltime; + printf("Dhrystone(%s) time for %ld passes = %ld\n", Version, (long)LOOPS, + benchtime); + printf("This machine benchmarks at %ld dhrystones/second\n", + ((long)LOOPS) / benchtime); + +#endif +} + +Proc1(PtrParIn) REG RecordPtr PtrParIn; +{ +#define NextRecord (*(PtrParIn->PtrComp)) + + structassign(NextRecord, *PtrGlb); + PtrParIn->IntComp = 5; + NextRecord.IntComp = PtrParIn->IntComp; + NextRecord.PtrComp = PtrParIn->PtrComp; + Proc3(NextRecord.PtrComp); + if (NextRecord.Discr == Ident1) { + NextRecord.IntComp = 6; + Proc6(PtrParIn->EnumComp, &NextRecord.EnumComp); + NextRecord.PtrComp = PtrGlb->PtrComp; + Proc7(NextRecord.IntComp, 10, &NextRecord.IntComp); + } else + structassign(*PtrParIn, NextRecord); + +#undef NextRecord +} + +Proc2(IntParIO) OneToFifty *IntParIO; +{ + REG OneToFifty IntLoc; + REG Enumeration EnumLoc; + + IntLoc = *IntParIO + 10; + for (;;) { + if (Char1Glob == 'A') { + --IntLoc; + *IntParIO = IntLoc - IntGlob; + EnumLoc = Ident1; + } + if (EnumLoc == Ident1) + break; + } +} + +Proc3(PtrParOut) RecordPtr *PtrParOut; +{ + if (PtrGlb != NULL) + *PtrParOut = PtrGlb->PtrComp; + else + IntGlob = 100; + Proc7(10, IntGlob, &PtrGlb->IntComp); +} + +Proc4() { + REG boolean BoolLoc; + + BoolLoc = Char1Glob == 'A'; + BoolLoc |= BoolGlob; + Char2Glob = 'B'; +} + +Proc5() { + Char1Glob = 'A'; + BoolGlob = FALSE; +} + +extern boolean Func3(); + +Proc6(EnumParIn, EnumParOut) REG Enumeration EnumParIn; +REG Enumeration *EnumParOut; +{ + *EnumParOut = EnumParIn; + if (!Func3(EnumParIn)) + *EnumParOut = Ident4; + switch (EnumParIn) { + case Ident1: + *EnumParOut = Ident1; + break; + case Ident2: + if (IntGlob > 100) + *EnumParOut = Ident1; + else + *EnumParOut = Ident4; + break; + case Ident3: + *EnumParOut = Ident2; + break; + case Ident4: + break; + case Ident5: + *EnumParOut = Ident3; + } +} + +Proc7(IntParI1, IntParI2, IntParOut) OneToFifty IntParI1; +OneToFifty IntParI2; +OneToFifty *IntParOut; +{ + REG OneToFifty IntLoc; + + IntLoc = IntParI1 + 2; + *IntParOut = IntParI2 + IntLoc; +} + +Proc8(Array1Par, Array2Par, IntParI1, IntParI2) Array1Dim Array1Par; +Array2Dim Array2Par; +OneToFifty IntParI1; +OneToFifty IntParI2; +{ + REG OneToFifty IntLoc; + REG OneToFifty IntIndex; + + IntLoc = IntParI1 + 5; + Array1Par[IntLoc] = IntParI2; + Array1Par[IntLoc + 1] = Array1Par[IntLoc]; + Array1Par[IntLoc + 30] = IntLoc; + for (IntIndex = IntLoc; IntIndex <= (IntLoc + 1); ++IntIndex) + Array2Par[IntLoc][IntIndex] = IntLoc; + ++Array2Par[IntLoc][IntLoc - 1]; + Array2Par[IntLoc + 20][IntLoc] = Array1Par[IntLoc]; + IntGlob = 5; +} + +Enumeration Func1(CharPar1, CharPar2) +CapitalLetter CharPar1; +CapitalLetter CharPar2; +{ + REG CapitalLetter CharLoc1; + REG CapitalLetter CharLoc2; + + CharLoc1 = CharPar1; + CharLoc2 = CharLoc1; + if (CharLoc2 != CharPar2) + return (Ident1); + else + return (Ident2); +} + +boolean Func2(StrParI1, StrParI2) +String30 StrParI1; +String30 StrParI2; +{ + REG OneToThirty IntLoc; + REG CapitalLetter CharLoc; + + IntLoc = 1; + while (IntLoc <= 1) + if (Func1(StrParI1[IntLoc], StrParI2[IntLoc + 1]) == Ident1) { + CharLoc = 'A'; + ++IntLoc; + } + if (CharLoc >= 'W' && CharLoc <= 'Z') + IntLoc = 7; + if (CharLoc == 'X') + return (TRUE); + else { + if (strcmp(StrParI1, StrParI2) > 0) { + IntLoc += 7; + return (TRUE); + } else + return (FALSE); + } +} + +boolean Func3(EnumParIn) +REG Enumeration EnumParIn; +{ + REG Enumeration EnumLoc; + + EnumLoc = EnumParIn; + if (EnumLoc == Ident3) + return (TRUE); + return (FALSE); +} + +#ifdef NOSTRUCTASSIGN +memcpy(d, s, l) register char *d; +register char *s; +register int l; +{ + while (l--) + *d++ = *s++; +} +#endif + +main() { + Proc0(); + for (;;) { + ztimer_sleep(ZTIMER_SEC, 1); + } +} +/* ---------- */ diff --git a/tasks/task6/Makefile b/tasks/task6/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fab8371c53d8859486019396d5f15be3f1e08913 --- /dev/null +++ b/tasks/task6/Makefile @@ -0,0 +1,27 @@ +# name of your application +APPLICATION = blinky + +# If no BOARD is found in the environment, use this default: +BOARD ?= nucleo-f401re + +# This has to be the absolute path to the RIOT base directory: +RIOTBASE ?= $(CURDIR)/../../deps/RIOT + +# Comment this out to disable code in RIOT that does safety checking +# which is not needed in a production environment but helps in the +# development process: +DEVELHELP ?= 1 + +# Change this to 0 show compiler invocation lines by default: +QUIET ?= 1 + +# Use a peripheral timer for the delay, if available +FEATURES_REQUIRED += periph_timer +FEATURES_REQUIRED += periph_gpio_irq +USEMODULE += ztimer +USEMODULE += ztimer_usec +USEMODULE += periph_gpio + +CFLAGS += -w + +include $(RIOTBASE)/Makefile.include diff --git a/tasks/task6/main.c b/tasks/task6/main.c new file mode 100644 index 0000000000000000000000000000000000000000..66f8293d407fb8378caf87706fec95f675bcbf31 --- /dev/null +++ b/tasks/task6/main.c @@ -0,0 +1,35 @@ +#include <stdio.h> +#include <stdint.h> + +#include "board.h" +#include "periph/gpio.h" +#include "ztimer.h" + +static int static_glob = 10; +const int const_glob = 20; + +void button_irq_handler(void *arg) { + (void)arg; + int a = 10; + static int static_a = 20; + printf("IRQ handler local var addr: %p\n", &a); + printf("IRQ handler static var addr: %p\n", &static_a); +} + +int main(void) { + static int static_a = 20; + int a = 10; + + gpio_init_int(BTN0_PIN, GPIO_IN_PU, GPIO_FALLING, button_irq_handler, NULL); + + printf("Main local var addr: %p\n", &a); + printf("Main statuc var addr: %p\n", &static_a); + + printf("Static var addr: %p\n", &static_glob); + printf("Const global var addr: %p\n, &const_glob"); + + for (;;) { + ztimer_sleep(ZTIMER_USEC, US_PER_SEC); + } +} +