/********************************************************************************************************* * ------------------------------------------------------------------------------------------------------ * 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; } } }