From ca9bdaad241537a0da669ea7657b69416849371c Mon Sep 17 00:00:00 2001 From: Lamdonn Date: Mon, 21 Oct 2024 01:19:11 +0800 Subject: [PATCH] Add performance class module, update make --- makefile | 79 +++++- source/06_performance/ramt.c | 389 +++++++++++++++++++++++++++++ source/06_performance/ramt.h | 87 +++++++ source/06_performance/romt.c | 469 +++++++++++++++++++++++++++++++++++ source/06_performance/romt.h | 135 ++++++++++ 5 files changed, 1149 insertions(+), 10 deletions(-) create mode 100644 source/06_performance/ramt.c create mode 100644 source/06_performance/ramt.h create mode 100644 source/06_performance/romt.c create mode 100644 source/06_performance/romt.h diff --git a/makefile b/makefile index 1a92297..fd9d55d 100644 --- a/makefile +++ b/makefile @@ -1,8 +1,9 @@ ################################################################################## ### config ################################################################################## -CC = gcc -AR = ar +CC := gcc +AR := ar +CSTD := c11 BUILT_DIR = built TARGET = app LIB = varch @@ -18,18 +19,18 @@ VSTD_PATH = $(WORKSPACE)/02_vstd CONTAINER_PATH = $(WORKSPACE)/03_container ALGORITHM_PATH = $(WORKSPACE)/04_algorithm PARSER_PATH = $(WORKSPACE)/05_parser +PERFORMANCE_PATH = $(WORKSPACE)/06_performance ################################################################################## -### sources and head path +### sources, libaries and head path ################################################################################## -include $(TESTSPACE)/test.mk - INCLUDE += $(APPLICATION_PATH) INCLUDE += $(GENDATA_PATH) INCLUDE += $(VSTD_PATH) INCLUDE += $(CONTAINER_PATH) INCLUDE += $(ALGORITHM_PATH) INCLUDE += $(PARSER_PATH) +INCLUDE += $(PERFORMANCE_PATH) LIBSRCS += $(APPLICATION_PATH)/init.c LIBSRCS += $(wildcard $(APPLICATION_PATH)/console/*.c) @@ -38,14 +39,30 @@ LIBSRCS += $(wildcard $(VSTD_PATH)/*.c) LIBSRCS += $(wildcard $(CONTAINER_PATH)/*.c) LIBSRCS += $(wildcard $(ALGORITHM_PATH)/*.c) LIBSRCS += $(wildcard $(PARSER_PATH)/*.c) +LIBSRCS += $(wildcard $(PERFORMANCE_PATH)/*.c) + +LIBLIST += m +LIBLIST += pthread +# LIBLIST += X11 + +CFLAG += -std=$(CSTD) +# CFLAG += -Wall +# CFLAG += -Werror + +################################################################################## +### test source +################################################################################## + +include $(TESTSPACE)/test.mk TESTSRC += $(APPLICATION_PATH)/main.c TESTSRC += $(TEST_SRC) ################################################################################## -### targets and recipes +### recipes ################################################################################## INCS = $(addprefix -I,$(INCLUDE)) +LIBS = $(addprefix -l,$(LIBLIST)) OBJP = $(BUILT_DIR)/obj BINP = $(BUILT_DIR)/bin LIBO = $(patsubst %.c, $(OBJP)/%.o, $(LIBSRCS)) @@ -56,17 +73,55 @@ LIBN = lib$(LIB) LIBA = $(BUILT_DIR)/$(LIBN).a LIBP ?= /usr +################################################################################## +### make targets +################################################################################## + # link ${TARP}:$(OBJS) mkdir -p $(dir $@) -# @ $(CC) $(OBJS) -o $(TARP) -lm -lX11 -lpthread - @ $(CC) $(CFLAG) $(OBJS) -o $(TARP) -lm -lpthread + @ $(CC) $(CFLAG) $(OBJS) -o $(TARP) $(LIBS) # compile $(OBJP)/%.o:%.c @ mkdir -p $(dir $@) @ echo "compiling $(notdir $<)" @ $(CC) $(CFLAG) $(INCS) -c $< -o $@ + +app:${TARP} + +# lib +lib:$(LIBO) + @ $(AR) -crv $(LIBA) $(LIBO) + +.PHONY:help +help: + @echo "Makefile Help" + @echo "Usage: make [target] [options]" + @echo "" + @echo "Available targets:" + @echo "" + @echo " app - Build the project (default target $(TARP))" + @echo " [CC] - Specify the compiler (default is $(CC))" + @echo " [AR] - Specify the archiver (default is $(AR))" + @echo " [CSTD] - Specify the C std version (c89, c99, c11, c18, default is $(CSTD))" + @echo "" + @echo " lib - Build the library ($(LIB))" + @echo "" + @echo " run - Execute the default application" + @echo "" + @echo " install - Install the library" + @echo " [LIBP] - Specify the lib installation path (default is $(LIBP))" + @echo " example: linux - make install" + @echo " MinGW - make install LIBP=D:/MinGW" + @echo "" + @echo " uninstall - Uninstall the library" + @echo " [LIBP] - Same as install" + @echo "" + @echo " clean - Remove build artifacts" + @echo "" + @echo " help - Show this help message" + .PHONY:clean clean: @@ -74,9 +129,13 @@ clean: @ rm $(BUILT_DIR)/$(WORKSPACE) -rf @ rm $(BUILT_DIR)/* -rf +.PHONY:run +run:app + @ echo "executing..." + ./$(BUILT_DIR)/bin/$(TARGET) + .PHONY:install -install:$(LIBO) - @ $(AR) -crv $(LIBA) $(LIBO) +install:lib @ mkdir -p $(LIBP)/include/$(LIB) @ find $(INCLUDE) -name "*.h" -exec cp {} $(LIBP)/include/$(LIB) \; @ mv -f $(LIBA) $(LIBP)/lib \ diff --git a/source/06_performance/ramt.c b/source/06_performance/ramt.c new file mode 100644 index 0000000..549f4c5 --- /dev/null +++ b/source/06_performance/ramt.c @@ -0,0 +1,389 @@ +/********************************************************************************************************* + * ------------------------------------------------------------------------------------------------------ + * file description + * ------------------------------------------------------------------------------------------------------ + * \file ramt.c + * \unit ramt + * \brief This is a simple ram test module for C language + * \author Lamdonn + * \version v0.1.0 + * \license GPL-2.0 + * \copyright Copyright (C) 2023 Lamdonn. + ********************************************************************************************************/ +#include "ramt.h" + +#define PRIVATE_INDEX_RESULT_HISTORY 0 +#define PRIVATE_INDEX_RESULT_LATEST 1 +#define PRIVATE_INDEX_DURATION 2 +#define PRIVATE_INDEX_TEST_MODE 3 + +/** + * \brief Performs a normal read/write test on the RAM + * \param[in] ramt: pointer to the RAMT structure + * \return 1 if the test passes, 0 if it fails + */ +static uint8_t test_normal(RAMT *ramt) +{ + uint8_t *base = (uint8_t *)(ramt->base); // Cast the base pointer to a uint8_t pointer + uint32_t i = 0; + + // Write data: set each byte to its index value modulo 256 + for (i = 0; i < ramt->size; i++) + { + base[i] = (uint8_t)(i % 256); // Write data + } + + // Read and verify data + for (i = 0; i < ramt->size; i++) + { + // If the read value does not match the expected value, return 0 + if (base[i] != (uint8_t)(i % 256)) + { + return 0; // Test failed + } + } + + return 1; // Test passed +} + +/** + * \brief Test RAM boundary conditions + * \param[in] ramt: Pointer to the RAMT structure + * \return 1 if the boundary write test passes, 0 if it fails + */ +static uint8_t test_boundary(RAMT *ramt) +{ + uint8_t *base = (uint8_t *)(ramt->base); // Cast the base pointer to a uint8_t pointer + + // Test writing at the boundaries + base[0] = 0xAA; // Write to the start address + base[ramt->size - 1] = 0xBB; // Write to the end address + + // Check boundary writes + if (base[0] != 0xAA || base[ramt->size - 1] != 0xBB) + { + return 0; // Boundary write failed + } + + return 1; // Boundary write succeeded +} + +/** + * \brief Test RAM random writes and reads + * \param[in] ramt: Pointer to the RAMT structure + * \param[in] iterations: Number of random write/read iterations + * \return 1 if the random write/read test passes, 0 if it fails + */ +static uint8_t test_random(RAMT *ramt, uint32_t iterations) +{ + uint8_t *base = (uint8_t *)(ramt->base); // Cast the base pointer to a uint8_t pointer + uint8_t data; + uint32_t i = 0; + uint32_t addr = 0; + + // srand((unsigned int)time(NULL)); // Set random seed (uncomment to enable randomness) + for (i = 0; i < iterations; i++) + { + // Generate random address and data + addr = rand() % (ramt->size); // Generate a random address within the RAM size + data = (uint8_t)(rand() % 256); // Generate random data + + base[addr] = data; // Write random data to the RAM + + // Read and verify the data + if (base[addr] != data) + { + return 0; // Data mismatch + } + } + + return 1; // Random write/read test succeeded +} + +/** + * \brief Test RAM data pattern + * \param[in] ramt: Pointer to the RAMT structure + * \param[in] pattern: The data pattern to write to the RAM + * \return 1 if the data pattern test passes, 0 if it fails + */ +static uint8_t test_data_pattern(RAMT *ramt, uint8_t pattern) +{ + uint8_t *base = (uint8_t *)(ramt->base); // Cast the base pointer to a uint8_t pointer + uint32_t i = 0; + + // Write the specified pattern data to the RAM + for (i = 0; i < ramt->size; i++) + { + base[i] = pattern; // Write pattern data + } + + // Check the pattern data + for (i = 0; i < ramt->size; i++) + { + if (base[i] != pattern) + { + return 0; // If data doesn't match, return 0 + } + } + + return 1; // Data pattern test passed +} + +/** + * \brief Test RAM inversion + * \param[in] ramt: Pointer to the RAMT structure + * \return 1 if the inversion test passes, 0 if it fails + */ +static uint8_t test_inversion(RAMT *ramt) +{ + uint8_t *base = (uint8_t *)(ramt->base); // Cast the base pointer to a uint8_t pointer + uint32_t i = 0; + uint8_t temp; + + // Initialize data + for (i = 0; i < ramt->size; i++) + { + base[i] = (uint8_t)(i % 256); // Fill RAM with initial data + } + + // Invert RAM data + for (i = 0; i < ramt->size / 2; i++) + { + temp = base[i]; // Temporarily store the value + base[i] = base[ramt->size - 1 - i]; // Swap values + base[ramt->size - 1 - i] = temp; // Complete the swap + } + + // Check if inversion is correct + for (i = 0; i < ramt->size; i++) + { + if (base[i] != (uint8_t)((ramt->size - 1 - i) % 256)) + { + return 0; // If data does not match, return 0 + } + } + + return 1; // Inversion test passed +} + +/** + * \brief Test RAM clearing + * \param[in] ramt: Pointer to the RAMT structure + * \return 1 if the clearing test passes, 0 if it fails + */ +static uint8_t test_clearing(RAMT *ramt) +{ + uint8_t *base = (uint8_t *)(ramt->base); // Cast the base pointer to a uint8_t pointer + uint32_t i = 0; + + // Clear RAM + for (i = 0; i < ramt->size; i++) + { + base[i] = 0; // Set all data to 0 + } + + // Check if clearing was successful + for (i = 0; i < ramt->size; i++) + { + if (base[i] != 0) + { + return 0; // If any data is not 0, return 0 + } + } + + return 1; // Clearing test passed +} + +/** + * \brief Test specific data writing and reading in RAM + * \param[in] ramt: Pointer to the RAMT structure + * \param[in] data: The specific data to write to the RAM + * \return 1 if the specific data test passes, 0 if it fails + */ +static uint8_t test_specific_data(RAMT *ramt, uint8_t data) +{ + uint8_t *base = (uint8_t *)(ramt->base); // Cast the base pointer to a uint8_t pointer + uint32_t i = 0; + + // Write specific data to RAM + for (i = 0; i < ramt->size; i++) + { + base[i] = data; // Write the specified data to each location in RAM + } + + // Check the specific data + for (i = 0; i < ramt->size; i++) + { + if (base[i] != data) + { + return 0; // If any data does not match, return 0 + } + } + + return 1; // Specific data test passed +} + +int ramt_init(RAMT *ramt) +{ + // Check if the ramt pointer is valid + if (!ramt) return 0; + + // Check if the base pointer within the ramt structure is valid + if (!ramt->base) return 0; + + // Check if the size of RAM is greater than 0 + if (ramt->size == 0) return 0; + + // Initialize the private data to zero + memset(ramt->private, 0, sizeof(ramt->private)); + + return 1; // Initialization successful +} + +int ramt_start(RAMT *ramt, uint32_t mode, uint32_t duration) +{ + // Check if the ramt pointer is valid + if (!ramt) return 0; + + // Check if the base pointer within the ramt structure is valid + if (!ramt->base) return 0; + + // Check if the size of RAM is greater than 0 + if (ramt->size == 0) return 0; + + // Check if mode and duration are valid + if (mode == 0 || duration == 0) return 0; + + // Set the test mode and duration in the private data + ramt->private[PRIVATE_INDEX_TEST_MODE] = mode; + ramt->private[PRIVATE_INDEX_DURATION] = duration; + + return 1; // Operation successful +} + +int ramt_stop(RAMT *ramt) +{ + // Check if the ramt pointer is valid + if (!ramt) return 0; + + // Check if the base pointer within the ramt structure is valid + if (!ramt->base) return 0; + + // Check if the size of RAM is greater than 0 + if (ramt->size == 0) return 0; + + // Reset the test mode and duration in the private data + ramt->private[PRIVATE_INDEX_TEST_MODE] = 0; + ramt->private[PRIVATE_INDEX_DURATION] = 0; + + return 1; // Operation successful +} + +uint32_t ramt_result(RAMT *ramt) +{ + // Check if the ramt pointer is valid + if (!ramt) return 0xFFFFFFFF; + + // Check if the base pointer within the ramt structure is valid + if (!ramt->base) return 0xFFFFFFFF; + + // Check if the size of RAM is greater than 0 + if (ramt->size == 0) return 0xFFFFFFFF; + + // Return the historical result from the private data + return ramt->private[PRIVATE_INDEX_RESULT_HISTORY]; +} + +uint32_t ramt_result_latest(RAMT *ramt) +{ + // Check if the ramt pointer is valid + if (!ramt) return 0xFFFFFFFF; + + // Check if the base pointer within the ramt structure is valid + if (!ramt->base) return 0xFFFFFFFF; + + // Check if the size of RAM is greater than 0 + if (ramt->size == 0) return 0xFFFFFFFF; + + // Return the latest result from the private data + return ramt->private[PRIVATE_INDEX_RESULT_LATEST]; +} + +void ramt_task(RAMT *ramt) +{ + uint32_t result = 0; // Variable to store the results of the tests + uint32_t mode = 0; // Variable to store the current testing mode + + // Check if the ramt pointer is not NULL + if (ramt != NULL) + { + // Check if the duration is set to a special value or decrements it + if (ramt->private[PRIVATE_INDEX_DURATION] == 0xFFFFFFFF || + (ramt->private[PRIVATE_INDEX_DURATION] > 0 && (ramt->private[PRIVATE_INDEX_DURATION])--)) + { + // Get the current testing mode + mode = ramt->private[PRIVATE_INDEX_TEST_MODE]; + + // Execute tests based on the current mode + if (mode & RAMT_MODE_NORMAL) + { + if (!test_normal(ramt)) + { + result |= RAMT_MODE_NORMAL; // Mark failure for normal test + } + } + + if (mode & RAMT_MODE_BOUNDARY) + { + if (!test_boundary(ramt)) + { + result |= RAMT_MODE_BOUNDARY; // Mark failure for boundary test + } + } + + if (mode & RAMT_MODE_PATTERN) + { + if (!test_data_pattern(ramt, 0x55)) + { + result |= RAMT_MODE_PATTERN; // Mark failure for data pattern test + } + } + + if (mode & RAMT_MODE_RANDOM) + { + if (!test_random(ramt, 0x55)) + { + result |= RAMT_MODE_RANDOM; // Mark failure for random test + } + } + + if (mode & RAMT_MODE_INVERSION) + { + if (!test_inversion(ramt)) + { + result |= RAMT_MODE_INVERSION; // Mark failure for inversion test + } + } + + if (mode & RAMT_MODE_CLEARING) + { + if (!test_clearing(ramt)) + { + result |= RAMT_MODE_CLEARING; // Mark failure for clearing test + } + } + + if (mode & RAMT_MODE_SPECIFIC) + { + if (!test_specific_data(ramt, 0x55)) + { + result |= RAMT_MODE_SPECIFIC; // Mark failure for specific data test + } + } + + // Update the latest result and accumulate the historical result + ramt->private[PRIVATE_INDEX_RESULT_LATEST] = result; + ramt->private[PRIVATE_INDEX_RESULT_HISTORY] |= result; + } + } +} diff --git a/source/06_performance/ramt.h b/source/06_performance/ramt.h new file mode 100644 index 0000000..bb9a42d --- /dev/null +++ b/source/06_performance/ramt.h @@ -0,0 +1,87 @@ +/********************************************************************************************************* + * ------------------------------------------------------------------------------------------------------ + * file description + * ------------------------------------------------------------------------------------------------------ + * \file ramt.h + * \unit ramt + * \brief This is a simple ram test module for C language + * \author Lamdonn + * \version v0.1.0 + * \license GPL-2.0 + * \copyright Copyright (C) 2023 Lamdonn. + ********************************************************************************************************/ +#ifndef __ramt_H +#define __ramt_H + +#include +#include +#include +#include +#include + +/* Version infomation */ +#define RAMT_V_MAJOR 0 +#define RAMT_V_MINOR 1 +#define RAMT_V_REVISE 0 + +// Define different RAM test modes +#define RAMT_MODE_NORMAL ((uint32_t)0x00000001) // Normal read/write test +#define RAMT_MODE_BOUNDARY ((uint32_t)0x00000002) // Boundary test +#define RAMT_MODE_PATTERN ((uint32_t)0x00000004) // Data pattern test +#define RAMT_MODE_RANDOM ((uint32_t)0x00000008) // Random access test +#define RAMT_MODE_INVERSION ((uint32_t)0x00000010) // Inversion test +#define RAMT_MODE_CLEARING ((uint32_t)0x00000020) // Clearing test +#define RAMT_MODE_SPECIFIC ((uint32_t)0x00000040) // Specific data test + +// RAM structure definition +typedef struct +{ + void *base; // Pointer to the simulated RAM + uint32_t size; // Size of the RAM + uint32_t private[4]; // Private data, modification not allowed +} RAMT; + +/** + * \brief Initialize RAMT structure + * \param[in] ramt: Pointer to the RAMT structure to be initialized + * \return 1 if initialization is successful, 0 if it fails + */ +int ramt_init(RAMT *ramt); + +/** + * \brief Start the RAM testing with specified mode and duration + * \param[in] ramt: Pointer to the RAMT structure + * \param[in] mode: The mode of the RAM test, see RAMT_MODE_XXX define + * \param[in] duration: The duration for which the RAM test should run, 0xFFFFFFFF continuous running + * \return 1 if the operation is successful, 0 if it fails + */ +int ramt_start(RAMT *ramt, uint32_t mode, uint32_t duration); + +/** + * \brief Stop the RAM testing + * \param[in] ramt: Pointer to the RAMT structure + * \return 1 if the operation is successful, 0 if it fails + */ +int ramt_stop(RAMT *ramt); + +/** + * \brief Retrieve the historical result of the RAM test + * \param[in] ramt: Pointer to the RAMT structure + * \return The result history if successful, 0xFFFFFFFF if it invalid, fail mask see RAMT_MODE_XXX define + */ +uint32_t ramt_result(RAMT *ramt); + +/** + * \brief Retrieve the latest result of the RAM test + * \param[in] ramt: Pointer to the RAMT structure + * \return The latest result if successful, 0xFFFFFFFF if it invalid, fail mask see RAMT_MODE_XXX define + */ +uint32_t ramt_result_latest(RAMT *ramt); + +/** + * \brief Periodically execute RAM testing tasks based on the mode and duration + * \param[in] ramt: Pointer to the RAMT structure + */ +void ramt_task(RAMT *ramt); + +#endif diff --git a/source/06_performance/romt.c b/source/06_performance/romt.c new file mode 100644 index 0000000..a1e0217 --- /dev/null +++ b/source/06_performance/romt.c @@ -0,0 +1,469 @@ +/********************************************************************************************************* + * ------------------------------------------------------------------------------------------------------ + * file description + * ------------------------------------------------------------------------------------------------------ + * \file romt.c + * \unit romt + * \brief This is a simple rom test module for C language + * \author Lamdonn + * \version v0.1.0 + * \license GPL-2.0 + * \copyright Copyright (C) 2023 Lamdonn. + ********************************************************************************************************/ +#include "romt.h" + +#define PRIVATE_INDEX_RESULT_HISTORY 0 +#define PRIVATE_INDEX_RESULT_LATEST 1 +#define PRIVATE_INDEX_DURATION 2 +#define PRIVATE_INDEX_TEST_MODE 3 + +/** + * \brief Test the read functionality of the ROMT structure. + * + * This function reads data from the ROMT structure in units of UNIT_SIZE + * until the entire ROM is read. It verifies that the number of bytes read + * matches the expected number for each read operation. + * + * \param[in] romt: Pointer to the ROMT structure to be tested. + * \return Returns 1 if the read test is successful; otherwise, returns 0. + */ +static uint8_t test_read(ROMT *romt) +{ + uint32_t base = romt->base; ///< Current address in the ROM + uint32_t size = 0; ///< Total bytes read + uint8_t buffer[UNIT_SIZE]; ///< Buffer to hold read data + uint16_t num; ///< Number of bytes to read in current iteration + + while (size < romt->size) ///< Loop until the entire ROM is read + { + if (romt->size - size > UNIT_SIZE) num = UNIT_SIZE; ///< Determine number of bytes to read + else num = romt->size - size; + + // Perform the read operation and check if the number of bytes read is correct + if (num != (uint8_t)(romt->read)(base, buffer, num)) + { + return 0; ///< Return 0 if read operation fails + } + + base += num; ///< Update the base address + size += num; ///< Update the total bytes read + } + + return 1; ///< Return 1 if the read test is successful +} + +/** + * \brief Test the write functionality of the ROMT structure. + * + * This function writes data to the ROMT structure in units of UNIT_SIZE + * until the entire ROM is written. It verifies that the number of bytes + * written matches the expected number for each write operation. + * + * \param[in] romt: Pointer to the ROMT structure to be tested. + * \return Returns 1 if the write test is successful; otherwise, returns 0. + */ +static uint8_t test_write(ROMT *romt) +{ + uint32_t base = romt->base; ///< Current address in the ROM + uint32_t size = 0; ///< Total bytes written + uint8_t buffer[UNIT_SIZE] = {0}; ///< Buffer initialized to zeros for writing + uint16_t num; ///< Number of bytes to write in current iteration + + while (size < romt->size) ///< Loop until the entire ROM is written + { + if (romt->size - size > UNIT_SIZE) num = UNIT_SIZE; ///< Determine number of bytes to write + else num = romt->size - size; + + // Perform the write operation and check if the number of bytes written is correct + if (num != (uint8_t)(romt->write)(base, buffer, num)) + { + return 0; ///< Return 0 if write operation fails + } + + base += num; ///< Update the base address + size += num; ///< Update the total bytes written + } + + return 1; ///< Return 1 if the write test is successful +} + +/** + * \brief Test the normal functionality of the ROMT structure. + * + * This function writes a pattern to the ROMT structure and then reads it back. + * It verifies that the data read matches the pattern that was written. + * The pattern consists of values from 0 to 255, repeating as necessary. + * + * \param[in] romt: Pointer to the ROMT structure to be tested. + * \return Returns 1 if the normal test is successful; otherwise, returns 0. + */ +static uint8_t test_normal(ROMT *romt) +{ + uint32_t base = romt->base; ///< Current address in the ROM + uint32_t size = 0; ///< Total bytes processed + uint8_t buffer[UNIT_SIZE]; ///< Buffer for reading and writing data + uint16_t i, num; ///< Loop index and number of bytes for current iteration + + while (size < romt->size) ///< Loop until the entire ROM is processed + { + // Determine number of bytes to write in the current iteration + if (romt->size - size > UNIT_SIZE) + num = UNIT_SIZE; + else + num = romt->size - size; + + // Fill the buffer with a pattern (0, 1, 2, ..., 255) + for (i = 0; i < UNIT_SIZE; i++) + { + buffer[i] = (uint8_t)(i % 256); + } + + // Perform the write operation and check if the number of bytes written is correct + if (num != (uint8_t)(romt->write)(base, buffer, num)) + { + return 0; ///< Return 0 if write operation fails + } + + // Clear the buffer before reading + memset(buffer, 0, sizeof(buffer)); + + // Perform the read operation and check if the number of bytes read is correct + if (num != (uint8_t)(romt->read)(base, buffer, num)) + { + return 0; ///< Return 0 if read operation fails + } + + // Verify that the read data matches the expected pattern + for (i = 0; i < UNIT_SIZE; i++) + { + if (buffer[i] != (uint8_t)(i % 256)) + { + return 0; ///< Return 0 if the read data does not match the expected pattern + } + } + + base += num; ///< Update the base address for the next iteration + size += num; ///< Update the total bytes processed + } + + return 1; ///< Return 1 if the normal test is successful +} + +/** + * \brief Test the boundary write and read functionality of the ROMT structure. + * + * This function writes data to the first and last byte of the ROMT structure + * and then reads it back to verify that the data was written correctly. + * + * \param[in] romt: Pointer to the ROMT structure to be tested. + * \return Returns 1 if the boundary test is successful; otherwise, returns 0. + */ +static uint8_t test_boundary(ROMT *romt) +{ + uint8_t data = 0; ///< Variable for data to be written and read + + // Write a value to the beginning of the ROM + data = 0xAA; + if ((romt->write)(romt->base, &data, 1) != 1) + { + return 0; ///< Return 0 if the write operation at the start fails + } + + // Write a value to the end of the ROM + data = 0xBB; + if ((romt->write)(romt->base + romt->size - 1, &data, 1) != 1) + { + return 0; ///< Return 0 if the write operation at the end fails + } + + // Read back the value from the beginning of the ROM and check if it matches + if ((romt->read)(romt->base, &data, 1) != 1 || data != 0xAA) + { + return 0; ///< Return 0 if the read operation at the start fails or if the data does not match + } + + // Read back the value from the end of the ROM and check if it matches + if ((romt->read)(romt->base + romt->size - 1, &data, 1) != 1 || data != 0xBB) + { + return 0; ///< Return 0 if the read operation at the end fails or if the data does not match + } + + return 1; ///< Return 1 if the boundary write and read tests are successful +} + +/** + * \brief Test the random write and read functionality of the ROMT structure. + * + * This function randomly generates addresses and data to write to the ROMT structure + * and then reads back the data to verify that it matches what was written. + * + * \param[in] romt: Pointer to the ROMT structure to be tested. + * \param[in] iterations: Number of random write/read operations to perform. + * \return Returns 1 if the random test is successful; otherwise, returns 0. + */ +static uint8_t test_random(ROMT *romt, uint32_t iterations) +{ + uint8_t data, temp; ///< Variables for data to write and read back + uint32_t i = 0; ///< Loop index + uint32_t addr; ///< Random address for writing and reading + + // srand((unsigned int)time(NULL)); // Set random seed (uncomment to enable randomness) + for (i = 0; i < iterations; i++) + { + // Generate random address and data + addr = (rand() % (romt->size)) + romt->base; // Generate a random address within the ROM size + data = (uint8_t)(rand() % 256); // Generate random data (0 to 255) + + // Write data to the randomly generated address + if ((romt->write)(addr, &data, 1) != 1) + { + return 0; // Return 0 if the write operation fails + } + + // Read data back from the same address + if ((romt->read)(addr, &temp, 1) != 1 || temp != data) + { + return 0; // Return 0 if the read operation fails or if the data does not match + } + } + + return 1; // Return 1 if the random write/read test succeeded +} + +/** + * \brief Test the pattern write and read functionality of the ROMT structure. + * + * This function writes a specified pattern to the ROMT structure and then reads it back + * to verify that the data matches the expected pattern. + * + * \param[in] romt: Pointer to the ROMT structure to be tested. + * \param[in] pattern: Byte value to write repeatedly to the ROM. + * \return Returns 1 if the pattern test is successful; otherwise, returns 0. + */ +static uint8_t test_pattern(ROMT *romt, uint8_t pattern) +{ + uint32_t base = romt->base; ///< Current base address in the ROM + uint32_t size = 0; ///< Total bytes processed + uint8_t buffer[UNIT_SIZE], temp[UNIT_SIZE]; ///< Buffers for writing and reading data + uint16_t i, num; ///< Loop index and number of bytes for current iteration + + // Fill the buffer with the specified pattern + for (i = 0; i < UNIT_SIZE; i++) + { + buffer[i] = pattern; + } + + while (size < romt->size) ///< Loop until the entire ROM is processed + { + // Determine number of bytes to write in the current iteration + if (romt->size - size > UNIT_SIZE) + num = UNIT_SIZE; + else + num = romt->size - size; + + // Write the pattern to the ROM + if (num != (uint8_t)(romt->write)(base, buffer, num)) + { + return 0; // Return 0 if the write operation fails + } + + memset(temp, 0, sizeof(temp)); // Clear the temporary buffer before reading + + // Read back the data from the ROM + if (num != (uint8_t)(romt->read)(base, temp, num)) + { + return 0; // Return 0 if the read operation fails + } + + // Verify that the read data matches the expected pattern + for (i = 0; i < UNIT_SIZE; i++) + { + if (temp[i] != pattern) + { + return 0; // Return 0 if the read data does not match the expected pattern + } + } + + base += num; ///< Update the base address for the next iteration + size += num; ///< Update the total bytes processed + } + + return 1; ///< Return 1 if the pattern write/read test succeeded +} + +int romt_init(ROMT *romt) +{ + // Check if the provided ROMT pointer is NULL + if (!romt) return 0; + + // Check if the size of the ROM is zero + if (romt->size == 0) return 0; + + // Check if the read function pointer is NULL + if (!romt->read) return 0; + + // Check if the write function pointer is NULL + if (!romt->write) return 0; + + // Initialize the private data to zero + memset(romt->private, 0, sizeof(romt->private)); + + return 1; // Initialization successful +} + +int romt_start(ROMT *romt, uint32_t mode, uint32_t duration) +{ + // Check if the romt pointer is valid + if (!romt) return 0; + + // Check if the size of ROM is greater than 0 + if (romt->size == 0) return 0; + + // Check if the read function pointer is valid + if (!romt->read) return 0; + + // Check if the write function pointer is valid + if (!romt->write) return 0; + + // Check if mode and duration are valid + if (mode == 0 || duration == 0) return 0; + + // Set the test mode and duration in the private data + romt->private[PRIVATE_INDEX_TEST_MODE] = mode; + romt->private[PRIVATE_INDEX_DURATION] = duration; + + return 1; // Operation successful +} + +int romt_stop(ROMT *romt) +{ + // Check if the romt pointer is valid + if (!romt) return 0; + + // Check if the size of ROM is greater than 0 + if (romt->size == 0) return 0; + + // Check if the read function pointer is valid + if (!romt->read) return 0; + + // Check if the write function pointer is valid + if (!romt->write) return 0; + + // Reset the test mode and duration in the private data + romt->private[PRIVATE_INDEX_TEST_MODE] = 0; + romt->private[PRIVATE_INDEX_DURATION] = 0; + + return 1; // Operation successful +} + +uint32_t romt_result(ROMT *romt) +{ + // Check if the romt pointer is valid + if (!romt) return 0xFFFFFFFF; + + // Check if the size of ROM is greater than 0 + if (romt->size == 0) return 0xFFFFFFFF; + + // Check if the read function pointer is valid + if (!romt->read) return 0xFFFFFFFF; + + // Check if the write function pointer is valid + if (!romt->write) return 0xFFFFFFFF; + + // Return the historical result from the private data + return romt->private[PRIVATE_INDEX_RESULT_HISTORY]; +} + +uint32_t romt_result_latest(ROMT *romt) +{ + // Check if the romt pointer is valid + if (!romt) return 0xFFFFFFFF; + + // Check if the size of ROM is greater than 0 + if (romt->size == 0) return 0xFFFFFFFF; + + // Check if the read function pointer is valid + if (!romt->read) return 0xFFFFFFFF; + + // Check if the write function pointer is valid + if (!romt->write) return 0xFFFFFFFF; + + // Return the latest result from the private data + return romt->private[PRIVATE_INDEX_RESULT_LATEST]; +} + +void romt_task(ROMT *romt) +{ + uint32_t result = 0; // Variable to store the results of the tests + uint32_t mode = 0; // Variable to store the current testing mode + + // Check if the romt pointer is not NULL + if (romt != NULL) + { + // Check if the duration is set to a special value or decrements it + if (romt->private[PRIVATE_INDEX_DURATION] == 0xFFFFFFFF || + (romt->private[PRIVATE_INDEX_DURATION] > 0 && (romt->private[PRIVATE_INDEX_DURATION])--)) + { + // Get the current testing mode + mode = romt->private[PRIVATE_INDEX_TEST_MODE]; + + // Perform read test if the read mode is enabled + if (mode & ROMT_MODE_READ) + { + if (!test_read(romt)) + { + result |= ROMT_MODE_READ; // Mark failure for read test + } + } + + // Perform write test if the write mode is enabled + if (mode & ROMT_MODE_WRITE) + { + if (!test_write(romt)) + { + result |= ROMT_MODE_WRITE; // Mark failure for write test + } + } + + // Perform normal test if the normal mode is enabled + if (mode & ROMT_MODE_NORMAL) + { + if (!test_normal(romt)) + { + result |= ROMT_MODE_NORMAL; // Mark failure for normal test + } + } + + // Perform boundary test if the boundary mode is enabled + if (mode & ROMT_MODE_BOUNDARY) + { + if (!test_boundary(romt)) + { + result |= ROMT_MODE_BOUNDARY; // Mark failure for boundary test + } + } + + // Perform random test if the random mode is enabled + if (mode & ROMT_MODE_RANDOM) + { + if (!test_random(romt, 0x55)) + { + result |= ROMT_MODE_RANDOM; // Mark failure for random test + } + } + + // Perform pattern test if the pattern mode is enabled + if (mode & ROMT_MODE_PATTERN) + { + if (!test_pattern(romt, 0x55)) + { + result |= ROMT_MODE_PATTERN; // Mark failure for pattern test + } + } + + // Update the latest result and accumulate the historical result + romt->private[PRIVATE_INDEX_RESULT_LATEST] = result; + romt->private[PRIVATE_INDEX_RESULT_HISTORY] |= result; + } + } +} \ No newline at end of file diff --git a/source/06_performance/romt.h b/source/06_performance/romt.h new file mode 100644 index 0000000..fb5577f --- /dev/null +++ b/source/06_performance/romt.h @@ -0,0 +1,135 @@ +/********************************************************************************************************* + * ------------------------------------------------------------------------------------------------------ + * file description + * ------------------------------------------------------------------------------------------------------ + * \file romt.h + * \unit romt + * \brief This is a simple rom test module for C language + * \author Lamdonn + * \version v0.1.0 + * \license GPL-2.0 + * \copyright Copyright (C) 2023 Lamdonn. + ********************************************************************************************************/ +#ifndef __romt_H +#define __romt_H + +#include +#include +#include + +/* Version infomation */ +#define ROMT_V_MAJOR 0 +#define ROMT_V_MINOR 1 +#define ROMT_V_REVISE 0 + +#define ROMT_MODE_READ ((uint32_t)0x00000001) ///< Mode for reading from ROM +#define ROMT_MODE_WRITE ((uint32_t)0x00000002) ///< Mode for writing to ROM +#define ROMT_MODE_NORMAL ((uint32_t)0x00000004) ///< Normal operation mode +#define ROMT_MODE_BOUNDARY ((uint32_t)0x00000008) ///< Boundary condition mode +#define ROMT_MODE_RANDOM ((uint32_t)0x00000010) ///< Random access mode +#define ROMT_MODE_PATTERN ((uint32_t)0x00000020) ///< Pattern generation mode + +#define UNIT_SIZE ((uint16_t)256) ///< Size of a unit data block + +/** + * \brief Type definition for read callback function. + * \param[in] address: Address from which to read data. + * \param[in] data: Pointer to the buffer where data will be stored. + * \param[in] length: Number of bytes to read. + * \return Returns the number of bytes read on success; otherwise, an error code. + */ +typedef int (*romt_read_t)(uint32_t address, const uint8_t *data, uint32_t length); + +/** + * \brief Type definition for write callback function. + * \param[in] address: Address at which to write data. + * \param[in] data: Pointer to the buffer containing data to be written. + * \param[in] length: Number of bytes to write. + * \return Returns the number of bytes written on success; otherwise, an error code. + */ +typedef int (*romt_write_t)(uint32_t address, const uint8_t *data, uint32_t length); + +// ROM structure definition +typedef struct +{ + uint32_t base; ///< Pointer to the simulated ROM + uint32_t size; ///< Size of the ROM + romt_read_t read; ///< Read function pointer + romt_write_t write; ///< Write function pointer + uint32_t private[4]; ///< Private data, modification not allowed +} ROMT; + +/** + * \brief Initialize the ROMT structure. + * + * This function checks the validity of the provided ROMT structure and its parameters, + * and initializes the private data field to zero. It ensures that the size, read, and + * write function pointers are valid before proceeding with the initialization. + * + * \param[in] romt: Pointer to the ROMT structure to be initialized. + * \return Returns 1 if initialization is successful; otherwise, returns 0. + */ +int romt_init(ROMT *romt); + +/** + * \brief Start the ROMT operations with specified mode and duration. + * + * This function initializes the ROMT structure for operation by setting the test mode + * and duration. It checks the validity of the input parameters and ensures that the ROM + * is properly initialized before starting the operation. + * + * \param[in] romt: Pointer to the ROMT structure to be started. + * \param[in] mode: The mode of operation for the ROMT. + * \param[in] duration: The duration for which the operation should run. + * \return Returns 1 if the operation is successful; otherwise, returns 0. + */ +int romt_start(ROMT *romt, uint32_t mode, uint32_t duration); + +/** + * \brief Stop the ROMT operations and reset its configuration. + * + * This function halts the operation of the ROMT structure and resets the test mode + * and duration to zero. It ensures that the ROM is properly initialized before stopping + * the operation. + * + * \param[in] romt: Pointer to the ROMT structure to be stopped. + * \return Returns 1 if the operation is successful; otherwise, returns 0. + */ +int romt_stop(ROMT *romt); + +/** + * \brief Retrieve the historical result from the ROMT structure. + * + * This function checks the validity of the ROMT structure and returns the historical + * result stored in the private data. If any checks fail, it returns 0xFFFFFFFF + * to indicate an error. + * + * \param[in] romt: Pointer to the ROMT structure from which to retrieve the result. + * \return Returns the historical result if successful; otherwise, returns 0xFFFFFFFF. + */ +uint32_t romt_result(ROMT *romt); + +/** + * \brief Retrieve the latest result from the ROMT structure. + * + * This function checks the validity of the ROMT structure and returns the latest + * result stored in the private data. If any checks fail, it returns 0xFFFFFFFF + * to indicate an error. + * + * \param[in] romt: Pointer to the ROMT structure from which to retrieve the result. + * \return Returns the latest result if successful; otherwise, returns 0xFFFFFFFF. + */ +uint32_t romt_result_latest(ROMT *romt); + +/** + * \brief Execute the ROMT test tasks based on the configured test mode. + * + * This function checks the current test mode and performs the respective tests (read, write, + * normal, boundary, random, pattern) on the ROMT structure if the duration allows for it. + * It updates the latest result and accumulates the historical result in the private data. + * + * \param[in] romt: Pointer to the ROMT structure to be tested. + */ +void romt_task(ROMT *romt); + +#endif