2024-10-21 01:19:11 +08:00

390 lines
11 KiB
C

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