/********************************************************************************************************* * ------------------------------------------------------------------------------------------------------ * 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 ROMT_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[ROMT_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 > ROMT_UNIT_SIZE) num = ROMT_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 != (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 ROMT_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[ROMT_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 > ROMT_UNIT_SIZE) num = ROMT_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 != (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[ROMT_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 > ROMT_UNIT_SIZE) num = ROMT_UNIT_SIZE; else num = romt->size - size; // Fill the buffer with a pattern (0, 1, 2, ..., 255) for (i = 0; i < ROMT_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 != (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 != (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 < ROMT_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[ROMT_UNIT_SIZE], temp[ROMT_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 < ROMT_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 > ROMT_UNIT_SIZE) num = ROMT_UNIT_SIZE; else num = romt->size - size; // Write the pattern to the ROM if (num != (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 != (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 < ROMT_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; } } }