469 lines
17 KiB
C

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