mirror of
https://gitee.com/Lamdonn/varch.git
synced 2025-12-06 08:46:42 +08:00
390 lines
11 KiB
C
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;
|
|
}
|
|
}
|
|
}
|